summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/firetrk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/firetrk.c')
-rw-r--r--src/mame/drivers/firetrk.c1213
1 files changed, 1213 insertions, 0 deletions
diff --git a/src/mame/drivers/firetrk.c b/src/mame/drivers/firetrk.c
new file mode 100644
index 00000000000..bdc24ea0d51
--- /dev/null
+++ b/src/mame/drivers/firetrk.c
@@ -0,0 +1,1213 @@
+/***************************************************************************
+
+Atari Fire Truck + Super Bug + Monte Carlo driver
+
+***************************************************************************/
+
+
+#include "driver.h"
+#include "firetrk.h"
+#include "sound/discrete.h"
+
+#define FIRETRK_CPU_CLOCK_1MHZ (12096000 / 12)
+#define FIRETRK_CPU_CLOCK_750KZ (12096000 /16)
+
+
+int firetrk_game;
+
+static int last_service;
+static int steer_dir[2];
+static int steer_flag[2];
+static int attract;
+static int gear;
+
+
+static DRIVER_INIT( firetrk )
+{
+ firetrk_game = 1;
+}
+static DRIVER_INIT( superbug )
+{
+ firetrk_game = 2;
+}
+static DRIVER_INIT( montecar )
+{
+ firetrk_game = 3;
+}
+
+
+static void set_firetrk_service(int enable)
+{
+ /* watchdog is disabled during service mode */
+ watchdog_enable(!enable);
+
+ /* change CPU clock speed according to service switch change */
+ cpunum_set_clock(0, enable ? FIRETRK_CPU_CLOCK_750KZ : FIRETRK_CPU_CLOCK_1MHZ);
+}
+
+
+static INTERRUPT_GEN( firetrk_interrupt )
+{
+ int firetrk_service;
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ firetrk_service = readinputport(4) & 0x80;
+ if (firetrk_service != last_service)
+ {
+ set_firetrk_service(firetrk_service);
+
+ last_service = firetrk_service;
+ }
+ if (firetrk_service)
+ return;
+ }
+ else
+ if (GAME_IS_MONTECARLO)
+ {
+ firetrk_service = readinputport(6) & 0x04;
+ if (firetrk_service != last_service)
+ {
+ set_firetrk_service(firetrk_service);
+
+ last_service = firetrk_service;
+ }
+ if (firetrk_service)
+ return;
+ }
+ else
+ discrete_sound_w(SUPERBUG_ASR_EN, 0); /* Super Bug - ASR */
+
+ /* NMI interrupts are disabled during service mode in firetrk and montecar */
+ /* they never make it here if in service mode */
+ cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
+}
+
+
+static TIMER_CALLBACK( periodic_callback )
+{
+ int scanline = param;
+
+ cpunum_set_input_line(0, 0, PULSE_LINE);
+
+ /* IRQs are generated by inverse 16V signal */
+
+ scanline += 32;
+
+ if (scanline > 262)
+ {
+ scanline = 0;
+ }
+
+ timer_set(video_screen_get_time_until_pos(0, scanline, 0), scanline, periodic_callback);
+}
+
+
+static TIMER_CALLBACK( frame_callback )
+{
+ static UINT8 dial[2];
+
+ int i;
+
+ /* handle steering wheels */
+
+ for (i = 0; i < 2; i++)
+ {
+ signed char delta = readinputport(i) - dial[i];
+
+ if (delta < 0)
+ {
+ steer_flag[i] = 1;
+ steer_dir[i] = 0;
+ }
+ if (delta > 0)
+ {
+ steer_flag[i] = 1;
+ steer_dir[i] = 1;
+ }
+
+ dial[i] += delta;
+ }
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ /* map horn button onto discrete sound emulation */
+ discrete_sound_w(FIRETRUCK_HORN_EN, readinputport(7));
+ }
+
+ /* update gear shift */
+ if (GAME_IS_SUPERBUG || GAME_IS_MONTECARLO)
+ {
+ switch (readinputport(7) & 15)
+ {
+ case 1: gear = 1; break;
+ case 2: gear = 2; break;
+ case 4: gear = 3; break;
+ case 8: gear = 4; break;
+ }
+ }
+}
+
+
+static void write_output(UINT8 flags)
+{
+ if (GAME_IS_FIRETRUCK)
+ {
+ /* BIT0 => START1 LAMP */
+ /* BIT1 => START2 LAMP */
+ /* BIT2 => FLASH */
+ /* BIT3 => TRACK LAMP */
+ /* BIT4 => ATTRACT */
+ /* BIT5 => START3 LAMP */
+ /* BIT6 => UNUSED */
+ /* BIT7 => BELL OUT */
+
+ set_led_status(0, !(flags & 0x01));
+ set_led_status(1, !(flags & 0x02));
+ set_led_status(2, !(flags & 0x20));
+ set_led_status(3, !(flags & 0x08));
+
+ attract = flags & 0x10;
+
+ discrete_sound_w(FIRETRUCK_BELL_EN, flags & 0x80); /* Bell Sound */
+ discrete_sound_w(FIRETRUCK_ATTRACT_EN, flags & 0x10); /* Attract */
+
+ coin_lockout_w(0, !attract);
+ coin_lockout_w(1, !attract);
+
+ firetrk_set_flash(flags & 0x04);
+ }
+
+ if (GAME_IS_SUPERBUG)
+ {
+ /* BIT0 => START LAMP */
+ /* BIT1 => ATTRACT */
+ /* BIT2 => FLASH */
+ /* BIT3 => TRACK LAMP */
+
+ attract = flags & 0x02;
+
+ set_led_status(0, flags & 0x01);
+ set_led_status(1, flags & 0x08);
+
+ discrete_sound_w(SUPERBUG_ATTRACT_EN, flags & 0x02); /* Attract */
+
+ coin_lockout_w(0, !attract);
+ coin_lockout_w(1, !attract);
+
+ firetrk_set_flash(flags & 0x04);
+ }
+
+ if (GAME_IS_MONTECARLO)
+ {
+ /* BIT0 => START LAMP */
+ /* BIT1 => TRACK LAMP */
+ /* BIT2 => ATTRACT */
+ /* BIT3 => UNUSED */
+ /* BIT4 => UNUSED */
+ /* BIT5 => COIN3 COUNTER */
+ /* BIT6 => COIN2 COUNTER */
+ /* BIT7 => COIN1 COUNTER */
+
+ set_led_status(0, !(flags & 0x01));
+ set_led_status(1, !(flags & 0x02));
+
+ discrete_sound_w(MONTECAR_ATTRACT_INV, flags & 0x04); /* Attract */
+
+ coin_counter_w(0, flags & 0x80);
+ coin_counter_w(1, flags & 0x40);
+ coin_counter_w(2, flags & 0x20);
+ }
+}
+
+
+static MACHINE_RESET( firetrk )
+{
+ timer_pulse(video_screen_get_frame_period(0), 0, frame_callback);
+
+ if (GAME_IS_MONTECARLO)
+ {
+ write_output(0);
+ last_service = readinputport(6) & 0x04;
+ set_firetrk_service(last_service);
+ }
+ else
+ if (GAME_IS_FIRETRUCK)
+ {
+ last_service = readinputport(4) & 0x80;
+ set_firetrk_service(last_service);
+ }
+
+ timer_call_after_resynch(0, periodic_callback);
+}
+
+
+static PALETTE_INIT( firetrk )
+{
+ static const UINT16 colortable_source[] =
+ {
+ 0, 0, 1, 0,
+ 2, 0, 3, 0,
+ 3, 3, 2, 3,
+ 1, 3, 0, 3,
+ 0, 0, 1, 0,
+ 2, 0, 0, 3,
+ 3, 0, 0, 3
+ };
+
+ palette_set_color(machine, 0, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(machine, 1, MAKE_RGB(0x5b, 0x5b, 0x5b));
+ palette_set_color(machine, 2, MAKE_RGB(0xa4, 0xa4, 0xa4));
+ palette_set_color(machine, 3, MAKE_RGB(0xff, 0xff, 0xff));
+
+ memcpy(colortable, colortable_source, sizeof(colortable_source));
+}
+
+
+static void prom_to_palette(running_machine *machine, int number, UINT8 val)
+{
+ palette_set_color_rgb(machine, number, pal1bit(val >> 2), pal1bit(val >> 1), pal1bit(val >> 0));
+}
+
+
+static PALETTE_INIT( montecar )
+{
+ static const UINT16 colortable_source[] =
+ {
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x02, 0x00, 0x03,
+ 0x03, 0x03, 0x03, 0x02,
+ 0x03, 0x01, 0x03, 0x00,
+ 0x00, 0x00, 0x02, 0x00,
+ 0x02, 0x01, 0x02, 0x02,
+ 0x00, 0x05, 0x06, 0x07,
+ 0x00, 0x09, 0x0A, 0x0B,
+ 0x00, 0x0D, 0x0E, 0x0F,
+ 0x00, 0x11, 0x12, 0x13,
+ 0x00, 0x15, 0x16, 0x17,
+ 0x18, 0x19
+ };
+
+ /*
+ * The color PROM is addressed as follows:
+ *
+ * A0 => PLAYFIELD 1
+ * A1 => PLAYFIELD 2
+ * A2 => DRONE 1
+ * A3 => DRONE 2
+ * A4 => CAR 1
+ * A5 => CAR 2
+ * A6 => DRONE COLOR 1
+ * A7 => DRONE COLOR 2
+ * A8 => PLAYFIELD WINDOW
+ *
+ * This driver hard-codes some behavior which actually depends
+ * on the PROM, like priorities, clipping and transparency.
+ *
+ */
+
+ const UINT8* p = memory_region(REGION_PROMS);
+
+ int number = 0;
+
+ prom_to_palette(machine, number++, p[0x100]);
+ prom_to_palette(machine, number++, p[0x101]);
+ prom_to_palette(machine, number++, p[0x102]);
+ prom_to_palette(machine, number++, p[0x103]);
+
+ prom_to_palette(machine, number++, p[0x100]);
+ prom_to_palette(machine, number++, p[0x110]);
+ prom_to_palette(machine, number++, p[0x120]);
+ prom_to_palette(machine, number++, p[0x130]);
+
+ prom_to_palette(machine, number++, p[0x100]);
+ prom_to_palette(machine, number++, p[0x104]);
+ prom_to_palette(machine, number++, p[0x108]);
+ prom_to_palette(machine, number++, p[0x10C]);
+
+ prom_to_palette(machine, number++, p[0x140]);
+ prom_to_palette(machine, number++, p[0x144]);
+ prom_to_palette(machine, number++, p[0x148]);
+ prom_to_palette(machine, number++, p[0x14C]);
+
+ prom_to_palette(machine, number++, p[0x180]);
+ prom_to_palette(machine, number++, p[0x184]);
+ prom_to_palette(machine, number++, p[0x188]);
+ prom_to_palette(machine, number++, p[0x18C]);
+
+ prom_to_palette(machine, number++, p[0x1C0]);
+ prom_to_palette(machine, number++, p[0x1C4]);
+ prom_to_palette(machine, number++, p[0x1C8]);
+ prom_to_palette(machine, number++, p[0x1CC]);
+
+ palette_set_color(machine, number++, MAKE_RGB(0x00, 0x00, 0x00));
+ palette_set_color(machine, number++, MAKE_RGB(0xff, 0xff, 0xff));
+
+ memcpy(colortable, colortable_source, sizeof(colortable_source));
+}
+
+
+static READ8_HANDLER( firetrk_dip_r )
+{
+ UINT8 val0 = readinputport(2);
+ UINT8 val1 = readinputport(3);
+
+ if (GAME_IS_FIRETRUCK || GAME_IS_SUPERBUG)
+ {
+ if (val1 & (1 << (2 * offset + 0))) val0 |= 1;
+ if (val1 & (1 << (2 * offset + 1))) val0 |= 2;
+ }
+ if (GAME_IS_MONTECARLO)
+ {
+ if (val1 & (1 << (3 - offset))) val0 |= 1;
+ if (val1 & (1 << (7 - offset))) val0 |= 2;
+ }
+
+ return val0;
+}
+
+
+static READ8_HANDLER( firetrk_input_r )
+{
+ UINT8 val = 0;
+
+ UINT8 bit0 = readinputport(4);
+ UINT8 bit6 = readinputport(5);
+ UINT8 bit7 = readinputport(6);
+
+ if (GAME_IS_FIRETRUCK)
+ {
+ if (!steer_dir[0])
+ bit0 |= 0x04;
+ if (!steer_flag[0])
+ bit7 |= 0x04;
+ if (firetrk_skid[0] || firetrk_skid[1])
+ bit0 |= 0x40;
+ if (firetrk_crash[0] || firetrk_crash[1])
+ bit7 |= 0x40;
+ if (!steer_dir[1])
+ bit0 |= 0x08;
+ if (!steer_flag[1])
+ bit7 |= 0x08;
+ }
+
+ if (GAME_IS_SUPERBUG)
+ {
+ if (!steer_dir[0])
+ bit0 |= 0x04;
+ if (!steer_flag[0])
+ bit7 |= 0x04;
+ if (firetrk_skid[0])
+ bit0 |= 0x40;
+ if (firetrk_crash[0])
+ bit7 |= 0x40;
+ if (gear == 1)
+ bit7 |= 0x02;
+ if (gear == 2)
+ bit0 |= 0x01;
+ if (gear == 3)
+ bit7 |= 0x01;
+ }
+
+ if (GAME_IS_MONTECARLO)
+ {
+ if (!steer_dir[0])
+ bit6 |= 0x40;
+ if (!steer_flag[0])
+ bit7 |= 0x40;
+ if (gear == 1)
+ bit6 |= 0x01;
+ if (gear == 2)
+ bit6 |= 0x02;
+ if (gear == 3)
+ bit6 |= 0x04;
+ if (firetrk_skid[0])
+ bit7 |= 0x80;
+ if (firetrk_skid[1])
+ bit6 |= 0x80;
+ if (firetrk_crash[0])
+ val |= 0x02;
+ if (firetrk_crash[1])
+ val |= 0x01;
+ }
+
+ if (bit0 & (1 << offset)) val |= 0x01;
+ if (bit6 & (1 << offset)) val |= 0x40;
+ if (bit7 & (1 << offset)) val |= 0x80;
+
+ return val;
+}
+
+
+static WRITE8_HANDLER( firetrk_arrow_off_w )
+{
+ firetrk_set_blink(1);
+}
+
+
+static WRITE8_HANDLER( firetrk_car_reset_w )
+{
+ firetrk_crash[0] = 0;
+ firetrk_skid[0] = 0;
+}
+
+
+static WRITE8_HANDLER( firetrk_drone_reset_w )
+{
+ firetrk_crash[1] = 0;
+ firetrk_skid[1] = 0;
+}
+
+
+static WRITE8_HANDLER( firetrk_steer_reset_w )
+{
+ steer_flag[0] = 0;
+ steer_flag[1] = 0;
+}
+
+
+static WRITE8_HANDLER( firetrk_crash_reset_w )
+{
+ firetrk_crash[0] = 0;
+ firetrk_crash[1] = 0;
+}
+
+
+static WRITE8_HANDLER( firetrk_out_w )
+{
+ if (GAME_IS_FIRETRUCK || GAME_IS_MONTECARLO)
+ {
+ write_output(data);
+ }
+ if (GAME_IS_SUPERBUG)
+ {
+ write_output(offset);
+ }
+}
+
+
+
+static ADDRESS_MAP_START( firetrk_map, ADDRESS_SPACE_PROGRAM, 8 )
+ ADDRESS_MAP_FLAGS( AMEF_ABITS(14) )
+ AM_RANGE(0x0000, 0x00ff) AM_MIRROR(0x700) AM_RAM AM_BASE(&firetrk_alpha_num_ram)
+ AM_RANGE(0x0800, 0x08ff) AM_MIRROR(0x700) AM_READWRITE(MRA8_RAM, firetrk_playfield_w) AM_BASE(&firetrk_playfield_ram)
+ AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x1f) AM_WRITE(firetrk_vert_w)
+ AM_RANGE(0x1020, 0x1020) AM_MIRROR(0x1f) AM_WRITE(firetrk_horz_w)
+ AM_RANGE(0x1040, 0x1040) AM_MIRROR(0x1f) AM_WRITE(firetrk_crash_reset_w)
+ AM_RANGE(0x1060, 0x1060) AM_MIRROR(0x1f) AM_WRITE(firetrk_skid_reset_w)
+ AM_RANGE(0x1080, 0x1080) AM_MIRROR(0x1f) AM_WRITE(firetrk_car_rot_w)
+ AM_RANGE(0x10a0, 0x10a0) AM_MIRROR(0x1f) AM_WRITE(firetrk_steer_reset_w)
+ AM_RANGE(0x10c0, 0x10c0) AM_MIRROR(0x1f) AM_WRITE(watchdog_reset_w)
+ AM_RANGE(0x10e0, 0x10e0) AM_MIRROR(0x1f) AM_WRITE(firetrk_arrow_off_w)
+ AM_RANGE(0x1400, 0x1400) AM_MIRROR(0x1f) AM_WRITE(firetrk_motor_snd_w)
+ AM_RANGE(0x1420, 0x1420) AM_MIRROR(0x1f) AM_WRITE(firetrk_crash_snd_w)
+ AM_RANGE(0x1440, 0x1440) AM_MIRROR(0x1f) AM_WRITE(firetrk_skid_snd_w)
+ AM_RANGE(0x1460, 0x1460) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_hpos_w)
+ AM_RANGE(0x1480, 0x1480) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_vpos_w)
+ AM_RANGE(0x14a0, 0x14a0) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_rot_w)
+ AM_RANGE(0x14c0, 0x14c0) AM_MIRROR(0x1f) AM_WRITE(firetrk_out_w)
+ AM_RANGE(0x14e0, 0x14e0) AM_MIRROR(0x1f) AM_WRITE(firetrk_xtndply_w)
+ AM_RANGE(0x1800, 0x1807) AM_MIRROR(0x3f8) AM_READWRITE(firetrk_input_r, MWA8_NOP)
+ AM_RANGE(0x1c00, 0x1c03) AM_MIRROR(0x3fc) AM_READ(firetrk_dip_r)
+ AM_RANGE(0x2000, 0x3fff) AM_ROM
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( superbug_map, ADDRESS_SPACE_PROGRAM, 8 )
+ ADDRESS_MAP_FLAGS( AMEF_ABITS(13) )
+ AM_RANGE(0x0000, 0x00ff) AM_RAM
+ AM_RANGE(0x0100, 0x0100) AM_MIRROR(0x1f) AM_WRITE(firetrk_vert_w)
+ AM_RANGE(0x0120, 0x0120) AM_MIRROR(0x1f) AM_WRITE(firetrk_horz_w)
+ AM_RANGE(0x0140, 0x0140) AM_MIRROR(0x1f) AM_WRITE(firetrk_crash_reset_w)
+ AM_RANGE(0x0160, 0x0160) AM_MIRROR(0x1f) AM_WRITE(firetrk_skid_reset_w)
+ AM_RANGE(0x0180, 0x0180) AM_MIRROR(0x1f) AM_WRITE(firetrk_car_rot_w)
+ AM_RANGE(0x01a0, 0x01a0) AM_MIRROR(0x1f) AM_WRITE(firetrk_steer_reset_w)
+ AM_RANGE(0x01c0, 0x01c0) AM_MIRROR(0x1f) AM_WRITE(watchdog_reset_w)
+ AM_RANGE(0x01e0, 0x01e0) AM_MIRROR(0x1f) AM_WRITE(firetrk_arrow_off_w)
+ AM_RANGE(0x0200, 0x0207) AM_MIRROR(0x18) AM_READ(firetrk_input_r)
+ AM_RANGE(0x0220, 0x0220) AM_MIRROR(0x1f) AM_WRITE(firetrk_asr_w)
+ AM_RANGE(0x0240, 0x0243) AM_MIRROR(0x1c) AM_READ(firetrk_dip_r)
+ AM_RANGE(0x0260, 0x026f) AM_MIRROR(0x10) AM_WRITE(firetrk_out_w)
+ AM_RANGE(0x0280, 0x0280) AM_MIRROR(0x1f) AM_WRITE(firetrk_motor_snd_w)
+ AM_RANGE(0x02a0, 0x02a0) AM_MIRROR(0x1f) AM_WRITE(firetrk_crash_snd_w)
+ AM_RANGE(0x02c0, 0x02c0) AM_MIRROR(0x1f) AM_WRITE(firetrk_skid_snd_w)
+ AM_RANGE(0x0400, 0x041f) AM_RAM AM_BASE(&firetrk_alpha_num_ram)
+ AM_RANGE(0x0500, 0x05ff) AM_READWRITE(MRA8_RAM, firetrk_playfield_w) AM_BASE(&firetrk_playfield_ram)
+ AM_RANGE(0x0800, 0x1fff) AM_ROM
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( montecar_map, ADDRESS_SPACE_PROGRAM, 8 )
+ ADDRESS_MAP_FLAGS( AMEF_ABITS(14) )
+ AM_RANGE(0x0000, 0x00ff) AM_MIRROR(0x700) AM_RAM AM_BASE(&firetrk_alpha_num_ram)
+ AM_RANGE(0x0800, 0x08ff) AM_MIRROR(0x700) AM_READWRITE(MRA8_RAM, firetrk_playfield_w) AM_BASE(&firetrk_playfield_ram)
+ AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x1f) AM_WRITE(firetrk_vert_w)
+ AM_RANGE(0x1020, 0x1020) AM_MIRROR(0x1f) AM_WRITE(firetrk_horz_w)
+ AM_RANGE(0x1040, 0x1040) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_reset_w)
+ AM_RANGE(0x1060, 0x1060) AM_MIRROR(0x1f) AM_WRITE(firetrk_car_reset_w)
+ AM_RANGE(0x1080, 0x1080) AM_MIRROR(0x1f) AM_WRITE(firetrk_car_rot_w)
+ AM_RANGE(0x10a0, 0x10a0) AM_MIRROR(0x1f) AM_WRITE(firetrk_steer_reset_w)
+ AM_RANGE(0x10c0, 0x10c0) AM_MIRROR(0x1f) AM_WRITE(watchdog_reset_w)
+ AM_RANGE(0x10e0, 0x10e0) AM_MIRROR(0x1f) AM_WRITE(firetrk_skid_reset_w)
+ AM_RANGE(0x1400, 0x1400) AM_MIRROR(0x1f) AM_WRITE(firetrk_motor_snd_w)
+ AM_RANGE(0x1420, 0x1420) AM_MIRROR(0x1f) AM_WRITE(firetrk_crash_snd_w)
+ AM_RANGE(0x1440, 0x1440) AM_MIRROR(0x1f) AM_WRITE(firetrk_skid_snd_w)
+ AM_RANGE(0x1460, 0x1460) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_hpos_w)
+ AM_RANGE(0x1480, 0x1480) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_vpos_w)
+ AM_RANGE(0x14a0, 0x14a0) AM_MIRROR(0x1f) AM_WRITE(firetrk_drone_rot_w)
+ AM_RANGE(0x14c0, 0x14c0) AM_MIRROR(0x1f) AM_WRITE(firetrk_out_w)
+ AM_RANGE(0x14e0, 0x14e0) AM_MIRROR(0x1f) AM_WRITE(firetrk_out2_w)
+ AM_RANGE(0x1800, 0x1807) AM_MIRROR(0x3f8) AM_READWRITE(firetrk_input_r, MWA8_NOP)
+ AM_RANGE(0x1c00, 0x1c03) AM_MIRROR(0x3fc) AM_READ(firetrk_dip_r)
+ AM_RANGE(0x2000, 0x3fff) AM_ROM
+ADDRESS_MAP_END
+
+
+static INPUT_PORTS_START( firetrk )
+ PORT_START
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10) PORT_PLAYER(1)
+
+ PORT_START
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10) PORT_PLAYER(2)
+
+ PORT_START
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED) /* other DIPs connect here */
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_UNUSED) /* other DIPs connect here */
+ PORT_DIPNAME( 0x0c, 0x08, DEF_STR( Coinage ))
+ PORT_DIPSETTING( 0x0c, DEF_STR( 2C_1C ))
+ PORT_DIPSETTING( 0x08, DEF_STR( 1C_1C ))
+ PORT_DIPSETTING( 0x04, DEF_STR( 1C_2C ))
+ PORT_DIPSETTING( 0x00, DEF_STR( Free_Play ))
+ PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unused ))
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ))
+ PORT_DIPSETTING( 0x00, DEF_STR( On ))
+ PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unused ))
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ))
+ PORT_DIPSETTING( 0x00, DEF_STR( On ))
+
+ PORT_START
+ PORT_DIPNAME( 0x03, 0x00, DEF_STR( Language ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( English ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( French ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Spanish ) )
+ PORT_DIPSETTING( 0x03, DEF_STR( German ) )
+ PORT_DIPNAME( 0x0c, 0x04, "Play Time" )
+ PORT_DIPSETTING( 0x00, "60 Seconds" )
+ PORT_DIPSETTING( 0x04, "90 Seconds" )
+ PORT_DIPSETTING( 0x08, "120 Seconds" )
+ PORT_DIPSETTING( 0x0c, "150 Seconds" )
+ PORT_DIPNAME( 0x30, 0x20, "Extended Play" )
+ PORT_DIPSETTING( 0x10, "Liberal" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Medium ) )
+ PORT_DIPSETTING( 0x30, "Conservative" )
+ PORT_DIPSETTING( 0x00, "Never" )
+
+ PORT_START /* bit 0 */
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Gas") PORT_PLAYER(1)
+ PORT_BIT (0x04, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER DIR 1 */
+ PORT_BIT (0x08, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER DIR 2 */
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Bell") PORT_PLAYER(2)
+ PORT_BIT (0x20, IP_ACTIVE_HIGH, IPT_TILT)
+ PORT_BIT (0x40, IP_ACTIVE_HIGH, IPT_UNUSED) /* SKID */
+ PORT_SERVICE(0x80, IP_ACTIVE_HIGH)
+
+ PORT_START /* bit 6 */
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Front Player Start")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_START2 ) PORT_NAME("Back Player Start")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_START3 ) PORT_NAME("Both Players Start")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Track Select") PORT_CODE(KEYCODE_SPACE) PORT_PLAYER(1)
+ PORT_BIT (0x10, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT (0x20, IP_ACTIVE_LOW, IPT_VBLANK)
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Cabinet ))
+ PORT_DIPSETTING( 0x00, "Smokey Joe (1 Player)" )
+ PORT_DIPSETTING( 0x40, "Fire Truck (2 Players)" )
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_SERVICE ) PORT_NAME("Diag Hold") PORT_CODE(KEYCODE_F6)
+
+ PORT_START /* bit 7 */
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT (0x04, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER FLAG 1 */
+ PORT_BIT (0x08, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER FLAG 2 */
+ PORT_BIT (0x10, IP_ACTIVE_HIGH, IPT_COIN1)
+ PORT_BIT (0x20, IP_ACTIVE_HIGH, IPT_COIN2)
+ PORT_BIT (0x40, IP_ACTIVE_HIGH, IPT_UNUSED) /* CRASH */
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_SERVICE ) PORT_NAME("Diag Step") PORT_CODE(KEYCODE_F1)
+
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Horn") PORT_PLAYER(1)
+
+ PORT_START_TAG("R27")
+ PORT_ADJUSTER( 20, "R27 - Motor Frequency" )
+INPUT_PORTS_END
+
+
+static INPUT_PORTS_START( superbug )
+ PORT_START
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10)
+
+ PORT_START
+ PORT_BIT (0xff, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED) /* other DIPs connect here */
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_UNUSED) /* other DIPs connect here */
+
+ PORT_START
+ PORT_DIPNAME( 0x03, 0x02, DEF_STR( Coinage ))
+ PORT_DIPSETTING( 0x03, DEF_STR( 2C_1C ))
+ PORT_DIPSETTING( 0x02, DEF_STR( 1C_1C ))
+ PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ))
+ PORT_DIPSETTING( 0x00, DEF_STR( Free_Play ))
+ PORT_DIPNAME( 0x0c, 0x04, "Play Time" )
+ PORT_DIPSETTING( 0x00, "60 seconds" )
+ PORT_DIPSETTING( 0x04, "90 seconds" )
+ PORT_DIPSETTING( 0x08, "120 seconds" )
+ PORT_DIPSETTING( 0x0c, "150 seconds" )
+ PORT_DIPNAME( 0x30, 0x20, "Extended Play" )
+ PORT_DIPSETTING( 0x10, "Liberal" )
+ PORT_DIPSETTING( 0x20, DEF_STR( Medium ) )
+ PORT_DIPSETTING( 0x30, "Conservative" )
+ PORT_DIPSETTING( 0x00, "Never" )
+ PORT_DIPNAME( 0xc0, 0x00, DEF_STR( Language ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( English ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( French ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Spanish ) )
+ PORT_DIPSETTING( 0xc0, DEF_STR( German ) )
+
+ PORT_START /* bit 0 */
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED) /* GEAR 2 */
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Gas")
+ PORT_BIT (0x04, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER DIR */
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_NAME("Hiscore Reset") PORT_CODE(KEYCODE_H)
+ PORT_BIT (0x10, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_SERVICE( 0x20, IP_ACTIVE_HIGH)
+ PORT_BIT (0x40, IP_ACTIVE_HIGH, IPT_UNUSED) /* SKID */
+ PORT_BIT (0x80, IP_ACTIVE_HIGH, IPT_TILT)
+
+ PORT_START /* bit 6 */
+ PORT_BIT(0xff, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START /* bit 7 */
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED) /* GEAR 3 */
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_UNUSED) /* GEAR 1 */
+ PORT_BIT (0x04, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER FLAG */
+ PORT_BIT (0x08, IP_ACTIVE_HIGH, IPT_COIN1)
+ PORT_BIT (0x10, IP_ACTIVE_HIGH, IPT_COIN2)
+ PORT_BIT (0x20, IP_ACTIVE_HIGH, IPT_START1)
+ PORT_BIT (0x40, IP_ACTIVE_HIGH, IPT_UNUSED) /* CRASH */
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("Track Select") PORT_CODE(KEYCODE_SPACE)
+
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Gear 1") PORT_CODE(KEYCODE_Z)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Gear 2") PORT_CODE(KEYCODE_X)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Gear 3") PORT_CODE(KEYCODE_C)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("Gear 4") PORT_CODE(KEYCODE_V)
+
+ PORT_START_TAG("R62")
+ PORT_ADJUSTER( 20, "R62 - Motor Frequency" )
+INPUT_PORTS_END
+
+
+static INPUT_PORTS_START( montecar )
+ PORT_START
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(25) PORT_KEYDELTA(10) PORT_PLAYER(1)
+
+ PORT_START
+ PORT_BIT (0xff, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED) /* other DIPs connect here */
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_UNUSED) /* other DIPs connect here */
+ PORT_DIPNAME( 0x0c, 0x0c, "Coin 3 Multiplier" )
+ PORT_DIPSETTING( 0x0c, "1" )
+ PORT_DIPSETTING( 0x08, "4" )
+ PORT_DIPSETTING( 0x04, "5" )
+ PORT_DIPSETTING( 0x00, "6" )
+ PORT_DIPNAME( 0x10, 0x10, "Coin 2 Multiplier" )
+ PORT_DIPSETTING( 0x10, "1" )
+ PORT_DIPSETTING( 0x00, "2" )
+ PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unused ))
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ))
+ PORT_DIPSETTING( 0x00, DEF_STR( On ))
+
+ PORT_START
+ PORT_DIPNAME( 0x03, 0x02, DEF_STR( Coinage ))
+ PORT_DIPSETTING( 0x00, DEF_STR( 2C_1C ))
+ PORT_DIPSETTING( 0x02, DEF_STR( 1C_1C ))
+ PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ))
+ PORT_DIPSETTING( 0x03, DEF_STR( Free_Play ))
+ PORT_DIPNAME( 0x0c, 0x08, "Extended Play" )
+ PORT_DIPSETTING( 0x04, "Liberal" )
+ PORT_DIPSETTING( 0x08, DEF_STR( Medium ) )
+ PORT_DIPSETTING( 0x00, "Conservative" )
+ PORT_DIPSETTING( 0x0c, "Never" )
+ PORT_DIPNAME( 0x30, 0x20, "Play Time" )
+ PORT_DIPSETTING( 0x30, "60 Seconds" )
+ PORT_DIPSETTING( 0x10, "90 Seconds" )
+ PORT_DIPSETTING( 0x20, "120 Seconds" )
+ PORT_DIPSETTING( 0x00, "150 Seconds" )
+ PORT_DIPNAME( 0xc0, 0xc0, DEF_STR( Language ) )
+ PORT_DIPSETTING( 0xc0, DEF_STR( English ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Spanish ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( French ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( German ) )
+
+ PORT_START /* bit 0 */
+ PORT_BIT(0xff, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START /* bit 6 */
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_UNUSED) /* GEAR 1 */
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_UNUSED) /* GEAR 2 */
+ PORT_BIT (0x04, IP_ACTIVE_HIGH, IPT_UNUSED) /* GEAR 3 */
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("Track Select") PORT_CODE(KEYCODE_SPACE)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Gas")
+ PORT_BIT (0x20, IP_ACTIVE_HIGH, IPT_VBLANK)
+ PORT_BIT (0x40, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER DIR */
+ PORT_BIT (0x80, IP_ACTIVE_HIGH, IPT_UNUSED) /* SKID 1 */
+
+ PORT_START /* bit 7 */
+ PORT_BIT (0x01, IP_ACTIVE_HIGH, IPT_START1)
+ PORT_BIT (0x02, IP_ACTIVE_HIGH, IPT_TILT)
+ PORT_SERVICE(0x04, IP_ACTIVE_HIGH)
+ PORT_BIT (0x08, IP_ACTIVE_HIGH, IPT_COIN1)
+ PORT_BIT (0x10, IP_ACTIVE_HIGH, IPT_COIN2)
+ PORT_BIT (0x20, IP_ACTIVE_HIGH, IPT_COIN3)
+ PORT_BIT (0x40, IP_ACTIVE_HIGH, IPT_UNUSED) /* STEER FLAG */
+ PORT_BIT (0x80, IP_ACTIVE_HIGH, IPT_UNUSED) /* SKID 0 */
+
+ PORT_START
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Gear 1") PORT_CODE(KEYCODE_Z)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Gear 2") PORT_CODE(KEYCODE_X)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Gear 3") PORT_CODE(KEYCODE_C)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("Gear 4") PORT_CODE(KEYCODE_V)
+
+ PORT_START_TAG("R89")
+ PORT_ADJUSTER( 20, "R89 - Motor Frequency" )
+
+ PORT_START_TAG("R88")
+ PORT_ADJUSTER( 25, "R88 - Drone Motor Frequency" )
+INPUT_PORTS_END
+
+
+static const gfx_layout firetrk_text_layout =
+{
+ 16, 16, /* width, height */
+ 32, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x04, 0x05, 0x06, 0x07,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x14, 0x15, 0x16, 0x17
+ },
+ {
+ 0x000, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0C0, 0x0E0,
+ 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0
+ },
+ 0x200
+};
+
+
+static const gfx_layout superbug_text_layout =
+{
+ 16, 16, /* width, height */
+ 32, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x14, 0x15, 0x16, 0x17,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x04, 0x05, 0x06, 0x07
+ },
+ {
+ 0x000, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0C0, 0x0E0,
+ 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0
+ },
+ 0x200
+};
+
+
+static const gfx_layout montecar_text_layout =
+{
+ 8, 8, /* width, height */
+ 64, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0xC, 0xD, 0xE, 0xF, 0x4, 0x5, 0x6, 0x7
+ },
+ {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70
+ },
+ 0x80
+};
+
+
+static const gfx_layout firetrk_tile_layout =
+{
+ 16, 16, /* width, height */
+ 64, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
+ },
+ {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0
+ },
+ 0x100
+};
+
+
+static const gfx_layout superbug_tile_layout =
+{
+ 16, 16, /* width, height */
+ 64, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x07, 0x06, 0x05, 0x04, 0x0F, 0x0E, 0x0D, 0x0C,
+ 0x17, 0x16, 0x15, 0x14, 0x1F, 0x1E, 0x1D, 0x1C
+ },
+ {
+ 0x000, 0x020, 0x040, 0x060, 0x080, 0x0A0, 0x0C0, 0x0E0,
+ 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0
+ },
+ 0x200
+};
+
+
+static const gfx_layout firetrk_car_layout1 =
+{
+ 32, 32, /* width, height */
+ 4, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x000, 0x040, 0x080, 0x0C0, 0x100, 0x140, 0x180, 0x1C0,
+ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x340, 0x380, 0x3C0,
+ 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, 0x5C0,
+ 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780, 0x7C0
+ },
+ {
+ 0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x24, 0x25, 0x26, 0x27, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x34, 0x35, 0x36, 0x37, 0x3C, 0x3D, 0x3E, 0x3B
+ },
+ 0x800
+};
+
+
+static const gfx_layout superbug_car_layout1 =
+{
+ 32, 32, /* width, height */
+ 4, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
+ 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00,
+ 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700,
+ 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, 0x1E00, 0x1F00
+ },
+ {
+ 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x34, 0x3C,
+ 0x44, 0x4C, 0x54, 0x5C, 0x64, 0x6C, 0x74, 0x7C,
+ 0x84, 0x8C, 0x94, 0x9C, 0xA4, 0xAC, 0xB4, 0xBC,
+ 0xC4, 0xCC, 0xD4, 0xDC, 0xE4, 0xEC, 0xF4, 0xFC
+ },
+ 0x001
+};
+
+
+static const gfx_layout montecar_car_layout =
+{
+ 32, 32, /* width, height */
+ 8, /* total */
+ 2, /* planes */
+ /* plane offsets */
+ { 1, 0 },
+ {
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,
+ 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E,
+ 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E
+ },
+ {
+ 0x000, 0x040, 0x080, 0x0C0, 0x100, 0x140, 0x180, 0x1C0,
+ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x340, 0x380, 0x3C0,
+ 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, 0x5C0,
+ 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780, 0x7C0
+ },
+ 0x800
+};
+
+
+static const gfx_layout firetrk_car_layout2 =
+{
+ 32, 32, /* width, height */
+ 4, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x24, 0x25, 0x26, 0x27, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x34, 0x35, 0x36, 0x37, 0x3C, 0x3D, 0x3E, 0x3B
+ },
+ {
+ 0x000, 0x040, 0x080, 0x0C0, 0x100, 0x140, 0x180, 0x1C0,
+ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x340, 0x380, 0x3C0,
+ 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, 0x5C0,
+ 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780, 0x7C0
+ },
+ 0x800
+};
+
+
+static const gfx_layout superbug_car_layout2 =
+{
+ 32, 32, /* width, height */
+ 4, /* total */
+ 1, /* planes */
+ { 0 }, /* plane offsets */
+ {
+ 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x34, 0x3C,
+ 0x44, 0x4C, 0x54, 0x5C, 0x64, 0x6C, 0x74, 0x7C,
+ 0x84, 0x8C, 0x94, 0x9C, 0xA4, 0xAC, 0xB4, 0xBC,
+ 0xC4, 0xCC, 0xD4, 0xDC, 0xE4, 0xEC, 0xF4, 0xFC
+ },
+ {
+ 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
+ 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00,
+ 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700,
+ 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, 0x1E00, 0x1F00
+ },
+ 0x001
+};
+
+static const UINT32 firetrk_trailer_layout_xoffset[64] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
+};
+
+static const UINT32 firetrk_trailer_layout_yoffset[64] =
+{
+ 0x000, 0x040, 0x080, 0x0C0, 0x100, 0x140, 0x180, 0x1C0,
+ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x340, 0x380, 0x3C0,
+ 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, 0x5C0,
+ 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780, 0x7C0,
+ 0x800, 0x840, 0x880, 0x8C0, 0x900, 0x940, 0x980, 0x9C0,
+ 0xA00, 0xA40, 0xA80, 0xAC0, 0xB00, 0xB40, 0xB80, 0xBC0,
+ 0xC00, 0xC40, 0xC80, 0xCC0, 0xD00, 0xD40, 0xD80, 0xDC0,
+ 0xE00, 0xE40, 0xE80, 0xEC0, 0xF00, 0xF40, 0xF80, 0xFC0
+};
+
+static const gfx_layout firetrk_trailer_layout =
+{
+ 64, 64, /* width, height */
+ 8, /* total */
+ 1, /* planes */
+ { 0 },
+ EXTENDED_XOFFS,
+ EXTENDED_YOFFS,
+ 0x1000,
+ firetrk_trailer_layout_xoffset,
+ firetrk_trailer_layout_yoffset
+};
+
+
+static GFXDECODE_START( firetrk )
+ GFXDECODE_ENTRY( REGION_GFX1, 0, firetrk_text_layout, 26, 1 )
+ GFXDECODE_ENTRY( REGION_GFX2, 0, firetrk_tile_layout, 0, 8 )
+ GFXDECODE_ENTRY( REGION_GFX2, 0, firetrk_tile_layout, 16, 3 )
+ GFXDECODE_ENTRY( REGION_GFX3, 0, firetrk_car_layout1, 22, 2 )
+ GFXDECODE_ENTRY( REGION_GFX3, 0, firetrk_car_layout2, 22, 2 )
+ GFXDECODE_ENTRY( REGION_GFX4, 0, firetrk_trailer_layout, 22, 2 )
+GFXDECODE_END
+
+
+static GFXDECODE_START( superbug )
+ GFXDECODE_ENTRY( REGION_GFX1, 0, superbug_text_layout, 26, 1 )
+ GFXDECODE_ENTRY( REGION_GFX2, 0, superbug_tile_layout, 0, 8 )
+ GFXDECODE_ENTRY( REGION_GFX2, 0, superbug_tile_layout, 16, 3 )
+ GFXDECODE_ENTRY( REGION_GFX3, 0, superbug_car_layout1, 22, 2 )
+ GFXDECODE_ENTRY( REGION_GFX3, 0, superbug_car_layout2, 22, 2 )
+GFXDECODE_END
+
+
+static GFXDECODE_START( montecar )
+ GFXDECODE_ENTRY( REGION_GFX1, 0, montecar_text_layout, 44, 1 )
+ GFXDECODE_ENTRY( REGION_GFX2, 0, firetrk_tile_layout, 0, 8 )
+ GFXDECODE_ENTRY( REGION_GFX2, 0, firetrk_tile_layout, 16, 4 )
+ GFXDECODE_ENTRY( REGION_GFX3, 0, montecar_car_layout, 24, 1 )
+ GFXDECODE_ENTRY( REGION_GFX4, 0, montecar_car_layout, 28, 4 )
+GFXDECODE_END
+
+
+static MACHINE_DRIVER_START( firetrk )
+
+ /* basic machine hardware */
+ MDRV_CPU_ADD_TAG("main", M6800, FIRETRK_CPU_CLOCK_1MHZ) /* 750Khz during service mode */
+ MDRV_CPU_PROGRAM_MAP(firetrk_map, 0)
+ MDRV_CPU_VBLANK_INT(firetrk_interrupt, 1)
+ MDRV_WATCHDOG_VBLANK_INIT(5)
+
+ MDRV_SCREEN_REFRESH_RATE(60)
+
+ MDRV_MACHINE_RESET(firetrk)
+
+ /* video hardware */
+ MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
+ MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MDRV_SCREEN_SIZE(320, 262)
+ MDRV_SCREEN_VISIBLE_AREA(0, 319, 0, 239)
+ MDRV_GFXDECODE(firetrk)
+
+ MDRV_PALETTE_INIT(firetrk)
+ MDRV_PALETTE_LENGTH(4)
+ MDRV_COLORTABLE_LENGTH(28)
+
+ MDRV_VIDEO_START(firetrk)
+ MDRV_VIDEO_EOF(firetrk)
+ MDRV_VIDEO_UPDATE(firetrk)
+
+ /* sound hardware */
+ MDRV_SPEAKER_STANDARD_MONO("mono")
+
+ MDRV_SOUND_ADD_TAG("discrete", DISCRETE, 0)
+ MDRV_SOUND_CONFIG_DISCRETE(firetrk)
+ MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+MACHINE_DRIVER_END
+
+
+static MACHINE_DRIVER_START( superbug )
+
+ /* basic machine hardware */
+ MDRV_IMPORT_FROM(firetrk)
+ MDRV_CPU_REPLACE("main", M6800, FIRETRK_CPU_CLOCK_750KZ)
+ MDRV_CPU_PROGRAM_MAP(superbug_map, 0)
+
+ /* video hardware */
+ MDRV_GFXDECODE(superbug)
+
+ MDRV_PALETTE_INIT(firetrk)
+ MDRV_PALETTE_LENGTH(4)
+ MDRV_COLORTABLE_LENGTH(28)
+
+ /* sound hardware */
+ MDRV_SOUND_REPLACE("discrete", DISCRETE, 0)
+ MDRV_SOUND_CONFIG_DISCRETE(superbug)
+ MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+MACHINE_DRIVER_END
+
+
+static MACHINE_DRIVER_START( montecar )
+
+ /* basic machine hardware */
+ MDRV_IMPORT_FROM(firetrk)
+ MDRV_CPU_REPLACE("main", M6800, FIRETRK_CPU_CLOCK_1MHZ) /* 750Khz during service mode */
+ MDRV_CPU_PROGRAM_MAP(montecar_map, 0)
+
+ /* video hardware */
+ MDRV_GFXDECODE(montecar)
+
+ MDRV_PALETTE_INIT(montecar)
+ MDRV_PALETTE_LENGTH(26)
+ MDRV_COLORTABLE_LENGTH(46)
+
+ /* sound hardware */
+ MDRV_SOUND_REPLACE("discrete", DISCRETE, 0)
+ MDRV_SOUND_CONFIG_DISCRETE(montecar)
+ MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+MACHINE_DRIVER_END
+
+
+ROM_START( firetrk )
+ ROM_REGION( 0x4000, REGION_CPU1, 0 )
+ ROM_LOAD( "032823-02.c1", 0x2000, 0x800, CRC(9570bdd3) SHA1(4d26a9490d05d53da55fc59459a4dce5bca6c761) )
+ ROM_LOAD( "032824-01.d1", 0x2800, 0x800, CRC(a5fc5629) SHA1(bf20510d8623eda2740ff296a7813a3e6f7ec76e) )
+ ROM_LOAD_NIB_HIGH( "032816-01.k1", 0x3000, 0x800, CRC(c0535598) SHA1(15cb6985b0b22140b7fae1e050e0b63dd4d0f793) )
+ ROM_LOAD_NIB_LOW ( "032820-01.k2", 0x3000, 0x800, CRC(5733f9ed) SHA1(0f19a40793dadfb7de2c2b54a44929b414d0f4ed) )
+ ROM_LOAD_NIB_HIGH( "032815-01.j1", 0x3800, 0x800, CRC(506ee759) SHA1(d111356c84f3d9942a27fbe243e716d14c258a16) )
+ ROM_LOAD_NIB_LOW ( "032819-01.j2", 0x3800, 0x800, CRC(f1c3fa87) SHA1(d75cf4ad0bcac3289c068837fc24cfe84ce7542a) )
+
+ ROM_REGION( 0x0800, REGION_GFX1, ROMREGION_DISPOSE ) /* text */
+ ROM_LOAD( "032827-01.r3", 0x000, 0x800, CRC(cca31d2b) SHA1(78235176c9cb2abd73a5778b54560b87634ca0e4) )
+
+ ROM_REGION( 0x0800, REGION_GFX2, ROMREGION_DISPOSE ) /* tiles */
+ ROM_LOAD( "032828-02.f5", 0x000, 0x800, CRC(68ef5f19) SHA1(df227d6a57bba6298ebdeb5a118878da21d889f6) )
+
+ ROM_REGION( 0x0400, REGION_GFX3, ROMREGION_DISPOSE ) /* cab */
+ ROM_LOAD( "032831-01.p7", 0x000, 0x400, CRC(bb8d144f) SHA1(9a1355ea6f88e96926c32e0e36ac0525b0243906) )
+
+ ROM_REGION( 0x1000, REGION_GFX4, ROMREGION_DISPOSE ) /* trailer */
+ ROM_LOAD( "032829-01.j5", 0x000, 0x800, CRC(e7267d71) SHA1(7132b98622e899227a378ba8c010dde39c479978) )
+ ROM_LOAD( "032830-01.l5", 0x800, 0x800, CRC(e4d8b685) SHA1(30978658899c83e32dabdf554a13cf5e5235c725) )
+
+ ROM_REGION( 0x100, REGION_PROMS, 0 )
+ ROM_LOAD( "009114.prm", 0x0000, 0x100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync */
+ROM_END
+
+
+ROM_START( superbug )
+ ROM_REGION( 0x2000, REGION_CPU1, 0 )
+ ROM_LOAD( "009121.d1", 0x0800, 0x800, CRC(350df308) SHA1(b957c830bb95e0752ea9793e3edcfdd52235e0ab) )
+ ROM_LOAD( "009122.c1", 0x1000, 0x800, CRC(eb6e3e37) SHA1(5237f6bd3a7a3eca737c728296230cf0d1f436b0) )
+ ROM_LOAD( "009123.a1", 0x1800, 0x800, CRC(f42c6bbe) SHA1(41470984fe951eac9f6dc77862b00ecfe8aaa51d) )
+
+ ROM_REGION( 0x0800, REGION_GFX1, ROMREGION_DISPOSE ) /* text */
+ ROM_LOAD( "009124.m3", 0x0000, 0x400, CRC(f8af8dd5) SHA1(49ab85550f546f85048e2f73163837c602dde568) )
+ ROM_LOAD( "009471.n3", 0x0400, 0x400, CRC(52250698) SHA1(cc55254c54dbcd3fd1465c82a715f2e567f44951) )
+
+ ROM_REGION( 0x1000, REGION_GFX2, ROMREGION_DISPOSE ) /* tiles */
+ ROM_LOAD( "009126.f5", 0x0000, 0x400, CRC(ee695137) SHA1(295fdfef88e0c841fe8ad505151ca0837e77ef83) )
+ ROM_LOAD( "009472.h5", 0x0400, 0x400, CRC(5ddb80ac) SHA1(bdbbbba6efdd4cca75630d203f7c7eaf41b1a32d) )
+ ROM_LOAD( "009127.e5", 0x0800, 0x400, CRC(be1386b4) SHA1(17e92df58b25075ec7a383a958db02b42066578a) )
+ ROM_RELOAD( 0x0C00, 0x400 )
+
+ ROM_REGION( 0x0400, REGION_GFX3, ROMREGION_DISPOSE ) /* car */
+ ROM_LOAD( "009125.k6", 0x0000, 0x400, CRC(a3c835df) SHA1(e9b6dba1919c389bb55a8fe3c074b6702322e4e5) )
+
+ ROM_REGION( 0x0100, REGION_PROMS, 0 )
+ ROM_LOAD( "009114.prm", 0x0000, 0x100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync */
+ROM_END
+
+
+ROM_START( montecar )
+ ROM_REGION( 0x4000, REGION_CPU1, 0 )
+ ROM_LOAD( "35766-01.h1", 0x2000, 0x800, CRC(d3695f09) SHA1(8aa3b3921acd0d2c3230d610843042613defcba9) )
+ ROM_LOAD( "35765-01.f1", 0x2800, 0x800, CRC(9491a7ee) SHA1(712959c5f97be3db7be1d5bd70c780d4da2f6d47) )
+ ROM_LOAD( "35764-01.d1", 0x3000, 0x800, CRC(899aaf4e) SHA1(84fab58d135ffc6e4b076d438b4d588b394364b6) )
+ ROM_LOAD( "35763-01.c1", 0x3800, 0x800, CRC(378bfe47) SHA1(fd6b28907340a2ffc82a4e634273c3f03ab76642) )
+
+ ROM_REGION( 0x0400, REGION_GFX1, ROMREGION_DISPOSE ) /* text */
+ ROM_LOAD( "35778-01.m4", 0x0000, 0x400, CRC(294ee08e) SHA1(fbb0656468a027b2795073d811affc93c50994ec) )
+
+ ROM_REGION( 0x0800, REGION_GFX2, ROMREGION_DISPOSE ) /* tiles */
+ ROM_LOAD( "35775-01.e6", 0x0000, 0x800, CRC(504106e9) SHA1(33eae2cf39b24eaf5b438a2af3060b2fdc0012b5) )
+
+ ROM_REGION( 0x0800, REGION_GFX3, ROMREGION_DISPOSE ) /* car */
+ ROM_LOAD( "35779-01.m6", 0x0000, 0x800, CRC(4fbb3fe1) SHA1(4267cd098a19892322d21f8fa7b55896158f8d6a) )
+
+ ROM_REGION( 0x0800, REGION_GFX4, ROMREGION_DISPOSE ) /* drone */
+ ROM_LOAD( "35780-01.b6", 0x0000, 0x800, CRC(9d0f1374) SHA1(52d1130d48dc877e1e47e26b2e4548633ed91b21) )
+
+ ROM_REGION( 0x300, REGION_PROMS, 0 )
+ ROM_LOAD( "35785-01.e7", 0x0000, 0x200, CRC(386c543a) SHA1(04edda180e6ff432b438947ffa46621ca0a823b4) ) /* color */
+ ROM_LOAD( "9114.prm", 0x0200, 0x100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync */
+ROM_END
+
+
+GAME( 1977, superbug, 0, superbug, superbug, superbug, ROT270, "Atari", "Super Bug", 0 )
+GAME( 1978, firetrk, 0, firetrk, firetrk, firetrk, ROT270, "Atari", "Fire Truck", 0 )
+GAME( 1979, montecar, 0, montecar, montecar, montecar, ROT270, "Atari", "Monte Carlo", 0 )
'#n1950'>1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827
/*
   Taito Type-Zero hardware

   Driver by Ville Linde


Landing High Japan PCB info
===========================

Taito Landing High

Top board
    silkscreened        TYPE-ZERO MOTHER PCB

    stickered       298100308
                K11X0886A
                JC101

.5  29LV400BC-90        stamped E68-05-1
.6  29LV400BC-90        stamped E68-04-1
.24 PALV 18V8-10JC      stamped E68-06


IC30    Taito TCG020AGP
IC26    IDT7024 S35J V9928P
IC10    IBM EMPPC603eBG-100
IC53    ADV7120KP30 9926 F101764.1
IC16,17         M54256V32A-10
IC15,25,31,39,45,49,44  48D4811650GF-A10-9BT
IC27,36         D4564163G5-A10n-9JF
IC 41,46,42,47      D4516161AG5-A10B-9F
IC43            QSV991-7JRI
66.6667 Oscillator near IC43

Bottom board
    silkscreened        JC101 DAUGHTER PCB

    stickered       K91J0775A
                LANDING H.JAPAN

                299100308

                M43J0741A
                LANDING H.JAPAN

.14 27c1001     stickered   E82
                    03*

.15 27c1001     stickered   E82
                    04*

.44 PALCE16V8H  stamped     E82-01

.45 PALCE22V10H stamped     E82-02

IC40    Toshiba TMP95C063F
IC55    Panasonic MN89306
EPSON 9X5C pscillator near IC55
IC56    HY57V161610D TC-10
IC22    ID7133 SA70J
25.000 oscillator near IC22
IC11    Xilinx XC9572
IC5 HY5118164C JC-60
IC10    ZOOM ZSG-2
IC20    ZOOM ZFX 2 HD 96NE2VJ
IC26    TM TECH  UA4464V T224162B-28J
IC7 Panasonic MN1020819DA E68-01
20.000 oscillator near IC7



Rizing Ping Pong
Taito 2002

This game runs on Taito Type Zero hardware.

PCB Layout
----------

TYPE ZERO MOTHER PCB
K11X0878A
J1100365A
K11X0951A (Sticker)
|-----------------------------------------------------------|
|   D4811650 D4811650 D4811650 D4811650 D4811650  E87-02.IC6|
|   D4811650 D4811650 D4811650                              |
|                                                           |
|G                                     M54V25632            |
|                        |-----------|            E87-01.IC5|
|   AD8073               | TAITO     |                      |
|                        | TCG020AGP | M54V25632            |
|        HY57V161610     |           |                      |
|   ADV7120KP30          |           |                      |
|        HY57V161610     |           |                      |
|        HY57V161610     |-----------|                      |
|        HY57V161610      V54C365164                        |
|                         V54C365164                        |
|                                                           |
|                                PAL16V8                    |
|               QS5V991          (E68-06)                   |
|            66.6667MHz                                     |
|                                  |-------|M51955A         |
|                                  |       |      |-------| |
|                                  |IDT7024|      |PPC603E| |
|                                  |       |      |       | |
|                                  |-------|      |-------| |
|                                                           |
|-----------------------------------------------------------|


TYPE ZERO DAUGHTER PCB
K9100745A
J9100491A
RIZINGPINGPONG K91J0905A (Sticker)
RIZINGPINGPONG M43J0775A (Sticker)
|-----------------------------------------------------------|
|RESET_SW  5.5V        RTC64613                             |
|          SUPERCAP  MB3790               F14-02.IC15       |
|DS14C239              LC3564                               |
|                                         F14-01.IC14       |
|        IDC40       LC321664                               |
|TD62064                                               20MHz|
|          TOSHIBA            IDT7133         MN1020819     |
|          TMP95C063                          (E68-01)      |
|                     PAL16V8                               |
|                     (E68-03)  25MHz XC9572                |
|                                             HY5118164     |
|             3.686MHz                                      |
|                                                           |
|C        SN74S1057                                         |
|                                                           |
|                                                           |
|                                 ZOOM      ZOOM            |
|                      V53C16258  ZFX-2     ZSG-2           |
|                                                           |
|                 MC3418          GM71C17403  GM71C17403    |
|           LA2650     LC78834M                             |
|                                 GM71C17403  GM71C17403    |
|                                                           |
|-----------------------------------------------------------|
Notes:
      Connectors C (daughter) and G (main) join to filter board
      IDC40 - IDE HDD connector for Quantum Fireball LCT 4.3AT LA04A011 Rev 01-A
              Serial number 691934013492 DGPXX
              Sticker on HDD reads.....
              4.3GB QUANTUM
              QML04300LA-A
              RIZING PING PONG EXP
              M9005557A VER. 2.01O  (note '01O' is slightly scratched and could be incorrect)


*/

#define ADDRESS_MAP_MODERN

#include "emu.h"
#include "cpu/powerpc/ppc.h"
#include "cpu/tlcs900/tlcs900.h"
#include "machine/idectrl.h"
#include "machine/nvram.h"
#include "video/polynew.h"

/*
    Interesting mem areas

    0x40080400...0x400807fc: PPC Interrupt handler table for TLCS900 interrupts (called from 0x4002ea80)
        0x40080440 (0x10): 0x4003b274       (0xfc06f7 on TLCS sets 0x1000)
        0x400804c0 (0x30): 0x4003f1e4       (INT1 handler on TLCS sets 0x3010)  (comms, could be IEEE1394)
        0x40080500 (0x40): 0x4002ed94       (debug/trace)
        0x40080504 (0x41): 0x4002ede4       (debug/break)
        0x40080540 (0x50): 0x4003c21c                                                           0x5001: sets 0x00000001 in 0x40049c58
        0x40080740 (0xd0): 0x4002ecc0       (INT3 handler on TLCS sets 0xd000)  (VBlank?)
        0x400807c0 (0xf0): 0x4002eae4       (0xfc0a44 on TLCS sets 0xf001)

    PPC -> TLCS Commands:
        0x1000:            0x4003a9e0()                             HDD Reset
        0x1001:            0x4003aa14()                             HDD Init. Writes HDD status and error to io_shared[0x1a00].
        0x1010:            0x4003aaf4(), 0x4003ab8c()               HDD Read Sector
        0x1020:            0x4003ac1c()                             HDD Write Sector
        0x4000:            ?                                        Related to sound loading?
        0x4001:            0x400429b0()                             MBox related
        0x4002:            ?                                        Loads a byte from MBox ram. Address in io_shared[0x1c04]
        0x4003:            ?                                        Writes a byte into MBox ram. Address in io_shared[0x1c04], data in io_shared[0x1c06].
        0x4004:            0x40042bc4(), 0x40042c50()               Play music/sound? Params in io_shared[0x1c08...0x1c12]
        0x5000:            0x4003bc68()                             Reset RTC?
        0x5010:            0x4003bb68()                             Read RTC
        0x5020:            0x4003bbec()                             Write RTC
        0x6000:            ?                                        Backup RAM Read. Address in io_shared[0x1d00].
        0x6010:            ?                                        Backup RAM Write. Address in io_shared[0x1d00].
        0x7000:            0x4003d1c4()
        0x7001:            0x4003d28c()
        0x7002:            0x4003d4ac()
        0x7003:            0x4003d508()
        0x7004:            0x4003d554()
        0x7005:            0x4003d168()
        0x8000:            ?                                        Used by vibration (force feedback?) on pwrshovl
        0xa000:            ?                                        Used by vibration (force feedback?) on pwrshovl
        0xf000:            0x4002f328() TLCS_Init
        0xf010:            0x4002f074()                             Enables TLCS watchdog timer
        0xf011:            0x4002f0a8()                             Disables TLCS watchdog
        0xf020:            ?
        0xf055:            0x4002f0dc()                             Enables TLCS watchdog and infloops the TLCS
        0xf0ff:            ?                                        TLCS soft reset?

    TLCS -> PPC Commands:
        0x10xx:            0xfc06f7()                               HDD Command ack?
                                                                    0x40094ec8:
                                                                        0x00:   IDLE
                                                                        0x10:   READ
                                                                        0x11:   READ SECTOR
                                                                        0x12:   READ ALL
                                                                        0x20:   WRITE
                                                                        0x21:   WRITE SECTOR
                                                                        0x22:   WRITE ALL
                                                                        0x30:   VENDER
                                                                        0xff:   ERROR
                                                                        0x??:   UNKNOWN
        0x3010:            0xfc071c() int1 handler                  Comm IRQ, IEEE1394
        0x40xx:            ?                                        Debug
        0x41xx:            ?                                        Debug
        0x5001:            ?                                        RTC?
        0xd000:            0xfc06b4() int3 handler                  VBlank? Runs a counter on the PPC side
        0xf001:            0xfc0a44()                               PPC sync?


    BG2 intro packet writes:

    construction?
    0x4012f390()
        -> 0x401304f0() scene graph parser?
            -> 0x40130d60()
                -> 0x401aff48()     R3 = dest, R4 = source, R5 = length

    0x40174674()
    0x401ba294()
                            R3 = 0x000007d0, R4 = 0x40707bac, R5 = 0x00000398

                            f1 00 00 63 0c 00 00 7f 0c 00 00 00 08 00 00 00
                            00 40 01 3e 00 00 81 00 00 00 7f 00 00 7f 00 00
                            00 40 3e 3e 00 00 7f 00 00 00 7f 00 00 7f 00 00
                            00 40 3e 00 00 00 7f 00 00 00 81 00 00 7f 00 00
                            00 40 01 00 00 00 81 00 00 00 81 00 00 7f 00 00
                            f1 00 00 69 00 00 7f 00 0c 7f 00 00 0d 00 00 7f
                            00 40 00 3f 00 00 e0 40 00 00 00 00 00 7f 7f 00
                            00 40 00 00 00 00 e0 40 00 00 00 00 00 7f 81 00
                            00 40 1f 00 00 00 1f c0 00 00 00 00 00 7f 81 00
                            00 40 1f 3f 00 00 1f c0 00 00 00 00 00 7f 7f 00
                            ...

                            R3 = 0x00000b68, R4 = 0x40707e58, R5 = 0x00001000

                            e1 00 00 73 00 81 00 00 04 00 00 00 0c 00 00 00
                            00 40 06 00 00 94 fd d1 00 d2 82 ce 00 2e 03 ef
                            00 40 06 00 00 99 fd d1 00 c0 82 ce 00 df 00 40
                            00 40 06 02 00 91 fd d1 00 ef 88 9e 00 c7 fc 40
                            00 40 06 1f 00 88 fd d1 00 00 b8 60 00 26 03 ef
                            e0 00 00 73 00 81 00 00 04 00 00 00 0c 00 00 00
                            00 40 06 1f 00 8b fd d1 00 00 b8 60 00 d0 fc 40
                            00 40 06 1f 00 88 fd d1 00 00 b8 60 00 26 03 ef
                            00 40 06 02 00 91 fd d1 00 ef 88 9e 00 c7 fc 40
                            ...

                            R3 = 0x00001b68, R4 = 0x40707e58, R5 = 0x00000d19
                            R3 = 0x00075770, R4 = 0x40443e2c, R5 = 0x00000014
                            R3 = 0x00075784, R4 = 0x40443e7c, R5 = 0x00000014
                            R3 = 0x00075798, R4 = 0x40443ecc, R5 = 0x00000014
                            R3 = 0x000757ac, R4 = 0x40443f1c, R5 = 0x00000014
                            R3 = 0x000757c0, R4 = 0x40443e6c, R5 = 0x00000014

                            R3 = 0x00062ca0, R4 = 0x409cfa70, R5 = 0x000001e0
                            R3 = 0x00008ca0, R4 = 0x409f8f70, R5 = 0x000002c5
                            R3 = 0x00002ba4, R4 = 0x40fffaf0, R5 = 0x00000028
                            R3 = 0x0001f4a0, R4 = 0x40a06350, R5 = 0x00000340
                            R3 = 0x00002bcc, R4 = 0x40fffaf0, R5 = 0x00000028

                            R3 = 0x00000190, R4 = 0x40fff8f8, R5 = 0x00000014

    0x40188514()
                            R3 = 0x0000d818, R4 = 0x40ffcce0, R5 = 0x00000bc0

                            00 00 00 dd 00 00 00 00 00 00 00 00 00 00 00 00
                            00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            ...

                            R3 = 0x0001494c, R4 = 0x40ffcce0, R5 = 0x00000bc0

    0x40116c28():       Draws 2D images
                            R3 = 0x009e0c7a, R4 = 0x40a7c3bc, R5 = 0x0000007c

    0x40116a80():       Clears 2D images?
                            R3 = 0x009f6308, R4 = 0x40a9a784, R5 = 0x000000f0



        -> 0x40116430():    R3 = dest (|= 0x30800000), R4 = source, R5 = num words
            -> 0x401162ac() WriteVideoMem:      R3 = source, R4 = dest, R5 = num words
                -> 0x401064b0() Write video data using FIFO:        R3 = source, R4 = dest, R5 = num words (must be divisible by 8)
                -> 0x40106668() Write video data using write port:  R3 = source, R4 = dest, R5 = num words



    0x40106788(): FIFO Packet write:            R3 = source, R4 = select between cmd 0 and 1, R5 = num words (must be divisible by 8)



    BG2: 4x4 Matrices at 0x40223218
            word 0: ?? (0x62e6c, 0xf20a0, ...)      anded by 0x1fffff on read, or'd by 0xff800000, or'd by 0x400000 if no matrix, store -> [0x00]
            word 1: ?? (usually zero)
            word 2: float (often 1.0)               multiplied by 31.0f, converted to (int), anded by 0x1f, or by 0x80 if word 1 == 1, store -> [0x08]
            word 3: float                           if (exponent < 1, mult by 0.5), store -> [0x04]
            word 4: usually 0x00000001              if 0, matrix not stored
            16x float: 4x4 matrix
                matrix[0][0] -> store [0x10]
                matrix[1][0] -> store [0x14]
                matrix[2][0] -> store [0x18]
                matrix[3][0] -> store [0x1c]
                ...
            word 0: Pointer to another matrix
            word 1: Pointer to another matrix

        0x401afffc(): Write

    0x40118af0():
        -> 0x401195e0(): Read   (Transposes matrix, only columns 0-2 stored + 4 extra command words)

        -> 0x40118080: Read, store to [0x40362314+], never read


    Display list top?:      0x403408c0 (pointer to at 0x4020b80c)
                 bottom?:   0x403608e4 (pointer to at 0x4020b81c)

    0x40123fcc():
        -> 0x401186c8():    Display list parser?

    0x40117fb4():   Insert command to disp list. R3 = command word

    Display list format
    -------------------
                    0xffff0010: ?

                    0xffff0011: Draw Polygon Object
                                0 = Polygon data address (21 bits) in screen RAM (in dwords). If 0x400000 set, no matrix.
                                1 = Object scale (float), if <1.0f multiply scale by 2.0f
                                2 = 0x80 = object alpha enable, 0x1f = object alpha (0x1f = opaque)
                                3 = ?
                                4...15 = 4x3 matrix

                    0xffff0020: ? (no parameters)

                    0xffff0021: Draw Pretransformed Polygon (used for drawing the background images)
                                0 = address? (if 0x400 set, 24 words)
                                1 = Texture number (* 0x4000 to address the texture)
                                2 = ?
                                3 = ? (usually 0)

                                Vertex data: 4x or 5x 4 words
                                0 = XY coordinates. X = high 16 bits, Y = low 16 bits
                                1 = Z value?
                                2 = UV coordinates. U = high 16 bits, V = low 16 bits (possibly shifted left by 4?)
                                3 = ? (usually 0)

                    0xffff0022: ? (1 word)
                                0 = ? (Set to 0x00000001 before drawing the background. Z-buffer read disable?)

                    0xffff0030: ? (2 + n words) FIFO write?
                                0 = ?
                                1 = num of words
                                n words = ?

                    0xffff0080: Display List Call?

                    0xffff00ff: End of List?

    Polygon data format
    -------------------

    Word 0:
                    ---x---- -------- -------- --------     1: this is the last polygon of the model
                    -------x -------- -------- --------     0: triangle, 1: quad
                    -------- -------- -----xxx xxxxxxxx     Texture number (* 0x4000 to address the texture)

    Word 1:
                    ?

    Word 2:
                    ?

    Word 3:
                    ?

    Vertex data: 3x (triangle) or 4x (quad) 4 words
    Word 0:
                    -------- -------- -------- xxxxxxxx     Texture V coordinate (0..63 with max 4x repeat)
                    -------- -------- xxxxxxxx --------     Texture U coordinate (0..63 with max 4x repeat)
                    -------- xxxxxxxx -------- --------     Usually 0x40. HUD elements set 0xff. Self-illumination?

    Word 1:
                    -------- -------- xxxxxxxx xxxxxxxx     Vertex X coordinate (signed 8.8 fixed point)
                    -------- xxxxxxxx -------- --------     Normal X (signed 1.7 fixed point)

    Word 2:
                    -------- -------- xxxxxxxx xxxxxxxx     Vertex Y coordinate (signed 8.8 fixed point)
                    -------- xxxxxxxx -------- --------     Normal Y (signed 1.7 fixed point)

    Word 3:
                    -------- -------- xxxxxxxx xxxxxxxx     Vertex Z coordinate (signed 8.8 fixed point)
                    -------- xxxxxxxx -------- --------     Normal Z (signed 1.7 fixed point)

    3D registers
    ------------

    0x00000100:     xxxxxxxx xxxxxxxx -------- --------     Viewport Y?
                    -------- -------- xxxxxxxx xxxxxxxx     Viewport X?

    0x00000101:     xxxxxxxx xxxxxxxx -------- --------     Viewport center X? (usually 255 or 240)
                    -------- -------- xxxxxxxx xxxxxxxx     Viewport center Y? (usually 200 or 191)

    0x00000102:     xxxxxxxx xxxxxxxx -------- --------     ? (usually 0x100)
                    -------- -------- xxxxxxxx xxxxxxxx     ? (usually 0x100 or 0xc0)

    0x00000103:

    0x00000104:

    0x10000100:

    0x10000101:

    0x10000102:     xxxxxxxx xxxxxxxx -------- --------     Diffuse light color (ARGB1555)
                    -------- -------- xxxxxxxx xxxxxxxx     Ambient light color (ARGB1555)

    0x10000103:

    0x10000104:

    0x10000105:
*/

#define LOG_PPC_TO_TLCS_COMMANDS		1
#define LOG_TLCS_TO_PPC_COMMANDS		1

#define LOG_DISPLAY_LIST				0

#define PPC_TLCS_COMM_TRIGGER			12345
#define TLCS_PPC_COMM_TRIGGER			12346

struct taitotz_polydata
{
	UINT32 texture;
	UINT32 alpha;
	int diffuse_r, diffuse_g, diffuse_b;
	int ambient_r, ambient_g, ambient_b;
	int specular_r, specular_g, specular_b;
};

struct PLANE
{
	float x, y, z, d;
};

typedef float VECTOR3[3];

class taitotz_renderer : public poly_manager<float, taitotz_polydata, 6, 50000>
{
public:
	taitotz_renderer(running_machine &machine, int width, int height, UINT32 *texram)
		: poly_manager<float, taitotz_polydata, 6, 50000>(machine)
	{
		m_zbuffer = auto_bitmap_ind32_alloc(machine, width, height);
		m_texture = texram;

		m_light_vector[0] = 0.0f;
		m_light_vector[1] = 0.0f;
		m_light_vector[2] = -1.0f;

		m_diffuse_intensity = 224;
		m_ambient_intensity = 32;
		m_specular_intensity = 256;
		m_specular_power = 10;
	}

	void set_fb(bitmap_rgb32 *fb) { m_fb = fb; }
	void render_displaylist(running_machine &machine, const rectangle &cliprect);
	void draw_object(running_machine &machine, UINT32 address, float scale, UINT8 alpha);
	float line_plane_intersection(const vertex_t *v1, const vertex_t *v2, PLANE cp);
	int clip_polygon(const vertex_t *v, int num_vertices, PLANE cp, vertex_t *vout);
	void setup_viewport(int x, int y, int width, int height, int center_x, int center_y);
	void draw_scanline_noz(INT32 scanline, const extent_t &extent, const taitotz_polydata &extradata, int threadid);
	void draw_scanline(INT32 scanline, const extent_t &extent, const taitotz_polydata &extradata, int threadid);

private:
	enum
	{
		POLY_Z		= 0,
		POLY_U		= 1,
		POLY_V		= 2,
		POLY_NX		= 3,
		POLY_NY		= 4,
		POLY_NZ		= 5,
	};

	//static const float ZBUFFER_MAX = 10000000000.0f;

	bitmap_rgb32 *m_fb;
	bitmap_ind32 *m_zbuffer;
	UINT32 *m_texture;

	PLANE m_clip_plane[6];
	float m_matrix[4][3];

	VECTOR3 m_light_vector;
	float m_diffuse_intensity;
	float m_ambient_intensity;
	float m_specular_intensity;
	float m_specular_power;

	int m_ambient_r;
	int m_ambient_g;
	int m_ambient_b;
	int m_diffuse_r;
	int m_diffuse_g;
	int m_diffuse_b;
	int m_specular_r;
	int m_specular_g;
	int m_specular_b;

	float m_vp_center_x;
	float m_vp_center_y;
	float m_vp_focus;
	float m_vp_x;
	float m_vp_y;
	float m_vp_mul;

	UINT32 m_reg_100;
	UINT32 m_reg_101;
	UINT32 m_reg_102;
};



class taitotz_state : public driver_device
{
public:
	taitotz_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag),
		m_maincpu(*this, "maincpu"),
		m_iocpu(*this, "iocpu"),
		m_work_ram(*this, "work_ram"),
		m_mbox_ram(*this, "mbox_ram") { }

	required_device<cpu_device> m_maincpu;
	required_device<cpu_device> m_iocpu;
	required_shared_ptr<UINT64> m_work_ram;
	required_shared_ptr<UINT8>  m_mbox_ram;

	DECLARE_READ64_MEMBER(ppc_common_r);
	DECLARE_WRITE64_MEMBER(ppc_common_w);
	DECLARE_READ64_MEMBER(ieee1394_r);
	DECLARE_WRITE64_MEMBER(ieee1394_w);
	DECLARE_READ64_MEMBER(video_chip_r);
	DECLARE_WRITE64_MEMBER(video_chip_w);
	DECLARE_READ64_MEMBER(video_fifo_r);
	DECLARE_WRITE64_MEMBER(video_fifo_w);

	UINT32 *m_screen_ram;
	UINT32 *m_frame_ram;
	UINT32 *m_texture_ram;
	UINT32 m_video_unk_reg[0x10];

	UINT32 m_video_fifo_ptr;
	UINT32 m_video_ram_ptr;
	UINT32 m_video_reg;
	UINT32 m_scr_base;

	UINT64 m_video_fifo_mem[4];

	UINT16 m_io_share_ram[0x2000];

	const char *m_hdd_serial_number;

	DECLARE_READ8_MEMBER(tlcs_common_r);
	DECLARE_WRITE8_MEMBER(tlcs_common_w);
	DECLARE_READ8_MEMBER(tlcs_rtc_r);
	DECLARE_WRITE8_MEMBER(tlcs_rtc_w);
	DECLARE_WRITE8_MEMBER(tlcs900_to1);
	DECLARE_WRITE8_MEMBER(tlcs900_to3);
	DECLARE_READ8_MEMBER(tlcs900_port_read);
	DECLARE_WRITE8_MEMBER(tlcs900_port_write);

	UINT8 m_rtcdata[8];



	UINT32 m_reg105;
	UINT32 m_displist_addr;
	int m_count;

	taitotz_renderer *m_renderer;
	DECLARE_DRIVER_INIT(batlgr2a);
	DECLARE_DRIVER_INIT(batlgr2);
	DECLARE_DRIVER_INIT(pwrshovl);
	DECLARE_DRIVER_INIT(batlgear);
	DECLARE_DRIVER_INIT(landhigh);
	DECLARE_DRIVER_INIT(raizpin);
	virtual void machine_start();
	virtual void machine_reset();
	virtual void video_start();
	UINT32 screen_update_taitotz(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
	INTERRUPT_GEN_MEMBER(taitotz_vbi);
	DECLARE_READ8_MEMBER(tlcs_ide0_r);
	DECLARE_WRITE8_MEMBER(tlcs_ide0_w);
	DECLARE_READ8_MEMBER(tlcs_ide1_r);
	DECLARE_WRITE8_MEMBER(tlcs_ide1_w);
	DECLARE_WRITE_LINE_MEMBER(ide_interrupt);
};


static void taitotz_exit(running_machine &machine)
{
	/*
    taitotz_state *state = machine.driver_data<taitotz_state>();

    FILE *file;
    int i;

    file = fopen("screen_ram.bin","wb");
    for (i=0; i < 0x200000; i++)
    {
        fputc((UINT8)(state->m_screen_ram[i] >> 24), file);
        fputc((UINT8)(state->m_screen_ram[i] >> 16), file);
        fputc((UINT8)(state->m_screen_ram[i] >> 8), file);
        fputc((UINT8)(state->m_screen_ram[i] >> 0), file);
    }
    fclose(file);

    file = fopen("frame_ram.bin","wb");
    for (i=0; i < 0x80000; i++)
    {
        fputc((UINT8)(state->m_frame_ram[i] >> 24), file);
        fputc((UINT8)(state->m_frame_ram[i] >> 16), file);
        fputc((UINT8)(state->m_frame_ram[i] >> 8), file);
        fputc((UINT8)(state->m_frame_ram[i] >> 0), file);
    }
    fclose(file);

    file = fopen("texture_ram.bin","wb");
    for (i=0; i < 0x800000; i++)
    {
        fputc((UINT8)(state->m_texture_ram[i] >> 24), file);
        fputc((UINT8)(state->m_texture_ram[i] >> 16), file);
        fputc((UINT8)(state->m_texture_ram[i] >> 8), file);
        fputc((UINT8)(state->m_texture_ram[i] >> 0), file);
    }
    fclose(file);
    */
}

void taitotz_state::video_start()
{

	int width = machine().primary_screen->width();
	int height = machine().primary_screen->height();

	m_screen_ram = auto_alloc_array(machine(), UINT32, 0x200000);
	m_frame_ram = auto_alloc_array(machine(), UINT32, 0x80000);
	m_texture_ram = auto_alloc_array(machine(), UINT32, 0x800000);

	/* create renderer */
	m_renderer = auto_alloc(machine(), taitotz_renderer(machine(), width, height, m_texture_ram));

	machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(taitotz_exit), &machine()));
}

static const float dot3_tex_table[32] =
{
	-0.500000f, -0.466666f, -0.433333f, -0.400000f, -0.366666f, -0.333333f, -0.300000f, -0.266666f,
	-0.233333f, -0.200000f, -0.166666f, -0.133333f, -0.100000f, -0.066666f, -0.033333f, -0.000000f,
	 0.000000f,  0.033333f,  0.066666f,  0.100000f,  0.133333f,  0.166666f,  0.200000f,  0.233333f,
	 0.266666f,  0.300000f,  0.333333f,  0.366666f,  0.400000f,  0.433333f,  0.466666f,  0.500000f,
};

INLINE float dot_product_vec3(VECTOR3 a, VECTOR3 b)
{
	return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
}

// Fast inverse square-root
// Adapted from http://en.wikipedia.org/wiki/Fast_inverse_square_root
INLINE float finvsqrt(float number)
{
	UINT32 i;
	float x2, y;
	const float threehalfs = 1.5f;

	x2 = number * 0.5f;
	y  = number;
	i  = *(UINT32*)&y;
    i  = 0x5f3759df - ( i >> 1 );
    y  = *(float*)&i;
    y  = y * ( threehalfs - ( x2 * y * y ) );
	return y;
}

INLINE void normalize_vec3(VECTOR3 *v)
{
	float l = finvsqrt(*v[0] * *v[0] + *v[1] * *v[1] + *v[2] * *v[2]);
	*v[0] *= l;
	*v[1] *= l;
	*v[2] *= l;
}

INLINE float clamp_pos(float v)
{
	if (v < 0.0f)
		return 0.0f;
	else
		return v;
}

INLINE UINT32 generate_texel_address(int iu, int iv)
{
	// generate texel address from U and V
	UINT32 addr = 0;
	addr += (iu & 0x01) ? 1 : 0;
	addr += (iu >> 1) * 4;
	addr += (iv & 0x01) ? 2 : 0;
	addr += (iv >> 1) * 128;

	return addr;
}

void taitotz_renderer::draw_scanline_noz(INT32 scanline, const extent_t &extent, const taitotz_polydata &extradata, int threadid)
{
	UINT32 *fb = &m_fb->pix32(scanline);

	float u = extent.param[POLY_U].start;
	float v = extent.param[POLY_V].start;
	float du = extent.param[POLY_U].dpdx;
	float dv = extent.param[POLY_V].dpdx;

	UINT32 *texram = &m_texture[extradata.texture * 0x1000];

	int shift = 16;		// TODO: subtexture

	for (int x = extent.startx; x < extent.stopx; x++)
	{
		int iu = (int)(u) & 0x3f;
		int iv = (int)(v) & 0x3f;

		UINT32 addr = generate_texel_address(iu, iv);

		UINT32 texel = (texram[addr] >> shift) & 0xffff;
		if (!(texel & 0x8000))
		{
			int r = (texel & 0x7c00) << 9;
			int g = (texel & 0x03e0) << 6;
			int b = (texel & 0x001f) << 3;
			fb[x] = 0xff000000 | r | g | b;
		}

		u += du;
		v += dv;
	}
}

void taitotz_renderer::draw_scanline(INT32 scanline, const extent_t &extent, const taitotz_polydata &extradata, int threadid)
{
	UINT32 *fb = &m_fb->pix32(scanline);
	float *zb = (float*)&m_zbuffer->pix32(scanline);

	float ooz = extent.param[POLY_Z].start;
	float uoz = extent.param[POLY_U].start;
	float voz = extent.param[POLY_V].start;
	float dooz = extent.param[POLY_Z].dpdx;
	float duoz = extent.param[POLY_U].dpdx;
	float dvoz = extent.param[POLY_V].dpdx;

	float nx= extent.param[POLY_NX].start;
	float dnx = extent.param[POLY_NX].dpdx;
	float ny = extent.param[POLY_NY].start;
	float dny = extent.param[POLY_NY].dpdx;
	float nz = extent.param[POLY_NZ].start;
	float dnz = extent.param[POLY_NZ].dpdx;

	UINT32 *texram = &m_texture[extradata.texture * 0x1000];
	UINT32 alpha = extradata.alpha & 0x1f;
	UINT32 alpha_enable = extradata.alpha & 0x80;
	int diff_r = extradata.diffuse_r;
	int diff_g = extradata.diffuse_g;
	int diff_b = extradata.diffuse_b;
	int amb_r = extradata.ambient_r;
	int amb_g = extradata.ambient_g;
	int amb_b = extradata.ambient_b;
	int spec_r = extradata.specular_r;
	int spec_g = extradata.specular_g;
	int spec_b = extradata.specular_b;

	// TODO: these might get swapped around, the color texture doesn't always seem to be tex0
	int tex0_shift = 0;
	int tex1_shift = 16;

	VECTOR3 view = { -0.0f, -0.0f, -1.0f };

	for (int x = extent.startx; x < extent.stopx; x++)
	{
		if (ooz > zb[x])
		{
			float z = 1.0f / ooz;
			float u = uoz * z;
			float v = voz * z;
			int iu = (int)(u) & 0x3f;
			int iv = (int)(v) & 0x3f;

			UINT32 addr = generate_texel_address(iu, iv);

			UINT32 texel = texram[addr];
			UINT32 texel0 = (texel >> tex0_shift) & 0xffff;
			if (!(texel0 & 0x8000))
			{
				VECTOR3 normal;
				VECTOR3 half;

				// fetch texture1 and apply normal map
				UINT32 texel1 = (texel >> tex1_shift) & 0xffff;
				float bumpx = dot3_tex_table[(texel1 & 0x7c00) >> 10];
				float bumpy = dot3_tex_table[(texel1 & 0x03e0) >>  5];
				float bumpz = dot3_tex_table[(texel1 & 0x001f)];

				// FIXME!!! the normal needs to be in tangent-space so the bump normal can be applied!!!
				normal[0] = nx + bumpx;
				normal[1] = ny + bumpy;
				normal[2] = nz + bumpz;

				// normalize
				float l = finvsqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);
				normal[0] *= l;
				normal[1] *= l;
				normal[2] *= l;

				// calculate per-pixel lighting
				float dot = dot_product_vec3(normal, m_light_vector);


				// calculate half-angle vector for specular
				half[0] =  m_light_vector[0] + view[0];
				half[1] =  m_light_vector[1] + view[1];
				half[2] =  m_light_vector[2] + view[2];
				// normalize it
				l = finvsqrt(half[0] * half[0] + half[1] * half[1] + half[2] * half[2]);
				half[0] *= l;
				half[1] *= l;
				half[2] *= l;

				// calculate specularity
				int specular = (int)(pow(clamp_pos(dot_product_vec3(normal, half)), m_specular_power) * m_specular_intensity);

				int intensity = (int)(dot * m_diffuse_intensity);

				// extract texel RGB
				int r = (texel0 & 0x7c00) >> 7;
				int g = (texel0 & 0x03e0) >> 2;
				int b = (texel0 & 0x001f) << 3;

				// apply lighting
				r = ((r * intensity * diff_r) >> 16) + ((r * amb_r) >> 8) + ((specular * spec_r) >> 8);
				g = ((g * intensity * diff_g) >> 16) + ((g * amb_g) >> 8) + ((specular * spec_g) >> 8);
				b = ((b * intensity * diff_b) >> 16) + ((b * amb_b) >> 8) + ((specular * spec_b) >> 8);

				if (r > 255) r = 255;
				if (g > 255) g = 255;
				if (b > 255) b = 255;
				if (r < 0) r = 0;
				if (g < 0) g = 0;
				if (b < 0) b = 0;

				// alpha blending
				if (alpha_enable && alpha < 0x1f)
				{
					int sr = (fb[x] >> 16) & 0xff;
					int sg = (fb[x] >>  8) & 0xff;
					int sb = fb[x] & 0xff;
					int a = alpha + 1;
					r = ((r * a) >> 5) + ((sr * (31 - a)) >> 5);
					g = ((g * a) >> 5) + ((sg * (31 - a)) >> 5);
					b = ((b * a) >> 5) + ((sb * (31 - a)) >> 5);
				}


				// write to framebuffer
				fb[x] = 0xff000000 | (r << 16) | (g << 8) | b;
			}

			zb[x] = ooz;
		}

		ooz += dooz;
		uoz += duoz;
		voz += dvoz;

		nx += dnx;
		ny += dny;
		nz += dnz;
	}
}

