Skip to content

Commit 9ffdeb3

Browse files
committed
sim: add new simulation interface
1 parent 70099f6 commit 9ffdeb3

File tree

2 files changed

+236
-132
lines changed

2 files changed

+236
-132
lines changed

pifo-hardware/hw/spinal/rio/sim/PifoMeshSim.scala

Lines changed: 22 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import spinal.core._
44
import spinal.core.sim._
55
import spinal.lib._
66
import rio._
7+
import spinal.sim.SimThread
78

89
object PifoMeshSim extends App {
9-
1010
val testConfig = EngineConfig(
1111
numEngines = 2,
1212
numVPIFOs = 32,
@@ -20,97 +20,9 @@ object PifoMeshSim extends App {
2020
.withFstWave
2121
.compile(new PifoMesh(testConfig)).doSim { dut =>
2222

23-
def mkFlowId(engineId: Int, vPifoId: Int): Int = {
24-
assert(engineId >= 0 && engineId <= testConfig.numEngines, s"Invalid engineId: $engineId")
25-
assert(vPifoId >= 0 && vPifoId < testConfig.numVPIFOs, s"Invalid vPifoId: $vPifoId")
26-
27-
(engineId << testConfig.vpifoIdWidth) | vPifoId
28-
}
29-
30-
def initialize() = {
31-
// Initialize all insert ports
32-
for (i <- 0 until testConfig.numEngines) {
33-
dut.io.insert(i).valid #= false
34-
dut.io.insert(i).payload.engineId #= 0
35-
dut.io.insert(i).payload.vPifoId #= 0
36-
}
37-
38-
// Initialize dataRequest port
39-
dut.io.dataRequest.valid #= false
40-
dut.io.dataRequest.payload.engineId #= 0
41-
dut.io.dataRequest.payload.vPifoId #= 0
42-
43-
// Initialize pop port
44-
dut.io.pop.ready #= true
45-
46-
// Initialize control port
47-
dut.io.controlRequest.valid #= false
48-
dut.io.controlRequest.payload.command #= ControlCommand.UpdateMapperPre
49-
dut.io.controlRequest.payload.engineId #= 0
50-
dut.io.controlRequest.payload.vPifoId #= 0
51-
dut.io.controlRequest.payload.flowId #= 0
52-
dut.io.controlRequest.payload.data #= 0
53-
}
54-
55-
def sendControl(cmd: ControlCommand.E, engineId: Int, data: Int, vPifoId: Int = 0, flowId: Int = 0) = {
56-
dut.io.controlRequest.valid #= true
57-
dut.io.controlRequest.payload.command #= cmd
58-
dut.io.controlRequest.payload.engineId #= engineId
59-
dut.io.controlRequest.payload.vPifoId #= vPifoId
60-
dut.io.controlRequest.payload.flowId #= flowId
61-
dut.io.controlRequest.payload.data #= data
62-
dut.clockDomain.waitRisingEdge()
63-
dut.io.controlRequest.valid #= false
64-
}
65-
66-
def enqueueToEngine(engineId: Int, vPifoId: Int) = {
67-
val pid = engineId - 1 // Adjust for control port offset
68-
dut.io.insert(pid).valid #= true
69-
dut.io.insert(pid).payload.engineId #= engineId
70-
dut.io.insert(pid).payload.vPifoId #= vPifoId
71-
dut.clockDomain.waitRisingEdge()
72-
dut.io.insert(pid).valid #= false
73-
}
23+
val controller = PifoMeshSimController(testConfig, dut)
7424

75-
def requestDequeue(engineId: Int, vPifoId: Int) = {
76-
dut.io.dataRequest.valid #= true
77-
dut.io.dataRequest.payload.engineId #= engineId
78-
dut.io.dataRequest.payload.vPifoId #= vPifoId
79-
dut.clockDomain.waitRisingEdge()
80-
dut.io.dataRequest.valid #= false
81-
}
82-
83-
def monitor() = {
84-
fork {
85-
while (true) {
86-
dut.clockDomain.waitRisingEdge()
87-
if(dut.io.pop.valid.toBoolean) {
88-
val eng = dut.io.pop.payload.engineId.toLong
89-
val vp = dut.io.pop.payload.vPifoId.toLong
90-
println(s"[Monitor] Pop response: vPifoId=0x${vp.toHexString}")
91-
}
92-
}
93-
}
94-
}
95-
96-
// Clock generation
97-
fork {
98-
while (true) {
99-
sleep(5)
100-
dut.clockDomain.clockToggle()
101-
sleep(5)
102-
dut.clockDomain.clockToggle()
103-
}
104-
}
105-
106-
initialize()
107-
108-
dut.clockDomain.assertReset()
109-
dut.clockDomain.waitRisingEdge(4)
110-
dut.clockDomain.deassertReset()
111-
dut.clockDomain.waitRisingEdge(4)
112-
113-
monitor()
25+
controller.start
11426

11527
val flow0 = 0xE
11628
val flow1 = 0xF
@@ -119,67 +31,45 @@ object PifoMeshSim extends App {
11931
val vPifo_B = 0xB
12032
val vPifo_C = 0xC
12133

122-
val engine_out = 0
12334
val engine1 = 1
12435
val engine2 = 2
12536

126-
val vPifoMap = Map(
127-
engine1 -> Map(
128-
flow0 -> vPifo_A,
129-
flow1 -> vPifo_A
130-
),
131-
engine2 -> Map(
132-
flow0 -> vPifo_B,
133-
flow1 -> vPifo_C
134-
)
37+
val tree1 = TreeController(
38+
controller,
39+
pifos = Seq((engine1, vPifo_A), (engine2, vPifo_B), (engine2, vPifo_C))
13540
)
13641

137-
println("=== PifoMesh Simulation: Multi-Engine Test ===")
42+
val configThread = tree1.async_config { tc => {
43+
tc.addFlow(flow0, Seq(vPifo_A, vPifo_B))
44+
tc.addFlow(flow1, Seq(vPifo_A, vPifo_C))
13845

139-
// Configure engine 0
140-
println(s"Configuring Engine $engine1...")
141-
// Format: data = engineType (1=WFQ,2=SP,3=FIFO), vPifoId= vPifoId
142-
sendControl(ControlCommand.UpdateBrainEngine, engine1, 2, vPifoId = vPifo_A) // SP
143-
// add the non-exist rewrite
144-
// Format: data = (targetEngine, targetvPifoId), vPifoId = vPifoId
145-
sendControl(ControlCommand.UpdateMapperNonExist, engine1, mkFlowId(0, testConfig.numVPIFOs-1), vPifoId = vPifo_A)
146-
// SP MUST set per-flow state as priority
147-
// Format: data = state (priority in SP, Weight in WFQ), flowId = (engineId, flowId), vPifoId = vPifoId
148-
sendControl(ControlCommand.UpdateBrainFlowState, engine1, 10, vPifoId = vPifo_A, flowId = mkFlowId(engine1, flow0)) // prio flow0 -> 10
149-
sendControl(ControlCommand.UpdateBrainFlowState, engine1, 20, vPifoId = vPifo_A, flowId = mkFlowId(engine1, flow1)) // prio flow1 -> 20
150-
vPifoMap(engine1).foreach { case (flowId, vPifoId) =>
151-
// Format: data = vPifoId, vPifoId = flowId
152-
sendControl(ControlCommand.UpdateMapperPre, engine1, vPifoId, vPifoId = flowId)
153-
// Format: data = (targetEngineId, targetvPifoId), flowId = (sourceEngineId, sourceFlowId)
154-
sendControl(ControlCommand.UpdateMapperPost, engine1, mkFlowId(engine2, vPifoMap(engine2)(flowId)), flowId = mkFlowId(engine1, flowId))
155-
}
46+
tc.setBrainSP(vPifo_A)
47+
tc.setBrainState(vPifo_A, flow0, 10) // prio flow0 -> 10
48+
tc.setBrainState(vPifo_A, flow1, 20) // prio flow1 -> 20
49+
tc.setBrainFIFO(vPifo_B)
50+
tc.setBrainFIFO(vPifo_C)
51+
}}
15652

157-
println(s"Configuring Engine $engine2...")
158-
sendControl(ControlCommand.UpdateBrainEngine, engine2, 3, vPifoId = vPifo_B) // FIFO
159-
// Should not have non-exist on a non-root vPifo
160-
sendControl(ControlCommand.UpdateBrainEngine, engine2, 3, vPifoId = vPifo_C) // FIFO
161-
vPifoMap(engine2).foreach { case (flowId, vPifoId) =>
162-
sendControl(ControlCommand.UpdateMapperPre, engine2, vPifoId, vPifoId = flowId)
163-
sendControl(ControlCommand.UpdateMapperPost, engine2, mkFlowId(engine_out, flowId), flowId = mkFlowId(engine2, flowId))
164-
}
53+
// join here to ensure configuration completes before proceeding
54+
// but you could let it run in parallel with other testbench activity!
55+
configThread.join()
16556

57+
println("=== PifoMesh Simulation: Multi-Engine Test ===")
16658
dut.clockDomain.waitRisingEdge(4)
16759

16860
println(s"Enqueueing packets to Engine $engine1")
16961
for (i <- 0 until 3) {
170-
enqueueToEngine(engine1, flow0)
171-
enqueueToEngine(engine2, flow0)
62+
controller.enque(flow0)
17263
dut.clockDomain.waitRisingEdge(1)
173-
enqueueToEngine(engine1, flow1)
174-
enqueueToEngine(engine2, flow1)
64+
controller.enque(flow1)
17565
dut.clockDomain.waitRisingEdge(1)
17666
}
17767

17868
dut.clockDomain.waitRisingEdge(6)
17969

18070
println(s"Requesting dequeue from Engine $engine1 (root vPifo=$vPifo_A):")
18171
for (_ <- 0 until 8) {
182-
requestDequeue(engine1, vPifo_A)
72+
tree1.deque
18373
}
18474

18575
dut.clockDomain.waitRisingEdge(20)

0 commit comments

Comments
 (0)