Skip to content

Commit

Permalink
Added a new option --slice-by.
Browse files Browse the repository at this point in the history
This option is still experimental and limited in its use.
  • Loading branch information
tpircher-zz committed Oct 6, 2015
1 parent fe67929 commit 7e56b14
Show file tree
Hide file tree
Showing 6 changed files with 432 additions and 226 deletions.
3 changes: 3 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ Matthias Urlichs: removed the unused 'direct' parameter and added a fix not to

Marti Raudsepp: improved spacin for the table-driven algorithm.

Stephan Brumme: his implementation of the slice-by-x algorithm was used as a
basis for the implementation in pycrc.

Danjel McGougan: whose Universal Crc project was highly influential in the
implementation of widths < 8 in the table-driven algorithm.
17 changes: 16 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
2015-10-06 Thomas Pircher <tehpeh-pycrc@tty1.net>

* AUTHORS:
Added Stephan Brumme as his implementation of the slice-by algorithm is the
basis for pycrc's implementation.

* crc_algorithms.py:
* crc_opt.py:
* crc_symtable.py:
Added a new option --slice-by. This option is still experimental and
limited in its use.

* test/test.py:
Added tests for --slice-by.

2015-09-12 Thomas Pircher <tehpeh-pycrc@tty1.net>

* crc_algorithms.py:
Expand All @@ -10,8 +25,8 @@
Run the code through pylint.
API change: changed the names of the member variables from CamelCase to the
format suggested in PEP 0008 (lowercase letters and words separated by

underscore).

2015-08-31 Thomas Pircher <tehpeh-pycrc@tty1.net>

* crc_opt.py:
Expand Down
15 changes: 10 additions & 5 deletions crc_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Crc(object):

# Class constructor
###############################################################################
def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width=None):
def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width=None, slice_by=1):
"""The Crc constructor.
The parameters are as follows:
Expand All @@ -75,6 +75,7 @@ def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_
self.reflect_out = reflect_out
self.xor_out = xor_out
self.tbl_idx_width = table_idx_width
self.slice_by = slice_by

self.msb_mask = 0x1 << (self.width - 1)
self.mask = ((self.msb_mask - 1) << 1) | 1
Expand Down Expand Up @@ -196,7 +197,7 @@ def gen_table(self):
instead.
"""
table_length = 1 << self.tbl_idx_width
tbl = [0] * table_length
tbl = [[0 for i in range(table_length)] for j in range(self.slice_by)]
for i in range(table_length):
reg = i
if self.reflect_in:
Expand All @@ -209,7 +210,11 @@ def gen_table(self):
reg = (reg << 1)
if self.reflect_in:
reg = self.reflect(reg >> self.crc_shift, self.width) << self.crc_shift
tbl[i] = reg & (self.mask << self.crc_shift)
tbl[0][i] = reg & (self.mask << self.crc_shift)

for j in range(1, self.slice_by):
for i in range(table_length):
tbl[j][i] = (tbl[j - 1][i] >> 8) ^ tbl[0][tbl[j - 1][i] & 0xff]
return tbl


Expand All @@ -231,13 +236,13 @@ def table_driven(self, in_data):
if not self.reflect_in:
for octet in in_data:
tblidx = ((reg >> (self.width - self.tbl_idx_width + self.crc_shift)) ^ octet) & 0xff
reg = ((reg << (self.tbl_idx_width - self.crc_shift)) ^ tbl[tblidx]) & (self.mask << self.crc_shift)
reg = ((reg << (self.tbl_idx_width - self.crc_shift)) ^ tbl[0][tblidx]) & (self.mask << self.crc_shift)
reg = reg >> self.crc_shift
else:
reg = self.reflect(reg, self.width + self.crc_shift) << self.crc_shift
for octet in in_data:
tblidx = ((reg >> self.crc_shift) ^ octet) & 0xff
reg = ((reg >> self.tbl_idx_width) ^ tbl[tblidx]) & (self.mask << self.crc_shift)
reg = ((reg >> self.tbl_idx_width) ^ tbl[0][tblidx]) & (self.mask << self.crc_shift)
reg = self.reflect(reg, self.width + self.crc_shift) & self.mask

