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
package/src/index.ts
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import figlet from 'figlet'
|
|
4
4
|
import { Machine } from './components/Machine'
|
|
5
|
-
import { Command } from 'commander'
|
|
5
|
+
import { Command, Option } from 'commander'
|
|
6
6
|
import { SerialPort } from 'serialport'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { Video } from './components/IO/Video'
|
|
8
|
+
import { Terminal } from './components/IO/Terminal'
|
|
9
|
+
import { Storage } from './components/IO/Storage'
|
|
10
|
+
import { Sound } from './components/IO/Sound'
|
|
10
11
|
import sdl from '@kmamal/sdl'
|
|
12
|
+
import { readFile, writeFile } from 'fs/promises'
|
|
13
|
+
import { existsSync } from 'fs'
|
|
11
14
|
|
|
12
|
-
const VERSION = '1.
|
|
15
|
+
const VERSION = '1.4.0'
|
|
13
16
|
const WIDTH = 320
|
|
14
17
|
const HEIGHT = 240
|
|
15
18
|
|
|
@@ -19,7 +22,7 @@ const AUDIO_CHANNELS = 1
|
|
|
19
22
|
const AUDIO_FORMAT = 'f32'
|
|
20
23
|
const AUDIO_BUFFERED = 2048
|
|
21
24
|
|
|
22
|
-
// Joystick button bit masks (matching
|
|
25
|
+
// Joystick button bit masks (matching JoystickAttachment)
|
|
23
26
|
const BUTTON_UP = 0x01
|
|
24
27
|
const BUTTON_DOWN = 0x02
|
|
25
28
|
const BUTTON_LEFT = 0x04
|
|
@@ -43,7 +46,7 @@ interface EmulatorOptions {
|
|
|
43
46
|
stopbits?: string
|
|
44
47
|
port?: string
|
|
45
48
|
storage?: string
|
|
46
|
-
|
|
49
|
+
target?: string
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
class Emulator {
|
|
@@ -58,7 +61,7 @@ class Emulator {
|
|
|
58
61
|
|
|
59
62
|
constructor(options: EmulatorOptions) {
|
|
60
63
|
this.options = options
|
|
61
|
-
this.machine = new Machine(options.
|
|
64
|
+
this.machine = new Machine(options.target ?? 'cob')
|
|
62
65
|
this.controllers = new Map()
|
|
63
66
|
this.joystickButtonStateA = 0x00
|
|
64
67
|
this.joystickButtonStateB = 0x00
|
|
@@ -91,21 +94,30 @@ class Emulator {
|
|
|
91
94
|
|
|
92
95
|
private async loadBinaries(): Promise<void> {
|
|
93
96
|
if (this.options.rom) {
|
|
94
|
-
await
|
|
97
|
+
const romData = await readFile(this.options.rom)
|
|
98
|
+
this.machine.loadROM(new Uint8Array(romData))
|
|
95
99
|
console.log(`Loaded ROM: ${this.options.rom}`)
|
|
96
100
|
} else {
|
|
97
101
|
console.log('Loaded ROM: NONE')
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
if (this.options.cart) {
|
|
101
|
-
await
|
|
105
|
+
const cartData = await readFile(this.options.cart)
|
|
106
|
+
this.machine.loadCart(new Uint8Array(cartData))
|
|
102
107
|
console.log(`Loaded Cart: ${this.options.cart}`)
|
|
103
108
|
} else {
|
|
104
109
|
console.log('Loaded Cart: NONE')
|
|
105
110
|
}
|
|
106
111
|
|
|
107
|
-
if (this.options.storage &&
|
|
108
|
-
|
|
112
|
+
if (this.options.storage && this.options.target !== 'kim') {
|
|
113
|
+
if (existsSync(this.options.storage)) {
|
|
114
|
+
const storageData = await readFile(this.options.storage)
|
|
115
|
+
;(this.machine.io4 as Storage).loadData(new Uint8Array(storageData))
|
|
116
|
+
} else {
|
|
117
|
+
console.log(`Storage file not found: ${this.options.storage}`)
|
|
118
|
+
console.log('A new storage file will be created on exit.')
|
|
119
|
+
;(this.machine.io4 as Storage).loadData(null)
|
|
120
|
+
}
|
|
109
121
|
}
|
|
110
122
|
}
|
|
111
123
|
|
|
@@ -183,7 +195,7 @@ class Emulator {
|
|
|
183
195
|
}
|
|
184
196
|
|
|
185
197
|
private setupAudio(): void {
|
|
186
|
-
if (this.options.kim) return
|
|
198
|
+
if (this.options.target === 'kim' || this.options.target === 'dev') return
|
|
187
199
|
try {
|
|
188
200
|
this.audioDevice = sdl.audio.openDevice({ type: 'playback' }, {
|
|
189
201
|
channels: AUDIO_CHANNELS as 1,
|
|
@@ -192,11 +204,11 @@ class Emulator {
|
|
|
192
204
|
buffered: AUDIO_BUFFERED,
|
|
193
205
|
})
|
|
194
206
|
|
|
195
|
-
// Configure
|
|
196
|
-
;(this.machine.io7 as
|
|
207
|
+
// Configure Sound sample rate to match audio device
|
|
208
|
+
;(this.machine.io7 as Sound).sampleRate = this.audioDevice.frequency
|
|
197
209
|
|
|
198
210
|
// Connect the Machine's audio callback to the SDL audio device
|
|
199
|
-
this.machine.
|
|
211
|
+
this.machine.play = (samples: Float32Array) => {
|
|
200
212
|
if (!this.audioDevice || this.audioDevice.closed) return
|
|
201
213
|
|
|
202
214
|
const { channels, bytesPerSample } = this.audioDevice
|
|
@@ -218,7 +230,7 @@ class Emulator {
|
|
|
218
230
|
}
|
|
219
231
|
|
|
220
232
|
private setupWindow(): void {
|
|
221
|
-
const isKIM = this.options.
|
|
233
|
+
const isKIM = this.options.target === 'kim'
|
|
222
234
|
const lcd = this.machine.lcdAttachment
|
|
223
235
|
|
|
224
236
|
// LCD dot-matrix rendering constants
|
|
@@ -238,7 +250,7 @@ class Emulator {
|
|
|
238
250
|
}
|
|
239
251
|
|
|
240
252
|
this.window = sdl.video.createWindow({
|
|
241
|
-
title:
|
|
253
|
+
title: `6502 Emulator (${(this.options.target ?? 'cob').toUpperCase()})`,
|
|
242
254
|
width: windowWidth * this.machine.scale,
|
|
243
255
|
height: windowHeight * this.machine.scale,
|
|
244
256
|
accelerated: true,
|
|
@@ -320,11 +332,27 @@ class Emulator {
|
|
|
320
332
|
|
|
321
333
|
this.window.render(renderWidth, renderHeight, renderWidth * 4, 'rgba32', rgbaBuffer)
|
|
322
334
|
}
|
|
323
|
-
} else {
|
|
324
|
-
const
|
|
335
|
+
} else if (this.options.target === 'cob' || this.options.target === 'vcs') {
|
|
336
|
+
const Video = this.machine.io8 as Video
|
|
337
|
+
this.machine.render = () => {
|
|
338
|
+
if (!this.window) { return }
|
|
339
|
+
this.window.render(WIDTH, HEIGHT, WIDTH * 4, 'rgba32', Video.buffer)
|
|
340
|
+
}
|
|
341
|
+
} else if (this.options.target === 'dev') {
|
|
342
|
+
const devBoard = this.machine.io8 as Terminal
|
|
343
|
+
const rgbaBuffer = Buffer.alloc(WIDTH * HEIGHT * 4)
|
|
325
344
|
this.machine.render = () => {
|
|
326
345
|
if (!this.window) { return }
|
|
327
|
-
|
|
346
|
+
const src = devBoard.vtac.buffer
|
|
347
|
+
for (let i = 0; i < WIDTH * HEIGHT; i++) {
|
|
348
|
+
const v = src[i]
|
|
349
|
+
const off = i * 4
|
|
350
|
+
rgbaBuffer[off] = v
|
|
351
|
+
rgbaBuffer[off + 1] = v
|
|
352
|
+
rgbaBuffer[off + 2] = v
|
|
353
|
+
rgbaBuffer[off + 3] = 0xFF
|
|
354
|
+
}
|
|
355
|
+
this.window.render(WIDTH, HEIGHT, WIDTH * 4, 'rgba32', rgbaBuffer)
|
|
328
356
|
}
|
|
329
357
|
}
|
|
330
358
|
|
|
@@ -337,7 +365,7 @@ class Emulator {
|
|
|
337
365
|
}
|
|
338
366
|
|
|
339
367
|
private setupControllers(): void {
|
|
340
|
-
if (this.options.kim) return
|
|
368
|
+
if (this.options.target === 'kim') return
|
|
341
369
|
// Controller device add/remove handlers
|
|
342
370
|
(sdl.controller as any).on('deviceAdd', (device: any) => {
|
|
343
371
|
console.log(`Controller added: ${device.name || device.id}`)
|
|
@@ -499,7 +527,6 @@ class Emulator {
|
|
|
499
527
|
}
|
|
500
528
|
})
|
|
501
529
|
}
|
|
502
|
-
this.machine.end()
|
|
503
530
|
|
|
504
531
|
const uptime = Date.now() - this.machine.startTime
|
|
505
532
|
|
|
@@ -513,10 +540,13 @@ class Emulator {
|
|
|
513
540
|
})
|
|
514
541
|
|
|
515
542
|
// Save storage data if path was provided
|
|
516
|
-
if (this.options.storage &&
|
|
517
|
-
(this.machine.io4 as
|
|
543
|
+
if (this.options.storage && this.options.target !== 'kim') {
|
|
544
|
+
const storageData = (this.machine.io4 as Storage).getData()
|
|
545
|
+
writeFile(this.options.storage, storageData).then(() => {
|
|
546
|
+
console.log(`Storage saved to: ${this.options.storage}`)
|
|
518
547
|
process.exit(0)
|
|
519
|
-
}).catch(() => {
|
|
548
|
+
}).catch((error) => {
|
|
549
|
+
console.error('Error saving storage file:', error)
|
|
520
550
|
process.exit(1)
|
|
521
551
|
})
|
|
522
552
|
} else {
|
|
@@ -524,8 +554,8 @@ class Emulator {
|
|
|
524
554
|
}
|
|
525
555
|
}
|
|
526
556
|
|
|
527
|
-
|
|
528
|
-
this.machine.
|
|
557
|
+
run(): void {
|
|
558
|
+
this.machine.run()
|
|
529
559
|
}
|
|
530
560
|
}
|
|
531
561
|
|
|
@@ -536,17 +566,17 @@ program
|
|
|
536
566
|
.description('Emulator for the A.C. Wright 6502 project.')
|
|
537
567
|
.version(VERSION, '-v, --version', 'Output the current emulator version')
|
|
538
568
|
.helpOption('-h, --help', 'Output help / options')
|
|
569
|
+
.option('-a, --parity <parity>', 'Parity (odd | even | none)', 'none')
|
|
570
|
+
.option('-b, --baudrate <baudrate>', 'Baud Rate', '9600')
|
|
539
571
|
.option('-c, --cart <path>', 'Path to 32K Cart binary file')
|
|
572
|
+
.option('-d, --databits <databits>', 'Data Bits (5 | 6 | 7 | 8)', '8')
|
|
540
573
|
.option('-f, --freq <freq>', 'Set the clock frequency in Hz', '1000000')
|
|
574
|
+
.option('-p, --port <port>', 'Path to the serial port (e.g., /dev/ttyUSB0)')
|
|
541
575
|
.option('-r, --rom <path>', 'Path to 32K ROM binary file')
|
|
542
576
|
.option('-s, --scale <scale>', 'Set the emulator scale', '2')
|
|
543
|
-
.option('-b, --baudrate <baudrate>', 'Baud Rate', '9600')
|
|
544
|
-
.option('-a, --parity <parity>', 'Parity (odd | even | none)', 'none')
|
|
545
|
-
.option('-d, --databits <databits>', 'Data Bits (5 | 6 | 7 | 8)', '8')
|
|
546
|
-
.option('-t, --stopbits <stopbits>', 'Stop Bits (1 | 1.5 | 2)', '1')
|
|
547
|
-
.option('-p, --port <port>', 'Path to the serial port (e.g., /dev/ttyUSB0)')
|
|
548
577
|
.option('-S, --storage <path>', 'Path to storage data file for Compact Flash card persistence')
|
|
549
|
-
.option('-
|
|
578
|
+
.option('-t, --stopbits <stopbits>', 'Stop Bits (1 | 1.5 | 2)', '1')
|
|
579
|
+
.addOption(new Option('-T, --target <target>', 'System target').choices(['cob', 'vcs', 'kim', 'dev']).default('cob'))
|
|
550
580
|
.addHelpText('beforeAll', figlet.textSync('6502 Emulator', { font: 'cricket' }) + '\n' + `Version: ${VERSION} | A.C. Wright Design\n`)
|
|
551
581
|
.parse(process.argv)
|
|
552
582
|
|
|
@@ -556,7 +586,7 @@ const options = program.opts()
|
|
|
556
586
|
async function main() {
|
|
557
587
|
const emulator = new Emulator(options)
|
|
558
588
|
await emulator.initialize()
|
|
559
|
-
emulator.
|
|
589
|
+
emulator.run()
|
|
560
590
|
}
|
|
561
591
|
|
|
562
592
|
// Run the main function
|
package/src/lib.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Core components
|
|
2
|
+
export { Machine } from './components/Machine'
|
|
3
|
+
export { CPU } from './components/CPU'
|
|
4
|
+
export { RAM } from './components/RAM'
|
|
5
|
+
export { ROM } from './components/ROM'
|
|
6
|
+
export { Cart } from './components/Cart'
|
|
7
|
+
export type { IO } from './components/IO'
|
|
8
|
+
|
|
9
|
+
// IO cards
|
|
10
|
+
export { Empty } from './components/IO/Empty'
|
|
11
|
+
export { VIA } from './components/IO/VIA'
|
|
12
|
+
export { RAMBank } from './components/IO/RAMBank'
|
|
13
|
+
export { RTC } from './components/IO/RTC'
|
|
14
|
+
export { ACIA } from './components/IO/ACIA'
|
|
15
|
+
export { SIDVoice, Sound } from './components/IO/Sound'
|
|
16
|
+
export { Storage } from './components/IO/Storage'
|
|
17
|
+
export { Video } from './components/IO/Video'
|
|
18
|
+
export { Terminal } from './components/IO/Terminal'
|
|
19
|
+
|
|
20
|
+
// GPIO attachments
|
|
21
|
+
export type { Attachment } from './components/IO/Attachments/Attachment'
|
|
22
|
+
export { AttachmentBase } from './components/IO/Attachments/Attachment'
|
|
23
|
+
export { JoystickAttachment } from './components/IO/Attachments/JoystickAttachment'
|
|
24
|
+
export { KeyboardEncoderAttachment } from './components/IO/Attachments/KeyboardEncoderAttachment'
|
|
25
|
+
export { KeyboardMatrixAttachment } from './components/IO/Attachments/KeyboardMatrixAttachment'
|
|
26
|
+
export { KeypadAttachment } from './components/IO/Attachments/KeypadAttachment'
|
|
27
|
+
export { LCDAttachment } from './components/IO/Attachments/LCDAttachment'
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ACIA } from '../../components/IO/ACIA'
|
|
2
2
|
|
|
3
|
-
describe('
|
|
4
|
-
let serialCard:
|
|
3
|
+
describe('ACIA (6551 ACIA)', () => {
|
|
4
|
+
let serialCard: ACIA
|
|
5
5
|
|
|
6
6
|
beforeEach(() => {
|
|
7
|
-
serialCard = new
|
|
7
|
+
serialCard = new ACIA()
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
describe('Initialization', () => {
|
|
@@ -399,7 +399,7 @@ describe('SerialCard (6551 ACIA)', () => {
|
|
|
399
399
|
]
|
|
400
400
|
|
|
401
401
|
baudRates.forEach(([code, rate]) => {
|
|
402
|
-
const card = new
|
|
402
|
+
const card = new ACIA()
|
|
403
403
|
card.write(0x03, code as number) // Control register with baud rate code
|
|
404
404
|
// Baud rate affects tick timing - verify no errors occur
|
|
405
405
|
})
|
package/src/tests/IO/{GPIOAttachments/GPIOAttachment.test.ts → Attachments/Attachment.test.ts}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Attachment, AttachmentBase } from '../../../components/IO/Attachments/Attachment'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Concrete implementation of
|
|
4
|
+
* Concrete implementation of AttachmentBase for testing
|
|
5
5
|
*/
|
|
6
|
-
class
|
|
6
|
+
class TestAttachment extends AttachmentBase {
|
|
7
7
|
public portAValue: number = 0xFF
|
|
8
8
|
public portBValue: number = 0xFF
|
|
9
9
|
public tickCount: number = 0
|
|
@@ -62,11 +62,11 @@ class TestGPIOAttachment extends GPIOAttachmentBase {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
describe('
|
|
66
|
-
let attachment:
|
|
65
|
+
describe('AttachmentBase', () => {
|
|
66
|
+
let attachment: TestAttachment
|
|
67
67
|
|
|
68
68
|
beforeEach(() => {
|
|
69
|
-
attachment = new
|
|
69
|
+
attachment = new TestAttachment()
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
describe('Initialization', () => {
|
|
@@ -75,7 +75,7 @@ describe('GPIOAttachmentBase', () => {
|
|
|
75
75
|
})
|
|
76
76
|
|
|
77
77
|
it('should initialize with custom priority', () => {
|
|
78
|
-
const customAttachment = new
|
|
78
|
+
const customAttachment = new TestAttachment(5)
|
|
79
79
|
expect(customAttachment.getPriority()).toBe(5)
|
|
80
80
|
})
|
|
81
81
|
|
|
@@ -91,7 +91,7 @@ describe('GPIOAttachmentBase', () => {
|
|
|
91
91
|
})
|
|
92
92
|
|
|
93
93
|
it('should initialize with specified interrupt states', () => {
|
|
94
|
-
const interruptAttachment = new
|
|
94
|
+
const interruptAttachment = new TestAttachment(0, true, true, true, true)
|
|
95
95
|
expect(interruptAttachment.hasCA1Interrupt()).toBe(true)
|
|
96
96
|
expect(interruptAttachment.hasCA2Interrupt()).toBe(true)
|
|
97
97
|
expect(interruptAttachment.hasCB1Interrupt()).toBe(true)
|
|
@@ -121,7 +121,7 @@ describe('GPIOAttachmentBase', () => {
|
|
|
121
121
|
})
|
|
122
122
|
|
|
123
123
|
it('should maintain priority after reset', () => {
|
|
124
|
-
const priorityAttachment = new
|
|
124
|
+
const priorityAttachment = new TestAttachment(10)
|
|
125
125
|
priorityAttachment.reset()
|
|
126
126
|
expect(priorityAttachment.getPriority()).toBe(10)
|
|
127
127
|
})
|
|
@@ -129,15 +129,15 @@ describe('GPIOAttachmentBase', () => {
|
|
|
129
129
|
|
|
130
130
|
describe('Priority', () => {
|
|
131
131
|
it('should return correct priority value', () => {
|
|
132
|
-
const lowPriority = new
|
|
133
|
-
const highPriority = new
|
|
132
|
+
const lowPriority = new TestAttachment(0)
|
|
133
|
+
const highPriority = new TestAttachment(10)
|
|
134
134
|
|
|
135
135
|
expect(lowPriority.getPriority()).toBe(0)
|
|
136
136
|
expect(highPriority.getPriority()).toBe(10)
|
|
137
137
|
})
|
|
138
138
|
|
|
139
139
|
it('should support negative priority values', () => {
|
|
140
|
-
const negativePriority = new
|
|
140
|
+
const negativePriority = new TestAttachment(-5)
|
|
141
141
|
expect(negativePriority.getPriority()).toBe(-5)
|
|
142
142
|
})
|
|
143
143
|
})
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JoystickAttachment } from '../../../components/IO/Attachments/JoystickAttachment'
|
|
2
2
|
|
|
3
|
-
describe('
|
|
4
|
-
let joystick:
|
|
3
|
+
describe('JoystickAttachment', () => {
|
|
4
|
+
let joystick: JoystickAttachment
|
|
5
5
|
|
|
6
6
|
beforeEach(() => {
|
|
7
|
-
joystick = new
|
|
7
|
+
joystick = new JoystickAttachment(true, 0)
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
describe('constructor and reset', () => {
|
|
@@ -26,20 +26,20 @@ describe('GPIOJoystickAttachment', () => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
it('should check if button is pressed', () => {
|
|
29
|
-
joystick.pressButton(
|
|
30
|
-
expect(joystick.isButtonPressed(
|
|
31
|
-
expect(joystick.isButtonPressed(
|
|
29
|
+
joystick.pressButton(JoystickAttachment.BUTTON_A)
|
|
30
|
+
expect(joystick.isButtonPressed(JoystickAttachment.BUTTON_A)).toBe(true)
|
|
31
|
+
expect(joystick.isButtonPressed(JoystickAttachment.BUTTON_B)).toBe(false)
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
it('should press a button', () => {
|
|
35
|
-
joystick.pressButton(
|
|
36
|
-
expect(joystick.getButtonState()).toBe(
|
|
35
|
+
joystick.pressButton(JoystickAttachment.BUTTON_START)
|
|
36
|
+
expect(joystick.getButtonState()).toBe(JoystickAttachment.BUTTON_START)
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
it('should release a button', () => {
|
|
40
40
|
joystick.updateJoystick(0xFF)
|
|
41
|
-
joystick.releaseButton(
|
|
42
|
-
expect(joystick.getButtonState()).toBe(0xFF & ~
|
|
41
|
+
joystick.releaseButton(JoystickAttachment.BUTTON_A)
|
|
42
|
+
expect(joystick.getButtonState()).toBe(0xFF & ~JoystickAttachment.BUTTON_A)
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
it('should release all buttons', () => {
|
|
@@ -51,7 +51,7 @@ describe('GPIOJoystickAttachment', () => {
|
|
|
51
51
|
|
|
52
52
|
describe('port reading - Port A', () => {
|
|
53
53
|
beforeEach(() => {
|
|
54
|
-
joystick = new
|
|
54
|
+
joystick = new JoystickAttachment(true, 0) // Attach to Port A
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
it('should return inverted button state on Port A when attached', () => {
|
|
@@ -70,7 +70,7 @@ describe('GPIOJoystickAttachment', () => {
|
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
it('should handle individual button presses correctly', () => {
|
|
73
|
-
joystick.updateJoystick(
|
|
73
|
+
joystick.updateJoystick(JoystickAttachment.BUTTON_UP)
|
|
74
74
|
const result = joystick.readPortA(0x00, 0x00)
|
|
75
75
|
expect(result & 0x01).toBe(0x00) // UP button bit should be low (pressed)
|
|
76
76
|
expect(result & 0xFE).toBe(0xFE) // Other bits should be high (not pressed)
|
|
@@ -79,7 +79,7 @@ describe('GPIOJoystickAttachment', () => {
|
|
|
79
79
|
|
|
80
80
|
describe('port reading - Port B', () => {
|
|
81
81
|
beforeEach(() => {
|
|
82
|
-
joystick = new
|
|
82
|
+
joystick = new JoystickAttachment(false, 0) // Attach to Port B
|
|
83
83
|
})
|
|
84
84
|
|
|
85
85
|
it('should return inverted button state on Port B when attached', () => {
|
|
@@ -100,20 +100,20 @@ describe('GPIOJoystickAttachment', () => {
|
|
|
100
100
|
|
|
101
101
|
describe('button constants', () => {
|
|
102
102
|
it('should have correct button bit values', () => {
|
|
103
|
-
expect(
|
|
104
|
-
expect(
|
|
105
|
-
expect(
|
|
106
|
-
expect(
|
|
107
|
-
expect(
|
|
108
|
-
expect(
|
|
109
|
-
expect(
|
|
110
|
-
expect(
|
|
103
|
+
expect(JoystickAttachment.BUTTON_UP).toBe(0x01)
|
|
104
|
+
expect(JoystickAttachment.BUTTON_DOWN).toBe(0x02)
|
|
105
|
+
expect(JoystickAttachment.BUTTON_LEFT).toBe(0x04)
|
|
106
|
+
expect(JoystickAttachment.BUTTON_RIGHT).toBe(0x08)
|
|
107
|
+
expect(JoystickAttachment.BUTTON_A).toBe(0x10)
|
|
108
|
+
expect(JoystickAttachment.BUTTON_B).toBe(0x20)
|
|
109
|
+
expect(JoystickAttachment.BUTTON_SELECT).toBe(0x40)
|
|
110
|
+
expect(JoystickAttachment.BUTTON_START).toBe(0x80)
|
|
111
111
|
})
|
|
112
112
|
})
|
|
113
113
|
|
|
114
114
|
describe('priority and enabled', () => {
|
|
115
115
|
it('should return correct priority', () => {
|
|
116
|
-
const j = new
|
|
116
|
+
const j = new JoystickAttachment(true, 5)
|
|
117
117
|
expect(j.getPriority()).toBe(5)
|
|
118
118
|
})
|
|
119
119
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { KeyboardEncoderAttachment } from '../../../components/IO/Attachments/KeyboardEncoderAttachment'
|
|
2
2
|
|
|
3
|
-
describe('
|
|
4
|
-
let encoder:
|
|
3
|
+
describe('KeyboardEncoderAttachment', () => {
|
|
4
|
+
let encoder: KeyboardEncoderAttachment
|
|
5
5
|
|
|
6
6
|
beforeEach(() => {
|
|
7
|
-
encoder = new
|
|
7
|
+
encoder = new KeyboardEncoderAttachment(5)
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
describe('Initialization', () => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { KeyboardMatrixAttachment } from '../../../components/IO/Attachments/KeyboardMatrixAttachment'
|
|
2
2
|
|
|
3
|
-
describe('
|
|
4
|
-
let keyboard:
|
|
3
|
+
describe('KeyboardMatrixAttachment', () => {
|
|
4
|
+
let keyboard: KeyboardMatrixAttachment
|
|
5
5
|
|
|
6
6
|
beforeEach(() => {
|
|
7
|
-
keyboard = new
|
|
7
|
+
keyboard = new KeyboardMatrixAttachment(0)
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
describe('Initialization', () => {
|
|
@@ -22,7 +22,7 @@ describe('GPIOKeyboardMatrixAttachment', () => {
|
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
it('should have correct priority', () => {
|
|
25
|
-
const kb = new
|
|
25
|
+
const kb = new KeyboardMatrixAttachment(5)
|
|
26
26
|
expect(kb.getPriority()).toBe(5)
|
|
27
27
|
})
|
|
28
28
|
})
|