Hardware breakpoint feature added
Murax XIP debugging passed tests
This commit is contained in:
parent
ff1d1072a7
commit
5024cc5616
|
@ -89,3 +89,7 @@ class CacheReport {
|
||||||
@BeanProperty var size = 0
|
@BeanProperty var size = 0
|
||||||
@BeanProperty var bytePerLine = 0
|
@BeanProperty var bytePerLine = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DebugReport {
|
||||||
|
@BeanProperty var hardwareBreakpointCount = 0
|
||||||
|
}
|
|
@ -31,40 +31,40 @@ object TestsWorkspace {
|
||||||
SpinalConfig(mergeAsyncProcess = false).generateVerilog {
|
SpinalConfig(mergeAsyncProcess = false).generateVerilog {
|
||||||
val configFull = VexRiscvConfig(
|
val configFull = VexRiscvConfig(
|
||||||
plugins = List(
|
plugins = List(
|
||||||
new IBusSimplePlugin(
|
// new IBusSimplePlugin(
|
||||||
resetVector = 0x80000000l,
|
|
||||||
relaxedPcCalculation = false,
|
|
||||||
relaxedBusCmdValid = false,
|
|
||||||
prediction = NONE,
|
|
||||||
historyRamSizeLog2 = 10,
|
|
||||||
catchAccessFault = true,
|
|
||||||
compressedGen = true,
|
|
||||||
busLatencyMin = 1,
|
|
||||||
injectorStage = true
|
|
||||||
),
|
|
||||||
// new IBusCachedPlugin(
|
|
||||||
// resetVector = 0x80000000l,
|
// resetVector = 0x80000000l,
|
||||||
|
// relaxedPcCalculation = false,
|
||||||
|
// relaxedBusCmdValid = false,
|
||||||
|
// prediction = NONE,
|
||||||
|
// historyRamSizeLog2 = 10,
|
||||||
|
// catchAccessFault = true,
|
||||||
// compressedGen = true,
|
// compressedGen = true,
|
||||||
// prediction = DYNAMIC_TARGET,
|
// busLatencyMin = 1,
|
||||||
// injectorStage = true,
|
// 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 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(
|
// new DBusSimplePlugin(
|
||||||
// catchAddressMisaligned = true,
|
// catchAddressMisaligned = true,
|
||||||
// catchAccessFault = true,
|
// catchAccessFault = true,
|
||||||
|
@ -108,7 +108,7 @@ object TestsWorkspace {
|
||||||
new SrcPlugin(
|
new SrcPlugin(
|
||||||
separatedAddSub = false
|
separatedAddSub = false
|
||||||
),
|
),
|
||||||
new FullBarrelShifterPlugin(earlyInjection = false),
|
new FullBarrelShifterPlugin(earlyInjection = true),
|
||||||
// new LightShifterPlugin,
|
// new LightShifterPlugin,
|
||||||
new HazardSimplePlugin(
|
new HazardSimplePlugin(
|
||||||
bypassExecute = true,
|
bypassExecute = true,
|
||||||
|
@ -132,7 +132,7 @@ object TestsWorkspace {
|
||||||
new CsrPlugin(CsrPluginConfig.all(0x80000020l).copy(deterministicInteruptionEntry = false)),
|
new CsrPlugin(CsrPluginConfig.all(0x80000020l).copy(deterministicInteruptionEntry = false)),
|
||||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||||
new BranchPlugin(
|
new BranchPlugin(
|
||||||
earlyBranch = false,
|
earlyBranch = true,
|
||||||
catchAddressMisaligned = true
|
catchAddressMisaligned = true
|
||||||
),
|
),
|
||||||
new YamlPlugin("cpu0.yaml")
|
new YamlPlugin("cpu0.yaml")
|
||||||
|
|
|
@ -40,6 +40,7 @@ case class MuraxConfig(coreFrequency : HertzNumber,
|
||||||
gpioWidth : Int,
|
gpioWidth : Int,
|
||||||
uartCtrlConfig : UartCtrlMemoryMappedConfig,
|
uartCtrlConfig : UartCtrlMemoryMappedConfig,
|
||||||
xipConfig : SpiDdrMasterCtrl.MemoryMappingParameters,
|
xipConfig : SpiDdrMasterCtrl.MemoryMappingParameters,
|
||||||
|
hardwareBreakpointCount : Int,
|
||||||
cpuPlugins : ArrayBuffer[Plugin[VexRiscv]]){
|
cpuPlugins : ArrayBuffer[Plugin[VexRiscv]]){
|
||||||
require(pipelineApbBridge || pipelineMainBus, "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions")
|
require(pipelineApbBridge || pipelineMainBus, "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions")
|
||||||
val genXpi = xipConfig != null
|
val genXpi = xipConfig != null
|
||||||
|
@ -64,6 +65,7 @@ object MuraxConfig{
|
||||||
rspFifoDepth = 32,
|
rspFifoDepth = 32,
|
||||||
xip = SpiDdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32)
|
xip = SpiDdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32)
|
||||||
)),
|
)),
|
||||||
|
hardwareBreakpointCount = if(withXip) 3 else 0,
|
||||||
cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel
|
cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel
|
||||||
new IBusSimplePlugin(
|
new IBusSimplePlugin(
|
||||||
resetVector = if(withXip) 0xF001E000l else 0x80000000l,
|
resetVector = if(withXip) 0xF001E000l else 0x80000000l,
|
||||||
|
@ -77,7 +79,7 @@ object MuraxConfig{
|
||||||
catchAccessFault = false,
|
catchAccessFault = false,
|
||||||
earlyInjection = false
|
earlyInjection = false
|
||||||
),
|
),
|
||||||
new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = 0x80000020l)),
|
new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = if(withXip) 0xE0040020l else 0x80000000l)),
|
||||||
new DecoderSimplePlugin(
|
new DecoderSimplePlugin(
|
||||||
catchIllegalInstruction = false
|
catchIllegalInstruction = false
|
||||||
),
|
),
|
||||||
|
@ -216,7 +218,7 @@ case class Murax(config : MuraxConfig) extends Component{
|
||||||
//Instanciate the CPU
|
//Instanciate the CPU
|
||||||
val cpu = new VexRiscv(
|
val cpu = new VexRiscv(
|
||||||
config = VexRiscvConfig(
|
config = VexRiscvConfig(
|
||||||
plugins = cpuPlugins += new DebugPlugin(debugClockDomain)
|
plugins = cpuPlugins += new DebugPlugin(debugClockDomain, hardwareBreakpointCount)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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
|
var io : DebugExtensionIo = null
|
||||||
val injectionAsks = ArrayBuffer[(Stage, Bool)]()
|
val injectionAsks = ArrayBuffer[(Stage, Bool)]()
|
||||||
|
@ -104,6 +104,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
||||||
|
|
||||||
|
|
||||||
object IS_EBREAK extends Stageable(Bool)
|
object IS_EBREAK extends Stageable(Bool)
|
||||||
|
object DO_EBREAK extends Stageable(Bool)
|
||||||
override def setup(pipeline: VexRiscv): Unit = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
import Riscv._
|
import Riscv._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
@ -113,15 +114,18 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
||||||
val decoderService = pipeline.service(classOf[DecoderService])
|
val decoderService = pipeline.service(classOf[DecoderService])
|
||||||
|
|
||||||
decoderService.addDefault(IS_EBREAK, False)
|
decoderService.addDefault(IS_EBREAK, False)
|
||||||
decoderService.add(EBREAK,List(
|
decoderService.add(EBREAK,List(IS_EBREAK -> True))
|
||||||
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
|
|
||||||
))
|
|
||||||
|
|
||||||
injectionPort = pipeline.service(classOf[IBusFetcher]).getInjectionPort()
|
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 isPipBusy = isPipActive || RegNext(isPipActive)
|
||||||
val haltedByBreak = RegInit(False)
|
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))
|
val busReadDataReg = Reg(Bits(32 bit))
|
||||||
when(writeBack.arbitration.isValid) {
|
when(writeBack.arbitration.isValid) {
|
||||||
|
@ -160,8 +169,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
||||||
injectionPort.payload := io.bus.cmd.data
|
injectionPort.payload := io.bus.cmd.data
|
||||||
|
|
||||||
when(io.bus.cmd.valid) {
|
when(io.bus.cmd.valid) {
|
||||||
switch(io.bus.cmd.address(2 downto 2)) {
|
switch(io.bus.cmd.address(7 downto 2)) {
|
||||||
is(0) {
|
is(0x0) {
|
||||||
when(io.bus.cmd.wr) {
|
when(io.bus.cmd.wr) {
|
||||||
stepIt := io.bus.cmd.data(4)
|
stepIt := io.bus.cmd.data(4)
|
||||||
resetIt setWhen (io.bus.cmd.data(16)) clearWhen (io.bus.cmd.data(24))
|
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))
|
haltedByBreak clearWhen (io.bus.cmd.data(25))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is(1) {
|
is(0x1) {
|
||||||
when(io.bus.cmd.wr) {
|
when(io.bus.cmd.wr) {
|
||||||
injectionPort.valid := True
|
injectionPort.valid := True
|
||||||
io.bus.cmd.ready := injectionPort.ready
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)){
|
||||||
// Component.current.addPrePopTask(() => {
|
iBusFetcher.flushIt()
|
||||||
// //Check if the decode instruction is driven by a register
|
iBusFetcher.haltIt()
|
||||||
// val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null}
|
execute.arbitration.haltByOther := True
|
||||||
// if(instructionDriver != null){ //If yes =>
|
busReadDataReg := execute.input(PC).asBits
|
||||||
// //Insert the instruction by writing the "fetch to decode instruction register",
|
when(List(memory, writeBack).map(_.arbitration.isValid).orR === False){
|
||||||
// // Work even if it need to cross some hierarchy (caches)
|
execute.arbitration.flushAll := True
|
||||||
// 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) {
|
|
||||||
haltIt := True
|
haltIt := True
|
||||||
haltedByBreak := True
|
haltedByBreak := True
|
||||||
}
|
}
|
||||||
|
@ -215,7 +210,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
||||||
|
|
||||||
when(haltIt) {
|
when(haltIt) {
|
||||||
iBusFetcher.haltIt()
|
iBusFetcher.haltIt()
|
||||||
// decode.arbitration.haltByOther := True
|
|
||||||
}
|
}
|
||||||
|
|
||||||
when(stepIt && iBusFetcher.incoming()) {
|
when(stepIt && iBusFetcher.incoming()) {
|
||||||
|
|
Loading…
Reference in New Issue