openc166 0.1.15__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.
Files changed (161) hide show
  1. openc166-0.1.15/.gitattributes +2 -0
  2. openc166-0.1.15/.github/workflows/ci.yml +41 -0
  3. openc166-0.1.15/.github/workflows/wheels.yml +185 -0
  4. openc166-0.1.15/.gitignore +22 -0
  5. openc166-0.1.15/CMakeLists.txt +61 -0
  6. openc166-0.1.15/LICENSE +21 -0
  7. openc166-0.1.15/PKG-INFO +308 -0
  8. openc166-0.1.15/README.md +285 -0
  9. openc166-0.1.15/cli/CMakeLists.txt +10 -0
  10. openc166-0.1.15/cli/main.cpp +260 -0
  11. openc166-0.1.15/cmake/embed_files.cmake +24 -0
  12. openc166-0.1.15/docs/compatibility.md +1160 -0
  13. openc166-0.1.15/docs/phase1-feasibility.md +424 -0
  14. openc166-0.1.15/docs/releasing.md +73 -0
  15. openc166-0.1.15/docs/tasking.md +170 -0
  16. openc166-0.1.15/examples/mtos/README.md +43 -0
  17. openc166-0.1.15/examples/mtos/bsl_shim.a66 +26 -0
  18. openc166-0.1.15/examples/mtos/driver_patch.a66 +26 -0
  19. openc166-0.1.15/examples/mtos/kline_hello.a66 +35 -0
  20. openc166-0.1.15/examples/mtos/loader.a66 +52 -0
  21. openc166-0.1.15/examples/mtos/marker.a66 +18 -0
  22. openc166-0.1.15/examples/mtos/memory_dump.a66 +33 -0
  23. openc166-0.1.15/examples/mtos/stage2_hello.a66 +28 -0
  24. openc166-0.1.15/examples/payload.a66 +26 -0
  25. openc166-0.1.15/examples/sections.a66 +25 -0
  26. openc166-0.1.15/inc/REG167.INC +631 -0
  27. openc166-0.1.15/include/openc166/openc166.h +300 -0
  28. openc166-0.1.15/pyproject.toml +65 -0
  29. openc166-0.1.15/python/openc166/__init__.py +574 -0
  30. openc166-0.1.15/python/openc166/_native.py +155 -0
  31. openc166-0.1.15/python/openc166/py.typed +0 -0
  32. openc166-0.1.15/python/tests/test_openc166.py +503 -0
  33. openc166-0.1.15/src/CMakeLists.txt +99 -0
  34. openc166-0.1.15/src/assembler.cpp +4714 -0
  35. openc166-0.1.15/src/assembler.hpp +192 -0
  36. openc166-0.1.15/src/bundled.cpp +35 -0
  37. openc166-0.1.15/src/bundled.hpp +19 -0
  38. openc166-0.1.15/src/capi.cpp +377 -0
  39. openc166-0.1.15/src/capi.map +5 -0
  40. openc166-0.1.15/src/diag.hpp +60 -0
  41. openc166-0.1.15/src/encode.cpp +414 -0
  42. openc166-0.1.15/src/encode.hpp +60 -0
  43. openc166-0.1.15/src/expr.cpp +650 -0
  44. openc166-0.1.15/src/expr.hpp +134 -0
  45. openc166-0.1.15/src/isa/c166.tbl +368 -0
  46. openc166-0.1.15/src/isa/isa.cpp +39 -0
  47. openc166-0.1.15/src/isa/isa.hpp +32 -0
  48. openc166-0.1.15/src/isa/isa_types.hpp +135 -0
  49. openc166-0.1.15/src/lexer.cpp +144 -0
  50. openc166-0.1.15/src/lexer.hpp +42 -0
  51. openc166-0.1.15/src/m166.cpp +559 -0
  52. openc166-0.1.15/src/m166.hpp +68 -0
  53. openc166-0.1.15/src/operand.cpp +62 -0
  54. openc166-0.1.15/src/operand.hpp +33 -0
  55. openc166-0.1.15/src/output.cpp +151 -0
  56. openc166-0.1.15/src/predef.cpp +306 -0
  57. openc166-0.1.15/src/predef.hpp +51 -0
  58. openc166-0.1.15/src/value.hpp +109 -0
  59. openc166-0.1.15/tests/CMakeLists.txt +152 -0
  60. openc166-0.1.15/tests/acceptance/minimon.py +269 -0
  61. openc166-0.1.15/tests/capi/test_capi.c +425 -0
  62. openc166-0.1.15/tests/check_binary.cmake +23 -0
  63. openc166-0.1.15/tests/diff/cases/alignment.a66 +83 -0
  64. openc166-0.1.15/tests/diff/cases/bit_section_errors.a66 +72 -0
  65. openc166-0.1.15/tests/diff/cases/bit_sections.a66 +91 -0
  66. openc166-0.1.15/tests/diff/cases/bits.a66 +102 -0
  67. openc166-0.1.15/tests/diff/cases/branches.a66 +135 -0
  68. openc166-0.1.15/tests/diff/cases/cond.a66 +255 -0
  69. openc166-0.1.15/tests/diff/cases/cond_errors.a66 +117 -0
  70. openc166-0.1.15/tests/diff/cases/controls.a66 +29 -0
  71. openc166-0.1.15/tests/diff/cases/defs.a66 +131 -0
  72. openc166-0.1.15/tests/diff/cases/directives.a66 +109 -0
  73. openc166-0.1.15/tests/diff/cases/dpp.a66 +129 -0
  74. openc166-0.1.15/tests/diff/cases/expressions.a66 +92 -0
  75. openc166-0.1.15/tests/diff/cases/group_errors.a66 +80 -0
  76. openc166-0.1.15/tests/diff/cases/groups.a66 +108 -0
  77. openc166-0.1.15/tests/diff/cases/inc/code.inc +4 -0
  78. openc166-0.1.15/tests/diff/cases/inc/comments.inc +2 -0
  79. openc166-0.1.15/tests/diff/cases/inc/count.inc +2 -0
  80. openc166-0.1.15/tests/diff/cases/inc/crlf.inc +3 -0
  81. openc166-0.1.15/tests/diff/cases/inc/ignored.inc +2 -0
  82. openc166-0.1.15/tests/diff/cases/inc/lit.inc +3 -0
  83. openc166-0.1.15/tests/diff/cases/inc/nested.inc +4 -0
  84. openc166-0.1.15/tests/diff/cases/inc/noeol.inc +2 -0
  85. openc166-0.1.15/tests/diff/cases/inc/regs.inc +6 -0
  86. openc166-0.1.15/tests/diff/cases/inc/sub/deep.inc +3 -0
  87. openc166-0.1.15/tests/diff/cases/inc/sub/level3.inc +1 -0
  88. openc166-0.1.15/tests/diff/cases/include.a66 +30 -0
  89. openc166-0.1.15/tests/diff/cases/link/bits/1main.a66 +38 -0
  90. openc166-0.1.15/tests/diff/cases/link/bits/2lib.a66 +29 -0
  91. openc166-0.1.15/tests/diff/cases/link/bits/3more.a66 +25 -0
  92. openc166-0.1.15/tests/diff/cases/link/calls/1main.a66 +39 -0
  93. openc166-0.1.15/tests/diff/cases/link/calls/2lib.a66 +40 -0
  94. openc166-0.1.15/tests/diff/cases/link/combine/1first.a66 +42 -0
  95. openc166-0.1.15/tests/diff/cases/link/combine/2second.a66 +33 -0
  96. openc166-0.1.15/tests/diff/cases/link/combine/3third.a66 +36 -0
  97. openc166-0.1.15/tests/diff/cases/link/fixups/1use.a66 +35 -0
  98. openc166-0.1.15/tests/diff/cases/link/fixups/2def.a66 +28 -0
  99. openc166-0.1.15/tests/diff/cases/link/groups/1main.a66 +45 -0
  100. openc166-0.1.15/tests/diff/cases/link/groups/2lib.a66 +34 -0
  101. openc166-0.1.15/tests/diff/cases/link/mixed/1seg.a66 +14 -0
  102. openc166-0.1.15/tests/diff/cases/link/mixed/2flat.a66 +11 -0
  103. openc166-0.1.15/tests/diff/cases/link/mixed/3seg.a66 +12 -0
  104. openc166-0.1.15/tests/diff/cases/link/regbanks/1main.a66 +39 -0
  105. openc166-0.1.15/tests/diff/cases/link/regbanks/2lib.a66 +25 -0
  106. openc166-0.1.15/tests/diff/cases/link/sections/1first.a66 +25 -0
  107. openc166-0.1.15/tests/diff/cases/link/sections/2second.a66 +22 -0
  108. openc166-0.1.15/tests/diff/cases/link/sections/3third.a66 +13 -0
  109. openc166-0.1.15/tests/diff/cases/link/segmented/1main.a66 +34 -0
  110. openc166-0.1.15/tests/diff/cases/link/segmented/2lib.a66 +25 -0
  111. openc166-0.1.15/tests/diff/cases/link/unresolved/1main.a66 +16 -0
  112. openc166-0.1.15/tests/diff/cases/link/unresolved/2one.a66 +12 -0
  113. openc166-0.1.15/tests/diff/cases/link/unresolved/3two.a66 +11 -0
  114. openc166-0.1.15/tests/diff/cases/link/values/1use.a66 +29 -0
  115. openc166-0.1.15/tests/diff/cases/link/values/2def.a66 +28 -0
  116. openc166-0.1.15/tests/diff/cases/lit.a66 +64 -0
  117. openc166-0.1.15/tests/diff/cases/lit_errors.a66 +38 -0
  118. openc166-0.1.15/tests/diff/cases/locate.a66 +129 -0
  119. openc166-0.1.15/tests/diff/cases/macro_args.a66 +64 -0
  120. openc166-0.1.15/tests/diff/cases/macro_errors.a66 +63 -0
  121. openc166-0.1.15/tests/diff/cases/macros.a66 +133 -0
  122. openc166-0.1.15/tests/diff/cases/operands.a66 +119 -0
  123. openc166-0.1.15/tests/diff/cases/primary.a66 +34 -0
  124. openc166-0.1.15/tests/diff/cases/redefine.a66 +74 -0
  125. openc166-0.1.15/tests/diff/cases/regbank_errors.a66 +82 -0
  126. openc166-0.1.15/tests/diff/cases/regbanks.a66 +51 -0
  127. openc166-0.1.15/tests/diff/cases/reloc.a66 +157 -0
  128. openc166-0.1.15/tests/diff/cases/section_errors.a66 +178 -0
  129. openc166-0.1.15/tests/diff/cases/section_length.a66 +91 -0
  130. openc166-0.1.15/tests/diff/cases/segmented.a66 +175 -0
  131. openc166-0.1.15/tests/diff/cases/type_operator_errors.a66 +49 -0
  132. openc166-0.1.15/tests/diff/cases/type_operators.a66 +87 -0
  133. openc166-0.1.15/tests/diff/gen_sweep.py +77 -0
  134. openc166-0.1.15/tests/diff/keil_diff.py +664 -0
  135. openc166-0.1.15/tests/expected/driver_patch.hex +4 -0
  136. openc166-0.1.15/tests/expected/driver_patch.s28 +5 -0
  137. openc166-0.1.15/tests/expected/payload.srec +6 -0
  138. openc166-0.1.15/tests/unit/helpers.hpp +60 -0
  139. openc166-0.1.15/tests/unit/main.cpp +3 -0
  140. openc166-0.1.15/tests/unit/test_assembler.cpp +271 -0
  141. openc166-0.1.15/tests/unit/test_bits.cpp +239 -0
  142. openc166-0.1.15/tests/unit/test_branches.cpp +288 -0
  143. openc166-0.1.15/tests/unit/test_cond.cpp +232 -0
  144. openc166-0.1.15/tests/unit/test_defs.cpp +193 -0
  145. openc166-0.1.15/tests/unit/test_dpp.cpp +246 -0
  146. openc166-0.1.15/tests/unit/test_encode.cpp +100 -0
  147. openc166-0.1.15/tests/unit/test_expr.cpp +263 -0
  148. openc166-0.1.15/tests/unit/test_groups.cpp +175 -0
  149. openc166-0.1.15/tests/unit/test_include.cpp +293 -0
  150. openc166-0.1.15/tests/unit/test_lexer.cpp +77 -0
  151. openc166-0.1.15/tests/unit/test_link.cpp +184 -0
  152. openc166-0.1.15/tests/unit/test_lit.cpp +253 -0
  153. openc166-0.1.15/tests/unit/test_macros.cpp +292 -0
  154. openc166-0.1.15/tests/unit/test_output.cpp +114 -0
  155. openc166-0.1.15/tests/unit/test_regbanks.cpp +121 -0
  156. openc166-0.1.15/tests/unit/test_sections.cpp +221 -0
  157. openc166-0.1.15/tests/unit/test_tasking.cpp +287 -0
  158. openc166-0.1.15/third_party/doctest/LICENSE.txt +21 -0
  159. openc166-0.1.15/third_party/doctest/doctest.h +7106 -0
  160. openc166-0.1.15/tools/CMakeLists.txt +5 -0
  161. openc166-0.1.15/tools/isagen.cpp +432 -0
