Widen the memory controller's path to sixteen bits

The controller now reaches bank memory two bytes at a time, so a transfer whose source,
destination and length are all even moves two bytes a cycle between banks and one within
a bank - twice what each was. A 256 byte block between banks falls from 257 cycles to 129.

Alignment is required all three ways because a word is read at an even address and written
at an even address; an odd anything would mean shifting bytes across word boundaries to
line them up, which is a different design. A misaligned transfer falls back to the byte a
cycle it cost before, so nothing already written got slower.

THE CPU DOES NOT CHANGE. It still sees eight bits, a Data Pointer still addresses a byte,
and no instruction means anything different. This is a peripheral getting faster, which is
why it is worth doing now rather than after more is built on top of it.

The rule is deliberately visible rather than smoothed over: aligning a buffer costs nothing
and halves what moving it costs, and a cost a program cannot see is a cost it cannot avoid.

Tests/cycles.sh is new, and is the test the Test Manual has always said this kind of change
would need - run.sh strips the cycle count from every recorded result, so nothing else in
the suite can see any of this. It pins the RATE rather than a total: each case runs twice
from programs whose instructions are identical but for the byte written to the Command
port, once asking for the transfer and once for GuardOff, which costs nothing beyond the
port write. The difference is the transfer and nothing else. Verified by disabling the
widening, which failed exactly the three aligned cases and left the five misaligned ones
passing.

The Programming Manual gains a section saying what a transfer costs, which it never said at
all - it only promised a transfer does not wait, which is a different claim and could be
read as promising it is free.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-08-28 21:30:12 -04:00
co-authored by Claude Opus 5
parent c3c2451afe
commit 4c3eac8d9c
7 changed files with 234 additions and 17 deletions
+18 -5
View File
@@ -9,7 +9,7 @@ believe them.
## What The Suite Claims:
The suite is not one thing. It is seven scripts making five different kinds of claim, and
The suite is not one thing. It is eight scripts making five different kinds of claim, and
knowing which claim you are relying on is the whole point of this document. A recorded
transcript and a byte-for-byte comparison against a second implementation both print
`[ok ]`, and they are worth wildly different amounts.
@@ -55,6 +55,7 @@ Individual scripts can be run on their own, from anywhere:
./Tests/run.sh hello waitTest Only the named ones.
./Tests/run.sh --bless Record current output as expected. See below.
./Tests/disk.sh The disk tool against the format.
./Tests/cycles.sh What the memory controller charges.
./Tests/terminal.sh The things a recorded file cannot see.
./Tests/native.sh The two assemblers against each other.
./Tests/agree.sh The two filesystems against each other.
@@ -153,10 +154,22 @@ that a prompt arrives before input is read, that a keystroke arrives without Ret
the terminal is handed back however the machine dies - SIGHUP, SIGINT, SIGQUIT, SIGABRT,
SIGSEGV, SIGTERM - and that suspending and resuming leave it as they found it.
It also asks the one question about cycles that nothing else can, since the count is
stripped from every recorded result: whether a program on a slow disk slept through the
wait or spun on it. Both print the same characters and take the same elapsed time. Only the
split between idle and bus cycles tells them apart.
It also asks the one question about *waiting* that nothing else can, since the count is
stripped from every recorded result: whether a program on a slow disk slept through the wait
or spun on it. Both print the same characters and take the same elapsed time. Only the split
between idle and bus cycles tells them apart.
`Tests/cycles.sh` is the other half of the same bargain, and exists because the determinism
rules below throw the cycle count away. It measures what the memory controller charges for
moving memory - which is real time out of a program's budget, and is invisible everywhere
else in this suite.
**It pins the rate rather than a total.** Each case runs twice, from programs whose
instructions are identical except for the byte written to the Command port: once asking for
the transfer, and once asking for `GuardOff`, which lowers a fence that was never raised and
costs nothing beyond the port write. The difference between the two runs is the transfer and
nothing else - no instruction count, no setup, no startup - so the check survives every
change to the machine that is not a change to what a transfer costs.
### 5. The documents against the code