diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index de29409..ccc1f57 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -6,8 +6,10 @@ import spinal.core.sim.{onSimEnd, simSuccess} import spinal.lib._ import spinal.lib.bus.bmb.sim.BmbMemoryAgent import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} -import spinal.lib.com.jtag.Jtag +import spinal.lib.bus.misc.SizeMapping +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} @@ -38,21 +40,23 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val externalInterrupts = in Bits(p.cpuConfigs.size bits) val softwareInterrupts = in Bits(p.cpuConfigs.size bits) val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) - val jtag = slave(Jtag()) + val debugBus = slave(Bmb(SystemDebuggerConfig().getBmbParameter.copy(addressWidth = 20))) val debugReset = out Bool() val time = in UInt(64 bits) } + io.debugReset := False val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ var iBus : Bmb = null var dBus : Bmb = null + var debug : Bmb = null cpuConfig.plugins.foreach { case plugin: DebugPlugin => debugClockDomain{ plugin.debugClockDomain = debugClockDomain } case _ => } - if(cpuId == 0) cpuConfig.plugins += new DebugPlugin(debugClockDomain) + cpuConfig.plugins += new DebugPlugin(debugClockDomain) val core = new VexRiscv(cpuConfig) core.plugins.foreach { case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() @@ -65,8 +69,8 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, if (plugin.utime != null) plugin.utime := io.time } case plugin: DebugPlugin => debugClockDomain{ - io.debugReset := RegNext(plugin.io.resetOut) - io.jtag <> plugin.io.bus.fromJtag() + io.debugReset setWhen(RegNext(plugin.io.resetOut)) + debug = plugin.io.bus.fromBmb() } case _ => } @@ -97,19 +101,18 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, io.dMem << invalidateMonitor.io.output -// val iBusArbiter = BmbArbiter( -// p = iBusArbiterParameter, -// portCount = cpus.size, -// pendingRspMax = 64, -// lowerFirstPriority = false, -// inputsWithInv = cpus.map(_ => true), -// inputsWithSync = cpus.map(_ => true), -// pendingInvMax = 16 -// ) -// -// (iBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.iBus) -// io.iMem << iBusArbiter.io.output (io.iMems, cpus).zipped.foreach(_ << _.iBus) + + val debug = debugClockDomain on new Area{ + val arbiter = BmbDecoder( + p = io.debugBus.p, + mappings = List.tabulate(p.cpuConfigs.size)(i => SizeMapping(0x00000 + i*0x1000, 0x1000)), + capabilities = List.fill(p.cpuConfigs.size)(io.debugBus.p), + pendingMax = 2 + ) + arbiter.io.input << io.debugBus + (arbiter.io.outputs, cpus.map(_.debug)).zipped.foreach(_ >> _) + } } @@ -417,10 +420,7 @@ object VexRiscvSmpClusterTestInfrastructure{ import spinal.core.sim._ dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) -// JtagTcp(dut.io.jtag, 100) - dut.io.jtag.tck #= false - dut.io.jtag.tdi #= false - dut.io.jtag.tms #= false + dut.io.debugBus.cmd.valid #= false } } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 9466cfe..43ae242 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -3,13 +3,15 @@ package vexriscv.demo.smp import spinal.core._ import spinal.lib.bus.bmb._ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib._ import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint +import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} @@ -25,7 +27,8 @@ case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParamet //addAttribute("""mark_debug = "true"""") case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, - debugClockDomain : ClockDomain) extends Component{ + debugClockDomain : ClockDomain, + jtagClockDomain : ClockDomain) extends Component{ val peripheralWishboneConfig = WishboneConfig( addressWidth = 30, @@ -41,9 +44,9 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, val iMem = master(LiteDramNative(p.liteDram)) val peripheral = master(Wishbone(peripheralWishboneConfig)) val clint = slave(Wishbone(Clint.getWisboneConfig())) - val externalInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val externalSupervisorInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val jtag = slave(Jtag()) + val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) + val interrupts = in Bits(32 bits) + val jtagInstruction = slave(JtagTapInstructionCtrl()) val debugReset = out Bool() } val cpuCount = p.cluster.cpuConfigs.size @@ -51,14 +54,25 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, clint.driveFrom(WishboneSlaveFactory(io.clint)) val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) - cluster.io.externalInterrupts <> io.externalInterrupts - cluster.io.externalSupervisorInterrupts <> io.externalSupervisorInterrupts - cluster.io.jtag <> io.jtag cluster.io.debugReset <> io.debugReset cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) cluster.io.time := clint.time + val debug = debugClockDomain on new Area{ + val jtagConfig = SystemDebuggerConfig() + val jtagBridge = new JtagBridgeNoTap( + c = jtagConfig, + jtagClockDomain = jtagClockDomain + ) + jtagBridge.io.ctrl << io.jtagInstruction + + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + + cluster.io.debugBus << debugger.io.mem.toBmb() + } + val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, mappings = Seq(DefaultMapping, p.liteDramMapping), @@ -114,9 +128,39 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() io.peripheral << peripheralWishbone + + val plic = new Area{ + val priorityWidth = 2 + + val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( + source = io.interrupts(i), + id = i, + priorityWidth = priorityWidth + ) + + val bus = WishboneSlaveFactory(io.plic) + + val targets = for(i <- 0 until cpuCount) yield new Area{ + val machine = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + val supervisor = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + + cluster.io.externalInterrupts(i) := machine.iep + cluster.io.externalSupervisorInterrupts(i) := supervisor.iep + } + + val bridge = PlicMapper(bus, PlicMapping.sifive)( + gateways = gateways, + targets = targets.flatMap(t => List(t.machine, t.supervisor)) + ) + } } -//ifconfig eth0 192.168.0.50 netmask 255.255.255.0 up object VexRiscvLitexSmpClusterGen extends App { for(cpuCount <- List(1,2,4,8)) { def parameter = VexRiscvLitexSmpClusterParameter( @@ -136,7 +180,8 @@ object VexRiscvLitexSmpClusterGen extends App { def dutGen = { val toplevel = VexRiscvLitexSmpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) ) toplevel } @@ -175,7 +220,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ def dutGen = { val top = VexRiscvLitexSmpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) ) top.rework{ top.io.clint.setAsDirectionLess.allowDirectionLessIo @@ -216,8 +262,7 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ dut.io.iMem.simSlave(ram, dut.clockDomain) dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified) - dut.io.externalInterrupts #= 0 - dut.io.externalSupervisorInterrupts #= 0 + dut.io.interrupts #= 0 dut.clockDomain.onFallingEdges{ if(dut.io.peripheral.CYC.toBoolean){ diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 0f2af9b..3631cfc 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -3,13 +3,19 @@ package vexriscv.demo.smp import spinal.core._ import spinal.lib.bus.bmb._ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.{Jtag, JtagTap, JtagTapInstructionCtrl} import spinal.lib._ +import spinal.lib.blackbox.xilinx.s7.BSCANE2 import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.com.jtag.xilinx.Bscane2BmbMaster import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint +import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} +import sun.jvm.hotspot.oops.DataLayout import vexriscv.demo.smp.VexRiscvLitexSmpMpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} @@ -24,8 +30,9 @@ case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParam liteDramMapping : AddressMapping) //addAttribute("""mark_debug = "true"""") -case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, - debugClockDomain : ClockDomain) extends Component{ +class VexRiscvLitexSmpMpCluster(val p : VexRiscvLitexSmpMpClusterParameter, + val debugClockDomain : ClockDomain, + val jtagClockDomain : ClockDomain) extends Component{ val peripheralWishboneConfig = WishboneConfig( addressWidth = 30, @@ -43,23 +50,48 @@ case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, val iMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) val peripheral = master(Wishbone(peripheralWishboneConfig)) val clint = slave(Wishbone(Clint.getWisboneConfig())) - val externalInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val externalSupervisorInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val jtag = slave(Jtag()) + val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) + val interrupts = in Bits(32 bits) + val jtagInstruction = slave(JtagTapInstructionCtrl()) val debugReset = out Bool() } val clint = Clint(cpuCount) clint.driveFrom(WishboneSlaveFactory(io.clint)) val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) - cluster.io.externalInterrupts <> io.externalInterrupts - cluster.io.externalSupervisorInterrupts <> io.externalSupervisorInterrupts - cluster.io.jtag <> io.jtag cluster.io.debugReset <> io.debugReset cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) cluster.io.time := clint.time + val debug = debugClockDomain on new Area{ + val jtagConfig = SystemDebuggerConfig() + + val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) + jtagBridge.io.ctrl << io.jtagInstruction + + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + + cluster.io.debugBus << debugger.io.mem.toBmb() + +// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess +// val bridge = Bscane2BmbMaster(1) +// cluster.io.debugBus << bridge.io.bmb + + +// val bscane2 = BSCANE2(usedId) +// val jtagClockDomain = ClockDomain(bscane2.TCK) +// +// val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) +// jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl() +// +// val debugger = new SystemDebugger(jtagConfig) +// debugger.io.remote <> jtagBridge.io.remote +// +// io.bmb << debugger.io.mem.toBmb() + } + val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, mappings = Seq(DefaultMapping, p.liteDramMapping), @@ -116,6 +148,38 @@ case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, val dMemBridge = for(id <- 0 until cpuCount) yield { io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) } + + + val plic = new Area{ + val priorityWidth = 2 + + val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( + source = io.interrupts(i), + id = i, + priorityWidth = priorityWidth + ) + + val bus = WishboneSlaveFactory(io.plic) + + val targets = for(i <- 0 until cpuCount) yield new Area{ + val machine = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + val supervisor = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + + cluster.io.externalInterrupts(i) := machine.iep + cluster.io.externalSupervisorInterrupts(i) := supervisor.iep + } + + val bridge = PlicMapper(bus, PlicMapping.sifive)( + gateways = gateways, + targets = targets.flatMap(t => List(t.machine, t.supervisor)) + ) + } // // io.dMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) // io.dMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) @@ -145,9 +209,10 @@ object VexRiscvLitexSmpMpClusterGen extends App { ) def dutGen = { - val toplevel = VexRiscvLitexSmpMpCluster( + val toplevel = new VexRiscvLitexSmpMpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) ) toplevel } @@ -185,10 +250,20 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ ) def dutGen = { - val top = VexRiscvLitexSmpMpCluster( + val top = new VexRiscvLitexSmpMpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) - ) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) + ){ + io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess + val jtag = slave(Jtag()) + jtagClockDomain.readClockWire.setAsDirectionLess() := jtag.tck + val jtagLogic = jtagClockDomain on new Area{ + val tap = new JtagTap(jtag, 4) + val idcodeArea = tap.idcode(B"x10001FFF")(1) + val wrapper = tap.map(io.jtagInstruction, instructionId = 2) + } + } top.rework{ top.io.clint.setAsDirectionLess.allowDirectionLessIo top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() @@ -217,6 +292,7 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ dut.debugClockDomain.resetSim #= false } + JtagTcp(dut.jtag, 10*20) val ram = SparseMemory() ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") @@ -229,8 +305,8 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ dut.io.dMem(id).simSlave(ram, dut.clockDomain) } - dut.io.externalInterrupts #= 0 - dut.io.externalSupervisorInterrupts #= 0 + dut.io.interrupts #= 0 + // val stdin = mutable.Queue[Byte]() // def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte) @@ -272,7 +348,7 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ fork{ val at = 0 - val duration = 0 + val duration = 1000 while(simTime() < at*1000000l) { disableSimWave() sleep(100000 * 10)