mirror of
https://github.com/holub/mame
synced 2025-04-25 17:56:43 +03:00
gb.cpp: Some cpu, sound, and video updates (nw)
This commit is contained in:
parent
8566a1fd10
commit
c3e0ead534
@ -25823,7 +25823,7 @@ more investigation needed...
|
||||
<feature name="led2" value="LED2" /> <!-- green, connected to CN2? -->
|
||||
<feature name="cart_model" value="SHVC-042" />
|
||||
<feature name="cart_back_label" value="SHVC-SGB2-JPN" />
|
||||
<feature name="slot" value="lorom_sgb" />
|
||||
<feature name="slot" value="lorom_sgb2" />
|
||||
<dataarea name="rom" size="524288">
|
||||
<rom name="sys-sgb2-10.u4" size="524288" crc="cb176e45" sha1="e5b2922ca137051059e4269b236d07a22c07bc84" offset="0x000000" />
|
||||
</dataarea>
|
||||
|
@ -19,15 +19,17 @@
|
||||
// sns_rom_sgb_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
const device_type SNS_LOROM_SUPERGB = &device_creator<sns_rom_sgb_device>;
|
||||
const device_type SNS_LOROM_SUPERGB = &device_creator<sns_rom_sgb1_device>;
|
||||
const device_type SNS_LOROM_SUPERGB2 = &device_creator<sns_rom_sgb2_device>;
|
||||
|
||||
|
||||
sns_rom_sgb_device::sns_rom_sgb_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
|
||||
sns_rom_device(mconfig, SNS_LOROM_SUPERGB, "SNES Super Game Boy Cart", tag, owner, clock, "sns_rom_sgb", __FILE__),
|
||||
m_gb_cpu(*this, "sgb_cpu"),
|
||||
m_gb_snd(*this, "sgb_snd"),
|
||||
m_gb_lcd(*this, "sgb_lcd"),
|
||||
sns_rom_sgb_device::sns_rom_sgb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
|
||||
: sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||
m_sgb_cpu(*this, "sgb_cpu"),
|
||||
m_sgb_apu(*this, "sgb_apu"),
|
||||
m_sgb_ppu(*this, "sgb_ppu"),
|
||||
m_cartslot(*this, "gb_slot"),
|
||||
m_region_bios(*this, "sgb_cpu"),
|
||||
m_sgb_ly(0),
|
||||
m_sgb_row(0),
|
||||
m_vram(0),
|
||||
@ -39,7 +41,20 @@ sns_rom_sgb_device::sns_rom_sgb_device(const machine_config& mconfig, const char
|
||||
m_vram_offs(0),
|
||||
m_mlt_req(0),
|
||||
m_lcd_row(0),
|
||||
m_packetsize(0)
|
||||
m_packetsize(0),
|
||||
m_bios_disabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
sns_rom_sgb1_device::sns_rom_sgb1_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
|
||||
sns_rom_sgb_device(mconfig, SNS_LOROM_SUPERGB, "SNES Super Game Boy Cart", tag, owner, clock, "sns_rom_sgb", __FILE__)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
sns_rom_sgb2_device::sns_rom_sgb2_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
|
||||
sns_rom_sgb_device(mconfig, SNS_LOROM_SUPERGB2, "SNES Super Game Boy 2 Cart", tag, owner, clock, "sns_rom_sgb2", __FILE__)
|
||||
{
|
||||
}
|
||||
|
||||
@ -62,6 +77,10 @@ void sns_rom_sgb_device::device_reset()
|
||||
|
||||
READ8_MEMBER(sns_rom_sgb_device::gb_cart_r)
|
||||
{
|
||||
if (offset < 0x100 && !m_bios_disabled)
|
||||
{
|
||||
return m_region_bios->base()[offset];
|
||||
}
|
||||
return m_cartslot->read_rom(space, offset);
|
||||
}
|
||||
|
||||
@ -101,12 +120,12 @@ WRITE8_MEMBER(sns_rom_sgb_device::gb_io_w)
|
||||
|
||||
READ8_MEMBER(sns_rom_sgb_device::gb_ie_r)
|
||||
{
|
||||
return m_gb_cpu->get_ie();
|
||||
return m_sgb_cpu->get_ie();
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(sns_rom_sgb_device::gb_ie_w)
|
||||
{
|
||||
m_gb_cpu->set_ie(data & 0x1f);
|
||||
m_sgb_cpu->set_ie(data);
|
||||
}
|
||||
|
||||
|
||||
@ -114,16 +133,16 @@ WRITE8_MEMBER(sns_rom_sgb_device::gb_ie_w)
|
||||
static ADDRESS_MAP_START(supergb_map, AS_PROGRAM, 8, sns_rom_sgb_device )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("sgb_ppu", sgb_ppu_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w ) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w) /* echo RAM */
|
||||
AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w)
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("sgb_ppu", sgb_ppu_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("sgb_snd", gameboy_sound_device, sound_r, sound_w) /* sound registers */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("sgb_apu", gameboy_sound_device, sound_r, sound_w) /* sound registers */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("sgb_snd", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, video_r, video_w) /* also disable bios?? */ /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("sgb_apu", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_DEVREADWRITE("sgb_ppu", sgb_ppu_device, video_r, video_w) /* also disable bios?? */ /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
@ -140,26 +159,71 @@ static SLOT_INTERFACE_START(supergb_cart)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc1", GB_ROM_MBC1)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( supergb )
|
||||
MCFG_CPU_ADD("sgb_cpu", LR35902, 4295454) /* 4.295454 MHz */
|
||||
MCFG_CPU_PROGRAM_MAP(supergb_map)
|
||||
MCFG_LR35902_TIMER_CB(WRITE8(sns_rom_sgb_device, gb_timer_callback))
|
||||
MCFG_LR35902_HALT_BUG
|
||||
|
||||
MCFG_GB_LCD_SGB_ADD("sgb_lcd")
|
||||
MCFG_SGB_PPU_ADD("sgb_ppu", "sgb_cpu")
|
||||
|
||||
MCFG_SOUND_ADD("sgb_snd", GAMEBOY, 0)
|
||||
MCFG_SOUND_ADD("sgb_apu", DMG_APU, 4295454)
|
||||
|
||||
MCFG_GB_CARTRIDGE_ADD("gb_slot", supergb_cart, nullptr)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
machine_config_constructor sns_rom_sgb_device::device_mconfig_additions() const
|
||||
machine_config_constructor sns_rom_sgb1_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( supergb );
|
||||
}
|
||||
|
||||
|
||||
ROM_START( supergb )
|
||||
ROM_REGION(0x100, "sgb_cpu", 0)
|
||||
ROM_LOAD("sgb_boot.bin", 0x0000, 0x0100, CRC(ec8a83b9) SHA1(aa2f50a77dfb4823da96ba99309085a3c6278515))
|
||||
ROM_END
|
||||
|
||||
|
||||
const tiny_rom_entry *sns_rom_sgb1_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( supergb );
|
||||
}
|
||||
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( supergb2 )
|
||||
MCFG_CPU_ADD("sgb_cpu", LR35902, XTAL_4_194304Mhz) /* 4.194MHz derived from clock on sgb2 pcb */
|
||||
MCFG_CPU_PROGRAM_MAP(supergb_map)
|
||||
MCFG_LR35902_TIMER_CB(WRITE8(sns_rom_sgb_device, gb_timer_callback))
|
||||
MCFG_LR35902_HALT_BUG
|
||||
|
||||
MCFG_SGB_PPU_ADD("sgb_ppu", "sgb_cpu")
|
||||
|
||||
MCFG_SOUND_ADD("sgb_apu", DMG_APU, XTAL_4_194304Mhz)
|
||||
|
||||
MCFG_GB_CARTRIDGE_ADD("gb_slot", supergb_cart, nullptr)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
machine_config_constructor sns_rom_sgb2_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( supergb2 );
|
||||
}
|
||||
|
||||
|
||||
ROM_START( supergb2 )
|
||||
ROM_REGION(0x100, "sgb_cpu", 0)
|
||||
ROM_LOAD("sgb2_boot.bin", 0x0000, 0x0100, CRC(53d0dd63) SHA1(93407ea10d2f30ab96a314d8eca44fe160aea734))
|
||||
ROM_END
|
||||
|
||||
|
||||
const tiny_rom_entry *sns_rom_sgb2_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( supergb2 );
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
mapper specific handlers
|
||||
-------------------------------------------------*/
|
||||
|
@ -20,12 +20,11 @@ class sns_rom_sgb_device : public sns_rom_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
sns_rom_sgb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
sns_rom_sgb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_l) override;
|
||||
@ -45,10 +44,12 @@ public:
|
||||
virtual DECLARE_WRITE8_MEMBER(gb_ie_w);
|
||||
virtual DECLARE_WRITE8_MEMBER(gb_timer_callback);
|
||||
|
||||
required_device<lr35902_cpu_device> m_gb_cpu;
|
||||
required_device<gameboy_sound_device> m_gb_snd;
|
||||
required_device<sgb_lcd_device> m_gb_lcd;
|
||||
protected:
|
||||
required_device<lr35902_cpu_device> m_sgb_cpu;
|
||||
required_device<gameboy_sound_device> m_sgb_apu;
|
||||
required_device<sgb_ppu_device> m_sgb_ppu;
|
||||
required_device<gb_cart_slot_device> m_cartslot;
|
||||
required_memory_region m_region_bios;
|
||||
|
||||
void lcd_render(UINT32 *source);
|
||||
|
||||
@ -69,10 +70,36 @@ public:
|
||||
// input bits
|
||||
int m_packetsize;
|
||||
UINT8 m_packet_data[64][16];
|
||||
|
||||
bool m_bios_disabled;
|
||||
};
|
||||
|
||||
|
||||
class sns_rom_sgb1_device : public sns_rom_sgb_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
sns_rom_sgb1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
};
|
||||
|
||||
|
||||
class sns_rom_sgb2_device : public sns_rom_sgb_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
sns_rom_sgb2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type SNS_LOROM_SUPERGB;
|
||||
extern const device_type SNS_LOROM_SUPERGB2;
|
||||
|
||||
#endif
|
||||
|
@ -19,6 +19,7 @@ SLOT_INTERFACE_START(snes_cart)
|
||||
SLOT_INTERFACE_INTERNAL("lorom_sdd1", SNS_LOROM_SDD1)
|
||||
SLOT_INTERFACE_INTERNAL("lorom_sfx", SNS_LOROM_SUPERFX)
|
||||
SLOT_INTERFACE_INTERNAL("lorom_sgb", SNS_LOROM_SUPERGB) // SuperGB base cart - unsupported
|
||||
SLOT_INTERFACE_INTERNAL("lorom_sgb2", SNS_LOROM_SUPERGB2) // SuperGB2 base cart - unsupported
|
||||
SLOT_INTERFACE_INTERNAL("lorom_st010", SNS_LOROM_SETA10)
|
||||
SLOT_INTERFACE_INTERNAL("lorom_st011", SNS_LOROM_SETA11)
|
||||
SLOT_INTERFACE_INTERNAL("lorom_st018", SNS_LOROM) // Cart + ST018 - unsupported
|
||||
|
@ -80,6 +80,7 @@ lr35902_cpu_device::lr35902_cpu_device(const machine_config &mconfig, const char
|
||||
, m_IF(0)
|
||||
, m_enable(0)
|
||||
, m_has_halt_bug(false)
|
||||
, m_entering_halt(false)
|
||||
, m_timer_func(*this)
|
||||
, m_incdec16_func(*this)
|
||||
{
|
||||
@ -156,7 +157,7 @@ void lr35902_cpu_device::device_start()
|
||||
save_item(NAME(m_gb_speed));
|
||||
save_item(NAME(m_gb_speed_change_pending));
|
||||
save_item(NAME(m_enable));
|
||||
save_item(NAME(m_handle_halt_bug));
|
||||
save_item(NAME(m_entering_halt));
|
||||
|
||||
// Register state for debugger
|
||||
state_add( LR35902_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X");
|
||||
@ -218,10 +219,10 @@ void lr35902_cpu_device::device_reset()
|
||||
m_IF = 0;
|
||||
|
||||
m_execution_state = 0;
|
||||
m_handle_halt_bug = false;
|
||||
m_handle_ei_delay = false;
|
||||
m_gb_speed_change_pending = 0;
|
||||
m_gb_speed = 1;
|
||||
m_entering_halt = false;
|
||||
}
|
||||
|
||||
|
||||
@ -254,6 +255,7 @@ void lr35902_cpu_device::check_interrupts()
|
||||
logerror("LR35902 Interrupt IRQ $%02X\n", irq);
|
||||
*/
|
||||
|
||||
bool was_halted = (m_enable & HALTED);
|
||||
for( ; irqline < 5; irqline++ )
|
||||
{
|
||||
if( irq & (1<<irqline) )
|
||||
@ -262,17 +264,42 @@ void lr35902_cpu_device::check_interrupts()
|
||||
{
|
||||
m_enable &= ~HALTED;
|
||||
m_PC++;
|
||||
// In general there seems to be a 4 cycle delay to leave the halt state; except when the
|
||||
// trigger is caused by the VBlank interrupt (on DMG/MGB/SGB?/SGB2?).
|
||||
//
|
||||
// On CGB/AGB/AGS this delay to leave the halt seems to always be 4 cycles.
|
||||
//
|
||||
if ( m_has_halt_bug ) {
|
||||
if ( ! ( m_enable & IME ) ) {
|
||||
/* Old cpu core (dmg/mgb/sgb) */
|
||||
m_handle_halt_bug = true;
|
||||
m_PC--;
|
||||
}
|
||||
// TODO: Properly detect when the delay should be skipped. Cases seen so far:
|
||||
// - Vblank irq
|
||||
// - STAT mode 1 irq (triggered at same time as vblank)
|
||||
// - STAT mode 2 irq (8 cycles?, breaks gambatte halt/m2irq_ly tests when always applied but fix other gambatte halt/m2irq and halt/m2int cases)
|
||||
// No delay:
|
||||
// - LY=LYC irq
|
||||
// STAT and not vblank just triggered (this on dmg/mgb/sgb only)? or Timer IRQ
|
||||
//
|
||||
// This is a bit hacky, more testing is needed to determine exact
|
||||
// hardware behavior.
|
||||
if ((irqline == 1 && !(m_IF & 0x01)) || irqline == 2)
|
||||
{
|
||||
// Cycles needed for leaving the halt state
|
||||
cycles_passed(4);
|
||||
if (irqline == 2)
|
||||
{
|
||||
cycles_passed(2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* New cpu core (cgb/agb/ags) */
|
||||
/* Adjust for internal syncing with video core */
|
||||
/* This feature needs more investigation */
|
||||
if ( irqline < 2 ) {
|
||||
cycles_passed( 4 );
|
||||
// Leaving halt state seems to take 4 cycles.
|
||||
cycles_passed(4);
|
||||
if (!(m_enable & IME) && !m_entering_halt)
|
||||
{
|
||||
cycles_passed(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -284,6 +311,9 @@ void lr35902_cpu_device::check_interrupts()
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x40 + irqline * 8;
|
||||
/*logerror("LR35902 Interrupt PC $%04X\n", m_PC );*/
|
||||
if (was_halted) {
|
||||
m_op = mem_read_byte( m_PC );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -299,32 +329,50 @@ void lr35902_cpu_device::execute_run()
|
||||
{
|
||||
do
|
||||
{
|
||||
if ( m_execution_state ) {
|
||||
UINT8 x;
|
||||
/* Execute instruction */
|
||||
switch( m_op ) {
|
||||
#include "opc_main.hxx"
|
||||
default:
|
||||
// actually this should lock up the cpu!
|
||||
logerror("LR35902: Illegal opcode $%02X @ %04X\n", m_op, m_PC);
|
||||
break;
|
||||
if (m_dma_cycles_to_burn > 0)
|
||||
{
|
||||
if (m_dma_cycles_to_burn < 4)
|
||||
{
|
||||
cycles_passed(m_dma_cycles_to_burn);
|
||||
m_dma_cycles_to_burn = 0;
|
||||
}
|
||||
} else {
|
||||
/* Fetch and count cycles */
|
||||
check_interrupts();
|
||||
debugger_instruction_hook(this, m_PC);
|
||||
if ( m_enable & HALTED ) {
|
||||
cycles_passed( 4 );
|
||||
m_execution_state = 1;
|
||||
} else {
|
||||
m_op = mem_read_byte( m_PC++ );
|
||||
if ( m_handle_halt_bug ) {
|
||||
m_PC--;
|
||||
m_handle_halt_bug = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cycles_passed(4);
|
||||
m_dma_cycles_to_burn -= 4;
|
||||
}
|
||||
}
|
||||
m_execution_state ^= 1;
|
||||
else
|
||||
{
|
||||
if ( m_execution_state ) {
|
||||
UINT8 x;
|
||||
/* Execute instruction */
|
||||
switch( m_op ) {
|
||||
#include "opc_main.hxx"
|
||||
default:
|
||||
// actually this should lock up the cpu!
|
||||
logerror("LR35902: Illegal opcode $%02X @ %04X\n", m_op, m_PC);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Fetch and count cycles */
|
||||
bool was_halted = (m_enable & HALTED);
|
||||
check_interrupts();
|
||||
debugger_instruction_hook(this, m_PC);
|
||||
if ( m_enable & HALTED ) {
|
||||
cycles_passed(m_has_halt_bug ? 2 : 4);
|
||||
m_execution_state = 1;
|
||||
m_entering_halt = false;
|
||||
} else {
|
||||
if (was_halted) {
|
||||
m_PC++;
|
||||
} else {
|
||||
m_op = mem_read_byte( m_PC++ );
|
||||
}
|
||||
}
|
||||
}
|
||||
m_execution_state ^= 1;
|
||||
}
|
||||
} while (m_icount > 0);
|
||||
}
|
||||
|
||||
|
@ -45,13 +45,30 @@ public:
|
||||
static void set_halt_bug(device_t &device) { downcast<lr35902_cpu_device &>(device).m_has_halt_bug = true; }
|
||||
|
||||
UINT8 get_speed();
|
||||
void set_speed( UINT8 speed_request );
|
||||
void set_speed(UINT8 speed_request);
|
||||
|
||||
UINT8 get_ie() { return m_IE; }
|
||||
void set_ie( UINT8 data ) { m_IE = data; }
|
||||
inline UINT8 get_ie() { return m_IE; }
|
||||
inline void set_ie(UINT8 data) { m_IE = data; }
|
||||
|
||||
UINT8 get_if() { return m_IF; }
|
||||
void set_if( UINT8 data ) { m_IF = data; }
|
||||
inline UINT8 get_if() { return m_IF; }
|
||||
inline void set_if(UINT8 data) { m_IF = data; }
|
||||
|
||||
inline void dma_cycles_to_burn(UINT16 cycles_to_burn) { m_dma_cycles_to_burn += cycles_to_burn; }
|
||||
|
||||
// Needed for some gameboy operation which needs to read the results
|
||||
// of setting an input during the currently running timeslice.
|
||||
// Can become protected again once this core becomes cycle accurate.
|
||||
virtual void execute_set_input(int inputnum, int state) override;
|
||||
|
||||
enum
|
||||
{
|
||||
/* Interrupts */
|
||||
VBL_INT = 0, /* V-Blank */
|
||||
LCD_INT = 1, /* LCD Status */
|
||||
TIM_INT = 2, /* Timer */
|
||||
SIO_INT = 3, /* Serial I/O */
|
||||
EXT_INT = 4 /* Joypad */
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
@ -64,7 +81,6 @@ protected:
|
||||
virtual UINT32 execute_max_cycles() const override { return 16; }
|
||||
virtual UINT32 execute_input_lines() const override { return 5; }
|
||||
virtual void execute_run() override;
|
||||
virtual void execute_set_input(int inputnum, int state) override;
|
||||
|
||||
// device_memory_interface overrides
|
||||
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override { return (spacenum == AS_PROGRAM) ? &m_program_config : nullptr; }
|
||||
@ -115,8 +131,9 @@ protected:
|
||||
int m_gb_speed;
|
||||
int m_gb_speed_change_pending;
|
||||
int m_enable;
|
||||
bool m_handle_halt_bug;
|
||||
bool m_has_halt_bug;
|
||||
UINT32 m_dma_cycles_to_burn;
|
||||
bool m_entering_halt;
|
||||
|
||||
/* Callbacks */
|
||||
devcb_write8 m_timer_func;
|
||||
|
@ -229,8 +229,21 @@ case 0x0F: /* RRCA */
|
||||
}
|
||||
break;
|
||||
case 0x10: /* STOP */
|
||||
if ( m_gb_speed_change_pending ) {
|
||||
m_gb_speed = ( m_gb_speed == 1 ) ? 2 : 1;
|
||||
if ( m_gb_speed_change_pending )
|
||||
{
|
||||
if (m_gb_speed == 1)
|
||||
{
|
||||
// Quite a lot of time for a simple input clock change...
|
||||
// And still not all speedchange related tests are passing.
|
||||
UINT32 cycles = ( 2 * 45 + 1 ) * 65536 + 8;
|
||||
|
||||
do {
|
||||
cycles_passed(128);
|
||||
cycles -= 128;
|
||||
} while (cycles > 128);
|
||||
cycles_passed(cycles);
|
||||
}
|
||||
m_gb_speed = ( m_gb_speed == 1 ) ? 2 : 1;
|
||||
}
|
||||
m_gb_speed_change_pending = 0;
|
||||
break;
|
||||
@ -717,6 +730,9 @@ case 0x75: /* LD (HL),L */
|
||||
break;
|
||||
case 0x76: /* HALT */
|
||||
m_enable |= HALTED;
|
||||
m_entering_halt = true;
|
||||
// Prefetch the next instruction
|
||||
m_op = mem_read_byte( m_PC );
|
||||
m_PC--;
|
||||
break;
|
||||
case 0x77: /* LD (HL),A */
|
||||
@ -1060,16 +1076,17 @@ case 0xC4: /* CALL NZ,n16 */
|
||||
|
||||
if ( ! (m_F & FLAG_Z) )
|
||||
{
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = addr;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = addr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xC5: /* PUSH BC */
|
||||
PUSH( m_B, m_C );
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_B, m_C );
|
||||
break;
|
||||
case 0xC6: /* ADD A,n8 */
|
||||
|
||||
@ -1077,10 +1094,10 @@ case 0xC6: /* ADD A,n8 */
|
||||
ADD_A_X (x)
|
||||
break;
|
||||
case 0xC7: /* RST 0 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0;
|
||||
break;
|
||||
case 0xC8: /* RET Z */
|
||||
cycles_passed( 4 );
|
||||
@ -1122,10 +1139,10 @@ case 0xCC: /* CALL Z,n16 */
|
||||
|
||||
if (m_F & FLAG_Z)
|
||||
{
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = addr;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = addr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1134,10 +1151,11 @@ case 0xCD: /* CALL n16 */
|
||||
UINT16 addr = mem_read_word( m_PC );
|
||||
m_PC += 2;
|
||||
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = addr;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = addr;
|
||||
}
|
||||
break;
|
||||
case 0xCE: /* ADC A,n8 */
|
||||
@ -1146,10 +1164,10 @@ case 0xCE: /* ADC A,n8 */
|
||||
ADC_A_X (x)
|
||||
break;
|
||||
case 0xCF: /* RST 8 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 8;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 8;
|
||||
break;
|
||||
case 0xD0: /* RET NC */
|
||||
cycles_passed( 4 );
|
||||
@ -1182,16 +1200,17 @@ case 0xD4: /* CALL NC,n16 */
|
||||
|
||||
if ( ! (m_F & FLAG_C) )
|
||||
{
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = addr;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = addr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xD5: /* PUSH DE */
|
||||
PUSH( m_D, m_E );
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_D, m_E );
|
||||
break;
|
||||
case 0xD6: /* SUB A,n8 */
|
||||
|
||||
@ -1199,10 +1218,10 @@ case 0xD6: /* SUB A,n8 */
|
||||
SUB_A_X (x)
|
||||
break;
|
||||
case 0xD7: /* RST $10 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x10;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0x10;
|
||||
break;
|
||||
case 0xD8: /* RET C */
|
||||
cycles_passed( 4 );
|
||||
@ -1238,10 +1257,10 @@ case 0xDC: /* CALL C,n16 */
|
||||
|
||||
if (m_F & FLAG_C)
|
||||
{
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = addr;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = addr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1251,10 +1270,10 @@ case 0xDE: /* SBC A,n8 */
|
||||
SBC_A_X (x)
|
||||
break;
|
||||
case 0xDF: /* RST $18 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x18;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0x18;
|
||||
break;
|
||||
case 0xE0: /* LD ($FF00+n8),A */
|
||||
{
|
||||
@ -1270,8 +1289,9 @@ case 0xE2: /* LD ($FF00+C),A */
|
||||
mem_write_byte( 0xFF00 + m_C, m_A );
|
||||
break;
|
||||
case 0xE5: /* PUSH HL */
|
||||
PUSH( m_H, m_L );
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_H, m_L );
|
||||
break;
|
||||
case 0xE6: /* AND A,n8 */
|
||||
|
||||
@ -1279,10 +1299,10 @@ case 0xE6: /* AND A,n8 */
|
||||
AND_A_X (x)
|
||||
break;
|
||||
case 0xE7: /* RST $20 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x20;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0x20;
|
||||
break;
|
||||
case 0xE8: /* ADD SP,n8 */
|
||||
/*
|
||||
@ -1329,10 +1349,10 @@ case 0xEE: /* XOR A,n8 */
|
||||
XOR_A_X (x)
|
||||
break;
|
||||
case 0xEF: /* RST $28 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x28;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0x28;
|
||||
break;
|
||||
case 0xF0: /* LD A,($FF00+n8) */
|
||||
{
|
||||
@ -1353,9 +1373,10 @@ case 0xF3: /* DI */
|
||||
m_enable &= ~IME;
|
||||
break;
|
||||
case 0xF5: /* PUSH AF */
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
m_F &= 0xF0;
|
||||
PUSH( m_A, m_F );
|
||||
cycles_passed( 4 );
|
||||
break;
|
||||
case 0xF6: /* OR A,n8 */
|
||||
|
||||
@ -1363,10 +1384,10 @@ case 0xF6: /* OR A,n8 */
|
||||
OR_A_X (x)
|
||||
break;
|
||||
case 0xF7: /* RST $30 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x30;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0x30;
|
||||
break;
|
||||
case 0xF8: /* LD HL,SP+n8 */
|
||||
/*
|
||||
@ -1422,8 +1443,8 @@ case 0xFE: /* CP A,n8 */
|
||||
CP_A_X (x)
|
||||
break;
|
||||
case 0xFF: /* RST $38 */
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x38;
|
||||
// Internal delay
|
||||
cycles_passed( 4 );
|
||||
PUSH( m_PC >> 8, m_PC & 0xff );
|
||||
m_PC = 0x38;
|
||||
break;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,105 +1,199 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Anthony Kruize
|
||||
// copyright-holders:Anthony Kruize, Wilbert Pol
|
||||
// thanks-to:Shay Green
|
||||
#ifndef __GBSOUND_H__
|
||||
#define __GBSOUND_H__
|
||||
|
||||
|
||||
#define MAX_FREQUENCIES 2048
|
||||
|
||||
|
||||
struct SOUND
|
||||
{
|
||||
/* Common */
|
||||
UINT8 on;
|
||||
UINT8 channel;
|
||||
INT32 length;
|
||||
INT32 pos;
|
||||
UINT32 period;
|
||||
INT32 count;
|
||||
INT8 mode;
|
||||
/* Mode 1, 2, 3 */
|
||||
INT8 duty;
|
||||
/* Mode 1, 2, 4 */
|
||||
INT32 env_value;
|
||||
INT8 env_direction;
|
||||
INT32 env_length;
|
||||
INT32 env_count;
|
||||
INT8 signal;
|
||||
/* Mode 1 */
|
||||
UINT32 frequency;
|
||||
INT32 swp_shift;
|
||||
INT32 swp_direction;
|
||||
INT32 swp_time;
|
||||
INT32 swp_count;
|
||||
/* Mode 3 */
|
||||
INT8 level;
|
||||
UINT8 offset;
|
||||
UINT32 dutycount;
|
||||
/* Mode 4 */
|
||||
INT32 ply_step;
|
||||
INT16 ply_value;
|
||||
};
|
||||
|
||||
struct SOUNDC
|
||||
{
|
||||
UINT8 on;
|
||||
UINT8 vol_left;
|
||||
UINT8 vol_right;
|
||||
UINT8 mode1_left;
|
||||
UINT8 mode1_right;
|
||||
UINT8 mode2_left;
|
||||
UINT8 mode2_right;
|
||||
UINT8 mode3_left;
|
||||
UINT8 mode3_right;
|
||||
UINT8 mode4_left;
|
||||
UINT8 mode4_right;
|
||||
};
|
||||
|
||||
|
||||
class gameboy_sound_device : public device_t,
|
||||
public device_sound_interface
|
||||
public device_sound_interface
|
||||
{
|
||||
public:
|
||||
gameboy_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
gameboy_sound_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
|
||||
DECLARE_READ8_MEMBER(sound_r);
|
||||
DECLARE_READ8_MEMBER(wave_r);
|
||||
DECLARE_WRITE8_MEMBER(sound_w);
|
||||
DECLARE_WRITE8_MEMBER(wave_w);
|
||||
virtual DECLARE_READ8_MEMBER(wave_r) = 0;
|
||||
virtual DECLARE_WRITE8_MEMBER(sound_w) = 0;
|
||||
virtual DECLARE_WRITE8_MEMBER(wave_w) = 0;
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_config_complete() override;
|
||||
virtual void device_start() override;
|
||||
|
||||
virtual void device_reset() override;
|
||||
|
||||
// sound stream update overrides
|
||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
||||
|
||||
private:
|
||||
void sound_w_internal(int offset, UINT8 data);
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
NR10 = 0x00,
|
||||
NR11 = 0x01,
|
||||
NR12 = 0x02,
|
||||
NR13 = 0x03,
|
||||
NR14 = 0x04,
|
||||
// 0x05
|
||||
NR21 = 0x06,
|
||||
NR22 = 0x07,
|
||||
NR23 = 0x08,
|
||||
NR24 = 0x09,
|
||||
NR30 = 0x0A,
|
||||
NR31 = 0x0B,
|
||||
NR32 = 0x0C,
|
||||
NR33 = 0x0D,
|
||||
NR34 = 0x0E,
|
||||
// 0x0F
|
||||
NR41 = 0x10,
|
||||
NR42 = 0x11,
|
||||
NR43 = 0x12,
|
||||
NR44 = 0x13,
|
||||
NR50 = 0x14,
|
||||
NR51 = 0x15,
|
||||
NR52 = 0x16,
|
||||
// 0x17 - 0x1F
|
||||
AUD3W0 = 0x20,
|
||||
AUD3W1 = 0x21,
|
||||
AUD3W2 = 0x22,
|
||||
AUD3W3 = 0x23,
|
||||
AUD3W4 = 0x24,
|
||||
AUD3W5 = 0x25,
|
||||
AUD3W6 = 0x26,
|
||||
AUD3W7 = 0x27,
|
||||
AUD3W8 = 0x28,
|
||||
AUD3W9 = 0x29,
|
||||
AUD3WA = 0x2A,
|
||||
AUD3WB = 0x2B,
|
||||
AUD3WC = 0x2C,
|
||||
AUD3WD = 0x2D,
|
||||
AUD3WE = 0x2E,
|
||||
AUD3WF = 0x2F
|
||||
};
|
||||
|
||||
static const unsigned int FRAME_CYCLES = 8192;
|
||||
static const int wave_duty_table[4][8];
|
||||
|
||||
sound_stream *m_channel;
|
||||
int m_rate;
|
||||
|
||||
INT32 m_env_length_table[8];
|
||||
INT32 m_swp_time_table[8];
|
||||
UINT32 m_period_table[MAX_FREQUENCIES];
|
||||
UINT32 m_period_mode3_table[MAX_FREQUENCIES];
|
||||
UINT32 m_period_mode4_table[8][16];
|
||||
UINT32 m_length_table[64];
|
||||
UINT32 m_length_mode3_table[256];
|
||||
struct SOUND
|
||||
{
|
||||
/* Common */
|
||||
UINT8 reg[5];
|
||||
bool on;
|
||||
UINT8 channel;
|
||||
UINT8 length;
|
||||
UINT8 length_mask;
|
||||
bool length_counting;
|
||||
bool length_enabled;
|
||||
/* Mode 1, 2, 3 */
|
||||
UINT64 cycles_left;
|
||||
INT8 duty;
|
||||
/* Mode 1, 2, 4 */
|
||||
bool envelope_enabled;
|
||||
INT8 envelope_value;
|
||||
INT8 envelope_direction;
|
||||
UINT8 envelope_time;
|
||||
UINT8 envelope_count;
|
||||
INT8 signal;
|
||||
/* Mode 1 */
|
||||
UINT16 frequency;
|
||||
UINT16 frequency_counter;
|
||||
bool sweep_enabled;
|
||||
bool sweep_neg_mode_used;
|
||||
UINT8 sweep_shift;
|
||||
INT32 sweep_direction;
|
||||
UINT8 sweep_time;
|
||||
UINT8 sweep_count;
|
||||
/* Mode 3 */
|
||||
UINT8 level;
|
||||
UINT8 offset;
|
||||
UINT32 duty_count;
|
||||
INT8 current_sample;
|
||||
bool sample_reading;
|
||||
/* Mode 4 */
|
||||
bool noise_short;
|
||||
UINT16 noise_lfsr;
|
||||
};
|
||||
|
||||
struct SOUND m_snd_1;
|
||||
struct SOUND m_snd_2;
|
||||
struct SOUND m_snd_3;
|
||||
struct SOUND m_snd_4;
|
||||
struct SOUNDC m_snd_control;
|
||||
|
||||
struct
|
||||
{
|
||||
UINT8 on;
|
||||
UINT8 vol_left;
|
||||
UINT8 vol_right;
|
||||
UINT8 mode1_left;
|
||||
UINT8 mode1_right;
|
||||
UINT8 mode2_left;
|
||||
UINT8 mode2_right;
|
||||
UINT8 mode3_left;
|
||||
UINT8 mode3_right;
|
||||
UINT8 mode4_left;
|
||||
UINT8 mode4_right;
|
||||
UINT64 cycles;
|
||||
bool wave_ram_locked;
|
||||
} m_snd_control;
|
||||
|
||||
UINT8 m_snd_regs[0x30];
|
||||
attotime m_last_updated;
|
||||
emu_timer *m_timer;
|
||||
|
||||
virtual void apu_power_off() = 0;
|
||||
void sound_w_internal(int offset, UINT8 data);
|
||||
void update_square_channel(struct SOUND &snd, UINT64 cycles);
|
||||
virtual void update_wave_channel(struct SOUND &snd, UINT64 cycles) = 0;
|
||||
void update_noise_channel(struct SOUND &snd, UINT64 cycles);
|
||||
INT32 calculate_next_sweep(struct SOUND &snd);
|
||||
void apply_next_sweep(struct SOUND &snd);
|
||||
void tick_length(struct SOUND &snd);
|
||||
void tick_sweep(struct SOUND &snd);
|
||||
void tick_envelope(struct SOUND &snd);
|
||||
void update_state();
|
||||
bool dac_enabled(struct SOUND &snd);
|
||||
virtual void corrupt_wave_ram() { };
|
||||
UINT64 noise_period_cycles();
|
||||
TIMER_CALLBACK_MEMBER(timer_callback);
|
||||
};
|
||||
|
||||
extern const device_type GAMEBOY;
|
||||
|
||||
class dmg_apu_device : public gameboy_sound_device
|
||||
{
|
||||
public:
|
||||
dmg_apu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(wave_r) override;
|
||||
virtual DECLARE_WRITE8_MEMBER(wave_w) override;
|
||||
virtual DECLARE_WRITE8_MEMBER(sound_w) override;
|
||||
|
||||
protected:
|
||||
virtual void apu_power_off() override;
|
||||
virtual void corrupt_wave_ram() override;
|
||||
virtual void update_wave_channel(struct SOUND &snd, UINT64 cycles) override;
|
||||
};
|
||||
|
||||
|
||||
class cgb04_apu_device : public gameboy_sound_device
|
||||
{
|
||||
public:
|
||||
cgb04_apu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(wave_r) override;
|
||||
virtual DECLARE_WRITE8_MEMBER(wave_w) override;
|
||||
virtual DECLARE_WRITE8_MEMBER(sound_w) override;
|
||||
|
||||
protected:
|
||||
virtual void device_reset() override;
|
||||
virtual void apu_power_off() override;
|
||||
virtual void update_wave_channel(struct SOUND &snd, UINT64 cycles) override;
|
||||
};
|
||||
|
||||
|
||||
extern const device_type DMG_APU;
|
||||
//extern const device_type CGB02_APU;
|
||||
extern const device_type CGB04_APU;
|
||||
//extern const device_type CGB05_APU;
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@
|
||||
#define __GB_LCD_H__
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/lr35902/lr35902.h"
|
||||
|
||||
|
||||
struct layer_struct {
|
||||
@ -26,13 +27,14 @@ struct layer_struct {
|
||||
};
|
||||
|
||||
|
||||
class gb_lcd_device : public device_t,
|
||||
class dmg_ppu_device : public device_t,
|
||||
public device_video_interface
|
||||
{
|
||||
public:
|
||||
gb_lcd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
gb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
dmg_ppu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, UINT32 vram_size);
|
||||
dmg_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
static void static_set_lr35902_tag(device_t &device, const char *tag) { downcast<dmg_ppu_device &>(device).m_lr35902.set_tag(tag); }
|
||||
|
||||
UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
@ -46,21 +48,42 @@ public:
|
||||
// FIXME: remove it when proper sgb support is added
|
||||
void set_sgb_hack(bool val) { m_sgb_border_hack = val ? 1 : 0; }
|
||||
|
||||
virtual void update_state();
|
||||
|
||||
protected:
|
||||
inline void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color);
|
||||
enum {
|
||||
// bits in LCD Control register
|
||||
ENABLED = 0x80,
|
||||
WINDOW_ENABLED = 0x20,
|
||||
LARGE_SPRITES = 0x04,
|
||||
SPRITES_ENABLED = 0x02,
|
||||
BACKGROUND_ENABLED = 0x01,
|
||||
// bits in LCD Status register
|
||||
LY_LYC_INT_ENABLED = 0x40,
|
||||
MODE_2_INT_ENABLED = 0x20,
|
||||
MODE_1_INT_ENABLED = 0x10,
|
||||
MODE_0_INT_ENABLED = 0x08,
|
||||
LY_LYC_FLAG = 0x04
|
||||
};
|
||||
|
||||
inline void plot_pixel(int x, int y, UINT16 color);
|
||||
|
||||
void select_sprites();
|
||||
void calculate_window_cycles();
|
||||
virtual void update_sprites();
|
||||
virtual void update_scanline();
|
||||
virtual void update_scanline(UINT32 cycles_to_go);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
void common_start();
|
||||
void common_reset();
|
||||
|
||||
// pointer to the main system
|
||||
cpu_device *m_maincpu;
|
||||
required_device<lr35902_cpu_device> m_lr35902;
|
||||
|
||||
address_space *m_program_space;
|
||||
|
||||
// state variables
|
||||
bitmap_ind16 m_bitmap;
|
||||
@ -87,11 +110,56 @@ protected:
|
||||
UINT16 m_cgb_bpal[32]; /* CGB current background palette table */
|
||||
UINT16 m_cgb_spal[32]; /* CGB current sprite palette table */
|
||||
|
||||
UINT8 m_gb_bpal[4]; /* Background palette */
|
||||
UINT8 m_gb_spal0[4]; /* Sprite 0 palette */
|
||||
UINT8 m_gb_spal1[4]; /* Sprite 1 palette */
|
||||
UINT16 m_gb_bpal[4]; /* Background palette */
|
||||
UINT16 m_gb_spal0[4]; /* Sprite 0 palette */
|
||||
UINT16 m_gb_spal1[4]; /* Sprite 1 palette */
|
||||
|
||||
/* WIP Things used to render current line */
|
||||
struct {
|
||||
// Background/window data
|
||||
UINT8 tile_cycle;
|
||||
UINT8 tile_count;
|
||||
UINT8 y;
|
||||
UINT16 pattern_address;
|
||||
UINT8 pattern;
|
||||
UINT16 tile_address;
|
||||
UINT8 plane0;
|
||||
UINT8 plane1;
|
||||
UINT16 shift_register;
|
||||
|
||||
// Sprite data
|
||||
struct {
|
||||
bool enabled;
|
||||
UINT8 x;
|
||||
UINT8 y;
|
||||
UINT8 pattern;
|
||||
UINT8 flags;
|
||||
UINT8 tile_plane_0;
|
||||
UINT8 tile_plane_1;
|
||||
} sprite[10];
|
||||
UINT8 sprite_delay_cycles;
|
||||
// other internal data
|
||||
bool starting; // Inital fetches when (re)starting the rendering engine.
|
||||
UINT8 sequence_counter;
|
||||
bool drawing;
|
||||
bool start_drawing;
|
||||
UINT8 scrollx_delay;
|
||||
UINT8 scrollx_to_apply;
|
||||
UINT8 pixels_drawn;
|
||||
UINT16 window_compare_position;
|
||||
bool window_active;
|
||||
UINT8 scrollx;
|
||||
// To keep track of when changes to WNDPOSY/WNDPOSX should kick in
|
||||
UINT8 window_start_y[16];
|
||||
UINT8 window_start_x[16];
|
||||
int window_start_y_index;
|
||||
// To keep track of when changes to LCDCONT should kick in for window
|
||||
UINT8 window_enable[16];
|
||||
int window_enable_index;
|
||||
bool window_should_trigger;
|
||||
} m_line;
|
||||
bool m_frame_window_active;
|
||||
|
||||
/* Things used to render current line */
|
||||
int m_current_line; /* Current line */
|
||||
int m_cmp_line; /* Compare line */
|
||||
int m_sprCount; /* Number of sprites on current line */
|
||||
@ -101,25 +169,38 @@ protected:
|
||||
int m_end_x; /* Pixel to end drawing (exclusive) */
|
||||
int m_mode; /* Keep track of internal STAT mode */
|
||||
int m_state; /* Current state of the video state machine */
|
||||
int m_lcd_irq_line;
|
||||
int m_triggering_line_irq;
|
||||
int m_line_irq;
|
||||
int m_triggering_mode_irq;
|
||||
int m_mode_irq;
|
||||
int m_delayed_line_irq;
|
||||
int m_sprite_cycles;
|
||||
int m_window_cycles;
|
||||
int m_scrollx_adjust;
|
||||
int m_oam_locked;
|
||||
int m_oam_locked_reading;
|
||||
int m_vram_locked;
|
||||
int m_pal_locked;
|
||||
int m_hdma_enabled;
|
||||
int m_hdma_possible;
|
||||
int m_hdma_cycles_to_start;
|
||||
UINT16 m_hdma_length;
|
||||
struct layer_struct m_layer[2];
|
||||
emu_timer *m_lcd_timer;
|
||||
int m_oam_dma_start_cycles;
|
||||
int m_oam_dma_cycles_left;
|
||||
UINT16 m_oam_dma_source_address;
|
||||
int m_gbc_mode;
|
||||
UINT8 m_window_x;
|
||||
UINT8 m_window_y;
|
||||
UINT8 m_old_curline;
|
||||
// Interrupt related
|
||||
bool m_stat_mode0_int;
|
||||
bool m_stat_mode1_int;
|
||||
bool m_stat_mode2_int;
|
||||
bool m_stat_lyc_int;
|
||||
bool m_stat_lyc_int_prev;
|
||||
bool m_stat_write_int;
|
||||
bool m_stat_int;
|
||||
|
||||
std::unique_ptr<UINT8[]> m_vram; // Pointer to VRAM
|
||||
std::unique_ptr<UINT8[]> m_oam; // Pointer to OAM memory
|
||||
bool m_oam_dma_processing;
|
||||
UINT8 m_gb_tile_no_mod;
|
||||
UINT32 m_gb_chrgen_offs; // GB Character generator
|
||||
UINT32 m_gb_bgdtab_offs; // GB Background character table
|
||||
@ -129,18 +210,32 @@ protected:
|
||||
UINT32 m_gbc_wndtab_offs; // CGB Window character table
|
||||
int m_vram_bank;
|
||||
|
||||
TIMER_CALLBACK_MEMBER(video_init_vbl);
|
||||
virtual TIMER_CALLBACK_MEMBER(lcd_timer_proc);
|
||||
attotime m_last_updated;
|
||||
UINT64 m_cycles_left;
|
||||
int m_next_state;
|
||||
bool m_updating_state;
|
||||
bool m_enable_experimental_engine;
|
||||
|
||||
virtual void videoptr_restore();
|
||||
virtual bool stat_write(UINT8 new_data);
|
||||
void increment_scanline();
|
||||
void lcd_switch_on();
|
||||
void lcd_switch_on(UINT8 new_data);
|
||||
void update_oam_dma_state(UINT64 cycles);
|
||||
void check_stat_irq();
|
||||
void clear_line_state();
|
||||
void update_line_state(UINT64 cycles);
|
||||
void check_start_of_window();
|
||||
|
||||
private:
|
||||
UINT32 m_oam_size;
|
||||
UINT32 m_vram_size;
|
||||
};
|
||||
|
||||
|
||||
class mgb_lcd_device : public gb_lcd_device
|
||||
class mgb_ppu_device : public dmg_ppu_device
|
||||
{
|
||||
public:
|
||||
mgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
mgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
protected:
|
||||
|
||||
@ -149,10 +244,10 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class sgb_lcd_device : public gb_lcd_device
|
||||
class sgb_ppu_device : public dmg_ppu_device
|
||||
{
|
||||
public:
|
||||
sgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
sgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
void sgb_io_write_pal(int offs, UINT8 *data);
|
||||
|
||||
@ -163,15 +258,15 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual void update_sprites() override;
|
||||
virtual void update_scanline() override;
|
||||
virtual void update_scanline(UINT32 cycles_to_go) override;
|
||||
void refresh_border();
|
||||
};
|
||||
|
||||
|
||||
class cgb_lcd_device : public gb_lcd_device
|
||||
class cgb_ppu_device : public dmg_ppu_device
|
||||
{
|
||||
public:
|
||||
cgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
cgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(video_r) override;
|
||||
virtual DECLARE_WRITE8_MEMBER(video_w) override;
|
||||
@ -183,31 +278,38 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual void update_sprites() override;
|
||||
virtual void update_scanline() override;
|
||||
virtual void update_scanline(UINT32 cycles_to_go) override;
|
||||
|
||||
virtual TIMER_CALLBACK_MEMBER(lcd_timer_proc) override;
|
||||
virtual void update_state() override;
|
||||
virtual void videoptr_restore() override;
|
||||
virtual bool stat_write(UINT8 new_data) override;
|
||||
void update_hdma_state(UINT64 cycles);
|
||||
void hdma_trans(UINT16 length);
|
||||
void hdma_trans_execute();
|
||||
};
|
||||
|
||||
|
||||
extern const device_type GB_LCD_DMG;
|
||||
extern const device_type GB_LCD_MGB;
|
||||
extern const device_type GB_LCD_SGB;
|
||||
extern const device_type GB_LCD_CGB;
|
||||
extern const device_type DMG_PPU;
|
||||
extern const device_type MGB_PPU;
|
||||
extern const device_type SGB_PPU;
|
||||
extern const device_type CGB_PPU;
|
||||
|
||||
|
||||
#define MCFG_GB_LCD_DMG_ADD(_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, GB_LCD_DMG, 0 )
|
||||
#define MCFG_DMG_PPU_ADD(_tag, _cpu_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, DMG_PPU, 0 ) \
|
||||
dmg_ppu_device::static_set_lr35902_tag(*device, "^" _cpu_tag);
|
||||
|
||||
#define MCFG_GB_LCD_MGB_ADD(_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, GB_LCD_MGB, 0 )
|
||||
#define MCFG_MGB_PPU_ADD(_tag, _cpu_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, MGB_PPU, 0 ) \
|
||||
dmg_ppu_device::static_set_lr35902_tag(*device, "^" _cpu_tag);
|
||||
|
||||
#define MCFG_GB_LCD_SGB_ADD(_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, GB_LCD_SGB, 0 )
|
||||
#define MCFG_SGB_PPU_ADD(_tag, _cpu_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, SGB_PPU, 0 ) \
|
||||
dmg_ppu_device::static_set_lr35902_tag(*device, "^" _cpu_tag);
|
||||
|
||||
#define MCFG_GB_LCD_CGB_ADD(_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, GB_LCD_CGB, 0 )
|
||||
#define MCFG_CGB_PPU_ADD(_tag, _cpu_tag ) \
|
||||
MCFG_DEVICE_ADD( _tag, CGB_PPU, 0 ) \
|
||||
dmg_ppu_device::static_set_lr35902_tag(*device, "^" _cpu_tag);
|
||||
|
||||
|
||||
#endif /* GB_LCD_H_ */
|
||||
|
@ -18,134 +18,6 @@
|
||||
- Emulate OAM corruption bug on 16bit inc/dec in $fe** region
|
||||
|
||||
|
||||
Timers
|
||||
======
|
||||
|
||||
There seems to be some kind of selectable internal clock divider which is used to drive
|
||||
the timer increments. This causes the first timer cycle to now always be a full cycle.
|
||||
For instance in 1024 clock cycle mode, the first timer cycle could easily only take 400
|
||||
clock cycles. The next timer cycle will take the full 1024 clock cycles though.
|
||||
|
||||
Writes to the DIV register seem to cause this internal clock divider/register to be
|
||||
reset in such a way that the next stimulus cause a timer increment (in any mode).
|
||||
|
||||
|
||||
Interrupts
|
||||
==========
|
||||
|
||||
Taking an interrupt seems to take around 20 clock cycles.
|
||||
|
||||
|
||||
Stat timing
|
||||
===========
|
||||
|
||||
This timing table is accurate within 4 cycles:
|
||||
| stat = 2 | stat = 3 | stat = 0 |
|
||||
No sprites | 80 | 172 | 204 |
|
||||
1 sprite | 80 | 182 | 194 |
|
||||
2 sprites | 80 | 192 | 184 |
|
||||
3 sprites | 80 | 202 | 174 |
|
||||
4 sprites | 80 | 212 | 164 |
|
||||
5 sprites | 80 | 222 | 154 |
|
||||
6 sprites | 80 | 232 | 144 |
|
||||
7 sprites | 80 | 242 | 134 |
|
||||
8 sprites | 80 | 252 | 124 |
|
||||
9 sprites | 80 | 262 | 114 |
|
||||
10 sprites | 80 | 272 | 104 |
|
||||
|
||||
In other words, each sprite on a line makes stat 3 last 10 cycles longer.
|
||||
|
||||
|
||||
For lines 1 - 143 when stat changes to 2 the line counter is incremented.
|
||||
|
||||
Line 153 is little odd timing wise. The line counter stays 153 for ~4 clock cycles
|
||||
and is then rolls over to 0.
|
||||
|
||||
When the line counter is changed it gets checked against the lyc register.
|
||||
|
||||
Here is a detailed run of the STAT and LY register together with LYC set to 3 on a
|
||||
dmg and mgb. The time between each sample is 4 clock cycles:
|
||||
STAT:
|
||||
22222222 22233333 33333333 33333333 33333333 33333333 33333300 00000000 00000000 00000000
|
||||
00000000 00000000 00000000 06666666 66666666 66666777 77777777 77777777 77777777 77777777
|
||||
77777777 44444444 44444444 44444444 44444444 44444444 44444444 44022222 22222222
|
||||
|
||||
LY:
|
||||
33333333 33333333 33333333 33333333 33333333 33333333 33333333 33333333 33333333 33333333
|
||||
33333333 33333333 33333333 44444444 44444444 44444444 44444444 44444444 44444444 44444444
|
||||
44444444 44444444 44444444 44444444 44444444 44444444 44444444 44555555 55555555
|
||||
^ ^
|
||||
|
||||
As you can see, it seems as though the LY register is incremented slightly before the STAT
|
||||
register is changed, resulting in a short period where STAT goes 0 before going to 2. This
|
||||
bug/feature has been fixed in the CGB and AGB.
|
||||
|
||||
|
||||
|
||||
Around lines 152-153-0 the picture becomes as follows:
|
||||
STAT:
|
||||
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
|
||||
11111111 11111111 11111111 15555555 55555555 55555555 55555555 55555555 55555555 55555555
|
||||
55555555 55555555 55555555 55555555 55555555 55555555 55555555 55111111 11111111 11111111
|
||||
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
|
||||
11111111 11110222 22222222 22222222 23333333 33333333 33333333 33333333 33333333
|
||||
|
||||
LY:
|
||||
77777777 77777777 77777777 77777777 77777777 77777777 77777777 77777777 77777777 77777777
|
||||
77777777 77777777 77777777 88888888 88888888 88888888 88888888 88888888 88888888 88888888
|
||||
88888888 88888888 88888888 88888888 88888888 88888888 88888888 88900000 00000000 00000000
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
|
||||
|
||||
|
||||
The full STAT/LY value state machine.
|
||||
=====================================
|
||||
|
||||
The timing information below is with sprites disabled.
|
||||
|
||||
For STAT we only show the lower 3 bits and for LY only the lower 5 bits of the full
|
||||
register. Each digit stands for 4 clock cycles (the smallest measurable unit on a
|
||||
dmg or mgb). When the video hardware is switched on the LY register is set 0 and
|
||||
the STAT mode is 0. The values for STAT and LY will change as follows:
|
||||
|
||||
STAT 000000000000000000003333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000
|
||||
LY 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 line #0
|
||||
^LY=LYC bit can get set here LY=LYC bit is reset here^
|
||||
|
||||
STAT 222222222222222222223333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000
|
||||
LY 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 line #1
|
||||
|
||||
:
|
||||
:
|
||||
|
||||
STAT 222222222222222222223333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000
|
||||
LY FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 line #143
|
||||
|
||||
STAT 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
||||
LY 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 line #144
|
||||
|
||||
:
|
||||
:
|
||||
|
||||
STAT 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
||||
LY 888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889 line #152
|
||||
|
||||
STAT 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
|
||||
LY 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 line #153
|
||||
^
|
||||
LY=LYC interrupt for 153 can get triggered here
|
||||
|
||||
STAT 222222222222222222223333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000
|
||||
LY 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 line #0
|
||||
|
||||
STAT 222222222222222222223333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000
|
||||
LY 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112 line #1
|
||||
|
||||
:
|
||||
etc
|
||||
|
||||
|
||||
Mappers used in the Game Boy
|
||||
===========================
|
||||
|
||||
@ -429,6 +301,11 @@ space. This mapper uses 32KB sized banks.
|
||||
#include "bus/gameboy/mbc.h"
|
||||
#include "softlist.h"
|
||||
|
||||
|
||||
#define DMG_FRAMES_PER_SECOND 59.732155
|
||||
#define SGB_FRAMES_PER_SECOND 61.17
|
||||
|
||||
|
||||
READ8_MEMBER(gb_state::gb_cart_r)
|
||||
{
|
||||
if (m_bios_disable && m_cartslot)
|
||||
@ -545,75 +422,75 @@ WRITE8_MEMBER(megaduck_state::bank2_w)
|
||||
}
|
||||
|
||||
|
||||
static ADDRESS_MAP_START(gameboy_map, AS_PROGRAM, 8, gb_state )
|
||||
static ADDRESS_MAP_START(gameboy_map, AS_PROGRAM, 8, gb_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("lcd", gb_lcd_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w) /* echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("lcd", gb_lcd_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("custom", gameboy_sound_device, sound_r, sound_w) /* sound registers */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("custom", gameboy_sound_device, wave_r, wave_w) /* Wave ram */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_DEVREAD("lcd", gb_lcd_device, video_r) AM_WRITE(gb_io2_w) /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("ppu", dmg_ppu_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w)
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("ppu", dmg_ppu_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("apu", gameboy_sound_device, sound_r, sound_w) /* sound registers */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("apu", gameboy_sound_device, wave_r, wave_w) /* Wave ram */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_DEVREAD("ppu", dmg_ppu_device, video_r) AM_WRITE(gb_io2_w) /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(sgb_map, AS_PROGRAM, 8, gb_state )
|
||||
static ADDRESS_MAP_START(sgb_map, AS_PROGRAM, 8, gb_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("lcd", sgb_lcd_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w) /* echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("lcd", sgb_lcd_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, sgb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("custom", gameboy_sound_device, sound_r, sound_w) /* sound registers */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("custom", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_DEVREAD("lcd", sgb_lcd_device, video_r) AM_WRITE(gb_io2_w) /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("ppu", sgb_ppu_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w)
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("ppu", sgb_ppu_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, sgb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("apu", gameboy_sound_device, sound_r, sound_w) /* sound registers */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("apu", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_DEVREAD("ppu", sgb_ppu_device, video_r) AM_WRITE(gb_io2_w) /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(gbc_map, AS_PROGRAM, 8, gb_state )
|
||||
static ADDRESS_MAP_START(gbc_map, AS_PROGRAM, 8, gb_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gbc_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("lcd", cgb_lcd_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xcfff) AM_RAM /* 4k fixed RAM bank */
|
||||
AM_RANGE(0xd000, 0xdfff) AM_RAMBANK("cgb_ram") /* 4k switched RAM bank */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w) /* echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("lcd", cgb_lcd_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("custom", gameboy_sound_device, sound_r, sound_w) /* sound controller */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("custom", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_READWRITE(gbc_io2_r, gbc_io2_w) /* Other I/O and video controller */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* high RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("ppu", cgb_ppu_device, vram_r, vram_w) /* 8k banked VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xcfff) AM_RAM /* 4k fixed RAM bank */
|
||||
AM_RANGE(0xd000, 0xdfff) AM_RAMBANK("cgb_ram") /* 4k switched RAM bank */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w)
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("ppu", cgb_ppu_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gbc_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("apu", gameboy_sound_device, sound_r, sound_w) /* sound controller */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("apu", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_READWRITE(gbc_io2_r, gbc_io2_w) /* Other I/O and video controller */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* high RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(megaduck_map, AS_PROGRAM, 8, megaduck_state )
|
||||
static ADDRESS_MAP_START(megaduck_map, AS_PROGRAM, 8, megaduck_state)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(cart_r, bank1_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("lcd", gb_lcd_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xafff) AM_NOP /* unused? */
|
||||
AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("ppu", dmg_ppu_device, vram_r, vram_w) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xafff) AM_NOP /* unused? */
|
||||
AM_RANGE(0xb000, 0xb000) AM_WRITE(bank2_w)
|
||||
AM_RANGE(0xb001, 0xbfff) AM_NOP /* unused? */
|
||||
AM_RANGE(0xc000, 0xfe9f) AM_RAM /* 8k low RAM, echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("lcd", gb_lcd_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff1f) AM_READWRITE(megaduck_video_r, megaduck_video_w) /* video controller */
|
||||
AM_RANGE(0xff20, 0xff2f) AM_READWRITE(megaduck_sound_r1, megaduck_sound_w1) /* sound controller pt1 */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("custom", gameboy_sound_device, wave_r, wave_w) /* wave ram */
|
||||
AM_RANGE(0xff40, 0xff46) AM_READWRITE(megaduck_sound_r2, megaduck_sound_w2) /* sound controller pt2 */
|
||||
AM_RANGE(0xff47, 0xff7f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* high RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* interrupt enable register */
|
||||
AM_RANGE(0xb001, 0xbfff) AM_NOP /* unused? */
|
||||
AM_RANGE(0xc000, 0xfe9f) AM_RAM /* 8k/16k? RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("ppu", dmg_ppu_device, oam_r, oam_w) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff1f) AM_READWRITE(megaduck_video_r, megaduck_video_w) /* video controller */
|
||||
AM_RANGE(0xff20, 0xff2f) AM_READWRITE(megaduck_sound_r1, megaduck_sound_w1) /* sound controller pt1 */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("apu", gameboy_sound_device, wave_r, wave_w) /* wave ram */
|
||||
AM_RANGE(0xff40, 0xff46) AM_READWRITE(megaduck_sound_r2, megaduck_sound_w2) /* sound controller pt2 */
|
||||
AM_RANGE(0xff47, 0xff7f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* high RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static GFXDECODE_START( gb )
|
||||
@ -758,7 +635,7 @@ static MACHINE_CONFIG_START( gameboy, gb_state )
|
||||
MCFG_SCREEN_ADD("screen", LCD)
|
||||
MCFG_SCREEN_REFRESH_RATE(DMG_FRAMES_PER_SECOND)
|
||||
MCFG_SCREEN_VBLANK_TIME(0)
|
||||
MCFG_SCREEN_UPDATE_DEVICE("lcd", gb_lcd_device, screen_update)
|
||||
MCFG_SCREEN_UPDATE_DEVICE("ppu", dmg_ppu_device, screen_update)
|
||||
MCFG_SCREEN_PALETTE("palette")
|
||||
|
||||
MCFG_DEFAULT_LAYOUT(layout_lcd)
|
||||
@ -770,11 +647,11 @@ static MACHINE_CONFIG_START( gameboy, gb_state )
|
||||
MCFG_PALETTE_ADD("palette", 4)
|
||||
MCFG_PALETTE_INIT_OWNER(gb_state,gb)
|
||||
|
||||
MCFG_GB_LCD_DMG_ADD("lcd")
|
||||
MCFG_DMG_PPU_ADD("ppu", "maincpu")
|
||||
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_SOUND_ADD("custom", GAMEBOY, 0)
|
||||
MCFG_SOUND_ADD("apu", DMG_APU, XTAL_4_194304Mhz)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
|
||||
|
||||
@ -785,13 +662,11 @@ static MACHINE_CONFIG_START( gameboy, gb_state )
|
||||
MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("gbc_list","gbcolor")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( supergb, gameboy )
|
||||
|
||||
static MACHINE_CONFIG_START( supergb, gb_state )
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_REPLACE("maincpu", LR35902, 4295454) /* 4.295454 MHz, derived from SNES xtal */
|
||||
MCFG_CPU_ADD("maincpu", LR35902, 4295454) /* 4.295454 MHz, derived from SNES xtal */
|
||||
MCFG_CPU_PROGRAM_MAP(sgb_map)
|
||||
|
||||
MCFG_CPU_MODIFY("maincpu")
|
||||
MCFG_LR35902_TIMER_CB( WRITE8(gb_state, gb_timer_callback ) )
|
||||
MCFG_LR35902_HALT_BUG
|
||||
|
||||
@ -799,29 +674,41 @@ static MACHINE_CONFIG_DERIVED( supergb, gameboy )
|
||||
MCFG_MACHINE_RESET_OVERRIDE(gb_state, sgb)
|
||||
|
||||
/* video hardware */
|
||||
MCFG_DEFAULT_LAYOUT(layout_horizont) /* runs on a TV, not an LCD */
|
||||
MCFG_SCREEN_ADD("screen", LCD)
|
||||
MCFG_SCREEN_REFRESH_RATE(SGB_FRAMES_PER_SECOND)
|
||||
MCFG_SCREEN_VBLANK_TIME(0)
|
||||
MCFG_SCREEN_UPDATE_DEVICE("ppu", dmg_ppu_device, screen_update)
|
||||
MCFG_SCREEN_PALETTE("palette")
|
||||
|
||||
MCFG_SCREEN_MODIFY("screen")
|
||||
MCFG_DEFAULT_LAYOUT(layout_horizont) /* runs on a TV, not an LCD */
|
||||
MCFG_SCREEN_SIZE(32*8, 28*8)
|
||||
MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 28*8-1)
|
||||
|
||||
MCFG_PALETTE_MODIFY("palette")
|
||||
MCFG_PALETTE_ENTRIES(32768)
|
||||
MCFG_GFXDECODE_ADD("gfxdecode", "palette", gb)
|
||||
MCFG_PALETTE_ADD("palette", 32768)
|
||||
MCFG_PALETTE_INIT_OWNER(gb_state,sgb)
|
||||
|
||||
MCFG_DEVICE_REMOVE("lcd")
|
||||
MCFG_GB_LCD_SGB_ADD("lcd")
|
||||
MCFG_SGB_PPU_ADD("ppu", "maincpu")
|
||||
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_SOUND_ADD("apu", DMG_APU, 4295454)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
|
||||
|
||||
/* cartslot */
|
||||
MCFG_GB_CARTRIDGE_ADD("gbslot", gb_cart, nullptr)
|
||||
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list","gameboy")
|
||||
MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("gbc_list","gbcolor")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( supergb2, gameboy )
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_MODIFY("maincpu")
|
||||
MCFG_CPU_PROGRAM_MAP(sgb_map)
|
||||
|
||||
MCFG_CPU_MODIFY("maincpu")
|
||||
MCFG_LR35902_TIMER_CB( WRITE8(gb_state, gb_timer_callback ) )
|
||||
MCFG_LR35902_HALT_BUG
|
||||
|
||||
MCFG_MACHINE_START_OVERRIDE(gb_state, sgb)
|
||||
MCFG_MACHINE_RESET_OVERRIDE(gb_state, sgb)
|
||||
|
||||
@ -836,18 +723,19 @@ static MACHINE_CONFIG_DERIVED( supergb2, gameboy )
|
||||
MCFG_PALETTE_ENTRIES(32768)
|
||||
MCFG_PALETTE_INIT_OWNER(gb_state,sgb)
|
||||
|
||||
MCFG_DEVICE_REMOVE("lcd")
|
||||
MCFG_GB_LCD_SGB_ADD("lcd")
|
||||
MCFG_DEVICE_REMOVE("ppu")
|
||||
MCFG_SGB_PPU_ADD("ppu", "maincpu")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( gbpocket, gameboy )
|
||||
|
||||
/* video hardware */
|
||||
MCFG_PALETTE_MODIFY("palette")
|
||||
MCFG_PALETTE_INIT_OWNER(gb_state,gbp)
|
||||
|
||||
MCFG_DEVICE_REMOVE("lcd")
|
||||
MCFG_GB_LCD_MGB_ADD("lcd")
|
||||
MCFG_DEVICE_REMOVE("ppu")
|
||||
MCFG_MGB_PPU_ADD("ppu", "maincpu")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_START( gbcolor, gb_state )
|
||||
@ -864,7 +752,7 @@ static MACHINE_CONFIG_START( gbcolor, gb_state )
|
||||
MCFG_SCREEN_ADD("screen", LCD)
|
||||
MCFG_SCREEN_REFRESH_RATE(DMG_FRAMES_PER_SECOND)
|
||||
MCFG_SCREEN_VBLANK_TIME(0)
|
||||
MCFG_SCREEN_UPDATE_DEVICE("lcd", gb_lcd_device, screen_update)
|
||||
MCFG_SCREEN_UPDATE_DEVICE("ppu", dmg_ppu_device, screen_update)
|
||||
MCFG_SCREEN_PALETTE("palette")
|
||||
|
||||
MCFG_DEFAULT_LAYOUT(layout_lcd)
|
||||
@ -877,11 +765,11 @@ static MACHINE_CONFIG_START( gbcolor, gb_state )
|
||||
MCFG_PALETTE_ADD("palette", 32768)
|
||||
MCFG_PALETTE_INIT_OWNER(gb_state,gbc)
|
||||
|
||||
MCFG_GB_LCD_CGB_ADD("lcd")
|
||||
MCFG_CGB_PPU_ADD("ppu", "maincpu")
|
||||
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_SOUND_ADD("custom", GAMEBOY, 0)
|
||||
MCFG_SOUND_ADD("apu", CGB04_APU, XTAL_4_194304Mhz)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
|
||||
|
||||
@ -899,7 +787,7 @@ MACHINE_CONFIG_END
|
||||
static MACHINE_CONFIG_START( megaduck, megaduck_state )
|
||||
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_ADD("maincpu", LR35902, 4194304) /* 4.194304 MHz */
|
||||
MCFG_CPU_ADD("maincpu", LR35902, XTAL_4_194304Mhz) /* 4.194304 MHz */
|
||||
MCFG_CPU_PROGRAM_MAP(megaduck_map)
|
||||
MCFG_LR35902_TIMER_CB( WRITE8(gb_state, gb_timer_callback ) )
|
||||
MCFG_LR35902_HALT_BUG
|
||||
@ -913,7 +801,7 @@ static MACHINE_CONFIG_START( megaduck, megaduck_state )
|
||||
MCFG_MACHINE_START_OVERRIDE(megaduck_state, megaduck)
|
||||
MCFG_MACHINE_RESET_OVERRIDE(megaduck_state, megaduck)
|
||||
|
||||
MCFG_SCREEN_UPDATE_DEVICE("lcd", gb_lcd_device, screen_update)
|
||||
MCFG_SCREEN_UPDATE_DEVICE("ppu", dmg_ppu_device, screen_update)
|
||||
MCFG_SCREEN_SIZE(20*8, 18*8)
|
||||
MCFG_SCREEN_VISIBLE_AREA(0*8, 20*8-1, 0*8, 18*8-1)
|
||||
|
||||
@ -923,11 +811,11 @@ static MACHINE_CONFIG_START( megaduck, megaduck_state )
|
||||
MCFG_PALETTE_ADD("palette", 4)
|
||||
MCFG_PALETTE_INIT_OWNER(megaduck_state,megaduck)
|
||||
|
||||
MCFG_GB_LCD_DMG_ADD("lcd")
|
||||
MCFG_DMG_PPU_ADD("ppu", "maincpu")
|
||||
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_SOUND_ADD("custom", GAMEBOY, 0)
|
||||
MCFG_SOUND_ADD("apu", DMG_APU, XTAL_4_194304Mhz)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
|
||||
|
||||
|
@ -1408,7 +1408,7 @@ static MACHINE_CONFIG_START( gbadv, gba_state )
|
||||
MCFG_GBA_LCD_DMA_VBLANK(WRITELINE(gba_state, dma_vblank_callback))
|
||||
|
||||
MCFG_SPEAKER_STANDARD_STEREO("spkleft", "spkright")
|
||||
MCFG_SOUND_ADD("custom", GAMEBOY, 0)
|
||||
MCFG_SOUND_ADD("custom", CGB04_APU, XTAL_16_777216MHz/4)
|
||||
MCFG_SOUND_ROUTE(0, "spkleft", 0.50)
|
||||
MCFG_SOUND_ROUTE(1, "spkright", 0.50)
|
||||
MCFG_SOUND_ADD("direct_a_left", DAC, 0) // GBA direct sound A left
|
||||
|
@ -1328,7 +1328,7 @@ static MACHINE_CONFIG_START( vgmplay, vgmplay_state )
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
|
||||
|
||||
MCFG_SOUND_ADD("dmg", GAMEBOY, 0)
|
||||
MCFG_SOUND_ADD("dmg", DMG_APU, XTAL_4_194304Mhz)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
|
||||
|
||||
|
@ -15,33 +15,6 @@
|
||||
#include "machine/ram.h"
|
||||
#include "video/gb_lcd.h"
|
||||
|
||||
/* Interrupts */
|
||||
#define VBL_INT 0 /* V-Blank */
|
||||
#define LCD_INT 1 /* LCD Status */
|
||||
#define TIM_INT 2 /* Timer */
|
||||
#define SIO_INT 3 /* Serial I/O */
|
||||
#define EXT_INT 4 /* Joypad */
|
||||
|
||||
#ifdef TIMER
|
||||
#undef TIMER
|
||||
#endif
|
||||
|
||||
/* Cartridge types */
|
||||
#define CART_RAM 0x01 /* Cartridge has RAM */
|
||||
#define BATTERY 0x02 /* Cartridge has a battery to save RAM */
|
||||
#define TIMER 0x04 /* Cartridge has a real-time-clock (MBC3 only) */
|
||||
#define RUMBLE 0x08 /* Cartridge has a rumble motor (MBC5 only) */
|
||||
#define SRAM 0x10 /* Cartridge has SRAM */
|
||||
#define UNKNOWN 0x80 /* Cartridge is of an unknown type */
|
||||
|
||||
#define DMG_FRAMES_PER_SECOND 59.732155
|
||||
#define SGB_FRAMES_PER_SECOND 61.17
|
||||
|
||||
|
||||
#define MAX_ROMBANK 512
|
||||
#define MAX_RAMBANK 256
|
||||
|
||||
|
||||
|
||||
class gb_state : public driver_device
|
||||
{
|
||||
@ -50,13 +23,13 @@ public:
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_cartslot(*this, "gbslot"),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_custom(*this, "custom"),
|
||||
m_apu(*this, "apu"),
|
||||
m_region_maincpu(*this, "maincpu"),
|
||||
m_rambank(*this, "cgb_ram"),
|
||||
m_inputs(*this, "INPUTS"),
|
||||
m_bios_hack(*this, "SKIP_CHECK"),
|
||||
m_ram(*this, RAM_TAG),
|
||||
m_lcd(*this, "lcd") { }
|
||||
m_ppu(*this, "ppu") { }
|
||||
|
||||
//gb_state driver_data;
|
||||
UINT8 m_gb_io[0x10];
|
||||
@ -69,8 +42,9 @@ public:
|
||||
UINT8 m_reloading;
|
||||
|
||||
/* Serial I/O related */
|
||||
UINT16 m_internal_serial_clock;
|
||||
UINT16 m_internal_serial_frequency;
|
||||
UINT32 m_sio_count; /* Serial I/O counter */
|
||||
emu_timer *m_gb_serial_timer;
|
||||
|
||||
/* SGB variables */
|
||||
INT8 m_sgb_packets;
|
||||
@ -86,7 +60,7 @@ public:
|
||||
UINT8 *m_gbc_rammap[8]; /* (CGB) Addresses of internal RAM banks */
|
||||
UINT8 m_gbc_rambank; /* (CGB) Current CGB RAM bank */
|
||||
|
||||
int m_bios_disable;
|
||||
bool m_bios_disable;
|
||||
|
||||
DECLARE_WRITE8_MEMBER(gb_io_w);
|
||||
DECLARE_WRITE8_MEMBER(gb_io2_w);
|
||||
@ -94,6 +68,7 @@ public:
|
||||
DECLARE_READ8_MEMBER(gb_ie_r);
|
||||
DECLARE_WRITE8_MEMBER(gb_ie_w);
|
||||
DECLARE_READ8_MEMBER(gb_io_r);
|
||||
DECLARE_WRITE8_MEMBER(gbc_io_w);
|
||||
DECLARE_WRITE8_MEMBER(gbc_io2_w);
|
||||
DECLARE_READ8_MEMBER(gbc_io2_r);
|
||||
DECLARE_PALETTE_INIT(gb);
|
||||
@ -104,7 +79,6 @@ public:
|
||||
DECLARE_MACHINE_START(gbc);
|
||||
DECLARE_MACHINE_RESET(gbc);
|
||||
DECLARE_PALETTE_INIT(gbc);
|
||||
TIMER_CALLBACK_MEMBER(gb_serial_timer_proc);
|
||||
DECLARE_WRITE8_MEMBER(gb_timer_callback);
|
||||
|
||||
DECLARE_READ8_MEMBER(gb_cart_r);
|
||||
@ -118,18 +92,19 @@ public:
|
||||
|
||||
protected:
|
||||
required_device<lr35902_cpu_device> m_maincpu;
|
||||
required_device<gameboy_sound_device> m_custom;
|
||||
required_device<gameboy_sound_device> m_apu;
|
||||
required_memory_region m_region_maincpu;
|
||||
optional_memory_bank m_rambank; // cgb
|
||||
required_ioport m_inputs;
|
||||
required_ioport m_bios_hack;
|
||||
optional_device<ram_device> m_ram;
|
||||
required_device<gb_lcd_device> m_lcd;
|
||||
required_device<dmg_ppu_device> m_ppu;
|
||||
|
||||
void gb_timer_increment();
|
||||
void gb_timer_check_irq();
|
||||
void gb_init();
|
||||
void gb_init_regs();
|
||||
void gb_serial_timer_tick();
|
||||
|
||||
void save_gb_base();
|
||||
void save_gbc_only();
|
||||
|
@ -80,36 +80,27 @@ TODO:
|
||||
13/6/2005 WP - Added support for bootstrap rom banking.
|
||||
|
||||
***************************************************************************/
|
||||
#define __MACHINE_GB_C
|
||||
|
||||
#include "emu.h"
|
||||
#include "includes/gb.h"
|
||||
|
||||
|
||||
#define ENABLE_LOGGING 0
|
||||
#define LOG(x) do { if (ENABLE_LOGGING) logerror x; } while(0)
|
||||
|
||||
|
||||
/* RAM layout defines */
|
||||
#define CGB_START_VRAM_BANKS 0x0000
|
||||
#define CGB_START_RAM_BANKS ( 2 * 8 * 1024 )
|
||||
|
||||
|
||||
#define JOYPAD m_gb_io[0x00] /* Joystick: 1.1.P15.P14.P13.P12.P11.P10 */
|
||||
#define SIODATA m_gb_io[0x01] /* Serial IO data buffer */
|
||||
#define SIOCONT m_gb_io[0x02] /* Serial IO control register */
|
||||
#define DIVREG m_gb_io[0x04] /* Divider register (???) */
|
||||
#define TIMECNT m_gb_io[0x05] /* Timer counter. Gen. int. when it overflows */
|
||||
#define TIMEMOD m_gb_io[0x06] /* New value of TimeCount after it overflows */
|
||||
#define TIMEFRQ m_gb_io[0x07] /* Timer frequency and start/stop switch */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Prototypes
|
||||
*/
|
||||
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
/* #define V_GENERAL*/ /* Display general debug information */
|
||||
/* #define V_BANK*/ /* Display bank switching debug information */
|
||||
#endif
|
||||
|
||||
//-------------------------
|
||||
// handle save state
|
||||
//-------------------------
|
||||
@ -160,29 +151,31 @@ void gb_state::gb_init_regs()
|
||||
void gb_state::gb_init()
|
||||
{
|
||||
address_space &space = m_maincpu->space(AS_PROGRAM);
|
||||
m_custom->sound_w(space, 0x16, 0x00); /* Initialize sound hardware */
|
||||
m_apu->sound_w(space, 0x16, 0x00); /* Initialize sound hardware */
|
||||
|
||||
m_divcount = 0;
|
||||
m_divcount = 8;
|
||||
m_internal_serial_clock = 0;
|
||||
m_internal_serial_frequency = 512 / 2;
|
||||
m_triggering_irq = 0;
|
||||
m_shift = 10; // slowest timer?
|
||||
m_shift_cycles = 1 << m_shift;
|
||||
|
||||
/* Set registers to default/startup values */
|
||||
m_gb_io[0x00] = 0xCF;
|
||||
m_gb_io[0x01] = 0x00;
|
||||
m_gb_io[0x02] = 0x7E;
|
||||
m_gb_io[0x03] = 0xFF;
|
||||
m_gb_io[0x07] = 0xF8; /* Upper bits of TIMEFRQ register are set to 1 */
|
||||
}
|
||||
|
||||
|
||||
void gb_state::machine_start()
|
||||
{
|
||||
/* Allocate the serial timer, and disable it */
|
||||
m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this));
|
||||
m_gb_serial_timer->enable( 0 );
|
||||
|
||||
save_gb_base();
|
||||
}
|
||||
|
||||
MACHINE_START_MEMBER(gb_state,gbc)
|
||||
{
|
||||
/* Allocate the serial timer, and disable it */
|
||||
m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this));
|
||||
m_gb_serial_timer->enable( 0 );
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
m_gbc_rammap[i] = m_ram->pointer() + CGB_START_RAM_BANKS + i * 0x1000;
|
||||
|
||||
@ -195,15 +188,11 @@ MACHINE_START_MEMBER(gb_state,sgb)
|
||||
{
|
||||
m_sgb_packets = -1;
|
||||
|
||||
/* Allocate the serial timer, and disable it */
|
||||
m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this));
|
||||
m_gb_serial_timer->enable( 0 );
|
||||
|
||||
save_gb_base();
|
||||
save_sgb_only();
|
||||
|
||||
if (m_cartslot && m_cartslot->get_sgb_hack()) {
|
||||
dynamic_cast<sgb_lcd_device*>(m_lcd.target())->set_sgb_hack(TRUE);
|
||||
dynamic_cast<sgb_ppu_device*>(m_ppu.target())->set_sgb_hack(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,9 +201,7 @@ void gb_state::machine_reset()
|
||||
gb_init();
|
||||
|
||||
/* Enable BIOS rom */
|
||||
m_bios_disable = 0;
|
||||
|
||||
m_divcount = 0x0004;
|
||||
m_bios_disable = false;
|
||||
}
|
||||
|
||||
MACHINE_RESET_MEMBER(gb_state,gbc)
|
||||
@ -224,7 +211,7 @@ MACHINE_RESET_MEMBER(gb_state,gbc)
|
||||
gb_init_regs();
|
||||
|
||||
/* Enable BIOS rom */
|
||||
m_bios_disable = 0;
|
||||
m_bios_disable = false;
|
||||
|
||||
for (auto & elem : m_gbc_rammap)
|
||||
memset(elem, 0, 0x1000);
|
||||
@ -237,9 +224,7 @@ MACHINE_RESET_MEMBER(gb_state,sgb)
|
||||
gb_init_regs();
|
||||
|
||||
/* Enable BIOS rom */
|
||||
m_bios_disable = 0;
|
||||
|
||||
m_divcount = 0x0004;
|
||||
m_bios_disable = false;
|
||||
}
|
||||
|
||||
|
||||
@ -259,37 +244,42 @@ WRITE8_MEMBER(gb_state::gb_io_w)
|
||||
case 0x01: /* SB - Serial transfer data */
|
||||
break;
|
||||
case 0x02: /* SC - SIO control */
|
||||
switch( data & 0x81 )
|
||||
switch (data & 0x81)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x80: /* enabled & external clock */
|
||||
m_sio_count = 0;
|
||||
case 0x80: /* enabled & external clock */
|
||||
m_sio_count = 16;
|
||||
break;
|
||||
case 0x81: /* enabled & internal clock */
|
||||
SIODATA = 0xFF;
|
||||
m_sio_count = 8;
|
||||
m_gb_serial_timer->adjust(m_maincpu->cycles_to_attotime(512), 0, m_maincpu->cycles_to_attotime(512));
|
||||
m_gb_serial_timer->enable( 1 );
|
||||
m_sio_count = 16;
|
||||
break;
|
||||
}
|
||||
logerror("SIOCONT write, serial clock is %04x\n", m_internal_serial_clock);
|
||||
data |= 0x7E; // unused bits stay high
|
||||
break;
|
||||
case 0x03:
|
||||
return;
|
||||
case 0x04: /* DIV - Divider register */
|
||||
/* Force increment of TIMECNT register */
|
||||
if ( m_divcount >= 16 )
|
||||
/* Force increment of TIMECNT register when the 'highest' bit is set */
|
||||
if ((m_divcount >> (m_shift - 1)) & 1)
|
||||
{
|
||||
gb_timer_increment();
|
||||
}
|
||||
LOG(("DIV write\n"));
|
||||
m_divcount = 0;
|
||||
return;
|
||||
case 0x05: /* TIMA - Timer counter */
|
||||
/* Check if the counter is being reloaded in this cycle */
|
||||
if ( m_reloading && ( m_divcount & ( m_shift_cycles - 1 ) ) == 4 )
|
||||
if ((TIMEFRQ & 0x04) && TIMECNT == TIMEMOD && (m_divcount & (m_shift_cycles - 1)) == 4)
|
||||
{
|
||||
data = TIMECNT;
|
||||
data = TIMEMOD;
|
||||
}
|
||||
break;
|
||||
case 0x06: /* TMA - Timer module */
|
||||
/* Check if the counter is being reloaded in this cycle */
|
||||
if ( m_reloading && ( m_divcount & ( m_shift_cycles - 1 ) ) == 4 )
|
||||
if ((TIMEFRQ & 0x04) && TIMECNT == TIMEMOD && (m_divcount & (m_shift_cycles - 1)) == 4)
|
||||
{
|
||||
TIMECNT = data;
|
||||
}
|
||||
@ -297,10 +287,10 @@ WRITE8_MEMBER(gb_state::gb_io_w)
|
||||
case 0x07: /* TAC - Timer control */
|
||||
data |= 0xF8;
|
||||
/* Check if timer is just disabled or the timer frequency is changing */
|
||||
if ( ( ! ( data & 0x04 ) && ( TIMEFRQ & 0x04 ) ) || ( ( data & 0x04 ) && ( TIMEFRQ & 0x04 ) && ( data & 0x03 ) != ( TIMEFRQ & 0x03 ) ) )
|
||||
if ((!(data & 0x04) && (TIMEFRQ & 0x04)) || ((data & 0x04) && (TIMEFRQ & 0x04) && (data & 0x03) != (TIMEFRQ & 0x03)))
|
||||
{
|
||||
/* Check if TIMECNT should be incremented */
|
||||
if ( ( m_divcount & ( m_shift_cycles - 1 ) ) >= ( m_shift_cycles >> 1 ) )
|
||||
if ((m_divcount & (m_shift_cycles - 1)) >= (m_shift_cycles >> 1))
|
||||
{
|
||||
gb_timer_increment();
|
||||
}
|
||||
@ -309,8 +299,10 @@ WRITE8_MEMBER(gb_state::gb_io_w)
|
||||
m_shift_cycles = 1 << m_shift;
|
||||
break;
|
||||
case 0x0F: /* IF - Interrupt flag */
|
||||
m_ppu->update_state();
|
||||
LOG(("write if\n"));
|
||||
data &= 0x1F;
|
||||
m_maincpu->set_if( data );
|
||||
m_maincpu->set_if(data);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -322,11 +314,10 @@ WRITE8_MEMBER(gb_state::gb_io2_w)
|
||||
if (offset == 0x10)
|
||||
{
|
||||
/* disable BIOS ROM */
|
||||
m_bios_disable = 1;
|
||||
//printf("here again?\n");
|
||||
m_bios_disable = true;
|
||||
}
|
||||
else
|
||||
m_lcd->video_w(space, offset, data);
|
||||
m_ppu->video_w(space, offset, data);
|
||||
}
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
@ -371,7 +362,7 @@ WRITE8_MEMBER(gb_state::sgb_io_w)
|
||||
{
|
||||
UINT8 *sgb_data = m_sgb_data;
|
||||
|
||||
switch( offset )
|
||||
switch (offset)
|
||||
{
|
||||
case 0x00:
|
||||
switch (data & 0x30)
|
||||
@ -411,15 +402,13 @@ WRITE8_MEMBER(gb_state::sgb_io_w)
|
||||
case 0x20: /* data false */
|
||||
if (m_sgb_rest)
|
||||
{
|
||||
if( m_sgb_bytecount == 16 && m_sgb_packets == -1 )
|
||||
if (m_sgb_bytecount == 16 && m_sgb_packets == -1)
|
||||
{
|
||||
#ifdef MAME_DEBUG
|
||||
logerror("SGB: %s (%02X) pkts: %d data: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
LOG(("SGB: %s (%02X) pkts: %d data: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
sgbcmds[sgb_data[0] >> 3],sgb_data[0] >> 3, sgb_data[0] & 0x07, sgb_data[1], sgb_data[2], sgb_data[3],
|
||||
sgb_data[4], sgb_data[5], sgb_data[6], sgb_data[7],
|
||||
sgb_data[8], sgb_data[9], sgb_data[10], sgb_data[11],
|
||||
sgb_data[12], sgb_data[13], sgb_data[14], sgb_data[15]);
|
||||
#endif
|
||||
sgb_data[12], sgb_data[13], sgb_data[14], sgb_data[15]));
|
||||
m_sgb_packets = sgb_data[0] & 0x07;
|
||||
m_sgb_start = 0;
|
||||
}
|
||||
@ -434,14 +423,14 @@ WRITE8_MEMBER(gb_state::sgb_io_w)
|
||||
m_sgb_controller_mode = 2;
|
||||
break;
|
||||
default:
|
||||
dynamic_cast<sgb_lcd_device*>(m_lcd.target())->sgb_io_write_pal(sgb_data[0] >> 3, &sgb_data[0]);
|
||||
dynamic_cast<sgb_ppu_device*>(m_ppu.target())->sgb_io_write_pal(sgb_data[0] >> 3, &sgb_data[0]);
|
||||
break;
|
||||
}
|
||||
m_sgb_start = 0;
|
||||
m_sgb_bytecount = 0;
|
||||
m_sgb_packets = -1;
|
||||
}
|
||||
if( m_sgb_start )
|
||||
if (m_sgb_start)
|
||||
{
|
||||
sgb_data[m_sgb_bytecount] >>= 1;
|
||||
m_sgb_bitcount++;
|
||||
@ -469,14 +458,14 @@ WRITE8_MEMBER(gb_state::sgb_io_w)
|
||||
JOYPAD = 0x3F;
|
||||
|
||||
/* Hack to let cartridge know it's running on an SGB */
|
||||
if ( (sgb_data[0] >> 3) == 0x1F )
|
||||
if ((sgb_data[0] >> 3) == 0x1F)
|
||||
JOYPAD = 0x3E;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
default:
|
||||
/* we didn't handle the write, so pass it to the GB handler */
|
||||
gb_io_w( space, offset, data );
|
||||
gb_io_w(space, offset, data);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -491,7 +480,7 @@ READ8_MEMBER(gb_state::gb_ie_r)
|
||||
|
||||
WRITE8_MEMBER(gb_state::gb_ie_w)
|
||||
{
|
||||
m_maincpu->set_ie( data & 0x1F );
|
||||
m_maincpu->set_ie(data);
|
||||
}
|
||||
|
||||
/* IO read */
|
||||
@ -500,7 +489,8 @@ READ8_MEMBER(gb_state::gb_io_r)
|
||||
switch(offset)
|
||||
{
|
||||
case 0x04:
|
||||
return ( m_divcount >> 8 ) & 0xFF;
|
||||
LOG(("read DIV, divcount = %04x\n", m_divcount));
|
||||
return (m_divcount >> 8) & 0xFF;
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
@ -511,39 +501,55 @@ READ8_MEMBER(gb_state::gb_io_r)
|
||||
return m_gb_io[offset];
|
||||
case 0x0F:
|
||||
/* Make sure the internal states are up to date */
|
||||
m_ppu->update_state();
|
||||
LOG(("read if\n"));
|
||||
logerror("IF read, serial clock is %04x\n", m_internal_serial_clock);
|
||||
return 0xE0 | m_maincpu->get_if();
|
||||
default:
|
||||
/* It seems unsupported registers return 0xFF */
|
||||
/* Unsupported registers return 0xFF */
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(gb_state::gb_serial_timer_proc)
|
||||
/* Called when 512 internal cycles are passed */
|
||||
void gb_state::gb_serial_timer_tick()
|
||||
{
|
||||
/* Shift in a received bit */
|
||||
SIODATA = (SIODATA << 1) | 0x01;
|
||||
/* Decrement number of handled bits */
|
||||
m_sio_count--;
|
||||
/* If all bits done, stop timer and trigger interrupt */
|
||||
if ( ! m_sio_count )
|
||||
if (SIOCONT & 0x80)
|
||||
{
|
||||
SIOCONT &= 0x7F;
|
||||
m_gb_serial_timer->enable( 0 );
|
||||
m_maincpu->set_input_line(SIO_INT, ASSERT_LINE);
|
||||
if (m_sio_count & 1)
|
||||
{
|
||||
/* Shift in a received bit */
|
||||
SIODATA = (SIODATA << 1) | 0x01;
|
||||
}
|
||||
/* Decrement number of handled bits */
|
||||
m_sio_count--;
|
||||
|
||||
LOG(("%04x - gb_serial_timer_proc: SIODATA = %02x, sio_count = %u\n", m_maincpu->pc(), SIODATA, m_sio_count));
|
||||
/* If all bits done, stop timer and trigger interrupt */
|
||||
if (m_sio_count == 0)
|
||||
{
|
||||
SIOCONT &= 0x7F;
|
||||
m_maincpu->set_input_line(lr35902_cpu_device::SIO_INT, ASSERT_LINE);
|
||||
// Make sure the state is updated during the current timeslice in case it is read.
|
||||
m_maincpu->execute_set_input(lr35902_cpu_device::SIO_INT, ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gb_state::gb_timer_check_irq()
|
||||
{
|
||||
m_reloading = 0;
|
||||
if ( m_triggering_irq )
|
||||
if (m_triggering_irq)
|
||||
{
|
||||
m_triggering_irq = 0;
|
||||
if ( TIMECNT == 0 )
|
||||
if (TIMECNT == 0)
|
||||
{
|
||||
TIMECNT = TIMEMOD;
|
||||
m_maincpu->set_input_line(TIM_INT, ASSERT_LINE);
|
||||
m_maincpu->set_input_line(lr35902_cpu_device::TIM_INT, ASSERT_LINE);
|
||||
// Make sure the state is updated during the current timeslice in case it is read.
|
||||
m_maincpu->execute_set_input(lr35902_cpu_device::TIM_INT, ASSERT_LINE);
|
||||
m_reloading = 1;
|
||||
}
|
||||
}
|
||||
@ -553,49 +559,75 @@ void gb_state::gb_timer_increment()
|
||||
{
|
||||
gb_timer_check_irq();
|
||||
|
||||
LOG(("increment timer\n"));
|
||||
TIMECNT += 1;
|
||||
if ( TIMECNT == 0 )
|
||||
if (TIMECNT == 0)
|
||||
{
|
||||
m_triggering_irq = 1;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( gb_state::gb_timer_callback )
|
||||
// This gets called while the cpu is executing instructions to keep the timer state in sync
|
||||
WRITE8_MEMBER(gb_state::gb_timer_callback)
|
||||
{
|
||||
UINT16 old_gb_divcount = m_divcount;
|
||||
UINT16 old_internal_serial_clock = m_internal_serial_clock;
|
||||
m_divcount += data;
|
||||
m_internal_serial_clock += data;
|
||||
|
||||
if ( (old_gb_divcount >> 8) != (m_divcount >> 8)) {
|
||||
//LOG(("DIV became %02x\n", m_divcount >> 8));
|
||||
}
|
||||
gb_timer_check_irq();
|
||||
|
||||
if ( TIMEFRQ & 0x04 )
|
||||
if (TIMEFRQ & 0x04)
|
||||
{
|
||||
UINT16 old_count = old_gb_divcount >> m_shift;
|
||||
UINT16 new_count = m_divcount >> m_shift;
|
||||
if ( data > m_shift_cycles )
|
||||
if (data > m_shift_cycles)
|
||||
{
|
||||
gb_timer_increment();
|
||||
old_count++;
|
||||
}
|
||||
if ( new_count != old_count )
|
||||
if (new_count != old_count)
|
||||
{
|
||||
gb_timer_increment();
|
||||
if (new_count << m_shift < m_divcount)
|
||||
{
|
||||
gb_timer_check_irq();
|
||||
}
|
||||
}
|
||||
if ( new_count << m_shift < m_divcount )
|
||||
{
|
||||
gb_timer_check_irq();
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_internal_serial_clock ^ old_internal_serial_clock) & m_internal_serial_frequency)
|
||||
{
|
||||
gb_serial_timer_tick();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE8_MEMBER(gb_state::gbc_io_w)
|
||||
{
|
||||
gb_io_w(space, offset, data);
|
||||
|
||||
// On CGB the internal serial transfer clock is selectable
|
||||
if (offset == 0x02)
|
||||
{
|
||||
m_internal_serial_frequency = ((data & 0x02) ? 16 : 512) / 2;
|
||||
SIOCONT = (SIOCONT & ~0x02) | (data & 0x02);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE8_MEMBER(gb_state::gbc_io2_w)
|
||||
{
|
||||
switch( offset )
|
||||
switch (offset)
|
||||
{
|
||||
case 0x0D: /* KEY1 - Prepare speed switch */
|
||||
m_maincpu->set_speed(data);
|
||||
return;
|
||||
case 0x10: /* BFF - Bios disable */
|
||||
m_bios_disable = 1;
|
||||
m_bios_disable = true;
|
||||
return;
|
||||
case 0x16: /* RP - Infrared port */
|
||||
break;
|
||||
@ -608,12 +640,12 @@ WRITE8_MEMBER(gb_state::gbc_io2_w)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_lcd->video_w(space, offset, data);
|
||||
m_ppu->video_w(space, offset, data);
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_state::gbc_io2_r)
|
||||
{
|
||||
switch( offset )
|
||||
switch (offset)
|
||||
{
|
||||
case 0x0D: /* KEY1 */
|
||||
return m_maincpu->get_speed();
|
||||
@ -624,7 +656,7 @@ READ8_MEMBER(gb_state::gbc_io2_r)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return m_lcd->video_r(space, offset);
|
||||
return m_ppu->video_r(space, offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -635,10 +667,6 @@ READ8_MEMBER(gb_state::gbc_io2_r)
|
||||
|
||||
MACHINE_START_MEMBER(megaduck_state,megaduck)
|
||||
{
|
||||
/* Allocate the serial timer, and disable it */
|
||||
m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this));
|
||||
m_gb_serial_timer->enable( 0 );
|
||||
|
||||
save_gb_base();
|
||||
}
|
||||
|
||||
@ -647,7 +675,7 @@ MACHINE_RESET_MEMBER(megaduck_state,megaduck)
|
||||
/* We may have to add some more stuff here, if not then it can be merged back into gb */
|
||||
gb_init();
|
||||
|
||||
m_bios_disable = 1;
|
||||
m_bios_disable = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -694,8 +722,8 @@ READ8_MEMBER(megaduck_state::megaduck_video_r)
|
||||
{
|
||||
offset ^= 0x0C;
|
||||
}
|
||||
data = m_lcd->video_r(space, offset);
|
||||
if ( offset )
|
||||
data = m_ppu->video_r(space, offset);
|
||||
if (offset)
|
||||
return data;
|
||||
return BITSWAP8(data,7,0,5,4,6,3,2,1);
|
||||
}
|
||||
@ -710,7 +738,7 @@ WRITE8_MEMBER(megaduck_state::megaduck_video_w)
|
||||
{
|
||||
offset ^= 0x0C;
|
||||
}
|
||||
m_lcd->video_w(space, offset, data);
|
||||
m_ppu->video_w(space, offset, data);
|
||||
}
|
||||
|
||||
/* Map megaduck audio offset to game boy audio offsets */
|
||||
@ -721,14 +749,14 @@ static const UINT8 megaduck_sound_offsets[16] = { 0, 2, 1, 3, 4, 6, 5, 7, 8, 9,
|
||||
WRITE8_MEMBER(megaduck_state::megaduck_sound_w1)
|
||||
{
|
||||
if ((offset == 0x01) || (offset == 0x07))
|
||||
m_custom->sound_w(space, megaduck_sound_offsets[offset], ((data & 0x0f)<<4) | ((data & 0xf0)>>4));
|
||||
m_apu->sound_w(space, megaduck_sound_offsets[offset], ((data & 0x0f)<<4) | ((data & 0xf0)>>4));
|
||||
else
|
||||
m_custom->sound_w(space, megaduck_sound_offsets[offset], data);
|
||||
m_apu->sound_w(space, megaduck_sound_offsets[offset], data);
|
||||
}
|
||||
|
||||
READ8_MEMBER(megaduck_state::megaduck_sound_r1)
|
||||
{
|
||||
UINT8 data = m_custom->sound_r(space, megaduck_sound_offsets[offset]);
|
||||
UINT8 data = m_apu->sound_r(space, megaduck_sound_offsets[offset]);
|
||||
if ((offset == 0x01) || (offset == 0x07))
|
||||
return ((data & 0x0f)<<4) | ((data & 0xf0)>>4);
|
||||
else
|
||||
@ -738,14 +766,14 @@ READ8_MEMBER(megaduck_state::megaduck_sound_r1)
|
||||
WRITE8_MEMBER(megaduck_state::megaduck_sound_w2)
|
||||
{
|
||||
if ((offset == 0x01) || (offset == 0x02))
|
||||
m_custom->sound_w(space, 0x10 + megaduck_sound_offsets[offset], ((data & 0x0f)<<4) | ((data & 0xf0)>>4));
|
||||
m_apu->sound_w(space, 0x10 + megaduck_sound_offsets[offset], ((data & 0x0f)<<4) | ((data & 0xf0)>>4));
|
||||
else
|
||||
m_custom->sound_w(space, 0x10 + megaduck_sound_offsets[offset], data);
|
||||
m_apu->sound_w(space, 0x10 + megaduck_sound_offsets[offset], data);
|
||||
}
|
||||
|
||||
READ8_MEMBER(megaduck_state::megaduck_sound_r2)
|
||||
{
|
||||
UINT8 data = m_custom->sound_r(space, 0x10 + megaduck_sound_offsets[offset]);
|
||||
UINT8 data = m_apu->sound_r(space, 0x10 + megaduck_sound_offsets[offset]);
|
||||
if ((offset == 0x01) || (offset == 0x02))
|
||||
return ((data & 0x0f)<<4) | ((data & 0xf0)>>4);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user