8b10b encoder and decoder working
Tested on all 24-bit inputs after sync and on ~500M of random input with and without intermediate sync
This commit is contained in:
parent
90038f4378
commit
132fd4f9c0
7 changed files with 271 additions and 65 deletions
3
fw/.gitignore
vendored
3
fw/.gitignore
vendored
|
|
@ -8,4 +8,5 @@
|
|||
sources.c
|
||||
sources.tar.xz
|
||||
sources.tar.xz.zip
|
||||
8b10b_test
|
||||
8b10b_test_decode
|
||||
8b10b_test_encode
|
||||
|
|
|
|||
136
fw/8b10b.c
136
fw/8b10b.c
|
|
@ -1,39 +1,42 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "8b10b.h"
|
||||
|
||||
static const struct entry_5b6b map_5b6b[32] = {
|
||||
{0b100111, 0b011000}, /* D.00 */
|
||||
{0b011101, 0b100010}, /* D.01 */
|
||||
{0b101101, 0b010010}, /* D.02 */
|
||||
{0b110001, 0b110001}, /* D.03 */
|
||||
{0b110101, 0b001010}, /* D.04 */
|
||||
{0b101001, 0b101001}, /* D.05 */
|
||||
{0b011001, 0b011001}, /* D.06 */
|
||||
{0b111000, 0b000111}, /* D.07 */
|
||||
{0b111001, 0b000110}, /* D.08 */
|
||||
{0b100101, 0b100101}, /* D.09 */
|
||||
{0b010101, 0b010101}, /* D.10 */
|
||||
{0b110100, 0b110100}, /* D.11 */
|
||||
{0b001101, 0b001101}, /* D.12 */
|
||||
{0b101100, 0b101100}, /* D.13 */
|
||||
{0b011100, 0b011100}, /* D.14 */
|
||||
{0b010111, 0b101000}, /* D.15 */
|
||||
{0b011011, 0b100100}, /* D.16 */
|
||||
{0b100011, 0b100011}, /* D.17 */
|
||||
{0b010011, 0b010011}, /* D.18 */
|
||||
{0b110010, 0b110010}, /* D.19 */
|
||||
{0b001011, 0b001011}, /* D.20 */
|
||||
{0b101010, 0b101010}, /* D.21 */
|
||||
{0b011010, 0b011010}, /* D.22 */
|
||||
{0b111010, 0b000101}, /* D.23 */
|
||||
{0b110011, 0b001100}, /* D.24 */
|
||||
{0b100110, 0b100110}, /* D.25 */
|
||||
{0b010110, 0b010110}, /* D.26 */
|
||||
{0b110110, 0b001001}, /* D.27 */
|
||||
{0b001110, 0b001110}, /* D.28 */
|
||||
{0b101110, 0b010001}, /* D.29 */
|
||||
{0b011110, 0b100001}, /* D.30 */
|
||||
{0b101011, 0b010100} /* D.31 */
|
||||
static const struct entry map_5b6b[32] = {
|
||||
{0b100111, 0b011000, 2}, /* D.00 */
|
||||
{0b011101, 0b100010, 2}, /* D.01 */
|
||||
{0b101101, 0b010010, 2}, /* D.02 */
|
||||
{0b110001, 0b110001, 0}, /* D.03 */
|
||||
{0b110101, 0b001010, 2}, /* D.04 */
|
||||
{0b101001, 0b101001, 0}, /* D.05 */
|
||||
{0b011001, 0b011001, 0}, /* D.06 */
|
||||
{0b111000, 0b000111, 0}, /* D.07 */
|
||||
{0b111001, 0b000110, 2}, /* D.08 */
|
||||
{0b100101, 0b100101, 0}, /* D.09 */
|
||||
{0b010101, 0b010101, 0}, /* D.10 */
|
||||
{0b110100, 0b110100, 0}, /* D.11 */
|
||||
{0b001101, 0b001101, 0}, /* D.12 */
|
||||
{0b101100, 0b101100, 0}, /* D.13 */
|
||||
{0b011100, 0b011100, 0}, /* D.14 */
|
||||
{0b010111, 0b101000, 2}, /* D.15 */
|
||||
{0b011011, 0b100100, 2}, /* D.16 */
|
||||
{0b100011, 0b100011, 0}, /* D.17 */
|
||||
{0b010011, 0b010011, 0}, /* D.18 */
|
||||
{0b110010, 0b110010, 0}, /* D.19 */
|
||||
{0b001011, 0b001011, 0}, /* D.20 */
|
||||
{0b101010, 0b101010, 0}, /* D.21 */
|
||||
{0b011010, 0b011010, 0}, /* D.22 */
|
||||
{0b111010, 0b000101, 2}, /* D.23 */
|
||||
{0b110011, 0b001100, 2}, /* D.24 */
|
||||
{0b100110, 0b100110, 0}, /* D.25 */
|
||||
{0b010110, 0b010110, 0}, /* D.26 */
|
||||
{0b110110, 0b001001, 2}, /* D.27 */
|
||||
{0b001110, 0b001110, 0}, /* D.28 */
|
||||
{0b101110, 0b010001, 2}, /* D.29 */
|
||||
{0b011110, 0b100001, 2}, /* D.30 */
|
||||
{0b101011, 0b010100, 2} /* D.31 */
|
||||
};
|
||||
|
||||
static const int8_t map_6b5b[64] = {
|
||||
|
|
@ -87,22 +90,22 @@ static const int8_t map_6b5b[64] = {
|
|||
[0b111010] = 23 /* rd = -1 */
|
||||
};
|
||||
|
||||
static const struct entry_5b6b K28 = {0b001111, 0b110000};
|
||||
static const struct entry K28 = {0b001111, 0b110000};
|
||||
|
||||
static const struct entry_3b4b map_d_3b4b[7] = {
|
||||
{0b1011, 0b0100}, /* D.x.0 */
|
||||
{0b1001, 0b1001}, /* D.x.1 */
|
||||
{0b0101, 0b0101}, /* D.x.2 */
|
||||
{0b1100, 0b0011}, /* D.x.3 */
|
||||
{0b1101, 0b0010}, /* D.x.4 */
|
||||
{0b1010, 0b1010}, /* D.x.5 */
|
||||
{0b0110, 0b0110} /* D.x.6 */
|
||||
static const struct entry map_3b4b_d[8] = {
|
||||
{0b1011, 0b0100, 2}, /* D.x.0 */
|
||||
{0b1001, 0b1001, 0}, /* D.x.1 */
|
||||
{0b0101, 0b0101, 0}, /* D.x.2 */
|
||||
{0b1100, 0b0011, 0}, /* D.x.3 */
|
||||
{0b1101, 0b0010, 2}, /* D.x.4 */
|
||||
{0b1010, 0b1010, 0}, /* D.x.5 */
|
||||
{0b0110, 0b0110, 0}, /* D.x.6 */
|
||||
{0b1110, 0b0001, 2} /* D.x.P7 */
|
||||
};
|
||||
|
||||
static const struct entry_3b4b Dx_P7 = {0b1110, 0b0001},
|
||||
Dx_A7 = {0b0111, 0b1000};
|
||||
static const struct entry Dx_A7 = {0b0111, 0b1000, 2};
|
||||
|
||||
static const struct entry_3b4b map_3b4b_k[8] = {
|
||||
static const struct entry map_3b4b_k[8] = {
|
||||
{0b1011, 0b0100}, /* K.x.0 */
|
||||
{0b0110, 0b1001}, /* K.x.1 */
|
||||
{0b1010, 0b0101}, /* K.x.2 */
|
||||
|
|
@ -147,12 +150,12 @@ static const uint16_t k_sym_map[K_CODES_LAST] = {
|
|||
[K30_7] = 0b0111101000
|
||||
};
|
||||
|
||||
void xfr_8b10b_reset(struct state_8b10b *st) {
|
||||
void xfr_8b10b_reset(struct state_8b10b_dec *st) {
|
||||
st->rx = 0;
|
||||
st->bit_ctr = 0; /* unsynchronized */
|
||||
}
|
||||
|
||||
int xfr_8b10b_feed_bit(struct state_8b10b *st, int bit) {
|
||||
int xfr_8b10b_feed_bit(struct state_8b10b_dec *st, int bit) {
|
||||
uint32_t pattern = st->rx = (st->rx<<1 | !!bit) & 0x3ff;
|
||||
uint16_t comma = k_sym_map[K28_1];
|
||||
if (pattern == comma || pattern == ((~comma)&0x3ff)) {
|
||||
|
|
@ -184,7 +187,44 @@ int xfr_8b10b_feed_bit(struct state_8b10b *st, int bit) {
|
|||
return -DECODING_IN_PROGRESS;
|
||||
}
|
||||
|
||||
bool xfr_8b10b_has_sync(struct state_8b10b *st) {
|
||||
bool xfr_8b10b_has_sync(struct state_8b10b_dec *st) {
|
||||
return st->bit_ctr != 0;
|
||||
}
|
||||
|
||||
void xfr_8b10b_encode_reset(struct state_8b10b_enc *st) {
|
||||
st->rd = -1;
|
||||
}
|
||||
|
||||
int xfr_8b10b_encode(struct state_8b10b_enc *st, int data) {
|
||||
if (data < 0) {
|
||||
if (-data >= sizeof(k_sym_map)/sizeof(k_sym_map[0]))
|
||||
return -EINVAL;
|
||||
|
||||
return k_sym_map[-data];
|
||||
}
|
||||
|
||||
if (data > 255)
|
||||
return -EINVAL;
|
||||
|
||||
int p5b = data&0x1f, p3b = data>>5;
|
||||
//fprintf(stderr, "\nrd %d data %x p5b %d p3b %d\n", st->rd, data, p5b, p3b);
|
||||
|
||||
int x5b = (st->rd == -1) ? map_5b6b[p5b].rd_neg : map_5b6b[p5b].rd_pos;
|
||||
st->rd -= map_5b6b[p5b].disp * st->rd;
|
||||
//fprintf(stderr, "\nnow: rd %d data %x p5b %d p3b %d\n", st->rd, data, p5b, p3b);
|
||||
assert(st->rd == -1 || st->rd == 1);
|
||||
|
||||
int x3b = (st->rd == -1) ? map_3b4b_d[p3b].rd_neg : map_3b4b_d[p3b].rd_pos;
|
||||
if (p3b == 7) {
|
||||
if ( (st->rd == -1 && (p5b == 17 || p5b == 18 || p5b == 20))
|
||||
|| (st->rd == 1 && (p5b == 11 || p5b == 13 || p5b == 14))) {
|
||||
//fprintf(stderr, "A7 override\n");
|
||||
x3b = (st->rd == -1) ? Dx_A7.rd_neg : Dx_A7.rd_pos;
|
||||
}
|
||||
}
|
||||
st->rd -= map_3b4b_d[p3b].disp * st->rd; /* D.x.A7 and D.x.P7 both have parity 2 */
|
||||
assert(st->rd == -1 || st->rd == 1);
|
||||
|
||||
return x5b<<4 | x3b;
|
||||
}
|
||||
|
||||
|
|
|
|||
23
fw/8b10b.h
23
fw/8b10b.h
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
enum k_code {
|
||||
K28_0=1, K28_1, K28_2, K28_3,
|
||||
|
|
@ -17,22 +18,24 @@ enum decoder_return_codes {
|
|||
DECODING_IN_PROGRESS
|
||||
};
|
||||
|
||||
struct entry_3b4b {
|
||||
uint8_t rd_neg, rd_pos;
|
||||
struct entry {
|
||||
uint8_t rd_neg, rd_pos, disp;
|
||||
};
|
||||
|
||||
struct entry_5b6b {
|
||||
uint8_t rd_neg, rd_pos;
|
||||
};
|
||||
|
||||
struct state_8b10b {
|
||||
struct state_8b10b_dec {
|
||||
uint32_t rx;
|
||||
int bit_ctr;
|
||||
};
|
||||
|
||||
struct state_8b10b_enc {
|
||||
int rd;
|
||||
};
|
||||
|
||||
void xfr_8b10b_reset(struct state_8b10b *st);
|
||||
int xfr_8b10b_feed_bit(struct state_8b10b *st, int bit);
|
||||
bool xfr_8b10b_has_sync(struct state_8b10b *st);
|
||||
void xfr_8b10b_reset(struct state_8b10b_dec *st);
|
||||
int xfr_8b10b_feed_bit(struct state_8b10b_dec *st, int bit);
|
||||
bool xfr_8b10b_has_sync(struct state_8b10b_dec *st);
|
||||
|
||||
void xfr_8b10b_encode_reset(struct state_8b10b_enc *st);
|
||||
int xfr_8b10b_encode(struct state_8b10b_enc *st, int data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ static const char * const rc_names[] = {
|
|||
};
|
||||
|
||||
int main(void) {
|
||||
struct state_8b10b st;
|
||||
|
||||
struct state_8b10b_dec st;
|
||||
xfr_8b10b_reset(&st);
|
||||
|
||||
int c;
|
||||
|
|
@ -33,14 +32,18 @@ int main(void) {
|
|||
if (comment) {
|
||||
if (c == '\n')
|
||||
comment = 0;
|
||||
printf("%c", c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\r' || c == ' ' || c == '\t' || c == '\n')
|
||||
if (c == '\r' || c == ' ' || c == '\t' || c == '\n') {
|
||||
printf("%c", c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '#') {
|
||||
comment = 1;
|
||||
printf("%c", c);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -57,9 +60,13 @@ int main(void) {
|
|||
char sync_status = xfr_8b10b_has_sync(&st) ? 'S' : 'U';
|
||||
|
||||
if (read_result >= 0) {
|
||||
fprintf(stdout, "%c%02x ", sync_status, read_result);
|
||||
//fprintf(stdout, "%c%02x ", sync_status, read_result);
|
||||
fprintf(stdout, "%02x", read_result);
|
||||
|
||||
} else {
|
||||
if (-read_result == DECODING_IN_PROGRESS)
|
||||
continue;
|
||||
|
||||
if (-read_result > sizeof(rc_names)/sizeof(rc_names[0])) {
|
||||
fprintf(stderr, "Illegal read result %d. Exiting.\n", read_result);
|
||||
return 2;
|
||||
|
|
@ -71,7 +78,8 @@ int main(void) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
fprintf(stdout, "%c%s ", sync_status, msg);
|
||||
//fprintf(stdout, "%c%s ", sync_status, msg);
|
||||
fprintf(stdout, "%s", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
108
fw/8b10b_test_encode.c
Normal file
108
fw/8b10b_test_encode.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "8b10b.h"
|
||||
|
||||
static const char * const rc_names[] = {
|
||||
[K28_0] = "K.28.0",
|
||||
[K28_1] = "K.28.1",
|
||||
[K28_2] = "K.28.2",
|
||||
[K28_3] = "K.28.3",
|
||||
[K28_4] = "K.28.4",
|
||||
[K28_5] = "K.28.5",
|
||||
[K28_6] = "K.28.6",
|
||||
[K28_7] = "K.28.7",
|
||||
[K23_7] = "K.23.7",
|
||||
[K27_7] = "K.27.7",
|
||||
[K29_7] = "K.29.7",
|
||||
[K30_7] = "K.30.7",
|
||||
};
|
||||
|
||||
int hex_to_uint(const char *s, size_t len) {
|
||||
if (len > 7)
|
||||
return -2;
|
||||
|
||||
int acc = 0;
|
||||
for (int i=0; i<len; i++) {
|
||||
int digit = s[i];
|
||||
if ('0' <= digit && digit <= '9')
|
||||
digit -= '0';
|
||||
else if ('a' <= digit && digit <= 'f')
|
||||
digit -= 'a' - 0xa;
|
||||
else if ('A' <= digit && digit <= 'F')
|
||||
digit -= 'A' - 0xA;
|
||||
else return -1;
|
||||
acc = acc << 4 | digit;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct state_8b10b_enc st;
|
||||
xfr_8b10b_encode_reset(&st);
|
||||
|
||||
int c;
|
||||
int comment = 0;
|
||||
char parse_buf[32];
|
||||
int parse_buf_pos = 0;
|
||||
while ((c=fgetc(stdin)) != EOF) {
|
||||
if (comment) {
|
||||
if (c == '\n')
|
||||
comment = 0;
|
||||
printf("%c", c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '#') {
|
||||
comment = 1;
|
||||
printf("%c", c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c != '\r' && c != ' ' && c != '\t' && c != '\n') {
|
||||
parse_buf[parse_buf_pos++] = (char)c;
|
||||
if (parse_buf_pos == sizeof(parse_buf)) {
|
||||
parse_buf[sizeof(parse_buf)-1] = '\0';
|
||||
fprintf(stderr, "Parse error: Token \"%s[...]\" too long. Exiting.\n", parse_buf);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parse_buf_pos == 0)
|
||||
continue;
|
||||
|
||||
int data = 0;
|
||||
for (int i=1; i<sizeof(rc_names)/sizeof(rc_names[0]); i++) {
|
||||
if (!strncmp(rc_names[i], parse_buf, parse_buf_pos)) {
|
||||
data = -i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
data = hex_to_uint(parse_buf, parse_buf_pos);
|
||||
if (data < 0) {
|
||||
parse_buf[parse_buf_pos] = '\0';
|
||||
fprintf(stderr, "Invalid hex number: \"%s\"\n", parse_buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
parse_buf_pos = 0; /* reset for next token */
|
||||
|
||||
int encoded = xfr_8b10b_encode(&st, data);
|
||||
if (encoded < 0) {
|
||||
fprintf(stderr, "Invalid argument error encoding\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (int i=0; i<10; i++)
|
||||
printf("%c", (encoded & (1<<(9-i))) ? '1' : '0');
|
||||
|
||||
printf("%c", c); /* print whitespace character */
|
||||
}
|
||||
}
|
||||
|
||||
43
fw/8b10b_test_vector_gen.py
Executable file
43
fw/8b10b_test_vector_gen.py
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
def parse_size(s):
|
||||
s = s.lower()
|
||||
SUFFIXES = {'k': 1e3, 'm': 1e6, 'g': 1e9}
|
||||
if s[-1] in SUFFIXES:
|
||||
return int(int(s[:-1]) * SUFFIXES[s[-1]])
|
||||
return int(s)
|
||||
|
||||
def hexdump(data, byte_per_line=64):
|
||||
for i in range(0, len(data), byte_per_line):
|
||||
out = data[i:i+byte_per_line]
|
||||
print(' '.join(f'{out[k]:02x}' for k in range(len(out)))) # use len(out) to handle partial lines
|
||||
|
||||
if __name__ == '__main__':
|
||||
from itertools import product
|
||||
import os
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('cmd')
|
||||
parser.add_argument('-l', '--length', default='1M', help='Generate [length} byte test vector. Only applicable to random.')
|
||||
parser.add_argument('-s', '--syncfreq', default=None, help='Emit comma every [syncfreq] bytes. Default: don\'t emit any commas. Only applicable to random.')
|
||||
args = parser.parse_args()
|
||||
|
||||
length = parse_size(args.length)
|
||||
syncfreq = parse_size(args.syncfreq)
|
||||
|
||||
|
||||
if args.cmd == 'exhaustive_separated':
|
||||
for i, j, k in product(range(256), range(256), range(256)):
|
||||
print(f'K.28.1 {i:02x} {j:02x} {k:02x}')
|
||||
|
||||
elif args.cmd == 'exhaustive_block':
|
||||
print('K.28.1')
|
||||
for i, j, k in product(range(256), range(256), range(256)):
|
||||
print(f'{i:02x} {j:02x} {k:02x}')
|
||||
|
||||
elif args.cmd == 'random':
|
||||
for chunk in range(0, length, syncfreq):
|
||||
print('K.28.1')
|
||||
hexdump(os.urandom(min(length-chunk, syncfreq)))
|
||||
|
||||
|
|
@ -86,7 +86,10 @@ main.elf: main.o startup_stm32f030x6.o system_stm32f0xx.o $(HAL_PATH)/Src/stm32f
|
|||
program: main.elf openocd.cfg
|
||||
openocd -f openocd.cfg -c "program $< verify reset exit"
|
||||
|
||||
8b10b_test: 8b10b_test.c 8b10b.c
|
||||
8b10b_test_encode: 8b10b_test_encode.c 8b10b.c
|
||||
gcc -o $@ $^
|
||||
|
||||
8b10b_test_decode: 8b10b_test_decode.c 8b10b.c
|
||||
gcc -o $@ $^
|
||||
|
||||
clean:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue