assembly Motorola 68000汇编代码:未显示在Easy68k模拟器应用程序中

yshpjwxd  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(187)

说明:程序演示了一个简化的printf函数(printg),它是硬编码的,什么都没有播放。我不知道为什么。

  1. ORG $8000
  2. START:
  3. ; Push parameters onto the stack (right-to-left)
  4. MOVE.L #300, -(SP) ; Push the sixth number
  5. MOVE.L #11, -(SP) ; Push the fifth number
  6. MOVE.L #134212, -(SP) ; Push the fourth number
  7. MOVE.L #92, -(SP) ; Push the third number
  8. MOVE.L #51, -(SP) ; Push the second number
  9. MOVE.L #23, -(SP) ; Push the first number
  10. ; Push the address of the format string onto the stack
  11. LEA FMT, A0 ; Load the address of FMT into A0
  12. MOVE.L A0, -(SP) ; Push the address onto the stack
  13. ; Call printg subroutine
  14. BSR printg
  15. ; Clean up the stack
  16. ADDA.L #28, SP ; Remove all six 32-bit numbers and the format string address
  17. ; Rest of the program or exit
  18. SIMHALT ; Stop simulation
  19. printg:
  20. ; Save registers that will be used
  21. MOVE.L A0, -(SP) ; Save A0
  22. MOVE.L D0, -(SP) ; Save D0
  23. MOVE.L D1, -(SP) ; Save D1
  24. ; Call LENGTH to get the number of integers to print
  25. MOVEA.L 8(SP), A0 ; Move the address of the format string into A0
  26. BSR LENGTH ; Call LENGTH, result will be in D0
  27. MOVE.B D0, D1 ; Store the number of integers in D1
  28. ; Calculate the starting address of the integers on the stack
  29. ADDA.L #4, SP ; Adjust stack pointer to the first integer
  30. PRINT_LOOP:
  31. ; Check if we have processed all format characters
  32. DBF D1, END_PRINT ; Decrement D1 and branch if D1 is -1
  33. ; Get the next format character
  34. MOVE.B (A0)+, D0 ; Move the next format character into D0
  35. ; Determine the base for the DISPLAY subroutine
  36. CMP.B #'B', D0
  37. BEQ DISPLAY_BINARY
  38. CMP.B #'0', D0
  39. BEQ DISPLAY_OCTAL
  40. CMP.B #'D', D0
  41. BEQ DISPLAY_DECIMAL
  42. CMP.B #'H', D0
  43. BEQ DISPLAY_HEXADECIMAL
  44. BRA PRINT_LOOP ; If the character is not B, O, D, or H, skip it
  45. DISPLAY_BINARY:
  46. MOVE.B #2, -(SP) ; Push base 2 for binary
  47. BRA CALL_DISPLAY
  48. DISPLAY_OCTAL:
  49. MOVE.B #8, -(SP) ; Push base 8 for octal
  50. BRA CALL_DISPLAY
  51. DISPLAY_DECIMAL:
  52. MOVE.B #10, -(SP) ; Push base 10 for decimal
  53. BRA CALL_DISPLAY
  54. DISPLAY_HEXADECIMAL:
  55. MOVE.B #16, -(SP) ; Push base 16 for hexadecimal
  56. CALL_DISPLAY:
  57. ; Calculate the offset for the current integer
  58. MOVE.L D1, D2 ; Copy the index to D2
  59. LSL.L #2, D2 ; Multiply the index by 4 to get the byte offset
  60. LEA (SP), A1 ; Load the address of the first integer into A1
  61. ADDA.L D2, A1 ; Add the offset to the address
  62. MOVE.L (A1), D1 ; Move the integer at the calculated offset into D1
  63. MOVE.L D2, -(SP) ; Push the base onto the stack
  64. MOVE.L D1, -(SP) ; Push the integer onto the stack
  65. BSR DISPLAY ; Call DISPLAY subroutine
  66. ADDA.L #8, SP ; Clean up the stack (base + integer)
  67. BRA PRINT_LOOP ; Process the next character
  68. END_PRINT:
  69. ; Restore the original stack pointer position
  70. SUBA.L #4, SP ; Adjust stack pointer back to the format string address
  71. ; Restore registers
  72. MOVE.L (SP)+, D1 ; Restore D1
  73. MOVE.L (SP)+, D0 ; Restore D0
  74. MOVE.L (SP)+, A0 ; Restore A0
  75. RTS ; Return from subroutine
  76. LENGTH:
  77. MOVE.L A0, -(SP) ; Save A0 on the stack
  78. CLR.B D0 ; Initialize the length counter to 0
  79. LENGTH_LOOP:
  80. MOVE.B (A0)+, D1 ; Load the next character from the format string
  81. BEQ LENGTH_DONE ; If the character is null (0), we are done
  82. ADDQ.B #1, D0 ; Increment the length counter
  83. BRA LENGTH_LOOP ; Loop back to process the next character
  84. LENGTH_DONE:
  85. MOVE.L (SP)+, A0 ; Restore A0 from the stack
  86. RTS ; Return from subroutine
  87. DISPLAY:
  88. ; Save registers that will be used by TRAP #15
  89. MOVE.L D0, -(SP) ; Save D0 on the stack
  90. MOVE.L D1, -(SP) ; Save D1 on the stack
  91. ; Pop the base and the number off the stack
  92. MOVE.L (SP)+, D2 ; Pop the base off the stack into D2
  93. MOVE.L (SP)+, D1 ; Pop the integer value off the stack into D1
  94. ; Ensure D2 only contains the base in the lower byte
  95. ANDI.L #$FF, D2 ; Clear upper bytes of D2, leaving only the base
  96. ; Set up for TRAP #15 to display the number
  97. MOVE.L D1, D1 ; Number to display
  98. MOVE.L D2, D2 ; Base
  99. MOVE.W #3, D0 ; Task number for TRAP #15
  100. TRAP #15 ; Execute the trap to display the number
  101. ; Restore registers after TRAP #15
  102. MOVE.L (SP)+, D1 ; Restore D1
  103. MOVE.L (SP)+, D0 ; Restore D0
  104. RTS ; Return from subroutine
  105. ORG $9000
  106. FMT DC.B 'B','D','O','O','H','B',0 ; Format string for printg
  107. END START

