单周期ORI指令的实现

  • ORI指令说明
  • 单周期系统结构框图
  • 模块划分以及功能代码实现
    • 1. 宏定义define
    • 2. 取指pc
    • 3. 译码id
    • 4. 通用寄存器RegFile
    • 5. 执行ex
    • 6.访存mem
    • 7. 回写wb
    • 8 .顶模块OpenMIPS
    • 9 .指令存储器
    • 10 .最小SOPC实现
  • 测试模块以及仿真波形
  • 指令存储文件inst_rom.dat
  • 遇到的问题以及解决
    • 1. 仿真波形输错_1
    • 2. 仿真波形出错_2
    • 3. 顶层模块段端口定义
    • 4. 解决取操作数不准确

写在最前面,后续的一些指令我还在慢慢学,在这个框架上继续增加,有兴趣可以私信我,代码可以互相分享学习

ORI指令说明


这是一个I型指令,ORI指令的指令码为6’b00_1101
ORI指令作用:将16位立即数immediate进行无符号扩展至32位,然后与索引为rs的通用寄存器里的值进行“或”运算,运算结果保存到索引为rt的通用寄存器中
扩展1:立即数扩展

n位立即数扩展到3位。符号扩展是将n位立即数的最高为复制到扩展后的32位数据的高(32-n)位,无符号扩展是将扩展后的32位数据的高(32-n)位都置0
16位立即数: 0x8000、0x8000
符号扩展: 0xFFFF8000、0x00001000
无符号扩展: 0x00008000、0x00001000

扩展2:寄存器

MIPS架构定义了32个通用寄存器,使用$0、$1、…、%31表示,索引5位。其中%0一般用作常量0。

寄存器名字 约定命名 用途
$0 zero 总是为0
$1 at 留作汇编器生成一些合法指令
$2、$3 v0、v1 用来存放程序返回值
$4-$7 a0-a3 调用子程序时,使用这4个寄存器传输前4个非浮点参数
$8-$15 t0-t7 临时寄存器 、子程序使用时可以不用存储和恢复
$16-$23 s0-s7 子程序寄存器变量,改变这些寄存器值的子程序必须存储旧的值并在退出前恢复,对调用程序来说值不变
$24、$25 t7、t9 临时寄存器,子程序使用时可以不用存储和恢复
$26、$27 k 0 、 k0、 k0、k1 由异常处理程序使用
28 或 28或 28或gp gp 全局指针
29 或 29或 29或sp sp 堆栈指针
30 或 30或 30或fp fp 子程序可以用来作堆栈帧指针
$31 ra 存放程序返回地址

单周期系统结构框图

模块划分以及功能代码实现

1. 宏定义define

