mirror of
https://github.com/holub/mame
synced 2025-04-24 09:20:02 +03:00
gba: decouple video device from main machine state using callbacks
This commit is contained in:
parent
a942ce2004
commit
0f4337d6a6
@ -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::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<gba_state>()->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<gba_state>()->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<gba_state>()->request_irq(INT_VBL);
|
||||
if (!m_int_vblank_cb.isnull())
|
||||
m_int_vblank_cb(ASSERT_LINE);
|
||||
}
|
||||
|
||||
machine().driver_data<gba_state>()->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<gba_state>()->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<UINT32[]>(0x400 / 4);
|
||||
m_vram = make_unique_clear<UINT32[]>(0x18000 / 4);
|
||||
m_oam = make_unique_clear<UINT32[]>(0x400 / 4);
|
||||
|
@ -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<class _Object> static devcb_base &set_int_hblank_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<gba_lcd_device &>(device).m_int_hblank_cb.set_callback(object);
|
||||
}
|
||||
|
||||
template<class _Object> static devcb_base &set_int_vblank_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<gba_lcd_device &>(device).m_int_vblank_cb.set_callback(object);
|
||||
}
|
||||
|
||||
template<class _Object> static devcb_base &set_int_vcount_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<gba_lcd_device &>(device).m_int_vcount_cb.set_callback(object);
|
||||
}
|
||||
|
||||
template<class _Object> static devcb_base &set_dma_hblank_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<gba_lcd_device &>(device).m_dma_hblank_cb.set_callback(object);
|
||||
}
|
||||
|
||||
template<class _Object> static devcb_base &set_dma_vblank_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<gba_lcd_device &>(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<UINT32[]> m_pram;
|
||||
std::unique_ptr<UINT32[]> m_vram;
|
||||
std::unique_ptr<UINT32[]> m_oam;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user