INLINE int is_point_inside(float x, float y, float z, PLANE cp)
{
	float s = (x * cp.x) + (y * cp.y) + (z * cp.z) + cp.d;
	if (s >= 0.0f)
		return 1;
	else
		return 0;
}

float taitotz_renderer::line_plane_intersection(const vertex_t *v1, const vertex_t *v2, PLANE cp)
{
	float x = v1->x - v2->x;
	float y = v1->y - v2->y;
	float z = v1->p[POLY_Z] - v2->p[POLY_Z];
	float t = ((cp.x * v1->x) + (cp.y * v1->y) + (cp.z * v1->p[POLY_Z])) / ((cp.x * x) + (cp.y * y) + (cp.z * z));
	return t;
}

int taitotz_renderer::clip_polygon(const vertex_t *v, int num_vertices, PLANE cp, vertex_t *vout)
{
	vertex_t clipv[10];
	int clip_verts = 0;
	float t;
	int i;

	int previ = num_vertices - 1;

	for (i=0; i < num_vertices; i++)
	{
		int v1_in = is_point_inside(v[i].x, v[i].y, v[i].p[POLY_Z], cp);
		int v2_in = is_point_inside(v[previ].x, v[previ].y, v[previ].p[POLY_Z], cp);

		if (v1_in && v2_in)			/* edge is completely inside the volume */
		{
			clipv[clip_verts] = v[i];
			++clip_verts;
		}
		else if (!v1_in && v2_in)	/* edge is entering the volume */
		{
			/* insert vertex at intersection point */
			t = line_plane_intersection(&v[i], &v[previ], cp);
			clipv[clip_verts].x = v[i].x + ((v[previ].x - v[i].x) * t);
			clipv[clip_verts].y = v[i].y + ((v[previ].y - v[i].y) * t);
			clipv[clip_verts].p[POLY_Z] = v[i].p[POLY_Z] + ((v[previ].p[POLY_Z] - v[i].p[POLY_Z]) * t);
			clipv[clip_verts].p[POLY_U] = v[i].p[POLY_U] + ((v[previ].p[POLY_U] - v[i].p[POLY_U]) * t);
			clipv[clip_verts].p[POLY_V] = v[i].p[POLY_V] + ((v[previ].p[POLY_V] - v[i].p[POLY_V]) * t);

			clipv[clip_verts].p[POLY_NX] = v[i].p[POLY_NX] + ((v[previ].p[POLY_NX] - v[i].p[POLY_NX]) * t);
			clipv[clip_verts].p[POLY_NY] = v[i].p[POLY_NY] + ((v[previ].p[POLY_NY] - v[i].p[POLY_NY]) * t);
			clipv[clip_verts].p[POLY_NZ] = v[i].p[POLY_NZ] + ((v[previ].p[POLY_NZ] - v[i].p[POLY_NZ]) * t);

			++clip_verts;
		}
		else if (v1_in && !v2_in)	/* edge is leaving the volume */
		{
			/* insert vertex at intersection point */
			t = line_plane_intersection(&v[i], &v[previ], cp);
			clipv[clip_verts].x = v[i].x + ((v[previ].x - v[i].x) * t);
			clipv[clip_verts].y = v[i].y + ((v[previ].y - v[i].y) * t);
			clipv[clip_verts].p[POLY_Z] = v[i].p[POLY_Z] + ((v[previ].p[POLY_Z] - v[i].p[POLY_Z]) * t);
			clipv[clip_verts].p[POLY_U] = v[i].p[POLY_U] + ((v[previ].p[POLY_U] - v[i].p[POLY_U]) * t);
			clipv[clip_verts].p[POLY_V] = v[i].p[POLY_V] + ((v[previ].p[POLY_V] - v[i].p[POLY_V]) * t);

			clipv[clip_verts].p[POLY_NX] = v[i].p[POLY_NX] + ((v[previ].p[POLY_NX] - v[i].p[POLY_NX]) * t);
			clipv[clip_verts].p[POLY_NY] = v[i].p[POLY_NY] + ((v[previ].p[POLY_NY] - v[i].p[POLY_NY]) * t);
			clipv[clip_verts].p[POLY_NZ] = v[i].p[POLY_NZ] + ((v[previ].p[POLY_NZ] - v[i].p[POLY_NZ]) * t);

			++clip_verts;

			/* insert the existing vertex */
			clipv[clip_verts] = v[i];
			++clip_verts;
		}

		previ = i;
	}
	memcpy(&vout[0], &clipv[0], sizeof(vout[0]) * clip_verts);
	return clip_verts;
}

