1 // license:BSD-3-Clause
2 // copyright-holders:Angelo Salese, Miodrag Milanovic, Carl
3 /**********************************************************************
4 
5     Intel 82720 Graphics Display Controller emulation
6 
7 **********************************************************************/
8 
9 /*
10 
11     TODO:
12 
13     - implement FIFO as ring buffer
14     - commands
15         - DMAR
16         - DMAW
17     - incomplete / unimplemented FIGD / GCHRD draw modes
18         - FIGD character
19         - slanted character
20     - read-modify-write cycle
21         - read data
22         - modify data
23         - write data
24     - QX-10 diagnostic test has positioning bugs with the bitmap display test;
25     - QX-10 diagnostic test misses the zooming factor (external pin);
26     - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking);
27     - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up.
28       The problem is that DMA-ing with RDAT/WDAT shouldn't be instant;
29 
30     - honor visible area
31     - wide mode (32-bit access)
32     - light pen
33     - dad and mask are the same, in figd dad is shifted every step and when msb or lsb are 1 ead is advanced in x dir
34 
35 */
36 
37 #include "emu.h"
38 #include "upd7220.h"
39 
40 #include "screen.h"
41 
42 //#define VERBOSE 1
43 #include "logmacro.h"
44 
45 
46 
47 
48 //**************************************************************************
49 //  MACROS / CONSTANTS
50 //**************************************************************************
51 
52 // todo typedef
53 enum
54 {
55 	COMMAND_INVALID = -1,
56 	COMMAND_RESET,
57 	COMMAND_SYNC,
58 	COMMAND_VSYNC,
59 	COMMAND_CCHAR,
60 	COMMAND_START,
61 	COMMAND_BCTRL,
62 	COMMAND_ZOOM,
63 	COMMAND_CURS,
64 	COMMAND_PRAM,
65 	COMMAND_PITCH,
66 	COMMAND_WDAT,
67 	COMMAND_MASK,
68 	COMMAND_FIGS,
69 	COMMAND_FIGD,
70 	COMMAND_GCHRD,
71 	COMMAND_RDAT,
72 	COMMAND_CURD,
73 	COMMAND_LPRD,
74 	COMMAND_DMAR,
75 	COMMAND_DMAW,
76 	COMMAND_5A,
77 	COMMAND_05
78 };
79 
80 enum
81 {
82 	FIFO_READ = 0,
83 	FIFO_WRITE
84 };
85 
86 enum
87 {
88 	FIFO_EMPTY = -1,
89 	FIFO_PARAMETER,
90 	FIFO_COMMAND
91 };
92 
93 #define UPD7220_COMMAND_RESET           0x00
94 #define UPD7220_COMMAND_SYNC            0x0e // & 0xfe
95 #define UPD7220_COMMAND_VSYNC           0x6e // & 0xfe
96 #define UPD7220_COMMAND_CCHAR           0x4b
97 #define UPD7220_COMMAND_START           0x6b
98 #define UPD7220_COMMAND_BCTRL           0x0c // & 0xfe
99 #define UPD7220_COMMAND_05              0x05
100 #define UPD7220_COMMAND_ZOOM            0x46
101 #define UPD7220_COMMAND_CURS            0x49
102 #define UPD7220_COMMAND_PRAM            0x70 // & 0xf0
103 #define UPD7220_COMMAND_PITCH           0x47
104 #define UPD7220_COMMAND_WDAT            0x20 // & 0xe4
105 #define UPD7220_COMMAND_MASK            0x4a
106 #define UPD7220_COMMAND_FIGS            0x4c
107 #define UPD7220_COMMAND_FIGD            0x6c
108 #define UPD7220_COMMAND_GCHRD           0x68
109 #define UPD7220_COMMAND_RDAT            0xa0 // & 0xe4
110 #define UPD7220_COMMAND_CURD            0xe0
111 #define UPD7220_COMMAND_LPRD            0xc0
112 #define UPD7220_COMMAND_DMAR            0xa4 // & 0xe4
113 #define UPD7220_COMMAND_DMAW            0x24 // & 0xe4
114 #define UPD7220_COMMAND_5A              0x5a
115 
116 #define UPD7220_SR_DATA_READY           0x01
117 #define UPD7220_SR_FIFO_FULL            0x02
118 #define UPD7220_SR_FIFO_EMPTY           0x04
119 #define UPD7220_SR_DRAWING_IN_PROGRESS  0x08
120 #define UPD7220_SR_DMA_EXECUTE          0x10
121 #define UPD7220_SR_VSYNC_ACTIVE         0x20
122 #define UPD7220_SR_HBLANK_ACTIVE        0x40
123 #define UPD7220_SR_LIGHT_PEN_DETECT     0x80
124 
125 #define UPD7220_MODE_REFRESH_RAM        0x04
126 #define UPD7220_MODE_DRAW_ON_RETRACE    0x10
127 #define UPD7220_MODE_DISPLAY_MASK       0x22
128 #define UPD7220_MODE_DISPLAY_MIXED      0x00
129 #define UPD7220_MODE_DISPLAY_GRAPHICS   0x02
130 #define UPD7220_MODE_DISPLAY_CHARACTER  0x20
131 #define UPD7220_MODE_DISPLAY_INVALID    0x22
132 #define UPD7220_MODE_INTERLACE_MASK     0x09
133 #define UPD7220_MODE_INTERLACE_NONE     0x00
134 #define UPD7220_MODE_INTERLACE_INVALID  0x01
135 #define UPD7220_MODE_INTERLACE_REPEAT   0x08
136 #define UPD7220_MODE_INTERLACE_ON       0x09
137 
138 
139 static constexpr int x_dir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
140 static constexpr int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1};
141 
142 
143 //**************************************************************************
144 //  GLOBAL VARIABLES
145 //**************************************************************************
146 
147 // devices
148 DEFINE_DEVICE_TYPE(UPD7220, upd7220_device, "upd7220", "NEC uPD7220")
149 
150 
151 // default address map
upd7220_vram(address_map & map)152 void upd7220_device::upd7220_vram(address_map &map)
153 {
154 	if (!has_configured_map(0))
155 		map(0x00000, 0x3ffff).ram();
156 }
157 
158 
159 // internal 128x14 control ROM
160 // hand-dumped as little-endian from a die shot
161 ROM_START( upd7220 )
162 	ROM_REGION( 0x100, "upd7220", 0 )
163 	ROM_LOAD( "upd7220.bin", 0x000, 0x100, CRC(3c92b218) SHA1(e154b3106a80c9c98d9f2ee18efcd7f4b4aa7d49) )
164 ROM_END
165 
166 
167 //-------------------------------------------------
168 //  memory_space_config - return a description of
169 //  any address spaces owned by this device
170 //-------------------------------------------------
171 
memory_space_config() const172 device_memory_interface::space_config_vector upd7220_device::memory_space_config() const
173 {
174 	return space_config_vector {
175 		std::make_pair(0, &m_space_config)
176 	};
177 }
178 
179 
180 //-------------------------------------------------
181 //  rom_region - device-specific ROM region
182 //-------------------------------------------------
183 
device_rom_region() const184 const tiny_rom_entry *upd7220_device::device_rom_region() const
185 {
186 	return ROM_NAME( upd7220 );
187 }
188 
189 
190 
191 //**************************************************************************
192 //  INLINE HELPERS
193 //**************************************************************************
194 
195 //-------------------------------------------------
196 //  readbyte - read a byte at the given address
197 //-------------------------------------------------
198 
readbyte(offs_t address)199 inline uint8_t upd7220_device::readbyte(offs_t address)
200 {
201 	return space().read_byte(address);
202 }
203 
204 
205 //-------------------------------------------------
206 //  writebyte - write a byte at the given address
207 //-------------------------------------------------
208 
writebyte(offs_t address,uint8_t data)209 inline void upd7220_device::writebyte(offs_t address, uint8_t data)
210 {
211 	space().write_byte(address, data);
212 }
213 
readword(offs_t address)214 inline uint16_t upd7220_device::readword(offs_t address)
215 {
216 	return space().read_word(address);
217 }
218 
219 
writeword(offs_t address,uint16_t data)220 inline void upd7220_device::writeword(offs_t address, uint16_t data)
221 {
222 	space().write_word(address, data);
223 }
224 
225 //-------------------------------------------------
226 //  fifo_clear -
227 //-------------------------------------------------
228 
fifo_clear()229 inline void upd7220_device::fifo_clear()
230 {
231 	for (int i = 0; i < 16; i++)
232 	{
233 		m_fifo[i] = 0;
234 		m_fifo_flag[i] = FIFO_EMPTY;
235 	}
236 
237 	m_fifo_ptr = -1;
238 
239 	m_sr &= ~UPD7220_SR_DATA_READY;
240 	m_sr |= UPD7220_SR_FIFO_EMPTY;
241 	m_sr &= ~UPD7220_SR_FIFO_FULL;
242 }
243 
244 
245 //-------------------------------------------------
246 //  fifo_param_count -
247 //-------------------------------------------------
248 
fifo_param_count()249 inline int upd7220_device::fifo_param_count()
250 {
251 	int i;
252 
253 	for (i = 0; i < 16; i++)
254 	{
255 		if (m_fifo_flag[i] != FIFO_PARAMETER) break;
256 	}
257 
258 	return i;
259 }
260 
261 
262 //-------------------------------------------------
263 //  fifo_set_direction -
264 //-------------------------------------------------
265 
fifo_set_direction(int dir)266 inline void upd7220_device::fifo_set_direction(int dir)
267 {
268 	if (m_fifo_dir != dir)
269 	{
270 		fifo_clear();
271 	}
272 
273 	m_fifo_dir = dir;
274 }
275 
276 
277 //-------------------------------------------------
278 //  queue -
279 //-------------------------------------------------
280 
queue(uint8_t data,int flag)281 inline void upd7220_device::queue(uint8_t data, int flag)
282 {
283 	if (m_fifo_ptr < 15)
284 	{
285 		m_fifo_ptr++;
286 
287 		m_fifo[m_fifo_ptr] = data;
288 		m_fifo_flag[m_fifo_ptr] = flag;
289 
290 		if (m_fifo_ptr == 16)
291 		{
292 			m_sr |= UPD7220_SR_FIFO_FULL;
293 		}
294 
295 		m_sr &= ~UPD7220_SR_FIFO_EMPTY;
296 	}
297 	else
298 	{
299 		// TODO what happen? somebody set us up the bomb
300 		logerror("FIFO?\n");
301 	}
302 }
303 
304 
305 //-------------------------------------------------
306 //  dequeue -
307 //-------------------------------------------------
308 
dequeue(uint8_t * data,int * flag)309 inline void upd7220_device::dequeue(uint8_t *data, int *flag)
310 {
311 	*data = m_fifo[0];
312 	*flag = m_fifo_flag[0];
313 
314 	if (m_fifo_ptr > -1)
315 	{
316 		for (int i = 0; i < 15; i++)
317 		{
318 			m_fifo[i] = m_fifo[i + 1];
319 			m_fifo_flag[i] = m_fifo_flag[i + 1];
320 		}
321 
322 		m_fifo[15] = 0;
323 		m_fifo_flag[15] = 0;
324 
325 		m_fifo_ptr--;
326 
327 		if (m_fifo_ptr <= 0)
328 			m_sr |= UPD7220_SR_FIFO_EMPTY;
329 		if (m_fifo_ptr == -1)
330 			m_sr &= ~UPD7220_SR_DATA_READY;
331 	}
332 }
333 
334 
335 //-------------------------------------------------
336 //  update_vsync_timer -
337 //-------------------------------------------------
338 
update_vsync_timer(int state)339 inline void upd7220_device::update_vsync_timer(int state)
340 {
341 	int next_y = state ? m_vs : 0;
342 
343 	attotime duration = screen().time_until_pos(next_y, 0);
344 
345 	m_vsync_timer->adjust(duration, !state);
346 }
347 
348 
349 //-------------------------------------------------
350 //  update_hsync_timer -
351 //-------------------------------------------------
352 
update_hsync_timer(int state)353 inline void upd7220_device::update_hsync_timer(int state)
354 {
355 	int y = screen().vpos();
356 
357 	int next_x = state ? m_hs : 0;
358 	int next_y = state ? y : ((y + 1) % m_al);
359 
360 	attotime duration = screen().time_until_pos(next_y, next_x);
361 
362 	m_hsync_timer->adjust(duration, !state);
363 }
364 
365 
366 //-------------------------------------------------
367 //  update_blank_timer -
368 //-------------------------------------------------
369 
update_blank_timer(int state)370 inline void upd7220_device::update_blank_timer(int state)
371 {
372 	int y = screen().vpos();
373 
374 	int next_x = state ? (m_hs + m_hbp) : (m_hs + m_hbp + (m_aw << 3));
375 	int next_y = state ? ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1)) : y;
376 
377 	attotime duration = screen().time_until_pos(next_y, next_x);
378 
379 	m_hsync_timer->adjust(duration, !state);
380 }
381 
382 
383 //-------------------------------------------------
384 //  recompute_parameters -
385 //-------------------------------------------------
386 
recompute_parameters()387 inline void upd7220_device::recompute_parameters()
388 {
389 	int horiz_mult = 16, vert_mult = 1;
390 	/* TODO: assume that the pitch also controls number of horizontal pixels in a single cell */
391 	// horiz_mult = 4 if both mixed and interlace?
392 	if((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED)
393 		horiz_mult = 8;
394 	else if((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON)
395 	{
396 		// in interlaced mode every line contains both fields
397 		horiz_mult = 8; // TODO this breaks compis uhrg video, characters are 16 pixels wide in interlaced mode too
398 		vert_mult = 2;
399 	}
400 
401 	int horiz_pix_total = (m_hs + m_hbp + m_hfp + m_aw) * horiz_mult;
402 	int vert_pix_total = (m_vs + m_vbp + m_al + m_vfp) * vert_mult;
403 
404 	//printf("%d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp);
405 	//printf("%d %d\n",m_aw * 8,m_pitch * 8);
406 
407 	if (horiz_pix_total == 0 || vert_pix_total == 0) //bail out if screen params aren't valid
408 		return;
409 
410 	attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock() * 8) * horiz_pix_total * vert_pix_total;
411 
412 	rectangle visarea(
413 			0, //(m_hs + m_hbp) * 8;
414 			m_aw * horiz_mult - 1,//horiz_pix_total - (m_hfp * 8) - 1;
415 			m_vbp, //m_vs + m_vbp;
416 			m_al * vert_mult + m_vbp - 1);//vert_pix_total - m_vfp - 1;
417 
418 	LOG("uPD7220 Screen: %u x %u @ %f Hz\n", horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
419 	LOG("Visible Area: (%u, %u) - (%u, %u)\n", visarea.left(), visarea.top(), visarea.right(), visarea.bottom());
420 	LOG("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch);
421 	LOG("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp);
422 
423 	if (m_m)
424 	{
425 		screen().configure(horiz_pix_total, vert_pix_total, visarea, refresh);
426 
427 		update_hsync_timer(0);
428 		update_vsync_timer(0);
429 	}
430 	else
431 	{
432 		m_hsync_timer->enable(0);
433 		m_vsync_timer->enable(0);
434 	}
435 
436 	update_blank_timer(0);
437 }
438 
439 
440 //-------------------------------------------------
441 //  reset_figs_param -
442 //-------------------------------------------------
443 
reset_figs_param()444 inline void upd7220_device::reset_figs_param()
445 {
446 	m_figs.m_dc = 0x0000;
447 	m_figs.m_d = 0x0008;
448 	m_figs.m_d1 = 0x0008;
449 	m_figs.m_d2 = 0x0000;
450 	m_figs.m_dm = 0x0000;
451 	m_figs.m_gd = 0;
452 }
453 
454 
455 //-------------------------------------------------
456 //  read_vram -
457 //-------------------------------------------------
458 
read_vram(uint8_t type,uint8_t mod)459 inline void upd7220_device::read_vram(uint8_t type, uint8_t mod)
460 {
461 	if (type == 1)
462 	{
463 		LOG("uPD7220 invalid type 1 RDAT parameter\n");
464 		return;
465 	}
466 
467 	if (mod)
468 		LOG("uPD7220 RDAT used with mod = %02x?\n",mod);
469 
470 	while (m_figs.m_dc && m_fifo_ptr < (type ? 15 : 14))
471 	{
472 		switch(type)
473 		{
474 			case 0:
475 				queue(readbyte(m_ead*2), 0);
476 				queue(readbyte(m_ead*2+1), 0);
477 				break;
478 			case 2:
479 				queue(readbyte(m_ead*2), 0);
480 				break;
481 			case 3:
482 				queue(readbyte(m_ead*2+1), 0);
483 				break;
484 		}
485 
486 		m_figs.m_dc--;
487 		m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch);
488 		m_ead &= 0x3ffff;
489 	}
490 
491 	if (m_figs.m_dc == 0)
492 		reset_figs_param();
493 }
494 
495 
496 //-------------------------------------------------
497 //  write_vram -
498 //-------------------------------------------------
499 
write_vram(uint8_t type,uint8_t mod)500 inline void upd7220_device::write_vram(uint8_t type, uint8_t mod)
501 {
502 	uint16_t result;
503 
504 	if (type == 1)
505 	{
506 		logerror("uPD7220 invalid type 1 WDAT parameter\n");
507 		return;
508 	}
509 
510 	result = 0;
511 
512 	result = m_pr[1] | (m_pr[2] << 8);
513 
514 	switch(type)
515 	{
516 		case 0:
517 			result &= m_mask;
518 			break;
519 		case 2:
520 			result &= (m_mask & 0xff);
521 			break;
522 		case 3:
523 			result <<= 8;
524 			result &= (m_mask & 0xff00);
525 			break;
526 	}
527 
528 	//if(result)
529 	{
530 		//printf("%04x %02x %02x %04x %02x %02x\n",readbyte(m_ead),m_pr[1],m_pr[2],m_mask,type,mod);
531 		//printf("%04x %02x %02x\n",m_ead,m_figs.m_dir,m_pitch);
532 		//printf("%04x %04x %02x %04x\n",m_ead,result,mod,m_figs.m_dc);
533 	}
534 
535 	for(int i = 0; i < m_figs.m_dc + 1; i++)
536 	{
537 		switch(mod & 3)
538 		{
539 			case 0x00: //replace
540 				if(type == 0)
541 					writeword(m_ead*2+0, result);
542 				if(type == 2)
543 					writebyte(m_ead*2+0, result & 0xff);
544 				if(type == 3)
545 					writebyte(m_ead*2+1, result >> 8);
546 				break;
547 			case 0x01: //complement
548 				if(type == 0)
549 					writeword(m_ead*2+0, readword(m_ead*2+0) ^ result);
550 				if(type == 2)
551 					writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff));
552 				if(type == 3)
553 					writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8));
554 				break;
555 			case 0x02: //reset to zero
556 				if(type == 0)
557 					writeword(m_ead*2+0, readword(m_ead*2+0) & ~result);
558 				if(type == 2)
559 					writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff));
560 				if(type == 3)
561 					writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8));
562 				break;
563 			case 0x03: //set to one
564 				if(type == 0)
565 					writeword(m_ead*2+0, readword(m_ead*2+0) | result);
566 				if(type == 2)
567 					writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff));
568 				if(type == 3)
569 					writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8));
570 				break;
571 		}
572 
573 		m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch);
574 		m_ead &= 0x3ffff;
575 	}
576 }
577 
578 
579 //-------------------------------------------------
580 //  get_text_partition -
581 //-------------------------------------------------
582 
get_text_partition(int index,uint32_t * sad,uint16_t * len,int * im,int * wd)583 inline void upd7220_device::get_text_partition(int index, uint32_t *sad, uint16_t *len, int *im, int *wd)
584 {
585 	*sad = ((m_ra[(index * 4) + 1] & 0x1f) << 8) | m_ra[(index * 4) + 0];
586 	*len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4);
587 	*im = BIT(m_ra[(index * 4) + 3], 6);
588 	*wd = BIT(m_ra[(index * 4) + 3], 7);
589 }
590 
591 
592 //-------------------------------------------------
593 //  get_graphics_partition -
594 //-------------------------------------------------
595 
get_graphics_partition(int index,uint32_t * sad,uint16_t * len,int * im,int * wd)596 inline void upd7220_device::get_graphics_partition(int index, uint32_t *sad, uint16_t *len, int *im, int *wd)
597 {
598 	*sad = ((m_ra[(index * 4) + 2] & 0x03) << 16) | (m_ra[(index * 4) + 1] << 8) | m_ra[(index * 4) + 0];
599 	*len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4);
600 	*im = BIT(m_ra[(index * 4) + 3], 6);
601 	*wd = BIT(m_ra[(index * 4) + 3], 7);
602 }
603 
604 
605 
606 //**************************************************************************
607 //  LIVE DEVICE
608 //**************************************************************************
609 
610 //-------------------------------------------------
611 //  upd7220_device - constructor
612 //-------------------------------------------------
613 
upd7220_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)614 upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
615 	device_t(mconfig, UPD7220, tag, owner, clock),
616 	device_memory_interface(mconfig, *this),
617 	device_video_interface(mconfig, *this),
618 	m_display_cb(*this),
619 	m_draw_text_cb(*this),
620 	m_write_drq(*this),
621 	m_write_hsync(*this),
622 	m_write_vsync(*this),
623 	m_write_blank(*this),
624 	m_mask(0),
625 	m_pitch(0),
626 	m_ead(0),
627 	m_dad(0),
628 	m_lad(0),
629 	m_ra_addr(0),
630 	m_sr(UPD7220_SR_FIFO_EMPTY),
631 	m_cr(0),
632 	m_param_ptr(0),
633 	m_fifo_ptr(-1),
634 	m_fifo_dir(0),
635 	m_mode(0),
636 	m_de(0),
637 	m_m(0),
638 	m_aw(0),
639 	m_al(0),
640 	m_vs(0),
641 	m_vfp(0),
642 	m_vbp(0),
643 	m_hs(0),
644 	m_hfp(0),
645 	m_hbp(0),
646 	m_dc(0),
647 	m_sc(0),
648 	m_br(0),
649 	m_ctop(0),
650 	m_cbot(0),
651 	m_lr(1),
652 	m_disp(0),
653 	m_gchr(0),
654 	m_bitmap_mod(0),
655 	m_space_config("videoram", ENDIANNESS_LITTLE, 16, 18, 0, address_map_constructor(FUNC(upd7220_device::upd7220_vram), this))
656 {
657 	for (int i = 0; i < 16; i++)
658 	{
659 		m_fifo[i] = 0;
660 		m_fifo_flag[i] = FIFO_EMPTY;
661 
662 		m_ra[i] = 0;
663 	}
664 
665 	for (auto & elem : m_pr)
666 	{
667 		elem = 0;
668 	}
669 
670 	memset(&m_figs, 0x00, sizeof(m_figs));
671 }
672 
673 
674 //-------------------------------------------------
675 //  device_start - device-specific startup
676 //-------------------------------------------------
677 
device_start()678 void upd7220_device::device_start()
679 {
680 	// resolve callbacks
681 	m_display_cb.resolve();
682 	m_draw_text_cb.resolve();
683 
684 	m_write_drq.resolve_safe();
685 	m_write_hsync.resolve_safe();
686 	m_write_vsync.resolve_safe();
687 	m_write_blank.resolve_safe();
688 
689 	// allocate timers
690 	m_vsync_timer = timer_alloc(TIMER_VSYNC);
691 	m_hsync_timer = timer_alloc(TIMER_HSYNC);
692 	m_blank_timer = timer_alloc(TIMER_BLANK);
693 
694 	// register for state saving
695 	save_item(NAME(m_ra));
696 	save_item(NAME(m_sr));
697 	save_item(NAME(m_mode));
698 	save_item(NAME(m_de));
699 	save_item(NAME(m_aw));
700 	save_item(NAME(m_al));
701 	save_item(NAME(m_vs));
702 	save_item(NAME(m_vfp));
703 	save_item(NAME(m_vbp));
704 	save_item(NAME(m_hs));
705 	save_item(NAME(m_hfp));
706 	save_item(NAME(m_hbp));
707 	save_item(NAME(m_m));
708 	save_item(NAME(m_dc));
709 	save_item(NAME(m_sc));
710 	save_item(NAME(m_br));
711 	save_item(NAME(m_lr));
712 	save_item(NAME(m_ctop));
713 	save_item(NAME(m_cbot));
714 	save_item(NAME(m_ead));
715 	save_item(NAME(m_dad));
716 	save_item(NAME(m_lad));
717 	save_item(NAME(m_disp));
718 	save_item(NAME(m_gchr));
719 	save_item(NAME(m_mask));
720 	save_item(NAME(m_pitch));
721 	save_item(NAME(m_ra_addr));
722 	save_item(NAME(m_cr));
723 	save_item(NAME(m_pr));
724 	save_item(NAME(m_param_ptr));
725 	save_item(NAME(m_fifo));
726 	save_item(NAME(m_fifo_flag));
727 	save_item(NAME(m_fifo_ptr));
728 	save_item(NAME(m_fifo_dir));
729 	save_item(NAME(m_bitmap_mod));
730 	save_item(NAME(m_figs.m_dir));
731 	save_item(NAME(m_figs.m_figure_type));
732 	save_item(NAME(m_figs.m_dc));
733 	save_item(NAME(m_figs.m_gd));
734 	save_item(NAME(m_figs.m_d));
735 	save_item(NAME(m_figs.m_d1));
736 	save_item(NAME(m_figs.m_d2));
737 	save_item(NAME(m_figs.m_dm));
738 }
739 
740 
741 //-------------------------------------------------
742 //  device_reset - device-specific reset
743 //-------------------------------------------------
744 
device_reset()745 void upd7220_device::device_reset()
746 {
747 	m_write_drq(CLEAR_LINE);
748 }
749 
750 
751 //-------------------------------------------------
752 //  device_timer - handler timer events
753 //-------------------------------------------------
754 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)755 void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
756 {
757 	switch (id)
758 	{
759 	case TIMER_HSYNC:
760 		if (param)
761 		{
762 			m_sr |= UPD7220_SR_HBLANK_ACTIVE;
763 		}
764 		else
765 		{
766 			m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
767 		}
768 
769 		m_write_hsync(param);
770 
771 		update_hsync_timer(param);
772 		break;
773 
774 	case TIMER_VSYNC:
775 		if (param)
776 		{
777 			m_sr |= UPD7220_SR_VSYNC_ACTIVE;
778 		}
779 		else
780 		{
781 			m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
782 		}
783 
784 		m_write_vsync(param);
785 
786 		update_vsync_timer(param);
787 		break;
788 
789 	case TIMER_BLANK:
790 		if (param)
791 		{
792 			m_sr |= UPD7220_SR_HBLANK_ACTIVE;
793 		}
794 		else
795 		{
796 			m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
797 		}
798 
799 		m_write_blank(param);
800 
801 		update_blank_timer(param);
802 		break;
803 	}
804 }
805 
806 
807 //-------------------------------------------------
808 //  draw_pixel -
809 //-------------------------------------------------
810 
draw_pixel(int x,int y,int xi,uint16_t tile_data)811 void upd7220_device::draw_pixel(int x, int y, int xi, uint16_t tile_data)
812 {
813 	uint32_t addr = ((y * (m_pitch << (m_figs.m_gd ? 0 : 1))) + (x >> 3)) & 0x3ffff;
814 	uint16_t data = readword(addr);
815 	uint16_t new_pixel = (tile_data & (1 << (xi & 0xf))) ? (1 << (x & 0xf)) : 0;
816 
817 	switch(m_bitmap_mod)
818 	{
819 		case 0: //replace
820 			writeword(addr, (data & ~(1 << (x & 0xf))) | new_pixel);
821 			break;
822 		case 1: //complement
823 			writeword(addr, data ^ new_pixel);
824 			break;
825 		case 2: //reset
826 			writeword(addr, data & ~new_pixel);
827 			break;
828 		case 3: //set
829 			writeword(addr, data | new_pixel);
830 			break;
831 	}
832 }
833 
834 
835 //-------------------------------------------------
836 //  draw_line -
837 //-------------------------------------------------
838 
draw_line(int x,int y)839 void upd7220_device::draw_line(int x, int y)
840 {
841 	int xi, yi;
842 	int d = (m_figs.m_d & 0x2000) ? (int16_t)(m_figs.m_d | 0xe000) : m_figs.m_d;
843 	int d1 = (m_figs.m_d1 & 0x2000) ? (int16_t)(m_figs.m_d1 | 0xe000) : m_figs.m_d1;
844 	int d2 = (m_figs.m_d2 & 0x2000) ? (int16_t)(m_figs.m_d2 | 0xe000) : m_figs.m_d2;
845 	uint16_t pattern = (m_ra[8]) | (m_ra[9]<<8);
846 	const int dot_dir[4] = {1, -1, -1, 1};
847 
848 	LOG("uPD7220 line check: %d %d %02x %08x %d %d %d\n",x,y,m_figs.m_dir,m_ead,d1,m_figs.m_dc,m_bitmap_mod);
849 
850 	for(yi = xi = 0; yi <= m_figs.m_dc; yi++)
851 	{
852 		switch(m_figs.m_dir & 3)
853 		{
854 			case 1:
855 			case 2:
856 				draw_pixel(yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, xi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
857 				break;
858 			default:
859 				draw_pixel(xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, yi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
860 				break;
861 		}
862 		if(d > 0)
863 		{
864 			xi++;
865 			d += d2;
866 		}
867 		else
868 			d += d1;
869 	}
870 
871 	switch(m_figs.m_dir & 3)
872 	{
873 		case 1:
874 		case 2:
875 			x += yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3];
876 			y += xi * dot_dir[m_figs.m_dir >> 1];
877 			break;
878 		default:
879 			x += xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3];
880 			y += yi * dot_dir[m_figs.m_dir >> 1];
881 			break;
882 	}
883 
884 	m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
885 	m_dad = x & 0x0f;
886 }
887 
888 //-------------------------------------------------
889 //  draw_arc -
890 //-------------------------------------------------
891 
draw_arc(int x,int y)892 void upd7220_device::draw_arc(int x, int y)
893 {
894 	int xi = 0, err = -m_figs.m_d, d = m_figs.m_d + 1;
895 	uint16_t pattern = (m_ra[8]) | (m_ra[9]<<8);
896 	const int dot_dir[4] = {1, -1, -1, 1};
897 
898 	LOG("uPD7220 arc check: %d %d %02x %08x %d %d %d\n",x,y,m_figs.m_dir,m_ead,m_figs.m_dm,m_figs.m_dc,m_figs.m_d);
899 
900 	for(int yi = 0; yi <= m_figs.m_dc; yi++)
901 	{
902 		if(yi >= m_figs.m_dm)
903 		{
904 			switch(m_figs.m_dir & 3)
905 			{
906 				case 1:
907 				case 2:
908 					draw_pixel(yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, xi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
909 					break;
910 				default:
911 					draw_pixel(xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, yi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
912 					break;
913 			}
914 		}
915 		if(err < 0)
916 			err += (yi + 1) << 1;
917 		else
918 		{
919 			xi++;
920 			d--;
921 			err += (yi - d + 1) << 1;
922 		}
923 	}
924 	switch(m_figs.m_dir & 3)
925 	{
926 		case 1:
927 		case 2:
928 			x += (m_figs.m_dc + 1) * dot_dir[((m_figs.m_dir >> 1) + 3) & 3];
929 			break;
930 		default:
931 			y += (m_figs.m_dc + 1) * dot_dir[m_figs.m_dir >> 1];
932 			break;
933 	}
934 
935 	m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
936 	m_dad = x & 0x0f;
937 }
938 
939 //-------------------------------------------------
940 //  draw_rectangle -
941 //-------------------------------------------------
942 
draw_rectangle(int x,int y)943 void upd7220_device::draw_rectangle(int x, int y)
944 {
945 	int i;
946 	const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 };
947 	const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 };
948 	uint8_t rect_type,rect_dir;
949 	uint16_t pattern = (m_ra[8]) | (m_ra[9]<<8);
950 
951 	LOG("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead);
952 
953 	rect_type = (m_figs.m_dir & 1) << 2;
954 	rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3);
955 
956 	for(i = 0;i < m_figs.m_d;i++)
957 	{
958 		draw_pixel(x,y,i,pattern);
959 		x+=rect_x_dir[rect_dir];
960 		y+=rect_y_dir[rect_dir];
961 	}
962 
963 	rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3);
964 
965 	for(i = 0;i < m_figs.m_d2;i++)
966 	{
967 		draw_pixel(x,y,i,pattern);
968 		x+=rect_x_dir[rect_dir];
969 		y+=rect_y_dir[rect_dir];
970 	}
971 
972 	rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3);
973 
974 	for(i = 0;i < m_figs.m_d;i++)
975 	{
976 		draw_pixel(x,y,i,pattern);
977 		x+=rect_x_dir[rect_dir];
978 		y+=rect_y_dir[rect_dir];
979 	}
980 
981 	rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3);
982 
983 	for(i = 0;i < m_figs.m_d2;i++)
984 	{
985 		draw_pixel(x,y,i,pattern);
986 		x+=rect_x_dir[rect_dir];
987 		y+=rect_y_dir[rect_dir];
988 	}
989 
990 	m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
991 	m_dad = x & 0x0f;
992 
993 }
994 
995 
996 //-------------------------------------------------
997 //  draw_char -
998 //-------------------------------------------------
999 
draw_char(int x,int y)1000 void upd7220_device::draw_char(int x, int y)
1001 {
1002 	int isize,psize;
1003 	uint16_t tile_data;
1004 
1005 	LOG("uPD7220 char check: %d %d %02x %08x %d %d %02x\n",x,y,m_figs.m_dir,m_ead,m_figs.m_d,m_figs.m_dc,m_figs.m_figure_type);
1006 
1007 	/* QX10 may require upper bits for psize, VT240 requires the opposite */
1008 	isize = m_figs.m_d;
1009 	psize = m_figs.m_dc + 1;
1010 
1011 	for(int pi = 0; pi < psize; pi++)
1012 	{
1013 		tile_data = (m_ra[((psize-1-pi) & 7) | 8] << 8) | m_ra[((psize-1-pi) & 7) | 8];
1014 		for(int pz = 0; pz <= m_gchr; pz++)
1015 		{
1016 			int ii = 0, curpixel = 0;
1017 			if(pi & 1)
1018 			{
1019 				ii = isize - 1;
1020 				curpixel = (isize * (m_gchr + 1)) - 1;
1021 			}
1022 			while(pi & 1 ? ii >= 0 : ii < isize)
1023 			{
1024 				for(int iz = 0; iz <= m_gchr; iz++)
1025 				{
1026 					draw_pixel(x + (curpixel * x_dir[m_figs.m_dir]), y + (curpixel * y_dir[m_figs.m_dir]), ii, tile_data);
1027 					if(pi & 1)
1028 						curpixel--;
1029 					else
1030 						curpixel++;
1031 				}
1032 				if(pi & 1)
1033 					ii--;
1034 				else
1035 					ii++;
1036 			}
1037 			if(m_figs.m_figure_type == 2)
1038 			{
1039 				x += x_dir[(m_figs.m_dir + 2) & 7];
1040 				y += y_dir[(m_figs.m_dir + 2) & 7];
1041 			}
1042 			else
1043 			{
1044 				x += x_dir[(m_figs.m_dir + 1) & 7];
1045 				y += y_dir[(m_figs.m_dir + 1) & 7];
1046 			}
1047 		}
1048 	}
1049 
1050 	m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
1051 	m_dad = (x & 0xf);
1052 }
1053 
1054 
1055 //-------------------------------------------------
1056 //  translate_command -
1057 //-------------------------------------------------
1058 
translate_command(uint8_t data)1059 int upd7220_device::translate_command(uint8_t data)
1060 {
1061 	int command = COMMAND_INVALID;
1062 
1063 	switch (data)
1064 	{
1065 	case UPD7220_COMMAND_RESET: command = COMMAND_RESET; break;
1066 	case UPD7220_COMMAND_CCHAR: command = COMMAND_CCHAR; break;
1067 	case UPD7220_COMMAND_START: command = COMMAND_START; break;
1068 	case UPD7220_COMMAND_ZOOM:  command = COMMAND_ZOOM;  break;
1069 	case UPD7220_COMMAND_CURS:  command = COMMAND_CURS;  break;
1070 	case UPD7220_COMMAND_PITCH: command = COMMAND_PITCH; break;
1071 	case UPD7220_COMMAND_MASK:  command = COMMAND_MASK;  break;
1072 	case UPD7220_COMMAND_FIGS:  command = COMMAND_FIGS;  break;
1073 	case UPD7220_COMMAND_FIGD:  command = COMMAND_FIGD;  break;
1074 	case UPD7220_COMMAND_GCHRD: command = COMMAND_GCHRD; break;
1075 	case UPD7220_COMMAND_CURD:  command = COMMAND_CURD;  break;
1076 	case UPD7220_COMMAND_LPRD:  command = COMMAND_LPRD;  break;
1077 	case UPD7220_COMMAND_5A:    command = COMMAND_5A;    break;
1078 	case UPD7220_COMMAND_05:    command = COMMAND_05;    break;
1079 	default:
1080 		switch (data & 0xfe)
1081 		{
1082 		case UPD7220_COMMAND_SYNC:  command = COMMAND_SYNC;  break;
1083 		case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break;
1084 		case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break;
1085 		default:
1086 			switch (data & 0xf0)
1087 			{
1088 			case UPD7220_COMMAND_PRAM: command = COMMAND_PRAM; break;
1089 			default:
1090 				switch (data & 0xe4)
1091 				{
1092 				case UPD7220_COMMAND_WDAT: command = COMMAND_WDAT; break;
1093 				case UPD7220_COMMAND_RDAT: command = COMMAND_RDAT; break;
1094 				case UPD7220_COMMAND_DMAR: command = COMMAND_DMAR; break;
1095 				case UPD7220_COMMAND_DMAW: command = COMMAND_DMAW; break;
1096 				}
1097 			}
1098 		}
1099 	}
1100 
1101 	return command;
1102 }
1103 
1104 
1105 //-------------------------------------------------
1106 //  process_fifo -
1107 //-------------------------------------------------
1108 
process_fifo()1109 void upd7220_device::process_fifo()
1110 {
1111 	uint8_t data;
1112 	int flag;
1113 	uint16_t eff_pitch = m_pitch >> m_figs.m_gd;
1114 	int cr;
1115 
1116 	dequeue(&data, &flag);
1117 
1118 	if (flag == FIFO_COMMAND)
1119 	{
1120 		cr = translate_command(data);
1121 		if (cr != COMMAND_BCTRL) // workaround for Rainbow 100 Windows 1.03, needs verification
1122 		{
1123 			m_cr = data;
1124 			m_param_ptr = 1;
1125 		}
1126 	}
1127 	else
1128 	{
1129 		cr = translate_command(m_cr);
1130 		m_pr[m_param_ptr] = data;
1131 		m_param_ptr++;
1132 	}
1133 
1134 	switch (cr)
1135 	{
1136 	case COMMAND_INVALID:
1137 		logerror("uPD7220 Invalid Command Byte %02x\n", m_cr);
1138 		break;
1139 
1140 	case COMMAND_5A:
1141 		if (m_param_ptr == 4)
1142 			logerror("uPD7220 Undocumented Command 0x5A Executed %02x %02x %02x\n", m_pr[1],m_pr[2],m_pr[3] );
1143 		break;
1144 
1145 	case COMMAND_RESET: /* reset */
1146 		switch (m_param_ptr)
1147 		{
1148 		case 0:
1149 			LOG("uPD7220 RESET\n");
1150 
1151 			m_de = 0;
1152 			m_ra[0] = m_ra[1] = m_ra[2] = 0;
1153 			m_ra[3] = 0x19;
1154 			m_ead = 0;
1155 			m_dad = 0;
1156 			m_mask = 0;
1157 			break;
1158 
1159 		case 9:
1160 			m_mode = m_pr[1];
1161 			m_aw = m_pr[2] + 2;
1162 			m_hs = (m_pr[3] & 0x1f) + 1;
1163 			m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5);
1164 			m_hfp = (m_pr[4] >> 2) + 1;
1165 			m_hbp = (m_pr[5] & 0x3f) + 1;
1166 			m_vfp = m_pr[6] & 0x3f;
1167 			m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7];
1168 			m_vbp = m_pr[8] >> 2;
1169 
1170 			m_pitch = m_aw;
1171 
1172 			LOG("uPD7220 Mode: %02x\n", m_mode);
1173 			LOG("uPD7220 AW: %u\n", m_aw);
1174 			LOG("uPD7220 HS: %u\n", m_hs);
1175 			LOG("uPD7220 VS: %u\n", m_vs);
1176 			LOG("uPD7220 HFP: %u\n", m_hfp);
1177 			LOG("uPD7220 HBP: %u\n", m_hbp);
1178 			LOG("uPD7220 VFP: %u\n", m_vfp);
1179 			LOG("uPD7220 AL: %u\n", m_al);
1180 			LOG("uPD7220 VBP: %u\n", m_vbp);
1181 			LOG("uPD7220 PITCH: %u\n", m_pitch);
1182 
1183 			recompute_parameters();
1184 			break;
1185 		}
1186 		break;
1187 
1188 	case COMMAND_SYNC: /* sync format specify */
1189 		if (m_param_ptr == 9)
1190 		{
1191 			m_mode = m_pr[1];
1192 			m_aw = m_pr[2] + 2;
1193 			m_hs = (m_pr[3] & 0x1f) + 1;
1194 			m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5);
1195 			m_hfp = (m_pr[4] >> 2) + 1;
1196 			m_hbp = (m_pr[5] & 0x3f) + 1;
1197 			m_vfp = m_pr[6] & 0x3f;
1198 			m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7];
1199 			m_vbp = m_pr[8] >> 2;
1200 
1201 			m_pitch = m_aw;
1202 
1203 			LOG("uPD7220 Mode: %02x\n", m_mode);
1204 			LOG("uPD7220 AW: %u\n", m_aw);
1205 			LOG("uPD7220 HS: %u\n", m_hs);
1206 			LOG("uPD7220 VS: %u\n", m_vs);
1207 			LOG("uPD7220 HFP: %u\n", m_hfp);
1208 			LOG("uPD7220 HBP: %u\n", m_hbp);
1209 			LOG("uPD7220 VFP: %u\n", m_vfp);
1210 			LOG("uPD7220 AL: %u\n", m_al);
1211 			LOG("uPD7220 VBP: %u\n", m_vbp);
1212 			LOG("uPD7220 PITCH: %u\n", m_pitch);
1213 
1214 			recompute_parameters();
1215 		}
1216 		break;
1217 
1218 	case COMMAND_VSYNC: /* vertical sync mode */
1219 		m_m = m_cr & 0x01;
1220 
1221 		LOG("uPD7220 M: %u\n", m_m);
1222 
1223 		recompute_parameters();
1224 		break;
1225 
1226 	case COMMAND_CCHAR: /* cursor & character characteristics */
1227 		if(m_param_ptr == 2)
1228 		{
1229 			m_lr = (m_pr[1] & 0x1f) + 1;
1230 			m_dc = BIT(m_pr[1], 7);
1231 
1232 			LOG("uPD7220 LR: %u\n", m_lr);
1233 			LOG("uPD7220 DC: %u\n", m_dc);
1234 		}
1235 
1236 		if(m_param_ptr == 3)
1237 		{
1238 			m_ctop = m_pr[2] & 0x1f;
1239 			m_sc = BIT(m_pr[2], 5);
1240 			m_br = (m_pr[2] >> 6); /* guess, assume that blink rate clears upper bits (if any) */
1241 
1242 			LOG("uPD7220 CTOP: %u\n", m_ctop);
1243 			LOG("uPD7220 SC: %u\n", m_sc);
1244 		}
1245 
1246 		if(m_param_ptr == 4)
1247 		{
1248 			m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6);
1249 			m_cbot = m_pr[3] >> 3;
1250 
1251 			LOG("uPD7220 BR: %u\n", m_br);
1252 			LOG("uPD7220 CBOT: %u\n", m_cbot);
1253 		}
1254 		break;
1255 
1256 	case COMMAND_START: /* start display & end idle mode */
1257 		m_de = 1;
1258 
1259 		//LOG("uPD7220 '%s' DE: 1\n");
1260 		break;
1261 
1262 	case COMMAND_05:
1263 		m_de = 0;
1264 		break;
1265 
1266 	case COMMAND_BCTRL: /* display blanking control */
1267 		m_de = data & 0x01;
1268 
1269 		//LOG("uPD7220 DE: %u\n", m_de);
1270 		break;
1271 
1272 	case COMMAND_ZOOM: /* zoom factors specify */
1273 		if (flag == FIFO_PARAMETER)
1274 		{
1275 			m_gchr = m_pr[1] & 0x0f;
1276 			m_disp = m_pr[1] >> 4;
1277 
1278 			LOG("uPD7220 GCHR: %01x\n", m_gchr);
1279 			LOG("uPD7220 DISP: %01x\n", m_disp);
1280 		}
1281 		break;
1282 
1283 	case COMMAND_CURS: /* cursor position specify */
1284 		if (m_param_ptr >= 3)
1285 		{
1286 			uint8_t upper_addr = (m_param_ptr == 3) ? 0 : (m_pr[3] & 0x03);
1287 
1288 			m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1];
1289 
1290 			LOG("uPD7220 EAD: %06x\n", m_ead);
1291 
1292 			if(m_param_ptr == 4)
1293 			{
1294 				m_dad = m_pr[3] >> 4;
1295 				LOG("uPD7220 DAD: %01x\n", m_dad);
1296 			}
1297 		}
1298 		break;
1299 
1300 	case COMMAND_PRAM: /* parameter RAM load */
1301 		if (flag == FIFO_COMMAND)
1302 		{
1303 			m_ra_addr = m_cr & 0x0f;
1304 		}
1305 		else
1306 		{
1307 			if (m_ra_addr < 16)
1308 			{
1309 				LOG("uPD7220 RA%u: %02x\n", m_ra_addr, data);
1310 
1311 				m_ra[m_ra_addr] = data;
1312 				m_ra_addr++;
1313 			}
1314 
1315 			m_param_ptr = 0;
1316 		}
1317 		break;
1318 
1319 	case COMMAND_PITCH: /* pitch specification */
1320 		if (flag == FIFO_PARAMETER)
1321 		{
1322 			m_pitch = data;
1323 
1324 			LOG("uPD7220 PITCH: %u\n", m_pitch);
1325 		}
1326 		break;
1327 
1328 	case COMMAND_WDAT: /* write data into display memory */
1329 		m_bitmap_mod = m_cr & 3;
1330 
1331 		if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10))
1332 		{
1333 			LOG("%02x = %02x %02x (%c) %06x %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1]?m_pr[1]:' ',m_ead,m_figs.m_dc);
1334 			fifo_set_direction(FIFO_WRITE);
1335 
1336 			write_vram((m_cr & 0x18) >> 3,m_cr & 3);
1337 			reset_figs_param();
1338 			m_param_ptr = 1;
1339 		}
1340 		break;
1341 
1342 	case COMMAND_MASK: /* mask register load */
1343 		if (m_param_ptr == 3)
1344 		{
1345 			m_mask = (m_pr[2] << 8) | m_pr[1];
1346 
1347 			LOG("uPD7220 MASK: %04x\n", m_mask);
1348 		}
1349 		break;
1350 
1351 	case COMMAND_FIGS: /* figure drawing parameters specify */
1352 		if (m_param_ptr == 2)
1353 		{
1354 			m_figs.m_dir = m_pr[1] & 0x7;
1355 			m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3;
1356 
1357 			//if(m_figs.m_dir != 2)
1358 			//  printf("DIR %02x\n",m_pr[1]);
1359 		}
1360 
1361 		// the Decision Mate V during start-up test upload only 2 params before execute the
1362 		// RDAT command, so I assume this is the expected behaviour, but this needs to be verified.
1363 		if (m_param_ptr == 3)
1364 			m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00);
1365 
1366 		if (m_param_ptr == 4)
1367 		{
1368 			m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8);
1369 			m_figs.m_gd = (m_pr[3] & 0x40) && ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED);
1370 		}
1371 
1372 		if (m_param_ptr == 6)
1373 			m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8);
1374 
1375 		if (m_param_ptr == 8)
1376 			m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8);
1377 
1378 		if (m_param_ptr == 10)
1379 			m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8);
1380 
1381 		if (m_param_ptr == 12)
1382 			m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8);
1383 
1384 		break;
1385 
1386 	case COMMAND_FIGD: /* figure draw start */
1387 		if(m_figs.m_figure_type == 0)
1388 			draw_pixel(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch),m_dad,(m_ra[8]) | (m_ra[9]<<8));
1389 		else if(m_figs.m_figure_type == 1)
1390 			draw_line(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
1391 		else if(m_figs.m_figure_type == 4)
1392 			draw_arc(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
1393 		else if(m_figs.m_figure_type == 8)
1394 			draw_rectangle(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
1395 		else
1396 			logerror("uPD7220 Unimplemented command FIGD %02x\n", m_figs.m_figure_type);
1397 
1398 		reset_figs_param();
1399 		m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
1400 		break;
1401 
1402 	case COMMAND_GCHRD: /* graphics character draw and area filling start */
1403 		if((m_figs.m_figure_type & 0xf) == 2)
1404 			draw_char(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
1405 		else
1406 			logerror("uPD7220 Unimplemented command GCHRD %02x\n", m_figs.m_figure_type);
1407 
1408 		reset_figs_param();
1409 		m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
1410 		break;
1411 
1412 	case COMMAND_RDAT: /* read data from display memory */
1413 		fifo_set_direction(FIFO_READ);
1414 
1415 		read_vram((m_cr & 0x18) >> 3,m_cr & 3);
1416 
1417 		m_sr |= UPD7220_SR_DATA_READY;
1418 		break;
1419 
1420 	case COMMAND_CURD: /* cursor address read */
1421 	{
1422 		uint16_t dad = 1 << m_dad;
1423 		fifo_set_direction(FIFO_READ);
1424 
1425 		queue(m_ead & 0xff, 0);
1426 		queue((m_ead >> 8) & 0xff, 0);
1427 		queue(m_ead >> 16, 0);
1428 		queue(dad & 0xff, 0);
1429 		queue(dad >> 8, 0);
1430 
1431 		m_sr |= UPD7220_SR_DATA_READY;
1432 		break;
1433 	}
1434 
1435 	case COMMAND_LPRD: /* light pen address read */
1436 		fifo_set_direction(FIFO_READ);
1437 
1438 		queue(m_lad & 0xff, 0);
1439 		queue((m_lad >> 8) & 0xff, 0);
1440 		queue(m_lad >> 16, 0);
1441 
1442 		m_sr |= UPD7220_SR_DATA_READY;
1443 		m_sr &= ~UPD7220_SR_LIGHT_PEN_DETECT;
1444 		break;
1445 
1446 	case COMMAND_DMAR: /* DMA read request */
1447 		logerror("uPD7220 Unimplemented command DMAR\n");
1448 		break;
1449 
1450 	case COMMAND_DMAW: /* DMA write request */
1451 		logerror("uPD7220 Unimplemented command DMAW\n");
1452 		break;
1453 	}
1454 }
1455 
1456 
1457 //-------------------------------------------------
1458 //  continue command
1459 //-------------------------------------------------
1460 
continue_command()1461 void upd7220_device::continue_command()
1462 {
1463 	// continue RDAT command when data to read are larger than the FIFO (a5105 and dmv text scrolling)
1464 	if (m_figs.m_dc && translate_command(m_cr) == COMMAND_RDAT)
1465 	{
1466 		read_vram((m_cr & 0x18) >> 3, m_cr & 3);
1467 		m_sr |= UPD7220_SR_DATA_READY;
1468 	}
1469 }
1470 
1471 
1472 //-------------------------------------------------
1473 //  read -
1474 //-------------------------------------------------
1475 
read(offs_t offset)1476 uint8_t upd7220_device::read(offs_t offset)
1477 {
1478 	uint8_t data;
1479 
1480 	if (offset & 1)
1481 	{
1482 		/* FIFO read */
1483 		int flag;
1484 		fifo_set_direction(FIFO_READ);
1485 		dequeue(&data, &flag);
1486 
1487 		continue_command();
1488 	}
1489 	else
1490 	{
1491 		/* status register */
1492 		data = m_sr;
1493 
1494 		/* TODO: timing of these */
1495 		m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS;
1496 		m_sr &= ~UPD7220_SR_DMA_EXECUTE;
1497 	}
1498 
1499 	return data;
1500 }
1501 
1502 
1503 //-------------------------------------------------
1504 //  write -
1505 //-------------------------------------------------
1506 
write(offs_t offset,uint8_t data)1507 void upd7220_device::write(offs_t offset, uint8_t data)
1508 {
1509 	if (offset & 1)
1510 	{
1511 		/* command into FIFO */
1512 		fifo_set_direction(FIFO_WRITE);
1513 		queue(data, 1);
1514 	}
1515 	else
1516 	{
1517 		/* parameter into FIFO */
1518 //      fifo_set_direction(FIFO_WRITE);
1519 		queue(data, 0);
1520 	}
1521 
1522 	process_fifo();
1523 }
1524 
1525 
1526 //-------------------------------------------------
1527 //  dack_r -
1528 //-------------------------------------------------
1529 
dack_r()1530 uint8_t upd7220_device::dack_r()
1531 {
1532 	return 0;
1533 }
1534 
1535 
1536 //-------------------------------------------------
1537 //  dack_w -
1538 //-------------------------------------------------
1539 
dack_w(uint8_t data)1540 void upd7220_device::dack_w(uint8_t data)
1541 {
1542 }
1543 
1544 
1545 //-------------------------------------------------
1546 //  ext_sync_w -
1547 //-------------------------------------------------
1548 
WRITE_LINE_MEMBER(upd7220_device::ext_sync_w)1549 WRITE_LINE_MEMBER( upd7220_device::ext_sync_w )
1550 {
1551 	//LOG("uPD7220 External Synchronization: %u\n", state);
1552 
1553 	if (state)
1554 	{
1555 		m_sr |= UPD7220_SR_VSYNC_ACTIVE;
1556 	}
1557 	else
1558 	{
1559 		m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
1560 	}
1561 }
1562 
1563 
1564 //-------------------------------------------------
1565 //  ext_sync_w -
1566 //-------------------------------------------------
1567 
WRITE_LINE_MEMBER(upd7220_device::lpen_w)1568 WRITE_LINE_MEMBER( upd7220_device::lpen_w )
1569 {
1570 	/* only if 2 rising edges on the lpen input occur at the same
1571 	   point during successive video fields are the pulses accepted */
1572 
1573 	/*
1574 
1575 	    1. compute the address of the location on the CRT
1576 	    2. compare with LAD
1577 	    3. if not equal move address to LAD
1578 	    4. if equal set LPEN DETECT flag to 1
1579 
1580 	*/
1581 }
1582 
1583 
1584 //-------------------------------------------------
1585 //  update_text -
1586 //-------------------------------------------------
1587 
update_text(bitmap_rgb32 & bitmap,const rectangle & cliprect)1588 void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
1589 {
1590 	uint32_t addr, sad;
1591 	uint16_t len;
1592 	int im, wd;
1593 	int y, sy = 0;
1594 
1595 	for (int area = 0; area < 4; area++)
1596 	{
1597 		get_text_partition(area, &sad, &len, &im, &wd);
1598 
1599 		for (y = sy; y < sy + len; y++)
1600 		{
1601 			addr = sad + (y * m_pitch);
1602 
1603 			if (!m_draw_text_cb.isnull())
1604 				m_draw_text_cb(bitmap, addr, (y * m_lr) + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead);
1605 		}
1606 
1607 		sy = y + 1;
1608 	}
1609 }
1610 
1611 
1612 //-------------------------------------------------
1613 //  draw_graphics_line -
1614 //-------------------------------------------------
1615 
draw_graphics_line(bitmap_rgb32 & bitmap,uint32_t addr,int y,int wd,int pitch)1616 void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, uint32_t addr, int y, int wd, int pitch)
1617 {
1618 	int sx, al = bitmap.cliprect().height();
1619 
1620 	for (sx = 0; sx < pitch; sx++)
1621 	{
1622 		if((sx << 4) < m_aw * 16 && y < al)
1623 			m_display_cb(bitmap, y, sx << 4, addr);
1624 
1625 		addr+= (wd + 1) * 2;
1626 	}
1627 }
1628 
1629 
1630 //-------------------------------------------------
1631 //  update_graphics -
1632 //-------------------------------------------------
1633 
update_graphics(bitmap_rgb32 & bitmap,const rectangle & cliprect,int force_bitmap)1634 void upd7220_device::update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap)
1635 {
1636 	uint32_t addr, sad;
1637 	uint16_t len;
1638 	int im, wd, area;
1639 	int y = 0, tsy = 0, bsy = 0;
1640 	bool mixed = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED);
1641 	uint8_t interlace = ((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON) ? 0 : 1;
1642 
1643 	for (area = 0; area < 4; area++)
1644 	{
1645 		get_graphics_partition(area, &sad, &len, &im, &wd);
1646 
1647 		if (im || force_bitmap)
1648 		{
1649 			//get_graphics_partition(area, &sad, &len, &im, &wd);
1650 
1651 			if(area >= 3) // TODO: most likely to be correct, Quarth (PC-98xx) definitely draws with area 2. We might see an area 3 someday ...
1652 				break;
1653 
1654 			if(!interlace)
1655 				len <<= 1;
1656 
1657 			for (y = 0; y < len; y++)
1658 			{
1659 				/* TODO: again correct?
1660 				         Quarth (PC-98xx) doesn't seem to use pitch here and it definitely wants bsy to be /2 to make scrolling to work.
1661 				         Xevious (PC-98xx) wants the pitch to be fixed at 80, and wants bsy to be /1
1662 				         Dragon Buster (PC-98xx) contradicts with Xevious with regards of the pitch tho ... */
1663 				addr = ((sad << 1) & 0x3ffff) + ((y / (mixed ? 1 : m_lr)) * (m_pitch << (im ? 0 : 1)));
1664 
1665 				if (!m_display_cb.isnull())
1666 					draw_graphics_line(bitmap, addr, y + bsy + m_vbp, wd, (m_pitch << interlace));
1667 			}
1668 		}
1669 		else
1670 		{
1671 			get_text_partition(area, &sad, &len, &im, &wd);
1672 
1673 			if(m_lr)
1674 			{
1675 				for (y = 0; y < len; y+=m_lr)
1676 				{
1677 					addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch);
1678 
1679 					if (!m_draw_text_cb.isnull())
1680 						m_draw_text_cb(bitmap, addr, y + tsy + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead);
1681 				}
1682 			}
1683 		}
1684 
1685 		if (m_lr)
1686 			tsy += y;
1687 		bsy += y;
1688 	}
1689 }
1690 
1691 
1692 //-------------------------------------------------
1693 //  update_screen -
1694 //-------------------------------------------------
1695 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1696 uint32_t upd7220_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1697 {
1698 	if (m_de)
1699 	{
1700 		switch (m_mode & UPD7220_MODE_DISPLAY_MASK)
1701 		{
1702 		case UPD7220_MODE_DISPLAY_MIXED:
1703 			update_graphics(bitmap, cliprect, 0);
1704 			break;
1705 
1706 		case UPD7220_MODE_DISPLAY_GRAPHICS:
1707 			update_graphics(bitmap, cliprect, 1);
1708 			break;
1709 
1710 		case UPD7220_MODE_DISPLAY_CHARACTER:
1711 			update_text(bitmap, cliprect);
1712 			break;
1713 
1714 		case UPD7220_MODE_DISPLAY_INVALID:
1715 			LOG("uPD7220 Invalid Display Mode!\n");
1716 		}
1717 	}
1718 	return 0;
1719 }
1720