phanerozoic commited on
Commit
bba04cf
·
verified ·
1 Parent(s): 76a0242

Delete generate_routing.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. generate_routing.py +0 -1395
generate_routing.py DELETED
@@ -1,1395 +0,0 @@
1
- """
2
- Generate routing.json for the 8-bit threshold computer.
3
- Maps each gate to its input sources.
4
- """
5
-
6
- import json
7
- from safetensors import safe_open
8
- from collections import defaultdict
9
-
10
- def get_all_gates(tensors_path):
11
- """Extract all unique gate paths from tensors file."""
12
- gates = set()
13
- with safe_open(tensors_path, framework='pt') as f:
14
- for key in f.keys():
15
- if key.endswith('.weight'):
16
- gates.add(key[:-7])
17
- elif key.endswith('.bias'):
18
- gates.add(key[:-5])
19
- else:
20
- gates.add(key)
21
- return sorted(gates)
22
-
23
-
24
- def generate_boolean_routing():
25
- """Generate routing for boolean gates."""
26
- routing = {}
27
-
28
- # Single-layer 2-input gates
29
- for gate in ['and', 'or', 'nand', 'nor', 'implies']:
30
- routing[f'boolean.{gate}'] = {
31
- 'inputs': ['$a', '$b'],
32
- 'type': 'single_layer'
33
- }
34
-
35
- # NOT gate (1 input)
36
- routing['boolean.not'] = {
37
- 'inputs': ['$a'],
38
- 'type': 'single_layer'
39
- }
40
-
41
- # Two-layer gates (XOR, XNOR, BIIMPLIES)
42
- for gate in ['xor', 'xnor', 'biimplies']:
43
- routing[f'boolean.{gate}'] = {
44
- 'inputs': ['$a', '$b'],
45
- 'type': 'two_layer_neuron',
46
- 'internal': {
47
- 'layer1.neuron1': ['$a', '$b'],
48
- 'layer1.neuron2': ['$a', '$b'],
49
- 'layer2': ['layer1.neuron1', 'layer1.neuron2']
50
- },
51
- 'output': 'layer2'
52
- }
53
-
54
- return routing
55
-
56
-
57
- def generate_arithmetic_halfadder_routing():
58
- """Generate routing for half adder."""
59
- return {
60
- 'arithmetic.halfadder': {
61
- 'inputs': ['$a', '$b'],
62
- 'type': 'composite',
63
- 'internal': {
64
- # Sum is XOR(a, b)
65
- 'sum.layer1.or': ['$a', '$b'],
66
- 'sum.layer1.nand': ['$a', '$b'],
67
- 'sum.layer2': ['sum.layer1.or', 'sum.layer1.nand'],
68
- # Carry is AND(a, b)
69
- 'carry': ['$a', '$b']
70
- },
71
- 'outputs': {
72
- 'sum': 'sum.layer2',
73
- 'carry': 'carry'
74
- }
75
- }
76
- }
77
-
78
-
79
- def generate_arithmetic_fulladder_routing():
80
- """Generate routing for full adder."""
81
- return {
82
- 'arithmetic.fulladder': {
83
- 'inputs': ['$a', '$b', '$cin'],
84
- 'type': 'composite',
85
- 'internal': {
86
- # HA1: a + b
87
- 'ha1.sum.layer1.or': ['$a', '$b'],
88
- 'ha1.sum.layer1.nand': ['$a', '$b'],
89
- 'ha1.sum.layer2': ['ha1.sum.layer1.or', 'ha1.sum.layer1.nand'],
90
- 'ha1.carry': ['$a', '$b'],
91
- # HA2: ha1.sum + cin
92
- 'ha2.sum.layer1.or': ['ha1.sum.layer2', '$cin'],
93
- 'ha2.sum.layer1.nand': ['ha1.sum.layer2', '$cin'],
94
- 'ha2.sum.layer2': ['ha2.sum.layer1.or', 'ha2.sum.layer1.nand'],
95
- 'ha2.carry': ['ha1.sum.layer2', '$cin'],
96
- # Carry out
97
- 'carry_or': ['ha1.carry', 'ha2.carry']
98
- },
99
- 'outputs': {
100
- 'sum': 'ha2.sum.layer2',
101
- 'cout': 'carry_or'
102
- }
103
- }
104
- }
105
-
106
-
107
- def generate_ripplecarry_routing(bits):
108
- """Generate routing for N-bit ripple carry adder."""
109
- name = f'arithmetic.ripplecarry{bits}bit'
110
- internal = {}
111
-
112
- for i in range(bits):
113
- prefix = f'fa{i}'
114
- if i == 0:
115
- cin = '#0' # First carry in is 0
116
- else:
117
- cin = f'fa{i-1}.carry_or'
118
-
119
- a_bit = f'$a[{i}]'
120
- b_bit = f'$b[{i}]'
121
-
122
- # Full adder structure
123
- internal[f'{prefix}.ha1.sum.layer1.or'] = [a_bit, b_bit]
124
- internal[f'{prefix}.ha1.sum.layer1.nand'] = [a_bit, b_bit]
125
- internal[f'{prefix}.ha1.sum.layer2'] = [f'{prefix}.ha1.sum.layer1.or', f'{prefix}.ha1.sum.layer1.nand']
126
- internal[f'{prefix}.ha1.carry'] = [a_bit, b_bit]
127
-
128
- internal[f'{prefix}.ha2.sum.layer1.or'] = [f'{prefix}.ha1.sum.layer2', cin]
129
- internal[f'{prefix}.ha2.sum.layer1.nand'] = [f'{prefix}.ha1.sum.layer2', cin]
130
- internal[f'{prefix}.ha2.sum.layer2'] = [f'{prefix}.ha2.sum.layer1.or', f'{prefix}.ha2.sum.layer1.nand']
131
- internal[f'{prefix}.ha2.carry'] = [f'{prefix}.ha1.sum.layer2', cin]
132
-
133
- internal[f'{prefix}.carry_or'] = [f'{prefix}.ha1.carry', f'{prefix}.ha2.carry']
134
-
135
- outputs = {f'sum[{i}]': f'fa{i}.ha2.sum.layer2' for i in range(bits)}
136
- outputs['cout'] = f'fa{bits-1}.carry_or'
137
-
138
- return {
139
- name: {
140
- 'inputs': [f'$a[0:{bits-1}]', f'$b[0:{bits-1}]'],
141
- 'type': 'ripple_carry',
142
- 'internal': internal,
143
- 'outputs': outputs
144
- }
145
- }
146
-
147
-
148
- def generate_comparator_routing():
149
- """Generate routing for 8-bit comparators."""
150
- routing = {}
151
-
152
- # These are single-layer weighted comparators
153
- for name in ['greaterthan8bit', 'lessthan8bit', 'greaterorequal8bit', 'lessorequal8bit']:
154
- routing[f'arithmetic.{name}'] = {
155
- 'inputs': ['$a[0:7]', '$b[0:7]'],
156
- 'type': 'weighted_comparator',
157
- 'internal': {
158
- 'comparator': ['$a[0:7]', '$b[0:7]'] # Difference weighted by position
159
- },
160
- 'output': 'comparator'
161
- }
162
-
163
- return routing
164
-
165
-
166
- def generate_threshold_routing():
167
- """Generate routing for threshold gates."""
168
- routing = {}
169
-
170
- # k-of-8 gates
171
- for name in ['oneoutof8', 'twooutof8', 'threeoutof8', 'fouroutof8',
172
- 'fiveoutof8', 'sixoutof8', 'sevenoutof8', 'alloutof8']:
173
- routing[f'threshold.{name}'] = {
174
- 'inputs': ['$x[0:7]'],
175
- 'type': 'threshold_gate',
176
- 'internal': {
177
- '': ['$x[0]', '$x[1]', '$x[2]', '$x[3]', '$x[4]', '$x[5]', '$x[6]', '$x[7]']
178
- }
179
- }
180
-
181
- # Majority/minority
182
- routing['threshold.majority'] = {
183
- 'inputs': ['$x[0:7]'],
184
- 'type': 'threshold_gate',
185
- 'internal': {'': ['$x[0:7]']}
186
- }
187
- routing['threshold.minority'] = {
188
- 'inputs': ['$x[0:7]'],
189
- 'type': 'threshold_gate',
190
- 'internal': {'': ['$x[0:7]']}
191
- }
192
-
193
- # atleastk, atmostk, exactlyk for 4-bit
194
- routing['threshold.atleastk_4'] = {
195
- 'inputs': ['$x[0:3]'],
196
- 'type': 'threshold_gate'
197
- }
198
- routing['threshold.atmostk_4'] = {
199
- 'inputs': ['$x[0:3]'],
200
- 'type': 'threshold_gate'
201
- }
202
- routing['threshold.exactlyk_4'] = {
203
- 'inputs': ['$x[0:3]'],
204
- 'type': 'composite',
205
- 'internal': {
206
- 'atleast': ['$x[0:3]'],
207
- 'atmost': ['$x[0:3]'],
208
- 'and': ['atleast', 'atmost']
209
- },
210
- 'output': 'and'
211
- }
212
-
213
- return routing
214
-
215
-
216
- def generate_modular_routing():
217
- """Generate routing for modular arithmetic circuits."""
218
- routing = {}
219
-
220
- # Powers of 2 are single-layer
221
- for mod in [2, 4, 8]:
222
- routing[f'modular.mod{mod}'] = {
223
- 'inputs': ['$x[0:7]'],
224
- 'type': 'single_layer',
225
- 'internal': {'': ['$x[0:7]']}
226
- }
227
-
228
- # Non-powers of 2 use 3-layer detection
229
- for mod in [3, 5, 6, 7, 9, 10, 11, 12]:
230
- # Count detectors (values divisible by mod in range 0-255)
231
- num_detectors = len([v for v in range(256) if v % mod == 0])
232
-
233
- internal = {}
234
- layer2_inputs = []
235
-
236
- for idx in range(num_detectors):
237
- internal[f'layer1.geq{idx}'] = ['$x[0:7]']
238
- internal[f'layer1.leq{idx}'] = ['$x[0:7]']
239
- internal[f'layer2.eq{idx}'] = [f'layer1.geq{idx}', f'layer1.leq{idx}']
240
- layer2_inputs.append(f'layer2.eq{idx}')
241
-
242
- internal['layer3.or'] = layer2_inputs
243
-
244
- routing[f'modular.mod{mod}'] = {
245
- 'inputs': ['$x[0:7]'],
246
- 'type': 'modular_detector',
247
- 'internal': internal,
248
- 'output': 'layer3.or'
249
- }
250
-
251
- return routing
252
-
253
-
254
- def generate_equality_routing():
255
- """Generate routing for 8-bit equality circuit."""
256
- internal = {}
257
- xnor_outputs = []
258
-
259
- for i in range(8):
260
- # Each XNOR compares bit i of a and b
261
- internal[f'xnor{i}.layer1.and'] = [f'$a[{i}]', f'$b[{i}]']
262
- internal[f'xnor{i}.layer1.nor'] = [f'$a[{i}]', f'$b[{i}]']
263
- internal[f'xnor{i}.layer2'] = [f'xnor{i}.layer1.and', f'xnor{i}.layer1.nor']
264
- xnor_outputs.append(f'xnor{i}.layer2')
265
-
266
- # Final AND of all XNORs
267
- internal['and'] = xnor_outputs
268
-
269
- return {
270
- 'arithmetic.equality8bit': {
271
- 'inputs': ['$a[0:7]', '$b[0:7]'],
272
- 'type': 'equality',
273
- 'internal': internal,
274
- 'output': 'and'
275
- }
276
- }
277
-
278
-
279
- def generate_neg8bit_routing():
280
- """Generate routing for 8-bit negation (two's complement)."""
281
- internal = {}
282
-
283
- # NOT gates for each bit
284
- for i in range(8):
285
- internal[f'not{i}'] = [f'$x[{i}]']
286
-
287
- # Add 1 using half/full adders (simplified view)
288
- # Bit 0: XOR(not0, 1) = NOT(not0) = x0, carry = not0
289
- internal['sum0'] = ['not0'] # Actually just passes through for +1
290
- internal['carry0'] = ['not0']
291
-
292
- # Remaining bits use XOR with carry propagation
293
- for i in range(1, 8):
294
- prev_carry = f'carry{i-1}' if i > 1 else 'carry0'
295
- internal[f'xor{i}.layer1.nand'] = [f'not{i}', prev_carry]
296
- internal[f'xor{i}.layer1.or'] = [f'not{i}', prev_carry]
297
- internal[f'xor{i}.layer2'] = [f'xor{i}.layer1.nand', f'xor{i}.layer1.or']
298
- internal[f'and{i}'] = [f'not{i}', prev_carry]
299
-
300
- internal['overflow'] = ['not7', 'carry6'] if 8 > 1 else ['not0']
301
-
302
- return {
303
- 'arithmetic.neg8bit': {
304
- 'inputs': ['$x[0:7]'],
305
- 'type': 'negation',
306
- 'internal': internal,
307
- 'outputs': {f'out[{i}]': f'xor{i}.layer2' if i > 0 else 'sum0' for i in range(8)}
308
- }
309
- }
310
-
311
-
312
- def generate_multiplier2x2_routing():
313
- """Generate routing for 2x2 multiplier."""
314
- internal = {}
315
-
316
- # Partial products (AND gates)
317
- for a in range(2):
318
- for b in range(2):
319
- internal[f'and{a}{b}'] = [f'$a[{a}]', f'$b[{b}]']
320
-
321
- # Product bits:
322
- # p0 = a0*b0
323
- # p1 = a1*b0 + a0*b1
324
- # p2 = a1*b1 + carry from p1
325
- # p3 = carry from p2
326
-
327
- # Half adder for bit 1
328
- internal['ha0.sum.layer1.or'] = ['and10', 'and01']
329
- internal['ha0.sum.layer1.nand'] = ['and10', 'and01']
330
- internal['ha0.sum.layer2'] = ['ha0.sum.layer1.or', 'ha0.sum.layer1.nand']
331
- internal['ha0.carry'] = ['and10', 'and01']
332
-
333
- # Full adder for bit 2
334
- internal['fa0.ha1.sum.layer1.or'] = ['and11', 'ha0.carry']
335
- internal['fa0.ha1.sum.layer1.nand'] = ['and11', 'ha0.carry']
336
- internal['fa0.ha1.sum.layer2'] = ['fa0.ha1.sum.layer1.or', 'fa0.ha1.sum.layer1.nand']
337
- internal['fa0.ha1.carry'] = ['and11', 'ha0.carry']
338
- internal['fa0.ha2.sum.layer1.or'] = ['fa0.ha1.sum.layer2', '#0']
339
- internal['fa0.ha2.sum.layer1.nand'] = ['fa0.ha1.sum.layer2', '#0']
340
- internal['fa0.ha2.sum.layer2'] = ['fa0.ha2.sum.layer1.or', 'fa0.ha2.sum.layer1.nand']
341
- internal['fa0.ha2.carry'] = ['fa0.ha1.sum.layer2', '#0']
342
- internal['fa0.carry_or'] = ['fa0.ha1.carry', 'fa0.ha2.carry']
343
-
344
- return {
345
- 'arithmetic.multiplier2x2': {
346
- 'inputs': ['$a[0:1]', '$b[0:1]'],
347
- 'type': 'multiplier',
348
- 'internal': internal,
349
- 'outputs': {
350
- 'p[0]': 'and00',
351
- 'p[1]': 'ha0.sum.layer2',
352
- 'p[2]': 'fa0.ha2.sum.layer2',
353
- 'p[3]': 'fa0.carry_or'
354
- }
355
- }
356
- }
357
-
358
-
359
- def generate_pattern_routing():
360
- """Generate routing for pattern recognition circuits."""
361
- routing = {}
362
-
363
- # Simple threshold-based patterns
364
- for name in ['popcount', 'allzeros', 'allones', 'leadingones', 'trailingones', 'runlength']:
365
- routing[f'pattern_recognition.{name}'] = {
366
- 'inputs': ['$x[0:7]'],
367
- 'type': 'weighted_sum'
368
- }
369
-
370
- # One-hot detector (atleast1 AND atmost1)
371
- routing['pattern_recognition.onehotdetector'] = {
372
- 'inputs': ['$x[0:7]'],
373
- 'type': 'composite',
374
- 'internal': {
375
- 'atleast1': ['$x[0:7]'],
376
- 'atmost1': ['$x[0:7]'],
377
- 'and': ['atleast1', 'atmost1']
378
- },
379
- 'output': 'and'
380
- }
381
-
382
- # Alternating pattern (2 pattern matchers)
383
- routing['pattern_recognition.alternating8bit'] = {
384
- 'inputs': ['$x[0:7]'],
385
- 'type': 'composite',
386
- 'internal': {
387
- 'pattern1': ['$x[0:7]'], # 10101010
388
- 'pattern2': ['$x[0:7]'] # 01010101
389
- }
390
- }
391
-
392
- # Hamming distance (XOR + popcount)
393
- routing['pattern_recognition.hammingdistance8bit'] = {
394
- 'inputs': ['$a[0:7]', '$b[0:7]'],
395
- 'type': 'composite',
396
- 'internal': {
397
- 'xor': ['$a[0:7]', '$b[0:7]'],
398
- 'popcount': ['xor']
399
- },
400
- 'output': 'popcount'
401
- }
402
-
403
- # Symmetry detector (4 XNORs + AND)
404
- routing['pattern_recognition.symmetry8bit'] = {
405
- 'inputs': ['$x[0:7]'],
406
- 'type': 'composite',
407
- 'internal': {
408
- 'xnor0': ['$x[0]', '$x[7]'],
409
- 'xnor1': ['$x[1]', '$x[6]'],
410
- 'xnor2': ['$x[2]', '$x[5]'],
411
- 'xnor3': ['$x[3]', '$x[4]'],
412
- 'and': ['xnor0', 'xnor1', 'xnor2', 'xnor3']
413
- },
414
- 'output': 'and'
415
- }
416
-
417
- return routing
418
-
419
-
420
- def generate_manifest_routing():
421
- """Generate routing for manifest (constants, no actual routing)."""
422
- return {
423
- 'manifest.alu_operations': {'type': 'constant', 'value': 16},
424
- 'manifest.flags': {'type': 'constant', 'value': 4},
425
- 'manifest.instruction_width': {'type': 'constant', 'value': 16},
426
- 'manifest.memory_bytes': {'type': 'constant', 'value': 256},
427
- 'manifest.pc_width': {'type': 'constant', 'value': 8},
428
- 'manifest.register_width': {'type': 'constant', 'value': 8},
429
- 'manifest.registers': {'type': 'constant', 'value': 4},
430
- 'manifest.turing_complete': {'type': 'constant', 'value': 1},
431
- 'manifest.version': {'type': 'constant', 'value': 1}
432
- }
433
-
434
-
435
- def generate_multiplier8x8_routing():
436
- """Generate routing for 8x8 multiplier."""
437
- internal = {}
438
-
439
- # Partial products: 64 AND gates (8x8)
440
- for row in range(8):
441
- for col in range(8):
442
- internal[f'pp.r{row}.c{col}'] = [f'$a[{col}]', f'$b[{row}]']
443
-
444
- # Stage adders: 7 stages, each stage adds one row of partial products
445
- # Stage i adds row i+1, result width grows from 9 to 15 bits
446
- for stage in range(7):
447
- row_idx = stage + 1
448
- shift = row_idx
449
- sum_width = 8 + stage + 1 # 9, 10, 11, 12, 13, 14, 15
450
-
451
- for bit in range(sum_width):
452
- prefix = f'stage{stage}.bit{bit}'
453
-
454
- # Determine inputs for this bit position
455
- if bit < shift:
456
- # Below shift: comes from previous result only
457
- if stage == 0:
458
- prev = f'pp.r0.c{bit}' if bit < 8 else '#0'
459
- else:
460
- prev = f'stage{stage-1}.bit{bit}.ha2.sum' if bit < 8 + stage else '#0'
461
- pp_bit = '#0'
462
- elif bit <= shift + 7:
463
- # In range of partial products
464
- if stage == 0:
465
- prev = f'pp.r0.c{bit}' if bit < 8 else '#0'
466
- else:
467
- prev = f'stage{stage-1}.bit{bit}.ha2.sum' if bit < 8 + stage else f'stage{stage-1}.bit{8+stage-1}.carry_or'
468
- pp_bit = f'pp.r{row_idx}.c{bit-shift}'
469
- else:
470
- # Above partial product range
471
- prev = f'stage{stage-1}.bit{bit-1}.carry_or' if stage > 0 else '#0'
472
- pp_bit = '#0'
473
-
474
- # Carry from previous bit
475
- if bit == 0:
476
- cin = '#0'
477
- else:
478
- cin = f'stage{stage}.bit{bit-1}.carry_or'
479
-
480
- # Full adder structure
481
- internal[f'{prefix}.ha1.sum.layer1.or'] = [prev, pp_bit]
482
- internal[f'{prefix}.ha1.sum.layer1.nand'] = [prev, pp_bit]
483
- internal[f'{prefix}.ha1.sum.layer2'] = [f'{prefix}.ha1.sum.layer1.or', f'{prefix}.ha1.sum.layer1.nand']
484
- internal[f'{prefix}.ha1.carry'] = [prev, pp_bit]
485
-
486
- internal[f'{prefix}.ha2.sum.layer1.or'] = [f'{prefix}.ha1.sum.layer2', cin]
487
- internal[f'{prefix}.ha2.sum.layer1.nand'] = [f'{prefix}.ha1.sum.layer2', cin]
488
- internal[f'{prefix}.ha2.sum.layer2'] = [f'{prefix}.ha2.sum.layer1.or', f'{prefix}.ha2.sum.layer1.nand']
489
- internal[f'{prefix}.ha2.carry'] = [f'{prefix}.ha1.sum.layer2', cin]
490
-
491
- internal[f'{prefix}.carry_or'] = [f'{prefix}.ha1.carry', f'{prefix}.ha2.carry']
492
-
493
- # Outputs: 16 bits
494
- outputs = {}
495
- for i in range(8):
496
- outputs[f'p[{i}]'] = f'pp.r0.c{i}' if i < 8 else f'stage6.bit{i}.ha2.sum.layer2'
497
- for i in range(8, 16):
498
- outputs[f'p[{i}]'] = f'stage6.bit{i}.ha2.sum.layer2' if i < 15 else 'stage6.bit14.carry_or'
499
-
500
- return {
501
- 'arithmetic.multiplier8x8': {
502
- 'inputs': ['$a[0:7]', '$b[0:7]'],
503
- 'type': 'multiplier',
504
- 'internal': internal,
505
- 'outputs': outputs
506
- }
507
- }
508
-
509
-
510
- def generate_div8bit_routing():
511
- """Generate routing for 8-bit restoring division."""
512
- internal = {}
513
-
514
- for stage in range(8):
515
- prefix = f'stage{stage}'
516
-
517
- # Previous remainder (from previous stage or initial 0)
518
- if stage == 0:
519
- prev_rem = ['#0'] * 8
520
- else:
521
- prev_rem = [f'stage{stage-1}.mux{i}' for i in range(8)]
522
-
523
- # Shift left and bring in dividend bit
524
- for bit in range(8):
525
- if bit < 7:
526
- internal[f'{prefix}.shift.bit{bit}'] = [prev_rem[bit + 1]]
527
- else:
528
- internal[f'{prefix}.shift.bit{bit}'] = [f'$dividend[{7-stage}]']
529
-
530
- # OR dividend bit into LSB
531
- internal[f'{prefix}.or_dividend'] = [f'{prefix}.shift.bit7', f'$dividend[{7-stage}]']
532
-
533
- # NOT divisor for subtraction
534
- for bit in range(8):
535
- internal[f'{prefix}.sub.notd{bit}'] = [f'$divisor[{bit}]']
536
-
537
- # Subtractor: 8 full adders
538
- for bit in range(8):
539
- fa_prefix = f'{prefix}.sub.fa{bit}'
540
- shifted = f'{prefix}.shift.bit{bit}'
541
- notd = f'{prefix}.sub.notd{bit}'
542
-
543
- if bit == 0:
544
- cin = '#1' # +1 for two's complement
545
- else:
546
- cin = f'{prefix}.sub.fa{bit-1}.or_carry'
547
-
548
- # XOR1: shifted ^ notd
549
- internal[f'{fa_prefix}.xor1.layer1.nand'] = [shifted, notd]
550
- internal[f'{fa_prefix}.xor1.layer1.or'] = [shifted, notd]
551
- internal[f'{fa_prefix}.xor1.layer2'] = [f'{fa_prefix}.xor1.layer1.nand', f'{fa_prefix}.xor1.layer1.or']
552
-
553
- # XOR2: xor1 ^ cin
554
- internal[f'{fa_prefix}.xor2.layer1.nand'] = [f'{fa_prefix}.xor1.layer2', cin]
555
- internal[f'{fa_prefix}.xor2.layer1.or'] = [f'{fa_prefix}.xor1.layer2', cin]
556
- internal[f'{fa_prefix}.xor2.layer2'] = [f'{fa_prefix}.xor2.layer1.nand', f'{fa_prefix}.xor2.layer1.or']
557
-
558
- # AND1, AND2, OR_carry
559
- internal[f'{fa_prefix}.and1'] = [shifted, notd]
560
- internal[f'{fa_prefix}.and2'] = [f'{fa_prefix}.xor1.layer2', cin]
561
- internal[f'{fa_prefix}.or_carry'] = [f'{fa_prefix}.and1', f'{fa_prefix}.and2']
562
-
563
- # Comparator: check if subtraction result >= 0 (carry out = 1 means no borrow)
564
- internal[f'{prefix}.cmp'] = [f'{prefix}.sub.fa7.or_carry']
565
-
566
- # MUX: select subtracted value if cmp=1, else keep original
567
- for bit in range(8):
568
- mux_prefix = f'{prefix}.mux{bit}'
569
- original = f'{prefix}.shift.bit{bit}'
570
- subtracted = f'{prefix}.sub.fa{bit}.xor2.layer2'
571
- sel = f'{prefix}.cmp'
572
-
573
- internal[f'{mux_prefix}.not_sel'] = [sel]
574
- internal[f'{mux_prefix}.and0'] = [original, f'{mux_prefix}.not_sel']
575
- internal[f'{mux_prefix}.and1'] = [subtracted, sel]
576
- internal[f'{mux_prefix}.or'] = [f'{mux_prefix}.and0', f'{mux_prefix}.and1']
577
-
578
- # Quotient outputs: cmp values from each stage
579
- for i in range(8):
580
- internal[f'quotient{i}'] = [f'stage{i}.cmp']
581
-
582
- # Remainder outputs: final mux values
583
- for i in range(8):
584
- internal[f'remainder{i}'] = [f'stage7.mux{i}.or']
585
-
586
- return {
587
- 'arithmetic.div8bit': {
588
- 'inputs': ['$dividend[0:7]', '$divisor[0:7]'],
589
- 'type': 'divider',
590
- 'internal': internal,
591
- 'outputs': {
592
- 'quotient': [f'quotient{i}' for i in range(8)],
593
- 'remainder': [f'remainder{i}' for i in range(8)]
594
- }
595
- }
596
- }
597
-
598
-
599
- def generate_adc_sbc_routing():
600
- """Generate routing for ADC and SBC circuits."""
601
- routing = {}
602
-
603
- # ADC: Add with Carry (8-bit)
604
- internal_adc = {}
605
- for i in range(8):
606
- fa_prefix = f'fa{i}'
607
- a_bit = f'$a[{i}]'
608
- b_bit = f'$b[{i}]'
609
- cin = '$cin' if i == 0 else f'fa{i-1}.or_carry'
610
-
611
- internal_adc[f'{fa_prefix}.xor1.layer1.nand'] = [a_bit, b_bit]
612
- internal_adc[f'{fa_prefix}.xor1.layer1.or'] = [a_bit, b_bit]
613
- internal_adc[f'{fa_prefix}.xor1.layer2'] = [f'{fa_prefix}.xor1.layer1.nand', f'{fa_prefix}.xor1.layer1.or']
614
-
615
- internal_adc[f'{fa_prefix}.xor2.layer1.nand'] = [f'{fa_prefix}.xor1.layer2', cin]
616
- internal_adc[f'{fa_prefix}.xor2.layer1.or'] = [f'{fa_prefix}.xor1.layer2', cin]
617
- internal_adc[f'{fa_prefix}.xor2.layer2'] = [f'{fa_prefix}.xor2.layer1.nand', f'{fa_prefix}.xor2.layer1.or']
618
-
619
- internal_adc[f'{fa_prefix}.and1'] = [a_bit, b_bit]
620
- internal_adc[f'{fa_prefix}.and2'] = [f'{fa_prefix}.xor1.layer2', cin]
621
- internal_adc[f'{fa_prefix}.or_carry'] = [f'{fa_prefix}.and1', f'{fa_prefix}.and2']
622
-
623
- routing['arithmetic.adc8bit'] = {
624
- 'inputs': ['$a[0:7]', '$b[0:7]', '$cin'],
625
- 'type': 'adder_with_carry',
626
- 'internal': internal_adc
627
- }
628
-
629
- # SBC: Subtract with Carry (A - B - borrow)
630
- internal_sbc = {}
631
- for i in range(8):
632
- internal_sbc[f'notb{i}'] = [f'$b[{i}]']
633
-
634
- for i in range(8):
635
- fa_prefix = f'fa{i}'
636
- a_bit = f'$a[{i}]'
637
- notb_bit = f'notb{i}'
638
- cin = '$cin' if i == 0 else f'fa{i-1}.or_carry'
639
-
640
- internal_sbc[f'{fa_prefix}.xor1.layer1.nand'] = [a_bit, notb_bit]
641
- internal_sbc[f'{fa_prefix}.xor1.layer1.or'] = [a_bit, notb_bit]
642
- internal_sbc[f'{fa_prefix}.xor1.layer2'] = [f'{fa_prefix}.xor1.layer1.nand', f'{fa_prefix}.xor1.layer1.or']
643
-
644
- internal_sbc[f'{fa_prefix}.xor2.layer1.nand'] = [f'{fa_prefix}.xor1.layer2', cin]
645
- internal_sbc[f'{fa_prefix}.xor2.layer1.or'] = [f'{fa_prefix}.xor1.layer2', cin]
646
- internal_sbc[f'{fa_prefix}.xor2.layer2'] = [f'{fa_prefix}.xor2.layer1.nand', f'{fa_prefix}.xor2.layer1.or']
647
-
648
- internal_sbc[f'{fa_prefix}.and1'] = [a_bit, notb_bit]
649
- internal_sbc[f'{fa_prefix}.and2'] = [f'{fa_prefix}.xor1.layer2', cin]
650
- internal_sbc[f'{fa_prefix}.or_carry'] = [f'{fa_prefix}.and1', f'{fa_prefix}.and2']
651
-
652
- routing['arithmetic.sbc8bit'] = {
653
- 'inputs': ['$a[0:7]', '$b[0:7]', '$cin'],
654
- 'type': 'subtractor_with_carry',
655
- 'internal': internal_sbc
656
- }
657
-
658
- # SUB: Subtract (A - B), carry_in forced to 1
659
- internal_sub = {'carry_in': ['#1']}
660
- for i in range(8):
661
- internal_sub[f'notb{i}'] = [f'$b[{i}]']
662
-
663
- for i in range(8):
664
- fa_prefix = f'fa{i}'
665
- a_bit = f'$a[{i}]'
666
- notb_bit = f'notb{i}'
667
- cin = 'carry_in' if i == 0 else f'fa{i-1}.or_carry'
668
-
669
- internal_sub[f'{fa_prefix}.xor1.layer1.nand'] = [a_bit, notb_bit]
670
- internal_sub[f'{fa_prefix}.xor1.layer1.or'] = [a_bit, notb_bit]
671
- internal_sub[f'{fa_prefix}.xor1.layer2'] = [f'{fa_prefix}.xor1.layer1.nand', f'{fa_prefix}.xor1.layer1.or']
672
-
673
- internal_sub[f'{fa_prefix}.xor2.layer1.nand'] = [f'{fa_prefix}.xor1.layer2', cin]
674
- internal_sub[f'{fa_prefix}.xor2.layer1.or'] = [f'{fa_prefix}.xor1.layer2', cin]
675
- internal_sub[f'{fa_prefix}.xor2.layer2'] = [f'{fa_prefix}.xor2.layer1.nand', f'{fa_prefix}.xor2.layer1.or']
676
-
677
- internal_sub[f'{fa_prefix}.and1'] = [a_bit, notb_bit]
678
- internal_sub[f'{fa_prefix}.and2'] = [f'{fa_prefix}.xor1.layer2', cin]
679
- internal_sub[f'{fa_prefix}.or_carry'] = [f'{fa_prefix}.and1', f'{fa_prefix}.and2']
680
-
681
- routing['arithmetic.sub8bit'] = {
682
- 'inputs': ['$a[0:7]', '$b[0:7]'],
683
- 'type': 'subtractor',
684
- 'internal': internal_sub
685
- }
686
-
687
- # CMP: Compare (like SUB but only sets flags)
688
- internal_cmp = {}
689
- for i in range(8):
690
- internal_cmp[f'notb{i}'] = [f'$b[{i}]']
691
-
692
- for i in range(8):
693
- fa_prefix = f'fa{i}'
694
- a_bit = f'$a[{i}]'
695
- notb_bit = f'notb{i}'
696
- cin = '#1' if i == 0 else f'fa{i-1}.or_carry'
697
-
698
- internal_cmp[f'{fa_prefix}.xor1.layer1.nand'] = [a_bit, notb_bit]
699
- internal_cmp[f'{fa_prefix}.xor1.layer1.or'] = [a_bit, notb_bit]
700
- internal_cmp[f'{fa_prefix}.xor1.layer2'] = [f'{fa_prefix}.xor1.layer1.nand', f'{fa_prefix}.xor1.layer1.or']
701
-
702
- internal_cmp[f'{fa_prefix}.xor2.layer1.nand'] = [f'{fa_prefix}.xor1.layer2', cin]
703
- internal_cmp[f'{fa_prefix}.xor2.layer1.or'] = [f'{fa_prefix}.xor1.layer2', cin]
704
- internal_cmp[f'{fa_prefix}.xor2.layer2'] = [f'{fa_prefix}.xor2.layer1.nand', f'{fa_prefix}.xor2.layer1.or']
705
-
706
- internal_cmp[f'{fa_prefix}.and1'] = [a_bit, notb_bit]
707
- internal_cmp[f'{fa_prefix}.and2'] = [f'{fa_prefix}.xor1.layer2', cin]
708
- internal_cmp[f'{fa_prefix}.or_carry'] = [f'{fa_prefix}.and1', f'{fa_prefix}.and2']
709
-
710
- # Flags
711
- internal_cmp['flags.zero_or'] = [f'fa{i}.xor2.layer2' for i in range(8)]
712
- internal_cmp['flags.zero'] = ['flags.zero_or']
713
- internal_cmp['flags.negative'] = ['fa7.xor2.layer2']
714
- internal_cmp['flags.carry'] = ['fa7.or_carry']
715
-
716
- routing['arithmetic.cmp8bit'] = {
717
- 'inputs': ['$a[0:7]', '$b[0:7]'],
718
- 'type': 'compare',
719
- 'internal': internal_cmp
720
- }
721
-
722
- return routing
723
-
724
-
725
- def generate_rotate_routing():
726
- """Generate routing for ROL and ROR circuits."""
727
- routing = {}
728
-
729
- # ROL: Rotate Left (bit 7 goes to carry, carry goes to bit 0)
730
- internal_rol = {}
731
- for i in range(8):
732
- if i == 0:
733
- internal_rol[f'bit{i}'] = ['$cin']
734
- else:
735
- internal_rol[f'bit{i}'] = [f'$x[{i-1}]']
736
- internal_rol['cout'] = ['$x[7]']
737
-
738
- routing['arithmetic.rol8bit'] = {
739
- 'inputs': ['$x[0:7]', '$cin'],
740
- 'type': 'rotate',
741
- 'internal': internal_rol
742
- }
743
-
744
- # ROR: Rotate Right (bit 0 goes to carry, carry goes to bit 7)
745
- internal_ror = {}
746
- for i in range(8):
747
- if i == 7:
748
- internal_ror[f'bit{i}'] = ['$cin']
749
- else:
750
- internal_ror[f'bit{i}'] = [f'$x[{i+1}]']
751
- internal_ror['cout'] = ['$x[0]']
752
-
753
- routing['arithmetic.ror8bit'] = {
754
- 'inputs': ['$x[0:7]', '$cin'],
755
- 'type': 'rotate',
756
- 'internal': internal_ror
757
- }
758
-
759
- return routing
760
-
761
-
762
- def generate_combinational_routing():
763
- """Generate routing for combinational circuits."""
764
- routing = {}
765
-
766
- # 3-to-8 Decoder
767
- internal_dec = {}
768
- for out in range(8):
769
- # out = sel[2]*4 + sel[1]*2 + sel[0]
770
- # Each output is AND of (possibly inverted) select lines
771
- internal_dec[f'out{out}'] = ['$sel[0]', '$sel[1]', '$sel[2]']
772
-
773
- routing['combinational.decoder3to8'] = {
774
- 'inputs': ['$sel[0:2]'],
775
- 'type': 'decoder',
776
- 'internal': internal_dec
777
- }
778
-
779
- # 8-to-3 Encoder
780
- internal_enc = {}
781
- for bit in range(3):
782
- internal_enc[f'bit{bit}'] = ['$x[0:7]']
783
-
784
- routing['combinational.encoder8to3'] = {
785
- 'inputs': ['$x[0:7]'],
786
- 'type': 'encoder',
787
- 'internal': internal_enc
788
- }
789
-
790
- # 2-to-1 MUX
791
- routing['combinational.multiplexer2to1'] = {
792
- 'inputs': ['$a', '$b', '$sel'],
793
- 'type': 'mux',
794
- 'internal': {
795
- 'not_s': ['$sel'],
796
- 'and0': ['$a', 'not_s'],
797
- 'and1': ['$b', '$sel'],
798
- 'or': ['and0', 'and1']
799
- },
800
- 'output': 'or'
801
- }
802
-
803
- # 4-to-1 MUX
804
- routing['combinational.multiplexer4to1'] = {
805
- 'inputs': ['$x[0:3]', '$sel[0:1]'],
806
- 'type': 'mux',
807
- 'internal': {'select': ['$x[0:3]', '$sel[0:1]']}
808
- }
809
-
810
- # 8-to-1 MUX
811
- routing['combinational.multiplexer8to1'] = {
812
- 'inputs': ['$x[0:7]', '$sel[0:2]'],
813
- 'type': 'mux',
814
- 'internal': {'select': ['$x[0:7]', '$sel[0:2]']}
815
- }
816
-
817
- # 1-to-2 DEMUX
818
- routing['combinational.demultiplexer1to2'] = {
819
- 'inputs': ['$x', '$sel'],
820
- 'type': 'demux',
821
- 'internal': {
822
- 'and0': ['$x', '$sel'], # sel inverted internally
823
- 'and1': ['$x', '$sel']
824
- }
825
- }
826
-
827
- # 1-to-4 DEMUX
828
- routing['combinational.demultiplexer1to4'] = {
829
- 'inputs': ['$x', '$sel[0:1]'],
830
- 'type': 'demux',
831
- 'internal': {'decode': ['$x', '$sel[0:1]']}
832
- }
833
-
834
- # 1-to-8 DEMUX
835
- routing['combinational.demultiplexer1to8'] = {
836
- 'inputs': ['$x', '$sel[0:2]'],
837
- 'type': 'demux',
838
- 'internal': {'decode': ['$x', '$sel[0:2]']}
839
- }
840
-
841
- # Barrel Shifter
842
- routing['combinational.barrelshifter8bit'] = {
843
- 'inputs': ['$x[0:7]', '$shift[0:2]'],
844
- 'type': 'barrel_shifter',
845
- 'internal': {'shift': ['$x[0:7]', '$shift[0:2]']}
846
- }
847
-
848
- # Priority Encoder
849
- routing['combinational.priorityencoder8bit'] = {
850
- 'inputs': ['$x[0:7]'],
851
- 'type': 'priority_encoder',
852
- 'internal': {'priority': ['$x[0:7]']}
853
- }
854
-
855
- # Register MUX 4-to-1 (8-bit wide)
856
- internal_regmux = {'not_s0': ['$sel[0]'], 'not_s1': ['$sel[1]']}
857
- for bit in range(8):
858
- for and_idx in range(4):
859
- sel0 = 'not_s0' if (and_idx & 1) == 0 else '$sel[0]'
860
- sel1 = 'not_s1' if (and_idx & 2) == 0 else '$sel[1]'
861
- internal_regmux[f'bit{bit}.and{and_idx}'] = [f'$r{and_idx}[{bit}]', sel0, sel1]
862
- internal_regmux[f'bit{bit}.or'] = [f'bit{bit}.and{i}' for i in range(4)]
863
-
864
- routing['combinational.regmux4to1'] = {
865
- 'inputs': ['$r0[0:7]', '$r1[0:7]', '$r2[0:7]', '$r3[0:7]', '$sel[0:1]'],
866
- 'type': 'register_mux',
867
- 'internal': internal_regmux
868
- }
869
-
870
- return routing
871
-
872
-
873
- def generate_control_routing():
874
- """Generate routing for control circuits."""
875
- routing = {}
876
-
877
- # Instruction Decoder (4-bit to 16 one-hot)
878
- internal_dec = {}
879
- for op in range(16):
880
- internal_dec[f'decode{op}'] = ['$opcode[0:3]']
881
- for op in range(4):
882
- internal_dec[f'not_op{op}'] = [f'$opcode[{op}]']
883
- internal_dec['is_alu'] = ['$opcode[0:3]']
884
- internal_dec['is_control'] = ['$opcode[0:3]']
885
-
886
- routing['control.decoder'] = {
887
- 'inputs': ['$opcode[0:3]'],
888
- 'type': 'instruction_decoder',
889
- 'internal': internal_dec
890
- }
891
-
892
- # Jump (unconditional)
893
- internal_jump = {}
894
- for bit in range(8):
895
- internal_jump[f'bit{bit}'] = [f'$target[{bit}]']
896
-
897
- routing['control.jump'] = {
898
- 'inputs': ['$target[0:7]'],
899
- 'type': 'jump',
900
- 'internal': internal_jump
901
- }
902
-
903
- # Conditional Jump (generic template)
904
- def make_cond_jump(name, flag):
905
- internal = {}
906
- for bit in range(8):
907
- internal[f'bit{bit}.not_sel'] = [f'${flag}']
908
- internal[f'bit{bit}.and_a'] = [f'$pc[{bit}]', f'bit{bit}.not_sel']
909
- internal[f'bit{bit}.and_b'] = [f'$target[{bit}]', f'${flag}']
910
- internal[f'bit{bit}.or'] = [f'bit{bit}.and_a', f'bit{bit}.and_b']
911
-
912
- routing[f'control.{name}'] = {
913
- 'inputs': ['$pc[0:7]', '$target[0:7]', f'${flag}'],
914
- 'type': 'conditional_jump',
915
- 'internal': internal
916
- }
917
-
918
- make_cond_jump('conditionaljump', 'cond')
919
- make_cond_jump('jc', 'carry')
920
- make_cond_jump('jn', 'negative')
921
- make_cond_jump('jz', 'zero')
922
- make_cond_jump('jv', 'overflow')
923
- make_cond_jump('jnc', 'not_carry')
924
- make_cond_jump('jnz', 'not_zero')
925
- make_cond_jump('jnv', 'not_overflow')
926
- make_cond_jump('jp', 'positive')
927
-
928
- # CALL and RET
929
- routing['control.call'] = {
930
- 'inputs': ['$target[0:7]'],
931
- 'type': 'call',
932
- 'internal': {'jump': ['$target[0:7]'], 'push': ['$pc[0:7]']}
933
- }
934
-
935
- routing['control.ret'] = {
936
- 'inputs': ['$stack_top[0:7]'],
937
- 'type': 'return',
938
- 'internal': {'jump': ['$stack_top[0:7]'], 'pop': ['#1']}
939
- }
940
-
941
- # PUSH and POP
942
- routing['control.push'] = {
943
- 'inputs': ['$value[0:7]', '$sp[0:7]'],
944
- 'type': 'push',
945
- 'internal': {'sp_dec': ['$sp[0:7]'], 'store': ['$value[0:7]']}
946
- }
947
-
948
- routing['control.pop'] = {
949
- 'inputs': ['$sp[0:7]'],
950
- 'type': 'pop',
951
- 'internal': {'load': ['$sp[0:7]'], 'sp_inc': ['$sp[0:7]']}
952
- }
953
-
954
- # SP increment/decrement
955
- routing['control.sp_dec'] = {'inputs': ['$sp[0:7]'], 'type': 'sp_dec', 'internal': {'uses': ['$sp[0:7]']}}
956
- routing['control.sp_inc'] = {'inputs': ['$sp[0:7]'], 'type': 'sp_inc', 'internal': {'uses': ['$sp[0:7]']}}
957
-
958
- # PC Increment
959
- internal_pc_inc = {'sum0': ['$pc[0]'], 'carry0': ['$pc[0]'], 'overflow': ['$pc[7]']}
960
- for bit in range(1, 8):
961
- prev_carry = f'carry{bit-1}' if bit > 1 else 'carry0'
962
- internal_pc_inc[f'xor{bit}.layer1.nand'] = [f'$pc[{bit}]', prev_carry]
963
- internal_pc_inc[f'xor{bit}.layer1.or'] = [f'$pc[{bit}]', prev_carry]
964
- internal_pc_inc[f'xor{bit}.layer2'] = [f'xor{bit}.layer1.nand', f'xor{bit}.layer1.or']
965
- internal_pc_inc[f'and{bit}'] = [f'$pc[{bit}]', prev_carry]
966
-
967
- routing['control.pc_inc'] = {
968
- 'inputs': ['$pc[0:7]'],
969
- 'type': 'pc_increment',
970
- 'internal': internal_pc_inc
971
- }
972
-
973
- # PC Load (mux between PC+1 and jump target)
974
- internal_pc_load = {'not_jump': ['$jump']}
975
- for bit in range(8):
976
- internal_pc_load[f'bit{bit}.and_pc'] = [f'$pc_inc[{bit}]', 'not_jump']
977
- internal_pc_load[f'bit{bit}.and_jump'] = [f'$target[{bit}]', '$jump']
978
- internal_pc_load[f'bit{bit}.or'] = [f'bit{bit}.and_pc', f'bit{bit}.and_jump']
979
-
980
- routing['control.pc_load'] = {
981
- 'inputs': ['$pc_inc[0:7]', '$target[0:7]', '$jump'],
982
- 'type': 'pc_load',
983
- 'internal': internal_pc_load
984
- }
985
-
986
- # HALT
987
- internal_halt = {'signal': ['$halt']}
988
- for flag in ['flag_c', 'flag_n', 'flag_v', 'flag_z']:
989
- internal_halt[flag] = [f'${flag}']
990
- for bit in range(8):
991
- internal_halt[f'pc.bit{bit}'] = [f'$pc[{bit}]']
992
- internal_halt[f'value.bit{bit}'] = [f'$value[{bit}]']
993
-
994
- routing['control.halt'] = {
995
- 'inputs': ['$halt', '$flag_c', '$flag_n', '$flag_v', '$flag_z', '$pc[0:7]', '$value[0:7]'],
996
- 'type': 'halt',
997
- 'internal': internal_halt
998
- }
999
-
1000
- # NOP
1001
- internal_nop = {'output': ['#1']}
1002
- for bit in range(8):
1003
- internal_nop[f'bit{bit}'] = [f'$x[{bit}]']
1004
- for flag in ['flag_c', 'flag_n', 'flag_v', 'flag_z']:
1005
- internal_nop[flag] = [f'${flag}']
1006
-
1007
- routing['control.nop'] = {
1008
- 'inputs': ['$x[0:7]', '$flag_c', '$flag_n', '$flag_v', '$flag_z'],
1009
- 'type': 'nop',
1010
- 'internal': internal_nop
1011
- }
1012
-
1013
- return routing
1014
-
1015
-
1016
- def generate_error_detection_routing():
1017
- """Generate routing for error detection circuits."""
1018
- routing = {}
1019
-
1020
- # Even Parity Checker
1021
- routing['error_detection.evenparitychecker'] = {
1022
- 'inputs': ['$x[0:7]'],
1023
- 'type': 'parity',
1024
- 'internal': {'': ['$x[0:7]']}
1025
- }
1026
-
1027
- # Odd Parity Checker
1028
- routing['error_detection.oddparitychecker'] = {
1029
- 'inputs': ['$x[0:7]'],
1030
- 'type': 'parity',
1031
- 'internal': {
1032
- 'parity': ['$x[0:7]'],
1033
- 'not': ['parity']
1034
- }
1035
- }
1036
-
1037
- # Checksum
1038
- routing['error_detection.checksum8bit'] = {
1039
- 'inputs': ['$x[0:7]'],
1040
- 'type': 'checksum',
1041
- 'internal': {'sum': ['$x[0:7]']}
1042
- }
1043
-
1044
- # CRC
1045
- routing['error_detection.crc4'] = {
1046
- 'inputs': ['$data[0:7]'],
1047
- 'type': 'crc',
1048
- 'internal': {'divisor': ['#1', '#0', '#0', '#1', '#1']}
1049
- }
1050
-
1051
- routing['error_detection.crc8'] = {
1052
- 'inputs': ['$data[0:7]'],
1053
- 'type': 'crc',
1054
- 'internal': {'divisor': ['#1', '#0', '#0', '#0', '#0', '#0', '#1', '#1', '#1']}
1055
- }
1056
-
1057
- # Hamming Encode (4 data bits -> 7 code bits)
1058
- routing['error_detection.hammingencode4bit'] = {
1059
- 'inputs': ['$d[0:3]'],
1060
- 'type': 'hamming_encode',
1061
- 'internal': {
1062
- 'p0': ['$d[0:3]'],
1063
- 'p1': ['$d[0:3]'],
1064
- 'p2': ['$d[0:3]'],
1065
- 'p3': ['$d[0:3]']
1066
- }
1067
- }
1068
-
1069
- # Hamming Decode (7 code bits -> syndrome)
1070
- routing['error_detection.hammingdecode7bit'] = {
1071
- 'inputs': ['$c[0:6]'],
1072
- 'type': 'hamming_decode',
1073
- 'internal': {
1074
- 's1': ['$c[0:6]'],
1075
- 's2': ['$c[0:6]'],
1076
- 's3': ['$c[0:6]']
1077
- }
1078
- }
1079
-
1080
- # Hamming Syndrome
1081
- routing['error_detection.hammingsyndrome'] = {
1082
- 'inputs': ['$c[0:6]'],
1083
- 'type': 'hamming_syndrome',
1084
- 'internal': {
1085
- 's1': ['$c[0:6]'],
1086
- 's2': ['$c[0:6]'],
1087
- 's3': ['$c[0:6]']
1088
- }
1089
- }
1090
-
1091
- # Longitudinal Parity
1092
- routing['error_detection.longitudinalparity'] = {
1093
- 'inputs': ['$data'],
1094
- 'type': 'longitudinal_parity',
1095
- 'internal': {
1096
- 'col_parity': ['$data'],
1097
- 'row_parity': ['$data']
1098
- }
1099
- }
1100
-
1101
- # Parity Checker (3-stage XOR tree)
1102
- internal_parity_check = {}
1103
- for stage in range(1, 4):
1104
- num_xors = 4 if stage == 1 else (2 if stage == 2 else 1)
1105
- for i in range(num_xors):
1106
- prefix = f'stage{stage}.xor{i}'
1107
- internal_parity_check[f'{prefix}.layer1.nand'] = [f'$stage{stage}_in[{2*i}]', f'$stage{stage}_in[{2*i+1}]']
1108
- internal_parity_check[f'{prefix}.layer1.or'] = [f'$stage{stage}_in[{2*i}]', f'$stage{stage}_in[{2*i+1}]']
1109
- internal_parity_check[f'{prefix}.layer2'] = [f'{prefix}.layer1.nand', f'{prefix}.layer1.or']
1110
- internal_parity_check['output.not'] = ['stage3.xor0.layer2']
1111
-
1112
- routing['error_detection.paritychecker8bit'] = {
1113
- 'inputs': ['$x[0:7]'],
1114
- 'type': 'parity_tree',
1115
- 'internal': internal_parity_check
1116
- }
1117
-
1118
- # Parity Generator (same structure as checker)
1119
- routing['error_detection.paritygenerator8bit'] = {
1120
- 'inputs': ['$x[0:7]'],
1121
- 'type': 'parity_tree',
1122
- 'internal': internal_parity_check.copy()
1123
- }
1124
-
1125
- return routing
1126
-
1127
-
1128
- def generate_alu_routing():
1129
- """Generate routing for ALU circuits."""
1130
- routing = {}
1131
-
1132
- # ALU Control (opcode to operation select)
1133
- internal_ctrl = {}
1134
- for op in range(16):
1135
- internal_ctrl[f'op{op}'] = ['$opcode[0:3]']
1136
-
1137
- routing['alu.alucontrol'] = {
1138
- 'inputs': ['$opcode[0:3]'],
1139
- 'type': 'alu_control',
1140
- 'internal': internal_ctrl
1141
- }
1142
-
1143
- # ALU Flags
1144
- routing['alu.aluflags'] = {
1145
- 'inputs': ['$result[0:7]', '$carry', '$overflow'],
1146
- 'type': 'alu_flags',
1147
- 'internal': {
1148
- 'zero': ['$result[0:7]'],
1149
- 'negative': ['$result[7]'],
1150
- 'carry': ['$carry'],
1151
- 'overflow': ['$overflow']
1152
- }
1153
- }
1154
-
1155
- # ALU 8-bit operations
1156
- routing['alu.alu8bit.and'] = {
1157
- 'inputs': ['$a[0:7]', '$b[0:7]'],
1158
- 'type': 'bitwise_and',
1159
- 'internal': {f'bit{i}': [f'$a[{i}]', f'$b[{i}]'] for i in range(8)}
1160
- }
1161
-
1162
- routing['alu.alu8bit.or'] = {
1163
- 'inputs': ['$a[0:7]', '$b[0:7]'],
1164
- 'type': 'bitwise_or',
1165
- 'internal': {f'bit{i}': [f'$a[{i}]', f'$b[{i}]'] for i in range(8)}
1166
- }
1167
-
1168
- routing['alu.alu8bit.not'] = {
1169
- 'inputs': ['$a[0:7]'],
1170
- 'type': 'bitwise_not',
1171
- 'internal': {f'bit{i}': [f'$a[{i}]'] for i in range(8)}
1172
- }
1173
-
1174
- # XOR with two-layer structure
1175
- internal_xor = {}
1176
- for i in range(8):
1177
- internal_xor[f'layer1.nand.bit{i}'] = [f'$a[{i}]', f'$b[{i}]']
1178
- internal_xor[f'layer1.or.bit{i}'] = [f'$a[{i}]', f'$b[{i}]']
1179
- internal_xor[f'layer2.bit{i}'] = [f'layer1.nand.bit{i}', f'layer1.or.bit{i}']
1180
-
1181
- routing['alu.alu8bit.xor'] = {
1182
- 'inputs': ['$a[0:7]', '$b[0:7]'],
1183
- 'type': 'bitwise_xor',
1184
- 'internal': internal_xor
1185
- }
1186
-
1187
- # Shifts
1188
- routing['alu.alu8bit.shl'] = {
1189
- 'inputs': ['$a[0:7]'],
1190
- 'type': 'shift_left',
1191
- 'internal': {'': ['$a[0:7]']}
1192
- }
1193
-
1194
- routing['alu.alu8bit.shr'] = {
1195
- 'inputs': ['$a[0:7]'],
1196
- 'type': 'shift_right',
1197
- 'internal': {'': ['$a[0:7]']}
1198
- }
1199
-
1200
- # ADD (references ripple carry)
1201
- routing['alu.alu8bit.add'] = {
1202
- 'inputs': ['$a[0:7]', '$b[0:7]'],
1203
- 'type': 'add',
1204
- 'internal': {'': ['$a[0:7]', '$b[0:7]']}
1205
- }
1206
-
1207
- # Output MUX
1208
- routing['alu.alu8bit.output_mux'] = {
1209
- 'inputs': ['$results[0:15]', '$opcode[0:3]'],
1210
- 'type': 'output_mux',
1211
- 'internal': {'': ['$results[0:15]', '$opcode[0:3]']}
1212
- }
1213
-
1214
- return routing
1215
-
1216
-
1217
- def generate_div8bit_routing():
1218
- """Generate routing for 8-bit restoring division circuit."""
1219
- internal = {}
1220
-
1221
- for stage in range(8):
1222
- prefix = f'stage{stage}'
1223
-
1224
- # Previous stage remainder (or 0 for stage 0)
1225
- if stage == 0:
1226
- prev_rem = ['#0'] * 8
1227
- else:
1228
- prev_rem = [f'stage{stage-1}.mux{i}.or' for i in range(8)]
1229
-
1230
- # Dividend bit for this stage (MSB first)
1231
- dividend_bit = f'$dividend[{7-stage}]'
1232
-
1233
- # Shift: shift remainder left, bring in dividend bit at LSB
1234
- for bit in range(8):
1235
- if bit == 0:
1236
- internal[f'{prefix}.shift.bit{bit}'] = [dividend_bit]
1237
- else:
1238
- internal[f'{prefix}.shift.bit{bit}'] = [prev_rem[bit - 1] if stage > 0 else '#0']
1239
-
1240
- shifted = [f'{prefix}.shift.bit{i}' for i in range(8)]
1241
-
1242
- # NOT divisor for two's complement subtraction
1243
- for bit in range(8):
1244
- internal[f'{prefix}.sub.notd{bit}'] = [f'$divisor[{bit}]']
1245
-
1246
- not_divisor = [f'{prefix}.sub.notd{i}' for i in range(8)]
1247
-
1248
- # Subtractor: 8 full adders computing shifted - divisor (LSB to MSB)
1249
- carry = '#1' # +1 for two's complement
1250
- for bit in range(8): # LSB (bit 0) to MSB (bit 7)
1251
- fa_prefix = f'{prefix}.sub.fa{bit}'
1252
- a = shifted[bit]
1253
- b = not_divisor[bit]
1254
-
1255
- internal[f'{fa_prefix}.xor1.layer1.or'] = [a, b]
1256
- internal[f'{fa_prefix}.xor1.layer1.nand'] = [a, b]
1257
- internal[f'{fa_prefix}.xor1.layer2'] = [f'{fa_prefix}.xor1.layer1.or', f'{fa_prefix}.xor1.layer1.nand']
1258
-
1259
- internal[f'{fa_prefix}.xor2.layer1.or'] = [f'{fa_prefix}.xor1.layer2', carry]
1260
- internal[f'{fa_prefix}.xor2.layer1.nand'] = [f'{fa_prefix}.xor1.layer2', carry]
1261
- internal[f'{fa_prefix}.xor2.layer2'] = [f'{fa_prefix}.xor2.layer1.or', f'{fa_prefix}.xor2.layer1.nand']
1262
-
1263
- internal[f'{fa_prefix}.and1'] = [a, b]
1264
- internal[f'{fa_prefix}.and2'] = [f'{fa_prefix}.xor1.layer2', carry]
1265
- internal[f'{fa_prefix}.or_carry'] = [f'{fa_prefix}.and1', f'{fa_prefix}.and2']
1266
-
1267
- carry = f'{fa_prefix}.or_carry'
1268
-
1269
- sub_result = [f'{prefix}.sub.fa{i}.xor2.layer2' for i in range(8)]
1270
-
1271
- # Comparator: carry out from MSB (fa7) = 1 means no borrow (shifted >= divisor)
1272
- internal[f'{prefix}.cmp'] = [f'{prefix}.sub.fa7.or_carry']
1273
-
1274
- cmp_out = f'{prefix}.cmp'
1275
-
1276
- # OR dividend (combine shifted LSB with dividend bit)
1277
- internal[f'{prefix}.or_dividend'] = [shifted[7], dividend_bit]
1278
-
1279
- # MUX: select sub_result if cmp=1 (no borrow), else shifted
1280
- for bit in range(8):
1281
- mux_prefix = f'{prefix}.mux{bit}'
1282
- internal[f'{mux_prefix}.not_sel'] = [cmp_out]
1283
- internal[f'{mux_prefix}.and0'] = [shifted[bit], f'{mux_prefix}.not_sel']
1284
- internal[f'{mux_prefix}.and1'] = [sub_result[bit], cmp_out]
1285
- internal[f'{mux_prefix}.or'] = [f'{mux_prefix}.and0', f'{mux_prefix}.and1']
1286
-
1287
- # Output quotient bits (cmp outputs from each stage)
1288
- for i in range(8):
1289
- internal[f'quotient{i}'] = [f'stage{i}.cmp']
1290
-
1291
- # Output remainder bits (final mux outputs)
1292
- for i in range(8):
1293
- internal[f'remainder{i}'] = [f'stage7.mux{i}.or']
1294
-
1295
- outputs = {f'quotient[{i}]': f'quotient{i}' for i in range(8)}
1296
- outputs.update({f'remainder[{i}]': f'remainder{i}' for i in range(8)})
1297
-
1298
- return {
1299
- 'arithmetic.div8bit': {
1300
- 'inputs': ['$dividend[0:7]', '$divisor[0:7]'],
1301
- 'type': 'restoring_division',
1302
- 'internal': internal,
1303
- 'outputs': outputs
1304
- }
1305
- }
1306
-
1307
-
1308
- def main():
1309
- routing = {
1310
- 'version': 1,
1311
- 'description': 'Routing information for 8-bit threshold computer',
1312
- 'circuits': {}
1313
- }
1314
-
1315
- # Generate routing for each category
1316
- print('Generating routing...')
1317
-
1318
- print(' Boolean gates')
1319
- routing['circuits'].update(generate_boolean_routing())
1320
-
1321
- print(' Half adder')
1322
- routing['circuits'].update(generate_arithmetic_halfadder_routing())
1323
-
1324
- print(' Full adder')
1325
- routing['circuits'].update(generate_arithmetic_fulladder_routing())
1326
-
1327
- print(' Ripple carry adders')
1328
- routing['circuits'].update(generate_ripplecarry_routing(2))
1329
- routing['circuits'].update(generate_ripplecarry_routing(4))
1330
- routing['circuits'].update(generate_ripplecarry_routing(8))
1331
-
1332
- print(' Comparators')
1333
- routing['circuits'].update(generate_comparator_routing())
1334
-
1335
- print(' Equality')
1336
- routing['circuits'].update(generate_equality_routing())
1337
-
1338
- print(' Negation')
1339
- routing['circuits'].update(generate_neg8bit_routing())
1340
-
1341
- print(' 2x2 Multiplier')
1342
- routing['circuits'].update(generate_multiplier2x2_routing())
1343
-
1344
- print(' 8-bit Division')
1345
- routing['circuits'].update(generate_div8bit_routing())
1346
-
1347
- print(' Threshold gates')
1348
- routing['circuits'].update(generate_threshold_routing())
1349
-
1350
- print(' Modular arithmetic')
1351
- routing['circuits'].update(generate_modular_routing())
1352
-
1353
- print(' Pattern recognition')
1354
- routing['circuits'].update(generate_pattern_routing())
1355
-
1356
- print(' Manifest')
1357
- routing['circuits'].update(generate_manifest_routing())
1358
-
1359
- # Save to file
1360
- with open('routing.json', 'w') as f:
1361
- json.dump(routing, f, indent=2)
1362
-
1363
- print(f'\nGenerated routing for {len(routing["circuits"])} circuits')
1364
- print('Saved to routing.json')
1365
-
1366
- # Show what's missing
1367
- all_gates = get_all_gates('neural_computer.safetensors')
1368
- covered = set()
1369
- for circuit_path in routing['circuits'].keys():
1370
- # Add the circuit itself and all internal gates
1371
- covered.add(circuit_path)
1372
- circuit = routing['circuits'][circuit_path]
1373
- if 'internal' in circuit:
1374
- for gate in circuit['internal'].keys():
1375
- if gate:
1376
- covered.add(f'{circuit_path}.{gate}')
1377
-
1378
- missing = [g for g in all_gates if not any(g.startswith(c) for c in routing['circuits'].keys())]
1379
- if missing:
1380
- print(f'\nMissing circuits ({len(missing)}):')
1381
- # Group by category
1382
- by_cat = defaultdict(list)
1383
- for g in missing:
1384
- cat = g.split('.')[0]
1385
- by_cat[cat].append(g)
1386
- for cat in sorted(by_cat.keys()):
1387
- print(f' {cat}: {len(by_cat[cat])} gates')
1388
- for g in by_cat[cat][:5]:
1389
- print(f' - {g}')
1390
- if len(by_cat[cat]) > 5:
1391
- print(f' ... and {len(by_cat[cat])-5} more')
1392
-
1393
-
1394
- if __name__ == '__main__':
1395
- main()