void taitotz_renderer::draw_object(running_machine &machine, UINT32 address, float scale, UINT8 alpha)
{
	taitotz_state *state = machine.driver_data<taitotz_state>();
	const rectangle& visarea = machine.primary_screen->visible_area();

	UINT32 *src = &state->m_screen_ram[address];
	taitotz_renderer::vertex_t v[10];

	int end = 0;
	int index = 0;
	do
	{
		taitotz_polydata &extra = object_data_alloc();

		int num_verts;

		if (src[index] & 0x10000000)
			end = 1;

		if (src[index] & 0x01000000)
			num_verts = 4;
		else
			num_verts = 3;

		int texture = src[index] & 0x7ff;

		index += 4;

		for (int i=0; i < num_verts; i++)
		{
			// texture coordinates
			UINT8 tu = (src[index] >> 8) & 0xff;
			UINT8 tv = (src[index] >> 0) & 0xff;
			v[i].p[POLY_U] = (float)(tu);
			v[i].p[POLY_V] = (float)(tv);

			// coordinates
			INT16 x = src[index + 1] & 0xffff;
			INT16 y = src[index + 2] & 0xffff;
			INT16 z = src[index + 3] & 0xffff;
			float px = ((float)(x) / 256.0f) * scale;
			float py = ((float)(y) / 256.0f) * scale;
			float pz = ((float)(z) / 256.0f) * scale;

			// normals
			INT8 inx = (src[index + 1] >> 16) & 0xff;
			INT8 iny = (src[index + 2] >> 16) & 0xff;
			INT8 inz = (src[index + 3] >> 16) & 0xff;
			float nx = (float)(inx) / 128.0f;
			float ny = (float)(iny) / 128.0f;
			float nz = (float)(inz) / 128.0f;

			// transform
			v[i].x			= (px * m_matrix[0][0]) + (py * m_matrix[1][0]) + (pz * m_matrix[2][0]) + m_matrix[3][0];
			v[i].y			= (px * m_matrix[0][1]) + (py * m_matrix[1][1]) + (pz * m_matrix[2][1]) + m_matrix[3][1];
			v[i].p[POLY_Z]	= (px * m_matrix[0][2]) + (py * m_matrix[1][2]) + (pz * m_matrix[2][2]) + m_matrix[3][2];

			v[i].p[POLY_NX]	= (nx * m_matrix[0][0]) + (ny * m_matrix[1][0]) + (nz * m_matrix[2][0]);
			v[i].p[POLY_NY]	= (nx * m_matrix[0][1]) + (ny * m_matrix[1][1]) + (nz * m_matrix[2][1]);
			v[i].p[POLY_NZ] = (nx * m_matrix[0][2]) + (ny * m_matrix[1][2]) + (nz * m_matrix[2][2]);

			index += 4;
		}

		// clip against viewport frustum
		num_verts = clip_polygon(v, num_verts, m_clip_plane[0], v);
		num_verts = clip_polygon(v, num_verts, m_clip_plane[1], v);
		num_verts = clip_polygon(v, num_verts, m_clip_plane[2], v);
		num_verts = clip_polygon(v, num_verts, m_clip_plane[3], v);
		num_verts = clip_polygon(v, num_verts, m_clip_plane[4], v);

		// apply homogeneous Z-transform on coords and perspective correction on UV coords
		for (int i=0; i < num_verts; i++)
		{
			float ooz = 1.0f / v[i].p[POLY_Z];
			v[i].x = (((v[i].x * ooz) * m_vp_focus) * m_vp_mul) + m_vp_center_x;
			v[i].y = (((v[i].y * ooz) * m_vp_focus) * m_vp_mul) + m_vp_center_y;
			v[i].p[POLY_Z] = ooz;
			v[i].p[POLY_U] *= ooz;
			v[i].p[POLY_V] *= ooz;
		}

		extra.texture = texture;
		extra.alpha = alpha;
		extra.diffuse_r = m_diffuse_r;
		extra.diffuse_g = m_diffuse_g;
		extra.diffuse_b = m_diffuse_b;
		extra.ambient_r = m_ambient_r;
		extra.ambient_g = m_ambient_g;
		extra.ambient_b = m_ambient_b;
		extra.specular_r = m_specular_r;
		extra.specular_g = m_specular_g;
		extra.specular_b = m_specular_b;

		for (int i=2; i < num_verts; i++)
		{
			render_triangle(visarea, render_delegate(FUNC(taitotz_renderer::draw_scanline), this), 6, v[0], v[i-1], v[i]);
		}
	}
	while (!end);
}

