Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Keyboard interupt

Status
Not open for further replies.

jeclow

Programmer
Feb 22, 2003
6
0
0
US
Can somebody explain briefly explain to me how this code works and which part of the code asks for hitting cap once and 'A' 11 times? Thank you!!

.model small
.stack 10H
.data
flag2 db 0
flag3 db 0
rahul db 0
try db 'we can print out strings of any length up to 2^16-1=65535\'

numtry dw 0
keyorigs dw ?
keyorigo dw ?
flag1 db 0

.code
main proc
mov ax, @data
mov ds,ax

mov ax,0
mov es,ax
mov ax,36
mov di,ax
mov ax,es: [di]
mov keyorigo,ax
mov ax,es: [di+2]
mov keyorigs,ax
mov ax,offset keyisr
mov es: [di],ax
mov ax,seg keyisr
mov es: [di+2],ax



mov ah,0
mov al,2
int 10h

push di
push ax
push cx
mov cx,0
lea di,try
mov ah,'\'
unover:
cmp ah,[di]
je over
add cx,1
add di,1
jmp unover

over:
mov numtry,cx
pop cx
pop ax
pop di



mov ax,0B800H
mov es,ax
mov cx,numtry
label1:
mov di,numtry
sub di,cx
push di
mov ax,di
push di
lea di,try
add ax,di
pop di
mov di,ax
mov ah,[di]
pop di
add di,di

mov es:[di],ah
loop label1
label2:
cmp flag1, 10
jle label2

mov ax,keyorigo
mov es: [di],ax
mov ax,keyorigs
mov es: [di+2],ax
mov ah,4cH
int 21h
main endp


keyisr proc
push AX
push BX
push CX
push DX


in al,60h

cmp al,58
jne label3
xor flag2,1

label3:
cmp al,30
jne label5
cmp flag2,1
jne label5
inc flag1

label5:
in al, 61h
mov bl,al
or al, 80h
out 61h,al
mov al,bl
out 61h,al
mov al,20h
out 20h,al

pop DX
pop CX
pop BX
pop AX
iret

keyisr endp

end main



 
I didn't know how exactly to answer this, so I have just annotated the code. All questions should be answered in the comments. I suggest renaming some of the variables, eg. instead of 'flag1 dw 0' use 'no_of_As dw 0', so it makes more sense. Anyway, here is the code:
Code:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;  Keyboard Interrupt handler
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.model small
.stack 10H
.data
flag2 db 0  ; Capslock pressed status.
flag3 db 0  ; I don't know what these two are for...
rahul db 0  ; ...I can't see them in the program.
try   db 'we can print out strings of any length up to 2^16-1=65535\'

numtry dw 0     ; length of 'try'
keyorigs dw ?   ; Old key int segment.
keyorigo dw ?   ; Old key int offset.
flag1 db 0      ; Number of 'A's pressed.
    
.code

main proc
  mov ax, @data   ; Set data segment to address of DATA.
  mov ds,ax

  mov ax,0        ; ES=0
  mov es,ax
  mov ax,36       ; di=36  
  mov di,ax    
  mov ax,es:[di]  ; Save offset of original key int.
  mov keyorigo,ax 
  mov ax,es:[di+2]; Save segment of original key int.
  mov keyorigs,ax

  mov ax,offset keyisr 
  mov es:[di],ax      ; Replace with offset of new int.
  mov ax,seg keyisr
  mov es:[di+2],ax    ; Replace with segment of new int.
    
  mov ah,0
  mov al,2
  int 10h   ; Set videomode to B&W,80x25 text-resolution

  push di   ; Save neccesary registers
  push ax
  push cx

  mov cx,0
  lea di,try
  mov ah,'\'
unover:       ; This gets the length of 'try' string...
  cmp ah,[di]
  je over
  add cx,1
  add di,1
  jmp unover
over:
  mov numtry,cx  ; ... and saves in 'numtry'

  pop cx   ; Restore saved registers
  pop ax
  pop di

  mov ax,0B800H  ; Address for video page
  mov es,ax
  mov cx,numtry

label1:
  mov di,numtry  ; This is a way of outputting text
  sub di,cx      ; by directly changing video data
  push di        ; area (B800).
  mov ax,di      ; I think there is a bios int. that
  push di        ; would do the same job here...
  lea di,try
  add ax,di
  pop di
  mov di,ax
  mov ah,[di]
  pop di
  add di,di
  mov es:[di],ah
  loop label1

label2:         ; Basically a hanging loop.
  cmp flag1,10  ; The only way to exit is if flag1 > 10, ie 11.
  jle label2
      
  ; I think ES=0 should go here, ie.
  mov ax,0        ; ES=0
  mov es,ax
  
  mov ax,keyorigo   ; Restore the old interrupt offset/segment
  mov es:[di],ax
  mov ax,keyorigs
  mov es:[di+2],ax

  mov ah,4cH        ; DOS terminate program
  int 21h