@@ -0,0 +1,2 @@
1
+ # Expected outputs are compared byte for byte; keep their CR LF line ends.
2
+ tests/expected/** -text
@@ -0,0 +1,41 @@
1
+ name: CI
2
+
3
+ # Pushes to main run this from the release workflow (wheels.yml) instead.
4
+ on:
5
+ push:
6
+ branches-ignore: [main]
7
+ pull_request:
8
+ workflow_call:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ build:
15
+ name: ${{ matrix.os }}
16
+ runs-on: ${{ matrix.os }}
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ os: [ubuntu-latest, macos-latest, windows-latest]
21
+ steps:
22
+ - uses: actions/checkout@v7
23
+ - name: Configure
24
+ # MSVC warnings have not been reviewed yet, so they do not fail the build.
25
+ run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DOPENC166_WERROR=${{ runner.os != 'Windows' }}
26
+ - name: Build
27
+ run: cmake --build build --config Release --parallel
28
+ - name: Test
29
+ run: ctest --test-dir build --build-config Release --output-on-failure
30
+
31
+ sanitizers:
32
+ name: ubuntu-latest (ASan + UBSan)
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v7
36
+ - name: Configure
37
+ run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DOPENC166_WERROR=ON -DOPENC166_SANITIZE=ON
38
+ - name: Build
39
+ run: cmake --build build --parallel
40
+ - name: Test
41
+ run: ctest --test-dir build --output-on-failure
@@ -0,0 +1,185 @@
1
+ # Builds and tests the Python packages (sdist and wheels) on every push to
2
+ # main and every pull request. Every push to main is also released: once CI
3
+ # and the packages pass, they go to PyPI and to a GitHub release. See
4
+ # docs/releasing.md.
5
+ name: Build and release
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ pull_request:
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ version:
18
+ name: Version
19
+ runs-on: ubuntu-latest
20
+ outputs:
21
+ version: ${{ steps.version.outputs.version }}
22
+ steps:
23
+ - uses: actions/checkout@v7
24
+ with:
25
+ fetch-depth: 0
26
+ persist-credentials: false
27
+ - name: Work out the version
28
+ id: version
29
+ env:
30
+ EVENT: ${{ github.event_name }}
31
+ # x.y.z from CMakeLists.txt, with z raised by the number of commits
32
+ # since the commit that last changed that version.
33
+ run: |
34
+ base=$(perl -0777 -ne 'print $1 if /project\(openc166\s+VERSION\s+([0-9]+\.[0-9]+\.[0-9]+)/' CMakeLists.txt)
35
+ if [ -z "$base" ]; then
36
+ echo "::error::CMakeLists.txt has no project(openc166 VERSION x.y.z)"
37
+ exit 1
38
+ fi
39
+ IFS=. read -r major minor patch <<< "$base"
40
+ since=$(git log -1 --format=%H -G 'VERSION [0-9][0-9]*[.][0-9][0-9]*[.][0-9]' -- CMakeLists.txt)
41
+ count=$(git rev-list --count "$since..HEAD")
42
+ version="$major.$minor.$((patch + count))"
43
+ if [ "$EVENT" = push ] &&
44
+ tagged=$(git rev-parse -q --verify "refs/tags/v$version^{commit}") &&
45
+ [ "$tagged" != "$(git rev-parse HEAD)" ]; then
46
+ echo "::error::v$version was already released from another commit; raise the version in CMakeLists.txt"
47
+ exit 1
48
+ fi
49
+ echo "version=$version" >> "$GITHUB_OUTPUT"
50
+ echo "Version $version" >> "$GITHUB_STEP_SUMMARY"
51
+
52
+ sdist:
53
+ name: Source package
54
+ needs: version
55
+ runs-on: ubuntu-latest
56
+ env:
57
+ VERSION: ${{ needs.version.outputs.version }}
58
+ steps:
59
+ - uses: actions/checkout@v7
60
+ with:
61
+ persist-credentials: false
62
+ - name: Set the version
63
+ shell: bash
64
+ run: |
65
+ perl -0777 -pi.orig -e 's/(project\(openc166\s+VERSION\s+)[0-9][0-9.]*/${1}$ENV{VERSION}/' CMakeLists.txt
66
+ rm CMakeLists.txt.orig
67
+ set=$(perl -0777 -ne 'print $1 if /project\(openc166\s+VERSION\s+([0-9.]+)/' CMakeLists.txt)
68
+ if [ "$set" != "$VERSION" ]; then
69
+ echo "::error::Could not set the version in CMakeLists.txt"
70
+ exit 1
71
+ fi
72
+ - uses: actions/setup-python@v7
73
+ with:
74
+ python-version: "3.x"
75
+ - name: Build
76
+ run: |
77
+ python -m pip install build twine
78
+ python -m build --sdist
79
+ python -m twine check --strict dist/*
80
+ test -f "dist/openc166-$VERSION.tar.gz"
81
+ - name: Install and test
82
+ env:
83
+ OPENC166_TEST_COMMAND: "1"
84
+ run: |
85
+ python -m pip install dist/*.tar.gz
86
+ python -m unittest discover -s python/tests -v
87
+ - uses: actions/upload-artifact@v7
88
+ with:
89
+ name: sdist
90
+ path: dist/*.tar.gz
91
+
92
+ wheels:
93
+ name: Wheels (${{ matrix.os }})
94
+ needs: version
95
+ runs-on: ${{ matrix.os }}
96
+ env:
97
+ VERSION: ${{ needs.version.outputs.version }}
98
+ strategy:
99
+ fail-fast: false
100
+ matrix:
101
+ # Linux x86-64 and ARM64 (glibc and musl), Windows x64, x86 and ARM64,
102
+ # macOS Intel and Apple silicon (see [tool.cibuildwheel] in pyproject.toml).
103
+ os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-latest]
104
+ steps:
105
+ - uses: actions/checkout@v7
106
+ with:
107
+ persist-credentials: false
108
+ - name: Set the version
109
+ shell: bash
110
+ run: |
111
+ perl -0777 -pi.orig -e 's/(project\(openc166\s+VERSION\s+)[0-9][0-9.]*/${1}$ENV{VERSION}/' CMakeLists.txt
112
+ rm CMakeLists.txt.orig
113
+ set=$(perl -0777 -ne 'print $1 if /project\(openc166\s+VERSION\s+([0-9.]+)/' CMakeLists.txt)
114
+ if [ "$set" != "$VERSION" ]; then
115
+ echo "::error::Could not set the version in CMakeLists.txt"
116
+ exit 1
117
+ fi
118
+ - uses: pypa/cibuildwheel@v4.3.5
119
+ - uses: actions/upload-artifact@v7
120
+ with:
121
+ name: wheels-${{ matrix.os }}
122
+ path: wheelhouse/*.whl
123
+
124
+ # The CI workflow (.github/workflows/ci.yml): nothing is released unless it
125
+ # passes.
126
+ ci:
127
+ name: CI
128
+ if: github.event_name == 'push'
129
+ uses: ./.github/workflows/ci.yml
130
+
131
+ publish:
132
+ name: Publish to PyPI
133
+ needs: [version, sdist, wheels, ci]
134
+ if: github.event_name == 'push'
135
+ runs-on: ubuntu-latest
136
+ environment:
137
+ name: pypi
138
+ url: https://pypi.org/project/openc166/${{ needs.version.outputs.version }}/
139
+ permissions:
140
+ id-token: write
141
+ steps:
142
+ - uses: actions/download-artifact@v8
143
+ with:
144
+ path: dist
145
+ merge-multiple: true
146
+ - uses: pypa/gh-action-pypi-publish@release/v1
147
+ with:
148
+ # Lets a failed upload be re-run.
149
+ skip-existing: true
150
+
151
+ github-release:
152
+ name: GitHub release
153
+ needs: [version, publish]
154
+ runs-on: ubuntu-latest
155
+ permissions:
156
+ contents: write
157
+ env:
158
+ VERSION: ${{ needs.version.outputs.version }}
159
+ GH_TOKEN: ${{ github.token }}
160
+ steps:
161
+ - uses: actions/checkout@v7
162
+ with:
163
+ fetch-depth: 0
164
+ persist-credentials: false
165
+ - uses: actions/download-artifact@v8
166
+ with:
167
+ path: dist
168
+ merge-multiple: true
169
+ - name: Create the release
170
+ run: |
171
+ tag="v$VERSION"
172
+ previous=$(git describe --tags --abbrev=0 --match 'v[0-9]*' HEAD^ 2>/dev/null || true)
173
+ {
174
+ echo "Install it with \`pip install openc166==$VERSION\`."
175
+ echo
176
+ echo "## Changes"
177
+ echo
178
+ git log --no-merges --format='- %s' "${previous:+$previous..}HEAD"
179
+ } > notes.md
180
+ if gh release view "$tag" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
181
+ gh release upload "$tag" dist/* --repo "$GITHUB_REPOSITORY" --clobber
182
+ else
183
+ gh release create "$tag" dist/* --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" \
184
+ --title "openc166 $VERSION" --notes-file notes.md
185
+ fi
@@ -0,0 +1,22 @@
1
+ # Build trees
2
+ /build*/
3
+ /cmake-build-*/
4
+ /out/
5
+
6
+ # IDEs
7
+ /.idea/
8
+ /.vscode/
9
+ /.vs/
10
+ *.swp
11
+
12
+ # Python
13
+ __pycache__/
14
+ *.pyc
15
+ /.pytest_cache/
16
+
17
+ # Local test corpora and tool outputs that must never be committed
18
+ # (third-party sources such as Infineon MiniMon, Keil-generated files)
19
+ /tests/local/
20
+ *.LST
21
+ *.lst
22
+ *.OBJ
@@ -0,0 +1,61 @@
1
+ cmake_minimum_required(VERSION 3.20)
2
+ project(openc166
3
+ VERSION 0.1.15
4
+ DESCRIPTION "Keil A166-compatible assembler for the Infineon C166/C167 family"
5
+ LANGUAGES CXX)
6
+
7
+ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
8
+ set(OPENC166_TOP_LEVEL ON)
9
+ else()
10
+ set(OPENC166_TOP_LEVEL OFF)
11
+ endif()
12
+
13
+ option(OPENC166_BUILD_CLI "Build the openc166 command-line tool" ON)
14
+ option(OPENC166_BUILD_SHARED "Build the shared library with the C interface" ON)
15
+ option(OPENC166_BUILD_TESTS "Build the unit tests" ${OPENC166_TOP_LEVEL})
16
+ option(OPENC166_SANITIZE "Build with AddressSanitizer and UndefinedBehaviorSanitizer" OFF)
17
+ option(OPENC166_WERROR "Treat compiler warnings as errors" OFF)
18
+ set(OPENC166_ISAGEN_EXECUTABLE "" CACHE FILEPATH
19
+ "Prebuilt host isagen to use when cross-compiling (empty: build it)")
20
+
21
+ set(CMAKE_CXX_STANDARD 20)
22
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
23
+ set(CMAKE_CXX_EXTENSIONS OFF)
24
+
25
+ # Link the C++ runtime statically with MSVC, so that openc166.exe and
26
+ # openc166.dll run without the Visual C++ Redistributable.
27
+ if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
28
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
29
+ endif()
30
+
31
+ # Shared warning and sanitizer settings for every target in this project.
32
+ add_library(openc166_options INTERFACE)
33
+ if(MSVC)
34
+ target_compile_options(openc166_options INTERFACE /W4 /utf-8 $<$<COMPILE_LANGUAGE:CXX>:/permissive->)
35
+ if(OPENC166_WERROR)
36
+ target_compile_options(openc166_options INTERFACE /WX)
37
+ endif()
38
+ else()
39
+ target_compile_options(openc166_options INTERFACE
40
+ -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wno-sign-conversion)
41
+ if(OPENC166_WERROR)
42
+ target_compile_options(openc166_options INTERFACE -Werror)
43
+ endif()
44
+ if(OPENC166_SANITIZE)
45
+ target_compile_options(openc166_options INTERFACE
46
+ -fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all)
47
+ target_link_options(openc166_options INTERFACE -fsanitize=address,undefined)
48
+ endif()
49
+ endif()
50
+
51
+ add_subdirectory(tools)
52
+ add_subdirectory(src)
53
+
54
+ if(OPENC166_BUILD_CLI)
55
+ add_subdirectory(cli)
56
+ endif()
57
+
58
+ if(OPENC166_BUILD_TESTS)
59
+ enable_testing()
60
+ add_subdirectory(tests)
61
+ endif()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Piotr Zdolski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,308 @@
1
+ Metadata-Version: 2.4
2
+ Name: openc166
3
+ Version: 0.1.15
4
+ Summary: Keil A166-compatible assembler for the Infineon C166/C167 microcontrollers
5
+ Keywords: c166,c167,st10,assembler,keil,a166,infineon,ecu
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Operating System :: MacOS
11
+ Classifier: Operating System :: Microsoft :: Windows
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Programming Language :: Assembly
14
+ Classifier: Programming Language :: C++
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Software Development :: Assemblers
17
+ Classifier: Topic :: Software Development :: Embedded Systems
18
+ Classifier: Typing :: Typed
19
+ Project-URL: Homepage, https://github.com/Dante383/openc166
20
+ Project-URL: Issues, https://github.com/Dante383/openc166/issues
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+
24
+ # openc166
25
+
26
+ An open-source assembler for the Infineon C166 and C167 microcontroller
27
+ family (including ST10 parts), compatible with the Keil A166 assembler.
28
+
29
+ It turns Keil-style assembly source into a **raw binary image** at a fixed
30
+ address, or into an Intel HEX or Motorola S-record file. That suits small
31
+ programs loaded into RAM or flash and started directly, such as ECU
32
+ payloads, bootstrap loaders, and test code. No linker or object-file
33
+ converter is needed.
34
+
35
+ openc166 runs on Linux, Windows and macOS. It needs only a C++20 compiler and
36
+ CMake.
37
+
38
+ ## Status
39
+
40
+ Early development (version 0.x). What works today:
41
+
42
+ - **The complete C166 and C167 instruction set**, with all addressing modes.
43
+ Every instruction form is checked byte for byte against Keil A166 V5.38:
44
+ over 5,000 checks of code bytes, addresses and symbol values, all
45
+ identical.
46
+ - Keil expression syntax: operators, `HIGH`/`LOW`, `SOF`/`SEG`/`PAG`/`POF`,
47
+ `BOF`, `DATA3`/`DATA4`/`DATA8`/`DATA16`, character constants, bit
48
+ addresses such as `PSW.3` or `0FD00H.5`, and extended-SFR checks inside
49
+ `EXTR` sequences.
50
+ - Sections with an address (`SECTION CODE AT 0E000H`) and without one.
51
+ openc166 places sections without `AT` as Keil's L166 linker would, or at
52
+ addresses you give (`--section NAME=ADDR`), so code that leaves placement
53
+ to the linker can still be assembled straight to a binary. `DGROUP` and
54
+ `CGROUP` keep sections in one data page or code segment, as in L166.
55
+ `BIT` sections and `DBIT` hold bit variables, placed bit by bit as L166
56
+ places them.
57
+ - `PROC`/`ENDP`, `ORG`, `EVEN`, `EQU`/`SET`/`BIT`, `DB`/`DW`/`DD`,
58
+ `DS`/`DSB`/`DSW`/`DSD`, and `DPPTR`/`DSPTR`/`DBPTR`, including Keil's
59
+ automatic alignment of word data.
60
+ - Segmented mode (`$SEGMENTED`): `ASSUME`, `DPPn:` prefixes, and Keil's
61
+ rules for which data page register an address goes through.
62
+ - `DEFR`/`DEFA`/`DEFB`, the register-definition directives that register
63
+ files use, with Keil's rules for repeated definitions.
64
+ - A built-in `REG167.INC` register file, written from Infineon's manuals, so
65
+ `$INCLUDE(REG167.INC)` works without Keil installed.
66
+ - Keil's rules for label arithmetic, which decide between short and long
67
+ instruction forms.
68
+ - Generic `JMP` and `CALL`: like Keil, openc166 picks the shortest
69
+ instruction that reaches the target and shortens forward jumps over
70
+ several passes. Label types (`NEAR`, `FAR`, `WORD`, ...) and the `SHORT`
71
+ and type operators (`FAR x`, `WORD PTR x`, ...) work as in Keil.
72
+ - `$INCLUDE` and `$INCDIR`, with Keil's search order and listing format.
73
+ - Conditional assembly: `$SET`/`$RESET`, `$IF`/`$ELSEIF`/`$ELSE`/`$ENDIF`
74
+ and the `IF`/`ELSEIF`/`ELSE`/`ENDIF` statements, with Keil's quirks (only
75
+ bit 0 of a condition counts) and listing format.
76
+ - `LIT` text replacement (`PORT LIT 'R2'`), with Keil's rules for where
77
+ names are replaced.
78
+ - Keil's standard macros: `MACRO`/`ENDM` with parameters and `LOCAL`
79
+ labels, `REPT`, `IRP`, `IRPC`, `EXITM`, `NUL`, `&` and `%`, with Keil's
80
+ rules for splitting arguments. `$GEN`/`$NOGEN` choose whether the listing
81
+ shows expanded lines.
82
+ - The `$MOD167`, `$CASE`, `$SEGMENTED` and `$TABS` controls, with Keil's
83
+ rule that these come before the first statement. Listing-only controls
84
+ are accepted and ignored.
85
+ - Keil error and warning codes (A74, A111, ...), so messages line up with
86
+ the Keil manual.
87
+ - Raw binary, Intel HEX and Motorola S-record output. The HEX records match
88
+ Keil OH166's `H167` format.
89
+ - Several source files linked into one program, as L166 does: `EXTERN`,
90
+ `PUBLIC` and `GLOBAL` symbols, and sections of the same name combined
91
+ across files. Each file is assembled separately (a "module"), so a name
92
+ that is not `PUBLIC` stays private to its file.
93
+ - Register banks (`REGBANK`/`REGDEF`), placed in `0FC00H..0FDFFH` as L166
94
+ places them, and the `NAME`, `SSKDEF`, `PECDEF` and `TYPEDEC` directives.
95
+ - **TASKING sources** (`--dialect tasking`): the common part of TASKING's
96
+ m166 preprocessor (`@SET`, `@EVAL`, `@IF`/`@ELSE`/`@ENDI`, `@DEFINED`),
97
+ TASKING's controls and `STDNAMES` register files, and the places where
98
+ its assembler differs from Keil's. Infineon's MiniMon monitor and flash
99
+ drivers, which gkflasher's ECU code comes from, rebuild byte for byte
100
+ from their TASKING sources. See
101
+ [docs/tasking.md](https://github.com/Dante383/openc166/blob/main/docs/tasking.md).
102
+ - A Python package and a C API, for tools that assemble code themselves.
103
+
104
+ Not done yet:
105
+
106
+ - Keil's MPL macro language (`%DEFINE` and the like); put `$NOMPL` at the
107
+ top of the file to use `%` as text
108
+ - OMF-166 object files and libraries
109
+ - TASKING's m166 macros with parameters (`@DEFINE`), loops and string
110
+ functions
111
+
112
+ See [docs/compatibility.md](https://github.com/Dante383/openc166/blob/main/docs/compatibility.md) for exact behaviour and
113
+ the few places where openc166 deliberately differs from Keil.
114
+
115
+ ## Building
116
+
117
+ ```sh
118
+ cmake -S . -B build
119
+ cmake --build build
120
+ ctest --test-dir build
121
+ ```
122
+
123
+ The program is `build/cli/openc166`. On Windows with Visual Studio it is
124
+ under `build\cli\Debug\` or `build\cli\Release\`. The shared library with
125
+ the C API is built in `build/src/`.
126
+
127
+ ## Usage
128
+
129
+ ```sh
130
+ openc166 payload.a66 # writes payload.bin
131
+ openc166 payload.a66 -o out.bin -l out.lst # choose names, add a listing
132
+ openc166 payload.a66 -o payload.hex # Intel HEX
133
+ openc166 payload.a66 -o payload.s19 # S-records (S1)
134
+ openc166 main.a66 lib.a66 -o payload.bin # link two source files
135
+ ```
136
+
137
+ Several source files are linked into one program, the way Keil's L166
138
+ linker joins the object files of A166:
139
+
140
+ - An `EXTERN` name in one file takes the value of the `PUBLIC` or `GLOBAL`
141
+ name in another. A name that no file exports is an error.
142
+ - Sections with the same name and class are joined into one: the parts of
143
+ a `PUBLIC` or `GLOBAL` section follow one another, the parts of a
144
+ `COMMON` section lie on top of each other.
145
+ - Without `-o`, the output is named after the first file. With `-l`, the
146
+ listing has one part per file and a symbol table that names the file
147
+ each symbol comes from.
148
+ - Code outside sections starts at `--origin` in every file, so normally
149
+ each file puts its code in sections.
150
+
151
+ `$INCLUDE` looks in each file's own directory.
152
+ [docs/compatibility.md](https://github.com/Dante383/openc166/blob/main/docs/compatibility.md#linking-several-files)
153
+ has the exact rules.
154
+
155
+ The output format follows the extension of the `-o` file: `.hex`, `.h86`
156
+ and `.ihx` give Intel HEX; `.srec`, `.s19`, `.s28`, `.s37`, `.mot` and
157
+ `.sx` give S-records; anything else gives a raw binary. `--format` chooses
158
+ it explicitly.
159
+
160
+ A raw binary starts at the lowest address used. For example, code in
161
+ `SECTION CODE AT 0E000H` produces a file whose first byte belongs at
162
+ `0E000H`. Gaps between pieces of code are filled. HEX and S-record files
163
+ carry the address of every record, so they hold only the bytes used.
164
+
165
+ | Option | Meaning |
166
+ |---|---|
167
+ | `-f, --format FMT` | `bin`, `hex` or `srec` (default: from the output extension) |
168
+ | `--origin ADDR` | address of code outside sections, and the lowest address for sections without `AT` (default 0) |
169
+ | `--section NAME=ADDR` | put section `NAME`, which has no `AT`, at `ADDR` (may be repeated) |
170
+ | `--base ADDR` | binary: address of the first byte of the file |
171
+ | `--fill BYTE` | binary: value of gaps between pieces of code (default `0FFh`) |
172
+ | `--record-size N` | HEX and S-records: data bytes per record (default 16) |
173
+ | `--cpu c166\|c167` | instruction set (`$MOD167` in the source also selects C167) |
174
+ | `-I DIR` | also search `DIR` for `$INCLUDE` files (may be repeated) |
175
+ | `--dialect D` | `keil` (default) or `tasking`, for TASKING a166 sources |
176
+ | `-c, --control TEXT` | controls read before the sources, e.g. `-c "CASE STDNAMES(reg167.def)"` (may be repeated) |
177
+
178
+ Sections without `AT` go in order of first appearance to the first free,
179
+ suitably aligned place from the origin on, as L166 places them by default.
180
+ `--section` overrides that for chosen sections, like L166's `SECTIONS`
181
+ control. The listing ends with a table of where each section went.
182
+ [examples/sections.a66](https://github.com/Dante383/openc166/blob/main/examples/sections.a66) shows both.
183
+
184
+ Intel HEX files use extended linear address records (type 04) for addresses
185
+ above 64 KB, like OH166 with its `H167` option. S-records use S1, S2 or S3
186
+ records by extension (`.s19`, `.s28`, `.s37`); otherwise the smallest kind
187
+ that holds every address.
188
+
189
+ The exit status is 0 on success, 1 on assembly errors (no output is
190
+ written), and 2 for usage or file errors. Messages use the format
191
+ `file:line:column: error A74: ...`.
192
+
193
+ [examples/payload.a66](https://github.com/Dante383/openc166/blob/main/examples/payload.a66) is a short, commented example.
194
+ [examples/mtos/](https://github.com/Dante383/openc166/tree/main/examples/mtos) holds real ECU payloads for Siemens SIMK43
195
+ ECUs, taken from gkflasher.
196
+
197
+ ## Python
198
+
199
+ ```sh
200
+ pip install openc166 # or "pip install ." in a checkout
201
+ ```
202
+
203
+ Wheels are published for Linux, Windows and macOS on x86 and ARM; other
204
+ systems build from source, which needs CMake and a C++20 compiler. To get
205
+ just the `openc166` command, `pipx install openc166` works too.
206
+
207
+ ```python
208
+ import openc166
209
+
210
+ result = openc166.assemble("""
211
+ $MOD167
212
+ PROG SECTION CODE AT 0E000H
213
+ MOV R4, #0BEEFH
214
+ RET
215
+ PROG ENDS
216
+ END
217
+ """)
218
+ image = result.image() # raises openc166.AssemblyError if there are errors
219
+ image.base # 0xE000, the address of image.data[0]
220
+ image.data # b'\xe6\xf4\xef\xbe\xcb\x00'
221
+ ```
222
+
223
+ - `openc166.assemble(source, *, file_name=None, cpu=None, origin=0, include_dirs=(), sections=None, dialect="keil", controls=())`
224
+ assembles a `str` or `bytes`. `sections` gives addresses for sections
225
+ without `AT`, e.g. `{"VARS": 0xF600}`. `dialect="tasking"` reads TASKING
226
+ source; `controls` is a list of controls read before the source, as with
227
+ `-c`. `openc166.assemble_file(path, ...)`
228
+ reads a file; `$INCLUDE` then also searches the file's directory.
229
+ - The result has `ok`, `diagnostics` (each with `severity`, `code`,
230
+ `message`, `file`, `line`, `column`; `str()` gives the usual one-line
231
+ message), `errors`, `warnings`, `chunks` (address and bytes of each piece
232
+ of code), `symbols` (a dict of name to `Symbol`), `symbol(name)` (lookup
233
+ ignoring case), `sections` (a dict of name to `Section`: `type`, `align`,
234
+ `address`, `size`, and `placement`, which is `"at"`, `"given"` or
235
+ `"located"`), `listing` and `cpu`.
236
+ - `openc166.assemble_many({"main.a66": text1, "lib.a66": text2}, ...)`
237
+ links several sources into one program, like several files on the
238
+ command line; `openc166.assemble_files([path1, path2], ...)` reads them
239
+ from files. Each `Symbol` then says which file defines it (`module`) and
240
+ whether it is `PUBLIC` or `GLOBAL` (`exported`). `result.modules` lists
241
+ the file names; `result.symbols` holds one symbol per name (the exported
242
+ one if there is one), `result.all_symbols` all of them. Each `Section`
243
+ has its `class_name` and `group`.
244
+ - `result.image(base=None, fill=0xFF)` lays all code out as one block, like
245
+ the command-line tool.
246
+ - `result.intel_hex(record_size=16)` and
247
+ `result.srec(record_size=16, address_size=None)` return Intel HEX and
248
+ S-record text (`address_size` 2, 3 or 4 picks S1, S2 or S3 records).
249
+
250
+ The package needs Python 3.9 or newer. It also installs the `openc166`
251
+ command. It loads the library through `ctypes`, so one wheel works with
252
+ every Python version.
253
+
254
+ ## C API
255
+
256
+ [include/openc166/openc166.h](https://github.com/Dante383/openc166/blob/main/include/openc166/openc166.h) declares a plain C
257
+ interface, exported by the shared library (`libopenc166.so`,
258
+ `libopenc166.dylib` or `openc166.dll`). Any language that can call C can
259
+ use it: `oc166_assemble` assembles one source, `oc166_assemble_many`
260
+ links several. The header documents every function; the Python package is
261
+ an example of a complete binding.
262
+
263
+ ## Testing
264
+
265
+ - `ctest --test-dir build` runs the unit tests, the C API test and the
266
+ Python package tests, and assembles the examples, checking every byte.
267
+ - `tests/acceptance/minimon.py` rebuilds Infineon's MiniMon from its
268
+ TASKING sources and compares the result with its HEX files. MiniMon is
269
+ not included; set `MINIMON_DIR` to its directory (the one that holds
270
+ `MCPROG` and `Driver`) and `ctest` runs it too.
271
+ - `tests/diff/` contains the differential test against Keil A166. Keil is
272
+ **not** included. If you have your own copy, run:
273
+
274
+ ```sh
275
+ KEIL_A166=/path/to/A166.EXE python3 tests/diff/keil_diff.py tests/diff/cases/*.a66
276
+ ```
277
+
278
+ It compares every line: address, code bytes, warnings and errors, and
279
+ the final value of every symbol. Add `--image` to also link Keil's output
280
+ with L166 and OH166 and compare the complete memory image, and `--codes`
281
+ to list lines where both assemblers report an error but with different
282
+ codes. Lines marked `; DIVERGES:` are deliberate differences (see
283
+ [docs/compatibility.md](https://github.com/Dante383/openc166/blob/main/docs/compatibility.md)) and are skipped.
284
+
285
+ Given a directory instead of a file, it treats each `.a66` file in it as
286
+ one module, links Keil's objects with L166, and compares the linked
287
+ image and the linker's errors with openc166's:
288
+
289
+ ```sh
290
+ KEIL_A166=/path/to/A166.EXE python3 tests/diff/keil_diff.py tests/diff/cases/link/*/
291
+ ```
292
+
293
+ On Linux and macOS, Keil runs under Wine. To generate test lines that
294
+ cover the whole instruction set, run
295
+ `tests/diff/gen_sweep.py build/generated/openc166/isa.json c167 > sweep.a66`.
296
+
297
+ The test inputs were written independently for this project. Keil's output
298
+ is used only for the local comparison and is never stored in the
299
+ repository.
300
+
301
+ ## License
302
+
303
+ MIT; see [LICENSE](https://github.com/Dante383/openc166/blob/main/LICENSE). The bundled [doctest](https://github.com/Dante383/openc166/tree/main/third_party/doctest)
304
+ test framework is also MIT.
305
+
306
+ openc166 is not affiliated with Arm/Keil or Infineon. "Keil", "A166",
307
+ "C166", "C167" and "TASKING" are trademarks of their respective owners. The
308
+ names are used only to describe compatibility.