如何在8086汇编语言中捕获定时器中断

huangapple go评论56阅读模式
英文:

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:

  1. 你的代码片段从 START: 标签开始,带有两个 DW ? 指令。它们将被执行,就好像它们是代码一样。你的代码在那里没有崩溃,这是一个奇迹。

  2. 为了绝对(甚至过于)正确,保存旧中断应该在 CLI/STI 块内完成,因为理论上有人可能在你保存它之后,但在你修补它之前进行更改。

  3. 你的 JС OVERFLOW_REACHED 跳转如果设置了 C 标志,但没有遵循任何会修改 C 标志的指令。(MOV 指令不会改变 C 标志。)因此,它可能会在中断抢占的代码设置 C 标志时跳转。这是一场灾难的前奏。

  4. 循环 LOOP TO_THE_SECOND_POWER 使用 CX 寄存器作为循环计数器。你没有在任何地方初始化 CX

  5. LOOP TO_THE_SECOND_POWER 之后,你没有采取任何有意义的措施来确保你的程序能够优雅地处理计算所有应该计算的数字的情况。

  6. 你的中断处理程序可能会调用 OVERFLOW_REACHED:,它将调用 INT 21H。这是一场灾难的前奏。不要从中断处理程序中调用任何操作系统函数。

简而言之,你的中断处理程序应该设置某个变量,通知主循环停止循环。

英文:
  1. Your code segment begins at the START: label with two DW ? directives. They will be executed as if they were code. The fact that your code does not crash right there is a miracle.

  2. 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.

  3. 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.

  4. Loop LOOP TO_THE_SECOND_POWER uses the CX register as a loop counter. You do not initialize CX anywhere.

  5. 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.

  6. Your interrupt handler may invoke OVERFLOW_REACHED:, which will invoke INT 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.

huangapple
  • 本文由 发表于 2023年4月11日 16:59:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75984100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定