FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

自作CPUにベクトル命令を追加する実装検討(40. リプレイキューとベクトルuopsの考え直し)

ベクトル命令の実装検討、リプレイキューの構造について考え直す。

ベクトル命令は1命令で複数のuopに分解されるが、一度ハザードが発生してそれ以降のuopをすべてリプレイキューに格納すると、必要なリプレイキューの大きさが非常に大きくなってしまう。 そこで、リプレイキューに格納するのは、1命令内の複数のuopのうち、最初のuopのみをリプレイキューに格納し、それ以外を破棄するようにする。

これをサポートするためには、リプレイキューからの再実行においても、命令をuopに分解する機構が必要になる。 これまでは命令キュー内に命令をuopに分解する機能を実装していたが、これを移動し、パイプラインの直前のステージに移動する。

always_comb begin
  case (r_state)
    INIT : begin
      w_uop_next = i_issue;
      if (i_issue.valid & i_ready) begin
        if (!w_is_last_uop) begin
          w_state_next = UOP_GEN;
          w_uop_next.vec_step_index = i_issue.vec_step_index + 'h1;
          w_uop_next.vec_lmul_index = i_issue.vec_lmul_index + (w_uop_next.vec_step_index == mycpu_vec_pkg::VEC_STEP_W-1);

          for (int rs_idx = 0; rs_idx < NUM_OPERANDS; rs_idx++) begin
            if (i_issue.rd_regs[rs_idx].valid & i_issue.rd_regs[rs_idx].typ == mycpu_pkg::VPR) begin
              w_uop_next.rd_regs[rs_idx].rnid = i_issue.rd_regs[rs_idx].rnid + 'h1;
            end
          end
          w_uop_next.wr_old_reg.rnid = i_issue.wr_old_reg.rnid + 'h1;
          w_uop_next.wr_reg.rnid     = i_issue.wr_reg.rnid + 'h1;
        end // else: !if(i_issue.vec_lmul_index == (1 << i_issue.vlvtype.vtype.vlmul)-1)
      end // if (i_issue.valid)
    end // case: INIT
    UOP_GEN : begin
      if (i_ready) begin
        w_uop_next.vec_step_index = r_uop.vec_step_index + 'h1;
        if (r_uop.vec_step_index == mycpu_vec_pkg::VEC_STEP_W-1) begin
          if (r_uop.vec_lmul_index == mycpu_vec_pkg::calc_num_req(i_issue)-1) begin
            w_state_next = INIT;
            w_uop_next.vec_lmul_index = r_uop.vec_lmul_index + 'h1;
          end

          for (int rs_idx = 0; rs_idx < NUM_OPERANDS; rs_idx++) begin
            if (r_uop.rd_regs[rs_idx].valid & r_uop.rd_regs[rs_idx].typ == mycpu_pkg::VPR) begin
              w_uop_next.rd_regs[rs_idx].rnid = r_uop.rd_regs[rs_idx].rnid + 'h1;
            end
          end
          w_uop_next.wr_old_reg.rnid = r_uop.wr_old_reg.rnid + 'h1;
          w_uop_next.wr_reg.rnid     = r_uop.wr_reg.rnid + 'h1;
        end // else: !if(r_uop.vec_lmul_index == (1 << r_uop.vlvtype.vtype.vlmul)-1)
      end // if (i_ready)
    end // case: UOP_GEN
    default : begin
    end
  endcase // case (r_state)
end // always_comb