RISC-V MCU中文社区

【分享】 oitf模块分享

发表于 开源蜂鸟E203 2023-05-22 10:21:07
0
1569
1

组别:CICC3327
oitf模块主要是用于描述 RISC-V 处理器的 Out-of-Order Scheduler 中的指令调度单元 OITF(Out of Order Instruction Fetch Buffer)。OITF 可以接受新的指令,并对指令进行排序、重组以及存储。在指令的执行过程中,OITF 还可以进行一些特殊操作,如匹配正在执行的指令和等待退役的指令中是否有冲突的源/目标寄存器等以此判断是否需要控制disp模块延迟转发,此外,该代码还实现了 OITF 的一些其他功能,例如指令计数器和 OITF 深度控制逻辑等。下面为一些具体的注释。

// 输入输出端口定义
module e203_exu_oitf (
  output dis_ready,   // 可以接受新的指令的标志位

  input  dis_ena,     // 派遣命令使能信号
  input  ret_ena,     // 退役命令使能信号

  output [`E203_ITAG_WIDTH-1:0] dis_ptr,  // 派遣指针
  output [`E203_ITAG_WIDTH-1:0] ret_ptr,  // 退役指针

  output [`E203_RFIDX_WIDTH-1:0] ret_rdidx, // 退役指令写回寄存器的索引
  output ret_rdwen,    // 标志位,表示是否写入退役指令的目标寄存器
  output ret_rdfpu,    // 标志位,表示是否为浮点运算指令
  output [`E203_PC_SIZE-1:0] ret_pc,  // 退役指令所在的PC地址

  input  disp_i_rs1en,   // 标志位,表示指令的第一个操作数是否存在
  input  disp_i_rs2en,   // 标志位,表示指令的第二个操作数是否存在
  input  disp_i_rs3en,   // 标志位,表示指令的第三个操作数是否存在
  input  disp_i_rdwen,   // 标志位,表示指令是否写入目标寄存器
  input  disp_i_rs1fpu,  // 标志位,表示指令的第一个操作数是否为浮点运算指令
  input  disp_i_rs2fpu,  // 标志位,表示指令的第二个操作数是否为浮点运算指令
  input  disp_i_rs3fpu,  // 标志位,表示指令的第三个操作数是否为浮点运算指令
  input  disp_i_rdfpu,   // 标志位,表示指令是否为浮点运算指令
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rs1idx,  // 指令的第一个操作数的寄存器写索引
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rs2idx,  // 指令的第二个操作数的寄存器写索引
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rs3idx,  // 指令的第三个操作数的寄存器写索引
  input  [`E203_RFIDX_WIDTH-1:0] disp_i_rdidx,  // 指令的目标寄存器的索引
  input  [`E203_PC_SIZE    -1:0] disp_i_pc,      // 指令所在的PC地址

  output oitfrd_match_disprs1,   // 标志位,表示是否有指令在OITF中等待退役的第一个操作数匹配当前正在写入的目标寄存器
  output oitfrd_match_disprs2,   // 标志位,表示是否有指令在OITF中等待退役的第二个操作数匹配当前正在写入的目标寄存器
  output oitfrd_match_disprs3,   // 标志位,表示是否有指令在OITF中等待退役的第三个操作数匹配当前正在写入的目标寄存器
  output oitfrd_match_disprd,    // 标志位,表示是否有指令已在OITF中等待退役而要写入的目标寄存器与当前正在写入的目标寄存器相同

  output oitf_empty,     // 标志位,表示OITF是否为空
  input  clk,
  input  rst_n
);

  // 各种状态寄存器和控制逻辑的定义
  wire [`E203_OITF_DEPTH-1:0] vld_set;
  wire [`E203_OITF_DEPTH-1:0] vld_clr;
  wire [`E203_OITF_DEPTH-1:0] vld_ena;
  wire [`E203_OITF_DEPTH-1:0] vld_nxt;
  wire [`E203_OITF_DEPTH-1:0] vld_r;
  wire [`E203_OITF_DEPTH-1:0] rdwen_r;
  wire [`E203_OITF_DEPTH-1:0] rdfpu_r;
  wire [`E203_RFIDX_WIDTH-1:0] rdidx_r[`E203_OITF_DEPTH-1:0];
  wire [`E203_PC_SIZE-1:0] pc_r[`E203_OITF_DEPTH-1:0];

  wire alc_ptr_ena = dis_ena;   // 将派遣命令的使能信号作为状态寄存器“alc_ptr”的写入使能信号
  wire ret_ptr_ena = ret_ena;   // 将退役命令的使能信号作为状态寄存器“ret_ptr”的写入使能信号

  wire oitf_full ;    // 标志位,表示OITF是否已满

  wire [`E203_ITAG_WIDTH-1:0] alc_ptr_r;  // 存储当前OITF中下一个可以用来写入的位置的指针
  wire [`E203_ITAG_WIDTH-1:0] ret_ptr_r;  // 存储当前OITF中第一个可以退役的指令的指针

  generate
  // 当OITF的深度不是1时需要进行以下操作
  if(`E203_OITF_DEPTH > 1) begin: depth_gt1//{
      wire alc_ptr_flg_r;   // 指标计数器已到达最大值的标志位
      // 下一轮的指标计数器当前值的相反数,用于在下一轮时将其重置为0
      wire alc_ptr_flg_nxt = ~alc_ptr_flg_r;
      // 派遣命令已经被启用,且指标计数器已到达最大值,用于产生状态寄存器alc_ptr的更新使能信号
      wire alc_ptr_flg_ena = (alc_ptr_r == ($unsigned(`E203_OITF_DEPTH-1))) & alc_ptr_ena;

      // 存储alc_ptr的标志位相关的状态寄存器和它们的控制逻辑
      sirv_gnrl_d
(
.clk(clk),
.rst_n(rst_n),
.d(alc_ptr_flg_nxt),
.qv(alc_ptr_flg_r),
.ena(alc_ptr_flg_ena)
);

  // OITF的深度是否已满的判断
  assign oitf_full = (alc_ptr_r == ret_ptr_r) & vld_r[alc_ptr_r];

  // OITF的空状态寄存器
  assign oitf_empty = (alc_ptr_r == ret_ptr_r) & ~vld_r[alc_ptr_r];

  // OITF已经满的情况下,不能再接受新的指令,此时置dis_ready为0
  assign dis_ready = ~oitf_full;

  // 下一轮OITF的读取指针
  assign ret_ptr = ret_ptr_r + vld_r[ret_ptr_r];

  // 当OITF的指标计数器alc_ptr已到达最大值且有新指令需要入队,
  // 将指标计数器重置为0,并将alc_ptr和它的相关寄存器重置为正确的值
  assign alc_ptr_ena = (alc_ptr_r == ($unsigned(`E203_OITF_DEPTH-1))) & ~oitf_full;
  sirv_gnrl_d
  #(.WIDTH(`E203_ITAG_WIDTH))
  alc_ptr_d
  (
      .clk(clk),
      .rst_n(rst_n),
      .d({alc_ptr_r[`E203_ITAG_WIDTH-2:0],1'b0}),
      .ena(alc_ptr_ena),
      .qv(alc_ptr_r)
  );

  // 对于OITF中每一个指令,检查它的目标寄存器是否需要写入,并将该信息保存在状态寄存器rdwen_r中
  assign rdwen_r = {`E203_OITF_DEPTH{disp_i_rdwen}} & vld_r;

  // 对于OITF中每一个指令,检查它是否是浮点运算指令,并将该信息保存在状态寄存器rdfpu_r中
  assign rdfpu_r = {`E203_OITF_DEPTH{disp_i_rdfpu}} & vld_r;

  // 对于OITF中每一个指令,保存它的目标寄存器的写索引和PC地址
  assign rdidx_r = {`E203_OITF_DEPTH{disp_i_rdidx}} & vld_r;
  assign pc_r = {`E203_OITF_DEPTH{disp_i_pc}} & vld_r;

  // vld_nxt表示下一轮OITF的有效指令数量,它等于当前OITF中的指令数量加上新指令的数量
  assign vld_nxt = {vld_r[alc_ptr_r+1:`E203_OITF_DEPTH-1], vld_set};

  // 对于本轮不需要退役的指令,在下一轮前都需要保留它们的有效位,因此vld_clr等于vld_r而不是全零
  assign vld_clr = vld_r & {~oitf_empty,{oitf_empty}&vld_r[`E203_OITF_DEPTH-1]} ;

  // 在状态寄存器vld_r中保存当前OITF中每个指令的有效位
  sirv_gnrl_d
  #(.WIDTH(`E203_OITF_DEPTH))
  vld_d
  (
      .clk(clk),
      .rst_n(rst_n),
      .d(vld_nxt),
      .ena(1'b1),
      .qv(vld_r)
  );

  // 根据vld_r中的值判断当前OITF中有多少个有效指令,更新alc_ptr_r和ret_ptr_r
  sirv_idcnt
  #(.WIDTH(`E203_OITF_DEPTH))
  oitf_cnt
  (
      .clk(clk),
      .rst_n(rst_n),
      .ena(1'b1),
      .id(vld_r),
      .cnt({alc_ptr_r, ret_ptr_r})
  );

  // 将新指令保存在OITF中
  assign vld_set = (alc_ptr_ena & ~oitf_full) << alc_ptr_r;
end else: depth_eq1 //{
// OITF深度为1的情况下,需要用一个状态寄存器来保存当前指令是否有效
wire oitf_valid_r;
sirv_gnrl_d
#(.WIDTH(1))
oitf_valid_d
(
.clk(clk),
.rst_n(rst_n),
.d(vld_set[0]),
.ena(alc_ptr_ena & ~oitf_valid_r & ~oitf_full),
.qv(oitf_valid_r)
);

  // 根据当前指令是否有效,判断OITF是否为空或已满
  assign oitf_empty = ~oitf_valid_r;
  assign oitf_full = oitf_valid_r;

  // OITF深度为1时,只需要一个指针指向当前指令的位置
  wire [`E203_ITAG_WIDTH-1:0] ptr_r;
  sirv_gnrl_d
  #(.WIDTH(`E203_ITAG_WIDTH))
  ptr_d
  (
      .clk(clk),
      .rst_n(rst_n),
      .d(alc_ptr_r),
      .ena(alc_ptr_ena & ~oitf_valid_r & ~oitf_full),
      .qv(ptr_r)
  );

  // 当前指令是否有效,等价于OITF是否为空
  assign dis_ready = ~oitf_valid_r;

  // OITF深度为1时,所有指令的目标寄存器索引、PC地址、浮点标志位以及写使能信号可以用单个状态寄存器来保存
  wire [`E203_RFIDX_WIDTH+`E203_PC_SIZE+2:0] state_r = {rdfpu_r, rdidx_r, pc_r};

  // 将disp_i_rdwen左移1位并与oitf_valid_r进行与运算,将其结果保存在state_r的最低位中,
  // 确定当前指令是否有目标寄存器需要写入
  assign state_r[0] = {disp_i_rdwen, 1'b0} & {`E203_RFIDX_WIDTH+`E203_PC_SIZE+1{oitf_valid_r}};

  // 将当前指令需要写入目标寄存器的索引左移1位,将结果保存在state_r的次低位中
  assign state_r[1] = {disp_i_rdidx, `E203_PC_SIZE{1'b0}} << 1;

  // 将PC地址左移1位,将结果保存在state_r的剩余位中
  assign state_r[`E203_RFIDX_WIDTH+`E203_PC_SIZE+2:2] = {pc_r, `E203_RFIDX_WIDTH{1'b0}};

  // 当OITF深度为1时,退役指令的指针等于当前指针加1,并且不受任何控制逻辑的影响
  assign ret_ptr_r = ptr_r + oitf_valid_r;

  // 将state_r拆分为rdfpu_r、rd_idx_r、pc_r并输出
  assign ret_rdfpu = state_r[0];
  assign ret_rdidx = state_r[1:`E203_RFIDX_WIDTH];
  assign ret_pc = state_r[`E203_RFIDX_WIDTH+1:`E203_RFIDX_WIDTH+`E203_PC_SIZE];

  // OITF深度为1时,OITF中不会有多个指令,因此所有指令都会等待直到下一轮才能退役
  assign oitfrd_match_disprs1 = (vld_clr & disp_i_rs1en) & (disp_i_rs1idx == ret_rdidx);
  assign oitfrd_match_disprs2 = (vld_clr & disp_i_rs2en) & (disp_i_rs2idx == ret_rdidx);
  assign oitfrd_match_disprs3 = (vld_clr & disp_i_rs3en) & (disp_i_rs3idx == ret_rdidx);
  assign oitfrd_match_disprd = (vld_clr & disp_i_rdwen) & (disp_i_rdidx == ret_rdidx);
end
endgenerate

endmodule
喜欢1
用户评论
studying_drh

studying_drh 实名认证

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

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