【【深入浅出TinyRisc-v】】

发布于:2025-02-11 ⋅ 阅读:(75) ⋅ 点赞:(0)

深入浅出TinyRisc-v

本代码参考于 https://gitee.com/liangkangnan/tinyriscv 自己理解之后又重新写了一遍

tinyriscv.v

// 涓嬮潰鏄鏁翠釜top妯″潡鐨勪功鍐?
module  tinyriscv(
    input                     clk             ,
    input                     rst_n           ,
    //澶栬鐨勪俊鎭鍙?
    input       [31 : 0]      rib_ex_data_i   , // 浠庡璁捐鍙栫殑鏁版嵁
    output      [31 : 0]      rib_ex_addr_o   , // 璇诲啓澶栬鐨勫湴鍧?
    output      [31 : 0]      rib_ex_data_o   , // 鍐欏叆澶栬鐨勬暟鎹?
    output                    rib_ex_req_o    ,
    output                    rib_ex_we_o     ,

    // 鍙栨寚浠? 浠? ROM涓?
    input       [31 : 0]      rib_pc_data_i   ,
    output      [31 : 0]      rib_pc_addr_o   ,  // 鍙栨寚鍦板潃

    // jtag浜や簰鐨勬帴鍙?
    input       [4  : 0]      jtag_reg_addr_i ,   // jtag妯″潡璇汇?佸啓瀵勫瓨鍣ㄧ殑鍦板潃 4:0
    input       [31 : 0]      jtag_reg_data_i ,       // jtag妯″潡鍐欏瘎瀛樺櫒鏁版嵁 31 : 0
    input                     jtag_reg_we_i   ,                  // jtag妯″潡鍐欏瘎瀛樺櫒鏍囧織
    output      [31 : 0]      jtag_reg_data_o ,      // jtag妯″潡璇诲彇鍒扮殑瀵勫瓨鍣ㄦ暟鎹?

    input                     rib_hold_flag_i    ,                // 鎬荤嚎鏆傚仠鏍囧織
    input                     jtag_halt_flag_i   ,               // jtag鏆傚仠鏍囧織
    input                     jtag_reset_flag_i  ,              // jtag澶嶄綅PC鏍囧織

    input       [7  : 0]      int_i                 // 涓柇淇″彿 7:0
  );


  // -------------------------------------------------------- //
  //           internal signal  and deffine                  //
  // -----------------------------------------------------  //

  wire   [31 : 0]   pc_pc_o  ;
  assign    rib_pc_addr_o   =  pc_pc_o  ;  // 杩欐槸鍙栨寚浠ゅ湴鍧?
  wire   [2  : 0]   ctrl_hold_flag_o    ;
  wire              ctrl_jump_flag_o    ;
  wire   [31 : 0]   ctrl_jump_addr_o    ;
  wire   [7  : 0]   if_int_flag_o       ;
  wire   [31 : 0]   if_inst_o           ;
  wire   [31 : 0]   if_inst_addr_o      ;

  wire   [31 : 0]   regs_rdata1_o       ;
  wire   [31 : 0]   regs_rdata2_o       ;

  wire   [4  : 0]   id_reg1_raddr_o     ;
  wire   [4  : 0]   id_reg2_raddr_o     ;
  wire   [31 : 0]   id_inst_o           ;
  wire   [31 : 0]   id_inst_addr_o      ;
  wire   [31 : 0]   id_reg1_rdata_o     ;
  wire   [31 : 0]   id_reg2_rdata_o     ;
  wire              id_reg_we_o         ;
  wire   [4  : 0]   id_reg_waddr_o      ;
  wire   [31 : 0]   id_csr_raddr_o      ;
  wire              id_csr_we_o         ;
  wire   [31 : 0]   id_csr_rdata_o      ;
  wire   [31 : 0]   id_csr_waddr_o      ;
  wire   [31 : 0]   id_op1_o            ;
  wire   [31 : 0]   id_op2_o            ;
  wire   [31 : 0]   id_op1_jump_o       ;
  wire   [31 : 0]   id_op2_jump_o       ;

  // id_ex妯″潡杈撳嚭淇″彿
  wire   [31 : 0]   ie_inst_o           ;
  wire   [31 : 0]   ie_inst_addr_o      ;
  wire              ie_reg_we_o         ;
  wire   [4 : 0]    ie_reg_waddr_o      ;
  wire   [31 : 0]   ie_reg1_rdata_o     ;
  wire   [31 : 0]   ie_reg2_rdata_o     ;
  wire              ie_csr_we_o         ;
  wire   [31 : 0]   ie_csr_waddr_o      ;
  wire   [31 : 0]   ie_csr_rdata_o      ;
  wire   [31 : 0]   ie_op1_o            ;
  wire   [31 : 0]   ie_op2_o            ;
  wire   [31 : 0]   ie_op1_jump_o       ;
  wire   [31 : 0]   ie_op2_jump_o       ;

  // ex妯″潡杈撳嚭淇″彿
  wire   [31 : 0]   ex_mem_wdata_o      ;
  wire   [31 : 0]   ex_mem_raddr_o      ;
  wire   [31 : 0]   ex_mem_waddr_o      ;
  wire              ex_mem_we_o         ;
  wire              ex_mem_req_o        ;
  wire   [31 : 0]   ex_reg_wdata_o      ;
  wire              ex_reg_we_o         ;
  wire   [4 : 0]   ex_reg_waddr_o      ;
  wire              ex_hold_flag_o      ;
  wire              ex_jump_flag_o      ;
  wire   [31 : 0]   ex_jump_addr_o      ;
  wire              ex_div_start_o      ;
  wire   [31 : 0]   ex_div_dividend_o   ;
  wire   [31 : 0]   ex_div_divisor_o    ;
  wire   [2  : 0]   ex_div_op_o         ;
  wire   [4  : 0]   ex_div_reg_waddr_o  ;
  wire   [31 : 0]   ex_csr_wdata_o      ;
  wire              ex_csr_we_o         ;
  wire   [31 : 0]   ex_csr_waddr_o      ;

  wire   [31 : 0]   csr_data_o          ;
  wire   [31 : 0]   csr_clint_data_o    ;
  wire              csr_global_int_en_o ;
  wire   [31 : 0]   csr_clint_csr_mtvec ;
  wire   [31 : 0]   csr_clint_csr_mepc  ;
  wire   [31 : 0]   csr_clint_csr_mstatus;


  wire   [31 : 0]   div_result_o        ;
  wire              div_ready_o         ;
  wire              div_busy_o          ;
  wire   [4  : 0]   div_reg_waddr_o     ;

  wire              clint_we_o          ;
  wire   [31 : 0]   clint_waddr_o       ;
  wire   [31 : 0]   clint_raddr_o       ;
  wire   [31 : 0]   clint_data_o        ;
  wire   [31 : 0]   clint_int_addr_o    ;
  wire              clint_int_assert_o  ;
  wire              clint_hold_flag_o   ;


  assign rib_ex_addr_o = (ex_mem_we_o == 1)? ex_mem_waddr_o: ex_mem_raddr_o;
  assign rib_ex_data_o = ex_mem_wdata_o   ;
  assign rib_ex_req_o  = ex_mem_req_o     ;
  assign rib_ex_we_o   = ex_mem_we_o      ;









  // -----------------------------------------------------  //
  //               渚嬪寲 浠嬬粛                                 //
  // -----------------------------------------------------  //

  pc_reg u_pc_reg(
           .clk                ( clk                ),
           .rst_n              ( rst_n              ),
           .jtag_reset_flag_i(jtag_reset_flag_i),
           .pc_o(pc_pc_o),
           .hold_flag_i(ctrl_hold_flag_o),
           .jump_flag_i(ctrl_jump_flag_o),
           .jump_addr_i(ctrl_jump_addr_o)
         );


  // 鎸夐『搴忎笅涓?涓槸 if_id
  if_id u_if_id(
          .clk          ( clk          ),
          .rst_n        ( rst_n        ),
          .inst_i(rib_pc_data_i),
          .inst_addr_i(pc_pc_o),
          .int_flag_i(int_i),
          .int_flag_o(if_int_flag_o),
          .hold_flag_i(ctrl_hold_flag_o),
          .inst_o(if_inst_o),
          .inst_addr_o(if_inst_addr_o)
        );

  //鎺ヤ笅鏉ユ槸 id妯″潡
  id u_id(
       .rst_n         ( rst_n         ),
       .inst_i(if_inst_o),
        .inst_addr_i(if_inst_addr_o),
        .reg1_rdata_i(regs_rdata1_o),
        .reg2_rdata_i(regs_rdata2_o),
       
        .reg1_raddr_o(id_reg1_raddr_o),
        .reg2_raddr_o(id_reg2_raddr_o),
        .inst_o(id_inst_o),
        .inst_addr_o(id_inst_addr_o),
        .reg1_rdata_o(id_reg1_rdata_o),
        .reg2_rdata_o(id_reg2_rdata_o),
        .reg_we_o(id_reg_we_o),
        .reg_waddr_o(id_reg_waddr_o),
        .op1_o(id_op1_o),
        .op2_o(id_op2_o),
        .op1_jump_o(id_op1_jump_o),
        .op2_jump_o(id_op2_jump_o),
        .csr_rdata_i(csr_data_o),
        .csr_raddr_o(id_csr_raddr_o),
        .csr_we_o(id_csr_we_o),
        .csr_rdata_o(id_csr_rdata_o),
        .csr_waddr_o(id_csr_waddr_o)
     );
  // 杩欓噷闈㈠苟娌℃湁鍗忓晢ex_jump_flag

  // 鐢ㄧ殑鏄? id_ex
  id_ex u_id_ex(
          .clk(clk                      ),
          .rst_n(rst_n                  ),
          .inst_i(id_inst_o),
          .inst_addr_i(id_inst_addr_o),
          .reg_we_i(id_reg_we_o),
          .reg_waddr_i(id_reg_waddr_o),
          .reg1_rdata_i(id_reg1_rdata_o),
          .reg2_rdata_i(id_reg2_rdata_o),
          .hold_flag_i(ctrl_hold_flag_o),
          .inst_o(ie_inst_o),
          .inst_addr_o(ie_inst_addr_o),
          .reg_we_o(ie_reg_we_o),
          .reg_waddr_o(ie_reg_waddr_o),
          .reg1_rdata_o(ie_reg1_rdata_o),
          .reg2_rdata_o(ie_reg2_rdata_o),
          .op1_i(id_op1_o),
          .op2_i(id_op2_o),
          .op1_jump_i(id_op1_jump_o),
          .op2_jump_i(id_op2_jump_o),
          .op1_o(ie_op1_o),
          .op2_o(ie_op2_o),
          .op1_jump_o(ie_op1_jump_o),
          .op2_jump_o(ie_op2_jump_o),
          .csr_we_i(id_csr_we_o),
          .csr_waddr_i(id_csr_waddr_o),
          .csr_rdata_i(id_csr_rdata_o),
          .csr_we_o(ie_csr_we_o),
          .csr_waddr_o(ie_csr_waddr_o),
          .csr_rdata_o(ie_csr_rdata_o)
        );

  // ex妯″潡

  ex u_ex(
       .rst_n(rst_n ),
       .inst_i(ie_inst_o),
       .inst_addr_i(ie_inst_addr_o),
       .reg_we_i(ie_reg_we_o),
       .reg_waddr_i(ie_reg_waddr_o),
       .reg1_rdata_i(ie_reg1_rdata_o),
       .reg2_rdata_i(ie_reg2_rdata_o),
       .op1_i(ie_op1_o),
       .op2_i(ie_op2_o),
       .op1_jump_i(ie_op1_jump_o),
       .op2_jump_i(ie_op2_jump_o),
       .mem_rdata_i(rib_ex_data_i),
       .mem_wdata_o(ex_mem_wdata_o),
       .mem_raddr_o(ex_mem_raddr_o),
       .mem_waddr_o(ex_mem_waddr_o),
       .mem_we_o(ex_mem_we_o),
       .mem_req_o(ex_mem_req_o),
       .reg_wdata_o(ex_reg_wdata_o),
       .reg_we_o(ex_reg_we_o),
       .reg_waddr_o(ex_reg_waddr_o),
       .hold_flag_o(ex_hold_flag_o),
       .jump_flag_o(ex_jump_flag_o),
       .jump_addr_o(ex_jump_addr_o),
       .int_assert_i(clint_int_assert_o),
       .int_addr_i(clint_int_addr_o),
       .div_ready_i(div_ready_o),
       .div_result_i(div_result_o),
       .div_busy_i(div_busy_o),
       .div_reg_waddr_i(div_reg_waddr_o),
       .div_start_o(ex_div_start_o),
       .div_dividend_o(ex_div_dividend_o),
       .div_divisor_o(ex_div_divisor_o),
       .div_op_o(ex_div_op_o),
       .div_reg_waddr_o(ex_div_reg_waddr_o),
       .csr_we_i(ie_csr_we_o),
       .csr_waddr_i(ie_csr_waddr_o),
       .csr_rdata_i(ie_csr_rdata_o),
       .csr_wdata_o(ex_csr_wdata_o),
       .csr_we_o(ex_csr_we_o),
       .csr_waddr_o(ex_csr_waddr_o)
     );


  ctrl u_ctrl(
         .jump_flag_i(ex_jump_flag_o),
         .jump_addr_i(ex_jump_addr_o),
         .hold_flag_ex_i(ex_hold_flag_o),
         .hold_flag_rib_i(rib_hold_flag_i),
         .hold_flag_o(ctrl_hold_flag_o),
         .hold_flag_clint_i(clint_hold_flag_o),
         .jump_flag_o(ctrl_jump_flag_o),
         .jump_addr_o(ctrl_jump_addr_o),
         .jtag_halt_flag_i(jtag_halt_flag_i)
       );

  regs u_regs(
         .clk(clk),
         .rst_n(rst_n),
         .we_i(ex_reg_we_o),
         .waddr_i(ex_reg_waddr_o),
         .wdata_i(ex_reg_wdata_o),
         .raddr1_i(id_reg1_raddr_o),
         .rdata1_o(regs_rdata1_o),
         .raddr2_i(id_reg2_raddr_o),
         .rdata2_o(regs_rdata2_o),
         .jtag_we_i(jtag_reg_we_i),
         .jtag_addr_i(jtag_reg_addr_i),
         .jtag_data_i(jtag_reg_data_i),
         .jtag_data_o(jtag_reg_data_o)
       );


  csr_reg u_csr_reg(
            .clk(clk),
            .rst_n(rst_n),
            .we_i(ex_csr_we_o),
            .raddr_i(id_csr_raddr_o),
            .waddr_i(ex_csr_waddr_o),
            .data_i(ex_csr_wdata_o),
            .data_o(csr_data_o),
            .global_int_en_o(csr_global_int_en_o),
            .clint_we_i(clint_we_o),
            .clint_raddr_i(clint_raddr_o),
            .clint_waddr_i(clint_waddr_o),
            .clint_data_i(clint_data_o),
            .clint_data_o(csr_clint_data_o),
            .clint_csr_mtvec(csr_clint_csr_mtvec),
            .clint_csr_mepc(csr_clint_csr_mepc),
            .clint_csr_mstatus(csr_clint_csr_mstatus)
          );


  div u_div(
        .clk(clk),
        .rst_n(rst_n),
        .dividend_i(ex_div_dividend_o),
        .divisor_i(ex_div_divisor_o),
        .start_i(ex_div_start_o),
        .op_i(ex_div_op_o),
        .reg_waddr_i(ex_div_reg_waddr_o),
        .result_o(div_result_o),
        .ready_o(div_ready_o),
        .busy_o(div_busy_o),
        .reg_waddr_o(div_reg_waddr_o)
      );

  clint u_clint(
          .clk(clk),
          .rst_n(rst_n),
          .int_flag_i(if_int_flag_o),
          .inst_i(id_inst_o),
          .inst_addr_i(id_inst_addr_o),
          .jump_flag_i(ex_jump_flag_o),
          .jump_addr_i(ex_jump_addr_o),
          .div_started_i(ex_div_start_o),
          .csr_mtvec(csr_clint_csr_mtvec),
          .csr_mepc(csr_clint_csr_mepc),
          .csr_mstatus(csr_clint_csr_mstatus),
          .we_o(clint_we_o),
          .waddr_o(clint_waddr_o),
          .raddr_o(clint_raddr_o),
          .data_o(clint_data_o),
          .hold_flag_o(clint_hold_flag_o),
          .global_int_en_i(csr_global_int_en_o),
          .int_addr_o(clint_int_addr_o),
          .int_assert_o(clint_int_assert_o)
        );