void taitotz_renderer::setup_viewport(int x, int y, int width, int height, int center_x, int center_y)
{
	m_vp_center_x = center_x;
	m_vp_center_y = center_y;
	m_vp_focus = width * 2;
	m_vp_mul = 512.0f / m_vp_focus;
	m_vp_x = x;
	m_vp_y = y;

	// set up clip planes
	//float angleh =  atan2(512/2, 512.0f) - 0.0001;
	//float anglev =  atan2(384/2, 512.0f) - 0.0001;

	float angleh =  atan2(width, m_vp_focus) - 0.0001;
	float anglev =  atan2(height, m_vp_focus) - 0.0001;
	float sh = sin(angleh);
	float sv = sin(anglev);
	float ch = cos(angleh);
	float cv = cos(anglev);

	// left
	m_clip_plane[0].x = ch;
	m_clip_plane[0].y = 0.0f;
	m_clip_plane[0].z = sh;
	m_clip_plane[0].d = 0.0f;

	// right
	m_clip_plane[1].x = -ch;
	m_clip_plane[1].y = 0.0f;
	m_clip_plane[1].z = sh;
	m_clip_plane[1].d = 0.0f;

	// top
	m_clip_plane[2].x = 0.0f;
	m_clip_plane[2].y = cv;
	m_clip_plane[2].z = sv;
	m_clip_plane[2].d = 0.0f;

	// bottom
	m_clip_plane[3].x = 0.0f;
	m_clip_plane[3].y = -cv;
	m_clip_plane[3].z = sv;
	m_clip_plane[3].d = 0.0f;

	// Z-near
	m_clip_plane[4].x = 0.0f;
	m_clip_plane[4].y = 0.0f;
	m_clip_plane[4].z = 1.0f;
	m_clip_plane[4].d = 0.1f;
}

