static void __interrupt __far irq0() { counter++; #if T8254_IRQ >= 8 p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI); #endif p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI); }
void sb1_sc_play_adpcm2_test(void) { unsigned long time,bytes,expect,tlen,timeout; unsigned int count; unsigned int pc,c; unsigned long d; uint32_t irqc; doubleprintf("SB 1.x ADPCM 2-bit single cycle DSP playback test.\n"); timeout = T8254_REF_CLOCK_HZ * 4UL; for (count=0;count < 256;count++) { expect = 1000000UL / (unsigned long)(256 - count); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = (expect / 4UL) + 1; // 1 sec if (tlen > sb_card->buffer_size) tlen = sb_card->buffer_size; sb_card->buffer_dma_started_length = tlen; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; sndsb_write_dsp_timeconst(sb_card,count); _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); { unsigned int lv = (unsigned int)(tlen - 1UL); sndsb_write_dsp(sb_card,SNDSB_DSPCMD_DMA_DAC_OUT_ADPCM_2BIT_REF); /* 0x17 */ sndsb_write_dsp(sb_card,lv); sndsb_write_dsp(sb_card,lv >> 8); } while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)(((bytes - 1UL) * 4UL) + 1UL) / t; /* 4 samples/byte + 1 reference */ doubleprintf(" - TC 0x%02X: expecting %luHz, %lub/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,t,rate); } if (kbhit()) { if (getch() == 27) break; } continue; x_timeout: d = d8237_read_count(sb_card->dma8); /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_write_dsp_timeconst(sb_card,0x83); /* 8000Hz */ sndsb_reset_dsp(sb_card); }
void sb16_sc_play_test(void) { unsigned char bytespersample = wav_16bit ? 2 : 1; unsigned long time,bytes,expect,tlen,timeout; unsigned long count; unsigned int pc,c; unsigned long d; uint32_t irqc; int dma; if (wav_16bit && sb_card->dma16 >= 4) dma = sb_card->dma16; else dma = sb_card->dma8; if (sb_card->dsp_vmaj >= 4) /* Sound Blaster 16 */ { } else if (sb_card->is_gallant_sc6600) /* Reveal SC-4000 / Gallant SC-6600 */ { } else return; doubleprintf("SB16 4.x single cycle DSP playback test (%u bit).\n",wav_16bit?16:8); timeout = T8254_REF_CLOCK_HZ * 2UL; count = 0; do { expect = count; _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = expect; // 1 sec if (tlen < 4000UL) tlen = 4000UL; if (tlen > (sb_card->buffer_size / (unsigned long)bytespersample)) tlen = sb_card->buffer_size / (unsigned long)bytespersample; sb_card->buffer_dma_started_length = tlen * (unsigned long)bytespersample; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; sndsb_write_dsp_outrate(sb_card,count); _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); { unsigned int lv = (unsigned int)(tlen - 1UL); /* NTS: Reveal SC-4000 (Gallant 6600) cards DO support SB16 but only specific commands. * Command 0xC0 is not recognized, but command 0xC6 works. */ if (wav_16bit) { if (sb_card->is_gallant_sc6600) sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_AUTOINIT_DMA_DAC_OUT_16BIT); /* 0xB6 */ else sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_DMA_DAC_OUT_16BIT); /* 0xB0 */ sndsb_write_dsp(sb_card,0x10); /* mode (16-bit signed PCM) */ } else { if (sb_card->is_gallant_sc6600) sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_AUTOINIT_DMA_DAC_OUT_8BIT); /* 0xC6 */ else sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_DMA_DAC_OUT_8BIT); /* 0xC0 */ sndsb_write_dsp(sb_card,0x00); /* mode (8-bit unsigned PCM) */ } sndsb_write_dsp(sb_card,lv); sndsb_write_dsp(sb_card,lv >> 8); } while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - Rate 0x%04lX: expecting %luHz, %lu%c/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,wav_16bit?'w':'b',t,rate); } if (kbhit()) { if (getch() == 27) break; } count += 0x80; /* count by 128 because enumerating all would take too long */ if (count > 0xFFFFUL) break; continue; x_timeout: d = d8237_read_count(dma) / (unsigned long)bytespersample; /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } while (1); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_reset_dsp(sb_card); sndsb_write_dsp_outrate(sb_card,8000U); }
void ess_sc_play_test(void) { unsigned char bytespersample = wav_16bit ? 2 : 1; unsigned long time,bytes,expect,tlen,timeout; unsigned long count; unsigned int pc,c; unsigned long d; uint32_t irqc; if (!sb_card->ess_extensions || sb_card->ess_chipset == 0) return; doubleprintf("ESS688 single cycle DSP playback test (%u bit).\n",wav_16bit?16:8); timeout = T8254_REF_CLOCK_HZ * 2UL; for (count=0;count < 256;count++) { if (count >= 128) expect = 795500UL / (256 - count); else expect = 397700UL / (128 - count); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = expect; // 1 sec if (tlen > (sb_card->buffer_size / (unsigned long)bytespersample)) tlen = sb_card->buffer_size / (unsigned long)bytespersample; /* NTS: We ask the card to use demand ISA, 4 bytes at a time. * Behavior observed on real hardware, is that if you set up * DMA this way and then set up a non-auto-init DMA transfer * that isn't a multiple of 4, the DMA will stop short of * the full transfer and the IRQ will never fire. Therefore * the transfer length must be a multiple of 4! */ tlen -= tlen & 3; if (tlen == 0) tlen = 4; sb_card->buffer_dma_started_length = tlen * (unsigned long)bytespersample; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_ess_set_extended_mode(sb_card,1/*enable*/); sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; { /* ESS 688/1869 chipset specific DSP playback. using this mode bypasses a lot of the Sound Blaster Pro emulation and restrictions and allows us to run up to 48KHz 16-bit stereo */ unsigned short t16; int b; _cli(); /* clear IRQ */ sndsb_interrupt_ack(sb_card,3); b = 0x00; /* DMA disable */ b |= 0x00; /* no auto-init */ b |= 0x00; /* [3]=DMA converter in ADC mode [1]=DMA read for ADC playback mode */ sndsb_ess_write_controller(sb_card,0xB8,b); b = sndsb_ess_read_controller(sb_card,0xA8); b &= ~0xB; /* clear mono/stereo and record monitor (bits 3, 1, and 0) */ b |= 2; /* mono 10=mono 01=stereo */ sndsb_ess_write_controller(sb_card,0xA8,b); /* NTS: The meaning of bits 1:0 in register 0xB9 * * 00 single DMA transfer mode * 01 demand DMA transfer mode, 2 bytes/request * 10 demand DMA transfer mode, 4 bytes/request * 11 reserved * * NOTES on what happens if you set bits 1:0 (DMA transfer type) to the "reserved" 11 value: * * ESS 688 (Sharp laptop) Nothing, apparently. Treated the same as 4 bytes/request * * ESS 1887 (Compaq Presario) Triggers a hardware bug where the chip appears to fetch * 3 bytes per demand transfer but then only handle 1 byte, * which translates to audio playing at 3x the sample rate * it should be. NOT because the DAC is running any faster, * but because the chip is only playing back every 3rd sample! * This play only 3rds behavior is consistent across 8/16-bit * PCM and mono/stereo. */ b = 2; /* demand transfer DMA 4 bytes per request */ sndsb_ess_write_controller(sb_card,0xB9,b); sndsb_ess_write_controller(sb_card,0xA1,count); /* effectively disable the lowpass filter (NTS: 0xFF mutes the audio, apparently) */ sndsb_ess_write_controller(sb_card,0xA2,0xFE); t16 = -(tlen * (uint16_t)bytespersample); /* DMA transfer count reload register value is 2's complement of length */ sndsb_ess_write_controller(sb_card,0xA4,t16); /* DMA transfer count low */ sndsb_ess_write_controller(sb_card,0xA5,t16>>8); /* DMA transfer count high */ b = sndsb_ess_read_controller(sb_card,0xB1); b &= ~0xA0; /* clear compat game IRQ, fifo half-empty IRQs */ b |= 0x50; /* set overflow IRQ, and "no function" */ sndsb_ess_write_controller(sb_card,0xB1,b); b = sndsb_ess_read_controller(sb_card,0xB2); b &= ~0xA0; /* clear compat */ b |= 0x50; /* set DRQ/DACKB inputs for DMA */ sndsb_ess_write_controller(sb_card,0xB2,b); b = 0x51; /* enable FIFO+DMA, reserved, load signal */ b |= wav_16bit ? 0x20 : 0x00; /* signed complement mode or not */ sndsb_ess_write_controller(sb_card,0xB7,b); b = 0x90; /* enable FIFO+DMA, reserved, load signal */ b |= wav_16bit ? 0x20 : 0x00; /* signed complement mode or not */ b |= 0x40; /* [3]=stereo [6]=!stereo */ b |= wav_16bit ? 0x04 : 0x00; /* [2]=16bit */ sndsb_ess_write_controller(sb_card,0xB7,b); b = sndsb_ess_read_controller(sb_card,0xB8); sndsb_ess_write_controller(sb_card,0xB8,b | 1); } _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { int b; b = sndsb_ess_read_controller(sb_card,0xB8); if (b != -1) { b &= ~0x01; /* stop DMA */ sndsb_ess_write_controller(sb_card,0xB8,b); } } { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - TC 0x%02lX: expecting %luHz, %lu%c/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,wav_16bit?'w':'b',t,rate); } if (kbhit()) { if (getch() == 27) break; } continue; x_timeout: d = d8237_read_count(sb_card->dma8) / (unsigned long)bytespersample; /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_reset_dsp(sb_card); }