mirror of
https://github.com/lowRISC/ibex.git
synced 2025-06-27 17:00:41 -04:00
This change has been informed by advice from the lowRISC legal committee. The Solderpad 0.51 license states "the Licensor permits any Work licensed under this License, at the option of the Licensee, to be treated as licensed under the Apache License Version 2.0". We use this freedom to convert license markings to Apache 2.0. This commit ensures that we retain all authorship and copyright attribution information.
247 lines
6.8 KiB
Systemverilog
247 lines
6.8 KiB
Systemverilog
// Copyright lowRISC contributors.
|
|
// Copyright 2018 ETH Zurich and University of Bologna.
|
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch //
|
|
// //
|
|
// Design Name: Prefetcher Buffer for 32 bit memory interface //
|
|
// Project Name: ibex //
|
|
// Language: SystemVerilog //
|
|
// //
|
|
// Description: Prefetch Buffer that caches instructions. This cuts overly //
|
|
// long critical paths to the instruction cache //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
module ibex_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
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
ibex_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
|