1 /*************************************************************************
2
3 Driver for Midway T-unit games.
4
5 **************************************************************************/
6
7 #include "driver.h"
8 #include "cpu/tms34010/tms34010.h"
9 #include "cpu/tms34010/34010ops.h"
10 #include "midtunit.h"
11
12
13 /* compile-time options */
14 #define FAST_DMA 0 /* DMAs complete immediately; reduces number of CPU switches */
15 #define LOG_DMA 0 /* DMAs are logged if the 'L' key is pressed */
16
17
18 /* constants for the DMA chip */
19 enum
20 {
21 DMA_LRSKIP = 0,
22 DMA_COMMAND,
23 DMA_OFFSETLO,
24 DMA_OFFSETHI,
25 DMA_XSTART,
26 DMA_YSTART,
27 DMA_WIDTH,
28 DMA_HEIGHT,
29 DMA_PALETTE,
30 DMA_COLOR,
31 DMA_SCALE_X,
32 DMA_SCALE_Y,
33 DMA_TOPCLIP,
34 DMA_BOTCLIP,
35 DMA_UNKNOWN_E, /* MK1/2 never write here; NBA only writes 0 */
36 DMA_CONFIG,
37 DMA_LEFTCLIP, /* pseudo-register */
38 DMA_RIGHTCLIP /* pseudo-register */
39 };
40
41
42
43 /* graphics-related variables */
44 UINT8 midtunit_gfx_rom_large;
45 static data16_t midtunit_control;
46 static UINT8 midtunit_using_34020;
47
48 /* videoram-related variables */
49 static UINT32 gfxbank_offset[2];
50 static UINT16 * local_videoram;
51 static UINT8 videobank_select;
52
53 /* DMA-related variables */
54 static data16_t dma_register[18];
55 static struct
56 {
57 UINT32 offset; /* source offset, in bits */
58 INT32 rowbits; /* source bits to skip each row */
59 INT32 xpos; /* x position, clipped */
60 INT32 ypos; /* y position, clipped */
61 INT32 width; /* horizontal pixel count */
62 INT32 height; /* vertical pixel count */
63 UINT16 palette; /* palette base */
64 UINT16 color; /* current foreground color with palette */
65
66 UINT8 yflip; /* yflip? */
67 UINT8 bpp; /* bits per pixel */
68 UINT8 preskip; /* preskip scale */
69 UINT8 postskip; /* postskip scale */
70 INT32 topclip; /* top clipping scanline */
71 INT32 botclip; /* bottom clipping scanline */
72 INT32 leftclip; /* left clipping column */
73 INT32 rightclip; /* right clipping column */
74 INT32 startskip; /* pixels to skip at start */
75 INT32 endskip; /* pixels to skip at end */
76 UINT16 xstep; /* 8.8 fixed number scale x factor */
77 UINT16 ystep; /* 8.8 fixed number scale y factor */
78 } dma_state;
79
80
81
82 /* macros */
83 #define TMS_SET_IRQ_LINE(x) \
84 if (midtunit_using_34020) \
85 tms34020_set_irq_line(0, x); \
86 else \
87 tms34010_set_irq_line(0, x); \
88
89
90
91 /*************************************
92 *
93 * Video startup
94 *
95 *************************************/
96
VIDEO_START(midtunit)97 VIDEO_START( midtunit )
98 {
99 /* allocate memory */
100 local_videoram = auto_malloc(0x100000);
101
102 /* handle failure */
103 if (!local_videoram)
104 return 1;
105
106 /* reset all the globals */
107 gfxbank_offset[0] = 0x000000;
108 gfxbank_offset[1] = 0x400000;
109
110 memset(dma_register, 0, sizeof(dma_register));
111 memset(&dma_state, 0, sizeof(dma_state));
112
113 midtunit_using_34020 = 0;
114 return 0;
115 }
116
117
VIDEO_START(midwunit)118 VIDEO_START( midwunit )
119 {
120 int result = video_start_midtunit();
121 midtunit_gfx_rom_large = 1;
122 return result;
123 }
124
125
VIDEO_START(midxunit)126 VIDEO_START( midxunit )
127 {
128 int result = video_start_midtunit();
129 midtunit_gfx_rom_large = 1;
130 midtunit_using_34020 = 1;
131 videobank_select = 1;
132 return result;
133 }
134
135
136
137 /*************************************
138 *
139 * Banked graphics ROM access
140 *
141 *************************************/
142
READ16_HANDLER(midtunit_gfxrom_r)143 READ16_HANDLER( midtunit_gfxrom_r )
144 {
145 UINT8 *base = &midyunit_gfx_rom[gfxbank_offset[(offset >> 21) & 1]];
146 offset = (offset & 0x01fffff) * 2;
147 return base[offset] | (base[offset + 1] << 8);
148 }
149
150
READ16_HANDLER(midwunit_gfxrom_r)151 READ16_HANDLER( midwunit_gfxrom_r )
152 {
153 UINT8 *base = &midyunit_gfx_rom[gfxbank_offset[0]];
154 offset *= 2;
155 return base[offset] | (base[offset + 1] << 8);
156 }
157
158
159
160 /*************************************
161 *
162 * Video RAM read/write
163 *
164 *************************************/
165
WRITE16_HANDLER(midtunit_vram_w)166 WRITE16_HANDLER( midtunit_vram_w )
167 {
168 offset *= 2;
169 if (videobank_select)
170 {
171 if (ACCESSING_LSB)
172 local_videoram[offset] = (data & 0xff) | ((dma_register[DMA_PALETTE] & 0xff) << 8);
173 if (ACCESSING_MSB)
174 local_videoram[offset + 1] = ((data >> 8) & 0xff) | (dma_register[DMA_PALETTE] & 0xff00);
175 }
176 else
177 {
178 if (ACCESSING_LSB)
179 local_videoram[offset] = (local_videoram[offset] & 0xff) | ((data & 0xff) << 8);
180 if (ACCESSING_MSB)
181 local_videoram[offset + 1] = (local_videoram[offset + 1] & 0xff) | (data & 0xff00);
182 }
183 }
184
185
WRITE16_HANDLER(midtunit_vram_data_w)186 WRITE16_HANDLER( midtunit_vram_data_w )
187 {
188 offset *= 2;
189 if (ACCESSING_LSB)
190 local_videoram[offset] = (data & 0xff) | ((dma_register[DMA_PALETTE] & 0xff) << 8);
191 if (ACCESSING_MSB)
192 local_videoram[offset + 1] = ((data >> 8) & 0xff) | (dma_register[DMA_PALETTE] & 0xff00);
193 }
194
195
WRITE16_HANDLER(midtunit_vram_color_w)196 WRITE16_HANDLER( midtunit_vram_color_w )
197 {
198 offset *= 2;
199 if (ACCESSING_LSB)
200 local_videoram[offset] = (local_videoram[offset] & 0xff) | ((data & 0xff) << 8);
201 if (ACCESSING_MSB)
202 local_videoram[offset + 1] = (local_videoram[offset + 1] & 0xff) | (data & 0xff00);
203 }
204
205
READ16_HANDLER(midtunit_vram_r)206 READ16_HANDLER( midtunit_vram_r )
207 {
208 offset *= 2;
209 if (videobank_select)
210 return (local_videoram[offset] & 0x00ff) | (local_videoram[offset + 1] << 8);
211 else
212 return (local_videoram[offset] >> 8) | (local_videoram[offset + 1] & 0xff00);
213 }
214
215
READ16_HANDLER(midtunit_vram_data_r)216 READ16_HANDLER( midtunit_vram_data_r )
217 {
218 offset *= 2;
219 return (local_videoram[offset] & 0x00ff) | (local_videoram[offset + 1] << 8);
220 }
221
222
READ16_HANDLER(midtunit_vram_color_r)223 READ16_HANDLER( midtunit_vram_color_r )
224 {
225 offset *= 2;
226 return (local_videoram[offset] >> 8) | (local_videoram[offset + 1] & 0xff00);
227 }
228
229
230
231 /*************************************
232 *
233 * Shift register read/write
234 *
235 *************************************/
236
midtunit_to_shiftreg(UINT32 address,UINT16 * shiftreg)237 void midtunit_to_shiftreg(UINT32 address, UINT16 *shiftreg)
238 {
239 memcpy(shiftreg, &local_videoram[address >> 3], 2 * 512 * sizeof(UINT16));
240 }
241
242
midtunit_from_shiftreg(UINT32 address,UINT16 * shiftreg)243 void midtunit_from_shiftreg(UINT32 address, UINT16 *shiftreg)
244 {
245 memcpy(&local_videoram[address >> 3], shiftreg, 2 * 512 * sizeof(UINT16));
246 }
247
248
249
250 /*************************************
251 *
252 * Control register
253 *
254 *************************************/
255
WRITE16_HANDLER(midtunit_control_w)256 WRITE16_HANDLER( midtunit_control_w )
257 {
258 /*
259 other important bits:
260 bit 2 (0x0004) is toggled periodically
261 */
262 log_cb(RETRO_LOG_DEBUG, LOGPRE "T-unit control = %04X\n", data);
263
264 COMBINE_DATA(&midtunit_control);
265
266 /* gfx bank select is bit 7 */
267 if (!(midtunit_control & 0x0080) || !midtunit_gfx_rom_large)
268 gfxbank_offset[0] = 0x000000;
269 else
270 gfxbank_offset[0] = 0x800000;
271
272 /* video bank select is bit 5 */
273 videobank_select = (midtunit_control >> 5) & 1;
274 }
275
276
WRITE16_HANDLER(midwunit_control_w)277 WRITE16_HANDLER( midwunit_control_w )
278 {
279 /*
280 other important bits:
281 bit 2 (0x0004) is toggled periodically
282 */
283 log_cb(RETRO_LOG_DEBUG, LOGPRE "Wolf-unit control = %04X\n", data);
284
285 COMBINE_DATA(&midtunit_control);
286
287 /* gfx bank select is bits 8-9 */
288 gfxbank_offset[0] = 0x800000 * ((midtunit_control >> 8) & 3);
289
290 /* video bank select is unknown */
291 videobank_select = (midtunit_control >> 11) & 1;
292 }
293
294
READ16_HANDLER(midwunit_control_r)295 READ16_HANDLER( midwunit_control_r )
296 {
297 return midtunit_control;
298 }
299
300
301
302 /*************************************
303 *
304 * Palette handlers
305 *
306 *************************************/
307
WRITE16_HANDLER(midtunit_paletteram_w)308 WRITE16_HANDLER( midtunit_paletteram_w )
309 {
310 int newword, r, g, b;
311
312 COMBINE_DATA(&paletteram16[offset]);
313 newword = paletteram16[offset];
314
315 r = (newword >> 10) & 0x1f;
316 g = (newword >> 5) & 0x1f;
317 b = (newword ) & 0x1f;
318
319 r = (r << 3) | (r >> 2);
320 g = (g << 3) | (g >> 2);
321 b = (b << 3) | (b >> 2);
322
323 palette_set_color(offset, r, g, b);
324 }
325
326
WRITE16_HANDLER(midxunit_paletteram_w)327 WRITE16_HANDLER( midxunit_paletteram_w )
328 {
329 if (!(offset & 1))
330 midtunit_paletteram_w(offset / 2, data, mem_mask);
331 }
332
333
READ16_HANDLER(midxunit_paletteram_r)334 READ16_HANDLER( midxunit_paletteram_r )
335 {
336 return paletteram16_word_r(offset / 2, 0);
337 }
338
339
340
341 /*************************************
342 *
343 * DMA drawing routines
344 *
345 *************************************/
346
347 /*** constant definitions ***/
348 #define PIXEL_SKIP 0
349 #define PIXEL_COLOR 1
350 #define PIXEL_COPY 2
351
352 #define XFLIP_NO 0
353 #define XFLIP_YES 1
354
355 #define SKIP_NO 0
356 #define SKIP_YES 1
357
358 #define SCALE_NO 0
359 #define SCALE_YES 1
360
361 #define XPOSMASK 0x3ff
362 #define YPOSMASK 0x1ff
363
364
365 typedef void (*dma_draw_func)(void);
366
367
368 /*** fast pixel extractors ***/
369 #if !defined(ALIGN_SHORTS) && !defined(MSB_FIRST)
370 #define EXTRACTGEN(m) ((*(UINT16 *)&base[o >> 3] >> (o & 7)) & (m))
371 #elif defined(powerc)
372 #define EXTRACTGEN(m) ((__lhbrx(base, o >> 3) >> (o & 7)) & (m))
373 #else
374 #define EXTRACTGEN(m) (((base[o >> 3] | (base[(o >> 3) + 1] << 8)) >> (o & 7)) & (m))
375 #endif
376
377 /*** core blitter routine macro ***/
378 #define DMA_DRAW_FUNC_BODY(name, bitsperpixel, extractor, xflip, skip, scale, zero, nonzero) \
379 { \
380 int height = dma_state.height << 8; \
381 UINT8 *base = midyunit_gfx_rom; \
382 UINT32 offset = dma_state.offset; \
383 UINT16 pal = dma_state.palette; \
384 UINT16 color = pal | dma_state.color; \
385 int sy = dma_state.ypos, iy = 0, ty; \
386 int bpp = bitsperpixel; \
387 int mask = (1 << bpp) - 1; \
388 int xstep = scale ? dma_state.xstep : 0x100; \
389 \
390 /* loop over the height */ \
391 while (iy < height) \
392 { \
393 int startskip = dma_state.startskip << 8; \
394 int endskip = dma_state.endskip << 8; \
395 int width = dma_state.width << 8; \
396 int sx = dma_state.xpos, ix = 0, tx; \
397 UINT32 o = offset; \
398 int pre, post; \
399 UINT16 *d; \
400 \
401 /* handle skipping */ \
402 if (skip) \
403 { \
404 UINT8 value = EXTRACTGEN(0xff); \
405 o += 8; \
406 \
407 /* adjust for preskip */ \
408 pre = (value & 0x0f) << (dma_state.preskip + 8); \
409 tx = pre / xstep; \
410 if (xflip) \
411 sx = (sx - tx) & XPOSMASK; \
412 else \
413 sx = (sx + tx) & XPOSMASK; \
414 ix += tx * xstep; \
415 \
416 /* adjust for postskip */ \
417 post = ((value >> 4) & 0x0f) << (dma_state.postskip + 8); \
418 width -= post; \
419 endskip -= post; \
420 } \
421 \
422 /* handle Y clipping */ \
423 if (sy < dma_state.topclip || sy > dma_state.botclip) \
424 goto clipy; \
425 \
426 /* handle start skip */ \
427 if (ix < startskip) \
428 { \
429 tx = ((startskip - ix) / xstep) * xstep; \
430 ix += tx; \
431 o += (tx >> 8) * bpp; \
432 } \
433 \
434 /* handle end skip */ \
435 if ((width >> 8) > dma_state.width - dma_state.endskip) \
436 width = (dma_state.width - dma_state.endskip) << 8; \
437 \
438 /* determine destination pointer */ \
439 d = &local_videoram[sy * 512]; \
440 \
441 /* loop until we draw the entire width */ \
442 while (ix < width) \
443 { \
444 /* only process if not clipped */ \
445 if (sx >= dma_state.leftclip && sx <= dma_state.rightclip) \
446 { \
447 /* special case similar handling of zero/non-zero */ \
448 if (zero == nonzero) \
449 { \
450 if (zero == PIXEL_COLOR) \
451 d[sx] = color; \
452 else if (zero == PIXEL_COPY) \
453 d[sx] = (extractor(mask)) | pal; \
454 } \
455 \
456 /* otherwise, read the pixel and look */ \
457 else \
458 { \
459 int pixel = (extractor(mask)); \
460 \
461 /* non-zero pixel case */ \
462 if (pixel) \
463 { \
464 if (nonzero == PIXEL_COLOR) \
465 d[sx] = color; \
466 else if (nonzero == PIXEL_COPY) \
467 d[sx] = pixel | pal; \
468 } \
469 \
470 /* zero pixel case */ \
471 else \
472 { \
473 if (zero == PIXEL_COLOR) \
474 d[sx] = color; \
475 else if (zero == PIXEL_COPY) \
476 d[sx] = pal; \
477 } \
478 } \
479 } \
480 \
481 /* update pointers */ \
482 if (xflip) \
483 sx = (sx - 1) & XPOSMASK; \
484 else \
485 sx = (sx + 1) & XPOSMASK; \
486 \
487 /* advance to the next pixel */ \
488 if (!scale) \
489 { \
490 ix += 0x100; \
491 o += bpp; \
492 } \
493 else \
494 { \
495 tx = ix >> 8; \
496 ix += xstep; \
497 tx = (ix >> 8) - tx; \
498 o += bpp * tx; \
499 } \
500 } \
501 \
502 clipy: \
503 /* advance to the next row */ \
504 if (dma_state.yflip) \
505 sy = (sy - 1) & YPOSMASK; \
506 else \
507 sy = (sy + 1) & YPOSMASK; \
508 if (!scale) \
509 { \
510 iy += 0x100; \
511 width = dma_state.width; \
512 if (skip) \
513 { \
514 offset += 8; \
515 width -= (pre + post) >> 8; \
516 if (width > 0) offset += width * bpp; \
517 } \
518 else \
519 offset += width * bpp; \
520 } \
521 else \
522 { \
523 ty = iy >> 8; \
524 iy += dma_state.ystep; \
525 ty = (iy >> 8) - ty; \
526 if (!skip) \
527 offset += ty * dma_state.width * bpp; \
528 else if (ty--) \
529 { \
530 o = offset + 8; \
531 width = dma_state.width - ((pre + post) >> 8); \
532 if (width > 0) o += width * bpp; \
533 while (ty--) \
534 { \
535 UINT8 value = EXTRACTGEN(0xff); \
536 o += 8; \
537 pre = (value & 0x0f) << dma_state.preskip; \
538 post = ((value >> 4) & 0x0f) << dma_state.postskip; \
539 width = dma_state.width - pre - post; \
540 if (width > 0) o += width * bpp; \
541 } \
542 offset = o; \
543 } \
544 } \
545 } \
546 }
547
548
549 /*** slightly simplified one for most blitters ***/
550 #define DMA_DRAW_FUNC(name, bpp, extract, xflip, skip, scale, zero, nonzero) \
551 static void name(void) \
552 { \
553 DMA_DRAW_FUNC_BODY(name, bpp, extract, xflip, skip, scale, zero, nonzero) \
554 }
555
556 /*** empty blitter ***/
dma_draw_none(void)557 static void dma_draw_none(void)
558 {
559 }
560
561 /*** super macro for declaring an entire blitter family ***/
562 #define DECLARE_BLITTER_SET(prefix, bpp, extract, skip, scale) \
563 DMA_DRAW_FUNC(prefix##_p0, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COPY, PIXEL_SKIP) \
564 DMA_DRAW_FUNC(prefix##_p1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_SKIP, PIXEL_COPY) \
565 DMA_DRAW_FUNC(prefix##_c0, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COLOR, PIXEL_SKIP) \
566 DMA_DRAW_FUNC(prefix##_c1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_SKIP, PIXEL_COLOR) \
567 DMA_DRAW_FUNC(prefix##_p0p1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COPY, PIXEL_COPY) \
568 DMA_DRAW_FUNC(prefix##_c0c1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COLOR, PIXEL_COLOR) \
569 DMA_DRAW_FUNC(prefix##_c0p1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COLOR, PIXEL_COPY) \
570 DMA_DRAW_FUNC(prefix##_p0c1, bpp, extract, XFLIP_NO, skip, scale, PIXEL_COPY, PIXEL_COLOR) \
571 \
572 DMA_DRAW_FUNC(prefix##_p0_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COPY, PIXEL_SKIP) \
573 DMA_DRAW_FUNC(prefix##_p1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_SKIP, PIXEL_COPY) \
574 DMA_DRAW_FUNC(prefix##_c0_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COLOR, PIXEL_SKIP) \
575 DMA_DRAW_FUNC(prefix##_c1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_SKIP, PIXEL_COLOR) \
576 DMA_DRAW_FUNC(prefix##_p0p1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COPY, PIXEL_COPY) \
577 DMA_DRAW_FUNC(prefix##_c0c1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COLOR, PIXEL_COLOR) \
578 DMA_DRAW_FUNC(prefix##_c0p1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COLOR, PIXEL_COPY) \
579 DMA_DRAW_FUNC(prefix##_p0c1_xf, bpp, extract, XFLIP_YES, skip, scale, PIXEL_COPY, PIXEL_COLOR) \
580 \
581 static dma_draw_func prefix[32] = \
582 { \
583 /* B0:N / B1:N B0:Y / B1:N B0:N / B1:Y B0:Y / B1:Y */ \
584 dma_draw_none, prefix##_p0, prefix##_p1, prefix##_p0p1, /* no color */ \
585 prefix##_c0, prefix##_c0, prefix##_c0p1, prefix##_c0p1, /* color 0 pixels */ \
586 prefix##_c1, prefix##_p0c1, prefix##_c1, prefix##_p0c1, /* color non-0 pixels */\
587 prefix##_c0c1, prefix##_c0c1, prefix##_c0c1, prefix##_c0c1, /* fill */ \
588 \
589 dma_draw_none, prefix##_p0_xf, prefix##_p1_xf, prefix##_p0p1_xf, /* no color */ \
590 prefix##_c0_xf, prefix##_c0_xf, prefix##_c0p1_xf, prefix##_c0p1_xf, /* color 0 pixels */ \
591 prefix##_c1_xf, prefix##_p0c1_xf, prefix##_c1_xf, prefix##_p0c1_xf, /* color non-0 pixels */\
592 prefix##_c0c1_xf, prefix##_c0c1_xf, prefix##_c0c1_xf, prefix##_c0c1_xf /* fill */ \
593 };
594
595
596 /* allow for custom blitters */
597 #ifdef midtunit_CUSTOM_BLITTERS
598 #include "midtblit.c"
599 #endif
600
601
602 /*** blitter family declarations ***/
603 DECLARE_BLITTER_SET(dma_draw_skip_scale, dma_state.bpp, EXTRACTGEN, SKIP_YES, SCALE_YES)
604 DECLARE_BLITTER_SET(dma_draw_noskip_scale, dma_state.bpp, EXTRACTGEN, SKIP_NO, SCALE_YES)
605 DECLARE_BLITTER_SET(dma_draw_skip_noscale, dma_state.bpp, EXTRACTGEN, SKIP_YES, SCALE_NO)
606 DECLARE_BLITTER_SET(dma_draw_noskip_noscale, dma_state.bpp, EXTRACTGEN, SKIP_NO, SCALE_NO)
607
608
609
610 /*************************************
611 *
612 * DMA finished callback
613 *
614 *************************************/
615
temp_irq_callback(int irqline)616 static int temp_irq_callback(int irqline)
617 {
618 TMS_SET_IRQ_LINE(CLEAR_LINE);
619 return 0;
620 }
621
622
dma_callback(int is_in_34010_context)623 static void dma_callback(int is_in_34010_context)
624 {
625 dma_register[DMA_COMMAND] &= ~0x8000; /* tell the cpu we're done */
626 if (is_in_34010_context)
627 {
628 if (midtunit_using_34020)
629 tms34020_set_irq_callback(temp_irq_callback);
630 else
631 tms34010_set_irq_callback(temp_irq_callback);
632 TMS_SET_IRQ_LINE(ASSERT_LINE);
633 }
634 else
635 cpu_set_irq_line(0, 0, HOLD_LINE);
636 }
637
638
639
640 /*************************************
641 *
642 * DMA reader
643 *
644 *************************************/
645
READ16_HANDLER(midtunit_dma_r)646 READ16_HANDLER( midtunit_dma_r )
647 {
648 /* rmpgwt sometimes reads register 0, expecting it to return the */
649 /* current DMA status; thus we map register 0 to register 1 */
650 /* openice does it as well */
651 if (offset == 0)
652 offset = 1;
653 return dma_register[offset];
654 }
655
656
657 /*************************************
658 *
659 * DMA write handler
660 *
661 *************************************/
662
663 /*
664 * DMA registers
665 * ------------------
666 *
667 * Register | Bit | Use
668 * ----------+-FEDCBA9876543210-+------------
669 * 0 | xxxxxxxx-------- | pixels to drop at the start of each row
670 * | --------xxxxxxxx | pixels to drop at the end of each row
671 * 1 | x--------------- | trigger write (or clear if zero)
672 * | -421------------ | image bpp (0=8)
673 * | ----84---------- | post skip size = (1<<x)
674 * | ------21-------- | pre skip size = (1<<x)
675 * | --------8------- | pre/post skip enable
676 * | ---------4------ | clipping enable
677 * | ----------2----- | flip y
678 * | -----------1---- | flip x
679 * | ------------8--- | blit nonzero pixels as color
680 * | -------------4-- | blit zero pixels as color
681 * | --------------2- | blit nonzero pixels
682 * | ---------------1 | blit zero pixels
683 * 2 | xxxxxxxxxxxxxxxx | source address low word
684 * 3 | xxxxxxxxxxxxxxxx | source address high word
685 * 4 | -------xxxxxxxxx | detination x
686 * 5 | -------xxxxxxxxx | destination y
687 * 6 | ------xxxxxxxxxx | image columns
688 * 7 | ------xxxxxxxxxx | image rows
689 * 8 | xxxxxxxxxxxxxxxx | palette
690 * 9 | xxxxxxxxxxxxxxxx | color
691 * 10 | ---xxxxxxxxxxxxx | scale x
692 * 11 | ---xxxxxxxxxxxxx | scale y
693 * 12 | -------xxxxxxxxx | top/left clip
694 * 13 | -------xxxxxxxxx | bottom/right clip
695 * 14 | ---------------- | test
696 * 15 | xxxxxxxx-------- | zero detect byte
697 * | --------8------- | extra page
698 * | ---------4------ | destination size
699 * | ----------2----- | select top/bottom or left/right for reg 12/13
700 */
701
WRITE16_HANDLER(midtunit_dma_w)702 WRITE16_HANDLER( midtunit_dma_w )
703 {
704 static const UINT8 register_map[2][16] =
705 {
706 { 0,1,2,3,4,5,6,7,8,9,10,11,16,17,14,15 },
707 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }
708 };
709 int regbank = (dma_register[DMA_CONFIG] >> 5) & 1;
710 int command, bpp, regnum;
711 UINT32 gfxoffset;
712 int pixels = 0;
713
714 /* blend with the current register contents */
715 regnum = register_map[regbank][offset];
716 COMBINE_DATA(&dma_register[regnum]);
717
718 /* only writes to DMA_COMMAND actually cause actions */
719 if (regnum != DMA_COMMAND)
720 return;
721
722 /* high bit triggers action */
723 command = dma_register[DMA_COMMAND];
724 if (!(command & 0x8000))
725 {
726 TMS_SET_IRQ_LINE(CLEAR_LINE);
727 return;
728 }
729
730 profiler_mark(PROFILER_USER1);
731
732 /* determine bpp */
733 bpp = (command >> 12) & 7;
734
735 /* fill in the basic data */
736 dma_state.xpos = dma_register[DMA_XSTART] & XPOSMASK;
737 dma_state.ypos = dma_register[DMA_YSTART] & YPOSMASK;
738 dma_state.width = dma_register[DMA_WIDTH] & 0x3ff;
739 dma_state.height = dma_register[DMA_HEIGHT] & 0x3ff;
740 dma_state.palette = dma_register[DMA_PALETTE] & 0x7f00;
741 dma_state.color = dma_register[DMA_COLOR] & 0xff;
742
743 /* fill in the rev 2 data */
744 dma_state.yflip = (command & 0x20) >> 5;
745 dma_state.bpp = bpp ? bpp : 8;
746 dma_state.preskip = (command >> 8) & 3;
747 dma_state.postskip = (command >> 10) & 3;
748 dma_state.xstep = dma_register[DMA_SCALE_X] ? dma_register[DMA_SCALE_X] : 0x100;
749 dma_state.ystep = dma_register[DMA_SCALE_Y] ? dma_register[DMA_SCALE_Y] : 0x100;
750
751 /* clip the clippers */
752 dma_state.topclip = dma_register[DMA_TOPCLIP] & 0x1ff;
753 dma_state.botclip = dma_register[DMA_BOTCLIP] & 0x1ff;
754 dma_state.leftclip = dma_register[DMA_LEFTCLIP] & 0x3ff;
755 dma_state.rightclip = dma_register[DMA_RIGHTCLIP] & 0x3ff;
756
757 /* determine the offset */
758 gfxoffset = dma_register[DMA_OFFSETLO] | (dma_register[DMA_OFFSETHI] << 16);
759
760 #if LOG_DMA
761 if (keyboard_pressed(KEYCODE_L))
762 {
763 logerror("DMA command %04X: (bpp=%d skip=%d xflip=%d yflip=%d preskip=%d postskip=%d)\n",
764 command, (command >> 12) & 7, (command >> 7) & 1, (command >> 4) & 1, (command >> 5) & 1, (command >> 8) & 3, (command >> 10) & 3);
765 logerror(" offset=%08X pos=(%d,%d) w=%d h=%d clip=(%d,%d)-(%d,%d)\n", gfxoffset, dma_register[DMA_XSTART], dma_register[DMA_YSTART],
766 dma_register[DMA_WIDTH], dma_register[DMA_HEIGHT], dma_register[DMA_LEFTCLIP], dma_register[DMA_TOPCLIP], dma_register[DMA_RIGHTCLIP], dma_register[DMA_BOTCLIP]);
767 logerror(" offset=%08X pos=(%d,%d) w=%d h=%d clip=(%d,%d)-(%d,%d)\n", gfxoffset, dma_state.xpos, dma_state.ypos,
768 dma_state.width, dma_state.height, dma_state.leftclip, dma_state.topclip, dma_state.rightclip, dma_state.botclip);
769 logerror(" palette=%04X color=%04X lskip=%02X rskip=%02X xstep=%04X ystep=%04X test=%04X config=%04X\n",
770 dma_register[DMA_PALETTE], dma_register[DMA_COLOR],
771 dma_register[DMA_LRSKIP] >> 8, dma_register[DMA_LRSKIP] & 0xff,
772 dma_register[DMA_SCALE_X], dma_register[DMA_SCALE_Y], dma_register[DMA_UNKNOWN_E],
773 dma_register[DMA_CONFIG]);
774 log_cb(RETRO_LOG_DEBUG, LOGPRE "----\n");
775 }
776 #endif
777
778 /* special case: drawing mode C doesn't need to know about any pixel data */
779 if ((command & 0x0f) == 0x0c)
780 gfxoffset = 0;
781
782 /* determine the location */
783 if (!midtunit_gfx_rom_large && gfxoffset >= 0x2000000)
784 gfxoffset -= 0x2000000;
785 if (gfxoffset >= 0xf8000000)
786 gfxoffset -= 0xf8000000;
787 if (gfxoffset < 0x10000000)
788 dma_state.offset = gfxoffset;
789 else
790 {
791 log_cb(RETRO_LOG_DEBUG, LOGPRE "DMA source out of range: %08X\n", gfxoffset);
792 goto skipdma;
793 }
794
795 /* there seems to be two types of behavior for the DMA chip */
796 /* for MK1 and MK2, the upper byte of the LRSKIP is the */
797 /* starting skip value, and the lower byte is the ending */
798 /* skip value; for the NBA Jam, Hangtime, and Open Ice, the */
799 /* full word seems to be the starting skip value. */
800 if (command & 0x40)
801 {
802 dma_state.startskip = dma_register[DMA_LRSKIP] & 0xff;
803 dma_state.endskip = dma_register[DMA_LRSKIP] >> 8;
804 }
805 else
806 {
807 dma_state.startskip = 0;
808 dma_state.endskip = dma_register[DMA_LRSKIP];
809 }
810
811 /* then draw */
812 if (dma_state.xstep == 0x100 && dma_state.ystep == 0x100)
813 {
814 if (command & 0x80)
815 (*dma_draw_skip_noscale[command & 0x1f])();
816 else
817 (*dma_draw_noskip_noscale[command & 0x1f])();
818
819 pixels = dma_state.width * dma_state.height;
820 }
821 else
822 {
823 if (command & 0x80)
824 (*dma_draw_skip_scale[command & 0x1f])();
825 else
826 (*dma_draw_noskip_scale[command & 0x1f])();
827
828 if (dma_state.xstep && dma_state.ystep)
829 pixels = ((dma_state.width << 8) / dma_state.xstep) * ((dma_state.height << 8) / dma_state.ystep);
830 else
831 pixels = 0;
832 }
833
834 /* signal we're done */
835 skipdma:
836
837 /* special case for Open Ice: use a timer for command 0x8000, which is */
838 /* used to initiate the DMA. What they do is start the DMA, *then* set */
839 /* up the memory for it, which means that there must be some non-zero */
840 /* delay that gives them enough time to build up the DMA command list */
841 if (options.activate_dcs_speedhack)
842 {
843 if (command != 0x8000)
844 dma_callback(1);
845 else
846 {
847 TMS_SET_IRQ_LINE(CLEAR_LINE);
848 timer_set(TIME_IN_NSEC(41 * pixels), 0, dma_callback);
849 }
850 }
851 else
852 {
853 TMS_SET_IRQ_LINE(CLEAR_LINE);
854 timer_set(TIME_IN_NSEC(41 * pixels), 0, dma_callback);
855 }
856
857 profiler_mark(PROFILER_END);
858 }
859
860
861
862 /*************************************
863 *
864 * Core refresh routine
865 *
866 *************************************/
867
VIDEO_UPDATE(midtunit)868 VIDEO_UPDATE( midtunit )
869 {
870 int v, width, xoffs, dpytap;
871 UINT32 offset;
872
873 #if LOG_DMA
874 if (keyboard_pressed(KEYCODE_L))
875 log_cb(RETRO_LOG_DEBUG, LOGPRE "---\n");
876 #endif
877
878 /* get the current scroll offset */
879 cpuintrf_push_context(0);
880 dpytap = tms34010_io_register_r(REG_DPYTAP, 0) & 0x3fff;
881 cpuintrf_pop_context();
882
883 /* determine the base of the videoram */
884 if (midtunit_using_34020)
885 offset = (tms34020_get_DPYSTRT(0) >> 3) & 0x3ffff;
886 else
887 offset = ((~tms34010_get_DPYSTRT(0) & 0x1ff0) << 5) & 0x3ffff;
888 offset += dpytap * 2;
889
890 /* determine how many pixels to copy */
891 xoffs = cliprect->min_x;
892 width = cliprect->max_x - xoffs + 1;
893
894 /* adjust the offset */
895 offset += xoffs;
896 offset += 512 * cliprect->min_y;
897 offset &= 0x3ffff;
898
899 /* loop over rows */
900 for (v = cliprect->min_y; v <= cliprect->max_y; v++)
901 {
902 const uint16_t *src = &local_videoram[offset];
903 UINT16 *dst = (UINT16 *)bitmap->base + v * bitmap->rowpixels + xoffs;
904 int length = width;
905
906 while (length--)
907 *dst++ = *src++;
908
909 offset = (offset + 512) & 0x3ffff;
910 }
911 }
912