From a252416535aa381160195a3dece9b20deacfc072 Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Sun, 4 Jul 2021 16:49:34 -0500 Subject: [PATCH 1/7] Removed the TranslationVAdrQ as it is not necessary. --- wally-pipelined/regression/wave.do | 93 +++++++++++++++------- wally-pipelined/src/mmu/pagetablewalker.sv | 36 ++++----- 2 files changed, 81 insertions(+), 48 deletions(-) diff --git a/wally-pipelined/regression/wave.do b/wally-pipelined/regression/wave.do index 42da6093..213b5cee 100644 --- a/wally-pipelined/regression/wave.do +++ b/wally-pipelined/regression/wave.do @@ -7,19 +7,19 @@ add wave -noupdate -expand -group {Execution Stage} /testbench/FunctionName/Func add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/PCE add wave -noupdate -expand -group {Execution Stage} /testbench/InstrEName add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/InstrE -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/InstrMisalignedFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/InstrAccessFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/IllegalInstrFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/BreakpointFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/LoadMisalignedFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/StoreMisalignedFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/LoadAccessFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/StoreAccessFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/EcallFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/InstrPageFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/LoadPageFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/StorePageFaultM -add wave -noupdate -expand -group HDU -group traps /testbench/dut/hart/priv/trap/InterruptM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/InstrMisalignedFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/InstrAccessFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/IllegalInstrFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/BreakpointFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/LoadMisalignedFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/StoreMisalignedFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/LoadAccessFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/StoreAccessFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/EcallFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/InstrPageFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/LoadPageFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/StorePageFaultM +add wave -noupdate -expand -group HDU -expand -group traps /testbench/dut/hart/priv/trap/InterruptM add wave -noupdate -expand -group HDU -expand -group hazards /testbench/dut/hart/hzu/BPPredWrongE add wave -noupdate -expand -group HDU -expand -group hazards /testbench/dut/hart/hzu/CSRWritePendingDEM add wave -noupdate -expand -group HDU -expand -group hazards /testbench/dut/hart/hzu/RetM @@ -118,18 +118,18 @@ add wave -noupdate -group RegFile -group {write regfile mux} /testbench/dut/hart add wave -noupdate -group RegFile -group {write regfile mux} /testbench/dut/hart/ieu/dp/CSRReadValW add wave -noupdate -group RegFile -group {write regfile mux} /testbench/dut/hart/ieu/dp/ResultSrcW add wave -noupdate -group RegFile -group {write regfile mux} /testbench/dut/hart/ieu/dp/ResultW -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/a -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/b -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/alucontrol -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/result -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/flags -add wave -noupdate -group alu -divider internals -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/overflow -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/carry -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/zero -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/neg -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/lt -add wave -noupdate -group alu /testbench/dut/hart/ieu/dp/alu/ltu +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/a +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/b +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/alucontrol +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/result +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/flags +add wave -noupdate -expand -group alu -divider internals +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/overflow +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/carry +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/zero +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/neg +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/lt +add wave -noupdate -expand -group alu /testbench/dut/hart/ieu/dp/alu/ltu add wave -noupdate -group Forward /testbench/dut/hart/ieu/fw/Rs1D add wave -noupdate -group Forward /testbench/dut/hart/ieu/fw/Rs2D add wave -noupdate -group Forward /testbench/dut/hart/ieu/fw/Rs1E @@ -243,6 +243,7 @@ add wave -noupdate -group AHB /testbench/dut/hart/ebu/StallW add wave -noupdate -expand -group lsu -color Gold /testbench/dut/hart/lsu/CurrState add wave -noupdate -expand -group lsu /testbench/dut/hart/lsu/DisableTranslation add wave -noupdate -expand -group lsu /testbench/dut/hart/lsu/MemRWM +add wave -noupdate -expand -group lsu /testbench/dut/hart/lsu/DataStall add wave -noupdate -expand -group lsu /testbench/dut/hart/lsu/MemAdrM add wave -noupdate -expand -group lsu /testbench/dut/hart/lsu/MemPAdrM add wave -noupdate -expand -group lsu /testbench/dut/hart/lsu/ReadDataW @@ -293,7 +294,42 @@ add wave -noupdate -group CLINT /testbench/dut/uncore/genblk1/clint/MTIME add wave -noupdate -group CLINT /testbench/dut/uncore/genblk1/clint/MTIMECMP add wave -noupdate -group CLINT /testbench/dut/uncore/genblk1/clint/TimerIntM add wave -noupdate -group CLINT /testbench/dut/uncore/genblk1/clint/SwIntM +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/MMUTranslate +add wave -noupdate -expand -group ptwalker -color Gold /testbench/dut/hart/pagetablewalker/WalkerState +add wave -noupdate -expand -group ptwalker -color Salmon /testbench/dut/hart/pagetablewalker/HPTWStall +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/HPTWRead +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/MMUPAdr +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/MMUStall +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/EndWalk +add wave -noupdate -expand -group ptwalker -expand -group pte /testbench/dut/hart/pagetablewalker/MMUReadPTE +add wave -noupdate -expand -group ptwalker -expand -group pte /testbench/dut/hart/pagetablewalker/PRegEn +add wave -noupdate -expand -group ptwalker -expand -group pte /testbench/dut/hart/pagetablewalker/CurrentPTE add wave -noupdate -expand -group ptwalker -divider data +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/TranslationPAdr +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/ValidPTE +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/LeafPTE +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/MMUStall +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/TranslationPAdr +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/PageTableEntry +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/PageType +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/ITLBWriteF +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/DTLBWriteM +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/WalkerInstrPageFaultF +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/WalkerLoadPageFaultM +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/WalkerStorePageFaultM +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/MMUStall +add wave -noupdate -expand -group ptwalker -group {fsm outputs} /testbench/dut/hart/pagetablewalker/EndWalk +add wave -noupdate -expand -group ptwalker /testbench/dut/hart/pagetablewalker/MMUPAdr +add wave -noupdate -expand -group {LSU ARB} -color Gold /testbench/dut/hart/arbiter/CurrState +add wave -noupdate -expand -group {LSU ARB} -color {Medium Orchid} /testbench/dut/hart/arbiter/SelPTW +add wave -noupdate -expand -group {LSU ARB} /testbench/dut/hart/pagetablewalker/MMUStall +add wave -noupdate -expand -group {LSU ARB} -expand -group hptw /testbench/dut/hart/arbiter/HPTWTranslate +add wave -noupdate -expand -group {LSU ARB} -expand -group hptw /testbench/dut/hart/arbiter/HPTWRead +add wave -noupdate -expand -group {LSU ARB} -expand -group hptw /testbench/dut/hart/arbiter/HPTWPAdr +add wave -noupdate -expand -group {LSU ARB} -expand -group hptw /testbench/dut/hart/arbiter/HPTWReadPTE +add wave -noupdate -expand -group {LSU ARB} -expand -group hptw /testbench/dut/hart/arbiter/HPTWReady +add wave -noupdate -expand -group {LSU ARB} -group toLSU /testbench/dut/hart/arbiter/MemAdrMtoLSU +add wave -noupdate /testbench/dut/hart/lsu/DataStall add wave -noupdate -group csr /testbench/dut/hart/priv/csr/MIP_REGW add wave -noupdate -group uart /testbench/dut/uncore/genblk4/uart/HCLK add wave -noupdate -group uart /testbench/dut/uncore/genblk4/uart/HRESETn @@ -320,6 +356,7 @@ add wave -noupdate -group uart -expand -group outputs /testbench/dut/uncore/genb add wave -noupdate -group dtlb /testbench/dut/hart/lsu/dmmu/TLBMiss add wave -noupdate -group dtlb /testbench/dut/hart/lsu/dmmu/tlb/TLBWrite add wave -noupdate -group itlb /testbench/dut/hart/ifu/ITLBMissF +add wave -noupdate /testbench/dut/hart/pagetablewalker/StartWalk add wave -noupdate /testbench/dut/hart/lsu/dmmu/tlb/DisableTranslation add wave -noupdate -group tlbread /testbench/dut/hart/lsu/dmmu/tlb/VirtualAddress add wave -noupdate -group tlbread /testbench/dut/hart/lsu/dmmu/tlb/tlbcam/CAMHit @@ -330,8 +367,8 @@ add wave -noupdate -group tlbwrite /testbench/dut/hart/lsu/dmmu/tlb/tlbcam/TLBWr add wave -noupdate -group tlbwrite /testbench/dut/hart/lsu/dmmu/tlb/PTEWriteVal add wave -noupdate -group tlbwrite /testbench/dut/hart/lsu/dmmu/tlb/tlbcam/WriteLines TreeUpdate [SetDefaultTree] -WaveRestoreCursors {{Cursor 8} {4545 ns} 0} {{Cursor 3} {2540 ns} 0} {{Cursor 4} {681 ns} 0} -quietly wave cursor active 2 +WaveRestoreCursors {{Cursor 8} {4545 ns} 0} {{Cursor 3} {3377 ns} 0} {{Cursor 4} {3215 ns} 0} +quietly wave cursor active 1 configure wave -namecolwidth 250 configure wave -valuecolwidth 189 configure wave -justifyvalue left @@ -346,4 +383,4 @@ configure wave -griddelta 40 configure wave -timeline 0 configure wave -timelineunits ns update -WaveRestoreZoom {2313 ns} {2789 ns} +WaveRestoreZoom {4209 ns} {4657 ns} diff --git a/wally-pipelined/src/mmu/pagetablewalker.sv b/wally-pipelined/src/mmu/pagetablewalker.sv index 45479d4a..c92fc597 100644 --- a/wally-pipelined/src/mmu/pagetablewalker.sv +++ b/wally-pipelined/src/mmu/pagetablewalker.sv @@ -72,7 +72,6 @@ module pagetablewalker // Internal signals // register TLBs translation miss requests - logic [`XLEN-1:0] TranslationVAdrQ; logic ITLBMissFQ, DTLBMissMQ; logic [`PPN_BITS-1:0] BasePageTablePPN; @@ -110,6 +109,8 @@ module pagetablewalker statetype WalkerState, NextWalkerState; logic PRegEn; + logic SelDataTranslation; + assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]; @@ -118,13 +119,8 @@ module pagetablewalker assign MemStore = MemRWM[0]; // Prefer data address translations over instruction address translations - assign TranslationVAdr = (DTLBMissM) ? MemAdrM : PCF; // *** need to register TranslationVAdr - flopenr #(`XLEN) - TranslationVAdrReg(.clk(clk), - .reset(reset), - .en(StartWalk), // *** use enable later to save power - .d(TranslationVAdr), - .q(TranslationVAdrQ)); + assign TranslationVAdr = (SelDataTranslation) ? MemAdrM : PCF; // *** need to register TranslationVAdr + assign SelDataTranslation = DTLBMissMQ | DTLBMissM; flopenrc #(1) DTLBMissMReg(.clk(clk), @@ -227,7 +223,7 @@ module pagetablewalker PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; // *** not sure about this mux? DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; + TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. else if (ValidPTE && ~LeafPTE) begin @@ -256,7 +252,7 @@ module pagetablewalker PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; + TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; end else begin NextWalkerState = FAULT; end @@ -281,8 +277,8 @@ module pagetablewalker assign MegapageMisaligned = |(CurrentPPN[9:0]); assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - assign VPN1 = TranslationVAdrQ[31:22]; - assign VPN0 = TranslationVAdrQ[21:12]; + assign VPN1 = TranslationVAdr[31:22]; + assign VPN0 = TranslationVAdr[21:12]; @@ -372,7 +368,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. else if (ValidPTE && ~LeafPTE) begin @@ -409,7 +405,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. else if (ValidPTE && ~LeafPTE) begin @@ -446,7 +442,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. @@ -478,7 +474,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; end else begin NextWalkerState = FAULT; end @@ -516,10 +512,10 @@ module pagetablewalker assign BadGigapage = GigapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - assign VPN3 = TranslationVAdrQ[47:39]; - assign VPN2 = TranslationVAdrQ[38:30]; - assign VPN1 = TranslationVAdrQ[29:21]; - assign VPN0 = TranslationVAdrQ[20:12]; + assign VPN3 = TranslationVAdr[47:39]; + assign VPN2 = TranslationVAdr[38:30]; + assign VPN1 = TranslationVAdr[29:21]; + assign VPN0 = TranslationVAdr[20:12]; // Capture page table entry from ahblite From 530ddd667b0455837a6e4767681bd529ab3f534f Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Mon, 5 Jul 2021 16:37:26 -0500 Subject: [PATCH 2/7] Fixed combo loop in the page table walker. --- wally-pipelined/src/mmu/pagetablewalker.sv | 54 +++++++++++++++------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/wally-pipelined/src/mmu/pagetablewalker.sv b/wally-pipelined/src/mmu/pagetablewalker.sv index c92fc597..c746696a 100644 --- a/wally-pipelined/src/mmu/pagetablewalker.sv +++ b/wally-pipelined/src/mmu/pagetablewalker.sv @@ -72,6 +72,7 @@ module pagetablewalker // Internal signals // register TLBs translation miss requests + logic [`XLEN-1:0] TranslationVAdrQ; logic ITLBMissFQ, DTLBMissMQ; logic [`PPN_BITS-1:0] BasePageTablePPN; @@ -104,6 +105,7 @@ module pagetablewalker LEVEL3, LEAF, IDLE, + START, FAULT} statetype; statetype WalkerState, NextWalkerState; @@ -122,6 +124,13 @@ module pagetablewalker assign TranslationVAdr = (SelDataTranslation) ? MemAdrM : PCF; // *** need to register TranslationVAdr assign SelDataTranslation = DTLBMissMQ | DTLBMissM; + flopenr #(`XLEN) + TranslationVAdrReg(.clk(clk), + .reset(reset), + .en(StartWalk), + .d(TranslationVAdr), + .q(TranslationVAdrQ)); + flopenrc #(1) DTLBMissMReg(.clk(clk), .reset(reset), @@ -193,14 +202,17 @@ module pagetablewalker case (WalkerState) IDLE: begin if (MMUTranslate && SvMode == `SV32) begin // *** Added SvMode - NextWalkerState = LEVEL1_WDV; - TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; - HPTWRead = 1'b1; + NextWalkerState = START; end else begin NextWalkerState = IDLE; - TranslationPAdr = '0; end end + + START: begin + NextWalkerState = LEVEL1_WDV; + TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; + HPTWRead = 1'b1; + end LEVEL1_WDV: begin TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; @@ -223,7 +235,7 @@ module pagetablewalker PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; // *** not sure about this mux? DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; + TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. else if (ValidPTE && ~LeafPTE) begin @@ -252,7 +264,7 @@ module pagetablewalker PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; + TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; end else begin NextWalkerState = FAULT; end @@ -277,8 +289,8 @@ module pagetablewalker assign MegapageMisaligned = |(CurrentPPN[9:0]); assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - assign VPN1 = TranslationVAdr[31:22]; - assign VPN0 = TranslationVAdr[21:12]; + assign VPN1 = TranslationVAdrQ[31:22]; + assign VPN0 = TranslationVAdrQ[21:12]; @@ -331,6 +343,14 @@ module pagetablewalker case (WalkerState) IDLE: begin + if (MMUTranslate && (SvMode == `SV48 || SvMode == `SV39)) begin + NextWalkerState = START; + end else begin + NextWalkerState = IDLE; + end + end + + START: begin if (MMUTranslate && SvMode == `SV48) begin NextWalkerState = LEVEL3_WDV; TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; @@ -339,7 +359,7 @@ module pagetablewalker NextWalkerState = LEVEL2_WDV; TranslationPAdr = {BasePageTablePPN, VPN2, 3'b000}; HPTWRead = 1'b1; - end else begin + end else begin // *** should not get here NextWalkerState = IDLE; TranslationPAdr = '0; end @@ -368,7 +388,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. else if (ValidPTE && ~LeafPTE) begin @@ -405,7 +425,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. else if (ValidPTE && ~LeafPTE) begin @@ -442,7 +462,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; end // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. @@ -474,7 +494,7 @@ module pagetablewalker ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); DTLBWriteM = DTLBMissMQ; ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; end else begin NextWalkerState = FAULT; end @@ -512,10 +532,10 @@ module pagetablewalker assign BadGigapage = GigapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - assign VPN3 = TranslationVAdr[47:39]; - assign VPN2 = TranslationVAdr[38:30]; - assign VPN1 = TranslationVAdr[29:21]; - assign VPN0 = TranslationVAdr[20:12]; + assign VPN3 = TranslationVAdrQ[47:39]; + assign VPN2 = TranslationVAdrQ[38:30]; + assign VPN1 = TranslationVAdrQ[29:21]; + assign VPN0 = TranslationVAdrQ[20:12]; // Capture page table entry from ahblite From 6bac566bb72da13f74e03e36f6fa28eb55962c66 Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 5 Jul 2021 20:35:31 -0400 Subject: [PATCH 3/7] Added support for TVM flag in CSRS and to disabl TLB when MEM_VIRTMEM = 0 --- wally-pipelined/config/buildroot/wally-config.vh | 2 +- wally-pipelined/config/busybear/wally-config.vh | 2 +- wally-pipelined/config/rv64imc/wally-config.vh | 2 +- wally-pipelined/src/mmu/mmu.sv | 16 ++++++++++++++-- wally-pipelined/src/privileged/csr.sv | 3 ++- wally-pipelined/src/privileged/csrs.sv | 15 ++++++++++++--- wally-pipelined/src/privileged/csrsr.sv | 6 +++--- 7 files changed, 34 insertions(+), 12 deletions(-) diff --git a/wally-pipelined/config/buildroot/wally-config.vh b/wally-pipelined/config/buildroot/wally-config.vh index cb59bb69..3a834ab0 100644 --- a/wally-pipelined/config/buildroot/wally-config.vh +++ b/wally-pipelined/config/buildroot/wally-config.vh @@ -46,7 +46,7 @@ `define MEM_DCACHE 0 `define MEM_DTIM 1 `define MEM_ICACHE 0 -`define MEM_VIRTMEM 0 +`define MEM_VIRTMEM 1 `define VECTORED_INTERRUPTS_SUPPORTED 1 // Domenico Ottolia 4/15: Support for vectored interrupts in _tvec csrs. Just implemented in src/privileged/trap.sv around line 75. Pretty sure this should be 1. `define ITLB_ENTRIES 32 diff --git a/wally-pipelined/config/busybear/wally-config.vh b/wally-pipelined/config/busybear/wally-config.vh index 26e37fa6..d3822863 100644 --- a/wally-pipelined/config/busybear/wally-config.vh +++ b/wally-pipelined/config/busybear/wally-config.vh @@ -47,7 +47,7 @@ `define MEM_DCACHE 0 `define MEM_DTIM 1 `define MEM_ICACHE 0 -`define MEM_VIRTMEM 0 +`define MEM_VIRTMEM 1 `define VECTORED_INTERRUPTS_SUPPORTED 1 // Domenico Ottolia 4/15: Support for vectored interrupts in _tvec csrs. Just implemented in src/privileged/trap.sv around line 75. Pretty sure this should be 1. `define ITLB_ENTRIES 32 diff --git a/wally-pipelined/config/rv64imc/wally-config.vh b/wally-pipelined/config/rv64imc/wally-config.vh index a554a612..925e9865 100644 --- a/wally-pipelined/config/rv64imc/wally-config.vh +++ b/wally-pipelined/config/rv64imc/wally-config.vh @@ -45,7 +45,7 @@ `define MEM_DCACHE 0 `define MEM_DTIM 1 `define MEM_ICACHE 0 -`define MEM_VIRTMEM 0 +`define MEM_VIRTMEM 1 `define VECTORED_INTERRUPTS_SUPPORTED 1 `define ITLB_ENTRIES 32 diff --git a/wally-pipelined/src/mmu/mmu.sv b/wally-pipelined/src/mmu/mmu.sv index 4faac7bc..288fb931 100644 --- a/wally-pipelined/src/mmu/mmu.sv +++ b/wally-pipelined/src/mmu/mmu.sv @@ -81,8 +81,20 @@ module mmu #(parameter TLB_ENTRIES = 8, // nuber of TLB Entries logic Cacheable, Idempotent, AtomicAllowed; // *** here so that the pmachecker has somewhere to put these outputs. *** I'm leaving them as outputs to pma checker, but I'm stopping them here. // Translation lookaside buffer - tlb #(.TLB_ENTRIES(TLB_ENTRIES), .ITLB(IMMU)) tlb(.*); - + // only instantiate TLB if Virtual Memory is supported + generate + if (`MEM_VIRTMEM) + tlb #(.TLB_ENTRIES(TLB_ENTRIES), .ITLB(IMMU)) tlb(.*); + else begin // just pass address through as physical + logic [`XLEN+1:0] VAExt; + assign VAExt = {2'b00, VirtualAddress}; // extend length of virtual address if necessary for RV32 + assign PhysicalAddress = VAExt[`PA_BITS-1:0]; + assign TLBMiss = 0; + assign TLBHit = 1; + assign TLBPageFault = 0; + end + endgenerate + /////////////////////////////////////////// // Check physical memory accesses /////////////////////////////////////////// diff --git a/wally-pipelined/src/privileged/csr.sv b/wally-pipelined/src/privileged/csr.sv index 7162263c..48e4f4ef 100644 --- a/wally-pipelined/src/privileged/csr.sv +++ b/wally-pipelined/src/privileged/csr.sv @@ -76,6 +76,7 @@ module csr #(parameter logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW; logic WriteMSTATUSM, WriteSSTATUSM, WriteUSTATUSM; logic CSRMWriteM, CSRSWriteM, CSRUWriteM; + logic STATUS_TVM; logic [`XLEN-1:0] UnalignedNextEPCM, NextEPCM, NextCauseM, NextMtvalM; @@ -109,7 +110,7 @@ module csr #(parameter assign NextCauseM = TrapM ? CauseM : CSRWriteValM; assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValM; assign CSRMWriteM = CSRWriteM && (PrivilegeModeW == `M_MODE); - assign CSRSWriteM = CSRWriteM && (PrivilegeModeW[0]); + assign CSRSWriteM = CSRWriteM && (|PrivilegeModeW); assign CSRUWriteM = CSRWriteM; csri csri(.*); diff --git a/wally-pipelined/src/privileged/csrs.sv b/wally-pipelined/src/privileged/csrs.sv index ca64b053..5a6fb96f 100644 --- a/wally-pipelined/src/privileged/csrs.sv +++ b/wally-pipelined/src/privileged/csrs.sv @@ -51,7 +51,9 @@ module csrs #(parameter input logic CSRSWriteM, STrapM, input logic [11:0] CSRAdrM, input logic [`XLEN-1:0] NextEPCM, NextCauseM, NextMtvalM, SSTATUS_REGW, + input logic STATUS_TVM, input logic [`XLEN-1:0] CSRWriteValM, + input logic [1:0] PrivilegeModeW, output logic [`XLEN-1:0] CSRSReadValM, SEPC_REGW, STVEC_REGW, output logic [31:0] SCOUNTEREN_REGW, output logic [`XLEN-1:0] SEDELEG_REGW, SIDELEG_REGW, @@ -79,7 +81,7 @@ module csrs #(parameter assign WriteSEPCM = STrapM | (CSRSWriteM && (CSRAdrM == SEPC)) && ~StallW; assign WriteSCAUSEM = STrapM | (CSRSWriteM && (CSRAdrM == SCAUSE)) && ~StallW; assign WriteSTVALM = STrapM | (CSRSWriteM && (CSRAdrM == STVAL)) && ~StallW; - assign WriteSATPM = CSRSWriteM && (CSRAdrM == SATP) && ~StallW; + assign WriteSATPM = CSRSWriteM && (CSRAdrM == SATP) && (PrivilegeModeW == `M_MODE || ~STATUS_TVM) && ~StallW; assign WriteSCOUNTERENM = CSRSWriteM && (CSRAdrM == SCOUNTEREN) && ~StallW; // CSRs @@ -88,7 +90,10 @@ module csrs #(parameter flopenr #(`XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW); flopenl #(`XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, NextCauseM, `XLEN'b0, SCAUSE_REGW); flopenr #(`XLEN) STVALreg(clk, reset, WriteSTVALM, NextMtvalM, STVAL_REGW); - flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW); + if (`MEM_VIRTMEM) + flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW); + else + assign SATP_REGW = 0; if (`BUSYBEAR == 1) flopenl #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, {CSRWriteValM[31:2],1'b0,CSRWriteValM[0]}, 32'b0, SCOUNTEREN_REGW); else if (`BUILDROOT == 1) @@ -122,7 +127,11 @@ module csrs #(parameter SEPC: CSRSReadValM = SEPC_REGW; SCAUSE: CSRSReadValM = SCAUSE_REGW; STVAL: CSRSReadValM = STVAL_REGW; - SATP: CSRSReadValM = SATP_REGW; + SATP: if (`MEM_VIRTMEM && (PrivilegeModeW == `M_MODE || ~STATUS_TVM)) CSRSReadValM = SATP_REGW; + else begin + CSRSReadValM = 0; + IllegalCSRSAccessM = 1; + end SCOUNTEREN:CSRSReadValM = {{(`XLEN-32){1'b0}}, SCOUNTEREN_REGW}; default: begin CSRSReadValM = 0; diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index 0b36df49..b02baeb9 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -38,10 +38,10 @@ module csrsr ( output logic STATUS_SPP, STATUS_TSR, output logic STATUS_MIE, STATUS_SIE, output logic STATUS_MXR, STATUS_SUM, - output logic STATUS_MPRV + output logic STATUS_MPRV, STATUS_TVM ); - logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, STATUS_MPRV_INT; + logic STATUS_SD, STATUS_TW, STATUS_SUM_INT, STATUS_MPRV_INT; logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT; logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE; @@ -96,7 +96,7 @@ module csrsr ( assign STATUS_SD = (STATUS_FS == 2'b11) || (STATUS_XS == 2'b11); // dirty state logic assign STATUS_TSR = 0; // Trap SRET not supported; revisit whether this is necessary for an OS assign STATUS_TW = 0; // Timeout Wait not supported - assign STATUS_TVM = 0; // Trap Virtual Memory not supported (revisit if supporting virtualizations) + assign STATUS_TVM = 0; // Trap Virtual Memory not supported (revisit if supporting virtualizations, but hooks in place for it in satp) assign STATUS_MXR = 0; // Make Executable Readable (may need to add support for VM later) assign STATUS_XS = 2'b00; // No additional user-mode state to be dirty From 71711c54c962bf1adba37626e32a83ebdeaf6310 Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 5 Jul 2021 23:35:44 -0400 Subject: [PATCH 4/7] Don't generate HPTW when MEM_VIRTMEM=0 --- .../config/rv64icfd/wally-config.vh | 2 +- wally-pipelined/src/mmu/pagetablewalker.sv | 893 +++++++++--------- 2 files changed, 453 insertions(+), 442 deletions(-) diff --git a/wally-pipelined/config/rv64icfd/wally-config.vh b/wally-pipelined/config/rv64icfd/wally-config.vh index 25b8cbca..a7605021 100644 --- a/wally-pipelined/config/rv64icfd/wally-config.vh +++ b/wally-pipelined/config/rv64icfd/wally-config.vh @@ -46,7 +46,7 @@ `define MEM_DCACHE 0 `define MEM_DTIM 1 `define MEM_ICACHE 0 -`define MEM_VIRTMEM 1 +`define MEM_VIRTMEM 0\1 `define VECTORED_INTERRUPTS_SUPPORTED 1 `define ITLB_ENTRIES 32 diff --git a/wally-pipelined/src/mmu/pagetablewalker.sv b/wally-pipelined/src/mmu/pagetablewalker.sv index c746696a..6357f1c6 100644 --- a/wally-pipelined/src/mmu/pagetablewalker.sv +++ b/wally-pipelined/src/mmu/pagetablewalker.sv @@ -70,484 +70,495 @@ module pagetablewalker output logic WalkerStorePageFaultM ); - // Internal signals - // register TLBs translation miss requests - logic [`XLEN-1:0] TranslationVAdrQ; - logic ITLBMissFQ, DTLBMissMQ; - - logic [`PPN_BITS-1:0] BasePageTablePPN; - logic [`XLEN-1:0] TranslationVAdr; - logic [`XLEN-1:0] SavedPTE, CurrentPTE; - logic [`PA_BITS-1:0] TranslationPAdr; - logic [`PPN_BITS-1:0] CurrentPPN; - logic [`SVMODE_BITS-1:0] SvMode; - logic MemStore; - - // PTE Control Bits - logic Dirty, Accessed, Global, User, - Executable, Writable, Readable, Valid; - // PTE descriptions - logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE; - - // Outputs of walker - logic [`XLEN-1:0] PageTableEntry; - logic [1:0] PageType; - logic StartWalk; - logic EndWalk; - - typedef enum {LEVEL0_WDV, - LEVEL0, - LEVEL1_WDV, - LEVEL1, - LEVEL2_WDV, - LEVEL2, - LEVEL3_WDV, - LEVEL3, - LEAF, - IDLE, - START, - FAULT} statetype; - - statetype WalkerState, NextWalkerState; - - logic PRegEn; - logic SelDataTranslation; - - - assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]; - - assign BasePageTablePPN = SATP_REGW[`PPN_BITS-1:0]; - - assign MemStore = MemRWM[0]; - - // Prefer data address translations over instruction address translations - assign TranslationVAdr = (SelDataTranslation) ? MemAdrM : PCF; // *** need to register TranslationVAdr - assign SelDataTranslation = DTLBMissMQ | DTLBMissM; - - flopenr #(`XLEN) - TranslationVAdrReg(.clk(clk), - .reset(reset), - .en(StartWalk), - .d(TranslationVAdr), - .q(TranslationVAdrQ)); - - flopenrc #(1) - DTLBMissMReg(.clk(clk), - .reset(reset), - .en(StartWalk | EndWalk), - .clear(EndWalk), - .d(DTLBMissM), - .q(DTLBMissMQ)); - - flopenrc #(1) - ITLBMissMReg(.clk(clk), - .reset(reset), - .en(StartWalk | EndWalk), - .clear(EndWalk), - .d(ITLBMissF), - .q(ITLBMissFQ)); - - - assign StartWalk = WalkerState == IDLE && (DTLBMissM | ITLBMissF); - assign EndWalk = WalkerState == LEAF || - //(WalkerState == LEVEL0 && ValidPTE && LeafPTE && ~AccessAlert) || - (WalkerState == LEVEL1 && ValidPTE && LeafPTE && ~AccessAlert) || - (WalkerState == LEVEL2 && ValidPTE && LeafPTE && ~AccessAlert) || - (WalkerState == LEVEL3 && ValidPTE && LeafPTE && ~AccessAlert) || - (WalkerState == FAULT); - - assign MMUTranslate = (DTLBMissMQ | ITLBMissFQ) & ~EndWalk; - //assign MMUTranslate = DTLBMissM | ITLBMissF; - - // unswizzle PTE bits - assign {Dirty, Accessed, Global, User, - Executable, Writable, Readable, Valid} = CurrentPTE[7:0]; - - // Assign PTE descriptors common across all XLEN values - assign LeafPTE = Executable | Writable | Readable; - assign ValidPTE = Valid && ~(Writable && ~Readable); - assign AccessAlert = ~Accessed | (MemStore & ~Dirty); - - // Assign specific outputs to general outputs - assign PageTableEntryF = PageTableEntry; - assign PageTableEntryM = PageTableEntry; - assign PageTypeF = PageType; - assign PageTypeM = PageType; - - generate - if (`XLEN == 32) begin - logic [9:0] VPN1, VPN0; + if (`MEM_VIRTMEM) begin + // Internal signals + // register TLBs translation miss requests + logic [`XLEN-1:0] TranslationVAdrQ; + logic ITLBMissFQ, DTLBMissMQ; + + logic [`PPN_BITS-1:0] BasePageTablePPN; + logic [`XLEN-1:0] TranslationVAdr; + logic [`XLEN-1:0] SavedPTE, CurrentPTE; + logic [`PA_BITS-1:0] TranslationPAdr; + logic [`PPN_BITS-1:0] CurrentPPN; + logic [`SVMODE_BITS-1:0] SvMode; + logic MemStore; - flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); + // PTE Control Bits + logic Dirty, Accessed, Global, User, + Executable, Writable, Readable, Valid; + // PTE descriptions + logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE; -/* -----\/----- EXCLUDED -----\/----- - assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV) && ~HPTWStall; - -----/\----- EXCLUDED -----/\----- */ + // Outputs of walker + logic [`XLEN-1:0] PageTableEntry; + logic [1:0] PageType; + logic StartWalk; + logic EndWalk; + + typedef enum {LEVEL0_WDV, + LEVEL0, + LEVEL1_WDV, + LEVEL1, + LEVEL2_WDV, + LEVEL2, + LEVEL3_WDV, + LEVEL3, + LEAF, + IDLE, + START, + FAULT} statetype; - // State transition logic - always_comb begin - PRegEn = 1'b0; - TranslationPAdr = '0; - HPTWRead = 1'b0; - PageTableEntry = '0; - PageType = '0; - DTLBWriteM = '0; - ITLBWriteF = '0; - - WalkerInstrPageFaultF = 1'b0; - WalkerLoadPageFaultM = 1'b0; - WalkerStorePageFaultM = 1'b0; + statetype WalkerState, NextWalkerState; - case (WalkerState) - IDLE: begin - if (MMUTranslate && SvMode == `SV32) begin // *** Added SvMode - NextWalkerState = START; - end else begin - NextWalkerState = IDLE; - end - end + logic PRegEn; + logic SelDataTranslation; + + + assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]; - START: begin - NextWalkerState = LEVEL1_WDV; - TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; - HPTWRead = 1'b1; - end - - LEVEL1_WDV: begin - TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; - if (HPTWStall) begin - NextWalkerState = LEVEL1_WDV; - end else begin - NextWalkerState = LEVEL1; - PRegEn = 1'b1; - end - end - - LEVEL1: begin - // *** According to the architecture, we should - // fault upon finding a superpage that is misaligned or has 0 - // access bit. The following commented line of code is - // supposed to perform that check. However, it is untested. - if (ValidPTE && LeafPTE && ~BadMegapage) begin - NextWalkerState = LEAF; - PageTableEntry = CurrentPTE; - PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; // *** not sure about this mux? - DTLBWriteM = DTLBMissMQ; - ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; - end - // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. - else if (ValidPTE && ~LeafPTE) begin - NextWalkerState = LEVEL0_WDV; - TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; - HPTWRead = 1'b1; - end else begin - NextWalkerState = FAULT; - end - end - - LEVEL0_WDV: begin - TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; - if (HPTWStall) begin - NextWalkerState = LEVEL0_WDV; - end else begin - NextWalkerState = LEVEL0; - PRegEn = 1'b1; - end - end + assign BasePageTablePPN = SATP_REGW[`PPN_BITS-1:0]; - LEVEL0: begin - if (ValidPTE & LeafPTE & ~AccessAlert) begin - NextWalkerState = LEAF; - PageTableEntry = CurrentPTE; - PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; - DTLBWriteM = DTLBMissMQ; - ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; - end else begin - NextWalkerState = FAULT; - end - end - - LEAF: begin - NextWalkerState = IDLE; - end - FAULT: begin - NextWalkerState = IDLE; - WalkerInstrPageFaultF = ~DTLBMissMQ; - WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore; - WalkerStorePageFaultM = DTLBMissMQ && MemStore; - end - - // Default case should never happen, but is included for linter. - default: NextWalkerState = IDLE; - endcase - end + assign MemStore = MemRWM[0]; - // A megapage is a Level 1 leaf page. This page must have zero PPN[0]. - assign MegapageMisaligned = |(CurrentPPN[9:0]); - assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme + // Prefer data address translations over instruction address translations + assign TranslationVAdr = (SelDataTranslation) ? MemAdrM : PCF; // *** need to register TranslationVAdr + assign SelDataTranslation = DTLBMissMQ | DTLBMissM; - assign VPN1 = TranslationVAdrQ[31:22]; - assign VPN0 = TranslationVAdrQ[21:12]; + flopenr #(`XLEN) + TranslationVAdrReg(.clk(clk), + .reset(reset), + .en(StartWalk), + .d(TranslationVAdr), + .q(TranslationVAdrQ)); + flopenrc #(1) + DTLBMissMReg(.clk(clk), + .reset(reset), + .en(StartWalk | EndWalk), + .clear(EndWalk), + .d(DTLBMissM), + .q(DTLBMissMQ)); + + flopenrc #(1) + ITLBMissMReg(.clk(clk), + .reset(reset), + .en(StartWalk | EndWalk), + .clear(EndWalk), + .d(ITLBMissF), + .q(ITLBMissFQ)); - // Capture page table entry from data cache - // *** may need to delay reading this value until the next clock cycle. - // The clk to q latency of the SRAM in the data cache will be long. - // I cannot see directly using this value. This is no different than - // a load delay hazard. This will require rewriting the walker fsm. - // also need a new signal to save. Should be a mealy output of the fsm - // request followed by ~stall. - flopenr #(32) ptereg(clk, reset, PRegEn, MMUReadPTE, SavedPTE); - //mux2 #(32) ptemux(SavedPTE, MMUReadPTE, PRegEn, CurrentPTE); - assign CurrentPTE = SavedPTE; - assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10]; - - // Assign outputs to ahblite - // *** Currently truncate address to 32 bits. This must be changed if - // we support larger physical address spaces - assign MMUPAdr = TranslationPAdr[31:0]; - - end else begin + assign StartWalk = WalkerState == IDLE && (DTLBMissM | ITLBMissF); + assign EndWalk = WalkerState == LEAF || + //(WalkerState == LEVEL0 && ValidPTE && LeafPTE && ~AccessAlert) || + (WalkerState == LEVEL1 && ValidPTE && LeafPTE && ~AccessAlert) || + (WalkerState == LEVEL2 && ValidPTE && LeafPTE && ~AccessAlert) || + (WalkerState == LEVEL3 && ValidPTE && LeafPTE && ~AccessAlert) || + (WalkerState == FAULT); - logic [8:0] VPN3, VPN2, VPN1, VPN0; + assign MMUTranslate = (DTLBMissMQ | ITLBMissFQ) & ~EndWalk; + //assign MMUTranslate = DTLBMissM | ITLBMissF; - logic TerapageMisaligned, GigapageMisaligned, BadTerapage, BadGigapage; + // unswizzle PTE bits + assign {Dirty, Accessed, Global, User, + Executable, Writable, Readable, Valid} = CurrentPTE[7:0]; - flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); + // Assign PTE descriptors common across all XLEN values + assign LeafPTE = Executable | Writable | Readable; + assign ValidPTE = Valid && ~(Writable && ~Readable); + assign AccessAlert = ~Accessed | (MemStore & ~Dirty); - /* -----\/----- EXCLUDED -----\/----- - assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV || - WalkerState == LEVEL2_WDV || WalkerState == LEVEL3_WDV) && ~HPTWStall; - -----/\----- EXCLUDED -----/\----- */ + // Assign specific outputs to general outputs + assign PageTableEntryF = PageTableEntry; + assign PageTableEntryM = PageTableEntry; + assign PageTypeF = PageType; + assign PageTypeM = PageType; - //assign HPTWRead = (WalkerState == IDLE && MMUTranslate) || WalkerState == LEVEL3 || - // WalkerState == LEVEL2 || WalkerState == LEVEL1; + +// generate + if (`XLEN == 32) begin + logic [9:0] VPN1, VPN0; + + flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); + + /* -----\/----- EXCLUDED -----\/----- + assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV) && ~HPTWStall; + -----/\----- EXCLUDED -----/\----- */ + + // State transition logic + always_comb begin + PRegEn = 1'b0; + TranslationPAdr = '0; + HPTWRead = 1'b0; + PageTableEntry = '0; + PageType = '0; + DTLBWriteM = '0; + ITLBWriteF = '0; + WalkerInstrPageFaultF = 1'b0; + WalkerLoadPageFaultM = 1'b0; + WalkerStorePageFaultM = 1'b0; - always_comb begin - PRegEn = 1'b0; - TranslationPAdr = '0; - HPTWRead = 1'b0; - PageTableEntry = '0; - PageType = '0; - DTLBWriteM = '0; - ITLBWriteF = '0; - - WalkerInstrPageFaultF = 1'b0; - WalkerLoadPageFaultM = 1'b0; - WalkerStorePageFaultM = 1'b0; + case (WalkerState) + IDLE: begin + if (MMUTranslate && SvMode == `SV32) begin // *** Added SvMode + NextWalkerState = START; + end else begin + NextWalkerState = IDLE; + end + end - case (WalkerState) - IDLE: begin - if (MMUTranslate && (SvMode == `SV48 || SvMode == `SV39)) begin - NextWalkerState = START; - end else begin - NextWalkerState = IDLE; - end - end - - START: begin - if (MMUTranslate && SvMode == `SV48) begin - NextWalkerState = LEVEL3_WDV; - TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; - HPTWRead = 1'b1; - end else if (MMUTranslate && SvMode == `SV39) begin - NextWalkerState = LEVEL2_WDV; - TranslationPAdr = {BasePageTablePPN, VPN2, 3'b000}; - HPTWRead = 1'b1; - end else begin // *** should not get here - NextWalkerState = IDLE; - TranslationPAdr = '0; - end - end - - LEVEL3_WDV: begin - TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; - if (HPTWStall) begin - NextWalkerState = LEVEL3_WDV; - end else begin - NextWalkerState = LEVEL3; - PRegEn = 1'b1; - end - end - - LEVEL3: begin - // *** According to the architecture, we should - // fault upon finding a superpage that is misaligned or has 0 - // access bit. The following commented line of code is - // supposed to perform that check. However, it is untested. - if (ValidPTE && LeafPTE && ~BadTerapage) begin - NextWalkerState = LEAF; - PageTableEntry = CurrentPTE; - PageType = (WalkerState == LEVEL3) ? 2'b11 : // *** not sure about this mux? - ((WalkerState == LEVEL2) ? 2'b10 : - ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); - DTLBWriteM = DTLBMissMQ; - ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; - end - // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. - else if (ValidPTE && ~LeafPTE) begin - NextWalkerState = LEVEL2_WDV; - TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; - HPTWRead = 1'b1; - end else begin - NextWalkerState = FAULT; - end + START: begin + NextWalkerState = LEVEL1_WDV; + TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; + HPTWRead = 1'b1; + end + + LEVEL1_WDV: begin + TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; + if (HPTWStall) begin + NextWalkerState = LEVEL1_WDV; + end else begin + NextWalkerState = LEVEL1; + PRegEn = 1'b1; + end + end + + LEVEL1: begin + // *** According to the architecture, we should + // fault upon finding a superpage that is misaligned or has 0 + // access bit. The following commented line of code is + // supposed to perform that check. However, it is untested. + if (ValidPTE && LeafPTE && ~BadMegapage) begin + NextWalkerState = LEAF; + PageTableEntry = CurrentPTE; + PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; // *** not sure about this mux? + DTLBWriteM = DTLBMissMQ; + ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions + TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; + end + // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. + else if (ValidPTE && ~LeafPTE) begin + NextWalkerState = LEVEL0_WDV; + TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; + HPTWRead = 1'b1; + end else begin + NextWalkerState = FAULT; + end + end + + LEVEL0_WDV: begin + TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; + if (HPTWStall) begin + NextWalkerState = LEVEL0_WDV; + end else begin + NextWalkerState = LEVEL0; + PRegEn = 1'b1; + end + end + LEVEL0: begin + if (ValidPTE & LeafPTE & ~AccessAlert) begin + NextWalkerState = LEAF; + PageTableEntry = CurrentPTE; + PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; + DTLBWriteM = DTLBMissMQ; + ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions + TranslationPAdr = {2'b00, TranslationVAdrQ[31:0]}; + end else begin + NextWalkerState = FAULT; + end + end + + LEAF: begin + NextWalkerState = IDLE; + end + FAULT: begin + NextWalkerState = IDLE; + WalkerInstrPageFaultF = ~DTLBMissMQ; + WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore; + WalkerStorePageFaultM = DTLBMissMQ && MemStore; + end + + // Default case should never happen, but is included for linter. + default: NextWalkerState = IDLE; + endcase end - LEVEL2_WDV: begin - TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; - //HPTWRead = 1'b1; - if (HPTWStall) begin - NextWalkerState = LEVEL2_WDV; - end else begin - NextWalkerState = LEVEL2; - PRegEn = 1'b1; - end - end + // A megapage is a Level 1 leaf page. This page must have zero PPN[0]. + assign MegapageMisaligned = |(CurrentPPN[9:0]); + assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme + + assign VPN1 = TranslationVAdrQ[31:22]; + assign VPN0 = TranslationVAdrQ[21:12]; + - LEVEL2: begin - // *** According to the architecture, we should - // fault upon finding a superpage that is misaligned or has 0 - // access bit. The following commented line of code is - // supposed to perform that check. However, it is untested. - if (ValidPTE && LeafPTE && ~BadGigapage) begin - NextWalkerState = LEAF; - PageTableEntry = CurrentPTE; - PageType = (WalkerState == LEVEL3) ? 2'b11 : - ((WalkerState == LEVEL2) ? 2'b10 : - ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); - DTLBWriteM = DTLBMissMQ; - ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; - end - // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. - else if (ValidPTE && ~LeafPTE) begin - NextWalkerState = LEVEL1_WDV; - TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; - HPTWRead = 1'b1; - end else begin - NextWalkerState = FAULT; - end + // Capture page table entry from data cache + // *** may need to delay reading this value until the next clock cycle. + // The clk to q latency of the SRAM in the data cache will be long. + // I cannot see directly using this value. This is no different than + // a load delay hazard. This will require rewriting the walker fsm. + // also need a new signal to save. Should be a mealy output of the fsm + // request followed by ~stall. + flopenr #(32) ptereg(clk, reset, PRegEn, MMUReadPTE, SavedPTE); + //mux2 #(32) ptemux(SavedPTE, MMUReadPTE, PRegEn, CurrentPTE); + assign CurrentPTE = SavedPTE; + assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10]; + + // Assign outputs to ahblite + // *** Currently truncate address to 32 bits. This must be changed if + // we support larger physical address spaces + assign MMUPAdr = TranslationPAdr[31:0]; + + end else begin + + logic [8:0] VPN3, VPN2, VPN1, VPN0; + + logic TerapageMisaligned, GigapageMisaligned, BadTerapage, BadGigapage; + + flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); + + /* -----\/----- EXCLUDED -----\/----- + assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV || + WalkerState == LEVEL2_WDV || WalkerState == LEVEL3_WDV) && ~HPTWStall; + -----/\----- EXCLUDED -----/\----- */ + + //assign HPTWRead = (WalkerState == IDLE && MMUTranslate) || WalkerState == LEVEL3 || + // WalkerState == LEVEL2 || WalkerState == LEVEL1; + + + always_comb begin + PRegEn = 1'b0; + TranslationPAdr = '0; + HPTWRead = 1'b0; + PageTableEntry = '0; + PageType = '0; + DTLBWriteM = '0; + ITLBWriteF = '0; + + WalkerInstrPageFaultF = 1'b0; + WalkerLoadPageFaultM = 1'b0; + WalkerStorePageFaultM = 1'b0; + + case (WalkerState) + IDLE: begin + if (MMUTranslate && (SvMode == `SV48 || SvMode == `SV39)) begin + NextWalkerState = START; + end else begin + NextWalkerState = IDLE; end + end - LEVEL1_WDV: begin - TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; - //HPTWRead = 1'b1; - if (HPTWStall) begin - NextWalkerState = LEVEL1_WDV; - end else begin - NextWalkerState = LEVEL1; - PRegEn = 1'b1; - end + START: begin + if (MMUTranslate && SvMode == `SV48) begin + NextWalkerState = LEVEL3_WDV; + TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; + HPTWRead = 1'b1; + end else if (MMUTranslate && SvMode == `SV39) begin + NextWalkerState = LEVEL2_WDV; + TranslationPAdr = {BasePageTablePPN, VPN2, 3'b000}; + HPTWRead = 1'b1; + end else begin // *** should not get here + NextWalkerState = IDLE; + TranslationPAdr = '0; end + end - LEVEL1: begin - // *** According to the architecture, we should - // fault upon finding a superpage that is misaligned or has 0 - // access bit. The following commented line of code is - // supposed to perform that check. However, it is untested. - if (ValidPTE && LeafPTE && ~BadMegapage) begin - NextWalkerState = LEAF; - PageTableEntry = CurrentPTE; - PageType = (WalkerState == LEVEL3) ? 2'b11 : - ((WalkerState == LEVEL2) ? 2'b10 : - ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); - DTLBWriteM = DTLBMissMQ; - ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + LEVEL3_WDV: begin + TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; + if (HPTWStall) begin + NextWalkerState = LEVEL3_WDV; + end else begin + NextWalkerState = LEVEL3; + PRegEn = 1'b1; + end + end + + LEVEL3: begin + // *** According to the architecture, we should + // fault upon finding a superpage that is misaligned or has 0 + // access bit. The following commented line of code is + // supposed to perform that check. However, it is untested. + if (ValidPTE && LeafPTE && ~BadTerapage) begin + NextWalkerState = LEAF; + PageTableEntry = CurrentPTE; + PageType = (WalkerState == LEVEL3) ? 2'b11 : // *** not sure about this mux? + ((WalkerState == LEVEL2) ? 2'b10 : + ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); + DTLBWriteM = DTLBMissMQ; + ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + end + // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. + else if (ValidPTE && ~LeafPTE) begin + NextWalkerState = LEVEL2_WDV; + TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; + HPTWRead = 1'b1; + end else begin + NextWalkerState = FAULT; + end + + end + + LEVEL2_WDV: begin + TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; + //HPTWRead = 1'b1; + if (HPTWStall) begin + NextWalkerState = LEVEL2_WDV; + end else begin + NextWalkerState = LEVEL2; + PRegEn = 1'b1; + end + end - end - // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. - else if (ValidPTE && ~LeafPTE) begin - NextWalkerState = LEVEL0_WDV; - TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; - HPTWRead = 1'b1; - end else begin - NextWalkerState = FAULT; - end + LEVEL2: begin + // *** According to the architecture, we should + // fault upon finding a superpage that is misaligned or has 0 + // access bit. The following commented line of code is + // supposed to perform that check. However, it is untested. + if (ValidPTE && LeafPTE && ~BadGigapage) begin + NextWalkerState = LEAF; + PageTableEntry = CurrentPTE; + PageType = (WalkerState == LEVEL3) ? 2'b11 : + ((WalkerState == LEVEL2) ? 2'b10 : + ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); + DTLBWriteM = DTLBMissMQ; + ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + end + // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. + else if (ValidPTE && ~LeafPTE) begin + NextWalkerState = LEVEL1_WDV; + TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; + HPTWRead = 1'b1; + end else begin + NextWalkerState = FAULT; + end + + end + + LEVEL1_WDV: begin + TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; + //HPTWRead = 1'b1; + if (HPTWStall) begin + NextWalkerState = LEVEL1_WDV; + end else begin + NextWalkerState = LEVEL1; + PRegEn = 1'b1; + end + end + + LEVEL1: begin + // *** According to the architecture, we should + // fault upon finding a superpage that is misaligned or has 0 + // access bit. The following commented line of code is + // supposed to perform that check. However, it is untested. + if (ValidPTE && LeafPTE && ~BadMegapage) begin + NextWalkerState = LEAF; + PageTableEntry = CurrentPTE; + PageType = (WalkerState == LEVEL3) ? 2'b11 : + ((WalkerState == LEVEL2) ? 2'b10 : + ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); + DTLBWriteM = DTLBMissMQ; + ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + + end + // else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line. + else if (ValidPTE && ~LeafPTE) begin + NextWalkerState = LEVEL0_WDV; + TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; + HPTWRead = 1'b1; + end else begin + NextWalkerState = FAULT; + end + end + + LEVEL0_WDV: begin + TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; + if (HPTWStall) begin + NextWalkerState = LEVEL0_WDV; + end else begin + NextWalkerState = LEVEL0; + PRegEn = 1'b1; + end + end + + LEVEL0: begin + if (ValidPTE && LeafPTE && ~AccessAlert) begin + NextWalkerState = LEAF; + PageTableEntry = CurrentPTE; + PageType = (WalkerState == LEVEL3) ? 2'b11 : + ((WalkerState == LEVEL2) ? 2'b10 : + ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); + DTLBWriteM = DTLBMissMQ; + ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions + TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; + end else begin + NextWalkerState = FAULT; + end + end + + LEAF: begin + NextWalkerState = IDLE; + end + + FAULT: begin + NextWalkerState = IDLE; + WalkerInstrPageFaultF = ~DTLBMissMQ; + WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore; + WalkerStorePageFaultM = DTLBMissMQ && MemStore; + end + + // Default case should never happen + default: begin + NextWalkerState = IDLE; + end + + endcase end - LEVEL0_WDV: begin - TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; - if (HPTWStall) begin - NextWalkerState = LEVEL0_WDV; - end else begin - NextWalkerState = LEVEL0; - PRegEn = 1'b1; - end - end + // A terapage is a level 3 leaf page. This page must have zero PPN[2], + // zero PPN[1], and zero PPN[0] + assign TerapageMisaligned = |(CurrentPPN[26:0]); + // A gigapage is a Level 2 leaf page. This page must have zero PPN[1] and + // zero PPN[0] + assign GigapageMisaligned = |(CurrentPPN[17:0]); + // A megapage is a Level 1 leaf page. This page must have zero PPN[0]. + assign MegapageMisaligned = |(CurrentPPN[8:0]); - LEVEL0: begin - if (ValidPTE && LeafPTE && ~AccessAlert) begin - NextWalkerState = LEAF; - PageTableEntry = CurrentPTE; - PageType = (WalkerState == LEVEL3) ? 2'b11 : - ((WalkerState == LEVEL2) ? 2'b10 : - ((WalkerState == LEVEL1) ? 2'b01 : 2'b00)); - DTLBWriteM = DTLBMissMQ; - ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions - TranslationPAdr = TranslationVAdrQ[`PA_BITS-1:0]; - end else begin - NextWalkerState = FAULT; - end - end - - LEAF: begin - NextWalkerState = IDLE; - end + assign BadTerapage = TerapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme + assign BadGigapage = GigapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme + assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - FAULT: begin - NextWalkerState = IDLE; - WalkerInstrPageFaultF = ~DTLBMissMQ; - WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore; - WalkerStorePageFaultM = DTLBMissMQ && MemStore; - end - - // Default case should never happen - default: begin - NextWalkerState = IDLE; - end - - endcase - end - - // A terapage is a level 3 leaf page. This page must have zero PPN[2], - // zero PPN[1], and zero PPN[0] - assign TerapageMisaligned = |(CurrentPPN[26:0]); - // A gigapage is a Level 2 leaf page. This page must have zero PPN[1] and - // zero PPN[0] - assign GigapageMisaligned = |(CurrentPPN[17:0]); - // A megapage is a Level 1 leaf page. This page must have zero PPN[0]. - assign MegapageMisaligned = |(CurrentPPN[8:0]); - - assign BadTerapage = TerapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - assign BadGigapage = GigapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme - - assign VPN3 = TranslationVAdrQ[47:39]; - assign VPN2 = TranslationVAdrQ[38:30]; - assign VPN1 = TranslationVAdrQ[29:21]; - assign VPN0 = TranslationVAdrQ[20:12]; + assign VPN3 = TranslationVAdrQ[47:39]; + assign VPN2 = TranslationVAdrQ[38:30]; + assign VPN1 = TranslationVAdrQ[29:21]; + assign VPN0 = TranslationVAdrQ[20:12]; - // Capture page table entry from ahblite - flopenr #(`XLEN) ptereg(clk, reset, PRegEn, MMUReadPTE, SavedPTE); - //mux2 #(`XLEN) ptemux(SavedPTE, MMUReadPTE, PRegEn, CurrentPTE); - assign CurrentPTE = SavedPTE; - assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10]; + // Capture page table entry from ahblite + flopenr #(`XLEN) ptereg(clk, reset, PRegEn, MMUReadPTE, SavedPTE); + //mux2 #(`XLEN) ptemux(SavedPTE, MMUReadPTE, PRegEn, CurrentPTE); + assign CurrentPTE = SavedPTE; + assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10]; - // Assign outputs to ahblite - // *** Currently truncate address to 32 bits. This must be changed if - // we support larger physical address spaces - assign MMUPAdr = {{(`XLEN-`PA_BITS){1'b0}}, TranslationPAdr[`PA_BITS-1:0]}; + // Assign outputs to ahblite + // *** Currently truncate address to 32 bits. This must be changed if + // we support larger physical address spaces + assign MMUPAdr = {{(`XLEN-`PA_BITS){1'b0}}, TranslationPAdr[`PA_BITS-1:0]}; + end + //endgenerate + end else begin + assign MMUPAdr = 0; + assign MMUTranslate = 0; + assign HPTWRead = 0; + assign WalkerInstrPageFaultF = 0; + assign WalkerLoadPageFaultM = 0; + assign WalkerStorePageFaultM = 0; end endgenerate From 8b23162d6dcfb6c95bd341a71988331b7030715e Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 5 Jul 2021 23:42:58 -0400 Subject: [PATCH 5/7] Fixed adrdecs to use Access signals for TIMs --- wally-pipelined/src/mmu/adrdecs.sv | 4 ++-- wally-pipelined/src/privileged/csrsr.sv | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/wally-pipelined/src/mmu/adrdecs.sv b/wally-pipelined/src/mmu/adrdecs.sv index 94951aad..3084b0ac 100644 --- a/wally-pipelined/src/mmu/adrdecs.sv +++ b/wally-pipelined/src/mmu/adrdecs.sv @@ -35,8 +35,8 @@ module adrdecs ( // Determine which region of physical memory (if any) is being accessed // *** eventually uncomment Access signals - adrdec boottimdec(PhysicalAddress, `BOOTTIM_BASE, `BOOTTIM_RANGE, `BOOTTIM_SUPPORTED, 1'b1/*AccessRX*/, Size, 4'b1111, SelRegions[5]); - adrdec timdec(PhysicalAddress, `TIM_BASE, `TIM_RANGE, `TIM_SUPPORTED, 1'b1/*AccessRWX*/, Size, 4'b1111, SelRegions[4]); + adrdec boottimdec(PhysicalAddress, `BOOTTIM_BASE, `BOOTTIM_RANGE, `BOOTTIM_SUPPORTED, /*1'b1*/AccessRX, Size, 4'b1111, SelRegions[5]); + adrdec timdec(PhysicalAddress, `TIM_BASE, `TIM_RANGE, `TIM_SUPPORTED, /*1'b1*/AccessRWX, Size, 4'b1111, SelRegions[4]); adrdec clintdec(PhysicalAddress, `CLINT_BASE, `CLINT_RANGE, `CLINT_SUPPORTED, AccessRW, Size, 4'b1111, SelRegions[3]); adrdec gpiodec(PhysicalAddress, `GPIO_BASE, `GPIO_RANGE, `GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[2]); adrdec uartdec(PhysicalAddress, `UART_BASE, `UART_RANGE, `UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[1]); diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index b02baeb9..f918290a 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -112,6 +112,7 @@ module csrsr ( STATUS_SUM_INT <= #1 0; STATUS_MPRV_INT <= #1 0; // Per Priv 3.3 STATUS_FS_INT <= #1 0; //2'b01; // busybear: change all these reset values to 0 + //STATUS_TVM_INT <= #1 0; // when S_SUPPORTED STATUS_MPP <= #1 0; //`M_MODE; STATUS_SPP <= #1 0; //1'b1; STATUS_MPIE <= #1 0; //1; @@ -125,6 +126,7 @@ module csrsr ( STATUS_SUM_INT <= #1 CSRWriteValM[18]; STATUS_MPRV_INT <= #1 CSRWriteValM[17]; STATUS_FS_INT <= #1 CSRWriteValM[14:13]; + //STATUS_TVM_INT <= #1 CSRWriteValM[] STATUS_MPP <= #1 STATUS_MPP_NEXT; STATUS_SPP <= #1 `S_SUPPORTED & CSRWriteValM[8]; STATUS_MPIE <= #1 CSRWriteValM[7]; From f805aea236438050a8c8cb8cbbfff0f8e4d77598 Mon Sep 17 00:00:00 2001 From: David Harris Date: Tue, 6 Jul 2021 01:32:05 -0400 Subject: [PATCH 6/7] Implemented TSR, TW, TVM, MXR status bits --- wally-pipelined/src/privileged/csr.sv | 2 +- wally-pipelined/src/privileged/csrs.sv | 2 +- wally-pipelined/src/privileged/csrsr.sv | 96 ++++++++++---------- wally-pipelined/src/privileged/privdec.sv | 4 +- wally-pipelined/src/privileged/privileged.sv | 19 ++-- 5 files changed, 67 insertions(+), 56 deletions(-) diff --git a/wally-pipelined/src/privileged/csr.sv b/wally-pipelined/src/privileged/csr.sv index 48e4f4ef..a618e8d6 100644 --- a/wally-pipelined/src/privileged/csr.sv +++ b/wally-pipelined/src/privileged/csr.sv @@ -58,7 +58,7 @@ module csr #(parameter output logic [`XLEN-1:0] SATP_REGW, output logic [11:0] MIP_REGW, MIE_REGW, SIP_REGW, SIE_REGW, output logic STATUS_MIE, STATUS_SIE, - output logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, + output logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, STATUS_TW, output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0], output var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0], input logic [4:0] SetFflagsM, diff --git a/wally-pipelined/src/privileged/csrs.sv b/wally-pipelined/src/privileged/csrs.sv index 5a6fb96f..0daaf4f5 100644 --- a/wally-pipelined/src/privileged/csrs.sv +++ b/wally-pipelined/src/privileged/csrs.sv @@ -130,7 +130,7 @@ module csrs #(parameter SATP: if (`MEM_VIRTMEM && (PrivilegeModeW == `M_MODE || ~STATUS_TVM)) CSRSReadValM = SATP_REGW; else begin CSRSReadValM = 0; - IllegalCSRSAccessM = 1; + if (PrivilegeModeW == `S_MODE & STATUS_TVM) IllegalCSRSAccessM = 1; end SCOUNTEREN:CSRSReadValM = {{(`XLEN-32){1'b0}}, SCOUNTEREN_REGW}; default: begin diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index f918290a..30c41c0c 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -35,13 +35,13 @@ module csrsr ( input logic [`XLEN-1:0] CSRWriteValM, output logic [`XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, USTATUS_REGW, output logic [1:0] STATUS_MPP, - output logic STATUS_SPP, STATUS_TSR, + output logic STATUS_SPP, STATUS_TSR, STATUS_TW, output logic STATUS_MIE, STATUS_SIE, output logic STATUS_MXR, STATUS_SUM, output logic STATUS_MPRV, STATUS_TVM ); - - logic STATUS_SD, STATUS_TW, STATUS_SUM_INT, STATUS_MPRV_INT; + + logic STATUS_SD, STATUS_TW_INT, STATUS_TSR_INT, STATUS_TVM_INT, STATUS_MXR_INT, STATUS_SUM_INT, STATUS_MPRV_INT; logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT; logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE; @@ -86,18 +86,18 @@ module csrsr ( // harwired STATUS bits generate + assign STATUS_TSR = `S_SUPPORTED & STATUS_TSR_INT; // override reigster with 0 if supervisor mode not supported + assign STATUS_TW = (`S_SUPPORTED | `U_SUPPORTED) & STATUS_TW_INT; // override reigster with 0 if only machine mode supported + assign STATUS_TVM = `S_SUPPORTED & STATUS_TVM_INT; // override reigster with 0 if supervisor mode not supported + assign STATUS_MXR = `S_SUPPORTED & STATUS_MXR_INT; // override reigster with 0 if supervisor mode not supported // SXL and UXL bits only matter for RV64. Set to 10 for RV64 if mode is supported, or 0 if not assign STATUS_SXL = `S_SUPPORTED ? 2'b10 : 2'b00; // 10 if supervisor mode supported assign STATUS_UXL = `U_SUPPORTED ? 2'b10 : 2'b00; // 10 if user mode supported - assign STATUS_SUM = `S_SUPPORTED & STATUS_SUM_INT; // override reigster with 0 if supervisor mode not supported + assign STATUS_SUM = `S_SUPPORTED & `MEM_VIRTMEM & STATUS_SUM_INT; // override reigster with 0 if supervisor mode not supported assign STATUS_MPRV = `U_SUPPORTED & STATUS_MPRV_INT; // override with 0 if user mode not supported assign STATUS_FS = (`S_SUPPORTED && (`F_SUPPORTED || `D_SUPPORTED)) ? STATUS_FS_INT : 2'b00; // off if no FP endgenerate assign STATUS_SD = (STATUS_FS == 2'b11) || (STATUS_XS == 2'b11); // dirty state logic - assign STATUS_TSR = 0; // Trap SRET not supported; revisit whether this is necessary for an OS - assign STATUS_TW = 0; // Timeout Wait not supported - assign STATUS_TVM = 0; // Trap Virtual Memory not supported (revisit if supporting virtualizations, but hooks in place for it in satp) - assign STATUS_MXR = 0; // Make Executable Readable (may need to add support for VM later) assign STATUS_XS = 2'b00; // No additional user-mode state to be dirty always_comb @@ -109,10 +109,13 @@ module csrsr ( // complex register with reset, write enable, and the ability to update other bits in certain cases always_ff @(posedge clk, posedge reset) if (reset) begin + STATUS_TSR_INT <= #1 0; + STATUS_TW_INT <= #1 0; + STATUS_TVM_INT <= #1 0; + STATUS_MXR_INT <= #1 0; STATUS_SUM_INT <= #1 0; STATUS_MPRV_INT <= #1 0; // Per Priv 3.3 STATUS_FS_INT <= #1 0; //2'b01; // busybear: change all these reset values to 0 - //STATUS_TVM_INT <= #1 0; // when S_SUPPORTED STATUS_MPP <= #1 0; //`M_MODE; STATUS_SPP <= #1 0; //1'b1; STATUS_MPIE <= #1 0; //1; @@ -122,11 +125,45 @@ module csrsr ( STATUS_SIE <= #1 0; //`S_SUPPORTED; STATUS_UIE <= #1 0; //`U_SUPPORTED; end else if (~StallW) begin - if (WriteMSTATUSM) begin + if (FloatRegWriteW) STATUS_FS_INT <= #12'b11; // mark Float State dirty *** this should happen in M stage, be part of if/else + if (TrapM) begin + // Update interrupt enables per Privileged Spec p. 21 + // y = PrivilegeModeW + // x = NextPrivilegeModeM + // Modes: 11 = Machine, 01 = Supervisor, 00 = User + if (NextPrivilegeModeM == `M_MODE) begin + STATUS_MPIE <= #1 STATUS_MIE; + STATUS_MIE <= #1 0; + STATUS_MPP <= #1 PrivilegeModeW; + end else if (NextPrivilegeModeM == `S_MODE) begin + STATUS_SPIE <= #1 STATUS_SIE; + STATUS_SIE <= #1 0; + STATUS_SPP <= #1 PrivilegeModeW[0]; // *** seems to disagree with P. 56 + end else begin // user mode + STATUS_UPIE <= #1 STATUS_UIE; + STATUS_UIE <= #1 0; + end + end else if (mretM) begin // Privileged 3.1.6.1 + STATUS_MIE <= #1 STATUS_MPIE; + STATUS_MPIE <= #1 1; + STATUS_MPP <= #1 `U_SUPPORTED ? `U_MODE : `M_MODE; // per spec, not sure why + STATUS_MPRV_INT <= #1 0; // per 20210108 draft spec + end else if (sretM) begin + STATUS_SIE <= #1 STATUS_SPIE; + STATUS_SPIE <= #1 `S_SUPPORTED; + STATUS_SPP <= #1 0; // Privileged 4.1.1 + STATUS_MPRV_INT <= #1 0; // per 20210108 draft spec + end else if (uretM) begin + STATUS_UIE <= #1 STATUS_UPIE; + STATUS_UPIE <= #1 `U_SUPPORTED; + end else if (WriteMSTATUSM) begin + STATUS_TSR_INT <= #1 CSRWriteValM[22]; + STATUS_TW_INT <= #1 CSRWriteValM[21]; + STATUS_TVM_INT <= #1 CSRWriteValM[20]; + STATUS_MXR_INT <= #1 CSRWriteValM[19]; STATUS_SUM_INT <= #1 CSRWriteValM[18]; STATUS_MPRV_INT <= #1 CSRWriteValM[17]; STATUS_FS_INT <= #1 CSRWriteValM[14:13]; - //STATUS_TVM_INT <= #1 CSRWriteValM[] STATUS_MPP <= #1 STATUS_MPP_NEXT; STATUS_SPP <= #1 `S_SUPPORTED & CSRWriteValM[8]; STATUS_MPIE <= #1 CSRWriteValM[7]; @@ -136,6 +173,7 @@ module csrsr ( STATUS_SIE <= #1 `S_SUPPORTED & CSRWriteValM[1]; STATUS_UIE <= #1 `U_SUPPORTED & CSRWriteValM[0]; end else if (WriteSSTATUSM) begin // write a subset of the STATUS bits + STATUS_MXR_INT <= #1 CSRWriteValM[19]; STATUS_SUM_INT <= #1 CSRWriteValM[18]; STATUS_FS_INT <= #1 CSRWriteValM[14:13]; STATUS_SPP <= #1 `S_SUPPORTED & CSRWriteValM[8]; @@ -147,40 +185,6 @@ module csrsr ( STATUS_FS_INT <= #1 CSRWriteValM[14:13]; STATUS_UPIE <= #1 `U_SUPPORTED & CSRWriteValM[4]; STATUS_UIE <= #1 `U_SUPPORTED & CSRWriteValM[0]; - end else begin - if (FloatRegWriteW) STATUS_FS_INT <= #12'b11; // mark Float State dirty - if (TrapM) begin - // Update interrupt enables per Privileged Spec p. 21 - // y = PrivilegeModeW - // x = NextPrivilegeModeM - // Modes: 11 = Machine, 01 = Supervisor, 00 = User - if (NextPrivilegeModeM == `M_MODE) begin - STATUS_MPIE <= #1 STATUS_MIE; - STATUS_MIE <= #1 0; - STATUS_MPP <= #1 PrivilegeModeW; - end else if (NextPrivilegeModeM == `S_MODE) begin - STATUS_SPIE <= #1 STATUS_SIE; - STATUS_SIE <= #1 0; - STATUS_SPP <= #1 PrivilegeModeW[0]; // *** seems to disagree with P. 56 - end else begin // user mode - STATUS_UPIE <= #1 STATUS_UIE; - STATUS_UIE <= #1 0; - end - end else if (mretM) begin // Privileged 3.1.6.1 - STATUS_MIE <= #1 STATUS_MPIE; - STATUS_MPIE <= #1 1; - STATUS_MPP <= #1 `U_SUPPORTED ? `U_MODE : `M_MODE; // per spec, not sure why - STATUS_MPRV_INT <= #1 0; // per 20210108 draft spec - end else if (sretM) begin - STATUS_SIE <= #1 STATUS_SPIE; - STATUS_SPIE <= #1 `S_SUPPORTED; - STATUS_SPP <= #1 0; // Privileged 4.1.1 - STATUS_MPRV_INT <= #1 0; // per 20210108 draft spec - end else if (uretM) begin - STATUS_UIE <= #1 STATUS_UPIE; - STATUS_UPIE <= #1 `U_SUPPORTED; - end - // *** add code to track STATUS_FS_INT for dirty floating point registers - end + end end endmodule diff --git a/wally-pipelined/src/privileged/privdec.sv b/wally-pipelined/src/privileged/privdec.sv index 621ef9a2..ec01f414 100644 --- a/wally-pipelined/src/privileged/privdec.sv +++ b/wally-pipelined/src/privileged/privdec.sv @@ -28,7 +28,7 @@ module privdec ( input logic [31:20] InstrM, - input logic PrivilegedM, IllegalIEUInstrFaultM, IllegalCSRAccessM, IllegalFPUInstrM, + input logic PrivilegedM, IllegalIEUInstrFaultM, IllegalCSRAccessM, IllegalFPUInstrM, TrappedSRETM, input logic [1:0] PrivilegeModeW, input logic STATUS_TSR, output logic IllegalInstrFaultM, @@ -47,7 +47,7 @@ module privdec ( assign wfiM = PrivilegedM & (InstrM[31:20] == 12'b000100000101); assign sfencevmaM = PrivilegedM & (InstrM[31:25] == 7'b0001001); assign IllegalPrivilegedInstrM = PrivilegedM & ~(uretM|sretM|mretM|ecallM|ebreakM|wfiM|sfencevmaM); - assign IllegalInstrFaultM = (IllegalIEUInstrFaultM & IllegalFPUInstrM) | IllegalPrivilegedInstrM | IllegalCSRAccessM; // *** generalize this for other instructions + assign IllegalInstrFaultM = (IllegalIEUInstrFaultM & IllegalFPUInstrM) | IllegalPrivilegedInstrM | IllegalCSRAccessM | TrappedSRETM; // *** generalize this for other instructions // *** initially, wfi and sfencevma are nop // *** zfenci extension? diff --git a/wally-pipelined/src/privileged/privileged.sv b/wally-pipelined/src/privileged/privileged.sv index 90830137..d34c47ef 100644 --- a/wally-pipelined/src/privileged/privileged.sv +++ b/wally-pipelined/src/privileged/privileged.sv @@ -89,13 +89,13 @@ module privileged ( logic InstrPageFaultF, InstrPageFaultD, InstrPageFaultE, InstrPageFaultM; logic InstrAccessFaultF, InstrAccessFaultD, InstrAccessFaultE, InstrAccessFaultM; logic LoadAccessFaultM, StoreAccessFaultM; - logic IllegalInstrFaultM; + logic IllegalInstrFaultM, TrappedSRETM; logic BreakpointFaultM, EcallFaultM; logic MTrapM, STrapM, UTrapM; logic InterruptM; - logic STATUS_SPP, STATUS_TSR; + logic STATUS_SPP, STATUS_TSR, STATUS_TW; logic STATUS_MIE, STATUS_SIE; logic [11:0] MIP_REGW, MIE_REGW, SIP_REGW, SIE_REGW; logic md, sd; @@ -112,10 +112,14 @@ module privileged ( assign sd = CauseM[`XLEN-1] ? SIDELEG_REGW[CauseM[`LOG_XLEN-1:0]] : SEDELEG_REGW[CauseM[`LOG_XLEN-1:0]]; // depricated // PrivilegeMode FSM - always_comb - /* if (reset) NextPrivilegeModeM = `M_MODE; // Privilege resets to 11 (Machine Mode) // moved reset to flop - else */ if (mretM) NextPrivilegeModeM = STATUS_MPP; - else if (sretM) NextPrivilegeModeM = {1'b0, STATUS_SPP}; + always_comb begin + TrappedSRETM = 0; + if (mretM) NextPrivilegeModeM = STATUS_MPP; + else if (sretM) + if (STATUS_TSR & PrivilegeModeW == `S_MODE) begin + TrappedSRETM = 1; + NextPrivilegeModeM = PrivilegeModeW; + end else NextPrivilegeModeM = {1'b0, STATUS_SPP}; else if (uretM) NextPrivilegeModeM = `U_MODE; else if (TrapM) begin // Change privilege based on DELEG registers (see 3.1.8) if (PrivilegeModeW == `U_MODE) @@ -127,6 +131,8 @@ module privileged ( else NextPrivilegeModeM = `M_MODE; else NextPrivilegeModeM = `M_MODE; end else NextPrivilegeModeM = PrivilegeModeW; + end + // *** WFI could be implemented here and depends on TW flopenl #(2) privmodereg(clk, reset, ~StallW, NextPrivilegeModeM, `M_MODE, PrivilegeModeW); @@ -171,6 +177,7 @@ module privileged ( flopenrc #(4) faultregM(clk, reset, FlushM, ~StallM, {IllegalIEUInstrFaultE, InstrPageFaultE, InstrAccessFaultE, IllegalFPUInstrE}, {IllegalIEUInstrFaultM, InstrPageFaultM, InstrAccessFaultM, IllegalFPUInstrM}); + // *** it should be possible to compbine some of these faults earlier to reduce module boundary crossings and save flops dh 5 july 2021 trap trap(.*); From 694badcc6bc0d33fd6ce596cb88d39dacc59d8f6 Mon Sep 17 00:00:00 2001 From: David Harris Date: Tue, 6 Jul 2021 03:25:11 -0400 Subject: [PATCH 7/7] Created tlbcontrol module to hide details --- wally-pipelined/src/ifu/ifu.sv | 5 +- wally-pipelined/src/lsu/lsu.sv | 5 +- wally-pipelined/src/mmu/mmu.sv | 10 ++- wally-pipelined/src/mmu/tlb.sv | 57 +------------- wally-pipelined/src/mmu/tlbcontrol.sv | 109 ++++++++++++++++++++++++++ wally-pipelined/src/mmu/tlbram.sv | 4 +- 6 files changed, 125 insertions(+), 65 deletions(-) create mode 100644 wally-pipelined/src/mmu/tlbcontrol.sv diff --git a/wally-pipelined/src/ifu/ifu.sv b/wally-pipelined/src/ifu/ifu.sv index 24952edf..fd927ca6 100644 --- a/wally-pipelined/src/ifu/ifu.sv +++ b/wally-pipelined/src/ifu/ifu.sv @@ -117,10 +117,9 @@ module ifu ( endgenerate mmu #(.TLB_ENTRIES(`ITLB_ENTRIES), .IMMU(1)) - itlb(.TLBAccessType(2'b10), - .VirtualAddress(PCF), + itlb(.VirtualAddress(PCF), .Size(2'b10), - .PTEWriteVal(PageTableEntryF), + .PTE(PageTableEntryF), .PageTypeWriteVal(PageTypeF), .TLBWrite(ITLBWriteF), .TLBFlush(ITLBFlushF), diff --git a/wally-pipelined/src/lsu/lsu.sv b/wally-pipelined/src/lsu/lsu.sv index a2bcf52b..ffd96be9 100644 --- a/wally-pipelined/src/lsu/lsu.sv +++ b/wally-pipelined/src/lsu/lsu.sv @@ -218,10 +218,9 @@ module lsu ( mmu #(.TLB_ENTRIES(`DTLB_ENTRIES), .IMMU(0)) - dmmu(.TLBAccessType(MemRWMtoLSU), - .VirtualAddress(MemAdrMtoLSU), + dmmu(.VirtualAddress(MemAdrMtoLSU), .Size(SizeToLSU[1:0]), - .PTEWriteVal(PageTableEntryM), + .PTE(PageTableEntryM), .PageTypeWriteVal(PageTypeM), .TLBWrite(DTLBWriteM), .TLBFlush(DTLBFlushM), diff --git a/wally-pipelined/src/mmu/mmu.sv b/wally-pipelined/src/mmu/mmu.sv index 288fb931..d6d8fb15 100644 --- a/wally-pipelined/src/mmu/mmu.sv +++ b/wally-pipelined/src/mmu/mmu.sv @@ -42,7 +42,6 @@ module mmu #(parameter TLB_ENTRIES = 8, // nuber of TLB Entries // 1x - TLB is accessed for a read (or an instruction) // x1 - TLB is accessed for a write // 11 - TLB is accessed for both read and write - input logic [1:0] TLBAccessType, input logic DisableTranslation, // Virtual address input @@ -50,7 +49,7 @@ module mmu #(parameter TLB_ENTRIES = 8, // nuber of TLB Entries input logic [1:0] Size, // 00 = 8 bits, 01 = 16 bits, 10 = 32 bits , 11 = 64 bits // Controls for writing a new entry to the TLB - input logic [`XLEN-1:0] PTEWriteVal, + input logic [`XLEN-1:0] PTE, input logic [1:0] PageTypeWriteVal, input logic TLBWrite, @@ -83,9 +82,12 @@ module mmu #(parameter TLB_ENTRIES = 8, // nuber of TLB Entries // only instantiate TLB if Virtual Memory is supported generate - if (`MEM_VIRTMEM) + if (`MEM_VIRTMEM) begin + logic ReadAccess, WriteAccess; + assign ReadAccess = ExecuteAccessF | ReadAccessM; // execute also acts as a TLB read. Execute and Read are never active for the same MMU, so safe to mix pipestages + assign WriteAccess = WriteAccessM; tlb #(.TLB_ENTRIES(TLB_ENTRIES), .ITLB(IMMU)) tlb(.*); - else begin // just pass address through as physical + end else begin // just pass address through as physical logic [`XLEN+1:0] VAExt; assign VAExt = {2'b00, VirtualAddress}; // extend length of virtual address if necessary for RV32 assign PhysicalAddress = VAExt[`PA_BITS-1:0]; diff --git a/wally-pipelined/src/mmu/tlb.sv b/wally-pipelined/src/mmu/tlb.sv index 34400647..d16a97a4 100644 --- a/wally-pipelined/src/mmu/tlb.sv +++ b/wally-pipelined/src/mmu/tlb.sv @@ -65,14 +65,14 @@ module tlb #(parameter TLB_ENTRIES = 8, // 1x - TLB is accessed for a read (or an instruction) // x1 - TLB is accessed for a write // 11 - TLB is accessed for both read and write - input logic [1:0] TLBAccessType, + input logic ReadAccess, WriteAccess, input logic DisableTranslation, // Virtual address input input logic [`XLEN-1:0] VirtualAddress, // Controls for writing a new entry to the TLB - input logic [`XLEN-1:0] PTEWriteVal, + input logic [`XLEN-1:0] PTE, input logic [1:0] PageTypeWriteVal, input logic TLBWrite, @@ -89,7 +89,6 @@ module tlb #(parameter TLB_ENTRIES = 8, ); logic Translate; - logic TLBAccess, ReadAccess, WriteAccess; // Store current virtual memory mode (SV32, SV39, SV48, ect...) logic [`SVMODE_BITS-1:0] SvMode; @@ -111,13 +110,9 @@ module tlb #(parameter TLB_ENTRIES = 8, logic [1:0] HitPageType; logic CAMHit; logic [`ASID_BITS-1:0] ASID; - logic DAFault; // Grab the sv mode from SATP and determine whether translation should occur - assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]; assign ASID = SATP_REGW[`ASID_BASE+`ASID_BITS-1:`ASID_BASE]; - assign EffectivePrivilegeMode = (ITLB == 1) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1 - assign Translate = (SvMode != `NO_TRANSLATE) & (EffectivePrivilegeMode != `M_MODE) & ~ DisableTranslation; // Determine whether to write TLB assign WriteEnables = WriteLines & {(TLB_ENTRIES){TLBWrite}}; @@ -135,11 +130,7 @@ module tlb #(parameter TLB_ENTRIES = 8, end endgenerate - // Determine how the TLB is currently being used - // Note that we use ReadAccess for both loads and instruction fetches - assign ReadAccess = TLBAccessType[1]; - assign WriteAccess = TLBAccessType[0]; - assign TLBAccess = ReadAccess || WriteAccess; + tlbcontrol tlbcontrol(.*); // TLB entries are evicted according to the LRU algorithm tlblru #(TLB_ENTRIES) lru(.*); @@ -153,50 +144,10 @@ module tlb #(parameter TLB_ENTRIES = 8, // For superpages, some segments are considered offsets into a larger page. tlbphysicalpagemask PageMask(VirtualPageNumber, PhysicalPageNumber, HitPageType, PhysicalPageNumberMixed); - // unswizzle useful PTE bits - assign {PTE_D, PTE_A} = PTEAccessBits[7:6]; - assign {PTE_U, PTE_X, PTE_W, PTE_R} = PTEAccessBits[4:1]; - - // Check whether the access is allowed, page faulting if not. - generate - if (ITLB == 1) begin - logic ImproperPrivilege; - - // User mode may only execute user mode pages, and supervisor mode may - // only execute non-user mode pages. - assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) && ~PTE_U) || - ((EffectivePrivilegeMode == `S_MODE) && PTE_U); - // fault for software handling if access bit is off - assign DAFault = ~PTE_A; - assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || ~PTE_X || DAFault); - end else begin - logic ImproperPrivilege, InvalidRead, InvalidWrite; - - // User mode may only load/store from user mode pages, and supervisor mode - // may only access user mode pages when STATUS_SUM is low. - assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) && ~PTE_U) || - ((EffectivePrivilegeMode == `S_MODE) && PTE_U && ~STATUS_SUM); - // Check for read error. Reads are invalid when the page is not readable - // (and executable pages are not readable) or when the page is neither - // readable nor executable (and executable pages are readable). - assign InvalidRead = ReadAccess && ~PTE_R && (~STATUS_MXR | ~PTE_X); - // Check for write error. Writes are invalid when the page's write bit is - // low. - assign InvalidWrite = WriteAccess && ~PTE_W; - // Fault for software handling if access bit is off or writing a page with dirty bit off - assign DAFault = ~PTE_A | WriteAccess & ~PTE_D; - assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || InvalidRead || InvalidWrite || DAFault); - end - endgenerate - - // Output the hit physical address if translation is currently on. // Provide physical address of zero if not TLBHits, to cause segmentation error if miss somehow percolated through signal assign VAExt = {2'b00, VirtualAddress}; // extend length of virtual address if necessary for RV32 assign PageOffset = VirtualAddress[11:0]; - assign PhysicalAddressFull = TLBHit ? {PhysicalPageNumberMixed, PageOffset} : '0; + assign PhysicalAddressFull = TLBHit ? {PhysicalPageNumberMixed, PageOffset} : '0; // *** in block diagram TLB just works on page numbers mux2 #(`PA_BITS) addressmux(VAExt[`PA_BITS-1:0], PhysicalAddressFull, Translate, PhysicalAddress); - - assign TLBHit = CAMHit & TLBAccess; - assign TLBMiss = ~TLBHit & ~TLBFlush & Translate & TLBAccess; endmodule diff --git a/wally-pipelined/src/mmu/tlbcontrol.sv b/wally-pipelined/src/mmu/tlbcontrol.sv new file mode 100644 index 00000000..21f42dae --- /dev/null +++ b/wally-pipelined/src/mmu/tlbcontrol.sv @@ -0,0 +1,109 @@ +/////////////////////////////////////////// +// tlbcontrol.sv +// +// Written: David_Harris@hmc.edu 5 July 2021 +// Modified: +// +// Purpose: Control signals for TLB +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +`include "wally-config.vh" + +// The TLB will have 2**ENTRY_BITS total entries +module tlbcontrol #(parameter TLB_ENTRIES = 8, + parameter ITLB = 0) ( +// input logic clk, reset, + + // Current value of satp CSR (from privileged unit) + input logic [`XLEN-1:0] SATP_REGW, + input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, + input logic [1:0] STATUS_MPP, + input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor + + // 00 - TLB is not being accessed + // 1x - TLB is accessed for a read (or an instruction) + // x1 - TLB is accessed for a write + // 11 - TLB is accessed for both read and write + input logic ReadAccess, WriteAccess, + input logic DisableTranslation, + input logic TLBFlush, // Invalidate all TLB entries + input logic [7:0] PTEAccessBits, + input logic CAMHit, + output logic TLBMiss, + output logic TLBHit, + output logic TLBPageFault, + output logic [1:0] EffectivePrivilegeMode, + output logic [`SVMODE_BITS-1:0] SvMode, + output logic Translate +); + + // Sections of the page table entry + logic [11:0] PageOffset; + + logic PTE_D, PTE_A, PTE_U, PTE_X, PTE_W, PTE_R; // Useful PTE Control Bits + logic DAFault; + logic TLBAccess; + + // Grab the sv mode from SATP and determine whether translation should occur + assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]; + assign EffectivePrivilegeMode = (ITLB == 1) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1 + assign Translate = (SvMode != `NO_TRANSLATE) & (EffectivePrivilegeMode != `M_MODE) & ~ DisableTranslation; + + // Determine whether TLB is being used + assign TLBAccess = ReadAccess || WriteAccess; + + // unswizzle useful PTE bits + assign {PTE_D, PTE_A} = PTEAccessBits[7:6]; + assign {PTE_U, PTE_X, PTE_W, PTE_R} = PTEAccessBits[4:1]; + + // Check whether the access is allowed, page faulting if not. + generate + if (ITLB == 1) begin + logic ImproperPrivilege; + + // User mode may only execute user mode pages, and supervisor mode may + // only execute non-user mode pages. + assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) && ~PTE_U) || + ((EffectivePrivilegeMode == `S_MODE) && PTE_U); + // fault for software handling if access bit is off + assign DAFault = ~PTE_A; + assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || ~PTE_X || DAFault); + end else begin + logic ImproperPrivilege, InvalidRead, InvalidWrite; + + // User mode may only load/store from user mode pages, and supervisor mode + // may only access user mode pages when STATUS_SUM is low. + assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) && ~PTE_U) || + ((EffectivePrivilegeMode == `S_MODE) && PTE_U && ~STATUS_SUM); + // Check for read error. Reads are invalid when the page is not readable + // (and executable pages are not readable) or when the page is neither + // readable nor executable (and executable pages are readable). + assign InvalidRead = ReadAccess && ~PTE_R && (~STATUS_MXR | ~PTE_X); + // Check for write error. Writes are invalid when the page's write bit is + // low. + assign InvalidWrite = WriteAccess && ~PTE_W; + // Fault for software handling if access bit is off or writing a page with dirty bit off + assign DAFault = ~PTE_A | WriteAccess & ~PTE_D; + assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || InvalidRead || InvalidWrite || DAFault); + end + endgenerate + + assign TLBHit = CAMHit & TLBAccess; + assign TLBMiss = ~TLBHit & ~TLBFlush & Translate & TLBAccess; +endmodule diff --git a/wally-pipelined/src/mmu/tlbram.sv b/wally-pipelined/src/mmu/tlbram.sv index 98650d0b..3aa5e65e 100644 --- a/wally-pipelined/src/mmu/tlbram.sv +++ b/wally-pipelined/src/mmu/tlbram.sv @@ -29,7 +29,7 @@ module tlbram #(parameter TLB_ENTRIES = 8) ( input logic clk, reset, - input logic [`XLEN-1:0] PTEWriteVal, + input logic [`XLEN-1:0] PTE, input logic [TLB_ENTRIES-1:0] ReadLines, WriteEnables, output logic [`PPN_BITS-1:0] PhysicalPageNumber, output logic [7:0] PTEAccessBits, @@ -40,7 +40,7 @@ module tlbram #(parameter TLB_ENTRIES = 8) ( logic [`XLEN-1:0] PageTableEntry; // Generate a flop for every entry in the RAM - tlbramline #(`XLEN) tlblineram[TLB_ENTRIES-1:0](clk, reset, ReadLines, WriteEnables, PTEWriteVal, RamRead, PTE_G); + tlbramline #(`XLEN) tlblineram[TLB_ENTRIES-1:0](clk, reset, ReadLines, WriteEnables, PTE, RamRead, PTE_G); assign PageTableEntry = RamRead.or; // OR each column of RAM read to read PTE assign PTEAccessBits = PageTableEntry[7:0];