******
设 计 性 实 验(报告)
题 目: 简单16位CPU设计 课 程: 计算机系统结构 院 (部): 计算机科学与技术学院 专 业: 计算机科学与技术专业 班 级: *** 学生姓名: *** 学 号: ****** 指导教师: *** 完成日期: 2010-12-8
*******计算机科学与技术学院
简单16位CPU设计
一、实验内容
完成从指令系统到CPU的设计,编写测试程序,通过运行测试程序对CPU设计进行正确性评定。具体内容包括:典型指令系统(包括运算类、转移类、访存类)设计;CPU结构设计;CPU的VHDL程序代码编写;规则文件与调试程序设计;CPU调试及测试程序运行。 二、实验目的及要求
1.加深对计算机的基本概念、基本原理和基本结构的理解; 2.掌握计算机组成与系统结构方面的基本设计、分析与实现方法; 3.掌握典型16CPU设计方法;
4.熟练掌握VHDL语言及应用,完成对CPU各功能模块的代码描述,实现各个功能模块部分的连接,从而形成一个完整的CPU体系结构;
5.学会利用先进的硬件设计工具软件Quartus II对程序进行仿真和调试; 6.掌握基于“TEC-CA试验教学系统”进行CPU调试的方法。 三、实验仪器设备
(1)TEC-CA试验教学系统; (2)虚拟仪器平台; (3)计算机。 (4)实验环境 四、实验方案设计 (一)指令系统设计 1、指令系统的作用和地位
指令系统是从程序设计者看到的机器的主要属性,是软、硬件的主要界面。 指令系统是计算机系统结构的主要组成部分。 指令系统是软件与硬件分界面的一个主要标志。 指令系统是软件与硬件之间互相沟通的桥梁。 2、指令系统的设计规范
设计的原则:支持编译系统能高效、简易地将源程序翻译成目标代码。
正交性:指令字段编码相互独立。 规整性:相似操作有相同的规定。 可扩充性:操作码冗余。
对称性:A-B=》A;A-B=》B,便于编译。 3、CPU中操作数的存储方法
CPU中操作数的存储方法是各种指令集结构之间最主要的区别所在,其影响运算器的组织。
CPU中用来存储操作数的存储单元主要有: (1)堆栈; (2)累加器; (3)一组寄存器;
通用寄存器型指令集结构的主要优点: (1)使编译器有效地使用寄存器;
(2)在表达式求值方面,比其它类型指令集结构,具有更大的灵活性; (3)寄存器可以用来存放变量;
a.减少存储器的访问量,加快程序的执行速度。(因为寄存器比存储器快) b.可以用更少的地址位来寻址寄存器,从而可以有效改进程序的目标代码大小。
由于通用寄存器型指令系统存在诸多的优点因此我们选择通用寄存器型指令结构。
4、 指令格式与功能 1、ADD DR,SR
指令编码: 0000 DR SR 0000 0111 功能:DR DR+SR,影响C和Z标志,PC PC+1。 2、INC DR
指令编码: 0001 DR SR 0000 0111 功能:DR DR+1,影响C和Z标志,PC PC+1 3、SUB DR,SR
指令编码: 0010 DR SR 0000 0111 功能: DR DR-SR,影响C和Z标志,PC PC+1 4、DEC DR
指令编码: 0011 DR SR 0000 0111 功能:DR DR-1,影响C和Z标志,PC PC+1 5、AND DR,SR
指令编码: 0100 DR SR 0000 0011 功能:DR DR and SR,影响Z标志,PC PC+1 6、OR DR,SR
指令编码: 0101 DR SR 0000 0011 功能:DR DR or SR,影响Z标志,PC PC+1 7、NOT DR
指令编码: 0110 DR SR 0000 0011 功能:DR not SR,影响Z标志,PC PC+1 8、MOV DR,SR
指令编码: 0111 DR SR 0000 0001 功能:功能:DR SR,不影响标志位,PC PC+1 9、JMP ADR 1000 0000 0000 0000 指令编码: ADR 功能:PC ADR 10、
JNC ADR
指令编码: 1001 0000 ADR -@-1 功能:如果C=0,则PC ADR;如果C=1,则PC PC+1 11、
JNZ ADR
指令编码: 1010 0000 ADR -@-1 功能:如果Z=0,则PC ADR;如果C=1,则PC PC+1 12、
MVRD DR,DATA
指令编码: 1000 0000 0000 0000 ADR
功能:DR DATA,PC PC+2 13、 LDR DR,SR
指令编码: 1101 DR SR 0000 0001 功能:DR [SR],PC PC+1 14、
STR SR,DR
指令编码: 1110 DR SR 0000 0000 功能:[DR] SR,PC PC+1 15、
NOP
指令编码: 0111 0000 0000 0000 功能:PC PC+1 16、补充: PUSH SR POP DR RET CALL ADR 5、 指令编码 CPU为16位:CPU的并行处理能力16位,总线宽度为16位,指令长度至少16位。
采用对称式寄存器结构:无累加器的概念,形成的通用寄存器组有两个输出端口(读端口)、一个输入端口(写端口)。共设有4个R(R0-R3)。
指令分类:运算类、转移类、访存类。 用两位编码: IR15, IR14 运算类: 0 0 转移类: 1 0 访存类: 1 1 运算类:
(IR15=0) IR14, IR13, IR12
01000110 01000111 01010001 10000000 SR入栈 出栈 DR 子程序返回 调用首地址在ADR的子程序(双字指令) ADD 0 0 0 INC 0 0 1 SUB 0 1 0
DEC 0 1 1 AND 1 0 0 OR 1 0 1 NOT 1 1 0 NOP 1 1 1 结果处理(送R或送M)
两种选择,1位编码: IR0=1:送DR; 影响Z标志否, 1位编码:IR1=1,影响; 影响C标志否, 1位编码:IR2=1,影响。 没用的位设为0(保留位) 指令机器码:
ADD DR, SR INC DR SUB DR, SR DEC DR AND DR, SR OR DR, SR NOT DR MOV DR, SR JMP ADR 0000 DR SR-0000 0111 0001 DR SR-0000 0111 0010 DR SR-0000 0111 0011 DR SR-0000 0111 0100 DR SR-0000 0011 0101 DR SR-0000 0011 0110 DR SR-0000 0011 0111 DR SR-0000 0001 1000 0000—0000 0000 “16位ADR” JNC ADR JNZ ADR MVRD RD, DATA LDA DR, SR STR SR, DR NOP 1001 0000- rel(8 bit) 1010 0000-rel(8 bit) 1100 0000-0000 0000 1101 DR SR- 0000 0001 1110 DR SR-0000 0000 0111 0000---0000 0000 说明:(1)本CPU中含有4个通用寄存器,用R0,R1,R2,和R3表示。源寄存
器用SR表示,目的寄存器用DR表示,因此DR和SR在指令编码中各
用2bit编码。
(2)指令编码中的@代表该指令当前的PC值。
(3)设计指令系统时首要考虑的是指令要满足功能的需求。这个指令系统
还包括PUSH、POP、以上指令包括运算指令、转移指令和存储指令3类。这三类指令根据
IR15、IR14进行分类: IR15为0时运算指令; IR15、IR14为10时转移指令; IR15、IR14为11时存储指令。
(4)考虑指令译码方便,减少硬件资源的消耗:
①算术逻辑指令的IR14—IR12对应运算器ALU的3位运算操作码 ②当IR0=1时,本指令中对DR的写操作 ③当IR1=1时,本指令影响标志位Z ④当IR2=1时,本指令影响标志位C
⑤NOP指令实际上是一条“MOV R0,R0”指令,只是不改变目的寄
存器的内容。
(二)设计指令流程; 1、时序部件(电路) (1)概述
CPU工作的关键部件,产生计算机执行机器指令所需的时序信号。计算机的工作过程:一个指令周期接一个指令周期;在一个指令周期内是一个机器周期接一个机器周期;在一个机器周期内是一个节拍接一个节拍;在一个节拍内产生哪些微操作信号取决于指令操作流程。伴随着指令的执行,计算机内部有两股信息在流动:一股是数据流,流过不同的部件完成不同处理;一股是控制信号流,控制数据从何处流出、经过何地(运算处理部件)、流往何处,微控制信号的产生由指令操作流程规定(操作码),控制信号有效状态的先后顺序由节拍控制。 (2)机器周期
目标:一个机器周期执行一条单字指令。 如:ADD DR,SR
执行过程:1)取指;2)译码分析;3)执行(运算);4)写结果。
可合并为三个阶段:1)取指;2)分析、执行;3)写结果(存储器、寄存器)
(3)节拍
三个阶段(取指、分析执行、写结果)对应三个节拍。
t1:取指—t1上升沿MADDRPC,t2上升沿指令送IR;PC+1(temp) t2:译码分析、运算处理(Z、C—TEMP);
t3:存储器、寄存器读写,下降沿写寄存器,改变C、Z、PC等。 1、ADD DR,SR
t1 t2 t3 Madd<=pc Result<=DR+SR R/W<=1 PC<=pc_t Dread<=ob DR<=Result
IR<=Dread Z<=Z_TEMP
PC_t<=PC+1 C<=C_TEMP 2、INC DR
t1 t2 t3 Madd<=pc Result<=DR+1
R/W<=1 Z_TEMP PC<=pc_t Dread<=ob DR<=Result
Z_TEMP IR<=Dread Z<=Z_TEMP
PC_t<=PC+1 C<=C_TEMP
C_TEMP 3、SUB DR,SR
t1 t2 t3 Madd<=pc Result<=DR-SR R/W<=1 PC<=pc_t Dread<=ob DR<=Result
IR<=Dread Z<=Z_TEMP
C_TEMP
Z_TEMP
C_TEMP
PC_t<=PC+1 C<=C_TEMP 4、DEC DR
t1 t2 t3 Madd<=pc Result<=DR-1 R/W<=1
PC_t<=PC+1 7、NOT DR
t1 t2 t3 Madd<=pc Result<=not DR R/W<=1 Z_TEMP PC<=pc_t
Z_TEMP Dread<=ob
PC<=pc_t Dread<=ob
C_TEMP DR<=Result
IR<=Dread Z<=Z_TEMP
PC_t<=PC+1 C<=C_TEMP 5、AND DR,SR
t1 t2 t3 Madd<=pc Result<=DR and SR R/W<=1
Z_TEMP PC<=pc_t
Dread<=ob DR<=Result
IR<=Dread Z<=Z_TEMP
PC_t<=PC+1 6、OR DR,SR
t1 t2 t3 Madd<=pc Result<=DR or SR R/W<=1 Z_TEMP PC<=pc_t Dread<=ob DR<=Result IR<=Dread Z<=Z_TEMP
DR<=Result
IR<=Dread Z<=Z_TEMP
PC_t<=PC+1 8、MOV DR,SR
t1 t2 t3 Madd<=pc Result<= SR
R/W<=1 PC<=pc_t Dread<=ob DR<=Result
IR<=Dread PC_t<=PC+1
9、JMP ADR
t1 t2 t3 Madd<=pc Madd<= PC_t R/W=1 R/W<=1 Dread<=ob Dread<=ob PC<=Dread
IR<=Dread
PC_t<=PC+1 10、JNC ADR
t1 t2 t3 Madd<=pc generate if c_z_j_f=1 R/W<=1 c_z_j_f then PC<=sjmp_a Dread<=ob sjmp_a else PC<=PC_t
IR<=Dread
PC_t<=PC+1 11、JNZ ADR
t1 t2 t3 Madd<=pc generate if c_z_j_f=1 R/W<=1 c_z_j_f then PC<=sjmp_a Dread<=ob sjmp_a else PC<=PC_t
Dread<=ob
Dread<=ob DR<=Dread
IR<=Dread PC<=PC_t PC_t<=PC+1 14、STR SR,DR
IR<=Dread t1 t2 t3 PC_t<=PC+1 12、MVRD DR,DATA
t1 t2 t3 Madd<=pc Madd<= PC_t R/W=1 R/W<=1 Dread<=ob Dread<=ob DR<=Dread IR<=Dread PC<=PC+2 PC_t<=PC+1 13、LRD DR,SR
t1 t2 t3 Madd<=pc Madd<= SR R/W=1 R/W<=1 说明:
(1) Mem_Addr是存储器地址总线。 (2) Ob是存储器数据总线。
(3) We是存储器读写信号,为0时写存储器,为1时读存储器。 (4) Z_tmp是运算产生的结果为0的标志,z_out是本条指令执行完成
后的结果为0的标志。
(5) C_tem是运算产生的进位标志,c_out是本条指令执行完成后的进
位标志。
(6) IR是指令寄存器。
(7) C_z_j_flag是条件转移指令“JNC ADR”或者“JNZ ADR”产生的
Madd<=pc Madd<= DR R/W=0 R/W<=1 ob<=SR
Dread<=ob IR<=Dread PC<=PC_t PC_t<=PC+1 15、NOP
t1 t2 t3 Madd<=pc
R/W<=1 Dread<=ob IR<=Dread PC<=PC_t PC_t<=PC+1
条件转移指令
(8) Sjmp_addr是条件转移指令“JNC ADR”或者“JNZ ADR”产生的
条件转移地址。
(9) Result是运算器产生的运算结果。
(三)CPU结构设计 1. 一条指令需要3拍时间
(1)t1:取指。t1上升沿MADDR PC,t2上升沿指令送IR;PC+1(temp) (2)t2:译码分析、运算处理(Z、C—TEMP);
(3)t3:存储器、寄存器读写,下降沿写寄存器,改变C、Z、PC等。
三周期指令:包括所有的算术逻辑指令:ADD,SUB,DEC,INC,CMP,AND,OR,XOR,TEST,SHL,SHR,SAR。除了绝对转移指令JMPA外的所有控制转移指令:JR,JRC,JRNC,JRZ,JRNZ。一条数据传送指令:MOV。这些指令只需三个周期就可以完成,其中,前两个周期用于取指。这些指令都可以用操作码前两位都是00,所以很容易和其它指令区别。见下图:
000010011PC->AR更新PCMem->IR算逻运算
三周期指令时序图 2.简单CPU结构:
无流水、无Cache;主要部件有:运算单元ALU;通用寄存器组;控制器(译码);取指操作(时序电路);存储器操作。
CPU由5部分组成:取指部分instru_fetch、指令译码部分decoder_unit、执行部分exe_unit、存储器部分memory_unit、和通用寄存器组regfile。另外,还需设计一个程序包exe_cpu_components,将各底层设计实体作为元件存储,供各设计实体使用。顶层设计实体exe_cpu完成CPU 的5个组成部分的连接。 3、整体结构设计
我们在设计整体结构时,依据的是各指令的数据通路。然后采用自顶向下,逐步分解细化的方法进行设计。先整体模块,后局部模块。
CPU整体结构
串行指令CPU整体结构图CLKFLAGRegSel<寄存器选择>SelSrcSelOprSelDst<数据运算,传送>控制器运算器(含寄存器堆)SCI<进位>SST<设置状态>SA,SB<寄存器选择>FLAGALU输出AIsel<控制AR,IR接收>BusSel<选择总线数据来源>AR(地址寄存器)IR(指令寄存器)符号扩展Bus MUX寄存器数据<调试用>数据总线地址总线wrMem<内存读写> 串行指令CPU整体结构图 4、 各分模块结构设计 控制器结构
串行指令CPU控制器结构图指令字(16位)CLKRESET指令字的高8位(即操作码)FLAGStateGeneratorState(2~0)DecoderSelSrcSelOprSelDstBusSelAISelwrMemSCISSTSASB
串行指令CPU控制器结构图
运算器结构
运算器结构图RARBDQSelSrcMUXExtTo17bitsExtTo17bitsClkSelOprLatchLatchRSCICCinSOPRATIONMUX加法器与门或门异或SHLSHRSARCXFDSSTSelOprCXRAClkSASBRegSelSelDstC,Z,V,SFLAGMUXYRegArrayRARBRegOut 串行指令CPU运算器结构图
(四)CPU设计实现
1、通用寄存器组regfile
通用寄存器组内包含4个16位寄存器。这是一个具有写入端口,2个读出端口的通用寄存器组。写入端口将指令执行后得到的目的寄存器的值在t3的下降沿写入目的寄存器中。只有具有写目的寄存器功能的指令执行结束时才写目的寄存器。有些指令,如JMP指令等执行结束后不会改变通用寄存器组的值。通用寄存器组的2个读出端口,一个是目的寄存器读出端口,一个是源寄存器读出端口,从这2个端口读出的内容供执行部分exe_unit和存储器部分memory_unit使用。
通用寄存组内还有2个标志位:z_out和c_out,在t3的下降沿根据指令执行的结果改变或者不改变它们的值。这2个标志位的值送执行部分exe_unit使用。
通用寄存器组各引脚结构如下图:
REGFILEDR[1..0]SR[1..0]RESETWRITE_SCLKCHANGE_ZCHANGE_CC_INZ_IND_INPUT[15..0]C_OUTZ_OUTOUTPUT_DR[15..0]OUTPUT_SR[15..0]inst
图regfile
通用寄存器组是通过4个寄存器、2个2-4译码器和1个4-1选择器构成,其各个部分连接关系如下图所示:
图regfile组成
通用寄存器组部分regifile源代码: (1)寄存器reg
regfile的引脚如下图所示:
REGRESETQ_OUTPUT[15..0]D_INPUT[15..0]CLKWRITE_SSELinst 图regfile
library ieee;
use ieee.std_logic_1164.all;
entity reg is port (reset: in std_logic;
d_input: in
std_logic_vector(15 downto 0); clk:
in std_logic;
write:
in std_logic; sel: in std_logic;
q_output: out
std_logic_vector(15 downto 0) ); end reg;
architecture a OF reg is begin process(reset,clk) begin IF reset = '0' then
q_output <= x\"0000\"; elsif clk'event and clk =
'0' then --时钟下降沿触发 if sel ='1' and write = '1' then q_output <= d_input;
end if;
end if;
end process;
end a;
(2)2-4译码器decoder_2_to_4 2-4译码器的引脚如下图所示:
DECODER_2_TO_4SEL[1..0]SEL00SEL01SEL02SEL03inst2
图2-4译码器
Library ieee;
use ieee.std_logic_1164.all;
entity decoder_2_to_4 is port (
sel: in
std_logic_vector(1 downto 0); sel00: out std_logic; sel01: out std_logic; sel02: out std_logic;
sel03: out std_logic );
end decoder_2_to_4;
architecture
Behavioral
of
std_logic_vector(15 downto 0);
sel:
in
decoder_2_to_4 is begin
sel00 <= (not sel(1)) and (not std_logic_vector(1 downto 0);
out_put:
out
std_logic_vector(15 downto 0)); sel(0));
sel01 <= (not sel(1)) and
sel(0) ;
sel02 <= sel(1) and (not
sel(0)) ;
sel03 <= sel(1) and sel(0) ;
end Behavioral;
(3)4选1选择器mux_4_to_1 4-1 选择器的引脚如下图所示:
MUX_4_TO_1INPUT0[15..0]OUTPUT[15..0]INPUT1[15..0]INPUT2[15..0]INPUT3[15..0]SEL[1..0]inst1 图4-1选择器
library ieee;
use ieee.std_logic_1164.all;
entity mux_4_to_1 is port ( input0, input1, input2,
input3:
in
end mux_4_to_1;
architecture Behavioral
of
mux_4_to_1 is begin
mux: process(sel, input0, input1, input2, input3) begin case sel is
when \"00\" =>
out_put <= input0;
when \"01\" =>
out_put <= input1;
when \"10\" =>
out_put <= Input2;
when \"11\" =>
out_put <= Input3;
end case;
end process; end Behavioral; (4)通用寄存器组regfile library ieee;
use ieee.std_logic_1164.all; use work.exp_cpu_components.all;
entity regfile is port ( DR: in
std_logic_vector(1 downto 0); --源寄存器号
SR:
in
std_logic_vector(1 downto 0); --目的寄存器号 reset: in std_logic;
write:
in std_logic;
--写寄存器信号 clk:
in std_logic;
d_input:
in std_logic_vector(15 downto 0); --写寄存器的数据
change_z: in std_logic;
--如果为1,则重新设置z标志
change_c: in std_logic;
c_in: in std_logic; z_in: in std_logic;
R0,R1,R2,R3:
out
std_logic_vector(15 downto 0);
output_DR:
out
std_logic_vector(15 downto 0);
output_SR:
out
std_logic_vector(15 downto 0);
c_out: out std_logic;
z_out: out std_logic ); end regfile;
architecture struct of regfile is signal reg00, reg01, reg02,reg03: std_logic_vector(15 downto 0); signal sel00, sel01, sel02, sel03: std_logic; begin
R0 <= reg00; R1 <= reg01;
R2 <= reg02; R3 <= reg03;
z_c_proc: process(reset,clk) --
对指令执行结束后的z、c标志进行处理 begin
if reset = '0' then z_out <= '0';
c_out <= '0';
elsif clk'event and clk = '0'
then if change_z = '1' then
z_out <= z_in;
end if;
if change_c = '1' then
c_out <= c_in;
end if; end if; end process;
Areg00: reg port map(--寄存器R0 reset d_input => reset,
=> d_input,
q_output => reg03);
des_decoder: decoder_2_to_4 port clk
=> clk,
write
=> write, sel
=> sel00,
q_output => reg00);
Areg01: reg port map(--寄存器R1 reset => reset, d_input => d_input, clk
=> clk,
write
=> write,
sel => sel01,
q_output => reg01 ); Areg02: reg port map(--寄存器R2 reset => reset, d_input => d_input, clk
=> clk,
write
=> write, sel
=> sel02,
q_output => reg02);
Areg03: reg port map(
--寄存器R3 reset => reset, d_input => d_input, clk
=> clk,
write
=> write,
sel
=> sel03,
map( --2 — 4译码器
sel
=> DR,
sel00 => sel00, sel01 => sel01, sel02 => sel02,
sel03 => sel03 );
muxB: mux_4_to_1 port map( --目的寄存器读出4选1选择器
input0 => reg00, input1 => reg01, input2 => reg02, input3 => reg03, sel => DR,
out_put => output_DR);
muxA: mux_4_to_1 PORT MAP( --源寄存器读出4选1选择器
input0
=> reg00, input1 => reg01, input2 => reg02, input3 => reg03,
sel
=> SR,
out_put => output_SR);
end struct;
2、取指部分instru_fetch 取指部分完成4项工作:
(1)产生时钟信号t1、t2和t3,供实验CPU各部分使用
(2)在复位信号reset为低时将PC复位为0;在一条指令执行结束后,根
据指令执行的结果在t3的下降沿改变PC的值。
(3)将从存储器读出的指令的堆一个字在t2的上升沿送至指令寄存器IR中。 (4)计算PC+1的值pc_inc,为双字指令取第二个指令字做准备。 取指部分instru_fetch源代码 取指部分的各引脚关系如图:
INSTRU_FETCHRESETCLKDATA_READ[15..0]LJ_INSTRUCTDW_INSTRUCTC_Z_J_FLAGSJMP_ADDR[15..0]inst6PC_INC[15..0]IR[15..0]T1T3PC[15..0]--长转移指令
DW_intruct:in std_logic; c_z_j_flag: in std_logic;
--为1时进行条件转移
sjmp_addr: in
std_logic_vector(15 downto 0); --条件转移指令的转移地址
t1,t2,t3: buffer std_logic;
pc:
buffer
图instru_fetch
library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.exp_cpu_components.all;
entity instru_fetch is
port(reset,clk:in std_logic;
data_read: in
std_logic_vector(15 downto 0);
pc_inc:
buffer
std_logic_vector(15 downto 0);
IR:
out
std_logic_vector(15 downto 0)); end instru_fetch;
architecture behav of instru_fetch is signal start: std_logic; begin
IR_poc: process(reset,t2) begin
std_logic_vector(15 downto 0); --存储器读出的数
lj_instruct: in std_logic;
if reset = '0' then
IR <= x\"7000\"; --nop指令
t2 <= t1; t3 <= t2;
elsif t2'event and t2 = '1' then
IR <= data_read;
end if;
end process;
pc_inc <= pc + '1';
--为取双
end if;
end process;
process(reset,clk) begin
if reset = '0' then start <= '1';
else
if clk'event and clk ='0'
字指令的第2个字或者计算相对转移地址做准备
PC_proc: process(reset,t3) begin
if reset = '0' then
pc <= x\"0000\";
elsif t3'event and t3 = '0' then
if lj_instruct = '1' then
pc <= data_read;
then start <= '0';
end if;
elsif c_z_j_flag ='1' then
pc <= sjmp_addr;
end if;
end process;
process(reset,clk) begin
if reset = '0' then
elsif DW_intruct = '1' then
pc <= pc + \"10\";
else
pc <= pc_inc;
end if;
t1 <= '0'; t2 <= '0';
t3 <= '0';
elsif clk'event and clk = '1'
end if;
end process; end behav;
then t1 <= start or t3; 3、
指令译码部分decoder_unit
指令译码部分根据指令寄存器IR的值产生实验CPU所需要的各种控制信号和其他信号:
SR:源寄存器号(编址) DR:目的寄存器号(编址)
Op_code:控制ALU进行8种运算操作的3位编码 Zj_instruct:为1表示本条指令是条“JNZ ADR”指令 Cj_instruct: 为1表示本条指令是条“JNC ADR”指令 Lj_instruct: 为1表示本条指令是条“JMP ADR”指令
DRWr:为1表示在t3的下降沿将本条指令的执行结果写入目的寄存器 Mem_Write:为1表示本条指令有存储器写操作,存储器的地址是源寄存器
的内容。
DW_instruct:为1表示本条指令是双字指令
Change_z:为1表示本条指令可能改变Z(结果为0)标志 Change_c:为1表示本条指令可能改变C(进位)标志
Sel_memdata:为1表四本条指令写入目的寄存器的值来自读寄存器 R_sjmp_addr:计算条件转移地址所需要的16位相对地址。它是由条件转移
指令中的8位相对地址经过符号扩展生成的。
指令译码器在传统上属于控制器部分,是控制器的核心。所谓组合逻辑控制器是指指令译码器是有组合逻辑构成的,所谓微程序控制器是指指令译码器主要由控制存储器ROM和少许组合逻辑构成的。 指令译码部分decoder_unit源代码:
decoder_unit的引脚关系如下图:
DECODER_UNITIR[15..0]SR[1..0]DR[1..0]OP_CODE[2..0]ZJ_INSTRUCTCJ_INSTRUCTLJ_INSTRUCTDRWRMEM_WRITEDW_INTRUCTCHANGE_ZCHANGE_CSEL_MEMDATAR_SJMP_ADDR[15..0]inst7library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.exp_cpu_components.all;
entity decoder_unit is
port (IR:
in
std_logic_vector(15 downto 0);
SR:
out
std_logic_vector(1 downto 0);
DR:
out
std_logic_vector(1 downto 0);
op_code: out
std_logic_vector(2 downto 0); zj_instruct: out std_logic; cj_instruct: out std_logic;
lj_instruct: out std_logic; DRWr: buffer std_logic; --为1时写DR寄存器
Mem_Write: out std_logic; DW_intruct: buffer std_logic; change_z: out std_logic; change_c: out std_logic; sel_memdata: out std_logic; --为1时存储器的读出数据作为写入DR的数据
r_sjmp_addr:
out
std_logic_vector(15 downto 0) --相对转移地址); end decoder_unit;
architecture behav of decoder_unit is begin
SR <= IR(9 downto 8); DR <= IR(11 downto 10);
sel_memdata <= IR(15) and IR(14) and (not IR(13));
change_z <= not IR(15) and IR(1); change_c <= not IR(15) and IR(2); DRWr_proc: process(IR) begin if IR(15) = '0' then if IR(0) ='1' then
DRWr <= '1';
Else DRWr <= '0';
end if;
elsif IR(14) = '1' and IR(13) =
'0' then DRWr <= '1'; else
DRWr <= '0';
end if;
end process; sj_addr_proc:
process(IR) --
条件转移指令的相对转移地址从8位扩展到16位 begin if IR(7) ='1' then
r_sjmp_addr <= \"11111111\" &
IR(7 downto 0); else
r_sjmp_addr <= \"00000000\" &
IR(7 downto 0);
end if;
end process;
M_instruct:process(IR) begin
case IR(15 downto 12) is
when \"1000\" | \"1100\" => begin
case IR(15 downto 12) is
when \"1000\" => --jmp adr
zj_instruct <= '0'; cj_instruct <= '0'; lj_instruct <= '1';
--jmp addr;mvDR dr,data
Mem_Write <= '0'; DW_intruct <= '1';
when \"1110\" => -- str dr,sr
Mem_Write <= '1'; DW_intruct <= '0';
when \"1001\" => --jnc addr
zj_instruct <= '0'; cj_instruct <= '1'; lj_instruct <= '0';
when others =>
Mem_Write <= '0'; DW_intruct <= '0';
end case; when \"1010\" => --jnz addr
zj_instruct <= '1'; cj_instruct <= '0'; lj_instruct <= '0';
end process;
ALUOP_CODE_PROC: PROCESS(IR) begin
if IR(15) = '0' then
op_code <= IR(14 downto 12); else op_code <= \"111\"; end if;
when others =>
zj_instruct <= '0'; cj_instruct <= '0'; lj_instruct <= '0';
end case;
end process;
Jinstruct_PROC: process(IR) 4、执行部分exe_unit 执行部分完成下列任务:
end process; end behav;
(1)8种算术逻辑运算:加,加1,减,减1,与,或,非核数据传送,并临时将运算结果存放在result中。根据运算结果产生进位标志,临时存放在c_tmp中;根据运算结果产生结果为0的标志,临时存放在z_tmp中。
(2)产生存储器读写操作所需要的存储器地址Mem_Addr。存储器地址是根据下列情况决定的:在t1节拍时选择pc,在双字指令时选择pc_inc,在LDR指令时
选择SR(源寄存器)内容,在STR指令时选择DR(目的寄存器)内容。 (3)产生条件转移指令(jnc和jnz)所需要的转移标志c_z_j_flag(为1表示转移)和转移地址sjmp_addr。
执行部分的核心传统上属于运算器,是运算器的核心。 执行部分exe_unit源代码: exe_unit引脚关系如下:
EXE_UNITT1C_TMPOP_CODE[2..0]Z_TMPZJ_INSTRUCTC_Z_J_FLAGCJ_INSTRUCTSJMP_ADDR[15..0]PC[15..0]MEM_ADDR[15..0]PC_INC[15..0]RESULT[15..0]C_INZ_INMEM_WRITER_JIMP_ADDR[15..0]DW_INTRUCTSR_DATA[15..0]DR_DATA[15..0]inst8 library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.exp_cpu_components.all;
entity exe_unit is port(
t1: in std_logic;
op_code: in
std_logic_vector(2 downto 0);
zj_instruct: in std_logic;
cj_instruct: in std_logic;
pc: in std_logic_vector(15
downto 0);
pc_inc: in
std_logic_vector(15 downto 0);
c_in: in std_logic; --以
前指令产生的进位C
z_in: in std_logic; --以
前指令产生的Z
Mem_Write: in std_logic;
--为1时,写存储器 c_tmp: out std_logic; z_tmp: out std_logic;
c_z_j_flag: out std_logic;
--为1时进行条件转移
r_sjmp_addr: in
std_logic_vector(15 downto 0); --相对转移地址 DW_intruct: in std_logic;
sjmp_addr: out
std_logic_vector(15 downto 0); --条件转移指令的转移地址
SR_data:
in
std_logic_vector(15 downto 0);
DR_data:
in
std_logic_vector(15 downto 0);
Mem_Addr:
out
std_logic_vector(15 downto 0);
result:
out
else
Mem_Addr <= SR_data;
std_logic_vector(15 downto 0) --运算结果); end exe_unit;
architecture behav of exe_unit is signal A,B :std_logic_vector(15 downto 0); signal
result_t: std_logic_vector(16 downto 0); begin
c_z_j_flag <= ( (not c_in) and cj_instruct) or ((not z_in) and zj_instruct); A <= DR_data; B <= SR_data;
sjmp_addr <= pc_inc + r_sjmp_addr; Mem_Addr_proc:
process(t1,SR_DATA,pc,DW_intruc) begin if t1 = '1' then
Mem_Addr <= pc;
else if DW_intruct = '1' then
Mem_Addr <= pc_inc;
elsif Mem_Write = '1' then
Mem_Addr <= DR_data;
end if;
end if;
end process;
alu_proc:process(op_code,A,B) begin case op_code is
when \"000\" =>
result_t <= ('0' & A) + ('0' & B);
when \"001\" =>
result_t <= ('0' & A) + '1'; when \"010\" =>
result_t <= ('0' & A) - ('0' & B);
when \"011\" =>
result_t <= ('0' & A) - '1';
when \"100\" =>
result_t <= ('0' & A) and ('0' & B);
when \"101\" =>
result_t <= ('0' & A) or ('0' & B);
when \"110\" =>
result_t <= not ('0' & A);
when \"111\" =>
result_t <= ('0' & B);
end case;
end process;
result <= result_t(15 downto 0); c_tmp <= result_t(16);
z_tmp <= (not result_t(15)) and
(not result_t(14)) and
(not result_t(13)) and (not
result_t(6)) and
(not result_t(5)) and (not
result_t(12)) and
(not result_t(11)) and (not
result_t(4)) and
(not result_t(3)) and (not
result_t(10)) and
(not result_t(9)) and (not
result_t(2)) and
(not result_t(1)) and (not
result_t(8)) and
(not result_t(7)) and (not
result_t(0)); end behav;
5、存储部分memory_unit 存储器部分主要完成下列任务:
(1)它是CPU和TEC-CA试验台上存储器的接口部分。向实验台上的存储器送出16位存储器地址总线Mem_addr、16位双向数据总线ob,读写信号rw。当rw为1时,实验台上的存储器作为读存储器信号处理;当rw信号为0时,实验台上的存储器信号处理。实验台上的存储器由2片静态存储器6116和少量附加电路构成。在TEC-CA实验台上,2片6116并联构成16位字长的存储器,6116所需的片选信号为cs为低信号,读信号oe由rw反相长生,写信号we直接选用rw。 (2)存储器地址Mem_addr来自执行部分,写信号Mem_Write由指令译码部分产生。当Mem_Write为1时在t3节拍完成写操作,其余情况下均进行读操作。 (3)在t1节拍完成读指令的第一个字。
(4)对于双字指令,t3节拍完成读指令的第二个字。
(5)对于JMP指令,在t3节拍读出转移地址,放在data_read。 (6)对于MVRD指令,在t3节拍读出立即数DATA,放在data_read。 (7)对于LDR指令,在t3节拍读出存储器的值,放在data_read中。 (8)对于STR指令,在t3节拍将源寄存器的值写入存储器。
(9)对于在t3下降沿写入目的寄存器的值进行选择。在LDR指令中,选中独处的存储器的值,其他的指令中,选中执行部分送来的运算结果result。
实验CPU中的存储器部分传统上属于控制器部分,实验台上的存储器属于计
算机的存储器部分。 memory_unit引脚关系如下:
MEMMORY_UNITRESETRWCLKOB[15..0]T3AR[15..0]MEM_ADDR[15..0]DATA_READ[15..0]MEM_WRITEDR_DATA_OUT[15..0]SEL_MEMDATASR_DATA[15..0]RESULT[15..0]inst9 存储部分memory_unit源代码: library IEEE;
use IEEE.std_logic_1164.all; use work.exp_cpu_components.all;
entity memory_unit is port( reset: in std_logic; clk,t3:
in std_logic;
Mem_addr: in
std_logic_vector(15 downto 0); Mem_Write: in std_logic;
sel_memdata: in std_logic; --为1时存储器的读出数据作为写入DR的数据
SR_data:
in
std_logic_vector(15 downto 0); --写存储器的数据
result:
in
std_logic_vector(15 downto 0); --运算结果
rw: out std_logic;
ob:
inout
std_logic_vector(15 downto 0);
ar:
out
std_logic_vector(15 downto 0);
data_read:
buffer
std_logic_vector(15 downto 0); --从存储器读出的指令或者数据
DR_data_out:
out
std_logic_vector(15 downto 0) --写入DR的数据); end memory_unit;
architecture behav of memory_unit is begin ar <= Mem_addr; R_W_Memory_proc:
process(reset,ob,SR_DATA,clk,t3,Mem_Write) --读写存储器处理 begin
if reset = '0' then
rw <= '1';
ob <= \"ZZZZZZZZZZZZZZZZ\"; --将存储器数据总线置为高阻,读存储器
else
if Mem_Write = '1' and t3 = '1' then ob <= SR_DATA; --写存储器
rw <= clk;
else ob <= \"ZZZZZZZZZZZZZZZZ\"; begin --将存储器数据总线置为高阻,读存储器
rw <= '1'; data_read <= ob;
if sel_memdata = '1' then DR_data_out <= data_read; --
存储器数据作为写DR的数据
else
DR_data_out <= result; --
end if;
end if; 运算结果作为写DR的数据
end if;
end process; sele_DR_proc:
process(sel_memdata,data_read,result)
6、程序包exp_cpu_components
end process; end behav;
程序包exp_cpu_components把实验CPU中除顶层设计实体exp_cpu意外的设计实体作为元件(componnent)予以说明,供实验CPU中的其他设计实体作为与案件予以引用。
程序包exp_cpu_components源代码: library ieee;
use ieee.std_logic_1164.all;
package exp_cpu_components is
component reg port (reset:
in std_logic;
end component;
component mux_4_to_1 port
input0, input1, input2, input3: in
(
std_logic_vector(15 downto 0);
sel:
in
d_input: in
std_logic_vector(15 downto 0);
clk:
in std_logic; in std_logic;
std_logic_vector(1 downto 0);
out_put: out
write: std_logic_vector(15 downto 0));
end component;
component decoder_2_to_4port
sel: in std_logic;
q_output: out
std_logic_vector(15 downto 0));
( sel: in end component;
std_logic_vector(1 downto 0); sel00: out std_logic; sel01: out std_logic; sel02: out std_logic; sel03: out std_logic ); end component;
component regfile Port
(DR: in
std_logic_vector(1 downto 0);
SR:
in
std_logic_vector(1 downto 0); reset: in std_logic;
write: in std_logic; clk: in std_logic;
d_input: in
std_logic_vector(15 downto 0); change_z: in std_logic;
change_c: in std_logic;
c_in: in std_logic; z_in: in std_logic;
R0,R1,R2,R3:
out
std_logic_vector(15 downto 0);
output_DR:
out
std_logic_vector(15 downto 0);
output_SR:
out
std_logic_vector(15 downto 0); c_out: out std_logic;
z_out: out std_logic );
component instru_fetch port (reset,clk: in std_logic;
data_read: in
std_logic_vector(15 downto 0); --存储器读出的数
lj_instruct: in std_logic;
--长转移指令
DW_intruct:
in std_logic;
--双字指令
c_z_j_flag: in std_logic;
--为1时进行条件转移
sjmp_addr: in
std_logic_vector(15 downto 0); --条件转移指令的转移地址 t1,t2,t3: buffer std_logic;
pc:
buffer
std_logic_vector(15 downto 0);
pc_inc:
buffer
std_logic_vector(15 downto 0);
IR:
out
std_logic_vector(15 downto 0)); end component;
component decoder_unit port
(IR:
in
std_logic_vector(15 downto 0);
SR:
out
std_logic_vector(1 downto 0);
DR:
out
std_logic_vector(1 downto 0);
op_code: out
c_in: in std_logic; --以
前指令产生的进位C
z_in: in std_logic; --以
std_logic_vector(2 downto 0); zj_instruct: out std_logic; cj_instruct: out std_logic; lj_instruct: out std_logic; 前指令产生的Z
Mem_Write: in std_logic;
--为1时,写存储器
DRWr: buffer std_logic; --
为1时写DR寄存器 Mem_Write: out std_logic; DW_intruct:buffer std_logic; change_z: out std_logic; change_c: out std_logic;
sel_memdata: out std_logic; --为1时存储器的读出数据作为写入DR的数据 r_sjmp_addr:out
std_logic_vector(15 downto 0) --相对转移地址); end component;
component exe_unit port (t1:
in std_logic;
op_code: in
std_logic_vector(2 downto 0); zj_instruct: in std_logic; cj_instruct: in std_logic;
pc:
in
std_logic_vector(15 downto 0);
pc_inc:
in
std_logic_vector(15 downto 0); c_tmp: out std_logic;
z_tmp:
out std_logic;
c_z_j_flag: out std_logic;
--为1时进行条件转移
r_sjmp_addr:
in
std_logic_vector(15 downto 0); --
相对转移地址
DW_intruct : in std_logic;
sjmp_addr:
out
std_logic_vector(15 downto 0); --条件转移指令的转移地址
SR_data: in
std_logic_vector(15 downto 0);
DR_data: in
std_logic_vector(15 downto 0);
Mem_Addr:
out
std_logic_vector(15 downto 0);
result: out
std_logic_vector(15 downto 0) --运算结果); end component;
component memory_unit port
(reset:
in std_logic;
clk,t3: in std_logic; Mem_addr: in
写存储器的数据
result:
in
std_logic_vector(15 downto 0);
Mem_Write:
in std_logic;
std_logic_vector(15 downto 0); --运算结果
rw: out std_logic; ob: inout
sel_memdata: in std_logic;
--为1时存储器的读出数据作为写入DR的数据
SR_data:
in
std_logic_vector(15 downto 0); --std_logic_vector(15 downto 0);
ar:out
DR_data_out:
out
std_logic_vector(15 downto 0) --写入DR的数据);
end component;
std_logic_vector(15 downto 0);
data_read:
buffer
std_logic_vector(15 downto 0); --从存储器读出的指令或者数据ts;
7、顶层设计实体exp_cpu
end exp_cpu_componen
顶层设计实体exp_cpu把5个2级实体regfile,instruct_fetch,decoder_unit,exe_unit和memory_unit作为元件引用,每次例化一次,用信号把它们连接起来,构成实验CPU。Exp_cpu同时也定义了实验CPU对外的接口。
Clk:外部输入的时钟
Reset:外部输入的CPU复位信号,低电平有效。 Ar:向外部输出的16位存储器地址总线。 Ob:16位外向存储器数据总线。
We:向外部输出的存储器读写信号。当为高电平时,对存储器进行读操作;当为低电平时,对存储器进行写操作。 顶层设计实体exp_cpu源代码: library ieee;
use ieee.std_logic_1164.all;
use work.exp_cpu_components.all; entity exp_cpu is port
(clk: in std_logic;
reset: in std_logic; zj_instruct,cj_instruct,lj_instr
uct: std_logic; signal
DRWr,Mem_Write,DW_intruct,change
out
_z: std_logic; reg_sel: in
std_logic_vector(5 downto 0); --选择寄存器
reg_content:
std_logic_vector(15 downto 0); --寄存器输出 c_flag: out std_logic; z_flag: out std_logic;
WE: out std_logic;
--//读写内存控制信号
AR: out std_logic_vector(15 downto 0); --//读写内存地址
OB:
inout
std_logic_vector(15 downto 0)
--//外部总线);
end exp_cpu;
architecture behav of exp_cpu is
--instru_fetch out
signal t1,t2,t3: std_logic; signal
pc,pc_inc,IR:
std_logic_vector(15 downto 0);
--decoder_unit out
signal SR,DR: std_logic_vector(1 downto 0); signal op_code:
std_logic_vector(2 downto 0);
signal
signal change_c,sel_memdata:
std_logic;
signal
r_sjmp_addr:
std_logic_vector(15 downto 0);
--exe_unit out
signal
c_tmp,z_tmp,c_z_j_flag:
std_logic;
signal Mem_Addr,result,sjmp_addr: std_logic_vector(15 downto 0);
--memory out
signal
data_read,DR_data_out:
std_logic_vector(15 downto 0);
--regfile out
signal
R0,R1,R2,R3:
std_logic_vector(15 downto 0); signal
output_DR,output_SR:
std_logic_vector(15 downto 0); signal c_out,z_out: std_logic; begin
c_flag <= c_out; z_flag <= z_out;
TEST_OUT: process(reg_sel) --被测信号以寄存器内容输出
begin case reg_sel is when \"000000\" =>
reg_content <= R0;
when \"000001\" =>
reg_content <= R1;
when \"000010\" => reg_content <= R2; when \"000011\" => reg_content <= R3; when \"000100\" =>
reg_content<= \"0000000\" &
t3 & \"000\" & t2 & \"000\" & t1; when \"111110\" => reg_content <= pc; when \"111111\" =>
reg_content <= IR;
when others =>
reg_content <= x\"0000\";
end case; end process;
G_INSTRU_FETCH: instru_fetch port map (reset => reset, clk => clk,
data_read => data_read, --存储器读出的数
lj_instruct => lj_instruct,
--来自decoder的长转移指令标志
DW_intruct => DW_intruct,
--来自decoder的双字指令标志
c_z_j_flag => c_z_j_flag,
--为1时进行条件转移,来自EXE
sjmp_addr => sjmp_addr, --
条件转移指令的转移地址,来自EXE t1 => t1, t2 => t2, t3 => t3, pc => pc, pc_inc => pc_inc,
IR => IR);
G_DECODER: decoder_unit port map (IR => IR, --来自instru_fetch SR => SR, --源寄存器号 DR => DR, --目的寄存器号
op_code => op_code, --ALU
运算的操作码
zj_instruct => zj_instruct,
--为1时是如果Z=0则转移指令
cj_instruct => cj_instruct,
--为1时是如果C=0则转移指令
lj_instruct => lj_instruct,
--为1时是无条件长转移指令
DRWr => DRWr, --为1时在
t3下降沿写DR寄存器,送往regfile
Mem_Write => Mem_Write,
--为1时对存储器进行写操作。
DW_intruct => DW_intruct,
--为1时是双字指令
change_z => change_z, --
为1时在t3下降沿根据指令执行结果置Z标志
change_c => change_c, --
为1时在t3下降沿根据指令执行结果置Z标志
sel_memdata => sel_memdata, --为1时存储器的读出数据作为写入DR的数据
r_sjmp_addr => r_sjmp_addr
--相对转移地址); G_EXE: exe_unit port map ( t1 => t1,
op_code => op_code, --ALU
运算的操作码,来自decoder
zj_instruct => zj_instruct,
--为1时是如果Z=1则转移指令,来自decoder
cj_instruct => cj_instruct,
--为1时是如果C=1则转移指令,来自decoder pc => pc, --来自instru_fetch
pc_inc => pc_inc, --来自
instru_fetch
c_in => c_out,--以前指令产
生的进位C,来自regfile
z_in => z_out, --以前指令
产生的Z,来自regfile
Mem_Write => Mem_Write, --
存储器写,来自decoder_unit
c_tmp => c_tmp, --本条指令
产生的Z标志送往regfile
z_tmp => z_tmp, --本条指令
产生的Z标志送往regfile
c_z_j_flag => c_z_j_flag,
--为1时进行条件转移,送往
instru_fetch
r_sjmp_addr => r_sjmp_addr,
--相对转移地址,来自decoder
DW_intruct => DW_intruct,
--双字指令标志,来自decoder,送往
sjmp_addr => sjmp_addr,--
条件转移指令的转移地址instru_fetch
SR_data
=>
output_SR,
--SR寄存器值,来自regfile
DR_data
=>
output_DR,
--SR寄存器值,来自regfile
Mem_Addr => Mem_Addr, --存
储器地址,送往memory
result => result --运算结
果,送往regfile);
G_MEMORY: memory_unit port map (reset => reset, clk => clk, t3 => t3,
Mem_addr => Mem_addr, --
存储器地址,来自exe_unit
Mem_Write => Mem_Write, --
存储器的数据,来自regfile
result => result, --运算结
存储器写,来自decoder_unit
果,来自exe_unit
sel_memdata => sel_memdata,
--为1时存储器的读出数据作为写入DR的数据,来自decoder
SR_data => output_SR,--写
rw => WE, --存储器读写信号,送往芯片外部
ob => ob, --存储器数据总线,和芯片外部存储器数据总线连接
ar => AR, --存储器地址,
送往芯片外部和存储器地址总线连接
data_read => data_read,
--从存储器读出的指令,送往instru_fetch
DR_data_out => DR_data_out
--写入DR的数据,送往regfile);
G_REGFILE: regfile port map (DR => DR, --DR寄存器号,
来自decoder
SR => SR, --SR寄存器号,
来自decoder reset => reset,
write => DRWr, --寄存器写
控制信号,来自decoder
clk => t3, --寄存器写入脉
冲,来自instru_fetch,下降沿写入
d_input => DR_data_out, --
写入寄存器的数据,来自memory
change_z => change_z, --为
1时在t4下降沿根据Z_tmp置Z标志,来自decoder
change_c => change_c, --为
1时在t4下降沿根据C_tmp置C标志,来自decoder
c_in => c_tmp, --本条指令
得到的c,来自decoder
z_in => z_tmp, --本条指令
得到的c,来自decoder R0 => R0, R1 => R1, R2 => R2, R3 => R3,
output_DR => output_DR,
--DR寄存器内容,送往exe和memory
output_SR => output_SR,
--SR寄存器内容,送往exe
c_out => c_out, --C标志,
送往exe和exp
z_out => z_out --Z标志,
送往exe和exp); end behav;
(五)设计方法
我们采用基于VHDL的自顶向下的设计方法首先定义构成系统的最底层的电路模块或元件的结构和功能,然后根据主系统的功能要求,将他们组合成更大的功能模块,使他们的结构和功能满足高层系统的需求,以此流程,逐步向上递推 ,直到完成整个系统。 (六)关键技术
我们采用现在很流行的EDA(电子设计自动化)技术,EDA技术就是以计算机为工具,设计者在EDA软件平台上,用硬件描述语言HDL完成设计文件(在这里我们采用VHDL),然后由计算机自动地完成逻辑编译、化简、分割、综合、优化、布局、布线和仿真,直至对于特定目标芯片的适配编译、逻辑映射和编程下载等工作。EDA技术的出现,极大地提高了电路设计的效率和可操作性,减轻了设计者的劳动强度。采用Quartus II 7.2集成开发环境开发我们设计的CPU。 (七)编写规则文件和测试程序 1、编写规则文件
因指令系统是自己定义的,需为汇编程序提供规则文件,以便将汇编源程序翻译成目标程序。规则文件编写的依据是指令的机器码,根据这令的机器码和规则文件语法要求编写完成。
编写规则文件的目的是让机器根据以定制好的规则文件将汇编程序装换成对应的二进制文件以取代人工汇编提高效率和正确性。
规则文件:汇编指令与机器指令的对照表。可用文本编辑器形成。(*.txt) 如:CPU.TXT
ADD DR,SR \"0000[u2][u2]00000111\INC DR \"0001[u2]0000000111\SUB DR,SR \"0010[u2][u2]00000111\DEC DR \"0011[u2]0000000111\AND DR,SR \"0100[u2][u2]00000011\OR DR,SR \"0101[u2][u2]00000011\NOT DR \"0110[u2]0000000011\
MOV DR,SR \"0111[u2][u2]00000001\JMP ADR \"1000000000000000[u16]\JNC ADR \"10010000[8]\JNZ ADR \"10100000[8]\
MVRD DR,DATA \"1100[u2]0000000001[u16]\LDR DR,SR \"1101[u2][u2]00000001\STR SR,DR \"1110[u2][u2]00000000\NOP . \"0111000000000000\" R0 = 0 R1 = 1 R2 = 2 R3 = 3 2、测试程序
测试文件编写的依据是指令系统根据指令系统中各条指令的功能编写测试程序以验证指令系统中各条指令的正确性。 测试程序用于检测FPGA-CPU设计的正确性。 main: MVRD
MVRD MVRD MVRD
R0,0x100 R1,0x200 R2,0X10 R3,0x3500
T1: STR R3,R0
INC R3 INC R0 DEC R2 JNZ T1
R0,0x100
T2: MVRD
MVRD R2,0x10
T3: LDR R3,R0
STR R3,R1
INC R0 INC R1 DEC R2 JNZ T3
T4: NOP
NOP
五、 实验方案实施
(一)调试环境及使用 1、调试环境 (1)总体描述
FPGA-CPU设计平台能够支持下载到FPGA中的CPU的单步调试和连续运行。用户用VHDL编写的CPU代码通过编译之后,可以下载到设计平台上的FPGA芯片中。FPGA-CPU的运行通过执行预先写到外部存储器中的程序来实现。使用DebugController程序对外部存储器进行读写操作,并能监控FPGA-CPU的状态和通过设置断点调试FPGA-CPU正在执行的程序。这套实验环境为实验者提供了最大的自由度来写出具有自己风格的CPU软核,并在测试运行平台上调试和运行。 (2)硬件环境
整个硬件平台主要有PC监控系统、外部程序存储器、FPGA-CPU及其下载相关电路,以及控制电路组成。其中PC监控系统主要是由监控软件DebugController及相关通信接口等构成,提供一整套的运行和调试功能。见图1:
FPGA-CPU测试平台总体结构串口通信控制电路CPU监控PC监控系统存储器读写FPGA-CPU外部程序存储器存储器读写 FPGA-CPU
设计平台总体结构图
(3)软件环境
a) 监控程序DebugController
使用该软件对外部存储器进行读写操作,并能监控FPGA-CPU的状态和通过设置断点调试FPGA-CPU正在执行的程序。
b) Active-HDL4.2
我们用该软件做功能仿真。该软件编译时间短,并可以查看中间信号,因此模拟、调试十分方便。这对于检测并纠正逻辑错误是很有利的。美中不足的是,它无法进行有效的时序模拟。
c) Quartus-4.1
我们使用该软件完成编码工作,并在active-hdl功能模拟通过后,进行有效的时序模拟。最终烧片等都用该软件。 2、调试环境的使用
模式选择开关CLKSEL、REGSEL和FDSEL的设置
(1)CLKSEL是时钟选择开关,用于选择FPGA-CPU的时钟。FPGA-CPU的时钟有
3个来源,一个是由单片机产生的;一个是按单脉冲按钮(在实验平台左下角)产生的正脉冲,每按一次单脉冲按钮,产生一个正脉冲;一个是由l6MHz晶振和分频器16l(U2)组成的时钟电路产生的。CLKSEL开关拨到l(向上)时,选择按单脉冲按钮产生的单脉冲或者时钟电路产生的时钟;CLKSEL开关拨到0(向下)时,选择单片机产生的时钟。在此我们设置CLKSEL到0上让单片机提供时钟信号。
(2)寄存器选择开关REGSEL位于实验平台左下角,用于选择寄存器。FPGA-CPU
中最多允许64个16位寄存器。当需要检测这些寄存器的内容时,有两种途径:一种途径是由单片机设置寄存器地址,然后将检测到的指定的寄存器内容发送到运行在PC机上的软件Debugcontroller,由Debugcontroller显示在PC机的屏幕上;另一种途径是通过实验平台上的开关SA5--SA0设置寄存器地址,在实验平台上部的R0一R15指示灯上显示指定的寄存器的内容。当开关REGSEL=l(开关向上)时,由单片机指定寄存器,寄存器的内容在PC机屏幕上显示指定的寄存器内容;当开关REGSEL=O(开关向下)时,由实验平台上的开关SA5—SA0指定寄存器地址,在实验平台上的指示灯R15--R0显示指定寄存器的内容。
(3)FPCA-CPU DATA选择开关FDSEL位于实验平台左下角,主要用于对FPGA-CPU的总线FD0—FD15置数。当开关FDSEL=O(向下)时,可以使用数据开关SD0—SD15给FPGA-CPU的总线FD0—FD15置数。其中SD0对应FD0,SD1对应FD1,„,SD15对应FD15。这种功能主要用于FPGA-CPU单独工作的时候。当开关FDSEL=l(向上)时,不能使用数据开关SD0—SD15给FPGA-CPU的总线FD0—FD15置数。 (二)实验调试步骤
1、创建新的Quartus II工程(在创建新工程前,需要创建一个工作目录) 打开File—New Project Wizard菜单,创建工程,并指定芯片为EP1C6Q240C8. 2、
采用VHDL file作为输入。
3、编译系统。
打开Processing-Start Compilation进行编译。
4、引脚锁定
打开Assignments-Pins进行相应的引脚锁定。锁定时参考“实验用到的资
源和原理”部分,把输入锁定到逻辑开关,输出锁定到LED发光二极管指示灯。 5、编译系统 6、下载验证
打开Tools-Programmer,Mode选则JTAG,Hareware Setup选择ByteBlaster II,编程文件选择*.sof的文件,即可开始下载。
下载完成后,拨动相应的两个开关,观察LED显示,验证系统工作的正确性。
7、编写规则文件
规则文件是用户自己指定的汇编指令格式文件。由于在TEC-CA系统中指令集是用户自己定义的,因此需要用户自己编写规则文件。规则文件以行为单位。汇编器在初始化的时候会逐行解释规则文件,生成指令表和部分符号表。如果用户进行计算机组成部件设计,由于没有测试程序,因此不需要规则文件,这一步骤可以跳过。规则文件在文本编辑器下生成即可。 8.编写测试程序
如果做CPU设计实验,由于FPGA-CPU和实验平台上的存储器构成16位实验计算机,编写测试程序是必须的。测试程序用于检验FPGA-CPU设计的工确性。必须按照规则文件指定的格式编写测试文件。如果用户进行计算机组成部件设计,由于没有测试程序,这一步骤可以跳过。 以上8个步骤是正式实验之前的准备工作。 9.将PC机和TEC-CA连接
将PC机和TEC-CA连接是做两件事情。一是将下载电缆的一头插到PC机的并行口上,将下载电缆的另一头插到TEC-CA子板上的下载插座(JTAG)上。二是将RS-232通信电缆的一头插在PC机的串行口上,将RS-232通信电缆的另一头插到TEC-CA实验箱背面的9针插座上;或者在使用USB口的情况下,将USB通信电缆一端接PC机的USB口,另一端接实验台上的B型USB口。当SW22=1时,使用USB通信电缆;当SW22=0时,使用RS232通信电缆。 10.打开TEC-CA实验系统的电源
打开电源后检查实验平台上的+5V指示灯是否点亮。如果指示灯点亮,表示电源系统正常。 11.选择实验的调试模式
按选定的调试模式设置好3个模式选择开关,将短路子DZ1—DZ8按本实验要求的正确方式短接或者断开。
12.按单片机复位按钮,使单片机处干初始状态 13.将FPCA-CPU设计下载到TEC-CA子板上的FPGA中
在PC机上启动EDA软件Quartus II,将sof文件形式的FPGA-CPU设计下载到TEC-CA子板上的FPGA芯片中,构成一个物理上的FPGA-CPU。 14.将测试程序装到存储器中
在PC机上启动Debugcontroller软件,将测试程序装到实验平台上的存储器中。在FPGA-CPU独立调试模式中,没有存储器,也没有测试程序,这一步骤可以跳过。
14.根据选择的调试模式调试程序 (三)、调试过程
按照实验步骤操作完毕以后选择调试模式开始调试,在这里可以选择单周期调试或者半周期调试,如果选择的是单周期调试则再选的调试模式后F8执行下一个周期根据测试程序对应指令的对应周期下应有的现象和观察到的现象比较验证cpu的正确性。在观察现象时刻根据实验说明里提到的根据需要选择观察方式。在观察现象是主要关注一下几个方面:
数据总线上数据的变化 地址总线上数据的变化 寄存器组中各个值的变化 Pc和IR寄存器的值的变化 六、实验总结 (一).评价与改进 1、评价
当第一次说要设计CPU的时候,说实话,心里比较发慌的,感觉自己的知识还不够。但是,当我真正的去做了这个CPU设计实验,通过多方面的学习和老师的指导,虽然借鉴了别人的很多设计思想和好的设计方法,最后还是圆满的完成了任务和实验。而在设计实现时我们采用现在很流行的EDA技术,采用vhdl语言设计硬件电路,在FPGA实验平台上验证CPU的正确性。
从指令系统的设计说起,我们设计的CPU是基于RISC结构的,全部指令是单周期指令。CPU操作数存取我们选用通用寄存器型,简化了指令的译码分析电路的复杂度,而整个指令系统只有只有仅仅15条指令但在功能基本上能完成全部基本的操作。并且该指令系统有冗余便于以后指令系统的扩展。在时序逻辑上我们把整个指令的执行周期分为三个阶段即取值、译码和分析。而指令的格式我们采用的是:指令格式=操作码+地址码。并且指令编码采用的是等长编码,方便译码分析。 2、改进
虽然我们设计的CPU已基本实现了全部的基本指令功能,但我们为采用指令流水所以该CPU的执行效率很低,我们下一步的改进将主要针对指令的流水执行。设计实现3级流水线,除此之外我们也没有设计Cache,在下一步的工作中我们将加入Cache模块减小指令的访存次数提高系统的效率。在完成以上计划后我们计划采用超标量带Cache的CPU进一步提高指令的执行效率。 (二).收获与体会
本次实验用到计算机组成原理。系统结构、汇编语言、数字逻辑和电子设计自动化等课程的知识,加深了我对他们的理解和知识的综合应用,提高了自己的动手能力和知识综合应用能力。同时也深深的体会到了现在电子技术的强大以及自己知识的欠缺。通过本次实验,使我对课本上的知识有了更深入的理解,让我把课本上的知识转化真正的动手能力。
在仅仅几平方厘米的面积上就集成上百万个电子元器件。通过自己设计CPU我加深了对指令执行过程的理解,通过自己理解代码,知道了每个引脚代表的东西,以前对于每一个阶段CPU具体做了哪些细微的处理,哪些地方发生了改变我一无所知。而在本次试验的调试过程中我看到了执行一条指令时每个阶段具体做了哪些工作,发生了什么变化以及指令之间到底是怎么有条不紊的顺序执行的。
在指令系统的设计过程中我也实实在在的体会到了指令系统的设计对于CPU的设计是多么的重要他不仅影响着你的CPU的上层应用的功能的强弱,而且决定着你的CPU的物理实现的硬件复杂度。我现在的理解是你设计的功能越强大对应的硬件电路就会越复杂调试难度也会相应增加,而你设计的指令系统如果不合理那么相应的硬件电路会变得异常的复杂以至于不可能完成最初的设计要求。
通过本次实验,让我真正的认识到了系统结构这门课程的闪光点,让我对CPU的设计和电子设计自动化等 方面的知识产生了浓厚的兴趣。本次实验,让我了解到了自己在动手能力和知识的掌握方面还存在许多的不足,这就要求了我在以后的学习过程中要严格的要求自己。不断地提高自己,让自己在学习中掌握更扎实的知识,提高自己的能力。
七、参考文献
《数字电路与数字逻辑》; 《汇编语言程序设计》 《计算机组成原理》; 《计算机系统结构》; 《电子设计自动化EDA技术》
因篇幅问题不能全部显示,请点此查看更多更全内容