1 // license:LGPL-2.1+
2 // copyright-holders:Angelo Salese,Ryan Holtz
3 /***************************************************************************
4 
5 
6     Funtech Super A'Can
7     -------------------
8 
9     Preliminary driver by Angelo Salese
10     Improvements by Ryan Holtz
11 
12 
13 *******************************************************************************
14 
15 INFO:
16 
17     The system unit contains a reset button.
18 
19     Controllers:
20     - 4 directional buttons
21     - A, B, X, Y, buttons
22     - Start, select buttons
23     - L, R shoulder buttons
24 
25 STATUS:
26 
27     The driver is begging for a re-write or at least a split into video/supracan.c.  It will happen eventually.
28 
29     Sound chip is completely unknown.
30 
31     There are 6 interrupt sources on the 6502 side, all of which use the IRQ line.
32     The register at 0x411 is bitmapped to indicate what source(s) are active.
33     In priority order from most to least important, they are:
34 
35     411 value  How acked                     Notes
36     0x40       read reg 0x16 of sound chip   likely timer. snd regs 0x16/0x17 are time constant, write 0 to reg 0x9f to start
37     0x04       read at 0x405                 latch 1?  0xcd is magic value
38     0x08       read at 0x404                 latch 2?  0xcd is magic value
39     0x10       read at 0x409                 unknown, dispatched but not used in startup 6502 code
40     0x20       read at 0x40a                 IRQ request from 68k, flags data available in shared-RAM mailbox
41     0x80       read reg 0x14 of sound chip   depends on reg 0x14 of sound chip & 0x40: if not set writes 0x8f to reg 0x14,
42                                              otherwise writes 0x4f to reg 0x14 and performs additional processing
43 
44     Known unemulated graphical effects and issues:
45     - All: Sprite sizing is still imperfect.
46     - All: Sprites need to be converted to use scanline rendering for proper clipping.
47     - All: Improperly-emulated 1bpp ROZ mode, used by the Super A'Can BIOS logo.
48     - All: Unimplemented ROZ scaling tables, used by the Super A'Can BIOS logo and Speedy Dragon intro, among others.
49     - All: Priorities are largely unknown.
50     - C.U.G.: Gameplay backgrounds are broken.
51     - Sango Fighter: Possible missing masking on the upper edges of the screen during gameplay.
52     - Sango Fighter: Raster effects off by 1 line
53     - Sango Fighter: Specifies tiles out of range of video ram??
54     - Speedy Dragon: Backgrounds are broken (wrong tile bank/region).
55     - Super Taiwanese Baseball League: Does not boot, uses an unemulated DMA type
56     - Super Taiwanese Baseball League: Missing window effect applied on tilemaps?
57     - The Son of Evil: Many graphical issues.
58     - Visible area, looks like it should be 224 pixels high at most, most games need 8 off the top and 8 off the bottom (or a global scroll)
59       Sango looks like it needs 16 off the bottom instead
60       Visible area is almost certainly 224 as Son of Evil has an explicit check in the vblank handler
61 
62     - All: are ALL the layers ROZ capable??
63 
64 DEBUG TRICKS:
65 
66     baseball game debug trick:
67     wpset e90020,1f,w
68     do pc=5ac40
69     ...
70     do pc=5acd4
71     wpclear
72     bp 0269E4
73     [ff7be4] <- 0x269ec
74     bpclear
75 
76 ***************************************************************************/
77 
78 #include "emu.h"
79 #include "cpu/m68000/m68000.h"
80 #include "cpu/m6502/m6502.h"
81 #include "bus/generic/slot.h"
82 #include "bus/generic/carts.h"
83 #include "emupal.h"
84 #include "screen.h"
85 #include "softlist.h"
86 #include "tilemap.h"
87 
88 #define DRAW_DEBUG_ROZ          (0)
89 
90 #define DRAW_DEBUG_UNK_SPRITE   (0)
91 
92 #define DEBUG_PRIORITY          (0)
93 #define DEBUG_PRIORITY_INDEX    (0) // 0-3
94 
95 #define LOG_UNKNOWNS    (1 << 0)
96 #define LOG_DMA         (1 << 1)
97 #define LOG_SPRDMA      (1 << 2)
98 #define LOG_SPRITES     (1 << 3)
99 #define LOG_TILEMAP0    (1 << 4)
100 #define LOG_TILEMAP1    (1 << 5)
101 #define LOG_TILEMAP2    (1 << 6)
102 #define LOG_ROZ         (1 << 7)
103 #define LOG_HFVIDEO     (1 << 8)
104 #define LOG_IRQS        (1 << 9)
105 #define LOG_SOUND       (1 << 10)
106 #define LOG_HFUNKNOWNS  (1 << 11)
107 #define LOG_68K_SOUND   (1 << 12)
108 #define LOG_CONTROLS    (1 << 13)
109 #define LOG_VIDEO       (LOG_SPRDMA | LOG_SPRITES | LOG_TILEMAP0 | LOG_TILEMAP1 | LOG_TILEMAP2 | LOG_ROZ)
110 #define LOG_ALL         (LOG_UNKNOWNS | LOG_HFUNKNOWNS | LOG_DMA | LOG_VIDEO | LOG_HFVIDEO | LOG_IRQS | LOG_SOUND | LOG_68K_SOUND | LOG_CONTROLS)
111 #define LOG_DEFAULT     (LOG_ALL & ~(LOG_HFVIDEO | LOG_HFUNKNOWNS))
112 
113 #define VERBOSE         (0)
114 #include "logmacro.h"
115 
116 class supracan_state : public driver_device
117 {
118 public:
supracan_state(const machine_config & mconfig,device_type type,const char * tag)119 	supracan_state(const machine_config &mconfig, device_type type, const char *tag)
120 		: driver_device(mconfig, type, tag)
121 		, m_maincpu(*this, "maincpu")
122 		, m_soundcpu(*this, "soundcpu")
123 		, m_cart(*this, "cartslot")
124 		, m_vram(*this, "vram")
125 		, m_soundram(*this, "soundram")
126 		, m_gfxdecode(*this, "gfxdecode")
127 		, m_screen(*this, "screen")
128 		, m_pads(*this, "P%u", 1U)
129 	{
130 	}
131 
132 	void supracan(machine_config &config);
133 
134 private:
135 	virtual void machine_start() override;
136 	virtual void machine_reset() override;
137 	virtual void video_start() override;
138 
139 	void supracan_mem(address_map &map);
140 	void supracan_sound_mem(address_map &map);
141 
142 	uint16_t _68k_soundram_r(offs_t offset, uint16_t mem_mask = ~0);
143 	void _68k_soundram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
144 	uint8_t _6502_soundmem_r(offs_t offset);
145 	void _6502_soundmem_w(offs_t offset, uint8_t data);
146 
147 	void dma_w(int offset, uint16_t data, uint16_t mem_mask, int ch);
148 	void dma_channel0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
149 	void dma_channel1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
150 
151 	uint16_t sound_r(offs_t offset, uint16_t mem_mask = 0);
152 	void sound_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
153 	uint16_t video_r(offs_t offset, uint16_t mem_mask = 0);
154 	void video_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
155 	void vram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
156 
157 	struct dma_regs_t
158 	{
159 		uint32_t source[2];
160 		uint32_t dest[2];
161 		uint16_t count[2];
162 		uint16_t control[2];
163 	};
164 
165 	struct sprdma_regs_t
166 	{
167 		uint32_t src;
168 		uint16_t src_inc;
169 		uint32_t dst;
170 		uint16_t dst_inc;
171 		uint16_t count;
172 		uint16_t control;
173 	};
174 
175 	required_device<cpu_device> m_maincpu;
176 	required_device<cpu_device> m_soundcpu;
177 	required_device<generic_slot_device> m_cart;
178 
179 	required_shared_ptr<uint16_t> m_vram;
180 	required_shared_ptr<uint8_t> m_soundram;
181 
182 	required_device<gfxdecode_device> m_gfxdecode;
183 	required_device<screen_device> m_screen;
184 
185 	required_ioport_array<2> m_pads;
186 
187 	dma_regs_t m_dma_regs;
188 	sprdma_regs_t m_sprdma_regs;
189 
190 	uint16_t m_sound_cpu_ctrl;
191 	uint8_t m_soundcpu_irq_enable;
192 	uint8_t m_soundcpu_irq_source;
193 	uint8_t m_sound_cpu_shift_ctrl;
194 	uint8_t m_sound_cpu_shift_regs[2];
195 	uint16_t m_latched_controls[2];
196 	uint8_t m_sound_status;
197 	uint8_t m_sound_reg_addr;
198 	uint8_t m_sound_regs[0x100];
199 
200 	emu_timer *m_video_timer;
201 	emu_timer *m_hbl_timer;
202 	emu_timer *m_line_on_timer;
203 	emu_timer *m_line_off_timer;
204 
205 	std::vector<uint8_t> m_vram_addr_swapped;
206 
207 #if 0
208 	uint16_t *m_pram;
209 #endif
210 
211 	uint16_t m_sprite_count;
212 	uint32_t m_sprite_base_addr;
213 	uint8_t m_sprite_flags;
214 
215 	uint32_t m_tilemap_base_addr[3];
216 	int m_tilemap_scrollx[3];
217 	int m_tilemap_scrolly[3];
218 	uint16_t m_video_flags;
219 	uint16_t m_tilemap_flags[3];
220 	uint16_t m_tilemap_mode[3];
221 	uint16_t m_irq_mask;
222 #if 0
223 	uint16_t m_hbl_mask;
224 #endif
225 
226 	uint32_t m_roz_base_addr;
227 	uint16_t m_roz_mode;
228 	uint32_t m_roz_scrollx;
229 	uint32_t m_roz_scrolly;
230 	uint16_t m_roz_tile_bank;
231 	uint32_t m_roz_unk_base0;
232 	uint32_t m_roz_unk_base1;
233 	uint32_t m_roz_unk_base2;
234 	uint16_t m_roz_coeffa;
235 	uint16_t m_roz_coeffb;
236 	uint16_t m_roz_coeffc;
237 	uint16_t m_roz_coeffd;
238 	int32_t m_roz_changed;
239 	uint16_t m_unk_1d0;
240 
241 	uint16_t m_video_regs[256];
242 
243 	tilemap_t *m_tilemap_sizes[4][4];
244 	bitmap_ind16 m_sprite_final_bitmap;
245 	bitmap_ind8 m_sprite_mask_bitmap;
246 	bitmap_ind8 m_prio_bitmap;
247 
248 	void write_swapped_byte(int offset, uint8_t byte);
249 	TILE_GET_INFO_MEMBER(get_tilemap0_tile_info);
250 	TILE_GET_INFO_MEMBER(get_tilemap1_tile_info);
251 	TILE_GET_INFO_MEMBER(get_tilemap2_tile_info);
252 	TILE_GET_INFO_MEMBER(get_roz_tile_info);
253 	void palette_init(palette_device &palette) const;
254 	uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
255 	INTERRUPT_GEN_MEMBER(sound_irq);
256 	TIMER_CALLBACK_MEMBER(hbl_callback);
257 	TIMER_CALLBACK_MEMBER(line_on_callback);
258 	TIMER_CALLBACK_MEMBER(line_off_callback);
259 	TIMER_CALLBACK_MEMBER(video_callback);
260 	DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load);
261 	int get_tilemap_region(int layer);
262 	void get_tilemap_info_common(int layer, tile_data &tileinfo, int count);
263 	void get_roz_tilemap_info(int layer, tile_data &tileinfo, int count);
264 	int get_tilemap_dimensions(int &xsize, int &ysize, int layer);
265 	void draw_sprite_tile(bitmap_ind16 &dst, bitmap_ind8 &priomap, const rectangle &cliprect, gfx_element *gfx, int tile, int palette, bool xflip, bool yflip, int dstx, int dsty, int prio);
266 	void draw_sprite_tile_mask(bitmap_ind8 &dst, const rectangle &cliprect, gfx_element *gfx, int tile, bool xflip, bool yflip, int dstx, int dsty);
267 	void draw_sprite_tile_masked(bitmap_ind16 &dst, bitmap_ind8 &mask, bitmap_ind8 &priomap, const rectangle &cliprect, gfx_element *gfx, int tile, int palette, bool xflip, bool yflip, int dstx, int dsty, int prio);
268 	void draw_sprites(bitmap_ind16 &bitmap, bitmap_ind8 &maskmap, bitmap_ind8 &priomap, const rectangle &cliprect);
269 	void mark_active_tilemap_all_dirty(int layer);
270 	void draw_roz_layer(bitmap_ind16 &bitmap, const rectangle &cliprect, tilemap_t *tmap, uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, int wraparound/*, int columnscroll, uint32_t* scrollram*/, int transmask);
271 
272 	void set_sound_irq(uint8_t mask);
273 };
274 
275 
get_tilemap_region(int layer)276 int supracan_state::get_tilemap_region(int layer)
277 {
278 	// HACK!!!
279 	if (layer == 2)
280 	{
281 		return 2;
282 	}
283 
284 	if (layer == 3)
285 	{
286 		// roz layer
287 		static const int s_roz_mode_lut[4] = { 4, 2, 1, 0 };
288 		return s_roz_mode_lut[m_roz_mode & 3];
289 	}
290 	else
291 	{
292 		// normal layers
293 		if ((m_tilemap_mode[layer] & 0x7000) == 0x7000)
294 		{
295 			return 2;
296 		}
297 		return 1;
298 	}
299 
300 }
301 
get_tilemap_info_common(int layer,tile_data & tileinfo,int count)302 void supracan_state::get_tilemap_info_common(int layer, tile_data &tileinfo, int count)
303 {
304 	uint16_t* supracan_vram = m_vram;
305 
306 	uint32_t base = m_tilemap_base_addr[layer];
307 	int gfx_mode = (m_tilemap_mode[layer] & 0x7000) >> 12;
308 	int region = get_tilemap_region(layer);
309 
310 	count += base;
311 
312 	uint16_t tile_bank = 0;
313 	uint16_t palette_bank = 0;
314 	switch (gfx_mode)
315 	{
316 	case 7:
317 		tile_bank = 0x1c00;
318 		palette_bank = 0x00;
319 		break;
320 
321 	case 6: // gambling lord
322 		tile_bank = 0x0c00;
323 		palette_bank = 0x00;
324 		break;
325 
326 	case 4:
327 		tile_bank = 0x800;
328 		palette_bank = 0x00;
329 		break;
330 
331 	case 2:
332 		tile_bank = 0x400;
333 		palette_bank = 0x00;
334 		break;
335 
336 	case 0:
337 		tile_bank = 0;
338 		palette_bank = 0x00;
339 		break;
340 
341 	default:
342 		LOGMASKED(LOG_UNKNOWNS, "Unsupported tilemap mode: %d\n", (m_tilemap_mode[layer] & 0x7000) >> 12);
343 		break;
344 	}
345 
346 
347 	if (layer == 2)
348 	{
349 		tile_bank = 0x1000;
350 	}
351 
352 	int tile = (supracan_vram[count] & 0x03ff) + tile_bank;
353 	int flipxy = (supracan_vram[count] & 0x0c00) >> 10;
354 	int palette = ((supracan_vram[count] & 0xf000) >> 12) + palette_bank;
355 
356 	tileinfo.set(region, tile, palette, TILE_FLIPXY(flipxy));
357 }
358 
359 // I wonder how different this really is.. my guess, not at all.
get_roz_tilemap_info(int layer,tile_data & tileinfo,int count)360 void supracan_state::get_roz_tilemap_info(int layer, tile_data &tileinfo, int count)
361 {
362 	uint16_t* supracan_vram = m_vram;
363 
364 	uint32_t base = m_roz_base_addr;
365 
366 	int region = 1;
367 	uint16_t tile_bank = 0;
368 	uint16_t palette_bank = 0;
369 
370 	region = get_tilemap_region(layer);
371 
372 	switch (m_roz_mode & 3) // FIXME: fix gfx bpp order
373 	{
374 	case 0:
375 	{
376 		// HACK: case for startup logo
377 		// This isn't understood properly, it's rendering a single 64x64 tile, which for convenience we've rearranged and decoded as 8x8 for the tilemaps
378 		int tile = 0x880 + ((count & 7) * 2);
379 		// tile += (count & 0x070) >> 2;
380 
381 		if (count & 0x20) tile ^= 1;
382 		tile |= (count & 0xc0) >> 2;
383 
384 		tileinfo.set(region, tile, 0, 0);
385 		return;
386 	}
387 
388 	case 1:
389 		tile_bank = (m_roz_tile_bank & 0xf000) >> 3;
390 		break;
391 
392 	case 2:
393 		tile_bank = (m_roz_tile_bank & 0xf000) >> 3;
394 		break;
395 
396 	case 3:
397 		tile_bank = (m_roz_tile_bank & 0xf000) >> 3;
398 		break;
399 	}
400 
401 	count += base;
402 
403 	int tile = (supracan_vram[count] & 0x03ff) + tile_bank;
404 	int flipxy = (supracan_vram[count] & 0x0c00) >> 10;
405 	int palette = ((supracan_vram[count] & 0xf000) >> 12) + palette_bank;
406 
407 	tileinfo.set(region, tile, palette, TILE_FLIPXY(flipxy));
408 }
409 
410 
411 
TILE_GET_INFO_MEMBER(supracan_state::get_tilemap0_tile_info)412 TILE_GET_INFO_MEMBER(supracan_state::get_tilemap0_tile_info)
413 {
414 	get_tilemap_info_common(0, tileinfo, tile_index);
415 }
416 
TILE_GET_INFO_MEMBER(supracan_state::get_tilemap1_tile_info)417 TILE_GET_INFO_MEMBER(supracan_state::get_tilemap1_tile_info)
418 {
419 	get_tilemap_info_common(1, tileinfo, tile_index);
420 }
421 
TILE_GET_INFO_MEMBER(supracan_state::get_tilemap2_tile_info)422 TILE_GET_INFO_MEMBER(supracan_state::get_tilemap2_tile_info)
423 {
424 	get_tilemap_info_common(2, tileinfo, tile_index);
425 }
426 
TILE_GET_INFO_MEMBER(supracan_state::get_roz_tile_info)427 TILE_GET_INFO_MEMBER(supracan_state::get_roz_tile_info)
428 {
429 	get_roz_tilemap_info(3, tileinfo, tile_index);
430 }
431 
432 
video_start()433 void supracan_state::video_start()
434 {
435 	m_sprite_final_bitmap.allocate(1024, 1024, BITMAP_FORMAT_IND16);
436 	m_sprite_mask_bitmap.allocate(1024, 1024, BITMAP_FORMAT_IND8);
437 	m_prio_bitmap.allocate(1024, 1024, BITMAP_FORMAT_IND8);
438 
439 	m_vram_addr_swapped.resize(0x20000); // hack for 1bpp layer at startup
440 	m_gfxdecode->gfx(4)->set_source(&m_vram_addr_swapped[0]);
441 	m_gfxdecode->gfx(4)->set_xormask(0);
442 
443 	m_tilemap_sizes[0][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap0_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
444 	m_tilemap_sizes[0][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap0_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
445 	m_tilemap_sizes[0][2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap0_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
446 	m_tilemap_sizes[0][3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap0_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
447 
448 	m_tilemap_sizes[1][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap1_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
449 	m_tilemap_sizes[1][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap1_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
450 	m_tilemap_sizes[1][2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap1_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
451 	m_tilemap_sizes[1][3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap1_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
452 
453 	m_tilemap_sizes[2][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap2_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
454 	m_tilemap_sizes[2][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap2_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
455 	m_tilemap_sizes[2][2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap2_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
456 	m_tilemap_sizes[2][3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_tilemap2_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
457 
458 	m_tilemap_sizes[3][0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_roz_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
459 	m_tilemap_sizes[3][1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_roz_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
460 	m_tilemap_sizes[3][2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_roz_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 32);
461 	m_tilemap_sizes[3][3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(supracan_state::get_roz_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
462 }
463 
get_tilemap_dimensions(int & xsize,int & ysize,int layer)464 int supracan_state::get_tilemap_dimensions(int &xsize, int &ysize, int layer)
465 {
466 	xsize = 32;
467 	ysize = 32;
468 
469 	int select;
470 	if (layer == 3)
471 		select = m_roz_mode & 0x0f00;
472 	else
473 		select = m_tilemap_flags[layer] & 0x0f00;
474 
475 	switch (select)
476 	{
477 	case 0x600:
478 		xsize = 64;
479 		ysize = 32;
480 		return 1;
481 
482 	case 0xa00:
483 		xsize = 128;
484 		ysize = 32;
485 		return 2;
486 
487 	case 0xc00:
488 		xsize = 64;
489 		ysize = 64;
490 		return 3;
491 
492 	default:
493 		LOGMASKED(LOG_HFUNKNOWNS, "Unsupported tilemap size for layer %d: %04x\n", layer, select);
494 		return 0;
495 	}
496 }
497 
draw_sprite_tile(bitmap_ind16 & dst,bitmap_ind8 & priomap,const rectangle & cliprect,gfx_element * gfx,int tile,int palette,bool xflip,bool yflip,int dstx,int dsty,int prio)498 void supracan_state::draw_sprite_tile(bitmap_ind16 &dst, bitmap_ind8 &priomap, const rectangle &cliprect, gfx_element *gfx, int tile, int palette,
499 	bool xflip, bool yflip, int dstx, int dsty, int prio)
500 {
501 	// compute final pixel in X and exit if we are entirely clipped
502 	int dstendx = dstx + 7;
503 	if (dstx > cliprect.right() || dstendx < cliprect.left())
504 		return;
505 
506 	// apply left clip
507 	int srcx = 0;
508 	if (dstx < cliprect.left())
509 	{
510 		srcx = cliprect.left() - dstx;
511 		dstx = cliprect.left();
512 	}
513 
514 	// apply right clip
515 	if (dstendx > cliprect.right())
516 		dstendx = cliprect.right();
517 
518 	// compute final pixel in Y and exit if we are entirely clipped
519 	int dstendy = dsty + 7;
520 	if (dsty > cliprect.bottom() || dstendy < cliprect.top())
521 		return;
522 
523 	// apply top clip
524 	int srcy = 0;
525 	if (dsty < cliprect.top())
526 	{
527 		srcy = cliprect.top() - dsty;
528 		dsty = cliprect.top();
529 	}
530 
531 	// apply bottom clip
532 	if (dstendy > cliprect.bottom())
533 		dstendy = cliprect.bottom();
534 
535 	// apply X flipping
536 	int dx = 1;
537 	if (xflip)
538 	{
539 		srcx = 7 - srcx;
540 		dx = -dx;
541 	}
542 
543 	// apply Y flipping
544 	int dy = gfx->rowbytes();
545 	if (yflip)
546 	{
547 		srcy = 7 - srcy;
548 		dy = -dy;
549 	}
550 
551 	const int color = gfx->colorbase() + gfx->granularity() * (palette % gfx->colors());
552 	const uint8_t *src_data = &gfx->get_data(tile % gfx->elements())[srcy * gfx->rowbytes()];
553 	for (int y = dsty; y <= dstendy; y++)
554 	{
555 		const uint8_t *srcp = &src_data[srcx];
556 		uint8_t *priop = &priomap.pix(y, dstx);
557 		uint16_t *dstp = &dst.pix(y, dstx);
558 		for (int x = dstx; x <= dstendx; x++)
559 		{
560 			const uint32_t srcdata = *srcp;
561 			if (srcdata != 0)
562 			{
563 				*dstp = (uint16_t)(srcdata + color);
564 				*priop = (*priop & 0xf0) | (uint8_t)prio;
565 			}
566 			srcp += dx;
567 			priop++;
568 			dstp++;
569 		}
570 		src_data += dy;
571 	}
572 }
573 
draw_sprite_tile_mask(bitmap_ind8 & dst,const rectangle & cliprect,gfx_element * gfx,int tile,bool xflip,bool yflip,int dstx,int dsty)574 void supracan_state::draw_sprite_tile_mask(bitmap_ind8 &dst, const rectangle &cliprect, gfx_element *gfx, int tile, bool xflip, bool yflip, int dstx, int dsty)
575 {
576 	// compute final pixel in X and exit if we are entirely clipped
577 	int dstendx = dstx + 7;
578 	if (dstx > cliprect.right() || dstendx < cliprect.left())
579 		return;
580 
581 	// apply left clip
582 	int srcx = 0;
583 	if (dstx < cliprect.left())
584 	{
585 		srcx = cliprect.left() - dstx;
586 		dstx = cliprect.left();
587 	}
588 
589 	// apply right clip
590 	if (dstendx > cliprect.right())
591 		dstendx = cliprect.right();
592 
593 	// compute final pixel in Y and exit if we are entirely clipped
594 	int dstendy = dsty + 7;
595 	if (dsty > cliprect.bottom() || dstendy < cliprect.top())
596 		return;
597 
598 	// apply top clip
599 	int srcy = 0;
600 	if (dsty < cliprect.top())
601 	{
602 		srcy = cliprect.top() - dsty;
603 		dsty = cliprect.top();
604 	}
605 
606 	// apply bottom clip
607 	if (dstendy > cliprect.bottom())
608 		dstendy = cliprect.bottom();
609 
610 	// apply X flipping
611 	int dx = 1;
612 	if (xflip)
613 	{
614 		srcx = 7 - srcx;
615 		dx = -dx;
616 	}
617 
618 	// apply Y flipping
619 	int dy = gfx->rowbytes();
620 	if (yflip)
621 	{
622 		srcy = 7 - srcy;
623 		dy = -dy;
624 	}
625 
626 	const uint8_t *src_data = &gfx->get_data(tile % gfx->elements())[srcy * gfx->rowbytes()];
627 	for (int y = dsty; y <= dstendy; y++)
628 	{
629 		const uint8_t *srcp = &src_data[srcx];
630 		uint8_t *dstp = &dst.pix(y, dstx);
631 		for (int x = dstx; x <= dstendx; x++)
632 		{
633 			if (*srcp)
634 				*dstp = 1;
635 			srcp += dx;
636 			dstp++;
637 		}
638 		src_data += dy;
639 	}
640 }
641 
draw_sprite_tile_masked(bitmap_ind16 & dst,bitmap_ind8 & mask,bitmap_ind8 & priomap,const rectangle & cliprect,gfx_element * gfx,int tile,int palette,bool xflip,bool yflip,int dstx,int dsty,int prio)642 void supracan_state::draw_sprite_tile_masked(bitmap_ind16 &dst, bitmap_ind8 &mask, bitmap_ind8 &priomap, const rectangle &cliprect, gfx_element *gfx, int tile,
643 	int palette, bool xflip, bool yflip, int dstx, int dsty, int prio)
644 {
645 	// compute final pixel in X and exit if we are entirely clipped
646 	int dstendx = dstx + 7;
647 	if (dstx > cliprect.right() || dstendx < cliprect.left())
648 		return;
649 
650 	// apply left clip
651 	int srcx = 0;
652 	if (dstx < cliprect.left())
653 	{
654 		srcx = cliprect.left() - dstx;
655 		dstx = cliprect.left();
656 	}
657 
658 	// apply right clip
659 	if (dstendx > cliprect.right())
660 		dstendx = cliprect.right();
661 
662 	// compute final pixel in Y and exit if we are entirely clipped
663 	int dstendy = dsty + 7;
664 	if (dsty > cliprect.bottom() || dstendy < cliprect.top())
665 		return;
666 
667 	// apply top clip
668 	int srcy = 0;
669 	if (dsty < cliprect.top())
670 	{
671 		srcy = cliprect.top() - dsty;
672 		dsty = cliprect.top();
673 	}
674 
675 	// apply bottom clip
676 	if (dstendy > cliprect.bottom())
677 		dstendy = cliprect.bottom();
678 
679 	// apply X flipping
680 	int dx = 1;
681 	if (xflip)
682 	{
683 		srcx = 7 - srcx;
684 		dx = -dx;
685 	}
686 
687 	// apply Y flipping
688 	int dy = gfx->rowbytes();
689 	if (yflip)
690 	{
691 		srcy = 7 - srcy;
692 		dy = -dy;
693 	}
694 
695 	const int color = gfx->colorbase() + gfx->granularity() * (palette % gfx->colors());
696 	const uint8_t *src_data = &gfx->get_data(tile % gfx->elements())[srcy * gfx->rowbytes()];
697 	for (int y = dsty; y <= dstendy; y++)
698 	{
699 		const uint8_t *srcp = &src_data[srcx];
700 		uint16_t *dstp = &dst.pix(y, dstx);
701 		uint8_t *priop = &priomap.pix(y, dstx);
702 		uint8_t *maskp = &mask.pix(y, dstx);
703 		for (int x = dstx; x <= dstendx; x++)
704 		{
705 			const uint32_t srcdata = *srcp;
706 			if (srcdata != 0 && *maskp != 0)
707 			{
708 				*dstp = (uint16_t)(srcdata + color);
709 				*priop = (*priop & 0xf0) | (uint8_t)prio;
710 			}
711 			srcp += dx;
712 			dstp++;
713 			priop++;
714 			maskp++;
715 		}
716 		src_data += dy;
717 	}
718 }
719 
draw_sprites(bitmap_ind16 & bitmap,bitmap_ind8 & maskmap,bitmap_ind8 & priomap,const rectangle & cliprect)720 void supracan_state::draw_sprites(bitmap_ind16 &bitmap, bitmap_ind8 &maskmap, bitmap_ind8 &priomap, const rectangle &cliprect)
721 {
722 	uint16_t *supracan_vram = m_vram;
723 
724 //      [0]
725 //      -e-- ---- ---- ---- sprite enable?
726 //      ---h hhh- ---- ---- Y size (not always right)
727 //      ---- ---y yyyy yyyy Y position
728 //      [1]
729 //      bbbb ---- ---- ---- Tile bank
730 //      ---- h--- ---- ---- Horizontal flip
731 //      ---- -v-- ---- ---- Vertical flip
732 //      ---- --mm ---- ---- Masking mode
733 //      ---- ---- ---- -www X size
734 //      [2]
735 //      zzz- ---- ---- ---- X scale
736 //      ---- ???- ---- ---- Unknown, but often written.
737 //                          Values include 111 and 110 for the Super A'Can logo, 110 in the Sango Fighter intro, and 101/100 in the Boom Zoo intro.
738 //      ---- ---x xxxx xxxx X position
739 //      [3]
740 //      d--- ---- ---- ---- Direct Sprite (use details from here, not looked up in vram)
741 //      -ooo oooo oooo oooo Sprite address
742 
743 	uint32_t skip_count = 0;
744 	uint32_t start_word = (m_sprite_base_addr >> 1) + skip_count * 4;
745 	uint32_t end_word = start_word + (m_sprite_count - skip_count) * 4;
746 	int region = (m_sprite_flags & 1) ? 0 : 1; // 8bpp : 4bpp
747 
748 	static const uint16_t VRAM_MASK = 0xffff;
749 
750 	for (int i = start_word; i < end_word; i += 4)
751 	{
752 		int x = supracan_vram[i + 2] & 0x01ff;
753 		int y = supracan_vram[i + 0] & 0x01ff;
754 
755 		int sprite_offset = (supracan_vram[i + 3])<< 1;
756 
757 		int bank = (supracan_vram[i + 1] & 0xf000) >> 12;
758 		int mask = (supracan_vram[i + 1] & 0x0300) >> 8;
759 		int sprite_xflip = (supracan_vram[i + 1] & 0x0800) >> 11;
760 		int sprite_yflip = (supracan_vram[i + 1] & 0x0400) >> 10;
761 		int prio = (supracan_vram[i + 2] >> 9) & 3;
762 		//int xscale = supracan_vram[i + 2] >> 13;
763 		gfx_element *gfx = m_gfxdecode->gfx(region);
764 
765 		// wraparound
766 		if (y >= 0x180) y -= 0x200;
767 		if (x >= 0x180) x -= 0x200;
768 
769 		if ((supracan_vram[i + 0] & 0x4000))
770 		{
771 		#if 0
772 			printf("%d (unk %02x) (enable %02x) (unk Y2 %02x, %02x) (y pos %02x) (bank %01x) (flip %01x) (unknown %02x) (x size %02x) (xscale %01x) (unk %01x) (xpos %02x) (code %04x)\n", i,
773 				(supracan_vram[i + 0] & 0x8000) >> 15,
774 				(supracan_vram[i + 0] & 0x4000) >> 14,
775 				(supracan_vram[i + 0] & 0x2000) >> 13,
776 				(supracan_vram[i + 0] & 0x1e00) >> 8,
777 				(supracan_vram[i + 0] & 0x01ff),
778 				(supracan_vram[i + 1] & 0xf000) >> 12,
779 				(supracan_vram[i + 1] & 0x0c00) >> 10,
780 				(supracan_vram[i + 1] & 0x03f0) >> 4,
781 				(supracan_vram[i + 1] & 0x000f),
782 				(supracan_vram[i + 2] & 0xf000) >> 12,
783 				(supracan_vram[i + 2] & 0x0e00) >> 8,
784 				(supracan_vram[i + 2] & 0x01ff) >> 0,
785 				(supracan_vram[i + 3] & 0xffff));
786 		#endif
787 
788 			if (supracan_vram[i + 3] & 0x8000)
789 			{
790 				uint16_t data = supracan_vram[i + 3];
791 				int tile = (bank * 0x200) + (data & 0x03ff);
792 
793 				int palette = (data & 0xf000) >> 12; // this might not be correct, due to the & 0x8000 condition above this would force all single tile sprites to be using palette >= 0x8 only
794 
795 				// printf("sprite data %04x %04x %04x %04x\n", supracan_vram[i+0] , supracan_vram[i+1] , supracan_vram[i+2] ,supracan_vram[i+3]  );
796 
797 				if (mask > 1)
798 					draw_sprite_tile_mask(maskmap, cliprect, gfx, tile, sprite_xflip, sprite_yflip, x, y);
799 				else if (mask == 1)
800 					draw_sprite_tile_masked(bitmap, maskmap, priomap, cliprect, gfx, tile, palette, sprite_xflip, sprite_yflip, x, y, prio);
801 				else
802 					draw_sprite_tile(bitmap, priomap, cliprect, gfx, tile, palette, sprite_xflip, sprite_yflip, x, y, prio);
803 			}
804 			else
805 			{
806 				int xsize = 1 << (supracan_vram[i + 1] & 7);
807 				int ysize = ((supracan_vram[i + 0] & 0x1e00) >> 9) + 1;
808 
809 				// I think the xsize must influence the ysize somehow, there are too many conflicting cases otherwise
810 				// there don't appear to be any special markers in the actual looked up tile data to indicate skip / end of list
811 
812 				for (int ytile = 0; ytile < ysize; ytile++)
813 				{
814 					for (int xtile = 0; xtile < xsize; xtile++)
815 					{
816 						uint16_t data = supracan_vram[(sprite_offset + ytile * xsize + xtile) & VRAM_MASK];
817 						int tile = (bank * 0x200) + (data & 0x03ff);
818 						int palette = (data & 0xf000) >> 12;
819 
820 						int xpos = sprite_xflip ? (x - (xtile + 1) * 8 + xsize * 8) : (x + xtile * 8);
821 						int ypos = sprite_yflip ? (y - (ytile + 1) * 8 + ysize * 8) : (y + ytile * 8);
822 
823 						int tile_xflip = sprite_xflip ^ ((data & 0x0800) >> 11);
824 						int tile_yflip = sprite_yflip ^ ((data & 0x0400) >> 10);
825 
826 						if (mask > 1)
827 							draw_sprite_tile_mask(maskmap, cliprect, gfx, tile, tile_xflip, tile_yflip, xpos, ypos);
828 						else if (mask == 1)
829 							draw_sprite_tile_masked(bitmap, maskmap, priomap, cliprect, gfx, tile, palette, tile_xflip, tile_yflip, xpos, ypos, prio);
830 						else
831 							draw_sprite_tile(bitmap, priomap, cliprect, gfx, tile, palette, tile_xflip, tile_yflip, xpos, ypos, prio);
832 					}
833 				}
834 			}
835 
836 #if 0
837 			if (xscale == 0) continue;
838 			uint32_t delta = (1 << 17) / xscale;
839 			for (int sy = 0; sy < ysize * 8; sy++)
840 			{
841 				uint16_t *src = &sprite_bitmap->pix(sy);
842 				uint16_t *dst = &bitmap.pix(y + sy);
843 				uint32_t dx = x << 16;
844 				for (int sx = 0; sx < xsize * 8; sx++)
845 				{
846 					dst[dx >> 16] = src[sx];
847 					dx += delta;
848 				}
849 			}
850 #endif
851 
852 		}
853 	}
854 }
855 
856 
857 
mark_active_tilemap_all_dirty(int layer)858 void supracan_state::mark_active_tilemap_all_dirty(int layer)
859 {
860 	int xsize = 0;
861 	int ysize = 0;
862 
863 	int which_tilemap_size = get_tilemap_dimensions(xsize, ysize, layer);
864 //  for (int i=0;i<4;i++)
865 //    tilemap_mark_all_tiles_dirty(m_tilemap_sizes[layer][i]);
866 	m_tilemap_sizes[layer][which_tilemap_size]->mark_all_dirty();
867 }
868 
869 
870 
871 /* draws tilemap with linescroll OR columnscroll to 16-bit indexed bitmap */
draw_roz_layer(bitmap_ind16 & bitmap,const rectangle & cliprect,tilemap_t * tmap,uint32_t startx,uint32_t starty,int incxx,int incxy,int incyx,int incyy,int wraparound,int transmask)872 void supracan_state::draw_roz_layer(bitmap_ind16 &bitmap, const rectangle &cliprect, tilemap_t *tmap, uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, int wraparound/*, int columnscroll, uint32_t* scrollram*/, int transmask)
873 {
874 	bitmap_ind16 &srcbitmap = tmap->pixmap();
875 	const int xmask = srcbitmap.width() - 1;
876 	const int ymask = srcbitmap.height() - 1;
877 	const int widthshifted = srcbitmap.width() << 16;
878 	const int heightshifted = srcbitmap.height() << 16;
879 
880 	/* pre-advance based on the cliprect */
881 	startx += cliprect.min_x * incxx + cliprect.min_y * incyx;
882 	starty += cliprect.min_x * incxy + cliprect.min_y * incyy;
883 
884 	/* extract start/end points */
885 	int sx = cliprect.min_x;
886 	int sy = cliprect.min_y;
887 	int ex = cliprect.max_x;
888 	int ey = cliprect.max_y;
889 
890 	{
891 		/* loop over rows */
892 		while (sy <= ey)
893 		{
894 			/* initialize X counters */
895 			int x = sx;
896 			uint32_t cx = startx;
897 			uint32_t cy = starty;
898 
899 			/* get dest and priority pointers */
900 			uint16_t *dest = &bitmap.pix(sy, sx);
901 
902 			/* loop over columns */
903 			while (x <= ex)
904 			{
905 				if ((wraparound) || (cx < widthshifted && cy < heightshifted)) // not sure how this will cope with no wraparound, but row/col scroll..
906 				{
907 					#if 0
908 					if (columnscroll)
909 					{
910 						int scroll = 0; // scrollram[(cx>>16)&0x3ff]);
911 
912 						uint16_t data = &srcbitmap.pix(((cy >> 16) - scroll) & ymask, (cx >> 16) & xmask)[0];
913 
914 						if ((data & transmask) != 0)
915 							dest[0] = data;
916 					}
917 					else
918 					#endif
919 					{
920 						int scroll = 0;//scrollram[(cy>>16)&0x3ff]);
921 						uint16_t data =  srcbitmap.pix((cy >> 16) & ymask, ((cx >> 16) - scroll) & xmask);
922 
923 						if ((data & transmask) != 0)
924 							*dest = data;
925 					}
926 				}
927 
928 				/* advance in X */
929 				cx += incxx;
930 				cy += incxy;
931 				x++;
932 				dest++;
933 			}
934 
935 			/* advance in Y */
936 			startx += incyx;
937 			starty += incyy;
938 			sy++;
939 		}
940 	}
941 }
942 
943 
944 // VIDEO FLAGS                  ROZ MODE            TILEMAP FLAGS
945 //
946 //  Bit                         Bit                 Bit
947 // 15-9: Unknown                15-13: Priority?    15-13: Priority?
948 //    8: X ht. (256/320)        12: Unknown         12: Unknown
949 //    7: Tilemap 0 enable       11-8: Dims          11-8: Dims
950 //    6: Tilemap 1 enable       7-6: Unknown        7-6: Unknown
951 //    5: Tilemap 2 enable?      5: Wrap             5: Wrap
952 //    3: Sprite enable          4-2: Unknown        4-2: Mosaic
953 //    2: ROZ enable             1-0: Bit Depth      1-0: Bit Depth
954 //  1-0: Unknown
955 
956 //                      Video Flags                 ROZ Mode                    Tilemap 0   Tilemap 1   Tilemap 2   VF Unk0
957 // A'Can logo:          120e: 0001 0010 0000 1110   4020: 0100 0000 0010 0000   4620        ----        ----        0x09
958 // Boomzoo Intro:       9a82: 1001 1010 1000 0010   0402: 0000 0100 0000 0010   6400        6400        4400        0x4d
959 // Boomzoo Title:       9acc: 1001 1010 1100 1100   0402: 0000 0100 0000 0010   6400        6400        4400        0x4d
960 // C.U.G. Intro:        11c8: 0001 0001 1100 1000   0402: 0000 0100 0000 0010   2400        4400        6400        0x08
961 // C.U.G. Title:        11cc: 0001 0001 1100 1100   0602: 0000 0110 0000 0010   2600        4600        ----        0x08
962 // Speedy Dragon Logo:  0388: 0000 0011 1000 1000   4020: 0100 0000 0010 0000   6c20        6c20        2600        0x01
963 // Speedy Dragon Title: 038c: 0000 0011 1000 1100   2603: 0010 0110 0000 0011   6c20        2c20        2600        0x01
964 // Sango Fighter Intro: 03c8: 0000 0011 1100 1000   ----: ---- ---- ---- ----   6c20        4620        ----        0x01
965 // Sango Fighter Game:  03ce: 0000 0011 1100 1110   0622: 0000 0110 0010 0010   2620        4620        ----        0x01
966 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)967 uint32_t supracan_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
968 {
969 	// treat the sprites as frame-buffered and only update the buffer when drawing scanline 0 - this might not be true!
970 
971 	if (0)
972 	{
973 		if (cliprect.min_y == 0x00)
974 		{
975 			const rectangle &visarea = screen.visible_area();
976 
977 			m_sprite_final_bitmap.fill(0x00, visarea);
978 			m_sprite_mask_bitmap.fill(0x00, cliprect);
979 			m_prio_bitmap.fill(0xff, cliprect);
980 			bitmap.fill(0x80, visarea);
981 
982 			draw_sprites(m_sprite_final_bitmap, m_sprite_mask_bitmap, m_prio_bitmap, visarea);
983 		}
984 	}
985 	else
986 	{
987 		m_sprite_final_bitmap.fill(0x00, cliprect);
988 		m_sprite_mask_bitmap.fill(0x00, cliprect);
989 		m_prio_bitmap.fill(0xff, cliprect);
990 		bitmap.fill(0x80, cliprect);
991 
992 		draw_sprites(m_sprite_final_bitmap, m_sprite_mask_bitmap, m_prio_bitmap, cliprect);
993 	}
994 
995 	// mix screen
996 	int xsize = 0, ysize = 0;
997 //  int tilemap_num;
998 	int priority = 0;
999 
1000 	for (int pri = 7; pri >= 0; pri--)
1001 	{
1002 		for (int layer = 3; layer >=0; layer--)
1003 		{
1004 		//  popmessage("%04x\n",m_video_flags);
1005 			int enabled = 0;
1006 
1007 			if (m_video_flags & 0x04)
1008 				if (layer==3) enabled = 1;
1009 
1010 			if (m_video_flags & 0x80)
1011 				if (layer==0) enabled = 1;
1012 
1013 			if (m_video_flags & 0x40)
1014 				if (layer==1) enabled = 1;
1015 
1016 			if (m_video_flags & 0x20)
1017 				if (layer==2) enabled = 1;
1018 
1019 
1020 			if (layer==3)
1021 				priority = ((m_roz_mode >> 13) & 7); // roz case
1022 			else
1023 				priority = ((m_tilemap_flags[layer] >> 13) & 7); // normal cases
1024 
1025 
1026 			if (priority == pri)
1027 			{
1028 //            tilemap_num = layer;
1029 				int which_tilemap_size = get_tilemap_dimensions(xsize, ysize, layer);
1030 				bitmap_ind16 &src_bitmap = m_tilemap_sizes[layer][which_tilemap_size]->pixmap();
1031 				int gfx_region = get_tilemap_region(layer);
1032 				int transmask = 0xff;
1033 
1034 				switch (gfx_region)
1035 				{
1036 					case 0: transmask = 0xff; break;
1037 					case 1: transmask = 0x0f; break;
1038 					case 2: transmask = 0x03; break;
1039 					case 3: transmask = 0x01; break;
1040 					case 4: transmask = 0x01; break;
1041 				}
1042 
1043 				if (enabled)
1044 				{
1045 					if (layer != 3) // standard layers, NOT roz
1046 					{
1047 						int wrap = (m_tilemap_flags[layer] & 0x20);
1048 
1049 						int scrollx = m_tilemap_scrollx[layer];
1050 						int scrolly = m_tilemap_scrolly[layer];
1051 
1052 						if (scrollx & 0x8000) scrollx -= 0x10000;
1053 						if (scrolly & 0x8000) scrolly -= 0x10000;
1054 
1055 						int mosaic_count = (m_tilemap_flags[layer] & 0x001c) >> 2;
1056 						int mosaic_mask = 0xffffffff << mosaic_count;
1057 
1058 						// yes, it will draw a single line if you specify a cliprect as such (partial updates...)
1059 
1060 						for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
1061 						{
1062 							// these will have to change to uint32_t* etc. once alpha blending is supported
1063 							uint16_t* screen = &bitmap.pix(y);
1064 
1065 							int actualy = y & mosaic_mask;
1066 							int realy = actualy + scrolly;
1067 
1068 							if (!wrap)
1069 								if (scrolly + y < 0 || scrolly + y > ((ysize * 8) - 1))
1070 									continue;
1071 
1072 							uint16_t* src = &src_bitmap.pix(realy & ((ysize * 8) - 1));
1073 							uint8_t* priop = &m_prio_bitmap.pix(y);
1074 
1075 							for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
1076 							{
1077 								int actualx = x & mosaic_mask;
1078 								int realx = actualx + scrollx;
1079 
1080 								if (!wrap)
1081 									if (scrollx + x < 0 || scrollx + x > ((xsize * 8) - 1))
1082 										continue;
1083 
1084 								uint16_t srcpix = src[realx & ((xsize * 8) - 1)];
1085 
1086 								if ((srcpix & transmask) != 0 && priority < (priop[x] >> 4))
1087 								{
1088 									screen[x] = srcpix;
1089 									priop[x] = (priop[x] & 0x0f) | (priority << 4);
1090 								}
1091 							}
1092 						}
1093 					}
1094 					else
1095 					{
1096 						int wrap = m_roz_mode & 0x20;
1097 
1098 						int incxx = m_roz_coeffa;
1099 						int incyy = m_roz_coeffd;
1100 
1101 						int incxy = m_roz_coeffc;
1102 						int incyx = m_roz_coeffb;
1103 
1104 						int scrollx = m_roz_scrollx;
1105 						int scrolly = m_roz_scrolly;
1106 
1107 						if (incyx & 0x8000) incyx -= 0x10000;
1108 						if (incxy & 0x8000) incxy -= 0x10000;
1109 
1110 						if (incyy & 0x8000) incyy -= 0x10000;
1111 						if (incxx & 0x8000) incxx -= 0x10000;
1112 
1113 						//popmessage("%04x %04x\n",m_video_flags, m_roz_mode);
1114 
1115 						// roz mode..
1116 						//4020 = enabled speedyd
1117 						//6c22 = enabled speedyd
1118 						//2c22 = enabled speedyd
1119 						//4622 = disabled jttlaugh
1120 						//2602 = disabled monopoly
1121 						//0402 = disabled (sango title)
1122 						// or is it always enabled, and only corrupt because we don't clear ram properly?
1123 						// (probably not this register?)
1124 
1125 						if (!(m_roz_mode & 0x0200) && (m_roz_mode & 0xf000)) // HACK - Not trusted: Acan Logo, Speedy Dragon Intro, Speed Dragon Bonus stage need it.  Monopoly and JTT *don't* causes graphical issues
1126 						{
1127 							// NOT accurate, causes issues when the attract mode loops and the logo is shown the 2nd time in some games - investigate
1128 							for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
1129 							{
1130 								rectangle clip(cliprect.min_x, cliprect.max_x, y, y);
1131 
1132 								scrollx = (m_roz_scrollx);
1133 								scrolly = (m_roz_scrolly);
1134 								incxx = (m_roz_coeffa);
1135 
1136 								incxx += m_vram[m_roz_unk_base0/2 + y];
1137 
1138 								scrollx += m_vram[m_roz_unk_base1/2 + y * 2] << 16;
1139 								scrollx += m_vram[m_roz_unk_base1/2 + y * 2 + 1];
1140 
1141 								scrolly += m_vram[m_roz_unk_base2/2 + y * 2] << 16;
1142 								scrolly += m_vram[m_roz_unk_base2/2 + y * 2 + 1];
1143 
1144 								if (incxx & 0x8000) incxx -= 0x10000;
1145 
1146 								if (m_vram[m_roz_unk_base0/2 + y]) // incxx = 0, no draw?
1147 									draw_roz_layer(bitmap, clip, m_tilemap_sizes[layer][which_tilemap_size], scrollx<<8, scrolly<<8, incxx<<8, incxy<<8, incyx<<8, incyy<<8, wrap, transmask);
1148 							}
1149 						}
1150 						else
1151 						{
1152 							draw_roz_layer(bitmap, cliprect, m_tilemap_sizes[layer][which_tilemap_size], scrollx<<8, scrolly<<8, incxx<<8, incxy<<8, incyx<<8, incyy<<8, wrap, transmask);
1153 						}
1154 					}
1155 				}
1156 			}
1157 		}
1158 	}
1159 
1160 
1161 	// combine sprites
1162 	if (m_video_flags & 0x08)
1163 	{
1164 		for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
1165 		{
1166 			uint16_t* dstp = &bitmap.pix(y);
1167 			uint8_t* priop = &m_prio_bitmap.pix(y);
1168 			uint16_t* spritep = &m_sprite_final_bitmap.pix(y);
1169 
1170 			for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
1171 			{
1172 				uint16_t sprite_pix = spritep[x];
1173 				uint8_t tile_prio = priop[x] >> 4;
1174 				uint8_t sprite_prio = priop[x] & 0x0f;
1175 				if (sprite_pix != 0 && sprite_prio <= tile_prio)
1176 				{
1177 					dstp[x] = sprite_pix;
1178 				}
1179 			}
1180 		}
1181 	}
1182 
1183 	return 0;
1184 }
1185 
1186 
dma_w(int offset,uint16_t data,uint16_t mem_mask,int ch)1187 void supracan_state::dma_w(int offset, uint16_t data, uint16_t mem_mask, int ch)
1188 {
1189 	address_space &mem = m_maincpu->space(AS_PROGRAM);
1190 
1191 	switch (offset)
1192 	{
1193 	case 0x00/2: // Source address MSW
1194 		LOGMASKED(LOG_DMA, "dma_w: source msw %d: %04x\n", ch, data);
1195 		m_dma_regs.source[ch] &= 0x0000ffff;
1196 		m_dma_regs.source[ch] |= data << 16;
1197 		break;
1198 	case 0x02/2: // Source address LSW
1199 		LOGMASKED(LOG_DMA, "dma_w: source lsw %d: %04x\n", ch, data);
1200 		m_dma_regs.source[ch] &= 0xffff0000;
1201 		m_dma_regs.source[ch] |= data;
1202 		break;
1203 	case 0x04/2: // Destination address MSW
1204 		LOGMASKED(LOG_DMA, "dma_w: dest msw %d: %04x\n", ch, data);
1205 		m_dma_regs.dest[ch] &= 0x0000ffff;
1206 		m_dma_regs.dest[ch] |= data << 16;
1207 		break;
1208 	case 0x06/2: // Destination address LSW
1209 		LOGMASKED(LOG_DMA, "dma_w: dest lsw %d: %04x\n", ch, data);
1210 		m_dma_regs.dest[ch] &= 0xffff0000;
1211 		m_dma_regs.dest[ch] |= data;
1212 		break;
1213 	case 0x08/2: // Byte count
1214 		LOGMASKED(LOG_DMA, "dma_w: count %d: %04x\n", ch, data);
1215 		m_dma_regs.count[ch] = data;
1216 		break;
1217 	case 0x0a/2: // Control
1218 		LOGMASKED(LOG_DMA, "dma_w: control %d: %04x\n", ch, data);
1219 		if (data & 0x8800)
1220 		{
1221 //            if (data & 0x2000)
1222 //            m_dma_regs.source-=2;
1223 			LOGMASKED(LOG_DMA, "dma_w: Kicking off a DMA from %08x to %08x, %d bytes (%04x)\n", m_dma_regs.source[ch], m_dma_regs.dest[ch], m_dma_regs.count[ch] + 1, data);
1224 
1225 			for (int i = 0; i <= m_dma_regs.count[ch]; i++)
1226 			{
1227 				if (data & 0x1000)
1228 				{
1229 					mem.write_word(m_dma_regs.dest[ch], mem.read_word(m_dma_regs.source[ch]));
1230 					m_dma_regs.dest[ch] += 2;
1231 					m_dma_regs.source[ch] += 2;
1232 					if (data & 0x0100)
1233 						if ((m_dma_regs.dest[ch] & 0xf) == 0)
1234 							m_dma_regs.dest[ch] -= 0x10;
1235 				}
1236 				else
1237 				{
1238 					mem.write_byte(m_dma_regs.dest[ch], mem.read_byte(m_dma_regs.source[ch]));
1239 					m_dma_regs.dest[ch]++;
1240 					m_dma_regs.source[ch]++;
1241 				}
1242 			}
1243 		}
1244 		else if (data != 0x0000) // fake DMA, used by C.U.G.
1245 		{
1246 			LOGMASKED(LOG_UNKNOWNS | LOG_DMA, "dma_w: Unknown DMA kickoff value of %04x (other regs %08x, %08x, %d)\n", data, m_dma_regs.source[ch], m_dma_regs.dest[ch], m_dma_regs.count[ch] + 1);
1247 			fatalerror("dma_w: Unknown DMA kickoff value of %04x (other regs %08x, %08x, %d)\n",data, m_dma_regs.source[ch], m_dma_regs.dest[ch], m_dma_regs.count[ch] + 1);
1248 		}
1249 		break;
1250 	default:
1251 		LOGMASKED(LOG_UNKNOWNS | LOG_DMA, "dma_w: Unknown register: %08x = %04x & %04x\n", 0xe90020 + (offset << 1), data, mem_mask);
1252 		break;
1253 	}
1254 }
1255 
dma_channel0_w(offs_t offset,uint16_t data,uint16_t mem_mask)1256 void supracan_state::dma_channel0_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1257 {
1258 	dma_w(offset, data, mem_mask, 0);
1259 }
1260 
dma_channel1_w(offs_t offset,uint16_t data,uint16_t mem_mask)1261 void supracan_state::dma_channel1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1262 {
1263 	dma_w(offset, data, mem_mask, 1);
1264 }
1265 
1266 
1267 #if 0
1268 void supracan_state::supracan_pram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1269 {
1270 	m_pram[offset] &= ~mem_mask;
1271 	m_pram[offset] |= data & mem_mask;
1272 }
1273 #endif
1274 
1275 // swap address around so that 64x64 tile can be decoded as 8x8 tiles..
write_swapped_byte(int offset,uint8_t byte)1276 void supracan_state::write_swapped_byte(int offset, uint8_t byte)
1277 {
1278 	int swapped_offset = bitswap<32>(offset, 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,2,1,0,6,5,4,3);
1279 
1280 	m_vram_addr_swapped[swapped_offset] = byte;
1281 }
1282 
vram_w(offs_t offset,uint16_t data,uint16_t mem_mask)1283 void supracan_state::vram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1284 {
1285 	COMBINE_DATA(&m_vram[offset]);
1286 
1287 	// hack for 1bpp layer at startup
1288 	write_swapped_byte(offset * 2, data >> 8);
1289 	write_swapped_byte(offset * 2 + 1, (data & 0x00ff));
1290 
1291 	// mark tiles of each depth as dirty
1292 	m_gfxdecode->gfx(0)->mark_dirty((offset * 2) / 64);
1293 	m_gfxdecode->gfx(1)->mark_dirty((offset * 2) / 32);
1294 	m_gfxdecode->gfx(2)->mark_dirty((offset * 2) / 16);
1295 	m_gfxdecode->gfx(3)->mark_dirty((offset * 2) / 512);
1296 	m_gfxdecode->gfx(4)->mark_dirty((offset * 2) / 8);
1297 
1298 }
1299 
supracan_mem(address_map & map)1300 void supracan_state::supracan_mem(address_map &map)
1301 {
1302 	// 0x000000..0x3fffff is mapped by the cartslot
1303 	map(0xe80000, 0xe8ffff).rw(FUNC(supracan_state::_68k_soundram_r), FUNC(supracan_state::_68k_soundram_w));
1304 	map(0xe90000, 0xe9001f).rw(FUNC(supracan_state::sound_r), FUNC(supracan_state::sound_w));
1305 	map(0xe90020, 0xe9002f).w(FUNC(supracan_state::dma_channel0_w));
1306 	map(0xe90030, 0xe9003f).w(FUNC(supracan_state::dma_channel1_w));
1307 
1308 	map(0xf00000, 0xf001ff).rw(FUNC(supracan_state::video_r), FUNC(supracan_state::video_w));
1309 	map(0xf00200, 0xf003ff).ram().w("palette", FUNC(palette_device::write16)).share("palette");
1310 	map(0xf40000, 0xf5ffff).ram().w(FUNC(supracan_state::vram_w)).share("vram");
1311 	map(0xfc0000, 0xfcffff).mirror(0x30000).ram(); /* System work ram */
1312 }
1313 
set_sound_irq(uint8_t mask)1314 void supracan_state::set_sound_irq(uint8_t mask)
1315 {
1316 	const uint8_t old = m_soundcpu_irq_source;
1317 	m_soundcpu_irq_source |= mask;
1318 	const uint8_t changed = old ^ m_soundcpu_irq_source;
1319 	if (changed)
1320 	{
1321 		m_soundcpu->set_input_line(0, (m_soundcpu_irq_enable & m_soundcpu_irq_source) ? ASSERT_LINE : CLEAR_LINE);
1322 	}
1323 }
1324 
_6502_soundmem_r(offs_t offset)1325 uint8_t supracan_state::_6502_soundmem_r(offs_t offset)
1326 {
1327 	uint8_t data = m_soundram[offset];
1328 
1329 	switch (offset)
1330 	{
1331 	case 0x300: // Boot OK status
1332 		break;
1333 	case 0x402:
1334 	case 0x403:
1335 	{
1336 		const uint8_t index = offset - 0x402;
1337 		data = m_sound_cpu_shift_regs[index];
1338 		if (!machine().side_effects_disabled())
1339 		{
1340 			LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_r: Shift register %d read: %02x\n", machine().describe_context(), index, data);
1341 		}
1342 		break;
1343 	}
1344 	case 0x410:
1345 		data = m_soundcpu_irq_enable;
1346 		if (!machine().side_effects_disabled())
1347 		{
1348 			LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_r: IRQ enable read: %02x\n", machine().describe_context(), data);
1349 		}
1350 		break;
1351 	case 0x411:
1352 		data = m_soundcpu_irq_source;
1353 		m_soundcpu_irq_source = 0;
1354 		if (!machine().side_effects_disabled())
1355 		{
1356 			LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_r: Sound IRQ source read + clear: %02x\n", machine().describe_context(), data);
1357 			m_soundcpu->set_input_line(0, CLEAR_LINE);
1358 		}
1359 		break;
1360 	case 0x420:
1361 		if (!machine().side_effects_disabled())
1362 		{
1363 			data = m_sound_status;
1364 			LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_r: Sound hardware status read:       0420 = %02x\n", machine().describe_context(), m_sound_status);
1365 		}
1366 		break;
1367 	case 0x422:
1368 		if (!machine().side_effects_disabled())
1369 		{
1370 			data = m_sound_regs[m_sound_reg_addr];
1371 			LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_r: Sound hardware reg data read:     0422 = %02x\n", machine().describe_context(), data);
1372 		}
1373 		break;
1374 	case 0x404:
1375 	case 0x405:
1376 	case 0x409:
1377 	case 0x414:
1378 	case 0x416:
1379 		// Intentional fall-through
1380 	default:
1381 		if (offset >= 0x300 && offset < 0x500)
1382 		{
1383 			if (!machine().side_effects_disabled())
1384 			{
1385 				LOGMASKED(LOG_SOUND | LOG_UNKNOWNS, "%s: 6502_soundmem_r: Unknown register %04x (%02x)\n", machine().describe_context(), offset, data);
1386 			}
1387 		}
1388 		break;
1389 	}
1390 
1391 	return data;
1392 }
1393 
_6502_soundmem_w(offs_t offset,uint8_t data)1394 void supracan_state::_6502_soundmem_w(offs_t offset, uint8_t data)
1395 {
1396 	switch (offset)
1397 	{
1398 	case 0x407:
1399 	{
1400 		LOGMASKED(LOG_CONTROLS, "%s: 6502_soundmem_w: Shift register control: %02x\n", machine().describe_context(), data);
1401 		const uint8_t old = m_sound_cpu_shift_ctrl;
1402 		m_sound_cpu_shift_ctrl = data;
1403 		const uint8_t lowered = old & ~m_sound_cpu_shift_ctrl;
1404 		for (uint8_t pad = 0; pad < 2; pad++)
1405 		{
1406 			if (BIT(lowered, pad + 0))
1407 			{
1408 				m_latched_controls[pad] = m_pads[pad]->read();
1409 			}
1410 			if (BIT(lowered, pad + 2))
1411 			{
1412 				m_sound_cpu_shift_regs[pad] <<= 1;
1413 				m_sound_cpu_shift_regs[pad] |= BIT(m_latched_controls[pad], 15);
1414 				m_latched_controls[pad] <<= 1;
1415 			}
1416 			if (BIT(lowered, pad + 4))
1417 			{
1418 				m_sound_cpu_shift_regs[pad] = 0;
1419 			}
1420 		}
1421 		break;
1422 	}
1423 	case 0x410:
1424 		m_soundcpu_irq_enable = data;
1425 		LOGMASKED(LOG_SOUND | LOG_IRQS, "%s: 6502_soundmem_w: IRQ enable: %02x\n", machine().describe_context(), data);
1426 		break;
1427 	case 0x420:
1428 		LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_w: Sound hardware reg addr write:    0420 = %02x\n", machine().describe_context(), data);
1429 		m_sound_reg_addr = data;
1430 		break;
1431 	case 0x422:
1432 		LOGMASKED(LOG_SOUND, "%s: 6502_soundmem_w: Sound hardware reg data write:    0422 = %02x\n", machine().describe_context(), data);
1433 		m_sound_regs[m_sound_reg_addr] = data;
1434 		break;
1435 	default:
1436 		if (offset >= 0x300 && offset < 0x500)
1437 		{
1438 			LOGMASKED(LOG_SOUND | LOG_UNKNOWNS, "%s: 6502_soundmem_w: Unknown register %04x = %02x\n", machine().describe_context(), offset, data);
1439 		}
1440 		m_soundram[offset] = data;
1441 		break;
1442 	}
1443 }
1444 
supracan_sound_mem(address_map & map)1445 void supracan_state::supracan_sound_mem(address_map &map)
1446 {
1447 	map(0x0000, 0xffff).rw(FUNC(supracan_state::_6502_soundmem_r), FUNC(supracan_state::_6502_soundmem_w)).share("soundram");
1448 }
1449 
1450 static INPUT_PORTS_START( supracan )
1451 	PORT_START("P1")
1452 	PORT_BIT(0x000f, IP_ACTIVE_LOW, IPT_UNUSED)
1453 	PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_PLAYER(1) PORT_NAME("P1 Button R")
1454 	PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_PLAYER(1) PORT_NAME("P1 Button L")
1455 	PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_PLAYER(1) PORT_NAME("P1 Button Y")
1456 	PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_PLAYER(1) PORT_NAME("P1 Button X")
1457 	PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(1) PORT_NAME("P1 Joypad Right")
1458 	PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(1) PORT_NAME("P1 Joypad Left")
1459 	PORT_BIT(0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(1) PORT_NAME("P1 Joypad Down")
1460 	PORT_BIT(0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(1) PORT_NAME("P1 Joypad Up")
1461 	PORT_BIT(0x1000, IP_ACTIVE_LOW, IPT_UNUSED)
1462 	PORT_BIT(0x2000, IP_ACTIVE_LOW, IPT_START1)
1463 	PORT_BIT(0x4000, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_PLAYER(1) PORT_NAME("P1 Button B")
1464 	PORT_BIT(0x8000, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1) PORT_NAME("P1 Button A")
1465 
1466 	PORT_START("P2")
1467 	PORT_BIT(0x000f, IP_ACTIVE_LOW, IPT_UNUSED)
1468 	PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_PLAYER(2) PORT_NAME("P2 Button R")
1469 	PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_PLAYER(2) PORT_NAME("P2 Button L")
1470 	PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_PLAYER(2) PORT_NAME("P2 Button Y")
1471 	PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_PLAYER(2) PORT_NAME("P2 Button X")
1472 	PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) PORT_NAME("P2 Joypad Right")
1473 	PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) PORT_NAME("P2 Joypad Left")
1474 	PORT_BIT(0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) PORT_NAME("P2 Joypad Down")
1475 	PORT_BIT(0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(2) PORT_NAME("P2 Joypad Up")
1476 	PORT_BIT(0x1000, IP_ACTIVE_LOW, IPT_UNUSED)
1477 	PORT_BIT(0x2000, IP_ACTIVE_LOW, IPT_START2)
1478 	PORT_BIT(0x4000, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_PLAYER(2) PORT_NAME("P2 Button B")
1479 	PORT_BIT(0x8000, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) PORT_NAME("P2 Button A")
1480 INPUT_PORTS_END
1481 
palette_init(palette_device & palette) const1482 void supracan_state::palette_init(palette_device &palette) const
1483 {
1484 	// Used for debugging purposes for now
1485 	for (int i = 0; i < 32768; i++)
1486 	{
1487 		int const r = (i & 0x1f) << 3;
1488 		int const g = ((i >> 5) & 0x1f) << 3;
1489 		int const b = ((i >> 10) & 0x1f) << 3;
1490 		palette.set_pen_color(i, r, g, b);
1491 	}
1492 }
1493 
_68k_soundram_w(offs_t offset,uint16_t data,uint16_t mem_mask)1494 void supracan_state::_68k_soundram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1495 {
1496 	m_soundram[offset * 2 + 1] = data & 0xff;
1497 	m_soundram[offset * 2] = data >> 8;
1498 
1499 	if (offset * 2 < 0x500 && offset * 2 >= 0x300)
1500 	{
1501 		if (ACCESSING_BITS_8_15)
1502 		{
1503 			_6502_soundmem_w(offset * 2, data >> 8);
1504 		}
1505 		if (ACCESSING_BITS_0_7)
1506 		{
1507 			_6502_soundmem_w(offset * 2 + 1, data & 0xff);
1508 		}
1509 	}
1510 	LOGMASKED(LOG_68K_SOUND, "%s: 68k sound RAM write: %04x & %04x = %04x\n", machine().describe_context(), offset << 1, mem_mask, (uint16_t)data);
1511 }
1512 
_68k_soundram_r(offs_t offset,uint16_t mem_mask)1513 uint16_t supracan_state::_68k_soundram_r(offs_t offset, uint16_t mem_mask)
1514 {
1515 	uint16_t data = m_soundram[offset * 2] << 8;
1516 	data |= m_soundram[offset * 2 + 1];
1517 
1518 	if (offset * 2 >= 0x300 && offset * 2 < 0x500)
1519 	{
1520 		data = 0;
1521 		if (ACCESSING_BITS_8_15)
1522 		{
1523 			data |= _6502_soundmem_r(offset * 2) << 8;
1524 		}
1525 		if (ACCESSING_BITS_0_7)
1526 		{
1527 			data |= _6502_soundmem_r(offset * 2 + 1);
1528 		}
1529 	}
1530 	//LOGMASKED(LOG_68K_SOUND, "%s: 68k sound RAM read: %04x & %04x (%04x)\n", machine().describe_context(), offset << 1, mem_mask, data);
1531 
1532 	return data;
1533 }
1534 
sound_r(offs_t offset,uint16_t mem_mask)1535 uint16_t supracan_state::sound_r(offs_t offset, uint16_t mem_mask)
1536 {
1537 	uint16_t data = 0;
1538 
1539 	switch (offset)
1540 	{
1541 	default:
1542 		LOGMASKED(LOG_SOUND | LOG_UNKNOWNS, "sound_r: Unknown register: (%08x) & %04x\n", 0xe90000 + (offset << 1), mem_mask);
1543 		break;
1544 	}
1545 
1546 	return data;
1547 }
1548 
sound_w(offs_t offset,uint16_t data,uint16_t mem_mask)1549 void supracan_state::sound_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1550 {
1551 	switch (offset)
1552 	{
1553 	case 0x000a/2:  /* Sound cpu IRQ request. */
1554 		LOGMASKED(LOG_SOUND, "%s: Sound CPU IRQ request: %04x\n", machine().describe_context(), data);
1555 		set_sound_irq(0x20);
1556 		//m_soundcpu->set_input_line(0, ASSERT_LINE);
1557 		break;
1558 	case 0x001c/2:  /* Sound cpu control. Bit 0 tied to sound cpu RESET line */
1559 	{
1560 		const uint16_t old = m_sound_cpu_ctrl;
1561 		m_sound_cpu_ctrl = data;
1562 		const uint16_t changed = old ^ m_sound_cpu_ctrl;
1563 		if (BIT(changed, 0))
1564 		{
1565 			if (BIT(m_sound_cpu_ctrl, 0))
1566 			{
1567 				/* Reset and enable the sound cpu */
1568 				m_soundcpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
1569 				m_soundcpu->reset();
1570 			}
1571 			else
1572 			{
1573 				/* Halt the sound cpu */
1574 				m_soundcpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
1575 			}
1576 		}
1577 		LOGMASKED(LOG_SOUND, "%s: Sound CPU ctrl write: %04x\n", machine().describe_context(), data);
1578 		break;
1579 	}
1580 	default:
1581 		LOGMASKED(LOG_SOUND | LOG_UNKNOWNS, "%s: sound_w: Unknown register: %08x = %04x & %04x\n", machine().describe_context(), 0xe90000 + (offset << 1), data, mem_mask);
1582 		break;
1583 	}
1584 }
1585 
1586 
video_r(offs_t offset,uint16_t mem_mask)1587 uint16_t supracan_state::video_r(offs_t offset, uint16_t mem_mask)
1588 {
1589 	uint16_t data = m_video_regs[offset];
1590 
1591 	switch (offset)
1592 	{
1593 	case 0x00/2: // Video IRQ flags
1594 		if (!machine().side_effects_disabled())
1595 		{
1596 			LOGMASKED(LOG_HFVIDEO, "read video IRQ flags (%04x)\n", data);
1597 			m_maincpu->set_input_line(7, CLEAR_LINE);
1598 		}
1599 		break;
1600 	case 0x02/2: // Current scanline
1601 		LOGMASKED(LOG_VIDEO, "read current scanline (%04x)\n", data);
1602 		break;
1603 	case 0x08/2: // Unknown (not video flags!) - gambling lord disagrees, it MUST read back what it wrote because it reads it before turning on/off layers and writes it back
1604 		LOGMASKED(LOG_VIDEO, "read unkown 0x08 (%04x)\n", data);
1605 		break;
1606 	case 0x100/2:
1607 		if (!machine().side_effects_disabled())
1608 		{
1609 			LOGMASKED(LOG_TILEMAP0, "read tilemap_flags[0] (%04x)\n", data);
1610 		}
1611 		break;
1612 	case 0x106/2:
1613 		if (!machine().side_effects_disabled())
1614 		{
1615 			LOGMASKED(LOG_TILEMAP0, "read tilemap_scrolly[0] (%04x)\n", data);
1616 		}
1617 		break;
1618 	case 0x120/2:
1619 		if (!machine().side_effects_disabled())
1620 		{
1621 			LOGMASKED(LOG_TILEMAP1, "read tilemap_flags[1] (%04x)\n", data);
1622 		}
1623 		break;
1624 	default:
1625 		if (!machine().side_effects_disabled())
1626 		{
1627 			LOGMASKED(LOG_UNKNOWNS, "video_r: Unknown register: %08x (%04x & %04x)\n", 0xf00000 + (offset << 1), data, mem_mask);
1628 		}
1629 		break;
1630 	}
1631 
1632 	return data;
1633 }
1634 
TIMER_CALLBACK_MEMBER(supracan_state::hbl_callback)1635 TIMER_CALLBACK_MEMBER(supracan_state::hbl_callback)
1636 {
1637 	m_maincpu->set_input_line(3, HOLD_LINE);
1638 
1639 	m_hbl_timer->adjust(attotime::never);
1640 }
1641 
TIMER_CALLBACK_MEMBER(supracan_state::line_on_callback)1642 TIMER_CALLBACK_MEMBER(supracan_state::line_on_callback)
1643 {
1644 	m_maincpu->set_input_line(5, HOLD_LINE);
1645 
1646 	m_line_on_timer->adjust(attotime::never);
1647 }
1648 
TIMER_CALLBACK_MEMBER(supracan_state::line_off_callback)1649 TIMER_CALLBACK_MEMBER(supracan_state::line_off_callback)
1650 {
1651 	m_maincpu->set_input_line(5, CLEAR_LINE);
1652 
1653 	m_line_on_timer->adjust(attotime::never);
1654 }
1655 
TIMER_CALLBACK_MEMBER(supracan_state::video_callback)1656 TIMER_CALLBACK_MEMBER(supracan_state::video_callback)
1657 {
1658 	int vpos = m_screen->vpos();
1659 
1660 	m_video_regs[0] &= ~0x0002;
1661 
1662 	switch (vpos)
1663 	{
1664 	case 0:
1665 		m_video_regs[0] &= 0x7fff;
1666 
1667 		// we really need better management of this
1668 		mark_active_tilemap_all_dirty(0);
1669 		mark_active_tilemap_all_dirty(1);
1670 		mark_active_tilemap_all_dirty(2);
1671 		mark_active_tilemap_all_dirty(3);
1672 		break;
1673 
1674 	case 224: // FIXME: Son of Evil is pretty picky about this one, a timing of 240 makes it crash
1675 		m_video_regs[0] |= 0x8000;
1676 		break;
1677 
1678 	case 240:
1679 		if (m_irq_mask & 1)
1680 		{
1681 			LOGMASKED(LOG_IRQS, "Triggering VBL IRQ\n\n");
1682 			m_maincpu->set_input_line(7, HOLD_LINE);
1683 		}
1684 		break;
1685 	}
1686 
1687 	m_video_regs[1] = m_screen->vpos() - 16; // for son of evil, wants vblank active around 224 instead...
1688 
1689 	m_hbl_timer->adjust(m_screen->time_until_pos(vpos, 320));
1690 	m_video_timer->adjust(m_screen->time_until_pos((vpos + 1) % 256, 0));
1691 }
1692 
video_w(offs_t offset,uint16_t data,uint16_t mem_mask)1693 void supracan_state::video_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1694 {
1695 	address_space &mem = m_maincpu->space(AS_PROGRAM);
1696 
1697 	// if any of this changes we need a partial update (see sango fighters intro)
1698 	m_screen->update_partial(m_screen->vpos());
1699 
1700 	COMBINE_DATA(&m_video_regs[offset]);
1701 	data = m_video_regs[offset];
1702 
1703 	switch (offset)
1704 	{
1705 	case 0x10/2: // Byte count
1706 		LOGMASKED(LOG_SPRDMA, "sprite dma word count: %04x\n", data);
1707 		m_sprdma_regs.count = data;
1708 		break;
1709 	case 0x12/2: // Destination address MSW
1710 		m_sprdma_regs.dst &= 0x0000ffff;
1711 		m_sprdma_regs.dst |= data << 16;
1712 		LOGMASKED(LOG_SPRDMA, "sprite dma dest msw: %04x\n", data);
1713 		break;
1714 	case 0x14/2: // Destination address LSW
1715 		m_sprdma_regs.dst &= 0xffff0000;
1716 		m_sprdma_regs.dst |= data;
1717 		LOGMASKED(LOG_SPRDMA, "sprite dma dest lsw: %04x\n", data);
1718 		break;
1719 	case 0x16/2: // Source word increment
1720 		LOGMASKED(LOG_SPRDMA, "sprite dma dest word inc: %04x\n", data);
1721 		m_sprdma_regs.dst_inc = data;
1722 		break;
1723 	case 0x18/2: // Source address MSW
1724 		m_sprdma_regs.src &= 0x0000ffff;
1725 		m_sprdma_regs.src |= data << 16;
1726 		LOGMASKED(LOG_SPRDMA, "sprite dma src msw: %04x\n", data);
1727 		break;
1728 	case 0x1a/2: // Source address LSW
1729 		LOGMASKED(LOG_SPRDMA, "sprite dma src lsw: %04x\n", data);
1730 		m_sprdma_regs.src &= 0xffff0000;
1731 		m_sprdma_regs.src |= data;
1732 		break;
1733 	case 0x1c/2: // Source word increment
1734 		LOGMASKED(LOG_SPRDMA, "sprite dma src word inc: %04x\n", data);
1735 		m_sprdma_regs.src_inc = data;
1736 		break;
1737 	case 0x1e/2:
1738 		LOGMASKED(LOG_SPRDMA, "video_w: Kicking off a DMA from %08x to %08x, %d bytes (%04x)\n", m_sprdma_regs.src, m_sprdma_regs.dst, m_sprdma_regs.count, data);
1739 
1740 		/* TODO: what's 0x2000 and 0x4000 for? */
1741 		if (data & 0x8000)
1742 		{
1743 			if (data & 0x2000 || data & 0x4000)
1744 			{
1745 				m_sprdma_regs.dst |= 0xf40000;
1746 			}
1747 
1748 			if (data & 0x2000)
1749 			{
1750 				//m_sprdma_regs.count <<= 1;
1751 			}
1752 
1753 			for (int i = 0; i <= m_sprdma_regs.count; i++)
1754 			{
1755 				if (data & 0x0100) // dma 0x00 fill (or fixed value?)
1756 				{
1757 					mem.write_word(m_sprdma_regs.dst, 0);
1758 					m_sprdma_regs.dst += 2 * m_sprdma_regs.dst_inc;
1759 					//memset(supracan_vram, 0x00, 0x020000);
1760 				}
1761 				else
1762 				{
1763 					mem.write_word(m_sprdma_regs.dst, mem.read_word(m_sprdma_regs.src));
1764 					m_sprdma_regs.dst += 2 * m_sprdma_regs.dst_inc;
1765 					m_sprdma_regs.src += 2 * m_sprdma_regs.src_inc;
1766 				}
1767 			}
1768 		}
1769 		else
1770 		{
1771 			LOGMASKED(LOG_SPRDMA | LOG_UNKNOWNS, "dma_w: Attempting to kick off a DMA without bit 15 set! (%04x)\n", data);
1772 		}
1773 		break;
1774 	case 0x08/2:
1775 		if (data != m_video_flags)
1776 		{
1777 			LOGMASKED(LOG_VIDEO, "video_flags = %04x\n", data);
1778 
1779 			m_video_flags = data;
1780 
1781 			rectangle visarea = m_screen->visible_area();
1782 
1783 			visarea.set(0, ((m_video_flags & 0x100) ? 320 : 256) - 1, 8, 232 - 1);
1784 			m_screen->configure(348, 256, visarea, m_screen->frame_period().attoseconds());
1785 		}
1786 		break;
1787 	case 0x0a/2:
1788 		// raster interrupt
1789 		LOGMASKED(LOG_IRQS, "Raster 'line on' IRQ Trigger write? = %04x\n", data);
1790 		if (data & 0x8000)
1791 		{
1792 			m_line_on_timer->adjust(m_screen->time_until_pos((data & 0x00ff), 0));
1793 		}
1794 		else
1795 		{
1796 			m_line_on_timer->adjust(attotime::never);
1797 		}
1798 		break;
1799 
1800 	case 0x0c/2:
1801 		LOGMASKED(LOG_IRQS, "Raster 'line off' IRQ Trigger write? = %04x\n", data);
1802 		if (data & 0x8000)
1803 		{
1804 			m_line_off_timer->adjust(m_screen->time_until_pos(data & 0x00ff, 0));
1805 		}
1806 		else
1807 		{
1808 			m_line_off_timer->adjust(attotime::never);
1809 		}
1810 		break;
1811 
1812 	/* Sprites */
1813 	case 0x20/2: m_sprite_base_addr = data << 2; LOGMASKED(LOG_SPRITES, "sprite_base_addr = %04x\n", data); break;
1814 	case 0x22/2: m_sprite_count = data + 1; LOGMASKED(LOG_SPRITES, "sprite_count = %d\n", data + 1); break;
1815 	case 0x26/2: m_sprite_flags = data; LOGMASKED(LOG_SPRITES, "sprite_flags = %04x\n", data); break;
1816 
1817 	/* Tilemap 0 */
1818 	case 0x100/2: m_tilemap_flags[0] = data; LOGMASKED(LOG_TILEMAP0, "tilemap_flags[0] = %04x\n", data); break;
1819 	case 0x104/2: m_tilemap_scrollx[0] = data; LOGMASKED(LOG_TILEMAP0, "tilemap_scrollx[0] = %04x\n", data); break;
1820 	case 0x106/2: m_tilemap_scrolly[0] = data; LOGMASKED(LOG_TILEMAP0, "tilemap_scrolly[0] = %04x\n", data); break;
1821 	case 0x108/2: m_tilemap_base_addr[0] = data << 1; LOGMASKED(LOG_TILEMAP0, "tilemap_base_addr[0] = %05x\n", data << 2); break;
1822 	case 0x10a/2: m_tilemap_mode[0] = data; LOGMASKED(LOG_TILEMAP0, "tilemap_mode[0] = %04x\n", data); break;
1823 
1824 	/* Tilemap 1 */
1825 	case 0x120/2: m_tilemap_flags[1] = data; LOGMASKED(LOG_TILEMAP1, "tilemap_flags[1] = %04x\n", data); break;
1826 	case 0x124/2: m_tilemap_scrollx[1] = data; LOGMASKED(LOG_TILEMAP1, "tilemap_scrollx[1] = %04x\n", data); break;
1827 	case 0x126/2: m_tilemap_scrolly[1] = data; LOGMASKED(LOG_TILEMAP1, "tilemap_scrolly[1] = %04x\n", data); break;
1828 	case 0x128/2: m_tilemap_base_addr[1] = data << 1; LOGMASKED(LOG_TILEMAP1, "tilemap_base_addr[1] = %05x\n", data << 2); break;
1829 	case 0x12a/2: m_tilemap_mode[1] = data; LOGMASKED(LOG_TILEMAP1, "tilemap_mode[1] = %04x\n", data); break;
1830 
1831 	/* Tilemap 2? */
1832 	case 0x140/2: m_tilemap_flags[2] = data; LOGMASKED(LOG_TILEMAP2, "tilemap_flags[2] = %04x\n", data); break;
1833 	case 0x144/2: m_tilemap_scrollx[2] = data; LOGMASKED(LOG_TILEMAP2, "tilemap_scrollx[2] = %04x\n", data); break;
1834 	case 0x146/2: m_tilemap_scrolly[2] = data; LOGMASKED(LOG_TILEMAP2, "tilemap_scrolly[2] = %04x\n", data); break;
1835 	case 0x148/2: m_tilemap_base_addr[2] = data << 1; LOGMASKED(LOG_TILEMAP2, "tilemap_base_addr[2] = %05x\n", data << 2); break;
1836 	case 0x14a/2: m_tilemap_mode[2] = data; LOGMASKED(LOG_TILEMAP2, "tilemap_mode[2] = %04x\n", data); break;
1837 
1838 	/* ROZ */
1839 	case 0x180/2: m_roz_mode = data; LOGMASKED(LOG_ROZ, "roz_mode = %04x\n", data); break;
1840 	case 0x184/2: m_roz_scrollx = (data << 16) | (m_roz_scrollx & 0xffff); m_roz_changed |= 1; LOGMASKED(LOG_ROZ, "roz_scrollx = %08x\n", m_roz_scrollx); break;
1841 	case 0x186/2: m_roz_scrollx = (data) | (m_roz_scrollx & 0xffff0000); m_roz_changed |= 1; LOGMASKED(LOG_ROZ, "roz_scrollx = %08x\n", m_roz_scrollx); break;
1842 	case 0x188/2: m_roz_scrolly = (data << 16) | (m_roz_scrolly & 0xffff); m_roz_changed |= 2; LOGMASKED(LOG_ROZ, "roz_scrolly = %08x\n", m_roz_scrolly); break;
1843 	case 0x18a/2: m_roz_scrolly = (data) | (m_roz_scrolly & 0xffff0000); m_roz_changed |= 2; LOGMASKED(LOG_ROZ, "roz_scrolly = %08x\n", m_roz_scrolly); break;
1844 	case 0x18c/2: m_roz_coeffa = data; LOGMASKED(LOG_ROZ, "roz_coeffa = %04x\n", data); break;
1845 	case 0x18e/2: m_roz_coeffb = data; LOGMASKED(LOG_ROZ, "roz_coeffb = %04x\n", data); break;
1846 	case 0x190/2: m_roz_coeffc = data; LOGMASKED(LOG_ROZ, "roz_coeffc = %04x\n", data); break;
1847 	case 0x192/2: m_roz_coeffd = data; LOGMASKED(LOG_ROZ, "roz_coeffd = %04x\n", data); break;
1848 	case 0x194/2: m_roz_base_addr = data << 1; LOGMASKED(LOG_ROZ, "roz_base_addr = %05x\n", data << 2); break;
1849 	case 0x196/2: m_roz_tile_bank = data; LOGMASKED(LOG_ROZ, "roz_tile_bank = %04x\n", data); break; //tile bank
1850 	case 0x198/2: m_roz_unk_base0 = data << 2; LOGMASKED(LOG_ROZ, "roz_unk_base0 = %05x\n", data << 2); break;
1851 	case 0x19a/2: m_roz_unk_base1 = data << 2; LOGMASKED(LOG_ROZ, "roz_unk_base1 = %05x\n", data << 2); break;
1852 	case 0x19e/2: m_roz_unk_base2 = data << 2; LOGMASKED(LOG_ROZ, "roz_unk_base2 = %05x\n", data << 2); break;
1853 
1854 	case 0x1d0/2: m_unk_1d0 = data; LOGMASKED(LOG_UNKNOWNS, "unk_1d0 = %04x\n", data); break;
1855 
1856 	case 0x1f0/2: // FIXME: this register is mostly not understood
1857 		m_irq_mask = data;//(data & 8) ? 0 : 1;
1858 #if 0
1859 		if (!m_irq_mask && !m_hbl_mask)
1860 		{
1861 			m_maincpu->set_input_line(7, CLEAR_LINE);
1862 		}
1863 #endif
1864 		LOGMASKED(LOG_IRQS, "irq_mask = %04x\n", data);
1865 		break;
1866 	default:
1867 		LOGMASKED(LOG_UNKNOWNS, "video_w: Unknown register: %08x = %04x & %04x\n", 0xf00000 + (offset << 1), data, mem_mask);
1868 		break;
1869 	}
1870 //  m_video_regs[offset] = data;
1871 }
1872 
1873 
DEVICE_IMAGE_LOAD_MEMBER(supracan_state::cart_load)1874 DEVICE_IMAGE_LOAD_MEMBER(supracan_state::cart_load)
1875 {
1876 	uint32_t size = m_cart->common_get_size("rom");
1877 
1878 	if (size > 0x400000)
1879 	{
1880 		image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size");
1881 		return image_init_result::FAIL;
1882 	}
1883 
1884 	m_cart->rom_alloc(size, GENERIC_ROM16_WIDTH, ENDIANNESS_BIG);
1885 	m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom");
1886 
1887 	return image_init_result::PASS;
1888 }
1889 
1890 
machine_start()1891 void supracan_state::machine_start()
1892 {
1893 	save_item(NAME(m_dma_regs.source));
1894 	save_item(NAME(m_dma_regs.dest));
1895 	save_item(NAME(m_dma_regs.count));
1896 	save_item(NAME(m_dma_regs.control));
1897 
1898 	save_item(NAME(m_sprdma_regs.src));
1899 	save_item(NAME(m_sprdma_regs.src_inc));
1900 	save_item(NAME(m_sprdma_regs.dst));
1901 	save_item(NAME(m_sprdma_regs.dst_inc));
1902 	save_item(NAME(m_sprdma_regs.count));
1903 	save_item(NAME(m_sprdma_regs.control));
1904 
1905 	save_item(NAME(m_sound_cpu_ctrl));
1906 	save_item(NAME(m_soundcpu_irq_enable));
1907 	save_item(NAME(m_soundcpu_irq_source));
1908 	save_item(NAME(m_sound_cpu_shift_ctrl));
1909 	save_item(NAME(m_sound_cpu_shift_regs));
1910 	save_item(NAME(m_latched_controls));
1911 	save_item(NAME(m_sound_status));
1912 	save_item(NAME(m_sound_reg_addr));
1913 	save_item(NAME(m_sound_regs));
1914 
1915 	save_item(NAME(m_sprite_count));
1916 	save_item(NAME(m_sprite_base_addr));
1917 	save_item(NAME(m_sprite_flags));
1918 
1919 	save_item(NAME(m_tilemap_base_addr));
1920 	save_item(NAME(m_tilemap_scrollx));
1921 	save_item(NAME(m_tilemap_scrolly));
1922 	save_item(NAME(m_video_flags));
1923 	save_item(NAME(m_tilemap_flags));
1924 	save_item(NAME(m_tilemap_mode));
1925 	save_item(NAME(m_irq_mask));
1926 #if 0
1927 	save_item(NAME(m_hbl_mask));
1928 #endif
1929 
1930 	save_item(NAME(m_roz_base_addr));
1931 	save_item(NAME(m_roz_mode));
1932 	save_item(NAME(m_roz_scrollx));
1933 	save_item(NAME(m_roz_scrolly));
1934 	save_item(NAME(m_roz_tile_bank));
1935 	save_item(NAME(m_roz_unk_base0));
1936 	save_item(NAME(m_roz_unk_base1));
1937 	save_item(NAME(m_roz_unk_base2));
1938 	save_item(NAME(m_roz_coeffa));
1939 	save_item(NAME(m_roz_coeffb));
1940 	save_item(NAME(m_roz_coeffc));
1941 	save_item(NAME(m_roz_coeffd));
1942 	save_item(NAME(m_roz_changed));
1943 	save_item(NAME(m_unk_1d0));
1944 
1945 	save_item(NAME(m_video_regs));
1946 
1947 	m_video_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(supracan_state::video_callback), this));
1948 	m_hbl_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(supracan_state::hbl_callback), this));
1949 	m_line_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(supracan_state::line_on_callback), this));
1950 	m_line_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(supracan_state::line_off_callback), this));
1951 
1952 	if (m_cart->exists())
1953 		m_maincpu->space(AS_PROGRAM).install_read_handler(0x000000, 0x3fffff, read16s_delegate(*m_cart, FUNC(generic_slot_device::read16_rom)));
1954 }
1955 
1956 
machine_reset()1957 void supracan_state::machine_reset()
1958 {
1959 	m_sprite_count = 0;
1960 	m_sprite_base_addr = 0;
1961 	m_sprite_flags = 0;
1962 
1963 	m_sound_cpu_ctrl = 0;
1964 	m_soundcpu_irq_enable = 0;
1965 	m_soundcpu_irq_source = 0;
1966 	m_sound_cpu_shift_ctrl = 0;
1967 	memset(m_sound_cpu_shift_regs, 0, ARRAY_LENGTH(m_sound_cpu_shift_regs));
1968 	memset(m_latched_controls, 0, sizeof(uint16_t) * ARRAY_LENGTH(m_latched_controls));
1969 	m_sound_status = 0;
1970 	m_sound_reg_addr = 0;
1971 	memset(m_sound_regs, 0, ARRAY_LENGTH(m_sound_regs));
1972 
1973 	m_soundcpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
1974 
1975 	m_video_timer->adjust(m_screen->time_until_pos(0, 0));
1976 	m_irq_mask = 0;
1977 }
1978 
1979 /* gfxdecode is retained for reference purposes but not otherwise used by the driver */
1980 static const gfx_layout supracan_gfx8bpp =
1981 {
1982 	8, 8,
1983 	RGN_FRAC(1, 1),
1984 	8,
1985 	{ 0, 1, 2, 3, 4, 5, 6, 7 },
1986 	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
1987 	{ STEP8(0, 8*8) },
1988 	8*8*8
1989 };
1990 
1991 
1992 
1993 static const gfx_layout supracan_gfx4bpp =
1994 {
1995 	8, 8,
1996 	RGN_FRAC(1, 1),
1997 	4,
1998 	{ 0, 1, 2, 3 },
1999 	{ 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 },
2000 	{ 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 },
2001 	8*32
2002 };
2003 
2004 static const gfx_layout supracan_gfx2bpp =
2005 {
2006 	8, 8,
2007 	RGN_FRAC(1, 1),
2008 	2,
2009 	{ 0, 1 },
2010 	{ 0*2, 1*2, 2*2, 3*2, 4*2, 5*2, 6*2, 7*2 },
2011 	{ 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
2012 	8*16
2013 };
2014 
2015 
2016 static const uint32_t xtexlayout_xoffset[64] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
2017 												24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
2018 												45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 };
2019 
2020 static const uint32_t xtexlayout_yoffset[64] = {  0*64,1*64,2*64,3*64,4*64,5*64,6*64,7*64,8*64,
2021 												9*64,10*64,11*64,12*64,13*64,14*64,15*64,
2022 												16*64,17*64,18*64,19*64,20*64,21*64,22*64,23*64,
2023 												24*64,25*64,26*64,27*64,28*64,29*64,30*64,31*64,
2024 												32*64,33*64,34*64,35*64,36*64,37*64,38*64,39*64,
2025 												40*64,41*64,42*64,43*64,44*64,45*64,46*64,47*64,
2026 												48*64,49*64,50*64,51*64,52*64,53*64,54*64,55*64,
2027 												56*64,57*64,58*64,59*64,60*64,61*64,62*64,63*64 };
2028 static const gfx_layout supracan_gfx1bpp =
2029 {
2030 	64, 64,
2031 	RGN_FRAC(1, 1),
2032 	1,
2033 	{ 0 },
2034 	EXTENDED_XOFFS,
2035 	EXTENDED_YOFFS,
2036 	64*64,
2037 	xtexlayout_xoffset,
2038 	xtexlayout_yoffset
2039 };
2040 
2041 static const gfx_layout supracan_gfx1bpp_alt =
2042 {
2043 	8, 8,
2044 	RGN_FRAC(1, 1),
2045 	1,
2046 	{ 0 },
2047 	{ 0, 1, 2, 3, 4, 5, 6, 7 },
2048 	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
2049 	8*8
2050 };
2051 
2052 
2053 static GFXDECODE_START( gfx_supracan )
2054 	GFXDECODE_RAM( "vram", 0, supracan_gfx8bpp, 0, 1 )
2055 	GFXDECODE_RAM( "vram", 0, supracan_gfx4bpp, 0, 0x10 )
2056 	GFXDECODE_RAM( "vram", 0, supracan_gfx2bpp, 0, 0x40 )
2057 	GFXDECODE_RAM( "vram", 0, supracan_gfx1bpp, 0, 0x80 )
2058 	GFXDECODE_RAM( "vram", 0, supracan_gfx1bpp_alt, 0, 0x80 )
2059 GFXDECODE_END
2060 
INTERRUPT_GEN_MEMBER(supracan_state::sound_irq)2061 INTERRUPT_GEN_MEMBER(supracan_state::sound_irq)
2062 {
2063 	set_sound_irq(0x80);
2064 }
2065 
supracan(machine_config & config)2066 void supracan_state::supracan(machine_config &config)
2067 {
2068 	M68000(config, m_maincpu, XTAL(10'738'635));        /* Correct frequency unknown */
2069 	m_maincpu->set_addrmap(AS_PROGRAM, &supracan_state::supracan_mem);
2070 
2071 	M6502(config, m_soundcpu, XTAL(3'579'545));     /* TODO: Verify actual clock */
2072 	m_soundcpu->set_addrmap(AS_PROGRAM, &supracan_state::supracan_sound_mem);
2073 	m_soundcpu->set_vblank_int("screen", FUNC(supracan_state::sound_irq));
2074 
2075 	config.set_perfect_quantum(m_soundcpu);
2076 
2077 	SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
2078 	m_screen->set_raw(XTAL(10'738'635)/2, 348, 0, 256, 256, 0, 240);  /* No idea if this is correct */
2079 	m_screen->set_screen_update(FUNC(supracan_state::screen_update));
2080 	m_screen->set_palette("palette");
2081 
2082 	PALETTE(config, "palette", FUNC(supracan_state::palette_init)).set_format(palette_device::xBGR_555, 32768);
2083 
2084 	GFXDECODE(config, m_gfxdecode, "palette", gfx_supracan);
2085 
2086 	generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "supracan_cart"));
2087 	cartslot.set_width(GENERIC_ROM16_WIDTH);
2088 	cartslot.set_endian(ENDIANNESS_BIG);
2089 	cartslot.set_device_load(FUNC(supracan_state::cart_load));
2090 
2091 	SOFTWARE_LIST(config, "cart_list").set_original("supracan");
2092 }
2093 
2094 ROM_START( supracan )
2095 ROM_END
2096 
2097 /*    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT     STATE           INIT        COMPANY                  FULLNAME        FLAGS */
2098 CONS( 1995, supracan, 0,      0,      supracan, supracan, supracan_state, empty_init, "Funtech Entertainment", "Super A'Can",  MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
2099