ac6502 1.4.1 → 1.5.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/src/index.ts CHANGED
@@ -12,7 +12,7 @@ import sdl from '@kmamal/sdl'
12
12
  import { readFile, writeFile } from 'fs/promises'
13
13
  import { existsSync } from 'fs'
14
14
 
15
- const VERSION = '1.4.1'
15
+ const VERSION = '1.5.1'
16
16
  const WIDTH = 320
17
17
  const HEIGHT = 240
18
18
 
@@ -72,10 +72,11 @@ class Emulator {
72
72
  await this.loadBinaries()
73
73
  this.configureFrequency()
74
74
  this.configureScale()
75
- this.setupSerialPort()
75
+ await this.setupSerialPort()
76
76
  this.setupAudio()
77
77
  this.setupWindow()
78
78
  this.setupControllers()
79
+ this.machine.reset(true)
79
80
  }
80
81
 
81
82
  private validateOptions(): void {
@@ -155,7 +156,7 @@ class Emulator {
155
156
  }
156
157
  }
157
158
 
158
- private setupSerialPort(): void {
159
+ private async setupSerialPort(): Promise<void> {
159
160
  if (!this.options.port) {
160
161
  return
161
162
  }
@@ -170,11 +171,8 @@ class Emulator {
170
171
  baudRate: baudRate,
171
172
  parity: parity,
172
173
  dataBits: dataBits,
173
- stopBits: stopBits
174
- }, (err) => {
175
- if (err) {
176
- console.log('Error: ', err.message)
177
- }
174
+ stopBits: stopBits,
175
+ autoOpen: false
178
176
  })
179
177
 
180
178
  this.serialPort.on('data', (data: Buffer<ArrayBuffer>) => {
@@ -192,10 +190,22 @@ class Emulator {
192
190
  })
193
191
  }
194
192
  }
193
+
194
+ await new Promise<void>((resolve, reject) => {
195
+ this.serialPort!.open((err) => {
196
+ if (err) {
197
+ console.log('Error opening serial port: ', err.message)
198
+ reject(err)
199
+ } else {
200
+ console.log(`Serial port opened: ${this.options.port}`)
201
+ resolve()
202
+ }
203
+ })
204
+ })
195
205
  }
196
206
 
