计算机组成原理课设源码+报告+设计过程


哈尔滨理工大学

课 程 设 计

(计算机组成原理)

题  目:  模型机综合设计

班  级: 计算机科学与技术2019 - 5

姓  名:   

学  号:   

指导教师:      

系主任:

2021年03月12日

目 录
1.课程设计的目的11

2.课程设计的任务11

3.课程设计所用设备及所需资料11

4.设计内容11

4.1设计原理11

4.1.1 COP2000模型机总体结构....................................................................1

4.1.2 COP2000 微程序控制器组成及原理....................................................3

4.2设计过程与步骤3

4.2.1 乘法器...................................................................................................3

4.2.2 快速幂...................................................................................................7

4.2.3 冒泡排序(从小到大)......................................................................11

4.3设计结果及分析19

4.3.1 乘法器.................................................................................................19

4.3.2 快速幂.................................................................................................20

4.3.3 冒泡排序(从小到大)......................................................................20

5心得体会221

1.课程设计的目的
1.在实验机上设计机器指令及对应的微指令(微程序),从而进一步掌握微程序设计控制器的基本方法并了解指令系统与硬件结构的对应关系;

2. 通过控制器的微程序设计,综合理解计算机组成原理课程的核心知识并进一步建立整机系统的概念;

3. 培养综合实践及独立分析、解决问题的能力。

2.课程设计的任务
针对COP2000实验仪,首先通过综合实验了解该模型机微程序控制器原理(主要指熟悉该模型机指令/微指令系统的详细情况),然后在COP2000的集成开发环境下,设计全新的指令系统并编写对应的微程序;并编写运行实现乘法和快速幂算法的程序以及对主存中的数据进行排序的程序设计的验证。

3.课程设计所用设备及所需资料
COP2000实验系统
PC机( COP2000仿真软件)
COP2000计算机组成原理实验仪说明书
4.设计内容
4.1设计原理
4.1.1 COP2000模型机指令系统的特点

模型机指令系统的特点:

模型机的指令码为8位,根据指令类型的不同,可以有0到2个操作数。指令码的最低两位用来选择R0-R3寄存器,在微程序控制方式中,用指令码做为微地址来寻址微程序存储器,找到执行该指令的微程序。而在组合逻辑控制方式中,按时序用指令码产生相应的控制位。

在本模型机中,一条指令最多分为四个状态周期,一个状态周期为一个时钟脉冲,每个状态产生不同的控制信号,以实现模型机的各种功能。模型机有24位控制位以控制寄存器的输入、输出,选择运算器的运算功能,存储器的读写。

模型机中24位控制位分别为:

XRD :外部设备读信号,当给出了外设的地址后,输出此信号,从指定外设读数据。

EMWR :程序存储器EM写信号。

EMRD :程序存储器EM读信号。

PCOE :将程序计数器PC的值送到地址总线ABUS上。

EMEN :将程序存储器EM与数据总线DBUS接通,由EMWR和EMRD决定是将DBUS数据写到 EM中,还是从EM读出数据送到DBUS。

IREN :将程序存储器EM读出的数据打入指令寄存器IR和微指令计数器uPC。

EINT :中断返回时清除中断响应和中断请求标志,便于下次中断。

ELP :PC打入允许,与指令寄存器的IR3、IR2位结合,控制程序跳转。

MAREN:将数据总线DBUS上数据打入地址寄存器MAR。

MAROE:将地址寄存器MAR的值送到地址总线ABUS上。

OUTEN:将数据总线DBUS上数据送到输出端口寄存器OUT里。

STEN :将数据总线DBUS上数据存入堆栈寄存器ST中。

RRD :读寄存器组R0-R3,寄存器R?的选择由指令的最低两位决定。

RWR :写寄存器组R0-R3,寄存器R?的选择由指令的最低两位决定。

CN :决定运算器是否带进位移位,CN=1带进位,CN=0不带进位。

FEN :将标志位存入ALU内部的标志寄存器。

X2、X1、X0:X2、X1、X0三位组合来译码选择将数据送到DBUS上的寄存器。

表1 寄存器输出

