10 KiB
Cardiograph computers
The Cardiographs are a pair of imaginary computers, designed as educational toys.
Inspired by the CARDIAC paper computer, they are intended to be simple enough to build as hand-operated paper models.
Their design is guided by two additional criteria:
- They should be capable of producing interesting graphical output
- They should accurately model the functioning of a real computer (by operating on binary data, for example)
The two computers
The two Cardiograph computers are:
- the Cardiograph Mark I (CG) is a mainframe machine
- the Micro Cardiograph (µCG) is a microprocessor trainer (a miniaturized descendent of the mainframe)
They use the same instruction set and have very similar CPUs. (TODO: is that true?)
The main difference is in their peripheral hardware: the Mark I is designed for batch processing and supports punched-card input, while the MicroCardiograph is designed to be used interactively.
Simulator
Micro ElectroCardiograph (µECG) is a simulator for the Micro Cardiograph.
CPU
Registers
There are four 8-bit registers:
- A, the accumulator (and the only general-purpose register)
- IP, the instruction pointer (aka program counter)
- IOD, the ID of the current I/O device
- Status
Status register
The high byte holds the state of the four Sense Switches. (TODO: is this easy enough to do in hardware?)
The low byte holds four flags:
Overflow, Negative, Zero, and Carry.
These are all addressed by number:*
| S1 | S2 | S3 | S4 | O | N | Z | C | |
|---|---|---|---|---|---|---|---|---|
| 80 | 40 | 20 | 10 | 08 | 04 | 02 | 01 |
- (Because the core instruction set doesn't include bitwise operations)
Instruction set
- Instructions are two bytes long: one byte for the opcode, one for the operand
TODO: revise this based on note dated 2023-09-24
GGMM IIII - Group, Mode, Instruction
| lo ↓ / hi → | 0 (G0, M0) | 5 (G1, M1) | 6 (G1, M2) | 9 (G2, M1) | A (G2, M2) | F (G3, M3) |
|---|---|---|---|---|---|---|
| 0 | END | LDA # | LDA ind | DEV # | DEV ind | |
| 1 | NOP | STO # | STO ind | INP # | INP ind | |
| 2 | ADD # | ADD ind | OUT # | OUT ind | ||
| 3 | SUB # | SUB ind | FED | FED | ||
| 4 | JMP # | JMP ind | ||||
| 5 | JEQ # | JEQ ind | ||||
| 6 | JFL # | JFL ind | ||||
| 7 | FTG # | FTG ind | ||||
| 8 | MUL # | MUL ind | RSL A | |||
| 9 | DIV # | DIV ind | RSR A | |||
| A | JLT # | JLT # | ASL A | |||
| B | JGT # | JGT # | ASR A | |||
| C | NOT # | NOT # | ||||
| D | AND # | AND # | ||||
| E | OR # | OR # | ||||
| F | XOR # | XOR # |
TODO: assess JMPs vs. HOPs
- RSL/RSR: Ring Shift Left/Right
- JLT/JGT: Jump Less/Greater Than
- DEV: select IO device
- FED: "feed" - line feed / end of card
TODO: format/document better:
- core computational operations: low nibbles of 0x, 5x, 6x
- arithmetic extension (optional): MUL, DIV
- IO extension (optional): 9x, Ax
- bitwise arithmetic extension (optional): NOT, AND, OR, XOR and RSL, RSR, ASL, ASR
- control flow extension (optional): JLT, JGT
- The mainframe system implements at least 1, 2, and 3
- The microprocessor trainer implements 1
- (see note dated 2023-09-24)
Connections (pinout)
TBC
| name | in/out? | description |
|---|---|---|
| RST | in | reset |
| VCC | in | power |
| GND | in | ground |
| CLK | in | clock |
| A0 - A7 | out | address bus |
| D0 - D7 | out | data bus |
| ABE | out | address bus enable: low when the CPU is using the address bus |
| DBE | out | data bus enable: low when the CPU is using the data bus |
| WAIT | in | wait — when pulled low, the current operation is completed and then execution pauses |
| /RD | out | TODO |
| /WR | out | |
| M/IO | out |
Start-up
TODO: see if this makes sense for the mainframe
When starting up, the CPU executes a JMP $FF.
Put differently: it starts executing instructions at the address contained in $FF.
TODO: currently the simulator doesn't actually do this
Cardiograph Mark I (mainframe)
The components of a Mark I are:
- an CG 101 Central Processing Unit
- an CG 102 Core Memory Unit
- an CG 103 Print-Key-Punch
- an CG 104 Matrix Display
Console
TBC TBC TBC
The console is equipped with:
-
Power switch
-
Load button
-
Run button
-
Run Single Step button
-
Halt button
-
Memory Read button
-
Memory Read Next button
-
Memory Write button
-
Memory Write Next button
-
4 Sense Switches
-
8 Accumulator lights
-
8 Address lights
-
8 Data lights
-
8 Instruction Pointer lights (review IP size?)
-
8 Status Register lights
IO programming
Only one input or output device can be accessed at a time.
Reading data
- Use
DEV xxto select input device xx - Use
INP yyto read one byte into memory at address yy
TODO: find a way to allow the input device to refuse to provide input
Writing data
- Use
DEV xxto select output device xx - Use
OUT yyto write one byte from memory at address yy - Use
FED xxto...
- card punch: load a new card
- printer: begin a new line (CR, LF)
- display: begin a new line
Punched card format
FIXME:
Cards are punched in EBCDICEBCDIC data is translated into binary by the card reader/punch- Only columns 1-64 are used (for a maximum of 64 bytes of data per card)
Printer format
- The printer format is the same as the card format
- One line of printing is equivalent to one card
- The printer can print up to 64 characters per line
Matrix display format
- The display is a 5x5 grid of lights
- Each light has 16 possible brightness levels (0 = off, 15 = maximum)
- The display is written one line at a time
- After the display is selected with
DEV, writing begins on the top line - Writing wraps around and begins at the top again, if more than 5 lines are written
Device numbers
- card reader / typewriter
- card punch / line printer
- display
Print-Key-Punch configurations
A dial allows you to select which input device to connect to the CPU:
- none
- card reader
- keyboard
A similar dial selects the output device to connect:
- none
- card punch
- printer
Thus, this all-in-one device allows the following configurations:
| printer | card punch | none | |
|---|---|---|---|
| keyboard | teletypewriter | auto punch | keypunch (offline) |
| card reader | (keys + print) | card duplicator | (card reader) |
| none | line printer | (auto punch) | (scrap metal) |
MicroCardiograph (microprocessor trainer)
The MicroCardiograph uses memory-mapped IO.
Memory map
| Address | Used for... |
|---|---|
| 00 to 19 | display (5x5) |
| 1A | pointer to display memory |
| 1B | keypad: value of latest key pressed |
| 1C | reserved for future use (bank switching flag) |
| 1D | initial IP |
| 1D to FE | free |
| FF | * ROM (unwriteable) pointer to initial IP |
* Not implemented yet
Peripherals
Keypad
The value of the latest keypress on a hex keypad is stored at $1B.
The keypad uses the same layout as the COSMAC VIP (and CHIP-8). The CPU simulator maps those keys onto a Qwerty set:
1 2 3 C = 1 2 3 4
4 5 6 D = Q W E R
7 8 9 E = A S D F
A 0 B F = Z X C V
The arrow keys are also mapped onto the hex keypad:
5 = ↑
7 8 9 = ← ↓ →
Assembly language
ADD $01 ; comments follow a `;`
ADD $FF ; this is direct addressing
ADD ($CC) ; this is indirect addressing
END ; END and NOP don't require operands
; (the assembler will fill in a default value of 0)
@subroutine ; create a label
ADD $01 ; (it must be on the line before the code it names)
ADD $02
JMP @subroutine ; use a label as operand
; the label will be replaced with
; the address of the label
#foo $FF ; define a constant
; (must be defined before it is referenced)
ADD #foo ; use a constant as an operand
LDA * ; `*` is a special label referencing the memory address
; where the current line will be stored after assembly
- Prefix hexadecimal numbers with
$(or0x) - Prefix binary numbers with
0b - Whitespace is ignored