# Cardiograph Mark I — simulator for an imaginary computer Cardiograph is an imaginary computer. It has three main components: 1. the CPU, *Card* (short for 'Completely Analogue Risc Machine') 2. an input-output processor, *IO* 3. a display, *Graph* ## Simulator ### Dependencies Cardiograph is an imaginary computer. It has three main components: 1. the CPU, *Card* (short for 'Completely Analogue Risc Machine') 2. an input-output processor, *IO* 3. a display, *Graph* ## Simulator ### Dependencies - Node.js ### Quick examples Assemble and run: ```./assembler.js -i | ./cardiograph.js``` Assemble to a file: ```./assembler.js -i -o ``` Run from a file: ```./cardiograph.js -i ``` ### Assembler: assembler.js ``` Usage: ./assembler.js [-a] -i [-o ] -a, --annotate Output code with debugging annotations -i, --in Assembly-language input -o, --out Machine-code output ``` - If an output file is not provided, the output is printed to stdout - If the `annotate` flag is not set, the machine code is returned as a string of space-separated decimal numbers ### Simulator: cardiograph.js ``` Usage: ./cardiograph.js [-i ] -i, --in Machine-code input ``` - If an input file is not provided, the input is read from stdin ## CPU ### Registers and Flags There are three registers: 1. **A**, an 8-bit accumulator 2. **IP**, an 8-bit instruction pointer (aka program counter) 3. **flags**, a 4-bit flag register The four flags are **O**verflow, **N**egative, **Z**ero, and **C**arry. (Overflow is the high bit and carry is the low bit.) In decimal: | O | N | Z | C | |---|---|---|---| | 3 | 2 | 1 | 0 | ### Instruction set #### Operations ``` Hex Mnem. Operand Effect 00 END (ignored) Halt CPU 01 STO literal # mem[lit#] = A 02 STO address mem[mem[addr]] = A 03 LDA literal # A = lit# 04 LDA address A = addr 05 ADD literal # A = A + lit# 06 ADD address A = A + mem[addr] 07 SUB literal # A = A - lit# 08 SUB address A = A - mem[addr] 09 HOP literal # If A == lit#, skip next op (IP += 4) 0A HOP address If A == mem[addr], skip next instruction (IP += 4) 0B JMP literal # IP = lit# 0C JMP address IP = mem[addr] 0D FTG literal # Toggle flag, where flag number == lit# 0E FHP literal # Skip next op if flag is set, where flag number == lit# 0F NOP (ignored) None ``` - Instructions are two bytes long: one byte for the opcode, one for the operand #### Effects on memory, flags, registers ``` op mem flags IP END +2 NOP +2 STO w +2 LDA r NZ +2 ADD ONZC +2 SUB ONZC +2 HOP +2/+4 JMP arg FTG ONZC +2 FHP ONZC +2/+4 STO r,w +2 LDA r,r NZ +2 ADD r ONZC +2 SUB r ONZC +2 HOP r +2/+4 JMP r arg FTG r ONZC +2 FHP r ONZC +2/+4 ``` ### Start-up 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 ### 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 ## Cardiograph 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 ## Cardiograph 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`   =   `←` `↓` `→`