X2    X1    X0    输出寄存器
0    0    0    IN_OE 外部输出门
0    0    1    IA_OE 中断向量
0    1    0    ST_OE 堆栈寄存器
0    1    1    PC_OE PC寄存器
1    0    0    D_OE 直通门
1    0    1    R_OE 右移门
1    1    0    L_OE 左移门
1    1    1    没有输出
WEN:将数据总线DBUS的值打入工作寄存器W中。

AEN:将数据总线DBUS的值打入累加器A中。

S2、S1、S0:S2、S1、S0三位组合决定 ALU 做何种运算。

表2 ALU运算控制

S2    S1    S0    功能
0    0    0    A+W 加
0    0    1    A-W 减
0    1    0    A|W 或
0    1    1    A&W 与
1    0    0    A+W+C 带进位加
1    0    1    A-W-C 带进位减
1    1    0    ~A A取反
1    1    1    A 输出A
4.1.2 微程序控制器组成及原理

微程序控制器主要由控制存储器、微指令寄存器和地址转移逻辑三大部分组成。其工作原理为:

(1)将程序和数据通过输入设备送入存储器。

(2)启动运行后,从存储器中取出程序指令送到控制器去识别,分析该指令要求什么事。

(3)控制器根据指令的含义发出相应的命令(如加法、减法),将存储单元中存放的操作数据取出送出运算器进行运算,再把运算结果送回存储器指定的单元中。

(4)运算任务完成后,就可以根据指令将结果通过输出设备输出。

图1 微程序控制器原理

4.2设计过程与步骤
4.2.1乘法器

十进制下的乘法算式计算 5 x 11 :

图2 十进制算式

分析:从运算过程中可以分析得出,部分积的由来可以看作是将乘数2分为10+1,乘数1与1相乘得到部分积1;乘数1与10相乘得到部分积2,两部分积相加即得到最终的运算结果。
由于这个过程是在十进制下进行的,因此1相当于是1*10^0而10相当于是1*10^1,即每一步的部分积是通过该位的数与乘数相乘,再乘以标志位的权值即可得到对应位的部分积,因此部分积1可以写作:1*5*10^0;部分积2可以写作:1*5*10^1,这是在十进制下的运算过程。
转换为二进制再列出算式可得:
图3 二进制算式
分析:由于二进制计算过程同十进制的规则一致,因此每次得到的部分积都是该位上的数与乘数1相乘再乘该位上的权值得到的结果。由于此时数制是二进制,每一位上的数只有0和1两种,因此每一步得到的部分积只有两种可能,0或1与乘数1相乘后再乘上对应位的权值(2^n),由于此时的数制为二进制,故后一位的权值总是前一位权值的二倍,在计算机中,*2与位运算中的左移位等价,每一次将乘数1进行左移位。判断乘数2的对应位的值,0可以认为是该项不存在,答案不变,1则表示求最终结果时该项存在,答案增加此时乘数1的值,根据这个原理就可以将乘法转换成加法和移位运算。所以设计程序主要问题在于:
判断乘数2化为二级制后的每一位的值(0或1)
每次循环将乘数向左移一位
程序设计:

首先在C语言的IDE下确定出程序的代码框架,实现C语言下的加法移位算乘法分析程序的具体代码结构:


图5 运行结果

图4 乘法器的C语言代码

问题(1)的解决:首先将乘数2与1进行与运算,若乘数2的最后一位为1,则运算结果为1,否则为零。并在循环结束时将乘数2向右移一位,进行判断下一位的值。

问题(2)的解决:使用变量pos存储变量a的值,每次循环将pos的值向左移动1为,实现每一步乘2的过程。

微指令系统设计:需要用到的微指令

指令    功能
MOV R,#II    将立即数II送寄存器R?中
MOV A,R?    将寄存器R?的值送到累加器A中
AND A,R?    累加器A“与”寄存器R?将结果存放到累加器A中
AND A,#II    累加器A“与”立即数将结果存放到累加器A中
ADD A,R?    累加器A与R?的值相加将结果存放到累加器A中
MOV R?,A    将累加器A的值送到寄存器R?中
RR A    累加器A中的值右移一位将结果存放到累加器A中
RL A    累加器A中的值左移一位将结果存放到累加器A中
JC MM    若进位标志置1,跳转到MM地址
JZ MM    若零标志位置1,跳转到MM地址
JMP MM    跳转到MM地址
汇编程序代码:

初始化操作:

MOV R0,#06H ;存放乘数a

MOV R1,#02H ;存放乘数b

MOV R2,#00H ;存放乘法结果

LOOP1:

MOV A,R0 ;将R0中的数送到A

AND A,#255 ;判断此时A中的值是否为0

JZ LOOP4 ;初始为0则直接跳转到结束,R2为0;否则为程序正常结尾

MOV A,R1 ;将R1中的数送到A

AND A,#255 ;判断此时A中的值是否为0

JZ LOOP4 ;乘数b为0则直接跳转到结束,R2为0;

MOV A,R0 ;将R0中的数送到A

AND A,#01H ;将A与立即数1进行与运算

JZ LOOP2 ;若该位为0则跳转至loop3,否则继续执行

MOV A,R0 ;将R0中的数放到A中

RR A ;将A中的值向右移一位(最低为改变)

MOV R0,A ;将A中的数送到R0

MOV A,R2 ;将R2中的数送到A

ADD A,R1 ;令A加上R1中的值

MOV R2,A ;将A的数送到R2中

MOV A,R1 ;将R1的值送到A中

RL A ;将A中的值向左移一位

MOV R1,A ;将A中的值送到R1中

JMP LOOP1 ;返回循环开始,判断下一轮循环

LOOP2: ;最低为为0时的步骤

MOV A,R0 ;将R0送到寄存器A中

RR A ;将A中的值向右移一位

MOV R0,A ;将A中的值送到R0

MOV A,R1 ;将R1中的值送到A

RL A ;将A中的值向左移一位

MOV R1,A ;将A中的值送到R1

JMP LOOP1 ;返回循环开始,判断下一轮循环

LOOP3:

JMP LOOP3 ;加入死循环终止程序

程序解读:主程序:寄存器R0中保存乘数a,寄存器R1中保存乘数b,寄存器R2中保存运算结果。

Loop1中首先对R0中的乘数a和R1中的乘数b进行判0,若两项中有一项为0则直接终止程序。再用R0中的值与1进行“与”运算,若该项为0则跳转到loop2中执行;若该项为1则继续在loop1中执行。在loop1中继续执行时:先将R0右移一位,将此时的倒数第二位转换为倒数第一位,准备下次判断。再将R1中的结果加到R2上,将R1的值左移(相当于乘2)返回到loop1开始;若跳转到loop2中,将R0右移和R1左移的操作与loop1中的一致,只是不更改保存答案的R2中的值,执行后跳转至loop1开始。再次循环若R0为0则证明运算已经完成,跳转到loop3结束程序;否则继续进行一轮循环。

4.2.2快速幂

十进制下的幂指运算:,这个过程需要进行5次乘法操作。从运算过程可知当指数为N时,程序需要计算的次数为N,故此程序的时间复杂度为O(N),通过数学原理,将2的指数化为2进制的表达式有:,再将指数拆分写就有:,此时可以发现原本5项乘积转变为三项进行乘积,此时再进一步化解将指数顺序进行更改就可以得到:。至此运算过程化解完成。

分析:根据最终的表达式来看,最终的结果有几项取决于指数(N)的值(化为二进制之后的项数)。由于还要计算每一项底数的值,每一步还需要额外进行一次乘法,故最终进行的常数级操作的复杂度为,忽略常数的时间复杂度为O(logN)。故使用快速幂算法计算可以大大提高程序的运行速度。

此外通过观察可以发现,最终化解的结果中,每一项指数的值自右向左分别为指数(25中的5)化解为二进制后从低位到高位每一项的值。而每一项的底数,自右向左每一项均为前一项的值的平方,第一项的值为算式最初的底数(25中的2)。

结合底数与指数,若化解后代式子该项指数为0,则该项的运算结果为1;若该指数项为1,则该项的运算结果为底数的值。所以程序设计主要的问题在于:

判断指数化为二进制后每一位的值(0或1)
每次循环时将底数的值进行平方
程序设计:

首先在C语言的IDE下确定出程序的代码框架,实现C语言下的快速幂算法分析程序的具体代码结构:


图7 运行结果

图6 快速幂的C语言代码