main endp


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; New Key Interrupt:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
keyisr proc
  push AX      ; Saves neccessary registers.
  push BX
  push CX
  push DX

  in al,60h    ; Port 60h is for keyboard input.
  cmp al,58    ; al=scan code. If al isn't 58 (Capslock)...
  jne label3   ;   ...then goto label3.
  xor flag2,1  ; Sets flag2 to 1 if it is 0.

label3:            
  cmp al,30    ; al=scan code. If al isn't 30 ('A' key)...
  jne label5   ;   ...then goto label5.
  cmp flag2,1  ; If flag2 isn't 1 (capslock not pressed)...
  jne label5   ;   ...then goto label5.
  inc flag1    ; flag1 increased by 1 (count of 'A' presses).

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; This is quite a complicated low level input routine.
; Basically port 61h is used for getting/setting keyb state.
; Port 20h is the ISR(Interrupt Service Register),it sets up
; the interrupt controller (8259) - BEFORE iret(!)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
label5:        ; label5 = start of cleanup.
  in al,61h    ; Port 61h is PPI control. (basically key state)
  mov bl,al    ; Save al
  or al,80h    ; Enable keyboard access bit set
  out 61h,al   ; Send confirmation
  mov al,bl    ; Restore al
  out 61h,al   ; Send back to restore key state
  mov al,20h   ; EOI (End of Interrupt) code
  out 20h,al   ; Interupt processed.

  pop DX        ; Restore registers.
  pop CX
  pop BX
  pop AX    
  iret          ; Interrupt return.
keyisr endp
    
end main
Any problems, just buzz. Adonai :)
 
Thanks a lot man!!! Totally answer my question, and even better. U the best!!!!
 
Thanks adholioshake for very educational annotations! And for doing all the hard work!
Are there any good sources of info about how to process keyboard interrupts? The or-ing with 080h and sending to port 61h left me a bit puzzled about what was going on?

Here are a few extra minor comments about the original code, in case useful to orginal poster:

(1) it's probably better to use DOS to change interrupt vectors rather than doing it yourself. In any case, it's less work.
(2) It's not really necessary to find the length of 'try' at run-time. You can just put the correct value in the dw statement, and cut some code. If you like, make the compiler calculate the proper value for you so you can change the string without worrying.
Actually it's not hard to write a bit of string-outputing code that doesn't need to know the length of the code, anyway. Just stop at a particular character (and yes, DOS provides a call that does this, if you prefer not to write your own).
(3) the saving and restoring of registers with pushing and popping isn't terribly useful in this bit of code, because after popping cx ax and di, the next 4 instructions actually set those 3 registers...
(4) ditto the keyboard interrupt doesn't need to save cx and dx, since it doesn't use them. In this case it's actually verging on relevant, because normally you cannot be sure where the processor is when it is interrupted by a keyboard press. Although user programs usually have immense stack spaces, DOS guaruntees only a tiny stack, so too much pushing can easily cause a problem. It is not unlikely that a keyboard interrupt will be called from DOS, because no program lives in an interrupt-free environment, and no programmer can be utterly sure that s/he's not interrupting an interrupt....
 
Hi Lionelhill.
I agree the code isn't really optimal, but it does work. I think the writer wanted to be as low-level as possible, eg. changing Interrupt Vector Table directly, and using port 60h for keyboard input. Its good to write something like this for experience, as it does not rely on DOS interrupts, so you can see what the interrupt would actually need to do.

For everyday-code you are right, Lionelhill - its better to use the DOS interrupts (and BIOS) as these are guaranteed to work (and not screw your PC like own written ones can).
As for pushing too much, well I think everyone does it. Its probably routine,cos you would do it before most interrupts.

The very low-level stuff can be very useful - replacing the key interrupt needs to access port directly - what I suggest is instead of replacing the key interrupt completely, get the new interrupt to call the old interrupt at the end of all its processing, then you need not worry about all the technical bits from 'label5' downwards. This is the way most TSRs can get 'hotkeys'.

I learnt a lot about the ports from 'The Revolutionary Guide to Assembly Language'. Its quite old, but written by top Russian assemblers. I'm sure 'The Art of Assembly' has a chapter on low-level harware access too.
If you are keen, try searching the web (sometimes you get lucky), but I think visiting a local library is better. Enquire about books on assembly, and they can usually get hold of them.
Any more code for me to look at, just post it. I wrote a keylogging TSR a while back if anyone is interrested.
Adonai :)
 
Thanks for Lionelhill's advice.

Just another question. The part where I'm confused is the order of the execution. in the program, it compare flag1 to 10 in the main code, but flag1 is incremented in the keyisr proc. How do they effect each other? I thought when CPU execute the code, it should be like all the way down then end.

Thank you.
 
