Compare commits

...

42 Commits
main ... notes

Author SHA1 Message Date
n loewen 549d337354 2023-10-23 - Create note 2023-10-29 18:04:01 -07:00
n loewen 3ab072b926 Add list of links from phone browser tabs 2023-10-23 18:53:55 -07:00
n loewen 1aa68490e6 Add notes jotted down elsewhere over the last month 2023-10-23 18:21:42 -07:00
n loewen 75fbd20e52 2023-09-26 - Update 2023-09-27 18:24:53 -07:00
n loewen 562ba47cb5 2023-09-26 - Create note 2023-09-26 17:02:50 -07:00
n loewen a09fc19567 2023-09-25 - Remove redundant line 2023-09-26 17:02:34 -07:00
n loewen 2e45bb5cc8 2023-09-25 - Update with notes from later in the day 2023-09-26 16:48:22 -07:00
n loewen b036f520aa (2023-09-25) Add notes (todos, networking, 6502 vectors...) 2023-09-25 14:40:26 -07:00
n loewen 4207393d31 2023-09-25 - Create note (with todo list) 2023-09-25 07:15:34 -07:00
n loewen d17572b35f (2023-09-24) Update note 2023-09-24 23:28:40 -07:00
n loewen 8c196dcc93 (2023-09-24) Add more notes to the notes 2023-09-24 21:27:53 -07:00
n loewen 3e3337e42a (2023-09-24) Fix strikethrough formatting 2023-09-24 20:02:42 -07:00
n loewen 9ac9a9ecd6 (2023-09-24) Add notes from this evening 2023-09-24 20:00:28 -07:00
n loewen 9db7b5f455 (2023-09-24) Create note 2023-09-24 14:35:51 -07:00
n loewen 25b34bedf2 (issues) Update todo, issues lists + give up on keeping a list of 'closed' todos 2023-09-23 21:08:14 -07:00
n loewen 796735daec Add notes from the last two weeks 2023-09-23 16:32:24 -07:00
n loewen 1ad4020574 (2023-09-11) Create note, with thoughts on ISA and CPU pinout 2023-09-11 11:14:46 -07:00
n loewen ce60b9cb23 Update link to reflect changed filename 2023-09-11 10:42:02 -07:00
n loewen 8876bd60d2 Change heading for ISA section to make it eash to search for 2023-09-11 10:41:44 -07:00
n loewen 73e818b090 Update links to reflect changed filenames 2023-09-11 10:41:31 -07:00
n loewen 1bb22ce993 Remove "--dev-notes" suffix from file names 2023-09-11 10:32:04 -07:00
n loewen 762e84345d Add headings + Split notes that contained material from more than one day 2023-09-11 10:31:13 -07:00
n loewen 4b35057f78 Add new (very rough) notes 2023-09-10 16:27:30 -07:00
n loewen 6d112b6e79 2023-09-05 - Create note. Bi-quinary, plus quick notes on ISA and naming. 2023-09-05 11:07:38 -07:00
n loewen 05b4f9e72d 2023-09-04 - Update todos 2023-09-05 10:42:59 -07:00
n loewen 348b78b9b6 2023-09-04 - Create note with summary of recent work + thinking-out-loud about what to do next; research notes on cpu decode-step; design notes on keypad, DMA/IO, ISA 2023-09-04 17:35:53 -07:00
n loewen 2582899922 bibliography - Add new list of references that need reviewing 2023-09-04 17:34:05 -07:00
n loewen 506de4d293 2023-09-03 - Fix typo in link 2023-09-04 17:31:42 -07:00
n loewen 9baf3ab750 2023-09-03 - Create (extensive) note - sketch for a more comprehensive (lower-level) cpu design, in javascript; todos; reference links 2023-09-03 23:14:31 -07:00
n loewen 243f000ace 2023-09-01 - Create note (with idea copied from apple notes) 2023-09-03 23:12:45 -07:00
n loewen 1d3f35a363 2023-08-31 - Add "features to add" section (copied from apple notes) 2023-09-03 23:12:27 -07:00
n loewen 13a2562046 Add notes for 2023-08-30 and 31 2023-08-31 21:08:14 -04:00
n loewen 19eb9a3925 2023-08-29 - Update todos 2023-08-29 22:28:23 -04:00
n loewen 05f57ed93c 2023-08-29 - Add info on how overflow flag should behave 2023-08-29 21:22:41 -04:00
n loewen 9cbf34be6e 2023-08-29 - Update todo list 2023-08-29 13:13:25 -04:00
n loewen 1c60fa5ab8 2023-08-29 - Update todos 2023-08-29 10:04:46 -04:00
n loewen b27e1e7496 2023-08-29 - Update todos 2023-08-29 09:27:12 -04:00
n loewen 0eee5a2624 Move issues and notes back into this branch 2023-08-29 08:55:03 -04:00
n loewen b161fb1415 Remove empty .gitmodules 2023-08-29 08:45:05 -04:00
n loewen 33539224a4 Move all files to root dir 2023-08-29 08:44:49 -04:00
n loewen 3982ce3254 Remove files that aren't notes 2023-08-29 08:40:36 -04:00
n loewen 3cc41b8b5a Remove 'test-programs' dir 2023-08-29 08:34:01 -04:00
73 changed files with 2818 additions and 2965 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "src/argparser"]
path = src/argparser
url = https://git.nloewen.com/n/argv-parser.git

View File

@ -1,5 +1,7 @@
# Dev notes — 2023-08-12
## Call stack
Brainstorming/sketching around subroutines with a return stack...
; need an instruction for IP → A i guess?

View File

@ -8,9 +8,19 @@
2. Highlight the most recent keypress on there
- [ ] Notes re: ROM and/or tape loader
## Program ideas
- Programming ideas:
- Keypad display
1. Light pixel corresponding to most recent keypress
2. Display character corresponging to most recent keypress
- Draw dot at (x, y)
- Move dot around display using keypad
- Move dot around display using keypad
## Docs/graphics ideas
From apple note "2023-07-17 - cardiograph - worksheet for hand-assembling code… + other docs"
- [ ] docs/graphics: machine code quick ref (ops + short explanations + mnems)
- [ ] docs/graphics: assembly quick ref (as above, plus assembler-specific syntax like constants)
- [ ] docs/graphics: worksheet for hand-assembling

18
2023-08-18.md Normal file
View File

@ -0,0 +1,18 @@
# 2023-08-18 — Dev notes
From "2023-08-18 cardiograph loose thoughts" apple note
- use binary encoded punch cards for cardiog progs in machine code
- try making a microbit based emulator
- (microbit + hex keypad)
- (machine code monitor like VIP…)
- (+ tape input??)
- a4 template with full size 80 col card
- snake
- [/] add simulator todo: pass asm line thru to cpu to print when debugging
- asm: create a second array that stores every line with code (nor blank or comment only lines) + its line number
- cpu: accept an optional debugging array, print line # and statement
- readme:
- [x] readme: rename (or split up?) mem map / peripherals section
- [x] ? readme: put 2 keypad charts side by side (they would fit on my phone)
- [/] see paper notes on mem map

11
2023-08-19.md Normal file
View File