问题(1)的解决:首先将指数与1进行与运算,若指数的最后一位为1,则运算结果为1,否则为零。并在循环结束时将指数向右移一位,进行判断下一位的值。

问题(2)的解决:利用pos存储底数的值,无论指数该位是否为1,每次循环都将pos的值更改为pos的平方。

通过对程序的过程分析可以发现快速幂的实现方式在本质上与乘法器的实现有着异曲同工之妙,两者都是通过将原来的运算过程转换为二进制以简化运算过程。

微指令系统设计:需要用到的微指令

指令    功能
MOV R,#II    将立即数II送寄存器R?中
MOV A,R?    将寄存器R?的值送到累加器A中
MOV R?,A    将累加器A的值送到寄存器R?中
MOV A,#II    将立即数II送到累加器A中
MOV MM,A    将累加器A中的数送到主存MM地址中
MOV A,MM    将主存MM地址中的数送到累加器A中
MOV R?,MM    将主存MM地址中的数送到寄存器R?中
AND A,R?    累加器A“与”寄存器R?将结果存放到累加器A中
AND A,#II    累加器A“与”立即数将结果存放到累加器A中
ADD A,R?    累加器A与R?的值相加将结果存放到累加器A中
RR A    累加器A中的值右移一位将结果存放到累加器A中
RL A    累加器A中的值左移一位将结果存放到累加器A中
JC MM    若进位标志置1,跳转到MM地址
JZ MM    若零标志位置1,跳转到MM地址
JMP MM    跳转到MM地址
汇编程序代码:

MOV A,#06H ;

MOV 80H,A ;将底数存入主存80H

MOV A,#02H ;

MOV 81H,A ;将指数存入主存81H

MOV R3,#01H ;将结果初始化为1,R3保存运算结果

LOOP1: ;主循环

MOV A,81H ;将主存81H的数送入累加器A中

AND A,#255 ;判断累加器A中的数是否为0(指数为0结果为1直接结束程序)

JZ LOOPEND ;为0则直接跳转结束

MOV A,81H ;将主存81H的数送入累加器A中

AND A,#01H ;将累加器A中的数与1进行“与”运算

JZ LOOP2 ;为0则跳转至loop2;为1继续按步进行

MOV A,R3 ;将R3中的数据送累加器A中

MOV R0,A ;将A中的数送到R0寄存器中

MOV R1,80H ;将主存80H中的数送到R1寄存器中

MOV R2,#00H ;初始化R2寄存器(用于存放乘法运算的中间结果)

;乘法程序,实现过程与乘法器一致R0中存放乘数1;R1中存放乘数2

LOOP6: ;运算结果存放至R2中

MOV A,R0

AND A,#255

JZ LOOP8

MOV A,R1

AND A,#255

JZ LOOP8

MOV A,R0

AND A,#01H

JZ LOOP7

MOV A,R0

RR A

MOV R0,A

MOV A,R2

ADD A,R1

MOV R2,A

MOV A,R1

RL A

MOV R1,A

JMP LOOP6

LOOP7:

MOV A,R0

RR A

MOV R0,A

MOV A,R1

RL A

MOV R1,A

JMP LOOP6 ;乘法结束

LOOP8: ;

MOV A,R2 ;将R2中的运算结果存放到累加器A中

MOV R3,A ;将累加器A中的数送到R3

JMP LOOP2 ;跳转至loop2将底数平方

LOOP11: ;用于回跳

MOV A,81H ;将主存81H中的数据送到累加器A中

RR A ;将累加器中的数据右移一位(指数右移)

MOV 81H,A ;将累加器A中的数存送到主存81H中

JMP LOOP1 ;返回循环开头,进行下一轮判断

;loop2中的程序实现的是底数进行平方的过程

LOOP2: ;

MOV R2,#00H ;初始化R2寄存器(用于存放乘法运算的中间结果)

MOV R0,80H ;将主存80H中的数据送到寄存器R0中

MOV R1,80H ;将主存80H中的数据送到寄存器R1中(乘数与被乘数一致)

;乘法程序,实现过程与乘法器一致R0中存放乘数1;R1中存放乘数2

LOOP3: ;运算结果存放至R2中

MOV A,R0

AND A,#255

JZ LOOP5

MOV A,R1

AND A,#255

