From c2595273ec4c3e1e3dd405e9424e554168fd54ae Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 8 Apr 2019 11:38:40 +0200 Subject: [PATCH] Add a busy flag from MMU ports iBus/dBus now halt on MMU busy, which avoid looping forever on page fault --- src/main/scala/vexriscv/Services.scala | 3 +- .../scala/vexriscv/ip/InstructionCache.scala | 10 ++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 6 ++ .../vexriscv/plugin/DBusSimplePlugin.scala | 10 ++++ .../vexriscv/plugin/IBusCachedPlugin.scala | 55 ++++++++++++------- .../vexriscv/plugin/IBusSimplePlugin.scala | 4 ++ .../scala/vexriscv/plugin/MmuPlugin.scala | 5 ++ 7 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 666cb47..0e04127 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -78,10 +78,11 @@ case class MemoryTranslatorBus() extends Bundle with IMasterSlave{ val cmd = MemoryTranslatorCmd() val rsp = MemoryTranslatorRsp() val end = Bool + val busy = Bool override def asMaster() : Unit = { out(cmd, end) - in(rsp) + in(rsp, busy) } } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 29df3af..e3722d6 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -99,10 +99,11 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val mmuBus = MemoryTranslatorBus() val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) + val haltIt = Bool override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, pc) - inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress) + inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress, haltIt) outWithNull(isUser, dataBypass, dataBypassValid) slaveWithNull(mmuBus) } @@ -290,10 +291,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } }) - io.cpu.prefetch.haltIt := False - - - + io.cpu.fetch.haltIt := io.cpu.fetch.mmuBus.busy val lineLoader = new Area{ val fire = False @@ -307,7 +305,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ address := io.cpu.fill.payload } - io.cpu.prefetch.haltIt setWhen(valid || flushPending) + io.cpu.prefetch.haltIt := valid || flushPending val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) when(!flushCounter.msb){ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 917d50d..89779ad 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -159,7 +159,13 @@ class DBusCachedPlugin(config : DataCacheConfig, dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) + decode plug new Area { + import decode._ + when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) { + arbitration.haltItself := True + } + } execute plug new Area { import execute._ diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 9e1de8c..32e6f37 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -312,6 +312,15 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus = master(DBusSimpleBus()).setName("dBus") + + decode plug new Area { + import decode._ + + if(mmuBus != null) when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) { + arbitration.haltItself := True + } + } + //Emit dBus.cmd request val cmdStage = if(emitCmdInMemoryStage) memory else execute cmdStage plug new Area{ @@ -359,6 +368,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, mmuBus.cmd.isValid := arbitration.isValid && input(MEMORY_ENABLE) mmuBus.cmd.virtualAddress := input(SRC_ADD).asUInt mmuBus.cmd.bypassTranslation := False + mmuBus.end := !arbitration.isStuck || arbitration.isRemoved dBus.cmd.address := mmuBus.rsp.physicalAddress //do not emit memory request if MMU refilling diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index f55d92e..ed74c86 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -165,6 +165,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.isStuck := !stages(1).input.ready cache.io.cpu.fetch.pc := stages(1).input.payload + + stages(1).halt setWhen(cache.io.cpu.fetch.haltIt) + if (!twoCycleCache) { cache.io.cpu.fetch.isUser := privilegeService.isUser() } @@ -188,39 +191,49 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val cacheRsp = if (twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch val cacheRspArbitration = stages(if (twoCycleCache) 2 else 1) var issueDetected = False - val redoFetch = False //RegNext(False) init(False) - when(cacheRsp.isValid && (cacheRsp.cacheMiss || cacheRsp.mmuRefilling) && !issueDetected) { - issueDetected \= True - redoFetch := iBusRsp.readyForError - } + val redoFetch = False //Refill / redo assert(decodePcGen == compressedGen) - cache.io.cpu.fill.valid := redoFetch + cache.io.cpu.fill.valid := redoFetch && !cacheRsp.mmuRefilling cache.io.cpu.fill.payload := cacheRsp.physicalAddress - redoBranch.valid := redoFetch - redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) + if (catchSomething) { decodeExceptionPort.valid := False decodeExceptionPort.code.assignDontCare() decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00" - - if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) { - issueDetected \= True - decodeExceptionPort.valid := iBusRsp.readyForError - decodeExceptionPort.code := 12 - } - - if(catchAccessFault) when(cacheRsp.isValid && cacheRsp.error && !issueDetected) { - issueDetected \= True - decodeExceptionPort.valid := iBusRsp.readyForError - decodeExceptionPort.code := 1 - } - decodeExceptionPort.valid clearWhen(fetcherHalt) } + when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) { + issueDetected \= True + redoFetch := True + } + + if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) { + issueDetected \= True + decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code := 12 + } + + when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected) { + issueDetected \= True + cache.io.cpu.fill.valid := True + redoFetch := True + } + + if(catchAccessFault) when(cacheRsp.isValid && cacheRsp.error && !issueDetected) { + issueDetected \= True + decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code := 1 + } + + redoFetch clearWhen(!iBusRsp.readyForError) + if (catchSomething) decodeExceptionPort.valid clearWhen(fetcherHalt) + + redoBranch.valid := redoFetch + redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) iBusRsp.output.valid := cacheRspArbitration.output.valid diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index ddd3ff3..fb296fb 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -247,6 +247,8 @@ class IBusSimplePlugin(resetVector : BigInt, mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False + mmuBus.end := !cmdForkStage.output.fire || flush + cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" //do not emit memory request if MMU miss @@ -255,6 +257,8 @@ class IBusSimplePlugin(resetVector : BigInt, cmd.valid := False } + cmdForkStage.halt.setWhen(mmuBus.busy) + val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp) } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index b6b7d44..9fce74e 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -100,6 +100,7 @@ class MmuPlugin(ioRange : UInt => Bool, val core = pipeline plug new Area { val ports = for (port <- sortedPortsInfo) yield new Area { + val handle = port val id = port.id val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) val cacheHits = cache.map(line => line.valid && line.virtualAddress(1) === port.bus.cmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === port.bus.cmd.virtualAddress(21 downto 12))) @@ -224,6 +225,10 @@ class MmuPlugin(ioRange : UInt => Bool, } } + for(port <- ports) { + port.handle.bus.busy := state =/= State.IDLE && portId === port.id + } + when(dBusAccess.rsp.valid && !dBusAccess.rsp.redo && (dBusRsp.leaf || dBusRsp.exception)){ for(port <- ports){ when(portId === port.id) {