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