JZ LOOP5

MOV A,R0

AND A,#01H

JZ LOOP4

MOV A,R0

RR A

MOV R0,A

MOV A,R2

ADD A,R1

MOV R2,A

MOV A,R1

RL A

MOV R1,A

JMP LOOP3

LOOP4:

MOV A,R0

RR A

MOV R0,A

MOV A,R1

RL A

MOV R1,A

JMP LOOP3

LOOP5: ;乘法结束

MOV 80H,R2 ;将R2中的运算结果送到主存80H中

JMP LOOP11 ;跳转回主循环结尾

LOOPEND: ;

JMP LOOPEND ;添加死循环终止程序

程序解读:主循环:主存80H中存放的是参与运算的底数,主存81H中存放的是参与运算的指数,运算结果储存于R3中;

中间调用的乘法:乘数1存放于R0,乘数2存放于R1,运算结果存放于R2中。

首先先初始化将数据打入80H和81H。进入loop1首先判断指数(81H)是否为0,为0则直接跳转到程序终止,为1则继续判断指数转换为二进制最低为是否为1(与1进行“与”运算)结果为0跳转至loop2,为1则将R3的数送至R0,80H的数送至R1,两数相乘,并将保存在R2中的结果送到R3中。跳转至loop2,将80H中保存的底数进行平方,将结果依旧保存于80H中。完成后跳转回loop11,将指数右移一位后跳转至loop1开始。再次循环若指数(81H)为0则证明运算已经完成,跳转到loopEnd结束程序;否则继续进行一轮循环。

4.2.3冒泡排序(从小到大)

冒泡排序的基本思想:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。

算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。因此每次需要进行的比较次数都会比上一次少1次。有n个数的无序队列需要进行的排序次数为1+2+3...(n-1),故冒泡排序的时间复杂度为O(n2)。

冒泡排序在C语言中的实现为:

图8 冒泡排序的实现

图9 运行结果

通过图8代码可以实现在C语言中对于十个有符号数的从小到大排序。而在cop2000模型机中实现排序操作最大的难点在于比较过程。最容易实现的是通过减运算中出现的溢出来进行比较,若使用小数减去一个较大的数,则CF标志位会变为1。而一个较大的数减去一个较小的数,CF标志位会为0,因此借助减运算和JC跳转命令就可以判断出两数的大小关系。

在实际操作中发现,cop2000模型机存储负数时会以补码的行式进行储存,但是进行运算时,会忽略掉符号位,以一个正数的形式参与运算,这样就会导致有负数参与的排序在排序后,越小的负数反而处于越大的位置。直接使用补码进行比较,此时能够正常的排序范围在00H~FFH。

而由于负数在模型机中以补码的形式储存,故机器中的该数加上该数的相反数正好为零,且当两数相加溢出时,CF为1同时其会再从0开始计数。因此可以使用移码将参与运算的负数通过一个偏移量转换成对应的有大小关系的正数就可以实现使用cop2000对有符号数的排序了。因为cop2000的数据线有8根因此选择2(8-1)=80H作为偏移量。不考虑溢出时,负数会转化为0~80H的正数,正数会转化为80H~FFH的正数。此时能够正常排序的范围在-80H~7FH。

微指令系统设计:需要用到的微指令

指令    功能
MOV R,#II    将立即数II送寄存器R?中
MOV A,R?    将寄存器R?的值送到累加器A中
MOV R?,A    将累加器A的值送到寄存器R?中
MOV A,#II    将立即数II送到累加器A中
MOV MM,A    将累加器A中的数送到主存MM地址中
MOV A,MM    将主存MM地址中的数送到累加器A中
MOV R?,MM    将主存MM地址中的数送到寄存器R?中
AND A,R?    累加器A“与”寄存器R?将结果存放到累加器A中
AND A,#II    累加器A“与”立即数将结果存放到累加器A中
ADD A,R?    累加器A与R?的值相加将结果存放到累加器A中
RR A    累加器A中的值右移一位将结果存放到累加器A中
RL A    累加器A中的值左移一位将结果存放到累加器A中
JC MM    若进位标志置1,跳转到MM地址
JZ MM    若零标志位置1,跳转到MM地址
JMP MM    跳转到MM地址
汇编程序代码:

