Add VexRiscvSmpCluster, seem to work on simple case
This commit is contained in:
parent
b9ceabf128
commit
73c21177e5
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
*.map
|
||||
*.v
|
||||
*.elf
|
||||
*.o
|
||||
*.hex
|
|
@ -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 <test1_data>
|
||||
8000000c: 00000513 li a0,0
|
||||
80000010: 00a52023 sw a0,0(a0)
|
||||
|
||||
80000014 <count_thread_start>:
|
||||
80000014: 00100513 li a0,1
|
||||
80000018: 00000597 auipc a1,0x0
|
||||
8000001c: 05c58593 addi a1,a1,92 # 80000074 <thread_count>
|
||||
80000020: 00a5a02f amoadd.w zero,a0,(a1)
|
||||
|
||||
80000024 <count_thread_wait>:
|
||||
80000024: 00000417 auipc s0,0x0
|
||||
80000028: 05042403 lw s0,80(s0) # 80000074 <thread_count>
|
||||
8000002c: 0c800513 li a0,200
|
||||
80000030: 038000ef jal ra,80000068 <sleep>
|
||||
80000034: 00000497 auipc s1,0x0
|
||||
80000038: 0404a483 lw s1,64(s1) # 80000074 <thread_count>
|
||||
8000003c: fe8494e3 bne s1,s0,80000024 <count_thread_wait>
|
||||
80000040: 00000513 li a0,0
|
||||
80000044: 00952023 sw s1,0(a0)
|
||||
80000048: 0040006f j 8000004c <success>
|
||||
|
||||
8000004c <success>:
|
||||
8000004c: 00800513 li a0,8
|
||||
80000050: 00052023 sw zero,0(a0)
|
||||
80000054: 0100006f j 80000064 <end>
|
||||
|
||||
80000058 <failure>:
|
||||
80000058: 00c00513 li a0,12
|
||||
8000005c: 00052023 sw zero,0(a0)
|
||||
80000060: 0040006f j 80000064 <end>
|
||||
|
||||
80000064 <end>:
|
||||
80000064: 0000006f j 80000064 <end>
|
||||
|
||||
80000068 <sleep>:
|
||||
80000068: fff50513 addi a0,a0,-1
|
||||
8000006c: fe051ee3 bnez a0,80000068 <sleep>
|
||||
80000070: 00008067 ret
|
||||
|
||||
80000074 <thread_count>:
|
||||
80000074: 0000 unimp
|
||||
...
|
||||
|
||||
80000078 <shared_memory_1>:
|
||||
80000078: 0000 unimp
|
||||
...
|
||||
|
||||
8000007c <test1_data>:
|
||||
8000007c: 0000000b 0xb
|
||||
|
||||
80000080 <test2_data>:
|
||||
80000080: 0016 c.slli zero,0x5
|
||||
...
|
||||
|
||||
80000084 <test3_data>:
|
||||
80000084: 0049 c.nop 18
|
||||
...
|
||||
|
||||
80000088 <test4_data>:
|
||||
80000088: 003a c.slli zero,0xe
|
||||
...
|
||||
|
||||
8000008c <test5_data>:
|
||||
8000008c: 0038 addi a4,sp,8
|
||||
...
|
||||
|
||||
80000090 <test6_data>:
|
||||
80000090: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne
|
||||
|
||||
80000094 <test7_data>:
|
||||
80000094: 0038 addi a4,sp,8
|
||||
...
|
||||
|
||||
80000098 <test8_data>:
|
||||
80000098: 00000053 fadd.s ft0,ft0,ft0,rne
|
||||
|
||||
8000009c <test9_data>:
|
||||
8000009c: 0021 c.nop 8
|
||||
...
|
||||
|
||||
800000a0 <test10_data>:
|
||||
800000a0: ffffffbf 0xffffffbf
|
||||
|
||||
800000a4 <test11_data>:
|
||||
800000a4: ffa9 bnez a5,7ffffffe <_start-0x2>
|
||||
800000a6: ffff 0xffff
|
||||
|
||||
800000a8 <test12_data>:
|
||||
800000a8: ffc9 bnez a5,80000042 <count_thread_wait+0x1e>
|
||||
800000aa: ffff 0xffff
|
||||
|
||||
800000ac <test13_data>:
|
||||
800000ac: 0004 0x4
|
||||
800000ae: ffff 0xffff
|
||||
|
||||
800000b0 <test14_data>:
|
||||
800000b0: 0005 c.nop 1
|
||||
800000b2: ffff 0xffff
|
|
@ -0,0 +1,5 @@
|
|||
PROJ_NAME=smp
|
||||
|
||||
ATOMIC=yes
|
||||
|
||||
include ../common/asm.mk
|
|
@ -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
|
|
@ -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
|
||||
|
||||
}
|
Loading…
Reference in New Issue