diff options
author | jaseg <git@jaseg.net> | 2018-12-20 22:42:17 +0900 |
---|---|---|
committer | jaseg <git@jaseg.net> | 2018-12-20 22:42:17 +0900 |
commit | 132fd4f9c0184be033533953cc2c7ae92da311d9 (patch) | |
tree | 634c961de6168237d915e459c53fb6d5f1aed8b3 | |
parent | 90038f4378b7cdbe98e32ed1e5e3055dbe4776f2 (diff) | |
download | 8seg-132fd4f9c0184be033533953cc2c7ae92da311d9.tar.gz 8seg-132fd4f9c0184be033533953cc2c7ae92da311d9.tar.bz2 8seg-132fd4f9c0184be033533953cc2c7ae92da311d9.zip |
8b10b encoder and decoder working
Tested on all 24-bit inputs after sync and on ~500M of random input
with and without intermediate sync
-rw-r--r-- | fw/.gitignore | 3 | ||||
-rw-r--r-- | fw/8b10b.c | 138 | ||||
-rw-r--r-- | fw/8b10b.h | 23 | ||||
-rw-r--r-- | fw/8b10b_test_decode.c (renamed from fw/8b10b_test.c) | 18 | ||||
-rw-r--r-- | fw/8b10b_test_encode.c | 108 | ||||
-rwxr-xr-x | fw/8b10b_test_vector_gen.py | 43 | ||||
-rw-r--r-- | fw/Makefile | 5 |
7 files changed, 272 insertions, 66 deletions
diff --git a/fw/.gitignore b/fw/.gitignore index 3e36fab..ed41bfa 100644 --- a/fw/.gitignore +++ b/fw/.gitignore @@ -8,4 +8,5 @@ sources.c sources.tar.xz sources.tar.xz.zip -8b10b_test +8b10b_test_decode +8b10b_test_encode @@ -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_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 K28 = {0b001111, 0b110000}; + +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; +} + @@ -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_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_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_encode_reset(struct state_8b10b_enc *st); +int xfr_8b10b_encode(struct state_8b10b_enc *st, int data); #endif diff --git a/fw/8b10b_test.c b/fw/8b10b_test_decode.c index d11e6b2..433f7b8 100644 --- a/fw/8b10b_test.c +++ b/fw/8b10b_test_decode.c @@ -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); } } } diff --git a/fw/8b10b_test_encode.c b/fw/8b10b_test_encode.c new file mode 100644 index 0000000..2ba75d9 --- /dev/null +++ b/fw/8b10b_test_encode.c @@ -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 */ + } +} + diff --git a/fw/8b10b_test_vector_gen.py b/fw/8b10b_test_vector_gen.py new file mode 100755 index 0000000..12460c1 --- /dev/null +++ b/fw/8b10b_test_vector_gen.py @@ -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))) + diff --git a/fw/Makefile b/fw/Makefile index 1098717..b779789 100644 --- a/fw/Makefile +++ b/fw/Makefile @@ -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: |