summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/mpu4.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/mpu4.cpp')
-rw-r--r--src/mame/machine/mpu4.cpp3184
1 files changed, 3184 insertions, 0 deletions
diff --git a/src/mame/machine/mpu4.cpp b/src/mame/machine/mpu4.cpp
new file mode 100644
index 00000000000..6165b3f6d8c
--- /dev/null
+++ b/src/mame/machine/mpu4.cpp
@@ -0,0 +1,3184 @@
+// license:BSD-3-Clause
+// copyright-holders:James Wallace
+// thanks-to:Chris Wren, Tony Friery, MFME
+/* MPU4 hardware emulation
+ for sets see the various includes prefixed 'mpu4'
+*/
+
+/* Note 19/07/11 DH
+ - added lots of sets
+
+ these are mostly unsorted and need to be split into clones
+ the original source of these was a mess, assume things to be mislabled, bad, duplicated, or otherwise
+ badly organized. a lot of work is needed to sort them out, especially the Barcrest sets! Some of this
+ stuff MIGHT be in the wrong driver, or missing roms (sound roms especially)
+*/
+
+/***********************************************************************************************************
+ Barcrest MPU4 highly preliminary driver.
+ MAME Driver J. Wallace and Haze
+
+ Thanks to Chris Wren and MFME for documentation.
+
+ This is the core driver, no video specific stuff should go in here.
+ This driver holds all the mechanical games.
+
+ 06-2011: Fixed boneheaded interface glitch that was causing samples to not be cancelled correctly.
+ Added the ability to read each segment of an LED display separately, this may be necessary for some
+ games that use them as surrogate lamp lines.
+ New persistence 'hack' to stop light flicker for the small extender.
+ 05-2011: Add better OKI emulation
+ 04-2011: More accurate gamball code, fixed ROM banking (Project Amber), added BwB CHR simulator (Amber)
+ This is still a hard coded system, but significantly different to Barcrest's version.
+ Started adding support for the Crystal Gaming program card, and the link keys for setting parameters.
+ 03-2011: Lamp timing fixes, support for all known expansion cards added.
+ 01-2011: Adding the missing 'OKI' sound card, and documented it, but it needs a 6376 rewrite.
+ 09-2007: Haze: Added Deal 'Em video support.
+ 03-08-2007: J Wallace: Removed audio filter for now, since sound is more accurate without them.
+ Connect 4 now has the right sound.
+ 03-07-2007: J Wallace: Several major changes, including input relabelling, and system timer improvements.
+ 06-2007: Atari Ace, many cleanups and optimizations of I/O routines
+ 09-06-2007: J Wallace: Fixed 50Hz detection circuit.
+ 17-02-2007: J Wallace: Added Deal 'Em - still needs some work.
+ 10-02-2007: J Wallace: Improved input timing.
+ 30-01-2007: J Wallace: Characteriser rewritten to run the 'extra' data needed by some games.
+ 24-01-2007: J Wallace: With thanks to Canonman and HIGHWAYMAN/System 80, I was able to confirm a seemingly
+ ghastly misuse of a PIA is actually on the real hardware. This fixes the meters.
+
+See http://agemame.mameworld.info/techinfo/mpu4.php for Information.
+
+--- 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 used 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' ??
+ |
+ +--------> 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
+ | | | 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
+
+TODO: - Distinguish door switches using manual
+ - Complete stubs for hoppers (needs slightly better 68681 emulation, and new 'hoppers' device emulation)
+ - It seems that the MPU4 core program relies on some degree of persistence when switching strobes and handling
+ writes to the various hardware ports. This explains the occasional lamping/LED blackout and switching bugs
+ For now, we're ignoring any extra writes to strobes, as the alternative is to assign a timer to *everything* and
+ start modelling the individual hysteresis curves of filament lamps.
+ - Fix BwB characteriser, need to be able to calculate stabiliser bytes. Anyone fancy reading 6809 source?
+ - Strange bug in Andy's Great Escape - Mystery nudge sound effect is not played, mpu4 latches in silence instead (?)
+
+ - Per game inputs not currently supported, may need to do something about DIPs, inverted lines etc.
+***********************************************************************************************************/
+#include "emu.h"
+#include "includes/mpu4.h"
+
+#include "video/awpvid.h" //Fruit Machines Only
+
+#include "speaker.h"
+
+#include "mpu4.lh"
+#include "mpu4ext.lh"
+
+
+/*
+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(int data)
+{
+ int lamp_ext_data,column,i;
+ 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
+ //Once again, lamp persistences would take care of this, but we can't do that
+ {
+ for (i = 0; i < 5; i++)
+ {
+ output().set_lamp_value((8*column)+i+128,((lamp_ext_data & (1 << i)) != 0));
+ }
+ }
+ m_lamp_strobe_ext_persistence ++;
+ if ((m_lamp_strobe_ext_persistence == 3)||(m_lamp_strobe_ext!=column))
+ {
+ m_lamp_strobe_ext_persistence = 0;
+ m_lamp_strobe_ext=column;
+ }
+}
+
+void mpu4_state::lamp_extend_large(int data,int column,int active)
+{
+ int lampbase,i,bit7;
+
+ m_lamp_sense = 0;
+ bit7 = data & 0x80;
+ if ( bit7 != m_last_b7 )
+ {
+ m_card_live = 1;
+ //depending on bit 7, we can access one of two 'blocks' of 64 lamps
+ lampbase = bit7 ? 0 : 64;
+ if ( data & 0x3f )
+ {
+ m_lamp_sense = 1;
+ }
+ if ( active )
+ {
+ if (m_lamp_strobe_ext != column)
+ {
+ for (i = 0; i < 8; i++)
+ {//CHECK, this includes bit 7
+ output().set_lamp_value((8*column)+i+128+lampbase ,(data & (1 << i)) != 0);
+ }
+ m_lamp_strobe_ext = column;
+ }
+ }
+ m_last_b7 = bit7;
+ }
+ else
+ {
+ m_card_live = 0;
+ }
+}
+
+void mpu4_state::led_write_latch(int latch, int data, int column)
+{
+ int diff,i,j;
+
+ diff = (latch ^ m_last_latch) & latch;
+ column = 7 - column; // like main board, these are wired up in reverse
+ data = ~data;//inverted drive lines?
+
+ for(i=0; i<5; i++)
+ {
+ if (diff & (1<<i))
+ {
+ column += i;
+ }
+ }
+ for(j=0; j<8; j++)
+ {
+ output().set_indexed_value("mpu4led",(8*column)+j,(data & (1 << j)) !=0);
+ }
+ output().set_digit_value(column * 8, data);
+
+ m_last_latch = diff;
+}
+
+
+void mpu4_state::update_meters()
+{
+ int meter;
+ int data = ((m_mmtr_data & 0x7f) | m_remote_meter);
+ switch (m_reel_mux)
+ {
+ case STANDARD_REEL:
+ // Change nothing
+ break;
+
+ case FIVE_REEL_5TO8:
+ m_reel4->update(((data >> 4) & 0x0f));
+ data = (data & 0x0F); //Strip reel data from meter drives, leaving active elements
+ awp_draw_reel(machine(),"reel5", *m_reel4);
+ break;
+
+ case FIVE_REEL_8TO5:
+ m_reel4->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_reel4);
+ break;
+
+ case FIVE_REEL_3TO6:
+ m_reel4->update(((data >> 2) & 0x0f));
+ data = 0x00; //Strip all reel data from meter drives
+ awp_draw_reel(machine(),"reel5", *m_reel4);
+ break;
+
+ case SIX_REEL_1TO8:
+ m_reel4->update( data & 0x0f);
+ m_reel5->update((data >> 4) & 0x0f);
+ data = 0x00; //Strip all reel data from meter drives
+ awp_draw_reel(machine(),"reel5", *m_reel4);
+ awp_draw_reel(machine(),"reel6", *m_reel5);
+ break;
+
+ case SIX_REEL_5TO8:
+ m_reel4->update(((data >> 4) & 0x0f));
+ data = 0x00; //Strip all reel data from meter drives
+ awp_draw_reel(machine(),"reel5", *m_reel4);
+ break;
+
+ case SEVEN_REEL:
+ m_reel0->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_reel0);
+ 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
+ output().set_value("flutterbox", data & 0x80);
+ data &= ~0x80; //Strip flutterbox data from meter drives
+ break;
+ }
+
+ m_meters->update(7, (data & 0x80));
+ for (meter = 0; meter < 4; meter ++)
+ {
+ m_meters->update(meter, (data & (1 << meter)));
+ }
+ if (m_reel_mux == STANDARD_REEL)
+ {
+ for (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_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;
+
+ m_prot_col = 0;
+ m_chr_counter = 0;
+ m_chr_value = 0;
+
+
+ {
+ if (m_numbanks)
+ m_bank1->set_entry(m_numbanks);
+
+ m_maincpu->reset();
+ }
+}
+
+
+/* 6809 IRQ handler */
+WRITE_LINE_MEMBER(mpu4_state::cpu0_irq)
+{
+ /* The PIA and PTM IRQ lines are all connected to a common PCB track, leading directly to the 6809 IRQ line. */
+ int 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_link7a_connected) //7B = IRQ, 7A = FIRQ, both = NMI
+ {
+ m_maincpu->set_input_line(M6809_IRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE);
+ LOG(("6809 int%d \n", combined_state));
+ }
+ else
+ {
+ m_maincpu->set_input_line(M6809_FIRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE);
+ LOG(("6809 fint%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.
+*/
+WRITE8_MEMBER(mpu4_state::bankswitch_w)
+{
+// printf("bankswitch_w %02x\n", data);
+
+ // m_pageset is never even set??
+ m_pageval = (data & 0x03);
+ m_bank1->set_entry((m_pageval + (m_pageset ? 4 : 0)) & m_numbanks);
+}
+
+
+READ8_MEMBER(mpu4_state::bankswitch_r)
+{
+ return m_bank1->entry();
+}
+
+
+WRITE8_MEMBER(mpu4_state::bankset_w)
+{
+// printf("bankset_w %02x\n", data);
+
+ // m_pageset is never even set??
+
+ 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 */
+WRITE_LINE_MEMBER(mpu4_state::ic2_o1_callback)
+{
+ m_6840ptm->set_c2(state); /* copy output value to IC2 c2
+ this output is the clock for timer2 */
+ /* 1200Hz System interrupt timer */
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::ic2_o2_callback)
+{
+ 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);
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::ic2_o3_callback)
+{
+ /* 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_6840ptm->set_c1(state);
+}
+
+/* 6821 PIA handlers */
+/* IC3, lamp data lines + alpha numeric display */
+WRITE8_MEMBER(mpu4_state::pia_ic3_porta_w)
+{
+ int i;
+ 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.
+
+ for (i = 0; i < 8; i++)
+ {
+ output().set_lamp_value((8*m_input_strobe)+i, ((data & (1 << i)) !=0));
+ }
+ m_lamp_strobe = m_input_strobe;
+ }
+ }
+}
+
+WRITE8_MEMBER(mpu4_state::pia_ic3_portb_w)
+{
+ int i;
+ 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)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ output().set_lamp_value((8*m_input_strobe)+i+64, ((data & (1 << i)) !=0));
+ }
+ m_lamp_strobe2 = m_input_strobe;
+ }
+
+ if (m_led_lamp)
+ {
+ /* Some games (like Connect 4) use 'programmable' LED displays, built from light display lines in section 2. */
+ /* These are mostly low-tech machines, where such wiring proved cheaper than an extender card */
+ /* TODO: replace this with 'segment' lamp masks, to make it more generic */
+ uint8_t pled_segs[2] = {0,0};
+
+ static const int lamps1[8] = { 106, 107, 108, 109, 104, 105, 110, 133 };
+ static const int lamps2[8] = { 114, 115, 116, 117, 112, 113, 118, 119 };
+
+ for (i = 0; i < 8; i++)
+ {
+ if (output().get_lamp_value(lamps1[i])) pled_segs[0] |= (1 << i);
+ if (output().get_lamp_value(lamps2[i])) pled_segs[1] |= (1 << i);
+ }
+
+ output().set_digit_value(8,pled_segs[0]);
+ output().set_digit_value(9,pled_segs[1]);
+ }
+ }
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic3_ca2_w)
+{
+ LOG_IC3(("%s: IC3 PIA Write CA2 (alpha data), %02X\n", machine().describe_context(),state));
+ m_vfd->data(state);
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic3_cb2_w)
+{
+ 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(int 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=1;
+ ic24_output(0);
+ m_ic24_timer->adjust(attotime::from_double(duration));
+ }
+ }
+}
+
+
+void mpu4_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_IC24:
+ m_ic23_active=0;
+ ic24_output(1);
+ break;
+ }
+}
+
+
+/* IC4, 7 seg leds, 50Hz timer reel sensors, current sensors */
+WRITE8_MEMBER(mpu4_state::pia_ic4_porta_w)
+{
+ int i;
+ if(m_ic23_active)
+ {
+ if (((m_lamp_extender == NO_EXTENDER)||(m_lamp_extender == SMALL_CARD)||(m_lamp_extender == LARGE_CARD_C))&& (m_led_extender == NO_EXTENDER))
+ {
+ if(m_led_strobe != m_input_strobe)
+ {
+ for(i=0; i<8; i++)
+ {
+ output().set_indexed_value("mpu4led",((7 - m_input_strobe) * 8) +i,(data & (1 << i)) !=0);
+ }
+ output().set_digit_value(7 - m_input_strobe,data);
+ }
+ m_led_strobe = m_input_strobe;
+ }
+ }
+}
+
+WRITE8_MEMBER(mpu4_state::pia_ic4_portb_w)
+{
+ 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];
+ }
+}
+
+READ8_MEMBER(mpu4_state::pia_ic4_portb_r)
+{
+ /// TODO: this shouldn't be clocked from a read callback
+ if ( m_serial_data )
+ {
+ m_ic4_input_b |= 0x80;
+ m_pia4->cb1_w(1);
+ }
+ else
+ {
+ m_ic4_input_b &= ~0x80;
+ m_pia4->cb1_w(0);
+ }
+
+ if (!m_reel_mux)
+ {
+ if ( m_optic_pattern & 0x01 ) m_ic4_input_b |= 0x40; /* reel A tab */
+ else m_ic4_input_b &= ~0x40;
+
+ if ( m_optic_pattern & 0x02 ) m_ic4_input_b |= 0x20; /* reel B tab */
+ else m_ic4_input_b &= ~0x20;
+
+ if ( m_optic_pattern & 0x04 ) m_ic4_input_b |= 0x10; /* reel C tab */
+ else m_ic4_input_b &= ~0x10;
+
+ if ( m_optic_pattern & 0x08 ) m_ic4_input_b |= 0x08; /* reel D tab */
+ else m_ic4_input_b &= ~0x08;
+
+ }
+ else
+ {
+ if (m_optic_pattern & (1<<m_active_reel))
+ {
+ m_ic4_input_b |= 0x08;
+ }
+ else
+ {
+ m_ic4_input_b &= ~0x08;
+ }
+ }
+ if ( m_signal_50hz ) m_ic4_input_b |= 0x04; /* 50 Hz */
+ else m_ic4_input_b &= ~0x04;
+
+ if (m_ic4_input_b & 0x02)
+ {
+ m_ic4_input_b &= ~0x02;
+ }
+ else
+ {
+ m_ic4_input_b |= 0x02; //Pulse the overcurrent line with every read to show the CPU each lamp has lit
+ }
+ #ifdef UNUSED_FUNCTION
+ if ( lamp_undercurrent ) m_ic4_input_b |= 0x01;
+ #endif
+
+ LOG_IC3(("%s: IC4 PIA Read of Port B %x\n",machine().describe_context(),m_ic4_input_b));
+ return m_ic4_input_b;
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic4_ca2_w)
+{
+ LOG_IC3(("%s: IC4 PIA Write CA (input MUX strobe /LED B), %02X\n", machine().describe_context(),state));
+
+ m_IC23GB = state;
+ ic23_update();
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic4_cb2_w)
+{
+ LOG_IC3(("%s: IC4 PIA Write CA (input MUX strobe /LED B), %02X\n", machine().describe_context(),state));
+ m_reel_flag=state;
+}
+
+/* IC5, AUX ports, coin lockouts and AY sound chip select (MODs below 4 only) */
+READ8_MEMBER(mpu4_state::pia_ic5_porta_r)
+{
+ if (m_lamp_extender == LARGE_CARD_A)
+ {
+ 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 == HOPPER_NONDUART_A)
+ {
+/* if (hopper1_active)
+ {
+ 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;
+ if (m_aux1_invert)
+ {
+ return ~tempinput;
+ }
+ else
+ {
+ return tempinput;
+ }
+}
+
+WRITE8_MEMBER(mpu4_state::pia_ic5_porta_w)
+{
+ int i;
+ if (m_hopper == HOPPER_NONDUART_A)
+ {
+ //opto line
+ //hopper1_drive_sensor(data&0x10);
+ }
+ switch (m_lamp_extender)
+ {
+ case NO_EXTENDER:
+ if (m_led_extender == CARD_B)
+ {
+ led_write_latch(data & 0x1f, m_pia4->a_output(),m_input_strobe);
+ }
+ else if ((m_led_extender != CARD_A)&&(m_led_extender != NO_EXTENDER))
+ {
+ for(i=0; i<8; i++)
+ {
+ output().set_indexed_value("mpu4led",((m_input_strobe + 8) * 8) +i,(data & (1 << i)) !=0);
+ }
+ output().set_digit_value((m_input_strobe+8),data);
+ }
+ 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 ((m_ic23_active) && m_card_live)
+ {
+ for(i=0; i<8; i++)
+ {
+ output().set_indexed_value("mpu4led",(((8*(m_last_b7 >>7))+ m_input_strobe) * 8) +i,(~data & (1 << i)) !=0);
+ }
+ output().set_digit_value(((8*(m_last_b7 >>7))+m_input_strobe),~data);
+ }
+ break;
+
+ case LARGE_CARD_C:
+ lamp_extend_large(data,m_input_strobe,m_ic23_active);
+ break;
+ }
+ if (m_reel_mux == SIX_REEL_5TO8)
+ {
+ m_reel4->update( data &0x0F);
+ m_reel5->update((data >> 4)&0x0F);
+ awp_draw_reel(machine(),"reel5", *m_reel4);
+ awp_draw_reel(machine(),"reel6", *m_reel5);
+ }
+ else
+ if (m_reel_mux == SEVEN_REEL)
+ {
+ m_reel1->update( data &0x0F);
+ m_reel2->update((data >> 4)&0x0F);
+ awp_draw_reel(machine(),"reel2", *m_reel1);
+ awp_draw_reel(machine(),"reel3", *m_reel2);
+ }
+
+ if (core_stricmp(machine().system().name, "m4gambal") == 0)
+ {
+ /* The 'Gamball' device is a unique piece of mechanical equipment, designed to
+ provide a truly fair hi-lo gamble for an AWP. Functionally, it consists of
+ a ping-pong ball or similar enclosed in the machine's backbox, on a platform with 12
+ holes. When the low 4 bytes of AUX1 are triggered, this fires the ball out from the
+ hole it's currently in, to land in another. Landing in the same hole causes the machine to
+ refire the ball. The ball detection is done by the high 4 bytes of AUX1.
+ Here we call the MAME RNG, once to pick a row, once to pick from the four pockets within it. We
+ then trigger the switches corresponding to the correct number. This appears to be the best way
+ of making the game fair, short of simulating the physics of a bouncing ball ;)*/
+ if (data & 0x0f)
+ {
+ switch ((machine().rand()>>5) % 0x3)
+ {
+ case 0x00: //Top row
+ switch (machine().rand() & 0x3)
+ {
+ case 0x00: //7
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0xa0;
+ break;
+
+ case 0x01://4
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0xb0;
+ break;
+
+ case 0x02://9
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0xc0;
+ break;
+
+ case 0x03://8
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0xd0;
+ break;
+ }
+
+ case 0x01: //Middle row - note switches don't match pattern
+ switch (machine().rand() & 0x3)
+ {
+ case 0x00://12
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x40;
+ break;
+
+ case 0x01://1
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x50;
+ break;
+
+ case 0x02://11
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x80;
+ break;
+
+ case 0x03://2
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x90;
+ break;
+ }
+
+ case 0x02: //Bottom row
+ switch (machine().rand() & 0x3)
+ {
+ case 0x00://5
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x00;
+ break;
+
+ case 0x01://10
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x10;
+ break;
+
+ case 0x02://3
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x20;
+ break;
+
+ case 0x03://6
+ m_aux1_input = (m_aux1_input & 0x0f);
+ m_aux1_input|= 0x30;
+ break;
+ }
+ }
+ }
+ }
+}
+
+WRITE8_MEMBER(mpu4_state::pia_ic5_portb_w)
+{
+ if (m_hopper == HOPPER_NONDUART_B)
+ {
+ //hopper1_drive_motor(data &0x01) motor
+ //hopper1_drive_sensor(data &0x08) opto
+ }
+ if (m_led_extender == CARD_A)
+ {
+ led_write_latch(data & 0x07, m_pia4->a_output(),m_input_strobe);
+ }
+
+}
+READ8_MEMBER(mpu4_state::pia_ic5_portb_r)
+{
+ if (m_hopper == HOPPER_NONDUART_B)
+ {/*
+ if (hopper1_active)
+ {
+ m_aux2_input |= 0x08;
+ }
+ else
+ {
+ m_aux2_input &= ~0x08;
+ }*/
+ }
+
+ LOG(("%s: IC5 PIA Read of Port B (coin input AUX2)\n",machine().describe_context()));
+ 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;
+ if (m_aux2_invert)
+ {
+ return ~tempinput;
+ }
+ else
+ {
+ return tempinput;
+ }
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic5_ca2_w)
+{
+ LOG(("%s: IC5 PIA Write CA2 (Serial Tx) %2x\n",machine().describe_context(),state));
+ m_serial_data = state;
+}
+
+
+/* ---------------------------------------
+ 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.
+
+PSG function selection:
+-----------------------
+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(device_t *device)
+{
+ ay8910_device *ay8910 = machine().device<ay8910_device>("ay8913");
+ if (!ay8910) return;
+
+ pia6821_device *pia = downcast<pia6821_device *>(device);
+ if (!pia->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 */
+ ay8910->data_w(generic_space(), 0, 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.*/
+ ay8910->address_w(generic_space(), 0, m_pia6->a_output());
+ LOG(("AY Chip Select \n"));
+ break;
+
+ default:
+ LOG(("AY Chip error \n"));
+ break;
+ }
+ }
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic5_cb2_w)
+{
+ update_ay(m_pia5);
+}
+
+
+/* IC6, Reel A and B and AY registers (MODs below 4 only) */
+WRITE8_MEMBER(mpu4_state::pia_ic6_portb_w)
+{
+ 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_reel3->update( data &0x0F);
+ m_reel4->update((data >> 4)&0x0F);
+ awp_draw_reel(machine(),"reel4", *m_reel3);
+ awp_draw_reel(machine(),"reel5", *m_reel4);
+ }
+ else if (m_reels)
+ {
+ m_reel0->update( data &0x0F);
+ m_reel1->update((data >> 4)&0x0F);
+ awp_draw_reel(machine(),"reel1", *m_reel0);
+ awp_draw_reel(machine(),"reel2", *m_reel1);
+ }
+}
+
+
+WRITE8_MEMBER(mpu4_state::pia_ic6_porta_w)
+{
+ LOG(("%s: IC6 PIA Write A %2x\n", machine().describe_context(),data));
+ if (m_mod_number <4)
+ {
+ m_ay_data = data;
+ update_ay(m_pia6);
+ }
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic6_ca2_w)
+{
+ LOG(("%s: IC6 PIA write CA2 %2x (AY8913 BC1)\n", machine().describe_context(),state));
+ if (m_mod_number <4)
+ {
+ if ( state ) m_ay8913_address |= 0x01;
+ else m_ay8913_address &= ~0x01;
+ update_ay(m_pia6);
+ }
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic6_cb2_w)
+{
+ LOG(("%s: IC6 PIA write CB2 %2x (AY8913 BCDIR)\n", machine().describe_context(),state));
+ if (m_mod_number <4)
+ {
+ if ( state ) m_ay8913_address |= 0x02;
+ else m_ay8913_address &= ~0x02;
+ update_ay(m_pia6);
+ }
+}
+
+
+/* IC7 Reel C and D, mechanical meters/Reel E and F, input strobe bit A */
+WRITE8_MEMBER(mpu4_state::pia_ic7_porta_w)
+{
+ 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_reel5->update( data &0x0F);
+ m_reel6->update((data >> 4)&0x0F);
+ awp_draw_reel(machine(),"reel6", *m_reel5);
+ awp_draw_reel(machine(),"reel7", *m_reel7);
+ }
+ else if (m_reels)
+ {
+ m_reel2->update( data &0x0F);
+ m_reel3->update((data >> 4)&0x0F);
+ awp_draw_reel(machine(),"reel3", *m_reel2);
+ awp_draw_reel(machine(),"reel4", *m_reel3);
+ }
+}
+
+WRITE8_MEMBER(mpu4_state::pia_ic7_portb_w)
+{
+ if (m_hopper == HOPPER_DUART_A)
+ {
+ //duart write data
+ }
+ else if (m_hopper == HOPPER_NONDUART_A)
+ {
+ //hoppr1_drive_motor(data & 0x10);
+ }
+
+ m_mmtr_data = data;
+}
+
+READ8_MEMBER(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
+
+ int combined_meter = m_meters->GetActivity(0) | m_meters->GetActivity(1) |
+ m_meters->GetActivity(2) | m_meters->GetActivity(3) |
+ m_meters->GetActivity(4) | m_meters->GetActivity(5) |
+ m_meters->GetActivity(6) | m_meters->GetActivity(7);
+
+ if(combined_meter)
+ {
+ return 0x80;
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic7_ca2_w)
+{
+ 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();
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic7_cb2_w)
+{
+ m_remote_meter = state?0x80:0x00;
+}
+
+
+/* IC8, Inputs, TRIACS, alpha clock */
+READ8_MEMBER(mpu4_state::pia_ic8_porta_r)
+{
+ 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);
+ if ( (m_input_strobe == 2) && (m_door_invert ==1) )
+ {
+ return ((m_port_mux[m_input_strobe])->read() ^ 0x01);
+ }
+ else
+ {
+ return (m_port_mux[m_input_strobe])->read();
+ }
+}
+
+
+WRITE8_MEMBER(mpu4_state::pia_ic8_portb_w)
+{
+ if (m_hopper == HOPPER_DUART_B)
+ {
+// duart.drive_sensor(data & 0x04, data & 0x01, 0, 0);
+ }
+ else if (m_hopper == HOPPER_DUART_C)
+ {
+// duart.drive_sensor(data & 0x04, data & 0x01, data & 0x04, data & 0x02);
+ }
+ int i;
+ LOG_IC8(("%s: IC8 PIA Port B Set to %2x (OUTPUT PORT, TRIACS)\n", machine().describe_context(),data));
+ for (i = 0; i < 8; i++)
+ {
+ output().set_indexed_value("triac", i, data & (1 << i));
+ }
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic8_ca2_w)
+{
+ 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();
+}
+
+
+WRITE_LINE_MEMBER(mpu4_state::pia_ic8_cb2_w)
+{
+ LOG_IC8(("%s: IC8 PIA write CB2 (alpha clock) %02X\n", machine().describe_context(), state & 0xFF));
+
+ // DM Data pin B
+
+ m_vfd->sclk(!state);
+}
+
+// universal sampled sound program card PCB 683077
+// Sampled sound card, using a PIA and PTM for timing and data handling
+WRITE8_MEMBER(mpu4_state::pia_gb_porta_w)
+{
+ LOG_SS(("%s: GAMEBOARD: PIA Port A Set to %2x\n", machine().describe_context(),data));
+ m_msm6376->write(space, 0, data);
+}
+
+WRITE8_MEMBER(mpu4_state::pia_gb_portb_w)
+{
+ int changed = m_expansion_latch^data;
+
+ LOG_SS(("%s: GAMEBOARD: PIA Port B Set to %2x\n", machine().describe_context(),data));
+
+ if ( changed & 0x20)
+ { // digital volume clock line changed
+ if ( !(data & 0x20) )
+ { // changed from high to low,
+ if ( !(data & 0x10) )//down
+ {
+ if ( m_global_volume < 32 ) m_global_volume++; //steps unknown
+ }
+ else
+ {//up
+ if ( m_global_volume > 0 ) m_global_volume--;
+ }
+
+ {
+ float percent = (32-m_global_volume)/32.0;
+ m_msm6376->set_output_gain(0, percent);
+ m_msm6376->set_output_gain(1, percent);
+ }
+ }
+ }
+ m_msm6376->ch2_w(data&0x02);
+ m_msm6376->st_w(data&0x01);
+}
+READ8_MEMBER(mpu4_state::pia_gb_portb_r)
+{
+ LOG_SS(("%s: GAMEBOARD: PIA Read of Port B\n",machine().describe_context()));
+ int data=0;
+ // b7 NAR - we can load another address into Channel 1
+ // b6, 1 = OKI ready, 0 = OKI busy
+ // b5, vol clock
+ // b4, 1 = Vol down, 0 = Vol up
+ //
+
+ if ( m_msm6376->nar_r() ) data |= 0x80;
+ else data &= ~0x80;
+
+ if ( m_msm6376->busy_r() ) data |= 0x40;
+ else data &= ~0x40;
+
+ return ( data | m_expansion_latch );
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_gb_ca2_w)
+{
+ LOG_SS(("%s: GAMEBOARD: OKI RESET data = %02X\n", machine().describe_context(), state));
+
+// reset line
+}
+
+WRITE_LINE_MEMBER(mpu4_state::pia_gb_cb2_w)
+{
+ //Some BWB games use this to drive the bankswitching
+ if (m_bwb_bank)
+ {
+ //printf("pia_gb_cb2_w %d\n", state);
+ m_pageval = state;
+ m_bank1->set_entry((m_pageval + (m_pageset ? 4 : 0)) & m_numbanks);
+ }
+}
+
+//Sampled sound timer
+/*
+The MSM6376 sound chip is configured in a slightly strange way, to enable dynamic
+sample rate changes (8Khz, 10.6 Khz, 16 KHz) by varying the clock.
+According to the BwB programmer's guide, the formula is:
+MSM6376 clock frequency:-
+freq = (1720000/((t3L+1)(t3H+1)))*[(t3H(T3L+1)+1)/(2(t1+1))]
+where [] means rounded up integer,
+t3L is the LSB of Clock 3,
+t3H is the MSB of Clock 3,
+and t1 is the initial value in clock 1.
+*/
+
+//O3 -> G1 O1 -> c2 o2 -> c1
+
+/* This is a bit of a cheat - since we don't clock into the OKI chip directly, we need to
+calculate the oscillation frequency in advance. We're running the timer for interrupt
+purposes, but the frequency calculation is done by plucking the values out as they are written.*/
+WRITE8_MEMBER(mpu4_state::ic3ss_w)
+{
+ device_t *ic3ss = machine().device("ptm_ic3ss");
+ downcast<ptm6840_device *>(ic3ss)->write(offset,data);
+
+ if (offset == 3)
+ {
+ m_t1 = data;
+ }
+ if (offset == 6)
+ {
+ m_t3h = data;
+ }
+ if (offset == 7)
+ {
+ m_t3l = data;
+ }
+
+ float num = (1720000/((m_t3l + 1)*(m_t3h + 1)));
+ float denom1 = ((m_t3h *(m_t3l + 1)+ 1)/(2*(m_t1 + 1)));
+
+ int denom2 = denom1 + 0.5f;//need to round up, this gives same precision as chip
+ int freq=num*denom2;
+
+ if (freq)
+ {
+ m_msm6376->set_frequency(freq);
+ }
+}
+
+/* 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, 0x08, "Out of Credit Display Inhibit" ) PORT_DIPLOCATION("DIL2:04") // many games need this on to boot
+ 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_SPECIAL)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_SPECIAL)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_SPECIAL)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_SPECIAL)
+ 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
+
+
+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( 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( 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( 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_SPECIAL)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_SPECIAL)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_SPECIAL)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_SPECIAL)
+ 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
+
+
+
+/*
+Characteriser (CHR)
+
+As built, the CHR is a PAL which can perform basic bit manipulation according to
+an as yet unknown unique key. However, the programmers decided to best use this protection device in read/write/compare
+cycles, storing almost the entire 'hidden' data table in the ROMs in plain sight. Only later rebuilds by BwB
+avoided this 'feature' of the development kit, and will need a different setup.
+
+This information has been used to generate the CHR tables loaded by the programs, until a key can be determined.
+
+For most Barcrest games, the following method was used:
+
+The initial 'PALTEST' routine as found in the Barcrest programs simply writes the first 'call' to the CHR space,
+to read back the 'response'. There is no attempt to alter the order or anything else, just
+a simple runthrough of the entire data table. The only 'catch' in this is to note that the CHR chip always scans
+through the table starting at the last accessed data value, unless 00 is used to reset to the beginning. This is obviously
+a simplification, in fact the PAL does bit manipulation with some latching.
+
+However, a final 8 byte row, that controls the lamp matrix is not tested - to date, no-one outside of Barcrest knows
+how this is generated, and currently trial and error is the only sensible method. It is noted that the default,
+of all 00, is sometimes the correct answer, particularly in non-Barcrest use of the CHR chip, though when used normally,
+there are again fixed call values.
+
+Apparently, just before the characteriser is checked bit 1 at 0x61DF is checked and if zero the characteriser
+check is bypassed. This may be something to look at for prototype ROMs and hacks.
+
+*/
+
+
+WRITE8_MEMBER(mpu4_state::characteriser_w)
+{
+ int x;
+ int call=data;
+ LOG_CHR_FULL(("%04x Characteriser write offset %02X data %02X", space.device().safe_pcbase(),offset,data));
+ if (!m_current_chr_table)
+ {
+ logerror("No Characteriser Table @ %04x\n", space.device().safe_pcbase());
+ return;
+ }
+
+
+
+ if (offset == 0)
+ {
+ {
+ if (call == 0)
+ {
+ m_prot_col = 0;
+ }
+ else
+ {
+ for (x = m_prot_col; x < 64; x++)
+ {
+ if (m_current_chr_table[(x)].call == call)
+ {
+ m_prot_col = x;
+ LOG_CHR(("Characteriser find column %02X\n",m_prot_col));
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (offset == 2)
+ {
+ LOG_CHR(("Characteriser write 2 data %02X\n",data));
+ // Rather than the search strategy, we can map the calls directly here. Note that they are hex versions of the square number series
+ switch (call)
+ {
+ case 0x00:
+ m_lamp_col = 0;
+ break;
+
+ case 0x01:
+ m_lamp_col = 1;
+ break;
+
+ case 0x04:
+ m_lamp_col = 2;
+ break;
+
+ case 0x09:
+ m_lamp_col = 3;
+ break;
+
+ case 0x10:
+ m_lamp_col = 4;
+ break;
+
+ case 0x19:
+ m_lamp_col = 5;
+ break;
+
+ case 0x24:
+ m_lamp_col = 6;
+ break;
+
+ case 0x31:
+ m_lamp_col = 7;
+ break;
+ }
+ LOG_CHR(("Characteriser find 2 column %02X\n",m_lamp_col));
+ }
+}
+
+
+READ8_MEMBER(mpu4_state::characteriser_r)
+{
+ if (!m_current_chr_table)
+ {
+ logerror("No Characteriser Table @ %04x", space.device().safe_pcbase());
+
+ /* a cheat ... many early games use a standard check */
+ int addr = space.device().state().state_int(M6809_X);
+ if ((addr>=0x800) && (addr<=0xfff)) return 0x00; // prevent recursion, only care about ram/rom areas for this cheat.
+
+ uint8_t ret = space.read_byte(addr);
+ logerror(" (returning %02x)",ret);
+
+ logerror("\n");
+
+ return ret;
+ }
+
+ LOG_CHR(("Characteriser read offset %02X \n",offset));
+ if (offset == 0)
+ {
+ LOG_CHR(("Characteriser read data %02X \n",m_current_chr_table[m_prot_col].response));
+ return m_current_chr_table[m_prot_col].response;
+ }
+
+ if (offset == 3)
+ {
+ LOG_CHR(("Characteriser read data off 3 %02X \n",m_current_chr_table[m_lamp_col+64].response));
+ return m_current_chr_table[m_lamp_col+64].response;
+ }
+ return 0;
+}
+
+/*
+BwB Characteriser (CHR)
+
+The BwB method of protection is considerably different to the Barcrest one, with any
+incorrect behaviour manifesting in ridiculously large payouts. The hardware is the
+same, however the main weakness of the software has been eliminated.
+
+In fact, the software seems deliberately designed to mislead, but is (fortunately for
+us) prone to similar weaknesses that allow a per game solution.
+
+Project Amber performed a source analysis (available on request) which appears to make things work.
+Said weaknesses (A Cheats Guide according to Project Amber)
+
+The common initialisation sequence is "00 04 04 0C 0C 1C 14 2C 5C 2C"
+ 0 1 2 3 4 5 6 7 8
+Using debug search for the first read from said string (best to find it first).
+
+At this point, the X index on the CPU is at the magic number address.
+
+The subsequent calls for each can be found based on the magic address
+
+ (0) = ( (BWBMagicAddress))
+ (1) = ( (BWBMagicAddress + 1))
+ (2) = ( (BWBMagicAddress + 2))
+ (3) = ( (BWBMagicAddress + 4))
+ (4) = ( (BWBMagicAddress - 5))
+ (5) = ( (BWBMagicAddress - 4))
+ (6) = ( (BWBMagicAddress - 3))
+ (7) = ( (BWBMagicAddress - 2))
+ (8) = ( (BWBMagicAddress - 1))
+
+These return the standard init sequence as above.
+
+For ease of understanding, we use three tables, one holding the common responses
+and two holding the appropriate call and response pairs for the two stages of operation
+*/
+
+
+WRITE8_MEMBER(mpu4_state::bwb_characteriser_w)
+{
+ int x;
+ int call=data;
+ LOG_CHR_FULL(("%04x Characteriser write offset %02X data %02X \n", space.device().safe_pcbase(),offset,data));
+ if (!m_current_chr_table)
+ fatalerror("No Characteriser Table @ %04x\n", space.device().safe_pcbase());
+
+ if ((offset & 0x3f)== 0)//initialisation is always at 0x800
+ {
+ if (!m_chr_state)
+ {
+ m_chr_state=1;
+ m_chr_counter=0;
+ }
+ if (call == 0)
+ {
+ m_init_col ++;
+ }
+ else
+ {
+ m_init_col =0;
+ }
+ }
+
+ m_chr_value = machine().rand();
+ for (x = 0; x < 4; x++)
+ {
+ if (m_current_chr_table[(x)].call == call)
+ {
+ if (x == 0) // reinit
+ {
+ m_bwb_return = 0;
+ }
+ m_chr_value = bwb_chr_table_common[(m_bwb_return)];
+ m_bwb_return++;
+ break;
+ }
+ }
+}
+
+READ8_MEMBER(mpu4_state::bwb_characteriser_r)
+{
+ LOG_CHR(("Characteriser read offset %02X \n",offset));
+
+
+ if (offset ==0)
+ {
+ switch (m_chr_counter)
+ {
+ case 6:
+ case 13:
+ case 20:
+ case 27:
+ case 34:
+ return m_bwb_chr_table1[(((m_chr_counter + 1) / 7) - 1)].response;
+
+ default:
+ if (m_chr_counter > 34)
+ {
+ m_chr_counter = 35;
+ m_chr_state = 2;
+ }
+ m_chr_counter ++;
+ return m_chr_value;
+ }
+ }
+ else
+ {
+ return m_chr_value;
+ }
+}
+
+/* Common configurations */
+
+WRITE8_MEMBER(mpu4_state::mpu4_ym2413_w)
+{
+ ym2413_device *ym2413 = machine().device<ym2413_device>("ym2413");
+ if (ym2413) ym2413->write(space,offset,data);
+}
+
+READ8_MEMBER(mpu4_state::mpu4_ym2413_r)
+{
+// ym2413_device *ym2413 = machine().device<ym2413_device>("ym2413");
+// if (ym2413) return ym2413->read(space,offset);
+ return 0xff;
+}
+
+
+void mpu4_state::mpu4_install_mod4yam_space(address_space &space)
+{
+ space.install_read_handler(0x0880, 0x0882, read8_delegate(FUNC(mpu4_state::mpu4_ym2413_r),this));
+ space.install_write_handler(0x0880, 0x0881, write8_delegate(FUNC(mpu4_state::mpu4_ym2413_w),this));
+}
+
+void mpu4_state::mpu4_install_mod4oki_space(address_space &space)
+{
+ pia6821_device *pia_ic4ss = space.machine().device<pia6821_device>("pia_ic4ss");
+ ptm6840_device *ptm_ic3ss = space.machine().device<ptm6840_device>("ptm_ic3ss");
+
+ space.install_readwrite_handler(0x0880, 0x0883, read8_delegate(FUNC(pia6821_device::read), pia_ic4ss), write8_delegate(FUNC(pia6821_device::write), pia_ic4ss));
+ space.install_read_handler(0x08c0, 0x08c7, read8_delegate(FUNC(ptm6840_device::read), ptm_ic3ss));
+ space.install_write_handler(0x08c0, 0x08c7, write8_delegate(FUNC(mpu4_state::ic3ss_w),this));
+}
+
+void mpu4_state::mpu4_install_mod4bwb_space(address_space &space)
+{
+ space.install_readwrite_handler(0x0810, 0x0810, read8_delegate(FUNC(mpu4_state::bwb_characteriser_r),this),write8_delegate(FUNC(mpu4_state::bwb_characteriser_w),this));
+ mpu4_install_mod4oki_space(space);
+}
+
+
+void mpu4_state::mpu4_config_common()
+{
+ m_ic24_timer = timer_alloc(TIMER_IC24);
+ m_lamp_strobe_ext_persistence = 0;
+}
+
+MACHINE_START_MEMBER(mpu4_state,mod2)
+{
+ mpu4_config_common();
+
+ m_link7a_connected=0;
+ m_mod_number=2;
+}
+
+MACHINE_START_MEMBER(mpu4_state,mpu4yam)
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ mpu4_config_common();
+
+ m_link7a_connected=0;
+ m_mod_number=4;
+ mpu4_install_mod4yam_space(space);
+}
+
+MACHINE_START_MEMBER(mpu4_state,mpu4oki)
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ mpu4_config_common();
+
+ m_link7a_connected=0;
+ m_mod_number=4;
+ mpu4_install_mod4oki_space(space);
+}
+
+MACHINE_START_MEMBER(mpu4_state,mpu4bwb)
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ mpu4_config_common();
+
+ m_link7a_connected=0;
+ m_mod_number=4;
+ mpu4_install_mod4bwb_space(space);
+}
+
+MACHINE_START_MEMBER(mpu4_state,mpu4cry)
+{
+ mpu4_config_common();
+
+ m_link7a_connected=0;
+ m_mod_number=4;
+}
+
+/* CHR Tables */
+
+static mpu4_chr_table andycp10c_data[72] = {
+{0x00, 0x00},{0x1a, 0x14},{0x04, 0x04},{0x10, 0x54},{0x18, 0x4c},{0x0f, 0x20},{0x13, 0x50},{0x1b, 0x44},
+{0x03, 0x5c},{0x07, 0x78},{0x17, 0x70},{0x1d, 0x48},{0x36, 0x6c},{0x35, 0x60},{0x2b, 0x14},{0x28, 0x48},
+{0x39, 0x2c},{0x21, 0x6c},{0x22, 0x6c},{0x25, 0x28},{0x2c, 0x64},{0x29, 0x10},{0x31, 0x08},{0x34, 0x6c},
+{0x0a, 0x24},{0x1f, 0x5c},{0x06, 0x78},{0x0e, 0x34},{0x1c, 0x00},{0x12, 0x50},{0x1e, 0x00},{0x0d, 0x50},
+{0x14, 0x0c},{0x0a, 0x6c},{0x19, 0x2c},{0x15, 0x60},{0x06, 0x54},{0x0f, 0x00},{0x08, 0x58},{0x1b, 0x74},
+{0x1e, 0x00},{0x04, 0x14},{0x01, 0x4c},{0x0c, 0x60},{0x18, 0x1c},{0x1a, 0x74},{0x11, 0x4c},{0x0b, 0x64},
+{0x03, 0x5c},{0x17, 0x78},{0x10, 0x78},{0x1d, 0x78},{0x0e, 0x34},{0x07, 0x44},{0x12, 0x54},{0x09, 0x40},
+{0x0d, 0x50},{0x1f, 0x48},{0x16, 0x6c},{0x05, 0x28},{0x13, 0x60},{0x1c, 0x14},{0x02, 0x4c},{0x00, 0x00},
+{0x00, 0x04},{0x01, 0x58},{0x04, 0x14},{0x09, 0x58},{0x10, 0x50},{0x19, 0x1c},{0x24, 0x10},{0x31, 0x10}
+};
+
+static mpu4_chr_table ccelbr_data[72] = {
+{0x00, 0x00},{0x1a, 0x84},{0x04, 0x8c},{0x10, 0xb8},{0x18, 0x74},{0x0f, 0x80},{0x13, 0x1c},{0x1b, 0xb4},
+{0x03, 0xd8},{0x07, 0x74},{0x17, 0x00},{0x1d, 0xd4},{0x36, 0xc8},{0x35, 0x78},{0x2b, 0xa4},{0x28, 0x4c},
+{0x39, 0xe0},{0x21, 0xdc},{0x22, 0xf4},{0x25, 0x88},{0x2c, 0x78},{0x29, 0x24},{0x31, 0x84},{0x34, 0xcc},
+{0x0a, 0xb8},{0x1f, 0x74},{0x06, 0x90},{0x0e, 0x48},{0x1c, 0xa0},{0x12, 0x1c},{0x1e, 0x24},{0x0d, 0x94},
+{0x14, 0xc8},{0x0a, 0xb8},{0x19, 0x74},{0x15, 0x00},{0x06, 0x94},{0x0f, 0x48},{0x08, 0x30},{0x1b, 0x90},
+{0x1e, 0x08},{0x04, 0x60},{0x01, 0xd4},{0x0c, 0x58},{0x18, 0xf4},{0x1a, 0x18},{0x11, 0x74},{0x0b, 0x80},
+{0x03, 0xdc},{0x17, 0x74},{0x10, 0xd0},{0x1d, 0x58},{0x0e, 0x24},{0x07, 0x94},{0x12, 0xd8},{0x09, 0x34},
+{0x0d, 0x90},{0x1f, 0x58},{0x16, 0xf4},{0x05, 0x88},{0x13, 0x38},{0x1c, 0x24},{0x02, 0xd4},{0x00, 0x00},
+{0x00, 0x00},{0x01, 0x50},{0x04, 0x00},{0x09, 0x50},{0x10, 0x10},{0x19, 0x40},{0x24, 0x04},{0x31, 0x00}
+};
+
+
+static mpu4_chr_table gmball_data[72] = {
+{0x00, 0x00},{0x1a, 0x0c},{0x04, 0x50},{0x10, 0x90},{0x18, 0xb0},{0x0f, 0x38},{0x13, 0xd4},{0x1b, 0xa0},
+{0x03, 0xbc},{0x07, 0xd4},{0x17, 0x30},{0x1d, 0x90},{0x36, 0x38},{0x35, 0xc4},{0x2b, 0xac},{0x28, 0x70},
+{0x39, 0x98},{0x21, 0xdc},{0x22, 0xdc},{0x25, 0x54},{0x2c, 0x80},{0x29, 0xb4},{0x31, 0x38},{0x34, 0xcc},
+{0x0a, 0xe8},{0x1f, 0xf8},{0x06, 0xd4},{0x0e, 0x30},{0x1c, 0x00},{0x12, 0x84},{0x1e, 0x2c},{0x0d, 0xc8},
+{0x14, 0xf8},{0x0a, 0x4c},{0x19, 0x58},{0x15, 0xd4},{0x06, 0xa8},{0x0f, 0x78},{0x08, 0x44},{0x1b, 0x0c},
+{0x1e, 0x48},{0x04, 0x50},{0x01, 0x98},{0x0c, 0xd4},{0x18, 0xb0},{0x1a, 0xa0},{0x11, 0xa4},{0x0b, 0x3c},
+{0x03, 0xdc},{0x17, 0xd4},{0x10, 0xb8},{0x1d, 0xd4},{0x0e, 0x30},{0x07, 0x88},{0x12, 0xe0},{0x09, 0x24},
+{0x0d, 0x8c},{0x1f, 0xf8},{0x16, 0xcc},{0x05, 0x70},{0x13, 0x90},{0x1c, 0x20},{0x02, 0x9c},{0x00, 0x00},
+{0x00, 0x00},{0x01, 0x18},{0x04, 0x08},{0x09, 0x10},{0x10, 0x00},{0x19, 0x18},{0x24, 0x08},{0x31, 0x00}
+};
+
+
+
+
+static mpu4_chr_table grtecp_data[72] = {
+{0x00, 0x00},{0x1a, 0x84},{0x04, 0xa4},{0x10, 0xac},{0x18, 0x70},{0x0f, 0x80},{0x13, 0x2c},{0x1b, 0xc0},
+{0x03, 0xbc},{0x07, 0x5c},{0x17, 0x5c},{0x1d, 0x5c},{0x36, 0xdc},{0x35, 0x5c},{0x2b, 0xcc},{0x28, 0x68},
+{0x39, 0xd0},{0x21, 0xb8},{0x22, 0xdc},{0x25, 0x54},{0x2c, 0x08},{0x29, 0x58},{0x31, 0x54},{0x34, 0x90},
+{0x0a, 0xb8},{0x1f, 0x5c},{0x06, 0x5c},{0x0e, 0x44},{0x1c, 0x84},{0x12, 0xac},{0x1e, 0xe0},{0x0d, 0xbc},
+{0x14, 0xcc},{0x0a, 0xe8},{0x19, 0x70},{0x15, 0x00},{0x06, 0x8c},{0x0f, 0x70},{0x08, 0x00},{0x1b, 0x84},
+{0x1e, 0xa4},{0x04, 0xa4},{0x01, 0xbc},{0x0c, 0xdc},{0x18, 0x5c},{0x1a, 0xcc},{0x11, 0xe8},{0x0b, 0xe0},
+{0x03, 0xbc},{0x17, 0x4c},{0x10, 0xc8},{0x1d, 0xf8},{0x0e, 0xd4},{0x07, 0xa8},{0x12, 0x68},{0x09, 0x40},
+{0x0d, 0x0c},{0x1f, 0xd8},{0x16, 0xdc},{0x05, 0x54},{0x13, 0x98},{0x1c, 0x44},{0x02, 0x9c},{0x00, 0x00},
+{0x00, 0x00},{0x01, 0x18},{0x04, 0x00},{0x09, 0x18},{0x10, 0x08},{0x19, 0x10},{0x24, 0x00},{0x31, 0x00}
+};
+
+static mpu4_chr_table oldtmr_data[72] = {
+{0x00, 0x00},{0x1a, 0x90},{0x04, 0xc0},{0x10, 0x54},{0x18, 0xa4},{0x0f, 0xf0},{0x13, 0x64},{0x1b, 0x90},
+{0x03, 0xe4},{0x07, 0xd4},{0x17, 0x60},{0x1d, 0xb4},{0x36, 0xc0},{0x35, 0x70},{0x2b, 0x80},{0x28, 0x74},
+{0x39, 0xa4},{0x21, 0xf4},{0x22, 0xe4},{0x25, 0xd0},{0x2c, 0x64},{0x29, 0x10},{0x31, 0x20},{0x34, 0x90},
+{0x0a, 0xe4},{0x1f, 0xf4},{0x06, 0xc4},{0x0e, 0x70},{0x1c, 0x00},{0x12, 0x14},{0x1e, 0x00},{0x0d, 0x14},
+{0x14, 0xa0},{0x0a, 0xf0},{0x19, 0x64},{0x15, 0x10},{0x06, 0x84},{0x0f, 0x70},{0x08, 0x00},{0x1b, 0x90},
+{0x1e, 0x40},{0x04, 0x90},{0x01, 0xe4},{0x0c, 0xf4},{0x18, 0x64},{0x1a, 0x90},{0x11, 0x64},{0x0b, 0x90},
+{0x03, 0xe4},{0x17, 0x50},{0x10, 0x24},{0x1d, 0xb4},{0x0e, 0xe0},{0x07, 0xd4},{0x12, 0xe4},{0x09, 0x50},
+{0x0d, 0x04},{0x1f, 0xb4},{0x16, 0xc0},{0x05, 0xd0},{0x13, 0x64},{0x1c, 0x90},{0x02, 0xe4},{0x00, 0x00},
+{0x00, 0x00},{0x01, 0x00},{0x04, 0x00},{0x09, 0x00},{0x10, 0x00},{0x19, 0x10},{0x24, 0x00},{0x31, 0x00}
+};
+
+static const bwb_chr_table blsbys_data1[5] = {
+//Magic number 724A
+
+// PAL Codes
+// 0 1 2 3 4 5 6 7 8
+// ?? ?? 20 0F 24 3C 36 27 09
+
+ {0x67},{0x17},{0x0f},{0x24},{0x3c},
+};
+
+static mpu4_chr_table blsbys_data[8] = {
+{0xEF, 0x02},{0x81, 0x00},{0xCE, 0x00},{0x00, 0x2e},
+{0x06, 0x20},{0xC6, 0x0f},{0xF8, 0x24},{0x8E, 0x3c},
+};
+
+// set percentage and other options. 2e 20 0f
+// PAL Codes
+// 0 1 2 3 4 5 6 7 8
+// 42 2E 20 0F 24 3C 36 27 09
+ // 6 0 7 0 8 0 7 0 0 8
+//request 36 42 27 42 09 42 27 42 42 09
+//verify 00 04 04 0C 0C 1C 14 2C 5C 2C
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_low_volt_alt)
+{
+ //Some games can't use the 50Hz circuit to check voltage issues, handle it here
+ m_low_volt_detect_disable =1;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_aux1_invert)
+{
+ m_aux1_invert =1;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_aux2_invert)
+{
+ m_aux2_invert =1;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_door_invert)
+{
+ m_aux2_invert =1;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_small_extender)
+{
+ m_lamp_extender=SMALL_CARD;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_large_extender_a)
+{
+ m_lamp_extender=LARGE_CARD_A;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_large_extender_b)
+{
+ m_lamp_extender=LARGE_CARD_B;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_large_extender_c)
+{
+ m_lamp_extender=LARGE_CARD_C;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_hopper_tubes)
+{
+ m_hopper = TUBES;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_hopper_duart_a)
+{
+ m_hopper = HOPPER_DUART_A;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_hopper_duart_b)
+{
+ m_hopper = HOPPER_DUART_B;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_hopper_duart_c)
+{
+ m_hopper = HOPPER_DUART_C;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_hopper_nonduart_a)
+{
+ m_hopper = HOPPER_NONDUART_A;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_hopper_nonduart_b)
+{
+ m_hopper = HOPPER_NONDUART_B;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_led_a)
+{
+ m_led_extender = CARD_A;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_led_b)
+{
+ m_led_extender = CARD_B;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_led_c)
+{
+ m_led_extender = CARD_C;
+}
+
+//TODO: Replace with standard six reels once sets are sorted out - is really six_reel_std
+DRIVER_INIT_MEMBER(mpu4_state,m4altreels)
+{
+ m_reel_mux=SIX_REEL_1TO8;
+ m_reels = 6;
+ DRIVER_INIT_CALL(m4default_banks);
+}
+DRIVER_INIT_MEMBER(mpu4_state,m4default_reels)
+{
+ m_reel_mux=STANDARD_REEL;
+ m_reels = 4;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_five_reel_std)
+{
+ m_reel_mux=FIVE_REEL_5TO8;
+ m_reels = 5;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_five_reel_rev)
+{
+ m_reel_mux=FIVE_REEL_8TO5;
+ m_reels = 5;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_five_reel_alt)
+{
+ m_reel_mux=FIVE_REEL_3TO6;
+ m_reels = 5;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_six_reel_std)
+{
+ m_reel_mux=SIX_REEL_1TO8;
+ m_reels = 6;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_six_reel_alt)
+{
+ m_reel_mux=SIX_REEL_5TO8;
+ m_reels = 6;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_seven_reel)
+{
+ m_reel_mux=SEVEN_REEL;
+ m_reels = 7;
+}
+
+
+DRIVER_INIT_MEMBER(mpu4_state,m4_andycp10c)
+{
+ DRIVER_INIT_CALL(m4default);
+ DRIVER_INIT_CALL(m4_small_extender);
+ m_current_chr_table = andycp10c_data;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m_oldtmr)
+{
+ DRIVER_INIT_CALL(m4_six_reel_std);
+ DRIVER_INIT_CALL(m4default_banks);
+
+ m_current_chr_table = oldtmr_data;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m_ccelbr)
+{
+ DRIVER_INIT_CALL(m4default);
+ m_current_chr_table = ccelbr_data;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4gambal)
+{
+ DRIVER_INIT_CALL(m4default);
+ m_current_chr_table = gmball_data;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m_grtecp)
+{
+ m_current_chr_table = grtecp_data;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m_blsbys)
+{
+ m_bwb_bank=1;
+ DRIVER_INIT_CALL(m4_five_reel_std);
+ m_bwb_chr_table1 = blsbys_data1;
+ m_current_chr_table = blsbys_data;
+ DRIVER_INIT_CALL(m4default_big);
+}
+
+
+DRIVER_INIT_MEMBER(mpu4_state,m4default_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);
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4default_alt)
+{
+ m_reel_mux=STANDARD_REEL;
+ m_reels = 8;
+ DRIVER_INIT_CALL(m4default_banks);
+
+ m_bwb_bank=0;
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m4default)
+{
+ DRIVER_INIT_CALL(m4default_reels);
+ m_bwb_bank=0;
+ m_aux1_invert=0;
+ m_aux2_invert=0;
+ m_door_invert=0;
+ DRIVER_INIT_CALL(m4default_banks);
+}
+
+
+DRIVER_INIT_MEMBER(mpu4_state,m4default_big)
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ m_aux1_invert=0;
+ m_aux2_invert=0;
+ m_door_invert=0;
+
+ int size = memregion( "maincpu" )->bytes();
+ if (size<=0x10000)
+ {
+ printf("Error: Extended banking selected on set <=0x10000 in size, ignoring\n");
+ DRIVER_INIT_CALL(m4default_reels);
+ m_bwb_bank=0;
+ DRIVER_INIT_CALL(m4default_banks);
+ }
+ else
+ {
+ m_bwb_bank=1;
+ space.install_write_handler(0x0858, 0x0858, write8_delegate(FUNC(mpu4_state::bankswitch_w),this));
+ space.install_write_handler(0x0878, 0x0878, write8_delegate(FUNC(mpu4_state::bankset_w),this));
+ 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);
+ }
+}
+
+
+
+
+
+READ8_MEMBER(mpu4_state::crystal_sound_r)
+{
+ return machine().rand();
+}
+//this may be a YMZ280B
+WRITE8_MEMBER(mpu4_state::crystal_sound_w)
+{
+ printf("crystal_sound_w %02x\n",data);
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,m_frkstn)
+{
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ DRIVER_INIT_CALL(m4default_big);
+ space.install_read_handler(0x0880, 0x0880, read8_delegate(FUNC(mpu4_state::crystal_sound_r),this));
+ space.install_write_handler(0x0881, 0x0881, write8_delegate(FUNC(mpu4_state::crystal_sound_w),this));
+}
+
+// thanks to Project Amber for descramble information
+static void descramble_crystal( uint8_t* region, int start, int end, uint8_t extra_xor)
+{
+ for (int i=start;i<end;i++)
+ {
+ uint8_t x = region[i];
+ switch (i & 0x58)
+ {
+ case 0x00: // same as 0x08
+ case 0x08: x = BITSWAP8( x^0xca , 3,2,1,0,7,4,6,5 ); break;
+ case 0x10: x = BITSWAP8( x^0x30 , 3,0,4,6,1,5,7,2 ); break;
+ case 0x18: x = BITSWAP8( x^0x89 , 4,1,2,5,7,0,6,3 ); break;
+ case 0x40: x = BITSWAP8( x^0x14 , 6,1,4,3,2,5,0,7 ); break;
+ case 0x48: x = BITSWAP8( x^0x40 , 1,0,3,2,5,4,7,6 ); break;
+ case 0x50: x = BITSWAP8( x^0xcb , 3,2,1,0,7,6,5,4 ); break;
+ case 0x58: x = BITSWAP8( x^0xc0 , 2,3,6,0,5,1,7,4 ); break;
+ }
+ region[i] = x ^ extra_xor;
+ }
+}
+
+
+DRIVER_INIT_MEMBER(mpu4_state,crystal)
+{
+ DRIVER_INIT_CALL(m_frkstn);
+ descramble_crystal(memregion( "maincpu" )->base(), 0x0000, 0x10000, 0x00);
+}
+
+DRIVER_INIT_MEMBER(mpu4_state,crystali)
+{
+ DRIVER_INIT_CALL(m_frkstn);
+ descramble_crystal(memregion( "maincpu" )->base(), 0x0000, 0x10000, 0xff); // invert after decrypt?!
+}
+
+/* generate a 50 Hz signal (based on an RC time) */
+TIMER_DEVICE_CALLBACK_MEMBER(mpu4_state::gen_50hz)
+{
+ if (!m_low_volt_detect_disable)
+ {
+ /* 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
+}
+
+static ADDRESS_MAP_START( mpu4_memmap, AS_PROGRAM, 8, mpu4_state )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM AM_SHARE("nvram")
+ AM_RANGE(0x0800, 0x0810) AM_READWRITE(characteriser_r,characteriser_w)
+ AM_RANGE(0x0850, 0x0850) AM_READWRITE(bankswitch_r,bankswitch_w) /* write bank (rom page select) */
+/* AM_RANGE(0x08e0, 0x08e7) AM_READWRITE(68681_duart_r,68681_duart_w) */ //Runs hoppers
+ AM_RANGE(0x0900, 0x0907) AM_DEVREADWRITE("ptm_ic2", ptm6840_device, read, write)/* PTM6840 IC2 */
+ AM_RANGE(0x0a00, 0x0a03) AM_DEVREADWRITE("pia_ic3", pia6821_device, read, write) /* PIA6821 IC3 */
+ AM_RANGE(0x0b00, 0x0b03) AM_DEVREADWRITE("pia_ic4", pia6821_device, read, write) /* PIA6821 IC4 */
+ AM_RANGE(0x0c00, 0x0c03) AM_DEVREADWRITE("pia_ic5", pia6821_device, read, write) /* PIA6821 IC5 */
+ AM_RANGE(0x0d00, 0x0d03) AM_DEVREADWRITE("pia_ic6", pia6821_device, read, write) /* PIA6821 IC6 */
+ AM_RANGE(0x0e00, 0x0e03) AM_DEVREADWRITE("pia_ic7", pia6821_device, read, write) /* PIA6821 IC7 */
+ AM_RANGE(0x0f00, 0x0f03) AM_DEVREADWRITE("pia_ic8", pia6821_device, read, write) /* PIA6821 IC8 */
+ AM_RANGE(0x1000, 0xffff) AM_ROMBANK("bank1") /* 64k paged ROM (4 pages) */
+ADDRESS_MAP_END
+
+#define MCFG_MPU4_STD_REEL_ADD(_tag)\
+ MCFG_STEPPER_ADD(_tag)\
+ MCFG_STEPPER_REEL_TYPE(BARCREST_48STEP_REEL)\
+ MCFG_STEPPER_START_INDEX(1)\
+ MCFG_STEPPER_END_INDEX(3)\
+ MCFG_STEPPER_INDEX_PATTERN(0x00)\
+ MCFG_STEPPER_INIT_PHASE(2)
+
+#define MCFG_MPU4_TYPE2_REEL_ADD(_tag)\
+ MCFG_STEPPER_ADD(_tag)\
+ MCFG_STEPPER_REEL_TYPE(BARCREST_48STEP_REEL)\
+ MCFG_STEPPER_START_INDEX(4)\
+ MCFG_STEPPER_END_INDEX(12)\
+ MCFG_STEPPER_INDEX_PATTERN(0x00)\
+ MCFG_STEPPER_INIT_PHASE(2)
+
+#define MCFG_MPU4_TYPE3_REEL_ADD(_tag)\
+ MCFG_STEPPER_ADD(_tag)\
+ MCFG_STEPPER_REEL_TYPE(BARCREST_48STEP_REEL)\
+ MCFG_STEPPER_START_INDEX(92)\
+ MCFG_STEPPER_END_INDEX(3)\
+ MCFG_STEPPER_INDEX_PATTERN(0x00)\
+ MCFG_STEPPER_INIT_PHASE(2)
+
+#define MCFG_MPU4_TYPE4_REEL_ADD(_tag)\
+ MCFG_STEPPER_ADD(_tag)\
+ MCFG_STEPPER_REEL_TYPE(BARCREST_48STEP_REEL)\
+ MCFG_STEPPER_START_INDEX(93)\
+ MCFG_STEPPER_END_INDEX(2)\
+ MCFG_STEPPER_INDEX_PATTERN(0x00)\
+ MCFG_STEPPER_INIT_PHASE(2)
+
+#define MCFG_MPU4_BWB_REEL_ADD(_tag)\
+ MCFG_STEPPER_ADD(_tag)\
+ MCFG_STEPPER_REEL_TYPE(BARCREST_48STEP_REEL)\
+ MCFG_STEPPER_START_INDEX(96)\
+ MCFG_STEPPER_END_INDEX(3)\
+ MCFG_STEPPER_INDEX_PATTERN(0x00)\
+ MCFG_STEPPER_INIT_PHASE(2)
+
+MACHINE_CONFIG_START( mpu4_std_3reel )
+ MCFG_MPU4_STD_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type2_3reel )
+ MCFG_MPU4_TYPE2_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type3_3reel )
+ MCFG_MPU4_TYPE3_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type4_3reel )
+ MCFG_MPU4_TYPE4_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_bwb_3reel )
+ MCFG_MPU4_BWB_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_std_4reel )
+ MCFG_MPU4_STD_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type2_4reel )
+ MCFG_MPU4_TYPE2_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type3_4reel )
+ MCFG_MPU4_TYPE3_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type4_4reel )
+ MCFG_MPU4_TYPE4_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_bwb_4reel )
+ MCFG_MPU4_BWB_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_std_5reel )
+ MCFG_MPU4_STD_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type2_5reel )
+ MCFG_MPU4_TYPE2_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type3_5reel )
+ MCFG_MPU4_TYPE3_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type4_5reel )
+ MCFG_MPU4_TYPE4_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_bwb_5reel )
+ MCFG_MPU4_BWB_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_std_6reel )
+ MCFG_MPU4_STD_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type2_6reel )
+ MCFG_MPU4_TYPE2_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type3_6reel )
+ MCFG_MPU4_TYPE3_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type4_6reel )
+ MCFG_MPU4_TYPE4_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_bwb_6reel )
+ MCFG_MPU4_BWB_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+MACHINE_CONFIG_END
+
+
+MACHINE_CONFIG_START( mpu4_std_7reel )
+ MCFG_MPU4_STD_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel6")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel6_optic_cb))
+ MCFG_MPU4_STD_REEL_ADD("reel7")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel7_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type2_7reel )
+ MCFG_MPU4_TYPE2_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel6")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel6_optic_cb))
+ MCFG_MPU4_TYPE2_REEL_ADD("reel7")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel7_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type3_7reel )
+ MCFG_MPU4_TYPE3_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel6")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel6_optic_cb))
+ MCFG_MPU4_TYPE3_REEL_ADD("reel7")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel7_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_type4_7reel )
+ MCFG_MPU4_TYPE4_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel6")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel6_optic_cb))
+ MCFG_MPU4_TYPE4_REEL_ADD("reel7")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel7_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_bwb_7reel )
+ MCFG_MPU4_BWB_REEL_ADD("reel0")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel0_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel1")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel1_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel2")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel2_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel3")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel3_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel4")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel4_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel5")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel5_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel6")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel6_optic_cb))
+ MCFG_MPU4_BWB_REEL_ADD("reel7")
+ MCFG_STEPPER_OPTIC_CALLBACK(WRITELINE(mpu4_state, reel7_optic_cb))
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_common )
+ MCFG_TIMER_DRIVER_ADD_PERIODIC("50hz", mpu4_state, gen_50hz, attotime::from_hz(100))
+
+ MCFG_MSC1937_ADD("vfd",0)
+ /* 6840 PTM */
+ MCFG_DEVICE_ADD("ptm_ic2", PTM6840, MPU4_MASTER_CLOCK / 4)
+ MCFG_PTM6840_EXTERNAL_CLOCKS(0, 0, 0)
+ MCFG_PTM6840_OUT0_CB(WRITELINE(mpu4_state, ic2_o1_callback))
+ MCFG_PTM6840_OUT1_CB(WRITELINE(mpu4_state, ic2_o2_callback))
+ MCFG_PTM6840_OUT2_CB(WRITELINE(mpu4_state, ic2_o3_callback))
+ MCFG_PTM6840_IRQ_CB(WRITELINE(mpu4_state, cpu0_irq))
+
+ MCFG_DEVICE_ADD("pia_ic3", PIA6821, 0)
+ MCFG_PIA_WRITEPA_HANDLER(WRITE8(mpu4_state, pia_ic3_porta_w))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_ic3_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state, pia_ic3_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state, pia_ic3_cb2_w))
+ MCFG_PIA_IRQA_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+ MCFG_PIA_IRQB_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+
+ MCFG_DEVICE_ADD("pia_ic4", PIA6821, 0)
+ MCFG_PIA_READPB_HANDLER(READ8(mpu4_state, pia_ic4_portb_r))
+ MCFG_PIA_WRITEPA_HANDLER(WRITE8(mpu4_state, pia_ic4_porta_w))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_ic4_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state,pia_ic4_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state,pia_ic4_cb2_w))
+ MCFG_PIA_IRQA_HANDLER(WRITELINE(mpu4_state,cpu0_irq))
+ MCFG_PIA_IRQB_HANDLER(WRITELINE(mpu4_state,cpu0_irq))
+
+ MCFG_DEVICE_ADD("pia_ic5", PIA6821, 0)
+ MCFG_PIA_READPA_HANDLER(READ8(mpu4_state, pia_ic5_porta_r))
+ MCFG_PIA_READPB_HANDLER(READ8(mpu4_state, pia_ic5_portb_r))
+ MCFG_PIA_WRITEPA_HANDLER(WRITE8(mpu4_state, pia_ic5_porta_w))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_ic5_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state, pia_ic5_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state, pia_ic5_cb2_w))
+ MCFG_PIA_IRQA_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+ MCFG_PIA_IRQB_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+
+ MCFG_DEVICE_ADD("pia_ic6", PIA6821, 0)
+ MCFG_PIA_WRITEPA_HANDLER(WRITE8(mpu4_state, pia_ic6_porta_w))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_ic6_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state, pia_ic6_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state, pia_ic6_cb2_w))
+ MCFG_PIA_IRQA_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+ MCFG_PIA_IRQB_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+
+ MCFG_DEVICE_ADD("pia_ic7", PIA6821, 0)
+ MCFG_PIA_READPB_HANDLER(READ8(mpu4_state, pia_ic7_portb_r))
+ MCFG_PIA_WRITEPA_HANDLER(WRITE8(mpu4_state, pia_ic7_porta_w))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_ic7_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state, pia_ic7_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state, pia_ic7_cb2_w))
+ MCFG_PIA_IRQA_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+ MCFG_PIA_IRQB_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+
+ MCFG_DEVICE_ADD("pia_ic8", PIA6821, 0)
+ MCFG_PIA_READPA_HANDLER(READ8(mpu4_state, pia_ic8_porta_r))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_ic8_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state, pia_ic8_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state, pia_ic8_cb2_w))
+ MCFG_PIA_IRQA_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+ MCFG_PIA_IRQB_HANDLER(WRITELINE(mpu4_state, cpu0_irq))
+
+ MCFG_DEVICE_ADD("meters", METERS, 0)
+ MCFG_METERS_NUMBER(8)
+
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_START( mpu4_common2 )
+ MCFG_DEVICE_ADD("ptm_ic3ss", PTM6840, MPU4_MASTER_CLOCK / 4)
+ MCFG_PTM6840_EXTERNAL_CLOCKS(0, 0, 0)
+ MCFG_PTM6840_OUT0_CB(DEVWRITELINE("ptm_ic3ss", ptm6840_device, set_c2))
+ MCFG_PTM6840_OUT1_CB(DEVWRITELINE("ptm_ic3ss", ptm6840_device, set_c1))
+ //MCFG_PTM6840_OUT2_CB(DEVWRITELINE("ptm_ic3ss", ptm6840_device, set_g1))
+ //MCFG_PTM6840_IRQ_CB(WRITELINE(mpu4_state, cpu1_ptm_irq))
+
+ MCFG_DEVICE_ADD("pia_ic4ss", PIA6821, 0)
+ MCFG_PIA_READPB_HANDLER(READ8(mpu4_state, pia_gb_portb_r))
+ MCFG_PIA_WRITEPA_HANDLER(WRITE8(mpu4_state, pia_gb_porta_w))
+ MCFG_PIA_WRITEPB_HANDLER(WRITE8(mpu4_state, pia_gb_portb_w))
+ MCFG_PIA_CA2_HANDLER(WRITELINE(mpu4_state, pia_gb_ca2_w))
+ MCFG_PIA_CB2_HANDLER(WRITELINE(mpu4_state, pia_gb_cb2_w))
+MACHINE_CONFIG_END
+
+/* machine driver for MOD 2 board */
+MACHINE_CONFIG_START( mpu4base )
+
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mod2 )
+ MCFG_MACHINE_RESET_OVERRIDE(mpu4_state,mpu4)
+ MCFG_CPU_ADD("maincpu", M6809, MPU4_MASTER_CLOCK/4)
+ MCFG_CPU_PROGRAM_MAP(mpu4_memmap)
+
+ MCFG_FRAGMENT_ADD(mpu4_common)
+
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+
+ MCFG_NVRAM_ADD_0FILL("nvram")
+
+ MCFG_DEFAULT_LAYOUT(layout_mpu4)
+MACHINE_CONFIG_END
+
+
+MACHINE_CONFIG_DERIVED( mod2 , mpu4base )
+ MCFG_SOUND_ADD("ay8913", AY8913, MPU4_MASTER_CLOCK/4)
+ MCFG_AY8910_OUTPUT_TYPE(AY8910_SINGLE_OUTPUT)
+ MCFG_AY8910_RES_LOADS(820, 0, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+ MCFG_FRAGMENT_ADD(mpu4_std_6reel)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED( mod2_alt , mpu4base )
+ MCFG_SOUND_ADD("ay8913", AY8913, MPU4_MASTER_CLOCK/4)
+ MCFG_AY8910_OUTPUT_TYPE(AY8910_SINGLE_OUTPUT)
+ MCFG_AY8910_RES_LOADS(820, 0, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+ MCFG_FRAGMENT_ADD(mpu4_type2_6reel)
+MACHINE_CONFIG_END
+
+
+
+MACHINE_CONFIG_DERIVED( mod4yam, mpu4base )
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mpu4yam)
+
+ MCFG_FRAGMENT_ADD(mpu4_std_6reel)
+
+ MCFG_SOUND_ADD("ym2413", YM2413, MPU4_MASTER_CLOCK/4)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED( mod4oki, mpu4base )
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mpu4oki)
+
+ MCFG_FRAGMENT_ADD(mpu4_common2)
+ MCFG_FRAGMENT_ADD(mpu4_std_6reel)
+
+ MCFG_SOUND_ADD("msm6376", OKIM6376, 128000) //16KHz sample Can also be 85430 at 10.5KHz and 64000 at 8KHz
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED( mod4oki_alt, mpu4base )
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mpu4oki)
+
+ MCFG_FRAGMENT_ADD(mpu4_common2)
+ MCFG_FRAGMENT_ADD(mpu4_type2_6reel)
+
+ MCFG_SOUND_ADD("msm6376", OKIM6376, 128000) //16KHz sample Can also be 85430 at 10.5KHz and 64000 at 8KHz
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED( mod4oki_5r, mpu4base )
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mpu4oki)
+
+ MCFG_FRAGMENT_ADD(mpu4_common2)
+ MCFG_FRAGMENT_ADD(mpu4_std_5reel)
+
+ MCFG_SOUND_ADD("msm6376", OKIM6376, 128000) //16KHz sample Can also be 85430 at 10.5KHz and 64000 at 8KHz
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED( bwboki, mpu4base )
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mpu4bwb)
+ MCFG_FRAGMENT_ADD(mpu4_common2)
+ MCFG_FRAGMENT_ADD(mpu4_bwb_5reel)
+
+ MCFG_SOUND_ADD("msm6376", OKIM6376, 128000) //16KHz sample Can also be 85430 at 10.5KHz and 64000 at 8KHz
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED(mpu4crys, mod2 )
+ MCFG_MACHINE_START_OVERRIDE(mpu4_state,mpu4cry)
+
+ MCFG_SOUND_ADD("upd", UPD7759, UPD7759_STANDARD_CLOCK)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+#define GAME_FLAGS (MACHINE_NOT_WORKING|MACHINE_REQUIRES_ARTWORK|MACHINE_MECHANICAL)