字符串
我希望硬编码输出显示在输出上。

bogh5gae

bogh5gae1#

一切都是关于堆栈的

一旦到达 printg 子例程,您的堆栈就具有:

  1. 300 ; the sixth number
  2. 11 ; the fifth number
  3. 134212 ; the fourth number
  4. 92 ; the third number
  5. 51 ; the second number
  6. 23 ; the first number
  7. FMT ; the address of FMT
  8. ? ; the return address

字符串
然后在堆栈上保留一些寄存器:

  1. 300 ; the sixth number
  2. 11 ; the fifth number
  3. 134212 ; the fourth number
  4. 92 ; the third number
  5. 51 ; the second number
  6. 23 ; the first number this is at 20(SP)
  7. FMT ; the address of FMT this is at 16(SP)
  8. ? ; the return address
  9. ? ; preserved A0
  10. ? ; preserved D0
  11. ? ; preserved D1 this is at (SP)

  • 第一个错误是在MOVEA.L 8(SP), A0中,你应该从堆栈中获取格式字符串的地址。在偏移量+8处,你已经存储了A0的内容,碰巧包含该地址,所以你在这一点上实际上并没有失败。正确的指令是MOVEA.L 16(SP), A0
  • LENGTH 子例程最好不要将D 0视为字节,最好将其视为一个long,这样一旦将其完整复制到D1中,依赖于位0到15的DBF D1, END_PRINT指令就可以正确工作。
  • 当在 * BLOG_BINARY* 中推送那些基值{2,8,10,16}时,不要使用.B。始终保持堆栈指针为偶数(并使用.L以清晰地显示堆栈布局),因此使用MOVE.L #2, -(SP)等。
  • 堆栈上整数的起始地址的计算完全是假的!指令ADDA.L #4, SP ; Adjust stack pointer to the first integer不好。只要删除它。不要忘记也删除它的恢复指令SUBA.L #4, SP ; Adjust stack pointer back to the format string address进一步下降。

因为堆栈现在看起来像:

  1. 300 ; the sixth number
  2. 11 ; the fifth number
  3. 134212 ; the fourth number
  4. 92 ; the third number
  5. 51 ; the second number
  6. 23 ; the first number this is at 24(SP)
  7. FMT ; the address of FMT
  8. ? ; the return address
  9. ? ; preserved A0
  10. ? ; preserved D0
  11. ? ; preserved D1
  12. ? ; the base value


在 *CALL_CALL * 处的代码变为:

  1. CALL_DISPLAY:
  2. ; Calculate the offset for the current integer
  3. MOVE.L D1, D2 ; Copy the index to D2
  4. LSL.L #2, D2 ; Multiply the index by 4 to get the byte offset
  5. LEA 24(SP), A1 ; Load the address of the first integer into A1
  6. ADDA.L D2, A1 ; Add the offset to the address


第一次运行此代码段时,D1包含值5。乘以4将为已经指向第一个数字(23)的A1加上20。最终结果是第六个数字(300)是您的程序将显示的第一个数字。不知道这是否是您想要的...

  • 你用栈上的两个长参数调用 * 子例程,并立即在栈上保留D 0和D1寄存器:
  1. ? ; the base this is at 16(SP) (*)
  2. ? ; the integer this is at 12(SP)
  3. ? ; the return address
  4. ? ; preserved D0
  5. ? ; preserved D1


代码:

  1. MOVE.L (SP)+, D2 ; Pop the base off the stack into D2
  2. MOVE.L (SP)+, D1 ; Pop the integer value off the stack into D1


是不起作用的。你将弹出你刚刚推送保存的值!使用MOVE.L 16(SP), D2MOVE.L 12(SP), D1分别检索基数和整数。
(*)最后一个提示:你的程序将基值两次推入堆栈(相邻)。

展开查看全部

相关问题