// *****************  全局的宏定义  ***************
`define RstEnable       1'b1          // 复位信号有效
`define RstDisable      1'b0          // 复位信号无效
`define ZeroWord        32'h00000000  // 32位的数值0
`define WriteEnable     1'b1          // 使能写
`define WriteDisable    1'b0          // 禁止写
`define ReadEnable      1'b1          // 使能读
`define ReadDisable     1'b0          // 禁止读
`define AluOpBus        7:0           // 译码阶段的输出aluop_o的宽度  子类型
`define AluSelBus       2:0           // 译码阶段的输出alusel_o的宽度 类型
`define InstValid       1'b0          // 指令有效
`define InstInvalid     1'b1          // 指令无效
`define True_v          1'b1          // 逻辑真
`define False_v         1'b0          // 逻辑假
`define ChipEnable      1'b1          // 芯片使能
`define ChipDisable     1'b0          // 芯片禁止// ***************  与具体指令有关的宏定义  ***************
`define EXE_ORI         6'b001101     // 指令ori的指令码
`define EXE_NOP         6'b000000     // //AluOp   子类型
`define EXE_OR_OP       8'b00100101   // or_func
`define EXE_NOP_OP      8'b00000000
//AluSel  类型
`define EXE_RES_LOGIC   3'b001        // 逻辑运算
`define EXE_RES_NOP     3'b000// ***************  与指令存储器ROM有关的宏定义  ***************
`define InstAddrBus     31:0          // ROM的地址总线宽度
`define InstBus         31:0          // ROM数的据总线宽度
`define InstMemNum      131071
`define InstMemNumLog2  17// **************  与通用寄存器Regfile有关的宏定义  ***************
`define RegAddrBus      4:0           // Regfile模块的地址线宽度
`define RegBus          31:0          // Regfile模块的数据线宽度
`define RegWidth        32
`define DoubleRegWidth  64
`define DoubleRegBus    63:0
`define RegNum          32            // 通用寄存器的数量
`define RegNumLog2      5             // 寻址通用寄存器使用的地址位数
`define NOPRegAddr      5'b00000

2. 取指pc

// 取出指令存储器中的指令、PC增值,准备取下一条指令
`include "defines.v"
module pc_reg (output  reg [`InstAddrBus]  pc,     // 要读取的指令地址output  reg                 ce,     // 指令存储器使能信号input   wire                clk,    // 时钟信号input   wire                rst     // 复位信号
);always @ (posedge clk) beginif (rst == `RstEnable) begince <= `ChipDisable;     // 复位的时候指令存储器禁用end else begince <= `ChipEnable;      // 复位结束后指令存储器使能endendalways @ (posedge clk) beginif (ce == `ChipDisable) beginpc <= 32'h00000000;        // 指令存储器禁用的时候,pc为0end else beginpc <= pc + 4'h4;        // 指令存储器使能的时候,pc值每时钟周期+4字节endendendmodule

3. 译码id

// 对指令进行译码,得到最终运算的类型、子类型、源操作数1、源操作数2、要写入的目的寄存器地址信息等
`include "defines.v"module id (// 输出到regfile的信息output  reg                   reg1_read_o,    // regfile模块第一个读寄存器端口的读使能信号output  reg                   reg2_read_o,    // regfile模块第二个读寄存器端口的读使能信号output  reg   [`RegAddrBus]   reg1_addr_o,    // regfile模块第一个读寄存器端口的读地址信号output  reg   [`RegAddrBus]   reg2_addr_o,    // regfile模块第二个读寄存器端口的读地址信号// 送到执行阶段的信息output  reg   [`AluOpBus]     aluop_o,        // 译码阶段的指令要进行的运算的子类型output  reg   [`AluSelBus]    alusel_o,       // 译码阶段的指令要进行的运算的类型output  reg   [`RegBus]       reg1_o,         // 译码阶段的指令要进行的运算的源操作数1output  reg   [`RegBus]       reg2_o,         // 译码阶段的指令要进行的运算的源操作数2output  reg   [`RegAddrBus]   wd_o,           // 译码阶段的指令要写入的目的寄存器地址output  reg                   wreg_o,         // 译码阶段的指令是否有要写入的目的寄存器input   wire                  rst,            // 复位input   wire  [`InstAddrBus]  pc_i,           // 译码阶段指令对应的地址input   wire  [`InstBus]      inst_i,         // 译码阶段的指令// 读取的regfile的值input   wire  [`RegBus]       reg1_data_i,    // 从regfile输入的第一个读寄存器端口的输出input   wire  [`RegBus]       reg2_data_i     // 从regfile输入的第一个读寄存器端口的输出
);// 取得指令的指令码,功能码// 对于ori指令只需通过判断26-31bits的值,即可判断是否是ori指令,6'b00_1101wire  [5:0]     op  = inst_i[31:26];    // 高6位决定具体操作wire  [4:0]     op2 = inst_i[10:6];     wire  [5:0]     op3 = inst_i[5:0];wire  [4:0]     op4 = inst_i[20:16];// 保存指令执行需要的立即数reg   [`RegBus] imm  // 指令指示是否有效reg             instvalid;// ****************************************************************************// **************************第一阶段:对指令进行译码******************************// ****************************************************************************always @ (*) beginif (rst == `RstEnable) beginaluop_o   <=  `EXE_NOP_OP;alusel_o  <=  `EXE_RES_NOP;wd_o      <=  `NOPRegAddr;      // 写入地址赋值为无效wreg_o    <=  `WriteDisable;    // 没有要写入的目的寄存器instvalid <=  `InstValid;       // 指令有效reg1_read_o <=  1'b0;reg2_read_o <=  1'b0;reg1_addr_o <=  `NOPRegAddr;reg2_addr_o <=  `NOPRegAddr;imm         <=  32'h0;end else beginaluop_o   <=  `EXE_NOP_OP;alusel_o  <=  `EXE_RES_NOP;wd_o      <=  inst_i[15:11];      // rd,目的寄存器编号wreg_o    <=  `WriteDisable; instvalid <=  `InstInvalid;       // 指令无效reg1_read_o <=  1'b0;reg2_read_o <=  1'b0;reg1_addr_o <=  inst_i[25:21];  // 默认通过regfile读端口1读取的寄存器地址,rs,源寄存器地址reg2_addr_o <=  inst_i[20:16];  // 默认通过regfile读端口2读取的寄存器地址,rt,源寄存器地址imm         <=  `ZeroWord;case (op)`EXE_ORI: begin               // 依据op的值判断指令是否为ori指令// ori指令需要将结果写入目的寄存器wreg_o      <=  `WriteEnable;// 运算子类型是逻辑'or'运算aluop_o     <=  `EXE_OR_OP;// 运算类型是逻辑运算alusel_o    <= `EXE_RES_LOGIC;// 需要通过regfile的读端口1读取寄存器reg1_read_o <=  `WriteEnable;// 不需要通过regfile的读端口2读取寄存器reg2_read_o <=  `WriteDisable;// 指令执行需要的立即数,无符号扩展imm         <=  {16'h0, inst_i[15:0]};// 指令执行要写的目的寄存器地址wd_o        <=  inst_i[20:16];// ori指令是有效指令instvalid   <=  `InstValid;enddefault: beginend  endcase // caseend //ifend //always// ****************************************************************************// ********************第二阶段:确定进行运算的操作数1 ******************************// ****************************************************************************   always @ (*) beginif (rst == `RstEnable) beginreg1_o  <=  `ZeroWord;end else if (reg1_read_o == 1'b1) beginreg1_o  <=  reg1_data_i;    // regfile读端口1的输出值end else if (reg1_read_o == 1'b0) beginreg1_o  <=  imm;            // 立即数end else beginreg1_o  <=  `ZeroWord;endend    // ****************************************************************************// ********************第三阶段:确定进行运算的操作数2 ******************************// ****************************************************************************   always @ (*) beginif (rst == `RstEnable) beginreg2_o  <=  `ZeroWord;end else if (reg2_read_o == 1'b1) beginreg2_o  <=  reg2_data_i;    // regfile读端口2的输出值end else if (reg2_read_o == 1'b0) beginreg2_o  <=  imm;            // 立即数end else beginreg2_o  <=  `ZeroWord;endend
endmodule

4. 通用寄存器RegFile

// 寄存器堆栈,实现了32个32位通用整数寄存器,可以同时进行两个寄存器的读操作和一个寄存器的写操作
`include   "defines.v"module regfile (// 写端口input   wire                  we,          // 写使能信号input   wire  [`RegAddrBus]   waddr,       // 要写入的寄存器地址input  reg   [`RegBus]       wdata,       // 要写入的数据// 读端口1input   wire                  re1,          // 第一个读寄存器端口读使能信号   input   wire  [`RegAddrBus]   raddr1,       // 第一个读寄存器端口要读取的寄存器的地址output  reg   [`RegBus]       rdata1,       // 第一个读寄存器端口输出的寄存器值// 读端口2input   wire                  re2,          // 第二个读寄存器端口读使能信号input   wire  [`RegAddrBus]   raddr2,       // 第二个读寄存器端口要读取的寄存器的地址output  reg   [`RegBus]       rdata2,       // 第二个读寄存器端口输出的寄存器值input   wire                  clk,input   wire                  rst
);// **********************第一阶段:定义32个32位寄存器************************
reg     [`RegBus]     regs[0:`RegNum-1];// **************************第二阶段:写操作******************************always @ (posedge clk) beginif (rst == `RstDisable) begin  // 复位信号无效if ((we ==`WriteEnable) && (waddr != `RegNumLog2'h0)) begin  // 写使能&&写目的寄存器≠$0regs[waddr] <= wdata;endendend// *************************第三阶段:读端口1的读操作******************************always @ (*) beginif (rst == `RstEnable) beginrdata1  <= `ZeroWord;     // 复位信号有效,输出0end else if (raddr1 == `RegNumLog2'h0) begin    // 读目的寄存器为$0,输出0rdata1  <= `ZeroWord;end else if (re1 == `ReadEnable) begin    // 输出要读取的目的寄存器地址对应的值rdata1  <= regs[raddr1];end else if ((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) begin    // 读目的寄存器是写目的寄存器&&写使能&&读使能,输出写入的值rdata1  <= wdata;end else beginrdata1  <= `ZeroWord;endend// *************************第四阶段:读端口2的读操作******************************always @ (*) beginif (rst == `RstEnable) beginrdata2  <= `ZeroWord;end else if (raddr2 == `RegNumLog2'h0) beginrdata2  <= `ZeroWord;end else if ((raddr2 == waddr) && (we == `WriteEnable) && (re2 == `ReadEnable)) beginrdata2  <= wdata;end else if (re2 == `ReadEnable) beginrdata2  <= regs[raddr2];end else beginrdata2  <= `ZeroWord;endend
endmodule/*
注:
读操作时组合逻辑电路,输入的要读取的寄存器地址raddr1和raddr2发生变化,立刻得到新地址对应的寄存器的值,这样可以保证在译码阶段取得要读取的寄存器的值
写操作时时序逻辑电路,发生在时钟上升沿
*/