MOV A,#100 ;将10个有符号数转换成移码保存于主存中(80H~89H)

ADD A,#80H

MOV 80H,A

MOV A,#-77

ADD A,#80H

MOV 81H,A

MOV A,#42

ADD A,#80H

MOV 82H,A

MOV A,#65

ADD A,#80H

MOV 83H,A

MOV A,#17

ADD A,#80H

MOV 84H,A

MOV A,#-8

ADD A,#80H

MOV 85H,A

MOV A,#-32

ADD A,#80H

MOV 86H,A

MOV A,#67

ADD A,#80H

MOV 87H,A

MOV A,#4

ADD A,#80H

MOV 88H,A

MOV A,#22

ADD A,#80H

MOV 89H,A ;10个有符号数转移码保存结束

MOV R0,#80H ;初始化外循环上边界

MOV R1,#89H ;初始化外循环下边界

LOOP1: ;外循环开始

MOV A,R1 ;

SUB A,R0 ;外下边界减去外上边界

JZ LOOPRE ;判断是否全部排完,若外下边界与外上边界相等跳到转码循环

MOV A,R0 ;

MOV R2,A ;用外下边界初始化内指针R2

ADD A,#01H ;R3指针始终指向R2的下一个位置

MOV R3,A ;初始化R2,R3

LOOP2: ;内循环开始

MOV A,R1 ;将寄存器R1中的数送到累加器A中

SUB A,R2 ;用下边界减去内指针

JZ LOOP11 ;为零则完成一次内循环跳出到外循环尾部

MOV A,@R3 ;通过寄存器寻址将R3寄存器中对应地址主存中的数据送至累加器A中

SUB A,@R2 ;累加器A减去R2寄存器中对应地址主存中的数据

JC LOOP3 ;若R3位置的数小于R2位置的数,CF=1,两数交换

LOOP22: ;内循环尾部

ADD R2,#01H ;

ADD R3,#01H ;移动内指针

JMP LOOP2 ;跳转至内循环开始

LOOP11: ;外循环尾部

SUB R1,#01H ;外下边界减小1

JMP LOOP1 ;返回外边界开始位置,进行下一轮循环

LOOP3: ;两数交换

MOV A,@R2 ;通过寄存器寻址将R2寄存器中对应地址主存中的数据送至累加器A中

MOV 90H,A ;将A中的数暂存至主存90H中

MOV A,@R3 ;通过寄存器寻址将R3寄存器中对应地址主存中的数据送至累加器A中

MOV @R2,A ;将累加器A中的数送到R2寄存器中对应地址的主存中去

MOV A,90H ;将主存90H中的数送回累加器A中

MOV @R3,A ;将累加器A中的数送到R3寄存器中对应地址的主存中去

JMP LOOP22 ;返回内循环后部

LOOPRE: ;转换补码

MOV R0,#80H ;

MOV R1,#89H ;初始化循环上下边界

LOOP4: ;转码循环开始

MOV A,R1 ;将寄存器R1的值送到累加器A中

ADD A,#10H ;累加器A加上16(作为存储位置的地址)

MOV R2,A ;将累加器A中的数送到寄存器R2中作为寄存器寻址的地址

MOV A,@R1 ;通过寄存器寻址将R1寄存器中对应地址主存中的数据送至累加器A中

SUB A,#80H ;累加器A中的数加上80H并存放至累加器A中

MOV @R2,A ;将累加器A中的数送到R2寄存器中对应地址的主存中去

MOV A,R1 ;将寄存器R1的数送到累加器A中去

SUB A,R0 ;下边界减去上边界,相等则全部转换,跳转至结束否则继续执行

JZ LOOPEND ;

SUB R1,#01H ;将下边界减小1准备下一次循环

JMP LOOP4 ;返回转码循环开始

;

LOOPEND: ;排序完成

JMP LOOPEND ;加入死循环结束程序

程序解读:主循环:寄存器R0储存外循环上边界,在转码期间存储循环上边界;寄存器R1在排序期间存储外循环的下边界,在转码期间存储循环下边界;寄存器R2在排序期间充当内指针,在转码期间存储转码后数据的存储地址;寄存器R3充当排序期间的内指针。主存80H~89H存储排序前的十个移码数,90H在排序中充当交换的中间变量,90H~99H在程序结束后存放着排序完成的数据的补码。

