diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 91cf876..90a40c5 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -4,6 +4,8 @@ import spinal.core._ object Riscv{ + def misaToInt(values : String) = values.toLowerCase.map(e => 1 << (e-'a')).reduce(_ | _) + def funct7Range = 31 downto 25 def rdRange = 11 downto 7 def funct3Range = 14 downto 12 diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index fff9b03..f92321c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -1,14 +1,17 @@ package vexriscv.demo.smp +import spinal.core import spinal.core._ +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.com.jtag.sim.JtagTcp +import vexriscv.demo.smp.VexRiscvSmpClusterTest.{cpuCount, withStall} import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} -import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer @@ -34,6 +37,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val iMems = Vec(master(Bmb(iMemParameter)), p.cpuConfigs.size) val timerInterrupts = in Bits(p.cpuConfigs.size bits) 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 debugReset = out Bool() @@ -53,6 +57,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb() case plugin: CsrPlugin => { + plugin.softwareInterrupt := io.softwareInterrupts(cpuId) plugin.externalInterrupt := io.externalInterrupts(cpuId) plugin.timerInterrupt := io.timerInterrupts(cpuId) if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) @@ -228,7 +233,7 @@ object VexRiscvSmpClusterGen { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id)), + new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id, misaExtensionsInit = Riscv.misaToInt("imas"))), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, @@ -279,59 +284,51 @@ object VexRiscvSmpClusterGen { } -object SmpTest{ + +object VexRiscvSmpClusterTestInfrastructure{ val REPORT_OFFSET = 0xF8000000 val REPORT_THREAD_ID = 0x00 val REPORT_THREAD_COUNT = 0x04 val REPORT_END = 0x08 val REPORT_BARRIER_START = 0x0C val REPORT_BARRIER_END = 0x10 -} -object VexRiscvSmpClusterTest extends App{ - import spinal.core.sim._ - val simConfig = SimConfig - simConfig.withWave - simConfig.allOptimisation - simConfig.addSimulatorFlag("--threads 1") + val PUTC = 0x00 + val GETC = 0x04 + val CLINT_ADDR = 0x10000 + val CLINT_IPI_ADDR = CLINT_ADDR+0x0000 + val CLINT_CMP_ADDR = CLINT_ADDR+0x4000 + val CLINT_TIME_ADDR = CLINT_ADDR+0xBFF8 - val cpuCount = 4 - simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => - SimTimeout(10000*10*cpuCount) - dut.clockDomain.forkSimSpeedPrinter(1.0) - dut.clockDomain.forkStimulus(10) - dut.debugClockDomain.forkStimulus(10) - - - JtagTcp(dut.io.jtag, 100) - - val withStall = false - val cpuEnd = Array.fill(dut.p.cpuConfigs.size)(false) - val barriers = mutable.HashMap[Int, Int]() - - var reportWatchdog = 0 - periodicaly(10000*10){ - assert(reportWatchdog != 0) - reportWatchdog = 0 - } - - case class Report(hart : Int, code : Int, data : Int){ - override def toString: String = { - f"CPU:$hart%2d h${code}%3x -> $data%3d" - } - } - val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) - onSimEnd{ - for((list, hart) <- reports.zipWithIndex){ - println(f"\n\n**** CPU $hart%2d ****") - for((report, reportId) <- list.zipWithIndex){ - println(f" $reportId%3d : h${report.code}%3x -> ${report.data}%3d") + def ram(dut : VexRiscvSmpCluster) = { + import spinal.core.sim._ + val cpuCount = dut.cpus.size + val ram = new BmbMemoryAgent(0x100000000l){ + case class Report(hart : Int, code : Int, data : Int){ + override def toString: String = { + f"CPU:$hart%2d ${code}%3x -> $data%3d" + } + } + val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) + onSimEnd{ + for((list, hart) <- reports.zipWithIndex){ + println(f"\n\n**** CPU $hart%2d ****") + for((report, reportId) <- list.zipWithIndex){ + println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d") + } } } - } - val ram = new BmbMemoryAgent(0x100000000l){ + val writeTable = mutable.HashMap[Int, Int => Unit]() + val readTable = mutable.HashMap[Int, () => Int]() + def onWrite(address : Int)(body : Int => Unit) = writeTable(address) = body + def onRead(address : Int)(body : => Int) = readTable(address) = () => body + var writeData = 0 + var readData = 0 + var reportWatchdog = 0 + val cpuEnd = Array.fill(cpuCount)(false) + val barriers = mutable.HashMap[Int, Int]() override def setByte(address: Long, value: Byte): Unit = { if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value) val byteId = address & 3 @@ -339,7 +336,7 @@ object VexRiscvSmpClusterTest extends App{ writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask) if(byteId != 3) return val offset = (address & ~0xF0000000l)-3 -// println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") + // println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") offset match { case _ if offset >= 0x8000000 && offset < 0x9000000 => { val report = Report( @@ -351,7 +348,6 @@ object VexRiscvSmpClusterTest extends App{ reports(report.hart) += report reportWatchdog += 1 import report._ - import SmpTest._ code match { case REPORT_THREAD_ID => assert(data == hart) case REPORT_THREAD_COUNT => assert(data == cpuCount) @@ -367,13 +363,108 @@ object VexRiscvSmpClusterTest extends App{ } } } + case _ => writeTable.get(offset.toInt) match { + case Some(x) => x(writeData) + case _ => simFailure(f"\n\nWrite at ${address-3}%8x with $writeData%8x") + } } } - } - dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) //Moarr powaaaaa -// ram.addPort(dut.io.iMem,0,dut.clockDomain,true, withStall) - ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) + override def getByte(address: Long): Byte = { + if((address & 0xF0000000l) != 0xF0000000l) return super.getByte(address) + val byteId = address & 3 + val offset = (address & ~0xF0000000l) + if(byteId == 0) readData = readTable.get(offset.toInt) match { + case Some(x) => x() + case _ => simFailure(f"\n\nRead at $address%8x") + } + (readData >> (byteId*8)).toByte + } + + val clint = new { + val cmp = Array.fill(cpuCount)(0l) + } + + onWrite(PUTC)(data => print(data.toChar)) +// onWrite(GETC)(data => System.in.read().toInt) + + onRead(CLINT_TIME_ADDR)(simTime().toInt) + onRead(CLINT_TIME_ADDR+4)((simTime() >> 32).toInt) + for(hartId <- 0 until cpuCount){ + onWrite(CLINT_IPI_ADDR + hartId*4) {data => + val mask = 1l << hartId + val value = (dut.io.softwareInterrupts.toLong & ~mask) | (if(data == 1) mask else 0) + dut.io.softwareInterrupts #= value + } + onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) + onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) + onWrite(CLINT_CMP_ADDR + hartId*8)(data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data) + onWrite(CLINT_CMP_ADDR + hartId*8+4)(data => (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data << 32)) + } + + var time = 0l + periodicaly(100){ + time += 10 + var timerInterrupts = 0l + for(i <- 0 until cpuCount){ + if(clint.cmp(i) < time) timerInterrupts |= 1l << i + } + dut.io.timerInterrupts #= timerInterrupts + } + + } + dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) + ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) + ram + } + def init(dut : VexRiscvSmpCluster): Unit ={ + import spinal.core.sim._ + dut.clockDomain.forkSimSpeedPrinter(1.0) + dut.clockDomain.forkStimulus(10) + dut.debugClockDomain.forkStimulus(10) + JtagTcp(dut.io.jtag, 100) + } +} + +object VexRiscvSmpClusterTest extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig +// simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + val cpuCount = 4 + val withStall = true + + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + SimTimeout(10000*10*cpuCount) + VexRiscvSmpClusterTestInfrastructure.init(dut) + val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") + periodicaly(20000*10){ + assert(ram.reportWatchdog != 0) + ram.reportWatchdog = 0 + } + } +} + + +object VexRiscvSmpClusterOpenSbi extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + val cpuCount = 4 + val withStall = false + + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + VexRiscvSmpClusterTestInfrastructure.init(dut) + val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) + ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") +// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") } } \ No newline at end of file diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm index db25d17..06f2616 100644 --- a/src/test/cpp/raw/smp/build/smp.asm +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -21,7 +21,7 @@ Disassembly of section .crt_section: 80000028 : 80000028: 00000417 auipc s0,0x0 8000002c: 1c442403 lw s0,452(s0) # 800001ec -80000030: 0c800513 li a0,200 +80000030: 19000513 li a0,400 80000034: 1ac000ef jal ra,800001e0 80000038: 00000497 auipc s1,0x0 8000003c: 1b44a483 lw s1,436(s1) # 800001ec diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin index 9eaea40..59a832f 100755 Binary files a/src/test/cpp/raw/smp/build/smp.bin and b/src/test/cpp/raw/smp/build/smp.bin differ diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S index eb197d6..72cc5b8 100644 --- a/src/test/cpp/raw/smp/src/crt.S +++ b/src/test/cpp/raw/smp/src/crt.S @@ -26,7 +26,7 @@ count_thread_start: count_thread_wait: //Wait everybody lw s0, thread_count - li a0, 200 + li a0, 400 call sleep lw s1, thread_count bne s1, s0, count_thread_wait