5. 执行ex

// 从ID模块得到运算类型alusel_i、运算子类型aluse_i、源操作数reg1_i、源操作数reg2_i、要写入的目的寄存器地址wd_i
// EX模块依据这些数据进行运算
`include "defines.v"module ex (// 执行的结果output  reg   [`RegAddrBus]   wd_o,         // 最终要写入的目的寄存器地址output  reg                   wreg_o,       // 最终是否有要写入的目的寄存器output  reg   [`RegBus]       wdata_o,      // 最终要写入目的寄存器的值input   wire                  rst,// 译码阶段送到执行阶段的信息input   wire  [`AluOpBus]     aluop_i,      // 执行阶段运算子类型input   wire  [`AluSelBus]    alusel_i,     // 执行阶段运算类型input   wire  [`RegBus]       reg1_i,       // 执行阶段源操作数1input   wire  [`RegBus]       reg2_i,       // 执行阶段源操作数2input   wire  [`RegAddrBus]   wd_i,         // 执行阶段要写入的目的寄存器地址input   wire                  wreg_i        // 执行阶段是否有要写入的目的寄存器
);// 保存逻辑运算的结果reg   [`RegBus]   logicout;// ****************************************************************************// ***************第一阶段:依据aluop_i指示的运算子类型进行运算*********************// ****************************************************************************always @ (*) beginif (rst == `RstEnable) beginlogicout  <=  `ZeroWord;end else begincase (aluop_i)`EXE_OR_OP: beginlogicout  <=  reg1_i | reg2_i;enddefault:    beginlogicout  <=  `ZeroWord;endendcase // caseend // ifend // always// ****************************************************************************// **********第二阶段:依据alusel_i指示的运算类型,选择一个运算结果作为最终结果********// ****************************************************************************always @ (*) beginwd_o    <=  wd_i;     // 要写入的目的寄存器地址wreg_o  <=  wreg_i;   // 是否要写入目的寄存器case (alusel_i)`EXE_RES_LOGIC: beginwdata_o <=  logicout;   // wdata_o中存放运算结果enddefault:        beginwdata_o <=  `ZeroWord;endendcase // caseend // always  endmodule

6.访存mem