void taitotz_renderer::render_displaylist(running_machine &machine, const rectangle &cliprect)
{
	taitotz_state *state = machine.driver_data<taitotz_state>();

	float zvalue = 0;//ZBUFFER_MAX;
	m_zbuffer->fill(*(int*)&zvalue, cliprect);

	const rectangle& visarea = machine.primary_screen->visible_area();
	vertex_t v[8];

	UINT32 *src = (UINT32*)&state->m_work_ram[0];

	UINT32 w[32];
	int j;
	int end = 0;

	UINT32 index = state->m_displist_addr / 4;

	setup_viewport(0, 0, 256, 192, 256, 192);


	m_specular_r = 0xff;
	m_specular_g = 0xff;
	m_specular_b = 0xff;
	m_diffuse_r = 0;
	m_diffuse_g = 0;
	m_diffuse_b = 0;
	m_ambient_r = 0;
	m_ambient_g = 0;
	m_ambient_b = 0;


#if LOG_DISPLAY_LIST
	printf("--------------------------------------------\n");
	printf("Start of displist\n");
#endif

	do
	{
		UINT32 cmd = src[index^1];
		index++;

		if (cmd == 0xffff0011)
		{
			for (j=0; j < 16; j++)
			{
				w[j] = src[index^1];
				index++;
			}

			m_matrix[0][0]= *(float*)&w[4];
			m_matrix[1][0]= *(float*)&w[5];
			m_matrix[2][0]= *(float*)&w[6];
			m_matrix[3][0]= *(float*)&w[7];

			m_matrix[0][1]= *(float*)&w[8];
			m_matrix[1][1]= *(float*)&w[9];
			m_matrix[2][1]= *(float*)&w[10];
			m_matrix[3][1]= *(float*)&w[11];

			m_matrix[0][2]= *(float*)&w[12];
			m_matrix[1][2]= *(float*)&w[13];
			m_matrix[2][2]= *(float*)&w[14];
			m_matrix[3][2]= *(float*)&w[15];

			float scale = *(float*)&w[1];
			if (scale < 1.0f)
				scale *= 2;

			UINT32 alpha = w[2];

			draw_object(machine, w[0] & 0x1fffff, scale, alpha);

#if LOG_DISPLAY_LIST
			printf("0xffff0011:   %08X, %08X, %08X, %08X\n", w[0], w[1], w[2], w[3]);
#endif
		}
		else if (cmd == 0xffff0010)
		{
#if LOG_DISPLAY_LIST
			printf("0xffff0010\n");
#endif
		}
		else if (cmd == 0xffff0020)
		{
#if LOG_DISPLAY_LIST
			printf("0xffff0020\n");
#endif
		}
		else if (cmd == 0xffff0021)
		{
			taitotz_polydata &extra = object_data_alloc();

			int num_verts;
			w[0] = src[index^1];
			index++;
			w[1] = src[index^1];
			index++;
			w[2] = src[index^1];
			index++;
			w[3] = src[index^1];
			index++;

			num_verts = ((w[0] >> 8) & 0xf) + 1;

			for (j=0; j < num_verts; j++)
			{
				w[4] = src[index^1];
				index++;
				w[5] = src[index^1];
				index++;
				w[6] = src[index^1];
				index++;
				w[7] = src[index^1];
				index++;

				UINT16 x = (w[4] >> 16) & 0xffff;
				UINT16 y = (w[4] >>  0) & 0xffff;
				UINT16 tu = (w[6] >> 20) & 0xfff;
				UINT16 tv = (w[6] >>  4) & 0xfff;
//              UINT16 z = (w[5] & 0xffff);

				v[j].x = x;
				v[j].y = y;		// batlgear needs -50 modifier here (why?)
				v[j].p[POLY_U] = tu;
				v[j].p[POLY_V] = tv;
			}

			extra.texture = w[1] & 0x7ff;

			for (j=2; j < num_verts; j++)
			{
				render_triangle(visarea, render_delegate(FUNC(taitotz_renderer::draw_scanline_noz), this), 3, v[0], v[j-1], v[j]);
			}

#if LOG_DISPLAY_LIST
			printf("0xffff0021:   %08X, %08X, %08X, %08X\n", w[0], w[1], w[2], w[3]);
#endif
		}
		else if (cmd == 0xffff0022)
		{
			w[0] = src[index^1];
			index++;

#if LOG_DISPLAY_LIST
			printf("0xffff0022:    %08X\n", w[0]);
#endif
		}
		else if (cmd == 0xffff0030)
		{
			UINT32 address = src[index^1];
			index++;
			UINT32 num = src[index^1];
			index++;

#if LOG_DISPLAY_LIST
			printf("0xffff0030:   %08X = ", address);
#endif

			int addr = address;

			for (j=0; j < num; j++)
			{
				UINT32 word = src[index^1];
				index++;

				if (addr == 0x100)
				{
					m_reg_100 = word;
				}
				else if (addr == 0x101)
				{
					m_reg_101 = word;
				}
				else if (addr == 0x102)
				{
					m_reg_102 = word;
				}
				else if (addr == 0x10000102)
				{
					m_diffuse_r = ((word >> (16+10)) & 0x1f) << 3;
					m_diffuse_g = ((word >> (16+5)) & 0x1f) << 3;
					m_diffuse_b = ((word >> 16) & 0x1f) << 3;
					m_ambient_r = ((word >> 10) & 0x1f) << 3;
					m_ambient_g = ((word >> 5) & 0x1f) << 3;
					m_ambient_b = (word & 0x1f) << 3;
				}
				addr++;

#if LOG_DISPLAY_LIST
				printf("%08X, ", word);
#endif
			}
#if LOG_DISPLAY_LIST
			printf("\n");
#endif

			if (address == 0x100)
			{
				int vpw = (m_reg_101 >> 16) & 0xffff;
				int vph = (m_reg_101 >>  0) & 0xffff;
				int xw = (m_reg_100 >>  0) & 0xffff;
				int xh = (m_reg_100 >> 16) & 0xffff;

				setup_viewport(xw, xh, vpw-xw, vph-xh, vpw, vph);
			}
		}
		else if (cmd == 0xffff0080)
		{
		}
		else if (cmd == 0xffff00ff)
		{
			end = 1;
			w[0] = src[index^1];
			index++;
			w[1] = src[index^1];
			index++;
		}
		else
		{
#if LOG_DISPLAY_LIST
			printf("%08X: %08X (unknown)\n", index, cmd);
#endif
			end = 1;
		}
	}
	while (!end);

	wait("render_polygons");
}

