home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / Assembly / KEEPER.ASM < prev    next >
Assembly Source File  |  1979-12-31  |  23KB  |  491 lines

  1.  
  2. VECTORS SEGMENT AT 0H           ;Set up segment to intercept Interrupts
  3.         ORG     9H*4            ;The keyboard Interrupt
  4. KEYBOARD_INT     LABEL   DWORD
  5. KEYBOARD_INT_WORD DW 2 DUP(?)
  6.         ORG     1CH*4           ;Timer Interrupt
  7. TIMER_VECTOR      LABEL   DWORD
  8. TIMER_VECTOR_WORD DW 2 DUP(?)
  9. VECTORS ENDS
  10.  
  11. SCREEN  SEGMENT AT 0B000H       ;A dummy segment to use as the
  12. SCREEN  ENDS                    ;Extra Segment 
  13.  
  14. ROM_BIOS_DATA   SEGMENT AT 40H  ;BIOS statuses held here, also keyboard buffer
  15.  
  16.         ORG     1AH
  17.         HEAD DW      ?                  ;Unread chars go from Head to Tail
  18.         TAIL DW      ?
  19.         BUFFER       DW      16 DUP (?)         ;The buffer itself
  20.         BUFFER_END   LABEL   WORD
  21.  
  22. ROM_BIOS_DATA   ENDS
  23.  
  24. CODE_SEG        SEGMENT
  25.         ASSUME  CS:CODE_SEG
  26.         ORG     100H            ;ORG = 100H to make this into a .COM file
  27. FIRST:  JMP     LOAD_KEEPER        ;First time through 
  28.  
  29.         COPY_RIGHT      DB      '(C)1985 S.HOLZNER' ;Ascii autograph
  30.         PAD             DB      20*102 DUP(0)       ;Memory storage for pad  
  31.         PAD_CURSOR      DW      9*102               ;Current position in pad
  32.         ATTRIBUTE       DB      112             ;Pad Attribute -- reverse video
  33.         LINE_ATTRIBUTE  DB      240             ;Flashing Rev video
  34.         OLD_ATTRIBUTE   DB      7               ;Original screen attrib: normal
  35.         PAD_OFFSET      DW      0               ;Chooses 1st 250 bytes or 2nd
  36.         FIRST_POSITION  DW      ?               ;Position of 1st char on screen
  37.         TRIGGER_FLAG    DW      0               ;Trigger on or off
  38.         FULL_FLAG       DB      0               ;Buffer Full Flag
  39.         LINE            DW      9               ;Line number, 0-9
  40.         SCREEN_SEG_OFFSET       DW      0       ;0 for mono, 8000H for graphics
  41.         IO_CHAR         DW      ?               ;Holds addr of Put or Get_Char
  42.         STATUS_PORT     DW      ?               ;Video controller status port
  43.         OLD_KEYBOARD_INT        LABEL DWORD     ;Location of old kbd interrupt
  44.         OLD_KEYBOARD_INT_WORD   DW 2 DUP(?)
  45.         FINISHED_FLAG           DB      1       ;If not finished,f buffer 
  46.         COMMAND_INDEX           DW      1       ;Stores positior timer)
  47.         ROM_TIMER               LABEL DWORD     ;The Timer interrupt's address
  48.         ROM_TIMER_WORD          DW 2 DUP(1)
  49.         OLD_HEAD        DW      0
  50.  
  51. KEEPER   PROC    NEAR            ;The keyboard interrupt will now come here.
  52.         ASSUME  CS:CODE_SEG
  53.         PUSH    AX              ;Save the used registers for good form
  54.         PUSH    BX
  55.         PUSH    CX
  56.         PUSH    DX
  57.         PUSH    DI
  58.         PUSH    SI
  59.         PUSH    DS
  60.         PUSH    ES
  61.         PUSHF                           ;First, call old keyboard interrupt
  62.         CALL    OLD_KEYBOARD_INT
  63.         ASSUME  DS:ROM_BIOS_DATA        ;Examine the char just put in
  64.         MOV     BX,ROM_BIOS_DATA
  65.         MOV     DS,BX
  66.         MOV     BX,TAIL                 ;Point to current tail
  67.         CMP     BX,HEAD                 ;If at head, kbd int has deleted char
  68.         JE      BYE                     ;So leave 
  69.         MOV     DX,HEAD
  70.         SUB     DX,2                    ;Point to just read in character
  71.         CMP     DX,OFFSET BUFFER        ;Did we undershoot buffer?
  72.         JAE     NOWRAP                  ;Nope
  73.         MOV     DX,OFFSET BUFFER_END    ;Yes -- move to buffer top
  74.         SUB     DX,2                    ;Compare two bytes back from head
  75. NOWRAP: CMP     DX,TAIL                 ;If it's the tail, buffer is full
  76.         JNE     NOTFULL                 ;We're OK, jump to NotFull
  77.         CMP     FULL_FLAG,1             ;Check if keyboard buffer full
  78.         JE      BYE                     ;Yep, leave
  79.         MOV     FULL_FLAG,1             ;Oops, full, set flag and take
  80.         JMP     CHK                     ; this last character
  81. NOTFULL:MOV     FULL_FLAG,0             ;Always reset Full_Flag when buff clears
  82. CHK:    CMP     TRIGGER_FLAG,0          ;Is the window on (triggered?)
  83.         JNE     SUBT                    ;Yep, keep going
  84.         MOV     DX,OLD_HEAD             ;Check position of buffer head
  85.         CMP     DX,HEAD
  86.         JNE     CONT
  87.         MOV     OLD_HEAD,0
  88. BYE:    JMP     OUT
  89. CONT:   MOV     DX,HEAD
  90.         MOV     OLD_HEAD,DX
  91. SUBT:   SUB     BX,2                    ;Point to just read in character
  92.         CMP     BX,OFFSET BUFFER        ;Did we undershoot buffer?
  93.         JAE     NO_WRAP                 ;Nope
  94.         MOV     BX,OFFSET BUFFER_END    ;Yes -- move to buffer top
  95.         SUB     BX,2                    ;
  96. NO_WRAP:MOV     DX,[BX]                 ;Char in DX now        
  97.         ;------ CHAR IN DX NOW -------
  98.         CMP     FINISHED_FLAG,0
  99.         JE      IN                                                    
  100.         ;Change the next line to change trigger keys (scan, then ASCII in hex).
  101.         ;31H=^N's scan code, 0EH=^N's ASCII code.
  102.         CMP     DX,310EH                ;Default trigger is a ^N here.
  103.         JNE     NOT_TRIGGER             ;No
  104.         MOV     TAIL,BX
  105.         NOT     TRIGGER_FLAG            ;Switch Modes
  106.         CMP     TRIGGER_FLAG,0          ;Trigger off?
  107.         JNE     TRIGGER_ON              ;No, only other choice is on
  108. TRIGGER_OFF:
  109.         MOV     OLD_HEAD,0              ;Reset old head
  110.         MOV     AH,OLD_ATTRIBUTE        ;Get ready to restore screen
  111.         MOV     ATTRIBUTE,AH            ;Pad and blinking line set to orig.
  112.         MOV     LINE_ATTRIBUTE,AH       ; values
  113.         MOV     PAD_OFFSET,10*102       ;Point to 2nd half of pad
  114.         LEA     AX,PUT_CHAR             ;Make IO call Put_Char as it scans
  115.         MOV     IO_CHAR,AX              ;over all locations in pad on screen
  116.         CALL    IO                      ;Restore screen
  117.         CMP     LINE,9                  ;Was the window turned off without
  118.         JE      IN                      ; using up-down keys? If so, exit
  119.         MOV     AX,LINE                 ;No, there is a line to stuff in
  120.         MOV     CL,102                  ; keyboard buffer
  121.         MUL     CL                      ;Find its location in Pad
  122.         MOV     COMMAND_INDEX,AX        ;And send to Put
  123.         CALL    PUT                     ;Which will do actual stuffing
  124. IN:     JMP     OUT                     ;Done
  125. TRIGGER_ON:                             ;Window just turned on
  126.         MOV     LINE,9                  ;Set blinking line to bottom
  127.         MOV     PAD_OFFSET,10*102       ;Point to screen storage part of pad
  128.         LEA     AX,GET_CHAR             ;Make IO use Get_char so current screen
  129.         MOV     IO_CHAR,AX              ;is stored
  130.         CALL    IO                      ;Store Screen
  131.         CALL    DISPLAY                 ;And put up the pad
  132.         JMP     OUT                     ;Done here.
  133. NOT_TRIGGER:
  134.         TEST    TRIGGER_FLAG,1          ;Is Trigger on?
  135.         JZ      RUBOUT_TEST
  136.         MOV     TAIL,BX                 ;Yes, delete this char from buffer
  137. UP:     CMP     DX,4800H                ;An Up cursor key?
  138.         JNE     DOWN                    ;No, try Down
  139.         DEC     LINE                    ;Move blinker up one line
  140.         CMP     LINE,0                  ;At top? If so, reset
  141.         JGE     NOT_TOP
  142.         MOV     LINE,9
  143. NOT_TOP:CALL    DISPLAY                 ;Display result
  144.         JMP     OUT                     ;And leave
  145. DOWN:   CMP     DX,5000H                ;Perhaps Down cusor key pushed
  146.         JNE     IN                      ;If not, ignore key
  147.         INC     LINE                    ;If so, move down one
  148.         CMP     LINE,9                  ;If at bottom, wrap to top
  149.         JLE     NOT_BOT
  150.         MOV     LINE,0
  151. NOT_BOT:CALL    DISPLAY                 ;Show results
  152.         JMP     OUT                     ;And exit
  153. RUBOUT_TEST:
  154.         CMP     DX,0E08H                ;Is it a Rubout?
  155.         JNE     CHAR_TEST               ;No -- try carriage return-line feed
  156.         MOV     BX,PAD_CURSOR           ;Yes -- get current pad location
  157.         CMP     BX,9*102                ;Are we at beginning of last line?
  158.         JLE     NEVER_MIND              ;Yes -- can't rubout past beginning
  159.         SUB     PAD_CURSOR,2            ;No, rubout this char
  160.         MOV     PAD[BX-2],20H           ;Move a space in instead (3920H)
  161.         MOV     PAD[BX-1],39H
  162. NEVER_MIND:
  163.         JMP     OUT                     ;Done here.
  164. CHAR_TEST:
  165.         CMP     DL,13                   ;Is this a carriage return?
  166.         JE      PLUG                    ;If yes, plug this line into Pad
  167.         CMP     DL,32                   ;If this char < Ascii 32, delete line
  168.         JGE     PLUG
  169.         MOV     PAD_CURSOR,9*102        ;Clear the current line
  170.         MOV     CX,51
  171.         MOV     BX,9*102
  172. CLEAR:  MOV     WORD PTR PAD[BX],0
  173.         ADD     BX,2
  174.         LOOP    CLEAR
  175.         JMP     OUT                     ;And exit
  176.  
  177. PLUG:   MOV     BX,PAD_CURSOR           ;Get current pad location
  178.         CMP     BX,10*102-2             ;Are we past the end of the pad?
  179.         JGE     CRLF_TEST               ;Yes -- throw away char
  180.         MOV     WORD PTR PAD[BX],DX     ;No -- move ASCII code into pad
  181.         ADD     PAD_CURSOR,2            ;Increment pad location
  182. CRLF_TEST:
  183.         CMP     DX,1C0DH                ;Is it a carriage return-line feed?
  184.         JNE     OUT                     ;No -- put it in the pad
  185.         CALL    CRLF                    ;Yes -- move everything up in pad
  186. OUT:    POP     ES                      ;Having done Pushes, here are the Pops
  187.         POP     DS
  188.         POP     SI
  189.         POP     DI
  190.         POP     DX
  191.         POP     CX
  192.         POP     BX
  193.         POP     AX     
  194.         IRET                    ;An interrupt needs an IRET
  195. KEEPER   ENDP
  196.  
  197. DISPLAY PROC    NEAR                    ;Puts the whole pad on the screen
  198.         PUSH    AX
  199.         MOV     ATTRIBUTE,112           ;Use reverse video
  200.         MOV     LINE_ATTRIBUTE,240
  201.         MOV     PAD_OFFSET,0            ;Use 1st 250 bytes of pad memory
  202.         LEA     AX,PUT_CHAR             ;Make IO use Put-Char so it does
  203.         MOV     IO_CHAR,AX              
  204.         CALL    IO                      ;Put result on screen
  205.         POP     AX
  206.         RET                             ;Leave
  207. DISPLAY ENDP
  208.  
  209. CRLF    PROC    NEAR                    ;This handles carriage returns
  210.         PUSH    BX                      ;Push everything conceivable
  211.         PUSH    CX           
  212.         PUSH    DI
  213.         PUSH    SI
  214.         PUSH    DS
  215.         PUSH    ES   
  216.         ASSUME  DS:CODE_SEG             ;Set DS to Code_Seg here
  217.         PUSH    CS
  218.         POP     DS
  219.         ASSUME  ES:CODE_SEG             ;And ES too
  220.         PUSH    DS
  221.         POP     ES
  222.         LEA     DI,PAD                  ;Get ready to move contents of Pad
  223.         MOV     SI,DI                   ; up one line
  224.         ADD     SI,102                  ;DI-top line, SI-one below top line
  225.         MOV     CX,9*51
  226.         MOV     BX,PAD_CURSOR           ;But first finish line with a 0        
  227.         CMP     BX,9*102+2              ; as a flag letting Put know line is
  228.         JE      POPS                    ; done.
  229.         MOV     WORD PTR PAD[BX],0
  230. REP     MOVSW                           ;Move up Pad contents
  231.         MOV     CX,51                   ;Now fill the last line with spaces
  232.         MOV     AX,3920H
  233. REP     STOSW                           ;Using Stosw
  234. POPS:   MOV     PAD_CURSOR,9*102        ;And finally reset Cursor to beginning
  235.         POP     ES                      ; of the last line again.
  236.         POP     DS
  237.         POP     SI
  238.         POP     DI
  239.         POP     CX
  240.         POP     BX
  241. DONE:   RET                             ;And out.
  242. CRLF    ENDP
  243.  
  244. GET_CHAR        PROC    NEAR    ;Gets a char from screen and advances position
  245.         ASSUME  ES:SCREEN,DS:ROM_BIOS_DATA
  246.         PUSH    DX
  247.         MOV     SI,2            ;Loop twice, once for char, once for attribute
  248.         MOV     DX,STATUS_PORT  ;Get ready to read video controller status
  249. G_WAIT_LOW:                     ;Start waiting for a new horizontal scan -
  250.         IN      AL,DX           ;Make sure the video controller scan status
  251.         TEST    AL,1            ;is low
  252.         JNZ     G_WAIT_LOW
  253. G_WAIT_HIGH:                    ;After port has gone low, it must go high
  254.         IN      AL,DX           ;before it is safe to read directly from
  255.         TEST    AL,1            ;the screen buffer in memory
  256.         JZ      G_WAIT_HIGH
  257.         MOV     AH,ES:[DI]      ;Do the move from the screen, one byte at a time
  258.         INC     DI              ;Move to next screen location                   
  259.         DEC     SI              ;Decrement loop counter
  260.         CMP     SI,0            ;Are we done?
  261.         JE      LEAVE           ;Yes
  262.         MOV     PAD[BX],AH      ;No -- put char we got into the pad
  263.         JMP     G_WAIT_LOW      ;Do it again
  264. LEAVE:  MOV     OLD_ATTRIBUTE,AH
  265.         ADD     BX,2
  266.         POP     DX
  267.         RET
  268. GET_CHAR        ENDP
  269.  
  270. PUT_CHAR        PROC    NEAR    ;Puts one char on screen and advances position
  271.         PUSH    DX
  272.         MOV     AH,PAD[BX]      ;Get the char to be put onto the screen
  273.         CMP     AH,32
  274.         JAE     GO
  275.         MOV     AH,32
  276. GO:     MOV     SI,2            ;Loop twice, once for char, once for attribute
  277.         MOV     DX,STATUS_PORT  ;Get ready to read video controller status
  278. P_WAIT_LOW:                     ;Start waiting for a new horizontal scan -
  279.         IN      AL,DX           ;Make sure the video controller scan status
  280.         TEST    AL,1            ;is low
  281.         JNZ     P_WAIT_LOW
  282. P_WAIT_HIGH:                    ;After port has gone low, it must go high
  283.         IN      AL,DX           ;before it is safe to write directly to
  284.         TEST    AL,1            ;the screen buffer in memory
  285.         JZ      P_WAIT_HIGH
  286.         MOV     ES:[DI],AH      ;Move to screen, one byte at a time
  287.         MOV     AH,ATTRIBUTE    ;Load attribute byte for second pass
  288.         INC     DI              ;Point to next screen postion
  289.         DEC     SI              ;Decrement loop counter
  290.         JNZ     P_WAIT_LOW      ;If not zero, do it one more time
  291.         ADD     BX,2
  292.         POP     DX
  293.         RET                     ;Exeunt
  294. PUT_CHAR        ENDP
  295.  
  296. IO      PROC    NEAR            ;This scans over all screen positions of the pad
  297.         ASSUME  ES:SCREEN       ;Use screen as extra segment
  298.         MOV     BX,SCREEN
  299.         MOV     ES,BX
  300.         
  301.         PUSH    DS
  302.         MOV     BX,ROM_BIOS_DATA
  303.         MOV     DS,BX
  304.         MOV     BX,4AH
  305.         MOV     BX,DS:[BX]
  306.         SUB     BX,51
  307.         ADD     BX,BX
  308.         MOV     FIRST_POSITION,BX
  309.         POP     DS
  310.  
  311.         MOV     DI,SCREEN_SEG_OFFSET    ;DI will be pointer to screen postion
  312.         ADD     DI,FIRST_POSITION       ;Add width of screen minus pad width
  313.         MOV     BX,PAD_OFFSET           ;BX will be pad location pointer
  314.         MOV     CX,10                   ;There will be 10 lines
  315.  
  316. LINE_LOOP:      
  317.         PUSH    WORD PTR ATTRIBUTE
  318.         PUSH    CX                      ;Figure out whether this is blinking 
  319.         NEG     CX                      ; line and if so, temporarily change
  320.         ADD     CX,10                   ; display attribute
  321.         CMP     CX,LINE
  322.         JNE     NOLINE
  323.         MOV     CL,LINE_ATTRIBUTE
  324.         MOV     ATTRIBUTE,CL
  325. NOLINE: POP     CX
  326.         MOV     DX,51                   ;And 51 spaces across
  327. CHAR_LOOP:
  328.         CALL    IO_CHAR                 ;Call Put-Char or Get-Char
  329.         DEC     DX                      ;Decrement character loop counter
  330.         JNZ     CHAR_LOOP               ;If not zero, scan over next character
  331.         ADD     DI,FIRST_POSITION       ;Add width of screen minus pad width
  332.                          
  333.         POP     WORD PTR ATTRIBUTE
  334.         LOOP    LINE_LOOP               ;And now go back to do next line
  335.         RET                             ;Finished
  336. IO      ENDP
  337.  
  338. PUT  PROC    NEAR    ;Here it is.             
  339.         ASSUME  DS:ROM_BIOS_DATA      ;Free DS
  340.         PUSH    DS                    ;Save all used registers
  341.         PUSH    SI
  342.         PUSH    DI
  343.         PUSH    DX
  344.         PUSH    CX
  345.         PUSH    BX
  346.         PUSH    AX
  347.         MOV     AX,ROM_BIOS_DATA        ;Just to make sure
  348.         MOV     DS,AX                   ;Set DS correctly
  349. FIN:    MOV     FINISHED_FLAG,1         ;Assume we'll finish
  350.         MOV     BX,TAIL                 ;Prepare to move to buffer's tail
  351.         MOV     SI,COMMAND_INDEX        ;Get our source index
  352.  
  353. STUFF:  MOV     AX,WORD PTR PAD[SI]
  354.         ADD     SI,2                    ;Point to the command's next character
  355.         CMP     AX,0                    ;Is it a zero? (End of command)
  356.         JE      NO_NEW_CHARACTERS       ;Yes, leave with Finished_Flag=1
  357.         MOV     DX,BX                   ;Find position in buffer from BX
  358.         ADD     DX,2                    ;Move to next position for this word
  359.         CMP     DX,OFFSET BUFFER_END ;Are we past the end?
  360.         JL      NO_WRAP2                ;No, don't wrap
  361.         MOV     DX,OFFSET BUFFER        ;Wrap
  362. NO_WRAP2:
  363.         CMP     DX,HEAD                 ;Buffer full but not yet done?
  364.         JE      BUFFER_FULL             ;Time to leave, set Finished_Flag=0.
  365.         ADD     COMMAND_INDEX,2         ;Move to next word in command
  366.         MOV     [BX],AX                 ;Put it into the buffer right here.
  367.         ADD     BX,2                    ;Point to next space in buffer
  368.         CMP     BX,OFFSET BUFFER_END ;Wrap here?
  369.         JL      NO_WRAP3                ;No, readjust buffer tail
  370.         MOV     BX,OFFSET BUFFER        ;Yes, wrap
  371. NO_WRAP3: 
  372.         MOV     TAIL,BX                 ;Reset buffer tail
  373.         JMP     STUFF                   ;Back to stuff in another character.
  374. BUFFER_FULL:                            ;If buffer is full, let timer take over
  375.         MOV     FINISHED_FLAG,0         ; by setting Finished_Flag to 0.
  376. NO_NEW_CHARACTERS:
  377.         POP     AX                      ;Restore everything before departure.
  378.         POP     BX
  379.         POP     CX
  380.         POP     DX
  381.         POP     DI
  382.         POP     SI
  383.         POP     DS
  384.         STI
  385.         RET
  386. PUT  ENDP
  387.  
  388.         ASSUME  DS:CODE_SEG
  389. INTERCEPT_TIMER   PROC    NEAR          ;This completes filling the buffer
  390.         PUSHF                           ;Store used flags
  391.         PUSH    DS                      ;Save DS since we'll change it
  392.         PUSH    CS                      ;Put current value of CS into DS
  393.         POP     DS
  394.         CALL    ROM_TIMER               ;Make obligatory call
  395.         PUSHF
  396.         CMP     FINISHED_FLAG,1         ;Do we have to do anything?
  397.         JE      OUT1                     ;No, leave
  398.         CLI                             ;Yes, start by clearing interrupts
  399.         PUSH    DS                      ;Save these.
  400.         PUSH    SI
  401.         PUSH    DX
  402.         PUSH    BX
  403.         PUSH    AX
  404.         ASSUME  DS:ROM_BIOS_DATA        ;Point to the keyboard buffer again.
  405.         MOV     AX,ROM_BIOS_DATA
  406.         MOV     DS,AX
  407.         MOV     BX,TAIL                 ;Prepare to put characters in at tail
  408.         MOV     FINISHED_FLAG,1         ;Assume we'll finish
  409.         MOV     SI,COMMAND_INDEX        ;Find where we left ourselves
  410.  
  411. STUFF2: MOV     AX,WORD PTR PAD[SI]     ;The same stuff loop as above.
  412.         ADD     SI,2                    ;Point to next command character.
  413.         CMP     AX,0                    ;Is it zero? (end of command)
  414.         JNE     OVER                    ;No, continue.
  415.         JMP     NO_NEW_CHARACTERS2      ;Yes, leave with Finished_Flag=1
  416. OVER:   MOV     DX,BX                   ;Find position in buffer from BX
  417.         ADD     DX,2                    ;Move to next position for this word
  418.         CMP     DX,OFFSET BUFFER_END    ;Are we past the end?
  419.         JL      NO_WRAP4                ;No, don't wrap
  420.         MOV     DX,OFFSET BUFFER        ;Do the Wrap rap.
  421. NO_WRAP4:                               
  422.         CMP     DX,HEAD                 ;Buffer full but not yet done?
  423.         JE      BUFFER_FULL2            ;Time to leave, come back later.
  424.         ADD     COMMAND_INDEX,2         ;Point to next word of command.
  425.         MOV     [BX],AX                 ;Put into buffer
  426.         ADD     BX,2                    ;Point to next space in buffer
  427.         CMP     BX,OFFSET BUFFER_END    ;Wrap here?
  428.         JL      NO_WRAP5                ;No, readjust buffer tail
  429.         MOV     BX,OFFSET BUFFER        ;Yes, wrap
  430. NO_WRAP5:                               
  431.         MOV     TAIL,BX                 ;Reset buffer tail
  432.         JMP     STUFF2                  ;Back to stuff in another character
  433. BUFFER_FULL2:
  434.         MOV     FINISHED_FLAG,0         ;Set flag to not-done-yet.
  435. NO_NEW_CHARACTERS2:
  436.         POP     AX                      ;Restore these.
  437.         POP     BX
  438.         POP     DX
  439.         POP     SI
  440.         POP     DS
  441. OUT1:   POPF                            ;And Exit.
  442.         POP     DS
  443.         IRET                            ;With customary IRET
  444. INTERCEPT_TIMER   ENDP
  445.  
  446. LOAD_KEEPER        PROC    NEAR    ;This procedure intializes everything
  447.         ASSUME  DS:VECTORS   ;The data segment will be the Interrupt area
  448.         MOV     AX,VECTORS
  449.         MOV     DS,AX
  450.         
  451.         MOV     AX,KEYBOARD_INT_WORD         
  452.         MOV     OLD_KEYBOARD_INT_WORD,AX     
  453.         MOV     AX,KEYBOARD_INT_WORD[2]      
  454.         MOV     OLD_KEYBOARD_INT_WORD[2],AX
  455.         
  456.         MOV     KEYBOARD_INT_WORD,OFFSET KEEPER
  457.         MOV     KEYBOARD_INT_WORD[2],CS        
  458.                                         
  459.         MOV     AX,TIMER_VECTOR_WORD         
  460.         MOV     ROM_TIMER_WORD,AX
  461.         MOV     AX,TIMER_VECTOR_WORD[2]
  462.         MOV     ROM_TIMER_WORD[2],AX
  463.  
  464.         MOV     TIMER_VECTOR_WORD,OFFSET INTERCEPT_TIMER
  465.         MOV     TIMER_VECTOR_WORD[2],CS      ;And intercept that too.
  466.  
  467.         ASSUME  DS:ROM_BIOS_DATA
  468.         MOV     AX,ROM_BIOS_DATA
  469.         MOV     DS,AX
  470.         MOV     BX,OFFSET BUFFER     ;Clear the keyboard buffer.
  471.         MOV     HEAD,BX
  472.         MOV     TAIL,BX
  473.         MOV     AH,15                   ;Ask for service 15 of INT 10H 
  474.         INT     10H                     ;This tells us how display is set up
  475.         MOV     STATUS_PORT,03BAH        ;Assume this is a monochrome display
  476.         TEST    AL,4                    ;Is it?
  477.         JNZ     EXIT                    ;Yes - jump out
  478.         MOV     SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
  479.         MOV     STATUS_PORT,03DAH
  480.  
  481. EXIT:   MOV     DX,OFFSET LOAD_KEEPER      ;Set up everything but LOAD_PAD to
  482.         INT     27H                     ;stay and attach itself to DOS
  483. LOAD_KEEPER        ENDP
  484.  
  485.         CODE_SEG        ENDS
  486.         
  487.         END     FIRST   ;END "FIRST" so 8088 will go to FIRST first.
  488.  
  489.  
  490.  
  491.