@aptre/v86 0.5.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 (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
package/src/sb16.ts ADDED
@@ -0,0 +1,1928 @@
1
+ import {
2
+ LOG_SB16,
3
+ MIXER_CHANNEL_BOTH,
4
+ MIXER_CHANNEL_LEFT,
5
+ MIXER_CHANNEL_RIGHT,
6
+ MIXER_SRC_PCSPEAKER,
7
+ MIXER_SRC_DAC,
8
+ MIXER_SRC_MASTER,
9
+ } from './const.js'
10
+ import { h } from './lib.js'
11
+ import { dbg_log } from './log.js'
12
+ import { SyncBuffer } from './buffer.js'
13
+
14
+ import { DMA } from './dma.js'
15
+ import { IO } from './io.js'
16
+ import { BusConnector } from './bus.js'
17
+ import { ByteQueue, FloatQueue } from './lib.js'
18
+
19
+ // Minimal interface for the CPU fields SB16 uses.
20
+ interface SB16Cpu {
21
+ io: IO
22
+ devices: { dma: DMA }
23
+ device_raise_irq(irq: number): void
24
+ device_lower_irq(irq: number): void
25
+ }
26
+
27
+ // Useful documentation, articles, and source codes for reference:
28
+ // ===============================================================
29
+ //
30
+ // Official Hardware Programming Guide
31
+ // -> https://pdos.csail.mit.edu/6.828/2011/readings/hardware/SoundBlaster.pdf
32
+ //
33
+ // Official Yamaha YMF262 Manual
34
+ // -> http://map.grauw.nl/resources/sound/yamaha_ymf262.pdf
35
+ //
36
+ // OPL3 Programming Guide
37
+ // -> http://www.fit.vutbr.cz/~arnost/opl/opl3.html
38
+ //
39
+ // DOSBox
40
+ // -> https://sourceforge.net/p/dosbox/code-0/HEAD/tree/dosbox/branches/mamesound/src/hardware/sblaster.cpp
41
+ // -> https://github.com/duganchen/dosbox/blob/master/src/hardware/sblaster.cpp
42
+ // -> https://github.com/joncampbell123/dosbox-x/blob/master/src/hardware/sblaster.cpp
43
+ //
44
+ // QEMU
45
+ // -> https://github.com/qemu/qemu/blob/master/hw/audio/sb16.c
46
+ // -> https://github.com/hackndev/qemu/blob/master/hw/sb16.c
47
+ //
48
+ // VirtualBox
49
+ // -> https://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/Audio/DevSB16.cpp
50
+ // -> https://github.com/mdaniel/virtualbox-org-svn-vbox-trunk/blob/master/src/VBox/Devices/Audio/DevSB16.cpp
51
+
52
+ const // Used for drivers to identify device (DSP command 0xE3).
53
+ DSP_COPYRIGHT = 'COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.',
54
+ // Value of the current DSP command that indicates that the
55
+ // next command/data write in port 2xC should be interpreted
56
+ // as a command number.
57
+ DSP_NO_COMMAND = 0,
58
+ // Size (bytes) of the DSP write/read buffers
59
+ DSP_BUFSIZE = 64,
60
+ // Size (bytes) of the buffers containing floating point linear PCM audio.
61
+ DSP_DACSIZE = 65536,
62
+ // Size (bytes) of the buffer in which DMA transfers are temporarily
63
+ // stored before being processed.
64
+ SB_DMA_BUFSIZE = 65536,
65
+ // Number of samples to attempt to retrieve per transfer.
66
+ SB_DMA_BLOCK_SAMPLES = 1024,
67
+ // Usable DMA channels.
68
+ SB_DMA0 = 0,
69
+ SB_DMA1 = 1,
70
+ SB_DMA3 = 3,
71
+ SB_DMA5 = 5,
72
+ SB_DMA6 = 6,
73
+ SB_DMA7 = 7,
74
+ // Default DMA channels.
75
+ SB_DMA_CHANNEL_8BIT = SB_DMA1,
76
+ SB_DMA_CHANNEL_16BIT = SB_DMA5,
77
+ // Usable IRQ channels.
78
+ SB_IRQ2 = 2,
79
+ SB_IRQ5 = 5,
80
+ SB_IRQ7 = 7,
81
+ SB_IRQ10 = 10,
82
+ // Default IRQ channel.
83
+ SB_IRQ = SB_IRQ5,
84
+ // Indices to the irq_triggered register.
85
+ SB_IRQ_8BIT = 0x1,
86
+ SB_IRQ_16BIT = 0x2,
87
+ _SB_IRQ_MIDI = 0x1,
88
+ _SB_IRQ_MPU = 0x4
89
+
90
+ // Probably less efficient, but it's more maintainable, instead
91
+ // of having a single large unorganised and decoupled table.
92
+ const DSP_COMMAND_SIZES = new Uint8Array(256)
93
+ const DSP_COMMAND_HANDLERS: Array<((this: SB16) => void) | undefined> = []
94
+ const MIXER_READ_HANDLERS: Array<((this: SB16) => number) | undefined> = []
95
+ const MIXER_WRITE_HANDLERS: Array<
96
+ ((this: SB16, data: number) => void) | undefined
97
+ > = []
98
+ const MIXER_REGISTER_IS_LEGACY = new Uint8Array(256)
99
+ const FM_HANDLERS: Array<
100
+ | ((this: SB16, data: number, register: number, address: number) => void)
101
+ | undefined
102
+ > = []
103
+
104
+ // Sound Blaster 16 Emulator, or so it seems.
105
+ export class SB16 {
106
+ cpu: SB16Cpu
107
+ bus: BusConnector
108
+
109
+ // I/O Buffers.
110
+ write_buffer: ByteQueue
111
+ read_buffer: ByteQueue
112
+ read_buffer_lastvalue: number
113
+
114
+ // Current DSP command info.
115
+ command: number
116
+ command_size: number
117
+
118
+ // Mixer.
119
+ mixer_current_address: number
120
+ mixer_registers: Uint8Array
121
+
122
+ // Dummy status and test registers.
123
+ dummy_speaker_enabled: boolean
124
+ test_register: number
125
+
126
+ // DSP state.
127
+ dsp_highspeed: boolean
128
+ dsp_stereo: boolean
129
+ dsp_16bit: boolean
130
+ dsp_signed: boolean
131
+
132
+ // DAC buffer.
133
+ // The final destination for audio data before being sent off
134
+ // to Web Audio APIs.
135
+ // Format:
136
+ // Floating precision linear PCM, nominal between -1 and 1.
137
+ dac_buffers: [FloatQueue, FloatQueue]
138
+
139
+ // Direct Memory Access transfer info.
140
+ dma: DMA
141
+ dma_sample_count: number
142
+ dma_bytes_count: number
143
+ dma_bytes_left: number
144
+ dma_bytes_block: number
145
+ dma_irq: number
146
+ dma_channel: number
147
+ dma_channel_8bit: number
148
+ dma_channel_16bit: number
149
+ dma_autoinit: boolean
150
+ dma_buffer: ArrayBuffer
151
+ dma_buffer_int8: Int8Array
152
+ dma_buffer_uint8: Uint8Array
153
+ dma_buffer_int16: Int16Array
154
+ dma_buffer_uint16: Uint16Array
155
+ dma_syncbuffer: SyncBuffer
156
+ dma_waiting_transfer: boolean
157
+ dma_paused: boolean
158
+ sampling_rate: number
159
+ bytes_per_sample: number
160
+
161
+ // DMA identification data.
162
+ e2_value: number
163
+ e2_count: number
164
+
165
+ // ASP data: not understood by me.
166
+ asp_registers: Uint8Array
167
+
168
+ // MPU.
169
+ mpu_read_buffer: ByteQueue
170
+ mpu_read_buffer_lastvalue: number
171
+ // Bug-compatible: get_state/set_state reference a different spelling.
172
+ mpu_read_buffer_last_value: number | undefined
173
+
174
+ // FM Synthesizer.
175
+ fm_current_address0: number
176
+ fm_current_address1: number
177
+ fm_waveform_select_enable: Record<number, number>
178
+
179
+ // Interrupts.
180
+ irq: number
181
+ irq_triggered: Uint8Array
182
+
183
+ name: string | undefined
184
+
185
+ constructor(cpu: SB16Cpu, bus: BusConnector) {
186
+ this.cpu = cpu
187
+ this.bus = bus
188
+
189
+ // I/O Buffers.
190
+ this.write_buffer = new ByteQueue(DSP_BUFSIZE)
191
+ this.read_buffer = new ByteQueue(DSP_BUFSIZE)
192
+ this.read_buffer_lastvalue = 0
193
+
194
+ // Current DSP command info.
195
+ this.command = DSP_NO_COMMAND
196
+ this.command_size = 0
197
+
198
+ // Mixer.
199
+ this.mixer_current_address = 0
200
+ this.mixer_registers = new Uint8Array(256)
201
+ this.mixer_reset()
202
+
203
+ // Dummy status and test registers.
204
+ this.dummy_speaker_enabled = false
205
+ this.test_register = 0
206
+
207
+ // DSP state.
208
+ this.dsp_highspeed = false
209
+ this.dsp_stereo = false
210
+ this.dsp_16bit = false
211
+ this.dsp_signed = false
212
+
213
+ // DAC buffer.
214
+ this.dac_buffers = [
215
+ new FloatQueue(DSP_DACSIZE),
216
+ new FloatQueue(DSP_DACSIZE),
217
+ ]
218
+
219
+ // Direct Memory Access transfer info.
220
+ this.dma = cpu.devices.dma
221
+ this.dma_sample_count = 0
222
+ this.dma_bytes_count = 0
223
+ this.dma_bytes_left = 0
224
+ this.dma_bytes_block = 0
225
+ this.dma_irq = 0
226
+ this.dma_channel = 0
227
+ this.dma_channel_8bit = SB_DMA_CHANNEL_8BIT
228
+ this.dma_channel_16bit = SB_DMA_CHANNEL_16BIT
229
+ this.dma_autoinit = false
230
+ this.dma_buffer = new ArrayBuffer(SB_DMA_BUFSIZE)
231
+ this.dma_buffer_int8 = new Int8Array(this.dma_buffer)
232
+ this.dma_buffer_uint8 = new Uint8Array(this.dma_buffer)
233
+ this.dma_buffer_int16 = new Int16Array(this.dma_buffer)
234
+ this.dma_buffer_uint16 = new Uint16Array(this.dma_buffer)
235
+ this.dma_syncbuffer = new SyncBuffer(this.dma_buffer)
236
+ this.dma_waiting_transfer = false
237
+ this.dma_paused = false
238
+ this.sampling_rate = 22050
239
+ bus.send('dac-tell-sampling-rate', this.sampling_rate)
240
+ this.bytes_per_sample = 1
241
+
242
+ // DMA identification data.
243
+ this.e2_value = 0xaa
244
+ this.e2_count = 0
245
+
246
+ // ASP data: not understood by me.
247
+ this.asp_registers = new Uint8Array(256)
248
+
249
+ // MPU.
250
+ this.mpu_read_buffer = new ByteQueue(DSP_BUFSIZE)
251
+ this.mpu_read_buffer_lastvalue = 0
252
+
253
+ // FM Synthesizer.
254
+ this.fm_current_address0 = 0
255
+ this.fm_current_address1 = 0
256
+ this.fm_waveform_select_enable = {}
257
+
258
+ // Interrupts.
259
+ this.irq = SB_IRQ
260
+ this.irq_triggered = new Uint8Array(0x10)
261
+
262
+ // IO Ports.
263
+ // http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#DSPPorts
264
+ // https://pdos.csail.mit.edu/6.828/2011/readings/hardware/SoundBlaster.pdf
265
+
266
+ cpu.io.register_read_consecutive(
267
+ 0x220,
268
+ this,
269
+ this.port2x0_read,
270
+ this.port2x1_read,
271
+ this.port2x2_read,
272
+ this.port2x3_read,
273
+ )
274
+ cpu.io.register_read_consecutive(
275
+ 0x388,
276
+ this,
277
+ this.port2x0_read,
278
+ this.port2x1_read,
279
+ )
280
+
281
+ cpu.io.register_read_consecutive(
282
+ 0x224,
283
+ this,
284
+ this.port2x4_read,
285
+ this.port2x5_read,
286
+ )
287
+
288
+ cpu.io.register_read(0x226, this, this.port2x6_read)
289
+ cpu.io.register_read(0x227, this, this.port2x7_read)
290
+ cpu.io.register_read(0x228, this, this.port2x8_read)
291
+ cpu.io.register_read(0x229, this, this.port2x9_read)
292
+
293
+ cpu.io.register_read(0x22a, this, this.port2xA_read)
294
+ cpu.io.register_read(0x22b, this, this.port2xB_read)
295
+ cpu.io.register_read(0x22c, this, this.port2xC_read)
296
+ cpu.io.register_read(0x22d, this, this.port2xD_read)
297
+
298
+ cpu.io.register_read_consecutive(
299
+ 0x22e,
300
+ this,
301
+ this.port2xE_read,
302
+ this.port2xF_read,
303
+ )
304
+
305
+ cpu.io.register_write_consecutive(
306
+ 0x220,
307
+ this,
308
+ this.port2x0_write,
309
+ this.port2x1_write,
310
+ this.port2x2_write,
311
+ this.port2x3_write,
312
+ )
313
+ cpu.io.register_write_consecutive(
314
+ 0x388,
315
+ this,
316
+ this.port2x0_write,
317
+ this.port2x1_write,
318
+ )
319
+
320
+ cpu.io.register_write_consecutive(
321
+ 0x224,
322
+ this,
323
+ this.port2x4_write,
324
+ this.port2x5_write,
325
+ )
326
+
327
+ cpu.io.register_write(0x226, this, this.port2x6_write)
328
+ cpu.io.register_write(0x227, this, this.port2x7_write)
329
+
330
+ cpu.io.register_write_consecutive(
331
+ 0x228,
332
+ this,
333
+ this.port2x8_write,
334
+ this.port2x9_write,
335
+ )
336
+
337
+ cpu.io.register_write(0x22a, this, this.port2xA_write)
338
+ cpu.io.register_write(0x22b, this, this.port2xB_write)
339
+ cpu.io.register_write(0x22c, this, this.port2xC_write)
340
+ cpu.io.register_write(0x22d, this, this.port2xD_write)
341
+ cpu.io.register_write(0x22e, this, this.port2xE_write)
342
+ cpu.io.register_write(0x22f, this, this.port2xF_write)
343
+
344
+ cpu.io.register_read_consecutive(
345
+ 0x330,
346
+ this,
347
+ this.port3x0_read,
348
+ this.port3x1_read,
349
+ )
350
+ cpu.io.register_write_consecutive(
351
+ 0x330,
352
+ this,
353
+ this.port3x0_write,
354
+ this.port3x1_write,
355
+ )
356
+
357
+ this.dma.on_unmask(this.dma_on_unmask, this)
358
+
359
+ bus.register(
360
+ 'dac-request-data',
361
+ function (this: SB16) {
362
+ this.dac_handle_request()
363
+ },
364
+ this,
365
+ )
366
+ bus.register(
367
+ 'speaker-has-initialized',
368
+ function (this: SB16) {
369
+ this.mixer_reset()
370
+ },
371
+ this,
372
+ )
373
+ bus.send('speaker-confirm-initialized')
374
+
375
+ this.dsp_reset()
376
+ }
377
+
378
+ //
379
+ // General
380
+ //
381
+
382
+ dsp_reset(): void {
383
+ this.write_buffer.clear()
384
+ this.read_buffer.clear()
385
+
386
+ this.command = DSP_NO_COMMAND
387
+ this.command_size = 0
388
+
389
+ this.dummy_speaker_enabled = false
390
+ this.test_register = 0
391
+
392
+ this.dsp_highspeed = false
393
+ this.dsp_stereo = false
394
+ this.dsp_16bit = false
395
+ this.dsp_signed = false
396
+
397
+ this.dac_buffers[0].clear()
398
+ this.dac_buffers[1].clear()
399
+
400
+ this.dma_sample_count = 0
401
+ this.dma_bytes_count = 0
402
+ this.dma_bytes_left = 0
403
+ this.dma_bytes_block = 0
404
+ this.dma_irq = 0
405
+ this.dma_channel = 0
406
+ this.dma_autoinit = false
407
+ this.dma_buffer_uint8.fill(0)
408
+ this.dma_waiting_transfer = false
409
+ this.dma_paused = false
410
+
411
+ this.e2_value = 0xaa
412
+ this.e2_count = 0
413
+
414
+ this.sampling_rate = 22050
415
+ this.bytes_per_sample = 1
416
+
417
+ this.lower_irq(SB_IRQ_8BIT)
418
+ this.irq_triggered.fill(0)
419
+
420
+ this.asp_registers.fill(0)
421
+ this.asp_registers[5] = 0x01
422
+ this.asp_registers[9] = 0xf8
423
+ }
424
+
425
+ get_state(): unknown[] {
426
+ const state: unknown[] = []
427
+
428
+ // state[0] = this.write_buffer;
429
+ // state[1] = this.read_buffer;
430
+ state[2] = this.read_buffer_lastvalue
431
+
432
+ state[3] = this.command
433
+ state[4] = this.command_size
434
+
435
+ state[5] = this.mixer_current_address
436
+ state[6] = this.mixer_registers
437
+
438
+ state[7] = this.dummy_speaker_enabled
439
+ state[8] = this.test_register
440
+
441
+ state[9] = this.dsp_highspeed
442
+ state[10] = this.dsp_stereo
443
+ state[11] = this.dsp_16bit
444
+ state[12] = this.dsp_signed
445
+
446
+ // state[13] = this.dac_buffers;
447
+ //state[14]
448
+
449
+ state[15] = this.dma_sample_count
450
+ state[16] = this.dma_bytes_count
451
+ state[17] = this.dma_bytes_left
452
+ state[18] = this.dma_bytes_block
453
+ state[19] = this.dma_irq
454
+ state[20] = this.dma_channel
455
+ state[21] = this.dma_channel_8bit
456
+ state[22] = this.dma_channel_16bit
457
+ state[23] = this.dma_autoinit
458
+ state[24] = this.dma_buffer_uint8
459
+ state[25] = this.dma_waiting_transfer
460
+ state[26] = this.dma_paused
461
+ state[27] = this.sampling_rate
462
+ state[28] = this.bytes_per_sample
463
+
464
+ state[29] = this.e2_value
465
+ state[30] = this.e2_count
466
+
467
+ state[31] = this.asp_registers
468
+
469
+ // state[32] = this.mpu_read_buffer;
470
+ state[33] = this.mpu_read_buffer_last_value
471
+
472
+ state[34] = this.irq
473
+ state[35] = this.irq_triggered
474
+ //state[36]
475
+
476
+ return state
477
+ }
478
+
479
+ set_state(state: any[]): void {
480
+ // this.write_buffer = state[0];
481
+ // this.read_buffer = state[1];
482
+ this.read_buffer_lastvalue = state[2]
483
+
484
+ this.command = state[3]
485
+ this.command_size = state[4]
486
+
487
+ this.mixer_current_address = state[5]
488
+ this.mixer_registers = state[6]
489
+ this.mixer_full_update()
490
+
491
+ this.dummy_speaker_enabled = state[7]
492
+ this.test_register = state[8]
493
+
494
+ this.dsp_highspeed = state[9]
495
+ this.dsp_stereo = state[10]
496
+ this.dsp_16bit = state[11]
497
+ this.dsp_signed = state[12]
498
+
499
+ // this.dac_buffers = state[13];
500
+ //state[14]
501
+
502
+ this.dma_sample_count = state[15]
503
+ this.dma_bytes_count = state[16]
504
+ this.dma_bytes_left = state[17]
505
+ this.dma_bytes_block = state[18]
506
+ this.dma_irq = state[19]
507
+ this.dma_channel = state[20]
508
+ this.dma_channel_8bit = state[21]
509
+ this.dma_channel_16bit = state[22]
510
+ this.dma_autoinit = state[23]
511
+ this.dma_buffer_uint8 = state[24]
512
+ this.dma_waiting_transfer = state[25]
513
+ this.dma_paused = state[26]
514
+ this.sampling_rate = state[27]
515
+ this.bytes_per_sample = state[28]
516
+
517
+ this.e2_value = state[29]
518
+ this.e2_count = state[30]
519
+
520
+ this.asp_registers = state[31]
521
+
522
+ // this.mpu_read_buffer = state[32];
523
+ this.mpu_read_buffer_last_value = state[33]
524
+
525
+ this.irq = state[34]
526
+ this.irq_triggered = state[35]
527
+ //state[36];
528
+
529
+ const buf = this.dma_buffer_uint8.buffer
530
+ if (buf instanceof ArrayBuffer) {
531
+ this.dma_buffer = buf
532
+ }
533
+ this.dma_buffer_int8 = new Int8Array(this.dma_buffer)
534
+ this.dma_buffer_int16 = new Int16Array(this.dma_buffer)
535
+ this.dma_buffer_uint16 = new Uint16Array(this.dma_buffer)
536
+ this.dma_syncbuffer = new SyncBuffer(this.dma_buffer)
537
+
538
+ if (this.dma_paused) {
539
+ this.bus.send('dac-disable')
540
+ } else {
541
+ this.bus.send('dac-enable')
542
+ }
543
+ }
544
+
545
+ //
546
+ // I/O handlers
547
+ //
548
+
549
+ port2x0_read(): number {
550
+ dbg_log('220 read: fm music status port (unimplemented)', LOG_SB16)
551
+ return 0xff
552
+ }
553
+
554
+ port2x1_read(): number {
555
+ dbg_log('221 read: fm music data port (write only)', LOG_SB16)
556
+ return 0xff
557
+ }
558
+
559
+ port2x2_read(): number {
560
+ dbg_log(
561
+ '222 read: advanced fm music status port (unimplemented)',
562
+ LOG_SB16,
563
+ )
564
+ return 0xff
565
+ }
566
+
567
+ port2x3_read(): number {
568
+ dbg_log('223 read: advanced music data port (write only)', LOG_SB16)
569
+ return 0xff
570
+ }
571
+
572
+ // Mixer Address Port.
573
+ port2x4_read(): number {
574
+ dbg_log('224 read: mixer address port', LOG_SB16)
575
+ return this.mixer_current_address
576
+ }
577
+
578
+ // Mixer Data Port.
579
+ port2x5_read(): number {
580
+ dbg_log('225 read: mixer data port', LOG_SB16)
581
+ return this.mixer_read(this.mixer_current_address)
582
+ }
583
+
584
+ port2x6_read(): number {
585
+ dbg_log('226 read: (write only)', LOG_SB16)
586
+ return 0xff
587
+ }
588
+
589
+ port2x7_read(): number {
590
+ dbg_log('227 read: undocumented', LOG_SB16)
591
+ return 0xff
592
+ }
593
+
594
+ port2x8_read(): number {
595
+ dbg_log('228 read: fm music status port (unimplemented)', LOG_SB16)
596
+ return 0xff
597
+ }
598
+
599
+ port2x9_read(): number {
600
+ dbg_log('229 read: fm music data port (write only)', LOG_SB16)
601
+ return 0xff
602
+ }
603
+
604
+ // Read Data.
605
+ // Used to access in-bound DSP data.
606
+ port2xA_read(): number {
607
+ dbg_log('22A read: read data', LOG_SB16)
608
+ if (this.read_buffer.length) {
609
+ this.read_buffer_lastvalue = this.read_buffer.shift()
610
+ }
611
+ dbg_log(
612
+ ' <- ' +
613
+ this.read_buffer_lastvalue +
614
+ ' ' +
615
+ h(this.read_buffer_lastvalue) +
616
+ " '" +
617
+ String.fromCharCode(this.read_buffer_lastvalue) +
618
+ "'",
619
+ LOG_SB16,
620
+ )
621
+ return this.read_buffer_lastvalue
622
+ }
623
+
624
+ port2xB_read(): number {
625
+ dbg_log('22B read: undocumented', LOG_SB16)
626
+ return 0xff
627
+ }
628
+
629
+ // Write-Buffer Status.
630
+ // Indicates whether the DSP is ready to accept commands or data.
631
+ port2xC_read(): number {
632
+ dbg_log('22C read: write-buffer status', LOG_SB16)
633
+ // Always return ready (bit-7 set to low)
634
+ return 0x7f
635
+ }
636
+
637
+ port2xD_read(): number {
638
+ dbg_log('22D read: undocumented', LOG_SB16)
639
+ return 0xff
640
+ }
641
+
642
+ // Read-Buffer Status.
643
+ // Indicates whether there is any in-bound data available for reading.
644
+ // Also used to acknowledge DSP 8-bit interrupt.
645
+ port2xE_read(): number {
646
+ dbg_log('22E read: read-buffer status / irq 8bit ack.', LOG_SB16)
647
+ if (this.irq_triggered[SB_IRQ_8BIT]) {
648
+ this.lower_irq(SB_IRQ_8BIT)
649
+ }
650
+ const ready = this.read_buffer.length && !this.dsp_highspeed
651
+ return ((ready ? 1 : 0) << 7) | 0x7f
652
+ }
653
+
654
+ // DSP 16-bit interrupt acknowledgement.
655
+ port2xF_read(): number {
656
+ dbg_log('22F read: irq 16bit ack', LOG_SB16)
657
+ this.lower_irq(SB_IRQ_16BIT)
658
+ return 0
659
+ }
660
+
661
+ // FM Address Port - primary register.
662
+ port2x0_write(_value: number): void {
663
+ dbg_log(
664
+ '220 write: (unimplemented) fm register 0 address = ' + h(_value),
665
+ LOG_SB16,
666
+ )
667
+ this.fm_current_address0 = 0
668
+ }
669
+
670
+ // FM Data Port - primary register.
671
+ port2x1_write(value: number): void {
672
+ dbg_log(
673
+ '221 write: (unimplemented) fm register 0 data = ' + h(value),
674
+ LOG_SB16,
675
+ )
676
+ let handler = FM_HANDLERS[this.fm_current_address0]
677
+ if (!handler) {
678
+ handler = this.fm_default_write
679
+ }
680
+ handler.call(this, value, 0, this.fm_current_address0)
681
+ }
682
+
683
+ // FM Address Port - secondary register.
684
+ port2x2_write(_value: number): void {
685
+ dbg_log(
686
+ '222 write: (unimplemented) fm register 1 address = ' + h(_value),
687
+ LOG_SB16,
688
+ )
689
+ this.fm_current_address1 = 0
690
+ }
691
+
692
+ // FM Data Port - secondary register.
693
+ port2x3_write(value: number): void {
694
+ dbg_log(
695
+ '223 write: (unimplemented) fm register 1 data =' + h(value),
696
+ LOG_SB16,
697
+ )
698
+ let handler = FM_HANDLERS[this.fm_current_address1]
699
+ if (!handler) {
700
+ handler = this.fm_default_write
701
+ }
702
+ handler.call(this, value, 1, this.fm_current_address1)
703
+ }
704
+
705
+ // Mixer Address Port.
706
+ port2x4_write(value: number): void {
707
+ dbg_log('224 write: mixer address = ' + h(value), LOG_SB16)
708
+ this.mixer_current_address = value
709
+ }
710
+
711
+ // Mixer Data Port.
712
+ port2x5_write(value: number): void {
713
+ dbg_log('225 write: mixer data = ' + h(value), LOG_SB16)
714
+ this.mixer_write(this.mixer_current_address, value)
715
+ }
716
+
717
+ // Reset.
718
+ // Used to reset the DSP to its default state and to exit highspeed mode.
719
+ port2x6_write(yesplease: number): void {
720
+ dbg_log('226 write: reset = ' + h(yesplease), LOG_SB16)
721
+
722
+ if (this.dsp_highspeed) {
723
+ dbg_log(' -> exit highspeed', LOG_SB16)
724
+ this.dsp_highspeed = false
725
+ } else if (yesplease) {
726
+ dbg_log(' -> reset', LOG_SB16)
727
+ this.dsp_reset()
728
+ }
729
+
730
+ // Signal completion.
731
+ this.read_buffer.clear()
732
+ this.read_buffer.push(0xaa)
733
+ }
734
+
735
+ port2x7_write(_value: number): void {
736
+ dbg_log('227 write: undocumented', LOG_SB16)
737
+ }
738
+
739
+ port2x8_write(_value: number): void {
740
+ dbg_log('228 write: fm music register port (unimplemented)', LOG_SB16)
741
+ }
742
+
743
+ port2x9_write(_value: number): void {
744
+ dbg_log('229 write: fm music data port (unimplemented)', LOG_SB16)
745
+ }
746
+
747
+ port2xA_write(_value: number): void {
748
+ dbg_log('22A write: dsp read data port (read only)', LOG_SB16)
749
+ }
750
+
751
+ port2xB_write(_value: number): void {
752
+ dbg_log('22B write: undocumented', LOG_SB16)
753
+ }
754
+
755
+ // Write Command/Data.
756
+ // Used to send commands or data to the DSP.
757
+ port2xC_write(value: number): void {
758
+ dbg_log('22C write: write command/data', LOG_SB16)
759
+
760
+ if (this.command === DSP_NO_COMMAND) {
761
+ // New command.
762
+ dbg_log('22C write: command = ' + h(value), LOG_SB16)
763
+ this.command = value
764
+ this.write_buffer.clear()
765
+ this.command_size = DSP_COMMAND_SIZES[value]
766
+ } else {
767
+ // More data for current command.
768
+ dbg_log('22C write: data: ' + h(value), LOG_SB16)
769
+ this.write_buffer.push(value)
770
+ }
771
+
772
+ // Perform command when we have all the needed data.
773
+ if (this.write_buffer.length >= this.command_size) {
774
+ this.command_do()
775
+ }
776
+ }
777
+
778
+ port2xD_write(_value: number): void {
779
+ dbg_log('22D write: undocumented', LOG_SB16)
780
+ }
781
+
782
+ port2xE_write(_value: number): void {
783
+ dbg_log('22E write: dsp read buffer status (read only)', LOG_SB16)
784
+ }
785
+
786
+ port2xF_write(_value: number): void {
787
+ dbg_log('22F write: undocumented', LOG_SB16)
788
+ }
789
+
790
+ // MPU UART Mode - Data Port
791
+ port3x0_read(): number {
792
+ dbg_log('330 read: mpu data', LOG_SB16)
793
+
794
+ if (this.mpu_read_buffer.length) {
795
+ this.mpu_read_buffer_lastvalue = this.mpu_read_buffer.shift()
796
+ }
797
+ dbg_log(' <- ' + h(this.mpu_read_buffer_lastvalue), LOG_SB16)
798
+
799
+ return this.mpu_read_buffer_lastvalue
800
+ }
801
+ port3x0_write(value: number): void {
802
+ dbg_log('330 write: mpu data (unimplemented) : ' + h(value), LOG_SB16)
803
+ }
804
+
805
+ // MPU UART Mode - Status Port
806
+ port3x1_read(): number {
807
+ dbg_log('331 read: mpu status', LOG_SB16)
808
+
809
+ let status = 0
810
+ status |= 0x40 * 0 // Output Ready
811
+ status |= 0x80 * +!this.mpu_read_buffer.length // Input Ready
812
+
813
+ return status
814
+ }
815
+
816
+ // MPU UART Mode - Command Port
817
+ port3x1_write(value: number): void {
818
+ dbg_log('331 write: mpu command: ' + h(value), LOG_SB16)
819
+ if (value === 0xff) {
820
+ // Command acknowledge.
821
+ this.mpu_read_buffer.clear()
822
+ this.mpu_read_buffer.push(0xfe)
823
+ }
824
+ }
825
+
826
+ //
827
+ // DSP command handlers
828
+ //
829
+
830
+ command_do(): void {
831
+ let handler = DSP_COMMAND_HANDLERS[this.command]
832
+ if (!handler) {
833
+ handler = this.dsp_default_handler
834
+ }
835
+ handler.call(this)
836
+
837
+ // Reset Inputs.
838
+ this.command = DSP_NO_COMMAND
839
+ this.command_size = 0
840
+ this.write_buffer.clear()
841
+ }
842
+
843
+ dsp_default_handler(): void {
844
+ dbg_log('Unhandled command: ' + h(this.command), LOG_SB16)
845
+ }
846
+
847
+ //
848
+ // Mixer Handlers (CT1745)
849
+ //
850
+
851
+ mixer_read(address: number): number {
852
+ const handler = MIXER_READ_HANDLERS[address]
853
+ let data: number
854
+ if (handler) {
855
+ data = handler.call(this)
856
+ } else {
857
+ data = this.mixer_registers[address]
858
+ dbg_log(
859
+ 'unhandled mixer register read. addr:' +
860
+ h(address) +
861
+ ' data:' +
862
+ h(data),
863
+ LOG_SB16,
864
+ )
865
+ }
866
+ return data
867
+ }
868
+
869
+ mixer_write(address: number, data: number): void {
870
+ const handler = MIXER_WRITE_HANDLERS[address]
871
+ if (handler) {
872
+ handler.call(this, data)
873
+ } else {
874
+ dbg_log(
875
+ 'unhandled mixer register write. addr:' +
876
+ h(address) +
877
+ ' data:' +
878
+ h(data),
879
+ LOG_SB16,
880
+ )
881
+ }
882
+ }
883
+
884
+ mixer_default_read(): number {
885
+ dbg_log(
886
+ 'mixer register read. addr:' + h(this.mixer_current_address),
887
+ LOG_SB16,
888
+ )
889
+ return this.mixer_registers[this.mixer_current_address]
890
+ }
891
+
892
+ mixer_default_write(data: number): void {
893
+ dbg_log(
894
+ 'mixer register write. addr:' +
895
+ h(this.mixer_current_address) +
896
+ ' data:' +
897
+ h(data),
898
+ LOG_SB16,
899
+ )
900
+ this.mixer_registers[this.mixer_current_address] = data
901
+ }
902
+
903
+ mixer_reset(): void {
904
+ // Values intentionally in decimal.
905
+ // Default values available at
906
+ // https://pdos.csail.mit.edu/6.828/2011/readings/hardware/SoundBlaster.pdf
907
+ this.mixer_registers[0x04] = (12 << 4) | 12
908
+ this.mixer_registers[0x22] = (12 << 4) | 12
909
+ this.mixer_registers[0x26] = (12 << 4) | 12
910
+ this.mixer_registers[0x28] = 0
911
+ this.mixer_registers[0x2e] = 0
912
+ this.mixer_registers[0x0a] = 0
913
+ this.mixer_registers[0x30] = 24 << 3
914
+ this.mixer_registers[0x31] = 24 << 3
915
+ this.mixer_registers[0x32] = 24 << 3
916
+ this.mixer_registers[0x33] = 24 << 3
917
+ this.mixer_registers[0x34] = 24 << 3
918
+ this.mixer_registers[0x35] = 24 << 3
919
+ this.mixer_registers[0x36] = 0
920
+ this.mixer_registers[0x37] = 0
921
+ this.mixer_registers[0x38] = 0
922
+ this.mixer_registers[0x39] = 0
923
+ this.mixer_registers[0x3b] = 0
924
+ this.mixer_registers[0x3c] = 0x1f
925
+ this.mixer_registers[0x3d] = 0x15
926
+ this.mixer_registers[0x3e] = 0x0b
927
+ this.mixer_registers[0x3f] = 0
928
+ this.mixer_registers[0x40] = 0
929
+ this.mixer_registers[0x41] = 0
930
+ this.mixer_registers[0x42] = 0
931
+ this.mixer_registers[0x43] = 0
932
+ this.mixer_registers[0x44] = 8 << 4
933
+ this.mixer_registers[0x45] = 8 << 4
934
+ this.mixer_registers[0x46] = 8 << 4
935
+ this.mixer_registers[0x47] = 8 << 4
936
+
937
+ this.mixer_full_update()
938
+ }
939
+
940
+ mixer_full_update(): void {
941
+ // Start at 1. Don't re-reset.
942
+ for (let i = 1; i < this.mixer_registers.length; i++) {
943
+ if (MIXER_REGISTER_IS_LEGACY[i]) {
944
+ // Legacy registers are actually mapped to other register locations. Update
945
+ // using the new registers rather than the legacy registers.
946
+ continue
947
+ }
948
+ this.mixer_write(i, this.mixer_registers[i])
949
+ }
950
+ }
951
+
952
+ //
953
+ // FM Handlers
954
+ //
955
+
956
+ fm_default_write(data: number, register: number, address: number): void {
957
+ dbg_log(
958
+ 'unhandled fm register write. addr:' +
959
+ register +
960
+ '|' +
961
+ h(address) +
962
+ ' data:' +
963
+ h(data),
964
+ LOG_SB16,
965
+ )
966
+ // No need to save into a dummy register as the registers are write-only.
967
+ }
968
+
969
+ //
970
+ // FM behaviours
971
+ //
972
+
973
+ fm_update_waveforms(): void {
974
+ // To be implemented.
975
+ }
976
+
977
+ //
978
+ // General behaviours
979
+ //
980
+
981
+ sampling_rate_change(rate: number): void {
982
+ this.sampling_rate = rate
983
+ this.bus.send('dac-tell-sampling-rate', rate)
984
+ }
985
+
986
+ get_channel_count(): number {
987
+ return this.dsp_stereo ? 2 : 1
988
+ }
989
+
990
+ dma_transfer_size_set(): void {
991
+ this.dma_sample_count =
992
+ 1 +
993
+ (this.write_buffer.shift() << 0) +
994
+ (this.write_buffer.shift() << 8)
995
+ }
996
+
997
+ dma_transfer_start(): void {
998
+ dbg_log('begin dma transfer', LOG_SB16)
999
+
1000
+ // (1) Setup appropriate settings.
1001
+
1002
+ this.bytes_per_sample = 1
1003
+ if (this.dsp_16bit) this.bytes_per_sample *= 2
1004
+
1005
+ // Don't count stereo interleaved bits apparently.
1006
+ // Disabling this line is needed for sounds to work correctly,
1007
+ // especially double buffering autoinit mode.
1008
+ // Learnt the hard way.
1009
+ // if(this.dsp_stereo) this.bytes_per_sample *= 2;
1010
+
1011
+ this.dma_bytes_count = this.dma_sample_count * this.bytes_per_sample
1012
+ this.dma_bytes_block = SB_DMA_BLOCK_SAMPLES * this.bytes_per_sample
1013
+
1014
+ // Ensure block size is small enough but not too small, and is divisible by 4
1015
+ const max_bytes_block = Math.max((this.dma_bytes_count >> 2) & ~0x3, 32)
1016
+ this.dma_bytes_block = Math.min(max_bytes_block, this.dma_bytes_block)
1017
+
1018
+ // (2) Wait until channel is unmasked (if not already)
1019
+ this.dma_waiting_transfer = true
1020
+ if (!this.dma.channel_mask[this.dma_channel]) {
1021
+ this.dma_on_unmask(this.dma_channel)
1022
+ }
1023
+ }
1024
+
1025
+ dma_on_unmask(channel: number): void {
1026
+ if (channel !== this.dma_channel || !this.dma_waiting_transfer) {
1027
+ return
1028
+ }
1029
+
1030
+ // (3) Configure amount of bytes left to transfer and tell speaker adapter
1031
+ // to start requesting transfers
1032
+ this.dma_waiting_transfer = false
1033
+ this.dma_bytes_left = this.dma_bytes_count
1034
+ this.dma_paused = false
1035
+ this.bus.send('dac-enable')
1036
+ }
1037
+
1038
+ dma_transfer_next(): void {
1039
+ dbg_log('dma transfering next block', LOG_SB16)
1040
+
1041
+ const size = Math.min(this.dma_bytes_left, this.dma_bytes_block)
1042
+ const samples = Math.floor(size / this.bytes_per_sample)
1043
+
1044
+ this.dma.do_write(
1045
+ this.dma_syncbuffer,
1046
+ 0,
1047
+ size,
1048
+ this.dma_channel,
1049
+ (error: boolean) => {
1050
+ dbg_log(
1051
+ 'dma block transfer ' +
1052
+ (error ? 'unsuccessful' : 'successful'),
1053
+ LOG_SB16,
1054
+ )
1055
+ if (error) return
1056
+
1057
+ this.dma_to_dac(samples)
1058
+ this.dma_bytes_left -= size
1059
+
1060
+ if (!this.dma_bytes_left) {
1061
+ // Completed requested transfer of given size.
1062
+ this.raise_irq(this.dma_irq)
1063
+
1064
+ if (this.dma_autoinit) {
1065
+ // Restart the transfer.
1066
+ this.dma_bytes_left = this.dma_bytes_count
1067
+ }
1068
+ }
1069
+ },
1070
+ )
1071
+ }
1072
+
1073
+ dma_to_dac(sample_count: number): void {
1074
+ const amplitude = this.dsp_16bit ? 32767.5 : 127.5
1075
+ const offset = this.dsp_signed ? 0 : -1
1076
+ const repeats = this.dsp_stereo ? 1 : 2
1077
+
1078
+ let buffer: Int8Array | Uint8Array | Int16Array | Uint16Array
1079
+ if (this.dsp_16bit) {
1080
+ buffer = this.dsp_signed
1081
+ ? this.dma_buffer_int16
1082
+ : this.dma_buffer_uint16
1083
+ } else {
1084
+ buffer = this.dsp_signed
1085
+ ? this.dma_buffer_int8
1086
+ : this.dma_buffer_uint8
1087
+ }
1088
+
1089
+ let channel = 0
1090
+ for (let i = 0; i < sample_count; i++) {
1091
+ const sample = audio_normalize(buffer[i], amplitude, offset)
1092
+ for (let j = 0; j < repeats; j++) {
1093
+ this.dac_buffers[channel].push(sample)
1094
+ channel ^= 1
1095
+ }
1096
+ }
1097
+
1098
+ this.dac_send()
1099
+ }
1100
+
1101
+ dac_handle_request(): void {
1102
+ if (!this.dma_bytes_left || this.dma_paused) {
1103
+ // No more data to transfer or is paused. Send whatever is in the buffers.
1104
+ this.dac_send()
1105
+ } else {
1106
+ this.dma_transfer_next()
1107
+ }
1108
+ }
1109
+
1110
+ dac_send(): void {
1111
+ if (!this.dac_buffers[0].length) {
1112
+ return
1113
+ }
1114
+
1115
+ const out0 = this.dac_buffers[0].shift_block(this.dac_buffers[0].length)
1116
+ const out1 = this.dac_buffers[1].shift_block(this.dac_buffers[1].length)
1117
+ this.bus.send('dac-send-data', [out0, out1], [out0.buffer, out1.buffer])
1118
+ }
1119
+
1120
+ raise_irq(type?: number): void {
1121
+ dbg_log('raise irq', LOG_SB16)
1122
+ if (type !== undefined) {
1123
+ this.irq_triggered[type] = 1
1124
+ }
1125
+ this.cpu.device_raise_irq(this.irq)
1126
+ }
1127
+
1128
+ lower_irq(type: number): void {
1129
+ dbg_log('lower irq', LOG_SB16)
1130
+ this.irq_triggered[type] = 0
1131
+ this.cpu.device_lower_irq(this.irq)
1132
+ }
1133
+ }
1134
+
1135
+ //
1136
+ // DSP command registration
1137
+ //
1138
+
1139
+ function register_dsp_command(
1140
+ commands: number[],
1141
+ size: number,
1142
+ handler?: (this: SB16) => void,
1143
+ ): void {
1144
+ if (!handler) {
1145
+ handler = SB16.prototype.dsp_default_handler
1146
+ }
1147
+ for (let i = 0; i < commands.length; i++) {
1148
+ DSP_COMMAND_SIZES[commands[i]] = size
1149
+ DSP_COMMAND_HANDLERS[commands[i]] = handler
1150
+ }
1151
+ }
1152
+
1153
+ function any_first_digit(base: number): number[] {
1154
+ const commands: number[] = []
1155
+ for (let i = 0; i < 16; i++) {
1156
+ commands.push(base + i)
1157
+ }
1158
+ return commands
1159
+ }
1160
+
1161
+ // ASP set register
1162
+ register_dsp_command([0x0e], 2, function () {
1163
+ this.asp_registers[this.write_buffer.shift()] = this.write_buffer.shift()
1164
+ })
1165
+
1166
+ // ASP get register
1167
+ register_dsp_command([0x0f], 1, function () {
1168
+ this.read_buffer.clear()
1169
+ this.read_buffer.push(this.asp_registers[this.write_buffer.shift()])
1170
+ })
1171
+
1172
+ // 8-bit direct mode single byte digitized sound output.
1173
+ register_dsp_command([0x10], 1, function () {
1174
+ const value = audio_normalize(this.write_buffer.shift(), 127.5, -1)
1175
+
1176
+ this.dac_buffers[0].push(value)
1177
+ this.dac_buffers[1].push(value)
1178
+ this.bus.send('dac-enable')
1179
+ })
1180
+
1181
+ // 8-bit single-cycle DMA mode digitized sound output.
1182
+ register_dsp_command([0x14, 0x15], 2, function () {
1183
+ this.dma_irq = SB_IRQ_8BIT
1184
+ this.dma_channel = this.dma_channel_8bit
1185
+ this.dma_autoinit = false
1186
+ this.dsp_signed = false
1187
+ this.dsp_16bit = false
1188
+ this.dsp_highspeed = false
1189
+ this.dma_transfer_size_set()
1190
+ this.dma_transfer_start()
1191
+ })
1192
+
1193
+ // Creative 8-bit to 2-bit ADPCM single-cycle DMA mode digitized sound output.
1194
+ register_dsp_command([0x16], 2)
1195
+
1196
+ // Creative 8-bit to 2-bit ADPCM single-cycle DMA mode digitzed sound output
1197
+ // with reference byte.
1198
+ register_dsp_command([0x17], 2)
1199
+
1200
+ // 8-bit auto-init DMA mode digitized sound output.
1201
+ register_dsp_command([0x1c], 0, function () {
1202
+ this.dma_irq = SB_IRQ_8BIT
1203
+ this.dma_channel = this.dma_channel_8bit
1204
+ this.dma_autoinit = true
1205
+ this.dsp_signed = false
1206
+ this.dsp_16bit = false
1207
+ this.dsp_highspeed = false
1208
+ this.dma_transfer_start()
1209
+ })
1210
+
1211
+ // Creative 8-bit to 2-bit ADPCM auto-init DMA mode digitized sound output
1212
+ // with reference byte.
1213
+ register_dsp_command([0x1f], 0)
1214
+
1215
+ // 8-bit direct mode single byte digitized sound input.
1216
+ register_dsp_command([0x20], 0, function () {
1217
+ // Fake silent input.
1218
+ this.read_buffer.clear()
1219
+ this.read_buffer.push(0x7f)
1220
+ })
1221
+
1222
+ // 8-bit single-cycle DMA mode digitized sound input.
1223
+ register_dsp_command([0x24], 2)
1224
+
1225
+ // 8-bit auto-init DMA mode digitized sound input.
1226
+ register_dsp_command([0x2c], 0)
1227
+
1228
+ // Polling mode MIDI input.
1229
+ register_dsp_command([0x30], 0)
1230
+
1231
+ // Interrupt mode MIDI input.
1232
+ register_dsp_command([0x31], 0)
1233
+
1234
+ // UART polling mode MIDI I/O.
1235
+ register_dsp_command([0x34], 0)
1236
+
1237
+ // UART interrupt mode MIDI I/O.
1238
+ register_dsp_command([0x35], 0)
1239
+
1240
+ // UART polling mode MIDI I/O with time stamping.
1241
+ register_dsp_command([0x36], 0)
1242
+
1243
+ // UART interrupt mode MIDI I/O with time stamping.
1244
+ register_dsp_command([0x37], 0)
1245
+
1246
+ // MIDI output.
1247
+ register_dsp_command([0x38], 0)
1248
+
1249
+ // Set digitized sound transfer Time Constant.
1250
+ register_dsp_command([0x40], 1, function () {
1251
+ // Note: bTimeConstant = 256 * time constant
1252
+ this.sampling_rate_change(
1253
+ 1000000 / (256 - this.write_buffer.shift()) / this.get_channel_count(),
1254
+ )
1255
+ })
1256
+
1257
+ // Set digitized sound output sampling rate.
1258
+ // Set digitized sound input sampling rate.
1259
+ register_dsp_command([0x41, 0x42], 2, function () {
1260
+ this.sampling_rate_change(
1261
+ (this.write_buffer.shift() << 8) | this.write_buffer.shift(),
1262
+ )
1263
+ })
1264
+
1265
+ // Set DSP block transfer size.
1266
+ register_dsp_command([0x48], 2, function () {
1267
+ // TODO: should be in bytes, but if this is only used
1268
+ // for 8 bit transfers, then this number is the same
1269
+ // as number of samples?
1270
+ // Wrong: e.g. stereo requires two bytes per sample.
1271
+ this.dma_transfer_size_set()
1272
+ })
1273
+
1274
+ // Creative 8-bit to 4-bit ADPCM single-cycle DMA mode digitized sound output.
1275
+ register_dsp_command([0x74], 2)
1276
+
1277
+ // Creative 8-bit to 4-bit ADPCM single-cycle DMA mode digitized sound output
1278
+ // with referene byte.
1279
+ register_dsp_command([0x75], 2)
1280
+
1281
+ // Creative 8-bit to 3-bit ADPCM single-cycle DMA mode digitized sound output.
1282
+ register_dsp_command([0x76], 2)
1283
+
1284
+ // Creative 8-bit to 3-bit ADPCM single-cycle DMA mode digitized sound output
1285
+ // with referene byte.
1286
+ register_dsp_command([0x77], 2)
1287
+
1288
+ // Creative 8-bit to 4-bit ADPCM auto-init DMA mode digitized sound output
1289
+ // with reference byte.
1290
+ register_dsp_command([0x7d], 0)
1291
+
1292
+ // Creative 8-bit to 3-bit ADPCM auto-init DMA mode digitized sound output
1293
+ // with reference byte.
1294
+ register_dsp_command([0x7f], 0)
1295
+
1296
+ // Pause DAC for a duration.
1297
+ register_dsp_command([0x80], 2)
1298
+
1299
+ // 8-bit high-speed auto-init DMA mode digitized sound output.
1300
+ register_dsp_command([0x90], 0, function () {
1301
+ this.dma_irq = SB_IRQ_8BIT
1302
+ this.dma_channel = this.dma_channel_8bit
1303
+ this.dma_autoinit = true
1304
+ this.dsp_signed = false
1305
+ this.dsp_highspeed = true
1306
+ this.dsp_16bit = false
1307
+ this.dma_transfer_start()
1308
+ })
1309
+
1310
+ // 8-bit high-speed single-cycle DMA mode digitized sound input.
1311
+ register_dsp_command([0x91], 0)
1312
+
1313
+ // 8-bit high-speed auto-init DMA mode digitized sound input.
1314
+ register_dsp_command([0x98], 0)
1315
+
1316
+ // 8-bit high-speed single-cycle DMA mode digitized sound input.
1317
+ register_dsp_command([0x99], 0)
1318
+
1319
+ // Set input mode to mono.
1320
+ register_dsp_command([0xa0], 0)
1321
+
1322
+ // Set input mode to stereo.
1323
+ register_dsp_command([0xa8], 0)
1324
+
1325
+ // Program 16-bit DMA mode digitized sound I/O.
1326
+ register_dsp_command(any_first_digit(0xb0), 3, function () {
1327
+ if (this.command & (1 << 3)) {
1328
+ // Analogue to digital not implemented.
1329
+ this.dsp_default_handler()
1330
+ return
1331
+ }
1332
+ const mode = this.write_buffer.shift()
1333
+ this.dma_irq = SB_IRQ_16BIT
1334
+ this.dma_channel = this.dma_channel_16bit
1335
+ this.dma_autoinit = !!(this.command & (1 << 2))
1336
+ this.dsp_signed = !!(mode & (1 << 4))
1337
+ this.dsp_stereo = !!(mode & (1 << 5))
1338
+ this.dsp_16bit = true
1339
+ this.dma_transfer_size_set()
1340
+ this.dma_transfer_start()
1341
+ })
1342
+
1343
+ // Program 8-bit DMA mode digitized sound I/O.
1344
+ register_dsp_command(any_first_digit(0xc0), 3, function () {
1345
+ if (this.command & (1 << 3)) {
1346
+ // Analogue to digital not implemented.
1347
+ this.dsp_default_handler()
1348
+ return
1349
+ }
1350
+ const mode = this.write_buffer.shift()
1351
+ this.dma_irq = SB_IRQ_8BIT
1352
+ this.dma_channel = this.dma_channel_8bit
1353
+ this.dma_autoinit = !!(this.command & (1 << 2))
1354
+ this.dsp_signed = !!(mode & (1 << 4))
1355
+ this.dsp_stereo = !!(mode & (1 << 5))
1356
+ this.dsp_16bit = false
1357
+ this.dma_transfer_size_set()
1358
+ this.dma_transfer_start()
1359
+ })
1360
+
1361
+ // Pause 8-bit DMA mode digitized sound I/O.
1362
+ register_dsp_command([0xd0], 0, function () {
1363
+ this.dma_paused = true
1364
+ this.bus.send('dac-disable')
1365
+ })
1366
+
1367
+ // Turn on speaker.
1368
+ // Documented to have no effect on SB16.
1369
+ register_dsp_command([0xd1], 0, function () {
1370
+ this.dummy_speaker_enabled = true
1371
+ })
1372
+
1373
+ // Turn off speaker.
1374
+ // Documented to have no effect on SB16.
1375
+ register_dsp_command([0xd3], 0, function () {
1376
+ this.dummy_speaker_enabled = false
1377
+ })
1378
+
1379
+ // Continue 8-bit DMA mode digitized sound I/O.
1380
+ register_dsp_command([0xd4], 0, function () {
1381
+ this.dma_paused = false
1382
+ this.bus.send('dac-enable')
1383
+ })
1384
+
1385
+ // Pause 16-bit DMA mode digitized sound I/O.
1386
+ register_dsp_command([0xd5], 0, function () {
1387
+ this.dma_paused = true
1388
+ this.bus.send('dac-disable')
1389
+ })
1390
+
1391
+ // Continue 16-bit DMA mode digitized sound I/O.
1392
+ register_dsp_command([0xd6], 0, function () {
1393
+ this.dma_paused = false
1394
+ this.bus.send('dac-enable')
1395
+ })
1396
+
1397
+ // Get speaker status.
1398
+ register_dsp_command([0xd8], 0, function () {
1399
+ this.read_buffer.clear()
1400
+ this.read_buffer.push(+this.dummy_speaker_enabled * 0xff)
1401
+ })
1402
+
1403
+ // Exit 16-bit auto-init DMA mode digitized sound I/O.
1404
+ // Exit 8-bit auto-init mode digitized sound I/O.
1405
+ register_dsp_command([0xd9, 0xda], 0, function () {
1406
+ this.dma_autoinit = false
1407
+ })
1408
+
1409
+ // DSP identification
1410
+ register_dsp_command([0xe0], 1, function () {
1411
+ this.read_buffer.clear()
1412
+ this.read_buffer.push(~this.write_buffer.shift())
1413
+ })
1414
+
1415
+ // Get DSP version number.
1416
+ register_dsp_command([0xe1], 0, function () {
1417
+ this.read_buffer.clear()
1418
+ this.read_buffer.push(4)
1419
+ this.read_buffer.push(5)
1420
+ })
1421
+
1422
+ // DMA identification.
1423
+ register_dsp_command([0xe2], 1)
1424
+
1425
+ // Get DSP copyright.
1426
+ register_dsp_command([0xe3], 0, function () {
1427
+ this.read_buffer.clear()
1428
+ for (let i = 0; i < DSP_COPYRIGHT.length; i++) {
1429
+ this.read_buffer.push(DSP_COPYRIGHT.charCodeAt(i))
1430
+ }
1431
+ // Null terminator.
1432
+ this.read_buffer.push(0)
1433
+ })
1434
+
1435
+ // Write test register.
1436
+ register_dsp_command([0xe4], 1, function () {
1437
+ this.test_register = this.write_buffer.shift()
1438
+ })
1439
+
1440
+ // Read test register.
1441
+ register_dsp_command([0xe8], 0, function () {
1442
+ this.read_buffer.clear()
1443
+ this.read_buffer.push(this.test_register)
1444
+ })
1445
+
1446
+ // Trigger IRQ
1447
+ register_dsp_command([0xf2, 0xf3], 0, function () {
1448
+ this.raise_irq()
1449
+ })
1450
+
1451
+ // ASP - unknown function
1452
+ const SB_F9 = new Uint8Array(256)
1453
+ SB_F9[0x0e] = 0xff
1454
+ SB_F9[0x0f] = 0x07
1455
+ SB_F9[0x37] = 0x38
1456
+ register_dsp_command([0xf9], 1, function () {
1457
+ const input = this.write_buffer.shift()
1458
+ dbg_log('dsp 0xf9: unknown function. input: ' + input, LOG_SB16)
1459
+
1460
+ this.read_buffer.clear()
1461
+ this.read_buffer.push(SB_F9[input])
1462
+ })
1463
+
1464
+ //
1465
+ // Mixer registration
1466
+ //
1467
+
1468
+ function register_mixer_read(
1469
+ address: number,
1470
+ handler?: (this: SB16) => number,
1471
+ ): void {
1472
+ if (!handler) {
1473
+ handler = SB16.prototype.mixer_default_read
1474
+ }
1475
+ MIXER_READ_HANDLERS[address] = handler
1476
+ }
1477
+
1478
+ function register_mixer_write(
1479
+ address: number,
1480
+ handler?: (this: SB16, data: number) => void,
1481
+ ): void {
1482
+ if (!handler) {
1483
+ handler = SB16.prototype.mixer_default_write
1484
+ }
1485
+ MIXER_WRITE_HANDLERS[address] = handler
1486
+ }
1487
+
1488
+ // Legacy registers map each nibble to the last 4 bits of the new registers
1489
+ function register_mixer_legacy(
1490
+ address_old: number,
1491
+ address_new_left: number,
1492
+ address_new_right: number,
1493
+ ): void {
1494
+ MIXER_REGISTER_IS_LEGACY[address_old] = 1
1495
+
1496
+ MIXER_READ_HANDLERS[address_old] = function (this: SB16): number {
1497
+ const left = this.mixer_registers[address_new_left] & 0xf0
1498
+ const right = this.mixer_registers[address_new_right] >>> 4
1499
+ return left | right
1500
+ }
1501
+
1502
+ MIXER_WRITE_HANDLERS[address_old] = function (
1503
+ this: SB16,
1504
+ data: number,
1505
+ ): void {
1506
+ this.mixer_registers[address_old] = data
1507
+ const prev_left = this.mixer_registers[address_new_left]
1508
+ const prev_right = this.mixer_registers[address_new_right]
1509
+ const left = (data & 0xf0) | (prev_left & 0x0f)
1510
+ const right = ((data << 4) & 0xf0) | (prev_right & 0x0f)
1511
+
1512
+ this.mixer_write(address_new_left, left)
1513
+ this.mixer_write(address_new_right, right)
1514
+ }
1515
+ }
1516
+
1517
+ function register_mixer_volume(
1518
+ address: number,
1519
+ mixer_source: number,
1520
+ channel: number,
1521
+ ): void {
1522
+ MIXER_READ_HANDLERS[address] = SB16.prototype.mixer_default_read
1523
+
1524
+ MIXER_WRITE_HANDLERS[address] = function (this: SB16, data: number): void {
1525
+ this.mixer_registers[address] = data
1526
+ this.bus.send('mixer-volume', [
1527
+ mixer_source,
1528
+ channel,
1529
+ (data >>> 2) - 62,
1530
+ ])
1531
+ }
1532
+ }
1533
+
1534
+ // Reset.
1535
+ register_mixer_read(0x00, function () {
1536
+ this.mixer_reset()
1537
+ return 0
1538
+ })
1539
+ register_mixer_write(0x00)
1540
+
1541
+ // Legacy Voice Volume Left/Right.
1542
+ register_mixer_legacy(0x04, 0x32, 0x33)
1543
+
1544
+ // Legacy Mic Volume. TODO.
1545
+ //register_mixer_read(0x0A);
1546
+ //register_mixer_write(0x0A, function(data)
1547
+ //{
1548
+ // this.mixer_registers[0x0A] = data;
1549
+ // var prev = this.mixer_registers[0x3A];
1550
+ // this.mixer_write(0x3A, data << 5 | (prev & 0x0F));
1551
+ //});
1552
+
1553
+ // Legacy Master Volume Left/Right.
1554
+ register_mixer_legacy(0x22, 0x30, 0x31)
1555
+ // Legacy Midi Volume Left/Right.
1556
+ register_mixer_legacy(0x26, 0x34, 0x35)
1557
+ // Legacy CD Volume Left/Right.
1558
+ register_mixer_legacy(0x28, 0x36, 0x37)
1559
+ // Legacy Line Volume Left/Right.
1560
+ register_mixer_legacy(0x2e, 0x38, 0x39)
1561
+
1562
+ // Master Volume Left.
1563
+ register_mixer_volume(0x30, MIXER_SRC_MASTER, MIXER_CHANNEL_LEFT)
1564
+ // Master Volume Right.
1565
+ register_mixer_volume(0x31, MIXER_SRC_MASTER, MIXER_CHANNEL_RIGHT)
1566
+ // Voice Volume Left.
1567
+ register_mixer_volume(0x32, MIXER_SRC_DAC, MIXER_CHANNEL_LEFT)
1568
+ // Voice Volume Right.
1569
+ register_mixer_volume(0x33, MIXER_SRC_DAC, MIXER_CHANNEL_RIGHT)
1570
+ // MIDI Volume Left. TODO.
1571
+ //register_mixer_volume(0x34, MIXER_SRC_SYNTH, MIXER_CHANNEL_LEFT);
1572
+ // MIDI Volume Right. TODO.
1573
+ //register_mixer_volume(0x35, MIXER_SRC_SYNTH, MIXER_CHANNEL_RIGHT);
1574
+ // CD Volume Left. TODO.
1575
+ //register_mixer_volume(0x36, MIXER_SRC_CD, MIXER_CHANNEL_LEFT);
1576
+ // CD Volume Right. TODO.
1577
+ //register_mixer_volume(0x37, MIXER_SRC_CD, MIXER_CHANNEL_RIGHT);
1578
+ // Line Volume Left. TODO.
1579
+ //register_mixer_volume(0x38, MIXER_SRC_LINE, MIXER_CHANNEL_LEFT);
1580
+ // Line Volume Right. TODO.
1581
+ //register_mixer_volume(0x39, MIXER_SRC_LINE, MIXER_CHANNEL_RIGHT);
1582
+ // Mic Volume. TODO.
1583
+ //register_mixer_volume(0x3A, MIXER_SRC_MIC, MIXER_CHANNEL_BOTH);
1584
+
1585
+ // PC Speaker Volume.
1586
+ register_mixer_read(0x3b)
1587
+ register_mixer_write(0x3b, function (data) {
1588
+ this.mixer_registers[0x3b] = data
1589
+ this.bus.send('mixer-volume', [
1590
+ MIXER_SRC_PCSPEAKER,
1591
+ MIXER_CHANNEL_BOTH,
1592
+ (data >>> 6) * 6 - 18,
1593
+ ])
1594
+ })
1595
+
1596
+ // Output Mixer Switches. TODO.
1597
+ //register_mixer_read(0x3C);
1598
+ //register_mixer_write(0x3C, function(data)
1599
+ //{
1600
+ // this.mixer_registers[0x3C] = data;
1601
+ //
1602
+ // if(data & 0x01) this.bus.send("mixer-connect", [MIXER_SRC_MIC, MIXER_CHANNEL_BOTH]);
1603
+ // else this.bus.send("mixer-disconnect", [MIXER_SRC_MIC, MIXER_CHANNEL_BOTH]);
1604
+ //
1605
+ // if(data & 0x02) this.bus.send("mixer-connect", [MIXER_SRC_CD, MIXER_CHANNEL_RIGHT]);
1606
+ // else this.bus.send("mixer-disconnect", [MIXER_SRC_CD, MIXER_CHANNEL_RIGHT]);
1607
+ //
1608
+ // if(data & 0x04) this.bus.send("mixer-connect", [MIXER_SRC_CD, MIXER_CHANNEL_LEFT]);
1609
+ // else this.bus.send("mixer-disconnect", [MIXER_SRC_CD, MIXER_CHANNEL_LEFT]);
1610
+ //
1611
+ // if(data & 0x08) this.bus.send("mixer-connect", [MIXER_SRC_LINE, MIXER_CHANNEL_RIGHT]);
1612
+ // else this.bus.send("mixer-disconnect", [MIXER_SRC_LINE, MIXER_CHANNEL_RIGHT]);
1613
+ //
1614
+ // if(data & 0x10) this.bus.send("mixer-connect", [MIXER_SRC_LINE, MIXER_CHANNEL_LEFT]);
1615
+ // else this.bus.send("mixer-disconnect", [MIXER_SRC_LINE, MIXER_CHANNEL_LEFT]);
1616
+ //});
1617
+
1618
+ // Input Mixer Left Switches. TODO.
1619
+ //register_mixer_read(0x3D);
1620
+ //register_mixer_write(0x3D);
1621
+
1622
+ // Input Mixer Right Switches. TODO.
1623
+ //register_mixer_read(0x3E);
1624
+ //register_mixer_write(0x3E);
1625
+
1626
+ // Input Gain Left. TODO.
1627
+ //register_mixer_read(0x3F);
1628
+ //register_mixer_write(0x3F);
1629
+
1630
+ // Input Gain Right. TODO.
1631
+ //register_mixer_read(0x40);
1632
+ //register_mixer_write(0x40);
1633
+
1634
+ // Output Gain Left.
1635
+ register_mixer_read(0x41)
1636
+ register_mixer_write(0x41, function (data) {
1637
+ this.mixer_registers[0x41] = data
1638
+ this.bus.send('mixer-gain-left', (data >>> 6) * 6)
1639
+ })
1640
+
1641
+ // Output Gain Right.
1642
+ register_mixer_read(0x42)
1643
+ register_mixer_write(0x42, function (data) {
1644
+ this.mixer_registers[0x42] = data
1645
+ this.bus.send('mixer-gain-right', (data >>> 6) * 6)
1646
+ })
1647
+
1648
+ // Mic AGC. TODO.
1649
+ //register_mixer_read(0x43);
1650
+ //register_mixer_write(0x43);
1651
+
1652
+ // Treble Left.
1653
+ register_mixer_read(0x44)
1654
+ register_mixer_write(0x44, function (data) {
1655
+ this.mixer_registers[0x44] = data
1656
+ data >>>= 3
1657
+ this.bus.send('mixer-treble-left', data - (data < 16 ? 14 : 16))
1658
+ })
1659
+
1660
+ // Treble Right.
1661
+ register_mixer_read(0x45)
1662
+ register_mixer_write(0x45, function (data) {
1663
+ this.mixer_registers[0x45] = data
1664
+ data >>>= 3
1665
+ this.bus.send('mixer-treble-right', data - (data < 16 ? 14 : 16))
1666
+ })
1667
+
1668
+ // Bass Left.
1669
+ register_mixer_read(0x46)
1670
+ register_mixer_write(0x46, function (data) {
1671
+ this.mixer_registers[0x46] = data
1672
+ data >>>= 3
1673
+ this.bus.send('mixer-bass-right', data - (data < 16 ? 14 : 16))
1674
+ })
1675
+
1676
+ // Bass Right.
1677
+ register_mixer_read(0x47)
1678
+ register_mixer_write(0x47, function (data) {
1679
+ this.mixer_registers[0x47] = data
1680
+ data >>>= 3
1681
+ this.bus.send('mixer-bass-right', data - (data < 16 ? 14 : 16))
1682
+ })
1683
+
1684
+ // IRQ Select.
1685
+ register_mixer_read(0x80, function () {
1686
+ switch (this.irq) {
1687
+ case SB_IRQ2:
1688
+ return 0x1
1689
+ case SB_IRQ5:
1690
+ return 0x2
1691
+ case SB_IRQ7:
1692
+ return 0x4
1693
+ case SB_IRQ10:
1694
+ return 0x8
1695
+ default:
1696
+ return 0x0
1697
+ }
1698
+ })
1699
+ register_mixer_write(0x80, function (bits) {
1700
+ if (bits & 0x1) this.irq = SB_IRQ2
1701
+ if (bits & 0x2) this.irq = SB_IRQ5
1702
+ if (bits & 0x4) this.irq = SB_IRQ7
1703
+ if (bits & 0x8) this.irq = SB_IRQ10
1704
+ })
1705
+
1706
+ // DMA Select.
1707
+ register_mixer_read(0x81, function () {
1708
+ let ret = 0
1709
+ switch (this.dma_channel_8bit) {
1710
+ case SB_DMA0:
1711
+ ret |= 0x1
1712
+ break
1713
+ case SB_DMA1:
1714
+ ret |= 0x2
1715
+ break
1716
+ // Channel 2 is hardwired to floppy disk.
1717
+ case SB_DMA3:
1718
+ ret |= 0x8
1719
+ break
1720
+ }
1721
+ switch (this.dma_channel_16bit) {
1722
+ // Channel 4 cannot be used.
1723
+ case SB_DMA5:
1724
+ ret |= 0x20
1725
+ break
1726
+ case SB_DMA6:
1727
+ ret |= 0x40
1728
+ break
1729
+ case SB_DMA7:
1730
+ ret |= 0x80
1731
+ break
1732
+ }
1733
+ return ret
1734
+ })
1735
+ register_mixer_write(0x81, function (bits) {
1736
+ if (bits & 0x1) this.dma_channel_8bit = SB_DMA0
1737
+ if (bits & 0x2) this.dma_channel_8bit = SB_DMA1
1738
+ if (bits & 0x8) this.dma_channel_8bit = SB_DMA3
1739
+ if (bits & 0x20) this.dma_channel_16bit = SB_DMA5
1740
+ if (bits & 0x40) this.dma_channel_16bit = SB_DMA6
1741
+ if (bits & 0x80) this.dma_channel_16bit = SB_DMA7
1742
+ })
1743
+
1744
+ // IRQ Status.
1745
+ register_mixer_read(0x82, function () {
1746
+ let ret = 0x20
1747
+ for (let i = 0; i < 16; i++) {
1748
+ ret |= i * this.irq_triggered[i]
1749
+ }
1750
+ return ret
1751
+ })
1752
+
1753
+ //
1754
+ // FM registration
1755
+ //
1756
+
1757
+ function register_fm_write(
1758
+ addresses: number[],
1759
+ handler?: (
1760
+ this: SB16,
1761
+ data: number,
1762
+ register: number,
1763
+ address: number,
1764
+ ) => void,
1765
+ ): void {
1766
+ if (!handler) {
1767
+ handler = SB16.prototype.fm_default_write
1768
+ }
1769
+ for (let i = 0; i < addresses.length; i++) {
1770
+ FM_HANDLERS[addresses[i]] = handler
1771
+ }
1772
+ }
1773
+
1774
+ function between(start: number, end: number): number[] {
1775
+ const a: number[] = []
1776
+ for (let i = start; i <= end; i++) {
1777
+ a.push(i)
1778
+ }
1779
+ return a
1780
+ }
1781
+
1782
+ const SB_FM_OPERATORS_BY_OFFSET = new Uint8Array(32)
1783
+ SB_FM_OPERATORS_BY_OFFSET[0x00] = 0
1784
+ SB_FM_OPERATORS_BY_OFFSET[0x01] = 1
1785
+ SB_FM_OPERATORS_BY_OFFSET[0x02] = 2
1786
+ SB_FM_OPERATORS_BY_OFFSET[0x03] = 3
1787
+ SB_FM_OPERATORS_BY_OFFSET[0x04] = 4
1788
+ SB_FM_OPERATORS_BY_OFFSET[0x05] = 5
1789
+ SB_FM_OPERATORS_BY_OFFSET[0x08] = 6
1790
+ SB_FM_OPERATORS_BY_OFFSET[0x09] = 7
1791
+ SB_FM_OPERATORS_BY_OFFSET[0x0a] = 8
1792
+ SB_FM_OPERATORS_BY_OFFSET[0x0b] = 9
1793
+ SB_FM_OPERATORS_BY_OFFSET[0x0c] = 10
1794
+ SB_FM_OPERATORS_BY_OFFSET[0x0d] = 11
1795
+ SB_FM_OPERATORS_BY_OFFSET[0x10] = 12
1796
+ SB_FM_OPERATORS_BY_OFFSET[0x11] = 13
1797
+ SB_FM_OPERATORS_BY_OFFSET[0x12] = 14
1798
+ SB_FM_OPERATORS_BY_OFFSET[0x13] = 15
1799
+ SB_FM_OPERATORS_BY_OFFSET[0x14] = 16
1800
+ SB_FM_OPERATORS_BY_OFFSET[0x15] = 17
1801
+
1802
+ function get_fm_operator(register: number, offset: number): number {
1803
+ return register * 18 + SB_FM_OPERATORS_BY_OFFSET[offset]
1804
+ }
1805
+
1806
+ register_fm_write([0x01], function (_bits, register, _address) {
1807
+ this.fm_waveform_select_enable[register] = _bits & 1
1808
+ this.fm_update_waveforms()
1809
+ })
1810
+
1811
+ // Timer 1 Count.
1812
+ register_fm_write([0x02])
1813
+
1814
+ // Timer 2 Count.
1815
+ register_fm_write([0x03])
1816
+
1817
+ register_fm_write([0x04], function (_bits, register, _address) {
1818
+ switch (register) {
1819
+ case 0:
1820
+ // if(bits & 0x80)
1821
+ // {
1822
+ // // IQR Reset
1823
+ // }
1824
+ // else
1825
+ // {
1826
+ // // Timer masks and on/off
1827
+ // }
1828
+ break
1829
+ case 1:
1830
+ // Four-operator enable
1831
+ break
1832
+ }
1833
+ })
1834
+
1835
+ register_fm_write([0x05], function (bits, register, address) {
1836
+ if (register === 0) {
1837
+ // No registers documented here.
1838
+ this.fm_default_write(bits, register, address)
1839
+ } else {
1840
+ // OPL3 Mode Enable
1841
+ }
1842
+ })
1843
+
1844
+ register_fm_write([0x08], function (_bits, _register, _address) {
1845
+ // Composite sine wave on/off
1846
+ // Note select (keyboard split selection method)
1847
+ })
1848
+
1849
+ register_fm_write(between(0x20, 0x35), function (_bits, register, address) {
1850
+ const _operator = get_fm_operator(register, address - 0x20)
1851
+ // Tremolo
1852
+ // Vibrato
1853
+ // Sustain
1854
+ // KSR Envelope Scaling
1855
+ // Frequency Multiplication Factor
1856
+ })
1857
+
1858
+ register_fm_write(between(0x40, 0x55), function (_bits, register, address) {
1859
+ const _operator = get_fm_operator(register, address - 0x40)
1860
+ // Key Scale Level
1861
+ // Output Level
1862
+ })
1863
+
1864
+ register_fm_write(between(0x60, 0x75), function (_bits, register, address) {
1865
+ const _operator = get_fm_operator(register, address - 0x60)
1866
+ // Attack Rate
1867
+ // Decay Rate
1868
+ })
1869
+
1870
+ register_fm_write(between(0x80, 0x95), function (_bits, register, address) {
1871
+ const _operator = get_fm_operator(register, address - 0x80)
1872
+ // Sustain Level
1873
+ // Release Rate
1874
+ })
1875
+
1876
+ register_fm_write(between(0xa0, 0xa8), function (_bits, _register, address) {
1877
+ const _channel = address - 0xa0
1878
+ // Frequency Number (Lower 8 bits)
1879
+ })
1880
+
1881
+ register_fm_write(between(0xb0, 0xb8), function (_bits, _register, _address) {
1882
+ // Key-On
1883
+ // Block Number
1884
+ // Frequency Number (Higher 2 bits)
1885
+ })
1886
+
1887
+ register_fm_write([0xbd], function (_bits, _register, _address) {
1888
+ // Tremelo Depth
1889
+ // Vibrato Depth
1890
+ // Percussion Mode
1891
+ // Bass Drum Key-On
1892
+ // Snare Drum Key-On
1893
+ // Tom-Tom Key-On
1894
+ // Cymbal Key-On
1895
+ // Hi-Hat Key-On
1896
+ })
1897
+
1898
+ register_fm_write(between(0xc0, 0xc8), function (_bits, _register, _address) {
1899
+ // Right Speaker Enable
1900
+ // Left Speaker Enable
1901
+ // Feedback Modulation Factor
1902
+ // Synthesis Type
1903
+ })
1904
+
1905
+ register_fm_write(between(0xe0, 0xf5), function (_bits, register, address) {
1906
+ const _operator = get_fm_operator(register, address - 0xe0)
1907
+ // Waveform Select
1908
+ })
1909
+
1910
+ //
1911
+ // Helpers
1912
+ //
1913
+
1914
+ function audio_normalize(
1915
+ value: number,
1916
+ amplitude: number,
1917
+ offset: number,
1918
+ ): number {
1919
+ return audio_clip(value / amplitude + offset, -1, 1)
1920
+ }
1921
+
1922
+ function audio_clip(value: number, low: number, high: number): number {
1923
+ return (
1924
+ +(value < low) * low +
1925
+ +(value > high) * high +
1926
+ +(low <= value && value <= high) * value
1927
+ )
1928
+ }