UINT32 taitotz_state::screen_update_taitotz(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{

	bitmap.fill(0x000000, cliprect);
	m_renderer->set_fb(&bitmap);
	m_renderer->render_displaylist(machine(), cliprect);


	UINT16 *screen_src = (UINT16*)&m_screen_ram[m_scr_base];

	for (int j=0; j < 384; j++)
	{
		UINT32 *fb = &bitmap.pix32(j);
		for (int i=0; i < 512; i++)
		{
			UINT16 p = *screen_src++;
			if (p & 0x8000)		// draw 2D framebuffer if there's an opaque pixel
			{
				int r = ((p >> 10) & 0x1f) << (3+16);
				int g = ((p >> 5) & 0x1f) << (3+8);
				int b = (p & 0x1f) << 3;
				fb[i^1] = 0xff000000 | r | g | b;
			}
		}
	}

	return 0;
}

static void draw_tile(taitotz_state *state, UINT32 pos, UINT32 tile)
{
	int tileu = (tile & 0x1f) * 16;
	int tilev = ((tile >> 5)) * 16;

	int tilex = (pos & 0x1f) * 16;
	int tiley = ((pos >> 5) & 0x1f) * 16;

	UINT16 *src_tile = (UINT16*)&state->m_screen_ram[0x180000];
	UINT16 *dst = (UINT16*)&state->m_screen_ram[state->m_scr_base];

	int v = tilev;

	for (int j=tiley; j < (tiley+16); j++)
	{
		int u = tileu;
		for (int i=tilex; i < (tilex+16); i++)
		{
			UINT16 p = src_tile[((v*512) + u)];
			dst[(j*512) + i] = p;
			u++;
		}
		v++;
	}
}

/*
    Video chip memory map

    0x800000...0x9fffff         Screen RAM
        0x980000...7fff         Char RAM
        0x9c0000...fffff        Tile RAM?

    0x1000000...0x17fffff       Texture RAM

    0x1800000...0x187ffff       Frame RAM


    landhigh puts fullscreen images into 0x9c0000
    batlgr2 into 0x9e0000
*/

static UINT32 video_mem_r(taitotz_state *state, UINT32 address)
{
	if (address >= 0x800000 && address < 0x1000000)
	{
		return state->m_screen_ram[address - 0x800000];
	}
	else if (address >= 0x1000000 && address < 0x1800000)
	{
		return state->m_texture_ram[address - 0x1000000];
	}
	else if (address >= 0x1800000 && address < 0x1880000)
	{
		return state->m_frame_ram[address - 0x1800000];
	}
	else
	{
		printf("video_mem_r: %08X\n", address);
		return 0;
	}
}

static void video_mem_w(taitotz_state *state, UINT32 address, UINT32 data)
{
	if (address >= 0x800000 && address < 0x1000000)
	{
		state->m_screen_ram[address - 0x800000] = data;
	}
	else if (address >= 0x1000000 && address < 0x1800000)
	{
		state->m_texture_ram[address - 0x1000000] = data;
	}
	else if (address >= 0x1800000 && address < 0x1880000)
	{
		state->m_frame_ram[address - 0x1800000] = data;
	}
	else
	{
		printf("video_mem_w: %08X, %08X\n", address, data);
	}
}

static UINT32 video_reg_r(taitotz_state *state, UINT32 reg)
{
	switch ((reg >> 28) & 0xf)
	{
		case 0x1:
		{
			if (reg == 0x10000105)		// Gets spammed a lot. Probably a status register.
			{
				state->m_reg105 ^= 0xffffffff;
				return state->m_reg105;
			}

			logerror("video_reg_r: reg: %08X\n", reg);
			return 0xffffffff;
		}
		case 0x2:
		{
			int subreg = reg & 0xfffffff;

			if (reg != 0x20000008)
				logerror("video_reg_r: reg: %08X\n", reg);

			if (subreg < 0x10)
			{
				return state->m_video_unk_reg[subreg];
			}
			break;
		}
		case 0xb:
		{
			return video_mem_r(state, reg & 0xfffffff);
		}
		default:
		{
			logerror("video_reg_r: reg: %08X\n", reg);
			break;
		}
	}

	return 0;
}

/*
video_reg_w: r: A0000000 d: 01FF029F
video_reg_w: r: A0000000 d: 02200278
video_reg_w: r: A0000000 d: 019001C2
video_reg_w: r: A0000000 d: 019F01B3
video_reg_w: r: A0000000 d: 00000000
video_reg_w: r: A0000000 d: 00001C00
video_reg_w: r: A0000000 d: 00000000
video_reg_w: r: A0000000 d: 00070000
video_reg_w: r: A0000000 d: 00000000
video_reg_w: r: 10000104 d: 00000000
video_reg_w: r: 10000105 d: 00000001

video_reg_w: r: 20000007 d: 00070000
video_reg_w: r: 20000000 d: 01F0029B
video_reg_w: r: 20000001 d: 02140261
video_reg_w: r: 20000002 d: 018101BE
video_reg_w: r: 20000003 d: 019501AA
video_reg_w: r: 20000004 d: 00000000
*/

static void video_reg_w(taitotz_state *state, UINT32 reg, UINT32 data)
{
	switch ((reg >> 28) & 0xf)
	{
	case 0x1:		// Register write?
		{
			if (reg == 0x10000105)
			{
				// This register gets spammed a lot. VB IRQ ack or buffer swap?
			}
			else
			{
				logerror("video_reg_w: reg: %08X data: %08X\n", reg, data);
			}
			break;
		}
	case 0x2:		// ???
		{
			int subreg = reg & 0xfffffff;
			if (subreg < 0x10)
			{
				state->m_video_unk_reg[subreg] = data;
			}
			logerror("video_reg_w: reg: %08X data: %08X\n", reg, data);
			break;
		}
	case 0x3:		// Draw 16x16 tile
		{
			UINT32 pos = (data >> 12) & 0xfff;
			UINT32 tile = data & 0xfff;
			draw_tile(state, pos, tile);
			break;
		}
	case 0xb:		// RAM write?
		{
			video_mem_w(state, state->m_video_ram_ptr, data);
			state->m_video_ram_ptr++;
			break;
		}
	default:
		{
			logerror("video_reg_w: reg: %08X data: %08X\n", reg, data);
			break;
		}
	}
}

READ64_MEMBER(taitotz_state::video_chip_r)
{
	UINT64 r = 0;
	UINT32 reg = offset * 8;

	if (ACCESSING_BITS_0_31)
	{
		reg += 4;

		switch (reg)
		{
			case 0x14:
				{
					r |= 0xffffffff;
					break;
				}

			default:
				printf("video_chip_r: %04X\n", reg);
				break;
		}
	}
	if (ACCESSING_BITS_32_63)
	{
		switch (reg)
		{
			case 0x0:
				{
					r |= (UINT64)(video_reg_r(this, m_video_reg)) << 32;
					break;
				}

			case 0x10:
				{
					r |= (UINT64)(0xff) << 32;		// busy flags? landhigh expects this
					break;
				}

			default:
				{
					printf("video_chip_r: %04X\n", reg);
					break;
				}
		}
	}

	return r;
}

WRITE64_MEMBER(taitotz_state::video_chip_w)
{
	UINT32 reg = offset * 8;
	UINT32 regdata;

	if (ACCESSING_BITS_0_31)
	{
		reg += 4;
		regdata = (UINT32)(data);
		switch (reg)
		{
			default:
			{
				logerror("video_chip_w: port 0x%02X: %08X\n", reg, regdata);
				break;
			}
		}
	}
	if (ACCESSING_BITS_32_63)
	{
		regdata = (UINT32)(data >> 32);
		switch (reg)
		{
			case 0:
			{
				video_reg_w(this, m_video_reg, regdata);
				break;
			}
			case 0x8:
			{
				m_video_reg = regdata;
				m_video_fifo_ptr = 0;

				switch ((m_video_reg >> 28) & 0xf)
				{
					case 0xb:
					{
						m_video_ram_ptr = m_video_reg & 0xfffffff;
						//logerror("video_chip_ram sel %08X at %08X\n", m_video_reg & 0x0fffffff, space.device().safe_pc());
						break;
					}
					case 0x0:
					{
						break;
					}
					case 0x1:
					{
						break;
					}
					case 0x2:
					{
						break;
					}
					case 0x3:
					{
						// video_chip_w: port 0x08: 30000001        gets spammed a lot
						break;
					}
					default:
					{
						logerror("video_chip_w: port 0x%02X: %08X\n", reg, regdata);
						break;
					}
				}
				break;
			}
			default:
			{
				logerror("video_chip_w: port 0x%02X: %08X\n", reg, regdata);
				break;
			}
		}
	}
}

READ64_MEMBER(taitotz_state::video_fifo_r)
{
	UINT64 r = 0;
	if (ACCESSING_BITS_32_63)
	{
		r |= (UINT64)(video_mem_r(this, m_video_ram_ptr)) << 32;
		m_video_ram_ptr++;
	}
	if (ACCESSING_BITS_0_31)
	{
		r |= (UINT64)(video_mem_r(this, m_video_ram_ptr));
		m_video_ram_ptr++;
	}

	return r;
}

WRITE64_MEMBER(taitotz_state::video_fifo_w)
{
	int command = (m_video_reg >> 28) & 0xf;
	if (command == 0xb)
	{
		// FIFO mem access

		if (ACCESSING_BITS_32_63)
		{
			if (m_video_fifo_ptr >= 8)
			{
				video_mem_w(this, m_video_ram_ptr, (UINT32)(data >> 32));
				m_video_ram_ptr++;
			}
			m_video_fifo_ptr++;
		}
		if (ACCESSING_BITS_0_31)
		{
			if (m_video_fifo_ptr >= 8)
			{
				video_mem_w(this, m_video_ram_ptr, (UINT32)(data));
				m_video_ram_ptr++;
			}
			m_video_fifo_ptr++;
		}
	}
	else if (command == 0x1)
	{
		// FIFO command/packet write

		if (ACCESSING_BITS_32_63)
		{
			if (m_video_fifo_ptr >= 8)
			{
				logerror("FIFO packet w: %08X at %08X\n", (UINT32)(data >> 32), space.device().safe_pc());
			}
			m_video_fifo_ptr++;
		}
		if (ACCESSING_BITS_0_31)
		{
			if (m_video_fifo_ptr >= 8)
			{
				logerror("FIFO packet w: %08X at %08X\n", (UINT32)(data), space.device().safe_pc());
			}
			m_video_fifo_ptr++;
		}
	}
	else
	{
		if (ACCESSING_BITS_32_63)
		{
			if (m_video_fifo_ptr >= 8)
			{
				printf("FIFO write with cmd %02X: %08X\n", command, (UINT32)(data >> 32));
			}
			m_video_fifo_ptr++;
		}
		if (ACCESSING_BITS_0_31)
		{
			if (m_video_fifo_ptr >= 8)
			{
				printf("FIFO write with cmd %02X: %08X\n", command, (UINT32)(data));
			}
			m_video_fifo_ptr++;
		}
	}

	//COMBINE_DATA(m_video_fifo_mem + offset);
}

READ64_MEMBER(taitotz_state::ieee1394_r)
{
	if (offset == 4)
	{
		return U64(0xffffffffffffffff);
	}

	//logerror("ieee1394_r: %08X, %08X%08X\n", offset, (UINT32)(mem_mask >> 32), (UINT32)(mem_mask));
	return 0;
}

WRITE64_MEMBER(taitotz_state::ieee1394_w)
{
	//logerror("ieee1394_w: %08X, %08X%08X, %08X%08X\n", offset, (UINT32)(data >> 32), (UINT32)(data), (UINT32)(mem_mask >> 32), (UINT32)(mem_mask));
	if (ACCESSING_BITS_32_63)
	{

	}
	if (ACCESSING_BITS_0_31)
	{

	}
}

READ64_MEMBER(taitotz_state::ppc_common_r)
{
	UINT64 res = 0;

	if (ACCESSING_BITS_0_15)
	{
		res |= m_io_share_ram[(offset * 2) + 1];
	}
	if (ACCESSING_BITS_32_47)
	{
		res |= (UINT64)(m_io_share_ram[(offset * 2) + 0]) << 32;
	}

	return res;
}

WRITE64_MEMBER(taitotz_state::ppc_common_w)
{
	if (ACCESSING_BITS_0_15)
	{
		m_io_share_ram[(offset * 2) + 1] = (UINT16)(data);
	}
	if (ACCESSING_BITS_32_47)
	{
		m_io_share_ram[(offset * 2) + 0] = (UINT16)(data >> 32);
	}

	if (offset == 0x7ff)
	{
#if LOG_PPC_TO_TLCS_COMMANDS
		if (m_io_share_ram[0xfff] != 0x0000 &&
			m_io_share_ram[0xfff] != 0x1010 &&
			m_io_share_ram[0xfff] != 0x1020 &&
			m_io_share_ram[0xfff] != 0x6000 &&
			m_io_share_ram[0xfff] != 0x6010 &&
			m_io_share_ram[0xfff] != 0x7004 &&
			m_io_share_ram[0xfff] != 0x4001 &&
			m_io_share_ram[0xfff] != 0x4002 &&
			m_io_share_ram[0xfff] != 0x4003)
		{
			printf("PPC -> TLCS cmd %04X\n", m_io_share_ram[0xfff]);
		}

		if (m_io_share_ram[0xfff] == 0x4000)
		{
			printf("   %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X\n",
					m_io_share_ram[0x1c34/2],
					m_io_share_ram[0x1c36/2],
					m_io_share_ram[0x1c38/2],
					m_io_share_ram[0x1c3a/2],
					m_io_share_ram[0x1c2c/2],
					m_io_share_ram[0x1c2e/2],
					m_io_share_ram[0x1c30/2],
					m_io_share_ram[0x1c32/2],
					m_io_share_ram[0x1c24/2],
					m_io_share_ram[0x1c26/2]
					);
			printf("   %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X\n",
					m_io_share_ram[0x1c28/2],
					m_io_share_ram[0x1c2a/2],
					m_io_share_ram[0x1c1c/2],
					m_io_share_ram[0x1c1e/2],
					m_io_share_ram[0x1c20/2],
					m_io_share_ram[0x1c22/2],
					m_io_share_ram[0x1c14/2],
					m_io_share_ram[0x1c16/2],
					m_io_share_ram[0x1c18/2],
					m_io_share_ram[0x1c1a/2]
					);
		}

		/*
        if (m_io_share_ram[0xfff] == 0x1010)
        {
            printf("   %04X %04X %04X %04X\n", m_io_share_ram[0x1a02/2], m_io_share_ram[0x1a04/2], m_io_share_ram[0x1a06/2], m_io_share_ram[0x1a08/2]);
        }
        */

#endif


		// hacky way to handle some commands for now
		if (m_io_share_ram[0xfff] == 0x4001)
		{
			m_io_share_ram[0xfff] = 0x0000;
			m_io_share_ram[0xe00] = 0xffff;
			machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
		}
		else if (m_io_share_ram[0xfff] == 0x4004 || m_io_share_ram[0xfff] == 0x4000)
		{
			m_io_share_ram[0xfff] = 0x0000;
			machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
		}
		else if (m_io_share_ram[0xfff] == 0x7004)
		{
			// this command seems to turn off interrupts on TLCS...
			m_io_share_ram[0xfff] = 0x0000;
			machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
		}
		else
		{
			// normally just raise INT0 on TLCS and let it handle the command
			machine().device("iocpu")->execute().set_input_line(TLCS900_INT0, ASSERT_LINE);
			machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);

			// The PPC always goes to busy loop waiting for TLCS here, so we can free up the timeslice.
			// Only do it for HDD access and backup RAM for now...
			if (m_io_share_ram[0xfff] == 0x1010 || m_io_share_ram[0xfff] == 0x1020 ||
				m_io_share_ram[0xfff] == 0x6000 || m_io_share_ram[0xfff] == 0x6010)
			{
				//machine().device("maincpu")->execute().spin_until_trigger(PPC_TLCS_COMM_TRIGGER);
				machine().device("maincpu")->execute().spin_until_interrupt();
			}

			// pwrshovl sometimes writes commands during command handling... make sure that doesn't happen
			if (m_io_share_ram[0xfff] == 0x0000)
			{
				machine().device("maincpu")->execute().spin_until_time(attotime::from_usec(50));
			}

			machine().scheduler().trigger(TLCS_PPC_COMM_TRIGGER);
		}
	}
}

