1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles, Nathan Woods
4 /***************************************************************************
6 v9938 / v9958 emulation
8 Vertical display parameters from Yamaha V9938 Technical Data Book.
9 NTSC: page 146, Table 7-2
10 PAL: page 147, Table 7-3
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
24 Refresh rate 50.158974 59.922743
27 ***************************************************************************/
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
41 #define m_vram_space this
44 //#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
45 #define LOG(x) void(x)
62 #define MODEL_V9938 (0)
63 #define MODEL_V9958 (1)
65 #define EXPMEM_OFFSET 0x20000
67 // LONG_WIDTH has already defined limits.h for GCC.20180614 K.O
68 #define _V9938_LONG_WIDTH (512 + 32)
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",
76 //**************************************************************************
78 //**************************************************************************
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).
84 //static ADDRESS_MAP_START(memmap, AS_DATA, 8, v99x8_device)
85 // ADDRESS_MAP_GLOBAL_MASK(0x3ffff)
86 // AM_RANGE(0x00000, 0x2ffff) AM_RAM
91 //const device_type V9938 = &device_creator<v9938_device>;
92 //const device_type V9958 = &device_creator<v9958_device>;
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),
107 m_pal_write_first(0),
108 m_cmd_write_first(0),
114 m_vram_size(/*0*/0x20000),
116 // m_int_callback(*this),
125 // m_palette(*this, "palette"),
128 // static_set_addrmap(*this, AS_DATA, ADDRESS_MAP_NAME(memmap));
129 initialize_output_signals(&outputs_irq);
130 set_device_name(_T("V99x8 VDP"));
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)
138 m_model = MODEL_V9938;
140 set_device_name(_T("V9938 VDP"));
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)
148 m_model = MODEL_V9958;
150 set_device_name(_T("V9958 VDP"));
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)
157 int scanline = (m_scanline - (m_scanline_start + m_offset_y));
162 if (m_scanline == (m_scanline_start + m_offset_y))
164 m_stat_reg[2] &= ~0x40;
166 else if (m_scanline == (m_scanline_start + m_offset_y + m_visible_y))
168 m_stat_reg[2] |= 0x40;
169 m_stat_reg[0] |= 0x80;
172 if ( (scanline >= 0) && (scanline <= m_scanline_max) &&
173 (((scanline + m_cont_reg[23]) & 255) == m_cont_reg[19]) )
176 LOG(("V9938: scanline interrupt (%d)\n", scanline));
178 else if (!(m_cont_reg[0] & 0x10))
180 m_stat_reg[1] &= 0xfe;
185 // check for start of vblank
186 if (m_scanline == m_vblank_start)
188 interrupt_start_vblank();
191 // render the current line
192 if (m_scanline < m_vblank_start)
194 refresh_line(scanline);
197 if (++m_scanline >= m_height)
201 /*int pal = m_cont_reg[9] & 2;
202 if (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();
214 void v99x8_device::set_screen_parameters()
219 m_scanline_start = (m_cont_reg[9] & 0x80) ? 43 : 53;
220 m_scanline_max = 255;
225 m_scanline_start = (m_cont_reg[9] & 0x80) ? 16 : 26;
226 m_scanline_max = (m_cont_reg[9] & 0x80) ? 234 : 244;
228 m_visible_y = (m_cont_reg[9] & 0x80) ? 212 : 192;
232 void v99x8_device::configure_pal_ntsc()
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));
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));
250 m_vblank_start = m_height - VERTICAL_SYNC - TOP_ERASE; /* Sync + top erase */
255 Not really right... won't work with sprites in graphics 7
256 and with palette updated mid-screen
258 int v99x8_device::get_transpen()
260 if (m_mode == V9938_MODE_GRAPHIC7)
262 return m_pal_ind256[0];
266 return m_pal_ind16[0];
271 Driver-specific function: update the vdp mouse state
273 /*void v99x8_device::update_mouse_state(int mx_delta, int my_delta, int button_state)
276 m_button_state = (button_state << 6) & 0xc0;
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;
287 /***************************************************************************
291 ***************************************************************************/
294 About the colour burst registers:
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.
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. :(
310 In screen 8, the colors are encoded as:
313 +--+--+--+--+--+--+--+--+
314 |g2|g1|g0|r2|r1|r0|b2|b1|
315 +--+--+--+--+--+--+--+--+
317 b0 is set if b2 and b1 are set (remember, color bus is 3 bits)
321 /*PALETTE_INIT_MEMBER(v9938_device, v9938)*/
322 void v9938_device::init_palette()
326 // create the full 512 colour palette
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));
334 The v9958 can display up to 19286 colours. For this we need a larger palette.
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. :)
343 UINT16 v99x8_device::s_pal_indYJK[0x20000];
345 /*PALETTE_INIT_MEMBER(v9958_device, v9958)*/
346 void v9958_device::init_palette()
348 int r,g,b,y,j,k,i,k0,j0,n;
351 // init v9938 512-color palette
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));
357 // if(palette.entries() != 19780)
358 // fatalerror("V9958: not enough palette, must be 19780");
361 LOG(("Building YJK table for V9958 screens, may take a while ... \n"));
363 for (y=0;y<32;y++) for (k=0;k<64;k++) for (j=0;j<64;j++)
365 // calculate the color
366 if (k >= 32) k0 = (k - 64); else k0 = k;
367 if (j >= 32) j0 = (j - 64); else j0 = j;
369 b = (y * 5 - 2 * j0 - k0) / 4;
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;
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?
382 if (pal[n*3+0] == r && pal[n*3+1] == g && pal[n*3+2] == b)
384 v99x8_device::s_pal_indYJK[y | j << 5 | k << (5 + 6)] = n + 512;
392 // so we haven't; add it
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;
404 LOG( ("Table creation failed - %d colours out of 19286 created\n", i));
407 /*UINT32 v99x8_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
409 copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
413 /*READ8_MEMBER( v99x8_device::read )*/
414 uint32_t v99x8_device::read_io8(uint32_t offset)
418 case 0: return vram_r();
419 case 1: return status_r();
424 /*WRITE8_MEMBER( v99x8_device::write )*/
425 void v99x8_device::write_io8(uint32_t offset, uint32_t data)
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;
436 UINT8 v99x8_device::vram_r()
441 address = ((int)m_cont_reg[14] << 14) | m_address_latch;
443 m_cmd_write_first = 0;
447 if (m_cont_reg[45] & 0x40) // Expansion memory
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);
459 m_read_ahead = vram_read(address);
462 m_address_latch = (m_address_latch + 1) & 0x3fff;
463 if ((!m_address_latch) && (m_cont_reg[0] & 0x0c) ) // correct ???
465 m_cont_reg[14] = (m_cont_reg[14] + 1) & 7;
471 UINT8 v99x8_device::status_r()
476 m_cmd_write_first = 0;
478 reg = m_cont_reg[15] & 0x0f;
486 m_stat_reg[0] &= 0x1f;
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;
496 /*update_command ();*/
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;
505 // if (machine().rand() & 1) m_stat_reg[2] |= 0x20;
506 // else m_stat_reg[2] &= ~0x20;
510 if ((m_cont_reg[8] & 0xc0) == 0x80)
511 { // mouse mode: return x mouse delta
519 if ((m_cont_reg[8] & 0xc0) == 0x80)
520 { // mouse mode: return y mouse delta
529 m_stat_reg[7] = m_cont_reg[44] = vdp_to_cpu () ;
532 ret = m_stat_reg[reg];
536 LOG(("V9938: Read %02x from S#%d\n", ret, reg));
542 void v99x8_device::palette_w(UINT8 data)
546 if (m_pal_write_first)
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;
553 m_pal_ind16[indexp] = (((int)m_pal_write << 2) & 0x01c0) |
554 (((int)data << 3) & 0x0038) |
555 ((int)m_pal_write & 0x0007);
557 m_cont_reg[0x10] = (m_cont_reg[0x10] + 1) & 15;
558 m_pal_write_first = 0;
563 m_pal_write_first = 1;
567 void v99x8_device::vram_w(UINT8 data)
571 /*update_command ();*/
573 m_cmd_write_first = 0;
575 address = ((int)m_cont_reg[14] << 14) | m_address_latch;
577 if (m_cont_reg[45] & 0x40)
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);
586 vram_write(address, data);
589 m_address_latch = (m_address_latch + 1) & 0x3fff;
590 if ((!m_address_latch) && (m_cont_reg[0] & 0x0c) ) // correct ???
592 m_cont_reg[14] = (m_cont_reg[14] + 1) & 7;
596 void v99x8_device::command_w(UINT8 data)
598 if (m_cmd_write_first)
603 register_write (data & 0x3f, m_cmd_write);
608 (((UINT16)data << 8) | m_cmd_write) & 0x3fff;
609 if ( !(data & 0x40) ) vram_r (); // read ahead!
612 m_cmd_write_first = 0;
617 m_cmd_write_first = 1;
621 void v99x8_device::register_w(UINT8 data)
625 reg = m_cont_reg[17] & 0x3f;
627 register_write(reg, data); // true ?
629 if (!(m_cont_reg[17] & 0x80))
630 m_cont_reg[17] = (m_cont_reg[17] + 1) & 0x3f;
633 /*void v99x8_device::static_set_vram_size(device_t &device, UINT32 vram_size)
635 downcast<v99x8_device &>(device).m_vram_size = vram_size;
638 /***************************************************************************
640 Init/stop/reset/Interrupt functions
642 ***************************************************************************/
644 void v99x8_device::device_start()
646 // m_int_callback.resolve_safe();
650 // m_screen->register_screen_bitmap(m_bitmap);
652 // Video RAM is allocated as an own address space
653 // m_vram_space = &space(AS_DATA);
656 assert(m_vram_size > 0);
658 if (m_vram_size < 0x20000)
660 // set unavailable RAM to 0xff
661 for (int addr = m_vram_size; addr < 0x30000; addr++) m_vram_space->write_byte(addr, 0xff);
664 // m_line_timer = timer_alloc(TIMER_LINE);
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));*/
715 void v99x8_device::device_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;
731 m_read_ahead = 0; m_address_latch = 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.
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;
747 // m_line_timer->adjust(attotime::from_ticks(HTOTAL*2, m_clock), 0, attotime::from_ticks(HTOTAL*2, m_clock));
749 configure_pal_ntsc();
750 set_screen_parameters();
754 void v99x8_device::reset_palette()
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
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
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
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];
786 // set internal palette GRAPHIC 7
789 ind = (i << 4) & 0x01c0;
790 ind |= (i >> 2) & 0x0038;
791 red = (i << 1) & 6; if (red == 6) red++;
794 m_pal_ind256[i] = ind;
798 /***************************************************************************
802 ***************************************************************************/
804 void v99x8_device::vram_write(int offset, int data)
808 if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) )
810 newoffset = ((offset & 1) << 16) | (offset >> 1);
811 if (newoffset < m_vram_size)
812 m_vram_space->write_byte(newoffset, data);
816 if (offset < m_vram_size)
817 m_vram_space->write_byte(offset, data);
821 int v99x8_device::vram_read(int offset)
823 if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) )
824 return m_vram_space->read_byte(((offset & 1) << 16) | (offset >> 1));
826 return m_vram_space->read_byte(offset);
829 void v99x8_device::check_int()
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) );
837 if(n && m_vblank_int)
843 if (n != m_int_state)
846 LOG(("V9938: IRQ line %s\n", n ? "up" : "down"));
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
854 if(!emu->now_waiting_in_debugger) {
855 // m_int_callback(n);
856 write_signals(&outputs_irq, n ? 0xffffffff : 0);
860 /***************************************************************************
864 ***************************************************************************/
866 void v99x8_device::register_write (int reg, int data)
868 static UINT8 const reg_mask[] =
870 0x7e, 0x7b, 0x7f, 0xff, 0x3f, 0xff, 0x3f, 0xff,
871 0xfb, 0xbf, 0x07, 0x03, 0xff, 0xff, 0x07, 0x0f,
872 0x0f, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
873 0x00, 0x7f, 0x3f, 0x07
878 data &= reg_mask[reg];
879 if (m_cont_reg[reg] == data)
885 LOG(("V9938: Attempted to write to non-existant R#%d\n", reg));
889 /*update_command ();*/
892 // registers that affect interrupt and display mode
895 m_cont_reg[reg] = data;
898 LOG(("v9938: mode = %s\n", v9938_modes[m_mode]));
903 m_cont_reg[reg] = data;
905 m_offset_x = 8 + position_offset(m_cont_reg[18] & 0x0f);
906 // Y offset is only applied once per frame?
910 m_pal_write_first = 0;
913 // color burst registers aren't emulated
917 LOG(("v9938: Write %02xh to R#%d; color burst not emulated\n", data, reg));
922 if (m_model != MODEL_V9958)
924 LOG(("v9938: Attempting to write %02xh to V9958 R#%d\n", data, reg));
930 m_v9958_sp_mode = data & 0x18;
939 command_unit_w (data);
944 LOG(("v9938: Write %02x to R#%d\n", data, reg));
946 m_cont_reg[reg] = data;
949 /***************************************************************************
951 Refresh / render function
953 ***************************************************************************/
955 inline bool v99x8_device::v9938_second_field()
957 return !(((m_cont_reg[9] & 0x04) && !(m_stat_reg[2] & 2)) || m_blink);
961 void v99x8_device::default_border(const scrntype_t *pens, scrntype_t *ln)
966 pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
967 i = _V9938_LONG_WIDTH;
968 while (i--) *ln++ = pen;
971 void v99x8_device::graphic7_border(const scrntype_t *pens, scrntype_t *ln)
976 pen = pens[m_pal_ind256[m_cont_reg[7]]];
977 i = _V9938_LONG_WIDTH;
978 while (i--) *ln++ = pen;
981 void v99x8_device::graphic5_border(const scrntype_t *pens, scrntype_t *ln)
987 pen1 = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
988 pen0 = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
989 i = _V9938_LONG_WIDTH / 2;
990 while (i--) { *ln++ = pen0; *ln++ = pen1; }
993 void v99x8_device::mode_text1(const scrntype_t *pens, scrntype_t *ln, int line)
995 int pattern, x, xx, name, xxx;
996 scrntype_t fg, bg, pen;
997 int nametbl_addr, patterntbl_addr;
999 patterntbl_addr = m_cont_reg[4] << 11;
1000 nametbl_addr = m_cont_reg[2] << 10;
1002 fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1003 bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1007 pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1009 xxx = (m_offset_x + 8) * 2;
1010 while (xxx--) *ln++ = pen;
1014 pattern = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) +
1015 ((line + m_cont_reg[23]) & 7));
1016 for (xx=0;xx<6;xx++)
1018 *ln++ = (pattern & 0x80) ? fg : bg;
1019 *ln++ = (pattern & 0x80) ? fg : bg;
1022 /* width height 212, characters start repeating at the bottom */
1023 name = (name + 1) & 0x3ff;
1026 xxx = ((16 - m_offset_x) + 8) * 2;
1027 while (xxx--) *ln++ = pen;
1030 void v99x8_device::mode_text2(const scrntype_t *pens, scrntype_t *ln, int line)
1032 int pattern, x, charcode, name, xxx, patternmask, colourmask;
1033 scrntype_t fg, bg, fg0, bg0, pen;
1034 int nametbl_addr, patterntbl_addr, colourtbl_addr;
1036 patterntbl_addr = m_cont_reg[4] << 11;
1037 colourtbl_addr = ((m_cont_reg[3] & 0xf8) << 6) + (m_cont_reg[10] << 14);
1039 colourmask = ((m_cont_reg[3] & 7) << 5) | 0x1f; /* cause a bug in Forth+ v1.0 on Geneve */
1041 colourmask = ((m_cont_reg[3] & 7) << 6) | 0x3f; /* verify! */
1043 nametbl_addr = ((m_cont_reg[2] & 0xfc) << 10);
1044 patternmask = ((m_cont_reg[2] & 3) << 10) | 0x3ff; /* seems correct */
1046 fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1047 bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1048 fg0 = pens[m_pal_ind16[m_cont_reg[12] >> 4]];
1049 bg0 = pens[m_pal_ind16[m_cont_reg[12] & 15]];
1053 xxx = (m_offset_x + 8) * 2;
1054 pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1055 while (xxx--) *ln++ = pen;
1059 charcode = m_vram_space->read_byte(nametbl_addr + (name&patternmask));
1062 pattern = m_vram_space->read_byte(colourtbl_addr + ((name/8)&colourmask));
1063 if (pattern & (0x80 >> (name & 7) ) )
1065 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) +
1066 ((line + m_cont_reg[23]) & 7)));
1068 *ln++ = (pattern & 0x80) ? fg0 : bg0;
1069 *ln++ = (pattern & 0x40) ? fg0 : bg0;
1070 *ln++ = (pattern & 0x20) ? fg0 : bg0;
1071 *ln++ = (pattern & 0x10) ? fg0 : bg0;
1072 *ln++ = (pattern & 0x08) ? fg0 : bg0;
1073 *ln++ = (pattern & 0x04) ? fg0 : bg0;
1080 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) +
1081 ((line + m_cont_reg[23]) & 7)));
1083 *ln++ = (pattern & 0x80) ? fg : bg;
1084 *ln++ = (pattern & 0x40) ? fg : bg;
1085 *ln++ = (pattern & 0x20) ? fg : bg;
1086 *ln++ = (pattern & 0x10) ? fg : bg;
1087 *ln++ = (pattern & 0x08) ? fg : bg;
1088 *ln++ = (pattern & 0x04) ? fg : bg;
1093 xxx = (16 - m_offset_x + 8) * 2;
1094 while (xxx--) *ln++ = pen;
1097 void v99x8_device::mode_multi(const scrntype_t *pens, scrntype_t *ln, int line)
1099 int nametbl_addr, patterntbl_addr, colour;
1100 int name, line2, x, xx;
1101 scrntype_t pen, pen_bg;
1103 nametbl_addr = (m_cont_reg[2] << 10);
1104 patterntbl_addr = (m_cont_reg[4] << 11);
1106 line2 = (line - m_cont_reg[23]) & 255;
1107 name = (line2/8)*32;
1109 pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1110 xx = m_offset_x * 2;
1111 while (xx--) *ln++ = pen_bg;
1115 colour = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) + ((line2/4)&7));
1116 pen = pens[m_pal_ind16[colour>>4]];
1126 pen = pens[m_pal_ind16[colour&15]];
1139 xx = (16 - m_offset_x) * 2;
1140 while (xx--) *ln++ = pen_bg;
1143 void v99x8_device::mode_graphic1(const scrntype_t *pens, scrntype_t *ln, int line)
1145 scrntype_t fg, bg, pen;
1146 int nametbl_addr, patterntbl_addr, colourtbl_addr;
1147 int pattern, x, xx, line2, name, charcode, colour, xxx;
1149 nametbl_addr = (m_cont_reg[2] << 10);
1150 colourtbl_addr = (m_cont_reg[3] << 6) + (m_cont_reg[10] << 14);
1151 patterntbl_addr = (m_cont_reg[4] << 11);
1153 line2 = (line - m_cont_reg[23]) & 255;
1155 name = (line2/8)*32;
1157 pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1158 xxx = m_offset_x * 2;
1159 while (xxx--) *ln++ = pen;
1163 charcode = m_vram_space->read_byte(nametbl_addr + name);
1164 colour = m_vram_space->read_byte(colourtbl_addr + charcode/8);
1165 fg = pens[m_pal_ind16[colour>>4]];
1166 bg = pens[m_pal_ind16[colour&15]];
1167 pattern = m_vram_space->read_byte(patterntbl_addr + (charcode * 8 + (line2 & 7)));
1169 for (xx=0;xx<8;xx++)
1171 *ln++ = (pattern & 0x80) ? fg : bg;
1172 *ln++ = (pattern & 0x80) ? fg : bg;
1178 xx = (16 - m_offset_x) * 2;
1179 while (xx--) *ln++ = pen;
1182 void v99x8_device::mode_graphic23(const scrntype_t *pens, scrntype_t *ln, int line)
1184 scrntype_t fg, bg, pen;
1185 int nametbl_addr, patterntbl_addr, colourtbl_addr;
1186 int pattern, x, xx, line2, name, charcode,
1187 colour, colourmask, patternmask, xxx;
1189 colourmask = ((m_cont_reg[3] & 0x7f) * 8) | 7;
1190 patternmask = ((m_cont_reg[4] & 0x03) * 256) | 0xff;
1192 nametbl_addr = (m_cont_reg[2] << 10);
1193 colourtbl_addr = ((m_cont_reg[3] & 0x80) << 6) + (m_cont_reg[10] << 14);
1194 patterntbl_addr = ((m_cont_reg[4] & 0x3c) << 11);
1196 line2 = (line + m_cont_reg[23]) & 255;
1197 name = (line2/8)*32;
1199 pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1200 xxx = m_offset_x * 2;
1201 while (xxx--) *ln++ = pen;
1205 charcode = m_vram_space->read_byte(nametbl_addr + name) + (line2&0xc0)*4;
1206 colour = m_vram_space->read_byte(colourtbl_addr + ((charcode&colourmask)*8+(line2&7)));
1207 pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode&patternmask)*8+(line2&7)));
1208 fg = pens[m_pal_ind16[colour>>4]];
1209 bg = pens[m_pal_ind16[colour&15]];
1210 for (xx=0;xx<8;xx++)
1212 *ln++ = (pattern & 0x80) ? fg : bg;
1213 *ln++ = (pattern & 0x80) ? fg : bg;
1219 xx = (16 - m_offset_x) * 2;
1220 while (xx--) *ln++ = pen;
1223 void v99x8_device::mode_graphic4(const scrntype_t *pens, scrntype_t *ln, int line)
1225 int nametbl_addr, colour;
1226 int line2, linemask, x, xx;
1227 scrntype_t pen, pen_bg;
1229 linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1231 line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1233 nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128;
1234 if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1235 nametbl_addr += 0x8000;
1237 pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1238 xx = m_offset_x * 2;
1239 while (xx--) *ln++ = pen_bg;
1243 colour = m_vram_space->read_byte(nametbl_addr++);
1244 pen = pens[m_pal_ind16[colour>>4]];
1247 pen = pens[m_pal_ind16[colour&15]];
1252 xx = (16 - m_offset_x) * 2;
1253 while (xx--) *ln++ = pen_bg;
1256 void v99x8_device::mode_graphic5(const scrntype_t *pens, scrntype_t *ln, int line)
1258 int nametbl_addr, colour;
1259 int line2, linemask, x, xx;
1260 scrntype_t pen_bg0[4];
1261 scrntype_t pen_bg1[4];
1263 linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1265 line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1267 nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128;
1268 if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1269 nametbl_addr += 0x8000;
1271 pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
1272 pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
1275 while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
1277 x = (m_cont_reg[8] & 0x20) ? 0 : 1;
1281 pen_bg0[x] = pens[m_pal_ind16[x]];
1282 pen_bg1[x] = pens[m_pal_ind16[x]];
1287 colour = m_vram_space->read_byte(nametbl_addr++);
1289 *ln++ = pen_bg0[colour>>6];
1290 *ln++ = pen_bg1[(colour>>4)&3];
1291 *ln++ = pen_bg0[(colour>>2)&3];
1292 *ln++ = pen_bg1[(colour&3)];
1295 pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]];
1296 pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]];
1297 xx = 16 - m_offset_x;
1298 while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; }
1301 void v99x8_device::mode_graphic6(const scrntype_t *pens, scrntype_t *ln, int line)
1304 int line2, linemask, x, xx, nametbl_addr;
1305 scrntype_t pen_bg, fg0;
1308 linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1310 line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1312 nametbl_addr = line2 << 8 ;
1313 if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1314 nametbl_addr += 0x10000;
1316 pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]];
1317 xx = m_offset_x * 2;
1318 while (xx--) *ln++ = pen_bg;
1320 if (m_cont_reg[2] & 0x40)
1325 colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1326 fg0 = pens[m_pal_ind16[colour>>4]];
1327 fg1 = pens[m_pal_ind16[colour&15]];
1328 *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1329 *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1330 *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1331 *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1;
1339 colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1340 *ln++ = pens[m_pal_ind16[colour>>4]];
1341 *ln++ = pens[m_pal_ind16[colour&15]];
1346 xx = (16 - m_offset_x) * 2;
1347 while (xx--) *ln++ = pen_bg;
1350 void v99x8_device::mode_graphic7(const scrntype_t *pens, scrntype_t *ln, int line)
1353 int line2, linemask, x, xx, nametbl_addr;
1354 scrntype_t pen, pen_bg;
1356 linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7;
1358 line2 = ((line + m_cont_reg[23]) & linemask) & 255;
1360 nametbl_addr = line2 << 8;
1361 if ( (m_cont_reg[2] & 0x20) && v9938_second_field() )
1362 nametbl_addr += 0x10000;
1364 pen_bg = pens[m_pal_ind256[m_cont_reg[7]]];
1365 xx = m_offset_x * 2;
1366 while (xx--) *ln++ = pen_bg;
1368 if ((m_v9958_sp_mode & 0x18) == 0x08) // v9958 screen 12, puzzle star title screen
1375 colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1377 colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1379 colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1381 colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1383 ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 |
1384 (colour[2] & 7) << 5 | (colour[3] & 7) << 8;
1386 *ln++ = pens[s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]];
1387 *ln++ = pens[s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]];
1389 *ln++ = pens[s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]];
1390 *ln++ = pens[s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]];
1392 *ln++ = pens[s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]];
1393 *ln++ = pens[s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]];
1395 *ln++ = pens[s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]];
1396 *ln++ = pens[s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]];
1401 else if ((m_v9958_sp_mode & 0x18) == 0x18) // v9958 screen 10/11, puzzle star & sexy boom gameplay
1408 colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1410 colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1412 colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1414 colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1416 ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 |
1417 (colour[2] & 7) << 5 | (colour[3] & 7) << 8;
1419 *ln++ = pens[colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]];
1420 *ln++ = pens[colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]];
1422 *ln++ = pens[colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]];
1423 *ln++ = pens[colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]];
1425 *ln++ = pens[colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]];
1426 *ln++ = pens[colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]];
1428 *ln++ = pens[colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]];
1429 *ln++ = pens[colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]];
1434 else if (m_cont_reg[2] & 0x40)
1439 colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1440 pen = pens[m_pal_ind256[colour]];
1441 *ln++ = pen; *ln++ = pen;
1442 *ln++ = pen; *ln++ = pen;
1443 *ln++ = pen; *ln++ = pen;
1444 *ln++ = pen; *ln++ = pen;
1445 *ln++ = pen; *ln++ = pen;
1446 *ln++ = pen; *ln++ = pen;
1447 *ln++ = pen; *ln++ = pen;
1448 *ln++ = pen; *ln++ = pen;
1456 colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1));
1457 pen = pens[m_pal_ind256[colour]];
1464 xx = (16 - m_offset_x) * 2;
1465 while (xx--) *ln++ = pen_bg;
1468 void v99x8_device::mode_unknown(const scrntype_t *pens, scrntype_t *ln, int line)
1473 fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]];
1474 bg = pens[m_pal_ind16[m_cont_reg[7] & 15]];
1477 while (x--) *ln++ = bg;
1480 while (x--) *ln++ = fg;
1482 x = (16 - m_offset_x) * 2;
1483 while (x--) *ln++ = bg;
1486 void v99x8_device::default_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1489 ln += m_offset_x * 2;
1495 *ln++ = pens[m_pal_ind16[col[i]&0x0f]];
1496 *ln++ = pens[m_pal_ind16[col[i]&0x0f]];
1505 void v99x8_device::graphic5_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1508 ln += m_offset_x * 2;
1514 *ln++ = pens[m_pal_ind16[(col[i]>>2)&0x03]];
1515 *ln++ = pens[m_pal_ind16[col[i]&0x03]];
1525 void v99x8_device::graphic7_draw_sprite(const scrntype_t *pens, scrntype_t *ln, UINT8 *col)
1527 static const UINT16 g7_ind16[16] = {
1528 0, 2, 192, 194, 48, 50, 240, 242,
1529 482, 7, 448, 455, 56, 63, 504, 511 };
1532 ln += m_offset_x * 2;
1538 *ln++ = pens[g7_ind16[col[i]&0x0f]];
1539 *ln++ = pens[g7_ind16[col[i]&0x0f]];
1549 void v99x8_device::sprite_mode1 (int line, UINT8 *col)
1551 int attrtbl_addr, patterntbl_addr, pattern_addr;
1552 int x, y, p, height, c, p2, i, n, pattern;
1554 memset(col, 0, 256);
1556 // are sprites disabled?
1557 if (m_cont_reg[8] & 0x02) return;
1559 attrtbl_addr = (m_cont_reg[5] << 7) + (m_cont_reg[11] << 15);
1560 patterntbl_addr = (m_cont_reg[6] << 11);
1562 // 16x16 or 8x8 sprites
1563 height = (m_cont_reg[1] & 2) ? 16 : 8;
1564 // magnified sprites (zoomed)
1565 if (m_cont_reg[1] & 1) height *= 2;
1570 y = m_vram_space->read_byte(attrtbl_addr);
1571 if (y == 208) break;
1572 y = (y - m_cont_reg[23]) & 255;
1578 // if sprite in range, has to be drawn
1579 if ( (line >= y) && (line < (y + height) ) )
1583 // max maximum sprites per line!
1584 if ( !(m_stat_reg[0] & 0x40) )
1585 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p;
1590 x = m_vram_space->read_byte(attrtbl_addr + 1);
1591 if (m_vram_space->read_byte(attrtbl_addr + 3) & 0x80) x -= 32;
1594 pattern = m_vram_space->read_byte(attrtbl_addr + 2);
1595 if (m_cont_reg[1] & 2)
1598 pattern_addr = patterntbl_addr + pattern * 8 + ((m_cont_reg[1] & 1) ? n/2 : n);
1599 pattern = (m_vram_space->read_byte(pattern_addr) << 8) | m_vram_space->read_byte(pattern_addr+16);
1602 c = m_vram_space->read_byte(attrtbl_addr + 3) & 0x0f;
1608 if (n == 0) pattern = m_vram_space->read_byte(pattern_addr);
1609 else if ( (n == 1) && (m_cont_reg[1] & 2) ) pattern = m_vram_space->read_byte(pattern_addr + 16);
1618 if ( (x >= 0) && (x < 256) )
1622 // we have a collision!
1624 m_stat_reg[0] |= 0x20;
1626 if ( !(col[x] & 0x80) )
1628 if (c || (m_cont_reg[8] & 0x20) )
1634 // if zoomed, draw another pixel
1635 if (m_cont_reg[1] & 1)
1637 if (col[x+1] & 0x40)
1639 // we have a collision!
1641 m_stat_reg[0] |= 0x20;
1643 if ( !(col[x+1] & 0x80) )
1645 if (c || (m_cont_reg[8] & 0x20) )
1646 col[x+1] |= 0xc0 | c;
1653 if (m_cont_reg[1] & 1) x += 2; else x++;
1666 if ( !(m_stat_reg[0] & 0x40) )
1667 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p;
1670 void v99x8_device::sprite_mode2 (int line, UINT8 *col)
1672 int attrtbl_addr, patterntbl_addr, pattern_addr, colourtbl_addr;
1673 int x, i, y, p, height, c, p2, n, pattern, colourmask, first_cc_seen;
1675 memset(col, 0, 256);
1677 // are sprites disabled?
1678 if (m_cont_reg[8] & 0x02) return;
1680 attrtbl_addr = ( (m_cont_reg[5] & 0xfc) << 7) + (m_cont_reg[11] << 15);
1681 colourtbl_addr = ( (m_cont_reg[5] & 0xf8) << 7) + (m_cont_reg[11] << 15);
1682 patterntbl_addr = (m_cont_reg[6] << 11);
1683 colourmask = ( (m_cont_reg[5] & 3) << 3) | 0x7; // check this!
1685 // 16x16 or 8x8 sprites
1686 height = (m_cont_reg[1] & 2) ? 16 : 8;
1687 // magnified sprites (zoomed)
1688 if (m_cont_reg[1] & 1) height *= 2;
1690 p2 = p = first_cc_seen = 0;
1693 y = vram_read(attrtbl_addr);
1694 if (y == 216) break;
1695 y = (y - m_cont_reg[23]) & 255;
1701 // if sprite in range, has to be drawn
1702 if ( (line >= y) && (line < (y + height) ) )
1706 // max maximum sprites per line!
1707 if ( !(m_stat_reg[0] & 0x40) )
1708 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p;
1713 n = line - y; if (m_cont_reg[1] & 1) n /= 2;
1715 c = vram_read(colourtbl_addr + (((p&colourmask)*16) + n));
1717 // don't draw all sprite with CC set before any sprites
1718 // with CC = 0 are seen on this line
1722 goto skip_first_cc_set;
1728 pattern = vram_read(attrtbl_addr + 2);
1729 if (m_cont_reg[1] & 2)
1731 pattern_addr = patterntbl_addr + pattern * 8 + n;
1732 pattern = (vram_read(pattern_addr) << 8) | vram_read(pattern_addr + 16);
1735 x = vram_read(attrtbl_addr + 1);
1736 if (c & 0x80) x -= 32;
1738 n = (m_cont_reg[1] & 2) ? 16 : 8;
1741 for (i=0;i<=(m_cont_reg[1] & 1);i++)
1743 if ( (x >= 0) && (x < 256) )
1745 if ( (pattern & 0x8000) && !(col[x] & 0x10) )
1747 if ( (c & 15) || (m_cont_reg[8] & 0x20) )
1751 if (col[x] & 0x20) col[x] |= 0x10;
1753 col[x] |= 0x20 | (c & 15);
1763 if ( !(c & 0x40) && (col[x] & 0x20) )
1767 if ( !(c & 0x60) && (pattern & 0x8000) )
1771 // sprite collision!
1773 m_stat_reg[0] |= 0x20;
1795 if ( !(m_stat_reg[0] & 0x40) )
1796 m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p;
1800 const v99x8_device::v99x8_mode v99x8_device::s_modes[] = {
1802 &v99x8_device::mode_text1,
1803 &v99x8_device::default_border,
1808 &v99x8_device::mode_multi,
1809 &v99x8_device::default_border,
1810 &v99x8_device::sprite_mode1,
1811 &v99x8_device::default_draw_sprite
1814 &v99x8_device::mode_graphic1,
1815 &v99x8_device::default_border,
1816 &v99x8_device::sprite_mode1,
1817 &v99x8_device::default_draw_sprite
1820 &v99x8_device::mode_graphic23,
1821 &v99x8_device::default_border,
1822 &v99x8_device::sprite_mode1,
1823 &v99x8_device::default_draw_sprite
1826 &v99x8_device::mode_graphic23,
1827 &v99x8_device::default_border,
1828 &v99x8_device::sprite_mode2,
1829 &v99x8_device::default_draw_sprite
1832 &v99x8_device::mode_graphic4,
1833 &v99x8_device::default_border,
1834 &v99x8_device::sprite_mode2,
1835 &v99x8_device::default_draw_sprite
1838 &v99x8_device::mode_graphic5,
1839 &v99x8_device::graphic5_border,
1840 &v99x8_device::sprite_mode2,
1841 &v99x8_device::graphic5_draw_sprite
1844 &v99x8_device::mode_graphic6,
1845 &v99x8_device::default_border,
1846 &v99x8_device::sprite_mode2,
1847 &v99x8_device::default_draw_sprite
1850 &v99x8_device::mode_graphic7,
1851 &v99x8_device::graphic7_border,
1852 &v99x8_device::sprite_mode2,
1853 &v99x8_device::graphic7_draw_sprite
1856 &v99x8_device::mode_text2,
1857 &v99x8_device::default_border,
1862 &v99x8_device::mode_unknown,
1863 &v99x8_device::default_border,
1869 void v99x8_device::set_mode()
1873 n = (((m_cont_reg[0] & 0x0e) << 1) | ((m_cont_reg[1] & 0x18) >> 3));
1876 if ( (s_modes[i].m == n) || (s_modes[i].m == 0xff) ) break;
1881 void v99x8_device::refresh_16(int line)
1883 //const pen_t *pens = m_palette->pens();
1884 const scrntype_t *pens = this->pens;
1885 bool double_lines = false;
1887 scrntype_t *ln, *ln2 = NULL;
1889 if (m_cont_reg[9] & 0x08)
1891 // ln = &m_bitmap.pix16(m_scanline*2+((m_stat_reg[2]>>1)&1));
1892 ln = screen+(m_scanline*2+((m_stat_reg[2]>>1)&1))*_V9938_LONG_WIDTH;
1896 // ln = &m_bitmap.pix16(m_scanline*2);
1897 // ln2 = &m_bitmap.pix16(m_scanline*2+1);
1898 ln = screen+(m_scanline*2)*_V9938_LONG_WIDTH;
1899 ln2 = screen+(m_scanline*2+1)*_V9938_LONG_WIDTH;
1900 double_lines = true;
1903 if ( !(m_cont_reg[1] & 0x40) || (m_stat_reg[2] & 0x40) )
1905 (this->*s_modes[m_mode].border_16)(pens, ln);
1909 (this->*s_modes[m_mode].visible_16)(pens, ln, line);
1910 if (s_modes[m_mode].sprites)
1912 (this->*s_modes[m_mode].sprites)(line, col);
1913 (this->*s_modes[m_mode].draw_sprite_16)(pens, ln, col);
1918 my_memcpy(ln2, ln, (512 + 32) * sizeof(scrntype_t));
1921 void v99x8_device::refresh_line(int line)
1925 ind16 = m_pal_ind16[0];
1926 ind256 = m_pal_ind256[0];
1928 if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) )
1930 m_pal_ind16[0] = m_pal_ind16[(m_cont_reg[7] & 0x0f)];
1931 m_pal_ind256[0] = m_pal_ind256[m_cont_reg[7]];
1936 if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) )
1938 m_pal_ind16[0] = ind16;
1939 m_pal_ind256[0] = ind256;
1945 From: awulms@inter.nl.net (Alex Wulms)
1946 *** About the HR/VR topic: this is how it works according to me:
1949 HR is very straightforward:
1950 -HR=1 during 'display time'
1951 -HR=0 during 'horizontal border, horizontal retrace'
1952 I have put 'display time' and 'horizontal border, horizontal retrace' between
1953 quotes because HR does not only flip between 0 and 1 during the display of
1954 the 192/212 display lines, but also during the vertical border and during the
1958 VR is a little bit tricky
1959 -VR always gets set to 0 when the VDP starts with display line 0
1960 -VR gets set to 1 when the VDP reaches display line (192 if LN=0) or (212 if
1962 -The VDP displays contents of VRAM as long as VR=0
1964 As a consequence of this behaviour, it is possible to program the famous
1965 overscan trick, where VRAM contents is shown in the borders:
1966 Generate an interrupt at line 230 (or so) and on this interrupt: set LN=1
1967 Generate an interrupt at line 200 (or so) and on this interrupt: set LN=0
1968 Repeat the above two steps
1970 *** The top/bottom border contents during overscan:
1972 1) The VDP keeps increasing the name table address pointer during bottom
1973 border, vertical retrace and top border
1974 2) The VDP resets the name table address pointer when the first display line
1977 On the other screens:
1978 1) The VDP keeps increasing the name table address pointer during the bottom
1980 2) The VDP resets the name table address pointer such that the top border
1981 contents connects up with the first display line. E.g., when the top border
1982 is 26 lines high, the VDP will take:
1996 *** About the horizontal interrupt
1998 All relevant definitions on a row:
1999 -FH: Bit 0 of status register 1
2000 -IE1: Bit 4 of mode register 0
2001 -IL: Line number in mode register 19
2002 -DL: The line that the VDP is going to display (corrected for vertical scroll)
2003 -IRQ: Interrupt request line of VDP to Z80
2005 At the *start* of every new line (display, bottom border, part of vertical
2006 display), the VDP does:
2007 -FH = (FH && IE1) || (IL==DL)
2009 After reading of status register 1 by the CPU, the VDP does:
2012 Furthermore, the following is true all the time:
2015 The resulting behaviour:
2017 -FH will be set as soon as display of line IL starts
2018 -FH will be reset as soon as status register 1 is read
2019 -FH will be reset as soon as the next display line is reached
2022 -FH and IRQ will be set as soon as display line IL is reached
2023 -FH and IRQ will be reset as soon as status register 1 is read
2025 Another subtile result:
2026 If, while FH and IRQ are set, IE1 gets reset, the next happens:
2027 -IRQ is reset immediately (since IRQ is always FH && IE1)
2028 -FH will be reset as soon as display of the next line starts (unless the next
2032 *** About the vertical interrupt:
2033 Another relevant definition:
2034 -FV: Bit 7 of status register 0
2035 -IE0: Bit 5 of mode register 1
2037 I only know for sure the behaviour when IE0=1:
2038 -FV and IRQ will be set as soon as VR changes from 0 to 1
2039 -FV and IRQ will be reset as soon as status register 0 is read
2041 A consequence is that NO vertical interrupts will be generated during the
2042 overscan trick, described in the VR section above.
2044 I do not know the behaviour of FV when IE0=0. That is the part that I still
2048 void v99x8_device::interrupt_start_vblank()
2051 if (machine.input().code_pressed (KEYCODE_D) )
2053 for (i=0;i<24;i++) osd_printf_debug ("R#%d = %02x\n", i, m_cont_reg[i]);
2057 // at every frame, vdp switches fields
2058 m_stat_reg[2] = (m_stat_reg[2] & 0xfd) | (~m_stat_reg[2] & 2);
2061 if (!(m_cont_reg[13] & 0xf0))
2063 else if (!(m_cont_reg[13] & 0x0f))
2067 // both on and off counter are non-zero: timed blinking
2074 m_blink_count = (m_cont_reg[13] >> 4) * 10;
2076 m_blink_count = (m_cont_reg[13] & 0x0f) * 10;
2081 /***************************************************************************
2085 ***************************************************************************/
2087 /*************************************************************/
2088 /** Completely rewritten by Alex Wulms: **/
2089 /** - VDP Command execution 'in parallel' with CPU **/
2090 /** - Corrected behaviour of VDP commands **/
2091 /** - Made it easier to implement correct S7/8 mapping **/
2092 /** by concentrating VRAM access in one single place **/
2093 /** - Made use of the 'in parallel' VDP command exec **/
2094 /** and correct timing. You must call the function **/
2095 /** LoopVDP() from LoopZ80 in MSX.c. You must call it **/
2096 /** exactly 256 times per screen refresh. **/
2097 /** Started on : 11-11-1999 **/
2098 /** Beta release 1 on: 9-12-1999 **/
2099 /** Beta release 2 on: 20-01-2000 **/
2100 /** - Corrected behaviour of VRM <-> Z80 transfer **/
2101 /** - Improved performance of the code **/
2102 /** Public release 1.0: 20-04-2000 **/
2103 /*************************************************************/
2105 #define VDP_VRMP5(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&255)>>1)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&255)>>1)))
2106 #define VDP_VRMP6(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2)))
2107 //#define VDP_VRMP7(MX, X, Y) ((!MX) ? (((Y&511)<<8) + ((X&511)>>1)) : (EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1)))
2108 #define VDP_VRMP7(MX, X, Y) ((!MX) ? (((X&2)<<15) + ((Y&511)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2))/*(EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1))*/)
2109 //#define VDP_VRMP8(MX, X, Y) ((!MX) ? (((Y&511)<<8) + (X&255)) : (EXPMEM_OFFSET + ((Y&255)<<8) + (X&255)))
2110 #define VDP_VRMP8(MX, X, Y) ((!MX) ? (((X&1)<<16) + ((Y&511)<<7) + ((X>>1)&127)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X>>1)&127))/*(EXPMEM_OFFSET + ((Y&255)<<8) + (X&255))*/)
2112 #define VDP_VRMP(M, MX, X, Y) VDPVRMP(M, MX, X, Y)
2113 #define VDP_POINT(M, MX, X, Y) VDPpoint(M, MX, X, Y)
2114 #define VDP_PSET(M, MX, X, Y, C, O) VDPpset(M, MX, X, Y, C, O)
2117 #define CM_POINT 0x4
2130 /*************************************************************
2131 Many VDP commands are executed in some kind of loop but
2132 essentially, there are only a few basic loop structures
2133 that are re-used. We define the loop structures that are
2134 re-used here so that they have to be entered only once
2135 *************************************************************/
2137 while ((cnt-=delta) > 0) {
2142 #define post__x_y(MX) \
2143 if (!--ANX || ((ADX+=TX)&MX)) { \
2144 if (!(--NY&1023) || (DY+=TY)==-1) \
2153 // Loop over DX, SY, DY
2154 #define post__xyy(MX) \
2155 if ((ADX+=TX)&MX) { \
2156 if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
2163 // Loop over SX, DX, SY, DY
2164 #define post_xxyy(MX) \
2165 if (!--ANX || ((ASX+=TX)&MX) || ((ADX+=TX)&MX)) { \
2166 if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \
2176 /*************************************************************/
2177 /** Variables visible only in this module **/
2178 /*************************************************************/
2179 static const UINT8 Mask[4] = { 0x0F,0x03,0x0F,0xFF };
2180 static const int PPB[4] = { 2,4,2,1 };
2181 static const int PPL[4] = { 256,512,512,256 };
2183 // SprOn SprOn SprOf SprOf
2184 // ScrOf ScrOn ScrOf ScrOn
2185 static const int srch_timing[8]={
2186 818, 1025, 818, 830, // ntsc
2187 696, 854, 696, 684 // pal
2189 static const int line_timing[8]={
2190 1063, 1259, 1063, 1161,
2193 static const int hmmv_timing[8]={
2197 static const int lmmv_timing[8]={
2198 873, 1135, 873, 1056,
2201 static const int ymmm_timing[8]={
2205 static const int hmmm_timing[8]={
2206 818, 1111, 818, 854,
2209 static const int lmmm_timing[8]={
2210 1160, 1599, 1160, 1172,
2214 /** VDPVRMP() **********************************************/
2215 /** Calculate addr of a pixel in vram **/
2216 /*************************************************************/
2217 inline int v99x8_device::VDPVRMP(UINT8 M,int MX,int X,int Y)
2221 case 0: return VDP_VRMP5(MX,X,Y);
2222 case 1: return VDP_VRMP6(MX,X,Y);
2223 case 2: return VDP_VRMP7(MX,X,Y);
2224 case 3: return VDP_VRMP8(MX,X,Y);
2230 /** VDPpoint5() ***********************************************/
2231 /** Get a pixel on screen 5 **/
2232 /*************************************************************/
2233 inline UINT8 v99x8_device::VDPpoint5(int MXS, int SX, int SY)
2235 return (m_vram_space->read_byte(VDP_VRMP5(MXS, SX, SY)) >>
2240 /** VDPpoint6() ***********************************************/
2241 /** Get a pixel on screen 6 **/
2242 /*************************************************************/
2243 inline UINT8 v99x8_device::VDPpoint6(int MXS, int SX, int SY)
2245 return (m_vram_space->read_byte(VDP_VRMP6(MXS, SX, SY)) >>
2250 /** VDPpoint7() ***********************************************/
2251 /** Get a pixel on screen 7 **/
2252 /*************************************************************/
2253 inline UINT8 v99x8_device::VDPpoint7(int MXS, int SX, int SY)
2255 return (m_vram_space->read_byte(VDP_VRMP7(MXS, SX, SY)) >>
2260 /** VDPpoint8() ***********************************************/
2261 /** Get a pixel on screen 8 **/
2262 /*************************************************************/
2263 inline UINT8 v99x8_device::VDPpoint8(int MXS, int SX, int SY)
2265 return m_vram_space->read_byte(VDP_VRMP8(MXS, SX, SY));
2268 /** VDPpoint() ************************************************/
2269 /** Get a pixel on a screen **/
2270 /*************************************************************/
2271 inline UINT8 v99x8_device::VDPpoint(UINT8 SM, int MXS, int SX, int SY)
2275 case 0: return VDPpoint5(MXS,SX,SY);
2276 case 1: return VDPpoint6(MXS,SX,SY);
2277 case 2: return VDPpoint7(MXS,SX,SY);
2278 case 3: return VDPpoint8(MXS,SX,SY);
2284 /** VDPpsetlowlevel() ****************************************/
2285 /** Low level function to set a pixel on a screen **/
2286 /** Make it inline to make it fast **/
2287 /*************************************************************/
2288 inline void v99x8_device::VDPpsetlowlevel(int addr, UINT8 CL, UINT8 M, UINT8 OP)
2290 // If this turns out to be too slow, get a pointer to the address space
2291 // and work directly on it.
2292 UINT8 val = m_vram_space->read_byte(addr);
2295 case 0: val = (val & M) | CL; break;
2296 case 1: val = val & (CL | M); break;
2297 case 2: val |= CL; break;
2298 case 3: val ^= CL; break;
2299 case 4: val = (val & M) | ~(CL | M); break;
2300 case 8: if (CL) val = (val & M) | CL; break;
2301 case 9: if (CL) val = val & (CL | M); break;
2302 case 10: if (CL) val |= CL; break;
2303 case 11: if (CL) val ^= CL; break;
2304 case 12: if (CL) val = (val & M) | ~(CL|M); break;
2306 LOG(("v9938: invalid operation %d in pset\n", OP));
2309 m_vram_space->write_byte(addr, val);
2312 /** VDPpset5() ***********************************************/
2313 /** Set a pixel on screen 5 **/
2314 /*************************************************************/
2315 inline void v99x8_device::VDPpset5(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2317 UINT8 SH = ((~DX)&1)<<2;
2318 VDPpsetlowlevel(VDP_VRMP5(MXD, DX, DY), CL << SH, ~(15<<SH), OP);
2321 /** VDPpset6() ***********************************************/
2322 /** Set a pixel on screen 6 **/
2323 /*************************************************************/
2324 inline void v99x8_device::VDPpset6(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2326 UINT8 SH = ((~DX)&3)<<1;
2328 VDPpsetlowlevel(VDP_VRMP6(MXD, DX, DY), CL << SH, ~(3<<SH), OP);
2331 /** VDPpset7() ***********************************************/
2332 /** Set a pixel on screen 7 **/
2333 /*************************************************************/
2334 inline void v99x8_device::VDPpset7(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2336 UINT8 SH = ((~DX)&1)<<2;
2338 VDPpsetlowlevel(VDP_VRMP7(MXD, DX, DY), CL << SH, ~(15<<SH), OP);
2341 /** VDPpset8() ***********************************************/
2342 /** Set a pixel on screen 8 **/
2343 /*************************************************************/
2344 inline void v99x8_device::VDPpset8(int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2346 VDPpsetlowlevel(VDP_VRMP8(MXD, DX, DY), CL, 0, OP);
2349 /** VDPpset() ************************************************/
2350 /** Set a pixel on a screen **/
2351 /*************************************************************/
2352 inline void v99x8_device::VDPpset(UINT8 SM, int MXD, int DX, int DY, UINT8 CL, UINT8 OP)
2355 case 0: VDPpset5(MXD, DX, DY, CL, OP); break;
2356 case 1: VDPpset6(MXD, DX, DY, CL, OP); break;
2357 case 2: VDPpset7(MXD, DX, DY, CL, OP); break;
2358 case 3: VDPpset8(MXD, DX, DY, CL, OP); break;
2362 /** get_vdp_timing_value() **************************************/
2363 /** Get timing value for a certain VDP command **/
2364 /*************************************************************/
2365 int v99x8_device::get_vdp_timing_value(const int *timing_values)
2367 return(timing_values[((m_cont_reg[1]>>6)&1)|(m_cont_reg[8]&2)|((m_cont_reg[9]<<1)&4)]);
2370 /** SrchEgine()** ********************************************/
2371 /** Search a dot **/
2372 /*************************************************************/
2373 void v99x8_device::srch_engine()
2380 int MXD = m_mmc.MXD;
2384 delta = get_vdp_timing_value(srch_timing);
2385 cnt = m_vdp_ops_count;
2387 #define post_srch(MX) \
2388 { m_stat_reg[2]|=0x10; /* Border detected */ break; } \
2389 if ((SX+=TX) & MX) { m_stat_reg[2] &= 0xEF; /* Border not detected */ break; }
2392 case V9938_MODE_GRAPHIC4: pre_loop if ((VDPpoint5(MXD, SX, SY)==CL) ^ANX) post_srch(256) post_loop
2394 case V9938_MODE_GRAPHIC5: pre_loop if ((VDPpoint6(MXD, SX, SY)==CL) ^ANX) post_srch(512) post_loop
2396 case V9938_MODE_GRAPHIC6: pre_loop if ((VDPpoint7(MXD, SX, SY)==CL) ^ANX) post_srch(512) post_loop
2398 case V9938_MODE_GRAPHIC7: pre_loop if ((VDPpoint8(MXD, SX, SY)==CL) ^ANX) post_srch(256) post_loop
2402 if ((m_vdp_ops_count=cnt)>0) {
2403 // Command execution done
2404 m_stat_reg[2] &= 0xFE;
2405 m_vdp_engine = NULL;
2406 // Update SX in VDP registers
2407 m_stat_reg[8] = SX & 0xFF;
2408 m_stat_reg[9] = (SX>>8) | 0xFE;
2415 /** LineEgine()** ********************************************/
2417 /*************************************************************/
2418 void v99x8_device::line_engine()
2430 int MXD = m_mmc.MXD;
2434 delta = get_vdp_timing_value(line_timing);
2435 cnt = m_vdp_ops_count;
2437 #define post_linexmaj(MX) \
2439 if ((ASX-=NY)<0) { \
2443 ASX&=1023; /* Mask to 10 bits range */\
2444 if (ADX++==NX || (DX&MX)) \
2448 #define post_lineymaj(MX) \
2450 if ((ASX-=NY)<0) { \
2454 ASX&=1023; /* Mask to 10 bits range */\
2455 if (ADX++==NX || (DX&MX)) \
2459 if ((m_cont_reg[45]&0x01)==0)
2460 // X-Axis is major direction
2463 case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_linexmaj(256)
2465 case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_linexmaj(512)
2467 case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_linexmaj(512)
2469 case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_linexmaj(256)
2473 // Y-Axis is major direction
2476 case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_lineymaj(256)
2478 case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_lineymaj(512)
2480 case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_lineymaj(512)
2482 case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_lineymaj(256)
2486 if ((m_vdp_ops_count=cnt)>0) {
2487 // Command execution done
2488 m_stat_reg[2]&=0xFE;
2490 m_cont_reg[38]=DY & 0xFF;
2491 m_cont_reg[39]=(DY>>8) & 0x03;
2501 /** lmmv_engine() *********************************************/
2503 /*************************************************************/
2504 void v99x8_device::lmmv_engine()
2516 int MXD = m_mmc.MXD;
2520 delta = get_vdp_timing_value(lmmv_timing);
2521 cnt = m_vdp_ops_count;
2525 case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, CL, LO); post__x_y(256)
2527 case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, CL, LO); post__x_y(512)
2529 case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, CL, LO); post__x_y(512)
2531 case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, CL, LO); post__x_y(256)
2535 if ((m_vdp_ops_count=cnt)>0) {
2536 // Command execution done
2537 m_stat_reg[2]&=0xFE;
2541 m_cont_reg[38]=DY & 0xFF;
2542 m_cont_reg[39]=(DY>>8) & 0x03;
2543 m_cont_reg[42]=NY & 0xFF;
2544 m_cont_reg[43]=(NY>>8) & 0x03;
2554 /** lmmm_engine() *********************************************/
2555 /** Vram -> Vram **/
2556 /*************************************************************/
2557 void v99x8_device::lmmm_engine()
2571 int MXS = m_mmc.MXS;
2572 int MXD = m_mmc.MXD;
2576 delta = get_vdp_timing_value(lmmm_timing);
2577 cnt = m_vdp_ops_count;
2581 case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, VDPpoint5(MXS, ASX, SY), LO); post_xxyy(256)
2583 case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, VDPpoint6(MXS, ASX, SY), LO); post_xxyy(512)
2585 case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, VDPpoint7(MXS, ASX, SY), LO); post_xxyy(512)
2587 case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, VDPpoint8(MXS, ASX, SY), LO); post_xxyy(256)
2591 if ((m_vdp_ops_count=cnt)>0) {
2592 // Command execution done
2593 m_stat_reg[2]&=0xFE;
2602 m_cont_reg[42]=NY & 0xFF;
2603 m_cont_reg[43]=(NY>>8) & 0x03;
2604 m_cont_reg[34]=SY & 0xFF;
2605 m_cont_reg[35]=(SY>>8) & 0x03;
2606 m_cont_reg[38]=DY & 0xFF;
2607 m_cont_reg[39]=(DY>>8) & 0x03;
2619 /** lmcm_engine() *********************************************/
2621 /*************************************************************/
2622 void v99x8_device::lmcm_engine()
2624 if ((m_stat_reg[2]&0x80)!=0x80) {
2625 m_stat_reg[7]=m_cont_reg[44]=VDP_POINT(((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0, m_mmc.MXS, m_mmc.ASX, m_mmc.SY);
2626 m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing);
2627 m_stat_reg[2]|=0x80;
2629 if (!--m_mmc.ANX || ((m_mmc.ASX+=m_mmc.TX)&m_mmc.MX)) {
2630 if (!(--m_mmc.NY & 1023) || (m_mmc.SY+=m_mmc.TY)==-1) {
2631 m_stat_reg[2]&=0xFE;
2635 m_cont_reg[42]=m_mmc.NY & 0xFF;
2636 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2637 m_cont_reg[34]=m_mmc.SY & 0xFF;
2638 m_cont_reg[35]=(m_mmc.SY>>8) & 0x03;
2648 /** lmmc_engine() *********************************************/
2650 /*************************************************************/
2651 void v99x8_device::lmmc_engine()
2653 if ((m_stat_reg[2]&0x80)!=0x80) {
2654 UINT8 SM=((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0;
2656 m_stat_reg[7]=m_cont_reg[44]&=Mask[SM];
2657 VDP_PSET(SM, m_mmc.MXD, m_mmc.ADX, m_mmc.DY, m_cont_reg[44], m_mmc.LO);
2658 m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing);
2659 m_stat_reg[2]|=0x80;
2661 if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) {
2662 if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) {
2663 m_stat_reg[2]&=0xFE;
2667 m_cont_reg[42]=m_mmc.NY & 0xFF;
2668 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2669 m_cont_reg[38]=m_mmc.DY & 0xFF;
2670 m_cont_reg[39]=(m_mmc.DY>>8) & 0x03;
2680 /** hmmv_engine() *********************************************/
2681 /** VDP --> Vram **/
2682 /*************************************************************/
2683 void v99x8_device::hmmv_engine()
2694 int MXD = m_mmc.MXD;
2698 delta = get_vdp_timing_value(hmmv_timing);
2699 cnt = m_vdp_ops_count;
2703 case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), CL); post__x_y(256)
2705 case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), CL); post__x_y(512)
2707 case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), CL); post__x_y(512)
2709 case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), CL); post__x_y(256)
2713 if ((m_vdp_ops_count=cnt)>0) {
2714 // Command execution done
2715 m_stat_reg[2]&=0xFE;
2719 m_cont_reg[42]=NY & 0xFF;
2720 m_cont_reg[43]=(NY>>8) & 0x03;
2721 m_cont_reg[38]=DY & 0xFF;
2722 m_cont_reg[39]=(DY>>8) & 0x03;
2732 /** hmmm_engine() *********************************************/
2733 /** Vram -> Vram **/
2734 /*************************************************************/
2735 void v99x8_device::hmmm_engine()
2748 int MXS = m_mmc.MXS;
2749 int MXD = m_mmc.MXD;
2753 delta = get_vdp_timing_value(hmmm_timing);
2754 cnt = m_vdp_ops_count;
2758 case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP5(MXS, ASX, SY))); post_xxyy(256)
2760 case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP6(MXS, ASX, SY))); post_xxyy(512)
2762 case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP7(MXS, ASX, SY))); post_xxyy(512)
2764 case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP8(MXS, ASX, SY))); post_xxyy(256)
2768 if ((m_vdp_ops_count=cnt)>0) {
2769 // Command execution done
2770 m_stat_reg[2]&=0xFE;
2779 m_cont_reg[42]=NY & 0xFF;
2780 m_cont_reg[43]=(NY>>8) & 0x03;
2781 m_cont_reg[34]=SY & 0xFF;
2782 m_cont_reg[35]=(SY>>8) & 0x03;
2783 m_cont_reg[38]=DY & 0xFF;
2784 m_cont_reg[39]=(DY>>8) & 0x03;
2796 /** ymmm_engine() *********************************************/
2797 /** Vram -> Vram **/
2798 /*************************************************************/
2800 void v99x8_device::ymmm_engine()
2809 int MXD = m_mmc.MXD;
2813 delta = get_vdp_timing_value(ymmm_timing);
2814 cnt = m_vdp_ops_count;
2818 case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP5(MXD, ADX, SY))); post__xyy(256)
2820 case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP6(MXD, ADX, SY))); post__xyy(512)
2822 case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP7(MXD, ADX, SY))); post__xyy(512)
2824 case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP8(MXD, ADX, SY))); post__xyy(256)
2828 if ((m_vdp_ops_count=cnt)>0) {
2829 // Command execution done
2830 m_stat_reg[2]&=0xFE;
2839 m_cont_reg[42]=NY & 0xFF;
2840 m_cont_reg[43]=(NY>>8) & 0x03;
2841 m_cont_reg[34]=SY & 0xFF;
2842 m_cont_reg[35]=(SY>>8) & 0x03;
2843 m_cont_reg[38]=DY & 0xFF;
2844 m_cont_reg[39]=(DY>>8) & 0x03;
2854 /** hmmc_engine() *********************************************/
2856 /*************************************************************/
2857 void v99x8_device::hmmc_engine()
2859 if ((m_stat_reg[2]&0x80)!=0x80) {
2860 m_vram_space->write_byte(VDP_VRMP(((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0, m_mmc.MXD, m_mmc.ADX, m_mmc.DY), m_cont_reg[44]);
2861 m_vdp_ops_count -= get_vdp_timing_value(hmmv_timing);
2862 m_stat_reg[2]|=0x80;
2864 if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) {
2865 if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) {
2866 m_stat_reg[2]&=0xFE;
2870 m_cont_reg[42]=m_mmc.NY & 0xFF;
2871 m_cont_reg[43]=(m_mmc.NY>>8) & 0x03;
2872 m_cont_reg[38]=m_mmc.DY & 0xFF;
2873 m_cont_reg[39]=(m_mmc.DY>>8) & 0x03;
2883 /** VDPWrite() ***********************************************/
2884 /** Use this function to transfer pixel(s) from CPU to m_ **/
2885 /*************************************************************/
2886 void v99x8_device::cpu_to_vdp(UINT8 V)
2888 m_stat_reg[2]&=0x7F;
2889 m_stat_reg[7]=m_cont_reg[44]=V;
2890 if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
2893 /** VDPRead() ************************************************/
2894 /** Use this function to transfer pixel(s) from VDP to CPU. **/
2895 /*************************************************************/
2896 UINT8 v99x8_device::vdp_to_cpu()
2898 m_stat_reg[2]&=0x7F;
2899 if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
2900 return(m_cont_reg[44]);
2903 /** report_vdp_command() ***************************************/
2904 /** Report VDP Command to be executed **/
2905 /*************************************************************/
2906 void v99x8_device::report_vdp_command(UINT8 Op)
2908 static const char *const Ops[16] =
2910 "SET ","AND ","OR ","XOR ","NOT ","NOP ","NOP ","NOP ",
2911 "TSET","TAND","TOR ","TXOR","TNOT","NOP ","NOP ","NOP "
2913 static const char *const Commands[16] =
2915 " ABRT"," ????"," ????"," ????","POINT"," PSET"," SRCH"," LINE",
2916 " LMMV"," LMMM"," LMCM"," LMMC"," HMMV"," HMMM"," YMMM"," HMMC"
2920 int SX,SY, DX,DY, NX,NY;
2923 CL = m_cont_reg[44];
2924 SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511;
2925 SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023;
2926 DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511;
2927 DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023;
2928 NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023;
2929 NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023;
2933 LOG(("V9938: Opcode %02Xh %s-%s (%d,%d)->(%d,%d),%d [%d,%d]%s\n",
2934 Op, Commands[CM], Ops[LO],
2935 SX,SY, DX,DY, CL, m_cont_reg[45]&0x04? -NX:NX,
2936 m_cont_reg[45]&0x08? -NY:NY,
2937 m_cont_reg[45]&0x70? " on ExtVRAM":""
2941 /** VDPDraw() ************************************************/
2942 /** Perform a given V9938 operation Op. **/
2943 /*************************************************************/
2944 UINT8 v99x8_device::command_unit_w(UINT8 Op)
2948 // V9938 ops only work in SCREENs 5-8
2952 SM = m_mode-5; // Screen mode index 0..3
2955 if ((m_mmc.CM & 0x0C) != 0x0C && m_mmc.CM != 0)
2956 // Dot operation: use only relevant bits of color
2957 m_stat_reg[7]=(m_cont_reg[44]&=Mask[SM]);
2960 report_vdp_command(Op);
2964 m_stat_reg[2]&=0xFE;
2968 m_stat_reg[2]&=0xFE;
2970 m_stat_reg[7]=m_cont_reg[44]=
2971 VDP_POINT(SM, (m_cont_reg[45] & 0x10) != 0,
2972 m_cont_reg[32]+((int)m_cont_reg[33]<<8),
2973 m_cont_reg[34]+((int)m_cont_reg[35]<<8));
2976 m_stat_reg[2]&=0xFE;
2978 VDP_PSET(SM, (m_cont_reg[45] & 0x20) != 0,
2979 m_cont_reg[36]+((int)m_cont_reg[37]<<8),
2980 m_cont_reg[38]+((int)m_cont_reg[39]<<8),
2985 m_vdp_engine=&v99x8_device::srch_engine;
2988 m_vdp_engine=&v99x8_device::line_engine;
2991 m_vdp_engine=&v99x8_device::lmmv_engine;
2994 m_vdp_engine=&v99x8_device::lmmm_engine;
2997 m_vdp_engine=&v99x8_device::lmcm_engine;
3000 m_vdp_engine=&v99x8_device::lmmc_engine;
3003 m_vdp_engine=&v99x8_device::hmmv_engine;
3006 m_vdp_engine=&v99x8_device::hmmm_engine;
3009 m_vdp_engine=&v99x8_device::ymmm_engine;
3012 m_vdp_engine=&v99x8_device::hmmc_engine;
3015 LOG(("V9938: Unrecognized opcode %02Xh\n",Op));
3019 // Fetch unconditional arguments
3020 m_mmc.SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511;
3021 m_mmc.SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023;
3022 m_mmc.DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511;
3023 m_mmc.DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023;
3024 m_mmc.NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023;
3025 m_mmc.TY = m_cont_reg[45]&0x08? -1:1;
3027 m_mmc.CL = m_cont_reg[44];
3029 m_mmc.MXS = (m_cont_reg[45] & 0x10) != 0;
3030 m_mmc.MXD = (m_cont_reg[45] & 0x20) != 0;
3032 // Argument depends on UINT8 or dot operation
3033 if ((m_mmc.CM & 0x0C) == 0x0C) {
3034 m_mmc.TX = m_cont_reg[45]&0x04? -PPB[SM]:PPB[SM];
3035 m_mmc.NX = ((m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023)/PPB[SM];
3038 m_mmc.TX = m_cont_reg[45]&0x04? -1:1;
3039 m_mmc.NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023;
3042 // X loop variables are treated specially for LINE command
3043 if (m_mmc.CM == CM_LINE) {
3044 m_mmc.ASX=((m_mmc.NX-1)>>1);
3048 m_mmc.ASX = m_mmc.SX;
3049 m_mmc.ADX = m_mmc.DX;
3052 // NX loop variable is treated specially for SRCH command
3053 if (m_mmc.CM == CM_SRCH)
3054 m_mmc.ANX=(m_cont_reg[45]&0x02)!=0; // Do we look for "==" or "!="?
3056 m_mmc.ANX = m_mmc.NX;
3058 // Command execution started
3059 m_stat_reg[2]|=0x01;
3061 // Start execution if we still have time slices
3062 if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
3064 // Operation successfully initiated
3068 /** LoopVDP() ************************************************
3069 Run X steps of active VDP command
3070 *************************************************************/
3071 void v99x8_device::update_command()
3073 if(m_vdp_ops_count<=0)
3075 m_vdp_ops_count+=13662;
3076 if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)();
3080 m_vdp_ops_count=13662;
3081 if(m_vdp_engine) (this->*m_vdp_engine)();
3085 /*static MACHINE_CONFIG_FRAGMENT( v9938 )
3086 MCFG_PALETTE_ADD("palette", 512)
3087 MCFG_PALETTE_INIT_OWNER(v9938_device, v9938)
3088 MACHINE_CONFIG_END*/
3090 //-------------------------------------------------
3091 // machine_config_additions - return a pointer to
3092 // the device's machine fragment
3093 //-------------------------------------------------
3095 /*machine_config_constructor v9938_device::device_mconfig_additions() const
3097 return MACHINE_CONFIG_NAME( v9938 );
3100 /*static MACHINE_CONFIG_FRAGMENT( v9958 )
3101 MCFG_PALETTE_ADD("palette", 19780)
3102 MCFG_PALETTE_INIT_OWNER(v9958_device, v9958)
3103 MACHINE_CONFIG_END*/
3105 //-------------------------------------------------
3106 // machine_config_additions - return a pointer to
3107 // the device's machine fragment
3108 //-------------------------------------------------
3110 /*machine_config_constructor v9958_device::device_mconfig_additions() const
3112 return MACHINE_CONFIG_NAME( v9958 );
3117 /* for common source code project */
3118 void v99x8_device::draw_screen()
3120 if(emu->now_waiting_in_debugger) {
3122 // int tmp_offset_x = m_offset_x;
3123 int tmp_offset_y = m_offset_y;
3124 int tmp_visible_y = m_visible_y;
3125 UINT8 tmp_stat_reg[10];
3126 memcpy(tmp_stat_reg, m_stat_reg, sizeof(m_stat_reg));
3127 UINT8 tmp_int_state = m_int_state;
3128 int tmp_scanline = m_scanline;
3129 int tmp_blink = m_blink;
3130 int tmp_blink_count = m_blink_count;
3131 UINT16 tmp_pal_ind16[16];
3132 UINT16 tmp_pal_ind256[256];
3133 memcpy(tmp_pal_ind16, m_pal_ind16, sizeof(m_pal_ind16));
3134 memcpy(tmp_pal_ind256, m_pal_ind256, sizeof(m_pal_ind256));
3135 // mmc_t tmp_mmc = m_mmc;
3136 int tmp_vdp_ops_count = m_vdp_ops_count;
3137 int tmp_scanline_start = m_scanline_start;
3138 int tmp_scanline_max = m_scanline_max;
3141 for(int v = /*get_cur_vline() + 1*/0; v < get_lines_per_frame(); v++) {
3146 // m_offset_x = tmp_offset_x;
3147 m_offset_y = tmp_offset_y;
3148 m_visible_y = tmp_visible_y;
3149 memcpy(m_stat_reg, tmp_stat_reg, sizeof(m_stat_reg));
3150 m_int_state = tmp_int_state;
3151 m_scanline = tmp_scanline;
3152 m_blink = tmp_blink;
3153 m_blink_count = tmp_blink_count;
3154 memcpy(m_pal_ind16, tmp_pal_ind16, sizeof(m_pal_ind16));
3155 memcpy(m_pal_ind256, tmp_pal_ind256, sizeof(m_pal_ind256));
3157 m_vdp_ops_count = tmp_vdp_ops_count;
3158 m_scanline_start = tmp_scanline_start;
3159 m_scanline_max = tmp_scanline_max;
3164 if(osd == NULL) return;
3165 emu->set_vm_screen_lines(__SCREEN_HEIGHT);
3166 for(y=0; y< __SCREEN_HEIGHT; y++) {
3167 if((dst = osd->get_vm_screen_buffer(y)) != NULL) {
3168 my_memcpy(dst, screen+(y+18)*_V9938_LONG_WIDTH+2, __SCREEN_WIDTH*sizeof(scrntype_t));
3173 void v99x8_device::initialize()
3175 DEVICE::initialize();
3176 __SCREEN_WIDTH = osd->get_feature_int_value(_T("SCREEN_WIDTH"));
3177 __SCREEN_HEIGHT = osd->get_feature_int_value(_T("SCREEN_HEIGHT"));
3178 if(__SCREEN_WIDTH <= 0) __SCREEN_WIDTH = 256;
3179 if(__SCREEN_HEIGHT <= 0) __SCREEN_HEIGHT = 192;
3182 register_vline_event(this);
3185 void v99x8_device::reset()
3190 void v99x8_device::event_vline(int v, int clock)
3192 m_stat_reg[2] ^= 0x20;
3196 void v99x8_device::write_signal(int id, uint32_t data, uint32_t mask)
3198 if(id == SIG_VDP_COMMAND_COMPLETION) {
3201 i = m_vdp_ops_count = 13662;
3202 if(m_vdp_engine) (this->*m_vdp_engine)();
3203 if (i == m_vdp_ops_count) break;
3208 #define STATE_VERSION 2
3210 bool v99x8_device::process_state(FILEIO* state_fio, bool loading)
3212 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
3215 if(!state_fio->StateCheckInt32(this_device_id)) {
3218 save_load_state(state_fio, !loading);
3222 void v99x8_device::save_load_state(FILEIO* state_fio, bool is_save)
3224 #define STATE_ENTRY(x) {&(x), sizeof(x)}
3229 t_state_table state_table[] = {
3230 STATE_ENTRY(m_offset_x),
3231 STATE_ENTRY(m_offset_y),
3232 STATE_ENTRY(m_visible_y),
3233 STATE_ENTRY(m_mode),
3234 STATE_ENTRY(m_pal_write_first),
3235 STATE_ENTRY(m_cmd_write_first),
3236 STATE_ENTRY(m_pal_write),
3237 STATE_ENTRY(m_cmd_write),
3238 STATE_ENTRY(m_pal_reg),
3239 STATE_ENTRY(m_stat_reg),
3240 STATE_ENTRY(m_cont_reg),
3241 STATE_ENTRY(m_read_ahead),
3242 STATE_ENTRY(m_int_state),
3243 STATE_ENTRY(m_scanline),
3244 STATE_ENTRY(m_blink),
3245 STATE_ENTRY(m_blink_count),
3246 STATE_ENTRY(m_mx_delta),
3247 STATE_ENTRY(m_my_delta),
3248 STATE_ENTRY(m_button_state),
3249 STATE_ENTRY(m_pal_ind16),
3250 STATE_ENTRY(m_pal_ind256),
3252 STATE_ENTRY(m_vdp_ops_count),
3253 STATE_ENTRY(m_pal_ntsc),
3254 STATE_ENTRY(m_scanline_start),
3255 STATE_ENTRY(m_vblank_start),
3256 STATE_ENTRY(m_scanline_max),
3257 STATE_ENTRY(m_height),
3258 STATE_ENTRY(m_v9958_sp_mode),
3259 STATE_ENTRY(m_address_latch),
3264 for(i=0; state_table[i].size>0; i++) {
3266 state_fio->Fwrite(state_table[i].address, state_table[i].size, 1);
3269 state_fio->Fread(state_table[i].address, state_table[i].size, 1);
3276 Common Source Code Project
3277 MSX Series (experimental)
3279 Origin : mame0172s.zip
3280 mame.zip\src\devices\video\v9938.cpp
3281 modified by umaiboux