1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz, David Haywood
3 /*****************************************************************************
4 
5     SunPlus GCM394-series SoC peripheral emulation (Video)
6 
7     This is very similar to spg2xx but with additional features, layers and modes
8 
9 **********************************************************************/
10 
11 
12 #include "emu.h"
13 #include "generalplus_gpl16250soc_video.h"
14 
15 DEFINE_DEVICE_TYPE(GCM394_VIDEO, gcm394_video_device, "gcm394_video", "GeneralPlus GPL16250 System-on-a-Chip (Video)")
16 
17 #define LOG_GCM394_VIDEO_PALETTE  (1U << 5)
18 #define LOG_GCM394_VIDEO_DMA      (1U << 4)
19 #define LOG_GCM394_TMAP_EXTRA     (1U << 3)
20 #define LOG_GCM394_TMAP           (1U << 2)
21 #define LOG_GCM394_VIDEO          (1U << 1)
22 
23 #define VERBOSE             (LOG_GCM394_TMAP | LOG_GCM394_VIDEO_DMA | LOG_GCM394_VIDEO |LOG_GCM394_VIDEO_PALETTE)
24 
25 #include "logmacro.h"
26 
27 
gcm394_base_video_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)28 gcm394_base_video_device::gcm394_base_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
29 	device_t(mconfig, type, tag, owner, clock),
30 	device_video_interface(mconfig, *this),
31 	m_cpu(*this, finder_base::DUMMY_TAG),
32 	m_screen(*this, finder_base::DUMMY_TAG),
33 	m_video_irq_cb(*this),
34 	m_palette(*this, "palette"),
35 	m_gfxdecode(*this, "gfxdecode"),
36 	m_space_read_cb(*this),
37 	m_rowscroll(*this, "^rowscroll"),
38 	m_rowzoom(*this, "^rowzoom"),
39 	m_alt_extrasprite_hack(0),
40 	m_alt_tile_addressing(0),
41 	m_renderer(*this, "renderer")
42 {
43 }
44 
gcm394_video_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)45 gcm394_video_device::gcm394_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
46 	: gcm394_base_video_device(mconfig, GCM394_VIDEO, tag, owner, clock)
47 {
48 }
49 
decodegfx(const char * tag)50 void gcm394_base_video_device::decodegfx(const char* tag)
51 {
52 	if (!memregion(tag))
53 		return;
54 
55 	uint8_t* gfxregion = memregion(tag)->base();
56 	int gfxregionsize = memregion(tag)->bytes();
57 
58 	if (1)
59 	{
60 		gfx_layout obj_layout =
61 		{
62 			16,16,
63 			0,
64 			4,
65 			{ STEP4(0,1) },
66 			{ STEP16(0,4) },
67 			{ STEP16(0,4 * 16) },
68 			16 * 16 * 4
69 		};
70 		obj_layout.total = gfxregionsize / (16 * 16 * 4 / 8);
71 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x10 * 0x10, 0));
72 		m_maxgfxelement++;
73 	}
74 
75 	if (1)
76 	{
77 		gfx_layout obj_layout =
78 		{
79 			32,16,
80 			0,
81 			4,
82 			{ STEP4(0,1) },
83 			{ STEP32(0,4) },
84 			{ STEP16(0,4 * 32) },
85 			16 * 32 * 4
86 		};
87 		obj_layout.total = gfxregionsize / (16 * 32 * 4 / 8);
88 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x10 * 0x10, 0));
89 		m_maxgfxelement++;
90 	}
91 
92 	if (1)
93 	{
94 		gfx_layout obj_layout =
95 		{
96 			16,32,
97 			0,
98 			4,
99 			{ STEP4(0,1) },
100 			{ STEP16(0,4) },
101 			{ STEP32(0,4 * 16) },
102 			32 * 16 * 4
103 		};
104 		obj_layout.total = gfxregionsize / (32 * 16 * 4 / 8);
105 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x10 * 0x10, 0));
106 		m_maxgfxelement++;
107 	}
108 
109 	if (1)
110 	{
111 		gfx_layout obj_layout =
112 		{
113 			32,32,
114 			0,
115 			4,
116 			{ STEP4(0,1) },
117 			{ STEP32(0,4) },
118 			{ STEP32(0,4 * 32) },
119 			32 * 32 * 4
120 		};
121 		obj_layout.total = gfxregionsize / (32 * 32 * 4 / 8);
122 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x10 * 0x10, 0));
123 		m_maxgfxelement++;
124 	}
125 
126 	if (1)
127 	{
128 		gfx_layout obj_layout =
129 		{
130 			8,16,
131 			0,
132 			2,
133 			{ 0,1 },
134 			{ STEP8(0,2) },
135 			{ STEP16(0,2 * 8) },
136 			8 * 16 * 2
137 		};
138 		obj_layout.total = gfxregionsize / (8 * 16 * 2 / 8);
139 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x40 * 0x10, 0));
140 		m_maxgfxelement++;
141 	}
142 
143 	if (1)
144 	{
145 		const uint32_t texlayout_xoffset[64] = { STEP64(0,2) };
146 		const uint32_t texlayout_yoffset[32] = { STEP32(0,2 * 64) };
147 
148 		gfx_layout obj_layout =
149 		{
150 			64,32,
151 			0,
152 			2,
153 			{ 0,1 },
154 			EXTENDED_XOFFS,
155 			EXTENDED_YOFFS,
156 			32 * 64 * 2,
157 			texlayout_xoffset,
158 			texlayout_yoffset
159 		};
160 		obj_layout.total = gfxregionsize / (16 * 32 * 2 / 8);
161 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x40 * 0x10, 0));
162 		m_maxgfxelement++;
163 	}
164 
165 	if (1)
166 	{
167 		gfx_layout obj_layout =
168 		{
169 			32,32,
170 			0,
171 			8,
172 			{ STEP8(0,1) },
173 			{ STEP32(0,8) },
174 			{ STEP32(0,8 * 32) },
175 			32 * 32 * 8
176 		};
177 		obj_layout.total = gfxregionsize / (32 * 32 * 8 / 8);
178 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x10, 0));
179 		m_maxgfxelement++;
180 	}
181 
182 	if (1)
183 	{
184 		gfx_layout obj_layout =
185 		{
186 			32,32,
187 			0,
188 			6,
189 			{ 0,1,2,3,4,5 },
190 			{ STEP32(0,6) },
191 			{ STEP32(0,6 * 32) },
192 			32 * 32 * 6
193 		};
194 		obj_layout.total = gfxregionsize / (32 * 32 * 6 / 8);
195 		m_gfxdecode->set_gfx(m_maxgfxelement, std::make_unique<gfx_element>(m_palette, obj_layout, gfxregion, 0, 0x40, 0));
196 		m_maxgfxelement++;
197 	}
198 }
199 
device_start()200 void gcm394_base_video_device::device_start()
201 {
202 	m_video_irq_cb.resolve();
203 
204 	m_maxgfxelement = 0;
205 
206 	// debug helper only
207 	if (memregion(":maincpu"))
208 		decodegfx(":maincpu");
209 
210 	m_space_read_cb.resolve_safe(0);
211 
212 	m_screenpos_timer = timer_alloc(TIMER_SCREENPOS);
213 	m_screenpos_timer->adjust(attotime::never);
214 
215 	save_item(NAME(m_page0_addr_lsb));
216 	save_item(NAME(m_page0_addr_msb));
217 	save_item(NAME(m_page1_addr_lsb));
218 	save_item(NAME(m_page1_addr_msb));
219 	save_item(NAME(m_707e_spritebank));
220 	save_item(NAME(m_videodma_size));
221 	save_item(NAME(m_videodma_dest));
222 	save_item(NAME(m_videodma_source));
223 	save_item(NAME(m_tmap0_regs));
224 	save_item(NAME(m_tmap1_regs));
225 	save_item(NAME(m_tmap2_regs));
226 	save_item(NAME(m_tmap3_regs));
227 	save_item(NAME(m_tmap0_scroll));
228 	save_item(NAME(m_tmap1_scroll));
229 	save_item(NAME(m_tmap2_scroll));
230 	save_item(NAME(m_tmap3_scroll));
231 	save_item(NAME(m_707f));
232 	save_item(NAME(m_703a_palettebank));
233 	save_item(NAME(m_video_irq_enable));
234 	save_item(NAME(m_video_irq_status));
235 	save_item(NAME(m_702a));
236 	save_item(NAME(m_7030_brightness));
237 	save_item(NAME(m_xirqpos));
238 	save_item(NAME(m_yirqpos));
239 	save_item(NAME(m_703c_tvcontrol1));
240 	save_item(NAME(m_7042_sprite));
241 	save_item(NAME(m_7080));
242 	save_item(NAME(m_7081));
243 	save_item(NAME(m_7082));
244 	save_item(NAME(m_7083));
245 	save_item(NAME(m_7084));
246 	save_item(NAME(m_7085));
247 	save_item(NAME(m_7086));
248 	save_item(NAME(m_7087));
249 	save_item(NAME(m_7088));
250 	save_item(NAME(m_sprite_7022_gfxbase_lsb));
251 	save_item(NAME(m_sprite_702d_gfxbase_msb));
252 	save_item(NAME(m_page2_addr_lsb));
253 	save_item(NAME(m_page2_addr_msb));
254 	save_item(NAME(m_page3_addr_lsb));
255 	save_item(NAME(m_page3_addr_msb));
256 	save_item(NAME(m_spriteram));
257 	save_item(NAME(m_paletteram));
258 	save_item(NAME(m_maxgfxelement));
259 	save_item(NAME(m_alt_tile_addressing));
260 }
261 
device_reset()262 void gcm394_base_video_device::device_reset()
263 {
264 	for (int i = 0; i < 4; i++)
265 	{
266 		m_tmap0_regs[i] = 0x0000;
267 		m_tmap1_regs[i] = 0x0000;
268 		m_tmap2_regs[i] = 0x0000;
269 		m_tmap3_regs[i] = 0x0000;
270 		m_tmap2_scroll[i] = 0x0000;
271 		m_tmap3_scroll[i] = 0x0000;
272 	}
273 
274 	for (int i = 0; i < 2; i++)
275 	{
276 		m_tmap0_scroll[i] = 0x0000;
277 		m_tmap1_scroll[i] = 0x0000;
278 	}
279 
280 	for (int i = 0; i < 0x400*2; i++)
281 	{
282 		m_spriteram[i] = 0x0000;
283 	}
284 
285 	for (int i=0;i<0x100 * 0x10;i++)
286 		m_paletteram[i] = machine().rand()&0x7fff;
287 
288 	m_707f = 0x0000;
289 	m_703a_palettebank = 0x0000;
290 	m_video_irq_enable = 0x0000;
291 	m_video_irq_status = 0x0000;
292 
293 	m_702a = 0x0000;
294 	m_7030_brightness = 0x0000;
295 	m_xirqpos = 0x0000;
296 	m_yirqpos = 0x0000;
297 	m_703c_tvcontrol1 = 0x0000;
298 
299 	m_7042_sprite = 0x0000;
300 
301 	m_7080 = 0x0000;
302 	m_7081 = 0x0000;
303 	m_7082 = 0x0000;
304 	m_7083 = 0x0000;
305 	m_7084 = 0x0000;
306 	m_7085 = 0x0000;
307 	m_7086 = 0x0000;
308 	m_7087 = 0x0000;
309 	m_7088 = 0x0000;
310 
311 	m_707e_spritebank = 0x0000;
312 	m_videodma_size = 0x0000;
313 	m_videodma_dest = 0x0000;
314 	m_videodma_source = 0x0000;
315 
316 	m_sprite_7022_gfxbase_lsb = 0;
317 	m_sprite_702d_gfxbase_msb = 0;
318 	m_page2_addr_lsb = 0;
319 	m_page2_addr_msb = 0;
320 	m_page3_addr_lsb = 0;
321 	m_page3_addr_msb = 0;
322 
323 	m_renderer->set_video_spaces(m_cpuspace, m_cs_space, m_csbase);
324 }
325 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)326 uint32_t gcm394_base_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
327 {
328 	// For jak_car2 and jak_gtg the palette entry for 'magenta' in the test mode is intentionally set to a transparent black pen
329 	// (it is stored in the palette table in ROM that way, and copied directly) so the only way for the magenta entries on the screen
330 	// to be correctly displayed is if there is a magenta BG pen to fall through to (or for another palette write to change the palette
331 	// that is copied, but this does not appear to be the case).  How the bg pen is set is unknown, it is not a regular palette entry.
332 	// The 'bitmap test mode' in jak_car2 requires this to be black instead.
333 
334 	// jak_s500 briely sets pen 0 of the layer to magenta, but then ends up erasing it
335 
336 	const uint32_t page0_addr = (m_page0_addr_msb << 16) | m_page0_addr_lsb;
337 	const uint32_t page1_addr = (m_page1_addr_msb << 16) | m_page1_addr_lsb;
338 	const uint32_t page2_addr = (m_page2_addr_msb << 16) | m_page2_addr_lsb;
339 	const uint32_t page3_addr = (m_page3_addr_msb << 16) | m_page3_addr_lsb;
340 
341 
342 	if (0)
343 	{
344 		uint16_t attr0 = m_tmap0_regs[0];
345 		uint16_t attr1 = m_tmap1_regs[0];
346 		uint16_t attr2 = m_tmap2_regs[0];
347 		uint16_t attr3 = m_tmap3_regs[0];
348 		uint16_t ctrl0 = m_tmap0_regs[1];
349 		uint16_t ctrl1 = m_tmap1_regs[1];
350 		uint16_t ctrl2 = m_tmap2_regs[1];
351 		uint16_t ctrl3 = m_tmap3_regs[1];
352 
353 		popmessage(
354 			"p0ct u:%02x Bl:%d HC:%d Ycmp:%d Hcmp:%d RS:%d E:%d WP:%d Rg:%d Bm:%d gfxadr: %08x t:%04x p:%04x\n"
355 			"p1ct u:%02x Bl:%d HC:%d Ycmp:%d Hcmp:%d RS:%d E:%d WP:%d Rg:%d Bm:%d gfxadr: %08x t:%04x p:%04x\n"
356 			"p2ct u:%02x Bl:%d HC:%d Ycmp:%d Hcmp:%d RS:%d E:%d WP:%d Rg:%d Bm:%d gfxadr: %08x t:%04x p:%04x\n"
357 			"p3ct u:%02x Bl:%d HC:%d Ycmp:%d Hcmp:%d RS:%d E:%d WP:%d Rg:%d Bm:%d gfxadr: %08x t:%04x p:%04x\n"
358 			"p0attr dw:%01x dh:%01x Z:%d P:%d V:%d H:%d FY:%d FX:%d D:%d xs: %04x ys %04x\n"
359 			"p1attr dw:%01x dh:%01x Z:%d P:%d V:%d H:%d FY:%d FX:%d D:%d xs: %04x ys %04x\n"
360 			"p2attr dw:%01x dh:%01x Z:%d P:%d V:%d H:%d FY:%d FX:%d D:%d xs: %04x ys %04x\n"
361 			"p3attr dw:%01x dh:%01x Z:%d P:%d V:%d H:%d FY:%d FX:%d D:%d xs: %04x ys %04x\n"
362 			"palbank %04x 707e: %04x 707f: %04x tvc703c: %04x spr7042: %04x\n",
363 			(ctrl0 & 0xfe00) >> 9, BIT(ctrl0, 8), BIT(ctrl0, 7), BIT(ctrl0, 6), BIT(ctrl0, 5), BIT(ctrl0, 4), BIT(ctrl0, 3), BIT(ctrl0, 2), BIT(ctrl0, 1), BIT(ctrl0, 0), page0_addr, m_tmap0_regs[2], m_tmap0_regs[3],
364 			(ctrl1 & 0xfe00) >> 9, BIT(ctrl1, 8), BIT(ctrl1, 7), BIT(ctrl1, 6), BIT(ctrl1, 5), BIT(ctrl1, 4), BIT(ctrl1, 3), BIT(ctrl1, 2), BIT(ctrl1, 1), BIT(ctrl1, 0), page1_addr, m_tmap1_regs[2], m_tmap1_regs[3],
365 			(ctrl2 & 0xfe00) >> 9, BIT(ctrl2, 8), BIT(ctrl2, 7), BIT(ctrl2, 6), BIT(ctrl2, 5), BIT(ctrl2, 4), BIT(ctrl2, 3), BIT(ctrl2, 2), BIT(ctrl2, 1), BIT(ctrl2, 0), page2_addr, m_tmap2_regs[2], m_tmap2_regs[3],
366 			(ctrl3 & 0xfe00) >> 9, BIT(ctrl3, 8), BIT(ctrl3, 7), BIT(ctrl3, 6), BIT(ctrl3, 5), BIT(ctrl3, 4), BIT(ctrl3, 3), BIT(ctrl3, 2), BIT(ctrl3, 1), BIT(ctrl3, 0), page3_addr, m_tmap3_regs[2], m_tmap3_regs[3],
367 			BIT(attr0, 15), BIT(attr0, 14), (attr0 >> 12) & 3, (attr0 >> 8) & 15, 8 << ((attr0 >> 6) & 3), 8 << ((attr0 >> 4) & 3), BIT(attr0, 3), BIT(attr0, 2), 2 * ((attr0 & 3) + 1), m_tmap0_scroll[0], m_tmap0_scroll[1],
368 			BIT(attr1, 15), BIT(attr1, 14), (attr1 >> 12) & 3, (attr1 >> 8) & 15, 8 << ((attr1 >> 6) & 3), 8 << ((attr1 >> 4) & 3), BIT(attr1, 3), BIT(attr1, 2), 2 * ((attr1 & 3) + 1), m_tmap1_scroll[0], m_tmap1_scroll[1],
369 			BIT(attr2, 15), BIT(attr2, 14), (attr2 >> 12) & 3, (attr2 >> 8) & 15, 8 << ((attr2 >> 6) & 3), 8 << ((attr2 >> 4) & 3), BIT(attr2, 3), BIT(attr2, 2), 2 * ((attr2 & 3) + 1), m_tmap2_scroll[0], m_tmap2_scroll[1],
370 			BIT(attr3, 15), BIT(attr3, 14), (attr3 >> 12) & 3, (attr3 >> 8) & 15, 8 << ((attr3 >> 6) & 3), 8 << ((attr3 >> 4) & 3), BIT(attr3, 3), BIT(attr3, 2), 2 * ((attr3 & 3) + 1), m_tmap3_scroll[0], m_tmap3_scroll[1],
371 			m_703a_palettebank, m_707e_spritebank, m_707f, m_703c_tvcontrol1, m_7042_sprite
372 		);
373 	}
374 
375 	//const uint16_t bgcol = 0x7c1f; // magenta
376 //  const uint16_t bgcol = 0x0000; // black
377 	bool highres;
378 	if (m_707f & 0x0010)
379 	{
380 		highres = true;
381 		m_screen->set_visible_area(0, 640-1, 0, 480-1);
382 	}
383 	else
384 	{
385 		highres = false;
386 		m_screen->set_visible_area(0, 320-1, 0, 240-1);
387 	}
388 
389 	address_space &mem = m_cpu->space(AS_PROGRAM);
390 
391 
392 	const uint32_t sprites_addr = (m_sprite_702d_gfxbase_msb << 16) | m_sprite_7022_gfxbase_lsb;
393 
394 	for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++)
395 	{
396 		m_renderer->new_line(cliprect);
397 
398 		for (int i = 0; i < 4; i++)
399 		{
400 			m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, scanline, i, page0_addr, m_tmap0_scroll, m_tmap0_regs, mem, m_paletteram, m_rowscroll, 0);
401 			m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, scanline, i, page1_addr, m_tmap1_scroll, m_tmap1_regs, mem, m_paletteram, m_rowscroll, 1);
402 			m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, scanline, i, page2_addr, m_tmap2_scroll, m_tmap2_regs, mem, m_paletteram, m_rowscroll, 2);
403 			m_renderer->draw_page(true, true, m_alt_tile_addressing ? false : true, m_703a_palettebank, cliprect, scanline, i, page3_addr, m_tmap3_scroll, m_tmap3_regs, mem, m_paletteram, m_rowscroll, 3);
404 
405 			m_renderer->draw_sprites(true, true, m_alt_extrasprite_hack ? true : false, m_703a_palettebank, highres, cliprect, scanline, i, sprites_addr, mem, m_paletteram, m_spriteram, -1);
406 		}
407 
408 		m_renderer->apply_saturation_and_fade(bitmap, cliprect, scanline);
409 	}
410 
411 	return 0;
412 }
413 
414 
write_tmap_scroll(int tmap,uint16_t * regs,int offset,uint16_t data)415 void gcm394_base_video_device::write_tmap_scroll(int tmap, uint16_t* regs, int offset, uint16_t data)
416 {
417 	switch (offset)
418 	{
419 	case 0x0: // Page X scroll
420 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d X Scroll = %04x\n", machine().describe_context(), tmap, data);
421 		regs[offset] = data;
422 		break;
423 
424 	case 0x1: // Page Y scroll
425 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d Y Scroll = %04x\n", machine().describe_context(), tmap, data);
426 		regs[offset] = data;
427 		break;
428 	}
429 }
430 
write_tmap_regs(int tmap,uint16_t * regs,int offset,uint16_t data)431 void gcm394_base_video_device::write_tmap_regs(int tmap, uint16_t* regs, int offset, uint16_t data)
432 {
433 	switch (offset)
434 	{
435 	case 0x0: // Page Attributes
436 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d Attributes = %04x (unk %01x: Depth:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n",  machine().describe_context(), tmap, data,
437 			(data & 0xc000) >> 14, (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1));
438 		regs[offset] = data;
439 		break;
440 
441 	case 0x1: // Page Control
442 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d Control = %04x (unk:%02x Blend:%d, HiColor:%d, unk:%d, unk%d, RowScroll:%d, Enable:%d, Wallpaper:%d, RegSet:%d, Bitmap:%d)\n",  machine().describe_context(), tmap, data,
443 			(data & 0xfe00) >> 9, BIT(data, 8), BIT(data, 7), BIT(data, 6), BIT(data, 5), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
444 		regs[offset] = data;
445 		break;
446 
447 	case 0x2: // Page Tile Address
448 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d Tile Address = %04x\n",  machine().describe_context(), tmap, data);
449 		regs[offset] = data;
450 		break;
451 
452 	case 0x3: // Page Attribute Address
453 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d Attribute Address = %04x\n",  machine().describe_context(), tmap, data);
454 		regs[offset] = data;
455 		break;
456 	}
457 }
458 
459 
460 // offsets 0,1,4,5,6,7 used in main IRQ code
461 // offsets 2,3 only cleared on startup
462 
463 // Based on code analysis this seems to be the same as the regular tilemap regs, except for the addition of regs 2,3 which shift the remaining ones along.
464 // As the hardware appears to support ROZ these are probably 2 extra tile layers, with the 2 additional words being the ROZ parameters?
465 
466 
write_tmap_extrascroll(int tmap,uint16_t * regs,int offset,uint16_t data)467 void gcm394_base_video_device::write_tmap_extrascroll(int tmap, uint16_t* regs, int offset, uint16_t data)
468 {
469 	switch (offset)
470 	{
471 	case 0x0: // Page X scroll
472 	case 0x1: // Page Y scroll
473 		write_tmap_scroll(tmap, regs, offset, data);
474 		break;
475 
476 	case 0x2: //
477 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d X Unk Rotation Zoom Attribute1 = %04x\n", machine().describe_context(), tmap, data);
478 		regs[offset] = data;
479 		break;
480 
481 	case 0x3:
482 		LOGMASKED(LOG_GCM394_TMAP, "%s: write_tmap_regs: Page %d X Unk Rotation Zoom Attribute = %04x\n", machine().describe_context(), tmap, data);
483 		regs[offset] = data;
484 		break;
485 
486 	}
487 }
488 
489 
490 // **************************************** TILEMAP 0 *************************************************
491 
tmap0_regs_r(offs_t offset)492 uint16_t gcm394_base_video_device::tmap0_regs_r(offs_t offset)
493 {
494 	if (offset < 2)
495 	{
496 		return m_tmap0_scroll[offset];
497 	}
498 	else
499 	{
500 		return m_tmap0_regs[offset-2];
501 	}
502 }
503 
tmap0_regs_w(offs_t offset,uint16_t data)504 void gcm394_base_video_device::tmap0_regs_w(offs_t offset, uint16_t data)
505 {
506 	LOGMASKED(LOG_GCM394_TMAP_EXTRA, "%s:gcm394_base_video_device::tmap0_regs_w %01x %04x\n", machine().describe_context(), offset, data);
507 	if (offset < 2)
508 	{
509 		write_tmap_scroll(0, m_tmap0_scroll, offset, data);
510 	}
511 	else
512 	{
513 		write_tmap_regs(0, m_tmap0_regs, offset-2, data);
514 	}
515 }
516 
tmap0_tilebase_lsb_r()517 uint16_t gcm394_base_video_device::tmap0_tilebase_lsb_r()
518 {
519 	return m_page0_addr_lsb;
520 }
521 
tmap0_tilebase_lsb_w(uint16_t data)522 void gcm394_base_video_device::tmap0_tilebase_lsb_w(uint16_t data)
523 {
524 	LOGMASKED(LOG_GCM394_TMAP, "%s:gcm394_base_video_device::tmap0_tilebase_lsb_w %04x\n", machine().describe_context(), data);
525 	m_page0_addr_lsb = data;
526 	LOGMASKED(LOG_GCM394_TMAP, "\t(tmap0 tilegfxbase is now %04x%04x)\n", m_page0_addr_msb, m_page0_addr_lsb);
527 }
528 
tmap0_tilebase_msb_r()529 uint16_t gcm394_base_video_device::tmap0_tilebase_msb_r()
530 {
531 	return m_page0_addr_msb;
532 }
533 
tmap0_tilebase_msb_w(uint16_t data)534 void gcm394_base_video_device::tmap0_tilebase_msb_w(uint16_t data)
535 {
536 	LOGMASKED(LOG_GCM394_TMAP, "%s:gcm394_base_video_device::tmap0_tilebase_msb_w %04x\n", machine().describe_context(), data);
537 	m_page0_addr_msb = data;
538 	LOGMASKED(LOG_GCM394_TMAP, "\t(tmap0 tilegfxbase is now %04x%04x)\n", m_page0_addr_msb, m_page0_addr_lsb);
539 }
540 
541 // **************************************** TILEMAP 1 *************************************************
542 
543 
tmap1_regs_r(offs_t offset)544 uint16_t gcm394_base_video_device::tmap1_regs_r(offs_t offset)
545 {
546 	if (offset < 2)
547 	{
548 		return m_tmap1_scroll[offset];
549 	}
550 	else
551 	{
552 		return m_tmap1_regs[offset-2];
553 	}
554 }
555 
tmap1_regs_w(offs_t offset,uint16_t data)556 void gcm394_base_video_device::tmap1_regs_w(offs_t offset, uint16_t data)
557 {
558 	LOGMASKED(LOG_GCM394_TMAP_EXTRA, "%s:gcm394_base_video_device::tmap1_regs_w %01x %04x\n", machine().describe_context(), offset, data);
559 	if (offset < 2)
560 	{
561 		write_tmap_scroll(1, m_tmap1_scroll, offset, data);
562 	}
563 	else
564 	{
565 		write_tmap_regs(1, m_tmap1_regs, offset-2, data);
566 	}
567 }
568 
tmap1_tilebase_lsb_r()569 uint16_t gcm394_base_video_device::tmap1_tilebase_lsb_r()
570 {
571 	return m_page1_addr_lsb;
572 }
573 
tmap1_tilebase_lsb_w(uint16_t data)574 void gcm394_base_video_device::tmap1_tilebase_lsb_w(uint16_t data)
575 {
576 	LOGMASKED(LOG_GCM394_TMAP, "%s:gcm394_base_video_device::tmap1_tilebase_lsb_w %04x\n", machine().describe_context(), data);
577 	m_page1_addr_lsb = data;
578 	LOGMASKED(LOG_GCM394_TMAP, "\t(tmap1 tilegfxbase is now %04x%04x)\n", m_page1_addr_msb, m_page1_addr_lsb);
579 }
580 
tmap1_tilebase_msb_r()581 uint16_t gcm394_base_video_device::tmap1_tilebase_msb_r()
582 {
583 	return m_page1_addr_msb;
584 }
585 
tmap1_tilebase_msb_w(uint16_t data)586 void gcm394_base_video_device::tmap1_tilebase_msb_w(uint16_t data)
587 {
588 	LOGMASKED(LOG_GCM394_TMAP, "%s:gcm394_base_video_device::tmap1_tilebase_msb_w %04x\n", machine().describe_context(), data);
589 	m_page1_addr_msb = data;
590 	LOGMASKED(LOG_GCM394_TMAP, "\t(tmap1 tilegfxbase is now %04x%04x)\n", m_page1_addr_msb, m_page1_addr_lsb);
591 }
592 
593 // **************************************** unknown video device 1 (another tilemap? roz? line? zooming sprite layer?) *************************************************
594 
tmap2_regs_r(offs_t offset)595 uint16_t gcm394_base_video_device::tmap2_regs_r(offs_t offset)
596 {
597 	if (offset < 4)
598 	{
599 		return m_tmap2_scroll[offset];
600 	}
601 	else
602 	{
603 		return m_tmap2_regs[offset-4];
604 	}
605 }
606 
tmap2_regs_w(offs_t offset,uint16_t data)607 void gcm394_base_video_device::tmap2_regs_w(offs_t offset, uint16_t data)
608 {
609 	LOGMASKED(LOG_GCM394_TMAP_EXTRA, "%s:gcm394_base_video_device::tmap2_regs_w %01x %04x\n", machine().describe_context(), offset, data);
610 	if (offset < 4)
611 	{
612 		write_tmap_extrascroll(2, m_tmap2_scroll, offset, data);
613 	}
614 	else
615 	{
616 		write_tmap_regs(2, m_tmap2_regs, offset-4, data);
617 	}
618 }
619 
tmap2_tilebase_lsb_r()620 uint16_t gcm394_base_video_device::tmap2_tilebase_lsb_r()
621 {
622 	return m_page2_addr_lsb;
623 }
624 
625 
tmap2_tilebase_lsb_w(uint16_t data)626 void gcm394_base_video_device::tmap2_tilebase_lsb_w(uint16_t data)
627 {
628 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::tmap2_tilebase_lsb_w %04x\n", machine().describe_context(), data);
629 	m_page2_addr_lsb = data;
630 	LOGMASKED(LOG_GCM394_TMAP, "\t(unk_vid1 tilegfxbase is now %04x%04x)\n", m_page2_addr_msb, m_page2_addr_lsb);
631 }
632 
tmap2_tilebase_msb_r()633 uint16_t gcm394_base_video_device::tmap2_tilebase_msb_r()
634 {
635 	return m_page2_addr_msb;
636 }
637 
tmap2_tilebase_msb_w(uint16_t data)638 void gcm394_base_video_device::tmap2_tilebase_msb_w(uint16_t data)
639 {
640 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::tmap2_tilebase_msb_w %04x\n", machine().describe_context(), data);
641 	m_page2_addr_msb = data;
642 	LOGMASKED(LOG_GCM394_TMAP, "\t(unk_vid1 tilegfxbase is now %04x%04x)\n", m_page2_addr_msb, m_page2_addr_lsb);
643 }
644 
645 // **************************************** unknown video device 2 (another tilemap? roz? lines? zooming sprite layer?) *************************************************
646 
tmap3_regs_r(offs_t offset)647 uint16_t gcm394_base_video_device::tmap3_regs_r(offs_t offset)
648 {
649 	if (offset < 4)
650 	{
651 		return m_tmap3_scroll[offset];
652 	}
653 	else
654 	{
655 		return m_tmap3_regs[offset-4];
656 	}
657 }
658 
tmap3_regs_w(offs_t offset,uint16_t data)659 void gcm394_base_video_device::tmap3_regs_w(offs_t offset, uint16_t data)
660 {
661 	LOGMASKED(LOG_GCM394_TMAP_EXTRA, "%s:gcm394_base_video_device::tmap3_regs_w %01x %04x\n", machine().describe_context(), offset, data);
662 	if (offset < 4)
663 	{
664 		write_tmap_extrascroll(3, m_tmap3_scroll, offset, data);
665 	}
666 	else
667 	{
668 		write_tmap_regs(3, m_tmap3_regs, offset-4, data);
669 	}
670 }
671 
tmap3_tilebase_lsb_r()672 uint16_t gcm394_base_video_device::tmap3_tilebase_lsb_r()
673 {
674 	return m_page3_addr_lsb;
675 }
676 
677 
tmap3_tilebase_lsb_w(uint16_t data)678 void gcm394_base_video_device::tmap3_tilebase_lsb_w(uint16_t data)
679 {
680 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::tmap3_tilebase_lsb_w %04x\n", machine().describe_context(), data);
681 	m_page3_addr_lsb = data;
682 	LOGMASKED(LOG_GCM394_TMAP, "\t(unk_vid2 tilegfxbase is now %04x%04x)\n", m_page3_addr_msb, m_page3_addr_lsb);
683 }
684 
tmap3_tilebase_msb_r()685 uint16_t gcm394_base_video_device::tmap3_tilebase_msb_r()
686 {
687 	return m_page3_addr_msb;
688 }
689 
690 
tmap3_tilebase_msb_w(uint16_t data)691 void gcm394_base_video_device::tmap3_tilebase_msb_w(uint16_t data)
692 {
693 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::tmap3_tilebase_msb_w %04x\n", machine().describe_context(), data);
694 	m_page3_addr_msb = data;
695 	LOGMASKED(LOG_GCM394_TMAP, "\t(unk_vid2 tilegfxbase is now %04x%04x)\n", m_page3_addr_msb, m_page3_addr_lsb);
696 }
697 
698 // **************************************** sprite control registers *************************************************
699 
700 // set to 001264c0 in wrlshunt, which point at the menu selectors (game names, arrows etc.)
701 
sprite_7022_gfxbase_lsb_r()702 uint16_t gcm394_base_video_device::sprite_7022_gfxbase_lsb_r()
703 {
704 	return m_sprite_7022_gfxbase_lsb;
705 }
706 
sprite_7022_gfxbase_lsb_w(uint16_t data)707 void gcm394_base_video_device::sprite_7022_gfxbase_lsb_w(uint16_t data)
708 {
709 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::sprite_7022_gfxbase_lsb_w %04x\n", machine().describe_context(), data);
710 	m_sprite_7022_gfxbase_lsb = data;
711 	LOGMASKED(LOG_GCM394_TMAP, "\t(sprite tilebase is now %04x%04x)\n", m_sprite_702d_gfxbase_msb, m_sprite_7022_gfxbase_lsb);
712 }
713 
sprite_702d_gfxbase_msb_r()714 uint16_t gcm394_base_video_device::sprite_702d_gfxbase_msb_r()
715 {
716 	return m_sprite_702d_gfxbase_msb;
717 }
718 
sprite_702d_gfxbase_msb_w(uint16_t data)719 void gcm394_base_video_device::sprite_702d_gfxbase_msb_w(uint16_t data)
720 {
721 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::sprite_702d_gfxbase_msb_w %04x\n", machine().describe_context(), data);
722 	m_sprite_702d_gfxbase_msb = data;
723 	LOGMASKED(LOG_GCM394_TMAP, "\t(sprite tilebase tilegfxbase is now %04x%04x)\n", m_sprite_702d_gfxbase_msb, m_sprite_7022_gfxbase_lsb);
724 }
725 
sprite_7042_extra_r()726 uint16_t gcm394_base_video_device::sprite_7042_extra_r()
727 {
728 	uint16_t retdata = m_7042_sprite;
729 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::sprite_7042_extra_r (returning: %04x)\n", machine().describe_context(), retdata);
730 	return retdata;
731 }
732 
sprite_7042_extra_w(uint16_t data)733 void gcm394_base_video_device::sprite_7042_extra_w(uint16_t data)
734 {
735 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::sprite_7042_extra_w %04x\n", machine().describe_context(), data);
736 	m_7042_sprite = data;
737 	m_renderer->set_video_reg_42(data);
738 
739 	//popmessage("extra modes %04x\n", data);
740 }
741 
742 
743 // **************************************** video DMA device *************************************************
744 
video_dma_source_w(uint16_t data)745 void gcm394_base_video_device::video_dma_source_w(uint16_t data)
746 {
747 	LOGMASKED(LOG_GCM394_VIDEO_DMA, "%s:gcm394_base_video_device::video_dma_source_w %04x\n", machine().describe_context(), data);
748 	m_videodma_source = data;
749 }
750 
video_dma_dest_w(uint16_t data)751 void gcm394_base_video_device::video_dma_dest_w(uint16_t data)
752 {
753 	LOGMASKED(LOG_GCM394_VIDEO_DMA, "%s:gcm394_base_video_device::video_dma_dest_w %04x\n", machine().describe_context(), data);
754 	m_videodma_dest = data;
755 }
756 
video_dma_size_busy_r()757 uint16_t gcm394_base_video_device::video_dma_size_busy_r()
758 {
759 	LOGMASKED(LOG_GCM394_VIDEO_DMA, "%s:gcm394_base_video_device::video_dma_size_busy_r\n", machine().describe_context());
760 	return 0x0000;
761 }
762 
video_dma_size_trigger_w(address_space & space,uint16_t data)763 void gcm394_base_video_device::video_dma_size_trigger_w(address_space &space, uint16_t data)
764 {
765 	LOGMASKED(LOG_GCM394_VIDEO_DMA, "%s:gcm394_base_video_device::video_dma_size_trigger_w %04x\n", machine().describe_context(), data);
766 	m_videodma_size = data;
767 
768 	LOGMASKED(LOG_GCM394_VIDEO_DMA, "%s: doing sprite / video DMA source %04x dest %04x size %04x value of 707e (bank) %04x value of 707f %04x\n", machine().describe_context(), m_videodma_source, m_videodma_dest, m_videodma_size, m_707e_spritebank, m_707f );
769 
770 	for (int i = 0; i <= m_videodma_size; i++)
771 	{
772 		uint16_t dat = space.read_word(m_videodma_source+i);
773 		space.write_word(m_videodma_dest + i, dat);
774 	}
775 
776 	m_videodma_size = 0x0000;
777 
778 	if (m_video_irq_enable & 4)
779 	{
780 		const uint16_t old = m_video_irq_status;
781 		m_video_irq_status |= 4;
782 		const uint16_t changed = old ^ (m_video_irq_enable & m_video_irq_status);
783 		if (changed)
784 			check_video_irq();
785 	}
786 }
787 
video_707e_spritebank_w(uint16_t data)788 void gcm394_base_video_device::video_707e_spritebank_w(uint16_t data)
789 {
790 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_707e_spritebank_w %04x\n", machine().describe_context(), data);
791 	m_707e_spritebank = data;
792 }
793 
video_707c_r()794 uint16_t gcm394_base_video_device::video_707c_r()
795 {
796 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_707c_r\n", machine().describe_context());
797 	return 0x8000;
798 }
799 
800 /* 707f is VERY important, lots of rendering codepaths in the code depend on the value it returns.
801 
802    all operations in the code based on 707f are bit based, usually read register, set / clear a bit
803    and then write register, or read register and test an individual bit.
804 
805    our current codeflow means that bits are only ever set, not cleared.
806 
807    are the bits triggers? acks? enables? status flags?
808 
809    in wrlshunt this ends up being set to  02f9   ---- --x- xxxx x--x
810    and in smartfp it ends up being set to 0065   ---- ---- -xx- -x-x
811 
812    is this because wrlshunt uses more layers?
813 */
814 
815 
video_707f_r()816 uint16_t gcm394_base_video_device::video_707f_r()
817 {
818 	uint16_t retdata = m_renderer->get_video_reg_7f();
819 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_707f_r (returning %04x)\n", machine().describe_context(), retdata);
820 	return retdata;
821 }
video_707f_w(uint16_t data)822 void gcm394_base_video_device::video_707f_w(uint16_t data)
823 {
824 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_707f_w %04x\n", machine().describe_context(), data);
825 
826 	for (int i = 0; i < 16; i++)
827 	{
828 		uint16_t mask = 1 << i;
829 
830 		if ((m_707f & mask) != (data & mask))
831 		{
832 			if (data & mask)
833 			{
834 				LOGMASKED(LOG_GCM394_VIDEO, "\tbit %04x Low -> High\n", mask);
835 			}
836 			else
837 			{
838 				LOGMASKED(LOG_GCM394_VIDEO, "\tbit %04x High -> Low\n", mask);
839 			}
840 		}
841 	}
842 
843 	m_707f = data;
844 	m_renderer->set_video_reg_7f(data);
845 	//popmessage("707f is %04x\n", data);
846 }
847 
video_703a_palettebank_r()848 uint16_t gcm394_base_video_device::video_703a_palettebank_r()
849 {
850 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703a_palettebank_r\n", machine().describe_context());
851 	return m_703a_palettebank;
852 }
853 
video_703a_palettebank_w(uint16_t data)854 void gcm394_base_video_device::video_703a_palettebank_w(uint16_t data)
855 {
856 	// I don't think bit 0 (0x01) is a bank select, it might be a 'mode select' for how the palette operates.
857 	// neither lazertag or tkmag220 set it
858 	// lazertag uses 2 banks (0 and 8)
859 	// tkmag220 only uses 1 bank (0)
860 
861 	// ---- bb-s
862 	// bb = write bank?
863 	// s = sprite palette bank select?
864 
865 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703a_palettebank_w %04x\n", machine().describe_context(), data);
866 	m_703a_palettebank = data;
867 }
868 
videoirq_source_enable_r()869 uint16_t gcm394_base_video_device::videoirq_source_enable_r()
870 {
871 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::videoirq_source_enable_r\n", machine().describe_context());
872 	return m_video_irq_enable;
873 }
874 
videoirq_source_enable_w(uint16_t data)875 void gcm394_base_video_device::videoirq_source_enable_w(uint16_t data)
876 {
877 	LOGMASKED(LOG_GCM394_VIDEO, "videoirq_source_enable_w: Video IRQ Enable = %04x (DMA:%d, Timing:%d, Blanking:%d)\n", data, BIT(data, 2), BIT(data, 1), BIT(data, 0));
878 	const uint16_t old = m_video_irq_enable & m_video_irq_status;
879 	m_video_irq_enable = data & 0x0007;
880 	const uint16_t changed = old ^ (m_video_irq_enable & m_video_irq_status);
881 	if (changed)
882 		check_video_irq();
883 }
884 
video_7063_videoirq_source_r()885 uint16_t gcm394_base_video_device::video_7063_videoirq_source_r()
886 {
887 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7063_videoirq_source_r\n", machine().describe_context());
888 	return m_video_irq_status;
889 }
890 
891 
video_7063_videoirq_source_ack_w(uint16_t data)892 void gcm394_base_video_device::video_7063_videoirq_source_ack_w(uint16_t data)
893 {
894 	LOGMASKED(LOG_GCM394_VIDEO, "video_7063_videoirq_source_ack_w: Video IRQ Acknowledge = %04x\n", data);
895 	const uint16_t old = m_video_irq_enable & m_video_irq_status;
896 	m_video_irq_status &= ~data;
897 	const uint16_t changed = old ^ (m_video_irq_enable & m_video_irq_status);
898 	if (changed)
899 		check_video_irq();
900 }
901 
video_702a_w(uint16_t data)902 void gcm394_base_video_device::video_702a_w(uint16_t data)
903 {
904 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_702a_w %04x\n", machine().describe_context(), data);
905 	m_702a = data;
906 	m_renderer->set_video_reg_2a(data);
907 }
908 
video_curline_r()909 uint16_t gcm394_base_video_device::video_curline_r()
910 {
911 	LOGMASKED(LOG_GCM394_VIDEO, "%s: video_r: Current Line: %04x\n", machine().describe_context(), m_screen->vpos());
912 	return m_screen->vpos();
913 }
914 
915 // read in IRQ
video_7030_brightness_r()916 uint16_t gcm394_base_video_device::video_7030_brightness_r()
917 {
918 	/* wrlshunt ends up doing an explicit jump to 0000 shortly after boot if you just return the value written here, however I think that is correct code flow and something else is wrong
919 	   as this simply looks like some kind of brightness register - there is code to decrease it from 0xff to 0x00 by 0x5 increments (waiting for it to hit 0x05) and code to do the reverse
920 	   either way it really looks like the data written should be read back.
921 	*/
922 	uint16_t retdat = m_7030_brightness;
923 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7030_brightness_r (returning %04x)\n", machine().describe_context(), retdat);
924 	return retdat;
925 }
926 
video_7030_brightness_w(uint16_t data)927 void gcm394_base_video_device::video_7030_brightness_w(uint16_t data)
928 {
929 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7030_brightness_w %04x\n", machine().describe_context(), data);
930 	m_7030_brightness = data;
931 	m_renderer->set_video_reg_30(data);
932 }
933 
update_raster_split_position()934 void gcm394_base_video_device::update_raster_split_position()
935 {
936 	// this might need updating to handle higher res modes
937 	LOGMASKED(LOG_GCM394_VIDEO, "update_raster_split_position: %04x,%04x\n", m_yirqpos, m_xirqpos);
938 	if (m_xirqpos < 300 && m_yirqpos < 256)
939 	{
940 		// where does -19 come from? needed for raster on paccon xevious to fire at correct line for bg scrolling to be seamless
941 		m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos-19, m_xirqpos));
942 		//printf("setting irq timer for y:%d x:%d", m_yirqpos, m_xirqpos);
943 	}
944 	else
945 		m_screenpos_timer->adjust(attotime::never);
946 }
947 
split_irq_ypos_w(uint16_t data)948 void gcm394_base_video_device::split_irq_ypos_w(uint16_t data)
949 {
950 	LOGMASKED(LOG_GCM394_VIDEO, "%s:split_irq_ypos_w %04x\n", machine().describe_context(), data);
951 
952 	m_yirqpos = data & 0x1ff;
953 	update_raster_split_position();
954 }
955 
split_irq_xpos_w(uint16_t data)956 void gcm394_base_video_device::split_irq_xpos_w(uint16_t data)
957 {
958 	LOGMASKED(LOG_GCM394_VIDEO, "%s:split_irq_xpos_w %04x\n", machine().describe_context(), data);
959 
960 	m_xirqpos = data & 0x1ff;
961 	update_raster_split_position();
962 }
963 
video_703c_tvcontrol1_r()964 uint16_t gcm394_base_video_device::video_703c_tvcontrol1_r()
965 {
966 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703c_tvcontrol1_r\n", machine().describe_context());
967 	return m_703c_tvcontrol1;
968 }
969 
video_703c_tvcontrol1_w(uint16_t data)970 void gcm394_base_video_device::video_703c_tvcontrol1_w(uint16_t data)
971 {
972 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_703c_tvcontrol1_w %04x\n", machine().describe_context(), data);
973 	m_703c_tvcontrol1 = data;
974 	m_renderer->set_video_reg_3c(data);
975 }
976 
video_7051_r()977 uint16_t gcm394_base_video_device::video_7051_r()
978 {
979 	/* related to what ends up crashing wrlshunt? */
980 	uint16_t retdat = 0x03ff;
981 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7051_r (returning %04x)\n", machine().describe_context(), retdat);
982 	return retdat;
983 }
984 
video_70e0_r()985 uint16_t gcm394_base_video_device::video_70e0_r()
986 {
987 	uint16_t retdat = machine().rand();
988 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_70e0_r (returning %04x)\n", machine().describe_context(), retdat);
989 	return retdat;
990 }
991 
992 
993 // this block get set once, in a single function, could be important
video_7080_w(uint16_t data)994 void gcm394_base_video_device::video_7080_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7080_w %04x\n", machine().describe_context(), data); m_7080 = data; }
video_7081_w(uint16_t data)995 void gcm394_base_video_device::video_7081_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7081_w %04x\n", machine().describe_context(), data); m_7081 = data; }
video_7082_w(uint16_t data)996 void gcm394_base_video_device::video_7082_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7082_w %04x\n", machine().describe_context(), data); m_7082 = data; }
video_7083_w(uint16_t data)997 void gcm394_base_video_device::video_7083_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7083_w %04x\n", machine().describe_context(), data); m_7083 = data; }
video_7084_w(uint16_t data)998 void gcm394_base_video_device::video_7084_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7084_w %04x\n", machine().describe_context(), data); m_7084 = data; }
video_7085_w(uint16_t data)999 void gcm394_base_video_device::video_7085_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7085_w %04x\n", machine().describe_context(), data); m_7085 = data; }
video_7086_w(uint16_t data)1000 void gcm394_base_video_device::video_7086_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7086_w %04x\n", machine().describe_context(), data); m_7086 = data; }
video_7087_w(uint16_t data)1001 void gcm394_base_video_device::video_7087_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7087_w %04x\n", machine().describe_context(), data); m_7087 = data; }
video_7088_w(uint16_t data)1002 void gcm394_base_video_device::video_7088_w(uint16_t data) { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7088_w %04x\n", machine().describe_context(), data); m_7088 = data; }
1003 
video_7083_r()1004 uint16_t gcm394_base_video_device::video_7083_r() { LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_7083_r\n", machine().describe_context()); return m_7083; }
1005 
spriteram_w(offs_t offset,uint16_t data)1006 void gcm394_base_video_device::spriteram_w(offs_t offset, uint16_t data)
1007 {
1008 	// transfers an additional word for each sprite with this bit set (smartfp) or an entire extra bank (wrlshunt)
1009 	// wrlshunt instead seems to base if it writes the extra data based on 707f so maybe this is more complex than banking
1010 
1011 	// however for 707e only 0/1 is written, and it also gets written before system DMA, so despite being in the video DMA
1012 	// region seems to operate separate from that.
1013 
1014 	if (m_707e_spritebank == 0x0000)
1015 	{
1016 		m_spriteram[offset] = data;
1017 	}
1018 	else if (m_707e_spritebank == 0x0001)
1019 	{
1020 		m_spriteram[offset + 0x400] = data;
1021 	}
1022 	else
1023 	{
1024 		LOGMASKED(LOG_GCM394_VIDEO, "%s: spriteram_w %04x %04x unknown bank %04x\n", machine().describe_context(), offset, data, m_707e_spritebank);
1025 	}
1026 }
1027 
spriteram_r(offs_t offset)1028 uint16_t gcm394_base_video_device::spriteram_r(offs_t offset)
1029 {
1030 	if (m_707e_spritebank == 0x0000)
1031 	{
1032 		return m_spriteram[offset];
1033 	}
1034 	else if (m_707e_spritebank == 0x0001)
1035 	{
1036 		return m_spriteram[offset + 0x400];
1037 	}
1038 	else
1039 	{
1040 		LOGMASKED(LOG_GCM394_VIDEO, "%s: spriteram_r %04x unknown bank %04x\n", machine().describe_context(), offset,  m_707e_spritebank);
1041 		return 0x0000;
1042 	}
1043 }
1044 
palette_w(offs_t offset,uint16_t data)1045 void gcm394_base_video_device::palette_w(offs_t offset, uint16_t data)
1046 {
1047 	LOGMASKED(LOG_GCM394_VIDEO_PALETTE, "%s:gcm394_base_video_device::palette_w %04x : %04x (value of 0x703a is %04x)\n", machine().describe_context(), offset, data, m_703a_palettebank);
1048 
1049 	if (m_703a_palettebank & 0xfff0)
1050 	{
1051 		LOGMASKED(LOG_GCM394_VIDEO_PALETTE,"palette writes with m_703a_palettebank %04x\n", m_703a_palettebank);
1052 	}
1053 
1054 
1055 	offset |= (m_703a_palettebank & 0x000c) << 6;
1056 	m_paletteram[offset] = data;
1057 
1058 	// for debug
1059 	m_palette->set_pen_color(offset, rgb_t(
1060 		(((data >> 10) & 0x1f)<<3),
1061 		(((data >> 5)  & 0x1f)<<3),
1062 		(((data >> 0)  & 0x1f)<<3)));
1063 
1064 }
1065 
palette_r(offs_t offset)1066 uint16_t gcm394_base_video_device::palette_r(offs_t offset)
1067 {
1068 	if (m_703a_palettebank & 0xfff0)
1069 	{
1070 		LOGMASKED(LOG_GCM394_VIDEO_PALETTE,"palette read with m_703a_palettebank %04x\n", m_703a_palettebank);
1071 	}
1072 
1073 	offset |= (m_703a_palettebank & 0x000c) << 6;
1074 	return m_paletteram[offset];
1075 }
1076 
video_701c_w(uint16_t data)1077 void gcm394_base_video_device::video_701c_w(uint16_t data)
1078 {
1079 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_701c_w (unknown video reg?) %04x\n", machine().describe_context(), data);
1080 	m_renderer->set_video_reg_1c(data);
1081 }
1082 
video_701d_w(uint16_t data)1083 void gcm394_base_video_device::video_701d_w(uint16_t data)
1084 {
1085 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_701d_w (unknown video reg?) %04x\n", machine().describe_context(), data);
1086 	m_renderer->set_video_reg_1d(data);
1087 }
1088 
video_701e_w(uint16_t data)1089 void gcm394_base_video_device::video_701e_w(uint16_t data)
1090 {
1091 	LOGMASKED(LOG_GCM394_VIDEO, "%s:gcm394_base_video_device::video_701e_w (unknown video reg?) %04x\n", machine().describe_context(), data);
1092 	m_renderer->set_video_reg_1e(data);
1093 }
1094 
1095 
check_video_irq()1096 void gcm394_base_video_device::check_video_irq()
1097 {
1098 	LOGMASKED(LOG_GCM394_VIDEO, "%ssserting Video IRQ (%04x, %04x)\n", (m_video_irq_status & m_video_irq_enable) ? "A" : "Dea", m_video_irq_status, m_video_irq_enable);
1099 	m_video_irq_cb((m_video_irq_status & m_video_irq_enable) ? ASSERT_LINE : CLEAR_LINE);
1100 }
1101 
WRITE_LINE_MEMBER(gcm394_base_video_device::vblank)1102 WRITE_LINE_MEMBER(gcm394_base_video_device::vblank)
1103 {
1104 	if (!state)
1105 	{
1106 		m_video_irq_status &= ~1;
1107 		LOGMASKED(LOG_GCM394_VIDEO, "Setting video IRQ status to %04x\n", m_video_irq_status);
1108 		check_video_irq();
1109 		return;
1110 	}
1111 
1112 	if (m_video_irq_enable & 1)
1113 	{
1114 		// jak_prft expects 0x800 to be set in the status register or most of the main vblank code is skipped, why?
1115 
1116 		m_video_irq_status |= 1 | 0x800;
1117 		LOGMASKED(LOG_GCM394_VIDEO, "Setting video IRQ status to %04x\n", m_video_irq_status);
1118 		check_video_irq();
1119 	}
1120 }
1121 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)1122 void gcm394_base_video_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
1123 {
1124 	switch (id)
1125 	{
1126 		case TIMER_SCREENPOS:
1127 		{
1128 			if (m_video_irq_enable & 2)
1129 			{
1130 				m_video_irq_status |= 2;
1131 				check_video_irq();
1132 			}
1133 
1134 			//printf("firing irq timer\n");
1135 
1136 			m_screen->update_partial(m_screen->vpos());
1137 
1138 			// fire again, jak_dbz pinball needs this
1139 			m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos-19, m_xirqpos));
1140 			break;
1141 		}
1142 	}
1143 }
1144 
1145 
GFXDECODE_START(gfx)1146 static GFXDECODE_START( gfx )
1147 GFXDECODE_END
1148 
1149 void gcm394_base_video_device::device_add_mconfig(machine_config &config)
1150 {
1151 	PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 256*0x10);
1152 	GFXDECODE(config, m_gfxdecode, m_palette, gfx);
1153 
1154 	SPG_RENDERER(config, m_renderer, 0);
1155 }
1156 
1157 
1158