Skip to content

Commit eb6ccda

Browse files
committed
Added rs-poly.py to help precompute generator polynomials
Not needed for ramrsbd (we always compute the generator polynomial during block device initialization), but may be useful for other implementations. This is an example project after all. Tested manually against the generator polynomials produced by ramrsbd for the tests.
1 parent a6c9320 commit eb6ccda

File tree

2 files changed

+174
-1
lines changed

2 files changed

+174
-1
lines changed

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,18 @@ noting:
13311331
precomputing and storing the generator polynomial in ROM will save a
13321332
couple (`ecc_size`) bytes of RAM.
13331333

1334-
TODO add a script?
1334+
[rs-poly.py][rs-poly.py] can help with this:
1335+
1336+
``` bash
1337+
$ ./rs-poly.py 8
1338+
// generator polynomial for ecc_size=8
1339+
//
1340+
// P(x) = prod_i^n-1 (x - g^i)
1341+
//
1342+
static const uint8_t RAMRSBD_P[8] = {
1343+
0xff, 0x0b, 0x51, 0x36, 0xef, 0xad, 0xc8, 0x18,
1344+
};
1345+
```
13351346

13361347
3. Minimizing the number of buffers.
13371348

rs-poly.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#!/usr/bin/env python3
2+
3+
import itertools as it
4+
import functools as ft
5+
import operator as op
6+
7+
8+
GF_POW = []
9+
GF_LOG = []
10+
11+
# build the GF_POW/GF_LOG tables
12+
def build_gf_tables(p):
13+
global GF_POW
14+
global GF_LOG
15+
pow_table = []
16+
log_table = {}
17+
18+
x = 1
19+
for i in range(256):
20+
pow_table.append(x)
21+
if x not in log_table:
22+
log_table[x] = i
23+
24+
x <<= 1
25+
if x & 0x100:
26+
x ^= p
27+
28+
GF_POW = pow_table
29+
GF_LOG = [log_table.get(i, 0xff) for i in range(256)]
30+
31+
# GF(256) operations
32+
def gf_mul(a, b):
33+
if a == 0 or b == 0:
34+
return 0
35+
36+
x = GF_LOG[a] + GF_LOG[b]
37+
if x > 255:
38+
x -= 255
39+
return GF_POW[x]
40+
41+
def gf_div(a, b):
42+
assert b != 0
43+
44+
x = GF_LOG[a] + 255 - GF_LOG[b]
45+
if x > 255:
46+
x -= 255
47+
return GF_POW[x]
48+
49+
def gf_pow(a, e):
50+
if e == 0:
51+
return 1
52+
elif a == 0:
53+
return 0
54+
else:
55+
x = (GF_LOG[a] * e) % 255
56+
return GF_POW[x]
57+
58+
59+
# GF(256) polynomial operations
60+
def gf_p_eval(p, x):
61+
y = 0
62+
for p_ in p:
63+
y = gf_mul(y, x) ^ p_
64+
return y
65+
66+
def gf_p_scale(p, c):
67+
return [gf_mul(p_, c) for p_ in p]
68+
69+
def gf_p_xor(a, b):
70+
r = [0]*max(len(a), len(b))
71+
for i, a_ in enumerate(a):
72+
r[i + len(r)-len(a)] ^= a_
73+
for i, b_ in enumerate(b):
74+
r[i + len(r)-len(b)] ^= b_
75+
return r
76+
77+
def gf_p_mul(a, b):
78+
r = [0]*(len(a)+len(b)-1)
79+
for i, a_ in enumerate(a):
80+
for j, b_ in enumerate(b):
81+
r[i+j] ^= gf_mul(a_, b_)
82+
return r
83+
84+
def gf_p_divmod(a, b):
85+
assert len(a) >= len(b)
86+
r = a.copy()
87+
for i in range(len(a)-len(b)+1):
88+
if r[i] != 0:
89+
r[i] = gf_div(r[i], b[0])
90+
91+
for j, b_ in enumerate(b[1:]):
92+
r[i+j] ^= gf_mul(r[i], b_)
93+
return r
94+
95+
96+
def main(ecc_size, *,
97+
p=None,
98+
no_truncate=False):
99+
# first build our GF_POW/GF_LOG tables based on p
100+
build_gf_tables(p)
101+
102+
# calculate generator polynomial
103+
#
104+
# P(x) = prod_i^n-1 (x - g^i)
105+
#
106+
# the important property of P(x) is that it evaluates to 0
107+
# at every x=g^i for i < n
108+
#
109+
p = ft.reduce(
110+
gf_p_mul,
111+
([1, gf_pow(2, i)] for i in range(ecc_size)),
112+
[1])
113+
114+
# print the generator polynomial
115+
print("// generator polynomial for ecc_size=%s" % ecc_size)
116+
print("//")
117+
print("// P(x) = prod_i^n-1 (x - g^i)")
118+
print("//")
119+
print("static const uint8_t RAMRSBD_P[%s] = {" % (
120+
len(p) if no_truncate else len(p[1:])))
121+
if no_truncate:
122+
print(" ", end='')
123+
print("0x%02x," % p[0])
124+
for j in range((len(p[1:])+8-1)//8):
125+
print(" ", end='')
126+
for i in range(8):
127+
if j*8+i < len(p[1:]):
128+
print("%s0x%02x," % (
129+
" " if i != 0 else "",
130+
p[1:][j*8+i]),
131+
end='')
132+
print()
133+
print("};")
134+
print()
135+
136+
137+
if __name__ == "__main__":
138+
import sys
139+
import argparse
140+
parser = argparse.ArgumentParser(
141+
description="Generate the generator polynomial for a Reed-Solomon code "
142+
"with the specified ecc_size.",
143+
allow_abbrev=False)
144+
parser.add_argument(
145+
'ecc_size',
146+
type=lambda x: int(x, 0),
147+
help="Size of the error-correcting code in bytes. The resulting "
148+
"polynomial will also be this size.")
149+
parser.add_argument(
150+
'-p',
151+
type=lambda x: int(x, 0),
152+
default=0x11d,
153+
help="The irreducible polynomial that defines the field. Defaults to "
154+
"0x11d")
155+
parser.add_argument(
156+
'-T', '--no-truncate',
157+
action='store_true',
158+
help="Including the leading 1 byte. This makes the resulting "
159+
"polynomial ecc_size+1 bytes.")
160+
sys.exit(main(**{k: v
161+
for k, v in vars(parser.parse_args()).items()
162+
if v is not None}))

0 commit comments

Comments
 (0)