Skip to content

Refuse --ram above what the configured CPU can address (issue #98) - #99

Merged
sidick merged 1 commit into
mainfrom
fix/ram-exceeds-cpu-address-width
Sep 28, 2026
Merged

sidick merged 1 commit into
mainfrom
fix/ram-exceeds-cpu-address-width

Conversation

@sidick

@sidick sidick commented Sep 28, 2026

Copy link
Copy Markdown
Owner

Fixes #98.

--ram 32M on the default --cpu 68000 gave you a program that died several library calls later with continuation stub trapped at 0x000000c4 with no pending continuation -- a message about volamos's internals that points at nothing the user did.

Cause

The 24-bit address bus. The guest stack sits at the top of the address space, so --ram 64M puts A7 near 0x0400_0000, which a 68000/68010 cannot express. The address wraps, the JSR into a library pushes its return address into low memory, and the RTS pops whatever happened to be there. The wrapping is faithful to the hardware; placing the stack where the CPU cannot reach it is not.

Reproduces on main with the repo's own fixtures at --ram 17M -- one byte over 16 MiB is enough:

$ volamos --ram 17M fixtures/exectest
volamos: fixtures/exectest: continuation stub trapped at 0x000000c4 with no pending
continuation (guest jumped to the trampoline stub directly, or ContinuationStack
bookkeeping is out of sync)

fixtures/memtest too. fixtures/hello does not, because it makes no call that has to return through a continuation -- which is why a smoke test never caught this.

Fix

run checks before it even reads the program, and fails naming both flags -- the same treatment an oversized --stack already got:

$ volamos --ram 17M fixtures/exectest
volamos: --ram 17825792 is more address space than a 68000 can reach: that CPU has a
24-bit address bus, so it can only address 16777216 bytes, and the guest stack at the
top of a larger space would be at an address it cannot express -- ask for a 32-bit
address bus with --cpu 68020 (or any later model), or lower the size to 16777216 or
less (--ram on the command line, RAM= in a config file)

$ volamos --ram 64M --cpu 68020 fixtures/exectest
exec ok

Only a raised --ram was ever affected -- the default is exactly 16 MiB, which a test now pins against the CPU's own limit so the two constants cannot drift apart.

backend::addressable_bytes asks the m68k crate for the limit rather than hardcoding a model table. The crate owns CpuCore::address_mask and sets it per model, so the one authority on which models wrap is the emulator that does the wrapping. That also settles the 68EC020, which has a 24-bit external bus on real silicon that the crate does not currently model: volamos follows the crate rather than rejecting a configuration that demonstrably works today. Verified empirically across all 11 models -- only 68000 and 68010 wrap.

The check covers the config-file path too, since it sits in run after the merge (RAM=32M in a .volamos is refused the same way, and the message names RAM= as well as --ram).

Also here

Tests

Four new: the default---ram-equals-68000's-limit invariant, rejection on both 24-bit models, acceptance at u32::MAX on all nine 32-bit ones, and a cpu_model_name <-> parse_cpu_type round trip so an error message can only ever show a spelling the user could have typed.

cargo test --release: 1014 passed, 0 failed. clippy -D warnings and fmt --check clean.

🤖 Generated with Claude Code

`--ram 32M` on the default `--cpu 68000` produced a program that died
several library calls later with "continuation stub trapped at
0x000000c4 with no pending continuation", which points at nothing the
user did. The cause is the 24-bit address bus: the guest stack sits at
the top of the address space, so a >16 MiB space puts A7 at an address a
68000/68010 cannot express. It wraps, the JSR into a library pushes its
return address into low memory, and the RTS pops whatever was there. The
wrapping is faithful to the hardware; placing the stack out of reach is
not. The repo's own fixtures/exectest and fixtures/memtest both hit it
at --ram 17M; fixtures/hello does not, because it makes no call that has
to return through a continuation, so a smoke test misses this entirely.

So `run` now checks it before reading the program, and fails naming both
flags -- the same treatment an oversized --stack already got. Only a
raised --ram was ever affected: the default is exactly 16 MiB, which a
new test pins against the CPU's own limit so the two constants cannot
drift apart.

`backend::addressable_bytes` asks the m68k crate for the limit rather
than hardcoding a model table, since the crate owns `address_mask` and
is the thing that does the wrapping. That also settles the 68EC020,
which has a 24-bit *external* bus on real silicon that the crate does
not model: volamos follows the crate instead of rejecting a
configuration that works today.

Also fixes two now-wrong doc examples (`--ram 64M` with no `--cpu`, in
CLI-Reference.md and Examples.md) and adds the missing 0.7 changelog
entry for #95/#97.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sidick
sidick merged commit fcbe14d into main Sep 28, 2026
9 checks passed
@sidick
sidick deleted the fix/ram-exceeds-cpu-address-width branch September 28, 2026 07:25
@sidick sidick mentioned this pull request Sep 28, 2026
sidick added a commit that referenced this pull request Sep 28, 2026
Opens the 0.8 changelog section with everything merged since v0.7, and
moves the #95/#97 and #98 entries into it -- both were written into the
already-released 0.7 section by mistake.

New in 0.8: the --sanitize recycled-block false positives (#95/#97), the
--ram-versus-CPU-address-bus check (#98/#99), pr_Arguments on the fake
Process (#89), AllocDosObject's DOS_FIB (#90), SetVar on a missing
variable (#91), and OpenLibrary's CMP.W version comparison (#92). The
three m68k crate bumps (#88/#93/#94) get no entry, as dependency updates
never have.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--ram above 16 MiB silently breaks 68000/68010 runs: guest stack is placed beyond the 24-bit address bus

1 participant