mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 05:47:36 -04:00
252 lines
7.3 KiB
Systemverilog
252 lines
7.3 KiB
Systemverilog
// Copyright 2017 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: Andreas Traber - atraber@iis.ee.ethz.ch //
|
|
// //
|
|
// Design Name: Prefetcher Buffer for 32 bit memory interface //
|
|
// Project Name: zero-riscy //
|
|
// Language: SystemVerilog //
|
|
// //
|
|
// Description: Prefetch Buffer that caches instructions. This cuts overly //
|
|
// long critical paths to the instruction cache //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
module zeroriscy_prefetch_buffer
|
|
(
|
|
input logic clk,
|
|
input logic rst_n,
|
|
|
|
input logic req_i,
|
|
|
|
input logic branch_i,
|
|
input logic [31:0] addr_i,
|
|
|
|
|
|
input logic ready_i,
|
|
output logic valid_o,
|
|
output logic [31:0] rdata_o,
|
|
output logic [31:0] addr_o,
|
|
|
|
|
|
// goes to instruction memory / instruction cache
|
|
output logic instr_req_o,
|
|
input logic instr_gnt_i,
|
|
output logic [31:0] instr_addr_o,
|
|
input logic [31:0] instr_rdata_i,
|
|
input logic instr_rvalid_i,
|
|
|
|
// Prefetch Buffer Status
|
|
output logic busy_o
|
|
);
|
|
|
|
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED } CS, NS;
|
|
|
|
logic [31:0] instr_addr_q, fetch_addr;
|
|
logic addr_valid;
|
|
|
|
logic fifo_valid;
|
|
logic fifo_ready;
|
|
logic fifo_clear;
|
|
|
|
logic valid_stored;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// prefetch buffer status
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
assign busy_o = (CS != IDLE) || instr_req_o;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// fetch fifo
|
|
// consumes addresses and rdata
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
zeroriscy_fetch_fifo fifo_i
|
|
(
|
|
.clk ( clk ),
|
|
.rst_n ( rst_n ),
|
|
|
|
.clear_i ( fifo_clear ),
|
|
|
|
.in_addr_i ( instr_addr_q ),
|
|
.in_rdata_i ( instr_rdata_i ),
|
|
.in_valid_i ( fifo_valid ),
|
|
.in_ready_o ( fifo_ready ),
|
|
|
|
|
|
.out_valid_o ( valid_o ),
|
|
.out_ready_i ( ready_i ),
|
|
.out_rdata_o ( rdata_o ),
|
|
.out_addr_o ( addr_o ),
|
|
|
|
.out_valid_stored_o ( valid_stored )
|
|
);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// fetch addr
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
assign fetch_addr = {instr_addr_q[31:2], 2'b00} + 32'd4;
|
|
|
|
always_comb
|
|
begin
|
|
fifo_clear = branch_i;
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// instruction fetch FSM
|
|
// deals with instruction memory / instruction cache
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
always_comb
|
|
begin
|
|
instr_req_o = 1'b0;
|
|
instr_addr_o = fetch_addr;
|
|
fifo_valid = 1'b0;
|
|
addr_valid = 1'b0;
|
|
NS = CS;
|
|
|
|
unique case(CS)
|
|
// default state, not waiting for requested data
|
|
IDLE:
|
|
begin
|
|
instr_addr_o = fetch_addr;
|
|
instr_req_o = 1'b0;
|
|
|
|
if (branch_i)
|
|
instr_addr_o = addr_i;
|
|
|
|
if (req_i & (fifo_ready | branch_i )) begin
|
|
instr_req_o = 1'b1;
|
|
addr_valid = 1'b1;
|
|
|
|
|
|
if(instr_gnt_i) //~> granted request
|
|
NS = WAIT_RVALID;
|
|
else begin //~> got a request but no grant
|
|
NS = WAIT_GNT;
|
|
end
|
|
end
|
|
end // case: IDLE
|
|
|
|
// we sent a request but did not yet get a grant
|
|
WAIT_GNT:
|
|
begin
|
|
instr_addr_o = instr_addr_q;
|
|
instr_req_o = 1'b1;
|
|
|
|
if (branch_i) begin
|
|
instr_addr_o = addr_i;
|
|
addr_valid = 1'b1;
|
|
end
|
|
|
|
if(instr_gnt_i)
|
|
NS = WAIT_RVALID;
|
|
else
|
|
NS = WAIT_GNT;
|
|
end // case: WAIT_GNT
|
|
|
|
// we wait for rvalid, after that we are ready to serve a new request
|
|
WAIT_RVALID: begin
|
|
instr_addr_o = fetch_addr;
|
|
|
|
if (branch_i)
|
|
instr_addr_o = addr_i;
|
|
|
|
|
|
if (req_i & (fifo_ready | branch_i)) begin
|
|
// prepare for next request
|
|
|
|
if (instr_rvalid_i) begin
|
|
instr_req_o = 1'b1;
|
|
fifo_valid = 1'b1;
|
|
addr_valid = 1'b1;
|
|
|
|
|
|
if (instr_gnt_i) begin
|
|
NS = WAIT_RVALID;
|
|
end else begin
|
|
NS = WAIT_GNT;
|
|
end
|
|
end else begin
|
|
// we are requested to abort our current request
|
|
// we didn't get an rvalid yet, so wait for it
|
|
if (branch_i) begin
|
|
addr_valid = 1'b1;
|
|
NS = WAIT_ABORTED;
|
|
end
|
|
end
|
|
end else begin
|
|
// just wait for rvalid and go back to IDLE, no new request
|
|
|
|
if (instr_rvalid_i) begin
|
|
fifo_valid = 1'b1;
|
|
NS = IDLE;
|
|
end
|
|
end
|
|
end // case: WAIT_RVALID
|
|
|
|
// our last request was aborted, but we didn't yet get a rvalid and
|
|
// there was no new request sent yet
|
|
// we assume that req_i is set to high
|
|
WAIT_ABORTED: begin
|
|
instr_addr_o = instr_addr_q;
|
|
|
|
if (branch_i) begin
|
|
instr_addr_o = addr_i;
|
|
addr_valid = 1'b1;
|
|
end
|
|
|
|
if (instr_rvalid_i) begin
|
|
instr_req_o = 1'b1;
|
|
// no need to send address, already done in WAIT_RVALID
|
|
|
|
if (instr_gnt_i) begin
|
|
NS = WAIT_RVALID;
|
|
end else begin
|
|
NS = WAIT_GNT;
|
|
end
|
|
end
|
|
end
|
|
|
|
default:
|
|
begin
|
|
NS = IDLE;
|
|
instr_req_o = 1'b0;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// registers
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
always_ff @(posedge clk, negedge rst_n)
|
|
begin
|
|
if(rst_n == 1'b0)
|
|
begin
|
|
CS <= IDLE;
|
|
instr_addr_q <= '0;
|
|
end
|
|
else
|
|
begin
|
|
CS <= NS;
|
|
|
|
if (addr_valid) begin
|
|
instr_addr_q <= instr_addr_o;
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|