/* Halley's Comet, 1986 Taito Halley's Comet was created by Fukio Mitsuji (MTJ), who also created Bubble Bobble, Rainbow Islands, Syvalion, etc. Issues: - Status reads from blitter RAM aren't well understood. They probably includes both completion and collision flags. - The blitter is missing many features, in particular certain sprites aren't erased properly. - It isn't known how many independent planes of graphics the blitter manages. The starfield, for example, probably involves at least two additional planes orthogonal to the sprites and scroll layer. - Background tiles inside the comet have wrong coordinates. - Score digits have wrong colors. - Blitter functions, especially those capable of screen warping, are unoptimized. - The starfields can probably be represented and rendered by two simple lists instead of costly bitmaps. - Ben Bero Beh has collision problems with the falling fireballs and a minor priority glitch with the "Elevator Action" baddies. - IRQ system needs a complete rewrite - De-achoize the blitter code * Halley's Comet's undocumented DIP switches only work if the player1 start button is depressed during boot-up. Special thanks to Phil Stroffolino for the creation of a solid framework, Jarek Burczynski for adding sound and providing awesome hand-drawn schematics, Jason MacFarlane for his continuous and selfless support. I'd never have come all this way without the invaluable videos and screen shots sent by Jason. To the Columbia crew and the forerunners who gave their lives to science and space exploration. Your bravery and devotion will not be forgotten. CPU: MC68B09EP Z80A(SOUND) Sound: YM2149F x 4 OSC: 19.968MHz 6MHz J1100021 sound daughterboard Z80A 6MHz 2016 A62-13 A62-14 YM2149 YM2149 YM2149 J1100018 sw1 sw2 sw3 sw4 A62-2 A62-15 68B09EP A62-1 A62-4 2016 YM2149 2016 J1100020 4116 4116 4116 4116 MB15511 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 MB15512 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 4116 MB15510 MB15510 2016 2016 J1100019 A62-9 A62-10 A26-13 A62-11 A62-12 A26-13 A62-5 A62-16 A26-13 A62-7 A62-8 HALLEY'S COMET Taito 1986 Pinout and DIP switch settings typed in by Pelle Einarsson, pelle@mensa.se NOTE: I had to guess the meaning of some Japanese text concerning the DIP switch settings, but I think I got it right. * = default settings T G PARTS SOLDER PARTS SOLDER ---------------------------------- --------------------------------------- GND 1 A GND GND 1 A GND GND 2 B GND 2 B GND 3 C GND 3 C GND 4 D GND 4 D Video GND 5 E Video GND Sound out+ 5 E Sound Out - Video sync 6 F Video sync Post 6 F Post Post 7 H Post 7 H Power on reset Video R 8 J Video R Coin sw A 8 J Coin sw B Video G 9 K Video G Coin counter A 9 K Coin counter B Video B 10 L Video B Coin lockout A 10 L Coin lockout B -5V 11 M -5V Service sw 11 M Tilt sw -5V 12 N -5V Select 1 12 N Select 2 +12V 13 P +12V 1P up 13 P 2P up +12V 14 R +12V 1P down 14 R 2P down +5V 15 S +5V 1P right 15 S 2P right +5V 16 T +5V 1P left 16 T 2P left +5V 17 U +5V 17 U +5V 18 V +5V 18 V 19 W 20 X H 1P shoot 21 Y 2p shoot -------- 1P hyperspace 22 Z 2P hyperspace 1 GND 2 GND 3 GND 4 GND 5 +5V 6 +5V 7 +5V 8 -5V 9 +13V (a typo?) DIP switch 1 Option 1-5 6 10 Post ---------------------------------------------- 11 +12V (single/dual controls?) *1-way off on 12 +12V 2-way off color test layout: (0,0) *ROT90 +------+-------+------+------+ | | | | | | White| Blue |Green | Red | 1 (brightest) | | | | | +------+-------+------+------+ | | | | | | | | | | 2 | | | | | +------+-------+------+------+ | | | | | | | | | | 3 | | | | | +------+-------+------+------+ | | | | | | | | | | 4 (darkest) | | | | | +------+-------+------+------+ */ //************************************************************************** // Compiler Directives #include "emu.h" #include "cpu/z80/z80.h" #include "includes/taitoipt.h" #include "cpu/m6809/m6809.h" #include "sound/ay8910.h" #define HALLEYS_DEBUG 0 //************************************************************************** // Driver Constants and Variables #define GAME_BENBEROB 0 #define GAME_HALLEYS 1 /* CAUTION: SENSITIVE VALUES */ #define SCREEN_WIDTH_L2 8 #define SCREEN_HEIGHT 256 #define VIS_MINX 0 #define VIS_MAXX 255 #define VIS_MINY 8 #define VIS_MAXY (255-8) #define MAX_LAYERS 6 #define MAX_SPRITES 256 #define MAX_SOUNDS 16 #define SP_2BACK 0x100 #define SP_ALPHA 0x200 #define SP_COLLD 0x300 #define BG_MONO 0x400 #define BG_RGB 0x500 #define PALETTE_SIZE 0x600 #define SCREEN_WIDTH (1 << SCREEN_WIDTH_L2) #define SCREEN_SIZE (SCREEN_HEIGHT << SCREEN_WIDTH_L2) #define SCREEN_BYTEWIDTH_L2 (SCREEN_WIDTH_L2 + 1) #define SCREEN_BYTEWIDTH (1 << SCREEN_BYTEWIDTH_L2) #define SCREEN_BYTESIZE (SCREEN_HEIGHT << SCREEN_BYTEWIDTH_L2) #define CLIP_SKIP (VIS_MINY * SCREEN_WIDTH + VIS_MINX) #define CLIP_W (VIS_MAXX - VIS_MINX + 1) #define CLIP_H (VIS_MAXY - VIS_MINY + 1) #define CLIP_BYTEW (CLIP_W << 1) class halleys_state : public driver_device { public: halleys_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) { } UINT16 *m_render_layer[MAX_LAYERS]; UINT8 m_sound_fifo[MAX_SOUNDS]; UINT8 *m_gfx_plane02; UINT8 *m_gfx_plane13; UINT8 *m_collision_list; UINT8 *m_scrolly0; UINT8 *m_scrollx0; UINT8 *m_scrolly1; UINT8 *m_scrollx1; UINT32 *m_internal_palette; UINT32 *m_alpha_table; UINT8 *m_cpu1_base; UINT8 *m_gfx1_base; UINT8 *m_blitter_ram; UINT8 *m_io_ram; size_t m_blitter_ramsize; size_t m_io_ramsize; int m_game_id; int m_blitter_busy; int m_collision_count; int m_stars_enabled; int m_bgcolor; int m_ffcount; int m_ffhead; int m_fftail; int m_mVectorType; int m_sndnmi_mask; int m_firq_level; emu_timer *m_blitter_reset_timer; offs_t m_collision_detection; int m_latch_delay; }; //************************************************************************** // MB1551x Blitter Functions static void blit(halleys_state *state, int offset) { /* The render layers can be converted to standard MAME bitmaps but I am not taking chances as long as the blitter has unknown draw modes which may go beyond MAME's capability. The function has grown tremendously as more features were added and become rather difficult to maintain. */ // status attributes #define ACTIVE 0x02 #define DECAY 0x10 #define RETIRE 0x80 // mode attributes #define IGNORE_0 0x01 #define MODE_02 0x02 #define COLOR_ON 0x04 #define MIRROR_X 0x08 #define MIRROR_Y 0x10 #define MODE_40 0x40 #define GROUP 0x80 // color attributes #define PENCOLOR 0x0f #define BANKBIT1 0x80 // code attributes #define COMMAND 0x0f #define BGLAYER 0x10 #define BANKBIT0 0x40 #define PLANE 0x80 // special draw commands #define EFX1 0x8 // draws to back?? #define HORIZBAR 0xe // draws 8-bit RGB horizontal bars #define STARPASS1 0x3 // draws the stars #define STARPASS2 0xd // modifies stars color #define TILEPASS1 0x5 // draws tiles(s1: embedded 8-bit RGB, s2: bit-packed pixel data) #define TILEPASS2 0xb // modifies tiles color/alpha // user flags #define FLIP_X 0x0100 #define FLIP_Y 0x0200 #define SINGLE_PEN 0x0400 #define RGB_MASK 0x0800 #define AD_HIGH 0x1000 #define SY_HIGH 0x2000 #define S1_IDLE 0x4000 #define S1_REV 0x8000 #define S2_IDLE 0x10000 #define S2_REV 0x20000 #define BACKMODE 0x40000 #define ALPHAMODE 0x80000 #define PPCD_ON 0x100000 // hard-wired defs and interfaces #define HALLEYS_SPLIT 0xf4 #define COLLISION_PORTA 0x67 #define COLLISION_PORTB 0x8b // short cuts #define XMASK (SCREEN_WIDTH-1) #define YMASK (SCREEN_HEIGHT-1) static const UINT8 penxlat[16]={0x03,0x07,0x0b,0x0f,0x02,0x06,0x0a,0x0e,0x01,0x05,0x09,0x0d,0x00,0x04,0x08,0x0c}; static const UINT8 rgbmask[16]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xff,0xff,0xff}; static const UINT8 tyremap[ 8]={ 0, 5, 9,13,16,20,24,28}; UINT8 *param, *src_base; UINT16 *dst_base; int stptr, mode, color, code, y, x, h, w, src1, src2; int status, flags, group, command, bank, layer, pen0, pen1; int yclip, xclip, src_yskip, src_xskip, dst_skip, hclip, wclip, src_dy, src_dx; UINT32 *pal_ptr; UINT8 *src1_ptr, *src2_ptr; // esi alias, ebx alias UINT16 *dst_ptr; // edi alias void *edi; // scratch int eax, ebx, ecx, edx; // scratch UINT16 ax; UINT8 al, ah; // partial regs param = state->m_blitter_ram + offset; #if HALLEYS_DEBUG if (0) { logerror("%s:[%04x]", machine.describe_context(), offset); for (ecx=0; ecx<16; ecx++) logerror(" %02x", param[ecx]); logerror("\n"); } #endif // init blitter controls stptr = (int)param[0x2]<<8 | (int)param[0x3]; mode = (int)param[0x5]; color = (int)param[0x6]; code = (int)param[0x7]; // update sprite status layer = (code>>3 & 2) | (code>>7 & 1); offset >>= 4; status = (stptr) ? state->m_cpu1_base[stptr] : ACTIVE; flags = mode; group = mode & GROUP; command = code & COMMAND; if (state->m_game_id == GAME_HALLEYS) { if (!layer) flags |= PPCD_ON; if (offset >= HALLEYS_SPLIT) flags |= AD_HIGH; else if (offset & 1) memcpy(param-0x10, param, 0x10); else group = param[0x15] & GROUP; // HACK: force engine flame in group zero to increase collision accuracy if (offset == 0x1a || offset == 0x1b) group = 0; } else if (offset & 1) memcpy(param-0x10, param, 0x10); // init draw parameters y = (int)param[0x8]; x = (int)param[0x9]; h = (int)param[0xa]; w = (int)param[0xb] + 1; if (!h) return; // translate source addresses src1 = (int)param[0xc]<<8 | (int)param[0xd]; src2 = (int)param[0xe]<<8 | (int)param[0xf]; flags |= src1 & (S1_IDLE | S1_REV); flags |= src2<<2 & (S2_IDLE | S2_REV); src1 &= 0x3fff; src2 &= 0x3fff; bank = ((code & BANKBIT0) | (color & BANKBIT1)) << 8; pal_ptr = state->m_internal_palette; // the crossroad of fate if (code & BGLAYER || command & 7) goto COMMAND_MODE; // reject off-screen objects if (flags & MIRROR_Y) { flags |= FLIP_Y; y -= (h - 1); } if (flags & MIRROR_X) { flags |= FLIP_X; x -= (w - 1); } if (y > VIS_MAXY || (y + h) <= VIS_MINY) return; if (x > VIS_MAXX || (x + w) <= VIS_MINX) return; // clip objects against the visible area yclip = y; xclip = x; hclip = h; wclip = w; src_yskip = src_xskip = dst_skip = 0; if (yclip < VIS_MINY) { src_yskip = VIS_MINY - yclip; yclip = VIS_MINY; hclip -= src_yskip; } if (yclip + hclip > VIS_MAXY+1) { hclip = VIS_MAXY+1 - yclip; } if (xclip < VIS_MINX) { src_xskip = VIS_MINX - xclip; xclip = VIS_MINX; wclip -= src_xskip; } if (xclip + wclip > VIS_MAXX+1) { wclip = VIS_MAXX+1 - xclip; } dst_skip = (yclip << SCREEN_WIDTH_L2) + xclip; // adjust orientations eax = 0; if (flags & (S1_REV | S2_REV)) { flags ^= FLIP_Y | FLIP_X; eax -= w * h - 8; } if (flags & FLIP_Y) { eax += w * (h - 1); src_yskip = -src_yskip; src_dy = (flags & FLIP_X) ? -w + wclip : -w - wclip; } else src_dy = (flags & FLIP_X) ? w + wclip : w - wclip; if (flags & FLIP_X) { eax += w - 1; src_xskip = -src_xskip; src_dx = -1; } else src_dx = 1; // calculate entry points and loop constants src1_ptr = state->m_gfx_plane02 + ((bank + src1)<<3) + eax; src2_ptr = state->m_gfx_plane13 + ((bank + src2)<<3) + eax; if (!(flags & (S1_IDLE | S2_IDLE))) { eax = src_yskip * w + src_xskip; src1_ptr += eax; src2_ptr += eax; } else src_dy = src_dx = 0; dst_ptr = state->m_render_layer[layer] + dst_skip; // look up pen values and set rendering flags pen0 = code>>3 & 0x10; pen1 = 0; if (command == EFX1) { flags |= BACKMODE; pen0 |= SP_2BACK; } if (src1 == src2) { flags |= SINGLE_PEN; eax = (UINT32)penxlat[color & PENCOLOR]; if (eax) pen1 = pen0 + eax; } else if (color & PENCOLOR) flags |= RGB_MASK; //-------------------------------------------------------------------------- #define BLOCK_WIPE_COMMON { \ eax = wclip<<1; \ ecx = hclip; \ edi = dst_ptr; \ do { memset((UINT8*)edi, 0, eax); edi = (UINT8*)edi + SCREEN_BYTEWIDTH; } while (--ecx); \ } //-------------------------------------------------------------------------- // multi-pen block or transparent blit if ((flags & (SINGLE_PEN | RGB_MASK | COLOR_ON)) == COLOR_ON) { if (!(flags & IGNORE_0)) BLOCK_WIPE_COMMON dst_ptr += wclip; ecx = wclip = -wclip; edx = src_dx; if (flags & PPCD_ON) goto COLLISION_MODE; al = ah = (UINT8)pen0; if (!(flags & BACKMODE)) { do { do { al |= *src1_ptr; src1_ptr += edx; al |= *src2_ptr; src2_ptr += edx; if (al & 0xf) { dst_ptr[ecx] = (UINT16)al; al = ah;} } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } else { do { do { al |= *src1_ptr; src1_ptr += edx; al |= *src2_ptr; src2_ptr += edx; if (al & 0xf) { dst_ptr[ecx] = (UINT16)al | SP_2BACK; al = ah; } } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } return; COLLISION_MODE: ax = 0; if (group) { do { do { al = *src1_ptr; src1_ptr += edx; al |= *src2_ptr; src2_ptr += edx; if (al & 0xf) { dst_ptr[ecx] = (UINT16)al | SP_COLLD; } // set collision flag on group one pixels } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } else { do { do { al = *src1_ptr; src1_ptr += edx; al |= *src2_ptr; src2_ptr += edx; if (al & 0xf) { ax |= dst_ptr[ecx]; dst_ptr[ecx] = (UINT16)al; } // combine collision flags in ax } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } // update collision list if object collided with the other group if (status & ACTIVE && ax & SP_COLLD) { state->m_collision_list[state->m_collision_count & (MAX_SPRITES-1)] = offset; state->m_collision_count++; #if HALLEYS_DEBUG popmessage("ID:%02x CC:%3d", offset, state->m_collision_count); #endif } } else //-------------------------------------------------------------------------- // multi-pen, RGB masked block or transparent blit if ((flags & (RGB_MASK | COLOR_ON)) == RGB_MASK + COLOR_ON) { if (!(flags & IGNORE_0)) BLOCK_WIPE_COMMON dst_ptr += wclip; ecx = wclip = -wclip; al = ah = (UINT8)pen0; ebx = rgbmask[color & PENCOLOR] | 0xffffff00; do { do { al |= *src1_ptr; src1_ptr += src_dx; al |= *src2_ptr; src2_ptr += src_dx; if (al & 0xf) { edx = (UINT32)al; al = ah; dst_ptr[ecx] = pal_ptr[edx] & ebx; } } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } else //-------------------------------------------------------------------------- // single-pen block or transparent blit if ((flags & (SINGLE_PEN | COLOR_ON)) == SINGLE_PEN + COLOR_ON) { if (!(flags & IGNORE_0)) BLOCK_WIPE_COMMON dst_ptr += wclip; ebx = hclip; ecx = wclip = -wclip; edx = src_dx; ax = (UINT16)pen1; do { do { if (*src1_ptr) dst_ptr[ecx] = ax; src1_ptr += edx; } while (++ecx); ecx = wclip; src1_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--ebx); } else //-------------------------------------------------------------------------- // transparent wipe if ((flags & (IGNORE_0 | COLOR_ON)) == IGNORE_0) { dst_ptr += wclip; wclip = -wclip; ecx = wclip; edx = src_dx; if (flags & PPCD_ON && !group) { // preserve collision flags when wiping group zero objects do { do { al = *src1_ptr; ah = *src2_ptr; src1_ptr += edx; src2_ptr += edx; if (al | ah) dst_ptr[ecx] &= SP_COLLD; } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } else { do { do { al = *src1_ptr; ah = *src2_ptr; src1_ptr += edx; src2_ptr += edx; if (al | ah) dst_ptr[ecx] = 0; } while (++ecx); ecx = wclip; src1_ptr += src_dy; src2_ptr += src_dy; dst_ptr += SCREEN_WIDTH; } while (--hclip); } } else //-------------------------------------------------------------------------- // block wipe if ((flags & (IGNORE_0 | COLOR_ON)) == 0) BLOCK_WIPE_COMMON //-------------------------------------------------------------------------- // End of Standard Mode return; //-------------------------------------------------------------------------- COMMAND_MODE: #define GFX_HI 0x10000 // reject illegal blits and adjust parameters if (command) { if (h > 8) return; if (y >= 0xf8) { y -= 0xf8; flags |= SY_HIGH; } else if (y >= 8) return; if (command != TILEPASS1) { h <<= 5; y <<= 5; } } // calculate entry points and loop constants if (flags & S1_IDLE) src_dx = 0; else src_dx = 1; if (flags & S1_REV ) src_dx = -src_dx; src_base = state->m_gfx1_base + bank; if (command == STARPASS1 || command == STARPASS2) layer = (layer & 1) + 4; dst_base = state->m_render_layer[layer]; //-------------------------------------------------------------------------- #define WARP_WIPE_COMMON { \ ebx = y + h; \ ecx = (x + w - SCREEN_WIDTH) << 1; \ for (edx=y; edx 0) { memset(dst_ptr, 0, ecx); eax = SCREEN_WIDTH - x; } else eax = w; \ memset(dst_ptr+x, 0, eax<<1); \ } \ } //-------------------------------------------------------------------------- // specialized block wipe if ((flags & (IGNORE_0 | COLOR_ON)) == 0) { // wipe star layer when the following conditions are met: if (!command && y == 0xff && h == 1) { y = 0; h = SCREEN_HEIGHT; dst_base = state->m_render_layer[(layer&1)+4]; WARP_WIPE_COMMON state->m_stars_enabled = ~layer & 1; } // wipe background and chain-wipe corresponding sprite layer when the command is zero else { WARP_WIPE_COMMON if (!command) { dst_base = state->m_render_layer[layer&1]; WARP_WIPE_COMMON } } } else //-------------------------------------------------------------------------- // gray shaded star map with 16x16 cells if (command == STARPASS1 && flags & COLOR_ON) { /* Each star map is generated by two data sets pointed by the second source address. The first 256-byte set has scattered bits to reflect the star population while the second 256-byte set appears to have random values. When the game runs the the star fields are updated a small portion at a time by a third data set containing gradient patterns which may indicate gray shades or alpha levels. Halley's Comet draws and clears the two star fields as if they are independent from the backgrounds, making it a total of four scrollable layers. However, only two pairs of scroll registers are in use and they affect the stars and the backgrounds together - possibly afterthoughts on the original Ben Bero Beh hardware. This algorithm is based on speculation and deemed inaccurate. */ #define RORB(R,N) ( ((R>>N)|(R<<(8-N))) & 0xff ) #define C2S(X,Y,O) ( (((Y+(O>>4))&YMASK)<m_stars_enabled = layer & 1; #undef RORB #undef C2S } else //-------------------------------------------------------------------------- // stars color modifier if (command == STARPASS2 && flags & COLOR_ON) { edx = SCREEN_WIDTH - x - w; w = -w; ax = (UINT16)(~src_base[src2] & 0xff); for (yclip=y+h; y 0xf8) return; if (code & PLANE) return; /* WARNING: UNEMULATED */ if (flags & IGNORE_0) { w=8; h=8; WARP_WIPE_COMMON } src1_ptr = src_base + src1; dst_ptr = state->m_render_layer[2] + (y << SCREEN_WIDTH_L2); src1_ptr += 8; edx = -8; if (x <= 0xf8) { dst_ptr += x; do { ax = (UINT16)src1_ptr[edx]; al = src1_ptr[edx+0x10000]; ax |= BG_RGB; if (al & 0x01) *dst_ptr = ax; if (al & 0x02) dst_ptr[1] = ax; if (al & 0x04) dst_ptr[2] = ax; if (al & 0x08) dst_ptr[3] = ax; if (al & 0x10) dst_ptr[4] = ax; if (al & 0x20) dst_ptr[5] = ax; if (al & 0x40) dst_ptr[6] = ax; if (al & 0x80) dst_ptr[7] = ax; dst_ptr += SCREEN_WIDTH; } while (++edx); } else { #define WARPMASK ((SCREEN_WIDTH<<1)-1) do { ecx = x & WARPMASK; ax = (UINT16)src1_ptr[edx]; al = src1_ptr[edx+0x10000]; ax |= BG_RGB; if (al & 0x01) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x02) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x04) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x08) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x10) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x20) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x40) dst_ptr[ecx] = ax; ecx++; ecx &= WARPMASK; if (al & 0x80) dst_ptr[ecx] = ax; dst_ptr += SCREEN_WIDTH; } while (++edx); #undef WARPMASK } } else //-------------------------------------------------------------------------- // RGB horizontal bar(foreground only) if (command == HORIZBAR && flags & COLOR_ON && !(layer & 1)) { #define WARP_LINE_COMMON { \ if (ecx & 1) { ecx--; *dst_ptr = (UINT16)eax; dst_ptr++; } \ dst_ptr += ecx; ecx = -ecx; \ while (ecx) { *(UINT32*)(dst_ptr+ecx) = eax; ecx += 2; } \ } src1_ptr = src_base + src1; src2_ptr = src_base + src2; hclip = y + h; if (!(flags & S2_IDLE)) { // double source mode src2_ptr += GFX_HI; wclip = x + w; w = 32; } else { // single source mode if (color & 4) src1_ptr += GFX_HI; wclip = 32; } for (xclip=x; xclip 0) { ecx = edx; dst_ptr = (UINT16*)edi; WARP_LINE_COMMON ecx = SCREEN_WIDTH - xclip; } else ecx = w; dst_ptr = (UINT16*)edi + xclip; WARP_LINE_COMMON } edi = src1_ptr; src1_ptr = src2_ptr; src2_ptr = (UINT8*)edi; } #undef WARP_LINE_COMMON } //-------------------------------------------------------------------------- } // end of blit() // draws Ben Bero Beh's color backdrop(verification required) static WRITE8_HANDLER( bgtile_w ) { halleys_state *state = space->machine().driver_data(); int yskip, xskip, ecx; UINT16 *edi; UINT16 ax; state->m_cpu1_base[0x1f00+offset] = data; offset -= 0x18; if (offset >= 191) return; yskip = offset / 48; xskip = offset % 48; if (xskip > 43) return; yskip = yskip * 48 + 24; xskip = xskip * 5 + 2; edi = state->m_render_layer[2] + (yskip<machine().driver_data(); if (state->m_game_id==GAME_HALLEYS && cpu_get_pc(&space->device())==0x8017) return(0x55); // HACK: trick SRAM test on startup return(0); } static READ8_HANDLER( blitter_r ) { halleys_state *state = space->machine().driver_data(); int i = offset & 0xf; if (i==0 || i==4) return(1); return(state->m_blitter_ram[offset]); } static TIMER_CALLBACK( blitter_reset ) { halleys_state *state = machine.driver_data(); state->m_blitter_busy = 0; } static WRITE8_HANDLER( blitter_w ) { halleys_state *state = space->machine().driver_data(); int i = offset & 0xf; state->m_blitter_ram[offset] = data; if (i==0) blit(state, offset); if (state->m_game_id == GAME_BENBEROB) { if (i==0 || (i==4 && !data)) { state->m_blitter_busy = 0; if (state->m_firq_level) cputag_set_input_line(space->machine(), "maincpu", M6809_FIRQ_LINE, ASSERT_LINE); // make up delayed FIRQ's } else { state->m_blitter_busy = 1; state->m_blitter_reset_timer->adjust(downcast(&space->device())->cycles_to_attotime(100)); // free blitter if no updates in 100 cycles } } } static READ8_HANDLER( collision_id_r ) { halleys_state *state = space->machine().driver_data(); /* Collision detection abstract: The blitter hardware does per-pixel comparison between two sprite groups. When a collision occurs the ID's(memory offsets/16) of the intersecting pair are written to ff8b(certain) and ff67(?). Then the blitter causes an alternate IRQ to alert the CPU and a second check is performed in software to verify the collision. The trial emulation of the above was painfully slow and inaccurate because collisions are not verified immediately during IRQ. Instead, a dedicated loop is run between game logic and VBLANK to constantly check whether new collision ID's have been reported. The blitter somehow knows to IRQ at the right moment but I couldn't find any clear-cut triggers within the register area. It is possible to bypass blitter-side collision altogether by feeding a redundant sprite list to the main CPU, given that the processor is fast enough. This method works reliably at 5MHz or above and will certainly break under 4MHz. UPDATE: re-implemented pixel collision to accompany the hack method. */ if (state->m_game_id==GAME_HALLEYS && cpu_get_pc(&space->device())==state->m_collision_detection) // HACK: collision detection bypass { if (state->m_collision_count) { state->m_collision_count--; return(state->m_collision_list[state->m_collision_count]); } return(0); } return(state->m_io_ram[0x66]); } //************************************************************************** // Video Initializations and Updates static PALETTE_INIT( halleys ) { halleys_state *state = machine.driver_data(); UINT32 d, r, g, b, i, j, count; UINT32 *pal_ptr = state->m_internal_palette; for (count=0; count<1024; count++) { pal_ptr[count] = 0; palette_set_color(machine, count, MAKE_RGB(0, 0, 0)); } // 00-31: palette RAM(ffc0-ffdf) // 32-63: colors decoded through unknown PROMs // 64-255: unused // 256-1023: palette mirrors // 1024-1279: gray shades for (i=0; i<16; i++) { d = (i<<6&0xc0) | (i<<2&0x30) | (i&0x0c) | (i>>2&0x03) | BG_RGB; for (count=0; count<16; count++) { r = i << 4; g = r + count + BG_MONO; r += i; pal_ptr[g] = d; palette_set_color(machine, g, MAKE_RGB(r, r, r)); } } // 1280-1535: RGB for (d=0; d<256; d++) { j = d + BG_RGB; pal_ptr[j] = j; i = d>>6 & 0x03; r = d>>2 & 0x0c; r |= i; g = d & 0x0c; g |= i; b = d<<2 & 0x0c; b |= i; palette_set_color_rgb(machine, j, pal4bit(r), pal4bit(g), pal4bit(b)); } } static void halleys_decode_rgb(running_machine &machine, UINT32 *r, UINT32 *g, UINT32 *b, int addr, int data) { /* proms contain: 00 00 00 00 c5 0b f3 17 fd cf 1f ef df bf 7f ff 00 00 00 00 01 61 29 26 0b f5 e2 17 57 fb cf f7 */ int latch1_273, latch2_273; UINT8 *sram_189; UINT8 *prom_6330; int bit0, bit1, bit2, bit3, bit4; // the four 16x4-bit SN74S189 SRAM chips are assumed be the game's 32-byte palette RAM sram_189 = machine.generic.paletteram.u8; // each of the three 32-byte 6330 PROM is wired to an RGB component output prom_6330 = machine.region("proms")->base(); // latch1 holds 8 bits from the selected palette RAM address latch1_273 = sram_189[addr]; // latch2 holds another 8 bits from somewhere on the data bus in a bit-swapped manner(inaccurate) latch2_273 = (data>>4 & 0x0f)|(data<<1 & 0x10)|(data<<3 & 0x20)|(data<<5 & 0x40)|(data<<7 & 0x80); // data from latch1 and 2 are combined and then decoded through PROMs to form three 8-bit tripplets bit0 = latch1_273>>5 & 0x01; bit1 = latch1_273>>3 & 0x02; bit2 = latch1_273>>5 & 0x04; bit3 = latch1_273>>3 & 0x08; bit4 = latch2_273>>2 & 0x10; *r = prom_6330[0x00 + (bit0|bit1|bit2|bit3|bit4)]; bit2 = latch1_273>>0 & 0x04; bit3 = latch1_273>>0 & 0x08; bit4 = latch2_273>>3 & 0x10; *g = prom_6330[0x20 + (bit0|bit1|bit2|bit3|bit4)]; bit2 = latch1_273<<2 & 0x04; bit3 = latch1_273<<2 & 0x08; bit4 = latch2_273<<1 & 0x10; *b = prom_6330[0x40 + (bit0|bit1|bit2|bit3|bit4)]; } static WRITE8_HANDLER( halleys_paletteram_IIRRGGBB_w ) { halleys_state *state = space->machine().driver_data(); UINT32 d, r, g, b, i, j; UINT32 *pal_ptr = state->m_internal_palette; space->machine().generic.paletteram.u8[offset] = data; d = (UINT32)data; j = d | BG_RGB; pal_ptr[offset] = j; pal_ptr[offset+SP_2BACK] = j; pal_ptr[offset+SP_ALPHA] = j; pal_ptr[offset+SP_COLLD] = j; // 8-bit RGB format: IIRRGGBB i = d>>6 & 0x03; r = d>>2 & 0x0c; r |= i; r = r<<4 | r; g = d & 0x0c; g |= i; g = g<<4 | g; b = d<<2 & 0x0c; b |= i; b = b<<4 | b; palette_set_color(space->machine(), offset, MAKE_RGB(r, g, b)); palette_set_color(space->machine(), offset+SP_2BACK, MAKE_RGB(r, g, b)); palette_set_color(space->machine(), offset+SP_ALPHA, MAKE_RGB(r, g, b)); palette_set_color(space->machine(), offset+SP_COLLD, MAKE_RGB(r, g, b)); halleys_decode_rgb(space->machine(), &r, &g, &b, offset, 0); palette_set_color(space->machine(), offset+0x20, MAKE_RGB(r, g, b)); } static VIDEO_START( halleys ) { halleys_state *state = machine.driver_data(); #define HALLEYS_Y0 0x8e #define HALLEYS_X0 0x9a #define HALLEYS_Y1 0xa2 #define HALLEYS_X1 0xa3 int dst, src, c; // create short cuts to scroll registers state->m_scrolly0 = state->m_io_ram + HALLEYS_Y0; state->m_scrollx0 = state->m_io_ram + HALLEYS_X0; state->m_scrolly1 = state->m_io_ram + HALLEYS_Y1; state->m_scrollx1 = state->m_io_ram + HALLEYS_X1; // fill alpha table for (src=0; src<256; src++) for (dst=0; dst<256; dst++) { c = (((src&0xc0)+(dst&0xc0))>>1) & 0xc0; c += (((src&0x30)+(dst&0x30))>>1) & 0x30; c += (((src&0x0c)+(dst&0x0c))>>1) & 0x0c; c += (((src&0x03)+(dst&0x03))>>1) & 0x03; state->m_alpha_table[(src<<8)+dst] = c | BG_RGB; } } static void copy_scroll_op(bitmap_t *bitmap, UINT16 *source, int sx, int sy) { //-------------------------------------------------------------------------- #define OPCOPY_COMMON { \ memcpy(edi, esi+sx, rcw); \ memcpy((UINT8*)edi+rcw, esi, CLIP_BYTEW-rcw); \ esi += SCREEN_WIDTH; \ edi += edx; } //-------------------------------------------------------------------------- UINT16 *esi, *edi; int rcw, bch, ecx, edx; sx = -sx & 0xff; sy = -sy & 0xff; if ((rcw = CLIP_W - sx) < 0) rcw = 0; else rcw <<= 1; if ((bch = CLIP_H - sy) < 0) bch = 0; esi = source + CLIP_SKIP + (sy << SCREEN_WIDTH_L2); edi = BITMAP_ADDR16(bitmap, VIS_MINY, VIS_MINX); edx = bitmap->rowpixels; // draw top split for (ecx=bch; ecx; ecx--) OPCOPY_COMMON esi = source + CLIP_SKIP; // draw bottom split for (ecx=CLIP_H-bch; ecx; ecx--) OPCOPY_COMMON #undef OPCOPY_COMMON } static void copy_scroll_xp(bitmap_t *bitmap, UINT16 *source, int sx, int sy) { //-------------------------------------------------------------------------- #define XCOPY_COMMON \ if (ecx) { \ if (ecx & 1) { ecx--; ax = *esi; esi++; if (ax) *edi = ax; edi++; } \ esi += ecx; edi += ecx; ecx = -ecx; \ while (ecx) { \ ax = esi[ecx]; \ bx = esi[ecx+1]; \ if (ax) edi[ecx] = ax; \ if (bx) edi[ecx+1] = bx; \ ecx += 2; \ } \ } //-------------------------------------------------------------------------- #define YCOPY_COMMON { \ esi = src_base + sx; ecx = rcw; XCOPY_COMMON \ esi = src_base; ecx = CLIP_W - rcw; XCOPY_COMMON \ src_base += SCREEN_WIDTH; \ edi += dst_adv; \ } //-------------------------------------------------------------------------- int rcw, bch, dst_adv; UINT16 *src_base, *esi, *edi; int ecx, edx; UINT16 ax, bx; sx = -sx & 0xff; sy = -sy & 0xff; if ((rcw = CLIP_W - sx) < 0) rcw = 0; if ((bch = CLIP_H - sy) < 0) bch = 0; src_base = source + CLIP_SKIP + (sy << SCREEN_WIDTH_L2); edi = BITMAP_ADDR16(bitmap, VIS_MINY, VIS_MINX); dst_adv = bitmap->rowpixels - CLIP_W; // draw top split for (edx=bch; edx; edx--) YCOPY_COMMON src_base = source + CLIP_SKIP; // draw bottom split for (edx=CLIP_H-bch; edx; edx--) YCOPY_COMMON #undef XCOPY_COMMON #undef YCOPY_COMMON } static void copy_fixed_xp(bitmap_t *bitmap, UINT16 *source) { UINT16 *esi, *edi; int dst_pitch, ecx, edx; UINT16 ax, bx; esi = source + CLIP_SKIP + CLIP_W; edi = BITMAP_ADDR16(bitmap, VIS_MINY, VIS_MINX + CLIP_W); dst_pitch = bitmap->rowpixels; ecx = -CLIP_W; edx = CLIP_H; do { do { ax = esi[ecx]; bx = esi[ecx+1]; if (ax) edi[ecx ] = ax; ax = esi[ecx+2]; if (bx) edi[ecx+1] = bx; bx = esi[ecx+3]; if (ax) edi[ecx+2] = ax; ax = esi[ecx+4]; if (bx) edi[ecx+3] = bx; bx = esi[ecx+5]; if (ax) edi[ecx+4] = ax; ax = esi[ecx+6]; if (bx) edi[ecx+5] = bx; bx = esi[ecx+7]; if (ax) edi[ecx+6] = ax; if (bx) edi[ecx+7] = bx; } while (ecx += 8); ecx = -CLIP_W; esi += SCREEN_WIDTH; edi += dst_pitch; } while (--edx); } static void copy_fixed_2b(bitmap_t *bitmap, UINT16 *source) { UINT16 *esi, *edi; int dst_pitch, ecx, edx; UINT16 ax, bx; esi = source + CLIP_SKIP + CLIP_W; edi = BITMAP_ADDR16(bitmap, VIS_MINY, VIS_MINX + CLIP_W); dst_pitch = bitmap->rowpixels; ecx = -CLIP_W; edx = CLIP_H; do { do { ax = esi[ecx]; bx = esi[ecx+1]; if (!(ax)) goto SKIP0; if (!(ax&SP_2BACK)) goto DRAW0; if (edi[ecx ]) goto SKIP0; DRAW0: edi[ecx ] = ax; SKIP0: ax = esi[ecx+2]; if (!(bx)) goto SKIP1; if (!(bx&SP_2BACK)) goto DRAW1; if (edi[ecx+1]) goto SKIP1; DRAW1: edi[ecx+1] = bx; SKIP1: bx = esi[ecx+3]; if (!(ax)) goto SKIP2; if (!(ax&SP_2BACK)) goto DRAW2; if (edi[ecx+2]) goto SKIP2; DRAW2: edi[ecx+2] = ax; SKIP2: ax = esi[ecx+4]; if (!(bx)) goto SKIP3; if (!(bx&SP_2BACK)) goto DRAW3; if (edi[ecx+3]) goto SKIP3; DRAW3: edi[ecx+3] = bx; SKIP3: bx = esi[ecx+5]; if (!(ax)) goto SKIP4; if (!(ax&SP_2BACK)) goto DRAW4; if (edi[ecx+4]) goto SKIP4; DRAW4: edi[ecx+4] = ax; SKIP4: ax = esi[ecx+6]; if (!(bx)) goto SKIP5; if (!(bx&SP_2BACK)) goto DRAW5; if (edi[ecx+5]) goto SKIP5; DRAW5: edi[ecx+5] = bx; SKIP5: bx = esi[ecx+7]; if (!(ax)) goto SKIP6; if (!(ax&SP_2BACK)) goto DRAW6; if (edi[ecx+6]) goto SKIP6; DRAW6: edi[ecx+6] = ax; SKIP6: if (!(bx)) continue; if (!(bx&SP_2BACK)) goto DRAW7; if (edi[ecx+7]) continue; DRAW7: edi[ecx+7] = bx; } while (ecx += 8); ecx = -CLIP_W; esi += SCREEN_WIDTH; edi += dst_pitch; } while (--edx); } static void filter_bitmap(running_machine &machine, bitmap_t *bitmap, int mask) { halleys_state *state = machine.driver_data(); int dst_pitch; UINT32 *pal_ptr, *edi; int esi, eax, ebx, ecx, edx; pal_ptr = state->m_internal_palette; esi = mask | 0xffffff00; edi = (UINT32*)BITMAP_ADDR16(bitmap, VIS_MINY, VIS_MINX + CLIP_W); dst_pitch = bitmap->rowpixels >> 1; ecx = -(CLIP_W>>1); edx = CLIP_H; do { do { eax = edi[ecx]; if (eax & 0x00ff00ff) { ebx = eax; eax >>= 16; ebx &= 0xffff; eax = pal_ptr[eax]; ebx = pal_ptr[ebx]; eax &= esi; ebx &= esi; eax <<= 16; ebx |= eax; edi[ecx] = ebx; } } while (++ecx); ecx = -(CLIP_W>>1); edi += dst_pitch; } while (--edx); } static SCREEN_UPDATE( halleys ) { halleys_state *state = screen->machine().driver_data(); int i, j; if (state->m_stars_enabled) { copy_scroll_op(bitmap, state->m_render_layer[5], *state->m_scrollx0, *state->m_scrolly0); copy_scroll_xp(bitmap, state->m_render_layer[4], *state->m_scrollx1, *state->m_scrolly1); } else bitmap_fill(bitmap, cliprect, state->m_bgcolor); #ifdef MAME_DEBUG if (input_port_read(screen->machine(), "DEBUG")) copy_scroll_xp(bitmap, state->m_render_layer[3], *state->m_scrollx0, *state->m_scrolly0); // not used??? #endif copy_scroll_xp(bitmap, state->m_render_layer[2], *state->m_scrollx1, *state->m_scrolly1); copy_fixed_2b (bitmap, state->m_render_layer[1]); copy_fixed_xp (bitmap, state->m_render_layer[0]); // HALF-HACK: apply RGB filter when the following conditions are met i = state->m_io_ram[0xa0]; j = state->m_io_ram[0xa1]; if (state->m_io_ram[0x2b] && (i>0xc6 && i<0xfe) && (j==0xc0 || j==0xed)) filter_bitmap(screen->machine(), bitmap, i); return 0; } static SCREEN_UPDATE( benberob ) { halleys_state *state = screen->machine().driver_data(); if (state->m_io_ram[0xa0] & 0x80) copy_scroll_op(bitmap, state->m_render_layer[2], *state->m_scrollx1, *state->m_scrolly1); else bitmap_fill(bitmap, cliprect, state->m_bgcolor); copy_fixed_xp (bitmap, state->m_render_layer[1]); copy_fixed_xp (bitmap, state->m_render_layer[0]); return 0; } //************************************************************************** // Debug and Test Handlers #if HALLEYS_DEBUG static READ8_HANDLER( zero_r ) { return(0); } static READ8_HANDLER( debug_r ) { halleys_state *state = space->machine().driver_data(); return(state->m_io_ram[offset]); } #endif //************************************************************************** // Interrupt and Hardware Handlers static TIMER_DEVICE_CALLBACK( halleys_scanline ) { halleys_state *state = timer.machine().driver_data(); int scanline = param; /* TODO: fix this */ switch (scanline) { case 248: // clear collision list of this frame unconditionally state->m_collision_count = 0; break; // In Halley's Comet, NMI is used exclusively to handle coin input case 56*3: cputag_set_input_line(timer.machine(),"maincpu", INPUT_LINE_NMI, PULSE_LINE); break; // FIRQ drives gameplay; we need both types of NMI each frame. case 56*2: state->m_mVectorType = 1; cputag_set_input_line(timer.machine(),"maincpu", M6809_FIRQ_LINE, ASSERT_LINE); break; case 56: state->m_mVectorType = 0; cputag_set_input_line(timer.machine(),"maincpu", M6809_FIRQ_LINE, ASSERT_LINE); break; } } static TIMER_DEVICE_CALLBACK( benberob_scanline ) { halleys_state *state = timer.machine().driver_data(); int scanline = param; /* TODO: fix this */ switch (scanline) { case 248: break; case 56*3: cputag_set_input_line(timer.machine(),"maincpu", INPUT_LINE_NMI, PULSE_LINE); break; case 56*2: case 56*1: // FIRQ must not happen when the blitter is being updated or it'll cause serious screen artifacts if (!state->m_blitter_busy) cputag_set_input_line(timer.machine(),"maincpu", M6809_FIRQ_LINE, ASSERT_LINE); else state->m_firq_level++; break; } } static READ8_HANDLER( vector_r ) { halleys_state *state = space->machine().driver_data(); return(state->m_cpu1_base[0xffe0 + (offset^(state->m_mVectorType<<4))]); } static WRITE8_HANDLER( firq_ack_w ) { halleys_state *state = space->machine().driver_data(); state->m_io_ram[0x9c] = data; if (state->m_firq_level) state->m_firq_level--; cputag_set_input_line(space->machine(), "maincpu", M6809_FIRQ_LINE, CLEAR_LINE); } static WRITE8_DEVICE_HANDLER( sndnmi_msk_w ) { halleys_state *state = device->machine().driver_data(); state->m_sndnmi_mask = data & 1; } static WRITE8_HANDLER( soundcommand_w ) { halleys_state *state = space->machine().driver_data(); state->m_io_ram[0x8a] = data; soundlatch_w(space,offset,data); cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_NMI, PULSE_LINE); } static READ8_HANDLER( coin_lockout_r ) { // This is a hack, but it lets you coin up when COIN1 or COIN2 are signaled. // See NMI for the twisted logic that is involved in handling coin input : // 0x8599 : 'benberob' // 0x83e2 : 'halleys', 'halleysc', 'halleycj' // 0x83df : 'halley87' int inp = input_port_read(space->machine(), "IN0"); int result = ((input_port_read(space->machine(), "DSW4")) & 0x20) >> 5; if (inp & 0x80) result |= 0x02; if (inp & 0x40) result |= 0x04; return(result); } static READ8_HANDLER( io_mirror_r ) { static const char *const portnames[] = { "IN0", "IN1", "IN2", "IN3" }; return input_port_read(space->machine(), portnames[offset]); } //************************************************************************** // Memory Maps static ADDRESS_MAP_START( halleys_map, AS_PROGRAM, 8 ) AM_RANGE(0x0000, 0x0fff) AM_READWRITE(blitter_r, blitter_w) AM_BASE_MEMBER(halleys_state, m_blitter_ram) AM_SIZE_MEMBER(halleys_state, m_blitter_ramsize) AM_RANGE(0x1f00, 0x1fff) AM_WRITE(bgtile_w) // background tiles?(Ben Bero Beh only) AM_RANGE(0x1000, 0xefff) AM_ROM AM_RANGE(0xf000, 0xfeff) AM_RAM // work ram AM_RANGE(0xff66, 0xff66) AM_READ(collision_id_r) // HACK: collision detection bypass(Halley's Comet only) AM_RANGE(0xff71, 0xff71) AM_READ(blitter_status_r) AM_RANGE(0xff80, 0xff83) AM_READ(io_mirror_r) AM_RANGE(0xff8a, 0xff8a) AM_WRITE(soundcommand_w) AM_RANGE(0xff90, 0xff90) AM_READ_PORT("IN0") // coin/start AM_RANGE(0xff91, 0xff91) AM_READ_PORT("IN1") // player 1 AM_RANGE(0xff92, 0xff92) AM_READ_PORT("IN2") // player 2 AM_RANGE(0xff93, 0xff93) AM_READ_PORT("IN3") // unused? AM_RANGE(0xff94, 0xff94) AM_READ(coin_lockout_r) AM_RANGE(0xff95, 0xff95) AM_READ_PORT("DSW1") // dipswitch 4 AM_RANGE(0xff96, 0xff96) AM_READ_PORT("DSW2") // dipswitch 3 AM_RANGE(0xff97, 0xff97) AM_READ_PORT("DSW3") // dipswitch 2 AM_RANGE(0xff9c, 0xff9c) AM_WRITE(firq_ack_w) AM_RANGE(0xff00, 0xffbf) AM_RAM AM_BASE_MEMBER(halleys_state, m_io_ram) AM_SIZE_MEMBER(halleys_state, m_io_ramsize) // I/O write fall-through AM_RANGE(0xffc0, 0xffdf) AM_RAM_WRITE(halleys_paletteram_IIRRGGBB_w) AM_BASE_GENERIC(paletteram) AM_RANGE(0xffe0, 0xffff) AM_READ(vector_r) ADDRESS_MAP_END static ADDRESS_MAP_START( sound_map, AS_PROGRAM, 8 ) AM_RANGE(0x0000, 0x3fff) AM_ROM AM_RANGE(0x4000, 0x47ff) AM_RAM AM_RANGE(0x4800, 0x4801) AM_DEVWRITE("ay2", ay8910_address_data_w) AM_RANGE(0x4801, 0x4801) AM_DEVREAD("ay2", ay8910_r) AM_RANGE(0x4802, 0x4803) AM_DEVWRITE("ay3", ay8910_address_data_w) AM_RANGE(0x4803, 0x4803) AM_DEVREAD("ay3", ay8910_r) AM_RANGE(0x4804, 0x4805) AM_DEVWRITE("ay4", ay8910_address_data_w) AM_RANGE(0x4805, 0x4805) AM_DEVREAD("ay4", ay8910_r) AM_RANGE(0x5000, 0x5000) AM_READ(soundlatch_r) AM_RANGE(0xe000, 0xefff) AM_ROM // space for diagnostic ROM ADDRESS_MAP_END //************************************************************************** // Port Maps static INPUT_PORTS_START( benberob ) PORT_START("DSW1") /* 0xff95 */ PORT_DIPNAME( 0x03, 0x03, DEF_STR( Bonus_Life ) ) /* code at 0xb00e */ PORT_DIPSETTING( 0x02, "Every 100k" ) PORT_DIPSETTING( 0x03, "100k 300k 200k+" ) PORT_DIPSETTING( 0x00, "100k 200k" ) PORT_DIPSETTING( 0x01, "150k 300k" ) PORT_DIPNAME( 0x04, 0x04, DEF_STR( Free_Play ) ) PORT_DIPSETTING( 0x04, DEF_STR( No ) ) PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) PORT_DIPNAME( 0x18, 0x08, DEF_STR( Lives ) ) PORT_DIPSETTING( 0x08, "3" ) PORT_DIPSETTING( 0x10, "4" ) PORT_DIPSETTING( 0x18, "5" ) PORT_DIPSETTING( 0x00, DEF_STR( Infinite ) ) PORT_DIPUNKNOWN( 0x20, IP_ACTIVE_LOW ) PORT_DIPNAME( 0x40, 0x40, DEF_STR( Flip_Screen ) ) /* TO DO : confirm OFF/ON when screen flipping emulated */ PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x80, 0x80, DEF_STR( Cabinet ) ) PORT_DIPSETTING( 0x80, DEF_STR( Upright ) ) PORT_DIPSETTING( 0x00, DEF_STR( Cocktail ) ) PORT_START("DSW2") /* 0xff96 */ PORT_DIPNAME( 0x0f, 0x00, DEF_STR( Coin_A ) ) PORT_DIPSETTING( 0x0f, DEF_STR( 9C_1C ) ) PORT_DIPSETTING( 0x0e, DEF_STR( 8C_1C ) ) PORT_DIPSETTING( 0x0d, DEF_STR( 7C_1C ) ) PORT_DIPSETTING( 0x0c, DEF_STR( 6C_1C ) ) PORT_DIPSETTING( 0x0b, DEF_STR( 5C_1C ) ) PORT_DIPSETTING( 0x0a, DEF_STR( 4C_1C ) ) PORT_DIPSETTING( 0x09, DEF_STR( 3C_1C ) ) PORT_DIPSETTING( 0x08, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ) ) PORT_DIPSETTING( 0x02, DEF_STR( 1C_3C ) ) PORT_DIPSETTING( 0x03, DEF_STR( 1C_4C ) ) PORT_DIPSETTING( 0x04, DEF_STR( 1C_5C ) ) PORT_DIPSETTING( 0x05, DEF_STR( 1C_6C ) ) PORT_DIPSETTING( 0x06, DEF_STR( 1C_7C ) ) PORT_DIPSETTING( 0x07, DEF_STR( 1C_8C ) ) PORT_DIPNAME( 0xf0, 0x00, DEF_STR( Coin_B ) ) PORT_DIPSETTING( 0xf0, DEF_STR( 9C_1C ) ) PORT_DIPSETTING( 0xe0, DEF_STR( 8C_1C ) ) PORT_DIPSETTING( 0xd0, DEF_STR( 7C_1C ) ) PORT_DIPSETTING( 0xc0, DEF_STR( 6C_1C ) ) PORT_DIPSETTING( 0xb0, DEF_STR( 5C_1C ) ) PORT_DIPSETTING( 0xa0, DEF_STR( 4C_1C ) ) PORT_DIPSETTING( 0x90, DEF_STR( 3C_1C ) ) PORT_DIPSETTING( 0x80, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x10, DEF_STR( 1C_2C ) ) PORT_DIPSETTING( 0x20, DEF_STR( 1C_3C ) ) PORT_DIPSETTING( 0x30, DEF_STR( 1C_4C ) ) PORT_DIPSETTING( 0x40, DEF_STR( 1C_5C ) ) PORT_DIPSETTING( 0x50, DEF_STR( 1C_6C ) ) PORT_DIPSETTING( 0x60, DEF_STR( 1C_7C ) ) PORT_DIPSETTING( 0x70, DEF_STR( 1C_8C ) ) PORT_START("DSW3") /* 0xff97 */ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Difficulty ) ) PORT_DIPSETTING( 0x01, DEF_STR( Easy ) ) PORT_DIPSETTING( 0x00, DEF_STR( Hard ) ) PORT_DIPNAME( 0x02, 0x00, "Use Both Buttons" ) PORT_DIPSETTING( 0x02, DEF_STR( No ) ) PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) PORT_DIPNAME( 0x0c, 0x0c, "Timer Speed" ) /* table at 0xb10e */ PORT_DIPSETTING( 0x0c, "Slowest" ) PORT_DIPSETTING( 0x08, "Slow" ) PORT_DIPSETTING( 0x04, "Fast" ) PORT_DIPSETTING( 0x00, "Fastest" ) PORT_DIPNAME( 0x10, 0x10, "Show Coinage" ) PORT_DIPSETTING( 0x00, DEF_STR( No ) ) PORT_DIPSETTING( 0x10, DEF_STR( Yes ) ) PORT_DIPNAME( 0x20, 0x20, "Show Year" ) PORT_DIPSETTING( 0x00, DEF_STR( No ) ) PORT_DIPSETTING( 0x20, DEF_STR( Yes ) ) PORT_DIPNAME( 0x40, 0x40, "No Hit" ) PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x80, 0x80, "Maximum Credits" ) PORT_DIPSETTING( 0x80, "9" ) PORT_DIPSETTING( 0x00, "16" ) PORT_START("DSW4") /* 0xff94 - read by coin_lockout_r */ PORT_DIPUNUSED( 0x01, IP_ACTIVE_LOW ) PORT_DIPUNUSED( 0x02, IP_ACTIVE_LOW ) PORT_DIPUNUSED( 0x04, IP_ACTIVE_LOW ) PORT_DIPUNUSED( 0x08, IP_ACTIVE_LOW ) PORT_DIPUNUSED( 0x10, IP_ACTIVE_LOW ) PORT_DIPNAME( 0x20, 0x20, "Coin Slots" ) PORT_DIPSETTING( 0x00, "1" ) PORT_DIPSETTING( 0x20, "2" ) PORT_DIPUNUSED( 0x40, IP_ACTIVE_LOW ) PORT_DIPUNUSED( 0x80, IP_ACTIVE_LOW ) PORT_START("IN0") /* 0xff90 */ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 ) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START2 ) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_TILT ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_IMPULSE(12) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_COIN2 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_START("IN1") /* 0xff91 */ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_START("IN2") /* 0xff92 */ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL PORT_START("IN3") /* 0xff93 */ INPUT_PORTS_END static INPUT_PORTS_START( halleys ) PORT_START("DSW1") /* 0xff95 */ TAITO_MACHINE_COCKTAIL_LOC(SW4) TAITO_COINAGE_JAPAN_OLD_LOC(SW4) PORT_START("DSW2") /* 0xff96 */ TAITO_DIFFICULTY_LOC(SW3) PORT_DIPNAME( 0x0c, 0x0c, DEF_STR( Bonus_Life ) ) PORT_DIPLOCATION("SW3:3,4") /* index of tables at 0x1a2f or 0x19b5 */ PORT_DIPSETTING( 0x00, "100k 600k 500k+" ) /* last bonus life at 5600k : max. 12 bonus lives */ PORT_DIPSETTING( 0x0c, "200k 800k 600k+" ) /* last bonus life at 6800k : max. 12 bonus lives */ PORT_DIPSETTING( 0x08, "200k 1000k 800k+" ) /* last bonus life at 9000k : max. 12 bonus lives */ PORT_DIPSETTING( 0x04, "200k 1200k 1000k+" ) /* last bonus life at 9200k : max. 10 bonus lives */ PORT_DIPNAME( 0x30, 0x30, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW3:5,6") PORT_DIPSETTING( 0x20, "2" ) PORT_DIPSETTING( 0x30, "3" ) PORT_DIPSETTING( 0x10, "4" ) PORT_DIPSETTING( 0x00, "4 (No Points Bonus Lives)" ) /* code at 0xa509 or 0xa502 - 3 in the US manual */ PORT_DIPNAME( 0x40, 0x40, "Operation Data Recorder" ) PORT_DIPLOCATION("SW3:7") /* from the US manual - what is this ? */ PORT_DIPSETTING( 0x40, "Not fixed" ) PORT_DIPSETTING( 0x00, "When fixed" ) PORT_DIPUNUSED_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW3:8" ) /* From US manual : "DIP SW 2 is not used and all contacts should be set off." However, they enable debug features if you press START1 during the boot sequence. */ PORT_START("DSW3") /* 0xff97 */ PORT_DIPUNUSED_DIPLOC( 0x01, IP_ACTIVE_LOW, "SW2:1" ) PORT_DIPNAME( 0x02, 0x02, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW2:2") PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x1c, 0x1c, "Start Area" ) PORT_DIPLOCATION("SW2:3,4,5") PORT_DIPSETTING( 0x1c, "1 (Earth)" ) PORT_DIPSETTING( 0x18, "4 (Venus)" ) PORT_DIPSETTING( 0x14, "7 (Mercury)" ) PORT_DIPSETTING( 0x10, "10 (Sun)" ) PORT_DIPSETTING( 0x0c, "13 (Pluto)" ) /* spelled "Plato" */ PORT_DIPSETTING( 0x08, "16 (Neptune)" ) PORT_DIPSETTING( 0x04, "19 (Uranus)" ) PORT_DIPSETTING( 0x00, "22 (Saturn)" ) PORT_DIPUNUSED_DIPLOC( 0x20, IP_ACTIVE_LOW, "SW2:6" ) PORT_DIPNAME( 0x40, 0x40, "Invincibility") PORT_DIPLOCATION("SW2:7") PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x80, 0x80, "Infinite Lives" ) PORT_DIPLOCATION("SW2:8") PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) /* From US manual : "Coin mechs system can be optioned by setting DIP SW 1. Position 6 on for single coin selector. Position 6 off for twin coin selector." */ PORT_START("DSW4") /* 0xff94 - read by coin_lockout_r */ PORT_DIPUNUSED_DIPLOC( 0x01, IP_ACTIVE_LOW, "SW1:1" ) PORT_DIPUNUSED_DIPLOC( 0x02, IP_ACTIVE_LOW, "SW1:2" ) PORT_DIPUNUSED_DIPLOC( 0x04, IP_ACTIVE_LOW, "SW1:3" ) PORT_DIPUNUSED_DIPLOC( 0x08, IP_ACTIVE_LOW, "SW1:4" ) PORT_DIPUNUSED_DIPLOC( 0x10, IP_ACTIVE_LOW, "SW1:5" ) PORT_DIPNAME( 0x20, 0x20, "Coin Slots" ) PORT_DIPLOCATION("SW1:6") PORT_DIPSETTING( 0x00, "1" ) PORT_DIPSETTING( 0x20, "2" ) PORT_DIPUNUSED_DIPLOC( 0x40, IP_ACTIVE_LOW, "SW1:7" ) PORT_DIPUNUSED_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW1:8" ) PORT_START("IN0") /* 0xff90 */ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 ) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START2 ) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_TILT ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_IMPULSE(12) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_COIN2 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_START("IN1") /* 0xff91 */ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_START("IN2") /* 0xff92 */ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL PORT_START("IN3") /* 0xff93 */ #ifdef MAME_DEBUG PORT_START("DEBUG") /* just to be safe */ PORT_DIPNAME( 0x01, 0x00, "Show Unused Layer" ) PORT_DIPSETTING( 0x00, DEF_STR( No ) ) PORT_DIPSETTING( 0x01, DEF_STR( Yes ) ) #endif INPUT_PORTS_END //************************************************************************** // Machine Definitions and Initializations static MACHINE_RESET( halleys ) { halleys_state *state = machine.driver_data(); state->m_mVectorType = 0; state->m_firq_level = 0; state->m_blitter_busy = 0; state->m_collision_count = 0; state->m_stars_enabled = 0; state->m_bgcolor = get_black_pen(machine); state->m_fftail = state->m_ffhead = state->m_ffcount = 0; memset(state->m_io_ram, 0xff, state->m_io_ramsize); memset(state->m_render_layer[0], 0, SCREEN_BYTESIZE * MAX_LAYERS); } static const ay8910_interface ay8910_config = { AY8910_LEGACY_OUTPUT, AY8910_DEFAULT_LOADS, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(sndnmi_msk_w) // port Bwrite }; static MACHINE_CONFIG_START( halleys, halleys_state ) MCFG_CPU_ADD("maincpu", M6809, XTAL_19_968MHz/12) /* verified on pcb */ MCFG_CPU_PROGRAM_MAP(halleys_map) MCFG_TIMER_ADD_SCANLINE("scantimer", halleys_scanline, "screen", 0, 1) MCFG_CPU_ADD("audiocpu", Z80, XTAL_6MHz/2) /* verified on pcb */ MCFG_CPU_PROGRAM_MAP(sound_map) MCFG_CPU_PERIODIC_INT(irq0_line_hold, (double)6000000/(4*16*16*10*16)) MCFG_MACHINE_RESET(halleys) // video hardware MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(59.50) /* verified on PCB */ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) MCFG_SCREEN_SIZE(SCREEN_WIDTH, SCREEN_HEIGHT) MCFG_SCREEN_VISIBLE_AREA(VIS_MINX, VIS_MAXX, VIS_MINY, VIS_MAXY) MCFG_SCREEN_UPDATE(halleys) MCFG_PALETTE_LENGTH(PALETTE_SIZE) MCFG_PALETTE_INIT(halleys) MCFG_VIDEO_START(halleys) // sound hardware MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("ay1", AY8910, XTAL_6MHz/4) /* verified on pcb */ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) MCFG_SOUND_ADD("ay2", AY8910, XTAL_6MHz/4) /* verified on pcb */ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) MCFG_SOUND_ADD("ay3", AY8910, XTAL_6MHz/4) /* verified on pcb */ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) MCFG_SOUND_ADD("ay4", AY8910, XTAL_6MHz/4) /* verified on pcb */ MCFG_SOUND_CONFIG(ay8910_config) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( benberob, halleys ) MCFG_CPU_MODIFY("maincpu") MCFG_CPU_CLOCK(XTAL_19_968MHz/12) /* not verified but pcb identical to halley's comet */ MCFG_TIMER_MODIFY("scantimer") MCFG_TIMER_CALLBACK(benberob_scanline) MCFG_SCREEN_MODIFY("screen") MCFG_SCREEN_UPDATE(benberob) MACHINE_CONFIG_END //************************************************************************** // ROM Definitions ROM_START( benberob ) ROM_REGION( 0x10000, "maincpu", 0 ) //MAIN PRG ROM_LOAD( "a26_01.31", 0x4000, 0x4000, CRC(9ed566ba) SHA1(15c042e727b00b1dc6f24c72226d1a361fc0fa58) ) ROM_LOAD( "a26_02.52", 0x8000, 0x4000, CRC(a563a033) SHA1(c2c4a73f190303b7101e7849a638d35a80e4c36b) ) ROM_LOAD( "a26_03.50", 0xc000, 0x4000, CRC(975849ef) SHA1(2724c3b7cca724bee5ae8331037529bfd8285011) ) ROM_REGION( 0x10000, "audiocpu", 0 ) //SOUND ROM_LOAD( "a26_12.5", 0x0000, 0x4000, CRC(7fd728f3) SHA1(772c14d9254e43a56f1e67ad4dd5d7840df50e34) ) ROM_REGION( 0x20000, "gfx1", 0 ) //CHR ROM_LOAD( "a26_06.78", 0x00000, 0x4000, CRC(79ae2e58) SHA1(726dbaf01dcb330a8a7bd69578b67ec48db01ae1) ) ROM_LOAD( "a26_07.77", 0x04000, 0x4000, CRC(fe976343) SHA1(68b655d00b1e7e72ab81974b39033f6c130dc829) ) ROM_LOAD( "a26_04.80", 0x08000, 0x4000, CRC(77d10723) SHA1(fd284de30c7740c56e7192e0d73a6939b8386538) ) ROM_LOAD( "a26_05.79", 0x0c000, 0x4000, CRC(098eebcc) SHA1(3dd82d92273b4d1ebbe0f81f6d367c8bc642815f) ) ROM_LOAD( "a26_10.89", 0x10000, 0x4000, CRC(3d406060) SHA1(f02df4957ad7ba59ac14fd0134d856b2a80c9342) ) ROM_LOAD( "a26_11.88", 0x14000, 0x4000, CRC(4561836a) SHA1(6bd582ddb980a1c0b1ed4981118d5a9c862ff89c) ) ROM_LOAD( "a26_08.91", 0x18000, 0x4000, CRC(7e63059d) SHA1(01e1e805fa2e05058ebd83aae95e26879b4a275d) ) ROM_LOAD( "a26_09.90", 0x1c000, 0x4000, CRC(ebd9a16c) SHA1(0230892f451cac310d5ad0d328cea0556b96157f) ) ROM_REGION( 0x0060, "proms", 0 ) //COLOR (all identical!) ROM_LOAD( "a26_13.r", 0x0000, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26_13.g", 0x0020, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26_13.b", 0x0040, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_END ROM_START( halleys ) ROM_REGION( 0x10000, "maincpu", 0 ) //MAIN PRG ROM_LOAD( "a62_01.30", 0x0000, 0x4000, CRC(a5e82b3e) SHA1(c16c6a6c23a579454b8a2be4b951c35b04f2a856) ) ROM_LOAD( "a62_02.31", 0x4000, 0x4000, CRC(25f5bcd3) SHA1(9d72afe866df363d2ac33dab3ed6c3913f4de12d) ) ROM_LOAD( "a62-15.52", 0x8000, 0x4000, CRC(e65d8312) SHA1(29870fe0dbb30d23970a8a816849dc5807d70675) ) ROM_LOAD( "a62_04.50", 0xc000, 0x4000, CRC(fad74dfe) SHA1(92c0d42c5e186bc07c168ad581e52a5ae340c2b2) ) ROM_REGION( 0x10000, "audiocpu", 0 ) //SOUND ROM_LOAD( "a62_13.5", 0x0000, 0x2000, CRC(7ce290db) SHA1(e3c72ba5d97cb07f0f72d2765a068af6fb5cca29) ) ROM_LOAD( "a62_14.4", 0x2000, 0x2000, CRC(ea74b1a2) SHA1(7be3b9e9d51cfa753ce97e92f7eebd9723fe5821) ) ROM_REGION( 0x20000, "gfx1", 0 ) ROM_LOAD( "a62_12.78", 0x00000, 0x4000, CRC(c5834a7a) SHA1(4a24b3fa707cde89ad5a52d4e994412fcf28e81f) ) ROM_LOAD( "a62_10.77", 0x04000, 0x4000, CRC(3ae7231e) SHA1(277f12570001d82104c79d3d0a58a0b57ed18778) ) ROM_LOAD( "a62_08.80", 0x08000, 0x4000, CRC(b9210dbe) SHA1(f72f2307e9acd2dd622a3efce71bd334b68a9b60) ) ROM_LOAD( "a62-16.79", 0x0c000, 0x4000, CRC(1165a622) SHA1(6a0b4a3eadf157f89c69b5202bd4f895f92a3ef1) ) //bad? ROM_LOAD( "a62_11.89", 0x10000, 0x4000, CRC(d0e9974e) SHA1(6826cfb4fbf098ed7b9d8b00e2684d7c85a13c11) ) ROM_LOAD( "a62_09.88", 0x14000, 0x4000, CRC(e93ef281) SHA1(8bfe1ecce1c7107a5bd1b43b531594c8cfc0719d) ) ROM_LOAD( "a62_07.91", 0x18000, 0x4000, CRC(64c95e8b) SHA1(4c3320a764b13a5751c0019c9fafb899ea2f908f) ) ROM_LOAD( "a62_05.90", 0x1c000, 0x4000, CRC(c3c877ef) SHA1(23180b106e50b7a2a230c5e9948832e5631972ae) ) ROM_REGION( 0x0060, "proms", 0 ) //COLOR (all identical!) ROM_LOAD( "a26-13.109", 0x0000, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.110", 0x0020, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.111", 0x0040, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_END ROM_START( halleycj ) ROM_REGION( 0x10000, "maincpu", 0 ) //MAIN PRG ROM_LOAD( "a62_01.30", 0x0000, 0x4000, CRC(a5e82b3e) SHA1(c16c6a6c23a579454b8a2be4b951c35b04f2a856) ) ROM_LOAD( "a62_02.31", 0x4000, 0x4000, CRC(25f5bcd3) SHA1(9d72afe866df363d2ac33dab3ed6c3913f4de12d) ) ROM_LOAD( "a62_03-1.52", 0x8000, 0x4000, CRC(e2fffbe4) SHA1(a10ced7103a26fd6753765bf11b00ca018f49a48) ) ROM_LOAD( "a62_04.50", 0xc000, 0x4000, CRC(fad74dfe) SHA1(92c0d42c5e186bc07c168ad581e52a5ae340c2b2) ) ROM_REGION( 0x10000, "audiocpu", 0 ) //SOUND ROM_LOAD( "a62_13.5", 0x0000, 0x2000, CRC(7ce290db) SHA1(e3c72ba5d97cb07f0f72d2765a068af6fb5cca29) ) ROM_LOAD( "a62_14.4", 0x2000, 0x2000, CRC(ea74b1a2) SHA1(7be3b9e9d51cfa753ce97e92f7eebd9723fe5821) ) ROM_REGION( 0x20000, "gfx1", 0 ) //CHR ROM_LOAD( "a62_12.78", 0x00000, 0x4000, CRC(c5834a7a) SHA1(4a24b3fa707cde89ad5a52d4e994412fcf28e81f) ) ROM_LOAD( "a62_10.77", 0x04000, 0x4000, CRC(3ae7231e) SHA1(277f12570001d82104c79d3d0a58a0b57ed18778) ) ROM_LOAD( "a62_08.80", 0x08000, 0x4000, CRC(b9210dbe) SHA1(f72f2307e9acd2dd622a3efce71bd334b68a9b60) ) ROM_LOAD( "a62_06.79", 0x0c000, 0x4000, CRC(600be9ca) SHA1(a705b10be37ee93908b1bbaf806cfe7955aa3ffc) ) ROM_LOAD( "a62_11.89", 0x10000, 0x4000, CRC(d0e9974e) SHA1(6826cfb4fbf098ed7b9d8b00e2684d7c85a13c11) ) ROM_LOAD( "a62_09.88", 0x14000, 0x4000, CRC(e93ef281) SHA1(8bfe1ecce1c7107a5bd1b43b531594c8cfc0719d) ) ROM_LOAD( "a62_07.91", 0x18000, 0x4000, CRC(64c95e8b) SHA1(4c3320a764b13a5751c0019c9fafb899ea2f908f) ) ROM_LOAD( "a62_05.90", 0x1c000, 0x4000, CRC(c3c877ef) SHA1(23180b106e50b7a2a230c5e9948832e5631972ae) ) ROM_REGION( 0x0060, "proms", 0 ) //COLOR (all identical!) ROM_LOAD( "a26-13.109", 0x0000, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.110", 0x0020, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.111", 0x0040, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_END ROM_START( halleysc ) ROM_REGION( 0x10000, "maincpu", 0 ) //MAIN PRG ROM_LOAD( "a62_01.30", 0x0000, 0x4000, CRC(a5e82b3e) SHA1(c16c6a6c23a579454b8a2be4b951c35b04f2a856) ) ROM_LOAD( "a62_02.31", 0x4000, 0x4000, CRC(25f5bcd3) SHA1(9d72afe866df363d2ac33dab3ed6c3913f4de12d) ) ROM_LOAD( "a62_03.52", 0x8000, 0x4000, CRC(8e90a97b) SHA1(9199628ad5353a88e4478a13c48df1ccb5d2b538) ) ROM_LOAD( "a62_04.50", 0xc000, 0x4000, CRC(fad74dfe) SHA1(92c0d42c5e186bc07c168ad581e52a5ae340c2b2) ) ROM_REGION( 0x10000, "audiocpu", 0 ) //SOUND ROM_LOAD( "a62_13.5", 0x0000, 0x2000, CRC(7ce290db) SHA1(e3c72ba5d97cb07f0f72d2765a068af6fb5cca29) ) ROM_LOAD( "a62_14.4", 0x2000, 0x2000, CRC(ea74b1a2) SHA1(7be3b9e9d51cfa753ce97e92f7eebd9723fe5821) ) ROM_REGION( 0x20000, "gfx1", 0 ) //CHR ROM_LOAD( "a62_12.78", 0x00000, 0x4000, CRC(c5834a7a) SHA1(4a24b3fa707cde89ad5a52d4e994412fcf28e81f) ) ROM_LOAD( "a62_10.77", 0x04000, 0x4000, CRC(3ae7231e) SHA1(277f12570001d82104c79d3d0a58a0b57ed18778) ) ROM_LOAD( "a62_08.80", 0x08000, 0x4000, CRC(b9210dbe) SHA1(f72f2307e9acd2dd622a3efce71bd334b68a9b60) ) ROM_LOAD( "a62_06.79", 0x0c000, 0x4000, CRC(600be9ca) SHA1(a705b10be37ee93908b1bbaf806cfe7955aa3ffc) ) ROM_LOAD( "a62_11.89", 0x10000, 0x4000, CRC(d0e9974e) SHA1(6826cfb4fbf098ed7b9d8b00e2684d7c85a13c11) ) ROM_LOAD( "a62_09.88", 0x14000, 0x4000, CRC(e93ef281) SHA1(8bfe1ecce1c7107a5bd1b43b531594c8cfc0719d) ) ROM_LOAD( "a62_07.91", 0x18000, 0x4000, CRC(64c95e8b) SHA1(4c3320a764b13a5751c0019c9fafb899ea2f908f) ) ROM_LOAD( "a62_05.90", 0x1c000, 0x4000, CRC(c3c877ef) SHA1(23180b106e50b7a2a230c5e9948832e5631972ae) ) ROM_REGION( 0x0060, "proms", 0 ) //COLOR (all identical!) ROM_LOAD( "a26-13.109", 0x0000, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.110", 0x0020, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.111", 0x0040, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_END ROM_START( halley87 ) ROM_REGION( 0x10000, "maincpu", 0 ) //MAIN PRG ROM_LOAD( "a62-17.30", 0x0000, 0x4000, CRC(fa2a58a6) SHA1(42cb587aad166ff74ece987f275aa7ad16d58300) ) ROM_LOAD( "a62-18.31", 0x4000, 0x4000, CRC(f3a078e6) SHA1(f8fa548b5814276d1ae2d575b9a5d3f0cc2f54fa) ) ROM_LOAD( "a62-19.52", 0x8000, 0x4000, CRC(e8bb695c) SHA1(066558ec48a38db03ae10ba873ff05ab5f911658) ) ROM_LOAD( "a62-20.50", 0xc000, 0x4000, CRC(59ed52cd) SHA1(059ee01610949a654741b853eed0235eabe0e313) ) ROM_REGION( 0x10000, "audiocpu", 0 ) //SOUND ROM_LOAD( "a62_13.5", 0x0000, 0x2000, CRC(7ce290db) SHA1(e3c72ba5d97cb07f0f72d2765a068af6fb5cca29) ) ROM_LOAD( "a62_14.4", 0x2000, 0x2000, CRC(ea74b1a2) SHA1(7be3b9e9d51cfa753ce97e92f7eebd9723fe5821) ) ROM_REGION( 0x20000, "gfx1", 0 ) ROM_LOAD( "a62_12.78", 0x00000, 0x4000, CRC(c5834a7a) SHA1(4a24b3fa707cde89ad5a52d4e994412fcf28e81f) ) ROM_LOAD( "a62_10.77", 0x04000, 0x4000, CRC(3ae7231e) SHA1(277f12570001d82104c79d3d0a58a0b57ed18778) ) ROM_LOAD( "a62_08.80", 0x08000, 0x4000, CRC(b9210dbe) SHA1(f72f2307e9acd2dd622a3efce71bd334b68a9b60) ) ROM_LOAD( "a62_06.79", 0x0c000, 0x4000, CRC(600be9ca) SHA1(a705b10be37ee93908b1bbaf806cfe7955aa3ffc) ) ROM_LOAD( "a62_11.89", 0x10000, 0x4000, CRC(d0e9974e) SHA1(6826cfb4fbf098ed7b9d8b00e2684d7c85a13c11) ) ROM_LOAD( "a62_09.88", 0x14000, 0x4000, CRC(e93ef281) SHA1(8bfe1ecce1c7107a5bd1b43b531594c8cfc0719d) ) ROM_LOAD( "a62_07.91", 0x18000, 0x4000, CRC(64c95e8b) SHA1(4c3320a764b13a5751c0019c9fafb899ea2f908f) ) ROM_LOAD( "a62_05.90", 0x1c000, 0x4000, CRC(c3c877ef) SHA1(23180b106e50b7a2a230c5e9948832e5631972ae) ) ROM_REGION( 0x0060, "proms", 0 ) //COLOR (all identical!) ROM_LOAD( "a26-13.109", 0x0000, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.110", 0x0020, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_LOAD( "a26-13.111", 0x0040, 0x0020, CRC(ec449aee) SHA1(aa33e82b592276d5ffd540d9a73d1b48d7d4accf) ) ROM_END //************************************************************************** // Driver Initializations static void init_common(running_machine &machine) { halleys_state *state = machine.driver_data(); UINT8 *buf, *rom; int addr, i; UINT8 al, ah, dl, dh; // allocate memory for unpacked graphics buf = auto_alloc_array(machine, UINT8, 0x100000); state->m_gfx_plane02 = buf; state->m_gfx_plane13 = buf + 0x80000; // allocate memory for render layers buf = auto_alloc_array(machine, UINT8, SCREEN_BYTESIZE * MAX_LAYERS); for (i=0; im_render_layer[i] = (UINT16*)buf; // allocate memory for pre-processed ROMs state->m_gfx1_base = auto_alloc_array(machine, UINT8, 0x20000); // allocate memory for alpha table state->m_alpha_table = auto_alloc_array(machine, UINT32, 0x10000); // allocate memory for internal palette state->m_internal_palette = auto_alloc_array(machine, UINT32, PALETTE_SIZE); // allocate memory for hardware collision list state->m_collision_list = auto_alloc_array(machine, UINT8, MAX_SPRITES); // decrypt main program ROM rom = state->m_cpu1_base = machine.region("maincpu")->base(); buf = state->m_gfx1_base; for (i=0; i<0x10000; i++) { addr = BITSWAP16(i,15,14,13,12,11,10,1,0,4,5,6,3,7,8,9,2); buf[i] = BITSWAP8(rom[addr],0,7,6,5,1,4,2,3); } memcpy(rom, buf, 0x10000); // swap graphics ROM addresses and unpack each pixel rom = machine.region("gfx1")->base(); buf = state->m_gfx_plane02; for (i=0xffff; i>=0; i--) { al = rom[i]; ah = rom[i+0x10000]; state->m_gfx1_base[0xffff-i] = al; state->m_gfx1_base[0x1ffff-i] = ah; buf[0] = dl = (al & 1) | (ah<<2 & 4); dl <<= 1; buf[1] = dh = (al>>1 & 1) | (ah<<1 & 4); dh <<= 1; buf[0+0x80000] = dl; buf[1+0x80000] = dh; buf[2] = dl = (al>>2 & 1) | (ah & 4); dl <<= 1; buf[3] = dh = (al>>3 & 1) | (ah>>1 & 4); dh <<= 1; buf[2+0x80000] = dl; buf[3+0x80000] = dh; buf[4] = dl = (al>>4 & 1) | (ah>>2 & 4); dl <<= 1; buf[5] = dh = (al>>5 & 1) | (ah>>3 & 4); dh <<= 1; buf[4+0x80000] = dl; buf[5+0x80000] = dh; buf[6] = dl = (al>>6 & 1) | (ah>>4 & 4); dl <<= 1; buf[7] = dh = (al>>7 ) | (ah>>5 & 4); dh <<= 1; buf[6+0x80000] = dl; buf[7+0x80000] = dh; buf += 8; } } static DRIVER_INIT( benberob ) { halleys_state *state = machine.driver_data(); state->m_game_id = GAME_BENBEROB; init_common(machine); state->m_blitter_reset_timer = machine.scheduler().timer_alloc(FUNC(blitter_reset)); } static DRIVER_INIT( halleys ) { halleys_state *state = machine.driver_data(); state->m_game_id = GAME_HALLEYS; state->m_collision_detection = 0xb114; init_common(machine); } static DRIVER_INIT( halley87 ) { halleys_state *state = machine.driver_data(); state->m_game_id = GAME_HALLEYS; state->m_collision_detection = 0xb10d; init_common(machine); } //************************************************************************** // Game Definitions GAME( 1984, benberob, 0, benberob, benberob, benberob, ROT0, "Taito", "Ben Bero Beh (Japan)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_COLORS | GAME_NO_COCKTAIL ) GAME( 1986, halleys, 0, halleys, halleys, halleys, ROT90, "Taito America Corporation (Coin-It license)", "Halley's Comet (US)", GAME_IMPERFECT_GRAPHICS | GAME_NO_COCKTAIL ) GAME( 1986, halleysc, halleys, halleys, halleys, halleys, ROT90, "Taito Corporation", "Halley's Comet (Japan, Newer)", GAME_IMPERFECT_GRAPHICS | GAME_NO_COCKTAIL ) GAME( 1986, halleycj, halleys, halleys, halleys, halleys, ROT90, "Taito Corporation", "Halley's Comet (Japan, Older)", GAME_IMPERFECT_GRAPHICS | GAME_NO_COCKTAIL ) GAME( 1986, halley87, halleys, halleys, halleys, halley87, ROT90, "Taito Corporation", "Halley's Comet '87", GAME_IMPERFECT_GRAPHICS | GAME_NO_COCKTAIL )