WIP: Add second commit port - not used right now

This commit is contained in:
Florian Zaruba 2017-09-12 15:08:25 +02:00
parent cca1a0220f
commit 8697c11dd3
8 changed files with 254 additions and 199 deletions

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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 ),
.*
);

View file

@ -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

View file

@ -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

@ -1 +1 @@
Subproject commit de126de43d25e8d95e1550e262c829cae44c012d
Subproject commit 184ef9b9bf920fc1a046e5e0bc8ba69e1772a687