Got VexRiscvSmpLitexCluster refractoring to work
This commit is contained in:
parent
0da94ac66f
commit
32539dfe6d
|
@ -0,0 +1,156 @@
|
||||||
|
package vexriscv
|
||||||
|
|
||||||
|
import spinal.core._
|
||||||
|
import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbParameter, BmbSmpInterconnectGenerator}
|
||||||
|
import spinal.lib.bus.misc.AddressMapping
|
||||||
|
import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl}
|
||||||
|
import spinal.lib.generator._
|
||||||
|
import spinal.lib.slave
|
||||||
|
import vexriscv.plugin._
|
||||||
|
|
||||||
|
|
||||||
|
object VexRiscvBmbGenerator{
|
||||||
|
val DEBUG_NONE = 0
|
||||||
|
val DEBUG_JTAG = 1
|
||||||
|
val DEBUG_JTAG_CTRL = 2
|
||||||
|
val DEBUG_BUS = 3
|
||||||
|
val DEBUG_BMB = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbSmpInterconnectGenerator = null) extends Generator {
|
||||||
|
import VexRiscvBmbGenerator._
|
||||||
|
|
||||||
|
val config = Handle[VexRiscvConfig]
|
||||||
|
val withDebug = Handle[Int]
|
||||||
|
val debugClockDomain = Handle[ClockDomain]
|
||||||
|
val debugReset = Handle[Bool]
|
||||||
|
val debugAskReset = Handle[() => Unit]
|
||||||
|
val hardwareBreakpointCount = Handle(0)
|
||||||
|
|
||||||
|
val iBus, dBus = product[Bmb]
|
||||||
|
|
||||||
|
val externalInterrupt = product[Bool]
|
||||||
|
val externalSupervisorInterrupt = product[Bool]
|
||||||
|
val timerInterrupt = product[Bool]
|
||||||
|
val softwareInterrupt = product[Bool]
|
||||||
|
|
||||||
|
def setTimerInterrupt(that: Handle[Bool]) = Dependable(that, timerInterrupt){timerInterrupt := that}
|
||||||
|
def setSoftwareInterrupt(that: Handle[Bool]) = Dependable(that, softwareInterrupt){softwareInterrupt := that}
|
||||||
|
|
||||||
|
|
||||||
|
def disableDebug() = {
|
||||||
|
withDebug.load(DEBUG_NONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{
|
||||||
|
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||||
|
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||||
|
debugAskReset.load(null)
|
||||||
|
withDebug.load(DEBUG_JTAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{
|
||||||
|
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||||
|
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||||
|
debugAskReset.load(null)
|
||||||
|
withDebug.load(DEBUG_JTAG_CTRL)
|
||||||
|
dependencies += jtagClockDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{
|
||||||
|
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||||
|
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||||
|
debugAskReset.load(null)
|
||||||
|
withDebug.load(DEBUG_BUS)
|
||||||
|
}
|
||||||
|
|
||||||
|
val debugBmbAccessSource = Handle[BmbAccessCapabilities]
|
||||||
|
val debugBmbAccessRequirements = Handle[BmbAccessParameter]
|
||||||
|
def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd{
|
||||||
|
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||||
|
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||||
|
debugAskReset.load(null)
|
||||||
|
withDebug.load(DEBUG_BMB)
|
||||||
|
val slaveModel = interconnectSmp.addSlave(
|
||||||
|
accessSource = debugBmbAccessSource,
|
||||||
|
accessCapabilities = debugBmbAccessSource.derivate(DebugExtensionBus.getBmbAccessParameter(_)),
|
||||||
|
accessRequirements = debugBmbAccessRequirements,
|
||||||
|
bus = debugBmb,
|
||||||
|
mapping = mapping
|
||||||
|
)
|
||||||
|
slaveModel.onClockDomain(debugCd.outputClockDomain)
|
||||||
|
debugBmb.derivatedFrom(debugBmbAccessRequirements)(Bmb(_))
|
||||||
|
if(debugMaster != null) interconnectSmp.addConnection(debugMaster.bus, debugBmb)
|
||||||
|
dependencies += debugBmb
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dependencies ++= List(config)
|
||||||
|
dependencies += Dependable(withDebug) {
|
||||||
|
if (withDebug.get != DEBUG_NONE) {
|
||||||
|
dependencies ++= List(debugClockDomain, debugAskReset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jtag = add task (withDebug.get == DEBUG_JTAG generate slave(Jtag()))
|
||||||
|
val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl())
|
||||||
|
val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus())
|
||||||
|
val debugBmb = Handle[Bmb]
|
||||||
|
val jtagClockDomain = Handle[ClockDomain]
|
||||||
|
|
||||||
|
val logic = add task new Area {
|
||||||
|
withDebug.get != DEBUG_NONE generate new Area {
|
||||||
|
config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
val cpu = new VexRiscv(config)
|
||||||
|
for (plugin <- cpu.plugins) plugin match {
|
||||||
|
case plugin: IBusSimplePlugin => iBus.load(plugin.iBus.toBmb())
|
||||||
|
case plugin: DBusSimplePlugin => dBus.load(plugin.dBus.toBmb())
|
||||||
|
case plugin: IBusCachedPlugin => iBus.load(plugin.iBus.toBmb())
|
||||||
|
case plugin: DBusCachedPlugin => dBus.load(plugin.dBus.toBmb())
|
||||||
|
case plugin: CsrPlugin => {
|
||||||
|
externalInterrupt load plugin.externalInterrupt
|
||||||
|
timerInterrupt load plugin.timerInterrupt
|
||||||
|
softwareInterrupt load plugin.softwareInterrupt
|
||||||
|
if (plugin.config.supervisorGen) externalSupervisorInterrupt load plugin.externalInterruptS
|
||||||
|
}
|
||||||
|
case plugin: DebugPlugin => plugin.debugClockDomain {
|
||||||
|
if(debugAskReset.get != null) when(RegNext(plugin.io.resetOut)) {
|
||||||
|
debugAskReset.get()
|
||||||
|
} else {
|
||||||
|
debugReset.load(RegNext(plugin.io.resetOut))
|
||||||
|
}
|
||||||
|
|
||||||
|
withDebug.get match {
|
||||||
|
case DEBUG_JTAG => jtag <> plugin.io.bus.fromJtag()
|
||||||
|
case DEBUG_JTAG_CTRL => jtagInstructionCtrl <> plugin.io.bus.fromJtagInstructionCtrl(jtagClockDomain)
|
||||||
|
case DEBUG_BUS => debugBus <> plugin.io.bus
|
||||||
|
case DEBUG_BMB => debugBmb >> plugin.io.bus.fromBmb()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val parameterGenerator = new Generator {
|
||||||
|
val iBusParameter, dBusParameter = product[BmbParameter]
|
||||||
|
dependencies += config
|
||||||
|
|
||||||
|
add task {
|
||||||
|
for (plugin <- config.plugins) plugin match {
|
||||||
|
case plugin: IBusSimplePlugin => iBusParameter.load(IBusSimpleBus.getBmbParameter())
|
||||||
|
case plugin: DBusSimplePlugin => dBusParameter.load(DBusSimpleBus.getBmbParameter())
|
||||||
|
case plugin: IBusCachedPlugin => iBusParameter.load(plugin.config.getBmbParameter())
|
||||||
|
case plugin: DBusCachedPlugin => dBusParameter.load(plugin.config.getBmbParameter())
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(interconnectSmp != null){
|
||||||
|
interconnectSmp.addMaster(accessRequirements = parameterGenerator.iBusParameter.derivate(_.access), bus = iBus)
|
||||||
|
interconnectSmp.addMaster(accessRequirements = parameterGenerator.dBusParameter.derivate(_.access), bus = dBus)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import spinal.lib._
|
||||||
import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester}
|
import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester}
|
||||||
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
||||||
import spinal.lib.eda.bench.Bench
|
import spinal.lib.eda.bench.Bench
|
||||||
|
import spinal.lib.generator.{Generator, Handle}
|
||||||
import spinal.lib.misc.Clint
|
import spinal.lib.misc.Clint
|
||||||
import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer}
|
import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer}
|
||||||
import vexriscv.{VexRiscv, VexRiscvConfig}
|
import vexriscv.{VexRiscv, VexRiscvConfig}
|
||||||
|
@ -245,3 +246,43 @@ object BmbToLiteDramTester extends App{
|
||||||
dut.io.output.simSlave(tester.memory.memory, dut.clockDomain)
|
dut.io.output.simSlave(tester.memory.memory, dut.clockDomain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbSmpInterconnectGenerator) extends Generator{
|
||||||
|
val liteDramParameter = createDependency[LiteDramNativeParameter]
|
||||||
|
val bmb = produce(logic.io.input)
|
||||||
|
val dram = produceIo(logic.io.output)
|
||||||
|
|
||||||
|
val accessSource = Handle[BmbAccessCapabilities]
|
||||||
|
val accessRequirements = createDependency[BmbAccessParameter]
|
||||||
|
interconnect.addSlave(
|
||||||
|
accessSource = accessSource,
|
||||||
|
accessCapabilities = accessSource,
|
||||||
|
accessRequirements = accessRequirements,
|
||||||
|
bus = bmb,
|
||||||
|
mapping = mapping
|
||||||
|
)
|
||||||
|
val logic = add task BmbToLiteDram(
|
||||||
|
bmbParameter = accessRequirements.toBmbParameter(),
|
||||||
|
liteDramParameter = liteDramParameter,
|
||||||
|
wdataFifoSize = 32,
|
||||||
|
rdataFifoSize = 32
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbSmpInterconnectGenerator) extends Generator{
|
||||||
|
val bmb = produce(logic.io.input)
|
||||||
|
val wishbone = produce(logic.io.output)
|
||||||
|
|
||||||
|
val accessSource = Handle[BmbAccessCapabilities]
|
||||||
|
val accessRequirements = createDependency[BmbAccessParameter]
|
||||||
|
interconnect.addSlave(
|
||||||
|
accessSource = accessSource,
|
||||||
|
accessCapabilities = accessSource,
|
||||||
|
accessRequirements = accessRequirements,
|
||||||
|
bus = bmb,
|
||||||
|
mapping = mapping
|
||||||
|
)
|
||||||
|
val logic = add task BmbToWishbone(
|
||||||
|
p = accessRequirements.toBmbParameter()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -5,21 +5,110 @@ import spinal.core._
|
||||||
import spinal.core.sim.{onSimEnd, simSuccess}
|
import spinal.core.sim.{onSimEnd, simSuccess}
|
||||||
import spinal.lib._
|
import spinal.lib._
|
||||||
import spinal.lib.bus.bmb.sim.BmbMemoryAgent
|
import spinal.lib.bus.bmb.sim.BmbMemoryAgent
|
||||||
import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter}
|
import spinal.lib.bus.bmb._
|
||||||
import spinal.lib.bus.misc.SizeMapping
|
import spinal.lib.bus.misc.{DefaultMapping, SizeMapping}
|
||||||
import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl}
|
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneToBmb, WishboneToBmbGenerator}
|
||||||
|
import spinal.lib.com.jtag.{Jtag, JtagInstructionDebuggerGenerator, JtagTapInstructionCtrl}
|
||||||
import spinal.lib.com.jtag.sim.JtagTcp
|
import spinal.lib.com.jtag.sim.JtagTcp
|
||||||
|
import spinal.lib.com.jtag.xilinx.Bscane2BmbMasterGenerator
|
||||||
|
import spinal.lib.generator.Handle
|
||||||
|
import spinal.lib.misc.plic.PlicMapping
|
||||||
import spinal.lib.system.debugger.SystemDebuggerConfig
|
import spinal.lib.system.debugger.SystemDebuggerConfig
|
||||||
import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig}
|
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.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}
|
import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import spinal.lib.generator._
|
||||||
|
|
||||||
|
case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig])
|
||||||
|
|
||||||
|
class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{
|
||||||
|
val cpuCount = p.cpuConfigs.size
|
||||||
|
|
||||||
|
val debugCd = ClockDomainResetGenerator()
|
||||||
|
debugCd.holdDuration.load(4095)
|
||||||
|
debugCd.makeExternal()
|
||||||
|
|
||||||
|
val systemCd = ClockDomainResetGenerator()
|
||||||
|
systemCd.holdDuration.load(63)
|
||||||
|
systemCd.setInput(debugCd)
|
||||||
|
|
||||||
|
this.onClockDomain(systemCd.outputClockDomain)
|
||||||
|
|
||||||
|
implicit val interconnect = BmbSmpInterconnectGenerator()
|
||||||
|
|
||||||
|
val debugBridge = JtagInstructionDebuggerGenerator() onClockDomain(debugCd.outputClockDomain)
|
||||||
|
debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false))
|
||||||
|
|
||||||
|
val debugPort = debugBridge.produceIo(debugBridge.logic.jtagBridge.io.ctrl)
|
||||||
|
|
||||||
|
val exclusiveMonitor = BmbExclusiveMonitorGenerator()
|
||||||
|
val invalidationMonitor = BmbInvalidateMonitorGenerator()
|
||||||
|
interconnect.addConnection(exclusiveMonitor.output, invalidationMonitor.input)
|
||||||
|
interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder()
|
||||||
|
|
||||||
|
val cores = for(cpuId <- 0 until cpuCount) yield new Area{
|
||||||
|
val cpu = VexRiscvBmbGenerator()
|
||||||
|
cpu.config.load(p.cpuConfigs(cpuId))
|
||||||
|
interconnect.addConnection(
|
||||||
|
cpu.dBus -> List(exclusiveMonitor.input)
|
||||||
|
)
|
||||||
|
cpu.enableDebugBmb(
|
||||||
|
debugCd = debugCd,
|
||||||
|
resetCd = systemCd,
|
||||||
|
mapping = SizeMapping(cpuId*0x1000, 0x1000)
|
||||||
|
)
|
||||||
|
interconnect.addConnection(debugBridge.bmb, cpu.debugBmb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends VexRiscvSmpClusterBase(p) {
|
||||||
|
val peripheralBridge = BmbToWishboneGenerator(DefaultMapping)
|
||||||
|
val peripheral = peripheralBridge.produceIo(peripheralBridge.logic.io.output)
|
||||||
|
interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32)
|
||||||
|
|
||||||
|
val plic = BmbPlicGenerator(0)
|
||||||
|
plic.priorityWidth.load(2)
|
||||||
|
plic.mapping.load(PlicMapping.sifive)
|
||||||
|
|
||||||
|
val plicWishboneBridge = WishboneToBmbGenerator()
|
||||||
|
val plicWishbone = plicWishboneBridge.produceIo(plicWishboneBridge.logic.io.input)
|
||||||
|
plicWishboneBridge.config.load(WishboneConfig(20, 32))
|
||||||
|
interconnect.addConnection(plicWishboneBridge.bmb, plic.bus)
|
||||||
|
|
||||||
|
val clint = BmbClintGenerator(0)
|
||||||
|
|
||||||
|
val clintWishboneBridge = WishboneToBmbGenerator()
|
||||||
|
val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.io.input)
|
||||||
|
clintWishboneBridge.config.load(WishboneConfig(14, 32))
|
||||||
|
interconnect.addConnection(clintWishboneBridge.bmb, clint.bus)
|
||||||
|
|
||||||
|
val interrupts = add task (in Bits(32 bits))
|
||||||
|
for(i <- 1 to 31) yield plic.addInterrupt(interrupts.derivate(_.apply(i)), i)
|
||||||
|
|
||||||
|
for ((core, cpuId) <- cores.zipWithIndex) {
|
||||||
|
core.cpu.setTimerInterrupt(clint.timerInterrupt(cpuId))
|
||||||
|
core.cpu.setSoftwareInterrupt(clint.softwareInterrupt(cpuId))
|
||||||
|
plic.priorityWidth.load(2)
|
||||||
|
plic.mapping.load(PlicMapping.sifive)
|
||||||
|
plic.addTarget(core.cpu.externalInterrupt)
|
||||||
|
plic.addTarget(core.cpu.externalSupervisorInterrupt)
|
||||||
|
List(clint.logic, core.cpu.logic).produce {
|
||||||
|
for (plugin <- core.cpu.config.plugins) plugin match {
|
||||||
|
case plugin: CsrPlugin if plugin.utime != null => plugin.utime := clint.logic.io.time
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clint.cpuCount.load(cpuCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
//case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig])
|
|
||||||
//
|
|
||||||
//case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter,
|
//case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter,
|
||||||
// debugClockDomain : ClockDomain) extends Component{
|
// debugClockDomain : ClockDomain) extends Component{
|
||||||
// val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter()
|
// val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter()
|
||||||
|
|
|
@ -1,305 +1,150 @@
|
||||||
//package vexriscv.demo.smp
|
package vexriscv.demo.smp
|
||||||
//
|
|
||||||
//import spinal.core._
|
import spinal.core._
|
||||||
//import spinal.lib.bus.bmb._
|
import spinal.lib.bus.bmb._
|
||||||
//import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory}
|
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
||||||
//import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl}
|
import spinal.lib.sim.SparseMemory
|
||||||
//import spinal.lib._
|
import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig
|
||||||
//import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester}
|
|
||||||
//import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
|
||||||
//import spinal.lib.eda.bench.Bench
|
case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter,
|
||||||
//import spinal.lib.misc.Clint
|
liteDram : LiteDramNativeParameter,
|
||||||
//import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget}
|
liteDramMapping : AddressMapping)
|
||||||
//import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer}
|
|
||||||
//import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig}
|
|
||||||
//import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter}
|
class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) {
|
||||||
//import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig
|
val iArbiter = BmbSmpBridgeGenerator()
|
||||||
//import vexriscv.{VexRiscv, VexRiscvConfig}
|
val iBridge = BmbToLiteDramGenerator(p.liteDramMapping)
|
||||||
//import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin}
|
val dBridge = BmbToLiteDramGenerator(p.liteDramMapping)
|
||||||
//
|
|
||||||
//import scala.collection.mutable
|
for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb))
|
||||||
//import scala.util.Random
|
interconnect.addConnection(
|
||||||
//
|
iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb),
|
||||||
//
|
invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb)
|
||||||
//case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter,
|
)
|
||||||
// liteDram : LiteDramNativeParameter,
|
interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder()
|
||||||
// liteDramMapping : AddressMapping)
|
|
||||||
//
|
dBridge.liteDramParameter.load(p.liteDram)
|
||||||
|
iBridge.liteDramParameter.load(p.liteDram)
|
||||||
|
|
||||||
|
// Interconnect pipelining (FMax)
|
||||||
|
for(core <- cores) {
|
||||||
|
interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true)
|
||||||
|
interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true)
|
||||||
|
interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true)
|
||||||
|
}
|
||||||
|
interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true)
|
||||||
|
interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object VexRiscvLitexSmpClusterGen extends App {
|
||||||
|
for(cpuCount <- List(1,2,4,8)) {
|
||||||
|
def parameter = VexRiscvLitexSmpClusterParameter(
|
||||||
|
cluster = VexRiscvSmpClusterParameter(
|
||||||
|
cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||||
|
vexRiscvConfig(
|
||||||
|
hartId = hartId,
|
||||||
|
ioRange = address => address.msb,
|
||||||
|
resetVector = 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||||
|
liteDramMapping = SizeMapping(0x40000000l, 0x40000000l)
|
||||||
|
)
|
||||||
|
|
||||||
|
def dutGen = {
|
||||||
|
val toplevel = new VexRiscvLitexSmpCluster(
|
||||||
|
p = parameter
|
||||||
|
).toComponent()
|
||||||
|
toplevel
|
||||||
|
}
|
||||||
|
|
||||||
|
val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables)
|
||||||
|
// genConfig.generateVerilog(Bench.compressIo(dutGen))
|
||||||
|
genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////addAttribute("""mark_debug = "true"""")
|
////addAttribute("""mark_debug = "true"""")
|
||||||
//case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter,
|
object VexRiscvLitexSmpClusterOpenSbi extends App{
|
||||||
// debugClockDomain : ClockDomain,
|
import spinal.core.sim._
|
||||||
// jtagClockDomain : ClockDomain) extends Component{
|
|
||||||
//
|
val simConfig = SimConfig
|
||||||
// val peripheralWishboneConfig = WishboneConfig(
|
simConfig.withWave
|
||||||
// addressWidth = 30,
|
simConfig.allOptimisation
|
||||||
// dataWidth = 32,
|
|
||||||
// selWidth = 4,
|
val cpuCount = 2
|
||||||
// useERR = true,
|
|
||||||
// useBTE = true,
|
def parameter = VexRiscvLitexSmpClusterParameter(
|
||||||
// useCTI = true
|
cluster = VexRiscvSmpClusterParameter(
|
||||||
// )
|
cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||||
//
|
vexRiscvConfig(
|
||||||
// val io = new Bundle {
|
hartId = hartId,
|
||||||
// val dMem = master(LiteDramNative(p.liteDram))
|
ioRange = address => address(31 downto 28) === 0xF,
|
||||||
// val iMem = master(LiteDramNative(p.liteDram))
|
resetVector = 0x80000000l
|
||||||
// val peripheral = master(Wishbone(peripheralWishboneConfig))
|
)
|
||||||
// val clint = slave(Wishbone(Clint.getWisboneConfig()))
|
}
|
||||||
// val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32)))
|
),
|
||||||
// val interrupts = in Bits(32 bits)
|
liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||||
// val jtagInstruction = slave(JtagTapInstructionCtrl())
|
liteDramMapping = SizeMapping(0x80000000l, 0x70000000l)
|
||||||
// val debugReset = out Bool()
|
)
|
||||||
// }
|
|
||||||
// val cpuCount = p.cluster.cpuConfigs.size
|
def dutGen = {
|
||||||
// val clint = Clint(cpuCount)
|
val top = new VexRiscvLitexSmpCluster(
|
||||||
// clint.driveFrom(WishboneSlaveFactory(io.clint))
|
p = parameter
|
||||||
//
|
).toComponent()
|
||||||
// val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain)
|
top.rework{
|
||||||
// cluster.io.debugReset <> io.debugReset
|
top.clintWishbone.setAsDirectionLess.allowDirectionLessIo
|
||||||
// cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt))
|
top.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic()
|
||||||
// cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt))
|
|
||||||
// cluster.io.time := clint.time
|
val hit = (top.peripheral.ADR <<2 >= 0xF0010000l && top.peripheral.ADR<<2 < 0xF0020000l)
|
||||||
//
|
top.clintWishbone.CYC := top.peripheral.CYC && hit
|
||||||
// val debug = debugClockDomain on new Area{
|
top.clintWishbone.STB := top.peripheral.STB
|
||||||
// val jtagConfig = SystemDebuggerConfig()
|
top.clintWishbone.WE := top.peripheral.WE
|
||||||
// val jtagBridge = new JtagBridgeNoTap(
|
top.clintWishbone.ADR := top.peripheral.ADR.resized
|
||||||
// c = jtagConfig,
|
top.clintWishbone.DAT_MOSI := top.peripheral.DAT_MOSI
|
||||||
// jtagClockDomain = jtagClockDomain
|
top.peripheral.DAT_MISO := top.clintWishbone.DAT_MISO
|
||||||
// )
|
top.peripheral.ACK := top.peripheral.CYC && (!hit || top.clintWishbone.ACK)
|
||||||
// jtagBridge.io.ctrl << io.jtagInstruction
|
top.peripheral.ERR := False
|
||||||
//
|
|
||||||
// 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),
|
|
||||||
// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p),
|
|
||||||
// pendingRspTransactionMax = 32
|
|
||||||
// )
|
|
||||||
//// val dBusDecoder = BmbDecoderOut(
|
|
||||||
//// p = cluster.io.dMem.p,
|
|
||||||
//// mappings = Seq(DefaultMapping, p.liteDramMapping),
|
|
||||||
//// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p),
|
|
||||||
//// pendingMax = 31
|
|
||||||
//// )
|
|
||||||
// dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true)
|
|
||||||
// val dMemBridge = io.dMem.fromBmb(dBusDecoder.io.outputs(1), wdataFifoSize = 32, rdataFifoSize = 32)
|
|
||||||
//
|
|
||||||
// val iBusArbiterParameter = cluster.iBusParameter.copy(sourceWidth = log2Up(cpuCount))
|
|
||||||
// val iBusArbiter = BmbArbiter(
|
|
||||||
// p = iBusArbiterParameter,
|
|
||||||
// portCount = cpuCount,
|
|
||||||
// lowerFirstPriority = false
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// (iBusArbiter.io.inputs, cluster.io.iMems).zipped.foreach(_ << _.pipelined(cmdHalfRate = true, rspValid = true))
|
|
||||||
//
|
|
||||||
// val iBusDecoder = BmbDecoder(
|
|
||||||
// p = iBusArbiter.io.output.p,
|
|
||||||
// mappings = Seq(DefaultMapping, p.liteDramMapping),
|
|
||||||
// capabilities = Seq(iBusArbiterParameter, iBusArbiterParameter),
|
|
||||||
// pendingMax = 15
|
|
||||||
// )
|
|
||||||
// iBusDecoder.io.input << iBusArbiter.io.output.pipelined(cmdValid = true)
|
|
||||||
//
|
|
||||||
// val iMem = LiteDramNative(p.liteDram)
|
|
||||||
// io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// val iBusDecoderToPeripheral = iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true)
|
|
||||||
// val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true)
|
|
||||||
//
|
|
||||||
// val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth)
|
|
||||||
// val peripheralArbiter = BmbArbiter(
|
|
||||||
// p = dBusDecoder.io.outputs(0).p.copy(
|
|
||||||
// sourceWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + 1,
|
|
||||||
// contextWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max,
|
|
||||||
// lengthWidth = peripheralAccessLength,
|
|
||||||
// dataWidth = 32
|
|
||||||
// ),
|
|
||||||
// portCount = 2,
|
|
||||||
// lowerFirstPriority = true
|
|
||||||
// )
|
|
||||||
// peripheralArbiter.io.inputs(0) << iBusDecoderToPeripheral
|
|
||||||
// peripheralArbiter.io.inputs(1) << dBusDecoderToPeripheral
|
|
||||||
//
|
|
||||||
// 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))
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//object VexRiscvLitexSmpClusterGen extends App {
|
|
||||||
// for(cpuCount <- List(1,2,4,8)) {
|
|
||||||
// def parameter = VexRiscvLitexSmpClusterParameter(
|
|
||||||
// cluster = VexRiscvSmpClusterParameter(
|
|
||||||
// cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
|
||||||
// vexRiscvConfig(
|
|
||||||
// hartId = hartId,
|
|
||||||
// ioRange = address => address.msb,
|
|
||||||
// resetVector = 0
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
|
||||||
// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l)
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// def dutGen = {
|
|
||||||
// val toplevel = VexRiscvLitexSmpCluster(
|
|
||||||
// p = parameter,
|
|
||||||
// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")),
|
|
||||||
// jtagClockDomain = ClockDomain.external("jtag", withReset = false)
|
|
||||||
// )
|
|
||||||
// toplevel
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables)
|
|
||||||
// // genConfig.generateVerilog(Bench.compressIo(dutGen))
|
|
||||||
// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c"))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//object VexRiscvLitexSmpClusterOpenSbi extends App{
|
|
||||||
// import spinal.core.sim._
|
|
||||||
//
|
|
||||||
// val simConfig = SimConfig
|
|
||||||
// simConfig.withWave
|
|
||||||
// simConfig.allOptimisation
|
|
||||||
//
|
|
||||||
// val cpuCount = 2
|
|
||||||
//
|
|
||||||
// def parameter = VexRiscvLitexSmpClusterParameter(
|
|
||||||
// cluster = VexRiscvSmpClusterParameter(
|
|
||||||
// cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
|
||||||
// vexRiscvConfig(
|
|
||||||
// hartId = hartId,
|
|
||||||
// ioRange = address => address(31 downto 28) === 0xF,
|
|
||||||
// resetVector = 0x80000000l
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
|
||||||
// liteDramMapping = SizeMapping(0x80000000l, 0x70000000l)
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// def dutGen = {
|
|
||||||
// val top = VexRiscvLitexSmpCluster(
|
|
||||||
// p = parameter,
|
|
||||||
// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")),
|
|
||||||
// jtagClockDomain = ClockDomain.external("jtag", withReset = false)
|
|
||||||
// )
|
|
||||||
// top.rework{
|
|
||||||
// top.io.clint.setAsDirectionLess.allowDirectionLessIo
|
|
||||||
// top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic()
|
|
||||||
//
|
|
||||||
// val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l)
|
|
||||||
// top.io.clint.CYC := top.io.peripheral.CYC && hit
|
|
||||||
// top.io.clint.STB := top.io.peripheral.STB
|
|
||||||
// top.io.clint.WE := top.io.peripheral.WE
|
|
||||||
// top.io.clint.ADR := top.io.peripheral.ADR.resized
|
|
||||||
// top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI
|
|
||||||
// top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO
|
|
||||||
// top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK)
|
|
||||||
// top.io.peripheral.ERR := False
|
|
||||||
//
|
|
||||||
// top.dMemBridge.unburstified.cmd.simPublic()
|
// top.dMemBridge.unburstified.cmd.simPublic()
|
||||||
// }
|
}
|
||||||
// top
|
top
|
||||||
// }
|
}
|
||||||
// simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut =>
|
simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut =>
|
||||||
// dut.clockDomain.forkStimulus(10)
|
dut.debugCd.inputClockDomain.get.forkStimulus(10)
|
||||||
// fork {
|
|
||||||
// dut.debugClockDomain.resetSim #= false
|
val ram = SparseMemory()
|
||||||
// sleep (0)
|
ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin")
|
||||||
// dut.debugClockDomain.resetSim #= true
|
ram.loadBin(0xC0000000l, "../buildroot/output/images/Image")
|
||||||
// sleep (10)
|
ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb")
|
||||||
// dut.debugClockDomain.resetSim #= false
|
ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio")
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
dut.iBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain)
|
||||||
// val ram = SparseMemory()
|
dut.dBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain/*, dut.dMemBridge.unburstified*/)
|
||||||
// ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin")
|
|
||||||
// ram.loadBin(0xC0000000l, "../buildroot/output/images/Image")
|
dut.interrupts.get #= 0
|
||||||
// ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb")
|
|
||||||
// ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio")
|
dut.debugCd.inputClockDomain.get.onFallingEdges{
|
||||||
//
|
if(dut.peripheral.CYC.toBoolean){
|
||||||
//
|
(dut.peripheral.ADR.toLong << 2) match {
|
||||||
// dut.io.iMem.simSlave(ram, dut.clockDomain)
|
case 0xF0000000l => print(dut.peripheral.DAT_MOSI.toLong.toChar)
|
||||||
// dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified)
|
case 0xF0000004l => dut.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl)
|
||||||
//
|
case _ =>
|
||||||
// dut.io.interrupts #= 0
|
}
|
||||||
//
|
}
|
||||||
// dut.clockDomain.onFallingEdges{
|
}
|
||||||
// if(dut.io.peripheral.CYC.toBoolean){
|
|
||||||
// (dut.io.peripheral.ADR.toLong << 2) match {
|
fork{
|
||||||
// case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar)
|
while(true) {
|
||||||
// case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl)
|
disableSimWave()
|
||||||
// case _ =>
|
sleep(100000 * 10)
|
||||||
// }
|
enableSimWave()
|
||||||
//// println(f"${dut.io.peripheral.ADR.toLong}%x")
|
sleep( 100 * 10)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
//// fork{
|
}
|
||||||
//// disableSimWave()
|
|
||||||
//// val atMs = 3790
|
|
||||||
//// val durationMs = 5
|
|
||||||
//// sleep(atMs*1000000l)
|
|
||||||
//// enableSimWave()
|
|
||||||
//// println("** enableSimWave **")
|
|
||||||
//// sleep(durationMs*1000000l)
|
|
||||||
//// println("** disableSimWave **")
|
|
||||||
//// while(true) {
|
|
||||||
//// disableSimWave()
|
|
||||||
//// sleep(100000 * 10)
|
|
||||||
//// enableSimWave()
|
|
||||||
//// sleep( 100 * 10)
|
|
||||||
//// }
|
|
||||||
//// // simSuccess()
|
|
||||||
//// }
|
|
||||||
//
|
|
||||||
// fork{
|
|
||||||
// while(true) {
|
|
||||||
// disableSimWave()
|
|
||||||
// sleep(100000 * 10)
|
|
||||||
// enableSimWave()
|
|
||||||
// sleep( 100 * 10)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
Loading…
Reference in New Issue