crcglot 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
crcglot-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,85 @@
1
+ Metadata-Version: 2.4
2
+ Name: crcglot
3
+ Version: 0.1.0
4
+ Summary: Verified CRC source-code for C, Rust, VHDL, Python — catalogue-driven, self-test embedded.
5
+ Keywords: crc,checksum,code-generation,embedded,reveng,rocksoft,williams
6
+ Author: Chuck Bass
7
+ Author-email: Chuck Bass <chuck@acrocad.net>
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Code Generators
20
+ Classifier: Topic :: Software Development :: Embedded Systems
21
+ Requires-Python: >=3.11
22
+ Project-URL: Homepage, https://github.com/hucker/crcglot
23
+ Project-URL: Repository, https://github.com/hucker/crcglot
24
+ Project-URL: Issues, https://github.com/hucker/crcglot/issues
25
+ Description-Content-Type: text/markdown
26
+
27
+ # crcglot
28
+
29
+ **Verified CRC source code for C, Rust, VHDL, and Python.** Catalogue-driven, self-test embedded, multi-language by design.
30
+
31
+ LLMs will gladly write you CRC code. It might even be right. `crcglot` guarantees the generated code matches the canonical [reveng catalogue](https://reveng.sourceforge.io/crc-catalogue/all.htm) test vector (`crc("123456789") == <check value>`) and ships a self-test you can run on your toolchain to prove it.
32
+
33
+ ## Quick start
34
+
35
+ ```bash
36
+ pip install crcglot
37
+
38
+ crcglot c crc32 --slice8 file=mycrc # → mycrc.h + mycrc.c
39
+ crcglot rust crc64-xz --slice8 > mycrc.rs
40
+ crcglot vhdl crc32 > mycrc.vhd
41
+ crcglot python crc16-modbus > mycrc.py
42
+
43
+ crcglot list # browse the catalogue
44
+ crcglot info crc32 # show parameters
45
+ ```
46
+
47
+ ## What you get per language
48
+
49
+ | Function | Purpose |
50
+ | --- | --- |
51
+ | `<fname>_init` / `_update` / `_finalize` | Streaming triple — feed data chunk by chunk |
52
+ | `<fname>` | One-shot wrapper that calls the streaming triple |
53
+ | `<fname>_self_test` | Verify against the reveng check value on your toolchain |
54
+
55
+ C / Rust / VHDL ship `_self_test()` returning 0/1 (or boolean for VHDL). Python verifies via the docstring's `check:` line — the same interpreter generated it.
56
+
57
+ ## Implementations
58
+
59
+ | Flag | Description | Width support |
60
+ | --- | --- | --- |
61
+ | (default) bit-by-bit | Smallest code, zero RAM table, slowest | All |
62
+ | `--table` | 256-entry lookup table, 4-8× faster | All |
63
+ | `--slice8` | 8 lookup tables, 5-10× faster than `--table` | CRC-32 / CRC-64 only |
64
+
65
+ Each generated file embeds the chosen implementation and the self-test. In constrained embedded targets, standard toolchain flags (`-Wl,--gc-sections` for C, LTO for Rust) strip whatever you don't call.
66
+
67
+ ## Custom polynomials
68
+
69
+ For algorithms not in the catalogue, pass Rocksoft/Williams parameters directly:
70
+
71
+ ```bash
72
+ crcglot c --custom width=16 poly=0x1234 init=0xFFFF refin=true refout=true xorout=0x0000 file=mycustom
73
+ ```
74
+
75
+ ## Catalogue
76
+
77
+ 64+ algorithms covering everything from CRC-8 (ATM, AUTOSAR, Bluetooth, Maxim 1-Wire) through CRC-16 (Modbus, XMODEM, CCITT, IBM SDLC) through CRC-32 (Ethernet, bzip2, iSCSI, AUTOSAR) to CRC-64 (XZ, ECMA-182, NVMe, Redis). Browse with `crcglot list`.
78
+
79
+ ## Acknowledgments
80
+
81
+ CRC catalogue data is derived from Greg Cook's [reveng project](https://reveng.sourceforge.io/) — the canonical source for CRC algorithm parameters since 1999.
82
+
83
+ ## License
84
+
85
+ MIT
@@ -0,0 +1,59 @@
1
+ # crcglot
2
+
3
+ **Verified CRC source code for C, Rust, VHDL, and Python.** Catalogue-driven, self-test embedded, multi-language by design.
4
+
5
+ LLMs will gladly write you CRC code. It might even be right. `crcglot` guarantees the generated code matches the canonical [reveng catalogue](https://reveng.sourceforge.io/crc-catalogue/all.htm) test vector (`crc("123456789") == <check value>`) and ships a self-test you can run on your toolchain to prove it.
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ pip install crcglot
11
+
12
+ crcglot c crc32 --slice8 file=mycrc # → mycrc.h + mycrc.c
13
+ crcglot rust crc64-xz --slice8 > mycrc.rs
14
+ crcglot vhdl crc32 > mycrc.vhd
15
+ crcglot python crc16-modbus > mycrc.py
16
+
17
+ crcglot list # browse the catalogue
18
+ crcglot info crc32 # show parameters
19
+ ```
20
+
21
+ ## What you get per language
22
+
23
+ | Function | Purpose |
24
+ | --- | --- |
25
+ | `<fname>_init` / `_update` / `_finalize` | Streaming triple — feed data chunk by chunk |
26
+ | `<fname>` | One-shot wrapper that calls the streaming triple |
27
+ | `<fname>_self_test` | Verify against the reveng check value on your toolchain |
28
+
29
+ C / Rust / VHDL ship `_self_test()` returning 0/1 (or boolean for VHDL). Python verifies via the docstring's `check:` line — the same interpreter generated it.
30
+
31
+ ## Implementations
32
+
33
+ | Flag | Description | Width support |
34
+ | --- | --- | --- |
35
+ | (default) bit-by-bit | Smallest code, zero RAM table, slowest | All |
36
+ | `--table` | 256-entry lookup table, 4-8× faster | All |
37
+ | `--slice8` | 8 lookup tables, 5-10× faster than `--table` | CRC-32 / CRC-64 only |
38
+
39
+ Each generated file embeds the chosen implementation and the self-test. In constrained embedded targets, standard toolchain flags (`-Wl,--gc-sections` for C, LTO for Rust) strip whatever you don't call.
40
+
41
+ ## Custom polynomials
42
+
43
+ For algorithms not in the catalogue, pass Rocksoft/Williams parameters directly:
44
+
45
+ ```bash
46
+ crcglot c --custom width=16 poly=0x1234 init=0xFFFF refin=true refout=true xorout=0x0000 file=mycustom
47
+ ```
48
+
49
+ ## Catalogue
50
+
51
+ 64+ algorithms covering everything from CRC-8 (ATM, AUTOSAR, Bluetooth, Maxim 1-Wire) through CRC-16 (Modbus, XMODEM, CCITT, IBM SDLC) through CRC-32 (Ethernet, bzip2, iSCSI, AUTOSAR) to CRC-64 (XZ, ECMA-182, NVMe, Redis). Browse with `crcglot list`.
52
+
53
+ ## Acknowledgments
54
+
55
+ CRC catalogue data is derived from Greg Cook's [reveng project](https://reveng.sourceforge.io/) — the canonical source for CRC algorithm parameters since 1999.
56
+
57
+ ## License
58
+
59
+ MIT
@@ -0,0 +1,60 @@
1
+ [project]
2
+ name = "crcglot"
3
+ version = "0.1.0"
4
+ description = "Verified CRC source-code for C, Rust, VHDL, Python — catalogue-driven, self-test embedded."
5
+ license = "MIT"
6
+ requires-python = ">=3.11"
7
+ readme = "README.md"
8
+ authors = [{name = "Chuck Bass", email = "chuck@acrocad.net"}]
9
+ keywords = ["crc", "checksum", "code-generation", "embedded", "reveng", "rocksoft", "williams"]
10
+ classifiers = [
11
+ "Development Status :: 4 - Beta",
12
+ "Environment :: Console",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Programming Language :: Python :: 3.14",
21
+ "Topic :: Software Development :: Code Generators",
22
+ "Topic :: Software Development :: Embedded Systems",
23
+ ]
24
+ dependencies = [] # pure stdlib
25
+
26
+ [project.scripts]
27
+ crcglot = "crcglot.cli:main"
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/hucker/crcglot"
31
+ Repository = "https://github.com/hucker/crcglot"
32
+ Issues = "https://github.com/hucker/crcglot/issues"
33
+
34
+ [build-system]
35
+ requires = ["uv_build"]
36
+ build-backend = "uv_build"
37
+
38
+ [tool.pytest.ini_options]
39
+ testpaths = ["tests"]
40
+ addopts = "-v --cov=crcglot --cov-report=term-missing -n auto"
41
+ markers = [
42
+ "slow: subprocess-spawning test (compiles + runs generated code via gcc / rustc / ghdl). Skip with -m 'not slow' for fast iteration.",
43
+ ]
44
+
45
+ [tool.coverage.run]
46
+ source = ["src/crcglot"]
47
+
48
+ [tool.coverage.report]
49
+ exclude_lines = [
50
+ "if __name__",
51
+ "pragma: no cover",
52
+ ]
53
+ show_missing = true
54
+
55
+ [dependency-groups]
56
+ dev = [
57
+ "pytest>=8.0",
58
+ "pytest-cov>=7.0",
59
+ "pytest-xdist>=3.8",
60
+ ]
@@ -0,0 +1,62 @@
1
+ """crcglot -- multi-language CRC code generator.
2
+
3
+ Generate ready-to-compile CRC source code in C, Rust, VHDL, or Python
4
+ for any of 64+ named algorithms (reveng catalogue) or any custom
5
+ Rocksoft/Williams polynomial. Three implementation shapes per target:
6
+ bit-by-bit (smallest), table-driven (4-8x faster), and slice-by-8
7
+ (another 5-10x faster, CRC-32/64 only).
8
+
9
+ Public API:
10
+ - CRC_CATALOGUE: dict of named algorithm parameters.
11
+ - generate_c, generate_python, generate_rust, generate_vhdl:
12
+ name-lookup generators.
13
+ - generate_c_from_entry, etc.: generate from a custom entry dict
14
+ (Rocksoft/Williams params without catalogue lookup).
15
+ - GENERATORS, GENERATORS_FROM_ENTRY: dicts of the two forms
16
+ keyed by language code, for parameterized callers.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from typing import Callable
22
+
23
+ from crcglot.c import generate_c, generate_c_from_entry
24
+ from crcglot.catalogue import CRC_CATALOGUE, _generic_crc, _reflect
25
+ from crcglot.python import generate_python, generate_python_from_entry
26
+ from crcglot.rust import generate_rust, generate_rust_from_entry
27
+ from crcglot.vhdl import generate_vhdl, generate_vhdl_from_entry
28
+
29
+
30
+ # Language code -> name-lookup generator callable.
31
+ GENERATORS: dict[str, Callable] = {
32
+ "c": generate_c,
33
+ "python": generate_python,
34
+ "rust": generate_rust,
35
+ "vhdl": generate_vhdl,
36
+ }
37
+
38
+
39
+ # Language code -> entry-dict generator callable (custom-params path).
40
+ GENERATORS_FROM_ENTRY: dict[str, Callable] = {
41
+ "c": generate_c_from_entry,
42
+ "python": generate_python_from_entry,
43
+ "rust": generate_rust_from_entry,
44
+ "vhdl": generate_vhdl_from_entry,
45
+ }
46
+
47
+
48
+ __all__ = [
49
+ "CRC_CATALOGUE",
50
+ "GENERATORS",
51
+ "GENERATORS_FROM_ENTRY",
52
+ "_generic_crc",
53
+ "_reflect",
54
+ "generate_c",
55
+ "generate_c_from_entry",
56
+ "generate_python",
57
+ "generate_python_from_entry",
58
+ "generate_rust",
59
+ "generate_rust_from_entry",
60
+ "generate_vhdl",
61
+ "generate_vhdl_from_entry",
62
+ ]
@@ -0,0 +1,124 @@
1
+ """Language-agnostic helpers shared by every target generator.
2
+
3
+ Function-name sanitization, hex formatting, bit masks, and CRC table
4
+ pre-computation are identical across Python / C / Rust / VHDL output
5
+ because they're math, not syntax. Each language module imports what
6
+ it needs from here; per-language helpers (table formatters,
7
+ self-test scaffolds, header builders) stay local to their target.
8
+
9
+ Underscore-prefixed; the package's public API is ``__init__.py``.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from crcglot.catalogue import _reflect
15
+
16
+
17
+ def _func_name(algo_name: str) -> str:
18
+ """Convert a CRC algorithm name into a valid identifier.
19
+
20
+ Algorithm names from the reveng catalogue use ``-`` and ``.``
21
+ which aren't valid in C / Python / Rust / VHDL identifiers;
22
+ swap them for underscores. Same mangling is applied
23
+ consistently across all four target languages.
24
+ """
25
+ return algo_name.replace("-", "_").replace(".", "_")
26
+
27
+
28
+ def _hex(value: int, width: int) -> str:
29
+ """Format an integer as a ``0xHEX`` literal sized for ``width`` bits.
30
+
31
+ The ``0x``-prefixed form is identical in C / Python / Rust source
32
+ (and acceptable in VHDL comments), so callers across all target
33
+ languages share this helper. VHDL *code* uses :func:`_vhdl_lit`
34
+ from the vhdl module because hex literals there have a different
35
+ syntax for arithmetic contexts.
36
+ """
37
+ hex_w = (width + 3) // 4
38
+ return f"0x{value:0{hex_w}X}"
39
+
40
+
41
+ def _mask(width: int) -> str:
42
+ """Format ``(1 << width) - 1`` as a hex literal of matching width."""
43
+ return _hex((1 << width) - 1, width)
44
+
45
+
46
+ def _build_table(width: int, poly: int, refin: bool) -> list[int]:
47
+ """Pre-compute the 256-entry CRC lookup table for an algorithm.
48
+
49
+ Returns the table as a list of ``width``-bit integers, one per
50
+ possible byte value. Caller renders this list to its target
51
+ language's array syntax via per-language formatters.
52
+
53
+ The reflected-input case uses the reflected polynomial and
54
+ right-shifts; the normal case left-shifts. Both are textbook
55
+ Sarwate's algorithm.
56
+ """
57
+ table = []
58
+ if refin:
59
+ ref_poly = _reflect(poly, width)
60
+ for i in range(256):
61
+ crc = i
62
+ for _ in range(8):
63
+ if crc & 1:
64
+ crc = (crc >> 1) ^ ref_poly
65
+ else:
66
+ crc >>= 1
67
+ table.append(crc & ((1 << width) - 1))
68
+ else:
69
+ for i in range(256):
70
+ crc = i << (width - 8)
71
+ for _ in range(8):
72
+ if crc & (1 << (width - 1)):
73
+ crc = (crc << 1) ^ poly
74
+ else:
75
+ crc <<= 1
76
+ crc &= (1 << width) - 1
77
+ table.append(crc)
78
+ return table
79
+
80
+
81
+ def _build_slice8_tables(
82
+ width: int, poly: int, refin: bool,
83
+ ) -> list[list[int]]:
84
+ """Pre-compute the 8 tables used by slice-by-8 CRC.
85
+
86
+ Returns ``[T0, T1, ..., T7]``: each Tk is a 256-entry list of
87
+ width-bit ints. Tk[i] is the CRC of ``[i] + [0] * k`` -- i.e.
88
+ the contribution to the running CRC of a byte at position k.
89
+
90
+ The recurrence: ``T(k+1)[i] = T0[low_byte(Tk[i])] ^ shifted_rest(Tk[i])``
91
+ where the shift direction matches the polynomial direction. This
92
+ is what powers Intel's slice-by-8 (5-10x throughput over standard
93
+ table-driven for CRC-32 / CRC-64 on big buffers).
94
+ """
95
+ mask = (1 << width) - 1
96
+ t0 = _build_table(width, poly, refin)
97
+ tables = [t0]
98
+ for _ in range(7):
99
+ prev = tables[-1]
100
+ nxt: list[int] = []
101
+ if refin:
102
+ # Reflected: low byte feeds next lookup, rest shifts right.
103
+ for i in range(256):
104
+ v = prev[i]
105
+ nxt.append((t0[v & 0xFF] ^ (v >> 8)) & mask)
106
+ else:
107
+ # Normal: high byte feeds next lookup, rest shifts left.
108
+ for i in range(256):
109
+ v = prev[i]
110
+ top = (v >> (width - 8)) & 0xFF
111
+ nxt.append((t0[top] ^ ((v << 8) & mask)) & mask)
112
+ tables.append(nxt)
113
+ return tables
114
+
115
+
116
+ # Note: a Python reference for slice-by-8 was considered but dropped.
117
+ # It would have served as a test oracle for the generated C / Rust
118
+ # code, but Python doesn't benefit from slice-by-N at runtime (per-int
119
+ # overhead eats the win), and using it as an oracle adds a third
120
+ # implementation that itself needs verification. Better verification:
121
+ # generate both bit-by-bit and slice-by-8 in the target language,
122
+ # compile both, run both on the same inputs, assert they agree.
123
+ # Bit-by-bit is reveng-verified, so equivalence means slice-by-8 is
124
+ # correct. Tests live in tests/test_crc_codegen_exec.py.