ICS计算系统概论实验—Lab2-LC3实现斐波那契数列(变型式)
Posted 之墨_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 \\text100 100 | 256 \\text256 256 | 123 \\text123 123 | 146 \\text146 146 |
200 \\text200 200 | 514 \\text514 514 | 456 \\text456 456 | 818 \\text818 818 |
300 \\text300 300 | 1024 \\text1024 1024 | 789 \\text789 789 | 1219 \\text1219 1219 |
Principles
Key issues:
如何进行求余运算
指令集中主要能利用的运算操作有
A
D
D
、
A
N
D
ADD、AND
ADD、AND,一般的使用
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(N−2),F(N−1),−p,−q,F(N−2)%p,F(N−1)%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
2k−1来求余,即例如
11
%
8
=
3
→
1011
&
0111
=
0011
11\\% 8=3\\rightarrow1011\\&0111=0011
11%8=3→1011&0111=0011,如果使用这个方法求
F
(
N
−
2
)
%
p
F(N-2)\\%p
F(N−2)%p,就不需要额外寄存器再保存
−
p
以
及
F
(
N
−
2
)
-p以及F(N-2)
−p以及F(N−2),因为:
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(N−1)%p=F(N−1)AND(p−1)
所以上述初始化代码改写为:
.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
这样只需要 R 0 − R 6 R0-R6 R0−R6共 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\\ \\beginaligned &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) AND (p-1)\\\\ &F((N+1)-1)\\%q = F(N)\\%q\\\\ \\endaligned \\right.
⎩⎪⎨⎪⎧F(N+1)=F((N+1)−2)%p+F((N+1)−1)%qF((N+1)−2)%p=F(N−1)%p=F(N−1)AND(p−1)F((N+1)−1)%q=F(N)%q
依照上述关系式,取余需要借助循环实现反复减法操作,由于 N ≥ 2 N\\ge2 N≥2,所以初始化得到 F ( 0 ) 、 F ( 1 ) F(0)、F(1) F(0)、F(1)之后直接相加得到 F ( 2 ) F(2) F(2),在循环体内首先直接输出该值,再判断是否需要继续循环,即是否满足 N − 1 ≥ 0 N-1\\ge0 N−1≥0,不满足则应该结束循环,输出结果,满足条件则继续循环,因为 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)%p,F((N+1)−1)的计算,在第二层循环中完成 F ( ( N + 1 ) − 1 ) % q F((N+1)-1)\\%q F((N+1)−1)%q的计算,这样不断的循环就能够实现递归的计算。
Flow chart:
Procedure
初始化:
- R1存储p-1
- R2存储q
- R3存储N
- R0存储F(N-2)%p
- R4存储F(N-1)
- R5存储 -q
- 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
处理:
- 计算F(N)
- 判断循环条件是否成立
- 不成立则跳转至存储
- 成立则继续计算F((N+1)-2)%p与F((N+1)-1)%q
- 无条件跳转至步骤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
存储:
- 取x3100地址
- 存储数据至x3103
- HALT终止程序
BREAK LD R0, BASE ;x3100->R0
STR R6, R0, #3 ;R6->x3103
TRAP x25 ;finish
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 \\textLC3Tool LC3Tool调试完毕后,将代码整理如下:用于网站在线 lc3 \\textlc3 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
评测结果如下,正常运行,输出正确。
Efficiency of loop structure
在循环体中,F((N+1)-2)%p的计算是在第一层循环中直接通过按位与计算出来的,即计算它的余数只需要一条指令即可,如果采用和F((N+1)-1)%q同样的计算方法:嵌套一个循环,利用ADD运算计算余数,那么需要的指令数与寄存器数量都会更多,循环的效率更低,并且复用了几个寄存器R0、R4、R6,使得过程中用到的寄存器数量更少
以上是关于ICS计算系统概论实验—Lab2-LC3实现斐波那契数列(变型式)的主要内容,如果未能解决你的问题,请参考以下文章
ICS计算系统概论LC3汇编实验Lab5—中断递归解决汉诺塔问题
ICS计算系统概论LC3汇编实验Lab5—中断递归解决汉诺塔问题
ICS计算系统概论LC3汇编实验Lab4—排序和计数 Sort and Count