.png)
Where things are, byte by byte, in both of the machine's memories.
This is a working document. It grows as facts are established, and it is deliberately explicit about the gaps - a map that quietly guesses at the parts nobody has checked is worse than one with blank spaces on it.
Every entry carries a mark:
| Mark | Means |
|---|---|
## |
Established by running code on the machine. |
~~ |
From documentation. Cited, plausible, not tested here. |
?? |
Unknown. Nobody has looked, or looking was inconclusive. |
Two separate memories use the same numbers. The Z80's 64K and the VDP's 16K
have nothing to do with each other: address 1800 in one is unrelated to
address 1800 in the other. Keeping that straight is most of the difficulty.
Not drawn to scale. The interesting parts are at the two ends.
0000 +====================================+
| Restart vectors |
| 0008 RST 08h - the MCAL entry | ##
| 0038 RST 38h - break | ~~
0100 +------------------------------------+
| Your program loads and runs here | ##
| |
| 0769 where a program's final | ##
| RET hands control back |
| |
| 4000 second ROM protocol area, | ~~
| execution entry at 4004 |
| |
| 7530, 8000, 8C3C all confirmed | ##
| writable RAM - spot checks only |
| |
| Everything else through here: | ??
| where RAM begins and ends, where |
| ROM sits, what paging exists |
| |
FB00 +====================================+
| MOS scratch pad - see below |
FC00 | interrupt routine area | ~~
FCED | <-- SP when your program starts | ##
FE00 | disc sector buffer, "normally" | ~~
FFFF +====================================+
Where MOS keeps its working values. Anything a ROM call needs told, beyond
what fits in registers, is here. Source for the ~~ rows: the Einstein
Compendium's "Scratchpad" chapter, which credits Crystal Research's own
"Albert Revealed" for the complete list - this project has only the
Compendium's subset.
| Address | Name | What it is | |
|---|---|---|---|
FB00 |
Interrupt vector, CTC channel 0 | ~~ |
|
FB02 |
Interrupt vector, CTC channel 1 | ~~ |
|
FB04 |
Interrupt vector, CTC channel 3 | ~~ |
|
FB06 |
Interrupt vector, real-time clock | ~~ |
|
FB08 |
Interrupt vector, keyboard | ~~ |
|
FB0A |
Interrupt vector, A/D converter | ~~ |
|
FB0C |
Interrupt vector, fire button | ~~ |
|
FB0E |
Interrupt vector, free for user code | ~~ |
|
FB10 |
Interrupt vector, printer | ~~ |
|
FB12 |
Interrupt vector, PIO port B | ~~ |
|
FB36 |
Current VDP mode (a shadow copy - the real register is write-only) | ~~ |
|
FB38 |
TCOLR | Text colour (high nibble fg, low nibble bg) | ~~ |
FB39 |
GCOLR | Graphics colour | ~~ |
FB43 |
Key repeat speed | ~~ |
|
FB44 |
Disc sector size, in 256-byte blocks (normally 2) | ~~ |
|
FB45 |
PCFLGS | 80-column card flags | ~~ |
FB46 |
Code of the last key pressed | ~~ |
|
FB50 |
HSTDSC | Disc drive, 0-3 | ~~ |
FB51 |
HSTTRK | Track, 0-27h | ~~ |
FB52 |
HSTSEC | Sector, 0-9 | ~~ |
FB53 |
HSTDMA | Sector buffer address | ~~ |
FB55 |
Flag: disc read or write | ~~ |
|
FB56 |
Disc error status | ~~ |
|
FB57 |
Retry count before signalling a disc error | ~~ |
|
FB58-FB5B |
Current track, one byte per drive 0-3 | ~~ |
|
FB5F |
VDP status (a shadow copy) | ~~ |
|
FB60-FB78 |
Saved registers for the register display: I, IX, IY, SP, AF', BC', DE', HL', AF, BC, DE, HL, PC | ~~ |
|
FB92 |
Flag for interrupts | ~~ |
|
FB93-FB94 |
Pointer to the current function key's data in VRAM | ~~ |
|
FB96 |
X1 | Line end X, two bytes | ## |
FB98 |
Y1 | Line end Y, two bytes | ## |
FB9A |
ORGX | Graphics origin X | ~~ |
FB9C |
ORGY | Graphics origin Y | ~~ |
FB9E |
CX | Polygon centre X | ~~ |
FBA0 |
CY | Polygon centre Y | ~~ |
FBA2 |
RADX | Horizontal radius | ~~ |
FBA4 |
RADY | Vertical radius | ~~ |
FBA6 |
CINC | Polygon sides | ~~ |
FBA8-FBAB |
DOTON etc | Line style, four bytes | ## |
FBAD |
FILLMOD | Fill mode | ~~ |
FBAE |
Fill routine's stack pointer | ~~ |
|
FBB0 |
Disc head stepping rate: 00=6ms, 01=12ms, 02=20ms, 03=30ms | ~~ |
|
FBB1 |
Side flag: single=0, double=1 | ~~ |
SP starts at FCED and grows downward.
FCED <-- SP at program entry ##
|
| 100 bytes of pushes: fine ##
|
FC8D ? somewhere in here it stops working ??
|
FC3D | 176 bytes of pushes: the machine resets ##
v
The boundary is bracketed, not located, and what gets overwritten is not
identified. Budget well under 176 bytes and remember every CALL costs two.
This one is fully mapped, and it is drawn roughly to scale.
Graphics II puts the pattern table and the colour table - 6144 bytes each - in the lower and upper 8K halves. That leaves exactly 2048 bytes spare in each half, and everything else the machine needs is squeezed into those two holes. It is worth seeing the halves before the detail:
0000 +====================================+
| LOWER HALF 8192 bytes |
| pattern table 0000-17FF 6144 |
| spare 1800-1FFF 2048 | <- the font
2000 +====================================+
| UPPER HALF 8192 bytes |
| colour table 2000-37FF 6144 |
| spare 3800-3FFF 2048 | <- everything else
3FFF +====================================+
In detail:
0000 +====================================+
| Pattern bank 0 | ##
| 256 patterns x 8 bytes |
| serves screen rows 0-7 |
0800 +------------------------------------+
| Pattern bank 1 | ##
| serves screen rows 8-15 |
1000 +------------------------------------+
| Pattern bank 2 | ##
| serves screen rows 16-23 |
1800 +====================================+
| MOS font AND sprite patterns | ##
| 256 characters x 8 bytes |
| a glyph is at 1800 + code * 8 |
| 6 pixels wide, left-justified |
| ** this is also the sprite |
| pattern table: sprite pattern |
| n IS character n ** |
| and it has to be - 1800 is the |
| only 2K block in VRAM that is |
| not already a VDP table |
2000 +====================================+
| Colour table | ##
| bank 0 2000-27FF |
| bank 1 2800-2FFF |
| bank 2 3000-37FF |
| 8 bytes per pattern, one per |
| row: high nibble colours the 1 |
| bits, low nibble the 0 bits |
| MOS leaves F0 everywhere |
| high bytes 96 / 104 / 112 |
3800 +====================================+
| Name table | ##
| 768 entries, one per cell |
| cell r,c is entry r * 32 + c |
| MOS leaves it 00 01 02 03 ... |
3B00 +------------------------------------+
| Sprite attribute table | ##
| 32 entries x 4 bytes |
| Y, X, pattern number, then |
| colour in the low nibble with |
| the early clock bit as bit 7 |
| MOS leaves it all 00 - every |
| sprite present and transparent |
3B80 +------------------------------------+
| Function key data | ~~
| 128 bytes, MOS leaves it all 80 |
| one string per key, separated |
| by adding 80h to its last byte |
3C00 +====================================+
| MOS's text buffer | ##
| 960 bytes of ASCII, 40 x 24 |
| row r, column c at |
| 3C00 + r * 40 + c |
| the VDP never reads this |
3FC0 +------------------------------------+
| 64 bytes, purpose unknown | ~~??
| not reset by the reset button |
| (power cycling it is) |
3FFF +====================================+
Worth spelling out, because it confuses everyone once.
MOS runs the display as a bitmap: the name table is filled with ascending
numbers so every cell owns a private pattern, and text is drawn as pixels into
the pattern banks. So the letters on screen exist as pixels in
0000-17FF.
The font at 1800 is the source those pixels are copied from.
And 3C00 is a plain ASCII copy of what has been printed, which MOS keeps
because a bitmap cannot be read back as characters. That is the copy the
line-input call hands you.
Three appearances of the same text, in three different forms, for three different reasons.
The Z80 has a third, separate space for talking to hardware, reached with
OUT and IN. Only two entries are established.
| Port | What it is | |
|---|---|---|
| 8 | VDP data | ## |
| 9 | VDP address and register control | ## |
Everything else - keyboard, sound, disc, printer, serial - is ??. The ROM
calls reach them and no experiment here has gone underneath.
write to VRAM: port 9 <- low byte of address
port 9 <- 40h + top six bits
port 8 <- data, address advances itself
read from VRAM: port 9 <- low byte
port 9 <- top six bits, no 40h
port 8 -> data ~~
write a register: port 9 <- the value
port 9 <- 80h + register number
read the status: port 9 -> status byte ~~
The write paths are established. The two read paths come from the datasheet and have not been exercised here.
Named plainly, because they are the honest content of a map like this:
Where RAM begins and ends. Three addresses have been poked and found writable. That is not a map. Nothing is known about where ROM sits, whether paging exists, or what a program may safely use.
The VDP registers. They are write-only, and the emulator exposes no way to read them. Their values have been worked out from behaviour instead - the display mode from the memory layout, and R5 = 118 and R6 = 3 from the sprite table addresses that work. Derived, not read.
Every port but 8 and 9.
The interrupt rate. Interrupts are known to be enabled and something generates them. How often is not established.
When an experiment settles something, the entry goes in with its mark. A ~~
becomes ## when code has confirmed it - not before, and the mark changes
only for the specific thing tested. "The datasheet says the sector buffer is
normally at FE00" and "a program read the sector buffer at FE00" are different
claims and get different marks.
A ?? that turns out to be genuinely unknowable stays ?? with a note. There
is no shame in a blank space, and considerable risk in filling one with a
guess.