From 5024cc5616f2314795c6df3db7095c0f58e30209 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 20 Sep 2018 13:11:20 +0200 Subject: [PATCH] Hardware breakpoint feature added Murax XIP debugging passed tests --- src/main/scala/vexriscv/Services.scala | 4 + src/main/scala/vexriscv/TestsWorkspace.scala | 66 ++++++++-------- src/main/scala/vexriscv/demo/Murax.scala | 6 +- .../scala/vexriscv/plugin/DebugPlugin.scala | 76 +++++++++---------- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 6ed4dcb..5a6dba2 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -88,4 +88,8 @@ class BusReport{ class CacheReport { @BeanProperty var size = 0 @BeanProperty var bytePerLine = 0 +} + +class DebugReport { + @BeanProperty var hardwareBreakpointCount = 0 } \ No newline at end of file diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 094c99b..04635db 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -31,40 +31,40 @@ object TestsWorkspace { SpinalConfig(mergeAsyncProcess = false).generateVerilog { val configFull = VexRiscvConfig( plugins = List( - new IBusSimplePlugin( - resetVector = 0x80000000l, - relaxedPcCalculation = false, - relaxedBusCmdValid = false, - prediction = NONE, - historyRamSizeLog2 = 10, - catchAccessFault = true, - compressedGen = true, - busLatencyMin = 1, - injectorStage = true - ), -// new IBusCachedPlugin( +// new IBusSimplePlugin( // resetVector = 0x80000000l, +// relaxedPcCalculation = false, +// relaxedBusCmdValid = false, +// prediction = NONE, +// historyRamSizeLog2 = 10, +// catchAccessFault = true, // compressedGen = true, -// prediction = DYNAMIC_TARGET, -// injectorStage = true, -// config = InstructionCacheConfig( -// cacheSize = 1024*16, -// bytePerLine = 32, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 32, -// catchIllegalAccess = true, -// catchAccessFault = true, -// catchMemoryTranslationMiss = true, -// asyncTagMemory = false, -// twoCycleRam = false, -// twoCycleCache = true -// ), -// memoryTranslatorPortConfig = MemoryTranslatorPortConfig( -// portTlbSize = 4 -// ) +// busLatencyMin = 1, +// injectorStage = true // ), + new IBusCachedPlugin( + resetVector = 0x80000000l, + compressedGen = true, + prediction = DYNAMIC_TARGET, + injectorStage = true, + config = InstructionCacheConfig( + cacheSize = 1024*16, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + catchMemoryTranslationMiss = true, + asyncTagMemory = false, + twoCycleRam = false, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + portTlbSize = 4 + ) + ), // new DBusSimplePlugin( // catchAddressMisaligned = true, // catchAccessFault = true, @@ -108,7 +108,7 @@ object TestsWorkspace { new SrcPlugin( separatedAddSub = false ), - new FullBarrelShifterPlugin(earlyInjection = false), + new FullBarrelShifterPlugin(earlyInjection = true), // new LightShifterPlugin, new HazardSimplePlugin( bypassExecute = true, @@ -132,7 +132,7 @@ object TestsWorkspace { new CsrPlugin(CsrPluginConfig.all(0x80000020l).copy(deterministicInteruptionEntry = false)), new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( - earlyBranch = false, + earlyBranch = true, catchAddressMisaligned = true ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 2716e04..6532458 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -40,6 +40,7 @@ case class MuraxConfig(coreFrequency : HertzNumber, gpioWidth : Int, uartCtrlConfig : UartCtrlMemoryMappedConfig, xipConfig : SpiDdrMasterCtrl.MemoryMappingParameters, + hardwareBreakpointCount : Int, cpuPlugins : ArrayBuffer[Plugin[VexRiscv]]){ require(pipelineApbBridge || pipelineMainBus, "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions") val genXpi = xipConfig != null @@ -64,6 +65,7 @@ object MuraxConfig{ rspFifoDepth = 32, xip = SpiDdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32) )), + hardwareBreakpointCount = if(withXip) 3 else 0, cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel new IBusSimplePlugin( resetVector = if(withXip) 0xF001E000l else 0x80000000l, @@ -77,7 +79,7 @@ object MuraxConfig{ catchAccessFault = false, earlyInjection = false ), - new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = 0x80000020l)), + new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = if(withXip) 0xE0040020l else 0x80000000l)), new DecoderSimplePlugin( catchIllegalInstruction = false ), @@ -216,7 +218,7 @@ case class Murax(config : MuraxConfig) extends Component{ //Instanciate the CPU val cpu = new VexRiscv( config = VexRiscvConfig( - plugins = cpuPlugins += new DebugPlugin(debugClockDomain) + plugins = cpuPlugins += new DebugPlugin(debugClockDomain, hardwareBreakpointCount) ) ) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index a91348a..70aef22 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -96,7 +96,7 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ -class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { +class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] { var io : DebugExtensionIo = null val injectionAsks = ArrayBuffer[(Stage, Bool)]() @@ -104,6 +104,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { object IS_EBREAK extends Stageable(Bool) + object DO_EBREAK extends Stageable(Bool) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ import pipeline.config._ @@ -113,15 +114,18 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(IS_EBREAK, False) - decoderService.add(EBREAK,List( - IS_EBREAK -> True, - SRC_USE_SUB_LESS -> False, - SRC1_CTRL -> Src1CtrlEnum.RS, // Zero - SRC2_CTRL -> Src2CtrlEnum.PC, - ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg - )) + decoderService.add(EBREAK,List(IS_EBREAK -> True)) injectionPort = pipeline.service(classOf[IBusFetcher]).getInjectionPort() + + if(pipeline.serviceExist(classOf[ReportService])){ + val report = pipeline.service(classOf[ReportService]) + report.add("debug" -> { + val e = new DebugReport() + e.hardwareBreakpointCount = hardwareBreakpointCount + e + }) + } } @@ -141,6 +145,11 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { val isPipBusy = isPipActive || RegNext(isPipActive) val haltedByBreak = RegInit(False) + val hardwareBreakpoints = Vec(Reg(new Bundle{ + val valid = Bool() + val pc = UInt(31 bits) + }), hardwareBreakpointCount) + hardwareBreakpoints.foreach(_.valid init(False)) val busReadDataReg = Reg(Bits(32 bit)) when(writeBack.arbitration.isValid) { @@ -160,8 +169,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { injectionPort.payload := io.bus.cmd.data when(io.bus.cmd.valid) { - switch(io.bus.cmd.address(2 downto 2)) { - is(0) { + switch(io.bus.cmd.address(7 downto 2)) { + is(0x0) { when(io.bus.cmd.wr) { stepIt := io.bus.cmd.data(4) resetIt setWhen (io.bus.cmd.data(16)) clearWhen (io.bus.cmd.data(24)) @@ -169,45 +178,31 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { haltedByBreak clearWhen (io.bus.cmd.data(25)) } } - is(1) { + is(0x1) { when(io.bus.cmd.wr) { injectionPort.valid := True io.bus.cmd.ready := injectionPort.ready } } + for(i <- 0 until hardwareBreakpointCount){ + is(0x10 + i){ + when(io.bus.cmd.wr){ + hardwareBreakpoints(i).assignFromBits(io.bus.cmd.data) + } + } + } } } - - -// Component.current.addPrePopTask(() => { -// //Check if the decode instruction is driven by a register -// val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null} -// if(instructionDriver != null){ //If yes => -// //Insert the instruction by writing the "fetch to decode instruction register", -// // Work even if it need to cross some hierarchy (caches) -// instructionDriver.component.rework { -// when(insertDecodeInstruction.pull()) { -// instructionDriver := io.bus.cmd.data.pull() -// } -// } -// } else{ -// //Insert the instruction via a mux in the decode stage -// when(RegNext(insertDecodeInstruction)){ -// decode.input(INSTRUCTION) := RegNext(io.bus.cmd.data) -// } -// } -// }) -// - - when(execute.input(IS_EBREAK)){ - when(execute.arbitration.isValid ) { - iBusFetcher.flushIt() - iBusFetcher.haltIt() - decode.arbitration.flushAll := True - } - when(execute.arbitration.isFiring) { + decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (execute.input(PC) >> 1)).foldLeft(False)(_ || _)) + when(execute.arbitration.isValid && execute.input(DO_EBREAK)){ + iBusFetcher.flushIt() + iBusFetcher.haltIt() + execute.arbitration.haltByOther := True + busReadDataReg := execute.input(PC).asBits + when(List(memory, writeBack).map(_.arbitration.isValid).orR === False){ + execute.arbitration.flushAll := True haltIt := True haltedByBreak := True } @@ -215,7 +210,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { when(haltIt) { iBusFetcher.haltIt() -// decode.arbitration.haltByOther := True } when(stepIt && iBusFetcher.incoming()) {