1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood
3 
4 #include "emu.h"
5 #include "elan_eu3a14vid.h"
6 
7 DEFINE_DEVICE_TYPE(ELAN_EU3A14_VID, elan_eu3a14vid_device, "elan_eu3a14vid", "Elan EU3A14 Video")
8 
elan_eu3a14vid_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)9 elan_eu3a14vid_device::elan_eu3a14vid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
10 	: elan_eu3a05commonvid_device(mconfig, ELAN_EU3A14_VID, tag, owner, clock),
11 	device_memory_interface(mconfig, *this),
12 	m_cpu(*this, finder_base::DUMMY_TAG),
13 	m_bank(*this, finder_base::DUMMY_TAG),
14 	m_screen(*this, finder_base::DUMMY_TAG),
15 	m_space_config("regs", ENDIANNESS_NATIVE, 8, 7, 0, address_map_constructor(FUNC(elan_eu3a14vid_device::map), this))
16 {
17 }
18 
memory_space_config() const19 device_memory_interface::space_config_vector elan_eu3a14vid_device::memory_space_config() const
20 {
21 	return space_config_vector {
22 		std::make_pair(0, &m_space_config)
23 	};
24 }
25 
26 /* Windowing mode note
27 
28  huntin'3 seems to use some registers for a windowing / highlight effect on the trophy room names and "Target Range" mode timer??
29  5100 - 0x0f when effect is enabled, 0x00 otherwise?
30  5101 - 0x0e in both modes
31  5102 - 0x86 in both modes
32  5103 - 0x0e in tropy room (left?)                                  / 0x2a in "Target Range" mode (left position?)
33  5104 - trophy room window / highlight top, move with cursor        / 0xbf in "Target Range" mode (top?)
34  5105 - 0x52 in trophy room (right?)                                / counts from 0xa1 to 0x2a in "Target Range" mode (right position?)
35  5106 - trophy room window / highlight bottom, move with cursor     / 0xcb in "Target Range" mode (bottom?)
36 */
37 
map(address_map & map)38 void elan_eu3a14vid_device::map(address_map &map)
39 {
40 	map(0x00, 0x7f).rw(FUNC(elan_eu3a14vid_device::read_unmapped), FUNC(elan_eu3a14vid_device::write_unmapped));
41 
42 	map(0x00, 0x06).ram(); // see Windowing note above
43 	map(0x07, 0x07).rw(FUNC(elan_eu3a14vid_device::reg5107_r), FUNC(elan_eu3a14vid_device::reg5107_w)); // writes on transitions, maybe layer disables?
44 	map(0x08, 0x08).rw(FUNC(elan_eu3a14vid_device::reg5108_r), FUNC(elan_eu3a14vid_device::reg5108_w)); // 0x04 in both modes // hnt3, frequently rewrites same values TODO
45 	map(0x09, 0x09).rw(FUNC(elan_eu3a14vid_device::reg5109_r), FUNC(elan_eu3a14vid_device::reg5109_w)); // related to above?
46 	// 0x0a
47 	// 0x0b
48 	// 0x0c
49 	// 0x0d
50 	// 0x0e
51 	// 0x0f
52 	map(0x10, 0x15).rw(FUNC(elan_eu3a14vid_device::tilecfg_r), FUNC(elan_eu3a14vid_device::tilecfg_w));
53 	map(0x16, 0x17).rw(FUNC(elan_eu3a14vid_device::rowscrollcfg_r), FUNC(elan_eu3a14vid_device::rowscrollcfg_w));
54 	// 0x18
55 	// 0x19
56 	map(0x1a, 0x1e).rw(FUNC(elan_eu3a14vid_device::rowscrollsplit_r), FUNC(elan_eu3a14vid_device::rowscrollsplit_w));
57 	// 0x1f
58 	// 0x20
59 	map(0x21, 0x24).rw(FUNC(elan_eu3a14vid_device::scrollregs_r), FUNC(elan_eu3a14vid_device::scrollregs_w));   // 0x21,0x22 = scroll reg 1,  0x23,0x24 = scroll reg 2
60 	map(0x25, 0x2c).rw(FUNC(elan_eu3a14vid_device::rowscrollregs_r), FUNC(elan_eu3a14vid_device::rowscrollregs_w)); // 0x25,0x26 = rowscroll reg 1, 0x27,0x28 = rowscroll reg 2, 0x29,0x2a = rowscroll reg 3, 0x2b,0x2c = rowscroll reg 3
61 	// 0x2d
62 	// 0x2e
63 	// 0x2f
64 	// 0x30
65 	// 0x31
66 	// 0x32
67 	// 0x33
68 	// 0x34
69 	// 0x35
70 	// 0x36
71 	// 0x37
72 	// 0x38
73 	// 0x39
74 	// 0x3a
75 	// 0x3b
76 	// 0x3c
77 	// 0x3d
78 	// 0x3e
79 	// 0x3f
80 	map(0x40, 0x45).rw(FUNC(elan_eu3a14vid_device::ramtilecfg_r), FUNC(elan_eu3a14vid_device::ramtilecfg_w));
81 	// 0x46
82 	// 0x47
83 	map(0x48, 0x4b).ram();  // hnt3 (always 0 tho?)
84 	// 0x4c
85 	// 0x4d
86 	// 0x4e
87 	// 0x4f
88 	map(0x50, 0x50).rw(FUNC(elan_eu3a14vid_device::spriteaddr_r), FUNC(elan_eu3a14vid_device::spriteaddr_w));
89 	map(0x51, 0x52).rw(FUNC(elan_eu3a14vid_device::spritebase_r), FUNC(elan_eu3a14vid_device::spritebase_w));
90 	map(0x53, 0x53).ram(); // startup
91 
92 	// nothing else used?
93 }
94 
device_start()95 void elan_eu3a14vid_device::device_start()
96 {
97 	elan_eu3a05commonvid_device::device_start();
98 
99 	save_item(NAME(m_scrollregs));
100 	save_item(NAME(m_tilecfg));
101 	save_item(NAME(m_rowscrollregs));
102 	save_item(NAME(m_rowscrollsplit));
103 	save_item(NAME(m_rowscrollcfg));
104 	save_item(NAME(m_ramtilecfg));
105 	save_item(NAME(m_spritebase));
106 
107 	save_item(NAME(m_5107));
108 	save_item(NAME(m_5108));
109 	save_item(NAME(m_5109));
110 
111 	save_item(NAME(m_spriteaddr));
112 }
113 
device_reset()114 void elan_eu3a14vid_device::device_reset()
115 {
116 	elan_eu3a05commonvid_device::device_reset();
117 
118 	for (int i = 0; i < 4; i++)
119 		m_scrollregs[i] = 0x00;
120 
121 	for (int i = 0; i < 6; i++)
122 		m_tilecfg[i] = 0x00;
123 
124 	for (int i = 0; i < 8; i++)
125 		m_rowscrollregs[i] = 0x00;
126 
127 	for (int i = 0; i < 5; i++)
128 		m_rowscrollsplit[i] = 0x00;
129 
130 	for (int i = 0; i < 2; i++)
131 		m_rowscrollcfg[i] = 0x00;
132 
133 	for (int i = 0; i < 6; i++)
134 		m_ramtilecfg[i] = 0x00;
135 
136 	for (int i = 0; i < 2; i++)
137 		m_spritebase[i] = 0x00;
138 
139 	m_5107 = 0x00;
140 	m_5108 = 0x00;
141 	m_5109 = 0x00;
142 
143 	m_spriteaddr = 0x14; // ?? rad_foot never writes, other games seem to use it to set sprite location
144 }
145 
read_vram(int offset)146 uint8_t elan_eu3a14vid_device::read_vram(int offset)
147 {
148 	address_space& cpuspace = m_cpu->space(AS_PROGRAM);
149 	int realoffset = offset + 0x200;
150 	if (realoffset < 0x4000)
151 	{
152 		return cpuspace.read_byte(realoffset);
153 	}
154 	else
155 		return 0x00;
156 }
157 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)158 uint32_t elan_eu3a14vid_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
159 {
160 	m_spriterambase = (m_spriteaddr * 0x200) - 0x200;
161 
162 	bitmap.fill(0, cliprect);
163 	m_prioritybitmap.fill(0, cliprect);
164 
165 	draw_background(screen, bitmap, cliprect);
166 
167 	draw_sprites(screen, bitmap, cliprect);
168 	return 0;
169 }
170 
video_start()171 void elan_eu3a14vid_device::video_start()
172 {
173 	m_screen->register_screen_bitmap(m_prioritybitmap);
174 }
175 
176 
read_gfxdata(int offset,int x)177 uint8_t elan_eu3a14vid_device::read_gfxdata(int offset, int x)
178 {
179 	address_space& fullbankspace = m_bank->space(AS_PROGRAM);
180 	return fullbankspace.read_byte((offset+x) & 0x3fffff);
181 }
182 
readpix(int baseaddr,int count,int drawfromram)183 uint8_t elan_eu3a14vid_device::readpix(int baseaddr, int count, int drawfromram)
184 {
185 	int pix;
186 
187 	if (drawfromram)
188 	{
189 		pix = read_vram((baseaddr + count) & 0x3fff);
190 	}
191 	else
192 	{
193 		address_space& fullbankspace = m_bank->space(AS_PROGRAM);
194 		pix =  fullbankspace.read_byte((baseaddr+count) & 0x3fffff);
195 	}
196 	return pix;
197 }
198 
draw_background_tile(bitmap_ind16 & bitmap,const rectangle & cliprect,int bpp,int tileno,int palette,int priority,int flipx,int flipy,int xpos,int ypos,int transpen,int size,int base,int drawfromram)199 void elan_eu3a14vid_device::draw_background_tile(bitmap_ind16& bitmap, const rectangle& cliprect, int bpp, int tileno, int palette, int priority, int flipx, int flipy, int xpos, int ypos, int transpen, int size, int base, int drawfromram)
200 {
201 	int baseaddr = base * 256;
202 
203 	int xstride = 8;
204 
205 	if (bpp == 8) // 8bpp selection
206 	{
207 		if (size == 8)
208 		{
209 			xstride = size / 1; baseaddr += tileno * 64; // 8x8 8bpp
210 		}
211 		else
212 		{
213 			xstride = size / 1; baseaddr += tileno * 256; // 16x16 8bpp
214 		}
215 
216 		palette &= 0x100; // only top bit valid, as there are only 2 palettes?
217 	}
218 	else if (bpp == 4) // 4bpp selection
219 	{
220 		if (size == 8)
221 		{
222 			xstride = size / 2; baseaddr += tileno * 32; // 8x8 4bpp
223 		}
224 		else
225 		{
226 			xstride = size / 2; baseaddr += tileno * 128; // 16x16 4bpp
227 		}
228 	}
229 	else if (bpp == 2) // 2bpp?
230 	{
231 		xstride = size / 4; baseaddr += tileno * 64; // 16x16 2bpp
232 	}
233 	else
234 	{
235 		popmessage("draw_background_tile unsupported bpp %d\n", bpp);
236 		return;
237 	}
238 
239 	int count = 0;
240 	for (int y = 0; y < size; y++)
241 	{
242 		int realy = ypos + y;
243 		int xposwithscroll = 0;
244 
245 		if (!drawfromram)
246 		{
247 			xposwithscroll = xpos - get_xscroll_for_screenypos(realy);
248 		}
249 		else
250 		{
251 			xposwithscroll = xpos;
252 			// RAM tile layer has no scrolling? (or we've never seen it used / enabled)
253 		}
254 
255 		uint16_t *const dst = &bitmap.pix(ypos + y);
256 		uint8_t *const pridst = &m_prioritybitmap.pix(ypos + y);
257 
258 		for (int x = 0; x < xstride; x++)
259 		{
260 			if (realy >= cliprect.min_y && realy <= cliprect.max_y)
261 			{
262 				if (bpp == 8) // 8bpp
263 				{
264 					int realx = x + xposwithscroll;
265 					if (realx >= cliprect.min_x && realx <= cliprect.max_x)
266 					{
267 						uint8_t pix = readpix(baseaddr, count, drawfromram);
268 
269 						if (pix)
270 						{
271 							if (pridst[realx] <= priority)
272 							{
273 								dst[realx] = pix | palette;
274 								pridst[realx] = priority;
275 							}
276 
277 						}
278 					}
279 				}
280 				else if (bpp == 7)
281 				{
282 					popmessage("draw_background_tile bpp == 7");
283 				}
284 				else if (bpp == 6)
285 				{
286 					popmessage("draw_background_tile bpp == 6");
287 				}
288 				else if (bpp == 5)
289 				{
290 					popmessage("draw_background_tile bpp == 5");
291 				}
292 				else if (bpp == 4) // 4bpp
293 				{
294 					int realx = (x * 2) + xposwithscroll;
295 
296 					if (((realx + 1) >= cliprect.min_x) || (realx <= cliprect.max_x))
297 					{
298 						uint8_t pix = readpix(baseaddr, count, drawfromram);
299 
300 						int mask = 0xf0;
301 						int shift = 4;
302 
303 						for (int i = 0; i < 4; i++)
304 						{
305 							if (realx >= cliprect.min_x && realx <= cliprect.max_x)
306 							{
307 								if (pix & mask)
308 								{
309 									if (pridst[realx] <= priority)
310 									{
311 										dst[realx] = ((pix & mask) >> shift) | palette;
312 										pridst[realx] = priority;
313 									}
314 								}
315 							}
316 							mask >>= 4;
317 							shift -= 4;
318 							realx++;
319 						}
320 					}
321 				}
322 				else if (bpp == 3)
323 				{
324 					popmessage("draw_background_tile bpp == 3");
325 				}
326 				else if (bpp == 2) // 2bpp (hnt3 ram text)
327 				{
328 					int realx = (x * 4) + xposwithscroll;
329 
330 					if (((realx + 3) >= cliprect.min_x) || (realx <= cliprect.max_x))
331 					{
332 						uint8_t pix = readpix(baseaddr, count, drawfromram);
333 
334 						int mask = 0xc0;
335 						int shift = 6;
336 
337 						for (int i = 0; i < 4; i++)
338 						{
339 							if (realx >= cliprect.min_x && realx <= cliprect.max_x)
340 							{
341 								if (pix & 0xc0)
342 								{
343 									if (pridst[realx] <= priority)
344 									{
345 										dst[realx] = ((pix & mask) >> shift) | palette;
346 										pridst[realx] = priority;
347 									}
348 								}
349 							}
350 
351 							realx++;
352 							mask >>= 2;
353 							shift -= 2;
354 						}
355 					}
356 				}
357 				else if (bpp == 1)
358 				{
359 					popmessage("draw_background_tile bpp == 1");
360 				}
361 			}
362 			count++;
363 		}
364 	}
365 }
366 
get_xscroll_for_screenypos(int ydraw)367 int elan_eu3a14vid_device::get_xscroll_for_screenypos(int ydraw)
368 {
369 	if ((ydraw < 0) || (ydraw >= 224))
370 		return 0;
371 
372 	int xscroll = m_scrollregs[0] | (m_scrollregs[1] << 8);
373 
374 	if (m_rowscrollcfg[1] == 0x01) // GUESS! could be anything, but this bit is set in Huntin'3
375 	{
376 		int split0 = m_rowscrollregs[0] | (m_rowscrollregs[1] << 8);
377 		int split1 = m_rowscrollregs[2] | (m_rowscrollregs[3] << 8);
378 		int split2 = m_rowscrollregs[4] | (m_rowscrollregs[5] << 8);
379 		int split3 = m_rowscrollregs[6] | (m_rowscrollregs[7] << 8);
380 
381 		if (ydraw < m_rowscrollsplit[0])
382 		{
383 			return xscroll;
384 		}
385 		else if (ydraw < m_rowscrollsplit[1])
386 		{
387 			return split0;
388 		}
389 		else if (ydraw < m_rowscrollsplit[2])
390 		{
391 			return split1;
392 		}
393 		else if (ydraw < m_rowscrollsplit[3])
394 		{
395 			return split2;
396 		}
397 		else if (ydraw < m_rowscrollsplit[4])
398 		{
399 			return split3;
400 		}
401 		else
402 		{
403 			return 0;
404 		}
405 	}
406 	else
407 	{
408 		return xscroll;
409 	}
410 }
411 
412 
draw_background_page(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect,int ramstart,int ramend,int xbase,int ybase,int size,int bpp,int base,int pagewidth,int pageheight,int bytespertile,int palettepri,int drawfromram)413 void elan_eu3a14vid_device::draw_background_page(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int ramstart, int ramend, int xbase, int ybase, int size, int bpp, int base, int pagewidth, int pageheight, int bytespertile, int palettepri, int drawfromram)
414 {
415 
416 	int palette = ((palettepri & 0xf0) >> 4) | ((palettepri & 0x08) << 1);
417 	palette = palette << 4;
418 	int priority = palettepri & 0x07;
419 
420 	int xdraw = xbase;
421 	int ydraw = ybase;
422 	int count = 0;
423 
424 	for (int i = ramstart; i < ramend; i += bytespertile)
425 	{
426 		int tile = 0;
427 		int realpalette = palette;
428 		int realpriority = priority;
429 		int realbpp = bpp;
430 
431 		if (bytespertile == 2)
432 		{
433 			tile = read_vram(i + 0) | (read_vram(i + 1) << 8);
434 		}
435 		else if (bytespertile == 4) // rad_foot hidden test mode, rad_hnt3 "Target Range" (not yet correct)
436 		{
437 			tile = read_vram(i + 0) | (read_vram(i + 1) << 8);// | (read_vram(i + 2) << 16) |  | (read_vram(i + 3) << 24);
438 
439 			// read_vram(i + 3) & 0x04 is set in both seen cases, maybe per-tile bpp?
440 			// this would match up with this mode being inline replacements for m_tilecfg[1] (palettepri) and m_tilecfg[2] (bpp);
441 
442 			int newpalette = ((read_vram(i + 2) & 0xf0) >> 4) | ((read_vram(i + 2) & 0x08) << 1);
443 			newpalette = newpalette << 4;
444 			realpalette = newpalette;
445 			realpriority = read_vram(i + 2) & 0x07;
446 			realbpp = read_vram(i + 3) & 0x07;
447 			if (realbpp == 0)
448 				realbpp = 8;
449 
450 		}
451 
452 
453 		draw_background_tile(bitmap, cliprect, realbpp, tile, realpalette, realpriority, 0, 0, xdraw, ydraw, 0, size, base, drawfromram);
454 
455 		xdraw += size;
456 
457 		count++;
458 		if (((count % pagewidth) == 0))
459 		{
460 			xdraw -= size * pagewidth;
461 			ydraw += size;
462 		}
463 	}
464 }
465 
draw_background_ramlayer(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)466 void elan_eu3a14vid_device::draw_background_ramlayer(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect)
467 {
468 	// this register use is questionable
469 	if (m_ramtilecfg[0] & 0x80)
470 	{
471 		int rtm_size;
472 		int rtm_pagewidth;
473 		int rtm_pageheight;
474 		int rtm_yscroll;
475 		int rtm_bpp;
476 		int rtm_bytespertile = 2;
477 		uint8_t palettepri = m_ramtilecfg[1];
478 
479 		rtm_yscroll = 0;
480 
481 		// this is the gfxbase in ram for all cases seen
482 		int rtm_base = (0x2000 - 0x200) / 256;
483 
484 		// same as regular layer?
485 		if (m_ramtilecfg[0] & 0x10)
486 		{
487 			rtm_size = 8;
488 			rtm_pagewidth = 32;
489 			rtm_pageheight = 28;
490 		}
491 		else
492 		{
493 			rtm_size = 16;
494 			rtm_pagewidth = 32 / 2;
495 			rtm_pageheight = 28 / 2;
496 		}
497 
498 		rtm_bpp = m_ramtilecfg[2] & 0x07;
499 		if (rtm_bpp == 0)
500 			rtm_bpp = 8;
501 
502 		// this is in the same place even when the first tilemap is in 16x16 mode, probably a base register somewhere
503 		int ramstart = m_tilerambase + 0x700;
504 		int ramend = m_tilerambase + 0x700 + 0x700;
505 
506 		// hack for "Target Range" mode
507 		if (m_ramtilecfg[5] == 0x06)
508 		{
509 			ramstart = 0x3980-0x200;
510 			ramend = 0x3980-0x200 + 0x700;
511 		}
512 
513 		// normal
514 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, 0, 0 - rtm_yscroll, rtm_size, rtm_bpp, rtm_base, rtm_pagewidth, rtm_pageheight, rtm_bytespertile, palettepri, 1);
515 		// wrap x
516 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, (rtm_size * rtm_pagewidth), 0 - rtm_yscroll, rtm_size, rtm_bpp, rtm_base, rtm_pagewidth, rtm_pageheight, rtm_bytespertile, palettepri, 1);
517 		// wrap y
518 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, 0, (rtm_size * rtm_pageheight) + 0 - rtm_yscroll, rtm_size, rtm_bpp, rtm_base, rtm_pagewidth, rtm_pageheight, rtm_bytespertile, palettepri, 1);
519 		// wrap x+y
520 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, (rtm_size * rtm_pagewidth), (rtm_size * rtm_pageheight) + 0 - rtm_yscroll, rtm_size, rtm_bpp, rtm_base, rtm_pagewidth, rtm_pageheight, rtm_bytespertile, palettepri, 1);
521 	}
522 }
523 
524 
draw_background(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)525 void elan_eu3a14vid_device::draw_background(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
526 {
527 	int yscroll = m_scrollregs[2] | (m_scrollregs[3] << 8);
528 
529 	int base = (m_tilecfg[5] << 8) | m_tilecfg[4];
530 	uint8_t palettepri = m_tilecfg[1];
531 
532 	int pagewidth = 1, pageheight = 1;
533 	int bytespertile = 2;
534 	int size;
535 
536 	// m_tilecfg[0]   b-as ?-hh    b = bytes per tile  s = tilesize / page size?  a = always set when tilemaps are in use - check? h = related to page positions, when set uses 2x2 pages? ? = used
537 	// m_tilecfg[1]   pppp x--?    ? = used foot x = used, huntin3 summary (palette bank?) p = palette (used for different stages in huntin3 and the hidden test modes in others)
538 	// m_tilecfg[2]   ---- bbbb    b = bpp mode (0 = 8bpp)
539 	// m_tilecfg[3]   ---- ----     (unused or more gfxbase?)
540 	// m_tilecfg[4]   gggg gggg     gfxbase (lower bits)
541 	// m_tilecfg[5]   gggg gggg     gfxbase (upper bits)
542 
543 	// ramtilecfg appears to be a similar format, except for the other layer with ram base tiles
544 	// however 'a' in m_tilecfg[0] is NOT set
545 	// also m_tilecfg[0] has 0x80 set, which would be 4 bytes per tile, but it isn't?
546 	// the layer seems to be disabled by setting m_tilecfg[0] to 0?
547 
548 	if (m_tilecfg[0] & 0x10)
549 	{
550 		size = 8;
551 		pagewidth = 32;
552 		pageheight = 28;
553 	}
554 	else
555 	{
556 		size = 16;
557 		pagewidth = 16;
558 		pageheight = 14;
559 	}
560 
561 	if (m_tilecfg[0] & 0x80)
562 	{
563 		bytespertile = 4;
564 	}
565 	else
566 	{
567 		bytespertile = 2;
568 	}
569 
570 	int bpp = (m_tilecfg[2] & 0x07);
571 	if (bpp == 0)
572 		bpp = 8;
573 
574 	int ramstart = 0;
575 	int ramend = 0;
576 
577 	int pagesize = pagewidth * pageheight * 2;
578 
579 	if (bytespertile == 4)
580 	{
581 		pagesize <<= 1; // shift because we need twice as much ram for this mode
582 	}
583 
584 	if ((m_tilecfg[0] & 0x03) == 0x00) // tilemaps arranged as 2x2 pages?
585 	{
586 		ramstart = m_tilerambase + pagesize * 0;
587 		ramend = m_tilerambase + pagesize * 1;
588 
589 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, 0,                        0 - yscroll,                          size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // normal
590 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 2),   0 - yscroll,                          size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x
591 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, 0,                       (size * pageheight * 2) + 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap y
592 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 2),  (size * pageheight * 2) + 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x+y
593 
594 		ramstart = m_tilerambase + pagesize * 1;
595 		ramend = m_tilerambase + pagesize * 2;
596 
597 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth),     0 - yscroll,                           size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // normal
598 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 3), 0 - yscroll,                           size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x
599 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth),     (size * pageheight * 2) + 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap y
600 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 3), (size * pageheight * 2) + 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x+y
601 
602 		ramstart = m_tilerambase + pagesize * 2;
603 		ramend = m_tilerambase + pagesize * 3;
604 
605 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, 0,                      (size * pageheight) - yscroll,     size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // normal
606 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 2), (size * pageheight) - yscroll,     size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x
607 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, 0,                      (size * pageheight * 3) - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap y
608 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 2), (size * pageheight * 3) - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x+y
609 
610 		ramstart = m_tilerambase + pagesize * 3;
611 		ramend = m_tilerambase + pagesize * 4;
612 
613 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth),     (size * pageheight) - yscroll,     size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // normal
614 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 3), (size * pageheight) - yscroll,     size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x
615 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth),     (size * pageheight * 3) - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0);// wrap y
616 		draw_background_page(screen, bitmap, cliprect, ramstart,ramend, (size * pagewidth * 3), (size * pageheight * 3) - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0); // wrap x+y
617 	}
618 	else if ((m_tilecfg[0] & 0x03) == 0x03) // individual tilemaps? multiple layers?
619 	{
620 	//  popmessage("m_tilecfg[0] & 0x03 multiple layers config %04x", base);
621 		ramstart = m_tilerambase + pagesize * 0;
622 		ramend = m_tilerambase + pagesize * 1;
623 
624 		// normal
625 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, 0, 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0);
626 		// wrap x
627 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, (size * pagewidth), 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0);
628 		// wrap y
629 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, 0, (size * pageheight) + 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0);
630 		// wrap x+y
631 		draw_background_page(screen, bitmap, cliprect, ramstart, ramend, (size * pagewidth), (size * pageheight) + 0 - yscroll, size, bpp, base, pagewidth,pageheight, bytespertile, palettepri, 0);
632 
633 		// RAM based tile layer
634 		draw_background_ramlayer(screen, bitmap, cliprect);
635 	}
636 	else
637 	{
638 		popmessage("m_tilecfg[0] & 0x03 unknown config");
639 	}
640 
641 }
642 
draw_sprite_pix(const rectangle & cliprect,uint16_t * dst,uint8_t * pridst,int realx,int priority,uint8_t pix,uint8_t mask,uint8_t shift,int palette)643 void elan_eu3a14vid_device::draw_sprite_pix(const rectangle& cliprect, uint16_t* dst, uint8_t* pridst, int realx, int priority, uint8_t pix, uint8_t mask, uint8_t shift, int palette)
644 {
645 	if (realx >= cliprect.min_x && realx <= cliprect.max_x)
646 	{
647 		if (pridst[realx] <= priority)
648 		{
649 			if (pix & mask)
650 			{
651 				dst[realx] = ((pix & mask) >> shift) | palette;
652 				pridst[realx] = priority;
653 			}
654 		}
655 	}
656 }
657 
draw_sprite_line(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect,int offset,int line,int palette,int flipx,int priority,int xpos,int ypos,int bpp)658 void elan_eu3a14vid_device::draw_sprite_line(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int offset, int line, int palette, int flipx, int priority, int xpos, int ypos, int bpp)
659 {
660 	offset = offset * 2;
661 
662 	int bppdiv = 0;
663 
664 	switch (bpp)
665 	{
666 	default:
667 	case 0x8:
668 	case 0x7:
669 	case 0x6:
670 	case 0x5:
671 		offset += line * 8;
672 		bppdiv = 1;
673 		break;
674 
675 	case 0x4:
676 	case 0x3:
677 		offset += line * 4;
678 		bppdiv = 2;
679 		break;
680 
681 	case 0x2:
682 		offset += line * 2;
683 		bppdiv = 4;
684 		break;
685 
686 	case 0x1:
687 		offset += line * 1;
688 		bppdiv = 8;
689 		break;
690 	}
691 
692 
693 	if (ypos >= cliprect.min_y && ypos <= cliprect.max_y)
694 	{
695 		uint16_t *const dst = &bitmap.pix(ypos);
696 		uint8_t *const pridst = &m_prioritybitmap.pix(ypos);
697 
698 		int count = 0;
699 		for (int x = 0; x < 8/bppdiv;x++)
700 		{
701 			if (bpp == 8)
702 			{
703 				int pix,mask,shift;
704 				if (flipx) { pix = read_gfxdata(offset, 7 - count); } else { pix = read_gfxdata(offset, count); }
705 				int realx = xpos + x * 1;
706 				if (flipx) { mask = 0xff; shift = 0; } else { mask = 0xff; shift = 0; }
707 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
708 			}
709 			else if (bpp == 7)
710 			{
711 				int pix,mask,shift;
712 				if (flipx) { pix = read_gfxdata(offset, 7 - count); } else { pix = read_gfxdata(offset, count); }
713 				int realx = xpos + x * 1;
714 				// stride doesn't change, data isn't packed, just don't use top bit
715 				if (flipx) { mask = 0x7f; shift = 0; } else { mask = 0x7f; shift = 0; }
716 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
717 			}
718 			else if (bpp == 6)
719 			{
720 				popmessage("6bpp sprite\n");
721 			}
722 			else if (bpp == 5)
723 			{
724 				popmessage("5bpp sprite\n");
725 			}
726 			else if (bpp == 4)
727 			{
728 				int pix,mask,shift;
729 				if (flipx) { pix = read_gfxdata(offset, 3 - count); } else { pix = read_gfxdata(offset, count); }
730 				int realx = xpos + x * 2;
731 				if (flipx) { mask = 0x0f; shift = 0; } else { mask = 0xf0; shift = 4; }
732 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
733 				realx++;
734 				if (flipx) { mask = 0xf0; shift = 4; } else { mask = 0x0f; shift = 0; }
735 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
736 			}
737 			else if (bpp == 3)
738 			{
739 				popmessage("3bpp sprite\n");
740 			}
741 			else if (bpp == 2)
742 			{
743 				int pix,mask,shift;
744 				if (flipx) { pix = read_gfxdata(offset, 1 - count); } else { pix = read_gfxdata(offset, count); }
745 				int realx = xpos + x * 4;
746 				if (flipx) { mask = 0x03; shift = 0; } else { mask = 0xc0; shift = 6; }
747 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
748 				realx++;
749 				if (flipx) { mask = 0x0c; shift = 2; } else { mask = 0x30; shift = 4; }
750 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
751 				realx++;
752 				if (flipx) { mask = 0x30; shift = 4; } else { mask = 0x0c; shift = 2; }
753 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
754 				realx++;
755 				if (flipx) { mask = 0xc0; shift = 6; } else { mask = 0x03; shift = 0; }
756 				draw_sprite_pix(cliprect, dst, pridst, realx, priority, pix, mask, shift, palette);
757 			}
758 			else if (bpp == 1)
759 			{
760 				popmessage("1bpp sprite\n");
761 			}
762 
763 			count++;
764 		}
765 	}
766 
767 }
768 
769 
draw_sprites(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)770 void elan_eu3a14vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
771 {
772 	for (int i = m_spriterambase; i < m_spriterambase + 0x800; i += 8)
773 	{
774 		/*
775 		+0  e-ff hhww  flip yx, enable, height, width
776 		+1  yyyy yyyy  ypos
777 		+2  xxxx xxxx  xpos
778 		+3  pppp Pzzz  p = palette, P = upper palette bank, z = priority
779 		+4  tttt tttt  tile bits
780 		+5  tttt tttt
781 		+6  --TT TPPP  TTT = tile bank PPP = bpp select (+more?)
782 		+7  ---- ----
783 
784 		*/
785 
786 		int attr = read_vram(i + 0);
787 		int y = read_vram(i + 1);
788 		int x = read_vram(i + 2);
789 		int palettepri = read_vram(i + 3);
790 
791 		int h = attr & 0x0c;
792 		int w = attr & 0x03;
793 		int flipx = (attr & 0x10) >> 4;
794 		int flipy = (attr & 0x20) >> 5;
795 
796 		int height = 0;
797 		int width = 0;
798 
799 		int pri = palettepri & 0x07;
800 
801 		int palette = ((palettepri & 0xf0) >> 4) | ((palettepri & 0x08) << 1);
802 		palette = palette << 4;
803 
804 		switch (h)
805 		{
806 		case 0x0:height = 2; break;
807 		case 0x4:height = 4; break;
808 		case 0x8:height = 8; break;
809 		case 0xc:height = 16; break;
810 		}
811 
812 		switch (w)
813 		{
814 		case 0x0:width = 1; break;
815 		case 0x1:width = 2; break;
816 		case 0x2:width = 4; break;
817 		case 0x3:width = 8; break;
818 		}
819 
820 		y -= ((height * 2) - 4);
821 
822 		x -= ((width * 4) - 4);
823 
824 		height *= 4;
825 
826 		x -= 6;
827 		y -= 4;
828 
829 		int offset = ((read_vram(i + 5) << 8) + (read_vram(i + 4) << 0));
830 		int extra = read_vram(i + 6);
831 
832 		int spritebase = (m_spritebase[1] << 8) | m_spritebase[0];
833 
834 		offset += (extra & 0xf8) << 13;
835 		offset += spritebase << 7;
836 
837 		int bpp = extra & 0x07;
838 		if (bpp == 0)
839 			bpp = 8;
840 
841 		if (attr & 0x80)
842 		{
843 			int count = 0;
844 			for (int yy = 0; yy < height; yy++)
845 			{
846 				int yoff = flipy ? height-1-yy : yy;
847 
848 				for (int xx = 0; xx < width; xx++)
849 				{
850 					int xoff = flipx ? (((width - 1) * 8) - (xx * 8)) : (xx * 8);
851 
852 					draw_sprite_line(screen, bitmap, cliprect, offset, count, palette, flipx, pri, x + xoff, y + yoff, bpp);
853 					count++;
854 				}
855 			}
856 		}
857 	}
858 }
read_unmapped(offs_t offset)859 uint8_t elan_eu3a14vid_device::read_unmapped(offs_t offset)
860 {
861 	logerror("%s: elan_eu3a14vid_device::read_unmapped (offset %02x)\n", machine().describe_context(), offset);
862 	return 0x00;
863 }
864 
write_unmapped(offs_t offset,uint8_t data)865 void elan_eu3a14vid_device::write_unmapped(offs_t offset, uint8_t data)
866 {
867 	logerror("%s: elan_eu3a14vid_device::write_unmapped (offset %02x) (data %02x)\n", machine().describe_context(), offset, data);
868 }
869