?? sb16.c
字號:
{ SB16State *s = opaque; int iport, retval, ack = 0; iport = nport - s->port; switch (iport) { case 0x06: /* reset */ retval = 0xff; break; case 0x0a: /* read data */ if (s->out_data_len) { 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; qemu_irq_lower (s->pic[s->irq]); } break; case 0x0f: /* irq 16 ack */ retval = 0xff; if (s->mixer_regs[0x82] & 2) { ack = 1; s->mixer_regs[0x82] &= 2; qemu_irq_lower (s->pic[s->irq]); } 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; qemu_irq_raise (s->pic[s->irq]); 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_be32 (f, s->irq); qemu_put_be32 (f, s->dma); qemu_put_be32 (f, s->hdma); qemu_put_be32 (f, s->port); qemu_put_be32 (f, s->ver); qemu_put_be32 (f, s->in_index); qemu_put_be32 (f, s->out_data_len); qemu_put_be32 (f, s->fmt_stereo); qemu_put_be32 (f, s->fmt_signed); qemu_put_be32 (f, s->fmt_bits); qemu_put_be32s (f, &s->fmt); qemu_put_be32 (f, s->dma_auto); qemu_put_be32 (f, s->block_size); qemu_put_be32 (f, s->fifo); qemu_put_be32 (f, s->freq); qemu_put_be32 (f, s->time_const); qemu_put_be32 (f, s->speaker); qemu_put_be32 (f, s->needed_bytes); qemu_put_be32 (f, s->cmd); qemu_put_be32 (f, s->use_hdma); qemu_put_be32 (f, s->highspeed); qemu_put_be32 (f, s->can_write); qemu_put_be32 (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_be32 (f, s->csp_reg83r); qemu_put_be32 (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_be32 (f, s->nzero); qemu_put_be32 (f, s->left_till_irq); qemu_put_be32 (f, s->dma_running); qemu_put_be32 (f, s->bytes_per_second); qemu_put_be32 (f, s->align); qemu_put_be32 (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; } s->irq=qemu_get_be32 (f); s->dma=qemu_get_be32 (f); s->hdma=qemu_get_be32 (f); s->port=qemu_get_be32 (f); s->ver=qemu_get_be32 (f); s->in_index=qemu_get_be32 (f); s->out_data_len=qemu_get_be32 (f); s->fmt_stereo=qemu_get_be32 (f); s->fmt_signed=qemu_get_be32 (f); s->fmt_bits=qemu_get_be32 (f); qemu_get_be32s (f, &s->fmt); s->dma_auto=qemu_get_be32 (f); s->block_size=qemu_get_be32 (f); s->fifo=qemu_get_be32 (f); s->freq=qemu_get_be32 (f); s->time_const=qemu_get_be32 (f); s->speaker=qemu_get_be32 (f); s->needed_bytes=qemu_get_be32 (f); s->cmd=qemu_get_be32 (f); s->use_hdma=qemu_get_be32 (f); s->highspeed=qemu_get_be32 (f); s->can_write=qemu_get_be32 (f); s->v2x6=qemu_get_be32 (f); 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); s->csp_reg83r=qemu_get_be32 (f); s->csp_reg83w=qemu_get_be32 (f); 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); s->nzero=qemu_get_be32 (f); s->left_till_irq=qemu_get_be32 (f); s->dma_running=qemu_get_be32 (f); s->bytes_per_second=qemu_get_be32 (f); s->align=qemu_get_be32 (f); s->mixer_nreg=qemu_get_be32 (f); 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; as.endianness = 0; s->voice = AUD_open_out ( &s->card, s->voice, "sb16", s, SB_audio_callback, &as ); } control (s, 1); speaker (s, s->speaker); } return 0;}int SB16_init (AudioState *audio, qemu_irq *pic){ 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->pic = pic; 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 + -