106 lines
3.9 KiB
Plaintext
106 lines
3.9 KiB
Plaintext
import IsaCfg::*;
|
|
import MemoryTypes::*;
|
|
import PipelineRegisters::*;
|
|
import RV_ISA::*;
|
|
import Trap::*;
|
|
|
|
import Assert::*;
|
|
import ClientServer::*;
|
|
import FIFOF::*;
|
|
import GetPut::*;
|
|
import Memory::*;
|
|
|
|
interface FetchStage_Ifc#(numeric type xlen);
|
|
method ActionValue#(IF_ID#(xlen)) step(PC_IF#(xlen) pc_if);
|
|
interface ReadOnlyMemoryClient#(xlen, 32) memoryClient;
|
|
endinterface
|
|
|
|
module mkFetchStage#(IsaCfg#(xlen) cfg)(FetchStage_Ifc#(xlen));
|
|
Reg#(Bool) stall <- mkReg(False);
|
|
Reg#(Bool) externalStall <- mkReg(False);
|
|
|
|
// Memory request output
|
|
Reg#(Bool) memoryRequestInFlight <- mkReg(False);
|
|
Wire#(ReadOnlyMemoryRequest#(xlen)) memoryRequest <- mkWire;
|
|
|
|
// Memory response input (FIFO)
|
|
// Note: This is an unguarded FIFO so status much be checked before attempting to enq() and deq().
|
|
FIFOF#(ReadOnlyMemoryResponse#(32)) memoryResponses <- mkUGFIFOF1;
|
|
|
|
//
|
|
// processMemoryResponse - takes a memory response and returns an IF_ID containing
|
|
// the encoded instruction (or a trap if the original request
|
|
// was denied by the memory system)
|
|
//
|
|
function IF_ID#(xlen) processMemoryResponse(PC_IF#(xlen) pc_if, ReadOnlyMemoryResponse#(32) response);
|
|
IF_ID#(xlen) if_id = defaultValue;
|
|
if_id.common.pc = pc_if.pc;
|
|
if_id.common.isBubble = False;
|
|
if_id.npc = pc_if.pc + 4;
|
|
|
|
if (!response.accessFault) begin
|
|
if_id.common.ir.value = response.data;
|
|
if_id.common.trap = tagged Invalid;
|
|
end else begin
|
|
Trap#(xlen) trap = Trap {
|
|
cause: exception_INSTRUCTION_ACCESS_FAULT,
|
|
isInterrupt: False,
|
|
tval: 0
|
|
};
|
|
|
|
if_id.common.trap = tagged Valid(trap);
|
|
end
|
|
return if_id;
|
|
endfunction
|
|
|
|
method ActionValue#(IF_ID#(xlen)) step(PC_IF#(xlen) pc_if);
|
|
IF_ID#(xlen) if_id = defaultValue;
|
|
if (!pc_if.isBubble) begin
|
|
// If there's an active request, handle it if it's returned
|
|
if (memoryRequestInFlight) begin
|
|
if (memoryResponses.notEmpty) begin
|
|
if_id = processMemoryResponse(pc_if, memoryResponses.first);
|
|
memoryResponses.deq;
|
|
memoryRequestInFlight <= False;
|
|
end else begin
|
|
// Memory request is in flight but hasn't returned yet.
|
|
end
|
|
end else begin
|
|
// No memory request is in flight...
|
|
|
|
// Check for a misaligned request
|
|
if (pc_if.pc[1:0] != 0) begin
|
|
// Address request was misaligned...
|
|
Trap#(xlen) trap = Trap {
|
|
cause: exception_INSTRUCTION_ADDRESS_MISALIGNED,
|
|
isInterrupt: False,
|
|
tval: 0
|
|
};
|
|
if_id.common.pc = pc_if.pc;
|
|
if_id.common.trap = tagged Valid(trap);
|
|
if_id.common.isBubble = False;
|
|
end else begin
|
|
// Construct a memory request and send it out.
|
|
ReadOnlyMemoryRequest#(xlen) request = ReadOnlyMemoryRequest {
|
|
address: pc_if.pc
|
|
};
|
|
memoryRequest <= request;
|
|
memoryRequestInFlight <= True;
|
|
end
|
|
end
|
|
end
|
|
|
|
return if_id;
|
|
endmethod
|
|
|
|
interface ReadOnlyMemoryClient memoryClient;
|
|
interface Get request = toGet(memoryRequest);
|
|
interface Put response;
|
|
method Action put(ReadOnlyMemoryResponse#(32) response);
|
|
dynamicAssert(memoryResponses.notFull, "FetchStage - attempt to put a memory respnose on a full queue");
|
|
memoryResponses.enq(response);
|
|
endmethod
|
|
endinterface
|
|
endinterface
|
|
endmodule
|