diff options
-rw-r--r-- | hw/sb16.c | 65 |
1 files changed, 45 insertions, 20 deletions
@@ -26,15 +26,16 @@ #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) #define dolog(...) AUD_log ("sb16", __VA_ARGS__) + +/* #define DEBUG */ +/* #define DEBUG_SB16_MOST */ + #ifdef DEBUG #define ldebug(...) dolog (__VA_ARGS__) #else #define ldebug(...) #endif -/* #define DEBUG */ -/* #define DEBUG_SB16_MOST */ - #define IO_READ_PROTO(name) \ uint32_t name (void *opaque, uint32_t nport) #define IO_WRITE_PROTO(name) \ @@ -206,8 +207,18 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->freq = (1000000 + (tmp / 2)) / tmp; } - if (-1 != dma_len) - s->block_size = dma_len + 1; + 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; + } s->freq >>= s->fmt_stereo; s->left_till_irq = s->block_size; @@ -216,6 +227,9 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->dma_auto = (mask & DMA8_AUTO) != 0; s->align = (1 << s->fmt_stereo) - 1; + if (s->block_size & s->align) + dolog ("warning: unaligned buffer\n"); + 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, @@ -260,8 +274,13 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) s->block_size = dma_len + 1; s->block_size <<= (s->fmt_bits == 16); - if (!s->dma_auto) /* Miles Sound System ? */ + 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 */ s->block_size <<= s->fmt_stereo; + } ldebug ("freq %d, stereo %d, sign %d, bits %d, " "dma %d, auto %d, fifo %d, high %d\n", @@ -290,6 +309,8 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) 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; + if (s->block_size & s->align) + dolog ("warning: unaligned buffer\n"); if (s->freq) s->voice = AUD_open (s->voice, "sb16", s->freq, @@ -373,6 +394,10 @@ static void command (SB16State *s, uint8_t cmd) s->block_size = 0; break; + case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ + control (s, 1); + break; + case 0x20: /* Direct ADC, Juice/PL */ dsp_out_data (s, 0xff); goto warn; @@ -607,9 +632,7 @@ static void complete (SB16State *s) 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); */ + dma_cmd8 (s, 0, dsp_get_lohi (s) + 1); break; case 0x40: @@ -626,22 +649,20 @@ static void complete (SB16State *s) break; case 0x48: - s->block_size = dsp_get_lohi (s); - /* s->highspeed = 1; */ + s->block_size = dsp_get_lohi (s) + 1; ldebug ("set dma block len %d\n", s->block_size); break; case 0x80: { - int samples, bytes; + int freq, samples, bytes; int64_t ticks; - if (-1 == s->freq) - s->freq = 11025; - samples = dsp_get_lohi (s); + freq = s->freq > 0 ? s->freq : 11025; + samples = dsp_get_lohi (s) + 1; bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); - ticks = bytes ? (ticks_per_sec / (s->freq / bytes)) : 0; - if (!bytes || ticks < ticks_per_sec / 1024) + ticks = (bytes * ticks_per_sec) / freq; + 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); @@ -658,7 +679,7 @@ static void complete (SB16State *s) case 0xe2: d0 = dsp_get_data (s); - dolog ("E2 = %#x\n", d0); + ldebug ("E2 = %#x\n", d0); break; case 0xe4: @@ -967,6 +988,9 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { SB16State *s = opaque; +#ifndef DEBUG_SB16_MOST + if (s->mixer_nreg != 0x82) +#endif ldebug ("mixer_read[%#x] -> %#x\n", s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); return s->mixer_regs[s->mixer_nreg]; @@ -1049,8 +1073,9 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) } #ifdef DEBUG_SB16_MOST - ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", - dma_pos, free, dma_len, s->left_till_irq, copy, s->block_size); + 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) { |