Wongi Kim
Wongi Kim

Reputation: 21

8086 Assembly INT 9h : keyboard ISR implementation

I'm trying to override the default interruption when a key is pressed. Here is my code : do not call the kbd_handler and change 'port60' How can I resolve this? What do you think is causing it?

 MAIN SEGMENT PUBLIC                        
         ASSUME CS:MAIN, DS:DATA

         MOV AX, MAIN   ; Set up the Data Segment address
         MOV DS, AX
         mov bx, 9 * 4 ;find the int 9

         mov dx, word ptr [bx]
         push dx
         mov dx, word ptr [bx] + 2    
         push dx


         mov ax, DATA
         mov DS, ax
         mov es, ax

         ;mov bx, 09h * 04h
        mov bx, 9 * 4 ;find the int 9 
         cli                    ; disable an interrupt
         mov word ptr [bx],  offset kbd_handler ; load your keyboard ISR
         mov word ptr [bx] + 2, seg kbd_handler ;
         sti                    ;enable interrupts      

    TEST_2 :
        call printc
        call delay_cx
        jmp test_2

         mov ax, MAIN
         mov dx, ax

         mov bx, 09h * 04h ;find the int 9

         cli ; disable interrupt
         pop dx
         mov word ptr [bx], dx ;back to normal address
         pop dx
         mov word ptr [bx]+2, dx
         sti ; enalbe interrupts  

         MOV AH, 4CH                        ;
         INT 21H                  

    PUBLIC    kbd_handler

    kbd_handler PROC    NEAR
         push ax
         push bx
         push cx
         push dx                                          
         push sp
         push bp
         push si
         push di

         in al, 64h
         test al, 01h

         ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
         in al, 60h
         mov byte ptr ds:[port60], al   
         ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

         mov al, 20h
         out 20h, al

         pop di
         pop si
         pop bp
         pop sp
         pop dx
         pop cx
         pop bx
         pop ax    
         IRET
    kbd_handler ENDP

    PRINT PROC NEAR
        CLD ; 
    PRINT_1 :
        MOVSB
        MOV AL, DL
        STOSB
        LOOP PRINT_1
        RET
    PRINT ENDP

    delay_cx proc   near            ; 
    delay_1:        
        push    cx          ; 
        mov cx, 50          ; 
    delay_2:
        loop    delay_2         ; 
        pop cx          ; 
        loop    delay_1         ;
        ret             ; 
    delay_cx    endp


    PRINTC PROC NEAR
        MOV AL, port60
        MOV DL, AL
        MOV AH, 02H
        INT 21H
        RET
    PRINTC ENDP

    MAIN ENDS

    DATA SEGMENT
        msg1 db 'Press and hold ESC'
        msg2 db 'ESC pressed, release ESC'
        msg3 db 'ESC released'
        kbdbuf      db 128 dup (0)
        port60    db    '1'
    DATA ENDS

    END  

Upvotes: 2

Views: 1630

Answers (1)

Fifoernik
Fifoernik

Reputation: 9899

Several errors found in your code:

  • To retrieve and restore the interrupt vector you need to set the segment register of your choice to zero. Michael Petch made the same remark. So let's use the ES segment register.

    ...
    xor dx, dx
    mov es, dx
    mov dx, word ptr es:[bx]
    ...
    
  • When you saved the interrupt vector on the stack, you have to restore it in reverse order! You've done it the other way round.

  • In the new handler you can only use the CS segment register as an override straight on.

    in al, 60h
    mov byte ptr cs:[port60], al 
    
  • It's not useful to push/pop registers that you don't intend to change. Furthermore push sp and pop sp are always reduntant.

  • Since your main program loop uses an unconditional jump the code to restore things back to normal will never run.

    TEST_2 :
     call printc
     call delay_cx
     jmp test_2
    
     mov ax, MAIN  <-- You're code will never get here!
     mov dx, ax
    
  • When you use call delay_cx you still need to set the CX register to a suitable value.


I see that your program is still very much a work in progress. Lots of temporary code that isn't used anymore. Remove what isn't needed in order to not loose on readability.
Looking at the messages that you've written, I dare suggest that you delimit these in some way.

msg1 db 'Press and hold ESC',13,10,0
msg2 db 'ESC pressed, release ESC',13,10,0
msg3 db 'ESC released',13,10,0

Upvotes: 2

Related Questions