mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-04-24 22:07:12 -04:00
Merge 45427c393e
into 701482f201
This commit is contained in:
commit
a9208932f1
1 changed files with 124 additions and 0 deletions
124
src/ifu/fetchbuffer.sv
Normal file
124
src/ifu/fetchbuffer.sv
Normal file
|
@ -0,0 +1,124 @@
|
|||
///////////////////////////////////////////
|
||||
// fetchbuffer.sv
|
||||
//
|
||||
// Written: vkrishna@hmc.edu 3 April 2025
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Cacheline buffer for instruction fetch
|
||||
//
|
||||
// A component of the CORE-V-WALLY configurable RISC-V project.
|
||||
// https://github.com/openhwgroup/cvw
|
||||
//
|
||||
// Copyright (C) 2021-25 Harvey Mudd College & Oklahoma State University
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
//
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module fetchbuffer import cvw::*; #(parameter cvw_t P) (
|
||||
input logic clk, reset,
|
||||
input logic DisableRead, DisableWrite,
|
||||
input logic [P.XLEN-1:0] PCF, // PC of the instruction
|
||||
input logic [P.XLEN-1:0] PCCacheF, // Address of the instruction
|
||||
input logic [P.ICACHE_LINELENINBITS-1:0] FetchData, // Data fetched from memory
|
||||
output logic Empty, Full,
|
||||
output logic FetchBufferStallD,
|
||||
output logic [31:0] InstrD, // Instruction to be decoded
|
||||
output logic [P.XLEN-1:0] PCD // PC of the instruction to be decoded
|
||||
);
|
||||
localparam ENTRY_INDEX_BITS = $clog2(P.ICACHE_LINELENINBITS/8);
|
||||
localparam TAG_BITS = P.XLEN - ENTRY_INDEX_BITS;
|
||||
localparam nop = 32'h00000013;
|
||||
|
||||
logic ReadPtr, WritePtr
|
||||
logic PrevReadPtr; // used to invalidate old cacheline
|
||||
// TODO: Check if we still need PrevReadPtr
|
||||
logic Spill;
|
||||
logic InstrMissing;
|
||||
|
||||
logic [P.XLEN-1:ENTRY_INDEX_BITS] PCFTag;
|
||||
logic [ENTRY_INDEX_BITS-1:0] EntryIndex; // used to get the last 6 bits of PCF
|
||||
|
||||
logic Valid [1:0];
|
||||
logic [TAG_BITS-1:0] PCTag [1:0];
|
||||
logic [P.ICACHE_LINELENINBITS-1:0] Data [1:0];
|
||||
|
||||
assign {PCFTag, EntryIndex} = PCF;
|
||||
|
||||
assign WritePtr = ~ReadPtr;
|
||||
assign Full = Valid[0] & Valid[1];
|
||||
assign Empty = ~Valid[0] & ~Valid[1];
|
||||
assign InstrMissing = ~((PCFTag == PCTag[0]) | (PCFTag == PCTag[1]))
|
||||
assign FetchBufferStallD = Empty | (Spill & ~Full) | InstrMissing;
|
||||
|
||||
|
||||
// Don't care if it tag doesn't match either, as InstrMissing will be 1
|
||||
assign ReadPtr = (PCFTag == PCTag[1]) ? 1'b1 : 1'b0;
|
||||
|
||||
flopr #(1) PrevReadPtrReg (clk, reset, ReadPtr, PrevReadPtr);
|
||||
|
||||
|
||||
// The priority for writing is:
|
||||
// 1. If the buffer is Empty, write the new Data
|
||||
// 2. If the buffer is not Empty, check if the new Data isn't already in the buffer
|
||||
// 3. If the new Data is not in the buffer, always write to WritePtr
|
||||
// 4. If the new Data is already in the buffer, check ReadPtr to invalidate the old Data
|
||||
always_ff @( posedge clk )
|
||||
if (reset) Valid <= 2'b0;
|
||||
else if (~DisableWrite & (~Full | InstrMissing)) begin
|
||||
Valid[WritePtr] <= 1'b1;
|
||||
PCTag[WritePtr] <= PCCacheF[P.XLEN-1:ENTRY_INDEX_BITS];
|
||||
Data[WritePtr] <= FetchData;
|
||||
end else if (~DisableWrite & (PrevReadPtr != ReadPtr))
|
||||
Valid[PrevReadPtr] <= 1'b0;
|
||||
// TODO: Check if we need to keep the old data in the buffer
|
||||
// else begin
|
||||
// Valid <= Valid;
|
||||
// PCTag <= PCTag;
|
||||
// Data <= Data;
|
||||
// end
|
||||
|
||||
// Decode Logic:
|
||||
always_ff @( posedge clk )
|
||||
if (reset) begin
|
||||
InstrD <= nop;
|
||||
PCD <= PCF;
|
||||
Spill <= 1'b0;
|
||||
end else if (DisableRead | Empty) begin
|
||||
InstrD <= InstrD;
|
||||
PCD <= PCD;
|
||||
Spill <= Spill;
|
||||
end else begin
|
||||
PCD <= PCF;
|
||||
// Spill logic
|
||||
if (EntryIndex[ENTRY_INDEX_BITS-1:1] == '1) begin
|
||||
if (Full) begin
|
||||
// next cacheline holds the Spill
|
||||
Spill <= 1'b0;
|
||||
InstrD <= {Data[~ReadPtr][15:0], Data[ReadPtr][P.ICACHE_LINELENINBITS-1:P.ICACHE_LINELENINBITS-16]};
|
||||
end else if (Data[ReadPtr][P.ICACHE_LINELENINBITS-15:P.ICACHE_LINELENINBITS-16] != 2'b11) begin
|
||||
// next cacheline doesn't hold Spill but instruction is compressed so doesn't Spill over
|
||||
Spill <= 1'b0;
|
||||
InstrD <= {16'b0, Data[ReadPtr][P.ICACHE_LINELENINBITS-1:P.ICACHE_LINELENINBITS-16]};
|
||||
end else begin
|
||||
// next cacheline doesn't hold Spill, but it is needed as the instruction is not compressed
|
||||
Spill <= 1'b1;
|
||||
InstrD <= InstrD;
|
||||
end
|
||||
end else begin
|
||||
// fetch instruction from the cacheline as needed
|
||||
Spill <= 1'b0;
|
||||
InstrD <= Data[ReadPtr][EntryIndex*8 + 31:EntryIndex*8];
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Add table
Add a link
Reference in a new issue