summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/a2600.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/drivers/a2600.c')
-rw-r--r--src/mess/drivers/a2600.c2307
1 files changed, 2307 insertions, 0 deletions
diff --git a/src/mess/drivers/a2600.c b/src/mess/drivers/a2600.c
new file mode 100644
index 00000000000..e2a640fc064
--- /dev/null
+++ b/src/mess/drivers/a2600.c
@@ -0,0 +1,2307 @@
+/***************************************************************************
+
+ Atari VCS 2600 driver
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/6532riot.h"
+#include "cpu/m6502/m6502.h"
+#include "sound/wave.h"
+#include "sound/tiaintf.h"
+#include "imagedev/cartslot.h"
+#include "imagedev/cassette.h"
+#include "formats/a26_cas.h"
+#include "video/tia.h"
+#include "hashfile.h"
+
+typedef struct {
+ UINT8 top;
+ UINT8 bottom;
+ UINT8 low;
+ UINT8 high;
+ UINT8 flag;
+ UINT8 music_mode; /* Only used by data fetchers 5,6, and 7 */
+ UINT8 osc_clk; /* Only used by data fetchers 5,6, and 7 */
+} df_t;
+
+typedef struct
+{
+ df_t df[8];
+ UINT8 movamt;
+ UINT8 latch_62;
+ UINT8 latch_64;
+ UINT8 dlc;
+ UINT8 shift_reg;
+ emu_timer *oscillator;
+} dpc_t;
+
+
+class a2600_state : public driver_device
+{
+public:
+ a2600_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag) ,
+ m_riot_ram(*this, "riot_ram"){ }
+
+ dpc_t m_dpc;
+ memory_region* m_extra_RAM;
+ UINT8* m_bank_base[5];
+ UINT8* m_ram_base;
+ required_shared_ptr<UINT8> m_riot_ram;
+ UINT8 m_banking_mode;
+ UINT8 m_keypad_left_column;
+ UINT8 m_keypad_right_column;
+ unsigned m_cart_size;
+ unsigned m_number_banks;
+ unsigned m_current_bank;
+ unsigned m_current_reset_bank_counter;
+ unsigned m_mode3E_ram_enabled;
+ UINT8 m_modeSS_byte;
+ UINT32 m_modeSS_byte_started;
+ unsigned m_modeSS_write_delay;
+ unsigned m_modeSS_write_enabled;
+ unsigned m_modeSS_high_ram_enabled;
+ unsigned m_modeSS_diff_adjust;
+ unsigned m_FVlocked;
+ UINT16 m_current_screen_height;
+ int m_FETimer;
+
+ direct_update_delegate m_FE_old_opbase_handler;
+
+ DECLARE_DIRECT_UPDATE_MEMBER(modeF6_opbase);
+ DECLARE_DIRECT_UPDATE_MEMBER(modeSS_opbase);
+ DECLARE_DIRECT_UPDATE_MEMBER(modeDPC_opbase_handler);
+ DECLARE_DIRECT_UPDATE_MEMBER(modeFE_opbase_handler);
+ DECLARE_READ8_MEMBER(modeF8_switch_r);
+ DECLARE_READ8_MEMBER(modeFA_switch_r);
+ DECLARE_READ8_MEMBER(modeF6_switch_r);
+ DECLARE_READ8_MEMBER(modeF4_switch_r);
+ DECLARE_READ8_MEMBER(modeE0_switch_r);
+ DECLARE_READ8_MEMBER(modeE7_switch_r);
+ DECLARE_READ8_MEMBER(modeE7_RAM_switch_r);
+ DECLARE_READ8_MEMBER(modeUA_switch_r);
+ DECLARE_READ8_MEMBER(modeDC_switch_r);
+ DECLARE_READ8_MEMBER(modeFV_switch_r);
+ DECLARE_READ8_MEMBER(modeJVP_switch_r);
+ DECLARE_WRITE8_MEMBER(modeF8_switch_w);
+ DECLARE_WRITE8_MEMBER(modeFA_switch_w);
+ DECLARE_WRITE8_MEMBER(modeF6_switch_w);
+ DECLARE_WRITE8_MEMBER(modeF4_switch_w);
+ DECLARE_WRITE8_MEMBER(modeE0_switch_w);
+ DECLARE_WRITE8_MEMBER(modeE7_switch_w);
+ DECLARE_WRITE8_MEMBER(modeE7_RAM_switch_w);
+ DECLARE_WRITE8_MEMBER(mode3F_switch_w);
+ DECLARE_WRITE8_MEMBER(modeUA_switch_w);
+ DECLARE_WRITE8_MEMBER(modeDC_switch_w);
+ DECLARE_WRITE8_MEMBER(mode3E_switch_w);
+ DECLARE_WRITE8_MEMBER(mode3E_RAM_switch_w);
+ DECLARE_WRITE8_MEMBER(mode3E_RAM_w);
+ DECLARE_WRITE8_MEMBER(modeFV_switch_w);
+ DECLARE_WRITE8_MEMBER(modeJVP_switch_w);
+ DECLARE_READ8_MEMBER(modeSS_r);
+ DECLARE_READ8_MEMBER(modeDPC_r);
+ DECLARE_WRITE8_MEMBER(modeDPC_w);
+ DECLARE_READ8_MEMBER(modeFE_switch_r);
+ DECLARE_WRITE8_MEMBER(modeFE_switch_w);
+ DECLARE_READ8_MEMBER(current_bank_r);
+ DECLARE_READ16_MEMBER(a2600_read_input_port);
+ DECLARE_READ8_MEMBER(a2600_get_databus_contents);
+ DECLARE_WRITE16_MEMBER(a2600_tia_vsync_callback);
+ DECLARE_WRITE16_MEMBER(a2600_tia_vsync_callback_pal);
+ void modeDPC_check_flag(UINT8 data_fetcher);
+ void modeDPC_decrement_counter(UINT8 data_fetcher);
+};
+
+
+
+#define CART machine.root_device().memregion("user1")->base()
+
+#define MASTER_CLOCK_NTSC 3579545
+#define MASTER_CLOCK_PAL 3546894
+#define CATEGORY_SELECT 16
+
+/* Some defines for the naming of the controller ports and the controllers */
+#define STR_LEFT_CONTROLLER "Left Controller"
+#define STR_RIGHT_CONTROLLER "Right Controller"
+#define STR_PADDLES "Paddles"
+#define STR_DRIVING "Driving"
+#define STR_KEYPAD "Keypad"
+#define STR_LIGHTGUN "Lightgun"
+#define STR_BOOSTERGRIP "Booster Grip"
+#define STR_CX22TRAKBALL "CX-22 Trak-Ball"
+#define STR_CX80TRAKBALL "CX-80 Trak-Ball (TB Mode) / AtariST Mouse"
+#define STR_AMIGAMOUSE "Amiga Mouse"
+#define STR_KIDVID "KidVid Voice Module"
+
+enum
+{
+ mode2K,
+ mode4K,
+ modeF8,
+ modeFA,
+ modeF6,
+ modeF4,
+ modeFE,
+ modeE0,
+ mode3F,
+ modeUA,
+ modeE7,
+ modeDC,
+ modeCV,
+ mode3E,
+ modeSS,
+ modeFV,
+ modeDPC,
+ mode32in1,
+ modeJVP
+};
+
+static const UINT16 supported_screen_heights[4] = { 262, 312, 328, 342 };
+
+static int detect_modeDC(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,numfound = 0;
+ // signature is also in 'video reflex'.. maybe figure out that controller port someday...
+ static const unsigned char signature[3] = { 0x8d, 0xf0, 0xff };
+ if (state->m_cart_size == 0x10000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature; i++)
+ {
+ if (!memcmp(&cart[i], signature,sizeof signature))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modef6(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i, numfound = 0;
+ static const unsigned char signature[3] = { 0x8d, 0xf6, 0xff };
+ if (state->m_cart_size == 0x4000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature; i++)
+ {
+ if (!memcmp(&cart[i], signature, sizeof signature))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_mode3E(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ // this one is a little hacky.. looks for STY $3e, which is unique to
+ // 'not boulderdash', but is the only example i have (cow)
+ // Would have used STA $3e, but 'Alien' and 'Star Raiders' do that for unknown reasons
+
+ int i,numfound = 0;
+ static const unsigned char signature[3] = { 0x84, 0x3e, 0x9d };
+ if (state->m_cart_size == 0x0800 || state->m_cart_size == 0x1000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature; i++)
+ {
+ if (!memcmp(&cart[i], signature,sizeof signature))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeSS(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,numfound = 0;
+ static const unsigned char signature[5] = { 0xbd, 0xe5, 0xff, 0x95, 0x81 };
+ if (state->m_cart_size == 0x0800 || state->m_cart_size == 0x1000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature; i++)
+ {
+ if (!memcmp(&cart[i], signature,sizeof signature))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeFE(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j,numfound = 0;
+ static const unsigned char signatures[][5] = {
+ { 0x20, 0x00, 0xd0, 0xc6, 0xc5 },
+ { 0x20, 0xc3, 0xf8, 0xa5, 0x82 },
+ { 0xd0, 0xfb, 0x20, 0x73, 0xfe },
+ { 0x20, 0x00, 0xf0, 0x84, 0xd6 }
+ };
+ if (state->m_cart_size == 0x2000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeE0(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j,numfound = 0;
+ static const unsigned char signatures[][3] = {
+ { 0x8d, 0xe0, 0x1f },
+ { 0x8d, 0xe0, 0x5f },
+ { 0x8d, 0xe9, 0xff },
+ { 0xad, 0xe9, 0xff },
+ { 0xad, 0xed, 0xff },
+ { 0xad, 0xf3, 0xbf }
+ };
+ if (state->m_cart_size == 0x2000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeCV(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j,numfound = 0;
+ static const unsigned char signatures[][3] = {
+ { 0x9d, 0xff, 0xf3 },
+ { 0x99, 0x00, 0xf4 }
+ };
+ if (state->m_cart_size == 0x0800 || state->m_cart_size == 0x1000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeFV(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j,numfound = 0;
+ static const unsigned char signatures[][3] = {
+ { 0x2c, 0xd0, 0xff }
+ };
+ if (state->m_cart_size == 0x2000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ state->m_FVlocked = 0;
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeJVP(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j,numfound = 0;
+ static const unsigned char signatures[][4] = {
+ { 0x2c, 0xc0, 0xef, 0x60 },
+ { 0x8d, 0xa0, 0x0f, 0xf0 }
+ };
+ if (state->m_cart_size == 0x4000 || state->m_cart_size == 0x2000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeE7(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j,numfound = 0;
+ static const unsigned char signatures[][3] = {
+ { 0xad, 0xe5, 0xff },
+ { 0x8d, 0xe7, 0xff }
+ };
+ if (state->m_cart_size == 0x2000 || state->m_cart_size == 0x4000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_modeUA(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,numfound = 0;
+ static const unsigned char signature[3] = { 0x8d, 0x40, 0x02 };
+ if (state->m_cart_size == 0x2000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature; i++)
+ {
+ if (!memcmp(&cart[i], signature,sizeof signature))
+ {
+ numfound = 1;
+ }
+ }
+ }
+ if (numfound) return 1;
+ return 0;
+}
+
+static int detect_8K_mode3F(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,numfound = 0;
+ static const unsigned char signature1[4] = { 0xa9, 0x01, 0x85, 0x3f };
+ static const unsigned char signature2[4] = { 0xa9, 0x02, 0x85, 0x3f };
+ // have to look for two signatures because 'not boulderdash' gives false positive otherwise
+ if (state->m_cart_size == 0x2000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature1; i++)
+ {
+ if (!memcmp(&cart[i], signature1,sizeof signature1))
+ {
+ numfound |= 0x01;
+ }
+ if (!memcmp(&cart[i], signature2,sizeof signature2))
+ {
+ numfound |= 0x02;
+ }
+ }
+ }
+ if (numfound == 0x03) return 1;
+ return 0;
+}
+
+static int detect_32K_mode3F(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,numfound = 0;
+ static const unsigned char signature[4] = { 0xa9, 0x0e, 0x85, 0x3f };
+ if (state->m_cart_size >= 0x8000)
+ {
+ UINT8 *cart = CART;
+ for (i = 0; i < state->m_cart_size - sizeof signature; i++)
+ {
+ if (!memcmp(&cart[i], signature,sizeof signature))
+ {
+ numfound++;
+ }
+ }
+ }
+ if (numfound > 1) return 1;
+ return 0;
+}
+
+static int detect_super_chip(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i,j;
+ UINT8 *cart = CART;
+ static const unsigned char signatures[][5] = {
+ { 0xa2, 0x7f, 0x9d, 0x00, 0xf0 }, // dig dug
+ { 0xae, 0xf6, 0xff, 0x4c, 0x00 } // off the wall
+ };
+
+ if (state->m_cart_size == 0x4000)
+ {
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]); j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0]))
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ for (i = 0x1000; i < state->m_cart_size; i += 0x1000)
+ {
+ if (memcmp(cart, cart + i, 0x100))
+ {
+ return 0;
+ }
+ }
+ /* Check the reset vector does not point into the super chip RAM area */
+ i = ( cart[0x0FFD] << 8 ) | cart[0x0FFC];
+ if ( ( i & 0x0FFF ) < 0x0100 )
+ {
+ return 0;
+ }
+ return 1;
+}
+
+
+static DEVICE_START( a2600_cart )
+{
+ a2600_state *state = device->machine().driver_data<a2600_state>();
+ state->m_banking_mode = 0xff;
+}
+
+
+static DEVICE_IMAGE_LOAD( a2600_cart )
+{
+ a2600_state *state = image.device().machine().driver_data<a2600_state>();
+ running_machine &machine = image.device().machine();
+ UINT8 *cart = CART;
+
+ if (image.software_entry() == NULL)
+ state->m_cart_size = image.length();
+ else
+ state->m_cart_size = image.get_software_region_length("rom");
+
+ switch (state->m_cart_size)
+ {
+ case 0x00800:
+ case 0x01000:
+ case 0x02000:
+ case 0x028ff:
+ case 0x02900:
+ case 0x03000:
+ case 0x04000:
+ case 0x08000:
+ case 0x10000:
+ case 0x80000:
+ break;
+
+ default:
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Invalid rom file size" );
+ return 1; /* unsupported image format */
+ }
+
+ state->m_current_bank = 0;
+
+ if (image.software_entry() == NULL)
+ image.fread(cart, state->m_cart_size);
+ else
+ memcpy(cart, image.get_software_region("rom"), state->m_cart_size);
+
+ if (!(state->m_cart_size == 0x4000 && detect_modef6(image.device().machine())))
+ {
+ while (state->m_cart_size > 0x00800)
+ {
+ if (!memcmp(cart, &cart[state->m_cart_size/2],state->m_cart_size/2)) state->m_cart_size /= 2;
+ else break;
+ }
+ }
+
+ return 0;
+}
+
+
+static int next_bank(a2600_state *state)
+{
+ return state->m_current_bank = (state->m_current_bank + 1) % 16;
+}
+
+
+static void modeF8_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x1000 * offset;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void modeFA_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x1000 * offset;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void modeF6_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x1000 * offset;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void modeF4_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x1000 * offset;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void mode3F_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x800 * (data & (state->m_number_banks - 1));
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void modeUA_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + (offset >> 6) * 0x1000;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void modeE0_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int bank = 1 + (offset >> 3);
+ char bank_name[10];
+ sprintf(bank_name,"bank%d",bank);
+ state->m_bank_base[bank] = CART + 0x400 * (offset & 7);
+ state->membank(bank_name)->set_base(state->m_bank_base[bank]);
+}
+static void modeE7_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x800 * offset;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void modeE7_RAM_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->membank("bank9")->set_base(state->m_extra_RAM->base() + (4 + offset) * 256 );
+}
+static void modeDC_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x1000 * next_bank(state);
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+}
+static void mode3E_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_bank_base[1] = CART + 0x800 * (data & (state->m_number_banks - 1));
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+ state->m_mode3E_ram_enabled = 0;
+}
+static void mode3E_RAM_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ state->m_ram_base = state->m_extra_RAM->base() + 0x200 * ( data & 0x3F );
+ state->membank("bank1")->set_base(state->m_ram_base );
+ state->m_mode3E_ram_enabled = 1;
+}
+static void modeFV_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ //printf("ModeFV %04x\n",offset);
+ if (!state->m_FVlocked && ( cpu_get_pc(machine.device("maincpu")) & 0x1F00 ) == 0x1F00 )
+ {
+ state->m_FVlocked = 1;
+ state->m_current_bank = state->m_current_bank ^ 0x01;
+ state->m_bank_base[1] = CART + 0x1000 * state->m_current_bank;
+ state->membank("bank1")->set_base(state->m_bank_base[1]);
+ }
+}
+static void modeJVP_switch(running_machine &machine, UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ switch( offset )
+ {
+ case 0x00:
+ case 0x20:
+ state->m_current_bank ^= 1;
+ break;
+ default:
+ printf("%04X: write to unknown mapper address %02X\n", cpu_get_pc(machine.device("maincpu")), 0xfa0 + offset );
+ break;
+ }
+ state->m_bank_base[1] = CART + 0x1000 * state->m_current_bank;
+ state->membank("bank1")->set_base(state->m_bank_base[1] );
+}
+
+
+/* These read handlers will return the byte from the new bank */
+READ8_MEMBER(a2600_state::modeF8_switch_r)
+{
+ modeF8_switch(machine(), offset, 0);
+ return m_bank_base[1][0xff8 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeFA_switch_r)
+{
+ modeFA_switch(machine(), offset, 0);
+ return m_bank_base[1][0xff8 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeF6_switch_r)
+{
+ modeF6_switch(machine(), offset, 0);
+ return m_bank_base[1][0xff6 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeF4_switch_r)
+{
+ modeF4_switch(machine(), offset, 0);
+ return m_bank_base[1][0xff4 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeE0_switch_r)
+{
+ modeE0_switch(machine(), offset, 0);
+ return m_bank_base[4][0x3e0 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeE7_switch_r)
+{
+ modeE7_switch(machine(), offset, 0);
+ return m_bank_base[1][0xfe0 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeE7_RAM_switch_r)
+{
+ modeE7_RAM_switch(machine(), offset, 0);
+ return 0;
+}
+
+READ8_MEMBER(a2600_state::modeUA_switch_r)
+{
+ modeUA_switch(machine(), offset, 0);
+ return 0;
+}
+
+READ8_MEMBER(a2600_state::modeDC_switch_r)
+{
+ modeDC_switch(machine(), offset, 0);
+ return m_bank_base[1][0xff0 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeFV_switch_r)
+{
+ modeFV_switch(machine(), offset, 0);
+ return m_bank_base[1][0xfd0 + offset];
+}
+
+READ8_MEMBER(a2600_state::modeJVP_switch_r)
+{
+ modeJVP_switch(machine(), offset, 0);
+ return m_riot_ram[ 0x20 + offset ];
+}
+
+
+WRITE8_MEMBER(a2600_state::modeF8_switch_w){ modeF8_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeFA_switch_w){ modeFA_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeF6_switch_w){ modeF6_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeF4_switch_w){ modeF4_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeE0_switch_w){ modeE0_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeE7_switch_w){ modeE7_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeE7_RAM_switch_w){ modeE7_RAM_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::mode3F_switch_w){ mode3F_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeUA_switch_w){ modeUA_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeDC_switch_w){ modeDC_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::mode3E_switch_w){ mode3E_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::mode3E_RAM_switch_w){ mode3E_RAM_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::mode3E_RAM_w)
+{
+ if ( m_mode3E_ram_enabled )
+ {
+ m_ram_base[offset] = data;
+ }
+}
+WRITE8_MEMBER(a2600_state::modeFV_switch_w){ modeFV_switch(machine(), offset, data); }
+WRITE8_MEMBER(a2600_state::modeJVP_switch_w)
+{
+ modeJVP_switch(machine(), offset, data); m_riot_ram[ 0x20 + offset ] = data;
+}
+
+
+DIRECT_UPDATE_MEMBER(a2600_state::modeF6_opbase)
+{
+ if ( ( address & 0x1FFF ) >= 0x1FF6 && ( address & 0x1FFF ) <= 0x1FF9 )
+ {
+ modeF6_switch_w(*machine().device("maincpu")->memory().space(AS_PROGRAM), ( address & 0x1FFF ) - 0x1FF6, 0 );
+ }
+ return address;
+}
+
+DIRECT_UPDATE_MEMBER(a2600_state::modeSS_opbase)
+{
+ if ( address & 0x1000 )
+ {
+ if ( address & 0x800 )
+ {
+ direct.explicit_configure(( address & 0xf800 ), ( address & 0xf800 ) | 0x7ff, 0x7ff, m_bank_base[2]);
+ }
+ else
+ {
+ direct.explicit_configure(( address & 0xf800 ), ( address & 0xf800 ) | 0x7ff, 0x7ff, m_bank_base[1]);
+ }
+ return ~0;
+ }
+ return address;
+}
+
+READ8_MEMBER(a2600_state::modeSS_r)
+{
+ UINT8 data = ( offset & 0x800 ) ? m_bank_base[2][offset & 0x7FF] : m_bank_base[1][offset];
+
+ //logerror("%04X: read from modeSS area offset = %04X\n", cpu_get_pc(machine().device("maincpu")), offset);
+ /* Check for control register "write" */
+ if ( offset == 0xFF8 )
+ {
+ //logerror("%04X: write to modeSS control register data = %02X\n", cpu_get_pc(machine().device("maincpu")), m_modeSS_byte);
+ m_modeSS_write_enabled = m_modeSS_byte & 0x02;
+ m_modeSS_write_delay = m_modeSS_byte >> 5;
+ switch ( m_modeSS_byte & 0x1C )
+ {
+ case 0x00:
+ m_bank_base[1] = m_extra_RAM->base() + 2 * 0x800;
+ m_bank_base[2] = ( m_modeSS_byte & 0x01 ) ? memregion("maincpu")->base() + 0x1800 : memregion("user1")->base();
+ m_modeSS_high_ram_enabled = 0;
+ break;
+ case 0x04:
+ m_bank_base[1] = m_extra_RAM->base();
+ m_bank_base[2] = ( m_modeSS_byte & 0x01 ) ? memregion("maincpu")->base() + 0x1800 : memregion("user1")->base();
+ m_modeSS_high_ram_enabled = 0;
+ break;
+ case 0x08:
+ m_bank_base[1] = m_extra_RAM->base() + 2 * 0x800;
+ m_bank_base[2] = m_extra_RAM->base();
+ m_modeSS_high_ram_enabled = 1;
+ break;
+ case 0x0C:
+ m_bank_base[1] = m_extra_RAM->base();
+ m_bank_base[2] = m_extra_RAM->base() + 2 * 0x800;
+ m_modeSS_high_ram_enabled = 1;
+ break;
+ case 0x10:
+ m_bank_base[1] = m_extra_RAM->base() + 2 * 0x800;
+ m_bank_base[2] = ( m_modeSS_byte & 0x01 ) ? memregion("maincpu")->base() + 0x1800 : memregion("user1")->base();
+ m_modeSS_high_ram_enabled = 0;
+ break;
+ case 0x14:
+ m_bank_base[1] = m_extra_RAM->base() + 0x800;
+ m_bank_base[2] = ( m_modeSS_byte & 0x01 ) ? memregion("maincpu")->base() + 0x1800 : memregion("user1")->base();
+ m_modeSS_high_ram_enabled = 0;
+ break;
+ case 0x18:
+ m_bank_base[1] = m_extra_RAM->base() + 2 * 0x800;
+ m_bank_base[2] = m_extra_RAM->base() + 0x800;
+ m_modeSS_high_ram_enabled = 1;
+ break;
+ case 0x1C:
+ m_bank_base[1] = m_extra_RAM->base() + 0x800;
+ m_bank_base[2] = m_extra_RAM->base() + 2 * 0x800;
+ m_modeSS_high_ram_enabled = 1;
+ break;
+ }
+ membank("bank1")->set_base(m_bank_base[1] );
+ membank("bank2")->set_base(m_bank_base[2] );
+ }
+ else if ( offset == 0xFF9 )
+ {
+ /* Cassette port read */
+ double tap_val = machine().device<cassette_image_device>(CASSETTE_TAG)->input();
+ //logerror("%04X: Cassette port read, tap_val = %f\n", cpu_get_pc(machine().device("maincpu")), tap_val);
+ if ( tap_val < 0 )
+ {
+ data = 0x00;
+ }
+ else
+ {
+ data = 0x01;
+ }
+ }
+ else
+ {
+ /* Possible RAM write */
+ if ( m_modeSS_write_enabled )
+ {
+ int diff = machine().device<cpu_device>("maincpu")->total_cycles() - m_modeSS_byte_started;
+ //logerror("%04X: offset = %04X, %d\n", cpu_get_pc(machine().device("maincpu")), offset, diff);
+ if ( diff - m_modeSS_diff_adjust == 5 )
+ {
+ //logerror("%04X: RAM write offset = %04X, data = %02X\n", cpu_get_pc(machine().device("maincpu")), offset, m_modeSS_byte );
+ if ( offset & 0x800 )
+ {
+ if ( m_modeSS_high_ram_enabled )
+ {
+ m_bank_base[2][offset & 0x7FF] = m_modeSS_byte;
+ data = m_modeSS_byte;
+ }
+ }
+ else
+ {
+ m_bank_base[1][offset] = m_modeSS_byte;
+ data = m_modeSS_byte;
+ }
+ }
+ else if ( offset < 0x0100 )
+ {
+ m_modeSS_byte = offset;
+ m_modeSS_byte_started = machine().device<cpu_device>("maincpu")->total_cycles();
+ }
+ /* Check for dummy read from same address */
+ if ( diff == 2 )
+ {
+ m_modeSS_diff_adjust = 1;
+ }
+ else
+ {
+ m_modeSS_diff_adjust = 0;
+ }
+ }
+ else if ( offset < 0x0100 )
+ {
+ m_modeSS_byte = offset;
+ m_modeSS_byte_started = machine().device<cpu_device>("maincpu")->total_cycles();
+ }
+ }
+ /* Because the mame core caches opcode data and doesn't perform reads like normal */
+ /* we have to put in this little hack here to get Suicide Mission to work. */
+ if ( offset != 0xFF8 && ( cpu_get_pc(machine().device("maincpu")) & 0x1FFF ) == 0x1FF8 )
+ {
+ modeSS_r( space, 0xFF8 );
+ }
+ return data;
+}
+
+void a2600_state::modeDPC_check_flag(UINT8 data_fetcher)
+{
+ /* Set flag when low counter equals top */
+ if ( m_dpc.df[data_fetcher].low == m_dpc.df[data_fetcher].top )
+ {
+ m_dpc.df[data_fetcher].flag = 1;
+ }
+ /* Reset flag when low counter equals bottom */
+ if ( m_dpc.df[data_fetcher].low == m_dpc.df[data_fetcher].bottom )
+ {
+ m_dpc.df[data_fetcher].flag = 0;
+ }
+}
+
+void a2600_state::modeDPC_decrement_counter(UINT8 data_fetcher)
+{
+ m_dpc.df[data_fetcher].low -= 1;
+ if ( m_dpc.df[data_fetcher].low == 0xFF )
+ {
+ m_dpc.df[data_fetcher].high -= 1;
+ if ( data_fetcher > 4 && m_dpc.df[data_fetcher].music_mode )
+ {
+ m_dpc.df[data_fetcher].low = m_dpc.df[data_fetcher].top;
+ }
+ }
+
+ modeDPC_check_flag(data_fetcher );
+}
+
+static TIMER_CALLBACK(modeDPC_timer_callback)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int data_fetcher;
+ for( data_fetcher = 5; data_fetcher < 8; data_fetcher++ )
+ {
+ if ( state->m_dpc.df[data_fetcher].osc_clk )
+ {
+ state->modeDPC_decrement_counter(data_fetcher );
+ }
+ }
+}
+
+DIRECT_UPDATE_MEMBER(a2600_state::modeDPC_opbase_handler)
+{
+ UINT8 new_bit;
+ new_bit = ( m_dpc.shift_reg & 0x80 ) ^ ( ( m_dpc.shift_reg & 0x20 ) << 2 );
+ new_bit = new_bit ^ ( ( ( m_dpc.shift_reg & 0x10 ) << 3 ) ^ ( ( m_dpc.shift_reg & 0x08 ) << 4 ) );
+ new_bit = new_bit ^ 0x80;
+ m_dpc.shift_reg = new_bit | ( m_dpc.shift_reg >> 1 );
+ return address;
+}
+
+READ8_MEMBER(a2600_state::modeDPC_r)
+{
+ static const UINT8 dpc_amplitude[8] = { 0x00, 0x04, 0x05, 0x09, 0x06, 0x0A, 0x0B, 0x0F };
+ UINT8 data_fetcher = offset & 0x07;
+ UINT8 data = 0xFF;
+
+ logerror("%04X: Read from DPC offset $%02X\n", cpu_get_pc(machine().device("maincpu")), offset);
+ if ( offset < 0x08 )
+ {
+ switch( offset & 0x06 )
+ {
+ case 0x00: /* Random number generator */
+ case 0x02:
+ return m_dpc.shift_reg;
+ case 0x04: /* Sound value, MOVAMT value AND'd with Draw Line Carry; with Draw Line Add */
+ m_dpc.latch_62 = m_dpc.latch_64;
+ case 0x06: /* Sound value, MOVAMT value AND'd with Draw Line Carry; without Draw Line Add */
+ m_dpc.latch_64 = m_dpc.latch_62 + m_dpc.df[4].top;
+ m_dpc.dlc = ( m_dpc.latch_62 + m_dpc.df[4].top > 0xFF ) ? 1 : 0;
+ data = 0;
+ if ( m_dpc.df[5].music_mode && m_dpc.df[5].flag )
+ {
+ data |= 0x01;
+ }
+ if ( m_dpc.df[6].music_mode && m_dpc.df[6].flag )
+ {
+ data |= 0x02;
+ }
+ if ( m_dpc.df[7].music_mode && m_dpc.df[7].flag )
+ {
+ data |= 0x04;
+ }
+ return ( m_dpc.dlc ? m_dpc.movamt & 0xF0 : 0 ) | dpc_amplitude[data];
+ }
+ }
+ else
+ {
+ UINT8 display_data = memregion("user1")->base()[0x2000 + ( ~ ( ( m_dpc.df[data_fetcher].low | ( m_dpc.df[data_fetcher].high << 8 ) ) ) & 0x7FF ) ];
+
+ switch( offset & 0x38 )
+ {
+ case 0x08: /* display data */
+ data = display_data;
+ break;
+ case 0x10: /* display data AND'd w/flag */
+ data = m_dpc.df[data_fetcher].flag ? display_data : 0x00;
+ break;
+ case 0x18: /* display data AND'd w/flag, nibbles swapped */
+ data = m_dpc.df[data_fetcher].flag ? BITSWAP8(display_data,3,2,1,0,7,6,5,4) : 0x00;
+ break;
+ case 0x20: /* display data AND'd w/flag, byte reversed */
+ data = m_dpc.df[data_fetcher].flag ? BITSWAP8(display_data,0,1,2,3,4,5,6,7) : 0x00;
+ break;
+ case 0x28: /* display data AND'd w/flag, rotated right */
+ data = m_dpc.df[data_fetcher].flag ? ( display_data >> 1 ) : 0x00;
+ break;
+ case 0x30: /* display data AND'd w/flag, rotated left */
+ data = m_dpc.df[data_fetcher].flag ? ( display_data << 1 ) : 0x00;
+ break;
+ case 0x38: /* flag */
+ data = m_dpc.df[data_fetcher].flag ? 0xFF : 0x00;
+ break;
+ }
+
+ if ( data_fetcher < 5 || ! m_dpc.df[data_fetcher].osc_clk )
+ {
+ modeDPC_decrement_counter(data_fetcher );
+ }
+ }
+ return data;
+}
+
+WRITE8_MEMBER(a2600_state::modeDPC_w)
+{
+ UINT8 data_fetcher = offset & 0x07;
+
+ switch( offset & 0x38 )
+ {
+ case 0x00: /* Top count */
+ m_dpc.df[data_fetcher].top = data;
+ m_dpc.df[data_fetcher].flag = 0;
+ modeDPC_check_flag(data_fetcher );
+ break;
+ case 0x08: /* Bottom count */
+ m_dpc.df[data_fetcher].bottom = data;
+ modeDPC_check_flag(data_fetcher );
+ break;
+ case 0x10: /* Counter low */
+ m_dpc.df[data_fetcher].low = data;
+ if ( data_fetcher == 4 )
+ {
+ m_dpc.latch_64 = data;
+ }
+ if ( data_fetcher > 4 && m_dpc.df[data_fetcher].music_mode )
+ {
+ m_dpc.df[data_fetcher].low = m_dpc.df[data_fetcher].top;
+ }
+ modeDPC_check_flag(data_fetcher );
+ break;
+ case 0x18: /* Counter high */
+ m_dpc.df[data_fetcher].high = data;
+ m_dpc.df[data_fetcher].music_mode = data & 0x10;
+ m_dpc.df[data_fetcher].osc_clk = data & 0x20;
+ if ( data_fetcher > 4 && m_dpc.df[data_fetcher].music_mode && m_dpc.df[data_fetcher].low == 0xFF )
+ {
+ m_dpc.df[data_fetcher].low = m_dpc.df[data_fetcher].top;
+ modeDPC_check_flag(data_fetcher );
+ }
+ break;
+ case 0x20: /* Draw line movement value / MOVAMT */
+ m_dpc.movamt = data;
+ break;
+ case 0x28: /* Not used */
+ logerror("%04X: Write to unused DPC register $%02X, data $%02X\n", cpu_get_pc(machine().device("maincpu")), offset, data);
+ break;
+ case 0x30: /* Random number generator reset */
+ m_dpc.shift_reg = 0;
+ break;
+ case 0x38: /* Not used */
+ logerror("%04X: Write to unused DPC register $%02X, data $%02X\n", cpu_get_pc(machine().device("maincpu")), offset, data);
+ break;
+ }
+}
+
+/*
+
+There seems to be a kind of lag between the writing to address 0x1FE and the
+Activision switcher springing into action. It waits for the next byte to arrive
+on the data bus, which is the new PCH in the case of a JSR, and the PCH of the
+stored PC on the stack in the case of an RTS.
+
+depending on last byte & 0x20 -> 0x00 -> switch to bank #1
+ -> 0x20 -> switch to bank #0
+
+ */
+
+
+DIRECT_UPDATE_MEMBER(a2600_state::modeFE_opbase_handler)
+{
+ if ( ! m_FETimer )
+ {
+ /* Still cheating a bit here by looking bit 13 of the address..., but the high byte of the
+ cpu should be the last byte that was on the data bus and so should determine the bank
+ we should switch in. */
+ m_bank_base[1] = memregion("user1")->base() + 0x1000 * ( ( address & 0x2000 ) ? 0 : 1 );
+ membank("bank1")->set_base(m_bank_base[1] );
+ /* and restore old opbase handler */
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(m_FE_old_opbase_handler);
+ }
+ else
+ {
+ /* Wait for one memory access to have passed (reading of new PCH either from code or from stack) */
+ m_FETimer--;
+ }
+ return address;
+}
+
+static void modeFE_switch(running_machine &machine,UINT16 offset, UINT8 data)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ /* Retrieve last byte read by the cpu (for this mapping scheme this
+ should be the last byte that was on the data bus
+ */
+ state->m_FETimer = 1;
+ state->m_FE_old_opbase_handler = space->set_direct_update_handler(direct_update_delegate(FUNC(a2600_state::modeFE_opbase_handler), state));
+}
+
+READ8_MEMBER(a2600_state::modeFE_switch_r)
+{
+ modeFE_switch(machine(),offset, 0 );
+ return space.read_byte(0xFE );
+}
+
+WRITE8_MEMBER(a2600_state::modeFE_switch_w)
+{
+ space.write_byte(0xFE, data );
+ modeFE_switch(machine(),offset, 0 );
+}
+
+READ8_MEMBER(a2600_state::current_bank_r)
+{
+ return m_current_bank;
+}
+
+static ADDRESS_MAP_START(a2600_mem, AS_PROGRAM, 8, a2600_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x007F) AM_MIRROR(0x0F00) AM_DEVREADWRITE("tia_video", tia_video_device, read, write)
+ AM_RANGE(0x0080, 0x00FF) AM_MIRROR(0x0D00) AM_RAM AM_SHARE("riot_ram")
+ AM_RANGE(0x0280, 0x029F) AM_MIRROR(0x0D00) AM_DEVREADWRITE_LEGACY("riot", riot6532_r, riot6532_w)
+ AM_RANGE(0x1000, 0x1FFF) AM_ROMBANK("bank1")
+ADDRESS_MAP_END
+
+static WRITE8_DEVICE_HANDLER(switch_A_w)
+{
+ a2600_state *state = device->machine().driver_data<a2600_state>();
+ running_machine &machine = device->machine();
+
+ /* Left controller port */
+ if ( machine.root_device().ioport("CONTROLLERS")->read() / CATEGORY_SELECT == 0x03 )
+ {
+ state->m_keypad_left_column = data / 16;
+ }
+
+ /* Right controller port */
+ switch( machine.root_device().ioport("CONTROLLERS")->read() % CATEGORY_SELECT )
+ {
+ case 0x03: /* Keypad */
+ state->m_keypad_right_column = data & 0x0F;
+ break;
+ case 0x0a: /* KidVid voice module */
+ machine.device<cassette_image_device>(CASSETTE_TAG)->change_state(( data & 0x02 ) ? (cassette_state)CASSETTE_MOTOR_DISABLED : (cassette_state)(CASSETTE_MOTOR_ENABLED | CASSETTE_PLAY), (cassette_state)CASSETTE_MOTOR_DISABLED );
+ break;
+ }
+}
+
+static READ8_DEVICE_HANDLER( switch_A_r )
+{
+ static const UINT8 driving_lookup[4] = { 0x00, 0x02, 0x03, 0x01 };
+ running_machine &machine = device->machine();
+ UINT8 val = 0;
+
+ /* Left controller port PINs 1-4 ( 4321 ) */
+ switch( machine.root_device().ioport("CONTROLLERS")->read() / CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ case 0x05: /* Joystick w/Boostergrip */
+ val |= machine.root_device().ioport("SWA_JOY")->read() & 0xF0;
+ break;
+ case 0x01: /* Paddle */
+ val |= machine.root_device().ioport("SWA_PAD")->read() & 0xF0;
+ break;
+ case 0x02: /* Driving */
+ val |= 0xC0;
+ val |= ( driving_lookup[ ( machine.root_device().ioport("WHEEL_L")->read() & 0x18 ) >> 3 ] << 4 );
+ break;
+ case 0x06: /* Trakball CX-22 */
+ case 0x07: /* Trakball CX-80 / ST mouse */
+ case 0x09: /* Amiga mouse */
+ default:
+ val |= 0xF0;
+ break;
+ }
+
+ /* Right controller port PINs 1-4 ( 4321 ) */
+ switch( machine.root_device().ioport("CONTROLLERS")->read() % CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ case 0x05: /* Joystick w/Boostergrip */
+ val |= machine.root_device().ioport("SWA_JOY")->read() & 0x0F;
+ break;
+ case 0x01: /* Paddle */
+ val |= machine.root_device().ioport("SWA_PAD")->read() & 0x0F;
+ break;
+ case 0x02: /* Driving */
+ val |= 0x0C;
+ val |= ( driving_lookup[ ( machine.root_device().ioport("WHEEL_R")->read() & 0x18 ) >> 3 ] );
+ break;
+ case 0x06: /* Trakball CX-22 */
+ case 0x07: /* Trakball CX-80 / ST mouse */
+ case 0x09: /* Amiga mouse */
+ default:
+ val |= 0x0F;
+ break;
+ }
+
+ return val;
+}
+
+static WRITE8_DEVICE_HANDLER(switch_B_w )
+{
+}
+
+static WRITE_LINE_DEVICE_HANDLER( irq_callback )
+{
+}
+
+static READ8_DEVICE_HANDLER( riot_input_port_8_r )
+{
+ return device->machine().root_device().ioport("SWB")->read();
+}
+
+static const riot6532_interface r6532_interface =
+{
+ DEVCB_HANDLER(switch_A_r),
+ DEVCB_HANDLER(riot_input_port_8_r),
+ DEVCB_HANDLER(switch_A_w),
+ DEVCB_HANDLER(switch_B_w),
+ DEVCB_LINE(irq_callback)
+};
+
+
+static void install_banks(running_machine &machine, int count, unsigned init)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ int i;
+ UINT8 *cart = CART;
+
+ for (i = 0; i < count; i++)
+ {
+ static const char *const handler[] =
+ {
+ "bank1",
+ "bank2",
+ "bank3",
+ "bank4",
+ };
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(
+ 0x1000 + (i + 0) * 0x1000 / count - 0,
+ 0x1000 + (i + 1) * 0x1000 / count - 1, handler[i]);
+
+ state->m_bank_base[i + 1] = cart + init;
+ state->membank(handler[i])->set_base(state->m_bank_base[i + 1]);
+ }
+}
+
+READ16_MEMBER(a2600_state::a2600_read_input_port)
+{
+ int i;
+
+ switch( offset )
+ {
+ case 0: /* Left controller port PIN 5 */
+ switch ( ioport("CONTROLLERS")->read() / CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ case 0x01: /* Paddle */
+ return ioport("PADDLE1")->read();
+ case 0x03: /* Keypad */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( ! ( ( m_keypad_left_column >> i ) & 0x01 ) )
+ {
+ if ( ( ioport("KEYPAD_L")->read() >> 3*i ) & 0x01 )
+ {
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ }
+ else
+ {
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ }
+ }
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ case 0x05: /* Boostergrip joystick */
+ return ( ioport("BUTTONS_L")->read() & 0x40 ) ? TIA_INPUT_PORT_ALWAYS_OFF : TIA_INPUT_PORT_ALWAYS_ON;
+ default:
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ break;
+ case 1: /* Right controller port PIN 5 */
+ switch ( ioport("CONTROLLERS")->read() / CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ case 0x01: /* Paddle */
+ return ioport("PADDLE3")->read();
+ case 0x03: /* Keypad */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( ! ( ( m_keypad_left_column >> i ) & 0x01 ) )
+ {
+ if ( ( ioport("KEYPAD_L")->read() >> 3*i ) & 0x02 )
+ {
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ }
+ else
+ {
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ }
+ }
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ case 0x05: /* Joystick w/Boostergrip */
+ return ( ioport("BUTTONS_L")->read() & 0x20 ) ? TIA_INPUT_PORT_ALWAYS_OFF : TIA_INPUT_PORT_ALWAYS_ON;
+ default:
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ break;
+ case 2: /* Left controller port PIN 9 */
+ switch ( ioport("CONTROLLERS")->read() % CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ case 0x01: /* Paddle */
+ return ioport("PADDLE2")->read();
+ case 0x03: /* Keypad */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( ! ( ( m_keypad_right_column >> i ) & 0x01 ) )
+ {
+ if ( ( ioport("KEYPAD_R")->read() >> 3*i ) & 0x01 )
+ {
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ }
+ else
+ {
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ }
+ }
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ case 0x05: /* Joystick w/Boostergrip */
+ return ( ioport("BUTTONS_R")->read() & 0x40 ) ? TIA_INPUT_PORT_ALWAYS_OFF : TIA_INPUT_PORT_ALWAYS_ON;
+ default:
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ break;
+ case 3: /* Right controller port PIN 9 */
+ switch ( ioport("CONTROLLERS")->read() % CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ case 0x01: /* Paddle */
+ return ioport("PADDLE4")->read();
+ case 0x03: /* Keypad */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( ! ( ( m_keypad_right_column >> i ) & 0x01 ) )
+ {
+ if ( ( ioport("KEYPAD_R")->read() >> 3*i ) & 0x02 )
+ {
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ }
+ else
+ {
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ }
+ }
+ return TIA_INPUT_PORT_ALWAYS_ON;
+ case 0x05: /* Joystick w/Boostergrip */
+ return ( ioport("BUTTONS_R")->read() & 0x20 ) ? TIA_INPUT_PORT_ALWAYS_OFF : TIA_INPUT_PORT_ALWAYS_ON;
+ default:
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+ }
+ break;
+ case 4: /* Left controller port PIN 6 */
+ switch ( ioport("CONTROLLERS")->read() / CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ case 0x05: /* Joystick w/Boostergrip */
+ return ioport("BUTTONS_L")->read();
+ case 0x01: /* Paddle */
+ return 0xff;
+ case 0x02: /* Driving */
+ return ioport("BUTTONS_L")->read() << 3;
+ case 0x03: /* Keypad */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( ! ( ( m_keypad_left_column >> i ) & 0x01 ) )
+ {
+ if ( ( ioport("KEYPAD_L")->read() >> 3*i ) & 0x04 )
+ {
+ return 0xff;
+ }
+ else
+ {
+ return 0x00;
+ }
+ }
+ }
+ return 0xff;
+ case 0x06: /* Trakball CX-22 */
+ return ioport("BUTTONS_L")->read() << 4;
+ default:
+ return 0xff;
+ }
+ break;
+ case 5: /* Right controller port PIN 6 */
+ switch ( ioport("CONTROLLERS")->read() % CATEGORY_SELECT )
+ {
+ case 0x00: /* Joystick */
+ case 0x05: /* Joystick w/Boostergrip */
+ return ioport("BUTTONS_R")->read();
+ case 0x01: /* Paddle */
+ return 0xff;
+ case 0x02: /* Driving */
+ return ioport("BUTTONS_R")->read() << 3;
+ case 0x03: /* Keypad */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( ! ( ( m_keypad_right_column >> i ) & 0x01 ) )
+ {
+ if ( ( ioport("KEYPAD_R")->read() >> 3*i ) & 0x04 )
+ {
+ return 0xff;
+ }
+ else
+ {
+ return 0x00;
+ }
+ }
+ }
+ return 0xff;
+ case 0x06: /* Trakball CX-22 */
+ return ioport("BUTTONS_R")->read() << 4;
+ default:
+ return 0xff;
+ }
+ }
+ return TIA_INPUT_PORT_ALWAYS_OFF;
+}
+
+/* There are a few games that do an LDA ($80-$FF),Y instruction.
+ The contents off the databus then depend on whatever was read
+ from the RAM. To do this really properly the 6502 core would
+ need to keep track of the last databus contents so we can query
+ that. For now this is a quick hack to determine that value anyway.
+ Examples:
+ Q-Bert's Qubes (NTSC,F6) at 0x1594
+ Berzerk at 0xF093.
+*/
+READ8_MEMBER(a2600_state::a2600_get_databus_contents)
+{
+ UINT16 last_address, prev_address;
+ UINT8 last_byte, prev_byte;
+
+ last_address = cpu_get_pc(machine().device("maincpu")) - 1;
+ if ( ! ( last_address & 0x1080 ) )
+ {
+ return offset;
+ }
+ last_byte = space.read_byte(last_address );
+ if ( last_byte < 0x80 || last_byte == 0xFF )
+ {
+ return last_byte;
+ }
+ prev_address = last_address - 1;
+ if ( ! ( prev_address & 0x1080 ) )
+ {
+ return last_byte;
+ }
+ prev_byte = space.read_byte(prev_address );
+ if ( prev_byte == 0xB1 )
+ { /* LDA (XX),Y */
+ return space.read_byte(last_byte + 1 );
+ }
+ return last_byte;
+}
+
+#if 0
+static const rectangle visarea[4] = {
+ { 26, 26 + 160 + 16, 24, 24 + 192 + 31 }, /* 262 */
+ { 26, 26 + 160 + 16, 32, 32 + 228 + 31 }, /* 312 */
+ { 26, 26 + 160 + 16, 45, 45 + 240 + 31 }, /* 328 */
+ { 26, 26 + 160 + 16, 48, 48 + 240 + 31 } /* 342 */
+};
+#endif
+
+WRITE16_MEMBER(a2600_state::a2600_tia_vsync_callback)
+{
+ int i;
+
+ for ( i = 0; i < ARRAY_LENGTH(supported_screen_heights); i++ )
+ {
+ if ( data >= supported_screen_heights[i] - 3 && data <= supported_screen_heights[i] + 3 )
+ {
+ if ( supported_screen_heights[i] != m_current_screen_height )
+ {
+ m_current_screen_height = supported_screen_heights[i];
+// machine.primary_screen->configure(228, m_current_screen_height, &visarea[i], HZ_TO_ATTOSECONDS( MASTER_CLOCK_NTSC ) * 228 * m_current_screen_height );
+ }
+ }
+ }
+}
+
+WRITE16_MEMBER(a2600_state::a2600_tia_vsync_callback_pal)
+{
+ int i;
+
+ for ( i = 0; i < ARRAY_LENGTH(supported_screen_heights); i++ )
+ {
+ if ( data >= supported_screen_heights[i] - 3 && data <= supported_screen_heights[i] + 3 )
+ {
+ if ( supported_screen_heights[i] != m_current_screen_height )
+ {
+ m_current_screen_height = supported_screen_heights[i];
+// machine.primary_screen->configure(228, m_current_screen_height, &visarea[i], HZ_TO_ATTOSECONDS( MASTER_CLOCK_PAL ) * 228 * m_current_screen_height );
+ }
+ }
+ }
+}
+
+static const tia_interface a2600_tia_interface =
+{
+ DEVCB_DRIVER_MEMBER16(a2600_state, a2600_read_input_port),
+ DEVCB_DRIVER_MEMBER(a2600_state, a2600_get_databus_contents),
+ DEVCB_DRIVER_MEMBER16(a2600_state, a2600_tia_vsync_callback)
+};
+
+static const tia_interface a2600_tia_interface_pal =
+{
+ DEVCB_DRIVER_MEMBER16(a2600_state, a2600_read_input_port),
+ DEVCB_DRIVER_MEMBER(a2600_state, a2600_get_databus_contents),
+ DEVCB_DRIVER_MEMBER16(a2600_state, a2600_tia_vsync_callback_pal)
+};
+
+
+static void common_init(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ screen_device *screen = machine.first_screen();
+ state->m_current_screen_height = screen->height();
+ state->m_extra_RAM = machine.memory().region_alloc("user2", 0x8600, 1, ENDIANNESS_LITTLE);
+ memset( state->m_riot_ram, 0x00, 0x80 );
+ state->m_current_reset_bank_counter = 0xFF;
+ state->m_dpc.oscillator = machine.scheduler().timer_alloc(FUNC(modeDPC_timer_callback));
+}
+
+static MACHINE_START( a2600 )
+{
+ common_init(machine);
+}
+
+static MACHINE_START( a2600p )
+{
+ common_init(machine);
+}
+
+#ifdef UNUSED_FUNCTIONS
+// try to detect 2600 controller setup. returns 32bits with left/right controller info
+static unsigned long detect_2600controllers(running_machine &machine)
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+#define JOYS 0x001
+#define PADD 0x002
+#define KEYP 0x004
+#define LGUN 0x008
+#define INDY 0x010
+#define BOOS 0x020
+#define KVID 0x040
+#define CMTE 0x080
+#define MLNK 0x100
+#define AMSE 0x200
+#define CX22 0x400
+#define CX80 0x800
+
+ unsigned int left,right;
+ int i,j,foundkeypad = 0;
+ UINT8 *cart;
+ static const unsigned char signatures[][5] = {
+ { 0x55, 0xa5, 0x3c, 0x29, 0}, // star raiders
+ { 0xf9, 0xff, 0xa5, 0x80, 1}, // sentinel
+ { 0x81, 0x02, 0xe8, 0x86, 1}, // shooting arcade
+ { 0x02, 0xa9, 0xec, 0x8d, 1}, // guntest4 tester
+ { 0x85, 0x2c, 0x85, 0xa7, 2}, // INDY 500
+ { 0xa1, 0x8d, 0x9d, 0x02, 2}, // omega race INDY
+ { 0x65, 0x72, 0x44, 0x43, 2}, // Sprintmaster INDY
+ { 0x89, 0x8a, 0x99, 0xaa, 3}, // omega race
+ { 0x9a, 0x8e, 0x81, 0x02, 4},
+ { 0xdd, 0x8d, 0x80, 0x02, 4},
+ { 0x85, 0x8e, 0x81, 0x02, 4},
+ { 0x8d, 0x81, 0x02, 0xe6, 4},
+ { 0xff, 0x8d, 0x81, 0x02, 4},
+ { 0xa9, 0x03, 0x8d, 0x81, 5},
+ { 0xa9, 0x73, 0x8d, 0x80, 6},
+ // { 0x82, 0x02, 0x85, 0x8f, 7}, // Mind Maze (really Mind Link??)
+ { 0xa9, 0x30, 0x8d, 0x80, 7}, // Bionic Breakthrough
+ { 0x02, 0x8e, 0x81, 0x02, 7}, // Telepathy
+ { 0x41, 0x6d, 0x69, 0x67, 9}, // Missile Command Amiga Mouse
+ { 0x43, 0x58, 0x2d, 0x32, 10}, // Missile Command CX22 TrackBall
+ { 0x43, 0x58, 0x2d, 0x38, 11}, // Missile Command CX80 TrackBall
+ { 0x4e, 0xa8, 0xa4, 0xa2, 12}, // Omega Race for Joystick ONLY
+ { 0xa6, 0xef, 0xb5, 0x38, 8} // Warlords.. paddles ONLY
+ };
+ // start with this.. if anyone finds a game that does NOT work with both controllers enabled
+ // it can be fixed here with a new signature (note that the Coleco Gemini has this setup also)
+ left = JOYS+PADD; right = JOYS+PADD;
+ // default for bad dumps and roms too large to have special controllers
+ if ((state->m_cart_size > 0x4000) || (state->m_cart_size & 0x7ff)) return (left << 16) + right;
+
+ cart = CART;
+ for (i = 0; i < state->m_cart_size - (sizeof signatures/sizeof signatures[0]); i++)
+ {
+ for (j = 0; j < (sizeof signatures/sizeof signatures[0]); j++)
+ {
+ if (!memcmp(&cart[i], &signatures[j],sizeof signatures[0] - 1))
+ {
+ int k = signatures[j][4];
+ if (k == 0) return (JOYS << 16) + KEYP;
+ if (k == 1) return (LGUN << 16);
+ if (k == 2) return (INDY << 16) + INDY;
+ if (k == 3) return (BOOS << 16) + BOOS;
+ if (k == 5) return (JOYS << 16) + KVID;
+ if (k == 6) return (CMTE << 16) + CMTE;
+ if (k == 7) return (MLNK << 16) + MLNK;
+ if (k == 8) return (PADD << 16) + PADD;
+ if (k == 9) return (AMSE << 16) + AMSE;
+ if (k == 10) return (CX22 << 16) + CX22;
+ if (k == 11) return (CX80 << 16) + CX80;
+ if (k == 12) return (JOYS << 16) + JOYS;
+ if (k == 4) foundkeypad = 1;
+ }
+ }
+ }
+ if (foundkeypad) return (KEYP << 16) + KEYP;
+ return (left << 16) + right;
+}
+
+static void set_category_value( running_machine &machine, const char* cat, const char *cat_selection )
+{
+ /* NPW 22-May-2008 - FIXME */
+#if 0
+ input_port_entry *cat_in = NULL;
+ input_port_entry *in;
+
+ for( in = machine.input_ports; in->type != IPT_END; in++ )
+ {
+ if ( in->type == IPT_CATEGORY_NAME && ! mame_stricmp( cat, input_port_name(in) ) )
+ {
+ cat_in = in;
+ }
+ if ( cat_in && in->type == IPT_CATEGORY_SETTING && ! mame_stricmp( cat_selection, input_port_name(in) ) )
+ {
+ cat_in->default_value = in->default_value;
+ return;
+ }
+ }
+#endif
+}
+
+static void set_controller( running_machine &machine, const char *controller, unsigned int selection )
+{
+ /* Defaulting to only joystick when joysstick and paddle are set for now... */
+ if ( selection == JOYS + PADD )
+ selection = JOYS;
+
+ switch( selection )
+ {
+ case JOYS: set_category_value( machine, controller, "Joystick" ); break;
+ case PADD: set_category_value( machine, controller, STR_PADDLES ); break;
+ case KEYP: set_category_value( machine, controller, STR_KEYPAD ); break;
+ case LGUN: set_category_value( machine, controller, STR_LIGHTGUN ); break;
+ case INDY: set_category_value( machine, controller, STR_DRIVING ); break;
+ case BOOS: set_category_value( machine, controller, STR_BOOSTERGRIP ); break;
+ case KVID: set_category_value( machine, controller, STR_KIDVID ); break;
+ case CMTE: break;
+ case MLNK: break;
+ case AMSE: set_category_value( machine, controller, STR_AMIGAMOUSE ); break;
+ case CX22: set_category_value( machine, controller, STR_CX22TRAKBALL ); break;
+ case CX80: set_category_value( machine, controller, STR_CX80TRAKBALL ); break;
+ }
+}
+#endif
+
+static MACHINE_RESET( a2600 )
+{
+ a2600_state *state = machine.driver_data<a2600_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int chip = 0xFF;
+ static const unsigned char snowwhite[] = { 0x10, 0xd0, 0xff, 0xff }; // Snow White Proto
+
+ state->m_current_reset_bank_counter++;
+
+#ifdef UNUSED_FUNCTIONS
+ /* auto-detect special controllers */
+ unsigned long controltemp;
+ controltemp = detect_2600controllers(machine);
+ set_controller( machine, STR_LEFT_CONTROLLER, controltemp >> 16 );
+ set_controller( machine, STR_RIGHT_CONTROLLER, controltemp & 0xFFFF );
+#endif
+
+ /* auto-detect bank mode */
+ if (state->m_banking_mode == 0xff) if (detect_modeDC(machine)) state->m_banking_mode = modeDC;
+ if (state->m_banking_mode == 0xff) if (detect_mode3E(machine)) state->m_banking_mode = mode3E;
+ if (state->m_banking_mode == 0xff) if (detect_modeFE(machine)) state->m_banking_mode = modeFE;
+ if (state->m_banking_mode == 0xff) if (detect_modeSS(machine)) state->m_banking_mode = modeSS;
+ if (state->m_banking_mode == 0xff) if (detect_modeE0(machine)) state->m_banking_mode = modeE0;
+ if (state->m_banking_mode == 0xff) if (detect_modeCV(machine)) state->m_banking_mode = modeCV;
+ if (state->m_banking_mode == 0xff) if (detect_modeFV(machine)) state->m_banking_mode = modeFV;
+ if (state->m_banking_mode == 0xff) if (detect_modeJVP(machine)) state->m_banking_mode = modeJVP;
+ if (state->m_banking_mode == 0xff) if (detect_modeUA(machine)) state->m_banking_mode = modeUA;
+ if (state->m_banking_mode == 0xff) if (detect_8K_mode3F(machine)) state->m_banking_mode = mode3F;
+ if (state->m_banking_mode == 0xff) if (detect_32K_mode3F(machine)) state->m_banking_mode = mode3F;
+ if (state->m_banking_mode == 0xff) if (detect_modeE7(machine)) state->m_banking_mode = modeE7;
+
+ if (state->m_banking_mode == 0xff)
+ {
+ switch (state->m_cart_size)
+ {
+ case 0x800:
+ state->m_banking_mode = mode2K;
+ break;
+ case 0x1000:
+ state->m_banking_mode = mode4K;
+ break;
+ case 0x2000:
+ state->m_banking_mode = modeF8;
+ break;
+ case 0x28FF:
+ case 0x2900:
+ state->m_banking_mode = modeDPC;
+ break;
+ case 0x3000:
+ state->m_banking_mode = modeFA;
+ break;
+ case 0x4000:
+ state->m_banking_mode = modeF6;
+ break;
+ case 0x8000:
+ state->m_banking_mode = modeF4;
+ break;
+ case 0x10000:
+ state->m_banking_mode = mode32in1;
+ break;
+ case 0x80000:
+ state->m_banking_mode = mode3F;
+ break;
+ }
+ }
+
+ /* auto-detect super chip */
+
+ chip = 0;
+
+ if (state->m_cart_size == 0x2000 || state->m_cart_size == 0x4000 || state->m_cart_size == 0x8000)
+ {
+ chip = detect_super_chip(machine);
+ }
+
+ /* Super chip games:
+ dig dig, crystal castles, millipede, stargate, defender ii, jr. Pac Man,
+ desert falcon, dark chambers, super football, sprintmaster, fatal run,
+ off the wall, shooting arcade, secret quest, radar lock, save mary, klax
+ */
+
+ /* set up ROM banks */
+
+ switch (state->m_banking_mode)
+ {
+ case mode2K:
+ install_banks(machine, 2, 0x0000);
+ break;
+
+ case mode4K:
+ install_banks(machine, 1, 0x0000);
+ break;
+
+ case modeF8:
+ if (!memcmp(&CART[0x1ffc],snowwhite,sizeof(snowwhite)))
+ {
+ install_banks(machine, 1, 0x0000);
+ }
+ else
+ {
+ install_banks(machine, 1, 0x1000);
+ }
+ break;
+
+ case modeFA:
+ install_banks(machine, 1, 0x2000);
+ break;
+
+ case modeF6:
+ install_banks(machine, 1, 0x0000);
+ break;
+
+ case modeF4:
+ install_banks(machine, 1, 0x7000);
+ break;
+
+ case modeFE:
+ install_banks(machine, 1, 0x0000);
+ break;
+
+ case modeE0:
+ install_banks(machine, 4, 0x1c00);
+ break;
+
+ case mode3F:
+ install_banks(machine, 2, state->m_cart_size - 0x800);
+ state->m_number_banks = state->m_cart_size / 0x800;
+ break;
+
+ case modeUA:
+ install_banks(machine, 1, 0x1000);
+ break;
+
+ case modeE7:
+ install_banks(machine, 2, 0x3800);
+ break;
+
+ case modeDC:
+ install_banks(machine, 1, 0x1000 * state->m_current_bank);
+ break;
+
+ case modeCV:
+ install_banks(machine, 2, 0x0000);
+ break;
+
+ case mode3E:
+ install_banks(machine, 2, state->m_cart_size - 0x800);
+ state->m_number_banks = state->m_cart_size / 0x800;
+ state->m_mode3E_ram_enabled = 0;
+ break;
+
+ case modeSS:
+ install_banks(machine, 2, 0x0000);
+ break;
+
+ case modeFV:
+ install_banks(machine, 1, 0x0000);
+ state->m_current_bank = 0;
+ break;
+
+ case modeDPC:
+ install_banks(machine, 1, 0x0000);
+ break;
+
+ case mode32in1:
+ install_banks(machine, 2, 0x0000);
+ state->m_current_reset_bank_counter = state->m_current_reset_bank_counter & 0x1F;
+ break;
+
+ case modeJVP:
+ state->m_current_reset_bank_counter = state->m_current_reset_bank_counter & 1;
+ if ( state->m_cart_size == 0x2000 )
+ state->m_current_reset_bank_counter = 0;
+ state->m_current_bank = state->m_current_reset_bank_counter * 2;
+ install_banks(machine, 1, 0x1000 * state->m_current_bank);
+ break;
+ }
+
+ /* set up bank counter */
+
+ if (state->m_banking_mode == modeDC)
+ {
+ space->install_read_handler(0x1fec, 0x1fec, read8_delegate(FUNC(a2600_state::current_bank_r),state));
+ }
+
+ /* set up bank switch registers */
+
+ switch (state->m_banking_mode)
+ {
+ case modeF8:
+ space->install_write_handler(0x1ff8, 0x1ff9, write8_delegate(FUNC(a2600_state::modeF8_switch_w),state));
+ space->install_read_handler(0x1ff8, 0x1ff9, read8_delegate(FUNC(a2600_state::modeF8_switch_r),state));
+ break;
+
+ case modeFA:
+ space->install_write_handler(0x1ff8, 0x1ffa, write8_delegate(FUNC(a2600_state::modeFA_switch_w),state));
+ space->install_read_handler(0x1ff8, 0x1ffa, read8_delegate(FUNC(a2600_state::modeFA_switch_r),state));
+ break;
+
+ case modeF6:
+ space->install_write_handler(0x1ff6, 0x1ff9, write8_delegate(FUNC(a2600_state::modeF6_switch_w),state));
+ space->install_read_handler(0x1ff6, 0x1ff9, read8_delegate(FUNC(a2600_state::modeF6_switch_r),state));
+ space->set_direct_update_handler(direct_update_delegate(FUNC(a2600_state::modeF6_opbase), state));
+ break;
+
+ case modeF4:
+ space->install_write_handler(0x1ff4, 0x1ffb, write8_delegate(FUNC(a2600_state::modeF4_switch_w),state));
+ space->install_read_handler(0x1ff4, 0x1ffb, read8_delegate(FUNC(a2600_state::modeF4_switch_r),state));
+ break;
+
+ case modeE0:
+ space->install_write_handler(0x1fe0, 0x1ff8, write8_delegate(FUNC(a2600_state::modeE0_switch_w),state));
+ space->install_read_handler(0x1fe0, 0x1ff8, read8_delegate(FUNC(a2600_state::modeE0_switch_r),state));
+ break;
+
+ case mode3F:
+ space->install_write_handler(0x00, 0x3f, write8_delegate(FUNC(a2600_state::mode3F_switch_w),state));
+ break;
+
+ case modeUA:
+ space->install_write_handler(0x200, 0x27f, write8_delegate(FUNC(a2600_state::modeUA_switch_w),state));
+ space->install_read_handler(0x200, 0x27f, read8_delegate(FUNC(a2600_state::modeUA_switch_r),state));
+ break;
+
+ case modeE7:
+ space->install_write_handler(0x1fe0, 0x1fe7, write8_delegate(FUNC(a2600_state::modeE7_switch_w),state));
+ space->install_read_handler(0x1fe0, 0x1fe7, read8_delegate(FUNC(a2600_state::modeE7_switch_r),state));
+ space->install_write_handler(0x1fe8, 0x1feb, write8_delegate(FUNC(a2600_state::modeE7_RAM_switch_w),state));
+ space->install_read_handler(0x1fe8, 0x1feb, read8_delegate(FUNC(a2600_state::modeE7_RAM_switch_r),state));
+ space->install_readwrite_bank(0x1800, 0x18ff, "bank9");
+ state->membank("bank9")->set_base(state->m_extra_RAM->base() + 4 * 256 );
+ break;
+
+ case modeDC:
+ space->install_write_handler(0x1ff0, 0x1ff0, write8_delegate(FUNC(a2600_state::modeDC_switch_w),state));
+ space->install_read_handler(0x1ff0, 0x1ff0, read8_delegate(FUNC(a2600_state::modeDC_switch_r),state));
+ break;
+
+ case modeFE:
+ space->install_write_handler(0x01fe, 0x01fe, write8_delegate(FUNC(a2600_state::modeFE_switch_w),state));
+ space->install_read_handler(0x01fe, 0x01fe, read8_delegate(FUNC(a2600_state::modeFE_switch_r),state));
+ break;
+
+ case mode3E:
+ space->install_write_handler(0x3e, 0x3e, write8_delegate(FUNC(a2600_state::mode3E_RAM_switch_w),state));
+ space->install_write_handler(0x3f, 0x3f, write8_delegate(FUNC(a2600_state::mode3E_switch_w),state));
+ space->install_write_handler(0x1400, 0x15ff, write8_delegate(FUNC(a2600_state::mode3E_RAM_w),state));
+ break;
+
+ case modeSS:
+ space->install_read_handler(0x1000, 0x1fff, read8_delegate(FUNC(a2600_state::modeSS_r),state));
+ state->m_bank_base[1] = state->m_extra_RAM->base() + 2 * 0x800;
+ state->m_bank_base[2] = CART;
+ state->membank("bank1")->set_base(state->m_bank_base[1] );
+ state->membank("bank2")->set_base(state->m_bank_base[2] );
+ state->m_modeSS_write_enabled = 0;
+ state->m_modeSS_byte_started = 0;
+ space->set_direct_update_handler(direct_update_delegate(FUNC(a2600_state::modeSS_opbase), state));
+ /* The Supercharger has no motor control so just enable it */
+ machine.device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MOTOR_DISABLED );
+ break;
+
+ case modeFV:
+ space->install_write_handler(0x1fd0, 0x1fd0, write8_delegate(FUNC(a2600_state::modeFV_switch_w),state));
+ space->install_read_handler(0x1fd0, 0x1fd0, read8_delegate(FUNC(a2600_state::modeFV_switch_r),state));
+ break;
+
+ case modeDPC:
+ space->install_read_handler(0x1000, 0x103f, read8_delegate(FUNC(a2600_state::modeDPC_r),state));
+ space->install_write_handler(0x1040, 0x107f, write8_delegate(FUNC(a2600_state::modeDPC_w),state));
+ space->install_write_handler(0x1ff8, 0x1ff9, write8_delegate(FUNC(a2600_state::modeF8_switch_w),state));
+ space->install_read_handler(0x1ff8, 0x1ff9, read8_delegate(FUNC(a2600_state::modeF8_switch_r),state));
+ space->set_direct_update_handler(direct_update_delegate(FUNC(a2600_state::modeDPC_opbase_handler), state));
+ {
+ int data_fetcher;
+ for( data_fetcher = 0; data_fetcher < 8; data_fetcher++ )
+ {
+ state->m_dpc.df[data_fetcher].osc_clk = 0;
+ state->m_dpc.df[data_fetcher].flag = 0;
+ state->m_dpc.df[data_fetcher].music_mode = 0;
+ }
+ }
+ state->m_dpc.oscillator->adjust(attotime::from_hz(42000), 0, attotime::from_hz(42000));
+ break;
+
+ case mode32in1:
+ state->membank("bank1")->set_base(CART + state->m_current_reset_bank_counter * 0x800 );
+ state->membank("bank2")->set_base(CART + state->m_current_reset_bank_counter * 0x800 );
+ break;
+
+ case modeJVP:
+ space->install_read_handler(0x0FA0, 0x0FC0, read8_delegate(FUNC(a2600_state::modeJVP_switch_r),state));
+ space->install_write_handler(0x0FA0, 0x0FC0, write8_delegate(FUNC(a2600_state::modeJVP_switch_w),state));
+ break;
+ }
+
+ /* set up extra RAM */
+
+ if (state->m_banking_mode == modeFA)
+ {
+ space->install_write_bank(0x1000, 0x10ff, "bank9");
+ space->install_read_bank(0x1100, 0x11ff, "bank9");
+
+ state->membank("bank9")->set_base(state->m_extra_RAM->base());
+ }
+
+ if (state->m_banking_mode == modeCV)
+ {
+ space->install_write_bank(0x1400, 0x17ff, "bank9");
+ space->install_read_bank(0x1000, 0x13ff, "bank9");
+
+ state->membank("bank9")->set_base(state->m_extra_RAM->base());
+ }
+
+ if (chip)
+ {
+ space->install_write_bank(0x1000, 0x107f, "bank9");
+ space->install_read_bank(0x1080, 0x10ff, "bank9");
+
+ state->membank("bank9")->set_base(state->m_extra_RAM->base());
+ }
+
+ /* Banks may have changed, reset the cpu so it uses the correct reset vector */
+ machine.device("maincpu")->reset();
+}
+
+
+static INPUT_PORTS_START( a2600 )
+
+ PORT_START("PADDLE1")
+ PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) PORT_PLAYER(1) PORT_REVERSE PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x10)
+ PORT_START("PADDLE3")
+ PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) PORT_PLAYER(3) PORT_REVERSE PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x10)
+ PORT_START("PADDLE2")
+ PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) PORT_PLAYER(2) PORT_REVERSE PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x01)
+ PORT_START("PADDLE4")
+ PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) PORT_PLAYER(4) PORT_REVERSE PORT_CODE_DEC(KEYCODE_4_PAD) PORT_CODE_INC(KEYCODE_6_PAD) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x01)
+
+ PORT_START("BUTTONS_L") /* left port button(s) */
+// PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x50)
+// PORT_BIT ( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x50)
+ PORT_BIT ( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x50)
+ PORT_BIT ( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x20)
+ PORT_BIT ( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+ PORT_BIT ( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+ PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+
+ PORT_START("BUTTONS_R") /* right port button(s) */
+// PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x05)
+// PORT_BIT ( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x05)
+ PORT_BIT ( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x05)
+ PORT_BIT ( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x02)
+ PORT_BIT ( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+ PORT_BIT ( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+ PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+
+ PORT_START("SWA_JOY") /* SWCHA joystick */
+ PORT_BIT ( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+ PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+ PORT_BIT ( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+ PORT_BIT ( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x00)
+ PORT_BIT ( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+ PORT_BIT ( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+ PORT_BIT ( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+ PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x00)
+
+ PORT_START("SWA_PAD") /* SWCHA paddles */
+ PORT_BIT ( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT ( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x01)
+ PORT_BIT ( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x01)
+ PORT_BIT ( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT ( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT ( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x10)
+ PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x10)
+
+ PORT_START("SWB") /* SWCHB */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset Game") PORT_CODE(KEYCODE_2)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("Select Game")
+ PORT_BIT ( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_DIPNAME( 0x08, 0x08, "TV Type" ) PORT_CODE(KEYCODE_C) PORT_TOGGLE
+ PORT_DIPSETTING( 0x08, "Color" )
+ PORT_DIPSETTING( 0x00, "B&W" )
+ PORT_BIT ( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT ( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_DIPNAME( 0x40, 0x00, "Left Diff. Switch" ) PORT_CODE(KEYCODE_3) PORT_TOGGLE
+ PORT_DIPSETTING( 0x40, "A" )
+ PORT_DIPSETTING( 0x00, "B" )
+ PORT_DIPNAME( 0x80, 0x00, "Right Diff. Switch" ) PORT_CODE(KEYCODE_4) PORT_TOGGLE
+ PORT_DIPSETTING( 0x80, "A" )
+ PORT_DIPSETTING( 0x00, "B" )
+
+ PORT_START("CONTROLLERS")
+ PORT_CONFNAME( 0xf0, 0x00, STR_LEFT_CONTROLLER )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x10, STR_PADDLES )
+ PORT_CONFSETTING( 0x20, STR_DRIVING )
+ PORT_CONFSETTING( 0x30, STR_KEYPAD )
+ //PORT_CONFSETTING( 0x40, STR_LIGHTGUN )
+ PORT_CONFSETTING( 0x50, STR_BOOSTERGRIP )
+ //PORT_CONFSETTING( 0x60, STR_CX22TRAKBALL )
+ //PORT_CONFSETTING( 0x70, STR_CX80TRAKBALL )
+ //PORT_CONFSETTING( 0x80, "CX-80 Trak-Ball (JS Mode)" )
+ //PORT_CONFSETTING( 0x90, STR_AMIGAMOUSE )
+ PORT_CONFNAME( 0x0f, 0x00, STR_RIGHT_CONTROLLER )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x01, STR_PADDLES )
+ PORT_CONFSETTING( 0x02, STR_DRIVING )
+ PORT_CONFSETTING( 0x03, STR_KEYPAD )
+ //PORT_CONFSETTING( 0x04, STR_LIGHTGUN )
+ PORT_CONFSETTING( 0x05, STR_BOOSTERGRIP )
+ //PORT_CONFSETTING( 0x06, STR_CX22TRAKBALL )
+ //PORT_CONFSETTING( 0x07, STR_CX80TRAKBALL )
+ //PORT_CONFSETTING( 0x08, "CX-80 Trak-Ball (JS Mode)" )
+ //PORT_CONFSETTING( 0x09, STR_AMIGAMOUSE )
+ PORT_CONFSETTING( 0x0a, STR_KIDVID )
+ //PORT_CONFSETTING( 0x0b, "Save Key" )
+
+ PORT_START("KEYPAD_L") /* left keypad */
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 1") PORT_CODE(KEYCODE_7_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 2") PORT_CODE(KEYCODE_8_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 3") PORT_CODE(KEYCODE_9_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 4") PORT_CODE(KEYCODE_4_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 5") PORT_CODE(KEYCODE_5_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 6") PORT_CODE(KEYCODE_6_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 7") PORT_CODE(KEYCODE_1_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 8") PORT_CODE(KEYCODE_2_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 9") PORT_CODE(KEYCODE_3_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left *") PORT_CODE(KEYCODE_0_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left 0") PORT_CODE(KEYCODE_DEL_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("left #") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x30)
+
+ PORT_START("KEYPAD_R") /* right keypad */
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 1") PORT_CODE(KEYCODE_5) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 2") PORT_CODE(KEYCODE_6) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 3") PORT_CODE(KEYCODE_7) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 4") PORT_CODE(KEYCODE_R) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 5") PORT_CODE(KEYCODE_T) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 6") PORT_CODE(KEYCODE_Y) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 7") PORT_CODE(KEYCODE_F) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 8") PORT_CODE(KEYCODE_G) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 9") PORT_CODE(KEYCODE_H) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right *") PORT_CODE(KEYCODE_V) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right 0") PORT_CODE(KEYCODE_B) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("right #") PORT_CODE(KEYCODE_N) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x03)
+
+ PORT_START("WHEEL_L") /* left driving controller */
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x20)
+
+ PORT_START("WHEEL_R") /* right driving controller */
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x02)
+
+ PORT_START("GUNX_L") /* left light gun X */
+// PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR( X, 1.0, 0.0, 0 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x40)
+
+ PORT_START("GUNY_L") /* left light gun Y */
+// PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR( Y, 1.0, 0.0, 0 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x40)
+
+ PORT_START("GUNX_R") /* right light gun X */
+// PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR( X, 1.0, 0.0, 0 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x04)
+
+ PORT_START("GUNY_R") /* right light gun Y */
+// PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR( Y, 1.0, 0.0, 0 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x04)
+
+ PORT_START("TRAKX_L") /* left trak ball X */
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x50)
+
+ PORT_START("TRAKY_L") /* left trak ball Y */
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) PORT_PLAYER(1) PORT_CONDITION("CONTROLLERS", 0xf0, EQUALS, 0x50)
+
+ PORT_START("TRAKX_R") /* right trak ball X */
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x05)
+
+ PORT_START("TRAKY_R") /* right trak ball Y */
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) PORT_PLAYER(2) PORT_CONDITION("CONTROLLERS", 0x0f, EQUALS, 0x05)
+
+INPUT_PORTS_END
+
+
+static const cassette_interface a2600_cassette_interface =
+{
+ a26_cassette_formats,
+ NULL,
+ (cassette_state)(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_ENABLED),
+ "a2600_cass",
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT(a2600_cartslot)
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_EXTENSION_LIST("bin,a26")
+ MCFG_CARTSLOT_MANDATORY
+ MCFG_CARTSLOT_START(a2600_cart)
+ MCFG_CARTSLOT_LOAD(a2600_cart)
+ MCFG_CARTSLOT_INTERFACE("a2600_cart")
+
+ /* software lists */
+ MCFG_SOFTWARE_LIST_ADD("cart_list","a2600")
+ MCFG_SOFTWARE_LIST_ADD("cass_list","a2600_cass")
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_START( a2600, a2600_state )
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", M6502, MASTER_CLOCK_NTSC / 3) /* actually M6507 */
+ MCFG_CPU_PROGRAM_MAP(a2600_mem)
+
+ MCFG_MACHINE_START(a2600)
+ MCFG_MACHINE_RESET(a2600)
+
+ /* video hardware */
+ MCFG_TIA_VIDEO_ADD("tia_video", a2600_tia_interface)
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS( MASTER_CLOCK_NTSC, 228, 26, 26 + 160 + 16, 262, 24 , 24 + 192 + 31 )
+ MCFG_SCREEN_UPDATE_DEVICE("tia_video", tia_video_device, screen_update)
+
+ MCFG_PALETTE_LENGTH( TIA_PALETTE_LENGTH )
+ MCFG_PALETTE_INIT(tia_NTSC)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("tia", TIA, MASTER_CLOCK_NTSC/114)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90)
+ MCFG_SOUND_WAVE_ADD(WAVE_TAG, CASSETTE_TAG)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ /* devices */
+ MCFG_RIOT6532_ADD("riot", MASTER_CLOCK_NTSC / 3, r6532_interface)
+ MCFG_FRAGMENT_ADD(a2600_cartslot)
+ MCFG_SOFTWARE_LIST_FILTER("cart_list", "NTSC")
+ MCFG_CASSETTE_ADD( CASSETTE_TAG, a2600_cassette_interface )
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_START( a2600p, a2600_state )
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", M6502, MASTER_CLOCK_PAL / 3) /* actually M6507 */
+ MCFG_CPU_PROGRAM_MAP(a2600_mem)
+
+ MCFG_MACHINE_START(a2600p)
+ MCFG_MACHINE_RESET(a2600)
+
+ /* video hardware */
+ MCFG_TIA_VIDEO_ADD("tia_video", a2600_tia_interface_pal)
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS( MASTER_CLOCK_PAL, 228, 26, 26 + 160 + 16, 312, 32, 32 + 228 + 31 )
+ MCFG_SCREEN_UPDATE_DEVICE("tia_video", tia_video_device, screen_update)
+
+ MCFG_PALETTE_LENGTH( TIA_PALETTE_LENGTH )
+ MCFG_PALETTE_INIT(tia_PAL)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("tia", TIA, MASTER_CLOCK_PAL/114)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90)
+ MCFG_SOUND_WAVE_ADD(WAVE_TAG, CASSETTE_TAG)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ /* devices */
+ MCFG_RIOT6532_ADD("riot", MASTER_CLOCK_PAL / 3, r6532_interface)
+ MCFG_FRAGMENT_ADD(a2600_cartslot)
+ MCFG_SOFTWARE_LIST_FILTER("cart_list", "PAL")
+ MCFG_CASSETTE_ADD( CASSETTE_TAG, a2600_cassette_interface )
+MACHINE_CONFIG_END
+
+
+ROM_START( a2600 )
+ ROM_REGION( 0x2000, "maincpu", 0 )
+ ROM_FILL( 0x0000, 0x2000, 0xFF )
+ ROM_REGION( 0x80000, "user1", 0 )
+ ROM_FILL( 0x00000, 0x80000, 0xFF )
+ROM_END
+
+#define rom_a2600p rom_a2600
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
+CONS( 1977, a2600, 0, 0, a2600, a2600, driver_device, 0, "Atari", "Atari 2600 (NTSC)" , 0)
+CONS( 1978, a2600p, a2600, 0, a2600p, a2600, driver_device, 0, "Atari", "Atari 2600 (PAL)", 0)