sb16.c 31.7 KB
Newer Older
B
bellard 已提交
1 2 3
/*
 * QEMU Soundblaster 16 emulation
 * 
B
bellard 已提交
4
 * Copyright (c) 2003-2004 Vassili Karpov (malc)
B
bellard 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "vl.h"

B
bellard 已提交
26
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
B
bellard 已提交
27

B
bellard 已提交
28
#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
B
bellard 已提交
29 30 31 32

/* #define DEBUG */
/* #define DEBUG_SB16_MOST */

B
bellard 已提交
33 34 35 36 37 38
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif

B
bellard 已提交
39
#define IO_READ_PROTO(name)                             \
B
bellard 已提交
40
    uint32_t name (void *opaque, uint32_t nport)
B
bellard 已提交
41
#define IO_WRITE_PROTO(name)                                    \
B
bellard 已提交
42
    void name (void *opaque, uint32_t nport, uint32_t val)
B
bellard 已提交
43

B
bellard 已提交
44
static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
B
bellard 已提交
45

B
bellard 已提交
46 47 48 49 50 51 52
static struct {
    int ver_lo;
    int ver_hi;
    int irq;
    int dma;
    int hdma;
    int port;
B
bellard 已提交
53
} conf = {5, 4, 5, 1, 5, 0x220};
B
bellard 已提交
54

55
typedef struct SB16State {
B
bellard 已提交
56 57 58 59 60 61
    int irq;
    int dma;
    int hdma;
    int port;
    int ver;

B
bellard 已提交
62 63 64 65 66
    int in_index;
    int out_data_len;
    int fmt_stereo;
    int fmt_signed;
    int fmt_bits;
B
bellard 已提交
67
    audfmt_e fmt;
B
bellard 已提交
68
    int dma_auto;
B
bellard 已提交
69
    int block_size;
B
bellard 已提交
70 71 72 73 74 75 76
    int fifo;
    int freq;
    int time_const;
    int speaker;
    int needed_bytes;
    int cmd;
    int use_hdma;
B
bellard 已提交
77 78
    int highspeed;
    int can_write;
B
bellard 已提交
79 80 81

    int v2x6;

B
bellard 已提交
82 83 84 85 86 87 88 89 90
    uint8_t csp_param;
    uint8_t csp_value;
    uint8_t csp_mode;
    uint8_t csp_regs[256];
    uint8_t csp_index;
    uint8_t csp_reg83[4];
    int csp_reg83r;
    int csp_reg83w;

B
bellard 已提交
91
    uint8_t in2_data[10];
B
bellard 已提交
92 93 94 95
    uint8_t out_data[50];
    uint8_t test_reg;
    uint8_t last_read_byte;
    int nzero;
B
bellard 已提交
96 97 98

    int left_till_irq;

B
bellard 已提交
99 100 101 102 103 104
    int dma_running;
    int bytes_per_second;
    int align;
    SWVoice *voice;

    QEMUTimer *ts, *aux_ts;
105 106
    /* mixer state */
    int mixer_nreg;
B
bellard 已提交
107
    uint8_t mixer_regs[256];
108
} SB16State;
B
bellard 已提交
109

110 111
/* XXX: suppress that and use a context */
static struct SB16State dsp;
B
bellard 已提交
112

B
bellard 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
static int magic_of_irq (int irq)
{
    switch (irq) {
    case 5:
        return 2;
    case 7:
        return 4;
    case 9:
        return 1;
    case 10:
        return 8;
    default:
        dolog ("bad irq %d\n", irq);
        return 2;
    }
}

static int irq_of_magic (int magic)
{
    switch (magic) {
    case 1:
        return 9;
    case 2:
        return 5;
    case 4:
        return 7;
    case 8:
        return 10;
    default:
        dolog ("bad irq magic %d\n", magic);
        return -1;
    }
}

#if 0
148 149
static void log_dsp (SB16State *dsp)
{
B
bellard 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
    ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
            dsp->fmt_stereo ? "Stereo" : "Mono",
            dsp->fmt_signed ? "Signed" : "Unsigned",
            dsp->fmt_bits,
            dsp->dma_auto ? "Auto" : "Single",
            dsp->block_size,
            dsp->freq,
            dsp->time_const,
            dsp->speaker);
}
#endif

static void speaker (SB16State *s, int on)
{
    s->speaker = on;
    /* AUD_enable (s->voice, on); */
B
bellard 已提交
166 167
}

B
bellard 已提交
168
static void control (SB16State *s, int hold)
B
bellard 已提交
169
{
B
bellard 已提交
170 171 172 173 174
    int dma = s->use_hdma ? s->hdma : s->dma;
    s->dma_running = hold;

    ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);

B
bellard 已提交
175
    if (hold) {
B
bellard 已提交
176 177
        DMA_hold_DREQ (dma);
        AUD_enable (s->voice, 1);
B
bellard 已提交
178 179
    }
    else {
B
bellard 已提交
180 181
        DMA_release_DREQ (dma);
        AUD_enable (s->voice, 0);
B
bellard 已提交
182 183 184
    }
}

B
bellard 已提交
185
static void aux_timer (void *opaque)
B
bellard 已提交
186
{
B
bellard 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    SB16State *s = opaque;
    s->can_write = 1;
    pic_set_irq (s->irq, 1);
}

#define DMA8_AUTO 1
#define DMA8_HIGH 2

