DOS INT 8 на основе движущейся звездочки не работает - PullRequest
0 голосов
/ 12 марта 2012

Я пытаюсь кодировать 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 ]

3 голосов
/ 12 марта 2012

Это то, как вы исправляете свои проблемы, которые в основном связаны с правильным сохранением состояния реестра.Смотрите комментарии.

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 голос
/ 12 марта 2012

Я не эксперт по TSR, но я вижу здесь ряд проблем.

Во-первых, я согласен с комментарием Джеймса Янгмана - я не вижу, куда вы цепляете оригинальный обработчик прерываний. Код, который вы процитировали в своем последующем комментарии к Джеймсу, - это просто код для безопасной замены существующего обработчика прерываний (отключение прерываний во время замены, чтобы не было условия гонки). Этого не достаточно. Вам нужно сохранить сегмент: адрес этого обработчика и вызвать этот обработчик, когда вы закончите с обработчиком.

Во-вторых, как я указал в своем комментарии, я не понимаю значение 3T838 в pos и не понимаю, как ассемблер может это обработать. Но я могу что-то упустить.

В-третьих, вы не можете ожидать какого-либо контекста при вводе обработчика. Вы выполняете ветвление на основе bx («call [рутина + bx]»), но для bx не установлено ничего между меткой «timer:» и этой инструкцией вызова. Действительно, здесь может быть что угодно. Если вы ожидаете, что bx будет рабочим значением от прерывания до прерывания, вам нужно сохранить его значение в отдельной переменной, переместив эту переменную в bx в начале обработчика и сохранив его обратно перед выходом. Это касается и регистра di, который я не наблюдаю как инициализированный в любом месте в вашем коде.

В-четвертых, я не совсем уверен в параметрах, которые вы передаете в int 21h / ah = 31h; документация, которую я могу найти, указывает, что dx должен быть установлен на количество абзацев, которые использует ваша программа. Вы загружаете адрес «start:» и умножаете его на 16 (это действительно размер абзаца). Вы можете перепроверить документы по этому вопросу; Я не уверен, что должно идти сюда.

Удачи. Я понимаю, что написание TSR было сложным делом даже в те дни, когда они были обычным явлением.

...