endmodule

pc_reg.v

// PC寄存器模块
module  pc_reg(
    input   wire            clk                ,
    input   wire            rst_n              ,  // 低电平复位

    input   wire            jump_flag_i        ,  // 跳转标志
    input   wire  [31:0]    jump_addr_i        ,  // 跳转地址
    input   wire  [2 :0]    hold_flag_i        ,  // 流水线暂停标志
    input   wire            jtag_reset_flag_i  ,  // 复位标志

    output  reg   [31:0]    pc_o
  );

  always@(posedge clk )
  begin
    // 复位
    if(rst_n == 0 || jtag_reset_flag_i == 1)
    begin
      pc_o  <= 32'h0 ;
    end
    else if(jump_flag_i == 1)
    begin
      pc_o  <= jump_addr_i  ;
    end
    else if(hold_flag_i >= 3'b001 )
    begin
      pc_o  <= pc_o ; // 这就是暂停保持的
    end
    else
    begin
      pc_o <= pc_o + 4'h4 ;
    end
  end
endmodule

if_id.v

// 将指令向译码模块传递
module if_id(
    input    wire             clk          ,
    input    wire             rst_n        ,

    input    wire   [31 : 0]  inst_i       ,
    output   wire   [31 : 0]  inst_o       ,

    input    wire   [31 : 0]  inst_addr_i  , 
    output    wire   [31 : 0]  inst_addr_o  ,  

    input    wire   [2  : 0]  hold_flag_i  ,

    input    wire   [7  : 0]  int_flag_i   ,    // 外设中断输入信号 
    output   wire   [7  : 0]  int_flag_o   
);

wire  hold_en = (hold_flag_i > 3'b010)     ; // 这里的和前面一样的控制信息 hold_IF 

wire [31 : 0]  inst       ; 
wire [31 : 0]  inst_addr  ; 
wire [7  : 0]  int_flag   ;  
 
gen_pipe_dff#(
    .DW       ( 32 )
)inst_ff(
    .clk      ( clk      ),
    .rst_n    ( rst_n    ),
    .hold_en  ( hold_en  ),
    .def_val  ( 32'h00000001  ),   // 其实我不懂默认的为什么要设置这个指令内容 1 我就设置成0 
    .din      ( inst_i       ),
    .qout     ( inst     )
);
assign  inst_o = inst ; 


gen_pipe_dff#(
    .DW       ( 32 )
)inst_addr_ff(
    .clk      ( clk      ),
    .rst_n    ( rst_n    ),
    .hold_en  ( hold_en  ),
    .def_val  ( 32'h0  ),       // 这里是 指令地址0 
    .din      ( inst_addr_i      ),
    .qout     ( inst_addr     )
);
assign  inst_addr_o = inst_addr  ;  

gen_pipe_dff#(
    .DW       ( 8 )
)int_flag_ff(
    .clk      ( clk      ),
    .rst_n    ( rst_n    ),
    .hold_en  ( hold_en  ),
    .def_val  ( 8'h0  ),
    .din      ( int_flag_i      ),  // 外设中断输入信号
    .qout     ( int_flag    )
);
assign  int_flag_o = int_flag ; 

endmodule  

id.v

// 译码阶段
module id(
    input                      rst_n          ,
    //
    input         [31 : 0]     inst_i         ,    // 指令内容
    input         [31 : 0]     inst_addr_i    ,
    // from reg 我在这里其实会等reg把指令传递回来
    input         [31 : 0]     reg1_rdata_i   ,
    input         [31 : 0]     reg2_rdata_i   ,
    // from csr reg
    input         [31 : 0]     csr_rdata_i    ,
    // from ex 跳转标志

    // input                      ex_jump_flag_i ,               // 跳转标志
    //这一个是根本用不到的数据 
    // 

    // to reg
    output   reg  [4 : 0]     reg1_raddr_o   ,   // 读通用寄存器1地址
    output   reg  [4 : 0]     reg2_raddr_o   ,
    // to csr reg
    output   reg  [31 : 0]     csr_raddr_o    ,
    // to ex
    output   reg  [31 : 0]     op1_o          ,
    output   reg  [31 : 0]     op2_o          ,
    output   reg  [31 : 0]     op1_jump_o     ,
    output   reg  [31 : 0]     op2_jump_o     ,
    output   reg  [31 : 0]     inst_o         ,
    output   reg  [31 : 0]     inst_addr_o    ,    // 指令地址
    output   reg  [31 : 0]     reg1_rdata_o   ,        // 通用寄存器1数据
    output   reg  [31 : 0]     reg2_rdata_o   ,        // 通用寄存器2数据
    output   reg               reg_we_o       ,        // 写通用寄存器标志
    output   reg  [4 : 0]      reg_waddr_o    ,        // 写通用寄存器地址
    output   reg               csr_we_o       ,        // 写CSR寄存器标志
    output   reg  [31 : 0]     csr_rdata_o    ,         // CSR寄存器数据
    output   reg  [31 : 0]     csr_waddr_o              // 写CSR寄存器地址
  ) ;


  // 还是先写整体的主题内容
  // 对于指令字段的分析
  // [31:25] [24:20] [19:15] [14:12] [11:7] [6:0]
  wire    [6 : 0]      opcode       ;
  wire    [4 : 0]      rd           ;
  wire    [2 : 0]      funct3       ;
  wire    [4 : 0]      rs1          ;
  wire    [4 : 0]      rs2          ;
  wire    [6 : 0]      funct7       ;

  assign    opcode  =   inst_i[6  : 0]  ;
  assign    rd      =   inst_i[11 : 7]  ;
  assign    funct3  =   inst_i[14 : 12] ;
  assign    rs1     =   inst_i[19 : 15] ;
  assign    rs2     =   inst_i[24 : 20] ;
  assign    funct7  =   inst_i[31 : 25] ;




  always@(*)
  begin
    inst_o          = inst_i        ;
    inst_addr_o     = inst_addr_i   ;
    reg1_rdata_o    = reg1_rdata_i  ;
    reg2_rdata_o    = reg2_rdata_i  ;
    csr_rdata_o     = csr_rdata_i   ;
    csr_raddr_o     = 0             ;
    csr_waddr_o     = 0             ;
    csr_we_o        = 0             ;
    op1_o           = 0             ;
    op2_o           = 0             ;
    op1_jump_o      = 0             ;
    op2_jump_o      = 0             ;

    case(opcode)
      7'b001_0011 :
      begin    // this is I type
        case(funct3)
          3'b000 ,             // addi  addi a0, a1, 0x5  //a0 = a1 + 0x5
          3'b010 ,             // slti a0, a1, 0x05  //a1 < 0x05 ? a0 = 1 : a0 = 0
          3'b011 ,             // SLTIU
          3'b100 ,             // XORI
          3'b110 ,             // ORI
          3'b111 ,             // ANDI
          3'b001 ,             // SLLI
          3'b101  :            // SRI
          begin
            reg_we_o      =  1              ;
            reg_waddr_o   =  rd             ;   // 这里的做法是写地址给出
            reg1_raddr_o  =  rs1            ;
            reg2_raddr_o  =  0              ;
            op1_o         =  reg1_rdata_i   ;
            op2_o         =  {{20{inst_i[31]}}, inst_i[31:20]}  ;
          end
          default :
          begin
            reg_we_o      =  0    ;
            reg_waddr_o   =  0    ;
            reg1_raddr_o  =  0    ;
            reg2_raddr_o  =  0    ;
          end
        endcase
      end

      7'b011_0011 :      // R型
      begin
        if( (funct7 == 7'b000_0000) || (funct7 == 7'b010_0000))
        begin
          case(funct3) // 这一部分是标准的指令集内容
            3'b000 ,           //  SUB
            3'b001 ,           //  SLL
            3'b010 ,           //  SLT
            3'b011 ,           //  SLTU
            3'b100 ,           //  XOR
            3'b101 ,           //  SR
            3'b110 ,           //  OR
            3'b111  :          //  AND
            begin
              reg_we_o      =   1               ;
              reg_waddr_o   =   rd              ;
              reg1_raddr_o  =   rs1             ;
              reg2_raddr_o  =   rs2             ;
              op1_o         =   reg1_rdata_i    ;
              op2_o         =   reg2_rdata_i    ;
            end
            default :
            begin
              reg_we_o    =   0               ;
              reg_waddr_o =   0               ;
              reg1_raddr_o =  0               ;
              reg2_raddr_o =  0               ;
            end
          endcase
        end
        else if( funct7 == 7'b000_0001)    // M
        begin
          case(funct3)
            3'b000 ,      // MUL
            3'b001 ,      // MULH
            3'b010 ,      // MULHSU
            3'b011  :     // MULHU
            begin
              reg_we_o      =   1               ;
              reg_waddr_o   =   rd              ;
              reg1_raddr_o  =   rs1             ;
              reg2_raddr_o  =   rs2             ;
              op1_o         =   reg1_rdata_i    ;
              op2_o         =   reg2_rdata_i    ;
            end
            3'b100 ,      // DIV
            3'b101 ,      // DIVU
            3'b110 ,      // REM
            3'b111    :   // REMU
            begin
              reg_we_o        =   0   ;   // 因为除法的计算时间比较长,所以会立即禁止写回
              reg_waddr_o     =   rd  ;
              reg1_raddr_o    =   rs1 ;
              reg2_raddr_o    =   rs2 ;
              op1_o           =   reg1_rdata_i  ;
              op2_o           =   reg2_rdata_i  ;
              op1_jump_o      =   inst_addr_i   ;       // 记录 当前指令的地址
              op2_jump_o      =   32'h4         ;
            end
            default:
            begin
              reg_we_o      =   0   ;
              reg_waddr_o   =   0   ;
              reg1_raddr_o  =   0   ;
              reg2_raddr_o  =   0   ;
            end
          endcase
        end
        else
        begin
          reg_we_o        =   0    ;
          reg_waddr_o     =   0    ;
          reg1_raddr_o    =   0    ;
          reg2_raddr_o    =   0    ;
        end
      end

      7'b000_0011 :
      begin     // 其实这里是对上面的I型指令的一部分扩展
        case(funct3)
          3'b000    ,    // lb x10,  0(x1)
          //将x1的值加上0,将这个值作为地址, 取出这个地址所对应的内存中的值, 将这个值赋值给x10(取出的是8位数值)
          3'b001    ,    // lh x10,  0(x1)  //从内存中取出16位数值
          3'b010    ,    // lw x10, 0(x1)  //从内存中取出32位数值
          3'b100    ,    //  lbu x10, 0(x1) //从内存中取出8位无符号数值
          3'b101    : // lhu x10, 0(x1) //从内存中取出16位无符号数值
          begin
            reg_we_o       =   1     ;
            reg_waddr_o    =   rd    ;
            reg1_raddr_o   =   rs1   ;
            reg2_raddr_o   =   0     ;
            op1_o          =   reg1_rdata_i  ;
            op2_o          =   {{20{inst_i[31]}},inst_i[31:20]} ;
          end
          default :
          begin
            reg1_raddr_o   =   0     ;
            reg2_raddr_o   =   0     ;
            reg_we_o       =   0     ;
            reg_waddr_o    =   0     ;
          end
        endcase
      end

      7'b01_00011 :      // S  类型
      begin
        case(funct3)         // S type
          3'b000        ,         // sb  x10, 0(x1)
          //x1的值加上0,将这个值作为地址, 将x10的值存储到上述地址所对应的内存中去 (只会将x10的值的低8位写入)
          3'b001        ,         // sh  x10, 0(x1)  //只会将x10的值的低16位写入
          3'b010        ://    sw  x10, 0(x1)  //只会将x10的值的低32位写入
          begin  
            reg_we_o      =     0    ;  // 并不需要写入寄存器 是直接存入内存的
            reg_waddr_o   =     0    ;
            reg1_raddr_o  =     rs1  ;
            reg2_raddr_o  =     rs2  ;
            op1_o         =     reg1_rdata_i  ;
            op2_o         =     {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]}  ;
          end
          default :
          begin
            reg_we_o      =     0    ;
            reg_waddr_o   =     0    ;
            reg1_raddr_o  =     0    ;
            reg2_raddr_o  =     0    ;
          end
        endcase
      end

      7'b1100011  :         //  B 型指令
      begin
        case(funct3)
          3'b000    ,            //beq a1,a2,Label   //if(a1==a2){goto Label;}
          3'b001    ,            //bne a1,a2,Label   //if(a1!=a2){goto Label;}
          3'b100    ,            //blt a1,a2,Label   //if(a1< a2){goto Label;}
          3'b101    ,            //BGE: Branch if Greater or Equal (大于等于时跳转,有符号比较)
          3'b110    ,            //BLTU: Branch if Less Than Unsigned (小于时跳转,无符号比较)
          3'b111    :
          begin     // BGEU: Branch if Greater or Equal Unsigned (大于等于时跳转,无符号比较)
            reg_we_o       =   0       ;
            reg_waddr_o    =   0       ;
            reg1_raddr_o   =   rs1     ;
            reg2_raddr_o   =   rs2     ;
            op1_o          =   reg1_rdata_i   ;
            op2_o          =   reg2_rdata_i   ;
            op1_jump_o     =   inst_addr_i    ;
            op2_jump_o     =   {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};
          end
          default :
          begin
            reg_we_o     =   0    ;
            reg_waddr_o  =   0    ;
            reg1_raddr_o =   0    ;
            reg2_raddr_o =   0    ;
          end
        endcase
      end

      7'b110_1111 :   // JAL  J型指令    pc = pc + imm 并将下一条指令的地址 给rd
      begin
        reg_we_o        =   1             ;
        reg_waddr_o     =   rd            ;
        reg1_raddr_o    =   0             ;
        reg2_raddr_o    =   0             ;
        op1_o           =   inst_addr_i   ;
        op2_o           =   32'h4         ;
        op1_jump_o      =   inst_addr_i   ;
        op2_jump_o      =   {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
      end

      7'b1100_111 :    // JALR  功能:PC = (rs1 + imm) & ~1,并将下一条指令地址存入 rd。
      begin
        reg_we_o        =   1             ;
        reg_waddr_o     =   rd            ;
        reg1_raddr_o    =   rs1           ;
        reg2_raddr_o    =   0             ;
        op1_o           =   inst_addr_i   ;
        op2_o           =   32'h4         ;
        op1_jump_o      =   reg1_rdata_i  ;
        op2_jump_o      =   {{20{inst_i[31]}}, inst_i[31:20]};
      end

      7'b011_0111 :   // LUT lui  将 imm[31:12] 左移 12 位后写入寄存器 rd
      begin
        reg_we_o         =   1             ;
        reg_waddr_o      =   rd            ;
        reg1_raddr_o     =   0             ;
        reg2_raddr_o     =   0             ;
        op1_o            =   {inst_i[31:12], 12'b0}  ;
        op2_o            =   0             ;
      end

      7'b001_0111 :    // 功能:PC + (imm[31:12] << 12) 写入寄存器 rd
      begin
        reg_we_o         =   1              ;
        reg_waddr_o      =   rd             ;
        reg1_raddr_o     =   0              ;
        reg2_raddr_o     =   0              ;
        op1_o            =   inst_addr_i    ;
        op2_o            =   {inst_i[31:12], 12'b0}   ;
      end

      7'b0000_001 :   // 单纯的占用流水线的时钟周期
      begin
        reg_we_o         =   0              ;
        reg_waddr_o      =   0              ;
        reg1_raddr_o     =   0              ;
        reg2_raddr_o     =   0              ;
      end

      7'b000_1111 :    //  功能:在执行不同类型的内存操作时插入屏障,确保指令执行顺序
      begin
        reg_we_o           =   0              ;
        reg_waddr_o        =   0              ;
        reg1_raddr_o       =   0              ;
        reg2_raddr_o       =   0              ;
        op1_jump_o         =   inst_addr_i    ;
        op2_jump_o         =   32'h4          ;
      end

      //下面是最后一部分CSR的编写
      7'b111_0011 :  //  CSR 指令属于 RISC-V 的标准基础指令集的扩展部分
        // 是的一共六个 特权指令集(Privileged ISA) 的核心部分。
      begin
        reg_we_o        = 0    ;
        reg_waddr_o     = 0    ;
        reg1_raddr_o    = 0    ;
        reg2_raddr_o    = 0    ;
        csr_raddr_o     = {20'h0, inst_i[31:20]};
        csr_waddr_o     = {20'h0, inst_i[31:20]};
        case (funct3)
          3'b001   ,
          3'b010   ,
          3'b011   :
          begin
            reg1_raddr_o   =   rs1   ;
            reg2_raddr_o   =   0     ;
            reg_we_o       =   1     ;
            reg_waddr_o    =   rd    ;
            csr_we_o       =   1     ;
          end
          3'b101    ,
          3'b110    ,
          3'b111    :
          begin
            reg1_raddr_o   =   0      ;
            reg2_raddr_o   =   0      ;
            reg_we_o       =   1      ;
            reg_waddr_o    =   rd     ;
            csr_we_o       =   1      ;
          end
          default:
          begin
            reg_we_o       =   0  ;
            reg_waddr_o    =   0  ;
            reg1_raddr_o   =   0  ;
            reg2_raddr_o   =   0  ;
            csr_we_o       =   0  ;
          end
        endcase
      end
      default:
      begin
        reg_we_o      =     0   ;
        reg_waddr_o   =     0   ;
        reg1_raddr_o  =     0   ;
        reg2_raddr_o  =     0   ;
      end
    endcase
  end

endmodule

clint.v

// 核心中断管理、仲裁
module  clint(
    input                     clk           ,
    input                     rst_n         ,
    // 其实很简单的区分
    input   [7 : 0]           int_flag_i    ,  // 这个信号是 来自于core的
    //  这一部分是中断的指令内容
    input   [31 : 0]          inst_i        ,   // 这里确定的是指令的内容
    // clint 模块需要知道当前执行的指令,以便检查是否是一个需要处理的指令(例如,ECALL 或 EBREAK)。
    // 如果是同步中断(如系统调用),需要根据指令类型决定如何处理中断。
    input   [31 : 0]          inst_addr_i   ,

    // form ex
    input                     jump_flag_i   ,  //
    // 中断处理需要知道当前是否有跳转指令正在执行。如果有跳转指令发生,中断处理时要注意将跳转地址保存或调整。
    input   [31 : 0]          jump_addr_i   ,
    input                     div_started_i ,  // 除法指令
    // 如果正在进行除法操作 可能要推迟同步中断的处理
    //input   [2 : 0]           hold_flag_i   ,  // 流水线暂停标志
    // 标注一下这里的 hold_flag_i 并没有用到
    // 下面是正常的交互  csr_reg
    //  input   [31 : 0]          data_i        ,  这是一个没用的值

    input   [31 : 0]          csr_mtvec     ,// 中断向量表地址
    input   [31 : 0]          csr_mepc      ,// 中断返回地址
    input   [31 : 0]          csr_mstatus   ,// 全局中断状态寄存器

    input                     global_int_en_i ,   // 全局中断使能

    output                    hold_flag_o   ,     // 全局流水线暂停
    // to  csr_reg
    output  reg               we_o          ,
    output  reg   [31 : 0]    waddr_o       ,
    output  reg   [31 : 0]    raddr_o       ,
    output  reg   [31 : 0]    data_o        ,

    // to ex
    output  reg   [31 : 0]    int_addr_o    ,
    output  reg               int_assert_o
  );




  // ------------------------------------------------------------- //
  //           next is define  and parameter                       //
  // ------------------------------------------------------------- //



  // 定义中断的状态机
  localparam S_INT_IDLE            = 4'b0001;
  localparam S_INT_SYNC_ASSERT     = 4'b0010;
  localparam S_INT_ASYNC_ASSERT    = 4'b0100;
  localparam S_INT_MRET            = 4'b1000;

  // 写CSR寄存器状态定义
  localparam S_CSR_IDLE            = 5'b00001;
  localparam S_CSR_MSTATUS         = 5'b00010;
  localparam S_CSR_MEPC            = 5'b00100;
  localparam S_CSR_MSTATUS_MRET    = 5'b01000;
  localparam S_CSR_MCAUSE          = 5'b10000;

  reg[3  : 0]   int_state   ;
  reg[4  : 0]   csr_state   ;
  reg[31 : 0]   inst_addr   ;
  reg[31 : 0]   cause       ;


  assign hold_flag_o  =  ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? 1 : 0 ;


  // 中断仲裁阶段
  always@(*)
  begin
    if(rst_n == 0)
    begin
      int_state   <=  S_INT_IDLE  ;
    end
    else
    begin
      if(inst_i == 32'h0000_0073 || inst_i == 32'h0010_0073)

      begin
        if(div_started_i == 1)
        begin
          int_state  <=  S_INT_IDLE  ;
        end
        else
        begin
          int_state  <=  S_INT_SYNC_ASSERT ;
        end
      end
      else if( int_flag_i != 0  && global_int_en_i == 1)
      begin
        int_state  <=  S_INT_ASYNC_ASSERT  ;
      end
      else if(inst_i == 32'h3020_0073)
      begin
        int_state  <=  S_INT_MRET ;  // 这个表示需要从异常状态恢复到正常程序状态
      end
      else
      begin
        int_state <= S_INT_IDLE ;
      end
    end
  end

  // 写CSR寄存器状态切换
  always@( posedge clk )
  begin
    if(rst_n == 0)
    begin
      csr_state   <=  S_CSR_IDLE  ;   // 状态机
      cause       <=  0           ;
      inst_addr   <=  0           ;
    end
    else
    begin
      case( csr_state )
        S_CSR_IDLE :
        begin
          // 同步中断
          if(int_state == S_INT_SYNC_ASSERT )    // 这部分的意思是如果系统捕获到了同步中断
          begin
            csr_state   <=   S_CSR_MEPC         ;
            // 在中断处理函数里会将中断返回地址 - 4
            if (jump_flag_i ==  1 )
            begin
              inst_addr <=   jump_addr_i - 4'h4 ;
            end
            else
            begin
              inst_addr <=   inst_addr_i  ;
            end
            case (inst_i)
              32'h0000_0073 :   // ECALL
              begin
                cause   <=   32'd11  ;
              end
              32'h010_0073  :   // EBREAK
              begin
                cause   <=   32'd3   ;
              end
              default:
              begin
                cause   <=   32'd10  ;
              end
            endcase
          end // 异步中断
          else if (int_state == S_INT_ASYNC_ASSERT)
          begin
            // 定时器中断
            cause <= 32'h80000004;
            csr_state <= S_CSR_MEPC;
            if (jump_flag_i == 1)
            begin
              inst_addr <= jump_addr_i;
              // 异步中断可以中断除法指令的执行,中断处理完再重新执行除法指令
            end
            else if (div_started_i == 1)
            begin
              inst_addr <= inst_addr_i - 4'h4;
            end
            else
            begin
              inst_addr <= inst_addr_i;
            end
            // 中断返回
          end
          else if (int_state == S_INT_MRET)
          begin
            csr_state <= S_CSR_MSTATUS_MRET;
          end
        end

        S_CSR_MEPC:
          // 在这个状态下,系统会将当前的中断返回地址保存到 MEPC,以便中断处理完后可以正确返回。
        begin
          csr_state <= S_CSR_MSTATUS;
        end
        S_CSR_MSTATUS:
          // 这个状态用于处理 MSTATUS 寄存器,通常涉及到恢复系统的中断使能和相关状态。
        begin
          csr_state <= S_CSR_MCAUSE;
        end
        S_CSR_MCAUSE:
          // MCAUSE 寄存器用于存储中断的原因。在这个状态下,系统会把中断的原因写入 MCAUSE 寄存器。
        begin
          csr_state <= S_CSR_IDLE;
        end
        S_CSR_MSTATUS_MRET:
          // 这是中断返回的特殊状态。执行完中断处理后,处理器需要返回到中断发生前的程序。
          // 这是通过恢复 MSTATUS 寄存器和中断前的状态来实现的。
        begin
          csr_state <= S_CSR_IDLE;
        end
        default:
        begin
          csr_state <= S_CSR_IDLE;
        end
      endcase
    end
  end

  // 发出信号前 先写几个寄存器
  always@(posedge clk )
  begin
    if(rst_n == 0)
    begin
      we_o      <=  0   ;
      waddr_o   <=  0   ;
      data_o    <=  0   ;
    end
    else
    begin  // 这一部分是按照上面的情况进行给予的
      case(csr_state )
        S_CSR_MEPC :
        begin
          // 在这个状态下,系统会将当前的中断返回地址保存到 MEPC,以便中断处理完后可以正确返回。
          we_o      <=  1            ;
          waddr_o   <=  {20'h0 , 12'h341} ;
          data_o    <=  inst_addr    ;
        end
        // 写中断产生的原因
        S_CSR_MCAUSE:
        begin
          we_o      <=  1      ;
          waddr_o   <=  {20'h0, 12'h342 };
          data_o    <=  cause  ;
        end
        // 关闭全局中断
        S_CSR_MSTATUS:
        begin
          we_o      <=  1     ;
          waddr_o   <= {20'h0, 12'h300};
          data_o    <= {csr_mstatus[31:4], 1'b0, csr_mstatus[2:0]};
        end
        // 中断返回
        S_CSR_MSTATUS_MRET :
        begin
          we_o      <=  0     ;
          waddr_o <= {20'h0, 12'h300};
          data_o <= {csr_mstatus[31:4], csr_mstatus[7], csr_mstatus[2:0]};
        end

        default:
        begin
          we_o      <=    0   ;
          waddr_o   <=    0   ;
          data_o    <=    0   ;
        end
      endcase
    end
  end

  // 发送中断信号给ex模块
  always@(posedge  clk )
  begin
    if(rst_n == 0)
    begin
      int_assert_o   <=  0   ;
      int_addr_o     <=  0   ;
    end
    else
    begin
      case (csr_state)
        // 发出中断进入信号.写完mcause寄存器才能发
        S_CSR_MCAUSE:
        begin
          int_assert_o   <= 1          ;
          int_addr_o     <= csr_mtvec  ;
        end
        // 发出中断返回信号
        S_CSR_MSTATUS_MRET:
        begin
          int_assert_o   <= 1         ;
          int_addr_o     <= csr_mepc  ;
        end
        default:
        begin
          int_assert_o   <= 0   ;
          int_addr_o     <= 0   ;
        end
      endcase
    end
  end

endmodule

csr_reg.v

module   csr_reg(  // 寄存器

    input                       clk               ,
    input                       rst_n             ,
    // from  ex
    input                       we_i              , // ex模块写寄存器标志位
    input   [31 : 0]            raddr_i           ,
    input   [31 : 0]            waddr_i           ,
    input   [31 : 0]            data_i            ,

    // from clint
    input                       clint_we_i        ,
    input   [31 : 0]            clint_raddr_i     ,
    input   [31 : 0]            clint_waddr_i     ,
    input   [31 : 0]            clint_data_i      ,

    output                      global_int_en_o   ,

    // to  clint
    output  reg  [31 : 0]       clint_data_o      ,
    output       [31 : 0]       clint_csr_mtvec   ,
    output       [31 : 0]       clint_csr_mepc    ,
    output       [31 : 0]       clint_csr_mstatus ,
    // to ex

    output  reg  [31 : 0]       data_o
  ) ;

  // --------------------------------------------- //
  //          next is parameter and define         //
  // --------------------------------------------- //

  reg     [63 : 0]  cycle     ;
  reg     [31 : 0]  mtvec     ;
  reg     [31 : 0]  mcause    ;
  reg     [31 : 0]  mepc      ;
  reg     [31 : 0]  mie       ;
  reg     [31 : 0]  mstatus   ;
  reg     [31 : 0]  mscratch  ;


  assign global_int_en_o   = (mstatus[3] == 1'b1)? 1: 0  ;

  assign clint_csr_mtvec   = mtvec                       ;
  assign clint_csr_mepc    = mepc                        ;
  assign clint_csr_mstatus = mstatus                     ;




  // next is main code
  always@(posedge clk )
  begin
    if(rst_n == 0 )
    begin
      cycle  <=  0         ;
    end
    else
    begin
      cycle  <=  cycle + 1 ;
    end
  end


  // write  reg  写寄存器
  always@(posedge  clk )
  begin
    if(rst_n == 0)
    begin
      mtvec         <=  0  ;
      mcause        <=  0  ;
      mepc          <=  0  ;
      mie           <=  0  ;
      mstatus       <=  0  ;
      mscratch      <=  0  ;
    end
    else
    begin
      if(we_i == 1)
      begin // 先响应ex写模块
        case( waddr_i[11 : 0])
          12'h305 :
          begin
            mtvec  <=  data_i  ;   //  处理器的中断向量地址寄存器。
          end
          12'h342:
          begin
            mcause <=  data_i  ;   //  记录中断发生的原因。
          end
          12'h341:
          begin
            mepc   <=  data_i  ;   //  记录中断发生时的程序计数器(PC)值,即出错时程序的执行地址
          end
          12'h304:
          begin
            mie    <=  data_i  ;   //   机器模式下的中断使能寄存器
          end
          12'h300:
          begin
            mstatus <= data_i  ;   //   机器状态寄存器,包含有关当前处理器状态的信息
          end
          12'h340:
          begin
            mscratch <= data_i  ;  //    用于保存机器模式下的临时值
          end
          default:
          begin
          end
        endcase
      end
      else if( clint_we_i == 1)
      begin
        case( clint_waddr_i[11:0])
          12'h305 :
          begin
            mtvec  <=  clint_data_i  ;   //  处理器的中断向量地址寄存器。
          end
          12'h342:
          begin
            mcause <=  clint_data_i  ;   //  记录中断发生的原因。
          end
          12'h341:
          begin
            mepc   <=  clint_data_i  ;   //  记录中断发生时的程序计数器(PC)值,即出错时程序的执行地址
          end
          12'h304:
          begin
            mie    <=  clint_data_i  ;   //   机器模式下的中断使能寄存器
          end
          12'h300:
          begin
            mstatus <= clint_data_i  ;   //   机器状态寄存器,包含有关当前处理器状态的信息
          end
          12'h340:
          begin
            mscratch <= clint_data_i  ;  //    用于保存机器模式下的临时值
          end
          default:
          begin
          end
        endcase
      end
    end
  end


  // 读寄存器
  always@(*)
  begin
    if((waddr_i[11:0] == raddr_i[11:0]) &&(we_i == 1) )
    begin
      data_o  <=  data_i   ;
    end
    else
    begin
      case(raddr_i[11 : 0])
        12'hc00 :
        begin
          data_o    <= cycle[31:0]   ;
        end
        12'hc80 :
        begin
          data_o    <= cycle[63:32]  ;
        end
        12'h305 :
        begin
          data_o    <= mtvec         ;
        end
        12'h342 :
        begin
          data_o    <= mcause        ;
        end
        12'h341 :
        begin
          data_o    <= mepc          ;
        end
        12'h304 :
        begin
          data_o    <= mie           ;
        end
        12'h300 :
        begin
          data_o    <= mstatus       ;
        end
        12'h340 :
        begin
          data_o    <= mscratch      ;
        end
        default:
        begin
          data_o <= 0 ;
        end
      endcase
    end
  end



  always@(*)
  begin
    if((clint_waddr_i[11:0] == clint_raddr_i[11:0]) &&(clint_we_i == 1) )
    begin
      clint_data_o  <=  clint_data_i   ;
    end
    else
    begin
      case(clint_raddr_i[11 : 0])
        12'hc00 :
        begin
          clint_data_o    <= cycle[31:0]   ;
        end
        12'hc80 :
        begin
          clint_data_o    <= cycle[63:32]  ;
        end
        12'h305 :
        begin
          clint_data_o    <= mtvec         ;
        end
        12'h342 :
        begin
          clint_data_o    <= mcause        ;
        end
        12'h341 :
        begin
          clint_data_o    <= mepc          ;
        end
        12'h304 :
        begin
          clint_data_o    <= mie           ;
        end
        12'h300 :
        begin
          clint_data_o    <= mstatus       ;
        end
        12'h340 :
        begin
          clint_data_o    <= mscratch      ;
        end
        default:
        begin
          clint_data_o <= 0 ;
        end
      endcase
    end
  end

endmodule

ctrl.v

// 这是控制模块的设计
module  ctrl(
    // from  ex 来自于ex 的处理
    // input                          rst_n               ,
    // 经过分析 这里也没有用到 rst_n
    input                          jump_flag_i         ,
    input           [31 : 0]       jump_addr_i         ,    // 传递给PC 跳转的
    input                          hold_flag_ex_i      ,    // 内部的比如说触发需要暂停这样的

    // from rib 总线
    input                          hold_flag_rib_i     ,
    // from  jtag
    input                          jtag_halt_flag_i    ,
    // clint
    input                          hold_flag_clint_i   ,
    // 输出 阶段
    output   reg     [2  : 0]      hold_flag_o         ,
    output   reg                   jump_flag_o         ,
    // to pc
    output   reg     [31 : 0]      jump_addr_o

  ) ;

  // 非常简单的组合逻辑阵列
  always@(*)
  begin
    jump_addr_o   =   jump_addr_i  ;
    jump_flag_o   =   jump_flag_i  ;
    // 默认不暂停
    hold_flag_o   =   0            ;
    // 按照优先级程度处理不同模块
    if(jump_flag_i == 1 ||  hold_flag_ex_i == 1  || hold_flag_clint_i === 1)
    begin
      // 暂停整条流水线
      hold_flag_o  =  3'b011 ;
    end
    else if(hold_flag_rib_i == 1)
    begin
      hold_flag_o  = 3'b001 ;
    end
    else if(jtag_halt_flag_i == 1)
    begin
      hold_flag_o  = 3'b011 ;
    end
    else
    begin
      hold_flag_o = 0 ;
    end
  end
endmodule

div.v

// 这里作者说使用试商法 实现整除
module  div(
    input                          rst_n         ,
    input                          clk           ,
    // from ex
    input              [31 : 0]    dividend_i    ,  // 被除数
    input              [31 : 0]    divisor_i     ,  // 除数
    input                          start_i       ,  // 开始信号
    input              [2  : 0]    op_i          ,  // 声明具体执行的是什么指令
    input              [4  : 0]    reg_waddr_i   ,  // 寄存器地址
    // to ex
    output   reg       [31 : 0]    result_o      ,  // 除法结果
    output   reg                   ready_o       ,
    output   reg                   busy_o        ,
    output   reg       [4  : 0]    reg_waddr_o      // 存放的寄存器地址
  );

  // 状态定义
  localparam    STATE_IDLE    =    4'b0001  ;
  localparam    STATE_START   =    4'b0010  ;
  localparam    STATE_CALC    =    4'b0100  ;
  localparam    STATE_END     =    4'b1000  ;

  // ----------------------------------------------------- //
  //    parameter   and  define                           //
  //  ------------------------------------------------   //
  reg  [2  : 0]    op_r         ;
  reg  [31 : 0]    dividend_r   ;
  reg  [31 : 0]    divisor_r    ;
  reg  [3  : 0]    state        ;
  wire op_div    = (op_r == 3'b100 );   // 100  有符号整数除法
  wire op_divu   = (op_r == 3'b101 );   // 101  无符号整数除法
  wire op_rem    = (op_r == 3'b110 );   // 110  有符号整数取余
  wire op_remu   = (op_r == 3'b111 );   // 111  无符号整数取余
  reg  [31 : 0]    count         ;
  reg  [31 : 0]    div_result    ;  // 暂存的商值
  reg  [31 : 0]    div_remain    ;  // 暂存的余数值
  reg  [31 : 0]    minuend       ;  // 表示当前的被减数
  reg              invert_result ;

  wire  [31 : 0]    dividend_invert  =   (-dividend_r ) ;
  wire  [31 : 0]    divisor_invert   =   (-divisor_r)   ;
  wire  minuend_ge_divisor  =   minuend >= divisor_r    ;  // 比较被减数 和 除数
  wire  [31 : 0]    div_result_tmp   =   minuend_ge_divisor ?
        ({div_result[30 : 0] ,1'b1}) : ({div_result[30 : 0] , 1'b0}) ;
  wire  [31 : 0]    minuend_sub_res  =   minuend  - divisor_r  ;
  wire  [31 : 0]    minuend_tmp      =   minuend_ge_divisor  ? minuend_sub_res[30 : 0] : minuend[30 : 0] ;







  //   -----------------------------------------------    //
  //             next is  main  code                      //
  //   -------------------------------------------------  //
  // 状态机的更新
  always@(posedge clk  )
  begin
    if(rst_n == 0 )
    begin
      state       <=   STATE_IDLE  ;
      ready_o     <=   0           ;
      result_o <= 0;
      div_result <= 0;
      div_remain <= 0;
      op_r <= 3'h0;
      reg_waddr_o <= 0;
      dividend_r <= 0;
      divisor_r <=0;
      minuend <= 0;
      invert_result <= 1'b0;
      busy_o <= 0;
      count <= 0;
    end
    else
    begin
      case(state)

        STATE_IDLE :
        begin
          if(start_i == 1)
          begin
            // 表示开始运算
            op_r            <=     op_i         ;
            dividend_r      <=     dividend_i   ;
            divisor_r       <=     divisor_i    ;
            reg_waddr_o     <=     reg_waddr_i  ;   // 寄存器地址 方便回写
            state           <=     STATE_START  ;
            busy_o          <=     1            ;
          end
          else
          begin
            op_r            <=     0            ;
            dividend_r      <=     0            ;
            divisor_r       <=     0            ;
            reg_waddr_o     <=     0            ;   // 寄存器地址 方便回写
            state           <=     0            ;
            busy_o          <=     0            ;
          end
        end

        STATE_START :
        begin
          if(start_i == 1)
          begin // 开始运算
            //先假设除数为0
            if(divisor_r == 0 )
            begin
              if(op_div | op_divu )
              begin
                // 取商的操作 那么输出 32'hFFFFFFFF 表示 错误商值,在 除数为 0 时由硬件返回。
                result_o  <= 32'hffff_ffff ;
              end
              else
              begin  // 那就是取余数
                result_o  <=  dividend_r   ; // 取余数的话 余下来的正好是被除数
              end
              // 上面两个都执行的在除数为0的情况下
              ready_o     <=   1             ;
              state       <=   STATE_IDLE    ;
              busy_o      <=   0             ;
            end
            else
            begin
              // 这部分是除数不为0
              busy_o      <=   1             ;
              state       <=   STATE_CALC    ;
              count       <=   32'h4000_0000 ;
              div_result  <=   0             ;
              div_remain  <=   0             ;
              // 先进行有符号的运算
              if(op_div | op_rem)  // 有符号运算
              begin
                // 被除数求补码
                if(dividend_r[31] == 1)
                begin
                  dividend_r   <=  dividend_invert ;
                  minuend      <=  dividend_invert[31] ;  // 初始化为被除数的符号位
                end
                else
                begin
                  minuend    <=   dividend_r[31] ; // 其实就是0
                end
                if(divisor_r[31] == 1)
                begin
                  divisor_r  <=  divisor_invert ;
                end
                else
                begin
                  minuend    <=  dividend_r[31] ;
                end
                // 判断计算的结果是否需要取补码
                if((op_div &&(dividend_r[31] ^ divisor_r[31] == 1))
                    || (op_rem && (dividend_r[31]  == 1)))
                begin
                  invert_result   <=  1 ;
                end
                else
                begin
                  invert_result   <=  0  ;
                end
              end
            end
          end
          else
          begin
            state       <=   STATE_IDLE   ;
            result_o    <=   0            ;
            ready_o     <=   0            ;
            busy_o      <=   0            ;
          end
        end

        // 这里是整体的计算部分
        STATE_CALC :
        begin
          if(start_i == 1)
          begin
            dividend_r  <=   {dividend_r[30 : 0] , 1'b0}  ;
            div_result  <=   div_result_tmp               ;
            count       <=   {1'b0 , count[31 : 1] }      ;
            if(|count)
            begin
              minuend   <=   {minuend_tmp[30 : 0] , dividend_r[30]} ;
            end
            else
            begin
              state     <=   STATE_END  ;
              if(minuend_ge_divisor)
              begin
                div_remain   <=  minuend_sub_res   ;
              end
              else
              begin
                div_remain   <=  minuend           ;
              end
            end
          end
          else
          begin
            state          <=   STATE_IDLE  ;
            result_o       <=   0           ;
            ready_o        <=   0           ;
            busy_o         <=   0           ;
          end
        end


        STATE_END  :
        begin
          if(start_i  == 1)
          begin
            ready_o       <=    1               ;
            state         <=    STATE_IDLE      ;
            busy_o        <=    0               ;
            if(op_div  |  op_divu )
            begin
              if(invert_result == 1)
              begin
                result_o  <=   (-div_result) ;
              end
              else
              begin
                result_o  <=   div_result    ;
              end
            end
            else
            begin
              if(invert_result == 1)
              begin
                result_o  <=  (-div_remain ) ;
              end
              else
              begin
                result_o  <=  div_remain    ;
              end
            end
          end
          else
          begin
            state      <=  STATE_IDLE  ;
            result_o   <=  0           ;
            ready_o    <=  0           ;
            busy_o     <=  0           ;
          end
        end
      endcase
    end
  end
endmodule

ex.v

module ex(

    input                rst_n   ,

    // from id
    input        [31:0] inst_i,            // 指令内容  31
    input        [31:0] inst_addr_i,   // 指令地址  31
    input         reg_we_i,                    // 是否写通用寄存器
    input        [4:0] reg_waddr_i,    // 写通用寄存器地址  4:0
    input        [31:0] reg1_rdata_i,       // 通用寄存器1输入数据 31
    input        [31:0] reg2_rdata_i,       // 通用寄存器2输入数据31
    input         csr_we_i,                    // 是否写CSR寄存器
    input        [31:0] csr_waddr_i,    // 写CSR寄存器地址 31
    input        [31:0] csr_rdata_i,        // CSR寄存器输入数据31
    input         int_assert_i,                // 中断发生标志     -- 来自于 clint
    input        [31:0] int_addr_i,    // 中断跳转地址31   -- 来自于 clint
    input        [31:0] op1_i,          // 31
    input        [31:0] op2_i,
    input        [31:0] op1_jump_i,
    input        [31:0] op2_jump_i,

    // from mem
    input wire[31:0] mem_rdata_i,        // 内存输入数据

    // from div
    input wire div_ready_i,                 // 除法运算完成标志
    input wire[31:0] div_result_i,       // 除法运算结果
    input wire div_busy_i,                  // 除法运算忙标志
    input wire[4:0] div_reg_waddr_i,// 除法运算结束后要写的寄存器地址 4:0

    // to mem
    output reg[31:0] mem_wdata_o,        // 写内存数据 31
    output reg[31:0] mem_raddr_o,    // 读内存地址
    output reg[31:0] mem_waddr_o,    // 写内存地址 31
    output wire mem_we_o,                   // 是否要写内存
    output wire mem_req_o,                  // 请求访问内存标志

    // to regs
    output wire[31:0] reg_wdata_o,       // 写寄存器数据 31:0
    output wire reg_we_o,                   // 是否要写通用寄存器
    output wire[4:0] reg_waddr_o,   // 写通用寄存器地址 4:0

    // to csr reg
    output reg[31:0] csr_wdata_o,        // 写CSR寄存器数据
    output wire csr_we_o,                   // 是否要写CSR寄存器
    output wire[31:0] csr_waddr_o,   // 写CSR寄存器地址 31:0

    // to div
    output wire div_start_o,                // 开始除法运算标志
    output reg[31:0] div_dividend_o,     // 被除数
    output reg[31:0] div_divisor_o,      // 除数
    output reg[2:0] div_op_o,               // 具体是哪一条除法指令
    output reg[4:0] div_reg_waddr_o,// 除法运算结束后要写的寄存器地址4:0

    // to ctrl
    output wire hold_flag_o,                // 是否暂停标志
    output wire jump_flag_o,                // 是否跳转标志
    output wire[31:0] jump_addr_o   // 跳转目的地址 31 : 0

  );

  wire[1:0] mem_raddr_index;                          //
  wire[1:0] mem_waddr_index;                          //
  wire[63:0] mul_temp;                      // 63:0
  wire[63:0] mul_temp_invert;               //
  wire[31:0] sr_shift;                               //
  wire[31:0] sri_shift;                              //
  wire[31:0] sr_shift_mask;                          //
  wire[31:0] sri_shift_mask;                         //
  wire[31:0] op1_add_op2_res;                        //
  wire[31:0] op1_jump_add_op2_jump_res;              //
  wire[31:0] reg1_data_invert;                       // 我合在一起写了
  wire[31:0] reg2_data_invert;                       //
  wire op1_ge_op2_signed;             			  //
  wire op1_ge_op2_unsigned;    					  //
  wire op1_eq_op2;                                  //
  reg[31:0] mul_op1;                             //1
  reg[31:0] mul_op2;                             //

  wire[6:0] opcode;                                 //
  wire[2:0] funct3;                                 //
  wire[6:0] funct7;                                 //
  wire[4:0] rd;                                     //
  wire[4:0] uimm;                                   //

  reg[31:0] reg_wdata;                          // 1
  reg reg_we;                                      // 1
  reg[4:0] reg_waddr;                      // 4: 0

  reg[31:0] div_wdata;                          //1
  reg div_we;                                      //1
  reg[4:0] div_waddr;                      // 4:0
  reg div_hold_flag;                               // 1
  reg div_jump_flag;                               // 1
  reg[31:0] div_jump_addr;                 //31 : 0
  reg hold_flag;                                   //
  reg jump_flag;                                   //
  reg[31:0] jump_addr;                     // 1
  reg mem_we;                                      //
  reg mem_req;                                    // 1
  reg div_start;                                  // 1

  assign opcode = inst_i[6:0];
  assign funct3 = inst_i[14:12];
  assign funct7 = inst_i[31:25];
  assign rd = inst_i[11:7];
  assign uimm = inst_i[19:15];

  assign sr_shift = reg1_rdata_i >> reg2_rdata_i[4:0];              //
  assign sri_shift = reg1_rdata_i >> inst_i[24:20];                //
  assign sr_shift_mask = 32'hffffffff >> reg2_rdata_i[4:0];       //
  assign sri_shift_mask = 32'hffffffff >> inst_i[24:20];          //

  assign op1_add_op2_res = op1_i + op2_i;                       //
  assign op1_jump_add_op2_jump_res = op1_jump_i + op2_jump_i;   //

  assign reg1_data_invert = ~reg1_rdata_i + 1;    //
  assign reg2_data_invert = ~reg2_rdata_i + 1;    //

  // 有符号数比较
  assign op1_ge_op2_signed = $signed(op1_i) >= $signed(op2_i);     //
  // 无符号数比较
  assign op1_ge_op2_unsigned = op1_i >= op2_i;      //
  assign op1_eq_op2 = (op1_i == op2_i);            //

  assign mul_temp = mul_op1 * mul_op2;             //
  assign mul_temp_invert = ~mul_temp + 1;         //

  assign mem_raddr_index = (reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:20]}) & 2'b11;      //                      //
  assign mem_waddr_index = (reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]}) & 2'b11;  //           //

  assign div_start_o = (int_assert_i == 1)? 0: div_start;  //

  assign reg_wdata_o = reg_wdata | div_wdata; //
  // 响应中断时不写通用寄存器
  assign reg_we_o = (int_assert_i == 1)? 0: (reg_we || div_we);
  assign reg_waddr_o = reg_waddr | div_waddr;

  // 响应中断时不写内存
  assign mem_we_o = (int_assert_i == 1)? 0: mem_we;

  // 响应中断时不向总线请求访问内存
  assign mem_req_o = (int_assert_i == 1)? 0: mem_req;

  assign hold_flag_o = hold_flag || div_hold_flag;
  assign jump_flag_o = jump_flag || div_jump_flag || ((int_assert_i == 1)? 1: 0);
  assign jump_addr_o = (int_assert_i == 1)? int_addr_i: (jump_addr | div_jump_addr);

  // 响应中断时不写CSR寄存器
  assign csr_we_o = (int_assert_i == 1)? 0: csr_we_i;
  assign csr_waddr_o = csr_waddr_i;


  // 处理乘法指令
  always @ (*)
  begin
    if ((opcode == 7'b0110011) && (funct7 == 7'b0000001))
    begin
      case (funct3)
        3'b000, 3'b011:
        begin  // 3'b000  -  3'b011  无符号乘法 一个保留了低32位 一个保留了高32位
          mul_op1 = reg1_rdata_i;
          mul_op2 = reg2_rdata_i;
        end
        3'b010:
        begin   // 3'b010 有符号与 无符号混合乘法
          mul_op1 = (reg1_rdata_i[31] == 1'b1)? (reg1_data_invert): reg1_rdata_i;
          mul_op2 = reg2_rdata_i;
        end
        3'b001:
        begin  //3'b001  有符号乘法
          mul_op1 = (reg1_rdata_i[31] == 1'b1)? (reg1_data_invert): reg1_rdata_i;
          mul_op2 = (reg2_rdata_i[31] == 1'b1)? (reg2_data_invert): reg2_rdata_i;
        end
        default:
        begin
          mul_op1 = reg1_rdata_i;
          mul_op2 = reg2_rdata_i;
        end
      endcase
    end
    else
    begin
      mul_op1 = reg1_rdata_i;
      mul_op2 = reg2_rdata_i;
    end
  end

  // 处理除法指令
  always @ (*)
  begin
    div_dividend_o = reg1_rdata_i;
    div_divisor_o = reg2_rdata_i;
    div_op_o = funct3;
    div_reg_waddr_o = reg_waddr_i;
    if ((opcode == 7'b0110011) && (funct7 == 7'b0000001))
    begin // 7'b0110011
      div_we = 0;
      div_wdata = 32'h0;
      div_waddr = 32'h0;
      case (funct3)
        3'b100,3'b101, 3'b110, 3'b101:
        begin  // 100 101 110 111
          div_start = 1;
          div_jump_flag = 1;
          div_hold_flag = 1;
          div_jump_addr = op1_jump_add_op2_jump_res;
        end
        default:
        begin
          div_start = 0;
          div_jump_flag = 0;
          div_hold_flag = 0;
          div_jump_addr = 32'h0;
        end
      endcase
    end
    else
    begin
      div_jump_flag = 0;
      div_jump_addr = 32'h0;
      if (div_busy_i == 1)
      begin
        div_start = 1;
        div_we = 0;
        div_wdata = 32'h0;
        div_waddr = 32'h0;
        div_hold_flag = 1;
      end
      else
      begin
        div_start = 0;
        div_hold_flag = 0;
        if (div_ready_i == 1)
        begin
          div_wdata = div_result_i;
          div_waddr = div_reg_waddr_i;
          div_we = 1;
        end
        else
        begin
          div_we = 0;
          div_wdata = 32'h0;
          div_waddr = 32'h0;
        end
      end
    end
  end


  // `define INST_ADDI   3'b000
  // `define INST_SLTI   3'b010
  // `define INST_SLTIU  3'b011
  // `define INST_XORI   3'b100
  // `define INST_ORI    3'b110
  // `define INST_ANDI   3'b111
  // `define INST_SLLI   3'b001
  // `define INST_SRI    3'b101

  // 执行
  always @ (*)
  begin
    reg_we = reg_we_i;
    reg_waddr = reg_waddr_i;
    mem_req = 0;           // 0
    csr_wdata_o = 32'h0;

    case (opcode)
      7'b0010011:
      begin   // 7'b0010011
        case (funct3)
          3'b000:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = op1_add_op2_res;
          end
          3'b010:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = {32{(~op1_ge_op2_signed)}} & 32'h1;
          end
          3'b011:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = {32{(~op1_ge_op2_unsigned)}} & 32'h1;
          end
          3'b100:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = op1_i ^ op2_i;
          end
          3'b110:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = op1_i | op2_i;
          end
          3'b111:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = op1_i & op2_i;
          end
          3'b001:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = reg1_rdata_i << inst_i[24:20];
          end
          3'b101:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            if (inst_i[30] == 1'b1)
            begin
              reg_wdata = (sri_shift & sri_shift_mask) | ({32{reg1_rdata_i[31]}} & (~sri_shift_mask));
            end
            else
            begin
              reg_wdata = reg1_rdata_i >> inst_i[24:20];
            end
          end
          default:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
          end
        endcase
      end
      // 			// R type inst
      // `define INST_ADD_SUB 3'b000
      // `define INST_SLL    3'b001
      // `define INST_SLT    3'b010
      // `define INST_SLTU   3'b011
      // `define INST_XOR    3'b100
      // `define INST_SR     3'b101
      // `define INST_OR     3'b110
      // `define INST_AND    3'b111
      7'b0110011:
      begin   // 7'b0110011
        if ((funct7 == 7'b0000000) || (funct7 == 7'b0100000))
        begin
          case (funct3)
            3'b000:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              if (inst_i[30] == 1'b0)
              begin
                reg_wdata = op1_add_op2_res;
              end
              else
              begin
                reg_wdata = op1_i - op2_i;
              end
            end
            3'b001:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = op1_i << op2_i[4:0];
            end
            3'b010:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = {32{(~op1_ge_op2_signed)}} & 32'h1;
            end
            3'b011:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = {32{(~op1_ge_op2_unsigned)}} & 32'h1;
            end
            3'b100:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = op1_i ^ op2_i;
            end
            3'b101:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              if (inst_i[30] == 1'b1)
              begin
                reg_wdata = (sr_shift & sr_shift_mask) | ({32{reg1_rdata_i[31]}} & (~sr_shift_mask));
              end
              else
              begin
                reg_wdata = reg1_rdata_i >> reg2_rdata_i[4:0];
              end
            end
            3'b110:
            begin // 110
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = op1_i | op2_i;
            end
            3'b111:
            begin  //111
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = op1_i & op2_i;
            end
            default:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = 32'h0;
            end
          endcase
        end
        else if (funct7 == 7'b0000001)
        begin
          // M type inst
          //`define INST_MUL    3'b000
          //`define INST_MULH   3'b001
          //`define INST_MULHSU 3'b010
          //`define INST_MULHU  3'b011
          //`define INST_DIV    3'b100
          //`define INST_DIVU   3'b101
          //`define INST_REM    3'b110
          //`define INST_REMU   3'b111
          case (funct3)
            3'b000:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = mul_temp[31:0];
            end
            3'b011:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = mul_temp[63:32];
            end
            3'b001:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              case ({reg1_rdata_i[31], reg2_rdata_i[31]})
                2'b00:
                begin
                  reg_wdata = mul_temp[63:32];
                end
                2'b11:
                begin
                  reg_wdata = mul_temp[63:32];
                end
                2'b10:
                begin
                  reg_wdata = mul_temp_invert[63:32];
                end
                default:
                begin
                  reg_wdata = mul_temp_invert[63:32];
                end
              endcase
            end
            3'b010:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              if (reg1_rdata_i[31] == 1'b1)
              begin
                reg_wdata = mul_temp_invert[63:32];
              end
              else
              begin
                reg_wdata = mul_temp[63:32];
              end
            end
            default:
            begin
              jump_flag = 0;
              hold_flag = 0;
              jump_addr = 32'h0;
              mem_wdata_o = 32'h0;
              mem_raddr_o = 32'h0;
              mem_waddr_o = 32'h0;
              mem_we = 0;
              reg_wdata = 32'h0;
            end
          endcase
        end
        else
        begin
          jump_flag = 0;
          hold_flag = 0;
          jump_addr = 32'h0;
          mem_wdata_o = 32'h0;
          mem_raddr_o = 32'h0;
          mem_waddr_o = 32'h0;
          mem_we = 0;
          reg_wdata = 32'h0;
        end
      end

      7'b0000011:
      begin
        case (funct3)
          3'b000:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            mem_req = 1;       // 1
            mem_raddr_o = op1_add_op2_res;
            case (mem_raddr_index)
              2'b00:
              begin
                reg_wdata = {{24{mem_rdata_i[7]}}, mem_rdata_i[7:0]};
              end
              2'b01:
              begin
                reg_wdata = {{24{mem_rdata_i[15]}}, mem_rdata_i[15:8]};
              end
              2'b10:
              begin
                reg_wdata = {{24{mem_rdata_i[23]}}, mem_rdata_i[23:16]};
              end
              default:
              begin
                reg_wdata = {{24{mem_rdata_i[31]}}, mem_rdata_i[31:24]};
              end
            endcase
          end
          3'b001:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            mem_req = 1;
            mem_raddr_o = op1_add_op2_res;
            if (mem_raddr_index == 2'b0)
            begin
              reg_wdata = {{16{mem_rdata_i[15]}}, mem_rdata_i[15:0]};
            end
            else
            begin
              reg_wdata = {{16{mem_rdata_i[31]}}, mem_rdata_i[31:16]};
            end
          end
          3'b010:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            mem_req = 1;
            mem_raddr_o = op1_add_op2_res;
            reg_wdata = mem_rdata_i;
          end
          3'b100:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            mem_req = 1;
            mem_raddr_o = op1_add_op2_res;
            case (mem_raddr_index)
              2'b00:
              begin
                reg_wdata = {24'h0, mem_rdata_i[7:0]};
              end
              2'b01:
              begin
                reg_wdata = {24'h0, mem_rdata_i[15:8]};
              end
              2'b10:
              begin
                reg_wdata = {24'h0, mem_rdata_i[23:16]};
              end
              default:
              begin
                reg_wdata = {24'h0, mem_rdata_i[31:24]};
              end
            endcase
          end
          3'b101:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            mem_req = 1;
            mem_raddr_o = op1_add_op2_res;
            if (mem_raddr_index == 2'b0)
            begin
              reg_wdata = {16'h0, mem_rdata_i[15:0]};
            end
            else
            begin
              reg_wdata = {16'h0, mem_rdata_i[31:16]};
            end
          end
          default:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
          end
        endcase
      end


      7'b0100011:
      begin    // 7'b0100011
        case (funct3)
          3'b000:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            reg_wdata = 32'h0;
            mem_we = 1;
            mem_req = 1;
            mem_waddr_o = op1_add_op2_res;
            mem_raddr_o = op1_add_op2_res;
            case (mem_waddr_index)
              2'b00:
              begin
                mem_wdata_o = {mem_rdata_i[31:8], reg2_rdata_i[7:0]};
              end
              2'b01:
              begin
                mem_wdata_o = {mem_rdata_i[31:16], reg2_rdata_i[7:0], mem_rdata_i[7:0]};
              end
              2'b10:
              begin
                mem_wdata_o = {mem_rdata_i[31:24], reg2_rdata_i[7:0], mem_rdata_i[15:0]};
              end
              default:
              begin
                mem_wdata_o = {reg2_rdata_i[7:0], mem_rdata_i[23:0]};
              end
            endcase
          end
          3'b001:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            reg_wdata = 32'h0;
            mem_we = 1;
            mem_req = 1;
            mem_waddr_o = op1_add_op2_res;
            mem_raddr_o = op1_add_op2_res;
            if (mem_waddr_index == 2'b00)
            begin
              mem_wdata_o = {mem_rdata_i[31:16], reg2_rdata_i[15:0]};
            end
            else
            begin
              mem_wdata_o = {reg2_rdata_i[15:0], mem_rdata_i[15:0]};
            end
          end
          3'b010:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            reg_wdata = 32'h0;
            mem_we = 1;
            mem_req = 1;
            mem_waddr_o = op1_add_op2_res;
            mem_raddr_o = op1_add_op2_res;
            mem_wdata_o = reg2_rdata_i;
          end
          default:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
          end
        endcase
      end

      //					`define INST_BEQ    3'b000
      //`define INST_BNE    3'b001
      //`define INST_BLT    3'b100
      //`define INST_BGE    3'b101
      //`define INST_BLTU   3'b110
      //`define INST_BGEU   3'b111

      7'b1100011:
      begin   // 7'b1100011
        case (funct3)
          3'b000:
          begin
            hold_flag = 0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
            jump_flag = op1_eq_op2 & 1;
            jump_addr = {32{op1_eq_op2}} & op1_jump_add_op2_jump_res;
          end
          3'b001:
          begin
            hold_flag = 0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
            jump_flag = (~op1_eq_op2) & 1;
            jump_addr = {32{(~op1_eq_op2)}} & op1_jump_add_op2_jump_res;
          end
          3'b100:
          begin
            hold_flag = 0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
            jump_flag = (~op1_ge_op2_signed) & 1;
            jump_addr = {32{(~op1_ge_op2_signed)}} & op1_jump_add_op2_jump_res;
          end
          3'b101:
          begin
            hold_flag = 0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
            jump_flag = (op1_ge_op2_signed) & 1;
            jump_addr = {32{(op1_ge_op2_signed)}} & op1_jump_add_op2_jump_res;
          end
          3'b110:
          begin
            hold_flag = 0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
            jump_flag = (~op1_ge_op2_unsigned) & 1;
            jump_addr = {32{(~op1_ge_op2_unsigned)}} & op1_jump_add_op2_jump_res;
          end
          3'b111:
          begin
            hold_flag = 0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
            jump_flag = (op1_ge_op2_unsigned) & 1;
            jump_addr = {32{(op1_ge_op2_unsigned)}} & op1_jump_add_op2_jump_res;
          end
          default:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
          end
        endcase
      end

      //  `define INST_JAL    7'b1101111
      //  `define INST_JALR   7'b1100111
      //
      //  `define INST_LUI    7'b0110111
      //  `define INST_AUIPC  7'b0010111
      //  `define INST_NOP    32'h00000001
      //  `define INST_NOP_OP 7'b0000001
      //  `define INST_MRET   32'h30200073
      //  `define INST_RET    32'h00008067
      //
      //  `define INST_FENCE  7'b0001111
      //  `define INST_ECALL  32'h73
      //  `define INST_EBREAK 32'h00100073
      7'b1101111, 7'b1100111:
      begin
        hold_flag = 0;
        mem_wdata_o = 32'h0;
        mem_raddr_o = 32'h0;
        mem_waddr_o = 32'h0;
        mem_we = 0;
        jump_flag = 1;
        jump_addr = op1_jump_add_op2_jump_res;
        reg_wdata = op1_add_op2_res;
      end
      7'b0110111, 7'b0010111:
      begin
        hold_flag = 0;
        mem_wdata_o = 32'h0;
        mem_raddr_o = 32'h0;
        mem_waddr_o = 32'h0;
        mem_we = 0;
        jump_addr = 32'h0;
        jump_flag = 0;
        reg_wdata = op1_add_op2_res;
      end
      7'b0000001:
      begin
        jump_flag = 0;
        hold_flag = 0;
        jump_addr = 32'h0;
        mem_wdata_o = 32'h0;
        mem_raddr_o = 32'h0;
        mem_waddr_o = 32'h0;
        mem_we = 0;
        reg_wdata = 32'h0;
      end
      7'b0001111:
      begin
        hold_flag = 0;
        mem_wdata_o = 32'h0;
        mem_raddr_o = 32'h0;
        mem_waddr_o = 32'h0;
        mem_we = 0;
        reg_wdata = 32'h0;
        jump_flag = 1;
        jump_addr = op1_jump_add_op2_jump_res;
      end

      //   			// CSR inst
      //   `define INST_CSR    7'b1110011
      //   `define INST_CSRRW  3'b001
      //   `define INST_CSRRS  3'b010
      //   `define INST_CSRRC  3'b011
      //   `define INST_CSRRWI 3'b101
      //   `define INST_CSRRSI 3'b110
      //   `define INST_CSRRCI 3'b111

      7'b1110011:
      begin
        jump_flag = 0;
        hold_flag = 0;
        jump_addr = 32'h0;
        mem_wdata_o = 32'h0;
        mem_raddr_o = 32'h0;
        mem_waddr_o = 32'h0;
        mem_we = 0;
        case (funct3)
          3'b001:
          begin
            csr_wdata_o = reg1_rdata_i;
            reg_wdata = csr_rdata_i;
          end
          3'b010:
          begin
            csr_wdata_o = reg1_rdata_i | csr_rdata_i;
            reg_wdata = csr_rdata_i;
          end
          3'b011:
          begin
            csr_wdata_o = csr_rdata_i & (~reg1_rdata_i);
            reg_wdata = csr_rdata_i;
          end
          3'b101:
          begin
            csr_wdata_o = {27'h0, uimm};
            reg_wdata = csr_rdata_i;
          end
          3'b110:
          begin
            csr_wdata_o = {27'h0, uimm} | csr_rdata_i;
            reg_wdata = csr_rdata_i;
          end
          3'b111:
          begin
            csr_wdata_o = (~{27'h0, uimm}) & csr_rdata_i;
            reg_wdata = csr_rdata_i;
          end
          default:
          begin
            jump_flag = 0;
            hold_flag = 0;
            jump_addr = 32'h0;
            mem_wdata_o = 32'h0;
            mem_raddr_o = 32'h0;
            mem_waddr_o = 32'h0;
            mem_we = 0;
            reg_wdata = 32'h0;
          end
        endcase
      end
      default:
      begin
        jump_flag = 0;
        hold_flag = 0;
        jump_addr = 32'h0;
        mem_wdata_o = 32'h0;
        mem_raddr_o = 32'h0;
        mem_waddr_o = 32'h0;
        mem_we = 0;
        reg_wdata = 32'h0;
      end
    endcase
  end

endmodule

gen_diff.v

module gen_pipe_dff#(
    parameter DW = 32
  )(
    input    wire               clk        ,
    input    wire               rst_n      ,
    input    wire               hold_en    ,

    input    wire  [DW-1 : 0]   def_val    ,
    input    wire  [DW-1 : 0]   din        ,
    output   wire  [DW-1 : 0]   qout
  );

  reg [DW - 1 : 0]  qout_r  ;
  always@(posedge clk )
  begin
    if(rst_n == 0 | hold_en == 1)
    begin
      qout_r <= def_val ;
    end
    else
    begin
      qout_r <= din ;
    end
  end

  assign  qout = qout_r ;
endmodule

id_ex.v

module  id_ex(
    input                   rst_n               ,
    input                   clk                 ,

    //来自于id_ex的完全输入
    input   [31 : 0]        inst_i              ,
    input   [31 : 0]        inst_addr_i         ,
    input                   reg_we_i            ,
    input   [4  : 0]        reg_waddr_i         ,
    input   [31 : 0]        reg1_rdata_i        ,
    input   [31 : 0]        reg2_rdata_i        ,
    input                   csr_we_i            ,
    input   [31 : 0]        csr_waddr_i         ,
    input   [31 : 0]        csr_rdata_i         ,
    input   [31 : 0]        op1_i               ,
    input   [31 : 0]        op2_i               ,
    input   [31 : 0]        op1_jump_i          ,
    input   [31 : 0]        op2_jump_i          ,

    // 暂停设计
    input   [2  : 0]        hold_flag_i         ,   // 流水线暂停标志

    output   [31 : 0]        inst_o              ,
    output   [31 : 0]        inst_addr_o         ,
    output                   reg_we_o            ,
    output   [4  : 0]        reg_waddr_o         ,
    output   [31 : 0]        reg1_rdata_o        ,
    output   [31 : 0]        reg2_rdata_o        ,
    output                   csr_we_o            ,
    output   [31 : 0]        csr_waddr_o         ,
    output   [31 : 0]        csr_rdata_o         ,
    output   [31 : 0]        op1_o               ,
    output   [31 : 0]        op2_o               ,
    output   [31 : 0]        op1_jump_o          ,
    output   [31 : 0]        op2_jump_o
  );


  wire hold_en =   (hold_flag_i >= 3'b011)  ;

  // ---- 果然这样的组合要写13个
  // -------------------------------------
  wire [31 : 0] inst ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )inst_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 32'h00000001        ),      // 它其实是32'h0000_0001 我就是写成0
                .din      ( inst_i      ),
                .qout     ( inst    )
              );
  assign  inst_o  =  inst  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] inst_addr ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )inst_addr_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( inst_addr_i      ),
                .qout     ( inst_addr    )
              );
  assign  inst_addr_o  =  inst_addr  ;

  // ----------------------------------

  // -------------------------------------
  wire  reg_we ;
  gen_pipe_dff#(
                .DW       ( 1 )
              )reg_we_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 1'h0        ),
                .din      ( reg_we_i      ),
                .qout     ( reg_we    )
              );
  assign  reg_we_o  =  reg_we  ;

  // ----------------------------------

  // -------------------------------------
  wire [4 : 0] reg_waddr ;
  gen_pipe_dff#(
                .DW       ( 5 )
              )reg_waddr_dff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 5'h0        ),
                .din      ( reg_waddr_i      ),
                .qout     ( reg_waddr    )
              );
  assign  reg_waddr_o  =  reg_waddr  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] reg1_rdata ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )reg1_rdata_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 32'h0        ),
                .din      ( reg1_rdata_i      ),
                .qout     ( reg1_rdata    )
              );
  assign  reg1_rdata_o  =  reg1_rdata  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] reg2_rdata ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )reg2_rdata_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( reg2_rdata_i      ),
                .qout     ( reg2_rdata    )
              );
  assign  reg2_rdata_o  =  reg2_rdata  ;

  // ----------------------------------
  // -------------------------------------
  wire csr_we ;
  gen_pipe_dff#(
                .DW       ( 1 )
              )csr_we_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 1'h0        ),
                .din      ( csr_we_i      ),
                .qout     ( csr_we    )
              );
  assign  csr_we_o  =  csr_we  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] csr_waddr ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )csr_waddr_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( csr_waddr_i      ),
                .qout     ( csr_waddr    )
              );
  assign  csr_waddr_o  =  csr_waddr  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] csr_rdata ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )csr_rdata_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( csr_rdata_i      ),
                .qout     ( csr_rdata    )
              );
  assign  csr_rdata_o  =  csr_rdata  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] op1 ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )op1_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( op1_i      ),
                .qout     ( op1    )
              );
  assign  op1_o  =  op1  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] op2 ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )op2_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( op2_i      ),
                .qout     ( op2    )
              );
  assign  op2_o  =  op2  ;

  // ----------------------------------


  // -------------------------------------
  wire [31 : 0] op1_jump;
  gen_pipe_dff#(
                .DW       ( 32 )
              )op1_jump_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( op1_jump_i      ),
                .qout     ( op1_jump   )
              );
  assign  op1_jump_o  =  op1_jump  ;

  // ----------------------------------

  // -------------------------------------
  wire [31 : 0] op2_jump ;
  gen_pipe_dff#(
                .DW       ( 32 )
              )op2_jump_ff(
                .clk      ( clk      ),
                .rst_n    ( rst_n    ),
                .hold_en  ( hold_en  ),
                .def_val  ( 0        ),
                .din      ( op2_jump_i      ),
                .qout     ( op2_jump    )
              );
  assign  op2_jump_o  =  op2_jump  ;

  // ----------------------------------
