diff --git a/src/Cpu/FetchStage.bsv b/src/Cpu/FetchStage.bsv index d5f6060..8bb20a7 100644 --- a/src/Cpu/FetchStage.bsv +++ b/src/Cpu/FetchStage.bsv @@ -17,6 +17,8 @@ interface FetchStage_Ifc#(numeric type xlen); endinterface module mkFetchStage#(IsaCfg#(xlen) cfg)(FetchStage_Ifc#(xlen)); + Reg#(Epoch) epoch <- mkReg(defaultValue); + Reg#(ProgramCounter#(xlen)) updatedPc <- mkRegU; // Holds the updated PC that is calculated when a fetch is issued // that is used to update the PC when the fetch completes. @@ -37,7 +39,8 @@ module mkFetchStage#(IsaCfg#(xlen) cfg)(FetchStage_Ifc#(xlen)); IF_ID#(xlen) if_id = defaultValue; if_id.common.pc = inflightMemoryRequest.Valid.address; if_id.common.isBubble = False; - if_id.npc = updatedPc; + if_id.npc = updatedPc + 4; + if_id.epoch = epoch; if (!response.accessFault) begin if_id.common.ir.value = response.data; @@ -73,10 +76,15 @@ module mkFetchStage#(IsaCfg#(xlen) cfg)(FetchStage_Ifc#(xlen)); end else begin // No memory request is in flight... - // Determine the PC the instruction will be fetchted from. It's either the calculated PC + // Determine the PC the instruction will be fetched from. It's either the calculated PC // or a redirected PC (due to a branch, jump, exception, etc) ProgramCounter#(xlen) updatedPc_ = fromMaybe(pc_if.pc, pc_if.redirection); + // If a redirection was specified, reflect that with a change in the epoch. + if (isValid(pc_if.redirection)) begin + epoch <= ~epoch; + end + // Check for a misaligned request if (updatedPc_[1:0] != 0) begin // Address request was misaligned... diff --git a/src/Cpu/FetchStage_tb.bsv b/src/Cpu/FetchStage_tb.bsv index bae73e6..a1be71c 100644 --- a/src/Cpu/FetchStage_tb.bsv +++ b/src/Cpu/FetchStage_tb.bsv @@ -40,6 +40,7 @@ module mkTopModule(Empty); dynamicAssert(!if_id.common.isBubble, "Fetch - Misaligned instruction trap check - common.isBubble"); dynamicAssert(isValid(if_id.common.trap), "Fetch - Misaligned instruction trap check - contains trap"); dynamicAssert(if_id.common.trap.Valid.cause == exception_INSTRUCTION_ADDRESS_MISALIGNED, "Fetch - Misaligned instruction trap check - cause is misaligned address"); + dynamicAssert(if_id.npc == defaultValue, "Fetch - Misaligned instruction trap check - NPC incorrect"); end // Memory request denied trap (request submit) @@ -74,13 +75,14 @@ module mkTopModule(Empty); 3: begin pc_if.pc = 'h100; - // The fetch should proceed and return a bubble. let if_id <- fetchStage32.step(pc_if); dynamicAssert(if_id.common.pc == pc_if.pc, "Fetch - Memory request denied trap check - common.pc"); dynamicAssert(if_id.common.ir == defaultValue, "Fetch - Memory request denied trap check - common.ir"); dynamicAssert(!if_id.common.isBubble, "Fetch - Memory request denied trap check - common.isBubble"); dynamicAssert(isValid(if_id.common.trap), "Fetch - Memory request denied trap check - contains trap"); dynamicAssert(if_id.common.trap.Valid.cause == exception_INSTRUCTION_ACCESS_FAULT, "Memory request denied trap check - cause is access fault"); + dynamicAssert(if_id.npc == 'h104, "Fetch - Misaligned instruction trap check - NPC incorrect"); + dynamicAssert(if_id.epoch == defaultValue, "Fetch - Misaligned instruction trap check - Verify epoch unchanged"); end // Normal memory request (request submit) @@ -115,16 +117,58 @@ module mkTopModule(Empty); 6: begin pc_if.pc = 'h100; - // The fetch should proceed and return a bubble. let if_id <- fetchStage32.step(pc_if); dynamicAssert(if_id.common.pc == pc_if.pc, "Fetch - Normal request - common.pc"); dynamicAssert(!if_id.common.isBubble, "Fetch - Normal request - common.isBubble"); dynamicAssert(!isValid(if_id.common.trap), "Fetch - Normal request - contains no trap"); dynamicAssert(if_id.common.ir.value == 'haabb_ccdd, "Fetch - Normal request - contains expected instruction data"); + dynamicAssert(if_id.npc == 'h104, "Fetch - Normal request - NPC incorrect"); + dynamicAssert(if_id.epoch == defaultValue, "Fetch - Normal request - Verify epoch unchanged"); + end + + // Redirect handling check + 7: begin + pc_if.pc = 'h100; + pc_if.redirection = tagged Valid 'h8000; + + // The fetch should proceed and return a bubble. + let if_id <- fetchStage32.step(pc_if); + dynamicAssert(if_id == defaultValue, "Fetch - Redirect check - request should return a bubble"); + end + + 8: begin + pc_if.pc = 'h100; + + // Ensure the fetch returns a bubble while the memory request is in flight + let if_id <- fetchStage32.step(pc_if); + dynamicAssert(if_id == defaultValue, "Fetch - Redirect check - request should return a bubble while fetch is in flight"); + + dynamicAssert(memoryRequests32.notEmpty, "Fetch - Redirect check - memory request queue should not be empty"); + let memoryRequest = memoryRequests32.first; + memoryRequests32.deq; + + dynamicAssert(memoryRequest.address == 'h8000, "Fetch - Redirect check - memory request should have correct address"); + fetchStage32.memoryClient.response.put(ReadOnlyMemoryResponse { + data: 'haabb_ccee, + accessFault: False + }); + end + + 9: begin + pc_if.pc = 'h100; + + // The fetch should proceed and return a bubble. + let if_id <- fetchStage32.step(pc_if); + dynamicAssert(if_id.common.pc == 'h8000, "Fetch - Redirect check - common.pc"); + dynamicAssert(!if_id.common.isBubble, "Fetch - Redirect check - common.isBubble"); + dynamicAssert(!isValid(if_id.common.trap), "Fetch - Redirect check - contains no trap"); + dynamicAssert(if_id.common.ir.value == 'haabb_ccee, "Fetch - Redirect check - contains expected instruction data"); + dynamicAssert(if_id.npc == 'h8004, "Fetch - Redirect check - NPC incorrect"); + dynamicAssert(if_id.epoch == 'h1, "Fetch - Redirect check - Verify epoch changed"); end default: begin - dynamicAssert(stepNumber == 7, "Fetch - not all tests run"); + dynamicAssert(stepNumber == 10, "Fetch - not all tests run"); $display(">>>PASS"); $finish(); end diff --git a/src/Cpu/PipelineRegisters.bsv b/src/Cpu/PipelineRegisters.bsv index 192d56c..8431941 100644 --- a/src/Cpu/PipelineRegisters.bsv +++ b/src/Cpu/PipelineRegisters.bsv @@ -1,6 +1,11 @@ import Trap::*; import DefaultValue::*; +// +// Epoch +// +typedef Bit#(1) Epoch; + // // Instruction // @@ -58,14 +63,14 @@ endinstance // typedef struct { PipelineRegisterCommon#(xlen) common; - Bit#(1) epoch; + Epoch epoch; ProgramCounter#(xlen) npc; // Next program counter } IF_ID#(numeric type xlen) deriving(Bits, Eq, FShow); instance DefaultValue #(IF_ID#(xlen)); defaultValue = IF_ID { common: defaultValue, - epoch: 'h-1, + epoch: defaultValue, npc: defaultValue }; endinstance @@ -75,7 +80,7 @@ endinstance // typedef struct { PipelineRegisterCommon#(xlen) common; - Bit#(1) epoch; + Epoch epoch; ProgramCounter#(xlen) npc; // Next program counter Bit#(xlen) a; // Operand 1 Bit#(xlen) b; // Operand 2 @@ -86,7 +91,7 @@ typedef struct { instance DefaultValue #(ID_EX#(xlen)); defaultValue = ID_EX { common: defaultValue, - epoch: 0, + epoch: defaultValue, npc: defaultValue, a: 'h-1, b: 'h-1,