197
207
  private setupAudio(): void {
198
- if (this.options.target === 'kim' || this.options.target === 'dev') return
208
+ if (this.options.target === 'kim') return
199
209
  try {
200
210
  this.audioDevice = sdl.audio.openDevice({ type: 'playback' }, {
201
211
  channels: AUDIO_CHANNELS as 1,
@@ -204,8 +214,10 @@ class Emulator {
204
214
  buffered: AUDIO_BUFFERED,
205
215
  })
206
216
 
207
- // Configure Sound sample rate to match audio device
208
- ;(this.machine.io7 as Sound).sampleRate = this.audioDevice.frequency
217
+ // Configure Sound sample rate to match audio device (not needed for dev target)
218
+ if (this.options.target !== 'dev') {
219
+ ;(this.machine.io7 as Sound).sampleRate = this.audioDevice.frequency
220
+ }
209
221
 
210
222
  // Connect the Machine's audio callback to the SDL audio device
211
223
  this.machine.play = (samples: Float32Array) => {
@@ -347,12 +359,32 @@ class Emulator {
347
359
  for (let i = 0; i < WIDTH * HEIGHT; i++) {
348
360
  const v = src[i]
349
361
  const off = i * 4
350
- rgbaBuffer[off] = v
351
- rgbaBuffer[off + 1] = v
352
- rgbaBuffer[off + 2] = v
362
+ const r3 = (v >> 5) & 0x07
363
+ const g3 = (v >> 2) & 0x07
364
+ const b2 = v & 0x03
365
+ rgbaBuffer[off] = (r3 << 5) | (r3 << 2) | (r3 >> 1)
366
+ rgbaBuffer[off + 1] = (g3 << 5) | (g3 << 2) | (g3 >> 1)
367
+ rgbaBuffer[off + 2] = (b2 << 6) | (b2 << 4) | (b2 << 2) | b2
353
368
  rgbaBuffer[off + 3] = 0xFF
354
369
  }
355
370
  this.window.render(WIDTH, HEIGHT, WIDTH * 4, 'rgba32', rgbaBuffer)
371
+
372
+ // Synthesize and play any queued VTAC bell tones
373
+ if (this.machine.play && this.audioDevice) {
374
+ const sampleRate = this.audioDevice.frequency
375
+ while (devBoard.vtac.hasQueuedBells()) {
376
+ const bell = devBoard.vtac.getNextBell()
377
+ if (bell) {
378
+ const numSamples = Math.floor((bell.duration / 60) * sampleRate)
379
+ const samples = new Float32Array(numSamples)
380
+ const twoPiF = 2 * Math.PI * bell.frequency
381
+ for (let i = 0; i < numSamples; i++) {
382
+ samples[i] = Math.sin(twoPiF * i / sampleRate)
383
+ }
384
+ this.machine.play(samples)
385
+ }
386
+ }
387
+ }
356
388
  }
357
389
  }
358
390
 
@@ -137,18 +137,18 @@ describe('ACIA (6551 ACIA)', () => {
137
137
  expect(mockIRQ).toHaveBeenCalled()
138
138
  })
139
139
 
140
- it('should disable receive IRQ when bit 2 is clear', () => {
140
+ it('should disable receive IRQ when RIIE bit (bit 1) is set', () => {
141
141
  const mockIRQ = jest.fn()
142
142
  serialCard.raiseIRQ = mockIRQ
143
143
 
144
- serialCard.write(0x02, 0x00) // Disable receive IRQ
144
+ serialCard.write(0x02, 0x02) // RIIE=1: receive IRQ disabled (W65C51N: bit1=1 disables)
145
145
  serialCard.onData(0x42)
146
146
 
147
147
  expect(mockIRQ).not.toHaveBeenCalled()
148
148
  })
149
149
 
150
- it('should enable echo mode when bit 5 is set', () => {
151
- serialCard.write(0x02, 0x20) // Enable echo mode
150
+ it('should enable echo mode when REM bit (bit 4) is set', () => {
151
+ serialCard.write(0x02, 0x10) // REM=1: echo mode enabled (bit 4 per 6551 spec)
152
152
  serialCard.onData(0x42)
153
153
 
154
154
  // In echo mode, received data is added to transmit buffer
@@ -276,7 +276,7 @@ describe('ACIA (6551 ACIA)', () => {
276
276
  serialCard.transmit = mockTransmit
277
277
 
278
278
  serialCard.write(0x03, 0x00) // Set control register
279
- serialCard.write(0x02, 0x08) // Enable transmit IRQ
279
+ serialCard.write(0x02, 0x04) // TIC=01: transmit IRQ enabled with /RTS low (bits 3-2 = 01)
280
280
  serialCard.write(0x00, 0x42)
281
281
 
282
282
  for (let i = 0; i < 100; i++) {
@@ -291,7 +291,7 @@ describe('ACIA (6551 ACIA)', () => {
291
291
  const mockIRQ = jest.fn()
292
292
  serialCard.raiseIRQ = mockIRQ
293
293
 
294
- serialCard.write(0x02, 0x00) // Disable receive IRQ
294
+ serialCard.write(0x02, 0x02) // RIIE=1: receive IRQ disabled (W65C51N: bit1=1 disables)
295
295
  serialCard.onData(0x42)
296
296
 
297
297
  expect(mockIRQ).not.toHaveBeenCalled()
@@ -343,7 +343,7 @@ describe('ACIA (6551 ACIA)', () => {
343
343
  const mockTransmit = jest.fn()
344
344
  serialCard.transmit = mockTransmit
345
345
 
346
- serialCard.write(0x02, 0x20) // Enable echo mode
346
+ serialCard.write(0x02, 0x10) // REM=1: echo mode enabled (bit 4 per 6551 spec)
347
347
  serialCard.onData(0x42)
348
348
 
349
349
  // Tick to allow transmission
@@ -369,7 +369,7 @@ describe('ACIA (6551 ACIA)', () => {
369
369
  })
370
370
 
371
371
  it('should clear TDRE flag in echo mode', () => {
372
- serialCard.write(0x02, 0x20) // Enable echo mode
372
+ serialCard.write(0x02, 0x10) // REM=1: echo mode enabled (bit 4 per 6551 spec)
373
373
  serialCard.onData(0x42)
374
374
 
375
375
  const status = serialCard.read(0x01)