【问题标题】:Stumped on Extended Multiplication for LC-3 Assembly难倒 LC-3 组装的扩展乘法
【发布时间】:2018-05-24 06:52:02
【问题描述】:

我正在尝试让扩展乘法在 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 模拟器上使用断点和 Step Into 函数来逐步检查我的代码,试图找出发生这种情况的原因,以及我唯一做过的事情值得注意的是,在乘法循环期间发生的逻辑右移在循环终止之前将 MPR 减少到 0(尽管 ACC 得到正确的值)。

正如我所说,所有的子程序(逻辑右移的 SHIFT 是其中最重要的)工作正常,而且看起来 MULOOP 正确地实现了通用乘法算法,那么为什么 MPR 会被归零呢?

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

我不知道怎么了。几个小时以来,我一直在不停地尝试各种事情:

  • 我改变了操作数的顺序(交换了乘数和被乘数),这对乘法当然没关系,但我绝望了

  • 我尝试了一个完全不同的逻辑右 SHIFT 实现,它也是正确的。不出所料,结果和原来的一模一样

  • 我已经更改了循环计数器的值,试图查看循环的较少迭代是否会导致 MPR 在循环终止之前未清零。回答:确实如此,但正如预期的那样,这会导致 ACC 在循环终止时不再存储正确的值。此外,MPR 也不存储正确的值 - 它最终不会为零(如果我使用较小的计数器)。

我很困惑。是我的乘法循环的实现有问题,还是有其他问题?我什至不知道在哪里寻找错误了。

【问题讨论】:

    标签: assembly binary hex lc3


    【解决方案1】:

    快速提问:
    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 右侧移出 out 的位必须在 MPR 左侧移入 in。由于这没有发生,因此您最终会得到一个空的 MPR。

    你应该做什么:

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

    【讨论】:

    • 关于 PRINT 程序:如果保存的意思是“保存和恢复”,那么不,但它实际上不使用 R6。它使用 R0 - R4 和 R7。对不起,如果这不是你的意思!关于“我应该做什么”的代码: Bit(ACC, 0) 是指检查 ACC 的第 0 位(即序列中的最低有效位)吗?如果是这样,是否会在您从我的代码中引用的块中的第一行之后进行此检查(即 ADD R0、R3、#0)?
    • 如果它没有被破坏,那同样可以。
    • 除了我关于Bit(ACC, 0)的问题:Else底部的Add指令中的32768是否对应十六进制值x8000(即b1000 0000 0000 0000)?跨度>
    • 程序中的 sn-p 仅对应于 Ifpart。显然,测试(最低位)必须采取任何行动之前进行。
    • 所以我刚刚根据您的建议完成了一些代码的实现。它工作得很好。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多