难以进行LC-3装配的扩展乘法

时间:2017-12-10 17:03:23

标签: assembly binary hex lc3

我试图让Extended Multiplication在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位无符号整数的双字乘积。当然,产品存储在两个连续的单词中,最不重要的是&#34;位存储在较低地址字处。

在XMULT子程序中,我使用R3(ACC用于累加器)和R1(用于MultiPlieR的MPR)来存储&#34;最重要的&#34;并且&#34;最不重要的&#34;部分产品,分别。这些是使用标准通用乘法算法

计算的
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模拟器上使用断点和Step Into功能在过去几个小时内逐步完成我的代码,试图弄清楚为什么会发生这种情况,而且我唯一能做的就是#39;注意到在乘法循环期间发生的逻辑右移在循环终止之前将MPR降低到0(但ACC得到了正确的值)。

正如我所说的,所有子程序(逻辑右移的SHIFT是其中最重要的)都正常工作,它像MULOOP这样的SEEMS正确实现了通用乘法算法,那么为什么MPR会被归零?

更令人困惑的是,我尝试将x0100和x0200相乘(只是尝试两个简单的数字),我得到了正确的答案:x0002存储在ACC中,x0000存储在MPR中,制作产品x20000(因为ACC是产品中最重要的部分,而MPR是最不重要的部分)。

我不知道出了什么问题。我现在几个小时都在试着各种各样的东西:

  • 我改变了操作数的顺序(交换乘数和被乘数),当然这对于乘法来说并不重要,但我很绝望

  • 我尝试了一个完全不同的逻辑右SHIFT实现,这也是正确的。正如所料,结果与原始结果完全相同

  • 我已经改变了循环计数器的值,试图查看在循环终止之前,循环的迭代次数是否导致MPR NOT geting为零。答案:确实如此,但正如预期的那样,这导致ACC不再在循环终止时存储正确的值。此外,MPR也没有存储正确的值 - 它只是没有结束为零(如果我使用较小的计数器)。

我合法地难倒了。这是我的乘法循环实现的问题,还是有其他错误?我甚至不知道在哪里寻找错误。

1 个答案:

答案 0 :(得分:2)

快速提问:
PRINT 程序是否会保留R6?如果不是,您需要使用额外的LEA R6, ARGS指令为第2和第3个参数重新加载它。

您实际上并不是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右侧移位 out 的位必须在MPR左侧位于位置。由于没有发生这种情况,你最终会得到一个空的MPR。

你应该做什么:

If Bit(ACC,0) = 0
    ShiftRight(ACC)
    ShiftRight(MPR)
Else
    ShiftRight(ACC)
    ShiftRight(MPR)
    Add(MPR,32768)
Endif