phanerozoic commited on
Commit
44df4b9
·
verified ·
1 Parent(s): 1daea9b

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -35,3 +35,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  __pycache__/iron_eval.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
37
  __pycache__/iron_eval.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  __pycache__/iron_eval.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
37
  __pycache__/iron_eval.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
38
+ eval/__pycache__/comprehensive_eval.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
eval/__pycache__/comprehensive_eval.cpython-312.pyc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8ccad37bd62a22e29a842384c0ed5a23cadfde2f662aa979bd946c67f8385b01
3
+ size 165009
eval/comprehensive_eval.py CHANGED
The diff for this file is too large to render. See raw diff
 
generate_routing.py ADDED
@@ -0,0 +1,1395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
routing.json ADDED
The diff for this file is too large to render. See raw diff
 
routing_schema.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Routing Schema for 8-bit Threshold Computer
2
+
3
+ ## Overview
4
+
5
+ The routing file (`routing.json`) defines how gates are interconnected. Each entry maps a gate path to its input sources.
6
+
7
+ ## Schema Format
8
+
9
+ ```json
10
+ {
11
+ "version": 1,
12
+ "external_inputs": {
13
+ "circuit_path": ["input_name", ...]
14
+ },
15
+ "routing": {
16
+ "gate_path": ["source1", "source2", ...]
17
+ }
18
+ }
19
+ ```
20
+
21
+ ## Input Source Types
22
+
23
+ 1. **External input**: `"$input_name"` - Named input to the circuit
24
+ - Example: `"$a"`, `"$b"`, `"$cin"`
25
+
26
+ 2. **Gate output**: `"path.to.gate"` - Output of another gate
27
+ - Example: `"ha1.sum"`, `"layer1.or"`
28
+
29
+ 3. **Bit extraction**: `"$input[i]"` - Single bit from multi-bit input
30
+ - Example: `"$a[0]"` (LSB), `"$a[7]"` (MSB for 8-bit)
31
+
32
+ 4. **Constant**: `"#0"` or `"#1"` - Fixed value
33
+ - Example: `"#1"` for carry-in in two's complement
34
+
35
+ 5. **Relative reference**: `"../sibling.gate"` - Reference to sibling in hierarchy
36
+ - Example: `"../fa0.cout"` from fa1
37
+
38
+ ## Circuit Types
39
+
40
+ ### Single-Layer Gates
41
+ Gates with just `.weight` and `.bias`:
42
+ ```json
43
+ "boolean.and": ["$a", "$b"]
44
+ ```
45
+
46
+ ### Two-Layer Gates (XOR, XNOR)
47
+ Gates decomposed into layer1 + layer2:
48
+ ```json
49
+ "boolean.xor.layer1.or": ["$a", "$b"],
50
+ "boolean.xor.layer1.nand": ["$a", "$b"],
51
+ "boolean.xor.layer2": ["layer1.or", "layer1.nand"]
52
+ ```
53
+
54
+ ### Hierarchical Circuits
55
+ Complex circuits with sub-components:
56
+ ```json
57
+ "arithmetic.fulladder": {
58
+ "external_inputs": ["$a", "$b", "$cin"],
59
+ "gates": {
60
+ "ha1.sum.layer1.or": ["$a", "$b"],
61
+ "ha1.sum.layer1.nand": ["$a", "$b"],
62
+ "ha1.sum.layer2": ["ha1.sum.layer1.or", "ha1.sum.layer1.nand"],
63
+ "ha1.carry": ["$a", "$b"],
64
+ "ha2.sum.layer1.or": ["ha1.sum", "$cin"],
65
+ "ha2.sum.layer1.nand": ["ha1.sum", "$cin"],
66
+ "ha2.sum.layer2": ["ha2.sum.layer1.or", "ha2.sum.layer1.nand"],
67
+ "ha2.carry": ["ha1.sum", "$cin"],
68
+ "carry_or": ["ha1.carry", "ha2.carry"]
69
+ },
70
+ "outputs": {
71
+ "sum": "ha2.sum",
72
+ "cout": "carry_or"
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### Bit-Indexed Circuits
78
+ Circuits operating on multi-bit values:
79
+ ```json
80
+ "arithmetic.ripplecarry8bit": {
81
+ "external_inputs": ["$a[0:7]", "$b[0:7]"],
82
+ "gates": {
83
+ "fa0": {"inputs": ["$a[0]", "$b[0]", "#0"], "type": "fulladder"},
84
+ "fa1": {"inputs": ["$a[1]", "$b[1]", "fa0.cout"], "type": "fulladder"},
85
+ ...
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## Naming Conventions
91
+
92
+ - External inputs: `$name` or `$name[bit]`
93
+ - Constants: `#0`, `#1`
94
+ - Internal gates: relative path from circuit root
95
+ - Outputs: named in `outputs` section
96
+
97
+ ## Validation Rules
98
+
99
+ 1. Every gate in routing must exist in tensors file
100
+ 2. Every tensor must have routing entry
101
+ 3. Input count must match weight dimensions
102
+ 4. No circular dependencies (DAG only)
103
+ 5. All referenced sources must exist