ac6502 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/dist/components/CPU.d.ts +162 -0
- package/dist/components/Cart.d.ts +9 -0
- package/dist/components/IO/ACIA.d.ts +76 -0
- package/dist/components/IO/ACIA.js +282 -0
- package/dist/components/IO/ACIA.js.map +1 -0
- package/dist/components/IO/Attachments/Attachment.d.ts +112 -0
- package/dist/components/IO/Attachments/Attachment.js +71 -0
- package/dist/components/IO/Attachments/Attachment.js.map +1 -0
- package/dist/components/IO/Attachments/JoystickAttachment.d.ts +53 -0
- package/dist/components/IO/Attachments/JoystickAttachment.js +90 -0
- package/dist/components/IO/Attachments/JoystickAttachment.js.map +1 -0
- package/dist/components/IO/Attachments/KeyboardEncoderAttachment.d.ts +63 -0
- package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js +489 -0
- package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js.map +1 -0
- package/dist/components/IO/Attachments/KeyboardMatrixAttachment.d.ts +44 -0
- package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js +274 -0
- package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js.map +1 -0
- package/dist/components/IO/Attachments/KeypadAttachment.d.ts +47 -0
- package/dist/components/IO/Attachments/KeypadAttachment.js +141 -0
- package/dist/components/IO/Attachments/KeypadAttachment.js.map +1 -0
- package/dist/components/IO/Attachments/LCDAttachment.d.ts +110 -0
- package/dist/components/IO/Attachments/LCDAttachment.js +716 -0
- package/dist/components/IO/Attachments/LCDAttachment.js.map +1 -0
- package/dist/components/IO/Attachments/SNESAttachment.d.ts +85 -0
- package/dist/components/IO/Attachments/SNESAttachment.js +184 -0
- package/dist/components/IO/Attachments/SNESAttachment.js.map +1 -0
- package/dist/components/IO/DevOutputBoard.d.ts +19 -0
- package/dist/components/IO/DevOutputBoard.js +33 -0
- package/dist/components/IO/DevOutputBoard.js.map +1 -0
- package/dist/components/IO/Empty.d.ts +9 -0
- package/dist/components/IO/Empty.js +5 -7
- package/dist/components/IO/Empty.js.map +1 -1
- package/dist/components/IO/EmptyCard.d.ts +9 -0
- package/dist/components/IO/GPIOAttachments/GPIOAttachment.d.ts +112 -0
- package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.d.ts +53 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.d.ts +63 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.d.ts +44 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeypadAttachment.d.ts +47 -0
- package/dist/components/IO/GPIOAttachments/GPIOLCDAttachment.d.ts +110 -0
- package/dist/components/IO/GPIOCard.d.ts +105 -0
- package/dist/components/IO/GPIOCard.js.map +1 -1
- package/dist/components/IO/RAMBank.d.ts +37 -0
- package/dist/components/IO/RAMBank.js +63 -0
- package/dist/components/IO/RAMBank.js.map +1 -0
- package/dist/components/IO/RAMCard.d.ts +37 -0
- package/dist/components/IO/RTC.d.ts +107 -0
- package/dist/components/IO/RTC.js +483 -0
- package/dist/components/IO/RTC.js.map +1 -0
- package/dist/components/IO/RTCCard.d.ts +107 -0
- package/dist/components/IO/SerialCard.d.ts +76 -0
- package/dist/components/IO/Sound.d.ts +120 -0
- package/dist/components/IO/Sound.js +622 -0
- package/dist/components/IO/Sound.js.map +1 -0
- package/dist/components/IO/SoundCard.d.ts +120 -0
- package/dist/components/IO/Storage.d.ts +74 -0
- package/dist/components/IO/Storage.js +409 -0
- package/dist/components/IO/Storage.js.map +1 -0
- package/dist/components/IO/StorageCard.d.ts +74 -0
- package/dist/components/IO/Terminal.d.ts +19 -0
- package/dist/components/IO/Terminal.js +33 -0
- package/dist/components/IO/Terminal.js.map +1 -0
- package/dist/components/IO/VIA.d.ts +105 -0
- package/dist/components/IO/VIA.js +597 -0
- package/dist/components/IO/VIA.js.map +1 -0
- package/dist/components/IO/Video.d.ts +141 -0
- package/dist/components/IO/Video.js +630 -0
- package/dist/components/IO/Video.js.map +1 -0
- package/dist/components/IO/VideoCard.d.ts +141 -0
- package/dist/components/IO.d.ts +8 -0
- package/dist/components/Machine.d.ts +62 -0
- package/dist/components/Machine.js +260 -153
- package/dist/components/Machine.js.map +1 -1
- package/dist/components/RAM.d.ts +9 -0
- package/dist/components/ROM.d.ts +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +61 -28
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +22 -0
- package/dist/lib.js +47 -0
- package/dist/lib.js.map +1 -0
- package/dist/tests/CPU.test.d.ts +1 -0
- package/dist/tests/Cart.test.d.ts +1 -0
- package/dist/tests/IO/ACIA.test.d.ts +1 -0
- package/dist/tests/IO/ACIA.test.js +423 -0
- package/dist/tests/IO/ACIA.test.js.map +1 -0
- package/dist/tests/IO/Attachments/Attachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/Attachment.test.js +339 -0
- package/dist/tests/IO/Attachments/Attachment.test.js.map +1 -0
- package/dist/tests/IO/Attachments/JoystickAttachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/JoystickAttachment.test.js +126 -0
- package/dist/tests/IO/Attachments/JoystickAttachment.test.js.map +1 -0
- package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js +779 -0
- package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js.map +1 -0
- package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js +355 -0
- package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js.map +1 -0
- package/dist/tests/IO/Attachments/KeypadAttachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/KeypadAttachment.test.js +323 -0
- package/dist/tests/IO/Attachments/KeypadAttachment.test.js.map +1 -0
- package/dist/tests/IO/Attachments/LCDAttachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/LCDAttachment.test.js +627 -0
- package/dist/tests/IO/Attachments/LCDAttachment.test.js.map +1 -0
- package/dist/tests/IO/Attachments/SNESAttachment.test.d.ts +1 -0
- package/dist/tests/IO/Attachments/SNESAttachment.test.js +331 -0
- package/dist/tests/IO/Attachments/SNESAttachment.test.js.map +1 -0
- package/dist/tests/IO/Empty.test.d.ts +1 -0
- package/dist/tests/IO/Empty.test.js +121 -0
- package/dist/tests/IO/Empty.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOCard.test.d.ts +1 -0
- package/dist/tests/IO/GPIOCard.test.js.map +1 -1
- package/dist/tests/IO/RAMBank.test.d.ts +1 -0
- package/dist/tests/IO/RAMBank.test.js +229 -0
- package/dist/tests/IO/RAMBank.test.js.map +1 -0
- package/dist/tests/IO/RAMCard.test.d.ts +1 -0
- package/dist/tests/IO/RTC.test.d.ts +1 -0
- package/dist/tests/IO/RTC.test.js +177 -0
- package/dist/tests/IO/RTC.test.js.map +1 -0
- package/dist/tests/IO/RTCCard.test.d.ts +1 -0
- package/dist/tests/IO/SerialCard.test.d.ts +1 -0
- package/dist/tests/IO/Sound.test.d.ts +1 -0
- package/dist/tests/IO/Sound.test.js +528 -0
- package/dist/tests/IO/Sound.test.js.map +1 -0
- package/dist/tests/IO/SoundCard.test.d.ts +1 -0
- package/dist/tests/IO/Storage.test.d.ts +1 -0
- package/dist/tests/IO/Storage.test.js +656 -0
- package/dist/tests/IO/Storage.test.js.map +1 -0
- package/dist/tests/IO/StorageCard.test.d.ts +1 -0
- package/dist/tests/IO/VIA.test.d.ts +1 -0
- package/dist/tests/IO/VIA.test.js +503 -0
- package/dist/tests/IO/VIA.test.js.map +1 -0
- package/dist/tests/IO/Video.test.d.ts +1 -0
- package/dist/tests/IO/Video.test.js +549 -0
- package/dist/tests/IO/Video.test.js.map +1 -0
- package/dist/tests/IO/VideoCard.test.d.ts +1 -0
- package/dist/tests/Machine.test.d.ts +1 -0
- package/dist/tests/Machine.test.js +27 -42
- package/dist/tests/Machine.test.js.map +1 -1
- package/dist/tests/RAM.test.d.ts +1 -0
- package/dist/tests/ROM.test.d.ts +1 -0
- package/package.json +5 -3
- package/src/components/IO/{SerialCard.ts → ACIA.ts} +2 -2
- package/src/components/IO/{GPIOAttachments/GPIOAttachment.ts → Attachments/Attachment.ts} +2 -2
- package/src/components/IO/{GPIOAttachments/GPIOJoystickAttachment.ts → Attachments/JoystickAttachment.ts} +3 -3
- package/src/components/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.ts → Attachments/KeyboardEncoderAttachment.ts} +3 -3
- package/src/components/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.ts → Attachments/KeyboardMatrixAttachment.ts} +5 -5
- package/src/components/IO/{GPIOAttachments/GPIOKeypadAttachment.ts → Attachments/KeypadAttachment.ts} +3 -3
- package/src/components/IO/{GPIOAttachments/GPIOLCDAttachment.ts → Attachments/LCDAttachment.ts} +7 -7
- package/src/components/IO/{EmptyCard.ts → Empty.ts} +1 -1
- package/src/components/IO/{RAMCard.ts → RAMBank.ts} +8 -8
- package/src/components/IO/{RTCCard.ts → RTC.ts} +1 -1
- package/src/components/IO/{SoundCard.ts → Sound.ts} +2 -2
- package/src/components/IO/{StorageCard.ts → Storage.ts} +70 -73
- package/src/components/IO/Terminal.ts +34 -0
- package/src/components/IO/{GPIOCard.ts → VIA.ts} +64 -64
- package/src/components/IO/{VideoCard.ts → Video.ts} +1 -1
- package/src/components/Machine.ts +286 -160
- package/src/index.ts +65 -35
- package/src/lib.ts +27 -0
- package/src/tests/IO/{SerialCard.test.ts → ACIA.test.ts} +5 -5
- package/src/tests/IO/{GPIOAttachments/GPIOAttachment.test.ts → Attachments/Attachment.test.ts} +12 -12
- package/src/tests/IO/{GPIOAttachments/GPIOJoystickAttachment.test.ts → Attachments/JoystickAttachment.test.ts} +23 -23
- package/src/tests/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts → Attachments/KeyboardEncoderAttachment.test.ts} +4 -4
- package/src/tests/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts → Attachments/KeyboardMatrixAttachment.test.ts} +5 -5
- package/src/tests/IO/{GPIOAttachments/GPIOKeypadAttachment.test.ts → Attachments/KeypadAttachment.test.ts} +38 -38
- package/src/tests/IO/{GPIOAttachments/GPIOLCDAttachment.test.ts → Attachments/LCDAttachment.test.ts} +12 -12
- package/src/tests/IO/Empty.test.ts +143 -0
- package/src/tests/IO/{RAMCard.test.ts → RAMBank.test.ts} +33 -33
- package/src/tests/IO/{RTCCard.test.ts → RTC.test.ts} +6 -6
- package/src/tests/IO/{SoundCard.test.ts → Sound.test.ts} +6 -6
- package/src/tests/IO/{StorageCard.test.ts → Storage.test.ts} +34 -25
- package/src/tests/IO/{GPIOCard.test.ts → VIA.test.ts} +7 -7
- package/src/tests/IO/{VideoCard.test.ts → Video.test.ts} +13 -13
- package/src/tests/Machine.test.ts +31 -38
- package/tsconfig.json +1 -0
|
@@ -2,21 +2,21 @@ import { CPU } from './CPU'
|
|
|
2
2
|
import { RAM } from './RAM'
|
|
3
3
|
import { ROM } from './ROM'
|
|
4
4
|
import { Cart } from './Cart'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
5
|
+
import { VIA } from './IO/VIA'
|
|
6
|
+
import { RAMBank } from './IO/RAMBank'
|
|
7
|
+
import { RTC } from './IO/RTC'
|
|
8
|
+
import { ACIA } from './IO/ACIA'
|
|
9
|
+
import { Sound } from './IO/Sound'
|
|
10
|
+
import { Storage } from './IO/Storage'
|
|
11
|
+
import { Video } from './IO/Video'
|
|
12
|
+
import { KeyboardMatrixAttachment } from './IO/Attachments/KeyboardMatrixAttachment'
|
|
13
|
+
import { KeyboardEncoderAttachment } from './IO/Attachments/KeyboardEncoderAttachment'
|
|
14
|
+
import { JoystickAttachment } from './IO/Attachments/JoystickAttachment'
|
|
15
|
+
import { LCDAttachment } from './IO/Attachments/LCDAttachment'
|
|
16
|
+
import { KeypadAttachment } from './IO/Attachments/KeypadAttachment'
|
|
17
|
+
import { Empty } from './IO/Empty'
|
|
18
|
+
import { Terminal } from './IO/Terminal'
|
|
18
19
|
import { IO } from './IO'
|
|
19
|
-
import { readFile } from 'fs/promises'
|
|
20
20
|
|
|
21
21
|
export class Machine {
|
|
22
22
|
|
|
@@ -25,184 +25,304 @@ export class Machine {
|
|
|
25
25
|
|
|
26
26
|
private ioCycleAccumulator: number = 0
|
|
27
27
|
private ioTickInterval: number = 128 // adjust (64/128/256)
|
|
28
|
+
private loopHandle?: ReturnType<typeof setImmediate> | ReturnType<typeof setTimeout>
|
|
28
29
|
|
|
29
30
|
cpu: CPU
|
|
30
31
|
ram: RAM
|
|
31
32
|
rom: ROM
|
|
33
|
+
cart?: Cart
|
|
34
|
+
|
|
32
35
|
io1: IO
|
|
33
36
|
io2: IO
|
|
34
37
|
io3: IO
|
|
35
38
|
io4: IO
|
|
36
|
-
io5:
|
|
39
|
+
io5: IO
|
|
37
40
|
io6: IO
|
|
38
41
|
io7: IO
|
|
39
42
|
io8: IO
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
keyboardEncoderAttachment: GPIOKeyboardEncoderAttachment
|
|
47
|
-
joystickAttachmentA: GPIOJoystickAttachment
|
|
48
|
-
joystickAttachmentB: GPIOJoystickAttachment
|
|
44
|
+
// VIA Attachments
|
|
45
|
+
keyboardMatrixAttachment?: KeyboardMatrixAttachment
|
|
46
|
+
keyboardEncoderAttachment?: KeyboardEncoderAttachment
|
|
47
|
+
joystickAttachmentA?: JoystickAttachment
|
|
48
|
+
joystickAttachmentB?: JoystickAttachment
|
|
49
49
|
|
|
50
50
|
// KIM mode attachments
|
|
51
|
-
lcdAttachment?:
|
|
52
|
-
keypadAttachment?:
|
|
51
|
+
lcdAttachment?: LCDAttachment
|
|
52
|
+
keypadAttachment?: KeypadAttachment
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
target: string
|
|
55
55
|
isRunning: boolean = false
|
|
56
56
|
frequency: number = 2000000 // 2 MHz
|
|
57
57
|
scale: number = 2
|
|
58
58
|
frames: number = 0
|
|
59
|
-
frameDelay: number = 0
|
|
60
|
-
frameDelayCount: number = 0
|
|
61
59
|
startTime: number = Date.now()
|
|
62
60
|
previousTime: number = performance.now()
|
|
63
61
|
|
|
64
62
|
transmit?: (data: number) => void
|
|
65
63
|
render?: () => void
|
|
66
|
-
|
|
64
|
+
play?: (samples: Float32Array) => void
|
|
67
65
|
|
|
68
66
|
//
|
|
69
67
|
// Initialization
|
|
70
68
|
//
|
|
71
69
|
|
|
72
|
-
constructor(
|
|
73
|
-
this.
|
|
70
|
+
constructor(target: string) {
|
|
71
|
+
this.target = target
|
|
74
72
|
this.cpu = new CPU(this.read.bind(this), this.write.bind(this))
|
|
75
73
|
this.ram = new RAM()
|
|
76
74
|
this.rom = new ROM()
|
|
77
75
|
|
|
78
|
-
this.
|
|
76
|
+
this.io1 = new Empty()
|
|
77
|
+
this.io2 = new Empty()
|
|
78
|
+
this.io3 = new Empty()
|
|
79
|
+
this.io4 = new Empty()
|
|
80
|
+
this.io5 = new Empty()
|
|
81
|
+
this.io6 = new Empty()
|
|
82
|
+
this.io7 = new Empty()
|
|
83
|
+
this.io8 = new Empty()
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
this.
|
|
85
|
+
this.configureTarget(target)
|
|
86
|
+
|
|
87
|
+
this.startTime = Date.now()
|
|
88
|
+
this.cpu.reset()
|
|
89
|
+
}
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
}
|
|
91
|
+
configureTarget(target: string): void {
|
|
92
|
+
if (target === 'kim') {
|
|
93
|
+
const acia = new ACIA()
|
|
94
|
+
this.io5 = acia
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.joystickAttachmentA = new GPIOJoystickAttachment(false, 100)
|
|
95
|
-
this.joystickAttachmentB = new GPIOJoystickAttachment(false, 100)
|
|
96
|
+
// Connect ACIA IRQ/NMI to CPU
|
|
97
|
+
acia.raiseIRQ = () => this.cpu.irq()
|
|
98
|
+
acia.raiseNMI = () => this.cpu.nmi()
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
// Connect ACIA transmit callback
|
|
101
|
+
acia.transmit = (data: number) => {
|
|
102
|
+
if (this.transmit) {
|
|
103
|
+
this.transmit(data)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.io1 = new Empty()
|
|
108
|
+
this.io2 = new Empty()
|
|
109
|
+
this.io3 = new Empty()
|
|
110
|
+
this.io4 = new Empty()
|
|
111
|
+
this.io6 = new Empty()
|
|
112
|
+
this.io7 = new Empty()
|
|
104
113
|
|
|
105
|
-
const
|
|
106
|
-
this.io8 =
|
|
114
|
+
const via = new VIA()
|
|
115
|
+
this.io8 = via
|
|
107
116
|
|
|
108
|
-
// Connect
|
|
109
|
-
|
|
110
|
-
|
|
117
|
+
// Connect VIA IRQ/NMI to CPU
|
|
118
|
+
via.raiseIRQ = () => this.cpu.irq()
|
|
119
|
+
via.raiseNMI = () => this.cpu.nmi()
|
|
111
120
|
|
|
112
121
|
// Create KIM GPIO Attachments
|
|
113
|
-
this.lcdAttachment = new
|
|
114
|
-
this.keypadAttachment = new
|
|
122
|
+
this.lcdAttachment = new LCDAttachment(16, 2, 10)
|
|
123
|
+
this.keypadAttachment = new KeypadAttachment(true, 20)
|
|
115
124
|
|
|
116
125
|
// Attach LCD to Port A (control: RS/RW/E on bits 5-7) and Port B (data bus)
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
via.attachToPortA(this.lcdAttachment)
|
|
127
|
+
via.attachToPortB(this.lcdAttachment)
|
|
119
128
|
|
|
120
129
|
// Attach keypad to Port A (bits 0-4)
|
|
121
|
-
|
|
122
|
-
} else {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
this.io7 = soundCard
|
|
135
|
-
this.io8 = videoCard
|
|
136
|
-
|
|
137
|
-
// Connect RTCCard IRQ/NMI to CPU
|
|
138
|
-
rtcCard.raiseIRQ = () => this.cpu.irq()
|
|
139
|
-
rtcCard.raiseNMI = () => this.cpu.nmi()
|
|
140
|
-
|
|
141
|
-
// Connect VideoCard IRQ/NMI to CPU
|
|
142
|
-
videoCard.raiseIRQ = () => this.cpu.irq()
|
|
143
|
-
videoCard.raiseNMI = () => this.cpu.nmi()
|
|
144
|
-
|
|
145
|
-
// Connect SoundCard pushSamples callback
|
|
146
|
-
soundCard.pushSamples = (samples: Float32Array) => {
|
|
147
|
-
if (this.pushAudioSamples) {
|
|
148
|
-
this.pushAudioSamples(samples)
|
|
130
|
+
via.attachToPortA(this.keypadAttachment)
|
|
131
|
+
} else if (target === 'dev') {
|
|
132
|
+
const acia = new ACIA()
|
|
133
|
+
this.io5 = acia
|
|
134
|
+
|
|
135
|
+
// Connect ACIA IRQ/NMI to CPU
|
|
136
|
+
acia.raiseIRQ = () => this.cpu.irq()
|
|
137
|
+
acia.raiseNMI = () => this.cpu.nmi()
|
|
138
|
+
|
|
139
|
+
// Connect ACIA transmit callback
|
|
140
|
+
acia.transmit = (data: number) => {
|
|
141
|
+
if (this.transmit) {
|
|
142
|
+
this.transmit(data)
|
|
149
143
|
}
|
|
150
144
|
}
|
|
151
145
|
|
|
146
|
+
const rtc = new RTC()
|
|
147
|
+
const storage = new Storage()
|
|
148
|
+
const via = new VIA()
|
|
149
|
+
|
|
150
|
+
this.io1 = new RAMBank()
|
|
151
|
+
this.io2 = new RAMBank()
|
|
152
|
+
this.io3 = rtc
|
|
153
|
+
this.io4 = storage
|
|
154
|
+
this.io6 = via
|
|
155
|
+
this.io7 = new Empty()
|
|
156
|
+
this.io8 = new Terminal()
|
|
157
|
+
|
|
158
|
+
// Connect RTC IRQ/NMI to CPU
|
|
159
|
+
rtc.raiseIRQ = () => this.cpu.irq()
|
|
160
|
+
rtc.raiseNMI = () => this.cpu.nmi()
|
|
161
|
+
|
|
162
|
+
// Create standard GPIO attachments
|
|
163
|
+
this.keyboardMatrixAttachment = new KeyboardMatrixAttachment(10)
|
|
164
|
+
this.keyboardEncoderAttachment = new KeyboardEncoderAttachment(20)
|
|
165
|
+
this.joystickAttachmentA = new JoystickAttachment(false, 100)
|
|
166
|
+
this.joystickAttachmentB = new JoystickAttachment(false, 100)
|
|
167
|
+
|
|
152
168
|
// Attach peripherals to GPIO Card
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
169
|
+
via.attachToPortA(this.keyboardMatrixAttachment)
|
|
170
|
+
via.attachToPortB(this.keyboardMatrixAttachment)
|
|
171
|
+
via.attachToPortA(this.keyboardEncoderAttachment)
|
|
172
|
+
via.attachToPortB(this.keyboardEncoderAttachment)
|
|
173
|
+
via.attachToPortA(this.joystickAttachmentA)
|
|
174
|
+
via.attachToPortB(this.joystickAttachmentB)
|
|
175
|
+
} else if (target === 'vcs') {
|
|
176
|
+
this.io5 = new Empty()
|
|
177
|
+
|
|
178
|
+
const via = new VIA()
|
|
179
|
+
const sound = new Sound()
|
|
180
|
+
const video = new Video()
|
|
181
|
+
|
|
182
|
+
this.io1 = new Empty()
|
|
183
|
+
this.io2 = new Empty()
|
|
184
|
+
this.io3 = new Empty()
|
|
185
|
+
this.io4 = new Empty()
|
|
186
|
+
this.io6 = via
|
|
187
|
+
this.io7 = sound
|
|
188
|
+
this.io8 = video
|
|
189
|
+
|
|
190
|
+
// Connect Video IRQ/NMI to CPU
|
|
191
|
+
video.raiseIRQ = () => this.cpu.irq()
|
|
192
|
+
video.raiseNMI = () => this.cpu.nmi()
|
|
193
|
+
|
|
194
|
+
// Connect Sound pushSamples callback
|
|
195
|
+
sound.pushSamples = (samples: Float32Array) => {
|
|
196
|
+
if (this.play) {
|
|
197
|
+
this.play(samples)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
160
200
|
|
|
161
|
-
|
|
201
|
+
// Create standard GPIO attachments
|
|
202
|
+
this.keyboardMatrixAttachment = new KeyboardMatrixAttachment(10)
|
|
203
|
+
this.keyboardEncoderAttachment = new KeyboardEncoderAttachment(20)
|
|
204
|
+
this.joystickAttachmentA = new JoystickAttachment(false, 100)
|
|
205
|
+
this.joystickAttachmentB = new JoystickAttachment(false, 100)
|
|
206
|
+
|
|
207
|
+
// Attach peripherals to GPIO Card
|
|
208
|
+
via.attachToPortA(this.keyboardMatrixAttachment)
|
|
209
|
+
via.attachToPortB(this.keyboardMatrixAttachment)
|
|
210
|
+
via.attachToPortA(this.keyboardEncoderAttachment)
|
|
211
|
+
via.attachToPortB(this.keyboardEncoderAttachment)
|
|
212
|
+
via.attachToPortA(this.joystickAttachmentA)
|
|
213
|
+
via.attachToPortB(this.joystickAttachmentB)
|
|
214
|
+
} else if (target === 'cob') {
|
|
215
|
+
const acia = new ACIA()
|
|
216
|
+
this.io5 = acia
|
|
217
|
+
|
|
218
|
+
// Connect ACIA IRQ/NMI to CPU
|
|
219
|
+
acia.raiseIRQ = () => this.cpu.irq()
|
|
220
|
+
acia.raiseNMI = () => this.cpu.nmi()
|
|
221
|
+
|
|
222
|
+
// Connect ACIA transmit callback
|
|
223
|
+
acia.transmit = (data: number) => {
|
|
224
|
+
if (this.transmit) {
|
|
225
|
+
this.transmit(data)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const rtc = new RTC()
|
|
230
|
+
const storage = new Storage()
|
|
231
|
+
const gpio = new VIA()
|
|
232
|
+
const sound = new Sound()
|
|
233
|
+
const video = new Video()
|
|
234
|
+
|
|
235
|
+
this.io1 = new RAMBank()
|
|
236
|
+
this.io2 = new RAMBank()
|
|
237
|
+
this.io3 = rtc
|
|
238
|
+
this.io4 = storage
|
|
239
|
+
this.io6 = gpio
|
|
240
|
+
this.io7 = sound
|
|
241
|
+
this.io8 = video
|
|
242
|
+
|
|
243
|
+
// Connect RTC IRQ/NMI to CPU
|
|
244
|
+
rtc.raiseIRQ = () => this.cpu.irq()
|
|
245
|
+
rtc.raiseNMI = () => this.cpu.nmi()
|
|
246
|
+
|
|
247
|
+
// Connect Video IRQ/NMI to CPU
|
|
248
|
+
video.raiseIRQ = () => this.cpu.irq()
|
|
249
|
+
video.raiseNMI = () => this.cpu.nmi()
|
|
250
|
+
|
|
251
|
+
// Connect Sound pushSamples callback
|
|
252
|
+
sound.pushSamples = (samples: Float32Array) => {
|
|
253
|
+
if (this.play) {
|
|
254
|
+
this.play(samples)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Create standard GPIO attachments
|
|
259
|
+
this.keyboardMatrixAttachment = new KeyboardMatrixAttachment(10)
|
|
260
|
+
this.keyboardEncoderAttachment = new KeyboardEncoderAttachment(20)
|
|
261
|
+
this.joystickAttachmentA = new JoystickAttachment(false, 100)
|
|
262
|
+
this.joystickAttachmentB = new JoystickAttachment(false, 100)
|
|
263
|
+
|
|
264
|
+
// Attach peripherals to GPIO Card
|
|
265
|
+
gpio.attachToPortA(this.keyboardMatrixAttachment)
|
|
266
|
+
gpio.attachToPortB(this.keyboardMatrixAttachment)
|
|
267
|
+
gpio.attachToPortA(this.keyboardEncoderAttachment)
|
|
268
|
+
gpio.attachToPortB(this.keyboardEncoderAttachment)
|
|
269
|
+
gpio.attachToPortA(this.joystickAttachmentA)
|
|
270
|
+
gpio.attachToPortB(this.joystickAttachmentB)
|
|
271
|
+
} else {
|
|
272
|
+
this.io1 = new Empty()
|
|
273
|
+
this.io2 = new Empty()
|
|
274
|
+
this.io3 = new Empty()
|
|
275
|
+
this.io4 = new Empty()
|
|
276
|
+
this.io5 = new Empty()
|
|
277
|
+
this.io6 = new Empty()
|
|
278
|
+
this.io7 = new Empty()
|
|
279
|
+
this.io8 = new Empty()
|
|
280
|
+
}
|
|
162
281
|
}
|
|
163
282
|
|
|
164
283
|
//
|
|
165
284
|
// Methods
|
|
166
285
|
//
|
|
167
286
|
|
|
168
|
-
loadROM =
|
|
169
|
-
|
|
170
|
-
this.rom.load(Array.from(new Uint8Array(
|
|
171
|
-
}
|
|
172
|
-
|
|
287
|
+
loadROM = (data: Uint8Array | number[] | ArrayBuffer) => {
|
|
288
|
+
if (data instanceof ArrayBuffer) {
|
|
289
|
+
this.rom.load(Array.from(new Uint8Array(data)))
|
|
290
|
+
} else if (data instanceof Uint8Array) {
|
|
291
|
+
this.rom.load(Array.from(data))
|
|
292
|
+
} else {
|
|
293
|
+
this.rom.load(data)
|
|
173
294
|
}
|
|
174
295
|
}
|
|
175
296
|
|
|
176
|
-
loadCart =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
297
|
+
loadCart = (data: Uint8Array | number[] | ArrayBuffer) => {
|
|
298
|
+
let dataArray: number[]
|
|
299
|
+
if (data instanceof ArrayBuffer) {
|
|
300
|
+
dataArray = Array.from(new Uint8Array(data))
|
|
301
|
+
} else if (data instanceof Uint8Array) {
|
|
302
|
+
dataArray = Array.from(data)
|
|
303
|
+
} else {
|
|
304
|
+
dataArray = data
|
|
184
305
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
this.cpu.reset()
|
|
189
|
-
this.startTime = Date.now()
|
|
190
|
-
this.isRunning = true
|
|
191
|
-
this.isAlive = true
|
|
192
|
-
this.loop()
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
end(): void {
|
|
196
|
-
this.isRunning = false
|
|
197
|
-
this.isAlive = false
|
|
306
|
+
const cart = new Cart()
|
|
307
|
+
cart.load(dataArray)
|
|
308
|
+
this.cart = cart
|
|
198
309
|
}
|
|
199
310
|
|
|
200
311
|
run(): void {
|
|
201
312
|
this.isRunning = true
|
|
313
|
+
this.loop()
|
|
202
314
|
}
|
|
203
315
|
|
|
204
316
|
stop(): void {
|
|
205
317
|
this.isRunning = false
|
|
318
|
+
if (this.loopHandle) {
|
|
319
|
+
if (typeof clearImmediate !== 'undefined') {
|
|
320
|
+
clearImmediate(this.loopHandle as any)
|
|
321
|
+
} else {
|
|
322
|
+
clearTimeout(this.loopHandle as any)
|
|
323
|
+
}
|
|
324
|
+
this.loopHandle = undefined
|
|
325
|
+
}
|
|
206
326
|
}
|
|
207
327
|
|
|
208
328
|
step(): void {
|
|
@@ -211,12 +331,12 @@ export class Machine {
|
|
|
211
331
|
|
|
212
332
|
// Tick IO cards for each cycle of the instruction
|
|
213
333
|
for (let i = 0; i < cyclesExecuted; i++) {
|
|
214
|
-
//
|
|
334
|
+
// ACIA must be cycle-accurate
|
|
215
335
|
this.io5.tick(this.frequency)
|
|
216
336
|
|
|
217
337
|
this.ioCycleAccumulator++
|
|
218
338
|
if (this.ioCycleAccumulator >= this.ioTickInterval) {
|
|
219
|
-
// Skip ticking
|
|
339
|
+
// Skip ticking RAMBank IO1 and IO2 since they have no timing behavior
|
|
220
340
|
this.io3.tick(this.frequency)
|
|
221
341
|
this.io4.tick(this.frequency)
|
|
222
342
|
this.io6.tick(this.frequency)
|
|
@@ -227,17 +347,30 @@ export class Machine {
|
|
|
227
347
|
}
|
|
228
348
|
}
|
|
229
349
|
|
|
350
|
+
reset(coldStart: boolean): void {
|
|
351
|
+
this.cpu.reset()
|
|
352
|
+
this.ram.reset(coldStart)
|
|
353
|
+
this.io1.reset(coldStart)
|
|
354
|
+
this.io2.reset(coldStart)
|
|
355
|
+
this.io3.reset(coldStart)
|
|
356
|
+
this.io4.reset(coldStart)
|
|
357
|
+
this.io5.reset(coldStart)
|
|
358
|
+
this.io6.reset(coldStart)
|
|
359
|
+
this.io7.reset(coldStart)
|
|
360
|
+
this.io8.reset(coldStart)
|
|
361
|
+
}
|
|
362
|
+
|
|
230
363
|
tick(): void {
|
|
231
364
|
// Execute one CPU clock cycle
|
|
232
365
|
this.cpu.tick()
|
|
233
366
|
|
|
234
|
-
//
|
|
367
|
+
// ACIA must be cycle-accurate
|
|
235
368
|
this.io5.tick(this.frequency)
|
|
236
369
|
|
|
237
370
|
// Tick other IO cards at intervals
|
|
238
371
|
this.ioCycleAccumulator++
|
|
239
372
|
if (this.ioCycleAccumulator >= this.ioTickInterval) {
|
|
240
|
-
// Skip ticking
|
|
373
|
+
// Skip ticking RAMBank IO1 and IO2 since they have no timing behavior
|
|
241
374
|
this.io3.tick(this.frequency)
|
|
242
375
|
this.io4.tick(this.frequency)
|
|
243
376
|
this.io6.tick(this.frequency)
|
|
@@ -248,22 +381,24 @@ export class Machine {
|
|
|
248
381
|
}
|
|
249
382
|
|
|
250
383
|
onReceive(data: number): void {
|
|
251
|
-
this.
|
|
384
|
+
if (this.target !== 'vcs') {
|
|
385
|
+
(this.io5 as ACIA).onData(data) // Pass data to Serial card
|
|
386
|
+
}
|
|
252
387
|
}
|
|
253
388
|
|
|
254
389
|
onKeyDown(scancode: number): void {
|
|
255
|
-
if (this.kim) {
|
|
390
|
+
if (this.target === 'kim') {
|
|
256
391
|
this.keypadAttachment?.updateKey(scancode, true)
|
|
257
392
|
} else {
|
|
258
|
-
this.keyboardMatrixAttachment
|
|
259
|
-
this.keyboardEncoderAttachment
|
|
393
|
+
this.keyboardMatrixAttachment?.updateKey(scancode, true)
|
|
394
|
+
this.keyboardEncoderAttachment?.updateKey(scancode, true)
|
|
260
395
|
}
|
|
261
396
|
}
|
|
262
397
|
|
|
263
398
|
onKeyUp(scancode: number): void {
|
|
264
|
-
if (
|
|
265
|
-
this.keyboardMatrixAttachment
|
|
266
|
-
this.keyboardEncoderAttachment
|
|
399
|
+
if (this.target !== 'kim') {
|
|
400
|
+
this.keyboardMatrixAttachment?.updateKey(scancode, false)
|
|
401
|
+
this.keyboardEncoderAttachment?.updateKey(scancode, false)
|
|
267
402
|
}
|
|
268
403
|
}
|
|
269
404
|
|
|
@@ -280,8 +415,6 @@ export class Machine {
|
|
|
280
415
|
//
|
|
281
416
|
|
|
282
417
|
private loop(): void {
|
|
283
|
-
if (!this.isAlive) { return }
|
|
284
|
-
|
|
285
418
|
const now = performance.now()
|
|
286
419
|
const elapsedMs = now - this.previousTime
|
|
287
420
|
this.previousTime = now
|
|
@@ -299,12 +432,12 @@ export class Machine {
|
|
|
299
432
|
for (let i = 0; i < ticksToRun; i++) {
|
|
300
433
|
this.cpu.tick()
|
|
301
434
|
|
|
302
|
-
//
|
|
435
|
+
// ACIA must be cycle-accurate
|
|
303
436
|
this.io5.tick(this.frequency)
|
|
304
437
|
|
|
305
438
|
this.ioCycleAccumulator++
|
|
306
439
|
if (this.ioCycleAccumulator >= this.ioTickInterval) {
|
|
307
|
-
// Skip ticking
|
|
440
|
+
// Skip ticking RAMBank IO1 and IO2 since they have no timing behavior
|
|
308
441
|
this.io3.tick(this.frequency)
|
|
309
442
|
this.io4.tick(this.frequency)
|
|
310
443
|
this.io6.tick(this.frequency)
|
|
@@ -319,38 +452,31 @@ export class Machine {
|
|
|
319
452
|
(this as any)._accumulatorMs = accumulator
|
|
320
453
|
}
|
|
321
454
|
|
|
322
|
-
if (this.render &&
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
455
|
+
if (this.render && (this.target === 'kim' || this.target === 'dev')) {
|
|
456
|
+
this.render()
|
|
457
|
+
this.frames += 1
|
|
458
|
+
} else if (this.render && (this.target === 'cob' || this.target === 'vcs')) {
|
|
459
|
+
const Video = this.io8 as Video
|
|
460
|
+
if (Video.frameReady) {
|
|
461
|
+
Video.frameReady = false
|
|
326
462
|
this.render()
|
|
327
463
|
this.frames += 1
|
|
328
464
|
}
|
|
329
|
-
} else if (this.render && this.kim) {
|
|
330
|
-
this.render()
|
|
331
|
-
this.frames += 1
|
|
332
465
|
}
|
|
333
466
|
|
|
334
|
-
|
|
467
|
+
if (this.isRunning) {
|
|
468
|
+
if (typeof setImmediate !== 'undefined') {
|
|
469
|
+
this.loopHandle = setImmediate(() => this.loop())
|
|
470
|
+
} else {
|
|
471
|
+
this.loopHandle = setTimeout(() => this.loop(), 0)
|
|
472
|
+
}
|
|
473
|
+
}
|
|
335
474
|
}
|
|
336
475
|
|
|
337
476
|
//
|
|
338
477
|
// Bus Operations
|
|
339
478
|
//
|
|
340
479
|
|
|
341
|
-
reset(coldStart: boolean): void {
|
|
342
|
-
this.cpu.reset()
|
|
343
|
-
this.ram.reset(coldStart)
|
|
344
|
-
this.io1.reset(coldStart)
|
|
345
|
-
this.io2.reset(coldStart)
|
|
346
|
-
this.io3.reset(coldStart)
|
|
347
|
-
this.io4.reset(coldStart)
|
|
348
|
-
this.io5.reset(coldStart)
|
|
349
|
-
this.io6.reset(coldStart)
|
|
350
|
-
this.io7.reset(coldStart)
|
|
351
|
-
this.io8.reset(coldStart)
|
|
352
|
-
}
|
|
353
|
-
|
|
354
480
|
read(address: number): number {
|
|
355
481
|
switch(true) {
|
|
356
482
|
case (this.cart && address >= Cart.CODE && address <= Cart.END):
|