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