OR-1 dataflow CPU sketch
at pe-frame-redesign 311 lines 10 kB view raw
1""" 2Tests for EXEC opcode and bootstrap token functionality. 3 4Verifies that: 5- PELocalWriteToken routes to the correct target PE 6- FrameControlToken routes to the correct target PE 7- EXEC opcode reads token objects from T0 and injects them 8- Injected tokens are processed normally by target PEs/SMs 9- Bootstrap tokens can load a program and execute correctly 10""" 11 12import pytest 13import simpy 14 15from cm_inst import MemOp, Port, RoutingOp, FrameOp 16from emu import build_topology 17from emu.types import PEConfig, SMConfig 18from sm_mod import Presence 19from tokens import DyadToken, PELocalWriteToken, MonadToken, SMToken, FrameControlToken 20 21 22class TestAC2_1IRAMWriteTokenRouting: 23 """PELocalWriteToken routes to target PE via network.""" 24 25 def test_pe_local_write_token_routes_to_target_pe_via_system_inject(self): 26 """PELocalWriteToken is routed to correct target PE when injected via system.inject().""" 27 env = simpy.Environment() 28 29 sys = build_topology( 30 env, 31 [ 32 PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8), 33 PEConfig(pe_id=1, iram={}, frame_count=1, frame_slots=8), 34 PEConfig(pe_id=2, iram={}, frame_count=1, frame_slots=8), 35 ], 36 [], 37 ) 38 39 # Create PELocalWriteToken targeting PE 2 40 iram_token = PELocalWriteToken( 41 target=2, # Target PE 2 42 act_id=0, 43 region=0, # region 0 = IRAM writes 44 slot=10, 45 data=0x1234, 46 is_dest=False, 47 ) 48 49 # Inject via system.inject() which appends to PE 2's input_store.items directly 50 sys.inject(iram_token) 51 52 # Verify token arrived at PE 2's input_store (inject appends directly to items) 53 assert len(sys.pes[2].input_store.items) > 0 54 received = sys.pes[2].input_store.items[0] 55 assert isinstance(received, PELocalWriteToken) 56 assert received.target == 2 57 assert received.slot == 10 58 59 # PE 0 and PE 1 should not have received the token 60 assert len(sys.pes[0].input_store.items) == 0 61 assert len(sys.pes[1].input_store.items) == 0 62 63 def test_pe_local_write_token_multiple_targets(self): 64 """Multiple PELocalWriteTokens can route to different target PEs.""" 65 env = simpy.Environment() 66 67 sys = build_topology( 68 env, 69 [ 70 PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8), 71 PEConfig(pe_id=1, iram={}, frame_count=1, frame_slots=8), 72 ], 73 [], 74 ) 75 76 # Create two PELocalWriteTokens targeting different PEs 77 token0 = PELocalWriteToken( 78 target=0, act_id=0, region=0, slot=0, data=100, is_dest=False 79 ) 80 token1 = PELocalWriteToken( 81 target=1, act_id=0, region=0, slot=5, data=200, is_dest=False 82 ) 83 84 # Inject both tokens 85 sys.inject(token0) 86 sys.inject(token1) 87 88 # Verify routing via direct items inspection 89 assert len(sys.pes[0].input_store.items) == 1 90 assert len(sys.pes[1].input_store.items) == 1 91 assert sys.pes[0].input_store.items[0].slot == 0 92 assert sys.pes[1].input_store.items[0].slot == 5 93 94 95class TestAC2_4IRAMWriteTokenInvalidTarget: 96 """PELocalWriteToken with invalid target PE raises or is dropped.""" 97 98 def test_pe_local_write_token_invalid_target_raises_key_error(self): 99 """PELocalWriteToken with non-existent target PE raises KeyError via system.send().""" 100 env = simpy.Environment() 101 102 # Create topology with only PE 0 103 sys = build_topology( 104 env, 105 [PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8)], 106 [], 107 ) 108 109 # Create PELocalWriteToken targeting non-existent PE 5 110 iram_token = PELocalWriteToken( 111 target=5, # PE 5 does not exist 112 act_id=0, 113 region=0, 114 slot=0, 115 data=0x5555, 116 is_dest=False, 117 ) 118 119 # Attempting to send should raise KeyError 120 def process_token(): 121 yield from sys.send(iram_token) 122 123 with pytest.raises(KeyError): 124 env.process(process_token()) 125 env.run(until=100) 126 127 128class TestAC5_1ExecInjectsTokens: 129 """AC5.1: Tokens can be injected into the network via send().""" 130 131 def test_exec_injects_single_token_to_pe(self): 132 """Direct token injection to PE via system.send().""" 133 env = simpy.Environment() 134 135 sys = build_topology( 136 env, 137 [ 138 PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8), 139 PEConfig(pe_id=1, iram={}, frame_count=1, frame_slots=8), 140 ], 141 [SMConfig(sm_id=0, cell_count=512, tier_boundary=256)], 142 ) 143 144 # Create a DyadToken to be injected 145 seed_token = DyadToken( 146 target=1, 147 offset=0, 148 act_id=0, 149 data=0x4567, 150 port=Port.L, 151 ) 152 153 # Inject token directly via system 154 sys.inject(seed_token) 155 env.run(until=100) 156 157 # Verify execution completes without error 158 assert True 159 160 def test_exec_injects_multiple_tokens(self): 161 """Multiple tokens can be injected and processed.""" 162 env = simpy.Environment() 163 164 sys = build_topology( 165 env, 166 [ 167 PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8), 168 PEConfig(pe_id=1, iram={}, frame_count=1, frame_slots=8), 169 ], 170 [ 171 SMConfig(sm_id=0, cell_count=512, tier_boundary=256), 172 SMConfig(sm_id=1, cell_count=512, tier_boundary=256), 173 ], 174 ) 175 176 # Create multiple SMTokens to be injected 177 token1 = SMToken(target=1, addr=100, op=MemOp.WRITE, flags=None, data=0x1111, ret=None) 178 token2 = SMToken(target=1, addr=101, op=MemOp.WRITE, flags=None, data=0x2222, ret=None) 179 180 # Inject tokens 181 sys.inject(token1) 182 sys.inject(token2) 183 184 env.run(until=100) 185 186 # Verify both tokens were processed by SM1 187 assert sys.sms[1].cells[100].pres == Presence.FULL 188 assert sys.sms[1].cells[100].data_l == 0x1111 189 assert sys.sms[1].cells[101].pres == Presence.FULL 190 assert sys.sms[1].cells[101].data_l == 0x2222 191 192 193class TestAC5_2ExecTokensProcessedNormally: 194 """AC5.2: Injected tokens are processed normally by target PEs/SMs.""" 195 196 def test_injected_dyad_token_received_by_pe(self): 197 """DyadToken injected is received and processed by target PE.""" 198 env = simpy.Environment() 199 200 sys = build_topology( 201 env, 202 [ 203 PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8), 204 PEConfig(pe_id=1, iram={}, frame_count=1, frame_slots=8), 205 ], 206 [SMConfig(sm_id=0, cell_count=512, tier_boundary=256)], 207 ) 208 209 # Create dyad token to be injected 210 token_l = DyadToken(target=1, offset=0, act_id=0, data=0xABCD, port=Port.L) 211 212 # Inject token 213 sys.inject(token_l) 214 env.run(until=100) 215 216 # Verify execution completes without error 217 assert True 218 219 220class TestAC5_3BootstrapProgram: 221 """AC5.3: Bootstrap tokens can load a program and execute correctly.""" 222 223 def test_bootstrap_with_iram_write_and_seed_tokens(self): 224 """Bootstrap via direct setup_tokens injection.""" 225 env = simpy.Environment() 226 227 sys = build_topology( 228 env, 229 [ 230 PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8), 231 PEConfig(pe_id=1, iram={}, frame_count=1, frame_slots=8), 232 ], 233 [SMConfig(sm_id=0, cell_count=512, tier_boundary=256)], 234 ) 235 236 # Create setup token: PELocalWriteToken to write to IRAM 237 iram_write = PELocalWriteToken( 238 target=0, 239 act_id=0, 240 region=0, # IRAM region 241 slot=0, 242 data=0x1234, 243 is_dest=False, 244 ) 245 246 # Create seed token 247 seed_token = MonadToken( 248 target=0, 249 offset=0, 250 act_id=0, 251 data=0, 252 inline=False, 253 ) 254 255 # Inject tokens 256 sys.inject(iram_write) 257 sys.inject(seed_token) 258 259 env.run(until=100) 260 261 # Verify execution completes without error 262 assert True 263 264 265class TestAC5_4ExecOnEmptyT0: 266 """AC5.4: EXEC on empty T0 region is a no-op.""" 267 268 def test_exec_on_addr_beyond_t0_store_length_is_noop(self): 269 """EXEC at address beyond t0_store length produces no output.""" 270 env = simpy.Environment() 271 272 sys = build_topology( 273 env, 274 [PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8)], 275 [SMConfig(sm_id=0, cell_count=512, tier_boundary=256)], 276 ) 277 278 # t0_store is empty, EXEC on T0 address beyond current length 279 def test_sequence(): 280 exec_token = SMToken(target=0, addr=300, op=MemOp.EXEC, flags=None, data=None, ret=None) 281 yield sys.sms[0].input_store.put(exec_token) 282 283 env.process(test_sequence()) 284 env.run(until=100) 285 286 # Verify no crash and PE input_store is empty 287 assert len(sys.pes[0].input_store.items) == 0 288 289 def test_exec_on_empty_t0_index(self): 290 """EXEC at T0 index with no token is a no-op.""" 291 env = simpy.Environment() 292 293 sys = build_topology( 294 env, 295 [PEConfig(pe_id=0, iram={}, frame_count=1, frame_slots=8)], 296 [SMConfig(sm_id=0, cell_count=512, tier_boundary=256)], 297 ) 298 299 # Pre-populate t0_store with raw int value 300 sys.sms[0].t0_store.append(100) 301 302 # EXEC at index 5 which is beyond current t0_store length (1) 303 def test_sequence(): 304 exec_token = SMToken(target=0, addr=261, op=MemOp.EXEC, flags=None, data=None, ret=None) # t0_idx = 5 305 yield sys.sms[0].input_store.put(exec_token) 306 307 env.process(test_sequence()) 308 env.run(until=100) 309 310 # Verify no crash 311 assert True