主循环:程序运行,先将10个有符号数转换成移码储存到主存80H~89H中,将最低地址80H存入上边界R0,将最高地址89H存入下边界R1.进入loop1的主循环首先经过设定的判断循环结束调节,利用R1的值减去R0的值,若差值为0则证明上下边界重合,排序完成,跳转至最后的转码循环否则利用R0中的上边界对内循环指针R2和R3进行赋值,每次将R2指向首位。然后将R3指向R2的下一位用寄存器寻址在主存中取到R2、R3对应的地址中主存所储存的值,用R3地址的值减去R2地址的值,若R3小于R2的,则证明两数的顺序相反,FC标志位就为一跳转至loop3中进行两数交换,操作后跳转回loop22,R2、R3指针均加一跳转至loop2开始进行下次循环;标志位为0则R2、R3指针直接加一跳转至loop2开始进行下次循环。再次进入loop2首先判断外循环的下边界与R2是否指向一个位置,若不指向一个位置就继续进行loop2的循环,指向一个位置就证明一次外循环已经完成,R1减一(每次冒泡都会将无序的最大项移至最后,无序数减一),跳转回loop1开始进行下一轮循环。再次进入loop1时,若外循环的上下边界重合就证明冒泡排序过程已经完成,跳转至转码过程,否则继续进行循环排序过程。

Loop3:利用主存90H作为中间变量将主存中R2地址的数送到90H,将R3地址的数送到R2地址,将90H送回到R3H中,返回内循环。

LoopRE:首先初始化上下循环边界,将下边界送到累加器A中,地址加16存放到R2中作为转换完成的存放地址。利用R1进行寄存器寻址将对应数值从主存中取出,减去80H转化为原数的补码,将补码存储到主存中R2地址的位置。判断上下边界是否重合,重合则直接跳转程序结束,不重合则上边界减小,跳转至loop4进行下一轮的循环。

主循环中的loop1与loop11、loop2与loop22,直接模拟了C语言中的for语句的跳转运行方式。

指令系统:


在uM 微程序窗口中对每条指令设计对应的微指令集:


 


 


 


 


4.3设计结果及分析
4.3.1乘法器

实验数据1:

乘数a(R0)    6
乘数b(R1)    2
预期结果:#0CH

实验结果:R2中储存乘法结果,运算结果符合预期。

实验数据2:

乘数a(R0)    3
乘数b(R1)    5
预期结果:#0FH

实验结果:R2中储存乘法结果,运算结果符合预期。

由于乘法程序设计时是按照四位无符号的乘法验证设计的,可以保证储存在寄存器R2中的运算结果不会出现溢出现象。

4.3.2快速幂

实验数据1:

底数(80H)    6
指数(81H)    2
预期结果:#24H

实验结果:R3中储存计算结果,运算结果符合预期。

实验数据2:

底数(80H)    3
指数(81H)    4
预期结果:#51H

实验结果:R3中储存计算结果,运算结果符合预期。

4.3.3冒泡排序(从小到大)

实验数据1:

排序前元数据    100    -77    42    65    17    -8    -32    67    4    22
排序前(移码)    E4H    33H    AAH    C1H    91H    78H    60H    C3H    84H    96H
排序后(移码)    33H    60H    78H    84H    91H    96H    AAH    C1H    C3H    E4H
排序后(补码)    B3H    E0H    F8H    04H    11H    16H    2AH    41H    43H    64H


排序前移码储存(80H行):

排序后移码储存(80H行)

排序后补码储存(90H行):

实验结果:主存中的存储结果符合预期。

实验数据1:

排序前元数据    -7    10    -42    16    -27    58    -32    31    9    44
排序前(移码)    79H    8AH    56H    90H    65H    BAH    60H    9FH    89H    ACH
排序后(移码)    56H    60H    65H    79H    89H    8AH    90H    9FH    ACH    BAH
排序后(补码)    D6H    E0H    E5H    F9H    09H    0AH    10H    1FH    2CH    3AH


排序前移码储存(80H行):

排序后移码储存(80H行)

排序后补码储存(90H行):

实验结果:主存中的存储结果符合预期。

