mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 22:07:43 -04:00
983 lines
No EOL
28 KiB
Systemverilog
983 lines
No EOL
28 KiB
Systemverilog
// Copyright 2015 ETH Zurich and University of Bologna.
|
|
// Copyright and related rights are licensed under the Solderpad Hardware
|
|
// License, Version 0.51 (the “License”); you may not use this file except in
|
|
// compliance with the License. You may obtain a copy of the License at
|
|
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
|
// or agreed to in writing, software, hardware and materials distributed under
|
|
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations under the License.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Engineer: Igor Loi - igor.loi@unibo.it //
|
|
// //
|
|
// Additional contributions by: //
|
|
// Andreas Traber - atraber@iis.ee.ethz.ch //
|
|
// //
|
|
// Design Name: Prefetcher Buffer for 128 bit memory interface //
|
|
// Project Name: RI5CY //
|
|
// Language: SystemVerilog //
|
|
// //
|
|
// Description: Prefetch Buffer that caches instructions. This cuts overly //
|
|
// long critical paths to the instruction cache //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
`include "riscv_config.sv"
|
|
|
|
module riscv_prefetch_L0_buffer
|
|
#(
|
|
parameter RDATA_IN_WIDTH = 128
|
|
)
|
|
(
|
|
input logic clk,
|
|
input logic rst_n,
|
|
|
|
input logic req_i,
|
|
|
|
input logic branch_i,
|
|
input logic [31:0] addr_i,
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
input logic hwloop_i,
|
|
input logic [31:0] hwloop_target_i,
|
|
`endif // HWLP_SUPPORT
|
|
|
|
input logic ready_i,
|
|
output logic valid_o,
|
|
output logic [31:0] rdata_o,
|
|
output logic [31:0] addr_o,
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
output logic is_hwlp_o, // is set when the currently served data is from a hwloop
|
|
`endif // HWLP_SUPPORT
|
|
|
|
// goes to instruction memory / instruction cache
|
|
output logic instr_req_o,
|
|
output logic [31:0] instr_addr_o,
|
|
input logic instr_gnt_i,
|
|
input logic instr_rvalid_i,
|
|
input logic [RDATA_IN_WIDTH/32-1:0][31:0] instr_rdata_i,
|
|
|
|
// Prefetch Buffer Status
|
|
output logic busy_o
|
|
);
|
|
|
|
logic busy_L0;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
enum logic [3:0] { IDLE, BRANCHED,
|
|
HWLP_WAIT_GNT, HWLP_GRANTED, HWLP_GRANTED_WAIT, HWLP_FETCH_DONE,
|
|
NOT_VALID, NOT_VALID_GRANTED, NOT_VALID_CROSS, NOT_VALID_CROSS_GRANTED,
|
|
VALID, VALID_CROSS, VALID_GRANTED, VALID_FETCH_DONE } CS, NS;
|
|
`else
|
|
enum logic [3:0] { IDLE, BRANCHED,
|
|
NOT_VALID, NOT_VALID_GRANTED, NOT_VALID_CROSS, NOT_VALID_CROSS_GRANTED,
|
|
VALID, VALID_CROSS, VALID_GRANTED, VALID_FETCH_DONE } CS, NS;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
logic do_fetch;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
logic do_hwlp, do_hwlp_int;
|
|
`endif // HWLP_SUPPORT
|
|
logic use_last;
|
|
logic save_rdata_last;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
logic use_hwlp;
|
|
logic save_rdata_hwlp;
|
|
`endif // HWLP_SUPPORT
|
|
logic valid;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
logic hwlp_is_crossword;
|
|
`endif // HWLP_SUPPORT
|
|
logic is_crossword;
|
|
logic next_is_crossword;
|
|
logic next_valid;
|
|
logic next_upper_compressed;
|
|
logic fetch_possible;
|
|
logic upper_is_compressed;
|
|
|
|
logic [31:0] addr_q, addr_n, addr_int, addr_aligned_next, addr_real_next;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
logic is_hwlp_q, is_hwlp_n;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
logic [31:0] rdata_last_q;
|
|
|
|
logic valid_L0;
|
|
logic [RDATA_IN_WIDTH/32-1:0][31:0] rdata_L0;
|
|
logic [31:0] addr_L0;
|
|
|
|
logic fetch_valid;
|
|
logic fetch_gnt;
|
|
|
|
// prepared data for output
|
|
logic [31:0] rdata, rdata_unaligned;
|
|
|
|
logic aligned_is_compressed, unaligned_is_compressed;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
logic hwlp_aligned_is_compressed, hwlp_unaligned_is_compressed;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
|
|
prefetch_L0_buffer_L0
|
|
#(
|
|
.RDATA_IN_WIDTH ( RDATA_IN_WIDTH )
|
|
)
|
|
L0_buffer_i
|
|
(
|
|
.clk ( clk ),
|
|
.rst_n ( rst_n ),
|
|
|
|
.prefetch_i ( do_fetch ),
|
|
.prefetch_addr_i ( addr_real_next ), //addr_aligned_next
|
|
|
|
.branch_i ( branch_i ),
|
|
.branch_addr_i ( addr_i ),
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
.hwlp_i ( do_hwlp | do_hwlp_int ),
|
|
.hwlp_addr_i ( hwloop_target_i ),
|
|
`endif // HWLP_SUPPORT
|
|
|
|
.fetch_gnt_o ( fetch_gnt ),
|
|
.fetch_valid_o ( fetch_valid ),
|
|
|
|
.valid_o ( valid_L0 ),
|
|
.rdata_o ( rdata_L0 ),
|
|
.addr_o ( addr_L0 ),
|
|
|
|
.instr_req_o ( instr_req_o ),
|
|
.instr_addr_o ( instr_addr_o ),
|
|
.instr_gnt_i ( instr_gnt_i ),
|
|
.instr_rvalid_i ( instr_rvalid_i ),
|
|
.instr_rdata_i ( instr_rdata_i ),
|
|
|
|
.busy_o ( busy_L0 )
|
|
);
|
|
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
assign rdata = (use_last || use_hwlp) ? rdata_last_q : rdata_L0[addr_o[3:2]];
|
|
`else
|
|
assign rdata = use_last ? rdata_last_q : rdata_L0[addr_o[3:2]];
|
|
`endif // HWLP_SUPPORT
|
|
|
|
// the lower part of rdata_unaligned is always the higher part of rdata
|
|
assign rdata_unaligned[15:0] = rdata[31:16];
|
|
|
|
always_comb
|
|
begin
|
|
rdata_unaligned[31:16] = 'x;
|
|
|
|
case(addr_o[3:2])
|
|
2'b00: begin rdata_unaligned[31:16] = rdata_L0[1][15:0]; end
|
|
2'b01: begin rdata_unaligned[31:16] = rdata_L0[2][15:0]; end
|
|
2'b10: begin rdata_unaligned[31:16] = rdata_L0[3][15:0]; end
|
|
2'b11: begin rdata_unaligned[31:16] = rdata_L0[0][15:0]; end
|
|
endcase // addr_o
|
|
end
|
|
|
|
|
|
assign unaligned_is_compressed = rdata[17:16] != 2'b11;
|
|
assign aligned_is_compressed = rdata[1:0] != 2'b11;
|
|
assign upper_is_compressed = rdata_L0[3][17:16] != 2'b11;
|
|
assign is_crossword = (addr_o[3:1] == 3'b111) && (~upper_is_compressed);
|
|
assign next_is_crossword = ((addr_o[3:1] == 3'b110) && (aligned_is_compressed) && (~upper_is_compressed)) || ((addr_o[3:1] == 3'b101) && (~unaligned_is_compressed) && (~upper_is_compressed));
|
|
assign next_upper_compressed = ((addr_o[3:1] == 3'b110) && (aligned_is_compressed) && upper_is_compressed) || ((addr_o[3:1] == 3'b101) && (~unaligned_is_compressed) && upper_is_compressed);
|
|
assign next_valid = ((addr_o[3:2] != 2'b11) || next_upper_compressed) && (~next_is_crossword) && valid;
|
|
|
|
//addr_o[3:2] == 2'b11;// ((addr_o[3:1] == 3'b101) & (~upper_is_compressed)) | addr_o[3:2] == 2'b11; //
|
|
assign fetch_possible = (addr_o[3:2] == 2'b11 );
|
|
|
|
assign addr_aligned_next = { addr_o[31:2], 2'b00 } + 32'h4;
|
|
assign addr_real_next = (next_is_crossword) ? { addr_o[31:4], 4'b0000 } + 32'h16 : { addr_o[31:2], 2'b00 } + 32'h4;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
assign hwlp_unaligned_is_compressed = rdata_L0[2][17:16] != 2'b11;
|
|
assign hwlp_aligned_is_compressed = rdata_L0[3][1:0] != 2'b11;
|
|
assign hwlp_is_crossword = (hwloop_target_i[3:1] == 3'b111) && (~upper_is_compressed);
|
|
`endif // HWLP_SUPPORT
|
|
|
|
always_comb
|
|
begin
|
|
addr_int = addr_o;
|
|
|
|
// advance address when pipeline is unstalled
|
|
if (ready_i) begin
|
|
|
|
if (addr_o[1]) begin
|
|
// unaligned case
|
|
// always move to next entry in the FIFO
|
|
|
|
if (unaligned_is_compressed) begin
|
|
addr_int = { addr_aligned_next[31:2], 2'b00};
|
|
end else begin
|
|
addr_int = { addr_aligned_next[31:2], 2'b10};
|
|
end
|
|
|
|
end else begin
|
|
// aligned case
|
|
|
|
if (aligned_is_compressed) begin
|
|
// just increase address, do not move to next entry in the FIFO
|
|
addr_int = { addr_o[31:2], 2'b10 };
|
|
end else begin
|
|
// move to next entry in the FIFO
|
|
addr_int = { addr_aligned_next[31:2], 2'b00 };
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
always_comb
|
|
begin
|
|
NS = CS;
|
|
do_fetch = 1'b0;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = 1'b0;
|
|
do_hwlp_int = 1'b0;
|
|
`endif // HWLP_SUPPORT
|
|
use_last = 1'b0;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
use_hwlp = 1'b0;
|
|
`endif // HWLP_SUPPORT
|
|
save_rdata_last = 1'b0;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
save_rdata_hwlp = 1'b0;
|
|
`endif // HWLP_SUPPORT
|
|
valid = 1'b0;
|
|
addr_n = addr_int;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
is_hwlp_n = is_hwlp_q;
|
|
|
|
if (ready_i)
|
|
is_hwlp_n = 1'b0;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
case (CS)
|
|
IDLE: begin
|
|
// wait here for something to happen
|
|
end
|
|
|
|
BRANCHED: begin
|
|
valid = 1'b0;
|
|
do_fetch = fetch_possible;
|
|
|
|
if (fetch_valid && (~is_crossword))
|
|
valid = 1'b1;
|
|
|
|
if (ready_i) begin
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
if (hwloop_i) begin
|
|
addr_n = addr_o; // keep the old address for now
|
|
NS = HWLP_WAIT_GNT;
|
|
end
|
|
else begin
|
|
`else
|
|
begin
|
|
`endif // HWLP_SUPPORT
|
|
|
|
if (next_valid) begin
|
|
if (fetch_gnt) begin
|
|
save_rdata_last = 1'b1;
|
|
NS = VALID_GRANTED;
|
|
end else
|
|
NS = VALID;
|
|
end else if (next_is_crossword) begin
|
|
if (fetch_gnt) begin
|
|
save_rdata_last = 1'b1;
|
|
NS = NOT_VALID_CROSS_GRANTED;
|
|
end else begin
|
|
NS = NOT_VALID_CROSS;
|
|
end
|
|
end else begin
|
|
if (fetch_gnt)
|
|
NS = NOT_VALID_GRANTED;
|
|
else
|
|
NS = NOT_VALID;
|
|
end
|
|
end
|
|
end else begin
|
|
if (fetch_valid) begin
|
|
if (is_crossword) begin
|
|
save_rdata_last = 1'b1;
|
|
if (fetch_gnt)
|
|
NS = NOT_VALID_CROSS_GRANTED;
|
|
else
|
|
NS = NOT_VALID_CROSS;
|
|
end else begin
|
|
if (fetch_gnt) begin
|
|
save_rdata_last = 1'b1;
|
|
NS = VALID_GRANTED;
|
|
end else
|
|
NS = VALID;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
NOT_VALID: begin
|
|
do_fetch = 1'b1;
|
|
|
|
if (fetch_gnt)
|
|
NS = NOT_VALID_GRANTED;
|
|
end
|
|
|
|
NOT_VALID_GRANTED: begin
|
|
valid = fetch_valid;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = hwloop_i;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
if (fetch_valid)
|
|
NS = VALID;
|
|
end
|
|
|
|
NOT_VALID_CROSS:
|
|
begin
|
|
do_fetch = 1'b1;
|
|
|
|
if (fetch_gnt)
|
|
begin
|
|
save_rdata_last = 1'b1;
|
|
NS = NOT_VALID_CROSS_GRANTED;
|
|
end
|
|
end
|
|
|
|
NOT_VALID_CROSS_GRANTED:
|
|
begin
|
|
valid = fetch_valid;
|
|
use_last = 1'b1;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = hwloop_i;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
if (fetch_valid)
|
|
begin
|
|
if (ready_i)
|
|
NS = VALID;
|
|
else
|
|
NS = VALID_CROSS;
|
|
end
|
|
end
|
|
|
|
VALID: begin
|
|
valid = 1'b1;
|
|
do_fetch = fetch_possible; // fetch_possible = addr_o[3:2] == 2'b11;//
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = hwloop_i;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
if (ready_i)
|
|
begin
|
|
if (next_is_crossword)
|
|
begin
|
|
do_fetch = 1'b1;
|
|
|
|
if (fetch_gnt)
|
|
begin
|
|
save_rdata_last = 1'b1;
|
|
NS = NOT_VALID_CROSS_GRANTED;
|
|
end
|
|
else // not fetching
|
|
begin
|
|
NS = NOT_VALID_CROSS;
|
|
end
|
|
end
|
|
else // Next is not crossword
|
|
if (~next_valid)
|
|
begin
|
|
if (fetch_gnt)
|
|
NS = NOT_VALID_GRANTED;
|
|
else
|
|
NS = NOT_VALID;
|
|
end
|
|
else // Next is valid
|
|
begin
|
|
if (fetch_gnt)
|
|
begin
|
|
if (next_upper_compressed)
|
|
begin
|
|
save_rdata_last = 1'b1;
|
|
NS = VALID_GRANTED;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else // NOT ready
|
|
begin
|
|
if (fetch_gnt)
|
|
begin
|
|
save_rdata_last = 1'b1;
|
|
NS = VALID_GRANTED;
|
|
end
|
|
end
|
|
end
|
|
|
|
VALID_CROSS: begin
|
|
valid = 1'b1;
|
|
use_last = 1'b1;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = hwloop_i;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
if (ready_i)
|
|
NS = VALID;
|
|
end
|
|
|
|
VALID_GRANTED: begin
|
|
valid = 1'b1;
|
|
use_last = 1'b1;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = hwloop_i;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
|
|
if (ready_i) begin
|
|
if (fetch_valid) begin
|
|
if (next_is_crossword)
|
|
NS = VALID_CROSS;
|
|
else if(next_upper_compressed)
|
|
NS = VALID_FETCH_DONE;
|
|
else
|
|
NS = VALID;
|
|
end else begin
|
|
if (next_is_crossword)
|
|
NS = NOT_VALID_CROSS_GRANTED;
|
|
else if (next_upper_compressed)
|
|
NS = VALID_GRANTED;
|
|
else
|
|
NS = NOT_VALID_GRANTED;
|
|
end
|
|
end else begin
|
|
if (fetch_valid)
|
|
NS = VALID_FETCH_DONE;
|
|
end
|
|
end
|
|
|
|
VALID_FETCH_DONE: begin
|
|
valid = 1'b1;
|
|
use_last = 1'b1;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
do_hwlp = hwloop_i;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
if (ready_i) begin
|
|
if (next_is_crossword)
|
|
NS = VALID_CROSS;
|
|
else if (next_upper_compressed)
|
|
NS = VALID_FETCH_DONE;
|
|
else
|
|
NS = VALID;
|
|
end
|
|
end
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
HWLP_WAIT_GNT: begin
|
|
do_hwlp_int = 1'b1;
|
|
|
|
if (fetch_gnt) begin
|
|
is_hwlp_n = 1'b1;
|
|
addr_n = hwloop_target_i;
|
|
NS = BRANCHED;
|
|
end
|
|
end
|
|
|
|
HWLP_GRANTED: begin
|
|
valid = 1'b1;
|
|
use_hwlp = 1'b1;
|
|
|
|
if (ready_i) begin
|
|
addr_n = hwloop_target_i;
|
|
|
|
if (fetch_valid) begin
|
|
is_hwlp_n = 1'b1;
|
|
|
|
if (hwlp_is_crossword) begin
|
|
NS = NOT_VALID_CROSS;
|
|
end else begin
|
|
NS = VALID;
|
|
end
|
|
end else begin
|
|
NS = HWLP_GRANTED_WAIT;
|
|
end
|
|
end else begin
|
|
if (fetch_valid)
|
|
NS = HWLP_FETCH_DONE;
|
|
end
|
|
end
|
|
|
|
HWLP_GRANTED_WAIT: begin
|
|
use_hwlp = 1'b1;
|
|
|
|
if (fetch_valid) begin
|
|
is_hwlp_n = 1'b1;
|
|
|
|
if (hwlp_is_crossword) begin
|
|
NS = NOT_VALID_CROSS;
|
|
end else begin
|
|
NS = VALID;
|
|
end
|
|
end
|
|
end
|
|
|
|
HWLP_FETCH_DONE: begin
|
|
valid = 1'b1;
|
|
use_hwlp = 1'b1;
|
|
|
|
if (ready_i) begin
|
|
is_hwlp_n = 1'b1;
|
|
addr_n = hwloop_target_i;
|
|
|
|
if (hwlp_is_crossword) begin
|
|
NS = NOT_VALID_CROSS;
|
|
end else begin
|
|
NS = VALID;
|
|
end
|
|
end
|
|
end
|
|
`endif // HWLP_SUPPORT
|
|
endcase
|
|
|
|
// branches always have priority
|
|
if (branch_i) begin
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
is_hwlp_n = 1'b0;
|
|
`endif // HWLP_SUPPORT
|
|
addr_n = addr_i;
|
|
NS = BRANCHED;
|
|
|
|
end
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
else if (hwloop_i) begin
|
|
if (do_hwlp) begin
|
|
if (ready_i) begin
|
|
if (fetch_gnt) begin
|
|
is_hwlp_n = 1'b1;
|
|
addr_n = hwloop_target_i;
|
|
NS = BRANCHED;
|
|
end else begin
|
|
addr_n = addr_o; // keep the old address for now
|
|
NS = HWLP_WAIT_GNT;
|
|
end
|
|
end else begin
|
|
if (fetch_gnt) begin
|
|
save_rdata_hwlp = 1'b1;
|
|
NS = HWLP_GRANTED;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
`endif // HWLP_SUPPORT
|
|
end
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// registers
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
always_ff @(posedge clk, negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
begin
|
|
addr_q <= '0;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
is_hwlp_q <= 1'b0;
|
|
`endif // HWLP_SUPPORT
|
|
CS <= IDLE;
|
|
rdata_last_q <= '0;
|
|
end
|
|
else
|
|
begin
|
|
addr_q <= addr_n;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
is_hwlp_q <= is_hwlp_n;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
CS <= NS;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
if (save_rdata_hwlp)
|
|
rdata_last_q <= rdata_o;
|
|
else if(save_rdata_last)
|
|
`else
|
|
if(save_rdata_last)
|
|
`endif // HWLP_SUPPORT
|
|
begin
|
|
//rdata_last_q <= rdata_L0[3];
|
|
if(ready_i)
|
|
begin
|
|
rdata_last_q <= rdata_L0[3];//rdata;
|
|
end
|
|
else
|
|
begin
|
|
rdata_last_q <= rdata;//rdata;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// output ports
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
assign rdata_o = ((~addr_o[1]) || use_hwlp) ? rdata : rdata_unaligned;
|
|
`else
|
|
assign rdata_o = (~addr_o[1]) ? rdata : rdata_unaligned;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
assign valid_o = valid & (~branch_i);
|
|
|
|
assign addr_o = addr_q;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
assign is_hwlp_o = is_hwlp_q & (~branch_i);
|
|
`endif // HWLP_SUPPORT
|
|
|
|
assign busy_o = busy_L0;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Assertions
|
|
//----------------------------------------------------------------------------
|
|
|
|
// there should never be a ready_i without valid_o
|
|
assert property (
|
|
@(posedge clk) (ready_i) |-> (valid_o) ) else $warning("IF Stage is ready without prefetcher having valid data");
|
|
|
|
// never is_crossword while also next_is_crossword
|
|
assert property (
|
|
@(posedge clk) (next_is_crossword) |-> (~is_crossword) ) else $warning("Cannot have two crossword accesses back-to-back");
|
|
assert property (
|
|
@(posedge clk) (is_crossword) |-> (~next_is_crossword) ) else $warning("Cannot have two crossword accesses back-to-back");
|
|
|
|
endmodule // prefetch_L0_buffer
|
|
|
|
|
|
module prefetch_L0_buffer_L0
|
|
#(
|
|
parameter RDATA_IN_WIDTH = 128
|
|
)
|
|
(
|
|
input logic clk,
|
|
input logic rst_n,
|
|
|
|
input logic prefetch_i,
|
|
input logic [31:0] prefetch_addr_i,
|
|
|
|
input logic branch_i,
|
|
input logic [31:0] branch_addr_i,
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
input logic hwlp_i,
|
|
input logic [31:0] hwlp_addr_i,
|
|
`endif // HWLP_SUPPORT
|
|
|
|
output logic fetch_gnt_o,
|
|
output logic fetch_valid_o,
|
|
|
|
output logic valid_o,
|
|
output logic [RDATA_IN_WIDTH/32-1:0][31:0] rdata_o,
|
|
output logic [31:0] addr_o,
|
|
|
|
// goes to instruction memory / instruction cache
|
|
output logic instr_req_o,
|
|
output logic [31:0] instr_addr_o,
|
|
input logic instr_gnt_i,
|
|
input logic instr_rvalid_i,
|
|
input logic [RDATA_IN_WIDTH/32-1:0][31:0] instr_rdata_i,
|
|
|
|
output logic busy_o
|
|
);
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
enum logic [2:0] { EMPTY, VALID_L0, WAIT_GNT, WAIT_RVALID, ABORTED_BRANCH, WAIT_HWLOOP } CS, NS;
|
|
`else
|
|
enum logic [2:0] { EMPTY, VALID_L0, WAIT_GNT, WAIT_RVALID, ABORTED_BRANCH} CS, NS;
|
|
`endif // HWLP_SUPPORT
|
|
|
|
logic [3:0][31:0] L0_buffer;
|
|
logic [31:0] addr_q, instr_addr_int;
|
|
logic valid;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// FSM
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
always_comb
|
|
begin
|
|
NS = CS;
|
|
valid = 1'b0;
|
|
instr_req_o = 1'b0;
|
|
instr_addr_int = 'x;
|
|
fetch_valid_o = 1'b0;
|
|
|
|
case(CS)
|
|
|
|
// wait for the first branch request before fetching any instructions
|
|
EMPTY:
|
|
begin
|
|
if (branch_i)
|
|
instr_addr_int = branch_addr_i;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
else if (hwlp_i)
|
|
instr_addr_int = hwlp_addr_i;
|
|
`endif // HWLP_SUPPORT
|
|
else
|
|
instr_addr_int = prefetch_addr_i;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
if (branch_i | hwlp_i | prefetch_i) // make the request to icache
|
|
`else
|
|
if (branch_i | prefetch_i) // make the request to icache
|
|
`endif // HWLP_SUPPORT
|
|
begin
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end
|
|
end //~EMPTY
|
|
|
|
WAIT_GNT:
|
|
begin
|
|
if (branch_i)
|
|
instr_addr_int = branch_addr_i;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
else if (hwlp_i)
|
|
instr_addr_int = hwlp_addr_i;
|
|
`endif // HWLP_SUPPORT
|
|
else
|
|
instr_addr_int = addr_q;
|
|
|
|
if (branch_i)
|
|
begin
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end
|
|
else
|
|
begin
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end
|
|
end //~WAIT_GNT
|
|
|
|
|
|
WAIT_RVALID:
|
|
begin
|
|
valid = instr_rvalid_i;
|
|
|
|
if (branch_i)
|
|
instr_addr_int = branch_addr_i;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
else if (hwlp_i)
|
|
instr_addr_int = hwlp_addr_i;
|
|
`endif // HWLP_SUPPORT
|
|
else
|
|
instr_addr_int = prefetch_addr_i;
|
|
|
|
if (branch_i)
|
|
begin
|
|
if (instr_rvalid_i)
|
|
begin
|
|
fetch_valid_o = 1'b1;
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end else begin
|
|
NS = ABORTED_BRANCH; // TODO: THIS STATE IS IDENTICAL WITH THIS ONE
|
|
end
|
|
|
|
end
|
|
else
|
|
begin
|
|
|
|
if (instr_rvalid_i)
|
|
begin
|
|
fetch_valid_o = 1'b1;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
if (prefetch_i | hwlp_i) // we are receiving the last packet, then prefetch the next one
|
|
`else
|
|
if (prefetch_i) // we are receiving the last packet, then prefetch the next one
|
|
`endif // HWLP_SUPPORT
|
|
begin
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end
|
|
else // not the last chunk
|
|
begin
|
|
NS = VALID_L0;
|
|
end
|
|
end
|
|
end
|
|
end //~WAIT_RVALID
|
|
|
|
VALID_L0:
|
|
begin
|
|
valid = 1'b1;
|
|
|
|
if (branch_i)
|
|
instr_addr_int = branch_addr_i;
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
else if (hwlp_i)
|
|
instr_addr_int = hwlp_addr_i;
|
|
`endif // HWLP_SUPPORT
|
|
else
|
|
instr_addr_int = prefetch_addr_i;
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
if (branch_i | hwlp_i | prefetch_i)
|
|
`else
|
|
if (branch_i | prefetch_i)
|
|
`endif // HWLP_SUPPORT
|
|
begin
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end
|
|
end //~VALID_L0
|
|
|
|
ABORTED_BRANCH:
|
|
begin
|
|
|
|
// prepare address even if we don't need it
|
|
// this removes the dependency for instr_addr_o on instr_rvalid_i
|
|
if (branch_i)
|
|
instr_addr_int = branch_addr_i;
|
|
else
|
|
instr_addr_int = addr_q;
|
|
|
|
if (instr_rvalid_i)
|
|
begin
|
|
instr_req_o = 1'b1;
|
|
|
|
if (instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end
|
|
end //~ABORTED_BRANCH
|
|
|
|
default:
|
|
begin
|
|
NS = EMPTY;
|
|
end
|
|
endcase //~CS
|
|
end
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// registers
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
always_ff @(posedge clk, negedge rst_n)
|
|
begin
|
|
if (~rst_n)
|
|
begin
|
|
CS <= EMPTY;
|
|
L0_buffer <= '0;
|
|
addr_q <= '0;
|
|
end
|
|
else
|
|
begin
|
|
CS <= NS;
|
|
|
|
if (instr_rvalid_i)
|
|
begin
|
|
L0_buffer <= instr_rdata_i;
|
|
end
|
|
|
|
// CONFIG_REGION: HWLP_SUPPORT
|
|
`ifdef HWLP_SUPPORT
|
|
if (branch_i | hwlp_i | prefetch_i)
|
|
`else
|
|
if (branch_i | prefetch_i)
|
|
`endif // HWLP_SUPPORT
|
|
addr_q <= instr_addr_int;
|
|
end
|
|
end
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// output ports
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
assign instr_addr_o = { instr_addr_int[31:4], 4'b0000 };
|
|
|
|
assign rdata_o = (instr_rvalid_i) ? instr_rdata_i : L0_buffer;
|
|
assign addr_o = addr_q;
|
|
|
|
assign valid_o = valid & (~branch_i);
|
|
|
|
assign busy_o = (CS != EMPTY) && (CS != VALID_L0) || instr_req_o;
|
|
|
|
assign fetch_gnt_o = instr_gnt_i;
|
|
|
|
endmodule |