From 73c21177e511aae1dc7dae800e2ad7fb8c1f8297 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Apr 2020 01:30:03 +0200 Subject: [PATCH] Add VexRiscvSmpCluster, seem to work on simple case --- .../demo/smp/VexRiscvSmpCluster.scala | 302 ++++++++++++++++++ src/test/cpp/raw/smp/.gitignore | 5 + src/test/cpp/raw/smp/build/smp.asm | 108 +++++++ src/test/cpp/raw/smp/makefile | 5 + src/test/cpp/raw/smp/src/crt.S | 70 ++++ src/test/cpp/raw/smp/src/ld | 16 + 6 files changed, 506 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala create mode 100644 src/test/cpp/raw/smp/.gitignore create mode 100644 src/test/cpp/raw/smp/build/smp.asm create mode 100644 src/test/cpp/raw/smp/makefile create mode 100644 src/test/cpp/raw/smp/src/crt.S create mode 100644 src/test/cpp/raw/smp/src/ld diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala new file mode 100644 index 0000000..474357f --- /dev/null +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -0,0 +1,302 @@ +package vexriscv.demo.smp + +import spinal.core._ +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.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} + + +case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) + +case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, + debugClockDomain : ClockDomain) extends Component{ + val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter() + val dBusArbiterParameter = dBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) + val exclusiveMonitorParameter = dBusArbiterParameter + val invalidateMonitorParameter = BmbExclusiveMonitor.outputParameter(exclusiveMonitorParameter) + val dMemParameter = BmbInvalidateMonitor.outputParameter(invalidateMonitorParameter) + + val iBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[IBusCachedPlugin]).get.asInstanceOf[IBusCachedPlugin].config.getBmbParameter() + val iBusArbiterParameter = iBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) + val iMemParameter = iBusArbiterParameter + + val io = new Bundle { + val dMem = master(Bmb(dMemParameter)) + val iMem = master(Bmb(iMemParameter)) + val timerInterrupts = in Bits(p.cpuConfigs.size bits) + val externalInterrupts = in Bits(p.cpuConfigs.size bits) + val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) + val jtag = slave(Jtag()) + val debugReset = out Bool() + } + + val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ + var iBus : Bmb = null + var dBus : Bmb = null + cpuConfig.plugins.foreach { + case plugin: DebugPlugin => debugClockDomain{ + plugin.debugClockDomain = debugClockDomain + } + case _ => + } + val core = new VexRiscv(cpuConfig) + core.plugins.foreach { + case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() + case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb() + case plugin: CsrPlugin => { + plugin.externalInterrupt := io.externalInterrupts(cpuId) + plugin.timerInterrupt := io.timerInterrupts(cpuId) + if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) + } + case plugin: DebugPlugin => debugClockDomain{ + io.debugReset := RegNext(plugin.io.resetOut) + io.jtag <> plugin.io.bus.fromJtag() + } + case _ => + } + } + + val dBusArbiter = BmbArbiter( + p = dBusArbiterParameter, + portCount = cpus.size, + pendingRspMax = 64, + lowerFirstPriority = false, + inputsWithInv = cpus.map(_ => true), + inputsWithSync = cpus.map(_ => true), + pendingInvMax = 16 + ) + + (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus) + + val exclusiveMonitor = BmbExclusiveMonitor( + inputParameter = exclusiveMonitorParameter, + pendingWriteMax = 64 + ) + exclusiveMonitor.io.input << dBusArbiter.io.output + + val invalidateMonitor = BmbInvalidateMonitor( + inputParameter = invalidateMonitorParameter, + pendingInvMax = 16 + ) + invalidateMonitor.io.input << exclusiveMonitor.io.output + + 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 +} + + + +object VexRiscvSmpClusterGen { + def vexRiscvConfig(id : Int) = { + val config = VexRiscvConfig( + plugins = List( + new MmuPlugin( + ioRange = x => x(31 downto 28) === 0xF + ), + //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config + // new IBusSimplePlugin( + // resetVector = 0x80000000l, + // cmdForkOnSecondStage = false, + // cmdForkPersistence = false, + // prediction = DYNAMIC_TARGET, + // historyRamSizeLog2 = 10, + // catchAccessFault = true, + // compressedGen = true, + // busLatencyMin = 1, + // injectorStage = true, + // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + // portTlbSize = 4 + // ) + // ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config + new IBusCachedPlugin( + resetVector = 0x80000000l, + compressedGen = false, + prediction = STATIC, + injectorStage = false, + config = InstructionCacheConfig( + cacheSize = 4096*1, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = false, + twoCycleCache = true + // ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), + // new DBusSimplePlugin( + // catchAddressMisaligned = true, + // catchAccessFault = true, + // earlyInjection = false, + // withLrSc = true, + // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + // portTlbSize = 4 + // ) + // ), + new DBusCachedPlugin( + dBusCmdMasterPipe = true, + dBusCmdSlavePipe = true, + dBusRspSlavePipe = true, + config = new DataCacheConfig( + cacheSize = 4096*1, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + withLrSc = true, + withAmo = true, + withExclusive = true, + withInvalidate = true + // ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + + // new MemoryTranslatorPlugin( + // tlbSize = 32, + // virtualRange = _(31 downto 28) === 0xC, + // ioRange = _(31 downto 28) === 0xF + // ), + + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = true + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false + ), + new FullBarrelShifterPlugin(earlyInjection = false), + // new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + // new HazardSimplePlugin(false, true, false, true), + // new HazardSimplePlugin(false, false, false, false), + new MulPlugin, + new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ), + // new DivPlugin, + new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id)), + // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* + // CsrPluginConfig( + // catchIllegalAccess = false, + // mvendorid = null, + // marchid = null, + // mimpid = null, + // mhartid = null, + // misaExtensionsInit = 0, + // misaAccess = CsrAccess.READ_ONLY, + // mtvecAccess = CsrAccess.WRITE_ONLY, + // mtvecInit = 0x80000020l, + // mepcAccess = CsrAccess.READ_WRITE, + // mscratchGen = true, + // mcauseAccess = CsrAccess.READ_ONLY, + // mbadaddrAccess = CsrAccess.READ_ONLY, + // mcycleAccess = CsrAccess.NONE, + // minstretAccess = CsrAccess.NONE, + // ecallGen = true, + // ebreakGen = true, + // wfiGenAsWait = false, + // wfiGenAsNop = true, + // ucycleAccess = CsrAccess.NONE + // )), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true, + fenceiGenAsAJump = false + ), + new YamlPlugin(s"cpu$id.yaml") + ) + ) + if(id == 0) config.plugins += new DebugPlugin(null) + config + } + def vexRiscvCluster() = VexRiscvSmpCluster( + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + p = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(4) { + vexRiscvConfig(_) + } + ) + ) + def main(args: Array[String]): Unit = { + SpinalVerilog { + vexRiscvCluster() + } + } +} + + +object VexRiscvSmpClusterTest extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster()).doSim(seed = 42){dut => + dut.clockDomain.forkSimSpeedPrinter(1.0) + dut.clockDomain.forkStimulus(10) + dut.debugClockDomain.forkStimulus(10) + + + JtagTcp(dut.io.jtag, 100) + + val ram = new BmbMemoryAgent(0x100000000l) + ram.addPort(dut.io.iMem,0,dut.clockDomain,true) + ram.addPort(dut.io.dMem,0,dut.clockDomain,true) + + ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") + + sleep(10000*10) + simSuccess() + } +} \ No newline at end of file diff --git a/src/test/cpp/raw/smp/.gitignore b/src/test/cpp/raw/smp/.gitignore new file mode 100644 index 0000000..16512ff --- /dev/null +++ b/src/test/cpp/raw/smp/.gitignore @@ -0,0 +1,5 @@ +*.map +*.v +*.elf +*.o +*.hex \ 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 new file mode 100644 index 0000000..8173f8c --- /dev/null +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -0,0 +1,108 @@ + +build/smp.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: f1402a73 csrr s4,mhartid +80000004: 00000517 auipc a0,0x0 +80000008: 07850513 addi a0,a0,120 # 8000007c +8000000c: 00000513 li a0,0 +80000010: 00a52023 sw a0,0(a0) + +80000014 : +80000014: 00100513 li a0,1 +80000018: 00000597 auipc a1,0x0 +8000001c: 05c58593 addi a1,a1,92 # 80000074 +80000020: 00a5a02f amoadd.w zero,a0,(a1) + +80000024 : +80000024: 00000417 auipc s0,0x0 +80000028: 05042403 lw s0,80(s0) # 80000074 +8000002c: 0c800513 li a0,200 +80000030: 038000ef jal ra,80000068 +80000034: 00000497 auipc s1,0x0 +80000038: 0404a483 lw s1,64(s1) # 80000074 +8000003c: fe8494e3 bne s1,s0,80000024 +80000040: 00000513 li a0,0 +80000044: 00952023 sw s1,0(a0) +80000048: 0040006f j 8000004c + +8000004c : +8000004c: 00800513 li a0,8 +80000050: 00052023 sw zero,0(a0) +80000054: 0100006f j 80000064 + +80000058 : +80000058: 00c00513 li a0,12 +8000005c: 00052023 sw zero,0(a0) +80000060: 0040006f j 80000064 + +80000064 : +80000064: 0000006f j 80000064 + +80000068 : +80000068: fff50513 addi a0,a0,-1 +8000006c: fe051ee3 bnez a0,80000068 +80000070: 00008067 ret + +80000074 : +80000074: 0000 unimp + ... + +80000078 : +80000078: 0000 unimp + ... + +8000007c : +8000007c: 0000000b 0xb + +80000080 : +80000080: 0016 c.slli zero,0x5 + ... + +80000084 : +80000084: 0049 c.nop 18 + ... + +80000088 : +80000088: 003a c.slli zero,0xe + ... + +8000008c : +8000008c: 0038 addi a4,sp,8 + ... + +80000090 : +80000090: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne + +80000094 : +80000094: 0038 addi a4,sp,8 + ... + +80000098 : +80000098: 00000053 fadd.s ft0,ft0,ft0,rne + +8000009c : +8000009c: 0021 c.nop 8 + ... + +800000a0 : +800000a0: ffffffbf 0xffffffbf + +800000a4 : +800000a4: ffa9 bnez a5,7ffffffe <_start-0x2> +800000a6: ffff 0xffff + +800000a8 : +800000a8: ffc9 bnez a5,80000042 +800000aa: ffff 0xffff + +800000ac : +800000ac: 0004 0x4 +800000ae: ffff 0xffff + +800000b0 : +800000b0: 0005 c.nop 1 +800000b2: ffff 0xffff diff --git a/src/test/cpp/raw/smp/makefile b/src/test/cpp/raw/smp/makefile new file mode 100644 index 0000000..0886c1b --- /dev/null +++ b/src/test/cpp/raw/smp/makefile @@ -0,0 +1,5 @@ +PROJ_NAME=smp + +ATOMIC=yes + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S new file mode 100644 index 0000000..be1e59d --- /dev/null +++ b/src/test/cpp/raw/smp/src/crt.S @@ -0,0 +1,70 @@ +#define REPORT_OFFSET 0xF0000000 +#define REPORT_THREAD_ID 0 +#define REPORT_THREAD_COUNT 1 +#define REPORT_SUCCESS 2 +#define REPORT_FAILURE 3 + +#define report(reg, id) \ + li a0, id*4; \ + sw reg, 0(a0); \ + +_start: + + #define HART_ID x20 + csrr HART_ID, mhartid + la a0, test1_data + report(a0, REPORT_THREAD_ID) + + +count_thread_start: + //Count up threads + li a0, 1 + la a1, thread_count + amoadd.w x0, a0, (a1) + +count_thread_wait: + //Wait everybody + lw s0, thread_count + li a0, 200 + call sleep + lw s1, thread_count + bne s1, s0, count_thread_wait + report(s1, REPORT_THREAD_ID) + + j success + +success: + report(x0, REPORT_SUCCESS) + j end + +failure: + report(x0, REPORT_FAILURE) + j end + +end: + j end + + +sleep: + addi a0, a0, -1 + bnez a0, sleep + ret + + +thread_count: .word 0 +shared_memory_1: .word 0 + +test1_data: .word 11 +test2_data: .word 22 +test3_data: .word 73 +test4_data: .word 58 +test5_data: .word 56 +test6_data: .word 75 +test7_data: .word 56 +test8_data: .word 83 +test9_data: .word 33 +test10_data: .word -65 +test11_data: .word -87 +test12_data: .word -55 +test13_data: .word 0xFFFF0004 +test14_data: .word 0xFFFF0005 \ No newline at end of file diff --git a/src/test/cpp/raw/smp/src/ld b/src/test/cpp/raw/smp/src/ld new file mode 100644 index 0000000..93d8de8 --- /dev/null +++ b/src/test/cpp/raw/smp/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +}