1 // Based on MAME sources by Sean Young, Nathan Woods, Aaron Giles, Wilbert Pol, and hap
2 
3 #include "tiles_generic.h"
4 #include "tms9928a.h"
5 
6 /* Some defines used in defining the screens */
7 #define TMS9928A_TOTAL_HORZ                 342
8 #define TMS9928A_TOTAL_VERT_NTSC            262
9 #define TMS9928A_TOTAL_VERT_PAL             313
10 
11 #define TMS9928A_HORZ_DISPLAY_START         (2 + 14 + 8 + 13)
12 #define TMS9928A_VERT_DISPLAY_START_PAL     (13 + 51)
13 #define TMS9928A_VERT_DISPLAY_START_NTSC    (13 + 27)
14 
15 static INT32 TMS9928A_palette[16] = {
16 	0x000000, 0x000000, 0x21c842, 0x5edc78, 0x5455ed, 0x7d76fc, 0xd4524d, 0x42ebf5,
17 	0xfc5554, 0xff7978, 0xd4c154, 0xe6ce80, 0x21b03b, 0xc95bba, 0xcccccc, 0xffffff
18 };
19 
20 typedef struct {
21 	UINT8 mode;
22 	UINT8 ReadAhead;
23 	UINT8 Regs[8];
24 	UINT8 StatusReg;
25 	UINT8 FifthSprite;
26 	UINT8 FirstByte;
27 	UINT8 latch;
28 	UINT8 INT;
29 	INT32 Addr;
30 	INT32 colour;
31 	INT32 pattern;
32 	INT32 nametbl;
33 	INT32 spriteattribute;
34 	INT32 spritepattern;
35 	INT32 colourmask;
36 	INT32 patternmask;
37 
38 	UINT8 *vMem;
39 	UINT16 *tmpbmp;
40 	INT32 tmpbmpsize;
41 	INT32 vramsize;
42 	INT32 model;
43 	INT32 revA;
44 
45 	INT32 LimitSprites;
46 	INT32 top_border;
47 	//INT32 bottom_border;
48 	INT32 vertical_size;
49 
50 	void (*INTCallback)(INT32);
51 } TMS9928A;
52 
53 static TMS9928A tms;
54 
55 static INT32 TMS9928A_initted = 0;
56 
57 static UINT32 Palette[16]; // high color support
58 
TMS89928aPaletteRecalc()59 static void TMS89928aPaletteRecalc()
60 {
61 	for (INT32 i = 0; i < 16; i++) {
62 		Palette[i] = BurnHighCol(TMS9928A_palette[i] >> 16, TMS9928A_palette[i] >> 8, TMS9928A_palette[i] >> 0 , 0);
63 	}
64 }
65 
check_interrupt()66 static void check_interrupt()
67 {
68 	INT32 b = (tms.StatusReg & 0x80 && tms.Regs[1] & 0x20) ? 1 : 0;
69 	if (b != tms.INT) {
70 		tms.INT = b;
71 		if (tms.INTCallback) tms.INTCallback (tms.INT);
72 	}
73 }
74 
update_table_masks()75 static void update_table_masks()
76 {
77 	tms.colourmask = (tms.Regs[3] & 0x7f) * 8 | 7;
78 	tms.patternmask = (tms.Regs[4] & 3) * 256 |	(tms.colourmask & 0xff);
79 }
80 
change_register(INT32 reg,UINT8 val)81 static void change_register(INT32 reg, UINT8 val)
82 {
83 	static const UINT8 Mask[8] = { 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff };
84 
85 	val &= Mask[reg];
86 	tms.Regs[reg] = val;
87 
88 	switch (reg)
89 	{
90 		case 0:
91 		{
92 			if (val & 2) {
93 				tms.colour = ((tms.Regs[3] & 0x80) * 64) & (tms.vramsize - 1);
94 				tms.pattern = ((tms.Regs[4] & 4) * 2048) & (tms.vramsize - 1);
95 				update_table_masks();
96 			} else {
97 				tms.colour = (tms.Regs[3] * 64) & (tms.vramsize - 1);
98 				tms.pattern = (tms.Regs[4] * 2048) & (tms.vramsize - 1);
99 			}
100 			tms.mode = ( (tms.revA ? (tms.Regs[0] & 2) : 0) | ((tms.Regs[1] & 0x10)>>4) | ((tms.Regs[1] & 8)>>1));
101 		}
102 		break;
103 
104 		case 1:
105 		{
106 			tms.mode = ( (tms.revA ? (tms.Regs[0] & 2) : 0) | ((tms.Regs[1] & 0x10)>>4) | ((tms.Regs[1] & 8)>>1));
107 			check_interrupt();
108 		}
109 		break;
110 
111 		case 2:
112 			tms.nametbl = (val * 1024) & (tms.vramsize - 1);
113 		break;
114 
115 		case 3:
116 		{
117 			if (tms.Regs[0] & 2) {
118 				tms.colour = ((val & 0x80) * 64) & (tms.vramsize - 1);
119 				update_table_masks();
120 			} else {
121 				tms.colour = (val * 64) & (tms.vramsize - 1);
122 			}
123 		}
124 		break;
125 
126 		case 4:
127 		{
128 			if (tms.Regs[0] & 2) {
129 				tms.pattern = ((val & 4) * 2048) & (tms.vramsize - 1);
130 				update_table_masks();
131 			} else {
132 				tms.pattern = (val * 2048) & (tms.vramsize - 1);
133 			}
134 		}
135 		break;
136 
137 		case 5:
138 			tms.spriteattribute = (val * 128) & (tms.vramsize - 1);
139 		break;
140 
141 		case 6:
142 			tms.spritepattern = (val * 2048) & (tms.vramsize - 1);
143 		break;
144 
145 		case 7:
146 			/* The backdrop is updated at TMS9928A_refresh() */
147 		break;
148 	}
149 }
150 
TMS9928AReset()151 void TMS9928AReset()
152 {
153 	for (INT32 i = 0; i < 8; i++)
154 		tms.Regs[i] = 0;
155 
156 	memset(tms.vMem, 0, tms.vramsize);
157 	memset(tms.tmpbmp, 0, tms.tmpbmpsize);
158 
159 	tms.StatusReg = 0;
160 	tms.FifthSprite = 31;
161 	tms.nametbl = tms.pattern = tms.colour = 0;
162 	tms.spritepattern = tms.spriteattribute = 0;
163 	tms.colourmask = tms.patternmask = 0x3fff;
164 	tms.Addr = tms.ReadAhead = tms.INT = 0;
165 	tms.FirstByte = 0;
166 	tms.latch = 0;
167 	tms.mode = 0;
168 }
169 
TMS9928AInit(INT32 model,INT32 vram,INT32 borderx,INT32 bordery,void (* INTCallback)(int))170 void TMS9928AInit(INT32 model, INT32 vram, INT32 borderx, INT32 bordery, void (*INTCallback)(int))
171 {
172 	TMS9928A_initted = 1;
173 
174 	GenericTilesInit();
175 
176 	memset(&tms, 0, sizeof(tms));
177 	tms.model = model;
178 	tms.revA = (tms.model == TMS99x8A || tms.model == TMS9929A);
179 
180 	tms.INTCallback = INTCallback;
181 
182 	INT32 is50hz = ((tms.model == TMS9929) || (tms.model == TMS9929A));
183 
184 	tms.top_border		= (is50hz) ? TMS9928A_VERT_DISPLAY_START_PAL : TMS9928A_VERT_DISPLAY_START_NTSC;
185 	//tms.bottom_border	= (is50hz) ? 51 : 24;
186 	tms.vertical_size   = (is50hz) ? TMS9928A_TOTAL_VERT_PAL : TMS9928A_TOTAL_VERT_NTSC;
187 
188 	tms.vramsize = vram;
189 	tms.vMem = (UINT8*)BurnMalloc(tms.vramsize);
190 
191 	tms.tmpbmpsize = TMS9928A_TOTAL_HORZ * TMS9928A_TOTAL_VERT_PAL * sizeof(short) * 2;
192 	tms.tmpbmp = (UINT16*)BurnMalloc(tms.tmpbmpsize);
193 
194 	TMS9928AReset ();
195 	tms.LimitSprites = 1;
196 }
197 
TMS9928AExit()198 void TMS9928AExit()
199 {
200 	if (!TMS9928A_initted) return;
201 
202 	TMS9928A_initted = 0;
203 	TMS9928AReset();
204 
205 	GenericTilesExit();
206 
207 	BurnFree (tms.tmpbmp);
208 	BurnFree (tms.vMem);
209 }
210 
TMS9928APostLoad()211 void TMS9928APostLoad()
212 {
213 	for (INT32 i = 0; i < 8; i++)
214 		change_register(i, tms.Regs[i]);
215 
216 	if (tms.INTCallback) tms.INTCallback(tms.INT);
217 }
218 
TMS9928AReadVRAM()219 UINT8 TMS9928AReadVRAM()
220 {
221 	INT32 b = tms.ReadAhead;
222 	tms.ReadAhead = tms.vMem[tms.Addr];
223 	tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
224 	tms.latch = 0;
225 	return b;
226 }
227 
TMS9928AWriteVRAM(INT32 data)228 void TMS9928AWriteVRAM(INT32 data)
229 {
230 	tms.vMem[tms.Addr] = data;
231 	tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
232 	tms.ReadAhead = data;
233 	tms.latch = 0;
234 }
235 
TMS9928AReadRegs()236 UINT8 TMS9928AReadRegs()
237 {
238 	INT32 b = tms.StatusReg;
239 	tms.StatusReg = tms.FifthSprite;
240 	check_interrupt();
241 	tms.latch = 0;
242 	return b;
243 }
244 
TMS9928AWriteRegs(INT32 data)245 void TMS9928AWriteRegs(INT32 data)
246 {
247 	if (tms.latch) {
248 		/* set high part of read/write address */
249 		tms.Addr = ((UINT16)data << 8 | (tms.Addr & 0xff)) & (tms.vramsize - 1);
250 		if (data & 0x80) {
251 			change_register(data & 0x07, tms.FirstByte);
252 		} else {
253 			if (!(data & 0x40)) {
254 				TMS9928AReadVRAM();
255 			}
256 		}
257 
258 		tms.latch = 0;
259 	} else {
260 		/* set low part of read/write address */
261 		tms.Addr = ((tms.Addr & 0xff00) | data) & (tms.vramsize - 1);
262 		tms.FirstByte = data;
263 		tms.latch = 1;
264 	}
265 }
266 
TMS9928ASetSpriteslimit(INT32 limit)267 void TMS9928ASetSpriteslimit(INT32 limit)
268 {
269 	tms.LimitSprites = limit; /* on or off! -dink */
270 }
271 
readvmem(INT32 vaddr)272 static inline UINT8 readvmem(INT32 vaddr)
273 {
274 	return tms.vMem[vaddr];
275 }
276 
TMS9928AScanline_INT(INT32 vpos)277 static void TMS9928AScanline_INT(INT32 vpos)
278 {
279 	UINT16 BackColour = tms.Regs[7] & 0xf;
280 	UINT16 *p = tms.tmpbmp + (vpos * TMS9928A_TOTAL_HORZ);
281 
282 	INT32 y = vpos - tms.top_border;
283 
284 	if ( y < 0 || y >= 192 || !(tms.Regs[1] & 0x40) )
285 	{
286 		/* Draw backdrop colour */
287 		for ( INT32 i = 0; i < TMS9928A_TOTAL_HORZ; i++ )
288 			p[i] = BackColour;
289 
290 		/* vblank is set at the last cycle of the first inactive line */
291 		if ( y == 193 )
292 		{
293 			tms.StatusReg |= 0x80;
294 			check_interrupt();
295 		}
296 	}
297 	else
298 	{
299 		/* Draw regular line */
300 
301 		/* Left border */
302 		for ( INT32 i = 0; i < TMS9928A_HORZ_DISPLAY_START; i++ )
303 			p[i] = BackColour;
304 
305 		/* Active display */
306 
307 		switch( tms.mode )
308 		{
309 		case 0:             /* MODE 0 */
310 			{
311 				UINT16 addr = tms.nametbl + ( ( y & 0xF8 ) << 2 );
312 
313 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
314 				{
315 					UINT8 charcode = readvmem( addr );
316 					UINT8 pattern =  readvmem( tms.pattern + ( charcode << 3 ) + ( y & 7 ) );
317 					UINT8 colour =  readvmem( tms.colour + ( charcode >> 3 ) );
318 					UINT16 fg = (colour >> 4) ? (colour >> 4) : BackColour;
319 					UINT16 bg = (colour & 15) ? (colour & 15) : BackColour;
320 
321 					for ( INT32 i = 0; i < 8; pattern <<= 1, i++ )
322 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
323 				}
324 			}
325 			break;
326 
327 		case 1:             /* MODE 1 */
328 			{
329 				UINT16 addr = tms.nametbl + ( ( y >> 3 ) * 40 );
330 				UINT16 fg = (tms.Regs[7] >> 4) ? (tms.Regs[7] >> 4) : BackColour;
331 				UINT16 bg = BackColour;
332 
333 				/* Extra 6 pixels left border */
334 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 6; x++ )
335 					p[x] = bg;
336 
337 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START + 6; x < TMS9928A_HORZ_DISPLAY_START + 246; x+= 6, addr++ )
338 				{
339 					UINT16 charcode =  readvmem( addr );
340 					UINT8 pattern =  readvmem( tms.pattern + ( charcode << 3 ) + ( y & 7 ) );
341 
342 					for ( INT32 i = 0; i < 6; pattern <<= 1, i++ )
343 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
344 				}
345 
346 				/* Extra 10 pixels right border */
347 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START + 246; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ )
348 					p[x] = bg;
349 			}
350 			break;
351 
352 		case 2:             /* MODE 2 */
353 			{
354 				UINT16 addr = tms.nametbl + ( ( y >> 3 ) * 32 );
355 
356 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
357 				{
358 					UINT16 charcode =  readvmem( addr ) + ( ( y >> 6 ) << 8 );
359 					UINT8 pattern =  readvmem( tms.pattern + ( ( charcode & tms.patternmask ) << 3 ) + ( y & 7 ) );
360 					UINT8 colour =  readvmem( tms.colour + ( ( charcode & tms.colourmask ) << 3 ) + ( y & 7 ) );
361 					UINT16 fg = (colour >> 4) ? (colour >> 4) : BackColour;
362 					UINT16 bg = (colour & 15) ? (colour & 15) : BackColour;
363 
364 					for ( INT32 i = 0; i < 8; pattern <<= 1, i++ )
365 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
366 				}
367 			}
368 			break;
369 
370 		case 3:             /* MODE 1+2 */
371 			{
372 				UINT16 addr = tms.nametbl + ( ( y >> 3 ) * 40 );
373 				UINT16 fg = (tms.Regs[7] >> 4) ? (tms.Regs[7] >> 4) : BackColour;
374 				UINT16 bg = BackColour;
375 
376 				/* Extra 6 pixels left border */
377 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 6; x++ )
378 					p[x] = bg;
379 
380 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START + 6; x < TMS9928A_HORZ_DISPLAY_START + 246; x+= 6, addr++ )
381 				{
382 					UINT16 charcode = (  readvmem( addr ) + ( ( y >> 6 ) << 8 ) ) & tms.patternmask;
383 					UINT8 pattern = readvmem( tms.pattern + ( charcode << 3 ) + ( y & 7 ) );
384 
385 					for ( INT32 i = 0; i < 6; pattern <<= 1, i++ )
386 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
387 				}
388 
389 				/* Extra 10 pixels right border */
390 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START + 246; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ )
391 					p[x] = bg;
392 			}
393 			break;
394 
395 		case 4:             /* MODE 3 */
396 			{
397 				UINT16 addr = tms.nametbl + ( ( y >> 3 ) * 32 );
398 
399 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
400 				{
401 					UINT8 charcode =  readvmem( addr );
402 					UINT8 colour =  readvmem( tms.pattern + ( charcode << 3 ) + ( ( y >> 2 ) & 7 ) );
403 					UINT16 fg = (colour >> 4) ? (colour >> 4) : BackColour;
404 					UINT16 bg = (colour & 15) ? (colour & 15) : BackColour;
405 
406 					p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
407 					p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg;
408 				}
409 			}
410 			break;
411 
412 		case 5: case 7:     /* MODE bogus */
413 			{
414 				UINT16 fg = (tms.Regs[7] >> 4) ? (tms.Regs[7] >> 4) : BackColour;
415 				UINT16 bg = BackColour;
416 
417 				/* Extra 6 pixels left border */
418 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 6; x++ )
419 					p[x] = bg;
420 
421 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START + 6; x < TMS9928A_HORZ_DISPLAY_START + 246; x+= 6 )
422 				{
423 					p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
424 					p[x+4] = p[x+5] = bg;
425 				}
426 
427 				/* Extra 10 pixels right border */
428 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START + 246; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ )
429 					p[x] = bg;
430 			}
431 			break;
432 
433 		case 6:             /* MODE 2+3 */
434 			{
435 				UINT16 addr = tms.nametbl + ( ( y >> 3 ) * 32 );
436 
437 				for ( INT32 x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
438 				{
439 					UINT8 charcode =  readvmem( addr );
440 					UINT8 colour =  readvmem( tms.pattern + ( ( ( charcode + ( ( y >> 2 ) & 7 ) + ( ( y >> 6 ) << 8 ) ) & tms.patternmask ) << 3 ) );
441 					UINT16 fg = (colour >> 4) ? (colour >> 4) : BackColour;
442 					UINT16 bg = (colour & 15) ? (colour & 15) : BackColour;
443 
444 					p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
445 					p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg;
446 				}
447 			}
448 			break;
449 		}
450 
451 		/* Draw sprites */
452 		if ( ( tms.Regs[1] & 0x50 ) != 0x40 )
453 		{
454 			/* sprites are disabled */
455 			tms.FifthSprite = 31;
456 		}
457 		else
458 		{
459 			UINT8 sprite_size = ( tms.Regs[1] & 0x02 ) ? 16 : 8;
460 			UINT8 sprite_mag = tms.Regs[1] & 0x01;
461 			UINT8 sprite_height = sprite_size * ( sprite_mag + 1 );
462 			UINT8 spr_drawn[32+256+32] = { 0 };
463 			UINT8 num_sprites = 0;
464 			bool fifth_encountered = false;
465 
466 			for ( UINT16 sprattr = 0; sprattr < 128; sprattr += 4 )
467 			{
468 				INT32 spr_y =  readvmem( tms.spriteattribute + sprattr + 0 );
469 
470 				tms.FifthSprite = sprattr / 4;
471 
472 				/* Stop processing sprites */
473 				if ( spr_y == 208 )
474 					break;
475 
476 				if ( spr_y > 0xE0 )
477 					spr_y -= 256;
478 
479 				/* vert pos 255 is displayed on the first line of the screen */
480 				spr_y++;
481 
482 				/* is sprite enabled on this line? */
483 				if ( spr_y <= y && y < spr_y + sprite_height )
484 				{
485 					INT32 spr_x =  readvmem( tms.spriteattribute + sprattr + 1 );
486 					UINT8 sprcode =  readvmem( tms.spriteattribute + sprattr + 2 );
487 					UINT8 sprcol =  readvmem( tms.spriteattribute + sprattr + 3 );
488 					UINT16 pataddr = tms.spritepattern + ( ( sprite_size == 16 ) ? sprcode & ~0x03 : sprcode ) * 8;
489 
490 					num_sprites++;
491 
492 					/* Fifth sprite encountered? */
493 					if ( num_sprites == 5 )
494 					{
495 						fifth_encountered = true;
496 						if (tms.LimitSprites)
497 							break;
498 					}
499 
500 					if ( sprite_mag )
501 						pataddr += ( ( ( y - spr_y ) & 0x1F ) >> 1 );
502 					else
503 						pataddr += ( ( y - spr_y ) & 0x0F );
504 
505 					UINT8 pattern =  readvmem( pataddr );
506 
507 					if ( sprcol & 0x80 )
508 						spr_x -= 32;
509 
510 					sprcol &= 0x0f;
511 
512 					for ( INT32 s = 0; s < sprite_size; s += 8 )
513 					{
514 						for ( INT32 i = 0; i < 8; pattern <<= 1, i++ )
515 						{
516 							INT32 colission_index = spr_x + ( sprite_mag ? i * 2 : i ) + 32;
517 
518 							for ( INT32 z = 0; z <= sprite_mag; colission_index++, z++ )
519 							{
520 								/* Check if pixel should be drawn */
521 								if ( pattern & 0x80 )
522 								{
523 									if ( colission_index >= 32 && colission_index < 32 + 256 )
524 									{
525 										/* Check for colission */
526 										if ( spr_drawn[ colission_index ] )
527 											tms.StatusReg |= 0x20;
528 										spr_drawn[ colission_index ] |= 0x01;
529 
530 										if ( sprcol )
531 										{
532 											/* Has another sprite already drawn here? */
533 											if ( ! ( spr_drawn[ colission_index ] & 0x02 ) )
534 											{
535 												spr_drawn[ colission_index ] |= 0x02;
536 												p[ TMS9928A_HORZ_DISPLAY_START + colission_index - 32 ] = sprcol;
537 											}
538 										}
539 									}
540 								}
541 							}
542 						}
543 
544 						pattern =  readvmem( pataddr + 16 );
545 						spr_x += sprite_mag ? 16 : 8;
546 					}
547 				}
548 			}
549 
550 			/* Update sprite overflow bits */
551 			if (~tms.StatusReg & 0x40)
552 			{
553 				tms.StatusReg = (tms.StatusReg & 0xe0) | tms.FifthSprite;
554 				if (fifth_encountered && ~tms.StatusReg & 0x80)
555 					tms.StatusReg |= 0x40;
556 			}
557 		}
558 
559 		/* Right border */
560 		for ( INT32 i = TMS9928A_HORZ_DISPLAY_START + 256; i < TMS9928A_TOTAL_HORZ; i++ )
561 			p[i] = BackColour;
562 	}
563 }
564 
TMS9928AScanline(INT32 vpos)565 void TMS9928AScanline(INT32 vpos)
566 {
567 	TMS9928AScanline_INT(vpos);
568 }
569 
TMS9928ADraw()570 INT32 TMS9928ADraw()
571 {
572 	TMS89928aPaletteRecalc();
573 
574 	{
575 		for (INT32 y = 0; y < nScreenHeight; y++)
576 		{
577 			for (INT32 x = 0; x < nScreenWidth; x++)
578 			{
579 				pTransDraw[y * nScreenWidth + x] = tms.tmpbmp[(y + tms.top_border - 16) * TMS9928A_TOTAL_HORZ + ((TMS9928A_HORZ_DISPLAY_START/2)+10)+x];
580 			}
581 		}
582 	}
583 
584 	BurnTransferCopy(Palette);
585 
586 	return 0;
587 }
588 
TMS9928AScan(INT32 nAction,INT32 * pnMin)589 INT32 TMS9928AScan(INT32 nAction, INT32 *pnMin)
590 {
591 	struct BurnArea ba;
592 
593 	if (pnMin) {
594 		*pnMin = 0x029708;
595 	}
596 
597 	if (nAction & ACB_VOLATILE) {
598 		memset(&ba, 0, sizeof(ba));
599 
600 		ba.Data   = tms.vMem;
601 		ba.nLen   = tms.vramsize;
602 		ba.szName = "video ram";
603 		BurnAcb(&ba);
604 
605 		ba.Data	  = tms.Regs;
606 		ba.nLen	  = 8;
607 		ba.szName = "tms registers";
608 		BurnAcb(&ba);
609 
610 		SCAN_VAR(tms.ReadAhead);
611 		SCAN_VAR(tms.StatusReg);
612 		SCAN_VAR(tms.FirstByte);
613 		SCAN_VAR(tms.latch);
614 		SCAN_VAR(tms.mode);
615 		SCAN_VAR(tms.INT);
616 		SCAN_VAR(tms.Addr);
617 		SCAN_VAR(tms.colour);
618 		SCAN_VAR(tms.pattern);
619 		SCAN_VAR(tms.nametbl);
620 		SCAN_VAR(tms.spriteattribute);
621 		SCAN_VAR(tms.spritepattern);
622 		SCAN_VAR(tms.colourmask);
623 		SCAN_VAR(tms.patternmask);
624 	}
625 
626 	return 0;
627 }
628