1 // license:BSD-3-Clause
2 // copyright-holders:Philip Bennett
3 /***************************************************************************
4
5 Lock-On video hardware
6
7 ***************************************************************************/
8
9 #include "emu.h"
10 #include "includes/lockon.h"
11 #include "cpu/nec/nec.h"
12 #include "video/resnet.h"
13
14 #define CURSOR_XPOS 168
15 #define CURSOR_YPOS 239
16 #define FRAMEBUFFER_MAX_X 431
17 #define FRAMEBUFFER_MAX_Y (uint32_t)((FRAMEBUFFER_CLOCK / (FRAMEBUFFER_MAX_X-1)).dvalue() / (PIXEL_CLOCK/(HTOTAL*VTOTAL)).dvalue())
18
19
20 /*************************************
21 *
22 * HD46505S-2 CRT Controller
23 *
24 *************************************/
25
lockon_crtc_r()26 uint16_t lockon_state::lockon_crtc_r()
27 {
28 return 0xffff;
29 }
30
lockon_crtc_w(offs_t offset,uint16_t data)31 void lockon_state::lockon_crtc_w(offs_t offset, uint16_t data)
32 {
33 #if 0
34 data &= 0xff;
35
36 if (offset == 0)
37 {
38 switch (data)
39 {
40 case 0x00: osd_printf_debug("Horizontal Total "); break;
41 case 0x01: osd_printf_debug("Horizontal displayed "); break;
42 case 0x02: osd_printf_debug("Horizontal sync position "); break;
43 case 0x03: osd_printf_debug("Horizontal sync width "); break;
44 case 0x04: osd_printf_debug("Vertical total "); break;
45 case 0x05: osd_printf_debug("Vertical total adjust "); break;
46 case 0x06: osd_printf_debug("Vertical displayed "); break;
47 case 0x07: osd_printf_debug("Vertical sync position "); break;
48 case 0x08: osd_printf_debug("Interlace mode "); break;
49 case 0x09: osd_printf_debug("Max. scan line address "); break;
50 case 0x0a: osd_printf_debug("Cursror start "); break;
51 case 0x0b: osd_printf_debug("Cursor end "); break;
52 case 0x0c: osd_printf_debug("Start address (h) "); break;
53 case 0x0d: osd_printf_debug("Start address (l) "); break;
54 case 0x0e: osd_printf_debug("Cursor (h) "); break;
55 case 0x0f: osd_printf_debug("Cursor (l) "); break;
56 case 0x10: osd_printf_debug("Light pen (h)) "); break;
57 case 0x11: osd_printf_debug("Light pen (l) "); break;
58 }
59 }
60 else if (offset == 1)
61 {
62 osd_printf_debug("0x%.2x, (%d)\n",data, data);
63 }
64 #endif
65 }
66
TIMER_CALLBACK_MEMBER(lockon_state::cursor_callback)67 TIMER_CALLBACK_MEMBER(lockon_state::cursor_callback)
68 {
69 if (m_main_inten)
70 m_maincpu->set_input_line_and_vector(0, HOLD_LINE, 0xff); // V30
71
72 m_cursor_timer->adjust(m_screen->time_until_pos(CURSOR_YPOS, CURSOR_XPOS));
73 }
74
75 /*************************************
76 *
77 * Palette decoding
78 *
79 *************************************/
80
81 static const res_net_info lockon_net_info =
82 {
83 RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT,
84 {
85 {RES_NET_AMP_NONE, 560, 0, 5, {4700, 2200, 1000, 470, 220}},
86 {RES_NET_AMP_NONE, 560, 0, 5, {4700, 2200, 1000, 470, 220}},
87 {RES_NET_AMP_NONE, 560, 0, 5, {4700, 2200, 1000, 470, 220}}
88 }
89 };
90
91 static const res_net_info lockon_pd_net_info =
92 {
93 RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT,
94 {
95 {RES_NET_AMP_NONE, 560, 580, 5, {4700, 2200, 1000, 470, 220}},
96 {RES_NET_AMP_NONE, 560, 580, 5, {4700, 2200, 1000, 470, 220}},
97 {RES_NET_AMP_NONE, 560, 580, 5, {4700, 2200, 1000, 470, 220}}
98 }
99 };
100
lockon_palette(palette_device & palette) const101 void lockon_state::lockon_palette(palette_device &palette) const
102 {
103 uint8_t const *const color_prom = memregion("proms")->base();
104
105 for (int i = 0; i < 1024; ++i)
106 {
107 uint8_t r, g, b;
108 uint8_t const p1 = color_prom[i];
109 uint8_t const p2 = color_prom[i + 0x400];
110
111 if (p2 & 0x80)
112 {
113 r = compute_res_net((p2 >> 2) & 0x1f, 0, lockon_net_info);
114 g = compute_res_net(((p1 >> 5) & 0x7) | (p2 & 3) << 3, 1, lockon_net_info);
115 b = compute_res_net((p1 & 0x1f), 2, lockon_net_info);
116 }
117 else
118 {
119 r = compute_res_net((p2 >> 2) & 0x1f, 0, lockon_pd_net_info);
120 g = compute_res_net(((p1 >> 5) & 0x7) | (p2 & 3) << 3, 1, lockon_pd_net_info);
121 b = compute_res_net((p1 & 0x1f), 2, lockon_pd_net_info);
122 }
123
124 palette.set_pen_color(i, rgb_t(r, g, b));
125 }
126 }
127
128
129 /*************************************
130 *
131 * Character tilemap handling
132 *
133 *************************************/
134
lockon_char_w(offs_t offset,uint16_t data)135 void lockon_state::lockon_char_w(offs_t offset, uint16_t data)
136 {
137 m_char_ram[offset] = data;
138 m_tilemap->mark_tile_dirty(offset);
139 }
140
TILE_GET_INFO_MEMBER(lockon_state::get_lockon_tile_info)141 TILE_GET_INFO_MEMBER(lockon_state::get_lockon_tile_info)
142 {
143 uint32_t tileno = m_char_ram[tile_index] & 0x03ff;
144 uint32_t col = (m_char_ram[tile_index] >> 10) & 0x3f;
145
146 col = (col & 0x1f) + (col & 0x20 ? 64 : 0);
147 tileinfo.set(0, tileno, col, 0);
148 }
149
150
151 /*******************************************************************************************
152
153 Scene tilemap hardware
154
155 *******************************************************************************************/
156
lockon_scene_h_scr_w(uint16_t data)157 void lockon_state::lockon_scene_h_scr_w(uint16_t data)
158 {
159 m_scroll_h = data & 0x1ff;
160 }
161
lockon_scene_v_scr_w(uint16_t data)162 void lockon_state::lockon_scene_v_scr_w(uint16_t data)
163 {
164 m_scroll_v = data & 0x81ff;
165 }
166
scene_draw()167 void lockon_state::scene_draw( )
168 {
169 /* 3bpp characters */
170 const uint8_t *const gfx1 = memregion("gfx2")->base();
171 const uint8_t *const gfx2 = gfx1 + 0x10000;
172 const uint8_t *const gfx3 = gfx1 + 0x20000;
173 const uint8_t *const clut = gfx1 + 0x30000;
174
175 for (uint32_t y = 0; y < FRAMEBUFFER_MAX_Y; ++y)
176 {
177 uint32_t d0 = 0, d1 = 0, d2 = 0;
178 uint32_t colour = 0;
179 uint32_t y_offs;
180 uint32_t x_offs;
181 uint32_t y_gran;
182 uint32_t ram_mask = 0x7ff;
183
184 y_offs = (y + m_scroll_v) & 0x1ff;
185
186 /* Clamp - stops tilemap wrapping when screen is rotated */
187 if (BIT(m_scroll_v, 15) && y_offs & 0x100)
188 ram_mask = 0x7;
189
190 x_offs = (m_scroll_h - 8) & 0x1ff;
191 y_gran = y_offs & 7;
192
193 if (x_offs & 7)
194 {
195 uint32_t tileidx;
196 uint16_t addr = ((y_offs & ~7) << 3) + ((x_offs >> 3) & 0x3f);
197 uint16_t ram_val = m_scene_ram[addr & ram_mask];
198
199 colour = (clut[ram_val & 0x7fff] & 0x3f) << 3;
200 tileidx = ((ram_val & 0x0fff) << 3) + y_gran;
201
202 d0 = *(gfx1 + tileidx);
203 d1 = *(gfx2 + tileidx);
204 d2 = *(gfx3 + tileidx);
205 }
206
207 uint16_t *bmpaddr = &m_back_buffer->pix(y);
208
209 for (uint32_t x = 0; x < FRAMEBUFFER_MAX_X; ++x)
210 {
211 uint32_t x_gran = (x_offs & 7) ^ 7;
212 uint32_t col;
213
214 if (!(x_offs & 7))
215 {
216 uint32_t tileidx;
217 uint16_t addr = ((y_offs & ~7) << 3) + ((x_offs >> 3) & 0x3f);
218 uint16_t ram_val = m_scene_ram[addr & ram_mask];
219
220 colour = (clut[ram_val & 0x7fff] & 0x3f) << 3;
221 tileidx = ((ram_val & 0x0fff) << 3) + y_gran;
222
223 d0 = *(gfx1 + tileidx);
224 d1 = *(gfx2 + tileidx);
225 d2 = *(gfx3 + tileidx);
226 }
227
228 col = colour
229 | (((d2 >> x_gran) & 1) << 2)
230 | (((d1 >> x_gran) & 1) << 1)
231 | ( (d0 >> x_gran) & 1);
232
233 *bmpaddr++ = 0xa00 + col;
234
235 x_offs = (x_offs + 1) & 0x1ff;
236 }
237
238 }
239 }
240
241 /*******************************************************************************************
242
243 Ground Hardware
244
245 Each framebuffer line corresponds to a three word entry in ground RAM,
246 starting from offset 3:
247
248 FEDCBA9876543210
249 0 |.............xxx| Tile line (A0-A2 GFX ROMs)
250 |...........xx...| Tile index (A6-A5 GFX ROMs)
251 |........xxx.....| ROM lut address (A6-A4)
252 |.xxxxxxx........| ROM lut address (A13-A7)
253 |x...............| /Line enable
254
255 1 |........xxxxxxxx| TZ2213 value
256 |xxxxxxxx........| X offset
257
258 2 |........xxxxxxxx| TZ2213 DX
259 |.......x........| Carry
260 |x...............| End of list marker
261
262 An 8-bit ground control register controls the following:
263
264 76543210
265 |......xx| LUT ROM A15-A14
266 |....xx..| LUT ROM select
267 |..xx....| CLUT ROM A13-A12
268 |.x......| GFX ROM A15, CLUT ROM A14
269 |x.......| GFX ROM bank select (always 0 - only 1 bank is present)
270
271 *******************************************************************************************/
272
lockon_ground_ctrl_w(uint16_t data)273 void lockon_state::lockon_ground_ctrl_w(uint16_t data)
274 {
275 m_ground_ctrl = data & 0xff;
276 }
277
TIMER_CALLBACK_MEMBER(lockon_state::bufend_callback)278 TIMER_CALLBACK_MEMBER(lockon_state::bufend_callback)
279 {
280 m_ground->set_input_line_and_vector(0, HOLD_LINE, 0xff); // V30
281 m_object->set_input_line(NEC_INPUT_LINE_POLL, ASSERT_LINE);
282 }
283
284 /* Get data for a each 8x8x3 ground tile */
285 #define GET_GROUND_DATA() \
286 { \
287 uint32_t gfx_a4_3 = (ls163 & 0xc) << 1; \
288 uint32_t lut_addr = lut_address + ((ls163 >> 4) & 0xf); \
289 uint32_t gfx_a14_7 = lut_rom[lut_addr] << 7; \
290 clut_addr = (lut_rom[lut_addr] << 4) | clut_a14_12 | clut_a4_3 | (ls163 & 0xc) >> 2; \
291 gfx_addr = gfx_a15 | gfx_a14_7 | gfx_a6_5 | gfx_a4_3 | gfx_a2_0; \
292 pal = (clut_rom[clut_addr] << 3); \
293 rom_data1 = gfx_rom[gfx_addr]; \
294 rom_data2 = gfx_rom[gfx_addr + 0x10000]; \
295 rom_data3 = gfx_rom[gfx_addr + 0x20000]; \
296 }
297
ground_draw()298 void lockon_state::ground_draw( )
299 {
300 /* ROM pointers */
301 const uint8_t *const gfx_rom = memregion("gfx4")->base();
302 const uint8_t *const lut_rom = gfx_rom + 0x30000 + ((m_ground_ctrl >> 2) & 0x3 ? 0x10000 : 0);
303 const uint8_t *const clut_rom = gfx_rom + 0x50000;
304
305 uint32_t lut_a15_14 = (m_ground_ctrl & 0x3) << 14;
306 uint32_t clut_a14_12 = (m_ground_ctrl & 0x70) << 8;
307 uint32_t gfx_a15 = (m_ground_ctrl & 0x40) << 9;
308 uint32_t offs = 3;
309 uint32_t y;
310
311 /* TODO: Clean up and emulate CS of GFX ROMs? */
312 for (y = 0; y < FRAMEBUFFER_MAX_Y; ++y)
313 {
314 uint16_t *bmpaddr = &m_back_buffer->pix(y);
315 uint8_t ls163;
316 uint32_t clut_addr;
317 uint32_t gfx_addr;
318 uint8_t rom_data1 = 0;
319 uint8_t rom_data2 = 0;
320 uint8_t rom_data3 = 0;
321 uint32_t pal = 0;
322 uint32_t x;
323
324 /* Draw this line? */
325 if (!(m_ground_ram[offs] & 0x8000))
326 {
327 uint32_t gfx_a2_0 = m_ground_ram[offs] & 0x0007;
328 uint32_t gfx_a6_5 = (m_ground_ram[offs] & 0x0018) << 2;
329 uint32_t clut_a4_3 = (m_ground_ram[offs] & 0x0018) >> 1;
330 uint8_t tz2213_x = m_ground_ram[offs + 1] & 0xff;
331 uint8_t tz2213_dx = m_ground_ram[offs + 2] & 0xff;
332
333 uint32_t lut_address = lut_a15_14 + ((m_ground_ram[offs] & 0x7fe0) >> 1);
334 uint32_t cy = m_ground_ram[offs + 2] & 0x0100;
335 uint32_t color;
336 uint32_t gpbal2_0_prev;
337
338 ls163 = m_ground_ram[offs + 1] >> 8;
339
340 gpbal2_0_prev = ((ls163 & 3) << 1) | BIT(tz2213_x, 7);
341
342 if (gpbal2_0_prev)
343 GET_GROUND_DATA();
344
345 for (x = 0; x < FRAMEBUFFER_MAX_X; x++)
346 {
347 uint32_t tz2213_cy;
348 uint32_t gpbal2_0 = ((ls163 & 3) << 1) | BIT(tz2213_x, 7);
349
350 /* Stepped into a new tile? */
351 if (gpbal2_0 < gpbal2_0_prev)
352 GET_GROUND_DATA();
353
354 gpbal2_0_prev = gpbal2_0;
355
356 color = pal;
357 color += (rom_data1 >> gpbal2_0) & 0x1;
358 color += ((rom_data2 >> gpbal2_0) & 0x1) << 1;
359 color += ((rom_data3 >> gpbal2_0) & 0x1) << 2;
360
361 *bmpaddr++ = 0x800 + color;
362
363 /* Update the counters */
364 tz2213_cy = (uint8_t)tz2213_dx > (uint8_t)~(tz2213_x);
365 tz2213_x = (tz2213_x + tz2213_dx);
366
367 /* Carry? */
368 if (tz2213_cy || cy)
369 ++ls163;
370 }
371 }
372
373 offs += 3;
374
375 /* End of list marker */
376 if (m_ground_ram[offs + 2] & 0x8000)
377 {
378 m_bufend_timer->adjust(attotime::from_hz(FRAMEBUFFER_CLOCK) * (FRAMEBUFFER_MAX_X * y));
379 }
380 }
381 }
382
383
384 /*******************************************************************************************
385
386 Object hardware
387
388 Customs (4 each, 1 per bitplane)
389 TZA118 - Scaling
390 TZ4203 - Objects with integrated line buffer.
391
392 FEDCBA9876543210
393 0 |......xxxxxxxxxx| Y position
394 |....xx..........| Object Y size
395 |..xx............| Object X size
396 |.x..............| Y flip
397 |x...............| X flip
398 1 |........xxxxxxxx| X/Y scale
399 |.xxxxxxx........| Colour
400 |x...............| End of list marker
401 2 |xxxxxxxxxxxxxxxx| Chunk ROM address
402 3 |.....xxxxxxxxxxx| X position
403
404 *******************************************************************************************/
405
406 /*
407 There's logic to prevent shadow pixels from being drawn against the scene tilemap,
408 so that shadows don't appear against the sky.
409 */
410 #define DRAW_OBJ_PIXEL(COLOR) \
411 do { \
412 if (px < FRAMEBUFFER_MAX_X) \
413 if (COLOR != 0xf) \
414 { \
415 uint8_t clr = m_obj_pal_ram[(pal << 4) + COLOR]; \
416 uint16_t *pix = (line + px); \
417 if (!(clr == 0xff && ((*pix & 0xe00) == 0xa00))) \
418 *pix = 0x400 + clr; \
419 } \
420 px = (px + 1) & 0x7ff; \
421 } while(0)
422
objects_draw()423 void lockon_state::objects_draw( )
424 {
425 const uint8_t *const romlut = memregion("user1")->base();
426 const uint16_t *const chklut = (uint16_t*)memregion("user2")->base();
427 const uint8_t *const gfxrom = memregion("gfx5")->base();
428 const uint8_t *const sproms = memregion("proms")->base() + 0x800;
429
430 for (uint32_t offs = 0; offs < m_object_ram.bytes(); offs += 4)
431 {
432 /* Retrieve the object attributes */
433 uint32_t ypos = m_object_ram[offs] & 0x03ff;
434 uint32_t xpos = m_object_ram[offs + 3] & 0x07ff;
435 uint32_t ysize = (m_object_ram[offs] >> 10) & 0x3;
436 uint32_t xsize = (m_object_ram[offs] >> 12) & 0x3;
437 uint32_t yflip = BIT(m_object_ram[offs], 14);
438 uint32_t xflip = BIT(m_object_ram[offs], 15);
439 uint32_t scale = m_object_ram[offs + 1] & 0xff;
440 uint32_t pal = (m_object_ram[offs + 1] >> 8) & 0x7f;
441 uint32_t opsta = m_object_ram[offs + 2];
442
443 if (m_iden)
444 {
445 m_obj_pal_ram[(pal << 4) + m_obj_pal_addr] = m_obj_pal_latch;
446 break;
447 }
448
449 /* How many lines will this sprite occupy? The PAL @ IC154 knows... */
450 uint32_t lines = scale >> (3 - ysize);
451
452 uint32_t opsta15_8 = opsta & 0xff00;
453
454 /* Account for line buffering */
455 ypos -=1;
456
457 for (uint32_t y = 0; y < FRAMEBUFFER_MAX_Y; y++)
458 {
459 uint32_t cy = (y + ypos) & 0x3ff;
460 uint32_t optab;
461 uint32_t lutaddr;
462 uint32_t tile;
463 uint8_t cnt;
464 uint32_t yidx;
465 uint16_t *line = &m_back_buffer->pix(y);
466 uint32_t px = xpos;
467
468 /* Outside the limits? */
469 if (cy & 0x300)
470 continue;
471
472 if ((cy & 0xff) >= lines)
473 break;
474
475 lutaddr = (scale & 0x80 ? 0x8000 : 0) | ((scale & 0x7f) << 8) | (cy & 0xff);
476 optab = romlut[lutaddr] & 0x7f;
477
478 if (yflip)
479 optab ^= 7;
480
481 yidx = (optab & 7);
482
483 /* Now calculate the lower 7-bits of the LUT ROM address. PAL @ IC157 does this */
484 cnt = (optab >> 3) * (1 << xsize);
485
486 if (xflip)
487 cnt ^= 7 >> (3 - xsize);
488 if (yflip)
489 cnt ^= (0xf >> (3 - ysize)) * (1 << xsize);
490
491 cnt = (cnt + (opsta & 0xff));
492
493 /* Draw! */
494 for (tile = 0; tile < (1 << xsize); ++tile)
495 {
496 uint16_t sc;
497 uint16_t scl;
498 uint32_t x;
499 uint32_t tileaddr;
500 uint16_t td0, td1, td2, td3;
501 uint32_t j;
502 uint32_t bank;
503
504 scl = scale & 0x7f;
505 tileaddr = (chklut[opsta15_8 + cnt] & 0x7fff);
506 bank = ((tileaddr >> 12) & 3) * 0x40000;
507 tileaddr = bank + ((tileaddr & ~0xf000) << 3);
508
509 if (xflip)
510 --cnt;
511 else
512 ++cnt;
513
514 /* Draw two 8x8 tiles */
515 for (j = 0; j < 2; ++j)
516 {
517 /* Get tile data */
518 uint32_t tileadd = tileaddr + (0x20000 * (j ^ xflip));
519
520 /* Retrieve scale values from PROMs */
521 sc = sproms[(scl << 4) + (tile * 2) + j];
522
523 /* Data from ROMs is inverted */
524 td3 = gfxrom[tileadd + yidx] ^ 0xff;
525 td2 = gfxrom[tileadd + 0x8000 + yidx] ^ 0xff;
526 td1 = gfxrom[tileadd + 0x10000 + yidx] ^ 0xff;
527 td0 = gfxrom[tileadd + 0x18000 + yidx] ^ 0xff;
528
529 if (scale & 0x80)
530 {
531 for (x = 0; x < 8; ++x)
532 {
533 uint8_t col;
534 uint8_t pix = x;
535
536 if (!xflip)
537 pix ^= 0x7;
538
539 col = BIT(td0, pix)
540 | (BIT(td1, pix) << 1)
541 | (BIT(td2, pix) << 2)
542 | (BIT(td3, pix) << 3);
543
544 DRAW_OBJ_PIXEL(col);
545
546 if (BIT(sc, x))
547 DRAW_OBJ_PIXEL(col);
548 }
549 }
550 else
551 {
552 for (x = 0; x < 8; ++x)
553 {
554 uint8_t col;
555 uint8_t pix = x;
556
557 if (BIT(sc, x))
558 {
559 if (!xflip)
560 pix ^= 0x7;
561
562 col = BIT(td0, pix)
563 | (BIT(td1, pix) << 1)
564 | (BIT(td2, pix) << 2)
565 | (BIT(td3, pix) << 3);
566
567 DRAW_OBJ_PIXEL(col);
568 }
569 }
570 }
571 }
572 }
573 }
574
575 /* Check for the end of list marker */
576 if (m_object_ram[offs + 1] & 0x8000)
577 return;
578 }
579 }
580
581 /* The mechanism used by the object CPU to update the object ASICs palette RAM */
lockon_tza112_w(offs_t offset,uint16_t data)582 void lockon_state::lockon_tza112_w(offs_t offset, uint16_t data)
583 {
584 if (m_iden)
585 {
586 m_obj_pal_latch = data & 0xff;
587 m_obj_pal_addr = offset & 0xf;
588 objects_draw();
589 }
590 }
591
lockon_obj_4000_r()592 uint16_t lockon_state::lockon_obj_4000_r()
593 {
594 m_object->set_input_line(NEC_INPUT_LINE_POLL, CLEAR_LINE);
595 return 0xffff;
596 }
597
lockon_obj_4000_w(uint16_t data)598 void lockon_state::lockon_obj_4000_w(uint16_t data)
599 {
600 m_iden = data & 1;
601 }
602
603
604 /*******************************************************************************************
605
606 Frame buffer rotation hardware
607
608 FEDCBA9876543210
609 0 |........xxxxxxxx| X start address
610 |.......x........| Direction
611 1 |........xxxxxxxx| TZ2213 IC65 value
612 |.......x........| TZ2213 IC65 /enable
613 2 |........xxxxxxxx| TZ2213 IC65 delta
614 3 |........xxxxxxxx| TZ2213 IC106 delta
615 |.......x........| TZ2213 IC106 enable
616 4 |.......xxxxxxxxx| Y start address
617 5 |........xxxxxxxx| TZ2213 IC66 value
618 6 |........xxxxxxxx| TZ2213 IC66 delta
619 |.......x........| TZ2213 IC65 /enable
620 7 |........xxxxxxxx| TZ2213 IC107 delta
621 |.......x........| TZ2213 /enable
622 |......x.........| Direction
623
624 *******************************************************************************************/
625
lockon_fb_clut_w(offs_t offset,uint16_t data)626 void lockon_state::lockon_fb_clut_w(offs_t offset, uint16_t data)
627 {
628 rgb_t color;
629
630 color = m_palette->pen_color(0x300 + (data & 0xff));
631 m_palette->set_pen_color(0x400 + offset, color);
632 }
633
634 /* Rotation control register */
lockon_rotate_w(offs_t offset,uint16_t data)635 void lockon_state::lockon_rotate_w(offs_t offset, uint16_t data)
636 {
637 switch (offset & 7)
638 {
639 case 0: m_xsal = data & 0x1ff; break;
640 case 1: m_x0ll = data & 0xff; break;
641 case 2: m_dx0ll = data & 0x1ff; break;
642 case 3: m_dxll = data & 0x1ff; break;
643
644 case 4: m_ysal = data & 0x1ff; break;
645 case 5: m_y0ll = data & 0xff; break;
646 case 6: m_dy0ll = data & 0x1ff; break;
647 case 7: m_dyll = data & 0x3ff; break;
648 }
649 }
650
651 #define INCREMENT(ACC, CNT) \
652 do { \
653 carry = (uint8_t)d##ACC > (uint8_t)~ACC; \
654 ACC += d##ACC; \
655 if (carry) ++CNT; \
656 } while(0)
657
658 #define DECREMENT(ACC, CNT) \
659 do { \
660 carry = (uint8_t)d##ACC > (uint8_t)ACC; \
661 ACC -= d##ACC; \
662 if (carry) --CNT; \
663 } while(0)
664
rotate_draw(bitmap_ind16 & bitmap,const rectangle & cliprect)665 void lockon_state::rotate_draw( bitmap_ind16 &bitmap, const rectangle &cliprect )
666 {
667 /* Counters */
668 uint32_t cxy = m_xsal & 0xff;
669 uint32_t cyy = m_ysal & 0x1ff;
670
671 /* Accumulator values and deltas */
672 uint8_t axy = m_x0ll & 0xff;
673 uint8_t daxy = m_dx0ll & 0xff;
674 uint8_t ayy = m_y0ll & 0xff;
675 uint8_t dayy = m_dy0ll & 0xff;
676 uint8_t dayx = m_dyll & 0xff;
677 uint8_t daxx = m_dxll & 0xff;
678
679 uint32_t xy_up = BIT(m_xsal, 8);
680 uint32_t yx_up = BIT(m_dyll, 9);
681 uint32_t axx_en = !BIT(m_dxll, 8);
682 uint32_t ayx_en = !BIT(m_dyll, 8);
683 uint32_t axy_en = !BIT(m_dx0ll, 8);
684 uint32_t ayy_en = !BIT(m_dy0ll, 8);
685
686 for (uint32_t y = 0; y <= cliprect.max_y; ++y)
687 {
688 uint32_t carry;
689 uint16_t *dst = &bitmap.pix(y);
690
691 uint32_t cx = cxy;
692 uint32_t cy = cyy;
693
694 uint8_t axx = axy;
695 uint8_t ayx = ayy;
696
697 for (uint32_t x = 0; x <= cliprect.max_x; ++x)
698 {
699 cx &= 0x1ff;
700 cy &= 0x1ff;
701
702 *dst++ = m_front_buffer->pix(cy, cx);
703
704 if (axx_en)
705 INCREMENT(axx, cx);
706 else
707 ++cx;
708
709 if (ayx_en)
710 {
711 if (yx_up)
712 INCREMENT(ayx, cy);
713 else
714 DECREMENT(ayx, cy);
715 }
716 else
717 {
718 if (yx_up)
719 ++cy;
720 else
721 --cy;
722 }
723 }
724
725 if (axy_en)
726 {
727 if (xy_up)
728 INCREMENT(axy, cxy);
729 else
730 DECREMENT(axy, cxy);
731 }
732 else
733 {
734 if (xy_up)
735 ++cxy;
736 else
737 --cxy;
738 }
739
740 if (ayy_en)
741 INCREMENT(ayy, cyy);
742 else
743 ++cyy;
744
745 cxy &= 0xff;
746 cyy &= 0x1ff;
747 }
748 }
749
750
751 /*******************************************************************************************
752
753 HUD Drawing Hardware
754
755 A sprite layer that uses 8x8x1bpp tiles to form bigger sprites
756
757 0 |.......xxxxxxxxx| Y Position
758 |xxxxxxx.........| Code
759 1 |.......xxxxxxxxx| X Position
760 |....xxx.........| Colour
761 |.xxx............| Sprite width (0=8, 1=16, 2=24, 3=32 pixels, etc.)
762 |x...............| End of list marker
763
764 *******************************************************************************************/
765
hud_draw(bitmap_ind16 & bitmap,const rectangle & cliprect)766 void lockon_state::hud_draw( bitmap_ind16 &bitmap, const rectangle &cliprect )
767 {
768 uint8_t const *const tile_rom = memregion("gfx3")->base();
769
770 for (uint32_t offs = 0x0; offs <= m_hud_ram.bytes(); offs += 2)
771 {
772 uint32_t y_pos;
773 uint32_t x_pos;
774 uint32_t y_size;
775 uint32_t x_size;
776 uint32_t layout;
777 uint16_t colour;
778 uint32_t code;
779 uint32_t rom_a12_7;
780
781 /* End of sprite list marker */
782 if (m_hud_ram[offs + 1] & 0x8000)
783 break;
784
785 y_pos = m_hud_ram[offs] & 0x1ff;
786 x_pos = m_hud_ram[offs + 1] & 0x1ff;
787 x_size = (m_hud_ram[offs + 1] >> 12) & 7;
788 code = (m_hud_ram[offs] >> 9) & 0x7f;
789 colour = 0x200 + ((m_hud_ram[offs + 1] >> 9) & 7);
790 layout = (code >> 5) & 3;
791
792 rom_a12_7 = (code & 0xfe) << 6;
793
794 /* Account for line buffering */
795 y_pos -= 1;
796
797 if (layout == 3)
798 y_size = 32;
799 else if (layout == 2)
800 y_size = 16;
801 else
802 y_size = 8;
803
804 for (uint32_t y = cliprect.min_y; y <= cliprect.max_y; ++y)
805 {
806 uint32_t xt;
807 uint32_t cy;
808
809 cy = y_pos + y;
810
811 if (cy < 0x200)
812 continue;
813
814 if ((cy & 0xff) == y_size)
815 break;
816
817 for (xt = 0; xt <= x_size; ++xt)
818 {
819 uint32_t rom_a6_3;
820 uint32_t px;
821 uint8_t gfx_strip;
822
823 if (layout == 3)
824 rom_a6_3 = (BIT(cy, 4) << 3) | (BIT(cy, 3) << 2) | (BIT(xt, 1) << 1) | BIT(xt, 0);
825 else if (layout == 2)
826 rom_a6_3 = ((BIT(code, 0) << 3) | (BIT(xt, 1) << 2) | (BIT(cy, 3) << 1) | (BIT(xt, 0)));
827 else
828 rom_a6_3 = (BIT(code, 0) << 3) | (xt & 7);
829
830 rom_a6_3 <<= 3;
831
832 /* Get tile data */
833 gfx_strip = tile_rom[rom_a12_7 | rom_a6_3 | (cy & 7)];
834
835 if (gfx_strip == 0)
836 continue;
837
838 /* Draw */
839 for (px = 0; px < 8; ++px)
840 {
841 uint32_t x = x_pos + (xt << 3) + px;
842
843 if (x <= cliprect.max_x)
844 {
845 uint16_t *const dst = &bitmap.pix(y, x);
846
847 if (BIT(gfx_strip, px ^ 7) && *dst > 255)
848 *dst = colour;
849 }
850 }
851 }
852 }
853 }
854 }
855
856
857 /*************************************
858 *
859 * Driver video handlers
860 *
861 *************************************/
862
video_start()863 void lockon_state::video_start()
864 {
865 m_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(lockon_state::get_lockon_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
866 m_tilemap->set_transparent_pen(0);
867
868 /* Allocate the two frame buffers for rotation */
869 m_back_buffer = std::make_unique<bitmap_ind16>(512, 512);
870 m_front_buffer = std::make_unique<bitmap_ind16>(512, 512);
871
872 /* 2kB of object ASIC palette RAM */
873 m_obj_pal_ram = std::make_unique<uint8_t[]>(2048);
874
875 /* Timer for ground display list callback */
876 m_bufend_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(lockon_state::bufend_callback),this));
877
878 /* Timer for the CRTC cursor pulse */
879 m_cursor_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(lockon_state::cursor_callback),this));
880 m_cursor_timer->adjust(m_screen->time_until_pos(CURSOR_YPOS, CURSOR_XPOS));
881
882 save_item(NAME(*m_back_buffer));
883 save_item(NAME(*m_front_buffer));
884 save_pointer(NAME(m_obj_pal_ram), 2048);
885 }
886
screen_update_lockon(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)887 uint32_t lockon_state::screen_update_lockon(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
888 {
889 /* If screen output is disabled, fill with black */
890 if (!BIT(m_ctrl_reg, 7))
891 {
892 bitmap.fill(m_palette->black_pen(), cliprect);
893 return 0;
894 }
895
896 /* Scan out the frame buffer in rotated order */
897 rotate_draw(bitmap, cliprect);
898
899 /* Draw the character tilemap */
900 m_tilemap->draw(screen, bitmap, cliprect, 0, 0);
901
902 /* Draw the HUD */
903 hud_draw(bitmap, cliprect);
904
905 return 0;
906 }
907
WRITE_LINE_MEMBER(lockon_state::screen_vblank_lockon)908 WRITE_LINE_MEMBER(lockon_state::screen_vblank_lockon)
909 {
910 // on falling edge
911 if (!state)
912 {
913 /* Swap the frame buffers */
914 m_front_buffer.swap(m_back_buffer);
915
916 /* Draw the frame buffer layers */
917 scene_draw();
918 ground_draw();
919 objects_draw();
920 }
921 }
922