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