static void dma_cmd8 (SB16State *s, int mask, int dma_len)
{
    s->fmt = AUD_FMT_U8;
    s->use_hdma = 0;
    s->fmt_bits = 8;
    s->fmt_signed = 0;
    s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
    if (-1 == s->time_const) {
        s->freq = 11025;
    }
    else {
        int tmp = (256 - s->time_const);
        s->freq = (1000000 + (tmp / 2)) / tmp;
    }

B
bellard 已提交
210 211 212 213 214 215 216 217 218 219 220 221
    if (dma_len != -1)
        s->block_size = dma_len << s->fmt_stereo;
    else {
        /* This is apparently the only way to make both Act1/PL
           and SecondReality/FC work

           Act1 sets block size via command 0x48 and it's an odd number
           SR does the same with even number
           Both use stereo, and Creatives own documentation states that
           0x48 sets block size in bytes less one.. go figure */
        s->block_size &= ~s->fmt_stereo;
    }
B
bellard 已提交
222 223 224 225 226 227 228 229

    s->freq >>= s->fmt_stereo;
    s->left_till_irq = s->block_size;
    s->bytes_per_second = (s->freq << s->fmt_stereo);
    /* s->highspeed = (mask & DMA8_HIGH) != 0; */
    s->dma_auto = (mask & DMA8_AUTO) != 0;
    s->align = (1 << s->fmt_stereo) - 1;

B
bellard 已提交
230 231 232
    if (s->block_size & s->align)
        dolog ("warning: unaligned buffer\n");

B
bellard 已提交
233 234 235 236 237 238 239 240 241 242 243 244
    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
            "dma %d, auto %d, fifo %d, high %d\n",
            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
            s->block_size, s->dma_auto, s->fifo, s->highspeed);

    if (s->freq)
        s->voice = AUD_open (s->voice, "sb16", s->freq,
                             1 << s->fmt_stereo, s->fmt);

    control (s, 1);
    speaker (s, 1);
}
B
bellard 已提交
245

B
bellard 已提交
246 247 248 249 250 251 252
static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
{
    s->use_hdma = cmd < 0xc0;
    s->fifo = (cmd >> 1) & 1;
    s->dma_auto = (cmd >> 2) & 1;
    s->fmt_signed = (d0 >> 4) & 1;
    s->fmt_stereo = (d0 >> 5) & 1;
B
bellard 已提交
253 254 255

    switch (cmd >> 4) {
    case 11:
B
bellard 已提交
256
        s->fmt_bits = 16;
B
bellard 已提交
257 258 259
        break;

    case 12:
B
bellard 已提交
260
        s->fmt_bits = 8;
B
bellard 已提交
261 262 263
        break;
    }

B
bellard 已提交
264 265 266 267 268 269 270 271 272
    if (-1 != s->time_const) {
#if 1
        int tmp = 256 - s->time_const;
        s->freq = (1000000 + (tmp / 2)) / tmp;
#else
        /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
        s->freq = 1000000 / ((255 - s->time_const));
#endif
        s->time_const = -1;
B
bellard 已提交
273 274
    }

B
bellard 已提交
275 276
    s->block_size = dma_len + 1;
    s->block_size <<= (s->fmt_bits == 16);
B
bellard 已提交
277 278 279 280 281
    if (!s->dma_auto) {
        /* It is clear that for DOOM and auto-init this value
           shouldn't take stereo into account, while Miles Sound Systems
           setsound.exe with single transfer mode wouldn't work without it
           wonders of SB16 yet again */
B
bellard 已提交
282
        s->block_size <<= s->fmt_stereo;
B
bellard 已提交
283
    }
B
bellard 已提交
284

B
bellard 已提交
285 286 287 288
    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
            "dma %d, auto %d, fifo %d, high %d\n",
            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
            s->block_size, s->dma_auto, s->fifo, s->highspeed);
B
bellard 已提交
289

B
bellard 已提交
290 291 292
    if (16 == s->fmt_bits) {
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S16;
B
bellard 已提交
293 294
        }
        else {
B
bellard 已提交
295
            s->fmt = AUD_FMT_U16;
B
bellard 已提交
296 297 298
        }
    }
    else {
B
bellard 已提交
299 300
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S8;
B
bellard 已提交
301 302
        }
        else {
B
bellard 已提交
303
            s->fmt = AUD_FMT_U8;
B
bellard 已提交
304 305 306
        }
    }

B
bellard 已提交
307
    s->left_till_irq = s->block_size;
B
bellard 已提交
308

B
bellard 已提交
309 310 311
    s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
    s->highspeed = 0;
    s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
B
bellard 已提交
312 313
    if (s->block_size & s->align)
        dolog ("warning: unaligned buffer\n");
B
bellard 已提交
314

B
bellard 已提交
315 316 317
    if (s->freq)
        s->voice = AUD_open (s->voice, "sb16", s->freq,
                             1 << s->fmt_stereo, s->fmt);
B
bellard 已提交
318

B
bellard 已提交
319 320
    control (s, 1);
    speaker (s, 1);
B
bellard 已提交
321 322
}

B
bellard 已提交
323
static inline void dsp_out_data (SB16State *s, uint8_t val)
B
bellard 已提交
324
{
B
bellard 已提交
325 326 327
    ldebug ("outdata %#x\n", val);
    if (s->out_data_len < sizeof (s->out_data))
        s->out_data[s->out_data_len++] = val;
B
bellard 已提交
328 329
}

B
bellard 已提交
330
static inline uint8_t dsp_get_data (SB16State *s)
B
bellard 已提交
331
{
B
bellard 已提交
332 333 334 335
    if (s->in_index)
        return s->in2_data[--s->in_index];
    else {
        dolog ("buffer underflow\n");
B
bellard 已提交
336
        return 0;
B
bellard 已提交
337
    }
B
bellard 已提交
338 339
}

