在 LC3 中使用非法向量号执行了陷阱
A trap was executed with an illegal vector number in LC3
我一直在做一项作业,我必须将给定的数字转换为 LC3 中的不同基数。要做到这一点,我需要使用除法,虽然我有一个作业在做同样的事情,但这个除法算法是不同的。
我应该在这个作业中使用扩展除法。基本算法是:
给定一个 32 位数字,将前 16 位存储到内存地址(称为高分子),最后 16 位(低分子)存储到另一个地址,除数,另一个 16 位数字,存储到另一个。因此,在子例程中,数字将从内存中提取到不同的寄存器中,算法将按如下方式工作:
- 高分子寄存器和低分子寄存器都左移一次(这样如果低分子的高位(最左边)为1,就传给高分子的低位,因为移位应该事先为零)
- 高分子与除数比较。如果大于或等于它,则从中减去除数并设置低分子的低位。如果没有,什么都不做(最终它会随着我们不断变化而变得更大)
- 重复移位校验16次,设置低分子的低位(最右边)
- 最后,高分子的寄存器将保存除法的余数,低分子的寄存器将保存商
为简单起见,我们的讲师让我们使用 0 作为高分子。所以,为了实现算法,我想出了以下程序:
- 首先我声明一个 5 的 .BLKW,命名为 ARGLIST,所有参数将存储在其中
- PRINT 子例程:我声明所有 ST 操作以将工作寄存器的值与它们在子例程中的用途分开,然后我将 ARGLIST 的地址加载到一个寄存器中,我将低位存储在该寄存器中分子,并递增以存储高分子(0)和除数> 然后,我加载到 BUFFER 和 DIGITS 的指针,以存储转换为指定基数的结果。然后调用 DIVIDE 子程序
- DIVIDE 子例程:我将 ARGLIST 的地址加载到寄存器(根据赋值指令为 R6),加载并递增到必要的寄存器以准备好值,执行循环 16 次,其中分子被移位(和使用 x0080 完成屏蔽以获得低分子的高位),每当 DVR 小于或等于高分子时减去并重复。然后商和余数存储在 R6 指向的位置(当然递增到下一个)和 return
- 所以回到 PRINT:我从 R7 指向的值加载到 R2 和 R3(保持相同以尝试尽可能多地重用分配 2 中的代码),因为它也指向 ARGLIST 现在应该被填充,然后子例程继续就像赋值 2
- 因此,当整个存储到缓冲区中时,我将指向 ARGLIST 的开头 "update" 低分子并指向商以准备下一次迭代(下一次除法)
下面是我目前的完整代码:
.ORIG x3000
LEA R0, MPROMPT
TRAP x22
LOOP
JSR GETDEC ;Input an unsigned (decimal) integer
ADD R0, R0, #0 ;Exit if the input integer is 0
BRZ EXIT
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 10 (output base 10 DECIMAL)
ADD R1, R1, #10
JSR PRINT ;Print the integer in decimal
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 2 (output base 2 BINARY)
ADD R1, R1, #2
JSR PRINT ;Print the integer in binary
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 8 (output base 8 OCTAL)
ADD R1, R1, #8
JSR PRINT ;Print the integer in octal
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 16 (output base 16 HEXADECIMAL)
ADD R1, R1, #15
ADD R1, R1, #1
JSR PRINT ;Print the integer in hexadecimal
JSR NEWLN ;Move cursor to the start of a new line
BRNZP LOOP
EXIT ;Loop exit point
TRAP x25 ;HALT program execution
MPROMPT .STRINGZ "Enter a sequence of unsigned integer values\nEnter 0 To Quit\n"
;Subroutine NEWLN*************************************************************
;Advances the console cursor to the start of a new line
NEWLN
ST R7, NEW7 ;Save working registers
ST R0, NEW0
LD R0, NL ;Output a newline character
TRAP x21
LD R0, NEW0 ;Restore working registers
LD R7, NEW7
RET ;Return
;Data
NL .FILL x000A ;Newline character
NEW0 .BLKW 1 ;Save area - R0
NEW7 .BLKW 1 ;Save area - R7
;Subroutine GETDEC************************************************************
;Inputs an unsigned integer typed at the console in decimal format
;The input value is returned in R0
GETDEC
;Save Values of ALL Registers that don't need to change
ST R1, GET1
ST R2, GET2
ST R3, GET3
ST R4, GET4
ST R5, GET5
ST R6, GET6
ST R7, GET7 ;Save R7 to be able to return to main
AND R3, R3, #0 ;Prepare a value
LEA R0, GPROMPT
TRAP x22
GETDKEY
TRAP x20 ;To input a keystroke
ADD R2, R0, #-10 ;Subtract new keystroke by 10 (new line, or enter)
BRZ GFINIS ;If R2 is 0 we just pressed enter, so we break out
TRAP x21 ;Echo keystroke
ADD R2, R0, #0 ;Get the number back
AND R2, R2, #15 ;We mask to only get the first four bits
ADD R3, R3, R3 ;1st addition: x + x = 2x
ADD R4, R3, #0 ;Store the 2x
ADD R3, R3, R3 ;2nd addition: 2x + 2x = 4x
ADD R3, R3, R3 ;3rd addition: 4x + 4x = 8x
ADD R3, R3, R4 ;4th addition: 8x + 2x = 10x
ADD R3, R3, R2 ;10x + new number
BRNZP GETDKEY ;Go back to get next number
GFINIS
ADD R0, R3, #0 ;Put number into R0
;Restore the values of registers that don't need change
LD R1, GET1
LD R2, GET2
LD R3, GET3
LD R4, GET4
LD R5, GET5
LD R6, GET6
LD R7, GET7 ;Get back the value of R7
RET
;Data
GPROMPT .STRINGZ "Enter an unsigned integer> " ;Input Prompt
GET1 .BLKW 1
GET2 .BLKW 1
GET3 .BLKW 1
GET4 .BLKW 1
GET5 .BLKW 1
GET6 .BLKW 1
GET7 .BLKW 1
;Subroutine PRINT*************************************************************
;Displays an unsigned integer in any base up to 16, e.g. binary, octal, decimal
;Parameters - R0: the integer - R1: the base
PRINT
ST R0, PR0
ST R1, PR1
ST R2, PR2
ST R3, PR3
ST R4, PR4
ST R5, PR5
ST R6, PR6
ST R7, PR7
LEA R7, ARGLIST ;Point to ARGLIST to start populating the args
STR R0, R7, #0 ;Put R0 to be the low numerator
AND R0, R0, #0 ;R0 is not needed after this, so it is cleared
ADD R7, R7, #1 ;Go down on pointer once to store next arg
STR R0, R7, #0 ;Put R0, now x0000, to be the high numerator
ADD R7, R7, #1
STR R1, R7, #0 ;Store the base, R1, to be the DVR
ADD R7, R7, #1 ;Have R7 point to Quotient
LEA R6, BUFFER
AND R5, R5, #0 ;To make sure R5 is cleared
LEA R4, DIGITS ;Prepare pointer to the digits
SDIV
JSR DIVIDE
LDR R2, R7, #0 ;Since the addresses should now be ready,
;R7 would point to quotient, passed to R2
LDR R3, R7, #1 ;Pass remainder to R3
ADD R3, R3, R4
LDR R5, R3, #0
ADD R6, R6, #-1 ;Decrement to get to the next one
STR R5, R6, #0 ;Store number into buffer
LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
STR R2, R7, #0
ADD R7, R7, #3 ;Point to quotient
ADD R0, R2, #0 ;Pass quotient into R0
BRP SDIV ;If number is at least 1, then divide again
ADD R0, R6, #0 ;If we got here, then we should have the converted number
TRAP x22 ;Last but not least we display
LD R0, PR0
LD R1, PR1
LD R2, PR2
LD R3, PR3
LD R4, PR4
LD R5, PR5
LD R6, PR6
LD R7, PR7
RET
;Data
DIGITS .STRINGZ "0123456789ABCDEF" ;Digits
.BLKW 18 ;Output Buffer
BUFFER .FILL x0000 ;Null
PR0 .BLKW 1
PR1 .BLKW 1
PR2 .BLKW 1
PR3 .BLKW 1
PR4 .BLKW 1
PR5 .BLKW 1
PR6 .BLKW 1
PR7 .BLKW 1
;Subroutine DIVIDE************************************************************
;Extended division is done here
DIVIDE
ST R1, DIV1
ST R2, DIV2
ST R3, DIV3
ST R4, DIV4
ST R5, DIV5
ST R6, DIV6
ST R7, DIV7
LEA R6, ARGLIST ;Point straight to where arguments start
LDR R5, R6, #0 ;Load NUMLOW into R5
ADD R6, R6, #1 ;Go down one step in pointer
LDR R4, R6, #0 ;Load NUMHIGH into R4
ADD R6, R6, #1 ;Go down once more
LDR R3, R6, #0 ;Load DVR into R3
ADD R6, R6, #1 ;Go down yet once more to be ready when we
;store results
LD R1, M8BIT ;Make R1 be equal to x0080 to get last bit
;from NUMLOW
AND R2, R2, #0 ;Set R2 as counter to decrement with each
ADD R2, R2, #10 ;iteration
ADD R2, R2, #6
ITER ADD R4, R4, R4 ;Shift NUMHIGH to the left once
AND R7, R5, R1 ;Masking. If R5[7] == 1, then R7 == x0080
BRNZ NOADD ;(or positive)
ADD R4, R4, #1 ;If this happens then R5[7] was set, so we're
;adding the bit that would be lost if R5
;shifts left
NOADD ADD R5, R5, R5 ;Shift NUMLOW to the left once
NOT R7, R3 ;Subtract NUMHIGH and DVR. If 0 or positive
ADD R7, R7, #1 ;then subtract and increment NUMLOW
ADD R7, R4, R7
BRN DECCNT ;If negative then DVR is greater than NUMHIGH,
;go straight to decrement the loop count
ADD R4, R7, #0
ADD R5, R5, #1
DECCNT ADD R2, R2, #-1
BRP ITER ;If count is positive, go back to ITER
STR R5, R6, #0 ;Store NUMLOW for the Quotient Address
ADD R6, R6, #1 ;Increment to store in the next one
STR R4, R6, #0 ;Store NUMHIGH for the Remainder Address
LD R1, DIV1
LD R2, DIV2
LD R3, DIV3
LD R4, DIV4
LD R5, DIV5
LD R6, DIV6
LD R7, DIV7
RET ;Return
;Data
ARGLIST .BLKW 5 ;Here we will put the LOWNUM, HIGHNUM,
;DVR, QUO, and REM
M8BIT .FILL x0080
DIV1 .BLKW 1
DIV2 .BLKW 1
DIV3 .BLKW 1
DIV4 .BLKW 1
DIV5 .BLKW 1
DIV6 .BLKW 1
DIV7 .BLKW 1
.END
我认为该算法应该有效,但是当我在 LC3 上 运行 它时,我收到以下错误:
A trap was executed with an illegal vector number
并且处理器停止。出于某种原因,我注意到当我在 LC3 中检查我的代码时,它在这一行之后立即被删除:
ADD R0, R2, #0
在分支之前再次调用 DIVIDE 子例程。
为什么会这样?据我所知,我一直在正确地保存和恢复寄存器(上次我遇到了与此类似的问题,有人指出我保存到同一个 .BLKW 导致了错误),但是错误坚持。如果有人知道可能出现故障的原因,或者您是否需要更多信息,请告诉我。提前感谢您的帮助
已解决。有两个主要错误:
1) 不需要戴口罩。如果有的话,掩码本身就是错误的,因为寄存器保存 16 位值。如果我想使用掩码,更合适的值应该是 x8000
,但仍然不能使用,因为这实际上是 RTI
的操作码。我所要做的就是确保将 R5(具有低分子的寄存器)纳入分支计算。如果是negative
,那么高位显然是1!
2) 这就是破坏程序的原因。请注意,在 PRINT
函数中,我使用的是 LEA
和 R7
。这意味着我让这个寄存器负责指向参数。但是在这之后的几行我称之为 JSR
:
JSR DIVIDE
我没有意识到在内部发生这种跳转时,能够return正常程序执行所需的 PC 值存储在一个寄存器中。在哪里? R7。所以即使在 DIVIDE
的开头和结尾我有一个 ST
和一个 LD
来恢复 R7 的值,在 return 到 PRINT
它应该是下一条指令的 地址 ,而不是指向 ARGLIST
的指针。程序正确 运行 所需要做的就是添加一个简单的 LEA
,添加 3 以指向商和余数,并将指针的操作修改得更远一点以存储更新的低位分子。总而言之,DIVIDE
调用之后的代码如下所示:
SDIV
JSR DIVIDE
LEA R7, ARGLIST
ADD R7, R7, #3
LDR R2, R7, #0 ;Since the addresses should now be ready,
;R7 would point to quotient, passed to R2
LDR R3, R7, #1 ;Pass remainder to R3
ADD R3, R3, R4
LDR R5, R3, #0
ADD R6, R6, #-1 ;Decrement to get to the next one
STR R5, R6, #0 ;Store number into buffer
LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
STR R2, R7, #0
ADD R0, R2, #0 ;Pass quotient into R0
BRP SDIV ;If number is at least 1, then divide again
ADD R0, R6, #0 ;If we got here, then we should have the converted number
TRAP x22 ;Last but not least we display
我一直在做一项作业,我必须将给定的数字转换为 LC3 中的不同基数。要做到这一点,我需要使用除法,虽然我有一个作业在做同样的事情,但这个除法算法是不同的。
我应该在这个作业中使用扩展除法。基本算法是:
给定一个 32 位数字,将前 16 位存储到内存地址(称为高分子),最后 16 位(低分子)存储到另一个地址,除数,另一个 16 位数字,存储到另一个。因此,在子例程中,数字将从内存中提取到不同的寄存器中,算法将按如下方式工作:
- 高分子寄存器和低分子寄存器都左移一次(这样如果低分子的高位(最左边)为1,就传给高分子的低位,因为移位应该事先为零)
- 高分子与除数比较。如果大于或等于它,则从中减去除数并设置低分子的低位。如果没有,什么都不做(最终它会随着我们不断变化而变得更大)
- 重复移位校验16次,设置低分子的低位(最右边)
- 最后,高分子的寄存器将保存除法的余数,低分子的寄存器将保存商
为简单起见,我们的讲师让我们使用 0 作为高分子。所以,为了实现算法,我想出了以下程序:
- 首先我声明一个 5 的 .BLKW,命名为 ARGLIST,所有参数将存储在其中
- PRINT 子例程:我声明所有 ST 操作以将工作寄存器的值与它们在子例程中的用途分开,然后我将 ARGLIST 的地址加载到一个寄存器中,我将低位存储在该寄存器中分子,并递增以存储高分子(0)和除数> 然后,我加载到 BUFFER 和 DIGITS 的指针,以存储转换为指定基数的结果。然后调用 DIVIDE 子程序
- DIVIDE 子例程:我将 ARGLIST 的地址加载到寄存器(根据赋值指令为 R6),加载并递增到必要的寄存器以准备好值,执行循环 16 次,其中分子被移位(和使用 x0080 完成屏蔽以获得低分子的高位),每当 DVR 小于或等于高分子时减去并重复。然后商和余数存储在 R6 指向的位置(当然递增到下一个)和 return
- 所以回到 PRINT:我从 R7 指向的值加载到 R2 和 R3(保持相同以尝试尽可能多地重用分配 2 中的代码),因为它也指向 ARGLIST 现在应该被填充,然后子例程继续就像赋值 2
- 因此,当整个存储到缓冲区中时,我将指向 ARGLIST 的开头 "update" 低分子并指向商以准备下一次迭代(下一次除法)
下面是我目前的完整代码:
.ORIG x3000
LEA R0, MPROMPT
TRAP x22
LOOP
JSR GETDEC ;Input an unsigned (decimal) integer
ADD R0, R0, #0 ;Exit if the input integer is 0
BRZ EXIT
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 10 (output base 10 DECIMAL)
ADD R1, R1, #10
JSR PRINT ;Print the integer in decimal
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 2 (output base 2 BINARY)
ADD R1, R1, #2
JSR PRINT ;Print the integer in binary
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 8 (output base 8 OCTAL)
ADD R1, R1, #8
JSR PRINT ;Print the integer in octal
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 16 (output base 16 HEXADECIMAL)
ADD R1, R1, #15
ADD R1, R1, #1
JSR PRINT ;Print the integer in hexadecimal
JSR NEWLN ;Move cursor to the start of a new line
BRNZP LOOP
EXIT ;Loop exit point
TRAP x25 ;HALT program execution
MPROMPT .STRINGZ "Enter a sequence of unsigned integer values\nEnter 0 To Quit\n"
;Subroutine NEWLN*************************************************************
;Advances the console cursor to the start of a new line
NEWLN
ST R7, NEW7 ;Save working registers
ST R0, NEW0
LD R0, NL ;Output a newline character
TRAP x21
LD R0, NEW0 ;Restore working registers
LD R7, NEW7
RET ;Return
;Data
NL .FILL x000A ;Newline character
NEW0 .BLKW 1 ;Save area - R0
NEW7 .BLKW 1 ;Save area - R7
;Subroutine GETDEC************************************************************
;Inputs an unsigned integer typed at the console in decimal format
;The input value is returned in R0
GETDEC
;Save Values of ALL Registers that don't need to change
ST R1, GET1
ST R2, GET2
ST R3, GET3
ST R4, GET4
ST R5, GET5
ST R6, GET6
ST R7, GET7 ;Save R7 to be able to return to main
AND R3, R3, #0 ;Prepare a value
LEA R0, GPROMPT
TRAP x22
GETDKEY
TRAP x20 ;To input a keystroke
ADD R2, R0, #-10 ;Subtract new keystroke by 10 (new line, or enter)
BRZ GFINIS ;If R2 is 0 we just pressed enter, so we break out
TRAP x21 ;Echo keystroke
ADD R2, R0, #0 ;Get the number back
AND R2, R2, #15 ;We mask to only get the first four bits
ADD R3, R3, R3 ;1st addition: x + x = 2x
ADD R4, R3, #0 ;Store the 2x
ADD R3, R3, R3 ;2nd addition: 2x + 2x = 4x
ADD R3, R3, R3 ;3rd addition: 4x + 4x = 8x
ADD R3, R3, R4 ;4th addition: 8x + 2x = 10x
ADD R3, R3, R2 ;10x + new number
BRNZP GETDKEY ;Go back to get next number
GFINIS
ADD R0, R3, #0 ;Put number into R0
;Restore the values of registers that don't need change
LD R1, GET1
LD R2, GET2
LD R3, GET3
LD R4, GET4
LD R5, GET5
LD R6, GET6
LD R7, GET7 ;Get back the value of R7
RET
;Data
GPROMPT .STRINGZ "Enter an unsigned integer> " ;Input Prompt
GET1 .BLKW 1
GET2 .BLKW 1
GET3 .BLKW 1
GET4 .BLKW 1
GET5 .BLKW 1
GET6 .BLKW 1
GET7 .BLKW 1
;Subroutine PRINT*************************************************************
;Displays an unsigned integer in any base up to 16, e.g. binary, octal, decimal
;Parameters - R0: the integer - R1: the base
PRINT
ST R0, PR0
ST R1, PR1
ST R2, PR2
ST R3, PR3
ST R4, PR4
ST R5, PR5
ST R6, PR6
ST R7, PR7
LEA R7, ARGLIST ;Point to ARGLIST to start populating the args
STR R0, R7, #0 ;Put R0 to be the low numerator
AND R0, R0, #0 ;R0 is not needed after this, so it is cleared
ADD R7, R7, #1 ;Go down on pointer once to store next arg
STR R0, R7, #0 ;Put R0, now x0000, to be the high numerator
ADD R7, R7, #1
STR R1, R7, #0 ;Store the base, R1, to be the DVR
ADD R7, R7, #1 ;Have R7 point to Quotient
LEA R6, BUFFER
AND R5, R5, #0 ;To make sure R5 is cleared
LEA R4, DIGITS ;Prepare pointer to the digits
SDIV
JSR DIVIDE
LDR R2, R7, #0 ;Since the addresses should now be ready,
;R7 would point to quotient, passed to R2
LDR R3, R7, #1 ;Pass remainder to R3
ADD R3, R3, R4
LDR R5, R3, #0
ADD R6, R6, #-1 ;Decrement to get to the next one
STR R5, R6, #0 ;Store number into buffer
LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
STR R2, R7, #0
ADD R7, R7, #3 ;Point to quotient
ADD R0, R2, #0 ;Pass quotient into R0
BRP SDIV ;If number is at least 1, then divide again
ADD R0, R6, #0 ;If we got here, then we should have the converted number
TRAP x22 ;Last but not least we display
LD R0, PR0
LD R1, PR1
LD R2, PR2
LD R3, PR3
LD R4, PR4
LD R5, PR5
LD R6, PR6
LD R7, PR7
RET
;Data
DIGITS .STRINGZ "0123456789ABCDEF" ;Digits
.BLKW 18 ;Output Buffer
BUFFER .FILL x0000 ;Null
PR0 .BLKW 1
PR1 .BLKW 1
PR2 .BLKW 1
PR3 .BLKW 1
PR4 .BLKW 1
PR5 .BLKW 1
PR6 .BLKW 1
PR7 .BLKW 1
;Subroutine DIVIDE************************************************************
;Extended division is done here
DIVIDE
ST R1, DIV1
ST R2, DIV2
ST R3, DIV3
ST R4, DIV4
ST R5, DIV5
ST R6, DIV6
ST R7, DIV7
LEA R6, ARGLIST ;Point straight to where arguments start
LDR R5, R6, #0 ;Load NUMLOW into R5
ADD R6, R6, #1 ;Go down one step in pointer
LDR R4, R6, #0 ;Load NUMHIGH into R4
ADD R6, R6, #1 ;Go down once more
LDR R3, R6, #0 ;Load DVR into R3
ADD R6, R6, #1 ;Go down yet once more to be ready when we
;store results
LD R1, M8BIT ;Make R1 be equal to x0080 to get last bit
;from NUMLOW
AND R2, R2, #0 ;Set R2 as counter to decrement with each
ADD R2, R2, #10 ;iteration
ADD R2, R2, #6
ITER ADD R4, R4, R4 ;Shift NUMHIGH to the left once
AND R7, R5, R1 ;Masking. If R5[7] == 1, then R7 == x0080
BRNZ NOADD ;(or positive)
ADD R4, R4, #1 ;If this happens then R5[7] was set, so we're
;adding the bit that would be lost if R5
;shifts left
NOADD ADD R5, R5, R5 ;Shift NUMLOW to the left once
NOT R7, R3 ;Subtract NUMHIGH and DVR. If 0 or positive
ADD R7, R7, #1 ;then subtract and increment NUMLOW
ADD R7, R4, R7
BRN DECCNT ;If negative then DVR is greater than NUMHIGH,
;go straight to decrement the loop count
ADD R4, R7, #0
ADD R5, R5, #1
DECCNT ADD R2, R2, #-1
BRP ITER ;If count is positive, go back to ITER
STR R5, R6, #0 ;Store NUMLOW for the Quotient Address
ADD R6, R6, #1 ;Increment to store in the next one
STR R4, R6, #0 ;Store NUMHIGH for the Remainder Address
LD R1, DIV1
LD R2, DIV2
LD R3, DIV3
LD R4, DIV4
LD R5, DIV5
LD R6, DIV6
LD R7, DIV7
RET ;Return
;Data
ARGLIST .BLKW 5 ;Here we will put the LOWNUM, HIGHNUM,
;DVR, QUO, and REM
M8BIT .FILL x0080
DIV1 .BLKW 1
DIV2 .BLKW 1
DIV3 .BLKW 1
DIV4 .BLKW 1
DIV5 .BLKW 1
DIV6 .BLKW 1
DIV7 .BLKW 1
.END
我认为该算法应该有效,但是当我在 LC3 上 运行 它时,我收到以下错误:
A trap was executed with an illegal vector number
并且处理器停止。出于某种原因,我注意到当我在 LC3 中检查我的代码时,它在这一行之后立即被删除:
ADD R0, R2, #0
在分支之前再次调用 DIVIDE 子例程。
为什么会这样?据我所知,我一直在正确地保存和恢复寄存器(上次我遇到了与此类似的问题,有人指出我保存到同一个 .BLKW 导致了错误),但是错误坚持。如果有人知道可能出现故障的原因,或者您是否需要更多信息,请告诉我。提前感谢您的帮助
已解决。有两个主要错误:
1) 不需要戴口罩。如果有的话,掩码本身就是错误的,因为寄存器保存 16 位值。如果我想使用掩码,更合适的值应该是 x8000
,但仍然不能使用,因为这实际上是 RTI
的操作码。我所要做的就是确保将 R5(具有低分子的寄存器)纳入分支计算。如果是negative
,那么高位显然是1!
2) 这就是破坏程序的原因。请注意,在 PRINT
函数中,我使用的是 LEA
和 R7
。这意味着我让这个寄存器负责指向参数。但是在这之后的几行我称之为 JSR
:
JSR DIVIDE
我没有意识到在内部发生这种跳转时,能够return正常程序执行所需的 PC 值存储在一个寄存器中。在哪里? R7。所以即使在 DIVIDE
的开头和结尾我有一个 ST
和一个 LD
来恢复 R7 的值,在 return 到 PRINT
它应该是下一条指令的 地址 ,而不是指向 ARGLIST
的指针。程序正确 运行 所需要做的就是添加一个简单的 LEA
,添加 3 以指向商和余数,并将指针的操作修改得更远一点以存储更新的低位分子。总而言之,DIVIDE
调用之后的代码如下所示:
SDIV
JSR DIVIDE
LEA R7, ARGLIST
ADD R7, R7, #3
LDR R2, R7, #0 ;Since the addresses should now be ready,
;R7 would point to quotient, passed to R2
LDR R3, R7, #1 ;Pass remainder to R3
ADD R3, R3, R4
LDR R5, R3, #0
ADD R6, R6, #-1 ;Decrement to get to the next one
STR R5, R6, #0 ;Store number into buffer
LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
STR R2, R7, #0
ADD R0, R2, #0 ;Pass quotient into R0
BRP SDIV ;If number is at least 1, then divide again
ADD R0, R6, #0 ;If we got here, then we should have the converted number
TRAP x22 ;Last but not least we display