// mem访存模块
`include "defines.v"module mem (output  reg   [`RegAddrBus]   wd_o,     // 传到回写阶段的寄存器地址output  reg                   wreg_o,   // 是否有写入output  reg   [`RegBus]       wdata_o,  // 传到回写阶段的数据input   wire                  rst,input   wire  [`RegAddrBus]   wd_i,input   wire                  wreg_i,input   wire  [`RegBus]       wdata_i
);always @ (*) beginif (rst == `RstEnable) beginwd_o    <=  `NOPRegAddr;wreg_o  <=  `WriteDisable;wdata_o <=  `ZeroWord;end else beginwd_o    <=  wd_i;wreg_o  <=  wreg_i;wdata_o <=  wdata_i;endendendmodule

7. 回写wb

// 将输入的执行阶段的结果直接作为输出
`include "defines.v"module wb (// 访存阶段的结果output  reg   [`RegAddrBus]   wd_o,       // 访存阶段的指令最终要写入的目的寄存器地址output  reg                   wreg_o,     // 访存阶段的指令最终是否有要写入的目的寄存器output  reg   [`RegBus]       wdata_o,    // 访存阶段的指令最终要写入目的寄存器的值input   wire                  rst,// 来自执行阶段的信息input   wire  [`RegAddrBus]   wd_i,input   wire                  wreg_i,input   wire  [`RegBus]       wdata_i
);always @ (*) beginif (rst == `RstEnable) beginwd_o    <=  `NOPRegAddr;wreg_o  <=  `WriteDisable;wdata_o <=  `ZeroWord;end else beginwd_o    <=  wd_i;wreg_o  <=  wreg_i;wdata_o <=  wdata_i;endendendmodule

8 .顶模块OpenMIPS

// 顶层模块
`include "defines.v"module openmips (output  wire    [`RegBus]   rom_addr_o,     // 输出到指令存储器的地址output  wire                rom_ce_o,       // 指令寄存器使能信号input   wire    [`RegBus]   rom_data_i,     // 从指令寄存器取得的指令input   wire                rst,input   wire                clk
);// ****************************************************************************// **************************第一阶段:物理连线声明******************************// **************************************************************************** // 连接ID模块和EX模块输入的变量wire  [`AluOpBus]     id_aluop;wire  [`AluSelBus]    id_alusel;wire  [`RegBus]       id_reg1;wire  [`RegBus]       id_reg2;wire                  id_wreg;wire  [`RegAddrBus]   id_wd;// 连接译码阶段ID模块和通用寄存器Regfile模块的变量wire                  reg1_read;wire                  reg2_read;wire  [`RegBus]       reg1_data;wire  [`RegBus]       reg2_data;wire  [`RegAddrBus]   reg1_addr;wire  [`RegAddrBus]   reg2_addr;// 连接EX模块输出和MEM模块的变量wire  [`RegAddrBus]   ex_wd;wire                  ex_wreg;wire  [`RegBus]       ex_wdata;  // 连接MEM模块输出和WB模块的变量wire  [`RegAddrBus]   mem_wd;wire                  mem_wreg;wire  [`RegBus]       mem_wdata;// 连接WB模块和RegFIle模块输入的变量wire  [`RegAddrBus]   wb_wd;wire                  wb_wreg;wire  [`RegBus]       wb_wdata;// ****************************************************************************// **********************第二阶段:对各个模块进行实例化*****************************// ****************************************************************************// pc_reg例化pc_reg  pc_reg0 (.pc(rom_addr_o), .ce(rom_ce_o),.clk(clk), .rst(rst));// 译码阶段ID模块例化id      id0 (// 送到RegFile模块的信息.reg1_read_o(reg1_read), .reg2_read_o(reg2_read),.reg1_addr_o(reg1_addr), .reg2_addr_o(reg2_addr),// 送到EX模块的信息.aluop_o(id_aluop), .alusel_o(id_alusel),.reg1_o(id_reg1), .reg2_o(id_reg2),.wd_o(id_wd), .wreg_o(id_wreg),.rst(rst), .pc_i(rom_addr_o), .inst_i(rom_data_i),// 来自RegFile模块的输出.reg1_data_i(reg1_data), .reg2_data_i(reg2_data));// 通用寄存器Regfile模块例化regfile regfile0 (.we(wb_wreg), .waddr(wb_wd), .wdata(wb_wdata),.re1(reg1_read), .raddr1(reg1_addr), .rdata1(reg1_data),.re2(reg2_read), .raddr2(reg2_addr), .rdata2(reg2_data),.clk(clk), .rst(rst));// EX模块例化ex      ex0 (// 输出到MEM模块的信息.wd_o(ex_wd), .wreg_o(ex_wreg), .wdata_o(ex_wdata),.rst(rst),// 从ID模块传递过来的信息.aluop_i(id_aluop), .alusel_i(id_alusel),.reg1_i(id_reg1), .reg2_i(id_reg2),.wd_i(id_wd), .wreg_i(id_wreg));// MEM模块例化mem     mem0 (// 输出到WB模块的信息.wd_o(mem_wd), .wreg_o(mem_wreg), .wdata_o(mem_wdata),.rst(rst),// 从EX模块接收到的信息.wd_i(ex_wd), .wreg_i(ex_wreg), .wdata_i(ex_wdata));// WB模块例化wb     wb0 (// 输出的信息.wd_o(wb_wd), .wreg_o(wb_wreg), .wdata_o(wb_wdata),.rst(rst),// 从EX模块接收到的信息.wd_i(ex_wd), .wreg_i(ex_wreg), .wdata_i(ex_wdata));endmodule

