📄 keeper.asm
字号:
IN AL,DX ;Make sure the video controller scan status
TEST AL,1 ;is low
JNZ G_WAIT_LOW
G_WAIT_HIGH: ;After port has gone low, it must go high
IN AL,DX ;before it is safe to read directly from
TEST AL,1 ;the screen buffer in memory
JZ G_WAIT_HIGH
MOV AH,ES:[DI] ;Do the move from the screen, one byte at a time
INC DI ;Move to next screen location
DEC SI ;Decrement loop counter
CMP SI,0 ;Are we done?
JE LEAVE ;Yes
MOV PAD[BX],AH ;No -- put char we got into the pad
JMP G_WAIT_LOW ;Do it again
LEAVE: MOV OLD_ATTRIBUTE,AH
ADD BX,2
POP DX
RET
GET_CHAR ENDP
PUT_CHAR PROC NEAR ;Puts one char on screen and advances position
PUSH DX
MOV AH,PAD[BX] ;Get the char to be put onto the screen
CMP AH,32
JAE GO
MOV AH,32
GO: MOV SI,2 ;Loop twice, once for char, once for attribute
MOV DX,STATUS_PORT ;Get ready to read video controller status
P_WAIT_LOW: ;Start waiting for a new horizontal scan -
IN AL,DX ;Make sure the video controller scan status
TEST AL,1 ;is low
JNZ P_WAIT_LOW
P_WAIT_HIGH: ;After port has gone low, it must go high
IN AL,DX ;before it is safe to write directly to
TEST AL,1 ;the screen buffer in memory
JZ P_WAIT_HIGH
MOV ES:[DI],AH ;Move to screen, one byte at a time
MOV AH,ATTRIBUTE ;Load attribute byte for second pass
INC DI ;Point to next screen postion
DEC SI ;Decrement loop counter
JNZ P_WAIT_LOW ;If not zero, do it one more time
ADD BX,2
POP DX
RET ;Exeunt
PUT_CHAR ENDP
IO PROC NEAR ;This scans over all screen positions of the pad
ASSUME ES:SCREEN ;Use screen as extra segment
MOV BX,SCREEN
MOV ES,BX
PUSH DS
MOV BX,ROM_BIOS_DATA
MOV DS,BX
MOV BX,4AH
MOV BX,DS:[BX]
SUB BX,51
ADD BX,BX
MOV FIRST_POSITION,BX
POP DS
MOV DI,SCREEN_SEG_OFFSET ;DI will be pointer to screen postion
ADD DI,FIRST_POSITION ;Add width of screen minus pad width
MOV BX,PAD_OFFSET ;BX will be pad location pointer
MOV CX,10 ;There will be 10 lines
LINE_LOOP:
PUSH WORD PTR ATTRIBUTE
PUSH CX ;Figure out whether this is blinking
NEG CX ; line and if so, temporarily change
ADD CX,10 ; display attribute
CMP CX,LINE
JNE NOLINE
MOV CL,LINE_ATTRIBUTE
MOV ATTRIBUTE,CL
NOLINE: POP CX
MOV DX,51 ;And 51 spaces across
CHAR_LOOP:
CALL IO_CHAR ;Call Put-Char or Get-Char
DEC DX ;Decrement character loop counter
JNZ CHAR_LOOP ;If not zero, scan over next character
ADD DI,FIRST_POSITION ;Add width of screen minus pad width
POP WORD PTR ATTRIBUTE
LOOP LINE_LOOP ;And now go back to do next line
RET ;Finished
IO ENDP
PUT PROC NEAR ;Here it is.
ASSUME DS:ROM_BIOS_DATA ;Free DS
PUSH DS ;Save all used registers
PUSH SI
PUSH DI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV AX,ROM_BIOS_DATA ;Just to make sure
MOV DS,AX ;Set DS correctly
FIN: MOV FINISHED_FLAG,1 ;Assume we'll finish
MOV BX,TAIL ;Prepare to move to buffer's tail
MOV SI,COMMAND_INDEX ;Get our source index
STUFF: MOV AX,WORD PTR PAD[SI]
ADD SI,2 ;Point to the command's next character
CMP AX,0 ;Is it a zero? (End of command)
JE NO_NEW_CHARACTERS ;Yes, leave with Finished_Flag=1
MOV DX,BX ;Find position in buffer from BX
ADD DX,2 ;Move to next position for this word
CMP DX,OFFSET BUFFER_END ;Are we past the end?
JL NO_WRAP2 ;No, don't wrap
MOV DX,OFFSET BUFFER ;Wrap
NO_WRAP2:
CMP DX,HEAD ;Buffer full but not yet done?
JE BUFFER_FULL ;Time to leave, set Finished_Flag=0.
ADD COMMAND_INDEX,2 ;Move to next word in command
MOV [BX],AX ;Put it into the buffer right here.
ADD BX,2 ;Point to next space in buffer
CMP BX,OFFSET BUFFER_END ;Wrap here?
JL NO_WRAP3 ;No, readjust buffer tail
MOV BX,OFFSET BUFFER ;Yes, wrap
NO_WRAP3:
MOV TAIL,BX ;Reset buffer tail
JMP STUFF ;Back to stuff in another character.
BUFFER_FULL: ;If buffer is full, let timer take over
MOV FINISHED_FLAG,0 ; by setting Finished_Flag to 0.
NO_NEW_CHARACTERS:
POP AX ;Restore everything before departure.
POP BX
POP CX
POP DX
POP DI
POP SI
POP DS
STI
RET
PUT ENDP
ASSUME DS:CODE_SEG
INTERCEPT_TIMER PROC NEAR ;This completes filling the buffer
PUSHF ;Store used flags
PUSH DS ;Save DS since we'll change it
PUSH CS ;Put current value of CS into DS
POP DS
CALL ROM_TIMER ;Make obligatory call
PUSHF
CMP FINISHED_FLAG,1 ;Do we have to do anything?
JE OUT1 ;No, leave
CLI ;Yes, start by clearing interrupts
PUSH DS ;Save these.
PUSH SI
PUSH DX
PUSH BX
PUSH AX
ASSUME DS:ROM_BIOS_DATA ;Point to the keyboard buffer again.
MOV AX,ROM_BIOS_DATA
MOV DS,AX
MOV BX,TAIL ;Prepare to put characters in at tail
MOV FINISHED_FLAG,1 ;Assume we'll finish
MOV SI,COMMAND_INDEX ;Find where we left ourselves
STUFF2: MOV AX,WORD PTR PAD[SI] ;The same stuff loop as above.
ADD SI,2 ;Point to next command character.
CMP AX,0 ;Is it zero? (end of command)
JNE OVER ;No, continue.
JMP NO_NEW_CHARACTERS2 ;Yes, leave with Finished_Flag=1
OVER: MOV DX,BX ;Find position in buffer from BX
ADD DX,2 ;Move to next position for this word
CMP DX,OFFSET BUFFER_END ;Are we past the end?
JL NO_WRAP4 ;No, don't wrap
MOV DX,OFFSET BUFFER ;Do the Wrap rap.
NO_WRAP4:
CMP DX,HEAD ;Buffer full but not yet done?
JE BUFFER_FULL2 ;Time to leave, come back later.
ADD COMMAND_INDEX,2 ;Point to next word of command.
MOV [BX],AX ;Put into buffer
ADD BX,2 ;Point to next space in buffer
CMP BX,OFFSET BUFFER_END ;Wrap here?
JL NO_WRAP5 ;No, readjust buffer tail
MOV BX,OFFSET BUFFER ;Yes, wrap
NO_WRAP5:
MOV TAIL,BX ;Reset buffer tail
JMP STUFF2 ;Back to stuff in another character
BUFFER_FULL2:
MOV FINISHED_FLAG,0 ;Set flag to not-done-yet.
NO_NEW_CHARACTERS2:
POP AX ;Restore these.
POP BX
POP DX
POP SI
POP DS
OUT1: POPF ;And Exit.
POP DS
IRET ;With customary IRET
INTERCEPT_TIMER ENDP
LOAD_KEEPER PROC NEAR ;This procedure intializes everything
ASSUME DS:VECTORS ;The data segment will be the Interrupt area
MOV AX,VECTORS
MOV DS,AX
MOV AX,KEYBOARD_INT ;Get the old interrupt service routine
MOV OLD_KEYBOARD_INT,AX ;address and put it into our location
MOV AX,KEYBOARD_INT[2] ;OLD_KEYBOARD_INT so we can call it.
MOV OLD_KEYBOARD_INT[2],AX
MOV KEYBOARD_INT,OFFSET KEEPER ;Now load the address of our notepad
MOV KEYBOARD_INT[2],CS ;routine into the keyboard interrupt
MOV AX,TIMER_VECTOR ;Now same for timer
MOV ROM_TIMER,AX
MOV AX,TIMER_VECTOR[2]
MOV ROM_TIMER[2],AX
MOV TIMER_VECTOR,OFFSET INTERCEPT_TIMER
MOV TIMER_VECTOR[2],CS ;And intercept that too.
ASSUME DS:ROM_BIOS_DATA
MOV AX,ROM_BIOS_DATA
MOV DS,AX
MOV BX,OFFSET BUFFER ;Clear the keyboard buffer.
MOV HEAD,BX
MOV TAIL,BX
MOV AH,15 ;Ask for service 15 of INT 10H
INT 10H ;This tells us how display is set up
MOV STATUS_PORT,03BAH ;Assume this is a monochrome display
TEST AL,4 ;Is it?
JNZ EXIT ;Yes - jump out
MOV SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
MOV STATUS_PORT,03DAH
EXIT: MOV DX,OFFSET LOAD_KEEPER ;Set up everything but LOAD_PAD to
INT 27H ;stay and attach itself to DOS
LOAD_KEEPER ENDP
CODE_SEG ENDS
END FIRST ;END "FIRST" so 8088 will go to FIRST first.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -