Assembly 更改IRQ8 ISR

Assembly 更改IRQ8 ISR,assembly,x86-16,Assembly,X86 16,我想每隔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 b

我想每隔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
注释用于调试

还有两个问题-

  • 即使调用int 21h,是否也需要cli和sti命令
  • 当我回到操作系统时,我猜“Hello.”不会出现在内存中,但它会打印垃圾吗?如何将字符串添加到内存中
  • 非常感谢

    我想每55秒打印一次“你好”

    我相信你的意思是55毫秒,而不是纳米秒

    您不需要为此目的挂接任何中断处理程序。只需监视BIOS.TimerTick并在滴答声改变时打印消息。这就是下一个程序所做的。可执行文件将是一个.COM程序,它以
    CS
    =
    DS
    =
    ES
    =
    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命令行或用户应用程序)是首选程序。

    不要按下并弹出
    sp
    。由于8086和更新的处理器之间的
    push sp
    行为不同,这可能会导致问题。这样做也是完全没有用的。还要注意的是,在信号处理程序中不能安全地调用DOS系统调用,因为另一个DOS系统调用可能已经在进行中。不要那样做。相反,考虑为此使用BIOS服务。更多的问题:你做代码> PUPF;按下按钮,但不要按下按钮。既然CPU已经在进入信号处理程序时保护了标志,我想知道你为什么要这么麻烦。还要注意的是,您不能安全地恢复
    ds
    es
    ,但是(a)假设
    ds
    具有特定值,并且(b)覆盖
    es
    。两者都是错误的。您没有初始化ES,您退出程序时ISR仍在原位(如果需要,请使用TSR程序),并且您正在访问ISR中的程序数据段,而不知道DS中的实际内容。要调用旧向量,您需要执行(NASM语法)
    pushf
    \
    调用far[cs:old\u vec]
    而不是你想做的任何事情。(不平衡的)
    pushf
    是因为旧处理程序希望返回
    iret
    。通过先按下标志,然后让程序远调用旧向量,您可以让它创建一个堆栈帧,就像为中断调用创建的堆栈帧一样,由一个标志字、一个
    cs
    ,然后是一个
    ip
    。我向上投票。我想说的是BIOS也不一定是可重入的。报纸上有一条关于这一点的说明。“该程序负责匹配相应的等待和Post调用,并对设备驱动程序的访问进行序列化。BIOS代码不可重入。”