我正在尝试让扩展乘法在LC-3上工作。我的代码的相关摘录:
.ORIG x3000
; Calculate AB = A x B
LEA R6, ARGS
LD R0, B
STR R0, R6, #0 ; Store B into Multiplier address of ARGS
JSR PRINT
LD R0, A
STR R0, R6, #1 ; Store A into Multiplicand address of ARGS
JSR PRINT
LEA R0, AB ; R0 <- starting address of AB
STR R0, R6, #2 ; Store starting address of AB into Product word of ARGS
JSR XMULT
; DID WE LOAD THE PRODUCT PROPERLY?
; THIS SHOULD PRINT THE LEAST SIGNIFICANT BITS OF PRODUCT
LDR R0, R0, #0
JSR PRINT
; THIS SHOULD PRINT THE MOST SIGNIFICANT BITS OF PRODUCT
LEA R0, AB
ADD R0, R0, #1
LDR R0, R0, #0
JSR PRINT
; Calculate XY = X * Y
TRAP x25
; Test Data
A .FILL x0010
B .FILL x00AB
X .FILL x1234
Y .FILL xABCD
AB .BLKW 2
XY .BLKW 2
; Argument List
ARGS .BLKW 1 ;Multiplier (value)
.BLKW 1 ;Multiplicand (value)
.BLKW 1 ;Product (address)
;**********************************************************
XMULT ;Extended Multiplication
;Arguments located by R6
; multiplier (value)
; multiplicand (value)
; product (address)
ST R7, XMU7 ;Save Registers
ST R0, XMU0 ; TEMP register (for storing temp results and passing to RightShift subroutine)
ST R1, XMU1 ; Will store MPR (Multiplier)
ST R2, XMU2 ; Will store MND (Multiplicand)
ST R3, XMU3 ; Will store ACC (Accumulator)
ST R4, XMU4 ; Will serve as a COUNTER for loop
ST R5, XMU5 ; Will store BITMASK for testing
ST R6, XMU6 ; Argument list
LDR R1, R6, #0 ; Store MPR into R1 (Multiplier is first item in the argument list pointed to by R6)
LDR R2, R6, #1 ; Store MND into R2 (Multiplicand is second item)
AND R3, R3, #0 ; ACC <- 0
LD R4, COUNTER ; Set counter
LD R5, BITMASK ; Set R5 to 0000 0000 0000 0001, the bitmask needed to test MPR[0]
; Counter and operands ready - now we can start the loop
MULOOP ; MUltiplication LOOP
AND R0, R5, R1 ; Test MPR[0]
BRz ELSE ; Branch if MPR[0] isn't set
ADD R3, R3, R2 ; ACC <- ACC + MND
ELSE
AND R0, R0, #0 ; Clear R0
ADD R0, R3, #0 ; R0 <- ACC
JSR SHIFT ; ShiftRight(ACC)
ADD R3, R0, #0 ; R3 <- Right-shifted ACC
ADD R0, R1, #0 ; R0 <- MPR
JSR SHIFT ; ShiftRight(MPR)
ADD R1, R0, #0 ; R1 <- Right-shifted MPR
ADD R4, R4, #-1 ; Decrement Counter
BRp MULOOP ; If Counter > 0, branch to beginning of loop
MULOOPEND ; MUltiplication LOOP ends here
; Write results to memory addresses (OUT-parameter segment)
LDR R0, R6, #2 ; R0 <- Product(address), least significant digit
STR R1, R0, #0 ; Right-shifted MPR goes in the lower address word
STR R3, R0, #1 ; Right-shifted ACC goes in the higher address word
LD R7, XMU7 ; Restore Registers
LD R0, XMU0
LD R1, XMU1
LD R2, XMU2
LD R3, XMU3
LD R4, XMU4
LD R5, XMU5
LD R6, XMU6
RET
XMU0 .BLKW 1
XMU1 .BLKW 1
XMU2 .BLKW 1
XMU3 .BLKW 1
XMU4 .BLKW 1
XMU5 .BLKW 1
XMU6 .BLKW 1
XMU7 .BLKW 1
; Data
COUNTER .FILL x0010
BITMASK .FILL x0001
请注意,子例程PRINT和SHIFT只是简单地以位形式将R0的内容打印到控制台,并分别对R0的内容执行右移操作。请假设它们工作正常(我已经对其进行了多次测试)。
因此,该代码应计算两个N位无符号整数的双字乘积。当然,乘积存储在两个连续的字中,“最低有效”位存储在低地址字中。
在XMULT子例程中,我分别使用R3(ACCumulator的ACC)和R1(MultiPlieR的MPR)存储产品的“最高有效”和“最低有效”部分。这些是使用标准通用乘法算法计算的
MPR <- Multiplier
MND <- Multiplicand
ACC <- 0
for (int k = 1; k <= N; k++)
{
if (MPR[0]) // Test MPR[0]
ACC <- ACC + MND
ShiftRight(ACC:MPR)
}
因此,在循环结束时,ACC:MPR中提供了双字乘积。
循环终止时,ACC似乎存储了正确的值,但MPR没有。例如,取值X和Y,咨询位乘法计算器,得出x1234 * xABCD = xC374FA4
现在,如果我运行我的代码并将X和Y相乘,一旦乘法循环终止,ACC(乘积的最高有效位)将存储b0000 1100 0011 0111 = x0C37,因此这部分似乎是正确的。但是,MPR存储零(b0000 0000 0000 0000 = x0000)。
在过去的几个小时中,我一直在使用LC-3仿真器上的断点和“步入”功能逐步检查代码,以试图弄清为什么会发生这种情况,而我唯一注意到的是乘法循环中发生的逻辑右移将在循环终止之前将MPR降低为0(尽管ACC获得了正确的值)。
就像我说的那样,所有子例程(逻辑右移的SHIFT是它们中最重要的)都可以正常工作,并且像MULOOP这样的SEEMS正确地实现了通用乘法算法,那么MPR为什么要归零?
更令人困惑的是,我尝试将x0100和x0200相乘(只是尝试两个简单的数字),我得到了正确的答案:x0002存储在ACC中,x0000存储在MPR中,乘积x20000(因为ACC是最大的)产品的重要部分,而MPR的重要性最低)。
我不知道怎么了几个小时以来,我一直在努力尝试各种事情:
我很困惑。我的乘法循环的实现是否有问题,还是还有其他问题?我什至不知道在哪里寻找错误了。
最佳答案
快速提问:
PRINT过程是否保留R6
?如果不是,则需要使用额外的LEA R6, ARGS
指令为第二个和第三个参数重新加载它。
您实际上不是ShiftRight(ACC:MPR)
您ShiftRight(ACC)
ShiftRight(MPR)
ADD R0, R3, #0 ; R0 <- ACC
JSR SHIFT ; ShiftRight(ACC)
ADD R3, R0, #0 ; R3 <- Right-shifted ACC
ADD R0, R1, #0 ; R0 <- MPR
JSR SHIFT ; ShiftRight(MPR)
ADD R1, R0, #0 ; R1 <- Right-shifted MPR
在程序的这一部分中,您将执行2个完全独立的操作。您将
R3
(ACC)中的单词向右移,然后将R1
(MPR)中的单词向右移。但是,您忘记了ACC:MPR应该是32位的数量。在ACC右侧将移出的位必须在MPR左侧的移出。由于这没有发生,因此您最终得到一个空的MPR。
您应该做什么:
If Bit(ACC,0) = 0
ShiftRight(ACC)
ShiftRight(MPR)
Else
ShiftRight(ACC)
ShiftRight(MPR)
Add(MPR,32768)
Endif