2023-09-03 - Create (extensive) note - sketch for a more comprehensive (lower-level) cpu design, in javascript; todos; reference links
This commit is contained in:
parent
243f000ace
commit
9baf3ab750
|
|
@ -0,0 +1,265 @@
|
|||
# Dev notes — 2023-09-03
|
||||
|
||||
## Todos
|
||||
|
||||
- [ ] add yesterday’s 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 interpreter](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/)
|
||||
|
||||
|
||||
## Corrections
|
||||
|
||||
It doesn’t execute “JMP $FF.” It just sets the IP to $FF on reset, and you put a JMP there in ROM.
|
||||
|
||||
- [ ] TODO: update docs elsewhere
|
||||
|
||||
|
||||
## More detailed CPU design + lower-level simulator
|
||||
|
||||
### Revising ISA
|
||||
|
||||
[See notes from 2023-08-23](2023-08-23--dev-notes.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 doesn’t seem useful at this point so I’m 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
|
||||
Loading…
Reference in New Issue