summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/icatel.c
blob: 400fe02633eeb61b83bb3b230abb86c44bf2a72a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
// license:GPL-2.0+
// copyright-holders: Felipe Sanches
/***************************************************************************

	icatel - Brazilian public payphone
	manufactured by icatel http://www.icatel.com.br/

	Partial schematics (drawn based on PCB inspection) available at:
	https://github.com/garoa/Icatel/blob/master/doc/icatel.pdf

	Driver by Felipe Sanches <juca@members.fsf.org>

	Changelog:

	2014 DEC 14 [Felipe Sanches]:
	* Initial driver skeleton

***************************************************************************/

#include "emu.h"
#include "cpu/mcs51/mcs51.h"
#include "video/hd44780.h"
//#include "sound/speaker.h"
#include "rendlay.h"
#include "debugger.h"

class icatel_state : public driver_device
{
public:
	icatel_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_maincpu(*this, "maincpu")
		, m_lcdc(*this, "hd44780")
	{ }

	DECLARE_READ8_MEMBER(magic_string);

	DECLARE_READ8_MEMBER(ioport_r);
	DECLARE_WRITE8_MEMBER(ioport_w);

	DECLARE_READ8_MEMBER(cn8_extension_r);
	DECLARE_WRITE8_MEMBER(cn8_extension_w);

	DECLARE_READ8_MEMBER(modem_r);
	DECLARE_WRITE8_MEMBER(modem_w);

	DECLARE_READ8_MEMBER(ci8_r);
	DECLARE_WRITE8_MEMBER(ci8_w);

	DECLARE_READ8_MEMBER(ci15_r);
	DECLARE_WRITE8_MEMBER(ci15_w);

	DECLARE_READ8_MEMBER(ci16_r);
	DECLARE_WRITE8_MEMBER(ci16_w);

	DECLARE_DRIVER_INIT(icatel);
	DECLARE_PALETTE_INIT(icatel);

private:
	virtual void machine_start();
	virtual void machine_reset();
	required_device<cpu_device> m_maincpu;
	required_device<hd44780_device> m_lcdc;
};

static ADDRESS_MAP_START(i80c31_prg, AS_PROGRAM, 8, icatel_state)
	AM_RANGE(0x0000, 0x7FFF) AM_MIRROR(0x8000) AM_ROM
ADDRESS_MAP_END

static ADDRESS_MAP_START(i80c31_io, AS_IO, 8, icatel_state)
	AM_RANGE(0x0000,0x3FFF) AM_RAM
	AM_RANGE(0x8000,0x8002) AM_RAM /* HACK! */
	AM_RANGE(0x8040,0x8040) AM_MIRROR(0x3F1E) AM_DEVWRITE("hd44780", hd44780_device, control_write) // not sure yet. CI12 (73LS273)
	AM_RANGE(0x8041,0x8041) AM_MIRROR(0x3F1E) AM_DEVWRITE("hd44780", hd44780_device, data_write) // not sure yet.  CI12
	AM_RANGE(0x8060,0x8060) AM_MIRROR(0x3F1F) AM_READWRITE(ci8_r, ci8_w)
	AM_RANGE(0x8080,0x8080) AM_MIRROR(0x3F1F) AM_READWRITE(ci16_r, ci16_w) // card reader (?)
	AM_RANGE(0x80C0,0x80C0) AM_MIRROR(0x3F1F) AM_READWRITE(ci15_r, ci15_w) // 74LS244 (tristate buffer)
	AM_RANGE(0xC000,0xCFFF) AM_READWRITE(cn8_extension_r, cn8_extension_w)
	AM_RANGE(0xE000,0xEFFF) AM_READWRITE(modem_r, modem_w)
	AM_RANGE(MCS51_PORT_P0, MCS51_PORT_P3) AM_READWRITE(ioport_r, ioport_w)
ADDRESS_MAP_END

static ADDRESS_MAP_START(i80c31_data, AS_DATA, 8, icatel_state)
//	AM_RANGE(0x0056,0x005A) AM_READ(magic_string) /* This is a hack! */
ADDRESS_MAP_END

DRIVER_INIT_MEMBER( icatel_state, icatel )
{
}

void icatel_state::machine_start()
{
}

void icatel_state::machine_reset()
{
}

READ8_MEMBER(icatel_state::magic_string)
{
//	logerror("read: magic_string, offset=%04X\n", offset);
	char mstr[] = "TP-OK";
	return mstr[offset%5];
}

READ8_MEMBER(icatel_state::ioport_r)
{
	switch (offset%4)
	{
		case 0: return 0xff;
		case 1:	return 0x7f;
		case 2: return 0xff;
		case 3: return 0xff;
	}
	return 0;
}

WRITE8_MEMBER(icatel_state::ioport_w)
{
}

//----------------------------------------

READ8_MEMBER(icatel_state::cn8_extension_r)
{
	/* TODO: Implement-me! */
	logerror("read: cn8_extension\n");
	return 0;
}

WRITE8_MEMBER(icatel_state::cn8_extension_w)
{
	/* TODO: Implement-me! */
	logerror("write: cn8_extension [%02x]\n", data);
}

//----------------------------------------

READ8_MEMBER(icatel_state::modem_r)
{
	/* TODO: Implement-me! */
	logerror("read: modem\n");
	return 0;
}

WRITE8_MEMBER(icatel_state::modem_w)
{
	/* TODO: Implement-me! */
	logerror("write: modem [%02x]\n", data);
}

//----------------------------------------

READ8_MEMBER(icatel_state::ci8_r)
{
	/* TODO: Implement-me! */
	logerror("read: ci8\n");
	return 0;
}

WRITE8_MEMBER(icatel_state::ci8_w)
{
	/* TODO: Implement-me! */
	logerror("write: ci8 [%02x]\n", data);
}

//----------------------------------------

READ8_MEMBER(icatel_state::ci15_r)
{
	/* TODO: Implement-me! */
//	debugger_break(machine());
//	logerror("read: ci15\n");
	return (1 << 3) | (1 << 0);
}

WRITE8_MEMBER(icatel_state::ci15_w)
{
	/* TODO: Implement-me! */
	logerror("write: ci15 [%02x]\n", data);
}

//----------------------------------------

READ8_MEMBER(icatel_state::ci16_r)
{
	/* TODO: Implement-me! */
	// seems to be the card reader.
	logerror("read: ci16\n");
	return 0;
}

WRITE8_MEMBER(icatel_state::ci16_w)
{
	/* TODO: Implement-me! */
	// seems to be the card reader.
	logerror("write: ci16 [%02x]\n", data);
}

//----------------------------------------

PALETTE_INIT_MEMBER(icatel_state, icatel)
{
	palette.set_pen_color(0, rgb_t(138, 146, 148));
	palette.set_pen_color(1, rgb_t(92, 83, 88));
}

static const gfx_layout prot_charlayout =
{
	5, 8,                   /* 5 x 8 characters */
	256,                    /* 256 characters */
	1,                      /* 1 bits per pixel */
	{ 0 },                  /* no bitplanes */
	{ 3, 4, 5, 6, 7},
	{ 0, 8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8},
	8*8                     /* 8 bytes */
};

static GFXDECODE_START( icatel )
	GFXDECODE_ENTRY( "hd44780:cgrom", 0x0000, prot_charlayout, 0, 1 )
GFXDECODE_END

static HD44780_PIXEL_UPDATE(icatel_pixel_update)
{
	if ( pos < 16 && line==0 )
	{
		bitmap.pix16(y, pos*6 + x) = state;
	}

	if ( pos >= 64 && pos < 80 && line==0 )
	{
		bitmap.pix16(y+9,(pos-64)*6 + x) = state;
	}
}

static MACHINE_CONFIG_START( icatel, icatel_state )
	/* basic machine hardware */
	MCFG_CPU_ADD("maincpu", I80C31, XTAL_2_097152MHz)
	MCFG_CPU_PROGRAM_MAP(i80c31_prg)
	MCFG_CPU_DATA_MAP(i80c31_data)
	MCFG_CPU_IO_MAP(i80c31_io)

	/* video hardware */
	MCFG_SCREEN_ADD("screen", LCD)
	MCFG_SCREEN_REFRESH_RATE(50)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
	MCFG_SCREEN_UPDATE_DEVICE("hd44780", hd44780_device, screen_update)
	MCFG_SCREEN_SIZE(6*16, 9*2)
	MCFG_SCREEN_VISIBLE_AREA(0, 6*16-1, 0, 9*2-1)
	MCFG_SCREEN_PALETTE("palette")

	MCFG_DEFAULT_LAYOUT(layout_lcd)
	MCFG_PALETTE_ADD("palette", 2)
	MCFG_PALETTE_INIT_OWNER(icatel_state, icatel)
	MCFG_GFXDECODE_ADD("gfxdecode", "palette", icatel)

	MCFG_HD44780_ADD("hd44780")
	MCFG_HD44780_LCD_SIZE(2, 16)
	MCFG_HD44780_PIXEL_UPDATE_CB(icatel_pixel_update)
MACHINE_CONFIG_END

ROM_START( icatel )
	ROM_REGION( 0x8000, "maincpu", 0 )
	ROM_LOAD( "icatel_tpci_em._4_v16.05.ci14",  0x00000, 0x8000, CRC(d310586e) SHA1(21736ad5a06cf9695f8cc5ff2dc2d19b101504f5) )
ROM_END

/*    YEAR  NAME      PARENT  COMPAT  MACHINE     INPUT     CLASS         INIT    COMPANY  FULLNAME                       FLAGS */
COMP( 1995, icatel,   0,      0,      icatel,     0,        icatel_state, icatel, "Icatel", "TPCI (Brazilian public payphone)",    GAME_IMPERFECT_GRAPHICS | GAME_NO_SOUND)
/*The hardware was clearly manufactured in 1995. There's no evindence of the actual date of the firmware.*/
11 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858
// license:BSD-3-Clause
// copyright-holders:Philip Bennett, Anonymous
/******************************************************************************

    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 "cpu/m6809/m6809.h"
#include "cpu/z80/z80.h"
#include "machine/6850acia.h"
#include "machine/clock.h"
#include "machine/meters.h"
#include "machine/nvram.h"
#include "sound/ay8910.h"
#include "sound/upd7759.h"
#include "video/ramdac.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"


/*
    Defines
*/
#define Z80_XTAL    5910000     /* Unconfirmed */
#define M6809_XTAL  4000000     /* Unconfirmed */



/***************************************************************************

    Split into video\cobra.c !

***************************************************************************/

union ADDR_REG
{
#ifdef LSB_FIRST
	struct { uint16_t loword, hiword ; } as16bit;
	struct { uint8_t addr0, addr1, addr2; } as8bit;
#else
	struct { uint16_t hiword, loword ; } as16bit;
	struct { uint8_t addr2, addr1, addr0; } as8bit;
#endif
	uint32_t addr;
};