5心得体会
在本次课程设计中,我设计了四位无符号数乘法、基于乘法的快速幂算法、冒泡排序的指令系统和相应的微指令系统、并编写了相对应的汇编语言程序。

在设计过程中遇到的问题有:

由于最初对于跳转指令的实现方式不是很明白,导致设计的几种跳转指令均不能正常工作,先是怀疑指令设计时微指令的实现方式不对。与资料书中的微指令系统进行比对后排除了这个可能。在仔细的查找了一遍说明手册后终于发现了问题所在,JC、JZ、JMP三条指令,虽然它们三条指令的微指令实现都是一样的,但是却有着不一样的功能,这是因为JC、JZ、JMP的指令码有差异。它们的指令码存入IR寄存器后,IR寄存器会根据指令码的后两位,来实现特定的功能。当指令码的后两位是00时,表示判进位跳转功能,故JC的指令码的后两位必须是00;当指令码的后两位时01时,表示判零跳转功能,故JZ的指令码的后两位必须是01;当指令码的后两位是11时,表示无条件跳转功能,故JMP的指令码的后两位必须是11。对微指令进行修改后程序成功运行。
在快速幂算法的实现中,用到了已经实现的乘法器。在对乘法器的代码进行修改时将原来乘法器中的初始化过程丢失了,导致最终的运算结果与期望结果相差很大。通过单步运行,分析每一条语句执行的过程,发现是乘法器修改后R2寄存器一直没有清空,导致单步结果一致累积出现数据错误。通过调试在乘法器之前加上初始化过程后程序成功运行。
心得体会:

在此次课程设计中,通过对cop2000实验平台的微指令系统设计和汇编程序的调试运行,使我深切体会到计算机发展初期进行程序设计的困难。在编写之前要对硬件平台有一个整体的把握,了解平台的控制方式,其次即使是一套程序,不同的硬件平台往往对应着不同的指令集,这是程序就要重新编写,这就导致了程序的应用受限。在编写过程中,使用C、JAVA等高级语言一条语句对应着的汇编语句可能多达十行,对应的微指令更是成倍增加,这就导致了早期程序开发的周期长,难度高,高级语言的出现大大加快了程序的设计进程。

在两周的设计周期中,通过上网查找资料,阅读文献了解cop2000的硬件电路控制方式和向老师同学请教。成功完成了指令系统的设计并通过了程序的验收。通过实验,我详细了解了数据在总线中的存取和流动,计算机的各种寻址方式和标志位的改变和条件跳转的使用及实现过程。我深刻体会到与最初的汇编相比现代计算机编程是多么的方便简洁。此次课程设计使我对计算机的硬件基础组成和使用有了全面的认识,面对高级语言中的语法能够联想出其在硬件层面的实现方式,能够透彻的理解语句的运行过程,对于以后的学习、程序设计和开发有着深刻意义。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/m0_66999594/article/details/139610553

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
华科计算机组成原理educoder源码是一个教育网站提供的计算机组成原理学习资料的源代码。它通过教学视频、实验代码和相关文档等多种形式,帮助学习者理解计算机组成原理的基本概念和原理。 该源码主要包括如下几个方面的内容:一是计算机硬件的基本组成部分,如CPU、内存、输入输出设备等。这部分内容主要通过实验代码来演示实际的计算机硬件工作原理,让学习者从零开始构建一个简单的计算机系统。 二是计算机指令和数据的存储与处理。通过实验代码的编写与执行,学习者可以了解指令和数据的存储方式以及计算机的指令执行过程。这部分内容有助于学习者理解计算机的运行过程和指令的执行机制。 三是计算机的系统总线和输入输出设备的控制。这部分内容通过实验代码来演示计算机内部各个部件之间的数据传输过程以及输入输出设备的控制方法。学习者可以通过实践操作来了解计算机系统总线的工作原理和输入输出设备的控制方式。 总之,华科计算机组成原理educoder源码是一个为学习计算机组成原理提供支持的教学资源,它通过实验代码的展示和解释,帮助学习者更好地理解和掌握计算机组成原理的相关知识。通过对该源码的学习和实践操作,学习者可以更深入地理解计算机硬件和软件之间的关系,提计算机系统设计和开发的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值