@@ -4,9 +4,9 @@ import spinal.core._
44import spinal .core .sim ._
55import spinal .lib ._
66import rio ._
7+ import spinal .sim .SimThread
78
89object 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