📄 sb16.c
字号:
retval = s->out_data[--s->out_data_len]; s->last_read_byte = retval; } else { if (s->cmd != -1) { dolog ("empty output buffer for command %#x\n", s->cmd); } retval = s->last_read_byte; /* goto error; */ } break; case 0x0c: /* 0 can write */ retval = s->can_write ? 0 : 0x80; break; case 0x0d: /* timer interrupt clear */ /* dolog ("timer interrupt clear\n"); */ retval = 0; break; 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); } break; case 0x0f: /* irq 16 ack */ retval = 0xff; if (s->mixer_regs[0x82] & 2) { ack = 1; s->mixer_regs[0x82] &= 2; pic_set_irq (s->irq, 0); } break; default: goto error; } if (!ack) { ldebug ("read %#x -> %#x\n", nport, retval); } return retval; error: dolog ("warning: dsp_read %#x error\n", nport); return 0xff;}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; }}static IO_WRITE_PROTO(mixer_write_indexb){ SB16State *s = opaque; (void) nport; s->mixer_nreg = val;}static IO_WRITE_PROTO(mixer_write_datab){ SB16State *s = opaque; (void) nport; ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); switch (s->mixer_nreg) { case 0x00: reset_mixer (s); break; case 0x80: { int irq = irq_of_magic (val); ldebug ("setting irq to %d (val=%#x)\n", irq, val); if (irq > 0) { s->irq = irq; } } break; case 0x81: { int dma, hdma; dma = lsbindex (val & 0xf); hdma = lsbindex (val & 0xf0); if (dma != s->dma || hdma != s->hdma) { dolog ( "attempt to change DMA " "8bit %d(%d), 16bit %d(%d) (val=%#x)\n", dma, s->dma, hdma, s->hdma, val); }#if 0 s->dma = dma; s->hdma = hdma;#endif } break; case 0x82: dolog ("attempt to write into IRQ status register (val=%#x)\n", val); return; default: if (s->mixer_nreg >= 0x80) { ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); } break; } s->mixer_regs[s->mixer_nreg] = val;}static IO_WRITE_PROTO(mixer_write_indexw){ mixer_write_indexb (opaque, nport, val & 0xff); mixer_write_datab (opaque, nport, (val >> 8) & 0xff);}static IO_READ_PROTO(mixer_read){ SB16State *s = opaque; (void) nport;#ifndef DEBUG_SB16_MOST if (s->mixer_nreg != 0x82) { ldebug ("mixer_read[%#x] -> %#x\n", s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); }#else ldebug ("mixer_read[%#x] -> %#x\n", s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);#endif return s->mixer_regs[s->mixer_nreg];}static int write_audio (SB16State *s, int nchan, int dma_pos, int dma_len, int len){ int temp, net; uint8_t tmpbuf[4096]; temp = len; net = 0; while (temp) { int left = dma_len - dma_pos; int copied; size_t to_copy; to_copy = audio_MIN (temp, left); if (to_copy > sizeof (tmpbuf)) { to_copy = sizeof (tmpbuf); } copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); copied = AUD_write (s->voice, tmpbuf, copied); temp -= copied; dma_pos = (dma_pos + copied) % dma_len; net += copied; if (!copied) { break; } } return net;}static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len){ SB16State *s = opaque; int till, copy, written, free; if (s->left_till_irq < 0) { s->left_till_irq = s->block_size; } if (s->voice) { free = s->audio_free & ~s->align; if ((free <= 0) || !dma_len) { return dma_pos; } } else { free = dma_len; } copy = free; till = s->left_till_irq;#ifdef DEBUG_SB16_MOST dolog ("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len);#endif if (till <= copy) { if (0 == s->dma_auto) { copy = till; } } written = write_audio (s, nchan, dma_pos, dma_len, copy); dma_pos = (dma_pos + written) % dma_len; s->left_till_irq -= written; 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); } }#ifdef DEBUG_SB16_MOST 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);#endif while (s->left_till_irq <= 0) { s->left_till_irq = s->block_size + s->left_till_irq; } return dma_pos;}static void SB_audio_callback (void *opaque, int free){ SB16State *s = opaque; s->audio_free = free;}static void SB_save (QEMUFile *f, void *opaque){ 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);}static int SB_load (QEMUFile *f, void *opaque, int version_id){ 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); if (s->voice) { AUD_close_out (&s->card, s->voice); s->voice = NULL; } if (s->dma_running) { if (s->freq) { audsettings_t as; s->audio_free = 0; as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; s->voice = AUD_open_out ( &s->card, s->voice, "sb16", s, SB_audio_callback, &as, 0 /* little endian */ ); } control (s, 1); speaker (s, s->speaker); } return 0;}int SB16_init (AudioState *audio){ SB16State *s; int i; static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; if (!audio) { dolog ("No audio state\n"); return -1; } s = qemu_mallocz (sizeof (*s)); if (!s) { dolog ("Could not allocate memory for SB16 (%zu bytes)\n", sizeof (*s)); return -1; } s->cmd = -1; 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); 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) { dolog ("warning: Could not create auxiliary timer\n"); } for (i = 0; i < LENOFA (dsp_write_ports); i++) { register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s); } for (i = 0; i < LENOFA (dsp_read_ports); i++) { register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s); } 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); DMA_register_channel (s->hdma, SB_read_DMA, s); DMA_register_channel (s->dma, SB_read_DMA, s); s->can_write = 1; register_savevm ("sb16", 0, 1, SB_save, SB_load, s); AUD_register_card (audio, "sb16", &s->card); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -