diff --git a/include/ariane_pkg.svh b/include/ariane_pkg.svh index 826a24a5b..56932453b 100644 --- a/include/ariane_pkg.svh +++ b/include/ariane_pkg.svh @@ -14,7 +14,7 @@ package ariane_pkg; // --------------- // Global Config // --------------- - localparam NR_SB_ENTRIES = 4; // number of scoreboard entries + localparam NR_SB_ENTRIES = 8; // number of scoreboard entries localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits // to uniquely identify the entry in the scoreboard localparam NR_WB_PORTS = 4; diff --git a/src/fifo.sv b/src/fifo.sv index 4bda4de62..f6e073197 100644 --- a/src/fifo.sv +++ b/src/fifo.sv @@ -68,6 +68,7 @@ module fifo #( // but increment the read pointer... read_pointer_n = read_pointer_q + 1; // ... and decrement the overall count + mem_n[read_pointer_q] = '0; status_cnt_n = status_cnt_q - 1; end // keep the count pointer stable if we push and pop at the same time diff --git a/src/issue_stage.sv b/src/issue_stage.sv index 7c2e5c0af..5233e3639 100755 --- a/src/issue_stage.sv +++ b/src/issue_stage.sv @@ -21,7 +21,7 @@ import ariane_pkg::*; module issue_stage #( - parameter int NR_ENTRIES = 4, + parameter int NR_ENTRIES = 8, parameter int NR_WB_PORTS = 4 )( input logic clk_i, // Clock diff --git a/src/load_unit.sv b/src/load_unit.sv index 19c7bf86d..0d3fbad16 100644 --- a/src/load_unit.sv +++ b/src/load_unit.sv @@ -25,7 +25,7 @@ module load_unit ( // load unit input port input logic valid_i, input lsu_ctrl_t lsu_ctrl_i, - input logic [7:0] be_i, + output logic pop_ld_o, // load unit output port output logic valid_o, output logic ready_o, @@ -93,6 +93,7 @@ module load_unit ( kill_req_o = 1'b0; tag_valid_o = 1'b0; data_be_o = lsu_ctrl_i.be; + pop_ld_o = 1'b0; case (CS) IDLE: begin @@ -109,10 +110,11 @@ module load_unit ( if (!data_gnt_i) begin NS = WAIT_GNT; end else begin - if (dtlb_hit_i) + if (dtlb_hit_i) begin // we got a grant and a hit on the DTLB so we can send the tag in the next cycle NS = SEND_TAG; - else + pop_ld_o = 1'b1; + end else NS = ABORT_TRANSACTION; end end else begin @@ -163,9 +165,10 @@ module load_unit ( // we finally got a data grant if (data_gnt_i) begin // so we send the tag in the next cycle - if (dtlb_hit_i) + if (dtlb_hit_i) begin NS = SEND_TAG; - else // should we not have hit on the TLB abort this transaction an retry later + pop_ld_o = 1'b1; + end else // should we not have hit on the TLB abort this transaction an retry later NS = ABORT_TRANSACTION; end // otherwise we keep waiting on our grant @@ -187,10 +190,11 @@ module load_unit ( NS = WAIT_GNT; end else begin // we got a grant so we can send the tag in the next cycle - if (dtlb_hit_i) + if (dtlb_hit_i) begin // we got a grant and a hit on the DTLB so we can send the tag in the next cycle NS = SEND_TAG; - else // we missed on the TLB -> wait for the translation + pop_ld_o = 1'b1; + end else // we missed on the TLB -> wait for the translation NS = ABORT_TRANSACTION; end end else begin diff --git a/src/lsu.sv b/src/lsu.sv index 15243b295..9bbc5705f 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -87,8 +87,10 @@ module lsu #( // e.g.: they keep the value in the stall case lsu_ctrl_t lsu_ctrl; - // registered address in case of a necessary stall - lsu_ctrl_t lsu_ctrl_n, lsu_ctrl_q, lsu_ctrl_nn, lsu_ctrl_qq; + logic lsu_ctrl_full; + lsu_ctrl_t lsu_ctrl_o; + logic pop_st; + logic pop_ld; // Address Generation Unit (AGU) // ------------------------------ @@ -211,6 +213,7 @@ module lsu #( store_unit store_unit_i ( .valid_i ( st_valid_i ), .lsu_ctrl_i ( lsu_ctrl ), + .pop_st_o ( pop_st ), .valid_o ( st_valid ), .ready_o ( st_ready_o ), @@ -246,6 +249,7 @@ module lsu #( load_unit load_unit_i ( .valid_i ( ld_valid_i ), .lsu_ctrl_i ( lsu_ctrl ), + .pop_ld_o ( pop_ld ), .valid_o ( ld_valid ), .ready_o ( ld_ready_o ), @@ -299,16 +303,6 @@ module lsu #( .ex_o ( lsu_exception_o ) ); - // ------------------ - // LSU Control - // ------------------ - always_comb begin : lsu_control - // the LSU is ready if both, stores and loads are ready because we do not know - // which unit we need for the instruction we get - // additionally it might be the case that we still have one instruction in the buffer, check for that - lsu_ready_o = ld_ready_o && st_ready_o && !lsu_ctrl_qq.valid; - end - // determine whether this is a load or store always_comb begin : which_op @@ -443,57 +437,35 @@ module lsu #( end end end + // ------------------ - // Input Select + // LSU Control // ------------------ - // this process selects the input based on the current state of the LSU - // it can either be feed-through from the issue stage or from the internal registers - always_comb begin : input_select - // if we are stalling use the values we saved - if (lsu_ctrl_qq.valid && ld_ready_o && st_ready_o) begin - lsu_ctrl = lsu_ctrl_qq; - end else if (lsu_ready_o) begin - lsu_ctrl = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i}; - end else begin // otherwise bypass them - lsu_ctrl = lsu_ctrl_q; - end - end - // 1st register stage - always_comb begin : register_stage - lsu_ctrl_n = lsu_ctrl_q; - lsu_ctrl_nn = lsu_ctrl_qq; - // if we are not ready it might be the case that we get another request from the issue stage - if (!lsu_ready_o && lsu_valid_i) begin - lsu_ctrl_nn = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i}; - end - // if both units are ready, invalidate the buffer flag - if (ld_ready_o && st_ready_o) begin - lsu_ctrl_nn.valid = 1'b0; - end - // get new input data - if (lsu_ready_o) begin - lsu_ctrl_n = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i}; - end + // The LSU consists of two independent block which share a common address translation block. + // The one block is the load unit, the other one is the store unit. They will signal their readiness + // with separate signals. If they are not ready the LSU control should keep the last applied signals stable. + // Furthermore it can be the case that another request for one of the two store units arrives in which case + // the LSU controll should sample it and store it for later application to the units. It does so, by storing it in a + // two element FIFO. - if (flush_i) begin - lsu_ctrl_nn.valid = 1'b0; - lsu_ctrl_n.valid = 1'b0; - end - end + // new data arrives here + lsu_ctrl_t lsu_req_i; - // registers - always_ff @(posedge clk_i or negedge rst_ni) begin - if (~rst_ni) begin - // 1st LSU stage - lsu_ctrl_q <= '0; - lsu_ctrl_qq <= '0; - end else begin - // 1st LSU stage - lsu_ctrl_q <= lsu_ctrl_n; - lsu_ctrl_qq <= lsu_ctrl_nn; - end - end + assign lsu_req_i = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i}; + lsu_bypass lsu_bypass_i ( + .lsu_req_i ( lsu_req_i ), + .lus_req_valid_i ( lsu_valid_i ), + .pop_ld_i ( pop_ld ), + .pop_st_i ( pop_st ), + + .ld_ready_i ( ld_ready_o ), + .st_ready_i ( st_ready_o), + + .lsu_ctrl_o ( lsu_ctrl ), + .ready_o ( lsu_ready_o ), + .* + ); // ------------ // Assertions // ------------ @@ -526,4 +498,98 @@ module lsu #( // else begin $error("address contains X when request is set"); $stop(); end `endif `endif -endmodule \ No newline at end of file +endmodule + +module lsu_bypass ( + input logic clk_i, + input logic rst_ni, + input logic flush_i, + + input lsu_ctrl_t lsu_req_i, + input logic lus_req_valid_i, + input logic pop_ld_i, + input logic pop_st_i, + + input logic ld_ready_i, + input logic st_ready_i, + + output lsu_ctrl_t lsu_ctrl_o, + output logic ready_o + ); + + lsu_ctrl_t [1:0] mem_n, mem_q; + logic read_pointer_n, read_pointer_q; + logic write_pointer_n, write_pointer_q; + int status_cnt_n, status_cnt_q; + + logic empty; + assign empty = (status_cnt_q == 0); + assign ready_o = empty; + + always_comb begin + automatic int status_cnt = status_cnt_q; + automatic logic write_pointer = write_pointer_q; + automatic logic read_pointer = read_pointer_q; + + mem_n = mem_q; + // we've got a valid LSU request + if (lus_req_valid_i) begin + mem_n[write_pointer_q] = lsu_req_i; + write_pointer++; + status_cnt++; + end + + if (pop_ld_i) begin + // invalidate the result + mem_n[read_pointer_q].valid = 1'b0; + read_pointer++; + status_cnt--; + end + + if (pop_st_i) begin + // invalidate the result + mem_n[read_pointer_q].valid = 1'b0; + read_pointer++; + status_cnt--; + end + + if (pop_st_i && pop_ld_i) + mem_n = '{default: 0}; + + if (flush_i) begin + status_cnt = '0; + write_pointer = '0; + read_pointer = '0; + mem_n = '{default: 0}; + end + // default assignments + read_pointer_n = read_pointer; + write_pointer_n = write_pointer; + status_cnt_n = status_cnt; + end + + // output assignment + always_comb begin : output_assignments + if (empty) begin + lsu_ctrl_o = lsu_req_i; + end else begin + lsu_ctrl_o = mem_q[read_pointer_q]; + end + end + + // registers + always_ff @(posedge clk_i or negedge rst_ni) begin + if(~rst_ni) begin + mem_q <= '{default: 0}; + status_cnt_q <= '0; + write_pointer_q <= '0; + read_pointer_q <= '0; + end else begin + mem_q <= mem_n; + status_cnt_q <= status_cnt_n; + write_pointer_q <= write_pointer_n; + read_pointer_q <= read_pointer_n; + end + end +endmodule + diff --git a/src/mmu.sv b/src/mmu.sv index 473d5c256..d7fe536ac 100644 --- a/src/mmu.sv +++ b/src/mmu.sv @@ -86,14 +86,14 @@ module mmu #( ); // instruction error // instruction error valid signal and exception, delayed one cycle - logic ierr_valid_q, ierr_valid_n; - exception fetch_ex_q, fetch_ex_n; + logic ierr_valid_q, ierr_valid_n; + exception fetch_ex_q, fetch_ex_n; - logic iaccess_err; // insufficient privilege to access this instruction page - logic daccess_err; // insufficient privilege to access this data page - logic ptw_active; // PTW is currently walking a page table - logic walking_instr; // PTW is walking because of an ITLB miss - logic ptw_error; // PTW threw an exception + logic iaccess_err; // insufficient privilege to access this instruction page + logic daccess_err; // insufficient privilege to access this data page + logic ptw_active; // PTW is currently walking a page table + logic walking_instr; // PTW is walking because of an ITLB miss + logic ptw_error; // PTW threw an exception logic update_is_2M; logic update_is_1G; @@ -101,19 +101,19 @@ module mmu #( logic [0:0] update_asid; pte_t update_content; - logic itlb_update; - logic itlb_lu_access; - pte_t itlb_content; - logic itlb_is_2M; - logic itlb_is_1G; - logic itlb_lu_hit; + logic itlb_update; + logic itlb_lu_access; + pte_t itlb_content; + logic itlb_is_2M; + logic itlb_is_1G; + logic itlb_lu_hit; - logic dtlb_update; - logic dtlb_lu_access; - pte_t dtlb_content; - logic dtlb_is_2M; - logic dtlb_is_1G; - logic dtlb_lu_hit; + logic dtlb_update; + logic dtlb_lu_access; + pte_t dtlb_content; + logic dtlb_is_2M; + logic dtlb_is_1G; + logic dtlb_lu_hit; // Assignments assign itlb_lu_access = fetch_req_i; diff --git a/src/store_unit.sv b/src/store_unit.sv index 71c28b1c9..1beb8bd09 100644 --- a/src/store_unit.sv +++ b/src/store_unit.sv @@ -26,6 +26,7 @@ module store_unit ( // store unit input port input logic valid_i, input lsu_ctrl_t lsu_ctrl_i, + output logic pop_st_o, input logic commit_i, // store unit output port output logic valid_o, @@ -79,6 +80,7 @@ module store_unit ( ready_o = 1'b1; valid_o = 1'b0; st_valid = 1'b0; + pop_st_o = 1'b0; ex_o = ex_i; trans_id_n = lsu_ctrl_i.trans_id; NS = CS; @@ -104,27 +106,31 @@ module store_unit ( end VALID_STORE: begin + ready_o = 1'b0; valid_o = 1'b1; // post this store to the store buffer if (!flush_i) st_valid = 1'b1; - // we have another request - if (valid_i) begin + pop_st_o = 1'b1; - translation_req_o = 1'b1; + // // we have another request + // if (valid_i) begin - if (!dtlb_hit_i) begin - NS = WAIT_TRANSLATION; - end + // translation_req_o = 1'b1; - if (!st_ready) begin - NS = WAIT_STORE_READY; - end - // if we do not have another request go back to idle - end else begin - NS = IDLE; - end + // if (!dtlb_hit_i) begin + // NS = WAIT_TRANSLATION; + // end + + // if (!st_ready) begin + // NS = WAIT_STORE_READY; + // end + // // if we do not have another request go back to idle + // end else begin + // NS = IDLE; + // end + NS = IDLE; end // the store queue is currently full diff --git a/tb/wave/wave_core.do b/tb/wave/wave_core.do index b2c51b2f9..782d133e8 100644 --- a/tb/wave/wave_core.do +++ b/tb/wave/wave_core.do @@ -14,18 +14,22 @@ add wave -noupdate -group issue_stage -group issue_read_operands /core_tb/dut/is add wave -noupdate -group issue_stage /core_tb/dut/issue_stage_i/* add wave -noupdate -group ex_stage -group alu /core_tb/dut/ex_stage_i/alu_i/* + +add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/* +add wave -noupdate -group ex_stage -group lsu -group lsu_bypass /core_tb/dut/ex_stage_i/lsu_i/lsu_bypass_i/* add wave -noupdate -group ex_stage -group lsu -group mmu /core_tb/dut/ex_stage_i/lsu_i/mmu_i/* add wave -noupdate -group ex_stage -group lsu -group mmu -group itlb /core_tb/dut/ex_stage_i/lsu_i/mmu_i/itlb_i/* add wave -noupdate -group ex_stage -group lsu -group mmu -group dtlb /core_tb/dut/ex_stage_i/lsu_i/mmu_i/dtlb_i/* add wave -noupdate -group ex_stage -group lsu -group mmu -group ptw /core_tb/dut/ex_stage_i/lsu_i/mmu_i/ptw_i/* -add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/* add wave -noupdate -group ex_stage -group lsu -group mem_arbiter /core_tb/dut/ex_stage_i/lsu_i/dcache_arbiter_i/* add wave -noupdate -group ex_stage -group lsu -group mem_arbiter -group arbiter_fifo /core_tb/dut/ex_stage_i/lsu_i/dcache_arbiter_i/fifo_i/* add wave -noupdate -group ex_stage -group lsu -group store_unit /core_tb/dut/ex_stage_i/lsu_i/store_unit_i/* add wave -noupdate -group ex_stage -group lsu -group store_unit -group store_queue /core_tb/dut/ex_stage_i/lsu_i/store_unit_i/store_queue_i/* add wave -noupdate -group ex_stage -group lsu -group load_unit /core_tb/dut/ex_stage_i/lsu_i/load_unit_i/* add wave -noupdate -group ex_stage -group lsu -group lsu_arbiter /core_tb/dut/ex_stage_i/lsu_i/lsu_arbiter_i/* + add wave -noupdate -group ex_stage -group branch_unit /core_tb/dut/ex_stage_i/branch_unit_i/* + add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/* add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/*