mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 21:57:11 -04:00
WIP: Add second commit port - not used right now
This commit is contained in:
parent
cca1a0220f
commit
8697c11dd3
8 changed files with 254 additions and 199 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ),
|
||||
.*
|
||||
);
|
||||
|
|
182
src/regfile.sv
182
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
|
||||
endmodule
|
||||
|
|
|
@ -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))
|
||||
|
|
2
tb
2
tb
|
@ -1 +1 @@
|
|||
Subproject commit de126de43d25e8d95e1550e262c829cae44c012d
|
||||
Subproject commit 184ef9b9bf920fc1a046e5e0bc8ba69e1772a687
|
Loading…
Add table
Add a link
Reference in a new issue