OSDN Git Service

[VM] Add vm_template.h . This class, VM_TEMPLATE:: must be mother of VM:: .See fm7...
[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 //      m_int_callback(n);
855         write_signals(&outputs_irq, n ? 0xffffffff : 0);
856 }
857
858 /***************************************************************************
859
860     Register functions
861
862 ***************************************************************************/
863
864 void v99x8_device::register_write (int reg, int data)
865 {
866         static UINT8 const reg_mask[] =
867         {
868                 0x7e, 0x7b, 0x7f, 0xff, 0x3f, 0xff, 0x3f, 0xff,
869                 0xfb, 0xbf, 0x07, 0x03, 0xff, 0xff, 0x07, 0x0f,
870                 0x0f, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
871                 0x00, 0x7f, 0x3f, 0x07
872         };
873
874         if (reg <= 27)
875         {
876                 data &= reg_mask[reg];
877                 if (m_cont_reg[reg] == data)
878                         return;
879         }
880
881         if (reg > 46)
882         {
883                 LOG(("V9938: Attempted to write to non-existant R#%d\n", reg));
884                 return;
885         }
886
887         /*update_command ();*/
888
889         switch (reg) {
890                 // registers that affect interrupt and display mode
891         case 0:
892         case 1:
893                 m_cont_reg[reg] = data;
894                 set_mode();
895                 check_int();
896                 LOG(("v9938: mode = %s\n", v9938_modes[m_mode]));
897                 break;
898
899         case 18:
900         case 9:
901                 m_cont_reg[reg] = data;
902                 // recalc offset
903                 m_offset_x = 8 + position_offset(m_cont_reg[18] & 0x0f);
904                 // Y offset is only applied once per frame?
905                 break;
906
907         case 15:
908                 m_pal_write_first = 0;
909                 break;
910
911                 // color burst registers aren't emulated
912         case 20:
913         case 21:
914         case 22:
915                 LOG(("v9938: Write %02xh to R#%d; color burst not emulated\n", data, reg));
916                 break;
917         case 25:
918         case 26:
919         case 27:
920                 if (m_model != MODEL_V9958)
921                 {
922                         LOG(("v9938: Attempting to write %02xh to V9958 R#%d\n", data, reg));
923                         data = 0;
924                 }
925                 else
926                 {
927                         if(reg == 25)
928                                 m_v9958_sp_mode = data & 0x18;
929                 }
930                 break;
931
932         case 44:
933                 cpu_to_vdp (data);
934                 break;
935
936         case 46:
937                 command_unit_w (data);
938                 break;
939         }
940
941         if (reg != 15)
942                 LOG(("v9938: Write %02x to R#%d\n", data, reg));
943
944         m_cont_reg[reg] = data;
945 }
946
947 /***************************************************************************
948
949 Refresh / render function
950
951 ***************************************************************************/
952
953 inline bool v99x8_device::v9938_second_field()
954 {
955         return !(((m_cont_reg[9] & 0x04) && !(m_stat_reg[2] & 2)) || m_blink);
956 }
957
958
959 void v99x8_device::default_border(const scrntype_t *pens, scrntype_t *ln)
960 {
961         scrntype_t pen;
962         int i;
963
964         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
965         i = _V9938_LONG_WIDTH;
966         while (i--) *ln++ = pen;
967 }
968
969 void v99x8_device::graphic7_border(const scrntype_t *pens, scrntype_t *ln)
970 {
971         scrntype_t pen;
972         int i;
973
974         pen = pens[m_pal_ind256[m_cont_reg[7]]];
975         i = _V9938_LONG_WIDTH;
976         while (i--) *ln++ = pen;
977 }
978
979 void v99x8_device::graphic5_border(const scrntype_t *pens, scrntype_t *ln)
980 {
981         int i;
982         scrntype_t pen0;
983         scrntype_t pen1;
984
985         pen1 = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
986         pen0 = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
987         i = _V9938_LONG_WIDTH / 2;
988         while (i--) { *ln++ = pen0; *ln++ = pen1; }
989 }
990
991 void v99x8_device::mode_text1(const scrntype_t *pens, scrntype_t *ln, int line)
992 {
993         int pattern, x, xx, name, xxx;
994         scrntype_t fg, bg, pen;
995         int nametbl_addr, patterntbl_addr;
996
997         patterntbl_addr = m_cont_reg[4] << 11;
998         nametbl_addr = m_cont_reg[2] << 10;
999
1000         fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1001         bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1002
1003         name = (line/8)*40;
1004
1005         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1006
1007         xxx = (m_offset_x + 8) * 2;
1008         while (xxx--) *ln++ = pen;
1009
1010         for (x=0;x<40;x++)
1011         {
1012                 pattern = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) +
1013                         ((line + m_cont_reg[23]) & 7));
1014                 for (xx=0;xx<6;xx++)
1015                 {
1016                         *ln++ = (pattern & 0x80) ? fg : bg;
1017                         *ln++ = (pattern & 0x80) ? fg : bg;
1018                         pattern <<= 1;
1019                 }
1020                 /* width height 212, characters start repeating at the bottom */
1021                 name = (name + 1) & 0x3ff;
1022         }
1023
1024         xxx = ((16 - m_offset_x) + 8) * 2;
1025         while (xxx--) *ln++ = pen;
1026 }
1027
1028 void v99x8_device::mode_text2(const scrntype_t *pens, scrntype_t *ln, int line)
1029 {
1030         int pattern, x, charcode, name, xxx, patternmask, colourmask;
1031         scrntype_t fg, bg, fg0, bg0, pen;
1032         int nametbl_addr, patterntbl_addr, colourtbl_addr;
1033
1034         patterntbl_addr = m_cont_reg[4] << 11;
1035         colourtbl_addr =  ((m_cont_reg[3] & 0xf8) << 6) + (m_cont_reg[10] << 14);
1036         #if 0
1037         colourmask = ((m_cont_reg[3] & 7) << 5) | 0x1f; /* cause a bug in Forth+ v1.0 on Geneve */
1038         #else
1039         colourmask = ((m_cont_reg[3] & 7) << 6) | 0x3f; /* verify! */
1040         #endif
1041         nametbl_addr = ((m_cont_reg[2] & 0xfc) << 10);
1042         patternmask = ((m_cont_reg[2] & 3) << 10) | 0x3ff; /* seems correct */
1043
1044         fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1045         bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1046         fg0 = pens[m_pal_ind16[m_cont_reg[12] >> 4]];
1047         bg0 = pens[m_pal_ind16[m_cont_reg[12] & 15]];
1048
1049         name = (line/8)*80;
1050
1051         xxx = (m_offset_x + 8) * 2;
1052         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1053         while (xxx--) *ln++ = pen;
1054
1055         for (x=0;x<80;x++)
1056         {
1057                 charcode = m_vram_space->read_byte(nametbl_addr + (name&patternmask));
1058                 if (m_blink)
1059                 {
1060                         pattern = m_vram_space->read_byte(colourtbl_addr + ((name/8)&colourmask));
1061                         if (pattern & (0x80 >> (name & 7) ) )
1062                         {
1063                                 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) +
1064                                         ((line + m_cont_reg[23]) & 7)));
1065
1066                                 *ln++ = (pattern & 0x80) ? fg0 : bg0;
1067                                 *ln++ = (pattern & 0x40) ? fg0 : bg0;
1068                                 *ln++ = (pattern & 0x20) ? fg0 : bg0;
1069                                 *ln++ = (pattern & 0x10) ? fg0 : bg0;
1070                                 *ln++ = (pattern & 0x08) ? fg0 : bg0;
1071                                 *ln++ = (pattern & 0x04) ? fg0 : bg0;
1072
1073                                 name++;
1074                                 continue;
1075                         }
1076                 }
1077
1078                 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) +
1079                         ((line + m_cont_reg[23]) & 7)));
1080
1081                 *ln++ = (pattern & 0x80) ? fg : bg;
1082                 *ln++ = (pattern & 0x40) ? fg : bg;
1083                 *ln++ = (pattern & 0x20) ? fg : bg;
1084                 *ln++ = (pattern & 0x10) ? fg : bg;
1085                 *ln++ = (pattern & 0x08) ? fg : bg;
1086                 *ln++ = (pattern & 0x04) ? fg : bg;
1087
1088                 name++;
1089         }
1090
1091         xxx = (16 - m_offset_x + 8) * 2;
1092         while (xxx--) *ln++ = pen;
1093 }
1094
1095 void v99x8_device::mode_multi(const scrntype_t *pens, scrntype_t *ln, int line)
1096 {
1097         int nametbl_addr, patterntbl_addr, colour;
1098         int name, line2, x, xx;
1099         scrntype_t pen, pen_bg;
1100
1101         nametbl_addr = (m_cont_reg[2] << 10);
1102         patterntbl_addr = (m_cont_reg[4] << 11);
1103
1104         line2 = (line - m_cont_reg[23]) & 255;
1105         name = (line2/8)*32;
1106
1107         pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1108         xx = m_offset_x * 2;
1109         while (xx--) *ln++ = pen_bg;
1110
1111         for (x=0;x<32;x++)
1112         {
1113                 colour = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) + ((line2/4)&7));
1114                 pen = pens[m_pal_ind16[colour>>4]];
1115                 /* eight pixels */
1116                 *ln++ = pen;
1117                 *ln++ = pen;
1118                 *ln++ = pen;
1119                 *ln++ = pen;
1120                 *ln++ = pen;
1121                 *ln++ = pen;
1122                 *ln++ = pen;
1123                 *ln++ = pen;
1124                 pen = pens[m_pal_ind16[colour&15]];
1125                 /* eight pixels */
1126                 *ln++ = pen;
1127                 *ln++ = pen;
1128                 *ln++ = pen;
1129                 *ln++ = pen;
1130                 *ln++ = pen;
1131                 *ln++ = pen;
1132                 *ln++ = pen;
1133                 *ln++ = pen;
1134                 name++;
1135         }
1136
1137         xx = (16 - m_offset_x) * 2;
1138         while (xx--) *ln++ = pen_bg;
1139 }
1140
1141 void v99x8_device::mode_graphic1(const scrntype_t *pens, scrntype_t *ln, int line)
1142 {
1143         scrntype_t fg, bg, pen;
1144         int nametbl_addr, patterntbl_addr, colourtbl_addr;
1145         int pattern, x, xx, line2, name, charcode, colour, xxx;
1146
1147         nametbl_addr = (m_cont_reg[2] << 10);
1148         colourtbl_addr = (m_cont_reg[3] << 6) + (m_cont_reg[10] << 14);
1149         patterntbl_addr = (m_cont_reg[4] << 11);
1150
1151         line2 = (line - m_cont_reg[23]) & 255;
1152
1153         name = (line2/8)*32;
1154
1155         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1156         xxx = m_offset_x * 2;
1157         while (xxx--) *ln++ = pen;
1158
1159         for (x=0;x<32;x++)
1160         {
1161                 charcode = m_vram_space->read_byte(nametbl_addr + name);
1162                 colour = m_vram_space->read_byte(colourtbl_addr + charcode/8);
1163                 fg = pens[m_pal_ind16[colour>>4]];
1164                 bg = pens[m_pal_ind16[colour&15]];
1165                 pattern = m_vram_space->read_byte(patterntbl_addr + (charcode * 8 + (line2 & 7)));
1166
1167                 for (xx=0;xx<8;xx++)
1168                 {
1169                         *ln++ = (pattern & 0x80) ? fg : bg;
1170                         *ln++ = (pattern & 0x80) ? fg : bg;
1171                         pattern <<= 1;
1172                 }
1173                 name++;
1174         }
1175
1176         xx = (16 - m_offset_x) * 2;
1177         while (xx--) *ln++ = pen;
1178 }
1179
1180 void v99x8_device::mode_graphic23(const scrntype_t *pens, scrntype_t *ln, int line)
1181 {
1182         scrntype_t fg, bg, pen;
1183         int nametbl_addr, patterntbl_addr, colourtbl_addr;
1184         int pattern, x, xx, line2, name, charcode,
1185         colour, colourmask, patternmask, xxx;
1186
1187         colourmask = ((m_cont_reg[3] & 0x7f) * 8) | 7;
1188         patternmask = ((m_cont_reg[4] & 0x03) * 256) | 0xff;
1189
1190         nametbl_addr =  (m_cont_reg[2] << 10);
1191         colourtbl_addr =  ((m_cont_reg[3] & 0x80) << 6) + (m_cont_reg[10] << 14);
1192         patterntbl_addr = ((m_cont_reg[4] & 0x3c) << 11);
1193
1194         line2 = (line + m_cont_reg[23]) & 255;
1195         name = (line2/8)*32;
1196
1197         pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1198         xxx = m_offset_x * 2;
1199         while (xxx--) *ln++ = pen;
1200
1201         for (x=0;x<32;x++)
1202         {
1203                 charcode = m_vram_space->read_byte(nametbl_addr + name) + (line2&0xc0)*4;
1204                 colour = m_vram_space->read_byte(colourtbl_addr + ((charcode&colourmask)*8+(line2&7)));
1205                 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode&patternmask)*8+(line2&7)));
1206                 fg = pens[m_pal_ind16[colour>>4]];
1207                 bg = pens[m_pal_ind16[colour&15]];
1208                 for (xx=0;xx<8;xx++)
1209                 {
1210                         *ln++ = (pattern & 0x80) ? fg : bg;
1211                         *ln++ = (pattern & 0x80) ? fg : bg;
1212                         pattern <<= 1;
1213                 }
1214                 name++;
1215         }
1216
1217         xx = (16 - m_offset_x) * 2;
1218         while (xx--) *ln++ = pen;
1219 }
1220
1221 void v99x8_device::mode_graphic4(const scrntype_t *pens, scrntype_t *ln, int line)
1222 {
1223         int nametbl_addr, colour;
1224         int line2, linemask, x, xx;
1225         scrntype_t pen, pen_bg;
1226
1227         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1228
1229         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1230
1231         nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128;
1232         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1233                 nametbl_addr += 0x8000;
1234
1235         pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1236         xx = m_offset_x * 2;
1237         while (xx--) *ln++ = pen_bg;
1238
1239         for (x=0;x<128;x++)
1240         {
1241                 colour = m_vram_space->read_byte(nametbl_addr++);
1242                 pen = pens[m_pal_ind16[colour>>4]];
1243                 *ln++ = pen;
1244                 *ln++ = pen;
1245                 pen = pens[m_pal_ind16[colour&15]];
1246                 *ln++ = pen;
1247                 *ln++ = pen;
1248         }
1249
1250         xx = (16 - m_offset_x) * 2;
1251         while (xx--) *ln++ = pen_bg;
1252 }
1253
1254 void v99x8_device::mode_graphic5(const scrntype_t *pens, scrntype_t *ln, int line)
1255 {
1256         int nametbl_addr, colour;
1257         int line2, linemask, x, xx;
1258         scrntype_t pen_bg0[4];
1259         scrntype_t pen_bg1[4];
1260
1261         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1262
1263         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1264
1265         nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128;
1266         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1267                 nametbl_addr += 0x8000;
1268
1269         pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
1270         pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
1271
1272         xx = m_offset_x;
1273         while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
1274
1275         x = (m_cont_reg[8] & 0x20) ? 0 : 1;
1276
1277         for (;x<4;x++)
1278         {
1279                 pen_bg0[x] = pens[m_pal_ind16[x]];
1280                 pen_bg1[x] = pens[m_pal_ind16[x]];
1281         }
1282
1283         for (x=0;x<128;x++)
1284         {
1285                 colour = m_vram_space->read_byte(nametbl_addr++);
1286
1287                 *ln++ = pen_bg0[colour>>6];
1288                 *ln++ = pen_bg1[(colour>>4)&3];
1289                 *ln++ = pen_bg0[(colour>>2)&3];
1290                 *ln++ = pen_bg1[(colour&3)];
1291         }
1292
1293         pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
1294         pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
1295         xx = 16 - m_offset_x;
1296         while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
1297 }
1298
1299 void v99x8_device::mode_graphic6(const scrntype_t *pens, scrntype_t *ln, int line)
1300 {
1301         UINT8 colour;
1302         int line2, linemask, x, xx, nametbl_addr;
1303         scrntype_t pen_bg, fg0;
1304         scrntype_t fg1;
1305
1306         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1307
1308         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1309
1310         nametbl_addr = line2 << 8 ;
1311         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1312                 nametbl_addr += 0x10000;
1313
1314         pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1315         xx = m_offset_x * 2;
1316         while (xx--) *ln++ = pen_bg;
1317
1318         if (m_cont_reg[2] & 0x40)
1319         {
1320                 for (x=0;x<32;x++)
1321                 {
1322                         nametbl_addr++;
1323                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1324                         fg0 = pens[m_pal_ind16[colour>>4]];
1325                         fg1 = pens[m_pal_ind16[colour&15]];
1326                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1327                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1328                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1329                         *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1330                         nametbl_addr += 7;
1331                 }
1332         }
1333         else
1334         {
1335                 for (x=0;x<256;x++)
1336                 {
1337                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1338                         *ln++ = pens[m_pal_ind16[colour>>4]];
1339                         *ln++ = pens[m_pal_ind16[colour&15]];
1340                         nametbl_addr++;
1341                 }
1342         }
1343
1344         xx = (16 - m_offset_x) * 2;
1345         while (xx--) *ln++ = pen_bg;
1346 }
1347
1348 void v99x8_device::mode_graphic7(const scrntype_t *pens, scrntype_t *ln, int line)
1349 {
1350         UINT8 colour;
1351         int line2, linemask, x, xx, nametbl_addr;
1352         scrntype_t pen, pen_bg;
1353
1354         linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1355
1356         line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1357
1358         nametbl_addr = line2 << 8;
1359         if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1360                 nametbl_addr += 0x10000;
1361
1362         pen_bg = pens[m_pal_ind256[m_cont_reg[7]]];
1363         xx = m_offset_x * 2;
1364         while (xx--) *ln++ = pen_bg;
1365
1366         if ((m_v9958_sp_mode & 0x18) == 0x08) // v9958 screen 12, puzzle star title screen
1367         {
1368                 for (x=0;x<64;x++)
1369                 {
1370                         int colour[4];
1371                         int ind;
1372
1373                         colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1374                         nametbl_addr++;
1375                         colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1376                         nametbl_addr++;
1377                         colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1378                         nametbl_addr++;
1379                         colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1380
1381                         ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 |
1382                         (colour[2] & 7) << 5 | (colour[3] & 7) << 8;
1383
1384                         *ln++ = pens[s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]];
1385                         *ln++ = pens[s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]];
1386
1387                         *ln++ = pens[s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]];
1388                         *ln++ = pens[s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]];
1389
1390                         *ln++ = pens[s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]];
1391                         *ln++ = pens[s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]];
1392
1393                         *ln++ = pens[s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]];
1394                         *ln++ = pens[s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]];
1395
1396                         nametbl_addr++;
1397                 }
1398         }
1399         else if ((m_v9958_sp_mode & 0x18) == 0x18) // v9958 screen 10/11, puzzle star & sexy boom gameplay
1400         {
1401                 for (x=0;x<64;x++)
1402                 {
1403                         int colour[4];
1404                         int ind;
1405
1406                         colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1407                         nametbl_addr++;
1408                         colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1409                         nametbl_addr++;
1410                         colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1411                         nametbl_addr++;
1412                         colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1413
1414                         ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 |
1415                         (colour[2] & 7) << 5 | (colour[3] & 7) << 8;
1416
1417                         *ln++ = pens[colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]];
1418                         *ln++ = pens[colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]];
1419
1420                         *ln++ = pens[colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]];
1421                         *ln++ = pens[colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]];
1422
1423                         *ln++ = pens[colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]];
1424                         *ln++ = pens[colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]];
1425
1426                         *ln++ = pens[colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]];
1427                         *ln++ = pens[colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]];
1428
1429                         nametbl_addr++;
1430                 }
1431         }
1432         else if (m_cont_reg[2] & 0x40)
1433         {
1434                 for (x=0;x<32;x++)
1435                 {
1436                         nametbl_addr++;
1437                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1438                         pen = pens[m_pal_ind256[colour]];
1439                         *ln++ = pen; *ln++ = pen;
1440                         *ln++ = pen; *ln++ = pen;
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                         nametbl_addr++;
1448                 }
1449         }
1450         else
1451         {
1452                 for (x=0;x<256;x++)
1453                 {
1454                         colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1455                         pen = pens[m_pal_ind256[colour]];
1456                         *ln++ = pen;
1457                         *ln++ = pen;
1458                         nametbl_addr++;
1459                 }
1460         }
1461
1462         xx = (16 - m_offset_x) * 2;
1463         while (xx--) *ln++ = pen_bg;
1464 }
1465
1466 void v99x8_device::mode_unknown(const scrntype_t *pens, scrntype_t *ln, int line)
1467 {
1468         scrntype_t fg, bg;
1469         int x;
1470
1471         fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1472         bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1473
1474         x = m_offset_x * 2;
1475         while (x--) *ln++ = bg;
1476
1477         x = 512;
1478         while (x--) *ln++ = fg;
1479
1480         x = (16 - m_offset_x) * 2;
1481         while (x--) *ln++ = bg;
1482 }
1483
1484 void v99x8_device::default_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1485 {
1486         int i;
1487         ln += m_offset_x * 2;
1488
1489         for (i=0;i<256;i++)
1490         {
1491                 if (col[i] & 0x80)
1492                 {
1493                         *ln++ = pens[m_pal_ind16[col[i]&0x0f]];
1494                         *ln++ = pens[m_pal_ind16[col[i]&0x0f]];
1495                 }
1496                 else
1497                 {
1498                         ln += 2;
1499                 }
1500         }
1501 }
1502
1503 void v99x8_device::graphic5_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1504 {
1505         int i;
1506         ln += m_offset_x * 2;
1507
1508         for (i=0;i<256;i++)
1509         {
1510                 if (col[i] & 0x80)
1511                 {
1512                         *ln++ = pens[m_pal_ind16[(col[i]>>2)&0x03]];
1513                         *ln++ = pens[m_pal_ind16[col[i]&0x03]];
1514                 }
1515                 else
1516                 {
1517                         ln += 2;
1518                 }
1519         }
1520 }
1521
1522
1523 void v99x8_device::graphic7_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1524 {
1525         static const UINT16 g7_ind16[16] = {
1526                 0, 2, 192, 194, 48, 50, 240, 242,
1527         482, 7, 448, 455, 56, 63, 504, 511  };
1528         int i;
1529
1530         ln += m_offset_x * 2;
1531
1532         for (i=0;i<256;i++)
1533         {
1534                 if (col[i] & 0x80)
1535                 {
1536                         *ln++ = pens[g7_ind16[col[i]&0x0f]];
1537                         *ln++ = pens[g7_ind16[col[i]&0x0f]];
1538                 }
1539                 else
1540                 {
1541                         ln += 2;
1542                 }
1543         }
1544 }
1545
1546
1547 void v99x8_device::sprite_mode1 (int line, UINT8 *col)
1548 {
1549         int attrtbl_addr, patterntbl_addr, pattern_addr;
1550         int x, y, p, height, c, p2, i, n, pattern;
1551
1552         memset(col, 0, 256);
1553
1554         // are sprites disabled?
1555         if (m_cont_reg[8] & 0x02) return;
1556
1557         attrtbl_addr = (m_cont_reg[5] << 7) + (m_cont_reg[11] << 15);
1558         patterntbl_addr = (m_cont_reg[6] << 11);
1559
1560         // 16x16 or 8x8 sprites
1561         height = (m_cont_reg[1] & 2) ? 16 : 8;
1562         // magnified sprites (zoomed)
1563         if (m_cont_reg[1] & 1) height *= 2;
1564
1565         p2 = p = 0;
1566         while (1)
1567         {
1568                 y = m_vram_space->read_byte(attrtbl_addr);
1569                 if (y == 208) break;
1570                 y = (y - m_cont_reg[23]) & 255;
1571                 if (y > 208)
1572                         y = -(~y&255);
1573                 else
1574                         y++;
1575
1576                 // if sprite in range, has to be drawn
1577                 if ( (line >= y) && (line  < (y + height) ) )
1578                 {
1579                         if (p2 == 4)
1580                         {
1581                                 // max maximum sprites per line!
1582                                 if ( !(m_stat_reg[0] & 0x40) )
1583                                         m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p;
1584
1585                                 break;
1586                         }
1587                         // get x
1588                         x = m_vram_space->read_byte(attrtbl_addr + 1);
1589                         if (m_vram_space->read_byte(attrtbl_addr + 3) & 0x80) x -= 32;
1590
1591                         // get pattern
1592                         pattern = m_vram_space->read_byte(attrtbl_addr + 2);
1593                         if (m_cont_reg[1] & 2)
1594                                 pattern &= 0xfc;
1595                         n = line - y;
1596                         pattern_addr = patterntbl_addr + pattern * 8 + ((m_cont_reg[1] & 1) ? n/2  : n);
1597                         pattern = (m_vram_space->read_byte(pattern_addr) << 8) | m_vram_space->read_byte(pattern_addr+16);
1598
1599                         // get colour
1600                         c = m_vram_space->read_byte(attrtbl_addr + 3) & 0x0f;
1601
1602                         // draw left part
1603                         n = 0;
1604                         while (1)
1605                         {
1606                                 if (n == 0) pattern = m_vram_space->read_byte(pattern_addr);
1607                                 else if ( (n == 1) && (m_cont_reg[1] & 2) ) pattern = m_vram_space->read_byte(pattern_addr + 16);
1608                                 else break;
1609
1610                                 n++;
1611
1612                                 for (i=0;i<8;i++)
1613                                 {
1614                                         if (pattern & 0x80)
1615                                         {
1616                                                 if ( (x >= 0) && (x < 256) )
1617                                                 {
1618                                                         if (col[x] & 0x40)
1619                                                         {
1620                                                                 // we have a collision!
1621                                                                 if (p2 < 4)
1622                                                                         m_stat_reg[0] |= 0x20;
1623                                                         }
1624                                                         if ( !(col[x] & 0x80) )
1625                                                         {
1626                                                                 if (c || (m_cont_reg[8] & 0x20) )
1627                                                                         col[x] |= 0xc0 | c;
1628                                                                 else
1629                                                                         col[x] |= 0x40;
1630                                                         }
1631
1632                                                         // if zoomed, draw another pixel
1633                                                         if (m_cont_reg[1] & 1)
1634                                                         {
1635                                                                 if (col[x+1] & 0x40)
1636                                                                 {
1637                                                                         // we have a collision!
1638                                                                         if (p2 < 4)
1639                                                                                 m_stat_reg[0] |= 0x20;
1640                                                                 }
1641                                                                 if ( !(col[x+1] & 0x80) )
1642                                                                 {
1643                                                                         if (c || (m_cont_reg[8] & 0x20) )
1644                                                                                 col[x+1] |= 0xc0 | c;
1645                                                                         else
1646                                                                                 col[x+1] |= 0x80;
1647                                                                 }
1648                                                         }
1649                                                 }
1650                                         }
1651                                         if (m_cont_reg[1] & 1) x += 2; else x++;
1652                                         pattern <<= 1;
1653                                 }
1654                         }
1655
1656                         p2++;
1657                 }
1658
1659                 if (p >= 31) break;
1660                 p++;
1661                 attrtbl_addr += 4;
1662         }
1663
1664         if ( !(m_stat_reg[0] & 0x40) )
1665                 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p;
1666 }
1667
1668 void v99x8_device::sprite_mode2 (int line, UINT8 *col)
1669 {
1670         int attrtbl_addr, patterntbl_addr, pattern_addr, colourtbl_addr;
1671         int x, i, y, p, height, c, p2, n, pattern, colourmask, first_cc_seen;
1672
1673         memset(col, 0, 256);
1674
1675         // are sprites disabled?
1676         if (m_cont_reg[8] & 0x02) return;
1677
1678         attrtbl_addr = ( (m_cont_reg[5] & 0xfc) << 7) + (m_cont_reg[11] << 15);
1679         colourtbl_addr =  ( (m_cont_reg[5] & 0xf8) << 7) + (m_cont_reg[11] << 15);
1680         patterntbl_addr = (m_cont_reg[6] << 11);
1681         colourmask = ( (m_cont_reg[5] & 3) << 3) | 0x7; // check this!
1682
1683         // 16x16 or 8x8 sprites
1684         height = (m_cont_reg[1] & 2) ? 16 : 8;
1685         // magnified sprites (zoomed)
1686         if (m_cont_reg[1] & 1) height *= 2;
1687
1688         p2 = p = first_cc_seen = 0;
1689         while (1)
1690         {
1691                 y = vram_read(attrtbl_addr);
1692                 if (y == 216) break;
1693                 y = (y - m_cont_reg[23]) & 255;
1694                 if (y > 216)
1695                         y = -(~y&255);
1696                 else
1697                         y++;
1698
1699                 // if sprite in range, has to be drawn
1700                 if ( (line >= y) && (line  < (y + height) ) )
1701                 {
1702                         if (p2 == 8)
1703                         {
1704                                 // max maximum sprites per line!
1705                                 if ( !(m_stat_reg[0] & 0x40) )
1706                                         m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p;
1707
1708                                 break;
1709                         }
1710
1711                         n = line - y; if (m_cont_reg[1] & 1) n /= 2;
1712                         // get colour
1713                         c = vram_read(colourtbl_addr + (((p&colourmask)*16) + n));
1714
1715                         // don't draw all sprite with CC set before any sprites
1716                         // with CC = 0 are seen on this line
1717                         if (c & 0x40)
1718                         {
1719                                 if (!first_cc_seen)
1720                                         goto skip_first_cc_set;
1721                         }
1722                         else
1723                                 first_cc_seen = 1;
1724
1725                         // get pattern
1726                         pattern = vram_read(attrtbl_addr + 2);
1727                         if (m_cont_reg[1] & 2)
1728                                 pattern &= 0xfc;
1729                         pattern_addr = patterntbl_addr + pattern * 8 + n;
1730                         pattern = (vram_read(pattern_addr) << 8) | vram_read(pattern_addr + 16);
1731
1732                         // get x
1733                         x = vram_read(attrtbl_addr + 1);
1734                         if (c & 0x80) x -= 32;
1735
1736                         n = (m_cont_reg[1] & 2) ? 16 : 8;
1737                         while (n--)
1738                         {
1739                                 for (i=0;i<=(m_cont_reg[1] & 1);i++)
1740                                 {
1741                                         if ( (x >= 0) && (x < 256) )
1742                                         {
1743                                                 if ( (pattern & 0x8000) && !(col[x] & 0x10) )
1744                                                 {
1745                                                         if ( (c & 15) || (m_cont_reg[8] & 0x20) )
1746                                                         {
1747                                                                 if ( !(c & 0x40) )
1748                                                                 {
1749                                                                         if (col[x] & 0x20) col[x] |= 0x10;
1750                                                                         else
1751                                                                                 col[x] |= 0x20 | (c & 15);
1752                                                                 }
1753                                                                 else
1754                                                                         col[x] |= c & 15;
1755
1756                                                                 col[x] |= 0x80;
1757                                                         }
1758                                                 }
1759                                                 else
1760                                                 {
1761                                                         if ( !(c & 0x40) && (col[x] & 0x20) )
1762                                                                 col[x] |= 0x10;
1763                                                 }
1764
1765                                                 if ( !(c & 0x60) && (pattern & 0x8000) )
1766                                                 {
1767                                                         if (col[x] & 0x40)
1768                                                         {
1769                                                                 // sprite collision!
1770                                                                 if (p2 < 8)
1771                                                                         m_stat_reg[0] |= 0x20;
1772                                                         }
1773                                                         else
1774                                                                 col[x] |= 0x40;
1775                                                 }
1776
1777                                                 x++;
1778                                         }
1779                                 }
1780
1781                                 pattern <<= 1;
1782                         }
1783
1784                 skip_first_cc_set:
1785                         p2++;
1786                 }
1787
1788                 if (p >= 31) break;
1789                 p++;
1790                 attrtbl_addr += 4;
1791         }
1792
1793         if ( !(m_stat_reg[0] & 0x40) )
1794                 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p;
1795 }
1796
1797
1798 const v99x8_device::v99x8_mode v99x8_device::s_modes[] = {
1799         { 0x02,
1800                 &v99x8_device::mode_text1,
1801                 &v99x8_device::default_border,
1802                 NULL,
1803                 NULL
1804         },
1805         { 0x01,
1806                 &v99x8_device::mode_multi,
1807                 &v99x8_device::default_border,
1808                 &v99x8_device::sprite_mode1,
1809                 &v99x8_device::default_draw_sprite
1810         },
1811         { 0x00,
1812                 &v99x8_device::mode_graphic1,
1813                 &v99x8_device::default_border,
1814                 &v99x8_device::sprite_mode1,
1815                 &v99x8_device::default_draw_sprite
1816         },
1817         { 0x04,
1818                 &v99x8_device::mode_graphic23,
1819                 &v99x8_device::default_border,
1820                 &v99x8_device::sprite_mode1,
1821                 &v99x8_device::default_draw_sprite
1822         },
1823         { 0x08,
1824                 &v99x8_device::mode_graphic23,
1825                 &v99x8_device::default_border,
1826                 &v99x8_device::sprite_mode2,
1827                 &v99x8_device::default_draw_sprite
1828         },
1829         { 0x0c,
1830                 &v99x8_device::mode_graphic4,
1831                 &v99x8_device::default_border,
1832                 &v99x8_device::sprite_mode2,
1833                 &v99x8_device::default_draw_sprite
1834         },
1835         { 0x10,
1836                 &v99x8_device::mode_graphic5,
1837                 &v99x8_device::graphic5_border,
1838                 &v99x8_device::sprite_mode2,
1839                 &v99x8_device::graphic5_draw_sprite
1840         },
1841         { 0x14,
1842                 &v99x8_device::mode_graphic6,
1843                 &v99x8_device::default_border,
1844                 &v99x8_device::sprite_mode2,
1845                 &v99x8_device::default_draw_sprite
1846         },
1847         { 0x1c,
1848                 &v99x8_device::mode_graphic7,
1849                 &v99x8_device::graphic7_border,
1850                 &v99x8_device::sprite_mode2,
1851                 &v99x8_device::graphic7_draw_sprite
1852         },
1853         { 0x0a,
1854                 &v99x8_device::mode_text2,
1855                 &v99x8_device::default_border,
1856                 NULL,
1857                 NULL
1858         },
1859         { 0xff,
1860                 &v99x8_device::mode_unknown,
1861                 &v99x8_device::default_border,
1862                 NULL,
1863                 NULL
1864         }
1865 };
1866
1867 void v99x8_device::set_mode()
1868 {
1869         int n,i;
1870
1871         n = (((m_cont_reg[0] & 0x0e) << 1) | ((m_cont_reg[1] & 0x18) >> 3));
1872         for (i=0;;i++)
1873         {
1874                 if ( (s_modes[i].m == n) || (s_modes[i].m == 0xff) ) break;
1875         }
1876         m_mode = i;
1877 }
1878
1879 void v99x8_device::refresh_16(int line)
1880 {
1881         //const pen_t *pens = m_palette->pens();
1882         const scrntype_t *pens = this->pens;
1883         bool double_lines = false;
1884         UINT8 col[256];
1885         scrntype_t *ln, *ln2 = NULL;
1886
1887         if (m_cont_reg[9] & 0x08)
1888         {
1889 //              ln = &m_bitmap.pix16(m_scanline*2+((m_stat_reg[2]>>1)&1));
1890                 ln = screen+(m_scanline*2+((m_stat_reg[2]>>1)&1))*_V9938_LONG_WIDTH;
1891         }
1892         else
1893         {
1894 //              ln = &m_bitmap.pix16(m_scanline*2);
1895 //              ln2 = &m_bitmap.pix16(m_scanline*2+1);
1896                 ln = screen+(m_scanline*2)*_V9938_LONG_WIDTH;
1897                 ln2 = screen+(m_scanline*2+1)*_V9938_LONG_WIDTH;
1898                 double_lines = true;
1899         }
1900
1901         if ( !(m_cont_reg[1] & 0x40) || (m_stat_reg[2] & 0x40) )
1902         {
1903                 (this->*s_modes[m_mode].border_16)(pens, ln);
1904         }
1905         else
1906         {
1907                 (this->*s_modes[m_mode].visible_16)(pens, ln, line);
1908                 if (s_modes[m_mode].sprites)
1909                 {
1910                         (this->*s_modes[m_mode].sprites)(line, col);
1911                         (this->*s_modes[m_mode].draw_sprite_16)(pens, ln, col);
1912                 }
1913         }
1914
1915         if (double_lines)
1916                 my_memcpy(ln2, ln, (512 + 32) * sizeof(scrntype_t));
1917 }
1918
1919 void v99x8_device::refresh_line(int line)
1920 {
1921         int ind16, ind256;
1922
1923         ind16 = m_pal_ind16[0];
1924         ind256 = m_pal_ind256[0];
1925
1926         if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) )
1927         {
1928                 m_pal_ind16[0] = m_pal_ind16[(m_cont_reg[7] & 0x0f)];
1929                 m_pal_ind256[0] = m_pal_ind256[m_cont_reg[7]];
1930         }
1931
1932         refresh_16 (line);
1933
1934         if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) )
1935         {
1936                 m_pal_ind16[0] = ind16;
1937                 m_pal_ind256[0] = ind256;
1938         }
1939 }
1940
1941 /*
1942
1943 From: awulms@inter.nl.net (Alex Wulms)
1944 *** About the HR/VR topic: this is how it works according to me:
1945
1946 *** HR:
1947 HR is very straightforward:
1948 -HR=1 during 'display time'
1949 -HR=0 during 'horizontal border, horizontal retrace'
1950 I have put 'display time' and 'horizontal border, horizontal retrace' between
1951 quotes because HR does not only flip between 0 and 1 during the display of
1952 the 192/212 display lines, but also during the vertical border and during the
1953 vertical retrace.
1954
1955 *** VR:
1956 VR is a little bit tricky
1957 -VR always gets set to 0 when the VDP starts with display line 0
1958 -VR gets set to 1 when the VDP reaches display line (192 if LN=0) or (212 if
1959 LN=1)
1960 -The VDP displays contents of VRAM as long as VR=0
1961
1962 As a consequence of this behaviour, it is possible to program the famous
1963 overscan trick, where VRAM contents is shown in the borders:
1964 Generate an interrupt at line 230 (or so) and on this interrupt: set LN=1
1965 Generate an interrupt at line 200 (or so) and on this interrupt: set LN=0
1966 Repeat the above two steps
1967
1968 *** The top/bottom border contents during overscan:
1969 On screen 0:
1970 1) The VDP keeps increasing the name table address pointer during bottom
1971 border, vertical retrace and top border
1972 2) The VDP resets the name table address pointer when the first display line
1973 is reached
1974
1975 On the other screens:
1976 1) The VDP keeps increasing the name table address pointer during the bottom
1977 border
1978 2) The VDP resets the name table address pointer such that the top border
1979 contents connects up with the first display line. E.g., when the top border
1980 is 26 lines high, the VDP will take:
1981 'logical'      vram line
1982 TOPB000  256-26
1983 ...
1984 TOPB025  256-01
1985 DISPL000 000
1986 ...
1987 DISPL211 211
1988 BOTB000  212
1989 ...
1990 BOTB024  236
1991
1992
1993
1994 *** About the horizontal interrupt
1995
1996 All relevant definitions on a row:
1997 -FH: Bit 0 of status register 1
1998 -IE1: Bit 4 of mode register 0
1999 -IL: Line number in mode register 19
2000 -DL: The line that the VDP is going to display (corrected for vertical scroll)
2001 -IRQ: Interrupt request line of VDP to Z80
2002
2003 At the *start* of every new line (display, bottom border, part of vertical
2004 display), the VDP does:
2005 -FH = (FH && IE1) || (IL==DL)
2006
2007 After reading of status register 1 by the CPU, the VDP does:
2008 -FH = 0
2009
2010 Furthermore, the following is true all the time:
2011 -IRQ = FH && IE1
2012
2013 The resulting behaviour:
2014 When IE1=0:
2015 -FH will be set as soon as display of line IL starts
2016 -FH will be reset as soon as status register 1 is read
2017 -FH will be reset as soon as the next display line is reached
2018
2019 When IE=1:
2020 -FH and IRQ will be set as soon as display line IL is reached
2021 -FH and IRQ will be reset as soon as status register 1 is read
2022
2023 Another subtile result:
2024 If, while FH and IRQ are set, IE1 gets reset, the next happens:
2025 -IRQ is reset immediately (since IRQ is always FH && IE1)
2026 -FH will be reset as soon as display of the next line starts (unless the next
2027 line is line IL)
2028
2029
2030 *** About the vertical interrupt:
2031 Another relevant definition:
2032 -FV: Bit 7 of status register 0
2033 -IE0: Bit 5 of mode register 1
2034
2035 I only know for sure the behaviour when IE0=1:
2036 -FV and IRQ will be set as soon as VR changes from 0 to 1
2037 -FV and IRQ will be reset as soon as status register 0 is read
2038
2039 A consequence is that NO vertical interrupts will be generated during the
2040 overscan trick, described in the VR section above.
2041
2042 I do not know the behaviour of FV when IE0=0. That is the part that I still
2043 have to test.
2044 */
2045
2046 void v99x8_device::interrupt_start_vblank()
2047 {
2048         #if 0
2049         if (machine.input().code_pressed (KEYCODE_D) )
2050         {
2051                 for (i=0;i<24;i++) osd_printf_debug ("R#%d = %02x\n", i, m_cont_reg[i]);
2052         }
2053         #endif
2054
2055         // at every frame, vdp switches fields
2056         m_stat_reg[2] = (m_stat_reg[2] & 0xfd) | (~m_stat_reg[2] & 2);
2057
2058         // color blinking
2059         if (!(m_cont_reg[13] & 0xf0))
2060                 m_blink = 0;
2061         else if (!(m_cont_reg[13] & 0x0f))
2062                 m_blink = 1;
2063         else
2064         {
2065                 // both on and off counter are non-zero: timed blinking
2066                 if (m_blink_count)
2067                         m_blink_count--;
2068                 if (!m_blink_count)
2069                 {
2070                         m_blink = !m_blink;
2071                         if (m_blink)
2072                                 m_blink_count = (m_cont_reg[13] >> 4) * 10;
2073                         else
2074                                 m_blink_count = (m_cont_reg[13] & 0x0f) * 10;
2075                 }
2076         }
2077 }
2078
2079 /***************************************************************************
2080
2081 Command unit
2082
2083 ***************************************************************************/
2084
2085 /*************************************************************/
2086 /** Completely rewritten by Alex Wulms:                     **/
2087 /**  - VDP Command execution 'in parallel' with CPU         **/
2088 /**  - Corrected behaviour of VDP commands                  **/
2089 /**  - Made it easier to implement correct S7/8 mapping     **/
2090 /**    by concentrating VRAM access in one single place     **/
2091 /**  - Made use of the 'in parallel' VDP command exec       **/
2092 /**    and correct timing. You must call the function       **/
2093 /**    LoopVDP() from LoopZ80 in MSX.c. You must call it    **/
2094 /**    exactly 256 times per screen refresh.                **/
2095 /** Started on       : 11-11-1999                           **/
2096 /** Beta release 1 on:  9-12-1999                           **/
2097 /** Beta release 2 on: 20-01-2000                           **/
2098 /**  - Corrected behaviour of VRM <-> Z80 transfer          **/
2099 /**  - Improved performance of the code                     **/
2100 /** Public release 1.0: 20-04-2000                          **/
2101 /*************************************************************/
2102
2103 #define VDP_VRMP5(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&255)>>1)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&255)>>1)))
2104 #define VDP_VRMP6(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2)))
2105 //#define VDP_VRMP7(MX, X, Y) ((!MX) ? (((Y&511)<<8) + ((X&511)>>1)) : (EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1)))
2106 #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))*/)
2107 //#define VDP_VRMP8(MX, X, Y) ((!MX) ? (((Y&511)<<8) + (X&255)) : (EXPMEM_OFFSET + ((Y&255)<<8) + (X&255)))
2108 #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))*/)
2109
2110 #define VDP_VRMP(M, MX, X, Y) VDPVRMP(M, MX, X, Y)
2111 #define VDP_POINT(M, MX, X, Y) VDPpoint(M, MX, X, Y)
2112 #define VDP_PSET(M, MX, X, Y, C, O) VDPpset(M, MX, X, Y, C, O)
2113
2114 #define CM_ABRT  0x0
2115 #define CM_POINT 0x4
2116 #define CM_PSET  0x5
2117 #define CM_SRCH  0x6
2118 #define CM_LINE  0x7
2119 #define CM_LMMV  0x8
2120 #define CM_LMMM  0x9
2121 #define CM_LMCM  0xA
2122 #define CM_LMMC  0xB
2123 #define CM_HMMV  0xC
2124 #define CM_HMMM  0xD
2125 #define CM_YMMM  0xE
2126 #define CM_HMMC  0xF
2127
2128 /*************************************************************
2129 Many VDP commands are executed in some kind of loop but
2130 essentially, there are only a few basic loop structures
2131 that are re-used. We define the loop structures that are
2132 re-used here so that they have to be entered only once
2133 *************************************************************/
2134 #define pre_loop \
2135 while ((cnt-=delta) > 0) {
2136         #define post_loop \
2137 }
2138
2139 // Loop over DX, DY
2140 #define post__x_y(MX) \
2141 if (!--ANX || ((ADX+=TX)&MX)) { \
2142         if (!(--NY&1023) || (DY+=TY)==-1) \
2143                 break; \
2144         else { \
2145                 ADX=DX; \
2146                 ANX=NX; \
2147         } \
2148 } \
2149 post_loop
2150
2151 // Loop over DX, SY, DY
2152 #define post__xyy(MX) \
2153 if ((ADX+=TX)&MX) { \
2154         if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
2155                 break; \
2156         else \
2157                 ADX=DX; \
2158 } \
2159 post_loop
2160
2161 // Loop over SX, DX, SY, DY
2162 #define post_xxyy(MX) \
2163 if (!--ANX || ((ASX+=TX)&MX) || ((ADX+=TX)&MX)) { \
2164         if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
2165                 break; \
2166         else { \
2167                 ASX=SX; \
2168                 ADX=DX; \
2169                 ANX=NX; \
2170         } \
2171 } \
2172 post_loop
2173
2174 /*************************************************************/
2175 /** Variables visible only in this module                   **/
2176 /*************************************************************/
2177 static const UINT8 Mask[4] = { 0x0F,0x03,0x0F,0xFF };
2178 static const int  PPB[4]  = { 2,4,2,1 };
2179 static const int  PPL[4]  = { 256,512,512,256 };
2180
2181 //  SprOn SprOn SprOf SprOf
2182 //  ScrOf ScrOn ScrOf ScrOn
2183 static const int srch_timing[8]={
2184         818, 1025,  818,  830, // ntsc
2185         696,  854,  696,  684  // pal
2186 };
2187 static const int line_timing[8]={
2188         1063, 1259, 1063, 1161,
2189         904,  1026, 904,  953
2190 };
2191 static const int hmmv_timing[8]={
2192         439,  549,  439,  531,
2193         366,  439,  366,  427
2194 };
2195 static const int lmmv_timing[8]={
2196         873,  1135, 873, 1056,
2197         732,  909,  732,  854
2198 };
2199 static const int ymmm_timing[8]={
2200         586,  952,  586,  610,
2201         488,  720,  488,  500
2202 };
2203 static const int hmmm_timing[8]={
2204         818,  1111, 818,  854,
2205         684,  879,  684,  708
2206 };
2207 static const int lmmm_timing[8]={
2208         1160, 1599, 1160, 1172,
2209         964,  1257, 964,  977
2210 };
2211
2212 /** VDPVRMP() **********************************************/
2213 /** Calculate addr of a pixel in vram                       **/
2214 /*************************************************************/
2215 inline int v99x8_device::VDPVRMP(UINT8 M,int MX,int X,int Y)
2216 {
2217         switch(M)
2218         {
2219         case 0: return VDP_VRMP5(MX,X,Y);
2220         case 1: return VDP_VRMP6(MX,X,Y);
2221         case 2: return VDP_VRMP7(MX,X,Y);
2222         case 3: return VDP_VRMP8(MX,X,Y);
2223         }
2224
2225         return 0;
2226 }
2227
2228 /** VDPpoint5() ***********************************************/
2229 /** Get a pixel on screen 5                                 **/
2230 /*************************************************************/
2231 inline UINT8 v99x8_device::VDPpoint5(int MXS, int SX, int SY)
2232 {
2233         return (m_vram_space->read_byte(VDP_VRMP5(MXS, SX, SY)) >>
2234                 (((~SX)&1)<<2)
2235                 )&15;
2236 }
2237
2238 /** VDPpoint6() ***********************************************/
2239 /** Get a pixel on screen 6                                 **/
2240 /*************************************************************/
2241 inline UINT8 v99x8_device::VDPpoint6(int MXS, int SX, int SY)
2242 {
2243         return (m_vram_space->read_byte(VDP_VRMP6(MXS, SX, SY)) >>
2244                 (((~SX)&3)<<1)
2245                 )&3;
2246 }
2247
2248 /** VDPpoint7() ***********************************************/
2249 /** Get a pixel on screen 7                                 **/
2250 /*************************************************************/
2251 inline UINT8 v99x8_device::VDPpoint7(int MXS, int SX, int SY)
2252 {
2253         return (m_vram_space->read_byte(VDP_VRMP7(MXS, SX, SY)) >>
2254                 (((~SX)&1)<<2)
2255                 )&15;
2256 }
2257
2258 /** VDPpoint8() ***********************************************/
2259 /** Get a pixel on screen 8                                 **/
2260 /*************************************************************/
2261 inline UINT8 v99x8_device::VDPpoint8(int MXS, int SX, int SY)
2262 {
2263         return m_vram_space->read_byte(VDP_VRMP8(MXS, SX, SY));
2264 }
2265
2266 /** VDPpoint() ************************************************/
2267 /** Get a pixel on a screen                                 **/
2268 /*************************************************************/
2269 inline UINT8 v99x8_device::VDPpoint(UINT8 SM, int MXS, int SX, int SY)
2270 {
2271         switch(SM)
2272         {
2273         case 0: return VDPpoint5(MXS,SX,SY);
2274         case 1: return VDPpoint6(MXS,SX,SY);
2275         case 2: return VDPpoint7(MXS,SX,SY);
2276         case 3: return VDPpoint8(MXS,SX,SY);
2277         }
2278
2279         return(0);
2280 }
2281
2282 /** VDPpsetlowlevel() ****************************************/
2283 /** Low level function to set a pixel on a screen           **/
2284 /** Make it inline to make it fast                          **/
2285 /*************************************************************/
2286 inline void v99x8_device::VDPpsetlowlevel(int addr, UINT8 CL, UINT8 M, UINT8 OP)
2287 {
2288         // If this turns out to be too slow, get a pointer to the address space
2289         // and work directly on it.
2290         UINT8 val = m_vram_space->read_byte(addr);
2291         switch (OP)
2292         {
2293         case 0: val = (val & M) | CL; break;
2294         case 1: val = val & (CL | M); break;
2295         case 2: val |= CL; break;
2296         case 3: val ^= CL; break;
2297         case 4: val = (val & M) | ~(CL | M); break;
2298         case 8: if (CL) val = (val & M) | CL; break;
2299         case 9: if (CL) val = val & (CL | M); break;
2300         case 10: if (CL) val |= CL; break;
2301         case 11:  if (CL) val ^= CL; break;
2302         case 12:  if (CL) val = (val & M) | ~(CL|M); break;
2303         default:
2304                 LOG(("v9938: invalid operation %d in pset\n", OP));
2305         }
2306
2307         m_vram_space->write_byte(addr, val);
2308 }
2309
2310 /** VDPpset5() ***********************************************/
2311 /** Set a pixel on screen 5                                 **/
2312 /*************************************************************/
2313 inline void v99x8_device::VDPpset5(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2314 {
2315         UINT8 SH = ((~DX)&1)<<2;
2316         VDPpsetlowlevel(VDP_VRMP5(MXD, DX, DY), CL << SH, ~(15<<SH), OP);
2317 }
2318
2319 /** VDPpset6() ***********************************************/
2320 /** Set a pixel on screen 6                                 **/
2321 /*************************************************************/
2322 inline void v99x8_device::VDPpset6(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2323 {
2324         UINT8 SH = ((~DX)&3)<<1;
2325
2326         VDPpsetlowlevel(VDP_VRMP6(MXD, DX, DY), CL << SH, ~(3<<SH), OP);
2327 }
2328
2329 /** VDPpset7() ***********************************************/
2330 /** Set a pixel on screen 7                                 **/
2331 /*************************************************************/
2332 inline void v99x8_device::VDPpset7(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2333 {
2334         UINT8 SH = ((~DX)&1)<<2;
2335
2336         VDPpsetlowlevel(VDP_VRMP7(MXD, DX, DY), CL << SH, ~(15<<SH), OP);
2337 }
2338
2339 /** VDPpset8() ***********************************************/
2340 /** Set a pixel on screen 8                                 **/
2341 /*************************************************************/
2342 inline void v99x8_device::VDPpset8(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2343 {
2344         VDPpsetlowlevel(VDP_VRMP8(MXD, DX, DY), CL, 0, OP);
2345 }
2346
2347 /** VDPpset() ************************************************/
2348 /** Set a pixel on a screen                                 **/
2349 /*************************************************************/
2350 inline void v99x8_device::VDPpset(UINT8 SM, int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2351 {
2352         switch (SM) {
2353         case 0: VDPpset5(MXD, DX, DY, CL, OP); break;
2354         case 1: VDPpset6(MXD, DX, DY, CL, OP); break;
2355         case 2: VDPpset7(MXD, DX, DY, CL, OP); break;
2356         case 3: VDPpset8(MXD, DX, DY, CL, OP); break;
2357         }
2358 }
2359
2360 /** get_vdp_timing_value() **************************************/
2361 /** Get timing value for a certain VDP command              **/
2362 /*************************************************************/
2363 int v99x8_device::get_vdp_timing_value(const int *timing_values)
2364 {
2365         return(timing_values[((m_cont_reg[1]>>6)&1)|(m_cont_reg[8]&2)|((m_cont_reg[9]<<1)&4)]);
2366 }
2367
2368 /** SrchEgine()** ********************************************/
2369 /** Search a dot                                            **/
2370 /*************************************************************/
2371 void v99x8_device::srch_engine()
2372 {
2373         int SX=m_mmc.SX;
2374         int SY=m_mmc.SY;
2375         int TX=m_mmc.TX;
2376         int ANX=m_mmc.ANX;
2377         UINT8 CL=m_mmc.CL;
2378         int MXD = m_mmc.MXD;
2379         int cnt;
2380         int delta;
2381
2382         delta = get_vdp_timing_value(srch_timing);
2383         cnt = m_vdp_ops_count;
2384
2385         #define post_srch(MX) \
2386         { m_stat_reg[2]|=0x10; /* Border detected */ break; } \
2387         if ((SX+=TX) & MX) { m_stat_reg[2] &= 0xEF; /* Border not detected */ break; }
2388         switch (m_mode) {
2389         default:
2390         case V9938_MODE_GRAPHIC4: pre_loop if ((VDPpoint5(MXD, SX, SY)==CL) ^ANX)  post_srch(256) post_loop
2391                         break;
2392         case V9938_MODE_GRAPHIC5: pre_loop if ((VDPpoint6(MXD, SX, SY)==CL) ^ANX)  post_srch(512) post_loop
2393                         break;
2394         case V9938_MODE_GRAPHIC6: pre_loop if ((VDPpoint7(MXD, SX, SY)==CL) ^ANX)  post_srch(512) post_loop
2395                         break;
2396         case V9938_MODE_GRAPHIC7: pre_loop if ((VDPpoint8(MXD, SX, SY)==CL) ^ANX)  post_srch(256) post_loop
2397                         break;
2398         }
2399
2400         if ((m_vdp_ops_count=cnt)>0) {
2401                 // Command execution done
2402                 m_stat_reg[2] &= 0xFE;
2403                 m_vdp_engine = NULL;
2404                 // Update SX in VDP registers
2405                 m_stat_reg[8] = SX & 0xFF;
2406                 m_stat_reg[9] = (SX>>8) | 0xFE;
2407         }
2408         else {
2409                 m_mmc.SX=SX;
2410         }
2411 }
2412
2413 /** LineEgine()** ********************************************/
2414 /** Draw a line                                             **/
2415 /*************************************************************/
2416 void v99x8_device::line_engine()
2417 {
2418         int DX=m_mmc.DX;
2419         int DY=m_mmc.DY;
2420         int TX=m_mmc.TX;
2421         int TY=m_mmc.TY;
2422         int NX=m_mmc.NX;
2423         int NY=m_mmc.NY;
2424         int ASX=m_mmc.ASX;
2425         int ADX=m_mmc.ADX;
2426         UINT8 CL=m_mmc.CL;
2427         UINT8 LO=m_mmc.LO;
2428         int MXD = m_mmc.MXD;
2429         int cnt;
2430         int delta;
2431
2432         delta = get_vdp_timing_value(line_timing);
2433         cnt = m_vdp_ops_count;
2434
2435         #define post_linexmaj(MX) \
2436         DX+=TX; \
2437         if ((ASX-=NY)<0) { \
2438                 ASX+=NX; \
2439                 DY+=TY; \
2440         } \
2441         ASX&=1023; /* Mask to 10 bits range */\
2442         if (ADX++==NX || (DX&MX)) \
2443                 break; \
2444         post_loop
2445
2446         #define post_lineymaj(MX) \
2447         DY+=TY; \
2448         if ((ASX-=NY)<0) { \
2449                 ASX+=NX; \
2450                 DX+=TX; \
2451         } \
2452         ASX&=1023; /* Mask to 10 bits range */\
2453         if (ADX++==NX || (DX&MX)) \
2454                 break; \
2455         post_loop
2456
2457         if ((m_cont_reg[45]&0x01)==0)
2458                 // X-Axis is major direction
2459         switch (m_mode) {
2460         default:
2461         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_linexmaj(256)
2462                 break;
2463         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_linexmaj(512)
2464                 break;
2465         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_linexmaj(512)
2466                 break;
2467         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_linexmaj(256)
2468                 break;
2469         }
2470         else
2471                 // Y-Axis is major direction
2472         switch (m_mode) {
2473         default:
2474         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_lineymaj(256)
2475                 break;
2476         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_lineymaj(512)
2477                 break;
2478         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_lineymaj(512)
2479                 break;
2480         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_lineymaj(256)
2481                 break;
2482         }
2483
2484         if ((m_vdp_ops_count=cnt)>0) {
2485                 // Command execution done
2486                 m_stat_reg[2]&=0xFE;
2487                 m_vdp_engine=NULL;
2488                 m_cont_reg[38]=DY & 0xFF;
2489                 m_cont_reg[39]=(DY>>8) & 0x03;
2490         }
2491         else {
2492                 m_mmc.DX=DX;
2493                 m_mmc.DY=DY;
2494                 m_mmc.ASX=ASX;
2495                 m_mmc.ADX=ADX;
2496         }
2497 }
2498
2499 /** lmmv_engine() *********************************************/
2500 /** VDP -> Vram                                             **/
2501 /*************************************************************/
2502 void v99x8_device::lmmv_engine()
2503 {
2504         int DX=m_mmc.DX;
2505         int DY=m_mmc.DY;
2506         int TX=m_mmc.TX;
2507         int TY=m_mmc.TY;
2508         int NX=m_mmc.NX;
2509         int NY=m_mmc.NY;
2510         int ADX=m_mmc.ADX;
2511         int ANX=m_mmc.ANX;
2512         UINT8 CL=m_mmc.CL;
2513         UINT8 LO=m_mmc.LO;
2514         int MXD = m_mmc.MXD;
2515         int cnt;
2516         int delta;
2517
2518         delta = get_vdp_timing_value(lmmv_timing);
2519         cnt = m_vdp_ops_count;
2520
2521         switch (m_mode) {
2522         default:
2523         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, CL, LO); post__x_y(256)
2524                 break;
2525         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, CL, LO); post__x_y(512)
2526                 break;
2527         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, CL, LO); post__x_y(512)
2528                 break;
2529         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, CL, LO); post__x_y(256)
2530                 break;
2531         }
2532
2533         if ((m_vdp_ops_count=cnt)>0) {
2534                 // Command execution done
2535                 m_stat_reg[2]&=0xFE;
2536                 m_vdp_engine=NULL;
2537                 if (!NY)
2538                         DY+=TY;
2539                 m_cont_reg[38]=DY & 0xFF;
2540                 m_cont_reg[39]=(DY>>8) & 0x03;
2541                 m_cont_reg[42]=NY & 0xFF;
2542                 m_cont_reg[43]=(NY>>8) & 0x03;
2543         }
2544         else {
2545                 m_mmc.DY=DY;
2546                 m_mmc.NY=NY;
2547                 m_mmc.ANX=ANX;
2548                 m_mmc.ADX=ADX;
2549         }
2550 }
2551
2552 /** lmmm_engine() *********************************************/
2553 /** Vram -> Vram                                            **/
2554 /*************************************************************/
2555 void v99x8_device::lmmm_engine()
2556 {
2557         int SX=m_mmc.SX;
2558         int SY=m_mmc.SY;
2559         int DX=m_mmc.DX;
2560         int DY=m_mmc.DY;
2561         int TX=m_mmc.TX;
2562         int TY=m_mmc.TY;
2563         int NX=m_mmc.NX;
2564         int NY=m_mmc.NY;
2565         int ASX=m_mmc.ASX;
2566         int ADX=m_mmc.ADX;
2567         int ANX=m_mmc.ANX;
2568         UINT8 LO=m_mmc.LO;
2569         int MXS = m_mmc.MXS;
2570         int MXD = m_mmc.MXD;
2571         int cnt;
2572         int delta;
2573
2574         delta = get_vdp_timing_value(lmmm_timing);
2575         cnt = m_vdp_ops_count;
2576
2577         switch (m_mode) {
2578         default:
2579         case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, VDPpoint5(MXS, ASX, SY), LO); post_xxyy(256)
2580                 break;
2581         case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, VDPpoint6(MXS, ASX, SY), LO); post_xxyy(512)
2582                 break;
2583         case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, VDPpoint7(MXS, ASX, SY), LO); post_xxyy(512)
2584                 break;
2585         case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, VDPpoint8(MXS, ASX, SY), LO); post_xxyy(256)
2586                 break;
2587         }
2588
2589         if ((m_vdp_ops_count=cnt)>0) {
2590                 // Command execution done
2591                 m_stat_reg[2]&=0xFE;
2592                 m_vdp_engine=NULL;
2593                 if (!NY) {
2594                         SY+=TY;
2595                         DY+=TY;
2596                 }
2597                 else
2598                         if (SY==-1)
2599                         DY+=TY;
2600                 m_cont_reg[42]=NY & 0xFF;
2601                 m_cont_reg[43]=(NY>>8) & 0x03;
2602                 m_cont_reg[34]=SY & 0xFF;
2603                 m_cont_reg[35]=(SY>>8) & 0x03;
2604                 m_cont_reg[38]=DY & 0xFF;
2605                 m_cont_reg[39]=(DY>>8) & 0x03;
2606         }
2607         else {
2608                 m_mmc.SY=SY;
2609                 m_mmc.DY=DY;
2610                 m_mmc.NY=NY;
2611                 m_mmc.ANX=ANX;
2612                 m_mmc.ASX=ASX;
2613                 m_mmc.ADX=ADX;
2614         }
2615 }
2616
2617 /** lmcm_engine() *********************************************/
2618 /** Vram -> CPU                                             **/
2619 /*************************************************************/
2620 void v99x8_device::lmcm_engine()
2621 {
2622         if ((m_stat_reg[2]&0x80)!=0x80) {
2623                 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);
2624                 m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing);
2625                 m_stat_reg[2]|=0x80;
2626
2627                 if (!--m_mmc.ANX || ((m_mmc.ASX+=m_mmc.TX)&m_mmc.MX)) {
2628                         if (!(--m_mmc.NY & 1023) || (m_mmc.SY+=m_mmc.TY)==-1) {
2629                                 m_stat_reg[2]&=0xFE;
2630                                 m_vdp_engine=NULL;
2631                                 if (!m_mmc.NY)
2632                                         m_mmc.DY+=m_mmc.TY;
2633                                 m_cont_reg[42]=m_mmc.NY & 0xFF;
2634                                 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2635                                 m_cont_reg[34]=m_mmc.SY & 0xFF;
2636                                 m_cont_reg[35]=(m_mmc.SY>>8) & 0x03;
2637                         }
2638                         else {
2639                                 m_mmc.ASX=m_mmc.SX;
2640                                 m_mmc.ANX=m_mmc.NX;
2641                         }
2642                 }
2643         }
2644 }
2645
2646 /** lmmc_engine() *********************************************/
2647 /** CPU -> Vram                                             **/
2648 /*************************************************************/
2649 void v99x8_device::lmmc_engine()
2650 {
2651         if ((m_stat_reg[2]&0x80)!=0x80) {
2652                 UINT8 SM=((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0;
2653
2654                 m_stat_reg[7]=m_cont_reg[44]&=Mask[SM];
2655                 VDP_PSET(SM, m_mmc.MXD, m_mmc.ADX, m_mmc.DY, m_cont_reg[44], m_mmc.LO);
2656                 m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing);
2657                 m_stat_reg[2]|=0x80;
2658
2659                 if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) {
2660                         if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) {
2661                                 m_stat_reg[2]&=0xFE;
2662                                 m_vdp_engine=NULL;
2663                                 if (!m_mmc.NY)
2664                                         m_mmc.DY+=m_mmc.TY;
2665                                 m_cont_reg[42]=m_mmc.NY & 0xFF;
2666                                 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2667                                 m_cont_reg[38]=m_mmc.DY & 0xFF;
2668                                 m_cont_reg[39]=(m_mmc.DY>>8) & 0x03;
2669                         }
2670                         else {
2671                                 m_mmc.ADX=m_mmc.DX;
2672                                 m_mmc.ANX=m_mmc.NX;
2673                         }
2674                 }
2675         }
2676 }
2677
2678 /** hmmv_engine() *********************************************/
2679 /** VDP --> Vram                                            **/
2680 /*************************************************************/
2681 void v99x8_device::hmmv_engine()
2682 {
2683         int DX=m_mmc.DX;
2684         int DY=m_mmc.DY;
2685         int TX=m_mmc.TX;
2686         int TY=m_mmc.TY;
2687         int NX=m_mmc.NX;
2688         int NY=m_mmc.NY;
2689         int ADX=m_mmc.ADX;
2690         int ANX=m_mmc.ANX;
2691         UINT8 CL=m_mmc.CL;
2692         int MXD = m_mmc.MXD;
2693         int cnt;
2694         int delta;
2695
2696         delta = get_vdp_timing_value(hmmv_timing);
2697         cnt = m_vdp_ops_count;
2698
2699         switch (m_mode) {
2700         default:
2701         case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), CL); post__x_y(256)
2702                 break;
2703         case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), CL); post__x_y(512)
2704                 break;
2705         case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), CL); post__x_y(512)
2706                 break;
2707         case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), CL); post__x_y(256)
2708                 break;
2709         }
2710
2711         if ((m_vdp_ops_count=cnt)>0) {
2712                 // Command execution done
2713                 m_stat_reg[2]&=0xFE;
2714                 m_vdp_engine=NULL;
2715                 if (!NY)
2716                         DY+=TY;
2717                 m_cont_reg[42]=NY & 0xFF;
2718                 m_cont_reg[43]=(NY>>8) & 0x03;
2719                 m_cont_reg[38]=DY & 0xFF;
2720                 m_cont_reg[39]=(DY>>8) & 0x03;
2721         }
2722         else {
2723                 m_mmc.DY=DY;
2724                 m_mmc.NY=NY;
2725                 m_mmc.ANX=ANX;
2726                 m_mmc.ADX=ADX;
2727         }
2728 }
2729
2730 /** hmmm_engine() *********************************************/
2731 /** Vram -> Vram                                            **/
2732 /*************************************************************/
2733 void v99x8_device::hmmm_engine()
2734 {
2735         int SX=m_mmc.SX;
2736         int SY=m_mmc.SY;
2737         int DX=m_mmc.DX;
2738         int DY=m_mmc.DY;
2739         int TX=m_mmc.TX;
2740         int TY=m_mmc.TY;
2741         int NX=m_mmc.NX;
2742         int NY=m_mmc.NY;
2743         int ASX=m_mmc.ASX;
2744         int ADX=m_mmc.ADX;
2745         int ANX=m_mmc.ANX;
2746         int MXS = m_mmc.MXS;
2747         int MXD = m_mmc.MXD;
2748         int cnt;
2749         int delta;
2750
2751         delta = get_vdp_timing_value(hmmm_timing);
2752         cnt = m_vdp_ops_count;
2753
2754         switch (m_mode) {
2755         default:
2756         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)
2757                 break;
2758         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)
2759                 break;
2760         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)
2761                 break;
2762         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)
2763                 break;
2764         }
2765
2766         if ((m_vdp_ops_count=cnt)>0) {
2767                 // Command execution done
2768                 m_stat_reg[2]&=0xFE;
2769                 m_vdp_engine=NULL;
2770                 if (!NY) {
2771                         SY+=TY;
2772                         DY+=TY;
2773                 }
2774                 else
2775                         if (SY==-1)
2776                         DY+=TY;
2777                 m_cont_reg[42]=NY & 0xFF;
2778                 m_cont_reg[43]=(NY>>8) & 0x03;
2779                 m_cont_reg[34]=SY & 0xFF;
2780                 m_cont_reg[35]=(SY>>8) & 0x03;
2781                 m_cont_reg[38]=DY & 0xFF;
2782                 m_cont_reg[39]=(DY>>8) & 0x03;
2783         }
2784         else {
2785                 m_mmc.SY=SY;
2786                 m_mmc.DY=DY;
2787                 m_mmc.NY=NY;
2788                 m_mmc.ANX=ANX;
2789                 m_mmc.ASX=ASX;
2790                 m_mmc.ADX=ADX;
2791         }
2792 }
2793
2794 /** ymmm_engine() *********************************************/
2795 /** Vram -> Vram                                            **/
2796 /*************************************************************/
2797
2798 void v99x8_device::ymmm_engine()
2799 {
2800         int SY=m_mmc.SY;
2801         int DX=m_mmc.DX;
2802         int DY=m_mmc.DY;
2803         int TX=m_mmc.TX;
2804         int TY=m_mmc.TY;
2805         int NY=m_mmc.NY;
2806         int ADX=m_mmc.ADX;
2807         int MXD = m_mmc.MXD;
2808         int cnt;
2809         int delta;
2810
2811         delta = get_vdp_timing_value(ymmm_timing);
2812         cnt = m_vdp_ops_count;
2813
2814         switch (m_mode) {
2815         default:
2816         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)
2817                 break;
2818         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)
2819                 break;
2820         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)
2821                 break;
2822         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)
2823                 break;
2824         }
2825
2826         if ((m_vdp_ops_count=cnt)>0) {
2827                 // Command execution done
2828                 m_stat_reg[2]&=0xFE;
2829                 m_vdp_engine=NULL;
2830                 if (!NY) {
2831                         SY+=TY;
2832                         DY+=TY;
2833                 }
2834                 else
2835                         if (SY==-1)
2836                         DY+=TY;
2837                 m_cont_reg[42]=NY & 0xFF;
2838                 m_cont_reg[43]=(NY>>8) & 0x03;
2839                 m_cont_reg[34]=SY & 0xFF;
2840                 m_cont_reg[35]=(SY>>8) & 0x03;
2841                 m_cont_reg[38]=DY & 0xFF;
2842                 m_cont_reg[39]=(DY>>8) & 0x03;
2843         }
2844         else {
2845                 m_mmc.SY=SY;
2846                 m_mmc.DY=DY;
2847                 m_mmc.NY=NY;
2848                 m_mmc.ADX=ADX;
2849         }
2850 }
2851
2852 /** hmmc_engine() *********************************************/
2853 /** CPU -> Vram                                             **/
2854 /*************************************************************/
2855 void v99x8_device::hmmc_engine()
2856 {
2857         if ((m_stat_reg[2]&0x80)!=0x80) {
2858                 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]);
2859                 m_vdp_ops_count -= get_vdp_timing_value(hmmv_timing);
2860                 m_stat_reg[2]|=0x80;
2861
2862                 if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) {
2863                         if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) {
2864                                 m_stat_reg[2]&=0xFE;
2865                                 m_vdp_engine=NULL;
2866                                 if (!m_mmc.NY)
2867                                         m_mmc.DY+=m_mmc.TY;
2868                                 m_cont_reg[42]=m_mmc.NY & 0xFF;
2869                                 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2870                                 m_cont_reg[38]=m_mmc.DY & 0xFF;
2871                                 m_cont_reg[39]=(m_mmc.DY>>8) & 0x03;
2872                         }
2873                         else {
2874                                 m_mmc.ADX=m_mmc.DX;
2875                                 m_mmc.ANX=m_mmc.NX;
2876                         }
2877                 }
2878         }
2879 }
2880
2881 /** VDPWrite() ***********************************************/
2882 /** Use this function to transfer pixel(s) from CPU to m_ **/
2883 /*************************************************************/
2884 void v99x8_device::cpu_to_vdp(UINT8 V)
2885 {
2886         m_stat_reg[2]&=0x7F;
2887         m_stat_reg[7]=m_cont_reg[44]=V;
2888         if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
2889 }
2890
2891 /** VDPRead() ************************************************/
2892 /** Use this function to transfer pixel(s) from VDP to CPU. **/
2893 /*************************************************************/
2894 UINT8 v99x8_device::vdp_to_cpu()
2895 {
2896         m_stat_reg[2]&=0x7F;
2897         if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
2898         return(m_cont_reg[44]);
2899 }
2900
2901 /** report_vdp_command() ***************************************/
2902 /** Report VDP Command to be executed                       **/
2903 /*************************************************************/
2904 void v99x8_device::report_vdp_command(UINT8 Op)
2905 {
2906         static const char *const Ops[16] =
2907         {
2908                 "SET ","AND ","OR  ","XOR ","NOT ","NOP ","NOP ","NOP ",
2909                 "TSET","TAND","TOR ","TXOR","TNOT","NOP ","NOP ","NOP "
2910         };
2911         static const char *const Commands[16] =
2912         {
2913                 " ABRT"," ????"," ????"," ????","POINT"," PSET"," SRCH"," LINE",
2914                 " LMMV"," LMMM"," LMCM"," LMMC"," HMMV"," HMMM"," YMMM"," HMMC"
2915         };
2916
2917         UINT8 CL, CM, LO;
2918         int SX,SY, DX,DY, NX,NY;
2919
2920         // Fetch arguments
2921         CL = m_cont_reg[44];
2922         SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511;
2923         SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023;
2924         DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511;
2925         DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023;
2926         NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023;
2927         NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023;
2928         CM = Op>>4;
2929         LO = Op&0x0F;
2930
2931         LOG(("V9938: Opcode %02Xh %s-%s (%d,%d)->(%d,%d),%d [%d,%d]%s\n",
2932                 Op, Commands[CM], Ops[LO],
2933                 SX,SY, DX,DY, CL, m_cont_reg[45]&0x04? -NX:NX,
2934                 m_cont_reg[45]&0x08? -NY:NY,
2935                 m_cont_reg[45]&0x70? " on ExtVRAM":""
2936                 ));
2937 }
2938
2939 /** VDPDraw() ************************************************/
2940 /** Perform a given V9938 operation Op.                     **/
2941 /*************************************************************/
2942 UINT8 v99x8_device::command_unit_w(UINT8 Op)
2943 {
2944         int SM;
2945
2946         // V9938 ops only work in SCREENs 5-8
2947         if (m_mode<5)
2948                 return(0);
2949
2950         SM = m_mode-5;         // Screen mode index 0..3
2951
2952         m_mmc.CM = Op>>4;
2953         if ((m_mmc.CM & 0x0C) != 0x0C && m_mmc.CM != 0)
2954                 // Dot operation: use only relevant bits of color
2955         m_stat_reg[7]=(m_cont_reg[44]&=Mask[SM]);
2956
2957         //  if(Verbose&0x02)
2958         report_vdp_command(Op);
2959
2960         switch(Op>>4) {
2961         case CM_ABRT:
2962                 m_stat_reg[2]&=0xFE;
2963                 m_vdp_engine=NULL;
2964                 return 1;
2965         case CM_POINT:
2966                 m_stat_reg[2]&=0xFE;
2967                 m_vdp_engine=NULL;
2968                 m_stat_reg[7]=m_cont_reg[44]=
2969                 VDP_POINT(SM, (m_cont_reg[45] & 0x10) != 0,
2970                         m_cont_reg[32]+((int)m_cont_reg[33]<<8),
2971                         m_cont_reg[34]+((int)m_cont_reg[35]<<8));
2972                 return 1;
2973         case CM_PSET:
2974                 m_stat_reg[2]&=0xFE;
2975                 m_vdp_engine=NULL;
2976                 VDP_PSET(SM, (m_cont_reg[45] & 0x20) != 0,
2977                         m_cont_reg[36]+((int)m_cont_reg[37]<<8),
2978                         m_cont_reg[38]+((int)m_cont_reg[39]<<8),
2979                         m_cont_reg[44],
2980                         Op&0x0F);
2981                 return 1;
2982         case CM_SRCH:
2983                 m_vdp_engine=&v99x8_device::srch_engine;
2984                 break;
2985         case CM_LINE:
2986                 m_vdp_engine=&v99x8_device::line_engine;
2987                 break;
2988         case CM_LMMV:
2989                 m_vdp_engine=&v99x8_device::lmmv_engine;
2990                 break;
2991         case CM_LMMM:
2992                 m_vdp_engine=&v99x8_device::lmmm_engine;
2993                 break;
2994         case CM_LMCM:
2995                 m_vdp_engine=&v99x8_device::lmcm_engine;
2996                 break;
2997         case CM_LMMC:
2998                 m_vdp_engine=&v99x8_device::lmmc_engine;
2999                 break;
3000         case CM_HMMV:
3001                 m_vdp_engine=&v99x8_device::hmmv_engine;
3002                 break;
3003         case CM_HMMM:
3004                 m_vdp_engine=&v99x8_device::hmmm_engine;
3005                 break;
3006         case CM_YMMM:
3007                 m_vdp_engine=&v99x8_device::ymmm_engine;
3008                 break;
3009         case CM_HMMC:
3010                 m_vdp_engine=&v99x8_device::hmmc_engine;
3011                 break;
3012         default:
3013                 LOG(("V9938: Unrecognized opcode %02Xh\n",Op));
3014                 return(0);
3015         }
3016
3017         // Fetch unconditional arguments
3018         m_mmc.SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511;
3019         m_mmc.SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023;
3020         m_mmc.DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511;
3021         m_mmc.DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023;
3022         m_mmc.NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023;
3023         m_mmc.TY = m_cont_reg[45]&0x08? -1:1;
3024         m_mmc.MX = PPL[SM];
3025         m_mmc.CL = m_cont_reg[44];
3026         m_mmc.LO = Op&0x0F;
3027         m_mmc.MXS = (m_cont_reg[45] & 0x10) != 0;
3028         m_mmc.MXD = (m_cont_reg[45] & 0x20) != 0;
3029
3030         // Argument depends on UINT8 or dot operation
3031         if ((m_mmc.CM & 0x0C) == 0x0C) {
3032                 m_mmc.TX = m_cont_reg[45]&0x04? -PPB[SM]:PPB[SM];
3033                 m_mmc.NX = ((m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023)/PPB[SM];
3034         }
3035         else {
3036                 m_mmc.TX = m_cont_reg[45]&0x04? -1:1;
3037                 m_mmc.NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023;
3038         }
3039
3040         // X loop variables are treated specially for LINE command
3041         if (m_mmc.CM == CM_LINE) {
3042                 m_mmc.ASX=((m_mmc.NX-1)>>1);
3043                 m_mmc.ADX=0;
3044         }
3045         else {
3046                 m_mmc.ASX = m_mmc.SX;
3047                 m_mmc.ADX = m_mmc.DX;
3048         }
3049
3050         // NX loop variable is treated specially for SRCH command
3051         if (m_mmc.CM == CM_SRCH)
3052                 m_mmc.ANX=(m_cont_reg[45]&0x02)!=0; // Do we look for "==" or "!="?
3053         else
3054                 m_mmc.ANX = m_mmc.NX;
3055
3056         // Command execution started
3057         m_stat_reg[2]|=0x01;
3058
3059         // Start execution if we still have time slices
3060         if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
3061
3062         // Operation successfully initiated
3063         return(1);
3064 }
3065
3066 /** LoopVDP() ************************************************
3067 Run X steps of active VDP command
3068 *************************************************************/
3069 void v99x8_device::update_command()
3070 {
3071         if(m_vdp_ops_count<=0)
3072         {
3073                 m_vdp_ops_count+=13662;
3074                 if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
3075         }
3076         else
3077         {
3078                 m_vdp_ops_count=13662;
3079                 if(m_vdp_engine) (this->*m_vdp_engine)();
3080         }
3081 }
3082
3083 /*static MACHINE_CONFIG_FRAGMENT( v9938 )
3084         MCFG_PALETTE_ADD("palette", 512)
3085         MCFG_PALETTE_INIT_OWNER(v9938_device, v9938)
3086 MACHINE_CONFIG_END*/
3087
3088 //-------------------------------------------------
3089 //  machine_config_additions - return a pointer to
3090 //  the device's machine fragment
3091 //-------------------------------------------------
3092
3093 /*machine_config_constructor v9938_device::device_mconfig_additions() const
3094 {
3095         return MACHINE_CONFIG_NAME( v9938 );
3096 }*/
3097
3098 /*static MACHINE_CONFIG_FRAGMENT( v9958 )
3099         MCFG_PALETTE_ADD("palette", 19780)
3100         MCFG_PALETTE_INIT_OWNER(v9958_device, v9958)
3101 MACHINE_CONFIG_END*/
3102
3103 //-------------------------------------------------
3104 //  machine_config_additions - return a pointer to
3105 //  the device's machine fragment
3106 //-------------------------------------------------
3107
3108 /*machine_config_constructor v9958_device::device_mconfig_additions() const
3109 {
3110         return MACHINE_CONFIG_NAME( v9958 );
3111 }*/
3112
3113
3114
3115 /* for common source code project */
3116 void v99x8_device::draw_screen()
3117 {
3118         scrntype_t *dst;
3119         int y;
3120         if(osd == NULL) return;
3121         emu->set_vm_screen_lines(__SCREEN_HEIGHT);
3122         for(y=0; y< __SCREEN_HEIGHT; y++) {
3123                 if((dst = osd->get_vm_screen_buffer(y)) != NULL) {
3124                         my_memcpy(dst, screen+(y+18)*_V9938_LONG_WIDTH+2, __SCREEN_WIDTH*sizeof(scrntype_t));
3125                 }
3126         }
3127 }
3128
3129 void v99x8_device::initialize()
3130 {
3131         DEVICE::initialize();
3132         __SCREEN_WIDTH = osd->get_feature_int_value(_T("SCREEN_WIDTH"));
3133         __SCREEN_HEIGHT = osd->get_feature_int_value(_T("SCREEN_HEIGHT"));
3134         if(__SCREEN_WIDTH <= 0) __SCREEN_WIDTH = 256;
3135         if(__SCREEN_HEIGHT <= 0) __SCREEN_HEIGHT = 192;
3136         
3137         device_start();
3138         register_vline_event(this);
3139 }
3140
3141 void v99x8_device::reset()
3142 {
3143         device_reset();
3144 }
3145
3146 void v99x8_device::event_vline(int v, int clock)
3147 {
3148         m_stat_reg[2] ^= 0x20;
3149         device_timer(v);
3150 }
3151
3152 void v99x8_device::write_signal(int id, uint32_t data, uint32_t mask)
3153 {
3154         if(id == SIG_VDP_COMMAND_COMPLETION) {
3155                 while(1) {
3156                         int i;
3157                         i = m_vdp_ops_count = 13662;
3158                         if(m_vdp_engine) (this->*m_vdp_engine)();
3159                         if (i == m_vdp_ops_count) break;
3160                 }
3161         }
3162 }
3163
3164 #define STATE_VERSION   2
3165
3166 #include "../statesub.h"
3167
3168 void v99x8_device::decl_state()
3169 {
3170         enter_decl_state(STATE_VERSION);
3171         
3172         DECL_STATE_ENTRY_INT32(m_offset_x);
3173         DECL_STATE_ENTRY_INT32(m_offset_y);
3174         DECL_STATE_ENTRY_INT32(m_visible_y);
3175         DECL_STATE_ENTRY_INT32(m_mode);
3176         DECL_STATE_ENTRY_INT32(m_pal_write_first);
3177         DECL_STATE_ENTRY_INT32(m_cmd_write_first);
3178         DECL_STATE_ENTRY_UINT8(m_pal_write);
3179         DECL_STATE_ENTRY_UINT8(m_cmd_write);
3180         DECL_STATE_ENTRY_1D_ARRAY(m_pal_reg, 32);
3181         DECL_STATE_ENTRY_1D_ARRAY(m_stat_reg, 10);
3182         DECL_STATE_ENTRY_1D_ARRAY(m_cont_reg, 46);
3183         DECL_STATE_ENTRY_UINT8(m_read_ahead);
3184                         
3185         DECL_STATE_ENTRY_UINT8(m_int_state);
3186         DECL_STATE_ENTRY_INT32(m_scanline);
3187         DECL_STATE_ENTRY_INT32(m_blink);
3188         DECL_STATE_ENTRY_UINT8(m_blink_count);
3189         DECL_STATE_ENTRY_UINT8(m_mx_delta);
3190         DECL_STATE_ENTRY_UINT8(m_my_delta);
3191         DECL_STATE_ENTRY_UINT8(m_button_state);
3192         DECL_STATE_ENTRY_1D_ARRAY(m_pal_ind16, 16);
3193         DECL_STATE_ENTRY_1D_ARRAY(m_pal_ind256, 256);
3194         {
3195                 DECL_STATE_ENTRY_INT32((m_mmc.SX));
3196                 DECL_STATE_ENTRY_INT32((m_mmc.SY));
3197                 DECL_STATE_ENTRY_INT32((m_mmc.DX));
3198                 DECL_STATE_ENTRY_INT32((m_mmc.DY));
3199                 DECL_STATE_ENTRY_INT32((m_mmc.TX));
3200                 DECL_STATE_ENTRY_INT32((m_mmc.TY));
3201                 DECL_STATE_ENTRY_INT32((m_mmc.NX));
3202                 DECL_STATE_ENTRY_INT32((m_mmc.NY));
3203                 DECL_STATE_ENTRY_INT32((m_mmc.MX));
3204                 DECL_STATE_ENTRY_INT32((m_mmc.ASX));
3205                 DECL_STATE_ENTRY_INT32((m_mmc.ADX));
3206                 DECL_STATE_ENTRY_INT32((m_mmc.ANX));
3207                 DECL_STATE_ENTRY_UINT8((m_mmc.CL));
3208                 DECL_STATE_ENTRY_UINT8((m_mmc.LO));
3209                 DECL_STATE_ENTRY_UINT8((m_mmc.CM));
3210                 DECL_STATE_ENTRY_UINT8((m_mmc.MXS));
3211                 DECL_STATE_ENTRY_UINT8((m_mmc.MXD));
3212         }
3213         DECL_STATE_ENTRY_INT32(m_vdp_ops_count);
3214         DECL_STATE_ENTRY_UINT8(m_pal_ntsc);
3215         DECL_STATE_ENTRY_INT32(m_scanline_start);
3216         DECL_STATE_ENTRY_INT32(m_vblank_start);
3217         DECL_STATE_ENTRY_INT32(m_scanline_max);
3218         DECL_STATE_ENTRY_INT32(m_height);
3219         
3220         DECL_STATE_ENTRY_INT32(m_v9958_sp_mode);
3221         DECL_STATE_ENTRY_UINT16(m_address_latch);
3222         
3223         DECL_STATE_ENTRY_1D_ARRAY(vram, sizeof(vram));
3224
3225         leave_decl_state();
3226 }
3227
3228 void v99x8_device::save_state(FILEIO* state_fio)
3229 {
3230         if(state_entry != NULL) {
3231                 state_entry->save_state(state_fio);
3232         }
3233         
3234 //      state_fio->FputUint32(STATE_VERSION);
3235 //      state_fio->FputInt32(this_device_id);
3236
3237 //      save_load_state(state_fio, true);
3238 }
3239
3240 bool v99x8_device::load_state(FILEIO* state_fio)
3241 {
3242         bool mb = false;
3243         if(state_entry != NULL) {
3244                 mb = state_entry->load_state(state_fio);
3245         }
3246         if(!mb) return false;
3247
3248 //      if(state_fio->FgetUint32() != STATE_VERSION) {
3249 //              return false;
3250 //      }
3251 //      if(state_fio->FgetInt32() != this_device_id) {
3252 //              return false;
3253 //      }
3254 //
3255 //      save_load_state(state_fio, false);
3256
3257         return true;
3258 }
3259
3260 void v99x8_device::save_load_state(FILEIO* state_fio, bool is_save)
3261 {
3262 #define STATE_ENTRY(x) {&(x), sizeof(x)}
3263         typedef struct {
3264                 void *address;
3265                 size_t size;
3266         } t_state_table;
3267         t_state_table state_table[] = {
3268                 STATE_ENTRY(m_offset_x),
3269                 STATE_ENTRY(m_offset_y),
3270                 STATE_ENTRY(m_visible_y),
3271                 STATE_ENTRY(m_mode),
3272                 STATE_ENTRY(m_pal_write_first),
3273                 STATE_ENTRY(m_cmd_write_first),
3274                 STATE_ENTRY(m_pal_write),
3275                 STATE_ENTRY(m_cmd_write),
3276                 STATE_ENTRY(m_pal_reg),
3277                 STATE_ENTRY(m_stat_reg),
3278                 STATE_ENTRY(m_cont_reg),
3279                 STATE_ENTRY(m_read_ahead),
3280                 STATE_ENTRY(m_int_state),
3281                 STATE_ENTRY(m_scanline),
3282                 STATE_ENTRY(m_blink),
3283                 STATE_ENTRY(m_blink_count),
3284                 STATE_ENTRY(m_mx_delta),
3285                 STATE_ENTRY(m_my_delta),
3286                 STATE_ENTRY(m_button_state),
3287                 STATE_ENTRY(m_pal_ind16),
3288                 STATE_ENTRY(m_pal_ind256),
3289                 STATE_ENTRY(m_mmc),
3290                 STATE_ENTRY(m_vdp_ops_count),
3291                 STATE_ENTRY(m_pal_ntsc),
3292                 STATE_ENTRY(m_scanline_start),
3293                 STATE_ENTRY(m_vblank_start),
3294                 STATE_ENTRY(m_scanline_max),
3295                 STATE_ENTRY(m_height),
3296                 STATE_ENTRY(m_v9958_sp_mode),
3297                 STATE_ENTRY(m_address_latch),
3298                 STATE_ENTRY(vram),
3299                 { NULL, 0 }
3300         };
3301         int i;
3302         for(i=0; state_table[i].size>0; i++) {
3303                 if (is_save) {
3304                         state_fio->Fwrite(state_table[i].address, state_table[i].size, 1);
3305                 }
3306                 else {
3307                         state_fio->Fread(state_table[i].address, state_table[i].size, 1);
3308                 }
3309         }
3310         return;
3311 }
3312
3313 /*
3314         Common Source Code Project
3315         MSX Series (experimental)
3316
3317         Origin : mame0172s.zip
3318                 mame.zip\src\devices\video\v9938.cpp
3319         modified by umaiboux
3320         Date   : 2016.04.xx-
3321
3322         [ V99x8 ]
3323 */