PCem
view src/sound_sb_dsp.c @ 133:24b744b9a632
ViRGE S3D triangle rendering now uses worker thread.
Fixed clipping bug on ViRGE.
Fixed status window crash.
| author | TomW |
|---|---|
| date | Tue Jul 22 21:10:39 2014 +0100 |
| parents | bc749e3a164e |
| children |
line source
1 /*Jazz sample rates :
2 386-33 - 12kHz
3 486-33 - 20kHz
4 486-50 - 32kHz
5 Pentium - 45kHz*/
7 #include <stdint.h>
8 #include <stdio.h>
9 #include "ibm.h"
12 #include "dma.h"
13 #include "io.h"
14 #include "pic.h"
15 #include "sound.h"
16 #include "sound_sb_dsp.h"
17 #include "timer.h"
19 void pollsb(void *p);
20 void sb_poll_i(void *p);
24 static int sbe2dat[4][9] = {
25 { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 },
26 { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 },
27 { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 },
28 { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 }
29 };
31 static int sb_commands[256]=
32 {
33 -1,-1,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1,
34 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0,
35 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,
36 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
37 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,
38 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
39 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
40 -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0,
41 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1,
42 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,
43 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
44 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
45 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
46 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1,
47 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1,
48 -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0
49 };
51 char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
52 uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d};
54 /*These tables were 'borrowed' from DOSBox*/
55 int8_t scaleMap4[64] = {
56 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7,
57 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15,
58 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30,
59 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60
60 };
61 uint8_t adjustMap4[64] = {
62 0, 0, 0, 0, 0, 16, 16, 16,
63 0, 0, 0, 0, 0, 16, 16, 16,
64 240, 0, 0, 0, 0, 16, 16, 16,
65 240, 0, 0, 0, 0, 16, 16, 16,
66 240, 0, 0, 0, 0, 16, 16, 16,
67 240, 0, 0, 0, 0, 16, 16, 16,
68 240, 0, 0, 0, 0, 0, 0, 0,
69 240, 0, 0, 0, 0, 0, 0, 0
70 };
72 int8_t scaleMap26[40] = {
73 0, 1, 2, 3, 0, -1, -2, -3,
74 1, 3, 5, 7, -1, -3, -5, -7,
75 2, 6, 10, 14, -2, -6, -10, -14,
76 4, 12, 20, 28, -4, -12, -20, -28,
77 5, 15, 25, 35, -5, -15, -25, -35
78 };
79 uint8_t adjustMap26[40] = {
80 0, 0, 0, 8, 0, 0, 0, 8,
81 248, 0, 0, 8, 248, 0, 0, 8,
82 248, 0, 0, 8, 248, 0, 0, 8,
83 248, 0, 0, 8, 248, 0, 0, 8,
84 248, 0, 0, 0, 248, 0, 0, 0
85 };
87 int8_t scaleMap2[24] = {
88 0, 1, 0, -1, 1, 3, -1, -3,
89 2, 6, -2, -6, 4, 12, -4, -12,
90 8, 24, -8, -24, 6, 48, -16, -48
91 };
92 uint8_t adjustMap2[24] = {
93 0, 4, 0, 4,
94 252, 4, 252, 4, 252, 4, 252, 4,
95 252, 4, 252, 4, 252, 4, 252, 4,
96 252, 0, 252, 0
97 };
101 void sb_irq(sb_dsp_t *dsp, int irq8)
102 {
103 // pclog("IRQ %i %02X\n",irq8,pic.mask);
104 if (irq8) dsp->sb_irq8 = 1;
105 else dsp->sb_irq16 = 1;
106 picint(1 << dsp->sb_irqnum);
107 }
108 void sb_irqc(sb_dsp_t *dsp, int irq8)
109 {
110 if (irq8) dsp->sb_irq8 = 0;
111 else dsp->sb_irq16 = 0;
112 picintc(1 << dsp->sb_irqnum);
113 }
115 void sb_dsp_reset(sb_dsp_t *dsp)
116 {
117 dsp->sbenable = dsp->sb_enable_i = 0;
118 dsp->sb_command = 0;
120 dsp->sb_8_length = 0xffff;
122 sb_irqc(dsp, 0);
123 sb_irqc(dsp, 1);
124 dsp->sb_16_pause = 0;
125 dsp->sb_read_wp = dsp->sb_read_rp = 0;
126 dsp->sb_data_stat = -1;
127 dsp->sb_speaker = 0;
128 dsp->sb_pausetime = -1;
129 dsp->sbe2 = 0xAA;
130 dsp->sbe2count = 0;
132 dsp->sbreset = 0;
133 dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0;
135 picintc(1 << dsp->sb_irqnum);
136 }
138 void sb_doreset(sb_dsp_t *dsp)
139 {
140 int c;
142 sb_dsp_reset(dsp);
144 if (dsp->sb_type==SB16) sb_commands[8] = 1;
145 else sb_commands[8] = -1;
147 for (c = 0; c < 256; c++)
148 dsp->sb_asp_regs[c] = 0;
149 dsp->sb_asp_regs[5] = 0x01;
150 dsp->sb_asp_regs[9] = 0xf8;
151 }
153 void sb_dsp_speed_changed(sb_dsp_t *dsp)
154 {
155 if (dsp->sb_timeo < 256)
156 dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo);
157 else
158 dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256)));
160 if (dsp->sb_timei < 256)
161 dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei);
162 else
163 dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256)));
164 }
166 void sb_add_data(sb_dsp_t *dsp, uint8_t v)
167 {
168 dsp->sb_read_data[dsp->sb_read_wp++] = v;
169 dsp->sb_read_wp &= 0xff;
170 }
172 #define ADPCM_4 1
173 #define ADPCM_26 2
174 #define ADPCM_2 3
176 void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
177 {
178 if (dma8)
179 {
180 dsp->sb_8_length = len;
181 dsp->sb_8_format = format;
182 dsp->sb_8_autoinit = autoinit;
183 dsp->sb_8_pause = 0;
184 dsp->sb_8_enable = 1;
185 if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0;
186 dsp->sb_8_output = 1;
187 timer_process();
188 dsp->sbenable = dsp->sb_8_enable;
189 timer_update_outstanding();
190 dsp->sbleftright = 0;
191 dsp->sbdacpos = 0;
192 // pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
193 }
194 else
195 {
196 dsp->sb_16_length = len;
197 dsp->sb_16_format = format;
198 dsp->sb_16_autoinit = autoinit;
199 dsp->sb_16_pause = 0;
200 dsp->sb_16_enable = 1;
201 if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0;
202 dsp->sb_16_output = 1;
203 timer_process();
204 dsp->sbenable = dsp->sb_16_enable;
205 timer_update_outstanding();
206 // pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len);
207 }
208 }
210 void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
211 {
212 if (dma8)
213 {
214 dsp->sb_8_length = len;
215 dsp->sb_8_format = format;
216 dsp->sb_8_autoinit = autoinit;
217 dsp->sb_8_pause = 0;
218 dsp->sb_8_enable = 1;
219 if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0;
220 dsp->sb_8_output = 0;
221 timer_process();
222 dsp->sb_enable_i = dsp->sb_8_enable;
223 timer_update_outstanding();
224 // pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
225 }
226 else
227 {
228 dsp->sb_16_length = len;
229 dsp->sb_16_format = format;
230 dsp->sb_16_autoinit = autoinit;
231 dsp->sb_16_pause = 0;
232 dsp->sb_16_enable = 1;
233 if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0;
234 dsp->sb_16_output = 0;
235 timer_process();
236 dsp->sb_enable_i = dsp->sb_16_enable;
237 timer_update_outstanding();
238 // pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len);
239 }
240 }
242 int sb_8_read_dma(sb_dsp_t *dsp)
243 {
244 return dma_channel_read(dsp->sb_8_dmanum);
245 }
246 void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val)
247 {
248 dma_channel_write(dsp->sb_8_dmanum, val);
249 }
250 uint16_t sb_16_read_dma(sb_dsp_t *dsp)
251 {
252 return dma_channel_read(5);
253 }
254 void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val)
255 {
256 dma_channel_write(5, val);
257 }
259 void sb_dsp_setirq(sb_dsp_t *dsp, int irq)
260 {
261 dsp->sb_irqnum = irq;
262 }
264 void sb_dsp_setdma8(sb_dsp_t *dsp, int dma)
265 {
266 dsp->sb_8_dmanum = dma;
267 }
269 void sb_exec_command(sb_dsp_t *dsp)
270 {
271 int temp,c;
272 // pclog("sb_exec_command : SB command %02X\n", dsp->sb_command);
273 switch (dsp->sb_command)
274 {
275 case 0x01: /*???*/
276 sb_add_data(dsp, 0);
277 break;
278 case 0x03: /*ASP status*/
279 sb_add_data(dsp, 0);
280 break;
281 case 0x10: /*8-bit direct mode*/
282 dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8;
283 break;
284 case 0x14: /*8-bit single cycle DMA output*/
285 sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
286 break;
287 case 0x17: /*2-bit ADPCM output with reference*/
288 dsp->sbref = sb_8_read_dma(dsp);
289 dsp->sbstep = 0;
290 // pclog("Ref byte 2 %02X\n",sbref);
291 case 0x16: /*2-bit ADPCM output*/
292 sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
293 dsp->sbdat2 = sb_8_read_dma(dsp);
294 dsp->sb_8_length--;
295 break;
296 case 0x1C: /*8-bit autoinit DMA output*/
297 if (dsp->sb_type < SB15) break;
298 sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen);
299 break;
300 case 0x1F: /*2-bit ADPCM autoinit output*/
301 if (dsp->sb_type < SB15) break;
302 sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
303 dsp->sbdat2 = sb_8_read_dma(dsp);
304 dsp->sb_8_length--;
305 break;
306 case 0x20: /*8-bit direct input*/
307 sb_add_data(dsp, 0);
308 break;
309 case 0x24: /*8-bit single cycle DMA input*/
310 sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
311 break;
312 case 0x2C: /*8-bit autoinit DMA input*/
313 if (dsp->sb_type < SB15) break;
314 sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
315 break;
316 case 0x40: /*Set time constant*/
317 dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0];
318 dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]);
319 temp = 256 - dsp->sb_data[0];
320 temp = 1000000 / temp;
321 // pclog("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho);
322 dsp->sb_freq = temp;
323 break;
324 case 0x41: /*Set output sampling rate*/
325 case 0x42: /*Set input sampling rate*/
326 if (dsp->sb_type < SB16) break;
327 dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8))));
328 // pclog("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho);
329 dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8);
330 dsp->sb_timeo = 256 + dsp->sb_freq;
331 dsp->sblatchi = dsp->sblatcho;
332 dsp->sb_timei = dsp->sb_timeo;
333 break;
334 case 0x48: /*Set DSP block transfer size*/
335 dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8);
336 break;
337 case 0x75: /*4-bit ADPCM output with reference*/
338 dsp->sbref = sb_8_read_dma(dsp);
339 dsp->sbstep = 0;
340 // pclog("Ref byte 4 %02X\n",sbref);
341 case 0x74: /*4-bit ADPCM output*/
342 sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
343 dsp->sbdat2 = sb_8_read_dma(dsp);
344 dsp->sb_8_length--;
345 break;
346 case 0x77: /*2.6-bit ADPCM output with reference*/
347 dsp->sbref = sb_8_read_dma(dsp);
348 dsp->sbstep = 0;
349 // pclog("Ref byte 26 %02X\n",sbref);
350 case 0x76: /*2.6-bit ADPCM output*/
351 sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
352 dsp->sbdat2 = sb_8_read_dma(dsp);
353 dsp->sb_8_length--;
354 break;
355 case 0x7D: /*4-bit ADPCM autoinit output*/
356 if (dsp->sb_type < SB15) break;
357 sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
358 dsp->sbdat2 = sb_8_read_dma(dsp);
359 dsp->sb_8_length--;
360 break;
361 case 0x7F: /*2.6-bit ADPCM autoinit output*/
362 if (dsp->sb_type < SB15) break;
363 sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
364 dsp->sbdat2 = sb_8_read_dma(dsp);
365 dsp->sb_8_length--;
366 break;
367 case 0x80: /*Pause DAC*/
368 dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8);
369 // pclog("SB pause %04X\n",sb_pausetime);
370 timer_process();
371 dsp->sbenable = 1;
372 timer_update_outstanding();
373 break;
374 case 0x90: /*High speed 8-bit autoinit DMA output*/
375 if (dsp->sb_type < SB2) break;
376 sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen);
377 break;
378 case 0x91: /*High speed 8-bit single cycle DMA output*/
379 if (dsp->sb_type < SB2) break;
380 sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen);
381 break;
382 case 0x98: /*High speed 8-bit autoinit DMA input*/
383 if (dsp->sb_type < SB2) break;
384 sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen);
385 break;
386 case 0x99: /*High speed 8-bit single cycle DMA input*/
387 if (dsp->sb_type < SB2) break;
388 sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen);
389 break;
390 case 0xA0: /*Set input mode to mono*/
391 case 0xA8: /*Set input mode to stereo*/
392 break;
393 case 0xB0: case 0xB1: case 0xB2: case 0xB3:
394 case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/
395 if (dsp->sb_type < SB16) break;
396 sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
397 dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
398 break;
399 case 0xB8: case 0xB9: case 0xBA: case 0xBB:
400 case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/
401 if (dsp->sb_type < SB16) break;
402 sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
403 dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
404 break;
405 case 0xC0: case 0xC1: case 0xC2: case 0xC3:
406 case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/
407 if (dsp->sb_type < SB16) break;
408 sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
409 dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
410 break;
411 case 0xC8: case 0xC9: case 0xCA: case 0xCB:
412 case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/
413 if (dsp->sb_type < SB16) break;
414 sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8));
415 dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8);
416 break;
417 case 0xD0: /*Pause 8-bit DMA*/
418 dsp->sb_8_pause = 1;
419 break;
420 case 0xD1: /*Speaker on*/
421 dsp->sb_speaker = 1;
422 break;
423 case 0xD3: /*Speaker off*/
424 dsp->sb_speaker = 0;
425 break;
426 case 0xD4: /*Continue 8-bit DMA*/
427 dsp->sb_8_pause = 0;
428 break;
429 case 0xD5: /*Pause 16-bit DMA*/
430 if (dsp->sb_type < SB16) break;
431 dsp->sb_16_pause = 1;
432 break;
433 case 0xD6: /*Continue 16-bit DMA*/
434 if (dsp->sb_type < SB16) break;
435 dsp->sb_16_pause = 0;
436 break;
437 case 0xD8: /*Get speaker status*/
438 sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0);
439 break;
440 case 0xD9: /*Exit 16-bit auto-init mode*/
441 if (dsp->sb_type < SB16) break;
442 dsp->sb_16_autoinit = 0;
443 break;
444 case 0xDA: /*Exit 8-bit auto-init mode*/
445 dsp->sb_8_autoinit = 0;
446 break;
447 case 0xE0: /*DSP identification*/
448 sb_add_data(dsp, ~dsp->sb_data[0]);
449 break;
450 case 0xE1: /*Get DSP version*/
451 sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8);
452 sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff);
453 break;
454 case 0xE2: /*Stupid ID/protection*/
455 for (c = 0; c < 8; c++)
456 if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c];
457 dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8];
458 dsp->sbe2count++;
459 sb_8_write_dma(dsp, dsp->sbe2);
460 break;
461 case 0xE3: /*DSP copyright*/
462 if (dsp->sb_type < SB16) break;
463 c = 0;
464 while (sb16_copyright[c])
465 sb_add_data(dsp, sb16_copyright[c++]);
466 sb_add_data(dsp, 0);
467 break;
468 case 0xE4: /*Write test register*/
469 dsp->sb_test = dsp->sb_data[0];
470 break;
471 case 0xE8: /*Read test register*/
472 sb_add_data(dsp, dsp->sb_test);
473 break;
474 case 0xF2: /*Trigger 8-bit IRQ*/
475 // pclog("Trigger IRQ\n");
476 sb_irq(dsp, 1);
477 break;
478 case 0xE7: /*???*/
479 case 0xFA: /*???*/
480 break;
481 case 0x07: /*No, that's not how you program auto-init DMA*/
482 case 0xFF:
483 break;
484 case 0x08: /*ASP get version*/
485 if (dsp->sb_type < SB16) break;
486 sb_add_data(dsp, 0x18);
487 break;
488 case 0x0E: /*ASP set register*/
489 if (dsp->sb_type < SB16) break;
490 dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1];
491 // pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]);
492 break;
493 case 0x0F: /*ASP get register*/
494 if (dsp->sb_type < SB16) break;
495 // sb_add_data(0);
496 sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]);
497 // pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]);
498 break;
499 case 0xF9:
500 if (dsp->sb_type < SB16) break;
501 if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff);
502 else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07);
503 else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38);
504 else sb_add_data(dsp, 0x00);
505 case 0x04:
506 case 0x05:
507 break;
508 // default:
509 // fatal("Exec bad SB command %02X\n",sb_command);
510 }
511 }
513 void sb_write(uint16_t a, uint8_t v, void *priv)
514 {
515 sb_dsp_t *dsp = (sb_dsp_t *)priv;
516 // pclog("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command);
517 switch (a&0xF)
518 {
519 case 6: /*Reset*/
520 if (!(v & 1) && (dsp->sbreset & 1))
521 {
522 sb_dsp_reset(dsp);
523 sb_add_data(dsp, 0xAA);
524 }
525 dsp->sbreset = v;
526 return;
527 case 0xC: /*Command/data write*/
528 if (dsp->sb_data_stat == -1)
529 {
530 dsp->sb_command = v;
531 // if (sb_commands[v]==-1)
532 // fatal("Bad SB command %02X\n",v);
533 dsp->sb_data_stat++;
534 }
535 else
536 dsp->sb_data[dsp->sb_data_stat++] = v;
537 if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1)
538 {
539 sb_exec_command(dsp);
540 dsp->sb_data_stat = -1;
541 }
542 break;
543 }
544 }
546 uint8_t sb_read(uint16_t a, void *priv)
547 {
548 sb_dsp_t *dsp = (sb_dsp_t *)priv;
549 // if (a==0x224) output=1;
550 // pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc);
551 switch (a & 0xf)
552 {
553 case 0xA: /*Read data*/
554 dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp];
555 if (dsp->sb_read_rp != dsp->sb_read_wp)
556 {
557 dsp->sb_read_rp++;
558 dsp->sb_read_rp &= 0xFF;
559 }
560 // pclog("SB read %02X\n",sbreaddat);
561 return dsp->sbreaddat;
562 case 0xC: /*Write data ready*/
563 cycles -= 100;
564 dsp->writebusy++;
565 if (dsp->writebusy & 8) return 0xff;
566 return 0x7f;
567 case 0xE: /*Read data ready*/
568 picintc(1 << dsp->sb_irqnum);
569 dsp->sb_irq8 = dsp->sb_irq16 = 0;
570 return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff;
571 case 0xF: /*16-bit ack*/
572 dsp->sb_irq16 = 0;
573 if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum);
574 return 0xff;
575 }
576 return 0;
577 }
579 void sb_dsp_init(sb_dsp_t *dsp, int type)
580 {
581 dsp->sb_type = type;
583 dsp->sb_irqnum = 7;
584 dsp->sb_8_dmanum = 1;
586 sb_doreset(dsp);
588 timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp);
589 timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp);
590 }
592 void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr)
593 {
594 // pclog("sb_dsp_setaddr : %04X\n", addr);
595 io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
596 io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
597 dsp->sb_addr = addr;
598 if (dsp->sb_addr != 0)
599 {
600 io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
601 io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp);
602 }
603 }
605 void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo)
606 {
607 dsp->stereo = stereo;
608 }
610 void pollsb(void *p)
611 {
612 sb_dsp_t *dsp = (sb_dsp_t *)p;
613 int tempi,ref;
615 dsp->sbcount += dsp->sblatcho;
616 // pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output);
617 if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output)
618 {
619 int data[2];
620 // pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho);
621 switch (dsp->sb_8_format)
622 {
623 case 0x00: /*Mono unsigned*/
624 data[0] = sb_8_read_dma(dsp);
625 /*Needed to prevent clicking in Worms, which programs the DSP to
626 auto-init DMA but programs the DMA controller to single cycle*/
627 if (data[0] == DMA_NODATA)
628 break;
629 dsp->sbdat = (data[0] ^ 0x80) << 8;
630 if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
631 {
632 if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
633 else dsp->sbdatr = dsp->sbdat;
634 dsp->sbleftright = !dsp->sbleftright;
635 }
636 else
637 dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
638 dsp->sb_8_length--;
639 break;
640 case 0x10: /*Mono signed*/
641 data[0] = sb_8_read_dma(dsp);
642 if (data[0] == DMA_NODATA)
643 break;
644 dsp->sbdat = data[0] << 8;
645 if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
646 {
647 if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
648 else dsp->sbdatr = dsp->sbdat;
649 dsp->sbleftright = !dsp->sbleftright;
650 }
651 else
652 dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
653 dsp->sb_8_length--;
654 break;
655 case 0x20: /*Stereo unsigned*/
656 data[0] = sb_8_read_dma(dsp);
657 data[1] = sb_8_read_dma(dsp);
658 if (data[0] == DMA_NODATA || data[1] == DMA_NODATA)
659 break;
660 dsp->sbdatl = (data[0] ^ 0x80) << 8;
661 dsp->sbdatr = (data[1] ^ 0x80) << 8;
662 dsp->sb_8_length -= 2;
663 break;
664 case 0x30: /*Stereo signed*/
665 data[0] = sb_8_read_dma(dsp);
666 data[1] = sb_8_read_dma(dsp);
667 if (data[0] == DMA_NODATA || data[1] == DMA_NODATA)
668 break;
669 dsp->sbdatl = data[0] << 8;
670 dsp->sbdatr = data[1] << 8;
671 dsp->sb_8_length -= 2;
672 break;
674 case ADPCM_4:
675 if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep;
676 else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep;
677 if (tempi < 0) tempi = 0;
678 if (tempi > 63) tempi = 63;
680 ref = dsp->sbref + scaleMap4[tempi];
681 if (ref > 0xff) dsp->sbref = 0xff;
682 else if (ref < 0x00) dsp->sbref = 0x00;
683 else dsp->sbref = ref;
685 dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff;
687 dsp->sbdat = (dsp->sbref ^ 0x80) << 8;
689 dsp->sbdacpos++;
690 if (dsp->sbdacpos >= 2)
691 {
692 dsp->sbdacpos = 0;
693 dsp->sbdat2 = sb_8_read_dma(dsp);
694 dsp->sb_8_length--;
695 }
697 if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
698 {
699 if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
700 else dsp->sbdatr = dsp->sbdat;
701 dsp->sbleftright = !dsp->sbleftright;
702 }
703 else
704 dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
705 break;
707 case ADPCM_26:
708 if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep;
709 else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep;
710 else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep;
712 if (tempi < 0) tempi = 0;
713 if (tempi > 39) tempi = 39;
715 ref = dsp->sbref + scaleMap26[tempi];
716 if (ref > 0xff) dsp->sbref = 0xff;
717 else if (ref < 0x00) dsp->sbref = 0x00;
718 else dsp->sbref = ref;
719 dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff;
721 dsp->sbdat = (dsp->sbref ^ 0x80) << 8;
723 dsp->sbdacpos++;
724 if (dsp->sbdacpos>=3)
725 {
726 dsp->sbdacpos = 0;
727 dsp->sbdat2 = sb_8_read_dma(dsp);
728 dsp->sb_8_length--;
729 }
731 if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
732 {
733 if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
734 else dsp->sbdatr = dsp->sbdat;
735 dsp->sbleftright = !dsp->sbleftright;
736 }
737 else
738 dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
739 break;
741 case ADPCM_2:
742 tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep;
743 if (tempi < 0) tempi = 0;
744 if (tempi > 23) tempi = 23;
746 ref = dsp->sbref + scaleMap2[tempi];
747 if (ref > 0xff) dsp->sbref = 0xff;
748 else if (ref < 0x00) dsp->sbref = 0x00;
749 else dsp->sbref = ref;
750 dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff;
752 dsp->sbdat = (dsp->sbref ^ 0x80) << 8;
754 dsp->sbdacpos++;
755 if (dsp->sbdacpos >= 4)
756 {
757 dsp->sbdacpos = 0;
758 dsp->sbdat2 = sb_8_read_dma(dsp);
759 }
761 if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
762 {
763 if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat;
764 else dsp->sbdatr = dsp->sbdat;
765 dsp->sbleftright = !dsp->sbleftright;
766 }
767 else
768 dsp->sbdatl = dsp->sbdatr = dsp->sbdat;
769 break;
771 // default:
772 //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format);
773 }
775 if (dsp->sb_8_length < 0)
776 {
777 if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen;
778 else dsp->sb_8_enable = dsp->sbenable=0;
779 sb_irq(dsp, 1);
780 }
781 }
782 if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && dsp->sb_16_output)
783 {
784 switch (dsp->sb_16_format)
785 {
786 case 0x00: /*Mono unsigned*/
787 dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000;
788 dsp->sb_16_length--;
789 break;
790 case 0x10: /*Mono signed*/
791 dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp);
792 dsp->sb_16_length--;
793 break;
794 case 0x20: /*Stereo unsigned*/
795 dsp->sbdatl = sb_16_read_dma(dsp) ^ 0x8000;
796 dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000;
797 dsp->sb_16_length -= 2;
798 break;
799 case 0x30: /*Stereo signed*/
800 dsp->sbdatl = sb_16_read_dma(dsp);
801 dsp->sbdatr = sb_16_read_dma(dsp);
802 dsp->sb_16_length -= 2;
803 break;
805 // default:
806 // fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format);
807 }
809 if (dsp->sb_16_length < 0)
810 {
811 // pclog("16DMA over %i\n",dsp->sb_16_autoinit);
812 if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen;
813 else dsp->sb_16_enable = dsp->sbenable = 0;
814 sb_irq(dsp, 0);
815 }
816 }
817 if (dsp->sb_pausetime > -1)
818 {
819 dsp->sb_pausetime--;
820 if (dsp->sb_pausetime < 0)
821 {
822 sb_irq(dsp, 1);
823 dsp->sbenable = dsp->sb_8_enable;
824 // pclog("SB pause over\n");
825 }
826 }
827 }
829 void sb_poll_i(void *p)
830 {
831 sb_dsp_t *dsp = (sb_dsp_t *)p;
833 dsp->sb_count_i += dsp->sblatchi;
834 // pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output);
835 if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output)
836 {
837 switch (dsp->sb_8_format)
838 {
839 case 0x00: /*Mono unsigned*/
840 sb_8_write_dma(dsp, 0x80);
841 dsp->sb_8_length--;
842 break;
843 case 0x10: /*Mono signed*/
844 sb_8_write_dma(dsp, 0x00);
845 dsp->sb_8_length--;
846 break;
847 case 0x20: /*Stereo unsigned*/
848 sb_8_write_dma(dsp, 0x80);
849 sb_8_write_dma(dsp, 0x80);
850 dsp->sb_8_length -= 2;
851 break;
852 case 0x30: /*Stereo signed*/
853 sb_8_write_dma(dsp, 0x00);
854 sb_8_write_dma(dsp, 0x00);
855 dsp->sb_8_length -= 2;
856 break;
858 // default:
859 // fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format);
860 }
862 if (dsp->sb_8_length < 0)
863 {
864 // pclog("Input DMA over %i\n",sb_8_autoinit);
865 if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen;
866 else dsp->sb_8_enable = dsp->sbenable = 0;
867 sb_irq(dsp, 1);
868 }
869 }
870 if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && !dsp->sb_16_output)
871 {
872 switch (dsp->sb_16_format)
873 {
874 case 0x00: /*Unsigned mono*/
875 sb_16_write_dma(dsp, 0x8000);
876 dsp->sb_16_length--;
877 break;
878 case 0x10: /*Signed mono*/
879 sb_16_write_dma(dsp, 0);
880 dsp->sb_16_length--;
881 break;
882 case 0x20: /*Unsigned stereo*/
883 sb_16_write_dma(dsp, 0x8000);
884 sb_16_write_dma(dsp, 0x8000);
885 dsp->sb_16_length -= 2;
886 break;
887 case 0x30: /*Signed stereo*/
888 sb_16_write_dma(dsp, 0);
889 sb_16_write_dma(dsp, 0);
890 dsp->sb_16_length -= 2;
891 break;
893 // default:
894 // fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format);
895 }
897 if (dsp->sb_16_length < 0)
898 {
899 // pclog("16iDMA over %i\n",sb_16_autoinit);
900 if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen;
901 else dsp->sb_16_enable = dsp->sbenable = 0;
902 sb_irq(dsp, 0);
903 }
904 }
905 }
907 void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r)
908 {
909 *l = dsp->sbdatl;
910 *r = dsp->sbdatr;
911 }
913 void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp)
914 {
915 char temps[128];
916 int len;
917 int freq;
919 if (dsp->sb_timeo < 256)
920 freq = 1000000 / (256 - dsp->sb_timeo);
921 else
922 freq = dsp->sb_timeo - 256;
924 if (dsp->sb_8_enable && dsp->sb_8_output)
925 {
926 switch (dsp->sb_8_format)
927 {
928 case 0x00: /*Mono unsigned*/
929 case 0x10: /*Mono signed*/
930 if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo)
931 {
932 strcpy(temps, "SB playback format : 8-bit stereo\n");
933 freq /= 2;
934 }
935 else
936 strcpy(temps, "SB playback format : 8-bit mono\n");
937 break;
938 case 0x20: /*Stereo unsigned*/
939 case 0x30: /*Stereo signed*/
940 strcpy(temps, "SB playback format : 8-bit stereo\n");
941 break;
942 case ADPCM_4:
943 strcpy(temps, "SB playback format : 4-bit ADPCM\n");
944 break;
945 case ADPCM_26:
946 strcpy(temps, "SB playback format : 2.6-bit ADPCM\n");
947 break;
948 case ADPCM_2:
949 strcpy(temps, "SB playback format : 2-bit ADPCM\n");
950 break;
951 }
952 }
953 else if (dsp->sb_16_enable && dsp->sb_16_output)
954 {
955 switch (dsp->sb_16_format)
956 {
957 case 0x00: /*Mono unsigned*/
958 case 0x10: /*Mono signed*/
959 strcpy(temps, "SB playback format : 16-bit mono\n");
960 break;
961 case 0x20: /*Stereo unsigned*/
962 case 0x30: /*Stereo signed*/
963 strcpy(temps, "SB playback format : 16-bit stereo\n");
964 break;
965 }
966 }
967 else
968 strcpy(temps, "SB playback stopped\n");
969 strncat(s, temps, max_len);
971 if ((dsp->sb_8_enable && dsp->sb_8_output) || (dsp->sb_16_enable && dsp->sb_16_output))
972 {
973 sprintf(temps, "SB playback frequency : %iHz\n", freq);
974 strncat(s, temps, max_len);
975 }
976 }
