Add memory circuits and CPU state layout
Browse files- README.md +48 -14
- cpu/__pycache__/cycle.cpython-311.pyc +0 -0
- cpu/__pycache__/state.cpython-311.pyc +0 -0
- cpu/cycle.py +137 -0
- cpu/state.py +103 -0
- eval/build_memory.py +107 -0
- eval/comprehensive_eval.py +185 -25
- eval/cpu_cycle_test.py +56 -0
- eval/iron_eval.py +11 -11
- llm/guide.md +3 -3
- neural_computer.safetensors +2 -2
- routing.json +0 -0
- routing/generate_routing.py +141 -36
- routing/routing_schema.md +5 -2
- tensors.txt +0 -0
- todo.md +1 -1
README.md
CHANGED
|
@@ -17,8 +17,8 @@ tags:
|
|
| 17 |
Every logic gate is a threshold neuron: `output = 1 if (Σ wᵢxᵢ + b) ≥ 0 else 0`
|
| 18 |
|
| 19 |
```
|
| 20 |
-
Tensors:
|
| 21 |
-
Parameters:
|
| 22 |
```
|
| 23 |
|
| 24 |
---
|
|
@@ -85,15 +85,16 @@ The weights in this repository implement a complete 8-bit computer: registers, A
|
|
| 85 |
| Arithmetic | 18 | Half/full adder, 2/4/8-bit ripple carry, comparators |
|
| 86 |
| ALU | 3 | 8-bit ALU, control decoder, flag computation |
|
| 87 |
| Combinational | 10 | MUX (2:1, 4:1, 8:1), DEMUX, encoders, decoders |
|
| 88 |
-
| Control Flow | 16 | JMP, conditional jumps, CALL, RET, PUSH, POP |
|
| 89 |
-
| Error Detection | 11 | Parity (XOR tree), checksum, CRC, Hamming |
|
| 90 |
-
| Modular | 11 | Divisibility by 2-12 (multi-layer for non-powers-of-2) |
|
| 91 |
-
| Threshold | 13 | k-of-n gates, majority, minority, exactly-k |
|
| 92 |
-
| Pattern | 10 | Popcount, leading/trailing ones, symmetry |
|
|
|
|
| 93 |
|
| 94 |
---
|
| 95 |
|
| 96 |
-
## Usage
|
| 97 |
|
| 98 |
```python
|
| 99 |
import torch
|
|
@@ -112,11 +113,44 @@ for a, b_in in [(0,0), (0,1), (1,0), (1,1)]:
|
|
| 112 |
inp = torch.tensor([a, b_in], dtype=torch.float32)
|
| 113 |
out = heaviside(inp @ w + b)
|
| 114 |
print(f"AND({a}, {b_in}) = {int(out.item())}")
|
| 115 |
-
```
|
| 116 |
-
|
| 117 |
-
---
|
| 118 |
-
|
| 119 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
|
| 121 |
The model includes `iron_eval.py` which exhaustively tests all circuits:
|
| 122 |
|
|
@@ -175,7 +209,7 @@ All weights are integers. All activations are Heaviside step. Designed for:
|
|
| 175 |
|
| 176 |
| File | Description |
|
| 177 |
|------|-------------|
|
| 178 |
-
| `neural_computer.safetensors` |
|
| 179 |
| `iron_eval.py` | Comprehensive test suite |
|
| 180 |
| `prune_weights.py` | Weight optimization tool |
|
| 181 |
|
|
|
|
| 17 |
Every logic gate is a threshold neuron: `output = 1 if (Σ wᵢxᵢ + b) ≥ 0 else 0`
|
| 18 |
|
| 19 |
```
|
| 20 |
+
Tensors: 24,200
|
| 21 |
+
Parameters: 40,323
|
| 22 |
```
|
| 23 |
|
| 24 |
---
|
|
|
|
| 85 |
| Arithmetic | 18 | Half/full adder, 2/4/8-bit ripple carry, comparators |
|
| 86 |
| ALU | 3 | 8-bit ALU, control decoder, flag computation |
|
| 87 |
| Combinational | 10 | MUX (2:1, 4:1, 8:1), DEMUX, encoders, decoders |
|
| 88 |
+
| Control Flow | 16 | JMP, conditional jumps, CALL, RET, PUSH, POP |
|
| 89 |
+
| Error Detection | 11 | Parity (XOR tree), checksum, CRC, Hamming |
|
| 90 |
+
| Modular | 11 | Divisibility by 2-12 (multi-layer for non-powers-of-2) |
|
| 91 |
+
| Threshold | 13 | k-of-n gates, majority, minority, exactly-k |
|
| 92 |
+
| Pattern | 10 | Popcount, leading/trailing ones, symmetry |
|
| 93 |
+
| Memory | 3 | 8-bit addr decoder, 256x8 read mux, write cell update |
|
| 94 |
|
| 95 |
---
|
| 96 |
|
| 97 |
+
## Usage
|
| 98 |
|
| 99 |
```python
|
| 100 |
import torch
|
|
|
|
| 113 |
inp = torch.tensor([a, b_in], dtype=torch.float32)
|
| 114 |
out = heaviside(inp @ w + b)
|
| 115 |
print(f"AND({a}, {b_in}) = {int(out.item())}")
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
---
|
| 119 |
+
|
| 120 |
+
## State Tensor Layout
|
| 121 |
+
|
| 122 |
+
All multi-bit fields are **MSB-first** (index 0 is the most-significant bit).
|
| 123 |
+
|
| 124 |
+
```
|
| 125 |
+
[ PC[8] | IR[16] | R0[8] R1[8] R2[8] R3[8] | FLAGS[4] | SP[8] | CTRL[4] | MEM[256][8] ]
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
Flags are ordered as: `Z, N, C, V`.
|
| 129 |
+
|
| 130 |
+
Control bits are ordered as: `HALT, MEM_WE, MEM_RE, RESERVED`.
|
| 131 |
+
|
| 132 |
+
Total state size: `2120` bits.
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
## Instruction Encoding (16-bit)
|
| 137 |
+
|
| 138 |
+
All instruction bits are **MSB-first**.
|
| 139 |
+
|
| 140 |
+
```
|
| 141 |
+
15..12 11..10 9..8 7..0
|
| 142 |
+
opcode rd rs imm8
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
Interpretation:
|
| 146 |
+
- **R-type**: `rd = rd op rs` (imm8 ignored).
|
| 147 |
+
- **I-type**: `rd = op rd, imm8` (rs ignored).
|
| 148 |
+
- **Jumps/Calls**: `imm8` is the absolute target address.
|
| 149 |
+
- **LOAD/STORE**: `imm8` is the absolute memory address.
|
| 150 |
+
|
| 151 |
+
---
|
| 152 |
+
|
| 153 |
+
## Verification
|
| 154 |
|
| 155 |
The model includes `iron_eval.py` which exhaustively tests all circuits:
|
| 156 |
|
|
|
|
| 209 |
|
| 210 |
| File | Description |
|
| 211 |
|------|-------------|
|
| 212 |
+
| `neural_computer.safetensors` | 24,200 tensors, 40,323 parameters |
|
| 213 |
| `iron_eval.py` | Comprehensive test suite |
|
| 214 |
| `prune_weights.py` | Weight optimization tool |
|
| 215 |
|
cpu/__pycache__/cycle.cpython-311.pyc
ADDED
|
Binary file (5.07 kB). View file
|
|
|
cpu/__pycache__/state.cpython-311.pyc
ADDED
|
Binary file (6.99 kB). View file
|
|
|
cpu/cycle.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Reference CPU cycle (software) for the threshold computer.
|
| 3 |
+
Implements fetch/decode/execute over the state layout.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
|
| 8 |
+
from typing import Tuple
|
| 9 |
+
|
| 10 |
+
from .state import CPUState
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def decode_ir(ir: int) -> Tuple[int, int, int, int]:
|
| 14 |
+
opcode = (ir >> 12) & 0xF
|
| 15 |
+
rd = (ir >> 10) & 0x3
|
| 16 |
+
rs = (ir >> 8) & 0x3
|
| 17 |
+
imm8 = ir & 0xFF
|
| 18 |
+
return opcode, rd, rs, imm8
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def _flags_from_result(result: int, carry: int, overflow: int) -> Tuple[int, int, int, int]:
|
| 22 |
+
z = 1 if result == 0 else 0
|
| 23 |
+
n = 1 if (result & 0x80) else 0
|
| 24 |
+
c = 1 if carry else 0
|
| 25 |
+
v = 1 if overflow else 0
|
| 26 |
+
return z, n, c, v
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _alu_add(a: int, b: int) -> Tuple[int, int, int]:
|
| 30 |
+
full = a + b
|
| 31 |
+
result = full & 0xFF
|
| 32 |
+
carry = 1 if full > 0xFF else 0
|
| 33 |
+
overflow = 1 if (((a ^ result) & (b ^ result)) & 0x80) else 0
|
| 34 |
+
return result, carry, overflow
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _alu_sub(a: int, b: int) -> Tuple[int, int, int]:
|
| 38 |
+
full = (a - b) & 0x1FF
|
| 39 |
+
result = full & 0xFF
|
| 40 |
+
carry = 1 if a >= b else 0
|
| 41 |
+
overflow = 1 if (((a ^ b) & (a ^ result)) & 0x80) else 0
|
| 42 |
+
return result, carry, overflow
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def step(state: CPUState) -> CPUState:
|
| 46 |
+
if state.ctrl[0] == 1: # HALT
|
| 47 |
+
return state.copy()
|
| 48 |
+
|
| 49 |
+
s = state.copy()
|
| 50 |
+
|
| 51 |
+
# Fetch: two bytes, big-endian
|
| 52 |
+
hi = s.mem[s.pc]
|
| 53 |
+
lo = s.mem[(s.pc + 1) & 0xFF]
|
| 54 |
+
s.ir = ((hi & 0xFF) << 8) | (lo & 0xFF)
|
| 55 |
+
next_pc = (s.pc + 2) & 0xFF
|
| 56 |
+
|
| 57 |
+
opcode, rd, rs, imm8 = decode_ir(s.ir)
|
| 58 |
+
a = s.regs[rd]
|
| 59 |
+
b = s.regs[rs]
|
| 60 |
+
|
| 61 |
+
write_result = True
|
| 62 |
+
result = a
|
| 63 |
+
carry = 0
|
| 64 |
+
overflow = 0
|
| 65 |
+
|
| 66 |
+
if opcode == 0x0: # ADD
|
| 67 |
+
result, carry, overflow = _alu_add(a, b)
|
| 68 |
+
elif opcode == 0x1: # SUB
|
| 69 |
+
result, carry, overflow = _alu_sub(a, b)
|
| 70 |
+
elif opcode == 0x2: # AND
|
| 71 |
+
result = a & b
|
| 72 |
+
elif opcode == 0x3: # OR
|
| 73 |
+
result = a | b
|
| 74 |
+
elif opcode == 0x4: # XOR
|
| 75 |
+
result = a ^ b
|
| 76 |
+
elif opcode == 0x5: # SHL
|
| 77 |
+
carry = 1 if (a & 0x80) else 0
|
| 78 |
+
result = (a << 1) & 0xFF
|
| 79 |
+
elif opcode == 0x6: # SHR
|
| 80 |
+
carry = 1 if (a & 0x01) else 0
|
| 81 |
+
result = (a >> 1) & 0xFF
|
| 82 |
+
elif opcode == 0x7: # MUL
|
| 83 |
+
full = a * b
|
| 84 |
+
result = full & 0xFF
|
| 85 |
+
carry = 1 if full > 0xFF else 0
|
| 86 |
+
elif opcode == 0x8: # DIV
|
| 87 |
+
if b == 0:
|
| 88 |
+
result = 0
|
| 89 |
+
carry = 1
|
| 90 |
+
overflow = 1
|
| 91 |
+
else:
|
| 92 |
+
result = (a // b) & 0xFF
|
| 93 |
+
elif opcode == 0x9: # CMP
|
| 94 |
+
result, carry, overflow = _alu_sub(a, b)
|
| 95 |
+
write_result = False
|
| 96 |
+
elif opcode == 0xA: # LOAD
|
| 97 |
+
result = s.mem[imm8]
|
| 98 |
+
elif opcode == 0xB: # STORE
|
| 99 |
+
s.mem[imm8] = b & 0xFF
|
| 100 |
+
write_result = False
|
| 101 |
+
elif opcode == 0xC: # JMP
|
| 102 |
+
s.pc = imm8 & 0xFF
|
| 103 |
+
write_result = False
|
| 104 |
+
elif opcode == 0xD: # JZ
|
| 105 |
+
if s.flags[0] == 1:
|
| 106 |
+
s.pc = imm8 & 0xFF
|
| 107 |
+
else:
|
| 108 |
+
s.pc = next_pc
|
| 109 |
+
write_result = False
|
| 110 |
+
elif opcode == 0xE: # CALL
|
| 111 |
+
s.sp = (s.sp - 1) & 0xFF
|
| 112 |
+
s.mem[s.sp] = next_pc
|
| 113 |
+
s.pc = imm8 & 0xFF
|
| 114 |
+
write_result = False
|
| 115 |
+
elif opcode == 0xF: # HALT
|
| 116 |
+
s.ctrl[0] = 1
|
| 117 |
+
write_result = False
|
| 118 |
+
|
| 119 |
+
if opcode <= 0x9 or opcode in (0xA, 0x7, 0x8):
|
| 120 |
+
s.flags = list(_flags_from_result(result, carry, overflow))
|
| 121 |
+
|
| 122 |
+
if write_result:
|
| 123 |
+
s.regs[rd] = result & 0xFF
|
| 124 |
+
|
| 125 |
+
if opcode not in (0xC, 0xD, 0xE):
|
| 126 |
+
s.pc = next_pc
|
| 127 |
+
|
| 128 |
+
return s
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def run_until_halt(state: CPUState, max_cycles: int = 256) -> Tuple[CPUState, int]:
|
| 132 |
+
s = state.copy()
|
| 133 |
+
for i in range(max_cycles):
|
| 134 |
+
if s.ctrl[0] == 1:
|
| 135 |
+
return s, i
|
| 136 |
+
s = step(s)
|
| 137 |
+
return s, max_cycles
|
cpu/state.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
State layout helpers for the 8-bit threshold computer.
|
| 3 |
+
All multi-bit fields are MSB-first.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
|
| 8 |
+
from dataclasses import dataclass
|
| 9 |
+
from typing import List
|
| 10 |
+
|
| 11 |
+
FLAG_NAMES = ["Z", "N", "C", "V"]
|
| 12 |
+
CTRL_NAMES = ["HALT", "MEM_WE", "MEM_RE", "RESERVED"]
|
| 13 |
+
|
| 14 |
+
PC_BITS = 8
|
| 15 |
+
IR_BITS = 16
|
| 16 |
+
REG_BITS = 8
|
| 17 |
+
REG_COUNT = 4
|
| 18 |
+
FLAG_BITS = 4
|
| 19 |
+
SP_BITS = 8
|
| 20 |
+
CTRL_BITS = 4
|
| 21 |
+
MEM_BYTES = 256
|
| 22 |
+
MEM_BITS = MEM_BYTES * 8
|
| 23 |
+
|
| 24 |
+
STATE_BITS = PC_BITS + IR_BITS + (REG_BITS * REG_COUNT) + FLAG_BITS + SP_BITS + CTRL_BITS + MEM_BITS
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def int_to_bits(value: int, width: int) -> List[int]:
|
| 28 |
+
return [(value >> (width - 1 - i)) & 1 for i in range(width)]
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def bits_to_int(bits: List[int]) -> int:
|
| 32 |
+
value = 0
|
| 33 |
+
for bit in bits:
|
| 34 |
+
value = (value << 1) | int(bit)
|
| 35 |
+
return value
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
@dataclass
|
| 39 |
+
class CPUState:
|
| 40 |
+
pc: int
|
| 41 |
+
ir: int
|
| 42 |
+
regs: List[int]
|
| 43 |
+
flags: List[int]
|
| 44 |
+
sp: int
|
| 45 |
+
ctrl: List[int]
|
| 46 |
+
mem: List[int]
|
| 47 |
+
|
| 48 |
+
def copy(self) -> "CPUState":
|
| 49 |
+
return CPUState(
|
| 50 |
+
pc=int(self.pc),
|
| 51 |
+
ir=int(self.ir),
|
| 52 |
+
regs=[int(r) for r in self.regs],
|
| 53 |
+
flags=[int(f) for f in self.flags],
|
| 54 |
+
sp=int(self.sp),
|
| 55 |
+
ctrl=[int(c) for c in self.ctrl],
|
| 56 |
+
mem=[int(m) for m in self.mem],
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def pack_state(state: CPUState) -> List[int]:
|
| 61 |
+
bits: List[int] = []
|
| 62 |
+
bits.extend(int_to_bits(state.pc, PC_BITS))
|
| 63 |
+
bits.extend(int_to_bits(state.ir, IR_BITS))
|
| 64 |
+
for reg in state.regs:
|
| 65 |
+
bits.extend(int_to_bits(reg, REG_BITS))
|
| 66 |
+
bits.extend([int(f) for f in state.flags])
|
| 67 |
+
bits.extend(int_to_bits(state.sp, SP_BITS))
|
| 68 |
+
bits.extend([int(c) for c in state.ctrl])
|
| 69 |
+
for byte in state.mem:
|
| 70 |
+
bits.extend(int_to_bits(byte, REG_BITS))
|
| 71 |
+
return bits
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def unpack_state(bits: List[int]) -> CPUState:
|
| 75 |
+
if len(bits) != STATE_BITS:
|
| 76 |
+
raise ValueError(f"Expected {STATE_BITS} bits, got {len(bits)}")
|
| 77 |
+
|
| 78 |
+
idx = 0
|
| 79 |
+
pc = bits_to_int(bits[idx:idx + PC_BITS])
|
| 80 |
+
idx += PC_BITS
|
| 81 |
+
ir = bits_to_int(bits[idx:idx + IR_BITS])
|
| 82 |
+
idx += IR_BITS
|
| 83 |
+
|
| 84 |
+
regs = []
|
| 85 |
+
for _ in range(REG_COUNT):
|
| 86 |
+
regs.append(bits_to_int(bits[idx:idx + REG_BITS]))
|
| 87 |
+
idx += REG_BITS
|
| 88 |
+
|
| 89 |
+
flags = [int(b) for b in bits[idx:idx + FLAG_BITS]]
|
| 90 |
+
idx += FLAG_BITS
|
| 91 |
+
|
| 92 |
+
sp = bits_to_int(bits[idx:idx + SP_BITS])
|
| 93 |
+
idx += SP_BITS
|
| 94 |
+
|
| 95 |
+
ctrl = [int(b) for b in bits[idx:idx + CTRL_BITS]]
|
| 96 |
+
idx += CTRL_BITS
|
| 97 |
+
|
| 98 |
+
mem = []
|
| 99 |
+
for _ in range(MEM_BYTES):
|
| 100 |
+
mem.append(bits_to_int(bits[idx:idx + REG_BITS]))
|
| 101 |
+
idx += REG_BITS
|
| 102 |
+
|
| 103 |
+
return CPUState(pc=pc, ir=ir, regs=regs, flags=flags, sp=sp, ctrl=ctrl, mem=mem)
|
eval/build_memory.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Generate memory and fetch/load/store buffers for the 8-bit threshold computer.
|
| 3 |
+
Updates neural_computer.safetensors and tensors.txt in-place.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Dict, Iterable, List
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
from safetensors import safe_open
|
| 13 |
+
from safetensors.torch import save_file
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
MODEL_PATH = Path(__file__).resolve().parent.parent / "neural_computer.safetensors"
|
| 17 |
+
MANIFEST_PATH = Path(__file__).resolve().parent.parent / "tensors.txt"
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def load_tensors(path: Path) -> Dict[str, torch.Tensor]:
|
| 21 |
+
tensors: Dict[str, torch.Tensor] = {}
|
| 22 |
+
with safe_open(str(path), framework="pt") as f:
|
| 23 |
+
for name in f.keys():
|
| 24 |
+
tensors[name] = f.get_tensor(name).float().cpu().clone()
|
| 25 |
+
return tensors
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def add_gate(tensors: Dict[str, torch.Tensor], name: str, weight: Iterable[float], bias: Iterable[float]) -> None:
|
| 29 |
+
w_key = f"{name}.weight"
|
| 30 |
+
b_key = f"{name}.bias"
|
| 31 |
+
if w_key in tensors or b_key in tensors:
|
| 32 |
+
raise ValueError(f"Gate already exists: {name}")
|
| 33 |
+
tensors[w_key] = torch.tensor(list(weight), dtype=torch.float32)
|
| 34 |
+
tensors[b_key] = torch.tensor(list(bias), dtype=torch.float32)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def add_decoder_8to256(tensors: Dict[str, torch.Tensor]) -> None:
|
| 38 |
+
for addr in range(256):
|
| 39 |
+
bits = [(addr >> (7 - i)) & 1 for i in range(8)] # MSB-first
|
| 40 |
+
weights = [1.0 if bit == 1 else -1.0 for bit in bits]
|
| 41 |
+
bias = -float(sum(bits))
|
| 42 |
+
add_gate(tensors, f"memory.addr_decode.out{addr}", weights, [bias])
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def add_memory_read_mux(tensors: Dict[str, torch.Tensor]) -> None:
|
| 46 |
+
# AND each mem bit with its address select, then OR across all addresses.
|
| 47 |
+
for bit in range(8):
|
| 48 |
+
for addr in range(256):
|
| 49 |
+
add_gate(tensors, f"memory.read.bit{bit}.and{addr}", [1.0, 1.0], [-2.0])
|
| 50 |
+
add_gate(tensors, f"memory.read.bit{bit}.or", [1.0] * 256, [-1.0])
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def add_memory_write_cells(tensors: Dict[str, torch.Tensor]) -> None:
|
| 54 |
+
# write_sel = addr_select AND write_enable
|
| 55 |
+
# new_bit = (NOT write_sel AND old_bit) OR (write_sel AND write_data_bit)
|
| 56 |
+
for addr in range(256):
|
| 57 |
+
add_gate(tensors, f"memory.write.sel.addr{addr}", [1.0, 1.0], [-2.0])
|
| 58 |
+
add_gate(tensors, f"memory.write.nsel.addr{addr}", [-1.0], [0.0])
|
| 59 |
+
for bit in range(8):
|
| 60 |
+
add_gate(tensors, f"memory.write.addr{addr}.bit{bit}.and_old", [1.0, 1.0], [-2.0])
|
| 61 |
+
add_gate(tensors, f"memory.write.addr{addr}.bit{bit}.and_new", [1.0, 1.0], [-2.0])
|
| 62 |
+
add_gate(tensors, f"memory.write.addr{addr}.bit{bit}.or", [1.0, 1.0], [-1.0])
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def add_fetch_load_store_buffers(tensors: Dict[str, torch.Tensor]) -> None:
|
| 66 |
+
# Buffer gates: output = input (weight=1, bias=-1)
|
| 67 |
+
for bit in range(16):
|
| 68 |
+
add_gate(tensors, f"control.fetch.ir.bit{bit}", [1.0], [-1.0])
|
| 69 |
+
for bit in range(8):
|
| 70 |
+
add_gate(tensors, f"control.load.bit{bit}", [1.0], [-1.0])
|
| 71 |
+
add_gate(tensors, f"control.store.bit{bit}", [1.0], [-1.0])
|
| 72 |
+
add_gate(tensors, f"control.mem_addr.bit{bit}", [1.0], [-1.0])
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def update_manifest(tensors: Dict[str, torch.Tensor]) -> None:
|
| 76 |
+
# Bump manifest version to reflect memory integration.
|
| 77 |
+
key = "manifest.version"
|
| 78 |
+
if key not in tensors:
|
| 79 |
+
tensors[key] = torch.tensor([2.0], dtype=torch.float32)
|
| 80 |
+
return
|
| 81 |
+
tensors[key] = torch.tensor([2.0], dtype=torch.float32)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def write_manifest(path: Path, tensors: Dict[str, torch.Tensor]) -> None:
|
| 85 |
+
lines: List[str] = []
|
| 86 |
+
lines.append("# Tensor Manifest")
|
| 87 |
+
lines.append(f"# Total: {len(tensors)} tensors")
|
| 88 |
+
for name in sorted(tensors.keys()):
|
| 89 |
+
t = tensors[name]
|
| 90 |
+
values = ", ".join(f"{v:.1f}" for v in t.flatten().tolist())
|
| 91 |
+
lines.append(f"{name}: shape={list(t.shape)}, values=[{values}]")
|
| 92 |
+
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def main() -> None:
|
| 96 |
+
tensors = load_tensors(MODEL_PATH)
|
| 97 |
+
add_decoder_8to256(tensors)
|
| 98 |
+
add_memory_read_mux(tensors)
|
| 99 |
+
add_memory_write_cells(tensors)
|
| 100 |
+
add_fetch_load_store_buffers(tensors)
|
| 101 |
+
update_manifest(tensors)
|
| 102 |
+
save_file(tensors, str(MODEL_PATH))
|
| 103 |
+
write_manifest(MANIFEST_PATH, tensors)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
if __name__ == "__main__":
|
| 107 |
+
main()
|
eval/comprehensive_eval.py
CHANGED
|
@@ -1896,17 +1896,17 @@ class CircuitEvaluator:
|
|
| 1896 |
|
| 1897 |
def test_manifest(self) -> TestResult:
|
| 1898 |
"""Test manifest metadata tensors."""
|
| 1899 |
-
manifest_tensors = [
|
| 1900 |
-
('manifest.alu_operations', 16),
|
| 1901 |
-
('manifest.flags', 4),
|
| 1902 |
-
('manifest.instruction_width', 16),
|
| 1903 |
-
('manifest.memory_bytes', 256),
|
| 1904 |
-
('manifest.pc_width', 8),
|
| 1905 |
-
('manifest.register_width', 8),
|
| 1906 |
-
('manifest.registers', 4),
|
| 1907 |
-
('manifest.turing_complete', 1),
|
| 1908 |
-
('manifest.version',
|
| 1909 |
-
]
|
| 1910 |
|
| 1911 |
failures = []
|
| 1912 |
passed = 0
|
|
@@ -2182,9 +2182,9 @@ class CircuitEvaluator:
|
|
| 2182 |
|
| 2183 |
return TestResult('control.negated_conditional_jumps', passed, passed, [])
|
| 2184 |
|
| 2185 |
-
def test_control_parity_jumps(self) -> TestResult:
|
| 2186 |
-
"""Test parity-based conditional jumps (jp, jnp - jump positive/not positive)."""
|
| 2187 |
-
passed = 0
|
| 2188 |
|
| 2189 |
for jump_type in ['jp', 'jnp', 'jpe', 'jpo']: # parity even/odd variants
|
| 2190 |
for bit in range(8):
|
|
@@ -2193,9 +2193,161 @@ class CircuitEvaluator:
|
|
| 2193 |
self.reg.get(f'control.{jump_type}.bit{bit}.{comp}.weight')
|
| 2194 |
self.reg.get(f'control.{jump_type}.bit{bit}.{comp}.bias')
|
| 2195 |
passed += 2
|
| 2196 |
-
|
| 2197 |
-
return TestResult('control.parity_jumps', passed, passed, [])
|
| 2198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2199 |
# =========================================================================
|
| 2200 |
# ARITHMETIC - ADDITIONAL CIRCUITS
|
| 2201 |
# =========================================================================
|
|
@@ -2850,14 +3002,22 @@ class ComprehensiveEvaluator:
|
|
| 2850 |
self._run_test(self.evaluator.test_control_register_mux, verbose)
|
| 2851 |
self._run_test(self.evaluator.test_control_halt, verbose)
|
| 2852 |
self._run_test(self.evaluator.test_control_pc_load, verbose)
|
| 2853 |
-
self._run_test(self.evaluator.test_control_nop, verbose)
|
| 2854 |
-
self._run_test(self.evaluator.test_control_conditional_jumps, verbose)
|
| 2855 |
-
self._run_test(self.evaluator.test_control_negated_conditional_jumps, verbose)
|
| 2856 |
-
self._run_test(self.evaluator.test_control_parity_jumps, verbose)
|
| 2857 |
-
|
| 2858 |
-
#
|
| 2859 |
-
if verbose:
|
| 2860 |
-
print("\n===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2861 |
self._run_test(self.evaluator.test_even_parity, verbose)
|
| 2862 |
self._run_test(self.evaluator.test_odd_parity, verbose)
|
| 2863 |
self._run_test(self.evaluator.test_checksum_8bit, verbose)
|
|
|
|
| 1896 |
|
| 1897 |
def test_manifest(self) -> TestResult:
|
| 1898 |
"""Test manifest metadata tensors."""
|
| 1899 |
+
manifest_tensors = [
|
| 1900 |
+
('manifest.alu_operations', 16),
|
| 1901 |
+
('manifest.flags', 4),
|
| 1902 |
+
('manifest.instruction_width', 16),
|
| 1903 |
+
('manifest.memory_bytes', 256),
|
| 1904 |
+
('manifest.pc_width', 8),
|
| 1905 |
+
('manifest.register_width', 8),
|
| 1906 |
+
('manifest.registers', 4),
|
| 1907 |
+
('manifest.turing_complete', 1),
|
| 1908 |
+
('manifest.version', 2),
|
| 1909 |
+
]
|
| 1910 |
|
| 1911 |
failures = []
|
| 1912 |
passed = 0
|
|
|
|
| 2182 |
|
| 2183 |
return TestResult('control.negated_conditional_jumps', passed, passed, [])
|
| 2184 |
|
| 2185 |
+
def test_control_parity_jumps(self) -> TestResult:
|
| 2186 |
+
"""Test parity-based conditional jumps (jp, jnp - jump positive/not positive)."""
|
| 2187 |
+
passed = 0
|
| 2188 |
|
| 2189 |
for jump_type in ['jp', 'jnp', 'jpe', 'jpo']: # parity even/odd variants
|
| 2190 |
for bit in range(8):
|
|
|
|
| 2193 |
self.reg.get(f'control.{jump_type}.bit{bit}.{comp}.weight')
|
| 2194 |
self.reg.get(f'control.{jump_type}.bit{bit}.{comp}.bias')
|
| 2195 |
passed += 2
|
| 2196 |
+
|
| 2197 |
+
return TestResult('control.parity_jumps', passed, passed, [])
|
| 2198 |
+
|
| 2199 |
+
# =========================================================================
|
| 2200 |
+
# MEMORY CIRCUITS
|
| 2201 |
+
# =========================================================================
|
| 2202 |
+
|
| 2203 |
+
def test_memory_decoder_8to256(self) -> TestResult:
|
| 2204 |
+
"""Test 8-to-256 address decoder exhaustively."""
|
| 2205 |
+
failures = []
|
| 2206 |
+
passed = 0
|
| 2207 |
+
total = 256 * 256
|
| 2208 |
+
|
| 2209 |
+
for addr in range(256):
|
| 2210 |
+
addr_bits = torch.tensor([(addr >> (7 - i)) & 1 for i in range(8)],
|
| 2211 |
+
device=self.device, dtype=torch.float32)
|
| 2212 |
+
|
| 2213 |
+
for out_idx in range(256):
|
| 2214 |
+
w = self.reg.get(f'memory.addr_decode.out{out_idx}.weight')
|
| 2215 |
+
b = self.reg.get(f'memory.addr_decode.out{out_idx}.bias')
|
| 2216 |
+
output = heaviside((addr_bits * w).sum() + b).item()
|
| 2217 |
+
expected = 1.0 if out_idx == addr else 0.0
|
| 2218 |
+
|
| 2219 |
+
if output == expected:
|
| 2220 |
+
passed += 1
|
| 2221 |
+
elif len(failures) < 20:
|
| 2222 |
+
failures.append(((addr, out_idx), expected, output))
|
| 2223 |
+
|
| 2224 |
+
return TestResult('memory.addr_decode', passed, total, failures)
|
| 2225 |
+
|
| 2226 |
+
def test_memory_read_mux(self) -> TestResult:
|
| 2227 |
+
"""Test 256-byte memory read mux for a few representative addresses."""
|
| 2228 |
+
failures = []
|
| 2229 |
+
passed = 0
|
| 2230 |
+
total = 0
|
| 2231 |
+
|
| 2232 |
+
mem = [(addr * 37) & 0xFF for addr in range(256)]
|
| 2233 |
+
test_addrs = [0, 1, 2, 127, 255]
|
| 2234 |
+
|
| 2235 |
+
for addr in test_addrs:
|
| 2236 |
+
addr_bits = torch.tensor([(addr >> (7 - i)) & 1 for i in range(8)],
|
| 2237 |
+
device=self.device, dtype=torch.float32)
|
| 2238 |
+
|
| 2239 |
+
selects = []
|
| 2240 |
+
for out_idx in range(256):
|
| 2241 |
+
w = self.reg.get(f'memory.addr_decode.out{out_idx}.weight')
|
| 2242 |
+
b = self.reg.get(f'memory.addr_decode.out{out_idx}.bias')
|
| 2243 |
+
selects.append(heaviside((addr_bits * w).sum() + b).item())
|
| 2244 |
+
|
| 2245 |
+
for bit in range(8):
|
| 2246 |
+
and_vals = []
|
| 2247 |
+
for out_idx in range(256):
|
| 2248 |
+
mem_bit = float((mem[out_idx] >> (7 - bit)) & 1)
|
| 2249 |
+
inp = torch.tensor([mem_bit, selects[out_idx]], device=self.device)
|
| 2250 |
+
w = self.reg.get(f'memory.read.bit{bit}.and{out_idx}.weight')
|
| 2251 |
+
b = self.reg.get(f'memory.read.bit{bit}.and{out_idx}.bias')
|
| 2252 |
+
and_vals.append(heaviside((inp * w).sum() + b).item())
|
| 2253 |
+
|
| 2254 |
+
or_inp = torch.tensor(and_vals, device=self.device)
|
| 2255 |
+
w_or = self.reg.get(f'memory.read.bit{bit}.or.weight')
|
| 2256 |
+
b_or = self.reg.get(f'memory.read.bit{bit}.or.bias')
|
| 2257 |
+
output = heaviside((or_inp * w_or).sum() + b_or).item()
|
| 2258 |
+
expected = float((mem[addr] >> (7 - bit)) & 1)
|
| 2259 |
+
|
| 2260 |
+
total += 1
|
| 2261 |
+
if output == expected:
|
| 2262 |
+
passed += 1
|
| 2263 |
+
elif len(failures) < 20:
|
| 2264 |
+
failures.append(((addr, bit), expected, output))
|
| 2265 |
+
|
| 2266 |
+
return TestResult('memory.read', passed, total, failures)
|
| 2267 |
+
|
| 2268 |
+
def test_memory_write_cells(self) -> TestResult:
|
| 2269 |
+
"""Test memory cell update logic with and without write enable."""
|
| 2270 |
+
failures = []
|
| 2271 |
+
passed = 0
|
| 2272 |
+
total = 0
|
| 2273 |
+
|
| 2274 |
+
mem = [(addr * 13 + 7) & 0xFF for addr in range(256)]
|
| 2275 |
+
test_cases = [
|
| 2276 |
+
(0xA5, 42, 1.0),
|
| 2277 |
+
(0x3C, 200, 0.0),
|
| 2278 |
+
]
|
| 2279 |
+
|
| 2280 |
+
for write_data, write_addr, write_en in test_cases:
|
| 2281 |
+
addr_bits = torch.tensor([(write_addr >> (7 - i)) & 1 for i in range(8)],
|
| 2282 |
+
device=self.device, dtype=torch.float32)
|
| 2283 |
+
|
| 2284 |
+
decodes = []
|
| 2285 |
+
for out_idx in range(256):
|
| 2286 |
+
w = self.reg.get(f'memory.addr_decode.out{out_idx}.weight')
|
| 2287 |
+
b = self.reg.get(f'memory.addr_decode.out{out_idx}.bias')
|
| 2288 |
+
decodes.append(heaviside((addr_bits * w).sum() + b).item())
|
| 2289 |
+
|
| 2290 |
+
for out_idx in range(256):
|
| 2291 |
+
sel_inp = torch.tensor([decodes[out_idx], write_en], device=self.device)
|
| 2292 |
+
w_sel = self.reg.get(f'memory.write.sel.addr{out_idx}.weight')
|
| 2293 |
+
b_sel = self.reg.get(f'memory.write.sel.addr{out_idx}.bias')
|
| 2294 |
+
sel = heaviside((sel_inp * w_sel).sum() + b_sel).item()
|
| 2295 |
+
|
| 2296 |
+
w_nsel = self.reg.get(f'memory.write.nsel.addr{out_idx}.weight')
|
| 2297 |
+
b_nsel = self.reg.get(f'memory.write.nsel.addr{out_idx}.bias')
|
| 2298 |
+
nsel = heaviside(sel * w_nsel + b_nsel).item()
|
| 2299 |
+
|
| 2300 |
+
for bit in range(8):
|
| 2301 |
+
old_bit = float((mem[out_idx] >> (7 - bit)) & 1)
|
| 2302 |
+
data_bit = float((write_data >> (7 - bit)) & 1)
|
| 2303 |
+
|
| 2304 |
+
inp_old = torch.tensor([old_bit, nsel], device=self.device)
|
| 2305 |
+
w_old = self.reg.get(f'memory.write.addr{out_idx}.bit{bit}.and_old.weight')
|
| 2306 |
+
b_old = self.reg.get(f'memory.write.addr{out_idx}.bit{bit}.and_old.bias')
|
| 2307 |
+
and_old = heaviside((inp_old * w_old).sum() + b_old).item()
|
| 2308 |
+
|
| 2309 |
+
inp_new = torch.tensor([data_bit, sel], device=self.device)
|
| 2310 |
+
w_new = self.reg.get(f'memory.write.addr{out_idx}.bit{bit}.and_new.weight')
|
| 2311 |
+
b_new = self.reg.get(f'memory.write.addr{out_idx}.bit{bit}.and_new.bias')
|
| 2312 |
+
and_new = heaviside((inp_new * w_new).sum() + b_new).item()
|
| 2313 |
+
|
| 2314 |
+
inp_or = torch.tensor([and_old, and_new], device=self.device)
|
| 2315 |
+
w_or = self.reg.get(f'memory.write.addr{out_idx}.bit{bit}.or.weight')
|
| 2316 |
+
b_or = self.reg.get(f'memory.write.addr{out_idx}.bit{bit}.or.bias')
|
| 2317 |
+
output = heaviside((inp_or * w_or).sum() + b_or).item()
|
| 2318 |
+
|
| 2319 |
+
expected = data_bit if (write_en == 1.0 and out_idx == write_addr) else old_bit
|
| 2320 |
+
|
| 2321 |
+
total += 1
|
| 2322 |
+
if output == expected:
|
| 2323 |
+
passed += 1
|
| 2324 |
+
elif len(failures) < 20:
|
| 2325 |
+
failures.append(((out_idx, bit), expected, output))
|
| 2326 |
+
|
| 2327 |
+
return TestResult('memory.write', passed, total, failures)
|
| 2328 |
+
|
| 2329 |
+
def test_control_fetch_load_store(self) -> TestResult:
|
| 2330 |
+
"""Test fetch/load/store buffer gate existence."""
|
| 2331 |
+
passed = 0
|
| 2332 |
+
total = 0
|
| 2333 |
+
|
| 2334 |
+
for bit in range(16):
|
| 2335 |
+
total += 2
|
| 2336 |
+
if self.reg.has(f'control.fetch.ir.bit{bit}.weight'):
|
| 2337 |
+
self.reg.get(f'control.fetch.ir.bit{bit}.weight')
|
| 2338 |
+
self.reg.get(f'control.fetch.ir.bit{bit}.bias')
|
| 2339 |
+
passed += 2
|
| 2340 |
+
|
| 2341 |
+
for bit in range(8):
|
| 2342 |
+
for name in ['control.load', 'control.store', 'control.mem_addr']:
|
| 2343 |
+
total += 2
|
| 2344 |
+
if self.reg.has(f'{name}.bit{bit}.weight'):
|
| 2345 |
+
self.reg.get(f'{name}.bit{bit}.weight')
|
| 2346 |
+
self.reg.get(f'{name}.bit{bit}.bias')
|
| 2347 |
+
passed += 2
|
| 2348 |
+
|
| 2349 |
+
return TestResult('control.fetch_load_store', passed, total, [])
|
| 2350 |
+
|
| 2351 |
# =========================================================================
|
| 2352 |
# ARITHMETIC - ADDITIONAL CIRCUITS
|
| 2353 |
# =========================================================================
|
|
|
|
| 3002 |
self._run_test(self.evaluator.test_control_register_mux, verbose)
|
| 3003 |
self._run_test(self.evaluator.test_control_halt, verbose)
|
| 3004 |
self._run_test(self.evaluator.test_control_pc_load, verbose)
|
| 3005 |
+
self._run_test(self.evaluator.test_control_nop, verbose)
|
| 3006 |
+
self._run_test(self.evaluator.test_control_conditional_jumps, verbose)
|
| 3007 |
+
self._run_test(self.evaluator.test_control_negated_conditional_jumps, verbose)
|
| 3008 |
+
self._run_test(self.evaluator.test_control_parity_jumps, verbose)
|
| 3009 |
+
|
| 3010 |
+
# Memory
|
| 3011 |
+
if verbose:
|
| 3012 |
+
print("\n=== MEMORY ===")
|
| 3013 |
+
self._run_test(self.evaluator.test_memory_decoder_8to256, verbose)
|
| 3014 |
+
self._run_test(self.evaluator.test_memory_read_mux, verbose)
|
| 3015 |
+
self._run_test(self.evaluator.test_memory_write_cells, verbose)
|
| 3016 |
+
self._run_test(self.evaluator.test_control_fetch_load_store, verbose)
|
| 3017 |
+
|
| 3018 |
+
# Error detection
|
| 3019 |
+
if verbose:
|
| 3020 |
+
print("\n=== ERROR DETECTION ===")
|
| 3021 |
self._run_test(self.evaluator.test_even_parity, verbose)
|
| 3022 |
self._run_test(self.evaluator.test_odd_parity, verbose)
|
| 3023 |
self._run_test(self.evaluator.test_checksum_8bit, verbose)
|
eval/cpu_cycle_test.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Basic CPU cycle smoke test.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import sys
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
sys.path.append(str(Path(__file__).resolve().parent.parent))
|
| 9 |
+
|
| 10 |
+
from cpu.cycle import run_until_halt
|
| 11 |
+
from cpu.state import CPUState
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def encode(opcode: int, rd: int, rs: int, imm8: int) -> int:
|
| 15 |
+
return ((opcode & 0xF) << 12) | ((rd & 0x3) << 10) | ((rs & 0x3) << 8) | (imm8 & 0xFF)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def write_instr(mem, addr, instr):
|
| 19 |
+
mem[addr & 0xFF] = (instr >> 8) & 0xFF
|
| 20 |
+
mem[(addr + 1) & 0xFF] = instr & 0xFF
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def main() -> None:
|
| 24 |
+
mem = [0] * 256
|
| 25 |
+
|
| 26 |
+
write_instr(mem, 0x00, encode(0xA, 0, 0, 0x10)) # LOAD R0, [0x10]
|
| 27 |
+
write_instr(mem, 0x02, encode(0xA, 1, 0, 0x11)) # LOAD R1, [0x11]
|
| 28 |
+
write_instr(mem, 0x04, encode(0x0, 0, 1, 0x00)) # ADD R0, R1
|
| 29 |
+
write_instr(mem, 0x06, encode(0xB, 0, 0, 0x12)) # STORE R0 -> [0x12]
|
| 30 |
+
write_instr(mem, 0x08, encode(0xF, 0, 0, 0x00)) # HALT
|
| 31 |
+
|
| 32 |
+
mem[0x10] = 5
|
| 33 |
+
mem[0x11] = 7
|
| 34 |
+
|
| 35 |
+
state = CPUState(
|
| 36 |
+
pc=0,
|
| 37 |
+
ir=0,
|
| 38 |
+
regs=[0, 0, 0, 0],
|
| 39 |
+
flags=[0, 0, 0, 0],
|
| 40 |
+
sp=0xFF,
|
| 41 |
+
ctrl=[0, 0, 0, 0],
|
| 42 |
+
mem=mem,
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
final, cycles = run_until_halt(state, max_cycles=20)
|
| 46 |
+
|
| 47 |
+
assert final.ctrl[0] == 1, "HALT flag not set"
|
| 48 |
+
assert final.regs[0] == 12, f"R0 expected 12, got {final.regs[0]}"
|
| 49 |
+
assert final.mem[0x12] == 12, f"MEM[0x12] expected 12, got {final.mem[0x12]}"
|
| 50 |
+
assert cycles <= 10, f"Unexpected cycle count: {cycles}"
|
| 51 |
+
|
| 52 |
+
print("cpu_cycle_test: ok")
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
if __name__ == "__main__":
|
| 56 |
+
main()
|
eval/iron_eval.py
CHANGED
|
@@ -3154,17 +3154,17 @@ class BatchedFitnessEvaluator:
|
|
| 3154 |
scores = torch.zeros(pop_size, device=self.device)
|
| 3155 |
total_tests = 0
|
| 3156 |
|
| 3157 |
-
manifest_tensors = [
|
| 3158 |
-
('manifest.alu_operations', 16),
|
| 3159 |
-
('manifest.flags', 4),
|
| 3160 |
-
('manifest.instruction_width', 16),
|
| 3161 |
-
('manifest.memory_bytes', 256),
|
| 3162 |
-
('manifest.pc_width', 8),
|
| 3163 |
-
('manifest.register_width', 8),
|
| 3164 |
-
('manifest.registers', 4),
|
| 3165 |
-
('manifest.turing_complete', 1),
|
| 3166 |
-
('manifest.version',
|
| 3167 |
-
]
|
| 3168 |
|
| 3169 |
for tensor_name, expected_value in manifest_tensors:
|
| 3170 |
w = pop[tensor_name].view(pop_size, -1)
|
|
|
|
| 3154 |
scores = torch.zeros(pop_size, device=self.device)
|
| 3155 |
total_tests = 0
|
| 3156 |
|
| 3157 |
+
manifest_tensors = [
|
| 3158 |
+
('manifest.alu_operations', 16),
|
| 3159 |
+
('manifest.flags', 4),
|
| 3160 |
+
('manifest.instruction_width', 16),
|
| 3161 |
+
('manifest.memory_bytes', 256),
|
| 3162 |
+
('manifest.pc_width', 8),
|
| 3163 |
+
('manifest.register_width', 8),
|
| 3164 |
+
('manifest.registers', 4),
|
| 3165 |
+
('manifest.turing_complete', 1),
|
| 3166 |
+
('manifest.version', 2),
|
| 3167 |
+
]
|
| 3168 |
|
| 3169 |
for tensor_name, expected_value in manifest_tensors:
|
| 3170 |
w = pop[tensor_name].view(pop_size, -1)
|
llm/guide.md
CHANGED
|
@@ -102,7 +102,7 @@ Total circuit depth: ~32 threshold layers (8 FAs × 4 layers each).
|
|
| 102 |
|
| 103 |
## 3. Circuit Inventory
|
| 104 |
|
| 105 |
-
The `neural_computer.safetensors` contains
|
| 106 |
|
| 107 |
| Category | Circuits | Tensors |
|
| 108 |
|----------|----------|---------|
|
|
@@ -459,7 +459,7 @@ Circuit computation adds ~5-10% overhead:
|
|
| 459 |
- BitInjector: 1 linear layer (16→960)
|
| 460 |
- Router: 2 linear layers
|
| 461 |
|
| 462 |
-
The circuits have only
|
| 463 |
|
| 464 |
### 9.3 Generalization
|
| 465 |
|
|
@@ -547,7 +547,7 @@ Model: [extracts 127, 128] [routes to circuit] [gets 255]
|
|
| 547 |
|
| 548 |
```
|
| 549 |
8bit-threshold-computer/
|
| 550 |
-
├── neural_computer.safetensors # Frozen circuits (
|
| 551 |
├── circuit_llm.py # Integration architecture
|
| 552 |
├── train_circuit_interface.py # Training loop
|
| 553 |
├── iron_eval.py # Circuit verification (6,590 tests)
|
|
|
|
| 102 |
|
| 103 |
## 3. Circuit Inventory
|
| 104 |
|
| 105 |
+
The `neural_computer.safetensors` contains 24,200 tensors / 40,323 parameters implementing:
|
| 106 |
|
| 107 |
| Category | Circuits | Tensors |
|
| 108 |
|----------|----------|---------|
|
|
|
|
| 459 |
- BitInjector: 1 linear layer (16→960)
|
| 460 |
- Router: 2 linear layers
|
| 461 |
|
| 462 |
+
The circuits have only 40,323 parameters total—negligible versus the 361M in the base model.
|
| 463 |
|
| 464 |
### 9.3 Generalization
|
| 465 |
|
|
|
|
| 547 |
|
| 548 |
```
|
| 549 |
8bit-threshold-computer/
|
| 550 |
+
├── neural_computer.safetensors # Frozen circuits (24,200 tensors)
|
| 551 |
├── circuit_llm.py # Integration architecture
|
| 552 |
├── train_circuit_interface.py # Training loop
|
| 553 |
├── iron_eval.py # Circuit verification (6,590 tests)
|
neural_computer.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9c40d35edb9ed7d37c0454b3aacde3d8effc68dfbc707b68ae1feb585836581f
|
| 3 |
+
size 2525316
|
routing.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
routing/generate_routing.py
CHANGED
|
@@ -417,19 +417,19 @@ def generate_pattern_routing():
|
|
| 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':
|
| 432 |
-
}
|
| 433 |
|
| 434 |
|
| 435 |
def generate_multiplier8x8_routing():
|
|
@@ -870,9 +870,9 @@ def generate_combinational_routing():
|
|
| 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 = {}
|
|
@@ -1004,18 +1004,99 @@ def generate_control_routing():
|
|
| 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 |
-
|
| 1014 |
-
|
| 1015 |
-
|
| 1016 |
-
|
| 1017 |
-
|
| 1018 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1019 |
|
| 1020 |
# Even Parity Checker
|
| 1021 |
routing['error_detection.evenparitychecker'] = {
|
|
@@ -1338,14 +1419,38 @@ def main():
|
|
| 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('
|
| 1345 |
-
routing['circuits'].update(
|
| 1346 |
-
|
| 1347 |
-
print('
|
| 1348 |
-
routing['circuits'].update(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1349 |
|
| 1350 |
print(' Modular arithmetic')
|
| 1351 |
routing['circuits'].update(generate_modular_routing())
|
|
|
|
| 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': 2}
|
| 432 |
+
}
|
| 433 |
|
| 434 |
|
| 435 |
def generate_multiplier8x8_routing():
|
|
|
|
| 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 = {}
|
|
|
|
| 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 |
+
# Fetch/load/store buffer gates
|
| 1014 |
+
internal_fetch = {f'bit{bit}': [f'$data[{bit}]'] for bit in range(16)}
|
| 1015 |
+
routing['control.fetch.ir'] = {
|
| 1016 |
+
'inputs': ['$data[0:15]'],
|
| 1017 |
+
'type': 'buffer',
|
| 1018 |
+
'internal': internal_fetch
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
internal_load = {f'bit{bit}': [f'$data[{bit}]'] for bit in range(8)}
|
| 1022 |
+
routing['control.load'] = {
|
| 1023 |
+
'inputs': ['$data[0:7]'],
|
| 1024 |
+
'type': 'buffer',
|
| 1025 |
+
'internal': internal_load
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
internal_store = {f'bit{bit}': [f'$data[{bit}]'] for bit in range(8)}
|
| 1029 |
+
routing['control.store'] = {
|
| 1030 |
+
'inputs': ['$data[0:7]'],
|
| 1031 |
+
'type': 'buffer',
|
| 1032 |
+
'internal': internal_store
|
| 1033 |
+
}
|
| 1034 |
+
|
| 1035 |
+
internal_mem_addr = {f'bit{bit}': [f'$addr[{bit}]'] for bit in range(8)}
|
| 1036 |
+
routing['control.mem_addr'] = {
|
| 1037 |
+
'inputs': ['$addr[0:7]'],
|
| 1038 |
+
'type': 'buffer',
|
| 1039 |
+
'internal': internal_mem_addr
|
| 1040 |
+
}
|
| 1041 |
+
|
| 1042 |
+
return routing
|
| 1043 |
+
|
| 1044 |
+
|
| 1045 |
+
def generate_memory_routing():
|
| 1046 |
+
"""Generate routing for memory decoder, read mux, and write cell update."""
|
| 1047 |
+
routing = {}
|
| 1048 |
+
|
| 1049 |
+
addr_bits = [f'$addr[{i}]' for i in range(8)]
|
| 1050 |
+
internal_dec = {f'out{addr}': addr_bits for addr in range(256)}
|
| 1051 |
+
routing['memory.addr_decode'] = {
|
| 1052 |
+
'inputs': ['$addr[0:7]'],
|
| 1053 |
+
'type': 'decoder',
|
| 1054 |
+
'internal': internal_dec
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
internal_read = {}
|
| 1058 |
+
for bit in range(8):
|
| 1059 |
+
for addr in range(256):
|
| 1060 |
+
internal_read[f'bit{bit}.and{addr}'] = [f'$mem[{addr}][{bit}]', f'$sel[{addr}]']
|
| 1061 |
+
internal_read[f'bit{bit}.or'] = [f'bit{bit}.and{i}' for i in range(256)]
|
| 1062 |
+
|
| 1063 |
+
routing['memory.read'] = {
|
| 1064 |
+
'inputs': ['$mem[0:255][0:7]', '$sel[0:255]'],
|
| 1065 |
+
'type': 'read_mux',
|
| 1066 |
+
'internal': internal_read,
|
| 1067 |
+
'outputs': {f'bit{bit}': f'bit{bit}.or' for bit in range(8)}
|
| 1068 |
+
}
|
| 1069 |
+
|
| 1070 |
+
internal_write = {}
|
| 1071 |
+
for addr in range(256):
|
| 1072 |
+
internal_write[f'sel.addr{addr}'] = [f'$sel[{addr}]', '$we']
|
| 1073 |
+
internal_write[f'nsel.addr{addr}'] = [f'sel.addr{addr}']
|
| 1074 |
+
for bit in range(8):
|
| 1075 |
+
internal_write[f'addr{addr}.bit{bit}.and_old'] = [f'$mem[{addr}][{bit}]', f'nsel.addr{addr}']
|
| 1076 |
+
internal_write[f'addr{addr}.bit{bit}.and_new'] = [f'$write_data[{bit}]', f'sel.addr{addr}']
|
| 1077 |
+
internal_write[f'addr{addr}.bit{bit}.or'] = [
|
| 1078 |
+
f'addr{addr}.bit{bit}.and_old',
|
| 1079 |
+
f'addr{addr}.bit{bit}.and_new'
|
| 1080 |
+
]
|
| 1081 |
+
|
| 1082 |
+
outputs = {
|
| 1083 |
+
f'mem[{addr}][{bit}]': f'addr{addr}.bit{bit}.or'
|
| 1084 |
+
for addr in range(256) for bit in range(8)
|
| 1085 |
+
}
|
| 1086 |
+
|
| 1087 |
+
routing['memory.write'] = {
|
| 1088 |
+
'inputs': ['$mem[0:255][0:7]', '$write_data[0:7]', '$sel[0:255]', '$we'],
|
| 1089 |
+
'type': 'write_mux',
|
| 1090 |
+
'internal': internal_write,
|
| 1091 |
+
'outputs': outputs
|
| 1092 |
+
}
|
| 1093 |
+
|
| 1094 |
+
return routing
|
| 1095 |
+
|
| 1096 |
+
|
| 1097 |
+
def generate_error_detection_routing():
|
| 1098 |
+
"""Generate routing for error detection circuits."""
|
| 1099 |
+
routing = {}
|
| 1100 |
|
| 1101 |
# Even Parity Checker
|
| 1102 |
routing['error_detection.evenparitychecker'] = {
|
|
|
|
| 1419 |
print(' Negation')
|
| 1420 |
routing['circuits'].update(generate_neg8bit_routing())
|
| 1421 |
|
| 1422 |
+
print(' 2x2 Multiplier')
|
| 1423 |
+
routing['circuits'].update(generate_multiplier2x2_routing())
|
| 1424 |
+
|
| 1425 |
+
print(' 8x8 Multiplier')
|
| 1426 |
+
routing['circuits'].update(generate_multiplier8x8_routing())
|
| 1427 |
+
|
| 1428 |
+
print(' 8-bit Division')
|
| 1429 |
+
routing['circuits'].update(generate_div8bit_routing())
|
| 1430 |
+
|
| 1431 |
+
print(' ADC/SBC')
|
| 1432 |
+
routing['circuits'].update(generate_adc_sbc_routing())
|
| 1433 |
+
|
| 1434 |
+
print(' Rotate')
|
| 1435 |
+
routing['circuits'].update(generate_rotate_routing())
|
| 1436 |
+
|
| 1437 |
+
print(' Combinational')
|
| 1438 |
+
routing['circuits'].update(generate_combinational_routing())
|
| 1439 |
+
|
| 1440 |
+
print(' Control')
|
| 1441 |
+
routing['circuits'].update(generate_control_routing())
|
| 1442 |
+
|
| 1443 |
+
print(' Memory')
|
| 1444 |
+
routing['circuits'].update(generate_memory_routing())
|
| 1445 |
+
|
| 1446 |
+
print(' Error detection')
|
| 1447 |
+
routing['circuits'].update(generate_error_detection_routing())
|
| 1448 |
+
|
| 1449 |
+
print(' ALU')
|
| 1450 |
+
routing['circuits'].update(generate_alu_routing())
|
| 1451 |
+
|
| 1452 |
+
print(' Threshold gates')
|
| 1453 |
+
routing['circuits'].update(generate_threshold_routing())
|
| 1454 |
|
| 1455 |
print(' Modular arithmetic')
|
| 1456 |
routing['circuits'].update(generate_modular_routing())
|
routing/routing_schema.md
CHANGED
|
@@ -32,8 +32,11 @@ The routing file (`routing.json`) defines how gates are interconnected. Each ent
|
|
| 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 |
|
|
|
|
| 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 |
+
6. **Memory indexing**: `"$mem[addr][bit]"` or `"$sel[addr]"` - Addressed memory bit or one-hot select line
|
| 39 |
+
- Example: `"$mem[42][3]"` (addr 42, bit 3), `"$sel[42]"`
|
| 40 |
|
| 41 |
## Circuit Types
|
| 42 |
|
tensors.txt
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
todo.md
CHANGED
|
@@ -151,7 +151,7 @@ The machine runs. Callers just provide initial state and collect results.
|
|
| 151 |
- Comparators, threshold gates
|
| 152 |
- Conditional jumps
|
| 153 |
|
| 154 |
-
**Current:
|
| 155 |
**Projected: ~1.65M tensors (with 64KB memory)**
|
| 156 |
|
| 157 |
## Applications
|
|
|
|
| 151 |
- Comparators, threshold gates
|
| 152 |
- Conditional jumps
|
| 153 |
|
| 154 |
+
**Current: 24,200 tensors**
|
| 155 |
**Projected: ~1.65M tensors (with 64KB memory)**
|
| 156 |
|
| 157 |
## Applications
|