// BAT Config:
// IBAT0 U: 0xf0001fff   L: 0xf0000023   (0xf0000000...0xffffffff)
// IBAT1 U: 0xe0001fff   L: 0xe0000023   (0xe0000000...0xefffffff)
// IBAT2 U: 0x40001fff   L: 0x40000003   (0x40000000...0x4fffffff)
// IBAT3 U: 0xa0001fff   L: 0xa0000023   (0xa0000000...0xafffffff)
// DBAT0 U: 0x00001fff   L: 0x00000022   (0x00000000...0x0fffffff)
// DBAT1 U: 0x10001fff   L: 0x10000002   (0x10000000...0x1fffffff)
// DBAT2 U: 0x40001fff   L: 0x40000002   (0x40000000...0x4fffffff)
// DBAT3 U: 0xa0001fff   L: 0xa0000022   (0xa0000000...0xafffffff)

// 0x10000000...0x1000001f: texture FIFO?
// 0x40000000...0x400fffff: BIOS Work RAM
// 0x40100000...0x40ffffff: User Work RAM

static ADDRESS_MAP_START( ppc603e_mem, AS_PROGRAM, 64, taitotz_state)
	AM_RANGE(0x00000000, 0x0000001f) AM_READWRITE(video_chip_r, video_chip_w)
	AM_RANGE(0x10000000, 0x1000001f) AM_READWRITE(video_fifo_r, video_fifo_w)
	AM_RANGE(0x40000000, 0x40ffffff) AM_RAM AM_SHARE("work_ram")				// Work RAM
	AM_RANGE(0xa4000000, 0xa40000ff) AM_READWRITE(ieee1394_r, ieee1394_w)		// IEEE1394 network
	AM_RANGE(0xa8000000, 0xa8003fff) AM_READWRITE(ppc_common_r, ppc_common_w)   // Common RAM (with TLCS-900)
	AM_RANGE(0xac000000, 0xac0fffff) AM_ROM AM_REGION("user1", 0)				// Apparently this should be flash ROM read/write access
	AM_RANGE(0xfff00000, 0xffffffff) AM_ROM AM_REGION("user1", 0)
ADDRESS_MAP_END



READ8_MEMBER(taitotz_state::tlcs_common_r)
{
	if (offset & 1)
	{
		return (UINT8)(m_io_share_ram[offset / 2] >> 8);
	}
	else
	{
		return (UINT8)(m_io_share_ram[offset / 2]);
	}
}

WRITE8_MEMBER(taitotz_state::tlcs_common_w)
{
	if (offset & 1)
	{
		m_io_share_ram[offset / 2] &= 0x00ff;
		m_io_share_ram[offset / 2] |= (UINT16)(data) << 8;
	}
	else
	{
		m_io_share_ram[offset / 2] &= 0xff00;
		m_io_share_ram[offset / 2] |= data;
	}

	if (offset == 0x1ffd)
	{
#if LOG_TLCS_TO_PPC_COMMANDS
		if (m_io_share_ram[0xffe] != 0xd000 &&
			m_io_share_ram[0xffe] != 0x1011 &&
			m_io_share_ram[0xffe] != 0x1012 &&
			m_io_share_ram[0xffe] != 0x1022)
		{
			printf("TLCS -> PPC cmd %04X\n", m_io_share_ram[0xffe]);
			//printf("0x40080104 = %08X\n", (UINT32)(m_work_ram[0x80104/8]));
		}
#endif

		machine().device("maincpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
		machine().device("iocpu")->execute().set_input_line(TLCS900_INT0, CLEAR_LINE);

		machine().device("iocpu")->execute().set_input_line(TLCS900_INT3, CLEAR_LINE);

		// The PPC is now free to continue running
		//machine().scheduler().trigger(PPC_TLCS_COMM_TRIGGER);
		//machine().device("iocpu")->execute().yield();
	}

	if (offset == 0x1ffe)
	{
		if (m_io_share_ram[0xfff] == 0 && m_io_share_ram[0xffe] == 0x1012)
		{
			//machine().device("iocpu")->execute().spin_until_trigger(TLCS_PPC_COMM_TRIGGER);
			machine().device("iocpu")->execute().yield();
			machine().scheduler().trigger(PPC_TLCS_COMM_TRIGGER);
		}
	}
}

// RTC could be Epson RTC-64613, same as taitopjc.c
READ8_MEMBER(taitotz_state::tlcs_rtc_r)
{
	switch (offset)
	{
		// NOTE: bcd numbers
		case 0x00:		return m_rtcdata[0];		// milliseconds?
		case 0x01:		return m_rtcdata[1];		// seconds
		case 0x02:		return m_rtcdata[2];		// minutes
		case 0x03:		return m_rtcdata[3];		// hours
		case 0x04:		return m_rtcdata[4];		// day of the week
		case 0x05:		return m_rtcdata[5];		// day
		case 0x06:		return m_rtcdata[6];		// month
		case 0x07:		return m_rtcdata[7];		// year

		case 0x0e:		return 0;

		default:
			printf("tlcs_rtc_r: %02X\n", offset);
			break;
	}

	return 0;
}

WRITE8_MEMBER(taitotz_state::tlcs_rtc_w)
{
	switch (offset)
	{
		case 0x00:		m_rtcdata[0] = data; break;
		case 0x01:		m_rtcdata[1] = data; break;
		case 0x02:		m_rtcdata[2] = data; break;
		case 0x03:		m_rtcdata[3] = data; break;
		case 0x04:		m_rtcdata[4] = data; break;
		case 0x05:		m_rtcdata[5] = data; break;
		case 0x06:		m_rtcdata[6] = data; break;
		case 0x07:		m_rtcdata[7] = data; break;
		case 0x0e:
			break;

		default:
			//printf("tlcs_rtc_w: %02X, %02X\n", offset, data);
			break;
	}
}

READ8_MEMBER(taitotz_state::tlcs_ide0_r)
{
	device_t *device = machine().device("ide");
	static UINT16 ide_reg_latch;
	int reg = offset >> 1;

	if (reg == 0)
	{
		if ((offset & 1) == 0)
		{
			ide_reg_latch = ide_bus_r(device, 0, reg);
			return (ide_reg_latch & 0xff);
		}
		else
		{
			return (ide_reg_latch >> 8) & 0xff;
		}
	}
	else
	{
		if (offset & 1)
			fatalerror("tlcs_ide0_r: %02X, odd offset\n", offset);

		UINT8 d = ide_bus_r(device, 0, reg);
		if (reg == 7)
			d &= ~0x2;		// Type Zero doesn't like the index bit. It's defined as vendor-specific, so it probably shouldn't be up...
							// The status check explicitly checks for 0x50 (drive ready, seek complete).
		return d;
	}
}

WRITE8_MEMBER(taitotz_state::tlcs_ide0_w)
{
	device_t *device = machine().device("ide");
	static UINT16 ide_reg_latch;
	int reg = offset >> 1;

	if (reg == 7 || reg == 0)
	{
		if ((offset & 1) == 0)
		{
			ide_reg_latch &= 0xff00;
			ide_reg_latch |= data;
		}
		else
		{
			ide_reg_latch &= 0x00ff;
			ide_reg_latch |= (UINT16)(data) << 8;
			ide_bus_w(device, 0, reg, ide_reg_latch);
		}
	}
	else
	{
		if (offset & 1)
			fatalerror("tlcs_ide0_w: %02X, %02X, odd offset\n", offset, data);
		ide_bus_w(device, 0, reg, data);
	}
}

READ8_MEMBER(taitotz_state::tlcs_ide1_r)
{
	device_t *device = machine().device("ide");
	//static UINT16 ide_reg_latch;
	int reg = offset >> 1;

	if (reg != 6)
		fatalerror("tlcs_ide1_r: %02X\n", offset);

	if ((offset & 1) == 0)
	{
		UINT8 d = ide_bus_r(device, 1, reg);
		d &= ~0x2;		// Type Zero doesn't like the index bit. It's defined as vendor-specific, so it probably shouldn't be up...
						// The status check explicitly checks for 0x50 (drive ready, seek complete).
		return d;
	}
	else
	{
		//fatalerror("tlcs_ide1_r: %02X, odd offset\n", offset);
		UINT8 d = ide_bus_r(device, 1, reg);
		d &= ~0x2;
		return d;
	}
}

WRITE8_MEMBER(taitotz_state::tlcs_ide1_w)
{
	device_t *device = machine().device("ide");
	static UINT16 ide_reg_latch;
	int reg = offset >> 1;

	if (reg != 6)
		fatalerror("tlcs_ide1_w: %02X, %02X\n", offset, data);

	if ((offset & 1) == 0)
	{
		ide_reg_latch &= 0xff00;
		ide_reg_latch |= data;
	}
	else
	{
		ide_reg_latch &= 0x00ff;
		ide_reg_latch |= (UINT16)(data) << 16;
		ide_bus_w(device, 1, reg, ide_reg_latch);
	}
}

READ8_MEMBER(taitotz_state::tlcs900_port_read)
{
	switch (offset)
	{
		case 0x7: return 0;		// ???
		case 0x9: return ioport("INPUTS1")->read();
		case 0xa: return 0;		// ???
		case 0xb: return ioport("INPUTS2")->read();
		case 0xd: return ioport("INPUTS3")->read();
		case 0xe: return ioport("INPUTS4")->read();

		default:
			//printf("tlcs900_port_read %02X\n", offset);
			break;
	}

	return 0;
}

WRITE8_MEMBER(taitotz_state::tlcs900_port_write)
{
	//taitotz_state *state = device->machine().driver_data<taitotz_state>();

	switch (offset)
	{
		case 0x7:
			//if (data != 0xff && data != 0xfa && data != 0xfe)
			//  printf("tlcs900_port_write %02X, %02X\n", offset, data);
			break;

		case 0x8:
			if (data & 1)
			{
				//state->m_mbox_ram[0x17] = 0x55;
			}
			break;

		case 0x9:
			//if (data != 0x00)
			//  printf("tlcs900_port_write %02X, %02X\n", offset, data);
			break;

		case 0xb:
			break;

		default:
			printf("tlcs900_port_write %02X, %02X\n", offset, data);
			break;
	}
}

// TLCS900 interrupt vectors
// 0xfc0150:    Reset
// 0xfc0120:    SWI1-7          -
// 0xfc0120:    NMI             -
// 0xfc0120:    INTWD           -
// 0xfc0122:    INT0            PPC communication
// 0xfc0137:    INT1            IEEE1394?
// 0xfc013c:    INT2            IDE
// 0xfc0141:    INT3            VBlank? Drives a counter on PPC side
// 0xfc0146:    INT4            -
// 0xfc0147:    INT5            -
// 0xfc0148:    INT6            -
// 0xfc0149:    INT7            -
// 0xfc014a:    INT8            Sound chip interrupt?
// 0xfc0120:    INTAD           -
// 0xfc0120:    INTTR8-A        -
// 0xfc0120:    INTT0           -
// 0xfc0467:    INTT1           A/D Conversion
// 0xfc0120:    INTT2-7         -
// 0xfc0120:    INTTC0-3        -
// 0xfc0d1d:    INTRX0          Serial 0 receive
// 0xfc0ca5:    INTTX0          Serial 0 transmit
// 0xfc0d55:    INTRX1          Serial 1 receive
// 0xfc0ce1:    INTTX1          Serial 1 transmit

static ADDRESS_MAP_START( tlcs900h_mem, AS_PROGRAM, 8, taitotz_state)
	AM_RANGE(0x010000, 0x02ffff) AM_RAM														// Work RAM
	AM_RANGE(0x040000, 0x041fff) AM_RAM	AM_SHARE("nvram")									// Backup RAM
	AM_RANGE(0x044000, 0x04400f) AM_READWRITE(tlcs_rtc_r, tlcs_rtc_w)
	AM_RANGE(0x060000, 0x061fff) AM_READWRITE(tlcs_common_r, tlcs_common_w)
	AM_RANGE(0x064000, 0x064fff) AM_RAM	AM_SHARE("mbox_ram")								// MBox
	AM_RANGE(0x068000, 0x06800f) AM_READWRITE(tlcs_ide0_r, tlcs_ide0_w)
	AM_RANGE(0x06c000, 0x06c00f) AM_READWRITE(tlcs_ide1_r, tlcs_ide1_w)
	AM_RANGE(0xfc0000, 0xffffff) AM_ROM AM_REGION("io_cpu", 0)
ADDRESS_MAP_END

static ADDRESS_MAP_START( landhigh_tlcs900h_mem, AS_PROGRAM, 8, taitotz_state)
	AM_RANGE(0x200000, 0x21ffff) AM_RAM														// Work RAM
	AM_RANGE(0x400000, 0x401fff) AM_RAM	AM_SHARE("nvram")									// Backup RAM
	AM_RANGE(0x404000, 0x40400f) AM_READWRITE(tlcs_rtc_r, tlcs_rtc_w)
	AM_RANGE(0x900000, 0x901fff) AM_READWRITE(tlcs_common_r, tlcs_common_w)
	AM_RANGE(0x910000, 0x910fff) AM_RAM	AM_SHARE("mbox_ram")								// MBox
	AM_RANGE(0x908000, 0x90800f) AM_READWRITE(tlcs_ide0_r, tlcs_ide0_w)
	AM_RANGE(0x918000, 0x91800f) AM_READWRITE(tlcs_ide1_r, tlcs_ide1_w)
	AM_RANGE(0xfc0000, 0xffffff) AM_ROM AM_REGION("io_cpu", 0)
ADDRESS_MAP_END



WRITE8_MEMBER(taitotz_state::tlcs900_to1)
{
}

WRITE8_MEMBER(taitotz_state::tlcs900_to3)
{
}


static INPUT_PORTS_START( taitotz )
	PORT_START("INPUTS1")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_SERVICE_NO_TOGGLE( 0x00000002, IP_ACTIVE_LOW) /* Test Button */
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Service") PORT_CODE(KEYCODE_7)
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS2")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_COIN1 )									// Coin A
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_COIN2 )									// Coin B
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS3")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(1)		// Trig1 / U
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)	// Trig2 / D
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)	// Trig3 / R
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)	// Trig4 / L
	PORT_BIT( 0x000000e0, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS4")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON5 )									// View 3
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON6 )									// View 4
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON7 )									// View 5
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON8 )									// View 6
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON3 )									// View 1
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON4 )									// View 2
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON1 )									// Select 1
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_BUTTON2 )									// Select 2
INPUT_PORTS_END

