OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / v9938.cpp
1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles, Nathan Woods
3
4 /***************************************************************************
5
6 v9938 / v9958 emulation
7
8 Vertical display parameters from Yamaha V9938 Technical Data Book.
9 NTSC: page 146, Table 7-2
10 PAL: page 147, Table 7-3
11
12 Vertical timing:
13                                        PAL                 NTSC
14                                        192(LN=0) 212(LN=1) 192(LN=0) 212(LN=1)
15                                        ------------------- --------------------
16 1. Top erase (top blanking)                13        13        13        13
17 2. Top border                              53        43        26        16
18 3. Active display                         192       212       192       212
19 4. Bottom border                           49        39        25        15
20 5. Bottom erase (bottom blanking)           3         3         3         3
21 6. Vertical sync (bottom blanking)          3         3         3         3
22 7. Total                                  313       313       262       262
23
24    Refresh rate                           50.158974           59.922743
25
26
27 ***************************************************************************/
28
29 /*
30 todo:
31
32 - sprite collision
33 - vdp engine -- make run at correct speed
34 - vr/hr/fh flags: double-check all of that
35 - make vdp engine work in exp. ram
36 */
37
38 //#include "../emu.h"
39 #include "v9938.h"
40
41 #define m_vram_space this
42
43 #define VERBOSE 0
44 //#define LOG(x)  do { if (VERBOSE) logerror x; } while (0)
45 #define LOG(x)  void(x)
46
47 enum
48 {
49         V9938_MODE_TEXT1 = 0,
50         V9938_MODE_MULTI,
51         V9938_MODE_GRAPHIC1,
52         V9938_MODE_GRAPHIC2,
53         V9938_MODE_GRAPHIC3,
54         V9938_MODE_GRAPHIC4,
55         V9938_MODE_GRAPHIC5,
56         V9938_MODE_GRAPHIC6,
57         V9938_MODE_GRAPHIC7,
58         V9938_MODE_TEXT2,
59         V9938_MODE_UNKNOWN
60 };
61
62 #define MODEL_V9938 (0)
63 #define MODEL_V9958 (1)
64
65 #define EXPMEM_OFFSET 0x20000
66
67 // LONG_WIDTH has already defined limits.h for GCC.20180614 K.O
68 #define _V9938_LONG_WIDTH (512 + 32)
69
70 static const char *const v9938_modes[] = {
71         "TEXT 1", "MULTICOLOR", "GRAPHIC 1", "GRAPHIC 2", "GRAPHIC 3",
72         "GRAPHIC 4", "GRAPHIC 5", "GRAPHIC 6", "GRAPHIC 7", "TEXT 2",
73         "UNKNOWN"
74 };
75
76 //**************************************************************************
77 //  GLOBAL VARIABLES
78 //**************************************************************************
79
80 /*
81 Similar to the TMS9928, the V9938 has an own address space. It can handle
82 at most 192 KiB RAM (128 KiB base, 64 KiB expansion).
83 */
84 //static ADDRESS_MAP_START(memmap, AS_DATA, 8, v99x8_device)
85 //      ADDRESS_MAP_GLOBAL_MASK(0x3ffff)
86 //      AM_RANGE(0x00000, 0x2ffff) AM_RAM
87 //ADDRESS_MAP_END
88
89
90 // devices
91 //const device_type V9938 = &device_creator<v9938_device>;
92 //const device_type V9958 = &device_creator<v9958_device>;
93
94
95 //v99x8_device::v99x8_device(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, device_t *owner, UINT32 clock)
96 //:   device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
97 v99x8_device::v99x8_device(VM_TEMPLATE* parent_vm, EMU* parent_emu)
98 :   DEVICE(parent_vm, parent_emu),
99 //      device_memory_interface(mconfig, *this),
100 //      device_video_interface(mconfig, *this),
101 //      m_space_config("vram", ENDIANNESS_BIG, 8, 18),
102         m_model(0),
103         m_offset_x(0),
104         m_offset_y(0),
105         m_visible_y(0),
106         m_mode(0),
107         m_pal_write_first(0),
108         m_cmd_write_first(0),
109         m_pal_write(0),
110         m_cmd_write(0),
111         m_read_ahead(0),
112         m_v9958_sp_mode(0),
113         m_address_latch(0),
114         m_vram_size(/*0*/0x20000),
115         m_int_state(0),
116 //      m_int_callback(*this),
117         m_scanline(0),
118         m_blink(0),
119         m_blink_count(0),
120         m_mx_delta(0),
121         m_my_delta(0),
122         m_button_state(0),
123         m_vdp_ops_count(0),
124         m_vdp_engine(NULL),
125 //      m_palette(*this, "palette"),
126         m_pal_ntsc(0)
127 {
128 //      static_set_addrmap(*this, AS_DATA, ADDRESS_MAP_NAME(memmap));
129         initialize_output_signals(&outputs_irq);
130         set_device_name(_T("V99x8 VDP"));
131 }
132
133 //v9938_device::v9938_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
134 //: v99x8_device(mconfig, V9938, "V9938 VDP", "v9938", tag, owner, clock)
135 v9938_device::v9938_device(VM_TEMPLATE* parent_vm, EMU* parent_emu)
136 : v99x8_device(parent_vm, parent_emu)
137 {
138         m_model = MODEL_V9938;
139         init_palette();
140         set_device_name(_T("V9938 VDP"));
141 }
142
143 //v9958_device::v9958_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
144 //: v99x8_device(mconfig, V9938, "V9958 VDP", "v9958", tag, owner, clock)
145 v9958_device::v9958_device(VM_TEMPLATE* parent_vm, EMU* parent_emu)
146 : v99x8_device(parent_vm, parent_emu)
147 {
148         m_model = MODEL_V9958;
149         init_palette();
150         set_device_name(_T("V9958 VDP"));
151 }
152
153
154 //void v99x8_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
155 void v99x8_device::device_timer(int v)
156 {
157         int scanline = (m_scanline - (m_scanline_start + m_offset_y));
158
159         update_command ();
160
161         // set flags
162         if (m_scanline == (m_scanline_start + m_offset_y))
163         {
164                 m_stat_reg[2] &= ~0x40;
165         }
166         else if (m_scanline == (m_scanline_start + m_offset_y + m_visible_y))
167         {
168                 m_stat_reg[2] |= 0x40;
169                 m_stat_reg[0] |= 0x80;
170         }
171
172         if ( (scanline >= 0) && (scanline <= m_scanline_max) &&
173                 (((scanline + m_cont_reg[23]) & 255) == m_cont_reg[19]) )
174         {
175                 m_stat_reg[1] |= 1;
176                 LOG(("V9938: scanline interrupt (%d)\n", scanline));
177         }
178         else if (!(m_cont_reg[0] & 0x10))
179         {
180                 m_stat_reg[1] &= 0xfe;
181         }
182
183         check_int();
184
185         // check for start of vblank
186         if (m_scanline == m_vblank_start)
187         {
188                 interrupt_start_vblank();
189         }
190
191         // render the current line
192         if (m_scanline < m_vblank_start)
193         {
194                 refresh_line(scanline);
195         }
196
197         if (++m_scanline >= m_height)
198         {
199                 m_scanline = 0;
200                 // PAL/NTSC changed?
201                 /*int pal = m_cont_reg[9] & 2;
202                 if (m_pal_ntsc != pal)
203                 {
204                         m_pal_ntsc = pal;
205                         configure_pal_ntsc();
206                 }*/ /* umaiboux: NTSC only! */
207                 //m_screen->reset_origin();
208                 m_offset_y = position_offset(m_cont_reg[18] >> 4);
209                 set_screen_parameters();
210         }
211 }
212
213
214 void v99x8_device::set_screen_parameters()
215 {
216         if (m_pal_ntsc)
217         {
218                 // PAL
219                 m_scanline_start = (m_cont_reg[9] & 0x80) ? 43 : 53;
220                 m_scanline_max = 255;
221         }
222         else
223         {
224                 // NYSC
225                 m_scanline_start = (m_cont_reg[9] & 0x80) ? 16 : 26;
226                 m_scanline_max = (m_cont_reg[9] & 0x80) ? 234 : 244;
227         }
228         m_visible_y = (m_cont_reg[9] & 0x80) ? 212 : 192;
229 }
230
231
232 void v99x8_device::configure_pal_ntsc()
233 {
234         if (m_pal_ntsc)
235         {
236                 // PAL
237                 m_height = VTOTAL_PAL;
238 //              rectangle visible;
239 //              visible.set(0, HVISIBLE - 1, VERTICAL_ADJUST * 2, VVISIBLE_PAL * 2 - 1 - VERTICAL_ADJUST * 2);
240 //              m_screen->configure(HTOTAL, VTOTAL_PAL * 2, visible, HZ_TO_ATTOSECONDS(50.158974));
241         }
242         else
243         {
244                 // NTSC
245                 m_height = VTOTAL_NTSC;
246 //              rectangle visible;
247 //              visible.set(0, HVISIBLE - 1, VERTICAL_ADJUST * 2, VVISIBLE_NTSC * 2 - 1 - VERTICAL_ADJUST * 2);
248 //              m_screen->configure(HTOTAL, VTOTAL_NTSC * 2, visible, HZ_TO_ATTOSECONDS(59.922743));
249         }
250         m_vblank_start = m_height - VERTICAL_SYNC - TOP_ERASE; /* Sync + top erase */
251 }
252
253
254 /*
255     Not really right... won't work with sprites in graphics 7
256     and with palette updated mid-screen
257 */
258 int v99x8_device::get_transpen()
259 {
260         if (m_mode == V9938_MODE_GRAPHIC7)
261         {
262                 return m_pal_ind256[0];
263         }
264         else
265         {
266                 return m_pal_ind16[0];
267         }
268 }
269
270 /*
271     Driver-specific function: update the vdp mouse state
272 */
273 /*void v99x8_device::update_mouse_state(int mx_delta, int my_delta, int button_state)
274 {
275         // save button state
276         m_button_state = (button_state << 6) & 0xc0;
277
278         if ((m_cont_reg[8] & 0xc0) == 0x80)
279         {   // vdp will process mouse deltas only if it is in mouse mode
280                 m_mx_delta += mx_delta;
281                 m_my_delta += my_delta;
282         }
283 }*/
284
285
286
287 /***************************************************************************
288
289 Palette functions
290
291 ***************************************************************************/
292
293 /*
294 About the colour burst registers:
295
296 The color burst registers will only have effect on the composite video output from
297 the V9938. but the output is only NTSC (Never The Same Color ,so the
298 effects are already present) . this system is not used in europe
299 the european machines use a separate PAL  (Phase Alternating Line) encoder
300 or no encoder at all , only RGB output.
301
302 Erik de Boer.
303
304 --
305 Right now they're not emulated. For completeness sake they should -- with
306 a dip-switch to turn them off. I really don't know how they work though. :(
307 */
308
309 /*
310 In screen 8, the colors are encoded as:
311
312 7  6  5  4  3  2  1  0
313 +--+--+--+--+--+--+--+--+
314 |g2|g1|g0|r2|r1|r0|b2|b1|
315 +--+--+--+--+--+--+--+--+
316
317 b0 is set if b2 and b1 are set (remember, color bus is 3 bits)
318
319 */
320
321 /*PALETTE_INIT_MEMBER(v9938_device, v9938)*/
322 void v9938_device::init_palette()
323 {
324         int i;
325
326         // create the full 512 colour palette
327         for (i=0;i<512;i++)
328 //              palette.set_pen_color(i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0));
329                 this->set_pen_color(i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0));
330 }
331
332 /*
333
334 The v9958 can display up to 19286 colours. For this we need a larger palette.
335
336 The colours are encoded in 17 bits; however there are just 19268 different colours.
337 Here we calculate the palette and a 2^17 reference table to the palette,
338 which is: s_pal_indYJK. It's 256K in size, but I can't think of a faster way
339 to emulate this. Also it keeps the palette a reasonable size. :)
340
341 */
342
343 UINT16 v99x8_device::s_pal_indYJK[0x20000];
344
345 /*PALETTE_INIT_MEMBER(v9958_device, v9958)*/
346 void v9958_device::init_palette()
347 {
348         int r,g,b,y,j,k,i,k0,j0,n;
349         UINT8 pal[19268*3];
350
351         // init v9938 512-color palette
352         for (i=0;i<512;i++)
353 //              palette.set_pen_color(i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0));
354                 this->set_pen_color(i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0));
355
356
357 //      if(palette.entries() != 19780)
358 //              fatalerror("V9958: not enough palette, must be 19780");
359
360         // set up YJK table
361         LOG(("Building YJK table for V9958 screens, may take a while ... \n"));
362         i = 0;
363         for (y=0;y<32;y++) for (k=0;k<64;k++) for (j=0;j<64;j++)
364         {
365                 // calculate the color
366                 if (k >= 32) k0 = (k - 64); else k0 = k;
367                 if (j >= 32) j0 = (j - 64); else j0 = j;
368                 r = y + j0;
369                 b = (y * 5 - 2 * j0 - k0) / 4;
370                 g = y + k0;
371                 if (r < 0) r = 0; else if (r > 31) r = 31;
372                 if (g < 0) g = 0; else if (g > 31) g = 31;
373                 if (b < 0) b = 0; else if (b > 31) b = 31;
374
375                 //r = (r << 3) | (r >> 2);
376                 //b = (b << 3) | (b >> 2);
377                 //g = (g << 3) | (g >> 2);
378                 // have we seen this one before?
379                 n = 0;
380                 while (n < i)
381                 {
382                         if (pal[n*3+0] == r && pal[n*3+1] == g && pal[n*3+2] == b)
383                         {
384                                 v99x8_device::s_pal_indYJK[y | j << 5 | k << (5 + 6)] = n + 512;
385                                 break;
386                         }
387                         n++;
388                 }
389
390                 if (i == n)
391                 {
392                         // so we haven't; add it
393                         pal[i*3+0] = r;
394                         pal[i*3+1] = g;
395                         pal[i*3+2] = b;
396 //                      palette.set_pen_color(i+512, rgb_t(pal5bit(r), pal5bit(g), pal5bit(b)));
397                         this->set_pen_color(i+512, pal5bit(r), pal5bit(g), pal5bit(b));
398                         v99x8_device::s_pal_indYJK[y | j << 5 | k << (5 + 6)] = i + 512;
399                         i++;
400                 }
401         }
402
403         if (i != 19268)
404                 LOG( ("Table creation failed - %d colours out of 19286 created\n", i));
405 }
406
407 /*UINT32 v99x8_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
408 {
409         copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
410         return 0;
411 }*/
412
413 /*READ8_MEMBER( v99x8_device::read )*/
414 uint32_t v99x8_device::read_io8(uint32_t offset)
415 {
416         switch (offset & 3)
417         {
418         case 0: return vram_r();
419         case 1: return status_r();
420         }
421         return 0xff;
422 }
423
424 /*WRITE8_MEMBER( v99x8_device::write )*/
425 void v99x8_device::write_io8(uint32_t offset, uint32_t data)
426 {
427         switch (offset & 3)
428         {
429         case 0: vram_w(data);       break;
430         case 1: command_w(data);    break;
431         case 2: palette_w(data);    break;
432         case 3: register_w(data);   break;
433         }
434 }
435
436 UINT8 v99x8_device::vram_r()
437 {
438         UINT8 ret;
439         int address;
440
441         address = ((int)m_cont_reg[14] << 14) | m_address_latch;
442
443         m_cmd_write_first = 0;
444
445         ret = m_read_ahead;
446
447         if (m_cont_reg[45] & 0x40)  // Expansion memory
448         {
449                 if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) )
450                         address >>= 1;  // correct?
451                 // Expansion memory only offers 64 K
452                 if (m_vram_size > 0x20000 && ((address & 0x10000)==0))
453                         m_read_ahead = m_vram_space->read_byte(address + EXPMEM_OFFSET);
454                 else
455                         m_read_ahead = 0xff;
456         }
457         else
458         {
459                 m_read_ahead = vram_read(address);
460         }
461
462         m_address_latch = (m_address_latch + 1) & 0x3fff;
463         if ((!m_address_latch) && (m_cont_reg[0] & 0x0c) ) // correct ???
464         {
465                 m_cont_reg[14] = (m_cont_reg[14] + 1) & 7;
466         }
467
468         return ret;
469 }
470
471 UINT8 v99x8_device::status_r()
472 {
473         int reg;
474         UINT8 ret;
475
476         m_cmd_write_first = 0;
477
478         reg = m_cont_reg[15] & 0x0f;
479         if (reg > 9)
480                 return 0xff;
481
482         switch (reg)
483         {
484         case 0:
485                 ret = m_stat_reg[0];
486                 m_stat_reg[0] &= 0x1f;
487                 break;
488         case 1:
489                 ret = m_stat_reg[1];
490                 m_stat_reg[1] &= 0xfe;
491                 if ((m_cont_reg[8] & 0xc0) == 0x80)
492                         // mouse mode: add button state
493                 ret |= m_button_state & 0xc0;
494                 break;
495         case 2:
496                 /*update_command ();*/
497                 /*
498                 WTF is this? Whatever this was intended to do, it is nonsensical.
499                 Might as well pick a random number....
500                 This was an attempt to emulate H-Blank flag ;)
501                 n = cycles_currently_ran ();
502                 if ( (n < 28) || (n > 199) ) vdp.statReg[2] |= 0x20;
503                 else vdp.statReg[2] &= ~0x20;
504                 */
505 //              if (machine().rand() & 1) m_stat_reg[2] |= 0x20;
506 //              else m_stat_reg[2] &= ~0x20;
507                 ret = m_stat_reg[2];
508                 break;
509         case 3:
510                 if ((m_cont_reg[8] & 0xc0) == 0x80)
511                 {   // mouse mode: return x mouse delta
512                         ret = m_mx_delta;
513                         m_mx_delta = 0;
514                 }
515                 else
516                         ret = m_stat_reg[3];
517                 break;
518         case 5:
519                 if ((m_cont_reg[8] & 0xc0) == 0x80)
520                 {   // mouse mode: return y mouse delta
521                         ret = m_my_delta;
522                         m_my_delta = 0;
523                 }
524                 else
525                         ret = m_stat_reg[5];
526                 break;
527         case 7:
528                 ret = m_stat_reg[7];
529                 m_stat_reg[7] = m_cont_reg[44] = vdp_to_cpu () ;
530                 break;
531         default:
532                 ret = m_stat_reg[reg];
533                 break;
534         }
535
536         LOG(("V9938: Read %02x from S#%d\n", ret, reg));
537         check_int ();
538
539         return ret;
540 }
541
542 void v99x8_device::palette_w(UINT8 data)
543 {
544         int indexp;
545
546         if (m_pal_write_first)
547         {
548                 // store in register
549                 indexp = m_cont_reg[0x10] & 15;
550                 m_pal_reg[indexp*2] = m_pal_write & 0x77;
551                 m_pal_reg[indexp*2+1] = data & 0x07;
552                 // update palette
553                 m_pal_ind16[indexp] = (((int)m_pal_write << 2) & 0x01c0)  |
554                 (((int)data << 3) & 0x0038)  |
555                 ((int)m_pal_write & 0x0007);
556
557                 m_cont_reg[0x10] = (m_cont_reg[0x10] + 1) & 15;
558                 m_pal_write_first = 0;
559         }
560         else
561         {
562                 m_pal_write = data;
563                 m_pal_write_first = 1;
564         }
565 }
566
567 void v99x8_device::vram_w(UINT8 data)
568 {
569         int address;
570
571         /*update_command ();*/
572
573         m_cmd_write_first = 0;
574
575         address = ((int)m_cont_reg[14] << 14) | m_address_latch;
576
577         if (m_cont_reg[45] & 0x40)
578         {
579                 if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) )
580                         address >>= 1;  // correct?
581                 if (m_vram_size > 0x20000 && ((address & 0x10000)==0))
582                         m_vram_space->write_byte(EXPMEM_OFFSET + address, data);
583         }
584         else
585         {
586                 vram_write(address, data);
587         }
588
589         m_address_latch = (m_address_latch + 1) & 0x3fff;
590         if ((!m_address_latch) && (m_cont_reg[0] & 0x0c) ) // correct ???
591         {
592                 m_cont_reg[14] = (m_cont_reg[14] + 1) & 7;
593         }
594 }
595
596 void v99x8_device::command_w(UINT8 data)
597 {
598         if (m_cmd_write_first)
599         {
600                 if (data & 0x80)
601                 {
602                         if (!(data & 0x40))
603                                 register_write (data & 0x3f, m_cmd_write);
604                 }
605                 else
606                 {
607                         m_address_latch =
608                         (((UINT16)data << 8) | m_cmd_write) & 0x3fff;
609                         if ( !(data & 0x40) ) vram_r (); // read ahead!
610                 }
611
612                 m_cmd_write_first = 0;
613         }
614         else
615         {
616                 m_cmd_write = data;
617                 m_cmd_write_first = 1;
618         }
619 }
620
621 void v99x8_device::register_w(UINT8 data)
622 {
623         int reg;
624
625         reg = m_cont_reg[17] & 0x3f;
626         if (reg != 17)
627                 register_write(reg, data); // true ?
628
629         if (!(m_cont_reg[17] & 0x80))
630                 m_cont_reg[17] = (m_cont_reg[17] + 1) & 0x3f;
631 }
632
633 /*void v99x8_device::static_set_vram_size(device_t &device, UINT32 vram_size)
634 {
635         downcast<v99x8_device &>(device).m_vram_size = vram_size;
636 }*/
637
638 /***************************************************************************
639
640     Init/stop/reset/Interrupt functions
641
642 ***************************************************************************/
643
644 void v99x8_device::device_start()
645 {
646 //      m_int_callback.resolve_safe();
647         m_vdp_ops_count = 1;
648         m_vdp_engine = NULL;
649
650 //      m_screen->register_screen_bitmap(m_bitmap);
651
652         // Video RAM is allocated as an own address space
653 //      m_vram_space = &space(AS_DATA);
654
655         // allocate VRAM
656         assert(m_vram_size > 0);
657
658         if (m_vram_size < 0x20000)
659         {
660                 // set unavailable RAM to 0xff
661                 for (int addr = m_vram_size; addr < 0x30000; addr++) m_vram_space->write_byte(addr, 0xff);
662         }
663
664 //      m_line_timer = timer_alloc(TIMER_LINE);
665
666 /*      save_item(NAME(m_offset_x));
667         save_item(NAME(m_offset_y));
668         save_item(NAME(m_visible_y));
669         save_item(NAME(m_mode));
670         save_item(NAME(m_pal_write_first));
671         save_item(NAME(m_cmd_write_first));
672         save_item(NAME(m_pal_write));
673         save_item(NAME(m_cmd_write));
674         save_item(NAME(m_pal_reg));
675         save_item(NAME(m_stat_reg));
676         save_item(NAME(m_cont_reg));
677         save_item(NAME(m_read_ahead));
678         //  save_item(NAME(m_vram));
679         //  if ( m_vram_exp != NULL )
680         //      save_pointer(NAME(m_vram_exp), 0x10000);
681         save_item(NAME(m_int_state));
682         save_item(NAME(m_scanline));
683         save_item(NAME(m_blink));
684         save_item(NAME(m_blink_count));
685         save_item(NAME(m_mx_delta));
686         save_item(NAME(m_my_delta));
687         save_item(NAME(m_button_state));
688         save_item(NAME(m_pal_ind16));
689         save_item(NAME(m_pal_ind256));
690         save_item(NAME(m_mmc.SX));
691         save_item(NAME(m_mmc.SY));
692         save_item(NAME(m_mmc.DX));
693         save_item(NAME(m_mmc.DY));
694         save_item(NAME(m_mmc.TX));
695         save_item(NAME(m_mmc.TY));
696         save_item(NAME(m_mmc.NX));
697         save_item(NAME(m_mmc.NY));
698         save_item(NAME(m_mmc.MX));
699         save_item(NAME(m_mmc.ASX));
700         save_item(NAME(m_mmc.ADX));
701         save_item(NAME(m_mmc.ANX));
702         save_item(NAME(m_mmc.CL));
703         save_item(NAME(m_mmc.LO));
704         save_item(NAME(m_mmc.CM));
705         save_item(NAME(m_mmc.MXS));
706         save_item(NAME(m_mmc.MXD));
707         save_item(NAME(m_vdp_ops_count));
708         save_item(NAME(m_pal_ntsc));
709         save_item(NAME(m_scanline_start));
710         save_item(NAME(m_vblank_start));
711         save_item(NAME(m_scanline_max));
712         save_item(NAME(m_height));*/
713 }
714
715 void v99x8_device::device_reset()
716 {
717         int i;
718
719         // offset reset
720         m_offset_x = 8;
721         m_offset_y = 0;
722         m_visible_y = 192;
723         // register reset
724         reset_palette (); // palette registers
725         for (i=0;i<10;i++) m_stat_reg[i] = 0;
726         m_stat_reg[2] = 0x0c;
727         if (m_model == MODEL_V9958) m_stat_reg[1] |= 4;
728         for (i=0;i<48;i++) m_cont_reg[i] = 0;
729         m_cmd_write_first = m_pal_write_first = 0;
730         m_int_state = 0;
731         m_read_ahead = 0; m_address_latch = 0; // ???
732         m_scanline = 0;
733         // MZ: The status registers 4 and 6 hold the high bits of the sprite
734         // collision location. The unused bits are set to 1.
735         // SR3: x x x x x x x x
736         // SR4: 1 1 1 1 1 1 1 x
737         // SR5: y y y y y y y y
738         // SR6: 1 1 1 1 1 1 y y
739         // Note that status register 4 is used in detection algorithms to tell
740         // apart the tms9929 from the v99x8.
741
742         // TODO: SR3-S6 do not yet store the information about the sprite collision
743         m_stat_reg[4] = 0xfe;
744         m_stat_reg[6] = 0xfc;
745
746         // Start the timer
747 //      m_line_timer->adjust(attotime::from_ticks(HTOTAL*2, m_clock), 0, attotime::from_ticks(HTOTAL*2, m_clock));
748
749         configure_pal_ntsc();
750         set_screen_parameters();
751 }
752
753
754 void v99x8_device::reset_palette()
755 {
756         // taken from V9938 Technical Data book, page 148. it's in G-R-B format
757         static const UINT8 pal16[16*3] = {
758                 0, 0, 0, // 0: black/transparent
759                 0, 0, 0, // 1: black
760                 6, 1, 1, // 2: medium green
761                 7, 3, 3, // 3: light green
762                 1, 1, 7, // 4: dark blue
763                 3, 2, 7, // 5: light blue
764                 1, 5, 1, // 6: dark red
765                 6, 2, 7, // 7: cyan
766                 1, 7, 1, // 8: medium red
767                 3, 7, 3, // 9: light red
768                 6, 6, 1, // 10: dark yellow
769                 6, 6, 4, // 11: light yellow
770                 4, 1, 1, // 12: dark green
771                 2, 6, 5, // 13: magenta
772                 5, 5, 5, // 14: gray
773                 7, 7, 7  // 15: white
774         };
775         int i, red, ind;
776
777         for (i=0;i<16;i++)
778         {
779                 // set the palette registers
780                 m_pal_reg[i*2+0] = pal16[i*3+1] << 4 | pal16[i*3+2];
781                 m_pal_reg[i*2+1] = pal16[i*3];
782                 // set the reference table
783                 m_pal_ind16[i] = pal16[i*3+1] << 6 | pal16[i*3] << 3 | pal16[i*3+2];
784         }
785
786         // set internal palette GRAPHIC 7
787         for (i=0;i<256;i++)
788         {
789                 ind = (i << 4) & 0x01c0;
790                 ind |= (i >> 2) & 0x0038;
791                 red = (i << 1) & 6; if (red == 6) red++;
792                 ind |= red;
793
794                 m_pal_ind256[i] = ind;
795         }
796 }
797
798 /***************************************************************************
799
800 Memory functions
801
802 ***************************************************************************/
803
804 void v99x8_device::vram_write(int offset, int data)
805 {
806         int newoffset;
807
808         if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) )
809         {
810                 newoffset = ((offset & 1) << 16) | (offset >> 1);
811                 if (newoffset < m_vram_size)
812                         m_vram_space->write_byte(newoffset, data);
813         }
814         else
815         {
816                 if (offset < m_vram_size)
817                         m_vram_space->write_byte(offset, data);
818         }
819 }
820
821 int v99x8_device::vram_read(int offset)
822 {
823         if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) )
824                 return m_vram_space->read_byte(((offset & 1) << 16) | (offset >> 1));
825         else
826                 return m_vram_space->read_byte(offset);
827 }
828
829 void v99x8_device::check_int()
830 {
831         UINT8 n;
832
833         n = ( (m_cont_reg[1] & 0x20) && (m_stat_reg[0] & 0x80) /*&& m_vblank_int*/) ||
834         ( (m_stat_reg[1] & 0x01) && (m_cont_reg[0] & 0x10) );
835
836         #if 0
837         if(n && m_vblank_int)
838         {
839                 m_vblank_int = 0;
840         }
841         #endif
842
843         if (n != m_int_state)
844         {
845                 m_int_state = n;
846                 LOG(("V9938: IRQ line %s\n", n ? "up" : "down"));
847         }
848
849         /*
850         ** Somehow the IRQ request is going down without cpu_irq_line () being
851         ** called; because of this Mr. Ghost, Xevious and SD Snatcher don't
852         ** run. As a patch it's called every scanline
853         */
854         if(!emu->now_waiting_in_debugger) {
855 //              m_int_callback(n);
856                 write_signals(&outputs_irq, n ? 0xffffffff : 0);
857         }
858 }
859
860 /***************************************************************************
861
862     Register functions
863
864 ***************************************************************************/
865
866 void v99x8_device::register_write (int reg, int data)
867 {
868         static UINT8 const reg_mask[] =
869         {
870                 0x7e, 0x7b, 0x7f, 0xff, 0x3f, 0xff, 0x3f, 0xff,
871                 0xfb, 0xbf, 0x07, 0x03, 0xff, 0xff, 0x07, 0x0f,
872                 0x0f, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
873                 0x00, 0x7f, 0x3f, 0x07
874         };
875
876         if (reg <= 27)
877         {
878                 data &= reg_mask[reg];
879                 if (m_cont_reg[reg] == data)
880                         return;
881         }
882
883         if (reg > 46)
884         {
885                 LOG(("V9938: Attempted to write to non-existant R#%d\n", reg));
886                 return;
887         }
888
889         /*update_command ();*/
890
891         switch (reg) {
892                 // registers that affect interrupt and display mode
893         case 0:
894         case 1:
895                 m_cont_reg[reg] = data;
896                 set_mode();
897                 check_int();
898                 LOG(("v9938: mode = %s\n", v9938_modes[m_mode]));
899                 break;
900
901         case 18:
902         case 9:
903                 m_cont_reg[reg] = data;
904                 // recalc offset
905                 m_offset_x = 8 + position_offset(m_cont_reg[18] & 0x0f);
906                 // Y offset is only applied once per frame?
907                 break;
908
909         case 15:
910                 m_pal_write_first = 0;
911                 break;
912
913                 // color burst registers aren't emulated
914         case 20:
915         case 21:
916         case 22:
917                 LOG(("v9938: Write %02xh to R#%d; color burst not emulated\n", data, reg));
918                 break;
919         case 25:
920         case 26:
921         case 27:
922                 if (m_model != MODEL_V9958)
923                 {
924                         LOG(("v9938: Attempting to write %02xh to V9958 R#%d\n", data, reg));
925                         data = 0;
926                 }
927                 else
928                 {
929                         if(reg == 25)
930                                 m_v9958_sp_mode = data & 0x18;
931                 }
932                 break;
933
934         case 44:
935                 cpu_to_vdp (data);
936                 break;
937
938         case 46:
939                 command_unit_w (data);
940                 break;
941         }
942
943         if (reg != 15)
944                 LOG(("v9938: Write %02x to R#%d\n", data, reg));
945
946         m_cont_reg[reg] = data;
947 }
948
949 /***************************************************************************
950
951 Refresh / render function
952
953 ***************************************************************************/
954
955 inline bool v99x8_device::v9938_second_field()
956 {
957         return !(((m_cont_reg[9] & 0x04) && !(m_stat_reg[2] & 2)) || m_blink);
958 }
959
960
961 void v99x8_device::default_border(const scrntype_t *pens, scrntype_t *ln)
962 {
963         scrntype_t pen;
964         int i;
965
966         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
967         i = _V9938_LONG_WIDTH;
968         while (i--) *ln++ = pen;
969 }
970
971 void v99x8_device::graphic7_border(const scrntype_t *pens, scrntype_t *ln)
972 {
973         scrntype_t pen;
974         int i;
975
976         pen = pens[m_pal_ind256[m_cont_reg[7]]];
977         i = _V9938_LONG_WIDTH;
978         while (i--) *ln++ = pen;
979 }
980
981 void v99x8_device::graphic5_border(const scrntype_t *pens, scrntype_t *ln)
982 {
983         int i;
984         scrntype_t pen0;
985         scrntype_t pen1;
986
987         pen1 = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
988         pen0 = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
989         i = _V9938_LONG_WIDTH / 2;
990         while (i--) { *ln++ = pen0; *ln++ = pen1; }
991 }
992
993 void v99x8_device::mode_text1(const scrntype_t *pens, scrntype_t *ln, int line)
994 {
995         int pattern, x, xx, name, xxx;
996         scrntype_t fg, bg, pen;
997         int nametbl_addr, patterntbl_addr;
998
999         patterntbl_addr = m_cont_reg[4] << 11;
1000         nametbl_addr = m_cont_reg[2] << 10;
1001
1002         fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1003         bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1004
1005         name = (line/8)*40;
1006
1007         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1008
1009         xxx = (m_offset_x + 8) * 2;
1010         while (xxx--) *ln++ = pen;
1011
1012         for (x=0;x<40;x++)
1013         {
1014                 pattern = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) +
1015                         ((line + m_cont_reg[23]) & 7));
1016                 for (xx=0;xx<6;xx++)
1017                 {
1018                         *ln++ = (pattern & 0x80) ? fg : bg;
1019                         *ln++ = (pattern & 0x80) ? fg : bg;
1020                         pattern <<= 1;
1021                 }
1022                 /* width height 212, characters start repeating at the bottom */
1023                 name = (name + 1) & 0x3ff;
1024         }
1025
1026         xxx = ((16 - m_offset_x) + 8) * 2;
1027         while (xxx--) *ln++ = pen;
1028 }
1029
1030 void v99x8_device::mode_text2(const scrntype_t *pens, scrntype_t *ln, int line)
1031 {
1032         int pattern, x, charcode, name, xxx, patternmask, colourmask;
1033         scrntype_t fg, bg, fg0, bg0, pen;
1034         int nametbl_addr, patterntbl_addr, colourtbl_addr;
1035
1036         patterntbl_addr = m_cont_reg[4] << 11;
1037         colourtbl_addr =  ((m_cont_reg[3] & 0xf8) << 6) + (m_cont_reg[10] << 14);
1038         #if 0
1039         colourmask = ((m_cont_reg[3] & 7) << 5) | 0x1f; /* cause a bug in Forth+ v1.0 on Geneve */
1040         #else
1041         colourmask = ((m_cont_reg[3] & 7) << 6) | 0x3f; /* verify! */
1042         #endif
1043         nametbl_addr = ((m_cont_reg[2] & 0xfc) << 10);
1044         patternmask = ((m_cont_reg[2] & 3) << 10) | 0x3ff; /* seems correct */
1045
1046         fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1047         bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1048         fg0 = pens[m_pal_ind16[m_cont_reg[12] >> 4]];
1049         bg0 = pens[m_pal_ind16[m_cont_reg[12] & 15]];
1050
1051         name = (line/8)*80;
1052
1053         xxx = (m_offset_x + 8) * 2;
1054         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1055         while (xxx--) *ln++ = pen;
1056
1057         for (x=0;x<80;x++)
1058         {
1059                 charcode = m_vram_space->read_byte(nametbl_addr + (name&patternmask));
1060                 if (m_blink)
1061                 {
1062                         pattern = m_vram_space->read_byte(colourtbl_addr + ((name/8)&colourmask));
1063                         if (pattern & (0x80 >> (name & 7) ) )
1064                         {
1065                                 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) +
1066                                         ((line + m_cont_reg[23]) & 7)));
1067
1068                                 *ln++ = (pattern & 0x80) ? fg0 : bg0;
1069                                 *ln++ = (pattern & 0x40) ? fg0 : bg0;
1070                                 *ln++ = (pattern & 0x20) ? fg0 : bg0;
1071                                 *ln++ = (pattern & 0x10) ? fg0 : bg0;
1072                                 *ln++ = (pattern & 0x08) ? fg0 : bg0;
1073                                 *ln++ = (pattern & 0x04) ? fg0 : bg0;
1074
1075                                 name++;
1076                                 continue;
1077                         }
1078                 }
1079
1080                 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) +
1081                         ((line + m_cont_reg[23]) & 7)));
1082
1083                 *ln++ = (pattern & 0x80) ? fg : bg;
1084                 *ln++ = (pattern & 0x40) ? fg : bg;
1085                 *ln++ = (pattern & 0x20) ? fg : bg;
1086                 *ln++ = (pattern & 0x10) ? fg : bg;
1087                 *ln++ = (pattern & 0x08) ? fg : bg;
1088                 *ln++ = (pattern & 0x04) ? fg : bg;
1089
1090                 name++;
1091         }
1092
1093         xxx = (16 - m_offset_x + 8) * 2;
1094         while (xxx--) *ln++ = pen;
1095 }
1096
1097 void v99x8_device::mode_multi(const scrntype_t *pens, scrntype_t *ln, int line)
1098 {
1099         int nametbl_addr, patterntbl_addr, colour;
1100         int name, line2, x, xx;
1101         scrntype_t pen, pen_bg;
1102
1103         nametbl_addr = (m_cont_reg[2] << 10);
1104         patterntbl_addr = (m_cont_reg[4] << 11);
1105
1106         line2 = (line - m_cont_reg[23]) & 255;
1107         name = (line2/8)*32;
1108
1109         pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1110         xx = m_offset_x * 2;
1111         while (xx--) *ln++ = pen_bg;
1112
1113         for (x=0;x<32;x++)
1114         {
1115                 colour = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) + ((line2/4)&7));
1116                 pen = pens[m_pal_ind16[colour>>4]];
1117                 /* eight pixels */
1118                 *ln++ = pen;
1119                 *ln++ = pen;
1120                 *ln++ = pen;
1121                 *ln++ = pen;
1122                 *ln++ = pen;
1123                 *ln++ = pen;
1124                 *ln++ = pen;
1125                 *ln++ = pen;
1126                 pen = pens[m_pal_ind16[colour&15]];
1127                 /* eight pixels */
1128                 *ln++ = pen;
1129                 *ln++ = pen;
1130                 *ln++ = pen;
1131                 *ln++ = pen;
1132                 *ln++ = pen;
1133                 *ln++ = pen;
1134                 *ln++ = pen;
1135                 *ln++ = pen;
1136                 name++;
1137         }
1138
1139         xx = (16 - m_offset_x) * 2;
1140         while (xx--) *ln++ = pen_bg;
1141 }
1142
1143 void v99x8_device::mode_graphic1(const scrntype_t *pens, scrntype_t *ln, int line)
1144 {
1145         scrntype_t fg, bg, pen;
1146         int nametbl_addr, patterntbl_addr, colourtbl_addr;
1147         int pattern, x, xx, line2, name, charcode, colour, xxx;
1148
1149         nametbl_addr = (m_cont_reg[2] << 10);
1150         colourtbl_addr = (m_cont_reg[3] << 6) + (m_cont_reg[10] << 14);
1151         patterntbl_addr = (m_cont_reg[4] << 11);
1152
1153         line2 = (line - m_cont_reg[23]) & 255;
1154
1155         name = (line2/8)*32;
1156
1157         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1158         xxx = m_offset_x * 2;
1159         while (xxx--) *ln++ = pen;
1160
1161         for (x=0;x<32;x++)
1162         {
1163                 charcode = m_vram_space->read_byte(nametbl_addr + name);
1164                 colour = m_vram_space->read_byte(colourtbl_addr + charcode/8);
1165                 fg = pens[m_pal_ind16[colour>>4]];
1166                 bg = pens[m_pal_ind16[colour&15]];
1167                 pattern = m_vram_space->read_byte(patterntbl_addr + (charcode * 8 + (line2 & 7)));
1168
1169                 for (xx=0;xx<8;xx++)
1170                 {
1171                         *ln++ = (pattern & 0x80) ? fg : bg;
1172                         *ln++ = (pattern & 0x80) ? fg : bg;
1173                         pattern <<= 1;
1174                 }
1175                 name++;
1176         }
1177
1178         xx = (16 - m_offset_x) * 2;
1179         while (xx--) *ln++ = pen;
1180 }
1181
1182 void v99x8_device::mode_graphic23(const scrntype_t *pens, scrntype_t *ln, int line)
1183 {
1184         scrntype_t fg, bg, pen;
1185         int nametbl_addr, patterntbl_addr, colourtbl_addr;
1186         int pattern, x, xx, line2, name, charcode,
1187         colour, colourmask, patternmask, xxx;
1188
1189         colourmask = ((m_cont_reg[3] & 0x7f) * 8) | 7;
1190         patternmask = ((m_cont_reg[4] & 0x03) * 256) | 0xff;
1191
1192         nametbl_addr =  (m_cont_reg[2] << 10);
1193         colourtbl_addr =  ((m_cont_reg[3] & 0x80) << 6) + (m_cont_reg[10] << 14);
1194         patterntbl_addr = ((m_cont_reg[4] & 0x3c) << 11);
1195
1196         line2 = (line + m_cont_reg[23]) & 255;
1197         name = (line2/8)*32;
1198
1199         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1200         xxx = m_offset_x * 2;
1201         while (xxx--) *ln++ = pen;
1202
1203         for (x=0;x<32;x++)
1204         {
1205                 charcode = m_vram_space->read_byte(nametbl_addr + name) + (line2&0xc0)*4;
1206                 colour = m_vram_space->read_byte(colourtbl_addr + ((charcode&colourmask)*8+(line2&7)));
1207                 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode&patternmask)*8+(line2&7)));
1208                 fg = pens[m_pal_ind16[colour>>4]];
1209                 bg = pens[m_pal_ind16[colour&15]];
1210                 for (xx=0;xx<8;xx++)
1211                 {
1212                         *ln++ = (pattern & 0x80) ? fg : bg;
1213                         *ln++ = (pattern & 0x80) ? fg : bg;
1214                         pattern <<= 1;
1215                 }
1216                 name++;
1217         }
1218
1219         xx = (16 - m_offset_x) * 2;
1220         while (xx--) *ln++ = pen;
1221 }
1222
1223 void v99x8_device::mode_graphic4(const scrntype_t *pens, scrntype_t *ln, int line)
1224 {
1225         int nametbl_addr, colour;
1226         int line2, linemask, x, xx;
1227         scrntype_t pen, pen_bg;
1228
1229         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1230
1231         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1232
1233         nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128;
1234         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1235                 nametbl_addr += 0x8000;
1236
1237         pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1238         xx = m_offset_x * 2;
1239         while (xx--) *ln++ = pen_bg;
1240
1241         for (x=0;x<128;x++)
1242         {
1243                 colour = m_vram_space->read_byte(nametbl_addr++);
1244                 pen = pens[m_pal_ind16[colour>>4]];
1245                 *ln++ = pen;
1246                 *ln++ = pen;
1247                 pen = pens[m_pal_ind16[colour&15]];
1248                 *ln++ = pen;
1249                 *ln++ = pen;
1250         }
1251
1252         xx = (16 - m_offset_x) * 2;
1253         while (xx--) *ln++ = pen_bg;
1254 }
1255
1256 void v99x8_device::mode_graphic5(const scrntype_t *pens, scrntype_t *ln, int line)
1257 {
1258         int nametbl_addr, colour;
1259         int line2, linemask, x, xx;
1260         scrntype_t pen_bg0[4];
1261         scrntype_t pen_bg1[4];
1262
1263         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1264
1265         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1266
1267         nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128;
1268         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1269                 nametbl_addr += 0x8000;
1270
1271         pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
1272         pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
1273
1274         xx = m_offset_x;
1275         while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
1276
1277         x = (m_cont_reg[8] & 0x20) ? 0 : 1;
1278
1279         for (;x<4;x++)
1280         {
1281                 pen_bg0[x] = pens[m_pal_ind16[x]];
1282                 pen_bg1[x] = pens[m_pal_ind16[x]];
1283         }
1284
1285         for (x=0;x<128;x++)
1286         {
1287                 colour = m_vram_space->read_byte(nametbl_addr++);
1288
1289                 *ln++ = pen_bg0[colour>>6];
1290                 *ln++ = pen_bg1[(colour>>4)&3];
1291                 *ln++ = pen_bg0[(colour>>2)&3];
1292                 *ln++ = pen_bg1[(colour&3)];
1293         }
1294
1295         pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
1296         pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
1297         xx = 16 - m_offset_x;
1298         while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
1299 }
1300
1301 void v99x8_device::mode_graphic6(const scrntype_t *pens, scrntype_t *ln, int line)
1302 {
1303         UINT8 colour;
1304         int line2, linemask, x, xx, nametbl_addr;
1305         scrntype_t pen_bg, fg0;
1306         scrntype_t fg1;
1307
1308         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1309
1310         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1311
1312         nametbl_addr = line2 << 8 ;
1313         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1314                 nametbl_addr += 0x10000;
1315
1316         pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1317         xx = m_offset_x * 2;
1318         while (xx--) *ln++ = pen_bg;
1319
1320         if (m_cont_reg[2] & 0x40)
1321         {
1322                 for (x=0;x<32;x++)
1323                 {
1324                         nametbl_addr++;
1325                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1326                         fg0 = pens[m_pal_ind16[colour>>4]];
1327                         fg1 = pens[m_pal_ind16[colour&15]];
1328                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1329                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1330                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1331                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1332                         nametbl_addr += 7;
1333                 }
1334         }
1335         else
1336         {
1337                 for (x=0;x<256;x++)
1338                 {
1339                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1340                         *ln++ = pens[m_pal_ind16[colour>>4]];
1341                         *ln++ = pens[m_pal_ind16[colour&15]];
1342                         nametbl_addr++;
1343                 }
1344         }
1345
1346         xx = (16 - m_offset_x) * 2;
1347         while (xx--) *ln++ = pen_bg;
1348 }
1349
1350 void v99x8_device::mode_graphic7(const scrntype_t *pens, scrntype_t *ln, int line)
1351 {
1352         UINT8 colour;
1353         int line2, linemask, x, xx, nametbl_addr;
1354         scrntype_t pen, pen_bg;
1355
1356         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1357
1358         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1359
1360         nametbl_addr = line2 << 8;
1361         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1362                 nametbl_addr += 0x10000;
1363
1364         pen_bg = pens[m_pal_ind256[m_cont_reg[7]]];
1365         xx = m_offset_x * 2;
1366         while (xx--) *ln++ = pen_bg;
1367
1368         if ((m_v9958_sp_mode & 0x18) == 0x08) // v9958 screen 12, puzzle star title screen
1369         {
1370                 for (x=0;x<64;x++)
1371                 {
1372                         int colour[4];
1373                         int ind;
1374
1375                         colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1376                         nametbl_addr++;
1377                         colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1378                         nametbl_addr++;
1379                         colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1380                         nametbl_addr++;
1381                         colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1382
1383                         ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 |
1384                         (colour[2] & 7) << 5 | (colour[3] & 7) << 8;
1385
1386                         *ln++ = pens[s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]];
1387                         *ln++ = pens[s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]];
1388
1389                         *ln++ = pens[s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]];
1390                         *ln++ = pens[s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]];
1391
1392                         *ln++ = pens[s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]];
1393                         *ln++ = pens[s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]];
1394
1395                         *ln++ = pens[s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]];
1396                         *ln++ = pens[s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]];
1397
1398                         nametbl_addr++;
1399                 }
1400         }
1401         else if ((m_v9958_sp_mode & 0x18) == 0x18) // v9958 screen 10/11, puzzle star & sexy boom gameplay
1402         {
1403                 for (x=0;x<64;x++)
1404                 {
1405                         int colour[4];
1406                         int ind;
1407
1408                         colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1409                         nametbl_addr++;
1410                         colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1411                         nametbl_addr++;
1412                         colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1413                         nametbl_addr++;
1414                         colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1415
1416                         ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 |
1417                         (colour[2] & 7) << 5 | (colour[3] & 7) << 8;
1418
1419                         *ln++ = pens[colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]];
1420                         *ln++ = pens[colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]];
1421
1422                         *ln++ = pens[colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]];
1423                         *ln++ = pens[colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]];
1424
1425                         *ln++ = pens[colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]];
1426                         *ln++ = pens[colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]];
1427
1428                         *ln++ = pens[colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]];
1429                         *ln++ = pens[colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]];
1430
1431                         nametbl_addr++;
1432                 }
1433         }
1434         else if (m_cont_reg[2] & 0x40)
1435         {
1436                 for (x=0;x<32;x++)
1437                 {
1438                         nametbl_addr++;
1439                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1440                         pen = pens[m_pal_ind256[colour]];
1441                         *ln++ = pen; *ln++ = pen;
1442                         *ln++ = pen; *ln++ = pen;
1443                         *ln++ = pen; *ln++ = pen;
1444                         *ln++ = pen; *ln++ = pen;
1445                         *ln++ = pen; *ln++ = pen;
1446                         *ln++ = pen; *ln++ = pen;
1447                         *ln++ = pen; *ln++ = pen;
1448                         *ln++ = pen; *ln++ = pen;
1449                         nametbl_addr++;
1450                 }
1451         }
1452         else
1453         {
1454                 for (x=0;x<256;x++)
1455                 {
1456                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1457                         pen = pens[m_pal_ind256[colour]];
1458                         *ln++ = pen;
1459                         *ln++ = pen;
1460                         nametbl_addr++;
1461                 }
1462         }
1463
1464         xx = (16 - m_offset_x) * 2;
1465         while (xx--) *ln++ = pen_bg;
1466 }
1467
1468 void v99x8_device::mode_unknown(const scrntype_t *pens, scrntype_t *ln, int line)
1469 {
1470         scrntype_t fg, bg;
1471         int x;
1472
1473         fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1474         bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1475
1476         x = m_offset_x * 2;
1477         while (x--) *ln++ = bg;
1478
1479         x = 512;
1480         while (x--) *ln++ = fg;
1481
1482         x = (16 - m_offset_x) * 2;
1483         while (x--) *ln++ = bg;
1484 }
1485
1486 void v99x8_device::default_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1487 {
1488         int i;
1489         ln += m_offset_x * 2;
1490
1491         for (i=0;i<256;i++)
1492         {
1493                 if (col[i] & 0x80)
1494                 {
1495                         *ln++ = pens[m_pal_ind16[col[i]&0x0f]];
1496                         *ln++ = pens[m_pal_ind16[col[i]&0x0f]];
1497                 }
1498                 else
1499                 {
1500                         ln += 2;
1501                 }
1502         }
1503 }
1504
1505 void v99x8_device::graphic5_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1506 {
1507         int i;
1508         ln += m_offset_x * 2;
1509
1510         for (i=0;i<256;i++)
1511         {
1512                 if (col[i] & 0x80)
1513                 {
1514                         *ln++ = pens[m_pal_ind16[(col[i]>>2)&0x03]];
1515                         *ln++ = pens[m_pal_ind16[col[i]&0x03]];
1516                 }
1517                 else
1518                 {
1519                         ln += 2;
1520                 }
1521         }
1522 }
1523
1524
1525 void v99x8_device::graphic7_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1526 {
1527         static const UINT16 g7_ind16[16] = {
1528                 0, 2, 192, 194, 48, 50, 240, 242,
1529         482, 7, 448, 455, 56, 63, 504, 511  };
1530         int i;
1531
1532         ln += m_offset_x * 2;
1533
1534         for (i=0;i<256;i++)
1535         {
1536                 if (col[i] & 0x80)
1537                 {
1538                         *ln++ = pens[g7_ind16[col[i]&0x0f]];
1539                         *ln++ = pens[g7_ind16[col[i]&0x0f]];
1540                 }
1541                 else
1542                 {
1543                         ln += 2;
1544                 }
1545         }
1546 }
1547
1548
1549 void v99x8_device::sprite_mode1 (int line, UINT8 *col)
1550 {
1551         int attrtbl_addr, patterntbl_addr, pattern_addr;
1552         int x, y, p, height, c, p2, i, n, pattern;
1553
1554         memset(col, 0, 256);
1555
1556         // are sprites disabled?
1557         if (m_cont_reg[8] & 0x02) return;
1558
1559         attrtbl_addr = (m_cont_reg[5] << 7) + (m_cont_reg[11] << 15);
1560         patterntbl_addr = (m_cont_reg[6] << 11);
1561
1562         // 16x16 or 8x8 sprites
1563         height = (m_cont_reg[1] & 2) ? 16 : 8;
1564         // magnified sprites (zoomed)
1565         if (m_cont_reg[1] & 1) height *= 2;
1566
1567         p2 = p = 0;
1568         while (1)
1569         {
1570                 y = m_vram_space->read_byte(attrtbl_addr);
1571                 if (y == 208) break;
1572                 y = (y - m_cont_reg[23]) & 255;
1573                 if (y > 208)
1574                         y = -(~y&255);
1575                 else
1576                         y++;
1577
1578                 // if sprite in range, has to be drawn
1579                 if ( (line >= y) && (line  < (y + height) ) )
1580                 {
1581                         if (p2 == 4)
1582                         {
1583                                 // max maximum sprites per line!
1584                                 if ( !(m_stat_reg[0] & 0x40) )
1585                                         m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p;
1586
1587                                 break;
1588                         }
1589                         // get x
1590                         x = m_vram_space->read_byte(attrtbl_addr + 1);
1591                         if (m_vram_space->read_byte(attrtbl_addr + 3) & 0x80) x -= 32;
1592
1593                         // get pattern
1594                         pattern = m_vram_space->read_byte(attrtbl_addr + 2);
1595                         if (m_cont_reg[1] & 2)
1596                                 pattern &= 0xfc;
1597                         n = line - y;
1598                         pattern_addr = patterntbl_addr + pattern * 8 + ((m_cont_reg[1] & 1) ? n/2  : n);
1599                         pattern = (m_vram_space->read_byte(pattern_addr) << 8) | m_vram_space->read_byte(pattern_addr+16);
1600
1601                         // get colour
1602                         c = m_vram_space->read_byte(attrtbl_addr + 3) & 0x0f;
1603
1604                         // draw left part
1605                         n = 0;
1606                         while (1)
1607                         {
1608                                 if (n == 0) pattern = m_vram_space->read_byte(pattern_addr);
1609                                 else if ( (n == 1) && (m_cont_reg[1] & 2) ) pattern = m_vram_space->read_byte(pattern_addr + 16);
1610                                 else break;
1611
1612                                 n++;
1613
1614                                 for (i=0;i<8;i++)
1615                                 {
1616                                         if (pattern & 0x80)
1617                                         {
1618                                                 if ( (x >= 0) && (x < 256) )
1619                                                 {
1620                                                         if (col[x] & 0x40)
1621                                                         {
1622                                                                 // we have a collision!
1623                                                                 if (p2 < 4)
1624                                                                         m_stat_reg[0] |= 0x20;
1625                                                         }
1626                                                         if ( !(col[x] & 0x80) )
1627                                                         {
1628                                                                 if (c || (m_cont_reg[8] & 0x20) )
1629                                                                         col[x] |= 0xc0 | c;
1630                                                                 else
1631                                                                         col[x] |= 0x40;
1632                                                         }
1633
1634                                                         // if zoomed, draw another pixel
1635                                                         if (m_cont_reg[1] & 1)
1636                                                         {
1637                                                                 if (col[x+1] & 0x40)
1638                                                                 {
1639                                                                         // we have a collision!
1640                                                                         if (p2 < 4)
1641                                                                                 m_stat_reg[0] |= 0x20;
1642                                                                 }
1643                                                                 if ( !(col[x+1] & 0x80) )
1644                                                                 {
1645                                                                         if (c || (m_cont_reg[8] & 0x20) )
1646                                                                                 col[x+1] |= 0xc0 | c;
1647                                                                         else
1648                                                                                 col[x+1] |= 0x80;
1649                                                                 }
1650                                                         }
1651                                                 }
1652                                         }
1653                                         if (m_cont_reg[1] & 1) x += 2; else x++;
1654                                         pattern <<= 1;
1655                                 }
1656                         }
1657
1658                         p2++;
1659                 }
1660
1661                 if (p >= 31) break;
1662                 p++;
1663                 attrtbl_addr += 4;
1664         }
1665
1666         if ( !(m_stat_reg[0] & 0x40) )
1667                 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p;
1668 }
1669
1670 void v99x8_device::sprite_mode2 (int line, UINT8 *col)
1671 {
1672         int attrtbl_addr, patterntbl_addr, pattern_addr, colourtbl_addr;
1673         int x, i, y, p, height, c, p2, n, pattern, colourmask, first_cc_seen;
1674
1675         memset(col, 0, 256);
1676
1677         // are sprites disabled?
1678         if (m_cont_reg[8] & 0x02) return;
1679
1680         attrtbl_addr = ( (m_cont_reg[5] & 0xfc) << 7) + (m_cont_reg[11] << 15);
1681         colourtbl_addr =  ( (m_cont_reg[5] & 0xf8) << 7) + (m_cont_reg[11] << 15);
1682         patterntbl_addr = (m_cont_reg[6] << 11);
1683         colourmask = ( (m_cont_reg[5] & 3) << 3) | 0x7; // check this!
1684
1685         // 16x16 or 8x8 sprites
1686         height = (m_cont_reg[1] & 2) ? 16 : 8;
1687         // magnified sprites (zoomed)
1688         if (m_cont_reg[1] & 1) height *= 2;
1689
1690         p2 = p = first_cc_seen = 0;
1691         while (1)
1692         {
1693                 y = vram_read(attrtbl_addr);
1694                 if (y == 216) break;
1695                 y = (y - m_cont_reg[23]) & 255;
1696                 if (y > 216)
1697                         y = -(~y&255);
1698                 else
1699                         y++;
1700
1701                 // if sprite in range, has to be drawn
1702                 if ( (line >= y) && (line  < (y + height) ) )
1703                 {
1704                         if (p2 == 8)
1705                         {
1706                                 // max maximum sprites per line!
1707                                 if ( !(m_stat_reg[0] & 0x40) )
1708                                         m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p;
1709
1710                                 break;
1711                         }
1712
1713                         n = line - y; if (m_cont_reg[1] & 1) n /= 2;
1714                         // get colour
1715                         c = vram_read(colourtbl_addr + (((p&colourmask)*16) + n));
1716
1717                         // don't draw all sprite with CC set before any sprites
1718                         // with CC = 0 are seen on this line
1719                         if (c & 0x40)
1720                         {
1721                                 if (!first_cc_seen)
1722                                         goto skip_first_cc_set;
1723                         }
1724                         else
1725                                 first_cc_seen = 1;
1726
1727                         // get pattern
1728                         pattern = vram_read(attrtbl_addr + 2);
1729                         if (m_cont_reg[1] & 2)
1730                                 pattern &= 0xfc;
1731                         pattern_addr = patterntbl_addr + pattern * 8 + n;
1732                         pattern = (vram_read(pattern_addr) << 8) | vram_read(pattern_addr + 16);
1733
1734                         // get x
1735                         x = vram_read(attrtbl_addr + 1);
1736                         if (c & 0x80) x -= 32;
1737
1738                         n = (m_cont_reg[1] & 2) ? 16 : 8;
1739                         while (n--)
1740                         {
1741                                 for (i=0;i<=(m_cont_reg[1] & 1);i++)
1742                                 {
1743                                         if ( (x >= 0) && (x < 256) )
1744                                         {
1745                                                 if ( (pattern & 0x8000) && !(col[x] & 0x10) )
1746                                                 {
1747                                                         if ( (c & 15) || (m_cont_reg[8] & 0x20) )
1748                                                         {
1749                                                                 if ( !(c & 0x40) )
1750                                                                 {
1751                                                                         if (col[x] & 0x20) col[x] |= 0x10;
1752                                                                         else
1753                                                                                 col[x] |= 0x20 | (c & 15);
1754                                                                 }
1755                                                                 else
1756                                                                         col[x] |= c & 15;
1757
1758                                                                 col[x] |= 0x80;
1759                                                         }
1760                                                 }
1761                                                 else
1762                                                 {
1763                                                         if ( !(c & 0x40) && (col[x] & 0x20) )
1764                                                                 col[x] |= 0x10;
1765                                                 }
1766
1767                                                 if ( !(c & 0x60) && (pattern & 0x8000) )
1768                                                 {
1769                                                         if (col[x] & 0x40)
1770                                                         {
1771                                                                 // sprite collision!
1772                                                                 if (p2 < 8)
1773                                                                         m_stat_reg[0] |= 0x20;
1774                                                         }
1775                                                         else
1776                                                                 col[x] |= 0x40;
1777                                                 }
1778
1779                                                 x++;
1780                                         }
1781                                 }
1782
1783                                 pattern <<= 1;
1784                         }
1785
1786                 skip_first_cc_set:
1787                         p2++;
1788                 }
1789
1790                 if (p >= 31) break;
1791                 p++;
1792                 attrtbl_addr += 4;
1793         }
1794
1795         if ( !(m_stat_reg[0] & 0x40) )
1796                 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p;
1797 }
1798
1799
1800 const v99x8_device::v99x8_mode v99x8_device::s_modes[] = {
1801         { 0x02,
1802                 &v99x8_device::mode_text1,
1803                 &v99x8_device::default_border,
1804                 NULL,
1805                 NULL
1806         },
1807         { 0x01,
1808                 &v99x8_device::mode_multi,
1809                 &v99x8_device::default_border,
1810                 &v99x8_device::sprite_mode1,
1811                 &v99x8_device::default_draw_sprite
1812         },
1813         { 0x00,
1814                 &v99x8_device::mode_graphic1,
1815                 &v99x8_device::default_border,
1816                 &v99x8_device::sprite_mode1,
1817                 &v99x8_device::default_draw_sprite
1818         },
1819         { 0x04,
1820                 &v99x8_device::mode_graphic23,
1821                 &v99x8_device::default_border,
1822                 &v99x8_device::sprite_mode1,
1823                 &v99x8_device::default_draw_sprite
1824         },
1825         { 0x08,
1826                 &v99x8_device::mode_graphic23,
1827                 &v99x8_device::default_border,
1828                 &v99x8_device::sprite_mode2,
1829                 &v99x8_device::default_draw_sprite
1830         },
1831         { 0x0c,
1832                 &v99x8_device::mode_graphic4,
1833                 &v99x8_device::default_border,
1834                 &v99x8_device::sprite_mode2,
1835                 &v99x8_device::default_draw_sprite
1836         },
1837         { 0x10,
1838                 &v99x8_device::mode_graphic5,
1839                 &v99x8_device::graphic5_border,
1840                 &v99x8_device::sprite_mode2,
1841                 &v99x8_device::graphic5_draw_sprite
1842         },
1843         { 0x14,
1844                 &v99x8_device::mode_graphic6,
1845                 &v99x8_device::default_border,
1846                 &v99x8_device::sprite_mode2,
1847                 &v99x8_device::default_draw_sprite
1848         },
1849         { 0x1c,
1850                 &v99x8_device::mode_graphic7,
1851                 &v99x8_device::graphic7_border,
1852                 &v99x8_device::sprite_mode2,
1853                 &v99x8_device::graphic7_draw_sprite
1854         },
1855         { 0x0a,
1856                 &v99x8_device::mode_text2,
1857                 &v99x8_device::default_border,
1858                 NULL,
1859                 NULL
1860         },
1861         { 0xff,
1862                 &v99x8_device::mode_unknown,
1863                 &v99x8_device::default_border,
1864                 NULL,
1865                 NULL
1866         }
1867 };
1868
1869 void v99x8_device::set_mode()
1870 {
1871         int n,i;
1872
1873         n = (((m_cont_reg[0] & 0x0e) << 1) | ((m_cont_reg[1] & 0x18) >> 3));
1874         for (i=0;;i++)
1875         {
1876                 if ( (s_modes[i].m == n) || (s_modes[i].m == 0xff) ) break;
1877         }
1878         m_mode = i;
1879 }
1880
1881 void v99x8_device::refresh_16(int line)
1882 {
1883         //const pen_t *pens = m_palette->pens();
1884         const scrntype_t *pens = this->pens;
1885         bool double_lines = false;
1886         UINT8 col[256];
1887         scrntype_t *ln, *ln2 = NULL;
1888
1889         if (m_cont_reg[9] & 0x08)
1890         {
1891 //              ln = &m_bitmap.pix16(m_scanline*2+((m_stat_reg[2]>>1)&1));
1892                 ln = screen+(m_scanline*2+((m_stat_reg[2]>>1)&1))*_V9938_LONG_WIDTH;
1893         }
1894         else
1895         {
1896 //              ln = &m_bitmap.pix16(m_scanline*2);
1897 //              ln2 = &m_bitmap.pix16(m_scanline*2+1);
1898                 ln = screen+(m_scanline*2)*_V9938_LONG_WIDTH;
1899                 ln2 = screen+(m_scanline*2+1)*_V9938_LONG_WIDTH;
1900                 double_lines = true;
1901         }
1902
1903         if ( !(m_cont_reg[1] & 0x40) || (m_stat_reg[2] & 0x40) )
1904         {
1905                 (this->*s_modes[m_mode].border_16)(pens, ln);
1906         }
1907         else
1908         {
1909                 (this->*s_modes[m_mode].visible_16)(pens, ln, line);
1910                 if (s_modes[m_mode].sprites)
1911                 {
1912                         (this->*s_modes[m_mode].sprites)(line, col);
1913                         (this->*s_modes[m_mode].draw_sprite_16)(pens, ln, col);
1914                 }
1915         }
1916
1917         if (double_lines)
1918                 my_memcpy(ln2, ln, (512 + 32) * sizeof(scrntype_t));
1919 }
1920
1921 void v99x8_device::refresh_line(int line)
1922 {
1923         int ind16, ind256;
1924
1925         ind16 = m_pal_ind16[0];
1926         ind256 = m_pal_ind256[0];
1927
1928         if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) )
1929         {
1930                 m_pal_ind16[0] = m_pal_ind16[(m_cont_reg[7] & 0x0f)];
1931                 m_pal_ind256[0] = m_pal_ind256[m_cont_reg[7]];
1932         }
1933
1934         refresh_16 (line);
1935
1936         if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) )
1937         {
1938                 m_pal_ind16[0] = ind16;
1939                 m_pal_ind256[0] = ind256;
1940         }
1941 }
1942
1943 /*
1944
1945 From: awulms@inter.nl.net (Alex Wulms)
1946 *** About the HR/VR topic: this is how it works according to me:
1947
1948 *** HR:
1949 HR is very straightforward:
1950 -HR=1 during 'display time'
1951 -HR=0 during 'horizontal border, horizontal retrace'
1952 I have put 'display time' and 'horizontal border, horizontal retrace' between
1953 quotes because HR does not only flip between 0 and 1 during the display of
1954 the 192/212 display lines, but also during the vertical border and during the
1955 vertical retrace.
1956
1957 *** VR:
1958 VR is a little bit tricky
1959 -VR always gets set to 0 when the VDP starts with display line 0
1960 -VR gets set to 1 when the VDP reaches display line (192 if LN=0) or (212 if
1961 LN=1)
1962 -The VDP displays contents of VRAM as long as VR=0
1963
1964 As a consequence of this behaviour, it is possible to program the famous
1965 overscan trick, where VRAM contents is shown in the borders:
1966 Generate an interrupt at line 230 (or so) and on this interrupt: set LN=1
1967 Generate an interrupt at line 200 (or so) and on this interrupt: set LN=0
1968 Repeat the above two steps
1969
1970 *** The top/bottom border contents during overscan:
1971 On screen 0:
1972 1) The VDP keeps increasing the name table address pointer during bottom
1973 border, vertical retrace and top border
1974 2) The VDP resets the name table address pointer when the first display line
1975 is reached
1976
1977 On the other screens:
1978 1) The VDP keeps increasing the name table address pointer during the bottom
1979 border
1980 2) The VDP resets the name table address pointer such that the top border
1981 contents connects up with the first display line. E.g., when the top border
1982 is 26 lines high, the VDP will take:
1983 'logical'      vram line
1984 TOPB000  256-26
1985 ...
1986 TOPB025  256-01
1987 DISPL000 000
1988 ...
1989 DISPL211 211
1990 BOTB000  212
1991 ...
1992 BOTB024  236
1993
1994
1995
1996 *** About the horizontal interrupt
1997
1998 All relevant definitions on a row:
1999 -FH: Bit 0 of status register 1
2000 -IE1: Bit 4 of mode register 0
2001 -IL: Line number in mode register 19
2002 -DL: The line that the VDP is going to display (corrected for vertical scroll)
2003 -IRQ: Interrupt request line of VDP to Z80
2004
2005 At the *start* of every new line (display, bottom border, part of vertical
2006 display), the VDP does:
2007 -FH = (FH && IE1) || (IL==DL)
2008
2009 After reading of status register 1 by the CPU, the VDP does:
2010 -FH = 0
2011
2012 Furthermore, the following is true all the time:
2013 -IRQ = FH && IE1
2014
2015 The resulting behaviour:
2016 When IE1=0:
2017 -FH will be set as soon as display of line IL starts
2018 -FH will be reset as soon as status register 1 is read
2019 -FH will be reset as soon as the next display line is reached
2020
2021 When IE=1:
2022 -FH and IRQ will be set as soon as display line IL is reached
2023 -FH and IRQ will be reset as soon as status register 1 is read
2024
2025 Another subtile result:
2026 If, while FH and IRQ are set, IE1 gets reset, the next happens:
2027 -IRQ is reset immediately (since IRQ is always FH && IE1)
2028 -FH will be reset as soon as display of the next line starts (unless the next
2029 line is line IL)
2030
2031
2032 *** About the vertical interrupt:
2033 Another relevant definition:
2034 -FV: Bit 7 of status register 0
2035 -IE0: Bit 5 of mode register 1
2036
2037 I only know for sure the behaviour when IE0=1:
2038 -FV and IRQ will be set as soon as VR changes from 0 to 1
2039 -FV and IRQ will be reset as soon as status register 0 is read
2040
2041 A consequence is that NO vertical interrupts will be generated during the
2042 overscan trick, described in the VR section above.
2043
2044 I do not know the behaviour of FV when IE0=0. That is the part that I still
2045 have to test.
2046 */
2047
2048 void v99x8_device::interrupt_start_vblank()
2049 {
2050         #if 0
2051         if (machine.input().code_pressed (KEYCODE_D) )
2052         {
2053                 for (i=0;i<24;i++) osd_printf_debug ("R#%d = %02x\n", i, m_cont_reg[i]);
2054         }
2055         #endif
2056
2057         // at every frame, vdp switches fields
2058         m_stat_reg[2] = (m_stat_reg[2] & 0xfd) | (~m_stat_reg[2] & 2);
2059
2060         // color blinking
2061         if (!(m_cont_reg[13] & 0xf0))
2062                 m_blink = 0;
2063         else if (!(m_cont_reg[13] & 0x0f))
2064                 m_blink = 1;
2065         else
2066         {
2067                 // both on and off counter are non-zero: timed blinking
2068                 if (m_blink_count)
2069                         m_blink_count--;
2070                 if (!m_blink_count)
2071                 {
2072                         m_blink = !m_blink;
2073                         if (m_blink)
2074                                 m_blink_count = (m_cont_reg[13] >> 4) * 10;
2075                         else
2076                                 m_blink_count = (m_cont_reg[13] & 0x0f) * 10;
2077                 }
2078         }
2079 }
2080
2081 /***************************************************************************
2082
2083 Command unit
2084
2085 ***************************************************************************/
2086
2087 /*************************************************************/
2088 /** Completely rewritten by Alex Wulms:                     **/
2089 /**  - VDP Command execution 'in parallel' with CPU         **/
2090 /**  - Corrected behaviour of VDP commands                  **/
2091 /**  - Made it easier to implement correct S7/8 mapping     **/
2092 /**    by concentrating VRAM access in one single place     **/
2093 /**  - Made use of the 'in parallel' VDP command exec       **/
2094 /**    and correct timing. You must call the function       **/
2095 /**    LoopVDP() from LoopZ80 in MSX.c. You must call it    **/
2096 /**    exactly 256 times per screen refresh.                **/
2097 /** Started on       : 11-11-1999                           **/
2098 /** Beta release 1 on:  9-12-1999                           **/
2099 /** Beta release 2 on: 20-01-2000                           **/
2100 /**  - Corrected behaviour of VRM <-> Z80 transfer          **/
2101 /**  - Improved performance of the code                     **/
2102 /** Public release 1.0: 20-04-2000                          **/
2103 /*************************************************************/
2104
2105 #define VDP_VRMP5(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&255)>>1)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&255)>>1)))
2106 #define VDP_VRMP6(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2)))
2107 //#define VDP_VRMP7(MX, X, Y) ((!MX) ? (((Y&511)<<8) + ((X&511)>>1)) : (EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1)))
2108 #define VDP_VRMP7(MX, X, Y) ((!MX) ? (((X&2)<<15) + ((Y&511)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2))/*(EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1))*/)
2109 //#define VDP_VRMP8(MX, X, Y) ((!MX) ? (((Y&511)<<8) + (X&255)) : (EXPMEM_OFFSET + ((Y&255)<<8) + (X&255)))
2110 #define VDP_VRMP8(MX, X, Y) ((!MX) ? (((X&1)<<16) + ((Y&511)<<7) + ((X>>1)&127)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X>>1)&127))/*(EXPMEM_OFFSET + ((Y&255)<<8) + (X&255))*/)
2111
2112 #define VDP_VRMP(M, MX, X, Y) VDPVRMP(M, MX, X, Y)
2113 #define VDP_POINT(M, MX, X, Y) VDPpoint(M, MX, X, Y)
2114 #define VDP_PSET(M, MX, X, Y, C, O) VDPpset(M, MX, X, Y, C, O)
2115
2116 #define CM_ABRT  0x0
2117 #define CM_POINT 0x4
2118 #define CM_PSET  0x5
2119 #define CM_SRCH  0x6
2120 #define CM_LINE  0x7
2121 #define CM_LMMV  0x8
2122 #define CM_LMMM  0x9
2123 #define CM_LMCM  0xA
2124 #define CM_LMMC  0xB
2125 #define CM_HMMV  0xC
2126 #define CM_HMMM  0xD
2127 #define CM_YMMM  0xE
2128 #define CM_HMMC  0xF
2129
2130 /*************************************************************
2131 Many VDP commands are executed in some kind of loop but
2132 essentially, there are only a few basic loop structures
2133 that are re-used. We define the loop structures that are
2134 re-used here so that they have to be entered only once
2135 *************************************************************/
2136 #define pre_loop \
2137 while ((cnt-=delta) > 0) {
2138         #define post_loop \
2139 }
2140
2141 // Loop over DX, DY
2142 #define post__x_y(MX) \
2143 if (!--ANX || ((ADX+=TX)&MX)) { \
2144         if (!(--NY&1023) || (DY+=TY)==-1) \
2145                 break; \
2146         else { \
2147                 ADX=DX; \
2148                 ANX=NX; \
2149         } \
2150 } \
2151 post_loop
2152
2153 // Loop over DX, SY, DY
2154 #define post__xyy(MX) \
2155 if ((ADX+=TX)&MX) { \
2156         if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
2157                 break; \
2158         else \
2159                 ADX=DX; \
2160 } \
2161 post_loop
2162
2163 // Loop over SX, DX, SY, DY
2164 #define post_xxyy(MX) \
2165 if (!--ANX || ((ASX+=TX)&MX) || ((ADX+=TX)&MX)) { \
2166         if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
2167                 break; \
2168         else { \
2169                 ASX=SX; \
2170                 ADX=DX; \
2171                 ANX=NX; \
2172         } \
2173 } \
2174 post_loop
2175
2176 /*************************************************************/
2177 /** Variables visible only in this module                   **/
2178 /*************************************************************/
2179 static const UINT8 Mask[4] = { 0x0F,0x03,0x0F,0xFF };
2180 static const int  PPB[4]  = { 2,4,2,1 };
2181 static const int  PPL[4]  = { 256,512,512,256 };
2182
2183 //  SprOn SprOn SprOf SprOf
2184 //  ScrOf ScrOn ScrOf ScrOn
2185 static const int srch_timing[8]={
2186         818, 1025,  818,  830, // ntsc
2187         696,  854,  696,  684  // pal
2188 };
2189 static const int line_timing[8]={
2190         1063, 1259, 1063, 1161,
2191         904,  1026, 904,  953
2192 };
2193 static const int hmmv_timing[8]={
2194         439,  549,  439,  531,
2195         366,  439,  366,  427
2196 };
2197 static const int lmmv_timing[8]={
2198         873,  1135, 873, 1056,
2199         732,  909,  732,  854
2200 };
2201 static const int ymmm_timing[8]={
2202         586,  952,  586,  610,
2203         488,  720,  488,  500
2204 };
2205 static const int hmmm_timing[8]={
2206         818,  1111, 818,  854,
2207         684,  879,  684,  708
2208 };
2209 static const int lmmm_timing[8]={
2210         1160, 1599, 1160, 1172,
2211         964,  1257, 964,  977
2212 };
2213
2214 /** VDPVRMP() **********************************************/
2215 /** Calculate addr of a pixel in vram                       **/
2216 /*************************************************************/
2217 inline int v99x8_device::VDPVRMP(UINT8 M,int MX,int X,int Y)
2218 {
2219         switch(M)
2220         {
2221         case 0: return VDP_VRMP5(MX,X,Y);
2222         case 1: return VDP_VRMP6(MX,X,Y);
2223         case 2: return VDP_VRMP7(MX,X,Y);
2224         case 3: return VDP_VRMP8(MX,X,Y);
2225         }
2226
2227         return 0;
2228 }
2229
2230 /** VDPpoint5() ***********************************************/
2231 /** Get a pixel on screen 5                                 **/
2232 /*************************************************************/
2233 inline UINT8 v99x8_device::VDPpoint5(int MXS, int SX, int SY)
2234 {
2235         return (m_vram_space->read_byte(VDP_VRMP5(MXS, SX, SY)) >>
2236                 (((~SX)&1)<<2)
2237                 )&15;
2238 }
2239
2240 /** VDPpoint6() ***********************************************/
2241 /** Get a pixel on screen 6                                 **/
2242 /*************************************************************/
2243 inline UINT8 v99x8_device::VDPpoint6(int MXS, int SX, int SY)
2244 {
2245         return (m_vram_space->read_byte(VDP_VRMP6(MXS, SX, SY)) >>
2246                 (((~SX)&3)<<1)
2247                 )&3;
2248 }
2249
2250 /** VDPpoint7() ***********************************************/
2251 /** Get a pixel on screen 7                                 **/
2252 /*************************************************************/
2253 inline UINT8 v99x8_device::VDPpoint7(int MXS, int SX, int SY)
2254 {
2255         return (m_vram_space->read_byte(VDP_VRMP7(MXS, SX, SY)) >>
2256                 (((~SX)&1)<<2)
2257                 )&15;
2258 }
2259
2260 /** VDPpoint8() ***********************************************/
2261 /** Get a pixel on screen 8                                 **/
2262 /*************************************************************/
2263 inline UINT8 v99x8_device::VDPpoint8(int MXS, int SX, int SY)
2264 {
2265         return m_vram_space->read_byte(VDP_VRMP8(MXS, SX, SY));
2266 }
2267
2268 /** VDPpoint() ************************************************/
2269 /** Get a pixel on a screen                                 **/
2270 /*************************************************************/
2271 inline UINT8 v99x8_device::VDPpoint(UINT8 SM, int MXS, int SX, int SY)
2272 {
2273         switch(SM)
2274         {
2275         case 0: return VDPpoint5(MXS,SX,SY);
2276         case 1: return VDPpoint6(MXS,SX,SY);
2277         case 2: return VDPpoint7(MXS,SX,SY);
2278         case 3: return VDPpoint8(MXS,SX,SY);
2279         }
2280
2281         return(0);
2282 }
2283
2284 /** VDPpsetlowlevel() ****************************************/
2285 /** Low level function to set a pixel on a screen           **/
2286 /** Make it inline to make it fast                          **/
2287 /*************************************************************/
2288 inline void v99x8_device::VDPpsetlowlevel(int addr, UINT8 CL, UINT8 M, UINT8 OP)
2289 {
2290         // If this turns out to be too slow, get a pointer to the address space
2291         // and work directly on it.
2292         UINT8 val = m_vram_space->read_byte(addr);
2293         switch (OP)
2294         {
2295         case 0: val = (val & M) | CL; break;
2296         case 1: val = val & (CL | M); break;
2297         case 2: val |= CL; break;
2298         case 3: val ^= CL; break;
2299         case 4: val = (val & M) | ~(CL | M); break;
2300         case 8: if (CL) val = (val & M) | CL; break;
2301         case 9: if (CL) val = val & (CL | M); break;
2302         case 10: if (CL) val |= CL; break;
2303         case 11:  if (CL) val ^= CL; break;
2304         case 12:  if (CL) val = (val & M) | ~(CL|M); break;
2305         default:
2306                 LOG(("v9938: invalid operation %d in pset\n", OP));
2307         }
2308
2309         m_vram_space->write_byte(addr, val);
2310 }
2311
2312 /** VDPpset5() ***********************************************/
2313 /** Set a pixel on screen 5                                 **/
2314 /*************************************************************/
2315 inline void v99x8_device::VDPpset5(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2316 {
2317         UINT8 SH = ((~DX)&1)<<2;
2318         VDPpsetlowlevel(VDP_VRMP5(MXD, DX, DY), CL << SH, ~(15<<SH), OP);
2319 }
2320
2321 /** VDPpset6() ***********************************************/
2322 /** Set a pixel on screen 6                                 **/
2323 /*************************************************************/
2324 inline void v99x8_device::VDPpset6(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2325 {
2326         UINT8 SH = ((~DX)&3)<<1;
2327
2328         VDPpsetlowlevel(VDP_VRMP6(MXD, DX, DY), CL << SH, ~(3<<SH), OP);
2329 }
2330
2331 /** VDPpset7() ***********************************************/
2332 /** Set a pixel on screen 7                                 **/
2333 /*************************************************************/
2334 inline void v99x8_device::VDPpset7(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2335 {
2336         UINT8 SH = ((~DX)&1)<<2;
2337
2338         VDPpsetlowlevel(VDP_VRMP7(MXD, DX, DY), CL << SH, ~(15<<SH), OP);
2339 }
2340
2341 /** VDPpset8() ***********************************************/
2342 /** Set a pixel on screen 8                                 **/
2343 /*************************************************************/
2344 inline void v99x8_device::VDPpset8(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2345 {
2346         VDPpsetlowlevel(VDP_VRMP8(MXD, DX, DY), CL, 0, OP);
2347 }
2348
2349 /** VDPpset() ************************************************/
2350 /** Set a pixel on a screen                                 **/
2351 /*************************************************************/
2352 inline void v99x8_device::VDPpset(UINT8 SM, int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2353 {
2354         switch (SM) {
2355         case 0: VDPpset5(MXD, DX, DY, CL, OP); break;
2356         case 1: VDPpset6(MXD, DX, DY, CL, OP); break;
2357         case 2: VDPpset7(MXD, DX, DY, CL, OP); break;
2358         case 3: VDPpset8(MXD, DX, DY, CL, OP); break;
2359         }
2360 }
2361
2362 /** get_vdp_timing_value() **************************************/
2363 /** Get timing value for a certain VDP command              **/
2364 /*************************************************************/
2365 int v99x8_device::get_vdp_timing_value(const int *timing_values)
2366 {
2367         return(timing_values[((m_cont_reg[1]>>6)&1)|(m_cont_reg[8]&2)|((m_cont_reg[9]<<1)&4)]);
2368 }
2369
2370 /** SrchEgine()** ********************************************/
2371 /** Search a dot                                            **/
2372 /*************************************************************/
2373 void v99x8_device::srch_engine()
2374 {
2375         int SX=m_mmc.SX;
2376         int SY=m_mmc.SY;
2377         int TX=m_mmc.TX;
2378         int ANX=m_mmc.ANX;
2379         UINT8 CL=m_mmc.CL;
2380         int MXD = m_mmc.MXD;
2381         int cnt;
2382         int delta;
2383
2384         delta = get_vdp_timing_value(srch_timing);
2385         cnt = m_vdp_ops_count;
2386
2387         #define post_srch(MX) \
2388         { m_stat_reg[2]|=0x10; /* Border detected */ break; } \
2389         if ((SX+=TX) & MX) { m_stat_reg[2] &= 0xEF; /* Border not detected */ break; }
2390         switch (m_mode) {
2391         default:
2392         case V9938_MODE_GRAPHIC4: pre_loop if ((VDPpoint5(MXD, SX, SY)==CL) ^ANX)  post_srch(256) post_loop
2393                         break;
2394         case V9938_MODE_GRAPHIC5: pre_loop if ((VDPpoint6(MXD, SX, SY)==CL) ^ANX)  post_srch(512) post_loop
2395                         break;
2396         case V9938_MODE_GRAPHIC6: pre_loop if ((VDPpoint7(MXD, SX, SY)==CL) ^ANX)  post_srch(512) post_loop
2397                         break;
2398         case V9938_MODE_GRAPHIC7: pre_loop if ((VDPpoint8(MXD, SX, SY)==CL) ^ANX)  post_srch(256) post_loop
2399                         break;
2400         }
2401
2402         if ((m_vdp_ops_count=cnt)>0) {
2403                 // Command execution done
2404                 m_stat_reg[2] &= 0xFE;
2405                 m_vdp_engine = NULL;
2406                 // Update SX in VDP registers
2407                 m_stat_reg[8] = SX & 0xFF;
2408                 m_stat_reg[9] = (SX>>8) | 0xFE;
2409         }
2410         else {
2411                 m_mmc.SX=SX;
2412         }
2413 }
2414
2415 /** LineEgine()** ********************************************/
2416 /** Draw a line                                             **/
2417 /*************************************************************/
2418 void v99x8_device::line_engine()
2419 {
2420         int DX=m_mmc.DX;
2421         int DY=m_mmc.DY;
2422         int TX=m_mmc.TX;
2423         int TY=m_mmc.TY;
2424         int NX=m_mmc.NX;
2425         int NY=m_mmc.NY;
2426         int ASX=m_mmc.ASX;
2427         int ADX=m_mmc.ADX;
2428         UINT8 CL=m_mmc.CL;
2429         UINT8 LO=m_mmc.LO;
2430         int MXD = m_mmc.MXD;
2431         int cnt;
2432         int delta;
2433
2434         delta = get_vdp_timing_value(line_timing);
2435         cnt = m_vdp_ops_count;
2436
2437         #define post_linexmaj(MX) \
2438         DX+=TX; \
2439         if ((ASX-=NY)<0) { \
2440                 ASX+=NX; \
2441                 DY+=TY; \
2442         } \
2443         ASX&=1023; /* Mask to 10 bits range */\
2444         if (ADX++==NX || (DX&MX)) \
2445                 break; \
2446         post_loop
2447
2448         #define post_lineymaj(MX) \
2449         DY+=TY; \
2450         if ((ASX-=NY)<0) { \
2451                 ASX+=NX; \
2452                 DX+=TX; \
2453         } \
2454         ASX&=1023; /* Mask to 10 bits range */\
2455         if (ADX++==NX || (DX&MX)) \
2456                 break; \
2457         post_loop
2458
2459         if ((m_cont_reg[45]&0x01)==0)
2460                 // X-Axis is major direction
2461         switch (m_mode) {
2462         default:
2463         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_linexmaj(256)
2464                 break;
2465         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_linexmaj(512)
2466                 break;
2467         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_linexmaj(512)
2468                 break;
2469         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_linexmaj(256)
2470                 break;
2471         }
2472         else
2473                 // Y-Axis is major direction
2474         switch (m_mode) {
2475         default:
2476         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_lineymaj(256)
2477                 break;
2478         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_lineymaj(512)
2479                 break;
2480         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_lineymaj(512)
2481                 break;
2482         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_lineymaj(256)
2483                 break;
2484         }
2485
2486         if ((m_vdp_ops_count=cnt)>0) {
2487                 // Command execution done
2488                 m_stat_reg[2]&=0xFE;
2489                 m_vdp_engine=NULL;
2490                 m_cont_reg[38]=DY & 0xFF;
2491                 m_cont_reg[39]=(DY>>8) & 0x03;
2492         }
2493         else {
2494                 m_mmc.DX=DX;
2495                 m_mmc.DY=DY;
2496                 m_mmc.ASX=ASX;
2497                 m_mmc.ADX=ADX;
2498         }
2499 }
2500
2501 /** lmmv_engine() *********************************************/
2502 /** VDP -> Vram                                             **/
2503 /*************************************************************/
2504 void v99x8_device::lmmv_engine()
2505 {
2506         int DX=m_mmc.DX;
2507         int DY=m_mmc.DY;
2508         int TX=m_mmc.TX;
2509         int TY=m_mmc.TY;
2510         int NX=m_mmc.NX;
2511         int NY=m_mmc.NY;
2512         int ADX=m_mmc.ADX;
2513         int ANX=m_mmc.ANX;
2514         UINT8 CL=m_mmc.CL;
2515         UINT8 LO=m_mmc.LO;
2516         int MXD = m_mmc.MXD;
2517         int cnt;
2518         int delta;
2519
2520         delta = get_vdp_timing_value(lmmv_timing);
2521         cnt = m_vdp_ops_count;
2522
2523         switch (m_mode) {
2524         default:
2525         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, CL, LO); post__x_y(256)
2526                 break;
2527         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, CL, LO); post__x_y(512)
2528                 break;
2529         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, CL, LO); post__x_y(512)
2530                 break;
2531         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, CL, LO); post__x_y(256)
2532                 break;
2533         }
2534
2535         if ((m_vdp_ops_count=cnt)>0) {
2536                 // Command execution done
2537                 m_stat_reg[2]&=0xFE;
2538                 m_vdp_engine=NULL;
2539                 if (!NY)
2540                         DY+=TY;
2541                 m_cont_reg[38]=DY & 0xFF;
2542                 m_cont_reg[39]=(DY>>8) & 0x03;
2543                 m_cont_reg[42]=NY & 0xFF;
2544                 m_cont_reg[43]=(NY>>8) & 0x03;
2545         }
2546         else {
2547                 m_mmc.DY=DY;
2548                 m_mmc.NY=NY;
2549                 m_mmc.ANX=ANX;
2550                 m_mmc.ADX=ADX;
2551         }
2552 }
2553
2554 /** lmmm_engine() *********************************************/
2555 /** Vram -> Vram                                            **/
2556 /*************************************************************/
2557 void v99x8_device::lmmm_engine()
2558 {
2559         int SX=m_mmc.SX;
2560         int SY=m_mmc.SY;
2561         int DX=m_mmc.DX;
2562         int DY=m_mmc.DY;
2563         int TX=m_mmc.TX;
2564         int TY=m_mmc.TY;
2565         int NX=m_mmc.NX;
2566         int NY=m_mmc.NY;
2567         int ASX=m_mmc.ASX;
2568         int ADX=m_mmc.ADX;
2569         int ANX=m_mmc.ANX;
2570         UINT8 LO=m_mmc.LO;
2571         int MXS = m_mmc.MXS;
2572         int MXD = m_mmc.MXD;
2573         int cnt;
2574         int delta;
2575
2576         delta = get_vdp_timing_value(lmmm_timing);
2577         cnt = m_vdp_ops_count;
2578
2579         switch (m_mode) {
2580         default:
2581         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, VDPpoint5(MXS, ASX, SY), LO); post_xxyy(256)
2582                 break;
2583         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, VDPpoint6(MXS, ASX, SY), LO); post_xxyy(512)
2584                 break;
2585         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, VDPpoint7(MXS, ASX, SY), LO); post_xxyy(512)
2586                 break;
2587         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, VDPpoint8(MXS, ASX, SY), LO); post_xxyy(256)
2588                 break;
2589         }
2590
2591         if ((m_vdp_ops_count=cnt)>0) {
2592                 // Command execution done
2593                 m_stat_reg[2]&=0xFE;
2594                 m_vdp_engine=NULL;
2595                 if (!NY) {
2596                         SY+=TY;
2597                         DY+=TY;
2598                 }
2599                 else
2600                         if (SY==-1)
2601                         DY+=TY;
2602                 m_cont_reg[42]=NY & 0xFF;
2603                 m_cont_reg[43]=(NY>>8) & 0x03;
2604                 m_cont_reg[34]=SY & 0xFF;
2605                 m_cont_reg[35]=(SY>>8) & 0x03;
2606                 m_cont_reg[38]=DY & 0xFF;
2607                 m_cont_reg[39]=(DY>>8) & 0x03;
2608         }
2609         else {
2610                 m_mmc.SY=SY;
2611                 m_mmc.DY=DY;
2612                 m_mmc.NY=NY;
2613                 m_mmc.ANX=ANX;
2614                 m_mmc.ASX=ASX;
2615                 m_mmc.ADX=ADX;
2616         }
2617 }
2618
2619 /** lmcm_engine() *********************************************/
2620 /** Vram -> CPU                                             **/
2621 /*************************************************************/
2622 void v99x8_device::lmcm_engine()
2623 {
2624         if ((m_stat_reg[2]&0x80)!=0x80) {
2625                 m_stat_reg[7]=m_cont_reg[44]=VDP_POINT(((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0, m_mmc.MXS, m_mmc.ASX, m_mmc.SY);
2626                 m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing);
2627                 m_stat_reg[2]|=0x80;
2628
2629                 if (!--m_mmc.ANX || ((m_mmc.ASX+=m_mmc.TX)&m_mmc.MX)) {
2630                         if (!(--m_mmc.NY & 1023) || (m_mmc.SY+=m_mmc.TY)==-1) {
2631                                 m_stat_reg[2]&=0xFE;
2632                                 m_vdp_engine=NULL;
2633                                 if (!m_mmc.NY)
2634                                         m_mmc.DY+=m_mmc.TY;
2635                                 m_cont_reg[42]=m_mmc.NY & 0xFF;
2636                                 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2637                                 m_cont_reg[34]=m_mmc.SY & 0xFF;
2638                                 m_cont_reg[35]=(m_mmc.SY>>8) & 0x03;
2639                         }
2640                         else {
2641                                 m_mmc.ASX=m_mmc.SX;
2642                                 m_mmc.ANX=m_mmc.NX;
2643                         }
2644                 }
2645         }
2646 }
2647
2648 /** lmmc_engine() *********************************************/
2649 /** CPU -> Vram                                             **/
2650 /*************************************************************/
2651 void v99x8_device::lmmc_engine()
2652 {
2653         if ((m_stat_reg[2]&0x80)!=0x80) {
2654                 UINT8 SM=((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0;
2655
2656                 m_stat_reg[7]=m_cont_reg[44]&=Mask[SM];
2657                 VDP_PSET(SM, m_mmc.MXD, m_mmc.ADX, m_mmc.DY, m_cont_reg[44], m_mmc.LO);
2658                 m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing);
2659                 m_stat_reg[2]|=0x80;
2660
2661                 if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) {
2662                         if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) {
2663                                 m_stat_reg[2]&=0xFE;
2664                                 m_vdp_engine=NULL;
2665                                 if (!m_mmc.NY)
2666                                         m_mmc.DY+=m_mmc.TY;
2667                                 m_cont_reg[42]=m_mmc.NY & 0xFF;
2668                                 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2669                                 m_cont_reg[38]=m_mmc.DY & 0xFF;
2670                                 m_cont_reg[39]=(m_mmc.DY>>8) & 0x03;
2671                         }
2672                         else {
2673                                 m_mmc.ADX=m_mmc.DX;
2674                                 m_mmc.ANX=m_mmc.NX;
2675                         }
2676                 }
2677         }
2678 }
2679
2680 /** hmmv_engine() *********************************************/
2681 /** VDP --> Vram                                            **/
2682 /*************************************************************/
2683 void v99x8_device::hmmv_engine()
2684 {
2685         int DX=m_mmc.DX;
2686         int DY=m_mmc.DY;
2687         int TX=m_mmc.TX;
2688         int TY=m_mmc.TY;
2689         int NX=m_mmc.NX;
2690         int NY=m_mmc.NY;
2691         int ADX=m_mmc.ADX;
2692         int ANX=m_mmc.ANX;
2693         UINT8 CL=m_mmc.CL;
2694         int MXD = m_mmc.MXD;
2695         int cnt;
2696         int delta;
2697
2698         delta = get_vdp_timing_value(hmmv_timing);
2699         cnt = m_vdp_ops_count;
2700
2701         switch (m_mode) {
2702         default:
2703         case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), CL); post__x_y(256)
2704                 break;
2705         case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), CL); post__x_y(512)
2706                 break;
2707         case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), CL); post__x_y(512)
2708                 break;
2709         case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), CL); post__x_y(256)
2710                 break;
2711         }
2712
2713         if ((m_vdp_ops_count=cnt)>0) {
2714                 // Command execution done
2715                 m_stat_reg[2]&=0xFE;
2716                 m_vdp_engine=NULL;
2717                 if (!NY)
2718                         DY+=TY;
2719                 m_cont_reg[42]=NY & 0xFF;
2720                 m_cont_reg[43]=(NY>>8) & 0x03;
2721                 m_cont_reg[38]=DY & 0xFF;
2722                 m_cont_reg[39]=(DY>>8) & 0x03;
2723         }
2724         else {
2725                 m_mmc.DY=DY;
2726                 m_mmc.NY=NY;
2727                 m_mmc.ANX=ANX;
2728                 m_mmc.ADX=ADX;
2729         }
2730 }
2731
2732 /** hmmm_engine() *********************************************/
2733 /** Vram -> Vram                                            **/
2734 /*************************************************************/
2735 void v99x8_device::hmmm_engine()
2736 {
2737         int SX=m_mmc.SX;
2738         int SY=m_mmc.SY;
2739         int DX=m_mmc.DX;
2740         int DY=m_mmc.DY;
2741         int TX=m_mmc.TX;
2742         int TY=m_mmc.TY;
2743         int NX=m_mmc.NX;
2744         int NY=m_mmc.NY;
2745         int ASX=m_mmc.ASX;
2746         int ADX=m_mmc.ADX;
2747         int ANX=m_mmc.ANX;
2748         int MXS = m_mmc.MXS;
2749         int MXD = m_mmc.MXD;
2750         int cnt;
2751         int delta;
2752
2753         delta = get_vdp_timing_value(hmmm_timing);
2754         cnt = m_vdp_ops_count;
2755
2756         switch (m_mode) {
2757         default:
2758         case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP5(MXS, ASX, SY))); post_xxyy(256)
2759                 break;
2760         case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP6(MXS, ASX, SY))); post_xxyy(512)
2761                 break;
2762         case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP7(MXS, ASX, SY))); post_xxyy(512)
2763                 break;
2764         case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP8(MXS, ASX, SY))); post_xxyy(256)
2765                 break;
2766         }
2767
2768         if ((m_vdp_ops_count=cnt)>0) {
2769                 // Command execution done
2770                 m_stat_reg[2]&=0xFE;
2771                 m_vdp_engine=NULL;
2772                 if (!NY) {
2773                         SY+=TY;
2774                         DY+=TY;
2775                 }
2776                 else
2777                         if (SY==-1)
2778                         DY+=TY;
2779                 m_cont_reg[42]=NY & 0xFF;
2780                 m_cont_reg[43]=(NY>>8) & 0x03;
2781                 m_cont_reg[34]=SY & 0xFF;
2782                 m_cont_reg[35]=(SY>>8) & 0x03;
2783                 m_cont_reg[38]=DY & 0xFF;
2784                 m_cont_reg[39]=(DY>>8) & 0x03;
2785         }
2786         else {
2787                 m_mmc.SY=SY;
2788                 m_mmc.DY=DY;
2789                 m_mmc.NY=NY;
2790                 m_mmc.ANX=ANX;
2791                 m_mmc.ASX=ASX;
2792                 m_mmc.ADX=ADX;
2793         }
2794 }
2795
2796 /** ymmm_engine() *********************************************/
2797 /** Vram -> Vram                                            **/
2798 /*************************************************************/
2799
2800 void v99x8_device::ymmm_engine()
2801 {
2802         int SY=m_mmc.SY;
2803         int DX=m_mmc.DX;
2804         int DY=m_mmc.DY;
2805         int TX=m_mmc.TX;
2806         int TY=m_mmc.TY;
2807         int NY=m_mmc.NY;
2808         int ADX=m_mmc.ADX;
2809         int MXD = m_mmc.MXD;
2810         int cnt;
2811         int delta;
2812
2813         delta = get_vdp_timing_value(ymmm_timing);
2814         cnt = m_vdp_ops_count;
2815
2816         switch (m_mode) {
2817         default:
2818         case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP5(MXD, ADX, SY))); post__xyy(256)
2819                 break;
2820         case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP6(MXD, ADX, SY))); post__xyy(512)
2821                 break;
2822         case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP7(MXD, ADX, SY))); post__xyy(512)
2823                 break;
2824         case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP8(MXD, ADX, SY))); post__xyy(256)
2825                 break;
2826         }
2827
2828         if ((m_vdp_ops_count=cnt)>0) {
2829                 // Command execution done
2830                 m_stat_reg[2]&=0xFE;
2831                 m_vdp_engine=NULL;
2832                 if (!NY) {
2833                         SY+=TY;
2834                         DY+=TY;
2835                 }
2836                 else
2837                         if (SY==-1)
2838                         DY+=TY;
2839                 m_cont_reg[42]=NY & 0xFF;
2840                 m_cont_reg[43]=(NY>>8) & 0x03;
2841                 m_cont_reg[34]=SY & 0xFF;
2842                 m_cont_reg[35]=(SY>>8) & 0x03;
2843                 m_cont_reg[38]=DY & 0xFF;
2844                 m_cont_reg[39]=(DY>>8) & 0x03;
2845         }
2846         else {
2847                 m_mmc.SY=SY;
2848                 m_mmc.DY=DY;
2849                 m_mmc.NY=NY;
2850                 m_mmc.ADX=ADX;
2851         }
2852 }
2853
2854 /** hmmc_engine() *********************************************/
2855 /** CPU -> Vram                                             **/
2856 /*************************************************************/
2857 void v99x8_device::hmmc_engine()
2858 {
2859         if ((m_stat_reg[2]&0x80)!=0x80) {
2860                 m_vram_space->write_byte(VDP_VRMP(((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0, m_mmc.MXD, m_mmc.ADX, m_mmc.DY), m_cont_reg[44]);
2861                 m_vdp_ops_count -= get_vdp_timing_value(hmmv_timing);
2862                 m_stat_reg[2]|=0x80;
2863
2864                 if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) {
2865                         if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) {
2866                                 m_stat_reg[2]&=0xFE;
2867                                 m_vdp_engine=NULL;
2868                                 if (!m_mmc.NY)
2869                                         m_mmc.DY+=m_mmc.TY;
2870                                 m_cont_reg[42]=m_mmc.NY & 0xFF;
2871                                 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2872                                 m_cont_reg[38]=m_mmc.DY & 0xFF;
2873                                 m_cont_reg[39]=(m_mmc.DY>>8) & 0x03;
2874                         }
2875                         else {
2876                                 m_mmc.ADX=m_mmc.DX;
2877                                 m_mmc.ANX=m_mmc.NX;
2878                         }
2879                 }
2880         }
2881 }
2882
2883 /** VDPWrite() ***********************************************/
2884 /** Use this function to transfer pixel(s) from CPU to m_ **/
2885 /*************************************************************/
2886 void v99x8_device::cpu_to_vdp(UINT8 V)
2887 {
2888         m_stat_reg[2]&=0x7F;
2889         m_stat_reg[7]=m_cont_reg[44]=V;
2890         if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
2891 }
2892
2893 /** VDPRead() ************************************************/
2894 /** Use this function to transfer pixel(s) from VDP to CPU. **/
2895 /*************************************************************/
2896 UINT8 v99x8_device::vdp_to_cpu()
2897 {
2898         m_stat_reg[2]&=0x7F;
2899         if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
2900         return(m_cont_reg[44]);
2901 }
2902
2903 /** report_vdp_command() ***************************************/
2904 /** Report VDP Command to be executed                       **/
2905 /*************************************************************/
2906 void v99x8_device::report_vdp_command(UINT8 Op)
2907 {
2908         static const char *const Ops[16] =
2909         {
2910                 "SET ","AND ","OR  ","XOR ","NOT ","NOP ","NOP ","NOP ",
2911                 "TSET","TAND","TOR ","TXOR","TNOT","NOP ","NOP ","NOP "
2912         };
2913         static const char *const Commands[16] =
2914         {
2915                 " ABRT"," ????"," ????"," ????","POINT"," PSET"," SRCH"," LINE",
2916                 " LMMV"," LMMM"," LMCM"," LMMC"," HMMV"," HMMM"," YMMM"," HMMC"
2917         };
2918
2919         UINT8 CL, CM, LO;
2920         int SX,SY, DX,DY, NX,NY;
2921
2922         // Fetch arguments
2923         CL = m_cont_reg[44];
2924         SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511;
2925         SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023;
2926         DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511;
2927         DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023;
2928         NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023;
2929         NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023;
2930         CM = Op>>4;
2931         LO = Op&0x0F;
2932
2933         LOG(("V9938: Opcode %02Xh %s-%s (%d,%d)->(%d,%d),%d [%d,%d]%s\n",
2934                 Op, Commands[CM], Ops[LO],
2935                 SX,SY, DX,DY, CL, m_cont_reg[45]&0x04? -NX:NX,
2936                 m_cont_reg[45]&0x08? -NY:NY,
2937                 m_cont_reg[45]&0x70? " on ExtVRAM":""
2938                 ));
2939 }
2940
2941 /** VDPDraw() ************************************************/
2942 /** Perform a given V9938 operation Op.                     **/
2943 /*************************************************************/
2944 UINT8 v99x8_device::command_unit_w(UINT8 Op)
2945 {
2946         int SM;
2947
2948         // V9938 ops only work in SCREENs 5-8
2949         if (m_mode<5)
2950                 return(0);
2951
2952         SM = m_mode-5;         // Screen mode index 0..3
2953
2954         m_mmc.CM = Op>>4;
2955         if ((m_mmc.CM & 0x0C) != 0x0C && m_mmc.CM != 0)
2956                 // Dot operation: use only relevant bits of color
2957         m_stat_reg[7]=(m_cont_reg[44]&=Mask[SM]);
2958
2959         //  if(Verbose&0x02)
2960         report_vdp_command(Op);
2961
2962         switch(Op>>4) {
2963         case CM_ABRT:
2964                 m_stat_reg[2]&=0xFE;
2965                 m_vdp_engine=NULL;
2966                 return 1;
2967         case CM_POINT:
2968                 m_stat_reg[2]&=0xFE;
2969                 m_vdp_engine=NULL;
2970                 m_stat_reg[7]=m_cont_reg[44]=
2971                 VDP_POINT(SM, (m_cont_reg[45] & 0x10) != 0,
2972                         m_cont_reg[32]+((int)m_cont_reg[33]<<8),
2973                         m_cont_reg[34]+((int)m_cont_reg[35]<<8));
2974                 return 1;
2975         case CM_PSET:
2976                 m_stat_reg[2]&=0xFE;
2977                 m_vdp_engine=NULL;
2978                 VDP_PSET(SM, (m_cont_reg[45] & 0x20) != 0,
2979                         m_cont_reg[36]+((int)m_cont_reg[37]<<8),
2980                         m_cont_reg[38]+((int)m_cont_reg[39]<<8),
2981                         m_cont_reg[44],
2982                         Op&0x0F);
2983                 return 1;
2984         case CM_SRCH:
2985                 m_vdp_engine=&v99x8_device::srch_engine;
2986                 break;
2987         case CM_LINE:
2988                 m_vdp_engine=&v99x8_device::line_engine;
2989                 break;
2990         case CM_LMMV:
2991                 m_vdp_engine=&v99x8_device::lmmv_engine;
2992                 break;
2993         case CM_LMMM:
2994                 m_vdp_engine=&v99x8_device::lmmm_engine;
2995                 break;
2996         case CM_LMCM:
2997                 m_vdp_engine=&v99x8_device::lmcm_engine;
2998                 break;
2999         case CM_LMMC:
3000                 m_vdp_engine=&v99x8_device::lmmc_engine;
3001                 break;
3002         case CM_HMMV:
3003                 m_vdp_engine=&v99x8_device::hmmv_engine;
3004                 break;
3005         case CM_HMMM:
3006                 m_vdp_engine=&v99x8_device::hmmm_engine;
3007                 break;
3008         case CM_YMMM:
3009                 m_vdp_engine=&v99x8_device::ymmm_engine;
3010                 break;
3011         case CM_HMMC:
3012                 m_vdp_engine=&v99x8_device::hmmc_engine;
3013                 break;
3014         default:
3015                 LOG(("V9938: Unrecognized opcode %02Xh\n",Op));
3016                 return(0);
3017         }
3018
3019         // Fetch unconditional arguments
3020         m_mmc.SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511;
3021         m_mmc.SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023;
3022         m_mmc.DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511;
3023         m_mmc.DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023;
3024         m_mmc.NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023;
3025         m_mmc.TY = m_cont_reg[45]&0x08? -1:1;
3026         m_mmc.MX = PPL[SM];
3027         m_mmc.CL = m_cont_reg[44];
3028         m_mmc.LO = Op&0x0F;
3029         m_mmc.MXS = (m_cont_reg[45] & 0x10) != 0;
3030         m_mmc.MXD = (m_cont_reg[45] & 0x20) != 0;
3031
3032         // Argument depends on UINT8 or dot operation
3033         if ((m_mmc.CM & 0x0C) == 0x0C) {
3034                 m_mmc.TX = m_cont_reg[45]&0x04? -PPB[SM]:PPB[SM];
3035                 m_mmc.NX = ((m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023)/PPB[SM];
3036         }
3037         else {
3038                 m_mmc.TX = m_cont_reg[45]&0x04? -1:1;
3039                 m_mmc.NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023;
3040         }
3041
3042         // X loop variables are treated specially for LINE command
3043         if (m_mmc.CM == CM_LINE) {
3044                 m_mmc.ASX=((m_mmc.NX-1)>>1);
3045                 m_mmc.ADX=0;
3046         }
3047         else {
3048                 m_mmc.ASX = m_mmc.SX;
3049                 m_mmc.ADX = m_mmc.DX;
3050         }
3051
3052         // NX loop variable is treated specially for SRCH command
3053         if (m_mmc.CM == CM_SRCH)
3054                 m_mmc.ANX=(m_cont_reg[45]&0x02)!=0; // Do we look for "==" or "!="?
3055         else
3056                 m_mmc.ANX = m_mmc.NX;
3057
3058         // Command execution started
3059         m_stat_reg[2]|=0x01;
3060
3061         // Start execution if we still have time slices
3062         if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
3063
3064         // Operation successfully initiated
3065         return(1);
3066 }
3067
3068 /** LoopVDP() ************************************************
3069 Run X steps of active VDP command
3070 *************************************************************/
3071 void v99x8_device::update_command()
3072 {
3073         if(m_vdp_ops_count<=0)
3074         {
3075                 m_vdp_ops_count+=13662;
3076                 if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
3077         }
3078         else
3079         {
3080                 m_vdp_ops_count=13662;
3081                 if(m_vdp_engine) (this->*m_vdp_engine)();
3082         }
3083 }
3084
3085 /*static MACHINE_CONFIG_FRAGMENT( v9938 )
3086         MCFG_PALETTE_ADD("palette", 512)
3087         MCFG_PALETTE_INIT_OWNER(v9938_device, v9938)
3088 MACHINE_CONFIG_END*/
3089
3090 //-------------------------------------------------
3091 //  machine_config_additions - return a pointer to
3092 //  the device's machine fragment
3093 //-------------------------------------------------
3094
3095 /*machine_config_constructor v9938_device::device_mconfig_additions() const
3096 {
3097         return MACHINE_CONFIG_NAME( v9938 );
3098 }*/
3099
3100 /*static MACHINE_CONFIG_FRAGMENT( v9958 )
3101         MCFG_PALETTE_ADD("palette", 19780)
3102         MCFG_PALETTE_INIT_OWNER(v9958_device, v9958)
3103 MACHINE_CONFIG_END*/
3104
3105 //-------------------------------------------------
3106 //  machine_config_additions - return a pointer to
3107 //  the device's machine fragment
3108 //-------------------------------------------------
3109
3110 /*machine_config_constructor v9958_device::device_mconfig_additions() const
3111 {
3112         return MACHINE_CONFIG_NAME( v9958 );
3113 }*/
3114
3115
3116
3117 /* for common source code project */
3118 void v99x8_device::draw_screen()
3119 {
3120         if(emu->now_waiting_in_debugger) {
3121                 // store regs
3122 //              int tmp_offset_x = m_offset_x;
3123                 int tmp_offset_y = m_offset_y;
3124                 int tmp_visible_y = m_visible_y;
3125                 UINT8 tmp_stat_reg[10];
3126                 memcpy(tmp_stat_reg, m_stat_reg, sizeof(m_stat_reg));
3127                 UINT8 tmp_int_state = m_int_state;
3128                 int tmp_scanline = m_scanline;
3129                 int tmp_blink = m_blink;
3130                 int tmp_blink_count = m_blink_count;
3131                 UINT16 tmp_pal_ind16[16];
3132                 UINT16 tmp_pal_ind256[256];
3133                 memcpy(tmp_pal_ind16, m_pal_ind16, sizeof(m_pal_ind16));
3134                 memcpy(tmp_pal_ind256, m_pal_ind256, sizeof(m_pal_ind256));
3135 //              mmc_t tmp_mmc = m_mmc;
3136                 int tmp_vdp_ops_count = m_vdp_ops_count;
3137                 int tmp_scanline_start = m_scanline_start;
3138                 int tmp_scanline_max = m_scanline_max;
3139                 
3140                 // drive vlines
3141                 for(int v = /*get_cur_vline() + 1*/0; v < get_lines_per_frame(); v++) {
3142                         event_vline(v, 0);
3143                 }
3144                 
3145                 // restore regs
3146 //              m_offset_x = tmp_offset_x;
3147                 m_offset_y = tmp_offset_y;
3148                 m_visible_y = tmp_visible_y;
3149                 memcpy(m_stat_reg, tmp_stat_reg, sizeof(m_stat_reg));
3150                 m_int_state = tmp_int_state;
3151                 m_scanline = tmp_scanline;
3152                 m_blink = tmp_blink;
3153                 m_blink_count = tmp_blink_count;
3154                 memcpy(m_pal_ind16, tmp_pal_ind16, sizeof(m_pal_ind16));
3155                 memcpy(m_pal_ind256, tmp_pal_ind256, sizeof(m_pal_ind256));
3156 //              m_mmc = tmp_mmc;
3157                 m_vdp_ops_count = tmp_vdp_ops_count;
3158                 m_scanline_start = tmp_scanline_start;
3159                 m_scanline_max = tmp_scanline_max;
3160         }
3161         
3162         scrntype_t *dst;
3163         int y;
3164         if(osd == NULL) return;
3165         emu->set_vm_screen_lines(__SCREEN_HEIGHT);
3166         for(y=0; y< __SCREEN_HEIGHT; y++) {
3167                 if((dst = osd->get_vm_screen_buffer(y)) != NULL) {
3168                         my_memcpy(dst, screen+(y+18)*_V9938_LONG_WIDTH+2, __SCREEN_WIDTH*sizeof(scrntype_t));
3169                 }
3170         }
3171 }
3172
3173 void v99x8_device::initialize()
3174 {
3175         DEVICE::initialize();
3176         __SCREEN_WIDTH = osd->get_feature_int_value(_T("SCREEN_WIDTH"));
3177         __SCREEN_HEIGHT = osd->get_feature_int_value(_T("SCREEN_HEIGHT"));
3178         if(__SCREEN_WIDTH <= 0) __SCREEN_WIDTH = 256;
3179         if(__SCREEN_HEIGHT <= 0) __SCREEN_HEIGHT = 192;
3180         
3181         device_start();
3182         register_vline_event(this);
3183 }
3184
3185 void v99x8_device::reset()
3186 {
3187         device_reset();
3188 }
3189
3190 void v99x8_device::event_vline(int v, int clock)
3191 {
3192         m_stat_reg[2] ^= 0x20;
3193         device_timer(v);
3194 }
3195
3196 void v99x8_device::write_signal(int id, uint32_t data, uint32_t mask)
3197 {
3198         if(id == SIG_VDP_COMMAND_COMPLETION) {
3199                 while(1) {
3200                         int i;
3201                         i = m_vdp_ops_count = 13662;
3202                         if(m_vdp_engine) (this->*m_vdp_engine)();
3203                         if (i == m_vdp_ops_count) break;
3204                 }
3205         }
3206 }
3207
3208 #define STATE_VERSION   2
3209
3210 bool v99x8_device::process_state(FILEIO* state_fio, bool loading)
3211 {
3212         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
3213                 return false;
3214         }
3215         if(!state_fio->StateCheckInt32(this_device_id)) {
3216                 return false;
3217         }
3218         save_load_state(state_fio, !loading);
3219         return true;
3220 }
3221
3222 void v99x8_device::save_load_state(FILEIO* state_fio, bool is_save)
3223 {
3224 #define STATE_ENTRY(x) {&(x), sizeof(x)}
3225         typedef struct {
3226                 void *address;
3227                 size_t size;
3228         } t_state_table;
3229         t_state_table state_table[] = {
3230                 STATE_ENTRY(m_offset_x),
3231                 STATE_ENTRY(m_offset_y),
3232                 STATE_ENTRY(m_visible_y),
3233                 STATE_ENTRY(m_mode),
3234                 STATE_ENTRY(m_pal_write_first),
3235                 STATE_ENTRY(m_cmd_write_first),
3236                 STATE_ENTRY(m_pal_write),
3237                 STATE_ENTRY(m_cmd_write),
3238                 STATE_ENTRY(m_pal_reg),
3239                 STATE_ENTRY(m_stat_reg),
3240                 STATE_ENTRY(m_cont_reg),
3241                 STATE_ENTRY(m_read_ahead),
3242                 STATE_ENTRY(m_int_state),
3243                 STATE_ENTRY(m_scanline),
3244                 STATE_ENTRY(m_blink),
3245                 STATE_ENTRY(m_blink_count),
3246                 STATE_ENTRY(m_mx_delta),
3247                 STATE_ENTRY(m_my_delta),
3248                 STATE_ENTRY(m_button_state),
3249                 STATE_ENTRY(m_pal_ind16),
3250                 STATE_ENTRY(m_pal_ind256),
3251                 STATE_ENTRY(m_mmc),
3252                 STATE_ENTRY(m_vdp_ops_count),
3253                 STATE_ENTRY(m_pal_ntsc),
3254                 STATE_ENTRY(m_scanline_start),
3255                 STATE_ENTRY(m_vblank_start),
3256                 STATE_ENTRY(m_scanline_max),
3257                 STATE_ENTRY(m_height),
3258                 STATE_ENTRY(m_v9958_sp_mode),
3259                 STATE_ENTRY(m_address_latch),
3260                 STATE_ENTRY(vram),
3261                 { NULL, 0 }
3262         };
3263         int i;
3264         for(i=0; state_table[i].size>0; i++) {
3265                 if (is_save) {
3266                         state_fio->Fwrite(state_table[i].address, state_table[i].size, 1);
3267                 }
3268                 else {
3269                         state_fio->Fread(state_table[i].address, state_table[i].size, 1);
3270                 }
3271         }
3272         return;
3273 }
3274
3275 /*
3276         Common Source Code Project
3277         MSX Series (experimental)
3278
3279         Origin : mame0172s.zip
3280                 mame.zip\src\devices\video\v9938.cpp
3281         modified by umaiboux
3282         Date   : 2016.04.xx-
3283
3284         [ V99x8 ]
3285 */