实验一 运算器设计实验
- 目的与要求
1.目的
(1)熟悉硬件描述语言及开发环境,了解硬件系统开发的基本过程
(2)掌握ALU基本设计方法和简单运算器的数据传输通路
(3)验证ALU的功能
2.要求
(1)运用所学的知识和方法采用最佳方案完成实验设计。
(2)编写简洁代码完成实验要求内容。
(3)认真书写实验报告,包括实验目的、实验内容、实验设计方案、实验仿真结果等。
二、实验正文
1.实验内容
(1)用VHDL语言实现一个简易的16位ALU。
(2)通过设计一个状态机,根据状态机状态的变化输入操作数和操作码,来实现不同运算。
(3)实验中ALU要求实现基本的算术运算、逻辑运算、移位运算等,具体功能如下表所示。合理设置每条指令的标志位,包括进位标志、溢出标志、最高位和全零标志。
ALU功能表:
操作码 | 功能 | 描述 |
ADD | A + B | 加法 |
SUB | A – B | 减法 |
AND | A and B | 与 |
OR | A or B | 或 |
XOR | A xor B | 异或 |
NOT | not A | 取非 |
SLL | A sll B | 逻辑左移B位 |
SLR | A srl B | 逻辑右移B位 |
SAL | A sal B | 算数左移B位 |
SAR | A sar B | 算数右移B位 |
ROL | A rol B | 循环左移B位 |
ROR | A ror B | 循环右移B位 |
要求:ALU 的数据输入 A、B 的长度为 16 位,操作码 op 为 4 位,算术运算时数据用补码表示。
(4)将实验过程中进行的操作与结果数据记录在下表中。
输入数据 | 实际输出 | 与预期一致性 | |||
操作码 | 操作数A | 操作数B | 运算结果 | 标志位 | |
0000 | 00000001 | 00000010 | 00000011 | 0000 | 一致 |
(5)在教学计算机上验证实现的ALU功能。
2.实验步骤
(1)先设置输入输出,设置clk和rst信号,设置In_temp为16位拨码输入,Out_Y为16位LED输出,Flags为标志位,stateCnt为7段数目管显示当前状态。
(2)定义signal,其中3位信号State记录当前状态。
(3)在程序主体设置状态转换,State为000时读取拨码输入的A操作数,为001时读取拨码输入的B操作数,为010时读取拨码输入的低4位操作数,为011时进行运算。在011状态下用when选择4位操作码定义的操作,并分别用读取的操作数进行运算。
(4)添加管脚约束。
(5)运行代码无误后烧录进板子进行验证。
3.代码部分
entity alu is
Port ( clk : in STD_LOGIC;--时钟
rst : in STD_LOGIC;--复位
In_temp : in STD_LOGIC_VECTOR (15 downto 0); --操作数
Out_Y : out STD_LOGIC_VECTOR (15 downto 0);--输出
Flags :out STD_LOGIC_VECTOR(3 DOWNTO 0);--标志位为 OF 溢出标志位/CF carry flag/ZF 零标志位/SF 正负标志位 0 正 1 负
stateCnt :out STD_LOGIC_VECTOR(6 DOWNTO 0));
end alu;
architecture Behavioral of alu is
signal State : STD_LOGIC_VECTOR (2 downto 0):= "000";--记录当前的状态,来判断该进行什么操作
signal int_A, int_B,int_Y : INTEGER RANGE -32768 TO 32767:=0;
signal temp_A, temp_B, temp_y: STD_LOGIC_VECTOR (15 downto 0);--定义临时操作数
signal OP : STD_LOGIC_VECTOR(3 downto 0);--操作码
signal Flag_OF : STD_LOGIC:= '0';--溢出标志
signal Flag_CF : STD_LOGIC:= '0';--进位标志
signal Flag_ZF : STD_LOGIC:= '0';--0 标志位
signal Flag_SF : STD_LOGIC:= '0';--正负标志
signal M: STD_LOGIC:='0';--扩展:对于带符号运算 ADC/SBB
begin
process(rst,clk)
VARIABLE int_T: INTEGER RANGE -32768 TO 32767:=0;
VARIABLE TEMP_Y : STD_LOGIC_VECTOR(15 DOWNTO 0);
begin
IF (rising_edge(clk)) then
if (State = "000") then --状态 1,读取 A 数字转换;
temp_A <= In_temp;
stateCnt <= not "1000000" ;
Flag_OF <='0';
Flag_CF <='0';
Flag_ZF <='0';
Flag_SF <='0';
int_A <= CONV_INTEGER(In_temp); --将 A 输入转化为整形
State <= "001";
elsif (State = "001") then --状态 2,读取 B 数字转换;
temp_B <= In_temp;
stateCnt <= not "1111001" ;
int_B <= CONV_INTEGER(In_temp); --将 B 输入转化为整形
State <= "010";
elsif (State = "010") then --状态 3,读 OP
OP <= In_temp(3 downto 0);
stateCnt <= not "0100100" ;
State <= "011";
elsif (State = "011") then--状态 4,进行运算;
stateCnt <= not "0110000" ;
CASE OP IS
WHEN "0000" => --ADD 加
M <= '1';
int_T := int_A + int_B;
int_Y <= int_T;
TEMP_Y := TEMP_A + TEMP_B;
Out_Y <= CONV_STD_LOGIC_VECTOR(int_T,16);
if(temp_A(15) = '0' and temp_B(15) = '0' and temp_Y(15) = '1') then--进行溢出和是否进位判断
Flag_OF <= '1';
end if;
if(temp_A(15)='1' and temp_B(15)='1' and temp_Y(15)='0') then --进行溢出和是否进位判断
Flag_OF <= '1';
Flag_CF <='1';
end if;
if(CONV_STD_LOGIC_VECTOR(int_T,16) = "0000000000000000") then --0 标志位与 0 进行比较
Flag_ZF <= '1';
end if;
if(INT_T < 0) then --通过符号位来判断正负标志位
Flag_SF <= '1';
end if;
State <= "100";
WHEN "0001" => --SUB 减
int_T := int_A - int_B;
if(int_T = 0) then
Flag_ZF <= '1';
end if;
if(int_T < 0) then
Flag_SF <= '1';
end if;
Out_Y <= CONV_STD_LOGIC_VECTOR(int_T,16);
State <= "100";
WHEN "0010" => --AND 逻辑与
Out_Y <= (temp_A AND temp_B);
temp_Y := (temp_A AND temp_B);
if(CONV_INTEGER(temp_Y) = 0) then
Flag_ZF <= '1';
end if;
if(CONV_INTEGER(temp_Y) < 0) then
Flag_SF <= '1';
end if;
State <= "100";
WHEN "0011" => --OR 逻辑或
Out_Y <= temp_A OR temp_B;
State <= "100";
WHEN "0100" => --XOR 逻辑异或
Out_Y <= temp_A XOR temp_B;
State <= "100";
WHEN "0101" => --NOT 逻辑非
Out_Y <= NOT temp_A;
State <= "100";
WHEN "0110" => --SLL 逻辑左移
if(temp_B(3 downto 0) /= "0000") then
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SLL CONV_INTEGER(temp_B(3 downto 0)));
else
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SLL 1);
end if;
State <= "100";
WHEN "0111" => --SLA 算术左移
if(temp_B(3 downto 0) /= "0000") then
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SLA CONV_INTEGER(temp_B(3 downto 0)));
else
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SLA 1);
end if;
State <= "100";
WHEN "1000" => --SRL 逻辑右移
if(temp_B(3 downto 0) /= "0000") then
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SRL CONV_INTEGER(temp_B));
else
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SRL 1);
end if;
State <= "100";
WHEN "1001" => --SRA 算术右移
if(temp_B(3 downto 0) /= "0000") then
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SRA CONV_INTEGER(temp_B(3 downto 0)));
else
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) SRA 1);
end if;
State <= "100";
WHEN "1010" => --ROL 循环逻辑左移
if(temp_B(3 downto 0) = "0000") then
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) ROL CONV_INTEGER(temp_B(3 downto 0)));
else
Out_Y <= TO_STDLOGICVECTOR(To_bitvector(temp_A) ROL 1);
end if;
State <= "100";
WHEN OTHERS =>
Out_Y <= "1111111111111111"; --默认报错用-1
State <= "100";
end case;
elsif (State = "100") then--状态 5,输出 FLAGS;
stateCnt <= not "0011001" ;
Flags(3) <= Flag_OF;
Flags(2) <= Flag_CF;
Flags(1) <= Flag_ZF;
Flags(0) <= Flag_SF;
State <= "000";
end if;
end if;
if (rst='0') then
State <= "000";
Flags(3) <= '0';
Flags(2) <= '0';
Flags(1) <= '0';
Flags(0) <= '0';
Out_Y <= "0000000000000000";
END if;
end process;
end Behavioral;
4.思考题
(1)ALU 进行算术逻辑运算所使用的电路是组合逻辑电路还是时序逻辑电路?
解:组合逻辑电路。
(2)如果给定了 A 和 B 的初值,且每次运算完后结果都写入到 B 中,再进行下次运算。这样一个带暂存功能的 ALU 要增加一些什么电路来实现?
解:增加暂存器 TMP 和累加器 AC。
三、综合实验总结
- 实验难点
- 第一次实验时对硬件操作不熟练,不知道如何定义管脚,经学长演示后明白了管脚操作。
- 程序烧进板子后,数据输入总是出问题,经排查后发现数据输入比状态转换慢了一个节拍,改变输入时间后可以正常操作。
- 心得体会
在本次实验中,我学到了很多知识,通过程序的编写,对计算机组成也有了更深刻的认识。实验小组内合作完成,讨论中交流了自己的想法,并把程序不断改进。
实验二 存储器实验
- 目的与要求
1.完成 SRAM 写,给定地址,写入相应数据。
2.完成 SRAM 读,给定地址,读出对应数据。
3.LED 和数码管正确显示数据及状态的变化。
4.掌握内存(RAM)的访问时序和方法。
5.理解总线数据传输的基本原理。
二、实验正文
1.实验内容
使用教学计算机上的FPGA芯片,设计一个状态机和内存读写逻辑,完成对存储器RAM的访问。
2.实验步骤
(1)先定义输入输出,定义时钟,置0和状态控制信号ctrl_r,定义16位拨码输入,16位地址输出和16位数据输出,绑定地址线和数据线。定义左右两个数码管显示状态变化。16位led灯输出地址低8位和数据低8位。
(2)定义signal,定义状态机,控制运行状态,地址输入状态,写入状态和读取状态。
(3)3个运行状态分别进行写地址,写数据,读地址和数据的操作,每个操作中又分为小状态。
(4)添加管脚约束。
(5)运行代码无误后烧录进板子进行验证。
3.代码部分
entity SRAM is
Port ( CLK : in STD_LOGIC; --时钟
RST : in STD_LOGIC; --置0
ctrl_r : in STD_LOGIC;
input : in STD_LOGIC_VECTOR (15 downto 0); --输入
--light
LIGHT: out STD_LOGIC_VECTOR (15 downto 0); --LED灯
SEG:out std_logic_vector(6 DOWNTO 0):=not "1111001"; --数码管
SEG_LGHET:out std_logic_vector(6 DOWNTO 0):=not "1111001"; --数码管
DBC : inout STD_LOGIC; --interconn3
--RAM
ADDR : out STD_LOGIC_VECTOR (15 downto 0); --地址线
DATA : inout STD_LOGIC_VECTOR (15 downto 0); --数据线
OE : out STD_LOGIC; --输出使能端
WE : out STD_LOGIC; --允许写入
EN : out STD_LOGIC); --片选信号
end SRAM;
architecture Behavioral of SRAM is
--signal State : STD_LOGIC_VECTOR(1 downto 0);
signal tmp_write_addr:std_logic_vector(15 downto 0); --写入地址
signal tmp_write_data:std_logic_vector(15 downto 0):=x"0000"; --写入数据
signal tmp_read_addr:std_logic_vector(15 downto 0); --读地址
signal tmp_read_data:std_logic_vector(15 downto 0):=x"0000"; --读数据
signal tmp_light:std_logic_vector(15 downto 0):=x"0000"; --LED灯
type prj_state is (N,W,R); --运行状态
signal ctrl_state:prj_state;
type adram_state is (waiting); --地址输入状态
signal address_state:adram_state;
type sram_state is (waiting,start,over); --写入状态
signal write_state:sram_state;
type rram_state is (waiting,start,read,over);--读取状态
signal read_state:rram_state;
begin
process(tmp_light,tmp_read_addr)
begin
light(7 downto 0) <= tmp_light(7 DOWNTO 0);
light(15 downto 8) <= tmp_read_addr(7 DOWNTO 0); --地址低8位和数据低8位
end process;
process(RST,ctrl_r)
begin
if RST='0' then
ctrl_state<=N;
SEG_LGHET <= not"1000000";
elsif rising_edge(ctrl_r) then
case ctrl_state is
when N=>
SEG_LGHET <= "0000110"; --1,数码管显示数字
ctrl_state<=W;
when W=>
SEG_LGHET <= "1011011";--2
ctrl_state<=R;
when R=>
SEG_LGHET <= not"1000000";
ctrl_state<=N;
end case;
end if;
end process;
process(RST,CLK,ctrl_state)
begin
if RST='0' then --置0
SEG <= "1000000";
tmp_write_data<=x"0000";
tmp_read_addr<=x"0000";
tmp_write_addr<=x"0000";
tmp_light<=x"0000";
OE<='0';
WE<='0';
address_state<=waiting;
write_state<=waiting;
read_state<=waiting;
elsif rising_edge(CLK) then
case ctrl_state is --运行状态
when N=>
ADDR <= input; --写入地址单元的地址
SEG <= not"1000000"; --0
tmp_write_addr <= input;
tmp_read_addr <= input;
when W=>
case write_state is
when waiting =>
address_state <= waiting;
write_state <= start;
read_state <= waiting;
SEG <= "0000110"; --1
when start =>
tmp_write_data<=input;
ADDR <= tmp_write_addr;
DATA <= input;
EN <= '0';
OE <= '1';
WE <= '0';
SEG <= "1011011"; --2
write_state <= over;
when over =>
write_state <= waiting;
tmp_write_addr <= tmp_write_addr + 1;
SEG <= "1001111"; --3
end case;
when R=>
case read_state is
when waiting =>
address_state <= waiting;
read_state <= start;
write_state <= waiting;
SEG <= "1100110"; --4
when start=>
ADDR <= tmp_read_addr;
DATA<=(others=>'Z');
read_state<=read;
SEG <= "1101101"; --5
EN <= '0';
OE <= '1';
WE <= '1';
when read =>
EN <= '0';
OE<='0';
We<='1';
tmp_light <= DATA;
SEG <="1111101"; --6
read_state<=over;
when over=>
SEG <= "0000111"; --7
read_state<=waiting;
tmp_read_addr<=tmp_read_addr + 1;
end case;
end case;
end if;
DBC <= '1';
end process;
end Behavioral;
4.思考题
静态存储器的读、写时序各有什么特点?
解:速度快,存储密度低,单位面积存储容量小,数据入/出共用管脚,能耗高,成本高。
三、综合实验总结
- 实验难点
- 一开始不明白为什么地址和数据能联系在一起,通过查阅资料,了解了地址线和数据线的绑定原理。
- 刚开始用数组存储,发现不能实现自由存储。明白内存的使用方法后,直接将数据存入内存相应地址中。
- 心得体会
通过本次实验,我对计算机内存有了更深刻的认识,明白了内存的存取原理和使用方法。掌握了如何存取数据和读出数据。
实验三 控制器实验
一、目的与要求
1.实验目的
(1)进一步理解和掌握计算机指令系统,包括指令功能,指令格式等。
(2)了解控制器的基本组成和控制方法
2.实验要求
- 编写VHDL程序,实现具有七条MIPS指令功能的控制器。
- 七条指令分别为:ADDU SUBU BNEZ JR OR LW SW。
- 7条指令格式及功能详见实验指导书。
二、实验正文
1.实验内容
编写一个简单的多周期控制器,并观察它的运行过程。
2.实验步骤
- 先定义输入输出,定义时钟,置0,刷新信号。定义16位拨码输入,16位LED输出控制信号。左右两侧数码管输出当前状态。
- 定义signal,其中定义状态机,来控制操作状态和输出状态。
3.代码部分
代码同实验四控制器部分
三、综合实验总结
- 实验难点
(1)定义状态机时不熟练,led灯不亮,经修改代码后成功运行。
- 心得体会
通过控制器实验,我对计算机控制器部分有了更深刻的认识,能够编写并使用控制器,知识也理解得更透彻。
实验四 16位CPU设计实验
一、目的与要求
1.实验目的
实现一个基于MIPS指令集的CPU,数据总线16位,地址总线16位,具有8个16位的通用寄存器。指令包括访存指令(如LW,SW),传送指令(如LI,MOVE),算术运算指令(如ADDU,SUBU),逻辑运算指令(NOT,OR),移位运算指令(如SLL),具体指令见实验指导书P23-P32。
2.实验要求
- 完成7条指令,必须包括访存指令LW和SW,其余每类指令最多2条。
- 按照取指、译码、执行、访存和写回五个工作周期,分析每条指令的指令流程。
- 根据指令流程,设计每条指令的CPU数据通路,定义涉及的所有微操作控制信号。然后逐一合并数据通路,说明增加或减少处理器功能部件的理由。给出控制器的完整设计过程。
- 编写VHDL程序实现CPU,并通过实验板验证。
二、实验正文
1.实验内容
实现一个7条指令多周期CPU,数据总线16位,地址总线18位,具有8个16位的通用寄存器。
2.实验步骤
(1)定义输入输出,时钟信号,置0信号和刷新信号。定义16位拨码输入,16位LED输出,绑定地址线和数据线。定义状态切换信号showctrl,和左右两个数码管显示当前状态。
(2)定义signal,其中定义8个16位寄存器,寄存器地址000~111。定义不同部分的控制信号。定义PC,IR。定义状态机,控制操作状态,输出状态,和转移状态。
(3)在主程序中,先定义输出状态,前4个状态同实验三输出不同部分的控制信号。5~7状态输出x,y,z寄存器的值,令高三位显示寄存器地址,便于确认。8,9状态分别输出PC和IR寄存器中的值。
(4)控制操作状态机中,在指令读取状态(1)读取指令值存入IR中,在写x寄存器地址状态(2)写入x寄存器地址,在写x寄存器数据(3)中写x寄存器数据。在写y寄存器地址状态(4)写y寄存器地址,在写y寄存器数据状态(5)写y寄存器数据。这4个写寄存器地址数据的状态可控制寄存器数据的手动存入。在译码状态(6)中译码,指令的高5位位操作码,根据不同的操作码进行不同的操作。在执行状态(7)中执行不同操作。在是否进入访存状态(8)和写回状态(9)由执行状态确定。
(5)其中在进行转移指令时,需要定义一个转移状态机来实现数据更新。
(6)简易CPU实现了访存指令(LW和SW),传送指令(BEQZ和JR),算数运算指令(ADD和SUB),逻辑运算指令(XOR),移位指令(SLLV),共8条。使用了8个16位寄存器R0~R7,地址位000~111.
3.代码部分
entity CPU is
Port ( rst : in STD_LOGIC; --复位信号
clk : in STD_LOGIC; --时钟信号
clk0 : in STD_LOGIC; --11.0592时钟信号
SW_IN : in STD_LOGIC_VECTOR (15 downto 0); --输入
light : out STD_LOGIC_VECTOR (15 downto 0); --LED输出
SHOW_STATE_RIGHT : out STD_LOGIC_VECTOR (6 downto 0):="1110110"; --输出当前状态 重置、取值、译码、执行、访存、写回 启动时显示H
SHow_STATE_LEFT : out STD_LOGIC_VECTOR (6 downto 0):="1110110"; --输出显示状态,同上
ADDR : inout STD_LOGIC_VECTOR (15 downto 0); --RAM地址
DATA : inout STD_LOGIC_VECTOR (15 downto 0); --RAM数据
RAM1_EN : out STD_LOGIC; --RAM使能
RAM1_OE : out STD_LOGIC; --RAM读使能
RAM1_WE : out STD_LOGIC; --RAM写使能
DBC : inout STD_LOGIC; --interconn3 SRAM 读锁存
showctrl : in STD_LOGIC; --切换输出
bzero_ctrl : in STD_LOGIC); -- 控 制PcWriteCond 用于判断是否满足转移条件
end CPU;
architecture Behavioral of CPU is
--寄存器
TYPE ARRAY_REG IS ARRAY(0 TO 7) OF STD_LOGIC_VECTOR(15 DOWNTO 0); --定义的寄存器
SIGNAL REGS:ARRAY_REG;
signal rex:std_logic_vector(2 downto 0) := "000"; --寄存器 x 地址,通过地址找到对应寄存器
signal rey:std_logic_vector(2 downto 0) := "000"; --寄存器 y 地址
signal rez:std_logic_vector(2 downto 0) := "000"; --寄存器 z 地址
signal memtoreg:std_logic_vector(1 downto 0); --写入寄存器堆的数据来源选择 (00-ALUout 01-主存中)
signal regwrite:std_logic_vector(2 downto 0); --写寄存器控制 (000-无 001-将数据写入指定通用寄存器 010-写 SP 011-写 T)
signal regdst:std_logic_vector(1 downto 0); --选择目的寄存器 (rx rz ry)
signal iord:std_logic; --寄存器地址来源(0-指令 1-ALUout)
signal taddr:std_logic_vector(15 downto 0);
--SP 堆栈指针
signal SP:std_logic_vector(15 downto 0) := x"0000";
type shower_state is (pc,alu,mem,reg,regx,regy,regz,pc_show,ir_show); -- 显示状态 pc - alu - 储存 - 寄存器 -regxx -regy -regy
signal shower:shower_state;
type controler_state is (instruction_fetch,wxaddr,wxdata,wyaddr,wydata,decode,execute,mem_control,write_reg); --控制周期(取指、写x地址、写x数据、写y地址、写y数据、译码、执行、访存、写回)
signal state:controler_state;
type BEQZstate is(updateaddr,updatedata);
signal beqz_state:BEQZstate;
--PC
signal pc_mem:std_logic_vector(15 downto 0) := x"0000"; --指令地址寄存器
signal pcwrite:std_logic; --写入 PC(1-写入 PC)
signal pcwritecond:std_logic; --转移指令的条件 (改写 PC)
signal pcsource:std_logic; -- 新 的 PC 来 源 选 择 (0-ALUout 1- 存 有ALUout 的寄存器)
--ALU
signal aluop:std_logic_vector(1 downto 0); --ALU 操作码 OP(00-加 01-减 10-指令功能字段决定)
signal alusrca:std_logic; --ALU 源操作数 A 的选择(1 寄存器 A 0 PC)
signal alusrcb:std_logic_vector(1 downto 0); --ALU 源操作数 B 的选择(00 寄存器 B 01 常数 1 10-IR)
--RAM
signal memread:std_logic; --RAM 读
signal memwrite:std_logic; --RAM 写
--signal tmp_write_addr:std_logic_vector(15 downto 0); --临时读
--signal tmp_read_addr:std_logic_vector(15 downto 0); --临时写
--signal tmp_data:std_logic_vector(15 downto 0); --数据
--IR
signal instructions:std_logic_vector(15 downto 0); --指令寄存器 IR
signal IR:std_logic_vector(15 downto 0) := x"0000";
signal irwrite:std_logic; --写入 IR
signal bzero:std_logic;
signal tmpb_zero:std_logic;
signal tmp_light:std_logic_vector(15 downto 0); --十六位输出
begin
--RAM_CTR:process(memread,memwrite)
--begin
-- RAM1_EN <= '0';
-- RAM1_OE <= NOT memread;
-- RAM1_WE <= NOT memwrite;f
--end process RAM_CTR;
--输出切换
Show_Switch_ctrl : process(clk,rst,showctrl)
begin
if rst='0' then
SHow_STATE_LEFT <= "1110110"; --H
shower<=PC;
elsif rising_edge(showctrl) then
case shower is --输出不同信号
when pc =>
shower<=alu; --输出状态
SHow_STATE_LEFT <= "0000110"; --1
when alu =>
shower<=mem;
SHow_STATE_LEFT <= "1011011"; --2
when mem =>
shower<=reg;
SHow_STATE_LEFT <= "1001111"; --3
when reg =>
shower<=regx;
SHow_STATE_LEFT <= "1100110"; --4
when regx =>
shower<=regy;
SHow_STATE_LEFT <= "1101101"; --5
when regy =>
shower<=regz;
SHow_STATE_LEFT <="1111101"; --6
when regz =>
shower <= pc_show;
SHow_STATE_LEFT <= "0000111"; --7
when pc_show =>
shower<= IR_show;
SHow_STATE_LEFT <= "1111111"; --8
when IR_show =>
shower<=pc;
SHow_STATE_LEFT <= "1110110"; --H
end case;
end if;
end process Show_Switch_ctrl;
--输出(先放入 temp signal)
SHOW_SINGNAL:process(clk0,rst,state)
begin --输出状态
if rst='0' then
tmp_light <= "0000000000000000";
elsif rising_edge(clk0) then
case shower is
when pc => --H
tmp_light(15 downto 0)<=x"0000";
tmp_light(15)<=pcwrite;
tmp_light(11)<=pcsource;
tmp_light(7)<=pcwritecond;
when alu => --1
tmp_light(15 downto 0)<=x"0000";
tmp_light(15 downto 14)<=aluop;
tmp_light(11)<=alusrca;
tmp_light(7 downto 6)<=alusrcb;
when mem => --2
tmp_light(15 downto 0)<=x"0000";
tmp_light(15)<=memread;
tmp_light(11)<=memwrite;
tmp_light(7)<=irwrite;
tmp_light(3 downto 2)<=memtoreg;
when reg => --3
tmp_light(15 downto 0)<=x"0000";
tmp_light(15 downto 13)<=regwrite;
tmp_light(11 downto 10)<=regdst;
tmp_light(7)<=iord;
when regx => --4
tmp_light(12 downto 0) <= REGS(conv_integer(rex))(12 downto 0);
tmp_light(15 downto 13) <= rex;
when regy => --5
tmp_light(12 downto 0) <= REGS(conv_integer(rey))(12 downto 0);
tmp_light(15 downto 13) <= rey;
when regz => --6
tmp_light(12 downto 0) <= REGS(conv_integer(rez))(12 downto 0);
tmp_light(15 downto 13) <= rez;
when PC_show => --7
tmp_light <= pc_mem;
when IR_show => --8
tmp_light <= instructions;
end case;
end if;
end process SHOW_SINGNAL;
process(rst,bzero_ctrl) --控制移位
begin
if rst='0' then
bzero<='0';
elsif rising_edge(bzero_ctrl) then
if bzero = '0' then
bzero<='1';
tmpb_zero<='0';
elsif bzero='1' then
tmpb_zero<='1';
bzero<='0';
end if;
end if;
end process;
process(bzero) --控制移位
begin
if bzero='1' then
pcwritecond<='1';
elsif bzero='0' then
pcwritecond<='0';
end if;
end process;
process(rst,clk)
begin --控制状态
if(rst='0') then
RAM1_EN <= '1'; --RAM1 的片选信号
RAM1_OE <= '0'; --读信号
RAM1_WE <= '0'; --写信号
state<=instruction_fetch;
beqz_state<=updateaddr; --BEQZ
SHOW_STATE_RIGHT <= "1110110"; --H
instructions <= X"0000";
iord<='0';
irwrite<='0';
memread<='0';
memwrite<='0';
memtoreg<="00";
aluop<="00";
alusrca<='0';
alusrcb<="00";
pcwrite<='0';
pcsource<='0';
regdst<="00";
regwrite<="000";
elsif rising_edge(clk)then
case state is
when instruction_fetch => --取指令值
SHOW_STATE_RIGHT <= "0000110"; --1-取值
instructions <= SW_IN; --SW 使用拨片传入地址 --将指令写入IR
MemRead<='1'; --从存储器中读数据
Memwrite <= '0'; --不写入存储器
ALUSrcA<='0'; --来自PC
IorD<='0'; --来源于PC
beqz_state<=updateaddr; --BEQZ
ALUSrcB<="01";
ALUOp<="00";
PCWrite<='1';
PCSource<='0';
IRWrite<='1';
RegWrite<="000";
state<=wxaddr;
rex <= instructions(10 downto 8);
when wxaddr => --写x地址-----2
SHOW_STATE_RIGHT<="1011011";
-- taddr <= SW_IN;
rex<=SW_IN(2 downto 0);
state<=wxdata;
when wxdata => --写x数据------3
SHOW_STATE_RIGHT<="1001111";
REGS(conv_integer(rex))<=SW_IN;
state<=wyaddr;
when wyaddr => --写y地址------4
SHOW_STATE_RIGHT<="1100110";
-- taddr<=SW_IN;
rey<=SW_IN(2 downto 0);
state<=wydata;
when wydata => --写y数据------5
SHOW_STATE_RIGHT<="1101101";
REGS(conv_integer(rey))<=SW_IN;
state<=decode;
when decode => --译码
SHOW_STATE_RIGHT <= "1111101"; --6-译码
IRWrite<='0';
MemRead<='0';
PCWrite<='0';
ALUSrcA<='0';
ALUSrcB<="10";
ALUOp<="00";
case instructions(15 downto 11) is
when "11100" => -- ADDU SUBU
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
rez <= instructions(4 downto 2);
when "00100" => --BEQZ
rex <= instructions(10 downto 8);
when "11101" =>
if (instructions(2 downto 0) = "000") then --JR
rex <= instructions(10 downto 8);
elsif (instructions(2 downto 0) = "110") then --XOR
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
elsif (instructions(2 downto 0) = "100") then --SLLV
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
end if;
when "10011" => --LW
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
when "11011" => --SW
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
when others =>
null;
end case;
state<=execute;
when execute=> --执行
SHOW_STATE_RIGHT <= "0000111"; --7
case instructions(15 downto 11)is
when "00100"=> --执行 BEQZ 如果x寄存器值为0,则跳转到目的地址执行
ALUSrcA<='1';
ALUOp<="10";
PCSource<='1';
rex <= instructions(10 downto 8);
state<=write_reg;
when "10011"=> --LW
ALUSrcA<='1';
ALUSrcB<="10";
ALUOp<="00";
state<=mem_control;
RAM1_EN <= '0';
RAM1_OE <= '0';
RAM1_WE <= '1';
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
ADDR <= REGS(conv_integer(rex)) + instructions(4 downto 0);
when "11011"=> --SW
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '0';
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
ADDR <= REGS(conv_integer(rex)) + instructions(4 downto 0);
ALUSrcA<='1';
ALUSrcB<="10";
ALUOp<="00";
state<=mem_control;
when "11100"=>
case instructions(1 downto 0) is
when "01" => --ADDU
ALUSrcA<='1';
ALUSrcB<="00";
ALUOp<="00";
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
rez <= instructions(4 downto 2);
when "11" => --SUBU
ALUSrcA<='1';
ALUSrcB<="00";
ALUOp<="01";
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
rez <= instructions(4 downto 2);
when others=>
null;
end case;
state<=write_reg;
when "11101"=>
case instructions(4 downto 0)is
when "01110"=> --XOR
ALUSrcA<='1';
ALUSrcB<="00";
ALUOp<="10";
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
state<=write_reg;
when "00000"=> --JR
rex <= instructions(10 downto 8);
--case instructions(7 downto 5)is
--when "000"=>
--ALUSrcA<='1';
--ALUOp<="10";
--PCWrite<='1';
--PCSource<='0';
--state<=instruction_fetch;
--when others=>
--null;
state<=write_reg;
--end case;
when "00100"=> --SLLV移位
rex <= instructions(10 downto 8);
rey <= instructions(7 downto 5);
state<=write_reg;
when others=>
null;
end case;
when others=>
null;
end case;
when mem_control=> --访存
SHOW_STATE_RIGHT <= "1111111"; --8
PCWrite<='0';
RegWrite<="000";
case instructions(15 downto 11)is
when "10011"=> --LW
MemRead<='1';
IorD<='1';
state<=write_reg;
REGS(conv_integer(rey)) <= DATA;
when "11011"=> --SW
RAM1_EN <= '0';
RAM1_OE <= '0';
RAM1_WE <= '1';
MemWrite<='1';
IorD<='1';
state<=instruction_fetch;
DATA <= REGS(conv_integer(rey));
when others=>
null;
end case;
when write_reg=> --写回
SHOW_STATE_RIGHT <= "1101111"; --9
MemWrite<='0';
MemRead<='0';
case instructions(15 downto 11)is
when "10011"=> --LW
RegDst<="10";
RegWrite<="001";
MemtoReg<="01";
state<=instruction_fetch;
when "11011"=> --SW
MemWrite<='0';
IorD<='0';
state<=instruction_fetch;
when "11100"=> --SUBU ADDU
case instructions(1 downto 0)is
when "11" => --SUBU
REGS(conv_integer(rez)) <= REGS(conv_integer(rex)) - REGS(conv_integer(rey));
RegDst<="01";
RegWrite<="001";
MemtoReg<="00";
when "01" => --ADDU
REGS(conv_integer(rez)) <= REGS(conv_integer(rex)) + REGS(conv_integer(rey));
RegDst<="01";
RegWrite<="001";
MemtoReg<="00";
when others=>
null;
end case;
state<=instruction_fetch;
when "11101"=> --JR XOR
case instructions(4 downto 0)is
when "00000"=> --JR
pc_mem <= REGS(conv_integer(rex));
RegDst<="00";
RegWrite<="001";
MemtoReg<="00";
case beqz_state is
when updateaddr=>
ADDR<=pc_mem;
beqz_state<=updatedata;
when updatedata=>
instructions<=DATA;
rex <= DATA(10 downto 8);
beqz_state<=updateaddr;
state<=wxaddr;
end case;
when "01110"=> --XOR
REGS(conv_integer(rex)) <= REGS(conv_integer(rex)) XOR REGS(conv_integer(rey));
RegDst<="00";
RegWrite<="001";
MemtoReg<="00";
state<=instruction_fetch;
when "00100"=> --SLLV
REGS(conv_integer(rey))<=TO_STDLOGICVECTOR(To_bitvector(REGS(conv_integer(rey))) SLL CONV_INTEGER(REGS(conv_integer(rex))));
state<=instruction_fetch;
when others=>
null;
end case;
when "00100" => --BEQZ
if (REGS(conv_integer(rex)) = 0) then
pc_mem <= pc_mem + instructions(7 downto 0);
case beqz_state is
when updateaddr=>
ADDR<=pc_mem;
beqz_state<=updatedata;
when updatedata=>
instructions<=DATA;
rex <= DATA(10 downto 8);
beqz_state<=updateaddr;
state<=wxaddr;
end case;
else
pc_mem<= pc_mem + "0000000000000001";
state<=instruction_fetch;
end if;
when others=>
null;
end case;
-- state<=instruction_fetch;
end case;
end if;
dbc <= '1';
end process;
light<=tmp_light; --输出结果
end Behavioral;
- 指令的数据通路图
三、综合实验总结
- 实验难点
- 刚开始做时不知道如何自由输入输入到寄存器中,思考后增加了寄存器地址数据输入的状态,来实现寄存器数据的手动写入。
- 此次实验的难点在于要将每条指令都设计出来,并进行验证。
- 在进行转移指令的编写时,一开始无法实现指令的传递,后来发现需要使用PC寄存器,定义了两个转移状态后实现了指令的正确转移。
- 在验证时发现存在数据刷新不及时的问题,经排查后发现是手动数据输入比状态转换慢了一拍,调整输入和切换状态时间后能正确验证,
- 心得体会
本次实验是一个综合性实验,刚看到题目是会有一些无从下手,但慢慢发现CPU的设计就是前面ALU,存储器,控制器设计的综合。将CPU的设计划分为几部分写,并把它们联系起来就可以实现。
组内分工:
负责代码编写,管脚约束,实验板调试。
申请优。