B
bellard 已提交
340
static void command (SB16State *s, uint8_t cmd)
B
bellard 已提交
341
{
B
bellard 已提交
342
    ldebug ("command %#x\n", cmd);
B
bellard 已提交
343 344

    if (cmd > 0xaf && cmd < 0xd0) {
B
bellard 已提交
345 346 347
        if (cmd & 8) {
            dolog ("ADC not yet supported (command %#x)\n", cmd);
        }
B
bellard 已提交
348 349 350 351 352 353

        switch (cmd >> 4) {
        case 11:
        case 12:
            break;
        default:
B
bellard 已提交
354
            dolog ("%#x wrong bits\n", cmd);
B
bellard 已提交
355
        }
B
bellard 已提交
356
        s->needed_bytes = 3;
B
bellard 已提交
357 358 359
    }
    else {
        switch (cmd) {
B
bellard 已提交
360
        case 0x03:
B
bellard 已提交
361 362 363
            dsp_out_data (s, 0x10); /* s->csp_param); */
            goto warn;

B
bellard 已提交
364
        case 0x04:
B
bellard 已提交
365 366
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
367 368

        case 0x05:
B
bellard 已提交
369 370 371 372 373 374
            s->needed_bytes = 2;
            goto warn;

        case 0x08:
            /* __asm__ ("int3"); */
            goto warn;
B
bellard 已提交
375

B
bellard 已提交
376
        case 0x0e:
B
bellard 已提交
377 378 379 380 381 382
            s->needed_bytes = 2;
            goto warn;

        case 0x09:
            dsp_out_data (s, 0xf8);
            goto warn;
B
bellard 已提交
383 384

        case 0x0f:
B
bellard 已提交
385 386
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
387

B
bellard 已提交
388
        case 0x10:
B
bellard 已提交
389 390
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
391 392

        case 0x14:
B
bellard 已提交
393 394
            s->needed_bytes = 2;
            s->block_size = 0;
B
bellard 已提交
395 396
            break;

B
bellard 已提交
397 398 399 400
        case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
            control (s, 1);
            break;

B
bellard 已提交
401 402 403
        case 0x20:              /* Direct ADC, Juice/PL */
            dsp_out_data (s, 0xff);
            goto warn;
B
bellard 已提交
404 405

        case 0x35:
B
bellard 已提交
406
            dolog ("MIDI command(0x35) not implemented\n");
B
bellard 已提交
407 408 409
            break;

        case 0x40:
B
bellard 已提交
410 411 412
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 1;
B
bellard 已提交
413 414 415
            break;

        case 0x41:
B
bellard 已提交
416 417 418
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 2;
B
bellard 已提交
419 420
            break;

B
bellard 已提交
421 422 423 424 425 426
        case 0x42:
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 2;
            goto warn;

B
bellard 已提交
427
        case 0x45:
B
bellard 已提交
428 429 430
            dsp_out_data (s, 0xaa);
            goto warn;

B
bellard 已提交
431 432 433 434
        case 0x47:                /* Continue Auto-Initialize DMA 16bit */
            break;

        case 0x48:
B
bellard 已提交
435
            s->needed_bytes = 2;
B
bellard 已提交
436 437 438
            break;

        case 0x80:
B
bellard 已提交
439
            s->needed_bytes = 2;
B
bellard 已提交
440 441 442 443
            break;

        case 0x90:
        case 0x91:
B
bellard 已提交
444 445
            dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
            break;
B
bellard 已提交
446

B
bellard 已提交
447 448 449
        case 0xd0:              /* halt DMA operation. 8bit */
            control (s, 0);
            break;
B
bellard 已提交
450

B
bellard 已提交
451 452
        case 0xd1:              /* speaker on */
            speaker (s, 1);
B
bellard 已提交
453 454
            break;

B
bellard 已提交
455 456 457
        case 0xd3:              /* speaker off */
            speaker (s, 0);
            break;
B
bellard 已提交
458

B
bellard 已提交
459 460
        case 0xd4:              /* continue DMA operation. 8bit */
            control (s, 1);
B
bellard 已提交
461 462
            break;

B
bellard 已提交
463 464
        case 0xd5:              /* halt DMA operation. 16bit */
            control (s, 0);
B
bellard 已提交
465 466
            break;

B
bellard 已提交
467 468
        case 0xd6:              /* continue DMA operation. 16bit */
            control (s, 1);
B
bellard 已提交
469 470
            break;

B
bellard 已提交
471 472 473
        case 0xd9:              /* exit auto-init DMA after this block. 16bit */
            s->dma_auto = 0;
            break;
B
bellard 已提交
474

B
bellard 已提交
475 476
        case 0xda:              /* exit auto-init DMA after this block. 8bit */
            s->dma_auto = 0;
B
bellard 已提交
477 478 479
            break;

        case 0xe0:
B
bellard 已提交
480 481
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
482 483

        case 0xe1:
B
bellard 已提交
484 485 486 487 488 489 490
            dsp_out_data (s, s->ver & 0xff);
            dsp_out_data (s, s->ver >> 8);
            break;

        case 0xe2:
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
491

B
bellard 已提交
492 493 494
        case 0xe3:
            {
                int i;
B
bellard 已提交
495 496
                for (i = sizeof (e3) - 1; i >= 0; --i)
                    dsp_out_data (s, e3[i]);
B
bellard 已提交
497
            }
B
bellard 已提交
498
            break;
B
bellard 已提交
499

B
bellard 已提交
500
        case 0xe4:              /* write test reg */
B
bellard 已提交
501
            s->needed_bytes = 1;
B
bellard 已提交
502 503
            break;

B
bellard 已提交
504 505 506 507
        case 0xe7:
            dolog ("Attempt to probe for ESS (0xe7)?\n");
            return;

B
bellard 已提交
508
        case 0xe8:              /* read test reg */
B
bellard 已提交
509
            dsp_out_data (s, s->test_reg);
B
bellard 已提交
510 511
            break;

B
bellard 已提交
512
        case 0xf2:
B
bellard 已提交
513 514 515 516 517
        case 0xf3:
            dsp_out_data (s, 0xaa);
            s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
            pic_set_irq (s->irq, 1);
            break;
B
bellard 已提交
518

B
bellard 已提交
519
        case 0xf9:
B
bellard 已提交
520 521
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
522 523

        case 0xfa:
B
bellard 已提交
524 525
            dsp_out_data (s, 0);
            goto warn;
B
bellard 已提交
526 527

        case 0xfc:              /* FIXME */
B
bellard 已提交
528 529
            dsp_out_data (s, 0);
            goto warn;
B
bellard 已提交
530

B
bellard 已提交
531
        default:
B
bellard 已提交
532
            dolog ("unrecognized command %#x\n", cmd);
B
bellard 已提交
533
            return;
B
bellard 已提交
534 535
        }
    }
B
bellard 已提交
536 537 538 539

    s->cmd = cmd;
    if (!s->needed_bytes)
        ldebug ("\n");
B
bellard 已提交
540 541
    return;

B
bellard 已提交
542
 warn:
B
bellard 已提交
543
    dolog ("warning: command %#x,%d is not trully understood yet\n",
B
bellard 已提交
544 545
           cmd, s->needed_bytes);
    s->cmd = cmd;
B
bellard 已提交
546 547 548
    return;
}

