说明:程序演示了一个简化的printf
函数(printg
),它是硬编码的,什么都没有播放。我不知道为什么。
ORG $8000
START:
; Push parameters onto the stack (right-to-left)
MOVE.L #300, -(SP) ; Push the sixth number
MOVE.L #11, -(SP) ; Push the fifth number
MOVE.L #134212, -(SP) ; Push the fourth number
MOVE.L #92, -(SP) ; Push the third number
MOVE.L #51, -(SP) ; Push the second number
MOVE.L #23, -(SP) ; Push the first number
; Push the address of the format string onto the stack
LEA FMT, A0 ; Load the address of FMT into A0
MOVE.L A0, -(SP) ; Push the address onto the stack
; Call printg subroutine
BSR printg
; Clean up the stack
ADDA.L #28, SP ; Remove all six 32-bit numbers and the format string address
; Rest of the program or exit
SIMHALT ; Stop simulation
printg:
; Save registers that will be used
MOVE.L A0, -(SP) ; Save A0
MOVE.L D0, -(SP) ; Save D0
MOVE.L D1, -(SP) ; Save D1
; Call LENGTH to get the number of integers to print
MOVEA.L 8(SP), A0 ; Move the address of the format string into A0
BSR LENGTH ; Call LENGTH, result will be in D0
MOVE.B D0, D1 ; Store the number of integers in D1
; Calculate the starting address of the integers on the stack
ADDA.L #4, SP ; Adjust stack pointer to the first integer
PRINT_LOOP:
; Check if we have processed all format characters
DBF D1, END_PRINT ; Decrement D1 and branch if D1 is -1
; Get the next format character
MOVE.B (A0)+, D0 ; Move the next format character into D0
; Determine the base for the DISPLAY subroutine
CMP.B #'B', D0
BEQ DISPLAY_BINARY
CMP.B #'0', D0
BEQ DISPLAY_OCTAL
CMP.B #'D', D0
BEQ DISPLAY_DECIMAL
CMP.B #'H', D0
BEQ DISPLAY_HEXADECIMAL
BRA PRINT_LOOP ; If the character is not B, O, D, or H, skip it
DISPLAY_BINARY:
MOVE.B #2, -(SP) ; Push base 2 for binary
BRA CALL_DISPLAY
DISPLAY_OCTAL:
MOVE.B #8, -(SP) ; Push base 8 for octal
BRA CALL_DISPLAY
DISPLAY_DECIMAL:
MOVE.B #10, -(SP) ; Push base 10 for decimal
BRA CALL_DISPLAY
DISPLAY_HEXADECIMAL:
MOVE.B #16, -(SP) ; Push base 16 for hexadecimal
CALL_DISPLAY:
; Calculate the offset for the current integer
MOVE.L D1, D2 ; Copy the index to D2
LSL.L #2, D2 ; Multiply the index by 4 to get the byte offset
LEA (SP), A1 ; Load the address of the first integer into A1
ADDA.L D2, A1 ; Add the offset to the address
MOVE.L (A1), D1 ; Move the integer at the calculated offset into D1
MOVE.L D2, -(SP) ; Push the base onto the stack
MOVE.L D1, -(SP) ; Push the integer onto the stack
BSR DISPLAY ; Call DISPLAY subroutine
ADDA.L #8, SP ; Clean up the stack (base + integer)
BRA PRINT_LOOP ; Process the next character
END_PRINT:
; Restore the original stack pointer position
SUBA.L #4, SP ; Adjust stack pointer back to the format string address
; Restore registers
MOVE.L (SP)+, D1 ; Restore D1
MOVE.L (SP)+, D0 ; Restore D0
MOVE.L (SP)+, A0 ; Restore A0
RTS ; Return from subroutine
LENGTH:
MOVE.L A0, -(SP) ; Save A0 on the stack
CLR.B D0 ; Initialize the length counter to 0
LENGTH_LOOP:
MOVE.B (A0)+, D1 ; Load the next character from the format string
BEQ LENGTH_DONE ; If the character is null (0), we are done
ADDQ.B #1, D0 ; Increment the length counter
BRA LENGTH_LOOP ; Loop back to process the next character
LENGTH_DONE:
MOVE.L (SP)+, A0 ; Restore A0 from the stack
RTS ; Return from subroutine
DISPLAY:
; Save registers that will be used by TRAP #15
MOVE.L D0, -(SP) ; Save D0 on the stack
MOVE.L D1, -(SP) ; Save D1 on the stack
; Pop the base and the number off the stack
MOVE.L (SP)+, D2 ; Pop the base off the stack into D2
MOVE.L (SP)+, D1 ; Pop the integer value off the stack into D1
; Ensure D2 only contains the base in the lower byte
ANDI.L #$FF, D2 ; Clear upper bytes of D2, leaving only the base
; Set up for TRAP #15 to display the number
MOVE.L D1, D1 ; Number to display
MOVE.L D2, D2 ; Base
MOVE.W #3, D0 ; Task number for TRAP #15
TRAP #15 ; Execute the trap to display the number
; Restore registers after TRAP #15
MOVE.L (SP)+, D1 ; Restore D1
MOVE.L (SP)+, D0 ; Restore D0
RTS ; Return from subroutine
ORG $9000
FMT DC.B 'B','D','O','O','H','B',0 ; Format string for printg
END START
字符串
我希望硬编码输出显示在输出上。
1条答案
按热度按时间bogh5gae1#
一切都是关于堆栈的
一旦到达 printg 子例程,您的堆栈就具有:
字符串
然后在堆栈上保留一些寄存器:
型
MOVEA.L 8(SP), A0
中,你应该从堆栈中获取格式字符串的地址。在偏移量+8处,你已经存储了A0的内容,碰巧包含该地址,所以你在这一点上实际上并没有失败。正确的指令是MOVEA.L 16(SP), A0
。DBF D1, END_PRINT
指令就可以正确工作。.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
进一步下降。因为堆栈现在看起来像:
型
在 *CALL_CALL * 处的代码变为:
型
第一次运行此代码段时,D1包含值5。乘以4将为已经指向第一个数字(23)的A1加上20。最终结果是第六个数字(300)是您的程序将显示的第一个数字。不知道这是否是您想要的...
型
代码:
型
是不起作用的。你将弹出你刚刚推送保存的值!使用
MOVE.L 16(SP), D2
和MOVE.L 12(SP), D1
分别检索基数和整数。(*)最后一个提示:你的程序将基值两次推入堆栈(相邻)。