diff --git a/core/dcache.sv b/core/dcache.sv index c00a388..c5ecd8c 100755 --- a/core/dcache.sv +++ b/core/dcache.sv @@ -100,12 +100,11 @@ module dcache logic hit_allowed; logic read_hit_allowed; - logic read_hit_data_valid; logic read_hit; logic address_range_valid; - logic idle; + logic busy; logic read_miss_complete; logic store_complete; @@ -136,7 +135,6 @@ module dcache //Signal is valid for a single cycle, RAM enables are used to hold outputs in case of pipeline stalls always_ff @ (posedge clk) begin read_hit_allowed <= ls.new_request & ls.re & dcache_on & ~(amo.is_lr | amo.is_amo) & ~uncacheable; - read_hit_data_valid <= read_hit_allowed; second_cycle <= ls.new_request; tag_update <= second_cycle & dcache_on & stage2.load & ~tag_hit & ~stage2.uncacheable;//Cache enabled, read miss end @@ -144,14 +142,11 @@ module dcache assign read_hit = tag_hit & read_hit_allowed; //LR reservation, cleared on exceptions - always_ff @ (posedge clk) begin if (rst) reservation <= 0; - else if (second_cycle) - reservation <= stage2.amo.is_lr; - else if (sc_complete | clear_reservation) - reservation <= 0; + else + reservation <= (reservation & ~(sc_complete | clear_reservation)) | (second_cycle & stage2.amo.is_lr); end //////////////////////////////////////////////////// @@ -165,10 +160,10 @@ module dcache assign l1_request.amo = stage2.amo.op; always_ff @ (posedge clk) begin - if (rst | line_complete) + if (ls.new_request) word_count <= 0; - else if (l1_response.data_valid) - word_count <= word_count + 1; + else + word_count <= word_count + SCONFIG.SUB_LINE_ADDR_W'(l1_response.data_valid); end assign is_target_word = (stage2.addr[SCONFIG.SUB_LINE_ADDR_W-1:0] == word_count) | stage2.uncacheable; @@ -176,32 +171,30 @@ module dcache always_ff @ (posedge clk) begin if (rst) arb_request_r <= 0; - else if (second_cycle & ~l1_request.ack) - arb_request_r <= new_arb_request; - else if (l1_request.ack) - arb_request_r <= 0; + else + arb_request_r <= (arb_request_r | new_arb_request) & ~l1_request.ack; end assign l1_request.request = new_arb_request | arb_request_r; //////////////////////////////////////////////////// //Replacement policy (free runing one-hot cycler, i.e. pseudo random) cycler #(CONFIG.DCACHE.WAYS) replacement_policy ( - .clk (clk), - .rst (rst), - .en (1'b1), - .one_hot (replacement_way) + .clk (clk), + .rst (rst), + .en (1'b1), + .one_hot (replacement_way) ); //One-hot tag hit / update logic to binary int one_hot_to_integer #(CONFIG.DCACHE.WAYS) hit_way_conv ( - .one_hot(tag_hit_way), - .int_out(tag_hit_way_int) + .one_hot (tag_hit_way), + .int_out (tag_hit_way_int) ); one_hot_to_integer #(CONFIG.DCACHE.WAYS) update_way_conv ( - .one_hot (replacement_way), - .int_out (replacement_way_int) + .one_hot (replacement_way), + .int_out (replacement_way_int) ); @@ -252,9 +245,9 @@ module dcache endgenerate always_comb begin - if (stage2.amo.is_amo & is_target_word) + if (CONFIG.INCLUDE_AMO & stage2.amo.is_amo & is_target_word) new_line_data = amo_result; - else if (stage2.amo.is_sc) + else if (CONFIG.INCLUDE_AMO & stage2.amo.is_sc) new_line_data = stage2.data; else new_line_data = l1_response.data; @@ -278,28 +271,27 @@ module dcache assign data_bank_addr_b = {tag_update_way_int, stage2.addr[SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W-1:SCONFIG.SUB_LINE_ADDR_W], update_word_index}; end endgenerate - ddata_bank #(.LINES(DCACHE_SIZE_IN_WORDS)) data_bank ( - .clk(clk), - .addr_a(data_bank_addr_a), - .addr_b(data_bank_addr_b), - .en_a(second_cycle), - .en_b((l1_response.data_valid & ~stage2.uncacheable) | (sc_complete & sc_success)), - .be_a(write_hit_be), - .data_in_a(stage2.data), - .data_in_b(new_line_data), - .data_out_a(dbank_data_out) - ); + ddata_bank #(.LINES(DCACHE_SIZE_IN_WORDS)) + data_bank ( + .clk(clk), + .addr_a(data_bank_addr_a), + .addr_b(data_bank_addr_b), + .en_a(second_cycle), + .en_b((l1_response.data_valid & ~stage2.uncacheable) | (sc_complete & sc_success)), + .be_a(write_hit_be), + .data_in_a(stage2.data), + .data_in_b(new_line_data), + .data_out_a(dbank_data_out) + ); //////////////////////////////////////////////////// //Output + logic l1_data_valid_r; always_ff @ (posedge clk) begin - if (l1_response.data_valid & is_target_word) - miss_data <= l1_response.data; - else if (sc_complete) - miss_data <= {31'b0, sc_success}; + l1_data_valid_r <= l1_response.data_valid; + miss_data <= sc_complete ? {31'b0, sc_success} : l1_response.data; end - - assign ls.data_out = read_hit_data_valid ? dbank_data_out : miss_data; + assign ls.data_out = l1_data_valid_r ? miss_data : dbank_data_out; //////////////////////////////////////////////////// //Pipeline Advancement @@ -321,15 +313,13 @@ module dcache ls.data_valid <= (l1_response.data_valid & is_target_word) | read_hit | sc_complete; end - assign ls.ready = read_hit | store_complete | read_miss_complete | idle; + assign ls.ready = read_hit | store_complete | read_miss_complete | ~busy; always_ff @ (posedge clk) begin if (rst) - idle <= 1; - else if (ls.new_request) - idle <= 0; - else if (ls.ready) - idle <= 1; + busy <= 0; + else + busy <= (busy & ~ls.ready) | ls.new_request; end //////////////////////////////////////////////////// diff --git a/core/icache.sv b/core/icache.sv index a312673..aa2877f 100755 --- a/core/icache.sv +++ b/core/icache.sv @@ -42,6 +42,7 @@ module icache ); localparam derived_cache_config_t SCONFIG = get_derived_cache_params(CONFIG, CONFIG.ICACHE, CONFIG.ICACHE_ADDR); + localparam bit [SCONFIG.SUB_LINE_ADDR_W-1:0] END_OF_LINE_COUNT = SCONFIG.SUB_LINE_ADDR_W'(CONFIG.ICACHE.LINE_W-1); logic tag_hit; logic [CONFIG.ICACHE.WAYS-1:0] tag_hit_way; @@ -51,20 +52,24 @@ module icache logic [CONFIG.ICACHE.WAYS-1:0] tag_update_way; logic [SCONFIG.SUB_LINE_ADDR_W-1:0] word_count; + logic [SCONFIG.SUB_LINE_ADDR_W-1:0] target_word; logic is_target_word; + logic line_complete; logic [31:0] data_out [CONFIG.ICACHE.WAYS-1:0]; - logic [31:0] miss_data; - logic miss_in_progress; + logic linefill_in_progress; + logic request_in_progress; logic miss_data_valid; logic second_cycle; logic [31:0] second_cycle_addr; - logic idle; - logic memory_complete; + fifo_interface #(.DATA_WIDTH(32)) input_fifo(); + + logic new_request; + logic [31:0] new_request_addr; //////////////////////////////////////////////////// //Implementation @@ -72,18 +77,44 @@ module icache //On the second cycle of a request hit/miss determination is performed //On a miss, the memory request starts on the third cycle + assign new_request = (fetch_sub.new_request | input_fifo.valid) & ((~request_in_progress | tag_hit) & ~linefill_in_progress); + + assign input_fifo.push = fetch_sub.new_request & (~new_request | input_fifo.valid); + assign input_fifo.potential_push = input_fifo.push; + assign input_fifo.pop = new_request & input_fifo.valid; + assign input_fifo.data_in = fetch_sub.addr; + + assign new_request_addr = input_fifo.valid ? input_fifo.data_out : fetch_sub.addr; + + cva5_fifo #(.DATA_WIDTH(32), .FIFO_DEPTH(2)) + cache_input_fifo ( + .clk (clk), + .rst (rst), + .fifo (input_fifo) + ); + //////////////////////////////////////////////////// + //Ready determination + always_ff @ (posedge clk) begin + if (rst) + request_in_progress <= 0; + else + request_in_progress <= (request_in_progress & ~fetch_sub.data_valid) | new_request; + end + + assign fetch_sub.ready = ~input_fifo.full; + //////////////////////////////////////////////////// //General Control Logic always_ff @ (posedge clk) begin if (rst) second_cycle <= 0; else - second_cycle <= fetch_sub.new_request; + second_cycle <= new_request; end always_ff @(posedge clk) begin - if (fetch_sub.new_request) - second_cycle_addr <= fetch_sub.addr; + if (new_request) + second_cycle_addr <= new_request_addr; end //As request can be aborted on any cycle, only update tags if memory request is in progress @@ -96,13 +127,13 @@ module icache //Replacement policy is psuedo random cycler #(CONFIG.ICACHE.WAYS) replacement_policy ( - .clk (clk), - .rst (rst), - .en (1'b1), - .one_hot (replacement_way) + .clk (clk), + .rst (rst), + .en (1'b1), + .one_hot (replacement_way) ); always_ff @ (posedge clk) begin - if (second_cycle) + if (second_cycle & ~linefill_in_progress) tag_update_way <= replacement_way; end @@ -132,24 +163,24 @@ module icache //Miss state tracking always_ff @ (posedge clk) begin if (rst) - miss_in_progress <= 0; + linefill_in_progress <= 0; else - miss_in_progress <= l1_request.ack | (miss_in_progress & ~line_complete); + linefill_in_progress <= (linefill_in_progress & ~line_complete) | l1_request.ack; end //////////////////////////////////////////////////// //Tag banks itag_banks #(.CONFIG(CONFIG), .SCONFIG(SCONFIG)) icache_tag_banks ( - .clk(clk), - .rst(rst), //clears the read_hit_allowed flag - .stage1_addr(fetch_sub.addr), - .stage2_addr(second_cycle_addr), - .update_way(tag_update_way), - .update(tag_update), - .stage1_adv(fetch_sub.new_request & icache_on), - .tag_hit(tag_hit), - .tag_hit_way(tag_hit_way) + .clk(clk), + .rst(rst), //clears the read_hit_allowed flag + .stage1_addr(new_request_addr), + .stage2_addr(second_cycle_addr), + .update_way(tag_update_way), + .update(tag_update), + .stage1_adv(new_request & icache_on), + .tag_hit(tag_hit), + .tag_hit_way(tag_hit_way) ); //////////////////////////////////////////////////// @@ -158,9 +189,9 @@ module icache 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.addr[2 +: SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W]), + .addr_a(new_request_addr[2 +: SCONFIG.LINE_ADDR_W+SCONFIG.SUB_LINE_ADDR_W]), .addr_b({second_cycle_addr[(2+SCONFIG.SUB_LINE_ADDR_W) +: SCONFIG.LINE_ADDR_W], word_count}), - .en_a(fetch_sub.new_request), + .en_a(new_request), .en_b(tag_update_way[i] & l1_response.data_valid), .be_a('0), .be_b('1), @@ -173,61 +204,42 @@ module icache //////////////////////////////////////////////////// //Miss data path + assign target_word = second_cycle_addr[2 +: SCONFIG.SUB_LINE_ADDR_W]; + assign is_target_word = (target_word == word_count); + always_ff @ (posedge clk) begin if (rst) word_count <= 0; - else if (l1_response.data_valid) - word_count <= word_count + 1; - end - - assign is_target_word = (second_cycle_addr[2 +: SCONFIG.SUB_LINE_ADDR_W] == word_count); - - always_ff @ (posedge clk) begin - if (l1_response.data_valid & is_target_word) - miss_data <= l1_response.data; else - miss_data <= 0; + word_count <= word_count + SCONFIG.SUB_LINE_ADDR_W'(l1_response.data_valid); end - always_ff @ (posedge clk) begin - if (rst) - miss_data_valid <= 0; - else - miss_data_valid <= miss_in_progress & l1_response.data_valid & is_target_word; - end - - 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; - else - memory_complete <= line_complete; - end + assign miss_data_valid = request_in_progress & l1_response.data_valid & is_target_word; + assign line_complete = l1_response.data_valid & (word_count == END_OF_LINE_COUNT); //////////////////////////////////////////////////// //Output muxing + localparam OMUX_W = CONFIG.ICACHE.WAYS+1; + logic [OMUX_W-1:0] priority_vector; + logic [$clog2(OMUX_W)-1:0] output_sel; + logic [31:0] output_array [OMUX_W]; always_comb begin - fetch_sub.data_out = miss_data;//zero if not a miss + priority_vector[0] = miss_data_valid; + output_array[0] = l1_response.data; 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]}}); + priority_vector[i+1] = tag_hit_way[i]; + output_array[i+1] = data_out[i]; end end - + priority_encoder #(.WIDTH(OMUX_W)) + arb_encoder + ( + .priority_vector (priority_vector), + .encoded_result (output_sel) + ); + assign fetch_sub.data_out = output_array[output_sel]; assign fetch_sub.data_valid = miss_data_valid | tag_hit; - //////////////////////////////////////////////////// - //Ready determination - always_ff @ (posedge clk) begin - if (rst) - idle <= 1; - else if (fetch_sub.new_request) - idle <= 0; - else if (memory_complete | tag_hit) //read miss OR write through complete - idle <= 1; - end - - assign fetch_sub.ready = tag_hit | memory_complete | idle; - //////////////////////////////////////////////////// //End of Implementation //////////////////////////////////////////////////// @@ -239,7 +251,7 @@ module icache else $error("Spurious icache ack received from arbiter!"); icache_l1_arb_data_valid_assertion: - assert property (@(posedge clk) disable iff (rst) l1_response.data_valid |-> miss_in_progress) + assert property (@(posedge clk) disable iff (rst) l1_response.data_valid |-> linefill_in_progress) else $error("Spurious icache data received from arbiter!"); endmodule diff --git a/core/interfaces.sv b/core/interfaces.sv index 1420ef0..f90cf83 100755 --- a/core/interfaces.sv +++ b/core/interfaces.sv @@ -198,12 +198,12 @@ interface load_store_queue_interface; lsq_entry_t data_in; logic potential_push; logic push; - logic full; + logic pop; //LSQ outputs data_access_shared_inputs_t data_out; logic valid; - logic pop; + logic full; //LSQ status logic sq_empty; @@ -228,12 +228,11 @@ interface store_queue_interface; //Issue inputs lsq_entry_t data_in; logic push; - logic full; + logic pop; sq_entry_t data_out; - logic valid; - logic pop; + logic full; //SQ status logic empty; diff --git a/core/l1_arbiter.sv b/core/l1_arbiter.sv index e6cc309..c0e3544 100755 --- a/core/l1_arbiter.sv +++ b/core/l1_arbiter.sv @@ -50,7 +50,7 @@ module l1_arbiter logic [L1_CONNECTIONS-1:0] acks; logic [((L1_CONNECTIONS == 1) ? 0 : ($clog2(L1_CONNECTIONS)-1)) : 0] arb_sel; - logic push_ready; + logic fifos_full; logic request_exists; //////////////////////////////////////////////////// //Implementation @@ -69,14 +69,14 @@ module l1_arbiter assign sc_success = CONFIG.INCLUDE_AMO & l2.con_result; //Arbiter can pop address FIFO at a different rate than the data FIFO, so check that both have space. - assign push_ready = ~(l2.request_full | l2.data_full); + assign fifos_full = l2.request_full | l2.data_full; assign request_exists = |requests; - assign l2.request_push = push_ready & request_exists; + assign l2.request_push = request_exists & ~fifos_full; //////////////////////////////////////////////////// //Dcache Specific - 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_push = CONFIG.INCLUDE_DCACHE & (l1_request[L1_DCACHE_ID].request & ~l1_request[L1_DCACHE_ID].rnw & ~fifos_full); //Assumes data cache has highest priority assign l2.wr_data = l1_request[L1_DCACHE_ID].data; assign l2.inv_ack = CONFIG.DCACHE.USE_EXTERNAL_INVALIDATIONS ? l1_response[L1_DCACHE_ID].inv_ack : l2.inv_valid; @@ -86,30 +86,26 @@ module l1_arbiter //////////////////////////////////////////////////// //Interface mapping generate for (genvar i = 0; i < L1_CONNECTIONS; i++) begin : gen_l2_requests - always_comb begin - l2_requests[i].addr = l1_request[i].addr[31:2]; - l2_requests[i].rnw = l1_request[i].rnw; - l2_requests[i].be = l1_request[i].be; - l2_requests[i].is_amo = l1_request[i].is_amo; - l2_requests[i].amo_type_or_burst_size = l1_request[i].size; - l2_requests[i].sub_id = L2_SUB_ID_W'(i); - end + assign l2_requests[i] = '{ + addr : l1_request[i].addr[31:2], + rnw : l1_request[i].rnw, + be : l1_request[i].be, + is_amo : l1_request[i].is_amo, + amo_type_or_burst_size : l1_request[i].size, + sub_id : L2_SUB_ID_W'(i) + }; end endgenerate //////////////////////////////////////////////////// //Arbitration - priority_encoder - #(.WIDTH(L1_CONNECTIONS)) + priority_encoder #(.WIDTH(L1_CONNECTIONS)) arb_encoder ( .priority_vector (requests), .encoded_result (arb_sel) ); - always_comb begin - acks = '0; - acks[arb_sel] = l2.request_push; - end + assign acks = L1_CONNECTIONS'(l2.request_push) << arb_sel; assign l2.addr = l2_requests[arb_sel].addr; assign l2.rnw = l2_requests[arb_sel].rnw; @@ -120,7 +116,7 @@ module l1_arbiter generate for (genvar i = 0; i < L1_CONNECTIONS; i++) begin : gen_l1_responses assign l1_response[i].data = l2.rd_data; - assign l1_response[i].data_valid = l2.rd_data_valid && (l2.rd_sub_id == i); + assign l1_response[i].data_valid = l2.rd_data_valid & (l2.rd_sub_id == i); end endgenerate endmodule