/* 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 bf_blitter_t
{
	ADDR_REG    program;

	uint8_t       control;
	uint8_t       status;

	uint8_t       command;
	ADDR_REG    source;
	ADDR_REG    dest;
	uint8_t       modectl;
	uint8_t       compfunc;
	uint8_t       outercnt;

	uint8_t       innercnt;
	uint8_t       step;
	uint8_t       pattern;
};

#define LOOPTYPE ( ( blitter.command&0x60 ) >> 5 )

struct fdc_t
{
	uint8_t   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_t   cmd[10];
	uint8_t   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),
		m_maincpu(*this, "maincpu"),
		m_audiocpu(*this, "audiocpu"),
		m_acia6850_0(*this, "acia6850_0"),
		m_acia6850_1(*this, "acia6850_1"),
		m_acia6850_2(*this, "acia6850_2"),
		m_upd7759(*this, "upd"),
		m_palette(*this, "palette"),
		m_meters(*this, "meters")
	{
	}

	void init_bfcobra();
	void bfcobra(machine_config &config);

protected:
	DECLARE_READ8_MEMBER(chipset_r);
	DECLARE_WRITE8_MEMBER(chipset_w);
	DECLARE_WRITE8_MEMBER(rombank_w);
	DECLARE_READ8_MEMBER(fdctrl_r);
	DECLARE_READ8_MEMBER(fddata_r);
	DECLARE_WRITE8_MEMBER(fdctrl_w);
	DECLARE_READ8_MEMBER(int_latch_r);
	DECLARE_READ8_MEMBER(meter_r);
	DECLARE_WRITE8_MEMBER(meter_w);
	DECLARE_READ8_MEMBER(latch_r);
	DECLARE_WRITE8_MEMBER(latch_w);
	DECLARE_READ8_MEMBER(upd_r);
	DECLARE_WRITE8_MEMBER(upd_w);
	DECLARE_WRITE_LINE_MEMBER(z80_acia_irq);
	DECLARE_WRITE_LINE_MEMBER(m6809_data_irq);
	DECLARE_WRITE_LINE_MEMBER(data_acia_tx_w);
	DECLARE_WRITE_LINE_MEMBER(write_acia_clock);
	virtual void machine_reset() override;
	virtual void video_start() override;
	uint32_t screen_update_bfcobra(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
	INTERRUPT_GEN_MEMBER(timer_irq);
	INTERRUPT_GEN_MEMBER(vblank_gen);
	void RunBlit(address_space &space);
	void update_irqs();
	void reset_fdc();
	void exec_w_phase(uint8_t data);
	void init_ram();
	void command_phase(struct fdc_t &fdc, uint8_t data);
	inline uint8_t* blitter_get_addr(uint32_t addr);
	inline void z80_bank(int num, int data);

	void m6809_prog_map(address_map &map);
	void ramdac_map(address_map &map);
	void z80_io_map(address_map &map);
	void z80_prog_map(address_map &map);

private:
	uint8_t m_bank_data[4];
	std::unique_ptr<uint8_t[]> m_work_ram;
	std::unique_ptr<uint8_t[]> m_video_ram;
	uint8_t m_h_scroll;
	uint8_t m_v_scroll;
	uint8_t m_flip_8;
	uint8_t m_flip_22;
	uint8_t m_videomode;
	uint8_t m_data_r;
	uint8_t m_data_t;
	int m_irq_state;
	int m_acia_irq;
	int m_vblank_irq;
	int m_blitter_irq;
	uint8_t m_z80_int;
	uint8_t m_z80_inten;
	uint32_t m_meter_latch;
	uint32_t m_mux_input;
	uint32_t m_mux_outputlatch;
	uint8_t m_col4bit[16];
	uint8_t m_col3bit[16];
	uint8_t m_col8bit[256];
	uint8_t m_col7bit[256];
	uint8_t m_col6bit[256];
	struct bf_blitter_t m_blitter;
	struct fdc_t m_fdc;
	required_device<cpu_device> m_maincpu;
	required_device<cpu_device> m_audiocpu;
	required_device<acia6850_device> m_acia6850_0;
	required_device<acia6850_device> m_acia6850_1;
	required_device<acia6850_device> m_acia6850_2;
	required_device<upd7759_device> m_upd7759;
	required_device<palette_device> m_palette;
	required_device<meters_device> m_meters;
};


static const uint8_t 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_t 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_t col76index[] = {0, 2, 4, 7};


void bfcobra_state::video_start()
{
	int i;

	memcpy(m_col4bit, col4bit_default, sizeof(m_col4bit));
	memcpy(m_col3bit, col3bit_default, sizeof(m_col3bit));
	for (i = 0; i < 256; ++i)
	{
		uint8_t col;

		m_col8bit[i] = i;
		col = i & 0x7f;
		col = (col & 0x1f) | (col76index[ ( (col & 0x60) >> 5 ) & 3] << 5);
		m_col7bit[i] = col;

		col = (col & 3) | (col76index[( (col & 0x0c) >> 2) & 3] << 2 ) |
				(col76index[( (col & 0x30) >> 4) & 3] << 5 );
		m_col6bit[i] = col;
	}
}

uint32_t bfcobra_state::screen_update_bfcobra(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	int x, y;
	uint8_t  *src;
	uint32_t *dest;
	uint32_t offset;
	uint8_t *hirescol;
	uint8_t *lorescol;

	/* Select screen has to be programmed into two registers */
	/* No idea what happens if the registers are different */
	if (m_flip_8 & 0x40 && m_flip_22 & 0x40)
		offset = 0x10000;
	else
		offset = 0;

	if(m_videomode & 0x20)
	{
		hirescol = m_col3bit;
		lorescol = m_col7bit;
	}
	else if(m_videomode & 0x40)
	{
		hirescol = m_col4bit;
		lorescol = m_col6bit;
	}
	else
	{
		hirescol = m_col4bit;
		lorescol = m_col8bit;
	}

	for (y = cliprect.top(); y <= cliprect.bottom(); ++y)
	{
		uint16_t y_offset = (y + m_v_scroll) * 256;
		src = &m_video_ram[offset + y_offset];
		dest = &bitmap.pix32(y);

		for (x = cliprect.left(); x <= cliprect.right() / 2; ++x)
		{
			uint8_t x_offset = x + m_h_scroll;
			uint8_t pen = *(src + x_offset);

			if ( ( m_videomode & 0x81 ) == 1 || (m_videomode & 0x80 && pen & 0x80) )
			{
				*dest++ = m_palette->pen(hirescol[pen & 0x0f]);
				*dest++ = m_palette->pen(hirescol[(pen >> 4) & 0x0f]);
			}
			else
			{
				*dest++ = m_palette->pen(lorescol[pen]);
				*dest++ = m_palette->pen(lorescol[pen]);
			}
		}
	}

	return 0;
}