B
bellard 已提交
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
static uint16_t dsp_get_lohi (SB16State *s)
{
    uint8_t hi = dsp_get_data (s);
    uint8_t lo = dsp_get_data (s);
    return (hi << 8) | lo;
}

static uint16_t dsp_get_hilo (SB16State *s)
{
    uint8_t lo = dsp_get_data (s);
    uint8_t hi = dsp_get_data (s);
    return (hi << 8) | lo;
}

static void complete (SB16State *s)
B
bellard 已提交
564
{
B
bellard 已提交
565
    int d0, d1, d2;
B
bellard 已提交
566 567
    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
            s->cmd, s->in_index, s->needed_bytes);
B
bellard 已提交
568

B
bellard 已提交
569 570 571 572
    if (s->cmd > 0xaf && s->cmd < 0xd0) {
        d2 = dsp_get_data (s);
        d1 = dsp_get_data (s);
        d0 = dsp_get_data (s);
B
bellard 已提交
573

B
bellard 已提交
574 575 576 577 578 579 580 581 582
        if (s->cmd & 8) {
            dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
                   s->cmd, d0, d1, d2);
        }
        else {
            ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
                    s->cmd, d0, d1, d2);
            dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
        }
B
bellard 已提交
583 584
    }
    else {
B
bellard 已提交
585
        switch (s->cmd) {
B
bellard 已提交
586
        case 0x04:
B
bellard 已提交
587 588 589 590
            s->csp_mode = dsp_get_data (s);
            s->csp_reg83r = 0;
            s->csp_reg83w = 0;
            ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
B
bellard 已提交
591 592
            break;

B
bellard 已提交
593 594 595 596 597 598
        case 0x05:
            s->csp_param = dsp_get_data (s);
            s->csp_value = dsp_get_data (s);
            ldebug ("CSP command 0x05: param=%#x value=%#x\n",
                    s->csp_param,
                    s->csp_value);
B
bellard 已提交
599
            break;
B
bellard 已提交
600

B
bellard 已提交
601
        case 0x0e:
B
bellard 已提交
602 603 604 605 606 607 608 609 610 611
            d0 = dsp_get_data (s);
            d1 = dsp_get_data (s);
            ldebug ("write CSP register %d <- %#x\n", d1, d0);
            if (d1 == 0x83) {
                ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
                s->csp_reg83[s->csp_reg83r % 4] = d0;
                s->csp_reg83r += 1;
            }
            else
                s->csp_regs[d1] = d0;
B
bellard 已提交
612 613
            break;

B
bellard 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627
        case 0x0f:
            d0 = dsp_get_data (s);
            ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
                    d0, s->csp_regs[d0], s->csp_mode);
            if (d0 == 0x83) {
                ldebug ("0x83[%d] -> %#x\n",
                        s->csp_reg83w,
                        s->csp_reg83[s->csp_reg83w % 4]);
                dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
                s->csp_reg83w += 1;
            }
            else
                dsp_out_data (s, s->csp_regs[d0]);
            break;
B
bellard 已提交
628

B
bellard 已提交
629 630 631 632
        case 0x10:
            d0 = dsp_get_data (s);
            dolog ("cmd 0x10 d0=%#x\n", d0);
            break;
B
bellard 已提交
633

B
bellard 已提交
634
        case 0x14:
B
bellard 已提交
635
            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
B
bellard 已提交
636
            break;
B
bellard 已提交
637 638

        case 0x40:
B
bellard 已提交
639 640
            s->time_const = dsp_get_data (s);
            ldebug ("set time const %d\n", s->time_const);
B
bellard 已提交
641 642
            break;

B
bellard 已提交
643 644
        case 0x42:              /* FT2 sets output freq with this, go figure */
            dolog ("cmd 0x42 might not do what it think it should\n");
B
bellard 已提交
645

B
bellard 已提交
646 647 648
        case 0x41:
            s->freq = dsp_get_hilo (s);
            ldebug ("set freq %d\n", s->freq);
B
bellard 已提交
649 650 651
            break;

        case 0x48:
B
bellard 已提交
652
            s->block_size = dsp_get_lohi (s) + 1;
B
bellard 已提交
653 654 655 656 657
            ldebug ("set dma block len %d\n", s->block_size);
            break;

        case 0x80:
            {
B
bellard 已提交
658
                int freq, samples, bytes;
B
bellard 已提交
659 660
                int64_t ticks;

B
bellard 已提交
661 662
                freq = s->freq > 0 ? s->freq : 11025;
                samples = dsp_get_lohi (s) + 1;
B
bellard 已提交
663
                bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
B
bellard 已提交
664 665
                ticks = (bytes * ticks_per_sec) / freq;
                if (ticks < ticks_per_sec / 1024)
B
bellard 已提交
666 667 668 669 670
                    pic_set_irq (s->irq, 1);
                else
                    qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + ticks);
                ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks);
            }
