# Cardiograph Mark I — simulator for a paper computer ## Dependencies - Node.js - readline-sync ## Run ### Assemble Hex output: ```./run-assembler run source_code.asm``` Binary output: ```./run-assembler runbin source_code.asm``` Verbose debugging output (hex): ```./run-assembler debug source_code.asm``` ### Assemble and run With animated display of screen memory: ```./run-cpu run source_code.asm``` With verbose debugging output: ```./run-cpu debug source_code.asm``` With single stepping + pretty-printed display: ```./run-cpu step source_code.asm``` With single stepping + verbose debugging output: ```./run-cpu stepdebug source_code.asm``` ## Instruction set 00 END 01 STO lit# ; store ... mem[lit#] <- A 02 STO addr ; store ... mem[mem[addr]] <- A 03 LDA lit# ; load ... A <- lit# 04 LDA addr ; load ... A <- mem[addr] 05 ADD lit# ; add ... A <- A + lit# ... and un/set carry flag 06 ADD addr ; add ... A <- A + mem[addr] ... and un/set carry flag 07 SUB lit# ; sub ... A <- A - lit# ... and un/set carry flag 08 SUB addr ; sub ... A <- A - mem[addr] ... and un/set carry flag 09 HOP lit# ; hop ... skip next instruction if A == lit# ... when true: IP <- PC + 4 0A HOP addr ; hop ... skip next instruction if A == addr ... when true: IP <- PC + 4 0B JMP lit# ; jump ... IP <- lit# 0C JMP addr ; jump ... IP <- addr 0D FTG lit# ; toggle flag by number (see details below) 0E FHP lit# ; flag hop ... skip next instruction if flag is set ... when true: IP <- PC + 4 0F NOP ———— ; no operation - Instructions are two bytes long: one byte for the opcode, one for the operand ## Registers and Flags - `A` - accumulator - `IP` - instruction pointer (aka program counter) - `FLAGS` - flags: **N**egative, **Z**ero, **O**verflow, **C**arry - in machine language, each flag is given a number: - N = 3 Z = 2 O = 1 C = 0 - (bitwise, `0000 = NZOC`) ## Memory map / Peripherals - `00-0F` - display (4x4) - `10-19` - reserved for future use - `20 ` - keypad - value of the most recent keypress - `21 ` - pointer to display memory - `22 ` - pointer to keypad memory - `23-2F` - reserved for future use / variable storage - `30 ` - initial value for IP - `30-FF` - free ### Keypad The value of the latest keypress on a hex keypad is stored at `$20`. (The keypad can also be relocated by changing the value of the pointer-to-keypad at `$22`.) The keypad uses the same layout as the COSMAC VIP (and CHIP-8): ``` 1 2 3 C 4 5 6 D 7 8 9 E A 0 B F ``` The CPU simulator maps the following Qwerty keys onto those values: ``` 1 2 3 4 Q W E R A S D F Z X C V ``` ## 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 *ADDR ; `*ADDR` is a magic value referencing the memory address ; that the current line will store at after assembly - Hexadecimal numbers are preceded by a `$` - Whitespace is ignored