1 // license:BSD-3-Clause
2 // copyright-holders:Sean Young, Nathan Woods, Aaron Giles, Wilbert Pol, hap
3 /*
4 ** File: tms9928a.c -- software implementation of the Texas Instruments
5 **                     TMS9918(A), TMS9928(A) and TMS9929(A), used by the Coleco, MSX and
6 **                     TI99/4(A).
7 **
8 ** All undocumented features as described in the following file
9 ** should be emulated.
10 **
11 ** http://bifi.msxnet.org/msxnet/tech/tms9918a.txt
12 **
13 ** By Sean Young 1999 (sean@msxnet.org).
14 ** Based on code by Mike Balfour.
15 ** Improved over the years by MESS and MAME teams.
16 **
17 ** Todo:
18 ** - External VDP input and sync (pin 34/35 on 9918A)
19 ** - Updates during mid-scanline, probably only used in some MSX1 demos
20 ** - Colours are incorrect. [fixed by R Nabet ?]
21 ** - Sprites 8-31 are ghosted/cloned in mode 3 when using less than
22 **   three pattern tables. Exact behaviour is not known.
23 ** - Address scrambling when setting TMS99xxA to 4K (not on TMS91xx)
24 */
25 
26 #include "emu.h"
27 #include "tms9928a.h"
28 
29 
30 DEFINE_DEVICE_TYPE(TMS9928A, tms9928a_device, "tms9928a", "TMS9928A VDP")
31 DEFINE_DEVICE_TYPE(TMS9918,  tms9918_device,  "tms9918",  "TMS9918 VDP")
32 DEFINE_DEVICE_TYPE(TMS9918A, tms9918a_device, "tms9918a", "TMS9918A VDP")
33 DEFINE_DEVICE_TYPE(TMS9118,  tms9118_device,  "tms9118",  "TMS9118 VDP")
34 DEFINE_DEVICE_TYPE(TMS9128,  tms9128_device,  "tms9128",  "TMS9128 VDP")
35 DEFINE_DEVICE_TYPE(TMS9929,  tms9929_device,  "tms9929",  "TMS9929 VDP")
36 DEFINE_DEVICE_TYPE(TMS9929A, tms9929a_device, "tms9929a", "TMS9929A VDP")
37 DEFINE_DEVICE_TYPE(TMS9129,  tms9129_device,  "tms9129",  "TMS9129 VDP")
38 DEFINE_DEVICE_TYPE(EFO90501, efo90501_device, "efo90501", "EFO90501 VDP")
39 
40 // ======= Debugging =========
41 
42 // Log register accesses
43 #define TRACE_REG 0
44 
45 // Log mode settings
46 #define TRACE_MODE 0
47 
48 // ===========================
49 
50 /*
51     The TMS9928 has an own address space.
52 */
memmap(address_map & map)53 void tms9928a_device::memmap(address_map &map)
54 {
55 	if (!has_configured_map(0))
56 		map(0x0000, 0x3fff).ram();
57 }
58 
tms9928a_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,uint16_t horz_total,bool is_50hz,bool is_reva,bool is_99)59 tms9928a_device::tms9928a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint16_t horz_total, bool is_50hz, bool is_reva, bool is_99)
60 	: device_t(mconfig, type, tag, owner, clock)
61 	, device_memory_interface(mconfig, *this)
62 	, device_palette_interface(mconfig, *this)
63 	, device_video_interface(mconfig, *this)
64 	, m_vram_size(0)
65 	, m_out_int_line_cb(*this)
66 	, m_out_gromclk_cb(*this)
67 	, m_total_horz(horz_total)
68 	, m_50hz(is_50hz)
69 	, m_reva(is_reva)
70 	, m_99(is_99)
71 	, m_space_config("vram", ENDIANNESS_BIG, 8, 14, 0, address_map_constructor(FUNC(tms9928a_device::memmap), this))
72 {
73 }
74 
device_config_complete()75 void tms9928a_device::device_config_complete()
76 {
77 	if (!has_screen())
78 		return;
79 
80 	if (!screen().has_screen_update())
81 		screen().set_screen_update(*this, FUNC(tms9928a_device::screen_update));
82 
83 	if (!screen().refresh_attoseconds())
84 	{
85 		if (m_50hz)
86 			screen().set_raw(clock() / 2, m_total_horz, HORZ_DISPLAY_START - 12, HORZ_DISPLAY_START + 256 + 12,
87 				TOTAL_VERT_PAL, VERT_DISPLAY_START_PAL - 12, VERT_DISPLAY_START_PAL + 192 + 12);
88 		else
89 			screen().set_raw(clock() / 2, m_total_horz, HORZ_DISPLAY_START - 12, HORZ_DISPLAY_START + 256 + 12,
90 				TOTAL_VERT_NTSC, VERT_DISPLAY_START_NTSC - 12, VERT_DISPLAY_START_NTSC + 192 + 12);
91 	}
92 }
93 
94 
tms9928a_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)95 tms9928a_device::tms9928a_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
96 	: tms9928a_device(mconfig, TMS9928A, tag, owner, clock, 342, false, true, true)
97 {
98 }
99 
tms9129_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)100 tms9129_device::tms9129_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
101 	: tms9928a_device(mconfig, TMS9129, tag, owner, clock, 342, true, true, false)
102 {
103 }
104 
tms9918_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)105 tms9918_device::tms9918_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
106 	: tms9928a_device(mconfig, TMS9918, tag, owner, clock, 342, false, false, true)
107 {
108 }
109 
tms9918a_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)110 tms9918a_device::tms9918a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
111 	: tms9928a_device(mconfig, TMS9918A, tag, owner, clock, 342, false, true, true)
112 {
113 }
114 
tms9118_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)115 tms9118_device::tms9118_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
116 	: tms9928a_device(mconfig, TMS9118, tag, owner, clock, 342, false, true, false)
117 {
118 }
119 
tms9128_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)120 tms9128_device::tms9128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
121 	: tms9928a_device(mconfig, TMS9128, tag, owner, clock, 342, false, true, false)
122 {
123 }
124 
tms9929_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)125 tms9929_device::tms9929_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
126 	: tms9928a_device(mconfig, TMS9929, tag, owner, clock, 342, true, false, true)
127 {
128 }
129 
tms9929a_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)130 tms9929a_device::tms9929a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
131 	: tms9928a_device(mconfig, TMS9929A, tag, owner, clock, 342, true, true, true)
132 {
133 }
134 
efo90501_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)135 efo90501_device::efo90501_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
136 	: tms9928a_device(mconfig, EFO90501, tag, owner, clock, 346, true, true, true)
137 {
138 }
139 
memory_space_config() const140 device_memory_interface::space_config_vector tms9928a_device::memory_space_config() const
141 {
142 	return space_config_vector {
143 		std::make_pair(AS_DATA, &m_space_config)
144 	};
145 }
146 
read(offs_t offset)147 uint8_t tms9928a_device::read(offs_t offset)
148 {
149 	uint8_t value = 0;
150 
151 	if ((offset & 1) == 0)
152 		value = vram_read();
153 	else
154 		value = register_read();
155 
156 	return value;
157 }
158 
write(offs_t offset,uint8_t data)159 void tms9928a_device::write(offs_t offset, uint8_t data)
160 {
161 	if ((offset & 1) == 0)
162 		vram_write(data);
163 	else
164 		register_write(data);
165 }
166 
vram_read()167 u8 tms9928a_device::vram_read()
168 {
169 	uint8_t data = m_ReadAhead;
170 
171 	// prevent debugger from changing the address base
172 	if (machine().side_effects_disabled()) return data;
173 
174 	m_ReadAhead = m_vram_space->read_byte(m_Addr);
175 	m_Addr = (m_Addr + 1) & (m_vram_size - 1);
176 	m_latch = 0;
177 
178 	return data;
179 }
180 
vram_write(u8 data)181 void tms9928a_device::vram_write(u8 data)
182 {
183 	m_vram_space->write_byte(m_Addr, data);
184 
185 	// prevent debugger from changing the address base
186 	if (!machine().side_effects_disabled())
187 	{
188 		m_Addr = (m_Addr + 1) & (m_vram_size - 1);
189 		m_ReadAhead = data;
190 		m_latch = 0;
191 	}
192 }
193 
register_read()194 u8 tms9928a_device::register_read()
195 {
196 	uint8_t data = m_StatusReg;
197 
198 	// prevent debugger from changing the internal state
199 	if (machine().side_effects_disabled()) return data;
200 
201 	m_StatusReg = m_FifthSprite;
202 	check_interrupt();
203 	m_latch = 0;
204 
205 	return data;
206 }
207 
check_interrupt()208 void tms9928a_device::check_interrupt()
209 {
210 	// trigger if vblank and interrupt-enable bits are set
211 	uint8_t b = (m_StatusReg & 0x80 && m_Regs[1] & 0x20) ? 1 : 0;
212 
213 	if (b != m_INT)
214 	{
215 		m_INT = b;
216 		if ( !m_out_int_line_cb.isnull() )
217 			m_out_int_line_cb( m_INT );
218 	}
219 }
220 
221 
update_backdrop()222 void tms9928a_device::update_backdrop()
223 {
224 	// update backdrop colour to transparent if EXTVID bit is set
225 	if ((m_Regs[7] & 15) == 0)
226 		set_pen_color(0, rgb_t(m_Regs[0] & 1 ? 0 : 255,0,0,0));
227 }
228 
229 
update_table_masks()230 void tms9928a_device::update_table_masks()
231 {
232 	m_colourmask = ( (m_Regs[3] & 0x7f) << 3 ) | 7;
233 
234 	// on 91xx family, the colour table mask doesn't affect the pattern table mask
235 	m_patternmask = ( (m_Regs[4] & 3) << 8 ) | ( m_99 ? (m_colourmask & 0xff) : 0xff );
236 }
237 
238 
change_register(uint8_t reg,uint8_t val)239 void tms9928a_device::change_register(uint8_t reg, uint8_t val)
240 {
241 	static const uint8_t Mask[8] =
242 		{ 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff };
243 	static const char *const modes[] =
244 	{
245 		"Mode 0 (GRAPHIC 1)", "Mode 1 (TEXT 1)", "Mode 2 (GRAPHIC 2)",
246 		"Mode 1+2 (TEXT 1 variation)", "Mode 3 (MULTICOLOR)",
247 		"Mode 1+3 (BOGUS)", "Mode 2+3 (MULTICOLOR variation)",
248 		"Mode 1+2+3 (BOGUS)"
249 	};
250 
251 	uint8_t prev = m_Regs[reg];
252 	val &= Mask[reg];
253 	m_Regs[reg] = val;
254 
255 	if (TRACE_REG) logerror("TMS9928A('%s'): Reg %d = %02xh\n", tag(), reg, (int)val);
256 
257 	switch (reg)
258 	{
259 	case 0:
260 		/* re-calculate masks and pattern generator & colour */
261 		if (val & 2)
262 		{
263 			m_colour = ((m_Regs[3] & 0x80) * 64) & (m_vram_size - 1);
264 			m_pattern = ((m_Regs[4] & 4) * 2048) & (m_vram_size - 1);
265 			update_table_masks();
266 		}
267 		else
268 		{
269 			m_colour = (m_Regs[3] * 64) & (m_vram_size - 1);
270 			m_pattern = (m_Regs[4] * 2048) & (m_vram_size - 1);
271 		}
272 		m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1));
273 		if ((val ^ prev) & 1)
274 			update_backdrop();
275 		if (TRACE_MODE) logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]);
276 		break;
277 	case 1:
278 		check_interrupt();
279 		m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1));
280 		if (TRACE_MODE) logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]);
281 		break;
282 	case 2:
283 		m_nametbl = (val * 1024) & (m_vram_size - 1);
284 		break;
285 	case 3:
286 		if (m_Regs[0] & 2)
287 		{
288 			m_colour = ((val & 0x80) * 64) & (m_vram_size - 1);
289 			update_table_masks();
290 		}
291 		else
292 		{
293 			m_colour = (val * 64) & (m_vram_size - 1);
294 		}
295 		break;
296 	case 4:
297 		if (m_Regs[0] & 2)
298 		{
299 			m_pattern = ((val & 4) * 2048) & (m_vram_size - 1);
300 			update_table_masks();
301 		}
302 		else
303 		{
304 			m_pattern = (val * 2048) & (m_vram_size - 1);
305 		}
306 		break;
307 	case 5:
308 		m_spriteattribute = (val * 128) & (m_vram_size - 1);
309 		break;
310 	case 6:
311 		m_spritepattern = (val * 2048) & (m_vram_size - 1);
312 		break;
313 	case 7:
314 		if ((val ^ prev) & 15)
315 			update_backdrop();
316 		break;
317 	}
318 }
319 
320 
register_write(u8 data)321 void tms9928a_device::register_write(u8 data)
322 {
323 	// prevent debugger from changing the internal state
324 	if (machine().side_effects_disabled()) return;
325 
326 	if (m_latch)
327 	{
328 		/* set high part of read/write address */
329 		m_Addr = ((data << 8) | (m_Addr & 0xff)) & (m_vram_size - 1);
330 
331 		if (data & 0x80)
332 		{
333 			/* register write */
334 			change_register (data & 7, m_Addr & 0xff);
335 		}
336 		else
337 		{
338 			if ( !(data & 0x40) )
339 			{
340 				/* read ahead */
341 				vram_read();
342 			}
343 		}
344 		m_latch = 0;
345 	}
346 	else
347 	{
348 		/* set low part of read/write address */
349 		m_Addr = ((m_Addr & 0xff00) | data) & (m_vram_size - 1);
350 		m_latch = 1;
351 	}
352 }
353 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)354 void tms9928a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
355 {
356 	// Handle GROM clock if present
357 	if (id==GROMCLK)
358 	{
359 		// Pulse it
360 		m_out_gromclk_cb(ASSERT_LINE);
361 		m_out_gromclk_cb(CLEAR_LINE);
362 		return;
363 	}
364 
365 	int raw_vpos = screen().vpos();
366 	int vpos = raw_vpos * m_vertical_size / screen().height();
367 	uint16_t BackColour = m_Regs[7] & 15;
368 	uint32_t *p = &m_tmpbmp.pix(vpos);
369 
370 	int y = vpos - m_top_border;
371 
372 	if ( y < 0 || y >= 192 || ! (m_Regs[1] & 0x40) )
373 	{
374 		/* Draw backdrop colour */
375 		for ( int i = 0; i < m_total_horz; i++ )
376 			p[i] = pen(BackColour);
377 
378 		/* vblank is set at the last cycle of the first inactive line */
379 		if ( y == 193 )
380 		{
381 			m_StatusReg |= 0x80;
382 			check_interrupt();
383 		}
384 	}
385 	else
386 	{
387 		/* Draw regular line */
388 
389 		/* Left border */
390 		for ( int i = 0; i < HORZ_DISPLAY_START; i++ )
391 			p[i] = pen(BackColour);
392 
393 		/* Active display */
394 
395 		switch( m_mode )
396 		{
397 		case 0:             /* MODE 0 */
398 			// if (vpos==100 ) popmessage("TMS9928A MODE 0");
399 			{
400 				uint16_t addr = m_nametbl + ( ( y & 0xF8 ) << 2 );
401 
402 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 256; x+= 8, addr++ )
403 				{
404 					uint8_t charcode = m_vram_space->read_byte( addr );
405 					uint8_t pattern =  m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( y & 7 ) );
406 					uint8_t colour =  m_vram_space->read_byte( m_colour + ( charcode >> 3 ) );
407 					rgb_t fg = pen((colour >> 4) ? (colour >> 4) : BackColour);
408 					rgb_t bg = pen((colour & 15) ? (colour & 15) : BackColour);
409 
410 					for ( int i = 0; i < 8; pattern <<= 1, i++ )
411 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
412 				}
413 			}
414 			break;
415 
416 		case 1:             /* MODE 1 */
417 			//if (vpos==100 ) popmessage("TMS9928A MODE 1");
418 			{
419 				uint16_t addr = m_nametbl + ( ( y >> 3 ) * 40 );
420 				rgb_t fg = pen((m_Regs[7] >> 4) ? (m_Regs[7] >> 4) : BackColour);
421 				rgb_t bg = pen(BackColour);
422 
423 				/* Extra 6 pixels left border */
424 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 6; x++ )
425 					p[x] = bg;
426 
427 				for ( int x = HORZ_DISPLAY_START + 6; x < HORZ_DISPLAY_START + 246; x+= 6, addr++ )
428 				{
429 					uint16_t charcode =  m_vram_space->read_byte( addr );
430 					uint8_t pattern =  m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( y & 7 ) );
431 
432 					for ( int i = 0; i < 6; pattern <<= 1, i++ )
433 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
434 				}
435 
436 				/* Extra 10 pixels right border */
437 				for ( int x = HORZ_DISPLAY_START + 246; x < HORZ_DISPLAY_START + 256; x++ )
438 					p[x] = bg;
439 			}
440 			break;
441 
442 		case 2:             /* MODE 2 */
443 			//if (vpos==100 ) popmessage("TMS9928A MODE 2");
444 			{
445 				uint16_t addr = m_nametbl + ( ( y >> 3 ) * 32 );
446 
447 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 256; x+= 8, addr++ )
448 				{
449 					uint16_t charcode =  m_vram_space->read_byte( addr ) + ( ( y >> 6 ) << 8 );
450 					uint8_t pattern =  m_vram_space->read_byte( m_pattern + ( ( charcode & m_patternmask ) << 3 ) + ( y & 7 ) );
451 					uint8_t colour =  m_vram_space->read_byte( m_colour + ( ( charcode & m_colourmask ) << 3 ) + ( y & 7 ) );
452 					rgb_t fg = pen((colour >> 4) ? (colour >> 4) : BackColour);
453 					rgb_t bg = pen((colour & 15) ? (colour & 15) : BackColour);
454 
455 					for ( int i = 0; i < 8; pattern <<= 1, i++ )
456 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
457 				}
458 			}
459 			break;
460 
461 		case 3:             /* MODE 1+2 */
462 			//if (vpos==100) popmessage("TMS9928A MODE1+2");
463 			{
464 				uint16_t addr = m_nametbl + ( ( y >> 3 ) * 40 );
465 				rgb_t fg = pen((m_Regs[7] >> 4) ? (m_Regs[7] >> 4) : BackColour);
466 				rgb_t bg = pen(BackColour);
467 
468 				/* Extra 6 pixels left border */
469 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 6; x++ )
470 					p[x] = bg;
471 
472 				for ( int x = HORZ_DISPLAY_START + 6; x < HORZ_DISPLAY_START + 246; x+= 6, addr++ )
473 				{
474 					uint16_t charcode = (  m_vram_space->read_byte( addr ) + ( ( y >> 6 ) << 8 ) ) & m_patternmask;
475 					uint8_t pattern = m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( y & 7 ) );
476 
477 					for ( int i = 0; i < 6; pattern <<= 1, i++ )
478 						p[x+i] = ( pattern & 0x80 ) ? fg : bg;
479 				}
480 
481 				/* Extra 10 pixels right border */
482 				for ( int x = HORZ_DISPLAY_START + 246; x < HORZ_DISPLAY_START + 256; x++ )
483 					p[x] = bg;
484 			}
485 			break;
486 
487 		case 4:             /* MODE 3 */
488 			//if (vpos==100 ) popmessage("TMS9928A MODE 3");
489 			{
490 				uint16_t addr = m_nametbl + ( ( y >> 3 ) * 32 );
491 
492 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 256; x+= 8, addr++ )
493 				{
494 					uint8_t charcode =  m_vram_space->read_byte( addr );
495 					uint8_t colour =  m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( ( y >> 2 ) & 7 ) );
496 					rgb_t fg = pen((colour >> 4) ? (colour >> 4) : BackColour);
497 					rgb_t bg = pen((colour & 15) ? (colour & 15) : BackColour);
498 
499 					p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
500 					p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg;
501 				}
502 			}
503 			break;
504 
505 		case 5: case 7:     /* MODE bogus */
506 			//if (vpos==100 ) popmessage("TMS9928A MODE bogus");
507 			{
508 				rgb_t fg = pen((m_Regs[7] >> 4) ? (m_Regs[7] >> 4) : BackColour);
509 				rgb_t bg = pen(BackColour);
510 
511 				/* Extra 6 pixels left border */
512 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 6; x++ )
513 					p[x] = bg;
514 
515 				for ( int x = HORZ_DISPLAY_START + 6; x < HORZ_DISPLAY_START + 246; x+= 6 )
516 				{
517 					p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
518 					p[x+4] = p[x+5] = bg;
519 				}
520 
521 				/* Extra 10 pixels right border */
522 				for ( int x = HORZ_DISPLAY_START + 246; x < HORZ_DISPLAY_START + 256; x++ )
523 					p[x] = bg;
524 			}
525 			break;
526 
527 		case 6:             /* MODE 2+3 */
528 			//if (vpos==100 ) popmessage("TMS9928A MODE 2+3");
529 			{
530 				uint16_t addr = m_nametbl + ( ( y >> 3 ) * 32 );
531 
532 				for ( int x = HORZ_DISPLAY_START; x < HORZ_DISPLAY_START + 256; x+= 8, addr++ )
533 				{
534 					uint8_t charcode =  m_vram_space->read_byte( addr );
535 					uint8_t colour =  m_vram_space->read_byte( m_pattern + ( ( ( charcode + ( ( y >> 2 ) & 7 ) + ( ( y >> 6 ) << 8 ) ) & m_patternmask ) << 3 ) );
536 					rgb_t fg = pen((colour >> 4) ? (colour >> 4) : BackColour);
537 					rgb_t bg = pen((colour & 15) ? (colour & 15) : BackColour);
538 
539 					p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
540 					p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg;
541 				}
542 			}
543 			break;
544 		}
545 
546 		/* Draw sprites */
547 		if ( ( m_Regs[1] & 0x50 ) != 0x40 )
548 		{
549 			/* sprites are disabled */
550 			m_FifthSprite = 31;
551 		}
552 		else
553 		{
554 			uint8_t sprite_size = ( m_Regs[1] & 0x02 ) ? 16 : 8;
555 			uint8_t sprite_mag = m_Regs[1] & 0x01;
556 			uint8_t sprite_height = sprite_size * ( sprite_mag + 1 );
557 			uint8_t spr_drawn[32+256+32] = { 0 };
558 			uint8_t num_sprites = 0;
559 			bool fifth_encountered = false;
560 
561 			for ( uint16_t sprattr = 0; sprattr < 128; sprattr += 4 )
562 			{
563 				int spr_y =  m_vram_space->read_byte( m_spriteattribute + sprattr + 0 );
564 
565 				m_FifthSprite = sprattr / 4;
566 
567 				/* Stop processing sprites */
568 				if ( spr_y == 208 )
569 					break;
570 
571 				if ( spr_y > 0xE0 )
572 					spr_y -= 256;
573 
574 				/* vert pos 255 is displayed on the first line of the screen */
575 				spr_y++;
576 
577 				/* is sprite enabled on this line? */
578 				if ( spr_y <= y && y < spr_y + sprite_height )
579 				{
580 					int spr_x =  m_vram_space->read_byte( m_spriteattribute + sprattr + 1 );
581 					uint8_t sprcode =  m_vram_space->read_byte( m_spriteattribute + sprattr + 2 );
582 					uint8_t sprcol =  m_vram_space->read_byte( m_spriteattribute + sprattr + 3 );
583 					uint16_t pataddr = m_spritepattern + ( ( sprite_size == 16 ) ? sprcode & ~0x03 : sprcode ) * 8;
584 
585 					num_sprites++;
586 
587 					/* Fifth sprite encountered? */
588 					if ( num_sprites == 5 )
589 					{
590 						fifth_encountered = true;
591 						break;
592 					}
593 
594 					if ( sprite_mag )
595 						pataddr += ( ( ( y - spr_y ) & 0x1F ) >> 1 );
596 					else
597 						pataddr += ( ( y - spr_y ) & 0x0F );
598 
599 					uint8_t pattern =  m_vram_space->read_byte( pataddr );
600 
601 					if ( sprcol & 0x80 )
602 						spr_x -= 32;
603 
604 					sprcol &= 0x0f;
605 
606 					for ( int s = 0; s < sprite_size; s += 8 )
607 					{
608 						for ( int i = 0; i < 8; pattern <<= 1, i++ )
609 						{
610 							int colission_index = spr_x + ( sprite_mag ? i * 2 : i ) + 32;
611 
612 							for ( int z = 0; z <= sprite_mag; colission_index++, z++ )
613 							{
614 								/* Check if pixel should be drawn */
615 								if ( pattern & 0x80 )
616 								{
617 									if ( colission_index >= 32 && colission_index < 32 + 256 )
618 									{
619 										/* Check for colission */
620 										if ( spr_drawn[ colission_index ] )
621 											m_StatusReg |= 0x20;
622 										spr_drawn[ colission_index ] |= 0x01;
623 
624 										if ( sprcol )
625 										{
626 											/* Has another sprite already drawn here? */
627 											if ( ! ( spr_drawn[ colission_index ] & 0x02 ) )
628 											{
629 												spr_drawn[ colission_index ] |= 0x02;
630 												p[ HORZ_DISPLAY_START + colission_index - 32 ] = pen(sprcol);
631 											}
632 										}
633 									}
634 								}
635 							}
636 						}
637 
638 						pattern =  m_vram_space->read_byte( pataddr + 16 );
639 						spr_x += sprite_mag ? 16 : 8;
640 					}
641 				}
642 			}
643 
644 			/* Update sprite overflow bits */
645 			if (~m_StatusReg & 0x40)
646 			{
647 				m_StatusReg = (m_StatusReg & 0xe0) | m_FifthSprite;
648 				if (fifth_encountered && ~m_StatusReg & 0x80)
649 					m_StatusReg |= 0x40;
650 			}
651 		}
652 
653 		/* Right border */
654 		for ( int i = HORZ_DISPLAY_START + 256; i < m_total_horz; i++ )
655 			p[i] = pen(BackColour);
656 	}
657 
658 	/* Schedule next callback */
659 	m_line_timer->adjust( screen().time_until_pos( ( raw_vpos + 1 ) % screen().height() , HORZ_DISPLAY_START ) );
660 }
661 
662 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)663 uint32_t tms9928a_device::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect )
664 {
665 	copybitmap( bitmap, m_tmpbmp, 0, 0, 0, 0, cliprect );
666 	return 0;
667 }
668 
set_palette()669 void tms9928a_device::set_palette()
670 {
671 	/*
672 	New palette (R. Nabet).
673 
674 	First 3 columns from TI datasheet (in volts).
675 	Next 3 columns based on formula :
676 	Y = .299*R + .587*G + .114*B (NTSC)
677 	(the coefficients are likely to be slightly different with PAL, but who cares ?)
678 	I assumed the "zero" for R-Y and B-Y was 0.47V.
679 	Last 3 coeffs are the 8-bit values.
680 
681 	Color            Y      R-Y     B-Y     R       G       B       R   G   B
682 	0 Transparent
683 	1 Black         0.00    0.47    0.47    0.00    0.00    0.00      0   0   0
684 	2 Medium green  0.53    0.07    0.20    0.13    0.79    0.26     33 200  66
685 	3 Light green   0.67    0.17    0.27    0.37    0.86    0.47     94 220 120
686 	4 Dark blue     0.40    0.40    1.00    0.33    0.33    0.93     84  85 237
687 	5 Light blue    0.53    0.43    0.93    0.49    0.46    0.99    125 118 252
688 	6 Dark red      0.47    0.83    0.30    0.83    0.32    0.30    212  82  77
689 	7 Cyan          0.73    0.00    0.70    0.26    0.92    0.96     66 235 245
690 	8 Medium red    0.53    0.93    0.27    0.99    0.33    0.33    252  85  84
691 	9 Light red     0.67    0.93    0.27    1.13(!) 0.47    0.47    255 121 120
692 	A Dark yellow   0.73    0.57    0.07    0.83    0.76    0.33    212 193  84
693 	B Light yellow  0.80    0.57    0.17    0.90    0.81    0.50    230 206 128
694 	C Dark green    0.47    0.13    0.23    0.13    0.69    0.23     33 176  59
695 	D Magenta       0.53    0.73    0.67    0.79    0.36    0.73    201  91 186
696 	E Gray          0.80    0.47    0.47    0.80    0.80    0.80    204 204 204
697 	F White         1.00    0.47    0.47    1.00    1.00    1.00    255 255 255
698 	*/
699 	static const rgb_t tms9928a_palette[PALETTE_SIZE] =
700 	{
701 		rgb_t::black(),
702 		rgb_t::black(),
703 		rgb_t(33, 200, 66),
704 		rgb_t(94, 220, 120),
705 		rgb_t(84, 85, 237),
706 		rgb_t(125, 118, 252),
707 		rgb_t(212, 82, 77),
708 		rgb_t(66, 235, 245),
709 		rgb_t(252, 85, 84),
710 		rgb_t(255, 121, 120),
711 		rgb_t(212, 193, 84),
712 		rgb_t(230, 206, 128),
713 		rgb_t(33, 176, 59),
714 		rgb_t(201, 91, 186),
715 		rgb_t(204, 204, 204),
716 		rgb_t::white()
717 	};
718 
719 	/* copy default palette into working palette */
720 	for (int i = 0; i < PALETTE_SIZE; i++)
721 	{
722 		set_pen_color(i, tms9928a_palette[i]);
723 	}
724 }
725 
device_start()726 void tms9928a_device::device_start()
727 {
728 	m_top_border = m_50hz ? VERT_DISPLAY_START_PAL : VERT_DISPLAY_START_NTSC;
729 	m_vertical_size = m_50hz ? TOTAL_VERT_PAL : TOTAL_VERT_NTSC;
730 
731 	m_out_int_line_cb.resolve();
732 	m_out_gromclk_cb.resolve();
733 
734 	// Video RAM is allocated as an own address space
735 	m_vram_space = &space(AS_DATA);
736 
737 	/* back bitmap */
738 	m_tmpbmp.allocate(m_total_horz, TOTAL_VERT_PAL);
739 
740 	m_line_timer = timer_alloc(TIMER_LINE);
741 	m_gromclk_timer = timer_alloc(GROMCLK);
742 
743 	set_palette();
744 
745 	save_item(NAME(m_Regs[0]));
746 	save_item(NAME(m_Regs[1]));
747 	save_item(NAME(m_Regs[2]));
748 	save_item(NAME(m_Regs[3]));
749 	save_item(NAME(m_Regs[4]));
750 	save_item(NAME(m_Regs[5]));
751 	save_item(NAME(m_Regs[6]));
752 	save_item(NAME(m_Regs[7]));
753 	save_item(NAME(m_StatusReg));
754 	save_item(NAME(m_FifthSprite));
755 	save_item(NAME(m_ReadAhead));
756 	save_item(NAME(m_latch));
757 	save_item(NAME(m_Addr));
758 	save_item(NAME(m_INT));
759 //  save_pointer(NAME(m_vMem), m_vram_size);
760 	save_item(NAME(m_colour));
761 	save_item(NAME(m_colourmask));
762 	save_item(NAME(m_pattern));
763 	save_item(NAME(m_patternmask));
764 	save_item(NAME(m_nametbl));
765 	save_item(NAME(m_spriteattribute));
766 	save_item(NAME(m_spritepattern));
767 	save_item(NAME(m_mode));
768 }
769 
770 
device_reset()771 void tms9928a_device::device_reset()
772 {
773 	for (auto & elem : m_Regs)
774 		elem = 0;
775 
776 	m_StatusReg = 0;
777 	m_FifthSprite = 31;
778 	m_nametbl = 0;
779 	m_pattern = 0;
780 	m_colour = 0;
781 	m_spritepattern = 0;
782 	m_spriteattribute = 0;
783 	m_colourmask = 0x3fff;
784 	m_patternmask = 0x3fff;
785 	m_Addr = 0;
786 	m_ReadAhead = 0;
787 	m_INT = 0;
788 	m_latch = 0;
789 	m_mode = 0;
790 
791 	m_line_timer->adjust( screen().time_until_pos( 0, HORZ_DISPLAY_START ) );
792 
793 	// TODO: Check clock freq settings in all drivers
794 	if (!m_out_gromclk_cb.isnull() && m_99)
795 		m_gromclk_timer->adjust(attotime::zero, 0, clocks_to_attotime(24));
796 }
797