@ -0,0 +1,11 @@
# 2023-08-19
## ISA quick note
[/] reconsider ISA order in light of supercat comment here
- [Why didn't the 6503 have increment/decrement opcodes for A?](https://retrocomputing.stackexchange.com/questions/13023/why-didnt-the-6502-have-increment-decrement-opcodes-for-a)
## Assembly pseudo-ops
- [/] look at use of `*` or `.` in assembly
- [What does "jmp *" mean in 6502 assembly?](https://retrocomputing.stackexchange.com/questions/7998/what-does-jmp-mean-in-6502-assembly)

View File

@ -39,39 +39,4 @@ Put differently: it starts executing instructions at the address contained in `$
- "Reset (RST): When the 6502's RST input gets pulled low and then brought back high, the 6502 starts its reset process, and gets the address to start executing program instructions from $FFFC-FFFD. Notice it does not start executing at address $FFFC, but reads it to get the beginning address of the routine where it should start executing. That routine will normally have to be in ROM."
- [What address does the x86 begin executing at?](https://stackoverflow.com/questions/4004493/what-address-does-the-x86-begin-executing-at)
- "The `cs` (code selector) register is set to `0xffff` and `ip` (instruction pointer) is set to `0x0000`."
- [Why is the first BIOS instruction located at 0xFFFFFFF0 ("top" of RAM)?](https://superuser.com/questions/988473/why-is-the-first-bios-instruction-located-at-0xfffffff0-top-of-ram) (x86)
## Imported notes from earlier
### 2023-08-18 cardiograph loose thoughts
- use binary encoded punch cards for cardiog progs in machine code
- try making a microbit based emulator
- (microbit + hex keypad)
- (machine code monitor like VIP…)
- (+ tape input??)
- a4 template with full size 80 col card
- snake
- [/] add simulator todo: pass asm line thru to cpu to print when debugging
- asm: create a second array that stores every line with code (nor blank or comment only lines) + its line number
- cpu: accept an optional debugging array, print line # and statement
- readme:
- [x] readme: rename (or split up?) mem map / peripherals section
- [x] ? readme: put 2 keypad charts side by side (they would fit on my phone)
- [/] see paper notes on mem map
## 2023-08-19
[/] reconsider ISA order in light of supercat comment here
- [Why didn't the 6503 have increment/decrement opcodes for A?](https://retrocomputing.stackexchange.com/questions/13023/why-didnt-the-6502-have-increment-decrement-opcodes-for-a)
- [/] look at use of `*` or `.` in assembly
- [What does "jmp *" mean in 6502 assembly?](https://retrocomputing.stackexchange.com/questions/7998/what-does-jmp-mean-in-6502-assembly)
## 2023-07-17 - cardiograph - worksheet for hand-assembling code… + other docs
- [ ] docs/graphics: machine code quick ref (ops + short explanations + mnems)
- [ ] docs/graphics: assembly quick ref (as above, plus assembler-specific syntax like constants)
- [ ] docs/graphics: worksheet for hand-assembling
- [Why is the first BIOS instruction located at 0xFFFFFFF0 ("top" of RAM)?](https://superuser.com/questions/988473/why-is-the-first-bios-instruction-located-at-0xfffffff0-top-of-ram) (x86)

View File

@ -10,7 +10,7 @@ Or maybe go with the simpler "just swap NOP and FHP" plan...
**→ Ok i'm going to bail on this for now; the current set is easier to work with and nicer to teach. It was good to learn about and think about this, and maybe it will come back later, but for now it feels like adding this complexity would be contrary to my goals of maximum simplicity and rapid learnability.**
## Instruction set layout notes
## ISA - Instruction set layout notes
### Reference: 6502

88
2023-08-29.md Normal file
View File

@ -0,0 +1,88 @@
# Dev notes — 2023-08-29
## Overflow flag
This looks like a better (simpler to understand) resource: http://c-jump.com/CIS77/CPU/Overflow/lecture.html#O01_0090_signed_overflow
> When two signed 2's complement numbers are added, overflow is detected if:
> 1. both operands are positive and the sum is negative, or
> 2. both operands are negative and the sum is positive.
> Notice that overflow occurs only when
> `CARRYin ≠ CARRYout`
> or simply
> `V = Cin XOR Cout`
> where `V` is the overflow signal.
And http://teaching.idallen.com/dat2343/11w/notes/040_overflow.txt:
> The rules for turning on the overflow flag in binary/integer math are two:
>
> 1. If the sum of two numbers with the sign bits off yields a result number
with the sign bit on, the "overflow" flag is turned on.
>
> 0100 + 0100 = 1000 (overflow flag is turned on)
>
> 2. If the sum of two numbers with the sign bits on yields a result number
> with the sign bit off, the "overflow" flag is turned on.
>
> 1000 + 1000 = 0000 (overflow flag is turned on)
>
> Otherwise, the overflow flag is turned off.
> * 0100 + 0001 = 0101 (overflow flag is turned off)
> * 0110 + 1001 = 1111 (overflow flag is turned off)
> * 1000 + 0001 = 1001 (overflow flag is turned off)
> * 1100 + 1100 = 1000 (overflow flag is turned off)
>
> Note that you only need to look at the sign bits (leftmost) of the three
> numbers to decide if the overflow flag is turned on or off.
>
> If you are doing two's complement (signed) arithmetic, overflow flag on
> means the answer is wrong - you added two positive numbers and got a
> negative, or you added two negative numbers and got a positive.
>
> If you are doing unsigned arithmetic, the overflow flag means nothing
> and should be ignored.
...
> Overflow in two's complement may occur, not when a bit is carried out
of the left column, but when one is carried into it and no matching
carry out occurs. That is, overflow happens when there is a carry into
the sign bit but no carry out of the sign bit.
>
> The OVERFLOW flag is the XOR of the carry coming into the sign bit (if
any) with the carry going out of the sign bit (if any). Overflow happens
if the carry in does not equal the carry out.
And https://stackoverflow.com/a/8966863:
> The signed overflow flag value, however, must be the same for both A-B and A+(-B) because it depends on whether or not the result has the correct sign bit and in both cases the sign bit will be the same.
## Short-term goals:
- [ ] **Update main TODO list**
- [x] Move notes, issues to their own branches
- [x] Make worktrees for those branches
- [ ] split into card, io, graph, all bound together in cardiograph.js
→ have split it a bit... display and keypad are both in `io.js`
- [x] make CPU errors throw errors
- [ ] new CLI interface
- [x] replace `run-...` with `./assembler.js` and `./cardiograph.js`
→ have done a basic implementation, which is a regression of the feature set
- [ ] parse args in a safer way
- [ ] implement missing features
- [ ] single-stepping
- [ ] various levels of debugging, pretty-printing
***
- [x] **fix overflow flag**
- [ ] **add 'dry run' mode to assembler - print debug info but don't write to file**
- [ ] implement 'jmp ($FF)' on startup
- [ ] implement ROM

38
2023-08-30.md Normal file
View File

@ -0,0 +1,38 @@
# Dev notes — 2023-08-30
## IO brainstorming
- more IO? brainstorming…
- input byte - could be used for loading from tape, …
- maybe something like: you set $f0 to 1, then the io controller checks for that 1, and if it sees it, it loads a byte into $f1 and sets $f0 back to 0
- output byte - could be used for printing to a printer; controlling a robot turtle…
## Interrupts?
- interrupts?
- for keypad
- how do they work on KIM 1 (6502) and VIP (1802, Chip 8)?
- probably/maybe requires new instructions?
- sth like: current IP is stashed at $fd; JMP ($fe) to keypad interrupt routine; jmp ($fd) to return when done ?
### CHIP-8
- chip8 doesnt have interrupts; just “skip if key (not) pressed”
- CHIP-8 virtual machine specification
### 1802
https://en.wikipedia.org/wiki/RCA_1802#DMA_and_load_mode:
> The CDP1802 has a simple built-in DMA controller, having two DMA request lines for DMA input and output. The CPU only accesses memory during certain cycles of the multi-step machine cycle, which required between 8 and 16 clock cycles. External hardware could read or write data during these periods without interrupting the processor, a general concept known as cycle stealing.
>
> R0 is used as the DMA address pointer. The starting address of the DMA data would be put in R0 and then pulling the appropriate read or write pin on the CPU low. The CPU responded to the DMA request by incrementing the value in R0, so that the next request automatically stored in the next location in memory. Thus by simply repeatedly triggering the DMA pins, the system would walk through the entire memory.
>
> The DMA controller also provides a special "load mode", which allows loading of memory while the CLEAR and WAIT inputs of the processor are active. This allows a program to be loaded without the need for a ROM-based bootstrap loader. This was used by the COSMAC Elf microcomputer and its successors to load a program from toggle switches or a hexadecimal keypad with no required software and minimal hardware. The user could simply set the switches to the next value, toggle the read, and then move on. There was no need to change the addresses, that was done automatically by the DMA stepping.
### COSMAC VIP
VIP manual
- looks like no keyboard interrupts
- see pp 22-25

171
2023-08-31.md Normal file
View File

@ -0,0 +1,171 @@
# Dev notes — 2023-08-31
- [ ] parse args in a safer way
- [ ] implement missing features
- [ ] single-stepping
- [ ] various levels of debugging, pretty-printing
- [ ] add 'dry run' mode to assembler - print debug info but don't write to file
- [ ] implement 'jmp ($FF)' on startup
- [ ] implement ROM
## Microprocessor trainer style keypad
### New keys
I'm thinking the system needs:
1. on/off switch
2. 'shift' key
3. hex keypad
The 'shift' key allows each of the keypad keys to have two functions:
`1 / + ` `2 ` `3 ` `C / ST`
`4 ` `5 ` `6 ` `D `
`7 / DA` `8 ` `9 ` `E / G1`
`A / AD` `0 ` `B ` `F / GO`
(These are based on the KIM-1 buttons)
- Updating and viewing memory:
- `AD` `n` `n` — go to address *nn*
- `DA` `n` `n` store data at address *nn*
- `+` go to next address
- Running programs:
- `GO` run, starting at current address
- `G1` execute next instruction (single-step)
- `ST` — stop running
`D` could be a reset key, but I'm not sure it's necessary?
#### Usage: inspecting memory
1. Press `AD` to switch to address-entry mode
2. Enter the address you want to inspect with `n` `n`
3. Press `+` to move to the next address
#### Usage: entering code
1. Press `AD` to switch to address-entry mode
2. Enter the starting address with `n` `n`
3. Press `DA` to switch to data-entry mode
4. Enter the data with `n` `n`
5. The system automatically advances to the next address; just keep entering data
#### Usage: running code
Running continuously:
- Press `GO` to begin continuous execution
- Press `ST` to stop execution
Single-stepping:
- (Press `ST` to stop execution)
- Press `G1` to execute one instruction
### To consider
- If I understand/remember correctly... When the `ST` button is pressed on the KIM-1, the values in the registers are copied into ram so that they can be inspected
- That seems like a good idea
### Handling
I think this is all handled by the I/O controller (or a new DMA controller?) — not the CPU, at any rate
> The DMA controller also provides a special "load mode", which allows loading of memory while the CLEAR and WAIT inputs of the processor are active. This allows a program to be loaded without the need for a ROM-based bootstrap loader. This was used by the COSMAC Elf microcomputer and its successors to load a program from toggle switches or a hexadecimal keypad with no required software and minimal hardware. The user could simply set the switches to the next value, toggle the read, and then move on. There was no need to change the addresses, that was done automatically by the DMA stepping.
 https://en.wikipedia.org/wiki/RCA_1802
### Displaying data, microprocessor trainer style
The Cardiograph's signature 5x5 display makes this a challenge. I have two ideas:
1 — Display data in binary, with one nibble per line. You can fit two bytes on screen with a space in between.
○ ● ● ● ● F
○ ● ○ ● ○ A
○ ○ ○ ○ ○
○ ○ ● ○ ● 5
○ ● ○ ● ○ A
2  Display data using a sort of abacus-esque encoding...
8s, 4s ... 3 2 1
○ ○ ○ ○ ○ 0
○ ○ ○ ○ ● 1
○ ○ ○ ● ○ 2
○ ○ ● ○ ○ 3
○ ● ○ ○ ○ 4
○ ● ○ ○ ● 5
○ ● ○ ● ○ 6
○ ● ● ○ ○ 7
● ○ ○ ○ ○ 8
● ○ ○ ○ ● 9
● ○ ○ ● ○ A
● ○ ● ○ ○ B
● ● ○ ○ ○ C
● ● ○ ○ ● D
● ● ○ ● ○ E
● ● ● ○ ○ F
or
○ ○ ○ ○ ○ 0
○ ○ ○ ○ ● 1
○ ○ ○ ● ● 2
○ ○ ● ● ● 3
○ ● ● ● ● 4
○ ● ○ ○ ● 5 = 4 + 1
○ ● ○ ● ● 6 = 4 + 2
○ ● ● ● ● 7 = 4 + 3
● ○ ○ ○ ○ 8
● ○ ○ ○ ● 9 = 8 + 1
● ○ ○ ● ● A = 8 + 2
● ○ ● ● ● B = 8 + 3
● ● ○ ○ ○ C = 8 + 4
● ● ○ ○ ● D = 8 + 4 + 1
● ● ○ ● ● E = 8 + 4 + 2
● ● ● ● ● F = 8 + 4 + 3
the first is maybe clearer as an encoding; more elegant
but mayber the second is easier to quickly read off of an LED display?
## Interrupts
From apple note "cardiograph 2023-09-31"
- [ ] interrupts…
- [ ] for extended system? (“cardiograph+”?)
- [ ] how does a big iron machine like a pdp, burroughs, system/360 load program?
- [ ] what are the buttons for memory access on a microprocessor trainer like a kim-1, cosmac?
## Startup
From apple note "cardiograph 2023-09-31"
“Typically, a microprocessor will, after a reset or power-on condition, perform a start-up process that usually takes the form of "begin execution of the code that is found starting at a specific address" or "look for a multibyte code at a specific address and jump to the indicated location to begin execution". A system built using that microprocessor will have the permanent ROM occupying these special locations so that the system always begins operating without operator assistance. For example, Intel x86 processors always start by running the instructions beginning at F000:FFF0,[46][47] while for the MOS 6502 processor, initialization begins by reading a two-byte vector address at $FFFD (MS byte) and $FFFC (LS byte) and jumping to that location to run the bootstrap code.[48]”
→ so i could just have a ROM
→ or maybe two possible configurations? because sth more Cosmac-like or Big Iron-like would be fun too
## Extended system
From apple notes -- "features to add / extended system"
- convenience instructions
- mul
- div
- ? rol ror
- ? return stack
- interrupt
- bank switching
- peripherals
- keypad with DMA for entering programs
- ?? printer

3
2023-09-01.md Normal file
View File

@ -0,0 +1,3 @@
# Dev notes — 2023-09-01
make a paper replica of the all-white VIP keypad

View File

@ -0,0 +1,73 @@
# references to process
2023-09-03
from phone tabs:
1. [John Graham-Cumming's blog: How I coded in 1985](https://blog.jgc.org/2013/04/how-i-coded-in-1985.html?m=1)
1. [Let's make a Teeny Tiny compiler, part 1 - Austin Z. Henley](https://austinhenley.com/blog/teenytinycompiler1.html)
1. [Early Emulator Memories (Audio Only) - YouTube](https://m.youtube.com/watch?v=sKnlNHHKTEE)
1. [I wrote a GameBoy emulator for my hobby OS | Hacker News](https://news.ycombinator.com/item?id=36004553)
1. [Old Vintage Computing Research: The KIM-1 that sounds like Stephen Hawking (or: "jitbanging" DECtalk)](http://oldvcr.blogspot.com/2023/05/the-kim-1-that-sounds-like-stephen.html?m=1)
1. [How Do Semiconductors Work? Introduction to SiliWiz | Hacker News](https://news.ycombinator.com/item?id=36016982)
1. [ICS4U CHUMP Project: A 4-bit TTL Processor](http://darcy.rsgc.on.ca/ACES/TEI4M/4BitComputer/index.html)
1. [ankangd/4bitPC: Verilog-HDL implementation of a simple 4-bit PC.](https://github.com/ankangd/4bitPC)
1. [8-Bit Wolf Remembering the NES Game Teaching Kids to Conquer Wall Street | Hacker News](https://news.ycombinator.com/item?id=36099022)
1. [How to Believe Six Impossible Things before Breakfast: Irigaray, Alice and Neo-Pagan Negotiation of the Otherworld - Christina N](https://journals.sagepub.com/doi/10.1177/096673500301100309)
1. [1.1 Annotated Slides | Computation Structures | Electrical Engineering and Computer Science | MIT OpenCourseWare](https://ocw.mit.edu/courses/6-004-computation-structures-spring-2017/pages/c1/c1s1/)
1. [IBM SCHOOLVIEW VERSION 1.01](https://www.ibm.com/common/ssi/cgi-bin/ssialias?appname=skmwww&htmlfid=897%2FENUS294-552&infotype=AN&subtype=CA&mhsrc=ibmsearch_a&mhq=44X2450)
1. [ONR Digital Computer Newsletter (1949-64) | Hacker News](https://news.ycombinator.com/item?id=36016774)
1. [Rhizome > blog > A Queer History of Computing: Part Three](https://rhizome.org/editorial/2013/apr/9/queer-history-computing-part-three/)
1. [Hardware Controlled 4 bit CPU | Hackaday.io](https://hackaday.io/project/188633-hardware-controlled-4-bit-cpu)
1. [Memory Allocation | Hacker News](https://news.ycombinator.com/item?id=36029087)
1. [Directly compiling Scheme to WebAssembly: lambdas, recursion, iteration! -- Spritely Institute](https://news.ycombinator.com/item?id=36135844)
1. [mjg59 | Booting modern Intel CPUs](https://mjg59.dreamwidth.org/66109.html)
1. [smlCPU - A small CPU/Microcontroller | Hackaday.io](https://hackaday.io/project/10556-smlcpu-a-small-cpumicrocontroller)
1. [Users Manual V1.0](http://retro.hansotten.nl/uploads/6502docs/usrman.htm#25)
1. [KIM-1 Programming Manual V1.0](http://retro.hansotten.nl/uploads/6502docs/proman.htm)
1. [Inventing the PC: The MCM/70 Story](http://www.cse.yorku.ca/~zbigniew/mcm_add.html)
1. [Edmund Berkeley, Giant Brains, Or Machines that Think at DuckDuckGo](https://duckduckgo.com/?q=Edmund+Berkeley%2C+Giant+Brains%2C+Or+Machines+that+Think&t=iphone&ia=web)
1. [LOAD"$",8 pagetable.com](https://www.pagetable.com/?p=273)
1. [The Adventures of Writing a CHIP8 Emulator - Part 1](https://benjcal.space/posts/the-adventures-of-writing-a-chip8-emulator-part-1/)
1. [Introduction to Verilog](https://www.chipverify.com/verilog/verilog-introduction)
1. [freand76/digsim: An interactive digital logic simulator with verilog support (Yosys)](https://github.com/freand76/digsim)
1. [Physical Turtle Graphics RasterWeb!](http://rasterweb.net/raster/2019/02/04/physical-turtle-graphics/)
1. [Possibly the coolest computer magazine covers ever created... - AnotherDesignBlog.](https://kathykavan.posthaven.com/possibly-the-coolest-computer-magazine-covers-ever-created-dot-dot-dot)
1. [KLOTH.NET - Card punch emulator](http://www.kloth.net/services/cardpunch.php)
1. [georg-rottensteiner.de](https://www.georg-rottensteiner.de/c64/projectj/step2/step2.html)
1. [The 1802 Instruction Set](https://www.atarimagazines.com/computeii/issue3/page52.php)
1. [ECMA-6 - Ecma International](https://www.ecma-international.org/publications-and-standards/standards/ecma-6/)
1. [Oxocards: Interactive programmable minicomputers | Hacker News](https://news.ycombinator.com/item?id=36953195)
1. [The First Book of KIM](http://retro.hansotten.nl/uploads/6502docs/fbok.html)
1. [Rediscovering Historys Lost First Female Video Game De | Co.Design](https://web.archive.org/web/20171027135907/https://www.fastcodesign.com/90147592/rediscovering-historys-lost-first-female-video-game-designer?utm_content=buffer81edd&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer)
1. [How MOS 6502 Illegal Opcodes really work pagetable.com](https://www.pagetable.com/?p=39)
1. [CHIP-8 (and Emulators) In Plain English Cg Math Blog](https://cgmathprog.home.blog/2021/05/20/chip-8-and-emulator-overview/)
1. [nturley/netlistsvg: draws an SVG schematic from a JSON netlist](https://github.com/nturley/netlistsvg)
1. [A Complete History Of Mainframe Computing: Page 3 | Tom's Hardware](https://www.tomshardware.com/picturestory/508-mainframe-computer-history-3.html)
1. [krashen's theory at DuckDuckGo](https://duckduckgo.com/?q=krashen%27s+theory&t=iphone&ia=web)
1. [git-annex](https://git-annex.branchable.com/)
1. [Thinking Machines: Art and Design in the Computer Age, 19591989 | MoMA](https://www.moma.org/calendar/exhibitions/3863)
1. [User defined characters - a really simple font editor (BASIC, Machine Language - C64) | Retro64](https://retro64.altervista.org/blog/user-defined-characters-really-simple-font-editor-basic-machine-language-c64/)
1. [Wayback Machine](https://web.archive.org/web/20190819144645/http://laurencescotford.co.uk/wp-content/uploads/2013/08/CHIP-8-Interpreter-Disassembly.pdf)
1. [DEC DEC DigitalLogicLaboratoryWorkbook 1965 : Free Download, Borrow, and Streaming : Internet Archive](https://archive.org/details/DEC_DEC_DigitalLogicLaboratoryWorkbook_1965/mode/1up?view=theater)
1. [Bit und Byte - Der 1 Bit Computer - Teil 1 - YouTube](https://m.youtube.com/watch?v=iGVIs3Aczog)
1. [A Short Course In Programming by Tom Pittman | COSMAC ELF](http://www.cosmacelf.com/publications/books/short-course-in-programming.html)
1. [Game ideas notebook...](https://digital.hagley.org/LMSS_246409_871_11?solr_nav%5Bid%5D=84f1ced8f24df145d53c&solr_nav%5Bpage%5D=0&solr_nav%5Boffset%5D=9#page/34/mode/2up)
1. [64er 04/1984 (PDF) pagetable.com](https://www.pagetable.com/?p=49)
1. [How to Write a Basic Verilog Module - FPGA Tutorial](https://fpgatutorial.com/how-to-write-a-basic-verilog-module/)
1. [Feminist Data Visualization; Or, the Shape of History Lauren F. Klein](http://lklein.com/conference-papers/feminist-data-visualization-or-the-shape-of-history/)
1. [Virtualizing uxn (eighty-twenty news)](https://eighty-twenty.org/2023/08/11/virtualizing-uxn)
1. [A Mind Is Born](https://linusakesson.net/scene/a-mind-is-born/)
1. [Tracing the roots of the 8086 instruction set to the Datapoint 2200 minicomputer](http://www.righto.com/2023/08/datapoint-to-8086.html?m=1)
1. [I Created the Nerdiest Game Ever | Pier-Luc Brault - Personal Website](https://plbrault.com/blog-posts/i-created-the-nerdierst-game-ever-en/)
1. [retroforth.org](http://www.retroforth.org/)
1. [RCA CDP1861 - Wikipedia](https://en.m.wikipedia.org/wiki/RCA_CDP1861)
1. [Commodore 64 Programming #8: Text and custom charsets | Modern art using the GPU](https://digitalerr0r.net/2011/05/01/commodore-64-programming-8-text-and-custom-charsets/)
1. [MCS6500 Microcomputer Family Programming Manual : Free Download, Borrow, and Streaming : Internet Archive](https://archive.org/details/6500-50a_mcs6500pgmmanjan76)
1. [The Compucolor 8001 (1976) | Hacker News](https://news.ycombinator.com/item?id=8391344)
1. [C64 Development | Retro Commodore | Page 2](https://www.retro-commodore.eu/c64-development/2/)
1. [[CSDb] - C6510 1.0.2 by Censor Design (2023)](https://csdb.dk/release/?id=233215)
1. [Scanning · Crafting Interpreters](http://www.craftinginterpreters.com/scanning.html)
1. [n/cardiograph-computer - cardiograph-computer - n loewen](https://git.nloewen.com/n/cardiograph-computer/src/branch/notes)
1. [cosmacelf@groups.io | DMA-OUT in LOAD mode?](https://groups.io/g/cosmacelf/topic/72979386?20,0,0,0::,,,0,0,0,72979386)
1. [jsbeeb Part Three - 6502 CPU timings — Matt Godbolts blog](https://xania.org/201405/jsbeeb-getting-the-timings-right-cpu)
1. [Linker (computing) - Wikipedia](https://en.m.wikipedia.org/wiki/Linker_(computing))

265
2023-09-03.md Normal file
View File

@ -0,0 +1,265 @@
# Dev notes — 2023-09-03
## Todos
- [ ] add yesterdays reading to dev notes
- chip8 stuff
- js stuff
- [x] reconsider revised ISA
- + a more-binary simulator
- [ ] set up semi-standard js eslint
- remember: meowbit
## Misc. references
TODO: organize these
- [Assembly in One Step](https://dwheeler.com/6502/oneelkruns/asm1step.html)
- [How to write an emulator (CHIP-8 interpreterhttp://www.emulator101.com/6502-addressing-modes.html)](https://web.archive.org/web/20180121070101/http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/)
- http://www.cosmacelf.com/publications/books/cosmac-elf-manual.pdf
- http://archive.6502.org/datasheets/wdc_w65c02s_mar_2000.pdf
- Weisbecker, Joseph, "[Build The COSMAC "ELF" A Low-Cost Experimenter's Microcomputer](http://www.exemark.com/Microcontrollers/PopularElecwebc.pdf)" (re-typed PDF)
- [The UNO1802: A Cosmac Elf for $13 in parts...](http://obsolescenceguaranteed.blogspot.com/2017/08/the-uno1802-cosmac-elf-for-15-in-parts.html)
- [Understanding the MAR and the MDR](https://web.archive.org/web/20170328171842/http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Overall/mar.html)
From earlier:
- [How does a microcontroller boot and startup, step by step?](https://electronics.stackexchange.com/questions/224156/how-does-a-microcontroller-boot-and-startup-step-by-step)
- http://www.6502.org
- [6502 PRIMER: Building your own 6502 computer](http://wilsonminesco.com/6502primer/index.html)
- http://visual6502.org/JSSim/
- [KIM-1 Microcomputer Module User Manual](http://retro.hansotten.nl/uploads/6502docs/usrman.htm) (HTML version)
- [How does a DMA controller work?](https://softwareengineering.stackexchange.com/questions/272470/how-does-a-dma-controller-work)
- [Photo of a KIM-1](http://retro.hansotten.nl/wp-content/uploads/2020/11/20201106_131253a-1-scaled.jpg)
- [Punched Cards & Paper Tape](https://www.computerhistory.org/revolution/memory-storage/8/326)
- [Semyon Korsakov](https://en.wikipedia.org/wiki/Semyon_Korsakov)
- [Punched Card Input/Output Devices](http://www.ibm1130.net/functional/Cards.html)
- [IBM Punched Card Stock Specifications](https://ibm1401.computerhistory.org/CardStockSpecifications.html)
- [The IBM 029 Key Punch](http://www.columbia.edu/cu/computinghistory/029.html)
- http://retro.hansotten.nl/6502-sbc/kim-1-manuals-and-software/kim-1-simulator/
- https://craftinginterpreters.com/a-map-of-the-territory.html
- "2023-08-10 cardiograph reference" tab group:
- [Inside the vintage 74181 ALU chip: how it works and why it's so strange](www.righto.com/2017/03/inside-vintage-74181-alu-chip-how-it.html?m=1)
- [Software woven into wire: Core rope and the Apollo Guidance Computer](www.righto.com/2019/07/software-woven-into-wire-core-rope-and.html?m=0)
- [Arithmetic logic unit - Wikipedia](en.m.wikipedia.org/wiki/Arithmetic_logic_unit)
- [29c05c9d7985b673e98f32fbf43ae628.jpg 1,960×2,014 pixels](i.pinimg.com/originals/29/c0/5c/29c05c9d7985b673e98f32fbf43ae628.jpg)
- [My First Program — ICL CES - Computer Education in Schools](iclces.uk/articles/first_cesil_program.html)
- [CSIRO Computing History Appendix 7: CSIRO Computing Museum / Artefacts CSIROpedia](csiropedia.csiro.au/csiro-computing-history-appendix-7-artefacts/)
- [CHIP-8 in Common Lisp: Input / Steve Losh](stevelosh.com/blog/2016/12/chip8-input/)
- [CHIP-8 virtual machine specification](tonisagrista.com/blog/2021/chip8-spec/)
- [Table of Contents - by Casey Muratori - Computer, Enhance!](www.computerenhance.com/p/table-of-contents)
- [Turing Complete](turingcomplete.game/)
- [6502 Registers](web.archive.org/web/20210626024532/http://www.obelisk.me.uk/6502/registers.html)
- [Easy 6502 by skilldrick](skilldrick.github.io/easy6502/)
- [bitsavers.org](www.bitsavers.org/components/rca/cosmac/COSMAC_VIP_Instruction_Manual_1978.pdf)
- [COSMAC Elf 2000](www.sparetimegizmos.com/Hardware/Elf2K.htm)
- [A Short Course In Programming by Tom Pittman | COSMAC ELF](www.cosmacelf.com/publications/books/short-course-in-programming.html)
- [A Short Course In Programming](www.ittybittycomputers.com/IttyBitty/ShortCor.htm)
- [exemark.com](www.exemark.com/Microcontrollers/PopularElecwebc.pdf)
- [Build The COSMAC "ELF" Part 1](billr.incolor.com/elf/html/elf-1-33.htm)
- [GitHub - tebl/RC1802-Cosmac-ELF: With the RC6502-project for making an Apple 1 replica done I wanted to do something different, so I started designing a simple version of the RCA 1802-based Cosmac ELF instead.](github.com/tebl/RC1802-Cosmac-ELF)
- [More musings of computers past: Popular Electronics, the COSMAC ELF | brainwagon](brainwagon.org/2014/07/27/more-musings-of-computers-past-popular-electronics-the-cosmac-elf/)
## Startup: correction
It doesnt execute “JMP $FF.” It just sets the IP to $FF on reset, and you put a JMP there in ROM.
- [ ] TODO: update docs elsewhere
## Detailed CPU design/low-level simulator
### Revising ISA
[See notes from 2023-08-23](2023-08-23.md)
### Instruction cycle
**For now, treat each instruction as taking one cycle.**
I started making notes on this, which I am leaving below… but this doesnt seem useful at this point so Im forgetting about it for now.
- references
- [Understanding the MAR and the MDR](https://web.archive.org/web/20170328171842/http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Overall/mar.html)
- https://en.wikipedia.org/wiki/Three-state_logic
* 1 cycle - fetch
* copy IP to MAR
* send Read command on memory control line
* copy data from data bus to instruction register
* calculate next IP (if no branch); IP += 2
* 1 cycle - decode
* (i think:) split instruction data into addressing mode, op, data
* calculate branch target
* 2 cycles - execute
* 1 cycle - memory read
* 1 cycle - compute
* 1 cycle - write back
### Sketch in JS
TODO:
- [ ] Figure out how to do DMA
- [ ] Learn more about how the 1802 does DMA
- http://www.cosmacelf.com/publications/books/cosmac-elf-manual.pdf
- http://www.exemark.com/Microcontrollers/PopularElecwebc.pdf
References:
- 6502 SYNC pin
- "The SYNC output is provided to identify those cycles during which the microprocessor is fetching an OpCode. The SYNC line goes high during the clock cycle of an opcode fetch and stays high for the entire cycle. If the RDY line is pulled low during the clock cycle in which SYNC went high, the processor will stop in its current state and will remain in the state until the RDY line goes high. In this manner, the SYNC signal can be used to control RDY to cause single instruction execution."
- -- http://archive.6502.org/datasheets/wdc_w65c02s_mar_2000.pdf
```
class CPU {
constructor (memory, addressBus, dataBus, memoryReadSignal, memoryWriteSignal, cpuWait) {
this.memory = memory;
// TODO: move buses etc to this.pins.foo
this.pins = {
dataBus : dataBus,
addressBus : addressBus,
memoryReadSignal : 0,
wait : cpuWait, // If 1, execution is paused (cf. 6502 RDY pin)
// readNotWrite : 0 // 1 if want to read mem // TODO lower level than i need right now?
}
this.reset();
}
IP = 0;
A = 0;
flags = 0b00000000;
instruction = 0x00;
//What do I want for interrupts…?
// interruptRequest = 0;
// TODO: can it be a simple setup with fixed instruction cycle length pls?
_instructionCycleStep = 0;
tickClock () {
if (this.wait) return false;
switch (this._instructionCycleStep) {
// Fetch
case (0) {
// this.instruction = this.memory.read(this.IP);
this.readWriteControl = 1; // TODO
break;
} case (1) {
// initiate read
this.pins.addressBus = this.IP;
this.pins.memoryReadSignal = 1;
} case (2) {
// complete read
this.pins.memoryReadSignal = 0;
this.instruction = this.dataBus;
}
// TODO: continue switch statement
// ...
/*
// decode
const op = this._decode(this.instruction);
// execute
op();
*/
}
}
reset () {
// this.IP = this.memory.read(0xFF);
this.IP = 0xFF;
this.A = 0;
this.flags = 0b00000000;
this.pins.dataBus = 0b00000000;
this._instructionCycleStep = 0;
this.debug.running = true;
}
_decode (instruction) {
const instrs = {
0x00: end,
// TODO etc
};
return instrs[instruction];
}
debug = {
// TODO include the rest of the stuff that I have here in the current version
running: false,
}
}
```
```
class Memory {
// ROM format: { addr: nn, data: nn }
constructor (sizeInBytes, ROM, addressBus, dataBus, readSignal, writeSignal) {
// memory format: [ { data: nn, type: str } ]
this.memory = new Array(sizeInBytes);
objectForEach(ROM, (byte) => {
this.memory[byte.addr] = { data: byte[data], type: ROM };
})
this.pins = {
addressBus: addressBus,
dataBus: dataBus,
readSignal: readSignal,
writeSignal: writeSignal,
}
}
tickClock () {
if (this.pins.readSignal) this._read();
if (this.pins.writeSignal) this._write();
}
_read () {
this.pins.dataBus = this.memory[this.pins.addressBus];
}
_write () {
if (this.memory[this.pins.addressBus].type === ROM) throw new Error(Attempted write to ROM);
this.memory[this.pins.addressBus].data = data;
}
}
function objectForEach (object, fn) {
return Object.keys(object).forEach(key => fn(key, object[key]));
}
```
```
/** DMA controller for screen, keypad... **/
class IO {
// TODO…
constructor (addressBus, dataBus, cpuWaitPin) {
// ...
}
}
```
cardiograph.js:
```
// TODO: these might all need to be functions?
let dataBus = 0;
let addressBus = 0;
let memoryReadSignal = 0;
let memoryWriteSignal = 0;
let cpuWait = 0;
let rom = // TODO read in…
let memory = new Memory(256, rom, addressBus, dataBus, memoryReadSignal, memoryWriteSignal);
let cpu = new CPU(memory, addressBus, dataBus, memoryReadSignal, memoryWriteSignal, cpuWait);
```
Sketch is missing:
- DMA stuff (IO)
- actual instruction decoding/execution

179
2023-09-04.md Normal file
View File

@ -0,0 +1,179 @@
# Dev notes — 2023-09-04
## To do
- [x] move recent sketch to its own branch
- [x] make a list of visual-research ideas
- [x] put “cpu datasheet” on it
- [ ] Implement keypad-based memory read/write (like ELF/KIM); see earlier notes for my design
- [ ] Maybe implement one IO pin, as described [below](#screen-memory-as-a-more-general-purpose-dmaio-area)
## Afternoon 2
- Interrupts and CPU-pin-based general-purpose IO are too far from being relevant to the real goal of this project — forget about 'em
### Screen memory as DMA area (general-purpose)
- ...but: it be cool to be able to print a copy of the screen...
- You would have a pin for 'DMA request'. When you're ready to write she screen out to the printer, you pull that high, signalling the printer to read from the screen memory, and then pull the pin low again.
- The same pin could presumably be used in the other direction, as an input...
## Afternoon 1
### Reflection on recent research
I have been trying to work out my answers to a few questions about the cpu design, mainly with the goal of deciding how programs should be loaded into the Cardiograph.
This has meant learning more about the details of cpu architecture — Ive read some general reference material, as well as more specific material on the 1802 and 6502.
Ive also made an incomplete (but instructive) sketch of a lower-level cpu simulation in Javascript.
This is all work that I will need to do eventually, since I hope to make a logic-level simulator of the system (in logisim), and maybe an FPGA implementation, etc.
(Those are things that I want to learn to do — but they also have good graphic potential. Logic and circuit schematics; timing diagrams (drawn or embroidered); …)
But for now I think I should put this line of inquiry on pause.
I think the answer to my “how are programs loaded” is (at least for now): through a keypad-entry system like the Cosmac Elf or the KIM-1. Im now content that something like that can be made, and so I think for now the low-level implementation details arent critical.
Or, thats a partial answer — another answer might be: from paper tape or punched cards. But I think thats not fundamentally too different… (It could also be done by DMA while the cpu is held idle. Or it could be done through a short loader-routine, if the cpu has some general-purpose IO…)
And its the keypad entry that interests me for now, because thats what I want to be able to implement on the simulator. (I already have something close enough to loading from tape, I think? For now, anyway.)
#### But wait, maybe there _is_ more…
Ah, but I had also wanted to work out:
1. what it would look like to have some general-purpose I/O
2. whether I need some interrupts
For I/O, Im interested in something that might run a LOGO turtle, and maybe a printer.
For interrupts, Im wondering if theyre needed for good keypad handling.
For both of those, the real Q is: Do I need new registers, and/or do I need new instructions?
(Can I service interrupts without a stack? Is that too weird?)
#### What next…?
- Implement keypad-based memory read/write (like ELF/KIM); see earlier notes for my design
- ~~Learn more about how interrupts were used with the ELF and KIM~~
- (maybe think about I/O for turtles and printers)
The ISA will probably have to change (as outlined in an earlier note), but I think not yet. Since the instructions should be staying the same, just getting re-numbered, that should be easy enough to do later, when creating a lower-level simulator makes it a necessity.
### Reading notes — re: decode step of instruction cycle, plus other relevant bits of processor design
[The central processing unit (CPU): Its components and functionality | Enable Sysadmin](https://www.redhat.com/sysadmin/cpu-components-functionality)
> For example, when adding two numbers, one number is placed in the A register and the other in the B register. The ALU performs the addition and puts the result in the accumulator. If the operation is a logical one, the data to be compared is placed into the input registers. The result of the comparison, a 1 or 0, is put in the accumulator. Whether this is a logical or arithmetic operation, the accumulator content is then placed into the cache location reserved by the program for the result.
>
> There is another type of operation performed by the ALU. The result is an address in memory, and it is used to calculate a new location in memory to begin loading instructions. The result is placed into the instruction pointer register.
[1.4 Instruction Cycles - Engineering LibreTexts](https://eng.libretexts.org/Courses/Delta_College/Operating_System%3A_The_Basics/01%3A_The_Basics_-_An_Overview/1.4_Instruction_Cycles)
- fetch
- pc → mar
- pc++
- mem(mar) → mdr
- mdr → cir (current instruction register)
- decode
- [control unit decodes, signals to ALU et al.]
- indirect address
- read from memory
- direct address
- do nothing this pulse
- i/o or register instruction
- execute that
- execute
- [control unit passes decoded info as series of signals…]
- [if involved, ALU sends a condition signal back to CU]
- write out data to memory or i/o
- update PC if appropriate
[1.5 Interrupts - Engineering LibreTexts](https://eng.libretexts.org/Courses/Delta_College/Operating_System%3A_The_Basics/01%3A_The_Basics_-_An_Overview/1.5_Interrupts)
[1.8 Direct Memory Access - Engineering LibreTexts](https://eng.libretexts.org/Courses/Delta_College/Operating_System%3A_The_Basics/01%3A_The_Basics_-_An_Overview/1.8_Direct_Memory_Access)
- Bus Request and Bus Grant signals/pins
[Instruction Cycle in CPU: How Fetch, Decode and Execute work | ITIGIC](https://itigic.com/instruction-cycle-in-cpu-how-fetch-decode-and-execute-work/)
**[https://www.cl.cam.ac.uk/teaching/2021/DigElec/slides/Micro_20.pdf](https://www.cl.cam.ac.uk/teaching/2021/DigElec/slides/Micro_20.pdf)**
- see p. 5
- there are 2 internal registers holding inputs (eg numbers to add)
- arithmetic: CU sends to ALU:
- src_r1 - num 1
- src_r2 - num 2
- [destination reg]
- op
- memory load:
- CU sets
- src_r1 - address
- src_r2 - null
- [destination reg]
- a flag indicates whether to send those to the ALU or to memory
- memory stores data to destination reg
***
- maybe break CPU into classes for each control unit?
## Morning
### Keypad musings
This is the current layout:
```
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
```
But the KIM-1 layout makes more sense...
```
on go st rs
ad da pc +
c d e f
8 9 a b
4 5 6 7
0 1 2 3
```
From [2023-08-31](2023-08-31.md):
> I'm thinking the system needs:
>
> 1. on/off switch
> 2. 'shift' key
> 3. hex keypad
>
> The 'shift' key allows each of the keypad keys to have two functions:
>
> `1 / + ` `2 ` `3 ` `C / ST`
> `4 ` `5 ` `6 ` `D `
> `7 / DA` `8 ` `9 ` `E / G1`
> `A / AD` `0 ` `B ` `F / GO`
A new idea:
```
AD DA . +
. . . .
. . . .
ST . G1 GO
```
### ISA
- mode for 'END' and 'NOP' can be called 'implied'
- http://www.emulator101.com/6502-addressing-modes.html

41
2023-09-05.md Normal file
View File

@ -0,0 +1,41 @@
# Dev notes — 2023-09-05
## Re: Blinkenlights
See [2023-08-31](2023-08-31.md#displaying-data-microprocessor-trainer-style)
That earlier note covers hexadecimal.
Here are some new notes on decimal display:
- https://en.wikipedia.org/wiki/Two-out-of-five_code -- used for representing the decimal digits using five bits.
- https://en.wikipedia.org/wiki/Bi-quinary_coded_decimal
- The Remington Rand 409 and UNIVAC LARC encodings listed on that bi-quinary page are close to what I might want.
**Here's my bi-quinary variation (similar to the IBM 650's):**
5 q q q q
○ ○ ○ ○ ○ = 0
○ ○ ○ ○ ● = 1
○ ○ ○ ● ○ = 2
○ ○ ● ○ ○ = 3
○ ● ○ ○ ○ = 4
● ○ ○ ○ ○ = 5
● ○ ○ ○ ● = 6
● ○ ○ ● ○ = 7
● ○ ● ○ ○ = 8
● ● ○ ○ ○ = 9
## ISA
I think the group and addressing-mode sections need to be smaller, so that you can have more than 16 distinct operations?
## Naming/design variations
- hex keypad version: “microcardiograph”
- toggle switches “minicardiograph”
- etc.
(allowing diff design for larger punch-card mainframe...)

154
2023-09-07.md Normal file
View File

@ -0,0 +1,154 @@
# 2023-09-07 — Dev notes
From apple note "card 7 sept"
## Peripherals brainstorm
[XXIIVV — varvara](https://wiki.xxiivv.com/site/varvara.html)
- i like their standardized IO…
- what IO do i have/want…?
- bitmapped display
- keypad
- ? printer
- ? paper tape / card reader
- other standard choices are…
- GPIO
- ascii keyboard
- serial terminal
- audio
- how about re-imagining it as a game system?
- just because that would help to explain the lack of standard IO
- but also it would ruin the whole idea of it being a model computer lol
- ok so cardiograph shouldnt have Keyboard, etc, because like a microprocessor trainer wouldnt
- (but a mainframe would… hmm)
- but at any rate, it would be nice if the CPU _did_ support those possibilities
- todo: look at uxntal runes and see how they compare to mine
## Interrupts
### uxn/varvara design
https://github.com/DeltaF1/uxn-impl-guide/blob/main/devices.md
> The Varvara specification asserts that the Uxn CPU core is non-interruptible. That is, the CPU is left to run on its current task until it hits a BRK instruction, even if some event happens in the host system ( such as the mouse moving ) Once the CPU stops executing, the next event can be serviced.
> Each device specification outlines the conditions under which the device vector will be triggered. Execution begins at the device's "vector" address. If this address is equal to 0x0000, then no code is executed. By convention, the first 2 bytes of each device store the device's vector address as a short.
> The initial vector that gets run by the emulator at startup is hardcoded to be address 0x0100.
- my understanding: this is similar to what i have… these “vectors” are memory-mapped inputs that are constantly kept up to date, but only read when a BRK instruction is encountered. when that happens, whatever routine you have pre-registered as an event handler gets called.
- Q: is that right?
- Q: is this a standard design?
- Q: lets see some examples?
### Scamp CPU (+ CP/M, 6502...)
[jes/scamp-cpu: A homebrew 16-bit CPU with a homebrew Unix-like-ish operating system.](https://github.com/jes/scamp-cpu)
[Scamp CPU: A homebrew 16-bit CPU with a homebrew Unix-like-ish operating system | Hacker News](https://news.ycombinator.com/item?id=29408046)
> I think the most surprising thing to me is the lack of interrupts. If you read this, jstanley: did you struggle much with that decision? I think of interrupts as nearly universally available on 8-bit micros, much less 16, but I have also wondered before how important they really were for what those machines ended up being used for. The (S)NES polled their controllers' shift registers in a really inefficient way, but it turned out fine. On the other hand, though, the vertical blank interrupt was pretty critical to their software and, of course, it became extremely common for NES cartridges to add extra chips to raise interrupts on particular horizontal scanlines. But, aside from neat graphical tricks, maybe interrupts just weren't all that important?
> You don't need to implement a nested vectored interrupt controller. Even just a timer/counter with overflow interrupt would solve your current issues with lockup by allowing you to implement preemptive multitasking. Once you do that it would be easy-ish to extend to the serial controller.
> Basically, on interrupt flag = 1, 1. Disable further interrupts (no nesting). This makes things easier to implement. 2. Save register state. For speed a special set of shadow registers can be used, or you can put register state on the stack. 3. Jump to interrupt routine code start. 4. Let interrupt handler run, clear interrupt flag, then return.
> In the simplest case an input flag simply causes a CALL (push pc, jump to address). In that case the interrupt handler needs to know to save state. You can test flags between instructions to see if you need to inject the push/jump.
> CP/M is really incredibly simple. You have some "kernel" type stuff towards the top of memory, with routines for reading/writing files on disk, and interacting with the console and a paper tape "reader + punch". When you type a command, the named program is loaded from disk into memory starting at 0x100 and then execution starts at 0x100. To interact with hardware, the program calls the kernel's routines (analogous to system calls). And that's basically all there is to it.
> 6502 is a very simple CPU and you can learn all of its instructions in several hours. But as it uses 1- address instructions, the code gets pretty verbose. For example, to add 10 to a variable you will have to write:
>
> ```
> LDA var
> CLC
> ADC #10
> STA var
>```
> That's 4 lines and many keypresses for a single addition! You might want to invent slightly more high-level language that would compile into assembly, like this:
>
> ```
> var, var2 = variables (2)
> var t=10
> var2 << 5 # Assign 5 to var2
>```
> By the way, you can use Python and operator overloading so that the lines above written in Python will generate assembly code when executed. I have used << instead of = in assignment because Python doesn't allow to
overload it.
### Apple II
!! [Keyboard interaction on the Apple II is entirely CPU-dependent, memory-mapped, a... | Hacker News](https://news.ycombinator.com/item?id=20404825)
### C64
[How the C64 Keyboard Works | C64 OS](https://c64os.com/post/?p=45)
## Reflections
i still want to understand the uxn approach better, and see if theres prior art
...
it seems like not having interrupts is fine
you just gotta do polling, but thats ok (and what some 8-bit micros did anyway)
and this should really help with the goal of making the simplest CPU possible
another thing that will help is leaving DMA to some other chip… and having a pin that pauses the CPU (like 1802/6502) should make that easy
## CPU pinout brainstorm
which means I think the CPU pinout can just be:
- power
- ground
- address x8
- data x8
- “dma okay”
- pause
- reset
(for later thought: bank-switching requires a memory controller… and how do we want to interface with that?)
### 1802 note
1802 clear + wait: load, reset, pause, run
## To do
Todo: make index for dev notes
## Bank switching
### Game boy
[game boy - How does the Gameboy's memory bank switching work? - Retrocomputing Stack Exchange](https://retrocomputing.stackexchange.com/questions/11732/how-does-the-gameboys-memory-bank-switching-work)
### C64
[Bank Switching - C64-Wiki](https://www.c64-wiki.com/wiki/Bank_Switching)
## ISA
consider an ISA with multiple operands?
good article: https://en.wikipedia.org/wiki/Orthogonal_instruction_set
## Think about writing simulators for these platforms
- Web
- Meowbit
- Microbit
- C64
- Gameboy
- Gameboy Advance
- Nintendo DS

123
2023-09-08.md Normal file
View File

@ -0,0 +1,123 @@
## 2023-09-08 — Dev notes
- what changes are required to address more memory?
•••
- drop the Overflow flag?
- … what flags does uxn have?
## Qs: Reading input
- what do we do if we want to ask the tape reader (etc.) to read in some data?
- is it enough to have that device do polling??
- what does uxn do?
## Networking??? - Gameboy link cable
- how does the gameboy link cable work?
- [emulation - How does the Gameboy Link Cable work? - Retrocomputing Stack Exchange](https://retrocomputing.stackexchange.com/questions/12549/how-does-the-gameboy-link-cable-work)
[Serial Data Transfer (Link Cable) - GbdevWiki](https://gbdev.gg8.se/wiki/articles/Serial_Data_Transfer_(Link_Cable))
gb link cable has 1 gb clocking the other, for synchronization
## Program ideas
- machine monitor w output to graph display
## Flags
- reconsider flags… i think i want to drop the overflow flag…
## Other educational machines
https://en.wikipedia.org/wiki/MIX
https://en.wikipedia.org/wiki/DLX
- good info on instruction cycle!
https://en.wikipedia.org/wiki/MicroBlaze
! https://en.wikipedia.org/wiki/MikroSim
_these educational machines seem to never cover actually loading a program into memory / bootstrapping …_
[freedosproject/toycpu: A simulation of a Minimal instruction set computer](https://github.com/freedosproject/toycpu)
- great readme opcode reference
- this has a front panel! loading!
### LC-3
https://en.wikipedia.org/wiki/Little_Computer_3
#### Articles on simulating + LC-3's design
[Let's build an LC-3 Virtual Machine :: Rodrigo Araujo — Computer Scientist and Software Engineer](https://www.rodrigoaraujo.me/posts/lets-build-an-lc-3-virtual-machine/)
- nb: section on TRAP
- get char
- write char
- puts
- prompt…
- putsp
- KBSR & KBDR mem mapped regusters
[great piece on building an LC-3 VM](https://justinmeiners.github.io/lc3-vm/)
enum
{
OP_BR = 0, /* branch */
OP_ADD, /* add */
OP_LD, /* load */
OP_ST, /* store */
OP_JSR, /* jump register */
OP_AND, /* bitwise and */
OP_LDR, /* load register */
OP_STR, /* store register */
OP_RTI, /* unused */
OP_NOT, /* bitwise not */
OP_LDI, /* load indirect */
OP_STI, /* store indirect */
OP_JMP, /* jump */
OP_RES, /* reserved (unused) */
OP_LEA, /* load effective address */
OP_TRAP /* execute trap */
};
LC-3 just has flags for pos, zero, neg
> You may be wondering why the trap codes are not included in the instructions. This is because they do not actually introduce any new functionality to the LC-3, they just provide a convenient way to perform a task (similar to OS system calls). In the official LC-3 simulator, trap routines are written in assembly. When a trap code is called, the PC is moved to that codes address. The CPU executes the procedures instructions, and when it is complete, the PC is reset to the location following the initial call.
> Note: This is why programs start at address 0x3000 instead of 0x0. The lower addresses are left empty to leave space for the trap routine code.
> Note: Getting input from the keyboard is one specific example of this. The assembly version uses a loop to continuously check the keyboard for input.
KBSR = keyboard status
KBDR = keyboard data
and those seem to just have regular memory addresses
https://www.jmeiners.com/lc3-vm/supplies/lc3-ref-card.png
## "IP" vs "PC"?
- should i rename IP to PC since thats what everyone else calls it?
## Misc. references
[history - Which computers did Donald Knuth "mix" together to get MIX? - Retrocomputing Stack Exchange](https://retrocomputing.stackexchange.com/questions/18117/which-computers-did-donald-knuth-mix-together-to-get-mix)
[How a CPU works: Bare metal C on my RISC-V toy CPU · Florian Noeding's blog](https://florian.noeding.com/posts/risc-v-toy-cpu/cpu-from-scratch/)
https://edaplayground.com/
### PDP
[PDP-10 Arith-Tests](http://pdp10.nocrew.org/docs/instruction-set/Arith-Tests.html)
[Learn PDP-11 Assembly Coding Lesson 1 - For absolute beginners! - YouTube](https://www.youtube.com/watch?v=sk5Y26Qb1Ow)

45
2023-09-10.md Normal file
View File

@ -0,0 +1,45 @@
# Dev notes — 2023-09-10
Links to organize:
- https://www.youtube.com/watch?v=21bQBCfMDb8
- https://www.masswerk.at/google60/
- https://www.masswerk.at/nowgobang/2021/nerdy-reading
- https://www.masswerk.at/misc/card-punch-typography/
- https://www.masswerk.at/6502/
- https://en.wikipedia.org/wiki/Charactron
- https://dsinecos.github.io/blog/Using-Bitmasks
- https://www.youtube.com/watch?app=desktop&v=eA3TtCCNmKo
- ? mail robots
- https://www.atlasobscura.com/articles/mailmobiles-mail-robots-technology-retirement
- https://www.cbc.ca/radio/day6/episode-357-little-rock-nine-historians-vs-neo-nazis-tabatha-southey-fired-robots-yuval-harari-and-more-1.4309188/so-long-and-thanks-for-all-the-mail-cbc-retires-its-fleet-of-mailbots-1.4309201
- https://news.ycombinator.com/item?id=37155752
- Weisbecker archive
- https://digital.hagley.org/AVD_246409_040_06#page/6/mode/2up
- https://socks-studio.com/2013/06/29/computer-graphics-archaeology-the-hp-9845c-demo/
- http://wiscasset.net/artcraft/antheil.htm
- http://wiscasset.net/artcraft/pleyel6.htm
- popular press:
- https://www.npr.org/sections/alltechconsidered/2014/10/06/345799830/the-forgotten-female-programmers-who-created-modern-tech
- https://www.nytimes.com/2019/02/13/magazine/women-coding-computer-programming.html
- artwork reference:
- https://www.pinterest.ca/pin/322851867052077355/
- https://en.wikipedia.org/wiki/Deltar
- https://damprojects.org/wp-content/uploads/2018/08/PressReleaseCODE_POETRY_EN.pdf
- http://digital-abstraction.net/catalog/flicker/index.html
- https://en.wikipedia.org/wiki/Arnulf_Rainer_(film)
- https://www.youtube.com/watch?v=JC0o2Msvdpg
- https://bethany.remingtonjohnson.com/work/field-notes/
- https://bethany.remingtonjohnson.com/work/woven-landscapes/
- MANY DAM PROJECTS
- https://damprojects.org/computergrafik1984/
- https://damprojects.org/codepoetry/
- & look at others

75
2023-09-11.md Normal file
View File

@ -0,0 +1,75 @@
# 2023-09-11 — Dev notes
## ISA
### To do
- Remove the END instruction, and use `$00` for NOP
### Goals
I want to keep a basic "bare minimum" set at `$00`-`$0F`, since that serves the educational goal.
That leaves the high byte free for adding more complex/convenience features.
### Possible additions
#### Things that are hard to do otherwise
- bitwise operations
- rotate left
- rotate right
#### Conveniences
- multiplication
- division
- add with carry
- sub with borrow
- comparisons
- less than
- greater than
### Layout idea
Maybe try to roughly map additional features onto the same areas as the basic ones:
| x | Mnm | Mnm |
|---|-----|-----|
| 0 | NOP | |
| 1 | STO | ROL |
| 2 | STO | ROR |
| 3 | LDA | ARL |
| 4 | LDA | ARR |
| 5 | ADD | MUL |
| 6 | ADD | MUL |
| 7 | SUB | DIV |
| 8 | SUB | DIV |
| 9 | HOP | HLT hop < |
| A | HOP | HLT hop < |
| B | JMP | HGT hop > |
| C | JMP | HGT hop > |
| D | FTG | |
| E | FHP | |
| F | | |
### Extended system
- Additional 'B' accumulator?? (cf. motorola 6800)
### Earlier notes
- [2023-08-23](2023-08-23.md#isa---instruction-set-layout-notes)
- [2023-09-04](2023-09-04.md#isa)
- [2023-09-07](2023-09-07.md#isa)
## Pinout
- [ ] TODO: review highlights in Petzold book
### Earlier notes
- [2023-09-07: 1802 note](2023-09-07.md#1802-note)
- [2023-09-07: pinout brainstorm ](2023-09-07.md#cpu-pinout-brainstorm)
- [2023-08-30: 1802](2023-08-30.md#1802)
- [2023-09-04: screen memory as DMA area](2023-09-04.md#screen-memory-as-dma-area-general-purpose)

121
2023-09-13.md Normal file
View File

@ -0,0 +1,121 @@
# 2023-09-13 — Dev notes
Highlights in this note:
- [BEFLIX](#beflix)
- [aperture cards](#aperture-cards)
## Tools that could be fun to use for simulators
- try Love2D for graphical simulator
- + fennel
- also P5
- pico8 / tic80
- C + Raylib
- [Defold](http://defold.com)
## Quick incomplete survey of decimal computers
- ENIAC
- 1951 — UNIVAC I
- & II
- …
- 1955/56 — TX-0
- 1959-1971 — IBM 1401
- 1964 — IBM System/360
- z80, 6502, x86… include instructions for BCD
## Quick survey of early computeres that *weren't* decimal
- 1950
- 1959-1969 — PDP-1 (spacewar)
- 1965 — PDP-8 (“DECs first major success and the start of the minicomputer revolution”)
- 1970 — PDP-11 (“the archetypical minicomputer” — wikipedia)
## Cardiac
- 1966-1968
### Links
- https://americanhistory.si.edu/collections/search/object/nmah_1465426
- https://www.drdobbs.com/embedded-systems/paper-to-fpga/240155922
- https://www.cs.drexel.edu/~bls96/museum/cardiac.html
- https://www.cs.drexel.edu/~bls96/museum/cardiac.pdf
(I'm looking for info about what computers they were using at Bell Labs, and what they were doing with them...)
From CARDIAC manual:
> The computer is playing an increasingly important part in all areas of research at Bell Laboratories. Today, about 30 per cent of the technical personnel there spend more than half their time programming computers.
>
> Currently, a Bell Laboratories task force is <mark>developing BIS (Business Information System)</mark> to supply Bell System management with the kind of up-to-the-minute information needed to reduce operating costs and provide better customer service. BIS will use new third generation computers-high-speed, on-line, real-time random-access machines with mass information storage and retrieval capabilities.
>
> It is no exaggeration to say the story of Bell Laboratories and computers is a significant one. Information theory, error detection and correction codes, electronic switching, <mark>programs for visual computer displays such as BEFLIX</mark>, as well as for design, simulation and modeling—these and many others are only highlights in the long story. And as a by-product of this story, CARDIAC was developed, which we hope will help you to understand computers.
## BEFLIX
→ https://en.wikipedia.org/wiki/BEFLIX
> BEFLIX is the name of the first embedded domain-specific language for computer animation, invented by Ken Knowlton at Bell Labs in 1963.[1] The name derives from a combination of <mark>Bell Flicks</mark>. Ken Knowlton used BEFLIX to create animated films for educational and engineering purposes. He also <mark>collaborated with the artist Stan Vanderbeek at Bell Labs to create a series of computer-animated films called Poemfields between 1966 and 1969.</mark>
>
> BEFLIX was <mark>developed on the IBM 7090 mainframe computer using a Stromberg-Carlson SC4020 microfilm recorder for output</mark>. The programming environment targeted by BEFLIX consisted of a FORTRAN II implementation with FORTRAN II Assembly Program (FAP) macros. The first version of BEFLIX was implemented through the FAP macro facility. A later version targeting FORTRAN IV resembled a more traditional subroutine library and lost some of the unique flavor to the language.
>
> <mark>Pixels are produced by writing characters to the screen of the microfilm recorder with a defocused electron beam. The SC4020 used a charactron tube to expose microfilm. In BEFLIX, the electron beam is defocused to draw pixels as blurred character shapes. Characters are selected to create a range of grayscale values for pixels.</mark> The microfilm recorder is not connected directly to the 7090, but communicates through magnetic tape. BEFLIX writes the magnetic tape output on the 7090 and the film recorder reads the tape to create the film output. BEFLIX also supports a preview mode where selected frames of the output are written to the line printer.
!!!
→ [Using his BEFLIX Computer Animation Language, Ken Knowlton Produces "A Computer Technique for the Production of Animated Movies" ](https://historyofinformation.com/detail.php?id=3467)
## IBM 7090
→ https://en.wikipedia.org/wiki/IBM_7090
- first install December 1959
- The basic instruction formats were the same as the IBM 709
- seems like this wasnt a decimal machine
- great console
- very Full Room
→ https://www.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP7094.html
## One Instruction Set Computer
Relevenat to CARDIAC?
https://www.cs.drexel.edu/~bls96/oisc/
## <mark>Aperture cards</mark>
- [Aperture Cards: The Last of an Art Form - The Crowley Company](https://thecrowleycompany.com/aperture-microfilm-cards-last-artform/)
- https://thecrowleycompany.com/aperture-microfilm-cards-last-artform/
- https://wwl.co.uk/micrographic-scanning-systems/microfilm-cards/
- https://homepage.divms.uiowa.edu/~jones/cards/collection/i-aperture.shtml
## TO READ: IBM System/360 etc.
- [Building the System/360 Mainframe Nearly Destroyed IBM](https://spectrum.ieee.org/building-the-system360-mainframe-nearly-destroyed-ibm)
- TODO: read
- includes great pictures of components + factory-floor photos
- https://news.ycombinator.com/item?id=19614548
- [IBM System/360 Principles of Operation (1964) [pdf] | Hacker News](https://news.ycombinator.com/item?id=21481045)
- Bitsavers: http://bitsavers.org/pdf/ibm/360/princOps/A22-6821-0_360PrincOps.pdf
- [System/360 Announcement](https://www.ibm.com/ibm/history/exhibits/mainframe/mainframe_PR360.html) — "press release distributed on April 7, 1964"
- [System/360 Announcement (1964) | Hacker News](https://news.ycombinator.com/item?id=30942342)
- [IBM: Producer or Predator ](https://reason.com/archives/1974/04/01/ibm/print)
- April 1974
## To do
- look at ibm reference cards
- download manuals for decimal machines
- + PDP
- **aperture cards as slides**
- [The Mystery of Claude Shannons Personal Computer](https://ieeexplore.ieee.org/stampPDF/getPDF.jsp?tp=&arnumber=9039960&ref=)

17
2023-09-20.md Normal file
View File

@ -0,0 +1,17 @@
# 2023-09-20 — Dev notes
- TODO: look at punch cards for knitting machines
## BEFLIX + related research projects
[The Incredible Machine (1968)
](https://www.youtube.com/watch?v=iwVu2BWLZqA)
- great reference
- includes brief demo of BEFLIX
- which is of relevance to my work, as an early comp graphics project
- and which makes it (iirc) contemporary with the Cardiac
- TODO listen to the *Advent of Computing* podcast's episode about BEFLIX
- https://adventofcomputing.com/?guid=a7aecef4-16f9-4c4b-811b-0c93320c6aa9
- https://www.youtube.com/watch?v=IL7dsFtauN4&pp=ygUPYmZsaXggYmVsbCBsYWJz

39
2023-09-22.md Normal file
View File

@ -0,0 +1,39 @@
# 2023-09-22 — Dev notes
## How did DMA work on the PDP-8?
[https://gunkies.org/wiki/PDP-8_architecture](https://gunkies.org/wiki/PDP-8_architecture):
> All supported DMA, called "data break" in the PDP-8's. There were two types.
In one, "three cycle data break", the buffer address and word count were kept in main memory (at an address usually specified by jumpers on the device). This required the assistance of the processor, placing the processor in charge of maintaining the DMA address and word count. This moved some of common logic (needed to implement the I/O device) from each I/O device into one common copy of the logic within the processor, reducing the device complexity (and thus cost). In three successive memory cycles, the processor would update the word count, update the transfer address, and finally store or retrieve the actual I/O data word.
The other, "single cycle data break", moved back to the individual I/O devices all the responsibility for maintaining the word count and transfer address (in registers in the device); this effectively tripled the DMA transfer rate because only the target data needed to be transferred to/from the main memory.
+ here's an overview of the PDP-8 [Another Real Machine: The DEC PDP-8](http://www.quadibloc.com/comp/cp0306.htm)
## How did DMA/memory access work on the IBM 709?
[1958 IBM 709 First Use of DMA](https://storagesystemshistory.wordpress.com/2021/05/31/1958-ibm-709-first-use-of-dma/)
> DMA did exist in two military systems prior to these commercial machines. Smotherman notes:
>
> > “The DYSEAC also appears to be the first computer to provide DMA, although IBM was granted a patent for DMA cycle-stealing on the SAGE system (US 3,319,230 Astrahan, et al., Data Processing Machine Including Program Interrupt Feature, filed Sept. 1956 and granted May 1967). (The SAGE project started in 1952, and I cannot yet determine the date of the first use of DMA in the design.)”
> IBM developed a buffered I/O system on its 709 computer, in which data channels attached to the memory could perform I/O at the same time as the processor was doing computation. The first 709 was delivered in late summer 1958.
> Whether interrupts are a necessary feature of DMA I/O may be subject to debate and I argue they arent as the 709 did not have interrupts. It doesnt matter if the I/O DMA address was part of the CPU logic or part of the peripheral controller in order to qualify.
## IBM 709 — more material
http://sky-visions.com/ibm/ibm709_instr.shtml
http://www.piercefuller.com/collect/main.html
http://www.piercefuller.com/library/ibm709diagrams.html
http://www.piercefuller.com/collect/709dwg/index.html
https://ed-thelen.org/comp-hist/BRL61-ibm0709.html
https://www.computer-history.info/Page4.dir/pages/IBM.7090.dir/index.html

25
2023-09-23.md Normal file
View File

@ -0,0 +1,25 @@
# 2023-09-23 — Dev notes
## BEFLIX
- [THE FIRST MAN TO FILL A MOVIE SCREEN WITH PIXELS-- the great career of Ken Knowlton](https://m.youtube.com/watch?v=gwPY7-jcLjk)
- Knowlton interviewed by Ted Nelson
- [Visualing Poetry With 1960s Computer Graphics - AT&T Archives
](https://m.youtube.com/watch?v=V4agEv3Nkcs)
## Interrupts - their history
- http://cap-lore.com/Hardware/int.html
- https://people.computing.clemson.edu/~mark/interrupts.html
## IBM 709 info + drawings
- http://www.piercefuller.com/collect/709dwg/index.html
## MIDSAC Pool game, 1954
https://ultimatehistoryvideogames.jimdofree.com/pool/
"First game with real time graphics (updated in real time, rather than only when the player making a move)"

333
2023-09-24.md Normal file
View File

@ -0,0 +1,333 @@
# 2023-08-23 — Dev notes
# Morning
## Architecture changes
### IO
- need new status register, to hold current io device number
- could use the high byte of the Flags register, PSW style
- need read/write instructions
- dev xx — select device xx
- or could do “ldd” and “std”
- inp xx — read one unit into memory, starting at xx
- out xx — write one byte from memory, starting at xx
- ? ota — write from A
### 'B' register?
- maybe? add B register, based on IBM 704/709/7090 “m/q”
- i thought this might be needed as an IO buffer but now Im thinking not
- might still need/want it for mul/div tho
- would need new instructions
- ldb
- stb
- tab
- tba
- ? xba (exchange a and b)
## System/360 IPL
From the [Wikipedia article on booting](https://en.m.wikipedia.org/wiki/Booting):
> In the System/360 processors, an IPL is initiated by the computer operator by selecting the three hexadecimal digit device address (CUU; C=I/O Channel address, UU=Control unit and Device address[nb 2]) followed by pressing the LOAD button.
> The IPL function in the System/360 and its successors prior to IBM Z, and its compatibles such as Amdahl's, reads 24 bytes from an operator-specified device into main storage starting at real address zero. The second and third groups of eight bytes are treated as Channel Command Words (CCWs) to continue loading the startup program (the first CCW is always simulated by the CPU and consists of a Read IPL command, 02h, with command chaining and suppress incorrect length indication being enforced). When the I/O channel commands are complete, the first group of eight bytes is then loaded into the processor's Program Status Word (PSW) and the startup program begins execution at the location designated by that PSW.
> The disk, tape or card deck must contain a special program to load the actual operating system or standalone utility into main storage, and for this specific purpose "IPL Text" is placed on the disk by the stand-alone DASDI (Direct Access Storage Device Initialization) program or an equivalent program running under an operating system, e.g., ICKDSF, but IPL-able tapes and card decks are usually distributed with this "IPL Text" already present.
# Evening
## THIS WAS WRONG: Sense switches + Status register brainstorm
change status register format to:
```ss dd ffff```
- ss - sense switches
- dd - io devices
- ffff - flags
then you are limited to
- 4 switches
- 4 io devices
- 4 flags
## Mainframe peripherals — new thoughts
_this was written in response to the previous section, which i have abandoned… but i think the ideas here are still good_
~~you could have an external switch that toggles between input from terminal vs punch~~
~~or i guess~~ you make an all-in-one console that has a few modes
1. keypunch
2. teletypewriter
3. card reader + line printer
4. card reader + computer-controlled
ie, you can choose to connect…
- no input devices
- card reader
- typewriter
…and likewise for outputs (none / punch / printer).
Now from the computers perspective the devices are:
1. 8 sense switches
2. card reader / typewriter
3. card punch / line printer
4. display
and this works fine because the card and tty interfaces are the same
…and the sense switches get read as a binary number,
- [ ] TODO: commit current readme, then…
- [ ] TODO: update readme with this design
## Mainframe peripherals: give them their own bus?
Should the DEV (IO device select) operation work over the address and data buses, or should it have its own?
…I guess I need a better understanding of what DEV really does.
OK I think that “DEV xx”:
- copies xx to the Device ID register
and then “OUT addr”
- copies the Device ID to the data bus
- copies addr to the address bus
- disconnects the data bus from memory, and connects the data bus to … ?
- some multiplexer? decoder? thing?
- (“disconnects” just means doesnt send memory its chip-enable signal i guess)
- disconnects data bus from mem / connects it to IO device
- sends IO device its chip-enable signal
- ?? … IO device writes directly to memory
OR theres a new register, IO buffer, and CPU handles the write to memory…
but then how does card input work?
perhaps:
- when card reader receives a read signal, it feeds in a card, then reads it into an internal buffer…
OK this is too complicated, lets give up and redesign based on the IBM 701
## Mainframe peripherals: new new interface
now weve got
- registers:
- “IOD” - 2 bits - address of current I/O device
- ~~“BUF” io buffer~~
- operations:
- DEV did — io start
- INP # — read 1 byte into memory
- INP ind
- OUT # — write 1 byte from memory
- OUT ind
- FED — feed / end of record / newline
it works like this
- “DEV” selects the IO device
- loads device id into IOD register
- “INP addr” …
1. cpu sends io device an input request
- ?? details TBD... first idea:
- there are 2 "IODS" ("IO device select") pins on the CPU
- there are "/RD" and "/WR" pins on the CPU
- there's a "M/IO" pin on the CPU, which indicates whether to read/write from memory or from IO
- cpu signals IO device by...
1. copying contents of IOD to the IODS pins
2. pulling M/IO low
3. pulling RD high
2. io device checks its internal buffer… if its empty, it reads the next unit (card / line) into the buffer
3. io device shifts a byte from the buffer to the data(?) bus
4. cpu copies addr to the address bus
5. cpu sends memory-write signal
- “OUT addr”
- cpu copies byte from addr to data bus
- cpu signals io device
- io device reads from data bus
- … io device does output
- … if io device is at end of line/card/etc, if does a line/card feed
- “FED”
1. cpu signals io device to feed
- TODO TBC: use a "IOE"
2. io device feeds
_! what i dont understand is how the 701 signals the end of a record/card/line — or how I should do that_
- → ok it seems like the 701 has a control line that the card reader uses to signal the end of a card
- also it halts the computer when it runs out of cards… is that good?
- I think so...
(the timing might be tricky here. it might be better to have the io device buffer the data as soon as it is selected. or maybe its even more complicated than that.)
## CPU connections
- [ ] TODO: need pins for memory access — RW (signal which you want) and ME(?) (when this is high, memory performs the r/w on the rising edge of the next clock… or sth like that)
Some relevant parts of the 8086 pinout:
- M/IO — O — distinguish between memory and IO operations: IO is high, M is low
- /WR — O — write signal — write to memory or to output device, depending on state of M/IO
- /RD — O — indicates that the processor is performing a memory or IO read cycle, depending on state of M/IO
- READY — I — acknowledgement from memory/IO that it will complete the data transfer
## Architecture idea: core + extensions
it might make sense to think in terms of something like the RISC V standards, where you the architecture is split into a mandatory core + optional extensions
1. core computational operations — ie, the original set of 16 operations
2. additional arithmetic operations — mul, div, rotates
3. additional IO operations — dev, inp, out (ie the mainframe-style IO that im working on today)
then
- the basic microprocessor trainer would implement just the core computational ops
- (an extended microprocessor trainer could implement the core ops + the arithmetic extension)
- the mainframe would implement core + arithmetic extension + IO extension
(i _think_ that a system with the core ops + arithmetic & bitwise extensions could implement all of the mainframe IO in software, so an extended microprocessor trainer could be source compatible with the mainframe…)
the extensions could also be broken down differently:
1. core computational ops
2. arithmetic extension: multiplication and division
3. control flow extension: jump less than / greater than
4. bitwise arithmetic extension: asl, asr, rrl, rrr… plus maybe AND, OR, XOR, NOT
- [x] TODO: i think these all only work on the accumulator?
? would that make the ISA feel tidier?
- [x] TODO: try that
- [x] ? TODO: in readme, rename “arl” and “arr” to “asl” and “asr”
## Sense switches + status register — oops, this still needs rethinking
give the device number its own register
then change the status register layout to
```ssss ffff``` — 4 sense switches, 4 flags
the switches can be read like flags (ie with JFL)
```
s4 s3 s2 s1 o n z c
80 40 20 10 08 04 02 01
```
(just remember that you cant use FTG on the switches…)
## IBM 701
https://mrochkind.com/new/701/Programming-the-IBM-701-2.pdf
> The emulator doesnt have a reader that can read real cards, so, instead, binary cards are in a file with a “.deck” suffix that contains a sequence of binary words, each corresponding to a word on the card. One card follows another in the file, so the first 24 words are card 1, the next 24 are card 2, and so on.
## Keypunch & terminal history
Q: were there any teletype-style terminals with integrated card punching?
The Teletype ASR33 (and others) had paper tape, but I don't know if any could do cards...
https://en.wikipedia.org/wiki/Keypunch:
> **IBM 129 Card Data Recorder**
>
> Introduced with the System/370 in 1971, the IBM 129 was capable of punching, verifying, and <mark>use as an auxiliary, on line, 80 column card reader/punch for some computers</mark>. A switch on the keyboard console provided the ability to toggle between the punch and verify modes.
- but it doesn't have a printer
https://en.wikipedia.org/wiki/IBM_1050
> The 1050 system could include the following devices:
> - IBM 1051 Central Control Unit
> - IBM 1052 <mark>Printer-Keyboard</mark>
> - IBM 1053 Console Printer
> - IBM 1054 Paper Tape Reader
> - IBM 1055 Paper Tape Punch
> - IBM 1056 <mark>Card Reader</mark>
> - IBM 1057 <mark>Card punch</mark>
> - IBM 1058 <mark>Printing Card punch</mark>
> - IBM 1092/1093 Programmed Keyboards
https://ub.fnwi.uva.nl/computermuseum/ibm1050.html
http://bitsavers.org/pdf/ibm/360/tss/C28-2003-3_TSS360Concepts.pdf:
> Two types of terminals are available with TSS/360: the IBM 1050 Data Communication System, with an IBM 1052 Printer-Keyboard and an optional IBM 1056 Card Reader; and the IBM 2741 Communication Terminal.
>
> The IBM 1050 data communication system is a multi-purpose terminal that can transmit and receive information to and from a central processing unit and also can be used to produce documents and cards, in the off-line mode. The IBM 1050 consists of a control unit and a keyboard printer.
- Amusing: they refer to interactive use as "Conversational Processing"
***
[What protocol do Teletypes use?](https://retrocomputing.stackexchange.com/questions/4456/what-protocol-do-teletypes-use)
## Misc. references
- Punched-card accessories: https://homepage.divms.uiowa.edu/~jones/cards/accessories/
- some real niche punch-card info: http://www.forwardlook.net/forums/forums/thread-view.asp?tid=71137&start=1
- http://jmc.stanford.edu/computing-science/timesharing.html
- https://historictech.com/product/v-rare1950s-ibm-704-salesmans-model/
> If like me you dont have the cupboard space for a full scale vintage IBM mainframe computer, then this might be the next best thing! It is also the best desk toy I have seen in years and a very rare example of its type.
## Incredible new graphics discoveries
This is full of gems: http://media.ibm1130.org/1130-012-ocr.pdf
also, do flowcharts as artworks.
<mark> TO READ http://www.bitsavers.org/pdf/ibm/generalInfo/C20-8078_Form_and_Card_Design_1961.pdf </mark>
## Punched card encoding: i understood it wrong
This is confusing, but I think:
- The pattern of punches on the cards are not "EBCDIC".
- (EBCDIC is an _8-bit character encoding_.)
- The standard pattern of punches is "Hollerith Encoding".
- From _ANSI X3.26-1980: American National Standard Hollerith Punched Card Code_:
- > The majority of cards used for these various purposes have to date been punched with Hollerith coding, which had thus acquired the status of a de facto standard.
- > For the basic 37 characters there is almost complete uniformity in the hole pattern assigned to each graphic.
- (space, digits, letters)
- So the pattern of punches on the cards are _translated into a digital character encoding when the cards are read_.
- But some translations are easier than others...and the EBCDIC character set was designed to easily map onto the existing Hollerith cards.
- From ["The Punched Card" at _quadibloc](http://www.quadibloc.com/comp/cardint.htm):
- > Before ASCII became the standard, many of the internal codes used to represent characters within computers were strongly influenced by the punched card code for characters. One of the most famous of such codes, and one that has persisted in use the longest, is, of course, EBCDIC (Extended Binary-Coded Decimal Interchange Code). The diagram below illustrates the relationship between EBCDIC and punched card code:
- http://www.quadibloc.com/comp/images/cardtabl.gif
- ...
- > Here is a chart showing the form of 8-bit ASCII currently in use, and the official punched card code for 8-bit ASCII:
- http://www.quadibloc.com/comp/images/ascpcc.gif
- Other references:
- https://homepage.divms.uiowa.edu/~jones/cards/codes.html
- https://ub.fnwi.uva.nl/computermuseum/DWcodes.html
- Interesting page on IBM's failed experiment with a smaller card: http://www.ibmsystem3.nl/hist.html

221
2023-09-25.md Normal file
View File

@ -0,0 +1,221 @@
# 2023-09-25 — Dev notes
## TODO
- [x] Notes on possible architecture extensions to add support for a 16-bit IP
- [ ] add tape drive to mainframe
- review 8080 style io ports
- works bc they have 2 operands per instruction, i think
- [ ] add notes on re-arranging extended system docs
## Networking - first bits of research
- [Bus network](https://en.m.wikipedia.org/wiki/Bus_network)
- [Econet](https://en.m.wikipedia.org/wiki/Econet)
- [Telnet](https://en.wikipedia.org/wiki/Telnet)
- [Adding a serial port to my 6502 computer Mike's Software Blog](https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer)
- uxn networking — not helpful to me, i think
- https://github.com/klardotsh/uxnyap
- https://compudanzas.net/uxn_tutorial_day_7.html
- https://hacklab.nilfm.cc/xrxs/about/
## 6502 vectors
https://www.masswerk.at/6502/6502_instruction_set.html
> System Vectors
>
> $FFFA, $FFFB ... NMI (Non-Maskable Interrupt) vector, 16-bit (LB, HB)
> $FFFC, $FFFD ... RES (Reset) vector, 16-bit (LB, HB)
> $FFFE, $FFFF ... IRQ (Interrupt Request) vector, 16-bit (LB, HB)
## Increasing addressing capacity — brainstorm
Increasing the address space would require extending the IP to 16 bits. It would also mean that you would need to be able to provide a 16 bit address when JMPing.
This could add a fair amount of complexity.
Here are a few options I can think of…
### Option 1:
- Extend the IP to 16 bits
- Add an additional addressing mode for JMP instructions, which takes the high byte from the accumulator and the low byte from memory
- Advantages:
- Maybe the simplest change?
- Downsides:
- Annoying to use
- Cant easily do an indirect JMP
### Option 2:
(this is what the 6502 does, basically)
- Extend the IP to 16 bits
- Give JMP instructions two bytes of operand
- Advantages:
- Simple programming
- Disadvantages
- Variable length instruction set (probably)
### Option 3:
- Extend the IP to 16 bits
- Give JMPs two bytes of operand
- Give _all_ operations two bytes of operand, making it possible to write “LDD addr, addr”
- no i dont like this
Aside: a few instructions already have a wasted operand byte. (NOP, HLT.) Maybe a variable length instruction set isnt so bad…? → maybe this is a question to return to, when i get around to trying to build something in a logic simulator
### Option 4:
- Add a “B” register
- ? Add instruction for “Load AB”
- JMP AB
- Advantages
- Simple enough programming
- New register might be nice
- Doesnt require any ops with 2-byte operands
- Disadvantages
- Big change
- Makes the system less simple
- Need a bunch of new B reg instructions (at least 4: LDB, STB in 2 modes)
### Option 5:
- Extend IP to 16 bits
- Extend A to 16 bits
- Keep the existing instructions — they just all work on the low byte of A now
- Add new mode for LDA and STA, to r/w two bytes, with the starting addr as the operand
- Advantages
- Simple?
- All ops still just 2 bytes
- Disadvantages
- Requires new modes, which are in short supply (and/or requires making the ISA a little less tidy)
- Maybe makes arithmetic weird
### Option 6:
- this is the same as the last one but presented a bit differently
- add a B register
- add instructions for loading and storing BA as a pair
- JMP uses BA, in direct mode
- everything else (ie, arithmetic) just works on A
- advantages
- same as above
- but arithmetic isnt weird
- disadvantages
- weird
- how do you clear B?
- i guess LDA would reset B?
### Also...
- [ ] TODO: review chip 8 instruction set
- [ ] try 1802-style opcodes... or is that essentially what I already have?
## Idea: Swap Overflow flag for "IO Error"
.
## Links: 1802
- http://t2k.wdfiles.com/local--files/membership-card/RCA1802-Instruction-Set.pdf
- ** http://bitsavers.trailing-edge.com/components/rca/cosmac/MPM-201A_User_Manual_for_the_CDP1802_COSMAC_Microprocessor_1976.pdf
## Links: 6502 history
- https://www.embeddedrelated.com/showarticle/1453.php
- https://www.team6502.org/sydney-anne-holt.html
## Docs leftovers: alternative table format for instructions
| lo ↓ / hi → | 0 (G0, M0) |
|-------------|------------|
| **0** | END |
| **1** | NOP |
| **2** | |
| **3** | |
| **4** | |
| **5** | |
| **6** | |
| **7** | |
| | |
| **8** | |
| **9** | |
| **A** | |
| **B** | |
| **C** | |
| **D** | |
| **E** | |
| **F** | |
| lo ↓ / hi → | 5 (G1, M1) | 6 (G1, M2) |
|-------------|------------|------------|
| **0** | LDA # | LDA ind |
| **1** | STO # | STO ind |
| **2** | ADD # | ADD ind |
| **3** | SUB # | SUB ind |
| **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** | JLT # | JLT # |
| **B** | JGT # | JGT # |
| **C** | NOT # | NOT # |
| **D** | AND # | AND # |
| **E** | OR # | OR # |
| **F** | XOR # | XOR # |
| lo ↓ / hi → | 9 (G2, M1) | A (G2, M2) |
|-------------|------------|------------|
| **0** | DEV # | DEV ind |
| **1** | INP # | INP ind |
| **2** | OUT # | OUT ind |
| **3** | FED | FED |
| **4** | | |
| **5** | | |
| **6** | | |
| **7** | | |
| | | |
| **8** | | |
| **9** | | |
| **A** | | |
| **B** | | |
| **C** | | |
| **D** | | |
| **E** | | |
| **F** | | |
| lo ↓ / hi → | F (G3, M3) |
|-------------|------------|
| **0** | |
| **1** | |
| **2** | |
| **3** | |
| **4** | |
| **5** | |
| **6** | |
| **7** | |
| | |
| **8** | RSL A |
| **9** | RSR A |
| **A** | ASL A |
| **B** | ASR A |
| **C** | |
| **D** | |
| **E** | |
| **F** | |

70
2023-09-26.md Normal file
View File

@ -0,0 +1,70 @@
# 2023-09-26 — Dev notes
## TODO
- [ ] Review yesterday's notes on extended addressing
- [ ] Add tape drive to mainframe
- [ ] Add notes on re-arranging extended system docs
## Start/Reset notes
Idea/observation: if the processor begins execution at $FE (say),
and instruction $00 is NOP, then after a few NOPs the instruction
pointer will overflow and execution will continue at address $00.
...which means that we can just pretend that it startts at $00,
but also have the option to add ROM at the top of memory, and have
a JMP at the top that redirects execution to somewhere else in ROM.
(This overflow behaviour is normal; see
https://stackoverflow.com/questions/26139662/program-counter-overflow)
### 6502 Start/Reset
https://www.masswerk.at/6502/6502_instruction_set.html:
> Start/Reset Operations
>
> An active-low reset line allows to hold the processor in a known disabled
state, while the system is initialized. As the reset line goes high, the
processor performs a start sequence of 7 cycles, at the end of which the
program counter (PC) is read from the address provided in the 16-bit reset
vector at $FFFC (LB-HB). Then, at the eighth cycle, the processor transfers
control by performing a JMP to the provided address.
Any other initializations are left to the thus executed program. (Notably,
instructions exist for the initialization and loading of all registers, but
for the program counter, which is provided by the reset vector at $FFFC.)
## Simulator memory management
To support ROM, I think this is the best plan:
- Create a new module that provides a "memory manager",
that contains the actual memory plus a set of annotations
indicating which parts are RAM and which are ROM
- When instantiating the CPU, the simulator provides it with
an instance of the memory manager
- The memory manager has a `.write(startingAddress, bytes)` method
— and it just does nothing when the address is in ROM
- (The memory manager might also need to provide some way of
attaching memory-mapped peripherals...)
## Changes to Microprocessor Trainer keypad IO ?
I think the DMA plan for the display is fine,
because probably the display controller can just tap into
the same address and read-signal lines as the main memory.
...but the keypad input is maybe trickier to do by DMA?
It could be done by cycle stealing.
(Or it could be done by halting the processor, writing to memory,
and then resuming... but that's a bad plan for the keypad.)
It seems like it would be simple enough, though, to use the
new IO system I've been planning for the mainframe version--
an `INP` could just enable the keypad to dump its current state
directly onto the bus.
- [ ] TODO: think a bit about how the INP/OUT commands would work electrically

11
2023-09-27.md Normal file
View File

@ -0,0 +1,11 @@
# 2023-09-27 — Dev notes
- Add `REW` rewind instruction for tape control?
- (and `BSP` 'backspace'?)
IBM 701 halts the machine and lights a 'checko
IBM 701 (24-6042-1_701_PrincOps.pdf):
If a copy instruction is given when there is no read-write component connected to the computing unit (e.g., fi nO READ Or WRITE instruction has been given, or fi a coPY has been given too late), the cal-
culator stops and a copy-check light turns on, indi- cating an error in the program.

107
2023-09-28.md Normal file
View File

@ -0,0 +1,107 @@
# 2023-09-28 — Dev notes
https://stackoverflow.com/questions/3215878/what-are-in-out-instructions-in-x86-used-for#3215958
https://wiki.osdev.org/ATA_PIO_Mode
> The disk that was selected last (by the BIOS, during boot) is supposed to maintain control of the electrical values on each IDE bus. If there is no disk connected to the bus at all, then the electrical values on the bus will all go "high" (to +5 volts). A computer will read this as an 0xFF byte -- this is a condition called a "floating" bus. This is an excellent way to find out if there are no drives on a bus. Before sending any data to the IO ports, read the Regular Status byte. The value 0xFF is an illegal status value, and indicates that the bus has no drives.
> …
> Measuring "float" is a shortcut for detecting that drives do not exist. Reading a non-0xFF value is not completely definitive. The definitive test for detecting drives is the #IDENTIFY command.
> Status Register (I/O base + 7)
| Bit | Abbreviation | Function |
|-----|--------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| 0 | ERR | Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset). |
| 1 | IDX | Index. Always set to zero. |
| 2 | CORR | Corrected data. Always set to zero. |
| 3 | DRQ | Set when the drive has PIO data to transfer, or is ready to accept PIO data. |
| 4 | SRV | Overlapped Mode Service Request. |
| 5 | DF | Drive Fault Error (does not set ERR). |
| 6 | RDY | Bit is clear when drive is spun down, or after an error. Set otherwise. |
| 7 | BSY | Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset. |
https://www.sci.muni.cz/docs/pc/serport.txt
> Q. Why does my PC have a 25pin/9pin connector if there are only 3 lines
needed?
A. There are several status lines that are only used with modems etc. See the
Hardware section and the Registers section of this file.
http://inputoutput5822.weebly.com/programmed-io.html
! https://industrial-electronics.com/DAQ/comp-archi_16.html
> It may seem that writing software to perform programmed I/O is trivial: a program merely assigns a value to an address on the bus. To understand I/O programming, however, we need to remember two things. First, a nonintelligent device cannot remember a list of commands. Instead, circuits in the device perform each command precisely when the processor sends the command. Second, a processor operates much faster than an I/O device - even a slow processor can execute thousands of instructions in the time it takes for a motor or mechanical actuator to move a physical mechanism.
> …
> To prevent problems, programmed I/O relies on synchronization. That is, once it issues a command, the processor must interact with the device to wait until the device is ready for another command.
> We use the term Control and Status Registers (CSRs) to refer to the set of ad dresses that a device uses. More specifically, a control register corresponds to a contiguous set of addresses (usually the size of an integer) that respond to a store operation, and a status register corresponds to a contiguous set of addresses that respond to a fetch operation.
! https://en.wikipedia.org/wiki/History_of_computing_hardware_(1960s%E2%80%93present)
https://en.wikipedia.org/wiki/CDC_6600
> The CP had no instructions for input and output, which are accomplished through Peripheral Processors (below).
CDC 6600 Simulation Model
- has ISA details
http://www.quadibloc.com/comp/cp0301.htm
https://detreville.substack.com/p/the-ibm-701
!!! https://amturing.acm.org/Buchholz_102636426.pdf
!! https://www.cambridgescholars.com/resources/pdfs/978-1-5275-0650-3-sample.pdf
> [OCR from screenshot:]
>
> The I/O system implemented five functions for using an I/O device:
>
> 1. Selecting an I/O unit for reading, writing, or a control operation, such as rewinding a tape on a magnetic tape drive.
>
> 2. Interlocking the selected I/O unit's operation with the execution of a program.
>
> 3. Copying data to/from the electrostatic storage unit and the I/0 units.
>
> 4. Synchronizing signals between the selected I/O unit and the CPU.
>
> 5. Disconnecting the I/O unit from control by the computer system its operation was completed.
>
> Because the IBM 701 could continue to execute a program after it had selected an I/O unit, an interlock was implemented that "remembered" that the I/O unit had been selected for reading or writing. When the program encountered another select instruction, its execution was delayed until the operation on the previously selected I/O unit was completed. Information transferred to or from an I/O unit was always routed through the MQ register. These transfers occurred one word at a time and required the execution of a copy instruction on each transfer.
>
> When a selected I/O unit was ready to transfer data, the program had to arrive at a copy instruction in order to perform the transfer. If no copy instruction was available, because the program had not reached the appropriate address, the I/O was disconnected from the computer and the interlock was turned off to prevent any information transfer.
***
https://retrocomputing.stackexchange.com/questions/27756/how-late-were-80-column-punched-cards-relevant
https://homepage.divms.uiowa.edu/~jones/cards/collection/i-ballot.html
https://verifiedvoting.org/election-system/ess-votomatic/
https://retrocomputing.stackexchange.com/questions/19686/how-were-card-sequence-numbers-typically-checked
https://en.m.wikipedia.org/wiki/IBM_1401
> Some operations use specific memory locations (those locations are not reserved and can be used for other purposes). Read a card stores the 80 columns of data from a card into memory locations 001080. Index registers 1, 2 and 3 are in memory locations 087089, 092-094 and 097-099 respectively. Punch a card punches the contents of memory locations 101-180 into a card. Write a line prints the contents of memory locations 201332.
https://www.multicians.org/thvv/1401s.html
http://www.righto.com/2021/02/an-ibm-1401-mainframe-computer-at.html?m=1

7
2023-09-29.md Normal file
View File

@ -0,0 +1,7 @@
# 2023-09-29 — Dev notes
## Games that teach assembly (and related material)
- [PROJEKT: OVERFLOW: RISC-V assembly board game](https://punkx.org/overflow/)
- [comments on Hacker News](https://news.ycombinator.com/item?id=37704760)
- [Machine Code is for Kids!](https://www.gamesindustry.biz/machine-code-is-for-kids-article) ("Dylan Cuthbert on why machine code is perfect for kids to learn programming")

28
2023-09-30.md Normal file
View File

@ -0,0 +1,28 @@
# 2023-09-30 — Dev notes
## ipad cardiograph links - 2023-09-30ish
### Toy RISC machines
- [GitHub - meetdoshi90/8-Bit-RISC-Microprocessor: An 8-bit RISC based processor designed in verilog with x86 instructions.](https://github.com/meetdoshi90/8-Bit-RISC-Microprocessor)
- [GitHub - olofk/serv: SERV - The SErial RISC-V CPU](https://github.com/olofk/serv)
- [GitHub - NayanaBannur/8-bit-RISC-Processor: A Verilog RTL model of a simple 8-bit RISC processor](https://github.com/NayanaBannur/8-bit-RISC-Processor)
- [GitHub - NayanaBannur/8-bit-RISC-Processor: A Verilog RTL model of a simple 8-bit RISC processor](https://github.com/TeamCM/Atom-Fluorine)
- [GitHub - AnkurRyder/8085-Processor: 8-bit RISC Processor on Logisim](https://github.com/AnkurRyder/8085-Processor)
- [natalius_8bit_risc/doc/Natalius 8 bit RISC Processor.pdf at master · freecores/natalius_8bit_risc · GitHub](https://github.com/freecores/natalius_8bit_risc/blob/master/doc/Natalius%208%20bit%20RISC%20Processor.pdf)
- [Amber 2 Core Specification](https://opencores.org/websvn/filedetails?repname=amber&path=%2Famber%2Ftrunk%2Fdoc%2Famber-core.pdf#page14) (PDF)
### MIPS
- [GitHub - GabrielGiurgica/8-bit-MIPS-Processor: A Verilog implementation of an 8-bit MIPS processor](https://github.com/GabrielGiurgica/8-bit-MIPS-Processor0
- [MIPS Reference Sheet](https://uweb.engr.arizona.edu/~ece369/Resources/spim/MIPSReference.pdf#page14)
- [MIPS Assembly/Instruction Formats](https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats)
- [GitHub - exallium/pyvm: 8-bit RISC Assembler and VM](https://github.com/exallium/pyvm)
### Assemblers
- [Simple 8-bit Assembler Simulator](https://schweigi.github.io/assembler-simulator/)
- [Make your own Assembler simulator in JavaScript (Part 1)](https://www.mschweighauser.com/make-your-own-assembler-simulator-in-javascript-part1/)
- [Simple 8-bit Assembler - Instruction Set Help](https://schweigi.github.io/assembler-simulator/instruction-set.html)

25
2023-10-01.md Normal file
View File

@ -0,0 +1,25 @@
# 2023-10-01 — Dev notes
i like the compare and branch setup here: https://schweigi.github.io/assembler-simulator/instruction-set.html
## A very incomplete survey of 8-bit RISC machines
- https://github.com/NayanaBannur/8-bit-RISC-Processor
- https://kevinpt.github.io/opbasm/rst/tutorial.html
- https://www.allaboutcircuits.com/ip-cores/processor/open8-urisc/
- https://opencores.org/projects/natalius_8bit_risc
- https://hackaday.io/project/28042-phx8-homebrew-8bit-risc-cpu
- https://shubham1172.github.io/SRM/
## Simple-As-Possible computer
- [Simple-As-Possible computer - Wikipedia](https://en.wikipedia.org/wiki/Simple-As-Possible_computer)
- http://aserrano.es/portafolio/informatica-con-processing/sap1english/
## ?? ADC
maybe swap add for adc — you can always manually zero the flag
## flags
i do wonder if they should be done in a more conventional way

11
2023-10-02.md Normal file
View File

@ -0,0 +1,11 @@
# 2023-10-02 — Dev notes
[AVR Microcontrollers](https://en.wikipedia.org/wiki/AVR_microcontrollers)... from screenshot (with OCR errors):
> In the tinyAVR and megaAVR variants of the AVR architecture, the working registers are mapped in as the first 32 data memory addresses (0000<sub>16</sub>-001F<sub>16</sub>, followed by 64 I/O registers
>
> (002016-005F16). In devices with many peripherals, these registers are followed by 160 "extended I/O" registers, only accessible as memory-mapped 1/0 (006016-00FF16).
>
> Actual SRAM starts after these register sections, at address 006016 or, in devices with "extended IO" at 010016
>
> Even though there are separate addressing schemes and optimized opcodes for accessing the register file and the first 64 I/O registers, all can also be addressed and manipulated as if they were in SRAM.

29
2023-10-14.md Normal file
View File

@ -0,0 +1,29 @@
# 2023-10-14 — Dev notes
https://en.wikipedia.org/wiki/Tape-out
Comment by "Stratoscope" on ["Examining the silicon dies of the Intel 386 processor"](https://news.ycombinator.com/item?id=37886065):
> Great article as always! One nit:
>
> > ..."tapeout", when the chip data is sent on magnetic tape to the mask fabrication company.
>
> That's roughly true in a temporal sense, but it's not where the term "tapeout" comes from. They could have shipped the data on a Winchester disk, and the event would still be called tapeout.
>
> In the earlier days of printed circuit board (PCB) manufacturing, you would literally "tape out" your circuit manually with black tape on a white board, typically in an enlarged form.
>
> "Tapeout" came to mean the point in time when you finished taping out your circuit and it was ready to be sent to be photographed and reduced and boards manufactured from the layout.
>
> There wasn't even any "data" involved here, magnetic or otherwise. Just a physical art board with tape on it.
>
> Wikipedia has a pretty good article on this:
>
> https://en.wikipedia.org/wiki/Tape-out
>
> And for the young'uns who are wondering "what the heck is a Winchester disk?"
>
> https://www.pcmag.com/encyclopedia/term/winchester-disk
>
> I taped out my first printed circuit board as a third-grader sometime around 1960 and shared the story here:
>
> https://news.ycombinator.com/item?id=32116169

View File

@ -0,0 +1,368 @@
# 2023-10-23 — References to process
Collected over the last several months...
- [Programmed
Inequality](https://mitpress.mit.edu/9780262535182/programmed-inequality/)
- [git.sr.ht](https://git.sr.ht/~rabbits/uxn11/blob/main/src/uxn.c)
- [Postmarks](https://motd.co/2023/09/postmarks-launch/)
- [The Social Organization of the Computer Underground (1989) \|
Hacker News](https://news.ycombinator.com/item?id=37421184)
- [XXIIVV
](https://wiki.xxiivv.com/site/adelie.html)[---](https://wiki.xxiivv.com/site/adelie.html)[
adelie](https://wiki.xxiivv.com/site/adelie.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/potato.html)[---](https://wiki.xxiivv.com/site/potato.html)[
- [XXIIVV
](https://wiki.xxiivv.com/site/journal.html)[---](https://wiki.xxiivv.com/site/journal.html)[
journal](https://wiki.xxiivv.com/site/journal.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/virtual_machines.html)[---](https://wiki.xxiivv.com/site/virtual_machines.html)[
virtual
machines](https://wiki.xxiivv.com/site/virtual_machines.html)
- [The polygons of Another
World](https://fabiensanglard.net/another_world_polygons/)
- [XXIIVV
](https://wiki.xxiivv.com/site/assembly.html)[---](https://wiki.xxiivv.com/site/assembly.html)[
assembly](https://wiki.xxiivv.com/site/assembly.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/drifblim.html)[---](https://wiki.xxiivv.com/site/drifblim.html)[
drifblim](https://wiki.xxiivv.com/site/drifblim.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/paper_computer.html)[---](https://wiki.xxiivv.com/site/paper_computer.html)[
paper computer](https://wiki.xxiivv.com/site/paper_computer.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/chip8.html)[---](https://wiki.xxiivv.com/site/chip8.html)[
chip8](https://wiki.xxiivv.com/site/chip8.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/anarchy.html)[---](https://wiki.xxiivv.com/site/anarchy.html)[
anarchy](https://wiki.xxiivv.com/site/anarchy.html)
- [That which is unique, breaks - by Simon
Sarris](https://map.simonsarris.com/p/that-which-is-unique-breaks)
- [XXIIVV
](https://wiki.xxiivv.com/site/bicycle.html)[---](https://wiki.xxiivv.com/site/bicycle.html)[
bicycle](https://wiki.xxiivv.com/site/bicycle.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/ethics.html)[---](https://wiki.xxiivv.com/site/ethics.html)[
ethics](https://wiki.xxiivv.com/site/ethics.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/interaction_nets.html)[---](https://wiki.xxiivv.com/site/interaction_nets.html)[
interaction
nets](https://wiki.xxiivv.com/site/interaction_nets.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/beetbug.html)[---](https://wiki.xxiivv.com/site/beetbug.html)[
beetbug](https://wiki.xxiivv.com/site/beetbug.html)
- [hundredrabbits/awesome-uxn: Awesome things from the
community](https://github.com/hundredrabbits/awesome-uxn)
- [uxn-impl-guide/devices.md at main
](https://github.com/DeltaF1/uxn-impl-guide/blob/main/devices.md)[·](https://github.com/DeltaF1/uxn-impl-guide/blob/main/devices.md)[
DeltaF1/uxn-impl-guide](https://github.com/DeltaF1/uxn-impl-guide/blob/main/devices.md)
- [metasyn.srht.site](https://metasyn.srht.site/learn-uxn/)
- [klardotsh/uxnyap: abstract networking for
uxn???](https://github.com/klardotsh/uxnyap)
- [Keyboard interaction on the Apple II is entirely CPU-dependent,
memory-mapped, a\... \| Hacker
News](https://news.ycombinator.com/item?id=20404825)
- [I have found an excellent programmer named Steve
Wozniac](https://tinyletter.com/jamesbowman/letters/i-have-found-an-excellent-programmer-named-steve-wozniac)
- [See also his (probably better known) 16-bit VM, Sweet 16. Published
in Byte Nove\... \| Hacker
News](https://news.ycombinator.com/item?id=20398571)
- [Write your Own Virtual
Machine](https://www.jmeiners.com/lc3-vm/#s0:1)
- [ed-thelen.org](https://ed-thelen.org/comp-hist/KnuthIBM650Appreciation.pdf)
- [MIX and MIXAL tutorial (GNU MIX Development Kit
(mdk))](https://www.gnu.org/software/mdk/manual/html_node/MIX-and-MIXAL-tutorial.html)
- [Brut Smog: Connect by Ken Garland for
- [Toy CPU Simulator by jimhall](https://jimhall.itch.io/toy-cpu)
- [How a CPU works: Bare metal C on my RISC-V toy CPU
](https://florian.noeding.com/posts/risc-v-toy-cpu/cpu-from-scratch/)[·](https://florian.noeding.com/posts/risc-v-toy-cpu/cpu-from-scratch/)[
Florian Noeding\'s
blog](https://florian.noeding.com/posts/risc-v-toy-cpu/cpu-from-scratch/)
- [FOSDEM 23: Learn 8-bit machine language with the Toy CPU emulator
\| Hacker News](https://news.ycombinator.com/item?id=34658206)
- [Call gate (Intel) -
Wikipedia](https://en.m.wikipedia.org/wiki/Call_gate_(Intel))
- [Lecture 9: Interrupts -
YouTube](https://m.youtube.com/watch?v=uFBNf7F3l60&pp=ygUOY3B1IGludGVycnVwdHM%3D)
- [Turing Complete - The What, Why, And How of the Intel 8008 -
YouTube](https://m.youtube.com/watch?v=21bQBCfMDb8)
- [I designed my own 8-bit computer just to play PONG -
YouTube](https://m.youtube.com/watch?v=7A1SzIIKMho)
- [Elmer and Elsie (robots) -
Wikipedia](https://en.m.wikipedia.org/wiki/Elmer_and_Elsie_(robots))
- [bbn-logo/BBN-Report-1889.pdf at master
](https://github.com/PDP-10/bbn-logo/blob/master/BBN-Report-1889.pdf)[·](https://github.com/PDP-10/bbn-logo/blob/master/BBN-Report-1889.pdf)[
PDP-10/bbn-logo](https://github.com/PDP-10/bbn-logo/blob/master/BBN-Report-1889.pdf)
- [its-vault/files/aplogo/usage.doc at master
](https://github.com/PDP-10/its-vault/blob/master/files/aplogo/usage.doc)[·](https://github.com/PDP-10/its-vault/blob/master/files/aplogo/usage.doc)[
PDP-10/its-vault](https://github.com/PDP-10/its-vault/blob/master/files/aplogo/usage.doc)
- [Systems Network Architecture -
Wikipedia](https://en.m.wikipedia.org/wiki/Systems_Network_Architecture)
- [STANDARD ST.7/A: 8-UP APERTURE CARD MICROFORM](https://www.wipo.int/export/sites/www/standards/en/pdf/03-07-a.pdf)
- [Aperture Card Stowage -
Varivane](https://www.varivane.com/product/aperture-card-stowage)
- [ISO 6342:2003 - Micrographics
](https://www.iso.org/standard/35521.html)[---](https://www.iso.org/standard/35521.html)[
Aperture cards
](https://www.iso.org/standard/35521.html)[---](https://www.iso.org/standard/35521.html)[
Method of measuring thickness of buildup
area](https://www.iso.org/standard/35521.html)
- [Criticalcommons.org -
Media](https://criticalcommons.org/Members/ccManager/clips/a-computer-threatens-to-disrupt-the-workplace-in/view)
- [IBM System/360 Model 67 \| Hacker
News](https://news.ycombinator.com/item?id=10098998)
- [BOOLR
](https://news.ycombinator.com/item?id=37492266)[--](https://news.ycombinator.com/item?id=37492266)[
A digital logic simulator \| Hacker
News](https://news.ycombinator.com/item?id=37492266)
- [The IBM System 360 Model 30](https://www.ljw.me.uk/ibm360/)
- [bitsavers.org](http://www.bitsavers.org/pdf/ibm/360/systemSummary/A22-6810-0_360sysSummary64.pdf)
- [Amazon.com: IBM\'s 360 and Early 370 Systems (History of
Computing): 9780262517201: Pugh, Emerson W., Johnson, Lyle R.,
Palmer, John H., Aspray, William:
Books](https://www.amazon.com/IBMs-Early-Systems-History-Computing/dp/0262517205/ref=as_li_ss_tl?ie=UTF8&qid=1549954895&sr=8-1&keywords=ibm%27s+360&linkCode=sl1&tag=rightocom&linkId=22fc11819a055cdec53fe11d8def11db&language=en_US)
- [bitsavers.trailing-edge.com](http://bitsavers.trailing-edge.com/pdf/ibm/360/princOps/A22-6821-0_360PrincOps.pdf)
- [The Hercules System/370, ESA/390, and z/Architecture
Emulator](http://www.hercules-390.eu/)
- [Case Study: IBM\'s System/360-370 Architecture (1987) \[pdf\] \|
Hacker News](https://news.ycombinator.com/item?id=19593677)
- [Paper Punching Machine Looks Like Cute Piece Of Computer History
Past \|
Hackaday](https://hackaday.com/2023/09/13/paper-punching-machine-looks-like-cute-piece-of-computer-history-past/#more-615327)
- [Index of /pdf/roytron](http://bitsavers.org/pdf/roytron/)
- [PDP-11/10 running paper tape BASIC using a high speed reader /
punch - YouTube](https://m.youtube.com/watch?v=lLNLYwdzyHo)
- [Pineapple: 32-bit RISC-V CPU that you can make at home -
YouTube](https://m.youtube.com/watch?v=KzSaFFpBPDM)
- [pineapple-one/hardware-eagle: Hardware design files in Autodesk
Eagle](https://github.com/pineapple-one/hardware-eagle)
- [Slu4 - YouTube](https://www.youtube.com/@slu467)
- [I Made a 32-bit Computer Inside Terraria -
YouTube](https://m.youtube.com/watch?v=zXPiqk0-zDY)
- [The Forth Deck - A portable Forth computer with a discrete
CPU](http://mynor.org/my4th_forthdeck.htm)
- [computerhistory.org](https://www.computerhistory.org/pdp-1/_media/pdf/dec.pdp-1.bell.pdp-1_IO_interface_F-25.1960.102630357.pdf)
- [input devices - What were the main uses of the large CRT and light
pen on early PDP computers? - Retrocomputing Stack
Exchange](https://retrocomputing.stackexchange.com/questions/8493/what-were-the-main-uses-of-the-large-crt-and-light-pen-on-early-pdp-computers)
- [MIR (computer) -
Wikipedia](https://en.m.wikipedia.org/wiki/MIR_(computer))
- [beflix bell labs -
YouTube](https://m.youtube.com/results?sp=mAEA&search_query=beflix+bell+labs)
- [AT&T Archives: Seeing the Digital Future (1961) -
YouTube](https://m.youtube.com/watch?v=avHo0-qU8xo)
- [first ever 3d animation (40 year old 3d computer graphics
pixar 1972) - YouTube](https://m.youtube.com/watch?v=T5seU-5U0ms)
- [1963 Rare IBM Film: \"The Big Switch\" and 1410 Data Processing
System, Computer Network Automation -
YouTube](https://m.youtube.com/watch?v=irPw9oyAju8)
- [UNIX: Making Computers Easier To Use \-- AT&T Archives film from
1982, Bell Laboratories -
YouTube](https://m.youtube.com/watch?v=XvDZLjaCJuw&pp=ygUPYmZsaXggYmVsbCBsYWJz)
- [Part 1 - Training Video for Bell Labs\' Holmdel Computing Center -
AT&T Archives -
YouTube](https://m.youtube.com/watch?v=HMYiktO0D64&pp=ygUPYmZsaXggYmVsbCBsYWJz)
- [Before Pixar, There Was Bell Labs \| Flashback \| History -
YouTube](https://m.youtube.com/watch?v=OnCw0HNnY3E&pp=ygUPYmZsaXggYmVsbCBsYWJz)
- [Early 3D Computer Graphics From Bell Labs - AT&T Archives -
YouTube](https://m.youtube.com/watch?v=M4nql28E_AE&pp=ygUPYmZsaXggYmVsbCBsYWJz)
- [Episode 88 - BEFLIX, Early Digital Animation -
YouTube](https://m.youtube.com/watch?v=IL7dsFtauN4&pp=ygUPYmZsaXggYmVsbCBsYWJz)
- [A computer technique for producing animated movies \| Proceedings
of the April 21-23, 1964, spring joint computer
conference](https://dl.acm.org/doi/10.1145/1464122.1464130)
- [Stromberg-Carlson -
Wikipedia](https://en.m.wikipedia.org/wiki/Stromberg-Carlson#SC4020_Microfilm_Printer_.26_Plotter)
- [BEFLIX \| PPT](https://www.slideshare.net/LegalizeAdulthood/beflix)
- [How Computer-Generated Animations Were Made, Circa 1964 - AT&T
Archives - YouTube](https://m.youtube.com/watch?v=_Lmi6cmrq0w)
- [dl.acm.org](https://dl.acm.org/doi/pdf/10.1145/1464122.1464130)
- [Computing History Hub \| Hacker
News](https://news.ycombinator.com/item?id=37609914)
- [amiga-news.de - Game: ASM - Das Computer-Spiel (The Director\'s
Cut) released
(German)](https://www.amiga-news.de/en/news/AN-2023-09-00044-EN.html)
- [ASM - Das Computer-Spiel (The Director\'s Cut) (German version),
Amiga
Onlineshop](https://www.amigashop.org/product_info.php?products_id=386)
- [ASM - Das Computer-Spiel](https://www.asm-das-spiel.de/)
- [How to build a computer using origami - by Richard
Green](https://apieceofthepi.substack.com/p/how-to-build-a-computer-using-origami)
- [PDP-8 architecture - Computer History
Wiki](https://gunkies.org/wiki/PDP-8_architecture)
- [Another Real Machine: The DEC
PDP-8](http://www.quadibloc.com/comp/cp0306.htm)
- [6502.org
](http://forum.6502.org/viewtopic.php?t=939)[•](http://forum.6502.org/viewtopic.php?t=939)[
View topic - dma and
6502](http://forum.6502.org/viewtopic.php?t=939)
- [6502.org: Build Your Own
KIM-1](http://www.6502.org/trainers/buildkim/buildkim.htm)
- [Kim Uno - A 6502 Kim-1 Computer On
Arduino](https://www.electromaker.io/project/view/kim-uno-a-6502-kim-1-computer-on-arduino)
- [PAL-1 - A MOS 6502 powered Computer Kit from KJXZZ on
Tindie](https://www.tindie.com/products/tkoak/pal-1-a-mos-6502-powered-computer-kit/)
- [1958 IBM 709
](https://storagesystemshistory.wordpress.com/2021/05/31/1958-ibm-709-first-use-of-dma/)[--](https://storagesystemshistory.wordpress.com/2021/05/31/1958-ibm-709-first-use-of-dma/)[
First Use of DMA
](https://storagesystemshistory.wordpress.com/2021/05/31/1958-ibm-709-first-use-of-dma/)[--](https://storagesystemshistory.wordpress.com/2021/05/31/1958-ibm-709-first-use-of-dma/)[
Storage Systems
History](https://storagesystemshistory.wordpress.com/2021/05/31/1958-ibm-709-first-use-of-dma/)
- \* [I/O History \-- Mark
Smotherman](https://people.computing.clemson.edu/~mark/io_hist.html)
- [A sequencing-based taxonomy of I/0 systems and review of historical
machines \| ACM SIGARCH Computer Architecture
News](https://dl.acm.org/doi/10.1145/71302.71303)
- [History and Overview of Interrupts and Interrupt Systems \-- Mark
Smotherman](https://people.computing.clemson.edu/~mark/interrupts.html)
- [REMINISCENCES ON THE HISTORY OF TIME
SHARING](http://www-formal.stanford.edu/jmc/history/timesharing/timesharing.html)
- [Fix Point](http://cap-lore.com/Hardware/Arith.html)
- [Order of
Execution](http://cap-lore.com/Software/CalcOrder.html#7090)
- [Documenting Software Architectures: Views and Beyond: Clements,
Paul, Bachmann, Felix, Bass, Len, Garlan, David, Ivers, James,
Little, Reed, Merson, Paulo, Nord, Robert, Stafford, Judith:
9780321552686: Amazon.com:
Books](https://www.amazon.com/Documenting-Software-Architectures-Views-Beyond/dp/0321552687)
- [Speedcoding -
Wikipedia](https://en.m.wikipedia.org/wiki/Speedcoding)
- [Direct-view bistable storage tube -
Wikipedia](https://en.m.wikipedia.org/wiki/Direct-view_bistable_storage_tube)
- [Pool - Ultimate History of Video
games](https://ultimatehistoryvideogames.jimdofree.com/pool/)
- [The IBM System/360- a series of planned machines which span a wide performance range](http://gordonbell.azurewebsites.net/Computer_Structures__Readings_and_Examples/00000581.htm?from=https://research.microsoft.com/~gbell/Computer_Structures__Readings_and_Examples/00000581.htm&type=path)
- [IBM System 360, Model
30](https://www.ed-thelen.org/comp-hist/ibm-360-30.html)
- [DOS/360 Installation - IPL of Older IBM
Systems](https://sites.google.com/site/dos360install/about/ipl-of-older-ibm-systems)
- [Your Own IBM Mainframe (or Vax, Or
Cray](https://hackaday.com/2022/06/19/your-own-ibm-mainframe-or-vax-or-cray-the-easy-way/)[...](https://hackaday.com/2022/06/19/your-own-ibm-mainframe-or-vax-or-cray-the-easy-way/)[)
The Easy Way \|
Hackaday](https://hackaday.com/2022/06/19/your-own-ibm-mainframe-or-vax-or-cray-the-easy-way/)
- [IPL Process](http://hansen-family.com/mvs/IPL_Process.htm)
- [IBM Archives: 1620 Data Processing
System](https://www.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP1620.html)
- [ibm 2671 paper tape at
DuckDuckGo](https://duckduckgo.com/?q=ibm+2671+paper+tape&t=iphone&iax=images&ia=images&iai=http%3A%2F%2Fwww.computersciencelab.com%2FComputerHistory%2FHtmlHelp%2FImages2%2FKeypunch.jpg)
- [archive.computerhistory.org](https://archive.computerhistory.org/resources/access/text/2021/05/102774235-05-01-acc.pdf)
- [Photographs \| TX-2 Project](https://tx-2.github.io/photographs)
- [Development of the TX-0 at MIT -
YouTube](https://m.youtube.com/watch?v=VFl_zNBK6es&embeds_referring_euri=https%3A%2F%2Fethw.org%2F&source_ve_path=MjM4NTE&feature=emb_title)
- [Early Frontiers for Computer Creativity: TX-0 Writes a Western -
CHM](https://computerhistory.org/blog/early-frontiers-for-computer-creativity-tx-0-writes-a-western/?key=early-frontiers-for-computer-creativity-tx-0-writes-a-western)
- [The Hercules System/370, ESA/390, and z/Architecture
Emulator](http://www.hercules-390.org/)
- [A fundamental introduction to x86 assembly
programming](https://www.nayuki.io/page/a-fundamental-introduction-to-x86-assembly-programming)
- [Network topology -
Wikipedia](https://en.m.wikipedia.org/wiki/Network_topology)
- [IBM Network Control Program -
Wikipedia](https://en.m.wikipedia.org/wiki/IBM_Network_Control_Program)
- [IBM 3745 - Wikipedia](https://en.m.wikipedia.org/wiki/IBM_3745)
- [DECnet - Wikipedia](https://en.m.wikipedia.org/wiki/DECnet)
- [Development of the MOS Technology 6502: A Historical Perspective -
Jason Sachs](https://www.embeddedrelated.com/showarticle/1453.php)
- [Programmed and Interrupt Driven
I/O](https://industrial-electronics.com/DAQ/comp-archi_16.html)
- [Comparison of Univac with IBM 701 : Goldfinger, Roy : Free
Download, Borrow, and Streaming : Internet
Archive](https://archive.org/details/comparisonofuniv00gold/page/n1/mode/2up)
- [The IBM 701](http://www.columbia.edu/cu/computinghistory/701.html)
- [Organization Sketch of IBM Stretch \-- Mark
Smotherman](https://people.computing.clemson.edu/~mark/stretch.html)
- [1401Restoration-CHM](https://ibm-1401.info/index.html)
- [Four California Crazy guys go to Conroe Texas.wmv -
YouTube](https://m.youtube.com/watch?v=pxCZ35y3O04)
- [IBM 1401 - Wikipedia](https://en.m.wikipedia.org/wiki/IBM_1401)
- [Multics](https://www.multicians.org/multics.html)
- [1401rcdf.gif
785](https://www.multicians.org/thvv/vvimg/1401rcdf.gif)[×](https://www.multicians.org/thvv/vvimg/1401rcdf.gif)[563
pixels](https://www.multicians.org/thvv/vvimg/1401rcdf.gif)
- [1401rcdb.gif
785](https://www.multicians.org/thvv/vvimg/1401rcdb.gif)[×](https://www.multicians.org/thvv/vvimg/1401rcdb.gif)[579
pixels](https://www.multicians.org/thvv/vvimg/1401rcdb.gif)
- [Simulating the IBM 360/50 mainframe from its
microcode](http://www.righto.com/2022/01/ibm360model50.html?m=0)
- [IBM, sonic delay lines, and the history of the
80](http://www.righto.com/2019/11/ibm-sonic-delay-lines-and-history-of.html?m=0)[×](http://www.righto.com/2019/11/ibm-sonic-delay-lines-and-history-of.html?m=0)[24
display](http://www.righto.com/2019/11/ibm-sonic-delay-lines-and-history-of.html?m=0)
- [LibrePCB \| Hacker
News](https://news.ycombinator.com/item?id=37694414)
- [MAGNETIC CORES - PART I - PROPERTIES : Department of Defense : Free
Download, Borrow, and Streaming : Internet
Archive](https://archive.org/details/gov.dod.dimoc.28374)
- [technikum29 - Plated wire
storage](https://web.archive.org/web/20110719093739/http://www.technikum29.de/en/devices/plated-wire-storage.shtm)
- [Show HN: RISC-V assembly tabletop board game (hack your opponent)
\| Hacker News](https://news.ycombinator.com/item?id=37704760)
- [\<Now Go Bang!\> Digital Video Game Firsts - Michigan Pool
(1954)](https://www.masswerk.at/nowgobang/2019/michigan-pool)
- [\<Now Go Bang!\> Raster CRT Typography (According to
DEC)](https://www.masswerk.at/nowgobang/2019/dec-crt-typography)
- [HP 2645 Terminal - Part 1: Overview and Adding New Fonts -
YouTube](https://m.youtube.com/watch?v=QikO0WOAGWI)
- [\<Now Go Bang!\> Anatomy of a Random Number
Generator](https://www.masswerk.at/nowgobang/2018/anatomy-of-an-rng)
- [mass:werk \<time-convert\>](https://www.masswerk.at/time/convert/)
- [\<Now Go Bang!\> A Modernist
Christmas](https://www.masswerk.at/nowgobang/2020/modernist-xmas)
- [\<Now Go Bang!\> Stay at Home Edition: Inside
Spacewar!](https://www.masswerk.at/nowgobang/2020/longreads-inside-spacewar)
- [masswerk.at](https://www.masswerk.at/nowgobang/misc/MINAC-IRE-March-1957.pdf)
- [You are welcome! :-) Regarding the PDP-8, have a look into
\"Computer Engineering\... \| Hacker
News](https://news.ycombinator.com/item?id=20488547)
- [All-magnetic logic computer - SRI
International](https://www.sri.com/hoi/all-magnetic-logic-computer/)
- [Wayne\'s Tinkering Page - One Bit Ferrite Core
Memory](https://sites.google.com/site/wayneholder/one-bit-ferrite-core-memory)
- [Magnetic core memory](https://www.nzeldes.com/HOC/CoreMemory.htm)
- [US2935622A - Magnetic core logic element - Google
Patents](https://patents.google.com/patent/US2935622A/en)
- [Magnetic Logic - Forgotten Technology -
YouTube](https://m.youtube.com/watch?v=p7SkE5pERtA&embeds_referring_euri=http%3A%2F%2Fdangerousprototypes.com%2F&source_ve_path=MjM4NTE&feature=emb_title)
- [How flip-flops are implemented in the Intel 8086 processor \|
Hacker News](https://news.ycombinator.com/item?id=37716910)
- [efi.com](https://www.efi.com/library/efi/documents/385/efi_fiery_wof_color_3key_steps_fq_en_us.pdf)
- [Building Processors from the Ground Up \| Hacker
News](https://news.ycombinator.com/item?id=37714395)
- [stnolting/neo430: :computer: A damn small msp430-compatible
customizable soft-core microcontroller-like processor system written
in platform-independent VHDL.](https://github.com/stnolting/neo430)
- [stnolting/neorv32:
](https://github.com/stnolting/neorv32)[<5B>](https://github.com/stnolting/neorv32)[<5B>](https://github.com/stnolting/neorv32)[](https://github.com/stnolting/neorv32)[
A tiny, customizable and highly extensible MCU-class 32-bit RISC-V
soft-core CPU and microcontroller-like SoC written in
platform-independent VHDL.](https://github.com/stnolting/neorv32)
- [RISC I \| Proceedings of the 8th annual symposium on Computer
Architecture](https://dl.acm.org/doi/10.5555/800052.801895)
- [ww1.microchip.com](http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf)
- [Build an 8-bit computer \| Ben Eater](https://eater.net/8bit)
- [Simple-As-Possible Computer (SAP-1) simulator
](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[--](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[
Dr.
](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[Á](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[ngel
Serrano
S](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[á](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[nchez
de
Le](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[ó](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)[n](http://aserrano.es/portafolio/informatica-con-processing/sap1english/)
- [PicoCalc: A fully-functional clone of VisiCalc for the PICO-8 \|
Hacker News](https://news.ycombinator.com/item?id=37746663)
- [New zine: How Integers and Floats
Work](https://jvns.ca/blog/2023/06/23/new-zine--how-integers-and-floats-work/)
- [Reflecting on the Soul of a New Machine \| Hacker
News](https://news.ycombinator.com/item?id=19133653)
- [Data General
](http://www.teamfoster.com/billteamfostercom)[---](http://www.teamfoster.com/billteamfostercom)[
Teamfoster](http://www.teamfoster.com/billteamfostercom)
- [CPSC 3300 / DG Eagle MV/8000 / The Soul of a New
Machine](https://people.computing.clemson.edu/~mark/330/eagle.html)
- [XXIIVV
](https://wiki.xxiivv.com/site/uxn_devlog.html)[---](https://wiki.xxiivv.com/site/uxn_devlog.html)[
uxn devlog](https://wiki.xxiivv.com/site/uxn_devlog.html)
- [What is the Demoscene? An obscure but influential art form \|
Hacker News](https://news.ycombinator.com/item?id=37927344)
- [IBM, Apple, RISC, and the Roots of the PowerPC \| Low End
Mac](https://lowendmac.com/2014/ibm-apple-risc-and-the-roots-of-the-powerpc/)

62
2023-10-23.md Normal file
View File

@ -0,0 +1,62 @@
# 2023-10-23 — Dev notes
Without really reviewing older notes:
- I'm not sure if I'm keen on the IO setup described in the current version of the re-architecting architecture docs
- I had some ideas about extending to 16 bits?
- Add an "H" register, to be used as the high byte, in an "HA" register pair?
- Need a M/Q register? (if providing MUL and DIV)
- The 6502 doesn't have 'em... https://www.llx.com/Neil/a2/mult.html
- Nor the Z80... https://tutorials.eeems.ca/Z80ASM/part4.htm
- https://www.reddit.com/r/beneater/comments/tcb76d/unpopular_opinion_rca1802_is_the_best_beginners/
- TODO: read this more and reconsider 1802-informed IO
Some more RCA 1802 links...
- https://www.sunrise-ev.com/1802.htm
- https://groups.io/g/cosmacelf
- http://www.cosmacelf.com
- https://www.reddit.com/r/retrocomputing/comments/ufz8g2/the_rca_1802_cosmac_the_architecture_that_came/
- http://www.visual6502.org/images/pages/RCA_1802.html
- http://www.retrotechnology.com/memship/1802_spacecraft.html
## Recent links
### DCPU-16
https://gist.githubusercontent.com/metaphox/3888117/raw/588a5f1fc24a67cb14939deab588fbff29b7e2aa/DCPU-16Spec.txt
https://fail0verflow.com/blog/2012/dcpu-16-review/
failoverflows redesign: https://fail0verflow.com/media/files/dcpu16-proposal.txt
networking: https://github.com/ManuelKiessling/dcpu16-networkhub#readme
### Book
https://www.amazon.ca/Computer-Organization-Design-MIPS-Interface/dp/0124077269
## Computer Confidence: A Womans Guide
https://archive.org/details/computerconfiden0000hell/page/n5/mode/1up?view=theater
### Misc.
- http://www.quadibloc.com/comp/cardint.htm
- http://www.quadibloc.com/comp/panint.htm
- http://www.quadibloc.com/arch/arcint.htm
- http://www.quadibloc.com/comp/lineint.htm
## Z80
- https://clrhome.org/table/
## System/360 Front Panels
- http://www.righto.com/2019/04/iconic-consoles-of-ibm-system360.html?m=1
### BEFLIX
- [Using his BEFLIX Computer Animation Language, Ken Knowlton Produces "A Computer Technique for the Production of Animated Movies”](https://historyofinformation.com/detail.php?id=3467)

View File

@ -2,6 +2,10 @@
Entries in bold are especially influential to my work on this project so far.
## Other files to see
- [2023-09-03--references-to-process.md](2023-09-03--references-to-process.md)
## To-read
- https://www.drdobbs.com/embedded-systems/paper-to-fpga/240155922

View File

@ -2,24 +2,27 @@
## Open
### #1 - Improve CLI interface
### #4 - Add single stepping
I'm thinking of an interface like this...
Q: should this be part of a more complex monitor interface? See note from [2023-08-31](../2023-08-31.md#microprocessor-trainer-style-keypad)
$ ./cpu.js -mc code.bin
$ ./cpu.js code.asm
$ ./cpu.js --debug code.asm
Or, a simpler option would be to add a command line flag:
Full list of flags I want:
-d --debug
-s --singlestep
-p --prettydisplay
-mc --machinecode
(Adapted from [#1](#1---improve-cli-interface))
### #3 - Add plain-text display output
With a command line option on `cardiograph.js`:
-p, --prettydisplay
(Adapted from [#1](#1---improve-cli-interface))
### #2 - Startup: Execute `JMP $FF`
See [2023-08-24](../notes/2023-08-24--dev-notes.md#cpu-start-up)
See [2023-08-24](../notes/2023-08-24.md#cpu-start-up)
... say that there's a 1-byte ROM at $FF.
@ -43,4 +46,19 @@ More step-by-step:
- Load ROM data into memory at CPU startup (`startCPU(RAM, ROM)`)
## Closed
## Closed
### #1 - Improve CLI interface
I'm thinking of an interface like this...
$ ./cpu.js -mc code.bin
$ ./cpu.js code.asm
$ ./cpu.js --debug code.asm
Full list of flags I want:
-d --debug
-s --singlestep
-p --prettydisplay
-mc --machinecode

View File

@ -4,52 +4,26 @@ This is a quick todo list.
For extended commentary, see [issues](issues.md).
## Open
## Todo
### Todo
- Finish WIP on run-cli arg parsing
- Pass CYCLE_COUNT as a cli arg
- (cpu) !! Fix overflow flag
- Add support for single stepping (cf. [#4](issues.md#4---add-single-stepping))
- Re-build support for plain-text output (cf. [#3](issues.md#3---add-plain-text-display-output))
- Pass `defaultCycleLimit` setting as a cli arg
- Add a flag for bank-switching to the ~zero-page
- Remove run-scripts and add the ability to run `./cpu.js` and `./assembler.js` directly -- cf. [#1](issues.md#1---improve-cli-interface)
- [fix] (cpu) Make single-stepping work with simulated keypad
### Features
## Features
- (cpu) allow arrow keys, too
- [fix] (cpu) Execute `JMP $FF` on startup / Implement ROM — see [#2](issues.md#2---startup-execute-jmp-ff)
- (assembler) Validate labels
- (assembler) Extract debugging to its own module
- (cpu) Consider adding a VIP-style keypad-based machine code monitor
- (cpu) Add a mode that prints the display as text, but still animates
- (cpu) Allow running pre-compiled machine code
- (cpu) DRY out addition and subtraction
- [Extended system (secret bonus operations)](../notes/2023-08-07--dev-notes.md)
- (research) Review CHIP-8
- read about the spec / ISA
- read these, and add them to the bibliography:
- Steve Losh: https://stevelosh.com/blog/2016/12/chip8-input/
- https://tonisagrista.com/blog/2021/chip8-spec/
- (cpu) Consider adding a VIP-style keypad-based machine code monitor
- [Extended system (secret bonus operations)](../notes/2023-08-07.md)
### Documentation
## Documentation
- Improve docs for flags register
...
### Testing
## Test programs
- Display (hex) numbers
- Greater than
- Minimal LOGO-ish interpreter for turtle graphics
## Closed
- 2023-08-26 - [fix] (logging) - 'undefined operand' situation is caused by assembling to an initial IP of $1C, which is an odd number
- (assembler) Pass asm line thru to cpu to print when debugging
## Abandoned
- (assembler) Return pure machine code when printing to stdout (and not in debug mode)
- Minimal LOGO-ish interpreter for turtle graphics

View File

@ -1,18 +0,0 @@
# Dev notes — 2023-08-29
Short-term goals:
- [ ] Move notes, issues to their own branches
- [ ] Make worktrees for those branches
- NB: VS Code's git management tools work fine with worktree folders if you open them in a new window -- but opening them in a workspace doesn't work
- [ ] split into card, io, graph, all bound together in cardiograph.js
- [ ] new CLI interface
- [ ] arg parser
- [ ] assembler output on stdout
- [ ] trash run-assembler
- [ ] fix overflow flag
- [ ] implement 'jmp ($FF)' on startup
- [ ] implement ROM

175
readme.md
View File

@ -1,175 +0,0 @@
# Cardiograph Mark I — simulator for an imaginary 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```
## Registers and Flags
- `A` - accumulator
- `IP` - instruction pointer (aka program counter)
- `FLAGS` - flags: **O**verflow, **N**egative, **Z**ero, **C**arry
- in machine language, each flag is given a number:
- O = 3
N = 2
Z = 1
C = 0
- (bitwise, `0000 = ONZC`)
## 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
```
## CPU start-up
When starting up, the CPU executes a `JMP $FF`.
Put differently: it starts executing instructions at the address contained in `$FF`.
## Cardiograph memory map
- `00-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-FE` - free
- `FF ` - ROM (unwriteable) pointer to initial IP (not yet implemented)
## 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
hex pad simulator
```
The arrow keys are also mapped onto the hex keypad:
```
5 ↑
7 8 9 ← ↓ →
hex pad simulator
```
## 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
- Hexadecimal numbers are preceded by a `$`
- Whitespace is ignored

@ -1 +0,0 @@
Subproject commit 584d9dd95f4b1b3c69065826cf96b3cda0cf9e16

View File

@ -1,422 +0,0 @@
const { logMemory, num2hex } = require('./logging.js');
const {
INITIAL_IP_ADDRESS,
DISPLAY_ADDR,
POINTER_TO_DISPLAY,
} = require('./machine.config.js');
// 1 = verbose
// 2 = what i'm currently focusing on
// 3 = always print
// 4 = silent
const DEBUG_LEVEL = 2;
let DEBUG; // Turn debugging on/off -- set by assemble()
/**
* @param {string} assemblyCode
* @param {Boolean} [debug = false]
**/
exports.assemble = (assemblyCode, debug = false) => {
DEBUG = debug;
return decodeInstructions(assemblyCode);
}
// Configure pseudo-ops:
const ASM_IP_LABEL = '*';
const ASM_CONSTANT_PREFIX = '#';
const ASM_LABEL_PREFIX = '@';
const mnemonicsWithOptionalArgs = ['end', 'nop'];
const mnemonics2opcodes = {
end: { direct: 0, indirect: 0 },
sto: { direct: 1, indirect: 2 },
lda: { direct: 3, indirect: 4 },
add: { direct: 5, indirect: 6 },
sub: { direct: 7, indirect: 8 },
hop: { direct: 9, indirect: 10 },
jmp: { direct: 11, indirect: 12 },
ftg: { direct: 13, indirect: 13 },
fhp: { direct: 14, indirect: 14 },
nop: { direct: 15, indirect: 15 },
};
/**
* @typedef {('code'|'comment'|'blank')} SourceLineType
**/
/**
* @typedef {Object} SourceLineInfo
* @property {number} number - line number
* @property {string} source - source text
* @property {string} sanitized - source text, with comments and whitespace removed
* @property {SourceLineType} type - line type
* @property {string} [operation] - For code: the first non-whitespace chunk
* @property {string} [argument] - For code: the second non-whitespace chunk, if there is one
* @property {string} [extraArgument] - For code: the third non-whitespace chunk, if there is one
**/
/**
* @param {string} source
* @returns {Array<SourceLineInfo>}
**/
function preparseSourceCode(source) {
let lines = source.split(/\n/); // returns an array of lines
const isLineBlank = (l) => { return stripWhitespaceFromEnds(l).length === 0 ? true : false };
const isLineComment = (l) => { return stripWhitespaceFromEnds(l).startsWith(';') };
/**
* @param {string} l
* @returns {SourceLineType}
**/
const getLineType = (l) => {
if (isLineBlank(l)) return 'blank';
if (isLineComment(l)) return 'comment';
return 'code';
}
return lines.map((line, index) => {
dbg(1, ` in: ${line}`);
let info = {
number: index + 1,
source: line,
sanitized: stripWhitespaceFromEnds(stripComments(line)),
type: getLineType(line),
};
dbg(1, `${info.number} - ${info.type}: ${info.sanitized}`);
dbg(1, ``);
if (info.type === 'code') {
const op_arg_array = info.sanitized.split(/\s+/); // split line into an array of [op, arg, extra_arg]
if (op_arg_array[0] !== 'undefined') {
info.operation = op_arg_array[0];
}
if (op_arg_array.length === 2) {
info.argument = op_arg_array[1];
}
if (op_arg_array.length === 3) {
info.argument = op_arg_array[1];
info.extraArgument = op_arg_array[2];
}
// If there's too many arguments, throw an error
// NB. there's a special case:
// lines with the ASM_IP_LABEL can take an extra argument
let maxArgs = 2;
if (op_arg_array.length > 2 && op_arg_array[1].startsWith(ASM_IP_LABEL)) {
maxArgs = 3;
}
if (op_arg_array.length > maxArgs) {
console.error();
console.error(`Error: Too many arguments`);
console.error(` at line ${info.number}`);
process.exit();
}
}
return info;
});
}
/**
* @param {string} arg
* @returns {number}
**/
function decodeNumericOp(arg) {
if (arg.startsWith("$")) return hex2num(arg.replace("$", ""));
return parseInt(arg);
}
/**
* @param {string} op
* @param {object} labels // TODO document better
* @param {number} IP
* @returns {Array<string>} - array of labels
**/
function handleLabelDefinition(op, IP, labels) {
let label = op.substring(1); // strip label prefix
if (label in labels) {
labels[label].pointsToByte = IP;
} else {
labels[label] = {
pointsToByte: IP,
bytesToReplace: [],
};
}
dbg(1, ` Label definition:`);
dbg(1, ` Points to byte: ${labels[label].pointsToByte}`);
dbg(1, ` Bytes to replace: ${labels[label].bytesToReplace}`);
dbg(1, ` IP: $${num2hex(IP)}, new code: none`);
dbgGroupEnd(1, 'Input line');
return labels;
}
/**
* @param {string} op
* @param {string} arg
* @param {number} IP
* @returns {Array<string>} - array of constants
**/
function handleConstantDefinitions(op, arg, IP, constants) {
let constantName = op.substring(1); // strip '>'
let constantValue = arg;
if (constantValue === ASM_IP_LABEL) {
constantValue = IP.toString();
}
constants[constantName] = constantValue;
dbg(1, '');
dbg(1, `Constants:`);
dbg(1, constants);
dbg(1, '');
return constants;
}
/**
* Assemble source code.
*
* If the source doesn't explicitly set an address to assemble to,
* it will be assembled to the default intial value of the IP,
* as specified in `machine.config.js`.
* @param {string} source - Assembly source to decode
* @return {{ debugInfo: Object, machineCode: Uint8Array }};
**/
function decodeInstructions(source) {
dbg(1, 'Pre-parsing...');
let lines = preparseSourceCode(source);
dbg(1, '');
dbg(1, 'Done pre-parsing.');
dbg(1, '');
dbg(1, 'Assembling...');
// Figure out where to start assembly...
/** @type {number} IP - Destination addr for the next line **/
let IP;
// Check if the source code explicitly sets an address to assemble at
// by including a `* [addr]` as the first (non-blank, non-comment) line
let idOfFirstLineWithCode = lines.findIndex((el) => el.type === 'code');
if (lines[idOfFirstLineWithCode].operation.startsWith(ASM_IP_LABEL)) {
IP = parseInt(lines[idOfFirstLineWithCode].argument);
} else {
IP = INITIAL_IP_ADDRESS;
}
// Initialize arrays to collect assembled code
/** @type {Array<number>} - Assembled source code, as an array of bytes **/
let machineCode = new Array(IP).fill(0);
let debugInfo = {};
// Initialize memory-mapped IO -- TODO this should probably be in the CPU, not here
machineCode[POINTER_TO_DISPLAY] = DISPLAY_ADDR;
// Initialize arrays that collect code references that
// have to be revisited after our first pass through the source
let labels = {};
let constants = {};
// Decode line by line...
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
// dbg(2, `line info:`);
// dbg(2, line);
if (line.type === 'code') {
const op = line.operation;
if (typeof line.argument === 'undefined') {
// If this isn't a label definition,
// or one of the ops with optional arguments,
// then it's an error
if (!line.operation.startsWith('@')) {
if (mnemonicsWithOptionalArgs.indexOf(line.operation.toLowerCase()) < 0) {
console.error('');
console.error(`Error: Missing operand ${line.source}`);
console.error(` at line ${line.number}`);
process.exit();
} else {
// It *is* one of the special optional-arg ops
// So let's fill in the implicit operand with $00
line.argument = '0';
}
}
}
// *** Decode special operations ***
// Opcodes - Handle label definitions
if (op.startsWith(ASM_LABEL_PREFIX)) {
labels = handleLabelDefinition(op, IP, labels);
continue;
}
// Opcodes - Handle constant definitions
if (op.startsWith(ASM_CONSTANT_PREFIX)) {
constants = handleConstantDefinitions(op, line.argument, IP, constants);
continue;
}
// Opcodes - Handle setting value of IP
if (op.startsWith(ASM_IP_LABEL)) {
IP = parseInt(line.argument);
continue;
}
// *** Decode regular operations ***
/** @type {number|null} decodedOp **/
let decodedOp = null;
/** @type {number|null} decodedArg **/
let decodedArg = null;
/** @typedef {'direct'|'indirect'} AddressingMode **/
let addressingMode = 'direct';
// Now that it can't be a label or a constant, normalize the opcode
line.operation = line.operation.toLowerCase();
// Operands - Handle references to labels
if (line.argument.startsWith(ASM_LABEL_PREFIX)) {
let label = line.argument.substring(1); // strip label prefix
if (label in labels) {
dbg(1, `'${label}' already in labels object`);
labels[label].bytesToReplace.push(IP + 1);
} else {
dbg(1, `'${label}' NOT in labels object`);
labels[label] = {
bytesToReplace: [IP + 1],
};
}
dbg(1, `Label reference:`);
dbg(1, ` Points to byte: ${labels[label].pointsToByte}`);
dbg(1, ` Bytes to replace: ${labels[label].bytesToReplace}`);
decodedArg = 0; // Return 0 for operand for now -- we'll replace it later
}
// Operands - Handle references to the Instruction Pointer
if (line.argument === ASM_IP_LABEL) {
dbg(1, ` References current IP - ${IP}`);
if (typeof line.extraArgument === 'undefined') {
decodedArg = IP;
} else {
decodedArg = IP + decodeNumericOp(line.extraArgument);
}
}
// Operands - Handle references to constants
if (line.argument.startsWith(ASM_CONSTANT_PREFIX)) {
dbg(1, `References '${line.argument}'`);
if (typeof constants[line.argument.substring(1)] === 'undefined') {
console.error();
console.error(`Error: Undefined constant '${line.argument}'`);
console.error(` at line ${line.number}`);
process.exit();
}
decodedArg = decodeNumericOp(constants[line.argument.substring(1)]); // substring(1) strips '>'
}
// Operands - Handle references to constants in indirect mode
if (line.argument.startsWith(`(${ASM_CONSTANT_PREFIX}`)) {
addressingMode = "indirect";
dbg(1, `(Indirectly) References '${line.argument}'`);
let constName = line.argument.replace(`(${ASM_CONSTANT_PREFIX}`, "");
constName = constName.replace(")", "");
decodedArg = decodeNumericOp(constants[constName]);
}
// Operands - Handle indirect expressions
if (decodedArg === null && line.argument.startsWith("(")) {
addressingMode = "indirect";
let indyTemp = line.argument.replace("(", "").replace(")", "");
decodedArg = decodeNumericOp(indyTemp);
}
// Decode regular opcodes
if (decodedOp === null) {
decodedOp = mnemonics2opcodes[line.operation][addressingMode];
}
// Decode regular operands
if (decodedArg === null) {
decodedArg = decodeNumericOp(line.argument);
}
machineCode[IP] = decodedOp;
machineCode[IP + 1] = decodedArg;
debugInfo[IP] = {
lineNumber: line.number,
source: line.source,
address: IP,
machine: [decodedOp, decodedArg]
};
dbg(3, ``);
dbg(3, `Line ${line.number}: ${line.source}`);
if (line.argument) {
dbg(3, ` Asm operation: ${line.operation.toUpperCase()} ${line.argument}`);
} else if (line.operation) {
dbg(3, ` Asm operation: ${line.operation.toUpperCase()}`);
}
dbg(3, ` Machine code: $${num2hex(decodedOp)} $${num2hex(decodedArg)}`);
dbg(3, ` IP: $${num2hex(IP)}`);
IP += 2;
};
}
dbg(1, '');
dbgGroup(1, 'Memory before filling in label constants');
dbgExec(1, () => logMemory(new Uint8Array(machineCode)));
dbgGroupEnd(1);
// Backfill label references
for (let k of Object.keys(labels)) {
dbgGroup(1, `${ASM_LABEL_PREFIX}${k}`);
let label = labels[k];
dbg(1, `Points to byte: ${label.pointsToByte}`);
dbg(1, `Bytes to replace: ${label.bytesToReplace}`);
dbgGroupEnd(1);
for (let j = 0; j < label.bytesToReplace.length; j++) {
machineCode[label.bytesToReplace[j]] = label.pointsToByte;
}
}
return { 'debugInfo': debugInfo, 'machineCode': new Uint8Array(machineCode) };
}
/**
* @param {string} line
* @returns {string}
**/
function stripComments(line) {
return line.replace(/;.+/,"");
}
/**
* @param {string} line
* @returns {string}
**/
function stripWhitespaceFromEnds(line) {
line = line.replace(/^\s+/,"");
line = line.replace(/\s+$/,"");
return line;
}
function hex2num(hex) { return parseInt(hex, 16) };
// Debug helpers
const dbg = (lvl, s) => { if (DEBUG && (lvl >= DEBUG_LEVEL)) console.log(s) };
const dbgGroup = (lvl, s) => { if (DEBUG && (lvl >= DEBUG_LEVEL)) console.group(s) };
const dbgGroupEnd = (lvl, s) => { if (DEBUG && (lvl >= DEBUG_LEVEL)) console.groupEnd() };
const dbgExec = (lvl, func) => { if (DEBUG && (lvl >= DEBUG_LEVEL)) func(); }

View File

@ -1,422 +0,0 @@
const readline = require('readline');
const readlineSync = require('readline-sync');
const {
INITIAL_IP_ADDRESS,
DEFAULT_CYCLE_LIMIT,
KEYPAD_ADDR,
KEY_MAP,
} = require('./machine.config');
const {
num2hex,
bool2bit,
} = require('./logging.js');
const display = require('./display.js');
// STATE
const CPU = {
// Core state
running: false,
IP: INITIAL_IP_ADDRESS,
FLAGS: {'C': false, 'Z': false, 'N': false, 'O': false},
FLAGNUMS2NAMES: {0: 'C', 1: 'Z', 2: 'N', 3: 'O'},
Acc: 0,
memory: null,
// Functions that update core state
/** @param {Uint8Array} data */
loadMemory: (data) => {
CPU.memory = new Uint8Array(256);
CPU.memory.set(data, 0);
},
incrementIP: (offset) => {
CPU.previousIP = CPU.IP;
CPU.IP = CPU.IP + offset;
},
setIP: (address) => {
CPU.previousIP = CPU.IP;
CPU.IP = address;
},
updateFlagZero: () => { CPU.FLAGS.Z = CPU.Acc === 0; },
updateFlagNegative: () => { CPU.Acc & 128 ? CPU.FLAGS.N = true : CPU.FLAGS.N = false },
// Debug info
previousIP: 0,
currentInstruction: {
opcode: null,
operand: null,
mnemonic: null,
},
cycleCounter: 0,
}
// FUNCTIONS THAT MODIFY STATE
const Instructions = {
end: () => {
CPU.currentInstruction.mnemonic = 'END';
CPU.running = false;
CPU.incrementIP(2);
},
store_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'STO lit';
CPU.memory[lit] = CPU.Acc;
CPU.incrementIP(2);
},
store_addr: (addr) => {
CPU.currentInstruction.mnemonic = `STO addr; @addr: ${num2hex(CPU.memory[addr])}`;
CPU.memory[CPU.memory[addr]] = CPU.Acc;
CPU.incrementIP(2);
},
load_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'LDA lit';
CPU.Acc = lit;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.incrementIP(2);
},
load_addr: (addr) => {
CPU.currentInstruction.mnemonic = `LDA addr; @ addr: ${num2hex(CPU.memory[addr])}`;
CPU.Acc = CPU.memory[addr];
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.incrementIP(2);
},
add_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'ADD lit';
// Calculate sum
let sum = CPU.Acc + lit;
if (sum > 255) {
CPU.FLAGS.C = true;
sum = (sum % 255) - 1;
} else {
CPU.FLAGS.C = false;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
// FIXME FIXME FIXME
// I'm on a plane and can't remember how this works
let overflow = 0;
if (overflow) {
CPU.FLAGS.O = true;
} else {
CPU.FLAGS.O = false;
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.incrementIP(2);
},
add_addr: (addr) => {
CPU.currentInstruction.mnemonic = 'ADD addr';
// Calculate sum
let sum = CPU.Acc + CPU.memory[addr];
if (sum > 255) {
CPU.FLAGS.C = true;
sum = (sum % 255) - 1;
} else {
CPU.FLAGS.C = false;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
// FIXME FIXME FIXME
// I'm on a plane and can't remember how this works
let overflow = 0;
if (overflow) {
CPU.FLAGS.O = true;
} else {
CPU.FLAGS.O = false;
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.incrementIP(2);
},
sub_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'SUB lit';
// Calculate sum
let sum = CPU.Acc - lit;
if (sum < 0) {
CPU.FLAGS.C = true;
sum = sum + 256;
} else {
CPU.FLAGS.C = false;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
// FIXME FIXME FIXME
// I'm on a plane and can't remember how this works
let overflow = 0;
if (overflow) {
CPU.FLAGS.O = true;
} else {
CPU.FLAGS.O = false;
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.incrementIP(2);
},
sub_addr: (addr) => {
CPU.currentInstruction.mnemonic = 'SUB addr';
// Calculate sum
let sum = CPU.Acc - CPU.memory[addr];
if (sum < 0) {
CPU.FLAGS.C = true;
sum = sum + 256;
} else {
CPU.FLAGS.C = false;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
// FIXME FIXME FIXME
// I'm on a plane and can't remember how this works
let overflow = 0;
if (overflow) {
CPU.FLAGS.O = true;
} else {
CPU.FLAGS.O = false;
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.incrementIP(2);
},
hop_lit: (lit) => {
CPU.currentInstruction.mnemonic = `HOP lit; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
if (CPU.Acc === lit) {
CPU.incrementIP(4);
} else {
CPU.incrementIP(2);
}
},
hop_addr: (addr) => {
CPU.currentInstruction.mnemonic = 'HOP addr';
if (CPU.Acc === CPU.memory[addr]) {
CPU.incrementIP(4);
} else {
CPU.incrementIP(2);
}
},
jump_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'JMP lit';
CPU.setIP(lit);
},
jump_addr: (addr) => {
CPU.currentInstruction.mnemonic = 'JMP addr';
CPU.setIP(CPU.memory[addr]);
},
flag_toggle: (flagNum) => {
if (flagNum === null) {
console.error('Invalid flag number');
process.exit();
}
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
CPU.currentInstruction.mnemonic = `FTG ${flagName}`;
CPU.FLAGS[flagName] = !CPU.FLAGS[flagName];
CPU.incrementIP(2);
},
flag_hop: (flagNum) => {
if (flagNum === null) {
console.error('Invalid flag number');
process.exit();
}
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
CPU.currentInstruction.mnemonic = `FHP ${flagName}; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
if (CPU.FLAGS[CPU.FLAGNUMS2NAMES[flagNum]]) {
CPU.incrementIP(4);
} else {
CPU.incrementIP(2);
}
},
no_op: () => {
CPU.currentInstruction.mnemonic = `NOP`;
CPU.incrementIP(2);
},
}
const opcodes2mnemonics = {
0: (operand) => Instructions.end(),
1: (operand) => Instructions.store_lit(operand),
2: (operand) => Instructions.store_addr(operand),
3: (operand) => Instructions.load_lit(operand),
4: (operand) => Instructions.load_addr(operand),
5: (operand) => Instructions.add_lit(operand),
6: (operand) => Instructions.add_addr(operand),
7: (operand) => Instructions.sub_lit(operand),
8: (operand) => Instructions.sub_addr(operand),
9: (operand) => Instructions.hop_lit(operand),
10: (operand) => Instructions.hop_addr(operand),
11: (operand) => Instructions.jump_lit(operand),
12: (operand) => Instructions.jump_addr(operand),
13: (operand) => Instructions.flag_toggle(operand),
14: (operand) => Instructions.flag_hop(operand),
15: (operand) => Instructions.no_op(),
};
/**
* Load code into memory and set CPU state to "running"
* @param {Uint8Array} code - Machine code to load
**/
function startCPU(code) {
CPU.loadMemory(code);
CPU.cycleCounter = 0;
CPU.running = true;
// FIXME: This conflicts with single-stepping
// (you can single-step, but keys aren't passed
// through to the Cardiograph)
//
// -> The fix is maybe to remove readlineSync,
// and instead stash the keypress into a buffer variable.*
// Then have the stepping function check that buffer,
// and then clear the buffer, each time it runs.
//
// * If it's in the set of keys that are relevant
// to single-stepping.
// Start listening for keypresses...
readline.emitKeypressEvents(process.stdin);
if (process.stdin.setRawMode != null) {
process.stdin.setRawMode(true);
}
process.stdin.on('keypress', (str, key) => { // TODO: is it possible to turn this off again?
if (key.sequence === '\x03') process.exit();
let name = key.name.toUpperCase();
if (name in KEY_MAP) {
CPU.memory[KEYPAD_ADDR] = KEY_MAP[name];
}
});
}
/**
* Execute just the next instruction in memory
* @param {Object} debugInfo
* @param {Boolean} [debug] - Print machine status and the line of code being executed
**/
async function stepCPU(debugInfo, debug = false, prettyPrintDisplay = false) {
if (CPU.IP >= CPU.memory.length) {
console.error('HALTING - IP greater than memory size');
CPU.running = false;
process.exit();
} else {
CPU.currentInstruction.opcode = CPU.memory[CPU.IP];
CPU.currentInstruction.operand = CPU.memory[CPU.IP+1];
let executeInstruction = opcodes2mnemonics[CPU.currentInstruction.opcode];
if (typeof executeInstruction === 'undefined') {
let info = debugInfo[CPU.previousIP];
console.error();
console.error(`Error: Invalid opcode`);
console.error(` Executing $${num2hex(info.machine[0])} $${num2hex(info.machine[1])}`);
console.error(` from line ${info.lineNumber}: ${info.source}`);
process.exit();
}
executeInstruction(CPU.currentInstruction.operand);
CPU.cycleCounter += 1;
}
logCPUState(debugInfo, debug, prettyPrintDisplay);
if (DEFAULT_CYCLE_LIMIT) { // Temporary limit as a lazy way to halt infinite loops
if (CPU.cycleCounter >= DEFAULT_CYCLE_LIMIT) {
console.warn(' HALTING - reached cycle limit');
CPU.running = false;
}
}
if (!CPU.running) process.exit();
}
/**
* @param {Uint8Array} code - Machine code to run
* @param {Object} debugInfo TODO type
* @param {Boolean} [debug] - Enable/disable debugging printouts
* @param {Boolean} [singleStep]
* @param {Boolean} [prettyPrint] - Print display with black and white emoji, instead of in hex
* @param {Number} [clockSpeed] - CPU clock speed in milliseconds
**/
exports.runProgram =
(code, debugInfo, debug=false, singleStep=false, prettyPrint=false, clockSpeed=100) => {
if (singleStep) {
this.singleStepProgram(code, debugInfo, debug, prettyPrint);
} else {
startCPU(code);
// Animate the output by pausing between steps
const loop = setInterval(async () => {
stepCPU(debugInfo, debug, prettyPrint);
if (!CPU.running) {
logCPUState(debugInfo, debug, prettyPrint);
console.log('Halted');
process.exit();
}
}, clockSpeed);
}
};
/**
* @param {Uint8Array} code - Machine code to run
* @param {any} debugInfo - TODO
* @param {Boolean} [debug] - Enable/disable debugging printouts
* @param {Boolean} [prettyPrintDisplay] - Print display using black and white emoji
**/
exports.singleStepProgram = (code, debugInfo, debug = false, prettyPrintDisplay = false) => {
startCPU(code);
while (CPU.running) {
stepCPU(debugInfo, debug, prettyPrintDisplay);
// FIXME: this prevents exiting with Ctrl+C:
let key = readlineSync.keyIn('S to step, Q to quit > ', {
limit: ['s', 'S', 'q', 'Q'],
});
if (key.toLowerCase() === 'q') { process.exit(); }
console.log();
}
}
// FUNCTIONS THAT PULL INFO FROM STATE TO DISPLAY
/**
* @param {Boolean} [debug] - Enable/disable debugging printouts
**/
function logCPUState(debugInfo, debug = false, prettyPrintDisplay = false) {
debugInfo = debugInfo[CPU.previousIP] !== 'undefined' ? debugInfo[CPU.previousIP] : false;
console.group(`Step ${CPU.cycleCounter}`);
console.log();
if (!debug) console.clear();
display.show(CPU.memory, prettyPrintDisplay);
console.log();
if (debugInfo) {
console.log(`Line ${debugInfo.lineNumber}: ${debugInfo.source}`);
console.log();
}
console.log('Mnemonic:', CPU.currentInstruction.mnemonic);
console.log(`Machine: $${num2hex(CPU.currentInstruction.opcode)} $${num2hex(CPU.currentInstruction.operand)}`);
console.log();
console.log(`IP: $${num2hex(CPU.IP)} Acc: $${num2hex(CPU.Acc)} ONZC ${bool2bit(CPU.FLAGS.O)}${bool2bit(CPU.FLAGS.N)}${bool2bit(CPU.FLAGS.Z)}${bool2bit(CPU.FLAGS.C)}`);
console.log(`KEY: $${num2hex(CPU.memory[KEYPAD_ADDR])}  ${CPU.running ? "running" : "halted" }`);
console.log();
console.log();
console.groupEnd();
};

View File

@ -1,22 +0,0 @@
const { POINTER_TO_DISPLAY } = require('./machine.config');
const { num2hex } = require('./logging.js');
/**
* Print the contents of display memory
* by default, each pixel is shown as a hex number
* @param {Uint8Array} mem - CPU memory
* @param {Boolean} pretty - Display pixels using black and white emoji circles
**/
const printDisplay = (mem, pretty=false) => {
const disp = mem[POINTER_TO_DISPLAY];
const num2pic = (n) => n > 0 ? '⚫' : '⚪';
let fmt = (n) => num2hex(n);
if (pretty) fmt = (n) => num2pic(n);
for (let i = disp; i < disp + 25; i += 5) {
console.log(`${fmt(mem[i])} ${fmt(mem[i+1])} ${fmt(mem[i+2])} ${fmt(mem[i+3])} ${fmt(mem[i+4])}`);
}
}
module.exports = {
"show": printDisplay,
}

View File

@ -1,6 +0,0 @@
{
"compilerOptions": {
"checkJs": true
},
"exclude": ["node_modules", "**/node_modules/*"]
}

View File

@ -1,91 +0,0 @@
/**
* Display a table of memory locations.
* Call with [start] and [end] indices to display a range.
* @param {Uint8Array} mem - Memory to display
* @param {number} [start] - A start-index, in decimal
* @param {number} [end] - An end-index, in decimal
**/
const logMemory = (mem, start=0, end=mem.length) => {
let top1 = `┌─────────┬────────┬─────────┐`;
let top2 = `│ addrs │ opcode │ operand │`;
let top3 = `├─────────┼────────┼─────────┤`;
let blnk = `│ │ │ │`;
let bot1 = `└─────────┴────────┴─────────┘`;
console.log(`${top1}\n${top2}\n${top3}`);
for (let i = start; i < mem.length; i +=2) {
let operand = mem[i+1];
if (typeof operand === 'undefined') {
console.log(` ${num2hex(i)} ${num2hex(i+1)}${num2hex(mem[i])} │ │`);
} else {
console.log(`${num2hex(i)} ${num2hex(i+1)}${num2hex(mem[i])}${num2hex(operand)}`);
}
// Add a blank row every 4 lines:
let rowNum = i - start + 2; // Not actually the row number...
if ((rowNum % 8 === 0)
&& (i < (mem.length - 2))) {
console.log(blnk);
}
}
console.log(bot1);
}
const logRunningHeader = () => {
console.log();
let time = new Date();
console.log( `┌─────────────────────┐`);
console.log( `│ Running at ${time.toLocaleTimeString('en-GB')}` );
console.log( `└─────────────────────┘`);
}
/**
* @param {number} num
* @returns {string}
*/
const num2hex = (num) => num.toString(16).toUpperCase().padStart(2, "0");
/**
* @param {string} hex
* @returns {number}
*/
const hex2num = (hex) => parseInt(hex, 16);
/**
* Convert a number to binary, padded to 8 bits
* See here for an explanation: https://stackoverflow.com/questions/9939760/how-do-i-convert-an-integer-to-binary-in-javascript
* @param {number} num
* @returns {string} binary representation of the input
**/
const num2bin = (num) => (num >>> 0).toString(2).padStart(8, "0");
/**
* Convert a number to binary, padded to 4 bits
* See here for an explanation: https://stackoverflow.com/questions/9939760/how-do-i-convert-an-integer-to-binary-in-javascript
* @param {number} num
* @returns {string} binary representation of the input
**/
const num2bin_4bit = (num) => (num >>> 0).toString(2).padStart(4, "0");
/**
* @param {string} bin
* @returns {number}
*/
const bin2num = (bin) => parseInt(bin, 2)
/**
* @param {Boolean} bool
* @returns {0|1}
**/
const bool2bit = (bool) => bool ? 1 : 0;
module.exports = {
"logMemory": logMemory,
"logRunningHeader": logRunningHeader,
"num2hex": num2hex,
"hex2num": hex2num,
"num2bin": num2bin,
"num2bin_4bit": num2bin_4bit,
"bin2num": bin2num,
"bool2bit": bool2bit,
}

View File

@ -1,31 +0,0 @@
module.exports = {
"INITIAL_IP_ADDRESS": 29,
// Use these in CPU:
"DISPLAY_ADDR": 0,
"KEYPAD_ADDR": 27,
// Store the `DISPLAY_ADDR` at this address when assembling:
"POINTER_TO_DISPLAY": 26,
"KEY_MAP": {
// Same layout as COSMAC VIP / CHIP-8
// (This object maps qwerty keys to hex keys
// so that they are arranged in the same layout
// as the real keypad)
'1':'1', '2':'2', '3':'3', '4':'C',
'Q':'4', 'W':'5', 'E':'6', 'R':'D',
'A':'7', 'S':'8', 'D':'9', 'F':'E',
'Z':'A', 'X':'0', 'C':'B', 'V':'F',
// Include conventional arrow keys
'UP': '5',
'LEFT': '7',
'DOWN': '8',
'RIGHT': '9',
},
// max number of times to step the CPU,
// to stop endless loops
// 0 = infinite
"DEFAULT_CYCLE_LIMIT": 2048,
}

1060
src/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
{
"name": "paper-computer",
"scripts": {
"jsdoc": "./node_modules/.bin/jsdoc"
},
"devDependencies": {
"jsdoc": "^4.0.2",
"jsdoc-to-markdown": "^8.0.0"
},
"dependencies": {
"readline-sync": "^1.4.10"
}
}

View File

@ -1,33 +0,0 @@
#!/usr/bin/env node
// Run with hex output: `./run-assembler.js run assembly.asm`
// Run with binary output: `./run-assembler.js runbin assembly.asm`
// Debug: `./run-assembler.js debug assembly.asm`
const fs = require('fs');
const assembler = require('./assembler.js');
const { logMemory, num2hex, num2bin } = require('./logging.js');
const machineConfig = require('./machine.config.js');
const mode = process.argv[2];
const filename = process.argv[3];
const inputFile_str = fs.readFileSync(filename, 'utf8');
let assembler_output;
if (mode === "debug") {
assembler_output = assembler.assemble(inputFile_str, true);
console.log('');
console.group("Machine code output");
logMemory(assembler_output.machineCode, machineConfig.INITIAL_IP_ADDRESS);
console.groupEnd();
} else {
assembler_output = assembler.assemble(inputFile_str);
let output = '';
if (mode === 'runbin') { // print binary output
assembler_output.machineCode.forEach((n) => output = `${output} ${num2bin(n)}`);
} else { // print hex output
assembler_output.machineCode.forEach((n) => output = `${output} ${num2hex(n)}`);
}
console.log(output);
}

View File

@ -1,71 +0,0 @@
#!/usr/bin/env node
// Usage: ./run-cpu.js -f code.asm [--debug] [--step] [--pretty]
const fs = require('fs');
const computer = require('./cpu.js');
const assembler = require('./assembler.js');
const { logRunningHeader } = require('./logging.js');
// Load file...
let filename;
try {
filename = getArgumentValue('-f', `Missing filename`);
} catch (error) {
console.error(error.message);
process.exit()
}
const inputFile_str = fs.readFileSync(filename, 'utf8');
// Check optional arguments...
let debug = false;
let singleStep = false;
let prettyPrint = false;
process.argv.forEach((arg) => { if (arg === '--debug') { debug = true } });
process.argv.forEach((arg) => { if (arg === '--step') { singleStep = true } });
process.argv.forEach((arg) => { if (arg === '--pretty') { prettyPrint = true } });
let speed = null;
process.argv.forEach((arg, index) => {
if (arg === '--speed' && process.argv.length > (index -1)) {
speed = parseInt(process.argv[index + 1]);
}
});
let assemblerOutput = assembler.assemble(inputFile_str);
logRunningHeader();
computer.runProgram(
assemblerOutput.machineCode,
assemblerOutput.debugInfo,
debug,
singleStep,
prettyPrint,
speed
);
// CLI args TODO
// - check if value is the name of another arg
// - usage info
// - catch nonexistant flags
/**
* @param {string} flag - The command line flag, eg. '-f'
* @param {string} errorMessage - The error to throw if a value isn't found
* @returns {string}
**/
function getArgumentValue(flag, errorMessage) {
let value = null;
process.argv.forEach((arg, index) => {
if (arg === flag && process.argv.length > (index -1)) {
value = process.argv[index + 1];
}
});
if (!value) throw new Error(errorMessage);
return value;
}

View File

@ -1,18 +0,0 @@
;; test addition and substraction
; with direct addressing...
LDA $FE
ADD $01 ; $FF
ADD $01 ; $00 + CF=1
ADD $01 ; $01 + CF=0
SUB $01 ; $00 + CF=0
SUB $01 ; $FF + CF=1
; and with indirect...
LDA $01
STO $00
LDA $FE
ADD ($00) ; $FF
ADD ($00) ; $00 + CF=1
ADD ($00) ; $01 + CF=0
SUB ($00) ; $00 + CF=0
SUB ($00) ; $00 + CF=1
END

View File

@ -1,6 +0,0 @@
;; Test constants
#foo $01
#bar $02
ADD #foo
STO #bar
STO (#bar)

View File

@ -1,69 +0,0 @@
; Routine for drawing at (x, y) coordinates
#zeroflag 1
; *** Set your desired (x, y) here: ***
#input_x 2
#input_y 2
; Set up some handy shortcuts
#x $FA
#y $FB
#return_addr_ptr $FE
; Main:
LDA #input_x
STO #x
LDA #input_y
STO #y
LDA * 6 ; acc = current address + 6 (LDA, STO, JMP = 6)
STO #return_addr_ptr
JMP @getxy
LDA $FF
STO ($FD)
END
;; Convert a pair of (x, y) coords
;; to the address of a pixel on the display
;;
;; Call with:
;; - x in #x
;; - y in #y
;; - return address in #return_addr_ptr
;;
;; Returns: pixel address in $FD
@getxy
#gxy_px $FD
; stash x...
LDA (#x)
STO #gxy_px
; check if this is row 0...
LDA (#y)
FHP #zeroflag
JMP @getxy_loop
JMP (#return_addr_ptr) ; if row 0, we're done
@getxy_loop
LDA (#gxy_px)
ADD 5 ; add 5 to get to the next row
STO #gxy_px
LDA (#y) ; decrement y (it's acting as a loop counter)...
SUB 1
STO #y
FHP #zeroflag
JMP @getxy_loop
JMP (#return_addr_ptr)
;; Main variables:
;; F8
;; F9
;; FA - x coord
;; FB - y coord
;; FC - gxy temp
;; FD - gxy temp
;; FE - Return address for subroutine

View File

@ -1,26 +0,0 @@
;; Fill display with $FF
; updated for 5x5 display
#Zero 1
#px_ptr $F0
#fill $F1
; Initialize variables...
LDA $00 ; (Address for the first px on the display)
STO #px_ptr ; Pointer to current px
LDA $FF ; ($FF is 'on', $00 is 'off')
STO #fill ; Stash value to fill with
@paint
LDA (#fill) ; (A = mem[fill] = $FF)
STO (#px_ptr); Paint pixel (mem[mem[*px]] = A = $FF)
LDA (#px_ptr) ; Increment pixel pointer...
ADD $01
STO #px_ptr
LDA (#px_ptr) ; Test whether to loop or not...
SUB $19 ; if *px - $19 == 0, we've reached the end
FHP #Zero
JMP @paint
END

View File

@ -1,10 +0,0 @@
;; test FHP and FTG for carry
ADD $FF ; Acc = $FF
FHP 0 ; shouldn't hop (CF = 0)
ADD 2 ; Acc = $01 and CF = 1
FHP 0 ; hop! (CF = 1)
END
SUB 1 ; Acc = $00, CF = 0
SUB 1 ; Acc = $FF, CF = 1
FTG 0 ; CF = 0
END

View File

@ -1,36 +0,0 @@
;; test overflow flag
; https://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
LDA $50
ADD $10 ; CF, OF: 0 0
LDA $50
ADD $50 ; CF, OF: 0 1
LDA $50
ADD $90 ; CF, OF: 0 0
LDA $50
ADD $D0 ; CF, OF: 1 0
LDA $D0
ADD $10 ; CF, OF: 0 0
LDA $D0
ADD $50 ; CF, OF: 1 0
LDA $D0
ADD $90 ; CF, OF: 1 1
LDA $D0
ADD $D0 ; CF, OF: 1 0
LDA $50
SUB $F0 ; CF, OF: 1 0
LDA $50
SUB $B0 ; CF, OF: 1 1
LDA $50
SUB $70 ; CF, OF: 1 0
LDA $50
SUB $30 ; CF, OF: 0 0
LDA $D0
SUB $F0 ; CF, OF: 1 0
LDA $D0
SUB $B0 ; CF, OF: 0 0
LDA $D0
SUB $70 ; CF, OF: 0 1
LDA $D0
SUB $30 ; CF, OF: 0 0

View File

@ -1,10 +0,0 @@
;; test jumping to a label
ADD 15
ADD 10 ; should set CF
JMP @end
ADD 1
ADD 2
ADD 3
@end
END

View File

@ -1,30 +0,0 @@
;; Test keypad input
;; 2023-08-16
; The latest keypress is shown in the top left corner of the display.
; A loop counter is shown in the top right corner; the program ends when it reaches zero.
; (For a 4x4 display.)
#LOOPCOUNT $80
#Z 1 ; the zero flag is #1
#keypad $20 ; magic memory location containing latest key pressed
#loopIter $FF ; address of loop iterator
#iterPx $03 ; where to display iterator
#keyPx $00 ; where to display key
LDA #LOOPCOUNT
STO #loopIter
@loop
LDA (#loopIter)
STO #iterPx ; display loop iterator
LDA (#keypad)
STO #keyPx ; display latest keypress
LDA (#loopIter)
SUB 1
STO #loopIter
FTG #Z
FHP #Z
END
JMP @loop

View File

@ -1,37 +0,0 @@
;; Conway's Game of Life
; n loewen & Elizabeth Pankratz
; 2023-08-23 -
; Flag numbers for easier reference
#Carry 0
#Zero 1
#live_colour $FF
#dead_colour $00
#top_left $00
#top_right $04
#bot_left $14
#bot_right $18
#px_ptr $00
#live_neighbours_ptr $FF
; start of code
* $1D
@loop
LDA (#px_ptr)
; do something...
; increment pixel pointer
LDA (#px_ptr)
STA #px_ptr
JMP @loop
@check_for_tl_corner
LDA (#px_ptr)
; choose a memory location to stash result. 0=false, 1=true
HOP

View File

@ -1,164 +0,0 @@
; Draw a pixel, and move it when a key is pressed
; 2023-08-26
#flagZ 1
#flagN 2
#keypad $1B ; contains latest key pressed
; Starting (x, y) coordinates
#input_x 0
#input_y 0
; Some handy shortcuts
#x $FA
#y $FB
#px_addr $FD ; holds return value from @xy2id
#return_addr_ptr $FE
; Main variables:
; F8
; F9 - xy2id temp
; FA - x coord
; FB - y coord
; FC - xy2id temp
; FD - xy2id return value / xy2id temp
; FE - Return address for subroutine
@setup
LDA #input_x
STO #x
LDA #input_y
STO #y
LDA @update
STO #return_addr_ptr
JMP @xy2id
@update
; draw pixel
LDA $FF
STO (#px_addr)
; determine direction
#up 5
#left 7
#down 8
#right 9
; test up
lda (#keypad)
sub #up
ftg #flagZ
fhp #flagZ
jmp @up
; test left
lda (#keypad)
sub #left
ftg #flagZ
fhp #flagZ
jmp @left
; test right
lda (#keypad)
sub #right
ftg #flagZ
fhp #flagZ
jmp @right
; test down
lda (#keypad)
sub #down
ftg #flagZ
fhp #flagZ
jmp @down
;; no key pressed...
jmp @stay_put
@up
lda (#y)
sub 1
ftg #flagN
fhp #flagN
jmp @stay_put
sto #y
jmp @xy2id
@left
lda (#x)
sub 1
ftg #flagN
fhp #flagN
jmp @stay_put
sto #x
jmp @xy2id
@right
lda (#x)
sub 4
ftg #flagZ
fhp #flagZ
jmp @stay_put
lda (#x)
add 1
sto #x
jmp @xy2id
@down
lda (#y)
sub 4
ftg #flagZ
fhp #flagZ
jmp @stay_put
lda (#y)
add 1
sto #y
jmp @xy2id
@stay_put
; draw pixel
LDA $FF
STO (#px_addr)
; TODO
; END
;; Convert a pair of (x, y) coords
;; to the address of a pixel on the display
;;
;; Call with:
;; - x in #x
;; - y in #y
;; - return address in #return_addr_ptr
;;
;; Returns:
;; - pixel address in #px_addr
@xy2id
; stash x, y...
#xy2id_y $FC
#xy2id_x $F9
LDA (#y)
STO #xy2id_y
LDA (#x)
STO #xy2id_x
STO #px_addr
; check if this is row 0...
LDA (#xy2id_y)
FHP #flagZ
JMP @xy2id_loop
JMP (#return_addr_ptr) ; if row 0, we're done
@xy2id_loop
LDA (#px_addr)
ADD 5 ; add 5 to get to the next row
STO #px_addr
LDA (#xy2id_y) ; decrement y (it's acting as a loop counter) ...
SUB 1
STO #xy2id_y
FHP #flagZ
JMP @xy2id_loop
JMP (#return_addr_ptr)

View File

@ -1,6 +0,0 @@
;; test NOP
ADD $01
NOP
NOP
NOP
END

View File

@ -1,17 +0,0 @@
;; Test referencing address of line being assembled
* 30
NOP ; Push the const below to a later address
#initAddr *
LDA *
STO $25
FHP 0 ; hop if carry set
JMP @setCarry
LDA #initAddr
END
@setCarry
FTG 0
JMP ($25)

View File

@ -1,8 +0,0 @@
;; test re-locating display memory
LDA $10
STO $20 ; change pointer-to-display-memory to $10
STO $10
STO $11
STO $12
STO $13
END

View File

@ -1,73 +0,0 @@
;; sketching around subroutines with return stack
; I think the sketching below contains some useful ideas,
; but the new `*ADDR` assembly op should make this a whole lot simpler
; sketches follow ..........
; jump table
; ----------
; each function has a label
; and you can get to it with `JMP @label`
; ...but you can't push a label onto a stack
; so instead we give each function a number
; and stash that number in $24 when jumping to a subroutine
; then when the subroutine ends, it jumps here
; where that number gets mapped back onto the function's label
=*reentryPoint
=routine1 $1
lda =routine1
sto $19 ; contains ID # for the next fn to jump to
@jump_table
hop $1
jmp @jt2
jmp @example_computation
@jt2
hop $2
; jmp @jt3
nop
; etc …
jmp @end
@example_computation
lda 5
sto $20
lda 3
sto $21
; $19 still has the # for this routine
; but lets pretend it doesnt and demonstrate updating it
lda $1
sto $19
jmp @greater?
; call with numbers to test in $20 and $21
; result is stored in acc
@greater?
; lda ($20)
; sub ($21)
; todo…
; wouldnt it be great to have a “hop if neg” op…
; do we have to just subtract numbers until we get 0?
; no!
; heres an approach thats at least better than that
lda ($21)
sto $22 ; stash
@loop
lda ($21)
sub $1
sto $22 ; stash
sub ($20)
hop $0
jmp @loop
sto $1
jmp $jmp_table
; ok this isnt quite it… we also need to chexk if we hit 0 by just deceementinf and if so retuen 0
@end
END