From 19fe998a5243b3bacdb703ca9c9344b85dd02eba Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 30 Mar 2017 17:34:24 +0200 Subject: [PATCH] Instruction cache is now able to catch bus errors --- .../SpinalRiscv/Plugin/IBusCachedPlugin.scala | 126 ++++++++++-------- src/main/scala/SpinalRiscv/TopLevel.scala | 9 +- src/test/cpp/testA/fail.gtkw | 65 ++++----- src/test/cpp/testA/main.cpp | 13 +- 4 files changed, 125 insertions(+), 88 deletions(-) diff --git a/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala b/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala index 36736bd..c237121 100644 --- a/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala +++ b/src/main/scala/SpinalRiscv/Plugin/IBusCachedPlugin.scala @@ -11,7 +11,8 @@ case class InstructionCacheConfig( cacheSize : Int, wrappedMemAccess : Boolean, addressWidth : Int, cpuDataWidth : Int, - memDataWidth : Int){ + memDataWidth : Int, + catchAccessFault : Boolean){ def burstSize = bytePerLine*8/memDataWidth } @@ -36,9 +37,6 @@ class IBusCachedPlugin(catchAccessFault : Boolean, cacheConfig : InstructionCach import pipeline._ import pipeline.config._ - assert(catchAccessFault == false) //unimplemented - - val cache = new InstructionCache(cacheConfig) iBus = master(new InstructionCacheMemBus(cacheConfig)).setName("iBus") iBus <> cache.io.mem @@ -59,13 +57,14 @@ class IBusCachedPlugin(catchAccessFault : Boolean, cacheConfig : InstructionCach cache.io.flush.cmd.valid := False -// fetch.insert(IBUS_ACCESS_ERROR) := iRsp.error -// if(catchAccessFault){ -// decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR) -// decodeExceptionPort.code := 1 -// decodeExceptionPort.badAddr := decode.input(PC) -// } + if(catchAccessFault){ + fetch.insert(IBUS_ACCESS_ERROR) := cache.io.cpu.rsp.error + + decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR) + decodeExceptionPort.code := 1 + decodeExceptionPort.badAddr := decode.input(PC) + } } } @@ -84,15 +83,17 @@ case class InstructionCacheCpuCmd(p : InstructionCacheConfig) extends Bundle wit } case class InstructionCacheCpuRsp(p : InstructionCacheConfig) extends Bundle with IMasterSlave { - val isValid = Bool + val isValid = Bool val haltIt = Bool - val isStuck = Bool + val isStuck = Bool val address = UInt(p.addressWidth bit) val data = Bits(32 bit) + val error = if(p.catchAccessFault) Bool else null override def asMaster(): Unit = { out(isValid, isStuck, address) in(haltIt, data) + if(p.catchAccessFault) in(error) } } @@ -107,12 +108,24 @@ case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle wit } } +case class InstructionCacheTranslationBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ + val virtualAddress = UInt(32 bits) + val physicalAddress = UInt(32 bits) + val error = if(p.catchAccessFault) Bool else null + + override def asMaster(): Unit = { + out(virtualAddress) + in(physicalAddress) + if(p.catchAccessFault) in(error) + } +} case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{ val address = UInt(p.addressWidth bit) } case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{ val data = Bits(32 bit) + val error = if(p.catchAccessFault) Bool else null } case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ @@ -141,6 +154,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ assert(cpuDataWidth == memDataWidth) val io = new Bundle{ val flush = slave(InstructionCacheFlushBus()) +// val translator = master(InstructionCacheTranslationBus(p)) val cpu = slave(InstructionCacheCpuBus(p)) val mem = master(InstructionCacheMemBus(p)) } @@ -158,16 +172,22 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine) val lineRange = tagRange.low-1 downto log2Up(bytePerLine) val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord) + val tagLineRange = tagRange.high downto lineRange.low - - class LineInfo() extends Bundle{ + class LineInfo extends Bundle{ val valid = Bool + val error = if(catchAccessFault) Bool else null val address = UInt(tagRange.length bit) } +// class LineWord extends Bundle{ +// val data = Bits(wordWidth bits) +// val error = Bool +// } + val ways = Array.fill(wayCount)(new Area{ val tags = Mem(new LineInfo(),wayLineCount) - val datas = Mem(Bits(wordWidth bit),wayWordCount) + val datas = Mem(Bits(wordWidth bits),wayWordCount) }) @@ -175,7 +195,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val lineLoader = new Area{ val requestIn = Stream(wrap(new Bundle{ - val addr = UInt(addressWidth bit) + val addr = UInt(addressWidth bits) })) @@ -204,46 +224,61 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.flush.rsp := flushCounter.msb.rise && flushFromInterface - val lineInfoWrite = new LineInfo() - lineInfoWrite.valid := flushCounter.msb - lineInfoWrite.address := requestIn.addr(tagRange) - when(requestIn.fire || !flushCounter.msb){ - val tagsAddress = Mux(flushCounter.msb,requestIn.addr(lineRange),flushCounter(flushCounter.high-1 downto 0)) - ways(0).tags(tagsAddress) := lineInfoWrite //TODO - } + val loadingWithErrorReg = if(catchAccessFault) RegInit(False) else null + val loadingWithError = if(catchAccessFault) loadingWithErrorReg else null + if(catchAccessFault) loadingWithErrorReg := loadingWithError + val request = requestIn.haltWhen(!io.mem.cmd.ready).stage() + + val lineInfoWrite = new LineInfo() + lineInfoWrite.valid := flushCounter.msb + lineInfoWrite.address := request.addr(tagRange) + if(catchAccessFault) lineInfoWrite.error := loadingWithError + + io.mem.cmd.valid := requestIn.valid && !request.isStall val wordIndex = Reg(UInt(log2Up(wordPerLine) bit)) val loadedWordsNext = Bits(wordPerLine bit) val loadedWords = RegNext(loadedWordsNext) val loadedWordsReadable = RegNext(loadedWords) loadedWordsNext := loadedWords - when(io.mem.rsp.fire){ + when(io.mem.rsp.valid){ wordIndex := wordIndex + 1 loadedWordsNext(wordIndex) := True ways(0).datas(request.addr(lineRange) @@ wordIndex) := io.mem.rsp.data //TODO + if(catchAccessFault) loadingWithError setWhen io.mem.rsp.error } + val memRspLast = loadedWordsNext === B(loadedWordsNext.range -> true) + val readyDelay = Reg(UInt(1 bit)) - when(loadedWordsNext === B(loadedWordsNext.range -> true)){ + when(memRspLast){ readyDelay := readyDelay + 1 } request.ready := readyDelay === 1 + + when((request.valid && memRspLast) || !flushCounter.msb){ + val tagsAddress = Mux(flushCounter.msb,request.addr(lineRange),flushCounter(flushCounter.high-1 downto 0)) + ways(0).tags(tagsAddress) := lineInfoWrite //TODO + } + when(requestIn.ready){ wordIndex := io.mem.cmd.address(wordRange) loadedWords := 0 loadedWordsReadable := 0 readyDelay := 0 + if(catchAccessFault) loadingWithErrorReg := False } } val task = new Area{ val waysHitValid = False + val waysHitError = Bool.assignDontCare() val waysHitWord = Bits(wordWidth bit) - waysHitWord.assignDontCare() +// waysHitWord.assignDontCare() val waysRead = for(way <- ways) yield new Area{ val readAddress = Mux(io.cpu.rsp.isStuck,io.cpu.rsp.address,io.cpu.cmd.address) @@ -254,18 +289,25 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ // val data = way.datas.readAsync(readAddress(lineRange.high downto wordRange.low)) // way.tags.add(new AttributeString("ramstyle","no_rw_check")) // way.datas.add(new AttributeString("ramstyle","no_rw_check")) + waysHitWord := data //Not applicable to multi way when(tag.valid && tag.address === io.cpu.rsp.address(tagRange)) { waysHitValid := True - waysHitWord := data + if(catchAccessFault) waysHitError := tag.error + } + + when(lineLoader.request.valid && lineLoader.request.addr(lineRange) === io.cpu.rsp.address(lineRange)){ + waysHitValid := False //Not applicable to multi way } } - val loaderHitValid = lineLoader.request.valid && lineLoader.request.addr(tagRange) === io.cpu.rsp.address(tagRange) + + val loaderHitValid = lineLoader.request.valid && lineLoader.request.addr(tagLineRange) === io.cpu.rsp.address(tagLineRange) val loaderHitReady = lineLoader.loadedWordsReadable(io.cpu.rsp.address(wordRange)) - io.cpu.rsp.haltIt := io.cpu.rsp.isValid && !( waysHitValid && !(loaderHitValid && !loaderHitReady)) + io.cpu.rsp.haltIt := io.cpu.rsp.isValid && !(waysHitValid || (loaderHitValid && loaderHitReady)) io.cpu.rsp.data := waysHitWord //TODO + if(catchAccessFault) io.cpu.rsp.error := (waysHitValid && waysHitError) || (loaderHitValid && loaderHitReady && lineLoader.loadingWithErrorReg) lineLoader.requestIn.valid := io.cpu.rsp.isValid && ! waysHitValid lineLoader.requestIn.addr := io.cpu.rsp.address } @@ -274,30 +316,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } object InstructionCacheMain{ - class TopLevel extends Component{ - implicit val p = InstructionCacheConfig( - cacheSize =4096, - bytePerLine =32, - wayCount = 1, - wrappedMemAccess = true, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32) -// val io = new Bundle{ -// val cpu = slave(InstructionCacheCpuBus()) -// val mem = master(InstructionCacheMemBus()) -// } - val cache = new InstructionCache(p) -// cache.io.cpu.cmd <-< io.cpu.cmd -// cache.io.mem.cmd >-> io.mem.cmd -// cache.io.mem.rsp <-< io.mem.rsp -// cache.io.cpu.rsp >-> io.cpu.rsp - // when(cache.io.cpu.rsp.valid){ - // cache.io.cpu.cmd.valid := RegNext(cache.io.cpu.cmd.valid) - // cache.io.cpu.cmd.address := RegNext(cache.io.cpu.cmd.address) - // } - } def main(args: Array[String]) { implicit val p = InstructionCacheConfig( cacheSize =4096, @@ -306,7 +325,8 @@ object InstructionCacheMain{ wrappedMemAccess = true, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32) + memDataWidth = 32, + catchAccessFault = true) // val io = new Bundle{ // val cpu = slave(InstructionCacheCpuBus()) // val mem = master(InstructionCacheMemBus()) diff --git a/src/main/scala/SpinalRiscv/TopLevel.scala b/src/main/scala/SpinalRiscv/TopLevel.scala index adb6043..e5732e2 100644 --- a/src/main/scala/SpinalRiscv/TopLevel.scala +++ b/src/main/scala/SpinalRiscv/TopLevel.scala @@ -84,7 +84,7 @@ object TopLevel { // catchAccessFault = true // ), new IBusCachedPlugin( - catchAccessFault = false, + catchAccessFault = true,//DUPLICATION cacheConfig = InstructionCacheConfig( cacheSize =4096, bytePerLine =32, @@ -92,7 +92,8 @@ object TopLevel { wrappedMemAccess = true, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32 + memDataWidth = 32, + catchAccessFault = true //DUPLICATION ) ), new DecoderSimplePlugin( @@ -156,7 +157,9 @@ object TopLevel { // ) val toplevel = new VexRiscv(config) - + toplevel.decode.input(config.INSTRUCTION).addAttribute("verilator public") + toplevel.decode.input(config.PC).addAttribute("verilator public") + toplevel.decode.arbitration.isValid.addAttribute("verilator public") // toplevel.service(classOf[DecoderSimplePlugin]).bench(toplevel) toplevel diff --git a/src/test/cpp/testA/fail.gtkw b/src/test/cpp/testA/fail.gtkw index a5e4002..e4b4acd 100644 --- a/src/test/cpp/testA/fail.gtkw +++ b/src/test/cpp/testA/fail.gtkw @@ -1,45 +1,50 @@ [*] [*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI -[*] Sat Mar 25 22:06:00 2017 +[*] Thu Mar 30 15:00:10 2017 [*] [dumpfile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/testA/dhrystoneO3.vcd" -[dumpfile_mtime] "Sat Mar 25 22:05:31 2017" -[dumpfile_size] 414222144 +[dumpfile_mtime] "Thu Mar 30 14:59:57 2017" +[dumpfile_size] 1227579722 [savefile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/testA/fail.gtkw" -[timestart] 60961 -[size] 1000 600 +[timestart] 555551 +[size] 1776 953 [pos] -1 -1 -*-7.000000 61271 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-2.000000 555567 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. -[sst_width] 201 -[signals_width] 571 +[treeopen] TOP.VexRiscv. +[sst_width] 378 +[signals_width] 418 [sst_expanded] 1 -[sst_vpaned_height] 155 +[sst_vpaned_height] 279 @28 -TOP.VexRiscv.decode_EXCEPTION -TOP.VexRiscv.execute_EXCEPTION -TOP.VexRiscv.memory_EXCEPTION -TOP.VexRiscv.writeBack_EXCEPTION -TOP.VexRiscv.execute_arbitration_isValid -TOP.VexRiscv.execute_MEMORY_ENABLE +TOP.VexRiscv.clk +TOP.VexRiscv.decode_arbitration_isValid @22 -TOP.VexRiscv.execute_PC[31:0] -TOP.VexRiscv.RegFilePlugin_regFile(8)[31:0] +TOP.VexRiscv.decode_PC[31:0] +TOP.VexRiscv.decode_INSTRUCTION[31:0] @28 -TOP.VexRiscv.writeBack_arbitration_isValid -@23 -TOP.VexRiscv.writeBack_PC[31:0] -@28 -TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_valid +TOP.VexRiscv.decode_LEGAL_INSTRUCTION @22 -TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_address[4:0] -TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_data[31:0] -TOP.VexRiscv.dCmd_payload_address[31:0] -TOP.VexRiscv.dCmd_payload_data[31:0] +TOP.VexRiscv.instructionCache_1.io_cpu_cmd_address[31:0] @28 -TOP.VexRiscv.dCmd_payload_size[1:0] -TOP.VexRiscv.dCmd_payload_wr -TOP.VexRiscv.dCmd_ready -TOP.VexRiscv.dCmd_valid +TOP.VexRiscv.instructionCache_1.io_cpu_cmd_haltIt +@22 +TOP.VexRiscv.instructionCache_1.io_cpu_rsp_address[31:0] +TOP.VexRiscv.instructionCache_1.io_cpu_rsp_data[31:0] +@28 +TOP.VexRiscv.instructionCache_1.io_cpu_rsp_haltIt +TOP.VexRiscv.instructionCache_1.io_cpu_rsp_isStuck +TOP.VexRiscv.instructionCache_1.io_cpu_rsp_isValid +TOP.VexRiscv.instructionCache_1.task_loaderHitReady +@29 +TOP.VexRiscv.instructionCache_1.task_loaderHitValid +@28 +TOP.VexRiscv.instructionCache_1.task_waysHitValid +@22 +TOP.VexRiscv.instructionCache_1.task_waysHitWord[31:0] +TOP.VexRiscv.instructionCache_1.lineLoader_request_payload_addr[31:0] +@28 +TOP.VexRiscv.instructionCache_1.lineLoader_request_ready +TOP.VexRiscv.instructionCache_1.lineLoader_request_valid [pattern_trace] 1 [pattern_trace] 0 diff --git a/src/test/cpp/testA/main.cpp b/src/test/cpp/testA/main.cpp index a38d951..b15a34b 100644 --- a/src/test/cpp/testA/main.cpp +++ b/src/test/cpp/testA/main.cpp @@ -342,6 +342,14 @@ public: } for(SimElement* simElement : simElements) simElement->preCycle(); + + if(top->VexRiscv->decode_arbitration_isValid){ + uint32_t expectedData; + bool dummy; + iBusAccess(top->VexRiscv->decode_PC, &expectedData, &dummy); + assertEq(top->VexRiscv->decode_INSTRUCTION,expectedData); + } + checks(); top->clk = 1; top->eval(); @@ -459,10 +467,11 @@ public: } virtual void postCycle(){ - bool dummy; + bool error; top->iBus_rsp_valid = 0; if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(8) < 100)){ - ws->iBusAccess(address,&top->iBus_rsp_payload_data,&dummy); + ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error); + top->iBus_rsp_payload_error = error; pendingCount--; address = (address & ~0x1F) + ((address + 4) & 0x1F); top->iBus_rsp_valid = 1;