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.
Files changed (182) hide show
  1. package/README.md +12 -12
  2. package/dist/components/CPU.d.ts +162 -0
  3. package/dist/components/Cart.d.ts +9 -0
  4. package/dist/components/IO/ACIA.d.ts +76 -0
  5. package/dist/components/IO/ACIA.js +282 -0
  6. package/dist/components/IO/ACIA.js.map +1 -0
  7. package/dist/components/IO/Attachments/Attachment.d.ts +112 -0
  8. package/dist/components/IO/Attachments/Attachment.js +71 -0
  9. package/dist/components/IO/Attachments/Attachment.js.map +1 -0
  10. package/dist/components/IO/Attachments/JoystickAttachment.d.ts +53 -0
  11. package/dist/components/IO/Attachments/JoystickAttachment.js +90 -0
  12. package/dist/components/IO/Attachments/JoystickAttachment.js.map +1 -0
  13. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.d.ts +63 -0
  14. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js +489 -0
  15. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js.map +1 -0
  16. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.d.ts +44 -0
  17. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js +274 -0
  18. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js.map +1 -0
  19. package/dist/components/IO/Attachments/KeypadAttachment.d.ts +47 -0
  20. package/dist/components/IO/Attachments/KeypadAttachment.js +141 -0
  21. package/dist/components/IO/Attachments/KeypadAttachment.js.map +1 -0
  22. package/dist/components/IO/Attachments/LCDAttachment.d.ts +110 -0
  23. package/dist/components/IO/Attachments/LCDAttachment.js +716 -0
  24. package/dist/components/IO/Attachments/LCDAttachment.js.map +1 -0
  25. package/dist/components/IO/Attachments/SNESAttachment.d.ts +85 -0
  26. package/dist/components/IO/Attachments/SNESAttachment.js +184 -0
  27. package/dist/components/IO/Attachments/SNESAttachment.js.map +1 -0
  28. package/dist/components/IO/DevOutputBoard.d.ts +19 -0
  29. package/dist/components/IO/DevOutputBoard.js +33 -0
  30. package/dist/components/IO/DevOutputBoard.js.map +1 -0
  31. package/dist/components/IO/Empty.d.ts +9 -0
  32. package/dist/components/IO/Empty.js +5 -7
  33. package/dist/components/IO/Empty.js.map +1 -1
  34. package/dist/components/IO/EmptyCard.d.ts +9 -0
  35. package/dist/components/IO/GPIOAttachments/GPIOAttachment.d.ts +112 -0
  36. package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.d.ts +53 -0
  37. package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.d.ts +63 -0
  38. package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.d.ts +44 -0
  39. package/dist/components/IO/GPIOAttachments/GPIOKeypadAttachment.d.ts +47 -0
  40. package/dist/components/IO/GPIOAttachments/GPIOLCDAttachment.d.ts +110 -0
  41. package/dist/components/IO/GPIOCard.d.ts +105 -0
  42. package/dist/components/IO/GPIOCard.js.map +1 -1
  43. package/dist/components/IO/RAMBank.d.ts +37 -0
  44. package/dist/components/IO/RAMBank.js +63 -0
  45. package/dist/components/IO/RAMBank.js.map +1 -0
  46. package/dist/components/IO/RAMCard.d.ts +37 -0
  47. package/dist/components/IO/RTC.d.ts +107 -0
  48. package/dist/components/IO/RTC.js +483 -0
  49. package/dist/components/IO/RTC.js.map +1 -0
  50. package/dist/components/IO/RTCCard.d.ts +107 -0
  51. package/dist/components/IO/SerialCard.d.ts +76 -0
  52. package/dist/components/IO/Sound.d.ts +120 -0
  53. package/dist/components/IO/Sound.js +622 -0
  54. package/dist/components/IO/Sound.js.map +1 -0
  55. package/dist/components/IO/SoundCard.d.ts +120 -0
  56. package/dist/components/IO/Storage.d.ts +74 -0
  57. package/dist/components/IO/Storage.js +409 -0
  58. package/dist/components/IO/Storage.js.map +1 -0
  59. package/dist/components/IO/StorageCard.d.ts +74 -0
  60. package/dist/components/IO/Terminal.d.ts +19 -0
  61. package/dist/components/IO/Terminal.js +33 -0
  62. package/dist/components/IO/Terminal.js.map +1 -0
  63. package/dist/components/IO/VIA.d.ts +105 -0
  64. package/dist/components/IO/VIA.js +597 -0
  65. package/dist/components/IO/VIA.js.map +1 -0
  66. package/dist/components/IO/Video.d.ts +141 -0
  67. package/dist/components/IO/Video.js +630 -0
  68. package/dist/components/IO/Video.js.map +1 -0
  69. package/dist/components/IO/VideoCard.d.ts +141 -0
  70. package/dist/components/IO.d.ts +8 -0
  71. package/dist/components/Machine.d.ts +62 -0
  72. package/dist/components/Machine.js +260 -153
  73. package/dist/components/Machine.js.map +1 -1
  74. package/dist/components/RAM.d.ts +9 -0
  75. package/dist/components/ROM.d.ts +9 -0
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.js +61 -28
  78. package/dist/index.js.map +1 -1
  79. package/dist/lib.d.ts +22 -0
  80. package/dist/lib.js +47 -0
  81. package/dist/lib.js.map +1 -0
  82. package/dist/tests/CPU.test.d.ts +1 -0
  83. package/dist/tests/Cart.test.d.ts +1 -0
  84. package/dist/tests/IO/ACIA.test.d.ts +1 -0
  85. package/dist/tests/IO/ACIA.test.js +423 -0
  86. package/dist/tests/IO/ACIA.test.js.map +1 -0
  87. package/dist/tests/IO/Attachments/Attachment.test.d.ts +1 -0
  88. package/dist/tests/IO/Attachments/Attachment.test.js +339 -0
  89. package/dist/tests/IO/Attachments/Attachment.test.js.map +1 -0
  90. package/dist/tests/IO/Attachments/JoystickAttachment.test.d.ts +1 -0
  91. package/dist/tests/IO/Attachments/JoystickAttachment.test.js +126 -0
  92. package/dist/tests/IO/Attachments/JoystickAttachment.test.js.map +1 -0
  93. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.d.ts +1 -0
  94. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js +779 -0
  95. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js.map +1 -0
  96. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.d.ts +1 -0
  97. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js +355 -0
  98. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js.map +1 -0
  99. package/dist/tests/IO/Attachments/KeypadAttachment.test.d.ts +1 -0
  100. package/dist/tests/IO/Attachments/KeypadAttachment.test.js +323 -0
  101. package/dist/tests/IO/Attachments/KeypadAttachment.test.js.map +1 -0
  102. package/dist/tests/IO/Attachments/LCDAttachment.test.d.ts +1 -0
  103. package/dist/tests/IO/Attachments/LCDAttachment.test.js +627 -0
  104. package/dist/tests/IO/Attachments/LCDAttachment.test.js.map +1 -0
  105. package/dist/tests/IO/Attachments/SNESAttachment.test.d.ts +1 -0
  106. package/dist/tests/IO/Attachments/SNESAttachment.test.js +331 -0
  107. package/dist/tests/IO/Attachments/SNESAttachment.test.js.map +1 -0
  108. package/dist/tests/IO/Empty.test.d.ts +1 -0
  109. package/dist/tests/IO/Empty.test.js +121 -0
  110. package/dist/tests/IO/Empty.test.js.map +1 -0
  111. package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.d.ts +1 -0
  112. package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.d.ts +1 -0
  113. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.d.ts +1 -0
  114. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.d.ts +1 -0
  115. package/dist/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.d.ts +1 -0
  116. package/dist/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.d.ts +1 -0
  117. package/dist/tests/IO/GPIOCard.test.d.ts +1 -0
  118. package/dist/tests/IO/GPIOCard.test.js.map +1 -1
  119. package/dist/tests/IO/RAMBank.test.d.ts +1 -0
  120. package/dist/tests/IO/RAMBank.test.js +229 -0
  121. package/dist/tests/IO/RAMBank.test.js.map +1 -0
  122. package/dist/tests/IO/RAMCard.test.d.ts +1 -0
  123. package/dist/tests/IO/RTC.test.d.ts +1 -0
  124. package/dist/tests/IO/RTC.test.js +177 -0
  125. package/dist/tests/IO/RTC.test.js.map +1 -0
  126. package/dist/tests/IO/RTCCard.test.d.ts +1 -0
  127. package/dist/tests/IO/SerialCard.test.d.ts +1 -0
  128. package/dist/tests/IO/Sound.test.d.ts +1 -0
  129. package/dist/tests/IO/Sound.test.js +528 -0
  130. package/dist/tests/IO/Sound.test.js.map +1 -0
  131. package/dist/tests/IO/SoundCard.test.d.ts +1 -0
  132. package/dist/tests/IO/Storage.test.d.ts +1 -0
  133. package/dist/tests/IO/Storage.test.js +656 -0
  134. package/dist/tests/IO/Storage.test.js.map +1 -0
  135. package/dist/tests/IO/StorageCard.test.d.ts +1 -0
  136. package/dist/tests/IO/VIA.test.d.ts +1 -0
  137. package/dist/tests/IO/VIA.test.js +503 -0
  138. package/dist/tests/IO/VIA.test.js.map +1 -0
  139. package/dist/tests/IO/Video.test.d.ts +1 -0
  140. package/dist/tests/IO/Video.test.js +549 -0
  141. package/dist/tests/IO/Video.test.js.map +1 -0
  142. package/dist/tests/IO/VideoCard.test.d.ts +1 -0
  143. package/dist/tests/Machine.test.d.ts +1 -0
  144. package/dist/tests/Machine.test.js +27 -42
  145. package/dist/tests/Machine.test.js.map +1 -1
  146. package/dist/tests/RAM.test.d.ts +1 -0
  147. package/dist/tests/ROM.test.d.ts +1 -0
  148. package/package.json +5 -3
  149. package/src/components/IO/{SerialCard.ts → ACIA.ts} +2 -2
  150. package/src/components/IO/{GPIOAttachments/GPIOAttachment.ts → Attachments/Attachment.ts} +2 -2
  151. package/src/components/IO/{GPIOAttachments/GPIOJoystickAttachment.ts → Attachments/JoystickAttachment.ts} +3 -3
  152. package/src/components/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.ts → Attachments/KeyboardEncoderAttachment.ts} +3 -3
  153. package/src/components/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.ts → Attachments/KeyboardMatrixAttachment.ts} +5 -5
  154. package/src/components/IO/{GPIOAttachments/GPIOKeypadAttachment.ts → Attachments/KeypadAttachment.ts} +3 -3
  155. package/src/components/IO/{GPIOAttachments/GPIOLCDAttachment.ts → Attachments/LCDAttachment.ts} +7 -7
  156. package/src/components/IO/{EmptyCard.ts → Empty.ts} +1 -1
  157. package/src/components/IO/{RAMCard.ts → RAMBank.ts} +8 -8
  158. package/src/components/IO/{RTCCard.ts → RTC.ts} +1 -1
  159. package/src/components/IO/{SoundCard.ts → Sound.ts} +2 -2
  160. package/src/components/IO/{StorageCard.ts → Storage.ts} +70 -73
  161. package/src/components/IO/Terminal.ts +34 -0
  162. package/src/components/IO/{GPIOCard.ts → VIA.ts} +64 -64
  163. package/src/components/IO/{VideoCard.ts → Video.ts} +1 -1
  164. package/src/components/Machine.ts +286 -160
  165. package/src/index.ts +65 -35
  166. package/src/lib.ts +27 -0
  167. package/src/tests/IO/{SerialCard.test.ts → ACIA.test.ts} +5 -5
  168. package/src/tests/IO/{GPIOAttachments/GPIOAttachment.test.ts → Attachments/Attachment.test.ts} +12 -12
  169. package/src/tests/IO/{GPIOAttachments/GPIOJoystickAttachment.test.ts → Attachments/JoystickAttachment.test.ts} +23 -23
  170. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts → Attachments/KeyboardEncoderAttachment.test.ts} +4 -4
  171. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts → Attachments/KeyboardMatrixAttachment.test.ts} +5 -5
  172. package/src/tests/IO/{GPIOAttachments/GPIOKeypadAttachment.test.ts → Attachments/KeypadAttachment.test.ts} +38 -38
  173. package/src/tests/IO/{GPIOAttachments/GPIOLCDAttachment.test.ts → Attachments/LCDAttachment.test.ts} +12 -12
  174. package/src/tests/IO/Empty.test.ts +143 -0
  175. package/src/tests/IO/{RAMCard.test.ts → RAMBank.test.ts} +33 -33
  176. package/src/tests/IO/{RTCCard.test.ts → RTC.test.ts} +6 -6
  177. package/src/tests/IO/{SoundCard.test.ts → Sound.test.ts} +6 -6
  178. package/src/tests/IO/{StorageCard.test.ts → Storage.test.ts} +34 -25
  179. package/src/tests/IO/{GPIOCard.test.ts → VIA.test.ts} +7 -7
  180. package/src/tests/IO/{VideoCard.test.ts → Video.test.ts} +13 -13
  181. package/src/tests/Machine.test.ts +31 -38
  182. 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 { VideoCard } from './components/IO/VideoCard'
