diff options
Diffstat (limited to 'hw/sb16.c')
-rw-r--r-- | hw/sb16.c | 1412 |
1 files changed, 821 insertions, 591 deletions
@@ -1,7 +1,7 @@ /* * QEMU Soundblaster 16 emulation * - * Copyright (c) 2003 Vassili Karpov (malc) + * Copyright (c) 2003-2004 Vassili Karpov (malc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,32 +23,20 @@ */ #include "vl.h" -#define MIN(a, b) ((a)>(b)?(b):(a)) -#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) - -#define dolog(...) fprintf (stderr, "sb16: " __VA_ARGS__); +/* #define DEBUG */ +#define AUDIO_CAP "sb16" +#include "audio/audio.h" -/* #define DEBUG_SB16 */ +#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) -#ifdef DEBUG_SB16 -#define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#define ldebug(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#else -#define lwarn(...) -#define linfo(...) -#define ldebug(...) -#endif +/* #define DEBUG_SB16_MOST */ -#define IO_READ_PROTO(name) \ +#define IO_READ_PROTO(name) \ uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ +#define IO_WRITE_PROTO(name) \ void name (void *opaque, uint32_t nport, uint32_t val) -static const char e3[] = - "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992\0" - "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994-1997"; - /* "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994."; */ +static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; static struct { int ver_lo; @@ -57,38 +45,58 @@ static struct { int dma; int hdma; int port; - int mix_block; -} sb = {5, 4, 5, 1, 5, 0x220, -1}; - -static int mix_block, noirq; +} conf = {5, 4, 5, 1, 5, 0x220}; typedef struct SB16State { + int irq; + int dma; + int hdma; + int port; + int ver; + int in_index; int out_data_len; int fmt_stereo; int fmt_signed; int fmt_bits; + audfmt_e fmt; int dma_auto; - int dma_buffer_size; + int block_size; int fifo; int freq; int time_const; int speaker; int needed_bytes; int cmd; - int dma_pos; int use_hdma; + int highspeed; + int can_write; int v2x6; + 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; + uint8_t in2_data[10]; - uint8_t out_data[1024]; + uint8_t out_data[50]; + uint8_t test_reg; + uint8_t last_read_byte; + int nzero; int left_till_irq; - uint64_t nzero; - uint8_t last_read_byte; - uint8_t test_reg; + int dma_running; + int bytes_per_second; + int align; + SWVoice *voice; + + QEMUTimer *ts, *aux_ts; /* mixer state */ int mixer_nreg; uint8_t mixer_regs[256]; @@ -97,664 +105,853 @@ typedef struct SB16State { /* XXX: suppress that and use a context */ static struct SB16State dsp; +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 static void log_dsp (SB16State *dsp) { - ldebug ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", - dsp->fmt_stereo ? 'S' : 'M', - dsp->fmt_signed ? 'S' : 'U', - dsp->fmt_bits, - dsp->dma_auto ? 'a' : 's', - dsp->dma_buffer_size, - dsp->dma_pos, - dsp->freq, - dsp->time_const, - dsp->speaker); + 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); */ } -static void control (int hold) +static void control (SB16State *s, int hold) { - linfo ("%d high %d\n", hold, dsp.use_hdma); + 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); + if (hold) { - if (dsp.use_hdma) - DMA_hold_DREQ (sb.hdma); - else - DMA_hold_DREQ (sb.dma); + DMA_hold_DREQ (dma); + AUD_enable (s->voice, 1); } else { - if (dsp.use_hdma) - DMA_release_DREQ (sb.hdma); - else - DMA_release_DREQ (sb.dma); + DMA_release_DREQ (dma); + AUD_enable (s->voice, 0); } } -static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) +static void aux_timer (void *opaque) { - int bps; - audfmt_e fmt; + 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; + } + + if (-1 != dma_len) + s->block_size = dma_len + 1; + + 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; + + 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); +} - dsp.use_hdma = cmd < 0xc0; - dsp.fifo = (cmd >> 1) & 1; - dsp.dma_auto = (cmd >> 2) & 1; +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; switch (cmd >> 4) { case 11: - dsp.fmt_bits = 16; + s->fmt_bits = 16; break; case 12: - dsp.fmt_bits = 8; + s->fmt_bits = 8; break; } - dsp.fmt_signed = (d0 >> 4) & 1; - dsp.fmt_stereo = (d0 >> 5) & 1; - - if (-1 != dsp.time_const) { - int tmp; - - tmp = 256 - dsp.time_const; - dsp.freq = (1000000 + (tmp / 2)) / tmp; + 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; } - bps = 1 << (16 == dsp.fmt_bits); - if (-1 != dma_len) - dsp.dma_buffer_size = (dma_len + 1) * bps; + s->block_size = dma_len + 1; + s->block_size <<= (s->fmt_bits == 16); + if (!s->dma_auto) /* Miles Sound System ? */ + s->block_size <<= s->fmt_stereo; - linfo ("frequency %d, stereo %d, signed %d, bits %d, size %d, auto %d\n", - dsp.freq, dsp.fmt_stereo, dsp.fmt_signed, dsp.fmt_bits, - dsp.dma_buffer_size, dsp.dma_auto); + 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 (16 == dsp.fmt_bits) { - if (dsp.fmt_signed) { - fmt = AUD_FMT_S16; + if (16 == s->fmt_bits) { + if (s->fmt_signed) { + s->fmt = AUD_FMT_S16; } else { - fmt = AUD_FMT_U16; + s->fmt = AUD_FMT_U16; } } else { - if (dsp.fmt_signed) { - fmt = AUD_FMT_S8; + if (s->fmt_signed) { + s->fmt = AUD_FMT_S8; } else { - fmt = AUD_FMT_U8; + s->fmt = AUD_FMT_U8; } } - dsp.dma_pos = 0; - dsp.left_till_irq = dsp.dma_buffer_size; + s->left_till_irq = s->block_size; - if (sb.mix_block) { - mix_block = sb.mix_block; - } - else { - int align; + 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; - align = bps << dsp.fmt_stereo; - mix_block = ((dsp.freq * align) / 100) & ~(align - 1); - } + if (s->freq) + s->voice = AUD_open (s->voice, "sb16", s->freq, + 1 << s->fmt_stereo, s->fmt); - if (dsp.freq) - AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt); - control (1); - dsp.speaker = 1; + control (s, 1); + speaker (s, 1); } -static inline void dsp_out_data(SB16State *dsp, int val) +static inline void dsp_out_data (SB16State *s, uint8_t val) { - if (dsp->out_data_len < sizeof(dsp->out_data)) - dsp->out_data[dsp->out_data_len++] = val; + ldebug ("outdata %#x\n", val); + if (s->out_data_len < sizeof (s->out_data)) + s->out_data[s->out_data_len++] = val; } -static inline uint8_t dsp_get_data(SB16State *dsp) +static inline uint8_t dsp_get_data (SB16State *s) { - if (dsp->in_index) - return dsp->in2_data[--dsp->in_index]; - else + if (s->in_index) + return s->in2_data[--s->in_index]; + else { + dolog ("buffer underflow\n"); return 0; + } } -static void command (SB16State *dsp, uint8_t cmd) +static void command (SB16State *s, uint8_t cmd) { - linfo ("command: %#x\n", cmd); + ldebug ("command %#x\n", cmd); if (cmd > 0xaf && cmd < 0xd0) { - if (cmd & 8) - goto error; + if (cmd & 8) { + dolog ("ADC not yet supported (command %#x)\n", cmd); + } switch (cmd >> 4) { case 11: case 12: break; default: - dolog ("command: %#x wrong bits specification\n", cmd); - goto error; + dolog ("%#x wrong bits\n", cmd); } - dsp->needed_bytes = 3; + s->needed_bytes = 3; } else { switch (cmd) { - case 0x00: - case 0xe7: - /* IMS uses those when probing for sound devices */ - return; - case 0x03: + dsp_out_data (s, 0x10); /* s->csp_param); */ + goto warn; + case 0x04: - dsp_out_data (dsp, 0); - return; + s->needed_bytes = 1; + goto warn; case 0x05: - dsp->needed_bytes = 2; - break; + s->needed_bytes = 2; + goto warn; + + case 0x08: + /* __asm__ ("int3"); */ + goto warn; case 0x0e: - dsp->needed_bytes = 2; - break; + s->needed_bytes = 2; + goto warn; + + case 0x09: + dsp_out_data (s, 0xf8); + goto warn; case 0x0f: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0x10: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0x14: - dsp->needed_bytes = 2; - dsp->dma_buffer_size = 0; + s->needed_bytes = 2; + s->block_size = 0; break; - case 0x20: - dsp_out_data(dsp, 0xff); - break; + case 0x20: /* Direct ADC, Juice/PL */ + dsp_out_data (s, 0xff); + goto warn; case 0x35: - lwarn ("MIDI commands not implemented\n"); + dolog ("MIDI command(0x35) not implemented\n"); break; case 0x40: - dsp->freq = -1; - dsp->time_const = -1; - dsp->needed_bytes = 1; + s->freq = -1; + s->time_const = -1; + s->needed_bytes = 1; break; case 0x41: - case 0x42: - dsp->freq = -1; - dsp->time_const = -1; - dsp->needed_bytes = 2; + s->freq = -1; + s->time_const = -1; + s->needed_bytes = 2; break; + case 0x42: + s->freq = -1; + s->time_const = -1; + s->needed_bytes = 2; + goto warn; + case 0x45: - dsp_out_data (dsp, 0xaa); + dsp_out_data (s, 0xaa); + goto warn; + case 0x47: /* Continue Auto-Initialize DMA 16bit */ break; case 0x48: - dsp->needed_bytes = 2; + s->needed_bytes = 2; break; - case 0x27: /* ????????? */ - case 0x4e: - return; - case 0x80: - cmd = -1; + s->needed_bytes = 2; break; case 0x90: case 0x91: - { - uint8_t d0; - - d0 = 4; - /* if (dsp->fmt_signed) d0 |= 16; */ - /* if (dsp->fmt_stereo) d0 |= 32; */ - dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); - cmd = -1; - break; - } + dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1); + break; - case 0xd0: /* XXX */ - control (0); - return; + case 0xd0: /* halt DMA operation. 8bit */ + control (s, 0); + break; - case 0xd1: - dsp->speaker = 1; + case 0xd1: /* speaker on */ + speaker (s, 1); break; - case 0xd3: - dsp->speaker = 0; - return; + case 0xd3: /* speaker off */ + speaker (s, 0); + break; - case 0xd4: - control (1); + case 0xd4: /* continue DMA operation. 8bit */ + control (s, 1); break; - case 0xd5: - control (0); + case 0xd5: /* halt DMA operation. 16bit */ + control (s, 0); break; - case 0xd6: - control (1); + case 0xd6: /* continue DMA operation. 16bit */ + control (s, 1); break; - case 0xd9: - control (0); - dsp->dma_auto = 0; - return; + case 0xd9: /* exit auto-init DMA after this block. 16bit */ + s->dma_auto = 0; + break; - case 0xda: - control (0); - dsp->dma_auto = 0; + case 0xda: /* exit auto-init DMA after this block. 8bit */ + s->dma_auto = 0; break; case 0xe0: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0xe1: - dsp_out_data(dsp, sb.ver_lo); - dsp_out_data(dsp, sb.ver_hi); - return; + dsp_out_data (s, s->ver & 0xff); + dsp_out_data (s, s->ver >> 8); + break; + + case 0xe2: + s->needed_bytes = 1; + goto warn; case 0xe3: { int i; - for (i = sizeof (e3) - 1; i >= 0; i--) - dsp_out_data (dsp, e3[i]); - return; + for (i = sizeof (e3) - 1; i >= 0; --i) + dsp_out_data (s, e3[i]); } + break; case 0xe4: /* write test reg */ - dsp->needed_bytes = 1; + s->needed_bytes = 1; break; + case 0xe7: + dolog ("Attempt to probe for ESS (0xe7)?\n"); + return; + case 0xe8: /* read test reg */ - dsp_out_data (dsp, dsp->test_reg); + dsp_out_data (s, s->test_reg); break; case 0xf2: - dsp_out_data (dsp, 0xaa); - dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; - pic_set_irq (sb.irq, 1); - return; + case 0xf3: + dsp_out_data (s, 0xaa); + s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2; + pic_set_irq (s->irq, 1); + break; case 0xf9: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0xfa: - dsp_out_data (dsp, 0); - break; + dsp_out_data (s, 0); + goto warn; case 0xfc: /* FIXME */ - dsp_out_data (dsp, 0); - break; + dsp_out_data (s, 0); + goto warn; default: dolog ("unrecognized command %#x\n", cmd); - goto error; + return; } } - dsp->cmd = cmd; + + s->cmd = cmd; + if (!s->needed_bytes) + ldebug ("\n"); return; - error: + warn: + dolog ("warning command %#x,%d is not trully understood yet\n", + cmd, s->needed_bytes); + s->cmd = cmd; return; } -static void complete (SB16State *dsp) +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) { int d0, d1, d2; - linfo ("complete command %#x, in_index %d, needed_bytes %d\n", - dsp->cmd, dsp->in_index, dsp->needed_bytes); + ldebug ("complete command %#x, in_index %d, needed_bytes %d\n", + s->cmd, s->in_index, s->needed_bytes); - if (dsp->cmd > 0xaf && dsp->cmd < 0xd0) { - d2 = dsp_get_data (dsp); - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); + if (s->cmd > 0xaf && s->cmd < 0xd0) { + d2 = dsp_get_data (s); + d1 = dsp_get_data (s); + d0 = dsp_get_data (s); - ldebug ("d0 = %d, d1 = %d, d2 = %d\n", - d0, d1, d2); - dma_cmd (dsp->cmd, d0, d1 + (d2 << 8)); + 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)); + } } else { - switch (dsp->cmd) { + switch (s->cmd) { case 0x04: - case 0x10: - dsp_get_data (dsp); + 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); break; - case 0x0f: - d0 = dsp_get_data (dsp); - dsp_out_data (dsp, 0xf8); + 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); break; - case 0x05: case 0x0e: - dsp_get_data (dsp); - dsp_get_data (dsp); + 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; break; - case 0x14: - { - int save_left; - int save_pos; - - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); + 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; - save_left = dsp->left_till_irq; - save_pos = dsp->dma_pos; - dma_cmd (0xc0, 0, d0 + (d1 << 8)); - dsp->left_till_irq = save_left; - dsp->dma_pos = save_pos; + case 0x10: + d0 = dsp_get_data (s); + dolog ("cmd 0x10 d0=%#x\n", d0); + break; - linfo ("set buffer size data[%d, %d] %d pos %d\n", - d0, d1, dsp->dma_buffer_size, dsp->dma_pos); - break; - } + case 0x14: + dma_cmd8 (s, 0, dsp_get_lohi (s)); + /* s->can_write = 0; */ + /* qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + (ticks_per_sec * 320) / 1000000); */ + break; case 0x40: - dsp->time_const = dsp_get_data (dsp); - linfo ("set time const %d\n", dsp->time_const); + s->time_const = dsp_get_data (s); + ldebug ("set time const %d\n", s->time_const); break; - case 0x41: - case 0x42: - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); + case 0x42: /* FT2 sets output freq with this, go figure */ + dolog ("cmd 0x42 might not do what it think it should\n"); - dsp->freq = d1 + (d0 << 8); - linfo ("set freq %#x, %#x = %d\n", d1, d0, dsp->freq); + case 0x41: + s->freq = dsp_get_hilo (s); + ldebug ("set freq %d\n", s->freq); break; case 0x48: - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); - dsp->dma_buffer_size = d1 + (d0 << 8); - linfo ("set dma len %#x, %#x = %d\n", - d1, d0, dsp->dma_buffer_size); + s->block_size = dsp_get_lohi (s); + /* s->highspeed = 1; */ + ldebug ("set dma block len %d\n", s->block_size); + break; + + case 0x80: + { + int samples, bytes; + int64_t ticks; + + if (-1 == s->freq) + s->freq = 11025; + samples = dsp_get_lohi (s); + bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); + ticks = ticks_per_sec / (s->freq / bytes); + if (ticks < ticks_per_sec / 1024) + 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); + } break; case 0xe0: - d0 = dsp_get_data (dsp); - dsp->out_data_len = 0; - linfo ("data = %#x\n", d0); - dsp_out_data (dsp, d0 ^ 0xff); + d0 = dsp_get_data (s); + s->out_data_len = 0; + ldebug ("E0 data = %#x\n", d0); + dsp_out_data(s, ~d0); break; - case 0xe4: - dsp->test_reg = dsp_get_data (dsp); + case 0xe2: + d0 = dsp_get_data (s); + dolog ("E2 = %#x\n", d0); break; + case 0xe4: + s->test_reg = dsp_get_data (s); + break; case 0xf9: - d0 = dsp_get_data (dsp); - ldebug ("f9 <- %#x\n", d0); + d0 = dsp_get_data (s); + ldebug ("command 0xf9 with %#x\n", d0); switch (d0) { - case 0x0e: dsp_out_data (dsp, 0xff); break; - case 0x0f: dsp_out_data (dsp, 0x07); break; - case 0xf9: dsp_out_data (dsp, 0x00); break; + case 0x0e: + dsp_out_data (s, 0xff); + break; + + case 0x0f: + dsp_out_data (s, 0x07); + break; + case 0x37: - dsp_out_data (dsp, 0x38); break; + dsp_out_data (s, 0x38); + break; + default: - dsp_out_data (dsp, 0); + dsp_out_data (s, 0x00); + break; } break; default: - dolog ("complete: unrecognized command %#x\n", dsp->cmd); + dolog ("complete: unrecognized command %#x\n", s->cmd); return; } } - dsp->needed_bytes = 0; - dsp->cmd = -1; + ldebug ("\n"); + s->cmd = -1; return; } +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); +} + static IO_WRITE_PROTO (dsp_write) { - SB16State *dsp = opaque; + SB16State *s = opaque; int iport; - iport = nport - sb.port; + iport = nport - s->port; - ldebug ("dsp_write %#x <- %#x\n", nport, val); + ldebug ("write %#x <- %#x\n", nport, val); switch (iport) { - case 0x6: - control (0); - if (0 == val) - dsp->v2x6 = 0; - else if ((1 == val) && (0 == dsp->v2x6)) { - dsp->v2x6 = 1; - dsp->dma_pos = 0; - dsp->dma_auto = 0; - dsp->in_index = 0; - dsp->out_data_len = 0; - dsp->left_till_irq = 0; - dsp->speaker = 0; - dsp->needed_bytes = 0; - pic_set_irq (sb.irq, 0); - dsp_out_data(dsp, 0xaa); + 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; } - else - dsp->v2x6 = ~0; break; - case 0xc: /* write data or command | write status */ - if (0 == dsp->needed_bytes) { - command (dsp, val); - if (0 == dsp->needed_bytes) { - log_dsp (dsp); + 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); } +#endif } else { - if (dsp->in_index == sizeof (dsp->in2_data)) { + if (s->in_index == sizeof (s->in2_data)) { dolog ("in data overrun\n"); } else { - dsp->in2_data[dsp->in_index++] = val; - if (dsp->in_index == dsp->needed_bytes) { - dsp->needed_bytes = 0; - complete (dsp); - log_dsp (dsp); + 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 + } } } - } break; default: - dolog ("dsp_write (nport=%#x, val=%#x)\n", nport, val); + ldebug ("(nport=%#x, val=%#x)\n", nport, val); break; } } static IO_READ_PROTO (dsp_read) { - SB16State *dsp = opaque; - int iport, retval; + SB16State *s = opaque; + int iport, retval, ack = 0; - iport = nport - sb.port; + iport = nport - s->port; switch (iport) { - case 0x6: /* reset */ - control (0); - retval = 0; - dsp->speaker = 0; + case 0x06: /* reset */ + retval = 0xff; break; - case 0xa: /* read data */ - if (dsp->out_data_len) { - retval = dsp->out_data[--dsp->out_data_len]; - dsp->last_read_byte = retval; - } else { - retval = dsp->last_read_byte; + case 0x0a: /* read data */ + if (s->out_data_len) { + retval = s->out_data[--s->out_data_len]; + s->last_read_byte = retval; + } + else { dolog ("empty output buffer\n"); + retval = s->last_read_byte; /* goto error; */ } break; - case 0xc: /* 0xxxxxxx can write */ - retval = 0; - if (dsp->out_data_len == sizeof (dsp->out_data)) retval |= 0x80; + case 0x0c: /* 0 can write */ + retval = s->can_write ? 0 : 0x80; break; - case 0xd: /* timer interrupt clear */ - dolog ("timer interrupt clear\n"); - goto error; + case 0x0d: /* timer interrupt clear */ + /* dolog ("timer interrupt clear\n"); */ + retval = 0; + break; - case 0xe: /* data available status | irq 8 ack */ - /* XXX drop pic irq line here? */ - /* ldebug ("8 ack\n"); */ - retval = dsp->out_data_len ? 0x80 : 0; - dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; - pic_set_irq (sb.irq, 0); + 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 0xf: /* irq 16 ack */ - /* XXX drop pic irq line here? */ - ldebug ("16 ack\n"); + case 0x0f: /* irq 16 ack */ retval = 0xff; - dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; - pic_set_irq (sb.irq, 0); + if (s->mixer_regs[0x82] & 2) { + ack = 1; + s->mixer_regs[0x82] &= 2; + pic_set_irq (s->irq, 0); + } break; default: goto error; } - if (0xe == iport) { - if (0 == retval) { - if (!dsp->nzero) { - ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", - nport, iport, retval, dsp->nzero); - } - dsp->nzero += 1; - } - else { - ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", - nport, iport, retval, dsp->nzero); - dsp->nzero = 0; - } - } - else { - ldebug ("dsp_read (nport=%#x iport %#x) = %#x\n", - nport, iport, retval); - } + if (!ack) + ldebug ("read %#x -> %#x\n", nport, retval); return retval; error: - printf ("dsp_read error %#x\n", nport); + 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 *dsp = opaque; - dsp->mixer_nreg = val; + SB16State *s = opaque; + s->mixer_nreg = val; } static IO_WRITE_PROTO(mixer_write_datab) { - SB16State *dsp = opaque; - int i; + SB16State *s = opaque; + + ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); + if (s->mixer_nreg > sizeof (s->mixer_regs)) + return; - linfo ("mixer [%#x] <- %#x\n", dsp->mixer_nreg, val); - switch (dsp->mixer_nreg) { + switch (s->mixer_nreg) { case 0x00: - /* Bochs */ - dsp->mixer_regs[0x04] = 0xcc; - dsp->mixer_regs[0x0a] = 0x00; - dsp->mixer_regs[0x22] = 0xcc; - dsp->mixer_regs[0x26] = 0xcc; - dsp->mixer_regs[0x28] = 0x00; - dsp->mixer_regs[0x2e] = 0x00; - dsp->mixer_regs[0x3c] = 0x1f; - dsp->mixer_regs[0x3d] = 0x15; - dsp->mixer_regs[0x3e] = 0x0b; - - for (i = 0x30; i <= 0x35; i++) - dsp->mixer_regs[i] = 0xc0; - - for (i = 0x36; i <= 0x3b; i++) - dsp->mixer_regs[i] = 0x00; - - for (i = 0x3f; i <= 0x43; i++) - dsp->mixer_regs[i] = 0x00; - - for (i = 0x44; i <= 0x47; i++) - dsp->mixer_regs[i] = 0x80; - - for (i = 0x30; i < 0x48; i++) { - dsp->mixer_regs[i] = 0x20; - } + reset_mixer (s); break; - case 0x04: - case 0x0a: - case 0x22: - case 0x26: - case 0x28: - case 0x2e: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: case 0x80: - case 0x81: + { + int irq = irq_of_magic (val); + ldebug ("setting irq to %d (val=%#x)\n", irq, val); + if (irq > 0) + s->irq = irq; + } break; - default: - return; - } - dsp->mixer_regs[dsp->mixer_nreg] = val; -} -static IO_WRITE_PROTO(mpu_write) -{ - linfo ("mpu: %#x\n", val); -} + case 0x81: + { + int dma, hdma; -static IO_WRITE_PROTO(adlib_write) -{ - linfo ("adlib: %#x\n", val); -} + 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; -static IO_READ_PROTO(mpu_read) -{ - linfo ("mpu read: %#x\n", nport); - return 0x80; -} + case 0x82: + dolog ("attempt to write into IRQ status register (val=%#x)\n", + val); + return; -static IO_READ_PROTO(adlib_read) -{ - linfo ("adlib read: %#x\n", nport); - return 0; + 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; } static IO_WRITE_PROTO(mixer_write_indexw) @@ -765,194 +962,229 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { - SB16State *dsp = opaque; - linfo ("mixer [%#x] -> %#x\n", dsp->mixer_nreg, dsp->mixer_regs[dsp->mixer_nreg]); - return dsp->mixer_regs[dsp->mixer_nreg]; -} - -void SB16_run (void) -{ - if (0 == dsp.speaker) - return; - - AUD_run (); + SB16State *s = opaque; + ldebug ("mixer_read[%#x] -> %#x\n", + s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); + return s->mixer_regs[s->mixer_nreg]; } -static int write_audio (uint32_t addr, int len, int size) +static int write_audio (SB16State *s, int nchan, int dma_pos, + int dma_len, int len) { int temp, net; uint8_t tmpbuf[4096]; - temp = size; - + temp = len; net = 0; while (temp) { - int left_till_end; - int to_copy; - int copied; + int left = dma_len - dma_pos; + int to_copy, copied; - left_till_end = len - dsp.dma_pos; - - to_copy = MIN (temp, left_till_end); + to_copy = audio_MIN (temp, left); if (to_copy > sizeof(tmpbuf)) to_copy = sizeof(tmpbuf); - cpu_physical_memory_read(addr + dsp.dma_pos, tmpbuf, to_copy); - copied = AUD_write (tmpbuf, to_copy); - temp -= copied; - dsp.dma_pos += copied; - - if (dsp.dma_pos == len) { - dsp.dma_pos = 0; - } + 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 != to_copy) - return net; + if (!copied) + break; } return net; } -static int SB_read_DMA (void *opaque, target_ulong addr, int size) +static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) { - SB16State *dsp = opaque; - int free, till, copy, written; - - if (0 == dsp->speaker) - return 0; + SB16State *s = opaque; + int free, rfree, till, copy, written, elapsed; - if (dsp->left_till_irq < 0) { - ldebug ("left_till_irq < 0, %d, pos %d \n", - dsp->left_till_irq, dsp->dma_buffer_size); - dsp->left_till_irq += dsp->dma_buffer_size; - return dsp->dma_pos; + if (s->left_till_irq < 0) { + s->left_till_irq = s->block_size; } - free = AUD_get_free (); - - if ((free <= 0) || (0 == size)) { - ldebug ("returning, since free = %d and size = %d\n", free, size); - return dsp->dma_pos; - } + elapsed = AUD_calc_elapsed (s->voice); + free = elapsed;/* AUD_get_free (s->voice); */ + rfree = free; + free = audio_MIN (free, elapsed) & ~s->align; - if (mix_block > 0) { - copy = MIN (free, mix_block); - } - else { - copy = free; + if ((free <= 0) || !dma_len) { + return dma_pos; } - till = dsp->left_till_irq; + copy = free; + till = s->left_till_irq; #ifdef DEBUG_SB16_MOST - ldebug ("addr:%#010x free:%d till:%d size:%d\n", - addr, free, till, size); + dolog ("pos:%06d free:%d,%d till:%d len:%d\n", + dma_pos, free, AUD_get_free (s->voice), till, dma_len); #endif if (till <= copy) { - if (0 == dsp->dma_auto) { + if (0 == s->dma_auto) { copy = till; } } - written = write_audio (addr, size, copy); - dsp->left_till_irq -= written; - AUD_adjust_estimate (free - written); + written = write_audio (s, nchan, dma_pos, dma_len, copy); + dma_pos = (dma_pos + written) % dma_len; + s->left_till_irq -= written; - if (dsp->left_till_irq <= 0) { - dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; - if (0 == noirq) { - ldebug ("request irq pos %d, left %d\n", - dsp->dma_pos, dsp->left_till_irq); - pic_set_irq(sb.irq, 1); - } - - if (0 == dsp->dma_auto) { - control (0); + 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 dma size %5d\n", - dsp->dma_pos, free, size, dsp->left_till_irq, copy, - dsp->dma_buffer_size); + dma_pos, free, dma_len, s->left_till_irq, copy, s->block_size); #endif - if (dsp->left_till_irq <= 0) { - dsp->left_till_irq += dsp->dma_buffer_size; + while (s->left_till_irq <= 0) { + s->left_till_irq = s->block_size + s->left_till_irq; } - return dsp->dma_pos; -} - -static int magic_of_irq (int irq) -{ - switch (irq) { - case 2: - return 1; - case 5: - return 2; - case 7: - return 4; - case 10: - return 8; - default: - dolog ("bad irq %d\n", irq); - return 2; - } + AUD_adjust (s->voice, written); + return dma_pos; } -#if 0 -static int irq_of_magic (int magic) +void SB_timer (void *opaque) { - switch (magic) { - case 1: - return 2; - case 2: - return 5; - case 4: - return 7; - case 8: - return 10; - default: - dolog ("bad irq magic %d\n", magic); - return 2; - } + SB16State *s = opaque; + AUD_run (); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); } -#endif -#ifdef SB16_TRAP_ALL -static IO_READ_PROTO (trap_read) +static void SB_save (QEMUFile *f, void *opaque) { - switch (nport) { - case 0x220: - return 0; - case 0x226: - case 0x22a: - case 0x22c: - case 0x22d: - case 0x22e: - case 0x22f: - return dsp_read (opaque, nport); - } - linfo ("trap_read: %#x\n", nport); - return 0xff; + 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 IO_WRITE_PROTO (trap_write) +static int SB_load (QEMUFile *f, void *opaque, int version_id) { - switch (nport) { - case 0x226: - case 0x22c: - dsp_write (opaque, nport, val); - return; + 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_reset (s->voice); + + 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); } - linfo ("trap_write: %#x = %#x\n", nport, val); + return 0; } -#endif void SB16_init (void) { @@ -961,47 +1193,45 @@ void SB16_init (void) static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; - memset(s->mixer_regs, 0xff, sizeof(s->mixer_regs)); + 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); - s->mixer_regs[0x00] = 0; - s->mixer_regs[0x0e] = ~0; - s->mixer_regs[0x80] = magic_of_irq (sb.irq); - s->mixer_regs[0x81] = 0x80 | 0x10 | (sb.dma << 1); - s->mixer_regs[0x82] = 0; - s->mixer_regs[0xfd] = 16; /* bochs */ - s->mixer_regs[0xfe] = 6; /* bochs */ - mixer_write_indexw (s, 0x224, 0); - -#ifdef SB16_TRAP_ALL - for (i = 0; i < 0x100; i++) { - if (i != 4 && i != 5) { - register_ioport_write (sb.port + i, 1, 1, trap_write, s); - register_ioport_read (sb.port + i, 1, 1, trap_read, s); - } - } -#else + 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; for (i = 0; i < LENOFA (dsp_write_ports); i++) { - register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, s); + 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 (sb.port + dsp_read_ports[i], 1, 1, dsp_read, s); + register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s); } -#endif - register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, s); - register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, s); - register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, s); - register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, 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); - for (i = 0; 4 < 4; i++) { - register_ioport_read (0x330 + i, 1, 1, mpu_read, s); - register_ioport_write (0x330 + i, 1, 1, mpu_write, s); - register_ioport_read (0x388 + i, 1, 1, adlib_read, s); - register_ioport_write (0x388 + i, 1, 1, adlib_write, s); - } + DMA_register_channel (s->hdma, SB_read_DMA, s); + DMA_register_channel (s->dma, SB_read_DMA, s); + s->can_write = 1; - DMA_register_channel (sb.hdma, SB_read_DMA, s); - DMA_register_channel (sb.dma, SB_read_DMA, s); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); + register_savevm ("sb16", 0, 1, SB_save, SB_load, s); } |