• ICS计算系统概论实验—Lab2-LC3实现斐波那契数列(变型式)


    Lab2

    Purpose

    calculate a variant of the Fibonacci sequence:
    在这里插入图片描述

    condition:

    • p will be stored in x3100, q will be stored in x3101 and N will be stored in
      x3102.
    • job: store F(N) in x3103.
    • R0-R7 are set to zeroes at the beginning, and your program should start at x3000.
    • Your program should start with .ORIG x3000
    • Your program should end with .END
    • Your last instruction should be TRAP x25 (HALT)
    • Capitalized keywords(also labels) are recommended
    • Spaces after commas ( ADD R0, R0, #1 rather than ADD R0,R0,#1 )
    • Decimal constants start with #, hexadecimal with lowercase x
    • Write comments when necessary

    several examples:

    N N N p p p q q q F ( N ) F(N) F(N)
    100 \text{100} 100 256 \text{256} 256 123 \text{123} 123 146 \text{146} 146
    200 \text{200} 200 514 \text{514} 514 456  \text{456 } 456  818 \text{818} 818
    300 \text{300} 300 1024 \text{1024} 1024 789  \text{789 } 789  1219 \text{1219} 1219

    Principles

    Key issues:

    如何进行求余运算

    指令集中主要能利用的运算操作有 A D D 、 A N D ADD、AND ADDAND,一般的使用 A D D ADD ADD运算求 x % p x\%p x%p,取余方式为用 x x x反复减 p p p,当 x x x减至负数时再加上一个 p p p得到的结果即为所求的余数,如果使用这个方法求实验要求的斐波那契数,那么就需要 9 9 9个寄存器分别存储 p , q , N , F ( N − 2 ) , F ( N − 1 ) , − p , − q , F ( N − 2 ) % p , F ( N − 1 ) % q p,q,N,F(N-2),F(N-1),-p,-q,F(N-2)\%p,F(N-1)\%q p,q,N,F(N2),F(N1),p,q,F(N2)%p,F(N1)%q,显然寄存器数量不支持这个方法
    所以需要利用 p = 2 k p=2^k p=2k这个特点,改进求余运算,注意到在二进制求余运算中,如果模为 2 k 2^k 2k那么就可以利用 A N D AND AND进行按位与 2 k − 1 2^k-1 2k1来求余,即例如 11 % 8 = 3 → 1011 & 0111 = 0011 11\% 8=3\rightarrow1011\&0111=0011 11%8=31011&0111=0011,如果使用这个方法求 F ( N − 2 ) % p F(N-2)\%p F(N2)%p,就不需要额外寄存器再保存 − p 以及 F ( N − 2 ) -p以及F(N-2) p以及F(N2),因为:
    F ( ( N + 1 ) − 2 ) % p = F ( N − 1 ) % p = F ( N − 1 ) A N D ( p − 1 ) F((N+1)-2)\%p = F(N-1)\%p = F(N-1) AND (p-1) F((N+1)2)%p=F(N1)%p=F(N1)AND(p1)
    所以上述初始化代码改写为:

    .ORIG x3000
    LD R0, BASE ;
    LDR R1, R0, #0  ;p -> R0
    LDR R2, R0, #1  ;q -> R2
    LDR R3, R0, #2  ;N -> R4
    AND R0, R0, #0  ;0 -> R0
    ADD R0, R0, #1  ;F(N-2) = F(0) = 1 -> R0
    ADD R4, R0, #0  ;F(N-1) = F(1) = F(0) = 1 -> R4
    ADD R1, R1, #-1 ;p-1->R1
    NOT R5, R2      ;NOT q -> R5
    ADD R5, R5, #1  ;-q -> R5
    ADD R3, R3, #-2 ;N-2 -> R3
    ADD R6, R4, #0  ;F(N-1)%q = F(1)%q->R6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这样只需要 R 0 − R 6 R0-R6 R0R6 7 7 7个寄存器,在减少了寄存器的数量同时也简化了后续循环中的求余运算。

    如何实现递归计算

    根据定义,可以得到如下递推关系式:
    { F ( N + 1 ) = F ( ( N + 1 ) − 2 ) % p + F ( ( N + 1 ) − 1 ) % q F ( ( N + 1 ) − 2 ) % p = F ( N − 1 ) % p = F ( N − 1 ) A N D ( p − 1 ) F ( ( N + 1 ) − 1 ) % q = F ( N ) % q \left\{

    F(N+1)=F((N+1)2)%p+F((N+1)1)%qF((N+1)2)%p=F(N1)%p=F(N1)AND(p1)F((N+1)1)%q=F(N)%q" role="presentation">F(N+1)=F((N+1)2)%p+F((N+1)1)%qF((N+1)2)%p=F(N1)%p=F(N1)AND(p1)F((N+1)1)%q=F(N)%q
    \right. F(N+1)=F((N+1)2)%p+F((N+1)1)%qF((N+1)2)%p=F(N1)%p=F(N1)AND(p1)F((N+1)1)%q=F(N)%q

    依照上述关系式,取余需要借助循环实现反复减法操作,由于 N ≥ 2 N\ge2 N2,所以初始化得到 F ( 0 ) 、 F ( 1 ) F(0)、F(1) F(0)F(1)之后直接相加得到 F ( 2 ) F(2) F(2),在循环体内首先直接输出该值,再判断是否需要继续循环,即是否满足 N − 1 ≥ 0 N-1\ge0 N10,不满足则应该结束循环,输出结果,满足条件则继续循环,因为 F ( ( N + 1 ) − 2 ) % p F((N+1)-2)\%p F((N+1)2)%p可以利用按位与运算直接计算出,所以在第一层循环中就可以完成 F ( N ) 、 F ( ( N + 1 ) − 2 ) % p , F ( ( N + 1 ) − 1 ) F(N)、F((N+1)-2)\%p,F((N+1)-1) F(N)F((N+1)2)%pF((N+1)1)的计算,在第二层循环中完成 F ( ( N + 1 ) − 1 ) % q F((N+1)-1)\%q F((N+1)1)%q的计算,这样不断的循环就能够实现递归的计算。

    Flow chart:

    请添加图片描述

    Procedure

    初始化:

    1. R1存储p-1
    2. R2存储q
    3. R3存储N
    4. R0存储F(N-2)%p
    5. R4存储F(N-1)
    6. R5存储 -q
    7. R6存储F(N-1)%q
    .ORIG x3000
    LD R0, BASE ;
    LDR R1, R0, #0  ;p -> R1
    LDR R2, R0, #1  ;q -> R2
    LDR R3, R0, #2  ;N -> R3
    AND R0, R0, #0  ;0 -> R0
    ADD R0, R0, #1  ;F(N-2) = F(0) = 1 -> R0
    ADD R4, R0, #0  ;F(N-1) = F(1) = F(0) = 1 -> R4
    ADD R1, R1, #-1 ;p-1->R1
    NOT R5, R2      ;NOT q -> R5
    ADD R5, R5, #1  ;-q -> R5
    ADD R3, R3, #-2 ;N-2 -> R3
    ADD R6, R4, #0  ;F(N-1)%q = F(1)%q->R6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    处理:

    1. 计算F(N)
    2. 判断循环条件是否成立
    3. 不成立则跳转至存储
    4. 成立则继续计算F((N+1)-2)%p与F((N+1)-1)%q
    5. 无条件跳转至步骤1
    MOD ADD R6, R6, R0  ;F(N) = F(N-2)%p + F(N-1)%q -> R6   
        ADD R3, R3, #-1 ;N-1 -> R3
        BRn BREAK       ;if N-1 < 0 then goto break
        AND R0, R4, R1  ;F((N+1)-2)%p = F(N-1)%p = F(N-1) AND (p-1)
        ADD R4, R6, #0  ;F((N+1)-1) -> R4
    RE  ADD R6, R6, R5  ;R6-q -> R6 F((N+1)-1)%q = F(N)%q
        BRzp RE         ;if R6-q >= 0 then goto RE
        ADD R6, R6, R2  ;F((N+1)-1)%q = R6 + q -> R6
        BR MOD          ;goto MOD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    存储:

    1. 取x3100地址
    2. 存储数据至x3103
    3. HALT终止程序
    BREAK LD   R0, BASE     ;x3100->R0
          STR  R6, R0, #3   ;R6->x3103
          TRAP x25          ;finish
    
    • 1
    • 2
    • 3

    Result

    Debug:

    过程中遇到的主要问题有:输出结果不对!
    在这里插入图片描述

    检查发现循环结构与初始化均没有问题,发现寄存器的使用存在不对,递归过程的部分寄存器应该需要复用,如图,在循环体中,如果我使用一个新的寄存器R7来存储F(N)结果,那么在执行ADD R7,R7,R2后R7存储了F((N+1)-1)%q的值,此时R6还是初始值,所以需要将R7的值赋给R6,否则会导致结果输出不对!但发现R6除第一次初始化后后续不再需要用到初始值,所以可以复用R6,即下图中的R7都用R6代替。
    在这里插入图片描述
    修改后的循环体如下,R6的复用即解决了上述问题,也减少了使用的寄存器数量
    在这里插入图片描述

    Test:

    Judge:

    在本地 LC3Tool \text{LC3Tool} LC3Tool调试完毕后,将代码整理如下:用于网站在线 lc3 \text{lc3} lc3评测

        .ORIG x3000
        LD R0, BASE ;
        LDR R1, R0, #0  ;p -> R0
        LDR R2, R0, #1  ;q -> R2
        LDR R3, R0, #2  ;N -> R4
        AND R0, R0, #0  ;0 -> R0
        ADD R0, R0, #1  ;F(N-2) = F(0) = 1 -> R0
        ADD R4, R0, #0  ;F(N-1) = F(1) = F(0) = 1 -> R4
        ADD R1, R1, #-1 ;p-1->R1
        NOT R5, R2      ;NOT q -> R5
        ADD R5, R5, #1  ;-q -> R5
        ADD R3, R3, #-2 ;N-2 -> R3
        ADD R6, R4, #0  ;F(N-1)%q = F(1)%q->R6
        
    MOD ADD R6, R6, R0  ;F(N) = F(N-2)%p + F(N-1)%q -> R7
        ADD R3, R3, #-1 ;N-1 -> R3
        BRn BREAK       ;if N-1 < 0 then goto break
        AND R0, R4, R1  ;F((N+1)-2)%p = F(N-1)%p = F(N-1) AND (p-1)
        ADD R4, R6, #0  ;F((N+1)-1) -> R4
    RE  ADD R6, R6, R5  ;R7-q -> R7 F((N+1)-1)%q = F(N)%q
        BRzp RE         ;if R7-q >= 0 then goto RE
        ADD R6, R6, R2  ;F((N+1)-1)%q = R6 + q -> R6
        BR MOD          ;goto MOD
        
    BREAK LD   R0, BASE     ;x3100->R0
          STR  R6, R0, #3   ;R6->x3103
          TRAP x25          ;finish
    
    BASE .FILL x3100;
         .END
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    评测结果如下,正常运行,输出正确。
    在这里插入图片描述

    Efficiency of loop structure

    在循环体中,F((N+1)-2)%p的计算是在第一层循环中直接通过按位与计算出来的,即计算它的余数只需要一条指令即可,如果采用和F((N+1)-1)%q同样的计算方法:嵌套一个循环,利用ADD运算计算余数,那么需要的指令数与寄存器数量都会更多,循环的效率更低,并且复用了几个寄存器R0、R4、R6,使得过程中用到的寄存器数量更少

  • 相关阅读:
    敏捷Scrum实施落地中的3大典型问题及解法
    数据库第四章习题-数据库安全性控制
    MATLAB 匿名函数
    如何写一个全局的 Notice 组件?
    45.【list链表的应用】
    【Leetcode每日一题】 递归 - 反转链表(难度⭐)(35)
    tensorflow 与 cuda和cuDNN的版本对应表
    推荐一下我使用的开发工具
    vue3.0 slot
    11种增加访问者在网站上平均停留时间的技巧
  • 原文地址:https://blog.csdn.net/weixin_56462041/article/details/128043190