gsasm 0.2.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.
Files changed (206) hide show
  1. gsasm-0.2.0/.forgejo/workflows/tests.yml +27 -0
  2. gsasm-0.2.0/.github/workflows/publish.yml +44 -0
  3. gsasm-0.2.0/.gitignore +26 -0
  4. gsasm-0.2.0/LICENSE +21 -0
  5. gsasm-0.2.0/PKG-INFO +287 -0
  6. gsasm-0.2.0/README.md +243 -0
  7. gsasm-0.2.0/docs/GSOS_MILESTONES.md +153 -0
  8. gsasm-0.2.0/docs/RESULTS.md +92 -0
  9. gsasm-0.2.0/docs/REZ_REVIEW_2026-07-14.md +215 -0
  10. gsasm-0.2.0/docs/TODO.md +98 -0
  11. gsasm-0.2.0/docs/design/P3_DECOMPOSE.md +81 -0
  12. gsasm-0.2.0/docs/design/README.md +101 -0
  13. gsasm-0.2.0/docs/design/expressload.md +194 -0
  14. gsasm-0.2.0/docs/design/linkiigs.md +99 -0
  15. gsasm-0.2.0/docs/design/makebin.md +83 -0
  16. gsasm-0.2.0/docs/design/rez.md +342 -0
  17. gsasm-0.2.0/gsasm/__init__.py +0 -0
  18. gsasm-0.2.0/gsasm/__main__.py +307 -0
  19. gsasm-0.2.0/gsasm/asm.py +2683 -0
  20. gsasm-0.2.0/gsasm/expr.py +241 -0
  21. gsasm-0.2.0/gsasm/expressload.py +1240 -0
  22. gsasm-0.2.0/gsasm/link.py +243 -0
  23. gsasm-0.2.0/gsasm/linkiigs.py +782 -0
  24. gsasm-0.2.0/gsasm/m65816.py +425 -0
  25. gsasm-0.2.0/gsasm/makebin.py +197 -0
  26. gsasm-0.2.0/gsasm/omf.py +1108 -0
  27. gsasm-0.2.0/gsasm/rez/__init__.py +69 -0
  28. gsasm-0.2.0/gsasm/rez/convert.py +47 -0
  29. gsasm-0.2.0/gsasm/rez/emit.py +310 -0
  30. gsasm-0.2.0/gsasm/rez/gen.py +1271 -0
  31. gsasm-0.2.0/gsasm/rez/lexer.py +670 -0
  32. gsasm-0.2.0/gsasm/rez/parser.py +963 -0
  33. gsasm-0.2.0/pyproject.toml +38 -0
  34. gsasm-0.2.0/tests/README.md +64 -0
  35. gsasm-0.2.0/tests/fixtures/001-basic-code/expected.dump +7 -0
  36. gsasm-0.2.0/tests/fixtures/001-basic-code/expected.obj +0 -0
  37. gsasm-0.2.0/tests/fixtures/001-basic-code/fixture.json +4 -0
  38. gsasm-0.2.0/tests/fixtures/001-basic-code/input.asm +13 -0
  39. gsasm-0.2.0/tests/fixtures/002-dcw-string-padding/expected.dump +5 -0
  40. gsasm-0.2.0/tests/fixtures/002-dcw-string-padding/expected.obj +0 -0
  41. gsasm-0.2.0/tests/fixtures/002-dcw-string-padding/fixture.json +4 -0
  42. gsasm-0.2.0/tests/fixtures/002-dcw-string-padding/input.asm +12 -0
  43. gsasm-0.2.0/tests/fixtures/003-dcb-string-fill/expected.dump +5 -0
  44. gsasm-0.2.0/tests/fixtures/003-dcb-string-fill/expected.obj +0 -0
  45. gsasm-0.2.0/tests/fixtures/003-dcb-string-fill/fixture.json +4 -0
  46. gsasm-0.2.0/tests/fixtures/003-dcb-string-fill/input.asm +9 -0
  47. gsasm-0.2.0/tests/fixtures/004-dollar-in-identifier/expected.dump +5 -0
  48. gsasm-0.2.0/tests/fixtures/004-dollar-in-identifier/expected.obj +0 -0
  49. gsasm-0.2.0/tests/fixtures/004-dollar-in-identifier/fixture.json +4 -0
  50. gsasm-0.2.0/tests/fixtures/004-dollar-in-identifier/input.asm +10 -0
  51. gsasm-0.2.0/tests/fixtures/005-if-and-or-bitwise/expected.dump +5 -0
  52. gsasm-0.2.0/tests/fixtures/005-if-and-or-bitwise/expected.obj +0 -0
  53. gsasm-0.2.0/tests/fixtures/005-if-and-or-bitwise/fixture.json +4 -0
  54. gsasm-0.2.0/tests/fixtures/005-if-and-or-bitwise/input.asm +19 -0
  55. gsasm-0.2.0/tests/fixtures/006-backslash-continuation/expected.dump +5 -0
  56. gsasm-0.2.0/tests/fixtures/006-backslash-continuation/expected.obj +0 -0
  57. gsasm-0.2.0/tests/fixtures/006-backslash-continuation/fixture.json +4 -0
  58. gsasm-0.2.0/tests/fixtures/006-backslash-continuation/input.asm +11 -0
  59. gsasm-0.2.0/tests/fixtures/007-expr-continues-whitespace/expected.dump +5 -0
  60. gsasm-0.2.0/tests/fixtures/007-expr-continues-whitespace/expected.obj +0 -0
  61. gsasm-0.2.0/tests/fixtures/007-expr-continues-whitespace/fixture.json +4 -0
  62. gsasm-0.2.0/tests/fixtures/007-expr-continues-whitespace/input.asm +11 -0
  63. gsasm-0.2.0/tests/fixtures/008-doubled-quote-escape/expected.dump +5 -0
  64. gsasm-0.2.0/tests/fixtures/008-doubled-quote-escape/expected.obj +0 -0
  65. gsasm-0.2.0/tests/fixtures/008-doubled-quote-escape/fixture.json +4 -0
  66. gsasm-0.2.0/tests/fixtures/008-doubled-quote-escape/input.asm +7 -0
  67. gsasm-0.2.0/tests/fixtures/009-case-on/expected.dump +5 -0
  68. gsasm-0.2.0/tests/fixtures/009-case-on/expected.obj +0 -0
  69. gsasm-0.2.0/tests/fixtures/009-case-on/fixture.json +4 -0
  70. gsasm-0.2.0/tests/fixtures/009-case-on/input.asm +11 -0
  71. gsasm-0.2.0/tests/fixtures/010-case-off-default/expected.dump +5 -0
  72. gsasm-0.2.0/tests/fixtures/010-case-off-default/expected.obj +0 -0
  73. gsasm-0.2.0/tests/fixtures/010-case-off-default/fixture.json +4 -0
  74. gsasm-0.2.0/tests/fixtures/010-case-off-default/input.asm +9 -0
  75. gsasm-0.2.0/tests/fixtures/011-record-typed-ds/expected.dump +10 -0
  76. gsasm-0.2.0/tests/fixtures/011-record-typed-ds/expected.obj +0 -0
  77. gsasm-0.2.0/tests/fixtures/011-record-typed-ds/fixture.json +4 -0
  78. gsasm-0.2.0/tests/fixtures/011-record-typed-ds/input.asm +16 -0
  79. gsasm-0.2.0/tests/fixtures/012-record-field-vs-import/expected.dump +6 -0
  80. gsasm-0.2.0/tests/fixtures/012-record-field-vs-import/expected.obj +0 -0
  81. gsasm-0.2.0/tests/fixtures/012-record-field-vs-import/fixture.json +4 -0
  82. gsasm-0.2.0/tests/fixtures/012-record-field-vs-import/input.asm +14 -0
  83. gsasm-0.2.0/tests/fixtures/013-import-comma-list/expected.dump +7 -0
  84. gsasm-0.2.0/tests/fixtures/013-import-comma-list/expected.obj +0 -0
  85. gsasm-0.2.0/tests/fixtures/013-import-comma-list/fixture.json +4 -0
  86. gsasm-0.2.0/tests/fixtures/013-import-comma-list/input.asm +9 -0
  87. gsasm-0.2.0/tests/fixtures/014-import-plus-const/expected.dump +6 -0
  88. gsasm-0.2.0/tests/fixtures/014-import-plus-const/expected.obj +0 -0
  89. gsasm-0.2.0/tests/fixtures/014-import-plus-const/fixture.json +4 -0
  90. gsasm-0.2.0/tests/fixtures/014-import-plus-const/input.asm +10 -0
  91. gsasm-0.2.0/tests/fixtures/015-extern-diff-immediate/expected.dump +6 -0
  92. gsasm-0.2.0/tests/fixtures/015-extern-diff-immediate/expected.obj +0 -0
  93. gsasm-0.2.0/tests/fixtures/015-extern-diff-immediate/fixture.json +4 -0
  94. gsasm-0.2.0/tests/fixtures/015-extern-diff-immediate/input.asm +9 -0
  95. gsasm-0.2.0/tests/fixtures/016-pcrel-same-seg-literal/expected.dump +5 -0
  96. gsasm-0.2.0/tests/fixtures/016-pcrel-same-seg-literal/expected.obj +0 -0
  97. gsasm-0.2.0/tests/fixtures/016-pcrel-same-seg-literal/fixture.json +4 -0
  98. gsasm-0.2.0/tests/fixtures/016-pcrel-same-seg-literal/input.asm +12 -0
  99. gsasm-0.2.0/tests/fixtures/017-equ-alias-relocatable/expected.dump +8 -0
  100. gsasm-0.2.0/tests/fixtures/017-equ-alias-relocatable/expected.obj +0 -0
  101. gsasm-0.2.0/tests/fixtures/017-equ-alias-relocatable/fixture.json +4 -0
  102. gsasm-0.2.0/tests/fixtures/017-equ-alias-relocatable/input.asm +12 -0
  103. gsasm-0.2.0/tests/fixtures/018-proc-temporg/expected.dump +5 -0
  104. gsasm-0.2.0/tests/fixtures/018-proc-temporg/expected.obj +0 -0
  105. gsasm-0.2.0/tests/fixtures/018-proc-temporg/fixture.json +4 -0
  106. gsasm-0.2.0/tests/fixtures/018-proc-temporg/input.asm +10 -0
  107. gsasm-0.2.0/tests/fixtures/019-seg-loadname-persists/expected.dump +13 -0
  108. gsasm-0.2.0/tests/fixtures/019-seg-loadname-persists/expected.obj +0 -0
  109. gsasm-0.2.0/tests/fixtures/019-seg-loadname-persists/fixture.json +4 -0
  110. gsasm-0.2.0/tests/fixtures/019-seg-loadname-persists/input.asm +16 -0
  111. gsasm-0.2.0/tests/fixtures/020-approx-ones-complement/expected.dump +5 -0
  112. gsasm-0.2.0/tests/fixtures/020-approx-ones-complement/expected.obj +0 -0
  113. gsasm-0.2.0/tests/fixtures/020-approx-ones-complement/fixture.json +4 -0
  114. gsasm-0.2.0/tests/fixtures/020-approx-ones-complement/input.asm +10 -0
  115. gsasm-0.2.0/tests/fixtures/021-sysdate-injection/expected.dump +5 -0
  116. gsasm-0.2.0/tests/fixtures/021-sysdate-injection/expected.obj +0 -0
  117. gsasm-0.2.0/tests/fixtures/021-sysdate-injection/fixture.json +6 -0
  118. gsasm-0.2.0/tests/fixtures/021-sysdate-injection/input.asm +7 -0
  119. gsasm-0.2.0/tests/fixtures/022-high-bank-immediate-link/expected.dump +10 -0
  120. gsasm-0.2.0/tests/fixtures/022-high-bank-immediate-link/expected.obj +0 -0
  121. gsasm-0.2.0/tests/fixtures/022-high-bank-immediate-link/expected.out +0 -0
  122. gsasm-0.2.0/tests/fixtures/022-high-bank-immediate-link/expected.out.dump +5 -0
  123. gsasm-0.2.0/tests/fixtures/022-high-bank-immediate-link/fixture.json +5 -0
  124. gsasm-0.2.0/tests/fixtures/022-high-bank-immediate-link/input.asm +11 -0
  125. gsasm-0.2.0/tests/fixtures/023-endproc-synonym/expected.dump +5 -0
  126. gsasm-0.2.0/tests/fixtures/023-endproc-synonym/expected.obj +0 -0
  127. gsasm-0.2.0/tests/fixtures/023-endproc-synonym/fixture.json +4 -0
  128. gsasm-0.2.0/tests/fixtures/023-endproc-synonym/input.asm +6 -0
  129. gsasm-0.2.0/tests/fixtures/024-operand-const-atomic/expected.dump +7 -0
  130. gsasm-0.2.0/tests/fixtures/024-operand-const-atomic/expected.obj +0 -0
  131. gsasm-0.2.0/tests/fixtures/024-operand-const-atomic/fixture.json +4 -0
  132. gsasm-0.2.0/tests/fixtures/024-operand-const-atomic/input.asm +517 -0
  133. gsasm-0.2.0/tests/fixtures/025-mvn-operand-order/expected.dump +5 -0
  134. gsasm-0.2.0/tests/fixtures/025-mvn-operand-order/expected.obj +0 -0
  135. gsasm-0.2.0/tests/fixtures/025-mvn-operand-order/fixture.json +4 -0
  136. gsasm-0.2.0/tests/fixtures/025-mvn-operand-order/input.asm +9 -0
  137. gsasm-0.2.0/tests/fixtures/026-tsa-tas-aliases/expected.dump +5 -0
  138. gsasm-0.2.0/tests/fixtures/026-tsa-tas-aliases/expected.obj +0 -0
  139. gsasm-0.2.0/tests/fixtures/026-tsa-tas-aliases/fixture.json +4 -0
  140. gsasm-0.2.0/tests/fixtures/026-tsa-tas-aliases/input.asm +13 -0
  141. gsasm-0.2.0/tests/fixtures/027-endfunc-synonym/expected.dump +5 -0
  142. gsasm-0.2.0/tests/fixtures/027-endfunc-synonym/expected.obj +0 -0
  143. gsasm-0.2.0/tests/fixtures/027-endfunc-synonym/fixture.json +4 -0
  144. gsasm-0.2.0/tests/fixtures/027-endfunc-synonym/input.asm +9 -0
  145. gsasm-0.2.0/tests/fixtures/028-len-literal-vs-substituted/expected.dump +5 -0
  146. gsasm-0.2.0/tests/fixtures/028-len-literal-vs-substituted/expected.obj +0 -0
  147. gsasm-0.2.0/tests/fixtures/028-len-literal-vs-substituted/fixture.json +4 -0
  148. gsasm-0.2.0/tests/fixtures/028-len-literal-vs-substituted/input.asm +20 -0
  149. gsasm-0.2.0/tests/fixtures/029-nested-record-fields/expected.dump +5 -0
  150. gsasm-0.2.0/tests/fixtures/029-nested-record-fields/expected.obj +0 -0
  151. gsasm-0.2.0/tests/fixtures/029-nested-record-fields/fixture.json +4 -0
  152. gsasm-0.2.0/tests/fixtures/029-nested-record-fields/input.asm +26 -0
  153. gsasm-0.2.0/tests/fixtures/030-name-macro-at-label-scope/expected.dump +5 -0
  154. gsasm-0.2.0/tests/fixtures/030-name-macro-at-label-scope/expected.obj +0 -0
  155. gsasm-0.2.0/tests/fixtures/030-name-macro-at-label-scope/fixture.json +4 -0
  156. gsasm-0.2.0/tests/fixtures/030-name-macro-at-label-scope/input.asm +52 -0
  157. gsasm-0.2.0/tests/omfdump.py +94 -0
  158. gsasm-0.2.0/tests/run_fixtures.py +157 -0
  159. gsasm-0.2.0/tests/test_branch_range.py +196 -0
  160. gsasm-0.2.0/tests/test_expressload_case_b.py +249 -0
  161. gsasm-0.2.0/tests/test_linkiigs_super_type26.py +148 -0
  162. gsasm-0.2.0/tests/test_rez_gen.py +776 -0
  163. gsasm-0.2.0/tests/test_rez_lexer.py +250 -0
  164. gsasm-0.2.0/tests/test_rez_parser.py +343 -0
  165. gsasm-0.2.0/tests/test_rez_pipeline.py +279 -0
  166. gsasm-0.2.0/work/buildrom.py +140 -0
  167. gsasm-0.2.0/work/bytecheck.py +114 -0
  168. gsasm-0.2.0/work/diskbuilders/__init__.py +32 -0
  169. gsasm-0.2.0/work/diskbuilders/expressload_files.py +458 -0
  170. gsasm-0.2.0/work/diskbuilders/kernel_os.py +298 -0
  171. gsasm-0.2.0/work/diskbuilders/kernel_setup.py +177 -0
  172. gsasm-0.2.0/work/diskbuilders/p8_driver.py +317 -0
  173. gsasm-0.2.0/work/diskbuilders/toolsets.py +380 -0
  174. gsasm-0.2.0/work/diskcheck.py +400 -0
  175. gsasm-0.2.0/work/drivercheck.py +345 -0
  176. gsasm-0.2.0/work/easymountcheck.py +306 -0
  177. gsasm-0.2.0/work/fstcheck.py +240 -0
  178. gsasm-0.2.0/work/gate.py +163 -0
  179. gsasm-0.2.0/work/gate_baseline.json +50 -0
  180. gsasm-0.2.0/work/generality_check.py +132 -0
  181. gsasm-0.2.0/work/hfs.py +127 -0
  182. gsasm-0.2.0/work/kernelcheck.py +984 -0
  183. gsasm-0.2.0/work/linkcheck.py +175 -0
  184. gsasm-0.2.0/work/linkrom.py +279 -0
  185. gsasm-0.2.0/work/loader_placed.py +87 -0
  186. gsasm-0.2.0/work/loader_residual.py +83 -0
  187. gsasm-0.2.0/work/mpwmake_probe.py +359 -0
  188. gsasm-0.2.0/work/objcheck.py +74 -0
  189. gsasm-0.2.0/work/p3_oracle.py +405 -0
  190. gsasm-0.2.0/work/probootcheck.py +147 -0
  191. gsasm-0.2.0/work/profst_diag.py +220 -0
  192. gsasm-0.2.0/work/recmap.py +98 -0
  193. gsasm-0.2.0/work/reloc_diag.py +141 -0
  194. gsasm-0.2.0/work/reloc_survey.py +220 -0
  195. gsasm-0.2.0/work/rezbuildcheck.py +201 -0
  196. gsasm-0.2.0/work/rezcheck.py +383 -0
  197. gsasm-0.2.0/work/rezemitcheck.py +121 -0
  198. gsasm-0.2.0/work/rezgencheck.py +159 -0
  199. gsasm-0.2.0/work/rezlexcheck.py +73 -0
  200. gsasm-0.2.0/work/rezloadcheck.py +291 -0
  201. gsasm-0.2.0/work/rezparsecheck.py +169 -0
  202. gsasm-0.2.0/work/romcov.py +64 -0
  203. gsasm-0.2.0/work/segdiff.py +73 -0
  204. gsasm-0.2.0/work/startgsos_diag.py +118 -0
  205. gsasm-0.2.0/work/toolcheck.py +331 -0
  206. gsasm-0.2.0/work/toolsetup_probe.py +84 -0
