diff options
Diffstat (limited to 'src/mame/drivers/gba.cpp')
-rw-r--r-- | src/mame/drivers/gba.cpp | 1467 |
1 files changed, 0 insertions, 1467 deletions
diff --git a/src/mame/drivers/gba.cpp b/src/mame/drivers/gba.cpp deleted file mode 100644 index 76e8e526333..00000000000 --- a/src/mame/drivers/gba.cpp +++ /dev/null @@ -1,1467 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont,Ryan Holtz -/*************************************************************************** - - gba.cpp - - Driver file to handle emulation of the Nintendo Game Boy Advance. - - By R. Belmont & Ryan Holtz - -***************************************************************************/ - -#include "emu.h" -#include "includes/gba.h" - -#include "bus/gba/rom.h" -#include "cpu/arm7/arm7.h" -#include "cpu/arm7/arm7core.h" -#include "sound/gb.h" -#include "softlist.h" -#include "speaker.h" - - -/* Sound Registers */ -#define SOUNDCNT_L HWLO(0x080) /* 0x4000080 2 R/W Control Stereo/Volume/Enable */ -#define SOUNDCNT_H HWHI(0x080) /* 0x4000082 2 R/W Control Mixing/DMA Control */ -#define SOUNDCNT_X HWLO(0x084) /* 0x4000084 2 R/W Control Sound on/off */ - /* 0x4000086 2 - Unused */ -#define SOUNDBIAS HWLO(0x088) /* 0x4000088 2 BIOS Sound PWM Control */ - /* 0x400008A 2 - Unused */ - -/* DMA Registers (4 Transfer Channels) */ -#define DMASAD(c) WORD(0x0B0 + c * 0xC) /* 0x40000B0 4 W DMA 0 Source Address */ -#define DMADAD(c) WORD(0x0B4 + c * 0xC) /* 0x40000B4 4 W DMA 0 Destination Address */ -#define DMACNT_L(c) HWLO(0x0B8 + c * 0xC) /* 0x40000B8 2 W DMA 0 Word Count */ -#define DMACNT_H(c) HWHI(0x0B8 + c * 0xC) /* 0x40000BA 2 R/W DMA 0 Control */ - -/* Serial Communication (1) Registers */ -#define SIODATA32 WORD(0x120) /* 0x4000120 4 R/W SIO Data (Normal-32bit Mode; shared with below) */ -#define SIOMULTI0 HWLO(0x120) /* 0x4000120 2 R/W SIO Data 0 (Parent) (Multi-Player Mode) */ -#define SIOMULTI1 HWHI(0x120) /* 0x4000122 2 R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ -#define SIOMULTI2 HWLO(0x124) /* 0x4000124 2 R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ -#define SIOMULTI3 HWHI(0x124) /* 0x4000126 2 R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ -#define SIOCNT HWLO(0x128) /* 0x4000128 2 R/W SIO Control Register */ -#define SIOMLT_SEND HWHI(0x128) /* 0x400012A 2 R/W SIO Data (Local of MultiPlayer; shared below) */ -#define SIODATA8 HWHI(0x128) /* 0x400012A 2 R/W SIO Data (Normal-8bit and UART Mode) */ - /* 0x400012C 2 - Unused */ - -/* Keypad Input Registers */ -#define KEYINPUT HWLO(0x130) /* 0x4000130 2 R Key Status */ -#define KEYCNT HWHI(0x130) /* 0x4000132 2 R/W Key Interrupt Control */ - -/* Serial Communication (2) Registers */ -#define RCNT HWLO(0x134) /* 0x4000134 2 R/W SIO Mode Select/General Purpose Data */ -#define IR HWHI(0x134) /* 0x4000136 2 R/W Ancient - Infrared Register (Prototypes only) */ - /* 0x4000138 8 - Unused */ -#define JOYCNT HWLO(0x140) /* 0x4000140 2 R/W SIO JOY Bus Control */ - /* 0x4000142 2 - Unused */ -#define JOY_RECV WORD(0x150) /* 0x4000150 4 R/W SIO JOY Bus Receive Data */ -#define JOY_TRANS WORD(0x154) /* 0x4000154 4 R/W SIO JOY Bus Transmit Data */ -#define JOYSTAT HWLO(0x158) /* 0x4000158 2 R/? SIO JOY Bus Receive Status */ - /* 0x400015A 2 - Unused */ - -/* Interrupt, Waitstate, and Power-Down Control Registers */ -#define IE HWLO(0x200) /* 0x4000200 2 R/W Interrupt Enable Register */ -#define IF HWHI(0x200) /* 0x4000202 2 R/W Interrupt Request Flags / IRQ Acknowledge */ -#define WAITCNT HWLO(0x204) /* 0x4000204 2 R/W Game Pak Waitstate Control */ - /* 0x4000206 - Unused */ -#define IME HWLO(0x208) /* 0x4000208 2 R/W Interrupt Master Enable Register */ - /* 0x400020A - Unused */ - /* 0x4000300 1 R/W Undocumented - Post Boot Flag */ - /* 0x4000301 1 W Undocumented - Power Down Control */ - /* 0x4000302 - Unused */ - /* 0x4000410 ? ? Undocumented - Purpose Unknown / Bug ??? 0FFh */ - /* 0x4000411 - Unused */ - /* 0x4000800 4 R/W Undocumented - Internal Memory Control (R/W) */ - /* 0x4000804 - Unused */ - /* 0x4xx0800 4 R/W Mirrors of 4000800h (repeated each 64K) */ - -#define SOUNDBIAS_SET(val) HWLO_SET(0x088, val) - -#define DMASAD_SET(c, val) WORD_SET(0x0B0 + (c * 0xC), val) -#define DMADAD_SET(c, val) WORD_SET(0x0B4 + (c * 0xC), val) -#define DMACNT_L_SET(c, val) HWLO_SET(0x0B8 + (c * 0xC), val) -#define DMACNT_H_SET(c, val) HWHI_SET(0x0B8 + (c * 0xC), val) -#define DMACNT_H_RESET(c, val) HWHI_RESET(0x0B8 + (c * 0xC), val) - -#define SIOMULTI0_SET(val) HWLO_SET(0x120, val) -#define SIOMULTI1_SET(val) HWHI_SET(0x120, val) -#define SIOMULTI2_SET(val) HWLO_SET(0x124, val) -#define SIOMULTI3_SET(val) HWHI_SET(0x124, val) - -#define SIOCNT_RESET(val) HWLO_RESET(0x128, val) - -#define KEYCNT_SET(val) HWHI_SET(0x130, val) - -#define RCNT_SET(val) HWLO_SET(0x134, val) - -#define JOYSTAT_SET(val) HWLO_SET(0x158, val) - -#define IF_SET(val) HWHI_SET(0x200, val) -#define IF_RESET(val) HWHI_RESET(0x200, val) - -#define INT_VBL 0x0001 -#define INT_HBL 0x0002 -#define INT_VCNT 0x0004 -#define INT_TM0_OVERFLOW 0x0008 -#define INT_TM1_OVERFLOW 0x0010 -#define INT_TM2_OVERFLOW 0x0020 -#define INT_TM3_OVERFLOW 0x0040 -#define INT_SIO 0x0080 -#define INT_DMA0 0x0100 -#define INT_DMA1 0x0200 -#define INT_DMA2 0x0400 -#define INT_DMA3 0x0800 -#define INT_KEYPAD 0x1000 -#define INT_GAMEPAK 0x2000 - -#define VERBOSE_LEVEL (0) - -static inline void ATTR_PRINTF(3,4) verboselog(device_t &device, int n_level, const char *s_fmt, ...) -{ - if( VERBOSE_LEVEL >= n_level ) - { - va_list v; - char buf[ 32768 ]; - va_start( v, s_fmt ); - vsprintf( buf, s_fmt, v ); - va_end( v ); - device.logerror( "%08x: %s", device.machine().describe_context(), buf ); - } -} - -static const XTAL timer_clks[4] = { XTAL(16'777'216), XTAL(16'777'216) / 64, XTAL(16'777'216) / 256, XTAL(16'777'216) / 1024 }; - - -void gba_state::request_irq(uint32_t int_type) -{ - // set flag for later recovery - IF_SET(int_type); - - // is this specific interrupt enabled? - int_type &= IE; - if (int_type != 0) - { - // master enable? - if (IME & 1) - { - m_maincpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE); - m_maincpu->set_input_line(ARM7_IRQ_LINE, CLEAR_LINE); - } - } -} - -TIMER_CALLBACK_MEMBER(gba_state::dma_complete) -{ - static const uint32_t ch_int[4] = { INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3 }; - - uintptr_t ch = param; - -// printf("dma complete: ch %d\n", ch); - - m_dma_timer[ch]->adjust(attotime::never); - - int ctrl = DMACNT_H(ch); - - // IRQ - if (ctrl & 0x4000) - { - request_irq(ch_int[ch]); - } - - // if we're supposed to repeat, don't clear "active" and then the next vbl/hbl will retrigger us - // always clear active for immediate DMAs though - if (!((ctrl>>9) & 1) || ((ctrl & 0x3000) == 0)) - { - DMACNT_H_RESET(ch, 0x8000); // clear "active" bit - } - else - { - // if repeat, reload the count - if ((ctrl>>9) & 1) - { - m_dma_cnt[ch] = DMACNT_L(ch); - - // if increment & reload mode, reload the destination - if (((ctrl>>5)&3) == 3) - { - m_dma_dst[ch] = DMADAD(ch); - } - } - } -} - -void gba_state::dma_exec(int ch) -{ - address_space &space = m_maincpu->space(AS_PROGRAM); - uint32_t src = m_dma_src[ch]; - uint32_t dst = m_dma_dst[ch]; - uint16_t ctrl = DMACNT_H(ch); - int srcadd = (ctrl >> 7) & 3; - int dstadd = (ctrl >> 5) & 3; - - int cnt = m_dma_cnt[ch]; - if (cnt == 0) - { - if (ch == 3) - cnt = 0x10000; - else - cnt = 0x4000; - } - - // override special parameters - if ((ctrl & 0x3000) == 0x3000) // special xfer mode - { - switch (ch) - { - case 1: // Ch 1&2 are for audio DMA - case 2: - dstadd = 2; // don't increment destination - cnt = 4; // always transfer 4 32-bit words - ctrl |= 0x400; // always 32-bit - break; - - case 3: - printf("Unsupported DMA 3 special mode\n"); - break; - } - } - else - { -// if (dst >= 0x6000000 && dst <= 0x6017fff) -// printf("DMA exec: ch %d from %08x to %08x, mode %04x, count %04x (%s)\n", (int)ch, src, dst, ctrl, cnt, ((ctrl>>10) & 1) ? "32" : "16"); - } - - for (int i = 0; i < cnt; i++) - { - if ((ctrl>>10) & 1) - { - src &= 0xfffffffe; - dst &= 0xfffffffe; - - // 32-bit - space.write_dword(dst, space.read_dword(src)); - switch (dstadd) - { - case 0: // increment - dst += 4; - break; - case 1: // decrement - dst -= 4; - break; - case 2: // don't move - break; - case 3: // increment and reload - dst += 4; - break; - } - switch (srcadd) - { - case 0: // increment - src += 4; - break; - case 1: // decrement - src -= 4; - break; - case 2: // don't move - break; - case 3: // not used ("Metal Max 2 Kai" expects no increment/decrement) - break; - } - } - else - { - src &= 0xfffffffe; - dst &= 0xfffffffe; - - // 16-bit - space.write_word(dst, space.read_word(src)); - switch (dstadd) - { - case 0: // increment - dst += 2; - break; - case 1: // decrement - dst -= 2; - break; - case 2: // don't move - break; - case 3: // increment and reload - dst += 2; - break; - } - switch (srcadd) - { - case 0: // increment - src += 2; - break; - case 1: // decrement - src -= 2; - break; - case 2: // don't move - break; - case 3: // not used (see note in 32-bit version above) - break; - } - } - } - - m_dma_src[ch] = src; - m_dma_dst[ch] = dst; - -// printf("settng DMA timer %d for %d cycs (tmr %x)\n", ch, cnt, (uint32_t)m_dma_timer[ch]); -// m_dma_timer[ch]->adjust(ATTOTIME_IN_CYCLES(0, cnt), ch); - dma_complete(nullptr, ch); -} - -void gba_state::audio_tick(int ref) -{ - if (!(SOUNDCNT_X & 0x80)) - return; - - if (!ref) - { - if (m_fifo_a_ptr != m_fifo_a_in) - { - if (m_fifo_a_ptr == 17) - { - m_fifo_a_ptr = 0; - } - - if (SOUNDCNT_H & 0x200) - { - m_ldaca->write(m_fifo_a[m_fifo_a_ptr]); - } - if (SOUNDCNT_H & 0x100) - { - m_rdaca->write(m_fifo_a[m_fifo_a_ptr]); - } - m_fifo_a_ptr++; - } - - // fifo empty? - if (m_fifo_a_ptr == m_fifo_a_in) - { - // is a DMA set up to feed us? - if ((DMADAD(1) == 0x40000a0) && ((DMACNT_H(1) & 0x3000) == 0x3000)) - { - // channel 1 it is - dma_exec(1); - } - if ((DMADAD(2) == 0x40000a0) && ((DMACNT_H(2) & 0x3000) == 0x3000)) - { - // channel 2 it is - dma_exec(2); - } - } - } - else - { - if (m_fifo_b_ptr != m_fifo_b_in) - { - if (m_fifo_b_ptr == 17) - { - m_fifo_b_ptr = 0; - } - - if (SOUNDCNT_H & 0x2000) - { - m_ldacb->write(m_fifo_b[m_fifo_b_ptr]); - } - if (SOUNDCNT_H & 0x1000) - { - m_rdacb->write(m_fifo_b[m_fifo_b_ptr]); - } - m_fifo_b_ptr++; - } - - if (m_fifo_b_ptr == m_fifo_b_in) - { - // is a DMA set up to feed us? - if ((DMADAD(1) == 0x40000a4) && ((DMACNT_H(1) & 0x3000) == 0x3000)) - { - // channel 1 it is - dma_exec(1); - } - if ((DMADAD(2) == 0x40000a4) && ((DMACNT_H(2) & 0x3000) == 0x3000)) - { - // channel 2 it is - dma_exec(2); - } - } - } -} - -TIMER_CALLBACK_MEMBER(gba_state::timer_expire) -{ - static const uint32_t tmr_ints[4] = { INT_TM0_OVERFLOW, INT_TM1_OVERFLOW, INT_TM2_OVERFLOW, INT_TM3_OVERFLOW }; - uintptr_t tmr = (uintptr_t) param; - - // "The reload value is copied into the counter only upon following two situations: Automatically upon timer overflows," - // "or when the timer start bit becomes changed from 0 to 1." - if (m_timer_recalc[tmr] != 0) - { - double rate, clocksel, final; - attotime time; - m_timer_recalc[tmr] = 0; - m_timer_regs[tmr] = (m_timer_regs[tmr] & 0xFFFF0000) | (m_timer_reload[tmr] & 0x0000FFFF); - rate = 0x10000 - (m_timer_regs[tmr] & 0xffff); - clocksel = timer_clks[(m_timer_regs[tmr] >> 16) & 3].dvalue(); - final = clocksel / rate; - m_timer_hz[tmr] = final; - time = attotime::from_hz(final); - m_tmr_timer[tmr]->adjust(time, tmr, time); - } - - // check if timers 0 or 1 are feeding directsound - if (tmr == 0) - { - if (!(SOUNDCNT_H & 0x400)) - audio_tick(0); - - if (!(SOUNDCNT_H & 0x4000)) - audio_tick(1); - } - - if (tmr == 1) - { - if (SOUNDCNT_H & 0x400) - audio_tick(0); - - if (SOUNDCNT_H & 0x4000) - audio_tick(1); - } - - // Handle count-up timing - switch (tmr) - { - case 0: - if (m_timer_regs[1] & 0x40000) - { - m_timer_regs[1] = (( ( m_timer_regs[1] & 0x0000ffff ) + 1 ) & 0x0000ffff) | (m_timer_regs[1] & 0xffff0000); - if( ( m_timer_regs[1] & 0x0000ffff ) == 0 ) - { - m_timer_regs[1] |= m_timer_reload[1]; - if( ( m_timer_regs[1] & 0x400000 ) && ( IME != 0 ) ) - { - request_irq(tmr_ints[1]); - } - if( ( m_timer_regs[2] & 0x40000 ) ) - { - m_timer_regs[2] = (( ( m_timer_regs[2] & 0x0000ffff ) + 1 ) & 0x0000ffff) | (m_timer_regs[2] & 0xffff0000); - if( ( m_timer_regs[2] & 0x0000ffff ) == 0 ) - { - m_timer_regs[2] |= m_timer_reload[2]; - if( ( m_timer_regs[2] & 0x400000 ) && ( IME != 0 ) ) - { - request_irq(tmr_ints[2]); - } - if( ( m_timer_regs[3] & 0x40000 ) ) - { - m_timer_regs[3] = (( ( m_timer_regs[3] & 0x0000ffff ) + 1 ) & 0x0000ffff) | (m_timer_regs[3] & 0xffff0000); - if( ( m_timer_regs[3] & 0x0000ffff ) == 0 ) - { - m_timer_regs[3] |= m_timer_reload[3]; - if( ( m_timer_regs[3] & 0x400000 ) && ( IME != 0 ) ) - { - request_irq(tmr_ints[3]); - } - } - } - } - } - } - } - break; - case 1: - if (m_timer_regs[2] & 0x40000) - { - m_timer_regs[2] = (( ( m_timer_regs[2] & 0x0000ffff ) + 1 ) & 0x0000ffff) | (m_timer_regs[2] & 0xffff0000); - if( ( m_timer_regs[2] & 0x0000ffff ) == 0 ) - { - m_timer_regs[2] |= m_timer_reload[2]; - if( ( m_timer_regs[2] & 0x400000 ) && ( IME != 0 ) ) - { - request_irq(tmr_ints[2]); - } - if( ( m_timer_regs[3] & 0x40000 ) ) - { - m_timer_regs[3] = (( ( m_timer_regs[3] & 0x0000ffff ) + 1 ) & 0x0000ffff) | (m_timer_regs[3] & 0xffff0000); - if( ( m_timer_regs[3] & 0x0000ffff ) == 0 ) - { - m_timer_regs[3] |= m_timer_reload[3]; - if( ( m_timer_regs[3] & 0x400000 ) && ( IME != 0 ) ) - { - request_irq(tmr_ints[3]); - } - } - } - } - } - break; - case 2: - if (m_timer_regs[3] & 0x40000) - { - m_timer_regs[3] = (( ( m_timer_regs[3] & 0x0000ffff ) + 1 ) & 0x0000ffff) | (m_timer_regs[3] & 0xffff0000); - if( ( m_timer_regs[3] & 0x0000ffff ) == 0 ) - { - m_timer_regs[3] |= m_timer_reload[3]; - if( ( m_timer_regs[3] & 0x400000 ) && ( IME != 0 ) ) - { - request_irq(tmr_ints[3]); - } - } - } - break; - } - - // are we supposed to IRQ? - if ((m_timer_regs[tmr] & 0x400000) && (IME != 0)) - { - request_irq(tmr_ints[tmr]); - } -} - -TIMER_CALLBACK_MEMBER(gba_state::handle_irq) -{ - request_irq(IF); - - m_irq_timer->adjust(attotime::never); -} - -static const char *const reg_names[] = { - /* Sound Registers */ - "SOUND1CNT_L", "SOUND1CNT_H", "SOUND1CNT_X", "Unused", - "SOUND2CNT_L", "Unused", "SOUND2CNT_H", "Unused", - "SOUND3CNT_L", "SOUND3CNT_H", "SOUND3CNT_X", "Unused", - "SOUND4CNT_L", "Unused", "SOUND4CNT_H", "Unused", - "SOUNDCNT_L", "SOUNDCNT_H", "SOUNDCNT_X", "Unused", - "SOUNDBIAS", "Unused", "WAVE_RAM", "WAVE_RAM", - "WAVE_RAM", "WAVE_RAM", "WAVE_RAM", "WAVE_RAM", - "WAVE_RAM", "WAVE_RAM", "WAVE_RAM", "WAVE_RAM", - "WAVE_RAM", "WAVE_RAM", "WAVE_RAM", "WAVE_RAM", - "WAVE_RAM", "WAVE_RAM", "FIFO_A_L", "FIFO_A_H", - "FIFO_B_L", "FIFO_B_H" -}; - -uint32_t gba_state::gba_io_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t retval = 0; - - switch( offset + 0x60/4 ) - { - case 0x0060/4: - retval = m_gbsound->sound_r(0) | m_gbsound->sound_r(1)<<16 | m_gbsound->sound_r(2)<<24; - break; - case 0x0064/4: - retval = m_gbsound->sound_r(3) | m_gbsound->sound_r(4)<<8; - break; - case 0x0068/4: - retval = m_gbsound->sound_r(6) | m_gbsound->sound_r(7)<<8; - break; - case 0x006c/4: - retval = m_gbsound->sound_r(8) | m_gbsound->sound_r(9)<<8; - break; - case 0x0070/4: - retval = m_gbsound->sound_r(0xa) | m_gbsound->sound_r(0xb)<<16 | m_gbsound->sound_r(0xc)<<24; - break; - case 0x0074/4: - retval = m_gbsound->sound_r(0xd) | m_gbsound->sound_r(0xe)<<8; - break; - case 0x0078/4: - retval = m_gbsound->sound_r(0x10) | m_gbsound->sound_r(0x11)<<8; - break; - case 0x007c/4: - retval = m_gbsound->sound_r(0x12) | m_gbsound->sound_r(0x13)<<8; - break; - case 0x0080/4: - retval = m_gbsound->sound_r(0x14) | m_gbsound->sound_r(0x15)<<8; - if( ACCESSING_BITS_16_31 ) - { - retval |= SOUNDCNT_H << 16; - } - break; - case 0x0084/4: - retval = m_gbsound->sound_r(0x16); - break; - case 0x0090/4: - retval = m_gbsound->wave_r(0) | m_gbsound->wave_r(1)<<8 | m_gbsound->wave_r(2)<<16 | m_gbsound->wave_r(3)<<24; - break; - case 0x0094/4: - retval = m_gbsound->wave_r(4) | m_gbsound->wave_r(5)<<8 | m_gbsound->wave_r(6)<<16 | m_gbsound->wave_r(7)<<24; - break; - case 0x0098/4: - retval = m_gbsound->wave_r(8) | m_gbsound->wave_r(9)<<8 | m_gbsound->wave_r(10)<<16 | m_gbsound->wave_r(11)<<24; - break; - case 0x009c/4: - retval = m_gbsound->wave_r(12) | m_gbsound->wave_r(13)<<8 | m_gbsound->wave_r(14)<<16 | m_gbsound->wave_r(15)<<24; - break; - case 0x00a0/4: - case 0x00a4/4: - retval = 0; // (does this actually do anything on real h/w?) - break; - case 0x00b0/4: - case 0x00b4/4: - // read only - break; - case 0x00b8/4: - if (ACCESSING_BITS_0_15) - { - // read only - } - if (ACCESSING_BITS_16_31) - { - retval |= DMACNT_H(0) << 16; - } - break; - case 0x00bc/4: - case 0x00c0/4: - // read only - break; - case 0x00c4/4: - if (ACCESSING_BITS_0_15) - { - // read only - } - if (ACCESSING_BITS_16_31) - { - retval |= DMACNT_H(1) << 16; - } - break; - case 0x00c8/4: - case 0x00cc/4: - // read only - break; - case 0x00d0/4: - if (ACCESSING_BITS_0_15) - { - // read only - } - if (ACCESSING_BITS_16_31) - { - retval |= DMACNT_H(2) << 16; - } - break; - case 0x00d4/4: - case 0x00d8/4: - // read only - break; - case 0x00dc/4: - // no idea why here, but it matches VBA better - // note: this suspicious piece of code crashes "Buffy The Vampire Slayer" (08008DB4) and "The Ant Bully", so disable it for now - if (ACCESSING_BITS_0_15) - { - // read only - } - if (ACCESSING_BITS_16_31) - { - retval |= DMACNT_H(3) << 16; - } - break; - case 0x0100/4: - case 0x0104/4: - case 0x0108/4: - case 0x010c/4: - { - uint32_t elapsed; - double time, ticks; - int timer = offset + 0x60/4 - 0x100/4; - -// printf("Read timer reg %x (PC=%x)\n", timer, m_maincpu->pc()); - - // update times for - if (m_timer_regs[timer] & 0x800000) - { - if (m_timer_regs[timer] & 0x00040000) - { - elapsed = m_timer_regs[timer] & 0xffff; - } - else - { - time = m_tmr_timer[timer]->elapsed().as_double(); - - ticks = (double)(0x10000 - (m_timer_regs[timer] & 0xffff)); - - // printf("time %f ticks %f 1/hz %f\n", time, ticks, 1.0 / m_timer_hz[timer]); - - time *= ticks; - time /= (1.0 / m_timer_hz[timer]); - - elapsed = (uint32_t)time; - } - -// printf("elapsed = %x\n", elapsed); - } - else - { -// printf("Reading inactive timer!\n"); - elapsed = 0; - } - - retval = (m_timer_regs[timer] & 0xffff0000) | (elapsed & 0xffff); - } - break; - case 0x0130/4: - if( ACCESSING_BITS_0_15 ) // KEYINPUT - { - retval = m_io_inputs->read(); - } - else if( ACCESSING_BITS_16_31 ) - { - retval |= KEYCNT << 16; - } - break; - case 0x0200/4: - retval = IE | (IF << 16); - break; - default: - if( ACCESSING_BITS_0_15 ) - { - retval |= m_regs[offset] & 0x0000ffff; - } - if( ACCESSING_BITS_16_31 ) - { - retval |= m_regs[offset] & 0xffff0000; - } - break; - } - -// assert_always(offset < ARRAY_LENGTH(reg_names) / 2, "Not enough register names in gba_state"); - - if (ACCESSING_BITS_0_15) - { - verboselog(*this, 2, "GBA I/O Read: %s = %04x\n", reg_names[offset * 2], retval & 0x0000ffff); - } - if (ACCESSING_BITS_16_31) - { - verboselog(*this, 2, "GBA I/O Read: %s = %04x\n", reg_names[offset * 2 + 1], (retval & 0xffff0000) >> 16); - } - - return retval; -} - -void gba_state::gba_io_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - uint8_t soundcnt_x = SOUNDCNT_X; - uint16_t siocnt = SIOCNT; - uint16_t dmachcnt[4] = { DMACNT_H(0), DMACNT_H(1), DMACNT_H(2), DMACNT_H(3) }; - - COMBINE_DATA(&m_regs[offset]); - -// assert_always(offset < ARRAY_LENGTH(reg_names) / 2, "Not enough register names in gba_state"); - - if (ACCESSING_BITS_0_15) - { - verboselog(*this, 2, "GBA I/O Write: %s = %04x\n", reg_names[offset * 2], data & 0x0000ffff); - } - if (ACCESSING_BITS_16_31) - { - verboselog(*this, 2, "GBA I/O Write: %s = %04x\n", reg_names[offset * 2 + 1], (data & 0xffff0000) >> 16); - } - - switch( offset + 0x60/4 ) - { - case 0x0060/4: - if( ACCESSING_BITS_0_7 ) // SOUNDCNTL - { - m_gbsound->sound_w(0, data); - } - if( ACCESSING_BITS_16_23 ) - { - m_gbsound->sound_w(1, data>>16); // SOUND1CNT_H - } - if( ACCESSING_BITS_24_31 ) - { - m_gbsound->sound_w(2, data>>24); - } - break; - case 0x0064/4: - if( ACCESSING_BITS_0_7 ) // SOUNDCNTL - { - m_gbsound->sound_w(3, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(4, data>>8); // SOUND1CNT_H - } - break; - case 0x0068/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(6, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(7, data>>8); - } - break; - case 0x006c/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(8, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(9, data>>8); - } - break; - case 0x0070/4: //SND3CNTL and H - if( ACCESSING_BITS_0_7 ) // SOUNDCNTL - { - m_gbsound->sound_w(0xa, data); - } - if( ACCESSING_BITS_16_23 ) - { - m_gbsound->sound_w(0xb, data>>16); // SOUND1CNT_H - } - if( ACCESSING_BITS_24_31 ) - { - m_gbsound->sound_w(0xc, data>>24); - } - break; - case 0x0074/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(0xd, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(0xe, data>>8); - } - break; - case 0x0078/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(0x10, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(0x11, data>>8); - } - break; - case 0x007c/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(0x12, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(0x13, data>>8); - } - break; - case 0x0080/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(0x14, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->sound_w(0x15, data>>8); - } - - if (ACCESSING_BITS_16_31) - { - // DAC A reset? - if (data & 0x08000000) - { - m_fifo_a_ptr = 17; - m_fifo_a_in = 17; - m_ldaca->write(0); - m_rdaca->write(0); - } - - // DAC B reset? - if (data & 0x80000000) - { - m_fifo_b_ptr = 17; - m_fifo_b_in = 17; - m_ldacb->write(0); - m_rdacb->write(0); - } - } - break; - case 0x0084/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->sound_w(0x16, data); - if ((data & 0x80) && !(soundcnt_x & 0x80)) - { - m_fifo_a_ptr = m_fifo_a_in = 17; - m_fifo_b_ptr = m_fifo_b_in = 17; - m_ldaca->write(0); - m_rdaca->write(0); - m_ldacb->write(0); - m_rdacb->write(0); - } - } - break; - case 0x0090/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->wave_w(0, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->wave_w(1, data>>8); - } - if( ACCESSING_BITS_16_23 ) - { - m_gbsound->wave_w(2, data>>16); - } - if( ACCESSING_BITS_24_31 ) - { - m_gbsound->wave_w(3, data>>24); - } - break; - case 0x0094/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->wave_w(4, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->wave_w(5, data>>8); - } - if( ACCESSING_BITS_16_23 ) - { - m_gbsound->wave_w(6, data>>16); - } - if( ACCESSING_BITS_24_31 ) - { - m_gbsound->wave_w(7, data>>24); - } - break; - case 0x0098/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->wave_w(8, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->wave_w(9, data>>8); - } - if( ACCESSING_BITS_16_23 ) - { - m_gbsound->wave_w(0xa, data>>16); - } - if( ACCESSING_BITS_24_31 ) - { - m_gbsound->wave_w(0xb, data>>24); - } - break; - case 0x009c/4: - if( ACCESSING_BITS_0_7 ) - { - m_gbsound->wave_w(0xc, data); - } - if( ACCESSING_BITS_8_15 ) - { - m_gbsound->wave_w(0xd, data>>8); - } - if( ACCESSING_BITS_16_23 ) - { - m_gbsound->wave_w(0xe, data>>16); - } - if( ACCESSING_BITS_24_31 ) - { - m_gbsound->wave_w(0xf, data>>24); - } - break; - case 0x00a0/4: - if (ACCESSING_BITS_0_7) - { - m_fifo_a_in %= 17; - m_fifo_a[m_fifo_a_in++] = (data)&0xff; - } - if (ACCESSING_BITS_8_15) - { - m_fifo_a_in %= 17; - m_fifo_a[m_fifo_a_in++] = (data>>8)&0xff; - } - if (ACCESSING_BITS_16_23) - { - m_fifo_a_in %= 17; - m_fifo_a[m_fifo_a_in++] = (data>>16)&0xff; - } - if (ACCESSING_BITS_24_31) - { - m_fifo_a_in %= 17; - m_fifo_a[m_fifo_a_in++] = (data>>24)&0xff; - } - break; - case 0x00a4/4: - if (ACCESSING_BITS_0_7) - { - m_fifo_b_in %= 17; - m_fifo_b[m_fifo_b_in++] = (data)&0xff; - } - if (ACCESSING_BITS_8_15) - { - m_fifo_b_in %= 17; - m_fifo_b[m_fifo_b_in++] = (data>>8)&0xff; - } - if (ACCESSING_BITS_16_23) - { - m_fifo_b_in %= 17; - m_fifo_b[m_fifo_b_in++] = (data>>16)&0xff; - } - if (ACCESSING_BITS_24_31) - { - m_fifo_b_in %= 17; - m_fifo_b[m_fifo_b_in++] = (data>>24)&0xff; - } - break; - case 0x00b8/4: - case 0x00c4/4: - case 0x00d0/4: - case 0x00dc/4: - if( ACCESSING_BITS_16_31 ) - { - int ch = (offset + 0x60/4 - 0xb0/4) / 3; - - int ctrl = data>>16; - - // Note: Metroid Fusion fails if we enforce the "rising edge" requirement... (who wrote this note?) - - // Note: Caesar's Palace Advance fails if we DO NOT enforce the "rising edge" requirement - // (value @ 0x3003F9C is accidentally incremented because DMA completion interrupt is accidentally triggered @ 08002F2A) - - // retrigger/restart on a rising edge. - // also reload internal regs - if ((ctrl & 0x8000) && !(dmachcnt[ch] & 0x8000)) - { - m_dma_src[ch] = DMASAD(ch); - m_dma_dst[ch] = DMADAD(ch); - m_dma_cnt[ch] = DMACNT_L(ch); - - // immediate start - if ((ctrl & 0x3000) == 0) - { - dma_exec(ch); - return; - } - } - } - break; - case 0x0100/4: - case 0x0104/4: - case 0x0108/4: - case 0x010c/4: - { - double rate, clocksel; - uint32_t old_timer_regs; - - int timer = offset + 0x60/4 - 0x100/4; - - old_timer_regs = m_timer_regs[timer]; - - m_timer_regs[timer] = (m_timer_regs[timer] & ~(mem_mask & 0xFFFF0000)) | (data & (mem_mask & 0xFFFF0000)); - -// printf("%x to timer %d (mask %x PC %x)\n", data, timer, ~mem_mask, m_maincpu->pc()); - - if (ACCESSING_BITS_0_15) - { - m_timer_reload[timer] = ((m_timer_reload[timer] & ~mem_mask) | (data & mem_mask)) & 0x0000FFFF; - m_timer_recalc[timer] = 1; - } - - // enabling this timer? - if ((ACCESSING_BITS_16_31) && (data & 0x800000)) - { - double final; - - if ((old_timer_regs & 0x00800000) == 0) // start bit 0 -> 1 - { - m_timer_regs[timer] = (m_timer_regs[timer] & 0xFFFF0000) | (m_timer_reload[timer] & 0x0000FFFF); - } - - rate = 0x10000 - (m_timer_regs[timer] & 0xffff); - - clocksel = timer_clks[(m_timer_regs[timer] >> 16) & 3].dvalue(); - - final = clocksel / rate; - - m_timer_hz[timer] = final; - - m_timer_recalc[timer] = 0; - -// printf("Enabling timer %d @ %f Hz\n", timer, final); - - // enable the timer - if( !(data & 0x40000) ) // if we're not in Count-Up mode - { - attotime time = attotime::from_hz(final); - m_tmr_timer[timer]->adjust(time, timer, time); - } - } - } - break; - case 0x0128/4: - if( ACCESSING_BITS_0_15 ) - { - // normal mode ? - if (!(RCNT & 0x8000) && !(data & 0x2000)) - { - // start ? - if (!(siocnt & 0x0080) && (data & 0x0080)) - { - SIOCNT_RESET(0x0080); - // request interrupt ? - if (data & 0x4000) - { - request_irq(INT_SIO); - } - } - } - } - break; - case 0x0200/4: - if( ACCESSING_BITS_0_15 ) - { -#if 0 - if (IE & IF) - { - request_irq(IF); - } -#endif - } - if( ACCESSING_BITS_16_31 ) - { - IF_RESET(( data & mem_mask ) >> 16); - - // if we still have interrupts, yank the IRQ line again - if (IF) - { - m_irq_timer->adjust(m_maincpu->clocks_to_attotime(120)); - } - } - break; - case 0x0208/4: - if( ACCESSING_BITS_0_15 ) - { - if (IF) - { - m_irq_timer->adjust(attotime::zero); - } - } - break; - case 0x0300/4: - if( ACCESSING_BITS_8_15 ) - { - // power down commanded, halt the CPU - m_maincpu->spin_until_interrupt(); - } - break; - } -} - -uint32_t gba_state::gba_bios_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t *rom = m_region_maincpu; - if (m_bios_hack->read()) - { - // partially patch out logo and checksum checks - // (useful to run some protos + to test homebrew) - if (ACCESSING_BITS_0_15 && (offset == 0x6fc/4)) - return 0; - } - - if (m_maincpu->pc() >= 0x4000) - { - //printf("GBA protection: blocking PC=%x\n", m_maincpu->pc()); - return 0; - } - - return rom[offset & 0x3fff]; -} - -uint32_t gba_state::gba_10000000_r(offs_t offset, uint32_t mem_mask) -{ - auto &mspace = m_maincpu->space(AS_PROGRAM); - uint32_t data; - uint32_t pc = m_maincpu->state_int(ARM7_PC); - if (pc >= 0x10000000) - { - return 0; - } - uint32_t cpsr = m_maincpu->state_int(ARM7_CPSR); - if (T_IS_SET( cpsr)) - { - data = mspace.read_dword(pc + 8); - } - else - { - uint16_t insn = mspace.read_word(pc + 4); - data = (insn << 16) | (insn << 0); - } - logerror("%s: unmapped program memory read from %08X = %08X & %08X\n", machine().describe_context( ), 0x10000000 + (offset << 2), data, mem_mask); - return data; -} - -WRITE_LINE_MEMBER(gba_state::int_hblank_callback) -{ - request_irq(INT_HBL); -} - -WRITE_LINE_MEMBER(gba_state::int_vblank_callback) -{ - request_irq(INT_VBL); -} - -WRITE_LINE_MEMBER(gba_state::int_vcount_callback) -{ - request_irq(INT_VCNT); -} - -WRITE_LINE_MEMBER(gba_state::dma_hblank_callback) -{ - for (int ch = 0; ch < 4; ch++) - { - int ctrl = DMACNT_H(ch); - - if ((ctrl & 0x8000) && ((ctrl & 0x3000) == 0x2000)) - dma_exec(ch); - } -} - -WRITE_LINE_MEMBER(gba_state::dma_vblank_callback) -{ - for (int ch = 0; ch < 4; ch++) - { - int ctrl = DMACNT_H(ch); - - if ((ctrl & 0x8000) && ((ctrl & 0x3000) == 0x1000)) - dma_exec(ch); - } -} - -void gba_state::gba_map(address_map &map) -{ - map.unmap_value_high(); // for "Fruit Mura no Doubutsu Tachi" and "Classic NES Series" - map(0x00000000, 0x00003fff).rom().mirror(0x01ffc000).r(FUNC(gba_state::gba_bios_r)); - map(0x02000000, 0x0203ffff).ram().mirror(0xfc0000); - map(0x03000000, 0x03007fff).ram().mirror(0xff8000); - map(0x04000000, 0x0400005f).rw("lcd", FUNC(gba_lcd_device::video_r), FUNC(gba_lcd_device::video_w)); - map(0x04000060, 0x040003ff).rw(FUNC(gba_state::gba_io_r), FUNC(gba_state::gba_io_w)); - map(0x04000400, 0x04ffffff).noprw(); // Not used - map(0x05000000, 0x050003ff).mirror(0x00fffc00).rw("lcd", FUNC(gba_lcd_device::gba_pram_r), FUNC(gba_lcd_device::gba_pram_w)); // Palette RAM - map(0x06000000, 0x06017fff).mirror(0x00fe0000).rw("lcd", FUNC(gba_lcd_device::gba_vram_r), FUNC(gba_lcd_device::gba_vram_w)); // VRAM - map(0x06018000, 0x0601ffff).mirror(0x00fe0000).rw("lcd", FUNC(gba_lcd_device::gba_vram_r), FUNC(gba_lcd_device::gba_vram_w)); // VRAM - map(0x07000000, 0x070003ff).mirror(0x00fffc00).rw("lcd", FUNC(gba_lcd_device::gba_oam_r), FUNC(gba_lcd_device::gba_oam_w)); // OAM - //map(0x08000000, 0x0cffffff) // cart ROM + mirrors, mapped here at machine_start if a cart is present - map(0x10000000, 0xffffffff).r(FUNC(gba_state::gba_10000000_r)); // for "Justice League Chronicles" (game bug) -} - -static INPUT_PORTS_START( gbadv ) - PORT_START("INPUTS") - PORT_BIT( 0xfc00, IP_ACTIVE_HIGH, IPT_UNUSED) - PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 L") PORT_PLAYER(1) // L - PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 R") PORT_PLAYER(1) // R - PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) - PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) - PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) - PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) - PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) // START - PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_PLAYER(1) // SELECT - PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("B") PORT_PLAYER(1) // B - PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("A") PORT_PLAYER(1) // A - - PORT_START("SKIP_CHECK") - PORT_CONFNAME( 0x01, 0x00, "[HACK] Skip BIOS Logo check" ) - PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) - PORT_CONFSETTING( 0x01, DEF_STR( On ) ) -INPUT_PORTS_END - - -void gba_state::machine_reset() -{ - memset(m_regs, 0, sizeof(m_regs)); - - SOUNDBIAS_SET(0x0200); - SIOMULTI0_SET(0xffff); - SIOMULTI1_SET(0xffff); - SIOMULTI2_SET(0xffff); - SIOMULTI3_SET(0xffff); - KEYCNT_SET(0x03ff); - RCNT_SET(0x8000); - JOYSTAT_SET(0x0002); - - m_dma_timer[0]->adjust(attotime::never); - m_dma_timer[1]->adjust(attotime::never, 1); - m_dma_timer[2]->adjust(attotime::never, 2); - m_dma_timer[3]->adjust(attotime::never, 3); - - m_fifo_a_ptr = m_fifo_b_ptr = 17; // indicate empty - m_fifo_a_in = m_fifo_b_in = 17; - - // and clear the DACs - m_ldaca->write(0); - m_rdaca->write(0); - m_ldacb->write(0); - m_rdacb->write(0); -} - -void gba_state::machine_start() -{ - /* and one for each DMA channel */ - m_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::dma_complete),this)); - m_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::dma_complete),this)); - m_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::dma_complete),this)); - m_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::dma_complete),this)); - m_dma_timer[0]->adjust(attotime::never); - m_dma_timer[1]->adjust(attotime::never, 1); - m_dma_timer[2]->adjust(attotime::never, 2); - m_dma_timer[3]->adjust(attotime::never, 3); - - /* also one for each timer (heh) */ - m_tmr_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::timer_expire),this)); - m_tmr_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::timer_expire),this)); - m_tmr_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::timer_expire),this)); - m_tmr_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::timer_expire),this)); - m_tmr_timer[0]->adjust(attotime::never); - m_tmr_timer[1]->adjust(attotime::never, 1); - m_tmr_timer[2]->adjust(attotime::never, 2); - m_tmr_timer[3]->adjust(attotime::never, 3); - - /* and an IRQ handling timer */ - m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gba_state::handle_irq),this)); - m_irq_timer->adjust(attotime::never); - - // install the cart ROM & SRAM into the address map, if present - if (m_cart->exists()) - { - m_maincpu->space(AS_PROGRAM).install_read_bank(0x08000000, 0x09ffffff, "rom1"); - m_maincpu->space(AS_PROGRAM).install_read_bank(0x0a000000, 0x0bffffff, "rom2"); - m_maincpu->space(AS_PROGRAM).install_read_bank(0x0c000000, 0x0cffffff, "rom3"); - - std::string region_tag; - memory_region *cart_rom = memregion(region_tag.assign(m_cart->tag()).append(GBASLOT_ROM_REGION_TAG)); - - // install ROM accesses - membank("rom1")->set_base(cart_rom->base()); - membank("rom2")->set_base(cart_rom->base()); - membank("rom3")->set_base(cart_rom->base()); - - m_maincpu->space(AS_PROGRAM).install_read_handler(0x80000c4, 0x80000cb, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_gpio))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0x80000c4, 0x80000cb, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_gpio))); - - // add nvram to save state - m_cart->save_nvram(); - - // install the cart NVRAM handlers if necessary - if (m_cart->get_type() == GBA_SRAM || m_cart->get_type() == GBA_DRILLDOZ || m_cart->get_type() == GBA_WARIOTWS) - { - m_maincpu->space(AS_PROGRAM).install_read_handler(0xe000000, 0xe00ffff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xe000000, 0xe00ffff, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_ram))); - m_maincpu->space(AS_PROGRAM).install_read_handler(0xe010000, 0xe01ffff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xe010000, 0xe01ffff, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_ram))); - } - if (m_cart->get_type() == GBA_EEPROM || m_cart->get_type() == GBA_EEPROM4 || m_cart->get_type() == GBA_EEPROM64 || m_cart->get_type() == GBA_BOKTAI) - { - // for games larger than 16MB the actual range is smaller but read_ram/write_ram handles that! - m_maincpu->space(AS_PROGRAM).install_read_handler(0xd000000, 0xdffffff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xd000000, 0xdffffff, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_ram))); - } - if (m_cart->get_type() == GBA_YOSHIUG) - { - // EEPROM - m_maincpu->space(AS_PROGRAM).install_read_handler(0xd000000, 0xdffffff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xd000000, 0xdffffff, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_ram))); - // Tilt Sensor - m_maincpu->space(AS_PROGRAM).install_read_handler(0xe008000, 0xe0085ff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_tilt))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xe008000, 0xe0085ff, write32sm_delegate(*m_cart, FUNC(gba_cart_slot_device::write_tilt))); - } - // merge the two flash and mask accesses in read_ram?!? - if (m_cart->get_type() == GBA_FLASH || m_cart->get_type() == GBA_FLASH512 || m_cart->get_type() == GBA_FLASH_RTC) - { - m_maincpu->space(AS_PROGRAM).install_read_handler(0xe000000, 0xe00ffff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xe000000, 0xe00ffff, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_ram))); - } - if (m_cart->get_type() == GBA_FLASH1M || m_cart->get_type() == GBA_FLASH1M_RTC) - { - m_maincpu->space(AS_PROGRAM).install_read_handler(0xe000000, 0xe01ffff, read32s_delegate(*m_cart, FUNC(gba_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0xe000000, 0xe01ffff, write32s_delegate(*m_cart, FUNC(gba_cart_slot_device::write_ram))); - } - if (m_cart->get_type() == GBA_3DMATRIX) - { - m_maincpu->space(AS_PROGRAM).install_write_handler(0x08800000, 0x088001ff, write32sm_delegate(*m_cart, FUNC(gba_cart_slot_device::write_mapper))); - memory_region *cart_romhlp = memregion(region_tag.assign(m_cart->tag()).append(GBAHELP_ROM_REGION_TAG)); - membank("rom1")->set_base(cart_romhlp->base()); - } - - } - - save_item(NAME(m_regs)); - save_item(NAME(m_dma_src)); - save_item(NAME(m_dma_dst)); - save_item(NAME(m_dma_cnt)); - save_item(NAME(m_timer_regs)); - save_item(NAME(m_timer_reload)); - save_item(NAME(m_timer_recalc)); - save_item(NAME(m_timer_hz)); - save_item(NAME(m_fifo_a_ptr)); - save_item(NAME(m_fifo_b_ptr)); - save_item(NAME(m_fifo_a_in)); - save_item(NAME(m_fifo_b_in)); - save_item(NAME(m_fifo_a)); - save_item(NAME(m_fifo_b)); -} - - -static void gba_cart(device_slot_interface &device) -{ - device.option_add_internal("gba_rom", GBA_ROM_STD); - device.option_add_internal("gba_sram", GBA_ROM_SRAM); - device.option_add_internal("gba_drilldoz", GBA_ROM_DRILLDOZ); // Rumble output unemulated - device.option_add_internal("gba_wariotws", GBA_ROM_WARIOTWS); // Rumble output unemulated - device.option_add_internal("gba_eeprom", GBA_ROM_EEPROM); - device.option_add_internal("gba_eeprom_4k", GBA_ROM_EEPROM); - device.option_add_internal("gba_yoshiug", GBA_ROM_YOSHIUG); - device.option_add_internal("gba_eeprom_64k", GBA_ROM_EEPROM64); - device.option_add_internal("gba_boktai", GBA_ROM_BOKTAI); - device.option_add_internal("gba_flash", GBA_ROM_FLASH); // Panasonic - device.option_add_internal("gba_flash_rtc", GBA_ROM_FLASH_RTC); // Panasonic - device.option_add_internal("gba_flash_512", GBA_ROM_FLASH); // Panasonic - device.option_add_internal("gba_flash_1m", GBA_ROM_FLASH1M); // Sanyo - device.option_add_internal("gba_flash_1m_rtc", GBA_ROM_FLASH1M_RTC); // Sanyo - device.option_add_internal("gba_3dmatrix", GBA_ROM_3DMATRIX); -} - - -void gba_state::gbadv(machine_config &config) -{ - ARM7(config, m_maincpu, XTAL(16'777'216)); - m_maincpu->set_addrmap(AS_PROGRAM, &gba_state::gba_map); - - gba_lcd_device &lcd(GBA_LCD(config, "lcd", 0)); - lcd.int_hblank_callback().set(FUNC(gba_state::int_hblank_callback)); - lcd.int_vblank_callback().set(FUNC(gba_state::int_vblank_callback)); - lcd.int_vcount_callback().set(FUNC(gba_state::int_vcount_callback)); - lcd.dma_hblank_callback().set(FUNC(gba_state::dma_hblank_callback)); - lcd.dma_vblank_callback().set(FUNC(gba_state::dma_vblank_callback)); - - SPEAKER(config, "lspeaker").front_left(); - SPEAKER(config, "rspeaker").front_right(); - CGB04_APU(config, m_gbsound, XTAL(16'777'216)/4); - m_gbsound->add_route(0, "lspeaker", 0.5); - m_gbsound->add_route(1, "rspeaker", 0.5); - - DAC_8BIT_R2R_TWOS_COMPLEMENT(config, m_ldaca, 0).add_route(ALL_OUTPUTS, "lspeaker", 0.5); // unknown DAC - DAC_8BIT_R2R_TWOS_COMPLEMENT(config, m_rdaca, 0).add_route(ALL_OUTPUTS, "rspeaker", 0.5); // unknown DAC - DAC_8BIT_R2R_TWOS_COMPLEMENT(config, m_ldacb, 0).add_route(ALL_OUTPUTS, "lspeaker", 0.5); // unknown DAC - DAC_8BIT_R2R_TWOS_COMPLEMENT(config, m_rdacb, 0).add_route(ALL_OUTPUTS, "rspeaker", 0.5); // unknown DAC - - GBA_CART_SLOT(config, m_cart, gba_cart, nullptr); - SOFTWARE_LIST(config, "cart_list").set_original("gba"); -} - - -ROM_START( gba ) - ROM_REGION( 0x4000, "maincpu", 0 ) - ROM_LOAD( "gba.bin", 0x000000, 0x004000, CRC(81977335) SHA1(300c20df6731a33952ded8c436f7f186d25d3492) ) -ROM_END - - -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -CONS(2001, gba, 0, 0, gbadv, gbadv, gba_state, empty_init, "Nintendo", "Game Boy Advance", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND) |