cardiograph-computer/readme.md

306 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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:
1. They should be capable of producing interesting graphical output
2. 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:
1. the _Cardiograph Mark I_ (CG) is a mainframe machine
2. 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)](micro/readme-micro.md)_ is a simulator for the Micro Cardiograph.
## CPU
### Registers
There are four 8-bit registers:
1. **A**, the accumulator (and the only general-purpose register)
2. **IP**, the instruction pointer (aka program counter)
3. **IOD**, the ID of the current I/O device
3. **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:
**O**verflow, **N**egative, **Z**ero, and **C**arry.
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
<mark>TODO: revise this based on note dated 2023-09-24</mark>
```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) | 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:
1. core computational operations: low nibbles of 0x, 5x, 6x
2. arithmetic extension (optional): MUL, DIV
3. IO extension (optional): 9x, Ax
4. bitwise arithmetic extension (optional): NOT, AND, OR, XOR and RSL, RSR, ASL, ASR
5. 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)
<mark>TBC</mark>
| 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*: <br> low when the CPU is using the address bus |
| DBE | out | *data bus enable*: <br> low when the CPU is using the data bus |
| WAIT | in | *wait* when pulled low, <br> the current operation is completed <br> and then execution pauses |
| /RD | out | TODO |
| /WR | out | |
| M/IO | out | |
### Start-up
<mark>TODO: see if this makes sense for the mainframe </mark>
When starting up, the CPU executes a `JMP $FF`.
Put differently: it starts executing instructions at the address contained in `$FF`.
<mark>TODO: currently the simulator doesn't actually do this</mark>
## 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
<mark>TBC TBC TBC</mark>
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 (<mark>review IP size?</mark>)
- 8 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 byte into memory at address _yy_
<mark>TODO: find a way to allow the input device to refuse to provide input</mark>
### Writing data
1. Use `DEV xx` to select output device _xx_
2. Use `OUT yy` to write one byte from memory at address _yy_
3. Use `FED xx` to...
- 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 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 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
1. card reader / typewriter
2. card punch / line printer
3. display
### Print-Key-Punch configurations
A dial allows you to select which input device to connect to the CPU:
1. none
2. card reader
3. keyboard
A similar dial selects the output device to connect:
1. none
2. card punch
3. 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 `$` (or `0x`)
- Prefix binary numbers with `0b`
- Whitespace is ignored