OR-1 dataflow CPU sketch
1"""
2Tests for network routing with frame-based PE.
3
4Verifies pe-frame-redesign.AC1.5:
5- Network routing uses isinstance(token, PEToken) for all PE-bound tokens
6- CMToken, PELocalWriteToken, FrameControlToken all route to target PE
7- SMToken routes to target SM
8- build_topology() constructs PE with frame_count, frame_slots, matchable_offsets
9- build_topology() loads initial_frames and initial_tag_store
10"""
11
12import simpy
13import pytest
14
15from emu import build_topology, PEConfig, SMConfig
16from emu.types import PEConfig as PECfg
17from tokens import (
18 CMToken, DyadToken, MonadToken, PELocalWriteToken, FrameControlToken,
19 SMToken,
20)
21from cm_inst import MemOp, Port, FrameOp
22
23
24class TestPETokenRouting:
25 """AC1.5: All PE-bound tokens (CMToken, PELocalWriteToken, FrameControlToken) route to target PE."""
26
27 def test_cmtoken_routes_to_target_pe(self):
28 """CMToken (as DyadToken subclass) routes to target PE."""
29 env = simpy.Environment()
30 pe_configs = [
31 PECfg(pe_id=0),
32 PECfg(pe_id=1),
33 ]
34 sm_configs = [SMConfig(sm_id=0)]
35 system = build_topology(env, pe_configs, sm_configs)
36
37 # Inject DyadToken to PE 1
38 token = DyadToken(
39 target=1,
40 offset=0,
41 act_id=0,
42 data=42,
43 port=Port.L,
44 )
45 system.inject(token)
46
47 # Verify token arrived at PE 1's input store
48 assert len(system.pes[1].input_store.items) > 0
49 assert system.pes[1].input_store.items[0] == token
50
51 def test_pelocal_write_token_routes_to_target_pe(self):
52 """PELocalWriteToken routes to target PE."""
53 env = simpy.Environment()
54 pe_configs = [
55 PECfg(pe_id=0),
56 PECfg(pe_id=1),
57 ]
58 sm_configs = [SMConfig(sm_id=0)]
59 system = build_topology(env, pe_configs, sm_configs)
60
61 # Inject PELocalWriteToken to PE 1
62 token = PELocalWriteToken(
63 target=1,
64 act_id=0,
65 region=0,
66 slot=10,
67 data=99,
68 is_dest=False,
69 )
70 system.inject(token)
71
72 # Verify token arrived at PE 1's input store
73 assert len(system.pes[1].input_store.items) > 0
74 assert system.pes[1].input_store.items[0] == token
75
76 def test_frame_control_token_routes_to_target_pe(self):
77 """FrameControlToken routes to target PE."""
78 env = simpy.Environment()
79 pe_configs = [
80 PECfg(pe_id=0),
81 PECfg(pe_id=1),
82 ]
83 sm_configs = [SMConfig(sm_id=0)]
84 system = build_topology(env, pe_configs, sm_configs)
85
86 # Inject FrameControlToken to PE 1
87 token = FrameControlToken(
88 target=1,
89 act_id=0,
90 op=FrameOp.ALLOC,
91 payload=0,
92 )
93 system.inject(token)
94
95 # Verify token arrived at PE 1's input store
96 assert len(system.pes[1].input_store.items) > 0
97 assert system.pes[1].input_store.items[0] == token
98
99 def test_smtoken_routes_to_target_sm(self):
100 """SMToken routes to target SM, not PE."""
101 env = simpy.Environment()
102 pe_configs = [PECfg(pe_id=0)]
103 sm_configs = [
104 SMConfig(sm_id=0),
105 SMConfig(sm_id=1),
106 ]
107 system = build_topology(env, pe_configs, sm_configs)
108
109 # Inject SMToken to SM 1
110 token = SMToken(
111 target=1,
112 addr=100,
113 op=MemOp.WRITE,
114 flags=None,
115 data=42,
116 ret=None,
117 )
118 system.inject(token)
119
120 # Verify token arrived at SM 1's input store
121 assert len(system.sms[1].input_store.items) > 0
122 assert system.sms[1].input_store.items[0] == token
123 # And NOT at PE 0
124 assert len(system.pes[0].input_store.items) == 0
125
126
127class TestBuildTopologyFrameConfig:
128 """AC1.5: build_topology passes frame config fields to PE constructor."""
129
130 def test_frame_config_params_passed(self):
131 """build_topology passes frame_count, frame_slots, matchable_offsets."""
132 env = simpy.Environment()
133 pe_configs = [
134 PECfg(
135 pe_id=0,
136 frame_count=16,
137 frame_slots=128,
138 matchable_offsets=16,
139 ),
140 ]
141 sm_configs = [SMConfig(sm_id=0)]
142 system = build_topology(env, pe_configs, sm_configs)
143
144 pe = system.pes[0]
145 assert pe.frame_count == 16
146 assert pe.frame_slots == 128
147 assert pe.matchable_offsets == 16
148
149 def test_loads_initial_frames(self):
150 """build_topology loads initial_frames into PE."""
151 env = simpy.Environment()
152 initial_frames = {
153 0: [1, 2, 3, 4, 5],
154 1: [10, 20, 30, 40, 50],
155 }
156 pe_configs = [
157 PECfg(
158 pe_id=0,
159 frame_count=8,
160 frame_slots=64,
161 initial_frames=initial_frames,
162 ),
163 ]
164 sm_configs = [SMConfig(sm_id=0)]
165 system = build_topology(env, pe_configs, sm_configs)
166
167 pe = system.pes[0]
168 # Frames are initialized with slots filled from the list
169 assert pe.frames[0][:5] == [1, 2, 3, 4, 5]
170 assert pe.frames[1][:5] == [10, 20, 30, 40, 50]
171
172 def test_loads_initial_tag_store(self):
173 """build_topology loads initial_tag_store into PE and removes frames from free_frames."""
174 env = simpy.Environment()
175 initial_tag_store = {
176 0: (2, 0), # act_id 0 → frame 2, lane 0
177 1: (3, 0), # act_id 1 → frame 3, lane 0
178 }
179 pe_configs = [
180 PECfg(
181 pe_id=0,
182 frame_count=8,
183 initial_tag_store=initial_tag_store,
184 ),
185 ]
186 sm_configs = [SMConfig(sm_id=0)]
187 system = build_topology(env, pe_configs, sm_configs)
188
189 pe = system.pes[0]
190 assert pe.tag_store[0] == (2, 0)
191 assert pe.tag_store[1] == (3, 0)
192 # Frames 2 and 3 should be removed from free_frames
193 assert 2 not in pe.free_frames
194 assert 3 not in pe.free_frames
195 # Other frames should still be in free_frames
196 assert 0 in pe.free_frames
197 assert 1 in pe.free_frames
198
199 def test_initial_frames_and_tag_store_together(self):
200 """build_topology correctly initializes both frames and tag_store."""
201 env = simpy.Environment()
202 initial_frames = {
203 0: [1, 2, 3],
204 1: [4, 5, 6],
205 2: [7, 8, 9],
206 }
207 initial_tag_store = {
208 0: (0, 0), # act_id 0 uses frame 0, lane 0
209 1: (1, 0), # act_id 1 uses frame 1, lane 0
210 }
211 pe_configs = [
212 PECfg(
213 pe_id=0,
214 frame_count=4,
215 initial_frames=initial_frames,
216 initial_tag_store=initial_tag_store,
217 ),
218 ]
219 sm_configs = [SMConfig(sm_id=0)]
220 system = build_topology(env, pe_configs, sm_configs)
221
222 pe = system.pes[0]
223 # Verify frames loaded (first N slots should match)
224 assert pe.frames[0][:3] == [1, 2, 3]
225 assert pe.frames[1][:3] == [4, 5, 6]
226 assert pe.frames[2][:3] == [7, 8, 9]
227 # Verify tag_store loaded
228 assert pe.tag_store[0] == (0, 0)
229 assert pe.tag_store[1] == (1, 0)
230 # Verify free_frames reflects allocations
231 assert 0 not in pe.free_frames
232 assert 1 not in pe.free_frames
233 assert 2 in pe.free_frames
234 assert 3 in pe.free_frames
235
236
237class TestMultiplePEs:
238 """Test network routing with multiple PEs and SMs."""
239
240 def test_multiple_pe_network(self):
241 """Multiple PEs route tokens correctly."""
242 env = simpy.Environment()
243 pe_configs = [
244 PECfg(pe_id=0),
245 PECfg(pe_id=1),
246 PECfg(pe_id=2),
247 ]
248 sm_configs = [SMConfig(sm_id=0)]
249 system = build_topology(env, pe_configs, sm_configs)
250
251 # Send tokens to different PEs
252 t0 = DyadToken(target=0, offset=0, act_id=0, data=10, port=Port.L)
253 t1 = DyadToken(target=1, offset=0, act_id=0, data=20, port=Port.L)
254 t2 = DyadToken(target=2, offset=0, act_id=0, data=30, port=Port.L)
255
256 system.inject(t0)
257 system.inject(t1)
258 system.inject(t2)
259
260 # Verify each PE received correct token
261 assert system.pes[0].input_store.items[0].data == 10
262 assert system.pes[1].input_store.items[0].data == 20
263 assert system.pes[2].input_store.items[0].data == 30
264
265 def test_multiple_sm_network(self):
266 """Multiple SMs route tokens correctly."""
267 env = simpy.Environment()
268 pe_configs = [PECfg(pe_id=0)]
269 sm_configs = [
270 SMConfig(sm_id=0),
271 SMConfig(sm_id=1),
272 SMConfig(sm_id=2),
273 ]
274 system = build_topology(env, pe_configs, sm_configs)
275
276 # Send tokens to different SMs
277 t0 = SMToken(target=0, addr=100, op=MemOp.READ, flags=None, data=None, ret=None)
278 t1 = SMToken(target=1, addr=100, op=MemOp.READ, flags=None, data=None, ret=None)
279 t2 = SMToken(target=2, addr=100, op=MemOp.READ, flags=None, data=None, ret=None)
280
281 system.inject(t0)
282 system.inject(t1)
283 system.inject(t2)
284
285 # Verify each SM received correct token
286 assert system.sms[0].input_store.items[0].target == 0
287 assert system.sms[1].input_store.items[0].target == 1
288 assert system.sms[2].input_store.items[0].target == 2