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