Hardware breakpoint feature added

Murax XIP debugging passed tests
This commit is contained in:
Dolu1990 2018-09-20 13:11:20 +02:00
parent ff1d1072a7
commit 5024cc5616
4 changed files with 76 additions and 76 deletions

View File

@ -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
}

View File

@ -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")

View File

@ -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)
) )
) )

View File

@ -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()) {