RISC-V MCU中文社区

【分享】 浮点寄存器的添加

发表于 开源蜂鸟E203 2023-05-22 10:04:16
0
1429
1

小组编号:CICC3327
浮点寄存器和整数寄存器是计算机体系结构中的两种不同类型的寄存器。
相较于整数寄存器,浮点寄存器专门用来进行浮点数运算。在计算机中,浮点数是一种用于表示实数的数值类型,它可以表示具有小数点的数字。而整数则是没有小数点的数值类型。
浮点寄存器通常比整数寄存器更大,因为浮点数需要更多的位数来表示。例如,在32位浮点单精度格式中,浮点寄存器通常使用32位。而在32位整数格式中,整数寄存器只需使用32位。

此外,浮点寄存器通常需要更高的处理速度,因为浮点数运算通常比整数运算更加复杂。因此,处理器通常配备了专用的浮点单元来执行浮点数运算,并拥有独立的浮点寄存器文件用于存储浮点数据。
蜂鸟e203自带整数型寄存器,代码和注释如下:

// 定义 e203_exu_regfile 模块
module e203_exu_regfile(
// 定义读端口src1和src2的索引和数据输出端口
input  [E203_RFIDX_WIDTH-1:0] read_src1_idx,   input  [E203_RFIDX_WIDTH-1:0] read_src2_idx,
output [E203_XLEN-1:0] read_src1_dat,   output [E203_XLEN-1:0] read_src2_dat,

// 定义写端口数据输入端口和写使能信号和数据端口
input  wbck_dest_wen,
input  [E203_RFIDX_WIDTH-1:0] wbck_dest_idx,   input  [E203_XLEN-1:0] wbck_dest_dat,

// 定义输出x1_r端口
output [`E203_XLEN-1:0] x1_r,

// 定义测试模式和时钟和复位信号
input  test_mode,
input  clk,
input  rst_n
);

// 定义寄存器堆读端口和写使能信号
wire [E203_XLEN-1:0] rf_r [E203_RFREG_NUM-1:0];
wire [`E203_RFREG_NUM-1:0] rf_wen;

ifdef E203_REGFILE_LATCH_BASED //{   // 如果采用锁存器方式,则定义写入数据经过D触发器缓存后再写入寄存器堆   wire [E203_XLEN-1:0] wbck_dest_dat_r;
sirv_gnrl_dffl #(E203_XLEN) wbck_dat_dffl (wbck_dest_wen, wbck_dest_dat, wbck_dest_dat_r, clk);   // 定义时钟使能信号   wire [E203_RFREG_NUM-1:0] clk_rf_ltch;
`endif//}

// 生成固定数量的寄存器堆,x0为常数0,不可写入,其余寄存器根据输入写入
genvar i;
generate //{
for (i=0; i<`E203_RFREG_NUM; i=i+1) begin:regfile//{
 if(i==0) begin: rf0
        // x0不能被写入,设置写使能信号为0
        assign rf_wen[i] = 1'b0;
        // x0为常数0
        assign rf_r[i] = `E203_XLEN'b0;
      `ifdef E203_REGFILE_LATCH_BASED //{
        assign clk_rf_ltch[i] = 1'b0;
      `endif//}
    end
    else begin: rfno0
        // 根据写使能信号和索引判断是否写入
        assign rf_wen[i] = wbck_dest_wen & (wbck_dest_idx == i) ;
      `ifdef E203_REGFILE_LATCH_BASED //{
        // 如果采用锁存器方式,则需要添加时钟门电路和锁存器
        e203_clkgate u_e203_clkgate(
          .clk_in  (clk  ),
          .test_mode(test_mode),
          .clock_en(rf_wen[i]),
          .clk_out (clk_rf_ltch[i])
        );
            // 写使能信号经过时钟门控制锁存器读入数据
        sirv_gnrl_ltch #(`E203_XLEN) rf_ltch (clk_rf_ltch[i], wbck_dest_dat_r, rf_r[i]);
      `else//}{
        // 如果采用D触发器方式,则写使能信号经过D触发器控制写入数据
        sirv_gnrl_dffl #(`E203_XLEN) rf_dffl (rf_wen[i], wbck_dest_dat, rf_r[i], clk);
      `endif//}
    end

  end//}
endgenerate//}

// 将读取到的数据输出到对应端口
assign read_src1_dat = rf_r[read_src1_idx];
assign read_src2_dat = rf_r[read_src2_idx];

// 定义所有寄存器变量,用于其他模块访问
wire  [E203_XLEN-1:0] x0  = rf_r[0];  wire  [E203_XLEN-1:0] x1  = rf_r[1];
wire  [E203_XLEN-1:0] x2  = rf_r[2];  wire  [E203_XLEN-1:0] x3  = rf_r[3];
wire  [E203_XLEN-1:0] x4  = rf_r[4];  wire  [E203_XLEN-1:0] x5  = rf_r[5];
wire  [E203_XLEN-1:0] x6  = rf_r[6];  wire  [E203_XLEN-1:0] x7  = rf_r[7];
wire  [E203_XLEN-1:0] x8  = rf_r[8];  wire  [E203_XLEN-1:0] x9  = rf_r[9];
wire  [E203_XLEN-1:0] x10 = rf_r[10];  wire  [E203_XLEN-1:0] x11 = rf_r[11];
wire  [E203_XLEN-1:0] x12 = rf_r[12];  wire  [E203_XLEN-1:0] x13 = rf_r[13];
wire  [E203_XLEN-1:0] x14 = rf_r[14];  wire  [E203_XLEN-1:0] x15 = rf_r[15];
ifdef E203_RFREG_NUM_IS_32 //{   wire  [E203_XLEN-1:0] x16 = rf_r[16];
wire  [E203_XLEN-1:0] x17 = rf_r[17];  wire  [E203_XLEN-1:0] x18 = rf_r[18];
wire  [E203_XLEN-1:0] x19 = rf_r[19];  wire  [E203_XLEN-1:0] x20 = rf_r[20];
wire  [E203_XLEN-1:0] x21 = rf_r[21];  wire  [E203_XLEN-1:0] x22 = rf_r[22];
wire  [E203_XLEN-1:0] x23 = rf_r[23];  wire  [E203_XLEN-1:0] x24 = rf_r[24];
wire  [E203_XLEN-1:0] x25 = rf_r[25];  wire  [E203_XLEN-1:0] x26 = rf_r[26];
wire  [E203_XLEN-1:0] x27 = rf_r[27];  wire  [E203_XLEN-1:0] x28 = rf_r[28];
wire  [E203_XLEN-1:0] x29 = rf_r[29];  wire  [E203_XLEN-1:0] x30 = rf_r[30];
wire  [E203_XLEN-1:0] x31 = rf_r[31];  endif//}

// 将x1的数值输出到x1_r端口
assign x1_r = rf_r[1];

endmodule

由整数寄存器的组织形式,我们可以仿照得出浮点寄存器的组织形式,该模块使用了generate语句生成了一组固定数量的浮点寄存器,并且定义了从寄存器文件中读取数据和向寄存器文件写入数据的逻辑。
在每个时钟周期中,通过读取读端口指定的寄存器索引来获取对应的寄存器值,并将其输出到read_src1_dat和read_src2_dat输出端口。同时,如果写端口使能,该模块会根据写端口的索引和写入数据更新相应的寄存器值。

需要注意的是,与整数寄存器不同,常数0所表示的浮点数通常是非零的,因此在这段代码中x0不能被写入。在这里,模块通过将rf_wen[0]设置为0来禁止对x0的写入,并将rf_r[0]设置为0以保持它的常数值。代码如下:

genvar i;
generate
  // 生成固定数量的浮点寄存器文件
  for (i=0; i<`E203_RFREG_NUM; i=i+1) begin:regfile
    if(i==0) begin: rf0
      // x0不能被写入,值保持为常数0
      assign rf_wen[i] = 1'b0;
      assign rf_r[i] = `E203_FLEN'b0;
      `ifdef E203_REGFILE_LATCH_BASED
        // 基于锁存器的寄存器文件需要时钟信号
        assign clk_rf_ltch[i] = 1'b0;
      `endif
    end
    else begin: rfno0
      // 根据写端口的索引和写入数据更新相应的寄存器值
      assign rf_wen[i] = wbck_dest_wen & (wbck_dest_idx == i) ;
      `ifdef E203_REGFILE_LATCH_BASED
        // 基于锁存器的寄存器文件需要时钟门电路
        e203_clkgate u_e203_clkgate(
          .clk_in  (clk  ),
          .test_mode(test_mode),
          .clock_en(rf_wen[i]),
          .clk_out (clk_rf_ltch[i])
        );
            //从write-enable到clk_rf_ltch到rf_ltch
        sirv_gnrl_ltch #(`E203_FLEN) rf_ltch (clk_rf_ltch[i], wbck_dest_dat_r, rf_r[i]);
      `else
        // D触发器实现的寄存器文件
        sirv_gnrl_dffl #(`E203_FLEN) rf_dffl (rf_wen[i], wbck_dest_dat, rf_r[i], clk);
      `endif
    end
  end
endgenerate

// 从寄存器文件中读取数据的逻辑
assign read_src1_dat = rf_r[read_src1_idx];
assign read_src2_dat = rf_r[read_src2_idx];
assign read_src3_dat = rf_r[read_src3_idx];
喜欢1
用户评论
studying_drh

studying_drh 实名认证

能拿个好名次将是收获的附带品

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板