endmodule

regs.v

module  regs(
    input                       clk            ,
    input                       rst_n          ,
    // from ex  在后续处理完成之后 写回reg
    input                       we_i           ,   // 使能 | 地址 | 标志
    input         [4 : 0]       waddr_i        ,
    input         [31 : 0]      wdata_i        ,

    // from jtag 用于调试
    input                       jtag_we_i      ,
    input         [4 : 0]       jtag_addr_i    ,
    input         [31 : 0]      jtag_data_i    ,
    output reg    [31 : 0]      jtag_data_o    ,
    // from id1
    input         [4 : 0]       raddr1_i       ,
    output reg    [31 : 0]      rdata1_o       ,
    // from id2
    input         [4 : 0]       raddr2_i       ,
    output reg    [31 : 0]      rdata2_o
  );

  reg [31 : 0] regs[0 : 31]  ;

  // 写寄存器的发射信号
  always@(posedge clk )
  begin
    if(rst_n == 1)
    begin
      // 先进行ex
      if((we_i == 1) && (waddr_i != 0))
      begin
        regs[waddr_i]      <=  wdata_i ;
      end
      else if((jtag_we_i == 1) && ( jtag_addr_i != 0))
      begin
        regs[jtag_addr_i]  <=  jtag_data_i ;
      end
    end
  end

  // 读寄存器1
  always @ (*)
  begin
    if (raddr1_i == 0)
    begin
      rdata1_o   <=   0;
      // 如果读地址等于写地址,并且正在写操作,则直接返回写数据
    end
    else if (raddr1_i == waddr_i && we_i == 1)
    begin
      rdata1_o   <=   wdata_i;
    end
    else
    begin
      rdata1_o   <=   regs[raddr1_i];
    end
  end


  // 读寄存器2
  always @ (*)
  begin
    if (raddr2_i == 0)
    begin
      rdata2_o    <=    0;
      // 如果读地址等于写地址,并且正在写操作,则直接返回写数据
    end
    else if (raddr2_i == waddr_i && we_i == 1)
    begin
      rdata2_o    <=    wdata_i;
    end
    else
    begin
      rdata2_o    <=    regs[raddr2_i];
    end
  end


  // jtag 读寄存器
  always@(*)
  begin
    if(jtag_addr_i == 0)
    begin
      jtag_data_o  <=  0  ;
    end
    else
    begin
      jtag_data_o  <=  regs[jtag_addr_i]  ;
    end
  end