@@ -0,0 +1,27 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ fixtures:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.9", "3.12", "3.14"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Run fixture suite
20
+ run: python3 tests/run_fixtures.py
21
+ - name: Run corpus-free test suites
22
+ run: |
23
+ set -e
24
+ for t in tests/test_*.py; do
25
+ echo "== $t"
26
+ python3 "$t"
27
+ done
@@ -0,0 +1,44 @@
1
+ # Publish gsasm to PyPI via Trusted Publisher (OIDC) on version tags.
2
+ # Requires the repo to be registered as a Trusted Publisher on pypi.org
3
+ # (project: gsasm, owner: emdeejay, repo: gsasm, workflow: publish.yml).
4
+ name: publish
5
+
6
+ on:
7
+ push:
8
+ tags: ["v*"]
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+ - name: Fixture suite
19
+ run: python3 tests/run_fixtures.py
20
+ - name: Corpus-free test suites
21
+ run: |
22
+ set -e
23
+ for t in tests/test_*.py; do
24
+ echo "== $t"
25
+ python3 "$t"
26
+ done
27
+
28
+ publish:
29
+ needs: test
30
+ runs-on: ubuntu-latest
31
+ environment: pypi
32
+ permissions:
33
+ id-token: write
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: actions/setup-python@v5
37
+ with:
38
+ python-version: "3.12"
39
+ - name: Build sdist and wheel
40
+ run: |
41
+ python3 -m pip install build
42
+ python3 -m build
43
+ - name: Publish to PyPI
44
+ uses: pypa/gh-action-pypi-publish@release/v1
gsasm-0.2.0/.gitignore ADDED
@@ -0,0 +1,26 @@
1
+ # build / packaging
2
+ dist/
3
+ *.egg-info/
4
+ build/
5
+ __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ .DS_Store
9
+
10
+ # extracted Apple ROM source and includes (must be supplied separately)
11
+ work/romsrc/
12
+ work/includes/
13
+ work/rincludes/
14
+ work/txt/
15
+
16
+ # linker working directory (generated artifacts)
17
+ work/link/
18
+
19
+ # built ROM images
20
+ work/*.built
21
+ work/*.bin
22
+ work/*.img
23
+
24
+ # reference materials (copyrighted Apple disk images, PDFs, ROM files)
25
+ ref/
26
+ .claude/
gsasm-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Matt Jenkins
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.
gsasm-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,287 @@
1
+ Metadata-Version: 2.4
2
+ Name: gsasm
3
+ Version: 0.2.0
4
+ Summary: Clean-room MPW IIgs toolchain in Python: 65816 assembler, OMF linker, Rez resource compiler
5
+ Project-URL: Homepage, https://github.com/emdeejay/gsasm
6
+ Project-URL: Repository, https://github.com/emdeejay/gsasm
7
+ License: MIT License
8
+
9
+ Copyright (c) 2024 Matt Jenkins
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+ License-File: LICENSE
29
+ Keywords: 65816,apple2gs,assembler,omf,retro
30
+ Classifier: Development Status :: 4 - Beta
31
+ Classifier: Intended Audience :: Developers
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Programming Language :: Python :: 3.9
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Programming Language :: Python :: 3.14
40
+ Classifier: Topic :: Software Development :: Assemblers
41
+ Classifier: Topic :: System :: Emulators
42
+ Requires-Python: >=3.9
43
+ Description-Content-Type: text/markdown
44
+
45
+ # gsasm
46
+
47
+ A clean-room Python reimplementation of the **MPW IIgs cross-development
48
+ toolchain** — the `AsmIIgs` assembler, `LinkIIgs` linker, the `RezIIgs`
49
+ resource compiler, the `MakeBinIIgs`/`OverlayIIgs`/`catenate` packagers, and
50
+ the `ExpressLoad` relinker — validated byte-for-byte against the Apple IIgs
51
+ ROM 03 and the GS/OS System 6.0.1 shipping binaries.
52
+
53
+ Apple built the IIgs ROM and GS/OS on a 68k Mac under MPW Shell. Running that
54
+ chain today means SheepShaver → a Mac OS 7 image → MPW → the GS cross-tools.
55
+ `gsasm` replaces it with pure Python — no emulator, no dependencies outside
56
+ the standard library.
57
+
58
+ ## Results
59
+
60
+ Rebuilt from the original source and verified byte-identical to the shipping
61
+ binaries:
62
+
63
+ - **ROM 03** — all 262,144 bytes
64
+ - **All 7 buildable FSTs** (ProDOS, HFS, Char, High Sierra, DOS 3.3, Pascal,
65
+ MS-DOS) and **11 of 12 device drivers**
66
+ - **`prodos`, `Start.GS.OS`, `Error.Msg`, the GS/OS Loader**, `Tool014`
67
+ (Window Manager), and 19 of the 30 System 6.0.1 files the disk harness
68
+ rebuilds
69
+ - **Resource forks** (`gsrez`): `Sys.Resources` (24,337 bytes, 143 resources
70
+ including embedded code resources) and `EasyMount` — the latter byte-exact
71
+ across **both** forks, code and resources, from source to shipping file
72
+ - **Instruction encoding: 100%** — every instruction in the ~97,000-line
73
+ corpus encodes to the same bytes as the original listings
74
+ - **61/61 ROM objects link-identical** — for every module, linking `gsasm`'s
75
+ object or Apple's original produces the same load image
76
+
77
+ `GS.OS` itself reaches 38,711 of 38,805 bytes (99.76%); the residual 94 bytes
78
+ reference symbols that exist nowhere in the source archive, so a byte-exact
79
+ build is provably out of reach from these sources. The other shortfalls have
80
+ similarly settled causes (a source-revision skew, a converter whose output
81
+ isn't a function of its input, missing sources). The full accounting, with
82
+ evidence for each limit, is in [docs/RESULTS.md](docs/RESULTS.md).
83
+
84
+ ## Install
85
+
86
+ ```sh
87
+ pip install git+https://github.com/emdeejay/gsasm.git
88
+ ```
89
+
90
+ Or install from a local clone in editable mode:
91
+
92
+ ```sh
93
+ git clone https://github.com/emdeejay/gsasm.git
94
+ cd gsasm
95
+ pip install -e .
96
+ ```
97
+
98
+ Requires Python 3.9+. No dependencies outside the standard library.
99
+
100
+ ## CLI
101
+
102
+ ### gsasm — assembler
103
+
104
+ ```
105
+ gsasm <source.asm> [-I <incdir>] [-d KEY=VAL] [-o <out.obj>]
106
+ ```
107
+
108
+ Assembles an MPW IIgs-dialect 65816 source file and writes an OMF v2 object file.
109
+
110
+ ```sh
111
+ # assemble a single file
112
+ gsasm MyTool.asm -I ./includes -o MyTool.obj
113
+
114
+ # pass command-line defines (equivalent to the -d flag in MPW IIgs)
115
+ gsasm ROMDataMgr.asm -I ./includes -d Big=1
116
+
117
+ # multiple include directories
118
+ gsasm monitor.aii -I ./includes -I ./romsrc/Monitor
119
+ ```
120
+
121
+ Include directories are searched in order for files referenced by `INCLUDE`
122
+ directives. The source file's own directory is not searched implicitly — add
123
+ `-I .` if you need it.
124
+
125
+ ### gslink — linker
126
+
127
+ ```
128
+ gslink <file.obj> [-o <out.load>]
129
+ ```
130
+
131
+ Links a single multi-segment OMF object file. All `LEXPR`/`BEXPR`/`EXPR`
132
+ relocation records and `RELEXPR` (relative branch) records are fully evaluated
133
+ against the collected `GLOBAL` symbol table. The output is a single-segment OMF
134
+ load file with a flat body.
135
+
136
+ ```sh
137
+ gslink MyTool.obj # writes MyTool.out
138
+ gslink MyTool.obj -o MyTool.load
139
+ ```
140
+
141
+ For multi-object linking — libraries, segment naming/placement, the
142
+ `LinkIIgs -apw` recipe used by the GS/OS build scripts — use
143
+ `gsasm/linkiigs.py`; for ROM bank layout see `work/linkrom.py`.
144
+
145
+ ### gsrez — resource compiler
146
+
147
+ ```
148
+ gsrez <source.r> [-I <incdir>]... [-o <out>] [-t <filetype>] [-c <creator>]
149
+ [--read-dir <dir>]... [--meta KEY=VAL]...
150
+ ```
151
+
152
+ Compiles a Rez source file (the MPW IIgs `RezIIgs` dialect: `type` templates,
153
+ `resource` bodies, `read` statements, the C-style preprocessor) into an Apple
154
+ IIgs resource fork, written as a raw fork image. `TypesIIGS.r`-style include
155
+ files are searched through `-I` directories; `read` files (e.g. linked code
156
+ resources) through `--read-dir`. `--meta` sets fork-header fields (creation
157
+ timestamp etc.) for byte-exact reproduction work.
158
+
159
+ ```sh
160
+ gsrez sys.resources.r -I ./rincludes --read-dir ./build -o SYS.RESOURCES -t "F9 "
161
+ ```
162
+
163
+ ## Python API
164
+
165
+ ```python
166
+ from gsasm import asm, omf, link
167
+
168
+ # Assemble (include paths are positional; defines optional)
169
+ a = asm.assemble("MyTool.asm", ["./includes"], defines={"Big": 1})
170
+ if a.errors:
171
+ raise SystemExit("\n".join(a.errors))
172
+
173
+ # Emit an OMF object
174
+ obj_bytes = omf.emit(a)
175
+ with open("MyTool.obj", "wb") as f:
176
+ f.write(obj_bytes)
177
+
178
+ # Link to a load file
179
+ load_bytes = link.link(obj_bytes)
180
+ with open("MyTool.out", "wb") as f:
181
+ f.write(load_bytes)
182
+
183
+ # Parse an existing OMF file
184
+ header = omf.parse_header(obj_bytes)
185
+ records, _ = omf.parse_records(obj_bytes, header["DISPDATA"],
186
+ numlen=header["NUMLEN"])
187
+ for offset, record_type, data in records:
188
+ print(offset, record_type, data)
189
+ ```
190
+
191
+ ## Source dialect
192
+
193
+ `gsasm` implements the **MPW IIgs** (`AsmIIgs`) source dialect as used in the
194
+ ROM 03 and System 6.0.1 source trees. Notable features:
195
+
196
+ - **65816 instruction set** — full addressing-mode selection (dp/abs/long,
197
+ cross-bank rules), `MVN`/`MVP`, `PEA`/`PEI`/`PER`
198
+ - **Macro engine** — `MACRO`/`ENDM`, positional parameters (`&1`…`&n`),
199
+ keyword parameters, `WHILE`/`ENDWHILE`, `IF`/`ELSE`/`ENDIF`,
200
+ `GOTO`/`AGO`/`AIF`, `MEXIT`, `ANOP`, builtins (`&sysdate`, `&systime`, …)
201
+ - **Directives** — `PROC` (with `TEMPORG`/`ENTRY`/`EXPORT` forms),
202
+ `ENTRY`/`EXPORT`/`IMPORT`, `RECORD`/`ENDR` (templates and typed `DS`
203
+ instances), `WITH`, `DC`/`DCB`/`DS`, `ORG`, `SEG`, `INCLUDE`,
204
+ `MSB`/`LONGA`/`LONGI`/`CASE ON|OFF`, `OBJEND`
205
+ - **Label scoping** — `@`-local labels scoped to the nearest enclosing
206
+ non-`@` label (per MPW Assembler Reference p. 17); per-`PROC` namespaces
207
+ - **Expression evaluator** — MPW operator precedence, byte extraction
208
+ (`#<x`, `#>x`, `#^x`), shifts, the `≈` one's-complement operator,
209
+ `MSB ON` character constants
210
+ - **OMF v2 emitter** — `CONST`/`LCONST`/`DS`, `LEXPR`/`BEXPR`/`EXPR`/`RELEXPR`,
211
+ `GLOBAL`/`GEQU`, `SUPER` relocation dictionaries, cross-segment and import
212
+ references, faithful record chunking
213
+
214
+ Sources are read as MacRoman with classic-Mac line endings, matching real MPW
215
+ files.
216
+
217
+ ## Module layout
218
+
219
+ ```
220
+ gsasm/
221
+ __init__.py
222
+ __main__.py CLI entry points (gsasm, gslink)
223
+ m65816.py 65816 opcode table and addressing-mode encoding
224
+ expr.py MPW expression evaluator
225
+ asm.py Multi-pass assembler: macro engine, symbols, segments
226
+ omf.py OMF v2 parser and emitter
227
+ link.py Single-object OMF linker
228
+ linkiigs.py General LinkIIgs: multi-object, libraries, -apw recipe,
229
+ segment naming and placement
230
+ makebin.py MakeBinIIgs / OverlayIIgs / catenate packaging
231
+ expressload.py ExpressLoad relinker (fast-load format + SUPER records)
232
+ ```
233
+
234
+ ## Tests
235
+
236
+ ```sh
237
+ python3 tests/run_fixtures.py
238
+ ```
239
+
240
+ The `tests/` fixture suite runs on a bare checkout — no reference material
241
+ needed. Each fixture is an original source pinning one discovered dialect or
242
+ OMF behavior, with expected bytes minted only while the full golden-corpus
243
+ validation passes. See [tests/README.md](tests/README.md) for how blessing
244
+ works and why the expected bytes are trustworthy.
245
+
246
+ ## Validation harnesses (work/)
247
+
248
+ The `work/` scripts are the differential-validation harnesses used during
249
+ development. They compare rebuilt output against captured artifacts of the
250
+ original build — Apple's source, listings, objects, and shipping binaries —
251
+ which are copyrighted and **not included** (everything under `ref/` and
252
+ `work/romsrc/` is gitignored; supply your own).
253
+
254
+ | Script | What it validates |
255
+ |---|---|
256
+ | `gate.py` | Runs every harness below against a committed baseline; fails on any regression |
257
+ | `buildrom.py` | Reconstructs `rom.03` and verifies it byte-identical to the shipping ROM |
258
+ | `bytecheck.py` | Instruction encoding against the `.lst` Object Code column |
259
+ | `objcheck.py` | Emitted `.obj` files record-by-record against the originals |
260
+ | `linkcheck.py` | Differential link: original vs `gsasm` object through the same linker |
261
+ | `toolcheck.py` | `System/Tools/ToolNNN` toolsets vs the shipping files |
262
+ | `fstcheck.py` | `System/FSTs/*` vs the shipping files |
263
+ | `drivercheck.py` | `System/Drivers/*` vs the shipping files |
264
+ | `kernelcheck.py` | `prodos`, `GS.OS`, `Start.GS.OS`, `Error.Msg`, P8 |
265
+ | `diskcheck.py` | Whole System 6.0.1 disk-image files (needs the `a2til` sibling tools; set `A2TIL_PATH`) |
266
+ | `linkrom.py` | The `LinkIIgs`-equivalent ROM bank layout |
267
+ | `hfs.py` | Minimal HFS reader for extracting sources from `.hfv` images |
268
+
269
+ ## Background
270
+
271
+ The ROM 03 and System 6.0.1 sources were assembled with **AsmIIgs** (circa
272
+ 1989–1993), Apple's 65816 cross-assembler for MPW, distributed through APDA
273
+ with the rest of the MPW IIgs cross-development tools. The tools' own source
274
+ code was never published, so this project is a clean-room reimplementation:
275
+ behaviour was reverse-engineered from captured `.obj` and `.lst` files. Given
276
+ source, listings, and objects from a known-good build, every discrepancy
277
+ between `gsasm`'s output and the original is a measurable bug, and every
278
+ target that passes a differential comparison is proven correct rather than
279
+ assumed. The same method then extended, tool by tool, to the rest of the MPW
280
+ IIgs chain until whole shipping binaries reproduced.
281
+
282
+ The OMF (Object Module Format) specification is documented in the _Apple IIgs
283
+ Toolbox Reference_ and the _Apple IIgs GS/OS Reference_.
284
+
285
+ ## License
286
+
287
+ MIT — see [LICENSE](LICENSE).
gsasm-0.2.0/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # gsasm
2
+
3
+ A clean-room Python reimplementation of the **MPW IIgs cross-development
4
+ toolchain** — the `AsmIIgs` assembler, `LinkIIgs` linker, the `RezIIgs`
5
+ resource compiler, the `MakeBinIIgs`/`OverlayIIgs`/`catenate` packagers, and
6
+ the `ExpressLoad` relinker — validated byte-for-byte against the Apple IIgs
7
+ ROM 03 and the GS/OS System 6.0.1 shipping binaries.
8
+
9
+ Apple built the IIgs ROM and GS/OS on a 68k Mac under MPW Shell. Running that
10
+ chain today means SheepShaver → a Mac OS 7 image → MPW → the GS cross-tools.
11
+ `gsasm` replaces it with pure Python — no emulator, no dependencies outside
12
+ the standard library.
13
+
14
+ ## Results
15
+
16
+ Rebuilt from the original source and verified byte-identical to the shipping
17
+ binaries:
18
+
19
+ - **ROM 03** — all 262,144 bytes
20
+ - **All 7 buildable FSTs** (ProDOS, HFS, Char, High Sierra, DOS 3.3, Pascal,
21
+ MS-DOS) and **11 of 12 device drivers**
22
+ - **`prodos`, `Start.GS.OS`, `Error.Msg`, the GS/OS Loader**, `Tool014`
23
+ (Window Manager), and 19 of the 30 System 6.0.1 files the disk harness
24
+ rebuilds
25
+ - **Resource forks** (`gsrez`): `Sys.Resources` (24,337 bytes, 143 resources
26
+ including embedded code resources) and `EasyMount` — the latter byte-exact
27
+ across **both** forks, code and resources, from source to shipping file
28
+ - **Instruction encoding: 100%** — every instruction in the ~97,000-line
29
+ corpus encodes to the same bytes as the original listings
30
+ - **61/61 ROM objects link-identical** — for every module, linking `gsasm`'s
31
+ object or Apple's original produces the same load image
32
+
33
+ `GS.OS` itself reaches 38,711 of 38,805 bytes (99.76%); the residual 94 bytes
34
+ reference symbols that exist nowhere in the source archive, so a byte-exact
35
+ build is provably out of reach from these sources. The other shortfalls have
36
+ similarly settled causes (a source-revision skew, a converter whose output
37
+ isn't a function of its input, missing sources). The full accounting, with
38
+ evidence for each limit, is in [docs/RESULTS.md](docs/RESULTS.md).
39
+
40
+ ## Install
41
+
42
+ ```sh
43
+ pip install git+https://github.com/emdeejay/gsasm.git
44
+ ```
45
+
46
+ Or install from a local clone in editable mode:
47
+
48
+ ```sh
49
+ git clone https://github.com/emdeejay/gsasm.git
50
+ cd gsasm
51
+ pip install -e .
52
+ ```
53
+
54
+ Requires Python 3.9+. No dependencies outside the standard library.
55
+
56
+ ## CLI
57
+
58
+ ### gsasm — assembler
59
+
60
+ ```
61
+ gsasm <source.asm> [-I <incdir>] [-d KEY=VAL] [-o <out.obj>]
62
+ ```
63
+
64
+ Assembles an MPW IIgs-dialect 65816 source file and writes an OMF v2 object file.
65
+
66
+ ```sh
67
+ # assemble a single file
68
+ gsasm MyTool.asm -I ./includes -o MyTool.obj
69
+
70
+ # pass command-line defines (equivalent to the -d flag in MPW IIgs)
71
+ gsasm ROMDataMgr.asm -I ./includes -d Big=1
72
+
73
+ # multiple include directories
74
+ gsasm monitor.aii -I ./includes -I ./romsrc/Monitor
75
+ ```
76
+
77
+ Include directories are searched in order for files referenced by `INCLUDE`
78
+ directives. The source file's own directory is not searched implicitly — add
79
+ `-I .` if you need it.
80
+
81
+ ### gslink — linker
82
+
83
+ ```
84
+ gslink <file.obj> [-o <out.load>]
85
+ ```
86
+
87
+ Links a single multi-segment OMF object file. All `LEXPR`/`BEXPR`/`EXPR`
88
+ relocation records and `RELEXPR` (relative branch) records are fully evaluated
89
+ against the collected `GLOBAL` symbol table. The output is a single-segment OMF
90
+ load file with a flat body.
91
+
92
+ ```sh
93
+ gslink MyTool.obj # writes MyTool.out
94
+ gslink MyTool.obj -o MyTool.load
95
+ ```
96
+
97
+ For multi-object linking — libraries, segment naming/placement, the
98
+ `LinkIIgs -apw` recipe used by the GS/OS build scripts — use
99
+ `gsasm/linkiigs.py`; for ROM bank layout see `work/linkrom.py`.
100
+
101
+ ### gsrez — resource compiler
102
+
103
+ ```
104
+ gsrez <source.r> [-I <incdir>]... [-o <out>] [-t <filetype>] [-c <creator>]
105
+ [--read-dir <dir>]... [--meta KEY=VAL]...
106
+ ```
107
+
108
+ Compiles a Rez source file (the MPW IIgs `RezIIgs` dialect: `type` templates,
109
+ `resource` bodies, `read` statements, the C-style preprocessor) into an Apple
110
+ IIgs resource fork, written as a raw fork image. `TypesIIGS.r`-style include
111
+ files are searched through `-I` directories; `read` files (e.g. linked code
112
+ resources) through `--read-dir`. `--meta` sets fork-header fields (creation
113
+ timestamp etc.) for byte-exact reproduction work.
114
+
115
+ ```sh
116
+ gsrez sys.resources.r -I ./rincludes --read-dir ./build -o SYS.RESOURCES -t "F9 "
117
+ ```
118
+
119
+ ## Python API
120
+
121
+ ```python
122
+ from gsasm import asm, omf, link
123
+
124
+ # Assemble (include paths are positional; defines optional)
125
+ a = asm.assemble("MyTool.asm", ["./includes"], defines={"Big": 1})
126
+ if a.errors:
127
+ raise SystemExit("\n".join(a.errors))
128
+
129
+ # Emit an OMF object
130
+ obj_bytes = omf.emit(a)
131
+ with open("MyTool.obj", "wb") as f:
132
+ f.write(obj_bytes)
133
+
134
+ # Link to a load file
135
+ load_bytes = link.link(obj_bytes)
136
+ with open("MyTool.out", "wb") as f:
137
+ f.write(load_bytes)
138
+
139
+ # Parse an existing OMF file
140
+ header = omf.parse_header(obj_bytes)
141
+ records, _ = omf.parse_records(obj_bytes, header["DISPDATA"],
142
+ numlen=header["NUMLEN"])
143
+ for offset, record_type, data in records:
144
+ print(offset, record_type, data)
145
+ ```
146
+
147
+ ## Source dialect
148
+
149
+ `gsasm` implements the **MPW IIgs** (`AsmIIgs`) source dialect as used in the
150
+ ROM 03 and System 6.0.1 source trees. Notable features:
151
+
152
+ - **65816 instruction set** — full addressing-mode selection (dp/abs/long,
153
+ cross-bank rules), `MVN`/`MVP`, `PEA`/`PEI`/`PER`
154
+ - **Macro engine** — `MACRO`/`ENDM`, positional parameters (`&1`…`&n`),
155
+ keyword parameters, `WHILE`/`ENDWHILE`, `IF`/`ELSE`/`ENDIF`,
156
+ `GOTO`/`AGO`/`AIF`, `MEXIT`, `ANOP`, builtins (`&sysdate`, `&systime`, …)
157
+ - **Directives** — `PROC` (with `TEMPORG`/`ENTRY`/`EXPORT` forms),
158
+ `ENTRY`/`EXPORT`/`IMPORT`, `RECORD`/`ENDR` (templates and typed `DS`
159
+ instances), `WITH`, `DC`/`DCB`/`DS`, `ORG`, `SEG`, `INCLUDE`,
160
+ `MSB`/`LONGA`/`LONGI`/`CASE ON|OFF`, `OBJEND`
161
+ - **Label scoping** — `@`-local labels scoped to the nearest enclosing
162
+ non-`@` label (per MPW Assembler Reference p. 17); per-`PROC` namespaces
163
+ - **Expression evaluator** — MPW operator precedence, byte extraction
164
+ (`#<x`, `#>x`, `#^x`), shifts, the `≈` one's-complement operator,
165
+ `MSB ON` character constants
166
+ - **OMF v2 emitter** — `CONST`/`LCONST`/`DS`, `LEXPR`/`BEXPR`/`EXPR`/`RELEXPR`,
167
+ `GLOBAL`/`GEQU`, `SUPER` relocation dictionaries, cross-segment and import
168
+ references, faithful record chunking
169
+
170
+ Sources are read as MacRoman with classic-Mac line endings, matching real MPW
171
+ files.
172
+
173
+ ## Module layout
174
+
175
+ ```
176
+ gsasm/
177
+ __init__.py
178
+ __main__.py CLI entry points (gsasm, gslink)
179
+ m65816.py 65816 opcode table and addressing-mode encoding
180
+ expr.py MPW expression evaluator
181
+ asm.py Multi-pass assembler: macro engine, symbols, segments
182
+ omf.py OMF v2 parser and emitter
183
+ link.py Single-object OMF linker
184
+ linkiigs.py General LinkIIgs: multi-object, libraries, -apw recipe,
185
+ segment naming and placement
186
+ makebin.py MakeBinIIgs / OverlayIIgs / catenate packaging
187
+ expressload.py ExpressLoad relinker (fast-load format + SUPER records)
188
+ ```
189
+
190
+ ## Tests
191
+
192
+ ```sh
193
+ python3 tests/run_fixtures.py
194
+ ```
195
+
196
+ The `tests/` fixture suite runs on a bare checkout — no reference material
197
+ needed. Each fixture is an original source pinning one discovered dialect or
198
+ OMF behavior, with expected bytes minted only while the full golden-corpus
199
+ validation passes. See [tests/README.md](tests/README.md) for how blessing
200
+ works and why the expected bytes are trustworthy.
201
+
202
+ ## Validation harnesses (work/)
203
+
204
+ The `work/` scripts are the differential-validation harnesses used during
205
+ development. They compare rebuilt output against captured artifacts of the
206
+ original build — Apple's source, listings, objects, and shipping binaries —
207
+ which are copyrighted and **not included** (everything under `ref/` and
208
+ `work/romsrc/` is gitignored; supply your own).
209
+
210
+ | Script | What it validates |
211
+ |---|---|
212
+ | `gate.py` | Runs every harness below against a committed baseline; fails on any regression |
213
+ | `buildrom.py` | Reconstructs `rom.03` and verifies it byte-identical to the shipping ROM |
214
+ | `bytecheck.py` | Instruction encoding against the `.lst` Object Code column |
215
+ | `objcheck.py` | Emitted `.obj` files record-by-record against the originals |
216
+ | `linkcheck.py` | Differential link: original vs `gsasm` object through the same linker |
217
+ | `toolcheck.py` | `System/Tools/ToolNNN` toolsets vs the shipping files |
218
+ | `fstcheck.py` | `System/FSTs/*` vs the shipping files |
219
+ | `drivercheck.py` | `System/Drivers/*` vs the shipping files |
220
+ | `kernelcheck.py` | `prodos`, `GS.OS`, `Start.GS.OS`, `Error.Msg`, P8 |
221
+ | `diskcheck.py` | Whole System 6.0.1 disk-image files (needs the `a2til` sibling tools; set `A2TIL_PATH`) |
222
+ | `linkrom.py` | The `LinkIIgs`-equivalent ROM bank layout |
223
+ | `hfs.py` | Minimal HFS reader for extracting sources from `.hfv` images |
224
+
225
+ ## Background
226
+
227
+ The ROM 03 and System 6.0.1 sources were assembled with **AsmIIgs** (circa
228
+ 1989–1993), Apple's 65816 cross-assembler for MPW, distributed through APDA
229
+ with the rest of the MPW IIgs cross-development tools. The tools' own source
230
+ code was never published, so this project is a clean-room reimplementation:
231
+ behaviour was reverse-engineered from captured `.obj` and `.lst` files. Given
232
+ source, listings, and objects from a known-good build, every discrepancy
233
+ between `gsasm`'s output and the original is a measurable bug, and every
234
+ target that passes a differential comparison is proven correct rather than
235
+ assumed. The same method then extended, tool by tool, to the rest of the MPW
236
+ IIgs chain until whole shipping binaries reproduced.
237
+
238
+ The OMF (Object Module Format) specification is documented in the _Apple IIgs
239
+ Toolbox Reference_ and the _Apple IIgs GS/OS Reference_.
240
+
241
+ ## License
242
+
243
+ MIT — see [LICENSE](LICENSE).