Skip to content

Commit 9a0e63f

Browse files
committed
70046: Added Error correction
1 parent b6e8889 commit 9a0e63f

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
## Fault Sources
2+
- Radiation (alpha particles hitting silicon and inducing enough charge to cause a bit flip)
3+
- Hardware breakage (by manufacturing or over lifetime due to aging)
4+
## Error Detection
5+
### Parity Bits
6+
Adding a single bit to a set of bits that represents the number of `1`s.
7+
- Can detect an odd number of fault events (as this changes the parity bit)
8+
9+
We can include multiple check parity bits to allow error correction (to deduce which bit was flipped, given a single fault).
10+
```rust
11+
P0 = parity(D0, D1, D3)
12+
P1 = parity(D0, D2, D3)
13+
P2 = parity(D1, D2, D3)
14+
15+
// If only one of P0, P1, P2 is unchanged, then we can deduce which data bit was changed
16+
```
17+
Each data bit needs to affect a different combination of check bits to allow us to infer the data bit changed, from the check bit change.
18+
$$2^n -n - 1 \ \text{data bits are covered by} \ n \ \text{ parity bits}$$
19+
- $n$ bits means $2^n$ combinations
20+
- of the $2^n$ combinations, only $n$ affect a single bit (`...010...`)
21+
- one combination should change no bits (no parity change)
22+
```python
23+
def parity(bits: list[bool]) -> bool:
24+
    """ Parity as the number of 1s is odd=True, even=False """
25+
    return bool(sum(bits) % 2)
26+
27+
def gen_indexes(size: int) -> list[set[int]]:
28+
    """ Generate the parity indexes for `size` data bits
29+
        [index{parity indices... }, ]
30+
        - If all parities chan ge except index, then index was flipped.
31+
        - The set contains the bit indicies to calculate parity
32+
    """
33+
    return [{j for j in range(size) if j != i} for i in range(size)]
34+
35+
def gen_parity_bits(data_bits: list[bool]) -> list[bool]:
36+
    """ Get the error correction bits """
37+
    return [parity([data_bits[i] for i in s]) for s in gen_indexes(len(data_bits))]
38+
39+
def check(data_bits: list[bool], parity_bits: list[bool]) -> int | None | str:
40+
    """ Compares the parity
41+
    single fault => (all except one parity bit are flipped) then
42+
    return the data bit index flipped
43+
    string       => double fault
44+
    none         => no change
45+
    """
46+
    same_index: int | None = None
47+
    differing: bool = False
48+
    for i, (o, n) in enumerate(zip(parity_bits, gen_parity_bits(data_bits))):
49+
        if o == n:
50+
            if same_index is not None and differing:
51+
                return "Double fault"
52+
            same_index = i
53+
        else:
54+
            differing = True
55+
    return same_index
56+
57+
original_bits = [True, True, False, False, True]
58+
original_parity = gen_parity_bits(original_bits)
59+
new_bits = [True, False, False, False, True]
60+
new_parity = gen_parity_bits(new_bits)
61+
assert check(new_bits, original_parity) == 1
62+
```
63+
64+
We can also add an extra bit fir the parity of the parity bits (to detect double faults)
65+
### Basic Checksum
66+
Add all data words together (ignoring carry) and store result.
67+
- Easy to compute
68+
- Errors can cancel out (no error detected)
69+
### Modified Checksum
70+
On every carry, add a 1 instead, this way carry information is not entirely lost.
71+
- Errors can still cancel out
72+
### Cyclic Redundancy Check
73+
Use polynomial division
74+
[[TODO]]

0 commit comments

Comments
 (0)