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 bytePerLine = 0
|
||||
}
|
||||
|
||||
class DebugReport {
|
||||
@BeanProperty var hardwareBreakpointCount = 0
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Reference in New Issue