8
- import { StorageCard } from './components/IO/StorageCard'
9
- import { SoundCard } from './components/IO/SoundCard'
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.2.0'
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 GPIOJoystickAttachment)
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
- kim?: boolean
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.kim ?? false)
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 this.machine.loadROM(this.options.rom)
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 this.machine.loadCart(this.options.cart)
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 && !this.options.kim) {
108
- await (this.machine.io4 as StorageCard).loadFromFile(this.options.storage)
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 SoundCard sample rate to match audio device
196
- ;(this.machine.io7 as SoundCard).sampleRate = this.audioDevice.frequency
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.pushAudioSamples = (samples: Float32Array) => {
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.kim ?? false
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: isKIM ? "6502 Emulator (KIM)" : "6502 Emulator",
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 videoCard = this.machine.io8 as VideoCard
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
- this.window.render(WIDTH, HEIGHT, WIDTH * 4, 'rgba32', videoCard.buffer)
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 && !this.options.kim) {
517
- (this.machine.io4 as StorageCard).saveToFile(this.options.storage).then(() => {
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
- start(): void {
528
- this.machine.start()
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('-K, --kim', 'Configure IO for the KIM system target', false)
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.start()
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 { SerialCard } from '../../components/IO/SerialCard'
1
+ import { ACIA } from '../../components/IO/ACIA'
2
2
 
3
- describe('SerialCard (6551 ACIA)', () => {
4
- let serialCard: SerialCard
3
+ describe('ACIA (6551 ACIA)', () => {
4
+ let serialCard: ACIA
5
5
 
6
6
  beforeEach(() => {
7
- serialCard = new SerialCard()
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 SerialCard()
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
  })
@@ -1,9 +1,9 @@
1
- import { GPIOAttachment, GPIOAttachmentBase } from '../../../components/IO/GPIOAttachments/GPIOAttachment'
1
+ import { Attachment, AttachmentBase } from '../../../components/IO/Attachments/Attachment'
2
2
 
3
3
  /**
4
- * Concrete implementation of GPIOAttachmentBase for testing
4
+ * Concrete implementation of AttachmentBase for testing
5
5
  */
6
- class TestGPIOAttachment extends GPIOAttachmentBase {
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('GPIOAttachmentBase', () => {
66
- let attachment: TestGPIOAttachment
65
+ describe('AttachmentBase', () => {
66
+ let attachment: TestAttachment
67
67
 
68
68
  beforeEach(() => {
69
- attachment = new TestGPIOAttachment()
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 TestGPIOAttachment(5)
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 TestGPIOAttachment(0, true, true, true, true)
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 TestGPIOAttachment(10)
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 TestGPIOAttachment(0)
133
- const highPriority = new TestGPIOAttachment(10)
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 TestGPIOAttachment(-5)
140
+ const negativePriority = new TestAttachment(-5)
141
141
  expect(negativePriority.getPriority()).toBe(-5)
142
142
  })
143
143
  })
@@ -1,10 +1,10 @@
1
- import { GPIOJoystickAttachment } from '../../../components/IO/GPIOAttachments/GPIOJoystickAttachment'
1
+ import { JoystickAttachment } from '../../../components/IO/Attachments/JoystickAttachment'
2
2
 
3
- describe('GPIOJoystickAttachment', () => {
4
- let joystick: GPIOJoystickAttachment
3
+ describe('JoystickAttachment', () => {
4
+ let joystick: JoystickAttachment
5
5
 
6
6
  beforeEach(() => {
7
- joystick = new GPIOJoystickAttachment(true, 0)
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(GPIOJoystickAttachment.BUTTON_A)
30
- expect(joystick.isButtonPressed(GPIOJoystickAttachment.BUTTON_A)).toBe(true)
31
- expect(joystick.isButtonPressed(GPIOJoystickAttachment.BUTTON_B)).toBe(false)
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(GPIOJoystickAttachment.BUTTON_START)
36
- expect(joystick.getButtonState()).toBe(GPIOJoystickAttachment.BUTTON_START)
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(GPIOJoystickAttachment.BUTTON_A)
42
- expect(joystick.getButtonState()).toBe(0xFF & ~GPIOJoystickAttachment.BUTTON_A)
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 GPIOJoystickAttachment(true, 0) // Attach to Port A
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(GPIOJoystickAttachment.BUTTON_UP)
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 GPIOJoystickAttachment(false, 0) // Attach to Port B
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(GPIOJoystickAttachment.BUTTON_UP).toBe(0x01)
104
- expect(GPIOJoystickAttachment.BUTTON_DOWN).toBe(0x02)
105
- expect(GPIOJoystickAttachment.BUTTON_LEFT).toBe(0x04)
106
- expect(GPIOJoystickAttachment.BUTTON_RIGHT).toBe(0x08)
107
- expect(GPIOJoystickAttachment.BUTTON_A).toBe(0x10)
108
- expect(GPIOJoystickAttachment.BUTTON_B).toBe(0x20)
109
- expect(GPIOJoystickAttachment.BUTTON_SELECT).toBe(0x40)
110
- expect(GPIOJoystickAttachment.BUTTON_START).toBe(0x80)
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 GPIOJoystickAttachment(true, 5)
116
+ const j = new JoystickAttachment(true, 5)
117
117
  expect(j.getPriority()).toBe(5)
118
118
  })
119
119
 
@@ -1,10 +1,10 @@
1
- import { GPIOKeyboardEncoderAttachment } from '../../../components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment'
1
+ import { KeyboardEncoderAttachment } from '../../../components/IO/Attachments/KeyboardEncoderAttachment'
2
2
 
3
- describe('GPIOKeyboardEncoderAttachment', () => {
4
- let encoder: GPIOKeyboardEncoderAttachment
3
+ describe('KeyboardEncoderAttachment', () => {
4
+ let encoder: KeyboardEncoderAttachment
5
5
 
6
6
  beforeEach(() => {
7
- encoder = new GPIOKeyboardEncoderAttachment(5)
7
+ encoder = new KeyboardEncoderAttachment(5)
8
8
  })
9
9
 
10
10
  describe('Initialization', () => {
@@ -1,10 +1,10 @@
1
- import { GPIOKeyboardMatrixAttachment } from '../../../components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment'
1
+ import { KeyboardMatrixAttachment } from '../../../components/IO/Attachments/KeyboardMatrixAttachment'
2
2
 
3
- describe('GPIOKeyboardMatrixAttachment', () => {
4
- let keyboard: GPIOKeyboardMatrixAttachment
3
+ describe('KeyboardMatrixAttachment', () => {
4
+ let keyboard: KeyboardMatrixAttachment
5
5
 
6
6
  beforeEach(() => {
7
- keyboard = new GPIOKeyboardMatrixAttachment(0)
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 GPIOKeyboardMatrixAttachment(5)
25
+ const kb = new KeyboardMatrixAttachment(5)
26
26
  expect(kb.getPriority()).toBe(5)
27
27
  })
28
28
  })