diff options
Diffstat (limited to 'trunk/src/mame/drivers/bfcobra.c')
-rw-r--r-- | trunk/src/mame/drivers/bfcobra.c | 1975 |
1 files changed, 1975 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/bfcobra.c b/trunk/src/mame/drivers/bfcobra.c new file mode 100644 index 00000000000..889fd5b30de --- /dev/null +++ b/trunk/src/mame/drivers/bfcobra.c @@ -0,0 +1,1975 @@ +/****************************************************************************** + + Bell-Fruit Cobra I/II and Viper Hardware + + driver by Phil Bennett and Anonymous + + Games supported: + * A Question of Sport [2 sets] + * Beeline (non-working - missing disk) + * Every Second Counts + * Inquizitor (Viper hardware, non-working - missing disk) + * Quizvaders + * Treble Top + + Other games on this hardware: + * Brain Box + * Quintoon alt. version (Cobra II/Cyclone hardware) + + Notes: + + The hardware is based on a chipset known as 'Flare One', developed + by Flare Technology. It consists of a 16-bit DSP (intended for sound + synthesis and 3D maths), an 8bpp blitter and a video controller, driven + by a Z80. + + Flare One would evolve to become 'Slipstream', used by the unreleased + Konix Multisystem console. + + The Flare One chipset is implemented as four Texas Instruments ASICs, + each an 84 pin PLCC package: + + CF30204, CF30205, CF30206 (DSP) and CF30207. + + The hardware using this chipset is as follows: + + Viper + ===== + + A video expansion PCB for Scorpion I? + On some PCB revisions there is audio output circuitry connected to the DSP. + Viper uses a WD1772 type floppy disk controller. + + Cobra I + ======= + + A combination of Viper and Scorpion I hardware on a single PCB. + Cobra uses an NEC '765 type FDC. Later revisions have no DSP. + + Cobra II (Cyclone) + ================== + + A compact video expansion board for Scorpion II. + The Z80 is replaced by a Z180 and there is no Flare DSP or FDC + + + To do: + + * Complete blitter emulation + * Cobra II support + * Hook up additional inputs, EM meters, lamps etc + + Known issues: + + * All games bar qos: NVRAM not saved + + * Viper does not have a colour palette - the Flare chipset drives RGB direct. + To fix this I set default values in the palette when the machine is initialised + * CPU execution rate is wrong, the hardware adds 1 TCycle to each access which is unaccounted for. + * Plane priority is probably wrong but it's only used in Treble Top. + * Blitter loop counts and step are wrong - they are 9 bit counts, not 8. + * Blitter emulation doesn't support hi-res mode (needed for Inquizitor) + +******************************************************************************/ + +#include "emu.h" +#include "machine/6850acia.h" +#include "machine/meters.h" +#include "cpu/z80/z80.h" +#include "cpu/m6809/m6809.h" +#include "sound/upd7759.h" +#include "sound/ay8910.h" +#include "machine/nvram.h" + + +/* + Defines +*/ +#define Z80_XTAL 5910000 /* Unconfirmed */ +#define M6809_XTAL 1000000 + + +/* + Function prototypes +*/ +INLINE void z80_bank(running_machine &machine, int num, int data); + + +/*************************************************************************** + + Split into video\cobra.c ! + +***************************************************************************/ + +typedef union +{ +#ifdef LSB_FIRST + struct { UINT16 loword, hiword ; } ; + struct { UINT8 addr0, addr1, addr2; }; +#else + struct { UINT16 hiword, loword ; } ; + struct { UINT8 addr2, addr1, addr0; }; +#endif + UINT32 addr; +} ADDR_REG; + +/* Blitter register flag bits */ +#define CMD_RUN 0x01 +#define CMD_COLST 0x02 +#define CMD_PARRD 0x04 /* Never used? */ +#define CMD_SRCUP 0x08 +#define CMD_DSTUP 0x10 +#define CMD_LT0 0x20 +#define CMD_LT1 0x40 +#define CMD_LINEDRAW 0x80 + + +/* All unconfirmed */ +//#define SRCDST_CMP 0x10 +//#define SRCDST_WRAP 0x20 +//#define SRCDST_SIGN 0x40 +#define SRCDST_A_1 0x80 /* This might be correct for line drawing? */ + +/* These appear to be correct */ +#define MODE_SSIGN 0x80 +#define MODE_DSIGN 0x40 +#define MODE_YFRAC 0x20 +#define MODE_BITTOBYTE 0x04 +#define MODE_PALREMAP 0x10 + +#define CMPFUNC_LT 0x01 +#define CMPFUNC_EQ 0x02 +#define CMPFUNC_GT 0x04 +#define CMPFUNC_BEQ 0x08 +#define CMPFUNC_LOG0 0x10 +#define CMPFUNC_LOG1 0x20 +#define CMPFUNC_LOG2 0x40 +#define CMPFUNC_LOG3 0x80 + +/* + Blitter state +*/ +struct blitter_t +{ + ADDR_REG program; + + UINT8 control; + UINT8 status; + + UINT8 command; + ADDR_REG source; + ADDR_REG dest; + UINT8 modectl; + UINT8 compfunc; + UINT8 outercnt; + + UINT8 innercnt; + UINT8 step; + UINT8 pattern; +}; + +#define LOOPTYPE ( ( blitter.command&0x60 ) >> 5 ) + +/* + MUSIC Semiconductor TR9C1710 RAMDAC or equivalent +*/ +struct ramdac_t +{ + UINT8 addr_w; + UINT8 addr_r; + UINT8 mask; + + /* 18-bit colors */ + UINT8 color_r[3]; + UINT8 color_w[3]; + UINT32 table[256]; + + /* Access counts */ + UINT8 count_r; + UINT8 count_w; +}; + + +struct fdc_t +{ + UINT8 MSR; + + int side; + int track; + int sector; + int number; + int stop_track; + int setup_read; + + int byte_pos; + int offset; + + int phase; + int next_phase; + int cmd_len; + int cmd_cnt; + int res_len; + int res_cnt; + UINT8 cmd[10]; + UINT8 results[8]; +}; + + +#define BLUE_0 0 +#define BLUE_1 1 +#define BLUE_2 2 +#define BLUE_3 3 +#define GREEN_0 ( 0 << 2 ) +#define GREEN_1 ( 1 << 2 ) +#define GREEN_2 ( 2 << 2 ) +#define GREEN_3 ( 3 << 2 ) +#define GREEN_4 ( 4 << 2 ) +#define GREEN_5 ( 5 << 2 ) +#define GREEN_6 ( 6 << 2 ) +#define GREEN_7 ( 7 << 2 ) +#define RED_0 ( 0 << 5 ) +#define RED_1 ( 1 << 5 ) +#define RED_2 ( 2 << 5 ) +#define RED_3 ( 3 << 5 ) +#define RED_4 ( 4 << 5 ) +#define RED_5 ( 5 << 5 ) +#define RED_6 ( 6 << 5 ) +#define RED_7 ( 7 << 5 ) + +class bfcobra_state : public driver_device +{ +public: + bfcobra_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) { } + + UINT8 m_bank_data[4]; + UINT8 *m_work_ram; + UINT8 *m_video_ram; + UINT8 m_h_scroll; + UINT8 m_v_scroll; + UINT8 m_flip_8; + UINT8 m_flip_22; + UINT8 m_videomode; + UINT8 m_z80_m6809_line; + UINT8 m_m6809_z80_line; + UINT8 m_data_r; + UINT8 m_data_t; + int m_irq_state; + int m_acia_irq; + int m_vblank_irq; + int m_blitter_irq; + UINT8 m_z80_int; + UINT8 m_z80_inten; + UINT32 m_meter_latch; + UINT32 m_mux_input; + UINT32 m_mux_outputlatch; + UINT8 m_col4bit[16]; + UINT8 m_col3bit[16]; + UINT8 m_col8bit[256]; + UINT8 m_col7bit[256]; + UINT8 m_col6bit[256]; + struct blitter_t m_blitter; + struct ramdac_t m_ramdac; + struct fdc_t m_fdc; +}; + + +static const UINT8 col4bit_default[16]= +{ + BLUE_0 | GREEN_0 | RED_0, + BLUE_1, + GREEN_2, + BLUE_1 | GREEN_2, + RED_2, + RED_2 | BLUE_1, + RED_2 | GREEN_2, + RED_2 | GREEN_2 | BLUE_1, + BLUE_2 | GREEN_5 | RED_5, + BLUE_3, + GREEN_7, + BLUE_3 | GREEN_7, + RED_7, + RED_7 | BLUE_3, + RED_7 | GREEN_7, + RED_7 | GREEN_7 | BLUE_3 +}; + +static const UINT8 col3bit_default[16]= +{ + 0, + BLUE_3, + GREEN_7, + BLUE_3 | GREEN_7, + RED_7, + RED_7 | BLUE_3, + RED_7 | GREEN_7, + RED_7 | GREEN_7 | BLUE_3, + 0, + BLUE_3, + GREEN_7, + BLUE_3 | GREEN_7, + RED_7, + RED_7 | BLUE_3, + RED_7 | GREEN_7, + RED_7 | GREEN_7 | BLUE_3 +}; + +static const UINT8 col76index[] = {0, 2, 4, 7}; + + +static VIDEO_START( bfcobra ) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + int i; + + memcpy(state->m_col4bit, col4bit_default, sizeof(state->m_col4bit)); + memcpy(state->m_col3bit, col3bit_default, sizeof(state->m_col3bit)); + for (i = 0; i < 256; ++i) + { + UINT8 col; + + state->m_col8bit[i] = i; + col = i & 0x7f; + col = (col & 0x1f) | (col76index[ ( (col & 0x60) >> 5 ) & 3] << 5); + state->m_col7bit[i] = col; + + col = (col & 3) | (col76index[( (col & 0x0c) >> 2) & 3] << 2 ) | + (col76index[( (col & 0x30) >> 4) & 3] << 5 ); + state->m_col6bit[i] = col; + } +} + +static SCREEN_UPDATE( bfcobra ) +{ + bfcobra_state *state = screen->machine().driver_data<bfcobra_state>(); + int x, y; + UINT8 *src; + UINT32 *dest; + UINT32 offset; + UINT8 *hirescol; + UINT8 *lorescol; + + /* Select screen has to be programmed into two registers */ + /* No idea what happens if the registers are different */ + if (state->m_flip_8 & 0x40 && state->m_flip_22 & 0x40) + offset = 0x10000; + else + offset = 0; + + if(state->m_videomode & 0x20) + { + hirescol = state->m_col3bit; + lorescol = state->m_col7bit; + } + else if(state->m_videomode & 0x40) + { + hirescol = state->m_col4bit; + lorescol = state->m_col6bit; + } + else + { + hirescol = state->m_col4bit; + lorescol = state->m_col8bit; + } + + for (y = cliprect->min_y; y <= cliprect->max_y; ++y) + { + UINT16 y_offset = (y + state->m_v_scroll) * 256; + src = &state->m_video_ram[offset + y_offset]; + dest = BITMAP_ADDR32(bitmap, y, 0); + + for (x = cliprect->min_x; x <= cliprect->max_x / 2; ++x) + { + UINT8 x_offset = x + state->m_h_scroll; + UINT8 pen = *(src + x_offset); + + if ( ( state->m_videomode & 0x81 ) == 1 || (state->m_videomode & 0x80 && pen & 0x80) ) + { + *dest++ = screen->machine().pens[hirescol[pen & 0x0f]]; + *dest++ = screen->machine().pens[hirescol[(pen >> 4) & 0x0f]]; + } + else + { + *dest++ = screen->machine().pens[lorescol[pen]]; + *dest++ = screen->machine().pens[lorescol[pen]]; + } + } + } + + return 0; +} + +INLINE UINT8* blitter_get_addr(running_machine &machine, UINT32 addr) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + if (addr < 0x10000) + { + /* Is this region fixed? */ + return (UINT8*)(machine.region("user1")->base() + addr); + } + else if(addr < 0x20000) + { + addr &= 0xffff; + addr += (state->m_bank_data[0] & 1) ? 0x10000 : 0; + + return (UINT8*)(machine.region("user1")->base() + addr + ((state->m_bank_data[0] >> 1) * 0x20000)); + } + else if (addr >= 0x20000 && addr < 0x40000) + { + return (UINT8*)&state->m_video_ram[addr - 0x20000]; + } + else + { + return (UINT8*)&state->m_work_ram[addr - 0x40000]; + } +} + + +/* + This is based this on the Slipstream technical reference manual. + The Flare One blitter is a simpler design with slightly different parameters + and will require hardware tests to figure everything out correctly. +*/ +static void RunBlit(address_space *space) +{ +#define BLITPRG_READ(x) blitter.x = *(blitter_get_addr(space->machine(), blitter.program.addr++)) + + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + struct blitter_t &blitter = state->m_blitter; + int cycles_used = 0; + + + do + { + UINT8 srcdata = 0; + UINT8 dstdata = 0; + + /* Read the blitter command */ + BLITPRG_READ(source.addr0); + BLITPRG_READ(source.addr1); + BLITPRG_READ(source.addr2); + BLITPRG_READ(dest.addr0); + BLITPRG_READ(dest.addr1); + BLITPRG_READ(dest.addr2); + BLITPRG_READ(modectl); + BLITPRG_READ(compfunc); + BLITPRG_READ(outercnt); + BLITPRG_READ(innercnt); + BLITPRG_READ(step); + BLITPRG_READ(pattern); + +#if 0 + /* This debug is now wrong ! */ + if (DEBUG_BLITTER) + { + mame_printf_debug("\n%s:Blitter: Running command from 0x%.5x\n\n", device->machine().describe_context(), blitter.program.addr - 12); + mame_printf_debug("Command Reg %.2x", blitter.command); + mame_printf_debug(" %s %s %s %s %s %s %s\n", + blitter.command & CMD_RUN ? "RUN" : " ", + blitter.command & CMD_COLST ? "COLST" : " ", + blitter.command & CMD_PARRD ? "PARRD" : " ", + blitter.command & CMD_SRCUP ? "SRCUP" : " ", + blitter.command & CMD_DSTUP ? "DSTUP" : " "); + + mame_printf_debug("Src Address Byte 0 %.2x\n", blitter.source.addr0); + mame_printf_debug("Src Address Byte 1 %.2x\n", blitter.source.addr1); + mame_printf_debug("Src Control %.2x\n", blitter.source.addr2); + mame_printf_debug(" Src Address %.5x\n", blitter.source.addr & 0xfffff); + mame_printf_debug("Dest Address Byte 0 %.2x\n", blitter.dest.addr0); + mame_printf_debug("Dest Address Byte 1 %.2x\n", blitter.dest.addr1); + mame_printf_debug("Dest Control %.2x\n", blitter.dest.addr2); + mame_printf_debug(" Dst. Address %.5x\n", blitter.dest.addr & 0xfffff); + mame_printf_debug("Mode Control %.2x", blitter.modectl); + mame_printf_debug(" %s\n", blitter.modectl & MODE_BITTOBYTE ? "BIT_TO_BYTE" : ""); + + mame_printf_debug("Comp. and LFU %.2x\n", blitter.compfunc); + mame_printf_debug("Outer Loop Count %.2x (%d)\n", blitter.outercnt, blitter.outercnt); + mame_printf_debug("Inner Loop Count %.2x (%d)\n", blitter.innercnt, blitter.innercnt); + mame_printf_debug("Step Value %.2x\n", blitter.step); + mame_printf_debug("Pattern Byte %.2x\n", blitter.pattern); + } +#endif + + /* Ignore these writes */ + if (blitter.dest.addr == 0) + return; + + /* Begin outer loop */ + for (;;) + { + UINT8 innercnt = blitter.innercnt; + dstdata = blitter.pattern; + + if (blitter.command & CMD_LINEDRAW) + { + do + { + if (blitter.modectl & MODE_YFRAC) + { + if (blitter.modectl & MODE_SSIGN ) + blitter.dest.addr0--; + else + blitter.dest.addr0++; + } + else + { + if (blitter.modectl & MODE_DSIGN ) + blitter.dest.addr1--; + else + blitter.dest.addr1++; + } + if( blitter.source.addr0 < blitter.step ) + { + + blitter.source.addr0 -=blitter.step ; + blitter.source.addr0 +=blitter.source.addr1; + + if ( blitter.modectl & MODE_YFRAC ) + { + if (blitter.modectl & MODE_DSIGN ) + blitter.dest.addr1--; + else + blitter.dest.addr1++; + } + else + { + if (blitter.modectl & MODE_SSIGN ) + blitter.dest.addr0--; + else + blitter.dest.addr0++; + } + } + else + { + blitter.source.addr0 -=blitter.step; + } + + *blitter_get_addr(space->machine(), blitter.dest.addr) = blitter.pattern; + cycles_used++; + + } while (--innercnt); + } + else do + { + UINT8 inhibit = 0; + + /* TODO: Set this correctly */ + UINT8 result = blitter.pattern; + + if (LOOPTYPE == 3 && innercnt == blitter.innercnt) + { + srcdata = *(blitter_get_addr(space->machine(), blitter.source.addr & 0xfffff)); + blitter.source.loword++; + cycles_used++; + } + + /* Enable source address read and increment? */ + if (!(blitter.modectl & (MODE_BITTOBYTE | MODE_PALREMAP))) + { + if (LOOPTYPE == 0 || LOOPTYPE == 1) + { + srcdata = *(blitter_get_addr(space->machine(), blitter.source.addr & 0xfffff)); + cycles_used++; + + if (blitter.modectl & MODE_SSIGN) + blitter.source.loword-- ; + else + blitter.source.loword++; + + result = srcdata; + } + } + + /* Read destination pixel? */ + if (LOOPTYPE == 0) + { + dstdata = *blitter_get_addr(space->machine(), blitter.dest.addr & 0xfffff); + cycles_used++; + } + + /* Inhibit depending on the bit selected by the inner count */ + + /* Switch on comparator type? */ + if (blitter.modectl & MODE_BITTOBYTE) + { + inhibit = !(srcdata & (1 << (8 - innercnt))); + } + + if (blitter.compfunc & CMPFUNC_BEQ) + { + if (srcdata == blitter.pattern) + { + inhibit = 1; + + /* TODO: Resume from inhibit? */ + if (blitter.command & CMD_COLST) + return; + } + } + if (blitter.compfunc & CMPFUNC_LT) + { + /* Might be wrong */ + if ((srcdata & 0xc0) < (dstdata & 0xc0)) + { + inhibit = 1; + + /* TODO: Resume from inhibit? */ + if (blitter.command & CMD_COLST) + return; + } + } + if (blitter.compfunc & CMPFUNC_EQ) + { + if ((srcdata & 0xc0) == (dstdata & 0xc0)) + { + inhibit = 1; + + /* TODO: Resume from inhibit? */ + if (blitter.command & CMD_COLST) + return; + } + } + if (blitter.compfunc & CMPFUNC_GT) + { + /* Might be wrong */ + if ((srcdata & 0xc0) > (dstdata & 0xc0)) + { + inhibit = 1; + + /* TODO: Resume from inhibit? */ + if (blitter.command & CMD_COLST) + return; + } + } + + /* Write the data if not inhibited */ + if (!inhibit) + { + if (blitter.modectl == MODE_PALREMAP) + { + /* + In this mode, the source points to a 256 entry lookup table. + The existing destination pixel is used as a lookup + into the table and the colours is replaced. + */ + UINT8 dest = *blitter_get_addr(space->machine(), blitter.dest.addr); + UINT8 newcol = *(blitter_get_addr(space->machine(), (blitter.source.addr + dest) & 0xfffff)); + + *blitter_get_addr(space->machine(), blitter.dest.addr) = newcol; + cycles_used += 3; + } + else + { + UINT8 final_result = 0; + + if (blitter.compfunc & CMPFUNC_LOG3) + final_result |= result & dstdata; + + if (blitter.compfunc & CMPFUNC_LOG2) + final_result |= result & ~dstdata; + + if (blitter.compfunc & CMPFUNC_LOG1) + final_result |= ~result & dstdata; + + if (blitter.compfunc & CMPFUNC_LOG0) + final_result |= ~result & ~dstdata; + + *blitter_get_addr(space->machine(), blitter.dest.addr) = final_result; + cycles_used++; + } + } + + /* Update destination address */ + if (blitter.modectl & MODE_DSIGN) + blitter.dest.loword--; + else + blitter.dest.loword++; + + } while (--innercnt); + + if (!--blitter.outercnt) + { + break; + } + else + { + if (blitter.command & CMD_DSTUP) + blitter.dest.loword += blitter.step; + + if (blitter.command & CMD_SRCUP) + blitter.source.loword += blitter.step; + + if (blitter.command & CMD_PARRD) + { + BLITPRG_READ(innercnt); + BLITPRG_READ(step); + BLITPRG_READ(pattern); + } + } + } + + /* Read next command header */ + BLITPRG_READ(command); + + } while (blitter.command & CMD_RUN); + + /* Burn Z80 cycles while blitter is in operation */ + device_spin_until_time(&space->device(), attotime::from_nsec( (1000000000 / Z80_XTAL)*cycles_used * 2 ) ); +} + + +static READ8_HANDLER( ramdac_r ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + struct ramdac_t &ramdac = state->m_ramdac; + UINT8 val = 0xff; + + switch (offset & 3) + { + case 1: + { + UINT8 *count = &ramdac.count_r; + + if (*count == 0) + { + rgb_t color; + color = palette_get_color(space->machine(), ramdac.addr_r); + + ramdac.color_r[0] = RGB_RED(color); + ramdac.color_r[1] = RGB_GREEN(color); + ramdac.color_r[2] = RGB_BLUE(color); + } + + val = ramdac.color_r[*count]; + + /* 8bpp -> 6bpp */ + val = ((val & 0xc0) >> 2) | ((val >>2) & 0xf); + + if (++*count == 3) + { + *count = 0; + ramdac.addr_r++; + } + break; + } + default: + { + mame_printf_debug("Unhandled RAMDAC read (PC:%.4x)\n", cpu_get_previouspc(&space->device())); + } + } + + return val; +} + +static WRITE8_HANDLER( ramdac_w ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + struct ramdac_t &ramdac = state->m_ramdac; + + switch (offset & 3) + { + case 0: + { + ramdac.addr_w = data; + break; + } + case 1: + { + data &= 0x3f; + ramdac.color_w[ramdac.count_w] = pal6bit(data); + if (++ramdac.count_w == 3) + { + palette_set_color_rgb(space->machine(), ramdac.addr_w, ramdac.color_w[0], ramdac.color_w[1], ramdac.color_w[2]); + ramdac.count_w = 0; + ramdac.addr_w++; + } + break; + } + case 2: + { + ramdac.mask = data; + break; + } + case 3: + { + ramdac.addr_r = data; + break; + } + } +} + +/*************************************************************************** + + Flare One Register Map + + 01 Bank control for Z80 region 0x4000-0x7fff (16kB) WR + 02 Bank control for Z80 region 0x8000-0xbfff (16kB) WR + 03 Bank control for Z80 region 0xc000-0xffff (16kB) WR + + 06 Interrupt status....................................WR + 07 Interrupt ack.......................................WR + Writing here sets the line number that vertical interrupt is generated at. + cmd1, bit2 is the 9th bit of the line number + ???? Written with 0x21 + 08 cmd1 WR * bit 6 = screen select + bit2 = 9th bit of vertical interrupt line number + bit6 = 1 = select screen 1 else screen 0 + 09 cmd2 Linked with c001...............................W * bit 0 = 1 = hires + bit0=1=hi res else lo res (as long as bit7 is 0) + bit5=mask msb of each pixel + bit6=mask 2 msbits of each lores pixel + bit7=1=variable resolution - resolution is set by bit 7 of each vram byte. bit7=1=2 hires pixels + 0A ???? Written with 0 and 1...........................W + color of border + + 0B Horizontal frame buffer scroll .....................W + 0C Vertical frame buffer scroll .......................W + + 0D Colour hold colour..................................W + 0E Palette value for hi-res magenta....................W + 0F Palette value for hi-res yellow?....................W + 14 ....................................................W + + 18 Blitter program low byte............................WR + 19 Blitter program middle byte.........................W + 1A Blitter program high byte...........................W + 1B Blitter command?....................................W + 1C Blitter status?......................................R + 20 Blitter control register............................W + + 22 ???? Linked with C002...............................W + Mask of 20 + + Joystick: xxx1 11xx R + ? (polled on tight loop): x1xx xxxx R + + 40: ROM bank select.....................................W + +***************************************************************************/ + +static void update_irqs(running_machine &machine) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + int newstate = state->m_blitter_irq || state->m_vblank_irq || state->m_acia_irq; + + if (newstate != state->m_irq_state) + { + state->m_irq_state = newstate; + cputag_set_input_line(machine, "maincpu", 0, state->m_irq_state ? ASSERT_LINE : CLEAR_LINE); + } +} + +static READ8_HANDLER( chipset_r ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + UINT8 val = 0xff; + + switch(offset) + { + case 1: + case 2: + case 3: + { + val = state->m_bank_data[offset]; + break; + } + case 6: + { + /* TODO */ + val = state->m_vblank_irq << 4; + break; + } + case 7: + { + state->m_vblank_irq = 0; + val = 0x1; + + /* TODO */ + update_irqs(space->machine()); + break; + } + case 0x1C: + { + /* Blitter status ? */ + val = 0; + break; + } + case 0x20: + { + /* Seems correct - used during RLE pic decoding */ + val = state->m_blitter.dest.addr0; + break; + } + case 0x22: + { + val = 0x40 | input_port_read(space->machine(), "JOYSTICK"); + break; + } + default: + { + mame_printf_debug("Flare One unknown read: 0x%.2x (PC:0x%.4x)\n", offset, cpu_get_previouspc(&space->device())); + } + } + + return val; +} + +static WRITE8_HANDLER( chipset_w ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + switch (offset) + { + case 0x01: + case 0x02: + case 0x03: + { + if (data > 0x3f) + popmessage("%x: Unusual bank access (%x)\n", cpu_get_previouspc(&space->device()), data); + + data &= 0x3f; + state->m_bank_data[offset] = data; + z80_bank(space->machine(), offset, data); + break; + } + + case 0x08: + { + state->m_flip_8 = data; + break; + } + case 9: + state->m_videomode = data; + break; + + case 0x0B: + { + state->m_h_scroll = data; + break; + } + case 0x0C: + { + state->m_v_scroll = data; + break; + } + case 0x0E: + { + state->m_col4bit[5] = data; + state->m_col3bit[5] = data; + state->m_col3bit[5 + 8] = data; + break; + } + case 0x0f: + { + state->m_col4bit[6] = data; + state->m_col3bit[6] = data; + state->m_col3bit[6 + 8] = data; + break; + } + case 0x18: + { + state->m_blitter.program.addr0 = data; + break; + } + case 0x19: + { + state->m_blitter.program.addr1 = data; + break; + } + case 0x1A: + { + state->m_blitter.program.addr2 = data; + break; + } + case 0x20: + { + state->m_blitter.command = data; + + if (data & CMD_RUN) + RunBlit(space); + else + mame_printf_debug("Blitter stopped by IO.\n"); + + break; + } + case 0x22: + { + state->m_flip_22 = data; + break; + } + default: + { + mame_printf_debug("Flare One unknown write: 0x%.2x with 0x%.2x (PC:0x%.4x)\n", offset, data, cpu_get_previouspc(&space->device())); + } + } +} + +INLINE void z80_bank(running_machine &machine, int num, int data) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + static const char * const bank_names[] = { "bank1", "bank2", "bank3" }; + + if (data < 0x08) + { + UINT32 offset = ((state->m_bank_data[0] >> 1) * 0x20000) + ((0x4000 * data) ^ ((state->m_bank_data[0] & 1) ? 0 : 0x10000)); + + memory_set_bankptr(machine, bank_names[num - 1], machine.region("user1")->base() + offset); + } + else if (data < 0x10) + { + memory_set_bankptr(machine, bank_names[num - 1], &state->m_video_ram[(data - 0x08) * 0x4000]); + } + else + { + memory_set_bankptr(machine, bank_names[num - 1], &state->m_work_ram[(data - 0x10) * 0x4000]); + } +} + +static WRITE8_HANDLER( rombank_w ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + state->m_bank_data[0] = data; + z80_bank(space->machine(), 1, state->m_bank_data[1]); + z80_bank(space->machine(), 2, state->m_bank_data[2]); + z80_bank(space->machine(), 3, state->m_bank_data[3]); +} + + + +/*************************************************************************** + + Split into machine\cobra.c ! + + Alternatively chuck it all away and borrow the MESS implementation + because it's a million times better. + +***************************************************************************/ + +static void command_phase(struct fdc_t &fdc, UINT8 data); +static void exec_w_phase(UINT8 data); +//UINT8 exec_r_phase(void); + +/* + WD37C656C-PL (or equivalent) Floppy Disk Controller +*/ + +enum fdc_phase +{ + COMMAND, + EXECUTION_R, + EXECUTION_W, + RESULTS, +}; + +enum command +{ + SENSE_DRIVE_STATUS = 0, + READ_A_TRACK = 2, + SPECIFY = 3, + WRITE_DATA = 5, + READ_DATA = 6, + RECALIBRATE = 7, + SENSE_INTERRUPT_STATUS = 8, + WRITE_DELETED_DATA = 9, + READ_ID = 10, + FORMAT_TRACK = 13, + READ_DELETED_DATA = 14, + SEEK = 15, + SCAN_EQUAL = 17, + SCAN_LOW_OR_EQUAL = 25, + SCAN_HIGH_OR_EQUAL = 29 +}; + +static void reset_fdc(running_machine &machine) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + memset(&state->m_fdc, 0, sizeof(state->m_fdc)); + + state->m_fdc.MSR = 0x80; + state->m_fdc.phase = COMMAND; +} + +static READ8_HANDLER( fdctrl_r ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + UINT8 val = 0; + + val = state->m_fdc.MSR; + + return val; +} + +static READ8_HANDLER( fddata_r ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + struct fdc_t &fdc = state->m_fdc; + #define BPS 1024 + #define SPT 10 + #define BPT 1024*10 + + UINT8 val = 0; + + if (fdc.phase == EXECUTION_R) + { + switch (fdc.cmd[0] & 0x1f) + { + /* Specify */ + case READ_DATA: + { + if (fdc.setup_read) + { + fdc.track = fdc.cmd[2]; + fdc.side = fdc.cmd[3]; + fdc.sector = fdc.cmd[4]; + fdc.number = fdc.cmd[5]; + fdc.stop_track = fdc.cmd[6]; + //int GPL = fdc.cmd[7]; + //int DTL = fdc.cmd[8]; + + fdc.setup_read = 0; + fdc.byte_pos = 0; + } + + fdc.offset = (BPT * fdc.track*2) + (fdc.side ? BPT : 0) + (BPS * (fdc.sector-1)) + fdc.byte_pos++; + val = *(space->machine().region("user2")->base() + fdc.offset); + + /* Move on to next sector? */ + if (fdc.byte_pos == 1024) + { + fdc.byte_pos = 0; + + if (fdc.sector == fdc.stop_track || ++fdc.sector == 11) + { + /* End of read operation */ + fdc.MSR = 0xd0; + fdc.phase = RESULTS; + + fdc.results[0] = 0; + fdc.results[1] = 0; + fdc.results[2] = 0; + + fdc.results[3] = 0; + fdc.results[4] = 0; + fdc.results[5] = 0; + fdc.results[6] = 0; + } + } + break; + } + } + } + else if (fdc.phase == RESULTS) + { + val = fdc.results[fdc.res_cnt++]; + + if (fdc.res_cnt == fdc.res_len) + { + fdc.phase = COMMAND; + fdc.res_cnt = 0; + fdc.MSR &= ~0x40; + } + } + + return val; +} + +static WRITE8_HANDLER( fdctrl_w ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + struct fdc_t &fdc = state->m_fdc; + switch (fdc.phase) + { + case COMMAND: + { + command_phase(fdc, data); + break; + } + case EXECUTION_W: + { + exec_w_phase(data); + break; + } + default: + { + mame_printf_debug("Unknown FDC phase?!"); + } + } +} + +static void command_phase(struct fdc_t &fdc, UINT8 data) +{ + if (fdc.cmd_cnt == 0) + { + fdc.cmd[0] = data; + + fdc.cmd_cnt = 1; + + switch (data & 0x1f) + { + /* Specify */ + case READ_DATA: + { +// mame_printf_debug("Read data\n"); + fdc.cmd_len = 9; + fdc.res_len = 7; + fdc.next_phase = EXECUTION_R; + fdc.setup_read = 1; + break; + } + case SPECIFY: + { +// mame_printf_debug("Specify\n"); + fdc.cmd_len = 3; + fdc.res_len = 0; + fdc.next_phase = COMMAND; + break; + } + case RECALIBRATE: + { +// mame_printf_debug("Recalibrate\n"); + fdc.cmd_len = 2; + fdc.res_len = 0; + fdc.next_phase = COMMAND; + //fdc.MSR |= 0x40; + break; + } + case SENSE_INTERRUPT_STATUS: + { +// mame_printf_debug("Sense interrupt status\n"); + fdc.cmd_len = 1; + fdc.res_len = 2; + fdc.phase = RESULTS; + + fdc.results[0] = 0; + fdc.results[1] = 0; + + fdc.cmd_cnt = 0; + fdc.MSR |= 0x40; + break; + } + case SEEK: + { +// mame_printf_debug("Seek\n"); + fdc.cmd_len = 3; + fdc.res_len = 0; + fdc.next_phase = COMMAND; + break; + } + default: + { +// mame_printf_debug("%x\n",data & 0x1f); + } + } + } + else + { + fdc.cmd[fdc.cmd_cnt++] = data; + //mame_printf_debug(" %x\n",data); + } + + if (fdc.cmd_cnt == fdc.cmd_len) + { + fdc.phase = fdc.next_phase; + fdc.cmd_cnt = 0; + + if ((fdc.cmd[0] & 0x1f) == READ_DATA) + fdc.MSR = 0xf0; + } +} + +#ifdef UNUSED_FUNCTION +UINT8 exec_r_phase(void) +{ + return 0; +} +#endif + +static void exec_w_phase(UINT8 data) +{ +} + +#ifdef UNUSED_FUNCTION +UINT8 results_phase(void) +{ + return 0; +} + +WRITE8_HANDLER( fd_op_w ) +{ +} + +WRITE8_HANDLER( fd_ctrl_w ) +{ +} +#endif + +static MACHINE_RESET( bfcobra ) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + unsigned int pal; + + for (pal = 0; pal < 256; ++pal) + { + palette_set_color_rgb(machine, pal, pal3bit((pal>>5)&7), pal3bit((pal>>2)&7), pal2bit(pal&3)); + } + + state->m_bank_data[0] = 1; + memset(&state->m_ramdac, 0, sizeof(state->m_ramdac)); + reset_fdc(machine); + + state->m_irq_state = state->m_blitter_irq = state->m_vblank_irq = state->m_acia_irq = 0; +} + +/*************************************************************************** + + Cobra I/Viper Z80 Memory Map + +***************************************************************************/ + +static ADDRESS_MAP_START( z80_prog_map, AS_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x3fff) AM_ROMBANK("bank4") + AM_RANGE(0x4000, 0x7fff) AM_RAMBANK("bank1") + AM_RANGE(0x8000, 0xbfff) AM_RAMBANK("bank2") + AM_RANGE(0xc000, 0xffff) AM_RAMBANK("bank3") +ADDRESS_MAP_END + +static ADDRESS_MAP_START( z80_io_map, AS_IO, 8 ) +ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x23) AM_READWRITE(chipset_r, chipset_w) + AM_RANGE(0x24, 0x24) AM_DEVWRITE_MODERN("acia6850_0", acia6850_device, control_write) + AM_RANGE(0x25, 0x25) AM_DEVWRITE_MODERN("acia6850_0", acia6850_device, data_write) + AM_RANGE(0x26, 0x26) AM_DEVREAD_MODERN("acia6850_0", acia6850_device, status_read) + AM_RANGE(0x27, 0x27) AM_DEVREAD_MODERN("acia6850_0", acia6850_device, data_read) + AM_RANGE(0x30, 0x30) AM_READ(fdctrl_r) + AM_RANGE(0x31, 0x31) AM_READWRITE(fddata_r, fdctrl_w) + AM_RANGE(0x40, 0x40) AM_WRITE(rombank_w) + AM_RANGE(0x50, 0x53) AM_READWRITE(ramdac_r, ramdac_w) +ADDRESS_MAP_END + + +/*************************************************************************** + + Cobra I/Viper 6809 Memory Map + + Cobra I has these components: + + EF68B50P - For communication with Z80 + EF68B50P - For data retrieval + AY38912A + UPD7759C + BFM1090 (CF30056) - 'TEXAS' I/O chip, lamps and misc + BFM1095 (CF30057) - 'TEXAS' I/O chip, handles switches + BFM1071 - 6809 Address decoding and bus control + + /IRQ provided by EF68850P at IC38 + /FIRQ connected to meter current sensing circuitry + + TODO: Calculate watchdog timer period. + +***************************************************************************/ + +/* TODO */ +static READ8_HANDLER( int_latch_r ) +{ + return 2 | 1; +} + +/* TODO */ +static READ8_HANDLER( meter_r ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + return state->m_meter_latch; +} + +/* TODO: This is borrowed from Scorpion 1 */ +static WRITE8_HANDLER( meter_w ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + int i; + int changed = state->m_meter_latch ^ data; + + state->m_meter_latch = data; + + /* + When a meter is triggered, the current drawn is sensed. If a meter + is connected, the /FIRQ line will be pulsed. + */ + for (i = 0; i < 8; i++) + { + if (changed & (1 << i)) + { + MechMtr_update(i, data & (1 << i) ); + generic_pulse_irq_line(&space->device(), M6809_FIRQ_LINE); + } + } +} + +/* TODO */ +static READ8_HANDLER( latch_r ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + return state->m_mux_input; +} + +static WRITE8_HANDLER( latch_w ) +{ + bfcobra_state *state = space->machine().driver_data<bfcobra_state>(); + /* TODO: This is borrowed from Scorpion 1 */ + switch(offset) + { + case 0: + { + int changed = state->m_mux_outputlatch ^ data; + static const char *const port[] = { "STROBE0", "STROBE1", "STROBE2", "STROBE3", "STROBE4", "STROBE5", "STROBE6", "STROBE7" }; + + state->m_mux_outputlatch = data; + + /* Clock has changed */ + if (changed & 0x08) + { + int input_strobe = data & 0x7; + + /* Clock is low */ + if (!(data & 0x08)) + state->m_mux_input = input_port_read(space->machine(), port[input_strobe]); + } + break; + } + case 1: + { +// strobe_data_l = data; + break; + } + case 2: + { +// strobe_data_h = data; + break; + } + } +} + +static READ8_DEVICE_HANDLER( upd_r ) +{ + return 2 | upd7759_busy_r(device); +} + +static WRITE8_DEVICE_HANDLER( upd_w ) +{ + upd7759_reset_w(device, data & 0x80); + upd7759_port_w(device, 0, data & 0x3f); + upd7759_start_w(device, data & 0x40 ? 0 : 1); +} + +static ADDRESS_MAP_START( m6809_prog_map, AS_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x1fff) AM_RAM AM_SHARE("nvram") + AM_RANGE(0x2000, 0x2000) AM_RAM // W 'B', 6F + AM_RANGE(0x2200, 0x2200) AM_RAM // W 'F' + AM_RANGE(0x2600, 0x2600) AM_READWRITE(meter_r, meter_w) + AM_RANGE(0x2800, 0x2800) AM_RAM // W + AM_RANGE(0x2A00, 0x2A02) AM_READWRITE(latch_r, latch_w) + AM_RANGE(0x2E00, 0x2E00) AM_READ(int_latch_r) + AM_RANGE(0x3001, 0x3001) AM_DEVWRITE("aysnd", ay8910_data_w) + AM_RANGE(0x3201, 0x3201) AM_DEVWRITE("aysnd", ay8910_address_w) + AM_RANGE(0x3404, 0x3404) AM_DEVREADWRITE_MODERN("acia6850_1", acia6850_device, status_read, control_write) + AM_RANGE(0x3405, 0x3405) AM_DEVREADWRITE_MODERN("acia6850_1", acia6850_device, data_read, data_write) + AM_RANGE(0x3406, 0x3406) AM_DEVREADWRITE_MODERN("acia6850_2", acia6850_device, status_read, control_write) + AM_RANGE(0x3407, 0x3407) AM_DEVREADWRITE_MODERN("acia6850_2", acia6850_device, data_read, data_write) +// AM_RANGE(0x3408, 0x3408) AM_NOP +// AM_RANGE(0x340A, 0x340A) AM_NOP +// AM_RANGE(0x3600, 0x3600) AM_NOP + AM_RANGE(0x3801, 0x3801) AM_DEVREADWRITE("upd", upd_r, upd_w) + AM_RANGE(0x8000, 0xffff) AM_ROM + AM_RANGE(0xf000, 0xf000) AM_WRITENOP /* Watchdog */ +ADDRESS_MAP_END + +static INPUT_PORTS_START( bfcobra ) + PORT_START("STROBE0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_NAME("Coin: 10p") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_COIN2 ) PORT_NAME("Coin: 20p") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_COIN3 ) PORT_NAME("Coin: 50p") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_COIN4 ) PORT_NAME("Coin: 1 pound") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SERVICE ) PORT_NAME("Green Test?") PORT_CODE(KEYCODE_F1) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_SERVICE ) PORT_NAME("Red Test?") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_START("STROBE1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Pass") PORT_CODE(KEYCODE_A) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Continue") PORT_CODE(KEYCODE_S) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Collect") PORT_CODE(KEYCODE_D) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Bonus") PORT_CODE(KEYCODE_F) +// PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) +// PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) +// PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) + + PORT_START("STROBE2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("<A") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("<B") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_NAME("<C") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_NAME("A>") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_NAME("B>") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON10 ) PORT_NAME("C>") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("STROBE3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_INTERLOCK) PORT_NAME("Cash box door") PORT_CODE(KEYCODE_Y) PORT_TOGGLE + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SERVICE ) PORT_NAME("Front Door? (resets)") PORT_CODE(KEYCODE_T) PORT_TOGGLE + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SERVICE ) PORT_NAME("Refill Key") PORT_CODE(KEYCODE_R) PORT_TOGGLE + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("STROBE4") + PORT_BIT( 0xFF, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("STROBE5") + PORT_BIT( 0xFF, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("STROBE6") + PORT_DIPNAME( 0x01, 0x00, "DIL09" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "DIL10" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "DIL11" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "DIL12" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "DIL13" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "DIL14" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "DIL15" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("STROBE7") + PORT_DIPNAME( 0x01, 0x00, "DIL02" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "DIL03" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "DIL04" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "DIL05" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "DIL06" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "DIL07" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "DIL08" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) + + PORT_START("JOYSTICK") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) +INPUT_PORTS_END + +/* + Allocate work RAM and video RAM shared by the Z80 and chipset. +*/ +static void init_ram(running_machine &machine) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + /* 768kB work RAM */ + state->m_work_ram = auto_alloc_array_clear(machine, UINT8, 0xC0000); + + /* 128kB video RAM */ + state->m_video_ram = auto_alloc_array_clear(machine, UINT8, 0x20000); +} + +/* + What are the correct ACIA clocks ? +*/ + +static READ_LINE_DEVICE_HANDLER( z80_acia_rx_r ) +{ + bfcobra_state *state = device->machine().driver_data<bfcobra_state>(); + return state->m_m6809_z80_line; +} + +static WRITE_LINE_DEVICE_HANDLER( z80_acia_tx_w ) +{ + bfcobra_state *drvstate = device->machine().driver_data<bfcobra_state>(); + drvstate->m_z80_m6809_line = state; +} + +static WRITE_LINE_DEVICE_HANDLER( z80_acia_irq ) +{ + bfcobra_state *drvstate = device->machine().driver_data<bfcobra_state>(); + drvstate->m_acia_irq = state ? CLEAR_LINE : ASSERT_LINE; + update_irqs(device->machine()); +} + +static ACIA6850_INTERFACE( z80_acia_if ) +{ + 500000, + 500000, + DEVCB_LINE(z80_acia_rx_r), /*&m6809_z80_line,*/ + DEVCB_LINE(z80_acia_tx_w), /*&z80_m6809_line,*/ + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_LINE(z80_acia_irq) +}; + +static READ_LINE_DEVICE_HANDLER( m6809_acia_rx_r ) +{ + bfcobra_state *state = device->machine().driver_data<bfcobra_state>(); + return state->m_z80_m6809_line; +} + +static WRITE_LINE_DEVICE_HANDLER( m6809_acia_tx_w ) +{ + bfcobra_state *drvstate = device->machine().driver_data<bfcobra_state>(); + drvstate->m_m6809_z80_line = state; +} + +static WRITE_LINE_DEVICE_HANDLER( m6809_data_irq ) +{ + cputag_set_input_line(device->machine(), "audiocpu", M6809_IRQ_LINE, state ? CLEAR_LINE : ASSERT_LINE); +} + +static ACIA6850_INTERFACE( m6809_acia_if ) +{ + 500000, + 500000, + DEVCB_LINE(m6809_acia_rx_r),/*&z80_m6809_line,*/ + DEVCB_LINE(m6809_acia_tx_w),/*&m6809_z80_line,*/ + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL +}; + +static READ_LINE_DEVICE_HANDLER( data_acia_rx_r ) +{ + bfcobra_state *state = device->machine().driver_data<bfcobra_state>(); + return state->m_data_r; +} + +static WRITE_LINE_DEVICE_HANDLER( data_acia_tx_w ) +{ + bfcobra_state *drvstate = device->machine().driver_data<bfcobra_state>(); + drvstate->m_data_t = state; +} + + +static ACIA6850_INTERFACE( data_acia_if ) +{ + 500000, + 500000, + DEVCB_LINE(data_acia_rx_r),/*data_r,*/ + DEVCB_LINE(data_acia_tx_w),/*data_t,*/ + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_LINE(m6809_data_irq) +}; + + +/* TODO: Driver vs Machine Init */ +static DRIVER_INIT( bfcobra ) +{ + bfcobra_state *state = machine.driver_data<bfcobra_state>(); + /* + 6809 ROM address and data lines are scrambled. + This is the same scrambling as Scorpion 2. + */ + static const UINT8 datalookup[] = { 1, 3, 5, 6, 4, 2, 0, 7 }; + static const UINT8 addrlookup[] = { 11, 12, 0, 2, 3, 5, 7, 9, 8, 6, 1, 4, 10, 13, 14 }; + + UINT32 i; + UINT8 *rom; + UINT8 *tmp; + + tmp = auto_alloc_array(machine, UINT8, 0x8000); + rom = machine.region("audiocpu")->base() + 0x8000; + memcpy(tmp, rom, 0x8000); + + for (i = 0; i < 0x8000; i++) + { + UINT16 addr = 0; + UINT8 x; + UINT8 data = 0; + UINT8 val = tmp[i]; + + for (x = 0; x < 8; x ++) + data |= ((val >> x) & 1) << datalookup[x]; + + for (x = 0; x < 15; x ++) + addr |= ((i >> x) & 1) << addrlookup[x]; + + rom[addr] = data; + } + + auto_free(machine, tmp); + + init_ram(machine); + + state->m_bank_data[0] = 1; + state->m_bank_data[1] = 0; + state->m_bank_data[2] = 0; + state->m_bank_data[3] = 0; + + /* Fixed 16kB ROM region */ + memory_set_bankptr(machine, "bank4", machine.region("user1")->base()); + + /* TODO: Properly sort out the data ACIA */ + state->m_data_r = 1; + + /* Finish this */ + state_save_register_global(machine, state->m_z80_m6809_line); + state_save_register_global(machine, state->m_m6809_z80_line); + state_save_register_global(machine, state->m_data_r); + state_save_register_global(machine, state->m_data_t); + state_save_register_global(machine, state->m_h_scroll); + state_save_register_global(machine, state->m_v_scroll); + state_save_register_global(machine, state->m_flip_8); + state_save_register_global(machine, state->m_flip_22); + state_save_register_global(machine, state->m_z80_int); + state_save_register_global(machine, state->m_z80_inten); + state_save_register_global_array(machine, state->m_bank_data); + state_save_register_global_pointer(machine, state->m_work_ram, 0xc0000); + state_save_register_global_pointer(machine, state->m_video_ram, 0x20000); +} + +/* TODO */ +static INTERRUPT_GEN( timer_irq ) +{ + generic_pulse_irq_line(device, M6809_IRQ_LINE); +} + +/* TODO */ +static INTERRUPT_GEN( vblank_gen ) +{ + bfcobra_state *state = device->machine().driver_data<bfcobra_state>(); + state->m_vblank_irq = 1; + update_irqs(device->machine()); +} + +static MACHINE_CONFIG_START( bfcobra, bfcobra_state ) + MCFG_CPU_ADD("maincpu", Z80, Z80_XTAL) + MCFG_CPU_PROGRAM_MAP(z80_prog_map) + MCFG_CPU_IO_MAP(z80_io_map) + MCFG_CPU_VBLANK_INT("screen", vblank_gen) + + MCFG_CPU_ADD("audiocpu", M6809, M6809_XTAL) + MCFG_CPU_PROGRAM_MAP(m6809_prog_map) + MCFG_CPU_PERIODIC_INT(timer_irq, 1000) + + MCFG_NVRAM_ADD_0FILL("nvram") + + MCFG_MACHINE_RESET(bfcobra) + + /* TODO */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) + MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) + MCFG_SCREEN_SIZE(512, 256) + MCFG_SCREEN_VISIBLE_AREA(0, 512 - 1, 0, 256 - 1) + MCFG_SCREEN_UPDATE(bfcobra) + + MCFG_PALETTE_LENGTH(256) + + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("aysnd", AY8910, M6809_XTAL) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20) + + MCFG_SOUND_ADD("upd", UPD7759, UPD7759_STANDARD_CLOCK) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) + + MCFG_VIDEO_START(bfcobra) + + /* ACIAs */ + MCFG_ACIA6850_ADD("acia6850_0", z80_acia_if) + MCFG_ACIA6850_ADD("acia6850_1", m6809_acia_if) + MCFG_ACIA6850_ADD("acia6850_2", data_acia_if) +MACHINE_CONFIG_END + +/*************************************************************************** + + Game driver(s) + + Note: Two different versions of each 6809 ROM exist: standard and protocol + It appears sets can be a combination of disk images, 6809 and Z80 ROMs! + +***************************************************************************/ + +ROM_START( inquiztr ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "inq6809", 0x08000, 0x08000, CRC(ae996600) SHA1(f360399e77b81399d910770fa8106c196f04363c) ) + + ROM_REGION( 0x20000, "user1", 0 ) + ROM_LOAD( "9576002.bin", 0x00000, 0x10000, CRC(5b8c8a04) SHA1(af5328fee79c370f45bff36f534aaf50964b6900) ) + + ROM_REGION( 0x20000, "altuser1", 0 ) + ROM_LOAD( "9576028.bin", 0x10000, 0x10000, CRC(2d85682c) SHA1(baec47bff4b8beef5afbb737dc57b22bf93ebcf8) ) + + // these look quite different.. (like they belong together) but booting with these gives a checksum error (banking?) + ROM_LOAD( "inqvypp1", 0x00000, 0x010000, CRC(9bac8c6e) SHA1(15e24d60c2f3997e637694f60daa552b22628766) ) + ROM_LOAD( "inqvypp2", 0x10000, 0x010000, CRC(f9cd196c) SHA1(0ac31d87462cbee6f41e19aefe740d876910bdf5) ) + + ROM_REGION( 0x1c2000, "user2", 0 ) + ROM_LOAD( "inqdisk.img", 0x000000, 0x1c2000, NO_DUMP ) +ROM_END + + + + +ROM_START( escounts ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "esc12int", 0x08000, 0x08000, CRC(741a1fe6) SHA1(e741d0ae0d2f11036a358120381e4b0df4a560a1) ) + + ROM_REGION( 0x10000, "altrevs", 0 ) + ROM_LOAD( "bfm_esc.bin", 0x08000, 0x08000, CRC(27acb5a5) SHA1(da50d650ab6456d61d0fb7f89247f2040b4bb9a8) ) + ROM_LOAD( "escint1b", 0x08000, 0x08000, CRC(fde413c9) SHA1(18724a1b771ba4c72e571c356591c5be32948d7a) ) + + ROM_REGION( 0x10000, "user1", 0 ) + ROM_LOAD( "esccobpa", 0x00000, 0x10000, CRC(d8eadeb7) SHA1(9b94f1454e6a17bf8321b0ef4ddd0ed1a56150f7) ) + + /* 95-100-207 */ + ROM_REGION( 0x190000, "user2", 0 ) + ROM_LOAD( "escdisk4.img", 0x000000, 0x190000, CRC(24156e0f) SHA1(e163daa8effadd93ace2bc2ba1af0f4a190abd7f) ) +ROM_END + +ROM_START( trebltop ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "95740078.bin", 0x08000, 0x08000, CRC(aca1980b) SHA1(3d4ed1dc545cc80f56d7daa13028fb10a12a718b) ) + + ROM_REGION( 0x10000, "altrevs", 0 ) + ROM_LOAD( "ttopint", 0x08000, 0x08000, CRC(cc798f90) SHA1(c3f541ebbb3a2c29cc4f00bbd47e289bcff50ecb) ) + + ROM_REGION( 0x20000, "user1", 0 ) + ROM_LOAD( "95760031.bin", 0x00000, 0x10000, CRC(8e75edb8) SHA1(0aaa3834d5ac20f92bdf1f2b8f1eb71854469cbe) ) + ROM_LOAD( "95760021.bin", 0x10000, 0x10000, CRC(f42016c0) SHA1(7067d018cb4bdcfba777267fb01cddf44e4216c3) ) + + ROM_REGION( 0x1c2000, "user2", 0 ) + ROM_LOAD( "ttdisk1.img", 0x000000, 0x190000, CRC(b2003228) SHA1(5eb49f05137cdd404f22948d39aa79c1518c06eb) ) + + ROM_REGION( 0x20000, "upd", 0 ) + ROM_LOAD( "95000172.bin", 0x00000, 0x10000, CRC(e85367a5) SHA1(695fd95ddeecdb16602f7b0f075cf5128a2fb808) ) + ROM_LOAD( "95000173.bin", 0x10000, 0x10000, CRC(8bda2c5e) SHA1(79aab5a2af7a5add5fe9132dc13bcc3705c6faf3) ) +ROM_END + +ROM_START( beeline ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "bln12int.a", 0x08000, 0x08000, CRC(cb97905e) SHA1(9725156bf64e53a56bc0f90795d4b07db41d059e) ) + + ROM_REGION( 0x10000, "altrevs", 0 ) + ROM_LOAD( "beeint12", 0x8000, 0x008000, CRC(0a77d0be) SHA1(8e55e7b4eb85cc2521d8fdf7ede02131ed80372e) ) + + + ROM_REGION( 0x20000, "user1", 0 ) + ROM_LOAD( "blncob.pa", 0x00000, 0x10000, CRC(8abc0017) SHA1(ecf6e7a4021b35295eb9bb9aed1b88fff27ffbd1) ) + ROM_LOAD( "blncob.pb", 0x10000, 0x10000, CRC(feb121fe) SHA1(e83bfd6db00a3264e5076f257e261a1cb4605a83) ) + + ROM_REGION( 0x1c2000, "user2", 0 ) + ROM_LOAD( "beedisk.img", 0x000000, 0x1c2000, NO_DUMP ) +ROM_END + +ROM_START( quizvadr ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "q6809.bin", 0x08000, 0x8000, CRC(a74dff10) SHA1(87578694a022dc3d7ade9cc76d387c1ae5fc74d9) ) + + ROM_REGION( 0x10000, "altrevs", 0 ) + ROM_LOAD( "qvadrint", 0x08000, 0x08000, CRC(4c729943) SHA1(ab4e0fb6cfc66540ea1e9e36eebdf85f65c5fd2a) ) + + ROM_REGION( 0x200000, "user1", 0 ) + ROM_LOAD( "5947011r.0", 0x000000, 0x80000, CRC(cac43c97) SHA1(3af529cd0f8ec57dd3596f5bca7b9c74cff171e4) ) + ROM_LOAD( "5947011r.1", 0x080000, 0x80000, CRC(120018dc) SHA1(cd153d2b7ed535b04dbcaf189d2fc96fe3c5b466) ) + ROM_LOAD( "5947011r.2", 0x100000, 0x80000, CRC(689b3b5a) SHA1(ea32d18acfd380de822efff4f2c95ce9873a33a2) ) + ROM_LOAD( "5947011r.3", 0x180000, 0x80000, CRC(c38dafeb) SHA1(d693387a5c3cde34c9d581f81a08a5fbc6f753f2) ) + + ROM_REGION( 0x20000, "upd", 0 ) + ROM_LOAD( "185snd2.bin", 0x00000, 0x10000, CRC(e36eccc2) SHA1(cfd8ca4c71528ea4e229074016240681b6de37cd) ) + ROM_LOAD( "184snd1.bin", 0x10000, 0x10000, CRC(aac058e8) SHA1(39e59ad9524130fc3bd8d46e1aa78bc4daf04e39) ) +ROM_END + +ROM_START( qos ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "39360107.bin", 0x08000, 0x8000, CRC(20844655) SHA1(b67c7f7bbabf6d5139b8ad8cbb5f8cc3f28e9cc7) ) + + ROM_REGION( 0x200000, "user1", 0 ) + ROM_LOAD( "95000338.rm0", 0x000000, 0x80000, CRC(96918aae) SHA1(849ce7b8eccc89c45aacc840a73935f95788a141) ) + ROM_LOAD( "95000339.rm1", 0x080000, 0x80000, CRC(b4c6dcc0) SHA1(56d8761766dfbd5b0e71f8c3ca575e88f1bc9929) ) + ROM_LOAD( "95000340.rm2", 0x100000, 0x80000, CRC(66d121fd) SHA1(ac65cc0ac6b0a41e78a3159c21ee44f765bdb5c8) ) + ROM_LOAD( "95000341.rm3", 0x180000, 0x80000, CRC(ef13658d) SHA1(240bc589900214eac79c91a531f254a9ac2f4ef6) ) + + ROM_REGION( 0x20000, "upd", 0 ) + ROM_LOAD( "snd1_218.ic7", 0x00000, 0x10000, CRC(061f496d) SHA1(653d16454d909c034191813b37d14010da7258c6) ) + ROM_LOAD( "snd2_219.ic8", 0x10000, 0x10000, CRC(d7874a47) SHA1(5bbd4040c7c0299e8cc135e6c6cd05370b260e9b) ) +ROM_END + +ROM_START( qosa ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "qos_nondata_68f4.bin", 0x08000, 0x8000, CRC(5f40005a) SHA1(180017acf6b432bc135d1090099fdf99f1e3583a) ) + + ROM_REGION( 0x200000, "user1", 0 ) + ROM_LOAD( "95000338.rm0", 0x000000, 0x80000, CRC(96918aae) SHA1(849ce7b8eccc89c45aacc840a73935f95788a141) ) + ROM_LOAD( "95000339.rm1", 0x080000, 0x80000, CRC(b4c6dcc0) SHA1(56d8761766dfbd5b0e71f8c3ca575e88f1bc9929) ) + ROM_LOAD( "95000340.rm2", 0x100000, 0x80000, CRC(66d121fd) SHA1(ac65cc0ac6b0a41e78a3159c21ee44f765bdb5c8) ) + ROM_LOAD( "95000341.rm3", 0x180000, 0x80000, CRC(ef13658d) SHA1(240bc589900214eac79c91a531f254a9ac2f4ef6) ) + + ROM_REGION( 0x20000, "upd", 0 ) + ROM_LOAD( "snd1_218.ic7", 0x00000, 0x10000, CRC(061f496d) SHA1(653d16454d909c034191813b37d14010da7258c6) ) + ROM_LOAD( "snd2_219.ic8", 0x10000, 0x10000, CRC(d7874a47) SHA1(5bbd4040c7c0299e8cc135e6c6cd05370b260e9b) ) +ROM_END + +ROM_START( qosb ) + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "95740599.bin", 0x08000, 0x8000, CRC(bf1e321f) SHA1(51f18620f22ba2a1b110954284ddf00614d51a0e) ) + + ROM_REGION( 0x200000, "user1", 0 ) + ROM_LOAD( "rom0_306.bin", 0x000000, 0x80000, CRC(c26c8f83) SHA1(6949027e1fe241cbb2e1cbbce18e47bcb0d84550) ) + ROM_LOAD( "rom1_307.bin", 0x080000, 0x80000, CRC(94611c03) SHA1(81f545ff96ff3d44285315400da94d870c89f896) ) + ROM_LOAD( "rom2_308.bin", 0x100000, 0x80000, CRC(f5572726) SHA1(e109265c5571d21213a6f405a13459e7bc6699bc) ) + ROM_LOAD( "rom3_309.bin", 0x180000, 0x80000, CRC(1b5edfa8) SHA1(348488debd4aa52f064e351ed0c082274da1db2b) ) + + ROM_REGION( 0x20000, "upd", 0 ) + ROM_LOAD( "snd1_218.ic7", 0x00000, 0x10000, CRC(061f496d) SHA1(653d16454d909c034191813b37d14010da7258c6) ) + ROM_LOAD( "snd2_219.ic8", 0x10000, 0x10000, CRC(d7874a47) SHA1(5bbd4040c7c0299e8cc135e6c6cd05370b260e9b) ) + + /* there is a set close to this with + + ROM_LOAD( "qosrom0", 0x0000, 0x080000, CRC(4f150634) SHA1(beb1d3c212b189f3baa08fe454e83f30108be08e) ) + qosrom1 = rom1_307.bin qosb A Question of Sport (39-960-089) + ROM_LOAD( "qosrom2", 0x0000, 0x080000, CRC(c39737db) SHA1(ccfdb19dab3af064db44e6022248aef98749bc97) ) + ROM_LOAD( "qosrom3", 0x0000, 0x080000, CRC(785b8ff9) SHA1(61b31e0e60c31ecb4b179bfe008a96155d939709) ) + ROM_LOAD( "qossnd1", 0x0000, 0x010000, CRC(888a29f8) SHA1(0e5aa9db54e783708ece1e8c7bffb10d994ab384) ) + + but it simply looks like a bad dump, rom3 is an alt 'rom 2' and the others are mostly the same as qosb + */ + +ROM_END + + +GAME( 1989, inquiztr, 0 , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "Inquizitor", GAME_NOT_WORKING ) +GAME( 1990, escounts, 0 , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "Every Second Counts (39-360-053)", GAME_IMPERFECT_GRAPHICS ) +GAME( 1991, trebltop, 0 , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "Treble Top (39-360-070)", GAME_IMPERFECT_GRAPHICS ) +GAME( 1991, beeline, 0 , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "Beeline (39-360-075)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS ) +GAME( 1991, quizvadr, 0 , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "Quizvaders (39-360-078)", GAME_IMPERFECT_GRAPHICS ) +GAME( 1992, qos, 0 , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "A Question of Sport (set 1, 39-960-107)", GAME_IMPERFECT_GRAPHICS ) +GAME( 1992, qosa, qos , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "A Question of Sport (set 2, 39-960-099)", GAME_IMPERFECT_GRAPHICS ) +GAME( 1992, qosb, qos , bfcobra, bfcobra, bfcobra, ROT0, "BFM", "A Question of Sport (set 3, 39-960-089)", GAME_IMPERFECT_GRAPHICS ) |