9 .指令存储器

// 指令存储器ROM模块
`include "defines.v"module inst_rom (output  reg   [`InstBus]      inst,     // 读出的指令input   wire                  ce,       // 使能信号input   wire  [`InstAddrBus]  addr      // 要读取的指令地址
);// 定义一个数组,大小是InstMemNum(131071),元素宽度是InstBusreg   [`InstBus]    inst_mem[0:`InstMemNum-1];// 使用文件inst_rom.data初始化指令存储器initial $readmemh ("inst_rom.dat", inst_mem);// 当复位信号无效时,依据输入的地址,给出指令存储器ROM中对应的元素always @ (*) beginif (ce == `ChipDisable) begininst   = `ZeroWord;end else begininst  <= inst_mem[addr[`InstMemNumLog2+1:2]];    // inst_mem[addr[5+1:2]]  endendendmodule

10 .最小SOPC实现

// 最小SOPC模块,仅包括OpenMIPS和指令存储器ROM,例化处理这个两个模块
`include "defines.v"module OpenMIPS_min_SOPC (input wire    clk,input wire    rst
);// 连接指令存储器wire  [`InstAddrBus]    inst_addr;wire  [`InstBus]        inst;wire                    rom_ce;// 例化处理器OpenMIPSopenmips  openmips0 (.rom_addr_o(inst_addr), .rom_ce_o(rom_ce),.rom_data_i(inst),.clk(clk), .rst(rst));// 例化指令存储器inst_rom  inst_rom0 (.inst(inst),.ce(rom_ce), .addr(inst_addr));endmodule

测试模块以及仿真波形

// testbench of "OpenMIPS_mini_SOPC_tb"
`include "defines.v"module OpenMIPS_min_SOPC_tb ();reg   clk;reg   rst;module OpenMIPS_min_SOPC_tb ();reg   clk;reg   rst;// 例化最小SOPCOpenMIPS_min_SOPC OpenMIPS_min_SOPC0 (.clk(clk), .rst(rst));initial beginclk = 1'b0;endalways #10 clk = ~clk; // 最初时刻,复位信号有效,在第195ns,复位信号无效,最小SOPC开始运行initial beginrst = `RstEnable;#195  rst = `RstDisable;
//    #1000 $stop;endendmodule



指令存储文件inst_rom.dat

记事本中存放数据:

34011100 // $1 = 0000_0000 | 0000_1100 = 0000_1100
34020020 // $2 = 0000_0000 | 0000_0020 = 0000_0020
3403ff00 // $3 = 0000_0000 | 0000_ff00 = 0000_ff00
3404ffff // $4 = 0000_0000 | 0000_ffff = 0000_ffff
34210020 // $1 = 0000_1100 | 0000_0020 = 0000_1120
34214400 // $1 = 0000_1120 | 0000_4400 = 0000_5520
34210044 // $1 = 0000_5520 | 0000_0040 = 0000_5564

------------------------------------------------------------------------------------------------------------------------------------------------------

遇到的问题以及解决

1. 仿真波形输错_1

  • 这里的reg1在执行完第五个周期时变为不定值是什么原因?

修改所有错误后,reg1_i等信号在第五个周期变为不定值都得到纠正

  • 有部分仿真波形从始至终都是蓝色直线?

在openmips.v中的实例化中端口对应没有匹配好,已修改,蓝线消失
ex ex0 (
.wreg_i(id_wreg),
// 错误代码:.wreg_i(ex_wreg),
);

2. 仿真波形出错_2

  • sim:/OpenMIPS_min_SOPC_tb/OpenMIPS_min_SOPC0/openmips0/wb_wdata 和sim:/OpenMIPS_min_SOPC_tb/OpenMIPS_min_SOPC0/openmips0/regfile0/wdata 两条仿真波形始终都是红色直线?

对于没有初始化的信号,输入信号为高阻态蓝线(Z),输出信号为不定态红线(X)
regfile.v模块中的信号输入输出没有定义好,已修改,红线消失
module regfile (
input reg ['RegBus] wdata, // 要写入的数据
// 错误代码:output reg ['RegBus] wdata,
);

3. 顶层模块段端口定义

两个输出信号rom_addr_o、rom_ce_o需要定义成wire。定义成reg会报错,编译可通过,仿真不通过。代码已修改

4. 解决取操作数不准确

指令5开始,rdata1本应该从寄存器$1读出上次写入的数据0x0000_1100,因为读写地址都相同,同时满足regfile.v中的读端口1读数据的结果值,实际读出指令5的执行结果0x0000_1120(0x0000_0000 ori ox0000_0020)
流水添加的是数据前推端口,没有这种困扰

解决方法1:
regfile.v读端口1模块使用if-case分支,顺序执行,交换分支顺序,优先判断是否从寄存器直接取到源操作数。当读写地址相同时,两个else都满足,但实际我们想要的是从寄存器中读出来的数据,为了防止被"被短路",需要交换顺序,先判断是否从寄存器取数

解决方法2:
在EX模块新添加寄存器模块reg [`RegBus] result;连线到regfile.v模块
若想实现,必须添加在指定位置。
(太乱了,实在看不懂为什么都是哪些值,只能保证正确的值存在result中,但其他信号还会有取错的,我投降)


2021/05/09
再回来看看读取操作数不正确的原因,方法1看不懂,方法2当时跑通测试,但是没有写笔记…
救命,以后我一定好好写笔记,尽量不省略
我还写的没有这种困扰…现在都不知道是啥困扰了,还别说解决

.
.
.
会了
这里是单周期

// *************************第三阶段:读端口1的读操作******************************always @ (*) beginif (rst == `RstEnable) beginrdata1  <= `ZeroWord;     // 复位信号有效,输出0end else if (raddr1 == `RegNumLog2'h0) begin    // 读目的寄存器为$0,输出0rdata1  <= `ZeroWord;end else if (re1 == `ReadEnable) begin            // 输出要读取的目的寄存器地址对应的值rdata1  <= regs[raddr1];end else if ((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) begin    // 读目的寄存器是写目的寄存器&&写使能&&读使能,输出写入的值rdata1  <= wdata;end else beginrdata1  <= `ZeroWord;endend// *************************第四阶段:读端口2的读操作******************************always @ (*) beginif (rst == `RstEnable) beginrdata2  <= `ZeroWord;end else if (raddr2 == `RegNumLog2'h0) beginrdata2  <= `ZeroWord;end else if ((raddr2 == waddr) && (we == `WriteEnable) && (re2 == `ReadEnable)) beginrdata2  <= wdata;end else if (re2 == `ReadEnable) beginrdata2  <= regs[raddr2];end else beginrdata2  <= `ZeroWord;endend
endmodule

这是交换后的代码,只需要交换读端口1的操作。因为指令如果是寄存器和立即数进行运算,默认通过读端口1读取寄存器数据
因为是单周期,在一个节拍下就要进行取数、执行、回写,交换之后就能保证,读取的数据是之前写入寄存器的数据,而不是本条指令执行后的运算结果。

流水线我也忘了需不需要处理这个读数据错误

自己动手写CPU——单周期ORI指令的实现相关推荐

  1. 【自己动手写CPU】第一条指令ori的实现

    验证过程 实现ori指令->建立最小SOPC->验证ori指令是否正确 ori指令说明 ori是进行逻辑"或"的运算指令 ori指令的指令码是6'b001101.处理器 ...

  2. 【自己动手写CPU】异常相关指令的实现

    MIPS架构中定义的异常类型 MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断.陷阱.系统调用以及其他打断程序执行流程的情况,统称为异常. 此处的OpenMIPS处理器只实现了其 ...

  3. 自己动手写CPU(5)简单算术操作指令实现_1

    自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...

  4. 自己动手写CPU(2)第一条ori指令

    本博客内容基于<自己动手写CPU>这本书 上一篇文章介绍了一下流水线思想.设计流程等,下面我们可以实操一下实现第一条ori指令. 其实实现一条ori指令不难,我目前对这一条指令的理解简单来 ...

  5. 自己动手写CPU(1)五级流水线及CPU第一条指令ori

    自己动手写CPU(1)五级流水线及CPU第一条指令ori 动机 不知为何研一的自由时间突然多起来,可能人一闲下来就容易焦虑吧,hhhhhh.正好之前看到一本<自己动手写CPU>,就按照此书 ...

  6. 自己动手写CPU(3)逻辑、移位操作与空指令

    自己动手写CPU(3)逻辑.移位操作与空指令 指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条: and.andi.or.ori.xor.xori.nor.lui,其中 ori指令已经实现. ...

  7. 自己动手写CPU(8)加载存储指令的实现

    自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...

  8. 自己动手写CPU(4)移动操作指令的实现

    自己动手写CPU(4)移动操作指令的实现 指令说明 MIPS32指令集架构中定义的移动操作指令共有6条: movn.movz.mfhi.mthi.mflo.mtlo,后4条指令涉及对特殊寄存器HI.L ...

  9. 自己动手写CPU之第九阶段(2)——加载存储指令说明2(lwl、lwr)

    将陆续上传新书<自己动手写CPU>,今天是第38篇,我尽量每周四篇,但是最近已经很久没有实现这个目标了,一直都有事,不好意思哈. 开展晒书评送书活动,在亚马逊.京东.当当三大图书网站上,发 ...

最新文章

  1. 谁说双非本科就一定无缘阿里?H哥粉丝刚刚6面通过,喜得Offer!
  2. html树形多选下拉列表,EasyUI 多行树形下拉框(Multiple ComboTree)_Vue EasyUI Demo
  3. java is alphabetic_JDK之Pattern类探索(一)
  4. keras添加正则化全连接_第16章 Keras使用Dropout正则化防止过拟合
  5. 云计算实战系列十四(MySQL基础)
  6. Java安全之数字证书
  7. windows 10无法安装virtualbox的解决方法
  8. Android 灯光系统开发
  9. 浅析pc机上如何将vmlinuz-2.6.31-14-generic解压出vmlinux
  10. 解决EXE文件无法打开的问题!
  11. js日历控件html,第11款插件:jquery.jCal.js显示日历插件
  12. 深耕企业组网 H3C企业主网交换机评测
  13. 【MATLAB】基于油猴脚本和MATLAB下载原创力文档
  14. 解决wordcloud导出图片不清楚
  15. Android界面 Html5还是Native,说说他们的各自的优缺点。
  16. 拯救中国传统文化教育
  17. 【Machine Learning, Coursera】机器学习Week6 偏斜数据集的处理
  18. 关于如何通过信息系统监理师的自我心得
  19. 实战项目:设计实现一个流程编排框架(实现)
  20. 助力苏州工业园区从“平民公交”转向“全民公交” ⑤

热门文章

  1. 鸿蒙系统王者荣耀能转区吗,王者荣耀跨系统转区开放!详细问答汇总,解决全部转区疑惑!...
  2. linux raw 分区 读取,在linux上使用raw device方式
  3. android 1g运行内存不足,内存不足每隔一次运行,在Android上
  4. 中国美术家协会吴冬梅的工笔人生
  5. verilog偶校验码实现
  6. 准滑动模态的滑模控制(几种替代sgn(⋅)的函数)
  7. Unity 音频管理框架
  8. 解决mac系统下无法手动设置ip的问题
  9. 这10大专业读研比考研还辛苦!有你的目标专业吗?​
  10. 榕树•梧桐•刺槐——城市的植物意象