diff options
Diffstat (limited to 'src/mame/machine/harddriv.c')
-rw-r--r-- | src/mame/machine/harddriv.c | 1941 |
1 files changed, 1941 insertions, 0 deletions
diff --git a/src/mame/machine/harddriv.c b/src/mame/machine/harddriv.c new file mode 100644 index 00000000000..76d4b3b8dbc --- /dev/null +++ b/src/mame/machine/harddriv.c @@ -0,0 +1,1941 @@ +/*************************************************************************** + + Hard Drivin' machine hardware + +****************************************************************************/ + +#include "driver.h" +#include "cpu/tms34010/tms34010.h" +#include "cpu/tms34010/34010ops.h" +#include "cpu/adsp2100/adsp2100.h" +#include "cpu/m68000/m68000.h" +#include "cpu/dsp32/dsp32.h" +#include "machine/atarigen.h" +#include "machine/asic65.h" +#include "audio/atarijsa.h" +#include "harddriv.h" + + +/************************************* + * + * Constants and macros + * + *************************************/ + +#define DUART_CLOCK (36864000) +#define DS3_TRIGGER 7777 + +/* debugging tools */ +#define LOG_COMMANDS 0 + + + +/************************************* + * + * External definitions + * + *************************************/ + +/* externally accessible */ +INT8 hdcpu_main; +INT8 hdcpu_gsp; +INT8 hdcpu_msp; +INT8 hdcpu_adsp; +INT8 hdcpu_sound; +INT8 hdcpu_sounddsp; +INT8 hdcpu_jsa; +INT8 hdcpu_dsp32; + +UINT8 hd34010_host_access; +UINT8 hddsk_pio_access; + +UINT16 *hdmsp_ram; +UINT16 *hddsk_ram; +UINT16 *hddsk_rom; +UINT16 *hddsk_zram; +UINT16 *hd68k_slapstic_base; +UINT16 *st68k_sloop_alt_base; + +UINT16 *hdadsp_data_memory; +UINT32 *hdadsp_pgm_memory; + +UINT16 *hdgsp_protection; +UINT16 *stmsp_sync[3]; + +UINT16 *hdgsp_speedup_addr[2]; +offs_t hdgsp_speedup_pc; + +UINT16 *hdmsp_speedup_addr; +offs_t hdmsp_speedup_pc; + +UINT16 *hdds3_speedup_addr; +offs_t hdds3_speedup_pc; +offs_t hdds3_transfer_pc; + +UINT32 *rddsp32_sync[2]; + +UINT32 gsp_speedup_count[4]; +UINT32 msp_speedup_count[4]; +UINT32 adsp_speedup_count[4]; + + +/* from slapstic.c */ +int slapstic_tweak(offs_t offset); +void slapstic_reset(void); + + +/* from video */ +extern UINT8 *hdgsp_vram; + + + +/************************************* + * + * Static globals + * + *************************************/ + +static UINT8 irq_state; +static UINT8 gsp_irq_state; +static UINT8 msp_irq_state; +static UINT8 adsp_irq_state; +static UINT8 duart_irq_state; + +static UINT8 duart_read_data[16]; +static UINT8 duart_write_data[16]; +static UINT8 duart_output_port; +static emu_timer *duart_timer; + +static UINT8 last_gsp_shiftreg; + +static UINT8 m68k_zp1, m68k_zp2; +static UINT8 m68k_adsp_buffer_bank; + +static UINT8 adsp_halt, adsp_br; +static UINT8 adsp_xflag; + +static UINT16 adsp_sim_address; +static UINT16 adsp_som_address; +static UINT32 adsp_eprom_base; + +static UINT16 *sim_memory; +static UINT16 *som_memory; +static UINT32 sim_memory_size; +static UINT16 *adsp_pgm_memory_word; + +static UINT8 ds3_gcmd, ds3_gflag, ds3_g68irqs, ds3_gfirqs, ds3_g68flag, ds3_send, ds3_reset; +static UINT16 ds3_gdata, ds3_g68data; +static UINT32 ds3_sim_address; + +static UINT16 adc_control; +static UINT8 adc8_select; +static UINT8 adc8_data; +static UINT8 adc12_select; +static UINT8 adc12_byte; +static UINT16 adc12_data; + +static UINT16 hdc68k_last_wheel; +static UINT16 hdc68k_last_port1; +static UINT8 hdc68k_wheel_edge; +static UINT8 hdc68k_shifter_state; + +static UINT8 st68k_sloop_bank = 0; +static offs_t st68k_last_alt_sloop_offset; + +#define MAX_MSP_SYNC 16 +static UINT32 *dataptr[MAX_MSP_SYNC]; +static UINT32 dataval[MAX_MSP_SYNC]; +static int next_msp_sync; + +static void hd68k_update_interrupts(void); +static TIMER_CALLBACK( duart_callback ); + + + +#if 0 +#pragma mark * DRIVER/MULTISYNC BOARD +#endif + + +/************************************* + * + * Initialization + * + *************************************/ + +MACHINE_START( harddriv ) +{ + /* predetermine memory regions */ + sim_memory = (UINT16 *)memory_region(REGION_USER1); + som_memory = (UINT16 *)auto_malloc(0x8000); + sim_memory_size = memory_region_length(REGION_USER1) / 2; + adsp_pgm_memory_word = (UINT16 *)((UINT8 *)hdadsp_pgm_memory + 1); +} + + +MACHINE_RESET( harddriv ) +{ + /* generic reset */ + atarigen_eeprom_reset(); + slapstic_reset(); + atarigen_interrupt_reset(hd68k_update_interrupts); + + /* halt several of the DSPs to start */ + if (hdcpu_adsp != -1) cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, ASSERT_LINE); + if (hdcpu_dsp32 != -1) cpunum_set_input_line(hdcpu_dsp32, INPUT_LINE_HALT, ASSERT_LINE); + if (hdcpu_sounddsp != -1) cpunum_set_input_line(hdcpu_sounddsp, INPUT_LINE_HALT, ASSERT_LINE); + + /* if we found a 6502, reset the JSA board */ + if (hdcpu_jsa != -1) + atarijsa_reset(); + + last_gsp_shiftreg = 0; + + m68k_adsp_buffer_bank = 0; + + /* reset IRQ states */ + irq_state = gsp_irq_state = msp_irq_state = adsp_irq_state = duart_irq_state = 0; + + /* reset the DUART */ + memset(duart_read_data, 0, sizeof(duart_read_data)); + memset(duart_write_data, 0, sizeof(duart_write_data)); + duart_output_port = 0; + duart_timer = timer_alloc(duart_callback); + + /* reset the ADSP/DSIII/DSIV boards */ + adsp_halt = 1; + adsp_br = 0; + adsp_xflag = 0; +} + + + +/************************************* + * + * 68000 interrupt handling + * + *************************************/ + +static void hd68k_update_interrupts(void) +{ + int newstate = 0; + + if (msp_irq_state) + newstate = 1; + if (adsp_irq_state) + newstate = 2; + if (gsp_irq_state) + newstate = 3; + if (atarigen_sound_int_state) /* /LINKIRQ on STUN Runner */ + newstate = 4; + if (irq_state) + newstate = 5; + if (duart_irq_state) + newstate = 6; + + if (newstate) + cpunum_set_input_line(hdcpu_main, newstate, ASSERT_LINE); + else + cpunum_set_input_line(hdcpu_main, 7, CLEAR_LINE); +} + + +INTERRUPT_GEN( hd68k_irq_gen ) +{ + irq_state = 1; + atarigen_update_interrupts(); +} + + +WRITE16_HANDLER( hd68k_irq_ack_w ) +{ + irq_state = 0; + atarigen_update_interrupts(); +} + + +void hdgsp_irq_gen(int state) +{ + gsp_irq_state = state; + atarigen_update_interrupts(); +} + + +void hdmsp_irq_gen(int state) +{ + msp_irq_state = state; + atarigen_update_interrupts(); +} + + + +/************************************* + * + * 68000 access to GSP + * + *************************************/ + +READ16_HANDLER( hd68k_gsp_io_r ) +{ + UINT16 result; + offset = (offset / 2) ^ 1; + hd34010_host_access = 1; + result = tms34010_host_r(hdcpu_gsp, offset); + hd34010_host_access = 0; + return result; +} + + +WRITE16_HANDLER( hd68k_gsp_io_w ) +{ + offset = (offset / 2) ^ 1; + hd34010_host_access = 1; + tms34010_host_w(hdcpu_gsp, offset, data); + hd34010_host_access = 0; +} + + + +/************************************* + * + * 68000 access to MSP + * + *************************************/ + +READ16_HANDLER( hd68k_msp_io_r ) +{ + UINT16 result; + offset = (offset / 2) ^ 1; + hd34010_host_access = 1; + result = (hdcpu_msp != -1) ? tms34010_host_r(hdcpu_msp, offset) : 0xffff; + hd34010_host_access = 0; + return result; +} + + +WRITE16_HANDLER( hd68k_msp_io_w ) +{ + offset = (offset / 2) ^ 1; + if (hdcpu_msp != -1) + { + hd34010_host_access = 1; + tms34010_host_w(hdcpu_msp, offset, data); + hd34010_host_access = 0; + } +} + + + +/************************************* + * + * 68000 input handlers + * + *************************************/ + +READ16_HANDLER( hd68k_port0_r ) +{ + /* port is as follows: + + 0x0001 = DIAGN + 0x0002 = /HSYNCB + 0x0004 = /VSYNCB + 0x0008 = EOC12 + 0x0010 = EOC8 + 0x0020 = SELF-TEST + 0x0040 = COIN2 + 0x0080 = COIN1 + 0x0100 = SW1 #8 + 0x0200 = SW1 #7 + ..... + 0x8000 = SW1 #1 + */ + int temp = readinputport(0); + if (atarigen_get_hblank(Machine, 0)) temp ^= 0x0002; + temp ^= 0x0018; /* both EOCs always high for now */ + return temp; +} + + +READ16_HANDLER( hdc68k_port1_r ) +{ + UINT16 result = readinputport(1); + UINT16 diff = result ^ hdc68k_last_port1; + + /* if a new shifter position is selected, use it */ + /* if it's the same shifter position as last time, go back to neutral */ + if ((diff & 0x0100) && !(result & 0x0100)) + hdc68k_shifter_state = (hdc68k_shifter_state == 1) ? 0 : 1; + if ((diff & 0x0200) && !(result & 0x0200)) + hdc68k_shifter_state = (hdc68k_shifter_state == 2) ? 0 : 2; + if ((diff & 0x0400) && !(result & 0x0400)) + hdc68k_shifter_state = (hdc68k_shifter_state == 4) ? 0 : 4; + if ((diff & 0x0800) && !(result & 0x0800)) + hdc68k_shifter_state = (hdc68k_shifter_state == 8) ? 0 : 8; + + /* merge in the new shifter value */ + result = (result | 0x0f00) ^ (hdc68k_shifter_state << 8); + + /* merge in the wheel edge latch bit */ + if (hdc68k_wheel_edge) + result ^= 0x4000; + + hdc68k_last_port1 = result; + return result; +} + + +READ16_HANDLER( hda68k_port1_r ) +{ + UINT16 result = readinputport(1); + + /* merge in the wheel edge latch bit */ + if (hdc68k_wheel_edge) + result ^= 0x4000; + + return result; +} + + +READ16_HANDLER( hdc68k_wheel_r ) +{ + /* grab the new wheel value and upconvert to 12 bits */ + UINT16 new_wheel = readinputport(10) << 4; + + /* hack to display the wheel position */ + if (input_code_pressed(KEYCODE_LSHIFT)) + popmessage("%04X", new_wheel); + + /* if we crossed the center line, latch the edge bit */ + if ((hdc68k_last_wheel / 0xf0) != (new_wheel / 0xf0)) + hdc68k_wheel_edge = 1; + + /* remember the last value and return the low 8 bits */ + hdc68k_last_wheel = new_wheel; + return (new_wheel << 8) | 0xff; +} + + +READ16_HANDLER( hd68k_adc8_r ) +{ + return adc8_data; +} + + +READ16_HANDLER( hd68k_adc12_r ) +{ + return adc12_byte ? ((adc12_data >> 8) & 0x0f) : (adc12_data & 0xff); +} + + +READ16_HANDLER( hd68k_sound_reset_r ) +{ + if (hdcpu_jsa != -1) + atarijsa_reset(); + return ~0; +} + + + +/************************************* + * + * 68000 output handlers + * + *************************************/ + +WRITE16_HANDLER( hd68k_adc_control_w ) +{ + COMBINE_DATA(&adc_control); + + /* handle a write to the 8-bit ADC address select */ + if (adc_control & 0x08) + { + adc8_select = adc_control & 0x07; + adc8_data = readinputport(2 + adc8_select); + } + + /* handle a write to the 12-bit ADC address select */ + if (adc_control & 0x40) + { + adc12_select = (adc_control >> 4) & 0x03; + adc12_data = readinputport(10 + adc12_select) << 4; + } + + /* bit 7 selects which byte of the 12 bit data to read */ + adc12_byte = (adc_control >> 7) & 1; +} + + +WRITE16_HANDLER( hd68k_wr0_write ) +{ + /* bit 3 selects the value; data is ignored */ + data = (offset >> 3) & 1; + + /* low 3 bits select the function */ + offset &= 7; + switch (offset) + { + case 1: /* SEL1 */ + case 2: /* SEL2 */ + case 3: /* SEL3 */ + case 4: /* SEL4 */ + default: + /* just ignore */ + break; + + case 6: /* CC1 */ + case 7: /* CC2 */ + coin_counter_w(offset - 6, data); + break; + } +} + + +WRITE16_HANDLER( hd68k_wr1_write ) +{ + if (offset == 0) { // logerror("Shifter Interface Latch = %02X\n", data); + } else { logerror("/WR1(%04X)=%02X\n", offset, data); + } +} + + +WRITE16_HANDLER( hd68k_wr2_write ) +{ + if (offset == 0) { // logerror("Steering Wheel Latch = %02X\n", data); + } else { logerror("/WR2(%04X)=%02X\n", offset, data); + } +} + + +WRITE16_HANDLER( hd68k_nwr_w ) +{ + /* bit 3 selects the value; data is ignored */ + data = (offset >> 3) & 1; + + /* low 3 bits select the function */ + offset &= 7; + switch (offset) + { + case 0: /* CR2 */ + case 1: /* CR1 */ + set_led_status(offset, data); + break; + case 2: /* LC1 */ + break; + case 3: /* LC2 */ + break; + case 4: /* ZP1 */ + m68k_zp1 = data; + break; + case 5: /* ZP2 */ + m68k_zp2 = data; + break; + case 6: /* /GSPRES */ + logerror("Write to /GSPRES(%d)\n", data); + if (hdcpu_gsp != -1) + cpunum_set_input_line(hdcpu_gsp, INPUT_LINE_RESET, data ? CLEAR_LINE : ASSERT_LINE); + break; + case 7: /* /MSPRES */ + logerror("Write to /MSPRES(%d)\n", data); + if (hdcpu_msp != -1) + cpunum_set_input_line(hdcpu_msp, INPUT_LINE_RESET, data ? CLEAR_LINE : ASSERT_LINE); + break; + } +} + + +WRITE16_HANDLER( hdc68k_wheel_edge_reset_w ) +{ + /* reset the edge latch */ + hdc68k_wheel_edge = 0; +} + + + +/************************************* + * + * 68000 ZRAM access + * + *************************************/ + +READ16_HANDLER( hd68k_zram_r ) +{ + return atarigen_eeprom[offset]; +} + + +WRITE16_HANDLER( hd68k_zram_w ) +{ + if (m68k_zp1 == 0 && m68k_zp2 == 1) + COMBINE_DATA(&atarigen_eeprom[offset]); +} + + + +/************************************* + * + * 68000 DUART interface + * + *************************************/ + +/* + DUART registers + + Read Write + ---------------------------------- ------------------------------------------- + 0x00 = Mode Register A (MR1A, MR2A) Mode Register A (MR1A, MR2A) + 0x02 = Status Register A (SRA) Clock-Select Register A (CSRA) + 0x04 = Clock-Select Register A 1 (CSRA) Command Register A (CRA) + 0x06 = Receiver Buffer A (RBA) Transmitter Buffer A (TBA) + 0x08 = Input Port Change Register (IPCR) Auxiliary Control Register (ACR) + 0x0a = Interrupt Status Register (ISR) Interrupt Mask Register (IMR) + 0x0c = Counter Mode: Current MSB of Counter/Timer Upper Register (CTUR) + Counter (CUR) + 0x0e = Counter Mode: Current LSB of Counter/Timer Lower Register (CTLR) + Counter (CLR) + 0x10 = Mode Register B (MR1B, MR2B) Mode Register B (MR1B, MR2B) + 0x12 = Status Register B (SRB) Clock-Select Register B (CSRB) + 0x14 = Clock-Select Register B 2 (CSRB) Command Register B (CRB) + 0x16 = Receiver Buffer B (RBB) Transmitter Buffer B (TBB) + 0x18 = Interrupt-Vector Register (IVR) Interrupt-Vector Register (IVR) + 0x1a = Input Port (IP) Output Port Configuration Register (OPCR) + 0x1c = Start-Counter Command 3 Output Port Register (OPR): Bit Set Command 3 + 0x1e = Stop-Counter Command 3 Output Port Register (OPR): Bit Reset Command 3 +*/ + + +INLINE int duart_clock(void) +{ + int mode = (duart_write_data[0x04] >> 4) & 7; + if (mode != 3) + logerror("DUART: unsupported clock mode %d\n", mode); + return DUART_CLOCK / 16; +} + + +INLINE attotime duart_clock_period(void) +{ + return ATTOTIME_IN_HZ(duart_clock()); +} + + +static TIMER_CALLBACK( duart_callback ) +{ + logerror("DUART timer fired\n"); + if (duart_write_data[0x05] & 0x08) + { + logerror("DUART interrupt generated\n"); + duart_read_data[0x05] |= 0x08; + duart_irq_state = (duart_read_data[0x05] & duart_write_data[0x05]) != 0; + atarigen_update_interrupts(); + } + timer_adjust(duart_timer, attotime_mul(duart_clock_period(), 65536), 0, attotime_zero); +} + + +READ16_HANDLER( hd68k_duart_r ) +{ + switch (offset) + { + case 0x00: /* Mode Register A (MR1A, MR2A) */ + case 0x08: /* Mode Register B (MR1B, MR2B) */ + return (duart_write_data[0x00] << 8) | 0x00ff; + case 0x01: /* Status Register A (SRA) */ + case 0x02: /* Clock-Select Register A 1 (CSRA) */ + case 0x03: /* Receiver Buffer A (RBA) */ + case 0x04: /* Input Port Change Register (IPCR) */ + case 0x05: /* Interrupt Status Register (ISR) */ + case 0x06: /* Counter Mode: Current MSB of Counter (CUR) */ + case 0x07: /* Counter Mode: Current LSB of Counter (CLR) */ + case 0x09: /* Status Register B (SRB) */ + case 0x0a: /* Clock-Select Register B 2 (CSRB) */ + case 0x0b: /* Receiver Buffer B (RBB) */ + case 0x0c: /* Interrupt-Vector Register (IVR) */ + case 0x0d: /* Input Port (IP) */ + return (duart_read_data[offset] << 8) | 0x00ff; + case 0x0e: /* Start-Counter Command 3 */ + { + int reps = (duart_write_data[0x06] << 8) | duart_write_data[0x07]; + timer_adjust(duart_timer, attotime_mul(duart_clock_period(), reps), 0, attotime_zero); + logerror("DUART timer started (period=%f)\n", attotime_to_double(attotime_mul(duart_clock_period(), reps))); + return 0x00ff; + } + case 0x0f: /* Stop-Counter Command 3 */ + { + int reps = attotime_to_double(attotime_mul(timer_timeleft(duart_timer), duart_clock())); + timer_adjust(duart_timer, attotime_never, 0, attotime_zero); + duart_read_data[0x06] = reps >> 8; + duart_read_data[0x07] = reps & 0xff; + logerror("DUART timer stopped (final count=%04X)\n", reps); + } + duart_read_data[0x05] &= ~0x08; + duart_irq_state = (duart_read_data[0x05] & duart_write_data[0x05]) != 0; + atarigen_update_interrupts(); + return 0x00ff; + } + return 0x00ff; +} + + +WRITE16_HANDLER( hd68k_duart_w ) +{ + if (ACCESSING_MSB) + { + int newdata = (data >> 8) & 0xff; + duart_write_data[offset] = newdata; + + switch (offset) + { + case 0x00: /* Mode Register A (MR1A, MR2A) */ + case 0x01: /* Clock-Select Register A (CSRA) */ + case 0x02: /* Command Register A (CRA) */ + case 0x03: /* Transmitter Buffer A (TBA) */ + case 0x04: /* Auxiliary Control Register (ACR) */ + case 0x05: /* Interrupt Mask Register (IMR) */ + case 0x06: /* Counter/Timer Upper Register (CTUR) */ + case 0x07: /* Counter/Timer Lower Register (CTLR) */ + case 0x08: /* Mode Register B (MR1B, MR2B) */ + case 0x09: /* Clock-Select Register B (CSRB) */ + case 0x0a: /* Command Register B (CRB) */ + case 0x0b: /* Transmitter Buffer B (TBB) */ + case 0x0c: /* Interrupt-Vector Register (IVR) */ + case 0x0d: /* Output Port Configuration Register (OPCR) */ + break; + case 0x0e: /* Output Port Register (OPR): Bit Set Command 3 */ + duart_output_port |= newdata; + break; + case 0x0f: /* Output Port Register (OPR): Bit Reset Command 3 */ + duart_output_port &= ~newdata; + break; + } + logerror("DUART write %02X @ %02X\n", (data >> 8) & 0xff, offset); + } + else + logerror("Unexpected DUART write %02X @ %02X\n", data, offset); +} + + + +/************************************* + * + * GSP I/O register writes + * + *************************************/ + +WRITE16_HANDLER( hdgsp_io_w ) +{ + /* detect an enabling of the shift register and force yielding */ + if (offset == REG_DPYCTL) + { + UINT8 new_shiftreg = (data >> 11) & 1; + if (new_shiftreg != last_gsp_shiftreg) + { + last_gsp_shiftreg = new_shiftreg; + if (new_shiftreg) + cpu_yield(); + } + } + + /* detect changes to HEBLNK and HSBLNK and force an update before they change */ + if ((offset == REG_HEBLNK || offset == REG_HSBLNK) && data != tms34010_io_register_r(offset, 0)) + video_screen_update_partial(0, video_screen_get_vpos(0) - 1); + + tms34010_io_register_w(offset, data, mem_mask); +} + + + +/************************************* + * + * GSP protection workarounds + * + *************************************/ + +WRITE16_HANDLER( hdgsp_protection_w ) +{ + /* this memory address is incremented whenever a protection check fails */ + /* after it reaches a certain value, the GSP will randomly trash a */ + /* register; we just prevent it from ever going above 0 */ + *hdgsp_protection = 0; +} + + + +/************************************* + * + * MSP synchronization helpers + * + *************************************/ + +static TIMER_CALLBACK( stmsp_sync_update ) +{ + int which = param >> 28; + offs_t offset = (param >> 16) & 0xfff; + UINT16 data = param; + stmsp_sync[which][offset] = data; + cpu_triggerint(hdcpu_msp); +} + + +INLINE void stmsp_sync_w(int which, offs_t offset, UINT16 data, UINT16 mem_mask) +{ + UINT16 newdata = stmsp_sync[which][offset]; + COMBINE_DATA(&newdata); + + /* if being written from the 68000, synchronize on it */ + if (hd34010_host_access) + timer_call_after_resynch(newdata | (offset << 16) | (which << 28), stmsp_sync_update); + + /* otherwise, just update */ + else + stmsp_sync[which][offset] = newdata; +} + + +WRITE16_HANDLER( stmsp_sync0_w ) +{ + stmsp_sync_w(0, offset, data, mem_mask); +} + + +WRITE16_HANDLER( stmsp_sync1_w ) +{ + stmsp_sync_w(1, offset, data, mem_mask); +} + + +WRITE16_HANDLER( stmsp_sync2_w ) +{ + stmsp_sync_w(2, offset, data, mem_mask); +} + + + +#if 0 +#pragma mark - +#pragma mark * ADSP BOARD +#endif + +/************************************* + * + * 68000 access to ADSP program memory + * + *************************************/ + +READ16_HANDLER( hd68k_adsp_program_r ) +{ + UINT32 word = hdadsp_pgm_memory[offset/2]; + return (!(offset & 1)) ? (word >> 16) : (word & 0xffff); +} + + +WRITE16_HANDLER( hd68k_adsp_program_w ) +{ + UINT32 *base = &hdadsp_pgm_memory[offset/2]; + UINT32 oldword = *base; + UINT16 temp; + + if (!(offset & 1)) + { + temp = oldword >> 16; + COMBINE_DATA(&temp); + oldword = (oldword & 0x0000ffff) | (temp << 16); + } + else + { + temp = oldword & 0xffff; + COMBINE_DATA(&temp); + oldword = (oldword & 0xffff0000) | temp; + } + *base = oldword; +} + + + +/************************************* + * + * 68000 access to ADSP data memory + * + *************************************/ + +READ16_HANDLER( hd68k_adsp_data_r ) +{ + return hdadsp_data_memory[offset]; +} + + +WRITE16_HANDLER( hd68k_adsp_data_w ) +{ + COMBINE_DATA(&hdadsp_data_memory[offset]); + + /* any write to $1FFF is taken to be a trigger; synchronize the CPUs */ + if (offset == 0x1fff) + { + logerror("%06X:ADSP sync address written (%04X)\n", activecpu_get_previouspc(), data); + timer_call_after_resynch(0, 0); + cpu_triggerint(hdcpu_adsp); + } + else + logerror("%06X:ADSP W@%04X (%04X)\n", activecpu_get_previouspc(), offset, data); +} + + + +/************************************* + * + * 68000 access to ADSP output memory + * + *************************************/ + +READ16_HANDLER( hd68k_adsp_buffer_r ) +{ +/* logerror("hd68k_adsp_buffer_r(%04X)\n", offset);*/ + return som_memory[m68k_adsp_buffer_bank * 0x2000 + offset]; +} + + +WRITE16_HANDLER( hd68k_adsp_buffer_w ) +{ + COMBINE_DATA(&som_memory[m68k_adsp_buffer_bank * 0x2000 + offset]); +} + + + +/************************************* + * + * 68000 access to ADSP control regs + * + *************************************/ + +static TIMER_CALLBACK( deferred_adsp_bank_switch ) +{ +#if LOG_COMMANDS + if (m68k_adsp_buffer_bank != param && input_code_pressed(KEYCODE_L)) + { + static FILE *commands; + if (!commands) commands = fopen("commands.log", "w"); + if (commands) + { + INT16 *base = (INT16 *)&som_memory[param * 0x2000]; + INT16 *end = base + (UINT16)*base++; + INT16 *current = base; + INT16 *table = base + (UINT16)*current++; + + fprintf(commands, "\n---------------\n"); + + while ((current + 5) < table) + { + int offset = (int)(current - base); + int c1 = *current++; + int c2 = *current++; + int c3 = *current++; + int c4 = *current++; + fprintf(commands, "Cmd @ %04X = %04X %d-%d @ %d\n", offset, c1, c2, c3, c4); + while (current < table) + { + UINT32 rslope, lslope; + rslope = (UINT16)*current++, + rslope |= *current++ << 16; + if (rslope == 0xffffffff) + { + fprintf(commands, " (end)\n"); + break; + } + lslope = (UINT16)*current++, + lslope |= *current++ << 16; + fprintf(commands, " L=%08X R=%08X count=%d\n", + (int)lslope, (int)rslope, (int)*current++); + } + } + fprintf(commands, "\nTable:\n"); + current = table; + while (current < end) + fprintf(commands, " %04X\n", *current++); + } + } +#endif + m68k_adsp_buffer_bank = param; + logerror("ADSP bank = %d\n", param); +} + + +WRITE16_HANDLER( hd68k_adsp_control_w ) +{ + /* bit 3 selects the value; data is ignored */ + int val = (offset >> 3) & 1; + + /* low 3 bits select the function */ + offset &= 7; + switch (offset) + { + case 0: + case 1: + /* LEDs */ + break; + + case 3: + logerror("ADSP bank = %d (deferred)\n", val); + timer_call_after_resynch(val, deferred_adsp_bank_switch); + break; + + case 5: + /* connected to the /BR (bus request) line; this effectively halts */ + /* the ADSP at the next instruction boundary */ + adsp_br = !val; + logerror("ADSP /BR = %d\n", !adsp_br); + if (adsp_br || adsp_halt) + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, ASSERT_LINE); + else + { + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, CLEAR_LINE); + /* a yield in this case is not enough */ + /* we would need to increase the interleaving otherwise */ + /* note that this only affects the test mode */ + cpu_spin(); + } + break; + + case 6: + /* connected to the /HALT line; this effectively halts */ + /* the ADSP at the next instruction boundary */ + adsp_halt = !val; + logerror("ADSP /HALT = %d\n", !adsp_halt); + if (adsp_br || adsp_halt) + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, ASSERT_LINE); + else + { + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, CLEAR_LINE); + /* a yield in this case is not enough */ + /* we would need to increase the interleaving otherwise */ + /* note that this only affects the test mode */ + cpu_spin(); + } + break; + + case 7: + logerror("ADSP reset = %d\n", val); + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_RESET, val ? CLEAR_LINE : ASSERT_LINE); + cpu_yield(); + break; + + default: + logerror("ADSP control %02X = %04X\n", offset, data); + break; + } +} + + +WRITE16_HANDLER( hd68k_adsp_irq_clear_w ) +{ + logerror("%06X:68k clears ADSP interrupt\n", activecpu_get_previouspc()); + adsp_irq_state = 0; + atarigen_update_interrupts(); +} + + +READ16_HANDLER( hd68k_adsp_irq_state_r ) +{ + int result = 0xfffd; + if (adsp_xflag) result ^= 2; + if (adsp_irq_state) result ^= 1; + logerror("%06X:68k reads ADSP interrupt state = %04x\n", activecpu_get_previouspc(), result); + return result; +} + + + +/************************************* + * + * ADSP memory-mapped I/O + * + *************************************/ + +READ16_HANDLER( hdadsp_special_r ) +{ + switch (offset & 7) + { + case 0: /* /SIMBUF */ + if (adsp_eprom_base + adsp_sim_address < sim_memory_size) + return sim_memory[adsp_eprom_base + adsp_sim_address++]; + else + return 0xff; + + case 1: /* /SIMLD */ + break; + + case 2: /* /SOMO */ + break; + + case 3: /* /SOMLD */ + break; + + default: + logerror("%04X:hdadsp_special_r(%04X)\n", activecpu_get_previouspc(), offset); + break; + } + return 0; +} + + +WRITE16_HANDLER( hdadsp_special_w ) +{ + switch (offset & 7) + { + case 1: /* /SIMCLK */ + adsp_sim_address = data; + break; + + case 2: /* SOMLATCH */ + som_memory[(m68k_adsp_buffer_bank ^ 1) * 0x2000 + (adsp_som_address++ & 0x1fff)] = data; + break; + + case 3: /* /SOMCLK */ + adsp_som_address = data; + break; + + case 5: /* /XOUT */ + adsp_xflag = data & 1; + break; + + case 6: /* /GINT */ + logerror("%04X:ADSP signals interrupt\n", activecpu_get_previouspc()); + adsp_irq_state = 1; + atarigen_update_interrupts(); + break; + + case 7: /* /MP */ + adsp_eprom_base = 0x10000 * data; + break; + + default: + logerror("%04X:hdadsp_special_w(%04X)=%04X\n", activecpu_get_previouspc(), offset, data); + break; + } +} + + + +#if 0 +#pragma mark - +#pragma mark * DS III BOARD +#endif + +/************************************* + * + * General DS III I/O + * + *************************************/ + +static void update_ds3_irq(void) +{ + /* update the IRQ2 signal to the ADSP2101 */ + if (!(!ds3_g68flag && ds3_g68irqs) && !(ds3_gflag && ds3_gfirqs)) + cpunum_set_input_line(hdcpu_adsp, ADSP2100_IRQ2, ASSERT_LINE); + else + cpunum_set_input_line(hdcpu_adsp, ADSP2100_IRQ2, CLEAR_LINE); +} + + +WRITE16_HANDLER( hd68k_ds3_control_w ) +{ + int val = (offset >> 3) & 1; + + switch (offset & 7) + { + case 0: + /* SRES - reset sound CPU */ + break; + + case 1: + /* XRES - reset sound helper CPU */ + break; + + case 2: + /* connected to the /BR (bus request) line; this effectively halts */ + /* the ADSP at the next instruction boundary */ + adsp_br = !val; + if (adsp_br) + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, ASSERT_LINE); + else + { + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_HALT, CLEAR_LINE); + /* a yield in this case is not enough */ + /* we would need to increase the interleaving otherwise */ + /* note that this only affects the test mode */ + cpu_spin(); + } + break; + + case 3: + cpunum_set_input_line(hdcpu_adsp, INPUT_LINE_RESET, val ? CLEAR_LINE : ASSERT_LINE); + if (val && !ds3_reset) + { + ds3_gflag = 0; + ds3_gcmd = 0; + ds3_gfirqs = 0; + ds3_g68irqs = !ds3_gfirqs; + ds3_send = 0; + update_ds3_irq(); + } + ds3_reset = val; + cpu_yield(); + logerror("DS III reset = %d\n", val); + break; + + case 7: + /* LED */ + break; + + default: + logerror("DS III control %02X = %04X\n", offset, data); + break; + } +} + + + +/************************************* + * + * DS III graphics I/O + * + *************************************/ + +READ16_HANDLER( hd68k_ds3_girq_state_r ) +{ + int result = 0x0fff; + if (ds3_g68flag) result ^= 0x8000; + if (ds3_gflag) result ^= 0x4000; + if (ds3_g68irqs) result ^= 0x2000; + if (!adsp_irq_state) result ^= 0x1000; + return result; +} + + +READ16_HANDLER( hd68k_ds3_gdata_r ) +{ + offs_t pc = activecpu_get_pc(); + + ds3_gflag = 0; + update_ds3_irq(); + + logerror("%06X:hd68k_ds3_gdata_r(%04X)\n", activecpu_get_previouspc(), ds3_gdata); + + /* attempt to optimize the transfer if conditions are right */ + if (cpu_getactivecpu() == 0 && pc == hdds3_transfer_pc && + !(!ds3_g68flag && ds3_g68irqs) && !(ds3_gflag && ds3_gfirqs)) + { + UINT32 destaddr = activecpu_get_reg(M68K_A1); + UINT16 count68k = activecpu_get_reg(M68K_D1); + UINT16 mstat = cpunum_get_reg(hdcpu_adsp, ADSP2100_MSTAT); + UINT16 i6 = cpunum_get_reg(hdcpu_adsp, (mstat & 1) ? ADSP2100_MR0 : ADSP2100_MR0_SEC); + UINT16 l6 = cpunum_get_reg(hdcpu_adsp, ADSP2100_L6) - 1; + UINT16 m7 = cpunum_get_reg(hdcpu_adsp, ADSP2100_M7); + + logerror("%06X:optimizing 68k transfer, %d words\n", activecpu_get_previouspc(), count68k); + + while (count68k > 0 && hdadsp_data_memory[0x16e6] > 0) + { + program_write_word(destaddr, ds3_gdata); + { + hdadsp_data_memory[0x16e6]--; + ds3_gdata = hdadsp_pgm_memory[i6] >> 8; + i6 = (i6 & ~l6) | ((i6 + m7) & l6); + } + count68k--; + } + activecpu_set_reg(M68K_D1, count68k); + cpunum_set_reg(hdcpu_adsp, (mstat & 1) ? ADSP2100_MR0 : ADSP2100_MR0_SEC, i6); + adsp_speedup_count[1]++; + } + + /* if we just cleared the IRQ, we are going to do some VERY timing critical reads */ + /* it is important that all the CPUs be in sync before we continue, so spin a little */ + /* while to let everyone else catch up */ + cpu_spinuntil_trigger(DS3_TRIGGER); + cpu_triggertime(ATTOTIME_IN_USEC(5), DS3_TRIGGER); + + return ds3_gdata; +} + + +WRITE16_HANDLER( hd68k_ds3_gdata_w ) +{ + logerror("%06X:hd68k_ds3_gdata_w(%04X)\n", activecpu_get_previouspc(), ds3_gdata); + + COMBINE_DATA(&ds3_g68data); + ds3_g68flag = 1; + ds3_gcmd = offset & 1; + cpu_triggerint(hdcpu_adsp); + update_ds3_irq(); +} + + + +/************************************* + * + * DS III sound I/O + * + *************************************/ + +READ16_HANDLER( hd68k_ds3_sirq_state_r ) +{ + return 0x4000; +} + + +READ16_HANDLER( hd68k_ds3_sdata_r ) +{ + return 0; +} + + +WRITE16_HANDLER( hd68k_ds3_sdata_w ) +{ +} + + +/************************************* + * + * DS III internal I/O + * + *************************************/ + +READ16_HANDLER( hdds3_special_r ) +{ + int result; + + switch (offset & 7) + { + case 0: + ds3_g68flag = 0; + update_ds3_irq(); + return ds3_g68data; + + case 1: + result = 0x0fff; + if (ds3_gcmd) result ^= 0x8000; + if (ds3_g68flag) result ^= 0x4000; + if (ds3_gflag) result ^= 0x2000; + return result; + + case 6: + logerror("ADSP r @ %04x\n", ds3_sim_address); + if (ds3_sim_address < sim_memory_size) + return sim_memory[ds3_sim_address]; + else + return 0xff; + } + return 0; +} + + +WRITE16_HANDLER( hdds3_special_w ) +{ + /* IMPORTANT! these data values also write through to the underlying RAM */ + hdadsp_data_memory[offset] = data; + + switch (offset & 7) + { + case 0: + logerror("%04X:ADSP sets gdata to %04X\n", activecpu_get_previouspc(), data); + ds3_gdata = data; + ds3_gflag = 1; + update_ds3_irq(); + + /* once we've written data, trigger the main CPU to wake up again */ + cpu_trigger(DS3_TRIGGER); + break; + + case 1: + logerror("%04X:ADSP sets interrupt = %d\n", activecpu_get_previouspc(), (data >> 1) & 1); + adsp_irq_state = (data >> 1) & 1; + hd68k_update_interrupts(); + break; + + case 2: + ds3_send = (data >> 0) & 1; + break; + + case 3: + ds3_gfirqs = (data >> 1) & 1; + ds3_g68irqs = !ds3_gfirqs; + update_ds3_irq(); + break; + + case 4: + ds3_sim_address = (ds3_sim_address & 0xffff0000) | (data & 0xffff); + break; + + case 5: + ds3_sim_address = (ds3_sim_address & 0xffff) | ((data << 16) & 0x00070000); + break; + } +} + + +READ16_HANDLER( hdds3_control_r ) +{ + logerror("adsp2101 control r @ %04X\n", 0x3fe0 + offset); + return 0; +} + + +WRITE16_HANDLER( hdds3_control_w ) +{ + if (offset != 0x1e && offset != 0x1f) + logerror("adsp2101 control w @ %04X = %04X\n", 0x3fe0 + offset, data); +} + + + +/************************************* + * + * DS III program memory handlers + * + *************************************/ + +READ16_HANDLER( hd68k_ds3_program_r ) +{ + UINT32 *base = &hdadsp_pgm_memory[offset & 0x1fff]; + UINT32 word = *base; + return (!(offset & 0x2000)) ? (word >> 8) : (word & 0xff); +} + + +WRITE16_HANDLER( hd68k_ds3_program_w ) +{ + UINT32 *base = &hdadsp_pgm_memory[offset & 0x1fff]; + UINT32 oldword = *base; + UINT16 temp; + + if (!(offset & 0x2000)) + { + temp = oldword >> 8; + COMBINE_DATA(&temp); + oldword = (oldword & 0x000000ff) | (temp << 8); + } + else + { + temp = oldword & 0xff; + COMBINE_DATA(&temp); + oldword = (oldword & 0xffffff00) | (temp & 0xff); + } + *base = oldword; +} + + + +#if 0 +#pragma mark - +#pragma mark * DSK BOARD +#endif + +/************************************* + * + * DSK board IRQ generation + * + *************************************/ + +void hddsk_update_pif(UINT32 pins) +{ + atarigen_sound_int_state = ((pins & DSP32_OUTPUT_PIF) != 0); + hd68k_update_interrupts(); +} + + + +/************************************* + * + * DSK board control handlers + * + *************************************/ + +WRITE16_HANDLER( hd68k_dsk_control_w ) +{ + int val = (offset >> 3) & 1; + switch (offset & 7) + { + case 0: /* DSPRESTN */ + cpunum_set_input_line(hdcpu_dsp32, INPUT_LINE_RESET, val ? CLEAR_LINE : ASSERT_LINE); + break; + + case 1: /* DSPZN */ + cpunum_set_input_line(hdcpu_dsp32, INPUT_LINE_HALT, val ? CLEAR_LINE : ASSERT_LINE); + break; + + case 2: /* ZW1 */ + break; + + case 3: /* ZW2 */ + break; + + case 4: /* ASIC65 reset */ + asic65_reset(!val); + break; + + case 7: /* LED */ + break; + + default: + logerror("hd68k_dsk_control_w(%d) = %d\n", offset & 7, val); + break; + } +} + + + +/************************************* + * + * DSK board RAM/ZRAM/ROM handlers + * + *************************************/ + +READ16_HANDLER( hd68k_dsk_ram_r ) +{ + return hddsk_ram[offset]; +} + + +WRITE16_HANDLER( hd68k_dsk_ram_w ) +{ + COMBINE_DATA(&hddsk_ram[offset]); +} + + +READ16_HANDLER( hd68k_dsk_zram_r ) +{ + return hddsk_zram[offset]; +} + + +WRITE16_HANDLER( hd68k_dsk_zram_w ) +{ + COMBINE_DATA(&hddsk_zram[offset]); +} + + +READ16_HANDLER( hd68k_dsk_small_rom_r ) +{ + return hddsk_rom[offset & 0x1ffff]; +} + + +READ16_HANDLER( hd68k_dsk_rom_r ) +{ + return hddsk_rom[offset]; +} + + + +/************************************* + * + * DSK board DSP32C I/O handlers + * + *************************************/ + +WRITE16_HANDLER( hd68k_dsk_dsp32_w ) +{ + hddsk_pio_access = 1; + dsp32c_pio_w(hdcpu_dsp32, offset, data); + hddsk_pio_access = 0; +} + + +READ16_HANDLER( hd68k_dsk_dsp32_r ) +{ + UINT16 result; + hddsk_pio_access = 1; + result = dsp32c_pio_r(hdcpu_dsp32, offset); + hddsk_pio_access = 0; + return result; +} + + +/************************************* + * + * DSP32C synchronization + * + *************************************/ + +static TIMER_CALLBACK( rddsp32_sync_cb ) +{ + *dataptr[param] = dataval[param]; +} + + +WRITE32_HANDLER( rddsp32_sync0_w ) +{ + if (hddsk_pio_access) + { + UINT32 *dptr = &rddsp32_sync[0][offset]; + UINT32 newdata = *dptr; + COMBINE_DATA(&newdata); + dataptr[next_msp_sync % MAX_MSP_SYNC] = dptr; + dataval[next_msp_sync % MAX_MSP_SYNC] = newdata; + timer_call_after_resynch(next_msp_sync++ % MAX_MSP_SYNC, rddsp32_sync_cb); + } + else + COMBINE_DATA(&rddsp32_sync[0][offset]); +} + + +WRITE32_HANDLER( rddsp32_sync1_w ) +{ + if (hddsk_pio_access) + { + UINT32 *dptr = &rddsp32_sync[1][offset]; + UINT32 newdata = *dptr; + COMBINE_DATA(&newdata); + dataptr[next_msp_sync % MAX_MSP_SYNC] = dptr; + dataval[next_msp_sync % MAX_MSP_SYNC] = newdata; + timer_call_after_resynch(next_msp_sync++ % MAX_MSP_SYNC, rddsp32_sync_cb); + } + else + COMBINE_DATA(&rddsp32_sync[1][offset]); +} + + + +#if 0 +#pragma mark - +#pragma mark * DSPCOM BOARD +#endif + +/************************************* + * + * DSPCOM control handlers + * + *************************************/ + +WRITE16_HANDLER( hddspcom_control_w ) +{ + int val = (offset >> 3) & 1; + switch (offset & 7) + { + case 2: /* ASIC65 reset */ + asic65_reset(!val); + break; + + default: + logerror("hddspcom_control_w(%d) = %d\n", offset & 7, val); + break; + } +} + + + +#if 0 +#pragma mark - +#pragma mark * GAME-SPECIFIC PROTECTION +#endif + +/************************************* + * + * Race Drivin' slapstic handling + * + *************************************/ + +WRITE16_HANDLER( rd68k_slapstic_w ) +{ + slapstic_tweak(offset & 0x3fff); +} + + +READ16_HANDLER( rd68k_slapstic_r ) +{ + int bank = slapstic_tweak(offset & 0x3fff) * 0x4000; + return hd68k_slapstic_base[bank + (offset & 0x3fff)]; +} + + + +/************************************* + * + * Steel Talons SLOOP handling + * + *************************************/ + +static int st68k_sloop_tweak(offs_t offset) +{ + static int last_offset; + + if (last_offset == 0) + { + switch (offset) + { + case 0x78e8: + st68k_sloop_bank = 0; + break; + case 0x6ca4: + st68k_sloop_bank = 1; + break; + case 0x15ea: + st68k_sloop_bank = 2; + break; + case 0x6b28: + st68k_sloop_bank = 3; + break; + } + } + last_offset = offset; + return st68k_sloop_bank; +} + + +WRITE16_HANDLER( st68k_sloop_w ) +{ + st68k_sloop_tweak(offset & 0x3fff); +} + + +READ16_HANDLER( st68k_sloop_r ) +{ + int bank = st68k_sloop_tweak(offset) * 0x4000; + return hd68k_slapstic_base[bank + (offset & 0x3fff)]; +} + + +READ16_HANDLER( st68k_sloop_alt_r ) +{ + if (st68k_last_alt_sloop_offset == 0x00fe) + { + switch (offset*2) + { + case 0x22c: + st68k_sloop_bank = 0; + break; + case 0x1e2: + st68k_sloop_bank = 1; + break; + case 0x1fa: + st68k_sloop_bank = 2; + break; + case 0x206: + st68k_sloop_bank = 3; + break; + } + } + st68k_last_alt_sloop_offset = offset*2; + return st68k_sloop_alt_base[offset]; +} + + +static int st68k_protosloop_tweak(offs_t offset) +{ + static int last_offset; + + if (last_offset == 0) + { + switch (offset) + { + case 0x0001: + st68k_sloop_bank = 0; + break; + case 0x0002: + st68k_sloop_bank = 1; + break; + case 0x0003: + st68k_sloop_bank = 2; + break; + case 0x0004: + st68k_sloop_bank = 3; + break; + } + } + last_offset = offset; + return st68k_sloop_bank; +} + + +WRITE16_HANDLER( st68k_protosloop_w ) +{ + st68k_protosloop_tweak(offset & 0x3fff); +} + + +READ16_HANDLER( st68k_protosloop_r ) +{ + int bank = st68k_protosloop_tweak(offset) * 0x4000; + return hd68k_slapstic_base[bank + (offset & 0x3fff)]; +} + + + +#if 0 +#pragma mark - +#pragma mark * GSP OPTIMIZATIONS +#endif + +/************************************* + * + * GSP Optimizations - case 1 + * Works for: + * Hard Drivin' + * STUN Runner + * + *************************************/ + +READ16_HANDLER( hdgsp_speedup_r ) +{ + int result = hdgsp_speedup_addr[0][offset]; + + /* if both this address and the other important address are not $ffff */ + /* then we can spin until something gets written */ + if (result != 0xffff && hdgsp_speedup_addr[1][0] != 0xffff && + cpu_getactivecpu() == hdcpu_gsp && activecpu_get_pc() == hdgsp_speedup_pc) + { + gsp_speedup_count[0]++; + cpu_spinuntil_int(); + } + + return result; +} + + +WRITE16_HANDLER( hdgsp_speedup1_w ) +{ + COMBINE_DATA(&hdgsp_speedup_addr[0][offset]); + + /* if $ffff is written, send an "interrupt" trigger to break us out of the spin loop */ + if (hdgsp_speedup_addr[0][offset] == 0xffff) + cpu_triggerint(hdcpu_gsp); +} + + +WRITE16_HANDLER( hdgsp_speedup2_w ) +{ + COMBINE_DATA(&hdgsp_speedup_addr[1][offset]); + + /* if $ffff is written, send an "interrupt" trigger to break us out of the spin loop */ + if (hdgsp_speedup_addr[1][offset] == 0xffff) + cpu_triggerint(hdcpu_gsp); +} + + + +/************************************* + * + * GSP Optimizations - case 2 + * Works for: + * Race Drivin' + * + *************************************/ + +READ16_HANDLER( rdgsp_speedup1_r ) +{ + int result = hdgsp_speedup_addr[0][offset]; + + /* if this address is equal to $f000, spin until something gets written */ + if (cpu_getactivecpu() == hdcpu_gsp && activecpu_get_pc() == hdgsp_speedup_pc && + (result & 0xff) < activecpu_get_reg(TMS34010_A1)) + { + gsp_speedup_count[0]++; + cpu_spinuntil_int(); + } + + return result; +} + + +WRITE16_HANDLER( rdgsp_speedup1_w ) +{ + COMBINE_DATA(&hdgsp_speedup_addr[0][offset]); + if (cpu_getactivecpu() != hdcpu_gsp) + cpu_triggerint(hdcpu_gsp); +} + + + +#if 0 +#pragma mark - +#pragma mark * MSP OPTIMIZATIONS +#endif + +/************************************* + * + * MSP Optimizations + * + *************************************/ + +READ16_HANDLER( hdmsp_speedup_r ) +{ + int data = hdmsp_speedup_addr[offset]; + + if (data == 0 && activecpu_get_pc() == hdmsp_speedup_pc && cpu_getactivecpu() == hdcpu_msp) + { + msp_speedup_count[0]++; + cpu_spinuntil_int(); + } + + return data; +} + + +WRITE16_HANDLER( hdmsp_speedup_w ) +{ + COMBINE_DATA(&hdmsp_speedup_addr[offset]); + if (offset == 0 && hdmsp_speedup_addr[offset] != 0) + cpu_triggerint(hdcpu_msp); +} + + +READ16_HANDLER( stmsp_speedup_r ) +{ + /* assumes: stmsp_sync[0] -> $80010, stmsp_sync[1] -> $99680, stmsp_sync[2] -> $99d30 */ + if (stmsp_sync[0][0] == 0 && /* 80010 */ + stmsp_sync[0][1] == 0 && /* 80020 */ + stmsp_sync[0][2] == 0 && /* 80030 */ + stmsp_sync[0][3] == 0 && /* 80040 */ + stmsp_sync[0][4] == 0 && /* 80050 */ + stmsp_sync[0][5] == 0 && /* 80060 */ + stmsp_sync[0][6] == 0 && /* 80070 */ + stmsp_sync[1][0] == 0 && /* 99680 */ + stmsp_sync[2][0] == 0xffff && /* 99d30 */ + stmsp_sync[2][1] == 0xffff && /* 99d40 */ + stmsp_sync[2][2] == 0 && /* 99d50 */ + activecpu_get_pc() == 0x3c0) + { + msp_speedup_count[0]++; + cpu_spinuntil_int(); + } + return stmsp_sync[0][1]; +} + + + +#if 0 +#pragma mark - +#pragma mark * ADSP OPTIMIZATIONS +#endif + +/************************************* + * + * ADSP Optimizations + * + *************************************/ + +READ16_HANDLER( hdadsp_speedup_r ) +{ + int data = hdadsp_data_memory[0x1fff]; + + if (data == 0xffff && activecpu_get_pc() <= 0x3b && cpu_getactivecpu() == hdcpu_adsp) + { + adsp_speedup_count[0]++; + cpu_spinuntil_int(); + } + + return data; +} + + +READ16_HANDLER( hdds3_speedup_r ) +{ + int data = *hdds3_speedup_addr; + + if (data != 0 && activecpu_get_pc() == hdds3_speedup_pc && cpu_getactivecpu() == hdcpu_adsp) + { + adsp_speedup_count[2]++; + cpu_spinuntil_int(); + } + + return data; +} |