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