首页 > 解决方案 > 更改 IRQ8 ISR

问题描述

我想打印“你好”。每 55ns。我究竟做错了什么?

.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

注释用于调试...

还有2个问题-

  1. 即使我调用 int 21h 是否需要 cli 和 sti 命令?
  2. 当我回到操作系统时,我猜是“你好”。不会在内存中,但它应该打印垃圾没有?以及如何将字符串添加到内存中?

非常感谢!!!

标签: assemblyx86-16

解决方案


我想打印“你好”。每 55ns

我相信您的意思是 55毫秒(ms) 而不是纳秒(ns)。

您不需要为此目标挂钩任何中断处理程序。只需监控 BIOS.TimerTick 并在滴答声发生变化时立即打印消息。这就是下一个程序所做的。CS可执行文件将是一个以== DS== ES==启动的 .COM 程序SS。该ORG 256指令是强制性的。

; 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, '$'

当然,可以通过挂钩计时器向量来执行此操作。在没有更多特殊要求的情况下,应该将 1Ch 向量挂钩,而将 08h 向量保留。

; 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, '$'
; --------------------------------
  • 使用 BIOS 输出功能可以避免 DOS 重入问题。
  • 将旧向量存储在远跳转指令上可以使您不必操作段寄存器。
  • 将消息放在代码段中便于访问。
  • 更改中断向量时,DOS 函数 25h 和 35h 很容易使用。

我使用了 FASM 汇编程序。即使您使用的是 MASM 风格的汇编器,您也可以从这些示例中学习...


尽管可以通过 TSR 完成上述所有操作,但将这么多文本字符快速连续地放在屏幕上将不可避免地造成真正的混乱!请记住,前台程序(DOS 命令行或用户应用程序)在使用屏幕时首先选择。


推荐阅读