re-parameterization

This commit is contained in:
Eric Matthews 2021-07-16 15:46:07 -07:00
parent 2a77a76132
commit 14075c8f13
27 changed files with 849 additions and 637 deletions

View file

@ -85,7 +85,7 @@ module axi_to_arb
logic address_phase_complete;
logic [31:0] amo_result;
logic [31:0] amo_result_r;
logic [DCACHE_SUB_LINE_ADDR_W-1:0] read_count;
logic [$clog2(EXAMPLE_CONFIG.DCACHE.LINE_W)-1:0] read_count;
logic amo_write_ready;
logic[4:0] write_reference_burst_count;
@ -141,7 +141,7 @@ module axi_to_arb
//TODO: assumption that all data caches have same line size, would have to update wrt the burst size to be safe if they have different line lengths
//also update araddr
always_ff @ (posedge clk) begin
if (axi_rvalid && (read_count == l2.addr[DCACHE_SUB_LINE_ADDR_W-1:0]))
if (axi_rvalid && (read_count == l2.addr[$clog2(EXAMPLE_CONFIG.DCACHE.LINE_W)-1:0]))
amo_result_r <= amo_result;
end
@ -150,7 +150,7 @@ module axi_to_arb
amo_write_ready <= 0;
else if (pop)
amo_write_ready <= 0;
else if (l2.is_amo && axi_rvalid && read_count == l2.addr[DCACHE_SUB_LINE_ADDR_W-1:0])
else if (l2.is_amo && axi_rvalid && read_count == l2.addr[$clog2(EXAMPLE_CONFIG.DCACHE.LINE_W)-1:0])
amo_write_ready <= 1;
end
//End AMO
@ -166,7 +166,7 @@ module axi_to_arb
assign axi_arprot = '0;
assign axi_arid = 6'(l2.id);
assign axi_araddr ={l2.addr[29:DCACHE_SUB_LINE_ADDR_W], {DCACHE_SUB_LINE_ADDR_W{1'b0}}, 2'b00};
assign axi_araddr ={l2.addr[29:$clog2(EXAMPLE_CONFIG.DCACHE.LINE_W)], {$clog2(EXAMPLE_CONFIG.DCACHE.LINE_W){1'b0}}, 2'b00};
assign write_reference_burst_count = read_modify_write ? 0 : burst_count;

View file

@ -26,30 +26,33 @@ module branch_predictor
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
branch_predictor_interface.branch_predictor bp,
output branch_metadata_t branch_metadata_if,
input branch_metadata_t branch_metadata_ex,
input branch_results_t br_results
input branch_results_t br_results,
ras_interface.branch_predictor ras
);
//BP tag width can be reduced, based on memory size, when virtual address
//support is not enabled
localparam longint CACHE_RANGE = 64'(MEMORY_ADDR_H) - 64'(MEMORY_ADDR_L) + 1;
localparam longint SCRATCH_RANGE = 64'(SCRATCH_ADDR_H) - 64'(SCRATCH_ADDR_L) + 1;
localparam longint CACHE_RANGE = 64'(CONFIG.ICACHE_ADDR.H) - 64'(CONFIG.ICACHE_ADDR.L) + 1;
localparam longint SCRATCH_RANGE = 64'(CONFIG.ILOCAL_MEM_ADDR.H) - 64'(CONFIG.ILOCAL_MEM_ADDR.L) + 1;
function int get_memory_width();
if(ENABLE_S_MODE)
if(CONFIG.INCLUDE_S_MODE)
return 32;
else if (USE_ICACHE && CACHE_RANGE > SCRATCH_RANGE)
else if (CONFIG.INCLUDE_ICACHE && CACHE_RANGE > SCRATCH_RANGE)
return $clog2(CACHE_RANGE);
else
return $clog2(SCRATCH_RANGE);
endfunction
localparam BRANCH_ADDR_W = $clog2(BRANCH_TABLE_ENTRIES);
localparam BRANCH_ADDR_W = $clog2(CONFIG.BP.ENTRIES);
localparam BTAG_W = get_memory_width() - BRANCH_ADDR_W - 2;
function logic[BTAG_W-1:0] get_tag (input logic[31:0] pc);
@ -65,31 +68,39 @@ module branch_predictor
branch_predictor_metadata_t metadata;
} branch_table_entry_t;
branch_table_entry_t [BRANCH_PREDICTOR_WAYS-1:0] if_entry;
branch_table_entry_t [CONFIG.BP.WAYS-1:0] if_entry;
branch_table_entry_t ex_entry;
typedef struct packed{
branch_predictor_metadata_t branch_predictor_metadata;
logic branch_prediction_used;
logic [CONFIG.BP.WAYS-1:0] branch_predictor_update_way;
} branch_metadata_t;
(* ramstyle = "MLAB, no_rw_check" *) logic [$bits(branch_metadata_t)-1:0] branch_metadata_table [MAX_IDS];
branch_metadata_t branch_metadata_if;
branch_metadata_t branch_metadata_ex;
logic branch_predictor_direction_changed;
logic [31:0] new_jump_addr;
logic [BRANCH_PREDICTOR_WAYS-1:0][31:0] predicted_pc;
logic [CONFIG.BP.WAYS-1:0][31:0] predicted_pc;
logic [BRANCH_PREDICTOR_WAYS-1:0] tag_matches;
logic [BRANCH_PREDICTOR_WAYS-1:0] replacement_way;
logic [BRANCH_PREDICTOR_WAYS-1:0] tag_update_way;
logic [BRANCH_PREDICTOR_WAYS-1:0] target_update_way;
logic [$clog2(BRANCH_PREDICTOR_WAYS > 1 ? BRANCH_PREDICTOR_WAYS : 2)-1:0] hit_way;
logic [CONFIG.BP.WAYS-1:0] tag_matches;
logic [CONFIG.BP.WAYS-1:0] replacement_way;
logic [CONFIG.BP.WAYS-1:0] tag_update_way;
logic [CONFIG.BP.WAYS-1:0] target_update_way;
logic [$clog2(CONFIG.BP.WAYS > 1 ? CONFIG.BP.WAYS : 2)-1:0] hit_way;
logic tag_match;
logic use_predicted_pc;
/////////////////////////////////////////
genvar i;
generate if (USE_BRANCH_PREDICTOR)
for (i=0; i<BRANCH_PREDICTOR_WAYS; i++) begin : branch_tag_banks
branch_predictor_ram #(.C_DATA_WIDTH($bits(branch_table_entry_t)), .C_DEPTH(BRANCH_TABLE_ENTRIES))
generate if (CONFIG.INCLUDE_BRANCH_PREDICTOR)
for (i=0; i<CONFIG.BP.WAYS; i++) begin : branch_tag_banks
branch_predictor_ram #(.C_DATA_WIDTH($bits(branch_table_entry_t)), .C_DEPTH(CONFIG.BP.ENTRIES))
tag_bank (
.clk (clk),
.rst (rst),
.write_addr (br_results.pc_ex[2 +: BRANCH_ADDR_W]),
.write_addr (br_results.pc[2 +: BRANCH_ADDR_W]),
.write_en (tag_update_way[i]),
.write_data (ex_entry),
.read_addr (bp.next_pc[2 +: BRANCH_ADDR_W]),
@ -98,15 +109,15 @@ module branch_predictor
end
endgenerate
generate if (USE_BRANCH_PREDICTOR)
for (i=0; i<BRANCH_PREDICTOR_WAYS; i++) begin : branch_table_banks
branch_predictor_ram #(.C_DATA_WIDTH(32), .C_DEPTH(BRANCH_TABLE_ENTRIES))
generate if (CONFIG.INCLUDE_BRANCH_PREDICTOR)
for (i=0; i<CONFIG.BP.WAYS; i++) begin : branch_table_banks
branch_predictor_ram #(.C_DATA_WIDTH(32), .C_DEPTH(CONFIG.BP.ENTRIES))
addr_table (
.clk (clk),
.rst (rst),
.write_addr(br_results.pc_ex[2 +: BRANCH_ADDR_W]),
.write_addr(br_results.pc[2 +: BRANCH_ADDR_W]),
.write_en(target_update_way[i]),
.write_data(br_results.new_pc),
.write_data(br_results.target_pc),
.read_addr(bp.next_pc[2 +: BRANCH_ADDR_W]),
.read_en(bp.new_mem_request),
.read_data(predicted_pc[i])
@ -114,16 +125,16 @@ module branch_predictor
end
endgenerate
generate if (USE_BRANCH_PREDICTOR)
for (i=0; i<BRANCH_PREDICTOR_WAYS; i++) begin : branch_hit_detection
generate if (CONFIG.INCLUDE_BRANCH_PREDICTOR)
for (i=0; i<CONFIG.BP.WAYS; i++) begin : branch_hit_detection
assign tag_matches[i] = ({if_entry[i].valid, if_entry[i].tag} == {1'b1, get_tag(bp.if_pc)});
end
endgenerate
////////////////////////////////////////////////////
//Instruction Fetch Response
generate if (BRANCH_PREDICTOR_WAYS > 1)
one_hot_to_integer #(BRANCH_PREDICTOR_WAYS) hit_way_conv (
generate if (CONFIG.BP.WAYS > 1)
one_hot_to_integer #(CONFIG.BP.WAYS) hit_way_conv (
.clk (clk),
.rst (rst),
.one_hot(tag_matches),
@ -134,7 +145,7 @@ module branch_predictor
endgenerate
assign tag_match = |tag_matches;
assign use_predicted_pc = USE_BRANCH_PREDICTOR & tag_match;
assign use_predicted_pc = CONFIG.INCLUDE_BRANCH_PREDICTOR & tag_match;
//Predicted PC and whether the prediction is valid
assign bp.predicted_pc = predicted_pc[hit_way];
@ -143,13 +154,32 @@ module branch_predictor
assign bp.is_return = if_entry[hit_way].is_return;
assign bp.is_call = if_entry[hit_way].is_call;
////////////////////////////////////////////////////
//Instruction Fetch metadata
cycler #(CONFIG.BP.WAYS)
replacement_policy (
.clk (clk),
.rst (rst),
.en (1'b1),
.one_hot (replacement_way)
);
assign branch_metadata_if.branch_predictor_metadata = if_entry[hit_way].metadata;
assign branch_metadata_if.branch_prediction_used = use_predicted_pc;
assign branch_metadata_if.branch_predictor_update_way = tag_match ? tag_matches : replacement_way;
always_ff @ (posedge clk) begin
if (bp.pc_id_assigned)
branch_metadata_table[bp.pc_id] <= branch_metadata_if;
end
assign branch_metadata_ex = branch_metadata_table[br_results.id];
////////////////////////////////////////////////////
//Execution stage update
assign ex_entry.valid = 1;
assign ex_entry.tag = get_tag(br_results.pc_ex);
assign ex_entry.is_branch = br_results.is_branch_ex;
assign ex_entry.is_return = br_results.is_return_ex;
assign ex_entry.is_call = br_results.is_call_ex;
assign ex_entry.tag = get_tag(br_results.pc);
assign ex_entry.is_branch = br_results.is_branch;
assign ex_entry.is_return = br_results.is_return;
assign ex_entry.is_call = br_results.is_call;
//2-bit saturating counter
@ -167,23 +197,14 @@ module branch_predictor
(~branch_metadata_ex.branch_prediction_used) |
(branch_metadata_ex.branch_predictor_metadata[1] ^ ex_entry.metadata[1]);
assign tag_update_way = {BRANCH_PREDICTOR_WAYS{br_results.branch_ex}} & (branch_metadata_ex.branch_predictor_update_way);
assign target_update_way = {BRANCH_PREDICTOR_WAYS{branch_predictor_direction_changed}} & tag_update_way;
assign tag_update_way = {CONFIG.BP.WAYS{br_results.valid}} & (branch_metadata_ex.branch_predictor_update_way);
assign target_update_way = {CONFIG.BP.WAYS{branch_predictor_direction_changed}} & tag_update_way;
////////////////////////////////////////////////////
//Target PC if branch flush occured
assign bp.branch_flush_pc = br_results.new_pc;
assign bp.branch_flush_pc = br_results.target_pc;
////////////////////////////////////////////////////
//Instruction Fetch metadata
cycler #(BRANCH_PREDICTOR_WAYS) replacement_policy (
.clk (clk),
.rst (rst),
.en (1'b1),
.one_hot (replacement_way)
);
assign branch_metadata_if.branch_predictor_metadata = if_entry[hit_way].metadata;
assign branch_metadata_if.branch_prediction_used = use_predicted_pc;
assign branch_metadata_if.branch_predictor_update_way = tag_match ? tag_matches : replacement_way;
//RAS support
assign ras.branch_retired = br_results.valid & br_results.is_branch & branch_metadata_ex.branch_prediction_used;
endmodule

View file

@ -26,6 +26,10 @@ module branch_unit
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -33,12 +37,8 @@ module branch_unit
unit_issue_interface.unit issue,
input branch_inputs_t branch_inputs,
output branch_results_t br_results,
ras_interface.branch_unit ras,
output logic branch_flush,
output id_t branch_id,
input branch_metadata_t branch_metadata_ex,
output logic potential_branch_exception,
output logic branch_exception_is_jump,
output exception_packet_t br_exception,
@ -115,7 +115,7 @@ module branch_unit
//Exception support
id_t jmp_id;
generate if (ENABLE_M_MODE) begin
generate if (CONFIG.INCLUDE_M_MODE) begin
always_ff @(posedge clk) begin
if (issue.possible_issue) begin
jmp_id <= issue.id;
@ -131,15 +131,6 @@ module branch_unit
end
endgenerate
////////////////////////////////////////////////////
//ID Management
assign branch_complete = instruction_is_completing & (~jal_jalr_ex) & (~br_exception.valid);
assign branch_id = id_ex;
////////////////////////////////////////////////////
//RAS support
assign ras.branch_retired = branch_complete & branch_metadata_ex.branch_prediction_used;
////////////////////////////////////////////////////
//Predictor support
logic is_return;
@ -152,13 +143,14 @@ module branch_unit
end
end
assign br_results.pc_ex = pc_ex;
assign br_results.new_pc = new_pc_ex;
assign br_results.id = id_ex;
assign br_results.valid = instruction_is_completing;
assign br_results.pc = pc_ex;
assign br_results.target_pc = new_pc_ex;
assign br_results.branch_taken = branch_taken_ex;
assign br_results.branch_ex = instruction_is_completing;
assign br_results.is_branch_ex = ~jal_jalr_ex;
assign br_results.is_return_ex = is_return;
assign br_results.is_call_ex = is_call;
assign br_results.is_branch = ~jal_jalr_ex;
assign br_results.is_return = is_return;
assign br_results.is_call = is_call;
assign branch_flush = instruction_is_completing && (branch_inputs.issue_pc[31:1] != new_pc_ex[31:1]);

View file

@ -27,6 +27,10 @@ module csr_regs
import taiga_types::*;
import csr_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -89,9 +93,9 @@ module csr_regs
satp_t satp;
logic[COUNTER_W-1:0] mcycle;
logic[COUNTER_W-1:0] mtime;
logic[COUNTER_W-1:0] minst_ret;
logic[CONFIG.CSRS.COUNTER_W-1:0] mcycle;
logic[CONFIG.CSRS.COUNTER_W-1:0] mtime;
logic[CONFIG.CSRS.COUNTER_W-1:0] minst_ret;
localparam INST_RET_INC_W = 2;
logic [INST_RET_INC_W-1:0] inst_ret_inc;
@ -152,14 +156,14 @@ module csr_regs
////////////////////////////////////////////////////
//Machine ISA register
const misa_t misa = '{default:0, mxlen:1, A:(USE_AMO), I:1, M:(USE_MUL && USE_DIV), S:(ENABLE_S_MODE), U:(ENABLE_U_MODE)};
const misa_t misa = '{default:0, mxlen:1, A:(CONFIG.INCLUDE_AMO), I:1, M:(CONFIG.INCLUDE_MUL && CONFIG.INCLUDE_DIV), S:(CONFIG.INCLUDE_S_MODE), U:(CONFIG.INCLUDE_U_MODE)};
////////////////////////////////////////////////////
//Machine Version Registers
const logic [XLEN-1:0] mvendorid = 0;
const logic [XLEN-1:0] marchid = 0;
const logic [XLEN-1:0] mimpid = MACHINE_IMPLEMENTATION_ID;
const logic [XLEN-1:0] mhartid = CPU_ID;
const logic [XLEN-1:0] mimpid = CONFIG.CSRS.MACHINE_IMPLEMENTATION_ID;
const logic [XLEN-1:0] mhartid = CONFIG.CSRS.CPU_ID;
////////////////////////////////////////////////////
//MSTATUS
@ -185,14 +189,14 @@ module csr_regs
//Virtualization support: TSR, TW, TVM unused
//Extension context status: SD, FS, XS unused
const mstatus_t mstatus_mask =
'{default:0, mprv:(ENABLE_U_MODE | ENABLE_S_MODE), mxr:(ENABLE_S_MODE),
sum:(ENABLE_U_MODE & ENABLE_S_MODE), mpp:'1, spp:(ENABLE_S_MODE),
mpie:1, spie:(ENABLE_S_MODE), mie:1, sie:(ENABLE_S_MODE)};
'{default:0, mprv:(CONFIG.INCLUDE_U_MODE | CONFIG.INCLUDE_S_MODE), mxr:(CONFIG.INCLUDE_S_MODE),
sum:(CONFIG.INCLUDE_U_MODE & CONFIG.INCLUDE_S_MODE), mpp:'1, spp:(CONFIG.INCLUDE_S_MODE),
mpie:1, spie:(CONFIG.INCLUDE_S_MODE), mie:1, sie:(CONFIG.INCLUDE_S_MODE)};
const mstatus_t sstatus_mask = '{default:0, mxr:1, sum:1, spp:1, spie:1, sie:1};
generate if (ENABLE_M_MODE) begin
generate if (CONFIG.INCLUDE_M_MODE) begin
privilege_t trap_return_privilege_level;
privilege_t exception_privilege_level;
@ -207,7 +211,7 @@ generate if (ENABLE_M_MODE) begin
always_comb begin
exception_privilege_level = MACHINE_PRIVILEGE;
interrupt_privilege_level = MACHINE_PRIVILEGE;
if (ENABLE_S_MODE && privilege_level inside {SUPERVISOR_PRIVILEGE, USER_PRIVILEGE}) begin
if (CONFIG.INCLUDE_S_MODE && privilege_level inside {SUPERVISOR_PRIVILEGE, USER_PRIVILEGE}) begin
if (medeleg[gc_exception.code])
exception_privilege_level = SUPERVISOR_PRIVILEGE;
if (mideleg[gc_exception.code])
@ -265,7 +269,7 @@ generate if (ENABLE_M_MODE) begin
end else if (mret) begin
mstatus_return.mie = mstatus.mpie;
mstatus_return.mpie = 1;
mstatus_return.mpp = ENABLE_U_MODE ? USER_PRIVILEGE : MACHINE_PRIVILEGE;
mstatus_return.mpp = CONFIG.INCLUDE_U_MODE ? USER_PRIVILEGE : MACHINE_PRIVILEGE;
if (mstatus.mpp != MACHINE_PRIVILEGE)
mstatus_return.mprv = 0;
end
@ -307,7 +311,7 @@ generate if (ENABLE_M_MODE) begin
logic [31:0] medeleg_mask;
always_comb begin
medeleg_mask = 0;
if (ENABLE_S_MODE) begin
if (CONFIG.INCLUDE_S_MODE) begin
medeleg_mask[INST_ADDR_MISSALIGNED] = 1;
medeleg_mask[INST_ACCESS_FAULT] = 1;
medeleg_mask[ILLEGAL_INST] = 1;
@ -335,10 +339,10 @@ generate if (ENABLE_M_MODE) begin
logic [31:0] mideleg_mask;
always_comb begin
mideleg_mask = 0;
if (ENABLE_S_MODE) begin
mideleg_mask[S_SOFTWARE_INTERRUPT] = ENABLE_S_MODE;
mideleg_mask[S_TIMER_INTERRUPT] = ENABLE_S_MODE;
mideleg_mask[S_EXTERNAL_INTERRUPT] = ENABLE_S_MODE;
if (CONFIG.INCLUDE_S_MODE) begin
mideleg_mask[S_SOFTWARE_INTERRUPT] = CONFIG.INCLUDE_S_MODE;
mideleg_mask[S_TIMER_INTERRUPT] = CONFIG.INCLUDE_S_MODE;
mideleg_mask[S_EXTERNAL_INTERRUPT] = CONFIG.INCLUDE_S_MODE;
end
end
always_ff @(posedge clk) begin
@ -350,7 +354,7 @@ generate if (ENABLE_M_MODE) begin
////////////////////////////////////////////////////
//MIP
assign mip_mask = '{default:0, meip:1, seip:ENABLE_S_MODE, mtip:1, stip:ENABLE_S_MODE, msip:1, ssip:ENABLE_S_MODE};
assign mip_mask = '{default:0, meip:1, seip:CONFIG.INCLUDE_S_MODE, mtip:1, stip:CONFIG.INCLUDE_S_MODE, msip:1, ssip:CONFIG.INCLUDE_S_MODE};
always_ff @(posedge clk) begin
if (rst)
mip <= 0;
@ -360,7 +364,7 @@ generate if (ENABLE_M_MODE) begin
////////////////////////////////////////////////////
//MIE
assign mie_mask = '{default:0, meie:1, seie:ENABLE_S_MODE, mtie:1, stie:ENABLE_S_MODE, msie:1, ssie:ENABLE_S_MODE};
assign mie_mask = '{default:0, meie:1, seie:CONFIG.INCLUDE_S_MODE, mtie:1, stie:CONFIG.INCLUDE_S_MODE, msie:1, ssie:CONFIG.INCLUDE_S_MODE};
assign sie_mask = '{default:0, seie:1, stie:1, ssie:1};
always_ff @(posedge clk) begin
@ -389,40 +393,40 @@ generate if (ENABLE_M_MODE) begin
//As the exception and interrupts codes are sparsely populated,
//to ensure that only legal values are written, a ROM lookup
//is used to validate the CSR write operation
logic MCAUSE_EXCEPTION_MASKING_ROM [2**ECODE_W];
logic MCAUSE_INTERRUPT_MASKING_ROM [2**ECODE_W];
logic MCAINCLUDE_EXCEPTION_MASKING_ROM [2**ECODE_W];
logic MCAINCLUDE_INTERRUPT_MASKING_ROM [2**ECODE_W];
always_comb begin
MCAUSE_EXCEPTION_MASKING_ROM = '{default: 0};
MCAUSE_EXCEPTION_MASKING_ROM[INST_ADDR_MISSALIGNED] = 1;
MCAUSE_EXCEPTION_MASKING_ROM[INST_ACCESS_FAULT] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[ILLEGAL_INST] = 1;
MCAUSE_EXCEPTION_MASKING_ROM[BREAK] = 1;
MCAUSE_EXCEPTION_MASKING_ROM[LOAD_ADDR_MISSALIGNED] = 1;
MCAUSE_EXCEPTION_MASKING_ROM[LOAD_FAULT] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[STORE_AMO_ADDR_MISSALIGNED] = 1;
MCAUSE_EXCEPTION_MASKING_ROM[STORE_AMO_FAULT] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[ECALL_U] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[ECALL_S] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[ECALL_M] = 1;
MCAUSE_EXCEPTION_MASKING_ROM[INST_PAGE_FAULT] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[LOAD_PAGE_FAULT] = ENABLE_S_MODE;
MCAUSE_EXCEPTION_MASKING_ROM[STORE_OR_AMO_PAGE_FAULT] = ENABLE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM = '{default: 0};
MCAINCLUDE_EXCEPTION_MASKING_ROM[INST_ADDR_MISSALIGNED] = 1;
MCAINCLUDE_EXCEPTION_MASKING_ROM[INST_ACCESS_FAULT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[ILLEGAL_INST] = 1;
MCAINCLUDE_EXCEPTION_MASKING_ROM[BREAK] = 1;
MCAINCLUDE_EXCEPTION_MASKING_ROM[LOAD_ADDR_MISSALIGNED] = 1;
MCAINCLUDE_EXCEPTION_MASKING_ROM[LOAD_FAULT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[STORE_AMO_ADDR_MISSALIGNED] = 1;
MCAINCLUDE_EXCEPTION_MASKING_ROM[STORE_AMO_FAULT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[ECALL_U] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[ECALL_S] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[ECALL_M] = 1;
MCAINCLUDE_EXCEPTION_MASKING_ROM[INST_PAGE_FAULT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[LOAD_PAGE_FAULT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_EXCEPTION_MASKING_ROM[STORE_OR_AMO_PAGE_FAULT] = CONFIG.INCLUDE_S_MODE;
MCAUSE_INTERRUPT_MASKING_ROM = '{default: 0};
MCAUSE_INTERRUPT_MASKING_ROM[S_SOFTWARE_INTERRUPT] = ENABLE_S_MODE;
MCAUSE_INTERRUPT_MASKING_ROM[M_SOFTWARE_INTERRUPT] = 1;
MCAUSE_INTERRUPT_MASKING_ROM[S_TIMER_INTERRUPT] = ENABLE_S_MODE;
MCAUSE_INTERRUPT_MASKING_ROM[M_TIMER_INTERRUPT] = 1;
MCAUSE_INTERRUPT_MASKING_ROM[S_EXTERNAL_INTERRUPT] = ENABLE_S_MODE;
MCAUSE_INTERRUPT_MASKING_ROM[M_EXTERNAL_INTERRUPT] = 1;
MCAINCLUDE_INTERRUPT_MASKING_ROM = '{default: 0};
MCAINCLUDE_INTERRUPT_MASKING_ROM[S_SOFTWARE_INTERRUPT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_INTERRUPT_MASKING_ROM[M_SOFTWARE_INTERRUPT] = 1;
MCAINCLUDE_INTERRUPT_MASKING_ROM[S_TIMER_INTERRUPT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_INTERRUPT_MASKING_ROM[M_TIMER_INTERRUPT] = 1;
MCAINCLUDE_INTERRUPT_MASKING_ROM[S_EXTERNAL_INTERRUPT] = CONFIG.INCLUDE_S_MODE;
MCAINCLUDE_INTERRUPT_MASKING_ROM[M_EXTERNAL_INTERRUPT] = 1;
end
logic mcause_write_valid;
always_comb begin
if (updated_csr[XLEN-1]) //interrupt
mcause_write_valid = MCAUSE_INTERRUPT_MASKING_ROM[updated_csr[ECODE_W-1:0]];
mcause_write_valid = MCAINCLUDE_INTERRUPT_MASKING_ROM[updated_csr[ECODE_W-1:0]];
else
mcause_write_valid = MCAUSE_EXCEPTION_MASKING_ROM[updated_csr[ECODE_W-1:0]];
mcause_write_valid = MCAINCLUDE_EXCEPTION_MASKING_ROM[updated_csr[ECODE_W-1:0]];
end
always_ff @(posedge clk) begin
@ -474,11 +478,11 @@ endgenerate
//BEGIN OF SUPERVISOR REGS
////////////////////////////////////////////////////
//TLB status --- used to mux physical/virtual address
assign tlb_on = ENABLE_S_MODE & satp.mode;
assign tlb_on = CONFIG.INCLUDE_S_MODE & satp.mode;
assign asid = satp.asid;
//******************
generate if (ENABLE_S_MODE) begin
generate if (CONFIG.INCLUDE_S_MODE) begin
////////////////////////////////////////////////////
//MMU interface
assign immu.mxr = mstatus.mxr;
@ -498,7 +502,7 @@ generate if (ENABLE_S_MODE) begin
logic [31:0] stvec_mask = '1;
always_ff @(posedge clk) begin
if (rst)
stvec <= {RESET_VEC[XLEN-1:2], 2'b00};
stvec <= {CONFIG.CSRS.RESET_VEC[XLEN-1:2], 2'b00};
else if (swrite_decoder[STVEC[7:0]])
stvec <= (updated_csr & stvec_mask);
end
@ -525,7 +529,7 @@ endgenerate
////////////////////////////////////////////////////
//Timers and Counters
//Register increment for instructions completed
logic[COUNTER_W-1:0] mcycle_next;
logic[CONFIG.CSRS.COUNTER_W-1:0] mcycle_next;
assign mcycle_next = mcycle + 1;
//As the CSR write takes effect after the instruction has otherwise completed,
@ -535,23 +539,23 @@ endgenerate
always_ff @(posedge clk) begin
if (rst) begin
mcycle[31:0] <= 0;
mcycle[COUNTER_W-1:32] <= 0;
mcycle[CONFIG.CSRS.COUNTER_W-1:32] <= 0;
end else begin
mcycle[31:0] <= mwrite_decoder[MCYCLE[7:0]] ? updated_csr : mcycle_next[31:0];
mcycle[COUNTER_W-1:32] <= mwrite_decoder[MCYCLEH[7:0]] ? updated_csr[COUNTER_W-33:0] : mcycle_next[COUNTER_W-1:32];
mcycle[CONFIG.CSRS.COUNTER_W-1:32] <= mwrite_decoder[MCYCLEH[7:0]] ? updated_csr[CONFIG.CSRS.COUNTER_W-33:0] : mcycle_next[CONFIG.CSRS.COUNTER_W-1:32];
end
end
logic[COUNTER_W-1:0] minst_ret_next;
assign minst_ret_next = minst_ret + COUNTER_W'(retire.count);
logic[CONFIG.CSRS.COUNTER_W-1:0] minst_ret_next;
assign minst_ret_next = minst_ret + CONFIG.CSRS.COUNTER_W'(retire.count);
always_ff @(posedge clk) begin
if (rst) begin
minst_ret[31:0] <= 0;
minst_ret[COUNTER_W-1:32] <= 0;
minst_ret[CONFIG.CSRS.COUNTER_W-1:32] <= 0;
end else begin
minst_ret[31:0] <= mwrite_decoder[MINSTRET[7:0]] ? updated_csr : minst_ret_next[31:0];
minst_ret[COUNTER_W-1:32] <= mwrite_decoder[MINSTRETH[7:0]] ? updated_csr[COUNTER_W-33:0] : minst_ret_next[COUNTER_W-1:32];
minst_ret[CONFIG.CSRS.COUNTER_W-1:32] <= mwrite_decoder[MINSTRETH[7:0]] ? updated_csr[CONFIG.CSRS.COUNTER_W-33:0] : minst_ret_next[CONFIG.CSRS.COUNTER_W-1:32];
end
end
@ -559,51 +563,51 @@ endgenerate
invalid_addr = 0;
case (csr_addr) inside
//Machine info
MISA : selected_csr = ENABLE_M_MODE ? misa : 0;
MVENDORID : selected_csr = ENABLE_M_MODE ? mvendorid : 0;
MARCHID : selected_csr = ENABLE_M_MODE ? marchid : 0;
MIMPID : selected_csr = ENABLE_M_MODE ? mimpid : 0;
MHARTID : selected_csr = ENABLE_M_MODE ? mhartid : 0;
MISA : selected_csr = CONFIG.INCLUDE_M_MODE ? misa : 0;
MVENDORID : selected_csr = CONFIG.INCLUDE_M_MODE ? mvendorid : 0;
MARCHID : selected_csr = CONFIG.INCLUDE_M_MODE ? marchid : 0;
MIMPID : selected_csr = CONFIG.INCLUDE_M_MODE ? mimpid : 0;
MHARTID : selected_csr = CONFIG.INCLUDE_M_MODE ? mhartid : 0;
//Machine trap setup
MSTATUS : selected_csr = ENABLE_M_MODE ? mstatus : 0;
MEDELEG : selected_csr = ENABLE_M_MODE ? medeleg : 0;
MIDELEG : selected_csr = ENABLE_M_MODE ? mideleg : 0;
MIE : selected_csr = ENABLE_M_MODE ? mie_reg : 0;
MTVEC : selected_csr = ENABLE_M_MODE ? mtvec : 0;
MSTATUS : selected_csr = CONFIG.INCLUDE_M_MODE ? mstatus : 0;
MEDELEG : selected_csr = CONFIG.INCLUDE_M_MODE ? medeleg : 0;
MIDELEG : selected_csr = CONFIG.INCLUDE_M_MODE ? mideleg : 0;
MIE : selected_csr = CONFIG.INCLUDE_M_MODE ? mie_reg : 0;
MTVEC : selected_csr = CONFIG.INCLUDE_M_MODE ? mtvec : 0;
MCOUNTEREN : selected_csr = 0;
//Machine trap handling
MSCRATCH : selected_csr = ENABLE_M_MODE ? scratch_out : 0;
MEPC : selected_csr = ENABLE_M_MODE ? mepc : 0;
MCAUSE : selected_csr = ENABLE_M_MODE ? mcause : 0;
MTVAL : selected_csr = ENABLE_M_MODE ? mtval : 0;
MIP : selected_csr = ENABLE_M_MODE ? mip : 0;
MSCRATCH : selected_csr = CONFIG.INCLUDE_M_MODE ? scratch_out : 0;
MEPC : selected_csr = CONFIG.INCLUDE_M_MODE ? mepc : 0;
MCAUSE : selected_csr = CONFIG.INCLUDE_M_MODE ? mcause : 0;
MTVAL : selected_csr = CONFIG.INCLUDE_M_MODE ? mtval : 0;
MIP : selected_csr = CONFIG.INCLUDE_M_MODE ? mip : 0;
//Machine Memory Protection
[12'h3EF : 12'h3A0] : selected_csr = 0;
//Machine Timers and Counters
MCYCLE : selected_csr = ENABLE_M_MODE ? mcycle[XLEN-1:0] : 0;
MINSTRET : selected_csr = ENABLE_M_MODE ? minst_ret[XLEN-1:0] : 0;
MCYCLE : selected_csr = CONFIG.INCLUDE_M_MODE ? mcycle[XLEN-1:0] : 0;
MINSTRET : selected_csr = CONFIG.INCLUDE_M_MODE ? minst_ret[XLEN-1:0] : 0;
[12'hB03 : 12'hB1F] : selected_csr = 0;
MCYCLEH : selected_csr = ENABLE_M_MODE ? 32'(mcycle[COUNTER_W-1:XLEN]) : 0;
MINSTRETH : selected_csr = ENABLE_M_MODE ? 32'(minst_ret[COUNTER_W-1:XLEN]) : 0;
MCYCLEH : selected_csr = CONFIG.INCLUDE_M_MODE ? 32'(mcycle[CONFIG.CSRS.COUNTER_W-1:XLEN]) : 0;
MINSTRETH : selected_csr = CONFIG.INCLUDE_M_MODE ? 32'(minst_ret[CONFIG.CSRS.COUNTER_W-1:XLEN]) : 0;
[12'hB83 : 12'hB9F] : selected_csr = 0;
//Machine Counter Setup
[12'h320 : 12'h33F] : selected_csr = 0;
//Supervisor Trap Setup
SSTATUS : selected_csr = ENABLE_S_MODE ? (mstatus & sstatus_mask) : '0;
SSTATUS : selected_csr = CONFIG.INCLUDE_S_MODE ? (mstatus & sstatus_mask) : '0;
SEDELEG : selected_csr = 0; //No user-level interrupts/exception handling
SIDELEG : selected_csr = 0;
SIE : selected_csr = ENABLE_S_MODE ? (mie_reg & sie_mask) : '0;
STVEC : selected_csr = ENABLE_S_MODE ? stvec : '0;
SIE : selected_csr = CONFIG.INCLUDE_S_MODE ? (mie_reg & sie_mask) : '0;
STVEC : selected_csr = CONFIG.INCLUDE_S_MODE ? stvec : '0;
SCOUNTEREN : selected_csr = 0;
//Supervisor trap handling
SSCRATCH : selected_csr = ENABLE_S_MODE ? scratch_out : '0;
SEPC : selected_csr = ENABLE_S_MODE ? scratch_out : '0;
SCAUSE : selected_csr = ENABLE_S_MODE ? scratch_out : '0;
STVAL : selected_csr = ENABLE_S_MODE ? scratch_out : '0;
SIP : selected_csr = ENABLE_S_MODE ? (mip & sip_mask) : '0;
SSCRATCH : selected_csr = CONFIG.INCLUDE_S_MODE ? scratch_out : '0;
SEPC : selected_csr = CONFIG.INCLUDE_S_MODE ? scratch_out : '0;
SCAUSE : selected_csr = CONFIG.INCLUDE_S_MODE ? scratch_out : '0;
STVAL : selected_csr = CONFIG.INCLUDE_S_MODE ? scratch_out : '0;
SIP : selected_csr = CONFIG.INCLUDE_S_MODE ? (mip & sip_mask) : '0;
//Supervisor Protection and Translation
SATP : selected_csr = ENABLE_S_MODE ? satp : '0;
SATP : selected_csr = CONFIG.INCLUDE_S_MODE ? satp : '0;
//User status
//Floating point
@ -615,9 +619,9 @@ endgenerate
TIME : selected_csr = mcycle[XLEN-1:0];
INSTRET : selected_csr = minst_ret[XLEN-1:0];
[12'hC03 : 12'hC1F] : selected_csr = 0;
CYCLEH : selected_csr = 32'(mcycle[COUNTER_W-1:XLEN]);
TIMEH : selected_csr = 32'(mcycle[COUNTER_W-1:XLEN]);
INSTRETH : selected_csr = 32'(minst_ret[COUNTER_W-1:XLEN]);
CYCLEH : selected_csr = 32'(mcycle[CONFIG.CSRS.COUNTER_W-1:XLEN]);
TIMEH : selected_csr = 32'(mcycle[CONFIG.CSRS.COUNTER_W-1:XLEN]);
INSTRETH : selected_csr = 32'(minst_ret[CONFIG.CSRS.COUNTER_W-1:XLEN]);
[12'hC83 : 12'hC9F] : selected_csr = 0;
default : begin selected_csr = 0; invalid_addr = 1; end

View file

@ -25,7 +25,11 @@ module dcache
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -43,26 +47,27 @@ module dcache
ls_sub_unit_interface.sub_unit ls
);
localparam DCACHE_SIZE_IN_WORDS = DCACHE_LINES*DCACHE_LINE_W*DCACHE_WAYS;
localparam DCACHE_SIZE_IN_WORDS = CONFIG.DCACHE.LINES*CONFIG.DCACHE.LINE_W*CONFIG.DCACHE.WAYS;
localparam derived_cache_config_t SCONFIG = get_derived_cache_params(CONFIG, CONFIG.DCACHE, CONFIG.DCACHE_ADDR);
logic [$clog2(DCACHE_SIZE_IN_WORDS)-1:0] data_bank_addr_a;
logic [$clog2(DCACHE_SIZE_IN_WORDS)-1:0] data_bank_addr_b;
logic tag_hit;
logic [DCACHE_WAYS-1:0] tag_hit_way;
logic [CONFIG.DCACHE.WAYS-1:0] tag_hit_way;
logic [$clog2(DCACHE_WAYS)-1:0] tag_hit_way_int;
logic [$clog2(CONFIG.DCACHE.WAYS)-1:0] tag_hit_way_int;
logic tag_update;
logic [DCACHE_WAYS-1:0] tag_update_way;
logic [DCACHE_WAYS-1:0] replacement_way;
logic [CONFIG.DCACHE.WAYS-1:0] tag_update_way;
logic [CONFIG.DCACHE.WAYS-1:0] replacement_way;
logic [$clog2(DCACHE_WAYS)-1:0] replacement_way_int;
logic [$clog2(DCACHE_WAYS)-1:0] tag_update_way_int;
logic [$clog2(CONFIG.DCACHE.WAYS)-1:0] replacement_way_int;
logic [$clog2(CONFIG.DCACHE.WAYS)-1:0] tag_update_way_int;
logic [DCACHE_SUB_LINE_ADDR_W-1:0] word_count;
logic [DCACHE_SUB_LINE_ADDR_W-1:0] sc_write_index;
logic [DCACHE_SUB_LINE_ADDR_W-1:0] update_word_index;
logic [SCONFIG.SUB_LINE_ADDR_W-1:0] word_count;
logic [SCONFIG.SUB_LINE_ADDR_W-1:0] sc_write_index;
logic [SCONFIG.SUB_LINE_ADDR_W-1:0] update_word_index;
logic line_complete;
logic reservation;
@ -148,7 +153,7 @@ module dcache
assign l1_request.data = stage2_data;
assign l1_request.rnw = ~stage2_store;
assign l1_request.be = stage2_be;
assign l1_request.size = stage2_load ? (DCACHE_LINE_W-1) : 0;//LR and AMO ops are included in load
assign l1_request.size = stage2_load ? 5'(CONFIG.DCACHE.LINE_W-1) : 0;//LR and AMO ops are included in load
assign l1_request.is_amo = (stage2_amo.is_amo | stage2_amo.is_lr | stage2_amo.is_sc);
assign l1_request.amo = stage2_amo.op;
@ -158,7 +163,7 @@ module dcache
else if (l1_response.data_valid)
word_count <= word_count + 1;
end
assign is_target_word = (stage2_addr[DCACHE_SUB_LINE_ADDR_W+1:2] == word_count);
assign is_target_word = (stage2_addr[SCONFIG.SUB_LINE_ADDR_W+1:2] == word_count);
assign new_arb_request = second_cycle & (~(tag_hit & read_hit_allowed) | ~dcache_on);
always_ff @ (posedge clk) begin
@ -173,7 +178,7 @@ module dcache
////////////////////////////////////////////////////
//Replacement policy (free runing one-hot cycler, i.e. pseudo random)
cycler #(DCACHE_WAYS) replacement_policy (
cycler #(CONFIG.DCACHE.WAYS) replacement_policy (
.clk (clk),
.rst (rst),
.en (1'b1),
@ -181,13 +186,13 @@ module dcache
);
//One-hot tag hit / update logic to binary int
one_hot_to_integer #(DCACHE_WAYS) hit_way_conv (
one_hot_to_integer #(CONFIG.DCACHE.WAYS) hit_way_conv (
.clk (clk),
.rst (rst),
.one_hot(tag_hit_way),
.int_out(tag_hit_way_int)
);
one_hot_to_integer #(DCACHE_WAYS) update_way_conv (
one_hot_to_integer #(CONFIG.DCACHE.WAYS) update_way_conv (
.clk (clk),
.rst (rst),
.one_hot (replacement_way),
@ -207,20 +212,21 @@ module dcache
////////////////////////////////////////////////////
//Tag banks
dtag_banks dcache_tag_banks (
.clk (clk),
.rst (rst),
.stage1_addr (ls_inputs.addr),
.stage2_addr (stage2_addr),
.inv_addr ({l1_response.inv_addr, 2'b00}),
.update_way (tag_update_way),
.update (tag_update),
.stage1_adv (ls.new_request),
.stage1_inv (1'b0),//For software invalidation
.extern_inv (l1_response.inv_valid),
.extern_inv_complete (l1_response.inv_ack),
.tag_hit (tag_hit),
.tag_hit_way (tag_hit_way)
dtag_banks #(.CONFIG(CONFIG), .SCONFIG(SCONFIG))
dcache_tag_banks (
.clk (clk),
.rst (rst),
.stage1_addr (ls_inputs.addr),
.stage2_addr (stage2_addr),
.inv_addr ({l1_response.inv_addr, 2'b00}),
.update_way (tag_update_way),
.update (tag_update),
.stage1_adv (ls.new_request),
.stage1_inv (1'b0),//For software invalidation
.extern_inv (l1_response.inv_valid),
.extern_inv_complete (l1_response.inv_ack),
.tag_hit (tag_hit),
.tag_hit_way (tag_hit_way)
);
////////////////////////////////////////////////////
@ -233,10 +239,10 @@ module dcache
assign amo_alu_inputs.rs2 = amo_rs2;
assign amo_alu_inputs.op = stage2_amo.op;
generate if (USE_AMO)
generate if (CONFIG.INCLUDE_AMO)
amo_alu amo_unit (
.amo_alu_inputs (amo_alu_inputs),
.result (amo_result)
.result (amo_result)
);
endgenerate
@ -249,7 +255,7 @@ module dcache
new_line_data = l1_response.data;
end
assign sc_write_index = stage2_addr[DCACHE_SUB_LINE_ADDR_W+1:2];
assign sc_write_index = stage2_addr[SCONFIG.SUB_LINE_ADDR_W+1:2];
////////////////////////////////////////////////////
@ -259,8 +265,8 @@ module dcache
assign write_hit_be = stage2_be & {4{tag_hit}};
assign update_word_index = stage2_amo.is_sc ? sc_write_index : word_count;
assign data_bank_addr_a = {tag_hit_way_int, stage2_addr[DCACHE_LINE_ADDR_W+DCACHE_SUB_LINE_ADDR_W+2-1:2]};
assign data_bank_addr_b = {tag_update_way_int, stage2_addr[DCACHE_LINE_ADDR_W+DCACHE_SUB_LINE_ADDR_W+2-1:DCACHE_SUB_LINE_ADDR_W+2], update_word_index};
assign data_bank_addr_a = {tag_hit_way_int, stage2_addr[SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W+2-1:2]};
assign data_bank_addr_b = {tag_update_way_int, stage2_addr[SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W+2-1:SCONFIG.SUB_LINE_ADDR_W+2], update_word_index};
ddata_bank #(.LINES(DCACHE_SIZE_IN_WORDS)) data_bank (
.clk(clk),
@ -287,7 +293,7 @@ module dcache
////////////////////////////////////////////////////
//Pipeline Advancement
assign line_complete = (l1_response.data_valid && (word_count == $clog2(DCACHE_LINE_W)'(DCACHE_LINE_W-1))); //covers load, LR, AMO
assign line_complete = (l1_response.data_valid && (word_count == $clog2(CONFIG.DCACHE.LINE_W)'(CONFIG.DCACHE.LINE_W-1))); //covers load, LR, AMO
assign store_complete = l1_request.ack & stage2_store & ~stage2_amo.is_sc;
//read miss complete includes store conditional complete

View file

@ -25,7 +25,13 @@ module decode_and_issue
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG,
parameter NUM_UNITS = 5,
parameter unit_id_param_t UNIT_IDS = EXAMPLE_UNIT_IDS
)
(
input logic clk,
input logic rst,
@ -108,8 +114,6 @@ module decode_and_issue
logic operands_ready;
logic mult_div_op;
logic [NUM_WB_UNITS-1:0] unit_needed_for_id_gen;
logic [WB_UNITS_WIDTH-1:0] unit_needed_for_id_gen_int;
logic [NUM_UNITS-1:0] unit_needed;
logic [NUM_UNITS-1:0] unit_needed_issue_stage;
logic [NUM_UNITS-1:0] unit_ready;
@ -152,18 +156,18 @@ module decode_and_issue
////////////////////////////////////////////////////
//Unit Determination
assign unit_needed[BRANCH_UNIT_ID] = opcode_trim inside {BRANCH_T, JAL_T, JALR_T};
assign unit_needed[ALU_UNIT_ID] = (opcode_trim inside {ARITH_T, ARITH_IMM_T, AUIPC_T, LUI_T, JAL_T, JALR_T}) & ~mult_div_op;
assign unit_needed[LS_UNIT_ID] = opcode_trim inside {LOAD_T, STORE_T, AMO_T};
assign unit_needed[GC_UNIT_ID] = opcode_trim inside {SYSTEM_T, FENCE_T};
assign unit_needed[UNIT_IDS.BR] = opcode_trim inside {BRANCH_T, JAL_T, JALR_T};
assign unit_needed[UNIT_IDS.ALU] = (opcode_trim inside {ARITH_T, ARITH_IMM_T, AUIPC_T, LUI_T, JAL_T, JALR_T}) & ~mult_div_op;
assign unit_needed[UNIT_IDS.LS] = opcode_trim inside {LOAD_T, STORE_T, AMO_T};
assign unit_needed[UNIT_IDS.CSR] = opcode_trim inside {SYSTEM_T, FENCE_T};
assign mult_div_op = (opcode_trim == ARITH_T) && decode.instruction[25];
generate if (USE_MUL)
assign unit_needed[MUL_UNIT_ID] = mult_div_op && ~fn3[2];
generate if (CONFIG.INCLUDE_MUL)
assign unit_needed[UNIT_IDS.MUL] = mult_div_op && ~fn3[2];
endgenerate
generate if (USE_DIV)
assign unit_needed[DIV_UNIT_ID] = mult_div_op && fn3[2];
generate if (CONFIG.INCLUDE_DIV)
assign unit_needed[UNIT_IDS.DIV] = mult_div_op && fn3[2];
endgenerate
////////////////////////////////////////////////////
@ -172,7 +176,7 @@ module decode_and_issue
assign renamer.rs_addr[RS1] = rs1_addr;
assign renamer.rs_addr[RS2] = rs2_addr;
assign renamer.uses_rd = uses_rd;
assign renamer.rd_wb_group = ~unit_needed[ALU_UNIT_ID];//TODO: automate generation of wb group logic
assign renamer.rd_wb_group = ~unit_needed[UNIT_IDS.ALU];//TODO: automate generation of wb group logic
assign renamer.id = decode.id;
////////////////////////////////////////////////////
@ -183,6 +187,8 @@ module decode_and_issue
////////////////////////////////////////////////////
//Issue
logic [REGFILE_READ_PORTS-1:0][$clog2(CONFIG.NUM_WB_GROUPS)-1:0] issue_rs_wb_group;
always_ff @(posedge clk) begin
if (issue_stage_ready) begin
issue.pc <= decode.pc;
@ -194,10 +200,10 @@ module decode_and_issue
issue.rs_addr[RS2] <= rs2_addr;
issue.phys_rs_addr[RS1] <= renamer.phys_rs_addr[RS1];
issue.phys_rs_addr[RS2] <= renamer.phys_rs_addr[RS2];
issue.rs_wb_group <= renamer.rs_wb_group;
issue_rs_wb_group <= renamer.rs_wb_group;
issue.rd_addr <= rd_addr;
issue.phys_rd_addr <= renamer.phys_rd_addr;
issue.rd_wb_group <= ~unit_needed[ALU_UNIT_ID];
issue.is_multicycle <= ~unit_needed[UNIT_IDS.ALU];
issue.id <= decode.id;
issue.uses_rs1 <= uses_rs1;
issue.uses_rs2 <= uses_rs2;
@ -241,9 +247,9 @@ module decode_and_issue
assign rf.phys_rs_addr[RS1] = issue.phys_rs_addr[RS1];
assign rf.phys_rs_addr[RS2] = issue.phys_rs_addr[RS2];
assign rf.phys_rd_addr = issue.phys_rd_addr;
assign rf.rs_wb_group[RS1] = issue.rs_wb_group[RS1];
assign rf.rs_wb_group[RS2] = issue.rs_wb_group[RS2];
assign rf.rd_wb_group = issue.rd_wb_group;
assign rf.rs_wb_group[RS1] = issue_rs_wb_group[RS1];
assign rf.rs_wb_group[RS2] = issue_rs_wb_group[RS2];
assign rf.rd_wb_group = issue.is_multicycle;
assign rf.issued = instruction_issued_with_rd;
////////////////////////////////////////////////////
//ALU unit inputs
@ -319,12 +325,12 @@ module decode_and_issue
logic load_reserve;
logic [4:0] amo_type;
assign amo_op = USE_AMO ? (opcode_trim == AMO_T) : 1'b0;
assign amo_op = CONFIG.INCLUDE_AMO ? (opcode_trim == AMO_T) : 1'b0;
assign amo_type = decode.instruction[31:27];
assign store_conditional = (amo_type == AMO_SC);
assign load_reserve = (amo_type == AMO_LR);
generate if (USE_AMO) begin
generate if (CONFIG.INCLUDE_AMO) begin
assign ls_inputs.amo.is_lr = load_reserve;
assign ls_inputs.amo.is_sc = store_conditional;
assign ls_inputs.amo.is_amo = amo_op & ~(load_reserve | store_conditional);
@ -459,12 +465,12 @@ module decode_and_issue
always_comb begin
sys_op_match = '0;
case (decode.instruction[31:20]) inside
ECALL_imm : sys_op_match[ECALL_i] = ENABLE_M_MODE;
EBREAK_imm : sys_op_match[EBREAK_i] = ENABLE_M_MODE;
URET_imm : sys_op_match[URET_i] = ENABLE_U_MODE;
SRET_imm : sys_op_match[SRET_i] = ENABLE_S_MODE;
MRET_imm : sys_op_match[MRET_i] = ENABLE_M_MODE;
SFENCE_imm : sys_op_match[SFENCE_i] = ENABLE_S_MODE;
ECALL_imm : sys_op_match[ECALL_i] = CONFIG.INCLUDE_M_MODE;
EBREAK_imm : sys_op_match[EBREAK_i] = CONFIG.INCLUDE_M_MODE;
URET_imm : sys_op_match[URET_i] = CONFIG.INCLUDE_U_MODE;
SRET_imm : sys_op_match[SRET_i] = CONFIG.INCLUDE_S_MODE;
MRET_imm : sys_op_match[MRET_i] = CONFIG.INCLUDE_M_MODE;
SFENCE_imm : sys_op_match[SFENCE_i] = CONFIG.INCLUDE_S_MODE;
default : sys_op_match = '0;
endcase
end
@ -476,7 +482,7 @@ module decode_and_issue
is_ecall <= environment_op & sys_op_match[ECALL_i];
is_ebreak <= environment_op & sys_op_match[EBREAK_i];
is_ret <= environment_op & (sys_op_match[URET_i] | sys_op_match[SRET_i] | sys_op_match[MRET_i]);
is_fence <= ENABLE_M_MODE && (opcode_trim == FENCE_T) && ~fn3[0];
is_fence <= CONFIG.INCLUDE_M_MODE && (opcode_trim == FENCE_T) && ~fn3[0];
is_ifence_r <= (opcode_trim == FENCE_T) && fn3[0];
potential_flush <= (environment_op | ifence);
end
@ -489,15 +495,15 @@ module decode_and_issue
assign gc_inputs.instruction = issue.instruction;
assign gc_inputs.is_csr = is_csr_r;
assign gc_inputs.is_fence = is_fence;
assign gc_inputs.is_i_fence = ENABLE_M_MODE & issue_to[GC_UNIT_ID] & is_ifence_r;
assign gc_inputs.is_i_fence = CONFIG.INCLUDE_M_MODE & issue_to[UNIT_IDS.CSR] & is_ifence_r;
assign gc_inputs.rs1 = rf.data[RS1];
assign gc_inputs.rs2 = rf.data[RS2];
assign gc_flush_required = ENABLE_M_MODE && issue_to[GC_UNIT_ID] && potential_flush;
assign gc_flush_required = CONFIG.INCLUDE_M_MODE && issue_to[UNIT_IDS.CSR] && potential_flush;
////////////////////////////////////////////////////
//Mul unit inputs
generate if (USE_MUL) begin
generate if (CONFIG.INCLUDE_MUL) begin
assign mul_inputs.rs1 = rf.data[RS1];
assign mul_inputs.rs2 = rf.data[RS2];
assign mul_inputs.op = issue.fn3[1:0];
@ -505,7 +511,7 @@ module decode_and_issue
////////////////////////////////////////////////////
//Div unit inputs
generate if (USE_DIV) begin
generate if (CONFIG.INCLUDE_DIV) begin
logic [4:0] prev_div_rs1_addr;
logic [4:0] prev_div_rs2_addr;
logic prev_div_result_valid;
@ -513,7 +519,7 @@ module decode_and_issue
logic div_op_reuse;
always_ff @(posedge clk) begin
if (issue_to[DIV_UNIT_ID]) begin
if (issue_to[UNIT_IDS.DIV]) begin
prev_div_rs1_addr <= rs1_addr;
prev_div_rs2_addr <= rs2_addr;
end
@ -522,11 +528,11 @@ module decode_and_issue
assign div_op_reuse = {prev_div_result_valid, prev_div_rs1_addr, prev_div_rs2_addr} == {1'b1, issue.rs_addr[RS1], issue.rs_addr[RS2]};
//If current div operation overwrites an input register OR any other instruction overwrites the last div operations input registers
assign div_rs_overwrite = (issue.rd_addr == (unit_needed_issue_stage[DIV_UNIT_ID] ? issue.rs_addr[RS1] : prev_div_rs1_addr)) || (issue.rd_addr == (unit_needed_issue_stage[DIV_UNIT_ID] ? issue.rs_addr[RS2] : prev_div_rs2_addr));
assign div_rs_overwrite = (issue.rd_addr == (unit_needed_issue_stage[UNIT_IDS.DIV] ? issue.rs_addr[RS1] : prev_div_rs1_addr)) || (issue.rd_addr == (unit_needed_issue_stage[UNIT_IDS.DIV] ? issue.rs_addr[RS2] : prev_div_rs2_addr));
set_clr_reg_with_rst #(.SET_OVER_CLR(0), .WIDTH(1), .RST_VALUE(0)) prev_div_result_valid_m (
.clk, .rst,
.set(instruction_issued & unit_needed_issue_stage[DIV_UNIT_ID]),
.set(instruction_issued & unit_needed_issue_stage[UNIT_IDS.DIV]),
.clr(instruction_issued & issue.uses_rd & div_rs_overwrite),
.result(prev_div_result_valid)
);
@ -551,8 +557,9 @@ module decode_and_issue
////////////////////////////////////////////////////
//Illegal Instruction check
logic illegal_instruction_pattern_r;
generate if (ENABLE_M_MODE) begin
illegal_instruction_checker illegal_op_check (
generate if (CONFIG.INCLUDE_M_MODE) begin
illegal_instruction_checker # (.CONFIG(CONFIG))
illegal_op_check (
.instruction(decode.instruction), .illegal_instruction(illegal_instruction_pattern)
);
always_ff @(posedge clk) begin
@ -586,10 +593,10 @@ module decode_and_issue
assign tr_no_id_stall = (~issue.stage_valid & ~pc_id_available & ~gc_fetch_flush); //All instructions in execution pipeline
assign tr_no_instruction_stall = (~tr_no_id_stall & ~issue.stage_valid) | gc_fetch_flush;
assign tr_other_stall = issue.stage_valid & ~instruction_issued & ~(tr_operand_stall | tr_unit_stall | tr_no_id_stall | tr_no_instruction_stall);
assign tr_branch_operand_stall = tr_operand_stall & unit_needed_issue_stage[BRANCH_UNIT_ID];
assign tr_alu_operand_stall = tr_operand_stall & unit_needed_issue_stage[ALU_UNIT_ID] & ~unit_needed_issue_stage[BRANCH_UNIT_ID];
assign tr_ls_operand_stall = tr_operand_stall & unit_needed_issue_stage[LS_UNIT_ID];
assign tr_div_operand_stall = tr_operand_stall & unit_needed_issue_stage[DIV_UNIT_ID];
assign tr_branch_operand_stall = tr_operand_stall & unit_needed_issue_stage[UNIT_IDS.BR];
assign tr_alu_operand_stall = tr_operand_stall & unit_needed_issue_stage[UNIT_IDS.ALU] & ~unit_needed_issue_stage[UNIT_IDS.BR];
assign tr_ls_operand_stall = tr_operand_stall & unit_needed_issue_stage[UNIT_IDS.LS];
assign tr_div_operand_stall = tr_operand_stall & unit_needed_issue_stage[UNIT_IDS.DIV];
//Instruction Mix
always_ff @(posedge clk) begin
@ -598,8 +605,8 @@ module decode_and_issue
tr_branch_or_jump_op <= instruction_issued && (opcode_trim inside {JAL_T, JALR_T, BRANCH_T});
tr_load_op <= instruction_issued && (opcode_trim inside {LOAD_T, AMO_T});
tr_store_op <= instruction_issued && (opcode_trim inside {STORE_T});
tr_mul_op <= instruction_issued && unit_needed_issue_stage[MUL_UNIT_ID];
tr_div_op <= instruction_issued && unit_needed_issue_stage[DIV_UNIT_ID];
tr_mul_op <= instruction_issued && unit_needed_issue_stage[UNIT_IDS.MUL];
tr_div_op <= instruction_issued && unit_needed_issue_stage[UNIT_IDS.DIV];
tr_misc_op <= instruction_issued & ~(tr_alu_op | tr_branch_or_jump_op | tr_load_op | tr_store_op | tr_mul_op | tr_div_op);
end
end

View file

@ -25,6 +25,11 @@ module dtag_banks
import taiga_config::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG,
parameter derived_cache_config_t SCONFIG = '{default: 0}
)
(
input logic clk,
input logic rst,
@ -33,7 +38,7 @@ module dtag_banks
input logic[31:0] stage2_addr,
input logic[31:0] inv_addr,
input logic[DCACHE_WAYS-1:0] update_way,
input logic[CONFIG.DCACHE.WAYS-1:0] update_way,
input logic update,
input logic stage1_adv,
@ -43,36 +48,36 @@ module dtag_banks
output logic extern_inv_complete,
output tag_hit,
output logic[DCACHE_WAYS-1:0] tag_hit_way
output logic[CONFIG.DCACHE.WAYS-1:0] tag_hit_way
);
typedef struct packed{
logic valid;
logic [DCACHE_TAG_W-1:0] tag;
logic [SCONFIG.TAG_W-1:0] tag;
} dtag_entry_t;
function logic[DCACHE_TAG_W-1:0] getTag(logic[31:0] addr);
return addr[2+DCACHE_SUB_LINE_ADDR_W+DCACHE_LINE_ADDR_W +: DCACHE_TAG_W];
function logic[SCONFIG.TAG_W-1:0] getTag(logic[31:0] addr);
return addr[2+SCONFIG.SUB_LINE_ADDR_W+SCONFIG.LINE_ADDR_W +: SCONFIG.TAG_W];
endfunction
function logic[DCACHE_LINE_ADDR_W-1:0] getLineAddr(logic[31:0] addr);
return addr[DCACHE_LINE_ADDR_W + DCACHE_SUB_LINE_ADDR_W + 1 : DCACHE_SUB_LINE_ADDR_W + 2];
function logic[SCONFIG.LINE_ADDR_W-1:0] getLineAddr(logic[31:0] addr);
return addr[SCONFIG.LINE_ADDR_W + SCONFIG.SUB_LINE_ADDR_W + 1 : SCONFIG.SUB_LINE_ADDR_W + 2];
endfunction
dtag_entry_t tag_line [DCACHE_WAYS - 1:0];
dtag_entry_t inv_tag_line [DCACHE_WAYS - 1:0];
dtag_entry_t tag_line [CONFIG.DCACHE.WAYS - 1:0];
dtag_entry_t inv_tag_line [CONFIG.DCACHE.WAYS - 1:0];
dtag_entry_t new_tagline;
logic miss_or_extern_invalidate;
logic [DCACHE_WAYS - 1:0] update_tag_way;
logic [CONFIG.DCACHE.WAYS - 1:0] update_tag_way;
logic inv_tags_accessed;
logic[DCACHE_WAYS-1:0] inv_hit_way;
logic[DCACHE_WAYS-1:0] inv_hit_way_r;
logic[CONFIG.DCACHE.WAYS-1:0] inv_hit_way;
logic[CONFIG.DCACHE.WAYS-1:0] inv_hit_way_r;
logic [DCACHE_LINE_ADDR_W-1:0] update_port_addr;
logic [SCONFIG.LINE_ADDR_W-1:0] update_port_addr;
////////////////////////////////////////////////////
//Implementation
@ -106,10 +111,10 @@ module dtag_banks
assign inv_hit_comparison_tagline.valid = 1;
assign inv_hit_comparison_tagline.tag = getTag(inv_addr);
for (i=0; i < DCACHE_WAYS; i=i+1) begin : dtag_bank_gen
for (i=0; i < CONFIG.DCACHE.WAYS; i=i+1) begin : dtag_bank_gen
assign update_tag_way[i] = update_way[i] | (inv_hit_way[i] & extern_inv_complete);
tag_bank #($bits(dtag_entry_t), DCACHE_LINES) dtag_bank (
tag_bank #($bits(dtag_entry_t), CONFIG.DCACHE.LINES) dtag_bank (
.clk (clk),
.rst (rst),
.en_a (stage1_adv),

View file

@ -26,6 +26,10 @@ module fetch
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -39,6 +43,7 @@ module fetch
input logic [31:0] gc_fetch_pc,
//ID Support
input id_t pc_id,
input logic pc_id_available,
output logic pc_id_assigned,
output logic fetch_complete,
@ -63,16 +68,18 @@ module fetch
output logic tr_early_branch_correction
);
localparam NUM_SUB_UNITS = USE_I_SCRATCH_MEM + USE_ICACHE;
localparam NUM_SUB_UNITS = int'(CONFIG.INCLUDE_ILOCAL_MEM) + int'(CONFIG.INCLUDE_ICACHE);
localparam NUM_SUB_UNITS_W = (NUM_SUB_UNITS == 1) ? 1 : $clog2(NUM_SUB_UNITS);
localparam BRAM_ID = 0;
localparam ICACHE_ID = USE_I_SCRATCH_MEM;
localparam ICACHE_ID = int'(CONFIG.INCLUDE_ILOCAL_MEM);
localparam NEXT_ID_DEPTH = USE_ICACHE ? 2 : 1;
localparam NEXT_ID_DEPTH = CONFIG.INCLUDE_ICACHE ? 2 : 1;
//Subunit signals
fetch_sub_unit_interface fetch_sub[NUM_SUB_UNITS-1:0]();
fetch_sub_unit_interface #(.BASE_ADDR(CONFIG.ILOCAL_MEM_ADDR.L), .UPPER_BOUND(CONFIG.ILOCAL_MEM_ADDR.H)) bram();
fetch_sub_unit_interface #(.BASE_ADDR(CONFIG.ICACHE_ADDR.L), .UPPER_BOUND(CONFIG.ICACHE_ADDR.H)) cache();
logic [NUM_SUB_UNITS-1:0] sub_unit_address_match;
logic [NUM_SUB_UNITS-1:0] unit_ready;
logic [NUM_SUB_UNITS-1:0] unit_data_valid;
@ -117,7 +124,7 @@ module fetch
assign update_pc = new_mem_request | gc_fetch_flush | early_branch_flush;
always_ff @(posedge clk) begin
if (rst)
pc <= RESET_VEC;
pc <= CONFIG.CSRS.RESET_VEC;
else if (update_pc)
pc <= {next_pc[31:2], 2'b0};
end
@ -148,6 +155,8 @@ module fetch
assign bp.new_mem_request = update_pc;
assign bp.next_pc = next_pc;
assign bp.if_pc = pc;
assign bp.pc_id = pc_id;
assign bp.pc_id_assigned = pc_id_assigned;
assign ras.pop = bp.use_prediction & bp.is_return & ~branch_flush & ~gc_fetch_pc_override & new_mem_request & (~early_branch_flush);
assign ras.push = bp.use_prediction & bp.is_call & ~branch_flush & ~gc_fetch_pc_override & new_mem_request & (~early_branch_flush);
@ -159,8 +168,8 @@ module fetch
assign tlb.virtual_address = pc;
assign tlb.execute = 1;
assign tlb.rnw = 0;
assign tlb.new_request = tlb.ready & (ENABLE_S_MODE & tlb_on);
assign translated_address = (ENABLE_S_MODE & tlb_on) ? tlb.physical_address : pc;
assign tlb.new_request = tlb.ready & (CONFIG.INCLUDE_S_MODE & tlb_on);
assign translated_address = (CONFIG.INCLUDE_S_MODE & tlb_on) ? tlb.physical_address : pc;
always_ff @(posedge clk) begin
if (new_mem_request)
@ -193,11 +202,11 @@ module fetch
assign fetch_attr_fifo.data_in = fetch_attr_next;
taiga_fifo #(.DATA_WIDTH($bits(fetch_attributes_t)), .FIFO_DEPTH(NEXT_ID_DEPTH))
attributes_fifo (
.clk (clk),
.rst (flush_or_rst),
.fifo (fetch_attr_fifo)
);
attributes_fifo (
.clk (clk),
.rst (flush_or_rst),
.fifo (fetch_attr_fifo)
);
assign fetch_attr = fetch_attr_fifo.data_out;
@ -206,43 +215,48 @@ module fetch
//In the case of a gc_fetch_flush, a request may already be in progress
//for any sub unit. That request can either be completed or aborted.
//In either case, data_valid must NOT be asserted.
generate
for (i = 0; i < NUM_SUB_UNITS; i++) begin
assign unit_ready[i] = fetch_sub[i].ready;
assign unit_data_valid[i] = fetch_sub[i].data_valid;
assign fetch_sub[i].new_request = new_mem_request & sub_unit_address_match[i];
assign fetch_sub[i].stage1_addr = translated_address;
assign fetch_sub[i].stage2_addr = stage2_phys_address;
assign fetch_sub[i].flush = gc_fetch_flush;
assign unit_data_array[i] = fetch_sub[i].data_out;
end
generate if (CONFIG.INCLUDE_ILOCAL_MEM) begin
assign sub_unit_address_match[BRAM_ID] = bram.address_range_check(translated_address);
assign unit_ready[BRAM_ID] = bram.ready;
assign unit_data_valid[BRAM_ID] = bram.data_valid;
assign bram.new_request = new_mem_request & sub_unit_address_match[BRAM_ID];
assign bram.stage1_addr = translated_address;
assign bram.stage2_addr = stage2_phys_address;
assign bram.flush = gc_fetch_flush;
assign unit_data_array[BRAM_ID] = bram.data_out;
ibram i_bram (
.clk (clk),
.rst (rst),
.fetch_sub (bram),
.instruction_bram (instruction_bram)
);
end
endgenerate
generate if (CONFIG.INCLUDE_ICACHE) begin
assign sub_unit_address_match[ICACHE_ID] = cache.address_range_check(translated_address);
assign unit_ready[ICACHE_ID] = cache.ready;
assign unit_data_valid[ICACHE_ID] = cache.data_valid;
assign cache.new_request = new_mem_request & sub_unit_address_match[ICACHE_ID];
assign cache.stage1_addr = translated_address;
assign cache.stage2_addr = stage2_phys_address;
assign cache.flush = gc_fetch_flush;
assign unit_data_array[ICACHE_ID] = cache.data_out;
icache #(.CONFIG(CONFIG))
i_cache (
.clk (clk),
.rst (rst),
.icache_on (icache_on),
.l1_request (l1_request),
.l1_response (l1_response),
.fetch_sub (cache)
);
end
endgenerate
assign units_ready = &unit_ready;
assign address_valid = |sub_unit_address_match;
generate if (USE_I_SCRATCH_MEM) begin
ibram i_bram (
.clk (clk),
.rst (rst),
.fetch_sub (fetch_sub[BRAM_ID]),
.instruction_bram (instruction_bram)
);
assign sub_unit_address_match[BRAM_ID] = translated_address[31:32-SCRATCH_BIT_CHECK] == SCRATCH_ADDR_L[31:32-SCRATCH_BIT_CHECK];
end
endgenerate
generate if (USE_ICACHE) begin
icache i_cache (
.clk (clk),
.rst (rst),
.icache_on (icache_on),
.l1_request (l1_request),
.l1_response (l1_response),
.fetch_sub (fetch_sub[ICACHE_ID])
);
assign sub_unit_address_match[ICACHE_ID] = translated_address[31:32-MEMORY_BIT_CHECK] == MEMORY_ADDR_L[31:32-MEMORY_BIT_CHECK];
end
endgenerate
////////////////////////////////////////////////////
//Instruction metada updates
logic valid_fetch_result;

View file

@ -27,6 +27,10 @@ module gc_unit
import taiga_types::*;
import csr_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -89,9 +93,9 @@ module gc_unit
);
//Largest depth for TLBs
localparam int TLB_CLEAR_DEPTH = (DTLB_DEPTH > ITLB_DEPTH) ? DTLB_DEPTH : ITLB_DEPTH;
localparam int TLB_CLEAR_DEPTH = (CONFIG.DTLB.DEPTH > CONFIG.ITLB.DEPTH) ? CONFIG.DTLB.DEPTH : CONFIG.ITLB.DEPTH;
//For general reset clear, greater of TLB depth or id-flight memory blocks (MAX_IDS)
localparam int INIT_CLEAR_DEPTH = ENABLE_S_MODE ? (TLB_CLEAR_DEPTH > 64 ? TLB_CLEAR_DEPTH : 64) : 64;
localparam int INIT_CLEAR_DEPTH = CONFIG.INCLUDE_S_MODE ? (TLB_CLEAR_DEPTH > 64 ? TLB_CLEAR_DEPTH : 64) : 64;
////////////////////////////////////////////////////
//Instructions
@ -301,7 +305,7 @@ module gc_unit
end
logic ecall_break_exception;
assign ecall_break_exception = issue.new_request & (gc_inputs.is_ecall | gc_inputs.is_ebreak);
assign gc_exception.valid = ENABLE_M_MODE & (ecall_break_exception | ls_exception.valid | br_exception.valid | illegal_instruction);
assign gc_exception.valid = CONFIG.INCLUDE_M_MODE & (ecall_break_exception | ls_exception.valid | br_exception.valid | illegal_instruction);
//PC determination (trap, flush or return)
//Two cycles: on first cycle the processor front end is flushed,
@ -325,7 +329,8 @@ module gc_unit
assign csr_inputs.rs1_is_zero = (rs1_addr == 0);
assign csr_inputs.rd_is_zero = (rd_addr == 0);
csr_regs csr_registers (
csr_regs # (.CONFIG(CONFIG))
csr_registers (
.clk(clk), .rst(rst),
.csr_inputs(csr_inputs),
.new_request(stage1.is_csr),

View file

@ -26,6 +26,10 @@ module icache
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -36,18 +40,20 @@ module icache
fetch_sub_unit_interface.sub_unit fetch_sub
);
localparam derived_cache_config_t SCONFIG = get_derived_cache_params(CONFIG, CONFIG.ICACHE, CONFIG.ICACHE_ADDR);
logic tag_hit;
logic [ICACHE_WAYS-1:0] tag_hit_way;
logic [CONFIG.ICACHE.WAYS-1:0] tag_hit_way;
logic tag_update;
logic [ICACHE_WAYS-1:0] replacement_way;
logic [ICACHE_WAYS-1:0] tag_update_way;
logic [CONFIG.ICACHE.WAYS-1:0] replacement_way;
logic [CONFIG.ICACHE.WAYS-1:0] tag_update_way;
logic [$clog2(ICACHE_LINE_W)-1:0] word_count;
logic [SCONFIG.SUB_LINE_ADDR_W-1:0] word_count;
logic is_target_word;
logic line_complete;
logic [31:0] data_out [ICACHE_WAYS-1:0];
logic [31:0] data_out [CONFIG.ICACHE.WAYS-1:0];
logic [31:0] miss_data;
logic miss_in_progress;
@ -92,7 +98,7 @@ module icache
end
//Replacement policy is psuedo random
cycler #(ICACHE_WAYS) replacement_policy (
cycler #(CONFIG.ICACHE.WAYS) replacement_policy (
.clk (clk),
.rst (rst),
.en (1'b1),
@ -112,7 +118,7 @@ module icache
assign l1_request.data = 0;
assign l1_request.rnw = 1;
assign l1_request.be = 0;
assign l1_request.size = (ICACHE_LINE_W-1);
assign l1_request.size = 5'(CONFIG.ICACHE.LINE_W-1);
assign l1_request.is_amo = 0;
assign l1_request.amo = 0;
@ -143,7 +149,8 @@ module icache
////////////////////////////////////////////////////
//Tag banks
itag_banks icache_tag_banks (
itag_banks #(.CONFIG(CONFIG), .SCONFIG(SCONFIG))
icache_tag_banks (
.clk(clk),
.rst(rst | fetch_sub.flush), //clears the read_hit_allowed flag
.stage1_addr(fetch_sub.stage1_addr),
@ -158,11 +165,11 @@ module icache
////////////////////////////////////////////////////
//Data Banks
genvar i;
generate for (i=0; i < ICACHE_WAYS; i++) begin : idata_bank_gen
byte_en_BRAM #(ICACHE_LINES*ICACHE_LINE_W) idata_bank (
generate for (i=0; i < CONFIG.ICACHE.WAYS; i++) begin : idata_bank_gen
byte_en_BRAM #(CONFIG.ICACHE.LINES*CONFIG.ICACHE.LINE_W) idata_bank (
.clk(clk),
.addr_a(fetch_sub.stage1_addr[2 +: ICACHE_LINE_ADDR_W+ICACHE_SUB_LINE_ADDR_W]),
.addr_b({fetch_sub.stage2_addr[(2+ICACHE_SUB_LINE_ADDR_W) +: ICACHE_LINE_ADDR_W], word_count}),
.addr_a(fetch_sub.stage1_addr[2 +: SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W]),
.addr_b({fetch_sub.stage2_addr[(2+SCONFIG.SUB_LINE_ADDR_W) +: SCONFIG.LINE_ADDR_W], word_count}),
.en_a(fetch_sub.new_request),
.en_b(tag_update_way[i] & l1_response.data_valid),
.be_a('0),
@ -183,7 +190,7 @@ module icache
word_count <= word_count + 1;
end
assign is_target_word = (fetch_sub.stage2_addr[2 +: ICACHE_SUB_LINE_ADDR_W] == word_count);
assign is_target_word = (fetch_sub.stage2_addr[2 +: SCONFIG.SUB_LINE_ADDR_W] == word_count);
always_ff @ (posedge clk) begin
if (l1_response.data_valid & is_target_word)
@ -199,7 +206,7 @@ module icache
miss_data_valid <= (miss_in_progress & ~miss_aborted_by_flush) & l1_response.data_valid & is_target_word;
end
assign line_complete = (l1_response.data_valid && (word_count == $clog2(ICACHE_LINE_W)'(ICACHE_LINE_W-1)));
assign line_complete = (l1_response.data_valid && (word_count == SCONFIG.SUB_LINE_ADDR_W'(CONFIG.ICACHE.LINE_W-1)));
always_ff @ (posedge clk) begin
if (rst)
memory_complete <= 0;
@ -211,7 +218,7 @@ module icache
//Output muxing
always_comb begin
fetch_sub.data_out = miss_data;//zero if not a miss
for (int i = 0; i < ICACHE_WAYS; i++) begin
for (int i = 0; i < CONFIG.ICACHE.WAYS; i++) begin
fetch_sub.data_out = fetch_sub.data_out | (data_out[i] & {32{tag_hit_way[i]}});
end
end

View file

@ -24,6 +24,10 @@ module illegal_instruction_checker
import taiga_config::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic [31:0] instruction,
output logic illegal_instruction
@ -153,11 +157,11 @@ module illegal_instruction_checker
assign illegal_instruction = ~(
base_legal |
(USE_MUL & mul_legal) |
(USE_DIV & div_legal) |
(USE_AMO & amo_legal) |
(ENABLE_M_MODE & machine_legal) |
(ENABLE_S_MODE & supervisor_legal)
(CONFIG.INCLUDE_MUL & mul_legal) |
(CONFIG.INCLUDE_DIV & div_legal) |
(CONFIG.INCLUDE_AMO & amo_legal) |
(CONFIG.INCLUDE_M_MODE & machine_legal) |
(CONFIG.INCLUDE_S_MODE & supervisor_legal)
);
endmodule

View file

@ -26,6 +26,10 @@ module instruction_metadata_and_id_management
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -58,14 +62,9 @@ module instruction_metadata_and_id_management
input logic instruction_issued,
input logic instruction_issued_with_rd,
//Branch Predictor
input branch_metadata_t branch_metadata_if,
input id_t branch_id,
output branch_metadata_t branch_metadata_ex,
//WB
input wb_packet_t wb_packet [NUM_WB_GROUPS],
output commit_packet_t commit_packet [NUM_WB_GROUPS],
input wb_packet_t wb_packet [CONFIG.NUM_WB_GROUPS],
output commit_packet_t commit_packet [CONFIG.NUM_WB_GROUPS],
//Retirer
output retire_packet_t retire,
@ -87,12 +86,11 @@ module instruction_metadata_and_id_management
(* ramstyle = "MLAB, no_rw_check" *) phys_addr_t phys_addr_table [MAX_IDS];
(* ramstyle = "MLAB, no_rw_check" *) logic [0:0] uses_rd_table [MAX_IDS];
(* ramstyle = "MLAB, no_rw_check" *) logic [$bits(branch_metadata_t)-1:0] branch_metadata_table [MAX_IDS];
(* ramstyle = "MLAB, no_rw_check" *) logic [$bits(fetch_metadata_t)-1:0] fetch_metadata_table [MAX_IDS];
id_t decode_id;
logic [LOG2_MAX_IDS:0] fetched_count; //MSB used as valid for decode stage
logic [LOG2_MAX_IDS:0] fetched_count;
logic [LOG2_MAX_IDS:0] pre_issue_count;
logic [LOG2_MAX_IDS:0] pre_issue_count_next;
logic [LOG2_MAX_IDS:0] post_issue_count_next;
@ -111,14 +109,6 @@ module instruction_metadata_and_id_management
pc_table[pc_id] <= if_pc;
end
////////////////////////////////////////////////////
//Branch metadata table
//Number of read ports = 1 (branch unit)
always_ff @ (posedge clk) begin
if (pc_id_assigned)
branch_metadata_table[pc_id] <= branch_metadata_if;
end
////////////////////////////////////////////////////
//Instruction table
//Number of read ports = 1 (decode stage)
@ -235,7 +225,7 @@ module instruction_metadata_and_id_management
.clk (clk),
.rst (rst),
.init_clear (gc_init_clear),
.toggle ('{(instruction_issued_with_rd & (issue.rd_wb_group == 1)), wb_packet[1].valid}),
.toggle ('{(instruction_issued_with_rd & issue.is_multicycle), wb_packet[1].valid}),
.toggle_addr ('{issue.id, wb_packet[1].id}),
.read_addr (retire_ids),
.in_use (id_inuse)
@ -293,17 +283,14 @@ module instruction_metadata_and_id_management
assign decode.instruction = instruction_table[decode_id];
assign decode.fetch_metadata = fetch_metadata_table[decode_id];
//Branch Predictor
assign branch_metadata_ex = branch_metadata_table[branch_id];
//Writeback/Commit support
phys_addr_t commit_phys_addr [NUM_WB_GROUPS];
phys_addr_t commit_phys_addr [CONFIG.NUM_WB_GROUPS];
assign commit_phys_addr[0] = issue.phys_rd_addr;
generate for (i = 1; i < NUM_WB_GROUPS; i++) begin
generate for (i = 1; i < CONFIG.NUM_WB_GROUPS; i++) begin
assign commit_phys_addr[i] = phys_addr_table[wb_packet[i].id];
end endgenerate
generate for (i = 0; i < NUM_WB_GROUPS; i++) begin
generate for (i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin
assign commit_packet[i].id = wb_packet[i].id;
assign commit_packet[i].phys_addr = commit_phys_addr[i];
assign commit_packet[i].valid = wb_packet[i].valid & |commit_phys_addr[i];
@ -311,7 +298,7 @@ module instruction_metadata_and_id_management
end endgenerate
//Exception Support
generate if (ENABLE_M_MODE) begin
generate if (CONFIG.INCLUDE_M_MODE) begin
assign exception_pc = pc_table[exception_id];
end endgenerate

View file

@ -28,6 +28,9 @@ interface branch_predictor_interface;
id_t if_id;
logic new_mem_request;
logic [31:0] next_pc;
id_t pc_id;
logic pc_id_assigned;
//Branch Predictor
logic [31:0] branch_flush_pc;
@ -38,12 +41,12 @@ interface branch_predictor_interface;
logic is_branch;
modport branch_predictor (
input if_pc, if_id, new_mem_request, next_pc,
input if_pc, if_id, new_mem_request, next_pc, pc_id, pc_id_assigned,
output branch_flush_pc, predicted_pc, use_prediction, is_return, is_call, is_branch
);
modport fetch (
input branch_flush_pc, predicted_pc, use_prediction, is_return, is_call, is_branch,
output if_pc, if_id, new_mem_request, next_pc
output if_pc, if_id, new_mem_request, next_pc, pc_id, pc_id_assigned
);
endinterface
@ -91,7 +94,7 @@ interface ras_interface;
logic [31:0] new_addr;
logic [31:0] addr;
modport branch_unit (output branch_retired);
modport branch_predictor (output branch_retired);
modport self (input push, pop, new_addr, branch_fetched, branch_retired, output addr);
modport fetch (input addr, output pop, push, new_addr, branch_fetched);
endinterface
@ -239,13 +242,27 @@ interface writeback_store_interface;
);
endinterface
interface ls_sub_unit_interface #(parameter BASE_ADDR = 32'h00000000, parameter UPPER_BOUND = 32'hFFFFFFFF, parameter BIT_CHECK = 4);
interface ls_sub_unit_interface #(parameter bit [31:0] BASE_ADDR = 32'h00000000, parameter bit [31:0] UPPER_BOUND = 32'hFFFFFFFF);
logic data_valid;
logic ready;
logic new_request;
function address_range_check (input logic[31:0] addr);
return (addr[31:32-BIT_CHECK] == BASE_ADDR[31:32-BIT_CHECK]);
//Based on the lower and upper address ranges,
//find the number of bits needed to uniquely identify this memory range.
//Assumption: address range is aligned to its size
function int unsigned bit_range ();
int unsigned i = 0;
for(; i < 32; i++) begin
if (BASE_ADDR[i] == UPPER_BOUND[i])
break;
end
return (32 - i);
endfunction
localparam int unsigned BIT_RANGE = bit_range();
function address_range_check (input logic[31:0] addr);
return (addr[31:32-BIT_RANGE] == BASE_ADDR[31:32-BIT_RANGE]);
endfunction
modport sub_unit (input new_request, output data_valid, ready);
@ -254,7 +271,7 @@ interface ls_sub_unit_interface #(parameter BASE_ADDR = 32'h00000000, parameter
endinterface
interface fetch_sub_unit_interface;
interface fetch_sub_unit_interface #(parameter bit [31:0] BASE_ADDR = 32'h00000000, parameter bit [31:0] UPPER_BOUND = 32'hFFFFFFFF);
logic [31:0] stage1_addr;
logic [31:0] stage2_addr;
@ -264,6 +281,24 @@ interface fetch_sub_unit_interface;
logic new_request;
logic flush;
//Based on the lower and upper address ranges,
//find the number of bits needed to uniquely identify this memory range.
//Assumption: address range is aligned to its size
function int unsigned bit_range ();
int unsigned i = 0;
for(; i < 32; i++) begin
if (BASE_ADDR[i] == UPPER_BOUND[i])
break;
end
return (32 - i);
endfunction
localparam int unsigned BIT_RANGE = bit_range();
function address_range_check (input logic[31:0] addr);
return (addr[31:32-BIT_RANGE] == BASE_ADDR[31:32-BIT_RANGE]);
endfunction
modport sub_unit (input stage1_addr, stage2_addr, new_request, flush, output data_out, data_valid, ready);
modport fetch (output stage1_addr, stage2_addr, new_request, flush, input data_out, data_valid, ready);
@ -284,21 +319,21 @@ interface unsigned_division_interface #(parameter DATA_WIDTH = 32);
modport divider (output remainder, quotient, done, input dividend, dividend_CLZ, divisor, divisor_CLZ, divisor_is_zero, start);
endinterface
interface renamer_interface;
interface renamer_interface #(parameter NUM_WB_GROUPS = 2);
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
rs_addr_t rd_addr;
rs_addr_t [REGFILE_READ_PORTS-1:0] rs_addr;
rs_wb_group_t rd_wb_group;
logic [$clog2(NUM_WB_GROUPS)-1:0] rd_wb_group;
logic uses_rd;
id_t id;
phys_addr_t [REGFILE_READ_PORTS-1:0] phys_rs_addr;
phys_addr_t phys_rd_addr;
rs_wb_group_t [REGFILE_READ_PORTS-1:0] rs_wb_group;
logic [REGFILE_READ_PORTS-1:0][$clog2(NUM_WB_GROUPS)-1:0] rs_wb_group;
modport renamer (
input rd_addr, rs_addr, rd_wb_group, uses_rd, id,
@ -310,20 +345,20 @@ interface renamer_interface;
);
endinterface
interface register_file_issue_interface;
interface register_file_issue_interface #(parameter NUM_WB_GROUPS = 2);
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
//read interface
phys_addr_t phys_rs_addr [REGFILE_READ_PORTS];
logic [LOG2_COMMIT_PORTS-1:0] rs_wb_group [REGFILE_READ_PORTS];
logic [$clog2(NUM_WB_GROUPS)-1:0] rs_wb_group [REGFILE_READ_PORTS];
logic [31:0] data [REGFILE_READ_PORTS];
logic inuse [REGFILE_READ_PORTS];
//write interface
phys_addr_t phys_rd_addr;
logic [LOG2_COMMIT_PORTS-1:0] rd_wb_group;
logic [$clog2(NUM_WB_GROUPS)-1:0] rd_wb_group;
logic issued;
modport register_file (

View file

@ -25,6 +25,11 @@ module itag_banks
import taiga_config::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG,
parameter derived_cache_config_t SCONFIG = '{default: 0}
)
(
input logic clk,
input logic rst,
@ -32,27 +37,27 @@ module itag_banks
input logic[31:0] stage1_addr,
input logic[31:0] stage2_addr,
input logic[ICACHE_WAYS-1:0] update_way,
input logic[CONFIG.ICACHE.WAYS-1:0] update_way,
input logic update,
input logic stage1_adv,
output tag_hit,
output logic[ICACHE_WAYS-1:0] tag_hit_way
output logic[CONFIG.ICACHE.WAYS-1:0] tag_hit_way
);
typedef logic [ICACHE_TAG_W : 0] itag_entry_t;
typedef logic [SCONFIG.TAG_W : 0] itag_entry_t;
function logic[ICACHE_TAG_W-1:0] getTag(logic[31:0] addr);
return addr[2+ICACHE_SUB_LINE_ADDR_W+ICACHE_LINE_ADDR_W +: ICACHE_TAG_W];
function logic[SCONFIG.TAG_W-1:0] getTag(logic[31:0] addr);
return addr[2+SCONFIG.SUB_LINE_ADDR_W+SCONFIG.LINE_ADDR_W +: SCONFIG.TAG_W];
endfunction
function logic[ICACHE_LINE_ADDR_W-1:0] getLineAddr(logic[31:0] addr);
return addr[ICACHE_LINE_ADDR_W + ICACHE_SUB_LINE_ADDR_W + 1 : ICACHE_SUB_LINE_ADDR_W + 2];
function logic[SCONFIG.LINE_ADDR_W-1:0] getLineAddr(logic[31:0] addr);
return addr[SCONFIG.LINE_ADDR_W + SCONFIG.SUB_LINE_ADDR_W + 1 : SCONFIG.SUB_LINE_ADDR_W + 2];
endfunction
logic hit_allowed;
itag_entry_t tag_line[ICACHE_WAYS-1:0];
itag_entry_t tag_line[CONFIG.ICACHE.WAYS-1:0];
itag_entry_t stage2_tag;
assign stage2_tag = {1'b1, getTag(stage2_addr)};
@ -67,9 +72,9 @@ module itag_banks
genvar i;
generate
for (i=0; i < ICACHE_WAYS; i++) begin : tag_bank_gen
for (i=0; i < CONFIG.ICACHE.WAYS; i++) begin : tag_bank_gen
tag_bank #(ICACHE_TAG_W+1, ICACHE_LINES) itag_bank (.*,
tag_bank #(SCONFIG.TAG_W+1, CONFIG.ICACHE.LINES) itag_bank (.*,
.en_a(stage1_adv), .wen_a('0),
.addr_a(getLineAddr(stage1_addr)),
.data_in_a('0), .data_out_a(tag_line[i]),

View file

@ -27,6 +27,10 @@ module l1_arbiter
import taiga_types::*;
import l2_config_and_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -72,12 +76,12 @@ module l1_arbiter
////////////////////////////////////////////////////
//Dcache Specific
assign l2.wr_data_push = USE_DCACHE & (push_ready & l1_request[L1_DCACHE_ID].request & ~l1_request[L1_DCACHE_ID].rnw); //Assumes data cache has highest priority
assign l2.wr_data_push = CONFIG.INCLUDE_DCACHE & (push_ready & l1_request[L1_DCACHE_ID].request & ~l1_request[L1_DCACHE_ID].rnw); //Assumes data cache has highest priority
assign l2.wr_data = l1_request[L1_DCACHE_ID].data;
assign l2.inv_ack = USE_DTAG_INVALIDATIONS ? l1_response[L1_DCACHE_ID].inv_ack : l2.inv_valid;
assign l2.inv_ack = CONFIG.DCACHE.USE_EXTERNAL_INVALIDATIONS ? l1_response[L1_DCACHE_ID].inv_ack : l2.inv_valid;
assign l1_response[L1_DCACHE_ID].inv_addr = l2.inv_addr;
assign l1_response[L1_DCACHE_ID].inv_valid = USE_DTAG_INVALIDATIONS & l2.inv_valid;
assign l1_response[L1_DCACHE_ID].inv_valid = CONFIG.DCACHE.USE_EXTERNAL_INVALIDATIONS & l2.inv_valid;
////////////////////////////////////////////////////
//Interface mapping

View file

@ -124,7 +124,7 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
//Priority is for loads over stores.
//A store will be selected only if either no loads are ready, OR if the store queue is full and a store is ready
assign load_selected = lq_output_valid & ~store_conflict & ~(sq_full & sq_output_valid);
assign load_selected = lq_output_valid & ~store_conflict;// & ~(sq_full & sq_output_valid);
assign lsq.transaction_ready = (lq_output_valid & ~store_conflict) | sq_output_valid;
assign load_ack = lsq.accepted & load_selected;
@ -150,7 +150,7 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
////////////////////////////////////////////////////
//Trace Interface
generate if (ENABLE_TRACE_INTERFACE) begin
assign tr_possible_load_conflict_delay = lq_output_valid & store_conflict;
assign tr_possible_load_conflict_delay = lq_output_valid & (store_conflict | (sq_full & sq_output_valid));
end
endgenerate

View file

@ -26,6 +26,10 @@ module load_store_unit
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -69,20 +73,20 @@ module load_store_unit
output logic tr_load_conflict_delay
);
localparam NUM_SUB_UNITS = USE_D_SCRATCH_MEM+USE_BUS+USE_DCACHE;
localparam NUM_SUB_UNITS = int'(CONFIG.INCLUDE_DLOCAL_MEM) + int'(CONFIG.INCLUDE_PERIPHERAL_BUS) + int'(CONFIG.INCLUDE_DCACHE);
localparam NUM_SUB_UNITS_W = (NUM_SUB_UNITS == 1) ? 1 : $clog2(NUM_SUB_UNITS);
localparam BRAM_ID = 0;
localparam BUS_ID = USE_D_SCRATCH_MEM;
localparam DCACHE_ID = USE_D_SCRATCH_MEM+USE_BUS;
localparam BUS_ID = int'(CONFIG.INCLUDE_DLOCAL_MEM);
localparam DCACHE_ID = int'(CONFIG.INCLUDE_DLOCAL_MEM) + int'(CONFIG.INCLUDE_PERIPHERAL_BUS);
//Should be equal to pipeline depth of longest load/store subunit
localparam ATTRIBUTES_DEPTH = USE_DCACHE ? 2 : 1;
localparam ATTRIBUTES_DEPTH = CONFIG.INCLUDE_DCACHE ? 2 : 1;
data_access_shared_inputs_t shared_inputs;
ls_sub_unit_interface #(.BASE_ADDR(SCRATCH_ADDR_L), .UPPER_BOUND(SCRATCH_ADDR_H), .BIT_CHECK(SCRATCH_BIT_CHECK)) bram();
ls_sub_unit_interface #(.BASE_ADDR(BUS_ADDR_L), .UPPER_BOUND(BUS_ADDR_H), .BIT_CHECK(BUS_BIT_CHECK)) bus();
ls_sub_unit_interface #(.BASE_ADDR(MEMORY_ADDR_L), .UPPER_BOUND(MEMORY_ADDR_H), .BIT_CHECK(MEMORY_BIT_CHECK)) cache();
ls_sub_unit_interface #(.BASE_ADDR(CONFIG.DLOCAL_MEM_ADDR.L), .UPPER_BOUND(CONFIG.DLOCAL_MEM_ADDR.H)) bram();
ls_sub_unit_interface #(.BASE_ADDR(CONFIG.PERIPHERAL_BUS_ADDR.L), .UPPER_BOUND(CONFIG.PERIPHERAL_BUS_ADDR.H)) bus();
ls_sub_unit_interface #(.BASE_ADDR(CONFIG.DCACHE_ADDR.L), .UPPER_BOUND(CONFIG.DCACHE_ADDR.H)) cache();
logic units_ready;
logic unit_switch_stall;
@ -129,7 +133,7 @@ module load_store_unit
////////////////////////////////////////////////////
//Alignment Exception
generate if (ENABLE_M_MODE) begin
generate if (CONFIG.INCLUDE_M_MODE) begin
always_comb begin
case(ls_inputs.fn3)
@ -261,7 +265,7 @@ endgenerate
////////////////////////////////////////////////////
//Unit Instantiation
generate if (USE_D_SCRATCH_MEM) begin
generate if (CONFIG.INCLUDE_DLOCAL_MEM) begin
assign sub_unit_address_match[BRAM_ID] = bram.address_range_check(shared_inputs.addr);
assign bram.new_request = sub_unit_address_match[BRAM_ID] & issue_request;
@ -279,14 +283,14 @@ endgenerate
end
endgenerate
generate if (USE_BUS) begin
generate if (CONFIG.INCLUDE_PERIPHERAL_BUS) begin
assign sub_unit_address_match[BUS_ID] = bus.address_range_check(shared_inputs.addr);
assign bus.new_request = sub_unit_address_match[BUS_ID] & issue_request;
assign unit_ready[BUS_ID] = bus.ready;
assign unit_data_valid[BUS_ID] = bus.data_valid;
if(BUS_TYPE == AXI_BUS)
if(CONFIG.PERIPHERAL_BUS_TYPE == AXI_BUS)
axi_master axi_bus (
.clk (clk),
.rst (rst),
@ -297,7 +301,7 @@ endgenerate
.ls (bus)
); //Lower two bits of fn3 match AXI specification for request size (byte/halfword/word)
else if (BUS_TYPE == WISHBONE_BUS)
else if (CONFIG.PERIPHERAL_BUS_TYPE == WISHBONE_BUS)
wishbone_master wishbone_bus (
.clk (clk),
.rst (rst),
@ -306,7 +310,7 @@ endgenerate
.ls_inputs (shared_inputs),
.ls (bus)
);
else if (BUS_TYPE == AVALON_BUS) begin
else if (CONFIG.PERIPHERAL_BUS_TYPE == AVALON_BUS) begin
avalon_master avalon_bus (
.clk (clk),
.rst (rst),
@ -319,14 +323,15 @@ endgenerate
end
endgenerate
generate if (USE_DCACHE) begin
generate if (CONFIG.INCLUDE_DCACHE) begin
assign sub_unit_address_match[DCACHE_ID] = cache.address_range_check(shared_inputs.addr);
assign cache.new_request = sub_unit_address_match[DCACHE_ID] & issue_request;
assign unit_ready[DCACHE_ID] = cache.ready;
assign unit_data_valid[DCACHE_ID] = cache.data_valid;
dcache data_cache (
dcache # (.CONFIG(CONFIG))
data_cache (
.clk (clk),
.rst (rst),
.dcache_on (dcache_on),

View file

@ -26,6 +26,10 @@ module ras
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -34,9 +38,9 @@ module ras
ras_interface.self ras
);
(* ramstyle = "MLAB, no_rw_check" *) logic[31:0] lut_ram [RAS_DEPTH];
(* ramstyle = "MLAB, no_rw_check" *) logic[31:0] lut_ram [CONFIG.BP.RAS_ENTRIES];
localparam RAS_DEPTH_W = $clog2(RAS_DEPTH);
localparam RAS_DEPTH_W = $clog2(CONFIG.BP.RAS_ENTRIES);
logic [RAS_DEPTH_W-1:0] read_index;
logic [RAS_DEPTH_W-1:0] new_index;
fifo_interface #(.DATA_WIDTH(RAS_DEPTH_W)) ri_fifo();

View file

@ -26,6 +26,10 @@ module register_file
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -36,13 +40,13 @@ module register_file
register_file_issue_interface.register_file rf_issue,
//Writeback
input commit_packet_t commit [NUM_WB_GROUPS]
input commit_packet_t commit [CONFIG.NUM_WB_GROUPS]
);
typedef logic [31:0] rs_data_set_t [REGFILE_READ_PORTS];
rs_data_set_t rs_data_set [NUM_WB_GROUPS];
rs_data_set_t rs_data_set [CONFIG.NUM_WB_GROUPS];
typedef logic inuse_t [REGFILE_READ_PORTS];
inuse_t phys_reg_inuse_set [NUM_WB_GROUPS];
inuse_t phys_reg_inuse_set [CONFIG.NUM_WB_GROUPS];
genvar i;
////////////////////////////////////////////////////
@ -82,7 +86,7 @@ module register_file
//Register Banks
//Implemented in seperate module as there is not universal tool support for inferring
//arrays of memory blocks.
generate for (i = 0; i < NUM_WB_GROUPS; i++) begin : register_file_gen
generate for (i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin : register_file_gen
register_bank #(.NUM_READ_PORTS(REGFILE_READ_PORTS)) reg_group (
.clk, .rst,
.write_addr(commit[i].phys_addr),
@ -107,7 +111,7 @@ module register_file
////////////////////////////////////////////////////
//Assertions
for (genvar i = 0; i < NUM_WB_GROUPS; i++) begin : write_to_rd_zero_assertion
for (genvar i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin : write_to_rd_zero_assertion
assert property (@(posedge clk) disable iff (rst) (commit[i].valid) |-> (commit[i].phys_addr != 0)) else $error("write to register zero");
end

View file

@ -25,6 +25,10 @@ module renamer
import taiga_config::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -86,7 +90,7 @@ module renamer
//During post reset init, initialize rd_to_phys with in-use list (lower 32 registers)
typedef struct packed{
phys_addr_t phys_addr;
rs_wb_group_t wb_group;
logic [$clog2(CONFIG.NUM_WB_GROUPS)-1:0] wb_group;
} spec_table_t;
spec_table_t spec_table_next;
spec_table_t spec_table_old;

View file

@ -29,6 +29,10 @@ module taiga
import riscv_types::*;
import taiga_types::*;
#(
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG
)
(
input logic clk,
input logic rst,
@ -48,6 +52,41 @@ module taiga
input logic interrupt
);
////////////////////////////////////////////////////
//Unit ID Assignment
//Generate Issue IDs based on configuration options
//Then assigned to a struct for ease in passing to sub modules
//Units with writeback
localparam int unsigned ALU_UNIT_ID = 32'd0;
localparam int unsigned LS_UNIT_ID = 32'd1;
localparam int unsigned GC_UNIT_ID = 32'd2;
localparam int unsigned MUL_UNIT_ID = GC_UNIT_ID + int'(CONFIG.INCLUDE_MUL);
localparam int unsigned DIV_UNIT_ID = MUL_UNIT_ID + int'(CONFIG.INCLUDE_DIV);
//Non-writeback units
localparam int unsigned BRANCH_UNIT_ID = DIV_UNIT_ID + 1;
//Total number of units
localparam int unsigned NUM_UNITS = BRANCH_UNIT_ID + 1;
localparam unit_id_param_t UNIT_IDS = '{
ALU : ALU_UNIT_ID,
LS : LS_UNIT_ID,
CSR : GC_UNIT_ID,
MUL : MUL_UNIT_ID,
DIV : DIV_UNIT_ID,
BR : BRANCH_UNIT_ID
};
////////////////////////////////////////////////////
//Writeback Port Assignment
//
localparam int unsigned NUM_WB_UNITS_GROUP_1 = 1;//ALU
localparam int unsigned NUM_WB_UNITS_GROUP_2 = 2 + int'(CONFIG.INCLUDE_MUL) + int'(CONFIG.INCLUDE_DIV);//LS + CSR
localparam int unsigned NUM_WB_UNITS = NUM_WB_UNITS_GROUP_1 + NUM_WB_UNITS_GROUP_2;
////////////////////////////////////////////////////
//Connecting Signals
l1_arbiter_request_interface l1_request[L1_CONNECTIONS-1:0]();
l1_arbiter_return_interface l1_response[L1_CONNECTIONS-1:0]();
logic sc_complete;
@ -63,7 +102,7 @@ module taiga
ras_interface ras();
issue_packet_t issue;
register_file_issue_interface rf_issue();
register_file_issue_interface #(.NUM_WB_GROUPS(CONFIG.NUM_WB_GROUPS)) rf_issue();
alu_inputs_t alu_inputs;
@ -106,23 +145,19 @@ module taiga
decode_packet_t decode;
logic decode_uses_rd;
rs_addr_t decode_rd_addr;
phys_addr_t decode_phys_rd_addr;
//Branch predictor
id_t branch_id;
branch_metadata_t branch_metadata_if;
branch_metadata_t branch_metadata_ex;
phys_addr_t decode_phys_rd_addr;
//ID freeing
retire_packet_t retire;
id_t retire_ids [RETIRE_PORTS];
logic retire_port_valid [RETIRE_PORTS];
//Writeback
wb_packet_t wb_packet [NUM_WB_GROUPS];
commit_packet_t commit_packet [NUM_WB_GROUPS];
wb_packet_t wb_packet [CONFIG.NUM_WB_GROUPS];
commit_packet_t commit_packet [CONFIG.NUM_WB_GROUPS];
//Exception
id_t exception_id;
logic [31:0] exception_pc;
renamer_interface decode_rename_interface ();
renamer_interface #(.NUM_WB_GROUPS(CONFIG.NUM_WB_GROUPS)) decode_rename_interface ();
//Global Control
logic gc_init_clear;
@ -181,18 +216,16 @@ module taiga
logic tr_rs2_forwarding_needed;
logic tr_rs1_and_rs2_forwarding_needed;
unit_id_t tr_num_instructions_completing;
id_t tr_num_instructions_in_flight;
id_t tr_num_of_instructions_pending_writeback;
////////////////////////////////////////////////////
//Implementation
////////////////////////////////////////////////////
// Memory Interface
generate if (ENABLE_S_MODE || USE_ICACHE || USE_DCACHE)
generate if (CONFIG.INCLUDE_S_MODE || CONFIG.INCLUDE_ICACHE || CONFIG.INCLUDE_DCACHE)
l1_arbiter arb(
l1_arbiter #(.CONFIG(CONFIG))
arb(
.clk (clk),
.rst (rst),
.l2 (l2),
@ -206,7 +239,8 @@ module taiga
////////////////////////////////////////////////////
// ID support
instruction_metadata_and_id_management id_block (
instruction_metadata_and_id_management #(.CONFIG(CONFIG))
id_block (
.clk (clk),
.rst (rst),
.gc_init_clear (gc_init_clear),
@ -228,9 +262,6 @@ module taiga
.issue (issue),
.instruction_issued (instruction_issued),
.instruction_issued_with_rd (instruction_issued_with_rd),
.branch_metadata_if (branch_metadata_if),
.branch_metadata_ex (branch_metadata_ex),
.branch_id (branch_id),
.wb_packet (wb_packet),
.commit_packet (commit_packet),
.retire (retire),
@ -243,14 +274,16 @@ module taiga
////////////////////////////////////////////////////
// Fetch
fetch fetch_block (
fetch # (.CONFIG(CONFIG))
fetch_block (
.clk (clk),
.rst (rst),
.branch_flush (branch_flush),
.gc_fetch_hold (gc_fetch_hold),
.gc_fetch_flush (gc_fetch_flush),
.gc_fetch_pc_override (gc_fetch_pc_override),
.gc_fetch_pc (gc_fetch_pc),
.gc_fetch_pc (gc_fetch_pc),
.pc_id (pc_id),
.pc_id_available (pc_id_available),
.pc_id_assigned (pc_id_assigned),
.fetch_complete (fetch_complete),
@ -271,16 +304,17 @@ module taiga
.tr_early_branch_correction (tr_early_branch_correction)
);
branch_predictor bp_block (
.clk (clk),
.rst (rst),
.bp (bp),
.branch_metadata_if (branch_metadata_if),
.branch_metadata_ex (branch_metadata_ex),
.br_results (br_results)
branch_predictor #(.CONFIG(CONFIG))
bp_block (
.clk (clk),
.rst (rst),
.bp (bp),
.br_results (br_results),
.ras (ras)
);
ras ras_block(
ras # (.CONFIG(CONFIG))
ras_block(
.clk (clk),
.rst (rst),
.gc_fetch_flush (gc_fetch_flush),
@ -288,9 +322,10 @@ module taiga
.ras (ras)
);
generate if (ENABLE_S_MODE) begin
generate if (CONFIG.INCLUDE_S_MODE) begin
tlb_lut_ram #(ITLB_WAYS, ITLB_DEPTH) i_tlb (
tlb_lut_ram #(.WAYS(CONFIG.ITLB.WAYS), .DEPTH(CONFIG.ITLB.DEPTH))
i_tlb (
.clk (clk),
.rst (rst),
.abort_request (gc_fetch_flush | early_branch_flush),
@ -319,7 +354,8 @@ module taiga
////////////////////////////////////////////////////
//Renamer
renamer renamer_block (
renamer #(.CONFIG(CONFIG))
renamer_block (
.clk (clk),
.rst (rst),
.gc_init_clear (gc_init_clear),
@ -332,7 +368,12 @@ module taiga
////////////////////////////////////////////////////
//Decode/Issue
decode_and_issue decode_and_issue_block (
decode_and_issue #(
.CONFIG (CONFIG),
.NUM_UNITS (NUM_UNITS),
.UNIT_IDS (UNIT_IDS)
)
decode_and_issue_block (
.clk (clk),
.rst (rst),
.pc_id_available (pc_id_available),
@ -382,7 +423,8 @@ module taiga
////////////////////////////////////////////////////
//Register File
register_file register_file_block (
register_file #(.CONFIG(CONFIG))
register_file_block (
.clk (clk),
.rst (rst),
.gc_init_clear (gc_init_clear),
@ -392,16 +434,14 @@ module taiga
////////////////////////////////////////////////////
//Execution Units
branch_unit branch_unit_block (
branch_unit #(.CONFIG(CONFIG))
branch_unit_block (
.clk (clk),
.rst (rst),
.issue (unit_issue[BRANCH_UNIT_ID]),
.issue (unit_issue[UNIT_IDS.BR]),
.branch_inputs (branch_inputs),
.br_results (br_results),
.ras (ras),
.branch_flush (branch_flush),
.branch_id (branch_id),
.branch_metadata_ex (branch_metadata_ex),
.potential_branch_exception (potential_branch_exception),
.branch_exception_is_jump (branch_exception_is_jump),
.br_exception (br_exception),
@ -416,15 +456,16 @@ module taiga
.clk (clk),
.rst (rst),
.alu_inputs (alu_inputs),
.issue (unit_issue[ALU_UNIT_ID]),
.wb (unit_wb[ALU_UNIT_ID])
.issue (unit_issue[UNIT_IDS.ALU]),
.wb (unit_wb[UNIT_IDS.ALU])
);
load_store_unit load_store_unit_block (
load_store_unit #(.CONFIG(CONFIG))
load_store_unit_block (
.clk (clk),
.rst (rst),
.ls_inputs (ls_inputs),
.issue (unit_issue[LS_UNIT_ID]),
.issue (unit_issue[UNIT_IDS.LS]),
.dcache_on (1'b1),
.clear_reservation (1'b0),
.tlb (dtlb),
@ -445,12 +486,13 @@ module taiga
.ls_is_idle (ls_is_idle),
.ls_exception (ls_exception),
.ls_exception_is_store (ls_exception_is_store),
.wb (unit_wb[LS_UNIT_ID]),
.wb (unit_wb[UNIT_IDS.LS]),
.tr_load_conflict_delay (tr_load_conflict_delay)
);
generate if (ENABLE_S_MODE) begin
tlb_lut_ram #(DTLB_WAYS, DTLB_DEPTH) d_tlb (
generate if (CONFIG.INCLUDE_S_MODE) begin
tlb_lut_ram #(.WAYS(CONFIG.DTLB.WAYS), .DEPTH(CONFIG.DTLB.DEPTH))
d_tlb (
.clk (clk),
.rst (rst),
.abort_request (1'b0),
@ -476,10 +518,11 @@ module taiga
end
endgenerate
gc_unit gc_unit_block (
gc_unit #(.CONFIG(CONFIG))
gc_unit_block (
.clk (clk),
.rst (rst),
.issue (unit_issue[GC_UNIT_ID]),
.issue (unit_issue[UNIT_IDS.CSR]),
.gc_inputs (gc_inputs),
.gc_flush_required (gc_flush_required),
.branch_flush (branch_flush),
@ -509,33 +552,41 @@ module taiga
.gc_fetch_pc (gc_fetch_pc),
.ls_is_idle (ls_is_idle),
.post_issue_count (post_issue_count),
.wb (unit_wb[GC_UNIT_ID])
.wb (unit_wb[UNIT_IDS.CSR])
);
generate if (USE_MUL)
generate if (CONFIG.INCLUDE_MUL)
mul_unit mul_unit_block (.*,
.clk (clk),
.rst (rst),
.mul_inputs (mul_inputs),
.issue (unit_issue[MUL_UNIT_ID]),
.wb (unit_wb[MUL_UNIT_ID])
.issue (unit_issue[UNIT_IDS.MUL]),
.wb (unit_wb[UNIT_IDS.MUL])
);
endgenerate
generate if (USE_DIV)
generate if (CONFIG.INCLUDE_DIV)
div_unit div_unit_block (
.clk (clk),
.rst (rst),
.gc_fetch_flush (gc_fetch_flush),
.div_inputs (div_inputs),
.issue (unit_issue[DIV_UNIT_ID]),
.wb (unit_wb[DIV_UNIT_ID])
.issue (unit_issue[UNIT_IDS.DIV]),
.wb (unit_wb[UNIT_IDS.DIV])
);
endgenerate
////////////////////////////////////////////////////
//Writeback
writeback writeback_block (
//First writeback port: ALU
//Second writeback port: LS, CSR, [MUL], [DIV]
localparam int unsigned NUM_UNITS_PER_PORT [CONFIG.NUM_WB_GROUPS] = '{NUM_WB_UNITS_GROUP_1, NUM_WB_UNITS_GROUP_2};
writeback #(
.CONFIG (CONFIG),
.NUM_UNITS (NUM_UNITS_PER_PORT),
.NUM_WB_UNITS (NUM_WB_UNITS)
)
writeback_block (
.clk (clk),
.rst (rst),
.wb_packet (wb_packet),
@ -587,9 +638,6 @@ module taiga
tr.events.rs1_forwarding_needed <= tr_rs1_forwarding_needed;
tr.events.rs2_forwarding_needed <= tr_rs2_forwarding_needed;
tr.events.rs1_and_rs2_forwarding_needed <= tr_rs1_and_rs2_forwarding_needed;
tr.events.num_instructions_completing <= tr_num_instructions_completing;
tr.events.num_instructions_in_flight <= tr_num_instructions_in_flight;
tr.events.num_of_instructions_pending_writeback <= tr_num_of_instructions_pending_writeback;
tr.instruction_pc_dec <= tr_instruction_pc_dec;
tr.instruction_data_dec <= tr_instruction_data_dec;
end

View file

@ -25,126 +25,202 @@ package taiga_config;
////////////////////////////////////////////////////
//Vendor Selection
localparam FPGA_VENDOR = "xilinx"; //xilinx or intel
////////////////////////////////////////////////////
//Privileged ISA Options
//Enable Machine level privilege spec
localparam ENABLE_M_MODE = 1;
//Enable Supervisor level privilege spec
localparam ENABLE_S_MODE = 1;
//Enable User level privilege spec
localparam ENABLE_U_MODE = 1;
localparam MACHINE_IMPLEMENTATION_ID = 0;
localparam CPU_ID = 0;//32-bicd ..t value
//CSR counter width (33-64 bits): 48-bits --> 32 days @ 100MHz
localparam COUNTER_W = 33;
////////////////////////////////////////////////////
//ISA Options
//Multiply and Divide Inclusion
localparam USE_MUL = 1;
localparam USE_DIV = 1;
//Enable Atomic extension (cache operations only)
localparam USE_AMO = 0;
//CSR Options
typedef struct packed {
bit [31:0] MACHINE_IMPLEMENTATION_ID;
bit [31:0] CPU_ID;
bit [31:0] RESET_VEC; //PC value on reset
int unsigned COUNTER_W; //CSR counter width (33-64 bits): 48-bits --> 32 days @ 100MHz
} csr_config_t;
////////////////////////////////////////////////////
//Memory Sources
//Must select at least one source for instruction and data interfaces
//Cache Options
//Size in bytes: (LINES * WAYS * LINE_W * 4)
//For optimal BRAM packing, LINES should not be less than 512
typedef struct packed {
int unsigned LINES;
int unsigned LINE_W;// In words
int unsigned WAYS;
bit USE_EXTERNAL_INVALIDATIONS;
} cache_config_t;
//Local memory
localparam USE_I_SCRATCH_MEM = 1;
localparam USE_D_SCRATCH_MEM = 1;
typedef struct packed {
int unsigned LINE_ADDR_W;
int unsigned SUB_LINE_ADDR_W;
int unsigned TAG_W;
} derived_cache_config_t;
//Peripheral bus
//Memory range [L, H]
//Address range is inclusive and must be aligned to its size
typedef struct packed {
bit [31:0] L;
bit [31:0] H;
} memory_config_t;
////////////////////////////////////////////////////
//Branch Predictor Options
typedef struct packed {
int unsigned WAYS;
int unsigned ENTRIES;//min512
int unsigned RAS_ENTRIES;
} branch_predictor_config_t;
////////////////////////////////////////////////////
//Bus Options
typedef enum {
AXI_BUS,
AVALON_BUS,
WISHBONE_BUS
} bus_type_t;
localparam USE_BUS = 1;
localparam bus_type_t BUS_TYPE = AXI_BUS;
//Caches
localparam USE_DCACHE = 0;
localparam USE_ICACHE = 0;
} peripheral_bus_type_t;
////////////////////////////////////////////////////
//Address space
localparam SCRATCH_ADDR_L = 32'h80000000;
localparam SCRATCH_ADDR_H = 32'h8001FFFF;
localparam SCRATCH_BIT_CHECK = 4;
//TLB Options
typedef struct packed {
int unsigned WAYS;
int unsigned DEPTH;
} tlb_config_t;
localparam MEMORY_ADDR_L = 32'h40000000;
localparam MEMORY_ADDR_H = 32'h4FFFFFFF;
localparam MEMORY_BIT_CHECK = 4;
typedef struct packed {
//ISA options
bit INCLUDE_M_MODE;
bit INCLUDE_S_MODE;
bit INCLUDE_U_MODE;
bit INCLUDE_MUL;
bit INCLUDE_DIV;
bit INCLUDE_AMO; //Enable Atomic extension (cache operations only)
csr_config_t CSRS;
//Memory Options
bit INCLUDE_ICACHE;
cache_config_t ICACHE;
memory_config_t ICACHE_ADDR;
tlb_config_t ITLB;
bit INCLUDE_DCACHE;
cache_config_t DCACHE;
memory_config_t DCACHE_ADDR;
tlb_config_t DTLB;
bit INCLUDE_ILOCAL_MEM;
memory_config_t ILOCAL_MEM_ADDR;
bit INCLUDE_DLOCAL_MEM;
memory_config_t DLOCAL_MEM_ADDR;
bit INCLUDE_PERIPHERAL_BUS;
memory_config_t PERIPHERAL_BUS_ADDR;
peripheral_bus_type_t PERIPHERAL_BUS_TYPE;
//Branch Predictor Options
bit INCLUDE_BRANCH_PREDICTOR;
branch_predictor_config_t BP;
//Writeback Options
int unsigned NUM_WB_GROUPS;
} cpu_config_t;
localparam BUS_ADDR_L = 32'h60000000;
localparam BUS_ADDR_H = 32'h6FFFFFFF;
localparam BUS_BIT_CHECK = 4;
//Function to generate derived cache parameters
//Tag width based off of memory size and cache parameters
function derived_cache_config_t get_derived_cache_params (input cpu_config_t cpu, input cache_config_t cache, input memory_config_t addr);
return '{
LINE_ADDR_W : $clog2(cache.LINES),
SUB_LINE_ADDR_W : $clog2(cache.LINE_W),
TAG_W : $clog2(64'(addr.H)-64'(addr.L)+1) - $clog2(cache.LINES) - $clog2(cache.LINE_W) - 2
};
endfunction
//PC address on reset
localparam bit[31:0] RESET_VEC = 32'h80000000;
localparam cpu_config_t EXAMPLE_CONFIG = '{
//ISA options
INCLUDE_M_MODE : 1,
INCLUDE_S_MODE : 1,
INCLUDE_U_MODE : 1,
INCLUDE_MUL : 1,
INCLUDE_DIV : 1,
INCLUDE_AMO : 0,
CSRS : '{
MACHINE_IMPLEMENTATION_ID : 0,
CPU_ID : 0,
RESET_VEC : 32'h80000000,
COUNTER_W : 33
},
//Memory Options
INCLUDE_ICACHE : 0,
ICACHE_ADDR : '{
L: 32'h40000000,
H: 32'h4FFFFFFF
},
ICACHE : '{
LINES : 512,
LINE_W : 4,
WAYS : 2,
USE_EXTERNAL_INVALIDATIONS : 0
},
ITLB : '{
WAYS : 2,
DEPTH : 64
},
INCLUDE_DCACHE : 0,
DCACHE_ADDR : '{
L: 32'h40000000,
H: 32'h4FFFFFFF
},
DCACHE : '{
LINES : 512,
LINE_W : 4,
WAYS : 2,
USE_EXTERNAL_INVALIDATIONS : 0
},
DTLB : '{
WAYS : 2,
DEPTH : 64
},
INCLUDE_ILOCAL_MEM : 1,
ILOCAL_MEM_ADDR : '{
L : 32'h80000000,
H : 32'h8FFFFFFF
},
INCLUDE_DLOCAL_MEM : 1,
DLOCAL_MEM_ADDR : '{
L : 32'h80000000,
H : 32'h8FFFFFFF
},
INCLUDE_PERIPHERAL_BUS : 1,
PERIPHERAL_BUS_ADDR : '{
L : 32'h60000000,
H : 32'h6FFFFFFF
},
PERIPHERAL_BUS_TYPE : AXI_BUS,
//Branch Predictor Options
INCLUDE_BRANCH_PREDICTOR : 1,
BP : '{
WAYS : 2,
ENTRIES : 512,
RAS_ENTRIES : 8
},
NUM_WB_GROUPS : 2
};
////////////////////////////////////////////////////
//Unit IDs
typedef struct packed {
int unsigned ALU;
int unsigned LS;
int unsigned CSR;
int unsigned MUL;
int unsigned DIV;
int unsigned BR;
} unit_id_param_t;
localparam unit_id_param_t EXAMPLE_UNIT_IDS = '{
ALU : 0,
LS : 1,
CSR : 2,
MUL : 3,
DIV : 4,
BR : 5
};
////////////////////////////////////////////////////
//Bus Options
parameter C_M_AXI_ADDR_WIDTH = 32; //Kept as parameter, due to localparam failing with scripted IP packaging
parameter C_M_AXI_DATA_WIDTH = 32; //Kept as parameter, due to localparam failing with scripted IP packaging
////////////////////////////////////////////////////
//Instruction Cache Options
//Size in bytes: (ICACHE_LINES * ICACHE_WAYS * ICACHE_LINE_W * 4)
//For optimal BRAM packing, lines should not be less than 512
localparam ICACHE_LINES = 512;
localparam ICACHE_WAYS = 2;
localparam ICACHE_LINE_ADDR_W = $clog2(ICACHE_LINES);
localparam ICACHE_LINE_W = 4; //In words
localparam ICACHE_SUB_LINE_ADDR_W = $clog2(ICACHE_LINE_W);
localparam ICACHE_TAG_W = $clog2(64'(MEMORY_ADDR_H)-64'(MEMORY_ADDR_L)+1) - ICACHE_LINE_ADDR_W - ICACHE_SUB_LINE_ADDR_W - 2;
////////////////////////////////////////////////////
//Data Cache Options
//Size in bytes: (DCACHE_LINES * DCACHE_WAYS * DCACHE_LINE_W * 4)
//For optimal BRAM packing, lines should not be less than 512
localparam DCACHE_LINES = 512;
localparam DCACHE_WAYS = 2;
localparam DCACHE_LINE_ADDR_W = $clog2(DCACHE_LINES);
localparam DCACHE_LINE_W = 4; //In words
localparam DCACHE_SUB_LINE_ADDR_W = $clog2(DCACHE_LINE_W);
localparam DCACHE_TAG_W = $clog2(64'(MEMORY_ADDR_H)-64'(MEMORY_ADDR_L)+1) - DCACHE_LINE_ADDR_W - DCACHE_SUB_LINE_ADDR_W - 2;
localparam USE_DTAG_INVALIDATIONS = 0;
////////////////////////////////////////////////////
//Instruction TLB Options
localparam ITLB_WAYS = 2;
localparam ITLB_DEPTH = 32;
////////////////////////////////////////////////////
//Data TLB Options
localparam DTLB_WAYS = 2;
localparam DTLB_DEPTH = 32;
///////////////////////////////////////////////////
////////////////////////////////////////////////////
//Branch Predictor Options
localparam USE_BRANCH_PREDICTOR = 1;
localparam BRANCH_PREDICTOR_WAYS = 2;
localparam BRANCH_TABLE_ENTRIES = 512; //min 512
localparam RAS_DEPTH = 8;
////////////////////////////////////////////////////
//ID limit
//MAX_IDS restricted to a power of 2
@ -154,7 +230,7 @@ package taiga_config;
//Number of commit ports
localparam RETIRE_PORTS = 2; //min 1. (Non-powers of two supported) > 1 is recommended to allow stores to commit sooner
localparam REGFILE_READ_PORTS = 2; //min 2, for RS1 and RS2. (Non-powers of two supported)
typedef enum logic {
typedef enum bit {
RS1 = 0,
RS2 = 1
} rs1_index_t;
@ -167,41 +243,13 @@ package taiga_config;
////////////////////////////////////////////////////
//L1 Arbiter IDs
localparam L1_CONNECTIONS = 4;//USE_ICACHE + USE_DCACHE + ENABLE_S_MODE*2;
localparam L1_DCACHE_ID = 0;
localparam L1_DMMU_ID = 1;//ENABLE_S_MODE;
localparam L1_ICACHE_ID = 2;//ENABLE_S_MODE + USE_DCACHE;
localparam L1_IMMU_ID = 3;//ENABLE_S_MODE + USE_DCACHE + USE_ICACHE;
////////////////////////////////////////////////////
//Write-Back Unit IDs
localparam NUM_WB_UNITS_GROUP_1 = 1;//ALU
localparam NUM_WB_UNITS_GROUP_2 = 2 + USE_MUL + USE_DIV;//LS + CSR
localparam NUM_WB_UNITS = NUM_WB_UNITS_GROUP_1 + NUM_WB_UNITS_GROUP_2;
localparam NUM_UNITS = NUM_WB_UNITS + 1;//Branch
localparam NUM_WB_GROUPS = 2;
localparam int NUM_WB_UNITS_GROUP [2] = '{NUM_WB_UNITS_GROUP_1, NUM_WB_UNITS_GROUP_2};
localparam int CUMULATIVE_NUM_WB_UNITS_GROUP [2] = '{0, NUM_WB_UNITS_GROUP_1};
localparam ALU_UNIT_ID = 0;
localparam LS_UNIT_ID = 1;
localparam DIV_UNIT_ID = LS_UNIT_ID + USE_DIV;
localparam MUL_UNIT_ID = DIV_UNIT_ID + USE_MUL;
localparam GC_UNIT_ID = MUL_UNIT_ID + 1;
//Non-writeback units
localparam BRANCH_UNIT_ID = GC_UNIT_ID + 1;
//Writeback group 1
localparam ALU_UNIT_WB1_ID = 0;
//Writeback group 2
localparam LS_UNIT_WB2_ID = 0;
localparam DIV_UNIT_WB2_ID = LS_UNIT_WB2_ID + USE_DIV;
localparam MUL_UNIT_WB2_ID = DIV_UNIT_WB2_ID + USE_MUL;
localparam GC_UNIT_WB2_ID = MUL_UNIT_WB2_ID + 1;
localparam L1_CONNECTIONS = 4;
typedef enum bit [1:0] {
L1_DCACHE_ID = 0,
L1_DMMU_ID = 1,
L1_ICACHE_ID = 2,
L1_IMMU_ID = 3
} l1_id_t;
////////////////////////////////////////////////////
//Debug Parameters

View file

@ -25,17 +25,13 @@ package taiga_types;
import riscv_types::*;
localparam LOG2_RETIRE_PORTS = $clog2(RETIRE_PORTS);
localparam WB_UNITS_WIDTH = $clog2(NUM_WB_UNITS);
localparam LOG2_COMMIT_PORTS = $clog2(NUM_WB_GROUPS);
localparam LOG2_MAX_IDS = $clog2(MAX_IDS);
typedef logic[LOG2_MAX_IDS-1:0] id_t;
typedef logic[WB_UNITS_WIDTH-1:0] unit_id_t;
typedef logic[1:0] branch_predictor_metadata_t;
typedef logic [3:0] addr_hash_t;
typedef logic [5:0] phys_addr_t;
typedef logic [$clog2(NUM_WB_GROUPS)-1:0] rs_wb_group_t;
typedef enum logic [1:0] {
ALU_CONSTANT = 2'b00,
@ -58,12 +54,6 @@ package taiga_types;
id_t id;
} exception_packet_t;
typedef struct packed{
branch_predictor_metadata_t branch_predictor_metadata;
logic branch_prediction_used;
logic [BRANCH_PREDICTOR_WAYS-1:0] branch_predictor_update_way;
} branch_metadata_t;
typedef enum logic {
FETCH_ACCESS_FAULT = 1'b0,
FETCH_PAGE_FAULT = 1'b1
@ -90,15 +80,14 @@ package taiga_types;
rs_addr_t [REGFILE_READ_PORTS-1:0] rs_addr;
phys_addr_t [REGFILE_READ_PORTS-1:0] phys_rs_addr;
rs_wb_group_t [REGFILE_READ_PORTS-1:0] rs_wb_group;
rs_addr_t rd_addr;
phys_addr_t phys_rd_addr;
rs_wb_group_t rd_wb_group;
logic uses_rs1;
logic uses_rs2;
logic uses_rd;
logic is_multicycle;
id_t id;
logic stage_valid;
fetch_metadata_t fetch_metadata;
@ -133,13 +122,14 @@ package taiga_types;
} branch_inputs_t;
typedef struct packed {
logic[31:0] pc_ex;
logic [31:0] new_pc;
id_t id;
logic valid;
logic [31:0] pc;
logic [31:0] target_pc;
logic branch_taken;
logic branch_ex;
logic is_branch_ex;
logic is_return_ex;
logic is_call_ex;
logic is_branch;
logic is_return;
logic is_call;
} branch_results_t;
typedef struct packed{
@ -314,10 +304,6 @@ package taiga_types;
logic rs2_forwarding_needed;
logic rs1_and_rs2_forwarding_needed;
//Writeback
unit_id_t num_instructions_completing;
id_t num_instructions_in_flight;
id_t num_of_instructions_pending_writeback;
} taiga_trace_events_t;
typedef struct packed {

View file

@ -26,38 +26,58 @@ module writeback
import riscv_types::*;
import taiga_types::*;
# (
parameter cpu_config_t CONFIG = EXAMPLE_CONFIG,
parameter int unsigned NUM_UNITS [CONFIG.NUM_WB_GROUPS] = '{1, 4},
parameter int unsigned NUM_WB_UNITS = 5
)
(
input logic clk,
input logic rst,
//Unit writeback
unit_writeback_interface.wb unit_wb[NUM_WB_UNITS],
//WB output
output wb_packet_t wb_packet [NUM_WB_GROUPS],
output wb_packet_t wb_packet [CONFIG.NUM_WB_GROUPS],
//Snoop interface (LS unit)
output wb_packet_t wb_snoop
);
//Writeback
logic [NUM_WB_UNITS-1:0] unit_ack [NUM_WB_GROUPS];
logic [NUM_WB_UNITS-1:0] unit_ack [CONFIG.NUM_WB_GROUPS];
//aliases for write-back-interface signals
id_t [NUM_WB_UNITS-1:0] unit_instruction_id [NUM_WB_GROUPS];
logic [NUM_WB_UNITS-1:0] unit_done [NUM_WB_GROUPS];
id_t [NUM_WB_UNITS-1:0] unit_instruction_id [CONFIG.NUM_WB_GROUPS];
logic [NUM_WB_UNITS-1:0] unit_done [CONFIG.NUM_WB_GROUPS];
typedef logic [XLEN-1:0] unit_rd_t [NUM_WB_UNITS];
unit_rd_t unit_rd [NUM_WB_GROUPS];
unit_rd_t unit_rd [CONFIG.NUM_WB_GROUPS];
//Per-ID muxes for commit buffer
logic [$clog2(NUM_WB_UNITS)-1:0] unit_sel [NUM_WB_GROUPS];
logic [$clog2(NUM_WB_UNITS)-1:0] unit_sel [CONFIG.NUM_WB_GROUPS];
typedef int unsigned unit_count_t [CONFIG.NUM_WB_GROUPS];
function unit_count_t get_cumulative_unit_count();
unit_count_t counts;
int unsigned cumulative_count = 0;
for (int i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin
counts[i] = cumulative_count;
cumulative_count += NUM_UNITS[i];
end
return counts;
endfunction
localparam unit_count_t CUMULATIVE_NUM_UNITS = get_cumulative_unit_count();
genvar i, j;
////////////////////////////////////////////////////
//Implementation
//Re-assigning interface inputs to array types so that they can be dynamically indexed
generate
for (i = 0; i < NUM_WB_GROUPS; i++) begin
for (j = 0; j < NUM_WB_UNITS_GROUP[i]; j++) begin
assign unit_instruction_id[i][j] = unit_wb[CUMULATIVE_NUM_WB_UNITS_GROUP[i] + j].id;
assign unit_done[i][j] = unit_wb[CUMULATIVE_NUM_WB_UNITS_GROUP[i] + j].done;
assign unit_wb[CUMULATIVE_NUM_WB_UNITS_GROUP[i] + j].ack = unit_ack[i][j];
for (i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin
for (j = 0; j < NUM_UNITS[i]; j++) begin
assign unit_instruction_id[i][j] = unit_wb[CUMULATIVE_NUM_UNITS[i] + j].id;
assign unit_done[i][j] = unit_wb[CUMULATIVE_NUM_UNITS[i] + j].done;
assign unit_wb[CUMULATIVE_NUM_UNITS[i] + j].ack = unit_ack[i][j];
end
end
endgenerate
@ -65,9 +85,9 @@ module writeback
//As units are selected for commit ports based on their unit ID,
//for each additional commit port one unit can be skipped for the commit mux
generate
for (i = 0; i < NUM_WB_GROUPS; i++) begin
for (j = 0; j < NUM_WB_UNITS_GROUP[i]; j++) begin
assign unit_rd[i][j] = unit_wb[CUMULATIVE_NUM_WB_UNITS_GROUP[i] + j].rd;
for (i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin
for (j = 0; j < NUM_UNITS[i]; j++) begin
assign unit_rd[i][j] = unit_wb[CUMULATIVE_NUM_UNITS[i] + j].rd;
end
end
endgenerate
@ -77,13 +97,13 @@ module writeback
//Iterating through all commit ports:
// Search for complete units (in fixed unit order)
// Assign to a commit port, mask that unit and commit port
generate for (i = 0; i < NUM_WB_GROUPS; i++) begin
generate for (i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin
priority_encoder
#(.WIDTH(NUM_WB_UNITS_GROUP[i]))
#(.WIDTH(NUM_UNITS[i]))
unit_done_encoder
(
.priority_vector (unit_done[i][NUM_WB_UNITS_GROUP[i]-1 : 0]),
.encoded_result (unit_sel[i][NUM_WB_UNITS_GROUP[i] == 1 ? 0 : ($clog2(NUM_WB_UNITS_GROUP[i])-1) : 0])
.priority_vector (unit_done[i][NUM_UNITS[i]-1 : 0]),
.encoded_result (unit_sel[i][NUM_UNITS[i] == 1 ? 0 : ($clog2(NUM_UNITS[i])-1) : 0])
);
assign wb_packet[i].valid = |unit_done[i];
assign wb_packet [i].id = unit_instruction_id[i][unit_sel[i]];
@ -91,7 +111,7 @@ module writeback
end endgenerate
always_comb begin
for (int i = 0; i < NUM_WB_GROUPS; i++) begin
for (int i = 0; i < CONFIG.NUM_WB_GROUPS; i++) begin
unit_ack[i] = '0;
unit_ack[i][unit_sel[i]] = wb_packet[i].valid;
end

View file

@ -235,7 +235,7 @@ module taiga_wrapper (
//design_2 infra(.*);
generate
if (ENABLE_S_MODE || USE_ICACHE || USE_DCACHE) begin
if (EXAMPLE_CONFIG.INCLUDE_S_MODE || EXAMPLE_CONFIG.INCLUDE_ICACHE || EXAMPLE_CONFIG.INCLUDE_DCACHE) begin
l2_arbiter l2_arb (.*, .request(l2));
axi_to_arb l2_to_mem (.*, .l2(mem));
end

View file

@ -68,10 +68,7 @@ static const char * const eventNames[] = {
"load_conflict_delay",
"rs1_forwarding_needed",
"rs2_forwarding_needed",
"rs1_and_rs2_forwarding_needed",
"num_instructions_completing",
"num_instructions_in_flight",
"num_of_instructions_pending_writeback"
"rs1_and_rs2_forwarding_needed"
};
static const int numEvents = arraySize(eventNames);

View file

@ -286,7 +286,7 @@ module taiga_sim
assign data_bram_data_in = data_bram.data_in;
assign data_bram.data_out = data_bram_data_out;
taiga cpu(.*, .l2(l2[0]));
taiga #(.CONFIG(EXAMPLE_CONFIG)) cpu(.*, .l2(l2[0]));
//read channel
logic[3:0] read_counter;
@ -436,13 +436,13 @@ module taiga_sim
////////////////////////////////////////////////////
//Performs the lookups to provide the speculative architectural register file with
//standard register names for simulation purposes
logic [31:0][31:0] sim_registers_unamed_groups[NUM_WB_GROUPS];
logic [31:0][31:0] sim_registers_unamed_groups[EXAMPLE_CONFIG.NUM_WB_GROUPS];
logic [31:0][31:0] sim_registers_unamed;
simulation_named_regfile sim_register;
genvar i, j;
generate for (i = 0; i < 32; i++) begin
for (j = 0; j < NUM_WB_GROUPS; j++) begin
for (j = 0; j < EXAMPLE_CONFIG.NUM_WB_GROUPS; j++) begin
assign sim_registers_unamed_groups[j][i] =
cpu.register_file_block.register_file_gen[j].reg_group.register_file_bank[cpu.renamer_block.spec_table[i].phys_addr];
end