.png)
Everything in this course is built on a modern computer and sent to the Einstein. In 1984 there was no modern computer: you wrote, assembled and ran your program on the Einstein itself. One tool for the job was Zen, an editor, assembler and debugger in one small program, and it still works.
This appendix is optional, and nothing in the course depends on it. It shows how to build the course's programs with Zen instead of the VS Code extension, and what to change in them so that Zen accepts them. How to drive Zen itself - typing, listing, the debugger - is covered in our guide Assembly Language with Zen, and the Zen disc is on the Downloads page.
The instructions are the same: LD, JP, RST 8 and the rest are the processor's, and Zen writes them into exactly the same bytes as the course's assembler. Everything around them is where the two disagree, just as Appendix II describes for assemblers in general.
| In the course | In Zen |
|---|---|
ORG 256 at the top | ORG 256 then LOAD 8000H |
| nothing at the end | END on the last line |
0FFh, 4000h | 0FFH, 4000H - the H must be a capital |
00011000b | 18H - Zen has no binary numbers |
DEFM "SCORE" | DEFB "SCORE" |
3800h+9*32+12 | 392CH - work it out yourself (see below) |
DEFS 64 is 64 zeros | DEFS 64 is 64 bytes of whatever was there |
include 'vdp.asm' | read the files in one after another |
| the extension builds and runs | A to assemble, WC to save, run from the 0: prompt |
Labels need no change: Zen wants the colon, allows lower case and long names, and, like the course's assembler, loop and LOOP are different labels. Double quotes, JP $ and comments after a semicolon all work as you know them.
Every program in the course starts with ORG 256, because every Einstein program runs from address 256, which is 100H. But while you work in Zen, Zen itself is sitting at 100H. So Zen needs to be told two things: where the program will run, and where to put it for now.
ORG 256 ; where the program will run
LOAD 8000H ; where Zen puts it while you work
ORG works exactly as it always has. LOAD 8000H tells Zen to store the machine code at 8000H instead, out of its own way. The code is built to run at 100H and kept at 8000H until you save it.
And at the very end, one more line:
END
Without it, Zen reads past your last line and stops with EOF.
Here is the program from S3, ready for Zen:
ORG 256 ; Start of the program in memory
LOAD 8000H
LD A,'H' ; Load the letter 'H' into register A
RST 8 ; Call a system routine
DEFB 158 ; ZOUTC - print the character in A
LD A,'E'
RST 8
DEFB 158 ; ZOUTC
LD A,'L'
RST 8
DEFB 158 ; ZOUTC
LD A,'L'
RST 8
DEFB 158 ; ZOUTC
LD A,'O'
RST 8
DEFB 158 ; ZOUTC
PROGEND:
RET ; Return to the prompt
END
Type it in with Zen's E command, or bring it across from your computer as described below. Then:
A to assemble. At OPTION> press ENTER. If a line is wrong, Zen names the problem and shows the line; if all is well you are back at ZEN> with nothing to report.S lists the labels with their addresses. It asks OPTION> too: type V to see the list on the screen.WC saves the program. It asks for START>, which is 8000H, then STOP>, the last byte, then NAME>: HELLO.B leaves Zen, and HELLO at the 0: prompt runs your program. It prints HELLO, and its RET brings you back to the prompt.STOP> is the address of the program's last byte, at 8000H onwards. The PROGEND: label above is there to find it. S shows its address as the program will run, from 100H onwards; add 7F00H to that and you have the address where it is stored. Here S shows PROGEND0114, and 0114H + 7F00H is 8014H, so:
WC
START>8000H
STOP>8014H
NAME>HELLO
Put PROGEND: in front of the last line that holds code or data you want saved. If that line is more than one byte long, STOP> has to reach its last byte, so add a few; going a little past the end does no harm, because Zen rounds every file up to a whole number of 256-byte blocks anyway.
Write PROGEND in capitals. S lists only labels written in capitals. The course's own lower-case labels work perfectly in Zen, but they do not appear in the list.
You can keep writing in VS Code and use Zen only to assemble. Zen reads a source file with RS, and Zen's source files are ordinary text files named NAME.SRC, with a name of up to eight capital letters or digits.
Two things matter when you save the file on your computer:
.SRC. GAME.SRC is read with RS and the name GAME.EOF. In VS Code, click LF in the status bar at the bottom of the window and choose CRLF before saving.Put the file on a disc image with the Einstein Disc Tools, put that disc in drive 1, and in Zen:
K
RS
NAME>1:GAME
K clears whatever text was in memory first, because RS adds what it reads to the end of the text already there.
Work down this list with any program from the course. Most of the changes show up as errors when you assemble, so Zen will point you at them. Two do not, and they are marked.
Add LOAD 8000H after ORG 256, and END on the last line.
4000h becomes 4000H. A small h gives OPERAND. A hex number must still start with a digit: 0FFH, not FFH, which Zen would take for a label.
Zen has none, and 00011000b gives OPERAND. Split the eight bits into two groups of four and write each group as one hex digit:
| Binary | Groups | Hex |
|---|---|---|
00011000b | 0001 1000 | 18H |
01111110b | 0111 1110 | 7EH |
11011011b | 1101 1011 | 0DBH |
| Group | Digit | Group | Digit | Group | Digit | Group | Digit |
|---|---|---|---|---|---|---|---|
0000 | 0 | 0100 | 4 | 1000 | 8 | 1100 | C |
0001 | 1 | 0101 | 5 | 1001 | 9 | 1101 | D |
0010 | 2 | 0110 | 6 | 1010 | A | 1110 | E |
0011 | 3 | 0111 | 7 | 1011 | B | 1111 | F |
You lose the picture that the ones and noughts drew. Keep the binary as a comment beside each line if you want it: DEFB 18H ; 00011000.
DEFM gives HUH?. DEFB takes text in quotes, so nothing else changes.
Zen does no multiplication before addition. 3800h+9*32+12 is worked as 3800H plus 9, times 32, plus 12, which is 012CH: a completely different address from the 392CH you meant, and your text lands nowhere near where you put it. Work any sum containing * or / out yourself and write the answer: 9 × 32 = 288 = 120H, and 3800H + 120H + 0CH = 392CH. Sums of + and - alone are safe, because order does not matter to them.
In the course, DEFS 64 gives 64 zero bytes. In Zen it reserves the 64 bytes and leaves in them whatever memory already held. A program that relies on a buffer starting at zero will misbehave. The simplest cure is to clear memory before you assemble, with Zen's F (Fill) command:
F
START>8000H
STOP>9FFFH
DATA>0
Better still, have the program clear its own buffers when it starts. Then it does not matter which assembler built it.
Zen has no include. The course's main.asm from S30 ends with its three include lines, so read the files in the same order they are included, and RS joins them into one text. Delete the include lines, put END at the end of the last file only, and then:
K
RS
NAME>1:MAIN
RS
NAME>1:VDP
RS
NAME>1:SCREENS
RS
NAME>1:SPRITES
Assemble the whole thing as one program, which is exactly what include made of it anyway: one ORG and one LOAD at the start, one END at the finish.
Zen keeps your source text in memory from 2400H upwards, and LOAD 8000H puts the code at 8000H, so the text has about 23K before the two meet. The final game of this course, comments and all, is about 16K of text and fits with room to spare. H (Howbig) shows where your text ends: if the second number it prints is getting close to 8000, it is time to shorten your comments.
For a quick test, Zen can run code where it sits, stop it at a breakpoint and show the registers, without saving anything. The code has to be built to run where it is stored, so use the same address for both, say ORG 9000H and LOAD 9000H, then G9000H. The Zen guide shows how. For the finished program, go back to ORG 256 and LOAD 8000H.
ORG 256, then LOAD 8000H, at the top; END at the bottom.A assembles, WC from 8000H saves a program, and it runs from the 0: prompt like any other.H for hex, no binary, DEFB for DEFM, and read files in turn instead of include.* or / yourself, and never assume DEFS space is zero.