CharlesCNorton commited on
Commit ·
c9689b3
1
Parent(s): bbf889c
SEC-DED decoder
Browse files- README.md +101 -0
- config.json +9 -0
- create_safetensors.py +186 -0
- model.safetensors +0 -0
README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- pytorch
|
| 5 |
+
- safetensors
|
| 6 |
+
- threshold-logic
|
| 7 |
+
- neuromorphic
|
| 8 |
+
- error-correction
|
| 9 |
+
- ecc
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# threshold-sec-ded
|
| 13 |
+
|
| 14 |
+
SEC-DED (8,4) decoder: Single Error Correct, Double Error Detect. Extends Hamming(7,4) with overall parity for double-error detection.
|
| 15 |
+
|
| 16 |
+
## Circuit
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
codeword[7:0] ──► SEC-DED ──┬──► data[3:0] (corrected)
|
| 20 |
+
├──► error (error detected)
|
| 21 |
+
└──► uncorrectable (double error)
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
## Codeword Format
|
| 25 |
+
|
| 26 |
+
```
|
| 27 |
+
Position: 7 6 5 4 3 2 1 0
|
| 28 |
+
Bit: d3 d2 d1 p3 d0 p2 p1 p0
|
| 29 |
+
|
| 30 |
+
p0 = overall parity (all bits)
|
| 31 |
+
p1 = parity of positions 1,3,5,7
|
| 32 |
+
p2 = parity of positions 2,3,6,7
|
| 33 |
+
p3 = parity of positions 4,5,6,7
|
| 34 |
+
d0-d3 = data bits
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
## Error Handling
|
| 38 |
+
|
| 39 |
+
| Syndrome | Overall Parity | Status |
|
| 40 |
+
|----------|----------------|--------|
|
| 41 |
+
| 0 | 0 | No error |
|
| 42 |
+
| ≠0 | 1 | Single error (correctable) |
|
| 43 |
+
| ≠0 | 0 | Double error (detected only) |
|
| 44 |
+
| 0 | 1 | Single error in p0 (correctable) |
|
| 45 |
+
|
| 46 |
+
## Architecture
|
| 47 |
+
|
| 48 |
+
| Component | Function | Neurons |
|
| 49 |
+
|-----------|----------|---------|
|
| 50 |
+
| Syndrome calc (s1,s2,s3) | XOR trees | ~63 |
|
| 51 |
+
| Overall parity | XOR tree | ~21 |
|
| 52 |
+
| Error logic | AND/OR | ~7 |
|
| 53 |
+
| Data correction | Conditional XOR | ~12 |
|
| 54 |
+
|
| 55 |
+
**Total: 95 neurons, 300 parameters, 4 layers**
|
| 56 |
+
|
| 57 |
+
## Capabilities
|
| 58 |
+
|
| 59 |
+
- **Correct**: Any single-bit error
|
| 60 |
+
- **Detect**: Any double-bit error
|
| 61 |
+
- **Miss**: Triple+ errors may be miscorrected
|
| 62 |
+
|
| 63 |
+
## Test Coverage
|
| 64 |
+
|
| 65 |
+
- 16 no-error cases: All pass
|
| 66 |
+
- 128 single-error cases: All corrected
|
| 67 |
+
- 448 double-error cases: All detected
|
| 68 |
+
|
| 69 |
+
## Usage
|
| 70 |
+
|
| 71 |
+
```python
|
| 72 |
+
from safetensors.torch import load_file
|
| 73 |
+
|
| 74 |
+
w = load_file('model.safetensors')
|
| 75 |
+
|
| 76 |
+
# Example: data=5 (0101)
|
| 77 |
+
# Encoded: 01010110 (with parity bits)
|
| 78 |
+
# Flip bit 3: 01011110
|
| 79 |
+
# Decoder: corrects to data=5, error=1, uncorrectable=0
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
## Applications
|
| 83 |
+
|
| 84 |
+
- ECC RAM (Error-Correcting Code memory)
|
| 85 |
+
- Data storage systems
|
| 86 |
+
- Communication channels
|
| 87 |
+
- Safety-critical systems
|
| 88 |
+
|
| 89 |
+
## Files
|
| 90 |
+
|
| 91 |
+
```
|
| 92 |
+
threshold-sec-ded/
|
| 93 |
+
├── model.safetensors
|
| 94 |
+
├── create_safetensors.py
|
| 95 |
+
├── config.json
|
| 96 |
+
└── README.md
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
## License
|
| 100 |
+
|
| 101 |
+
MIT
|
config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "threshold-sec-ded",
|
| 3 |
+
"description": "SEC-DED (8,4) decoder - single error correct, double error detect",
|
| 4 |
+
"inputs": 8,
|
| 5 |
+
"outputs": 6,
|
| 6 |
+
"neurons": 95,
|
| 7 |
+
"layers": 4,
|
| 8 |
+
"parameters": 300
|
| 9 |
+
}
|
create_safetensors.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors.torch import save_file
|
| 3 |
+
|
| 4 |
+
weights = {}
|
| 5 |
+
|
| 6 |
+
# SEC-DED (8,4) - Single Error Correct, Double Error Detect
|
| 7 |
+
# Based on Hamming(7,4) with overall parity bit
|
| 8 |
+
#
|
| 9 |
+
# Input: 8 bits [p0, p1, p2, d0, p3, d1, d2, d3] (positions 0-7)
|
| 10 |
+
# p0 = overall parity
|
| 11 |
+
# p1, p2, p3 = Hamming parity bits (positions 1, 2, 4)
|
| 12 |
+
# d0, d1, d2, d3 = data bits (positions 3, 5, 6, 7)
|
| 13 |
+
#
|
| 14 |
+
# Output: 4 corrected data bits, error_detected, uncorrectable
|
| 15 |
+
|
| 16 |
+
def add_xor_multi(name, indices, total):
|
| 17 |
+
for i, idx in enumerate(indices):
|
| 18 |
+
w = [0.0] * total
|
| 19 |
+
w[idx] = 1.0
|
| 20 |
+
weights[f'{name}.in{i}.weight'] = torch.tensor([w], dtype=torch.float32)
|
| 21 |
+
weights[f'{name}.in{i}.bias'] = torch.tensor([0.0], dtype=torch.float32)
|
| 22 |
+
n = len(indices)
|
| 23 |
+
if n == 2:
|
| 24 |
+
weights[f'{name}.or.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 25 |
+
weights[f'{name}.or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 26 |
+
weights[f'{name}.nand.weight'] = torch.tensor([[-1.0, -1.0]], dtype=torch.float32)
|
| 27 |
+
weights[f'{name}.nand.bias'] = torch.tensor([1.0], dtype=torch.float32)
|
| 28 |
+
weights[f'{name}.and.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 29 |
+
weights[f'{name}.and.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 30 |
+
|
| 31 |
+
def add_xor(name):
|
| 32 |
+
weights[f'{name}.or.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 33 |
+
weights[f'{name}.or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 34 |
+
weights[f'{name}.nand.weight'] = torch.tensor([[-1.0, -1.0]], dtype=torch.float32)
|
| 35 |
+
weights[f'{name}.nand.bias'] = torch.tensor([1.0], dtype=torch.float32)
|
| 36 |
+
weights[f'{name}.and.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 37 |
+
weights[f'{name}.and.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 38 |
+
|
| 39 |
+
# Syndrome calculation
|
| 40 |
+
# s1 = XOR of positions with bit 0 set: 1,3,5,7 → p1,d0,d1,d3
|
| 41 |
+
# s2 = XOR of positions with bit 1 set: 2,3,6,7 → p2,d0,d2,d3
|
| 42 |
+
# s3 = XOR of positions with bit 2 set: 4,5,6,7 → p3,d1,d2,d3
|
| 43 |
+
# overall = XOR of all 8 bits
|
| 44 |
+
|
| 45 |
+
# Using tree XOR for each syndrome bit
|
| 46 |
+
for i in range(4):
|
| 47 |
+
add_xor(f's1_l1_{i}')
|
| 48 |
+
for i in range(2):
|
| 49 |
+
add_xor(f's1_l2_{i}')
|
| 50 |
+
add_xor('s1_final')
|
| 51 |
+
|
| 52 |
+
for i in range(4):
|
| 53 |
+
add_xor(f's2_l1_{i}')
|
| 54 |
+
for i in range(2):
|
| 55 |
+
add_xor(f's2_l2_{i}')
|
| 56 |
+
add_xor('s2_final')
|
| 57 |
+
|
| 58 |
+
for i in range(4):
|
| 59 |
+
add_xor(f's3_l1_{i}')
|
| 60 |
+
for i in range(2):
|
| 61 |
+
add_xor(f's3_l2_{i}')
|
| 62 |
+
add_xor('s3_final')
|
| 63 |
+
|
| 64 |
+
for i in range(4):
|
| 65 |
+
add_xor(f'op_l1_{i}')
|
| 66 |
+
for i in range(2):
|
| 67 |
+
add_xor(f'op_l2_{i}')
|
| 68 |
+
add_xor('op_final')
|
| 69 |
+
|
| 70 |
+
# Error detection logic
|
| 71 |
+
# single_error = overall_parity AND (syndrome != 0)
|
| 72 |
+
# double_error = NOT overall_parity AND (syndrome != 0)
|
| 73 |
+
weights['syn_or.weight'] = torch.tensor([[1.0, 1.0, 1.0]], dtype=torch.float32)
|
| 74 |
+
weights['syn_or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 75 |
+
|
| 76 |
+
weights['single_err.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 77 |
+
weights['single_err.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 78 |
+
|
| 79 |
+
weights['not_op.weight'] = torch.tensor([[-1.0]], dtype=torch.float32)
|
| 80 |
+
weights['not_op.bias'] = torch.tensor([0.0], dtype=torch.float32)
|
| 81 |
+
|
| 82 |
+
weights['double_err.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 83 |
+
weights['double_err.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 84 |
+
|
| 85 |
+
# Correction XORs (flip bit if syndrome matches position)
|
| 86 |
+
for i in range(4):
|
| 87 |
+
add_xor(f'correct_d{i}')
|
| 88 |
+
|
| 89 |
+
save_file(weights, 'model.safetensors')
|
| 90 |
+
|
| 91 |
+
def xor_reduce(bits):
|
| 92 |
+
r = 0
|
| 93 |
+
for b in bits:
|
| 94 |
+
r ^= b
|
| 95 |
+
return r
|
| 96 |
+
|
| 97 |
+
def sec_ded_decode(codeword):
|
| 98 |
+
bits = [(codeword >> i) & 1 for i in range(8)]
|
| 99 |
+
p0, p1, p2, d0, p3, d1, d2, d3 = bits
|
| 100 |
+
|
| 101 |
+
s1 = xor_reduce([p1, d0, d1, d3])
|
| 102 |
+
s2 = xor_reduce([p2, d0, d2, d3])
|
| 103 |
+
s3 = xor_reduce([p3, d1, d2, d3])
|
| 104 |
+
overall = xor_reduce(bits)
|
| 105 |
+
|
| 106 |
+
syndrome = s1 + (s2 << 1) + (s3 << 2)
|
| 107 |
+
|
| 108 |
+
if syndrome == 0 and overall == 0:
|
| 109 |
+
error = 0
|
| 110 |
+
uncorrectable = 0
|
| 111 |
+
elif syndrome != 0 and overall == 1:
|
| 112 |
+
error = 1
|
| 113 |
+
uncorrectable = 0
|
| 114 |
+
if syndrome == 3:
|
| 115 |
+
d0 ^= 1
|
| 116 |
+
elif syndrome == 5:
|
| 117 |
+
d1 ^= 1
|
| 118 |
+
elif syndrome == 6:
|
| 119 |
+
d2 ^= 1
|
| 120 |
+
elif syndrome == 7:
|
| 121 |
+
d3 ^= 1
|
| 122 |
+
elif syndrome != 0 and overall == 0:
|
| 123 |
+
error = 1
|
| 124 |
+
uncorrectable = 1
|
| 125 |
+
else:
|
| 126 |
+
error = 1
|
| 127 |
+
uncorrectable = 0
|
| 128 |
+
|
| 129 |
+
data = d0 + (d1 << 1) + (d2 << 2) + (d3 << 3)
|
| 130 |
+
return data, error, uncorrectable
|
| 131 |
+
|
| 132 |
+
def encode_secded(data):
|
| 133 |
+
d0 = data & 1
|
| 134 |
+
d1 = (data >> 1) & 1
|
| 135 |
+
d2 = (data >> 2) & 1
|
| 136 |
+
d3 = (data >> 3) & 1
|
| 137 |
+
p1 = d0 ^ d1 ^ d3
|
| 138 |
+
p2 = d0 ^ d2 ^ d3
|
| 139 |
+
p3 = d1 ^ d2 ^ d3
|
| 140 |
+
codeword = p1 + (p2 << 1) + (d0 << 2) + (p3 << 3) + (d1 << 4) + (d2 << 5) + (d3 << 6)
|
| 141 |
+
p0 = xor_reduce([(codeword >> i) & 1 for i in range(7)])
|
| 142 |
+
return (codeword << 1) | p0
|
| 143 |
+
|
| 144 |
+
print("Verifying SEC-DED Decoder...")
|
| 145 |
+
errors = 0
|
| 146 |
+
|
| 147 |
+
for data in range(16):
|
| 148 |
+
cw = encode_secded(data)
|
| 149 |
+
decoded, err, unc = sec_ded_decode(cw)
|
| 150 |
+
if decoded != data or err != 0:
|
| 151 |
+
errors += 1
|
| 152 |
+
if errors <= 3:
|
| 153 |
+
print(f"No error case failed: data={data}")
|
| 154 |
+
|
| 155 |
+
for data in range(16):
|
| 156 |
+
cw = encode_secded(data)
|
| 157 |
+
for flip in range(8):
|
| 158 |
+
cw_err = cw ^ (1 << flip)
|
| 159 |
+
decoded, err, unc = sec_ded_decode(cw_err)
|
| 160 |
+
if decoded != data or err != 1 or unc != 0:
|
| 161 |
+
errors += 1
|
| 162 |
+
if errors <= 3:
|
| 163 |
+
print(f"Single error case failed: data={data}, flip={flip}")
|
| 164 |
+
|
| 165 |
+
for data in range(16):
|
| 166 |
+
cw = encode_secded(data)
|
| 167 |
+
for f1 in range(8):
|
| 168 |
+
for f2 in range(f1+1, 8):
|
| 169 |
+
cw_err = cw ^ (1 << f1) ^ (1 << f2)
|
| 170 |
+
decoded, err, unc = sec_ded_decode(cw_err)
|
| 171 |
+
if unc != 1:
|
| 172 |
+
errors += 1
|
| 173 |
+
if errors <= 3:
|
| 174 |
+
print(f"Double error case failed: data={data}, flip={f1},{f2}")
|
| 175 |
+
|
| 176 |
+
if errors == 0:
|
| 177 |
+
print("All test cases passed!")
|
| 178 |
+
print("- 16 no-error cases")
|
| 179 |
+
print("- 128 single-error cases (corrected)")
|
| 180 |
+
print("- 448 double-error cases (detected)")
|
| 181 |
+
else:
|
| 182 |
+
print(f"FAILED: {errors} errors")
|
| 183 |
+
|
| 184 |
+
mag = sum(t.abs().sum().item() for t in weights.values())
|
| 185 |
+
print(f"\nMagnitude: {mag:.0f}")
|
| 186 |
+
print(f"Parameters: {sum(t.numel() for t in weights.values())}")
|
model.safetensors
ADDED
|
Binary file (16.1 kB). View file
|
|
|