计算机组成与结构综合大实验验优:16位运算器设计实验、存储器实验、控制器实验、16位CPU设计实验
计算机组成与结构综合大实验:16位运算器设计实验、存储器实验、控制器实16位CPU设计实验
综合性比较强的大实验,先是在实验室完成前面三个小实验,最后再三个结合完成最后的16位CPU的设计,需要软硬件结合一起。
部分代码如下:
process(RST, CLK)
begin
if RST = '0' then state <= 0; a<="0000000000000000"; b<="0000000000000000"; opCode<="0000"; output <= (others=>'0'); stateCnt <= not "0000000";
elsif CLK'event and CLK = '1' then
case state is
when 0 => state <= 1; a <= INPUT; stateCnt <= not "1000000";OUTPUT<=a;
when 1 => state <= 2; b <= INPUT; stateCnt <= not "1111001";OUTPUT<=b;
when 2 => state <= 3; opCode <= input(3 downto 0); stateCnt <= not "0100100"; OUTPUT <= input;
when 3 => state <= 4; OUTPUT<= y; stateCnt <= not "0110000";
when 4 => state <= 0; output<= outout; stateCnt <= not "0011001";
end case;
end if;
end process;
process(RST, opCode)
begin
cflag <= '0';
oflag <= '0';
zflag <= '0';
sflag <= '0';
case opCode is
-- 加法
when "0000" => y<= a + b;
if(y = "0000000000000000") then
zflag <= '1';
end if;
if(a(15) = '1' and b(15) = '1') then
cflag <= '1';
if(y(15) = '0') then
oflag <= '1';
end if;
end if;
if(a(15) = '0' and b(15) = '0' and y(15) = '1') then
oflag <= '1';
end if;
if(y(15) = '1') then
sflag <= '1';
end if;
temp <= "1111111111111111" - a;
if(b > temp) then
cflag <= '1';
end if;
-- 减法
when "0001" => y<= a + (not b) + 1;
if(y(15) = '1') then
sflag <= '1';
end if;
if(y = "0000000000000000") then
zflag <= '1';
end if;
temp <= (not b) + 1;
if(a(15) = '1' and temp(15) = '1') then
cflag <= '1';
if(y(15) = '0') then
oflag <= '1';
end if;
end if;
if(a(15) = '0' and temp(15) = '0' and y(15) = '1') then
oflag <= '1';
end if;
if(a < b) then
cflag <= '1';
end if;
-- 加减,逻辑与,或,亦或,非,逻辑、循环、算数
when "0010" => y<= a and b;
if(y(15) = '1') then
sflag <= '1';
end if;
if(y = "0000000000000000") then
zflag <= '1';
end if;
when "0011" => y<= a or b;
if(y(15) = '1') then
sflag <= '1';
end if;
if(y = "0000000000000000") then
zflag <= '1';
end if;
when "0100" => y<= a xor b;
if(y(15) = '1') then
sflag <= '1';
end if;
if(y = "0000000000000000") then
zflag <= '1';
end if;
when "0101" => y<= not a;
if(y(15) = '1') then
sflag <= '1';
end if;
if(y = "0000000000000000") then
zflag <= '1';
end if;
-- 逻辑
when "0110" => y<= to_stdlogicvector(to_bitvector(a) sll conv_integer(b));
when "0111" => y<= to_stdlogicvector(to_bitvector(a) srl conv_integer(b));
-- 算数
when "1000" => y<= to_stdlogicvector(to_bitvector(a) sll conv_integer(b));
when "1001" => y<= to_stdlogicvector(to_bitvector(a) sra conv_integer(b));
-- 循环
when "1010" => y<= to_stdlogicvector(to_bitvector(a) rol conv_integer(b));
when "1011" => y<= to_stdlogicvector(to_bitvector(a) ror conv_integer(b));
-- when "0010" => y<= a + b + Cin;
-- when "0011" => y<= a - b - Cin;
3.实验拓展(实现ADC和SBB指令,已经验收通过)
-- ADC(带进位加)
初始进位,A异或B异或C(三个里面有奇数个1则为1),向高一位的进位,AB或AC或BC(至少有两个1则有进位)
when "1100" => y<= a + b+cflag;
if(y = "0000000000000000") then
zflag <= '1';
end if;
if(a(15) = '1' and b(15) = '1') then
cflag <= '1';
if(y(15) = '0') then
oflag <= '1';
end if;
end if;
if(a(15) = '0' and b(15) = '0' and y(15) = '1') then
oflag <= '1';
end if;
if(y(15) = '1') then
sflag <= '1';
end if;
temp <= "1111111111111111" - a;
if(b > temp) then
cflag <= '1';
end if;
-- SBB带借位减(A-B-C)
初始借位,A异或B异或C(三个里面有奇数个1则为1),向高一位的借位,(BC均为1或BC有一个为1同时A为0就要借位即借位为1)
when "1101" => y<= a + (not b) -cflag;
if(y(15) = '1') then
sflag <= '1';
end if;
if(y = "0000000000000000") then
zflag <= '1';
end if;
temp <= (not b) + 1;
if(a(15) = '1' and temp(15) = '1') then
cflag <= '1';
if(y(15) = '0') then
oflag <= '1';
end if;
end if;
if(a(15) = '0' and temp(15) = '0' and y(15) = '1') then
oflag <= '1';
end if;
if(a < b) then
cflag <= '1';
end if;
when others=> y<="0000000000000000";
end case;
outout(15) <= oflag;
outout(14) <= cflag;
outout(13) <= zflag;
outout(12) <= sflag;
end process;
- 实验截图
黄色圈的地方是输入步骤显示
蓝色圈的地方是标志位和结果显示的LED灯
红色圈的地方是输入决定ALU功能的操作码的地方,以及输入计算的数据的地方。
(需要小心的是0~15是从左到右,拨上去是0,拨下来是1)
三、综合实验总结
1.实验难点
(1) 在输出标志位时,如何通过操作数和操作结果判断标志位:
(2)在判断进位标志位cFlags时,需要仔细考虑指令对标志位的影响和影响的原理,尤其是ADC指令和SBB指令,需要记录每一位的进位并利用循环结构得到最终结果和进位标志位(类似全加器原理)。
(3)在判断溢出标志位oFlags时,要灵活掌握操作数和运算结果之间符号位的变化与OF标志位的关系,以便正确设置标志位。
(4)在进行移位运算时,要将需要被移位的操作数(即A)的数据类型转换为位矢量类型后才可以移位,将移位操作数转换成整数。
2.心得体会
略
四、思考题
(1)ALU进行算术逻辑运算所使用的电路是组合逻辑电路还是时序逻辑电路?
答:组合逻辑电路,没有记忆功能,此时刻输入只取决于此时刻输出。
(2)如果给定了A和B的初值,且每次运算完后结果都写入到B中,再进行下次运算。这样一个带暂存功能的ALU要增加一些什么电路来实现?
答: 增加暂存器TMP和累加器AC。
六.部分代码展示
begin
process(RST,ctrl_r)
begin
if RST='0' then
ctrl_state<=N;
elsif rising_edge(ctrl_r)then
case ctrl_state is
when N=>
ctrl_state<=W;
when W=>
ctrl_state<=R;
when R=>
ctrl_state<=W;
end case;
end if;
end process;
process(RST,CLK,ctrl_state)
begin
if RST='0' then
tmp_data<=x"0000";
tmp_read_addr<=x"0000";
tmp_addr<=x"0000";
to_light<=x"0000";
RAM1_EN<='1';
RAM1_OE<='0';
RAM1_We<='0';
address_state<=waiting;
write_state<=waiting;
read_state<=waiting;
elsif rising_edge(CLK) then
case ctrl_state is
when N=>
ADDR<=Input_data;
SEG <= not"1000000";
tmp_addr<=Input_data;
tmp_read_addr<=Input_data;
when W=>
case write_state is
when waiting =>
address_state<=waiting ;
write_state<=start;
read_state<=waiting;
SEG <= not"1000000";
when start=>
--tmp_data<=Input_data;
ADDR<=tmp_addr;
DATA<=Input_data;
RAM1_EN<='0';
RAM1_OE<='1';
RAM1_We<='0';
SEG<=not"1111001";
write_state<=over;
when over=>
write_state<=waiting;
tmp_addr<=tmp_addr+1;
SEG <= not "0100100";
end case;
when r=>
case read_state is
when waiting=>
address_state<=waiting;
read_state<=start;
write_state<=waiting;
SEG <= not"1000000";
when start=>
RAM1_EN<='0';
RAM1_OE<='1';
RAM1_We<='1';
ADDR<=tmp_read_addr;
DATA<=(others=>'Z');
read_state<=read;
SEG<=not"1111001";
when read=>
RAM1_OE<='0';
RAM1_We<='1';
to_light<=DATA;
SEG <=not "0100100";
read_state<=over;
when over=>
SEG <= not"0110000";
read_state<=waiting;
tmp_read_addr<=tmp_read_addr+1;
end case;
end case;
end if;
dbc<='1';
end process;
light<=to_light;
end Behavioral;
三、综合实验总结
1.实验难点
略
2.心得体会
略
四、思考题
静态存储器的读、写时序各有什么特点?
答:如图所示,特点如下:
3.部分代码展示
architecture Behavioral of unit is
signal bzero : std_logic;(布尔)------------------------
type shower_state is (PC,ALU,Mem,Reg);--------枚举类型,有四种状态---计数,加法器,内存,寄存器
signal shower : shower_state;--------------------
type controler_state is
(instruction_fetch,decode,execute,mem_control,write_reg);
signal state : controler_state;
signal PCWrite : std_logic;-------------------是否改写PC
signal PCWriteCond : std_logic;--------------------转移指令的条件
signal PCSource : std_logic;------------------------新的PC来源选择
signal ALUOp : std_logic_vector(1 downto 0);-----ALU运算功能选择
signal ALUSrcA : std_logic;---------------------------ALU源操作数A的选择
signal ALUSrcB : std_logic_vector(1 downto 0);
signal MemRead : std_logic;--------------------------是否读寄存器
signal MemWrite : std_logic;--------------------------是否写寄存器
signal IRWrite : std_logic;-----------------------------写IR
signal MemtoReg : std_logic_vector(1 downto 0);---写入寄存器堆的数据来源选择
signal RegWrite : std_logic_vector(2 downto 0);------写寄存器控制
signal RegDst : std_logic_vector(1 downto 0);--------选择目的寄存器
signal IorD : std_logic;-----------------存储器地址来源
signal tmpb_zero : std_logic;
signal tmp_light : std_logic_vector(15 downto 0);
begin
light <= tmp_light;----灯
process(clk,rst,showCtrl)---------按钮
begin
if rst='0' then
shower<=PC;
elsif rising_edge(showCtrl) then-----按
case shower is -----跳转四个状态
when PC=>
shower<=ALU;
when ALU=>
shower<=Mem;
when Mem=>
shower<=Reg;
when Reg=>
shower<=PC;
end case;
end if;
end process;
process(clk0,rst,state)
begin
if rst='0' then
tmp_light<=x"0000";
elsif rising_edge(clk0) then
case shower is
when PC=>
tmp_light(15 downto 0)<=x"0000";
tmp_light(15)<=PCWrite;
tmp_light(11)<=PCSource;
tmp_light(7)<=PCWriteCond;
when ALU=>
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=>
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=>
tmp_light(15 downto 0)<=x"0000";
tmp_light(15 downto 13)<=RegWrite;
tmp_light(11 downto 10)<=RegDst;
tmp_light(7)<=IorD;
end case;
end if;
end process;
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
state<=instruction_fetch;
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=>--------------取指
MemRead<='1';
ALUSrcA<='0';
IorD<='0';
ALUSrcB<="01";
ALUOp<="00";
PCWrite<='1';
PCSource<='0';
IRWrite<='1';
RegWrite<="000";
state<=decode;
when decode=>----------------译码
IRWrite<='0';
MemRead<='0';
PCWrite<='0';
ALUSrcA<='0';
ALUSrcB<="10";
ALUOp<="00";
state<=execute;
when execute=>---------------执行
case instructions(15 downto 11) is
when "00100" =>
ALUSrcA<='1';
ALUOp<="10";
PCSource<='1';
state<=instruction_fetch;
when "10011"=>
ALUSrcA<='1';
ALUSrcB<="10";
ALUOp<="00";
state<=mem_control;
when "11011"=>
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";
when "11" => -----subu
ALUSrcA<='1';
ALUSrcB<="00";
ALUOp<="01";
when others =>
null;
end case;
state <=write_reg;
when "11101" =>
case instructions(4 downto 0) is
when "01101" =>
ALUSrcA<='1';
ALUSrcB<="00";
ALUOp<="10";
state<=write_reg;
when "00000" =>
case instructions(7 downto 5) is
when "000"=>
ALUSrcA<='1';
ALUOp<="10";
PCWrite<= '1';
PCSource <= '0';
state<= instruction_fetch;
when others=>
null;
end case;
when others =>
null;
end case;
when others=>
null;
end case;
when mem_control =>---------------访存
PCWrite<= '0';
RegWrite<="000";
case instructions(15 downto 11) is
when "10011" =>
MemRead <= '1';
IorD <= '1';
state <= write_reg;
when "11011" =>
MemWrite <= '1';
IorD <= '1';
state <= write_reg;
when others =>
null;
end case;
when write_reg=>----------------写入
Memwrite <= '0';
MemRead <= '0';
case instructions (15 downto 11) is
when "10011" =>
RegDst <= "10";
RegWrite <= "001";
MemtoReg <= "01";
when "11011" =>
MemWrite <= '0';
IorD <= '0';
when "11100" =>
case instructions (1 downto 0) is
when "01" =>
RegDst<= "01";
RegWrite<= "001";
MemtoReg <= "00";
when "11" =>
RegDst <="01";
RegWrite<= "001";
MemtoReg <= "00";
when others =>
null;
end case;
when "11101" =>
case instructions (4 downto 0) is
when "01101"=>
RegDst <="00";
RegWrite<= "001";
MemtoReg <= "00";
when others =>
null;
end case;
when others=>
null;
end case;
state <= instruction_fetch;
end case;
end if;
end process;
end Behavioral;
三.执行阶段实现的七条指令
七条指令分别为:ADDU SUBU BNEZ JR OR LW SW。
前面演示了取值,译码,到执行的时候,需要参考实验书上的131页到133页的七条指令格式的设计,这时候对应的代码会有指令的指示跳转到各自的指令执行的地方,LED灯会有各自的位置亮起。至于指令的数据通路和解释,将在下一个实验CPU中给出。
下面给出实验时候执行阶段手写的指令:
![在这里插入图片描述](https://img-blog.csdnimg.cn/3de6e5a7b06941ba960d084772c93d5f.png
四.实验截图
红色部分是演示时候LED灯亮的位置
黄色部分是执行阶段输入的指令代表的数字
蓝色部分三个按钮有重置,跳转状态(ALU,Mem,Reg,PC),跳转周期(取值,译码,执行,访存,写回)的功能,即CLK,RST和右边第一个红色小按钮。
四、综合实验总结
1.实验难点
略
2.心得体会
略
实验四 16位CPU设计实验
一、目的与要求
实现一个基于MIPS指令集的CPU,数据总线16位,地址总线16位,具有8个16位的通用寄存器。指令包括访存指令(如LW,SW),传送指令(如LI,MOVE),算术运算指令(如ADDU,SUBU),逻辑运算指令(NOT,OR),移位运算指令(如SLL),具体指令见实验指导书P23-P32。
具体要求:
(1)完成7条指令,必须包括访存指令LW和SW,其余每类指令最多2条。
(2)按照取指、译码、执行、访存和写回五个工作周期,分析每条指令的指令流程。
(3)根据指令流程,设计每条指令的CPU数据通路,定义涉及的所有微操作控制信号。然后逐一合并数据通路,说明增加或减少处理器功能部件的理由。给出控制器的完整设计过程。
(4)编写VHDL程序实现CPU,并通过实验板验证。
二、实验正文
1.实验内容
(1)实现一个基于MIPS指令集的多周期CPU
(2)设计完成7条指令,必须包括访存指令LW和SW,其余每类指令最多2条
(3)按照取指、译码、执行、访存和写回五个工作周期,分析每条指令的指令流程
(4)根据指令流程,设计每条指令的CPU数据通路,定义涉及的所有微操作控制信号。然后逐一合并数据通路,说明增加或减少处理器功能部件的理由。给出控制器的完整设计过程。
(5)编写VHDL程序实现CPU,并通过实验板验证。
(6)给出完整的设计报告,包括基本部件设计,如寄存器组、特殊寄存器、多路选择器等;每一条指令的数据通路图,以及CPU总数据通路图;控制器的设计等。
(2)SUBU
数据通路分析过程:
①取指令阶段:需要从程序寄存器PC中取出当前指令地址送给指令存储器InstructionMemory的地址输入端,然后从指令存储器数据输出端口得到指令内容以便下一周期译码,同时要将PC当前内容加2送给PC寄存器,使其指向下一条指令。
②译码阶段:需要从指令中得到Rs寄存器和Rt寄存器的编号,送给寄存器组RegisterFiles的Ra和Rb输入端,从输出端A、B取出其中内容即源操作数,送给运算器输入端以便于下一步进行减法运算,同时需要从指令中取出Rd寄存器编号送给寄存器组Rw输入端作为目的地址,以便之后将运算器运算结果送给寄存器组的输入端W,写入寄存器Rd。
③计算阶段:A、B通过运算部件ALU进行减法运算。
④写回寄存器阶段:将ALU输出端得到的运算结果送给寄存器组的输入端W,写入寄存器Rd。
控制信号:
RegWrite:由于加法功能需要读出寄存器Ra和Rb的内容还需要向Rw寄存器写入内容,所以需要增加一个控制信号控制寄存器组的读/写。
ALUop:由于ALU的功能有多种,故增加一个控制信号控制ALU功能选择。
(3)LW
①取指令阶段:需要从程序寄存器PC中取出当前指令地址送给指令存储器InstructionMemory的地址输入端,然后从指令存储器数据输出端口得到指令内容以便下一周期译码,同时将PC加2送给PC,指向下一条指令。
②译码阶段:需要从指令中的第11位到第9位取出Rs寄存器编号送给寄存器组Ra输入端,从输出端A取出Rs寄存器内容送给运算器A输入端,第5位到第0位取出6位立即数经过扩展送给运算器B输入端,同时还要将指令第8位到第6位送给Rw输入端作为目的寄存器编号。
③计算阶段:A、B输入的内容送给运算器进行加法运算。
④读存储器:ALU输出内容送给数据存储器地址输入端addr。
⑤写回寄存器:数据存储器数据输出端D送给寄存器组数据写入端W,根据Rw中存放的Rt寄存器编号,将数据写入Rt寄存器。
控制信号:
ALUop:控制选择ALU功能为加法。
ALUsrcB:控制选择运算器B输入端的内容来源,本指令中来源于指令低6位扩展到16位后的立即数。
RegWrite:控制寄存器组的读出和写入。
RegDsrc:控制选择寄存器组Rw输入端的来源,本指令中应选择指令8到6位作为寄存器编号。
Jump、PCsource:控制下一条指令的转移。
RWmem:控制数据存储器的读出和写入。
Wsrc:控制选择写入寄存器的数据来源,本指令来源于数据存储器输出数据。
(4)SW
数据通路分析过程:
①取指令阶段:需要从程序寄存器PC中取出当前指令地址送给指令存储器InstructionMemory的地址输入端,然后从指令存储器数据输出端口得到指令内容以便下一周期译码,同时将PC加2送给PC,指向下一条指令。
②译码阶段:需要从指令中的第11位到第9位取出Rs寄存器编号送给寄存器组Ra输入端,从输出端A取出Rs寄存器内容送给运算器A输入端,第5位到第0位取出6位立即数经过扩展送给运算器B输入端,同时还要将指令第8位到第6位送给Rb输入端作为输入数据寄存器编号。
③计算阶段:运算器对A、B输入的内容进行加法运算,运算后结果为目的地址需要送给数据存储器地址端addr。
④读寄存器:寄存器组B输出端内容输入数据,将其送给数据存储器数据输入端W。
⑤写回存储器:将数据存储器输入端W的数据写入目的地址addr。
控制信号:
ALUop:控制选择ALU功能为加法。
ALUsrcB:控制选择运算器B输入端的内容来源,本指令中来源于指令低6位扩展到16位后的立即数。
RegWrite:控制寄存器组的读出和写入。
Jump、PCsource:控制下一条指令的转移。
RWmem:控制数据存储器的读出和写入。
Wsrc:控制选择写入寄存器的数据来源,本指令来源于数据存储器输出数据。
(5)ADDIU
数据通路分析过程:
①取指令阶段:需要从程序寄存器PC中取出当前指令地址送给指令存储器InstructionMemory的地址输入端,然后从指令存储器数据输出端口得到指令内容以便下一周期译码,同时将PC加2送给PC,指向下一条指令。
②译码阶段:需要从指令中的第11位到第9位取出Rs寄存器编号送给寄存器组Ra输入端,从输出端A取出Rs寄存器内容送给运算器A输入端,第11位到第9位取出Rs寄存器编号还要送给Rw输入端作为运算后的目的寄存器编号,取出指令的8到0位送给运算器B输入端,。
③计算阶段:A、B输入的内容送给运算器进行加法运算。
④写回阶段:ALU输出内容送给寄存器组W输入端写回Rw所存的编号的寄存器。
控制信号:
ALUop:控制选择ALU功能为加法。
ALUsrcB:控制选择运算器B输入端的内容来源,本指令中来源于指令低9位扩展到16位后的立即数。
RegWrite:控制寄存器组的读出和写入。
RegDsrc:控制选择寄存器组Rw输入端的来源,本指令中应选择指令11到9位作为寄存器编号。
Jump、PCsource:控制下一条指令的转移。
(6)B
数据通路分析过程:
①取指令阶段:需要从程序寄存器PC中取出当前指令地址送给指令存储器InstructionMemory的地址输入端,然后从指令存储器数据输出端口得到指令内容以便下一周期译码。
②译码阶段:需要从指令中的低12位扩展成16位与当前PC内容相加送回PC。
控制信号:
Jump:由于PC的值和当前执行指令有关,故增加一个控制信号Jump通过一个多路选择器控制PC的选择。
(7)JR
数据通路分析过程:
①取指令阶段:需要从程序寄存器PC中取出当前指令地址送给指令存储器InstructionMemory的地址输入端,然后从指令存储器数据输出端口得到指令内容以便下一周期译码。
②译码阶段:需要从指令中的第11位到第9位取出Rs寄存器编号送给寄存器组Ra输入端,从输出端A取出Rs寄存器内容以便下一步根据指令功能通过运算器运算。
③计算阶段:寄存器取出的内容送给ALU输入端A,通过ALUop控制信号选择直接输出源操作数A的功能。
④写回阶段:ALU输出内容送给PC。
控制信号:
RegWrite:由于需要将读出Rs寄存器内容,所以需要一个寄存器读信号,将内容从寄存器组输出端口A输出。
ALUop:此指令运算器需要新的功能,故用ALUop信号控制运算器功能选择,这条指令中应该选择输出Y=A。
PCsource:PC的内容又增加了新的选择,故需要一个OPsource信号通过多路选择器控制PC的输入选择。
(5)根据CPU总数据通路图设计控制器:列出控制信号表格以及每条指令在每个指令周期控制信号的值,完成控制器完整设计:
(7)部分代码展示
process(RST,showCtrl) -----状态转换
begin
if RST = '0' then
State_show <= PC;
stateCnt_L <= "0111001";
elsif showCtrl'event and showCtrl = '1' then
case State_show is
when PC =>
stateCnt_L <= "0000110";
State_show <= ALU;
when ALU =>
stateCnt_L <= "1011011";
State_show <= M;
when M =>
stateCnt_L <= "1001111";
State_show <= REG;
when REG =>
stateCnt_L <= "1100110";
State_show <= PC;
end case;
end if;
end process;
......
when decode =>
stateCnt_R <= "1011011";
AluSrcA <= '0';
ALUSrcB <= "10";
ALUOp <= "00";
MemRead <= '0';
IRWrite <= '0';
PcWrite <= '0';
CU_state <= execute;
case instruction(15 downto 11) is
when "11100" =>
rx <= instruction(10 downto 8);
ry <= instruction(7 downto 5);
rz <= instruction(4 downto 2);
when "00100" => --BEQZ
rx <= instruction(10 downto 8);
IMD <= instruction(7 downto 0);
when "11101" =>
case instruction(4 downto 0) is
when "00000" => --JR
rx <= instruction(10 downto 8);
when "01110" => --XOR
rx <= instruction(10 downto 8);
ry <= instruction(7 downto 5);
when others =>
null;
end case;
when "10011" => --LW
rx <= instruction(10 downto 8);
ry <= instruction(7 downto 5);
im <= instruction(4 downto 0);
when "11011" => --SW
rx <= instruction(10 downto 8);
ry <= instruction(7 downto 5);
im <= instruction(4 downto 0);
when others =>
null;
end case;
when execute =>
stateCnt_R <= "1001111";
control_state <= 0;
case instruction(15 downto 11) is
when "11100" =>
if instruction(1 downto 0) = "01" then --ADDU
ALUSrcA <= '1';
ALUSrcB <= "00";
ALUOp <= "00";
elsif instruction(1 downto 0) = "11" then --SUBU
ALUSrcA <= '1';
ALUSrcB <= "00";
ALUOp <= "01";
end if;
CU_state <= write_reg;
when "00100" => --BEQZ
ALUSrcA <= '1';
ALUOp <= "10";
PCSource <= '1';
CU_state <= instruction_fetch;
when "11101" =>
case instruction(4 downto 0) is
when "00000" => --JR
ALUSrcA <= '1';
ALUOp <= "10";
PcWrite <= '1';
PCSource <= '0';
CU_state <= instruction_fetch;
when "01110" => --XOR
ALUSrcA <= '1';
ALUSrcB <= "00";
ALUOp <= "10";
CU_state <= write_reg;
when others =>
null;
end case;
when "10011" => --LW
ALUSrcA <= '1';
ALUSrcB <= "10";
ALUOp <= "00";
CU_state <= write_reg;
when "11011" => --SW
ALUSrcA <= '1';
ALUSrcB <= "10";
ALUOp <= "00";
CU_state <= write_reg;
when others =>
null;
end case;
when mem_control =>
stateCnt_R <= "1100110";
case instruction(15 downto 11) is
when "10011" => --LW
RegWrite <= "000";
MemRead <= '1';
IorD <= '1';
PcWrite <= '0';
case control_state is
when 2 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
DATA(4 downto 0) <= DATA(4 downto 0) + im;
tmp_read_addr <= DATA;
CU_state <= mem_control;
control_state <= 3;
when 3 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 4;
when others =>
null;
end case;
when "11011" => --SW
RegWrite <= "000";
MemWrite <= '1';
IorD <= '1';
PcWrite <= '0';
case control_state is
when 4 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
DATA(4 downto 0) <= DATA(4 downto 0) + im;
tmp_addr <= DATA;
CU_state <= mem_control;
control_state <= 5;
when 5 =>
ADDR <= tmp_addr;
DATA <= tmp_data;
RAM1_WE<='0';
RAM1_OE<='1';
CU_state <= write_reg;
control_state <= 0;
when others =>
null;
end case;
when others =>
null;
end case;
when write_reg =>
stateCnt_R <= "1101101";
case instruction(15 downto 11) is
when "11100" =>
case instruction(1 downto 0) is
when "01" => --ADDU
RegDst <= "01";
RegWrite <= "001";
MemtoReg <= "00";
MemRead <= '0';
MemWrite <= '0';
case control_state is
when 0 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_addr1 <= "0000000000000000";
tmp_read_addr1 <="0000000000000000";
tmp_read_addr1(2 downto 0) <= rx;
CU_state <= write_reg;
control_state <= 1;
when 1 =>
ADDR <= tmp_read_addr1;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 2;
when 2 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data1 <= DATA;
tmp_read_addr1<="0000000000000000";
tmp_read_addr1(2 downto 0) <= ry;
CU_state <= write_reg;
control_state <= 3;
when 3 =>
ADDR <= tmp_read_addr1;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 4;
when 4 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data1 <= DATA + tmp_data1;
tmp_addr1(2 downto 0) <= rz;
CU_state <= write_reg;
control_state <= 5;
when 5 =>
ADDR <= tmp_addr1;
DATA <= tmp_data1;
RAM1_WE<='0';
RAM1_OE<='1';
CU_state<=instruction_fetch;
control_state <= 0;
when others =>
null;
end case;
when "11" => --SUBU
RegDst <= "01";
RegWrite <= "001";
MemtoReg <= "00";
MemRead <= '0';
MemWrite <= '0';
case control_state is
when 0 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_addr<="0000000000000000";
tmp_read_addr<="0000000000000000";
tmp_read_addr(2 downto 0) <= rx;
CU_state <= write_reg;
control_state <= 1;
when 1 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 2;
when 2 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data <= DATA;
tmp_read_addr<="0000000000000000";
tmp_read_addr(2 downto 0) <= ry;
CU_state <= write_reg;
control_state <= 3;
when 3 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 4;
when 4 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data <= tmp_data - DATA;
tmp_addr(2 downto 0) <= rz;
CU_state <= write_reg;
control_state <= 5;
when 5 =>
ADDR <= tmp_addr;
DATA <= tmp_data;
RAM1_WE<='0';
RAM1_OE<='1';
CU_state <=instruction_fetch;
control_state <= 0;
when others =>
null;
end case;
when others =>
null;
end case;
when "11101" => --XOR
RegDst <= "00";
RegWrite <= "001";
MemtoReg <= "00";
MemRead <= '0';
MemWrite <= '0';
case control_state is
when 0 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_addr <= "0000000000000000";
tmp_read_addr <="0000000000000000";
tmp_read_addr(2 downto 0) <= rx;
CU_state <= write_reg;
control_state <= 1;
when 1 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 2;
when 2 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data <= DATA;
tmp_read_addr <="0000000000000000";
tmp_read_addr(2 downto 0) <= ry;
CU_state <= write_reg;
control_state <= 3;
when 3 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 4;
when 4 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data <= tmp_data xor DATA;
tmp_addr(2 downto 0) <= rx;
CU_state <= write_reg;
control_state <= 5;
when 5 =>
ADDR <= tmp_addr;
DATA <= tmp_data;
RAM1_WE<='0';
RAM1_OE<='1';
CU_state <= instruction_fetch;
control_state <= 0;
when others =>
null;
end case;
when "10011" => --LW
RegDst <= "10";
RegWrite <= "001";
MemtoReg <= "01";
MemRead <= '0';
MemWrite <= '0';
case control_state is
when 0 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_addr <= "0000000000000000";
tmp_read_addr <="0000000000000000";
tmp_read_addr(2 downto 0) <= rx;
CU_state <= write_reg;
control_state <= 1;
when 1 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= mem_control;
control_state <= 2;
when 4 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data <= DATA;
tmp_addr(2 downto 0) <= ry;
CU_state <= write_reg;
control_state <= 5;
when 5 =>
ADDR <= tmp_addr;
DATA <= tmp_data;
RAM1_WE<='0';
RAM1_OE<='1';
CU_state <= instruction_fetch;
control_state <= 0;
when others =>
null;
end case;
when "11011" => --SW
MemRead <= '0';
MemWrite <= '0';
IorD <= '0';
case control_state is
when 0 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_addr <= "0000000000000000";
tmp_read_addr <="0000000000000000";
tmp_read_addr(2 downto 0) <= ry;
CU_state <= write_reg;
control_state <= 1;
when 1 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= write_reg;
control_state <= 2;
when 2 =>
RAM1_EN <= '0';
RAM1_OE <= '1';
RAM1_WE <= '1';
tmp_data <= DATA;
tmp_read_addr <="0000000000000000";
tmp_read_addr(2 downto 0) <= rx;
CU_state <= write_reg;
control_state <= 3;
when 3 =>
ADDR <= tmp_read_addr;
DATA <= (others=>'Z');
RAM1_OE<='0';
RAM1_WE<='1';
CU_state <= mem_control;
control_state <= 4;
when others =>
null;
end case;
when others =>
null;
end case;
end case;
end if;
end process;
三、综合实验总结
1.实验难点
略
2.心得体会
略
四.思考题
设计完成后,给出每条指令输入后在数据通路中的执行过程。
如上面实验步骤给出来的数据通路图,七条指令的都已经给出执行过程。
XXX申请验优!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)