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