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

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

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

  1. .MODEL SMALL
  2. .STACK 1024H
  3. .DATA
  4. NUM DB 1
  5. SQUARE DW ?
  6. .CODE
  7. ASSUME CS:@CODE, DS:@DATA, ES:NOTHING
  8. START:
  9. OLD_INT_SEG DW ?
  10. OLD_INT_OFF DW ?
  11. MOV AX, @DATA
  12. MOV DS, AX
  13. ;saving away the old interrupt;
  14. MOV AX, 0
  15. MOV ES, AX
  16. MOV AX, ES:[1CH * 4]
  17. MOV WORD PTR OLD_INT_OFF, AX
  18. MOV AX, ES:[1CH * 4 + 2]
  19. MOV WORD PTR OLD_INT_SEG, AX
  20. ;patching into the new one;
  21. CLI
  22. MOV WORD PTR ES:[1CH * 4], OFFSET TIMER_ISR
  23. MOV WORD PTR ES:[1CH * 4 + 2], CS
  24. STI
  25. ;calculating squares;
  26. TO_THE_SECOND_POWER:
  27. XOR AX, AX
  28. MOV AL, NUM
  29. MUL NUM
  30. ;outputing them;
  31. CALL PRINT_NUM
  32. INC NUM
  33. LOOP TO_THE_SECOND_POWER
  34. ;the new isr's body;
  35. TIMER_ISR PROC NEAR
  36. PUSH DS
  37. PUSH AX
  38. MOV AX, @DATA
  39. MOV DS, AX
  40. JС OVERFLOW_REACHED
  41. POP AX
  42. POP DS
  43. ;calling the original 1ch isr;
  44. JMP CS:OLD_INT_OFF
  45. TIMER_ISR ENDP
  46. PRINT_NUM PROC
  47. PUSH BX
  48. PUSH DX
  49. PUSH SI
  50. PUSH CX
  51. MOV CX, 0
  52. MOV BX, 10
  53. LOOP_HERE:
  54. MOV DX, 0
  55. DIV BX
  56. PUSH AX
  57. ADD DL, "0"
  58. POP AX
  59. PUSH DX
  60. INC CX
  61. CMP AX, 0
  62. JNZ LOOP_HERE
  63. MOV AH, 2
  64. LOOP_HERE_2:
  65. POP DX
  66. MOV AH, 02H
  67. INT 21H
  68. LOOP LOOP_HERE_2
  69. MOV DL, 10
  70. MOV AH, 02H
  71. INT 21H
  72. MOV DL, 13
  73. MOV AH, 02H
  74. INT 21H
  75. POP CX
  76. POP SI
  77. POP DX
  78. POP BX
  79. RET
  80. PRINT_NUM ENDP
  81. ;if overflow has occurred;
  82. OVERFLOW_REACHED:
  83. ;restoring the old isr;
  84. MOV AX, 0
  85. MOV ES, AX
  86. CLI
  87. MOV AX, WORD PTR OLD_INT_OFF
  88. MOV ES:[1CH * 4], AX
  89. MOV AX, WORD PTR OLD_INT_SEG
  90. MOV ES:[1CH * 4 + 2], AX
  91. STI
  92. ;and terminating the program;
  93. MOV AH, 4CH
  94. MOV AL, 0H
  95. INT 21H
  96. END START
  97. 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:

确定