# Cardiograph computers The Cardiographs are a pair of imaginary computers. The "Cardiograph Mark I" is an educational model of a mainframe machine. The "MicroCardiograph" is a its miniaturized descendent, a microprocessor trainer. They use the same instruction set and have very similar CPUs. The main difference is in their peripheral hardware: the Mark I is designed for batch processing programs on punched cards, while the MicroCardiograph is designed to be used interactively. The Cardiographs were built by an imaginary enterprise, the Electronic Computer Group (ECG). ## Simulator There is a [simulator](micro/readme-micro.md) for the MicroCardiograph. ## CPU ### Registers There are three 8-bit registers: 1. **A**, the accumulator (and the only general-purpose register) 2. **IP**, the instruction pointer (aka program counter) 3. **Status** #### Status register The *high byte* holds the ID number of the current **IO** device. (See the section on [IO programming](#io-programming).) The *low byte* holds four flags: **O**verflow, **N**egative, **Z**ero, and **C**arry. The flags are accessed by number: | O | N | Z | C | |---|---|---|---| | 8 | 4 | 2 | 1 | ### Instruction set - Instructions are two bytes long: one byte for the opcode, one for the operand ```GGMM IIII``` - **G**roup, **M**ode, **I**nstruction | lo ↓ / hi → | 0 (G0, M0) | 5 (G1, M1) | 6 (G1, M2) | 9 (G2, M1) | A (G2, M2) | |-------------|------------|------------|------------|------------|------------| | **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 | | | | **9** | | DIV # | DIV ind | | | | **A** | | RRL # | RRL ind | | | | **B** | | RRR # | RRR ind | | | | **C** | | ARL # | ARL ind | | | | **D** | | ARR # | ARR ind | | | | **E** | | JLT # | JLT ind | | | | **F** | | JGT # | JGT ind | | | - RRL/RRR: Ring Rotate - JLT: Jump Less Than - DEV: IO device select - FED: "feed" - line feed / end of card TODO: assess JMPs vs. HOPs ### Connections (pinout) TBC | number | name | in/out? | description | |---------|-----------|---------|---------------| | 1 | RST | in | *reset* | | 2 | VCC | in | *power* | | 3 | GND | in | *ground* | | 4 | CLK | in | *clock* | | 5 - 13 | A0 - A7 | out | *address bus* | | 15 - 23 | D0 - D7 | out | *data bus* | | 24 | ABE | out | *address bus enable*:
low when the CPU is using the address bus | | 25 | DBE | out | *data bus enable*:
low when the CPU is using the data bus | | 26 | WAIT | in | *wait* — when pulled low,
the current operation is completed
and then execution pauses | ### 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 ECG 101 Central Processing Unit - an ECG 102 Core Memory Unit - an ECG 103 Card Reader - an ECG 104 Card Punch - an ECG 105 Line Printer - an ECG 106 Matrix Display Additionally, an *ECG 100 Keypunch* is used for the initial preparation of cards or tape. ### Console 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 - 16 Sense switches (TBC) - 8 Accumulator lights - 8 Address lights - 8 Data lights - 8 Instruction Pointer lights (TBC) - 4 Status Register lights ## IO programming Only one input or output device can be accessed at a time. ### Reading data 1. Use `DEV xx` to select input device _xx_ 2. Use `INP yy` to read one card into memory, beginning at address _yy_ ### Writing data 1. Use `DEV xx` to select output device _xx_ 2. Use `OUT yy` to write one byte 3. Use `FED xx` to signal the end of a card, or the end of a line on the printer or display ### Punched card format - Cards are punched in EBCDIC - EBCDIC 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 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 1. Input - Card Reader 2. Output - Card Punch 3. Output - Line Printer 4. Output - Matrix Display ## 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 `$` (or `0x`) - Prefix binary numbers with `0b` - Whitespace is ignored