Ido Shany
Ido Shany

Reputation: 79

Change IRQ8 ISR

I want to print "Hello." every 55ns. what am I doing wrong?

.model small
.stack 100h

pusha MACRO
    push ax
    push bx
    push cx
    push dx
    push sp
    push bp
    push si
    push di
ENDM

popa MACRO
    pop di
    pop si
    pop bp
    pop sp
    pop dx
    pop cx
    pop bx
    pop ax
ENDM



.data
    old_vec dw 1  dup(?)
    old_seg dw 1  dup(?)
    HELLO db "HELLO.$"
    

.code
start:
    mov ax, @data
    mov ds, ax
    mov ax, es:[20h]
    mov bx, es:[20h+2] ;saving the old ISR ADDRESS
    mov old_vec, ax
    mov old_seg, bx
    mov es:[20h], OFFSET PRINT_HELLO ; setting the ivt to point to PRINT_HELLO
    mov es:[20h + 2], SEG PRINT_HELLO

    COMMENT @
    mov bx, offset old_vec
    mov ax, word ptr[bx]
    mov es:[20h], ax
    mov bx, offset old_seg
    mov ax, word ptr[bx]
    mov es:[20h+2], ax
    @

    ;for1:
    ;   jmp for1

    .exit
    mov ah, 4ch
    int 21h

PRINT_HELLO proc far
    pushf
    pusha
    mov ax, offset old_seg
    mov bx, ax
    mov es, word ptr[bx]
    mov bx, offset old_vec
    mov bx, word ptr[bx]
    call far PTR es:[bx] ; calling the old interrupt handler
    mov dx, offset HELLO
    mov ah, 09h
    int 21h
    popa
    iret
PRINT_HELLO endp


end

The comments are used for debugging...

2 more question -

  1. are the cli and sti commands necessary even if I call int 21h?
  2. When I go back to the OS, I guess that "Hello." won't be in memory, but it should print garbage no? and how do I add the String to memory?

Thanks a lot!!!

Upvotes: 2

Views: 222

Answers (1)

Sep Roland
Sep Roland

Reputation: 39676

I want to print "Hello." every 55ns

I believe you meant 55 milliseconds (ms) and not nanoseconds (ns).

You don't need to hook any interrupt handler for this objective. All it takes is monitoring the BIOS.TimerTick and print the message as soon as the tick changes. That's what next program does. The executable will be a .COM program that starts up with CS==DS==ES==SS. The ORG 256 directive is mandatory.

; This program prints a message every 55 milliseconds
; until a key is pressed

        ORG     256

        xor     ax, ax
        mov     es, ax
More:   mov     al, [es:046Ch]    ; BIOS.Timer
Wait:   cmp     al, [es:046Ch]
        je      Wait
        mov     dx, Msg
        mov     ah, 09h           ; DOS.PrintString
        int     21h
        mov     ah, 01h           ; BIOS.TestKey
        int     16h               ; -> AX ZF
        jz      More
        mov     ah, 00h           ; BIOS.GetKey
        int     16h               ; -> AX
        mov     ax, 4C00h         ; DOS.Terminate
        int     21h
; --------------------------------
Msg     db      'Hello, once every 55 milliseconds!', 13, 10, '$'

Of course it is possible to do this hooking the timer vector. In the absence of more special requirements, you should hook the 1Ch vector and leave the 08h vector be.

; This program prints a message every 55 milliseconds
; until a key is pressed

        ORG     256

        mov     ax, 351Ch         ; DOS.GetInterruptVector
        int     21h               ; -> ES:BX
        mov     [chain+1], bx
        mov     [chain+3], es

        mov     dx, int1C
        mov     ax, 251Ch         ; DOS.SetInterruptVector
        int     21h

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; In the 'main' part you can freely change DS, ES, and SS segment registers
main:   mov     ah, 01h           ; BIOS.TestKey
        int     16h               ; -> AX ZF
        jz      main
        mov     ah, 00h           ; BIOS.GetKey
        int     16h               ; -> AX
; In the 'main' part you can freely change DS, ES, and SS segment registers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        mov     dx, [cs:chain+1]
        mov     ds, [cs:chain+3]
        mov     ax, 251Ch         ; DOS.SetInterruptVector
        int     21h
        mov     ax, 4C00h         ; DOS.Terminate
        int     21h
; --------------------------------
int1C:  push    ax bx si
        cld
        mov     bx, 0007h         ; DisplayPage and GraphicsColor
        mov     si, Msg
.more:  lods byte [cs:si]
        mov     ah, 0Eh           ; BIOS.Teletype
        int     10h
        cmp     al, 10
        jne     .more
        pop     si bx ax    
chain:  jmp far 0:0               ; Chaining to the old interrupt handler
Msg:    db      'Hello, once every 55 milliseconds!', 13, 10, '$'
; --------------------------------
  • Using a BIOS output function avoids the DOS reentrancy problem.
  • Storing the old vector over the far jump instruction saves you from having to manipulate the segment registers.
  • Putting the message in the code segment makes for an easy access.
  • DOS functions 25h and 35h are easy to use when changing interrupt vectors.

I used the FASM assembler. Even if you're using a MASM style assembler can you learn from these examples...


Although it is possible to do all the above from a TSR, putting this many text characters on the screen in rapid succession will inevitably make a real mess! Do remember that the foreground program (DOS command line or user application) has first pick when it comes to using the screen.

Upvotes: 4

Related Questions