endmodule

rib.v

//这一部分是RIB总线模块
module rib(

    input                               clk         ,
    input                               rst_n       ,

    //  主四   从六
    // master 0
    input          [31 : 0]             m0_addr_i   ,
    input          [31 : 0]             m0_data_i   ,
    output  reg    [31 : 0]             m0_data_o   ,
    input                               m0_req_i    ,
    input                               m0_we_i     ,

    // master 1
    input          [31 : 0]             m1_addr_i   ,
    input          [31 : 0]             m1_data_i   ,
    output  reg    [31 : 0]             m1_data_o   ,
    input                               m1_req_i    ,
    input                               m1_we_i     ,

    // master 2
    input          [31 : 0]             m2_addr_i   ,
    input          [31 : 0]             m2_data_i   ,
    output  reg    [31 : 0]             m2_data_o   ,
    input                               m2_req_i    ,
    input                               m2_we_i     ,

    // master 3
    input          [31 : 0]             m3_addr_i   ,
    input          [31 : 0]             m3_data_i   ,
    output  reg    [31 : 0]             m3_data_o   ,
    input                               m3_req_i    ,
    input                               m3_we_i     ,

    // slave 0
    output  reg    [31 : 0]             s0_addr_o   ,
    output  reg    [31 : 0]             s0_data_o   ,
    input          [31 : 0]             s0_data_i   ,
    output  reg                         s0_we_o     ,

    // slave 1
    output  reg    [31 : 0]             s1_addr_o   ,
    output  reg    [31 : 0]             s1_data_o   ,
    input          [31 : 0]             s1_data_i   ,
    output  reg                         s1_we_o     ,

    // slave 2
    output  reg    [31 : 0]             s2_addr_o   ,
    output  reg    [31 : 0]             s2_data_o   ,
    input          [31 : 0]             s2_data_i   ,
    output  reg                         s2_we_o     ,

    // slave 3
    output  reg    [31 : 0]             s3_addr_o   ,
    output  reg    [31 : 0]             s3_data_o   ,
    input          [31 : 0]             s3_data_i   ,
    output  reg                         s3_we_o     ,

    // slave 4
    output  reg    [31 : 0]             s4_addr_o   ,
    output  reg    [31 : 0]             s4_data_o   ,
    input          [31 : 0]             s4_data_i   ,
    output  reg                         s4_we_o     ,

    // slave 5
    output  reg    [31 : 0]             s5_addr_o   ,
    output  reg    [31 : 0]             s5_data_o   ,
    input          [31 : 0]             s5_data_i   ,
    output  reg                         s5_we_o     ,

    output  reg                         hold_flag_o
  );

  // 访问地址的最高4位确定要访问的
  parameter   [3 : 0]  slave_0  =  4'b0000   ;
  parameter   [3 : 0]  slave_1  =  4'b0001   ;
  parameter   [3 : 0]  slave_2  =  4'b0010   ;
  parameter   [3 : 0]  slave_3  =  4'b0011   ;
  parameter   [3 : 0]  slave_4  =  4'b0100   ;
  parameter   [3 : 0]  slave_5  =  4'b0101   ;

  parameter   [1 : 0]  grant0   =  2'h0      ;
  parameter   [1 : 0]  grant1   =  2'h1      ;
  parameter   [1 : 0]  grant2   =  2'h2      ;
  parameter   [1 : 0]  grant3   =  2'h3      ;

  wire    [3 : 0]  req    ;
  reg     [1 : 0]  grant  ;

  // 主设备请求信号
  assign  req = {m3_req_i , m2_req_i  , m1_req_i , m0_req_i } ;

  // 接下来配置的是仲裁优先级
  // 优先级顺序按照3-0-2 - 1
  always@(*)
  begin
    if(req[3] == 1)
    begin
      grant        =   grant3   ;  // 第三个
      hold_flag_o  =   1        ;
    end
    else if(req[0] == 1)
    begin
      grant        =   grant0   ;  // 第三个
      hold_flag_o  =   1        ;
    end
    else if(req[2] == 1)
    begin
      grant        =   grant2   ;  // 第三个
      hold_flag_o  =   1        ;
    end
    else 
    begin
      grant        =   grant1   ;  // 第三个
      hold_flag_o  =   0        ;
    end
  end


  // 根据仲裁结果选择 访问从机
  always@(*)
  begin
    m0_data_o     =      0      ;
    m1_data_o     =      0      ;
    m2_data_o     =      0      ;
    m3_data_o     =      0      ;

    // 从机
    s0_addr_o     =      0      ;
    s0_data_o     =      0      ;
    s0_we_o       =      0      ;

    s1_addr_o     =      0      ;
    s1_data_o     =      0      ;
    s1_we_o       =      0      ;

    s2_addr_o     =      0      ;
    s2_data_o     =      0      ;
    s2_we_o       =      0      ;

    s3_addr_o     =      0      ;
    s3_data_o     =      0      ;
    s3_we_o       =      0      ;

    s4_addr_o     =      0      ;
    s4_data_o     =      0      ;
    s4_we_o       =      0      ;

    s5_addr_o     =      0      ;
    s5_data_o     =      0      ;
    s5_we_o       =      0      ;

    case(grant)
      grant0 :
      begin
        case(m0_addr_i[31:28])
          slave_0 :
          begin
            s0_we_o      =     m0_we_i  ;
            s0_addr_o    =     {{4'h0} , {m0_addr_i[27 : 0]}} ;
            s0_data_o    =     m0_data_i     ;
            m0_data_o    =     s0_data_i     ;
          end
          slave_1 :
          begin
            s1_we_o      =     m0_we_i  ;
            s1_addr_o    =     {{4'h0} , {m0_addr_i[27 : 0]}} ;
            s1_data_o    =     m0_data_i     ;
            m0_data_o    =     s1_data_i     ;
          end

          slave_2 :
          begin
            s2_we_o      =     m0_we_i  ;
            s2_addr_o    =     {{4'h0} , {m0_addr_i[27 : 0]}} ;
            s2_data_o    =     m0_data_i     ;
            m0_data_o    =     s2_data_i     ;
          end

          slave_3 :
          begin
            s3_we_o      =     m0_we_i  ;
            s3_addr_o    =     {{4'h0} , {m0_addr_i[27 : 0]}} ;
            s3_data_o    =     m0_data_i     ;
            m0_data_o    =     s3_data_i     ;
          end

          slave_4 :
          begin
            s4_we_o      =     m0_we_i  ;
            s4_addr_o    =     {{4'h0} , {m0_addr_i[27 : 0]}} ;
            s4_data_o    =     m0_data_i     ;
            m0_data_o    =     s4_data_i     ;
          end

          slave_5 :
          begin
            s5_we_o      =     m0_we_i  ;
            s5_addr_o    =     {{4'h0} , {m0_addr_i[27 : 0]}} ;
            s5_data_o    =     m0_data_i     ;
            m0_data_o    =     s5_data_i     ;
          end

          default :
          begin

          end
        endcase
      end

      grant1 :
      begin
        case(m1_addr_i[31:28])
          slave_0 :
          begin
            s0_we_o      =     m1_we_i  ;
            s0_addr_o    =     {{4'h0} , {m1_addr_i[27 : 0]}} ;
            s0_data_o    =     m1_data_i     ;
            m1_data_o    =     s0_data_i     ;
          end
          slave_1 :
          begin
            s1_we_o      =     m1_we_i  ;
            s1_addr_o    =     {{4'h0} , {m1_addr_i[27 : 0]}} ;
            s1_data_o    =     m1_data_i     ;
            m1_data_o    =     s1_data_i     ;
          end

          slave_2 :
          begin
            s2_we_o      =     m1_we_i  ;
            s2_addr_o    =     {{4'h0} , {m1_addr_i[27 : 0]}} ;
            s2_data_o    =     m1_data_i     ;
            m1_data_o    =     s2_data_i     ;
          end

          slave_3 :
          begin
            s3_we_o      =     m1_we_i  ;
            s3_addr_o    =     {{4'h0} , {m1_addr_i[27 : 0]}} ;
            s3_data_o    =     m1_data_i     ;
            m1_data_o    =     s3_data_i     ;
          end

          slave_4 :
          begin
            s4_we_o      =     m1_we_i  ;
            s4_addr_o    =     {{4'h0} , {m1_addr_i[27 : 0]}} ;
            s4_data_o    =     m1_data_i     ;
            m1_data_o    =     s4_data_i     ;
          end

          slave_5 :
          begin
            s5_we_o      =     m1_we_i  ;
            s5_addr_o    =     {{4'h0} , {m1_addr_i[27 : 0]}} ;
            s5_data_o    =     m1_data_i     ;
            m1_data_o    =     s5_data_i     ;
          end

          default :
          begin

          end
        endcase
      end


      grant2 :
      begin
        case(m2_addr_i[31:28])
          slave_0 :
          begin
            s0_we_o      =     m2_we_i  ;
            s0_addr_o    =     {{4'h0} , {m2_addr_i[27 : 0]}} ;
            s0_data_o    =     m2_data_i     ;
            m2_data_o    =     s0_data_i     ;
          end
          slave_1 :
          begin
            s1_we_o      =     m2_we_i  ;
            s1_addr_o    =     {{4'h0} , {m2_addr_i[27 : 0]}} ;
            s1_data_o    =     m2_data_i     ;
            m2_data_o    =     s1_data_i     ;
          end

          slave_2 :
          begin
            s2_we_o      =     m2_we_i  ;
            s2_addr_o    =     {{4'h0} , {m2_addr_i[27 : 0]}} ;
            s2_data_o    =     m2_data_i     ;
            m2_data_o    =     s2_data_i     ;
          end

          slave_3 :
          begin
            s3_we_o      =     m2_we_i  ;
            s3_addr_o    =     {{4'h0} , {m2_addr_i[27 : 0]}} ;
            s3_data_o    =     m2_data_i     ;
            m2_data_o    =     s3_data_i     ;
          end

          slave_4 :
          begin
            s4_we_o      =     m2_we_i  ;
            s4_addr_o    =     {{4'h0} , {m2_addr_i[27 : 0]}} ;
            s4_data_o    =     m2_data_i     ;
            m2_data_o    =     s4_data_i     ;
          end

          slave_5 :
          begin
            s5_we_o      =     m2_we_i  ;
            s5_addr_o    =     {{4'h0} , {m2_addr_i[27 : 0]}} ;
            s5_data_o    =     m2_data_i     ;
            m2_data_o    =     s5_data_i     ;
          end

          default :
          begin

          end
        endcase
      end

      grant3 :
      begin
        case(m3_addr_i[31:28])
          slave_0 :
          begin
            s0_we_o      =     m3_we_i  ;
            s0_addr_o    =     {{4'h0} , {m3_addr_i[27 : 0]}} ;
            s0_data_o    =     m3_data_i     ;
            m3_data_o    =     s0_data_i     ;
          end
          slave_1 :
          begin
            s1_we_o      =     m3_we_i  ;
            s1_addr_o    =     {{4'h0} , {m3_addr_i[27 : 0]}} ;
            s1_data_o    =     m3_data_i     ;
            m3_data_o    =     s1_data_i     ;
          end

          slave_2 :
          begin
            s2_we_o      =     m3_we_i  ;
            s2_addr_o    =     {{4'h0} , {m3_addr_i[27 : 0]}} ;
            s2_data_o    =     m3_data_i     ;
            m3_data_o    =     s2_data_i     ;
          end

          slave_3 :
          begin
            s3_we_o      =     m3_we_i  ;
            s3_addr_o    =     {{4'h0} , {m3_addr_i[27 : 0]}} ;
            s3_data_o    =     m3_data_i     ;
            m3_data_o    =     s3_data_i     ;
          end

          slave_4 :
          begin
            s4_we_o      =     m3_we_i  ;
            s4_addr_o    =     {{4'h0} , {m3_addr_i[27 : 0]}} ;
            s4_data_o    =     m3_data_i     ;
            m3_data_o    =     s4_data_i     ;
          end

          slave_5 :
          begin
            s5_we_o      =     m3_we_i  ;
            s5_addr_o    =     {{4'h0} , {m3_addr_i[27 : 0]}} ;
            s5_data_o    =     m3_data_i     ;
            m3_data_o    =     s5_data_i     ;
          end

          default :
          begin

          end
        endcase
      end
      default :
      begin
      end
    endcase
  end

endmodule

readme.md

本设计创建于2024年11月7日 预计完成时间2025年1月1日

支持RV32IM指令集 所以指令集的扩展是来自于RV32IM

一开始书写的是pc_reg 用于地址的把控跳转

if_id更像是一个中介模块 用于传递ROM的信息给下一级id的
gen_pipe_dff 来自于 gen_diff.v

2024年11月14日 continue

  1. CSR是特权寄存器 其中的CSR是特权指令集中的一部分
  2. 在这一个操作中虽然我暂时不知道这个的内容,但是我知道地址 我是阻塞赋值,所以我在前面把rs1给到reg1_raddr_o 过一会就会把reg1_rdada_i的值拿回来
  3. | opcode (7) | rd (5) | funct3 (3) | rs1 (5) | rs2 (5) | funct7 (7) |
    4.指令 功能描述
    CSRRW 将寄存器 rs1 的值写入 CSR,同时将 CSR 原值写入目标寄存器 rd。
    CSRRS 读取 CSR 原值并将其写入 rd,同时将 CSR 的指定位(由 rs1 指定)置 1。
    CSRRC 读取 CSR 原值并将其写入 rd,同时将 CSR 的指定位清 0。
    CSRRWI 与 CSRRW 类似,但立即数(imm)代替 rs1 作为写入 CSR 的值。
    CSRRSI 与 CSRRS 类似,但立即数(imm)代替 rs1 作为位掩码。
    CSRRCI 与 CSRRC 类似,但立即数(imm)代替 rs1 作为位掩码。

2024年11月20日 continue 开始写的是

2024年11月28日 continue

好久没看了 先去对整体的各个模块复习一下 -我觉得 这周能写的挺多的 28日周四

在pc_reg.v 中的
else if(hold_flag_i >= 3’b001 )
begin
pc_o <= pc_o ; // 这就是暂停保持的

这一段的代码 是为了后续流水线设置的方便
有人会问为什么设置了3bit 暂停而不是设置为1bit 因为后续的暂停标志位需要被if_id 和 id_ex使用
后续防线设置的阈值比001高 这样后面停PC就会被停下来 一级控制着一级 这就是三级流水线的定义

if_id 是流水线的暂存

reg是通用寄存器 reg模块里面的 两个寄存器意思指 一条指令里有可能会同时读取两个寄存器的值

regs.v 中的代码

else if (raddr2_i == waddr_i && we_i == 1)
begin
  rdata2_o    <=    wdata_i;
end

原因在于可能会有 译码阶段可能会需要用到上一条指令的结果
add x1 , x2 , x3
add x4 , x1 , x5

id.v是单纯的译码阶段的工作
— 11.28目前工作是 id_ex.v
这个模块的作用跟我想的一样 是作为过渡作用的 和 if_id 是用来传递存储到ex的信息的
// to ex
output reg [31 : 0] op1_o ,
output reg [31 : 0] op2_o ,
output reg [31 : 0] op1_jump_o ,
output reg [31 : 0] op2_jump_o ,
output reg [31 : 0] inst_o ,
output reg [31 : 0] inst_addr_o , // 指令地址
output reg [31 : 0] reg1_rdata_o , // 通用寄存器1数据
output reg [31 : 0] reg2_rdata_o , // 通用寄存器2数据
output reg reg_we_o , // 写通用寄存器标志
output reg [4 : 0] reg_waddr_o , // 写通用寄存器地址
output reg csr_we_o , // 写CSR寄存器标志
output reg [31 : 0] csr_rdata_o , // CSR寄存器数据
output reg [31 : 0] csr_waddr_o // 写CSR寄存器地址
就是这个


clint 的作用是 核心本地中断模块,对输入的中断请求信号进行总裁,产生最终的中断信号

2024年 11月29日

在编写 clint.v 模块
外设产生的中断信号与处理器的CSR寄存器紧密结合,共同构成了中断管理和中断响应机制。通过 CSR 寄存器的操作,系统能够记录中断的原因、保存当前的执行状态,并根据需要使能或屏蔽中断。这一过程确保了中断能够按预期进行处理,且在处理完中断后,处理器能够从正确的位置恢复并继续执行。

在你的系统架构中,clint 模块就是用来处理这些中断请求,并与 CSR 寄存器交互的核心组件,而 CSR 寄存器则承担了中断的状态管理和控制任务。

所以 clint是专门处理中断控制与管理的模块,负责与CSR寄存器相关联

为什么这个设计放在了第二阶段 ?
因为 中断是一个外部事件,通常是异步的,即它的发生时刻并不一定与指令的执行同步。在处理器流水线中,中断需要在适当的时机被捕获和响应,而选择在 ID 阶段进行中断的处理有助于确保中断能够及时响应,同时避免干扰指令的正常执行

问答? 还是有点疑惑的地方 就是说clint处理两种不同的中断嘛 一种是指令本身提供的中断 还有一种是外设提供的嘛?指令的中断从id解析出来之后反正都会传递给csr_reg 然后再给到clint 而 还有一种是外设的中断 这种需要clint写完传递给 csr_reg嘛 ???
–>
因此,clint 在处理中断时,确实需要通过 csr_reg 读取和更新中断相关的寄存器,如 mtvec(中断向量)、mepc(中断返回地址)和 mcause(中断原因)。而外设中断(来自 int_flag_i)也是通过 clint 来处理和管理,最终影响 csr_reg 中的寄存器,指导处理器如何跳转到中断处理程序。

所以,整体上你的理解是对的,clint 处理的是两类中断:指令中断和外设中断,并且它依赖于 csr_reg 来管理中断状态的保存和恢复。

理解之后 我决定先编写 csr_reg.v

问题 : ? 所以说ex是一个唯一的处理阶段的模块,处理了中断的信息,中断需要操作都经由ex模块来完成,clint是一个中断仲裁分析模块,会把外部的外设 指令的信息接收处理了 还给csr_reg 寄存器,最后由ex模块接收到详细处理嘛

–>
ex 模块是唯一的处理阶段模块,负责执行指令并处理与中断、异常相关的操作。
clint 是外部中断的控制器,它接收外设中断信号并将其信息传递给 csr_reg,然后 ex 模块在执行时根据这些信息进行中断处理。
csr_reg 存储与中断、异常相关的控制状态信息,而 ex 模块会根据这些信息执行实际的中断处理逻辑。

问题 : 为什么在写csr寄存器的时候会优先响应ex写模块 ?
–>
中断和异常处理可能会影响执行:当处理器需要处理中断或异常时,它会修改一些控制寄存器。这个修改必须在当前指令执行完后进行。也就是说,EX阶段的修改优先级更高,因为它关系到当前指令是否能顺利执行。比如,如果发生中断时,必须知道从哪里跳转到异常处理函数(mepc),但这是在指令执行完毕之后才处理的。

问题 : 所以这里是有变换的先后要求的嘛 先是保证除法的正常进行 然后是同步的指令 然后是core的外部中断吗 ?
–>
首先,需要确保除法指令等较长周期操作的完成,因此在除法未完成时,不会处理中断。
其次,优先处理中同步中断(如 ECALL、EBREAK),这些通常与程序的控制流相关,可能是系统调用或异常。
然后,处理外部的异步中断(来自硬件或外部设备),这些通常在同步中断后处理。
最后,处理 MRET 指令,恢复到机器模式继续执行。

问题 : 所以跳转中断处理是一个设定的特殊的地址 特殊的指令 包括特殊的 信息,PC是会不断自增的 jump_addr_i 的值在ex阶段会被确定成需要跳转的中断处理地址 ,但是 PC是会不断自增+4 的 ,所以回退一个位置,这样在处理的时候jump的地址就会是需要跳转的地址了 ?
—>
—>
这里的东西 我先按下不表 等我看到后面分析的时候自然而然懂了
我的理解是这样的
GPT 也觉得我的没问题
jump_addr_i - 4 是为了确保跳转到中断处理程序时,从发生中断的正确位置继续执行。
跳转的目标地址 jump_addr_i 是由中断向量表决定的,通常是中断处理程序的入口。
在 EX 阶段,处理器决定了跳转地址,而跳转到中断处理程序时需要回退 4 字节,因为 PC 是自动自增的。


2024年11月30日 -> 2024年12月1日 对前模块进行小总结

稍微带入一点整体的思想观念
注意 在id模块 – J型指令中 有这么一段代码
7’b1100_111 : // JALR 功能:PC = (rs1 + imm) & ~1,并将下一条指令地址存入 rd。
begin
reg_we_o = 1 ;
reg_waddr_o = rd ;
reg1_raddr_o = rs1 ;
reg2_raddr_o = 0 ;
op1_o = inst_addr_i ;
op2_o = 32’h4 ;
op1_jump_o = reg1_rdata_i ;
op2_jump_o = {{20{inst_i[31]}}, inst_i[31:20]};
end
这里所说的 op1_o 和 op2_o 是操作数
用这两个数值 来计算出 rd的值 inst_addr_i + 4 是下一条指令的地址
op1_jump_o 与 op2_jump_o操作 的得到 下一条指令的内容

  ---注明 读寄存器 不需要判断信号 直接读就可以了 
  问题 : 为什么已经传递了op1 op1_jump_o 等信息 还要把 寄存器的数据 reg1_rdata_o给ex模块?
  --> 回答: 
  将寄存器的数据 reg1_rdata_o 和 reg2_rdata_o 也传递给 EX 模块,是为了提供灵活性,允许在 EX 阶段根据指令的具体需求直接使用原始的寄存器数据。这种设计既考虑了性能优化,又兼顾了流水线设计的实际需求。
  如果流水线遇到特殊情况(例如复杂指令),EX 阶段可以直接使用寄存器的原始数据,而无需回退到 ID 阶段重新解码。

OK OK 我对中断充满了很多的疑问 我准备等 ex.v 完全结束之后开始了解这中断变换的含义

2024年12月1日 开始写执行模块

2024年 12月2日 开始编写执行模块

2024年 12月4日 备受折磨的12月 开始继续 ex模块的书写

2024年12月9日 继续进行ex.v模块的编写

问题? 没听懂字节对齐的含义 因为reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:20]} 这不是一个32位的数嘛 这是内存的地址嘛 ? 是不是因为内存的数据都是32位访问的 所以地址是4字节4字节变换的,所以传入的非4的倍数 就是定位到内存的哪一个具体的八位嘛 ?

回答 : 是的,你的理解正在接近正确!

参数的含义
jump_flag 跳转信号
hold_flag 跳转信号
jump_addr 跳转信号
mem_wdata_o 内存
mem_raddr_o
mem_waddr_o
mem_we
reg_wdata 寄存器数据信号

2024年12月11日 继续ex.v的编写

对于模块的第755行 其中 写成 jump_addr = {32{op1_eq_op2}} & op1_jump_add_op2_jump_res; 是为了一个保护作用
当不触发时,跳转地址设置到了保护的0
0 可以作为一个特殊寄存器的存在专门用来存储复位的信息情况

观察后面写的几个程序 才发现前面id分解的时候 全部拆开写的重要性

— 2024年12.11 21:43 结束到 CSR寄存器
希望明天上午把ex里面的 CSR寄存器搞完 和前面关系搞清楚
最后再检查一遍 下班

2024年12月12日 继续ex.v的CSR编写

问题 : 我现在有一个问题 就是 除法指令也都是写入reg寄存器的嘛 因为这里的复位的时候给reg_wdata 和 div_wdata都给0 所以本质上这两个数据再一条指令处理的时候不会赋值 ?
回答 : 关键: 在一个周期内,这两个信号 只能有一个有效数据源,不会出现两个同时非零的情况


现在开始讲述一下之前没懂的几个问题

解析

在clint 的第83行 if(inst_i == 32’h0000_0073 || inst_i == 32’h0010_0073)
这两个指令是直接从ROM中读出来的 系统指令
ECALL 和 EBACK

2024年12月14日 经过那么长时间的学习 终于把这个问题给搞清楚

我的理解 :
所以 我来说一下 我的理解 ,现在说同步中断的概念,首先假设输入的上一条是跳转指令,首先在系统内部会有关于clint 包括csr_reg寄存的读写的信息的,这是系统的概念,这一部分的执行,完全依靠于ex模块的读取和写入,和其他的具体具体跳转没有任何关系,接下来假设上一条的是跳转指令,因为是三级流水线的概念,所以clint的输入来自于id,其实是 ex阶段的下一个指令,所以当输入ecall指令时候,会立即读取csr_reg 寄存器中的信息,这些信息是由一开始就是我上面说的那段话传递进去的,接下来的会在这个阶段上把地址mevpc通过ex阶段完全发送给pc ,这时候并不会暂停流水线,会根据这个指令完成设计,接下来是当指令完成之后会重新回到ret保存的地址,因为Pc会自动+4 ,对于原来的指令Inst+4 就把当前的这个中断指令跳过了,对于上一条是jump的指令,那么这里-4也很合理了

GPT : 你的理解是很清晰的!让我总结并补充一下你说的内容,确保概念清晰

吃饭去了 接下来速速的完成其他模块的编写

2024年12月14日 这次编写的是 同为ex阶段的ctrl模块

ctrl 在了解清楚另外几个模块之后

现在编写div模块 就是 ex后面的除法单元

这边介绍一下试熵法的原理和使用规范


试熵法的基本步骤:**

  1. 初始化:**
    被除数(Dividend)和除数(Divisor)被加载到寄存器中。
    商(Quotient)和余数(Remainder)寄存器清零
  2. 试商(Trial Division):**
    从被除数中提取一个对应除数长度的高位部分,称为“被减数”(Minuend)。
    假设当前位的商为1,并尝试执行 减法运算:
    ( \text{Minuend} - \text{Divisor} \
  3. 判断结果:**
    如果减法结果为非负,则 试商成功,当前位的商值为1。
    如果减法结果为负,则 试商失败,恢复之前的被减数,当前位的商值为0
  4. 商寄存器更新:**
    将当前商位移入商寄存器,余数寄存器存储减法的结果(如果减法成功)
  5. 重复步骤 2 - 4:**
    对被除数的下一个最高位重复上述过程,直到处理完成
  6. 最终结果:**
    商寄存器中保存最终商值。
    余数寄存器中保存剩余的余数。

示例:
假设我们要计算 ( 1011_2 \div 10_2 )(即 11 除以 2)。

步骤:

  1. 初始被除数:1011,除数:10
  2. 提取最高位,得到 10,尝试减去 10,成功,商位为 1
  3. 移位提取下一位 1,组合成 01,无法减去 10,商位为 0
  4. 提取最后一位 1,组合成 11,减去 10 成功,商位为 1

最终结果:

  • 商:101_2(即 5
  • 余数:01_2(即 1

试商的除法 就是现实版的长除法的使用
自己拿笔推一下就出来了

2024年12月15日 上面的设计基本完成了

剩下top顶层 还有 rib总线的书写
现在是17:14先去吃饭
回来完成 rib总线的部分处理
完成之后 全部内容 检查一遍开始撰写top

2024年12月16日 下面该到了 tinyriscv的顶层模块的设计了

现在是北京时间2024年12月16日 完成了整个的主模块 risc-v的撰写
还剩下粗略15天 用来完成其他部分的书写

先去完成 外设的部分的设计

2024年12月16日

下面先进行 6个外设的设计
ROM
RAM
timer
uart_tx
gpio
spi

啊啊啊啊回归了

2024年12月22日 经过了长时间的蛰伏该到了

不会12月底来不及完成吧
先抓紧了

问题 : ok 我不懂的就是这个图上为什么说 ROM的大小是256MB,给他分配了 0x0000_0000到0x1000_0000的呢 ?
物理 ROM 实际大小可能远小于 256MB,比如你的设计中实际只有 16KB (4096 × 4B) 的 ROM。
剩余未用的空间是为了方便扩展或地址解码简化而划分出来的。

问题 : 那我有一个问题 就是说如何 准确完成CPU的处理,再解析C语言的时候就规定了你的 举例0x1000_0000到0x2000_0000是GPIO这样子嘛 ?
这个问题我想起来了,在C语言的define中 确实有这样的定义 ,
C 语言中,通过指针直接访问这些映射地址。例如 GPIO 寄存器的定义如下:

c
复制代码
#define GPIO_BASE 0x40000000 // GPIO 基地址
#define GPIO_DIR (volatile unsigned int)(GPIO_BASE + 0x00) // 方向寄存器
#define GPIO_OUT (volatile unsigned int)(GPIO_BASE + 0x04) // 输出寄存器
#define GPIO_IN (volatile unsigned int)(GPIO_BASE + 0x08) // 输入寄存器
示例操作:

c
复制代码
void gpio_init() {
GPIO_DIR = 0xFF; // 将所有 GPIO 设置为输出
}

void gpio_set(uint32_t value) {
GPIO_OUT = value; // 设置 GPIO 输出值
}

uint32_t gpio_read() {
return GPIO_IN; // 读取 GPIO 输入值
}
解析:

寄存器地址计算: 通过基地址 + 偏移量定义具体寄存器。
volatile 关键字: 确保每次访问直接读写硬件地址,而不是缓存值。


疑惑解除 开始继续工作

timer模块的作用
基于输入时钟信号进行计数,当计数值达到预设值时触发一个 中断信号,实现定时器功能。

飞快 现在在 使用 uart 端口

uart 有点长 所以先弄 gpio 吧 弄 GPIO的时候 感觉 死去的记忆在攻击我了

现在写完了 gpio 再写 uart

2024年12月23日 继续完成uart外设的编写

问题 : 是不是这个意思 下降沿呢 是和外面交流接收的 ,再在这里设计上升沿 是为了给下面uart传入寄存器做准备的 ?
是的,你的理解非常正确!

完成uart模块

2024年 12月23日 ----- spi.v 继续做另一个外设的设计

2024年 12月25日 ----- 继续spi

问题 : 那么其实说到底,同步进行输入输出的 并不是同一批数据喽 ?
回答 : 没错!

问题 : 那么我有一个问题 ,就是这里没有握手 或者数据对齐的功能 而且这个spi是不断的传输的,那么万一传输错误了 错就错了 是这个意思嘛 ?
回答 : 是的,你理解得完全正确!

CPOL 和 CPHA 控制具体行为
模式 CPOL CPHA 时钟空闲状态 采样边沿 输出边沿
模式 0 0 0 低电平 上升沿 (clock=1) 下降沿 (clock=0)
模式 1 0 1 低电平 下降沿 (clock=0) 上升沿 (clock=1)
模式 2 1 0 高电平 下降沿 (clock=0) 上升沿 (clock=1)
模式 3 1 1 高电平 上升沿 (clock=1) 下降沿 (clock=0)
示例分析:CPOL = 0, CPHA = 0(模式 0)
**时钟空闲状态:**低电平。
**数据输出:**下降沿 (clock=0) 更新 MOSI。
**数据采样:**上升沿 (clock=1) 从 MISO 读取数据

2024年12月25日 21:31 目前完成的进度是外设全部书写完毕

明天开始对uart模块进行创作
我把整个jtag删去了 因为我手头没有对JTAG的调试工具
把这个完成应该就差不多了
over 加油

2024年12月26日 开始编写其中使用的 UART_DEBUG 下载单元

状态机的第一步是往 UART的ctrl 地址 写入 3也就 11 表示
启用了TX使能 和 RX 使能

问题 : 那么对于下载而言的话 ,这个写入UART 的我看就是一个输出信号 是专门用来配置连接到FPGA上的UART串口模块吗 ?
回答 : 这段代码中的 UART 配置和数据传输信号 是用来控制连接到 FPGA 上的 UART 串口模块 的。

问题 : 这个地址status_reg是什么作用的 ,为什么写完首位就要清除接收溢出标志,这个状态寄存器有什么作用 ?
回答 : 第一步:
将地址 mem_addr_o 设置为 UART_STATUS_REG,准备访问状态寄存器。

第二步:
写入数据 32’h0,清除所有错误标志,包括溢出标志。

第三步:
写使能 mem_we_o 设置为 1,确保写入数据有效。

第四步:
状态机进入 S_WAIT_BYTE,开始等待 UART 模块接收新的字节数据。

位位置 标志名称 描述
0 TX_EMPTY_FLAG 发送 FIFO 空标志,表示发送缓冲区为空,可以写入新数据。
1 RX_FULL_FLAG 接收 FIFO 满标志,表示接收缓冲区已满,需要读取数据以避免溢出。
2 RX_OVER_FLAG 接收溢出标志,表示在读取数据之前 UART 收到更多数据,导致数据丢失。
3 PARITY_ERROR_FLAG 奇偶校验错误标志,接收数据时检测到校验错误。
4 FRAME_ERROR_FLAG 帧错误标志,接收数据的起始位或停止位异常。
5 BREAK_DETECT_FLAG 中断检测标志,检测到线路上出现中断信号。
其他位 保留位 未来扩展或保留位,默认忽略。

-> 问题 : ok 我明白了我们这个uart其实是跟外部的连接到FPGA端口的这个连接器的uart模块,我们读取的也就是这里的uart寄存器的信息,一旦上位机发起写入信号,那么其实这个的uart的寄存器的某些位就会发生变换,所以其实我们读取的是这个变化信息 ?
回答 ;
没错,你理解得很准确!

2024年12月26日 差不多可以说是结束了 现在把顶层写好找个tb验证一下

2024年12月27日 我还是怂了 我现在要把这个的JTAG端口加上去了 不然真的没法调试了

我没看 但是把jtag_dm.v这个模块先抄上去
这里面用到了 full_handshake_rx.v
– full_handshake_rx.v
– 现在加上 fuull_handshake_tx.v
– 加上了 jtag_top.v
–.–.–.–.—.----
再做一个合集把 剩下的几个module 写进去

2024年12月27日

准备把代码进行替换验证了
第一次
if_id 原代码 修改了
这个官方的 tb里 我把 最后的rst换成了rst_n
id 原代码也修改了
tinyrisc.v修改
tinyriscvsoc.v 修改

第二次
修改了id_ex

第三次
修改 tinyriscv.v

2024年12月28日 基本完成功能

其他的几个外设 我懒得去验证了 到时候想用直接拿过来
对于RTL部分核心的代码是完全无误的

2024.11.7 —> 2024.12.28