Fixed up NPC and Epoch handling.

This commit is contained in:
John Terrell 2023-03-24 14:48:05 -07:00
parent 9881cf00d4
commit 61d2a7cab4
Signed by untrusted user who does not match committer: johnt
GPG Key ID: 2E424258DD3731F4
3 changed files with 66 additions and 9 deletions

View File

@ -17,6 +17,8 @@ interface FetchStage_Ifc#(numeric type xlen);
endinterface endinterface
module mkFetchStage#(IsaCfg#(xlen) cfg)(FetchStage_Ifc#(xlen)); 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 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. // 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#(xlen) if_id = defaultValue;
if_id.common.pc = inflightMemoryRequest.Valid.address; if_id.common.pc = inflightMemoryRequest.Valid.address;
if_id.common.isBubble = False; if_id.common.isBubble = False;
if_id.npc = updatedPc; if_id.npc = updatedPc + 4;
if_id.epoch = epoch;
if (!response.accessFault) begin if (!response.accessFault) begin
if_id.common.ir.value = response.data; if_id.common.ir.value = response.data;
@ -73,10 +76,15 @@ module mkFetchStage#(IsaCfg#(xlen) cfg)(FetchStage_Ifc#(xlen));
end else begin end else begin
// No memory request is in flight... // 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) // or a redirected PC (due to a branch, jump, exception, etc)
ProgramCounter#(xlen) updatedPc_ = fromMaybe(pc_if.pc, pc_if.redirection); 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 // Check for a misaligned request
if (updatedPc_[1:0] != 0) begin if (updatedPc_[1:0] != 0) begin
// Address request was misaligned... // Address request was misaligned...

View File

@ -40,6 +40,7 @@ module mkTopModule(Empty);
dynamicAssert(!if_id.common.isBubble, "Fetch - Misaligned instruction trap check - common.isBubble"); 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(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.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 end
// Memory request denied trap (request submit) // Memory request denied trap (request submit)
@ -74,13 +75,14 @@ module mkTopModule(Empty);
3: begin 3: begin
pc_if.pc = 'h100; pc_if.pc = 'h100;
// The fetch should proceed and return a bubble.
let if_id <- fetchStage32.step(pc_if); 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.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.ir == defaultValue, "Fetch - Memory request denied trap check - common.ir");
dynamicAssert(!if_id.common.isBubble, "Fetch - Memory request denied trap check - common.isBubble"); 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(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.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 end
// Normal memory request (request submit) // Normal memory request (request submit)
@ -115,16 +117,58 @@ module mkTopModule(Empty);
6: begin 6: begin
pc_if.pc = 'h100; pc_if.pc = 'h100;
// The fetch should proceed and return a bubble.
let if_id <- fetchStage32.step(pc_if); let if_id <- fetchStage32.step(pc_if);
dynamicAssert(if_id.common.pc == pc_if.pc, "Fetch - Normal request - common.pc"); dynamicAssert(if_id.common.pc == pc_if.pc, "Fetch - Normal request - common.pc");
dynamicAssert(!if_id.common.isBubble, "Fetch - Normal request - common.isBubble"); dynamicAssert(!if_id.common.isBubble, "Fetch - Normal request - common.isBubble");
dynamicAssert(!isValid(if_id.common.trap), "Fetch - Normal request - contains no trap"); 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.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 end
default: begin default: begin
dynamicAssert(stepNumber == 7, "Fetch - not all tests run"); dynamicAssert(stepNumber == 10, "Fetch - not all tests run");
$display(">>>PASS"); $display(">>>PASS");
$finish(); $finish();
end end

View File

@ -1,6 +1,11 @@
import Trap::*; import Trap::*;
import DefaultValue::*; import DefaultValue::*;
//
// Epoch
//
typedef Bit#(1) Epoch;
// //
// Instruction // Instruction
// //
@ -58,14 +63,14 @@ endinstance
// //
typedef struct { typedef struct {
PipelineRegisterCommon#(xlen) common; PipelineRegisterCommon#(xlen) common;
Bit#(1) epoch; Epoch epoch;
ProgramCounter#(xlen) npc; // Next program counter ProgramCounter#(xlen) npc; // Next program counter
} IF_ID#(numeric type xlen) deriving(Bits, Eq, FShow); } IF_ID#(numeric type xlen) deriving(Bits, Eq, FShow);
instance DefaultValue #(IF_ID#(xlen)); instance DefaultValue #(IF_ID#(xlen));
defaultValue = IF_ID { defaultValue = IF_ID {
common: defaultValue, common: defaultValue,
epoch: 'h-1, epoch: defaultValue,
npc: defaultValue npc: defaultValue
}; };
endinstance endinstance
@ -75,7 +80,7 @@ endinstance
// //
typedef struct { typedef struct {
PipelineRegisterCommon#(xlen) common; PipelineRegisterCommon#(xlen) common;
Bit#(1) epoch; Epoch epoch;
ProgramCounter#(xlen) npc; // Next program counter ProgramCounter#(xlen) npc; // Next program counter
Bit#(xlen) a; // Operand 1 Bit#(xlen) a; // Operand 1
Bit#(xlen) b; // Operand 2 Bit#(xlen) b; // Operand 2
@ -86,7 +91,7 @@ typedef struct {
instance DefaultValue #(ID_EX#(xlen)); instance DefaultValue #(ID_EX#(xlen));
defaultValue = ID_EX { defaultValue = ID_EX {
common: defaultValue, common: defaultValue,
epoch: 0, epoch: defaultValue,
npc: defaultValue, npc: defaultValue,
a: 'h-1, a: 'h-1,
b: 'h-1, b: 'h-1,