data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv
1: b"%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:27: syntax error, unexpected ::, expecting ')' or ','\n  output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0]    rd_clobber_gpr_o,\n                   ^~\n                                                                                                              : ... Perhaps 'ariane_pkg' is a package which needs to be predeclared? (IEEE 1800-2017 26.3)\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:31: syntax error, unexpected ::, expecting ':'\n  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs1_i,\n                          ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:35: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs2_i,\n  ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:35: syntax error, unexpected ::, expecting ':'\n  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs2_i,\n                          ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:39: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs3_i,\n  ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:39: syntax error, unexpected ::, expecting ':'\n  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs3_i,\n                          ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:40: syntax error, unexpected ::, expecting ':'\n  output logic [ariane_pkg::FLEN-1:0]                           rs3_o,\n                          ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:44: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n  output ariane_pkg::scoreboard_entry_t [NR_COMMIT_PORTS-1:0]   commit_instr_o,\n  ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:49: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n  input  ariane_pkg::scoreboard_entry_t                         decoded_instr_i,\n  ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:51: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n  output logic                                                  decoded_instr_ack_o,\n  ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:54: syntax error, unexpected output, expecting IDENTIFIER or '=' or do or final\n  output ariane_pkg::scoreboard_entry_t                         issue_instr_o,\n  ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:56: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n  input  logic                                                  issue_ack_i,\n  ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:59: syntax error, unexpected input, expecting IDENTIFIER or '=' or do or final\n  input ariane_pkg::bp_resolve_t                                resolved_branch_i,\n  ^~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:60: syntax error, unexpected ::, expecting ':'\n  input logic [NR_WB_PORTS-1:0][ariane_pkg::TRANS_ID_BITS-1:0]  trans_id_i,   \n                                          ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:61: syntax error, unexpected ::, expecting ':'\n  input logic [NR_WB_PORTS-1:0][riscv::XLEN-1:0]                wbdata_i,     \n                                     ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:64: syntax error, unexpected ')', expecting ',' or ';'\n);\n^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:71: syntax error, unexpected IDENTIFIER, expecting TYPE-IDENTIFIER\n    ariane_pkg::scoreboard_entry_t sbe;             \n    ^~~~~~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:83: syntax error, unexpected assign\n  assign issue_full = &issue_cnt_q;\n  ^~~~~~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:89: syntax error, unexpected IDENTIFIER\n    for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++) begin\n                             ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:127: syntax error, unexpected IDENTIFIER\n    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin\n                             ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:136: syntax error, unexpected IDENTIFIER\n    for (int unsigned i = 0; i < NR_WB_PORTS; i++) begin\n                             ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:157: syntax error, unexpected IDENTIFIER\n    for (logic [BITS_ENTRIES-1:0] i = 0; i < NR_COMMIT_PORTS; i++) begin\n                                         ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:169: syntax error, unexpected IDENTIFIER\n      for (int unsigned i = 0; i < NR_ENTRIES; i++) begin\n                               ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:199: syntax error, unexpected ::, expecting ':'\n  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              gpr_clobber_vld;\n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:200: syntax error, unexpected ::, expecting ':'\n  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              fpr_clobber_vld;\n                      ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:209: syntax error, unexpected IDENTIFIER\n    for (int unsigned i = 0; i < 2**ariane_pkg::REG_ADDR_SIZE; i++) begin\n                             ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:215: syntax error, unexpected IDENTIFIER\n    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin\n                             ^\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:270: syntax error, unexpected ::, expecting ':'\n  logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data;\n                                          ^~\n%Error: data/full_repos/permissive/509468557/generators/cva6/src/main/resources/vsrc/cva6/src/scoreboard.sv:274: syntax error, unexpected for\n  for (genvar k = 0; unsigned'(k) < NR_WB_PORTS; k++) begin : gen_rs_wb\n  ^~~\n%Error: Exiting due to 29 error(s)\n"
module scoreboard #(
  parameter int unsigned NR_ENTRIES      = 8,
  parameter int unsigned NR_WB_PORTS     = 1,
  parameter int unsigned NR_COMMIT_PORTS = 2
) (
  input  logic                                                  clk_i,
  input  logic                                                  rst_ni,
  output logic                                                  sb_full_o,
  input  logic                                                  flush_unissued_instr_i,
  input  logic                                                  flush_i,
  input  logic                                                  unresolved_branch_i,

  output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0]    rd_clobber_gpr_o,
  output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0]    rd_clobber_fpr_o,


  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs1_i,
  output riscv::xlen_t                                          rs1_o,
  output logic                                                  rs1_valid_o,

  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs2_i,
  output riscv::xlen_t                                          rs2_o,
  output logic                                                  rs2_valid_o,

  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs3_i,
  output logic [ariane_pkg::FLEN-1:0]                           rs3_o,
  output logic                                                  rs3_valid_o,


  output ariane_pkg::scoreboard_entry_t [NR_COMMIT_PORTS-1:0]   commit_instr_o,
  input  logic              [NR_COMMIT_PORTS-1:0]               commit_ack_i,



  input  ariane_pkg::scoreboard_entry_t                         decoded_instr_i,
  input  logic                                                  decoded_instr_valid_i,
  output logic                                                  decoded_instr_ack_o,


  output ariane_pkg::scoreboard_entry_t                         issue_instr_o,
  output logic                                                  issue_instr_valid_o,
  input  logic                                                  issue_ack_i,


  input ariane_pkg::bp_resolve_t                                resolved_branch_i,
  input logic [NR_WB_PORTS-1:0][ariane_pkg::TRANS_ID_BITS-1:0]  trans_id_i,
  input logic [NR_WB_PORTS-1:0][riscv::XLEN-1:0]                wbdata_i,
  input ariane_pkg::exception_t [NR_WB_PORTS-1:0]               ex_i,
  input logic [NR_WB_PORTS-1:0]                                 wt_valid_i
);
  localparam int unsigned BITS_ENTRIES = $clog2(NR_ENTRIES);


  typedef struct packed {
    logic                          issued;
    logic                          is_rd_fpr_flag;
    ariane_pkg::scoreboard_entry_t sbe;
  } sb_mem_t;
  sb_mem_t [NR_ENTRIES-1:0] mem_q, mem_n;

  logic                    issue_full, issue_en;
  logic [BITS_ENTRIES-1:0] issue_cnt_n,      issue_cnt_q;
  logic [BITS_ENTRIES-1:0] issue_pointer_n,  issue_pointer_q;
  logic [NR_COMMIT_PORTS-1:0][BITS_ENTRIES-1:0] commit_pointer_n, commit_pointer_q;
  logic [$clog2(NR_COMMIT_PORTS):0] num_commit;



  assign issue_full = &issue_cnt_q;

  assign sb_full_o = issue_full;


  always_comb begin : commit_ports
    for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++) begin
      commit_instr_o[i] = mem_q[commit_pointer_q[i]].sbe;
      commit_instr_o[i].trans_id = commit_pointer_q[i];
    end
  end


  always_comb begin
    issue_instr_o          = decoded_instr_i;

    issue_instr_o.trans_id = issue_pointer_q;


    issue_instr_valid_o    = decoded_instr_valid_i & ~unresolved_branch_i & ~issue_full;
    decoded_instr_ack_o    = issue_ack_i & ~issue_full;
  end



  always_comb begin : issue_fifo

    mem_n          = mem_q;
    issue_en       = 1'b0;


    if (decoded_instr_valid_i && decoded_instr_ack_o && !flush_unissued_instr_i) begin


      issue_en = 1'b1;
      mem_n[issue_pointer_q] = {1'b1,
                                ariane_pkg::is_rd_fpr(decoded_instr_i.op),
                                decoded_instr_i
                                };
    end




    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin

      if (mem_q[i].sbe.fu == ariane_pkg::NONE && mem_q[i].issued)
        mem_n[i].sbe.valid = 1'b1;
    end




    for (int unsigned i = 0; i < NR_WB_PORTS; i++) begin


      if (wt_valid_i[i] && mem_q[trans_id_i[i]].issued) begin
        mem_n[trans_id_i[i]].sbe.valid  = 1'b1;
        mem_n[trans_id_i[i]].sbe.result = wbdata_i[i];

        mem_n[trans_id_i[i]].sbe.bp.predict_address = resolved_branch_i.target_address;

        if (ex_i[i].valid)
          mem_n[trans_id_i[i]].sbe.ex = ex_i[i];

        else if (mem_q[trans_id_i[i]].sbe.fu inside {ariane_pkg::FPU, ariane_pkg::FPU_VEC})
          mem_n[trans_id_i[i]].sbe.ex.cause = ex_i[i].cause;
      end
    end





    for (logic [BITS_ENTRIES-1:0] i = 0; i < NR_COMMIT_PORTS; i++) begin
      if (commit_ack_i[i]) begin

        mem_n[commit_pointer_q[i]].issued     = 1'b0;
        mem_n[commit_pointer_q[i]].sbe.valid  = 1'b0;
      end
    end




    if (flush_i) begin
      for (int unsigned i = 0; i < NR_ENTRIES; i++) begin

        mem_n[i].issued       = 1'b0;
        mem_n[i].sbe.valid    = 1'b0;
        mem_n[i].sbe.ex.valid = 1'b0;
      end
    end
  end


  popcount #(
    .INPUT_WIDTH(NR_COMMIT_PORTS)
  ) i_popcount (
    .data_i(commit_ack_i),
    .popcount_o(num_commit)
  );

  assign issue_cnt_n         = (flush_i) ? '0 : issue_cnt_q         - num_commit + issue_en;
  assign commit_pointer_n[0] = (flush_i) ? '0 : commit_pointer_q[0] + num_commit;
  assign issue_pointer_n     = (flush_i) ? '0 : issue_pointer_q     + issue_en;


  for (genvar k=1; k < NR_COMMIT_PORTS; k++) begin : gen_cnt_incr
    assign commit_pointer_n[k] = (flush_i) ? '0 : commit_pointer_n[0] + unsigned'(k);
  end





  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              gpr_clobber_vld;
  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              fpr_clobber_vld;
  ariane_pkg::fu_t [NR_ENTRIES:0]                                     clobber_fu;

  always_comb begin : clobber_assign
    gpr_clobber_vld  = '0;
    fpr_clobber_vld  = '0;


    clobber_fu[NR_ENTRIES] = ariane_pkg::NONE;
    for (int unsigned i = 0; i < 2**ariane_pkg::REG_ADDR_SIZE; i++) begin
      gpr_clobber_vld[i][NR_ENTRIES] = 1'b1;
      fpr_clobber_vld[i][NR_ENTRIES] = 1'b1;
    end


    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
      gpr_clobber_vld[mem_q[i].sbe.rd][i] = mem_q[i].issued & ~mem_q[i].is_rd_fpr_flag;
      fpr_clobber_vld[mem_q[i].sbe.rd][i] = mem_q[i].issued & mem_q[i].is_rd_fpr_flag;
      clobber_fu[i]                       = mem_q[i].sbe.fu;
    end


    gpr_clobber_vld[0] = '0;
  end

  for (genvar k = 0; k < 2**ariane_pkg::REG_ADDR_SIZE; k++) begin : gen_sel_clobbers

    rr_arb_tree #(
      .NumIn(NR_ENTRIES+1),
      .DataType(ariane_pkg::fu_t),
      .ExtPrio(1'b1),
      .AxiVldRdy(1'b1)
    ) i_sel_gpr_clobbers (
      .clk_i   ( clk_i               ),
      .rst_ni  ( rst_ni              ),
      .flush_i ( 1'b0                ),
      .rr_i    ( '0                  ),
      .req_i   ( gpr_clobber_vld[k]  ),
      .gnt_o   (                     ),
      .data_i  ( clobber_fu          ),
      .gnt_i   ( 1'b1                ),
      .req_o   (                     ),
      .data_o  ( rd_clobber_gpr_o[k] ),
      .idx_o   (                     )
    );
    rr_arb_tree #(
      .NumIn(NR_ENTRIES+1),
      .DataType(ariane_pkg::fu_t),
      .ExtPrio(1'b1),
      .AxiVldRdy(1'b1)
    ) i_sel_fpr_clobbers (
      .clk_i   ( clk_i               ),
      .rst_ni  ( rst_ni              ),
      .flush_i ( 1'b0                ),
      .rr_i    ( '0                  ),
      .req_i   ( fpr_clobber_vld[k]  ),
      .gnt_o   (                     ),
      .data_i  ( clobber_fu          ),
      .gnt_i   ( 1'b1                ),
      .req_o   (                     ),
      .data_o  ( rd_clobber_fpr_o[k] ),
      .idx_o   (                     )
    );
  end





  logic [NR_ENTRIES+NR_WB_PORTS-1:0] rs1_fwd_req, rs2_fwd_req, rs3_fwd_req;
  logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data;
  logic rs1_valid, rs2_valid;


  for (genvar k = 0; unsigned'(k) < NR_WB_PORTS; k++) begin : gen_rs_wb
    assign rs1_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs1_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_rs1_fpr(issue_instr_o.op));
    assign rs2_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs2_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_rs2_fpr(issue_instr_o.op));
    assign rs3_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs3_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_imm_fpr(issue_instr_o.op));
    assign rs_data[k]     = wbdata_i[k];
  end
  for (genvar k = 0; unsigned'(k) < NR_ENTRIES; k++) begin : gen_rs_entries
    assign rs1_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs1_i) & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_rs1_fpr(issue_instr_o.op));
    assign rs2_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs2_i) & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_rs2_fpr(issue_instr_o.op));
    assign rs3_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs3_i) & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_imm_fpr(issue_instr_o.op));
    assign rs_data[k+NR_WB_PORTS]     = mem_q[k].sbe.result;
  end


  assign rs1_valid_o = rs1_valid & ((|rs1_i) | ariane_pkg::is_rs1_fpr(issue_instr_o.op));
  assign rs2_valid_o = rs2_valid & ((|rs2_i) | ariane_pkg::is_rs2_fpr(issue_instr_o.op));



  rr_arb_tree #(
    .NumIn(NR_ENTRIES+NR_WB_PORTS),
    .DataWidth(riscv::XLEN),
    .ExtPrio(1'b1),
    .AxiVldRdy(1'b1)
  ) i_sel_rs1 (
    .clk_i   ( clk_i       ),
    .rst_ni  ( rst_ni      ),
    .flush_i ( 1'b0        ),
    .rr_i    ( '0          ),
    .req_i   ( rs1_fwd_req ),
    .gnt_o   (             ),
    .data_i  ( rs_data     ),
    .gnt_i   ( 1'b1        ),
    .req_o   ( rs1_valid   ),
    .data_o  ( rs1_o       ),
    .idx_o   (             )
  );

  rr_arb_tree #(
    .NumIn(NR_ENTRIES+NR_WB_PORTS),
    .DataWidth(riscv::XLEN),
    .ExtPrio(1'b1),
    .AxiVldRdy(1'b1)
  ) i_sel_rs2 (
    .clk_i   ( clk_i       ),
    .rst_ni  ( rst_ni      ),
    .flush_i ( 1'b0        ),
    .rr_i    ( '0          ),
    .req_i   ( rs2_fwd_req ),
    .gnt_o   (             ),
    .data_i  ( rs_data     ),
    .gnt_i   ( 1'b1        ),
    .req_o   ( rs2_valid   ),
    .data_o  ( rs2_o       ),
    .idx_o   (             )
  );

  riscv::xlen_t           rs3;

  rr_arb_tree #(
    .NumIn(NR_ENTRIES+NR_WB_PORTS),
    .DataWidth(riscv::XLEN),
    .ExtPrio(1'b1),
    .AxiVldRdy(1'b1)
  ) i_sel_rs3 (
    .clk_i   ( clk_i       ),
    .rst_ni  ( rst_ni      ),
    .flush_i ( 1'b0        ),
    .rr_i    ( '0          ),
    .req_i   ( rs3_fwd_req ),
    .gnt_o   (             ),
    .data_i  ( rs_data     ),
    .gnt_i   ( 1'b1        ),
    .req_o   ( rs3_valid_o ),
    .data_o  ( rs3         ),
    .idx_o   (             )
  );

  assign rs3_o = rs3[ariane_pkg::FLEN-1:0];


  always_ff @(posedge clk_i or negedge rst_ni) begin : regs
    if(!rst_ni) begin
      mem_q                 <= '{default: sb_mem_t'(0)};
      issue_cnt_q           <= '0;
      commit_pointer_q      <= '0;
      issue_pointer_q       <= '0;
    end else begin
      issue_cnt_q           <= issue_cnt_n;
      issue_pointer_q       <= issue_pointer_n;
      mem_q                 <= mem_n;
      commit_pointer_q      <= commit_pointer_n;
    end
  end


  `ifndef VERILATOR
  initial begin
    assert (NR_ENTRIES == 2**BITS_ENTRIES) else $fatal(1, "Scoreboard size needs to be a power of two.");
  end


  assert property (
    @(posedge clk_i) disable iff (!rst_ni) (rd_clobber_gpr_o[0] == ariane_pkg::NONE))
    else $fatal (1,"RD 0 should not bet set");

  assert property (
    @(posedge clk_i) disable iff (!rst_ni) commit_ack_i[0] |-> commit_instr_o[0].valid)
    else $fatal (1,"Commit acknowledged but instruction is not valid");

  assert property (
    @(posedge clk_i) disable iff (!rst_ni) commit_ack_i[1] |-> commit_instr_o[1].valid)
    else $fatal (1,"Commit acknowledged but instruction is not valid");


  assert property (
    @(posedge clk_i) disable iff (!rst_ni) issue_ack_i |-> issue_instr_valid_o)
    else $fatal (1,"Issue acknowledged but instruction is not valid");



  for (genvar i = 0; i < NR_WB_PORTS; i++) begin
    for (genvar j = 0; j < NR_WB_PORTS; j++)  begin
      assert property (
        @(posedge clk_i) disable iff (!rst_ni) wt_valid_i[i] && wt_valid_i[j] && (i != j) |-> (trans_id_i[i] != trans_id_i[j]))
        else $fatal (1,"Two or more functional units are retiring instructions with the same transaction id!");
    end
  end
  `endif

endmodule
module scoreboard #(
  parameter int unsigned NR_ENTRIES      = 8,
  parameter int unsigned NR_WB_PORTS     = 1,
  parameter int unsigned NR_COMMIT_PORTS = 2
) (
  input  logic                                                  clk_i,
  input  logic                                                  rst_ni,
  output logic                                                  sb_full_o,
  input  logic                                                  flush_unissued_instr_i,
  input  logic                                                  flush_i,
  input  logic                                                  unresolved_branch_i,

  output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0]    rd_clobber_gpr_o,
  output ariane_pkg::fu_t [2**ariane_pkg::REG_ADDR_SIZE-1:0]    rd_clobber_fpr_o,


  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs1_i,
  output riscv::xlen_t                                          rs1_o,
  output logic                                                  rs1_valid_o,

  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs2_i,
  output riscv::xlen_t                                          rs2_o,
  output logic                                                  rs2_valid_o,

  input  logic [ariane_pkg::REG_ADDR_SIZE-1:0]                  rs3_i,
  output logic [ariane_pkg::FLEN-1:0]                           rs3_o,
  output logic                                                  rs3_valid_o,


  output ariane_pkg::scoreboard_entry_t [NR_COMMIT_PORTS-1:0]   commit_instr_o,
  input  logic              [NR_COMMIT_PORTS-1:0]               commit_ack_i,



  input  ariane_pkg::scoreboard_entry_t                         decoded_instr_i,
  input  logic                                                  decoded_instr_valid_i,
  output logic                                                  decoded_instr_ack_o,


  output ariane_pkg::scoreboard_entry_t                         issue_instr_o,
  output logic                                                  issue_instr_valid_o,
  input  logic                                                  issue_ack_i,


  input ariane_pkg::bp_resolve_t                                resolved_branch_i,
  input logic [NR_WB_PORTS-1:0][ariane_pkg::TRANS_ID_BITS-1:0]  trans_id_i,
  input logic [NR_WB_PORTS-1:0][riscv::XLEN-1:0]                wbdata_i,
  input ariane_pkg::exception_t [NR_WB_PORTS-1:0]               ex_i,
  input logic [NR_WB_PORTS-1:0]                                 wt_valid_i
);

  localparam int unsigned BITS_ENTRIES = $clog2(NR_ENTRIES);


  typedef struct packed {
    logic                          issued;
    logic                          is_rd_fpr_flag;
    ariane_pkg::scoreboard_entry_t sbe;
  } sb_mem_t;
  sb_mem_t [NR_ENTRIES-1:0] mem_q, mem_n;

  logic                    issue_full, issue_en;
  logic [BITS_ENTRIES-1:0] issue_cnt_n,      issue_cnt_q;
  logic [BITS_ENTRIES-1:0] issue_pointer_n,  issue_pointer_q;
  logic [NR_COMMIT_PORTS-1:0][BITS_ENTRIES-1:0] commit_pointer_n, commit_pointer_q;
  logic [$clog2(NR_COMMIT_PORTS):0] num_commit;



  assign issue_full = &issue_cnt_q;

  assign sb_full_o = issue_full;


  always_comb begin : commit_ports
    for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++) begin
      commit_instr_o[i] = mem_q[commit_pointer_q[i]].sbe;
      commit_instr_o[i].trans_id = commit_pointer_q[i];
    end
  end


  always_comb begin
    issue_instr_o          = decoded_instr_i;

    issue_instr_o.trans_id = issue_pointer_q;


    issue_instr_valid_o    = decoded_instr_valid_i & ~unresolved_branch_i & ~issue_full;
    decoded_instr_ack_o    = issue_ack_i & ~issue_full;
  end



  always_comb begin : issue_fifo

    mem_n          = mem_q;
    issue_en       = 1'b0;


    if (decoded_instr_valid_i && decoded_instr_ack_o && !flush_unissued_instr_i) begin


      issue_en = 1'b1;
      mem_n[issue_pointer_q] = {1'b1,
                                ariane_pkg::is_rd_fpr(decoded_instr_i.op),
                                decoded_instr_i
                                };
    end




    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin

      if (mem_q[i].sbe.fu == ariane_pkg::NONE && mem_q[i].issued)
        mem_n[i].sbe.valid = 1'b1;
    end




    for (int unsigned i = 0; i < NR_WB_PORTS; i++) begin


      if (wt_valid_i[i] && mem_q[trans_id_i[i]].issued) begin
        mem_n[trans_id_i[i]].sbe.valid  = 1'b1;
        mem_n[trans_id_i[i]].sbe.result = wbdata_i[i];

        mem_n[trans_id_i[i]].sbe.bp.predict_address = resolved_branch_i.target_address;

        if (ex_i[i].valid)
          mem_n[trans_id_i[i]].sbe.ex = ex_i[i];

        else if (mem_q[trans_id_i[i]].sbe.fu inside {ariane_pkg::FPU, ariane_pkg::FPU_VEC})
          mem_n[trans_id_i[i]].sbe.ex.cause = ex_i[i].cause;
      end
    end





    for (logic [BITS_ENTRIES-1:0] i = 0; i < NR_COMMIT_PORTS; i++) begin
      if (commit_ack_i[i]) begin

        mem_n[commit_pointer_q[i]].issued     = 1'b0;
        mem_n[commit_pointer_q[i]].sbe.valid  = 1'b0;
      end
    end




    if (flush_i) begin
      for (int unsigned i = 0; i < NR_ENTRIES; i++) begin

        mem_n[i].issued       = 1'b0;
        mem_n[i].sbe.valid    = 1'b0;
        mem_n[i].sbe.ex.valid = 1'b0;
      end
    end
  end


  popcount #(
    .INPUT_WIDTH(NR_COMMIT_PORTS)
  ) i_popcount (
    .data_i(commit_ack_i),
    .popcount_o(num_commit)
  );

  assign issue_cnt_n         = (flush_i) ? '0 : issue_cnt_q         - num_commit + issue_en;
  assign commit_pointer_n[0] = (flush_i) ? '0 : commit_pointer_q[0] + num_commit;
  assign issue_pointer_n     = (flush_i) ? '0 : issue_pointer_q     + issue_en;


  for (genvar k=1; k < NR_COMMIT_PORTS; k++) begin : gen_cnt_incr
    assign commit_pointer_n[k] = (flush_i) ? '0 : commit_pointer_n[0] + unsigned'(k);
  end





  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              gpr_clobber_vld;
  logic [2**ariane_pkg::REG_ADDR_SIZE-1:0][NR_ENTRIES:0]              fpr_clobber_vld;
  ariane_pkg::fu_t [NR_ENTRIES:0]                                     clobber_fu;

  always_comb begin : clobber_assign
    gpr_clobber_vld  = '0;
    fpr_clobber_vld  = '0;


    clobber_fu[NR_ENTRIES] = ariane_pkg::NONE;
    for (int unsigned i = 0; i < 2**ariane_pkg::REG_ADDR_SIZE; i++) begin
      gpr_clobber_vld[i][NR_ENTRIES] = 1'b1;
      fpr_clobber_vld[i][NR_ENTRIES] = 1'b1;
    end


    for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
      gpr_clobber_vld[mem_q[i].sbe.rd][i] = mem_q[i].issued & ~mem_q[i].is_rd_fpr_flag;
      fpr_clobber_vld[mem_q[i].sbe.rd][i] = mem_q[i].issued & mem_q[i].is_rd_fpr_flag;
      clobber_fu[i]                       = mem_q[i].sbe.fu;
    end


    gpr_clobber_vld[0] = '0;
  end

  for (genvar k = 0; k < 2**ariane_pkg::REG_ADDR_SIZE; k++) begin : gen_sel_clobbers

    rr_arb_tree #(
      .NumIn(NR_ENTRIES+1),
      .DataType(ariane_pkg::fu_t),
      .ExtPrio(1'b1),
      .AxiVldRdy(1'b1)
    ) i_sel_gpr_clobbers (
      .clk_i   ( clk_i               ),
      .rst_ni  ( rst_ni              ),
      .flush_i ( 1'b0                ),
      .rr_i    ( '0                  ),
      .req_i   ( gpr_clobber_vld[k]  ),
      .gnt_o   (                     ),
      .data_i  ( clobber_fu          ),
      .gnt_i   ( 1'b1                ),
      .req_o   (                     ),
      .data_o  ( rd_clobber_gpr_o[k] ),
      .idx_o   (                     )
    );
    rr_arb_tree #(
      .NumIn(NR_ENTRIES+1),
      .DataType(ariane_pkg::fu_t),
      .ExtPrio(1'b1),
      .AxiVldRdy(1'b1)
    ) i_sel_fpr_clobbers (
      .clk_i   ( clk_i               ),
      .rst_ni  ( rst_ni              ),
      .flush_i ( 1'b0                ),
      .rr_i    ( '0                  ),
      .req_i   ( fpr_clobber_vld[k]  ),
      .gnt_o   (                     ),
      .data_i  ( clobber_fu          ),
      .gnt_i   ( 1'b1                ),
      .req_o   (                     ),
      .data_o  ( rd_clobber_fpr_o[k] ),
      .idx_o   (                     )
    );
  end





  logic [NR_ENTRIES+NR_WB_PORTS-1:0] rs1_fwd_req, rs2_fwd_req, rs3_fwd_req;
  logic [NR_ENTRIES+NR_WB_PORTS-1:0][riscv::XLEN-1:0] rs_data;
  logic rs1_valid, rs2_valid;


  for (genvar k = 0; unsigned'(k) < NR_WB_PORTS; k++) begin : gen_rs_wb
    assign rs1_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs1_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_rs1_fpr(issue_instr_o.op));
    assign rs2_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs2_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_rs2_fpr(issue_instr_o.op));
    assign rs3_fwd_req[k] = (mem_q[trans_id_i[k]].sbe.rd == rs3_i) & wt_valid_i[k] & (~ex_i[k].valid) & (mem_q[trans_id_i[k]].is_rd_fpr_flag == ariane_pkg::is_imm_fpr(issue_instr_o.op));
    assign rs_data[k]     = wbdata_i[k];
  end
  for (genvar k = 0; unsigned'(k) < NR_ENTRIES; k++) begin : gen_rs_entries
    assign rs1_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs1_i) & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_rs1_fpr(issue_instr_o.op));
    assign rs2_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs2_i) & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_rs2_fpr(issue_instr_o.op));
    assign rs3_fwd_req[k+NR_WB_PORTS] = (mem_q[k].sbe.rd == rs3_i) & mem_q[k].issued & mem_q[k].sbe.valid & (mem_q[k].is_rd_fpr_flag == ariane_pkg::is_imm_fpr(issue_instr_o.op));
    assign rs_data[k+NR_WB_PORTS]     = mem_q[k].sbe.result;
  end


  assign rs1_valid_o = rs1_valid & ((|rs1_i) | ariane_pkg::is_rs1_fpr(issue_instr_o.op));
  assign rs2_valid_o = rs2_valid & ((|rs2_i) | ariane_pkg::is_rs2_fpr(issue_instr_o.op));



  rr_arb_tree #(
    .NumIn(NR_ENTRIES+NR_WB_PORTS),
    .DataWidth(riscv::XLEN),
    .ExtPrio(1'b1),
    .AxiVldRdy(1'b1)
  ) i_sel_rs1 (
    .clk_i   ( clk_i       ),
    .rst_ni  ( rst_ni      ),
    .flush_i ( 1'b0        ),
    .rr_i    ( '0          ),
    .req_i   ( rs1_fwd_req ),
    .gnt_o   (             ),
    .data_i  ( rs_data     ),
    .gnt_i   ( 1'b1        ),
    .req_o   ( rs1_valid   ),
    .data_o  ( rs1_o       ),
    .idx_o   (             )
  );

  rr_arb_tree #(
    .NumIn(NR_ENTRIES+NR_WB_PORTS),
    .DataWidth(riscv::XLEN),
    .ExtPrio(1'b1),
    .AxiVldRdy(1'b1)
  ) i_sel_rs2 (
    .clk_i   ( clk_i       ),
    .rst_ni  ( rst_ni      ),
    .flush_i ( 1'b0        ),
    .rr_i    ( '0          ),
    .req_i   ( rs2_fwd_req ),
    .gnt_o   (             ),
    .data_i  ( rs_data     ),
    .gnt_i   ( 1'b1        ),
    .req_o   ( rs2_valid   ),
    .data_o  ( rs2_o       ),
    .idx_o   (             )
  );

  riscv::xlen_t           rs3;

  rr_arb_tree #(
    .NumIn(NR_ENTRIES+NR_WB_PORTS),
    .DataWidth(riscv::XLEN),
    .ExtPrio(1'b1),
    .AxiVldRdy(1'b1)
  ) i_sel_rs3 (
    .clk_i   ( clk_i       ),
    .rst_ni  ( rst_ni      ),
    .flush_i ( 1'b0        ),
    .rr_i    ( '0          ),
    .req_i   ( rs3_fwd_req ),
    .gnt_o   (             ),
    .data_i  ( rs_data     ),
    .gnt_i   ( 1'b1        ),
    .req_o   ( rs3_valid_o ),
    .data_o  ( rs3         ),
    .idx_o   (             )
  );

  assign rs3_o = rs3[ariane_pkg::FLEN-1:0];


  always_ff @(posedge clk_i or negedge rst_ni) begin : regs
    if(!rst_ni) begin
      mem_q                 <= '{default: sb_mem_t'(0)};
      issue_cnt_q           <= '0;
      commit_pointer_q      <= '0;
      issue_pointer_q       <= '0;
    end else begin
      issue_cnt_q           <= issue_cnt_n;
      issue_pointer_q       <= issue_pointer_n;
      mem_q                 <= mem_n;
      commit_pointer_q      <= commit_pointer_n;
    end
  end


  `ifndef VERILATOR
  initial begin
    assert (NR_ENTRIES == 2**BITS_ENTRIES) else $fatal(1, "Scoreboard size needs to be a power of two.");
  end


  assert property (
    @(posedge clk_i) disable iff (!rst_ni) (rd_clobber_gpr_o[0] == ariane_pkg::NONE))
    else $fatal (1,"RD 0 should not bet set");

  assert property (
    @(posedge clk_i) disable iff (!rst_ni) commit_ack_i[0] |-> commit_instr_o[0].valid)
    else $fatal (1,"Commit acknowledged but instruction is not valid");

  assert property (
    @(posedge clk_i) disable iff (!rst_ni) commit_ack_i[1] |-> commit_instr_o[1].valid)
    else $fatal (1,"Commit acknowledged but instruction is not valid");


  assert property (
    @(posedge clk_i) disable iff (!rst_ni) issue_ack_i |-> issue_instr_valid_o)
    else $fatal (1,"Issue acknowledged but instruction is not valid");



  for (genvar i = 0; i < NR_WB_PORTS; i++) begin
    for (genvar j = 0; j < NR_WB_PORTS; j++)  begin
      assert property (
        @(posedge clk_i) disable iff (!rst_ni) wt_valid_i[i] && wt_valid_i[j] && (i != j) |-> (trans_id_i[i] != trans_id_i[j]))
        else $fatal (1,"Two or more functional units are retiring instructions with the same transaction id!");
    end
  end
  `endif

endmodule