diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index c8a181277..ee0bd2719 100644 --- a/include/ariane_pkg.sv +++ b/include/ariane_pkg.sv @@ -22,6 +22,7 @@ package ariane_pkg; localparam ASID_WIDTH = 1; localparam BTB_ENTRIES = 8; localparam BITS_SATURATION_COUNTER = 2; + localparam NR_COMMIT_PORTS = 2; localparam logic [63:0] ISA_CODE = (1 << 2) // C - Compressed extension | (1 << 8) // I - RV32I/64I/128I base ISA diff --git a/src/ariane.sv b/src/ariane.sv index b3c0559f5..6eb8a118e 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -100,7 +100,7 @@ module ariane branchpredict resolved_branch; logic [63:0] pc_commit; logic eret; - logic commit_ack; + logic [NR_COMMIT_PORTS-1:0] commit_ack; // -------------- // PCGEN <-> IF @@ -193,13 +193,13 @@ module ariane // -------------- // ID <-> COMMIT // -------------- - scoreboard_entry commit_instr_id_commit; + scoreboard_entry [NR_COMMIT_PORTS-1:0] commit_instr_id_commit; // -------------- // COMMIT <-> ID // -------------- - logic [4:0] waddr_a_commit_id; - logic [63:0] wdata_a_commit_id; - logic we_a_commit_id; + logic [NR_COMMIT_PORTS-1:0][4:0] waddr_commit_id; + logic [NR_COMMIT_PORTS-1:0][63:0] wdata_commit_id; + logic [NR_COMMIT_PORTS-1:0] we_commit_id; // -------------- // IF <-> EX // -------------- @@ -385,16 +385,16 @@ module ariane .csr_valid_o ( csr_valid_id_ex ), .trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, branch_trans_id_ex_id, csr_trans_id_ex_id, mult_trans_id_ex_id }), - .wdata_i ( {alu_result_ex_id, lsu_result_ex_id, branch_result_ex_id, csr_result_ex_id, mult_result_ex_id }), + .wbdata_i ( {alu_result_ex_id, lsu_result_ex_id, branch_result_ex_id, csr_result_ex_id, mult_result_ex_id }), .ex_ex_i ( {{$bits(exception){1'b0}}, lsu_exception_ex_id, branch_exception_ex_id, {$bits(exception){1'b0}}, {$bits(exception){1'b0}} }), .wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, branch_valid_ex_id, csr_valid_ex_id, mult_valid_ex_id }), - .waddr_a_i ( waddr_a_commit_id ), - .wdata_a_i ( wdata_a_commit_id ), - .we_a_i ( we_a_commit_id ), + .waddr_i ( waddr_commit_id ), + .wdata_i ( wdata_commit_id ), + .we_i ( we_commit_id ), - .commit_instr_o ( commit_instr_id_commit ), - .commit_ack_i ( commit_ack ), + .commit_instr_o ( commit_instr_id_commit ), + .commit_ack_i ( commit_ack ), .* ); @@ -481,9 +481,9 @@ module ariane .commit_instr_i ( commit_instr_id_commit ), .commit_ack_o ( commit_ack ), .no_st_pending_i ( no_st_pending_ex_commit ), - .waddr_a_o ( waddr_a_commit_id ), - .wdata_a_o ( wdata_a_commit_id ), - .we_a_o ( we_a_commit_id ), + .waddr_o ( waddr_commit_id ), + .wdata_o ( wdata_commit_id ), + .we_o ( we_commit_id ), .commit_lsu_o ( lsu_commit_commit_ex ), .commit_lsu_ready_i ( lsu_commit_ready_ex_commit ), .commit_csr_o ( csr_commit_commit_ex ), @@ -512,7 +512,7 @@ module ariane .debug_csr_we_i ( csr_we_debug_csr ), .debug_csr_wdata_i ( csr_wdata_debug_csr ), .debug_csr_rdata_o ( csr_rdata_debug_csr ), - .commit_ack_i ( commit_ack ), + .commit_ack_i ( commit_ack[0] ), .ex_i ( ex_commit ), .csr_op_i ( csr_op_commit_csr ), .csr_addr_i ( csr_addr_ex_csr ), @@ -570,8 +570,8 @@ module ariane // Debug // ------------ debug_unit debug_unit_i ( - .commit_instr_i ( commit_instr_id_commit ), - .commit_ack_i ( commit_ack ), + .commit_instr_i ( commit_instr_id_commit[0] ), + .commit_ack_i ( commit_ack[0] ), .ex_i ( ex_commit ), .halt_o ( halt_debug_ctrl ), .fetch_enable_i ( fetch_enable ), @@ -613,12 +613,12 @@ module ariane assign tracer_if.issue_ack = issue_stage_i.scoreboard_i.issue_ack_i; assign tracer_if.issue_sbe = issue_stage_i.scoreboard_i.issue_instr_o; // write-back - assign tracer_if.waddr = waddr_a_commit_id; - assign tracer_if.wdata = wdata_a_commit_id; - assign tracer_if.we = we_a_commit_id; + assign tracer_if.waddr = waddr_commit_id[0]; + assign tracer_if.wdata = wdata_commit_id[0]; + assign tracer_if.we = we_commit_id[0]; // commit - assign tracer_if.commit_instr = commit_instr_id_commit; - assign tracer_if.commit_ack = commit_ack; + assign tracer_if.commit_instr = commit_instr_id_commit[0]; + assign tracer_if.commit_ack = commit_ack[0]; // address translation // stores assign tracer_if.st_valid = ex_stage_i.lsu_i.store_unit_i.store_buffer_i.valid_i; diff --git a/src/commit_stage.sv b/src/commit_stage.sv index b75c9016b..415359d00 100644 --- a/src/commit_stage.sv +++ b/src/commit_stage.sv @@ -18,40 +18,44 @@ // import ariane_pkg::*; -module commit_stage ( - input logic clk_i, - input logic halt_i, // request to halt the core +module commit_stage #( + parameter int unsigned NR_COMMIT_PORTS = 2 + )( + input logic clk_i, + input logic halt_i, // request to halt the core - output exception exception_o, // take exception to controller + output exception exception_o, // take exception to controller // from scoreboard - input scoreboard_entry commit_instr_i, // the instruction we want to commit - output logic commit_ack_o, // acknowledge that we are indeed committing + input scoreboard_entry [NR_COMMIT_PORTS-1:0] commit_instr_i, // the instruction we want to commit + output logic [NR_COMMIT_PORTS-1:0] commit_ack_o, // acknowledge that we are indeed committing // to register file - output logic[4:0] waddr_a_o, // register file write address - output logic[63:0] wdata_a_o, // register file write data - output logic we_a_o, // register file write enable + output logic [NR_COMMIT_PORTS-1:0][4:0] waddr_o, // register file write address + output logic [NR_COMMIT_PORTS-1:0][63:0] wdata_o, // register file write data + output logic [NR_COMMIT_PORTS-1:0] we_o, // register file write enable // to CSR file and PC Gen (because on certain CSR instructions we'll need to flush the whole pipeline) - output logic [63:0] pc_o, + output logic [63:0] pc_o, // to/from CSR file - output fu_op csr_op_o, // decoded CSR operation - output logic [63:0] csr_wdata_o, // data to write to CSR - input logic [63:0] csr_rdata_i, // data to read from CSR - input exception csr_exception_i, // exception or interrupt occurred in CSR stage (the same as commit) + output fu_op csr_op_o, // decoded CSR operation + output logic [63:0] csr_wdata_o, // data to write to CSR + input logic [63:0] csr_rdata_i, // data to read from CSR + input exception csr_exception_i, // exception or interrupt occurred in CSR stage (the same as commit) // commit signals to ex - output logic commit_lsu_o, // commit the pending store - input logic commit_lsu_ready_i, // commit buffer of LSU is ready - input logic no_st_pending_i, // there is no store pending - output logic commit_csr_o, // commit the pending CSR instruction - output logic fence_i_o, // flush I$ and pipeline - output logic fence_o, // flush D$ and pipeline - output logic sfence_vma_o // flush TLBs and pipeline + output logic commit_lsu_o, // commit the pending store + input logic commit_lsu_ready_i, // commit buffer of LSU is ready + input logic no_st_pending_i, // there is no store pending + output logic commit_csr_o, // commit the pending CSR instruction + output logic fence_i_o, // flush I$ and pipeline + output logic fence_o, // flush D$ and pipeline + output logic sfence_vma_o // flush TLBs and pipeline ); - assign waddr_a_o = commit_instr_i.rd; - assign pc_o = commit_instr_i.pc; + assign waddr_o[0] = commit_instr_i[0].rd; + assign waddr_o[1] = commit_instr_i[1].rd; + + assign pc_o = commit_instr_i[0].pc; // ------------------- // Commit Instruction @@ -59,22 +63,24 @@ module commit_stage ( // write register file or commit instruction in LSU or CSR Buffer always_comb begin : commit // default assignments - commit_ack_o = 1'b0; - we_a_o = 1'b0; - commit_lsu_o = 1'b0; - commit_csr_o = 1'b0; - wdata_a_o = commit_instr_i.result; - csr_op_o = ADD; // this corresponds to a CSR NOP - csr_wdata_o = 64'b0; - fence_i_o = 1'b0; - fence_o = 1'b0; - sfence_vma_o = 1'b0; + commit_ack_o[0] = 1'b0; + commit_ack_o[1] = 1'b0; + + we_o[0] = 1'b0; + commit_lsu_o = 1'b0; + commit_csr_o = 1'b0; + wdata_o[0] = commit_instr_i[0].result; + csr_op_o = ADD; // this corresponds to a CSR NOP + csr_wdata_o = 64'b0; + fence_i_o = 1'b0; + fence_o = 1'b0; + sfence_vma_o = 1'b0; // we will not commit the instruction if we took an exception // but we do not commit the instruction if we requested a halt - if (commit_instr_i.valid && !halt_i) begin + if (commit_instr_i[0].valid && !halt_i) begin - commit_ack_o = 1'b1; + commit_ack_o[0] = 1'b1; // register will be the all zero register. // and also acknowledge the instruction, this is mainly done for the instruction tracer // as it will listen on the instruction ack signal. For the overall result it does not make any @@ -82,17 +88,17 @@ module commit_stage ( if (!exception_o.valid) begin // we can definitely write the register file // if the instruction is not committing anything the destination - we_a_o = 1'b1; + we_o[0] = 1'b1; // check whether the instruction we retire was a store // do not commit the instruction if we got an exception since the store buffer will be cleared // by the subsequent flush triggered by an exception - if (commit_instr_i.fu == STORE) begin + if (commit_instr_i[0].fu == STORE) begin // check if the LSU is ready to accept another commit entry (e.g.: a non-speculative store) if (commit_lsu_ready_i) commit_lsu_o = 1'b1; else // if the LSU buffer is not ready - do not commit, wait - commit_ack_o = 1'b0; + commit_ack_o[0] = 1'b0; end end @@ -100,24 +106,24 @@ module commit_stage ( // CSR Logic // --------- // check whether the instruction we retire was a CSR instruction - if (commit_instr_i.fu == CSR) begin + if (commit_instr_i[0].fu == CSR) begin // write the CSR file commit_csr_o = 1'b1; - wdata_a_o = csr_rdata_i; - csr_op_o = commit_instr_i.op; - csr_wdata_o = commit_instr_i.result; + wdata_o[0] = csr_rdata_i; + csr_op_o = commit_instr_i[0].op; + csr_wdata_o = commit_instr_i[0].result; end // ------------------ // SFENCE.VMA Logic // ------------------ // check if this instruction was a SFENCE_VMA - if (commit_instr_i.op == SFENCE_VMA) begin + if (commit_instr_i[0].op == SFENCE_VMA) begin // no store pending so we can flush the TLBs and pipeline if (no_st_pending_i) begin sfence_vma_o = 1'b1; // wait for the store buffer to drain until flushing the pipeline end else begin - commit_ack_o = 1'b0; + commit_ack_o[0] = 1'b0; end end // ------------------ @@ -125,16 +131,16 @@ module commit_stage ( // ------------------ // Fence synchronizes data and instruction streams. That means that we need to flush the private icache // and the private dcache. This is the most expensive instruction. - if (commit_instr_i.op == FENCE_I) begin - commit_ack_o = 1'b1; + if (commit_instr_i[0].op == FENCE_I) begin + commit_ack_o[0] = 1'b1; // tell the controller to flush the I$ fence_i_o = 1'b1; end // ------------------ // FENCE Logic // ------------------ - if (commit_instr_i.op == FENCE) begin - commit_ack_o = 1'b1; + if (commit_instr_i[0].op == FENCE) begin + commit_ack_o[0] = 1'b1; // tell the controller to flush the D$ fence_o = 1'b1; end @@ -156,7 +162,7 @@ module commit_stage ( // can happen anywhere in the execution flow and might just happen between two legal instructions - the PC would then // be outdated. The solution here is to defer any exception/interrupt until we get a valid PC again (from where we cane // resume execution afterwards). - if (commit_instr_i.valid) begin + if (commit_instr_i[0].valid) begin // ------------------------ // check for CSR exception // ------------------------ @@ -165,14 +171,14 @@ module commit_stage ( // if no earlier exception happened the commit instruction will still contain // the instruction data from the ID stage. If a earlier exception happened we don't care // as we will overwrite it anyway in the next IF bl - exception_o.tval = commit_instr_i.ex.tval; + exception_o.tval = commit_instr_i[0].ex.tval; end // ------------------------ // Earlier Exceptions // ------------------------ // but we give precedence to exceptions which happened earlier - if (commit_instr_i.ex.valid) begin - exception_o = commit_instr_i.ex; + if (commit_instr_i[0].ex.valid) begin + exception_o = commit_instr_i[0].ex; end // ------------------------ // Interrupts @@ -181,7 +187,7 @@ module commit_stage ( // by putting interrupts here we give them precedence over any other exception if (csr_exception_i.valid && csr_exception_i.cause[63]) begin exception_o = csr_exception_i; - exception_o.tval = commit_instr_i.ex.tval; + exception_o.tval = commit_instr_i[0].ex.tval; end end // If we halted the processor don't take any exceptions diff --git a/src/issue_read_operands.sv b/src/issue_read_operands.sv index 2630e4aeb..b5c3d74a5 100644 --- a/src/issue_read_operands.sv +++ b/src/issue_read_operands.sv @@ -19,7 +19,9 @@ // import ariane_pkg::*; -module issue_read_operands ( +module issue_read_operands #( + parameter int unsigned NR_COMMIT_PORTS = 2 + )( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low input logic test_en_i, @@ -70,9 +72,9 @@ module issue_read_operands ( input logic csr_ready_i, // FU is ready output logic csr_valid_o, // Output is valid // commit port - input logic [4:0] waddr_a_i, - input logic [63:0] wdata_a_i, - input logic we_a_i + input logic [NR_COMMIT_PORTS-1:0][4:0] waddr_i, + input logic [NR_COMMIT_PORTS-1:0][63:0] wdata_i, + input logic [NR_COMMIT_PORTS-1:0] we_i // committing instruction instruction // from scoreboard // input scoreboard_entry commit_instr_i, @@ -134,9 +136,10 @@ module issue_read_operands ( end // or check that the target destination register will be written in this cycle by the // commit stage - if (we_a_i && waddr_a_i == issue_instr_i.rd) begin - issue_ack_o = 1'b1; - end + for (int unsigned i = 0; i < NR_COMMIT_PORTS; i++) + if (we_i[i] && waddr_i[i] == issue_instr_i.rd) begin + issue_ack_o = 1'b1; + end end // we can also issue the instruction under the following two circumstances: // we can do this even if we are stalled or no functional unit is ready (as we don't need one) @@ -293,9 +296,9 @@ module issue_read_operands ( debug_gpr_rdata_o = operand_a_regfile; raddr_a = issue_instr_i.rs1; // write port - waddr = waddr_a_i; - wdata = wdata_a_i; - we = we_a_i; + waddr = waddr_i[0]; + wdata = wdata_i[0]; + we = we_i[0]; // we've got a debug request in if (debug_gpr_req_i) begin raddr_a = debug_gpr_addr_i; @@ -310,8 +313,7 @@ module issue_read_operands ( // ---------------------- regfile #( .DATA_WIDTH ( 64 ) - ) - regfile_i ( + ) regfile_i ( // Clock and Reset .clk ( clk_i ), .rst_n ( rst_ni ), @@ -325,14 +327,18 @@ module issue_read_operands ( .waddr_a_i ( waddr ), .wdata_a_i ( wdata ), - .we_a_i ( we ) + .we_a_i ( we ), + + .waddr_b_i ( waddr_i[1] ), + .wdata_b_i ( wdata_i[1] ), + .we_b_i ( we_i[1] ) ); // ---------------------- // Registers (ID <-> EX) // ---------------------- always_ff @(posedge clk_i or negedge rst_ni) begin - if(~rst_ni) begin + if (~rst_ni) begin operand_a_q <= '{default: 0}; operand_b_q <= '{default: 0}; imm_q <= 64'b0; @@ -370,6 +376,10 @@ module issue_read_operands ( assert property ( @(posedge clk_i) (alu_valid_q || lsu_valid_q || csr_valid_q || branch_valid_q || mult_valid_q) |-> (!$isunknown(operand_a_q) && !$isunknown(operand_b_q))) else $warning ("Got unknown value in one of the operands"); + + initial begin + assert (NR_COMMIT_PORTS == 2) else $error("Only two commit ports are supported at the moment!"); + end `endif `endif endmodule diff --git a/src/issue_stage.sv b/src/issue_stage.sv index 6acc3ab41..3b031d63d 100644 --- a/src/issue_stage.sv +++ b/src/issue_stage.sv @@ -22,8 +22,9 @@ import ariane_pkg::*; module issue_stage #( - parameter int NR_ENTRIES = 8, - parameter int NR_WB_PORTS = 4 + parameter int unsigned NR_ENTRIES = 8, + parameter int unsigned NR_WB_PORTS = 4, + parameter int unsigned NR_COMMIT_PORTS = 2 )( input logic clk_i, // Clock input logic rst_ni, // Asynchronous reset active low @@ -72,17 +73,17 @@ module issue_stage #( // write back port input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i, - input logic [NR_WB_PORTS-1:0][63:0] wdata_i, + input logic [NR_WB_PORTS-1:0][63:0] wbdata_i, input exception [NR_WB_PORTS-1:0] ex_ex_i, // exception from execute stage input logic [NR_WB_PORTS-1:0] wb_valid_i, - // commit port - input logic[4:0] waddr_a_i, - input logic[63:0] wdata_a_i, - input logic we_a_i, + // commit port + input logic [NR_COMMIT_PORTS-1:0][4:0] waddr_i, + input logic [NR_COMMIT_PORTS-1:0][63:0] wdata_i, + input logic [NR_COMMIT_PORTS-1:0] we_i, - output scoreboard_entry commit_instr_o, - input logic commit_ack_i + output scoreboard_entry [NR_COMMIT_PORTS-1:0] commit_instr_o, + input logic [NR_COMMIT_PORTS-1:0] commit_ack_i ); // --------------------------------------------------- // Scoreboard (SB) <-> Issue and Read Operands (IRO) @@ -170,7 +171,7 @@ module issue_stage #( .issue_ack_i ( issue_ack_iro_sb ), .trans_id_i ( trans_id_i ), - .wdata_i ( wdata_i ), + .wbdata_i ( wbdata_i ), .ex_i ( ex_ex_i ), .* ); diff --git a/src/regfile.sv b/src/regfile.sv index 70799dd85..66fe3c7b2 100644 --- a/src/regfile.sv +++ b/src/regfile.sv @@ -50,107 +50,131 @@ module regfile // Write port W1 input logic [4:0] waddr_a_i, input logic [DATA_WIDTH-1:0] wdata_a_i, - input logic we_a_i + input logic we_a_i, + // Write port W2 + input logic [4:0] waddr_b_i, + input logic [DATA_WIDTH-1:0] wdata_b_i, + input logic we_b_i ); - localparam ADDR_WIDTH = 5;; - localparam NUM_WORDS = 2**ADDR_WIDTH; + localparam ADDR_WIDTH = 5;; + localparam NUM_WORDS = 2**ADDR_WIDTH; - logic [DATA_WIDTH-1:0] mem[NUM_WORDS]; + logic [DATA_WIDTH-1:0] mem[NUM_WORDS]; - logic [NUM_WORDS-1:1] waddr_onehot_a; + logic [NUM_WORDS-1:1] waddr_onehot_a; + logic [NUM_WORDS-1:1] waddr_onehot_b, waddr_onehot_b_q; - logic [NUM_WORDS-1:1] mem_clocks; - logic [DATA_WIDTH-1:0] wdata_a_q; + logic [NUM_WORDS-1:1] mem_clocks; + logic [DATA_WIDTH-1:0] wdata_a_q; + logic [DATA_WIDTH-1:0] wdata_b_q; + // Write port W1 + logic [ADDR_WIDTH-1:0] raddr_a_int, raddr_b_int, waddr_a_int; - // Write port W1 - logic [ADDR_WIDTH-1:0] raddr_a_int, raddr_b_int, waddr_a_int; + assign raddr_a_int = raddr_a_i[ADDR_WIDTH-1:0]; + assign raddr_b_int = raddr_b_i[ADDR_WIDTH-1:0]; + assign waddr_a_int = waddr_a_i[ADDR_WIDTH-1:0]; - assign raddr_a_int = raddr_a_i[ADDR_WIDTH-1:0]; - assign raddr_b_int = raddr_b_i[ADDR_WIDTH-1:0]; - assign waddr_a_int = waddr_a_i[ADDR_WIDTH-1:0]; + int unsigned i; + int unsigned j; + int unsigned k; + int unsigned l; + genvar x; + logic clk_int; - logic clk_int; + //----------------------------------------------------------------------------- + //-- READ : Read address decoder RAD + //----------------------------------------------------------------------------- + assign rdata_a_o = mem[raddr_a_int]; + assign rdata_b_o = mem[raddr_b_int]; - //----------------------------------------------------------------------------- - //-- READ : Read address decoder RAD - //----------------------------------------------------------------------------- - assign rdata_a_o = mem[raddr_a_int]; - assign rdata_b_o = mem[raddr_b_int]; + //----------------------------------------------------------------------------- + // WRITE : SAMPLE INPUT DATA + //--------------------------------------------------------------------------- - //----------------------------------------------------------------------------- - // WRITE : SAMPLE INPUT DATA - //--------------------------------------------------------------------------- + cluster_clock_gating CG_WE_GLOBAL + ( + .clk_i ( clk ), + .en_i ( we_a_i ), + .test_en_i ( test_en_i ), + .clk_o ( clk_int ) + ); - cluster_clock_gating CG_WE_GLOBAL - ( - .clk_i ( clk ), - .en_i ( we_a_i ), - .test_en_i ( test_en_i ), - .clk_o ( clk_int ) - ); + // use clk_int here, since otherwise we don't want to write anything anyway + always_ff @(posedge clk_int, negedge rst_n) begin : sample_waddr + if (~rst_n) begin + wdata_a_q <= '0; + wdata_b_q <= '0; + waddr_onehot_b_q <= '0; + end else begin + if (we_a_i) + wdata_a_q <= wdata_a_i; + if (we_b_i) + wdata_b_q <= wdata_b_i; - // use clk_int here, since otherwise we don't want to write anything anyway - always_ff @(posedge clk_int, negedge rst_n) begin : sample_waddr - if (~rst_n) begin - wdata_a_q <= '0; - end else begin - if (we_a_i) - wdata_a_q <= wdata_a_i; + waddr_onehot_b_q <= waddr_onehot_b; + end end - end - //----------------------------------------------------------------------------- - // WRITE : Write Address Decoder (WAD), combinatorial process - //----------------------------------------------------------------------------- - always_comb begin : p_WADa - for (int unsigned i = 1; i < NUM_WORDS; i++) begin : p_WordItera - if ( (we_a_i == 1'b1 ) && (waddr_a_int == i[4:0]) ) - waddr_onehot_a[i] = 1'b1; - else - waddr_onehot_a[i] = 1'b0; + //----------------------------------------------------------------------------- + //-- WRITE : Write Address Decoder (WAD), combinatorial process + //----------------------------------------------------------------------------- + always_comb begin : p_WADa + for (i = 1; i < NUM_WORDS; i++) begin : p_WordItera + if ((we_a_i == 1'b1) && (waddr_a_i == i)) + waddr_onehot_a[i] = 1'b1; + else + waddr_onehot_a[i] = 1'b0; + end end - end - - //----------------------------------------------------------------------------- - // WRITE : Clock gating (if integrated clock-gating cells are available) - //----------------------------------------------------------------------------- - genvar x; - generate - for (x = 1; x < NUM_WORDS; x++) begin : CG_CELL_WORD_ITER - cluster_clock_gating CG_Inst - ( - .clk_i ( clk_int ), - .en_i ( waddr_onehot_a[x] ), - .test_en_i ( test_en_i ), - .clk_o ( mem_clocks[x] ) - ); + always_comb begin : p_WADb + for (j = 1; j < NUM_WORDS; j++) begin : p_WordIterb + if ((we_b_i == 1'b1) && (waddr_b_i == j)) + waddr_onehot_b[j] = 1'b1; + else + waddr_onehot_b[j] = 1'b0; + end end - endgenerate - //----------------------------------------------------------------------------- - // WRITE : Write operation - //----------------------------------------------------------------------------- - // Generate M = WORDS sequential processes, each of which describes one - // word of the memory. The processes are synchronized with the clocks - // ClocksxC(i), i = 0, 1, ..., M-1 - // Use active low, i.e. transparent on low latches as storage elements - // Data is sampled on rising clock edge + //----------------------------------------------------------------------------- + //-- WRITE : Clock gating (if integrated clock-gating cells are available) + //----------------------------------------------------------------------------- + generate + for (x = 1; x < NUM_WORDS; x++) + begin : CG_CELL_WORD_ITER + cluster_clock_gating CG_Inst + ( + .clk_i ( clk_int ), + .en_i ( waddr_onehot_a[x] | waddr_onehot_b[x] ), + .test_en_i ( test_en_i ), + .clk_o ( mem_clocks[x] ) + ); + end + endgenerate - always_latch begin : latch_wdata - // Note: The assignment has to be done inside this process or Modelsim complains about it - mem[0] = '0; + //----------------------------------------------------------------------------- + //-- WRITE : Write operation + //----------------------------------------------------------------------------- + //-- Generate M = WORDS sequential processes, each of which describes one + //-- word of the memory. The processes are synchronized with the clocks + //-- ClocksxC(i), i = 0, 1, ..., M-1 + //-- Use active low, i.e. transparent on low latches as storage elements + //-- Data is sampled on rising clock edge - for (int unsigned k = 1; k < NUM_WORDS; k++) begin : w_WordIter - if (mem_clocks[k] == 1'b1) - mem[k] = wdata_a_q; + // Integer registers + always_latch begin : latch_wdata + // Note: The assignment has to be done inside this process or Modelsim complains about it + mem[0] = '0; + + for(k = 1; k < NUM_WORDS; k++) + begin : w_WordIter + if (mem_clocks[k] == 1'b1) + mem[k] = waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q; + end end - end - - -endmodule \ No newline at end of file +endmodule diff --git a/src/scoreboard.sv b/src/scoreboard.sv index ae8e2bb43..c3498067d 100644 --- a/src/scoreboard.sv +++ b/src/scoreboard.sv @@ -22,7 +22,8 @@ import ariane_pkg::*; module scoreboard #( parameter int unsigned NR_ENTRIES = 8, - parameter int unsigned NR_WB_PORTS = 1 + parameter int unsigned NR_WB_PORTS = 1, + parameter int unsigned NR_COMMIT_PORTS = 2 ) ( input logic clk_i, // Clock @@ -43,8 +44,8 @@ module scoreboard #( output logic rs2_valid_o, // advertise instruction to commit stage, if commit_ack_i is asserted advance the commit pointer - output scoreboard_entry commit_instr_o, - input logic commit_ack_i, + output scoreboard_entry [NR_COMMIT_PORTS-1:0] commit_instr_o, + input logic [NR_COMMIT_PORTS-1:0] commit_ack_i, // instruction to put on top of scoreboard e.g. : top pointer // we can always put this instruction to the to p unless we signal with asserted full_o @@ -59,7 +60,7 @@ module scoreboard #( // write-back port input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i, // transaction ID at which to write the result back - input logic [NR_WB_PORTS-1:0][63:0] wdata_i, // write data in + input logic [NR_WB_PORTS-1:0][63:0] wbdata_i, // write data in input exception [NR_WB_PORTS-1:0] ex_i, // exception from a functional unit (e.g.: ld/st exception, divide by zero) input logic [NR_WB_PORTS-1:0] wb_valid_i // data in is valid ); @@ -80,7 +81,10 @@ module scoreboard #( assign issue_full = (issue_cnt_q == NR_ENTRIES-1); // output commit instruction directly - assign commit_instr_o = mem_q[commit_pointer_q].sbe; + always_comb begin : commit_ports + for (logic [$clog2(NR_ENTRIES)-1:0] i = 0; i < NR_COMMIT_PORTS; i++) + commit_instr_o[i] = mem_q[commit_pointer_q + i].sbe; + end // an instruction is ready for issue if we have place in the issue FIFO and it the decoder says it is valid always_comb begin @@ -96,10 +100,10 @@ module scoreboard #( // maintain a FIFO with issued instructions // keep track of all issued instructions always_comb begin : issue_fifo - automatic logic [$clog2(NR_ENTRIES)-1:0] issue_cnt = issue_cnt_q; + automatic logic [$clog2(NR_ENTRIES)-1:0] issue_cnt = issue_cnt_q; + automatic logic [$clog2(NR_ENTRIES)-1:0] commit_pointer = commit_pointer_q; // default assignment mem_n = mem_q; - commit_pointer_n = commit_pointer_q; issue_pointer_n = issue_pointer_q; // if we got a acknowledge from the issue stage, put this scoreboard entry in the queue @@ -120,7 +124,7 @@ module scoreboard #( // something in the pipeline e.g. an incomplete memory operation) if (wb_valid_i[i] && mem_n[trans_id_i[i]].issued) begin mem_n[trans_id_i[i]].sbe.valid = 1'b1; - mem_n[trans_id_i[i]].sbe.result = wdata_i[i]; + mem_n[trans_id_i[i]].sbe.result = wbdata_i[i]; // write the exception back if it is valid if (ex_i[i].valid) mem_n[trans_id_i[i]].sbe.ex = ex_i[i]; @@ -131,14 +135,16 @@ module scoreboard #( // Commit Port // ------------ // we've got an acknowledge from commit - if (commit_ack_i) begin - // decrease the issue counter - issue_cnt--; - // this instruction is no longer in issue e.g.: it is considered finished - mem_n[commit_pointer_q].issued = 1'b0; - mem_n[commit_pointer_q].sbe.valid = 1'b0; - // advance commit pointer - commit_pointer_n = commit_pointer_n + 1'b1; + for (logic [$clog2(NR_ENTRIES)-1:0] i = 0; i < NR_COMMIT_PORTS; i++) begin + if (commit_ack_i[i]) begin + // decrease the issue counter + issue_cnt--; + // this instruction is no longer in issue e.g.: it is considered finished + mem_n[commit_pointer_q + i].issued = 1'b0; + mem_n[commit_pointer_q + i].sbe.valid = 1'b0; + // advance commit pointer + commit_pointer++; + end end // ------ // Flush @@ -152,11 +158,13 @@ module scoreboard #( // set the pointer and counter back to zero issue_cnt = '0; issue_pointer_n = '0; - commit_pointer_n = '0; + commit_pointer = '0; end end // update issue counter issue_cnt_n = issue_cnt; + // update commit potiner + commit_pointer_n = commit_pointer; end // ------------------- @@ -208,12 +216,12 @@ module scoreboard #( // make sure that we are not forwarding a result that got an exception for (int unsigned j = 0; j < NR_WB_PORTS; j++) begin if (mem_q[trans_id_i[j]].sbe.rd == rs1_i && wb_valid_i[j] && ~ex_i[j].valid) begin - rs1_o = wdata_i[j]; + rs1_o = wbdata_i[j]; rs1_valid_o = wb_valid_i[j]; break; end if (mem_q[trans_id_i[j]].sbe.rd == rs2_i && wb_valid_i[j] && ~ex_i[j].valid) begin - rs2_o = wdata_i[j]; + rs2_o = wbdata_i[j]; rs2_valid_o = wb_valid_i[j]; break; end @@ -252,8 +260,13 @@ module scoreboard #( else $error ("RD 0 should not bet set"); // assert that we never acknowledge a commit if the instruction is not valid assert property ( - @(posedge clk_i) (rst_ni && commit_ack_i |-> commit_instr_o.valid)) + @(posedge clk_i) (rst_ni && commit_ack_i[0] |-> commit_instr_o[0].valid)) else $error ("Commit acknowledged but instruction is not valid"); + + assert property ( + @(posedge clk_i) (rst_ni && commit_ack_i[1] |-> commit_instr_o[1].valid)) + else $error ("Commit acknowledged but instruction is not valid"); + // assert that we never give an issue ack signal if the instruction is not valid assert property ( @(posedge clk_i) (rst_ni && issue_ack_i |-> issue_instr_valid_o)) diff --git a/tb b/tb index de126de43..184ef9b9b 160000 --- a/tb +++ b/tb @@ -1 +1 @@ -Subproject commit de126de43d25e8d95e1550e262c829cae44c012d +Subproject commit 184ef9b9bf920fc1a046e5e0bc8ba69e1772a687