diff options
Diffstat (limited to 'src/mame/drivers/halleys.c')
-rw-r--r-- | src/mame/drivers/halleys.c | 2259 |
1 files changed, 2259 insertions, 0 deletions
diff --git a/src/mame/drivers/halleys.c b/src/mame/drivers/halleys.c new file mode 100644 index 00000000000..7b9ea25b0e3 --- /dev/null +++ b/src/mame/drivers/halleys.c @@ -0,0 +1,2259 @@ +/* +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. + + * 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 "driver.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) + +static UINT16 *render_layer[MAX_LAYERS]; +static UINT8 sound_fifo[MAX_SOUNDS]; +static UINT8 *gfx_plane02, *gfx_plane13, *collision_list; +static UINT8 *scrolly0, *scrollx0, *scrolly1, *scrollx1; +static UINT32 *internal_palette, *alpha_table; + +static UINT8 *cpu1_base, *gfx1_base, *blitter_ram, *io_ram; +static size_t blitter_ramsize, io_ramsize; + +static int game_id, blitter_busy, collision_count, stars_enabled, bgcolor, ffcount, ffhead, fftail; +static int mVectorType, sndnmi_mask, firq_level; +static emu_timer *blitter_reset_timer; + +static offs_t halleys_collision_detection; + + +//************************************************************************** +// MB1551x Blitter Functions + +static void blit(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 UINT8 penxlat[16]={0x03,0x07,0x0b,0x0f,0x02,0x06,0x0a,0x0e,0x01,0x05,0x09,0x0d,0x00,0x04,0x08,0x0c}; + static UINT8 rgbmask[16]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xff,0xff,0xff}; + static 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 = blitter_ram + offset; + + +#if HALLEYS_DEBUG +if (0) { + logerror("%04x:[%04x]", activecpu_get_pc(), 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) ? cpu1_base[stptr] : ACTIVE; + flags = mode; + group = mode & GROUP; + command = code & COMMAND; + if (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 = 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 = gfx_plane02 + ((bank + src1)<<3) + eax; + src2_ptr = 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 = 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) + { + collision_list[collision_count & (MAX_SPRITES-1)] = offset; + collision_count++; + + #if HALLEYS_DEBUG + popmessage("ID:%02x CC:%3d", offset, 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 = gfx1_base + bank; + + if (command == STARPASS1 || command == STARPASS2) layer = (layer & 1) + 4; + dst_base = render_layer[layer]; + + +//-------------------------------------------------------------------------- + +#define WARP_WIPE_COMMON { \ + ebx = y + h; \ + ecx = (x + w - SCREEN_WIDTH) << 1; \ + for (edx=y; edx<ebx; edx++) { \ + dst_ptr = dst_base + ((edx & YMASK) << SCREEN_WIDTH_L2); \ + if (ecx > 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 = render_layer[(layer&1)+4]; + WARP_WIPE_COMMON + + 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 = 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)<<SCREEN_WIDTH_L2) + ((X+(O&0xf))&XMASK) ) + + src2_ptr = src_base + src2 + GFX_HI; + + for (yclip=y+h; y<yclip; y+=16) + for (xclip=x+w; x<xclip; x+=16) + { + edx = (UINT32)*src2_ptr; + src2_ptr++; + if (edx) + { + ax = (UINT16)*(src2_ptr-0x100 -1); + ebx = (UINT32)ax; + ax |= BG_MONO; + if (edx & 0x01) { dst_base[C2S(x,y,ebx)] = ax; } + if (edx & 0x02) { ecx = RORB(ebx,1); dst_base[C2S(x,y,ecx)] = ax; } + if (edx & 0x04) { ecx = RORB(ebx,2); dst_base[C2S(x,y,ecx)] = ax; } + if (edx & 0x08) { ecx = RORB(ebx,3); dst_base[C2S(x,y,ecx)] = ax; } + if (edx & 0x10) { ecx = RORB(ebx,4); dst_base[C2S(x,y,ecx)] = ax; } + if (edx & 0x20) { ecx = RORB(ebx,5); dst_base[C2S(x,y,ecx)] = ax; } + if (edx & 0x40) { ecx = RORB(ebx,6); dst_base[C2S(x,y,ecx)] = ax; } + if (edx & 0x80) { ecx = RORB(ebx,7); dst_base[C2S(x,y,ecx)] = ax; } + } + } + + 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<yclip; y++) + { + edi = dst_base + ((y & YMASK) << SCREEN_WIDTH_L2); + + if (edx < 0) + { + ecx = edx; + dst_ptr = (UINT16*)edi - edx; + do { if (dst_ptr[ecx]) dst_ptr[ecx] ^= ax; } while (++ecx); + ecx = x - SCREEN_WIDTH; + } else ecx = w; + + dst_ptr = (UINT16*)edi + x - ecx; + do { if (dst_ptr[ecx]) dst_ptr[ecx] ^= ax; } while (++ecx); + } + + } else + +//-------------------------------------------------------------------------- + + // RGB 8x8 bit-packed transparent tile + if (command == TILEPASS1 && flags & COLOR_ON) + { + /* + Tile positioning in this mode is very cryptic and different from + others. The coordinate system seems banked and influenced by layer + number and whether the blit code is written to the upper or lower + off-screen area. These conditions may also imply height-doubling, + Y-flipping and draw-from-bottom attributes. + + Pixel and color information is embedded but the game draws a + second pass at the same location with zeroes. In addition the + X and Y values passed to the blitter do not reflect the tiles true + locations. For example, tiles near the top or bottom of the screen + are positioned resonably close but those in the middle are oddly + shifted toward either side. The tiles also resemble predefined + patterns but I don't know if there are supposed to be lookup tables + in ROM or hard-wired to the blitter chips. + */ + if (y & 1) x -= 8; + y = tyremap[y] << 3; + + if (flags & SY_HIGH) y += 8; + if (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 = 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<wclip; xclip+=32) + { + xclip &= XMASK; + edx = xclip + w - SCREEN_WIDTH; + + for (yclip=y; yclip<hclip; yclip++) + { + eax = (UINT32)*src1_ptr; + src1_ptr += src_dx; + if (!eax) continue; + eax = eax | (eax<<16) | ((BG_RGB<<16)|BG_RGB); + edi = dst_base + ((yclip & YMASK) << SCREEN_WIDTH_L2); + + if (edx > 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 ) +{ + int yskip, xskip, ecx; + UINT16 *edi; + UINT16 ax; + + 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 = render_layer[2] + (yskip<<SCREEN_WIDTH_L2) + xskip + (48<<SCREEN_WIDTH_L2); + ecx = -(48<<SCREEN_WIDTH_L2); + ax = (UINT16)data | BG_RGB; + + do { edi[ecx] = edi[ecx+1] = edi[ecx+2] = edi[ecx+3] = edi[ecx+4] = ax; } while (ecx += SCREEN_WIDTH); +} + + +static READ8_HANDLER( blitter_status_r ) +{ + if (game_id==GAME_HALLEYS && activecpu_get_pc()==0x8017) return(0x55); // HACK: trick SRAM test on startup + + return(0); +} + + +static READ8_HANDLER( blitter_r ) +{ + int i = offset & 0xf; + + if (i==0 || i==4) return(1); + + return(blitter_ram[offset]); +} + + +static TIMER_CALLBACK( blitter_reset ) +{ + blitter_busy = 0; +} + + +static WRITE8_HANDLER( blitter_w ) +{ + int i = offset & 0xf; + + blitter_ram[offset] = data; + + if (i==0) blit(offset); + + if (game_id == GAME_BENBEROB) + { + if (i==0 || (i==4 && !data)) + { + blitter_busy = 0; + if (firq_level) cpunum_set_input_line(0, M6809_FIRQ_LINE, ASSERT_LINE); // make up delayed FIRQ's + } + else + { + blitter_busy = 1; + timer_adjust(blitter_reset_timer, ATTOTIME_IN_CYCLES(100, 0), 0, attotime_zero); // free blitter if no updates in 100 cycles + } + } +} + + +static READ8_HANDLER( collision_id_r ) +{ +/* + 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 (game_id==GAME_HALLEYS && activecpu_get_pc()==halleys_collision_detection) // HACK: collision detection bypass + { + if (collision_count) { collision_count--; return(collision_list[collision_count]); } + + return(0); + } + + return(io_ram[0x66]); +} + + +//************************************************************************** +// Video Initializations and Updates + +static PALETTE_INIT( halleys ) +{ + UINT32 d, r, g, b, i, j, count; + UINT32 *pal_ptr = 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(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 = paletteram; + + // each of the three 32-byte 6330 PROM is wired to an RGB component output + prom_6330 = memory_region(REGION_PROMS); + + // 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 ) +{ + UINT32 d, r, g, b, i, j; + UINT32 *pal_ptr = internal_palette; + + paletteram[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(Machine, offset, MAKE_RGB(r, g, b)); + palette_set_color(Machine, offset+SP_2BACK, MAKE_RGB(r, g, b)); + palette_set_color(Machine, offset+SP_ALPHA, MAKE_RGB(r, g, b)); + palette_set_color(Machine, offset+SP_COLLD, MAKE_RGB(r, g, b)); + + halleys_decode_rgb(&r, &g, &b, offset, 0); + palette_set_color(Machine, offset+0x20, MAKE_RGB(r, g, b)); +} + + +static VIDEO_START( halleys ) +{ +#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 + scrolly0 = io_ram + HALLEYS_Y0; + scrollx0 = io_ram + HALLEYS_X0; + scrolly1 = io_ram + HALLEYS_Y1; + scrollx1 = 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; + + alpha_table[(src<<8)+dst] = c | BG_RGB; + } +} + + +static void copy_scroll_op(mame_bitmap *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(mame_bitmap *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(mame_bitmap *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(mame_bitmap *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(mame_bitmap *bitmap, int mask) +{ + int dst_pitch; + + UINT32 *pal_ptr, *edi; + int esi, eax, ebx, ecx, edx; + + pal_ptr = 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 VIDEO_UPDATE( halleys ) +{ + int i, j; + + if (stars_enabled) + { + copy_scroll_op(bitmap, render_layer[5], *scrollx0, *scrolly0); + copy_scroll_xp(bitmap, render_layer[4], *scrollx1, *scrolly1); + } + else + fillbitmap(bitmap, bgcolor, cliprect); + + if (readinputportbytag("FAKE")) copy_scroll_xp(bitmap, render_layer[3], *scrollx0, *scrolly0); // not used??? + copy_scroll_xp(bitmap, render_layer[2], *scrollx1, *scrolly1); + copy_fixed_2b (bitmap, render_layer[1]); + copy_fixed_xp (bitmap, render_layer[0]); + + // HALF-HACK: apply RGB filter when the following conditions are met + i = io_ram[0xa0]; + j = io_ram[0xa1]; + if (io_ram[0x2b] && (i>0xc6 && i<0xfe) && (j==0xc0 || j==0xed)) filter_bitmap(bitmap, i); + return 0; +} + + +static VIDEO_UPDATE( benberob ) +{ + if (io_ram[0xa0] & 0x80) + copy_scroll_op(bitmap, render_layer[2], *scrollx1, *scrolly1); + else + fillbitmap(bitmap, bgcolor, cliprect); + + copy_fixed_xp (bitmap, render_layer[1]); + copy_fixed_xp (bitmap, render_layer[0]); + return 0; +} + + +//************************************************************************** +// Debug and Test Handlers + +#if HALLEYS_DEBUG + +static READ8_HANDLER( zero_r ) { return(0); } + +static READ8_HANDLER( debug_r ) { return(io_ram[offset]); } + +#endif + + +//************************************************************************** +// Interrupt and Hardware Handlers + +static INTERRUPT_GEN( halleys_interrupt ) +{ + static int latch_delay = 0; + UINT8 latch_data; + + switch (cpu_getiloops()) + { + case 0: + /* + How the custom chips handle sound latching is largely unknown. + Halley's Comet dumps sound commands to register ff8a so + rapidly the AY8910 core sometimes fails to reset itself and + the music stops. Masking sound NMI is not enough to ensure + successive writes are processed properly so it is advisable to + queue sound commands or make the main CPU yield for a minimum + of 600 Z80 cycles. Furthermore, soundlatch NMI interval should + not be too much shorter than music IRQ's period(27306667ns), + and must be longer in case of a reset(00). + + Current implementation is quite safe although not 100% foul-proof. + */ + if (latch_delay) latch_delay--; else + if (ffcount) + { + ffcount--; + latch_data = sound_fifo[fftail]; + fftail = (fftail + 1) & (MAX_SOUNDS - 1); + latch_delay = (latch_data) ? 0 : 4; + soundlatch_w(0, latch_data); + cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE); + } + + // clear collision list of this frame unconditionally + collision_count = 0; + break; + + // In Halley's Comet, NMI is used exclusively to handle coin input + case 1: + cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE); + break; + + // FIRQ drives gameplay; we need both types of NMI each frame. + case 2: + mVectorType = 1; cpunum_set_input_line(0, M6809_FIRQ_LINE, ASSERT_LINE); + break; + + case 3: + mVectorType = 0; cpunum_set_input_line(0, M6809_FIRQ_LINE, ASSERT_LINE); + break; + } +} + + +static INTERRUPT_GEN( benberob_interrupt ) +{ + static int latch_delay = 0; + UINT8 latch_data; + + switch (cpu_getiloops()) + { + case 0: + if (latch_delay) latch_delay--; else + if (ffcount) + { + ffcount--; + latch_data = sound_fifo[fftail]; + fftail = (fftail + 1) & (MAX_SOUNDS - 1); + latch_delay = (latch_data) ? 0 : 4; + soundlatch_w(0, latch_data); + cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE); + } + break; + + case 1: + cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE); + break; + + case 2: + case 3: + // FIRQ must not happen when the blitter is being updated or it'll cause serious screen artifacts + if (!blitter_busy) cpunum_set_input_line(0, M6809_FIRQ_LINE, ASSERT_LINE); else firq_level++; + break; + } +} + + +static READ8_HANDLER( vector_r ) +{ + return(cpu1_base[0xffe0 + (offset^(mVectorType<<4))]); +} + + +static WRITE8_HANDLER( firq_ack_w ) +{ + io_ram[0x9c] = data; + + if (firq_level) firq_level--; + cpunum_set_input_line(0, M6809_FIRQ_LINE, CLEAR_LINE); +} + + +static WRITE8_HANDLER( sndnmi_msk_w ) +{ + sndnmi_mask = data & 1; +} + + +static WRITE8_HANDLER( soundcommand_w ) +{ + if (ffcount < MAX_SOUNDS) + { + ffcount++; + sound_fifo[ffhead] = io_ram[0x8a] = data; + ffhead = (ffhead + 1) & (MAX_SOUNDS - 1); + } +} + + +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. + int inp = readinputportbytag("IN0"); + int result = 0x01; // dual coin slots + + if (inp & 0x80) result |= 0x02; + if (inp & 0x40) result |= 0x04; + + return(result); +} + + +static READ8_HANDLER( io_mirror_r ) +{ + return(readinputport(offset + 3)); +} + + +//************************************************************************** +// Memory Maps + +static ADDRESS_MAP_START( readmem, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x0fff) AM_READ(blitter_r) + AM_RANGE(0x1000, 0xefff) AM_READ(MRA8_ROM) + AM_RANGE(0xf000, 0xfeff) AM_READ(MRA8_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(0xff90, 0xff90) AM_READ(input_port_3_r) // coin/start + AM_RANGE(0xff91, 0xff91) AM_READ(input_port_4_r) // player 1 + AM_RANGE(0xff92, 0xff92) AM_READ(input_port_5_r) // player 2 + AM_RANGE(0xff93, 0xff93) AM_READ(input_port_6_r) // unused? + AM_RANGE(0xff94, 0xff94) AM_READ(coin_lockout_r) + AM_RANGE(0xff95, 0xff95) AM_READ(input_port_0_r) // dipswitch 4 + AM_RANGE(0xff96, 0xff96) AM_READ(input_port_1_r) // dipswitch 3 + AM_RANGE(0xff97, 0xff97) AM_READ(input_port_2_r) // dipswitch 2 + AM_RANGE(0xff00, 0xffbf) AM_READ(MRA8_RAM) // I/O read fall-through + + AM_RANGE(0xffc0, 0xffdf) AM_READ(MRA8_RAM) // palette read + AM_RANGE(0xffe0, 0xffff) AM_READ(vector_r) +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( writemem, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x0fff) AM_WRITE(blitter_w) AM_BASE(&blitter_ram) AM_SIZE(&blitter_ramsize) + AM_RANGE(0x1f00, 0x1fff) AM_WRITE(bgtile_w) // background tiles?(Ben Bero Beh only) + AM_RANGE(0x1000, 0xefff) AM_WRITE(MWA8_ROM) + AM_RANGE(0xf000, 0xfeff) AM_WRITE(MWA8_RAM) // work ram + + AM_RANGE(0xff8a, 0xff8a) AM_WRITE(soundcommand_w) + AM_RANGE(0xff9c, 0xff9c) AM_WRITE(firq_ack_w) + AM_RANGE(0xff00, 0xffbf) AM_WRITE(MWA8_RAM) AM_BASE(&io_ram) AM_SIZE(&io_ramsize) // I/O write fall-through + + AM_RANGE(0xffc0, 0xffdf) AM_WRITE(halleys_paletteram_IIRRGGBB_w) AM_BASE(&paletteram) + AM_RANGE(0xffe0, 0xffff) AM_WRITE(MWA8_ROM) +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( sound_readmem, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x3fff) AM_READ(MRA8_ROM) + AM_RANGE(0x4000, 0x47ff) AM_READ(MRA8_RAM) + AM_RANGE(0x4801, 0x4801) AM_READ(AY8910_read_port_1_r) + AM_RANGE(0x4803, 0x4803) AM_READ(AY8910_read_port_2_r) + AM_RANGE(0x4805, 0x4805) AM_READ(AY8910_read_port_3_r) + AM_RANGE(0x5000, 0x5000) AM_READ(soundlatch_r) + AM_RANGE(0xe000, 0xefff) AM_READ(MRA8_ROM) // space for diagnostic ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( sound_writemem, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x3fff) AM_WRITE(MWA8_ROM) + AM_RANGE(0x4000, 0x47ff) AM_WRITE(MWA8_RAM) + AM_RANGE(0x4800, 0x4800) AM_WRITE(AY8910_control_port_1_w) + AM_RANGE(0x4801, 0x4801) AM_WRITE(AY8910_write_port_1_w) + AM_RANGE(0x4802, 0x4802) AM_WRITE(AY8910_control_port_2_w) + AM_RANGE(0x4803, 0x4803) AM_WRITE(AY8910_write_port_2_w) + AM_RANGE(0x4804, 0x4804) AM_WRITE(AY8910_control_port_3_w) + AM_RANGE(0x4805, 0x4805) AM_WRITE(AY8910_write_port_3_w) + AM_RANGE(0xe000, 0xefff) AM_WRITE(MWA8_ROM) +ADDRESS_MAP_END + + +//************************************************************************** +// Port Maps +/* + Halley's Comet + Taito/Coin-it 1986 + + 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. + + Dip sw 2 is not used and all contacts should be set off. +*/ + +static INPUT_PORTS_START( halleys ) + PORT_START_TAG("DSW1") // 0xff95 + PORT_DIPNAME( 0x01, 0x00, DEF_STR( Cabinet ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Upright ) ) + PORT_DIPSETTING( 0x01, DEF_STR( Cocktail ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Flip_Screen ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, "Test Mode" ) + PORT_DIPSETTING( 0x04, DEF_STR( No ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Demo_Sounds ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x30, 0x30, DEF_STR( Coin_A ) ) + PORT_DIPSETTING( 0x10, DEF_STR( 2C_1C ) ) + PORT_DIPSETTING( 0x30, DEF_STR( 1C_1C ) ) + PORT_DIPSETTING( 0x00, DEF_STR( 2C_3C ) ) + PORT_DIPSETTING( 0x20, DEF_STR( 1C_2C ) ) + PORT_DIPNAME( 0xc0, 0xc0, DEF_STR( Coin_B ) ) + PORT_DIPSETTING( 0x40, DEF_STR( 2C_1C ) ) + PORT_DIPSETTING( 0xc0, DEF_STR( 1C_1C ) ) + PORT_DIPSETTING( 0x00, DEF_STR( 2C_3C ) ) + PORT_DIPSETTING( 0x80, DEF_STR( 1C_2C ) ) + + PORT_START_TAG("DSW2") // 0xff96 + PORT_DIPNAME( 0x03, 0x01, DEF_STR( Difficulty ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Easiest ) ) + PORT_DIPSETTING( 0x03, DEF_STR( Easy ) ) + PORT_DIPSETTING( 0x01, DEF_STR( Normal ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Hard ) ) + PORT_DIPNAME( 0x0c, 0x04, DEF_STR( Bonus_Life ) ) + PORT_DIPSETTING( 0x0c, "20k/60k/680k" ) + PORT_DIPSETTING( 0x08, "20k/80k/840k" ) + PORT_DIPSETTING( 0x04, "20k/100k/920k" ) + PORT_DIPSETTING( 0x00, "10k/50k/560k" ) + PORT_DIPNAME( 0x30, 0x30, DEF_STR( Lives ) ) + PORT_DIPSETTING( 0x20, "2" ) + PORT_DIPSETTING( 0x30, "3" ) + PORT_DIPSETTING( 0x10, "4" ) + PORT_DIPSETTING( 0x00, "4 (no bonus ships)" ) + PORT_DIPNAME( 0x40, 0x40, "Record Data" ) + PORT_DIPSETTING( 0x40, DEF_STR( No ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) + PORT_DIPNAME( 0x80, 0x80, "Unknown(2-8)" ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START_TAG("DSW3") // 0xff97 + PORT_DIPNAME( 0x01, 0x01, "Unknown(3-1)" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Free_Play ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x1c, 0x1c, "Start Round" ) + PORT_DIPSETTING( 0x1c, "1" ) + PORT_DIPSETTING( 0x18, "4" ) + PORT_DIPSETTING( 0x14, "7" ) + PORT_DIPSETTING( 0x10, "10" ) + PORT_DIPSETTING( 0x0c, "13" ) + PORT_DIPSETTING( 0x08, "16" ) + PORT_DIPSETTING( 0x04, "19" ) + PORT_DIPSETTING( 0x00, "22" ) + PORT_DIPNAME( 0x20, 0x20, "Unknown(3-6)" ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, "Invincibility (Cheat)") + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, "Unknown(3-8)" ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START_TAG("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_TAG("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_NAME("P1 Hyperspace") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Fire") + + PORT_START_TAG("IN2") // 0xff92 + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) + 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_PLAYER(2) PORT_NAME("P2 Hyperspace") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 Fire") + + PORT_START_TAG("IN3") // 0xff93 + + PORT_START_TAG("FAKE") // just to be safe + PORT_DIPNAME( 0x01, 0x00, "Show Unused Layer" ) + PORT_DIPSETTING( 0x00, DEF_STR( No ) ) + PORT_DIPSETTING( 0x01, DEF_STR( Yes ) ) +INPUT_PORTS_END + + +static INPUT_PORTS_START( benberob ) + PORT_START_TAG("DSW1") // 0xff95 + PORT_DIPNAME( 0x03, 0x01, DEF_STR( Bonus_Life ) ) + PORT_DIPSETTING( 0x02, "Every 100K" ) + PORT_DIPSETTING( 0x00, "100K & Every 200K" ) + PORT_DIPSETTING( 0x01, "150K & Every 300K" ) + PORT_DIPSETTING( 0x03, "100K, 200K & 300K Only" ) + 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( 0x00, "Infinite (Cheat)") + PORT_DIPSETTING( 0x08, "3" ) + PORT_DIPSETTING( 0x10, "4" ) + PORT_DIPSETTING( 0x18, "5" ) + PORT_DIPNAME( 0x20, 0x20, "Unknown(1-6)" ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Flip_Screen ) ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, DEF_STR( Cabinet ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Upright ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Cocktail ) ) + + // 0xff96 + PORT_START_TAG("DSW2") + 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_TAG("DSW3") // 0xff97 + PORT_DIPNAME( 0x01, 0x01, "Starting Round" ) + PORT_DIPSETTING( 0x01, "1st Round" ) + PORT_DIPSETTING( 0x00, "2nd Round" ) + PORT_DIPNAME( 0x02, 0x00, "Use Both Buttons" ) + PORT_DIPSETTING( 0x02, DEF_STR( No ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Yes ) ) + PORT_DIPNAME( 0x0c, 0x08, "Bonus Countdown Time" ) + PORT_DIPSETTING( 0x00, "1:15" ) /* Fastest countdown */ + PORT_DIPSETTING( 0x04, "1:30" ) + PORT_DIPSETTING( 0x08, "1:45" ) + PORT_DIPSETTING( 0x0c, "2:00" ) /* Slowest countdown */ + PORT_DIPNAME( 0x10, 0x00, "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 (Cheat)") + 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_TAG("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_TAG("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_NAME("P1 Jump") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Extinguisher") + + PORT_START_TAG("IN2") // 0xff92 + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) + 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_PLAYER(2) PORT_NAME("P2 Jump") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 Extinguisher") + + PORT_START_TAG("IN3") // 0xff93 +INPUT_PORTS_END + + +//************************************************************************** +// Machine Definitions and Initializations + +static MACHINE_RESET( halleys ) +{ + mVectorType = 0; + firq_level = 0; + blitter_busy = 0; + collision_count = 0; + stars_enabled = 0; + bgcolor = get_black_pen(machine); + fftail = ffhead = ffcount = 0; + + memset(io_ram, 0xff, io_ramsize); + memset(render_layer[0], 0, SCREEN_BYTESIZE * MAX_LAYERS); +} + + +static struct AY8910interface ay8910_interface = +{ + 0, + 0, + 0, + sndnmi_msk_w // port Bwrite +}; + + +static MACHINE_DRIVER_START( halleys ) + MDRV_CPU_ADD_TAG("main", M6809, 19968000/4) // 5Mhz?(19.968MHz XTAL) + MDRV_CPU_PROGRAM_MAP(readmem, writemem) + MDRV_CPU_VBLANK_INT(halleys_interrupt, 4) + + MDRV_CPU_ADD(Z80, 6000000/2) // 3MHz(6MHz XTAL) + /* audio CPU */ + MDRV_CPU_PROGRAM_MAP(sound_readmem, sound_writemem) + MDRV_CPU_PERIODIC_INT(irq0_line_hold, (double)6000000/(4*16*16*10*16)) + + MDRV_SCREEN_REFRESH_RATE(60) + MDRV_SCREEN_VBLANK_TIME(DEFAULT_60HZ_VBLANK_DURATION) + MDRV_MACHINE_RESET(halleys) + + // video hardware + MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER) + MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) + MDRV_SCREEN_SIZE(SCREEN_WIDTH, SCREEN_HEIGHT) + MDRV_SCREEN_VISIBLE_AREA(VIS_MINX, VIS_MAXX, VIS_MINY, VIS_MAXY) + + MDRV_PALETTE_LENGTH(PALETTE_SIZE) + MDRV_PALETTE_INIT(halleys) + + MDRV_VIDEO_START(halleys) + MDRV_VIDEO_UPDATE(halleys) + + // sound hardware + MDRV_SPEAKER_STANDARD_MONO("mono") + + MDRV_SOUND_ADD(AY8910, 6000000/4) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) + + MDRV_SOUND_ADD(AY8910, 6000000/4) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) + + MDRV_SOUND_ADD(AY8910, 6000000/4) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) + + MDRV_SOUND_ADD(AY8910, 6000000/4) + MDRV_SOUND_CONFIG(ay8910_interface) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) +MACHINE_DRIVER_END + + +static MACHINE_DRIVER_START( benberob ) + MDRV_IMPORT_FROM(halleys) + MDRV_CPU_REPLACE("main", M6809, 1000000) // 19.968MHz/20? (CAUTION: timing critical) + MDRV_CPU_VBLANK_INT(benberob_interrupt, 4) + MDRV_VIDEO_UPDATE(benberob) +MACHINE_DRIVER_END + + +//************************************************************************** +// ROM Definitions + +ROM_START( benberob ) + ROM_REGION( 0x10000, REGION_CPU1, 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, REGION_CPU2, 0 ) //SOUND + ROM_LOAD( "a26_12.5", 0x0000, 0x4000, CRC(7fd728f3) SHA1(772c14d9254e43a56f1e67ad4dd5d7840df50e34) ) + + ROM_REGION( 0x20000, REGION_GFX1, ROMREGION_DISPOSE ) //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, REGION_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, REGION_CPU1, 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, REGION_CPU2, 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, REGION_GFX1, ROMREGION_DISPOSE ) + 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, REGION_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, REGION_CPU1, 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, REGION_CPU2, 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, REGION_GFX1, ROMREGION_DISPOSE ) //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, REGION_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, REGION_CPU1, 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, REGION_CPU2, 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, REGION_GFX1, ROMREGION_DISPOSE ) //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, REGION_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, REGION_CPU1, 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, REGION_CPU2, 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, REGION_GFX1, ROMREGION_DISPOSE ) + 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, REGION_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(void) +{ + UINT8 *buf, *rom; + int addr, i; + UINT8 al, ah, dl, dh; + + + // allocate memory for unpacked graphics + buf = auto_malloc(0x100000); + gfx_plane02 = buf; + gfx_plane13 = buf + 0x80000; + + + // allocate memory for render layers + buf = auto_malloc(SCREEN_BYTESIZE * MAX_LAYERS); + for (i=0; i<MAX_LAYERS; buf+=SCREEN_BYTESIZE, i++) render_layer[i] = (UINT16*)buf; + + + // allocate memory for pre-processed ROMs + gfx1_base = auto_malloc(0x20000); + + + // allocate memory for alpha table + alpha_table = auto_malloc(sizeof(UINT32) * 0x10000); + + + // allocate memory for internal palette + internal_palette = auto_malloc(sizeof(UINT32) * PALETTE_SIZE); + + + // allocate memory for hardware collision list + collision_list = auto_malloc(MAX_SPRITES); + + + // decrypt main program ROM + rom = cpu1_base = memory_region(REGION_CPU1); + buf = 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 = memory_region(REGION_GFX1); + buf = gfx_plane02; + + for (i=0xffff; i>=0; i--) + { + al = rom[i]; + ah = rom[i+0x10000]; + gfx1_base[0xffff-i] = al; + 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 ) +{ + game_id = GAME_BENBEROB; + + init_common(); + + blitter_reset_timer = timer_alloc(blitter_reset); +} + + +static DRIVER_INIT( halleys ) +{ + game_id = GAME_HALLEYS; + halleys_collision_detection = 0xb114; + + init_common(); +} + +static DRIVER_INIT( halley87 ) +{ + game_id = GAME_HALLEYS; + halleys_collision_detection = 0xb10d; + + init_common(); +} + + +//************************************************************************** +// Game Definitions + +GAME( 1984, benberob, 0, benberob, benberob, benberob, ROT0, "Taito", "Ben Bero Beh (Japan)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_COLORS ) +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 ) |