1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood
3 
4 #include "emu.h"
5 #include "k001604.h"
6 
7 
8 /***************************************************************************/
9 /*                                                                         */
10 /*                                  001604                                 */
11 /*                                                                         */
12 /***************************************************************************/
13 
14 
15 #define K001604_NUM_TILES_LAYER0        16384
16 #define K001604_NUM_TILES_LAYER1        4096
17 
18 DEFINE_DEVICE_TYPE(K001604, k001604_device, "k001604_device", "K001604 2D tilemaps + 2x ROZ")
19 
k001604_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)20 k001604_device::k001604_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
21 	: device_t(mconfig, K001604, tag, owner, clock),
22 	device_gfx_interface(mconfig, *this, nullptr),
23 	m_layer_size(0),
24 	m_roz_size(0),
25 	m_txt_mem_offset(0),
26 	m_roz_mem_offset(0),
27 	m_layer_roz(nullptr),
28 	m_tile_ram(nullptr),
29 	m_char_ram(nullptr),
30 	m_reg(nullptr)
31 {
32 }
33 
34 //-------------------------------------------------
35 //  device_start - device-specific startup
36 //-------------------------------------------------
37 
device_start()38 void k001604_device::device_start()
39 {
40 	if (!palette().device().started())
41 		throw device_missing_dependencies();
42 
43 	static const gfx_layout k001604_char_layout_layer_8x8 =
44 	{
45 		8, 8,
46 		K001604_NUM_TILES_LAYER0,
47 		8,
48 		{ 8,9,10,11,12,13,14,15 },
49 		{ 1*16, 0*16, 3*16, 2*16, 5*16, 4*16, 7*16, 6*16 },
50 		{ 0*128, 1*128, 2*128, 3*128, 4*128, 5*128, 6*128, 7*128 },
51 		8*128
52 	};
53 
54 	static const gfx_layout k001604_char_layout_layer_16x16 =
55 	{
56 		16, 16,
57 		K001604_NUM_TILES_LAYER1,
58 		8,
59 		{ 8,9,10,11,12,13,14,15 },
60 		{ 1*16, 0*16, 3*16, 2*16, 5*16, 4*16, 7*16, 6*16, 9*16, 8*16, 11*16, 10*16, 13*16, 12*16, 15*16, 14*16 },
61 		{ 0*256, 1*256, 2*256, 3*256, 4*256, 5*256, 6*256, 7*256, 8*256, 9*256, 10*256, 11*256, 12*256, 13*256, 14*256, 15*256 },
62 		16*256
63 	};
64 
65 	int roz_tile_size;
66 
67 	m_char_ram = make_unique_clear<uint32_t[]>(0x200000 / 4);
68 	m_tile_ram = make_unique_clear<uint32_t[]>(0x20000 / 4);
69 	m_reg = make_unique_clear<uint32_t[]>(0x400 / 4);
70 
71 	/* create tilemaps */
72 	roz_tile_size = m_roz_size ? 16 : 8;
73 
74 	if (m_layer_size)
75 	{
76 		m_layer_8x8[0] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(k001604_device::tile_info_layer_8x8)), tilemap_mapper_delegate(*this, FUNC(k001604_device::scan_layer_8x8_0_size1)), 8, 8, 64, 64);
77 		m_layer_8x8[1] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(k001604_device::tile_info_layer_8x8)), tilemap_mapper_delegate(*this, FUNC(k001604_device::scan_layer_8x8_1_size1)), 8, 8, 64, 64);
78 
79 		m_layer_roz = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(k001604_device::tile_info_layer_roz)), tilemap_mapper_delegate(*this, FUNC(k001604_device::scan_layer_roz_256)), roz_tile_size, roz_tile_size, 128, 64);
80 	}
81 	else
82 	{
83 		m_layer_8x8[0] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(k001604_device::tile_info_layer_8x8)), tilemap_mapper_delegate(*this, FUNC(k001604_device::scan_layer_8x8_0_size0)), 8, 8, 64, 64);
84 		m_layer_8x8[1] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(k001604_device::tile_info_layer_8x8)), tilemap_mapper_delegate(*this, FUNC(k001604_device::scan_layer_8x8_1_size0)), 8, 8, 64, 64);
85 
86 		m_layer_roz = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(k001604_device::tile_info_layer_roz)), tilemap_mapper_delegate(*this, FUNC(k001604_device::scan_layer_roz_128)), roz_tile_size, roz_tile_size, 128, 64);
87 	}
88 
89 	m_layer_8x8[0]->set_transparent_pen(0);
90 	m_layer_8x8[1]->set_transparent_pen(0);
91 
92 	set_gfx(0, std::make_unique<gfx_element>(&palette(), k001604_char_layout_layer_8x8, (uint8_t*)&m_char_ram[0], 0, palette().entries() / 16, 0));
93 	set_gfx(1, std::make_unique<gfx_element>(&palette(), k001604_char_layout_layer_16x16, (uint8_t*)&m_char_ram[0], 0, palette().entries() / 16, 0));
94 
95 	save_pointer(NAME(m_reg), 0x400 / 4);
96 	save_pointer(NAME(m_char_ram), 0x200000 / 4);
97 	save_pointer(NAME(m_tile_ram), 0x20000 / 4);
98 
99 }
100 
101 //-------------------------------------------------
102 //  device_reset - device-specific reset
103 //-------------------------------------------------
104 
device_reset()105 void k001604_device::device_reset()
106 {
107 	memset(m_char_ram.get(), 0, 0x200000);
108 	memset(m_tile_ram.get(), 0, 0x10000);
109 	memset(m_reg.get(), 0, 0x400);
110 }
111 
112 /*****************************************************************************
113     DEVICE HANDLERS
114 *****************************************************************************/
115 
116 /* FIXME: The TILEMAP_MAPPER below depends on parameters passed by the device interface (being game dependent).
117 we might simplify the code, by passing the whole TILEMAP_MAPPER as a callback in the interface, but is it really worth? */
118 
TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_0_size0)119 TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_0_size0)
120 {
121 	/* logical (col,row) -> memory offset */
122 	return (row * 128) + col + m_txt_mem_offset;
123 }
124 
TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_0_size1)125 TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_0_size1)
126 {
127 	/* logical (col,row) -> memory offset */
128 	return (row * 256) + col + m_txt_mem_offset;
129 }
130 
TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_1_size0)131 TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_1_size0)
132 {
133 	/* logical (col,row) -> memory offset */
134 	return (row * 128) + col + 64 + m_txt_mem_offset;
135 }
136 
TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_1_size1)137 TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_8x8_1_size1)
138 {
139 	/* logical (col,row) -> memory offset */
140 	return (row * 256) + col + 64 + m_txt_mem_offset;
141 }
142 
TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_roz_128)143 TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_roz_128)
144 {
145 	/* logical (col,row) -> memory offset */
146 	return (row * 128) + col + m_roz_mem_offset;
147 }
148 
TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_roz_256)149 TILEMAP_MAPPER_MEMBER(k001604_device::scan_layer_roz_256)
150 {
151 	/* logical (col,row) -> memory offset */
152 	return (row * 256) + col + 128 + m_roz_mem_offset;
153 }
154 
TILE_GET_INFO_MEMBER(k001604_device::tile_info_layer_8x8)155 TILE_GET_INFO_MEMBER(k001604_device::tile_info_layer_8x8)
156 {
157 	uint32_t val = m_tile_ram[tile_index];
158 	int color = (val >> 17) & 0x1f;
159 	int tile = (val & 0x7fff);
160 	int flags = 0;
161 
162 	if (val & 0x400000)
163 		flags |= TILE_FLIPX;
164 	if (val & 0x800000)
165 		flags |= TILE_FLIPY;
166 
167 	tileinfo.set(0, tile, color, flags);
168 }
169 
TILE_GET_INFO_MEMBER(k001604_device::tile_info_layer_roz)170 TILE_GET_INFO_MEMBER(k001604_device::tile_info_layer_roz)
171 {
172 	uint32_t val = m_tile_ram[tile_index];
173 	int flags = 0;
174 	int color = (val >> 17) & 0x1f;
175 	int tile = m_roz_size ? (val & 0x7ff) : (val & 0x1fff);
176 
177 	if (val & 0x400000)
178 		flags |= TILE_FLIPX;
179 	if (val & 0x800000)
180 		flags |= TILE_FLIPY;
181 
182 	tile += m_roz_size ? 0x800 : 0x2000;
183 
184 	tileinfo.set(m_roz_size, tile, color, flags);
185 }
186 
187 
draw_back_layer(bitmap_rgb32 & bitmap,const rectangle & cliprect)188 void k001604_device::draw_back_layer( bitmap_rgb32 &bitmap, const rectangle &cliprect )
189 {
190 	bitmap.fill(0, cliprect);
191 
192 	if ((m_reg[0x60 / 4] & 0x40000000) == 0)
193 		return;
194 
195 	int tile_size = m_roz_size ? 16 : 8;
196 
197 	int32_t x  = (int16_t)((m_reg[0x08] >> 16) & 0xffff);
198 	int32_t y  = (int16_t)((m_reg[0x08] >>  0) & 0xffff);
199 	int32_t xx = (int16_t)((m_reg[0x09] >>  0) & 0xffff);
200 	int32_t xy = (int16_t)((m_reg[0x09] >> 16) & 0xffff);
201 	int32_t yx = (int16_t)((m_reg[0x0a] >>  0) & 0xffff);
202 	int32_t yy = (int16_t)((m_reg[0x0a] >> 16) & 0xffff);
203 
204 	int pivotx = (int16_t)((m_reg[0x00] >> 16) & 0xffff);
205 	int pivoty = (int16_t)((m_reg[0x00] >>  0) & 0xffff);
206 
207 	int startx  = ((x - pivotx) * 256) * 32;
208 	int starty  = ((y - pivoty) * 256) * 32;
209 	int incxx = (xx) * 32;
210 	int incxy = (-xy) * 32;
211 	int incyx = (-yx) * 32;
212 	int incyy = (yy) * 32;
213 
214 	bitmap_ind16& pixmap = m_layer_roz->pixmap();
215 
216 	// extract start/end points
217 	int sx = cliprect.min_x;
218 	int sy = cliprect.min_y;
219 	int ex = cliprect.max_x;
220 	int ey = cliprect.max_y;
221 
222 	const rgb_t *clut = palette().palette()->entry_list_raw();
223 
224 	int window_x, window_y, window_xmask, window_ymask;
225 
226 	int layer_size = (m_reg[0x1b] >> 9) & 3;
227 
228 	if (m_roz_size)
229 		window_x = ((m_reg[0x1b] >> 1) & 3) * 512;
230 	else
231 		window_x = ((m_reg[0x1b] >> 1) & 1) * 512;
232 
233 	window_y = 0;
234 
235 	switch (layer_size)
236 	{
237 		case 0: window_xmask = (128 * tile_size) - 1; break;
238 		case 2: window_xmask = (64 * tile_size) - 1; break;
239 		case 3: window_xmask = (32 * tile_size) - 1; break;
240 		default: fatalerror("k001604_draw_back_layer(): layer_size %d\n", layer_size);
241 	}
242 
243 	window_ymask = pixmap.height() - 1;
244 
245 
246 	// loop over rows
247 	while (sy <= ey)
248 	{
249 		// initialize X counters
250 		int x = sx;
251 		uint32_t cx = startx;
252 		uint32_t cy = starty;
253 
254 		uint32_t *dest = &bitmap.pix(sy, sx);
255 
256 		// loop over columns
257 		while (x <= ex)
258 		{
259 			*dest = clut[pixmap.pix(((cy >> 16) & window_ymask) + window_y, ((cx >> 16) & window_xmask) + window_x)];
260 
261 			// advance in X
262 			cx += incxx;
263 			cy += incxy;
264 			x++;
265 			dest++;
266 		}
267 
268 		// advance in Y
269 		startx += incyx;
270 		starty += incyy;
271 		sy++;
272 	}
273 }
274 
draw_front_layer(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)275 void k001604_device::draw_front_layer( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect )
276 {
277 	int32_t x = (int16_t)((m_reg[0x00] >> 16) & 0xffff);
278 	int32_t y = (int16_t)((m_reg[0x00] >> 0) & 0xffff);
279 	int32_t yy = (int16_t)((m_reg[0x01] >> 0) & 0xffff);
280 	int32_t xy = (int16_t)((m_reg[0x01] >> 16) & 0xffff);
281 	int32_t yx = (int16_t)((m_reg[0x02] >> 0) & 0xffff);
282 	int32_t xx = (int16_t)((m_reg[0x02] >> 16) & 0xffff);
283 
284 	int pivotx = (int16_t)(0xfec0);
285 	int pivoty = (int16_t)(0xff28);
286 
287 	int startx = ((x - pivotx) * 256) * 32;
288 	int starty = ((y - pivoty) * 256) * 32;
289 	int incxx = (xx) * 32;
290 	int incxy = (-xy) * 32;
291 	int incyx = (-yx) * 32;
292 	int incyy = (yy) * 32;
293 
294 	bitmap_ind16& pixmap = m_layer_8x8[0]->pixmap();
295 
296 	// extract start/end points
297 	int sx = cliprect.min_x;
298 	int sy = cliprect.min_y;
299 	int ex = cliprect.max_x;
300 	int ey = cliprect.max_y;
301 
302 	const rgb_t *clut = palette().palette()->entry_list_raw();
303 
304 	int window_x, window_y, window_xmask, window_ymask;
305 
306 	window_x = 0;
307 	window_y = 0;
308 	window_xmask = pixmap.width() - 1;
309 	window_ymask = pixmap.height() - 1;
310 
311 
312 	// loop over rows
313 	while (sy <= ey)
314 	{
315 		// initialize X counters
316 		int x = sx;
317 		uint32_t cx = startx;
318 		uint32_t cy = starty;
319 
320 		uint32_t *dest = &bitmap.pix(sy, sx);
321 
322 		// loop over columns
323 		while (x <= ex)
324 		{
325 			uint16_t pix = pixmap.pix(((cy >> 16) & window_ymask) + window_y, ((cx >> 16) & window_xmask) + window_x);
326 			if ((pix & 0xff) != 0)
327 			{
328 				*dest = clut[pix];
329 			}
330 
331 			// advance in X
332 			cx += incxx;
333 			cy += incxy;
334 			x++;
335 			dest++;
336 		}
337 
338 		// advance in Y
339 		startx += incyx;
340 		starty += incyy;
341 		sy++;
342 	}
343 }
344 
tile_r(offs_t offset)345 uint32_t k001604_device::tile_r(offs_t offset)
346 {
347 	return m_tile_ram[offset];
348 }
349 
char_r(offs_t offset)350 uint32_t k001604_device::char_r(offs_t offset)
351 {
352 	int set, bank;
353 	uint32_t addr;
354 
355 	set = (m_reg[0x60 / 4] & 0x1000000) ? 0x100000 : 0;
356 
357 	if (set)
358 		bank = (m_reg[0x60 / 4] >> 8) & 0x3;
359 	else
360 		bank = (m_reg[0x60 / 4] & 0x3);
361 
362 	addr = offset + ((set + (bank * 0x40000)) / 4);
363 
364 	return m_char_ram[addr];
365 }
366 
reg_r(offs_t offset)367 uint32_t k001604_device::reg_r(offs_t offset)
368 {
369 	switch (offset)
370 	{
371 		case 0x54/4:    return machine().rand() << 16;
372 		case 0x5c/4:    return machine().rand() << 16 | machine().rand();
373 	}
374 
375 	return m_reg[offset];
376 }
377 
tile_w(offs_t offset,uint32_t data,uint32_t mem_mask)378 void k001604_device::tile_w(offs_t offset, uint32_t data, uint32_t mem_mask)
379 {
380 	int x/*, y*/;
381 	COMBINE_DATA(m_tile_ram.get() + offset);
382 
383 	if (m_layer_size)
384 	{
385 		x = offset & 0xff;
386 		/*y = offset / 256;*/
387 	}
388 	else
389 	{
390 		x = offset & 0x7f;
391 		/*y = offset / 128;*/
392 	}
393 
394 	if (m_layer_size)
395 	{
396 		if (x < 64)
397 		{
398 			m_layer_8x8[0]->mark_tile_dirty(offset);
399 		}
400 		else if (x < 128)
401 		{
402 			m_layer_8x8[1]->mark_tile_dirty(offset);
403 		}
404 		else
405 		{
406 			m_layer_roz->mark_tile_dirty(offset);
407 		}
408 	}
409 	else
410 	{
411 		if (x < 64)
412 		{
413 			m_layer_8x8[0]->mark_tile_dirty(offset);
414 		}
415 		else
416 		{
417 			m_layer_8x8[1]->mark_tile_dirty(offset);
418 		}
419 
420 		m_layer_roz->mark_tile_dirty(offset);
421 	}
422 }
423 
char_w(offs_t offset,uint32_t data,uint32_t mem_mask)424 void k001604_device::char_w(offs_t offset, uint32_t data, uint32_t mem_mask)
425 {
426 	int set, bank;
427 	uint32_t addr;
428 
429 	set = (m_reg[0x60/4] & 0x1000000) ? 0x100000 : 0;
430 
431 	if (set)
432 		bank = (m_reg[0x60 / 4] >> 8) & 0x3;
433 	else
434 		bank = (m_reg[0x60 / 4] & 0x3);
435 
436 	addr = offset + ((set + (bank * 0x40000)) / 4);
437 
438 	COMBINE_DATA(m_char_ram.get() + addr);
439 
440 	gfx(0)->mark_dirty(addr / 32);
441 	gfx(1)->mark_dirty(addr / 128);
442 }
443 
reg_w(offs_t offset,uint32_t data,uint32_t mem_mask)444 void k001604_device::reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
445 {
446 	COMBINE_DATA(m_reg.get() + offset);
447 
448 	switch (offset)
449 	{
450 		case 0x8:
451 		case 0x9:
452 		case 0xa:
453 			//printf("K001604_reg_w %02X, %08X, %08X\n", offset, data, mem_mask);
454 			break;
455 	}
456 
457 	if (offset != 0x08 && offset != 0x09 && offset != 0x0a /*&& offset != 0x17 && offset != 0x18*/)
458 	{
459 		//printf("K001604_reg_w (%d), %02X, %08X, %08X at %s\n", chip, offset, data, mem_mask, m_maincpu->pc());
460 	}
461 }
462