|
| 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