diff --git a/include/ariane_pkg.svh b/include/ariane_pkg.svh index 56932453b..6a23a258c 100644 --- a/include/ariane_pkg.svh +++ b/include/ariane_pkg.svh @@ -1,3 +1,4 @@ + /* File: ariane_pkg.svh * Author: Florian Zaruba * Date: 8.4.2017 @@ -19,6 +20,9 @@ package ariane_pkg; // to uniquely identify the entry in the scoreboard localparam NR_WB_PORTS = 4; localparam ASID_WIDTH = 1; + localparam BTB_ENTRIES = 64; + localparam BITS_SATURATION_COUNTER = 2; + localparam logic [63:0] ISA_CODE = (1 << 2) // C - Compressed extension | (1 << 8) // I - RV32I/64I/128I base ISA | (1 << 12) // M - Integer Multiply/Divide extension diff --git a/src/lsu.sv b/src/lsu.sv index 9bbc5705f..c89171041 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -441,29 +441,22 @@ module lsu #( // ------------------ // LSU Control // ------------------ - // 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. - // new data arrives here lsu_ctrl_t lsu_req_i; 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 ), + .lsu_req_i ( lsu_req_i ), .lus_req_valid_i ( lsu_valid_i ), - .pop_ld_i ( pop_ld ), - .pop_st_i ( pop_st ), + .pop_ld_i ( pop_ld ), + .pop_st_i ( pop_st ), - .ld_ready_i ( ld_ready_o ), - .st_ready_i ( st_ready_o), + .ld_ready_i ( ld_ready_o ), + .st_ready_i ( st_ready_o ), - .lsu_ctrl_o ( lsu_ctrl ), - .ready_o ( lsu_ready_o ), + .lsu_ctrl_o ( lsu_ctrl ), + .ready_o ( lsu_ready_o ), .* ); // ------------ @@ -500,6 +493,15 @@ module lsu #( `endif endmodule +// ------------------ +// LSU Control +// ------------------ +// 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. module lsu_bypass ( input logic clk_i, input logic rst_ni, diff --git a/src/pcgen.sv b/src/pcgen.sv index aa4858b2e..5fb12d406 100644 --- a/src/pcgen.sv +++ b/src/pcgen.sv @@ -49,8 +49,8 @@ module pcgen ( assign fetch_address_o = npc_q; btb #( - .NR_ENTRIES(64), - .BITS_SATURATION_COUNTER(2) + .NR_ENTRIES ( BTB_ENTRIES ), + .BITS_SATURATION_COUNTER ( BITS_SATURATION_COUNTER ) ) btb_i ( diff --git a/src/store_queue.sv b/src/store_queue.sv index e4b92812a..27266edcd 100644 --- a/src/store_queue.sv +++ b/src/store_queue.sv @@ -25,10 +25,8 @@ module store_queue ( // otherwise we will run in a deadlock with the memory arbiter output logic no_st_pending_o, // non-speculative queue is empty (e.g.: everything is committed to the memory hierarchy) - output logic [63:0] paddr_o, // physical address of the valid store - output logic [63:0] data_o, // data at the given address - output logic valid_o, // committed data is valid - output logic [7:0] be_o, // byte enable set + input logic [11:0] page_offset_i, + output logic page_offset_matches_o, input logic commit_i, // commit the instruction which was placed there most recently output logic ready_o, // the store queue is ready to accept a new request @@ -74,12 +72,6 @@ module store_queue ( logic is_speculative; // set if the entry isn't committed yet } commit_queue_n, commit_queue_q; - // we can directly output the commit entry since we have just one element in the "queue" - assign paddr_o = commit_queue_q.address; - assign data_o = commit_queue_q.data; - assign be_o = commit_queue_q.be; - assign valid_o = commit_queue_q.valid; - // those signals can directly be output to the memory assign address_index_o = commit_queue_q.address[11:0]; // if we got a new request we already saved the tag from the previous cycle @@ -153,6 +145,34 @@ module store_queue ( end + // ------------------ + // Address Checker + // ------------------ + // The load should return the data stored by the most recent store to the + // same physical address. The most direct way to implement this is to + // maintain physical addresses in the store buffer. + + // Of course, there are other micro-architectural techniques to accomplish + // the same thing: you can interlock and wait for the store buffer to + // drain if the load VA matches any store VA modulo the page size (i.e. + // bits 11:0). As a special case, it is correct to bypass if the full VA + // matches, and no younger stores' VAs match in bits 11:0. + // + // checks if the requested load is in the store buffer + // page offsets are virtually and physically the same + always_comb begin : address_checker + page_offset_matches_o = 1'b0; + // check if the LSBs are identical and the entry is valid + if ((page_offset_i[11:3] == commit_queue_q.address[11:3]) && commit_queue_q.valid) begin + page_offset_matches_o = 1'b1; + end + + if ((page_offset_i[11:3] == paddr_i[11:3]) && valid_i) begin + page_offset_matches_o = 1'b1; + end + end + + // registers always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ if(~rst_ni) begin diff --git a/src/store_unit.sv b/src/store_unit.sv index 1beb8bd09..222d9cf6e 100644 --- a/src/store_unit.sv +++ b/src/store_unit.sv @@ -59,9 +59,6 @@ module store_unit ( enum logic [1:0] {IDLE, VALID_STORE, WAIT_TRANSLATION, WAIT_STORE_READY} NS, CS; - logic [63:0] st_buffer_paddr; // physical address for store - logic [63:0] st_data; // aligned data to store buffer - logic st_buffer_valid; // store buffer control signals logic st_ready; logic st_valid; @@ -199,10 +196,6 @@ module store_unit ( .data_i ( st_data_q ), .be_i ( st_be_q ), // store buffer out - .paddr_o ( st_buffer_paddr ), - .data_o ( ), - .valid_o ( st_buffer_valid ), - .be_o ( ), .ready_o ( st_ready ), .* ); @@ -222,31 +215,5 @@ module store_unit ( trans_id_q <= trans_id_n; end end - // ------------------ - // Address Checker - // ------------------ - // The load should return the data stored by the most recent store to the - // same physical address. The most direct way to implement this is to - // maintain physical addresses in the store buffer. - - // Of course, there are other micro-architectural techniques to accomplish - // the same thing: you can interlock and wait for the store buffer to - // drain if the load VA matches any store VA modulo the page size (i.e. - // bits 11:0). As a special case, it is correct to bypass if the full VA - // matches, and no younger stores' VAs match in bits 11:0. - // - // checks if the requested load is in the store buffer - // page offsets are virtually and physically the same - always_comb begin : address_checker - page_offset_matches_o = 1'b0; - // check if the LSBs are identical and the entry is valid - if ((lsu_ctrl_i.vaddr[11:3] == st_buffer_paddr[11:3]) && st_buffer_valid) begin - page_offset_matches_o = 1'b1; - end - - if ((lsu_ctrl_i.vaddr[11:3] == paddr_i[11:3]) && (CS == VALID_STORE)) begin - page_offset_matches_o = 1'b1; - end - end endmodule \ No newline at end of file