From 4d6a6fbb02c1d29dc4f7855ef3fa7cedb4227b40 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 7 May 2017 12:51:47 +0200 Subject: [PATCH] Fix Instruction Data cache exceptions Pass all tests including CSR/FreeRTOS --- .../SpinalRiscv/Plugin/DBusCachedPlugin.scala | 29 ++++++---- .../Plugin/DecoderSimplePlugin.scala | 2 +- .../SpinalRiscv/Plugin/IBusCachedPlugin.scala | 19 ++++-- .../scala/SpinalRiscv/Plugin/MachineCsr.scala | 14 ++--- src/main/scala/SpinalRiscv/TopLevel.scala | 58 ++++++++++++------- src/test/cpp/testA/main.cpp | 8 +-- src/test/cpp/testA/makefile | 4 +- 7 files changed, 81 insertions(+), 53 deletions(-) diff --git a/src/main/scala/SpinalRiscv/Plugin/DBusCachedPlugin.scala b/src/main/scala/SpinalRiscv/Plugin/DBusCachedPlugin.scala index febd7f2..111ddd5 100644 --- a/src/main/scala/SpinalRiscv/Plugin/DBusCachedPlugin.scala +++ b/src/main/scala/SpinalRiscv/Plugin/DBusCachedPlugin.scala @@ -96,11 +96,7 @@ class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean U(1) -> input(REG2)(15 downto 0) ## input(REG2)(15 downto 0), default -> input(REG2)(31 downto 0) ) - cache.io.cpu.execute.args.mask := (size.mux ( - U(0) -> B"0001", - U(1) -> B"0011", - default -> B"1111" - ) << cache.io.cpu.execute.args.address(1 downto 0)).resized + cache.io.cpu.execute.args.size := size cache.io.cpu.execute.args.forceUncachedAccess := False // cache.io.cpu.execute.args.address(31 downto 28) === 0xF cache.io.cpu.execute.args.kind := DataCacheCpuCmdKind.MEMORY cache.io.cpu.execute.args.clean := False @@ -130,12 +126,15 @@ class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean cache.io.cpu.writeBack.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.writeBack.isStuck := arbitration.isStuck if(catchSomething) { - exceptionBus.valid := cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError + exceptionBus.valid := cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess exceptionBus.badAddr := cache.io.cpu.writeBack.badAddr exceptionBus.code := 13 - when(cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.accessError){ + when(cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError){ exceptionBus.code := (input(INSTRUCTION)(5) ? U(7) | U(5)).resized } + when(cache.io.cpu.writeBack.unalignedAccess){ + exceptionBus.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized + } } arbitration.haltIt.setWhen(cache.io.cpu.writeBack.haltIt) @@ -259,7 +258,7 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val wr = Bool val address = UInt(p.addressWidth bit) val data = Bits(p.cpuDataWidth bit) - val mask = Bits(p.cpuDataWidth/8 bit) + val size = UInt(2 bits) val forceUncachedAccess = Bool val clean, invalidate, way = Bool // val all = Bool //Address should be zero when "all" is used @@ -571,6 +570,12 @@ class DataCache(p : DataCacheConfig) extends Component{ val victimNotSent = RegInit(False) clearWhen(victim.requestIn.ready) setWhen(!io.cpu.memory.isStuck) val loadingNotDone = RegInit(False) clearWhen(loaderReady) setWhen(!io.cpu.memory.isStuck) + val writeMask = request.size.mux ( + U(0) -> B"0001", + U(1) -> B"0011", + default -> B"1111" + ) |<< mmuRsp.physicalAddress(1 downto 0) + io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid io.cpu.writeBack.mmuMiss := False io.cpu.writeBack.illegalAccess := False @@ -618,7 +623,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } is(MEMORY) { val illegal = if(catchIllegal) (request.wr && !mmuRsp.allowWrite) || (!request.wr && !mmuRsp.allowRead) else False - val unaligned = if(catchUnaligned) ((request.mask === 0xF && mmuRsp.physicalAddress(1 downto 0) =/= 0) || ((request.mask === 0x3 || request.mask === 0xC) && mmuRsp.physicalAddress(0) =/= False)) else False + val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False io.cpu.writeBack.illegalAccess := illegal io.cpu.writeBack.unalignedAccess := unaligned when((Bool(!catchMemoryTranslationMiss) || !mmuRsp.miss) && !illegal && !unaligned) { @@ -628,7 +633,7 @@ class DataCache(p : DataCacheConfig) extends Component{ //Avoid mixing memory request while victim is pending io.mem.cmd.wr := request.wr io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) - io.mem.cmd.mask := request.mask + io.mem.cmd.mask := writeMask io.mem.cmd.data := request.data io.mem.cmd.length := 1 @@ -646,7 +651,7 @@ class DataCache(p : DataCacheConfig) extends Component{ dataWriteCmd.valid := request.wr dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) dataWriteCmd.data := request.data - dataWriteCmd.mask := request.mask + dataWriteCmd.mask := writeMask tagsWriteCmd.valid := (!loadingNotDone) || request.wr tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) @@ -667,7 +672,7 @@ class DataCache(p : DataCacheConfig) extends Component{ assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") - io.cpu.writeBack.data := request.forceUncachedAccess ? io.mem.rsp.data | way.dataReadRspTwo //not multi ways + io.cpu.writeBack.data := (request.forceUncachedAccess || mmuRsp.isIoAccess) ? io.mem.rsp.data | way.dataReadRspTwo //not multi ways } //The whole life of a loading task, the corresponding manager request is present diff --git a/src/main/scala/SpinalRiscv/Plugin/DecoderSimplePlugin.scala b/src/main/scala/SpinalRiscv/Plugin/DecoderSimplePlugin.scala index dd2ed88..258a34f 100644 --- a/src/main/scala/SpinalRiscv/Plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/SpinalRiscv/Plugin/DecoderSimplePlugin.scala @@ -131,7 +131,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean) extends Plugin[VexR if(catchIllegalInstruction){ - decodeExceptionPort.valid := arbitration.isValid && arbitration.haltIt && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) //HalitIt to alow decoder stage to wait valid data from 2 stages cache cache + decodeExceptionPort.valid := arbitration.isValid && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ?? decodeExceptionPort.code := 2 decodeExceptionPort.badAddr.assignDontCare() } diff --git a/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala b/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala index 07f78d0..00ec6dd 100644 --- a/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala +++ b/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala @@ -12,12 +12,13 @@ case class InstructionCacheConfig( cacheSize : Int, addressWidth : Int, cpuDataWidth : Int, memDataWidth : Int, + catchIllegalAccess : Boolean, catchAccessFault : Boolean, catchMemoryTranslationMiss : Boolean, asyncTagMemory : Boolean, twoStageLogic : Boolean){ def burstSize = bytePerLine*8/memDataWidth - def catchSomething = catchAccessFault || catchMemoryTranslationMiss + def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess } @@ -102,8 +103,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B val accessFault = if(catchAccessFault) decode.input(IBUS_ACCESS_ERROR) else False val mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False + val illegalAccess = if(catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False - decodeExceptionPort.valid := decode.arbitration.isValid && (accessFault || mmuMiss) + decodeExceptionPort.valid := decode.arbitration.isValid && (accessFault || mmuMiss || illegalAccess) decodeExceptionPort.code := mmuMiss ? U(14) | 1 decodeExceptionPort.badAddr := decode.input(PC) } @@ -152,11 +154,12 @@ case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle val dataAnticipated = Bits(32 bits) val error = if(p.catchAccessFault) Bool else null val mmuMiss = if(p.catchMemoryTranslationMiss) Bool else null + val illegalAccess = if(p.catchIllegalAccess) Bool else null override def asMaster(): Unit = { out(isValid, isStuck, address) in(haltIt, data, dataAnticipated) - inWithNull(error,mmuMiss) + inWithNull(error,mmuMiss,illegalAccess) } } @@ -177,7 +180,7 @@ case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{ } case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{ val data = Bits(32 bit) - val error = if(p.catchAccessFault) Bool else null + val error = Bool } case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ @@ -281,8 +284,11 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.flush.rsp := flushCounter.msb.rise && flushFromInterface val loadingWithErrorReg = if(catchAccessFault) RegInit(False) else null - val loadingWithError = if(catchAccessFault) loadingWithErrorReg else null - if(catchAccessFault) loadingWithErrorReg := loadingWithError + val loadingWithError = if(catchAccessFault) Bool else null + if(catchAccessFault) { + loadingWithError := loadingWithErrorReg + loadingWithErrorReg := loadingWithError + } @@ -470,6 +476,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.decode.dataAnticipated := io.cpu.decode.isStuck ? Mux(dataPostWrite,lineLoader.waysDatasWritePort.data,data) | Mux(dataPreWrite,lineLoader.waysDatasWritePort.data,memRead.data) if(catchAccessFault) io.cpu.decode.error := tag.error if(catchMemoryTranslationMiss) io.cpu.decode.mmuMiss := mmuRsp.miss + if(catchIllegalAccess) io.cpu.decode.illegalAccess := !mmuRsp.miss && !mmuRsp.allowExecute lineLoader.requestIn.valid := io.cpu.decode.isValid && !hit && !mmuRsp.miss//TODO avoid duplicated request lineLoader.requestIn.addr := mmuRsp.physicalAddress diff --git a/src/main/scala/SpinalRiscv/Plugin/MachineCsr.scala b/src/main/scala/SpinalRiscv/Plugin/MachineCsr.scala index 4d2b1ab..ab3c3da 100644 --- a/src/main/scala/SpinalRiscv/Plugin/MachineCsr.scala +++ b/src/main/scala/SpinalRiscv/Plugin/MachineCsr.scala @@ -304,13 +304,13 @@ class MachineCsr(config : MachineCsrConfig) extends Plugin[VexRiscv] with Except ) mcause.interrupt := interrupt - mcause.exceptionCode := interrupt.mux( - True -> ((mip.MEIP && mie.MEIE) ? U(11) | ((mip.MSIP && mie.MSIE) ? U(3) | U(7))), - False -> (if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionContext.code else U(0)) - ) - when(RegNext(exception)){ - mbadaddr := (if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionContext.badAddr else U(0)) - } + + mcause.exceptionCode := ((mip.MEIP && mie.MEIE) ? U(11) | ((mip.MSIP && mie.MSIE) ? U(3) | U(7))) + } + + when(RegNext(exception)){ + mbadaddr := (if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionContext.badAddr else U(0)) + mcause.exceptionCode := (if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionContext.code else U(0)) } diff --git a/src/main/scala/SpinalRiscv/TopLevel.scala b/src/main/scala/SpinalRiscv/TopLevel.scala index 3dfdada..8874df9 100644 --- a/src/main/scala/SpinalRiscv/TopLevel.scala +++ b/src/main/scala/SpinalRiscv/TopLevel.scala @@ -99,24 +99,30 @@ object TopLevel { val configFull = VexRiscvConfig( plugins = List( new PcManagerSimplePlugin(0x00000000l, false), - new IBusSimplePlugin( - interfaceKeepData = true, - catchAccessFault = true +// new IBusSimplePlugin( +// interfaceKeepData = true, +// catchAccessFault = true +// ), + new IBusCachedPlugin( + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + wrappedMemAccess = true, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + catchMemoryTranslationMiss = true, + asyncTagMemory = false, + twoStageLogic = true + ), + askMemoryTranslation = true, + memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + portTlbSize = 4 + ) ), - // new IBusCachedPlugin( - // config = InstructionCacheConfig( - // cacheSize = 4096, - // bytePerLine =32, - // wayCount = 1, - // wrappedMemAccess = true, - // addressWidth = 32, - // cpuDataWidth = 32, - // memDataWidth = 32, - // catchAccessFault = true, - // asyncTagMemory = false, - // twoStageLogic = true - // ) - // ), // new DBusSimplePlugin( // catchAddressMisaligned = true, // catchAccessFault = true @@ -132,9 +138,18 @@ object TopLevel { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - catchMemoryTranslationMiss = false + catchMemoryTranslationMiss = true + ), + askMemoryTranslation = true, + memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + portTlbSize = 6 ) ), + new MemoryTranslatorPlugin( + tlbSize = 32, + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), new DecoderSimplePlugin( catchIllegalInstruction = true ), @@ -237,7 +252,8 @@ object TopLevel { addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, - catchAccessFault = false, + catchIllegalAccess = true, + catchAccessFault = true, catchMemoryTranslationMiss = true, asyncTagMemory = false, twoStageLogic = true @@ -324,9 +340,9 @@ object TopLevel { ) ) -// val toplevel = new VexRiscv(configFull) + val toplevel = new VexRiscv(configFull) // val toplevel = new VexRiscv(configLight) - val toplevel = new VexRiscv(configTest) +// val toplevel = new VexRiscv(configTest) toplevel.decode.input(toplevel.config.INSTRUCTION).addAttribute(Verilator.public) toplevel.decode.input(toplevel.config.PC).addAttribute(Verilator.public) toplevel.decode.arbitration.isValid.addAttribute(Verilator.public) diff --git a/src/test/cpp/testA/main.cpp b/src/test/cpp/testA/main.cpp index f27b64a..e950e72 100644 --- a/src/test/cpp/testA/main.cpp +++ b/src/test/cpp/testA/main.cpp @@ -332,6 +332,7 @@ public: // dump variables into VCD file and toggle clock dump(i); + //top->eval(); top->clk = 0; top->eval(); @@ -360,6 +361,7 @@ public: } checks(); + //top->eval(); top->clk = 1; top->eval(); @@ -469,9 +471,7 @@ public: top->iBus_rsp_valid = 0; if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(7) < 100)){ ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error); - #ifdef CSR top->iBus_rsp_payload_error = error; - #endif pendingCount--; address = (address & ~0x1F) + ((address + 4) & 0x1F); top->iBus_rsp_valid = 1; @@ -833,8 +833,8 @@ int main(int argc, char **argv, char **env) { #ifdef CSR uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u , - 8,6,9,6,10,4,11,4, 12,13,0, 14,2, 15,5,16,5,17,1 }; - redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).run(4e3);) + 8,6,9,6,10,4,11,4, 12,13,0, 14,2, 15,5,16,17,1 }; + redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(4e3);) #endif #ifdef MMU uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5, diff --git a/src/test/cpp/testA/makefile b/src/test/cpp/testA/makefile index f04e5ab..8ba5ebb 100644 --- a/src/test/cpp/testA/makefile +++ b/src/test/cpp/testA/makefile @@ -2,10 +2,10 @@ IBUS=IBUS_CACHED DBUS=DBUS_CACHED TRACE=no TRACE_START=0 -CSR=no +CSR=yes MMU=yes DHRYSTONE=yes -FREE_RTOS=no +FREE_RTOS=yes REDO=10 REF=no TRACE_WITH_TIME=no