Assembly 基于DOS INT 8的移动星号不工作

Assembly 基于DOS INT 8的移动星号不工作,assembly,timer,int,dos,nasm,Assembly,Timer,Int,Dos,Nasm,我正在尝试编写一个TSR(DOS16bit),其中INT8的每一个记号都会在屏幕周围向前移动一个星号。我有4个子例程,它们的“*”位置增量不同,对应于相应的屏幕边框。但是,代码挂起,我也不能在调试器中同时运行所有代码,因为它取决于中断。请提出解决办法 pos: dw 158,3998,3838,0 routine: dw subrt1,subrt2,subrt3,subrt4 subrt1: add di,2

我正在尝试编写一个TSR(DOS16bit),其中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

我不是TSR方面的专家,但我确实看到了一些问题

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

其次,正如我在评论中指出的,我不理解3T838在pos中的值,也不理解汇编程序如何处理它。但我可能错过了什么

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

第四,我对传递给int 21h/ah=31h的参数不完全有信心;我能找到的文档表明dx应该设置为程序使用的段落数。您正在加载“start:”的地址,并将其乘以16(这实际上是一个段落的大小)。您可能需要再次检查此页面上的文档;我不知道这里应该放什么


祝你好运。我知道即使在TSR很普遍的时候,编写TSR也是一项具有挑战性的壮举。

我不是TSR方面的专家,但我确实看到了一些问题

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

其次,正如我在评论中指出的,我不理解3T838在pos中的值,也不理解汇编程序如何处理它。但我可能错过了什么

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

第四,我对传递给int 21h/ah=31h的参数不完全有信心;我能找到的文档表明dx应该设置为程序使用的段落数。您正在加载“start:”的地址,并将其乘以16(这实际上是一个段落的大小)。您可能需要再次检查此页面上的文档;我不知道这里应该放什么


祝你好运。我知道编写TSR是一项具有挑战性的壮举,即使在TSR司空见惯的时代也是如此。

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

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

这就是您如何解决问题的方法,这些问题主要与正确保存寄存器状态有关。见评论

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

别忘了说明您正试图为哪个平台编写代码。但这里最明显的问题是,据我所知,您没有链接原始的int8h处理程序。在执行您自己的代码之前,您应该链接到原始的8h处理程序。TSR?你是在20世纪80年代初跌入虫洞的吗???不,我的朋友,我来自第三世界国家。希望这能回答你的问题,但也请回答我的问题:)詹姆斯,经过测试和正确的链接没有问题请参见…………cli mov字[es:8*4]、计时器mov字[es:8*4+2]、cs sti…………我很难理解3T838在pos定义中应该代表什么值。我不熟悉“T”符号。别忘了说明您正试图为哪个平台编写代码。但这里最明显的问题是,据我所知,您没有链接原始的int8h处理程序。在执行您自己的代码之前,您应该链接到原始的8h处理程序。TSR?你是在20世纪80年代初跌入虫洞的吗???不,我的朋友,我来自第三世界国家。希望这能回答你的问题,但也请回答我的问题:)詹姆斯,经过测试和正确的链接没有问题请参见…………cli mov字[es:8*4]、计时器mov字[es:8*4+2]、cs sti…………我很难理解3T838在pos定义中应该代表什么值。我不熟悉“T”符号。对不起,伙计们,这是复制粘贴代码时引入的一个输入错误。这是3838个抱歉的家伙,这是复制粘贴代码时引入的一个输入错误。是3838