mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Cleaned up hptw.
This commit is contained in:
parent
24916d42e2
commit
9b6b6617af
@ -104,7 +104,6 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
logic HPTWLoadPageFaultDelay, HPTWStoreAmoPageFaultDelay, HPTWInstrPageFaultDelay;
|
||||
logic HPTWAccessFaultDelay;
|
||||
logic TakeHPTWFault;
|
||||
logic [P.XLEN-1:0] ReadDataNoXM;
|
||||
logic PBMTFaultM;
|
||||
logic HPTWFaultM;
|
||||
|
||||
@ -171,9 +170,7 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
logic [P.XLEN-1:0] AccessedPTE;
|
||||
|
||||
assign AccessedPTE = {PTE[P.XLEN-1:8], (SetDirty | PTE[7]), 1'b1, PTE[5:0]}; // set accessed bit, conditionally set dirty bit
|
||||
//assign ReadDataNoXM = (ReadDataM[0] === 'x) ? 0 : ReadDataM; // If the PTE.V bit is x because it was read from uninitialized memory set to 0 to avoid x propagation and hanging the simulation.
|
||||
assign ReadDataNoXM = ReadDataM; // *** temporary fix for synthesis; === and x in line above are not synthesizable.
|
||||
mux2 #(P.XLEN) NextPTEMux(ReadDataNoXM, AccessedPTE, UpdatePTE, NextPTE); // NextPTE = ReadDataNoXM when ADUE = 0 because UpdatePTE = 0
|
||||
mux2 #(P.XLEN) NextPTEMux(ReadDataM, AccessedPTE, UpdatePTE, NextPTE); // NextPTE = ReadDataM when ADUE = 0 because UpdatePTE = 0
|
||||
flopenr #(P.PA_BITS) HPTWAdrWriteReg(clk, reset, SaveHPTWAdr, HPTWReadAdr, HPTWWriteAdr);
|
||||
|
||||
assign SaveHPTWAdr = WalkerState == L0_ADR;
|
||||
@ -209,7 +206,7 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
assign UpdatePTE = (WalkerState == LEAF) & HPTWUpdateDA; // UpdatePTE will always be 0 if ADUE = 0 because HPTWUpdateDA will be 0
|
||||
|
||||
end else begin // block: hptwwrites
|
||||
assign NextPTE = ReadDataNoXM;
|
||||
assign NextPTE = ReadDataM;
|
||||
assign HPTWAdr = HPTWReadAdr;
|
||||
assign HPTWUpdateDA = 1'b0;
|
||||
assign UpdatePTE = 1'b0;
|
||||
@ -265,60 +262,47 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
end else begin
|
||||
logic GigapageMisaligned, TerapageMisaligned;
|
||||
assign InitialWalkerState = (SvMode == P.SV48) ? L3_ADR : L2_ADR;
|
||||
assign TerapageMisaligned = |(CurrentPPN[26:0]); // must have zero PPN2, PPN1, PPN0
|
||||
assign GigapageMisaligned = |(CurrentPPN[17:0]); // must have zero PPN1 and PPN0
|
||||
assign MegapageMisaligned = |(CurrentPPN[8:0]); // must have zero PPN0
|
||||
assign TerapageMisaligned = |(CurrentPPN[26:0]); // Must have zero PPN2, PPN1, PPN0
|
||||
assign GigapageMisaligned = |(CurrentPPN[17:0]); // Must have zero PPN1 and PPN0
|
||||
assign MegapageMisaligned = |(CurrentPPN[8:0]); // Must have zero PPN0
|
||||
assign Misaligned = ((WalkerState == L2_ADR) & TerapageMisaligned) | ((WalkerState == L1_ADR) & GigapageMisaligned) | ((WalkerState == L0_ADR) & MegapageMisaligned);
|
||||
end
|
||||
|
||||
// Page Table Walker FSM
|
||||
// *** there is a bug here (RT). Each memory access needs to be potentially flushed if the PMA/P checkers
|
||||
// generate an access fault. Specially the store on UDPATE_PTE needs to check for access violation.
|
||||
// I think the solution is to do 1 of the following
|
||||
// 1. Allow the HPTW to generate exceptions and stop walking immediately.
|
||||
// 2. If the store would generate an exception don't store to dcache but still write the TLB. When we go back
|
||||
// to LEAF then the PMA/P. Wait this does not work. The PMA/P won't be looking a the address in the table, but
|
||||
// rather than physical address of the translated instruction/data. So we must generate the exception.
|
||||
flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset | FlushW, 1'b1, NextWalkerState, IDLE, WalkerState);
|
||||
always_comb
|
||||
case (WalkerState)
|
||||
IDLE: if (TLBMissOrUpdateDA) NextWalkerState = InitialWalkerState;
|
||||
else NextWalkerState = IDLE;
|
||||
L3_ADR: NextWalkerState = L3_RD; // first access in SV48
|
||||
L3_ADR: NextWalkerState = L3_RD; // First access in SV48
|
||||
L3_RD: if (DCacheBusStallM) NextWalkerState = L3_RD;
|
||||
else if(HPTWFaultM) NextWalkerState = FAULT;
|
||||
else if (HPTWFaultM) NextWalkerState = FAULT;
|
||||
else NextWalkerState = L2_ADR;
|
||||
L2_ADR: if (InitialWalkerState == L2_ADR | ValidNonLeafPTE) NextWalkerState = L2_RD; // first access in SV39
|
||||
L2_ADR: if (InitialWalkerState == L2_ADR | ValidNonLeafPTE) NextWalkerState = L2_RD; // First access in SV39
|
||||
else NextWalkerState = LEAF;
|
||||
L2_RD: if (DCacheBusStallM) NextWalkerState = L2_RD;
|
||||
else if(HPTWFaultM) NextWalkerState = FAULT;
|
||||
else if (HPTWFaultM) NextWalkerState = FAULT;
|
||||
else NextWalkerState = L1_ADR;
|
||||
L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // first access in SV32
|
||||
L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // First access in SV32
|
||||
else NextWalkerState = LEAF;
|
||||
L1_RD: if (DCacheBusStallM) NextWalkerState = L1_RD;
|
||||
else if(HPTWFaultM) NextWalkerState = FAULT;
|
||||
else if (HPTWFaultM) NextWalkerState = FAULT;
|
||||
else NextWalkerState = L0_ADR;
|
||||
L0_ADR: if (ValidNonLeafPTE) NextWalkerState = L0_RD;
|
||||
else NextWalkerState = LEAF;
|
||||
L0_RD: if (DCacheBusStallM) NextWalkerState = L0_RD;
|
||||
else if(HPTWFaultM) NextWalkerState = FAULT;
|
||||
else if (HPTWFaultM) NextWalkerState = FAULT;
|
||||
else NextWalkerState = LEAF;
|
||||
LEAF: if (P.SVADU_SUPPORTED & HPTWUpdateDA) NextWalkerState = UPDATE_PTE;
|
||||
else NextWalkerState = IDLE;
|
||||
UPDATE_PTE: if(DCacheBusStallM) NextWalkerState = UPDATE_PTE;
|
||||
UPDATE_PTE: if (DCacheBusStallM) NextWalkerState = UPDATE_PTE;
|
||||
else NextWalkerState = LEAF;
|
||||
FAULT: NextWalkerState = IDLE;
|
||||
default: NextWalkerState = IDLE; // should never be reached
|
||||
default: NextWalkerState = IDLE; // Should never be reached
|
||||
endcase // case (WalkerState)
|
||||
|
||||
assign IgnoreRequestTLB = (WalkerState == IDLE & TLBMissOrUpdateDA) | (HPTWFaultM); // RT : 05 April 2023 if hptw request has pmp/a fault suppress bus access.
|
||||
assign IgnoreRequestTLB = (WalkerState == IDLE & TLBMissOrUpdateDA) | (HPTWFaultM); // If hptw request has pmp/a fault suppress bus access.
|
||||
assign SelHPTW = WalkerState != IDLE;
|
||||
|
||||
// RT 30 May 2023: When there is an access fault caused by the hptw itself, the fsm jumps to FAULT, removes
|
||||
// stall and asserts one of HPTWLoadAccessFault, HPTWStoreAmoAccessFault or HPTWInstrAccessFaultDelay.
|
||||
// The FSM directly transistions to IDLE to ready for the next operation when the delayed version will not be high.
|
||||
|
||||
assign HPTWAccessFaultDelay = HPTWLoadAccessFaultDelay | HPTWStoreAmoAccessFaultDelay | HPTWInstrAccessFaultDelay; // *** unused - RT, can we delete?
|
||||
assign HPTWStall = (WalkerState != IDLE & WalkerState != FAULT) | (WalkerState == IDLE & TLBMissOrUpdateDA);
|
||||
|
||||
// HTPW address/data/control muxing
|
||||
@ -326,22 +310,17 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
// Once the walk is done and it is time to update the TLB we need to switch back
|
||||
// to the orignal data virtual address.
|
||||
assign SelHPTWAdr = SelHPTW & ~(DTLBWriteM | ITLBWriteF);
|
||||
// always block interrupts when using the hardware page table walker.
|
||||
|
||||
// multiplex the outputs to LSU
|
||||
if(P.XLEN == 64) assign HPTWAdrExt = {{(P.XLEN+2-P.PA_BITS){1'b0}}, HPTWAdr}; // extend to 66 bits
|
||||
else assign HPTWAdrExt = HPTWAdr;
|
||||
if (P.XLEN == 64) assign HPTWAdrExt = {{(P.XLEN+2-P.PA_BITS){1'b0}}, HPTWAdr}; // Extend to 66 bits
|
||||
else assign HPTWAdrExt = HPTWAdr;
|
||||
mux2 #(2) rwmux(MemRWM, HPTWRW, SelHPTW, PreLSURWM);
|
||||
mux2 #(3) sizemux(Funct3M, HPTWSize, SelHPTW, LSUFunct3M);
|
||||
mux2 #(7) funct7mux(Funct7M, 7'b0, SelHPTW, LSUFunct7M);
|
||||
mux2 #(2) atomicmux(AtomicM, 2'b00, SelHPTW, LSUAtomicM);
|
||||
mux2 #(P.XLEN+2) lsupadrmux(IEUAdrExtM, HPTWAdrExt, SelHPTWAdr, IHAdrM);
|
||||
if(P.SVADU_SUPPORTED)
|
||||
if (P.SVADU_SUPPORTED)
|
||||
mux2 #(P.XLEN) lsuwritedatamux(WriteDataM, PTE, SelHPTW, IHWriteDataM);
|
||||
else assign IHWriteDataM = WriteDataM;
|
||||
|
||||
endmodule
|
||||
|
||||
// another idea. We keep gating the control by ~FlushW, but this adds considerable length to the critical path.
|
||||
// should we do this differently? For example TLBMissOrUpdateDA is gated by ~FlushW and then drives HPTWStall, which drives LSUStallM, which drives
|
||||
// the hazard unit to issue stall and flush controlls. ~FlushW already suppresses these in the hazard unit.
|
||||
|
Loading…
Reference in New Issue
Block a user