summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/barcrest/mpu4.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/barcrest/mpu4.cpp')
-rw-r--r--src/mame/barcrest/mpu4.cpp2432
1 files changed, 2432 insertions, 0 deletions
diff --git a/src/mame/barcrest/mpu4.cpp b/src/mame/barcrest/mpu4.cpp
new file mode 100644
index 00000000000..283975abe40
--- /dev/null
+++ b/src/mame/barcrest/mpu4.cpp
@@ -0,0 +1,2432 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood, James Wallace
+// thanks-to:Chris Wren, Tony Friery, MFME
+
+/*
+ mpu4.cpp - MPU4 hardware emulation
+
+ this file contains emulation of the hardware only
+
+*/
+
+
+/*
+
+--- Board Setup ---
+
+The MPU4 BOARD is the driver board, originally designed to run Fruit Machines made by the Barcrest Group, but later
+licensed to other firms as a general purpose unit (even some old Photo-Me booths used the unit).
+
+This board uses a ~1.72 Mhz 6809B CPU, and a number of PIA6821 chips for multiplexing inputs and the like.
+
+To some extent, the hardware feels like a revision of the MPU3 design, integrating into the base unit features that were
+previously added through expansion ports. However, there is no backwards compatibility, and the entire memory map has been
+reworked.
+
+Like MPU3, a 6840PTM is used for internal timing, and other miscellaneous control functions, including as a crude analogue sound device
+(a square wave from the PTM being fed into a 1-bit DAC circuit as the alarm sound generator). However, the main sound functionality is provided by
+dedicated hardware (an AY8913).
+
+A MPU4 GAME CARD (cartridge) plugs into the MPU4 board containing the game, and a protection PAL (the 'characteriser').
+This PAL, as well as protecting the games, also controlled some of the lamp address matrix for many games, and acted as
+an anti-tampering device which helped to prevent the hacking of certain titles in a manner which broke UK gaming laws.
+
+Like MPU3, over the years developers have added more capabilities through the spare inputs and outputs provided. These provided
+support for more reels, lamps and LEDs through daughtercards.
+Several solutions were released depending on the manufacturer of the machine, all are emulated here.
+
+In later revisions of the main board (MOD4 onwards), the AY8913 was removed entirely, as two official alternatives for sound had been produced.
+In one, a YM2413 is built into the gameboard, and in the other an OKI MSM6376 is interfaced with a PIA and PTM to allow sophisticated
+sampled sound.
+
+The lamping and input handling side of the machine rely entirely on a column by column 'strobe' system, with lights and LEDs selected in turn.
+In the inputs there are two orange connectors (sampled every 8ms) and two black ones (sampled every 16ms), giving 32 multiplexed inputs.
+
+In addition there are two auxiliary ports that can be accessed separately to these and are bidirectional
+
+--- Preliminary MPU4 Memorymap ---
+
+(NV) indicates an item which is not present on the video version, which has a Comms card instead.
+
+ hex |r/w| D D D D D D D D |
+ location | | 7 6 5 4 3 2 1 0 | function
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0000-07FF |R/W| D D D D D D D D | 2k RAM
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0800 |R/W| | Characteriser (Security PAL) (NV)
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0850 ? | W | ??????????????? | page latch (NV)
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0880 |R/W| D D D D D D D D | PIA6821 on soundboard (Oki MSM6376 clocked by 6840 (8C0))
+ | | | port A = ??
+ | | | port B (882)
+ | | | b7 = NAR
+ | | | b6 = 0 if OKI busy, 1 if OKI ready
+ | | | b5 = volume control clock
+ | | | b4 = volume control direction (0= up, 1 = down)
+ | | | b3 = ??
+ | | | b2 = ??
+ | | | b1 = 2ch
+ | | | b0 = ST
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 08C0 | | | MC6840 on sound board
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0900- |R/W| D D D D D D D D | MC6840 PTM IC2
+
+
+ Clock1 <--------------------------------------
+ | |
+ V |
+ Output1 ---> Clock2 |
+ |
+ Output2 --+-> Clock3 |
+ | |
+ | Output3 ---> 'to audio amp' (square wave)
+ |
+ +--------> CA1 IC3 (
+
+IRQ line connected to CPU
+
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0A00-0A03 |R/W| D D D D D D D D | PIA6821 IC3 port A Lamp Drives 1,2,3,4,6,7,8,9 (sic)(IC14)
+ | | |
+ | | | CA1 <= output2 from PTM6840 (IC2)
+ | | | CA2 => alpha data
+ | | |
+ | | | port B Lamp Drives 10,11,12,13,14,15,16,17 (sic)(IC13)
+ | | |
+ | | | CB2 => alpha reset (clock on Dutch systems)
+ | | |
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0B00-0B03 |R/W| D D D D D D D D | PIA6821 IC4 port A = data for 7seg leds (pins 10 - 17, via IC32)
+ | | |
+ | | | CA1 INPUT, 50 Hz input (used to generate IRQ)
+ | | | CA2 OUTPUT, connected to pin2 74LS138 CE for multiplexer
+ | | | (B on LED strobe multiplexer)
+ | | | IRQA connected to IRQ of CPU
+ | | | port B
+ | | | PB7 = INPUT, serial port Receive data (Rx)
+ | | | PB6 = INPUT, reel A sensor
+ | | | PB5 = INPUT, reel B sensor
+ | | | PB4 = INPUT, reel C sensor
+ | | | PB3 = INPUT, reel D sensor
+ | | | PB2 = INPUT, Connected to CA1 (50Hz signal)
+ | | | PB1 = INPUT, undercurrent sense
+ | | | PB0 = INPUT, overcurrent sense
+ | | |
+ | | | CB1 INPUT, used to generate IRQ on edge of serial input line
+ | | | CB2 OUTPUT, enable signal for reel optics
+ | | | IRQB connected to IRQ of CPU
+ | | |
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0C00-0C03 |R/W| D D D D D D D D | PIA6821 IC5 port A
+ | | |
+ | | | PA0-PA7, INPUT AUX1 connector
+ | | |
+ | | | CA2 OUTPUT, serial port Transmit line (Tx)
+ | | | CA1 not connected
+ | | | IRQA connected to IRQ of CPU
+ | | |
+ | | | port B
+ | | |
+ | | | PB0-PB7 INPUT, AUX2 connector
+ | | |
+ | | | CB1 INPUT, connected to PB7 (Aux2 connector pin 4)
+ | | |
+ | | | CB2 OUTPUT, AY8913 chip select line
+ | | | IRQB connected to IRQ of CPU
+ | | |
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0D00-0D03 |R/W| D D D D D D D D | PIA6821 IC6
+ | | |
+ | | | port A
+ | | |
+ | | | PA0 - PA7 (INPUT/OUTPUT) data port AY8913 sound chip
+ | | |
+ | | | CA1 INPUT, not connected
+ | | | CA2 OUTPUT, BC1 pin AY8913 sound chip
+ | | | IRQA , connected to IRQ CPU
+ | | |
+ | | | port B
+ | | |
+ | | | PB0-PB3 OUTPUT, reel A
+ | | | PB4-PB7 OUTPUT, reel B
+ | | |
+ | | | CB1 INPUT, not connected
+ | | | CB2 OUTPUT, B01R pin AY8913 sound chip
+ | | | IRQB , connected to IRQ CPU
+ | | |
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0E00-0E03 |R/W| D D D D D D D D | PIA6821 IC7
+ | | |
+ | | | port A
+ | | |
+ | | | PA0-PA3 OUTPUT, reel C
+ | | | PA4-PA7 OUTPUT, reel D
+ | | | CA1 INPUT, not connected
+ | | | CA2 OUTPUT, A on LED strobe multiplexer
+ | | | IRQA , connected to IRQ CPU
+ | | |
+ | | | port B
+ | | |
+ | | | PB0-PB6 OUTPUT mech meter 1-7 or reel E + F
+ | | | PB7 Voltage drop sensor
+ | | | CB1 INPUT, not connected
+ | | | CB2 OUTPUT,mech meter 8
+ | | | IRQB , connected to IRQ CPU
+ | | |
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 0F00-0F03 |R/W| D D D D D D D D | PIA6821 IC8
+ | | |
+ | | | port A
+ | | |
+ | | | PA0-PA7 INPUT multiplexed inputs data
+ | | |
+ | | | CA1 INPUT, not connected
+ | | | CA2 OUTPUT, C on LED strobe multiplexer
+ | | | IRQA connected to IRQ CPU
+ | | |
+ | | | port B
+ | | |
+ | | | PB0-PB7 OUTPUT triacs outputs connector PL6
+ | | | used for slides / hoppers
+ | | |
+ | | | CB1 INPUT, not connected
+ | | | CB2 OUTPUT, pin1 alpha display PL7 (clock signal)
+ | | | IRQB connected to IRQ CPU
+ | | |
+-----------+---+-----------------+--------------------------------------------------------------------------
+ 1000-FFFF | R | D D D D D D D D | ROM (can be bank switched by 0x850 in 8 banks of 64 k ) (NV)
+-----------+---+-----------------+--------------------------------------------------------------------------
+
+Additional Notes:
+
+Games from around the era of Road Hog and Chase Invaders had sufficient additional space to store three sets of reel
+start/stop sounds.
+
+To change between them, follow these instructions:
+
+1) Load the game.
+2) Open the cashbox door and insert the refill key.
+3) Use Hi/Lo to adjust volume
+4) Use Hold 1/2/3 to choose between "Default", "Standard" and "Alternative" sound sets
+5) Use Cancel/collect to test the sounds.
+6) To return to the game, remove the refill key and close the door
+
+***********************************************************************************************************/
+#include "emu.h"
+#include "mpu4.h"
+
+#include "awpvid.h" //Fruit Machines Only
+
+#include "machine/rescap.h"
+#include "speaker.h"
+
+#include "mpu4.lh"
+#include "mpu4ext.lh"
+
+#define LOG_IC3 (1U << 1)
+#define LOG_IC8 (1U << 2)
+
+#ifdef MAME_DEBUG
+#define VERBOSE (LOG_GENERAL | LOG_IC3 | LOG_IC8)
+#else
+#define VERBOSE (0)
+#endif
+#include "logmacro.h"
+
+#include <cmath>
+
+
+/*
+LED Segments related to pins (5 is not connected):
+Unlike the controllers emulated in the layout code, each
+segment of an MPU4 LED can be set individually, even
+being used as individual lamps. However, we can get away
+with settings like this in the majority of cases.
+ _9_
+ | |
+ 3 8
+ | |
+ _2_
+ | |
+ 4 7
+ |_ _|
+ 6 1
+
+8 display enables (pins 10 - 17)
+*/
+
+void mpu4_state::lamp_extend_small(uint8_t data)
+{
+ uint8_t lamp_ext_data, column;
+ column = data & 0x07;
+
+ lamp_ext_data = 0x1f - ((data & 0xf8) >> 3);//remove the mux lines from the data
+
+ if (m_lamp_strobe_ext_persistence == 0)
+ {
+ //One write to reset the drive lines, one with the data, one to clear the lines, so only the 2nd write does anything
+ //TODO: PWM
+ for (int i = 0; i < 5; i++)
+ {
+ m_lamps[(8*column) + i + 128] = BIT(lamp_ext_data, i);
+ }
+ }
+ m_lamp_strobe_ext_persistence++;
+ if ((m_lamp_strobe_ext_persistence == 3)||(m_lamp_strobe_ext[0] != column))
+ {
+ m_lamp_strobe_ext_persistence = 0;
+ m_lamp_strobe_ext[0] = column;
+ }
+}
+
+void mpu4_state::lamp_extend_large(uint8_t data, uint8_t column, bool active)
+{
+ m_lamp_sense = false;
+ uint8_t bit7 = BIT(data, 7);
+ if (bit7 != m_last_b7)
+ {
+ m_card_live = true;
+ //depending on bit 7, we can access one of two 'blocks' of 64 lamps
+ uint8_t lampbase = bit7 ? 0 : 64;
+ if (data & 0x3f)
+ {
+ m_lamp_sense = true;
+ }
+ if (active)
+ {
+ if (m_lamp_strobe_ext[bit7] != column)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ // this includes bit 7, so you don't get a true 128 extra lamps as the last row is always 0 or 1 depending on which set of 64 we're dealing with
+ m_lamps[(8*column) + i + 128 + lampbase] = BIT(data, i);
+ }
+ m_lamp_strobe_ext[bit7] = column;
+ }
+ }
+ m_last_b7 = bit7;
+ }
+ else
+ {
+ m_card_live = false;
+ }
+}
+
+void mpu4_state::led_write_extender(uint8_t latch, uint8_t data, uint8_t column)
+{
+ const uint8_t diff = (latch ^ m_last_latch) & latch;
+ const uint8_t ext_strobe = (7 - column) * 8;
+
+ data = ~data;//invert drive lines
+ for (int i = 0; i < 5; i++)
+ {
+ if (BIT(diff, i))
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ m_mpu4leds[(ext_strobe + i) | j], BIT(data, j);
+ }
+ m_digits[(ext_strobe + i)] = data;
+ }
+ }
+
+ m_last_latch = diff;
+}
+
+
+void mpu4_state::update_meters()
+{
+ uint8_t data = ((m_mmtr_data & 0x7f) | m_remote_meter);
+ switch (m_reel_mux)
+ {
+ case STANDARD_REEL:
+ if (m_hopper_type != TUBES)
+ {
+ data = (data & 0x0f); //Strip reel data from meter drives, leaving active elements
+ }
+ break;
+
+ case FIVE_REEL_5TO8:
+ m_reel[4]->update(((data >> 4) & 0x0f));
+ data = (data & 0x0f); //Strip reel data from meter drives, leaving active elements
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ break;
+
+ case FIVE_REEL_8TO5:
+ m_reel[4]->update((((data & 0x01) + ((data & 0x08) >> 2) + ((data & 0x20) >> 3) + ((data & 0x80) >> 4)) & 0x0f)) ;
+ data = 0x00; //Strip all reel data from meter drives, nothing is connected
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ break;
+
+ case FIVE_REEL_3TO6:
+ m_reel[4]->update(((data >> 2) & 0x0f));
+ data = 0x00; //Strip all reel data from meter drives
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ break;
+
+ case SIX_REEL_1TO8:
+ m_reel[4]->update( data & 0x0f);
+ m_reel[5]->update((data >> 4) & 0x0f);
+ data = 0x00; //Strip all reel data from meter drives
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ awp_draw_reel(machine(),"reel6", *m_reel[5]);
+ break;
+
+#if 0
+ case SIX_REEL_5TO8: // m_reel[4] for this case is already handled in pia_ic5_porta_w
+ m_reel[4]->update(((data >> 4) & 0x0f));
+ //data = 0x00; //Strip all reel data from meter drives
+ data = (data & 0x0f);
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ break;
+#endif
+
+ case SEVEN_REEL:
+ m_reel[0]->update((((data & 0x01) + ((data & 0x08) >> 2) + ((data & 0x20) >> 3) + ((data & 0x80) >> 4)) & 0x0f)) ;
+ data = 0x00; //Strip all reel data from meter drives
+ awp_draw_reel(machine(),"reel1", *m_reel[0]);
+ break;
+
+ case FLUTTERBOX: //The backbox fan assembly fits in a reel unit sized box, wired to the remote meter pin, so we can handle it here
+ m_flutterbox = BIT(data, 7);
+ data &= ~0x80; //Strip flutterbox data from meter drives
+ break;
+ }
+
+ m_meters->update(7, data & 0x80);
+
+ for (int meter = 0; meter < 4; meter++)
+ {
+ m_meters->update(meter, (data & (1 << meter)));
+ }
+
+ if (m_reel_mux == STANDARD_REEL)
+ {
+ for (int meter = 4; meter < 7; meter++)
+ {
+ m_meters->update(meter, (data & (1 << meter)));
+ }
+ }
+}
+
+/* called if board is reset */
+MACHINE_RESET_MEMBER(mpu4_state, mpu4)
+{
+ m_vfd->reset();
+
+ m_lamp_strobe = 0;
+ m_lamp_strobe2 = 0;
+ m_led_strobe = 0;
+ m_pia4_porta_leds_strobe = 0;
+ m_simplecard_leds_strobe = 0;
+ m_mmtr_data = 0;
+ m_remote_meter = 0;
+
+ m_IC23GC = 0;
+ m_IC23GB = 0;
+ m_IC23GA = 0;
+ m_IC23G1 = 1;
+ m_IC23G2A = 0;
+ m_IC23G2B = 0;
+
+ // Bwb Orlando, which uses the bwb_bank address for banking requires the default bank to be 0!
+ if (m_numbanks)
+ m_bank1->set_entry(m_default_to_low_bank ? 0 : m_numbanks);
+
+ m_maincpu->reset();
+}
+
+
+/* 6809 IRQ handler */
+void mpu4_state::cpu0_irq(int state)
+{
+ /* The PIA and PTM IRQ lines are all connected to a common PCB track, leading directly to the 6809 IRQ line. */
+ uint8_t combined_state = m_pia3->irq_a_state() | m_pia3->irq_b_state() |
+ m_pia4->irq_a_state() | m_pia4->irq_b_state() |
+ m_pia5->irq_a_state() | m_pia5->irq_b_state() |
+ m_pia6->irq_a_state() | m_pia6->irq_b_state() |
+ m_pia7->irq_a_state() | m_pia7->irq_b_state() |
+ m_pia8->irq_a_state() | m_pia8->irq_b_state() |
+ m_6840ptm->irq_state();
+
+ if (m_link7b_connected) //7B = IRQ, 7A = FIRQ, both = NMI
+ {
+ if (!m_link7a_connected)
+ {
+ m_maincpu->set_input_line(M6809_IRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE);
+ LOG("6809 IRQ %d \n", combined_state);
+ }
+ else
+ {
+ m_maincpu->set_input_line(INPUT_LINE_NMI, combined_state ? ASSERT_LINE : CLEAR_LINE);
+ LOG("6809 NMI %d \n", combined_state);
+ }
+ }
+ else
+ {
+ m_maincpu->set_input_line(M6809_FIRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE);
+ LOG("6809 FIRQ %d \n", combined_state);
+ }
+}
+
+/* Bankswitching
+The MOD 4 ROM cards are set up to handle 8 separate ROM pages, arranged as 2 sets of 4.
+The bankswitch selects which of the 4 pages in the set is active, while the bankset
+switches between the sets.
+It appears that the cards were originally intended to be used in a 'half' page setup,
+where the two halves of the ROM space could be mixed and matched as appropriate.
+However, there is no evidence to suggest this was ever implemented.
+The controls for it exist however, in the form of the Soundboard PIA CB2 pin, which is
+used in some cabinets instead of the main control.
+*/
+void mpu4_state::bankswitch_w(uint8_t data)
+{
+ m_pageval = (data & 0x03);
+ m_bank1->set_entry((m_pageval + (m_pageset ? 4 : 0)) & m_numbanks);
+}
+
+
+uint8_t mpu4_state::bankswitch_r()
+{
+ return m_bank1->entry();
+}
+
+
+void mpu4_state::bankset_w(uint8_t data)
+{
+ m_pageval = (data - 2);//writes 2 and 3, to represent 0 and 1 - a hangover from the half page design?
+ m_bank1->set_entry((m_pageval + (m_pageset ? 4 : 0)) & m_numbanks);
+}
+
+
+/* IC2 6840 PTM handler */
+void mpu4_state::ic2_o1_callback(int state)
+{
+ m_6840ptm->set_c2(state); /* copy output value to IC2 c2
+ this output is the clock for timer2 */
+ /* 1200Hz System interrupt timer */
+}
+
+
+void mpu4_state::ic2_o2_callback(int state)
+{
+ m_pia3->ca1_w(state); /* copy output value to IC3 ca1 */
+ /* the output from timer2 is the input clock for timer3 */
+ /* miscellaneous interrupts generated here */
+ m_6840ptm->set_c3(state);
+}
+
+
+void mpu4_state::ic2_o3_callback(int state)
+{
+ /* the output from timer3 is used as a square wave for the alarm output
+ and as an external clock source for timer 1! */
+ /* also runs lamp fade */
+ m_alarmdac->write(state);
+ m_6840ptm->set_c1(state);
+}
+
+/* 6821 PIA handlers */
+/* IC3, lamp data lines + alpha numeric display */
+void mpu4_state::pia_ic3_porta_w(uint8_t data)
+{
+ LOGMASKED(LOG_IC3, "%s: IC3 PIA Port A Set to %2x (lamp strobes 1 - 9)\n", machine().describe_context(), data);
+
+ if(m_ic23_active)
+ {
+ if (m_lamp_strobe != m_input_strobe)
+ {
+ // Because of the nature of the lamping circuit, there is an element of persistance
+ // As a consequence, the lamp column data can change before the input strobe without
+ // causing the relevant lamps to black out.
+
+ if (m_overcurrent_detect) m_overcurrent = true;
+
+ if (m_undercurrent_detect) m_undercurrent = true;
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_lamps[(8*m_input_strobe) + i] = BIT(data, i);
+ }
+ m_lamp_strobe = m_input_strobe;
+ }
+ }
+}
+
+void mpu4_state::pia_ic3_portb_w(uint8_t data)
+{
+ LOGMASKED(LOG_IC3, "%s: IC3 PIA Port B Set to %2x (lamp strobes 10 - 17)\n", machine().describe_context(), data);
+
+ if (m_ic23_active)
+ {
+ if (m_lamp_strobe2 != m_input_strobe)
+ {
+ if (m_overcurrent_detect) m_overcurrent = true;
+
+ if (m_undercurrent_detect) m_undercurrent = true;
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_lamps[(8*m_input_strobe) + i + 64] = BIT(data, i);
+ }
+ m_lamp_strobe2 = m_input_strobe;
+ }
+
+ }
+}
+
+void mpu4_state::pia_ic3_ca2_w(int state)
+{
+ LOGMASKED(LOG_IC3, "%s: IC3 PIA Write CA2 (alpha data), %02X\n", machine().describe_context(), state);
+ m_vfd->data(state);
+}
+
+
+void mpu4_state::pia_ic3_cb2_w(int state)
+{
+ LOGMASKED(LOG_IC3, "%s: IC3 PIA Write CB (alpha reset), %02X\n", machine().describe_context(), state);
+// DM Data pin A
+ m_vfd->por(state);
+}
+
+
+/*
+IC23 emulation
+
+IC23 is a 74LS138 1-of-8 Decoder
+
+It is used as a multiplexer for the LEDs, lamp selects and inputs.*/
+
+void mpu4_state::ic23_update()
+{
+ if (!m_IC23G2A)
+ {
+ if (!m_IC23G2B)
+ {
+ if (m_IC23G1)
+ {
+ if (m_IC23GA) m_input_strobe |= 0x01;
+ else m_input_strobe &= ~0x01;
+
+ if (m_IC23GB) m_input_strobe |= 0x02;
+ else m_input_strobe &= ~0x02;
+
+ if (m_IC23GC) m_input_strobe |= 0x04;
+ else m_input_strobe &= ~0x04;
+ }
+ }
+ }
+ else if (m_IC23G2A || m_IC23G2B)
+ {
+ m_input_strobe = 0x00;
+ }
+}
+
+
+/*
+IC24 emulation
+
+IC24 is a 74LS122 pulse generator
+
+CLEAR and B2 are tied high and A1 and A2 tied low, meaning any pulse
+on B1 will give a low pulse on the output pin.
+*/
+void mpu4_state::ic24_output(uint8_t data)
+{
+ m_IC23G2A = data;
+ ic23_update();
+}
+
+
+void mpu4_state::ic24_setup()
+{
+ if (m_IC23GA)
+ {
+ double duration = TIME_OF_74LS123((220*1000),(0.1*0.000001));
+ m_ic23_active = true;
+ ic24_output(0);
+ m_ic24_timer->adjust(attotime::from_double(duration));
+ }
+}
+
+
+TIMER_CALLBACK_MEMBER(mpu4_state::update_ic24)
+{
+ m_ic23_active=false;
+ ic24_output(1);
+}
+
+
+void mpu4_state::dataport_rxd(int state)
+{
+ m_pia4->cb1_w(state);
+ m_serial_output = state;
+ LOGMASKED(LOG_IC3, "Dataport RX %x\n", state);
+}
+
+/* IC4, 7 seg leds, 50Hz timer reel sensors, current sensors */
+void mpu4_state::pia_ic4_porta_w(uint8_t data)
+{
+ if(m_ic23_active)
+ {
+ if (m_use_pia4_porta_leds)
+ {
+ if (m_pia4_porta_leds_strobe != m_input_strobe)
+ {
+ for (int i=0; i<8; i++)
+ {
+ m_mpu4leds[(((7 - m_input_strobe) | m_pia4_porta_leds_base) << 3) | i] = BIT(data, i);
+ }
+ m_digits[(7 - m_input_strobe) | m_pia4_porta_leds_base] = data;
+ }
+ m_pia4_porta_leds_strobe = m_input_strobe;
+ }
+ }
+}
+
+void mpu4_state::pia_ic4_portb_w(uint8_t data)
+{
+ if (m_reel_mux)
+ {
+ /* A write here connects one reel (and only one)
+ to the optic test circuit. This allows 8 reels
+ to be supported instead of 4. */
+ if (m_reel_mux == SEVEN_REEL)
+ {
+ m_active_reel = reel_mux_table7[(data >> 4) & 0x07];
+ }
+ else
+ {
+ m_active_reel = reel_mux_table[(data >> 4) & 0x07];
+ }
+ }
+}
+
+uint8_t mpu4_state::pia_ic4_portb_r()
+{
+ m_ic4_input_b = 0x00;
+
+ if (m_serial_output) m_ic4_input_b |= 0x80;
+
+ if (!m_reel_mux)
+ {
+ if (m_optic_pattern & 0x01) m_ic4_input_b |= 0x40; /* reel A tab */
+
+ if (m_optic_pattern & 0x02) m_ic4_input_b |= 0x20; /* reel B tab */
+
+ if (m_optic_pattern & 0x04) m_ic4_input_b |= 0x10; /* reel C tab */
+
+ if (m_optic_pattern & 0x08) m_ic4_input_b |= 0x08; /* reel D tab */
+ }
+ else
+ {
+ if (m_optic_pattern & (1<<m_active_reel)) m_ic4_input_b |= 0x08;
+ }
+
+ if (m_low_volt_detect)
+ {
+ if (m_signal_50hz) m_ic4_input_b |= 0x04;
+ }
+
+ if (m_overcurrent) m_ic4_input_b |= 0x02;
+
+ if (m_undercurrent) m_ic4_input_b |= 0x01;
+
+ LOGMASKED(LOG_IC3, "%s: IC4 PIA Read of Port B %x\n", machine().describe_context(), m_ic4_input_b);
+ return m_ic4_input_b;
+}
+
+
+void mpu4_state::pia_ic4_ca2_w(int state)
+{
+ LOGMASKED(LOG_IC3, "%s: IC4 PIA Write CA (input MUX strobe /LED B), %02X\n", machine().describe_context(), state);
+
+ m_IC23GB = state;
+ ic23_update();
+}
+
+void mpu4_state::pia_ic4_cb2_w(int state)
+{
+ LOGMASKED(LOG_IC3, "%s: IC4 PIA Write CB (Reel optic flag), %02X\n", machine().describe_context(), state);
+ m_reel_flag=state;
+}
+
+/* IC5, AUX ports, coin lockouts and AY sound chip select (MODs below 4 only) */
+uint8_t mpu4_state::pia_ic5_porta_r()
+{
+ if (m_lamp_extender == LARGE_CARD_A)
+ {
+ if (m_overcurrent_detect)
+ {
+ if (m_lamp_sense && m_ic23_active)
+ {
+ m_aux1_input |= 0x40;
+ }
+ else
+ {
+ m_aux1_input &= ~0x40; //Pulse the overcurrent line with every read to show the CPU each lamp has lit
+ }
+ }
+ }
+ if (m_hopper_type == HOPPER_NONDUART_A)
+ {
+ if (m_hopper1->line_r() && m_hopper1_opto)
+ {
+ m_aux1_input |= 0x04;
+ }
+ else
+ {
+ m_aux1_input &= ~0x04;
+ }
+ }
+ else if (m_hopper_type == HOPPER_TWIN_HOPPER)
+ {
+ if (m_hopper1->line_r())
+ {
+ m_aux1_input |= 0x08;
+ }
+ else
+ {
+ m_aux1_input &= ~0x08;
+ }
+
+ if (m_hopper2->line_r())
+ {
+ m_aux1_input |= 0x04;
+ }
+ else
+ {
+ m_aux1_input &= ~0x04;
+ }
+ }
+
+ LOG("%s: IC5 PIA Read of Port A (AUX1)\n", machine().describe_context());
+
+
+ uint8_t tempinput = m_aux1_port->read() | m_aux1_input;
+ return tempinput;
+}
+
+
+void mpu4_state::pia_ic5_porta_w(uint8_t data)
+{
+ if (m_hopper_type == HOPPER_NONDUART_A)
+ {
+ m_hopper1_opto = (data & 0x10);
+ }
+
+ switch (m_lamp_extender)
+ {
+ case NO_EXTENDER:
+ if (m_led_extender == CARD_B)
+ {
+ led_write_extender(data & 0x1f, m_pia4->a_output(), m_input_strobe);
+ }
+ else if ((m_led_extender != CARD_A) && (m_led_extender != NO_EXTENDER))
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ m_mpu4leds[((m_input_strobe | 8) << 3) | i] = BIT(data, i);
+ }
+ }
+ break;
+
+ case SMALL_CARD:
+ if(m_ic23_active)
+ {
+ lamp_extend_small(data);
+ }
+ break;
+
+ case LARGE_CARD_A:
+ lamp_extend_large(data, m_input_strobe, m_ic23_active);
+ break;
+
+ case LARGE_CARD_B:
+ lamp_extend_large(data, m_input_strobe, m_ic23_active);
+#if 0
+ if ((m_ic23_active) && m_card_live)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ m_mpu4leds[(m_last_b7 << 6) | (m_input_strobe << 3) | i] = BIT(~data, i);
+ }
+ m_digits[(m_last_b7 << 3) | m_input_strobe] = ~data;
+ }
+#endif
+ break;
+
+ case LARGE_CARD_C:
+ lamp_extend_large(data, m_input_strobe, m_ic23_active);
+ break;
+ }
+
+
+ if (m_reel_mux == SIX_REEL_5TO8)
+ {
+ m_reel[4]->update( data &0x0f);
+ m_reel[5]->update((data >> 4)&0x0f);
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ awp_draw_reel(machine(),"reel6", *m_reel[5]);
+ }
+ else if (m_reel_mux == SEVEN_REEL)
+ {
+ m_reel[1]->update( data &0x0f);
+ m_reel[2]->update((data >> 4)&0x0f);
+ awp_draw_reel(machine(),"reel2", *m_reel[1]);
+ awp_draw_reel(machine(),"reel3", *m_reel[2]);
+ }
+}
+
+
+void mpu4_state::pia_ic5_portb_w(uint8_t data)
+{
+ if (m_hopper_type == HOPPER_NONDUART_B)
+ {
+ m_hopper1->motor_w(data & 0x01);
+ m_hopper1_opto = (data & 0x08);
+ }
+ if (m_led_extender == CARD_A)
+ {
+ led_write_extender(data & 0x07, m_pia4->a_output(), m_input_strobe);
+ }
+
+ if (m_use_simplecard_leds)
+ {
+ if(m_simplecard_leds_strobe != m_input_strobe)
+ {
+ for(int i=0; i<8; i++)
+ {
+ m_mpu4leds[( ( (7 - m_input_strobe) | m_simplecard_leds_base) << 3) | i] = BIT(m_pia4->a_output(), i);
+ }
+ m_digits[(7 - m_input_strobe) | m_simplecard_leds_base] = m_pia4->a_output();
+ }
+ m_simplecard_leds_strobe = m_input_strobe;
+ }
+}
+
+uint8_t mpu4_state::pia_ic5_portb_r()
+{
+ if (m_hopper_type == HOPPER_NONDUART_B)
+ {
+ if (m_hopper1->line_r() && m_hopper1_opto)
+ {
+ m_aux2_input |= 0x08;
+ }
+ else
+ {
+ m_aux2_input &= ~0x08;
+ }
+ }
+
+ LOG("%s: IC5 PIA Read of Port B (coin input AUX2)\n", machine().describe_context());
+ if (m_use_coinlocks)
+ {
+ // why are these being set in a read, not when the outputs are written?
+ // maybe should be done as an output 'port' as differs between games?
+ machine().bookkeeping().coin_lockout_w(0, (m_pia5->b_output() & 0x01));
+ machine().bookkeeping().coin_lockout_w(1, (m_pia5->b_output() & 0x02));
+ machine().bookkeeping().coin_lockout_w(2, (m_pia5->b_output() & 0x04));
+ machine().bookkeeping().coin_lockout_w(3, (m_pia5->b_output() & 0x08));
+ }
+
+ uint8_t tempinput = m_aux2_port->read() | m_aux2_input;
+ return tempinput;
+}
+
+
+/* ---------------------------------------
+ AY Chip sound function selection -
+ ---------------------------------------
+The databus of the AY sound chip is connected to IC6 Port A.
+Data is read from/written to the AY chip through this port.
+
+If this sounds familiar, Amstrad did something very similar with their home computers.
+
+The PSG function, defined by the BC1,BC2 and BDIR signals, is controlled by CA2 and CB2 of IC6.
+
+The chipselect for the AY chip itself, however, is CB2 on IC5, so unless this goes live, things are likely to fail
+
+PSG function selection:
+-----------------------
+CSEL = IC5 CB2
+BDIR = IC6 CB2 and BC1 = IC6 CA2
+
+Pin | PSG Function
+BDIR BC1 |
+0 0 | Inactive
+0 1 | Read from selected PSG register. When function is set, the PSG will make the register data available to Port A.
+1 0 | Write to selected PSG register. When set, the PSG will take the data at Port A and write it into the selected PSG register.
+1 1 | Select PSG register. When set, the PSG will take the data at Port A and select a register.
+*/
+
+/* PSG function selected */
+void mpu4_state::update_ay()
+{
+ if (!m_ay8913) return;
+
+ if (!m_pia5->cb2_output())
+ {
+ switch (m_ay8913_address)
+ {
+ case 0x00:
+ /* Inactive */
+ break;
+
+ case 0x01:
+ /* CA2 = 1 CB2 = 0? : Read from selected PSG register and make the register data available to Port A */
+ LOG("AY8913 address = %d \n", m_pia6->a_output()&0x0f);
+ break;
+
+ case 0x02:
+ /* CA2 = 0 CB2 = 1? : Write to selected PSG register and write data to Port A */
+ m_ay8913->data_w(m_pia6->a_output());
+ LOG("AY Chip Write \n");
+ break;
+
+ case 0x03:
+ /* CA2 = 1 CB2 = 1? : The register will now be selected and the user can read from or write to it.
+ The register will remain selected until another is chosen.*/
+ m_ay8913->address_w(m_pia6->a_output());
+ LOG("AY Chip Select \n");
+ break;
+
+ default:
+ LOG("AY Chip error \n");
+ break;
+ }
+ }
+}
+
+
+void mpu4_state::pia_ic5_cb2_w(int state)
+{
+ update_ay();
+}
+
+
+/* IC6, Reel A and B and AY registers (MODs below 4 only) */
+void mpu4_state::pia_ic6_portb_w(uint8_t data)
+{
+ LOG("%s: IC6 PIA Port B Set to %2x (Reel A and B)\n", machine().describe_context(), data);
+
+ if (m_reel_mux == SEVEN_REEL)
+ {
+ m_reel[3]->update( data &0x0f);
+ m_reel[4]->update((data >> 4)&0x0f);
+ awp_draw_reel(machine(),"reel4", *m_reel[3]);
+ awp_draw_reel(machine(),"reel5", *m_reel[4]);
+ }
+ else if (m_reels)
+ {
+ m_reel[0]->update( data &0x0f);
+ m_reel[1]->update((data >> 4)&0x0f);
+ awp_draw_reel(machine(),"reel1", *m_reel[0]);
+ awp_draw_reel(machine(),"reel2", *m_reel[1]);
+ }
+}
+
+
+void mpu4_state::pia_ic6_porta_w(uint8_t data)
+{
+ LOG("%s: IC6 PIA Write A %2x\n", machine().describe_context(), data);
+ if (m_ay8913.found())
+ {
+ m_ay_data = data;
+ update_ay();
+ }
+}
+
+
+void mpu4_state::pia_ic6_ca2_w(int state)
+{
+ LOG("%s: IC6 PIA write CA2 %2x (AY8913 BC1)\n", machine().describe_context(), state);
+ if (m_ay8913.found())
+ {
+ if ( state ) m_ay8913_address |= 0x01;
+ else m_ay8913_address &= ~0x01;
+ update_ay();
+ }
+}
+
+
+void mpu4_state::pia_ic6_cb2_w(int state)
+{
+ LOG("%s: IC6 PIA write CB2 %2x (AY8913 BCDIR)\n", machine().describe_context(), state);
+ if (m_ay8913.found())
+ {
+ if ( state ) m_ay8913_address |= 0x02;
+ else m_ay8913_address &= ~0x02;
+ update_ay(); // using m_pia5 here allows m4fourmr to have sound
+ }
+}
+
+
+/* IC7 Reel C and D, mechanical meters/Reel E and F, input strobe bit A */
+void mpu4_state::pia_ic7_porta_w(uint8_t data)
+{
+ LOG("%s: IC7 PIA Port A Set to %2x (Reel C and D)\n", machine().describe_context(), data);
+ if (m_reel_mux == SEVEN_REEL)
+ {
+ m_reel[5]->update( data &0x0f);
+ m_reel[6]->update((data >> 4)&0x0f);
+ awp_draw_reel(machine(),"reel6", *m_reel[5]);
+ awp_draw_reel(machine(),"reel7", *m_reel[6]);
+ }
+ else if (m_reels)
+ {
+ m_reel[2]->update( data &0x0f);
+ m_reel[3]->update((data >> 4)&0x0f);
+ awp_draw_reel(machine(),"reel3", *m_reel[2]);
+ awp_draw_reel(machine(),"reel4", *m_reel[3]);
+ }
+}
+
+void mpu4_state::pia_ic7_portb_w(uint8_t data)
+{
+ if (m_hopper_type == HOPPER_DUART_A)
+ {
+ m_hopper1->motor_w(data & 0x10);
+ //opto line is DUART op BIT 4 (MR, channel B)
+ }
+ else if (m_hopper_type == HOPPER_NONDUART_A)
+ {
+ m_hopper1->motor_w(data & 0x20);
+ }
+ else if (m_hopper_type == HOPPER_TWIN_HOPPER)
+ {
+ m_hopper1->motor_w(data & 0x20);
+ m_hopper2->motor_w(data & 0x40);
+ }
+
+ m_mmtr_data = data;
+}
+
+uint8_t mpu4_state::pia_ic7_portb_r()
+{
+ /* The meters are connected to a voltage drop sensor, where current
+ flowing through them also passes through pin B7, meaning that when
+ any meter is activated, pin B7 goes high.
+ As for why they connected this to an output port rather than using
+ CB1, no idea, although it proved of benefit when the reel multiplexer was designed
+ as it allows a separate meter to be used when the rest of the port is blocked.
+ This appears to have confounded the schematic drawer, who has assumed that
+ all eight meters are driven from this port, giving the 8 line driver chip
+ 9 connections in total. */
+
+ //This may be overkill, but the meter sensing is VERY picky.
+
+ uint8_t combined_meter = m_meters->get_activity(0) | m_meters->get_activity(1) |
+ m_meters->get_activity(2) | m_meters->get_activity(3) |
+ m_meters->get_activity(4) | m_meters->get_activity(5) |
+ m_meters->get_activity(6) | m_meters->get_activity(7);
+
+ if(combined_meter)
+ {
+ return 0x80;
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+void mpu4_state::pia_ic7_ca2_w(int state)
+{
+ LOG("%s: IC7 PIA write CA2 %2x (input strobe bit 0 / LED A)\n", machine().describe_context(), state);
+
+ m_IC23GA = state;
+ ic24_setup();
+ ic23_update();
+}
+
+void mpu4_state::pia_ic7_cb2_w(int state)
+{
+ m_remote_meter = state?0x80:0x00;
+}
+
+
+/* IC8, Inputs, TRIACS, alpha clock */
+uint8_t mpu4_state::pia_ic8_porta_r()
+{
+ LOGMASKED(LOG_IC8, "%s: IC8 PIA Read of Port A (MUX input data)\n", machine().describe_context());
+ /* The orange inputs are polled twice as often as the black ones, for reasons of efficiency.
+ This is achieved via connecting every input line to an AND gate, thus allowing two strobes
+ to represent each orange input bank (strobes are active low). */
+ m_pia5->cb1_w(m_aux2_port->read() & 0x80);
+
+ return (m_port_mux[m_input_strobe])->read();
+}
+
+
+void mpu4_state::pia_ic8_portb_w(uint8_t data)
+{
+ if (m_hopper_type == HOPPER_DUART_B)
+ {
+ m_hopper1->motor_w(data & 0x01);
+ m_hopper1_opto = (data & 0x04);
+ data &= ~0x05; //remove Triacs from use
+ }
+ else if (m_hopper_type == HOPPER_DUART_C)
+ {
+ // Dual DUART hoppers share an opto line for some reason
+ m_hopper1->motor_w(data & 0x01);
+ m_hopper1_opto = (data & 0x04);
+ m_hopper2->motor_w(data & 0x02);
+ m_hopper2_opto = (data & 0x04);
+ data &= ~0x07; //remove Triacs from use
+ }
+ LOGMASKED(LOG_IC8, "%s: IC8 PIA Port B Set to %2x (OUTPUT PORT, TRIACS)\n", machine().describe_context(), data);
+ for (uint8_t i = 0; i < 8; i++)
+ {
+ m_triacs[i] = BIT(data, i);
+ }
+}
+
+void mpu4_state::pia_ic8_ca2_w(int state)
+{
+ LOGMASKED(LOG_IC8, "%s: IC8 PIA write CA2 (input_strobe bit 2 / LED C) %02X\n", machine().describe_context(), state & 0xff);
+
+ m_IC23GC = state;
+ ic23_update();
+}
+
+
+void mpu4_state::pia_ic8_cb2_w(int state)
+{
+ LOGMASKED(LOG_IC8, "%s: IC8 PIA write CB2 (alpha clock) %02X\n", machine().describe_context(), state & 0xff);
+
+ // DM Data pin B
+
+ m_vfd->sclk(!state);
+}
+
+void mpu4_state::pia_gb_cb2_w(int state)
+{
+ // Some BWB games use this to drive the bankswitching
+ // should the regular bankswitch still work in these cases?
+ if (m_bwb_bank)
+ {
+ m_pageval = state;
+ m_bank1->set_entry((m_pageval + (m_pageset ? 4 : 0)) & m_numbanks);
+ }
+}
+
+/* input ports for MPU4 board */
+INPUT_PORTS_START( mpu4 )
+ PORT_START("ORANGE1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("00")// 20p level
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("01")// 100p level
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("02")// Token 1 level
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("03")// Token 2 level
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("04")
+ PORT_CONFNAME( 0xe0, 0x00, "Stake Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 5p" )
+ PORT_CONFSETTING( 0x20, "10p" )
+ PORT_CONFSETTING( 0x40, "20p" )
+ PORT_CONFSETTING( 0x60, "25p" )
+ PORT_CONFSETTING( 0x80, "30p" )
+ PORT_CONFSETTING( 0xa0, "40p" )
+ PORT_CONFSETTING( 0xc0, "50p" )
+ PORT_CONFSETTING( 0xe0, "1 GBP" )
+
+ PORT_START("ORANGE2")
+ PORT_CONFNAME( 0x0f, 0x00, "Jackpot / Prize Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted" )
+ PORT_CONFSETTING( 0x01, "3 GBP" )
+ PORT_CONFSETTING( 0x02, "4 GBP" )
+ PORT_CONFSETTING( 0x08, "5 GBP" )
+ PORT_CONFSETTING( 0x03, "6 GBP" )
+ PORT_CONFSETTING( 0x04, "6 GBP Token" )
+ PORT_CONFSETTING( 0x05, "8 GBP" )
+ PORT_CONFSETTING( 0x06, "8 GBP Token" )
+ PORT_CONFSETTING( 0x07, "10 GBP" )
+ PORT_CONFSETTING( 0x09, "15 GBP" )
+ PORT_CONFSETTING( 0x0a, "25 GBP" )
+ PORT_CONFSETTING( 0x0b, "25 GBP (Licensed Betting Office Profile)" )
+ PORT_CONFSETTING( 0x0c, "35 GBP" )
+ PORT_CONFSETTING( 0x0d, "70 GBP" )
+ PORT_CONFSETTING( 0x0e, "Reserved" )
+ PORT_CONFSETTING( 0x0f, "Reserved" )
+
+ PORT_CONFNAME( 0xf0, 0x00, "Percentage Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 68% (Invalid for UK Games)" )
+ PORT_CONFSETTING( 0x10, "70" )
+ PORT_CONFSETTING( 0x20, "72" )
+ PORT_CONFSETTING( 0x30, "74" )
+ PORT_CONFSETTING( 0x40, "76" )
+ PORT_CONFSETTING( 0x50, "78" )
+ PORT_CONFSETTING( 0x60, "80" )
+ PORT_CONFSETTING( 0x70, "82" )
+ PORT_CONFSETTING( 0x80, "84" )
+ PORT_CONFSETTING( 0x90, "86" )
+ PORT_CONFSETTING( 0xa0, "88" )
+ PORT_CONFSETTING( 0xb0, "90" )
+ PORT_CONFSETTING( 0xc0, "92" )
+ PORT_CONFSETTING( 0xd0, "94" )
+ PORT_CONFSETTING( 0xe0, "96" )
+ PORT_CONFSETTING( 0xf0, "98" )
+
+ PORT_START("BLACK1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Hi")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Lo")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("18")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("19")
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("20")
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_SERVICE) PORT_NAME("Test Button") PORT_CODE(KEYCODE_W)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_SERVICE) PORT_NAME("Refill Key") PORT_CODE(KEYCODE_R) PORT_TOGGLE
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_INTERLOCK) PORT_NAME("Cashbox (Back) Door") PORT_CODE(KEYCODE_Q) PORT_TOGGLE
+
+ PORT_START("BLACK2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("24")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("25")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Cancel")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_NAME("Hold 1")
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_NAME("Hold 2")
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_NAME("Hold 3")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_NAME("Hold 4")
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_START1)
+
+ PORT_START("DIL1")
+ PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:03")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:04")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0xf0, 0x00, "Target Percentage (if key not fitted)" )PORT_DIPLOCATION("DIL1:05,06,07,08")
+ PORT_DIPSETTING( 0x00, "Unset (Program Optimum)" )
+ PORT_DIPSETTING( 0x10, "70" )
+ PORT_DIPSETTING( 0x20, "72" )
+ PORT_DIPSETTING( 0x30, "74" )
+ PORT_DIPSETTING( 0x40, "76" )
+ PORT_DIPSETTING( 0x50, "78" )
+ PORT_DIPSETTING( 0x60, "80" )
+ PORT_DIPSETTING( 0x70, "82" )
+ PORT_DIPSETTING( 0x80, "84" )
+ PORT_DIPSETTING( 0x90, "86" )
+ PORT_DIPSETTING( 0xa0, "88" )
+ PORT_DIPSETTING( 0xb0, "90" )
+ PORT_DIPSETTING( 0xc0, "92" )
+ PORT_DIPSETTING( 0xd0, "94" )
+ PORT_DIPSETTING( 0xe0, "96" )
+ PORT_DIPSETTING( 0xf0, "98" )
+
+ PORT_START("DIL2")
+ PORT_DIPNAME( 0x01, 0x00, "Token Lockout when full" ) PORT_DIPLOCATION("DIL2:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unused )) PORT_DIPLOCATION("DIL2:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, "Scottish Coin Handling" ) PORT_DIPLOCATION("DIL2:03")//20p payout
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, "Out of Credit Display Inhibit" ) PORT_DIPLOCATION("DIL2:04") // many games need this 'OFF' to display attract cycles
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x00, "OCD Audio Enable" ) PORT_DIPLOCATION("DIL2:05")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x00, "Coin Alarm Inhibit" ) PORT_DIPLOCATION("DIL2:06")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x00, "Token Refill Level Inhibit" ) PORT_DIPLOCATION("DIL2:07")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x00, "Single Credit Entry" ) PORT_DIPLOCATION("DIL2:08")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( On ) )
+
+ PORT_START("AUX1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_0")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_1")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_2")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_3")
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_4")
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_5")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_6")
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("A1_7")
+
+ PORT_START("AUX2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_CUSTOM) //Lockouts, in same order as below
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_COIN1)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_COIN2)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_COIN3)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_COIN4)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_dutch )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("ORANGE1")
+ PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE1:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) // avoid REFILL NEEDED
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) // avoid REFILL NEEDED
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) // avoid NO TUBES
+ PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE1:05")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE1:06")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE1:07")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( On ) )
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_INTERLOCK) PORT_NAME("Unknown Door") PORT_CODE(KEYCODE_T) PORT_TOGGLE
+
+ PORT_MODIFY("ORANGE2")
+ PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:03")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:04")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:05")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:06")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:07")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("ORANGE2:08")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( On ) )
+
+ PORT_MODIFY("DIL1")
+ PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:03")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:04")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:05")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:06")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:07")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:08")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( On ) )
+
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_dutch_invcoin )
+ PORT_INCLUDE( mpu4_dutch )
+
+ PORT_MODIFY("AUX2")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_COIN1)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_COIN2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_COIN3)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_COIN4)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_dutch_alt_invcoin )
+ PORT_INCLUDE( mpu4_dutch_invcoin )
+
+ PORT_MODIFY("AUX2")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) // needed for several sets to boot but gives coin jam error if pressed
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_impcoin )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("AUX2")
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_COIN1) PORT_IMPULSE(4)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_COIN2) PORT_IMPULSE(4)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_COIN3) PORT_IMPULSE(4)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_COIN4) PORT_IMPULSE(4)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_invcoin )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("AUX2")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_COIN1)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_COIN2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_COIN3)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_COIN4)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_invimpcoin )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("AUX2")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_COIN1) PORT_IMPULSE(5)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_COIN2) PORT_IMPULSE(5)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_COIN3) PORT_IMPULSE(5)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_COIN4) PORT_IMPULSE(5)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_cw )
+//Inputs for CoinWorld games
+ PORT_INCLUDE( mpu4 )
+ PORT_MODIFY("DIL1")
+ PORT_DIPNAME( 0x01, 0x00, "Profile Type" ) PORT_DIPLOCATION("DIL1:01")
+ PORT_DIPSETTING( 0x00, "Bingo Profile" )
+ PORT_DIPSETTING( 0x01, "Arcade" )
+ PORT_DIPNAME( 0x02, 0x00, "Accept 2 GBP Coin?" ) PORT_DIPLOCATION("DIL1:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( No ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Yes ) )
+ PORT_DIPNAME( 0x0C, 0x00, "Jackpot" ) PORT_DIPLOCATION("DIL1:03,04")
+ PORT_DIPSETTING( 0x04, "15 GBP" )
+ PORT_DIPSETTING( 0x00, "10 GBP" )
+ PORT_DIPSETTING( 0x08, "5 GBP" )
+ PORT_DIPNAME( 0x10, 0x00, "Hold Mode" ) PORT_DIPLOCATION("DIL1:05")
+ PORT_DIPSETTING( 0x00, "Show Hints" )
+ PORT_DIPSETTING( 0x10, "Auto Hold" )
+ PORT_DIPNAME( 0x20, 0x00, "Coin Mech Type" ) PORT_DIPLOCATION("DIL1:05")
+ PORT_DIPSETTING( 0x00, "6 Coin" )
+ PORT_DIPSETTING( 0x20, "5 Coin" )
+ PORT_DIPNAME( 0x40, 0x00, "Reel Motor Type" ) PORT_DIPLOCATION("DIL1:05")
+ PORT_DIPSETTING( 0x00, "Slim motor" )
+ PORT_DIPSETTING( 0x40, "Fat motor" )
+ PORT_DIPNAME( 0x80, 0x00, "Payout Tube" ) PORT_DIPLOCATION("DIL1:05")
+ PORT_DIPSETTING( 0x00, "20p" )
+ PORT_DIPSETTING( 0x80, "10p" )
+
+ PORT_MODIFY("DIL2")
+ PORT_DIPNAME( 0x07, 0x00, "Stake Setting" )
+ PORT_DIPSETTING( 0x00, "Not fitted / 5p" )
+ PORT_DIPSETTING( 0x01, "10p" )
+ PORT_DIPSETTING( 0x02, "20p" )
+ PORT_DIPSETTING( 0x03, "25p" )
+ PORT_DIPSETTING( 0x04, "30p" )
+ PORT_BIT(0xE0, IP_ACTIVE_HIGH, IPT_UNUSED)
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu420p )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("ORANGE1")
+ PORT_CONFNAME( 0xe0, 0x40, "Stake Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 5p" )
+ PORT_CONFSETTING( 0x20, "10p" )
+ PORT_CONFSETTING( 0x40, "20p" )
+ PORT_CONFSETTING( 0x60, "25p" )
+ PORT_CONFSETTING( 0x80, "30p" )
+ PORT_CONFSETTING( 0xa0, "40p" )
+ PORT_CONFSETTING( 0xc0, "50p" )
+ PORT_CONFSETTING( 0xe0, "1 GBP" )
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( mpu4jackpot8tkn )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("ORANGE2")
+ PORT_CONFNAME( 0x0f, 0x06, "Jackpot / Prize Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted" )
+ PORT_CONFSETTING( 0x01, "3 GBP" )
+ PORT_CONFSETTING( 0x02, "4 GBP" )
+ PORT_CONFSETTING( 0x08, "5 GBP" )
+ PORT_CONFSETTING( 0x03, "6 GBP" )
+ PORT_CONFSETTING( 0x04, "6 GBP Token" )
+ PORT_CONFSETTING( 0x05, "8 GBP" )
+ PORT_CONFSETTING( 0x06, "8 GBP Token" )
+ PORT_CONFSETTING( 0x07, "10 GBP" )
+ PORT_CONFSETTING( 0x09, "15 GBP" )
+ PORT_CONFSETTING( 0x0a, "25 GBP" )
+ PORT_CONFSETTING( 0x0b, "25 GBP (Licensed Betting Office Profile)" )
+ PORT_CONFSETTING( 0x0c, "35 GBP" )
+ PORT_CONFSETTING( 0x0d, "70 GBP" )
+ PORT_CONFSETTING( 0x0e, "Reserved" )
+ PORT_CONFSETTING( 0x0f, "Reserved" )
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( mpu4jackpot8tkn20p )
+ PORT_INCLUDE( mpu4jackpot8tkn )
+
+ PORT_MODIFY("ORANGE1")
+ PORT_CONFNAME( 0xe0, 0x40, "Stake Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 5p" )
+ PORT_CONFSETTING( 0x20, "10p" )
+ PORT_CONFSETTING( 0x40, "20p" )
+ PORT_CONFSETTING( 0x60, "25p" )
+ PORT_CONFSETTING( 0x80, "30p" )
+ PORT_CONFSETTING( 0xa0, "40p" )
+ PORT_CONFSETTING( 0xc0, "50p" )
+ PORT_CONFSETTING( 0xe0, "1 GBP" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4jackpot8tkn20p90pc )
+
+ PORT_INCLUDE( mpu4jackpot8tkn20p )
+
+ PORT_MODIFY("ORANGE2")
+ PORT_CONFNAME( 0xf0, 0xb0, "Percentage Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 68% (Invalid for UK Games)" )
+ PORT_CONFSETTING( 0x10, "70" )
+ PORT_CONFSETTING( 0x20, "72" )
+ PORT_CONFSETTING( 0x30, "74" )
+ PORT_CONFSETTING( 0x40, "76" )
+ PORT_CONFSETTING( 0x50, "78" )
+ PORT_CONFSETTING( 0x60, "80" )
+ PORT_CONFSETTING( 0x70, "82" )
+ PORT_CONFSETTING( 0x80, "84" )
+ PORT_CONFSETTING( 0x90, "86" )
+ PORT_CONFSETTING( 0xa0, "88" )
+ PORT_CONFSETTING( 0xb0, "90" )
+ PORT_CONFSETTING( 0xc0, "92" )
+ PORT_CONFSETTING( 0xd0, "94" )
+ PORT_CONFSETTING( 0xe0, "96" )
+ PORT_CONFSETTING( 0xf0, "98" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4jackpot8per )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("ORANGE2")
+ PORT_CONFNAME( 0x0f, 0x06, "Jackpot / Prize Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted" )
+ PORT_CONFSETTING( 0x01, "3 GBP" )
+ PORT_CONFSETTING( 0x02, "4 GBP" )
+ PORT_CONFSETTING( 0x08, "5 GBP" )
+ PORT_CONFSETTING( 0x03, "6 GBP" )
+ PORT_CONFSETTING( 0x04, "6 GBP Token" )
+ PORT_CONFSETTING( 0x05, "8 GBP" )
+ PORT_CONFSETTING( 0x06, "8 GBP Token" )
+ PORT_CONFSETTING( 0x07, "10 GBP" )
+ PORT_CONFSETTING( 0x09, "15 GBP" )
+ PORT_CONFSETTING( 0x0a, "25 GBP" )
+ PORT_CONFSETTING( 0x0b, "25 GBP (Licensed Betting Office Profile)" )
+ PORT_CONFSETTING( 0x0c, "35 GBP" )
+ PORT_CONFSETTING( 0x0d, "70 GBP" )
+ PORT_CONFSETTING( 0x0e, "Reserved" )
+ PORT_CONFSETTING( 0x0f, "Reserved" )
+
+ PORT_CONFNAME( 0xf0, 0x10, "Percentage Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 68% (Invalid for UK Games)" )
+ PORT_CONFSETTING( 0x10, "70" )
+ PORT_CONFSETTING( 0x20, "72" )
+ PORT_CONFSETTING( 0x30, "74" )
+ PORT_CONFSETTING( 0x40, "76" )
+ PORT_CONFSETTING( 0x50, "78" )
+ PORT_CONFSETTING( 0x60, "80" )
+ PORT_CONFSETTING( 0x70, "82" )
+ PORT_CONFSETTING( 0x80, "84" )
+ PORT_CONFSETTING( 0x90, "86" )
+ PORT_CONFSETTING( 0xa0, "88" )
+ PORT_CONFSETTING( 0xb0, "90" )
+ PORT_CONFSETTING( 0xc0, "92" )
+ PORT_CONFSETTING( 0xd0, "94" )
+ PORT_CONFSETTING( 0xe0, "96" )
+ PORT_CONFSETTING( 0xf0, "98" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4_70pc )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("ORANGE2")
+ PORT_CONFNAME( 0xf0, 0x10, "Percentage Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 68% (Invalid for UK Games)" )
+ PORT_CONFSETTING( 0x10, "70" )
+ PORT_CONFSETTING( 0x20, "72" )
+ PORT_CONFSETTING( 0x30, "74" )
+ PORT_CONFSETTING( 0x40, "76" )
+ PORT_CONFSETTING( 0x50, "78" )
+ PORT_CONFSETTING( 0x60, "80" )
+ PORT_CONFSETTING( 0x70, "82" )
+ PORT_CONFSETTING( 0x80, "84" )
+ PORT_CONFSETTING( 0x90, "86" )
+ PORT_CONFSETTING( 0xa0, "88" )
+ PORT_CONFSETTING( 0xb0, "90" )
+ PORT_CONFSETTING( 0xc0, "92" )
+ PORT_CONFSETTING( 0xd0, "94" )
+ PORT_CONFSETTING( 0xe0, "96" )
+ PORT_CONFSETTING( 0xf0, "98" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4jackpot10 )
+ PORT_INCLUDE( mpu4 )
+
+ PORT_MODIFY("ORANGE2")
+ PORT_CONFNAME( 0x0f, 0x07, "Jackpot / Prize Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted" )
+ PORT_CONFSETTING( 0x01, "3 GBP" )
+ PORT_CONFSETTING( 0x02, "4 GBP" )
+ PORT_CONFSETTING( 0x08, "5 GBP" )
+ PORT_CONFSETTING( 0x03, "6 GBP" )
+ PORT_CONFSETTING( 0x04, "6 GBP Token" )
+ PORT_CONFSETTING( 0x05, "8 GBP" )
+ PORT_CONFSETTING( 0x06, "8 GBP Token" )
+ PORT_CONFSETTING( 0x07, "10 GBP" )
+ PORT_CONFSETTING( 0x09, "15 GBP" )
+ PORT_CONFSETTING( 0x0a, "25 GBP" )
+ PORT_CONFSETTING( 0x0b, "25 GBP (Licensed Betting Office Profile)" )
+ PORT_CONFSETTING( 0x0c, "35 GBP" )
+ PORT_CONFSETTING( 0x0d, "70 GBP" )
+ PORT_CONFSETTING( 0x0e, "Reserved" )
+ PORT_CONFSETTING( 0x0f, "Reserved" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( mpu4jackpot10_20p )
+ PORT_INCLUDE( mpu4jackpot10 )
+
+ PORT_MODIFY("ORANGE1")
+ PORT_CONFNAME( 0xe0, 0x40, "Stake Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 5p" )
+ PORT_CONFSETTING( 0x20, "10p" )
+ PORT_CONFSETTING( 0x40, "20p" )
+ PORT_CONFSETTING( 0x60, "25p" )
+ PORT_CONFSETTING( 0x80, "30p" )
+ PORT_CONFSETTING( 0xa0, "40p" )
+ PORT_CONFSETTING( 0xc0, "50p" )
+ PORT_CONFSETTING( 0xe0, "1 GBP" )
+INPUT_PORTS_END
+
+INPUT_PORTS_START( grtecp )
+ PORT_START("ORANGE1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("00")// 20p level
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("01")// 100p level
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("02")// Token 1 level
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("03")// Token 2 level
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("04")
+ PORT_CONFNAME( 0xe0, 0x00, "Stake Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted / 5p" )
+ PORT_CONFSETTING( 0x20, "10p" )
+ PORT_CONFSETTING( 0x40, "20p" )
+ PORT_CONFSETTING( 0x60, "25p" )
+ PORT_CONFSETTING( 0x80, "30p" )
+ PORT_CONFSETTING( 0xa0, "40p" )
+ PORT_CONFSETTING( 0xc0, "50p" )
+ PORT_CONFSETTING( 0xe0, "1 GBP" )
+
+ PORT_START("ORANGE2")
+ PORT_CONFNAME( 0x0f, 0x00, "Jackpot / Prize Key" )
+ PORT_CONFSETTING( 0x00, "Not fitted" )
+ PORT_CONFSETTING( 0x01, "3 GBP" )
+ PORT_CONFSETTING( 0x02, "4 GBP" )
+ PORT_CONFSETTING( 0x08, "5 GBP" )
+ PORT_CONFSETTING( 0x03, "6 GBP" )
+ PORT_CONFSETTING( 0x04, "6 GBP Token" )
+ PORT_CONFSETTING( 0x05, "8 GBP" )
+ PORT_CONFSETTING( 0x06, "8 GBP Token" )
+ PORT_CONFSETTING( 0x07, "10 GBP" )
+ PORT_CONFSETTING( 0x09, "15 GBP" )
+ PORT_CONFSETTING( 0x0a, "25 GBP" )
+ PORT_CONFSETTING( 0x0b, "25 GBP (Licensed Betting Office Profile)" )
+ PORT_CONFSETTING( 0x0c, "35 GBP" )
+ PORT_CONFSETTING( 0x0d, "70 GBP" )
+ PORT_CONFSETTING( 0x0e, "Reserved" )
+ PORT_CONFSETTING( 0x0f, "Reserved" )
+
+ PORT_CONFNAME( 0xf0, 0x00, "Percentage Key" )
+ PORT_CONFSETTING( 0x00, "As Option Switches" )
+ PORT_CONFSETTING( 0x10, "70" )
+ PORT_CONFSETTING( 0x20, "72" )
+ PORT_CONFSETTING( 0x30, "74" )
+ PORT_CONFSETTING( 0x40, "76" )
+ PORT_CONFSETTING( 0x50, "78" )
+ PORT_CONFSETTING( 0x60, "80" )
+ PORT_CONFSETTING( 0x70, "82" )
+ PORT_CONFSETTING( 0x80, "84" )
+ PORT_CONFSETTING( 0x90, "86" )
+ PORT_CONFSETTING( 0xa0, "88" )
+ PORT_CONFSETTING( 0xb0, "90" )
+ PORT_CONFSETTING( 0xc0, "92" )
+ PORT_CONFSETTING( 0xd0, "94" )
+ PORT_CONFSETTING( 0xe0, "96" )
+ PORT_CONFSETTING( 0xf0, "98" )
+
+ PORT_START("BLACK1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_SERVICE) PORT_NAME("Test Button") PORT_CODE(KEYCODE_W)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_SERVICE) PORT_NAME("Refill Key") PORT_CODE(KEYCODE_R) PORT_TOGGLE
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_INTERLOCK) PORT_NAME("Cashbox (Back) Door") PORT_CODE(KEYCODE_Q) PORT_TOGGLE
+
+ PORT_START("BLACK2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Collect/Cancel")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Hold 1")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Hold 2")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_NAME("Hold 3")
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_NAME("Hi")
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_NAME("Lo")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_NAME("Exchange")
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_START1)
+
+ PORT_START("DIL1")
+ PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:03")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("DIL1:04")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0xf0, 0x00, "Target Percentage (if key not fitted)" )PORT_DIPLOCATION("DIL1:05,06,07,08")
+ PORT_DIPSETTING( 0x00, "Unset (Program Optimum)" )
+ PORT_DIPSETTING( 0x10, "70" )
+ PORT_DIPSETTING( 0x20, "72" )
+ PORT_DIPSETTING( 0x30, "74" )
+ PORT_DIPSETTING( 0x40, "76" )
+ PORT_DIPSETTING( 0x50, "78" )
+ PORT_DIPSETTING( 0x60, "80" )
+ PORT_DIPSETTING( 0x70, "82" )
+ PORT_DIPSETTING( 0x80, "84" )
+ PORT_DIPSETTING( 0x90, "86" )
+ PORT_DIPSETTING( 0xa0, "88" )
+ PORT_DIPSETTING( 0xb0, "90" )
+ PORT_DIPSETTING( 0xc0, "92" )
+ PORT_DIPSETTING( 0xd0, "94" )
+ PORT_DIPSETTING( 0xe0, "96" )
+ PORT_DIPSETTING( 0xf0, "98" )
+
+ PORT_START("DIL2")
+ PORT_DIPNAME( 0x01, 0x00, "Token Lockout when full" ) PORT_DIPLOCATION("DIL2:01")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unused )) PORT_DIPLOCATION("DIL2:02")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, "Scottish Coin Handling" ) PORT_DIPLOCATION("DIL2:03")//20p payout
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, "Out of Credit Display Inhibit" ) PORT_DIPLOCATION("DIL2:04")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x00, "OCD Audio Enable" ) PORT_DIPLOCATION("DIL2:05")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x00, "Coin Alarm Inhibit" ) PORT_DIPLOCATION("DIL2:06")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x00, "Token Refill Level Inhibit" ) PORT_DIPLOCATION("DIL2:07")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x00, "Single Credit Entry" ) PORT_DIPLOCATION("DIL2:08")
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( On ) )
+
+ PORT_START("AUX1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("0")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("1")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("2")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("3")
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("4")
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("5")
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("6")
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("7")
+
+ PORT_START("AUX2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_CUSTOM)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_COIN1) PORT_NAME("10p")//PORT_IMPULSE(5)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_COIN2) PORT_NAME("20p")//PORT_IMPULSE(5)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_COIN3) PORT_NAME("50p")//PORT_IMPULSE(5)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_COIN4) PORT_NAME("100p")//PORT_IMPULSE(5)
+INPUT_PORTS_END
+
+
+/* Common configurations */
+
+void mpu4_state::mpu4_install_mod4oki_space(address_space &space)
+{
+ space.install_readwrite_handler(0x0880, 0x0883, read8sm_delegate(*m_okicard, FUNC(mpu4_oki_sampled_sound::ic4_read)), write8sm_delegate(*m_okicard, FUNC(mpu4_oki_sampled_sound::ic4_write)));
+
+ space.install_read_handler(0x08c0, 0x08c7, read8sm_delegate(*m_okicard, FUNC(mpu4_oki_sampled_sound::ic3_read)));
+ space.install_write_handler(0x08c0, 0x08c7, write8sm_delegate(*m_okicard, FUNC(mpu4_oki_sampled_sound::ic3_write)));
+
+}
+
+
+
+void mpu4_state::mpu4_config_common()
+{
+ m_lamps.resolve();
+ m_mpu4leds.resolve();
+ m_digits.resolve();
+ m_triacs.resolve();
+ m_flutterbox.resolve();
+
+ m_ic24_timer = timer_alloc(FUNC(mpu4_state::update_ic24), this);
+
+
+ save_item(NAME( m_mmtr_data ));
+ save_item(NAME( m_ay8913_address ));
+ save_item(NAME( m_signal_50hz ));
+ save_item(NAME( m_ic4_input_b ));
+ save_item(NAME( m_aux1_input ));
+ save_item(NAME( m_aux2_input ));
+ save_item(NAME( m_IC23G1 ));
+ save_item(NAME( m_IC23G2A ));
+ save_item(NAME( m_IC23G2B ));
+ save_item(NAME( m_IC23GC ));
+ save_item(NAME( m_IC23GB ));
+ save_item(NAME( m_IC23GA ));
+
+ save_item(NAME( m_reel_flag ));
+ save_item(NAME( m_ic23_active ));
+ save_item(NAME( m_input_strobe ));
+ save_item(NAME( m_lamp_strobe ));
+ save_item(NAME( m_lamp_strobe2 ));
+ save_item(NAME( m_lamp_strobe_ext_persistence ));
+ save_item(NAME( m_led_strobe ));
+ save_item(NAME( m_ay_data ));
+ save_item(NAME( m_optic_pattern ));
+
+ save_item(NAME( m_active_reel ));
+ save_item(NAME( m_remote_meter ));
+ save_item(NAME( m_reel_mux ));
+ save_item(NAME( m_lamp_extender ));
+ save_item(NAME( m_last_b7 ));
+ save_item(NAME( m_last_latch ));
+ save_item(NAME( m_lamp_sense ));
+ save_item(NAME( m_card_live ));
+ save_item(NAME( m_led_extender ));
+ save_item(NAME( m_bwb_bank ));
+ save_item(NAME( m_default_to_low_bank ));
+
+ save_item(NAME( m_use_pia4_porta_leds ));
+ save_item(NAME( m_pia4_porta_leds_base ));
+ save_item(NAME( m_pia4_porta_leds_strobe ));
+
+ save_item(NAME( m_use_simplecard_leds ));
+ save_item(NAME( m_simplecard_leds_base ));
+ save_item(NAME( m_simplecard_leds_strobe ));
+
+ save_item(NAME( m_pageval ));
+ save_item(NAME( m_pageset ));
+ save_item(NAME( m_hopper_type ));
+ save_item(NAME( m_reels ));
+ save_item(NAME( m_chrdata ));
+ save_item(NAME( m_serial_output ));
+
+ save_item(NAME( m_numbanks ));
+
+ save_item(NAME( m_link7a_connected ));
+ save_item(NAME( m_link7b_connected ));
+
+ save_item(NAME( m_overcurrent ));
+ save_item(NAME( m_undercurrent ));
+
+ save_item(NAME( m_overcurrent_detect ));
+ save_item(NAME( m_undercurrent_detect ));
+
+ save_item(NAME( m_low_volt_detect ));
+
+ save_item(NAME( m_use_coinlocks ));
+
+ save_item(NAME( m_hack_duart_fixed_low ));
+
+ save_item(NAME( m_hopper1_opto ));
+ save_item(NAME( m_hopper2_opto ));
+
+ m_lamp_strobe_ext_persistence = 0;
+
+}
+
+MACHINE_START_MEMBER(mpu4_state, mod2)
+{
+ mpu4_config_common();
+
+ m_link7a_connected=false;
+ m_link7b_connected=true;
+}
+
+MACHINE_START_MEMBER(mpu4_state, mpu4oki)
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ mpu4_config_common();
+
+ m_link7a_connected=false;
+ m_link7b_connected=true;
+ mpu4_install_mod4oki_space(space);
+}
+
+void mpu4_state::init_m4()
+{
+ m_bwb_bank = false;
+ setup_rom_banks();
+}
+
+void mpu4_state::init_m4big()
+{
+ int size = memregion("maincpu")->bytes();
+ if (size <= 0x10000)
+ {
+ fatalerror("Error: Extended banking selected on set <=0x10000 in size\n");
+ }
+
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+
+ m_bwb_bank = true;
+ space.install_write_handler(0x0858, 0x0858, write8smo_delegate(*this, FUNC(mpu4_state::bankswitch_w)));
+ space.install_write_handler(0x0878, 0x0878, write8smo_delegate(*this, FUNC(mpu4_state::bankset_w)));
+ uint8_t *rom = memregion("maincpu")->base();
+
+ m_numbanks = size / 0x10000;
+ m_bank1->configure_entries(0, m_numbanks, &rom[0x01000], 0x10000);
+ m_numbanks--;
+
+ // some Bwb games must default to the last bank, does anything not like this
+ // behavior?
+ // some Bwb games don't work anyway tho, they seem to dislike something else
+ // about the way the regular banking behaves, not related to the CB2 stuff
+ m_bank1->set_entry(m_numbanks);
+}
+
+void mpu4_state::init_m4big_low()
+{
+ init_m4big();
+ m_default_to_low_bank = true;
+}
+
+void mpu4_state::setup_rom_banks()
+{
+ //Initialise paging for non-extended ROM space
+ uint8_t *rom = memregion("maincpu")->base();
+ membank("bank1")->configure_entries(0, 4, &rom[0x01000], 0x10000);
+ membank("bank1")->set_entry(0);
+}
+
+/* generate a 50 Hz signal (based on an RC time) */
+TIMER_DEVICE_CALLBACK_MEMBER(mpu4_state::gen_50hz)
+{
+ if (m_low_volt_detect)
+ {
+ /* Although reported as a '50Hz' signal, the fact that both rising and
+ falling edges of the pulse are used means the timer actually gives a 100Hz
+ oscillating signal.*/
+ m_signal_50hz = m_signal_50hz?0:1;
+ m_pia4->ca1_w(m_signal_50hz); /* signal is connected to IC4 CA1 */
+ }
+ update_meters();//run at 100Hz to sync with PIAs
+}
+
+
+void mpu4_state::mpu4_memmap(address_map &map)
+{
+ map(0x0000, 0x07ff).ram().share("nvram");
+// map(0x0800, 0x081f) // optional protection device lives here, see other maps
+ map(0x0850, 0x0850).rw(FUNC(mpu4_state::bankswitch_r), FUNC(mpu4_state::bankswitch_w)); /* write bank (rom page select) */
+ map(0x08e0, 0x08ef).rw(m_duart68681, FUNC(mc68681_device::read), FUNC(mc68681_device::write)); //Runs hoppers
+ map(0x0900, 0x0907).rw(m_6840ptm, FUNC(ptm6840_device::read), FUNC(ptm6840_device::write));/* PTM6840 IC2 */
+ map(0x0a00, 0x0a03).rw(m_pia3, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* PIA6821 IC3 */
+ map(0x0b00, 0x0b03).rw(m_pia4, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* PIA6821 IC4 */
+ map(0x0c00, 0x0c03).rw(m_pia5, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* PIA6821 IC5 */
+ map(0x0d00, 0x0d03).rw(m_pia6, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* PIA6821 IC6 */
+ map(0x0e00, 0x0e03).rw(m_pia7, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* PIA6821 IC7 */
+ map(0x0f00, 0x0f03).rw(m_pia8, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* PIA6821 IC8 */
+ map(0x1000, 0xffff).bankr("bank1"); /* 64k paged ROM (4 pages) */
+}
+
+void mpu4_state::mpu4_memmap_characteriser(address_map &map)
+{
+ mpu4_memmap(map);
+ map(0x0800, 0x0810).rw(m_characteriser, FUNC(mpu4_characteriser_pal::read), FUNC(mpu4_characteriser_pal::write));
+}
+
+void mpu4_state::mpu4_memmap_bootleg_characteriser(address_map &map)
+{
+ mpu4_memmap(map);
+ // a few sets use 0x840 for protection, 0x850 is where banking maps, so map up to that point
+ map(0x0800, 0x084f).rw(m_characteriser_bl, FUNC(mpu4_characteriser_bl::read), FUNC(mpu4_characteriser_bl::write));
+}
+
+void mpu4_state::mpu4_memmap_bl_characteriser_blastbank(address_map &map)
+{
+ mpu4_memmap(map);
+ map(0x0800, 0x081f).rw(m_characteriser_blastbank, FUNC(mpu4_characteriser_bl_blastbank::read), FUNC(mpu4_characteriser_bl_blastbank::write));
+}
+
+void mpu4_state::mpu4_reels(machine_config &config, uint8_t NumberOfReels, int16_t start_index, int16_t end_index)
+{
+ for(uint8_t i=0; i != NumberOfReels; i++)
+ {
+ REEL(config, m_reel[i], BARCREST_48STEP_REEL, start_index, end_index, 0x00, 2);
+ m_reel[i]->optic_handler().set([this, i](int state) {
+ if (state)
+ m_optic_pattern |= (1 << i);
+ else
+ m_optic_pattern &= ~(1 << i);
+ });
+ }
+}
+
+void mpu4_state::tr_r4(machine_config &config)
+{
+ m_reel_mux = STANDARD_REEL;
+ m_reels = 4;
+}
+
+void mpu4_state::tr_r5(machine_config &config)
+{
+ m_reel_mux = FIVE_REEL_5TO8;
+ m_reels = 5;
+}
+
+void mpu4_state::tr_r5r(machine_config &config)
+{
+ m_reel_mux = FIVE_REEL_8TO5;
+ m_reels = 5;
+}
+
+void mpu4_state::tr_r5a(machine_config &config)
+{
+ m_reel_mux = FIVE_REEL_3TO6;
+ m_reels = 5;
+}
+
+void mpu4_state::tr_r6(machine_config &config)
+{
+ m_reel_mux = SIX_REEL_1TO8;
+ m_reels = 6;
+}
+
+void mpu4_state::tr_r6a(machine_config &config)
+{
+ m_reel_mux = SIX_REEL_5TO8;
+ m_reels = 6;
+}
+
+void mpu4_state::tr_r7(machine_config &config)
+{
+ m_reel_mux = SEVEN_REEL;
+ m_reels = 7;
+}
+
+void mpu4_state::tr_r8(machine_config &config)
+{
+ m_reel_mux = STANDARD_REEL;
+ m_reels = 8;
+}
+
+void mpu4_state::tr_rt1(machine_config &config)
+{
+ mpu4_reels(config, m_reels, 1, 3);
+}
+
+void mpu4_state::tr_rt2(machine_config &config)
+{
+ mpu4_reels(config, m_reels, 4, 12);
+}
+
+void mpu4_state::tr_rt3(machine_config &config)
+{
+ mpu4_reels(config, m_reels, 96, 3);
+}
+
+void mpu4_state::tr_lps(machine_config &config)
+{
+ m_lamp_extender = SMALL_CARD;
+}
+
+void mpu4_state::tr_lpla(machine_config &config)
+{
+ m_lamp_extender = LARGE_CARD_A;
+}
+
+void mpu4_state::tr_lplb(machine_config &config)
+{
+ m_lamp_extender = LARGE_CARD_B;
+}
+
+void mpu4_state::tr_lplc(machine_config &config)
+{
+ m_lamp_extender = LARGE_CARD_C;
+}
+
+void mpu4_state::tr_lds(machine_config &config)
+{
+ m_led_extender = SIMPLE_CARD;
+}
+
+void mpu4_state::tr_lda(machine_config &config)
+{
+ m_led_extender = CARD_A;
+}
+
+void mpu4_state::tr_ldb(machine_config &config)
+{
+ m_led_extender = CARD_B;
+}
+
+void mpu4_state::tr_ldc(machine_config &config)
+{
+ m_led_extender = CARD_C;
+}
+
+void mpu4_state::tr_ht(machine_config &config)
+{
+ m_hopper_type = TUBES;
+}
+
+void mpu4_state::tr_hda(machine_config &config)
+{
+ m_hopper_type = HOPPER_DUART_A;
+ m_hopper1->dispense_handler().set("duart68681", FUNC(mc68681_device::ip5_w));
+}
+
+void mpu4_state::tr_hdb(machine_config &config)
+{
+ m_hopper_type = HOPPER_DUART_B;
+ m_hopper1->dispense_handler().set("duart68681", FUNC(mc68681_device::ip5_w));
+}
+
+void mpu4_state::tr_hdc(machine_config &config)
+{
+ m_hopper_type = HOPPER_DUART_C;
+ m_hopper1->dispense_handler().set("duart68681", FUNC(mc68681_device::ip5_w));
+ m_hopper2->dispense_handler().set("duart68681", FUNC(mc68681_device::ip6_w));
+}
+
+void mpu4_state::tr_hna(machine_config &config)
+{
+ m_hopper_type = HOPPER_NONDUART_A;
+}
+
+void mpu4_state::tr_hnb(machine_config &config)
+{
+ m_hopper_type = HOPPER_NONDUART_B;
+}
+
+void mpu4_state::tr_htw(machine_config &config)
+{
+ m_hopper_type = HOPPER_TWIN_HOPPER;
+}
+
+void mpu4_state::tr_over(machine_config &config)
+{
+ m_overcurrent_detect = true;
+}
+
+void mpu4_state::tr_lvdoff(machine_config &config)
+{
+ m_low_volt_detect = false;
+}
+
+void mpu4_state::tr_p4l(machine_config &config)
+{
+ m_use_pia4_porta_leds = true;
+}
+
+void mpu4_state::tr_scardl(machine_config &config)
+{
+ m_use_simplecard_leds = true;
+}
+
+
+void mpu4_state::mpu4_common(machine_config &config)
+{
+ TIMER(config, "50hz").configure_periodic(FUNC(mpu4_state::gen_50hz), attotime::from_hz(100));
+
+ MSC1937(config, m_vfd);
+ /* 6840 PTM */
+ PTM6840(config, m_6840ptm, MPU4_MASTER_CLOCK / 4);
+ m_6840ptm->set_external_clocks(0, 0, 0);
+ m_6840ptm->o1_callback().set(FUNC(mpu4_state::ic2_o1_callback));
+ m_6840ptm->o2_callback().set(FUNC(mpu4_state::ic2_o2_callback));
+ m_6840ptm->o3_callback().set(FUNC(mpu4_state::ic2_o3_callback));
+ m_6840ptm->irq_callback().set(FUNC(mpu4_state::cpu0_irq));
+
+ PIA6821(config, m_pia3);
+ m_pia3->writepa_handler().set(FUNC(mpu4_state::pia_ic3_porta_w));
+ m_pia3->writepb_handler().set(FUNC(mpu4_state::pia_ic3_portb_w));
+ m_pia3->ca2_handler().set(FUNC(mpu4_state::pia_ic3_ca2_w));
+ m_pia3->cb2_handler().set(FUNC(mpu4_state::pia_ic3_cb2_w));
+ m_pia3->irqa_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia3->irqb_handler().set(FUNC(mpu4_state::cpu0_irq));
+
+ PIA6821(config, m_pia4);
+ m_pia4->readpb_handler().set(FUNC(mpu4_state::pia_ic4_portb_r));
+ m_pia4->writepa_handler().set(FUNC(mpu4_state::pia_ic4_porta_w));
+ m_pia4->writepb_handler().set(FUNC(mpu4_state::pia_ic4_portb_w));
+ m_pia4->ca2_handler().set(FUNC(mpu4_state::pia_ic4_ca2_w));
+ m_pia4->cb2_handler().set(FUNC(mpu4_state::pia_ic4_cb2_w));
+ m_pia4->irqa_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia4->irqb_handler().set(FUNC(mpu4_state::cpu0_irq));
+
+ PIA6821(config, m_pia5);
+ m_pia5->readpa_handler().set(FUNC(mpu4_state::pia_ic5_porta_r));
+ m_pia5->readpb_handler().set(FUNC(mpu4_state::pia_ic5_portb_r));
+ m_pia5->writepa_handler().set(FUNC(mpu4_state::pia_ic5_porta_w));
+ m_pia5->writepb_handler().set(FUNC(mpu4_state::pia_ic5_portb_w));
+ m_pia5->ca2_handler().set(m_dataport, FUNC(bacta_datalogger_device::write_txd));
+ m_pia5->cb2_handler().set(FUNC(mpu4_state::pia_ic5_cb2_w));
+ m_pia5->irqa_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia5->irqb_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia5->set_port_a_input_overrides_output_mask(0x40); // needed for m4madhse
+
+ PIA6821(config, m_pia6);
+ m_pia6->writepa_handler().set(FUNC(mpu4_state::pia_ic6_porta_w));
+ m_pia6->writepb_handler().set(FUNC(mpu4_state::pia_ic6_portb_w));
+ m_pia6->ca2_handler().set(FUNC(mpu4_state::pia_ic6_ca2_w));
+ m_pia6->cb2_handler().set(FUNC(mpu4_state::pia_ic6_cb2_w));
+ m_pia6->irqa_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia6->irqb_handler().set(FUNC(mpu4_state::cpu0_irq));
+
+ PIA6821(config, m_pia7);
+ m_pia7->readpb_handler().set(FUNC(mpu4_state::pia_ic7_portb_r));
+ m_pia7->writepa_handler().set(FUNC(mpu4_state::pia_ic7_porta_w));
+ m_pia7->writepb_handler().set(FUNC(mpu4_state::pia_ic7_portb_w));
+ m_pia7->ca2_handler().set(FUNC(mpu4_state::pia_ic7_ca2_w));
+ m_pia7->cb2_handler().set(FUNC(mpu4_state::pia_ic7_cb2_w));
+ m_pia7->irqa_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia7->irqb_handler().set(FUNC(mpu4_state::cpu0_irq));
+
+ PIA6821(config, m_pia8);
+ m_pia8->readpa_handler().set(FUNC(mpu4_state::pia_ic8_porta_r));
+ m_pia8->writepb_handler().set(FUNC(mpu4_state::pia_ic8_portb_w));
+ m_pia8->ca2_handler().set(FUNC(mpu4_state::pia_ic8_ca2_w));
+ m_pia8->cb2_handler().set(FUNC(mpu4_state::pia_ic8_cb2_w));
+ m_pia8->irqa_handler().set(FUNC(mpu4_state::cpu0_irq));
+ m_pia8->irqb_handler().set(FUNC(mpu4_state::cpu0_irq));
+
+ METERS(config, m_meters, 0).set_number(8);
+
+ BACTA_DATALOGGER(config, m_dataport, 0);
+ m_dataport->rxd_handler().set(FUNC(mpu4_state::dataport_rxd));
+
+ HOPPER(config, m_hopper1, attotime::from_msec(100));
+
+
+ SPEAKER(config, "mono").front_center();
+
+ DAC_1BIT(config, m_alarmdac, 0);
+ m_alarmdac->add_route(ALL_OUTPUTS, "mono", 0.50);
+}
+
+/***********************************************************************************************
+
+ Base config with no sound
+
+***********************************************************************************************/
+
+void mpu4_state::mpu4base(machine_config &config)
+{
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state, mod2)
+ MCFG_MACHINE_RESET_OVERRIDE(mpu4_state, mpu4)
+ MC6809(config, m_maincpu, MPU4_MASTER_CLOCK); // MC68B09P
+ m_maincpu->set_addrmap(AS_PROGRAM, &mpu4_state::mpu4_memmap);
+
+ mpu4_common(config);
+
+
+ NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
+
+ MC68681(config, m_duart68681, MPU4_MASTER_CLOCK); // ?
+
+ config.set_default_layout(layout_mpu4);
+}
+
+/***********************************************************************************************
+
+ Configs for Mod2
+
+ TODO: mod2 should eventually become a subclass
+
+***********************************************************************************************/
+
+void mpu4_state::mod2_f(machine_config &config)
+{
+ mpu4base(config);
+ AY8913(config, m_ay8913, MPU4_MASTER_CLOCK/4);
+
+ m_ay8913->set_flags(AY8910_SINGLE_OUTPUT);
+ m_ay8913->set_resistors_load(820, 0, 0);
+ m_ay8913->add_route(ALL_OUTPUTS, "mono", 1.0);
+}
+
+void mpu4_state::mod2_no_bacta_f(machine_config &config)
+{
+ mod2_f(config);
+ config.device_remove("dataport");
+ m_pia5->ca2_handler().set(FUNC(mpu4_state::dataport_rxd));
+}
+
+void mpu4_state::mod2_cheatchr_f(machine_config &config)
+{
+ mod2_f(config);
+
+ m_maincpu->set_addrmap(AS_PROGRAM, &mpu4_state::mpu4_memmap_characteriser);
+
+ MPU4_CHARACTERISER_PAL(config, m_characteriser, 0);
+ m_characteriser->set_cpu_tag("maincpu");
+ m_characteriser->set_allow_6809_cheat(true);
+ m_characteriser->set_lamp_table(nullptr);
+}
+
+/***********************************************************************************************
+
+ Configs for Mod4 with OKI
+
+ TODO: OKI is its own device, should mod4oki eventually become a subclass
+
+***********************************************************************************************/
+
+// standard reel setup
+
+void mpu4_state::mod4oki_f(machine_config &config)
+{
+ mpu4base(config);
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state, mpu4oki)
+
+ MPU4_OKI_SAMPLED_SOUND(config, m_okicard, MPU4_MASTER_CLOCK/4);
+ m_okicard->add_route(ALL_OUTPUTS, "mono", 1.0);
+
+ m_okicard->cb2_handler().set(FUNC(mpu4_state::pia_gb_cb2_w));
+
+}
+
+void mpu4_state::mod4oki_no_bacta_f(machine_config &config)
+{
+ mod4oki_f(config);
+ config.device_remove("dataport");
+ m_pia5->ca2_handler().set(FUNC(mpu4_state::dataport_rxd));
+}
+
+void mpu4_state::mod4oki_cheatchr_f(machine_config &config)
+{
+ mod4oki_f(config);
+
+ m_maincpu->set_addrmap(AS_PROGRAM, &mpu4_state::mpu4_memmap_characteriser);
+
+ MPU4_CHARACTERISER_PAL(config, m_characteriser, 0);
+ m_characteriser->set_cpu_tag("maincpu");
+ m_characteriser->set_allow_6809_cheat(true);
+ m_characteriser->set_lamp_table(nullptr);
+}