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