《CPU设计实验报告》word版.docx
《《CPU设计实验报告》word版.docx》由会员分享,可在线阅读,更多相关《《CPU设计实验报告》word版.docx(12页珍藏版)》请在冰豆网上搜索。
![《CPU设计实验报告》word版.docx](https://file1.bdocx.com/fileroot1/2023-1/23/5d2a9228-9376-41c1-bcc5-f347d04a589c/5d2a9228-9376-41c1-bcc5-f347d04a589c1.gif)
《CPU设计实验报告》word版
CPU设计实验报告
姓名:
学号:
邮箱:
一、实验目的:
1、掌握硬件描述语言VHDL和EDA工具QuartusII;利用VHDL设计16位串行CPU,实现算术和逻辑运算指令、转移指令、访存指令、堆栈指令和控制指令;
2、掌握CPU的调试和测试方法。
二、实验内容:
1、运用硬件描述语言VHDL实现寄存器堆和算数逻辑单元设计、指令集和指令格式、时序设计和整体结构设计、指令译码器的设计、访存单元的设计、调试单元的设计;
2、上机调试。
三、实验步骤:
1、寄存器堆的设计
寄存器堆由16个16位寄存器组成。
其中reset是异步清0端,reset=0时将所有寄存器清0。
dr_sel和sr_sel是目标寄存器和源寄存器编号,dr_out和sr_out输出目标寄存器和源寄存器的内容。
reg_sel指定一个寄存器编号,将该寄存器内容送给reg_out,这两个端口用于调试时观察每个寄存器的值。
reg_en是写允许端。
reg_en=“01”时,在clk的上升沿将from_alu写入dr_sel指定的寄存器;reg_en=“10”时,在clk的上升沿将from_mem写入dr_sel指定的寄存器。
reg_en取其他值时不改变寄存器堆的值。
设计方法:
subtypeWORDisstd_logic_vector(15downto0);
typeREGISTERARRAYisarray(0to15)ofWORD;
signalreg_bank:
REGISTERARRAY
则reg_bank就是我们所需要的寄存器堆。
写寄存器堆的方法:
reg_bank(conv_integer(dr_sel))<=from_alu;
读寄存器堆的方法:
dr_out<=reg_bank(conv_integer(dr_sel));
其中,conv_integer是STD_LOGIC_UNSINGED程序包提供的函数,将标准逻辑矢量转换成整数,作为reg_bank的下标。
2、算数逻辑单元设计
ALU可以实现16种运算。
alu_func是运算功能选择,alu_a和alu_b是两个操作数,c_in是进位标志输入,用于实现ADC和SBB。
alu_o是运算结果,c、s、z、o分别是进位标志,符号标志,零标志和溢出标志。
ALU功能如下图所示:
设计方法:
7条算术运算指令可以调用Quartus提供的模块lpm_add_sub实现。
在库使用说明中增加:
LIBRARYLPM;
USELPM.LPM_COMPONENTS.ALL;
在构造体的ARCHITECTURE和BEGIN关键字之间,用COMPONENT语句声明该模块:
COMPONENTlpm_add_sub
GENERIC(lpm_width:
NATURAL;
lpm_direction:
STRING;
lpm_type:
STRING;
lpm_hint:
STRING);
PORT(dataa:
INSTD_LOGIC_VECTOR(lpm_width-1DOWNTO0);
datab:
INSTD_LOGIC_VECTOR(lpm_width-1DOWNTO0);
cin:
INSTD_LOGIC;
result:
OUTSTD_LOGIC_VECTOR(lpm_width-1DOWNTO0);
cout:
OUTSTD_LOGIC;
overflow:
OUTSTD_LOGIC);
ENDCOMPONENT;
并定义几个信号:
SIGNALaddsub_cin:
STD_LOGIC;
SIGNALaddsub_c:
STD_LOGIC;
SIGNALaddsub_o:
STD_LOGIC;
SIGNALaddsub_a:
STD_LOGIC_VECTOR(15DOWNTO0);
SIGNALaddsub_b:
STD_LOGIC_VECTOR(15DOWNTO0);
SIGNALaddsub_r:
STD_LOGIC_VECTOR(15DOWNTO0);
在构造体中,用GENERICMAP和PORTMAP语句说明lpm_add_sub的连接方式:
ALU_ADDSUB:
lpm_add_sub
GENERICMAP(lpm_width=>16,
lpm_direction=>"ADD",
lpm_type=>"LPM_ADD_SUB",
lpm_hint=>"ONE_INPUT_IS_CONSTANT=NO,CIN_USED=YES")
PORTMAP(dataa=>addsub_a,
datab=>addsub_b,
cin=>addsub_cin,
result=>addsub_r,
cout=>addsub_c,
overflow=>addsub_o);
实现7条算术运算指令时,addsub_a、addsub_b、addsub_cin的取值如下:
按照上述取值方法,addsub_r和addsub_o就是这7条指令的运算结果和溢出标志。
对于ADD和ADC指令,addsub_c就是进位标志,对于SUB、CMP和SBB,应将addsub_c取反后作为进位标志,而INC和DEC不影响进位标志,应将c_in作为进位标志。
三条移位指令的实现方法:
即:
将被移出的位作为进位标志,将移位前后最高位的异或作为溢出标志。
3、标志寄存器的设计
标志寄存器用来保存c,s,z,o四个标志位。
flag_en=“00”时不改变四个标志位;flag_en=“01”时同时保存四个标志位;flag_en=“10”时将进位标志清零,用于实现CLC指令;flag_en=“11”时将进位标志置1,用于实现STC指令。
4、执行单元的设计
将寄存器堆,ALU和标志寄存器连接在一起,构成执行单元。
编译后,为执行单元生成一个图形符号。
5、指令译码单元的设计
指令集共35条指令,其中单字长(16位)指令33条,双字长(32位)指令2条。
双字长指令:
指令编码采用定长操作码,所有指令的操作码都是8位。
为了将汇编指令转换为二进制形式的机器指令,需要编写一个规则文件。
规则文件是一个纯文本文件,以行为单位,每行指定一条汇编指令的机器码。
注释:
以/开头的行是注释。
常量定义:
R0IS0定义了一个常量R0,其值为0
指令格式定义:
包括三个字段,第一字段是指令名,第二字段是操作数声明,第三字段说明如何生成该指令的机器码。
指令译码单元共产生9个控制信号。
dr_sel<=ir(7DOWNTO4);
sr_sel<=ir(3DOWNTO0);
alu_func<=ir(11DOWNTO8);
mem_wr:
为1表示写存储器,为0表示读存储器。
SIGNALOP:
STD_LOGIC_VECTOR(7DOWNTO0);
OP<=ir(15DOWNTO8);
mem_wr<=‘1’WHENS=‘0’ANDOP=“10010000”ELSE--STR指令
‘1’WHENS=‘0’ANDOP=“10100000”ELSE--PUSH指令
'0';
类似地写出以下5个控制信号的代码:
reg_en:
寄存器堆的写允许信号。
flag_en:
标志寄存器的写允许信号。
jmp_relv:
类型为STD_LOGIC
为‘1’表示进行相对转移,为‘0’表示不进行相对转移。
sp_en:
类型为STD_LOGIC_VECTOR(1DOWNTO0)
为“01”表示堆栈指针SP加1,为“10”表示堆栈指针SP减1.
addr_sel:
类型为STD_LOGIC_VECTOR(2DOWNTO0)
用于确定S=0时地址总线上的值。
“000”表示SP,“001”表示SP-1,“010”表示DR,“011”表示SR,“100”表示PC。
6、节拍发生器
节拍发生器用来产生节拍信号S。
reset=0时将S清0;
clk出现上升沿时,若S=0且ir中保存的是HLT指令,则S继续为0,CPU进入死锁状态;否则对S取反。
7、访存单元的设计
data_bus连接数据总线,端口方向为INOUT;wr连接存储器的读写控制端;addr_bus连接地址总线。
访存单元的内部结构:
IR:
指令寄存器。
取指时将数据总线上传来的指令锁存进IR。
初始化时可以向IR存入NOP指令。
SP:
堆栈指针。
执行堆栈指令后根据sp_en的值对SP进行修改。
初始化时向SP存入0280H。
PC:
程序计数器
SIGNALOP:
STD_LOGIC_VECTOR(7DOWNTO0);
SIGNALoffset:
STD_LOGIC_VECTOR(15DOWNTO0);
OP<=ir(15DOWNTO8);
offset<=“11111111”&ir(7DOWNTO0)WHENir(7)='1'ELSE
“00000000”&ir(7DOWNTO0);--将偏移量扩展为16位
PROCESS(reset,clk)
VARIABLEtmp:
STD_LOGIC_VECTOR(15DOWNTO0);
BEGIN
IFreset='0'THEN
tmp:
=x“0000”;
ELSIFclk'EVENTANDclk='1'THEN
IFS='1'THEN--取指令之后PC加1
tmp:
=tmp+1;
ELSIFjmp_relv='1'THEN--进行相对转移
tmp:
=tmp+offset;
ELSIFOP=“11000000”THEN--JMPA指令
tmp:
=data_bus;
ELSIFOP=“11010000”THEN--MVRD指令
tmp:
=tmp+1;
ENDIF;
ENDIF;
pc<=tmp;
ENDPROCESS;
存储器地址选择:
PROCESS(reset,S,addr_sel,sp,dr,sr,pc)
VARIABLEtmp:
STD_LOGIC_VECTOR(15DOWNTO0);
BEGIN
IFreset='0'THEN
tmp:
=x“0000”;
ELSIFS='1'THEN--取指令
tmp:
=pc;
ELSE
IFaddr_sel=“000”THEN--PUSH
tmp:
=sp;
ELSIFaddr_sel=“001”THEN--POP
tmp:
=sp-1;
ELSIFaddr_sel=“010”THEN--STR
tmp:
=dr;
ELSIFaddr_sel=“011”THEN--LDR
tmp:
=sr;
ELSIFaddr_sel=“100”THEN--双字长指令
tmp:
=pc;
ELSE
tmp:
=“XXXXXXXXXXXXXXXX”;
ENDIF;
ENDIF;
addr_bus<=tmp;
ENDPROCESS;
存储器读写控制:
--mem_wr=‘1’:
wr<=clk,写存储器
--mem_wr=‘0’:
wr<=‘1’读存储器
PROCESS(clk,mem_wr,data_bus,sr)
BEGIN
IFmem_wr=‘1’THEN--写存储器(STR指令,PUSH指令)
data_bus<=sr;
wr<=clk;
ELSE--读存储器
data_bus<=“ZZZZZZZZZZZZZZZZ”;
wr<='1';
mem_data<=data_bus;
ENDIF;
ENDPROCESS;
8、调试单元的设计
调试单元是一个多路选择器,用于在调试过程中观察CPU内部主要寄存器的值。
reg_sel是数据选择端。
取63时将ir送到输出;取62时将pc送到输出;取16时将sp送到输出;取0~15时,将来自寄存器堆的reg送到输出。
调试过程中,调试程序debugcontroller会在reg_sel输入端循环地输入0~63,并将调试单元的输出在程序界面上进行显示。
寄存器堆和调试单元的连接关系:
将reg_sel[5..0]的最低四位reg_sel[3..0]送给寄存器堆的寄存器选择端,将寄存器堆的输出端reg_out作为调试单元的输入端reg。
当reg_sel[5..0]的最高两位为“00”,而最低四位在0到15之间变化时,debug_out输出的恰好是寄存器R0到R15。
9、上机调试
上机调试步骤:
将exe_unit,id_unit,mem_unit,timer,debug_unit连接成完整的CPU:
CPU外部端口包括:
输入端:
reset,clk,reg_sel[5..0]
输出端:
addr_bus[15..0],debug_out[15..0],wr,c_flag,z_flag,s_flag,o_flag
输入输出端:
data_bus[15..0]
共61个引脚。
芯片类型:
Cyclone家族的EP1C6Q240C8
引脚分配:
reset:
240clk:
29wr:
75
c_flag:
86z_flag:
85s_flag:
83o_flag:
84
reg_sel[5..0]:
17,16,15,14,13,12
addr_bus[15..0]:
64,63,62,61,60,59,58,57,48,47,46,45,44,43,42,41
data_bus[15..0]:
237,236,235,234,226,225,224,223,217,216,215,214,203,202,201,200
debug_out[15..0]:
181,180,179,178,177,175,174,173,165,164,163,162,161,160,159,158
然后将以上程序下载到实验箱芯片中;
设置实验箱:
SW22接USB,REGSEL接1,CLKSEL接0,FDSEL接1
调试步骤:
1.打开规则文件
2.打开汇编源文件
3.CompileCode
4.UploadBIN
5.CPU复位
6.BeginDebug
7.运行程序,可以选择半时钟周期运行、单时钟周期运行或运行至断点(双击某一行可以设置断点)。
运行过程中通过RegWindow观察CPU内部各寄存器的值。
8.EndDebug
四、实验心得:
通过对本门课程的学习,复习巩固了硬件描述语言VHDL;掌握了工具QuartusII的使用;深入了解了CPU的基本结构和原理;掌握了测试和调试的步骤。
非常感谢在实验过程中给予帮助的老师和同学,是我能顺利完成实验。