static INPUT_PORTS_START( landhigh )
	PORT_START("INPUTS1")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_SERVICE_NO_TOGGLE( 0x00000002, IP_ACTIVE_LOW) /* Test Button */
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Service") PORT_CODE(KEYCODE_7)
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS2")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_COIN1 )									// Coin
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS3")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON3 )									// Speak
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON4 )									// Help
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON1 )									// Flap Up
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON2 )									// Flap Down
	PORT_BIT( 0x000000e0, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS4")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON5 )									// ID Button
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON6 )									// Lever Sync
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_START )									// Start
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("ANALOG1")
	PORT_BIT( 0x3ff, 0x000, IPT_AD_STICK_X ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG2")
	PORT_BIT( 0x3ff, 0x000, IPT_AD_STICK_Y ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG3")
	PORT_BIT( 0x3ff, 0x000, IPT_PEDAL ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG4")
	PORT_BIT( 0x3ff, 0x000, IPT_PEDAL2 ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG5")
	PORT_BIT( 0x3ff, 0x000, IPT_PEDAL3 ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)
INPUT_PORTS_END

static INPUT_PORTS_START( batlgr2 )
	PORT_START("INPUTS1")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_SERVICE_NO_TOGGLE( 0x00000002, IP_ACTIVE_LOW) /* Test Button */
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Service") PORT_CODE(KEYCODE_7)
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS2")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_COIN1 )									// Coin
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS3")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON2 )									// Shift Down
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON1 )									// Shift Up
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON3 )									// View
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x000000e0, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS4")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_START )									// Start
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("ANALOG1")		// Steering
	PORT_BIT( 0x3ff, 0x200, IPT_PADDLE ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG2")		// Gas Pedal
	PORT_BIT( 0x3ff, 0x000, IPT_PEDAL) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG3")		// Brake Pedal
	PORT_BIT( 0x3ff, 0x000, IPT_PEDAL2 ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)
INPUT_PORTS_END

static INPUT_PORTS_START( pwrshovl )
	PORT_START("INPUTS1")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_SERVICE_NO_TOGGLE( 0x00000002, IP_ACTIVE_LOW) /* Test Button */
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("Service") PORT_CODE(KEYCODE_7)
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS2")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_COIN1 )									// Coin A
	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS3")
	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_PLAYER(1)					// P1-Foot-Sw: Left-Down
	PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1)					// P1-Foot-Sw: Left-Up
	PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(1)					// P1-Foot-Sw: Right-Down
	PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1)					// P1-Foot-Sw: Right-Up
	PORT_BIT( 0x000000e0, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("INPUTS4")
	PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2)					// P2-Foot-Sw: Left-Down
	PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2)					// P2-Foot-Sw: Left-Up
	PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_PLAYER(2)					// P2-Foot-Sw: Right-Down
	PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(2)					// P2-Foot-Sw: Right-Up
	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)					// P1 View
	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)					// P2 View
	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_START1 )									// P1 Start
	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_START2 )									// P2 Start

	PORT_START("ANALOG1")		// P1-Lever Left-X
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_X ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG2")		// P1-Lever Left-Y
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_Y ) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG3")		// P1-Lever Right-X
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_X ) PORT_PLAYER(2) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG4")		// P1_Lever Right-Y
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_Y ) PORT_PLAYER(2) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG5")		// P2-Lever Left-X
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_X ) PORT_PLAYER(3) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG6")		// P2-Lever Left-Y
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_Y ) PORT_PLAYER(3) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG7")		// P2-Lever Right-X
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_X ) PORT_PLAYER(4) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)

	PORT_START("ANALOG8")		// P2_Lever Right-Y
	PORT_BIT( 0x3ff, 0x200, IPT_AD_STICK_Y ) PORT_PLAYER(4) PORT_MINMAX(0x000,0x3ff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5)
INPUT_PORTS_END


static void set_ide_drive_serial_number(device_t *device, int drive, const char *serial)
{
	ide_controller_device *ide = (ide_controller_device *) device;
	UINT8 *ide_features = ide->ide_get_features(drive);

	for (int i=0; i < 20; i++)
	{
		ide_features[10*2+(i^1)] = serial[i];
	}
}


void taitotz_state::machine_reset()
{
	machine().device("ide")->reset();

	if (m_hdd_serial_number != NULL)
	{
		set_ide_drive_serial_number(machine().device("ide"), 0, m_hdd_serial_number);
	}
}

void taitotz_state::machine_start()
{

	/* set conservative DRC options */
	ppcdrc_set_options(machine().device("maincpu"), PPCDRC_COMPATIBLE_OPTIONS);

	/* configure fast RAM regions for DRC */
	ppcdrc_add_fastram(machine().device("maincpu"), 0x40000000, 0x40ffffff, FALSE, m_work_ram);
}


INTERRUPT_GEN_MEMBER(taitotz_state::taitotz_vbi)
{
	machine().device("iocpu")->execute().set_input_line(TLCS900_INT3, ASSERT_LINE);
}

WRITE_LINE_MEMBER(taitotz_state::ide_interrupt)
{
	machine().device("iocpu")->execute().set_input_line(TLCS900_INT2, state);
}

static const powerpc_config ppc603e_config =
{
	XTAL_66_6667MHz,		/* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */
	NULL,
	NULL
};

static const tlcs900_interface taitotz_tlcs900_interface =
{
	DEVCB_DRIVER_MEMBER(taitotz_state, tlcs900_to1),
	DEVCB_DRIVER_MEMBER(taitotz_state, tlcs900_to3),
	DEVCB_DRIVER_MEMBER(taitotz_state, tlcs900_port_read),
	DEVCB_DRIVER_MEMBER(taitotz_state, tlcs900_port_write),
};

static MACHINE_CONFIG_START( taitotz, taitotz_state )
	/* IBM EMPPC603eBG-100 */
	MCFG_CPU_ADD("maincpu", PPC603E, 100000000)
	MCFG_CPU_CONFIG(ppc603e_config)
	MCFG_CPU_PROGRAM_MAP(ppc603e_mem)

	/* TMP95C063F I/O CPU */
	MCFG_CPU_ADD("iocpu", TMP95C063, 25000000)
	MCFG_CPU_CONFIG(taitotz_tlcs900_interface)
	MCFG_CPU_PROGRAM_MAP(tlcs900h_mem)
	MCFG_CPU_VBLANK_INT_DRIVER("screen", taitotz_state,  taitotz_vbi)

	/* MN1020819DA sound CPU */

	MCFG_QUANTUM_TIME(attotime::from_hz(120))

	MCFG_IDE_CONTROLLER_ADD("ide", ide_devices, "hdd", NULL, true)
	MCFG_IDE_CONTROLLER_IRQ_HANDLER(DEVWRITELINE(DEVICE_SELF, taitotz_state, ide_interrupt))

	MCFG_NVRAM_ADD_0FILL("nvram")

	MCFG_SCREEN_ADD("screen", RASTER)
	MCFG_SCREEN_REFRESH_RATE(60)
	MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
	MCFG_SCREEN_SIZE(512, 384)
	MCFG_SCREEN_VISIBLE_AREA(0, 511, 0, 383)
	MCFG_SCREEN_UPDATE_DRIVER(taitotz_state, screen_update_taitotz)

MACHINE_CONFIG_END

static MACHINE_CONFIG_DERIVED( landhigh, taitotz )
	MCFG_CPU_MODIFY("iocpu")
	MCFG_CPU_PROGRAM_MAP(landhigh_tlcs900h_mem)
MACHINE_CONFIG_END


// Init for BIOS v1.52
static void init_taitotz_152(running_machine &machine)
{
	UINT32 *rom = (UINT32*)machine.root_device().memregion("user1")->base();
    rom[(0x2c87c^4)/4] = 0x38600000;	// skip sound load timeout...
//  rom[(0x2c620^4)/4] = 0x48000014;    // ID check skip (not needed with correct serial number)
}

// Init for BIOS 1.11a
static void init_taitotz_111a(running_machine &machine)
{
	UINT32 *rom = (UINT32*)machine.root_device().memregion("user1")->base();
	rom[(0x2b748^4)/4] = 0x480000b8;	// skip sound load timeout
}

static const char LANDHIGH_HDD_SERIAL[] =			// "824915746386        "
	{ 0x38, 0x32, 0x34, 0x39, 0x31, 0x35, 0x37, 0x34, 0x36, 0x33, 0x38, 0x36, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };

static const char BATLGR2_HDD_SERIAL[] =			// "            05412842"
	{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x35, 0x34, 0x31, 0x32, 0x38, 0x34, 0x32 };

static const char BATLGR2A_HDD_SERIAL[] =			// "            05411645"
	{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x35, 0x34, 0x31, 0x31, 0x36, 0x34, 0x35 };

static const char RAIZPIN_HDD_SERIAL[] =			// "691934013492        "
	{ 0x36, 0x39, 0x31, 0x39, 0x33, 0x34, 0x30, 0x31, 0x33, 0x34, 0x39, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };

DRIVER_INIT_MEMBER(taitotz_state,landhigh)
{

	init_taitotz_152(machine());

	m_hdd_serial_number = LANDHIGH_HDD_SERIAL;

	m_scr_base = 0x1c0000;

	m_displist_addr = 0x5200b8;
}

DRIVER_INIT_MEMBER(taitotz_state,batlgear)
{

	init_taitotz_111a(machine());

	// unknown, not used by BIOS 1.11a
	m_hdd_serial_number = NULL;

	m_scr_base = 0x1c0000;

	m_displist_addr = 0x420038;
}

DRIVER_INIT_MEMBER(taitotz_state,batlgr2)
{

	init_taitotz_152(machine());

	m_hdd_serial_number = BATLGR2_HDD_SERIAL;

	m_scr_base = 0x1e0000;

	m_displist_addr = 0x3608e4;
}

DRIVER_INIT_MEMBER(taitotz_state,batlgr2a)
{

	init_taitotz_152(machine());

	m_hdd_serial_number = BATLGR2A_HDD_SERIAL;

	m_scr_base = 0x1e0000;

	m_displist_addr = 0x3608e4;
}

DRIVER_INIT_MEMBER(taitotz_state,pwrshovl)
{

	init_taitotz_111a(machine());

	// unknown, not used by BIOS 1.11a
	m_hdd_serial_number = NULL;

	m_scr_base = 0x1c0000;

	m_displist_addr = 0x4a989c;
}

DRIVER_INIT_MEMBER(taitotz_state,raizpin)
{
	init_taitotz_152(machine());

	m_hdd_serial_number = RAIZPIN_HDD_SERIAL;

	m_scr_base = 0x1c0000;

	m_displist_addr = 0x33480c;
}


// Type-Zero System v1.52
#define TAITOTZ_BIOS_V152	\
	ROM_LOAD32_WORD_SWAP( "e68-05-1.ic6", 0x000000, 0x080000, CRC(6ad9b006) SHA1(f05a0ae26b6abaeda9c7944aee96c72b08fff7a5) )	\
	ROM_LOAD32_WORD_SWAP( "e68-04-1.ic5", 0x000002, 0x080000, CRC(c7c2dc6b) SHA1(bf88c818166c285130c5c73d6982f009da26e143) )

// Type-Zero System v1.11a (This was obtained from Battle Gear harddisk. An exact copy is also included in pwrshovl harddisk.)
#define TAITOTZ_BIOS_V111A	\
	ROM_LOAD32_WORD_SWAP( "ic6", 0x000000, 0x080000, CRC(29654245) SHA1(aaa34ff363eb96cf4a785fa6f9f7fc650b5ee93d) )	\
	ROM_LOAD32_WORD_SWAP( "ic5", 0x000002, 0x080000, CRC(8784804a) SHA1(fe9eed5289dcc89f2bc98cb752895b13e44b6097) )


ROM_START( taitotz )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V152

	ROM_REGION( 0x40000, "io_cpu", ROMREGION_ERASE00 )
	ROM_REGION( 0x10000, "sound_cpu", ROMREGION_ERASE00 ) /* Internal ROM :( */
	ROM_REGION( 0x500, "plds", ROMREGION_ERASE00 )
	DISK_REGION( "drive_0" )
ROM_END

ROM_START( landhigh )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V152

	ROM_REGION( 0x40000, "io_cpu", 0 )
	ROM_LOAD16_BYTE( "e82-03.ic14", 0x000000, 0x020000, CRC(0de65b4d) SHA1(932316f7435259b723a29843d58b2e3dca92e7b7) )
	ROM_LOAD16_BYTE( "e82-04.ic15", 0x000001, 0x020000, CRC(b3cb0f3d) SHA1(80414f50a1593c6b849d9f37e94a32168699a5c1) )

	ROM_REGION( 0x10000, "sound_cpu", 0 ) /* Internal ROM :( */
	ROM_LOAD( "e68-01.ic7", 0x000000, 0x010000, NO_DUMP )

	ROM_REGION( 0x500, "plds", 0 )
	ROM_LOAD( "e82-01.ic44", 0x000, 0x117, CRC(49eea30f) SHA1(ef97c792358f05b9214a2f58ee1e97e8208806c4) )
	ROM_LOAD( "e82-02.ic45", 0x117, 0x2dd, CRC(f581cff5) SHA1(468e0e6a3828f2dcda35c6d523154510f9c99db7) )
	ROM_LOAD( "e68-06.ic24", 0x3f4, 0x100, NO_DUMP )

	DISK_REGION( "drive_0" )
	DISK_IMAGE( "landhigh", 0, SHA1(7cea4ea5c3899e6ac774a4eb12821f44541d9c9c) )
ROM_END

ROM_START( batlgear )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V111A

	ROM_REGION( 0x40000, "io_cpu", 0 )
	ROM_LOAD16_BYTE( "e68-07.ic14",  0x000000, 0x020000, CRC(554c6fd7) SHA1(9f203dead81c7ccf73d7fd462cab147cd17f890f) )
	ROM_LOAD16_BYTE( "e68-08.ic15",  0x000001, 0x020000, CRC(f1932380) SHA1(64d12e858af15a9ba8254917da13863ac7c9c050) )

	ROM_REGION( 0x10000, "sound_cpu", 0 ) /* Internal ROM :( */
	ROM_LOAD( "e68-01.ic7", 0x000000, 0x010000, NO_DUMP )

	DISK_REGION( "drive_0" )
	DISK_IMAGE( "batlgear", 0, SHA1(eab283839ad3e0a3e6be11f6482570db334eacca) )
ROM_END

ROM_START( batlgr2 )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V152

	ROM_REGION( 0x40000, "io_cpu", 0 )
	ROM_LOAD16_BYTE( "e87-03.ic14",  0x000000, 0x020000, CRC(49ae7cd0) SHA1(15f07a6bb2044a85a2139481f1dc95a44520c929) )
	ROM_LOAD16_BYTE( "e87-04.ic15",  0x000001, 0x020000, CRC(59f8f75f) SHA1(f5595751b10c0033f460114c43f5e2c192fe61f1) )

	ROM_REGION( 0x10000, "sound_cpu", 0 ) /* Internal ROM :( */
	ROM_LOAD( "e68-01.ic7", 0x000000, 0x010000, NO_DUMP )

	DISK_REGION( "drive_0" )
	DISK_IMAGE( "bg2_204j", 0, SHA1(7ac100fba39ae0b93980c0af2f0212a731106912) )
ROM_END

ROM_START( batlgr2a )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V152

	ROM_REGION( 0x40000, "io_cpu", 0 )
	ROM_LOAD16_BYTE( "e87-03.ic14",  0x000000, 0x020000, CRC(49ae7cd0) SHA1(15f07a6bb2044a85a2139481f1dc95a44520c929) )
	ROM_LOAD16_BYTE( "e87-04.ic15",  0x000001, 0x020000, CRC(59f8f75f) SHA1(f5595751b10c0033f460114c43f5e2c192fe61f1) )

	ROM_REGION( 0x10000, "sound_cpu", 0 ) /* Internal ROM :( */
	ROM_LOAD( "e68-01.ic7", 0x000000, 0x010000, NO_DUMP )

	DISK_REGION( "drive_0" )
	DISK_IMAGE( "bg2_201j", 0, SHA1(542d12682bd0f95143368578461c6a4fcc492fcc) )
ROM_END

ROM_START( pwrshovl )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V111A

	ROM_REGION( 0x40000, "io_cpu", 0 )
    ROM_LOAD16_BYTE( "e74-04.ic14",   0x000000, 0x020000, CRC(ef21a261) SHA1(7398826dbf48014b9c7e9454f978f3e419ebc64b) )
    ROM_LOAD16_BYTE( "e74-05.ic15",   0x000001, 0x020000, CRC(2466217d) SHA1(dc814da3a1679cff001f179d3c1641af985a6490) )

	ROM_REGION( 0x10000, "sound_cpu", 0 ) /* Internal ROM :( */
	ROM_LOAD( "e68-01.ic7", 0x000000, 0x010000, NO_DUMP )

	DISK_REGION( "drive_0" )
	DISK_IMAGE( "pwrshovl", 0, SHA1(360f63b39f645851c513b4644fb40601b9ba1412) )
ROM_END

ROM_START( raizpin )
	ROM_REGION64_BE( 0x100000, "user1", 0 )
	TAITOTZ_BIOS_V152

	ROM_REGION( 0x40000, "io_cpu", 0 )
	ROM_LOAD16_BYTE( "f14-01.ic14",  0x000000, 0x020000, CRC(f86a184d) SHA1(46abd11430c08d4f384fb79a5a3a39e54f83b8d8) )
	ROM_LOAD16_BYTE( "f14-02.ic15",  0x000001, 0x020000, CRC(bd2d0dee) SHA1(652f810702598184551de9fd69436862d48c1608) )

	ROM_REGION( 0x10000, "sound_cpu", 0 ) /* Internal ROM :( */
	ROM_LOAD( "e68-01.ic7", 0x000000, 0x010000, NO_DUMP )

	DISK_REGION( "drive_0" )
	DISK_IMAGE( "raizpin", 0, SHA1(883ebcda03026df31da1cdb95af521e100c171ed) )
ROM_END

GAME( 1999, taitotz,  0, taitotz, taitotz, driver_device, 0, ROT0, "Taito", "Type Zero BIOS", GAME_NO_SOUND|GAME_NOT_WORKING|GAME_IS_BIOS_ROOT)
GAME( 1999, landhigh, taitotz, landhigh, landhigh, taitotz_state, landhigh, ROT0, "Taito", "Landing High Japan", GAME_NOT_WORKING | GAME_NO_SOUND )
GAME( 1999, batlgear, taitotz, taitotz,  batlgr2, taitotz_state,  batlgear, ROT0, "Taito", "Battle Gear", GAME_NOT_WORKING | GAME_NO_SOUND )
GAME( 1999, pwrshovl, taitotz, taitotz,  pwrshovl, taitotz_state, pwrshovl, ROT0, "Taito", "Power Shovel ni Norou!! - Power Shovel Simulator", GAME_NOT_WORKING | GAME_NO_SOUND )
GAME( 2000, batlgr2,  taitotz, taitotz,  batlgr2, taitotz_state,  batlgr2,  ROT0, "Taito", "Battle Gear 2 (v2.04J)", GAME_NOT_WORKING | GAME_NO_SOUND )
GAME( 2000, batlgr2a, batlgr2, taitotz,  batlgr2, taitotz_state,  batlgr2a, ROT0, "Taito", "Battle Gear 2 (v2.01J)", GAME_NOT_WORKING | GAME_NO_SOUND )
GAME( 2002, raizpin,  taitotz, taitotz,  taitotz, taitotz_state,  raizpin,  ROT0, "Taito", "Raizin Ping Pong", GAME_NOT_WORKING | GAME_NO_SOUND )