uint8_t* bfcobra_state::blitter_get_addr(uint32_t addr)
{
	if (addr < 0x10000)
	{
		/* Is this region fixed? */
		return (uint8_t*)(memregion("user1")->base() + addr);
	}
	else if(addr < 0x20000)
	{
		addr &= 0xffff;
		addr += (m_bank_data[0] & 1) ? 0x10000 : 0;

		return (uint8_t*)(memregion("user1")->base() + addr + ((m_bank_data[0] >> 1) * 0x20000));
	}
	else if (addr >= 0x20000 && addr < 0x40000)
	{
		return (uint8_t*)&m_video_ram[addr - 0x20000];
	}
	else
	{
		return (uint8_t*)&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.
*/
void bfcobra_state::RunBlit(address_space &space)
{
#define BLITPRG_READ(x)     blitter.x = *(blitter_get_addr(blitter.program.addr++))

	struct bf_blitter_t &blitter = m_blitter;
	int cycles_used = 0;


	do
	{
		uint8_t srcdata = 0;
		uint8_t dstdata = 0;

		/* Read the blitter command */
		BLITPRG_READ(source.as8bit.addr0);
		BLITPRG_READ(source.as8bit.addr1);
		BLITPRG_READ(source.as8bit.addr2);
		BLITPRG_READ(dest.as8bit.addr0);
		BLITPRG_READ(dest.as8bit.addr1);
		BLITPRG_READ(dest.as8bit.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)
		{
			osd_printf_debug("\n%s:Blitter: Running command from 0x%.5x\n\n", device->machine().describe_context().c_str(), blitter.program.addr - 12);
			osd_printf_debug("Command Reg         %.2x",   blitter.command);
			osd_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" : "     ");

			osd_printf_debug("Src Address Byte 0  %.2x\n", blitter.source.as8bit.addr0);
			osd_printf_debug("Src Address Byte 1  %.2x\n", blitter.source.as8bit.addr1);
			osd_printf_debug("Src Control         %.2x\n", blitter.source.as8bit.addr2);
			osd_printf_debug("  Src Address       %.5x\n", blitter.source.addr & 0xfffff);
			osd_printf_debug("Dest Address Byte 0 %.2x\n", blitter.dest.as8bit.addr0);
			osd_printf_debug("Dest Address Byte 1 %.2x\n", blitter.dest.as8bit.addr1);
			osd_printf_debug("Dest Control        %.2x\n", blitter.dest.as8bit.addr2);
			osd_printf_debug("  Dst. Address      %.5x\n", blitter.dest.addr & 0xfffff);
			osd_printf_debug("Mode Control        %.2x",   blitter.modectl);
			osd_printf_debug("     %s\n", blitter.modectl & MODE_BITTOBYTE ? "BIT_TO_BYTE" : "");

			osd_printf_debug("Comp. and LFU       %.2x\n", blitter.compfunc);
			osd_printf_debug("Outer Loop Count    %.2x (%d)\n", blitter.outercnt, blitter.outercnt);
			osd_printf_debug("Inner Loop Count    %.2x (%d)\n", blitter.innercnt, blitter.innercnt);
			osd_printf_debug("Step Value          %.2x\n", blitter.step);
			osd_printf_debug("Pattern Byte        %.2x\n", blitter.pattern);
		}
#endif

		/* Ignore these writes */
		if (blitter.dest.addr == 0)
			return;

		/* Begin outer loop */
		for (;;)
		{
			uint8_t innercnt = blitter.innercnt;
			dstdata = blitter.pattern;

			if (blitter.command & CMD_LINEDRAW)
			{
				do
				{
					if (blitter.modectl & MODE_YFRAC)
					{
						if (blitter.modectl & MODE_SSIGN )
							blitter.dest.as8bit.addr0--;
						else
							blitter.dest.as8bit.addr0++;
					}
					else
					{
						if (blitter.modectl & MODE_DSIGN )
							blitter.dest.as8bit.addr1--;
						else
							blitter.dest.as8bit.addr1++;
					}
					if( blitter.source.as8bit.addr0 < blitter.step )
					{
						blitter.source.as8bit.addr0 -= blitter.step ;
						blitter.source.as8bit.addr0 += blitter.source.as8bit.addr1;

						if ( blitter.modectl & MODE_YFRAC )
						{
							if (blitter.modectl & MODE_DSIGN )
								blitter.dest.as8bit.addr1--;
							else
								blitter.dest.as8bit.addr1++;
						}
						else
						{
							if (blitter.modectl & MODE_SSIGN )
								blitter.dest.as8bit.addr0--;
							else
								blitter.dest.as8bit.addr0++;
						}
					}
					else
					{
						blitter.source.as8bit.addr0 -= blitter.step;
					}

					*blitter_get_addr( blitter.dest.addr) = blitter.pattern;
					cycles_used++;

				} while (--innercnt);
			}
			else do
			{
				uint8_t   inhibit = 0;

				/* TODO: Set this correctly */
				uint8_t   result = blitter.pattern;

				if (LOOPTYPE == 3 && innercnt == blitter.innercnt)
				{
					srcdata = *(blitter_get_addr( blitter.source.addr & 0xfffff));
					blitter.source.as16bit.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( blitter.source.addr & 0xfffff));
						cycles_used++;

						if (blitter.modectl & MODE_SSIGN)
							blitter.source.as16bit.loword-- ;
						else
							blitter.source.as16bit.loword++;

						result = srcdata;
					}
				}

				/* Read destination pixel? */
				if (LOOPTYPE == 0)
				{
					dstdata = *blitter_get_addr( 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_t dest = *blitter_get_addr( blitter.dest.addr);
						uint8_t newcol = *(blitter_get_addr( (blitter.source.addr + dest) & 0xfffff));

						*blitter_get_addr( blitter.dest.addr) = newcol;
						cycles_used += 3;
					}
					else
					{
						uint8_t 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( blitter.dest.addr) = final_result;
						cycles_used++;
					}
				}

				/* Update destination address */
				if (blitter.modectl & MODE_DSIGN)
					blitter.dest.as16bit.loword--;
				else
					blitter.dest.as16bit.loword++;

			} while (--innercnt);

			if (!--blitter.outercnt)
			{
				break;
			}
			else
			{
				if (blitter.command & CMD_DSTUP)
					blitter.dest.as16bit.loword += blitter.step;

				if (blitter.command & CMD_SRCUP)
					blitter.source.as16bit.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 */
	space.device().execute().spin_until_time(attotime::from_nsec( (1000000000 / Z80_XTAL)*cycles_used * 2 ) );
}

/***************************************************************************

    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

***************************************************************************/

void bfcobra_state::update_irqs()
{
	int newstate = m_blitter_irq || m_vblank_irq || m_acia_irq;

	if (newstate != m_irq_state)
	{
		m_irq_state = newstate;
		m_maincpu->set_input_line(0, m_irq_state ? ASSERT_LINE : CLEAR_LINE);
	}
}

READ8_MEMBER(bfcobra_state::chipset_r)
{
	uint8_t val = 0xff;

	switch(offset)
	{
		case 1:
		case 2:
		case 3:
		{
			val = m_bank_data[offset];
			break;
		}
		case 6:
		{
			/* TODO */
			val = m_vblank_irq << 4;
			break;
		}
		case 7:
		{
			m_vblank_irq = 0;
			val = 0x1;

			/* TODO */
			update_irqs();
			break;
		}
		case 0x1C:
		{
			/* Blitter status ? */
			val = 0;
			break;
		}
		case 0x20:
		{
			/* Seems correct - used during RLE pic decoding */
			val = m_blitter.dest.as8bit.addr0;
			break;
		}
		case 0x22:
		{
			val = 0x40 | ioport("JOYSTICK")->read();
			break;
		}
		default:
		{
			osd_printf_debug("Flare One unknown read: 0x%.2x (PC:0x%.4x)\n", offset, m_maincpu->pcbase());
		}
	}

	return val;
}

WRITE8_MEMBER(bfcobra_state::chipset_w)
{
	switch (offset)
	{
		case 0x01:
		case 0x02:
		case 0x03:
		{
			if (data > 0x3f)
				popmessage("%x: Unusual bank access (%x)\n", m_maincpu->pcbase(), data);

			data &= 0x3f;
			m_bank_data[offset] = data;
			z80_bank(offset, data);
			break;
		}

		case 0x08:
		{
			m_flip_8 = data;
			break;
		}
		case 9:
			m_videomode = data;
			break;

		case 0x0B:
		{
			m_h_scroll = data;
			break;
		}
		case 0x0C:
		{
			m_v_scroll = data;
			break;
		}
		case 0x0E:
		{
			m_col4bit[5] = data;
			m_col3bit[5] = data;
			m_col3bit[5 + 8] = data;
			break;
		}
		case 0x0f:
		{
			m_col4bit[6] = data;
			m_col3bit[6] = data;
			m_col3bit[6 + 8] = data;
			break;
		}
		case 0x18:
		{
			m_blitter.program.as8bit.addr0 = data;
			break;
		}
		case 0x19:
		{
			m_blitter.program.as8bit.addr1 = data;
			break;
		}
		case 0x1A:
		{
			m_blitter.program.as8bit.addr2 = data;
			break;
		}
		case 0x20:
		{
			m_blitter.command = data;

			if (data & CMD_RUN)
				RunBlit(space);
			else
				osd_printf_debug("Blitter stopped by IO.\n");

			break;
		}
		case 0x22:
		{
			m_flip_22 = data;
			break;
		}
		default:
		{
			osd_printf_debug("Flare One unknown write: 0x%.2x with 0x%.2x (PC:0x%.4x)\n", offset, data, m_maincpu->pcbase());
		}
	}
}

void bfcobra_state::z80_bank(int num, int data)
{
	static const char * const bank_names[] = { "bank1", "bank2", "bank3" };

	if (data < 0x08)
	{
		uint32_t offset = ((m_bank_data[0] >> 1) * 0x20000) + ((0x4000 * data) ^ ((m_bank_data[0] & 1) ? 0 : 0x10000));

		membank(bank_names[num - 1])->set_base(memregion("user1")->base() + offset);
	}
	else if (data < 0x10)
	{
		membank(bank_names[num - 1])->set_base(&m_video_ram[(data - 0x08) * 0x4000]);
	}
	else
	{
		membank(bank_names[num - 1])->set_base(&m_work_ram[(data - 0x10) * 0x4000]);
	}
}

WRITE8_MEMBER(bfcobra_state::rombank_w)
{
	m_bank_data[0] = data;
	z80_bank(1, m_bank_data[1]);
	z80_bank(2, m_bank_data[2]);
	z80_bank(3, 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.

***************************************************************************/


/*
    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
};

void bfcobra_state::reset_fdc()
{
	memset(&m_fdc, 0, sizeof(m_fdc));

	m_fdc.MSR = 0x80;
	m_fdc.phase = COMMAND;
}

READ8_MEMBER(bfcobra_state::fdctrl_r)
{
	uint8_t val = 0;

	val = m_fdc.MSR;

	return val;
}

READ8_MEMBER(bfcobra_state::fddata_r)
{
	struct fdc_t &fdc = m_fdc;
	#define BPS     1024
	#define SPT     10
	#define BPT     1024*10

	uint8_t 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 = *(memregion("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;
}

WRITE8_MEMBER(bfcobra_state::fdctrl_w)
{
	struct fdc_t &fdc = m_fdc;
	switch (fdc.phase)
	{
		case COMMAND:
		{
			command_phase(fdc, data);
			break;
		}
		case EXECUTION_W:
		{
			exec_w_phase(data);
			break;
		}
		default:
		{
			osd_printf_debug("Unknown FDC phase?!");
		}
	}
}

void bfcobra_state::command_phase(struct fdc_t &fdc, uint8_t data)
{
	if (fdc.cmd_cnt == 0)
	{
		fdc.cmd[0] = data;

		fdc.cmd_cnt = 1;

		switch (data & 0x1f)
		{
			/* Specify */
			case READ_DATA:
			{
//              osd_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:
			{
//              osd_printf_debug("Specify\n");
				fdc.cmd_len = 3;
				fdc.res_len = 0;
				fdc.next_phase = COMMAND;
				break;
			}
			case RECALIBRATE:
			{
//              osd_printf_debug("Recalibrate\n");
				fdc.cmd_len = 2;
				fdc.res_len = 0;
				fdc.next_phase = COMMAND;
				//fdc.MSR |= 0x40;
				break;
			}
			case SENSE_INTERRUPT_STATUS:
			{
//              osd_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:
			{
//              osd_printf_debug("Seek\n");
				fdc.cmd_len = 3;
				fdc.res_len = 0;
				fdc.next_phase = COMMAND;
				break;
			}
			default:
			{
//              osd_printf_debug("%x\n",data & 0x1f);
			}
		}
	}
	else
	{
		fdc.cmd[fdc.cmd_cnt++] = data;
		//osd_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_t bfcobra_state::exec_r_phase(void)
{
	return 0;
}
#endif

void bfcobra_state::exec_w_phase(uint8_t data)
{
}

#ifdef UNUSED_FUNCTION
uint8_t bfcobra_state::results_phase(void)
{
	return 0;
}

WRITE8_MEMBER(bfcobra_state::fd_op_w)
{
}

WRITE8_MEMBER(bfcobra_state::fd_ctrl_w)
{
}
#endif

void bfcobra_state::machine_reset()
{
	unsigned int pal;

	for (pal = 0; pal < 256; ++pal)
	{
		m_palette->set_pen_color(pal, pal3bit((pal>>5)&7), pal3bit((pal>>2)&7), pal2bit(pal&3));
	}

	m_bank_data[0] = 1;
	reset_fdc();

	m_irq_state = m_blitter_irq = m_vblank_irq = m_acia_irq = 0;
}

/***************************************************************************

    Cobra I/Viper Z80 Memory Map

***************************************************************************/

void bfcobra_state::z80_prog_map(address_map &map)
{
	map(0x0000, 0x3fff).bankr("bank4");
	map(0x4000, 0x7fff).bankrw("bank1");
	map(0x8000, 0xbfff).bankrw("bank2");
	map(0xc000, 0xffff).bankrw("bank3");
}

void bfcobra_state::z80_io_map(address_map &map)
{
map.global_mask(0xff);
	map(0x00, 0x23).rw(FUNC(bfcobra_state::chipset_r), FUNC(bfcobra_state::chipset_w));
	map(0x24, 0x25).w(m_acia6850_0, FUNC(acia6850_device::write));
	map(0x26, 0x27).r(m_acia6850_0, FUNC(acia6850_device::read));
	map(0x30, 0x30).r(FUNC(bfcobra_state::fdctrl_r));
	map(0x31, 0x31).rw(FUNC(bfcobra_state::fddata_r), FUNC(bfcobra_state::fdctrl_w));
	map(0x40, 0x40).w(FUNC(bfcobra_state::rombank_w));
	map(0x50, 0x50).w("ramdac", FUNC(ramdac_device::index_w));
	map(0x51, 0x51).rw("ramdac", FUNC(ramdac_device::pal_r), FUNC(ramdac_device::pal_w));
	map(0x52, 0x52).w("ramdac", FUNC(ramdac_device::mask_w));
	map(0x53, 0x53).w("ramdac", FUNC(ramdac_device::index_r_w));
}


void bfcobra_state::ramdac_map(address_map &map)
{
	map(0x000, 0x3ff).rw("ramdac", FUNC(ramdac_device::ramdac_pal_r), FUNC(ramdac_device::ramdac_rgb666_w));
}


/***************************************************************************

    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 */
READ8_MEMBER(bfcobra_state::int_latch_r)
{
	return 2 | 1;
}

/* TODO */
READ8_MEMBER(bfcobra_state::meter_r)
{
	return m_meter_latch;
}

/* TODO: This is borrowed from Scorpion 1 */
WRITE8_MEMBER(bfcobra_state::meter_w)
{
	int i;
	int  changed = m_meter_latch ^ data;

	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))
		{
			m_meters->update(i, data & (1 << i) );
			m_audiocpu->set_input_line(M6809_FIRQ_LINE, HOLD_LINE);
		}
	}
}

/* TODO */
READ8_MEMBER(bfcobra_state::latch_r)
{
	return m_mux_input;
}

WRITE8_MEMBER(bfcobra_state::latch_w)
{
	/* TODO: This is borrowed from Scorpion 1 */
	switch(offset)
	{
		case 0:
		{
			int changed = m_mux_outputlatch ^ data;
			static const char *const port[] = { "STROBE0", "STROBE1", "STROBE2", "STROBE3", "STROBE4", "STROBE5", "STROBE6", "STROBE7" };

			m_mux_outputlatch = data;

			/* Clock has changed */
			if (changed & 0x08)
			{
				int input_strobe = data & 0x7;

				/* Clock is low */
				if (!(data & 0x08))
					m_mux_input = ioport(port[input_strobe])->read();
			}
			break;
		}
		case 1:
		{
//          strobe_data_l = data;
			break;
		}
		case 2:
		{
//          strobe_data_h = data;
			break;
		}
	}
}

READ8_MEMBER(bfcobra_state::upd_r)
{
	return 2 | m_upd7759->busy_r();
}

WRITE8_MEMBER(bfcobra_state::upd_w)
{
	m_upd7759->reset_w(data & 0x80);
	m_upd7759->port_w(space, 0, data & 0x3f);
	m_upd7759->start_w(data & 0x40 ? 0 : 1);
}

void bfcobra_state::m6809_prog_map(address_map &map)
{
	map(0x0000, 0x1fff).ram().share("nvram");
	map(0x2000, 0x2000).ram();     // W 'B', 6F
	map(0x2200, 0x2200).ram();     // W 'F'
	map(0x2600, 0x2600).rw(FUNC(bfcobra_state::meter_r), FUNC(bfcobra_state::meter_w));
	map(0x2800, 0x2800).ram();     // W
	map(0x2A00, 0x2A02).rw(FUNC(bfcobra_state::latch_r), FUNC(bfcobra_state::latch_w));
	map(0x2E00, 0x2E00).r(FUNC(bfcobra_state::int_latch_r));
	map(0x3001, 0x3001).w("aysnd", FUNC(ay8910_device::data_w));
	map(0x3201, 0x3201).w("aysnd", FUNC(ay8910_device::address_w));
	map(0x3404, 0x3405).rw(m_acia6850_1, FUNC(acia6850_device::read), FUNC(acia6850_device::write));
	map(0x3406, 0x3407).rw(m_acia6850_2, FUNC(acia6850_device::read), FUNC(acia6850_device::write));
//  AM_RANGE(0x3408, 0x3408) AM_NOP
//  AM_RANGE(0x340A, 0x340A) AM_NOP
//  AM_RANGE(0x3600, 0x3600) AM_NOP
	map(0x3801, 0x3801).rw(FUNC(bfcobra_state::upd_r), FUNC(bfcobra_state::upd_w));
	map(0x8000, 0xffff).rom();
	map(0xf000, 0xf000).nopw();    /* Watchdog */
}

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.
*/
void bfcobra_state::init_ram()
{
	/* 768kB work RAM */
	m_work_ram = make_unique_clear<uint8_t[]>(0xC0000);

	/* 128kB video RAM */
	m_video_ram = make_unique_clear<uint8_t[]>(0x20000);
}


WRITE_LINE_MEMBER(bfcobra_state::z80_acia_irq)
{
	m_acia_irq = state;
	update_irqs();
}


WRITE_LINE_MEMBER(bfcobra_state::m6809_data_irq)
{
	m_audiocpu->set_input_line(M6809_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}


WRITE_LINE_MEMBER(bfcobra_state::data_acia_tx_w)
{
	m_data_t = state;
}


WRITE_LINE_MEMBER(bfcobra_state::write_acia_clock)
{
	m_acia6850_0->write_txc(state);
	m_acia6850_0->write_rxc(state);
	m_acia6850_1->write_txc(state);
	m_acia6850_1->write_rxc(state);
	m_acia6850_2->write_txc(state);
	m_acia6850_2->write_rxc(state);
}


/* TODO: Driver vs Machine Init */
void bfcobra_state::init_bfcobra()
{
	/*
	    6809 ROM address and data lines are scrambled.
	    This is the same scrambling as Scorpion 2.
	*/
	static const uint8_t datalookup[] = { 1, 3, 5, 6, 4, 2, 0, 7 };
	static const uint8_t addrlookup[] = { 11, 12, 0, 2, 3, 5, 7, 9, 8, 6, 1, 4, 10, 13, 14 };

	std::vector<uint8_t> tmp(0x8000);
	uint8_t *rom = memregion("audiocpu")->base() + 0x8000;
	memcpy(&tmp[0], rom, 0x8000);

	for (uint32_t i = 0; i < 0x8000; i++)
	{
		uint8_t val = tmp[i];

		uint8_t data = 0;
		for (uint8_t x = 0; x < 8; x ++)
			data |= ((val >> x) & 1) << datalookup[x];

		uint16_t addr = 0;
		for (uint8_t x = 0; x < 15; x ++)
			addr |= ((i >> x) & 1)  << addrlookup[x];

		rom[addr] = data;
	}

	init_ram();

	m_bank_data[0] = 1;
	m_bank_data[1] = 0;
	m_bank_data[2] = 0;
	m_bank_data[3] = 0;

	/* Fixed 16kB ROM region */
	membank("bank4")->set_base(memregion("user1")->base());

	/* TODO: Properly sort out the data ACIA */
	m_acia6850_2->write_rxd(1);

	/* Finish this */
	save_item(NAME(m_data_r));
	save_item(NAME(m_data_t));
	save_item(NAME(m_h_scroll));
	save_item(NAME(m_v_scroll));
	save_item(NAME(m_flip_8));
	save_item(NAME(m_flip_22));
	save_item(NAME(m_z80_int));
	save_item(NAME(m_z80_inten));
	save_item(NAME(m_bank_data));
	save_pointer(NAME(m_work_ram), 0xc0000);
	save_pointer(NAME(m_video_ram), 0x20000);
}

/* TODO */
INTERRUPT_GEN_MEMBER(bfcobra_state::timer_irq)
{
	device.execute().set_input_line(M6809_IRQ_LINE, HOLD_LINE);
}

/* TODO */
INTERRUPT_GEN_MEMBER(bfcobra_state::vblank_gen)
{
	m_vblank_irq = 1;
	update_irqs();
}

MACHINE_CONFIG_START(bfcobra_state::bfcobra)
	MCFG_DEVICE_ADD("maincpu", Z80, Z80_XTAL)
	MCFG_DEVICE_PROGRAM_MAP(z80_prog_map)
	MCFG_DEVICE_IO_MAP(z80_io_map)
	MCFG_DEVICE_VBLANK_INT_DRIVER("screen", bfcobra_state,  vblank_gen)

	MCFG_DEVICE_ADD("audiocpu", MC6809, M6809_XTAL) // MC6809P
	MCFG_DEVICE_PROGRAM_MAP(m6809_prog_map)
	MCFG_DEVICE_PERIODIC_INT_DRIVER(bfcobra_state, timer_irq, 1000)

	MCFG_NVRAM_ADD_0FILL("nvram")


	/* TODO */
	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_REFRESH_RATE(50)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
	MCFG_SCREEN_SIZE(512, 256)
	MCFG_SCREEN_VISIBLE_AREA(0, 512 - 1, 0, 256 - 1)
	MCFG_SCREEN_UPDATE_DRIVER(bfcobra_state, screen_update_bfcobra)

	MCFG_PALETTE_ADD("palette", 256)

	MCFG_RAMDAC_ADD("ramdac", ramdac_map, "palette") // MUSIC Semiconductor TR9C1710 RAMDAC or equivalent
	MCFG_RAMDAC_SPLIT_READ(1)

	SPEAKER(config, "mono").front_center();

	MCFG_DEVICE_ADD("aysnd", AY8910, M6809_XTAL / 4)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20)

	MCFG_DEVICE_ADD("upd", UPD7759)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40)

	/* ACIAs */
	MCFG_DEVICE_ADD("acia6850_0", ACIA6850, 0)
	MCFG_ACIA6850_TXD_HANDLER(WRITELINE("acia6850_1", acia6850_device, write_rxd))
	MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(*this, bfcobra_state, z80_acia_irq))

	MCFG_DEVICE_ADD("acia6850_1", ACIA6850, 0)
	MCFG_ACIA6850_TXD_HANDLER(WRITELINE("acia6850_0", acia6850_device, write_rxd))

	MCFG_DEVICE_ADD("acia6850_2", ACIA6850, 0)
	MCFG_ACIA6850_TXD_HANDLER(WRITELINE(*this, bfcobra_state, data_acia_tx_w))
	MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(*this, bfcobra_state, m6809_data_irq))

	MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) // What are the correct ACIA clocks ?
	MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, bfcobra_state, write_acia_clock))

	MCFG_DEVICE_ADD("meters", METERS, 0)
	MCFG_METERS_NUMBER(8)
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_state, init_bfcobra, ROT0, "BFM", "Inquizitor",                       MACHINE_NOT_WORKING )
GAME( 1990, escounts, 0,   bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "Every Second Counts (39-360-053)", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1991, trebltop, 0,   bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "Treble Top (39-360-070)",          MACHINE_IMPERFECT_GRAPHICS )
GAME( 1991, beeline,  0,   bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "Beeline (39-360-075)",             MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
GAME( 1991, quizvadr, 0,   bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "Quizvaders (39-360-078)",          MACHINE_IMPERFECT_GRAPHICS )
GAME( 1992, qos,      0,   bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "A Question of Sport (set 1, 39-960-107)", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1992, qosa,     qos, bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "A Question of Sport (set 2, 39-960-099)", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1992, qosb,     qos, bfcobra, bfcobra, bfcobra_state, init_bfcobra, ROT0, "BFM", "A Question of Sport (set 3, 39-960-089)", MACHINE_IMPERFECT_GRAPHICS )