summaryrefslogtreecommitdiff
path: root/libnandfs/hamming31_26.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnandfs/hamming31_26.c')
-rw-r--r--libnandfs/hamming31_26.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/libnandfs/hamming31_26.c b/libnandfs/hamming31_26.c
new file mode 100644
index 00000000..a94262b7
--- /dev/null
+++ b/libnandfs/hamming31_26.c
@@ -0,0 +1,62 @@
+#include "lib9.h"
+#include "logfs.h"
+#include "nandfs.h"
+
+static unsigned long row4 = 0x001fffc0;
+static unsigned long row3 = 0x0fe03fc0;
+static unsigned long row2 = 0x71e3c3c0;
+static unsigned long row1 = 0xb66cccc0;
+static unsigned long row0 = 0xdab55540;
+
+static char map[] = {
+ -5, -4, 0, -3, 1, 2, 3, -2,
+ 4, 5, 6, 7, 8, 9, 10, -1, 11,
+ 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25,
+};
+
+#define mashbits(rown) \
+ c = (in) & (rown); \
+ c ^= c >> 16; \
+ c ^= c >> 8; \
+ c ^= c >> 4; \
+ c ^= c >> 2; \
+ c = (c ^ (c >> 1)) & 1; \
+
+static uchar
+_nandfshamming31_26calcparity(ulong in)
+{
+ ulong c;
+ uchar out;
+ mashbits(row4); out = c;
+ mashbits(row3); out = (out << 1) | c;
+ mashbits(row2); out = (out << 1) | c;
+ mashbits(row1); out = (out << 1) | c;
+ mashbits(row0); out = (out << 1) | c;
+ return out;
+}
+
+ulong
+_nandfshamming31_26calc(ulong in)
+{
+ in &= 0xffffffc0;
+ return in | _nandfshamming31_26calcparity(in);
+}
+
+int
+_nandfshamming31_26correct(ulong *in)
+{
+ uchar eparity, parity;
+ ulong e;
+ eparity = _nandfshamming31_26calcparity(*in);
+ parity = (*in) & 0x1f;
+ e = eparity ^ parity;
+ if (e == 0)
+ return 0;
+ e--;
+ if (map[e] < 0)
+ return 1; // error in parity bits
+ e = map[e];
+ *in ^= 1 << (31 - e);
+ return 1;
+}