System-5 programmer's guide¶
How to program System-5 on the bare machine: the memory and I/O maps, each device as software sees it, the boot ROM (HBIOS) and its monitor, the BIOS calls, and the tools.
The hardware behind each section is in the card chapters; the 1802 instruction set is in reference/datasheets/ (the RCA user manual, MPM-201A).
The machine at a glance¶
| Item | Value |
|---|---|
| CPU | CDP1802, about 1.76 MHz (crystal unread; the 1861 frequency), 4.5 µs per machine cycle |
| RAM | 0000–6FFF (28K) |
| Video RAM | 7000–77FF (64 × 16 characters at 7000–73FF) |
| CRTC | 7800 (address register), 7801 (data register) |
| EPROM | 8000–EFFF on the memory card; F000–FFFF the CPU card's boot ROM (HBIOS) |
| Console | the 6845 screen and the PS/2 keyboard (no serial port) |
| Disk | a CompactFlash card on the IDE card, 512-byte sectors by LBA |
| Operating system | ELF/OS (Mike Riley), booted from the CF card |
Memory map¶
| Address | Contents | Notes |
|---|---|---|
| 0000–00FF | monitor stack and workspace | the monitor's stack starts at 00FF and grows down |
| 0100–6FFF | programs; ELF/OS | ELF/OS's boot sector loads at 0100 |
| 7000–73FF | screen: row r, column c at 7000 + 64 r + c | one byte per character, 7-bit ASCII; bit 7 = reverse video |
| 7400–77FD | rest of the video RAM | free, not displayed |
| 77FE–77FF | HBIOS's cursor position (high, low) | do not use |
| 7800–7FFF | 6845 CRTC | even address = register select, odd = data |
| 8000–EFFF | EPROM | the memory card's jumpers decide this |
| F000–FFFF | HBIOS | boot code, video and keyboard drivers, Mike Riley's BIOS and monitor |
With the reworked memory Rev B in the machine today, its RAM also answers at 7000–7FFF and its EPROM at F000–FFFF (memory-card.md). Reads there see two drivers; avoid relying on those areas until Rev E is fitted.
I/O map¶
| Instruction | Device | Effect |
|---|---|---|
INP 1 |
keyboard (CDP1852) | the waiting character; clears the ready flag |
OUT 2 |
IDE register select | bits 0–2 = register, bit 3 = control block (0Eh = device control) |
OUT 3 |
IDE | write the selected register |
INP 3 |
IDE | read the selected register |
INP 4 / OUT 4 |
1861 display on / off | only if the IO card's SV6 is fitted (it is not on Ken's card) |
| Flag / line | Meaning |
|---|---|
| EF3 | a keyboard character is waiting (B3 / BN3) |
| Q | free: on the bus, and the CPU card's Q LED |
| EF1, EF2, EF4 | not connected |
| interrupt | only the 1861 can interrupt; with it off, interrupts never come |
Programming the devices¶
The screen¶
Write characters straight into the video RAM. Upper and lower case display (the "goodfont" character ROM); set bit 7 for reverse video.
ldi high 7000h+64*2+10 ; row 2, column 10
phi rf
ldi low 7000h+64*2+10
plo rf
ldi 'A'
str rf
The cursor is the 6845's R14 (high, 6 bits) and R15 (low): write the register number to 7800, then the value to 7801. The value is the character's address relative to 7000.
HBIOS's outchar (through f_type) does all this: it handles CR, LF, backspace and scrolling (by copying), and keeps the cursor in 77FE–77FF.
The keyboard¶
wait: bn3 wait ; EF3: a character is waiting
sex r2
inp 1 ; D = M(R2) = the character
INP also writes the byte into memory at R(X), so point X at a byte you can spare (the stack top, as above).
The keyboard sends ASCII; ESC is 1Bh (HBIOS's break test looks for it).
The CF card¶
sex r3 ; immediate OUT: the byte after the instruction
out 2
db 07h ; select the status register
sex r2
inp 3 ; D = status: 80 BSY, 40 DRDY, 08 DRQ, 01 ERR
To read a sector: wait for DRDY; write the sector count (register 2) = 1, LBA 0–23 (registers 3–5), E0h + LBA 24–27 (register 6); command 20h (register 7); wait for DRQ; select register 0 and do 512 INP 3s. Before the first transfer put the drive in 8-bit mode: features (register 1) = 01h, command EFh. The BIOS does all of this (f_ideread, f_idewrt, f_iderst).
The 6845¶
The registers and HBIOS's values are in video-6845-card.md. Only R14–R17 can be read back; the others are write-only. Hardware scrolling by changing R12/R13 works within 2K only (the bus sees 2K of the 4K video RAM).
Starting the machine¶
- Reset clears the CPU card's boot flip-flop: the boot EPROM answers at every address and the bus is hidden (-VMA high).
- The 1802 starts at 0000 with P = 0 and X = 0, and fetches HBIOS's first bytes.
LDI F0h / PHI R0makes the next fetch come from F0xx: the first access with A15 high sets the flip-flop, and from then on HBIOS runs at F000–FFFF with the bus cards visible. - HBIOS loads the 6845 (
vtable), clears the screen, stores the cursor position and jumps to the monitor (f_minimon). - The monitor sets R2 = 00FF, X = 2, initialises SCRT (R4 = call, R5 = return, R6 = return address) and prompts.
The monitor¶
Mike Riley's monitor reads a line and acts on its first character. Addresses and bytes are in hex.
| Command | Effect |
|---|---|
?addr |
dump 128 bytes from addr |
!addr bb bb … |
store bytes at addr |
=src dst count |
copy memory |
@addr |
run at addr with P = 0 and X = 0 (R0 = addr) |
@FF00 |
boot ELF/OS from the CF card (f_boot) |
H |
list the commands (HBIOS v1.0.5, not burned yet) |
B |
boot the OS from the CF card, as @FF00 (v1.0.5) |
D start:end |
disassemble, 14 lines a screen; at -- more -- any key goes on, Esc stops (v1.0.5). D start: one screenful |
Q1 / Q0 |
Q output on (SEQ) / off (REQ) (v1.0.5) |
@F1C0 |
the IO panel demo: toggles to the LEDs, INPUT (EF1) to Q, until Reset (v1.0.5) |
f_boot resets the drive, reads LBA 0 into 0100 and runs it there (R0 = 0100).
The monitor looks only at the first character and reads the rest as hex. Anything it does not know gives the prompt again, with no message. H, B, D and Q1 / Q0 are in HBIOS v1.0.5 (firmware/hbios/v1.0.5/), not yet burned: the machine's 2732 holds v1.0.4.
BIOS calls¶
HBIOS keeps Mike Riley's standard jump table at FF00, so ELF/OS and its programs find the BIOS at the same addresses as on every Riley-BIOS 1802. Call with SCRT:
sep r4 ; R4 = scall
dw 0ff09h ; f_msg: type the string at RF
The registers: R2 = stack (X = 2), R3 = program counter, R4 = call, R5 = return, R6 = return address and inline arguments. Most routines take and return values in D, DF (error flag), RD and RF.
| Address | Name | Does | In / out |
|---|---|---|---|
| FF00 | f_boot | boot from the CF card | |
| FF03 | f_type | type the character in D (System-5: the screen) | D |
| FF06 | f_read | read a character (System-5: the keyboard, echoed) | → D |
| FF09 | f_msg | type a zero-terminated string | RF |
| FF0F | f_input | read a line, up to 256 bytes | RF = buffer |
| FF12 | f_strcmp | compare strings | RF, RD |
| FF15 | f_ltrim | skip leading spaces | RF |
| FF18 | f_strcpy | copy a string | RF → RD |
| FF1B | f_memcpy | copy memory | RF → RD, RC = count |
| FF30 | f_mul16 | RC:RB = RF × RD | |
| FF33 | f_div16 | RB = RF / RD, RF = remainder | uses R8, R9 |
| FF36 | f_iderst | reset the drive, 8-bit mode | |
| FF39 | f_idewrt | write a sector | RF = buffer, R7 = LBA 0–15, R8.0 = LBA 16–23, R8.1 = E0h + LBA 24–27; DF = error |
| FF3C | f_ideread | read a sector | as f_idewrt |
| FF3F | f_initcall | set up SCRT (R4, R5), then jump to R6 | |
| FF42 | f_ideboot | boot from the drive | |
| FF45 | f_hexin | hex text to a number | RF = text → RD |
| FF48 | f_hexout2 | a byte as 2 hex digits | RD → text at RF |
| FF4B | f_hexout4 | a word as 4 hex digits | RD → text at RF |
| FF4E | f_tty | type the character in D | D |
| FF51 | f_mover | copy a program image from ROM into RAM and run it | RF = image: RAM start, RAM end, run address (2 bytes each), then the program |
| FF54 | f_minimon | the monitor | |
| FF57 | f_freemem | find the last writable address | → RF |
| FF5A | f_isnum | is D a digit? | DF |
| FF5D | f_atoi | decimal text to a number | RF → RD |
| FF60 | f_uintout | unsigned number to decimal text | RD → RF |
| FF63 | f_intout | signed number to decimal text | RD → RF |
| FF66 | f_inmsg | type the string that follows the call | inline |
| FF69 | f_inputl | read a line, RC = maximum length | RF |
| FF6C | f_brktest | was a break (ESC) typed? | DF |
| FF6F | f_findtkn | look up a token | |
| FF72–FF7E | f_isalpha, f_ishex, f_isalnum, f_idnum, f_isterm | character tests | DF |
| FF81 | f_getdev | which devices are present |
The serial-port, baud-rate and drive-geometry entries (FF0C, FF1E–FF2D) are stubs on System-5. The source, with each routine's register use, is firmware/hbios/v1.0.4/orig_bios/bios.asm; Ken's video and keyboard code is firmware/hbios/v1.0.4/sec1.asm, reached from Mike's type and read through F203 and F200.
ELF/OS¶
ELF/OS 0.2.x (Mike Riley) runs from the CF card; its commands are in the operator's guide. Its kernel API, file system and utilities are documented with its source in reference/mike-riley/. Known issues found with the emulator:
- HBIOS loses the first character after a 64-column line wrap, so DIR drops every fifth name.
- EDIT with no file name hangs (kernel 0.2.6 build 135's empty-path handling); give a name.
Tools¶
| Tool | Where | Use |
|---|---|---|
| rcasm | reference/mike-riley/ |
Mike Riley's 1802 assembler; HBIOS's Makefile uses it with cpp and srec_cat |
srecord (srec_cat) |
merges and converts ROM images (Intel hex, binary) | |
| s5emu | software/s5emu/ |
emulator: boots HBIOS and ELF/OS; --hw runs the cards from their netlists; terminal and browser debuggers |
| s5busdrv.py | software/busdrv/ |
the bus driver card: peek, poke, load, dump, memory test, INP/OUT with the CPU card out |
| bringup.py | software/busdrv/ |
test plans for the memory, CF and 6845 cards |
Building HBIOS: firmware/hbios/v1.0.4/Makefile assembles sec1.asm, merges it over Mike's bios.img and writes sec1.rom, the 4K image for the CPU card's 2732.