英文:
how do I catch the timer interrupt in 8086 assembly language
问题
我使用TASM和DOSBox来解决一个问题。我必须捕获定时器中断并输出自然数的平方,直到它们达到16位长度。在我的教授提供的示例中,08h中断被替换为一个新的中断,但这不是一个好的做法,因为改变08h可能导致故障。据我所知,更好的方法是切换1ch中断,它由08h每18.2毫秒触发,不会对计算机造成任何必要的影响。此外,阅读我的教授的代码让我感到困惑。
我编写了以下代码,但它似乎无法按预期工作,它确实输出了平方,但在随机时刻停止执行,我不明白我漏掉了什么。感谢阅读,如果有任何帮助将不胜感激。
(请注意,我只翻译了文本,未包括代码部分。)
英文:
I am using tasm and dosbox to solve a problem. I have to catch the timer interrrupt and output all squares of natural numbers until they have 16-bit length. In the example my professor provides the 08h interrupt is replaced with a new one, which is not a good thing to do, since altering 08h can lead to malfunction. As far as I know it is much better to toggle 1ch interrupt, which is triggered by 08h every 18,2 ms and does not do anything necessary to the computer. Moreover reading my professor's code has left me with a great number of whats and whys.
I wrote the following code, but it does not seem do work as intended, it does output squares, however, it stops execution at a random moment of time and I do not understand what I am missing. Any help would be appreciated, thanks for reading
.MODEL SMALL
.STACK 1024H
.DATA
NUM DB 1
SQUARE DW ?
.CODE
ASSUME CS:@CODE, DS:@DATA, ES:NOTHING
START:
OLD_INT_SEG DW ?
OLD_INT_OFF DW ?
MOV AX, @DATA
MOV DS, AX
;saving away the old interrupt;
MOV AX, 0
MOV ES, AX
MOV AX, ES:[1CH * 4]
MOV WORD PTR OLD_INT_OFF, AX
MOV AX, ES:[1CH * 4 + 2]
MOV WORD PTR OLD_INT_SEG, AX
;patching into the new one;
CLI
MOV WORD PTR ES:[1CH * 4], OFFSET TIMER_ISR
MOV WORD PTR ES:[1CH * 4 + 2], CS
STI
;calculating squares;
TO_THE_SECOND_POWER:
XOR AX, AX
MOV AL, NUM
MUL NUM
;outputing them;
CALL PRINT_NUM
INC NUM
LOOP TO_THE_SECOND_POWER
;the new isr's body;
TIMER_ISR PROC NEAR
PUSH DS
PUSH AX
MOV AX, @DATA
MOV DS, AX
JС OVERFLOW_REACHED
POP AX
POP DS
;calling the original 1ch isr;
JMP CS:OLD_INT_OFF
TIMER_ISR ENDP
PRINT_NUM PROC
PUSH BX
PUSH DX
PUSH SI
PUSH CX
MOV CX, 0
MOV BX, 10
LOOP_HERE:
MOV DX, 0
DIV BX
PUSH AX
ADD DL, "0"
POP AX
PUSH DX
INC CX
CMP AX, 0
JNZ LOOP_HERE
MOV AH, 2
LOOP_HERE_2:
POP DX
MOV AH, 02H
INT 21H
LOOP LOOP_HERE_2
MOV DL, 10
MOV AH, 02H
INT 21H
MOV DL, 13
MOV AH, 02H
INT 21H
POP CX
POP SI
POP DX
POP BX
RET
PRINT_NUM ENDP
;if overflow has occurred;
OVERFLOW_REACHED:
;restoring the old isr;
MOV AX, 0
MOV ES, AX
CLI
MOV AX, WORD PTR OLD_INT_OFF
MOV ES:[1CH * 4], AX
MOV AX, WORD PTR OLD_INT_SEG
MOV ES:[1CH * 4 + 2], AX
STI
;and terminating the program;
MOV AH, 4CH
MOV AL, 0H
INT 21H
END START
CODE ENDS
答案1
得分: 1
Here are the translated code-related segments:
-
你的代码片段从
START:
标签开始,带有两个DW ?
指令。它们将被执行,就好像它们是代码一样。你的代码在那里没有崩溃,这是一个奇迹。 -
为了绝对(甚至过于)正确,保存旧中断应该在
CLI
/STI
块内完成,因为理论上有人可能在你保存它之后,但在你修补它之前进行更改。 -
你的
JС OVERFLOW_REACHED
跳转如果设置了 C 标志,但没有遵循任何会修改 C 标志的指令。(MOV 指令不会改变 C 标志。)因此,它可能会在中断抢占的代码设置 C 标志时跳转。这是一场灾难的前奏。 -
循环
LOOP TO_THE_SECOND_POWER
使用CX
寄存器作为循环计数器。你没有在任何地方初始化CX
。 -
在
LOOP TO_THE_SECOND_POWER
之后,你没有采取任何有意义的措施来确保你的程序能够优雅地处理计算所有应该计算的数字的情况。 -
你的中断处理程序可能会调用
OVERFLOW_REACHED:
,它将调用INT 21H
。这是一场灾难的前奏。不要从中断处理程序中调用任何操作系统函数。
简而言之,你的中断处理程序应该设置某个变量,通知主循环停止循环。
英文:
-
Your code segment begins at the
START:
label with twoDW ?
directives. They will be executed as if they were code. The fact that your code does not crash right there is a miracle. -
To be perfectly (paranoidly so) correct, saving away the old interrupt should be done inside the
CLI
/STI
block, because in theory someone might change it after you have saved it and before you patched it. -
Your
JС OVERFLOW_REACHED
jumps if the C flag was set, but does not follow any instructions that would modify the C flag. (MOV instructions do not alter the C flag.) Therefore, it will probably jump if the C flag was set by whatever code was pre-empted by the interrupt. That's a recipe for disaster. -
Loop
LOOP TO_THE_SECOND_POWER
uses theCX
register as a loop counter. You do not initializeCX
anywhere. -
After
LOOP TO_THE_SECOND_POWER
you are not doing anything meaningful to ensure that your program will gracefully handle the case where it computes all numbers that were to be computed. -
Your interrupt handler may invoke
OVERFLOW_REACHED:
, which will invokeINT 21H
. That's a recipe for disaster. Do not invoke any operating system functions from within an interrupt handler.
In short, your interrupt handler should set some variable to inform your main loop that it should stop looping.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论