mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 06:07:19 -04:00
Add instruction scanner
This commit is contained in:
parent
c0abcc2c4e
commit
140ed0cadc
7 changed files with 137 additions and 50 deletions
12
Makefile
Normal file → Executable file
12
Makefile
Normal file → Executable file
|
@ -24,7 +24,7 @@ ariane_pkg := include/ariane_pkg.sv include/nbdcache_pkg.sv
|
|||
util := $(wildcard src/util/*.svh) src/util/instruction_tracer_pkg.sv src/util/instruction_tracer_if.sv \
|
||||
src/util/generic_fifo.sv src/util/cluster_clock_gating.sv src/util/behav_sram.sv
|
||||
# test targets
|
||||
tests := alu scoreboard fifo dcache_arbiter store_queue lsu core fetch_fifo
|
||||
tests := alu scoreboard fifo dcache_arbiter store_queue lsu core fetch_fifo icache
|
||||
# UVM agents
|
||||
agents := $(wildcard tb/agents/*/*.sv*)
|
||||
# path to interfaces
|
||||
|
@ -41,7 +41,7 @@ dpi := $(wildcard tb/dpi/*)
|
|||
src := $(wildcard src/*.sv) $(wildcard tb/common/*.sv) $(wildcard src/axi2per/*.sv) $(wildcard src/axi_slice/*.sv) \
|
||||
$(wildcard src/axi_node/*.sv) $(wildcard src/axi_mem_if/*.sv)
|
||||
# look for testbenches
|
||||
tbs := tb/alu_tb.sv tb/core_tb.sv tb/dcache_arbiter_tb.sv tb/store_queue_tb.sv tb/scoreboard_tb.sv tb/fifo_tb.sv
|
||||
tbs := tb/alu_tb.sv tb/core_tb.sv tb/dcache_arbiter_tb.sv tb/store_queue_tb.sv tb/scoreboard_tb.sv tb/fifo_tb.sv tb/icache_tb.sv
|
||||
|
||||
# RISCV-tests path
|
||||
riscv-test-dir := tmp/riscv-tests/build/isa
|
||||
|
@ -160,10 +160,10 @@ $(tests): build
|
|||
vopt${questa_version} -work ${library} ${compile_flag} $@_tb -o $@_tb_optimized +acc -check_synthesis
|
||||
# vsim${questa_version} $@_tb_optimized
|
||||
# vsim${questa_version} +UVM_TESTNAME=$@_test -coverage -classdebug $@_tb_optimized
|
||||
vsim${questa_version} +UVM_TESTNAME=$@_test +ASMTEST=$(riscv-test-dir)/$(riscv-test) \
|
||||
+uvm_set_action="*,_ALL_,UVM_ERROR,UVM_DISPLAY|UVM_STOP" -c -coverage -classdebug \
|
||||
-do "coverage save -onexit $@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]" \
|
||||
${library}.$@_tb_optimized
|
||||
# vsim${questa_version} +UVM_TESTNAME=$@_test +ASMTEST=$(riscv-test-dir)/$(riscv-test) \
|
||||
# +uvm_set_action="*,_ALL_,UVM_ERROR,UVM_DISPLAY|UVM_STOP" -c -coverage -classdebug \
|
||||
# -do "coverage save -onexit $@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]" \
|
||||
# ${library}.$@_tb_optimized
|
||||
|
||||
# User Verilator
|
||||
verilate:
|
||||
|
|
|
@ -234,6 +234,10 @@ package ariane_pkg;
|
|||
localparam OPCODE_AUIPC = 7'h17;
|
||||
localparam OPCODE_LUI = 7'h37;
|
||||
localparam OPCODE_AMO = 7'h2F;
|
||||
|
||||
localparam OPCODE_C_J = 3'b101;
|
||||
localparam OPCODE_C_BEQZ = 3'b110;
|
||||
localparam OPCODE_C_BNEZ = 3'b111;
|
||||
// --------------------
|
||||
// Atomics
|
||||
// --------------------
|
||||
|
@ -435,4 +439,19 @@ package ariane_pkg;
|
|||
function automatic logic [63:0] sext32 (logic [31:0] operand);
|
||||
return {{32{operand[31]}}, operand[31:0]};
|
||||
endfunction
|
||||
|
||||
// ----------------------
|
||||
// Immediate functions
|
||||
// ----------------------
|
||||
function automatic logic [63:0] uj_imm (logic [31:0] instruction_i);
|
||||
return { {44 {instruction_i[31]}}, instruction_i[19:12], instruction_i[20], instruction_i[30:21], 1'b0 };
|
||||
endfunction
|
||||
|
||||
function automatic logic [63:0] i_imm (logic [31:0] instruction_i);
|
||||
return { {52 {instruction_i[31]}}, instruction_i[31:20] };
|
||||
endfunction
|
||||
|
||||
function automatic logic [63:0] sb_imm (logic [31:0] instruction_i);
|
||||
return { {51 {instruction_i[31]}}, instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 };
|
||||
endfunction
|
||||
endpackage
|
||||
|
|
2
src/ariane.sv
Normal file → Executable file
2
src/ariane.sv
Normal file → Executable file
|
@ -648,7 +648,7 @@ module ariane #(
|
|||
// -------------------
|
||||
// Instruction Cache
|
||||
// -------------------
|
||||
icache #(
|
||||
icache_old #(
|
||||
.AXI_USER_WIDTH ( AXI_USER_WIDTH ),
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
|
||||
) i_icache (
|
||||
|
|
4
src/compressed_decoder.sv
Normal file → Executable file
4
src/compressed_decoder.sv
Normal file → Executable file
|
@ -90,7 +90,7 @@ module compressed_decoder
|
|||
illegal_instr_o = 1'b1;
|
||||
end
|
||||
|
||||
3'b101: begin
|
||||
OPCODE_C_J: begin
|
||||
// 101: c.j -> jal x0, imm
|
||||
instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6], instr_i[7], instr_i[2], instr_i[11], instr_i[5:3], {9 {instr_i[12]}}, 4'b0, ~instr_i[15], OPCODE_JAL};
|
||||
end
|
||||
|
@ -174,7 +174,7 @@ module compressed_decoder
|
|||
endcase
|
||||
end
|
||||
|
||||
3'b110, 3'b111: begin
|
||||
OPCODE_C_BEQZ, OPCODE_C_BNEZ: begin
|
||||
// 0: c.beqz -> beq rs1', x0, imm
|
||||
// 1: c.bnez -> bne rs1', x0, imm
|
||||
instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b0, 2'b01, instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3], instr_i[12], OPCODE_BRANCH};
|
||||
|
|
15
src/decoder.sv
Normal file → Executable file
15
src/decoder.sv
Normal file → Executable file
|
@ -55,12 +55,7 @@ module decoder (
|
|||
logic [63:0] imm_sb_type;
|
||||
logic [63:0] imm_u_type;
|
||||
logic [63:0] imm_uj_type;
|
||||
logic [63:0] imm_z_type;
|
||||
logic [63:0] imm_s2_type;
|
||||
logic [63:0] imm_bi_type;
|
||||
logic [63:0] imm_s3_type;
|
||||
logic [63:0] imm_vs_type;
|
||||
logic [63:0] imm_vu_type;
|
||||
|
||||
always_comb begin : decoder
|
||||
|
||||
|
@ -493,17 +488,13 @@ module decoder (
|
|||
// Sign extend immediate
|
||||
// --------------------------------
|
||||
always_comb begin : sign_extend
|
||||
imm_i_type = { {52 {instruction_i[31]}}, instruction_i[31:20] };
|
||||
imm_i_type = i_imm(instruction_i);
|
||||
imm_iz_type = { 52'b0, instruction_i[31:20] };
|
||||
imm_s_type = { {52 {instruction_i[31]}}, instruction_i[31:25], instruction_i[11:7] };
|
||||
imm_sb_type = { {51 {instruction_i[31]}}, instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 };
|
||||
imm_sb_type = sb_imm(instruction_i);
|
||||
imm_u_type = { {32 {instruction_i[31]}}, instruction_i[31:12], 12'b0 }; // JAL, AUIPC, sign extended to 64 bit
|
||||
imm_uj_type = { {44 {instruction_i[31]}}, instruction_i[19:12], instruction_i[20], instruction_i[30:21], 1'b0 };
|
||||
imm_s2_type = { 59'b0, instruction_i[24:20] };
|
||||
imm_uj_type = uj_imm(instruction_i);
|
||||
imm_bi_type = { {59{instruction_i[24]}}, instruction_i[24:20] };
|
||||
imm_s3_type = { 59'b0, instruction_i[29:25] };
|
||||
imm_vs_type = { {58 {instruction_i[24]}}, instruction_i[24:20], instruction_i[25] };
|
||||
imm_vu_type = { 58'b0, instruction_i[24:20], instruction_i[25] };
|
||||
|
||||
// NOIMM, PCIMM, IIMM, SIMM, BIMM, BIMM, UIMM, JIMM
|
||||
// select immediate
|
||||
|
|
133
src/frontend.sv
133
src/frontend.sv
|
@ -76,6 +76,7 @@ module frontend #(
|
|||
input logic debug_set_pc_i, // Set PC request from debug
|
||||
// Instruction Fetch
|
||||
AXI_BUS.Master axi,
|
||||
output logic l1_icache_miss_o, // instruction cache missed
|
||||
//
|
||||
// instruction output port -> to processor back-end
|
||||
output fetch_entry_t fetch_entry_o, // fetch entry containing all relevant data for the ID stage
|
||||
|
@ -140,7 +141,8 @@ icache #(.SET_ASSOCIATIVITY(4)) i_icache (
|
|||
.kill_req_i (),
|
||||
.ready_o (),
|
||||
.valid_o (),
|
||||
.axi (axi)
|
||||
.axi (axi),
|
||||
.miss_o (l1_icache_miss_o)
|
||||
);
|
||||
|
||||
|
||||
|
@ -150,24 +152,51 @@ endmodule
|
|||
// Instruction Scanner
|
||||
// ------------------------------
|
||||
module instr_scan (
|
||||
input logic [31:0] instr_i
|
||||
input logic [31:0] instr_i, // expect aligned instruction, compressed or not
|
||||
output logic is_rvc_o,
|
||||
output logic rvi_return_o,
|
||||
output logic rvi_call_o,
|
||||
output logic rvc_branch_o,
|
||||
output logic rvc_jump_o,
|
||||
output logic rvc_jr_o,
|
||||
output logic rvc_return_o,
|
||||
output logic rvc_jalr_o,
|
||||
output logic rvc_call_o,
|
||||
output logic [63:0] rvi_imm_o,
|
||||
output logic [63:0] rvc_imm_o,
|
||||
output logic rvi_branch_o,
|
||||
output logic rvi_jalr_o,
|
||||
output logic rvi_jump_o
|
||||
);
|
||||
// logic rviBranch;
|
||||
// logic rviJump;
|
||||
// logic rviJALR;
|
||||
// logic rviReturnl
|
||||
// logic rviCall;
|
||||
assign is_rvc_o = (instr_i[1:0] != 2'b00);
|
||||
// check that rs1 is either x1 or x5 and that rs1 is not x1 or x5, TODO: check the fact about bit 7
|
||||
assign rvi_return_o = rvi_jalr_o & ~instr_i[7] & ~instr_i[19] & ~instr_i[18] & instr_i[17] & ~instr_i[15];
|
||||
assign rvi_call_o = (rvi_jalr_o || rvi_jump_o) & instr_i[7]; // TODO: check that this captures calls
|
||||
assign rvc_branch_o = (instr_i[15:13] == OPCODE_C_BEQZ) | (instr_i[15:13] == OPCODE_C_BNEZ);
|
||||
// opcode JAL
|
||||
assign rvc_jump_o = (instr_i[15:13] == OPCODE_C_J);
|
||||
assign rvc_jr_o = (instr_i[15:12] == 4'b1000) & (instr_i[6:2] == 5'b00000);
|
||||
// check that rs1 is x1 or x5
|
||||
assign rvc_return_o = rvc_jr_o & ~instr_i[11] & ~instr_i[10] & ~instr_i[8] & ~instr_i[7];
|
||||
assign rvc_jalr_o = (instr_i[15:12] == 4'b1001) & (instr_i[6:2] == 5'b00000);
|
||||
assign rvc_call_o = rvc_jalr_o; // TODO: check that this captures calls
|
||||
|
||||
always_comb begin
|
||||
|
||||
end
|
||||
// differentiates between JAL and BRANCH opcode, JALR comes from BHT
|
||||
assign rvi_imm_o = (instr_i[3]) ? uj_imm(instr_i) : sb_imm(instr_i);
|
||||
// // differentiates between JAL and BRANCH opcode, JALR comes from BHT
|
||||
assign rvc_imm_o = (instr_i[14]) ? {{56{instr_i[12]}}, instr_i[6:5], instr_i[2], instr_i[11:10], instr_i[4:3], 1'b0}
|
||||
: {{53{instr_i[12]}}, instr_i[8], instr_i[10:9], instr_i[6], instr_i[7], instr_i[2], instr_i[11], instr_i[5:3], 1'b0};
|
||||
|
||||
assign rvi_branch_o = (instr_i[6:0] == OPCODE_BRANCH) ? 1'b1 : 1'b0;
|
||||
assign rvi_jalr_o = (instr_i[6:0] == OPCODE_JALR) ? 1'b1 : 1'b0;
|
||||
assign rvi_jump_o = (instr_i[6:0] == OPCODE_JAL) ? 1'b1 : 1'b0;
|
||||
endmodule
|
||||
|
||||
// ------------------------------
|
||||
// Instruction Cache
|
||||
// ------------------------------
|
||||
module icache #(
|
||||
parameter int unsigned SET_ASSOCIATIVITY = 8,
|
||||
parameter int unsigned SET_ASSOCIATIVITY = 4,
|
||||
parameter int unsigned INDEX_WIDTH = 12, // in bit
|
||||
parameter int unsigned TAG_WIDTH = 44, // in bit
|
||||
parameter int unsigned CACHE_LINE_WIDTH = 64, // in bit
|
||||
|
@ -175,7 +204,7 @@ module icache #(
|
|||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic flush_i, // flush the icache
|
||||
input logic flush_i, // flush the icache, flush and kill have to be asserted together
|
||||
input logic req_i, // we request a new word
|
||||
input logic kill_req_i, // kill the current request
|
||||
output logic ready_o, // icache is ready
|
||||
|
@ -183,6 +212,7 @@ module icache #(
|
|||
input logic [TAG_WIDTH-1:0] tag_i, // 2nd cycle: physical tag
|
||||
output logic [FETCH_WIDTH-1:0] data_o, // 2+ cycle out: tag
|
||||
output logic valid_o, // signals a valid read
|
||||
output logic miss_o, // we missed on the cache
|
||||
AXI_BUS.Master axi
|
||||
);
|
||||
|
||||
|
@ -190,13 +220,14 @@ module icache #(
|
|||
localparam ICACHE_NUM_WORD = 2**(INDEX_WIDTH - BYTE_OFFSET);
|
||||
|
||||
// registers
|
||||
enum logic [3:0] { FLUSH, IDLE, TAG_CMP, WAIT_AXI_R_RESP,
|
||||
enum logic [3:0] { FLUSH, IDLE, TAG_CMP, WAIT_AXI_R_RESP, WAIT_KILLED_REFILL, WAIT_KILLED_AXI_R_RESP,
|
||||
REDO_REQ, WAIT_TAG_SAVED, REFILL
|
||||
} state_d, state_q;
|
||||
logic [$clog2(ICACHE_NUM_WORD)-1:0] cnt_d, cnt_q;
|
||||
logic [INDEX_WIDTH-1:0] index_d, index_q;
|
||||
logic [TAG_WIDTH-1:0] tag_d, tag_q;
|
||||
logic [SET_ASSOCIATIVITY-1:0] evict_way_d, evict_way_q;
|
||||
logic flushing_d, flushing_q;
|
||||
|
||||
// signals
|
||||
logic [SET_ASSOCIATIVITY-1:0] req; // request to memory array
|
||||
|
@ -291,6 +322,7 @@ module icache #(
|
|||
for (genvar i = 0; i < SET_ASSOCIATIVITY; i++) begin
|
||||
assign way_valid[i] = tag_rdata[i].valid;
|
||||
end
|
||||
|
||||
// ------------------
|
||||
// AXI Plumbing
|
||||
// ------------------
|
||||
|
@ -327,7 +359,6 @@ module icache #(
|
|||
|
||||
assign axi.r_ready = 1'b1;
|
||||
|
||||
|
||||
// ------------------
|
||||
// Cache Ctrl
|
||||
// ------------------
|
||||
|
@ -338,15 +369,18 @@ module icache #(
|
|||
index_d = index_q;
|
||||
tag_d = tag_q;
|
||||
evict_way_d = evict_way_q;
|
||||
flushing_d = flushing_q;
|
||||
|
||||
req = '0;
|
||||
addr = index_i[INDEX_WIDTH-1:BYTE_OFFSET];
|
||||
we = 1'b0;
|
||||
data_wdata = '0;
|
||||
tag_wdata = '0;
|
||||
ready_o = 1'b0;
|
||||
tag = tag_i;
|
||||
valid_o = 1'b1;
|
||||
req = '0;
|
||||
addr = index_i[INDEX_WIDTH-1:BYTE_OFFSET];
|
||||
we = 1'b0;
|
||||
data_wdata = '0;
|
||||
tag_wdata = '0;
|
||||
ready_o = 1'b0;
|
||||
tag = tag_i;
|
||||
valid_o = 1'b0;
|
||||
update_lfsr = 1'b0;
|
||||
miss_o = 1'b0;
|
||||
|
||||
axi.ar_valid = 1'b0;
|
||||
axi.ar_addr = '0;
|
||||
|
@ -363,6 +397,11 @@ module icache #(
|
|||
index_d = index_i;
|
||||
state_d = TAG_CMP;
|
||||
end
|
||||
|
||||
// go to flushing state
|
||||
if (flush_i || flushing_q)
|
||||
state_d = FLUSH;
|
||||
|
||||
end
|
||||
// ~> compare the tag
|
||||
TAG_CMP: begin
|
||||
|
@ -376,13 +415,21 @@ module icache #(
|
|||
req = '1;
|
||||
// save the index and stay in compare mode
|
||||
index_d = index_i;
|
||||
// no new request -> go back to idle
|
||||
end else begin
|
||||
state_d = IDLE;
|
||||
end
|
||||
end else begin
|
||||
state_d = REFILL;
|
||||
evict_way_d = '0;
|
||||
// save tag
|
||||
tag_d = tag_i;
|
||||
miss_o = 1'b1;
|
||||
// get way which to replace
|
||||
if (repl_w_random) begin
|
||||
evict_way_d = random_way;
|
||||
// shift the lfsr
|
||||
update_lfsr = 1'b1;
|
||||
end else begin
|
||||
evict_way_d[repl_invalid] = 1'b1;
|
||||
end
|
||||
|
@ -392,8 +439,12 @@ module icache #(
|
|||
REFILL: begin
|
||||
axi.ar_valid = 1'b1;
|
||||
axi.ar_addr[INDEX_WIDTH+TAG_WIDTH-1:0] = {tag_q, index_q};
|
||||
|
||||
if (kill_req_i)
|
||||
state_d = WAIT_KILLED_REFILL;
|
||||
|
||||
if (axi.ar_ready)
|
||||
state_d = WAIT_AXI_R_RESP;
|
||||
state_d = (kill_req_i) ? WAIT_KILLED_AXI_R_RESP : WAIT_AXI_R_RESP;
|
||||
end
|
||||
// ~> wait for the read response
|
||||
// TODO: Handle responses for arbitrary cache line widths
|
||||
|
@ -410,8 +461,11 @@ module icache #(
|
|||
data_wdata = axi.r_data;
|
||||
end
|
||||
|
||||
if (kill_req_i)
|
||||
state_d = WAIT_KILLED_AXI_R_RESP;
|
||||
|
||||
if (axi.r_last) begin
|
||||
state_d = REDO_REQ;
|
||||
state_d = (kill_req_i) ? IDLE : REDO_REQ;
|
||||
end
|
||||
end
|
||||
// ~> redo the request,
|
||||
|
@ -421,13 +475,23 @@ module icache #(
|
|||
tag = tag_q;
|
||||
state_d = WAIT_TAG_SAVED;
|
||||
end
|
||||
|
||||
// we already saved the tag -> apply it
|
||||
WAIT_TAG_SAVED: begin
|
||||
tag = tag_q;
|
||||
state_d = IDLE;
|
||||
valid_o = 1'b1;
|
||||
end
|
||||
|
||||
// we need to wait for some AXI responses to come back
|
||||
// here for the AW valid
|
||||
WAIT_KILLED_REFILL: begin
|
||||
if (axi.aw_valid)
|
||||
state_d = IDLE;
|
||||
end
|
||||
// and here for the last R valid
|
||||
WAIT_KILLED_AXI_R_RESP: begin
|
||||
if (axi.r_last)
|
||||
state_d = IDLE;
|
||||
end
|
||||
// ~> we are coming here after reset or when a flush was requested
|
||||
FLUSH: begin
|
||||
addr = cnt_q;
|
||||
|
@ -435,11 +499,22 @@ module icache #(
|
|||
req = '1;
|
||||
we = 1;
|
||||
// we've finished flushing, go back to idle
|
||||
if (cnt_q == ICACHE_NUM_WORD - 1) state_d = IDLE;
|
||||
if (cnt_q == ICACHE_NUM_WORD - 1) begin
|
||||
state_d = IDLE;
|
||||
flushing_d = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
default : state_d = IDLE;
|
||||
endcase
|
||||
|
||||
if (kill_req_i && !(state_q inside {REFILL, WAIT_AXI_R_RESP, WAIT_KILLED_REFILL, WAIT_KILLED_AXI_R_RESP})) begin
|
||||
state_d = IDLE;
|
||||
end
|
||||
|
||||
if (flush_i) begin
|
||||
flushing_d = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
ff1 #(
|
||||
|
@ -469,18 +544,20 @@ module icache #(
|
|||
index_q <= '0;
|
||||
tag_q <= '0;
|
||||
evict_way_q <= '0;
|
||||
flushing_q <= 1'b0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
cnt_q <= cnt_d;
|
||||
index_q <= index_d;
|
||||
tag_q <= tag_d;
|
||||
evict_way_q <= evict_way_d;
|
||||
flushing_q <= flushing_d;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
assert ($bits(data_if.aw_addr) == 64) else $fatal(1, "Ariane needs a 64-bit bus");
|
||||
assert ($bits(axi.aw_addr) == 64) else $fatal(1, "Ariane needs a 64-bit bus");
|
||||
assert (CACHE_LINE_WIDTH == 64) else $fatal(1, "Instruction cacheline width needs to be 64 for the moment");
|
||||
end
|
||||
`endif
|
||||
|
|
2
src/icache.sv
Normal file → Executable file
2
src/icache.sv
Normal file → Executable file
|
@ -23,7 +23,7 @@
|
|||
// Revision v0.1 - File Created
|
||||
// Revision v0.2 - Remove SCMs
|
||||
|
||||
module icache #(
|
||||
module icache_old #(
|
||||
parameter int unsigned FETCH_ADDR_WIDTH = 56, // Size of the fetch address
|
||||
parameter int unsigned FETCH_DATA_WIDTH = 64, // Size of the fetch data
|
||||
parameter int unsigned ID_WIDTH = 4,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue