cvw/wally-pipelined/src/lsu/lsu.sv
Ross Thompson 32ec457e09 Removed the hardware page table walker fault state from the icache so that the icache will only unstall CPU for 1 cycle.
In the dcache we added a register to save the load read data in the event an itlb miss occurs concurrently with
the load in the memory stage.  Under this situation we need to record the load ReadDataM into a temporary register,
SavedReadDataM.  At this time the CPU is stall; however the walker is going to change the address in the dcache
which destroys this data.  When leaving the PTW_READY state via a walker instruction fault or ITLB write we select
this SavedReadDataM so that the CPU can capture it.
2021-07-22 19:42:19 -05:00

444 lines
14 KiB
Systemverilog

///////////////////////////////////////////
// lsu.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
// Modified:
//
// Purpose: Load/Store Unit
// Top level of the memory-stage hart logic
// Contains data cache, DTLB, subword read/write datapath, interface to external bus
//
// 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"
// *** Ross Thompson amo misalignment check?
module lsu
(
input logic clk, reset,
input logic StallM, FlushM, StallW, FlushW,
output logic LSUStall,
// Memory Stage
// connected to cpu (controls)
input logic [1:0] MemRWM,
input logic [2:0] Funct3M,
input logic [6:0] Funct7M,
input logic [1:0] AtomicM,
input logic ExceptionM,
input logic PendingInterruptM,
output logic CommittedM,
output logic SquashSCW,
output logic DataMisalignedM,
output logic DCacheMiss,
output logic DCacheAccess,
// address and write data
input logic [`XLEN-1:0] MemAdrM,
input logic [`XLEN-1:0] MemAdrE,
input logic [`XLEN-1:0] WriteDataM,
output logic [`XLEN-1:0] ReadDataM,
// cpu privilege
input logic [1:0] PrivilegeModeW,
input logic DTLBFlushM,
// faults
output logic DTLBLoadPageFaultM, DTLBStorePageFaultM,
output logic LoadMisalignedFaultM, LoadAccessFaultM,
// cpu hazard unit (trap)
output logic StoreMisalignedFaultM, StoreAccessFaultM,
// connect to ahb
input logic CommitM, // should this be generated in the abh interface?
output logic [`PA_BITS-1:0] DCtoAHBPAdrM,
output logic DCtoAHBReadM,
output logic DCtoAHBWriteM,
input logic DCfromAHBAck,
input logic [`XLEN-1:0] DCfromAHBReadData,
output logic [`XLEN-1:0] DCtoAHBWriteData,
output logic [2:0] DCtoAHBSizeM,
// mmu management
// page table walker
input logic [`XLEN-1:0] SATP_REGW, // from csr
input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
input logic [1:0] STATUS_MPP,
input logic [`XLEN-1:0] PCF,
input logic ITLBMissF,
output logic [`XLEN-1:0] PTE,
output logic [1:0] PageType,
output logic ITLBWriteF,
output logic WalkerInstrPageFaultF,
output logic WalkerLoadPageFaultM,
output logic WalkerStorePageFaultM,
output logic DTLBHitM, // not connected
input var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW[`PMP_ENTRIES-1:0] // *** this one especially has a large note attached to it in pmpchecker.
// output logic [5:0] DHSELRegionsM
);
logic SquashSCM;
logic DTLBPageFaultM;
logic MemAccessM;
/* -----\/----- EXCLUDED -----\/-----
logic preCommittedM;
-----/\----- EXCLUDED -----/\----- */
typedef enum {STATE_READY,
STATE_FETCH,
STATE_FETCH_AMO_1,
STATE_FETCH_AMO_2,
STATE_STALLED,
STATE_PTW_READY,
STATE_PTW_FETCH,
STATE_PTW_DONE} statetype;
statetype CurrState, NextState;
logic [`PA_BITS-1:0] MemPAdrM; // from mmu to dcache
logic DTLBMissM;
// logic [`XLEN-1:0] PTE;
logic DTLBWriteM;
logic HPTWStall;
logic [`XLEN-1:0] HPTWPAdrE;
// logic [`XLEN-1:0] HPTWPAdrM;
logic [`PA_BITS-1:0] TranslationPAdr;
logic HPTWRead;
logic [1:0] MemRWMtoDCache;
logic [1:0] MemRWMtoLRSC;
logic [2:0] Funct3MtoDCache;
logic [1:0] AtomicMtoDCache;
logic [`PA_BITS-1:0] MemPAdrMtoDCache;
logic [11:0] MemAdrEtoDCache;
logic [`XLEN-1:0] ReadDataWfromDCache;
logic StallWtoDCache;
logic MemReadM;
logic DataMisalignedMfromDCache;
logic HPTWReady;
logic DisableTranslation; // used to stop intermediate PTE physical addresses being saved to TLB.
logic DCacheStall;
logic CacheableM;
logic CacheableMtoDCache;
logic SelPTW;
logic CommittedMfromDCache;
logic PendingInterruptMtoDCache;
logic FlushWtoDCache;
logic WalkerPageFaultM;
logic [`XLEN-1:0] LSUData;
hptw hptw(
.clk(clk),
.reset(reset),
.SATP_REGW(SATP_REGW),
.PCF(PCF),
.MemAdrM(MemAdrM),
.ITLBMissF(ITLBMissF),
.DTLBMissM(DTLBMissM),
.MemRWM(MemRWM),
.PTE(PTE),
.PageType,
.ITLBWriteF(ITLBWriteF),
.DTLBWriteM(DTLBWriteM),
.HPTWReadPTE(LSUData),
.HPTWStall(HPTWStall),
.TranslationPAdr,
.HPTWRead(HPTWRead),
.SelPTW(SelPTW),
.WalkerInstrPageFaultF(WalkerInstrPageFaultF),
.WalkerLoadPageFaultM(WalkerLoadPageFaultM),
.WalkerStorePageFaultM(WalkerStorePageFaultM));
assign WalkerPageFaultM = WalkerStorePageFaultM | WalkerLoadPageFaultM;
// arbiter between IEU and hptw
lsuArb arbiter(.clk(clk),
.reset(reset),
// HPTW connection
.SelPTW(SelPTW),
.HPTWRead(HPTWRead),
.TranslationPAdrE(TranslationPAdr),
.HPTWStall(HPTWStall),
// CPU connection
.MemRWM(MemRWM),
.Funct3M(Funct3M),
.AtomicM(AtomicM),
.MemAdrM(MemAdrM),
.MemAdrE(MemAdrE),
.CommittedM(CommittedM),
.PendingInterruptM(PendingInterruptM),
.StallW(StallW),
.DataMisalignedM(DataMisalignedM),
.LSUStall(LSUStall),
// DCACHE
.DisableTranslation(DisableTranslation),
.MemRWMtoLRSC(MemRWMtoLRSC),
.Funct3MtoDCache(Funct3MtoDCache),
.AtomicMtoDCache(AtomicMtoDCache),
.MemPAdrMtoDCache(MemPAdrMtoDCache),
.MemAdrEtoDCache(MemAdrEtoDCache),
.StallWtoDCache(StallWtoDCache),
.DataMisalignedMfromDCache(DataMisalignedMfromDCache),
.CommittedMfromDCache(CommittedMfromDCache),
.PendingInterruptMtoDCache(PendingInterruptMtoDCache),
.DCacheStall(DCacheStall));
mmu #(.TLB_ENTRIES(`DTLB_ENTRIES), .IMMU(0))
dmmu(.PAdr(MemPAdrMtoDCache),
.VAdr(MemAdrM),
.Size(Funct3MtoDCache[1:0]),
.PTE(PTE),
.PageTypeWriteVal(PageType),
.TLBWrite(DTLBWriteM),
.TLBFlush(DTLBFlushM),
.PhysicalAddress(MemPAdrM),
.TLBMiss(DTLBMissM),
.TLBHit(DTLBHitM),
.TLBPageFault(DTLBPageFaultM),
.ExecuteAccessF(1'b0),
//.AtomicAccessM(AtomicMaskedM[1]),
.AtomicAccessM(1'b0),
.WriteAccessM(MemRWMtoLRSC[0]),
.ReadAccessM(MemRWMtoLRSC[1]),
.SquashBusAccess(),
.DisableTranslation(DisableTranslation),
.InstrAccessFaultF(),
.Cacheable(CacheableM),
.Idempotent(),
.AtomicAllowed(),
.*); // *** the pma/pmp instruction acess faults don't really matter here. is it possible to parameterize which outputs exist?
assign MemReadM = MemRWMtoLRSC[1] & ~(ExceptionM | PendingInterruptMtoDCache) & ~DTLBMissM; // & ~NonBusTrapM & ~DTLBMissM & CurrState != STATE_STALLED;
lrsc lrsc(.clk, .reset, .FlushW, .StallWtoDCache, .MemReadM, .MemRWMtoLRSC, .AtomicMtoDCache, .MemPAdrM,
.SquashSCM, .SquashSCW, .MemRWMtoDCache);
// *** BUG, this is most likely wrong
assign CacheableMtoDCache = SelPTW ? 1'b1 : CacheableM;
generate
if (`XLEN == 32) assign DCtoAHBSizeM = CacheableMtoDCache ? 3'b010 : Funct3MtoDCache;
else assign DCtoAHBSizeM = CacheableMtoDCache ? 3'b011 : Funct3MtoDCache;
endgenerate;
// Specify which type of page fault is occurring
assign DTLBLoadPageFaultM = DTLBPageFaultM & MemRWMtoLRSC[1];
assign DTLBStorePageFaultM = DTLBPageFaultM & MemRWMtoLRSC[0];
// Determine if an Unaligned access is taking place
always_comb
case(Funct3MtoDCache[1:0])
2'b00: DataMisalignedMfromDCache = 0; // lb, sb, lbu
2'b01: DataMisalignedMfromDCache = MemPAdrMtoDCache[0]; // lh, sh, lhu
2'b10: DataMisalignedMfromDCache = MemPAdrMtoDCache[1] | MemPAdrMtoDCache[0]; // lw, sw, flw, fsw, lwu
2'b11: DataMisalignedMfromDCache = |MemPAdrMtoDCache[2:0]; // ld, sd, fld, fsd
endcase
// Squash unaligned data accesses and failed store conditionals
// *** this is also the place to squash if the cache is hit
// Changed DataMisalignedMfromDCache to a larger combination of trap sources
// NonBusTrapM is anything that the bus doesn't contribute to producing
// By contrast, using TrapM results in circular logic errors
/* -----\/----- EXCLUDED -----\/-----
// *** BUG for now leave this out. come back later after the d cache is working. July 09, 2021
assign MemReadM = MemRWMtoLRSC[1] & ~NonBusTrapM & ~DTLBMissM & CurrState != STATE_STALLED;
assign MemWriteM = MemRWMtoLRSC[0] & ~NonBusTrapM & ~DTLBMissM & ~SquashSCM & CurrState != STATE_STALLED;
assign AtomicMaskedM = CurrState != STATE_STALLED ? AtomicMtoDCache : 2'b00 ;
assign MemAccessM = MemReadM | MemWriteM;
// Determine if M stage committed
// Reset whenever unstalled. Set when access successfully occurs
flopr #(1) committedMreg(clk,reset,(CommittedMfromDCache | CommitM) & StallM,preCommittedM);
assign CommittedMfromDCache = preCommittedM | CommitM;
-----/\----- EXCLUDED -----/\----- */
// Determine if address is valid
assign LoadMisalignedFaultM = DataMisalignedMfromDCache & MemRWMtoLRSC[1];
assign StoreMisalignedFaultM = DataMisalignedMfromDCache & MemRWMtoLRSC[0];
dcache dcache(.clk(clk),
.reset(reset),
.StallM(StallM),
.StallWtoDCache(StallWtoDCache),
.FlushM(FlushM),
.FlushW(FlushWtoDCache),
.MemRWM(MemRWMtoDCache),
.Funct3M(Funct3MtoDCache),
.Funct7M(Funct7M),
.AtomicM(AtomicMtoDCache),
.MemAdrE(MemAdrEtoDCache),
.MemPAdrM(MemPAdrM),
.VAdr(MemAdrM[11:0]),
.WriteDataM(WriteDataM),
.ReadDataM(ReadDataM),
.LSUData(LSUData),
.DCacheStall(DCacheStall),
.CommittedM(CommittedMfromDCache),
.DCacheMiss,
.DCacheAccess,
.ExceptionM(ExceptionM),
.PendingInterruptM(PendingInterruptMtoDCache),
.DTLBMissM(DTLBMissM),
.CacheableM(CacheableMtoDCache),
.DTLBWriteM(DTLBWriteM),
.ITLBWriteF(ITLBWriteF),
.SelPTW(SelPTW),
.WalkerPageFaultM(WalkerPageFaultM),
.WalkerInstrPageFaultF(WalkerInstrPageFaultF),
// AHB connection
.AHBPAdr(DCtoAHBPAdrM),
.AHBRead(DCtoAHBReadM),
.AHBWrite(DCtoAHBWriteM),
.AHBAck(DCfromAHBAck),
.HWDATA(DCtoAHBWriteData),
.HRDATA(DCfromAHBReadData)
);
// assign AtomicMaskedM = 2'b00; // *** Remove from AHB
// Data stall
//assign LSUStall = (NextState == STATE_FETCH) || (NextState == STATE_FETCH_AMO_1) || (NextState == STATE_FETCH_AMO_2);
// BUG *** July 09, 2021
//assign HPTWReady = (CurrState == STATE_READY);
// Ross Thompson April 22, 2021
// for now we need to handle the issue where the data memory interface repeately
// requests data from memory rather than issuing a single request.
/* -----\/----- EXCLUDED -----\/-----
// *** BUG will need to modify this so we can handle the ptw. July 09, 2021
flopenl #(.TYPE(statetype)) stateReg(.clk(clk),
.load(reset),
.en(1'b1),
.d(NextState),
.val(STATE_READY),
.q(CurrState));
always_comb begin
case (CurrState)
STATE_READY:
if (DTLBMissM) begin
NextState = STATE_PTW_READY;
LSUStall = 1'b1;
end else if (AtomicMaskedM[1]) begin
NextState = STATE_FETCH_AMO_1; // *** should be some misalign check
LSUStall = 1'b1;
end else if((MemReadM & AtomicMtoDCache[0]) | (MemWriteM & AtomicMtoDCache[0])) begin
NextState = STATE_FETCH_AMO_2;
LSUStall = 1'b1;
end else if (MemAccessM & ~DataMisalignedMfromDCache) begin
NextState = STATE_FETCH;
LSUStall = 1'b1;
end else begin
NextState = STATE_READY;
LSUStall = 1'b0;
end
STATE_FETCH_AMO_1: begin
LSUStall = 1'b1;
if (DCfromAHBAck) begin
NextState = STATE_FETCH_AMO_2;
end else begin
NextState = STATE_FETCH_AMO_1;
end
end
STATE_FETCH_AMO_2: begin
LSUStall = 1'b1;
if (DCfromAHBAck & ~StallWtoDCache) begin
NextState = STATE_FETCH_AMO_2;
end else if (DCfromAHBAck & StallWtoDCache) begin
NextState = STATE_STALLED;
end else begin
NextState = STATE_FETCH_AMO_2;
end
end
STATE_FETCH: begin
LSUStall = 1'b1;
if (DCfromAHBAck & ~StallWtoDCache) begin
NextState = STATE_READY;
end else if (DCfromAHBAck & StallWtoDCache) begin
NextState = STATE_STALLED;
end else begin
NextState = STATE_FETCH;
end
end
STATE_STALLED: begin
LSUStall = 1'b0;
if (~StallWtoDCache) begin
NextState = STATE_READY;
end else begin
NextState = STATE_STALLED;
end
end
STATE_PTW_READY: begin
LSUStall = 1'b0;
if (DTLBWriteM) begin
NextState = STATE_READY;
LSUStall = 1'b1;
end else if (MemReadM & ~DataMisalignedMfromDCache) begin
NextState = STATE_PTW_FETCH;
end else begin
NextState = STATE_PTW_READY;
end
end
STATE_PTW_FETCH : begin
LSUStall = 1'b1;
if (DCfromAHBAck & ~DTLBWriteM) begin
NextState = STATE_PTW_READY;
end else if (DCfromAHBAck & DTLBWriteM) begin
NextState = STATE_READY;
end else begin
NextState = STATE_PTW_FETCH;
end
end
STATE_PTW_DONE: begin
NextState = STATE_READY;
end
default: begin
LSUStall = 1'b0;
NextState = STATE_READY;
end
endcase
end // always_comb
-----/\----- EXCLUDED -----/\----- */
endmodule