if self.reflect_out:
Expand Down
121 changes: 70 additions & 51 deletions crc_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def __init__(self):
self.xor_out = None
self.tbl_idx_width = 8
self.tbl_width = 1 << self.tbl_idx_width
self.slice_by = 1
self.verbose = False
self.check_string = "123456789"
self.msb_mask = None
Expand Down Expand Up @@ -191,6 +192,11 @@ def parse(self, argv=None):
action="store", type="hex", dest="xor_out",
help="xor the final CRC value with HEX",
metavar="HEX")
parser.add_option(
"--slice-by",
action="store", type="int", dest="slice_by",
help="read NUM bytes at a time from the input. NUM must be one of the values {4, 8, 16}",
metavar="NUM")
parser.add_option(
"--table-idx-width",
action="store", type="int", dest="table_idx_width",
Expand Down Expand Up @@ -220,6 +226,15 @@ def parse(self, argv=None):

(options, args) = parser.parse_args(argv)

if options.c_std != None:
std = options.c_std.upper()
if std == "ANSI" or std == "C89":
self.c_std = "C89"
elif std == "C99":
self.c_std = std
else:
self.__error("unknown C standard {0:s}".format(options.c_std))

undefined_params = []
if options.width != None:
self.width = options.width
Expand Down Expand Up @@ -251,16 +266,11 @@ def parse(self, argv=None):
self.tbl_idx_width = options.table_idx_width
self.tbl_width = 1 << options.table_idx_width
else:
sys.stderr.write(
"{0:s}: error: unsupported table-idx-width {1:d}\n"
.format(sys.argv[0], options.table_idx_width))
sys.exit(1)
self.__error("unsupported table-idx-width {0:d}".format(options.table_idx_width))

if self.width != None:
if self.width <= 0:
sys.stderr.write(
"{0:s}: error: Width must be strictly positive\n".format(sys.argv[0]))
sys.exit(1)
self.__error("Width must be strictly positive")
self.msb_mask = 0x1 << (self.width - 1)
self.mask = ((self.msb_mask - 1) << 1) | 1
if self.poly != None:
Expand All @@ -283,6 +293,23 @@ def parse(self, argv=None):
else:
self.undefined_crc_parameters = False

if options.slice_by != None:
if options.slice_by in set((4, 8, 16)):
self.slice_by = options.slice_by
else:
self.__error("unsupported slice-by {0:d}".format(options.slice_by))
if self.undefined_crc_parameters:
self.__error("slice-by is only implemented for fully defined models")
if self.tbl_idx_width != 8:
self.__error("slice-by is only implemented for table-idx-width=8")
# FIXME tp: reintroduce this?
# if self.width % 8 != 0:
# self.__error("slice-by is only implemented for width multiples of 8")
# if options.slice_by < self.width / 8:
# self.__error("slice-by must be greater or equal width / 8")
if self.c_std == "C89":
self.__error("--slice-by not supported for C89")

if options.algorithm != None:
alg = options.algorithm.lower()
if alg in set(["bit-by-bit", "bbb", "all"]):
Expand All @@ -292,22 +319,8 @@ def parse(self, argv=None):
if alg in set(["table-driven", "tbl", "all"]):
self.algorithm |= self.algo_table_driven
if self.algorithm == 0:
sys.stderr.write(
"{0:s}: error: unknown algorithm {1:s}\n"
.format(sys.argv[0], options.algorithm))
sys.exit(1)
self.__error("unknown algorithm {0:s}".format(options.algorithm))

if options.c_std != None:
std = options.c_std.upper()
if std == "ANSI" or std == "C89":
self.c_std = "C89"
elif std == "C99":
self.c_std = std
else:
sys.stderr.write(
"{0:s}: error: unknown C standard {1:s}\n"
.format(sys.argv[0], options.c_std))
sys.exit(1)
if options.symbol_prefix != None:
self.symbol_prefix = options.symbol_prefix
if options.include_files != None:
Expand Down Expand Up @@ -340,56 +353,62 @@ def parse(self, argv=None):
elif arg == 'table':
self.action = self.action_generate_table
else:
sys.stderr.write(
"{0:s}: error: don't know how to generate {1:s}\n"
.format(sys.argv[0], options.generate))
sys.exit(1)
self.__error("don't know how to generate {0:s}".format(options.generate))
op_count += 1

if self.action == self.action_generate_table:
if self.algorithm & self.algo_table_driven == 0:
sys.stderr.write(
"{0:s}: error: the --generate table option is incompatible "
"with the --algorithm option\n".format(sys.argv[0]))
sys.exit(1)
self.__error("the --generate table option is incompatible "
"with the --algorithm option")
self.algorithm = self.algo_table_driven
elif self.algorithm not in set(
[self.algo_bit_by_bit, self.algo_bit_by_bit_fast, self.algo_table_driven]):
sys.stderr.write(
"{0:s}: error: select an algorithm to be used in the generated file\n"
.format(sys.argv[0]))
sys.exit(1)
self.__error("select an algorithm to be used in the generated file")
else:
if self.tbl_idx_width != 8:
sys.stderr.write(
"{0:s}: warning: reverting to Table Index Width = 8 "
"for internal CRC calculation\n"
.format(sys.argv[0]))
self.__warning("reverting to Table Index Width = 8 "
"for internal CRC calculation")
self.tbl_idx_width = 8
self.tbl_width = 1 << options.table_idx_width
if op_count == 0:
self.action = self.action_check_str
if op_count > 1:
sys.stderr.write(
"{0:s}: error: too many actions scecified\n".format(sys.argv[0]))
sys.exit(1)
self.__error("too many actions scecified")

if len(args) != 0:
sys.stderr.write(
"{0:s}: error: unrecognized argument(s): {1:s}\n"
.format(sys.argv[0], " ".join(args)))
sys.exit(1)
self.__error("unrecognized argument(s): {0:s}".format(" ".join(args)))

def_params_acts = (self.action_check_str, self.action_check_hex_str,
self.action_check_file, self.action_generate_table)
if self.undefined_crc_parameters and self.action in set(def_params_acts):
sys.stderr.write(
"{0:s}: error: undefined parameters: Add {1:s} or use --model\n"
.format(sys.argv[0], ", ".join(undefined_params)))
sys.exit(1)
self.__error("undefined parameters: Add {0:s} or use --model"
.format(", ".join(undefined_params)))
self.verbose = options.verbose



# function __warning
###############################################################################
def __warning(self, message):
"""
Print a warning message to stderr.
"""
sys.stderr.write(
"{0:s}: warning: {1:s}\n".format(sys.argv[0], message))



# function _error
###############################################################################
def __error(self, message):
"""
Print a error message to stderr and terminate the program.
"""
sys.stderr.write(
"{0:s}: error: {1:s}\n".format(sys.argv[0], message))
sys.exit(1)


# function _model_cb
##############################################################################
def _model_cb(option, opt_str, value, parser):
Expand Down Expand Up @@ -429,7 +448,7 @@ def _check_hex(dummy_option, opt, value):
return int(value)
except ValueError:
raise OptionValueError(
"option {0:s}: invalid integer or hexadecimal value: {1:r}.".format(opt, value))
"option {0:s}: invalid integer or hexadecimal value: {1:s}.".format(opt, value))


# function _check_bool
Expand All @@ -446,7 +465,7 @@ def _check_bool(dummy_option, opt, value):
elif value.lower() == "true":
return True
else:
raise OptionValueError("option {0:s}: invalid boolean value: {1:r}.".format(opt, value))
raise OptionValueError("option {0:s}: invalid boolean value: {1:s}.".format(opt, value))


# Class MyOption
Expand Down
Loading

0 comments on commit 7e56b14

Please sign in to comment.