diff options
Diffstat (limited to 'src/mame/audio/jaguar.c')
-rw-r--r-- | src/mame/audio/jaguar.c | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/src/mame/audio/jaguar.c b/src/mame/audio/jaguar.c new file mode 100644 index 00000000000..a9ae49e29a6 --- /dev/null +++ b/src/mame/audio/jaguar.c @@ -0,0 +1,475 @@ +/*************************************************************************** + + Atari Jaguar hardware + +**************************************************************************** + + ------------------------------------------------------------ + JERRY REGISTERS + ------------------------------------------------------------ + F10000-F13FFF R/W xxxxxxxx xxxxxxxx Jerry + F10000 W xxxxxxxx xxxxxxxx JPIT1 - timer 1 pre-scaler + F10004 W xxxxxxxx xxxxxxxx JPIT2 - timer 1 divider + F10008 W xxxxxxxx xxxxxxxx JPIT3 - timer 2 pre-scaler + F1000C W xxxxxxxx xxxxxxxx JPIT4 - timer 2 divider + F10010 W ------xx xxxxxxxx CLK1 - processor clock divider + F10012 W ------xx xxxxxxxx CLK2 - video clock divider + F10014 W -------- --xxxxxx CLK3 - chroma clock divider + F10020 R/W ---xxxxx ---xxxxx JINTCTRL - interrupt control register + W ---x---- -------- (J_SYNCLR - clear synchronous serial intf ints) + W ----x--- -------- (J_ASYNCLR - clear asynchronous serial intf ints) + W -----x-- -------- (J_TIM2CLR - clear timer 2 [tempo] interrupts) + W ------x- -------- (J_TIM1CLR - clear timer 1 [sample] interrupts) + W -------x -------- (J_EXTCLR - clear external interrupts) + R/W -------- ---x---- (J_SYNENA - enable synchronous serial intf ints) + R/W -------- ----x--- (J_ASYNENA - enable asynchronous serial intf ints) + R/W -------- -----x-- (J_TIM2ENA - enable timer 2 [tempo] interrupts) + R/W -------- ------x- (J_TIM1ENA - enable timer 1 [sample] interrupts) + R/W -------- -------x (J_EXTENA - enable external interrupts) + F10030 R/W -------- xxxxxxxx ASIDATA - asynchronous serial data + F10032 W -x------ -xxxxxxx ASICTRL - asynchronous serial control + W -x------ -------- (TXBRK - transmit break) + W -------- -x------ (CLRERR - clear error) + W -------- --x----- (RINTEN - enable receiver interrupts) + W -------- ---x---- (TINTEN - enable transmitter interrupts) + W -------- ----x--- (RXIPOL - receiver input polarity) + W -------- -----x-- (TXOPOL - transmitter output polarity) + W -------- ------x- (PAREN - parity enable) + W -------- -------x (ODD - odd parity select) + F10032 R xxx-xxxx x-xxxxxx ASISTAT - asynchronous serial status + R x------- -------- (ERROR - OR of PE,FE,OE) + R -x------ -------- (TXBRK - transmit break) + R --x----- -------- (SERIN - serial input) + R ----x--- -------- (OE - overrun error) + R -----x-- -------- (FE - framing error) + R ------x- -------- (PE - parity error) + R -------x -------- (TBE - transmit buffer empty) + R -------- x------- (RBF - receive buffer full) + R -------- ---x---- (TINTEN - enable transmitter interrupts) + R -------- ----x--- (RXIPOL - receiver input polarity) + R -------- -----x-- (TXOPOL - transmitter output polarity) + R -------- ------x- (PAREN - parity enable) + R -------- -------x (ODD - odd parity) + F10034 R/W xxxxxxxx xxxxxxxx ASICLK - asynchronous serial interface clock + ------------------------------------------------------------ + F14000-F17FFF R/W xxxxxxxx xxxxxxxx Joysticks and GPIO0-5 + F14000 R xxxxxxxx xxxxxxxx JOYSTICK - read joystick state + F14000 W x------- xxxxxxxx JOYSTICK - latch joystick output + W x------- -------- (enable joystick outputs) + W -------- xxxxxxxx (joystick output data) + F14002 R xxxxxxxx xxxxxxxx JOYBUTS - button register + F14800-F14FFF R/W xxxxxxxx xxxxxxxx GPI00 - reserved + F15000-F15FFF R/W xxxxxxxx xxxxxxxx GPI01 - reserved + F16000-F16FFF R/W xxxxxxxx xxxxxxxx GPI02 - reserved + F17000-F177FF R/W xxxxxxxx xxxxxxxx GPI03 - reserved + F17800-F17BFF R/W xxxxxxxx xxxxxxxx GPI04 - reserved + F17C00-F17FFF R/W xxxxxxxx xxxxxxxx GPI05 - reserved + ------------------------------------------------------------ + F18000-F1FFFF R/W xxxxxxxx xxxxxxxx Jerry DSP + F1A100 R/W xxxxxxxx xxxxxxxx D_FLAGS - DSP flags register + R/W x------- -------- (DMAEN - DMA enable) + R/W -x------ -------- (REGPAGE - register page) + W --x----- -------- (D_EXT0CLR - clear external interrupt 0) + W ---x---- -------- (D_TIM2CLR - clear timer 2 interrupt) + W ----x--- -------- (D_TIM1CLR - clear timer 1 interrupt) + W -----x-- -------- (D_I2SCLR - clear I2S interrupt) + W ------x- -------- (D_CPUCLR - clear CPU interrupt) + R/W -------x -------- (D_EXT0ENA - enable external interrupt 0) + R/W -------- x------- (D_TIM2ENA - enable timer 2 interrupt) + R/W -------- -x------ (D_TIM1ENA - enable timer 1 interrupt) + R/W -------- --x----- (D_I2SENA - enable I2S interrupt) + R/W -------- ---x---- (D_CPUENA - enable CPU interrupt) + R/W -------- ----x--- (IMASK - interrupt mask) + R/W -------- -----x-- (NEGA_FLAG - ALU negative) + R/W -------- ------x- (CARRY_FLAG - ALU carry) + R/W -------- -------x (ZERO_FLAG - ALU zero) + F1A102 R/W -------- ------xx D_FLAGS - upper DSP flags + R/W -------- ------x- (D_EXT1ENA - enable external interrupt 1) + R/W -------- -------x (D_EXT1CLR - clear external interrupt 1) + F1A104 W -------- ----xxxx D_MTXC - matrix control register + W -------- ----x--- (MATCOL - column/row major) + W -------- -----xxx (MATRIX3-15 - matrix width) + F1A108 W ----xxxx xxxxxx-- D_MTXA - matrix address register + F1A10C W -------- -----x-x D_END - data organization register + W -------- -----x-- (BIG_INST - big endian instruction fetch) + W -------- -------x (BIG_IO - big endian I/O) + F1A110 R/W xxxxxxxx xxxxxxxx D_PC - DSP program counter + F1A114 R/W xxxxxxxx xx-xxxxx D_CTRL - DSP control/status register + R xxxx---- -------- (VERSION - DSP version code) + R/W ----x--- -------- (BUS_HOG - hog the bus!) + R/W -----x-- -------- (D_EXT0LAT - external interrupt 0 latch) + R/W ------x- -------- (D_TIM2LAT - timer 2 interrupt latch) + R/W -------x -------- (D_TIM1LAT - timer 1 interrupt latch) + R/W -------- x------- (D_I2SLAT - I2S interrupt latch) + R/W -------- -x------ (D_CPULAT - CPU interrupt latch) + R/W -------- ---x---- (SINGLE_GO - single step one instruction) + R/W -------- ----x--- (SINGLE_STEP - single step mode) + R/W -------- -----x-- (FORCEINT0 - cause interrupt 0 on GPU) + R/W -------- ------x- (CPUINT - send GPU interrupt to CPU) + R/W -------- -------x (DSPGO - enable DSP execution) + F1A116 R/W -------- -------x D_CTRL - upper DSP control/status register + R/W -------- -------x (D_EXT1LAT - external interrupt 1 latch) + F1A118-F1A11B W xxxxxxxx xxxxxxxx D_MOD - modulo instruction mask + F1A11C-F1A11F R xxxxxxxx xxxxxxxx D_REMAIN - divide unit remainder + F1A11C W -------- -------x D_DIVCTRL - divide unit control + W -------- -------x (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide) + F1A120-F1A123 R xxxxxxxx xxxxxxxx D_MACHI - multiply & accumulate high bits + F1A148 W xxxxxxxx xxxxxxxx R_DAC - right transmit data + F1A14C W xxxxxxxx xxxxxxxx L_DAC - left transmit data + F1A150 W -------- xxxxxxxx SCLK - serial clock frequency + F1A150 R -------- ------xx SSTAT + R -------- ------x- (left - no description) + R -------- -------x (WS - word strobe status) + F1A154 W -------- --xxxx-x SMODE - serial mode + W -------- --x----- (EVERYWORD - interrupt on MSB of every word) + W -------- ---x---- (FALLING - interrupt on falling edge) + W -------- ----x--- (RISING - interrupt of rising edge) + W -------- -----x-- (WSEN - enable word strobes) + W -------- -------x (INTERNAL - enables serial clock) + ------------------------------------------------------------ + F1B000-F1CFFF R/W xxxxxxxx xxxxxxxx Local DSP RAM + ------------------------------------------------------------ + F1D000 R xxxxxxxx xxxxxxxx ROM_TRI - triangle wave + F1D200 R xxxxxxxx xxxxxxxx ROM_SINE - full sine wave + F1D400 R xxxxxxxx xxxxxxxx ROM_AMSINE - amplitude modulated sine wave + F1D600 R xxxxxxxx xxxxxxxx ROM_12W - sine wave and second order harmonic + F1D800 R xxxxxxxx xxxxxxxx ROM_CHIRP16 - chirp + F1DA00 R xxxxxxxx xxxxxxxx ROM_NTRI - traingle wave with noise + F1DC00 R xxxxxxxx xxxxxxxx ROM_DELTA - spike + F1DE00 R xxxxxxxx xxxxxxxx ROM_NOISE - white noise + ------------------------------------------------------------ + F20000-FFFFFF R xxxxxxxx xxxxxxxx Bootstrap ROM + +****************************************************************************/ + +#include "driver.h" +#include "includes/jaguar.h" +#include "cpu/jaguar/jaguar.h" +#include "sound/dac.h" +#include <math.h> + + +/* Jerry registers */ +enum +{ + JPIT1, DSP0, JPIT2, DSP1, + JPIT3, DSP2, JPIT4, DSP3, + CLK1, CLK2, CLK3, + JINTCTRL = 0x20/2, + ASIDATA = 0x30/2, ASICTRL, ASICLK, + DSP_REGS +}; + + + +/* DSP variables */ +static UINT16 dsp_regs[DSP_REGS]; + +static UINT16 serial_frequency; +static emu_timer *serial_timer; + +static UINT8 gpu_irq_state; + +#if ENABLE_SPEEDUP_HACKS + +static TIMER_CALLBACK( serial_chunky_callback ); +static WRITE32_HANDLER( dsp_flags_w ); + +#else + +static TIMER_CALLBACK( serial_callback ); + +#endif + + + +/************************************* + * + * DSP optimization control + * + *************************************/ + +void jaguar_dsp_suspend(void) +{ + cpunum_suspend(2, SUSPEND_REASON_SPIN, 1); +} + + +void jaguar_dsp_resume(void) +{ + cpunum_resume(2, SUSPEND_REASON_SPIN); +} + + + +/************************************* + * + * Jerry -> GPU interrupts + * + *************************************/ + +static void update_gpu_irq(void) +{ + if (gpu_irq_state & dsp_regs[JINTCTRL] & 0x1f) + { + cpunum_set_input_line(1, 1, ASSERT_LINE); + jaguar_gpu_resume(); + } + else + cpunum_set_input_line(1, 1, CLEAR_LINE); +} + + +void jaguar_external_int(int state) +{ + if (state != CLEAR_LINE) + gpu_irq_state |= 1; + else + gpu_irq_state &= ~1; + update_gpu_irq(); +} + + + +/************************************* + * + * Sound initialization + * + *************************************/ + +void cojag_sound_init(void) +{ + int i; + + /* fill the wave ROM -- these are pretty cheesy guesses */ + for (i = 0; i < 0x80; i++) + { + /* F1D000 = triangle wave */ + jaguar_wave_rom[0x000 + i] = ((i <= 0x40) ? i : 0x80 - i) * 32767 / 0x40; + + /* F1D200 = full sine wave */ + jaguar_wave_rom[0x080 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80)); + + /* F1D400 = amplitude modulated sine wave? */ + jaguar_wave_rom[0x100 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80)); + + /* F1D600 = sine wave and second order harmonic */ + jaguar_wave_rom[0x180 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80)); + + /* F1D800 = chirp (sine wave of increasing frequency) */ + jaguar_wave_rom[0x200 + i] = (int)(32767. * sin(2.0 * M_PI * (double)i / (double)0x80)); + + /* F1DA00 = traingle wave with noise */ + jaguar_wave_rom[0x280 + i] = jaguar_wave_rom[0x000 + i] * (mame_rand(Machine) % 32768) / 32768; + + /* F1DC00 = spike */ + jaguar_wave_rom[0x300 + i] = (i == 0x40) ? 32767 : 0; + + /* F1DE00 = white noise */ + jaguar_wave_rom[0x380 + i] = mame_rand(Machine) % 32768; + } + +#if ENABLE_SPEEDUP_HACKS + memory_install_write32_handler(2, ADDRESS_SPACE_PROGRAM, 0xf1a100, 0xf1a103, 0, 0, dsp_flags_w); +#endif +} + + + +/************************************* + * + * Sound reset + * + *************************************/ + +void cojag_sound_reset(void) +{ +#if ENABLE_SPEEDUP_HACKS + serial_timer = timer_alloc(serial_chunky_callback); +#else + serial_timer = timer_alloc(serial_callback); +#endif +} + + + +/************************************* + * + * Jerry 16-bit register access + * + *************************************/ + +READ16_HANDLER( jaguar_jerry_regs_r ) +{ + if (offset != JINTCTRL && offset != JINTCTRL+2) + logerror("%08X:jerry read register @ F10%03X\n", activecpu_get_previouspc(), offset * 2); + + switch (offset) + { + case JINTCTRL: + return gpu_irq_state; + } + + return dsp_regs[offset]; +} + + +WRITE16_HANDLER( jaguar_jerry_regs_w ) +{ + COMBINE_DATA(&dsp_regs[offset]); + + switch (offset) + { + case JINTCTRL: + gpu_irq_state &= ~(dsp_regs[JINTCTRL] >> 8); + update_gpu_irq(); + break; + } + + if (offset != JINTCTRL && offset != JINTCTRL+2 && offset != ASICTRL) + logerror("%08X:jerry write register @ F10%03X = %04X\n", activecpu_get_previouspc(), offset * 2, data); +} + + + +/************************************* + * + * Jerry 32-bit register access + * + *************************************/ + +READ32_HANDLER( jaguar_jerry_regs32_r ) +{ + return (jaguar_jerry_regs_r(offset * 2, 0) << 16) | jaguar_jerry_regs_r(offset * 2 + 1, 0); +} + + +WRITE32_HANDLER( jaguar_jerry_regs32_w ) +{ + if (ACCESSING_MSW32) + jaguar_jerry_regs_w(offset * 2, data >> 16, mem_mask >> 16); + if (ACCESSING_LSW32) + jaguar_jerry_regs_w(offset * 2 + 1, data, mem_mask); +} + + + +/************************************* + * + * Speedier sound hack + * + *************************************/ + +#if ENABLE_SPEEDUP_HACKS + +static WRITE32_HANDLER( dsp_flags_w ) +{ + /* write the data through */ + jaguardsp_ctrl_w(2, offset, data, mem_mask); + + /* if they were clearing the A2S interrupt, see if we are headed for the spin */ + /* loop with R22 != 0; if we are, just start spinning again */ + if (cpu_getactivecpu() == 2 && !(mem_mask & 0x0000ff00) && (data & 0x400)) + { + /* see if we're going back to the spin loop */ + if (!(data & 0x04000) && activecpu_get_reg(JAGUAR_R22) != 0) + { + UINT32 r30 = activecpu_get_reg(JAGUAR_R30) & 0xffffff; + if (r30 >= 0xf1b124 && r30 <= 0xf1b126) + jaguar_dsp_suspend(); + } + } +} + +#endif + + + +/************************************* + * + * Serial port interrupt generation + * + *************************************/ + +#if ENABLE_SPEEDUP_HACKS + +static TIMER_CALLBACK( serial_chunky_callback ) +{ + /* assert the A2S IRQ on CPU #2 (DSP) */ + cpunum_set_input_line(2, 1, ASSERT_LINE); + jaguar_dsp_resume(); + + /* fix flaky code in interrupt handler which thwarts our speedup */ + if ((jaguar_dsp_ram[0x3e/4] & 0xffff) == 0xbfbc && + (jaguar_dsp_ram[0x42/4] & 0xffff) == 0xe400) + { + /* move the store r28,(r29) into the branch delay slot, swapping it with */ + /* the nop that's currently there */ + jaguar_dsp_ram[0x3e/4] = (jaguar_dsp_ram[0x3e/4] & 0xffff0000) | 0xe400; + jaguar_dsp_ram[0x42/4] = (jaguar_dsp_ram[0x42/4] & 0xffff0000) | 0xbfbc; + } +} + +#else + +static TIMER_CALLBACK( serial_callback ) +{ + /* assert the A2S IRQ on CPU #2 (DSP) */ + cpunum_set_input_line(2, 1, ASSERT_LINE); + jaguar_dsp_resume(); +} + +#endif + + + +/************************************* + * + * Serial port handlers + * + *************************************/ + +READ32_HANDLER( jaguar_serial_r ) +{ + logerror("%08X:jaguar_serial_r(%X)\n", activecpu_get_previouspc(), offset); + return 0; +} + + +WRITE32_HANDLER( jaguar_serial_w ) +{ + switch (offset) + { + /* right DAC */ + case 2: + DAC_signed_data_16_w(1, (data & 0xffff) ^ 0x8000); + break; + + /* left DAC */ + case 3: + DAC_signed_data_16_w(0, (data & 0xffff) ^ 0x8000); + break; + + /* frequency register */ + case 4: + serial_frequency = data & 0xffff; + break; + + /* control register -- only very specific modes supported */ + case 5: + if ((data & 0x3f) != 0x15) + logerror("Unexpected write to SMODE = %X\n", data); + if ((data & 0x3f) == 0x15) + { + attotime rate = attotime_mul(ATTOTIME_IN_HZ(26000000), 32 * 2 * (serial_frequency + 1)); + timer_adjust(serial_timer, rate, 0, rate); + } + break; + + default: + logerror("%08X:jaguar_serial_w(%X,%X)\n", activecpu_get_previouspc(), offset, data); + break; + } +} + + |