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

问题描述 投票:0回答:1

描述:演示简化的

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

我期望硬编码输出显示在输出上。

assembly motorola 68000 easy68k
1个回答
0
投票

一切都与堆栈有关

到达 printg 子例程后,您的堆栈具有:

300    ; the sixth number
11     ; the fifth number
134212 ; the fourth number
92     ; the third number
51     ; the second number
23     ; the first number
FMT    ; the address of FMT
?      ; the return address

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

300    ; the sixth number
11     ; the fifth number
134212 ; the fourth number
92     ; the third number
51     ; the second number
23     ; the first number        this is at 20(SP)
FMT    ; the address of FMT      this is at 16(SP)
?      ; the return address
?      ; preserved A0
?      ; preserved D0
?      ; preserved D1            this is at (SP)
  • 第一个错误位于

    MOVEA.L 8(SP), A0
    ,您确实应该从堆栈检索格式字符串的地址。在偏移量 +8 处,您存储了 A0 的内容,该内容碰巧包含该地址,因此此时您实际上并没有失败。然而,正确的使用说明是
    MOVEA.L 16(SP), A0

  • LENGTH子例程最好不要将D0视为一个字节。最好将其视为 long,这样一旦将其全尺寸复制到 D1 中,依赖于位 0 到 15 的

    DBF D1, END_PRINT
    指令就可以正常工作。

  • DISPLAY_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

    因为堆栈现在看起来像:

    300    ; the sixth number
    11     ; the fifth number
    134212 ; the fourth number
    92     ; the third number
    51     ; the second number
    23     ; the first number        this is at 24(SP)
    FMT    ; the address of FMT
    ?      ; the return address
    ?      ; preserved A0
    ?      ; preserved D0
    ?      ; preserved D1
    ?      ; the base value
    

    CALL_DISPLAY处的代码变为:

    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     24(SP), A1 ; Load the address of the first integer into A1
    ADDA.L  D2, A1     ; Add the offset to the address
    

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

  • 您使用堆栈上的 2 个长参数调用 DISPLAY 子例程,并且立即将 D0 和 D1 寄存器保留在堆栈上:

    ?      ; the base           this is at 16(SP)     (*)
    ?      ; the integer        this is at 12(SP)
    ?      ; the return address
    ?      ; preserved D0
    ?      ; preserved D1
    

    代码:

     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
    

    不会起作用。您将弹出您刚刚推动保存的价值观!使用

    MOVE.L 16(SP), D2
    MOVE.L 12(SP), D1
    分别检索基数和整数。

(*) 最后提示:您的程序将基值两次推送到堆栈(相邻)。

© www.soinside.com 2019 - 2024. All rights reserved.