Previous 199869 Revisions Next

r23903 Monday 24th June, 2013 at 09:56:09 UTC by Fabio Priuli
(MESS) gb: misc lcd & includes cleanups. nw.
[src/mess]mess.mak
[src/mess/drivers]gb.c
[src/mess/includes]gb.h
[src/mess/machine]gb.c
[src/mess/video]gb.c gb_lcd.c* gb_lcd.h*

trunk/src/mess/video/gb.c
r23902r23903
1/***************************************************************************
2
3  gb.c
4
5  Video file to handle emulation of the Nintendo Game Boy.
6
7  Original code                               Carsten Sorensen   1998
8  Mess modifications, bug fixes and speedups  Hans de Goede      1998
9  Bug fixes, SGB and GBC code                 Anthony Kruize     2002
10  Improvements to match real hardware         Wilbert Pol        2006-2008
11
12  Timing is not accurate enough:
13  - Mode 3 takes 172 cycles (measuered with logic analyzer by costis)
14
15***************************************************************************/
16
17#include "emu.h"
18#include "cpu/lr35902/lr35902.h"
19#include "includes/gb.h"
20
21#define LCDCONT     m_vid_regs[0x00]  /* LCD control register                       */
22#define LCDSTAT     m_vid_regs[0x01]  /* LCD status register                        */
23#define SCROLLY     m_vid_regs[0x02]  /* Starting Y position of the background      */
24#define SCROLLX     m_vid_regs[0x03]  /* Starting X position of the background      */
25#define CURLINE     m_vid_regs[0x04]  /* Current screen line being scanned          */
26#define CMPLINE     m_vid_regs[0x05]  /* Gen. int. when scan reaches this line      */
27#define BGRDPAL     m_vid_regs[0x07]  /* Background palette                         */
28#define SPR0PAL     m_vid_regs[0x08]  /* Sprite palette #0                          */
29#define SPR1PAL     m_vid_regs[0x09]  /* Sprite palette #1                          */
30#define WNDPOSY     m_vid_regs[0x0A]  /* Window Y position                          */
31#define WNDPOSX     m_vid_regs[0x0B]  /* Window X position                          */
32#define KEY1        m_vid_regs[0x0D]  /* Prepare speed switch                       */
33#define HDMA1       m_vid_regs[0x11]  /* HDMA source high byte                      */
34#define HDMA2       m_vid_regs[0x12]  /* HDMA source low byte                       */
35#define HDMA3       m_vid_regs[0x13]  /* HDMA destination high byte                 */
36#define HDMA4       m_vid_regs[0x14]  /* HDMA destination low byte                  */
37#define HDMA5       m_vid_regs[0x15]  /* HDMA length/mode/start                     */
38#define GBCBCPS     m_vid_regs[0x28]  /* Backgound palette spec                     */
39#define GBCBCPD     m_vid_regs[0x29]  /* Backgound palette data                     */
40#define GBCOCPS     m_vid_regs[0x2A]  /* Object palette spec                        */
41#define GBCOCPD     m_vid_regs[0x2B]  /* Object palette data                        */
42
43enum {
44   UNLOCKED=0,
45   LOCKED
46};
47
48
49enum {
50   GB_LCD_STATE_LYXX_M3=1,
51   GB_LCD_STATE_LYXX_PRE_M0,
52   GB_LCD_STATE_LYXX_M0,
53   GB_LCD_STATE_LYXX_M0_SCX3,
54   GB_LCD_STATE_LYXX_M0_GBC_PAL,
55   GB_LCD_STATE_LYXX_M0_PRE_INC,
56   GB_LCD_STATE_LYXX_M0_INC,
57   GB_LCD_STATE_LY00_M2,
58   GB_LCD_STATE_LYXX_M2,
59   GB_LCD_STATE_LY9X_M1,
60   GB_LCD_STATE_LY9X_M1_INC,
61   GB_LCD_STATE_LY00_M1,
62   GB_LCD_STATE_LY00_M1_1,
63   GB_LCD_STATE_LY00_M1_2,
64   GB_LCD_STATE_LY00_M0
65};
66
67
68static const unsigned char palette[] =
69{
70/* Simple black and white palette */
71/*  0xFF,0xFF,0xFF,
72    0xB0,0xB0,0xB0,
73    0x60,0x60,0x60,
74    0x00,0x00,0x00 */
75
76/* Possibly needs a little more green in it */
77   0xFF,0xFB,0x87,     /* Background */
78   0xB1,0xAE,0x4E,     /* Light */
79   0x84,0x80,0x4E,     /* Medium */
80   0x4E,0x4E,0x4E,     /* Dark */
81
82/* Palette for Game Boy Pocket/Light */
83   0xC4,0xCF,0xA1,     /* Background */
84   0x8B,0x95,0x6D,     /* Light      */
85   0x6B,0x73,0x53,     /* Medium     */
86   0x41,0x41,0x41,     /* Dark       */
87};
88
89static const unsigned char palette_megaduck[] = {
90   0x6B, 0xA6, 0x4A, 0x43, 0x7A, 0x63, 0x25, 0x59, 0x55, 0x12, 0x42, 0x4C
91};
92
93/* Initialise the palettes */
94PALETTE_INIT_MEMBER(gb_state, gb)
95{
96   for (int i = 0; i < 4; i++)
97      palette_set_color_rgb(machine(), i, palette[i * 3 + 0], palette[i * 3 + 1], palette[i * 3 + 2]);
98}
99
100PALETTE_INIT_MEMBER(gb_state, gbp)
101{
102   for (int i = 0; i < 4; i++)
103      palette_set_color_rgb(machine(), i, palette[(i + 4) * 3 + 0], palette[(i + 4) * 3 + 1], palette[(i + 4) * 3 + 2]);
104}
105
106PALETTE_INIT_MEMBER(gb_state, sgb)
107{
108   int r, g, b;
109   
110   for (int i = 0; i < 32768; i++)
111   {
112      r = (i & 0x1F) << 3;
113      g = ((i >> 5) & 0x1F) << 3;
114      b = ((i >> 10) & 0x1F) << 3;
115      palette_set_color_rgb(machine(), i, r, g, b);
116   }
117}
118
119PALETTE_INIT_MEMBER(gb_state, gbc)
120{
121   int r, g, b;
122
123   for (int i = 0; i < 32768; i++)
124   {
125      r = (i & 0x1F) << 3;
126      g = ((i >> 5) & 0x1F) << 3;
127      b = ((i >> 10) & 0x1F) << 3;
128      palette_set_color_rgb(machine(), i, r, g, b);
129   }
130}
131
132PALETTE_INIT_MEMBER(megaduck_state, megaduck)
133{
134   for (int i = 0; i < 4; i++)
135      palette_set_color_rgb(machine(), i, palette_megaduck[i * 3 + 0], palette_megaduck[i * 3 + 1], palette_megaduck[i * 3 + 2]);
136}
137
138
139/* OAM contents on power up.
140 
141 The OAM area seems contain some kind of unit fingerprint. On each boot
142 the data is almost always the same. Some random bits are flipped between
143 different boots. It is currently unknown how much these fingerprints
144 differ between different units.
145 
146 OAM fingerprints taken from Wilbert Pol's own unit.
147 */
148
149static const UINT8 dmg_oam_fingerprint[0x100] = {
150   0xD8, 0xE6, 0xB3, 0x89, 0xEC, 0xDE, 0x11, 0x62, 0x0B, 0x7E, 0x48, 0x9E, 0xB9, 0x6E, 0x26, 0xC9,
151   0x36, 0xF4, 0x7D, 0xE4, 0xD9, 0xCE, 0xFA, 0x5E, 0xA3, 0x77, 0x60, 0xFC, 0x1C, 0x64, 0x8B, 0xAC,
152   0xB6, 0x74, 0x3F, 0x9A, 0x0E, 0xFE, 0xEA, 0xA9, 0x40, 0x3A, 0x7A, 0xB6, 0xF2, 0xED, 0xA8, 0x3E,
153   0xAF, 0x2C, 0xD2, 0xF2, 0x01, 0xE0, 0x5B, 0x3A, 0x53, 0x6A, 0x1C, 0x6C, 0x20, 0xD9, 0x22, 0xB4,
154   0x8C, 0x38, 0x71, 0x69, 0x3E, 0x93, 0xA3, 0x22, 0xCE, 0x76, 0x24, 0xE7, 0x1A, 0x14, 0x6B, 0xB1,
155   0xF9, 0x3D, 0xBF, 0x3D, 0x74, 0x64, 0xCB, 0xF5, 0xDC, 0x9A, 0x53, 0xC6, 0x0E, 0x78, 0x34, 0xCB,
156   0x42, 0xB3, 0xFF, 0x07, 0x73, 0xAE, 0x6C, 0xA2, 0x6F, 0x6A, 0xA4, 0x66, 0x0A, 0x8C, 0x40, 0xB3,
157   0x9A, 0x3D, 0x39, 0x78, 0xAB, 0x29, 0xE7, 0xC5, 0x7A, 0xDD, 0x51, 0x95, 0x2B, 0xE4, 0x1B, 0xF6,
158   0x31, 0x16, 0x34, 0xFE, 0x11, 0xF2, 0x5E, 0x11, 0xF3, 0x95, 0x66, 0xB9, 0x37, 0xC2, 0xAD, 0x6D,
159   0x1D, 0xA7, 0x79, 0x06, 0xD7, 0xE5, 0x8F, 0xFA, 0x9C, 0x02, 0x0C, 0x31, 0x8B, 0x17, 0x2E, 0x31,
160   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
166};
167
168static const UINT8 mgb_oam_fingerprint[0x100] = {
169   0xB9, 0xE9, 0x0D, 0x69, 0xBB, 0x7F, 0x00, 0x80, 0xE9, 0x7B, 0x79, 0xA2, 0xFD, 0xCF, 0xD8, 0x0A,
170   0x87, 0xEF, 0x44, 0x11, 0xFE, 0x37, 0x10, 0x21, 0xFA, 0xFF, 0x00, 0x17, 0xF6, 0x4F, 0x83, 0x03,
171   0x3A, 0xF4, 0x00, 0x24, 0xBB, 0xAE, 0x05, 0x01, 0xFF, 0xF7, 0x12, 0x48, 0xA7, 0x5E, 0xF6, 0x28,
172   0x5B, 0xFF, 0x2E, 0x10, 0xFF, 0xB9, 0x50, 0xC8, 0xAF, 0x77, 0x2C, 0x1A, 0x62, 0xD7, 0x81, 0xC2,
173   0xFD, 0x5F, 0xA0, 0x94, 0xAF, 0xFF, 0x51, 0x20, 0x36, 0x76, 0x50, 0x0A, 0xFD, 0xF6, 0x20, 0x00,
174   0xFE, 0xF7, 0xA0, 0x68, 0xFF, 0xFC, 0x29, 0x51, 0xA3, 0xFA, 0x06, 0xC4, 0x94, 0xFF, 0x39, 0x0A,
175   0xFF, 0x6C, 0x20, 0x20, 0xF1, 0xAD, 0x0C, 0x81, 0x56, 0xFB, 0x03, 0x82, 0xFF, 0xFF, 0x08, 0x58,
176   0x96, 0x7E, 0x01, 0x4D, 0xFF, 0xE4, 0x82, 0xE3, 0x3D, 0xBB, 0x54, 0x00, 0x3D, 0xF3, 0x04, 0x21,
177   0xB7, 0x39, 0xCC, 0x10, 0xF9, 0x5B, 0x80, 0x50, 0x3F, 0x6A, 0x1C, 0x21, 0x1F, 0xFA, 0xA8, 0x52,
178   0x5F, 0xB3, 0x44, 0xA1, 0x96, 0x1E, 0x00, 0x27, 0x63, 0x77, 0x30, 0x54, 0x37, 0x6F, 0x60, 0x22,
179   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
185};
186
187static const UINT8 cgb_oam_fingerprint[0x100] = {
188   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198   0x74, 0xFF, 0x09, 0x00, 0x9D, 0x61, 0xA8, 0x28, 0x36, 0x1E, 0x58, 0xAA, 0x75, 0x74, 0xA1, 0x42,
199   0x05, 0x96, 0x40, 0x09, 0x41, 0x02, 0x60, 0x00, 0x1F, 0x11, 0x22, 0xBC, 0x31, 0x52, 0x22, 0x54,
200   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
201   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
202   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
203   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04
204};
205
206/*
207 For an AGS in CGB mode this data is: */
208#if 0
209static const UINT8 abs_oam_fingerprint[0x100] = {
210   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220   0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
221   0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
222   0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
223   0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
224   0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
225   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
226};
227#endif
228
229
230const device_type GB_LCD_DMG = &device_creator<gb_lcd_device>;
231const device_type GB_LCD_MGB = &device_creator<mgb_lcd_device>;
232const device_type GB_LCD_SGB = &device_creator<sgb_lcd_device>;
233const device_type GB_LCD_CGB = &device_creator<cgb_lcd_device>;
234
235
236
237gb_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)
238            : device_t(mconfig, type, name, tag, owner, clock, shortname, source),
239               m_sgb_border_hack(0)
240{
241}
242
243gb_lcd_device::gb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
244            : device_t(mconfig, GB_LCD_DMG, "DMG LCD", tag, owner, clock, "dmg_lcd", __FILE__),
245               m_sgb_border_hack(0)
246{
247}
248
249mgb_lcd_device::mgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
250            : gb_lcd_device(mconfig, GB_LCD_MGB, "MGB LCD", tag, owner, clock, "mgb_lcd", __FILE__)
251{
252}
253
254sgb_lcd_device::sgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
255            : gb_lcd_device(mconfig, GB_LCD_SGB, "SGB LCD", tag, owner, clock, "sgb_lcd", __FILE__)
256{
257}
258
259cgb_lcd_device::cgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
260            : gb_lcd_device(mconfig, GB_LCD_CGB, "CGB LCD", tag, owner, clock, "cgb_lcd", __FILE__)
261{
262}
263
264
265//-------------------------------------------------
266//  device_start - device-specific startup
267//-------------------------------------------------
268
269void gb_lcd_device::common_start()
270{
271   machine().primary_screen->register_screen_bitmap(m_bitmap);
272   m_oam = auto_alloc_array_clear(machine(), UINT8, 0x100);
273   
274   m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_lcd_device::lcd_timer_proc),this));
275   machine().save().register_postload(save_prepost_delegate(FUNC(gb_lcd_device::videoptr_restore), this));
276
277   m_maincpu = machine().device<cpu_device>("maincpu");
278   m_screen = machine().device<screen_device>("screen");
279
280   save_pointer(NAME(m_oam), 0x100);
281   save_item(NAME(m_window_lines_drawn));
282   save_item(NAME(m_vid_regs));
283   save_item(NAME(m_bg_zbuf));
284   
285   save_item(NAME(m_cgb_bpal));
286   save_item(NAME(m_cgb_spal));
287   
288   save_item(NAME(m_gb_bpal));
289   save_item(NAME(m_gb_spal0));
290   save_item(NAME(m_gb_spal1));
291   
292   save_item(NAME(m_current_line));
293   save_item(NAME(m_cmp_line));
294   save_item(NAME(m_sprCount));
295   save_item(NAME(m_sprite));
296   save_item(NAME(m_previous_line));
297   save_item(NAME(m_start_x));
298   save_item(NAME(m_end_x));
299   save_item(NAME(m_mode));
300   save_item(NAME(m_state));
301   save_item(NAME(m_lcd_irq_line));
302   save_item(NAME(m_triggering_line_irq));
303   save_item(NAME(m_line_irq));
304   save_item(NAME(m_triggering_mode_irq));
305   save_item(NAME(m_mode_irq));
306   save_item(NAME(m_delayed_line_irq));
307   save_item(NAME(m_sprite_cycles));
308   save_item(NAME(m_scrollx_adjust));
309   save_item(NAME(m_oam_locked));
310   save_item(NAME(m_vram_locked));
311   save_item(NAME(m_pal_locked));
312   save_item(NAME(m_hdma_enabled));
313   save_item(NAME(m_hdma_possible));
314   save_item(NAME(m_gbc_mode));
315   save_item(NAME(m_gb_tile_no_mod));
316   save_item(NAME(m_vram_bank));
317   
318   save_item(NAME(m_gb_chrgen_offs));
319   save_item(NAME(m_gb_bgdtab_offs));
320   save_item(NAME(m_gb_wndtab_offs));
321   save_item(NAME(m_gbc_chrgen_offs));
322   save_item(NAME(m_gbc_bgdtab_offs));
323   save_item(NAME(m_gbc_wndtab_offs));
324   
325   save_item(NAME(m_layer[0].enabled));
326   save_item(NAME(m_layer[0].xindex));
327   save_item(NAME(m_layer[0].xshift));
328   save_item(NAME(m_layer[0].xstart));
329   save_item(NAME(m_layer[0].xend));
330   save_item(NAME(m_layer[0].bgline));
331   save_item(NAME(m_layer[1].enabled));
332   save_item(NAME(m_layer[1].xindex));
333   save_item(NAME(m_layer[1].xshift));
334   save_item(NAME(m_layer[1].xstart));
335   save_item(NAME(m_layer[1].xend));
336   save_item(NAME(m_layer[1].bgline));
337}
338
339
340void gb_lcd_device::videoptr_restore()
341{
342   m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
343   m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
344   m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
345   m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
346}
347
348void cgb_lcd_device::videoptr_restore()
349{
350   m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
351   m_layer[0].gbc_map = m_vram + m_gbc_bgdtab_offs;
352   m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
353   m_layer[1].gbc_map = m_vram + m_gbc_wndtab_offs;
354}
355
356
357void gb_lcd_device::device_start()
358{
359   common_start();
360
361   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
362   save_pointer(NAME(m_vram), 0x2000);
363   
364   memcpy(m_oam, dmg_oam_fingerprint, 0x100);
365}
366
367void mgb_lcd_device::device_start()
368{
369   common_start();
370   
371   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
372   save_pointer(NAME(m_vram), 0x2000);
373
374   memcpy(m_oam, mgb_oam_fingerprint, 0x100);
375
376   /* Initialize part of VRAM. This code must be deleted when we have added the bios dump */
377   for (int i = 1; i < 0x0d; i++)
378   {
379      m_vram[0x1903 + i] = i;
380      m_vram[0x1923 + i] = i + 0x0C;
381   }
382   m_vram[0x1910] = 0x19;
383}
384
385void sgb_lcd_device::device_start()
386{
387   common_start();
388   
389   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
390   save_pointer(NAME(m_vram), 0x2000);
391
392   m_sgb_tile_data = auto_alloc_array_clear(machine(), UINT8, 0x2000);
393   save_pointer(NAME(m_sgb_tile_data), 0x2000);
394   
395   /* Some default colours for non-SGB games */
396   m_sgb_pal[0] = 32767;
397   m_sgb_pal[1] = 21140;
398   m_sgb_pal[2] = 10570;
399   m_sgb_pal[3] = 0;
400   /* The rest of the colortable can be black */
401   for (int i = 4; i < 8 * 16; i++)
402      m_sgb_pal[i] = 0;
403
404   save_item(NAME(m_sgb_atf_data));
405   save_item(NAME(m_sgb_atf));
406   save_item(NAME(m_sgb_pal_data));
407   save_item(NAME(m_sgb_pal_map));
408   save_item(NAME(m_sgb_pal));
409   save_item(NAME(m_sgb_tile_map));
410   save_item(NAME(m_sgb_window_mask));
411}
412
413void cgb_lcd_device::device_start()
414{
415   common_start();
416   
417   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x4000);
418   save_pointer(NAME(m_vram), 0x4000);
419
420   memcpy(m_oam, cgb_oam_fingerprint, 0x100);
421
422   
423   /* Background is initialised as white */
424   for (int i = 0; i < 32; i++)
425      m_cgb_bpal[i] = 32767;
426   /* Sprites are supposed to be uninitialized, but we'll make them black */
427   for (int i = 0; i < 32; i++)
428      m_cgb_spal[i] = 0;
429}
430
431
432//-------------------------------------------------
433//  device_reset - device-specific reset
434//-------------------------------------------------
435
436void gb_lcd_device::common_reset()
437{   
438   m_window_lines_drawn = 0;
439   
440   m_current_line = 0;
441   m_cmp_line = 0;
442   m_sprCount = 0;
443   m_previous_line = 0;
444   m_start_x = 0;
445   m_end_x = 0;
446   m_mode = 0;
447   m_state = 0;
448   m_lcd_irq_line = 0;
449   m_triggering_line_irq = 0;
450   m_line_irq = 0;
451   m_triggering_mode_irq = 0;
452   m_mode_irq = 0;
453   m_delayed_line_irq = 0;
454   m_sprite_cycles = 0;
455   m_scrollx_adjust = 0;
456   m_oam_locked = 0;
457   m_vram_locked = 0;
458   m_pal_locked = 0;
459   m_gbc_mode = 0;
460   m_gb_tile_no_mod = 0;
461   m_vram_bank = 0;
462   
463   m_gb_chrgen_offs = 0;
464   m_gb_bgdtab_offs = 0x1c00;
465   m_gb_wndtab_offs = 0x1c00;
466   
467   memset(&m_vid_regs, 0, sizeof(m_vid_regs));
468   memset(&m_bg_zbuf, 0, sizeof(m_bg_zbuf));
469   memset(&m_cgb_bpal, 0, sizeof(m_cgb_bpal));
470   memset(&m_cgb_spal, 0, sizeof(m_cgb_spal));
471   memset(&m_sprite, 0, sizeof(m_sprite));
472   memset(&m_layer[0], 0, sizeof(m_layer[0]));
473   memset(&m_layer[1], 0, sizeof(m_layer[1]));
474   
475   // specific reg initialization
476   m_vid_regs[0x06] = 0xff;
477   
478   for (int i = 0x0c; i < _NR_GB_VID_REGS; i++)
479      m_vid_regs[i] = 0xff;
480   
481   LCDSTAT = 0x80;
482   LCDCONT = 0x00;     /* Video hardware is turned off at boot time */
483   m_current_line = CURLINE = CMPLINE = 0x00;
484   SCROLLX = SCROLLY = 0x00;
485   SPR0PAL = SPR1PAL = 0xFF;
486   WNDPOSX = WNDPOSY = 0x00;
487   
488   // Initialize palette arrays
489   for (int i = 0; i < 4; i++)
490      m_gb_bpal[i] = m_gb_spal0[i] = m_gb_spal1[i] = i;
491   
492}
493
494
495void gb_lcd_device::device_reset()
496{
497   common_reset();
498
499   m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
500}
501
502void mgb_lcd_device::device_reset()
503{
504   address_space &space = m_maincpu->space(AS_PROGRAM);
505   common_reset();
506
507   /* Make sure the VBlank interrupt is set when the first instruction gets executed */
508   machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(1), timer_expired_delegate(FUNC(mgb_lcd_device::video_init_vbl),this));
509   
510   /* Initialize some video registers */
511   video_w(space, 0x0, 0x91);    /* LCDCONT */
512   video_w(space, 0x7, 0xFC);    /* BGRDPAL */
513   video_w(space, 0x8, 0xFC);    /* SPR0PAL */
514   video_w(space, 0x9, 0xFC);    /* SPR1PAL */
515   
516   CURLINE = m_current_line = 0;
517   LCDSTAT = (LCDSTAT & 0xF8) | 0x05;
518   m_mode = 1;
519
520   m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(60), GB_LCD_STATE_LY00_M0);
521}
522
523void sgb_lcd_device::device_reset()
524{
525   common_reset();
526
527   memset(m_sgb_tile_data, 0, 0x2000);
528
529   m_sgb_window_mask = 0;
530
531   memset(m_sgb_pal_map, 0, sizeof(m_sgb_pal_map));   
532   memset(m_sgb_atf_data, 0, sizeof(m_sgb_atf_data));
533}
534
535void cgb_lcd_device::device_reset()
536{
537   common_reset();
538   
539   m_gbc_chrgen_offs = 0x2000;
540   m_gbc_bgdtab_offs = 0x3c00;
541   m_gbc_wndtab_offs = 0x3c00;
542   
543   /* HDMA disabled */
544   m_hdma_enabled = 0;
545   m_hdma_possible = 0;
546   
547   m_gbc_mode = 1;
548   
549}
550
551
552
553inline void gb_lcd_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
554{
555   bitmap.pix16(y, x) = (UINT16)color;
556}
557
558/*
559  Select which sprites should be drawn for the current scanline and return the
560  number of sprites selected.
561 */
562void gb_lcd_device::select_sprites()
563{
564   int /*yindex,*/ line, height;
565   UINT8 *oam = m_oam + 39 * 4;
566
567   m_sprCount = 0;
568
569   /* If video hardware is enabled and sprites are enabled */
570   if ((LCDCONT & 0x80) && (LCDCONT & 0x02))
571   {
572      /* Check for stretched sprites */
573      if (LCDCONT & 0x04)
574         height = 16;
575      else
576         height = 8;
577
578      //yindex = m_current_line;
579      line = m_current_line + 16;
580
581      for (int i = 39; i >= 0; i--)
582      {
583         if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
584         {
585            /* We limit the sprite count to max 10 here;
586               proper games should not exceed this... */
587            if (m_sprCount < 10)
588            {
589               m_sprite[m_sprCount] = i;
590               m_sprCount++;
591            }
592         }
593         oam -= 4;
594      }
595   }
596}
597
598void gb_lcd_device::update_sprites()
599{
600   bitmap_ind16 &bitmap = m_bitmap;
601   UINT8 height, tilemask, line, *oam, *vram;
602   int yindex;
603
604   if (LCDCONT & 0x04)
605   {
606      height = 16;
607      tilemask = 0xFE;
608   }
609   else
610   {
611      height = 8;
612      tilemask = 0xFF;
613   }
614
615   yindex = m_current_line;
616   line = m_current_line + 16;
617
618   oam = m_oam + 39 * 4;
619   vram = m_vram;
620   for (int i = 39; i >= 0; i--)
621   {
622      /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
623      if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
624      {
625         UINT16 data;
626         UINT8 bit, *spal;
627         int xindex, adr;
628
629         spal = (oam[3] & 0x10) ? m_gb_spal1 : m_gb_spal0;
630         xindex = oam[1] - 8;
631         if (oam[3] & 0x40)         /* flip y ? */
632         {
633            adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
634         }
635         else
636         {
637            adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
638         }
639         data = (vram[adr + 1] << 8) | vram[adr];
640
641         switch (oam[3] & 0xA0)
642         {
643         case 0xA0:                 /* priority is set (behind bgnd & wnd, flip x) */
644            for (bit = 0; bit < 8; bit++, xindex++)
645            {
646               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
647               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
648                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
649               data >>= 1;
650            }
651            break;
652         case 0x20:                 /* priority is not set (overlaps bgnd & wnd, flip x) */
653            for (bit = 0; bit < 8; bit++, xindex++)
654            {
655               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
656               if (colour && xindex >= 0 && xindex < 160)
657                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
658               data >>= 1;
659            }
660            break;
661         case 0x80:                 /* priority is set (behind bgnd & wnd, don't flip x) */
662            for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
663            {
664               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
665               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
666                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
667               data <<= 1;
668            }
669            break;
670         case 0x00:                 /* priority is not set (overlaps bgnd & wnd, don't flip x) */
671            for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
672            {
673               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
674               if (colour && xindex >= 0 && xindex < 160)
675                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
676               data <<= 1;
677            }
678            break;
679         }
680      }
681      oam -= 4;
682   }
683}
684
685void gb_lcd_device::update_scanline()
686{
687   bitmap_ind16 &bitmap = m_bitmap;
688
689   g_profiler.start(PROFILER_VIDEO);
690
691   /* Make sure we're in mode 3 */
692   if ((LCDSTAT & 0x03) == 0x03)
693   {
694      /* Calculate number of pixels to render based on time still left on the timer */
695      UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
696      int l = 0;
697
698      if (m_start_x < 0)
699      {
700         /* Window is enabled if the hardware says so AND the current scanline is
701          * within the window AND the window X coordinate is <=166 */
702         m_layer[1].enabled = ((LCDCONT & 0x20) && (m_current_line >= WNDPOSY) && (WNDPOSX <= 166)) ? 1 : 0;
703
704         /* BG is enabled if the hardware says so AND (window_off OR (window_on
705         * AND window's X position is >=7)) */
706         m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && (WNDPOSX >= 7)))) ? 1 : 0;
707
708         if (m_layer[0].enabled)
709         {
710            m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
711            m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
712            m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
713            m_layer[0].xindex = SCROLLX >> 3;
714            m_layer[0].xshift = SCROLLX & 7;
715            m_layer[0].xstart = 0;
716            m_layer[0].xend = 160;
717         }
718
719         if (m_layer[1].enabled)
720         {
721            int xpos = WNDPOSX - 7;             /* Window is offset by 7 pixels */
722            if (xpos < 0)
723               xpos = 0;
724
725            m_layer[1].bgline = m_window_lines_drawn;
726            m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
727            m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
728            m_layer[1].xindex = 0;
729            m_layer[1].xshift = 0;
730            m_layer[1].xstart = xpos;
731            m_layer[1].xend = 160;
732            m_layer[0].xend = xpos;
733         }
734         m_start_x = 0;
735      }
736
737      if (cycles_to_go < 160)
738      {
739         m_end_x = MIN(160 - cycles_to_go, 160);
740         /* Draw empty pixels when the background is disabled */
741         if (!(LCDCONT & 0x01))
742         {
743            rectangle r(m_start_x, m_end_x - 1, m_current_line, m_current_line);
744            bitmap.fill(m_gb_bpal[0], r);
745         }
746         while (l < 2)
747         {
748            UINT8 xindex, *map, *tiles;
749            UINT16 data;
750            int i, tile_index;
751
752            if (!m_layer[l].enabled)
753            {
754               l++;
755               continue;
756            }
757            map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
758            tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
759            xindex = m_start_x;
760            if (xindex < m_layer[l].xstart)
761               xindex = m_layer[l].xstart;
762            i = m_end_x;
763            if (i > m_layer[l].xend)
764               i = m_layer[l].xend;
765            i = i - xindex;
766
767            tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
768            data = tiles[tile_index] | (tiles[tile_index+1] << 8);
769            data <<= m_layer[l].xshift;
770
771            while (i > 0)
772            {
773               while ((m_layer[l].xshift < 8) && i)
774               {
775                  register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
776                  plot_pixel(bitmap, xindex, m_current_line, m_gb_bpal[colour]);
777                  m_bg_zbuf[xindex] = colour;
778                  xindex++;
779                  data <<= 1;
780                  m_layer[l].xshift++;
781                  i--;
782               }
783               if (m_layer[l].xshift == 8)
784               {
785                  /* Take possible changes to SCROLLY into account */
786                  if (l == 0)
787                  {
788                     m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
789                     map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
790                     tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
791                  }
792
793                  m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
794                  m_layer[l].xshift = 0;
795                  tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
796                  data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
797               }
798            }
799            l++;
800         }
801         if (m_end_x == 160 && LCDCONT & 0x02)
802         {
803            update_sprites();
804         }
805         m_start_x = m_end_x;
806      }
807   }
808   else
809   {
810      if (!(LCDCONT & 0x80))
811      {
812         /* Draw an empty line when LCD is disabled */
813         if (m_previous_line != m_current_line)
814         {
815            if (m_current_line < 144)
816            {
817               screen_device *screen = machine().first_screen();
818               const rectangle &r = screen->visible_area();
819               rectangle r1(r.min_x, r.max_x, m_current_line, m_current_line);
820               bitmap.fill(0, r1);
821            }
822            m_previous_line = m_current_line;
823         }
824      }
825   }
826
827   g_profiler.stop();
828}
829
830/* --- Super Game Boy Specific --- */
831
832void sgb_lcd_device::update_sprites()
833{
834   bitmap_ind16 &bitmap = m_bitmap;
835   UINT8 height, tilemask, line, *oam, *vram, pal;
836   INT16 yindex;
837
838   if (LCDCONT & 0x04)
839   {
840      height = 16;
841      tilemask = 0xFE;
842   }
843   else
844   {
845      height = 8;
846      tilemask = 0xFF;
847   }
848
849   /* Offset to center of screen */
850   yindex = m_current_line + SGB_YOFFSET;
851   line = m_current_line + 16;
852
853   oam = m_oam + 39 * 4;
854   vram = m_vram;
855   for (int i = 39; i >= 0; i--)
856   {
857      /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
858      if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
859      {
860         UINT16 data;
861         UINT8 bit, *spal;
862         INT16 xindex;
863         int adr;
864
865         spal = (oam[3] & 0x10) ? m_gb_spal1 : m_gb_spal0;
866         xindex = oam[1] - 8;
867         if (oam[3] & 0x40)         /* flip y ? */
868         {
869            adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
870         }
871         else
872         {
873            adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
874         }
875         data = (vram[adr + 1] << 8) | vram[adr];
876
877         /* Find the palette to use */
878         pal = m_sgb_pal_map[(xindex >> 3)][((yindex - SGB_YOFFSET) >> 3)] << 2;
879
880         /* Offset to center of screen */
881         xindex += SGB_XOFFSET;
882
883         switch (oam[3] & 0xA0)
884         {
885         case 0xA0:                 /* priority is set (behind bgnd & wnd, flip x) */
886            for (bit = 0; bit < 8; bit++, xindex++)
887            {
888               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
889               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !m_bg_zbuf[xindex - SGB_XOFFSET])
890                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
891               data >>= 1;
892            }
893            break;
894         case 0x20:                 /* priority is not set (overlaps bgnd & wnd, flip x) */
895            for (bit = 0; bit < 8; bit++, xindex++)
896            {
897               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
898               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
899                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
900               data >>= 1;
901            }
902            break;
903         case 0x80:                 /* priority is set (behind bgnd & wnd, don't flip x) */
904            for (bit = 0; bit < 8; bit++, xindex++)
905            {
906               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
907               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !m_bg_zbuf[xindex - SGB_XOFFSET])
908                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
909               data <<= 1;
910            }
911            break;
912         case 0x00:                 /* priority is not set (overlaps bgnd & wnd, don't flip x) */
913            for (bit = 0; bit < 8; bit++, xindex++)
914            {
915               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
916               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
917                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
918               data <<= 1;
919            }
920            break;
921         }
922      }
923      oam -= 4;
924   }
925}
926
927
928void sgb_lcd_device::refresh_border()
929{
930   UINT16 data, data2;
931   UINT8 *tiles, *tiles2;
932
933   for (UINT16 yidx = 0; yidx < 224; yidx++)
934   {
935      UINT8 *map = m_sgb_tile_map + ((yidx >> 3) * 64);
936      UINT16 xindex = 0;
937
938      for (UINT16 xidx = 0; xidx < 64; xidx += 2)
939      {
940         if (map[xidx + 1] & 0x80) /* Vertical flip */
941            tiles = m_sgb_tile_data + ((7 - (yidx % 8)) << 1);
942         else /* No vertical flip */
943            tiles = m_sgb_tile_data + ((yidx % 8) << 1);
944         tiles2 = tiles + 16;
945
946         UINT8 pal = (map[xidx + 1] & 0x1C) >> 2;
947         if (pal == 0)
948            pal = 1;
949         pal <<= 4;
950
951         if (m_sgb_border_hack)
952         { /* A few games do weird stuff */
953            UINT8 tileno = map[xidx];
954            if (tileno >= 128) tileno = ((64 + tileno) % 128) + 128;
955            else tileno = (64 + tileno) % 128;
956            data = tiles[tileno * 32] | (tiles[(tileno * 32) + 1] << 8);
957            data2 = tiles2[tileno * 32] | (tiles2[(tileno * 32) + 1] << 8);
958         }
959         else
960         {
961            data = tiles[map[xidx] * 32] | (tiles[(map[xidx] * 32) + 1] << 8);
962            data2 = tiles2[map[xidx] * 32] | (tiles2[(map[xidx] * 32) + 1] << 8);
963         }
964
965         for (int i = 0; i < 8; i++)
966         {
967            register UINT8 colour;
968            if ((map[xidx + 1] & 0x40))  /* Horizontal flip */
969            {
970               colour = ((data  & 0x0001) ? 1 : 0) | ((data  & 0x0100) ? 2 : 0) |
971                     ((data2 & 0x0001) ? 4 : 0) | ((data2 & 0x0100) ? 8 : 0);
972               data >>= 1;
973               data2 >>= 1;
974            }
975            else    /* No horizontal flip */
976            {
977               colour = ((data  & 0x0080) ? 1 : 0) | ((data  & 0x8000) ? 2 : 0) |
978                     ((data2 & 0x0080) ? 4 : 0) | ((data2 & 0x8000) ? 8 : 0);
979               data <<= 1;
980               data2 <<= 1;
981            }
982            /* A slight hack below so we don't draw over the GB screen.
983             * Drawing there is allowed, but due to the way we draw the
984             * scanline, it can obscure the screen even when it shouldn't.
985             */
986            if (!((yidx >= SGB_YOFFSET && yidx < SGB_YOFFSET + 144) &&
987               (xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160)))
988            {
989               plot_pixel(m_bitmap, xindex, yidx, m_sgb_pal[pal + colour]);
990            }
991            xindex++;
992         }
993      }
994   }
995}
996
997void sgb_lcd_device::update_scanline()
998{
999   bitmap_ind16 &bitmap = m_bitmap;
1000
1001   g_profiler.start(PROFILER_VIDEO);
1002
1003   if ((LCDSTAT & 0x03) == 0x03)
1004   {
1005      /* Calcuate number of pixels to render based on time still left on the timer */
1006      UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
1007      int l = 0;
1008
1009      if (m_start_x < 0)
1010      {
1011         /* Window is enabled if the hardware says so AND the current scanline is
1012          * within the window AND the window X coordinate is <=166 */
1013         m_layer[1].enabled = ((LCDCONT & 0x20) && m_current_line >= WNDPOSY && WNDPOSX <= 166) ? 1 : 0;
1014
1015         /* BG is enabled if the hardware says so AND (window_off OR (window_on
1016          * AND window's X position is >=7 )) */
1017         m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && WNDPOSX >= 7))) ? 1 : 0;
1018
1019         if (m_layer[0].enabled)
1020         {
1021            m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1022            m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
1023            m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
1024            m_layer[0].xindex = SCROLLX >> 3;
1025            m_layer[0].xshift = SCROLLX & 7;
1026            m_layer[0].xstart = 0;
1027            m_layer[0].xend = 160;
1028         }
1029
1030         if (m_layer[1].enabled)
1031         {
1032            int xpos;
1033
1034            /* Window X position is offset by 7 so we'll need to adjust */
1035            xpos = WNDPOSX - 7;
1036            if (xpos < 0)
1037               xpos = 0;
1038
1039            m_layer[1].bgline = m_window_lines_drawn;
1040            m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
1041            m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
1042            m_layer[1].xindex = 0;
1043            m_layer[1].xshift = 0;
1044            m_layer[1].xstart = xpos;
1045            m_layer[1].xend = 160;
1046            m_layer[0].xend = xpos;
1047         }
1048         m_start_x = 0;
1049      }
1050
1051      if (cycles_to_go == 0)
1052      {
1053         /* Does this belong here? or should it be moved to the else block */
1054         /* Handle SGB mask */
1055         switch (m_sgb_window_mask)
1056         {
1057         case 1: /* Freeze screen */
1058            return;
1059         case 2: /* Blank screen (black) */
1060            {
1061               rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160-1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
1062               bitmap.fill(0, r);
1063            }
1064            return;
1065         case 3: /* Blank screen (white - or should it be color 0?) */
1066            {
1067               rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
1068               bitmap.fill(32767, r);
1069            }
1070            return;
1071         }
1072
1073         /* Draw the "border" if we're on the first line */
1074         if (m_current_line == 0)
1075         {
1076            refresh_border();
1077         }
1078      }
1079      if (cycles_to_go < 160)
1080      {
1081         m_end_x = MIN(160 - cycles_to_go,160);
1082
1083         /* if background or screen disabled clear line */
1084         if (!(LCDCONT & 0x01))
1085         {
1086            rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, m_current_line + SGB_YOFFSET, m_current_line + SGB_YOFFSET);
1087            bitmap.fill(0, r);
1088         }
1089         while (l < 2)
1090         {
1091            UINT8   xindex, sgb_palette, *map, *tiles;
1092            UINT16  data;
1093            int i, tile_index;
1094
1095            if (!m_layer[l].enabled)
1096            {
1097               l++;
1098               continue;
1099            }
1100            map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1101            tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
1102            xindex = m_start_x;
1103            if (xindex < m_layer[l].xstart)
1104               xindex = m_layer[l].xstart;
1105            i = m_end_x;
1106            if (i > m_layer[l].xend)
1107               i = m_layer[l].xend;
1108            i = i - xindex;
1109
1110            tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1111            data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1112            data <<= m_layer[l].xshift;
1113
1114            /* Figure out which palette we're using */
1115            sgb_palette = m_sgb_pal_map[(m_end_x - i) >> 3][m_current_line >> 3] << 2;
1116
1117            while (i > 0)
1118            {
1119               while ((m_layer[l].xshift < 8) && i)
1120               {
1121                  register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1122                  plot_pixel(bitmap, xindex + SGB_XOFFSET, m_current_line + SGB_YOFFSET, m_sgb_pal[sgb_palette + m_gb_bpal[colour]]);
1123                  m_bg_zbuf[xindex] = colour;
1124                  xindex++;
1125                  data <<= 1;
1126                  m_layer[l].xshift++;
1127                  i--;
1128               }
1129               if (m_layer[l].xshift == 8)
1130               {
1131                  /* Take possible changes to SCROLLY into account */
1132                  if (l == 0)
1133                  {
1134                     m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1135                     map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1136                     tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
1137                  }
1138
1139                  m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
1140                  m_layer[l].xshift = 0;
1141                  tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1142                  data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1143                  sgb_palette = m_sgb_pal_map[(m_end_x - i) >> 3][m_current_line >> 3] << 2;
1144               }
1145            }
1146            l++;
1147         }
1148         if ((m_end_x == 160) && (LCDCONT & 0x02))
1149         {
1150            update_sprites();
1151         }
1152         m_start_x = m_end_x;
1153      }
1154   }
1155   else
1156   {
1157      if (!(LCDCONT * 0x80))
1158      {
1159         /* if screen disabled clear line */
1160         if (m_previous_line != m_current_line)
1161         {
1162            /* Also refresh border here??? */
1163            if (m_current_line < 144)
1164            {
1165               rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, m_current_line + SGB_YOFFSET, m_current_line + SGB_YOFFSET);
1166               bitmap.fill(0, r);
1167            }
1168            m_previous_line = m_current_line;
1169         }
1170      }
1171   }
1172
1173   g_profiler.stop();
1174}
1175
1176/* --- Game Boy Color Specific --- */
1177
1178void cgb_lcd_device::update_sprites()
1179{
1180   bitmap_ind16 &bitmap = m_bitmap;
1181   UINT8 height, tilemask, line, *oam;
1182   int xindex, yindex;
1183
1184   if (LCDCONT & 0x04)
1185   {
1186      height = 16;
1187      tilemask = 0xFE;
1188   }
1189   else
1190   {
1191      height = 8;
1192      tilemask = 0xFF;
1193   }
1194
1195   yindex = m_current_line;
1196   line = m_current_line + 16;
1197
1198   oam = m_oam + 39 * 4;
1199   for (int i = 39; i >= 0; i--)
1200   {
1201      /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
1202      if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
1203      {
1204         UINT16 data;
1205         UINT8 bit, pal;
1206
1207         /* Handle mono mode for GB games */
1208         if (!m_gbc_mode)
1209            pal = (oam[3] & 0x10) ? 4 : 0;
1210         else
1211            pal = ((oam[3] & 0x7) * 4);
1212
1213         xindex = oam[1] - 8;
1214         if (oam[3] & 0x40)         /* flip y ? */
1215         {
1216            data = *((UINT16 *) &m_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2]);
1217         }
1218         else
1219         {
1220            data = *((UINT16 *) &m_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (line - oam[0]) * 2]);
1221         }
1222#ifndef LSB_FIRST
1223         data = (data << 8) | (data >> 8);
1224#endif
1225
1226         switch (oam[3] & 0xA0)
1227         {
1228         case 0xA0:                 /* priority is set (behind bgnd & wnd, flip x) */
1229            for (bit = 0; bit < 8; bit++, xindex++)
1230            {
1231               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
1232               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
1233               {
1234                  if (! m_gbc_mode)
1235                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1236                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1237               }
1238               data >>= 1;
1239            }
1240            break;
1241         case 0x20:                 /* priority is not set (overlaps bgnd & wnd, flip x) */
1242            for (bit = 0; bit < 8; bit++, xindex++)
1243            {
1244               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
1245               if ((m_bg_zbuf[xindex] & 0x80) && (m_bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
1246                  colour = 0;
1247               if (colour && xindex >= 0 && xindex < 160)
1248               {
1249                  if (! m_gbc_mode)
1250                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1251                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1252               }
1253               data >>= 1;
1254            }
1255            break;
1256         case 0x80:                 /* priority is set (behind bgnd & wnd, don't flip x) */
1257            for (bit = 0; bit < 8; bit++, xindex++)
1258            {
1259               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1260               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
1261               {
1262                  if (! m_gbc_mode)
1263                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1264                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1265               }
1266               data <<= 1;
1267            }
1268            break;
1269         case 0x00:                 /* priority is not set (overlaps bgnd & wnd, don't flip x) */
1270            for (bit = 0; bit < 8; bit++, xindex++)
1271            {
1272               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1273               if ((m_bg_zbuf[xindex] & 0x80) && (m_bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
1274                  colour = 0;
1275               if (colour && xindex >= 0 && xindex < 160)
1276               {
1277                  if (! m_gbc_mode)
1278                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1279                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1280               }
1281               data <<= 1;
1282            }
1283            break;
1284         }
1285      }
1286      oam -= 4;
1287   }
1288}
1289
1290void cgb_lcd_device::update_scanline()
1291{
1292   bitmap_ind16 &bitmap = m_bitmap;
1293
1294   g_profiler.start(PROFILER_VIDEO);
1295
1296   if ((LCDSTAT & 0x03) == 0x03)
1297   {
1298      /* Calcuate number of pixels to render based on time still left on the timer */
1299      UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
1300      int l = 0;
1301
1302      if (m_start_x < 0)
1303      {
1304         /* Window is enabled if the hardware says so AND the current scanline is
1305          * within the window AND the window X coordinate is <=166 */
1306         m_layer[1].enabled = ((LCDCONT & 0x20) && (m_current_line >= WNDPOSY) && (WNDPOSX <= 166)) ? 1 : 0;
1307
1308         /* BG is enabled if the hardware says so AND (window_off OR (window_on
1309          * AND window's X position is >=7 )) */
1310         m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && (WNDPOSX >= 7)))) ? 1 : 0;
1311
1312         if (m_layer[0].enabled)
1313         {
1314            m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1315            m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
1316            m_layer[0].gbc_map = m_vram + m_gbc_bgdtab_offs;
1317            m_layer[0].xindex = SCROLLX >> 3;
1318            m_layer[0].xshift = SCROLLX & 7;
1319            m_layer[0].xstart = 0;
1320            m_layer[0].xend = 160;
1321         }
1322
1323         if (m_layer[1].enabled)
1324         {
1325            int xpos;
1326
1327            /* Window X position is offset by 7 so we'll need to adust */
1328            xpos = WNDPOSX - 7;
1329            if (xpos < 0)
1330               xpos = 0;
1331
1332            m_layer[1].bgline = m_window_lines_drawn;
1333            m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
1334            m_layer[1].gbc_map = m_vram + m_gbc_wndtab_offs;
1335            m_layer[1].xindex = 0;
1336            m_layer[1].xshift = 0;
1337            m_layer[1].xstart = xpos;
1338            m_layer[1].xend = 160;
1339            m_layer[0].xend = xpos;
1340         }
1341         m_start_x = 0;
1342      }
1343
1344      if (cycles_to_go < 160)
1345      {
1346         m_end_x = MIN(160 - cycles_to_go, 160);
1347         /* Draw empty line when the background is disabled */
1348         if (!(LCDCONT & 0x01))
1349         {
1350            rectangle r(m_start_x, m_end_x - 1, m_current_line, m_current_line);
1351            bitmap.fill((!m_gbc_mode) ? 0 : 32767, r);
1352         }
1353         while (l < 2)
1354         {
1355            UINT8   xindex, *map, *tiles, *gbcmap;
1356            UINT16  data;
1357            int i, tile_index;
1358
1359            if (!m_layer[l].enabled)
1360            {
1361               l++;
1362               continue;
1363            }
1364            map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1365            gbcmap = m_layer[l].gbc_map + ((m_layer[l].bgline << 2) & 0x3E0);
1366            tiles = (gbcmap[m_layer[l].xindex] & 0x08) ? (m_vram + m_gbc_chrgen_offs) : (m_vram + m_gb_chrgen_offs);
1367
1368            /* Check for vertical flip */
1369            if (gbcmap[m_layer[l].xindex] & 0x40)
1370            {
1371               tiles += ((7 - (m_layer[l].bgline & 0x07)) << 1);
1372            }
1373            else
1374            {
1375               tiles += ((m_layer[l].bgline & 0x07) << 1);
1376            }
1377            xindex = m_start_x;
1378            if (xindex < m_layer[l].xstart)
1379               xindex = m_layer[l].xstart;
1380            i = m_end_x;
1381            if (i > m_layer[l].xend)
1382               i = m_layer[l].xend;
1383            i = i - xindex;
1384
1385            tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1386            data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1387            /* Check for horinzontal flip */
1388            if (gbcmap[m_layer[l].xindex] & 0x20)
1389            {
1390               data >>= m_layer[l].xshift;
1391            }
1392            else
1393            {
1394               data <<= m_layer[l].xshift;
1395            }
1396
1397            while (i > 0)
1398            {
1399               while ((m_layer[l].xshift < 8) && i)
1400               {
1401                  int colour;
1402                  /* Check for horinzontal flip */
1403                  if (gbcmap[m_layer[l].xindex] & 0x20)
1404                  {
1405                     colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
1406                     data >>= 1;
1407                  }
1408                  else
1409                  {
1410                     colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1411                     data <<= 1;
1412                  }
1413                  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)]);
1414                  m_bg_zbuf[xindex] = colour + (gbcmap[m_layer[l].xindex] & 0x80);
1415                  xindex++;
1416                  m_layer[l].xshift++;
1417                  i--;
1418               }
1419               if (m_layer[l].xshift == 8)
1420               {
1421                  /* Take possible changes to SCROLLY into account */
1422                  if (l == 0)
1423                  {
1424                     m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1425                     map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1426                     gbcmap = m_layer[l].gbc_map + ((m_layer[l].bgline << 2) & 0x3E0);
1427                  }
1428
1429                  m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
1430                  m_layer[l].xshift = 0;
1431                  tiles = (gbcmap[m_layer[l].xindex] & 0x08) ? (m_vram + m_gbc_chrgen_offs) : (m_vram + m_gb_chrgen_offs);
1432
1433                  /* Check for vertical flip */
1434                  if (gbcmap[m_layer[l].xindex] & 0x40)
1435                  {
1436                     tiles += ((7 - (m_layer[l].bgline & 0x07)) << 1);
1437                  }
1438                  else
1439                  {
1440                     tiles += ((m_layer[l].bgline & 0x07) << 1);
1441                  }
1442                  tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1443                  data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1444               }
1445            }
1446            l++;
1447         }
1448         if (m_end_x == 160 && (LCDCONT & 0x02))
1449         {
1450            update_sprites();
1451         }
1452         m_start_x = m_end_x;
1453      }
1454   }
1455   else
1456   {
1457      if (!(LCDCONT & 0x80))
1458      {
1459         /* Draw an empty line when LCD is disabled */
1460         if (m_previous_line != m_current_line)
1461         {
1462            if (m_current_line < 144)
1463            {
1464               screen_device *screen = machine().first_screen();
1465               const rectangle &r1 = screen->visible_area();
1466               rectangle r(r1.min_x, r1.max_x, m_current_line, m_current_line);
1467               bitmap.fill((!m_gbc_mode) ? 0 : 32767 , r);
1468            }
1469            m_previous_line = m_current_line;
1470         }
1471      }
1472   }
1473
1474   g_profiler.stop();
1475}
1476
1477
1478TIMER_CALLBACK_MEMBER(gb_lcd_device::video_init_vbl)
1479{
1480   m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
1481}
1482
1483UINT32 gb_lcd_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
1484{
1485   copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
1486   return 0;
1487}
1488
1489
1490void gb_lcd_device::increment_scanline()
1491{
1492   m_current_line = (m_current_line + 1) % 154;
1493   if (LCDCONT & 0x80)
1494   {
1495      CURLINE = m_current_line;
1496   }
1497   if (m_current_line == 0)
1498   {
1499      m_window_lines_drawn = 0;
1500   }
1501}
1502
1503TIMER_CALLBACK_MEMBER(gb_lcd_device::lcd_timer_proc)
1504{
1505   static const int sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
1506
1507   m_state = param;
1508
1509   if (LCDCONT & 0x80)
1510   {
1511      switch (m_state)
1512      {
1513      case GB_LCD_STATE_LYXX_PRE_M0:  /* Just before switching to mode 0 */
1514         m_mode = 0;
1515         if (LCDSTAT & 0x08)
1516         {
1517            if (!m_mode_irq)
1518            {
1519               if (!m_line_irq && !m_delayed_line_irq)
1520               {
1521                  m_mode_irq = 1;
1522                  m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1523               }
1524            }
1525            else
1526            {
1527               m_mode_irq = 0;
1528            }
1529         }
1530         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
1531         break;
1532      case GB_LCD_STATE_LYXX_M0:      /* Switch to mode 0 */
1533         /* update current scanline */
1534         update_scanline();
1535         /* Increment the number of window lines drawn if enabled */
1536         if (m_layer[1].enabled)
1537         {
1538            m_window_lines_drawn++;
1539         }
1540         m_previous_line = m_current_line;
1541         /* Set Mode 0 lcdstate */
1542         m_mode = 0;
1543         LCDSTAT &= 0xFC;
1544         m_oam_locked = UNLOCKED;
1545         m_vram_locked = UNLOCKED;
1546         /*
1547             There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
1548             SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
1549             than usual.
1550             The SGB probably has the same bug.
1551         */
1552         if ((SCROLLX & 0x03) == 0x03)
1553         {
1554            m_scrollx_adjust += 4;
1555            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
1556            break;
1557         }
1558      case GB_LCD_STATE_LYXX_M0_SCX3:
1559         /* Generate lcd interrupt if requested */
1560         if (!m_mode_irq && (LCDSTAT & 0x08) &&
1561               ((!m_line_irq && m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1562         {
1563            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1564         }
1565         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(196 - m_scrollx_adjust - m_sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
1566         break;
1567      case GB_LCD_STATE_LYXX_M0_PRE_INC:  /* Just before incrementing the line counter go to mode 2 internally */
1568         if (CURLINE < 143)
1569         {
1570            m_mode = 2;
1571            m_triggering_mode_irq = (LCDSTAT & 0x20) ? 1 : 0;
1572            if (m_triggering_mode_irq)
1573            {
1574               if (!m_mode_irq)
1575               {
1576                  if (!m_line_irq && !m_delayed_line_irq)
1577                  {
1578                     m_mode_irq = 1;
1579                     m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1580                  }
1581               }
1582               else
1583               {
1584                  m_mode_irq = 0;
1585               }
1586            }
1587         }
1588         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
1589         break;
1590      case GB_LCD_STATE_LYXX_M0_INC:  /* Increment LY, stay in M0 for 4 more cycles */
1591         increment_scanline();
1592         m_delayed_line_irq = m_line_irq;
1593         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1594         m_line_irq = 0;
1595         if (!m_mode_irq && !m_delayed_line_irq && m_triggering_line_irq && !m_triggering_mode_irq)
1596         {
1597            m_line_irq = m_triggering_line_irq;
1598            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1599         }
1600         /* Reset LY==LYC STAT bit */
1601         LCDSTAT &= 0xFB;
1602         /* Check if we're going into VBlank next */
1603         if (CURLINE == 144)
1604         {
1605            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1606         }
1607         else
1608         {
1609            /* Internally switch to mode 2 */
1610            m_mode = 2;
1611            /* Generate lcd interrupt if requested */
1612            if (!m_mode_irq && m_triggering_mode_irq &&
1613                  ((!m_triggering_line_irq && !m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1614            {
1615               m_mode_irq = 1;
1616               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1617            }
1618            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
1619         }
1620         break;
1621      case GB_LCD_STATE_LY00_M2:      /* Switch to mode 2 on line #0 */
1622         /* Set Mode 2 lcdstate */
1623         m_mode = 2;
1624         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1625         m_oam_locked = LOCKED;
1626         /* Generate lcd interrupt if requested */
1627         if ((LCDSTAT & 0x20) && !m_line_irq)
1628         {
1629            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1630         }
1631         /* Check for regular compensation of x-scroll register */
1632         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1633         /* Mode 2 lasts approximately 80 clock cycles */
1634         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1635         break;
1636      case GB_LCD_STATE_LYXX_M2:      /* Switch to mode 2 */
1637         /* Update STAT register to the correct state */
1638         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1639         m_oam_locked = LOCKED;
1640         /* Generate lcd interrupt if requested */
1641         if ((m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20)) ||
1642               (!m_mode_irq && !m_line_irq && !m_delayed_line_irq && m_triggering_mode_irq))
1643         {
1644            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1645         }
1646         m_line_irq = m_triggering_line_irq;
1647         m_triggering_mode_irq = 0;
1648         /* Check if LY==LYC STAT bit should be set */
1649         if (CURLINE == CMPLINE)
1650         {
1651            LCDSTAT |= 0x04;
1652         }
1653         /* Check for regular compensation of x-scroll register */
1654         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1655         /* Mode 2 last for approximately 80 clock cycles */
1656         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1657         break;
1658      case GB_LCD_STATE_LYXX_M3:      /* Switch to mode 3 */
1659         select_sprites();
1660         m_sprite_cycles = sprite_cycles[m_sprCount];
1661         /* Set Mode 3 lcdstate */
1662         m_mode = 3;
1663         LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
1664         m_vram_locked = LOCKED;
1665         /* Check for compensations of x-scroll register */
1666         /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
1667         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(168 + m_scrollx_adjust + m_sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
1668         m_start_x = -1;
1669         break;
1670      case GB_LCD_STATE_LY9X_M1:      /* Switch to or stay in mode 1 */
1671         if (CURLINE == 144)
1672         {
1673            /* Trigger VBlank interrupt */
1674            m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
1675            /* Set VBlank lcdstate */
1676            m_mode = 1;
1677            LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
1678            /* Trigger LCD interrupt if requested */
1679            if (LCDSTAT & 0x10)
1680            {
1681               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1682            }
1683         }
1684         /* Check if LY==LYC STAT bit should be set */
1685         if (CURLINE == CMPLINE)
1686         {
1687            LCDSTAT |= 0x04;
1688         }
1689         if (m_delayed_line_irq && m_triggering_line_irq)
1690         {
1691            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1692         }
1693         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
1694         break;
1695      case GB_LCD_STATE_LY9X_M1_INC:      /* Increment scanline counter */
1696         increment_scanline();
1697         m_delayed_line_irq = m_line_irq;
1698         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1699         m_line_irq = 0;
1700         if (!m_delayed_line_irq && m_triggering_line_irq)
1701         {
1702            m_line_irq = m_triggering_line_irq;
1703            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1704         }
1705         /* Reset LY==LYC STAT bit */
1706         LCDSTAT &= 0xFB;
1707         if (m_current_line == 153)
1708         {
1709            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
1710         }
1711         else
1712         {
1713            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1714         }
1715         break;
1716      case GB_LCD_STATE_LY00_M1:      /* we stay in VBlank but current line counter should already be incremented */
1717         /* Check LY=LYC for line #153 */
1718         if (m_delayed_line_irq)
1719         {
1720            if (m_triggering_line_irq)
1721            {
1722               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1723            }
1724         }
1725         m_delayed_line_irq = m_delayed_line_irq | m_line_irq;
1726         if (CURLINE == CMPLINE)
1727         {
1728            LCDSTAT |= 0x04;
1729         }
1730         increment_scanline();
1731         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1732         m_line_irq = 0;
1733         LCDSTAT &= 0xFB;
1734         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4/*8*/), GB_LCD_STATE_LY00_M1_1);
1735         break;
1736      case GB_LCD_STATE_LY00_M1_1:
1737         if (!m_delayed_line_irq && m_triggering_line_irq)
1738         {
1739            m_line_irq = m_triggering_line_irq;
1740            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1741         }
1742         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
1743         break;
1744      case GB_LCD_STATE_LY00_M1_2:    /* Rest of line #0 during VBlank */
1745         if (m_delayed_line_irq && m_triggering_line_irq)
1746         {
1747            m_line_irq = m_triggering_line_irq;
1748            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1749         }
1750         if (CURLINE == CMPLINE)
1751         {
1752            LCDSTAT |= 0x04;
1753         }
1754         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
1755         break;
1756      case GB_LCD_STATE_LY00_M0:      /* The STAT register seems to go to 0 for about 4 cycles */
1757         /* Set Mode 0 lcdstat */
1758         m_mode = 0;
1759         LCDSTAT = (LCDSTAT & 0xFC);
1760         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
1761         break;
1762      }
1763   }
1764   else
1765   {
1766      increment_scanline();
1767      if (m_current_line < 144)
1768      {
1769         update_scanline();
1770      }
1771      m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
1772   }
1773}
1774
1775
1776// CGB specific code
1777
1778void cgb_lcd_device::hdma_trans(UINT16 length)
1779{
1780   UINT16 src, dst;
1781   address_space &space = m_maincpu->space(AS_PROGRAM);
1782   
1783   src = ((UINT16)HDMA1 << 8) | (HDMA2 & 0xF0);
1784   dst = ((UINT16)(HDMA3 & 0x1F) << 8) | (HDMA4 & 0xF0);
1785   dst |= 0x8000;
1786   while (length > 0)
1787   {
1788      space.write_byte(dst++, space.read_byte(src++));
1789      length--;
1790   }
1791   HDMA1 = src >> 8;
1792   HDMA2 = src & 0xF0;
1793   HDMA3 = 0x1f & (dst >> 8);
1794   HDMA4 = dst & 0xF0;
1795   HDMA5--;
1796   if ((HDMA5 & 0x7f) == 0x7f)
1797   {
1798      HDMA5 = 0xff;
1799      m_hdma_enabled = 0;
1800   }
1801}
1802
1803
1804TIMER_CALLBACK_MEMBER(cgb_lcd_device::lcd_timer_proc)
1805{
1806   static const int sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
1807
1808   m_state = param;
1809
1810   if (LCDCONT & 0x80)
1811   {
1812      switch (m_state)
1813      {
1814      case GB_LCD_STATE_LYXX_PRE_M0:  /* Just before switching to mode 0 */
1815         m_mode = 0;
1816         if (LCDSTAT & 0x08)
1817         {
1818            if (!m_mode_irq)
1819            {
1820               if (!m_line_irq && !m_delayed_line_irq)
1821               {
1822                  m_mode_irq = 1;
1823                  m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1824               }
1825            }
1826            else
1827            {
1828               m_mode_irq = 0;
1829            }
1830         }
1831         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
1832         break;
1833      case GB_LCD_STATE_LYXX_M0:      /* Switch to mode 0 */
1834         /* update current scanline */
1835         update_scanline();
1836         /* Increment the number of window lines drawn if enabled */
1837         if (m_layer[1].enabled)
1838         {
1839            m_window_lines_drawn++;
1840         }
1841         m_previous_line = m_current_line;
1842         /* Set Mode 0 lcdstate */
1843         m_mode = 0;
1844         LCDSTAT &= 0xFC;
1845         m_oam_locked = UNLOCKED;
1846         m_vram_locked = UNLOCKED;
1847         /*
1848             There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
1849             SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
1850             than usual.
1851             The SGB probably has the same bug.
1852         */
1853         m_triggering_mode_irq = (LCDSTAT & 0x08) ? 1 : 0;
1854         if ((SCROLLX & 0x03) == 0x03)
1855         {
1856            m_scrollx_adjust += 4;
1857            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
1858            break;
1859         }
1860      case GB_LCD_STATE_LYXX_M0_SCX3:
1861         /* Generate lcd interrupt if requested */
1862         if (!m_mode_irq && m_triggering_mode_irq &&
1863               ((!m_line_irq && m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1864         {
1865            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1866            m_triggering_mode_irq = 0;
1867         }
1868         if ((SCROLLX & 0x03) == 0x03)
1869         {
1870            m_pal_locked = UNLOCKED;
1871         }
1872         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_GBC_PAL);
1873         break;
1874      case GB_LCD_STATE_LYXX_M0_GBC_PAL:
1875         m_pal_locked = UNLOCKED;
1876         /* Check for HBLANK DMA */
1877         if (m_hdma_enabled)
1878         {
1879            hdma_trans(0x10);
1880//              cpunum_set_reg(0, LR35902_DMA_CYCLES, 36);
1881         }
1882         else
1883         {
1884            m_hdma_possible = 1;
1885         }
1886         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(192 - m_scrollx_adjust - m_sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
1887         break;
1888      case GB_LCD_STATE_LYXX_M0_PRE_INC:  /* Just before incrementing the line counter go to mode 2 internally */
1889         m_cmp_line = CMPLINE;
1890         if (CURLINE < 143)
1891         {
1892            m_mode = 2;
1893            if (LCDSTAT & 0x20)
1894            {
1895               if (!m_mode_irq)
1896               {
1897                  if (!m_line_irq && !m_delayed_line_irq)
1898                  {
1899                     m_mode_irq = 1;
1900                     m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1901                  }
1902               }
1903               else
1904               {
1905                  m_mode_irq = 0;
1906               }
1907            }
1908         }
1909         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
1910         break;
1911      case GB_LCD_STATE_LYXX_M0_INC:  /* Increment LY, stay in M0 for 4 more cycles */
1912         increment_scanline();
1913         m_delayed_line_irq = m_line_irq;
1914         m_triggering_line_irq = ((m_cmp_line == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1915         m_line_irq = 0;
1916         if (!m_mode_irq && !m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20))
1917         {
1918            m_line_irq = m_triggering_line_irq;
1919            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1920         }
1921         m_hdma_possible = 0;
1922         /* Check if we're going into VBlank next */
1923         if (CURLINE == 144)
1924         {
1925            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1926         }
1927         else
1928         {
1929            /* Internally switch to mode 2 */
1930            m_mode = 2;
1931            /* Generate lcd interrupt if requested */
1932            if (!m_mode_irq && (LCDSTAT & 0x20) &&
1933                  ((!m_triggering_line_irq && !m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1934            {
1935               m_mode_irq = 1;
1936               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1937            }
1938            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
1939         }
1940         break;
1941      case GB_LCD_STATE_LY00_M2:      /* Switch to mode 2 on line #0 */
1942         /* Set Mode 2 lcdstate */
1943         m_mode = 2;
1944         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1945         m_oam_locked = LOCKED;
1946         /* Generate lcd interrupt if requested */
1947         if ((LCDSTAT & 0x20) && ! m_line_irq)
1948         {
1949            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1950         }
1951         /* Check for regular compensation of x-scroll register */
1952         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1953         /* Mode 2 lasts approximately 80 clock cycles */
1954         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1955         break;
1956      case GB_LCD_STATE_LYXX_M2:      /* Switch to mode 2 */
1957         /* Update STAT register to the correct state */
1958         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1959         m_oam_locked = LOCKED;
1960         /* Generate lcd interrupt if requested */
1961         if ((m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20)) ||
1962               (!m_mode_irq && !m_line_irq && !m_delayed_line_irq && (LCDSTAT & 0x20)))
1963         {
1964            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1965         }
1966         m_line_irq = m_triggering_line_irq;
1967         /* Check if LY==LYC STAT bit should be set */
1968         if (CURLINE == CMPLINE)
1969         {
1970            LCDSTAT |= 0x04;
1971         }
1972         else
1973         {
1974            LCDSTAT &= ~0x04;
1975         }
1976         /* Check for regular compensation of x-scroll register */
1977         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1978         /* Mode 2 last for approximately 80 clock cycles */
1979         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1980         break;
1981      case GB_LCD_STATE_LYXX_M3:      /* Switch to mode 3 */
1982         select_sprites();
1983         m_sprite_cycles = sprite_cycles[m_sprCount];
1984         /* Set Mode 3 lcdstate */
1985         m_mode = 3;
1986         LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
1987         m_vram_locked = LOCKED;
1988         m_pal_locked = LOCKED;
1989         /* Check for compensations of x-scroll register */
1990         /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
1991         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(168 + m_scrollx_adjust + m_sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
1992         m_start_x = -1;
1993         break;
1994      case GB_LCD_STATE_LY9X_M1:      /* Switch to or stay in mode 1 */
1995         if (CURLINE == 144)
1996         {
1997            /* Trigger VBlank interrupt */
1998            m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
1999            /* Set VBlank lcdstate */
2000            m_mode = 1;
2001            LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
2002            /* Trigger LCD interrupt if requested */
2003            if (LCDSTAT & 0x10)
2004            {
2005               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2006            }
2007         }
2008         /* Check if LY==LYC STAT bit should be set */
2009         if (CURLINE == CMPLINE)
2010         {
2011            LCDSTAT |= 0x04;
2012         }
2013         else
2014         {
2015            LCDSTAT &= ~0x04;
2016         }
2017         if (m_delayed_line_irq && m_triggering_line_irq)
2018         {
2019            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2020         }
2021         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
2022         break;
2023      case GB_LCD_STATE_LY9X_M1_INC:      /* Increment scanline counter */
2024         increment_scanline();
2025         m_delayed_line_irq = m_line_irq;
2026         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
2027         m_line_irq = 0;
2028         if (!m_delayed_line_irq && m_triggering_line_irq)
2029         {
2030            m_line_irq = m_triggering_line_irq;
2031            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2032         }
2033         if (m_current_line == 153)
2034         {
2035            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
2036         }
2037         else
2038         {
2039            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
2040         }
2041         break;
2042      case GB_LCD_STATE_LY00_M1:      /* we stay in VBlank but current line counter should already be incremented */
2043         /* Check LY=LYC for line #153 */
2044         if (m_delayed_line_irq)
2045         {
2046            if (m_triggering_line_irq)
2047            {
2048               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2049            }
2050         }
2051         m_delayed_line_irq = m_delayed_line_irq | m_line_irq;
2052         if (CURLINE == CMPLINE)
2053         {
2054            LCDSTAT |= 0x04;
2055         }
2056         else
2057         {
2058            LCDSTAT &= ~0x04;
2059         }
2060         increment_scanline();
2061         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
2062         m_line_irq = 0;
2063         LCDSTAT &= 0xFB;
2064         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_1);
2065         break;
2066      case GB_LCD_STATE_LY00_M1_1:
2067         if (!m_delayed_line_irq && m_triggering_line_irq)
2068         {
2069            m_line_irq = m_triggering_line_irq;
2070            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2071         }
2072         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
2073         break;
2074      case GB_LCD_STATE_LY00_M1_2:    /* Rest of line #0 during VBlank */
2075         if (m_delayed_line_irq && m_triggering_line_irq)
2076         {
2077            m_line_irq = m_triggering_line_irq;
2078            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2079         }
2080         if (CURLINE == CMPLINE)
2081         {
2082            LCDSTAT |= 0x04;
2083         }
2084         else
2085         {
2086            LCDSTAT &= ~0x04;
2087         }
2088         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
2089         break;
2090      case GB_LCD_STATE_LY00_M0:      /* The STAT register seems to go to 0 for about 4 cycles */
2091         /* Set Mode 0 lcdstat */
2092         m_mode = 0;
2093         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
2094         break;
2095      }
2096   }
2097   else
2098   {
2099      increment_scanline();
2100      if (m_current_line < 144)
2101      {
2102         update_scanline();
2103      }
2104      m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
2105   }
2106}
2107
2108
2109void gb_lcd_device::lcd_switch_on()
2110{
2111   m_current_line = 0;
2112   m_previous_line = 153;
2113   m_window_lines_drawn = 0;
2114   m_line_irq = 0;
2115   m_delayed_line_irq = 0;
2116   m_mode = 0;
2117   m_oam_locked = LOCKED;   /* TODO: Investigate whether this OAM locking is correct. */
2118   /* Check for LY=LYC coincidence */
2119   if (CURLINE == CMPLINE)
2120   {
2121      LCDSTAT |= 0x04;
2122      /* Generate lcd interrupt if requested */
2123      if (LCDSTAT & 0x40)
2124      {
2125         m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2126      }
2127   }
2128   m_state = GB_LCD_STATE_LY00_M2;
2129   m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
2130}
2131
2132
2133
2134
2135READ8_MEMBER(gb_lcd_device::vram_r)
2136{
2137   return (m_vram_locked == LOCKED) ? 0xff : m_vram[offset + (m_vram_bank * 0x2000)];
2138}
2139
2140WRITE8_MEMBER(gb_lcd_device::vram_w)
2141{
2142   if (m_vram_locked == LOCKED)
2143      return;
2144   
2145   m_vram[offset + (m_vram_bank * 0x2000)] = data;
2146}
2147
2148READ8_MEMBER(gb_lcd_device::oam_r)
2149{
2150   return (m_oam_locked == LOCKED) ? 0xff : m_oam[offset];
2151}
2152
2153WRITE8_MEMBER(gb_lcd_device::oam_w)
2154{
2155   if (m_oam_locked == LOCKED || offset >= 0xa0)
2156      return;
2157   
2158   m_oam[offset] = data;
2159}
2160
2161
2162
2163READ8_MEMBER(gb_lcd_device::video_r)
2164{
2165   return m_vid_regs[offset];
2166}
2167
2168WRITE8_MEMBER(gb_lcd_device::video_w)
2169{
2170   switch (offset)
2171   {
2172   case 0x00:                      /* LCDC - LCD Control */
2173      m_gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800;
2174      m_gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
2175      m_gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800;
2176      m_gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800;
2177      /* if LCD controller is switched off, set STAT and LY to 00 */
2178      if (!(data & 0x80))
2179      {
2180         LCDSTAT &= ~0x03;
2181         CURLINE = 0;
2182         m_oam_locked = UNLOCKED;
2183         m_vram_locked = UNLOCKED;
2184      }
2185      /* If LCD is being switched on */
2186      if (!(LCDCONT & 0x80) && (data & 0x80))
2187      {
2188         lcd_switch_on();
2189      }
2190      break;
2191   case 0x01:                      /* STAT - LCD Status */
2192      data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
2193      /*
2194         Check for the STAT bug:
2195         Writing to STAT when the LCD controller is active causes a STAT
2196         interrupt to be triggered.
2197       */
2198      if (LCDCONT & 0x80)
2199      {
2200         /* Triggers seen so far:
2201            - 0x40 -> 0x00 - trigger
2202            - 0x00 -> 0x08 - trigger
2203            - 0x08 -> 0x00 - don't trigger
2204            - 0x00 -> 0x20 (mode 3) - trigger
2205            - 0x00 -> 0x60 (mode 2) - don't trigger
2206            - 0x20 -> 0x60 (mode 3) - trigger
2207            - 0x20 -> 0x40 (mode 3) - trigger
2208            - 0x40 -> 0x20 (mode 2) - don't trigger
2209            - 0x40 -> 0x08 (mode 0) - don't trigger
2210            - 0x00 -> 0x40 - trigger only if LY==LYC
2211            - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 2, after m2int) - don't trigger
2212            - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 3, after m2int) - don't trigger
2213         */
2214         if (!m_mode_irq && ((m_mode == 1) ||
2215            ((LCDSTAT & 0x40) && !(data & 0x68)) ||
2216            (!(LCDSTAT & 0x40) && (data & 0x40) && (LCDSTAT & 0x04)) ||
2217            (!(LCDSTAT & 0x48) && (data & 0x08)) ||
2218            ((LCDSTAT & 0x60) == 0x00 && (data & 0x60) == 0x20) ||
2219            ((LCDSTAT & 0x60) == 0x20 && (data & 0x40))
2220            ))
2221         {
2222            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2223         }
2224         /*
2225            - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
2226            - 0x20 -> 0x00/0x10/0x20/0x40 (mode 0, after m2int) - trigger (stat bug)
2227            - 0x00 -> 0xXX (mode 0) - trigger stat bug
2228         */
2229         if (m_mode_irq && m_mode == 0)
2230         {
2231            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2232         }
2233      }
2234      break;
2235   case 0x04:                      /* LY - LCD Y-coordinate */
2236      return;
2237   case 0x05:                      /* LYC */
2238      if (CMPLINE != data)
2239      {
2240         if (CURLINE == data)
2241         {
2242            if (m_state != GB_LCD_STATE_LYXX_M0_INC && m_state != GB_LCD_STATE_LY9X_M1_INC)
2243            {
2244               LCDSTAT |= 0x04;
2245               /* Generate lcd interrupt if requested */
2246               if (LCDSTAT & 0x40)
2247               {
2248                  m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2249               }
2250            }
2251         }
2252         else
2253         {
2254            LCDSTAT &= 0xFB;
2255            m_triggering_line_irq = 0;
2256         }
2257      }
2258      break;
2259   case 0x06:                      /* DMA - DMA Transfer and Start Address */
2260      {
2261         UINT8 *P = m_oam;
2262         offset = (UINT16) data << 8;
2263         for (data = 0; data < 0xA0; data++)
2264            *P++ = space.read_byte(offset++);
2265      }
2266      return;
2267   case 0x07:                      /* BGP - Background Palette */
2268      update_scanline();
2269      m_gb_bpal[0] = data & 0x3;
2270      m_gb_bpal[1] = (data & 0xC) >> 2;
2271      m_gb_bpal[2] = (data & 0x30) >> 4;
2272      m_gb_bpal[3] = (data & 0xC0) >> 6;
2273      break;
2274   case 0x08:                      /* OBP0 - Object Palette 0 */
2275//      update_scanline();
2276      m_gb_spal0[0] = data & 0x3;
2277      m_gb_spal0[1] = (data & 0xC) >> 2;
2278      m_gb_spal0[2] = (data & 0x30) >> 4;
2279      m_gb_spal0[3] = (data & 0xC0) >> 6;
2280      break;
2281   case 0x09:                      /* OBP1 - Object Palette 1 */
2282//      update_scanline();
2283      m_gb_spal1[0] = data & 0x3;
2284      m_gb_spal1[1] = (data & 0xC) >> 2;
2285      m_gb_spal1[2] = (data & 0x30) >> 4;
2286      m_gb_spal1[3] = (data & 0xC0) >> 6;
2287      break;
2288   case 0x02:                      /* SCY - Scroll Y */
2289   case 0x03:                      /* SCX - Scroll X */
2290      update_scanline();
2291      break;
2292   case 0x0A:                      /* WY - Window Y position */
2293   case 0x0B:                      /* WX - Window X position */
2294      break;
2295   default:                        /* Unknown register, no change */
2296      return;
2297   }
2298   m_vid_regs[offset] = data;
2299}
2300
2301READ8_MEMBER(cgb_lcd_device::video_r)
2302{
2303   switch (offset)
2304   {
2305   case 0x11:  /* FF51 */
2306   case 0x12:  /* FF52 */
2307   case 0x13:  /* FF53 */
2308   case 0x14:  /* FF54 */
2309      return 0xFF;
2310   case 0x29:  /* FF69 */
2311   case 0x2B:  /* FF6B */
2312      if (m_pal_locked == LOCKED)
2313      {
2314         return 0xFF;
2315      }
2316      break;
2317   }
2318   return m_vid_regs[offset];
2319}
2320
2321WRITE8_MEMBER(cgb_lcd_device::video_w)
2322{
2323   switch (offset)
2324   {
2325   case 0x00:      /* LCDC - LCD Control */
2326      m_gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800;
2327      m_gbc_chrgen_offs = (data & 0x10) ? 0x2000 : 0x2800;
2328      m_gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
2329      m_gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800;
2330      m_gbc_bgdtab_offs = (data & 0x08) ? 0x3c00 : 0x3800;
2331      m_gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800;
2332      m_gbc_wndtab_offs = (data & 0x40) ? 0x3c00 : 0x3800;
2333      /* if LCD controller is switched off, set STAT to 00 */
2334      if (!(data & 0x80))
2335      {
2336         LCDSTAT &= ~0x03;
2337         CURLINE = 0;
2338         m_oam_locked = UNLOCKED;
2339         m_vram_locked = UNLOCKED;
2340         m_pal_locked = UNLOCKED;
2341      }
2342      /* If LCD is being switched on */
2343      if (!(LCDCONT & 0x80) && (data & 0x80))
2344      {
2345         lcd_switch_on();
2346      }
2347      break;
2348   case 0x01:      /* STAT - LCD Status */
2349      data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
2350      if (LCDCONT & 0x80)
2351      {
2352         /*
2353            - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
2354         */
2355         if (m_mode_irq && m_mode == 0 && (LCDSTAT & 0x28) == 0x20 && (data & 0x08))
2356         {
2357            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2358         }
2359         /* Check if line irqs are being disabled */
2360         if (!(data & 0x40))
2361         {
2362            m_delayed_line_irq = 0;
2363         }
2364         /* Check if line irqs are being enabled */
2365         if (!(LCDSTAT & 0x40) && (data & 0x40))
2366         {
2367            if (CMPLINE == CURLINE)
2368            {
2369               m_line_irq = 1;
2370               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2371            }
2372         }
2373      }
2374      break;
2375   case 0x05:                      /* LYC */
2376      if (CMPLINE != data)
2377      {
2378         if ((m_state != GB_LCD_STATE_LYXX_M0_PRE_INC && CURLINE == data) ||
2379               (m_state == GB_LCD_STATE_LYXX_M0_INC && m_triggering_line_irq))
2380         {
2381            LCDSTAT |= 0x04;
2382            /* Generate lcd interrupt if requested */
2383            if (LCDSTAT & 0x40)
2384            {
2385               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2386            }
2387         }
2388         else
2389         {
2390            LCDSTAT &= 0xFB;
2391            m_triggering_line_irq = 0;
2392            m_cmp_line = data;
2393         }
2394      }
2395      break;
2396   case 0x07:      /* BGP - GB background palette */
2397      update_scanline();
2398      m_gb_bpal[0] = data & 0x3;
2399      m_gb_bpal[1] = (data & 0xC) >> 2;
2400      m_gb_bpal[2] = (data & 0x30) >> 4;
2401      m_gb_bpal[3] = (data & 0xC0) >> 6;
2402      break;
2403   case 0x08:      /* OBP0 - GB Object 0 palette */
2404      m_gb_spal0[0] = data & 0x3;
2405      m_gb_spal0[1] = (data & 0xC) >> 2;
2406      m_gb_spal0[2] = (data & 0x30) >> 4;
2407      m_gb_spal0[3] = (data & 0xC0) >> 6;
2408      break;
2409   case 0x09:      /* OBP1 - GB Object 1 palette */
2410      m_gb_spal1[0] = data & 0x3;
2411      m_gb_spal1[1] = (data & 0xC) >> 2;
2412      m_gb_spal1[2] = (data & 0x30) >> 4;
2413      m_gb_spal1[3] = (data & 0xC0) >> 6;
2414      break;
2415   case 0x0c:      /* Undocumented register involved in selecting gb/gbc mode */
2416      logerror("Write to undocumented register: %X = %X\n", offset, data);
2417      break;
2418   case 0x0F:      /* VBK - VRAM bank select */
2419      m_vram_bank = data & 0x01;
2420      data |= 0xFE;
2421      break;
2422   case 0x11:      /* HDMA1 - HBL General DMA - Source High */
2423      break;
2424   case 0x12:      /* HDMA2 - HBL General DMA - Source Low */
2425      data &= 0xF0;
2426      break;
2427   case 0x13:      /* HDMA3 - HBL General DMA - Destination High */
2428      data &= 0x1F;
2429      break;
2430   case 0x14:      /* HDMA4 - HBL General DMA - Destination Low */
2431      data &= 0xF0;
2432      break;
2433   case 0x15:      /* HDMA5 - HBL General DMA - Mode, Length */
2434      if (!(data & 0x80))
2435      {
2436         if (m_hdma_enabled)
2437         {
2438            m_hdma_enabled = 0;
2439            data = HDMA5 & 0x80;
2440         }
2441         else
2442         {
2443            /* General DMA */
2444            hdma_trans(((data & 0x7F) + 1) * 0x10);
2445//              cpunum_set_reg(0, LR35902_DMA_CYCLES, 4 + (((data & 0x7F) + 1) * 32));
2446            data = 0xff;
2447         }
2448      }
2449      else
2450      {
2451         /* H-Blank DMA */
2452         m_hdma_enabled = 1;
2453         data &= 0x7f;
2454         m_vid_regs[offset] = data;
2455         /* Check if HDMA should be immediately performed */
2456         if (m_hdma_possible)
2457         {
2458            hdma_trans(0x10);
2459//              cpunum_set_reg(0, LR35902_DMA_CYCLES, 36);
2460            m_hdma_possible = 0;
2461         }
2462      }
2463      break;
2464   case 0x28:      /* BCPS - Background palette specification */
2465      GBCBCPS = data;
2466      if (data & 0x01)
2467         GBCBCPD = m_cgb_bpal[(data >> 1) & 0x1F] >> 8;
2468      else
2469         GBCBCPD = m_cgb_bpal[(data >> 1) & 0x1F] & 0xFF;
2470      break;
2471   case 0x29:      /* BCPD - background palette data */
2472      if (m_pal_locked == LOCKED)
2473      {
2474         return;
2475      }
2476      GBCBCPD = data;
2477      if (GBCBCPS & 0x01)
2478         m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] = ((data << 8) | (m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] & 0xFF)) & 0x7FFF;
2479      else
2480         m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] = ((m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] & 0xFF00) | data) & 0x7FFF;
2481      if (GBCBCPS & 0x80)
2482      {
2483         GBCBCPS++;
2484         GBCBCPS &= 0xBF;
2485      }
2486      break;
2487   case 0x2A:      /* OCPS - Object palette specification */
2488      GBCOCPS = data;
2489      if (data & 0x01)
2490         GBCOCPD = m_cgb_spal[(data >> 1) & 0x1F] >> 8;
2491      else
2492         GBCOCPD = m_cgb_spal[(data >> 1) & 0x1F] & 0xFF;
2493      break;
2494   case 0x2B:      /* OCPD - Object palette data */
2495      if (m_pal_locked == LOCKED)
2496      {
2497         return;
2498      }
2499      GBCOCPD = data;
2500      if (GBCOCPS & 0x01)
2501         m_cgb_spal[(GBCOCPS >> 1) & 0x1F] = ((data << 8) | (m_cgb_spal[(GBCOCPS >> 1) & 0x1F] & 0xFF)) & 0x7FFF;
2502      else
2503         m_cgb_spal[(GBCOCPS >> 1) & 0x1F] = ((m_cgb_spal[(GBCOCPS >> 1) & 0x1F] & 0xFF00) | data) & 0x7FFF;
2504      if (GBCOCPS & 0x80)
2505      {
2506         GBCOCPS++;
2507         GBCOCPS &= 0xBF;
2508      }
2509      break;
2510   /* Undocumented registers */
2511   case 0x2C:
2512      /* bit 0 can be read/written */
2513      logerror("Write to undocumented register: %X = %X\n", offset, data);
2514      data = 0xFE | (data & 0x01);
2515      if (data & 0x01)
2516      {
2517         m_gbc_mode = 0;
2518      }
2519      break;
2520   case 0x32:
2521   case 0x33:
2522   case 0x34:
2523      /* whole byte can be read/written */
2524      logerror("Write to undocumented register: %X = %X\n", offset, data);
2525      break;
2526   case 0x35:
2527      /* bit 4-6 can be read/written */
2528      logerror("Write to undocumented register: %X = %X\n", offset, data);
2529      data = 0x8F | (data & 0x70);
2530      break;
2531   case 0x36:
2532   case 0x37:
2533      logerror("Write to undocumented register: %X = %X\n", offset, data);
2534      return;
2535   default:
2536      /* we didn't handle the write, so pass it to the GB handler */
2537      gb_lcd_device::video_w(space, offset, data);
2538      return;
2539   }
2540
2541   m_vid_regs[offset] = data;
2542}
2543
2544// Super Game Boy
2545
2546void sgb_lcd_device::sgb_io_write_pal(int offs, UINT8 *data)
2547{
2548   switch (offs)
2549   {
2550      case 0x00:  /* PAL01 */
2551         m_sgb_pal[0 * 4 + 0] = data[1] | (data[2] << 8);
2552         m_sgb_pal[0 * 4 + 1] = data[3] | (data[4] << 8);
2553         m_sgb_pal[0 * 4 + 2] = data[5] | (data[6] << 8);
2554         m_sgb_pal[0 * 4 + 3] = data[7] | (data[8] << 8);
2555         m_sgb_pal[1 * 4 + 0] = data[1] | (data[2] << 8);
2556         m_sgb_pal[1 * 4 + 1] = data[9] | (data[10] << 8);
2557         m_sgb_pal[1 * 4 + 2] = data[11] | (data[12] << 8);
2558         m_sgb_pal[1 * 4 + 3] = data[13] | (data[14] << 8);
2559         break;
2560      case 0x01:  /* PAL23 */
2561         m_sgb_pal[2 * 4 + 0] = data[1] | (data[2] << 8);
2562         m_sgb_pal[2 * 4 + 1] = data[3] | (data[4] << 8);
2563         m_sgb_pal[2 * 4 + 2] = data[5] | (data[6] << 8);
2564         m_sgb_pal[2 * 4 + 3] = data[7] | (data[8] << 8);
2565         m_sgb_pal[3 * 4 + 0] = data[1] | (data[2] << 8);
2566         m_sgb_pal[3 * 4 + 1] = data[9] | (data[10] << 8);
2567         m_sgb_pal[3 * 4 + 2] = data[11] | (data[12] << 8);
2568         m_sgb_pal[3 * 4 + 3] = data[13] | (data[14] << 8);
2569         break;
2570      case 0x02:  /* PAL03 */
2571         m_sgb_pal[0 * 4 + 0] = data[1] | (data[2] << 8);
2572         m_sgb_pal[0 * 4 + 1] = data[3] | (data[4] << 8);
2573         m_sgb_pal[0 * 4 + 2] = data[5] | (data[6] << 8);
2574         m_sgb_pal[0 * 4 + 3] = data[7] | (data[8] << 8);
2575         m_sgb_pal[3 * 4 + 0] = data[1] | (data[2] << 8);
2576         m_sgb_pal[3 * 4 + 1] = data[9] | (data[10] << 8);
2577         m_sgb_pal[3 * 4 + 2] = data[11] | (data[12] << 8);
2578         m_sgb_pal[3 * 4 + 3] = data[13] | (data[14] << 8);
2579         break;
2580      case 0x03:  /* PAL12 */
2581         m_sgb_pal[1 * 4 + 0] = data[1] | (data[2] << 8);
2582         m_sgb_pal[1 * 4 + 1] = data[3] | (data[4] << 8);
2583         m_sgb_pal[1 * 4 + 2] = data[5] | (data[6] << 8);
2584         m_sgb_pal[1 * 4 + 3] = data[7] | (data[8] << 8);
2585         m_sgb_pal[2 * 4 + 0] = data[1] | (data[2] << 8);
2586         m_sgb_pal[2 * 4 + 1] = data[9] | (data[10] << 8);
2587         m_sgb_pal[2 * 4 + 2] = data[11] | (data[12] << 8);
2588         m_sgb_pal[2 * 4 + 3] = data[13] | (data[14] << 8);
2589         break;
2590      case 0x04:  /* ATTR_BLK */
2591      {
2592         UINT8 I, J, K, o;
2593         for( K = 0; K < data[1]; K++ )
2594         {
2595            o = K * 6;
2596            if( data[o + 2] & 0x1 )
2597            {
2598               for( I = data[ o + 4]; I <= data[o + 6]; I++ )
2599               {
2600                  for( J = data[o + 5]; J <= data[o + 7]; J++ )
2601                  {
2602                     m_sgb_pal_map[I][J] = data[o + 3] & 0x3;
2603                  }
2604               }
2605            }
2606         }
2607      }
2608         break;
2609      case 0x05:  /* ATTR_LIN */
2610      {
2611         UINT8 J, K;
2612         if( data[1] > 15 )
2613            data[1] = 15;
2614         for( K = 0; K < data[1]; K++ )
2615         {
2616            if( data[K + 1] & 0x80 )
2617            {
2618               for( J = 0; J < 20; J++ )
2619               {
2620                  m_sgb_pal_map[J][data[K + 1] & 0x1f] = (data[K + 1] & 0x60) >> 5;
2621               }
2622            }
2623            else
2624            {
2625               for( J = 0; J < 18; J++ )
2626               {
2627                  m_sgb_pal_map[data[K + 1] & 0x1f][J] = (data[K + 1] & 0x60) >> 5;
2628               }
2629            }
2630         }
2631      }
2632         break;
2633      case 0x06:  /* ATTR_DIV */
2634      {
2635         UINT8 I, J;
2636         if( data[1] & 0x40 ) /* Vertical */
2637         {
2638            for( I = 0; I < data[2]; I++ )
2639            {
2640               for( J = 0; J < 20; J++ )
2641               {
2642                  m_sgb_pal_map[J][I] = (data[1] & 0xC) >> 2;
2643               }
2644            }
2645            for( J = 0; J < 20; J++ )
2646            {
2647               m_sgb_pal_map[J][data[2]] = (data[1] & 0x30) >> 4;
2648            }
2649            for( I = data[2] + 1; I < 18; I++ )
2650            {
2651               for( J = 0; J < 20; J++ )
2652               {
2653                  m_sgb_pal_map[J][I] = data[1] & 0x3;
2654               }
2655            }
2656         }
2657         else /* Horizontal */
2658         {
2659            for( I = 0; I < data[2]; I++ )
2660            {
2661               for( J = 0; J < 18; J++ )
2662               {
2663                  m_sgb_pal_map[I][J] = (data[1] & 0xC) >> 2;
2664               }
2665            }
2666            for( J = 0; J < 18; J++ )
2667            {
2668               m_sgb_pal_map[data[2]][J] = (data[1] & 0x30) >> 4;
2669            }
2670            for( I = data[2] + 1; I < 20; I++ )
2671            {
2672               for( J = 0; J < 18; J++ )
2673               {
2674                  m_sgb_pal_map[I][J] = data[1] & 0x3;
2675               }
2676            }
2677         }
2678      }
2679         break;
2680      case 0x07:  /* ATTR_CHR */
2681      {
2682         UINT16 I, sets;
2683         UINT8 x, y;
2684         sets = (data[3] | (data[4] << 8) );
2685         if( sets > 360 )
2686            sets = 360;
2687         sets >>= 2;
2688         sets += 6;
2689         x = data[1];
2690         y = data[2];
2691         if( data[5] ) /* Vertical */
2692         {
2693            for( I = 6; I < sets; I++ )
2694            {
2695               m_sgb_pal_map[x][y++] = (data[I] & 0xC0) >> 6;
2696               if( y > 17 )
2697               {
2698                  y = 0;
2699                  x++;
2700                  if( x > 19 )
2701                     x = 0;
2702               }
2703               
2704               m_sgb_pal_map[x][y++] = (data[I] & 0x30) >> 4;
2705               if( y > 17 )
2706               {
2707                  y = 0;
2708                  x++;
2709                  if( x > 19 )
2710                     x = 0;
2711               }
2712               
2713               m_sgb_pal_map[x][y++] = (data[I] & 0xC) >> 2;
2714               if( y > 17 )
2715               {
2716                  y = 0;
2717                  x++;
2718                  if( x > 19 )
2719                     x = 0;
2720               }
2721               
2722               m_sgb_pal_map[x][y++] = data[I] & 0x3;
2723               if( y > 17 )
2724               {
2725                  y = 0;
2726                  x++;
2727                  if( x > 19 )
2728                     x = 0;
2729               }
2730            }
2731         }
2732         else /* horizontal */
2733         {
2734            for( I = 6; I < sets; I++ )
2735            {
2736               m_sgb_pal_map[x++][y] = (data[I] & 0xC0) >> 6;
2737               if( x > 19 )
2738               {
2739                  x = 0;
2740                  y++;
2741                  if( y > 17 )
2742                     y = 0;
2743               }
2744               
2745               m_sgb_pal_map[x++][y] = (data[I] & 0x30) >> 4;
2746               if( x > 19 )
2747               {
2748                  x = 0;
2749                  y++;
2750                  if( y > 17 )
2751                     y = 0;
2752               }
2753               
2754               m_sgb_pal_map[x++][y] = (data[I] & 0xC) >> 2;
2755               if( x > 19 )
2756               {
2757                  x = 0;
2758                  y++;
2759                  if( y > 17 )
2760                     y = 0;
2761               }
2762               
2763               m_sgb_pal_map[x++][y] = data[I] & 0x3;
2764               if( x > 19 )
2765               {
2766                  x = 0;
2767                  y++;
2768                  if( y > 17 )
2769                     y = 0;
2770               }
2771            }
2772         }
2773      }
2774         break;
2775      case 0x08:  /* SOUND */
2776         /* This command enables internal sound effects */
2777         /* Not Implemented */
2778         break;
2779      case 0x09:  /* SOU_TRN */
2780         /* This command sends data to the SNES sound processor.
2781          We'll need to emulate that for this to be used */
2782         /* Not Implemented */
2783         break;
2784      case 0x0A:  /* PAL_SET */
2785      {
2786         UINT16 index_;
2787         
2788         /* Palette 0 */
2789         index_ = (UINT16)(data[1] | (data[2] << 8)) * 4;
2790         m_sgb_pal[0] = m_sgb_pal_data[index_];
2791         m_sgb_pal[1] = m_sgb_pal_data[index_ + 1];
2792         m_sgb_pal[2] = m_sgb_pal_data[index_ + 2];
2793         m_sgb_pal[3] = m_sgb_pal_data[index_ + 3];
2794         /* Palette 1 */
2795         index_ = (UINT16)(data[3] | (data[4] << 8)) * 4;
2796         m_sgb_pal[4] = m_sgb_pal_data[index_];
2797         m_sgb_pal[5] = m_sgb_pal_data[index_ + 1];
2798         m_sgb_pal[6] = m_sgb_pal_data[index_ + 2];
2799         m_sgb_pal[7] = m_sgb_pal_data[index_ + 3];
2800         /* Palette 2 */
2801         index_ = (UINT16)(data[5] | (data[6] << 8)) * 4;
2802         m_sgb_pal[8] = m_sgb_pal_data[index_];
2803         m_sgb_pal[9] = m_sgb_pal_data[index_ + 1];
2804         m_sgb_pal[10] = m_sgb_pal_data[index_ + 2];
2805         m_sgb_pal[11] = m_sgb_pal_data[index_ + 3];
2806         /* Palette 3 */
2807         index_ = (UINT16)(data[7] | (data[8] << 8)) * 4;
2808         m_sgb_pal[12] = m_sgb_pal_data[index_];
2809         m_sgb_pal[13] = m_sgb_pal_data[index_ + 1];
2810         m_sgb_pal[14] = m_sgb_pal_data[index_ + 2];
2811         m_sgb_pal[15] = m_sgb_pal_data[index_ + 3];
2812         /* Attribute File */
2813         if (data[9] & 0x40)
2814            m_sgb_window_mask = 0;
2815         m_sgb_atf = (data[9] & 0x3f) * (18 * 5);
2816         if (data[9] & 0x80)
2817         {
2818            for (int j = 0; j < 18; j++ )
2819            {
2820               for (int i = 0; i < 5; i++ )
2821               {
2822                  m_sgb_pal_map[i * 4][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC0) >> 6;
2823                  m_sgb_pal_map[(i * 4) + 1][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x30) >> 4;
2824                  m_sgb_pal_map[(i * 4) + 2][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC) >> 2;
2825                  m_sgb_pal_map[(i * 4) + 3][j] = m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x3;
2826               }
2827            }
2828         }
2829      }
2830         break;
2831      case 0x0B:  /* PAL_TRN */
2832      {
2833         UINT16 col;
2834         
2835         for (int i = 0; i < 2048; i++ )
2836         {
2837            col = (m_vram[0x0800 + (i * 2) + 1] << 8) | m_vram[0x0800 + (i * 2)];
2838            m_sgb_pal_data[i] = col;
2839         }
2840      }
2841         break;
2842      case 0x0C:  /* ATRC_EN */
2843         /* Not Implemented */
2844         break;
2845      case 0x0D:  /* TEST_EN */
2846         /* Not Implemented */
2847         break;
2848      case 0x0E:  /* ICON_EN */
2849         /* Not Implemented */
2850         break;
2851      case 0x0F:  /* DATA_SND */
2852         /* Not Implemented */
2853         break;
2854      case 0x10:  /* DATA_TRN */
2855         /* Not Implemented */
2856         break;
2857      case 0x12:  /* JUMP */
2858         /* Not Implemented */
2859         break;
2860      case 0x13:  /* CHR_TRN */
2861         if (data[1] & 0x1)
2862            memcpy(m_sgb_tile_data + 4096, m_vram + 0x0800, 4096);
2863         else
2864            memcpy(m_sgb_tile_data, m_vram + 0x0800, 4096);
2865         break;
2866      case 0x14:  /* PCT_TRN */
2867      {
2868         UINT16 col;
2869         if (m_sgb_border_hack)
2870         {
2871            memcpy(m_sgb_tile_map, m_vram + 0x1000, 2048);
2872            for (int i = 0; i < 64; i++)
2873            {
2874               col = (m_vram[0x0800 + (i * 2) + 1 ] << 8) | m_vram[0x0800 + (i * 2)];
2875               m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
2876            }
2877         }
2878         else /* Do things normally */
2879         {
2880            memcpy(m_sgb_tile_map, m_vram + 0x0800, 2048);
2881            for (int i = 0; i < 64; i++)
2882            {
2883               col = (m_vram[0x1000 + (i * 2) + 1] << 8) | m_vram[0x1000 + (i * 2)];
2884               m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
2885            }
2886         }
2887      }
2888         break;
2889      case 0x15:  /* ATTR_TRN */
2890         memcpy(m_sgb_atf_data, m_vram + 0x0800, 4050);
2891         break;
2892      case 0x16:  /* ATTR_SET */
2893      {         
2894         /* Attribute File */
2895         if (data[1] & 0x40)
2896            m_sgb_window_mask = 0;
2897         m_sgb_atf = (data[1] & 0x3f) * (18 * 5);
2898         for (int j = 0; j < 18; j++)
2899         {
2900            for (int i = 0; i < 5; i++)
2901            {
2902               m_sgb_pal_map[i * 4][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC0) >> 6;
2903               m_sgb_pal_map[(i * 4) + 1][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x30) >> 4;
2904               m_sgb_pal_map[(i * 4) + 2][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC) >> 2;
2905               m_sgb_pal_map[(i * 4) + 3][j] = m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x3;
2906            }
2907         }
2908      }
2909         break;
2910      case 0x17:  /* MASK_EN */
2911         m_sgb_window_mask = data[1];
2912         break;
2913      case 0x18:  /* OBJ_TRN */
2914         /* Not Implemnted */
2915         break;
2916      case 0x19:  /* ? */
2917         /* Called by: dkl,dkl2,dkl3,zeldadx
2918          But I don't know what it is for. */
2919         /* Not Implemented */
2920         break;
2921      case 0x1E:  /* Used by bootrom to transfer the gb cart header */
2922         break;
2923      case 0x1F:  /* Used by bootrom to transfer the gb cart header */
2924         break;
2925      default:
2926         logerror( "SGB: Unknown Command 0x%02x!\n", data[0] >> 3 );
2927   }
2928   
2929}
2930
2931
trunk/src/mess/video/gb_lcd.c
r0r23903
1/***************************************************************************
2
3  gb_lcd.c
4
5  Video file to handle emulation of the Nintendo Game Boy.
6
7  Original code                               Carsten Sorensen   1998
8  Mess modifications, bug fixes and speedups  Hans de Goede      1998
9  Bug fixes, SGB and GBC code                 Anthony Kruize     2002
10  Improvements to match real hardware         Wilbert Pol        2006-2008
11
12  Timing is not accurate enough:
13  - Mode 3 takes 172 cycles (measuered with logic analyzer by costis)
14
15***************************************************************************/
16
17#include "emu.h"
18//#include "cpu/lr35902/lr35902.h"
19#include "video/gb_lcd.h"
20
21/* Interrupts (copied from includes/gb.h)... */
22#define VBL_INT               0       /* V-Blank    */
23#define LCD_INT               1       /* LCD Status */
24#define TIM_INT               2       /* Timer      */
25#define SIO_INT               3       /* Serial I/O */
26#define EXT_INT               4       /* Joypad     */
27
28
29
30#define LCDCONT     m_vid_regs[0x00]  /* LCD control register                       */
31#define LCDSTAT     m_vid_regs[0x01]  /* LCD status register                        */
32#define SCROLLY     m_vid_regs[0x02]  /* Starting Y position of the background      */
33#define SCROLLX     m_vid_regs[0x03]  /* Starting X position of the background      */
34#define CURLINE     m_vid_regs[0x04]  /* Current screen line being scanned          */
35#define CMPLINE     m_vid_regs[0x05]  /* Gen. int. when scan reaches this line      */
36#define BGRDPAL     m_vid_regs[0x07]  /* Background palette                         */
37#define SPR0PAL     m_vid_regs[0x08]  /* Sprite palette #0                          */
38#define SPR1PAL     m_vid_regs[0x09]  /* Sprite palette #1                          */
39#define WNDPOSY     m_vid_regs[0x0A]  /* Window Y position                          */
40#define WNDPOSX     m_vid_regs[0x0B]  /* Window X position                          */
41#define KEY1        m_vid_regs[0x0D]  /* Prepare speed switch                       */
42#define HDMA1       m_vid_regs[0x11]  /* HDMA source high byte                      */
43#define HDMA2       m_vid_regs[0x12]  /* HDMA source low byte                       */
44#define HDMA3       m_vid_regs[0x13]  /* HDMA destination high byte                 */
45#define HDMA4       m_vid_regs[0x14]  /* HDMA destination low byte                  */
46#define HDMA5       m_vid_regs[0x15]  /* HDMA length/mode/start                     */
47#define GBCBCPS     m_vid_regs[0x28]  /* Backgound palette spec                     */
48#define GBCBCPD     m_vid_regs[0x29]  /* Backgound palette data                     */
49#define GBCOCPS     m_vid_regs[0x2A]  /* Object palette spec                        */
50#define GBCOCPD     m_vid_regs[0x2B]  /* Object palette data                        */
51
52/* -- Super Game Boy specific -- */
53#define SGB_BORDER_PAL_OFFSET   64  /* Border colours stored from pal 4-7   */
54#define SGB_XOFFSET             48  /* GB screen starts at column 48        */
55#define SGB_YOFFSET             40  /* GB screen starts at row 40           */
56
57
58enum {
59   UNLOCKED=0,
60   LOCKED
61};
62
63
64enum {
65   GB_LCD_STATE_LYXX_M3=1,
66   GB_LCD_STATE_LYXX_PRE_M0,
67   GB_LCD_STATE_LYXX_M0,
68   GB_LCD_STATE_LYXX_M0_SCX3,
69   GB_LCD_STATE_LYXX_M0_GBC_PAL,
70   GB_LCD_STATE_LYXX_M0_PRE_INC,
71   GB_LCD_STATE_LYXX_M0_INC,
72   GB_LCD_STATE_LY00_M2,
73   GB_LCD_STATE_LYXX_M2,
74   GB_LCD_STATE_LY9X_M1,
75   GB_LCD_STATE_LY9X_M1_INC,
76   GB_LCD_STATE_LY00_M1,
77   GB_LCD_STATE_LY00_M1_1,
78   GB_LCD_STATE_LY00_M1_2,
79   GB_LCD_STATE_LY00_M0
80};
81
82
83/* OAM contents on power up.
84 
85 The OAM area seems contain some kind of unit fingerprint. On each boot
86 the data is almost always the same. Some random bits are flipped between
87 different boots. It is currently unknown how much these fingerprints
88 differ between different units.
89 
90 OAM fingerprints taken from Wilbert Pol's own unit.
91 */
92
93static const UINT8 dmg_oam_fingerprint[0x100] = {
94   0xD8, 0xE6, 0xB3, 0x89, 0xEC, 0xDE, 0x11, 0x62, 0x0B, 0x7E, 0x48, 0x9E, 0xB9, 0x6E, 0x26, 0xC9,
95   0x36, 0xF4, 0x7D, 0xE4, 0xD9, 0xCE, 0xFA, 0x5E, 0xA3, 0x77, 0x60, 0xFC, 0x1C, 0x64, 0x8B, 0xAC,
96   0xB6, 0x74, 0x3F, 0x9A, 0x0E, 0xFE, 0xEA, 0xA9, 0x40, 0x3A, 0x7A, 0xB6, 0xF2, 0xED, 0xA8, 0x3E,
97   0xAF, 0x2C, 0xD2, 0xF2, 0x01, 0xE0, 0x5B, 0x3A, 0x53, 0x6A, 0x1C, 0x6C, 0x20, 0xD9, 0x22, 0xB4,
98   0x8C, 0x38, 0x71, 0x69, 0x3E, 0x93, 0xA3, 0x22, 0xCE, 0x76, 0x24, 0xE7, 0x1A, 0x14, 0x6B, 0xB1,
99   0xF9, 0x3D, 0xBF, 0x3D, 0x74, 0x64, 0xCB, 0xF5, 0xDC, 0x9A, 0x53, 0xC6, 0x0E, 0x78, 0x34, 0xCB,
100   0x42, 0xB3, 0xFF, 0x07, 0x73, 0xAE, 0x6C, 0xA2, 0x6F, 0x6A, 0xA4, 0x66, 0x0A, 0x8C, 0x40, 0xB3,
101   0x9A, 0x3D, 0x39, 0x78, 0xAB, 0x29, 0xE7, 0xC5, 0x7A, 0xDD, 0x51, 0x95, 0x2B, 0xE4, 0x1B, 0xF6,
102   0x31, 0x16, 0x34, 0xFE, 0x11, 0xF2, 0x5E, 0x11, 0xF3, 0x95, 0x66, 0xB9, 0x37, 0xC2, 0xAD, 0x6D,
103   0x1D, 0xA7, 0x79, 0x06, 0xD7, 0xE5, 0x8F, 0xFA, 0x9C, 0x02, 0x0C, 0x31, 0x8B, 0x17, 0x2E, 0x31,
104   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
110};
111
112static const UINT8 mgb_oam_fingerprint[0x100] = {
113   0xB9, 0xE9, 0x0D, 0x69, 0xBB, 0x7F, 0x00, 0x80, 0xE9, 0x7B, 0x79, 0xA2, 0xFD, 0xCF, 0xD8, 0x0A,
114   0x87, 0xEF, 0x44, 0x11, 0xFE, 0x37, 0x10, 0x21, 0xFA, 0xFF, 0x00, 0x17, 0xF6, 0x4F, 0x83, 0x03,
115   0x3A, 0xF4, 0x00, 0x24, 0xBB, 0xAE, 0x05, 0x01, 0xFF, 0xF7, 0x12, 0x48, 0xA7, 0x5E, 0xF6, 0x28,
116   0x5B, 0xFF, 0x2E, 0x10, 0xFF, 0xB9, 0x50, 0xC8, 0xAF, 0x77, 0x2C, 0x1A, 0x62, 0xD7, 0x81, 0xC2,
117   0xFD, 0x5F, 0xA0, 0x94, 0xAF, 0xFF, 0x51, 0x20, 0x36, 0x76, 0x50, 0x0A, 0xFD, 0xF6, 0x20, 0x00,
118   0xFE, 0xF7, 0xA0, 0x68, 0xFF, 0xFC, 0x29, 0x51, 0xA3, 0xFA, 0x06, 0xC4, 0x94, 0xFF, 0x39, 0x0A,
119   0xFF, 0x6C, 0x20, 0x20, 0xF1, 0xAD, 0x0C, 0x81, 0x56, 0xFB, 0x03, 0x82, 0xFF, 0xFF, 0x08, 0x58,
120   0x96, 0x7E, 0x01, 0x4D, 0xFF, 0xE4, 0x82, 0xE3, 0x3D, 0xBB, 0x54, 0x00, 0x3D, 0xF3, 0x04, 0x21,
121   0xB7, 0x39, 0xCC, 0x10, 0xF9, 0x5B, 0x80, 0x50, 0x3F, 0x6A, 0x1C, 0x21, 0x1F, 0xFA, 0xA8, 0x52,
122   0x5F, 0xB3, 0x44, 0xA1, 0x96, 0x1E, 0x00, 0x27, 0x63, 0x77, 0x30, 0x54, 0x37, 0x6F, 0x60, 0x22,
123   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
129};
130
131static const UINT8 cgb_oam_fingerprint[0x100] = {
132   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142   0x74, 0xFF, 0x09, 0x00, 0x9D, 0x61, 0xA8, 0x28, 0x36, 0x1E, 0x58, 0xAA, 0x75, 0x74, 0xA1, 0x42,
143   0x05, 0x96, 0x40, 0x09, 0x41, 0x02, 0x60, 0x00, 0x1F, 0x11, 0x22, 0xBC, 0x31, 0x52, 0x22, 0x54,
144   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
145   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
146   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04,
147   0x22, 0xA9, 0xC4, 0x00, 0x1D, 0xAD, 0x80, 0x0C, 0x5D, 0xFA, 0x51, 0x92, 0x93, 0x98, 0xA4, 0x04
148};
149
150/*
151 For an AGS in CGB mode this data is: */
152#if 0
153static const UINT8 abs_oam_fingerprint[0x100] = {
154   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164   0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
165   0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
166   0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
167   0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
168   0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
169   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
170};
171#endif
172
173
174const device_type GB_LCD_DMG = &device_creator<gb_lcd_device>;
175const device_type GB_LCD_MGB = &device_creator<mgb_lcd_device>;
176const device_type GB_LCD_SGB = &device_creator<sgb_lcd_device>;
177const device_type GB_LCD_CGB = &device_creator<cgb_lcd_device>;
178
179
180
181gb_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)
182            : device_t(mconfig, type, name, tag, owner, clock, shortname, source),
183               m_sgb_border_hack(0)
184{
185}
186
187gb_lcd_device::gb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
188            : device_t(mconfig, GB_LCD_DMG, "DMG LCD", tag, owner, clock, "dmg_lcd", __FILE__),
189               m_sgb_border_hack(0)
190{
191}
192
193mgb_lcd_device::mgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
194            : gb_lcd_device(mconfig, GB_LCD_MGB, "MGB LCD", tag, owner, clock, "mgb_lcd", __FILE__)
195{
196}
197
198sgb_lcd_device::sgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
199            : gb_lcd_device(mconfig, GB_LCD_SGB, "SGB LCD", tag, owner, clock, "sgb_lcd", __FILE__)
200{
201}
202
203cgb_lcd_device::cgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
204            : gb_lcd_device(mconfig, GB_LCD_CGB, "CGB LCD", tag, owner, clock, "cgb_lcd", __FILE__)
205{
206}
207
208
209//-------------------------------------------------
210//  device_start - device-specific startup
211//-------------------------------------------------
212
213void gb_lcd_device::common_start()
214{
215   machine().primary_screen->register_screen_bitmap(m_bitmap);
216   m_oam = auto_alloc_array_clear(machine(), UINT8, 0x100);
217   
218   m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_lcd_device::lcd_timer_proc),this));
219   machine().save().register_postload(save_prepost_delegate(FUNC(gb_lcd_device::videoptr_restore), this));
220
221   m_maincpu = machine().device<cpu_device>("maincpu");
222   m_screen = machine().device<screen_device>("screen");
223
224   save_pointer(NAME(m_oam), 0x100);
225   save_item(NAME(m_window_lines_drawn));
226   save_item(NAME(m_vid_regs));
227   save_item(NAME(m_bg_zbuf));
228   
229   save_item(NAME(m_cgb_bpal));
230   save_item(NAME(m_cgb_spal));
231   
232   save_item(NAME(m_gb_bpal));
233   save_item(NAME(m_gb_spal0));
234   save_item(NAME(m_gb_spal1));
235   
236   save_item(NAME(m_current_line));
237   save_item(NAME(m_cmp_line));
238   save_item(NAME(m_sprCount));
239   save_item(NAME(m_sprite));
240   save_item(NAME(m_previous_line));
241   save_item(NAME(m_start_x));
242   save_item(NAME(m_end_x));
243   save_item(NAME(m_mode));
244   save_item(NAME(m_state));
245   save_item(NAME(m_lcd_irq_line));
246   save_item(NAME(m_triggering_line_irq));
247   save_item(NAME(m_line_irq));
248   save_item(NAME(m_triggering_mode_irq));
249   save_item(NAME(m_mode_irq));
250   save_item(NAME(m_delayed_line_irq));
251   save_item(NAME(m_sprite_cycles));
252   save_item(NAME(m_scrollx_adjust));
253   save_item(NAME(m_oam_locked));
254   save_item(NAME(m_vram_locked));
255   save_item(NAME(m_pal_locked));
256   save_item(NAME(m_hdma_enabled));
257   save_item(NAME(m_hdma_possible));
258   save_item(NAME(m_gbc_mode));
259   save_item(NAME(m_gb_tile_no_mod));
260   save_item(NAME(m_vram_bank));
261   
262   save_item(NAME(m_gb_chrgen_offs));
263   save_item(NAME(m_gb_bgdtab_offs));
264   save_item(NAME(m_gb_wndtab_offs));
265   save_item(NAME(m_gbc_chrgen_offs));
266   save_item(NAME(m_gbc_bgdtab_offs));
267   save_item(NAME(m_gbc_wndtab_offs));
268   
269   save_item(NAME(m_layer[0].enabled));
270   save_item(NAME(m_layer[0].xindex));
271   save_item(NAME(m_layer[0].xshift));
272   save_item(NAME(m_layer[0].xstart));
273   save_item(NAME(m_layer[0].xend));
274   save_item(NAME(m_layer[0].bgline));
275   save_item(NAME(m_layer[1].enabled));
276   save_item(NAME(m_layer[1].xindex));
277   save_item(NAME(m_layer[1].xshift));
278   save_item(NAME(m_layer[1].xstart));
279   save_item(NAME(m_layer[1].xend));
280   save_item(NAME(m_layer[1].bgline));
281}
282
283
284void gb_lcd_device::videoptr_restore()
285{
286   m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
287   m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
288   m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
289   m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
290}
291
292void cgb_lcd_device::videoptr_restore()
293{
294   m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
295   m_layer[0].gbc_map = m_vram + m_gbc_bgdtab_offs;
296   m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
297   m_layer[1].gbc_map = m_vram + m_gbc_wndtab_offs;
298}
299
300
301void gb_lcd_device::device_start()
302{
303   common_start();
304
305   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
306   save_pointer(NAME(m_vram), 0x2000);
307   
308   memcpy(m_oam, dmg_oam_fingerprint, 0x100);
309}
310
311void mgb_lcd_device::device_start()
312{
313   common_start();
314   
315   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
316   save_pointer(NAME(m_vram), 0x2000);
317
318   memcpy(m_oam, mgb_oam_fingerprint, 0x100);
319
320   /* Initialize part of VRAM. This code must be deleted when we have added the bios dump */
321   for (int i = 1; i < 0x0d; i++)
322   {
323      m_vram[0x1903 + i] = i;
324      m_vram[0x1923 + i] = i + 0x0C;
325   }
326   m_vram[0x1910] = 0x19;
327}
328
329void sgb_lcd_device::device_start()
330{
331   common_start();
332   
333   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
334   save_pointer(NAME(m_vram), 0x2000);
335
336   m_sgb_tile_data = auto_alloc_array_clear(machine(), UINT8, 0x2000);
337   save_pointer(NAME(m_sgb_tile_data), 0x2000);
338   
339   /* Some default colours for non-SGB games */
340   m_sgb_pal[0] = 32767;
341   m_sgb_pal[1] = 21140;
342   m_sgb_pal[2] = 10570;
343   m_sgb_pal[3] = 0;
344   /* The rest of the colortable can be black */
345   for (int i = 4; i < 8 * 16; i++)
346      m_sgb_pal[i] = 0;
347
348   save_item(NAME(m_sgb_atf_data));
349   save_item(NAME(m_sgb_atf));
350   save_item(NAME(m_sgb_pal_data));
351   save_item(NAME(m_sgb_pal_map));
352   save_item(NAME(m_sgb_pal));
353   save_item(NAME(m_sgb_tile_map));
354   save_item(NAME(m_sgb_window_mask));
355}
356
357void cgb_lcd_device::device_start()
358{
359   common_start();
360   
361   m_vram = auto_alloc_array_clear(machine(), UINT8, 0x4000);
362   save_pointer(NAME(m_vram), 0x4000);
363
364   memcpy(m_oam, cgb_oam_fingerprint, 0x100);
365
366   
367   /* Background is initialised as white */
368   for (int i = 0; i < 32; i++)
369      m_cgb_bpal[i] = 32767;
370   /* Sprites are supposed to be uninitialized, but we'll make them black */
371   for (int i = 0; i < 32; i++)
372      m_cgb_spal[i] = 0;
373}
374
375
376//-------------------------------------------------
377//  device_reset - device-specific reset
378//-------------------------------------------------
379
380void gb_lcd_device::common_reset()
381{   
382   m_window_lines_drawn = 0;
383   
384   m_current_line = 0;
385   m_cmp_line = 0;
386   m_sprCount = 0;
387   m_previous_line = 0;
388   m_start_x = 0;
389   m_end_x = 0;
390   m_mode = 0;
391   m_state = 0;
392   m_lcd_irq_line = 0;
393   m_triggering_line_irq = 0;
394   m_line_irq = 0;
395   m_triggering_mode_irq = 0;
396   m_mode_irq = 0;
397   m_delayed_line_irq = 0;
398   m_sprite_cycles = 0;
399   m_scrollx_adjust = 0;
400   m_oam_locked = 0;
401   m_vram_locked = 0;
402   m_pal_locked = 0;
403   m_gbc_mode = 0;
404   m_gb_tile_no_mod = 0;
405   m_vram_bank = 0;
406   
407   m_gb_chrgen_offs = 0;
408   m_gb_bgdtab_offs = 0x1c00;
409   m_gb_wndtab_offs = 0x1c00;
410   
411   memset(&m_vid_regs, 0, sizeof(m_vid_regs));
412   memset(&m_bg_zbuf, 0, sizeof(m_bg_zbuf));
413   memset(&m_cgb_bpal, 0, sizeof(m_cgb_bpal));
414   memset(&m_cgb_spal, 0, sizeof(m_cgb_spal));
415   memset(&m_sprite, 0, sizeof(m_sprite));
416   memset(&m_layer[0], 0, sizeof(m_layer[0]));
417   memset(&m_layer[1], 0, sizeof(m_layer[1]));
418   
419   // specific reg initialization
420   m_vid_regs[0x06] = 0xff;
421   
422   for (int i = 0x0c; i < _NR_GB_VID_REGS; i++)
423      m_vid_regs[i] = 0xff;
424   
425   LCDSTAT = 0x80;
426   LCDCONT = 0x00;     /* Video hardware is turned off at boot time */
427   m_current_line = CURLINE = CMPLINE = 0x00;
428   SCROLLX = SCROLLY = 0x00;
429   SPR0PAL = SPR1PAL = 0xFF;
430   WNDPOSX = WNDPOSY = 0x00;
431   
432   // Initialize palette arrays
433   for (int i = 0; i < 4; i++)
434      m_gb_bpal[i] = m_gb_spal0[i] = m_gb_spal1[i] = i;
435   
436}
437
438
439void gb_lcd_device::device_reset()
440{
441   common_reset();
442
443   m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
444}
445
446void mgb_lcd_device::device_reset()
447{
448   address_space &space = m_maincpu->space(AS_PROGRAM);
449   common_reset();
450
451   /* Make sure the VBlank interrupt is set when the first instruction gets executed */
452   machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(1), timer_expired_delegate(FUNC(mgb_lcd_device::video_init_vbl),this));
453   
454   /* Initialize some video registers */
455   video_w(space, 0x0, 0x91);    /* LCDCONT */
456   video_w(space, 0x7, 0xFC);    /* BGRDPAL */
457   video_w(space, 0x8, 0xFC);    /* SPR0PAL */
458   video_w(space, 0x9, 0xFC);    /* SPR1PAL */
459   
460   CURLINE = m_current_line = 0;
461   LCDSTAT = (LCDSTAT & 0xF8) | 0x05;
462   m_mode = 1;
463
464   m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(60), GB_LCD_STATE_LY00_M0);
465}
466
467void sgb_lcd_device::device_reset()
468{
469   common_reset();
470
471   memset(m_sgb_tile_data, 0, 0x2000);
472
473   m_sgb_window_mask = 0;
474
475   memset(m_sgb_pal_map, 0, sizeof(m_sgb_pal_map));   
476   memset(m_sgb_atf_data, 0, sizeof(m_sgb_atf_data));
477}
478
479void cgb_lcd_device::device_reset()
480{
481   common_reset();
482   
483   m_gbc_chrgen_offs = 0x2000;
484   m_gbc_bgdtab_offs = 0x3c00;
485   m_gbc_wndtab_offs = 0x3c00;
486   
487   /* HDMA disabled */
488   m_hdma_enabled = 0;
489   m_hdma_possible = 0;
490   
491   m_gbc_mode = 1;
492   
493}
494
495
496
497inline void gb_lcd_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color)
498{
499   bitmap.pix16(y, x) = (UINT16)color;
500}
501
502/*
503  Select which sprites should be drawn for the current scanline and return the
504  number of sprites selected.
505 */
506void gb_lcd_device::select_sprites()
507{
508   int /*yindex,*/ line, height;
509   UINT8 *oam = m_oam + 39 * 4;
510
511   m_sprCount = 0;
512
513   /* If video hardware is enabled and sprites are enabled */
514   if ((LCDCONT & 0x80) && (LCDCONT & 0x02))
515   {
516      /* Check for stretched sprites */
517      if (LCDCONT & 0x04)
518         height = 16;
519      else
520         height = 8;
521
522      //yindex = m_current_line;
523      line = m_current_line + 16;
524
525      for (int i = 39; i >= 0; i--)
526      {
527         if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
528         {
529            /* We limit the sprite count to max 10 here;
530               proper games should not exceed this... */
531            if (m_sprCount < 10)
532            {
533               m_sprite[m_sprCount] = i;
534               m_sprCount++;
535            }
536         }
537         oam -= 4;
538      }
539   }
540}
541
542void gb_lcd_device::update_sprites()
543{
544   bitmap_ind16 &bitmap = m_bitmap;
545   UINT8 height, tilemask, line, *oam, *vram;
546   int yindex;
547
548   if (LCDCONT & 0x04)
549   {
550      height = 16;
551      tilemask = 0xFE;
552   }
553   else
554   {
555      height = 8;
556      tilemask = 0xFF;
557   }
558
559   yindex = m_current_line;
560   line = m_current_line + 16;
561
562   oam = m_oam + 39 * 4;
563   vram = m_vram;
564   for (int i = 39; i >= 0; i--)
565   {
566      /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
567      if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
568      {
569         UINT16 data;
570         UINT8 bit, *spal;
571         int xindex, adr;
572
573         spal = (oam[3] & 0x10) ? m_gb_spal1 : m_gb_spal0;
574         xindex = oam[1] - 8;
575         if (oam[3] & 0x40)         /* flip y ? */
576         {
577            adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
578         }
579         else
580         {
581            adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
582         }
583         data = (vram[adr + 1] << 8) | vram[adr];
584
585         switch (oam[3] & 0xA0)
586         {
587         case 0xA0:                 /* priority is set (behind bgnd & wnd, flip x) */
588            for (bit = 0; bit < 8; bit++, xindex++)
589            {
590               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
591               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
592                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
593               data >>= 1;
594            }
595            break;
596         case 0x20:                 /* priority is not set (overlaps bgnd & wnd, flip x) */
597            for (bit = 0; bit < 8; bit++, xindex++)
598            {
599               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
600               if (colour && xindex >= 0 && xindex < 160)
601                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
602               data >>= 1;
603            }
604            break;
605         case 0x80:                 /* priority is set (behind bgnd & wnd, don't flip x) */
606            for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
607            {
608               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
609               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
610                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
611               data <<= 1;
612            }
613            break;
614         case 0x00:                 /* priority is not set (overlaps bgnd & wnd, don't flip x) */
615            for (bit = 0; bit < 8 && xindex < 160; bit++, xindex++)
616            {
617               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
618               if (colour && xindex >= 0 && xindex < 160)
619                  plot_pixel(bitmap, xindex, yindex, spal[colour]);
620               data <<= 1;
621            }
622            break;
623         }
624      }
625      oam -= 4;
626   }
627}
628
629void gb_lcd_device::update_scanline()
630{
631   bitmap_ind16 &bitmap = m_bitmap;
632
633   g_profiler.start(PROFILER_VIDEO);
634
635   /* Make sure we're in mode 3 */
636   if ((LCDSTAT & 0x03) == 0x03)
637   {
638      /* Calculate number of pixels to render based on time still left on the timer */
639      UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
640      int l = 0;
641
642      if (m_start_x < 0)
643      {
644         /* Window is enabled if the hardware says so AND the current scanline is
645          * within the window AND the window X coordinate is <=166 */
646         m_layer[1].enabled = ((LCDCONT & 0x20) && (m_current_line >= WNDPOSY) && (WNDPOSX <= 166)) ? 1 : 0;
647
648         /* BG is enabled if the hardware says so AND (window_off OR (window_on
649         * AND window's X position is >=7)) */
650         m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && (WNDPOSX >= 7)))) ? 1 : 0;
651
652         if (m_layer[0].enabled)
653         {
654            m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
655            m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
656            m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
657            m_layer[0].xindex = SCROLLX >> 3;
658            m_layer[0].xshift = SCROLLX & 7;
659            m_layer[0].xstart = 0;
660            m_layer[0].xend = 160;
661         }
662
663         if (m_layer[1].enabled)
664         {
665            int xpos = WNDPOSX - 7;             /* Window is offset by 7 pixels */
666            if (xpos < 0)
667               xpos = 0;
668
669            m_layer[1].bgline = m_window_lines_drawn;
670            m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
671            m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
672            m_layer[1].xindex = 0;
673            m_layer[1].xshift = 0;
674            m_layer[1].xstart = xpos;
675            m_layer[1].xend = 160;
676            m_layer[0].xend = xpos;
677         }
678         m_start_x = 0;
679      }
680
681      if (cycles_to_go < 160)
682      {
683         m_end_x = MIN(160 - cycles_to_go, 160);
684         /* Draw empty pixels when the background is disabled */
685         if (!(LCDCONT & 0x01))
686         {
687            rectangle r(m_start_x, m_end_x - 1, m_current_line, m_current_line);
688            bitmap.fill(m_gb_bpal[0], r);
689         }
690         while (l < 2)
691         {
692            UINT8 xindex, *map, *tiles;
693            UINT16 data;
694            int i, tile_index;
695
696            if (!m_layer[l].enabled)
697            {
698               l++;
699               continue;
700            }
701            map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
702            tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
703            xindex = m_start_x;
704            if (xindex < m_layer[l].xstart)
705               xindex = m_layer[l].xstart;
706            i = m_end_x;
707            if (i > m_layer[l].xend)
708               i = m_layer[l].xend;
709            i = i - xindex;
710
711            tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
712            data = tiles[tile_index] | (tiles[tile_index+1] << 8);
713            data <<= m_layer[l].xshift;
714
715            while (i > 0)
716            {
717               while ((m_layer[l].xshift < 8) && i)
718               {
719                  register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
720                  plot_pixel(bitmap, xindex, m_current_line, m_gb_bpal[colour]);
721                  m_bg_zbuf[xindex] = colour;
722                  xindex++;
723                  data <<= 1;
724                  m_layer[l].xshift++;
725                  i--;
726               }
727               if (m_layer[l].xshift == 8)
728               {
729                  /* Take possible changes to SCROLLY into account */
730                  if (l == 0)
731                  {
732                     m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
733                     map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
734                     tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
735                  }
736
737                  m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
738                  m_layer[l].xshift = 0;
739                  tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
740                  data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
741               }
742            }
743            l++;
744         }
745         if (m_end_x == 160 && LCDCONT & 0x02)
746         {
747            update_sprites();
748         }
749         m_start_x = m_end_x;
750      }
751   }
752   else
753   {
754      if (!(LCDCONT & 0x80))
755      {
756         /* Draw an empty line when LCD is disabled */
757         if (m_previous_line != m_current_line)
758         {
759            if (m_current_line < 144)
760            {
761               screen_device *screen = machine().first_screen();
762               const rectangle &r = screen->visible_area();
763               rectangle r1(r.min_x, r.max_x, m_current_line, m_current_line);
764               bitmap.fill(0, r1);
765            }
766            m_previous_line = m_current_line;
767         }
768      }
769   }
770
771   g_profiler.stop();
772}
773
774/* --- Super Game Boy Specific --- */
775
776void sgb_lcd_device::update_sprites()
777{
778   bitmap_ind16 &bitmap = m_bitmap;
779   UINT8 height, tilemask, line, *oam, *vram, pal;
780   INT16 yindex;
781
782   if (LCDCONT & 0x04)
783   {
784      height = 16;
785      tilemask = 0xFE;
786   }
787   else
788   {
789      height = 8;
790      tilemask = 0xFF;
791   }
792
793   /* Offset to center of screen */
794   yindex = m_current_line + SGB_YOFFSET;
795   line = m_current_line + 16;
796
797   oam = m_oam + 39 * 4;
798   vram = m_vram;
799   for (int i = 39; i >= 0; i--)
800   {
801      /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
802      if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
803      {
804         UINT16 data;
805         UINT8 bit, *spal;
806         INT16 xindex;
807         int adr;
808
809         spal = (oam[3] & 0x10) ? m_gb_spal1 : m_gb_spal0;
810         xindex = oam[1] - 8;
811         if (oam[3] & 0x40)         /* flip y ? */
812         {
813            adr = (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2;
814         }
815         else
816         {
817            adr = (oam[2] & tilemask) * 16 + (line - oam[0]) * 2;
818         }
819         data = (vram[adr + 1] << 8) | vram[adr];
820
821         /* Find the palette to use */
822         pal = m_sgb_pal_map[(xindex >> 3)][((yindex - SGB_YOFFSET) >> 3)] << 2;
823
824         /* Offset to center of screen */
825         xindex += SGB_XOFFSET;
826
827         switch (oam[3] & 0xA0)
828         {
829         case 0xA0:                 /* priority is set (behind bgnd & wnd, flip x) */
830            for (bit = 0; bit < 8; bit++, xindex++)
831            {
832               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
833               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !m_bg_zbuf[xindex - SGB_XOFFSET])
834                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
835               data >>= 1;
836            }
837            break;
838         case 0x20:                 /* priority is not set (overlaps bgnd & wnd, flip x) */
839            for (bit = 0; bit < 8; bit++, xindex++)
840            {
841               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
842               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
843                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
844               data >>= 1;
845            }
846            break;
847         case 0x80:                 /* priority is set (behind bgnd & wnd, don't flip x) */
848            for (bit = 0; bit < 8; bit++, xindex++)
849            {
850               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
851               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour && !m_bg_zbuf[xindex - SGB_XOFFSET])
852                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
853               data <<= 1;
854            }
855            break;
856         case 0x00:                 /* priority is not set (overlaps bgnd & wnd, don't flip x) */
857            for (bit = 0; bit < 8; bit++, xindex++)
858            {
859               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
860               if ((xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160) && colour)
861                  plot_pixel(bitmap, xindex, yindex, m_sgb_pal[pal + spal[colour]]);
862               data <<= 1;
863            }
864            break;
865         }
866      }
867      oam -= 4;
868   }
869}
870
871
872void sgb_lcd_device::refresh_border()
873{
874   UINT16 data, data2;
875   UINT8 *tiles, *tiles2;
876
877   for (UINT16 yidx = 0; yidx < 224; yidx++)
878   {
879      UINT8 *map = m_sgb_tile_map + ((yidx >> 3) * 64);
880      UINT16 xindex = 0;
881
882      for (UINT16 xidx = 0; xidx < 64; xidx += 2)
883      {
884         if (map[xidx + 1] & 0x80) /* Vertical flip */
885            tiles = m_sgb_tile_data + ((7 - (yidx % 8)) << 1);
886         else /* No vertical flip */
887            tiles = m_sgb_tile_data + ((yidx % 8) << 1);
888         tiles2 = tiles + 16;
889
890         UINT8 pal = (map[xidx + 1] & 0x1C) >> 2;
891         if (pal == 0)
892            pal = 1;
893         pal <<= 4;
894
895         if (m_sgb_border_hack)
896         { /* A few games do weird stuff */
897            UINT8 tileno = map[xidx];
898            if (tileno >= 128) tileno = ((64 + tileno) % 128) + 128;
899            else tileno = (64 + tileno) % 128;
900            data = tiles[tileno * 32] | (tiles[(tileno * 32) + 1] << 8);
901            data2 = tiles2[tileno * 32] | (tiles2[(tileno * 32) + 1] << 8);
902         }
903         else
904         {
905            data = tiles[map[xidx] * 32] | (tiles[(map[xidx] * 32) + 1] << 8);
906            data2 = tiles2[map[xidx] * 32] | (tiles2[(map[xidx] * 32) + 1] << 8);
907         }
908
909         for (int i = 0; i < 8; i++)
910         {
911            register UINT8 colour;
912            if ((map[xidx + 1] & 0x40))  /* Horizontal flip */
913            {
914               colour = ((data  & 0x0001) ? 1 : 0) | ((data  & 0x0100) ? 2 : 0) |
915                     ((data2 & 0x0001) ? 4 : 0) | ((data2 & 0x0100) ? 8 : 0);
916               data >>= 1;
917               data2 >>= 1;
918            }
919            else    /* No horizontal flip */
920            {
921               colour = ((data  & 0x0080) ? 1 : 0) | ((data  & 0x8000) ? 2 : 0) |
922                     ((data2 & 0x0080) ? 4 : 0) | ((data2 & 0x8000) ? 8 : 0);
923               data <<= 1;
924               data2 <<= 1;
925            }
926            /* A slight hack below so we don't draw over the GB screen.
927             * Drawing there is allowed, but due to the way we draw the
928             * scanline, it can obscure the screen even when it shouldn't.
929             */
930            if (!((yidx >= SGB_YOFFSET && yidx < SGB_YOFFSET + 144) &&
931               (xindex >= SGB_XOFFSET && xindex < SGB_XOFFSET + 160)))
932            {
933               plot_pixel(m_bitmap, xindex, yidx, m_sgb_pal[pal + colour]);
934            }
935            xindex++;
936         }
937      }
938   }
939}
940
941void sgb_lcd_device::update_scanline()
942{
943   bitmap_ind16 &bitmap = m_bitmap;
944
945   g_profiler.start(PROFILER_VIDEO);
946
947   if ((LCDSTAT & 0x03) == 0x03)
948   {
949      /* Calcuate number of pixels to render based on time still left on the timer */
950      UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
951      int l = 0;
952
953      if (m_start_x < 0)
954      {
955         /* Window is enabled if the hardware says so AND the current scanline is
956          * within the window AND the window X coordinate is <=166 */
957         m_layer[1].enabled = ((LCDCONT & 0x20) && m_current_line >= WNDPOSY && WNDPOSX <= 166) ? 1 : 0;
958
959         /* BG is enabled if the hardware says so AND (window_off OR (window_on
960          * AND window's X position is >=7 )) */
961         m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && WNDPOSX >= 7))) ? 1 : 0;
962
963         if (m_layer[0].enabled)
964         {
965            m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
966            m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
967            m_layer[0].bg_tiles = m_vram + m_gb_chrgen_offs;
968            m_layer[0].xindex = SCROLLX >> 3;
969            m_layer[0].xshift = SCROLLX & 7;
970            m_layer[0].xstart = 0;
971            m_layer[0].xend = 160;
972         }
973
974         if (m_layer[1].enabled)
975         {
976            int xpos;
977
978            /* Window X position is offset by 7 so we'll need to adjust */
979            xpos = WNDPOSX - 7;
980            if (xpos < 0)
981               xpos = 0;
982
983            m_layer[1].bgline = m_window_lines_drawn;
984            m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
985            m_layer[1].bg_tiles = m_vram + m_gb_chrgen_offs;
986            m_layer[1].xindex = 0;
987            m_layer[1].xshift = 0;
988            m_layer[1].xstart = xpos;
989            m_layer[1].xend = 160;
990            m_layer[0].xend = xpos;
991         }
992         m_start_x = 0;
993      }
994
995      if (cycles_to_go == 0)
996      {
997         /* Does this belong here? or should it be moved to the else block */
998         /* Handle SGB mask */
999         switch (m_sgb_window_mask)
1000         {
1001         case 1: /* Freeze screen */
1002            return;
1003         case 2: /* Blank screen (black) */
1004            {
1005               rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160-1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
1006               bitmap.fill(0, r);
1007            }
1008            return;
1009         case 3: /* Blank screen (white - or should it be color 0?) */
1010            {
1011               rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, SGB_YOFFSET, SGB_YOFFSET + 144 - 1);
1012               bitmap.fill(32767, r);
1013            }
1014            return;
1015         }
1016
1017         /* Draw the "border" if we're on the first line */
1018         if (m_current_line == 0)
1019         {
1020            refresh_border();
1021         }
1022      }
1023      if (cycles_to_go < 160)
1024      {
1025         m_end_x = MIN(160 - cycles_to_go,160);
1026
1027         /* if background or screen disabled clear line */
1028         if (!(LCDCONT & 0x01))
1029         {
1030            rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, m_current_line + SGB_YOFFSET, m_current_line + SGB_YOFFSET);
1031            bitmap.fill(0, r);
1032         }
1033         while (l < 2)
1034         {
1035            UINT8   xindex, sgb_palette, *map, *tiles;
1036            UINT16  data;
1037            int i, tile_index;
1038
1039            if (!m_layer[l].enabled)
1040            {
1041               l++;
1042               continue;
1043            }
1044            map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1045            tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
1046            xindex = m_start_x;
1047            if (xindex < m_layer[l].xstart)
1048               xindex = m_layer[l].xstart;
1049            i = m_end_x;
1050            if (i > m_layer[l].xend)
1051               i = m_layer[l].xend;
1052            i = i - xindex;
1053
1054            tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1055            data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1056            data <<= m_layer[l].xshift;
1057
1058            /* Figure out which palette we're using */
1059            sgb_palette = m_sgb_pal_map[(m_end_x - i) >> 3][m_current_line >> 3] << 2;
1060
1061            while (i > 0)
1062            {
1063               while ((m_layer[l].xshift < 8) && i)
1064               {
1065                  register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1066                  plot_pixel(bitmap, xindex + SGB_XOFFSET, m_current_line + SGB_YOFFSET, m_sgb_pal[sgb_palette + m_gb_bpal[colour]]);
1067                  m_bg_zbuf[xindex] = colour;
1068                  xindex++;
1069                  data <<= 1;
1070                  m_layer[l].xshift++;
1071                  i--;
1072               }
1073               if (m_layer[l].xshift == 8)
1074               {
1075                  /* Take possible changes to SCROLLY into account */
1076                  if (l == 0)
1077                  {
1078                     m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1079                     map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1080                     tiles = m_layer[l].bg_tiles + ((m_layer[l].bgline & 7) << 1);
1081                  }
1082
1083                  m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
1084                  m_layer[l].xshift = 0;
1085                  tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1086                  data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1087                  sgb_palette = m_sgb_pal_map[(m_end_x - i) >> 3][m_current_line >> 3] << 2;
1088               }
1089            }
1090            l++;
1091         }
1092         if ((m_end_x == 160) && (LCDCONT & 0x02))
1093         {
1094            update_sprites();
1095         }
1096         m_start_x = m_end_x;
1097      }
1098   }
1099   else
1100   {
1101      if (!(LCDCONT * 0x80))
1102      {
1103         /* if screen disabled clear line */
1104         if (m_previous_line != m_current_line)
1105         {
1106            /* Also refresh border here??? */
1107            if (m_current_line < 144)
1108            {
1109               rectangle r(SGB_XOFFSET, SGB_XOFFSET + 160 - 1, m_current_line + SGB_YOFFSET, m_current_line + SGB_YOFFSET);
1110               bitmap.fill(0, r);
1111            }
1112            m_previous_line = m_current_line;
1113         }
1114      }
1115   }
1116
1117   g_profiler.stop();
1118}
1119
1120/* --- Game Boy Color Specific --- */
1121
1122void cgb_lcd_device::update_sprites()
1123{
1124   bitmap_ind16 &bitmap = m_bitmap;
1125   UINT8 height, tilemask, line, *oam;
1126   int xindex, yindex;
1127
1128   if (LCDCONT & 0x04)
1129   {
1130      height = 16;
1131      tilemask = 0xFE;
1132   }
1133   else
1134   {
1135      height = 8;
1136      tilemask = 0xFF;
1137   }
1138
1139   yindex = m_current_line;
1140   line = m_current_line + 16;
1141
1142   oam = m_oam + 39 * 4;
1143   for (int i = 39; i >= 0; i--)
1144   {
1145      /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */
1146      if (line >= oam[0] && line < (oam[0] + height) && oam[1] && oam[1] < 168)
1147      {
1148         UINT16 data;
1149         UINT8 bit, pal;
1150
1151         /* Handle mono mode for GB games */
1152         if (!m_gbc_mode)
1153            pal = (oam[3] & 0x10) ? 4 : 0;
1154         else
1155            pal = ((oam[3] & 0x7) * 4);
1156
1157         xindex = oam[1] - 8;
1158         if (oam[3] & 0x40)         /* flip y ? */
1159         {
1160            data = *((UINT16 *) &m_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2]);
1161         }
1162         else
1163         {
1164            data = *((UINT16 *) &m_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (line - oam[0]) * 2]);
1165         }
1166#ifndef LSB_FIRST
1167         data = (data << 8) | (data >> 8);
1168#endif
1169
1170         switch (oam[3] & 0xA0)
1171         {
1172         case 0xA0:                 /* priority is set (behind bgnd & wnd, flip x) */
1173            for (bit = 0; bit < 8; bit++, xindex++)
1174            {
1175               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
1176               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
1177               {
1178                  if (! m_gbc_mode)
1179                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1180                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1181               }
1182               data >>= 1;
1183            }
1184            break;
1185         case 0x20:                 /* priority is not set (overlaps bgnd & wnd, flip x) */
1186            for (bit = 0; bit < 8; bit++, xindex++)
1187            {
1188               register int colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
1189               if ((m_bg_zbuf[xindex] & 0x80) && (m_bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
1190                  colour = 0;
1191               if (colour && xindex >= 0 && xindex < 160)
1192               {
1193                  if (! m_gbc_mode)
1194                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1195                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1196               }
1197               data >>= 1;
1198            }
1199            break;
1200         case 0x80:                 /* priority is set (behind bgnd & wnd, don't flip x) */
1201            for (bit = 0; bit < 8; bit++, xindex++)
1202            {
1203               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1204               if (colour && !m_bg_zbuf[xindex] && xindex >= 0 && xindex < 160)
1205               {
1206                  if (! m_gbc_mode)
1207                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1208                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1209               }
1210               data <<= 1;
1211            }
1212            break;
1213         case 0x00:                 /* priority is not set (overlaps bgnd & wnd, don't flip x) */
1214            for (bit = 0; bit < 8; bit++, xindex++)
1215            {
1216               register int colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1217               if ((m_bg_zbuf[xindex] & 0x80) && (m_bg_zbuf[xindex] & 0x7f) && (LCDCONT & 0x1))
1218                  colour = 0;
1219               if (colour && xindex >= 0 && xindex < 160)
1220               {
1221                  if (! m_gbc_mode)
1222                     colour = pal ? m_gb_spal1[colour] : m_gb_spal0[colour];
1223                  plot_pixel(bitmap, xindex, yindex, m_cgb_spal[pal + colour]);
1224               }
1225               data <<= 1;
1226            }
1227            break;
1228         }
1229      }
1230      oam -= 4;
1231   }
1232}
1233
1234void cgb_lcd_device::update_scanline()
1235{
1236   bitmap_ind16 &bitmap = m_bitmap;
1237
1238   g_profiler.start(PROFILER_VIDEO);
1239
1240   if ((LCDSTAT & 0x03) == 0x03)
1241   {
1242      /* Calcuate number of pixels to render based on time still left on the timer */
1243      UINT32 cycles_to_go = m_maincpu->attotime_to_cycles(m_lcd_timer->remaining());
1244      int l = 0;
1245
1246      if (m_start_x < 0)
1247      {
1248         /* Window is enabled if the hardware says so AND the current scanline is
1249          * within the window AND the window X coordinate is <=166 */
1250         m_layer[1].enabled = ((LCDCONT & 0x20) && (m_current_line >= WNDPOSY) && (WNDPOSX <= 166)) ? 1 : 0;
1251
1252         /* BG is enabled if the hardware says so AND (window_off OR (window_on
1253          * AND window's X position is >=7 )) */
1254         m_layer[0].enabled = ((LCDCONT & 0x01) && ((!m_layer[1].enabled) || (m_layer[1].enabled && (WNDPOSX >= 7)))) ? 1 : 0;
1255
1256         if (m_layer[0].enabled)
1257         {
1258            m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1259            m_layer[0].bg_map = m_vram + m_gb_bgdtab_offs;
1260            m_layer[0].gbc_map = m_vram + m_gbc_bgdtab_offs;
1261            m_layer[0].xindex = SCROLLX >> 3;
1262            m_layer[0].xshift = SCROLLX & 7;
1263            m_layer[0].xstart = 0;
1264            m_layer[0].xend = 160;
1265         }
1266
1267         if (m_layer[1].enabled)
1268         {
1269            int xpos;
1270
1271            /* Window X position is offset by 7 so we'll need to adust */
1272            xpos = WNDPOSX - 7;
1273            if (xpos < 0)
1274               xpos = 0;
1275
1276            m_layer[1].bgline = m_window_lines_drawn;
1277            m_layer[1].bg_map = m_vram + m_gb_wndtab_offs;
1278            m_layer[1].gbc_map = m_vram + m_gbc_wndtab_offs;
1279            m_layer[1].xindex = 0;
1280            m_layer[1].xshift = 0;
1281            m_layer[1].xstart = xpos;
1282            m_layer[1].xend = 160;
1283            m_layer[0].xend = xpos;
1284         }
1285         m_start_x = 0;
1286      }
1287
1288      if (cycles_to_go < 160)
1289      {
1290         m_end_x = MIN(160 - cycles_to_go, 160);
1291         /* Draw empty line when the background is disabled */
1292         if (!(LCDCONT & 0x01))
1293         {
1294            rectangle r(m_start_x, m_end_x - 1, m_current_line, m_current_line);
1295            bitmap.fill((!m_gbc_mode) ? 0 : 32767, r);
1296         }
1297         while (l < 2)
1298         {
1299            UINT8   xindex, *map, *tiles, *gbcmap;
1300            UINT16  data;
1301            int i, tile_index;
1302
1303            if (!m_layer[l].enabled)
1304            {
1305               l++;
1306               continue;
1307            }
1308            map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1309            gbcmap = m_layer[l].gbc_map + ((m_layer[l].bgline << 2) & 0x3E0);
1310            tiles = (gbcmap[m_layer[l].xindex] & 0x08) ? (m_vram + m_gbc_chrgen_offs) : (m_vram + m_gb_chrgen_offs);
1311
1312            /* Check for vertical flip */
1313            if (gbcmap[m_layer[l].xindex] & 0x40)
1314            {
1315               tiles += ((7 - (m_layer[l].bgline & 0x07)) << 1);
1316            }
1317            else
1318            {
1319               tiles += ((m_layer[l].bgline & 0x07) << 1);
1320            }
1321            xindex = m_start_x;
1322            if (xindex < m_layer[l].xstart)
1323               xindex = m_layer[l].xstart;
1324            i = m_end_x;
1325            if (i > m_layer[l].xend)
1326               i = m_layer[l].xend;
1327            i = i - xindex;
1328
1329            tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1330            data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1331            /* Check for horinzontal flip */
1332            if (gbcmap[m_layer[l].xindex] & 0x20)
1333            {
1334               data >>= m_layer[l].xshift;
1335            }
1336            else
1337            {
1338               data <<= m_layer[l].xshift;
1339            }
1340
1341            while (i > 0)
1342            {
1343               while ((m_layer[l].xshift < 8) && i)
1344               {
1345                  int colour;
1346                  /* Check for horinzontal flip */
1347                  if (gbcmap[m_layer[l].xindex] & 0x20)
1348                  {
1349                     colour = ((data & 0x0100) ? 2 : 0) | ((data & 0x0001) ? 1 : 0);
1350                     data >>= 1;
1351                  }
1352                  else
1353                  {
1354                     colour = ((data & 0x8000) ? 2 : 0) | ((data & 0x0080) ? 1 : 0);
1355                     data <<= 1;
1356                  }
1357                  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)]);
1358                  m_bg_zbuf[xindex] = colour + (gbcmap[m_layer[l].xindex] & 0x80);
1359                  xindex++;
1360                  m_layer[l].xshift++;
1361                  i--;
1362               }
1363               if (m_layer[l].xshift == 8)
1364               {
1365                  /* Take possible changes to SCROLLY into account */
1366                  if (l == 0)
1367                  {
1368                     m_layer[0].bgline = (SCROLLY + m_current_line) & 0xFF;
1369                     map = m_layer[l].bg_map + ((m_layer[l].bgline << 2) & 0x3E0);
1370                     gbcmap = m_layer[l].gbc_map + ((m_layer[l].bgline << 2) & 0x3E0);
1371                  }
1372
1373                  m_layer[l].xindex = (m_layer[l].xindex + 1) & 31;
1374                  m_layer[l].xshift = 0;
1375                  tiles = (gbcmap[m_layer[l].xindex] & 0x08) ? (m_vram + m_gbc_chrgen_offs) : (m_vram + m_gb_chrgen_offs);
1376
1377                  /* Check for vertical flip */
1378                  if (gbcmap[m_layer[l].xindex] & 0x40)
1379                  {
1380                     tiles += ((7 - (m_layer[l].bgline & 0x07)) << 1);
1381                  }
1382                  else
1383                  {
1384                     tiles += ((m_layer[l].bgline & 0x07) << 1);
1385                  }
1386                  tile_index = (map[m_layer[l].xindex] ^ m_gb_tile_no_mod) * 16;
1387                  data = tiles[tile_index] | (tiles[tile_index + 1] << 8);
1388               }
1389            }
1390            l++;
1391         }
1392         if (m_end_x == 160 && (LCDCONT & 0x02))
1393         {
1394            update_sprites();
1395         }
1396         m_start_x = m_end_x;
1397      }
1398   }
1399   else
1400   {
1401      if (!(LCDCONT & 0x80))
1402      {
1403         /* Draw an empty line when LCD is disabled */
1404         if (m_previous_line != m_current_line)
1405         {
1406            if (m_current_line < 144)
1407            {
1408               screen_device *screen = machine().first_screen();
1409               const rectangle &r1 = screen->visible_area();
1410               rectangle r(r1.min_x, r1.max_x, m_current_line, m_current_line);
1411               bitmap.fill((!m_gbc_mode) ? 0 : 32767 , r);
1412            }
1413            m_previous_line = m_current_line;
1414         }
1415      }
1416   }
1417
1418   g_profiler.stop();
1419}
1420
1421
1422TIMER_CALLBACK_MEMBER(gb_lcd_device::video_init_vbl)
1423{
1424   m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
1425}
1426
1427UINT32 gb_lcd_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
1428{
1429   copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
1430   return 0;
1431}
1432
1433
1434void gb_lcd_device::increment_scanline()
1435{
1436   m_current_line = (m_current_line + 1) % 154;
1437   if (LCDCONT & 0x80)
1438   {
1439      CURLINE = m_current_line;
1440   }
1441   if (m_current_line == 0)
1442   {
1443      m_window_lines_drawn = 0;
1444   }
1445}
1446
1447TIMER_CALLBACK_MEMBER(gb_lcd_device::lcd_timer_proc)
1448{
1449   static const int sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
1450
1451   m_state = param;
1452
1453   if (LCDCONT & 0x80)
1454   {
1455      switch (m_state)
1456      {
1457      case GB_LCD_STATE_LYXX_PRE_M0:  /* Just before switching to mode 0 */
1458         m_mode = 0;
1459         if (LCDSTAT & 0x08)
1460         {
1461            if (!m_mode_irq)
1462            {
1463               if (!m_line_irq && !m_delayed_line_irq)
1464               {
1465                  m_mode_irq = 1;
1466                  m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1467               }
1468            }
1469            else
1470            {
1471               m_mode_irq = 0;
1472            }
1473         }
1474         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
1475         break;
1476      case GB_LCD_STATE_LYXX_M0:      /* Switch to mode 0 */
1477         /* update current scanline */
1478         update_scanline();
1479         /* Increment the number of window lines drawn if enabled */
1480         if (m_layer[1].enabled)
1481         {
1482            m_window_lines_drawn++;
1483         }
1484         m_previous_line = m_current_line;
1485         /* Set Mode 0 lcdstate */
1486         m_mode = 0;
1487         LCDSTAT &= 0xFC;
1488         m_oam_locked = UNLOCKED;
1489         m_vram_locked = UNLOCKED;
1490         /*
1491             There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
1492             SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
1493             than usual.
1494             The SGB probably has the same bug.
1495         */
1496         if ((SCROLLX & 0x03) == 0x03)
1497         {
1498            m_scrollx_adjust += 4;
1499            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
1500            break;
1501         }
1502      case GB_LCD_STATE_LYXX_M0_SCX3:
1503         /* Generate lcd interrupt if requested */
1504         if (!m_mode_irq && (LCDSTAT & 0x08) &&
1505               ((!m_line_irq && m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1506         {
1507            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1508         }
1509         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(196 - m_scrollx_adjust - m_sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
1510         break;
1511      case GB_LCD_STATE_LYXX_M0_PRE_INC:  /* Just before incrementing the line counter go to mode 2 internally */
1512         if (CURLINE < 143)
1513         {
1514            m_mode = 2;
1515            m_triggering_mode_irq = (LCDSTAT & 0x20) ? 1 : 0;
1516            if (m_triggering_mode_irq)
1517            {
1518               if (!m_mode_irq)
1519               {
1520                  if (!m_line_irq && !m_delayed_line_irq)
1521                  {
1522                     m_mode_irq = 1;
1523                     m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1524                  }
1525               }
1526               else
1527               {
1528                  m_mode_irq = 0;
1529               }
1530            }
1531         }
1532         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
1533         break;
1534      case GB_LCD_STATE_LYXX_M0_INC:  /* Increment LY, stay in M0 for 4 more cycles */
1535         increment_scanline();
1536         m_delayed_line_irq = m_line_irq;
1537         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1538         m_line_irq = 0;
1539         if (!m_mode_irq && !m_delayed_line_irq && m_triggering_line_irq && !m_triggering_mode_irq)
1540         {
1541            m_line_irq = m_triggering_line_irq;
1542            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1543         }
1544         /* Reset LY==LYC STAT bit */
1545         LCDSTAT &= 0xFB;
1546         /* Check if we're going into VBlank next */
1547         if (CURLINE == 144)
1548         {
1549            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1550         }
1551         else
1552         {
1553            /* Internally switch to mode 2 */
1554            m_mode = 2;
1555            /* Generate lcd interrupt if requested */
1556            if (!m_mode_irq && m_triggering_mode_irq &&
1557                  ((!m_triggering_line_irq && !m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1558            {
1559               m_mode_irq = 1;
1560               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1561            }
1562            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
1563         }
1564         break;
1565      case GB_LCD_STATE_LY00_M2:      /* Switch to mode 2 on line #0 */
1566         /* Set Mode 2 lcdstate */
1567         m_mode = 2;
1568         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1569         m_oam_locked = LOCKED;
1570         /* Generate lcd interrupt if requested */
1571         if ((LCDSTAT & 0x20) && !m_line_irq)
1572         {
1573            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1574         }
1575         /* Check for regular compensation of x-scroll register */
1576         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1577         /* Mode 2 lasts approximately 80 clock cycles */
1578         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1579         break;
1580      case GB_LCD_STATE_LYXX_M2:      /* Switch to mode 2 */
1581         /* Update STAT register to the correct state */
1582         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1583         m_oam_locked = LOCKED;
1584         /* Generate lcd interrupt if requested */
1585         if ((m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20)) ||
1586               (!m_mode_irq && !m_line_irq && !m_delayed_line_irq && m_triggering_mode_irq))
1587         {
1588            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1589         }
1590         m_line_irq = m_triggering_line_irq;
1591         m_triggering_mode_irq = 0;
1592         /* Check if LY==LYC STAT bit should be set */
1593         if (CURLINE == CMPLINE)
1594         {
1595            LCDSTAT |= 0x04;
1596         }
1597         /* Check for regular compensation of x-scroll register */
1598         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1599         /* Mode 2 last for approximately 80 clock cycles */
1600         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1601         break;
1602      case GB_LCD_STATE_LYXX_M3:      /* Switch to mode 3 */
1603         select_sprites();
1604         m_sprite_cycles = sprite_cycles[m_sprCount];
1605         /* Set Mode 3 lcdstate */
1606         m_mode = 3;
1607         LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
1608         m_vram_locked = LOCKED;
1609         /* Check for compensations of x-scroll register */
1610         /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
1611         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(168 + m_scrollx_adjust + m_sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
1612         m_start_x = -1;
1613         break;
1614      case GB_LCD_STATE_LY9X_M1:      /* Switch to or stay in mode 1 */
1615         if (CURLINE == 144)
1616         {
1617            /* Trigger VBlank interrupt */
1618            m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
1619            /* Set VBlank lcdstate */
1620            m_mode = 1;
1621            LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
1622            /* Trigger LCD interrupt if requested */
1623            if (LCDSTAT & 0x10)
1624            {
1625               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1626            }
1627         }
1628         /* Check if LY==LYC STAT bit should be set */
1629         if (CURLINE == CMPLINE)
1630         {
1631            LCDSTAT |= 0x04;
1632         }
1633         if (m_delayed_line_irq && m_triggering_line_irq)
1634         {
1635            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1636         }
1637         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
1638         break;
1639      case GB_LCD_STATE_LY9X_M1_INC:      /* Increment scanline counter */
1640         increment_scanline();
1641         m_delayed_line_irq = m_line_irq;
1642         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1643         m_line_irq = 0;
1644         if (!m_delayed_line_irq && m_triggering_line_irq)
1645         {
1646            m_line_irq = m_triggering_line_irq;
1647            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1648         }
1649         /* Reset LY==LYC STAT bit */
1650         LCDSTAT &= 0xFB;
1651         if (m_current_line == 153)
1652         {
1653            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
1654         }
1655         else
1656         {
1657            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1658         }
1659         break;
1660      case GB_LCD_STATE_LY00_M1:      /* we stay in VBlank but current line counter should already be incremented */
1661         /* Check LY=LYC for line #153 */
1662         if (m_delayed_line_irq)
1663         {
1664            if (m_triggering_line_irq)
1665            {
1666               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1667            }
1668         }
1669         m_delayed_line_irq = m_delayed_line_irq | m_line_irq;
1670         if (CURLINE == CMPLINE)
1671         {
1672            LCDSTAT |= 0x04;
1673         }
1674         increment_scanline();
1675         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1676         m_line_irq = 0;
1677         LCDSTAT &= 0xFB;
1678         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4/*8*/), GB_LCD_STATE_LY00_M1_1);
1679         break;
1680      case GB_LCD_STATE_LY00_M1_1:
1681         if (!m_delayed_line_irq && m_triggering_line_irq)
1682         {
1683            m_line_irq = m_triggering_line_irq;
1684            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1685         }
1686         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
1687         break;
1688      case GB_LCD_STATE_LY00_M1_2:    /* Rest of line #0 during VBlank */
1689         if (m_delayed_line_irq && m_triggering_line_irq)
1690         {
1691            m_line_irq = m_triggering_line_irq;
1692            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1693         }
1694         if (CURLINE == CMPLINE)
1695         {
1696            LCDSTAT |= 0x04;
1697         }
1698         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
1699         break;
1700      case GB_LCD_STATE_LY00_M0:      /* The STAT register seems to go to 0 for about 4 cycles */
1701         /* Set Mode 0 lcdstat */
1702         m_mode = 0;
1703         LCDSTAT = (LCDSTAT & 0xFC);
1704         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
1705         break;
1706      }
1707   }
1708   else
1709   {
1710      increment_scanline();
1711      if (m_current_line < 144)
1712      {
1713         update_scanline();
1714      }
1715      m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
1716   }
1717}
1718
1719
1720// CGB specific code
1721
1722void cgb_lcd_device::hdma_trans(UINT16 length)
1723{
1724   UINT16 src, dst;
1725   address_space &space = m_maincpu->space(AS_PROGRAM);
1726   
1727   src = ((UINT16)HDMA1 << 8) | (HDMA2 & 0xF0);
1728   dst = ((UINT16)(HDMA3 & 0x1F) << 8) | (HDMA4 & 0xF0);
1729   dst |= 0x8000;
1730   while (length > 0)
1731   {
1732      space.write_byte(dst++, space.read_byte(src++));
1733      length--;
1734   }
1735   HDMA1 = src >> 8;
1736   HDMA2 = src & 0xF0;
1737   HDMA3 = 0x1f & (dst >> 8);
1738   HDMA4 = dst & 0xF0;
1739   HDMA5--;
1740   if ((HDMA5 & 0x7f) == 0x7f)
1741   {
1742      HDMA5 = 0xff;
1743      m_hdma_enabled = 0;
1744   }
1745}
1746
1747
1748TIMER_CALLBACK_MEMBER(cgb_lcd_device::lcd_timer_proc)
1749{
1750   static const int sprite_cycles[] = { 0, 8, 20, 32, 44, 52, 64, 76, 88, 96, 108 };
1751
1752   m_state = param;
1753
1754   if (LCDCONT & 0x80)
1755   {
1756      switch (m_state)
1757      {
1758      case GB_LCD_STATE_LYXX_PRE_M0:  /* Just before switching to mode 0 */
1759         m_mode = 0;
1760         if (LCDSTAT & 0x08)
1761         {
1762            if (!m_mode_irq)
1763            {
1764               if (!m_line_irq && !m_delayed_line_irq)
1765               {
1766                  m_mode_irq = 1;
1767                  m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1768               }
1769            }
1770            else
1771            {
1772               m_mode_irq = 0;
1773            }
1774         }
1775         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0);
1776         break;
1777      case GB_LCD_STATE_LYXX_M0:      /* Switch to mode 0 */
1778         /* update current scanline */
1779         update_scanline();
1780         /* Increment the number of window lines drawn if enabled */
1781         if (m_layer[1].enabled)
1782         {
1783            m_window_lines_drawn++;
1784         }
1785         m_previous_line = m_current_line;
1786         /* Set Mode 0 lcdstate */
1787         m_mode = 0;
1788         LCDSTAT &= 0xFC;
1789         m_oam_locked = UNLOCKED;
1790         m_vram_locked = UNLOCKED;
1791         /*
1792             There seems to a kind of feature in the Game Boy hardware when the lowest bits of the
1793             SCROLLX register equals 3 or 7, then the delayed M0 irq is triggered 4 cycles later
1794             than usual.
1795             The SGB probably has the same bug.
1796         */
1797         m_triggering_mode_irq = (LCDSTAT & 0x08) ? 1 : 0;
1798         if ((SCROLLX & 0x03) == 0x03)
1799         {
1800            m_scrollx_adjust += 4;
1801            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_SCX3);
1802            break;
1803         }
1804      case GB_LCD_STATE_LYXX_M0_SCX3:
1805         /* Generate lcd interrupt if requested */
1806         if (!m_mode_irq && m_triggering_mode_irq &&
1807               ((!m_line_irq && m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1808         {
1809            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1810            m_triggering_mode_irq = 0;
1811         }
1812         if ((SCROLLX & 0x03) == 0x03)
1813         {
1814            m_pal_locked = UNLOCKED;
1815         }
1816         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_GBC_PAL);
1817         break;
1818      case GB_LCD_STATE_LYXX_M0_GBC_PAL:
1819         m_pal_locked = UNLOCKED;
1820         /* Check for HBLANK DMA */
1821         if (m_hdma_enabled)
1822         {
1823            hdma_trans(0x10);
1824//              cpunum_set_reg(0, LR35902_DMA_CYCLES, 36);
1825         }
1826         else
1827         {
1828            m_hdma_possible = 1;
1829         }
1830         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(192 - m_scrollx_adjust - m_sprite_cycles), GB_LCD_STATE_LYXX_M0_PRE_INC);
1831         break;
1832      case GB_LCD_STATE_LYXX_M0_PRE_INC:  /* Just before incrementing the line counter go to mode 2 internally */
1833         m_cmp_line = CMPLINE;
1834         if (CURLINE < 143)
1835         {
1836            m_mode = 2;
1837            if (LCDSTAT & 0x20)
1838            {
1839               if (!m_mode_irq)
1840               {
1841                  if (!m_line_irq && !m_delayed_line_irq)
1842                  {
1843                     m_mode_irq = 1;
1844                     m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1845                  }
1846               }
1847               else
1848               {
1849                  m_mode_irq = 0;
1850               }
1851            }
1852         }
1853         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M0_INC);
1854         break;
1855      case GB_LCD_STATE_LYXX_M0_INC:  /* Increment LY, stay in M0 for 4 more cycles */
1856         increment_scanline();
1857         m_delayed_line_irq = m_line_irq;
1858         m_triggering_line_irq = ((m_cmp_line == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1859         m_line_irq = 0;
1860         if (!m_mode_irq && !m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20))
1861         {
1862            m_line_irq = m_triggering_line_irq;
1863            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1864         }
1865         m_hdma_possible = 0;
1866         /* Check if we're going into VBlank next */
1867         if (CURLINE == 144)
1868         {
1869            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1870         }
1871         else
1872         {
1873            /* Internally switch to mode 2 */
1874            m_mode = 2;
1875            /* Generate lcd interrupt if requested */
1876            if (!m_mode_irq && (LCDSTAT & 0x20) &&
1877                  ((!m_triggering_line_irq && !m_delayed_line_irq) || !(LCDSTAT & 0x40)))
1878            {
1879               m_mode_irq = 1;
1880               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1881            }
1882            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LYXX_M2);
1883         }
1884         break;
1885      case GB_LCD_STATE_LY00_M2:      /* Switch to mode 2 on line #0 */
1886         /* Set Mode 2 lcdstate */
1887         m_mode = 2;
1888         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1889         m_oam_locked = LOCKED;
1890         /* Generate lcd interrupt if requested */
1891         if ((LCDSTAT & 0x20) && ! m_line_irq)
1892         {
1893            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1894         }
1895         /* Check for regular compensation of x-scroll register */
1896         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1897         /* Mode 2 lasts approximately 80 clock cycles */
1898         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1899         break;
1900      case GB_LCD_STATE_LYXX_M2:      /* Switch to mode 2 */
1901         /* Update STAT register to the correct state */
1902         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1903         m_oam_locked = LOCKED;
1904         /* Generate lcd interrupt if requested */
1905         if ((m_delayed_line_irq && m_triggering_line_irq && !(LCDSTAT & 0x20)) ||
1906               (!m_mode_irq && !m_line_irq && !m_delayed_line_irq && (LCDSTAT & 0x20)))
1907         {
1908            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1909         }
1910         m_line_irq = m_triggering_line_irq;
1911         /* Check if LY==LYC STAT bit should be set */
1912         if (CURLINE == CMPLINE)
1913         {
1914            LCDSTAT |= 0x04;
1915         }
1916         else
1917         {
1918            LCDSTAT &= ~0x04;
1919         }
1920         /* Check for regular compensation of x-scroll register */
1921         m_scrollx_adjust = (SCROLLX & 0x04) ? 4 : 0;
1922         /* Mode 2 last for approximately 80 clock cycles */
1923         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
1924         break;
1925      case GB_LCD_STATE_LYXX_M3:      /* Switch to mode 3 */
1926         select_sprites();
1927         m_sprite_cycles = sprite_cycles[m_sprCount];
1928         /* Set Mode 3 lcdstate */
1929         m_mode = 3;
1930         LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
1931         m_vram_locked = LOCKED;
1932         m_pal_locked = LOCKED;
1933         /* Check for compensations of x-scroll register */
1934         /* Mode 3 lasts for approximately 172+cycles needed to handle sprites clock cycles */
1935         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(168 + m_scrollx_adjust + m_sprite_cycles), GB_LCD_STATE_LYXX_PRE_M0);
1936         m_start_x = -1;
1937         break;
1938      case GB_LCD_STATE_LY9X_M1:      /* Switch to or stay in mode 1 */
1939         if (CURLINE == 144)
1940         {
1941            /* Trigger VBlank interrupt */
1942            m_maincpu->set_input_line(VBL_INT, ASSERT_LINE);
1943            /* Set VBlank lcdstate */
1944            m_mode = 1;
1945            LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
1946            /* Trigger LCD interrupt if requested */
1947            if (LCDSTAT & 0x10)
1948            {
1949               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1950            }
1951         }
1952         /* Check if LY==LYC STAT bit should be set */
1953         if (CURLINE == CMPLINE)
1954         {
1955            LCDSTAT |= 0x04;
1956         }
1957         else
1958         {
1959            LCDSTAT &= ~0x04;
1960         }
1961         if (m_delayed_line_irq && m_triggering_line_irq)
1962         {
1963            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1964         }
1965         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(452), GB_LCD_STATE_LY9X_M1_INC);
1966         break;
1967      case GB_LCD_STATE_LY9X_M1_INC:      /* Increment scanline counter */
1968         increment_scanline();
1969         m_delayed_line_irq = m_line_irq;
1970         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
1971         m_line_irq = 0;
1972         if (!m_delayed_line_irq && m_triggering_line_irq)
1973         {
1974            m_line_irq = m_triggering_line_irq;
1975            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1976         }
1977         if (m_current_line == 153)
1978         {
1979            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1);
1980         }
1981         else
1982         {
1983            m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY9X_M1);
1984         }
1985         break;
1986      case GB_LCD_STATE_LY00_M1:      /* we stay in VBlank but current line counter should already be incremented */
1987         /* Check LY=LYC for line #153 */
1988         if (m_delayed_line_irq)
1989         {
1990            if (m_triggering_line_irq)
1991            {
1992               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
1993            }
1994         }
1995         m_delayed_line_irq = m_delayed_line_irq | m_line_irq;
1996         if (CURLINE == CMPLINE)
1997         {
1998            LCDSTAT |= 0x04;
1999         }
2000         else
2001         {
2002            LCDSTAT &= ~0x04;
2003         }
2004         increment_scanline();
2005         m_triggering_line_irq = ((CMPLINE == CURLINE) && (LCDSTAT & 0x40)) ? 1 : 0;
2006         m_line_irq = 0;
2007         LCDSTAT &= 0xFB;
2008         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_1);
2009         break;
2010      case GB_LCD_STATE_LY00_M1_1:
2011         if (!m_delayed_line_irq && m_triggering_line_irq)
2012         {
2013            m_line_irq = m_triggering_line_irq;
2014            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2015         }
2016         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M1_2);
2017         break;
2018      case GB_LCD_STATE_LY00_M1_2:    /* Rest of line #0 during VBlank */
2019         if (m_delayed_line_irq && m_triggering_line_irq)
2020         {
2021            m_line_irq = m_triggering_line_irq;
2022            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2023         }
2024         if (CURLINE == CMPLINE)
2025         {
2026            LCDSTAT |= 0x04;
2027         }
2028         else
2029         {
2030            LCDSTAT &= ~0x04;
2031         }
2032         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(444), GB_LCD_STATE_LY00_M0);
2033         break;
2034      case GB_LCD_STATE_LY00_M0:      /* The STAT register seems to go to 0 for about 4 cycles */
2035         /* Set Mode 0 lcdstat */
2036         m_mode = 0;
2037         m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(4), GB_LCD_STATE_LY00_M2);
2038         break;
2039      }
2040   }
2041   else
2042   {
2043      increment_scanline();
2044      if (m_current_line < 144)
2045      {
2046         update_scanline();
2047      }
2048      m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(456));
2049   }
2050}
2051
2052
2053void gb_lcd_device::lcd_switch_on()
2054{
2055   m_current_line = 0;
2056   m_previous_line = 153;
2057   m_window_lines_drawn = 0;
2058   m_line_irq = 0;
2059   m_delayed_line_irq = 0;
2060   m_mode = 0;
2061   m_oam_locked = LOCKED;   /* TODO: Investigate whether this OAM locking is correct. */
2062   /* Check for LY=LYC coincidence */
2063   if (CURLINE == CMPLINE)
2064   {
2065      LCDSTAT |= 0x04;
2066      /* Generate lcd interrupt if requested */
2067      if (LCDSTAT & 0x40)
2068      {
2069         m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2070      }
2071   }
2072   m_state = GB_LCD_STATE_LY00_M2;
2073   m_lcd_timer->adjust(m_maincpu->cycles_to_attotime(80), GB_LCD_STATE_LYXX_M3);
2074}
2075
2076
2077
2078
2079READ8_MEMBER(gb_lcd_device::vram_r)
2080{
2081   return (m_vram_locked == LOCKED) ? 0xff : m_vram[offset + (m_vram_bank * 0x2000)];
2082}
2083
2084WRITE8_MEMBER(gb_lcd_device::vram_w)
2085{
2086   if (m_vram_locked == LOCKED)
2087      return;
2088   
2089   m_vram[offset + (m_vram_bank * 0x2000)] = data;
2090}
2091
2092READ8_MEMBER(gb_lcd_device::oam_r)
2093{
2094   return (m_oam_locked == LOCKED) ? 0xff : m_oam[offset];
2095}
2096
2097WRITE8_MEMBER(gb_lcd_device::oam_w)
2098{
2099   if (m_oam_locked == LOCKED || offset >= 0xa0)
2100      return;
2101   
2102   m_oam[offset] = data;
2103}
2104
2105
2106
2107READ8_MEMBER(gb_lcd_device::video_r)
2108{
2109   return m_vid_regs[offset];
2110}
2111
2112WRITE8_MEMBER(gb_lcd_device::video_w)
2113{
2114   switch (offset)
2115   {
2116   case 0x00:                      /* LCDC - LCD Control */
2117      m_gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800;
2118      m_gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
2119      m_gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800;
2120      m_gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800;
2121      /* if LCD controller is switched off, set STAT and LY to 00 */
2122      if (!(data & 0x80))
2123      {
2124         LCDSTAT &= ~0x03;
2125         CURLINE = 0;
2126         m_oam_locked = UNLOCKED;
2127         m_vram_locked = UNLOCKED;
2128      }
2129      /* If LCD is being switched on */
2130      if (!(LCDCONT & 0x80) && (data & 0x80))
2131      {
2132         lcd_switch_on();
2133      }
2134      break;
2135   case 0x01:                      /* STAT - LCD Status */
2136      data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
2137      /*
2138         Check for the STAT bug:
2139         Writing to STAT when the LCD controller is active causes a STAT
2140         interrupt to be triggered.
2141       */
2142      if (LCDCONT & 0x80)
2143      {
2144         /* Triggers seen so far:
2145            - 0x40 -> 0x00 - trigger
2146            - 0x00 -> 0x08 - trigger
2147            - 0x08 -> 0x00 - don't trigger
2148            - 0x00 -> 0x20 (mode 3) - trigger
2149            - 0x00 -> 0x60 (mode 2) - don't trigger
2150            - 0x20 -> 0x60 (mode 3) - trigger
2151            - 0x20 -> 0x40 (mode 3) - trigger
2152            - 0x40 -> 0x20 (mode 2) - don't trigger
2153            - 0x40 -> 0x08 (mode 0) - don't trigger
2154            - 0x00 -> 0x40 - trigger only if LY==LYC
2155            - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 2, after m2int) - don't trigger
2156            - 0x20 -> 0x00/0x08/0x10/0x20/0x40 (mode 3, after m2int) - don't trigger
2157         */
2158         if (!m_mode_irq && ((m_mode == 1) ||
2159            ((LCDSTAT & 0x40) && !(data & 0x68)) ||
2160            (!(LCDSTAT & 0x40) && (data & 0x40) && (LCDSTAT & 0x04)) ||
2161            (!(LCDSTAT & 0x48) && (data & 0x08)) ||
2162            ((LCDSTAT & 0x60) == 0x00 && (data & 0x60) == 0x20) ||
2163            ((LCDSTAT & 0x60) == 0x20 && (data & 0x40))
2164            ))
2165         {
2166            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2167         }
2168         /*
2169            - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
2170            - 0x20 -> 0x00/0x10/0x20/0x40 (mode 0, after m2int) - trigger (stat bug)
2171            - 0x00 -> 0xXX (mode 0) - trigger stat bug
2172         */
2173         if (m_mode_irq && m_mode == 0)
2174         {
2175            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2176         }
2177      }
2178      break;
2179   case 0x04:                      /* LY - LCD Y-coordinate */
2180      return;
2181   case 0x05:                      /* LYC */
2182      if (CMPLINE != data)
2183      {
2184         if (CURLINE == data)
2185         {
2186            if (m_state != GB_LCD_STATE_LYXX_M0_INC && m_state != GB_LCD_STATE_LY9X_M1_INC)
2187            {
2188               LCDSTAT |= 0x04;
2189               /* Generate lcd interrupt if requested */
2190               if (LCDSTAT & 0x40)
2191               {
2192                  m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2193               }
2194            }
2195         }
2196         else
2197         {
2198            LCDSTAT &= 0xFB;
2199            m_triggering_line_irq = 0;
2200         }
2201      }
2202      break;
2203   case 0x06:                      /* DMA - DMA Transfer and Start Address */
2204      {
2205         UINT8 *P = m_oam;
2206         offset = (UINT16) data << 8;
2207         for (data = 0; data < 0xA0; data++)
2208            *P++ = space.read_byte(offset++);
2209      }
2210      return;
2211   case 0x07:                      /* BGP - Background Palette */
2212      update_scanline();
2213      m_gb_bpal[0] = data & 0x3;
2214      m_gb_bpal[1] = (data & 0xC) >> 2;
2215      m_gb_bpal[2] = (data & 0x30) >> 4;
2216      m_gb_bpal[3] = (data & 0xC0) >> 6;
2217      break;
2218   case 0x08:                      /* OBP0 - Object Palette 0 */
2219//      update_scanline();
2220      m_gb_spal0[0] = data & 0x3;
2221      m_gb_spal0[1] = (data & 0xC) >> 2;
2222      m_gb_spal0[2] = (data & 0x30) >> 4;
2223      m_gb_spal0[3] = (data & 0xC0) >> 6;
2224      break;
2225   case 0x09:                      /* OBP1 - Object Palette 1 */
2226//      update_scanline();
2227      m_gb_spal1[0] = data & 0x3;
2228      m_gb_spal1[1] = (data & 0xC) >> 2;
2229      m_gb_spal1[2] = (data & 0x30) >> 4;
2230      m_gb_spal1[3] = (data & 0xC0) >> 6;
2231      break;
2232   case 0x02:                      /* SCY - Scroll Y */
2233   case 0x03:                      /* SCX - Scroll X */
2234      update_scanline();
2235      break;
2236   case 0x0A:                      /* WY - Window Y position */
2237   case 0x0B:                      /* WX - Window X position */
2238      break;
2239   default:                        /* Unknown register, no change */
2240      return;
2241   }
2242   m_vid_regs[offset] = data;
2243}
2244
2245READ8_MEMBER(cgb_lcd_device::video_r)
2246{
2247   switch (offset)
2248   {
2249   case 0x11:  /* FF51 */
2250   case 0x12:  /* FF52 */
2251   case 0x13:  /* FF53 */
2252   case 0x14:  /* FF54 */
2253      return 0xFF;
2254   case 0x29:  /* FF69 */
2255   case 0x2B:  /* FF6B */
2256      if (m_pal_locked == LOCKED)
2257      {
2258         return 0xFF;
2259      }
2260      break;
2261   }
2262   return m_vid_regs[offset];
2263}
2264
2265WRITE8_MEMBER(cgb_lcd_device::video_w)
2266{
2267   switch (offset)
2268   {
2269   case 0x00:      /* LCDC - LCD Control */
2270      m_gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800;
2271      m_gbc_chrgen_offs = (data & 0x10) ? 0x2000 : 0x2800;
2272      m_gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80;
2273      m_gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800;
2274      m_gbc_bgdtab_offs = (data & 0x08) ? 0x3c00 : 0x3800;
2275      m_gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800;
2276      m_gbc_wndtab_offs = (data & 0x40) ? 0x3c00 : 0x3800;
2277      /* if LCD controller is switched off, set STAT to 00 */
2278      if (!(data & 0x80))
2279      {
2280         LCDSTAT &= ~0x03;
2281         CURLINE = 0;
2282         m_oam_locked = UNLOCKED;
2283         m_vram_locked = UNLOCKED;
2284         m_pal_locked = UNLOCKED;
2285      }
2286      /* If LCD is being switched on */
2287      if (!(LCDCONT & 0x80) && (data & 0x80))
2288      {
2289         lcd_switch_on();
2290      }
2291      break;
2292   case 0x01:      /* STAT - LCD Status */
2293      data = 0x80 | (data & 0x78) | (LCDSTAT & 0x07);
2294      if (LCDCONT & 0x80)
2295      {
2296         /*
2297            - 0x20 -> 0x08/0x18/0x28/0x48 (mode 0, after m2int) - trigger
2298         */
2299         if (m_mode_irq && m_mode == 0 && (LCDSTAT & 0x28) == 0x20 && (data & 0x08))
2300         {
2301            m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2302         }
2303         /* Check if line irqs are being disabled */
2304         if (!(data & 0x40))
2305         {
2306            m_delayed_line_irq = 0;
2307         }
2308         /* Check if line irqs are being enabled */
2309         if (!(LCDSTAT & 0x40) && (data & 0x40))
2310         {
2311            if (CMPLINE == CURLINE)
2312            {
2313               m_line_irq = 1;
2314               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2315            }
2316         }
2317      }
2318      break;
2319   case 0x05:                      /* LYC */
2320      if (CMPLINE != data)
2321      {
2322         if ((m_state != GB_LCD_STATE_LYXX_M0_PRE_INC && CURLINE == data) ||
2323               (m_state == GB_LCD_STATE_LYXX_M0_INC && m_triggering_line_irq))
2324         {
2325            LCDSTAT |= 0x04;
2326            /* Generate lcd interrupt if requested */
2327            if (LCDSTAT & 0x40)
2328            {
2329               m_maincpu->set_input_line(LCD_INT, ASSERT_LINE);
2330            }
2331         }
2332         else
2333         {
2334            LCDSTAT &= 0xFB;
2335            m_triggering_line_irq = 0;
2336            m_cmp_line = data;
2337         }
2338      }
2339      break;
2340   case 0x07:      /* BGP - GB background palette */
2341      update_scanline();
2342      m_gb_bpal[0] = data & 0x3;
2343      m_gb_bpal[1] = (data & 0xC) >> 2;
2344      m_gb_bpal[2] = (data & 0x30) >> 4;
2345      m_gb_bpal[3] = (data & 0xC0) >> 6;
2346      break;
2347   case 0x08:      /* OBP0 - GB Object 0 palette */
2348      m_gb_spal0[0] = data & 0x3;
2349      m_gb_spal0[1] = (data & 0xC) >> 2;
2350      m_gb_spal0[2] = (data & 0x30) >> 4;
2351      m_gb_spal0[3] = (data & 0xC0) >> 6;
2352      break;
2353   case 0x09:      /* OBP1 - GB Object 1 palette */
2354      m_gb_spal1[0] = data & 0x3;
2355      m_gb_spal1[1] = (data & 0xC) >> 2;
2356      m_gb_spal1[2] = (data & 0x30) >> 4;
2357      m_gb_spal1[3] = (data & 0xC0) >> 6;
2358      break;
2359   case 0x0c:      /* Undocumented register involved in selecting gb/gbc mode */
2360      logerror("Write to undocumented register: %X = %X\n", offset, data);
2361      break;
2362   case 0x0F:      /* VBK - VRAM bank select */
2363      m_vram_bank = data & 0x01;
2364      data |= 0xFE;
2365      break;
2366   case 0x11:      /* HDMA1 - HBL General DMA - Source High */
2367      break;
2368   case 0x12:      /* HDMA2 - HBL General DMA - Source Low */
2369      data &= 0xF0;
2370      break;
2371   case 0x13:      /* HDMA3 - HBL General DMA - Destination High */
2372      data &= 0x1F;
2373      break;
2374   case 0x14:      /* HDMA4 - HBL General DMA - Destination Low */
2375      data &= 0xF0;
2376      break;
2377   case 0x15:      /* HDMA5 - HBL General DMA - Mode, Length */
2378      if (!(data & 0x80))
2379      {
2380         if (m_hdma_enabled)
2381         {
2382            m_hdma_enabled = 0;
2383            data = HDMA5 & 0x80;
2384         }
2385         else
2386         {
2387            /* General DMA */
2388            hdma_trans(((data & 0x7F) + 1) * 0x10);
2389//              cpunum_set_reg(0, LR35902_DMA_CYCLES, 4 + (((data & 0x7F) + 1) * 32));
2390            data = 0xff;
2391         }
2392      }
2393      else
2394      {
2395         /* H-Blank DMA */
2396         m_hdma_enabled = 1;
2397         data &= 0x7f;
2398         m_vid_regs[offset] = data;
2399         /* Check if HDMA should be immediately performed */
2400         if (m_hdma_possible)
2401         {
2402            hdma_trans(0x10);
2403//              cpunum_set_reg(0, LR35902_DMA_CYCLES, 36);
2404            m_hdma_possible = 0;
2405         }
2406      }
2407      break;
2408   case 0x28:      /* BCPS - Background palette specification */
2409      GBCBCPS = data;
2410      if (data & 0x01)
2411         GBCBCPD = m_cgb_bpal[(data >> 1) & 0x1F] >> 8;
2412      else
2413         GBCBCPD = m_cgb_bpal[(data >> 1) & 0x1F] & 0xFF;
2414      break;
2415   case 0x29:      /* BCPD - background palette data */
2416      if (m_pal_locked == LOCKED)
2417      {
2418         return;
2419      }
2420      GBCBCPD = data;
2421      if (GBCBCPS & 0x01)
2422         m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] = ((data << 8) | (m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] & 0xFF)) & 0x7FFF;
2423      else
2424         m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] = ((m_cgb_bpal[(GBCBCPS >> 1) & 0x1F] & 0xFF00) | data) & 0x7FFF;
2425      if (GBCBCPS & 0x80)
2426      {
2427         GBCBCPS++;
2428         GBCBCPS &= 0xBF;
2429      }
2430      break;
2431   case 0x2A:      /* OCPS - Object palette specification */
2432      GBCOCPS = data;
2433      if (data & 0x01)
2434         GBCOCPD = m_cgb_spal[(data >> 1) & 0x1F] >> 8;
2435      else
2436         GBCOCPD = m_cgb_spal[(data >> 1) & 0x1F] & 0xFF;
2437      break;
2438   case 0x2B:      /* OCPD - Object palette data */
2439      if (m_pal_locked == LOCKED)
2440      {
2441         return;
2442      }
2443      GBCOCPD = data;
2444      if (GBCOCPS & 0x01)
2445         m_cgb_spal[(GBCOCPS >> 1) & 0x1F] = ((data << 8) | (m_cgb_spal[(GBCOCPS >> 1) & 0x1F] & 0xFF)) & 0x7FFF;
2446      else
2447         m_cgb_spal[(GBCOCPS >> 1) & 0x1F] = ((m_cgb_spal[(GBCOCPS >> 1) & 0x1F] & 0xFF00) | data) & 0x7FFF;
2448      if (GBCOCPS & 0x80)
2449      {
2450         GBCOCPS++;
2451         GBCOCPS &= 0xBF;
2452      }
2453      break;
2454   /* Undocumented registers */
2455   case 0x2C:
2456      /* bit 0 can be read/written */
2457      logerror("Write to undocumented register: %X = %X\n", offset, data);
2458      data = 0xFE | (data & 0x01);
2459      if (data & 0x01)
2460      {
2461         m_gbc_mode = 0;
2462      }
2463      break;
2464   case 0x32:
2465   case 0x33:
2466   case 0x34:
2467      /* whole byte can be read/written */
2468      logerror("Write to undocumented register: %X = %X\n", offset, data);
2469      break;
2470   case 0x35:
2471      /* bit 4-6 can be read/written */
2472      logerror("Write to undocumented register: %X = %X\n", offset, data);
2473      data = 0x8F | (data & 0x70);
2474      break;
2475   case 0x36:
2476   case 0x37:
2477      logerror("Write to undocumented register: %X = %X\n", offset, data);
2478      return;
2479   default:
2480      /* we didn't handle the write, so pass it to the GB handler */
2481      gb_lcd_device::video_w(space, offset, data);
2482      return;
2483   }
2484
2485   m_vid_regs[offset] = data;
2486}
2487
2488// Super Game Boy
2489
2490void sgb_lcd_device::sgb_io_write_pal(int offs, UINT8 *data)
2491{
2492   switch (offs)
2493   {
2494      case 0x00:  /* PAL01 */
2495         m_sgb_pal[0 * 4 + 0] = data[1] | (data[2] << 8);
2496         m_sgb_pal[0 * 4 + 1] = data[3] | (data[4] << 8);
2497         m_sgb_pal[0 * 4 + 2] = data[5] | (data[6] << 8);
2498         m_sgb_pal[0 * 4 + 3] = data[7] | (data[8] << 8);
2499         m_sgb_pal[1 * 4 + 0] = data[1] | (data[2] << 8);
2500         m_sgb_pal[1 * 4 + 1] = data[9] | (data[10] << 8);
2501         m_sgb_pal[1 * 4 + 2] = data[11] | (data[12] << 8);
2502         m_sgb_pal[1 * 4 + 3] = data[13] | (data[14] << 8);
2503         break;
2504      case 0x01:  /* PAL23 */
2505         m_sgb_pal[2 * 4 + 0] = data[1] | (data[2] << 8);
2506         m_sgb_pal[2 * 4 + 1] = data[3] | (data[4] << 8);
2507         m_sgb_pal[2 * 4 + 2] = data[5] | (data[6] << 8);
2508         m_sgb_pal[2 * 4 + 3] = data[7] | (data[8] << 8);
2509         m_sgb_pal[3 * 4 + 0] = data[1] | (data[2] << 8);
2510         m_sgb_pal[3 * 4 + 1] = data[9] | (data[10] << 8);
2511         m_sgb_pal[3 * 4 + 2] = data[11] | (data[12] << 8);
2512         m_sgb_pal[3 * 4 + 3] = data[13] | (data[14] << 8);
2513         break;
2514      case 0x02:  /* PAL03 */
2515         m_sgb_pal[0 * 4 + 0] = data[1] | (data[2] << 8);
2516         m_sgb_pal[0 * 4 + 1] = data[3] | (data[4] << 8);
2517         m_sgb_pal[0 * 4 + 2] = data[5] | (data[6] << 8);
2518         m_sgb_pal[0 * 4 + 3] = data[7] | (data[8] << 8);
2519         m_sgb_pal[3 * 4 + 0] = data[1] | (data[2] << 8);
2520         m_sgb_pal[3 * 4 + 1] = data[9] | (data[10] << 8);
2521         m_sgb_pal[3 * 4 + 2] = data[11] | (data[12] << 8);
2522         m_sgb_pal[3 * 4 + 3] = data[13] | (data[14] << 8);
2523         break;
2524      case 0x03:  /* PAL12 */
2525         m_sgb_pal[1 * 4 + 0] = data[1] | (data[2] << 8);
2526         m_sgb_pal[1 * 4 + 1] = data[3] | (data[4] << 8);
2527         m_sgb_pal[1 * 4 + 2] = data[5] | (data[6] << 8);
2528         m_sgb_pal[1 * 4 + 3] = data[7] | (data[8] << 8);
2529         m_sgb_pal[2 * 4 + 0] = data[1] | (data[2] << 8);
2530         m_sgb_pal[2 * 4 + 1] = data[9] | (data[10] << 8);
2531         m_sgb_pal[2 * 4 + 2] = data[11] | (data[12] << 8);
2532         m_sgb_pal[2 * 4 + 3] = data[13] | (data[14] << 8);
2533         break;
2534      case 0x04:  /* ATTR_BLK */
2535      {
2536         UINT8 I, J, K, o;
2537         for( K = 0; K < data[1]; K++ )
2538         {
2539            o = K * 6;
2540            if( data[o + 2] & 0x1 )
2541            {
2542               for( I = data[ o + 4]; I <= data[o + 6]; I++ )
2543               {
2544                  for( J = data[o + 5]; J <= data[o + 7]; J++ )
2545                  {
2546                     m_sgb_pal_map[I][J] = data[o + 3] & 0x3;
2547                  }
2548               }
2549            }
2550         }
2551      }
2552         break;
2553      case 0x05:  /* ATTR_LIN */
2554      {
2555         UINT8 J, K;
2556         if( data[1] > 15 )
2557            data[1] = 15;
2558         for( K = 0; K < data[1]; K++ )
2559         {
2560            if( data[K + 1] & 0x80 )
2561            {
2562               for( J = 0; J < 20; J++ )
2563               {
2564                  m_sgb_pal_map[J][data[K + 1] & 0x1f] = (data[K + 1] & 0x60) >> 5;
2565               }
2566            }
2567            else
2568            {
2569               for( J = 0; J < 18; J++ )
2570               {
2571                  m_sgb_pal_map[data[K + 1] & 0x1f][J] = (data[K + 1] & 0x60) >> 5;
2572               }
2573            }
2574         }
2575      }
2576         break;
2577      case 0x06:  /* ATTR_DIV */
2578      {
2579         UINT8 I, J;
2580         if( data[1] & 0x40 ) /* Vertical */
2581         {
2582            for( I = 0; I < data[2]; I++ )
2583            {
2584               for( J = 0; J < 20; J++ )
2585               {
2586                  m_sgb_pal_map[J][I] = (data[1] & 0xC) >> 2;
2587               }
2588            }
2589            for( J = 0; J < 20; J++ )
2590            {
2591               m_sgb_pal_map[J][data[2]] = (data[1] & 0x30) >> 4;
2592            }
2593            for( I = data[2] + 1; I < 18; I++ )
2594            {
2595               for( J = 0; J < 20; J++ )
2596               {
2597                  m_sgb_pal_map[J][I] = data[1] & 0x3;
2598               }
2599            }
2600         }
2601         else /* Horizontal */
2602         {
2603            for( I = 0; I < data[2]; I++ )
2604            {
2605               for( J = 0; J < 18; J++ )
2606               {
2607                  m_sgb_pal_map[I][J] = (data[1] & 0xC) >> 2;
2608               }
2609            }
2610            for( J = 0; J < 18; J++ )
2611            {
2612               m_sgb_pal_map[data[2]][J] = (data[1] & 0x30) >> 4;
2613            }
2614            for( I = data[2] + 1; I < 20; I++ )
2615            {
2616               for( J = 0; J < 18; J++ )
2617               {
2618                  m_sgb_pal_map[I][J] = data[1] & 0x3;
2619               }
2620            }
2621         }
2622      }
2623         break;
2624      case 0x07:  /* ATTR_CHR */
2625      {
2626         UINT16 I, sets;
2627         UINT8 x, y;
2628         sets = (data[3] | (data[4] << 8) );
2629         if( sets > 360 )
2630            sets = 360;
2631         sets >>= 2;
2632         sets += 6;
2633         x = data[1];
2634         y = data[2];
2635         if( data[5] ) /* Vertical */
2636         {
2637            for( I = 6; I < sets; I++ )
2638            {
2639               m_sgb_pal_map[x][y++] = (data[I] & 0xC0) >> 6;
2640               if( y > 17 )
2641               {
2642                  y = 0;
2643                  x++;
2644                  if( x > 19 )
2645                     x = 0;
2646               }
2647               
2648               m_sgb_pal_map[x][y++] = (data[I] & 0x30) >> 4;
2649               if( y > 17 )
2650               {
2651                  y = 0;
2652                  x++;
2653                  if( x > 19 )
2654                     x = 0;
2655               }
2656               
2657               m_sgb_pal_map[x][y++] = (data[I] & 0xC) >> 2;
2658               if( y > 17 )
2659               {
2660                  y = 0;
2661                  x++;
2662                  if( x > 19 )
2663                     x = 0;
2664               }
2665               
2666               m_sgb_pal_map[x][y++] = data[I] & 0x3;
2667               if( y > 17 )
2668               {
2669                  y = 0;
2670                  x++;
2671                  if( x > 19 )
2672                     x = 0;
2673               }
2674            }
2675         }
2676         else /* horizontal */
2677         {
2678            for( I = 6; I < sets; I++ )
2679            {
2680               m_sgb_pal_map[x++][y] = (data[I] & 0xC0) >> 6;
2681               if( x > 19 )
2682               {
2683                  x = 0;
2684                  y++;
2685                  if( y > 17 )
2686                     y = 0;
2687               }
2688               
2689               m_sgb_pal_map[x++][y] = (data[I] & 0x30) >> 4;
2690               if( x > 19 )
2691               {
2692                  x = 0;
2693                  y++;
2694                  if( y > 17 )
2695                     y = 0;
2696               }
2697               
2698               m_sgb_pal_map[x++][y] = (data[I] & 0xC) >> 2;
2699               if( x > 19 )
2700               {
2701                  x = 0;
2702                  y++;
2703                  if( y > 17 )
2704                     y = 0;
2705               }
2706               
2707               m_sgb_pal_map[x++][y] = data[I] & 0x3;
2708               if( x > 19 )
2709               {
2710                  x = 0;
2711                  y++;
2712                  if( y > 17 )
2713                     y = 0;
2714               }
2715            }
2716         }
2717      }
2718         break;
2719      case 0x08:  /* SOUND */
2720         /* This command enables internal sound effects */
2721         /* Not Implemented */
2722         break;
2723      case 0x09:  /* SOU_TRN */
2724         /* This command sends data to the SNES sound processor.
2725          We'll need to emulate that for this to be used */
2726         /* Not Implemented */
2727         break;
2728      case 0x0A:  /* PAL_SET */
2729      {
2730         UINT16 index_;
2731         
2732         /* Palette 0 */
2733         index_ = (UINT16)(data[1] | (data[2] << 8)) * 4;
2734         m_sgb_pal[0] = m_sgb_pal_data[index_];
2735         m_sgb_pal[1] = m_sgb_pal_data[index_ + 1];
2736         m_sgb_pal[2] = m_sgb_pal_data[index_ + 2];
2737         m_sgb_pal[3] = m_sgb_pal_data[index_ + 3];
2738         /* Palette 1 */
2739         index_ = (UINT16)(data[3] | (data[4] << 8)) * 4;
2740         m_sgb_pal[4] = m_sgb_pal_data[index_];
2741         m_sgb_pal[5] = m_sgb_pal_data[index_ + 1];
2742         m_sgb_pal[6] = m_sgb_pal_data[index_ + 2];
2743         m_sgb_pal[7] = m_sgb_pal_data[index_ + 3];
2744         /* Palette 2 */
2745         index_ = (UINT16)(data[5] | (data[6] << 8)) * 4;
2746         m_sgb_pal[8] = m_sgb_pal_data[index_];
2747         m_sgb_pal[9] = m_sgb_pal_data[index_ + 1];
2748         m_sgb_pal[10] = m_sgb_pal_data[index_ + 2];
2749         m_sgb_pal[11] = m_sgb_pal_data[index_ + 3];
2750         /* Palette 3 */
2751         index_ = (UINT16)(data[7] | (data[8] << 8)) * 4;
2752         m_sgb_pal[12] = m_sgb_pal_data[index_];
2753         m_sgb_pal[13] = m_sgb_pal_data[index_ + 1];
2754         m_sgb_pal[14] = m_sgb_pal_data[index_ + 2];
2755         m_sgb_pal[15] = m_sgb_pal_data[index_ + 3];
2756         /* Attribute File */
2757         if (data[9] & 0x40)
2758            m_sgb_window_mask = 0;
2759         m_sgb_atf = (data[9] & 0x3f) * (18 * 5);
2760         if (data[9] & 0x80)
2761         {
2762            for (int j = 0; j < 18; j++ )
2763            {
2764               for (int i = 0; i < 5; i++ )
2765               {
2766                  m_sgb_pal_map[i * 4][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC0) >> 6;
2767                  m_sgb_pal_map[(i * 4) + 1][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x30) >> 4;
2768                  m_sgb_pal_map[(i * 4) + 2][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC) >> 2;
2769                  m_sgb_pal_map[(i * 4) + 3][j] = m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x3;
2770               }
2771            }
2772         }
2773      }
2774         break;
2775      case 0x0B:  /* PAL_TRN */
2776      {
2777         UINT16 col;
2778         
2779         for (int i = 0; i < 2048; i++ )
2780         {
2781            col = (m_vram[0x0800 + (i * 2) + 1] << 8) | m_vram[0x0800 + (i * 2)];
2782            m_sgb_pal_data[i] = col;
2783         }
2784      }
2785         break;
2786      case 0x0C:  /* ATRC_EN */
2787         /* Not Implemented */
2788         break;
2789      case 0x0D:  /* TEST_EN */
2790         /* Not Implemented */
2791         break;
2792      case 0x0E:  /* ICON_EN */
2793         /* Not Implemented */
2794         break;
2795      case 0x0F:  /* DATA_SND */
2796         /* Not Implemented */
2797         break;
2798      case 0x10:  /* DATA_TRN */
2799         /* Not Implemented */
2800         break;
2801      case 0x12:  /* JUMP */
2802         /* Not Implemented */
2803         break;
2804      case 0x13:  /* CHR_TRN */
2805         if (data[1] & 0x1)
2806            memcpy(m_sgb_tile_data + 4096, m_vram + 0x0800, 4096);
2807         else
2808            memcpy(m_sgb_tile_data, m_vram + 0x0800, 4096);
2809         break;
2810      case 0x14:  /* PCT_TRN */
2811      {
2812         UINT16 col;
2813         if (m_sgb_border_hack)
2814         {
2815            memcpy(m_sgb_tile_map, m_vram + 0x1000, 2048);
2816            for (int i = 0; i < 64; i++)
2817            {
2818               col = (m_vram[0x0800 + (i * 2) + 1 ] << 8) | m_vram[0x0800 + (i * 2)];
2819               m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
2820            }
2821         }
2822         else /* Do things normally */
2823         {
2824            memcpy(m_sgb_tile_map, m_vram + 0x0800, 2048);
2825            for (int i = 0; i < 64; i++)
2826            {
2827               col = (m_vram[0x1000 + (i * 2) + 1] << 8) | m_vram[0x1000 + (i * 2)];
2828               m_sgb_pal[SGB_BORDER_PAL_OFFSET + i] = col;
2829            }
2830         }
2831      }
2832         break;
2833      case 0x15:  /* ATTR_TRN */
2834         memcpy(m_sgb_atf_data, m_vram + 0x0800, 4050);
2835         break;
2836      case 0x16:  /* ATTR_SET */
2837      {         
2838         /* Attribute File */
2839         if (data[1] & 0x40)
2840            m_sgb_window_mask = 0;
2841         m_sgb_atf = (data[1] & 0x3f) * (18 * 5);
2842         for (int j = 0; j < 18; j++)
2843         {
2844            for (int i = 0; i < 5; i++)
2845            {
2846               m_sgb_pal_map[i * 4][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC0) >> 6;
2847               m_sgb_pal_map[(i * 4) + 1][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x30) >> 4;
2848               m_sgb_pal_map[(i * 4) + 2][j] = (m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0xC) >> 2;
2849               m_sgb_pal_map[(i * 4) + 3][j] = m_sgb_atf_data[(j * 5) + m_sgb_atf + i] & 0x3;
2850            }
2851         }
2852      }
2853         break;
2854      case 0x17:  /* MASK_EN */
2855         m_sgb_window_mask = data[1];
2856         break;
2857      case 0x18:  /* OBJ_TRN */
2858         /* Not Implemnted */
2859         break;
2860      case 0x19:  /* ? */
2861         /* Called by: dkl,dkl2,dkl3,zeldadx
2862          But I don't know what it is for. */
2863         /* Not Implemented */
2864         break;
2865      case 0x1E:  /* Used by bootrom to transfer the gb cart header */
2866         break;
2867      case 0x1F:  /* Used by bootrom to transfer the gb cart header */
2868         break;
2869      default:
2870         logerror( "SGB: Unknown Command 0x%02x!\n", data[0] >> 3 );
2871   }
2872   
2873}
2874
2875
Property changes on: trunk/src/mess/video/gb_lcd.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/video/gb_lcd.h
r0r23903
1/*****************************************************************************
2 *
3 * video/gb_lcd.h
4 *
5 ****************************************************************************/
6
7#ifndef __GB_LCD_H__
8#define __GB_LCD_H__
9
10#include "emu.h"
11
12
13#define _NR_GB_VID_REGS     0x40
14
15
16enum
17{
18   GB_VIDEO_DMG = 1,
19   GB_VIDEO_MGB,
20   GB_VIDEO_SGB,
21   GB_VIDEO_CGB
22};
23
24
25struct layer_struct {
26   UINT8  enabled;
27   UINT8  *bg_tiles;
28   UINT8  *bg_map;
29   UINT8  xindex;
30   UINT8  xshift;
31   UINT8  xstart;
32   UINT8  xend;
33   /* GBC specific */
34   UINT8  *gbc_map;
35   INT16  bgline;
36};
37
38
39class gb_lcd_device : public device_t
40{
41public:
42   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);
43   gb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
44
45   
46   UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
47
48   DECLARE_READ8_MEMBER(vram_r);
49   DECLARE_WRITE8_MEMBER(vram_w);
50   DECLARE_READ8_MEMBER(oam_r);
51   DECLARE_WRITE8_MEMBER(oam_w);
52   virtual DECLARE_READ8_MEMBER(video_r);
53   virtual DECLARE_WRITE8_MEMBER(video_w);
54
55   // FIXME: remove it when proper sgb support is added
56   void set_sgb_hack(bool val) { m_sgb_border_hack = val ? 1 : 0; }
57   
58protected:
59   inline void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color);
60   
61   void select_sprites();
62   virtual void update_sprites();
63   virtual void update_scanline();
64
65   // device-level overrides
66   virtual void device_start();
67   virtual void device_reset();
68   void common_start();
69   void common_reset();
70
71   // pointer to the main system
72   cpu_device *m_maincpu;
73   screen_device *m_screen;
74   
75   // state variables
76   bitmap_ind16 m_bitmap;
77
78   UINT8 m_sgb_atf_data[4050];       /* (SGB) Attributes files */
79   UINT32 m_sgb_atf;
80   UINT16 m_sgb_pal_data[4096];
81   UINT8 m_sgb_pal_map[20][18];
82   UINT16 m_sgb_pal[128];
83   UINT8 *m_sgb_tile_data;
84   UINT8 m_sgb_tile_map[2048];
85   UINT8 m_sgb_window_mask;
86   
87   // this is temporarily needed for a bunch of games which draw the border differently...
88   int m_sgb_border_hack;
89   
90   int m_window_lines_drawn;
91   
92   UINT8   m_vid_regs[_NR_GB_VID_REGS];
93   UINT8   m_bg_zbuf[160];
94   
95   UINT16  m_cgb_bpal[32];   /* CGB current background palette table */
96   UINT16  m_cgb_spal[32];   /* CGB current sprite palette table */
97   
98   UINT8   m_gb_bpal[4];     /* Background palette */
99   UINT8   m_gb_spal0[4];    /* Sprite 0 palette */
100   UINT8   m_gb_spal1[4];    /* Sprite 1 palette */
101   
102   /* Things used to render current line */
103   int m_current_line;       /* Current line */
104   int m_cmp_line;           /* Compare line */
105   int m_sprCount;           /* Number of sprites on current line */
106   int m_sprite[10];         /* References to sprites to draw on current line */
107   int m_previous_line;      /* Previous line we've drawn in */
108   int m_start_x;            /* Pixel to start drawing from (inclusive) */
109   int m_end_x;              /* Pixel to end drawing (exclusive) */
110   int m_mode;               /* Keep track of internal STAT mode */
111   int m_state;              /* Current state of the video state machine */
112   int m_lcd_irq_line;
113   int m_triggering_line_irq;
114   int m_line_irq;
115   int m_triggering_mode_irq;
116   int m_mode_irq;
117   int m_delayed_line_irq;
118   int m_sprite_cycles;
119   int m_scrollx_adjust;
120   int m_oam_locked;
121   int m_vram_locked;
122   int m_pal_locked;
123   int m_hdma_enabled;
124   int m_hdma_possible;
125   struct layer_struct m_layer[2];
126   emu_timer *m_lcd_timer;
127   int m_gbc_mode;
128   
129   UINT8   *m_vram;     // Pointer to VRAM
130   UINT8   *m_oam;      // Pointer to OAM memory
131   UINT8   m_gb_tile_no_mod;
132   UINT32  m_gb_chrgen_offs;     // GB Character generator
133   UINT32  m_gb_bgdtab_offs;     // GB Background character table
134   UINT32  m_gb_wndtab_offs;     // GB Window character table
135   UINT32  m_gbc_chrgen_offs;    // CGB Character generator
136   UINT32  m_gbc_bgdtab_offs;    // CGB Background character table
137   UINT32  m_gbc_wndtab_offs;    // CGB Window character table
138   int     m_vram_bank;
139
140   TIMER_CALLBACK_MEMBER(video_init_vbl);
141   virtual TIMER_CALLBACK_MEMBER(lcd_timer_proc);
142   virtual void videoptr_restore();
143   void save_gb_video();
144   void increment_scanline();
145   void lcd_switch_on();
146};
147
148
149class mgb_lcd_device : public gb_lcd_device
150{
151public:
152   mgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
153
154protected:
155   
156   // device-level overrides
157   virtual void device_start();
158   virtual void device_reset();
159};
160
161
162class sgb_lcd_device : public gb_lcd_device
163{
164public:
165   sgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
166   
167   void sgb_io_write_pal(int offs, UINT8 *data);
168
169protected:
170   
171   // device-level overrides
172   virtual void device_start();
173   virtual void device_reset();
174   
175   virtual void update_sprites();
176   virtual void update_scanline();
177   void refresh_border();
178};
179
180
181class cgb_lcd_device : public gb_lcd_device
182{
183public:
184   cgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
185   
186   virtual DECLARE_READ8_MEMBER(video_r);
187   virtual DECLARE_WRITE8_MEMBER(video_w);
188
189protected:
190   
191   // device-level overrides
192   virtual void device_start();
193   virtual void device_reset();
194   
195   virtual void update_sprites();
196   virtual void update_scanline();
197
198   virtual TIMER_CALLBACK_MEMBER(lcd_timer_proc);
199   virtual void videoptr_restore();
200   void hdma_trans(UINT16 length);
201};
202
203
204extern const device_type GB_LCD_DMG;
205extern const device_type GB_LCD_MGB;
206extern const device_type GB_LCD_SGB;
207extern const device_type GB_LCD_CGB;
208
209
210#define MCFG_GB_LCD_DMG_ADD(_tag ) \
211      MCFG_DEVICE_ADD( _tag, GB_LCD_DMG, 0 )
212
213#define MCFG_GB_LCD_MGB_ADD(_tag ) \
214      MCFG_DEVICE_ADD( _tag, GB_LCD_MGB, 0 )
215
216#define MCFG_GB_LCD_SGB_ADD(_tag ) \
217      MCFG_DEVICE_ADD( _tag, GB_LCD_SGB, 0 )
218
219#define MCFG_GB_LCD_CGB_ADD(_tag ) \
220      MCFG_DEVICE_ADD( _tag, GB_LCD_CGB, 0 )
221
222
223#endif /* GB_H_ */
Property changes on: trunk/src/mess/video/gb_lcd.h
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/includes/gb.h
r23902r23903
88#define GB_H_
99
1010#include "audio/gb.h"
11#include "cpu/lr35902/lr35902.h"
1112#include "machine/gb_slot.h"
1213#include "machine/ram.h"
14#include "video/gb_lcd.h"
1315
1416/* Interrupts */
1517#define VBL_INT               0       /* V-Blank    */
r23902r23903
3840#define MAX_RAMBANK 256
3941
4042
41#define _NR_GB_VID_REGS     0x40
4243
43
44
45
4644class gb_state : public driver_device
4745{
4846public:
r23902r23903
165163};
166164
167165
168/*----------- defined in machine/gb.c -----------*/
169166
170/* -- Super Game Boy specific -- */
171#define SGB_BORDER_PAL_OFFSET   64  /* Border colours stored from pal 4-7   */
172#define SGB_XOFFSET             48  /* GB screen starts at column 48        */
173#define SGB_YOFFSET             40  /* GB screen starts at row 40           */
174
175
176/*----------- defined in video/gb.c -----------*/
177
178enum
179{
180   GB_VIDEO_DMG = 1,
181   GB_VIDEO_MGB,
182   GB_VIDEO_SGB,
183   GB_VIDEO_CGB
184};
185
186
187struct layer_struct {
188   UINT8  enabled;
189   UINT8  *bg_tiles;
190   UINT8  *bg_map;
191   UINT8  xindex;
192   UINT8  xshift;
193   UINT8  xstart;
194   UINT8  xend;
195   /* GBC specific */
196   UINT8  *gbc_map;
197   INT16  bgline;
198};
199
200
201class gb_lcd_device : public device_t
202{
203public:
204   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);
205   gb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
206
207   
208   UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
209
210   DECLARE_READ8_MEMBER(vram_r);
211   DECLARE_WRITE8_MEMBER(vram_w);
212   DECLARE_READ8_MEMBER(oam_r);
213   DECLARE_WRITE8_MEMBER(oam_w);
214   virtual DECLARE_READ8_MEMBER(video_r);
215   virtual DECLARE_WRITE8_MEMBER(video_w);
216
217   // FIXME: remove it when proper sgb support is added
218   void set_sgb_hack(bool val) { m_sgb_border_hack = val ? 1 : 0; }
219   
220protected:
221   inline void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color);
222   
223   void select_sprites();
224   virtual void update_sprites();
225   virtual void update_scanline();
226
227   // device-level overrides
228   virtual void device_start();
229   virtual void device_reset();
230   void common_start();
231   void common_reset();
232
233   // pointer to the main system
234   cpu_device *m_maincpu;
235   screen_device *m_screen;
236   
237   // state variables
238   bitmap_ind16 m_bitmap;
239
240   UINT8 m_sgb_atf_data[4050];       /* (SGB) Attributes files */
241   UINT32 m_sgb_atf;
242   UINT16 m_sgb_pal_data[4096];
243   UINT8 m_sgb_pal_map[20][18];
244   UINT16 m_sgb_pal[128];
245   UINT8 *m_sgb_tile_data;
246   UINT8 m_sgb_tile_map[2048];
247   UINT8 m_sgb_window_mask;
248   
249   // this is temporarily needed for a bunch of games which draw the border differently...
250   int m_sgb_border_hack;
251   
252   int m_window_lines_drawn;
253   
254   UINT8   m_vid_regs[_NR_GB_VID_REGS];
255   UINT8   m_bg_zbuf[160];
256   
257   UINT16  m_cgb_bpal[32];   /* CGB current background palette table */
258   UINT16  m_cgb_spal[32];   /* CGB current sprite palette table */
259   
260   UINT8   m_gb_bpal[4];     /* Background palette */
261   UINT8   m_gb_spal0[4];    /* Sprite 0 palette */
262   UINT8   m_gb_spal1[4];    /* Sprite 1 palette */
263   
264   /* Things used to render current line */
265   int m_current_line;       /* Current line */
266   int m_cmp_line;           /* Compare line */
267   int m_sprCount;           /* Number of sprites on current line */
268   int m_sprite[10];         /* References to sprites to draw on current line */
269   int m_previous_line;      /* Previous line we've drawn in */
270   int m_start_x;            /* Pixel to start drawing from (inclusive) */
271   int m_end_x;              /* Pixel to end drawing (exclusive) */
272   int m_mode;               /* Keep track of internal STAT mode */
273   int m_state;              /* Current state of the video state machine */
274   int m_lcd_irq_line;
275   int m_triggering_line_irq;
276   int m_line_irq;
277   int m_triggering_mode_irq;
278   int m_mode_irq;
279   int m_delayed_line_irq;
280   int m_sprite_cycles;
281   int m_scrollx_adjust;
282   int m_oam_locked;
283   int m_vram_locked;
284   int m_pal_locked;
285   int m_hdma_enabled;
286   int m_hdma_possible;
287   struct layer_struct m_layer[2];
288   emu_timer *m_lcd_timer;
289   int m_gbc_mode;
290   
291   UINT8   *m_vram;     // Pointer to VRAM
292   UINT8   *m_oam;      // Pointer to OAM memory
293   UINT8   m_gb_tile_no_mod;
294   UINT32  m_gb_chrgen_offs;     // GB Character generator
295   UINT32  m_gb_bgdtab_offs;     // GB Background character table
296   UINT32  m_gb_wndtab_offs;     // GB Window character table
297   UINT32  m_gbc_chrgen_offs;    // CGB Character generator
298   UINT32  m_gbc_bgdtab_offs;    // CGB Background character table
299   UINT32  m_gbc_wndtab_offs;    // CGB Window character table
300   int     m_vram_bank;
301
302   TIMER_CALLBACK_MEMBER(video_init_vbl);
303   virtual TIMER_CALLBACK_MEMBER(lcd_timer_proc);
304   virtual void videoptr_restore();
305   void save_gb_video();
306   void increment_scanline();
307   void lcd_switch_on();
308};
309
310
311class mgb_lcd_device : public gb_lcd_device
312{
313public:
314   mgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
315
316protected:
317   
318   // device-level overrides
319   virtual void device_start();
320   virtual void device_reset();
321};
322
323
324class sgb_lcd_device : public gb_lcd_device
325{
326public:
327   sgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
328   
329   void sgb_io_write_pal(int offs, UINT8 *data);
330
331protected:
332   
333   // device-level overrides
334   virtual void device_start();
335   virtual void device_reset();
336   
337   virtual void update_sprites();
338   virtual void update_scanline();
339   void refresh_border();
340};
341
342
343class cgb_lcd_device : public gb_lcd_device
344{
345public:
346   cgb_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
347   
348   virtual DECLARE_READ8_MEMBER(video_r);
349   virtual DECLARE_WRITE8_MEMBER(video_w);
350
351protected:
352   
353   // device-level overrides
354   virtual void device_start();
355   virtual void device_reset();
356   
357   virtual void update_sprites();
358   virtual void update_scanline();
359
360   virtual TIMER_CALLBACK_MEMBER(lcd_timer_proc);
361   virtual void videoptr_restore();
362   void hdma_trans(UINT16 length);
363};
364
365
366extern const device_type GB_LCD_DMG;
367extern const device_type GB_LCD_MGB;
368extern const device_type GB_LCD_SGB;
369extern const device_type GB_LCD_CGB;
370
371
372#define MCFG_GB_LCD_DMG_ADD(_tag ) \
373      MCFG_DEVICE_ADD( _tag, GB_LCD_DMG, 0 )
374
375#define MCFG_GB_LCD_MGB_ADD(_tag ) \
376      MCFG_DEVICE_ADD( _tag, GB_LCD_MGB, 0 )
377
378#define MCFG_GB_LCD_SGB_ADD(_tag ) \
379      MCFG_DEVICE_ADD( _tag, GB_LCD_SGB, 0 )
380
381#define MCFG_GB_LCD_CGB_ADD(_tag ) \
382      MCFG_DEVICE_ADD( _tag, GB_LCD_CGB, 0 )
383
384
385167#endif /* GB_H_ */
trunk/src/mess/mess.mak
r23902r23903
17191719   $(MESS_DRIVERS)/snes.o      \
17201720   $(MESS_DRIVERS)/n64.o       \
17211721   $(MESS_AUDIO)/gb.o          \
1722   $(MESS_VIDEO)/gb.o          \
1722   $(MESS_VIDEO)/gb_lcd.o      \
17231723   $(MESS_MACHINE)/gb.o        \
17241724   $(MESS_MACHINE)/gb_slot.o   \
17251725   $(MESS_MACHINE)/gb_rom.o    \
trunk/src/mess/drivers/gb.c
r23902r23903
441441***************************************************************************/
442442
443443#include "emu.h"
444#include "machine/ram.h"
445#include "cpu/lr35902/lr35902.h"
446#include "imagedev/cartslot.h"
447444#include "rendlay.h"
448#include "audio/gb.h"
449445#include "includes/gb.h"
450#include "machine/gb_slot.h"
451446#include "machine/gb_rom.h"
452447#include "machine/gb_mbc.h"
453448
r23902r23903
671666SLOT_INTERFACE_END
672667
673668
669
670static const unsigned char palette[] =
671{
672   /* Simple black and white palette */
673   /*  0xFF,0xFF,0xFF,
674    0xB0,0xB0,0xB0,
675    0x60,0x60,0x60,
676    0x00,0x00,0x00 */
677   
678   /* Possibly needs a little more green in it */
679   0xFF,0xFB,0x87,     /* Background */
680   0xB1,0xAE,0x4E,     /* Light */
681   0x84,0x80,0x4E,     /* Medium */
682   0x4E,0x4E,0x4E,     /* Dark */
683   
684   /* Palette for Game Boy Pocket/Light */
685   0xC4,0xCF,0xA1,     /* Background */
686   0x8B,0x95,0x6D,     /* Light      */
687   0x6B,0x73,0x53,     /* Medium     */
688   0x41,0x41,0x41,     /* Dark       */
689};
690
691static const unsigned char palette_megaduck[] = {
692   0x6B, 0xA6, 0x4A, 0x43, 0x7A, 0x63, 0x25, 0x59, 0x55, 0x12, 0x42, 0x4C
693};
694
695/* Initialise the palettes */
696PALETTE_INIT_MEMBER(gb_state, gb)
697{
698   for (int i = 0; i < 4; i++)
699      palette_set_color_rgb(machine(), i, palette[i * 3 + 0], palette[i * 3 + 1], palette[i * 3 + 2]);
700}
701
702PALETTE_INIT_MEMBER(gb_state, gbp)
703{
704   for (int i = 0; i < 4; i++)
705      palette_set_color_rgb(machine(), i, palette[(i + 4) * 3 + 0], palette[(i + 4) * 3 + 1], palette[(i + 4) * 3 + 2]);
706}
707
708PALETTE_INIT_MEMBER(gb_state, sgb)
709{
710   int r, g, b;
711   
712   for (int i = 0; i < 32768; i++)
713   {
714      r = (i & 0x1F) << 3;
715      g = ((i >> 5) & 0x1F) << 3;
716      b = ((i >> 10) & 0x1F) << 3;
717      palette_set_color_rgb(machine(), i, r, g, b);
718   }
719}
720
721PALETTE_INIT_MEMBER(gb_state, gbc)
722{
723   int r, g, b;
724   
725   for (int i = 0; i < 32768; i++)
726   {
727      r = (i & 0x1F) << 3;
728      g = ((i >> 5) & 0x1F) << 3;
729      b = ((i >> 10) & 0x1F) << 3;
730      palette_set_color_rgb(machine(), i, r, g, b);
731   }
732}
733
734PALETTE_INIT_MEMBER(megaduck_state, megaduck)
735{
736   for (int i = 0; i < 4; i++)
737      palette_set_color_rgb(machine(), i, palette_megaduck[i * 3 + 0], palette_megaduck[i * 3 + 1], palette_megaduck[i * 3 + 2]);
738}
739
740
674741static MACHINE_CONFIG_START( gameboy, gb_state )
675742   /* basic machine hardware */
676743   MCFG_CPU_ADD("maincpu", LR35902, 4194304)           /* 4.194304 MHz */
trunk/src/mess/machine/gb.c
r23902r23903
8181#define __MACHINE_GB_C
8282
8383#include "emu.h"
84#include "cpu/lr35902/lr35902.h"
85#include "imagedev/cartslot.h"
86#include "machine/ram.h"
87#include "audio/gb.h"
8884#include "includes/gb.h"
8985
9086
r23902r23903
571567      if ( TIMECNT == 0 )
572568      {
573569         TIMECNT = TIMEMOD;
574         m_maincpu->set_input_line(TIM_INT, ASSERT_LINE );
570         m_maincpu->set_input_line(TIM_INT, ASSERT_LINE);
575571         m_reloading = 1;
576572      }
577573   }

Previous 199869 Revisions Next


© 1997-2024 The MAME Team