多周期CPU设计(Verilog) (更新:2017/5/29)

注:单周期CPU设计请移步我的另一篇博文:
单周期CPU设计(Verilog)


一、 实验目的

(1) 认识和掌握多周期数据通路原理及其设计方法;
(2) 掌握多周期CPU的实现方法,代码实现方法;
(3) 编写一个编译器,将MIPS汇编程序编译为二进制机器码;
(4) 掌握多周期CPU的测试方法。

二、 实验内容

设计一个多周期CPU,该CPU至少能实现以下指令功能操作。需设计的指令与格式如下:
(说明:操作码按照以下规定使用,都给每类指令预留扩展空间,后续实验相同。)
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

三、 实验原理

多周期CPU指的是将整个CPU的执行过程分成几个阶段,每个阶段用一个时钟去完成,然后开始下一条指令的执行,而每种指令执行时所用的时钟数不尽相同,这就是所谓的多周期CPU。CPU在处理指令时,一般需要经过以下几个阶段:

(1) 取指令(IF):根据程序计数器pc中的指令地址,从存储器中取出一条指令,同时,pc根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令时,则控制器把“转移地址”送入pc,当然得到的“地址”需要做些变换才送入pc。
(2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。
(3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。
(4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得到数据地址单元中的数据。
(5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。

实验中就按照这五个阶段进行设计,这样一条指令的执行最长需要五个(小)时钟周期才能完成,但具体情况怎样?要根据该条指令的情况而定,有些指令不需要五个时钟周期的,这就是多周期的CPU。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

特别提示,图上增加IR指令寄存器,目的是使指令代码保持稳定,pc写使能控制信号PCWre,是确保pc适时修改,原因都是和多周期工作的CPU有关。ADR、BDR、ALUoutDR、DBDR四个寄存器不需要写使能信号,其作用是切分数据通路,将大组合逻辑切分为若干个小组合逻辑,大延迟变为多个分段小延迟。

这里写图片描述

这里写图片描述

相关部件及引脚说明:

  • Instruction Memory:指令存储器
    • Iaddr,指令地址输入端口
    • DataIn,存储器数据输入端口
    • DataOut,存储器数据输出端口
    • RW,指令存储器读写控制信号,为0写,为1读
  • Data Memory:数据存储器
    • Daddr,数据地址输入端口
    • DataIn,存储器数据输入端口
    • DataOut,存储器数据输出端口
    • /RD,数据存储器读控制信号,为0读
    • /WR,数据存储器写控制信号,为0写
  • Register File:寄存器组
    • Read Reg1,rs寄存器地址输入端口
    • Read Reg2,rt寄存器地址输入端口
    • Write Reg,将数据写入的寄存器,其地址输入端口(rt、rd)
    • Write Data,写入寄存器的数据输入端口
    • Read Data1,rs寄存器数据输出端口
    • Read Data2,rt寄存器数据输出端口
    • WE,写使能信号,为1时,在时钟上升沿写入
  • IR: 指令寄存器,用于存放正在执行的指令代码
  • ALU: 算术逻辑单元
    • result,ALU运算结果
    • zero,运算结果标志,结果为0输出1,否则输出0

这里写图片描述
这里写图片描述

四、实验设备

PC机一台,BASYS 3 实验板一块,Xilinx Vivado 开发软件一套。

五、实验分析与设计

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

六、实验心得

这里写图片描述

七、代码

代码放的次序有点乱,实现模块的顺序可以参见我的实验过程设计,也就是第五部分!

// 顶层模块的实现
module Main(CLK, RST, outside_pc, ins, now_pc);
  input CLK, RST;
  input [31:0] outside_pc;
  output [31:0] ins, now_pc;
  parameter endReg = 5'b11111; // 31号寄存器

  // 数据通路
  wire [31:0] pc, pc0, pc4, i_IR, instruction, pcChoose3, pcChoose1, extendData, ALUResult, WriteData, ReadData1, ReadData2, DataOut;
  wire [31:0] o_ADR, o_BDR, o_ALUout, i_ALUM2DR,i_ALUData1,i_ALUData2;
  wire zero;
  // 控制信号
  wire [2:0] ALUOp;
  wire [1:0] ExtSel, RegDst, PCSrc;
  wire PCWre, IRWre, InsMemRW, WrRegData, RegWre, ALUSrcB, DataMemRW, DBDataSrc;

  // 数据选择输出
  wire [4:0] fiveChooseData;
  wire [31:0] InputWriteData1;

  // 引脚输出
  assign ins = instruction;
  assign now_pc = pc0;

  PC PC(CLK, pc, PCWre, RST, outside_pc, pc0); // 添加了外部pc
  PCAddFour PCAddFour(pc0, pc4);
  InstructionMEM InstructionMEM(pc0, InsMemRW, i_IR); // 添加了外部pc
  IR IR(i_IR, CLK, IRWre, instruction);
  PCJump PCJump(pc0, instruction[25:0], pcChoose3);
  DataSelector_3to1 DataSelector_3to1(endReg, instruction[20:16], instruction[15:11], RegDst, fiveChooseData);
  RegFile RegFile(instruction[25:21], instruction[20:16], fiveChooseData, WriteData, RegWre, CLK, ReadData1, ReadData2);
  ADR ADR(ReadData1, CLK, o_ADR);
  BDR BDR(ReadData2, CLK, o_BDR);
  SignExtend SignExtend(instruction[15:0], ExtSel, extendData);
  DataSelector_2to1_sa DataSelector_2to1_1(o_ADR, instruction[10:6] , ALUSrcA, i_ALUData1);
  DataSelector_2to1 DataSelector_2to1_2(o_BDR, extendData, ALUSrcB, i_ALUData2);
  ALU ALU(i_ALUData1, i_ALUData2, ALUOp, zero, ALUResult);
  ALUoutDR ALUoutDR(ALUResult, CLK, o_ALUout);
  DataMEM DataMEM(o_BDR, o_ALUout, DataMemRW, DataOut);
  DataSelector_2to1 DataSelector_2to1_3(ALUResult, DataOut, DBDataSrc, i_ALUM2DR);
  DBDR DBDR(i_ALUM2DR, CLK, InputWriteData1);
  DataSelector_2to1 DataSelector_2to1_4(pc4, InputWriteData1, WrRegData, WriteData);
  PCAddImm PCAddImm(pc4, extendData, pcChoose1);
  DataSelector_4to1 DataSelector_4to1(pc4, pcChoose1, ReadData1, pcChoose3, PCSrc, pc);
  ControlUnit ControlUnit(instruction[31:26], CLK, RST, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcA, ALUSrcB, DataMemRW, DBDataSrc, ExtSel, RegDst, PCSrc, ALUOp);
endmodule
// PC模块的实现
// @param clk 时钟信号
// @param pcWre信号
// @param reset信号
// @param i_pc 输入的pc值
// @param o_pc 输出的pc值
// @param outside_pc ???
module PC(clk, i_pc, pcWre, reset, outside_pc, o_pc);
  input wire clk, pcWre, reset;
  input wire [31:0] i_pc, outside_pc;
  output reg [31:0] o_pc;
  always @(pcWre or reset) begin // 这里和单周期不太一样,存在延迟的问题,只有当pcWre改变的时候或者reset改变的时候再检测
   // reset
    if (reset) begin
      o_pc = outside_pc;
    end else if (pcWre) begin
      o_pc = i_pc;
    end else if (!pcWre) begin 
        o_pc = o_pc;
     end
  end
endmodule
// 实现PC递增
// @param i_pc 输入的pc值
// @param o_pc 输出的pc值
module PCAddFour(i_pc, o_pc);
  input wire [31:0] i_pc;
  output wire [31:0] o_pc;
  
  • 30
    点赞
  • 200
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值