diff --git a/src/devices/video/gba_lcd.cpp b/src/devices/video/gba_lcd.cpp index 0c70f76b84f..e3af8236da6 100644 --- a/src/devices/video/gba_lcd.cpp +++ b/src/devices/video/gba_lcd.cpp @@ -15,8 +15,6 @@ #include "gba_lcd.h" -#include "includes/gba.h" // this is a dependency from src/devices to src/mame which is very bad and should be fixed - /* LCD I/O Registers */ #define DISPCNT HWLO(0x000) /* 0x4000000 2 R/W LCD Control */ #define GRNSWAP HWHI(0x000) /* 0x4000002 2 R/W Undocumented - Green Swap */ @@ -253,8 +251,13 @@ static inline UINT32 decrease_brightness(UINT32 color, int coeff_) const device_type GBA_LCD = &device_creator; gba_lcd_device::gba_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, GBA_LCD, "GBA LCD", tag, owner, clock, "gba_lcd", __FILE__), - device_video_interface(mconfig, *this) + : device_t(mconfig, GBA_LCD, "GBA LCD", tag, owner, clock, "gba_lcd", __FILE__) + , device_video_interface(mconfig, *this) + , m_int_hblank_cb(*this) + , m_int_vblank_cb(*this) + , m_int_vcount_cb(*this) + , m_dma_hblank_cb(*this) + , m_dma_vblank_cb(*this) { } @@ -2216,12 +2219,14 @@ TIMER_CALLBACK_MEMBER(gba_lcd_device::perform_hbl) { draw_scanline(scanline); - machine().driver_data()->request_dma(gba_state::dma_start_timing::hblank); + if (!m_dma_hblank_cb.isnull()) + m_dma_hblank_cb(ASSERT_LINE); } if ((DISPSTAT & DISPSTAT_HBL_IRQ_EN ) != 0) { - machine().driver_data()->request_irq(INT_HBL); + if (!m_int_hblank_cb.isnull()) + m_int_hblank_cb(ASSERT_LINE); } DISPSTAT_SET(DISPSTAT_HBL); @@ -2246,10 +2251,12 @@ TIMER_CALLBACK_MEMBER(gba_lcd_device::perform_scan) { if (DISPSTAT & DISPSTAT_VBL_IRQ_EN) { - machine().driver_data()->request_irq(INT_VBL); + if (!m_int_vblank_cb.isnull()) + m_int_vblank_cb(ASSERT_LINE); } - machine().driver_data()->request_dma(gba_state::dma_start_timing::vblank); + if (!m_dma_vblank_cb.isnull()) + m_dma_vblank_cb(ASSERT_LINE); } } else @@ -2264,7 +2271,8 @@ TIMER_CALLBACK_MEMBER(gba_lcd_device::perform_scan) if (DISPSTAT & DISPSTAT_VCNT_IRQ_EN) { - machine().driver_data()->request_irq(INT_VCNT); + if (!m_int_vcount_cb.isnull()) + m_int_vcount_cb(ASSERT_LINE); } } @@ -2294,6 +2302,13 @@ UINT32 gba_lcd_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap void gba_lcd_device::device_start() { + /* resolve callbacks */ + m_int_hblank_cb.resolve(); + m_int_vblank_cb.resolve(); + m_int_vcount_cb.resolve(); + m_dma_hblank_cb.resolve(); + m_dma_vblank_cb.resolve(); + m_pram = make_unique_clear(0x400 / 4); m_vram = make_unique_clear(0x18000 / 4); m_oam = make_unique_clear(0x400 / 4); diff --git a/src/devices/video/gba_lcd.h b/src/devices/video/gba_lcd.h index 8b36dcfeaca..6ca7405f7cb 100644 --- a/src/devices/video/gba_lcd.h +++ b/src/devices/video/gba_lcd.h @@ -34,6 +34,21 @@ extern const device_type GBA_LCD; #define MCFG_GBA_LCD_ADD(_tag) \ MCFG_DEVICE_ADD(_tag, GBA_LCD, 0) +#define MCFG_GBA_LCD_INT_HBLANK(_devcb) \ + devcb = &gba_lcd_device::set_int_hblank_callback(*device, DEVCB_##_devcb); + +#define MCFG_GBA_LCD_INT_VBLANK(_devcb) \ + devcb = &gba_lcd_device::set_int_vblank_callback(*device, DEVCB_##_devcb); + +#define MCFG_GBA_LCD_INT_VCOUNT(_devcb) \ + devcb = &gba_lcd_device::set_int_vcount_callback(*device, DEVCB_##_devcb); + +#define MCFG_GBA_LCD_DMA_HBLANK(_devcb) \ + devcb = &gba_lcd_device::set_dma_hblank_callback(*device, DEVCB_##_devcb); + +#define MCFG_GBA_LCD_DMA_VBLANK(_devcb) \ + devcb = &gba_lcd_device::set_dma_vblank_callback(*device, DEVCB_##_devcb); + //************************************************************************** // TYPE DEFINITIONS @@ -84,6 +99,31 @@ public: TIMER_CALLBACK_MEMBER(perform_hbl); TIMER_CALLBACK_MEMBER(perform_scan); + template static devcb_base &set_int_hblank_callback(device_t &device, _Object object) + { + return downcast(device).m_int_hblank_cb.set_callback(object); + } + + template static devcb_base &set_int_vblank_callback(device_t &device, _Object object) + { + return downcast(device).m_int_vblank_cb.set_callback(object); + } + + template static devcb_base &set_int_vcount_callback(device_t &device, _Object object) + { + return downcast(device).m_int_vcount_cb.set_callback(object); + } + + template static devcb_base &set_dma_hblank_callback(device_t &device, _Object object) + { + return downcast(device).m_dma_hblank_cb.set_callback(object); + } + + template static devcb_base &set_dma_vblank_callback(device_t &device, _Object object) + { + return downcast(device).m_dma_vblank_cb.set_callback(object); + } + protected: // device-level overrides virtual void device_start() override; @@ -101,6 +141,12 @@ private: inline int is_in_window(int x, int window); void draw_scanline(int y); + devcb_write_line m_int_hblank_cb; /* H-Blank interrupt callback function */ + devcb_write_line m_int_vblank_cb; /* V-Blank interrupt callback function */ + devcb_write_line m_int_vcount_cb; /* V-Counter Match interrupt callback function */ + devcb_write_line m_dma_hblank_cb; /* H-Blank DMA request callback function */ + devcb_write_line m_dma_vblank_cb; /* V-Blank DMA request callback function */ + std::unique_ptr m_pram; std::unique_ptr m_vram; std::unique_ptr m_oam; diff --git a/src/mame/drivers/gba.cpp b/src/mame/drivers/gba.cpp index ab4354e62ff..ff49c4fe127 100644 --- a/src/mame/drivers/gba.cpp +++ b/src/mame/drivers/gba.cpp @@ -99,6 +99,21 @@ #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, ...) @@ -135,34 +150,6 @@ void gba_state::request_irq(UINT32 int_type) } } -void gba_state::request_dma(dma_start_timing start) -{ - UINT16 mask = 0x0000; - switch (start) - { - case immediately: - mask = 0x0000; - break; - case vblank: - mask = 0x1000; - break; - case hblank: - mask = 0x2000; - break; - case special: - mask = 0x3000; - break; - } - - for (int ch = 0; ch < 4; ch++) - { - int ctrl = DMACNT_H(ch); - - if ((ctrl & 0x8000) && ((ctrl & 0x3000) == mask)) - dma_exec(ch); - } -} - TIMER_CALLBACK_MEMBER(gba_state::dma_complete) { static const UINT32 ch_int[4] = { INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3 }; @@ -1178,6 +1165,43 @@ READ32_MEMBER(gba_state::gba_10000000_r) 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); + } +} + static ADDRESS_MAP_START( gba_map, AS_PROGRAM, 32, gba_state ) ADDRESS_MAP_UNMAP_HIGH // for "Fruit Mura no Doubutsu Tachi" and "Classic NES Series" AM_RANGE(0x00000000, 0x00003fff) AM_ROM AM_READ(gba_bios_r) @@ -1377,6 +1401,11 @@ static MACHINE_CONFIG_START( gbadv, gba_state ) MCFG_CPU_PROGRAM_MAP(gba_map) MCFG_GBA_LCD_ADD("lcd") + MCFG_GBA_LCD_INT_HBLANK(WRITELINE(gba_state, int_hblank_callback)) + MCFG_GBA_LCD_INT_VBLANK(WRITELINE(gba_state, int_vblank_callback)) + MCFG_GBA_LCD_INT_VCOUNT(WRITELINE(gba_state, int_vcount_callback)) + MCFG_GBA_LCD_DMA_HBLANK(WRITELINE(gba_state, dma_hblank_callback)) + MCFG_GBA_LCD_DMA_VBLANK(WRITELINE(gba_state, dma_vblank_callback)) MCFG_SPEAKER_STANDARD_STEREO("spkleft", "spkright") MCFG_SOUND_ADD("custom", GAMEBOY, 0) diff --git a/src/mame/includes/gba.h b/src/mame/includes/gba.h index 254040e56fd..efb8406778d 100644 --- a/src/mame/includes/gba.h +++ b/src/mame/includes/gba.h @@ -9,22 +9,7 @@ #include "sound/dac.h" #include "video/gba_lcd.h" -#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 -/* driver state */ class gba_state : public driver_device, protected gba_registers<(0x400 - 0x060) / 4, 0x060> { public: @@ -52,14 +37,6 @@ public: void request_irq(UINT32 int_type); - enum dma_start_timing { - immediately = 0, - vblank, - hblank, - special - }; - - void request_dma(dma_start_timing start); void dma_exec(int ch); void audio_tick(int ref); @@ -94,6 +71,11 @@ public: DECLARE_READ32_MEMBER(gba_bios_r); DECLARE_READ32_MEMBER(gba_10000000_r); DECLARE_DRIVER_INIT(gbadv); + DECLARE_WRITE_LINE_MEMBER(int_hblank_callback); + DECLARE_WRITE_LINE_MEMBER(int_vblank_callback); + DECLARE_WRITE_LINE_MEMBER(int_vcount_callback); + DECLARE_WRITE_LINE_MEMBER(dma_hblank_callback); + DECLARE_WRITE_LINE_MEMBER(dma_vblank_callback); virtual void machine_start() override; virtual void machine_reset() override; TIMER_CALLBACK_MEMBER(dma_complete);