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