1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood
3 /* Sega 315-5313 - Megadrive VDP */
4 
5 #include "emu.h"
6 #include "video/315_5313.h"
7 
8 /*  The VDP occupies addresses C00000h to C0001Fh.
9 
10  C00000h    -   Data port (8=r/w, 16=r/w)
11  C00002h    -   Data port (mirror)
12  C00004h    -   Control port (8=r/w, 16=r/w)
13  C00006h    -   Control port (mirror)
14  C00008h    -   HV counter (8/16=r/o)
15  C0000Ah    -   HV counter (mirror)
16  C0000Ch    -   HV counter (mirror)
17  C0000Eh    -   HV counter (mirror)
18  C00011h    -   SN76489 PSG (8=w/o)
19  C00013h    -   SN76489 PSG (mirror)
20  C00015h    -   SN76489 PSG (mirror)
21  C00017h    -   SN76489 PSG (mirror)
22 */
23 
24 #define MEGADRIV_VDP_VRAM(address) m_vram[(address) & 0x7fff]
25 
26 
27 
28 /*
29 
30  $00 - Mode Set Register No. 1
31  -----------------------------
32 
33  d7 - No effect
34  d6 - No effect
35  d5 - No effect
36  d4 - IE1 (Horizontal interrupt enable)
37  d3 - 1= Invalid display setting
38  d2 - Palette select
39  d1 - M3 (HV counter latch enable)
40  d0 - Display disable
41 
42  */
43 
44 #define MEGADRIVE_REG0_UNUSED           ((m_regs[0x00] & 0xc0) >> 6)
45 #define MEGADRIVE_REG0_BLANK_LEFT       ((m_regs[0x00] & 0x20) >> 5) // like SMS, not used by any commercial games?
46 #define MEGADRIVE_REG0_IRQ4_ENABLE      ((m_regs[0x00] & 0x10) >> 4)
47 #define MEGADRIVE_REG0_INVALID_MODE     ((m_regs[0x00] & 0x08) >> 3) // invalid display mode, unhandled
48 #define MEGADRIVE_REG0_SPECIAL_PAL      ((m_regs[0x00] & 0x04) >> 2) // strange palette mode, unhandled
49 #define MEGADRIVE_REG0_HVLATCH_ENABLE   ((m_regs[0x00] & 0x02) >> 1) // HV Latch, used by lightgun games
50 #define MEGADRIVE_REG0_DISPLAY_DISABLE  ((m_regs[0x00] & 0x01) >> 0)
51 
52 /*
53 
54  $01 - Mode Set Register No. 2
55  -----------------------------
56 
57  d7 - TMS9918 / Genesis display select
58  d6 - DISP (Display Enable)
59  d5 - IE0 (Vertical Interrupt Enable)
60  d4 - M1 (DMA Enable)
61  d3 - M2 (PAL / NTSC)
62  d2 - SMS / Genesis display select
63  d1 - 0 (No effect)
64  d0 - 0 (See notes)
65 
66 */
67 
68 #define MEGADRIVE_REG01_TMS9918_SELECT  ((m_regs[0x01] & 0x80) >> 7)
69 #define MEGADRIVE_REG01_DISP_ENABLE     ((m_regs[0x01] & 0x40) >> 6)
70 #define MEGADRIVE_REG01_IRQ6_ENABLE     ((m_regs[0x01] & 0x20) >> 5)
71 #define MEGADRIVE_REG01_DMA_ENABLE      ((m_regs[0x01] & 0x10) >> 4)
72 #define MEGADRIVE_REG01_240_LINE        ((m_regs[0x01] & 0x08) >> 3)
73 #define MEGADRIVE_REG01_SMS_SELECT      ((m_regs[0x01] & 0x04) >> 2)
74 #define MEGADRIVE_REG01_UNUSED          ((m_regs[0x01] & 0x02) >> 1)
75 #define MEGADRIVE_REG01_STRANGE_VIDEO   ((m_regs[0x01] & 0x01) >> 0) // unhandled, does strange things to the display
76 
77 #define MEGADRIVE_REG02_UNUSED1         ((m_regs[0x02] & 0xc0) >> 6)
78 #define MEGADRIVE_REG02_PATTERN_ADDR_A  ((m_regs[0x02] & 0x38) >> 3)
79 #define MEGADRIVE_REG02_UNUSED2         ((m_regs[0x02] & 0x07) >> 0)
80 
81 #define MEGADRIVE_REG03_UNUSED1         ((m_regs[0x03] & 0xc0) >> 6)
82 #define MEGADRIVE_REG03_PATTERN_ADDR_W  ((m_regs[0x03] & 0x3e) >> 1)
83 #define MEGADRIVE_REG03_UNUSED2         ((m_regs[0x03] & 0x01) >> 0)
84 
85 #define MEGADRIVE_REG04_UNUSED          ((m_regs[0x04] & 0xf8) >> 3)
86 #define MEGADRIVE_REG04_PATTERN_ADDR_B  ((m_regs[0x04] & 0x07) >> 0)
87 
88 #define MEGADRIVE_REG05_UNUSED          ((m_regs[0x05] & 0x80) >> 7)
89 #define MEGADRIVE_REG05_SPRITE_ADDR     ((m_regs[0x05] & 0x7f) >> 0)
90 
91 /* 6? */
92 
93 #define MEGADRIVE_REG07_UNUSED          ((m_regs[0x07] & 0xc0) >> 6)
94 #define MEGADRIVE_REG07_BGCOLOUR        ((m_regs[0x07] & 0x3f) >> 0)
95 
96 /* 8? */
97 /* 9? */
98 
99 #define MEGADRIVE_REG0A_HINT_VALUE      ((m_regs[0x0a] & 0xff) >> 0)
100 
101 #define MEGADRIVE_REG0B_UNUSED          ((m_regs[0x0b] & 0xf0) >> 4)
102 #define MEGADRIVE_REG0B_IRQ2_ENABLE     ((m_regs[0x0b] & 0x08) >> 3)
103 #define MEGADRIVE_REG0B_VSCROLL_MODE    ((m_regs[0x0b] & 0x04) >> 2)
104 #define MEGADRIVE_REG0B_HSCROLL_MODE    ((m_regs[0x0b] & 0x03) >> 0)
105 
106 #define MEGADRIVE_REG0C_RS0             ((m_regs[0x0c] & 0x80) >> 7)
107 #define MEGADRIVE_REG0C_UNUSED1         ((m_regs[0x0c] & 0x40) >> 6)
108 #define MEGADRIVE_REG0C_SPECIAL         ((m_regs[0x0c] & 0x20) >> 5)
109 #define MEGADRIVE_REG0C_UNUSED2         ((m_regs[0x0c] & 0x10) >> 4)
110 #define MEGADRIVE_REG0C_SHADOW_HIGLIGHT ((m_regs[0x0c] & 0x08) >> 3)
111 #define MEGADRIVE_REG0C_INTERLEAVE      ((m_regs[0x0c] & 0x06) >> 1)
112 #define MEGADRIVE_REG0C_RS1             ((m_regs[0x0c] & 0x01) >> 0)
113 
114 #define MEGADRIVE_REG0D_UNUSED          ((m_regs[0x0d] & 0xc0) >> 6)
115 #define MEGADRIVE_REG0D_HSCROLL_ADDR    ((m_regs[0x0d] & 0x3f) >> 0)
116 
117 /* e? */
118 
119 #define MEGADRIVE_REG0F_AUTO_INC        ((m_regs[0x0f] & 0xff) >> 0)
120 
121 #define MEGADRIVE_REG10_UNUSED1         ((m_regs[0x10] & 0xc0) >> 6)
122 #define MEGADRIVE_REG10_VSCROLL_SIZE    ((m_regs[0x10] & 0x30) >> 4)
123 #define MEGADRIVE_REG10_UNUSED2         ((m_regs[0x10] & 0x0c) >> 2)
124 #define MEGADRIVE_REG10_HSCROLL_SIZE    ((m_regs[0x10] & 0x03) >> 0)
125 
126 #define MEGADRIVE_REG11_WINDOW_RIGHT    ((m_regs[0x11] & 0x80) >> 7)
127 #define MEGADRIVE_REG11_UNUSED          ((m_regs[0x11] & 0x60) >> 5)
128 #define MEGADRIVE_REG11_WINDOW_HPOS     ((m_regs[0x11] & 0x1f) >> 0)
129 
130 #define MEGADRIVE_REG12_WINDOW_DOWN     ((m_regs[0x12] & 0x80) >> 7)
131 #define MEGADRIVE_REG12_UNUSED          ((m_regs[0x12] & 0x60) >> 5)
132 #define MEGADRIVE_REG12_WINDOW_VPOS     ((m_regs[0x12] & 0x1f) >> 0)
133 
134 #define MEGADRIVE_REG13_DMALENGTH1      ((m_regs[0x13] & 0xff) >> 0)
135 
136 #define MEGADRIVE_REG14_DMALENGTH2      ((m_regs[0x14] & 0xff) >> 0)
137 
138 #define MEGADRIVE_REG15_DMASOURCE1      ((m_regs[0x15] & 0xff) >> 0)
139 #define MEGADRIVE_REG16_DMASOURCE2      ((m_regs[0x16] & 0xff) >> 0)
140 
141 #define MEGADRIVE_REG17_DMASOURCE3      ((m_regs[0x17] & 0xff) >> 0)
142 #define MEGADRIVE_REG17_DMATYPE         ((m_regs[0x17] & 0xc0) >> 6)
143 #define MEGADRIVE_REG17_UNUSED          ((m_regs[0x17] & 0x3f) >> 0)
144 
145 static constexpr u8 line_315_5313_mode4[8] = {
146 			  26 /* VINT_HPOS */
147 			, 26 /* VINT_FLAG_HPOS */
148 			, 27 /* HINT_HPOS */
149 			, 28 /* NMI_HPOS, not verified */
150 			, 25 /* XSCROLL_HPOS */
151 			, 28 /* VCOUNT_CHANGE_HPOS */
152 			, 26 /* SPROVR_HPOS */
153 			, 37 /* SPRCOL_BASEHPOS */
154 		};
155 
156 static const unsigned hres[4] = { 256, 256, 320, 320 };
157 static const unsigned hres_mul[4] = { 5, 5, 4, 4 };
158 
get_hres()159 inline u8 sega315_5313_device::get_hres() { return (MEGADRIVE_REG0C_RS0 | (MEGADRIVE_REG0C_RS1 << 1)) & 3; }
screen_hpos()160 int sega315_5313_device::screen_hpos() { return screen().hpos() / (m_lcm_scaling ? hres_mul[get_hres()] : 1); }
161 
162 #define MAX_HPOSITION 480
163 
164 
165 DEFINE_DEVICE_TYPE(SEGA315_5313, sega315_5313_device, "sega315_5313", "Sega 315-5313 Megadrive VDP")
166 
sega315_5313_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)167 sega315_5313_device::sega315_5313_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
168 	// mode 4 support, for SMS compatibility, is implemented in 315_5124.cpp
169 	: sega315_5313_mode4_device(mconfig, SEGA315_5313, tag, owner, clock, SEGA315_5124_CRAM_SIZE, 0x00, 0x1f, 0, 0, line_315_5313_mode4)
170 	, device_gfx_interface(mconfig, *this, nullptr, "gfx_palette")
171 	, m_render_bitmap(nullptr)
172 	, m_render_line(nullptr)
173 	, m_render_line_raw(nullptr)
174 	, m_megadriv_scanline_timer(nullptr)
175 	, m_sndirqline_callback(*this)
176 	, m_lv6irqline_callback(*this)
177 	, m_lv4irqline_callback(*this)
178 	, m_32x_scanline_func(*this)
179 	, m_32x_interrupt_func(*this)
180 	, m_32x_scanline_helper_func(*this)
181 	, m_command_pending(0)
182 	, m_command_part1(0)
183 	, m_command_part2(0)
184 	, m_vdp_code(0)
185 	, m_vdp_address(0)
186 	, m_vram_fill_pending(0)
187 	, m_vram_fill_length(0)
188 	, m_irq4counter(0)
189 	, m_imode_odd_frame(0)
190 	, m_sprite_collision(0)
191 	, m_irq6_pending(0)
192 	, m_irq4_pending(0)
193 	, m_scanline_counter(0)
194 	, m_vblank_flag(0)
195 	, m_imode(0)
196 	, m_lcm_scaling(false)
197 	, m_visible_scanlines(0)
198 	, m_irq6_scanline(0)
199 	, m_z80irq_scanline(0)
200 	, m_total_scanlines(0)
201 	, m_base_total_scanlines(0)
202 	, m_framerate(0)
203 	, m_vdp_pal(0)
204 	, m_use_cram(0)
205 	, m_dma_delay(0)
206 	, m_regs(nullptr)
207 	, m_vram(nullptr)
208 	, m_cram(nullptr)
209 	, m_vsram(nullptr)
210 	, m_internal_sprite_attribute_table(nullptr)
211 	, m_irq6_on_timer(nullptr)
212 	, m_irq4_on_timer(nullptr)
213 	, m_render_timer(nullptr)
214 	, m_sprite_renderline(nullptr)
215 	, m_highpri_renderline(nullptr)
216 	, m_video_renderline(nullptr)
217 	, m_palette_lookup(nullptr)
218 	, m_space68k(nullptr)
219 	, m_cpu68k(*this, finder_base::DUMMY_TAG)
220 	, m_ext_palette(*this, finder_base::DUMMY_TAG)
221 	, m_gfx_palette(*this, "gfx_palette")
222 	, m_gfx_palette_shadow(*this, "gfx_palette_shadow")
223 	, m_gfx_palette_hilight(*this, "gfx_palette_hilight")
224 {
225 	m_use_alt_timing = 0;
226 	m_palwrite_base = -1;
227 }
228 
229 //-------------------------------------------------
230 //  device_add_mconfig
231 //  add machine configuration
232 //-------------------------------------------------
233 
device_add_mconfig(machine_config & config)234 void sega315_5313_device::device_add_mconfig(machine_config &config)
235 {
236 	sega315_5313_mode4_device::device_add_mconfig(config);
237 
238 	SEGAPSG(config.replace(), m_snsnd, DERIVED_CLOCK(1, 15)).add_route(ALL_OUTPUTS, *this, 0.5, AUTO_ALLOC_INPUT, 0);
239 
240 	PALETTE(config, m_gfx_palette, palette_device::BLACK).set_entries(PALETTE_PER_FRAME);
241 	PALETTE(config, m_gfx_palette_shadow, palette_device::BLACK).set_entries(PALETTE_PER_FRAME);
242 	PALETTE(config, m_gfx_palette_hilight, palette_device::BLACK).set_entries(PALETTE_PER_FRAME);
243 }
244 
TIMER_CALLBACK_MEMBER(sega315_5313_device::irq6_on_timer_callback)245 TIMER_CALLBACK_MEMBER(sega315_5313_device::irq6_on_timer_callback)
246 {
247 // m_irq6_pending = 1;
248 	if (MEGADRIVE_REG01_IRQ6_ENABLE)
249 		m_lv6irqline_callback(true);
250 }
251 
TIMER_CALLBACK_MEMBER(sega315_5313_device::irq4_on_timer_callback)252 TIMER_CALLBACK_MEMBER(sega315_5313_device::irq4_on_timer_callback)
253 {
254 	m_lv4irqline_callback(true);
255 }
256 
257 static const gfx_layout md_debug_8x8_layout =
258 {
259 	8,8,
260 	0x10000 / ((8*8*4) / 8),
261 	4,
262 	{ STEP4(0,1) },
263 	{ 2*4,3*4,0*4,1*4,6*4,7*4,4*4,5*4 },
264 	{ STEP8(0,4*8) },
265 	8*8*4
266 };
267 
268 static const gfx_layout md_debug_8x16_layout =
269 {
270 	8,16,
271 	0x10000 / ((8*16*4) / 8),
272 	4,
273 	{ STEP4(0,1) },
274 	{ 2*4,3*4,0*4,1*4,6*4,7*4,4*4,5*4 },
275 	{ STEP16(0,4*8) },
276 	8*16*4
277 };
278 
device_post_load()279 void sega315_5313_device::device_post_load()
280 {
281 	sega315_5313_mode4_device::device_post_load();
282 	gfx(0)->mark_all_dirty();
283 	gfx(1)->mark_all_dirty();
284 	gfx(2)->mark_all_dirty();
285 	gfx(3)->mark_all_dirty();
286 	gfx(4)->mark_all_dirty();
287 	gfx(5)->mark_all_dirty();
288 }
289 
device_start()290 void sega315_5313_device::device_start()
291 {
292 	m_sndirqline_callback.resolve_safe();
293 	m_lv6irqline_callback.resolve_safe();
294 	m_lv4irqline_callback.resolve_safe();
295 
296 	m_32x_scanline_func.resolve();
297 	m_32x_interrupt_func.resolve();
298 	m_32x_scanline_helper_func.resolve();
299 
300 	m_vram  = std::make_unique<u16[]>(0x10000 / 2);
301 	m_cram  = std::make_unique<u16[]>(0x80 / 2);
302 	m_vsram = std::make_unique<u16[]>(0x80 / 2);
303 	m_regs  = std::make_unique<u16[]>(0x40 / 2);
304 	m_internal_sprite_attribute_table = std::make_unique<u16[]>(0x400 / 2);
305 
306 	memset(m_vram.get(), 0x00, 0x10000);
307 	memset(m_cram.get(), 0x00, 0x80);
308 	memset(m_vsram.get(), 0x00, 0x80);
309 	memset(m_regs.get(), 0x00, 0x40);
310 	memset(m_internal_sprite_attribute_table.get(), 0x00, 0x400);
311 
312 	save_pointer(NAME(m_vram), 0x10000 / 2);
313 	save_pointer(NAME(m_cram), 0x80 / 2);
314 	save_pointer(NAME(m_vsram), 0x80 / 2);
315 	save_pointer(NAME(m_regs), 0x40 / 2);
316 	save_pointer(NAME(m_internal_sprite_attribute_table), 0x400 / 2);
317 
318 	save_item(NAME(m_command_pending));
319 	save_item(NAME(m_command_part1));
320 	save_item(NAME(m_command_part2));
321 	save_item(NAME(m_vdp_code));
322 	save_item(NAME(m_vdp_address));
323 	save_item(NAME(m_vram_fill_pending));
324 	save_item(NAME(m_vram_fill_length));
325 	save_item(NAME(m_irq4counter));
326 	save_item(NAME(m_imode_odd_frame));
327 	save_item(NAME(m_sprite_collision));
328 	save_item(NAME(m_imode));
329 	save_item(NAME(m_irq6_pending));
330 	save_item(NAME(m_irq4_pending));
331 	save_item(NAME(m_visible_scanlines));
332 	save_item(NAME(m_irq6_scanline));
333 	save_item(NAME(m_z80irq_scanline));
334 	save_item(NAME(m_scanline_counter));
335 	save_item(NAME(m_vblank_flag));
336 	save_item(NAME(m_total_scanlines));
337 
338 	m_sprite_renderline = std::make_unique<u8[]>(1024);
339 	m_highpri_renderline = std::make_unique<u8[]>(320);
340 	m_video_renderline = std::make_unique<u32[]>(320);
341 
342 	m_palette_lookup = std::make_unique<u16[]>(0x40);
343 
344 	memset(m_palette_lookup.get(), 0x00, 0x40 * 2);
345 
346 	if (!m_use_alt_timing)
347 		m_render_bitmap = std::make_unique<bitmap_rgb32>(1280, 512); // allocate maximum sizes we're going to use, it's safer.
348 	else
349 		m_render_line = std::make_unique<u32[]>(1280);
350 
351 	m_render_line_raw = std::make_unique<u16[]>(320);
352 
353 	// FIXME: are these all needed? I'm pretty sure some of these (most?) are just helpers which don't need to be saved,
354 	// but better safe than sorry...
355 	save_pointer(NAME(m_sprite_renderline), 1024);
356 	save_pointer(NAME(m_highpri_renderline), 320);
357 	save_pointer(NAME(m_video_renderline), 320);
358 	save_pointer(NAME(m_palette_lookup), 0x40);
359 	save_pointer(NAME(m_render_line_raw), 320);
360 	if (m_use_alt_timing)
361 		save_pointer(NAME(m_render_line), 1280);
362 
363 	m_irq6_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sega315_5313_device::irq6_on_timer_callback), this));
364 	m_irq4_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sega315_5313_device::irq4_on_timer_callback), this));
365 	m_render_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sega315_5313_device::render_scanline), this));
366 
367 	m_space68k = &m_cpu68k->space();
368 
369 	sega315_5313_mode4_device::device_start();
370 
371 	set_gfx(0, std::make_unique<gfx_element>(&palette(), md_debug_8x8_layout, (u8 *)m_vram.get(), 0, palette().entries() / 16, 0));
372 	set_gfx(1, std::make_unique<gfx_element>(&palette(), md_debug_8x16_layout, (u8 *)m_vram.get(), 0, palette().entries() / 16, 0));
373 	set_gfx(2, std::make_unique<gfx_element>(m_gfx_palette_shadow, md_debug_8x8_layout, (u8 *)m_vram.get(), 0, m_gfx_palette_shadow->entries() / 16, 0));
374 	set_gfx(3, std::make_unique<gfx_element>(m_gfx_palette_shadow, md_debug_8x16_layout, (u8 *)m_vram.get(), 0, m_gfx_palette_shadow->entries() / 16, 0));
375 	set_gfx(4, std::make_unique<gfx_element>(m_gfx_palette_hilight, md_debug_8x8_layout, (u8 *)m_vram.get(), 0, m_gfx_palette_hilight->entries() / 16, 0));
376 	set_gfx(5, std::make_unique<gfx_element>(m_gfx_palette_hilight, md_debug_8x16_layout, (u8 *)m_vram.get(), 0, m_gfx_palette_hilight->entries() / 16, 0));
377 }
378 
device_reset()379 void sega315_5313_device::device_reset()
380 {
381 	m_command_pending = 0;
382 	m_command_part1 = 0;
383 	m_command_part2 = 0;
384 	m_vdp_code = 0;
385 	m_vdp_address = 0;
386 	m_vram_fill_pending = 0;
387 	m_vram_fill_length = 0;
388 	m_irq4counter = -1;
389 	m_imode_odd_frame = 0;
390 	m_sprite_collision = 0;
391 	m_imode = 0;
392 	m_irq6_pending = 0;
393 	m_irq4_pending = 0;
394 	m_scanline_counter = 0;
395 	m_vblank_flag = 0;
396 	m_total_scanlines = 262;
397 
398 	sega315_5313_mode4_device::device_reset();
399 }
400 
device_reset_old()401 void sega315_5313_device::device_reset_old()
402 {
403 	// other stuff, are we sure we want to set some of these every reset?
404 	// it's called from machine_reset
405 	m_total_scanlines = 262;
406 	m_visible_scanlines = 224;
407 	m_irq6_scanline = 224;
408 	m_z80irq_scanline = 226;
409 }
410 
vdp_address_inc()411 void sega315_5313_device::vdp_address_inc()
412 {
413 	m_vdp_address += MEGADRIVE_REG0F_AUTO_INC;
414 	m_vdp_address &= 0xffff;
415 }
416 
vdp_vram_write(u16 data)417 void sega315_5313_device::vdp_vram_write(u16 data)
418 {
419 	const u16 sprite_base_address = MEGADRIVE_REG0C_RS1 ? ((MEGADRIVE_REG05_SPRITE_ADDR & 0x7e) << 9) : ((MEGADRIVE_REG05_SPRITE_ADDR & 0x7f) << 9);
420 	const int spritetable_size = MEGADRIVE_REG0C_RS1 ? 0x400 : 0x200;
421 	const int lowlimit = sprite_base_address;
422 	const int highlimit = sprite_base_address + spritetable_size;
423 
424 	if (m_vdp_address & 1)
425 	{
426 		data = ((data & 0x00ff) << 8) | ((data & 0xff00) >> 8);
427 	}
428 
429 	vram_w(m_vdp_address >> 1, data);
430 
431 	/* The VDP stores an Internal copy of any data written to the Sprite Attribute Table.
432 	   This data is _NOT_ invalidated when the Sprite Base Address changes, thus allowing
433 	   for some funky effects, as used by Castlevania Bloodlines Stage 6-3 */
434 	if (m_vdp_address >= lowlimit && m_vdp_address < highlimit)
435 	{
436 //      osd_printf_debug("spritebase is %04x-%04x vram address is %04x, write %04x\n", lowlimit, highlimit - 1, m_vdp_address, data);
437 		m_internal_sprite_attribute_table[(m_vdp_address & (spritetable_size - 1)) >> 1] = data;
438 	}
439 
440 	vdp_address_inc();
441 }
442 
vdp_vsram_write(u16 data)443 void sega315_5313_device::vdp_vsram_write(u16 data)
444 {
445 	m_vsram[(m_vdp_address & 0x7e) >> 1] = data;
446 
447 	//logerror("Wrote to VSRAM addr %04x data %04x\n", m_vdp_address & 0xfffe, m_vsram[m_vdp_address >> 1]);
448 
449 	vdp_address_inc();
450 }
451 
write_cram_value(int offset,int data)452 void sega315_5313_device::write_cram_value(int offset, int data)
453 {
454 	m_cram[offset] = data;
455 
456 	//logerror("Wrote to CRAM addr %04x data %04x\n", m_vdp_address & 0xfffe, m_cram[m_vdp_address >> 1]);
457 	if (m_use_cram)
458 	{
459 		data = ((m_cram[offset] & 0xe) >> 1) | ((m_cram[offset] & 0xe0) >> 2) | ((m_cram[offset] & 0xe00) >> 3);
460 		m_palette_lookup[offset] = data;
461 		if (m_ext_palette != nullptr)
462 		{
463 			if (m_palwrite_base != -1)
464 			{
465 				m_ext_palette->set_pen_color(offset + m_palwrite_base, m_palette_lut->pen(data));
466 				m_ext_palette->set_pen_color(offset + m_palwrite_base + 0x40, m_palette_lut->pen(0x200 | data));
467 				m_ext_palette->set_pen_color(offset + m_palwrite_base + 0x80, m_palette_lut->pen(0x400 | data));
468 			}
469 		}
470 	}
471 }
472 
vdp_cram_write(u16 data)473 void sega315_5313_device::vdp_cram_write(u16 data)
474 {
475 	write_cram_value((m_vdp_address & 0x7e) >> 1, data);
476 
477 	vdp_address_inc();
478 }
479 
data_port_w(int data)480 void sega315_5313_device::data_port_w(int data)
481 {
482 	m_command_pending = 0;
483 
484 	/*
485 	0000b : VRAM read
486 	0001b : VRAM write
487 	0011b : CRAM write
488 	0100b : VSRAM read
489 	0101b : VSRAM write
490 	1000b : CRAM read
491 	1100b : VRAM byte read (unhandled)
492 	*/
493 //  logerror("write to vdp data port %04x with code %04x, write address %04x\n",data, m_vdp_code, m_vdp_address);
494 
495 	if (m_vram_fill_pending)
496 	{
497 		m_vdp_address &= 0xffff;
498 
499 		if (m_vdp_address & 1)
500 		{
501 			vram_w(m_vdp_address >> 1, data & 0x00ff, 0x00ff);
502 		}
503 		else
504 		{
505 			vram_w(m_vdp_address >> 1, (data & 0x00ff) << 8, 0x00ff << 8);
506 		}
507 
508 		for (int count = 0; count <= m_vram_fill_length; count++) // <= for james pond 3
509 		{
510 			if (m_vdp_address & 1)
511 			{
512 				vram_w(m_vdp_address >> 1, data & 0xff00, 0xff00);
513 			}
514 			else
515 			{
516 				vram_w(m_vdp_address >> 1, (data & 0xff00) >> 8, 0xff00 >> 8);
517 			}
518 
519 			vdp_address_inc();
520 		}
521 
522 		m_regs[0x13] = 0;
523 		m_regs[0x14] = 0;
524 
525 	//  m_regs[0x15] = (source >> 1) & 0xff;
526 	//  m_regs[0x16] = (source >> 9) & 0xff;
527 	//  m_regs[0x17] = (source >> 17) & 0xff;
528 
529 	}
530 	else
531 	{
532 		switch (m_vdp_code & 0x000f)
533 		{
534 			case 0x0000:
535 				logerror("Attempting to WRITE to DATA PORT in VRAM READ MODE\n");
536 				break;
537 
538 			case 0x0001:
539 				vdp_vram_write(data);
540 				break;
541 
542 			case 0x0003:
543 				vdp_cram_write(data);
544 				break;
545 
546 			case 0x0004:
547 				logerror("Attempting to WRITE to DATA PORT in VSRAM READ MODE\n");
548 				break;
549 
550 			case 0x0005:
551 				vdp_vsram_write(data);
552 				break;
553 
554 			case 0x0008:
555 				logerror("Attempting to WRITE to DATA PORT in CRAM READ MODE\n");
556 				break;
557 
558 			default:
559 				logerror("Attempting to WRITE to DATA PORT in #UNDEFINED# MODE %1x %04x\n", m_vdp_code & 0xf, data);
560 				break;
561 		}
562 	}
563 
564 }
565 
566 
vdp_set_register(int regnum,u8 value)567 void sega315_5313_device::vdp_set_register(int regnum, u8 value)
568 {
569 	m_regs[regnum] = value;
570 
571 	/* We need special handling for the IRQ enable registers, some games turn
572 	   off the irqs before they are taken, delaying them until the IRQ is turned
573 	   back on */
574 
575 	if (regnum == 0x00)
576 	{
577 	//osd_printf_debug("setting reg 0, irq enable is now %d\n", MEGADRIVE_REG0_IRQ4_ENABLE);
578 
579 		if (m_irq4_pending)
580 		{
581 			if (MEGADRIVE_REG0_IRQ4_ENABLE)
582 				m_lv4irqline_callback(true);
583 			else
584 				m_lv4irqline_callback(false);
585 		}
586 
587 		/* ??? Fatal Rewind needs this but I'm not sure it's accurate behavior
588 		   it causes flickering in roadrash */
589 	//  m_irq6_pending = 0;
590 	//  m_irq4_pending = 0;
591 
592 	}
593 
594 	if (regnum == 0x01)
595 	{
596 		if (m_irq6_pending)
597 		{
598 			if (MEGADRIVE_REG01_IRQ6_ENABLE)
599 				m_lv6irqline_callback(true);
600 			else
601 				m_lv6irqline_callback(false);
602 
603 		}
604 
605 		/* ??? */
606 	//  m_irq6_pending = 0;
607 	//  m_irq4_pending = 0;
608 
609 	}
610 
611 //  if (regnum == 0x0a)
612 //      osd_printf_debug("Set HINT Reload Register to %d on scanline %d\n", value, get_scanline_counter());
613 
614 //  osd_printf_debug("%s: Setting VDP Register #%02x to %02x\n", machine().describe_context(), regnum, value);
615 }
616 
update_code_and_address(void)617 void sega315_5313_device::update_code_and_address(void)
618 {
619 	m_vdp_code = ((m_command_part1 & 0xc000) >> 14) |
620 							((m_command_part2 & 0x00f0) >> 2);
621 
622 	m_vdp_address = ((m_command_part1 & 0x3fff) >> 0) |
623 							((m_command_part2 & 0x0003) << 14);
624 }
625 
626 // if either SVP CPU or segaCD is present, there is a 'lag' we have to compensate for
627 // hence, for segacd and svp we set m_dma_delay to the appropriate value at start
vdp_get_word_from_68k_mem(u32 source)628 inline u16 sega315_5313_device::vdp_get_word_from_68k_mem(u32 source)
629 {
630 	// should we limit the valid areas here?
631 	// how does this behave with the segacd etc?
632 	// note, the RV bit on 32x is important for this to work, because it causes a normal cart mapping - see tempo
633 
634 	//printf("vdp_get_word_from_68k_mem_default %08x\n", source);
635 
636 	if (source <= 0x3fffff)
637 		return m_space68k->read_word(source - m_dma_delay);    // compensate DMA lag
638 	else if ((source >= 0xe00000) && (source <= 0xffffff))
639 		return m_space68k->read_word(source);
640 	else
641 	{
642 		printf("DMA Read unmapped %06x\n", source);
643 		return machine().rand();
644 	}
645 }
646 
647 /*  Table from Charles Macdonald
648 
649 
650     DMA Mode      Width       Display      Transfer Count
651     -----------------------------------------------------
652     68K > VDP     32-cell     Active       16
653                               Blanking     167
654                   40-cell     Active       18
655                               Blanking     205
656     VRAM Fill     32-cell     Active       15
657                               Blanking     166
658                   40-cell     Active       17
659                               Blanking     204
660     VRAM Copy     32-cell     Active       8
661                               Blanking     83
662                   40-cell     Active       9
663                               Blanking     102
664 
665 */
666 
667 
668 /* Note, In reality this transfer is NOT instant, the 68k isn't paused
669    as the 68k address bus isn't accessed */
670 
671 /* Wani Wani World, James Pond 3, Pirates Gold! */
insta_vram_copy(u32 source,u16 length)672 void sega315_5313_device::insta_vram_copy(u32 source, u16 length)
673 {
674 	for (int x = 0; x < length; x++)
675 	{
676 		u8 source_byte;
677 
678 		//osd_printf_debug("vram copy length %04x source %04x dest %04x\n", length, source, m_vdp_address);
679 		if (source & 1) source_byte = MEGADRIV_VDP_VRAM((source & 0xffff) >> 1) & 0x00ff;
680 		else  source_byte = (MEGADRIV_VDP_VRAM((source & 0xffff) >> 1) & 0xff00) >> 8;
681 
682 		if (m_vdp_address & 1)
683 		{
684 			vram_w((m_vdp_address & 0xffff) >> 1, source_byte, 0x00ff);
685 		}
686 		else
687 		{
688 			vram_w((m_vdp_address & 0xffff) >> 1, (source_byte << 8), 0x00ff << 8);
689 		}
690 
691 		source++;
692 		vdp_address_inc();
693 	}
694 }
695 
696 /* Instant, but we pause the 68k a bit */
insta_68k_to_vram_dma(u32 source,int length)697 void sega315_5313_device::insta_68k_to_vram_dma(u32 source, int length)
698 {
699 	if (length == 0x00) length = 0xffff;
700 
701 	/* This is a hack until real DMA timings are implemented */
702 	m_cpu68k->spin_until_time(attotime::from_nsec(length * 1000 / 3500));
703 
704 	for (int count = 0; count < (length >> 1); count++)
705 	{
706 		vdp_vram_write(vdp_get_word_from_68k_mem(source));
707 		source += 2;
708 		if (source > 0xffffff) source = 0xe00000;
709 	}
710 
711 	m_vdp_address &= 0xffff;
712 
713 	m_regs[0x13] = 0;
714 	m_regs[0x14] = 0;
715 
716 	m_regs[0x15] = (source >> 1) & 0xff;
717 	m_regs[0x16] = (source >> 9) & 0xff;
718 	m_regs[0x17] = (source >> 17) & 0xff;
719 }
720 
721 
insta_68k_to_cram_dma(u32 source,u16 length)722 void sega315_5313_device::insta_68k_to_cram_dma(u32 source, u16 length)
723 {
724 	if (length == 0x00) length = 0xffff;
725 
726 	for (int count = 0; count < (length >> 1); count++)
727 	{
728 		//if (m_vdp_address >= 0x80) return; // abandon
729 
730 		write_cram_value((m_vdp_address & 0x7e) >> 1, vdp_get_word_from_68k_mem(source));
731 		source += 2;
732 
733 		if (source > 0xffffff) source = 0xfe0000;
734 
735 		vdp_address_inc();
736 	}
737 
738 	m_regs[0x13] = 0;
739 	m_regs[0x14] = 0;
740 
741 	m_regs[0x15] = (source >> 1) & 0xff;
742 	m_regs[0x16] = (source >> 9) & 0xff;
743 	m_regs[0x17] = (source >> 17) & 0xff;
744 
745 }
746 
insta_68k_to_vsram_dma(u32 source,u16 length)747 void sega315_5313_device::insta_68k_to_vsram_dma(u32 source, u16 length)
748 {
749 	if (length == 0x00) length = 0xffff;
750 
751 	for (int count = 0; count < (length >> 1); count++)
752 	{
753 		if (m_vdp_address >= 0x80) return; // abandon
754 
755 		m_vsram[(m_vdp_address & 0x7e) >> 1] = vdp_get_word_from_68k_mem(source);
756 		source += 2;
757 
758 		if (source > 0xffffff) source = 0xfe0000;
759 
760 		vdp_address_inc();
761 	}
762 
763 	m_regs[0x13] = 0;
764 	m_regs[0x14] = 0;
765 
766 	m_regs[0x15] = (source >> 1) & 0xff;
767 	m_regs[0x16] = (source >> 9) & 0xff;
768 	m_regs[0x17] = (source >> 17) & 0xff;
769 }
770 
771 /* This can be simplified quite a lot.. */
handle_dma_bits()772 void sega315_5313_device::handle_dma_bits()
773 {
774 #if 0
775 	const u32 source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2 << 8) | ((MEGADRIVE_REG17_DMASOURCE3 & 0xff) << 16)) << 1;
776 	const u16 length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2 << 8)) << 1;
777 	osd_printf_debug("%s 68k DMAtran set source %06x length %04x dest %04x enabled %01x code %02x %02x\n", machine().describe_context(), source, length, m_vdp_address, MEGADRIVE_REG01_DMA_ENABLE, m_vdp_code, MEGADRIVE_REG0F_AUTO_INC);
778 #endif
779 	if (MEGADRIVE_REG17_DMATYPE == 0x0 || MEGADRIVE_REG17_DMATYPE == 0x1)
780 	{
781 		const u32 source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2 << 8) | ((MEGADRIVE_REG17_DMASOURCE3 & 0x7f) << 16)) << 1;
782 		const u16 length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2 << 8)) << 1;
783 
784 		if (CODE_VRAM_WRITE())
785 		{
786 			/* The 68k is frozen during this transfer, it should be safe to throw a few cycles away and do 'instant' DMA because the 68k can't detect it being in progress (can the z80?) */
787 			//osd_printf_debug("68k->VRAM DMA transfer source %06x length %04x dest %04x enabled %01x\n", source, length, m_vdp_address, MEGADRIVE_REG01_DMA_ENABLE);
788 			if (MEGADRIVE_REG01_DMA_ENABLE) insta_68k_to_vram_dma(source, length);
789 		}
790 		else if (CODE_CRAM_WRITE())
791 		{
792 			/* The 68k is frozen during this transfer, it should be safe to throw a few cycles away and do 'instant' DMA because the 68k can't detect it being in progress (can the z80?) */
793 			//osd_printf_debug("68k->CRAM DMA transfer source %06x length %04x dest %04x enabled %01x\n", source, length, m_vdp_address, MEGADRIVE_REG01_DMA_ENABLE);
794 			if (MEGADRIVE_REG01_DMA_ENABLE) insta_68k_to_cram_dma(source, length);
795 		}
796 		else if (CODE_VSRAM_WRITE())
797 		{
798 			/* The 68k is frozen during this transfer, it should be safe to throw a few cycles away and do 'instant' DMA because the 68k can't detect it being in progress (can the z80?) */
799 			//osd_printf_debug("68k->VSRAM DMA transfer source %06x length %04x dest %04x enabled %01x\n", source, length, m_vdp_address, MEGADRIVE_REG01_DMA_ENABLE);
800 			if (MEGADRIVE_REG01_DMA_ENABLE) insta_68k_to_vsram_dma(source, length);
801 		}
802 		else
803 		{
804 			osd_printf_debug("setting vram 68k->vram (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE);
805 		}
806 	}
807 	else if (MEGADRIVE_REG17_DMATYPE == 0x2)
808 	{
809 		if (CODE_VRAM_WRITE() || CODE_CRAM_WRITE() || CODE_VSRAM_WRITE()) // only effects when code is write
810 		{
811 			//osd_printf_debug("vram fill length %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE);
812 			if (MEGADRIVE_REG01_DMA_ENABLE)
813 			{
814 				m_vram_fill_pending = 1;
815 				m_vram_fill_length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2 << 8));
816 			}
817 		}
818 		else
819 		{
820 			osd_printf_debug("setting vram fill (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE);
821 		}
822 	}
823 	else if (MEGADRIVE_REG17_DMATYPE == 0x3)
824 	{
825 		if (CODE_VRAM_COPY() || CODE_VRAM_WRITE()) // 0x21 can be affects?
826 		{
827 			const u32 source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2 << 8)); // source (byte offset)
828 			const u16 length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2 << 8)); // length in bytes
829 			//osd_printf_debug("setting vram copy mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE);
830 
831 			if (MEGADRIVE_REG01_DMA_ENABLE) insta_vram_copy(source, length);
832 		}
833 		else
834 		{
835 			osd_printf_debug("setting vram copy (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE);
836 		}
837 	}
838 }
839 
ctrl_port_w(int data)840 void sega315_5313_device::ctrl_port_w(int data)
841 {
842 //  logerror("write to vdp control port %04x\n",data);
843 	m_vram_fill_pending = 0; // ??
844 
845 	if (m_command_pending)
846 	{
847 		/* 2nd part of 32-bit command */
848 		m_command_pending = 0;
849 		m_command_part2 = data;
850 
851 		update_code_and_address();
852 		if (CODE_DMA())
853 			handle_dma_bits();
854 
855 		//logerror("VDP Write Part 2 setting Code %02x Address %04x\n", m_vdp_code, m_vdp_address);
856 	}
857 	else
858 	{
859 		if ((data & 0xc000) == 0x8000)
860 		{   /* Register Setting Command */
861 			const int regnum = (data & 0x3f00) >> 8;
862 			const int value  = (data & 0x00ff);
863 
864 			if (regnum & 0x20) osd_printf_debug("reg error\n");
865 
866 			vdp_set_register(regnum & 0x1f, value);
867 			m_vdp_code = 0;
868 			m_vdp_address = 0;
869 		}
870 		else
871 		{
872 			m_command_pending = 1;
873 			m_command_part1 = data;
874 			update_code_and_address();
875 			//logerror("VDP Write Part 1 setting Code %02x Address %04x\n", m_vdp_code, m_vdp_address);
876 		}
877 	}
878 }
879 
vdp_w(offs_t offset,u16 data,u16 mem_mask)880 void sega315_5313_device::vdp_w(offs_t offset, u16 data, u16 mem_mask)
881 {
882 	switch (offset << 1)
883 	{
884 		case 0x00:
885 		case 0x02:
886 			if (!ACCESSING_BITS_8_15)
887 			{
888 				data = (data & 0x00ff) | data << 8;
889 			//  osd_printf_debug("8-bit write VDP data port access, offset %04x data %04x mem_mask %04x\n", offset, data, mem_mask);
890 			}
891 			else if (!ACCESSING_BITS_0_7)
892 			{
893 				data = (data & 0xff00) | data >> 8;
894 			//  osd_printf_debug("8-bit write VDP data port access, offset %04x data %04x mem_mask %04x\n", offset, data, mem_mask);
895 			}
896 			data_port_w(data);
897 			break;
898 
899 		case 0x04:
900 		case 0x06:
901 			if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit write VDP control port access, offset %04x data %04x mem_mask %04x\n", offset, data, mem_mask);
902 			ctrl_port_w(data);
903 			break;
904 
905 		case 0x08:
906 		case 0x0a:
907 		case 0x0c:
908 		case 0x0e:
909 			logerror("Attempt to Write to HV counters!!\n");
910 			break;
911 
912 		case 0x10:
913 		case 0x12:
914 		case 0x14:
915 		case 0x16:
916 		{
917 			// accessed by either segapsg_device or sn76496_device
918 			if (ACCESSING_BITS_0_7)
919 				psg_w(data & 0xff);
920 			//if (ACCESSING_BITS_8_15) psg_w((data >> 8) & 0xff);
921 			break;
922 		}
923 
924 		default:
925 		osd_printf_debug("write to unmapped vdp port\n");
926 	}
927 }
928 
vdp_vram_r(void)929 u16 sega315_5313_device::vdp_vram_r(void)
930 {
931 	return MEGADRIV_VDP_VRAM((m_vdp_address & 0xfffe) >> 1);
932 }
933 
vdp_vsram_r(void)934 u16 sega315_5313_device::vdp_vsram_r(void)
935 {
936 	return m_vsram[(m_vdp_address & 0x7e) >> 1];
937 }
938 
vdp_cram_r(void)939 u16 sega315_5313_device::vdp_cram_r(void)
940 {
941 	return m_cram[(m_vdp_address & 0x7e) >> 1];
942 }
943 
data_port_r()944 u16 sega315_5313_device::data_port_r()
945 {
946 	u16 retdata = 0;
947 
948 	//return machine().rand();
949 
950 	if (!machine().side_effects_disabled())
951 		m_command_pending = 0;
952 
953 	switch (m_vdp_code & 0x000f)
954 	{
955 		case 0x0000:
956 			retdata = vdp_vram_r();
957 			if (!machine().side_effects_disabled())
958 				vdp_address_inc();
959 			break;
960 
961 		case 0x0001:
962 			if (!machine().side_effects_disabled())
963 				logerror("Attempting to READ from DATA PORT in VRAM WRITE MODE\n");
964 			retdata = machine().rand();
965 			break;
966 
967 		case 0x0003:
968 			if (!machine().side_effects_disabled())
969 				logerror("Attempting to READ from DATA PORT in CRAM WRITE MODE\n");
970 			retdata = machine().rand();
971 			break;
972 
973 		case 0x0004:
974 			retdata = vdp_vsram_r();
975 			if (!machine().side_effects_disabled())
976 				vdp_address_inc();
977 			break;
978 
979 		case 0x0005:
980 			if (!machine().side_effects_disabled())
981 				logerror("Attempting to READ from DATA PORT in VSRAM WRITE MODE\n");
982 			break;
983 
984 		case 0x0008:
985 			retdata = vdp_cram_r();
986 			if (!machine().side_effects_disabled())
987 				vdp_address_inc();
988 			break;
989 
990 		default:
991 			if (!machine().side_effects_disabled())
992 				logerror("Attempting to READ from DATA PORT in #UNDEFINED# MODE\n");
993 			retdata = machine().rand();
994 			break;
995 	}
996 
997 //  osd_printf_debug("vdp_data_port_r %04x %04x %04x\n", m_vdp_code, m_vdp_address, retdata);
998 
999 //  logerror("Read VDP Data Port\n");
1000 	return retdata;
1001 }
1002 
1003 /*
1004 
1005  NTSC, 256x224
1006  -------------
1007 
1008  Lines  Description
1009 
1010  224    Active display
1011  8      Bottom border
1012  3      Bottom blanking
1013  3      Vertical blanking
1014  13     Top blanking
1015  11     Top border
1016 
1017  V counter values
1018  00-EA, E5-FF
1019 
1020 PAL, 256x224
1021  ------------
1022 
1023  Lines  Description
1024 
1025  224    Active display
1026  32     Bottom border
1027  3      Bottom blanking
1028  3      Vertical blanking
1029  13     Top blanking
1030  38     Top border
1031 
1032  V counter values
1033  00-FF, 00-02, CA-FF
1034 
1035  PAL, 256x240
1036  ------------
1037 
1038  Lines  Description
1039 
1040  240    Active display
1041  24     Bottom border
1042  3      Bottom blanking
1043  3      Vertical blanking
1044  13     Top blanking
1045  30     Top border
1046 
1047  V counter values
1048  00-FF, 00-0A, D2-FF
1049 
1050 
1051 
1052  Pixels H.Cnt   Description
1053   256 : 00-7F : Active display
1054    15 : 80-87 : Right border
1055     8 : 87-8B : Right blanking
1056    26 : 8B-ED : Horizontal sync
1057     2 : ED-EE : Left blanking
1058    14 : EE-F5 : Color burst
1059     8 : F5-F9 : Left blanking
1060    13 : F9-FF : Left border
1061 
1062 */
1063 
1064 
1065 
ctrl_port_r()1066 u16 sega315_5313_device::ctrl_port_r()
1067 {
1068 	/* Battletoads is very fussy about the vblank flag
1069 	   it wants it to be 1. in scanline 224 */
1070 
1071 	/* Double Dragon 2 is very sensitive to hblank timing */
1072 	/* xperts is very fussy too */
1073 
1074 	/* Game no Kanzume Otokuyou (J) [!] is also fussy
1075 	  - it cares about the bits labeled always 0, always 1.. (!)
1076 	 */
1077 
1078 	/* Megalo Mania also fussy - cares about pending flag*/
1079 
1080 	const int sprite_overflow = 0;
1081 	int odd_frame = 0;
1082 	int hblank_flag = 0;
1083 	const int dma_active = 0;
1084 	int vblank = m_vblank_flag;
1085 	const int fifo_empty = 1;
1086 	const int fifo_full = 0;
1087 
1088 	if (m_imode & 1) odd_frame = m_imode_odd_frame ^ 1;
1089 
1090 	const u16 hpos = get_hposition();
1091 
1092 	if (hpos > 400) hblank_flag = 1;
1093 	if (hpos > 460) hblank_flag = 0;
1094 
1095 	/* extra case */
1096 	if (MEGADRIVE_REG01_DISP_ENABLE == 0) vblank = 1;
1097 
1098 /*
1099 
1100 // these aren't *always* 0/1 some of them are open bus return
1101  d15 - Always 0
1102  d14 - Always 0
1103  d13 - Always 1
1104  d12 - Always 1
1105 
1106  d11 - Always 0
1107  d10 - Always 1
1108  d9  - FIFO Empty
1109  d8  - FIFO Full
1110 
1111  d7  - Vertical interrupt pending
1112  d6  - Sprite overflow on current scan line
1113  d5  - Sprite collision
1114  d4  - Odd frame
1115 
1116  d3  - Vertical blanking
1117  d2  - Horizontal blanking
1118  d1  - DMA in progress
1119  d0  - PAL mode flag
1120 */
1121 
1122 	return (1 << 13) | // ALWAYS 1
1123 			(1 << 12) | // ALWAYS 1
1124 			(1 << 10) | // ALWAYS 1
1125 			(fifo_empty << 9) | // FIFO EMPTY
1126 			(fifo_full << 8) | // FIFO FULL
1127 			(m_irq6_pending << 7) | // exmutants has a tight loop checking this ..
1128 			(sprite_overflow << 6) |
1129 			(m_sprite_collision << 5) |
1130 			(odd_frame << 4) |
1131 			(vblank << 3) |
1132 			(hblank_flag << 2) |
1133 			(dma_active << 1) |
1134 			(m_vdp_pal << 0); // PAL MODE FLAG checked by striker for region prot..
1135 }
1136 
1137 static const u8 vc_ntsc_224[] =
1138 {
1139 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,    0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1140 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,    0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1141 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,    0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1142 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,    0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1143 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,    0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1144 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,    0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1145 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,    0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1146 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,    0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1147 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,    0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1148 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,    0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1149 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,    0xab, 0xac, 0xad, 0xae, 0xaf,
1150 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,    0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1151 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,    0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1152 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,    0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1153 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,/**/0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
1154 	0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4,    0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
1155 	0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1156 };
1157 
1158 static const u8 vc_ntsc_240[] =
1159 {
1160 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1161 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1162 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1163 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1164 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1165 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1166 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1167 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1168 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1169 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1170 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1171 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1172 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1173 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1174 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1175 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
1176 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05
1177 };
1178 
1179 static const u8 vc_pal_224[] =
1180 {
1181 	0x00, 0x01, 0x02,    0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1182 	0x10, 0x11, 0x12,    0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1183 	0x20, 0x21, 0x22,    0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1184 	0x30, 0x31, 0x32,    0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1185 	0x40, 0x41, 0x42,    0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1186 	0x50, 0x51, 0x52,    0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1187 	0x60, 0x61, 0x62,    0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1188 	0x70, 0x71, 0x72,    0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1189 	0x80, 0x81, 0x82,    0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1190 	0x90, 0x91, 0x92,    0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1191 	0xa0, 0xa1, 0xa2,    0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1192 	0xb0, 0xb1, 0xb2,    0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1193 	0xc0, 0xc1, 0xc2,    0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1194 	0xd0, 0xd1, 0xd2,    0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1195 	0xe0, 0xe1, 0xe2,    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1196 	0xf0, 0xf1, 0xf2,    0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
1197 	0x00, 0x01, 0x02,/**/0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
1198 	0xd7, 0xd8, 0xd9,    0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
1199 	0xe7, 0xe8, 0xe9,    0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
1200 	0xf7, 0xf8, 0xf9,    0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1201 };
1202 
1203 static const u8 vc_pal_240[] =
1204 {
1205 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,    0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1206 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,    0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1207 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,    0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1208 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,    0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1209 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,    0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1210 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,    0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1211 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,    0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1212 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,    0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1213 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,    0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1214 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,    0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1215 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,    0xab, 0xac, 0xad, 0xae, 0xaf,
1216 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,    0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1217 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,    0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1218 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,    0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1219 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,    0xeb, 0xec, 0xed, 0xee, 0xef,
1220 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,    0xfb, 0xfc, 0xfd, 0xfe, 0xff,
1221 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,/**/0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
1222 	0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,    0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
1223 	0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,    0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
1224 	0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1225 };
1226 
1227 
get_hposition()1228 u16 sega315_5313_device::get_hposition()
1229 {
1230 	u16 value4;
1231 
1232 	if ((!m_use_alt_timing) && (get_framerate() > 0.0))
1233 	{
1234 		attotime time_elapsed_since_megadriv_scanline_timer;
1235 
1236 		time_elapsed_since_megadriv_scanline_timer = m_megadriv_scanline_timer->time_elapsed();
1237 
1238 		if (time_elapsed_since_megadriv_scanline_timer.attoseconds() < (ATTOSECONDS_PER_SECOND/get_framerate() /double(m_total_scanlines)))
1239 		{
1240 			value4 = (u16)(MAX_HPOSITION * ((double)(time_elapsed_since_megadriv_scanline_timer.attoseconds()) / (double)(ATTOSECONDS_PER_SECOND/get_framerate() /double(m_total_scanlines))));
1241 		}
1242 		else /* in some cases (probably due to rounding errors) we get some stupid results (the odd huge value where the time elapsed is much higher than the scanline time??!).. hopefully by clamping the result to the maximum we limit errors */
1243 		{
1244 			value4 = MAX_HPOSITION;
1245 		}
1246 	}
1247 	else
1248 	{
1249 		value4 = screen_hpos();
1250 	}
1251 
1252 	return value4;
1253 }
1254 
get_scanline_counter()1255 int sega315_5313_device::get_scanline_counter()
1256 {
1257 	if (!m_use_alt_timing)
1258 		return m_scanline_counter;
1259 	else
1260 		return screen().vpos();
1261 }
1262 
1263 
megadriv_read_hv_counters()1264 u16 sega315_5313_device::megadriv_read_hv_counters()
1265 {
1266 	/* Bubble and Squeek wants vcount=0xe0 */
1267 	/* Dracula is very sensitive to this */
1268 	/* Marvel Land is sensitive to this */
1269 
1270 	int vpos = get_scanline_counter();
1271 	u16 hpos = get_hposition();
1272 
1273 //  if (hpos > 424) vpos++; // fixes dracula, breaks road rash
1274 	if (hpos > 460) vpos++; // when does vpos increase.. also on sms, check game gear manual..
1275 
1276 	/* shouldn't happen.. */
1277 	if (vpos < 0)
1278 	{
1279 		vpos = m_total_scanlines;
1280 		osd_printf_debug("negative vpos?!\n");
1281 	}
1282 
1283 	if (MEGADRIVE_REG01_240_LINE)
1284 	{
1285 		assert(vpos % m_total_scanlines < (m_vdp_pal ? sizeof(vc_pal_240) : sizeof(vc_ntsc_240)));
1286 		vpos = m_vdp_pal ? vc_pal_240[vpos % m_total_scanlines] : vc_ntsc_240[vpos % m_total_scanlines];
1287 	}
1288 	else
1289 	{
1290 		assert(vpos % m_total_scanlines < (m_vdp_pal ? sizeof(vc_pal_224) : sizeof(vc_ntsc_224)));
1291 		vpos = m_vdp_pal ? vc_pal_224[vpos % m_total_scanlines] : vc_ntsc_224[vpos % m_total_scanlines];
1292 	}
1293 
1294 	if (hpos > 0xf7) hpos -= 0x49;
1295 
1296 	return ((vpos & 0xff) << 8) | (hpos & 0xff);
1297 }
1298 
vdp_r(offs_t offset,u16 mem_mask)1299 u16 sega315_5313_device::vdp_r(offs_t offset, u16 mem_mask)
1300 {
1301 	u16 retvalue = 0;
1302 
1303 	switch (offset << 1)
1304 	{
1305 		case 0x00:
1306 		case 0x02:
1307 			if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7))
1308 			{
1309 				if (!machine().side_effects_disabled())
1310 					osd_printf_debug("8-bit VDP read data port access, offset %04x mem_mask %04x\n", offset, mem_mask);
1311 			}
1312 			retvalue = data_port_r();
1313 			break;
1314 
1315 		case 0x04:
1316 		case 0x06:
1317 		//  if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit VDP read control port access, offset %04x mem_mask %04x\n", offset, mem_mask);
1318 			retvalue = ctrl_port_r();
1319 		//  retvalue = machine().rand();
1320 		//  logerror("%s: Read Control Port at scanline %d hpos %d (return %04x)\n", machine().describe_context(), get_scanline_counter(), get_hposition(), retvalue);
1321 			break;
1322 
1323 		case 0x08:
1324 		case 0x0a:
1325 		case 0x0c:
1326 		case 0x0e:
1327 		//  if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit VDP read HV counter port access, offset %04x mem_mask %04x\n", offset, mem_mask);
1328 			retvalue = megadriv_read_hv_counters();
1329 		//  retvalue = machine().rand();
1330 		//  osd_printf_debug("%s: Read HV counters at scanline %d hpos %d (return %04x)\n", machine().describe_context(), get_scanline_counter(), get_hposition(), retvalue);
1331 			break;
1332 
1333 		case 0x10:
1334 		case 0x12:
1335 		case 0x14:
1336 		case 0x16:
1337 			if (!machine().side_effects_disabled())
1338 				logerror("Attempting to read PSG!\n");
1339 			retvalue = 0;
1340 			break;
1341 	}
1342 	return retvalue;
1343 }
1344 
1345 
1346 // line length = 342
1347 
1348 /*
1349  The V counter counts up from 00h to EAh, then it jumps back to E5h and
1350  continues counting up to FFh. This allows it to cover the entire 262 line
1351  display.
1352 
1353  The H counter counts up from 00h to E9h, then it jumps back to 93h and
1354  continues counting up to FFh. This allows it to cover an entire 342 pixel
1355  line.
1356 */
1357 
1358 /*
1359 
1360  - The 80th sprite has been drawn in 40-cell mode.
1361  - The 64th sprite has been drawn in 32-cell mode.
1362  - Twenty sprites on the same scanline have been drawn in 40 cell mode.
1363  - Sixteen sprites on the same scanline have been drawn in 32 cell mode.
1364  - 320 pixels worth of sprite data has been drawn on the same scanline
1365    in 40 cell mode.
1366  - 256 pixels worth of sprite data has been drawn on the same scanline
1367    in 32 cell mode.
1368  - The currently drawn sprite has a link field of zero.
1369 
1370 */
1371 
1372 /*
1373 
1374  $05 - Sprite Attribute Table Base Address
1375  -----------------------------------------
1376 
1377  Bits 6-0 of this register correspond to bits A15-A09 of the sprite
1378  attribute table.
1379 
1380  In 40-cell mode, A09 is always forced to zero.
1381 
1382 */
1383 
render_spriteline_to_spritebuffer(int scanline)1384 void sega315_5313_device::render_spriteline_to_spritebuffer(int scanline)
1385 {
1386 	const int ytile_shift = (m_imode == 3) ? 4 : 3;
1387 	const int yline_mask = (m_imode == 3) ? 0xf : 0x7;
1388 	gfx_element *spr_gfx = (m_imode == 3) ? gfx(1) : gfx(0);
1389 	int maxsprites = 0;
1390 	int maxpixels = 0;
1391 	u16 base_address = 0;
1392 
1393 	const int screenwidth = get_hres();
1394 
1395 	switch (screenwidth & 3)
1396 	{
1397 		case 0: maxsprites = 64; maxpixels = 256; base_address = (MEGADRIVE_REG05_SPRITE_ADDR & 0x7f) << 9; break;
1398 		case 1: maxsprites = 64; maxpixels = 256; base_address = (MEGADRIVE_REG05_SPRITE_ADDR & 0x7f) << 9; break;
1399 		case 2: maxsprites = 80; maxpixels = 320; base_address = (MEGADRIVE_REG05_SPRITE_ADDR & 0x7e) << 9; break;
1400 		case 3: maxsprites = 80; maxpixels = 320; base_address = (MEGADRIVE_REG05_SPRITE_ADDR & 0x7e) << 9; break;
1401 	}
1402 
1403 	/* Clear our Render Buffer */
1404 	memset(m_sprite_renderline.get(), 0, 1024);
1405 
1406 	{
1407 		int ypos, xpos, addr;
1408 		int drawypos;
1409 		int /*drawwidth,*/ drawheight;
1410 		int spritemask = 0;
1411 		u8 height, width, link, xflip, yflip, colour, pri;
1412 
1413 		/* Get Sprite Attribs */
1414 		int spritenum = 0;
1415 
1416 		//if (scanline == 40) osd_printf_debug("spritelist start base %04x\n", base_address);
1417 
1418 		do
1419 		{
1420 			//u16 value1, value2, value3, value4;
1421 
1422 			//value1 = m_vram[((base_address >> 1) + spritenum * 4) + 0x0];
1423 			//value2 = m_vram[((base_address >> 1) + spritenum * 4) + 0x1];
1424 			//value3 = m_vram[((base_address >> 1) + spritenum * 4) + 0x2];
1425 			//value4 = m_vram[((base_address >> 1) + spritenum * 4) + 0x3];
1426 
1427 			ypos  =  (m_internal_sprite_attribute_table[(spritenum * 4) + 0x0] & 0x01ff) >> 0; /* 0x03ff? */ // puyo puyo requires 0x1ff mask, not 0x3ff, see speech bubble corners
1428 			height= ((m_internal_sprite_attribute_table[(spritenum * 4) + 0x1] & 0x0300) >> 8) + 1;
1429 			width = ((m_internal_sprite_attribute_table[(spritenum * 4) + 0x1] & 0x0c00) >> 10) + 1;
1430 			link  =  (m_internal_sprite_attribute_table[(spritenum * 4) + 0x1] & 0x007f) >> 0;
1431 			xpos  =  (MEGADRIV_VDP_VRAM(((base_address >> 1) + spritenum * 4) + 0x3) & 0x01ff) >> 0; /* 0x03ff? */ // pirates gold has a sprite with co-ord 0x200...
1432 
1433 			if (m_imode == 3)
1434 			{
1435 				ypos  = (m_internal_sprite_attribute_table[(spritenum * 4) + 0x0] & 0x03ff) >> 0; /* 0x3ff requried in interlace mode (sonic 2 2 player) */
1436 				drawypos = ypos - 256;
1437 				drawheight = height * 16;
1438 			}
1439 			else
1440 			{
1441 				ypos  = (m_internal_sprite_attribute_table[(spritenum * 4) + 0x0] & 0x01ff) >> 0; /* 0x03ff? */ // puyo puyo requires 0x1ff mask, not 0x3ff, see speech bubble corners
1442 				drawypos = ypos - 128;
1443 				drawheight = height * 8;
1444 			}
1445 
1446 			//if (scanline == 40) osd_printf_debug("xpos %04x ypos %04x\n", xpos, ypos);
1447 
1448 			if ((drawypos <= scanline) && ((drawypos + drawheight) > scanline))
1449 			{
1450 				addr  = (MEGADRIV_VDP_VRAM(((base_address >> 1) + spritenum * 4) + 0x2) & 0x07ff) >> 0;
1451 				xflip = (MEGADRIV_VDP_VRAM(((base_address >> 1) + spritenum * 4) + 0x2) & 0x0800) >> 11;
1452 				yflip = (MEGADRIV_VDP_VRAM(((base_address >> 1) + spritenum * 4) + 0x2) & 0x1000) >> 12;
1453 				colour= (MEGADRIV_VDP_VRAM(((base_address >> 1) + spritenum * 4) + 0x2) & 0x6000) >> 13;
1454 				pri   = (MEGADRIV_VDP_VRAM(((base_address >> 1) + spritenum * 4) + 0x2) & 0x8000) >> 15;
1455 
1456 				if (m_imode == 3)
1457 					addr &= 0x3ff;
1458 
1459 				//drawwidth = width * 8;
1460 				if (pri == 1) pri = 0x80;
1461 				else pri = 0x40;
1462 
1463 				/* todo: fix me, I'm sure this isn't right but sprite 0 + other sprite seem to do something..
1464 				   maybe spritemask |= 2 should be set for anything < 0x40 ?*/
1465 				if (xpos == 0x00) spritemask |= 1;
1466 
1467 				//if (xpos == 0x01) spritemask |= 2;
1468 				//if (xpos == 0x04) spritemask |= 2;  // sonic 2 title screen
1469 				//if (xpos == 0x08) spritemask |= 2;  // rocket night adventures
1470 				//if (xpos == 0x10) spritemask |= 2;  // mercs l1 boss
1471 				//if (xpos == 0x0a) spritemask |= 2;  // legend of galahad
1472 				//if (xpos == 0x21) spritemask |= 2;  // shadow of the beast?
1473 				if ((xpos > 0) && (xpos < 0x40)) spritemask |= 2;
1474 
1475 				if (spritemask == 0x3)
1476 					return;
1477 				/* end todo: */
1478 
1479 				//int xdraw;
1480 				int yline = scanline - drawypos;
1481 				const int ytile = yline >> ytile_shift;
1482 				if (ytile < height)
1483 				{
1484 					yline &= yline_mask;
1485 
1486 					const int gfx_w = spr_gfx->width();
1487 
1488 					for (int xtile = 0; xtile < width; xtile++)
1489 					{
1490 						int xtile_code;
1491 						int ytile_code, yline_addr;
1492 
1493 						if (!xflip)
1494 							xtile_code = xtile;
1495 						else
1496 							xtile_code = (width - xtile - 1);
1497 
1498 						if (!yflip)
1499 						{
1500 							ytile_code = ytile;
1501 							yline_addr = yline;
1502 						}
1503 						else
1504 						{
1505 							ytile_code = (height - ytile - 1);
1506 							yline_addr = (spr_gfx->height() - yline - 1);
1507 						}
1508 
1509 						xtile_code *= height;
1510 						yline_addr *= spr_gfx->rowbytes();
1511 
1512 						const u8* base_addr = spr_gfx->get_data((addr + xtile_code + ytile_code) % spr_gfx->elements()) + yline_addr;
1513 
1514 						int xxx = (xpos + xtile * gfx_w) & 0x1ff;
1515 
1516 						if (!xflip)
1517 						{
1518 							for (int loopcount = 0; loopcount < gfx_w; loopcount++)
1519 							{
1520 								const u8 dat = base_addr[loopcount];
1521 								if (dat) { if (!m_sprite_renderline[xxx]) { m_sprite_renderline[xxx] = dat | (colour << 4) | pri; } else { m_sprite_collision = 1; } }
1522 								xxx++; xxx &= 0x1ff;
1523 								if (--maxpixels == 0x00) return;
1524 							}
1525 						}
1526 						else
1527 						{
1528 							for (int tmpcount = gfx_w - 1, loopcount = 0; loopcount < gfx_w; tmpcount--, loopcount++)
1529 							{
1530 								const u8 dat = base_addr[tmpcount];
1531 								if (dat) { if (!m_sprite_renderline[xxx]) { m_sprite_renderline[xxx] = dat | (colour << 4) | pri; } else { m_sprite_collision = 1; } }
1532 								xxx++; xxx &= 0x1ff;
1533 								if (--maxpixels == 0x00) return;
1534 							}
1535 						}
1536 
1537 					}
1538 				}
1539 			}
1540 
1541 			spritenum = link;
1542 			maxsprites--;
1543 		}
1544 		while ((maxsprites >= 0) && (link != 0));
1545 
1546 	}
1547 }
1548 
get_vcolumn_tilebase(int & vcolumn,int & tile_base,u16 base,int vscroll,int scanline,int vsize,int hsize,int hcolumn)1549 void sega315_5313_device::get_vcolumn_tilebase(int &vcolumn, int &tile_base, u16 base, int vscroll, int scanline, int vsize, int hsize, int hcolumn)
1550 {
1551 	if (m_imode == 3)
1552 	{
1553 		vcolumn = (vscroll + scanline) & ((vsize * 16) - 1);
1554 		tile_base = (base >> 1) + ((vcolumn >> 4) * hsize) + hcolumn;
1555 	}
1556 	else
1557 	{
1558 		vcolumn = (vscroll + scanline) & ((vsize * 8) - 1);
1559 		tile_base = (base >> 1) + ((vcolumn >> 3) * hsize) + hcolumn;
1560 	}
1561 	tile_base &= 0x7fff;
1562 }
1563 
get_window_tilebase(int & tile_base,u16 base,int vcolumn,int window_hsize,int hcolumn)1564 void sega315_5313_device::get_window_tilebase(int &tile_base, u16 base, int vcolumn, int window_hsize, int hcolumn)
1565 {
1566 	if (m_imode == 3)
1567 		tile_base = (base >> 1) + ((vcolumn >> 4) * window_hsize) + hcolumn;
1568 	else
1569 		tile_base = (base >> 1) + ((vcolumn >> 3) * window_hsize) + hcolumn;
1570 
1571 	tile_base &= 0x7fff;
1572 }
1573 
get_nametable(gfx_element * tile_gfx,u16 tile_base,nametable_t & tile,int vcolumn)1574 void sega315_5313_device::get_nametable(gfx_element *tile_gfx, u16 tile_base, nametable_t &tile, int vcolumn)
1575 {
1576 	const u16 tile_dat = MEGADRIV_VDP_VRAM(tile_base);
1577 	tile.xflip = (tile_dat & 0x0800);
1578 	tile.yflip = (tile_dat & 0x1000);
1579 	tile.colour =(tile_dat & 0x6000) >> 13;
1580 	tile.pri =   (tile_dat & 0x8000) >> 15;
1581 	u16 code =   (tile_dat & 0x07ff);
1582 
1583 	if (m_imode == 3)
1584 		code &= 0x3ff;
1585 
1586 	tile.gfx = tile_gfx;
1587 
1588 	const int hmask = tile.gfx->height() - 1;
1589 	tile.addr = tile.gfx->get_data(code % tile.gfx->elements());
1590 
1591 	if (!tile.yflip) tile.addr += (vcolumn & hmask) * tile.gfx->rowbytes();
1592 	else tile.addr += ((hmask - vcolumn) & hmask) * tile.gfx->rowbytes();
1593 }
1594 
draw_tile(nametable_t tile,int start,int end,int & dpos,bool is_fg)1595 inline void sega315_5313_device::draw_tile(nametable_t tile, int start, int end, int &dpos, bool is_fg)
1596 {
1597 	if (!tile.xflip)
1598 	{
1599 		/* 8 pixels */
1600 		for (int shift = start; shift < end; shift++)
1601 		{
1602 			const u8 dat = tile.addr[shift];
1603 			if (!tile.pri)
1604 			{
1605 				if (dat) m_video_renderline[dpos] = dat | (tile.colour << 4);
1606 			}
1607 			else
1608 			{
1609 				if (is_fg)
1610 				{
1611 					if (dat) m_highpri_renderline[dpos] = dat | (tile.colour << 4) | 0x80;
1612 					else m_highpri_renderline[dpos] = m_highpri_renderline[dpos] | 0x80;
1613 				}
1614 				else
1615 				{
1616 					m_highpri_renderline[dpos] = dat | (tile.colour << 4) | 0x80;
1617 				}
1618 			}
1619 			dpos++;
1620 		}
1621 	}
1622 	else
1623 	{
1624 		for (int tmp = tile.gfx->width() - start - 1, shift = start; shift < end; tmp--, shift++)
1625 		{
1626 			const u8 dat = tile.addr[tmp];
1627 			if (!tile.pri)
1628 			{
1629 				if (dat) m_video_renderline[dpos] = dat | (tile.colour << 4);
1630 			}
1631 			else
1632 			{
1633 				if (is_fg)
1634 				{
1635 					if (dat) m_highpri_renderline[dpos] = dat | (tile.colour << 4) | 0x80;
1636 					else m_highpri_renderline[dpos] = m_highpri_renderline[dpos] | 0x80;
1637 				}
1638 				else
1639 				{
1640 					m_highpri_renderline[dpos] = dat | (tile.colour << 4) | 0x80;
1641 				}
1642 			}
1643 			dpos++;
1644 		}
1645 	}
1646 }
1647 
1648 /* Clean up this function (!) */
render_videoline_to_videobuffer(int scanline)1649 void sega315_5313_device::render_videoline_to_videobuffer(int scanline)
1650 {
1651 	gfx_element *tile_gfx = (m_imode == 3) ? gfx(1) : gfx(0);
1652 	u16 base_w = 0;
1653 
1654 	u16 hsize = 64;
1655 	u16 vsize = 64;
1656 	int window_firstline;
1657 	int window_lastline;
1658 	int window_firstcol;
1659 	int window_lastcol;
1660 	int numcolumns = 0;
1661 	int hscroll_a = 0;
1662 	int hscroll_b = 0;
1663 	int window_hsize = 0;
1664 	int window_vsize = 0;
1665 	int non_window_firstcol;
1666 	int non_window_lastcol;
1667 	const int screenheight = MEGADRIVE_REG01_240_LINE ? 240 : 224;
1668 	struct nametable_t tile;
1669 	unsigned horz = m_lcm_scaling ? hres[get_hres()] : 320;
1670 
1671 	/* Clear our Render Buffer */
1672 	for (int x = 0; x < horz; x++)
1673 	{
1674 		m_video_renderline[x] = MEGADRIVE_REG07_BGCOLOUR | 0x20000; // mark as BG
1675 	}
1676 
1677 	memset(m_highpri_renderline.get(), 0, horz);
1678 
1679 	/* is this line enabled? */
1680 	if (!MEGADRIVE_REG01_DISP_ENABLE)
1681 	{
1682 		//osd_printf_debug("line disabled %d\n", scanline);
1683 		return;
1684 	}
1685 
1686 	/* looks different? */
1687 	if (MEGADRIVE_REG0_DISPLAY_DISABLE)
1688 	{
1689 		return;
1690 	}
1691 
1692 	const u16 base_a = MEGADRIVE_REG02_PATTERN_ADDR_A << 13;
1693 	const u16 base_b = MEGADRIVE_REG04_PATTERN_ADDR_B << 13;
1694 	const u16 size   = MEGADRIVE_REG10_HSCROLL_SIZE | (MEGADRIVE_REG10_VSCROLL_SIZE << 4);
1695 	const u16 window_right = MEGADRIVE_REG11_WINDOW_RIGHT;
1696 //  const u16 window_hpos = MEGADRIVE_REG11_WINDOW_HPOS;
1697 	const u16 window_down = MEGADRIVE_REG12_WINDOW_DOWN;
1698 //  const u16 window_vpos = MEGADRIVE_REG12_WINDOW_VPOS;
1699 
1700 	const int screenwidth = get_hres();
1701 
1702 	switch (screenwidth)
1703 	{
1704 		case 0: numcolumns = 32; window_hsize = 32; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W & 0x1f) << 11; break;
1705 		case 1: numcolumns = 32; window_hsize = 32; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W & 0x1f) << 11; break;
1706 		case 2: numcolumns = 40; window_hsize = 64; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W & 0x1e) << 11; break;
1707 		case 3: numcolumns = 40; window_hsize = 64; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W & 0x1e) << 11; break; // talespin cares about base mask, used for status bar
1708 	}
1709 
1710 	//osd_printf_debug("screenwidth %d\n", screenwidth);
1711 
1712 	//base_w = machine().rand() & 0xff;
1713 
1714 	/* Calculate Exactly where we're going to draw the Window, and if the Window Bug applies */
1715 	int window_is_bugged = 0;
1716 	if (window_right)
1717 	{
1718 		window_firstcol = MEGADRIVE_REG11_WINDOW_HPOS * 16;
1719 		window_lastcol = numcolumns * 8;
1720 		if (window_firstcol > window_lastcol) window_firstcol = window_lastcol;
1721 
1722 		non_window_firstcol = 0;
1723 		non_window_lastcol = window_firstcol;
1724 	}
1725 	else
1726 	{
1727 		window_firstcol = 0;
1728 		window_lastcol = MEGADRIVE_REG11_WINDOW_HPOS * 16;
1729 		if (window_lastcol > numcolumns * 8) window_lastcol = numcolumns * 8;
1730 
1731 		non_window_firstcol = window_lastcol;
1732 		non_window_lastcol = numcolumns * 8;
1733 
1734 		if (window_lastcol != 0) window_is_bugged = 1;
1735 	}
1736 
1737 	if (window_down)
1738 	{
1739 		window_firstline = MEGADRIVE_REG12_WINDOW_VPOS * 8;
1740 		window_lastline = screenheight; // 240 in PAL?
1741 		if (window_firstline > screenheight) window_firstline = screenheight;
1742 	}
1743 	else
1744 	{
1745 		window_firstline = 0;
1746 		window_lastline = MEGADRIVE_REG12_WINDOW_VPOS * 8;
1747 		if (window_lastline > screenheight) window_lastline = screenheight;
1748 	}
1749 
1750 	/* if we're on a window scanline between window_firstline and window_lastline the window is the full width of the screen */
1751 	if (scanline >= window_firstline && scanline < window_lastline)
1752 	{
1753 		window_firstcol = 0; window_lastcol = numcolumns * 8; // window is full-width of the screen
1754 		non_window_firstcol = 0; non_window_lastcol = 0; // disable non-window
1755 	}
1756 
1757 //  const u8  vscroll_mode = MEGADRIVE_REG0B_VSCROLL_MODE;
1758 //  const u8  hscroll_mode = MEGADRIVE_REG0B_HSCROLL_MODE;
1759 	const u16 hscroll_base = MEGADRIVE_REG0D_HSCROLL_ADDR << 10;
1760 
1761 	switch (size)
1762 	{
1763 		case 0x00: hsize = 32;  vsize = 32; break;
1764 		case 0x01: hsize = 64;  vsize = 32; break;
1765 		case 0x02: hsize = 64;  vsize = 1; /* osd_printf_debug("Invalid HSize! %02x\n", size);*/ break;
1766 		case 0x03: hsize = 128; vsize = 32; break;
1767 
1768 		case 0x10: hsize = 32;  vsize = 64; break;
1769 		case 0x11: hsize = 64;  vsize = 64; break;
1770 		case 0x12: hsize = 64;  vsize = 1; /*osd_printf_debug("Invalid HSize! %02x\n", size);*/ break;
1771 		case 0x13: hsize = 128; vsize = 32;/*osd_printf_debug("Invalid Total Size! %02x\n", size);*/break;
1772 
1773 		case 0x20: hsize = 32;  vsize = 64; osd_printf_debug("Invalid VSize!\n"); break;
1774 		case 0x21: hsize = 64;  vsize = 64; osd_printf_debug("Invalid VSize!\n"); break;
1775 		case 0x22: hsize = 64;  vsize = 1; /*osd_printf_debug("Invalid HSize & Invalid VSize!\n");*/ break;
1776 		case 0x23: hsize = 128; vsize = 64; osd_printf_debug("Invalid VSize!\n"); break;
1777 
1778 		case 0x30: hsize = 32;  vsize = 128; break;
1779 		case 0x31: hsize = 64;  vsize = 64; /*osd_printf_debug("Invalid Total Size! %02x\n", size);*/break; // super skidmarks attempts this..
1780 		case 0x32: hsize = 64;  vsize = 1; /*osd_printf_debug("Invalid HSize & Invalid Total Size!\n");*/ break;
1781 		case 0x33: hsize = 128; vsize = 128; osd_printf_debug("Invalid Total Size! %02x\n", size); break;
1782 	}
1783 
1784 	switch (MEGADRIVE_REG0B_HSCROLL_MODE)
1785 	{
1786 		case 0x00: // Full Screen Scroll
1787 			hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0);
1788 			hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1);
1789 			break;
1790 
1791 		case 0x01: // 'Broken' Line Scroll
1792 			if (m_imode == 3)
1793 			{
1794 				hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0 + ((scanline >> 1) & 7) * 2);
1795 				hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1 + ((scanline >> 1) & 7) * 2);
1796 			}
1797 			else
1798 			{
1799 				hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0 + (scanline & 7) * 2);
1800 				hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1 + (scanline & 7) * 2);
1801 			}
1802 			break;
1803 
1804 		case 0x02: // Cell Scroll
1805 			if (m_imode == 3)
1806 			{
1807 				hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0 + ((scanline >> 1) & ~7) * 2);
1808 				hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1 + ((scanline >> 1) & ~7) * 2);
1809 			}
1810 			else
1811 			{
1812 				hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0 + (scanline & ~7) * 2);
1813 				hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1 + (scanline & ~7) * 2);
1814 			}
1815 			break;
1816 
1817 		case 0x03: // Full Line Scroll
1818 			if (m_imode == 3)
1819 			{
1820 				hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0 + (scanline >> 1) * 2);
1821 				hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1 + (scanline >> 1) * 2);
1822 			}
1823 			else
1824 			{
1825 				hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 0 + scanline * 2);
1826 				hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base >> 1) + 1 + scanline * 2);
1827 			}
1828 			break;
1829 	}
1830 
1831 	int vscroll;
1832 	/* Low Priority B Tiles */
1833 	{
1834 		for (int column = 0; column < numcolumns / 2; column++)
1835 		{   /* 20x 16x1 blocks */
1836 			int vcolumn;
1837 
1838 			/* Get V Scroll Value for this block */
1839 
1840 			int dpos = column * 16;
1841 
1842 			{
1843 				/* hscroll is not divisible by 8, this segment will contain 3 tiles, 1 partial, 1 whole, 1 partial */
1844 				const int hscroll_part = 8 - (hscroll_b & 7);
1845 				int tile_base;
1846 
1847 				if (MEGADRIVE_REG0B_VSCROLL_MODE)
1848 				{
1849 					if (hscroll_b & 0xf) vscroll = m_vsram[((column - 1) * 2 + 1) & 0x3f];
1850 					else vscroll = m_vsram[(column * 2 + 1) & 0x3f];
1851 				}
1852 				else
1853 				{
1854 					vscroll = m_vsram[1];
1855 				}
1856 
1857 				int hcolumn = ((column * 2 - 1) - (hscroll_b >> 3)) & (hsize - 1);
1858 
1859 				get_vcolumn_tilebase(vcolumn, tile_base, base_b, vscroll, scanline, vsize, hsize, hcolumn);
1860 				get_nametable(tile_gfx, tile_base, tile, vcolumn);
1861 				draw_tile(tile, hscroll_part, 8, dpos, false);
1862 
1863 				if (MEGADRIVE_REG0B_VSCROLL_MODE)
1864 				{
1865 					if (hscroll_b & 0xf) vscroll = m_vsram[((column - 1) * 2 + 1) & 0x3f];
1866 					else vscroll = m_vsram[(column * 2 + 1) & 0x3f];
1867 				}
1868 				else
1869 				{
1870 					vscroll = m_vsram[1];
1871 				}
1872 
1873 				hcolumn = ((column * 2) - (hscroll_b >> 3)) & (hsize - 1);
1874 
1875 				get_vcolumn_tilebase(vcolumn, tile_base, base_b, vscroll, scanline, vsize, hsize, hcolumn);
1876 				get_nametable(tile_gfx, tile_base, tile, vcolumn);
1877 				draw_tile(tile, 0, 8, dpos, false);
1878 
1879 				if (MEGADRIVE_REG0B_VSCROLL_MODE)
1880 				{
1881 					vscroll = m_vsram[(column * 2 + 1) & 0x3f];
1882 				}
1883 				else
1884 				{
1885 					vscroll = m_vsram[1];
1886 				}
1887 
1888 				hcolumn = ((column * 2 + 1) - (hscroll_b >> 3)) & (hsize - 1);
1889 
1890 				get_vcolumn_tilebase(vcolumn, tile_base, base_b, vscroll, scanline, vsize, hsize, hcolumn);
1891 				get_nametable(tile_gfx, tile_base, tile, vcolumn);
1892 				draw_tile(tile, 0, hscroll_part, dpos, false);
1893 			}
1894 		}
1895 		/* END */
1896 	}
1897 	/* Low Priority A Tiles + Window(!) */
1898 
1899 	{
1900 		for (int column = window_firstcol / 16; column < window_lastcol / 16; column++)
1901 		{
1902 			int tile_base;
1903 
1904 			const int vcolumn = scanline & ((window_vsize * 8) - 1);
1905 			int dpos = column * 16;
1906 			int hcolumn = (column * 2) & (window_hsize - 1);
1907 
1908 			get_window_tilebase(tile_base, base_w, vcolumn, window_hsize, hcolumn);
1909 			get_nametable(tile_gfx, tile_base, tile, vcolumn);
1910 			draw_tile(tile, 0, 8, dpos, true);
1911 
1912 			hcolumn = (column * 2 + 1) & (window_hsize - 1);
1913 
1914 			get_window_tilebase(tile_base, base_w, vcolumn, window_hsize, hcolumn);
1915 			get_nametable(tile_gfx, tile_base, tile, vcolumn);
1916 			draw_tile(tile, 0, 8, dpos, true);
1917 		}
1918 
1919 		/* Non Window Part */
1920 
1921 		for (int column = non_window_firstcol / 16; column < non_window_lastcol / 16; column++)
1922 		{   /* 20x 16x1 blocks */
1923 		//  int xx;
1924 			int vcolumn;
1925 
1926 			int dpos = column * 16;
1927 
1928 			{   /* hscroll is not divisible by 8, this segment will contain 3 tiles, 1 partial, 1 whole, 1 partial */
1929 				const int hscroll_part = 8 - (hscroll_a & 7);
1930 				int hcolumn;
1931 				int tile_base;
1932 
1933 				if (MEGADRIVE_REG0B_VSCROLL_MODE)
1934 				{
1935 					if (hscroll_a & 0xf) vscroll = m_vsram[((column - 1) * 2 + 0) & 0x3f];
1936 					else vscroll = m_vsram[(column * 2 + 0) & 0x3f];
1937 				}
1938 				else
1939 				{
1940 					vscroll = m_vsram[0];
1941 				}
1942 
1943 				if ((!window_is_bugged) || ((hscroll_a & 0xf) == 0) || (column > non_window_firstcol / 16)) hcolumn = ((column * 2 - 1) - (hscroll_a >> 3)) & (hsize - 1);
1944 				else hcolumn = ((column * 2 + 1) - (hscroll_a >> 3)) & (hsize - 1);
1945 
1946 				get_vcolumn_tilebase(vcolumn, tile_base, base_a, vscroll, scanline, vsize, hsize, hcolumn);
1947 				get_nametable(tile_gfx, tile_base, tile, vcolumn);
1948 				draw_tile(tile, hscroll_part, 8, dpos, true);
1949 
1950 				if (MEGADRIVE_REG0B_VSCROLL_MODE)
1951 				{
1952 					if (hscroll_a & 0xf) vscroll = m_vsram[((column - 1) * 2 + 0) & 0x3f];
1953 					else vscroll = m_vsram[(column * 2 + 0) & 0x3f];
1954 				}
1955 				else
1956 				{
1957 					vscroll = m_vsram[0];
1958 				}
1959 
1960 				if ((!window_is_bugged) || ((hscroll_a & 0xf) == 0) || (column > non_window_firstcol / 16)) hcolumn = ((column * 2) - (hscroll_a >> 3)) & (hsize - 1); // not affected by bug?
1961 				else
1962 				{
1963 					if ((hscroll_a & 0xf) < 8) hcolumn = ((column * 2) - (hscroll_a >> 3)) & (hsize - 1);
1964 					else hcolumn = ((column * 2 + 2) - (hscroll_a >> 3)) & (hsize - 1);
1965 				}
1966 
1967 				get_vcolumn_tilebase(vcolumn, tile_base, base_a, vscroll, scanline, vsize, hsize, hcolumn);
1968 				get_nametable(tile_gfx, tile_base, tile, vcolumn);
1969 				draw_tile(tile, 0, 8, dpos, true);
1970 
1971 				if (MEGADRIVE_REG0B_VSCROLL_MODE)
1972 				{
1973 					vscroll = m_vsram[(column * 2 + 0) & 0x3f];
1974 				}
1975 				else
1976 				{
1977 					vscroll = m_vsram[0];
1978 				}
1979 
1980 				if ((!window_is_bugged) || ((hscroll_a & 0xf) == 0) || (column > non_window_firstcol / 16)) hcolumn = ((column * 2 + 1) - (hscroll_a >> 3)) & (hsize - 1);
1981 				else hcolumn = ((column * 2 + 1) - (hscroll_a >> 3)) & (hsize - 1);
1982 
1983 				get_vcolumn_tilebase(vcolumn, tile_base, base_a, vscroll, scanline, vsize, hsize, hcolumn);
1984 				get_nametable(tile_gfx, tile_base, tile, vcolumn);
1985 				draw_tile(tile, 0, hscroll_part, dpos, true);
1986 			}
1987 		}
1988 	}
1989 		/* END */
1990 
1991 /* MEGADRIVE_REG0C_SHADOW_HIGLIGHT */
1992 	/* Low Priority Sprites */
1993 	for (int x = 0; x < horz; x++)
1994 	{
1995 		if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT)
1996 		{
1997 			if (m_sprite_renderline[x + 128] & 0x40)
1998 			{
1999 				m_video_renderline[x] = m_sprite_renderline[x + 128] & 0x3f;
2000 				m_video_renderline[x] |= 0x10000; // mark as sprite pixel
2001 			}
2002 		}
2003 		else
2004 		{
2005 			/* Special Shadow / Highlight processing */
2006 			if (m_sprite_renderline[x + 128] & 0x40)
2007 			{
2008 				const u8 spritedata = m_sprite_renderline[x + 128] & 0x3f;
2009 
2010 				if ((spritedata == 0x0e) || (spritedata == 0x1e) || (spritedata == 0x2e))
2011 				{
2012 					/* BUG in sprite chip, these colours are always normal intensity */
2013 					m_video_renderline[x] = spritedata | 0x4000;
2014 					m_video_renderline[x] |= 0x10000; // mark as sprite pixel
2015 				}
2016 				else if (spritedata == 0x3e)
2017 				{
2018 					/* Everything below this is half colour, mark with 0x8000 to mark highlight' */
2019 					m_video_renderline[x] = m_video_renderline[x] | 0x8000; // spiderwebs..
2020 				}
2021 				else if (spritedata == 0x3f)
2022 				{
2023 					/* This is a Shadow operator, but everything below is already low pri, no effect */
2024 					m_video_renderline[x] = m_video_renderline[x] | 0x2000;
2025 				}
2026 				else
2027 				{
2028 					m_video_renderline[x] = spritedata;
2029 					m_video_renderline[x] |= 0x10000; // mark as sprite pixel
2030 				}
2031 			}
2032 		}
2033 	}
2034 
2035 	/* High Priority A+B Tiles */
2036 	for (int x = 0; x < horz; x++)
2037 	{
2038 		if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT)
2039 		{
2040 			/* Normal Processing */
2041 			const int dat = m_highpri_renderline[x];
2042 
2043 			if (dat & 0x80)
2044 			{
2045 				if (dat & 0x0f) m_video_renderline[x] = m_highpri_renderline[x] & 0x3f;
2046 			}
2047 		}
2048 		else
2049 		{
2050 			/* Shadow / Highlight Mode */
2051 			const int dat = m_highpri_renderline[x];
2052 
2053 			if (dat & 0x80)
2054 			{
2055 				if (dat & 0x0f) m_video_renderline[x] = (m_highpri_renderline[x] & 0x3f) | 0x4000;
2056 				else m_video_renderline[x] = m_video_renderline[x] | 0x4000; // set 'normal'
2057 			}
2058 		}
2059 	}
2060 
2061 	/* High Priority Sprites */
2062 	for (int x = 0; x < horz; x++)
2063 	{
2064 		if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT)
2065 		{
2066 			/* Normal */
2067 			if (m_sprite_renderline[x + 128] & 0x80)
2068 			{
2069 				m_video_renderline[x] = m_sprite_renderline[x + 128] & 0x3f;
2070 				m_video_renderline[x] |= 0x10000; // mark as sprite pixel
2071 			}
2072 		}
2073 		else
2074 		{
2075 			if (m_sprite_renderline[x + 128] & 0x80)
2076 			{
2077 				const u8 spritedata = m_sprite_renderline[x + 128] & 0x3f;
2078 
2079 				if (spritedata == 0x3e)
2080 				{
2081 					/* set flag 0x8000 to indicate highlight */
2082 					m_video_renderline[x] = m_video_renderline[x] | 0x8000;
2083 				}
2084 				else if (spritedata == 0x3f)
2085 				{
2086 					/* This is a Shadow operator set shadow bit */
2087 					m_video_renderline[x] = m_video_renderline[x] | 0x2000;
2088 				}
2089 				else
2090 				{
2091 					m_video_renderline[x] = spritedata | 0x4000;
2092 					m_video_renderline[x] |= 0x10000; // mark as sprite pixel
2093 				}
2094 			}
2095 		}
2096 	}
2097 }
2098 
2099 
2100 /* This converts our render buffer to real screen colours */
render_videobuffer_to_screenbuffer(int scanline)2101 void sega315_5313_device::render_videobuffer_to_screenbuffer(int scanline)
2102 {
2103 	const unsigned palette_per_scanline = scanline * 64;
2104 	u32 *lineptr;
2105 	unsigned horz = m_lcm_scaling ? hres[get_hres()] : 320;
2106 	unsigned mul = m_lcm_scaling ? hres_mul[get_hres()] : 1;
2107 
2108 	if (!m_use_alt_timing)
2109 	{
2110 		if (scanline >= m_render_bitmap->height()) // safety, shouldn't happen now we allocate a fixed amount tho
2111 			return;
2112 
2113 		lineptr = &m_render_bitmap->pix(scanline);
2114 	}
2115 	else
2116 		lineptr = m_render_line.get();
2117 
2118 	if (m_use_cram)
2119 	{
2120 		for (int p = 0; p < 64; p++)
2121 		{
2122 			u16 clut = m_palette_lookup[p];
2123 			if (!MEGADRIVE_REG0_SPECIAL_PAL) // 3 bit color mode, correct?
2124 				clut &= 0x49; // (1 << 6) | (1 << 3) | (1 << 0);
2125 
2126 			m_gfx_palette->set_pen_color(        p + palette_per_scanline, m_palette_lut->pen(clut));
2127 			m_gfx_palette_shadow->set_pen_color( p + palette_per_scanline, m_palette_lut->pen(0x200 | clut));
2128 			m_gfx_palette_hilight->set_pen_color(p + palette_per_scanline, m_palette_lut->pen(0x400 | clut));
2129 		}
2130 	}
2131 
2132 	for (int srcx = 0, xx = 0, dstx = 0; srcx < horz; dstx++)
2133 	{
2134 		const u32 dat = m_video_renderline[srcx];
2135 		const u16 clut = (dat & 0x3f) + palette_per_scanline;
2136 
2137 		if (!(dat & 0x20000))
2138 			m_render_line_raw[srcx] = 0x100;
2139 		else
2140 			m_render_line_raw[srcx] = 0x000;
2141 
2142 		if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT)
2143 		{
2144 			if (dat & 0x10000)
2145 			{
2146 				lineptr[dstx] = m_gfx_palette->pen(clut);
2147 				m_render_line_raw[srcx] |= (dat & 0x3f) | 0x080;
2148 			}
2149 			else
2150 			{
2151 				lineptr[dstx] = m_gfx_palette->pen(clut);
2152 				m_render_line_raw[srcx] |= (dat & 0x3f) | 0x040;
2153 			}
2154 		}
2155 		else
2156 		{
2157 			/* Verify my handling.. I'm not sure all cases are correct */
2158 			switch (dat & 0x1e000)
2159 			{
2160 				case 0x00000: // low priority, no shadow sprite, no highlight = shadow
2161 				case 0x02000: // low priority, shadow sprite, no highlight = shadow
2162 				case 0x06000: // normal pri,   shadow sprite, no highlight = shadow?
2163 				case 0x10000: // (sprite) low priority, no shadow sprite, no highlight = shadow
2164 				case 0x12000: // (sprite) low priority, shadow sprite, no highlight = shadow
2165 				case 0x16000: // (sprite) normal pri,   shadow sprite, no highlight = shadow?
2166 					lineptr[dstx] = m_gfx_palette_shadow->pen(clut);
2167 					m_render_line_raw[srcx] |= (dat & 0x3f) | 0x000;
2168 					break;
2169 
2170 				case 0x4000: // normal pri, no shadow sprite, no highlight = normal;
2171 				case 0x8000: // low pri, highlight sprite = normal;
2172 					lineptr[dstx] = m_gfx_palette->pen(clut);
2173 					m_render_line_raw[srcx] |= (dat & 0x3f) | 0x040;
2174 					break;
2175 
2176 				case 0x14000: // (sprite) normal pri, no shadow sprite, no highlight = normal;
2177 				case 0x18000: // (sprite) low pri, highlight sprite = normal;
2178 					lineptr[dstx] = m_gfx_palette->pen(clut);
2179 					m_render_line_raw[srcx] |= (dat & 0x3f) | 0x080;
2180 					break;
2181 
2182 				case 0x0c000: // normal pri, highlight set = highlight?
2183 				case 0x1c000: // (sprite) normal pri, highlight set = highlight?
2184 					lineptr[dstx] = m_gfx_palette_hilight->pen(clut);
2185 					m_render_line_raw[srcx] |= (dat & 0x3f) | 0x0c0;
2186 					break;
2187 
2188 				case 0x0a000: // shadow set, highlight set - not possible
2189 				case 0x0e000: // shadow set, highlight set, normal set, not possible
2190 				case 0x1a000: // (sprite)shadow set, highlight set - not possible
2191 				case 0x1e000: // (sprite)shadow set, highlight set, normal set, not possible
2192 				default:
2193 					lineptr[dstx] = m_render_line_raw[srcx] |= (machine().rand() & 0x3f);
2194 					break;
2195 			}
2196 		}
2197 		if (++xx >= mul)
2198 		{
2199 			srcx++;
2200 			xx = 0;
2201 		}
2202 	}
2203 
2204 	if (!m_32x_scanline_helper_func.isnull())
2205 		m_32x_scanline_helper_func(scanline);
2206 	if (!m_32x_scanline_func.isnull())
2207 	{
2208 		for (int srcx = 0, xx = 0, dstx = 0; srcx < horz; dstx++)
2209 		{
2210 			m_32x_scanline_func(srcx, m_video_renderline[srcx] & 0x20000, lineptr[dstx]);
2211 			if (++xx >= mul)
2212 			{
2213 				srcx++;
2214 				xx = 0;
2215 			}
2216 		}
2217 	}
2218 }
2219 
TIMER_CALLBACK_MEMBER(sega315_5313_device::render_scanline)2220 TIMER_CALLBACK_MEMBER(sega315_5313_device::render_scanline)
2221 {
2222 	const int scanline = get_scanline_counter();
2223 
2224 	if (scanline >= 0 && scanline < m_visible_scanlines)
2225 	{
2226 		//if (MEGADRIVE_REG01_DMA_ENABLE == 0) osd_printf_debug("off\n");
2227 		render_spriteline_to_spritebuffer(get_scanline_counter());
2228 		render_videoline_to_videobuffer(scanline);
2229 		render_videobuffer_to_screenbuffer(scanline);
2230 	}
2231 }
2232 
vdp_handle_scanline_callback(int scanline)2233 void sega315_5313_device::vdp_handle_scanline_callback(int scanline)
2234 {
2235 /* Compensate for some rounding errors
2236 
2237        When the counter reaches 261 we should have reached the end of the frame, however due
2238        to rounding errors in the timer calculation we're not quite there.  Let's assume we are
2239        still in the previous scanline for now.
2240     */
2241 
2242 	if (get_scanline_counter() != (m_total_scanlines - 1))
2243 	{
2244 		if (!m_use_alt_timing) m_scanline_counter++;
2245 //      osd_printf_debug("scanline %d\n", get_scanline_counter());
2246 		m_render_timer->adjust(attotime::from_usec(1));
2247 
2248 		if (get_scanline_counter() == m_irq6_scanline)
2249 		{
2250 		//  osd_printf_debug("x %d", get_scanline_counter());
2251 			m_irq6_on_timer->adjust(attotime::from_usec(6));
2252 			m_irq6_pending = 1;
2253 			m_vblank_flag = 1;
2254 
2255 		}
2256 
2257 	//  if (get_scanline_counter() == 0) m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE;
2258 		// m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE;
2259 
2260 		if (get_scanline_counter()<=224)
2261 		{
2262 			m_irq4counter--;
2263 
2264 			if (m_irq4counter== - 1)
2265 			{
2266 				if (m_imode == 3) m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE * 2;
2267 				else m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE;
2268 
2269 				m_irq4_pending = 1;
2270 
2271 				if (MEGADRIVE_REG0_IRQ4_ENABLE)
2272 				{
2273 					m_irq4_on_timer->adjust(attotime::from_usec(1));
2274 					//osd_printf_debug("irq4 on scanline %d reload %d\n", get_scanline_counter(), MEGADRIVE_REG0A_HINT_VALUE);
2275 				}
2276 			}
2277 		}
2278 		else
2279 		{
2280 			if (m_imode == 3) m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE * 2;
2281 			else m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE;
2282 		}
2283 
2284 		//if (get_scanline_counter() == 0) irq4_on_timer->adjust(attotime::from_usec(2));
2285 
2286 		if (get_scanline_counter() == m_z80irq_scanline)
2287 		{
2288 			m_sndirqline_callback(true);
2289 		}
2290 		if (get_scanline_counter() == m_z80irq_scanline + 1)
2291 		{
2292 			m_sndirqline_callback(false);
2293 		}
2294 	}
2295 	else /* pretend we're still on the same scanline to compensate for rounding errors */
2296 	{
2297 		if (!m_use_alt_timing) m_scanline_counter = m_total_scanlines - 1;
2298 	}
2299 
2300 	// 32x interrupts!
2301 	if (!m_32x_interrupt_func.isnull())
2302 		m_32x_interrupt_func(get_scanline_counter(), m_irq6_scanline);
2303 }
2304 
2305 
vdp_handle_eof()2306 void sega315_5313_device::vdp_handle_eof()
2307 {
2308 	rectangle visarea;
2309 	int scr_width = 320;
2310 	int scr_mul = 1;
2311 
2312 	m_vblank_flag = 0;
2313 	//m_irq6_pending = 0; /* NO! (breaks warlock) */
2314 
2315 	/* Set it to -1 here, so it becomes 0 when the first timer kicks in */
2316 	if (!m_use_alt_timing) m_scanline_counter = -1;
2317 	m_sprite_collision = 0;//? when to reset this ..
2318 	m_imode = MEGADRIVE_REG0C_INTERLEAVE; // can't change mid-frame..
2319 	m_imode_odd_frame ^= 1;
2320 //      m_genesis_snd_z80->set_input_line(0, CLEAR_LINE); // if the z80 interrupt hasn't happened by now, clear it..
2321 
2322 	if (MEGADRIVE_REG01_240_LINE)
2323 	{
2324 		/* this is invalid in PAL! */
2325 		m_total_scanlines = m_base_total_scanlines;
2326 		m_visible_scanlines = 240;
2327 		m_irq6_scanline = 240;
2328 		m_z80irq_scanline = 240;
2329 	}
2330 	else
2331 	{
2332 		m_total_scanlines = m_base_total_scanlines;
2333 		m_visible_scanlines = 224;
2334 		m_irq6_scanline = 224;
2335 		m_z80irq_scanline = 224;
2336 	}
2337 
2338 	if (m_imode == 3)
2339 	{
2340 		m_total_scanlines <<= 1;
2341 		m_visible_scanlines <<= 1;
2342 		m_irq6_scanline <<= 1;
2343 		m_z80irq_scanline <<= 1;
2344 	}
2345 
2346 	/* note, add 240 mode + init new timings! */
2347 	scr_mul = m_lcm_scaling ? hres_mul[get_hres()] : 1;
2348 	scr_width = hres[get_hres()] * scr_mul;
2349 //      osd_printf_debug("my mode %02x", m_regs[0x0c]);
2350 
2351 	visarea.set(0, scr_width - 1, 0, m_visible_scanlines - 1);
2352 
2353 	screen().configure(480 * scr_mul, m_total_scanlines, visarea, screen().frame_period().attoseconds());
2354 }
2355 
2356 
2357 // called at the start of each scanline
TIMER_DEVICE_CALLBACK_MEMBER(sega315_5313_device::megadriv_scanline_timer_callback)2358 TIMER_DEVICE_CALLBACK_MEMBER(sega315_5313_device::megadriv_scanline_timer_callback)
2359 {
2360 	if (!m_use_alt_timing)
2361 	{
2362 		machine().scheduler().synchronize();
2363 		vdp_handle_scanline_callback(param);
2364 
2365 		m_megadriv_scanline_timer->adjust(attotime::from_hz(get_framerate()) / double(m_total_scanlines));
2366 	}
2367 	else
2368 	{
2369 		vdp_handle_scanline_callback(param);
2370 	}
2371 }
2372 
TIMER_DEVICE_CALLBACK_MEMBER(sega315_5313_device::megadriv_scanline_timer_callback_alt_timing)2373 TIMER_DEVICE_CALLBACK_MEMBER(sega315_5313_device::megadriv_scanline_timer_callback_alt_timing)
2374 {
2375 	if (m_use_alt_timing)
2376 	{
2377 		if (param == 0)
2378 		{
2379 			//printf("where are we? %d %d\n", screen().vpos(), screen_hpos());
2380 			vdp_handle_eof();
2381 			//vdp_clear_bitmap();
2382 		}
2383 
2384 		vdp_handle_scanline_callback(param);
2385 
2386 		const int vpos = screen().vpos();
2387 		if (vpos > 0)
2388 			screen().update_partial(vpos - 1);
2389 	}
2390 }
2391