The 'keyisr' procedure is not run directly in the main program at all, which is why there is a seemingly endless loop at 'label2'. BUT because we have changed the interrupt for keyboard input, the procedure 'keyisr' is run everytime a key is pressed/released. It is this that can alter the value of 'flag1'. (The interrupt works by stopping the current execution of a program, running its own procedure, and then returning to the program's next instruction. For details of this look for fetch-execute cycle).

The code is not run all the way to the end, as at the end of 'main' there is the DOS terminate interrupt (int 21, sub 4C). This basically stops program running, frees memory used by program and returns control to the OS (or whatever else called it). Its probably equivelent to the following C code:
Code:
#include <stdio.h>
void function(void);

int main(void)
{
  return(0);
}

void function(void)
{
  printf(&quot;You can't see this as function is not called&quot;);
}
Although there is code after main, it is not executed.
If I've confused you more, sorry! Adonai :)
 
Thank you. The reply is very helpful.
I have another code here. If possible, could you please take a look at it and explain it a little bit to me?( doesn't have to be very very detailed. I also tried to put some comments in the code. if you found anything wrong, please feel free to correct it) There's still some errors in that code. If you can point out the error to me, I would really appreciate it. I have to add something to this code tonite, and I'll waiting for your reply. Thanks a lot!!

.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

INT 10h

MOV AX, VIDEO

MOV ES, AX ;MOVe Video to Extended Segment



call Output_Display ; clears the screen



MOV ax, 0h

MOV es, ax

MOV ax, 70h

MOV di, ax

MOV ax, es:[di]

MOV INT_28_offset, ax

MOV ax, offset Time_Int

MOV es:[di], ax ; Saves the first part of the int (70h)

MOV ax, es:[di+2]

MOV INT_28_seg, ax

MOV ax, seg Time_Int

MOV es:[di+2], ax ; Saves the second part of the interrupt





;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

MOV ax, 24h

MOV di, ax

MOV ax, es:[di]

MOV INT_9_offset, ax

MOV ax, offset My_INT_9 ;Stores the offset address of proc I9_hldr in ax

MOV es:[di], ax

MOV ax, es:[di+2]

MOV INT_9_seg, ax

MOV ax, seg My_INT_9 ;Stores the second part of the proc I9_hldr

MOV es:[di+2], ax



PROGRAMLOOP:



; while EndProgram is not 1 then loop

MOV ax, @data

MOV ds, ax



CMP EndProgram, 1 ; if end program then go to end of loop

JE ENDPROGRAMLOOP



CMP Same_Position, 1 ; if same position then go to

; Same_Position else continue loop

JNE PROGRAMLOOP



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:



jmp PROGRAMLOOP ;jumps to the PROGRAMLOOP



ENDPROGRAMLOOP:



cli ; disable interrupts



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 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

MOV ax, 70h

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, 4C00h

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, 'X'

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, 4000 ;set counter to 4000

MOV AL, '' ;set print character to a blank 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



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



;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 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



LP00:

PUSH CX

MOV CX, 000FFh

LP01:

LOOP LP01

POP CX

LOOP LP00



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

JMP LP1



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

MOV CX, 0FFFFh



LP4:

LOOP LP4



POP DI

POP ES

POP DX

POP CX

POP BX

POP AX



RET

Time_Int ENDP



;Produces a sound

SOUND PROC NEAR

PUSH AX

PUSH CX



MOV AX, 0B6h

OUT 43h, AX ;set port 43h with control word b6h



IN AL, 61h ; get initial speaker value

MOV BL, AL ; save present speaker statue

OR AL, 00000011B ; turn on speaker

OUT 61h, AL

MOV AL, 200 ; initial pitch



L1:

OUT 42h, AL ; timer port pulse speaker for better note

MOV CX, 5 ; create a delay loop for sound



L2:

PUSH CX

MOV CX, 0ffffh



L3:

loop L3

POP CX

loop L2

sub AL, 5 ; increase the pitch for better sound

OUT 42h, AL

jnz L1 ; play another note



MOV AL, BL ; turn off speaker and get original status

OUT 61h, AL

POP CX

POP AX



RET

sound ENDP



My_INT_9 PROC NEAR



My_INT_9 ENDP

END MAIN

 
Hi jeclow.
I have read through the code you wrote and have made some monor adjustments. Again I will post a commented out version of the code. I couldn't help much with the movement of 'X' because I don't know what the simulation is trying to show. I also removed the 'Sound' routine because: (a) it wasn't called in the program at all and (b) it wouldn't have worked as was using the wrong ports (I think!).
If sounds are neccessary I can post a code that does this.
Here's the code:
Code:
.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
That should help. Adonai :)
 
hi, just a newbies question, does this work on a .MODEL flat ? I know this thread is quite old, but it would help me a lot.

Thanks.

Nico.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top