diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index 60583cbad..7ca59c927 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index 8db8c6c34..1b517df37 100755 --- a/include/ariane_pkg.sv +++ b/include/ariane_pkg.sv @@ -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 diff --git a/src/ariane.sv b/src/ariane.sv old mode 100644 new mode 100755 index 83e851ce7..aca7eb658 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -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 ( diff --git a/src/compressed_decoder.sv b/src/compressed_decoder.sv old mode 100644 new mode 100755 index cc405555c..bfcc522a5 --- a/src/compressed_decoder.sv +++ b/src/compressed_decoder.sv @@ -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}; diff --git a/src/decoder.sv b/src/decoder.sv old mode 100644 new mode 100755 index 6f6d38350..9a351ccb0 --- a/src/decoder.sv +++ b/src/decoder.sv @@ -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 diff --git a/src/frontend.sv b/src/frontend.sv index 97f0d969d..491eeecde 100755 --- a/src/frontend.sv +++ b/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 diff --git a/src/icache.sv b/src/icache.sv old mode 100644 new mode 100755 index c20c0a163..6e0b76f05 --- a/src/icache.sv +++ b/src/icache.sv @@ -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,