B
bellard 已提交
671 672 673
            break;

        case 0xe0:
B
bellard 已提交
674 675 676 677
            d0 = dsp_get_data (s);
            s->out_data_len = 0;
            ldebug ("E0 data = %#x\n", d0);
            dsp_out_data(s, ~d0);
B
bellard 已提交
678 679
            break;

B
bellard 已提交
680 681
        case 0xe2:
            d0 = dsp_get_data (s);
B
bellard 已提交
682
            ldebug ("E2 = %#x\n", d0);
B
bellard 已提交
683 684
            break;

B
bellard 已提交
685 686 687
        case 0xe4:
            s->test_reg = dsp_get_data (s);
            break;
B
bellard 已提交
688 689

        case 0xf9:
B
bellard 已提交
690 691
            d0 = dsp_get_data (s);
            ldebug ("command 0xf9 with %#x\n", d0);
B
bellard 已提交
692
            switch (d0) {
B
bellard 已提交
693 694 695 696 697 698 699 700
            case 0x0e:
                dsp_out_data (s, 0xff);
                break;

            case 0x0f:
                dsp_out_data (s, 0x07);
                break;

B
bellard 已提交
701
            case 0x37:
B
bellard 已提交
702 703 704
                dsp_out_data (s, 0x38);
                break;

B
bellard 已提交
705
            default:
B
bellard 已提交
706 707
                dsp_out_data (s, 0x00);
                break;
B
bellard 已提交
708
            }
B
bellard 已提交
709 710 711
            break;

        default:
B
bellard 已提交
712
            dolog ("complete: unrecognized command %#x\n", s->cmd);
713
            return;
B
bellard 已提交
714 715 716
        }
    }

B
bellard 已提交
717 718
    ldebug ("\n");
    s->cmd = -1;
B
bellard 已提交
719 720 721
    return;
}

B
bellard 已提交
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
static void reset (SB16State *s)
{
    pic_set_irq (s->irq, 0);
    if (s->dma_auto) {
        pic_set_irq (s->irq, 1);
        pic_set_irq (s->irq, 0);
    }

    s->mixer_regs[0x82] = 0;
    s->dma_auto = 0;
    s->in_index = 0;
    s->out_data_len = 0;
    s->left_till_irq = 0;
    s->needed_bytes = 0;
    s->block_size = -1;
    s->nzero = 0;
    s->highspeed = 0;
    s->v2x6 = 0;

    dsp_out_data(s, 0xaa);
    speaker (s, 0);
    control (s, 0);
}

B
bellard 已提交
746 747
static IO_WRITE_PROTO (dsp_write)
{
B
bellard 已提交
748
    SB16State *s = opaque;
B
bellard 已提交
749 750
    int iport;

B
bellard 已提交
751
    iport = nport - s->port;
B
bellard 已提交
752

B
bellard 已提交
753
    ldebug ("write %#x <- %#x\n", nport, val);
B
bellard 已提交
754
    switch (iport) {
B
bellard 已提交
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
    case 0x06:
        switch (val) {
        case 0x00:
            if (s->v2x6 == 1) {
                if (0 && s->highspeed) {
                    s->highspeed = 0;
                    pic_set_irq (s->irq, 0);
                    control (s, 0);
                }
                else
                    reset (s);
            }
            s->v2x6 = 0;
            break;

        case 0x01:
        case 0x03:              /* FreeBSD kludge */
            s->v2x6 = 1;
            break;

        case 0xc6:
            s->v2x6 = 0;        /* Prince of Persia, csp.sys, diagnose.exe */
            break;

        case 0xb8:              /* Panic */
            reset (s);
            break;

        case 0x39:
            dsp_out_data (s, 0x38);
            reset (s);
            s->v2x6 = 0x39;
            break;

        default:
            s->v2x6 = val;
            break;
B
bellard 已提交
792 793 794
        }
        break;

B
bellard 已提交
795 796 797 798 799 800 801 802 803
    case 0x0c:                  /* write data or command | write status */
/*         if (s->highspeed) */
/*             break; */

        if (0 == s->needed_bytes) {
            command (s, val);
#if 0
            if (0 == s->needed_bytes) {
                log_dsp (s);
B
bellard 已提交
804
            }
B
bellard 已提交
805
#endif
B
bellard 已提交
806 807
        }
        else {
B
bellard 已提交
808
            if (s->in_index == sizeof (s->in2_data)) {
B
bellard 已提交
809 810 811
                dolog ("in data overrun\n");
            }
            else {
B
bellard 已提交
812 813 814 815 816 817 818 819
                s->in2_data[s->in_index++] = val;
                if (s->in_index == s->needed_bytes) {
                    s->needed_bytes = 0;
                    complete (s);
#if 0
                    log_dsp (s);
#endif
                }
B
bellard 已提交
820 821 822 823 824
            }
        }
        break;

    default:
B
bellard 已提交
825
        ldebug ("(nport=%#x, val=%#x)\n", nport, val);
826
        break;
B
bellard 已提交
827 828 829 830 831
    }
}

static IO_READ_PROTO (dsp_read)
{
B
bellard 已提交
832 833
    SB16State *s = opaque;
    int iport, retval, ack = 0;
B
bellard 已提交
834

B
bellard 已提交
835
    iport = nport - s->port;
B
bellard 已提交
836 837

    switch (iport) {
B
bellard 已提交
838 839
    case 0x06:                  /* reset */
        retval = 0xff;
B
bellard 已提交
840
        break;
B
bellard 已提交
841

B
bellard 已提交
842 843 844 845 846 847
    case 0x0a:                  /* read data */
        if (s->out_data_len) {
            retval = s->out_data[--s->out_data_len];
            s->last_read_byte = retval;
        }
        else {
B
bellard 已提交
848
            dolog ("empty output buffer\n");
B
bellard 已提交
849
            retval = s->last_read_byte;
B
bellard 已提交
850
            /* goto error; */
B
bellard 已提交
851 852 853
        }
        break;

B
bellard 已提交
854 855
    case 0x0c:                  /* 0 can write */
        retval = s->can_write ? 0 : 0x80;
B
bellard 已提交
856 857
        break;

B
bellard 已提交
858 859 860 861
    case 0x0d:                  /* timer interrupt clear */
        /* dolog ("timer interrupt clear\n"); */
        retval = 0;
        break;
B
bellard 已提交
862

B
bellard 已提交
863 864 865 866 867 868 869
    case 0x0e:                  /* data available status | irq 8 ack */
        retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
        if (s->mixer_regs[0x82] & 1) {
            ack = 1;
            s->mixer_regs[0x82] &= 1;
            pic_set_irq (s->irq, 0);
        }
B
bellard 已提交
870 871
        break;

B
bellard 已提交
872
    case 0x0f:                  /* irq 16 ack */
B
bellard 已提交
873
        retval = 0xff;
B
bellard 已提交
874 875 876 877 878
        if (s->mixer_regs[0x82] & 2) {
            ack = 1;
            s->mixer_regs[0x82] &= 2;
            pic_set_irq (s->irq, 0);
        }
B
bellard 已提交
879 880 881 882 883 884
        break;

    default:
        goto error;
    }

B
bellard 已提交
885 886
    if (!ack)
        ldebug ("read %#x -> %#x\n", nport, retval);
B
bellard 已提交
887 888 889 890

    return retval;

 error:
B
bellard 已提交
891
    dolog ("WARNING dsp_read %#x error\n", nport);
B
bellard 已提交
892
    return 0xff;
B
bellard 已提交
893 894
}

B
bellard 已提交
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
static void reset_mixer (SB16State *s)
{
    int i;

    memset (s->mixer_regs, 0xff, 0x7f);
    memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);

    s->mixer_regs[0x02] = 4;    /* master volume 3bits */
    s->mixer_regs[0x06] = 4;    /* MIDI volume 3bits */
    s->mixer_regs[0x08] = 0;    /* CD volume 3bits */
    s->mixer_regs[0x0a] = 0;    /* voice volume 2bits */

    /* d5=input filt, d3=lowpass filt, d1,d2=input source */
    s->mixer_regs[0x0c] = 0;

    /* d5=output filt, d1=stereo switch */
    s->mixer_regs[0x0e] = 0;

    /* voice volume L d5,d7, R d1,d3 */
    s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
    /* master ... */
    s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
    /* MIDI ... */
    s->mixer_regs[0x26] = (4 << 5) | (4 << 1);

    for (i = 0x30; i < 0x48; i++) {
        s->mixer_regs[i] = 0x20;
    }
}

B
bellard 已提交
925 926
static IO_WRITE_PROTO(mixer_write_indexb)
{
B
bellard 已提交
927 928
    SB16State *s = opaque;
    s->mixer_nreg = val;
B
bellard 已提交
929 930 931 932
}

static IO_WRITE_PROTO(mixer_write_datab)
{
B
bellard 已提交
933 934 935 936 937
    SB16State *s = opaque;

    ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
    if (s->mixer_nreg > sizeof (s->mixer_regs))
        return;
B
bellard 已提交
938

B
bellard 已提交
939
    switch (s->mixer_nreg) {
B
bellard 已提交
940
    case 0x00:
B
bellard 已提交
941
        reset_mixer (s);
B
bellard 已提交
942 943 944
        break;

    case 0x80:
B
bellard 已提交
945 946 947 948 949 950
        {
            int irq = irq_of_magic (val);
            ldebug ("setting irq to %d (val=%#x)\n", irq, val);
            if (irq > 0)
                s->irq = irq;
        }
B
bellard 已提交
951
        break;
B
bellard 已提交
952

B
bellard 已提交
953 954 955
    case 0x81:
        {
            int dma, hdma;
B
bellard 已提交
956

B
bellard 已提交
957 958 959 960 961 962 963 964 965 966
            dma = lsbindex (val & 0xf);
            hdma = lsbindex (val & 0xf0);
            dolog ("attempt to set DMA register 8bit %d, 16bit %d (val=%#x)\n",
                   dma, hdma, val);
#if 0
            s->dma = dma;
            s->hdma = hdma;
#endif
        }
        break;
B
bellard 已提交
967

B
bellard 已提交
968 969 970 971
    case 0x82:
        dolog ("attempt to write into IRQ status register (val=%#x)\n",
               val);
        return;
B
bellard 已提交
972

B
bellard 已提交
973 974 975 976 977 978 979
    default:
        if (s->mixer_nreg >= 0x80)
            dolog ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
        break;
    }

    s->mixer_regs[s->mixer_nreg] = val;
B
bellard 已提交
980 981
}

B
bellard 已提交
982 983
static IO_WRITE_PROTO(mixer_write_indexw)
{
B
bellard 已提交
984 985
    mixer_write_indexb (opaque, nport, val & 0xff);
    mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
B
bellard 已提交
986 987 988 989
}

static IO_READ_PROTO(mixer_read)
{
B
bellard 已提交
990
    SB16State *s = opaque;
B
bellard 已提交
991 992 993
#ifndef DEBUG_SB16_MOST
    if (s->mixer_nreg != 0x82)
#endif
B
bellard 已提交
994 995 996
    ldebug ("mixer_read[%#x] -> %#x\n",
            s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
    return s->mixer_regs[s->mixer_nreg];
B
bellard 已提交
997 998
}

B
bellard 已提交
999 1000
static int write_audio (SB16State *s, int nchan, int dma_pos,
                        int dma_len, int len)
B
bellard 已提交
1001 1002
{
    int temp, net;
1003
    uint8_t tmpbuf[4096];
B
bellard 已提交
1004

B
bellard 已提交
1005
    temp = len;
B
bellard 已提交
1006 1007 1008
    net = 0;

    while (temp) {
B
bellard 已提交
1009 1010
        int left = dma_len - dma_pos;
        int to_copy, copied;
B
bellard 已提交
1011

B
bellard 已提交
1012
        to_copy = audio_MIN (temp, left);
1013 1014
        if (to_copy > sizeof(tmpbuf))
            to_copy = sizeof(tmpbuf);
B
bellard 已提交
1015

B
bellard 已提交
1016 1017
        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
        copied = AUD_write (s->voice, tmpbuf, copied);
B
bellard 已提交
1018

B
bellard 已提交
1019 1020
        temp -= copied;
        dma_pos = (dma_pos + copied) % dma_len;
B
bellard 已提交
1021 1022
        net += copied;

B
bellard 已提交
1023 1024
        if (!copied)
            break;
B
bellard 已提交
1025 1026 1027 1028 1029
    }

    return net;
}

B
bellard 已提交
1030
static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
B
bellard 已提交
1031
{
B
bellard 已提交
1032 1033
    SB16State *s = opaque;
    int free, rfree, till, copy, written, elapsed;
B
bellard 已提交
1034

B
bellard 已提交
1035 1036
    if (s->left_till_irq < 0) {
        s->left_till_irq = s->block_size;
B
bellard 已提交
1037 1038
    }

B
bellard 已提交
1039 1040 1041 1042
    elapsed = AUD_calc_elapsed (s->voice);
    free = elapsed;/* AUD_get_free (s->voice); */
    rfree = free;
    free = audio_MIN (free, elapsed) & ~s->align;
B
bellard 已提交
1043

B
bellard 已提交
1044 1045
    if ((free <= 0) || !dma_len) {
        return dma_pos;
B
bellard 已提交
1046 1047
    }

B
bellard 已提交
1048 1049
    copy = free;
    till = s->left_till_irq;
B
bellard 已提交
1050

B
bellard 已提交
1051
#ifdef DEBUG_SB16_MOST
B
bellard 已提交
1052 1053
    dolog ("pos:%06d free:%d,%d till:%d len:%d\n",
           dma_pos, free, AUD_get_free (s->voice), till, dma_len);
B
bellard 已提交
1054 1055
#endif

B
bellard 已提交
1056
    if (till <= copy) {
B
bellard 已提交
1057
        if (0 == s->dma_auto) {
B
bellard 已提交
1058 1059 1060 1061
            copy = till;
        }
    }

B
bellard 已提交
1062 1063 1064
    written = write_audio (s, nchan, dma_pos, dma_len, copy);
    dma_pos = (dma_pos + written) % dma_len;
    s->left_till_irq -= written;
B
bellard 已提交
1065

B
bellard 已提交
1066 1067 1068 1069 1070 1071
    if (s->left_till_irq <= 0) {
        s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
        pic_set_irq (s->irq, 1);
        if (0 == s->dma_auto) {
            control (s, 0);
            speaker (s, 0);
B
bellard 已提交
1072 1073 1074
        }
    }

B
bellard 已提交
1075
#ifdef DEBUG_SB16_MOST
B
bellard 已提交
1076 1077 1078
    ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
            dma_pos, free, dma_len, s->left_till_irq, copy, written,
            s->block_size);
B
bellard 已提交
1079
#endif
B
bellard 已提交
1080

B
bellard 已提交
1081 1082
    while (s->left_till_irq <= 0) {
        s->left_till_irq = s->block_size + s->left_till_irq;
B
bellard 已提交
1083 1084
    }

B
bellard 已提交
1085 1086
    AUD_adjust (s->voice, written);
    return dma_pos;
B
bellard 已提交
1087 1088
}

B
bellard 已提交
1089
void SB_timer (void *opaque)
B
bellard 已提交
1090
{
B
bellard 已提交
1091 1092 1093
    SB16State *s = opaque;
    AUD_run ();
    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
B
bellard 已提交
1094 1095
}

B
bellard 已提交
1096
static void SB_save (QEMUFile *f, void *opaque)
B
bellard 已提交
1097
{
B
bellard 已提交
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
    SB16State *s = opaque;

    qemu_put_be32s (f, &s->irq);
    qemu_put_be32s (f, &s->dma);
    qemu_put_be32s (f, &s->hdma);
    qemu_put_be32s (f, &s->port);
    qemu_put_be32s (f, &s->ver);
    qemu_put_be32s (f, &s->in_index);
    qemu_put_be32s (f, &s->out_data_len);
    qemu_put_be32s (f, &s->fmt_stereo);
    qemu_put_be32s (f, &s->fmt_signed);
    qemu_put_be32s (f, &s->fmt_bits);
    qemu_put_be32s (f, &s->fmt);
    qemu_put_be32s (f, &s->dma_auto);
    qemu_put_be32s (f, &s->block_size);
    qemu_put_be32s (f, &s->fifo);
    qemu_put_be32s (f, &s->freq);
    qemu_put_be32s (f, &s->time_const);
    qemu_put_be32s (f, &s->speaker);
    qemu_put_be32s (f, &s->needed_bytes);
    qemu_put_be32s (f, &s->cmd);
    qemu_put_be32s (f, &s->use_hdma);
    qemu_put_be32s (f, &s->highspeed);
    qemu_put_be32s (f, &s->can_write);
    qemu_put_be32s (f, &s->v2x6);

    qemu_put_8s (f, &s->csp_param);
    qemu_put_8s (f, &s->csp_value);
    qemu_put_8s (f, &s->csp_mode);
    qemu_put_8s (f, &s->csp_param);
    qemu_put_buffer (f, s->csp_regs, 256);
    qemu_put_8s (f, &s->csp_index);
    qemu_put_buffer (f, s->csp_reg83, 4);
    qemu_put_be32s (f, &s->csp_reg83r);
    qemu_put_be32s (f, &s->csp_reg83w);

    qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data));
    qemu_put_buffer (f, s->out_data, sizeof (s->out_data));
    qemu_put_8s (f, &s->test_reg);
    qemu_put_8s (f, &s->last_read_byte);

    qemu_put_be32s (f, &s->nzero);
    qemu_put_be32s (f, &s->left_till_irq);
    qemu_put_be32s (f, &s->dma_running);
    qemu_put_be32s (f, &s->bytes_per_second);
    qemu_put_be32s (f, &s->align);

    qemu_put_be32s (f, &s->mixer_nreg);
    qemu_put_buffer (f, s->mixer_regs, 256);
B
bellard 已提交
1147 1148
}

B
bellard 已提交
1149
static int SB_load (QEMUFile *f, void *opaque, int version_id)
B
bellard 已提交
1150
{
B
bellard 已提交
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
    SB16State *s = opaque;

    if (version_id != 1)
        return -EINVAL;

    qemu_get_be32s (f, &s->irq);
    qemu_get_be32s (f, &s->dma);
    qemu_get_be32s (f, &s->hdma);
    qemu_get_be32s (f, &s->port);
    qemu_get_be32s (f, &s->ver);
    qemu_get_be32s (f, &s->in_index);
    qemu_get_be32s (f, &s->out_data_len);
    qemu_get_be32s (f, &s->fmt_stereo);
    qemu_get_be32s (f, &s->fmt_signed);
    qemu_get_be32s (f, &s->fmt_bits);
    qemu_get_be32s (f, &s->fmt);
    qemu_get_be32s (f, &s->dma_auto);
    qemu_get_be32s (f, &s->block_size);
    qemu_get_be32s (f, &s->fifo);
    qemu_get_be32s (f, &s->freq);
    qemu_get_be32s (f, &s->time_const);
    qemu_get_be32s (f, &s->speaker);
    qemu_get_be32s (f, &s->needed_bytes);
    qemu_get_be32s (f, &s->cmd);
    qemu_get_be32s (f, &s->use_hdma);
    qemu_get_be32s (f, &s->highspeed);
    qemu_get_be32s (f, &s->can_write);
    qemu_get_be32s (f, &s->v2x6);

    qemu_get_8s (f, &s->csp_param);
    qemu_get_8s (f, &s->csp_value);
    qemu_get_8s (f, &s->csp_mode);
    qemu_get_8s (f, &s->csp_param);
    qemu_get_buffer (f, s->csp_regs, 256);
    qemu_get_8s (f, &s->csp_index);
    qemu_get_buffer (f, s->csp_reg83, 4);
    qemu_get_be32s (f, &s->csp_reg83r);
    qemu_get_be32s (f, &s->csp_reg83w);

    qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data));
    qemu_get_buffer (f, s->out_data, sizeof (s->out_data));
    qemu_get_8s (f, &s->test_reg);
    qemu_get_8s (f, &s->last_read_byte);

    qemu_get_be32s (f, &s->nzero);
    qemu_get_be32s (f, &s->left_till_irq);
    qemu_get_be32s (f, &s->dma_running);
    qemu_get_be32s (f, &s->bytes_per_second);
    qemu_get_be32s (f, &s->align);

    qemu_get_be32s (f, &s->mixer_nreg);
    qemu_get_buffer (f, s->mixer_regs, 256);

B
bellard 已提交
1204 1205 1206 1207
    if (s->voice) {
        AUD_close (s->voice);
        s->voice = NULL;
    }
B
bellard 已提交
1208 1209 1210 1211 1212 1213 1214 1215

    if (s->dma_running) {
        if (s->freq)
            s->voice = AUD_open (s->voice, "sb16", s->freq,
                                 1 << s->fmt_stereo, s->fmt);

        control (s, 1);
        speaker (s, s->speaker);
B
bellard 已提交
1216
    }
B
bellard 已提交
1217
    return 0;
B
bellard 已提交
1218 1219
}

B
bellard 已提交
1220 1221
void SB16_init (void)
{
1222
    SB16State *s = &dsp;
B
bellard 已提交
1223 1224 1225 1226
    int i;
    static const uint8_t dsp_write_ports[] = {0x6, 0xc};
    static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};

B
bellard 已提交
1227 1228 1229 1230 1231 1232 1233 1234 1235
    s->ts = qemu_new_timer (vm_clock, SB_timer, s);
    if (!s->ts)
        return;

    s->irq = conf.irq;
    s->dma = conf.dma;
    s->hdma = conf.hdma;
    s->port = conf.port;
    s->ver = conf.ver_lo | (conf.ver_hi << 8);
B
bellard 已提交
1236

B
bellard 已提交
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
    s->mixer_regs[0x80] = magic_of_irq (s->irq);
    s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
    s->mixer_regs[0x82] = 2 << 5;

    s->csp_regs[5] = 1;
    s->csp_regs[9] = 0xf8;

    reset_mixer (s);
    s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
    if (!s->aux_ts)
        return;
B
bellard 已提交
1248 1249

    for (i = 0; i < LENOFA (dsp_write_ports); i++) {
B
bellard 已提交
1250
        register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
B
bellard 已提交
1251 1252 1253
    }

    for (i = 0; i < LENOFA (dsp_read_ports); i++) {
B
bellard 已提交
1254
        register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
B
bellard 已提交
1255 1256
    }

B
bellard 已提交
1257 1258 1259 1260
    register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
    register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
    register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
    register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
B
bellard 已提交
1261

B
bellard 已提交
1262 1263 1264
    DMA_register_channel (s->hdma, SB_read_DMA, s);
    DMA_register_channel (s->dma, SB_read_DMA, s);
    s->can_write = 1;
B
bellard 已提交
1265

B
bellard 已提交
1266 1267
    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
    register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
B
bellard 已提交
1268
}