dasmos 0.1.2__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.
- dasmos-0.1.2/LICENSE +21 -0
- dasmos-0.1.2/PKG-INFO +315 -0
- dasmos-0.1.2/README.md +285 -0
- dasmos-0.1.2/pyproject.toml +121 -0
- dasmos-0.1.2/setup.cfg +4 -0
- dasmos-0.1.2/src/dasmos/__init__.py +65 -0
- dasmos-0.1.2/src/dasmos/_text.py +57 -0
- dasmos-0.1.2/src/dasmos/cli.py +485 -0
- dasmos-0.1.2/src/dasmos/core/__init__.py +8 -0
- dasmos-0.1.2/src/dasmos/core/annotations.py +207 -0
- dasmos-0.1.2/src/dasmos/core/classification.py +223 -0
- dasmos-0.1.2/src/dasmos/core/config.py +74 -0
- dasmos-0.1.2/src/dasmos/core/cpu_state.py +46 -0
- dasmos-0.1.2/src/dasmos/core/disassembly.py +161 -0
- dasmos-0.1.2/src/dasmos/core/labels.py +373 -0
- dasmos-0.1.2/src/dasmos/core/markdown_asm.py +374 -0
- dasmos-0.1.2/src/dasmos/core/memory.py +318 -0
- dasmos-0.1.2/src/dasmos/core/move.py +301 -0
- dasmos-0.1.2/src/dasmos/cpu.py +388 -0
- dasmos-0.1.2/src/dasmos/disassembler.py +1350 -0
- dasmos-0.1.2/src/dasmos/environment.py +141 -0
- dasmos-0.1.2/src/dasmos/exceptions.py +6 -0
- dasmos-0.1.2/src/dasmos/ext/__init__.py +8 -0
- dasmos-0.1.2/src/dasmos/ext/cpus/__init__.py +10 -0
- dasmos-0.1.2/src/dasmos/ext/cpus/cmos65c02/__init__.py +22 -0
- dasmos-0.1.2/src/dasmos/ext/cpus/cmos65c02/cpu.py +148 -0
- dasmos-0.1.2/src/dasmos/ext/cpus/nmos6502/__init__.py +22 -0
- dasmos-0.1.2/src/dasmos/ext/cpus/nmos6502/cpu.py +550 -0
- dasmos-0.1.2/src/dasmos/ext/environments/__init__.py +0 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_bbc_hardware/__init__.py +13 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_bbc_hardware/environment.py +164 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_mos/__init__.py +13 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_mos/enums.py +299 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_mos/environment.py +182 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_mos/hooks.py +212 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_sideways_rom/__init__.py +13 -0
- dasmos-0.1.2/src/dasmos/ext/environments/acorn_sideways_rom/environment.py +183 -0
- dasmos-0.1.2/src/dasmos/ext/renderers/__init__.py +10 -0
- dasmos-0.1.2/src/dasmos/ext/renderers/beebasm/__init__.py +16 -0
- dasmos-0.1.2/src/dasmos/ext/renderers/beebasm/renderer.py +1743 -0
- dasmos-0.1.2/src/dasmos/ext/renderers/json/__init__.py +16 -0
- dasmos-0.1.2/src/dasmos/ext/renderers/json/renderer.py +718 -0
- dasmos-0.1.2/src/dasmos/extension.py +250 -0
- dasmos-0.1.2/src/dasmos/hooks.py +76 -0
- dasmos-0.1.2/src/dasmos/ir.py +117 -0
- dasmos-0.1.2/src/dasmos/output.py +82 -0
- dasmos-0.1.2/src/dasmos/py.typed +0 -0
- dasmos-0.1.2/src/dasmos/renderer.py +272 -0
- dasmos-0.1.2/src/dasmos.egg-info/PKG-INFO +315 -0
- dasmos-0.1.2/src/dasmos.egg-info/SOURCES.txt +69 -0
- dasmos-0.1.2/src/dasmos.egg-info/dependency_links.txt +1 -0
- dasmos-0.1.2/src/dasmos.egg-info/entry_points.txt +15 -0
- dasmos-0.1.2/src/dasmos.egg-info/requires.txt +4 -0
- dasmos-0.1.2/src/dasmos.egg-info/top_level.txt +1 -0
- dasmos-0.1.2/tests/test_beebasm.py +643 -0
- dasmos-0.1.2/tests/test_cli.py +305 -0
- dasmos-0.1.2/tests/test_cmos65c02.py +275 -0
- dasmos-0.1.2/tests/test_cpu.py +327 -0
- dasmos-0.1.2/tests/test_disassembler.py +451 -0
- dasmos-0.1.2/tests/test_driver_roundtrip.py +2444 -0
- dasmos-0.1.2/tests/test_econet_bridge_roundtrip.py +396 -0
- dasmos-0.1.2/tests/test_environment.py +550 -0
- dasmos-0.1.2/tests/test_json_renderer.py +290 -0
- dasmos-0.1.2/tests/test_nfs_roundtrip.py +496 -0
- dasmos-0.1.2/tests/test_nmos6502.py +401 -0
- dasmos-0.1.2/tests/test_output.py +96 -0
- dasmos-0.1.2/tests/test_py8dis2dasmos.py +463 -0
- dasmos-0.1.2/tests/test_renderer.py +204 -0
- dasmos-0.1.2/tests/test_smoke.py +60 -0
- dasmos-0.1.2/tests/test_trace.py +381 -0
- dasmos-0.1.2/tests/test_tube_client_roundtrip.py +232 -0
dasmos-0.1.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robert Smallshire
|
|
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.
|
dasmos-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dasmos
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Pluggable tracing disassembler with CPU, renderer and environment extension points.
|
|
5
|
+
Author-email: Robert Smallshire <rob@sixty-north.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/acornaeology/dasmos
|
|
8
|
+
Project-URL: Repository, https://github.com/acornaeology/dasmos
|
|
9
|
+
Project-URL: Issues, https://github.com/acornaeology/dasmos/issues
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Disassemblers
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: asyoulikeit>=1.1
|
|
26
|
+
Requires-Dist: click>=8.0
|
|
27
|
+
Requires-Dist: mistletoe>=1.4
|
|
28
|
+
Requires-Dist: stevedore
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Dasmos
|
|
32
|
+
|
|
33
|
+
A pluggable tracing disassembler for retro CPUs, version `0.1.2`.
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<a href="https://pypi.org/project/dasmos/"><img src="https://img.shields.io/pypi/v/dasmos.svg" alt="PyPI"></a>
|
|
37
|
+
<a href="https://github.com/acornaeology/dasmos/actions/workflows/release.yml"><img src="https://img.shields.io/github/actions/workflow/status/acornaeology/dasmos/release.yml?label=release" alt="Release"></a>
|
|
38
|
+
<a href="https://github.com/acornaeology/dasmos/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/acornaeology/dasmos/ci.yml?branch=master&label=CI" alt="CI"></a>
|
|
39
|
+
<a href="https://pypi.org/project/dasmos/"><img src="https://img.shields.io/pypi/pyversions/dasmos.svg" alt="Python versions"></a>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
> *From Ancient Greek* δασμός *(dasmós, "division"), from* δαίω
|
|
43
|
+
> *(daíō, "to divide, share").*
|
|
44
|
+
|
|
45
|
+
*Dasmos* is a ground-up rewrite and reimagining of a heavily modified
|
|
46
|
+
[fork][py8dis-fork] of [py8dis][py8dis-original] — Steven Flintham's
|
|
47
|
+
original programmable tracing disassembler for the 6502 family.
|
|
48
|
+
*Dasmos* owes the whole core idea to Steven and to the py8dis project;
|
|
49
|
+
this project organises a tracing disassembler as a core algorithm
|
|
50
|
+
customised through plug-in extensions which provide knowledge of CPUs,
|
|
51
|
+
different assembly syntaxes, and target environments. The core of the
|
|
52
|
+
essential design vocabulary — driver scripts, traced classification,
|
|
53
|
+
label/comment/banner annotations — is all inspired by py8dis.
|
|
54
|
+
|
|
55
|
+
Driver scripts written for py8dis can be ported automatically to
|
|
56
|
+
*Dasmos* with the bundled `scripts/py8dis2dasmos.py`.
|
|
57
|
+
|
|
58
|
+
[py8dis-original]: https://github.com/ZornsLemma/py8dis
|
|
59
|
+
[py8dis-fork]: https://github.com/acornaeology/py8dis
|
|
60
|
+
[acornaeology]: https://github.com/acornaeology
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
> The `uv` and `uvx` commands shown below come from
|
|
65
|
+
> [Astral's uv](https://docs.astral.sh/uv/). If you don't have it
|
|
66
|
+
> yet, see the [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/)
|
|
67
|
+
> — one-line installers are available for macOS, Linux, and Windows.
|
|
68
|
+
|
|
69
|
+
For one-shot CLI use, no install needed — `uvx` fetches and runs in
|
|
70
|
+
a transient environment:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
uvx dasmos disassemble myrom.bin --load-addr '&8000'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To add `dasmos` to a project (required for driver scripts that
|
|
77
|
+
`import dasmos`):
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
uv add dasmos
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or with pip:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
pip install dasmos
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
*Dasmos*'s round-trip / parity tests assemble back to bytes via
|
|
90
|
+
[beebasm](https://github.com/stardot/beebasm); `beebasm` on `PATH`
|
|
91
|
+
(or via the `BEEBASM` env var) activates them. CI builds beebasm
|
|
92
|
+
from source per matrix cell so the round-trip is part of the gate.
|
|
93
|
+
|
|
94
|
+
## Programmatic API
|
|
95
|
+
|
|
96
|
+
Every CLI capability is also reachable through the package. The
|
|
97
|
+
typical driver-script flow is: pick a CPU plug-in, load a binary,
|
|
98
|
+
register entry points / labels / classifications / annotations,
|
|
99
|
+
disassemble, then render via a renderer plug-in.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from dasmos import Disassembler, Align
|
|
103
|
+
|
|
104
|
+
d = Disassembler.create(cpu="nmos6502")
|
|
105
|
+
d.load("rom.bin", 0x8000)
|
|
106
|
+
d.entry(0x8000, name="start")
|
|
107
|
+
d.label(0x8006, "show", description="Display routine")
|
|
108
|
+
d.comment(0x8000, "Entry point.")
|
|
109
|
+
d.comment(0x8000, "magic", align=Align.INLINE)
|
|
110
|
+
|
|
111
|
+
ir = d.disassemble()
|
|
112
|
+
print(str(ir.render("beebasm")))
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
That produces beebasm-assemblable source. Re-assembling it via the
|
|
116
|
+
real `beebasm` binary yields a binary byte-identical to the input
|
|
117
|
+
— the load-bearing **round-trip property** *Dasmos*'s test suite
|
|
118
|
+
exercises against real Acorn ROMs (the 8 KB Econet Bridge and the
|
|
119
|
+
2 KB-mapped 6502 Tube Client both round-trip end-to-end with full
|
|
120
|
+
py8dis annotation-content parity).
|
|
121
|
+
|
|
122
|
+
## CLI
|
|
123
|
+
|
|
124
|
+
```console
|
|
125
|
+
$ dasmos --help
|
|
126
|
+
Usage: dasmos [OPTIONS] COMMAND [ARGS]...
|
|
127
|
+
|
|
128
|
+
A pluggable tracing disassembler.
|
|
129
|
+
|
|
130
|
+
Options:
|
|
131
|
+
--version Show the version and exit.
|
|
132
|
+
--help Show this message and exit.
|
|
133
|
+
|
|
134
|
+
Commands:
|
|
135
|
+
describe-cpu Describe a specific CPU plug-in.
|
|
136
|
+
describe-environment Describe a specific environment plug-in.
|
|
137
|
+
describe-renderer Describe a specific renderer plug-in.
|
|
138
|
+
disassemble Disassemble ROM and write the rendered output.
|
|
139
|
+
init Scaffold a starter dasmos driver at DRIVER_PATH.
|
|
140
|
+
list-cpus List the available CPU plug-ins.
|
|
141
|
+
list-environments List the available environment plug-ins.
|
|
142
|
+
list-renderers List the available renderer plug-ins.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The CLI commands inherit a uniform `--as display | tsv | json` story
|
|
146
|
+
(plus `--report`, `--header`, `--detailed`) from
|
|
147
|
+
[asyoulikeit](https://github.com/sixty-north/asyoulikeit), so any
|
|
148
|
+
command's structured output drives downstream tooling cleanly.
|
|
149
|
+
|
|
150
|
+
### Discovering plug-ins
|
|
151
|
+
|
|
152
|
+
Two namespaces are populated by the bundled extensions; third-party
|
|
153
|
+
packages register additional entries the same way.
|
|
154
|
+
|
|
155
|
+
```console
|
|
156
|
+
$ dasmos list-cpus
|
|
157
|
+
CPUs registered under 'dasmos.cpu'
|
|
158
|
+
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
159
|
+
┃ Name ┃ Description ┃
|
|
160
|
+
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
161
|
+
│ cmos65c02 │ The CMOS 65C02 — NMOS 6502 superset with 8 new mnemonics, 2 new │
|
|
162
|
+
│ nmos6502 │ The classic NMOS 6502. │
|
|
163
|
+
└───────────┴─────────────────────────────────────────────────────────────────┘
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```console
|
|
167
|
+
$ dasmos list-renderers
|
|
168
|
+
Renderers registered under 'dasmos.renderer'
|
|
169
|
+
┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
170
|
+
┃ Name ┃ Description ┃
|
|
171
|
+
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
172
|
+
│ beebasm │ Beebasm-syntax renderer. │
|
|
173
|
+
│ json │ JSON structured-output renderer. │
|
|
174
|
+
└─────────┴──────────────────────────────────┘
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```console
|
|
178
|
+
$ dasmos list-environments
|
|
179
|
+
Environments registered under 'dasmos.environment'
|
|
180
|
+
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
181
|
+
┃ Name ┃ Description ┃
|
|
182
|
+
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
183
|
+
│ acorn_bbc_hardware │ Acorn BBC Micro hardware-register Environment. │
|
|
184
|
+
│ acorn_mos │ Acorn MOS environment. │
|
|
185
|
+
│ acorn_sideways_rom │ Acorn sideways ROM environment. │
|
|
186
|
+
└────────────────────┴────────────────────────────────────────────────┘
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Environments layer onto a disassembler additively — a driver can
|
|
190
|
+
activate any number of them, in either the constructor's
|
|
191
|
+
``environments=[…]`` kwarg or via repeated
|
|
192
|
+
``d.use_environment(…)`` calls.
|
|
193
|
+
|
|
194
|
+
`describe-cpu` (and the matching `describe-renderer`) shows the full
|
|
195
|
+
docstring of a single plug-in:
|
|
196
|
+
|
|
197
|
+
```console
|
|
198
|
+
$ dasmos describe-cpu nmos6502
|
|
199
|
+
The classic NMOS 6502.
|
|
200
|
+
|
|
201
|
+
16-bit address space; the 56 documented mnemonics across 13
|
|
202
|
+
addressing modes; 151 documented opcodes (undocumented opcodes
|
|
203
|
+
deliberately omitted).
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
```console
|
|
207
|
+
$ dasmos list-cpus --help
|
|
208
|
+
Usage: dasmos list-cpus [OPTIONS]
|
|
209
|
+
|
|
210
|
+
List the available CPU plug-ins.
|
|
211
|
+
|
|
212
|
+
Produces reports:
|
|
213
|
+
cpus Registered CPU (processor) plug-ins with one-line descriptions.
|
|
214
|
+
|
|
215
|
+
Options:
|
|
216
|
+
Report Output Options:
|
|
217
|
+
--no-reports Suppress all report output. The handler still runs
|
|
218
|
+
(useful for action commands whose reports are
|
|
219
|
+
incidental); only rendering is skipped. Mutually
|
|
220
|
+
exclusive with --report and --all-reports.
|
|
221
|
+
--all-reports Render every report the handler returns,
|
|
222
|
+
regardless of the command's default_reports.
|
|
223
|
+
Useful for commands whose default is a subset (or
|
|
224
|
+
silent) but where you want the full picture this
|
|
225
|
+
time. Mutually exclusive with --report and --no-
|
|
226
|
+
reports.
|
|
227
|
+
--report [cpus] Report name(s) to display (can be specified
|
|
228
|
+
multiple times). Shows all if omitted. Valid
|
|
229
|
+
values: cpus.
|
|
230
|
+
--header / --no-header Include column headers in output. Overrides each
|
|
231
|
+
report's default. Format-specific: TSV prefixes
|
|
232
|
+
first cell with '#', display omits
|
|
233
|
+
headers/title/caption, JSON ignores this flag.
|
|
234
|
+
--detailed / --essential Include detailed columns or only essential
|
|
235
|
+
columns. Auto-detects based on output format if
|
|
236
|
+
not specified.
|
|
237
|
+
--as [display|json|tsv] Output format for tabular data. Defaults to
|
|
238
|
+
'display' for terminals, 'tsv' for pipes.
|
|
239
|
+
--help Show this message and exit.
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Migrating a py8dis driver
|
|
243
|
+
|
|
244
|
+
`scripts/py8dis2dasmos.py` is an AST-based porter that translates a
|
|
245
|
+
py8dis driver script into the equivalent *Dasmos* call shape:
|
|
246
|
+
|
|
247
|
+
```sh
|
|
248
|
+
uv run python scripts/py8dis2dasmos.py path/to/disasm_<rom>.py > ported.py
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
It rewrites the wildcard import, swaps `load(addr, file, cpu)` order,
|
|
252
|
+
maps `move()` → `d.add_move(...)`, threads `inline=True` →
|
|
253
|
+
`align=Align.INLINE`, recognises `subroutine(..., is_entry_point=False)`
|
|
254
|
+
as a label-plus-banner pair, expands `hook_subroutine` and the bundled
|
|
255
|
+
hooks (`stringhi_hook`, …) through `dasmos.hooks`, and configures the
|
|
256
|
+
`render()` call so the output matches py8dis's defaults
|
|
257
|
+
(`boundary_label_prefix='pydis_'`, `byte_column=True`).
|
|
258
|
+
|
|
259
|
+
Every transformation is covered by unit tests, plus a load-bearing
|
|
260
|
+
end-to-end test that ports the unmodified Econet Bridge driver and
|
|
261
|
+
asserts the resulting beebasm source re-assembles to the original ROM
|
|
262
|
+
bytes.
|
|
263
|
+
|
|
264
|
+
## Testing
|
|
265
|
+
|
|
266
|
+
`pytest -v` runs the suite. Tests marked `@pytest.mark.beebasm`
|
|
267
|
+
auto-skip when `beebasm` isn't on `PATH`; the rest run anywhere
|
|
268
|
+
Python and `uv` are installed. CI exercises the full matrix
|
|
269
|
+
(ubuntu/macos/windows × earliest+latest declared Python) **against
|
|
270
|
+
the installed wheel**, not the source tree, so packaging regressions
|
|
271
|
+
(missing entry points, omitted `py.typed` markers, unshipped
|
|
272
|
+
sub-packages) fail loud.
|
|
273
|
+
|
|
274
|
+
## Layout
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
src/dasmos/ the package
|
|
278
|
+
src/dasmos/cli.py Click entry point + asyoulikeit reports
|
|
279
|
+
src/dasmos/disassembler.py Disassembler (driver-script API)
|
|
280
|
+
src/dasmos/core/ Memory / labels / moves / classifications
|
|
281
|
+
src/dasmos/cpu.py Cpu base + Opcode shape
|
|
282
|
+
src/dasmos/renderer.py Renderer base
|
|
283
|
+
src/dasmos/ext/cpus/ Bundled CPU plug-ins (nmos6502, cmos65c02)
|
|
284
|
+
src/dasmos/ext/renderers/ Bundled renderer plug-ins (beebasm)
|
|
285
|
+
src/dasmos/hooks.py Subroutine hooks (stringhi_hook, …)
|
|
286
|
+
scripts/py8dis2dasmos.py py8dis → dasmos AST porter
|
|
287
|
+
scripts/generate_readme.py This README's generator
|
|
288
|
+
docs/design/ Architecture decisions & sweep memos
|
|
289
|
+
tests/ Unit + round-trip + py8dis-parity tests
|
|
290
|
+
tests/fixtures/ Vendored ROM + driver + reference output
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Related projects
|
|
294
|
+
|
|
295
|
+
- [py8dis (fork)][py8dis-fork] — the predecessor *Dasmos* is replacing.
|
|
296
|
+
Driver scripts written against this fork port via
|
|
297
|
+
`scripts/py8dis2dasmos.py`.
|
|
298
|
+
- The four sibling Acorn ROM disassembly repositories under the
|
|
299
|
+
[acornaeology][acornaeology] umbrella that drive *Dasmos*'s
|
|
300
|
+
round-trip / parity validation:
|
|
301
|
+
`acorn-econet-bridge`, `acorn-6502-tube-client`, `acorn-nfs`,
|
|
302
|
+
`acorn-adfs`.
|
|
303
|
+
- [beebasm](https://github.com/stardot/beebasm) — the BBC-Micro-style
|
|
304
|
+
assembler used as the round-trip oracle.
|
|
305
|
+
- [asyoulikeit](https://github.com/sixty-north/asyoulikeit) — the
|
|
306
|
+
CLI-output framework *Dasmos*'s reports are built on.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
This README is generated from `scripts/readme_template.md.j2` by
|
|
311
|
+
`scripts/generate_readme.py`. **Do not edit it directly** — edit the
|
|
312
|
+
template (or the generator, or the source files whose output it
|
|
313
|
+
captures) and re-run `uv run python scripts/generate_readme.py`. The
|
|
314
|
+
pre-commit hook and the `readme-check` CI job both run the
|
|
315
|
+
generator's `--check` mode and will refuse stale READMEs.
|
dasmos-0.1.2/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Dasmos
|
|
2
|
+
|
|
3
|
+
A pluggable tracing disassembler for retro CPUs, version `0.1.2`.
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://pypi.org/project/dasmos/"><img src="https://img.shields.io/pypi/v/dasmos.svg" alt="PyPI"></a>
|
|
7
|
+
<a href="https://github.com/acornaeology/dasmos/actions/workflows/release.yml"><img src="https://img.shields.io/github/actions/workflow/status/acornaeology/dasmos/release.yml?label=release" alt="Release"></a>
|
|
8
|
+
<a href="https://github.com/acornaeology/dasmos/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/acornaeology/dasmos/ci.yml?branch=master&label=CI" alt="CI"></a>
|
|
9
|
+
<a href="https://pypi.org/project/dasmos/"><img src="https://img.shields.io/pypi/pyversions/dasmos.svg" alt="Python versions"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
> *From Ancient Greek* δασμός *(dasmós, "division"), from* δαίω
|
|
13
|
+
> *(daíō, "to divide, share").*
|
|
14
|
+
|
|
15
|
+
*Dasmos* is a ground-up rewrite and reimagining of a heavily modified
|
|
16
|
+
[fork][py8dis-fork] of [py8dis][py8dis-original] — Steven Flintham's
|
|
17
|
+
original programmable tracing disassembler for the 6502 family.
|
|
18
|
+
*Dasmos* owes the whole core idea to Steven and to the py8dis project;
|
|
19
|
+
this project organises a tracing disassembler as a core algorithm
|
|
20
|
+
customised through plug-in extensions which provide knowledge of CPUs,
|
|
21
|
+
different assembly syntaxes, and target environments. The core of the
|
|
22
|
+
essential design vocabulary — driver scripts, traced classification,
|
|
23
|
+
label/comment/banner annotations — is all inspired by py8dis.
|
|
24
|
+
|
|
25
|
+
Driver scripts written for py8dis can be ported automatically to
|
|
26
|
+
*Dasmos* with the bundled `scripts/py8dis2dasmos.py`.
|
|
27
|
+
|
|
28
|
+
[py8dis-original]: https://github.com/ZornsLemma/py8dis
|
|
29
|
+
[py8dis-fork]: https://github.com/acornaeology/py8dis
|
|
30
|
+
[acornaeology]: https://github.com/acornaeology
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
> The `uv` and `uvx` commands shown below come from
|
|
35
|
+
> [Astral's uv](https://docs.astral.sh/uv/). If you don't have it
|
|
36
|
+
> yet, see the [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/)
|
|
37
|
+
> — one-line installers are available for macOS, Linux, and Windows.
|
|
38
|
+
|
|
39
|
+
For one-shot CLI use, no install needed — `uvx` fetches and runs in
|
|
40
|
+
a transient environment:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
uvx dasmos disassemble myrom.bin --load-addr '&8000'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
To add `dasmos` to a project (required for driver scripts that
|
|
47
|
+
`import dasmos`):
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
uv add dasmos
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or with pip:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
pip install dasmos
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
*Dasmos*'s round-trip / parity tests assemble back to bytes via
|
|
60
|
+
[beebasm](https://github.com/stardot/beebasm); `beebasm` on `PATH`
|
|
61
|
+
(or via the `BEEBASM` env var) activates them. CI builds beebasm
|
|
62
|
+
from source per matrix cell so the round-trip is part of the gate.
|
|
63
|
+
|
|
64
|
+
## Programmatic API
|
|
65
|
+
|
|
66
|
+
Every CLI capability is also reachable through the package. The
|
|
67
|
+
typical driver-script flow is: pick a CPU plug-in, load a binary,
|
|
68
|
+
register entry points / labels / classifications / annotations,
|
|
69
|
+
disassemble, then render via a renderer plug-in.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from dasmos import Disassembler, Align
|
|
73
|
+
|
|
74
|
+
d = Disassembler.create(cpu="nmos6502")
|
|
75
|
+
d.load("rom.bin", 0x8000)
|
|
76
|
+
d.entry(0x8000, name="start")
|
|
77
|
+
d.label(0x8006, "show", description="Display routine")
|
|
78
|
+
d.comment(0x8000, "Entry point.")
|
|
79
|
+
d.comment(0x8000, "magic", align=Align.INLINE)
|
|
80
|
+
|
|
81
|
+
ir = d.disassemble()
|
|
82
|
+
print(str(ir.render("beebasm")))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
That produces beebasm-assemblable source. Re-assembling it via the
|
|
86
|
+
real `beebasm` binary yields a binary byte-identical to the input
|
|
87
|
+
— the load-bearing **round-trip property** *Dasmos*'s test suite
|
|
88
|
+
exercises against real Acorn ROMs (the 8 KB Econet Bridge and the
|
|
89
|
+
2 KB-mapped 6502 Tube Client both round-trip end-to-end with full
|
|
90
|
+
py8dis annotation-content parity).
|
|
91
|
+
|
|
92
|
+
## CLI
|
|
93
|
+
|
|
94
|
+
```console
|
|
95
|
+
$ dasmos --help
|
|
96
|
+
Usage: dasmos [OPTIONS] COMMAND [ARGS]...
|
|
97
|
+
|
|
98
|
+
A pluggable tracing disassembler.
|
|
99
|
+
|
|
100
|
+
Options:
|
|
101
|
+
--version Show the version and exit.
|
|
102
|
+
--help Show this message and exit.
|
|
103
|
+
|
|
104
|
+
Commands:
|
|
105
|
+
describe-cpu Describe a specific CPU plug-in.
|
|
106
|
+
describe-environment Describe a specific environment plug-in.
|
|
107
|
+
describe-renderer Describe a specific renderer plug-in.
|
|
108
|
+
disassemble Disassemble ROM and write the rendered output.
|
|
109
|
+
init Scaffold a starter dasmos driver at DRIVER_PATH.
|
|
110
|
+
list-cpus List the available CPU plug-ins.
|
|
111
|
+
list-environments List the available environment plug-ins.
|
|
112
|
+
list-renderers List the available renderer plug-ins.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The CLI commands inherit a uniform `--as display | tsv | json` story
|
|
116
|
+
(plus `--report`, `--header`, `--detailed`) from
|
|
117
|
+
[asyoulikeit](https://github.com/sixty-north/asyoulikeit), so any
|
|
118
|
+
command's structured output drives downstream tooling cleanly.
|
|
119
|
+
|
|
120
|
+
### Discovering plug-ins
|
|
121
|
+
|
|
122
|
+
Two namespaces are populated by the bundled extensions; third-party
|
|
123
|
+
packages register additional entries the same way.
|
|
124
|
+
|
|
125
|
+
```console
|
|
126
|
+
$ dasmos list-cpus
|
|
127
|
+
CPUs registered under 'dasmos.cpu'
|
|
128
|
+
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
129
|
+
┃ Name ┃ Description ┃
|
|
130
|
+
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
131
|
+
│ cmos65c02 │ The CMOS 65C02 — NMOS 6502 superset with 8 new mnemonics, 2 new │
|
|
132
|
+
│ nmos6502 │ The classic NMOS 6502. │
|
|
133
|
+
└───────────┴─────────────────────────────────────────────────────────────────┘
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```console
|
|
137
|
+
$ dasmos list-renderers
|
|
138
|
+
Renderers registered under 'dasmos.renderer'
|
|
139
|
+
┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
140
|
+
┃ Name ┃ Description ┃
|
|
141
|
+
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
142
|
+
│ beebasm │ Beebasm-syntax renderer. │
|
|
143
|
+
│ json │ JSON structured-output renderer. │
|
|
144
|
+
└─────────┴──────────────────────────────────┘
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```console
|
|
148
|
+
$ dasmos list-environments
|
|
149
|
+
Environments registered under 'dasmos.environment'
|
|
150
|
+
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
151
|
+
┃ Name ┃ Description ┃
|
|
152
|
+
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
153
|
+
│ acorn_bbc_hardware │ Acorn BBC Micro hardware-register Environment. │
|
|
154
|
+
│ acorn_mos │ Acorn MOS environment. │
|
|
155
|
+
│ acorn_sideways_rom │ Acorn sideways ROM environment. │
|
|
156
|
+
└────────────────────┴────────────────────────────────────────────────┘
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Environments layer onto a disassembler additively — a driver can
|
|
160
|
+
activate any number of them, in either the constructor's
|
|
161
|
+
``environments=[…]`` kwarg or via repeated
|
|
162
|
+
``d.use_environment(…)`` calls.
|
|
163
|
+
|
|
164
|
+
`describe-cpu` (and the matching `describe-renderer`) shows the full
|
|
165
|
+
docstring of a single plug-in:
|
|
166
|
+
|
|
167
|
+
```console
|
|
168
|
+
$ dasmos describe-cpu nmos6502
|
|
169
|
+
The classic NMOS 6502.
|
|
170
|
+
|
|
171
|
+
16-bit address space; the 56 documented mnemonics across 13
|
|
172
|
+
addressing modes; 151 documented opcodes (undocumented opcodes
|
|
173
|
+
deliberately omitted).
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```console
|
|
177
|
+
$ dasmos list-cpus --help
|
|
178
|
+
Usage: dasmos list-cpus [OPTIONS]
|
|
179
|
+
|
|
180
|
+
List the available CPU plug-ins.
|
|
181
|
+
|
|
182
|
+
Produces reports:
|
|
183
|
+
cpus Registered CPU (processor) plug-ins with one-line descriptions.
|
|
184
|
+
|
|
185
|
+
Options:
|
|
186
|
+
Report Output Options:
|
|
187
|
+
--no-reports Suppress all report output. The handler still runs
|
|
188
|
+
(useful for action commands whose reports are
|
|
189
|
+
incidental); only rendering is skipped. Mutually
|
|
190
|
+
exclusive with --report and --all-reports.
|
|
191
|
+
--all-reports Render every report the handler returns,
|
|
192
|
+
regardless of the command's default_reports.
|
|
193
|
+
Useful for commands whose default is a subset (or
|
|
194
|
+
silent) but where you want the full picture this
|
|
195
|
+
time. Mutually exclusive with --report and --no-
|
|
196
|
+
reports.
|
|
197
|
+
--report [cpus] Report name(s) to display (can be specified
|
|
198
|
+
multiple times). Shows all if omitted. Valid
|
|
199
|
+
values: cpus.
|
|
200
|
+
--header / --no-header Include column headers in output. Overrides each
|
|
201
|
+
report's default. Format-specific: TSV prefixes
|
|
202
|
+
first cell with '#', display omits
|
|
203
|
+
headers/title/caption, JSON ignores this flag.
|
|
204
|
+
--detailed / --essential Include detailed columns or only essential
|
|
205
|
+
columns. Auto-detects based on output format if
|
|
206
|
+
not specified.
|
|
207
|
+
--as [display|json|tsv] Output format for tabular data. Defaults to
|
|
208
|
+
'display' for terminals, 'tsv' for pipes.
|
|
209
|
+
--help Show this message and exit.
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Migrating a py8dis driver
|
|
213
|
+
|
|
214
|
+
`scripts/py8dis2dasmos.py` is an AST-based porter that translates a
|
|
215
|
+
py8dis driver script into the equivalent *Dasmos* call shape:
|
|
216
|
+
|
|
217
|
+
```sh
|
|
218
|
+
uv run python scripts/py8dis2dasmos.py path/to/disasm_<rom>.py > ported.py
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
It rewrites the wildcard import, swaps `load(addr, file, cpu)` order,
|
|
222
|
+
maps `move()` → `d.add_move(...)`, threads `inline=True` →
|
|
223
|
+
`align=Align.INLINE`, recognises `subroutine(..., is_entry_point=False)`
|
|
224
|
+
as a label-plus-banner pair, expands `hook_subroutine` and the bundled
|
|
225
|
+
hooks (`stringhi_hook`, …) through `dasmos.hooks`, and configures the
|
|
226
|
+
`render()` call so the output matches py8dis's defaults
|
|
227
|
+
(`boundary_label_prefix='pydis_'`, `byte_column=True`).
|
|
228
|
+
|
|
229
|
+
Every transformation is covered by unit tests, plus a load-bearing
|
|
230
|
+
end-to-end test that ports the unmodified Econet Bridge driver and
|
|
231
|
+
asserts the resulting beebasm source re-assembles to the original ROM
|
|
232
|
+
bytes.
|
|
233
|
+
|
|
234
|
+
## Testing
|
|
235
|
+
|
|
236
|
+
`pytest -v` runs the suite. Tests marked `@pytest.mark.beebasm`
|
|
237
|
+
auto-skip when `beebasm` isn't on `PATH`; the rest run anywhere
|
|
238
|
+
Python and `uv` are installed. CI exercises the full matrix
|
|
239
|
+
(ubuntu/macos/windows × earliest+latest declared Python) **against
|
|
240
|
+
the installed wheel**, not the source tree, so packaging regressions
|
|
241
|
+
(missing entry points, omitted `py.typed` markers, unshipped
|
|
242
|
+
sub-packages) fail loud.
|
|
243
|
+
|
|
244
|
+
## Layout
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
src/dasmos/ the package
|
|
248
|
+
src/dasmos/cli.py Click entry point + asyoulikeit reports
|
|
249
|
+
src/dasmos/disassembler.py Disassembler (driver-script API)
|
|
250
|
+
src/dasmos/core/ Memory / labels / moves / classifications
|
|
251
|
+
src/dasmos/cpu.py Cpu base + Opcode shape
|
|
252
|
+
src/dasmos/renderer.py Renderer base
|
|
253
|
+
src/dasmos/ext/cpus/ Bundled CPU plug-ins (nmos6502, cmos65c02)
|
|
254
|
+
src/dasmos/ext/renderers/ Bundled renderer plug-ins (beebasm)
|
|
255
|
+
src/dasmos/hooks.py Subroutine hooks (stringhi_hook, …)
|
|
256
|
+
scripts/py8dis2dasmos.py py8dis → dasmos AST porter
|
|
257
|
+
scripts/generate_readme.py This README's generator
|
|
258
|
+
docs/design/ Architecture decisions & sweep memos
|
|
259
|
+
tests/ Unit + round-trip + py8dis-parity tests
|
|
260
|
+
tests/fixtures/ Vendored ROM + driver + reference output
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Related projects
|
|
264
|
+
|
|
265
|
+
- [py8dis (fork)][py8dis-fork] — the predecessor *Dasmos* is replacing.
|
|
266
|
+
Driver scripts written against this fork port via
|
|
267
|
+
`scripts/py8dis2dasmos.py`.
|
|
268
|
+
- The four sibling Acorn ROM disassembly repositories under the
|
|
269
|
+
[acornaeology][acornaeology] umbrella that drive *Dasmos*'s
|
|
270
|
+
round-trip / parity validation:
|
|
271
|
+
`acorn-econet-bridge`, `acorn-6502-tube-client`, `acorn-nfs`,
|
|
272
|
+
`acorn-adfs`.
|
|
273
|
+
- [beebasm](https://github.com/stardot/beebasm) — the BBC-Micro-style
|
|
274
|
+
assembler used as the round-trip oracle.
|
|
275
|
+
- [asyoulikeit](https://github.com/sixty-north/asyoulikeit) — the
|
|
276
|
+
CLI-output framework *Dasmos*'s reports are built on.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
This README is generated from `scripts/readme_template.md.j2` by
|
|
281
|
+
`scripts/generate_readme.py`. **Do not edit it directly** — edit the
|
|
282
|
+
template (or the generator, or the source files whose output it
|
|
283
|
+
captures) and re-run `uv run python scripts/generate_readme.py`. The
|
|
284
|
+
pre-commit hook and the `readme-check` CI job both run the
|
|
285
|
+
generator's `--check` mode and will refuse stale READMEs.
|