
Every character your programs have printed went through one routine, OUTC, at 0F1Ah. This section looks at the three doors into it, at the table that decides what a control code does, and at the 1,792 bytes that give each character its shape.
Call 158 is the one you know. Its table entry points at OUTC.
RST 10h is a one-byte shortcut to the same place. In the ROM, 0010h holds:
l0010h:
jp OUTC ;0010
The MOS uses it to print single characters - the prompt, for one (S9). It saves a byte over RST 8 / DEFB 158 every time.
RST 18h prints a whole message, and the message is written in the code, straight after the RST:
PRMZ:
ex (sp),hl ;0018
l0019h:
call PRMCHR ;0019
jr z,l0019h ;001c
ex (sp),hl ;001e
ret ;001f
...
PRMCHR:
ld a,(hl) ;0f3f
sub_0f40h:
bit 7,a ;0f40
res 7,a ;0f42
rst 10h ;0f44
inc hl ;0f45
ret ;0f46
EX (SP),HL swaps HL with the return address - which is the address of the message. PRMCHR prints one character with RST 10h, but first tests bit 7: the last character of every message has bit 7 set. BIT 7,A sets the zero flag for every character except the last, so JR Z loops until the last one is printed. The final EX (SP),HL puts back a return address that now points past the message, so the program carries on after it.
The design saves bytes twice. No separate pointer to the message is needed, and no terminating zero: the end marker is a bit borrowed from the last character, which never needs bit 7 anyway. ERROR (S9) is written exactly like this.
Characters below 20h are not printed; they do things. 13 returns to the start of the line, 10 moves down a line, 8 steps back. OUTC handles them with a table like FMTBL: VDUTBL, at 0A68h, 32 addresses - one for each code from 00h to 1Fh, in order.
VDUTBL:
defw NODSP ;0a68
defw l09fbh ;0a6a
defw NODSP ;0a6c
defw NODSP ;0a6e
defw l08cfh ;0a70
defw NODSP ;0a72
defw l09a6h ;0a74
defw l0f71h ;0a76
defw l08e7h ;0a78
defw NODSP ;0a7a
defw l08d9h ;0a7c
defw l08e2h ;0a7e
defw l0930h ;0a80
defw CRET ;0a82
...
Entry 0Dh is CRET, the carriage return. NODSP is a single RET: codes that do nothing all point at it, which is cheaper than testing for them.
The Einstein's video chip draws each character from an 8 x 8 pattern of bits. Those patterns come from the ROM. PGTAB, at 116Dh, holds eight bytes for every character from 20h (space) to FFh - 224 characters, 1,792 bytes - and at start-up the MOS sends all of them to the video chip's memory.
Here is A, code 41h, at 116Dh + 8 x (41h - 20h) = 1275h:
defb 000h,010h,028h,044h,07ch,044h,044h,000h ;1275 ..(D|DD.
Write the bytes in binary, one under another, and the letter appears:
00h ........
10h ...#....
28h ..#.#...
44h .#...#..
7Ch .#####..
44h .#...#..
44h .#...#..
00h ........
Top row first; each 1 bit is a lit pixel, bit 7 on the left.
Above code 90 the shapes are not all the ASCII characters you might expect: the Einstein uses some of those codes for its own symbols. Its glyphs are whatever these 1,792 bytes say.
Control codes are easiest to see by printing one between ordinary characters:
ORG 256
LD A,'A'
RST 8
DEFB 158
LD A,'B'
RST 8
DEFB 158
LD A,13 ; carriage return: VDUTBL entry 0Dh, CRET
RST 8
DEFB 158
LD A,'C'
RST 8
DEFB 158
RET
Build and run
Press Run.
What you should see
CAB
A BC DE HL PC SZ-H-PNC
43 3D41 08FF FB3E 0FA5 00101000
A and B were printed after the prompt; 13 went back to the start of the line, and C landed on top of the >. The register display shows A = 43h, the C.
In your copy of mos12.asm, change VDUTBL's entry for 0Dh from CRET to NODSP, rebuild the ROM (S5) and boot it. Before you look, predict two things: what the program above prints, and what the start-up screen looks like. The second is the more revealing - why does it change at all?
OUTC is reached by call 158, by RST 10h, and by RST 18h, which prints the text that follows it, ending at a byte with bit 7 set. Control codes 00h-1Fh are dispatched through VDUTBL, 32 addresses at 0A68h. Every character's shape is eight bytes in PGTAB, from 116Dh, copied to the video chip at start-up.
S11 turns to the keyboard: how a key press becomes the character OUTC prints.
This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.