.MODEL small
.STACK 100h
.DATA
VIDEO EQU 0B800h ; set video page
Char_X EQU 'X' ; set character X
Mem_offset_X DW 0640 ; default position for 'X' on screen
Mem_offset_Star DW 3920 ; default position for '*' on screen
New_offset_X DW 0640 ; stores the current positon of X
New_offset_Star DW 3920 ; stores the current position of *
INT_9_offset DW ? ; stores offset of INT 9
INT_9_seg DW ? ; stores segment address of INT 9
INT_28_offset DW ?
INT_28_seg DW ?
KB_BUFFER DB 0 ; stores user input
Same_Position DB 0 ; boolean for same position
X_Limit DW ?
EndProgram db 0 ; boolean for stopping program
Equal_Flag DB 1 ; FLAG set to 0
KEYrel DB 0 ; key release flag
.CODE
MAIN PROC FAR
MOV AX,@data
MOV DS,AX ; Move data to Data Segment
MOV ah,0
MOV al,2 ; B&W, 80x25 txt-res, scr-addr=B800h
int 10h ; ...OK
MOV AX,VIDEO
MOV ES,AX ; Move Video to Extended Segment
call Output_Display
MOV ax,0h ; ES is zero for Interrupt Vector Table
MOV es,ax
MOV ax,70h ; Offset for time interrupt.
MOV di,ax
cli ; Adonai: Always best to disable interrupts before.
MOV ax,es:[di]
MOV INT_28_offset,ax ; This saves interrupt offset...
MOV ax,offset Time_Int
MOV es:[di],ax ; ...and this replaces int offset.
MOV ax,es:[di+2]
MOV INT_28_seg,ax ; This saves interrupt segment...
MOV ax,seg Time_Int
MOV es:[di+2],ax ; ...and this replaces int seg.
;Initializes Keyboard Interrupt (Int9h)
; restores the ds segment so we can use INT_9_seg and offset
; MOV ax,@data
; MOV ds,ax
; MOV ax,0h
; MOV es,ax
; Adonai: Nothing has changed the data segment, so why does
; it need to be restored?
; The ES is already at zero for IVT.
MOV ax,24h ; Offset for keyboard interrupt.
MOV di,ax
MOV ax,es:[di]
MOV INT_9_offset, ax ; Save offset of int 9...
MOV ax,offset My_INT_9
MOV es:[di],ax ; ...replace it with new offset.
MOV ax,es:[di+2]
MOV INT_9_seg,ax ; Save segment of int 9...
MOV ax,seg My_INT_9
MOV es:[di+2],ax ; ...replace it with new seg.
; Adonai: At the moment the procedure 'My_INT_9' doesn't do
; any processing. This is probably why the program
; doesn't end.
sti ; Adonai: Restore interrupts after replaced.
PROGRAMLOOP:
; while EndProgram is not 1 then loop
; MOV ax, @data
; MOV ds, ax
; Adonai: Data segment hasn't changed, no need to reasign.
CMP EndProgram,1 ; if end program then go to end of loop
JE ENDPROGRAMLOOP ; OK.
jmp ProgramLoop
;CMP Same_Position, 1 ; if same position then go to
; Same_Position else continue loop
;JNE PROGRAMLOOP ; OK, but...
; Adonai: 'Same_positionLOOP' does the same processing as
; 'PROGRAMLOOP', so why is it neccessary?
;Same_PositionLOOP:
; if same position then wait until a key is pressed
;cmp EndProgram, 1 ; if end program then finish program
;je ENDPROGRAMLOOP
;jmp Same_PositionLOOP
;ENDNOOPLOOP: ; Adonai: What is this label used for?
;jmp PROGRAMLOOP ; jumps to the PROGRAMLOOP
ENDPROGRAMLOOP:
cli ; disable interrupts
; Adonai: The 20h sent to port 20h indicates End of Interrupt.
; Why is it being used here ? It should be within an
; interrupt procedure itself.
; MOV al,20h ;restores the data segment so INT_28_seg
; out 20h,al ; and offset can be used
; Restores the keyboard Interrupt
MOV ax,0h
MOV es,ax
; MOV ax,24h
mov ax,70h
MOV di,ax
MOV ax,INT_28_offset
MOV es:[di],ax
MOV ax,INT_28_seg
MOV es:[di+2],ax
;Restores the timer Interrupt
; MOV ax,0h
; MOV es,ax
; Adonai: ES is already zero.
; MOV ax,70h
mov ax,24h ; Adonai: restore the right interrupt vectors!
MOV di,ax
MOV ax,INT_9_offset
MOV es:[di],ax
MOV ax,INT_9_seg
MOV es:[di+2],ax
sti ;Re-enable interrupts
mov ax,VIDEO
mov es,ax
call Clear_Screen
MOV AX,4C00h ; Terminate: OK
INT 21h
MAIN ENDP
Output_Display PROC NEAR
PUSH DI
PUSH AX
PUSH BX
PUSH DX
CALL Clear_Screen ; Clear the screan before display X and *
MOV DI,Mem_offset_X
MOV AL,Char_X ; Adonai: Keep variable as standard.
MOV ES:[DI], AL ; display X
MOV DI,Mem_offset_Star
MOV AL,'*'
MOV ES:[DI], AL ; display *
POP DX
POP BX
POP AX
POP DI
RET
Output_Display ENDP
Clear_Screen PROC NEAR
PUSH DI
PUSH CX
PUSH AX
XOR DI,DI ;reset DI register
MOV CX,2000 ;set counter to 4000
MOV AL,' ' ;set print character to a blank space
; Adonai: Doesn't the counter only have to be 2000 for a
; 80x25 screen? AL should have a space, ' '.
again:
MOV ES:[DI], AL ;print blank character on entire screen
INC DI
INC DI ;increament index by 2 for next print area
LOOP again
; Adonai: Instead of two INC's, why not 'ADD DI,02' ?
POP AX
POP CX
POP DI
RET
CLEAR_SCREEN ENDP
;Allow user to capture the MOVemtn of 'X'
Time_Int PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSh DX
PUSH ES
PUSH DI
; Adonai: Missing vital piece here - VIDEO address.
mov ax,VIDEO
mov es,ax
;this is a test, not the actual function content
MOV DI,New_offset_Star
MOV AL,'*'
MOV ES:[DI],AL ; display *
;this is the actual function content
LP1:
PUSH BX ; calculate the last column position
PUSH AX ; for the current position of 'X'
PUSH DX
MOV DI,New_offset_X ; output a blank space to replace the previous 'X'
MOV AL, ' '
MOV ES:[DI],AL
MOV CX,0FFFFh
MOV BX,X_Limit
CMP New_offset_X, BX ; reposition the 'X' if it is on the edge of the screen
JBE LP2
SUB New_offset_X, 160
LP2:
INC New_offset_X ; MOVe the 'X' to the next position
INC New_offset_X
; Start previous LP1...
MOV AX,New_offset_X
MOV BL,160
DIV BL
INC AX
MUL BL
SUB AX, 4h
MOV X_Limit,AX
POP DX
POP AX
POP BX
MOV DI,New_offset_X
MOV AL,Char_X
MOV ES:[DI],AL
MOV CX,0FFFFh
MOV BX,New_offset_Star ; exit if 'X' and '*' are at the same position
CMP New_offset_X, BX
JE LP3
;JMP LP1
jmp My_Time_exit
; Adonai: Don't use loops for delay within a time interrupt.
LP3:
MOV Same_Position, 1 ; set flag indicating 'X' and '*' are at the same place
MOV DI,New_offset_X
MOV AL,' '
MOV ES:[DI], AL
My_Time_exit:
POP DI
POP ES
POP DX
POP CX
POP BX
mov al,20h ; Need this in here to show end of interrupt.
out 20h,al
POP AX
iret
Time_Int ENDP
My_INT_9 PROC NEAR
; Adonai:
; You need to do something in here for the program to work.
; This code simply terminates program when key is pressed.
; Probably more elaborate stuff is supposed to go here -
; hence variables 'KB_BUFFER' and 'KEYrel' ?
mov EndProgram,01
mov al,20h ; Need this in here to show end of interrupt.
out 20h,al
iret
My_INT_9 ENDP
END MAIN