summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/video/gb_lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/video/gb_lcd.c')
-rw-r--r--src/mess/video/gb_lcd.c2852
1 files changed, 0 insertions, 2852 deletions
diff --git a/src/mess/video/gb_lcd.c b/src/mess/video/gb_lcd.c
deleted file mode 100644
index b46aece5a15..00000000000
--- a/src/mess/video/gb_lcd.c
+++ /dev/null
@@ -1,2852 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Wilbert Pol
-/***************************************************************************
-
- gb_lcd.c
-
- Video file to handle emulation of the Nintendo Game Boy.
-
- Original code Carsten Sorensen 1998
- Mess modifications, bug fixes and speedups Hans de Goede 1998
- Bug fixes, SGB and GBC code Anthony Kruize 2002
- Improvements to match real hardware Wilbert Pol 2006-2008
-
- Timing is not accurate enough:
- - Mode 3 takes 172 cycles (measuered with logic analyzer by costis)
-
-***************************************************************************/
-
-#include "emu.h"
-//#include "cpu/lr35902/lr35902.h"
-#include "video/gb_lcd.h"
-
-/* Interrupts (copied from includes/gb.h)... */
-#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 */
-
-
-
-#define LCDCONT m_vid_regs[0x00] /* LCD control register */
-#define LCDSTAT m_vid_regs[0x01] /* LCD status register */
-#define SCROLLY m_vid_regs[0x02] /* Starting Y position of the background */
-#define SCROLLX m_vid_regs[0x03] /* Starting X position of the background */
-#define CURLINE m_vid_regs[0x04] /* Current screen line being scanned */
-#define CMPLINE m_vid_regs[0x05] /* Gen. int. when scan reaches this line */
-#define BGRDPAL m_vid_regs[0x07] /* Background palette */
-#define SPR0PAL m_vid_regs[0x08] /* Sprite palette #0 */
-#define SPR1PAL m_vid_regs[0x09] /* Sprite palette #1 */
-#define WNDPOSY m_vid_regs[0x0A] /* Window Y position */
-#define WNDPOSX m_vid_regs[0x0B] /* Window X position */
-#define KEY1 m_vid_regs[0x0D] /* Prepare speed switch */
-#define HDMA1 m_vid_regs[0x11] /* HDMA source high byte */
-#define HDMA2 m_vid_regs[0x12] /* HDMA source low byte */
-#define HDMA3 m_vid_regs[0x13] /* HDMA destination high byte */
-#define HDMA4 m_vid_regs[0x14] /* HDMA destination low byte */
-#define HDMA5 m_vid_regs[0x15] /* HDMA length/mode/start */
-#define GBCBCPS m_vid_regs[0x28] /* Backgound palette spec */
-#define GBCBCPD m_vid_regs[0x29] /* Backgound palette data */
-#define GBCOCPS m_vid_regs[0x2A] /* Object palette spec */
-#define GBCOCPD m_vid_regs[0x2B] /* Object palette data */
-
-/* -- Super Game Boy specific -- */
-#define SGB_BORDER_PAL_OFFSET 64 /* Border colours stored from pal 4-7 */
-#define SGB_XOFFSET 48 /* GB screen starts at column 48 */
-#define SGB_YOFFSET 40 /* GB screen starts at row 40 */
-
-
-enum {
- UNLOCKED=0,
- LOCKED
-};
-
-
-enum {
- GB_LCD_STATE_LYXX_M3=1,
- GB_LCD_STATE_LYXX_PRE_M0,
- GB_LCD_STATE_LYXX_M0,
- GB_LCD_STATE_LYXX_M0_SCX3,
- GB_LCD_STATE_LYXX_M0_GBC_PAL,
- GB_LCD_STATE_LYXX_M0_PRE_INC,
- GB_LCD_STATE_LYXX_M0_INC,
- GB_LCD_STATE_LY00_M2,
- GB_LCD_STATE_LYXX_M2,
- GB_LCD_STATE_LY9X_M1,
- GB_LCD_STATE_LY9X_M1_INC,
- GB_LCD_STATE_LY00_M1,
- GB_LCD_STATE_LY00_M1_1,
- GB_LCD_STATE_LY00_M1_2,
- GB_LCD_STATE_LY00_M0
-};
-
-
-/* OAM contents on power up.
-
- The OAM area seems contain some kind of unit fingerprint. On each boot
- the data is almost always the same. Some random bits are flipped between
- different boots. It is currently unknown how much these fingerprints
- differ between different units.
-
- OAM fingerprints taken from Wilbert Pol's own unit.
- */
-
-static const UINT8 dmg_oam_fingerprint[0x100] = {
- 0xD8, 0xE6, 0xB3, 0x89, 0xEC, 0xDE, 0x11, 0x62, 0x0B, 0x7E, 0x48, 0x9E, 0xB9, 0x6E, 0x26, 0xC9,
- 0x36, 0xF4, 0x7D, 0xE4, 0xD9, 0xCE, 0xFA, 0x5E, 0xA3, 0x77, 0x60, 0xFC, 0x1C, 0x64, 0x8B, 0xAC,
- 0xB6, 0x74, 0x3F, 0x9A, 0x0E, 0xFE, 0xEA, 0xA9, 0x40, 0x3A, 0x7A, 0xB6, 0xF2, 0xED, 0xA8, 0x3E,
- 0xAF, 0x2C, 0xD2, 0xF2, 0x01, 0xE0, 0x5B, 0x3A, 0x53, 0x6A, 0x1C, 0x6C, 0x20, 0xD9, 0x22, 0xB4,
- 0x8C, 0x38, 0x71, 0x69, 0x3E, 0x93, 0xA3, 0x22, 0xCE, 0x76, 0x24, 0xE7, 0x1A, 0x14, 0x6B, 0xB1,
- 0xF9, 0x3D, 0xBF, 0x3D, 0x74, 0x64, 0xCB, 0xF5, 0xDC, 0x9A, 0x53, 0xC6, 0x0E, 0x78, 0x34, 0xCB,
- 0x42, 0xB3, 0xFF, 0x07, 0x73, 0xAE, 0x6C, 0xA2, 0x6F, 0x6A, 0xA4, 0x66, 0x0A, 0x8C, 0x40, 0xB3,
- 0x9A, 0x3D, 0x39, 0x78, 0xAB, 0x29, 0xE7, 0xC5, 0x7A, 0xDD, 0x51, 0x95, 0x2B, 0xE4, 0x1B, 0xF6,
- 0x31, 0x16, 0x34, 0xFE, 0x11, 0xF2, 0x5E, 0x11, 0xF3, 0x95, 0x66, 0xB9, 0x37, 0xC2, 0xAD, 0x6D,
- 0x1D, 0xA7, 0x79, 0x06, 0xD7, 0xE5, 0x8F, 0xFA, 0x9C, 0x02, 0x0C, 0x31, 0x8B, 0x17, 0x2E, 0x31,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const UINT8 mgb_oam_fingerprint[0x100] = {
- 0xB9, 0xE9, 0x0D, 0x69, 0xBB, 0x7F, 0x00, 0x80, 0xE9, 0x7B, 0x79, 0xA2, 0xFD, 0xCF, 0xD8, 0x0A,
- 0x87, 0xEF, 0x44, 0x11, 0xFE, 0x37, 0x10, 0x21, 0xFA, 0xFF, 0x00, 0x17, 0xF6, 0x4F, 0x83, 0x03,
- 0x3A, 0xF4, 0x00, 0x24, 0xBB, 0xAE, 0x05, 0x01, 0xFF, 0xF7, 0x12, 0x48, 0xA7, 0x5E, 0xF6, 0x28,
- 0x5B, 0xFF, 0x2E, 0x10, 0xFF, 0xB9, 0x50, 0xC8, 0xAF, 0x77, 0x2C, 0x1A, 0x62, 0xD7, 0x81, 0xC2,
- 0xFD, 0x5F, 0xA0, 0x94, 0xAF, 0xFF, 0x51, 0x20, 0x36, 0x76, 0x50, 0x0A, 0xFD, 0xF6, 0x20, 0x00,
- 0xFE, 0xF7, 0xA0, 0x68, 0xFF, 0xFC, 0x29, 0x51, 0xA3, 0xFA, 0x06, 0xC4, 0x94, 0xFF, 0x39, 0x0A,
- 0xFF, 0x6C, 0x20, 0x20, 0xF1, 0xAD, 0x0C, 0x81, 0x56, 0xFB, 0x03, 0x82, 0xFF, 0xFF, 0x08, 0x58,
- 0x96, 0x7E, 0x01, 0x4D, 0xFF, 0xE4, 0x82, 0xE3, 0x3D, 0xBB, 0x54, 0x00, 0x3D, 0xF3, 0x04, 0x21,
- 0xB7, 0x39, 0xCC, 0x10, 0xF9, 0x5B, 0x80, 0x50, 0x3F, 0x6A, 0x1C, 0x21, 0x1F, 0xFA, 0xA8, 0x52,
- 0x5F, 0xB3, 0x44, 0xA1, 0x96, 0x1E, 0x00, 0x27, 0x63, 0x77, 0x30, 0x54, 0x37, 0x6F, 0x60, 0x22,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const UINT8 cgb_oam_fingerprint[0x100] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x74, 0xFF, 0x09, 0x00, 0x9D, 0x61, 0xA8, 0x28, 0x36, 0x1E, 0x58, 0xAA, 0x75, 0x74, 0xA1, 0x42,
- 0x05, 0x96, 0x40, 0x09, 0x41, 0x02, 0x60, 0x00, 0x1F, 0x11, 0x22, 0xBC, 0x31, 0x52, 0x22, 0x54,
- 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
- 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
- 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
- 0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04
-};
-
-/*
- For an AGS in CGB mode this data is: */
-#if 0
-static const UINT8 abs_oam_fingerprint[0x100] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
- 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
- 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
- 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-#endif
-
-
-const device_type GB_LCD_DMG = &device_creator<gb_lcd_device>;
-const device_type GB_LCD_MGB = &device_creator<mgb_lcd_device>;
-const device_type GB_LCD_SGB = &device_creator<sgb_lcd_device>;
-const device_type GB_LCD_CGB = &device_creator<cgb_lcd_device>;
-
-
-
-gb_lcd_device::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)
- : device_t(mconfig, type, name, tag, owner, clock, shortname, source),
- device_video_interface(mconfig, *this),
- m_sgb_border_hack(0)
-{
-}
-
-gb_lcd_device::gb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : device_t(mconfig, GB_LCD_DMG, "DMG LCD", tag, owner, clock, "dmg_lcd", __FILE__),
- device_video_interface(mconfig, *this),
- m_sgb_border_hack(0)
-{
-}
-
-mgb_lcd_device::mgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : gb_lcd_device(mconfig, GB_LCD_MGB, "MGB LCD", tag, owner, clock, "mgb_lcd", __FILE__)
-{
-}
-
-sgb_lcd_device::sgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : gb_lcd_device(mconfig, GB_LCD_SGB, "SGB LCD", tag, owner, clock, "sgb_lcd", __FILE__)
-{
-}
-
-cgb_lcd_device::cgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : gb_lcd_device(mconfig, GB_LCD_CGB, "CGB LCD", tag, owner, clock, "cgb_lcd", __FILE__)
-{
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void gb_lcd_device::common_start()
-{
- m_screen->register_screen_bitmap(m_bitmap);
- save_item(NAME(m_bitmap));
- m_oam = auto_alloc_array_clear(machine(), UINT8, 0x100);
-
- machine().save().register_postload(save_prepost_delegate(FUNC(gb_lcd_device::videoptr_restore), this));
-
- m_maincpu = machine().device<cpu_device>("maincpu");
-
- save_pointer(NAME(m_oam), 0x100);
- save_item(NAME(m_window_lines_drawn));
- save_item(NAME(m_vid_regs));
- save_item(NAME(m_bg_zbuf));
-
- save_item(NAME(m_cgb_bpal));
- save_item(NAME(m_cgb_spal));
-
- save_item(NAME(m_gb_bpal));
- save_item(NAME(m_gb_spal0));
- save_item(NAME(m_gb_spal1));
-
- save_item(NAME(m_current_line));
- save_item(NAME(m_cmp_line));
- save_item(NAME(m_sprCount));
- save_item(NAME(m_sprite));
- save_item(NAME(m_previous_line));
- save_item(NAME(m_start_x));
- save_item(NAME(m_end_x));
- save_item(NAME(m_mode));
- save_item(NAME(m_state));
- save_item(NAME(m_lcd_irq_line));
- save_item(NAME(m_triggering_line_irq));
- save_item(NAME(m_line_irq));
- save_item(NAME(m_triggering_mode_irq));
- save_item(NAME(m_mode_irq));
- save_item(NAME(m_delayed_line_irq));
- save_item(NAME(m_sprite_cycles));
- save_item(NAME(m_scrollx_adjust));
- save_item(NAME(m_oam_locked));
- save_item(NAME(m_vram_locked));
- save_item(NAME(m_pal_locked));
- save_item(NAME(m_hdma_enabled));
- save_item(NAME(m_hdma_possible));
- save_item(NAME(m_gbc_mode));
- save_item(NAME(m_gb_tile_no_mod));
- save_item(NAME(m_vram_bank));
-
- save_item(NAME(m_gb_chrgen_offs));
- save_item(NAME(m_gb_bgdtab_offs));
- save_item(NAME(m_gb_wndtab_offs));
- save_item(NAME(m_gbc_chrgen_offs));
- save_item(NAME(m_gbc_bgdtab_offs));
- save_item(NAME(m_gbc_wndtab_offs));
-
- save_item(NAME(m_layer[0].enabled));
- save_item(NAME(m_layer[0].xindex));
- save_item(NAME(m_layer[0].xshift));
- save_item(NAME(m_layer[0].xstart));
- save_item(NAME(m_layer[0].xend));
- save_item(NAME(m_layer[0].bgline));
- save_item(NAME(m_layer[1].enabled));
- save_item(NAME(m_layer[1].xindex));
- save_item(NAME(m_layer[1].xshift));
- save_item(NAME(m_layer[1].xstart));
- save_item(NAME(m_layer[1].xend));
- save_item(NAME(m_layer[1].bgline));
-}
-
-
-void gb_lcd_device::videoptr_restore()
-{
- m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
- m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
- m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
- m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
-}
-
-void cgb_lcd_device::videoptr_restore()
-{
- m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
- m_layer[0].gbc_map = m_vram + m_gbc_bgdtab_offs;
- m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
- m_layer[1].gbc_map = m_vram + m_gbc_wndtab_offs;
-}
-
-
-void gb_lcd_device::device_start()
-{
- common_start();
- m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_lcd_device::lcd_timer_proc),this));
-
- m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
- save_pointer(NAME(m_vram), 0x2000);
-
- memcpy(m_oam, dmg_oam_fingerprint, 0x100);
-}
-
-void mgb_lcd_device::device_start()
-{
- common_start();
- m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mgb_lcd_device::lcd_timer_proc),this));
-
- m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
- save_pointer(NAME(m_vram), 0x2000);
-
- memcpy(m_oam, mgb_oam_fingerprint, 0x100);
-}
-
-void sgb_lcd_device::device_start()
-{
- common_start();
- m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sgb_lcd_device::lcd_timer_proc),this));
-
- m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
- save_pointer(NAME(m_vram), 0x2000);
-
- m_sgb_tile_data = auto_alloc_array_clear(machine(), UINT8, 0x2000);
- save_pointer(NAME(m_sgb_tile_data), 0x2000);
-
- memset(m_sgb_tile_map, 0, sizeof(m_sgb_tile_map));
-
- /* Some default colours for non-SGB games */
- m_sgb_pal[0] = 32767;
- m_sgb_pal[1] = 21140;
- m_sgb_pal[2] = 10570;
- m_sgb_pal[3] = 0;
- /* The rest of the colortable can be black */
- for (int i = 4; i < 8 * 16; i++)
- m_sgb_pal[i] = 0;
-
- save_item(NAME(m_sgb_atf_data));
- save_item(NAME(m_sgb_atf));
- save_item(NAME(m_sgb_pal_data));
- save_item(NAME(m_sgb_pal_map));
- save_item(NAME(m_sgb_pal));
- save_item(NAME(m_sgb_tile_map));
- save_item(NAME(m_sgb_window_mask));
-}
-
-void cgb_lcd_device::device_start()
-{
- common_start();
- m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cgb_lcd_device::lcd_timer_proc),this));
-
- m_vram = auto_alloc_array_clear(machine(), UINT8, 0x4000);
- save_pointer(NAME(m_vram), 0x4000);
-
- memcpy(m_oam, cgb_oam_fingerprint, 0x100);
-
- /* Background is initialised as white */
- for (int i = 0; i < 32; i++)
- m_cgb_bpal[i] = 32767;
- /* Sprites are supposed to be uninitialized, but we'll make them black */
- for (int i = 0; i < 32; i++)
- m_cgb_spal[i] = 0;
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void gb_lcd_device::common_reset()
-{
- m_window_lines_drawn = 0;
-
- m_current_line = 0;
- m_cmp_line = 0;
- m_sprCount = 0;
- m_previous_line = 0;
- m_start_x = 0;
- m_end_x = 0;
- m_mode = 0;
- m_state = 0;
- m_lcd_irq_line = 0;
- m_triggering_line_irq = 0;
- m_line_irq = 0;
- m_triggering_mode_irq = 0;
- m_mode_irq = 0;
- m_delayed_line_irq = 0;
- m_sprite_cycles = 0;
- m_scrollx_adjust = 0;
- m_oam_locked = 0;
- m_vram_locked = 0;
- m_pal_locked = 0;
- m_gbc_mode = 0;
- m_gb_tile_no_mod = 0;
- m_vram_bank = 0;
-
- m_gb_chrgen_offs = 0;
- m_gb_bgdtab_offs = 0x1c00;
- m_gb_wndtab_offs = 0x1c00;
-
- memset(&m_vid_regs, 0, sizeof(m_vid_regs));
- memset(&m_bg_zbuf, 0, sizeof(m_bg_zbuf));
- memset(&m_cgb_bpal, 0, sizeof(m_cgb_bpal));
- memset(&m_cgb_spal, 0, sizeof(m_cgb_spal));
- memset(&m_sprite, 0, sizeof(m_sprite));
- memset(&m_layer[0], 0, sizeof(m_layer[0]));
- memset(&m_layer[1], 0, sizeof(m_layer[1]));
-
- // specific reg initialization
- m_vid_regs[0x06] = 0xff;
-
- for (int i = 0x0c; i < _NR_GB_VID_REGS; i++)
- m_vid_regs[i] = 0xff;
-
- LCDSTAT = 0x80;
- LCDCONT = 0x00; /* Video hardware is turned off at boot time */
- m_current_line = CURLINE = CMPLINE = 0x00;
- SCROLLX = SCROLLY = 0x00;
- SPR0PAL = SPR1PAL = 0xFF;
- WNDPOSX = WNDPOSY = 0x00;
-
- // Initialize palette arrays
- for (int i = 0; i < 4; i++)
- m_gb_bpal[i] = m_gb_spal0[i] = m_gb_spal1[i] = i;
-
-}
-
-
-void gb_lcd_device::device_reset()
-{
- common_reset();
-
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
-}
-
-void sgb_lcd_device::device_reset()
-{
- common_reset();
-
- memset(m_sgb_tile_data, 0, 0x2000);
-
- m_sgb_window_mask = 0;
-
- memset(m_sgb_pal_map, 0, sizeof(m_sgb_pal_map));
- memset(m_sgb_atf_data, 0, sizeof(m_sgb_atf_data));
-}
-
-void cgb_lcd_device::device_reset()
-{
- common_reset();
-
- m_gbc_chrgen_offs = 0x2000;
- m_gbc_bgdtab_offs = 0x3c00;
- m_gbc_wndtab_offs = 0x3c00;
-
- /* HDMA disabled */
- m_hdma_enabled = 0;
- m_hdma_possible = 0;
-
- m_gbc_mode = 1;
-}
-
-
-
-inline void gb_lcd_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
-{
- bitmap.pix16(y, x) = (UINT16)color;
-}
-
-/*
- Select which sprites should be drawn for the current scanline and return the
- number of sprites selected.
- */
-void gb_lcd_device::select_sprites()
-{
- int /*yindex,*/ line, height;
- UINT8 *oam = m_oam + 39 * 4;
-
- m_sprCount = 0;
-
- /* If video hardware is enabled and sprites are enabled */
- if ((LCDCONT & 0x80) && (LCDCONT & 0x02))
- {
- /* Check for stretched sprites */
- if (LCDCONT & 0x04)
- height = 16;
- else
- height = 8;
-
- //yindex = m_current_line;
- line = m_current_line + 16;
-
- for (int i = 39; i >= 0; i--)
- {
- if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
- {
- /* We limit the sprite count to max 10 here;
- proper games should not exceed this... */
- if (m_sprCount < 10)
- {
- m_sprite[m_sprCount] = i;
- m_sprCount++;
- }
- }
- oam -= 4;
- }
- }
-}
-
-void gb_lcd_device::update_sprites()
-{
- bitmap_ind16 &bitmap = m_bitmap;
- UINT8 height, tilemask, line, *oam, *vram;
- int yindex;
-
- if (LCDCONT & 0x04)
- {
- height = 16;
- tilemask = 0xFE;
- }
- else
- {
- height = 8;
- tilemask = 0xFF;
- }
-
- yindex = m_current_line;
- line = m_current_line + 16;
-
- oam = m_oam + 39 * 4;
- vram = m_vram;
- for (int i = 39; i >= 0; i--)
- {
- /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
- if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
- {
- UINT16 data;
- UINT8 bit, *spal;
- int xindex, adr;
-
- spal = (oam[3] & 0x10) ? m_gb_spal1 : m_gb_spal0;
- xindex = oam[1] - 8;
- if (oam[3] & 0x40) /* flip y ? */
- {
- adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
- }
- else
- {
- adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
- }
- data = (vram[adr + 1] << 8) | vram[adr];
-
- switch (oam[3] & 0xA0)
- {
- case 0xA0: /* priority is set (behind bgnd & wnd, flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
- plot_pixel(bitmap, xindex, yindex, spal[colour]);
- data >>= 1;
- }
- break;
- case 0x20: /* priority is not set (overlaps bgnd & wnd, flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- if (colour && xindex >= 0 && xindex < 160)
- plot_pixel(bitmap, xindex, yindex, spal[colour]);
- data >>= 1;
- }
- break;
- case 0x80: /* priority is set (behind bgnd & wnd, don't flip x) */
- for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
- plot_pixel(bitmap, xindex, yindex, spal[colour]);
- data <<= 1;
- }
- break;
- case 0x00: /* priority is not set (overlaps bgnd & wnd, don't flip x) */
- for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- if (colour && xindex >= 0 && xindex < 160)
- plot_pixel(bitmap, xindex, yindex, spal[colour]);
- data <<= 1;
- }
- break;
- }
- }
- oam -= 4;
- }
-}
-
-void gb_lcd_device::update_scanline()
-{
- bitmap_ind16 &bitmap = m_bitmap;
-
- g_profiler.start(PROFILER_VIDEO);
-
- /* Make sure we're in mode 3 */
- if ((LCDSTAT & 0x03) == 0x03)
- {
- /* Calculate number of pixels to render based on time still left on the timer */
- UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
- int l = 0;
-
- if (m_start_x < 0)
- {
- /* Window is enabled if the hardware says so AND the current scanline is
- * within the window AND the window X coordinate is <=166 */
- m_layer[1].enabled = ((LCDCONT & 0x20) && (m_current_line >= WNDPOSY) && (WNDPOSX <= 166)) ? 1 : 0;
-
- /* BG is enabled if the hardware says so AND (window_off OR (window_on
- * AND window's X position is >=7)) */
- m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && (WNDPOSX >= 7)))) ? 1 : 0;
-
- if (m_layer[0].enabled)
- {
- m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
- m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
- m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
- m_layer[0].xindex = SCROLLX >> 3;
- m_layer[0].xshift = SCROLLX & 7;
- m_layer[0].xstart = 0;
- m_layer[0].xend = 160;
- }
-
- if (m_layer[1].enabled)
- {
- int xpos = WNDPOSX - 7; /* Window is offset by 7 pixels */
- if (xpos < 0)
- xpos = 0;
-
- m_layer[1].bgline = m_window_lines_drawn;
- m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
- m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
- m_layer[1].xindex = 0;
- m_layer[1].xshift = 0;
- m_layer[1].xstart = xpos;
- m_layer[1].xend = 160;
- m_layer[0].xend = xpos;
- }
- m_start_x = 0;
- }
-
- if (cycles_to_go < 160)
- {
- m_end_x = MIN(160 - cycles_to_go, 160);
- /* Draw empty pixels when the background is disabled */
- if (!(LCDCONT & 0x01))
- {
- rectangle r(m_start_x, m_end_x - 1, m_current_line, m_current_line);
- bitmap.fill(m_gb_bpal[0], r);
- }
- while (l < 2)
- {
- UINT8 xindex, *map, *tiles;
- UINT16 data;
- int i, tile_index;
-
- if (!m_layer[l].enabled)
- {
- l++;
- continue;
- }
- map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
- tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
- xindex = m_start_x;
- if (xindex < m_layer[l].xstart)
- xindex = m_layer[l].xstart;
- i = m_end_x;
- if (i > m_layer[l].xend)
- i = m_layer[l].xend;
- i = i - xindex;
-
- tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
- data = tiles[tile_index] | (tiles[tile_index+1] << 8);
- data <<= m_layer[l].xshift;
-
- while (i > 0)
- {
- while ((m_layer[l].xshift < 8) && i)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- plot_pixel(bitmap, xindex, m_current_line, m_gb_bpal[colour]);
- m_bg_zbuf[xindex] = colour;
- xindex++;
- data <<= 1;
- m_layer[l].xshift++;
- i--;
- }
- if (m_layer[l].xshift == 8)
- {
- /* Take possible changes to SCROLLY into account */
- if (l == 0)
- {
- m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
- map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
- tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
- }
-
- m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
- m_layer[l].xshift = 0;
- tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
- data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
- }
- }
- l++;
- }
- if (m_end_x == 160 && LCDCONT & 0x02)
- {
- update_sprites();
- }
- m_start_x = m_end_x;
- }
- }
- else
- {
- if (!(LCDCONT & 0x80))
- {
- /* Draw an empty line when LCD is disabled */
- if (m_previous_line != m_current_line)
- {
- if (m_current_line < 144)
- {
- const rectangle &r = m_screen->visible_area();
- rectangle r1(r.min_x, r.max_x, m_current_line, m_current_line);
- bitmap.fill(0, r1);
- }
- m_previous_line = m_current_line;
- }
- }
- }
-
- g_profiler.stop();
-}
-
-/* --- Super Game Boy Specific --- */
-
-void sgb_lcd_device::update_sprites()
-{
- bitmap_ind16 &bitmap = m_bitmap;
- UINT8 height, tilemask, line, *oam, *vram, pal;
- INT16 yindex;
-
- if (LCDCONT & 0x04)
- {
- height = 16;
- tilemask = 0xFE;
- }
- else
- {
- height = 8;
- tilemask = 0xFF;
- }
-
- /* Offset to center of screen */
- yindex = m_current_line + SGB_YOFFSET;
- line = m_current_line + 16;
-
- oam = m_oam + 39 * 4;
- vram = m_vram;
- for (int i = 39; i >= 0; i--)
- {
- /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
- if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
- {
- UINT16 data;
- UINT8 bit, *spal;
- INT16 xindex;
- int adr;
-
- spal = (oam[3] & 0x10) ? m_gb_spal1 : m_gb_spal0;
- xindex = oam[1] - 8;
- if (oam[3] & 0x40) /* flip y ? */
- {
- adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
- }
- else
- {
- adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
- }
- data = (vram[adr + 1] << 8) | vram[adr];
-
- /* Find the palette to use */
- // If sprite started before the start of the line we may need to pick a different pal_map entry?
- pal = m_sgb_pal_map[(xindex < 0) ? 0 : (xindex >> 3)][((yindex - SGB_YOFFSET) >> 3)] << 2;
-
- /* Offset to center of screen */
- xindex += SGB_XOFFSET;
-
- switch (oam[3] & 0xA0)
- {
- case 0xA0: /* priority is set (behind bgnd & wnd, flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !m_bg_zbuf[xindex - SGB_XOFFSET])
- plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
- data >>= 1;
- }
- break;
- case 0x20: /* priority is not set (overlaps bgnd & wnd, flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
- plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
- data >>= 1;
- }
- break;
- case 0x80: /* priority is set (behind bgnd & wnd, don't flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !m_bg_zbuf[xindex - SGB_XOFFSET])
- plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
- data <<= 1;
- }
- break;
- case 0x00: /* priority is not set (overlaps bgnd & wnd, don't flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
- plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
- data <<= 1;
- }
- break;
- }
- }
- oam -= 4;
- }
-}
-
-
-void sgb_lcd_device::refresh_border()
-{
- UINT16 data, data2;
- UINT8 *tiles, *tiles2;
-
- for (UINT16 yidx = 0; yidx < 224; yidx++)
- {
- UINT8 *map = m_sgb_tile_map + ((yidx >> 3) * 64);
- UINT16 xindex = 0;
-
- for (UINT16 xidx = 0; xidx < 64; xidx += 2)
- {
- if (map[xidx + 1] & 0x80) /* Vertical flip */
- tiles = m_sgb_tile_data + ((7 - (yidx % 8)) << 1);
- else /* No vertical flip */
- tiles = m_sgb_tile_data + ((yidx % 8) << 1);
- tiles2 = tiles + 16;
-
- UINT8 pal = (map[xidx + 1] & 0x1C) >> 2;
- if (pal == 0)
- pal = 1;
- pal <<= 4;
-
- if (m_sgb_border_hack)
- { /* A few games do weird stuff */
- UINT8 tileno = map[xidx];
- if (tileno >= 128) tileno = ((64 + tileno) % 128) + 128;
- else tileno = (64 + tileno) % 128;
- data = tiles[tileno * 32] | (tiles[(tileno * 32) + 1] << 8);
- data2 = tiles2[tileno * 32] | (tiles2[(tileno * 32) + 1] << 8);
- }
- else
- {
- data = tiles[map[xidx] * 32] | (tiles[(map[xidx] * 32) + 1] << 8);
- data2 = tiles2[map[xidx] * 32] | (tiles2[(map[xidx] * 32) + 1] << 8);
- }
-
- for (int i = 0; i < 8; i++)
- {
- register UINT8 colour;
- if ((map[xidx + 1] & 0x40)) /* Horizontal flip */
- {
- colour = ((data & 0x0001) ? 1 : 0) | ((data & 0x0100) ? 2 : 0) |
- ((data2 & 0x0001) ? 4 : 0) | ((data2 & 0x0100) ? 8 : 0);
- data >>= 1;
- data2 >>= 1;
- }
- else /* No horizontal flip */
- {
- colour = ((data & 0x0080) ? 1 : 0) | ((data & 0x8000) ? 2 : 0) |
- ((data2 & 0x0080) ? 4 : 0) | ((data2 & 0x8000) ? 8 : 0);
- data <<= 1;
- data2 <<= 1;
- }
- /* A slight hack below so we don't draw over the GB screen.
- * Drawing there is allowed, but due to the way we draw the
- * scanline, it can obscure the screen even when it shouldn't.
- */
- if (!((yidx >= SGB_YOFFSET && yidx < SGB_YOFFSET + 144) &&
- (xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160)))
- {
- plot_pixel(m_bitmap, xindex, yidx, m_sgb_pal[pal + colour]);
- }
- xindex++;
- }
- }
- }
-}
-
-void sgb_lcd_device::update_scanline()
-{
- bitmap_ind16 &bitmap = m_bitmap;
-
- g_profiler.start(PROFILER_VIDEO);
-
- if ((LCDSTAT & 0x03) == 0x03)
- {
- /* Calcuate number of pixels to render based on time still left on the timer */
- UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
- int l = 0;
-
- if (m_start_x < 0)
- {
- /* Window is enabled if the hardware says so AND the current scanline is
- * within the window AND the window X coordinate is <=166 */
- m_layer[1].enabled = ((LCDCONT & 0x20) && m_current_line >= WNDPOSY && WNDPOSX <= 166) ? 1 : 0;
-
- /* BG is enabled if the hardware says so AND (window_off OR (window_on
- * AND window's X position is >=7 )) */
- m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && WNDPOSX >= 7))) ? 1 : 0;
-
- if (m_layer[0].enabled)
- {
- m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
- m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
- m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
- m_layer[0].xindex = SCROLLX >> 3;
- m_layer[0].xshift = SCROLLX & 7;
- m_layer[0].xstart = 0;
- m_layer[0].xend = 160;
- }
-
- if (m_layer[1].enabled)
- {
- int xpos;
-
- /* Window X position is offset by 7 so we'll need to adjust */
- xpos = WNDPOSX - 7;
- if (xpos < 0)
- xpos = 0;
-
- m_layer[1].bgline = m_window_lines_drawn;
- m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
- m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
- m_layer[1].xindex = 0;
- m_layer[1].xshift = 0;
- m_layer[1].xstart = xpos;
- m_layer[1].xend = 160;
- m_layer[0].xend = xpos;
- }
- m_start_x = 0;
- }
-
- if (cycles_to_go == 0)
- {
- /* Does this belong here? or should it be moved to the else block */
- /* Handle SGB mask */
- switch (m_sgb_window_mask)
- {
- case 1: /* Freeze screen */
- return;
- case 2: /* Blank screen (black) */
- {
- rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160-1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
- bitmap.fill(0, r);
- }
- return;
- case 3: /* Blank screen (white - or should it be color 0?) */
- {
- rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
- bitmap.fill(32767, r);
- }
- return;
- }
-
- /* Draw the "border" if we're on the first line */
- if (m_current_line == 0)
- {
- refresh_border();
- }
- }
- if (cycles_to_go < 160)
- {
- m_end_x = MIN(160 - cycles_to_go,160);
-
- /* if background or screen disabled clear line */
- if (!(LCDCONT & 0x01))
- {
- rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, m_current_line + SGB_YOFFSET, m_current_line + SGB_YOFFSET);
- bitmap.fill(0, r);
- }
- while (l < 2)
- {
- UINT8 xindex, sgb_palette, *map, *tiles;
- UINT16 data;
- int i, tile_index;
-
- if (!m_layer[l].enabled)
- {
- l++;
- continue;
- }
- map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
- tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
- xindex = m_start_x;
- if (xindex < m_layer[l].xstart)
- xindex = m_layer[l].xstart;
- i = m_end_x;
- if (i > m_layer[l].xend)
- i = m_layer[l].xend;
- i = i - xindex;
-
- tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
- data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
- data <<= m_layer[l].xshift;
-
- while (i > 0)
- {
- /* Figure out which palette we're using */
- assert(((m_end_x - i) >> 3) >= 0 && ((m_end_x - i) >> 3) < ARRAY_LENGTH(m_sgb_pal_map));
- sgb_palette = m_sgb_pal_map[(m_end_x - i) >> 3][m_current_line >> 3] << 2;
-
- while ((m_layer[l].xshift < 8) && i)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- plot_pixel(bitmap, xindex + SGB_XOFFSET, m_current_line + SGB_YOFFSET, m_sgb_pal[sgb_palette + m_gb_bpal[colour]]);
- m_bg_zbuf[xindex] = colour;
- xindex++;
- data <<= 1;
- m_layer[l].xshift++;
- i--;
- }
- if (m_layer[l].xshift == 8)
- {
- /* Take possible changes to SCROLLY into account */
- if (l == 0)
- {
- m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
- map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
- tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
- }
-
- m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
- m_layer[l].xshift = 0;
- tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
- data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
- }
- }
- l++;
- }
- if ((m_end_x == 160) && (LCDCONT & 0x02))
- {
- update_sprites();
- }
- m_start_x = m_end_x;
- }
- }
- else
- {
- if (!(LCDCONT * 0x80))
- {
- /* if screen disabled clear line */
- if (m_previous_line != m_current_line)
- {
- /* Also refresh border here??? */
- if (m_current_line < 144)
- {
- rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, m_current_line + SGB_YOFFSET, m_current_line + SGB_YOFFSET);
- bitmap.fill(0, r);
- }
- m_previous_line = m_current_line;
- }
- }
- }
-
- g_profiler.stop();
-}
-
-/* --- Game Boy Color Specific --- */
-
-void cgb_lcd_device::update_sprites()
-{
- bitmap_ind16 &bitmap = m_bitmap;
- UINT8 height, tilemask, line, *oam;
- int xindex, yindex;
-
- if (LCDCONT & 0x04)
- {
- height = 16;
- tilemask = 0xFE;
- }
- else
- {
- height = 8;
- tilemask = 0xFF;
- }
-
- yindex = m_current_line;
- line = m_current_line + 16;
-
- oam = m_oam + 39 * 4;
- for (int i = 39; i >= 0; i--)
- {
- /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
- if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
- {
- UINT16 data;
- UINT8 bit, pal;
-
- /* Handle mono mode for GB games */
- if (!m_gbc_mode)
- pal = (oam[3] & 0x10) ? 4 : 0;
- else
- pal = ((oam[3] & 0x7) * 4);
-
- xindex = oam[1] - 8;
- if (oam[3] & 0x40) /* flip y ? */
- {
- data = *((UINT16 *) &m_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2]);
- }
- else
- {
- data = *((UINT16 *) &m_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (line - oam[0]) * 2]);
- }
-
- data = LITTLE_ENDIANIZE_INT16(data);
-
- switch (oam[3] & 0xA0)
- {
- case 0xA0: /* priority is set (behind bgnd & wnd, flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
- {
- if (!m_gbc_mode)
- colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
- plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
- }
- data >>= 1;
- }
- break;
- case 0x20: /* priority is not set (overlaps bgnd & wnd, flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- if ((m_bg_zbuf[xindex] & 0x80) && (m_bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
- colour = 0;
- if (colour && xindex >= 0 && xindex < 160)
- {
- if (!m_gbc_mode)
- colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
- plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
- }
- data >>= 1;
- }
- break;
- case 0x80: /* priority is set (behind bgnd & wnd, don't flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
- {
- if (!m_gbc_mode)
- colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
- plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
- }
- data <<= 1;
- }
- break;
- case 0x00: /* priority is not set (overlaps bgnd & wnd, don't flip x) */
- for (bit = 0; bit < 8; bit++, xindex++)
- {
- if (xindex >= 0 && xindex < 160)
- {
- register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- if ((m_bg_zbuf[xindex] & 0x80) && (m_bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
- colour = 0;
- if (colour)
- {
- if (!m_gbc_mode)
- colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
- plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
- }
- }
- data <<= 1;
- }
- break;
- }
- }
- oam -= 4;
- }
-}
-
-void cgb_lcd_device::update_scanline()
-{
- bitmap_ind16 &bitmap = m_bitmap;
-
- g_profiler.start(PROFILER_VIDEO);
-
- if ((LCDSTAT & 0x03) == 0x03)
- {
- /* Calcuate number of pixels to render based on time still left on the timer */
- UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
- int l = 0;
-
- if (m_start_x < 0)
- {
- /* Window is enabled if the hardware says so AND the current scanline is
- * within the window AND the window X coordinate is <=166 */
- m_layer[1].enabled = ((LCDCONT & 0x20) && (m_current_line >= WNDPOSY) && (WNDPOSX <= 166)) ? 1 : 0;
-
- /* BG is enabled if the hardware says so AND (window_off OR (window_on
- * AND window's X position is >=7 )) */
- m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && (WNDPOSX >= 7)))) ? 1 : 0;
-
- if (m_layer[0].enabled)
- {
- m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
- m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
- m_layer[0].gbc_map = m_vram + m_gbc_bgdtab_offs;
- m_layer[0].xindex = SCROLLX >> 3;
- m_layer[0].xshift = SCROLLX & 7;
- m_layer[0].xstart = 0;
- m_layer[0].xend = 160;
- }
-
- if (m_layer[1].enabled)
- {
- int xpos;
-
- /* Window X position is offset by 7 so we'll need to adust */
- xpos = WNDPOSX - 7;
- if (xpos < 0)
- xpos = 0;
-
- m_layer[1].bgline = m_window_lines_drawn;
- m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
- m_layer[1].gbc_map = m_vram + m_gbc_wndtab_offs;
- m_layer[1].xindex = 0;
- m_layer[1].xshift = 0;
- m_layer[1].xstart = xpos;
- m_layer[1].xend = 160;
- m_layer[0].xend = xpos;
- }
- m_start_x = 0;
- }
-
- if (cycles_to_go < 160)
- {
- m_end_x = MIN(160 - cycles_to_go, 160);
- /* Draw empty line when the background is disabled */
- if (!(LCDCONT & 0x01))
- {
- rectangle r(m_start_x, m_end_x - 1, m_current_line, m_current_line);
- bitmap.fill((!m_gbc_mode) ? 0 : 32767, r);
- }
- while (l < 2)
- {
- UINT8 xindex, *map, *tiles, *gbcmap;
- UINT16 data;
- int i, tile_index;
-
- if (!m_layer[l].enabled)
- {
- l++;
- continue;
- }
- map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
- gbcmap = m_layer[l].gbc_map + ((m_layer[l].bgline << 2) & 0x3E0);
- tiles = (gbcmap[m_layer[l].xindex] & 0x08) ? (m_vram + m_gbc_chrgen_offs) : (m_vram + m_gb_chrgen_offs);
-
- /* Check for vertical flip */
- if (gbcmap[m_layer[l].xindex] & 0x40)
- {
- tiles += ((7 - (m_layer[l].bgline & 0x07)) << 1);
- }
- else
- {
- tiles += ((m_layer[l].bgline & 0x07) << 1);
- }
- xindex = m_start_x;
- if (xindex < m_layer[l].xstart)
- xindex = m_layer[l].xstart;
- i = m_end_x;
- if (i > m_layer[l].xend)
- i = m_layer[l].xend;
- i = i - xindex;
-
- tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
- data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
- /* Check for horinzontal flip */
- if (gbcmap[m_layer[l].xindex] & 0x20)
- {
- data >>= m_layer[l].xshift;
- }
- else
- {
- data <<= m_layer[l].xshift;
- }
-
- while (i > 0)
- {
- while ((m_layer[l].xshift < 8) && i)
- {
- int colour;
- /* Check for horinzontal flip */
- if (gbcmap[m_layer[l].xindex] & 0x20)
- {
- colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
- data >>= 1;
- }
- else
- {
- colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
- data <<= 1;
- }
- plot_pixel(bitmap, xindex, m_current_line, m_cgb_bpal[(!m_gbc_mode) ? m_gb_bpal[colour] : (((gbcmap[m_layer[l].xindex] & 0x07) * 4) + colour)]);
- m_bg_zbuf[xindex] = colour + (gbcmap[m_layer[l].xindex] & 0x80);
- xindex++;
- m_layer[l].xshift++;
- i--;
- }
- if (m_layer[l].xshift == 8)
- {
- /* Take possible changes to SCROLLY into account */
- if (l == 0)
- {
- m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
- map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
- gbcmap = m_layer[l].gbc_map + ((m_layer[l].bgline << 2) & 0x3E0);
- }
-
- m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
- m_layer[l].xshift = 0;
- tiles = (gbcmap[m_layer[l].xindex] & 0x08) ? (m_vram + m_gbc_chrgen_offs) : (m_vram + m_gb_chrgen_offs);
-
- /* Check for vertical flip */
- if (gbcmap[m_layer[l].xindex] & 0x40)
- {
- tiles += ((7 - (m_layer[l].bgline & 0x07)) << 1);
- }
- else
- {
- tiles += ((m_layer[l].bgline & 0x07) << 1);
- }
- tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
- data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
- }
- }
- l++;
- }
- if (m_end_x == 160 && (LCDCONT & 0x02))
- {
- update_sprites();
- }
- m_start_x = m_end_x;
- }
- }
- else
- {
- if (!(LCDCONT & 0x80))
- {
- /* Draw an empty line when LCD is disabled */
- if (m_previous_line != m_current_line)
- {
- if (m_current_line < 144)
- {
- const rectangle &r1 = m_screen->visible_area();
- rectangle r(r1.min_x, r1.max_x, m_current_line, m_current_line);
- bitmap.fill((!m_gbc_mode) ? 0 : 32767 , r);
- }
- m_previous_line = m_current_line;
- }
- }
- }
-
- g_profiler.stop();
-}
-
-
-TIMER_CALLBACK_MEMBER(gb_lcd_device::video_init_vbl)
-{
- m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
-}
-
-UINT32 gb_lcd_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
- return 0;
-}
-
-
-void gb_lcd_device::increment_scanline()
-{
- m_current_line = (m_current_line + 1) % 154;
- if (LCDCONT & 0x80)
- {
- CURLINE = m_current_line;
- }
- if (m_current_line == 0)
- {
- m_window_lines_drawn = 0;
- }
-}
-
-TIMER_CALLBACK_MEMBER(gb_lcd_device::lcd_timer_proc)
-{
- static const int gb_sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
-
- m_state = param;
-
- if (LCDCONT & 0x80)
- {
- switch (m_state)
- {
- case GB_LCD_STATE_LYXX_PRE_M0: /* Just before switching to mode 0 */
- m_mode = 0;
- if (LCDSTAT & 0x08)
- {
- if (!m_mode_irq)
- {
- if (!m_line_irq && !m_delayed_line_irq)
- {
- m_mode_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- else
- {
- m_mode_irq = 0;
- }
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
- break;
- case GB_LCD_STATE_LYXX_M0: /* Switch to mode 0 */
- /* update current scanline */
- update_scanline();
- /* Increment the number of window lines drawn if enabled */
- if (m_layer[1].enabled)
- {
- m_window_lines_drawn++;
- }
- m_previous_line = m_current_line;
- /* Set Mode 0 lcdstate */
- m_mode = 0;
- LCDSTAT &= 0xFC;
- m_oam_locked = UNLOCKED;
- m_vram_locked = UNLOCKED;
- /*
- There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
- SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
- than usual.
- The SGB probably has the same bug.
- */
- if ((SCROLLX & 0x03) == 0x03)
- {
- m_scrollx_adjust += 4;
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
- break;
- }
- case GB_LCD_STATE_LYXX_M0_SCX3:
- /* Generate lcd interrupt if requested */
- if (!m_mode_irq && (LCDSTAT & 0x08) &&
- ((!m_line_irq && m_delayed_line_irq) || !(LCDSTAT & 0x40)))
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(196 - m_scrollx_adjust - m_sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
- break;
- case GB_LCD_STATE_LYXX_M0_PRE_INC: /* Just before incrementing the line counter go to mode 2 internally */
- if (CURLINE < 143)
- {
- m_mode = 2;
- m_triggering_mode_irq = (LCDSTAT & 0x20) ? 1 : 0;
- if (m_triggering_mode_irq)
- {
- if (!m_mode_irq)
- {
- if (!m_line_irq && !m_delayed_line_irq)
- {
- m_mode_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- else
- {
- m_mode_irq = 0;
- }
- }
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
- break;
- case GB_LCD_STATE_LYXX_M0_INC: /* Increment LY, stay in M0 for 4 more cycles */
- increment_scanline();
- m_delayed_line_irq = m_line_irq;
- m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
- m_line_irq = 0;
- if (!m_mode_irq && !m_delayed_line_irq && m_triggering_line_irq && !m_triggering_mode_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- /* Reset LY==LYC STAT bit */
- LCDSTAT &= 0xFB;
- /* Check if we're going into VBlank next */
- if (CURLINE == 144)
- {
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
- }
- else
- {
- /* Internally switch to mode 2 */
- m_mode = 2;
- /* Generate lcd interrupt if requested */
- if (!m_mode_irq && m_triggering_mode_irq &&
- ((!m_triggering_line_irq && !m_delayed_line_irq) || !(LCDSTAT & 0x40)))
- {
- m_mode_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
- }
- break;
- case GB_LCD_STATE_LY00_M2: /* Switch to mode 2 on line #0 */
- /* Set Mode 2 lcdstate */
- m_mode = 2;
- LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
- m_oam_locked = LOCKED;
- /* Generate lcd interrupt if requested */
- if ((LCDSTAT & 0x20) && !m_line_irq)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- /* Check for regular compensation of x-scroll register */
- m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
- /* Mode 2 lasts approximately 80 clock cycles */
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
- break;
- case GB_LCD_STATE_LYXX_M2: /* Switch to mode 2 */
- /* Update STAT register to the correct state */
- LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
- m_oam_locked = LOCKED;
- /* Generate lcd interrupt if requested */
- if ((m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20)) ||
- (!m_mode_irq && !m_line_irq && !m_delayed_line_irq && m_triggering_mode_irq))
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_line_irq = m_triggering_line_irq;
- m_triggering_mode_irq = 0;
- /* Check if LY==LYC STAT bit should be set */
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- /* Check for regular compensation of x-scroll register */
- m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
- /* Mode 2 last for approximately 80 clock cycles */
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
- break;
- case GB_LCD_STATE_LYXX_M3: /* Switch to mode 3 */
- select_sprites();
- m_sprite_cycles = gb_sprite_cycles[m_sprCount];
- /* Set Mode 3 lcdstate */
- m_mode = 3;
- LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
- m_vram_locked = LOCKED;
- /* Check for compensations of x-scroll register */
- /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(168 + m_scrollx_adjust + m_sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
- m_start_x = -1;
- break;
- case GB_LCD_STATE_LY9X_M1: /* Switch to or stay in mode 1 */
- if (CURLINE == 144)
- {
- /* Trigger VBlank interrupt */
- m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
- /* Set VBlank lcdstate */
- m_mode = 1;
- LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
- /* Trigger LCD interrupt if requested */
- if (LCDSTAT & 0x10)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- /* Check if LY==LYC STAT bit should be set */
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- if (m_delayed_line_irq && m_triggering_line_irq)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
- break;
- case GB_LCD_STATE_LY9X_M1_INC: /* Increment scanline counter */
- increment_scanline();
- m_delayed_line_irq = m_line_irq;
- m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
- m_line_irq = 0;
- if (!m_delayed_line_irq && m_triggering_line_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- /* Reset LY==LYC STAT bit */
- LCDSTAT &= 0xFB;
- if (m_current_line == 153)
- {
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
- }
- else
- {
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
- }
- break;
- case GB_LCD_STATE_LY00_M1: /* we stay in VBlank but current line counter should already be incremented */
- /* Check LY=LYC for line #153 */
- if (m_delayed_line_irq)
- {
- if (m_triggering_line_irq)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- m_delayed_line_irq = m_delayed_line_irq | m_line_irq;
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- increment_scanline();
- m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
- m_line_irq = 0;
- LCDSTAT &= 0xFB;
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4/*8*/), GB_LCD_STATE_LY00_M1_1);
- break;
- case GB_LCD_STATE_LY00_M1_1:
- if (!m_delayed_line_irq && m_triggering_line_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
- break;
- case GB_LCD_STATE_LY00_M1_2: /* Rest of line #0 during VBlank */
- if (m_delayed_line_irq && m_triggering_line_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
- break;
- case GB_LCD_STATE_LY00_M0: /* The STAT register seems to go to 0 for about 4 cycles */
- /* Set Mode 0 lcdstat */
- m_mode = 0;
- LCDSTAT = (LCDSTAT & 0xFC);
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
- break;
- }
- }
- else
- {
- increment_scanline();
- if (m_current_line < 144)
- {
- update_scanline();
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
- }
-}
-
-
-// CGB specific code
-
-void cgb_lcd_device::hdma_trans(UINT16 length)
-{
- UINT16 src, dst;
- address_space &space = m_maincpu->space(AS_PROGRAM);
-
- src = ((UINT16)HDMA1 << 8) | (HDMA2 & 0xF0);
- dst = ((UINT16)(HDMA3 & 0x1F) << 8) | (HDMA4 & 0xF0);
- dst |= 0x8000;
- while (length > 0)
- {
- space.write_byte(dst++, space.read_byte(src++));
- length--;
- }
- HDMA1 = src >> 8;
- HDMA2 = src & 0xF0;
- HDMA3 = 0x1f & (dst >> 8);
- HDMA4 = dst & 0xF0;
- HDMA5--;
- if ((HDMA5 & 0x7f) == 0x7f)
- {
- HDMA5 = 0xff;
- m_hdma_enabled = 0;
- }
-}
-
-
-TIMER_CALLBACK_MEMBER(cgb_lcd_device::lcd_timer_proc)
-{
- static const int cgb_sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
-
- m_state = param;
-
- if (LCDCONT & 0x80)
- {
- switch (m_state)
- {
- case GB_LCD_STATE_LYXX_PRE_M0: /* Just before switching to mode 0 */
- m_mode = 0;
- if (LCDSTAT & 0x08)
- {
- if (!m_mode_irq)
- {
- if (!m_line_irq && !m_delayed_line_irq)
- {
- m_mode_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- else
- {
- m_mode_irq = 0;
- }
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
- break;
- case GB_LCD_STATE_LYXX_M0: /* Switch to mode 0 */
- /* update current scanline */
- update_scanline();
- /* Increment the number of window lines drawn if enabled */
- if (m_layer[1].enabled)
- {
- m_window_lines_drawn++;
- }
- m_previous_line = m_current_line;
- /* Set Mode 0 lcdstate */
- m_mode = 0;
- LCDSTAT &= 0xFC;
- m_oam_locked = UNLOCKED;
- m_vram_locked = UNLOCKED;
- /*
- There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
- SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
- than usual.
- The SGB probably has the same bug.
- */
- m_triggering_mode_irq = (LCDSTAT & 0x08) ? 1 : 0;
- if ((SCROLLX & 0x03) == 0x03)
- {
- m_scrollx_adjust += 4;
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
- break;
- }
- case GB_LCD_STATE_LYXX_M0_SCX3:
- /* Generate lcd interrupt if requested */
- if (!m_mode_irq && m_triggering_mode_irq &&
- ((!m_line_irq && m_delayed_line_irq) || !(LCDSTAT & 0x40)))
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- m_triggering_mode_irq = 0;
- }
- if ((SCROLLX & 0x03) == 0x03)
- {
- m_pal_locked = UNLOCKED;
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_GBC_PAL);
- break;
- case GB_LCD_STATE_LYXX_M0_GBC_PAL:
- m_pal_locked = UNLOCKED;
- /* Check for HBLANK DMA */
- if (m_hdma_enabled)
- {
- hdma_trans(0x10);
-// cpunum_set_reg(0, LR35902_DMA_CYCLES, 36);
- }
- else
- {
- m_hdma_possible = 1;
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(192 - m_scrollx_adjust - m_sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
- break;
- case GB_LCD_STATE_LYXX_M0_PRE_INC: /* Just before incrementing the line counter go to mode 2 internally */
- m_cmp_line = CMPLINE;
- if (CURLINE < 143)
- {
- m_mode = 2;
- if (LCDSTAT & 0x20)
- {
- if (!m_mode_irq)
- {
- if (!m_line_irq && !m_delayed_line_irq)
- {
- m_mode_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- else
- {
- m_mode_irq = 0;
- }
- }
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
- break;
- case GB_LCD_STATE_LYXX_M0_INC: /* Increment LY, stay in M0 for 4 more cycles */
- increment_scanline();
- m_delayed_line_irq = m_line_irq;
- m_triggering_line_irq = ((m_cmp_line == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
- m_line_irq = 0;
- if (!m_mode_irq && !m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20))
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_hdma_possible = 0;
- /* Check if we're going into VBlank next */
- if (CURLINE == 144)
- {
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
- }
- else
- {
- /* Internally switch to mode 2 */
- m_mode = 2;
- /* Generate lcd interrupt if requested */
- if (!m_mode_irq && (LCDSTAT & 0x20) &&
- ((!m_triggering_line_irq && !m_delayed_line_irq) || !(LCDSTAT & 0x40)))
- {
- m_mode_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
- }
- break;
- case GB_LCD_STATE_LY00_M2: /* Switch to mode 2 on line #0 */
- /* Set Mode 2 lcdstate */
- m_mode = 2;
- LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
- m_oam_locked = LOCKED;
- /* Generate lcd interrupt if requested */
- if ((LCDSTAT & 0x20) && !m_line_irq)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- /* Check for regular compensation of x-scroll register */
- m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
- /* Mode 2 lasts approximately 80 clock cycles */
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
- break;
- case GB_LCD_STATE_LYXX_M2: /* Switch to mode 2 */
- /* Update STAT register to the correct state */
- LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
- m_oam_locked = LOCKED;
- /* Generate lcd interrupt if requested */
- if ((m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20)) ||
- (!m_mode_irq && !m_line_irq && !m_delayed_line_irq && (LCDSTAT & 0x20)))
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_line_irq = m_triggering_line_irq;
- /* Check if LY==LYC STAT bit should be set */
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- else
- {
- LCDSTAT &= ~0x04;
- }
- /* Check for regular compensation of x-scroll register */
- m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
- /* Mode 2 last for approximately 80 clock cycles */
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
- break;
- case GB_LCD_STATE_LYXX_M3: /* Switch to mode 3 */
- select_sprites();
- m_sprite_cycles = cgb_sprite_cycles[m_sprCount];
- /* Set Mode 3 lcdstate */
- m_mode = 3;
- LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
- m_vram_locked = LOCKED;
- m_pal_locked = LOCKED;
- /* Check for compensations of x-scroll register */
- /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(168 + m_scrollx_adjust + m_sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
- m_start_x = -1;
- break;
- case GB_LCD_STATE_LY9X_M1: /* Switch to or stay in mode 1 */
- if (CURLINE == 144)
- {
- /* Trigger VBlank interrupt */
- m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
- /* Set VBlank lcdstate */
- m_mode = 1;
- LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
- /* Trigger LCD interrupt if requested */
- if (LCDSTAT & 0x10)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- /* Check if LY==LYC STAT bit should be set */
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- else
- {
- LCDSTAT &= ~0x04;
- }
- if (m_delayed_line_irq && m_triggering_line_irq)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
- break;
- case GB_LCD_STATE_LY9X_M1_INC: /* Increment scanline counter */
- increment_scanline();
- m_delayed_line_irq = m_line_irq;
- m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
- m_line_irq = 0;
- if (!m_delayed_line_irq && m_triggering_line_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- if (m_current_line == 153)
- {
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
- }
- else
- {
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
- }
- break;
- case GB_LCD_STATE_LY00_M1: /* we stay in VBlank but current line counter should already be incremented */
- /* Check LY=LYC for line #153 */
- if (m_delayed_line_irq)
- {
- if (m_triggering_line_irq)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- m_delayed_line_irq = m_delayed_line_irq | m_line_irq;
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- else
- {
- LCDSTAT &= ~0x04;
- }
- increment_scanline();
- m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
- m_line_irq = 0;
- LCDSTAT &= 0xFB;
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_1);
- break;
- case GB_LCD_STATE_LY00_M1_1:
- if (!m_delayed_line_irq && m_triggering_line_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
- break;
- case GB_LCD_STATE_LY00_M1_2: /* Rest of line #0 during VBlank */
- if (m_delayed_line_irq && m_triggering_line_irq)
- {
- m_line_irq = m_triggering_line_irq;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- }
- else
- {
- LCDSTAT &= ~0x04;
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
- break;
- case GB_LCD_STATE_LY00_M0: /* The STAT register seems to go to 0 for about 4 cycles */
- /* Set Mode 0 lcdstat */
- m_mode = 0;
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
- break;
- }
- }
- else
- {
- increment_scanline();
- if (m_current_line < 144)
- {
- update_scanline();
- }
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
- }
-}
-
-
-void gb_lcd_device::lcd_switch_on()
-{
- m_current_line = 0;
- m_previous_line = 153;
- m_window_lines_drawn = 0;
- m_line_irq = 0;
- m_delayed_line_irq = 0;
- m_mode = 0;
- m_oam_locked = LOCKED; /* TODO: Investigate whether this OAM locking is correct. */
- /* Check for LY=LYC coincidence */
- if (CURLINE == CMPLINE)
- {
- LCDSTAT |= 0x04;
- /* Generate lcd interrupt if requested */
- if (LCDSTAT & 0x40)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- m_state = GB_LCD_STATE_LY00_M2;
- m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
-}
-
-
-
-
-READ8_MEMBER(gb_lcd_device::vram_r)
-{
- return (m_vram_locked == LOCKED) ? 0xff : m_vram[offset + (m_vram_bank * 0x2000)];
-}
-
-WRITE8_MEMBER(gb_lcd_device::vram_w)
-{
- if (m_vram_locked == LOCKED)
- return;
-
- m_vram[offset + (m_vram_bank * 0x2000)] = data;
-}
-
-READ8_MEMBER(gb_lcd_device::oam_r)
-{
- return (m_oam_locked == LOCKED) ? 0xff : m_oam[offset];
-}
-
-WRITE8_MEMBER(gb_lcd_device::oam_w)
-{
- if (m_oam_locked == LOCKED || offset >= 0xa0)
- return;
-
- m_oam[offset] = data;
-}
-
-
-
-READ8_MEMBER(gb_lcd_device::video_r)
-{
- return m_vid_regs[offset];
-}
-
-WRITE8_MEMBER(gb_lcd_device::video_w)
-{
- switch (offset)
- {
- case 0x00: /* LCDC - LCD Control */
- m_gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800;
- m_gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
- m_gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800;
- m_gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800;
- /* if LCD controller is switched off, set STAT and LY to 00 */
- if (!(data & 0x80))
- {
- LCDSTAT &= ~0x03;
- CURLINE = 0;
- m_oam_locked = UNLOCKED;
- m_vram_locked = UNLOCKED;
- }
- /* If LCD is being switched on */
- if (!(LCDCONT & 0x80) && (data & 0x80))
- {
- lcd_switch_on();
- }
- break;
- case 0x01: /* STAT - LCD Status */
- data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
- /*
- Check for the STAT bug:
- Writing to STAT when the LCD controller is active causes a STAT
- interrupt to be triggered.
- */
- if (LCDCONT & 0x80)
- {
- /* Triggers seen so far:
- - 0x40 -> 0x00 - trigger
- - 0x00 -> 0x08 - trigger
- - 0x08 -> 0x00 - don't trigger
- - 0x00 -> 0x20 (mode 3) - trigger
- - 0x00 -> 0x60 (mode 2) - don't trigger
- - 0x20 -> 0x60 (mode 3) - trigger
- - 0x20 -> 0x40 (mode 3) - trigger
- - 0x40 -> 0x20 (mode 2) - don't trigger
- - 0x40 -> 0x08 (mode 0) - don't trigger
- - 0x00 -> 0x40 - trigger only if LY==LYC
- - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 2, after m2int) - don't trigger
- - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 3, after m2int) - don't trigger
- */
- if (!m_mode_irq && ((m_mode == 1) ||
- ((LCDSTAT & 0x40) && !(data & 0x68)) ||
- (!(LCDSTAT & 0x40) && (data & 0x40) && (LCDSTAT & 0x04)) ||
- (!(LCDSTAT & 0x48) && (data & 0x08)) ||
- ((LCDSTAT & 0x60) == 0x00 && (data & 0x60) == 0x20) ||
- ((LCDSTAT & 0x60) == 0x20 && (data & 0x40))
- ))
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- /*
- - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
- - 0x20 -> 0x00/0x10/0x20/0x40 (mode 0, after m2int) - trigger (stat bug)
- - 0x00 -> 0xXX (mode 0) - trigger stat bug
- */
- if (m_mode_irq && m_mode == 0)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- break;
- case 0x04: /* LY - LCD Y-coordinate */
- return;
- case 0x05: /* LYC */
- if (CMPLINE != data)
- {
- if (CURLINE == data)
- {
- if (m_state != GB_LCD_STATE_LYXX_M0_INC && m_state != GB_LCD_STATE_LY9X_M1_INC)
- {
- LCDSTAT |= 0x04;
- /* Generate lcd interrupt if requested */
- if (LCDSTAT & 0x40)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- }
- else
- {
- LCDSTAT &= 0xFB;
- m_triggering_line_irq = 0;
- }
- }
- break;
- case 0x06: /* DMA - DMA Transfer and Start Address */
- {
- UINT8 *P = m_oam;
- offset = (UINT16) data << 8;
- for (data = 0; data < 0xA0; data++)
- *P++ = space.read_byte(offset++);
- }
- return;
- case 0x07: /* BGP - Background Palette */
- update_scanline();
- m_gb_bpal[0] = data & 0x3;
- m_gb_bpal[1] = (data & 0xC) >> 2;
- m_gb_bpal[2] = (data & 0x30) >> 4;
- m_gb_bpal[3] = (data & 0xC0) >> 6;
- break;
- case 0x08: /* OBP0 - Object Palette 0 */
-// update_scanline();
- m_gb_spal0[0] = data & 0x3;
- m_gb_spal0[1] = (data & 0xC) >> 2;
- m_gb_spal0[2] = (data & 0x30) >> 4;
- m_gb_spal0[3] = (data & 0xC0) >> 6;
- break;
- case 0x09: /* OBP1 - Object Palette 1 */
-// update_scanline();
- m_gb_spal1[0] = data & 0x3;
- m_gb_spal1[1] = (data & 0xC) >> 2;
- m_gb_spal1[2] = (data & 0x30) >> 4;
- m_gb_spal1[3] = (data & 0xC0) >> 6;
- break;
- case 0x02: /* SCY - Scroll Y */
- case 0x03: /* SCX - Scroll X */
- update_scanline();
- break;
- case 0x0A: /* WY - Window Y position */
- case 0x0B: /* WX - Window X position */
- break;
- default: /* Unknown register, no change */
- return;
- }
- m_vid_regs[offset] = data;
-}
-
-READ8_MEMBER(cgb_lcd_device::video_r)
-{
- switch (offset)
- {
- case 0x11: /* FF51 */
- case 0x12: /* FF52 */
- case 0x13: /* FF53 */
- case 0x14: /* FF54 */
- return 0xFF;
- case 0x29: /* FF69 */
- case 0x2B: /* FF6B */
- if (m_pal_locked == LOCKED)
- {
- return 0xFF;
- }
- break;
- }
- return m_vid_regs[offset];
-}
-
-WRITE8_MEMBER(cgb_lcd_device::video_w)
-{
- switch (offset)
- {
- case 0x00: /* LCDC - LCD Control */
- m_gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800;
- m_gbc_chrgen_offs = (data & 0x10) ? 0x2000 : 0x2800;
- m_gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
- m_gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800;
- m_gbc_bgdtab_offs = (data & 0x08) ? 0x3c00 : 0x3800;
- m_gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800;
- m_gbc_wndtab_offs = (data & 0x40) ? 0x3c00 : 0x3800;
- /* if LCD controller is switched off, set STAT to 00 */
- if (!(data & 0x80))
- {
- LCDSTAT &= ~0x03;
- CURLINE = 0;
- m_oam_locked = UNLOCKED;
- m_vram_locked = UNLOCKED;
- m_pal_locked = UNLOCKED;
- }
- /* If LCD is being switched on */
- if (!(LCDCONT & 0x80) && (data & 0x80))
- {
- lcd_switch_on();
- }
- break;
- case 0x01: /* STAT - LCD Status */
- data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
- if (LCDCONT & 0x80)
- {
- /*
- - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
- */
- if (m_mode_irq && m_mode == 0 && (LCDSTAT & 0x28) == 0x20 && (data & 0x08))
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- /* Check if line irqs are being disabled */
- if (!(data & 0x40))
- {
- m_delayed_line_irq = 0;
- }
- /* Check if line irqs are being enabled */
- if (!(LCDSTAT & 0x40) && (data & 0x40))
- {
- if (CMPLINE == CURLINE)
- {
- m_line_irq = 1;
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- }
- break;
- case 0x05: /* LYC */
- if (CMPLINE != data)
- {
- if ((m_state != GB_LCD_STATE_LYXX_M0_PRE_INC && CURLINE == data) ||
- (m_state == GB_LCD_STATE_LYXX_M0_INC && m_triggering_line_irq))
- {
- LCDSTAT |= 0x04;
- /* Generate lcd interrupt if requested */
- if (LCDSTAT & 0x40)
- {
- m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
- }
- }
- else
- {
- LCDSTAT &= 0xFB;
- m_triggering_line_irq = 0;
- m_cmp_line = data;
- }
- }
- break;
- case 0x07: /* BGP - GB background palette */
- update_scanline();
- m_gb_bpal[0] = data & 0x3;
- m_gb_bpal[1] = (data & 0xC) >> 2;
- m_gb_bpal[2] = (data & 0x30) >> 4;
- m_gb_bpal[3] = (data & 0xC0) >> 6;
- break;
- case 0x08: /* OBP0 - GB Object 0 palette */
- m_gb_spal0[0] = data & 0x3;
- m_gb_spal0[1] = (data & 0xC) >> 2;
- m_gb_spal0[2] = (data & 0x30) >> 4;
- m_gb_spal0[3] = (data & 0xC0) >> 6;
- break;
- case 0x09: /* OBP1 - GB Object 1 palette */
- m_gb_spal1[0] = data & 0x3;
- m_gb_spal1[1] = (data & 0xC) >> 2;
- m_gb_spal1[2] = (data & 0x30) >> 4;
- m_gb_spal1[3] = (data & 0xC0) >> 6;
- break;
- case 0x0c: /* Undocumented register involved in selecting gb/gbc mode */
- logerror("Write to undocumented register: %X = %X\n", offset, data);
- break;
- case 0x0F: /* VBK - VRAM bank select */
- m_vram_bank = data & 0x01;
- data |= 0xFE;
- break;
- case 0x11: /* HDMA1 - HBL General DMA - Source High */
- break;
- case 0x12: /* HDMA2 - HBL General DMA - Source Low */
- data &= 0xF0;
- break;
- case 0x13: /* HDMA3 - HBL General DMA - Destination High */
- data &= 0x1F;
- break;
- case 0x14: /* HDMA4 - HBL General DMA - Destination Low */
- data &= 0xF0;
- break;
- case 0x15: /* HDMA5 - HBL General DMA - Mode, Length */
- if (!(data & 0x80))
- {
- if (m_hdma_enabled)
- {
- m_hdma_enabled = 0;
- data = HDMA5 & 0x80;
- }
- else
- {
- /* General DMA */
- hdma_trans(((data & 0x7F) + 1) * 0x10);
-// cpunum_set_reg(0, LR35902_DMA_CYCLES, 4 + (((data & 0x7F) + 1) * 32));
- data = 0xff;
- }
- }
- else
- {
- /* H-Blank DMA */
- m_hdma_enabled = 1;
- data &= 0x7f;
- m_vid_regs[offset] = data;
- /* Check if HDMA should be immediately performed */
- if (m_hdma_possible)
- {
- hdma_trans(0x10);
-// cpunum_set_reg(0, LR35902_DMA_CYCLES, 36);
- m_hdma_possible = 0;
- }
- }
- break;
- case 0x28: /* BCPS - Background palette specification */
- GBCBCPS = data;
- if (data & 0x01)
- GBCBCPD = m_cgb_bpal[(data >> 1) & 0x1F] >> 8;
- else
- GBCBCPD = m_cgb_bpal[(data >> 1) & 0x1F] & 0xFF;
- break;
- case 0x29: /* BCPD - background palette data */
- if (m_pal_locked == LOCKED)
- {
- return;
- }
- GBCBCPD = data;
- if (GBCBCPS & 0x01)
- m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] = ((data << 8) | (m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] & 0xFF)) & 0x7FFF;
- else
- m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] = ((m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] & 0xFF00) | data) & 0x7FFF;
- if (GBCBCPS & 0x80)
- {
- GBCBCPS++;
- GBCBCPS &= 0xBF;
- }
- break;
- case 0x2A: /* OCPS - Object palette specification */
- GBCOCPS = data;
- if (data & 0x01)
- GBCOCPD = m_cgb_spal[(data >> 1) & 0x1F] >> 8;
- else
- GBCOCPD = m_cgb_spal[(data >> 1) & 0x1F] & 0xFF;
- break;
- case 0x2B: /* OCPD - Object palette data */
- if (m_pal_locked == LOCKED)
- {
- return;
- }
- GBCOCPD = data;
- if (GBCOCPS & 0x01)
- m_cgb_spal[(GBCOCPS >> 1) & 0x1F] = ((data << 8) | (m_cgb_spal[(GBCOCPS >> 1) & 0x1F] & 0xFF)) & 0x7FFF;
- else
- m_cgb_spal[(GBCOCPS >> 1) & 0x1F] = ((m_cgb_spal[(GBCOCPS >> 1) & 0x1F] & 0xFF00) | data) & 0x7FFF;
- if (GBCOCPS & 0x80)
- {
- GBCOCPS++;
- GBCOCPS &= 0xBF;
- }
- break;
- /* Undocumented registers */
- case 0x2C:
- /* bit 0 can be read/written */
- logerror("Write to undocumented register: %X = %X\n", offset, data);
- data = 0xFE | (data & 0x01);
- if (data & 0x01)
- {
- m_gbc_mode = 0;
- }
- break;
- case 0x32:
- case 0x33:
- case 0x34:
- /* whole byte can be read/written */
- logerror("Write to undocumented register: %X = %X\n", offset, data);
- break;
- case 0x35:
- /* bit 4-6 can be read/written */
- logerror("Write to undocumented register: %X = %X\n", offset, data);
- data = 0x8F | (data & 0x70);
- break;
- case 0x36:
- case 0x37:
- logerror("Write to undocumented register: %X = %X\n", offset, data);
- return;
- default:
- /* we didn't handle the write, so pass it to the GB handler */
- gb_lcd_device::video_w(space, offset, data);
- return;
- }
-
- m_vid_regs[offset] = data;
-}
-
-// Super Game Boy
-
-void sgb_lcd_device::sgb_io_write_pal(int offs, UINT8 *data)
-{
- switch (offs)
- {
- case 0x00: /* PAL01 */
- m_sgb_pal[0 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[0 * 4 + 1] = data[3] | (data[4] << 8);
- m_sgb_pal[0 * 4 + 2] = data[5] | (data[6] << 8);
- m_sgb_pal[0 * 4 + 3] = data[7] | (data[8] << 8);
- m_sgb_pal[1 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[1 * 4 + 1] = data[9] | (data[10] << 8);
- m_sgb_pal[1 * 4 + 2] = data[11] | (data[12] << 8);
- m_sgb_pal[1 * 4 + 3] = data[13] | (data[14] << 8);
- break;
- case 0x01: /* PAL23 */
- m_sgb_pal[2 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[2 * 4 + 1] = data[3] | (data[4] << 8);
- m_sgb_pal[2 * 4 + 2] = data[5] | (data[6] << 8);
- m_sgb_pal[2 * 4 + 3] = data[7] | (data[8] << 8);
- m_sgb_pal[3 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[3 * 4 + 1] = data[9] | (data[10] << 8);
- m_sgb_pal[3 * 4 + 2] = data[11] | (data[12] << 8);
- m_sgb_pal[3 * 4 + 3] = data[13] | (data[14] << 8);
- break;
- case 0x02: /* PAL03 */
- m_sgb_pal[0 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[0 * 4 + 1] = data[3] | (data[4] << 8);
- m_sgb_pal[0 * 4 + 2] = data[5] | (data[6] << 8);
- m_sgb_pal[0 * 4 + 3] = data[7] | (data[8] << 8);
- m_sgb_pal[3 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[3 * 4 + 1] = data[9] | (data[10] << 8);
- m_sgb_pal[3 * 4 + 2] = data[11] | (data[12] << 8);
- m_sgb_pal[3 * 4 + 3] = data[13] | (data[14] << 8);
- break;
- case 0x03: /* PAL12 */
- m_sgb_pal[1 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[1 * 4 + 1] = data[3] | (data[4] << 8);
- m_sgb_pal[1 * 4 + 2] = data[5] | (data[6] << 8);
- m_sgb_pal[1 * 4 + 3] = data[7] | (data[8] << 8);
- m_sgb_pal[2 * 4 + 0] = data[1] | (data[2] << 8);
- m_sgb_pal[2 * 4 + 1] = data[9] | (data[10] << 8);
- m_sgb_pal[2 * 4 + 2] = data[11] | (data[12] << 8);
- m_sgb_pal[2 * 4 + 3] = data[13] | (data[14] << 8);
- break;
- case 0x04: /* ATTR_BLK */
- {
- UINT8 I, J, K, o;
- for( K = 0; K < data[1]; K++ )
- {
- o = K * 6;
- if( data[o + 2] & 0x1 )
- {
- for( I = data[ o + 4]; I <= data[o + 6]; I++ )
- {
- for( J = data[o + 5]; J <= data[o + 7]; J++ )
- {
- m_sgb_pal_map[I][J] = data[o + 3] & 0x3;
- }
- }
- }
- }
- }
- break;
- case 0x05: /* ATTR_LIN */
- {
- UINT8 J, K;
- if( data[1] > 15 )
- data[1] = 15;
- for( K = 0; K < data[1]; K++ )
- {
- if( data[K + 1] & 0x80 )
- {
- for( J = 0; J < 20; J++ )
- {
- m_sgb_pal_map[J][data[K + 1] & 0x1f] = (data[K + 1] & 0x60) >> 5;
- }
- }
- else
- {
- for( J = 0; J < 18; J++ )
- {
- m_sgb_pal_map[data[K + 1] & 0x1f][J] = (data[K + 1] & 0x60) >> 5;
- }
- }
- }
- }
- break;
- case 0x06: /* ATTR_DIV */
- {
- UINT8 I, J;
- if( data[1] & 0x40 ) /* Vertical */
- {
- for( I = 0; I < data[2]; I++ )
- {
- for( J = 0; J < 20; J++ )
- {
- m_sgb_pal_map[J][I] = (data[1] & 0xC) >> 2;
- }
- }
- for( J = 0; J < 20; J++ )
- {
- m_sgb_pal_map[J][data[2]] = (data[1] & 0x30) >> 4;
- }
- for( I = data[2] + 1; I < 18; I++ )
- {
- for( J = 0; J < 20; J++ )
- {
- m_sgb_pal_map[J][I] = data[1] & 0x3;
- }
- }
- }
- else /* Horizontal */
- {
- for( I = 0; I < data[2]; I++ )
- {
- for( J = 0; J < 18; J++ )
- {
- m_sgb_pal_map[I][J] = (data[1] & 0xC) >> 2;
- }
- }
- for( J = 0; J < 18; J++ )
- {
- m_sgb_pal_map[data[2]][J] = (data[1] & 0x30) >> 4;
- }
- for( I = data[2] + 1; I < 20; I++ )
- {
- for( J = 0; J < 18; J++ )
- {
- m_sgb_pal_map[I][J] = data[1] & 0x3;
- }
- }
- }
- }
- break;
- case 0x07: /* ATTR_CHR */
- {
- UINT16 I, sets;
- UINT8 x, y;
- sets = (data[3] | (data[4] << 8) );
- if( sets > 360 )
- sets = 360;
- sets >>= 2;
- sets += 6;
- x = data[1];
- y = data[2];
- if( data[5] ) /* Vertical */
- {
- for( I = 6; I < sets; I++ )
- {
- m_sgb_pal_map[x][y++] = (data[I] & 0xC0) >> 6;
- if( y > 17 )
- {
- y = 0;
- x++;
- if( x > 19 )
- x = 0;
- }
-
- m_sgb_pal_map[x][y++] = (data[I] & 0x30) >> 4;
- if( y > 17 )
- {
- y = 0;
- x++;
- if( x > 19 )
- x = 0;
- }
-
- m_sgb_pal_map[x][y++] = (data[I] & 0xC) >> 2;
- if( y > 17 )
- {
- y = 0;
- x++;
- if( x > 19 )
- x = 0;
- }
-
- m_sgb_pal_map[x][y++] = data[I] & 0x3;
- if( y > 17 )
- {
- y = 0;
- x++;
- if( x > 19 )
- x = 0;
- }
- }
- }
- else /* horizontal */
- {
- for( I = 6; I < sets; I++ )
- {
- m_sgb_pal_map[x++][y] = (data[I] & 0xC0) >> 6;
- if( x > 19 )
- {
- x = 0;
- y++;
- if( y > 17 )
- y = 0;
- }
-
- m_sgb_pal_map[x++][y] = (data[I] & 0x30) >> 4;
- if( x > 19 )
- {
- x = 0;
- y++;
- if( y > 17 )
- y = 0;
- }
-
- m_sgb_pal_map[x++][y] = (data[I] & 0xC) >> 2;
- if( x > 19 )
- {
- x = 0;
- y++;
- if( y > 17 )
- y = 0;
- }
-
- m_sgb_pal_map[x++][y] = data[I] & 0x3;
- if( x > 19 )
- {
- x = 0;
- y++;
- if( y > 17 )
- y = 0;
- }
- }
- }
- }
- break;
- case 0x08: /* SOUND */
- /* This command enables internal sound effects */
- /* Not Implemented */
- break;
- case 0x09: /* SOU_TRN */
- /* This command sends data to the SNES sound processor.
- We'll need to emulate that for this to be used */
- /* Not Implemented */
- break;
- case 0x0A: /* PAL_SET */
- {
- UINT16 index_;
-
- /* Palette 0 */
- index_ = (UINT16)(data[1] | (data[2] << 8)) * 4;
- m_sgb_pal[0] = m_sgb_pal_data[index_];
- m_sgb_pal[1] = m_sgb_pal_data[index_ + 1];
- m_sgb_pal[2] = m_sgb_pal_data[index_ + 2];
- m_sgb_pal[3] = m_sgb_pal_data[index_ + 3];
- /* Palette 1 */
- index_ = (UINT16)(data[3] | (data[4] << 8)) * 4;
- m_sgb_pal[4] = m_sgb_pal_data[index_];
- m_sgb_pal[5] = m_sgb_pal_data[index_ + 1];
- m_sgb_pal[6] = m_sgb_pal_data[index_ + 2];
- m_sgb_pal[7] = m_sgb_pal_data[index_ + 3];
- /* Palette 2 */
- index_ = (UINT16)(data[5] | (data[6] << 8)) * 4;
- m_sgb_pal[8] = m_sgb_pal_data[index_];
- m_sgb_pal[9] = m_sgb_pal_data[index_ + 1];
- m_sgb_pal[10] = m_sgb_pal_data[index_ + 2];
- m_sgb_pal[11] = m_sgb_pal_data[index_ + 3];
- /* Palette 3 */
- index_ = (UINT16)(data[7] | (data[8] << 8)) * 4;
- m_sgb_pal[12] = m_sgb_pal_data[index_];
- m_sgb_pal[13] = m_sgb_pal_data[index_ + 1];
- m_sgb_pal[14] = m_sgb_pal_data[index_ + 2];
- m_sgb_pal[15] = m_sgb_pal_data[index_ + 3];
- /* Attribute File */
- if (data[9] & 0x40)
- m_sgb_window_mask = 0;
- m_sgb_atf = (data[9] & 0x3f) * (18 * 5);
- if (data[9] & 0x80)
- {
- for (int j = 0; j < 18; j++ )
- {
- for (int i = 0; i < 5; i++ )
- {
- m_sgb_pal_map[i * 4][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC0) >> 6;
- m_sgb_pal_map[(i * 4) + 1][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x30) >> 4;
- m_sgb_pal_map[(i * 4) + 2][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC) >> 2;
- m_sgb_pal_map[(i * 4) + 3][j] = m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x3;
- }
- }
- }
- }
- break;
- case 0x0B: /* PAL_TRN */
- {
- UINT16 col;
-
- for (int i = 0; i < 2048; i++ )
- {
- col = (m_vram[0x0800 + (i * 2) + 1] << 8) | m_vram[0x0800 + (i * 2)];
- m_sgb_pal_data[i] = col;
- }
- }
- break;
- case 0x0C: /* ATRC_EN */
- /* Not Implemented */
- break;
- case 0x0D: /* TEST_EN */
- /* Not Implemented */
- break;
- case 0x0E: /* ICON_EN */
- /* Not Implemented */
- break;
- case 0x0F: /* DATA_SND */
- /* Not Implemented */
- break;
- case 0x10: /* DATA_TRN */
- /* Not Implemented */
- break;
- case 0x12: /* JUMP */
- /* Not Implemented */
- break;
- case 0x13: /* CHR_TRN */
- if (data[1] & 0x1)
- memcpy(m_sgb_tile_data + 4096, m_vram + 0x0800, 4096);
- else
- memcpy(m_sgb_tile_data, m_vram + 0x0800, 4096);
- break;
- case 0x14: /* PCT_TRN */
- {
- UINT16 col;
- if (m_sgb_border_hack)
- {
- memcpy(m_sgb_tile_map, m_vram + 0x1000, 2048);
- for (int i = 0; i < 64; i++)
- {
- col = (m_vram[0x0800 + (i * 2) + 1 ] << 8) | m_vram[0x0800 + (i * 2)];
- m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
- }
- }
- else /* Do things normally */
- {
- memcpy(m_sgb_tile_map, m_vram + 0x0800, 2048);
- for (int i = 0; i < 64; i++)
- {
- col = (m_vram[0x1000 + (i * 2) + 1] << 8) | m_vram[0x1000 + (i * 2)];
- m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
- }
- }
- }
- break;
- case 0x15: /* ATTR_TRN */
- memcpy(m_sgb_atf_data, m_vram + 0x0800, 4050);
- break;
- case 0x16: /* ATTR_SET */
- {
- /* Attribute File */
- if (data[1] & 0x40)
- m_sgb_window_mask = 0;
- m_sgb_atf = (data[1] & 0x3f) * (18 * 5);
- for (int j = 0; j < 18; j++)
- {
- for (int i = 0; i < 5; i++)
- {
- m_sgb_pal_map[i * 4][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC0) >> 6;
- m_sgb_pal_map[(i * 4) + 1][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x30) >> 4;
- m_sgb_pal_map[(i * 4) + 2][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC) >> 2;
- m_sgb_pal_map[(i * 4) + 3][j] = m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x3;
- }
- }
- }
- break;
- case 0x17: /* MASK_EN */
- m_sgb_window_mask = data[1];
- break;
- case 0x18: /* OBJ_TRN */
- /* Not Implemnted */
- break;
- case 0x19: /* ? */
- /* Called by: dkl,dkl2,dkl3,zeldadx
- But I don't know what it is for. */
- /* Not Implemented */
- break;
- case 0x1E: /* Used by bootrom to transfer the gb cart header */
- break;
- case 0x1F: /* Used by bootrom to transfer the gb cart header */
- break;
- default:
- logerror( "SGB: Unknown Command 0x%02x!\n", data[0] >> 3 );
- }
-
-}