基于DOS INT 8的移动星号不起作用

时间:2012-03-11 20:24:18

标签: assembly timer int dos nasm

我正在尝试编写TSR(DOS 16BIT)代码,其中INT8的每个刻度都会在屏幕周边向前移动一个星号。我有4个子程序,其'*'位置的不同增量对应于相应的屏幕边框。但是,代码挂起,我无法在调试器中同时运行它,因为它取决于中断。请提出解决方案

pos:        dw      158,3998,3838,0
routine:    dw      subrt1,subrt2,subrt3,subrt4

subrt1:     
            add di,2
            cmp di,[pos]
            jnz exit
            add bx,2

exit:       ret 

subrt2:     add di,160
            cmp di,[pos+2]
            jnz exit
            add bx,2
            ret 

subrt3:     sub di,2
            cmp di,[pos+4]
            jnz exit
            add bx,2
            ret
subrt4:     sub di,160
            cmp di,[pos+6]
            jnz exit
            mov bx,0
            ret


timer:      push ax

            mov ax,0xb800
            mov es,ax

            mov word[es:di],0x720
            call [routine+bx]           
            mov word[es:di],0x742

            mov al,0x20
            out 0x20,al
            pop ax
            iret

start:      xor ax,ax
            xor bx,bx
            mov es,ax
            cli
            mov word[es:8*4],timer
            mov word[es:8*4+2],cs
            sti
            mov dx,start
            add dx,15
            mov cl,4
            shr dx,cl
            mov ax,0x3100
            int 0x21

2 个答案:

答案 0 :(得分:3)

这就是你解决问题的方法,主要是正确保存寄存器状态。见评论。

org 0x100 ;; missing?
jmp start ;; missing?

pos:        dw      158,3998,3840,0 ;; what is 3T838?
routine:    dw      subrt1,subrt2,subrt3,subrt4
state       dw      0 ;; storage for bx
curpos      dw      0 ;; storage for di
oldisr      dd      0 ;; address of old timer interrupt ISR

subrt1:     
            add di,2
            cmp di,[pos]
            jnz exit
            add bx,2

exit:       ret 

subrt2:     add di,160
            cmp di,[pos+2]
            jnz exit
            add bx,2
            ret 

subrt3:     sub di,2
            cmp di,[pos+4]
            jnz exit
            add bx,2
            ret

subrt4:     sub di,160
            cmp di,[pos+6]
            jnz exit
            mov bx,0
            ret


timer:      push ax
            push bx ;; must preserve bx
            push di ;; must preserve di
            push ds ;; must preserve ds
            push es ;; must preserve es

            push cs ;; must load cs into ds to access pos,routine,state,curpos
            pop ds

            mov ax,0xb800
            mov es,ax

            mov di, [curpos] ;; must retrieve di from storage
            mov bx, [state] ;; must retrieve bx from storage

            mov word[es:di],0x720

            call [routine+bx]

            mov word[es:di],0x72A ;; you need 42 decimal (2A hex), not 42 hex

            mov [curpos], di ;; must preserve di between ints
            mov [state], bx ;; must preserve bx between ints

            ;mov al,0x20 ;; remove int acknowledge as the old ISR will do it for us
            ;out 0x20,al

            pop es ;; must restore es
            pop ds ;; must restore ds
            pop di ;; must restore di
            pop bx ;; must restore bx
            pop ax

            ;iret ;; instead of direct iret continue in the old ISR
            jmp far [cs:oldisr] ;; to prevent undesired effects (hangs/crashes)

start:      xor ax,ax
            ; xor bx,bx ;; unnecessary
            mov es,ax
            cli

            push word[es:8*4] ;; remember old ISR address
            push word[es:8*4+2]
            pop word[oldisr+2]
            pop word[oldisr]

            mov word[es:8*4],timer
            mov word[es:8*4+2],cs
            sti
            mov dx,start
            add dx,15
            mov cl,4
            shr dx,cl
            mov ax,0x3100
            int 0x21

答案 1 :(得分:1)

我不是TSR的专家,但我确实在这里看到了许多问题。

首先,我同意James Youngman的评论 - 我没有看到你在哪里链接原始的中断处理程序。您在对James的后续评论中引用的代码只是安全替换现有中断处理程序的代码(在替换期间禁用中断,因此没有竞争条件)。这还不够。您需要保存段:该处理程序的地址,并在完成处理程序后调用该处理程序。

其次,正如我在评论中指出的那样,我不理解pos中的3T838值并且不理解汇编程序如何处理它。但我可能会遗漏一些东西。

第三,当您进入处理程序时,您无法预测任何上下文。您基于bx(“call [routine + bx]”)进行分支,但bx未设置为“timer:”标签与该调用指令之间的任何内容。实际上,bx可以是任何东西。如果您希望bx是从中断到中断的运行值,则需要将其值保存在单独的变量中,在处理程序的开头将该变量移动到bx,并在离开之前将其保存回来。这也适用于di寄存器,我没有观察到在代码中任何地方进行初始化。

第四,我对你传递给int 21h / ah = 31h的参数并不完全有信心;我能找到的文档表明dx应该设置为程序使用的段落数。您正在加载“start:”的地址并将其乘以16(实际上是段落的大小)。您可能需要仔细检查这方面的文档;我不确定该怎么回事。

祝你好运。我知道写TSR是一项具有挑战性的壮举,即使在它们普遍存在的时代也是如此。