diff options
Diffstat (limited to 'src/mame/drivers/mpu4.c')
-rw-r--r-- | src/mame/drivers/mpu4.c | 1406 |
1 files changed, 1406 insertions, 0 deletions
diff --git a/src/mame/drivers/mpu4.c b/src/mame/drivers/mpu4.c new file mode 100644 index 00000000000..5c2bcbc85bd --- /dev/null +++ b/src/mame/drivers/mpu4.c @@ -0,0 +1,1406 @@ +/*************************************************************************** + Barcrest MPU4 highly preliminary driver by J.Wallace, and Anonymous. + This is the core driver, no game specific stuff should go in here. + + 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. + 09-04-2007: J Wallace: Corrected a lot of out of date info in this revision history. + Revisionism, if you will. + 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. + 30-12-2006: J Wallace: Fixed init routines, state saving is theoretically supported. + 23-09-2006: Converted 7Segment code to cleaner version, but have yet to add new 16k EPROM, as + the original image was purported to come from a Barcrest BBS service, and is probably + more 'official'. + 07-09-2006: It appears that the video firmware is intended to be a 16k EPROM, not 64k as dumped. + In fact, the current dump is just the code repeated 4 times, when nothing earlier than + 0xC000 is ever called. Presumably, the ROM is loaded into C000, and the remainder of the + 'ROM' space is in fact the extra 32k of RAM apparently needed to hold the video board data. + For now, we'll continue to use the old dump, as I am unsure as to how to map this in MAME. + Changed Turn Over's name, it's either 12 Pound or 20 Pound Turn Over, depending on settings. + + At this stage, I cannot see how to progress any further with the emulation, so I have transferred + a non-AWP version of this driver to MAME for further study. + + 06-09-2006: Connect 4 added - VFD is currently reversed, although it looks to me like + that's the correct behaviour, and that my 'correction' for Old Timer was wrong. + AY sound does work, but is horrendous - presumably there's a filter on the + sound that I haven't spotted. Trackball is apparently connected to AUX1, via + Schmitt triggers - I wish I had a clue what this meant (El Condor). + + 05-09-2006: And the award for most bone-headed bug goes to.. me! the 6840 handler wasn't + resetting the clocks after timeout, so the wave frequencies were way off. + Machines now hang on reset due to a lack of reel support. + CHR decoding now included, but still requires knowledge of the data table + location - this should be present in the ROMs somewhere. + + 11-08-2006: It appears that the PIA IRQ's are not connected after all - but even + disabling these won't get around the PTM issues. + It also looks like the video card CHR is just a word-based version + of the original, byte-based chip, meaning that should be fairly simple + to emulate too, when the time comes. + + 08-07-2006: Revised mapping of peripherals, and found method of calculating CHR + values - although their use is still unknown. + + 11-05-2006: El Condor, working from schematics and photos at present + 28-04-2006: El Condor + 20-05-2004: Re-Animator + + See http://www.mameworld.net/agemame/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 original board uses a ~1.72 Mhz 6809B CPU, and a number of PIA6821 chips for multiplexing inputs and the like. + +A 6840PTM is used for internal timing, one of it's functions is to act with an AY8913 chip as a crude analogue sound device. +(Data is transmitted through a PIA, with a square wave from the PTM being used as the alarm sound generator) + +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. + +One of the advantages of the hardware setup was that the developer could change the nature of the game card +up to a point, adding extra lamp support, different amounts of RAM, and (in many cases) an OKI MSM6376 or Yamaha synth chip +and related PIA and PTM for improved audio (This was eventually made the only way to generate sound in MOD4 of the hardware, +when the AY8913 was removed from the main board) + +Everything here is preliminary... the boards are quite fussy with regards their self tests +and the timing may have to be perfect for them to function correctly. (as the comms are +timer driven, the video is capable of various raster effects etc.) + +Datasheets are available for the main components, The AGEMAME site mirrors a few of the harder-to-find ones. + +--- 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@16MHz,(NV) + | | | port A = ?? + | | | port B (882) + | | | b7 = 0 if OKI busy + | | | 1 if OKI ready + | | | b6 = ?? + | | | b5 = volume control clock + | | | b4 = volume control direction (0= up, 1 = down) + | | | b3 = ?? + | | | b2 = ?? + | | | b1 = ?? + | | | b0 = ?? +-----------+---+-----------------+-------------------------------------------------------------------------- + 08C0 | | | MC6840 on sound board(NV?) +-----------+---+-----------------+-------------------------------------------------------------------------- + 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) +-----------+---+-----------------+-------------------------------------------------------------------------- + +TODO: - Fix lamp timing, MAME doesn't update fast enough to see everything + - Distinguish door switches using manual +*****************************************************************************************/ + +#include "driver.h" +#include "machine/6821pia.h" +#include "machine/6840ptm.h" + +// MPU4 +#include "ui.h" +#include "timer.h" +#include "cpu/m6809/m6809.h" +#include "sound/ay8910.h" +#include "machine/steppers.h" // stepper motor +#include "machine/roc10937.h" // vfd +#include "machine/meters.h" + +#ifdef MAME_DEBUG +#define LOG(x)logerror x +#define LOG_CHR(x)logerror x +#define LOG_CHR_FULL(x)logerror x +#define LOG_IC3(x)logerror x +#define LOG_IC8(x)logerror x +#else +#define LOG(x) +#define LOG_CHR(x) +#define LOG_CHR_FULL(x) +#define LOG_IC3(x) +#define LOG_IC8(x) +#endif + +#ifndef AWP_VIDEO //Defined for fruit machines with mechanical reels +#define draw_reel(x) +#else +#define draw_reel(x) awp_draw_reel x +#endif +#include "mpu4.lh" +#include "connect4.lh" +#define MPU4_MASTER_CLOCK (6880000) +// local vars ///////////////////////////////////////////////////////////// +static int mod_number; +static int mmtr_data; +static int alpha_data_line; +static int alpha_clock; +static int ay8913_address; +static int serial_data; +static int signal_50hz; +static int ic4_input_b; +static int IC23G1; +static int IC23G2A; +static int IC23G2B; +static int IC23GC; +static int IC23GB; +static int IC23GA; +static int prot_col; +static int lamp_col; +static int ic23_active; +static int led_extend; +static int serial_card_connected; +static emu_timer *ic24_timer; +static TIMER_CALLBACK( ic24_timeout ); + +static int input_strobe; // IC23 74LS138 A = CA2 IC7, B = CA2 IC4, C = CA2 IC8 +static UINT8 lamp_strobe,lamp_strobe2; +static UINT8 lamp_data; +static UINT8 aydata; + +extern const UINT8 MPU4_chr_lut[72]; +static UINT8 MPU4_chr_data[72]; +static UINT8 led_segs[8]; +static UINT8 Lamps[128]; // 128 multiplexed lamps + // 32 multiplexed inputs - but a further 8 possible per AUX. + // Two connectors 'orange' (sampled every 8ms) and 'black' (sampled every 16ms) + // Each connector carries two banks of eight inputs and two enable signals +static int optic_pattern; + +/* +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) +*/ + +static void mpu4_draw_led(UINT8 id, UINT8 value) +{ + output_set_digit_value(id,value); +} + +static void draw_lamps(void) +{ + int i; + + for (i=0; i<8; i++) + { + output_set_lamp_value((8*input_strobe)+i, (Lamps[(8*input_strobe)+i])); + output_set_lamp_value((8*input_strobe)+i+64, (Lamps[(8*input_strobe)+i+64])); + } +} + +static void update_lamps(void) +{ + int i; + + for (i=0; i<8; i++) + { + Lamps[(8*input_strobe)+i] = (lamp_strobe & (1 << i)) != 0; + Lamps[(8*input_strobe)+i+64] = (lamp_strobe2 & (1 << i)) != 0; + } + + if (led_extend) + { + //Some games uses 'programmable' displays, built from lights. + UINT8 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); + } + + mpu4_draw_led(8, pled_segs[0]); + mpu4_draw_led(9, pled_segs[1]); + } + +} + +// palette initialisation ///////////////////////////////////////////////// + +static PALETTE_INIT( mpu4 ) +{ + int i; + static const rgb_t color[16] = + { + MAKE_RGB(0x00,0x00,0x00), MAKE_RGB(0x00,0x00,0xFF), MAKE_RGB(0x00,0xFF,0x00), MAKE_RGB(0x00,0xFF,0xFF), + MAKE_RGB(0xFF,0x00,0x00), MAKE_RGB(0xFF,0x00,0xFF), MAKE_RGB(0xFF,0xFF,0x00), MAKE_RGB(0xFF,0xFF,0xFF), + MAKE_RGB(0x80,0x80,0x80), MAKE_RGB(0x00,0x00,0x80), MAKE_RGB(0x00,0x80,0x00), MAKE_RGB(0x00,0x80,0x80), + MAKE_RGB(0x80,0x00,0x00), MAKE_RGB(0x80,0x00,0x80), MAKE_RGB(0x80,0x80,0x00), MAKE_RGB(0x80,0x80,0x80) + }; + + for (i=0; i<16; i++) + palette_set_color(machine, i, color[i]); +} + +/////////////////////////////////////////////////////////////////////////// +// called if board is reset /////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +static void mpu4_stepper_reset(void) +{ + int pattern = 0,i; + for ( i = 0; i < 6; i++) + { + Stepper_reset_position(i); + if ( Stepper_optic_state(i) ) pattern |= 1<<i; + } + optic_pattern = pattern; +} + +static MACHINE_RESET( mpu4 ) +{ + ROC10937_reset(0); // reset display1 + + mpu4_stepper_reset(); + + lamp_strobe = 0; + lamp_strobe2 = 0; + lamp_data = 0; + + IC23GC = 0; + IC23GB = 0; + IC23GA = 0; + IC23G1 = 1; + IC23G2A = 0; + IC23G2B = 0; + + prot_col = 0; + +// init rom bank //////////////////////////////////////////////////////// + + { + UINT8 *rom = memory_region(REGION_CPU1); + + memory_configure_bank(1, 0, 8, &rom[0x01000], 0x10000); + + memory_set_bank(1,0); + } + +} + +/////////////////////////////////////////////////////////////////////////// + +static void cpu0_irq(int state) +{ + if (!serial_card_connected) + { + cpunum_set_input_line(0, M6809_IRQ_LINE, state?ASSERT_LINE:CLEAR_LINE); + LOG(("6809 int%d \n",state)); + } + else + { + cpunum_set_input_line(0, M6809_FIRQ_LINE, state?ASSERT_LINE:CLEAR_LINE); + LOG(("6809 fint%d \n",state)); + } +} + +/////////////////////////////////////////////////////////////////////////// +static WRITE8_HANDLER( bankswitch_w ) +{ + memory_set_bank(1,data & 0x07); +} + +// IC2 6840 PTM handler /////////////////////////////////////////////////////// + +static WRITE8_HANDLER( ic2_o1_callback ) +{ + ptm6840_set_c2(0,data); + + // copy output value to IC2 c2 + // this output is the clock for timer2, + // the output from timer2 is the input clock for timer3 + // the output from timer3 is used as a square wave for the alarm output + // and as an external clock source for timer 1! +} + +static WRITE8_HANDLER( ic2_o2_callback ) +{ + pia_set_input_ca1(0, data); // copy output value to IC3 ca1 + ptm6840_set_c3( 0, data); // copy output value to IC2 c3 +} + +static WRITE8_HANDLER( ic2_o3_callback ) +{ + ptm6840_set_c1( 0, data); // copy output value to IC2 c1 +} + +static const ptm6840_interface ptm_ic2_intf = +{ + MPU4_MASTER_CLOCK/4, + { 0,0,0 }, + { ic2_o1_callback, ic2_o2_callback, ic2_o3_callback }, + cpu0_irq +}; + +/*************************************************************************** + 6821 PIA handlers +***************************************************************************/ + +// IC3 +static WRITE8_HANDLER( pia_ic3_porta_w ) +{ + LOG_IC3(("%04x IC3 PIA Port A Set to %2x (lamp strobes 1 - 9)\n", activecpu_get_previouspc(),data)); + + if(ic23_active) + { + lamp_strobe = data; + update_lamps(); + } +} + +static WRITE8_HANDLER( pia_ic3_portb_w ) +{ + LOG_IC3(("%04x IC3 PIA Port B Set to %2x (lamp strobes 10 - 17)\n", activecpu_get_previouspc(),data)); + + if(ic23_active) + { + lamp_strobe2 = data; + update_lamps(); + } +} + +static WRITE8_HANDLER( pia_ic3_ca2_w ) +{ + LOG_IC3(("%04x IC3 PIA Write CA2 (alpha data), %02X\n", activecpu_get_previouspc(),data)); + + alpha_data_line = data; + ROC10937_draw_16seg(0); +} + +static WRITE8_HANDLER( pia_ic3_cb2_w ) +{ + LOG_IC3(("%04x IC3 PIA Write CB (alpha reset), %02X\n",activecpu_get_previouspc(),data)); + + if ( data ) ROC10937_reset(0); + ROC10937_draw_16seg(0); +} + +// IC3, lamp data lines + alpha numeric display + +static const pia6821_interface pia_ic3_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ 0, 0, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ pia_ic3_porta_w, pia_ic3_portb_w, pia_ic3_ca2_w, pia_ic3_cb2_w, + /*irqs : A/B */ cpu0_irq, cpu0_irq +}; + +/*--------------------------------------- + IC23 emulation + --------------------------------------- +IC23 is a 74LS138 1-of-8 Decoder + +It is used as a multiplexer for the LEDs, lamp selects and inputs. +*/ + +static void ic23_update(void) +{ + if (!IC23G2A) + { + if (!IC23G2B) + { + if (IC23G1) + { + if ( IC23GA ) input_strobe |= 0x01; + else input_strobe &= ~0x01; + + if ( IC23GB ) input_strobe |= 0x02; + else input_strobe &= ~0x02; + + if ( IC23GC ) input_strobe |= 0x04; + else input_strobe &= ~0x04; + } + } + } + else + if ((IC23G2A)||(IC23G2B)) + { + input_strobe = 0x00; + } + draw_lamps(); +} +/*--------------------------------------- + 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. +*/ + +static void ic24_output(int data) +{ + IC23G2A = data; + ic23_update(); +} + +static void ic24_setup(void) +{ + if (IC23GA) + { + double duration = TIME_OF_74LS123((220*1000),(0.1*0.000001)); + { + ic23_active=1; + ic24_output(0); + timer_adjust(ic24_timer, double_to_attotime(duration), 0, attotime_zero); + } + } +} + +static TIMER_CALLBACK( ic24_timeout ) +{ + ic23_active=0; + ic24_output(1); +} + +// IC4 + +static WRITE8_HANDLER( pia_ic4_porta_w ) +{ + if(ic23_active) + { + led_segs[input_strobe] = data; + mpu4_draw_led(input_strobe, led_segs[input_strobe]); + } +} + +static READ8_HANDLER( pia_ic4_portb_r ) +{ + if ( serial_data ) + { + ic4_input_b |= 0x80; + pia_set_input_cb1(1, 1); + } + else + { + ic4_input_b &= ~0x80; + pia_set_input_cb1(1, 0); + } + + if ( optic_pattern & 0x01 ) ic4_input_b |= 0x40; // reel A tab + else ic4_input_b &= ~0x40; + + if ( optic_pattern & 0x02 ) ic4_input_b |= 0x20; // reel B tab + else ic4_input_b &= ~0x20; + + if ( optic_pattern & 0x04 ) ic4_input_b |= 0x10; // reel C tab + else ic4_input_b &= ~0x10; + + if ( optic_pattern & 0x08 ) ic4_input_b |= 0x08; // reel D tab + else ic4_input_b &= ~0x08; + + if ( signal_50hz ) ic4_input_b |= 0x04; // 50 Hz + else ic4_input_b &= ~0x04; + + // if ( lamp_overcurrent ) ic4_input_b |= 0x02; + // if ( lamp_undercurrent ) ic4_input_b |= 0x01; + + LOG_IC3(("%04x IC4 PIA Read of Port B %x\n",activecpu_get_previouspc(),ic4_input_b)); + return ic4_input_b; +} + +static WRITE8_HANDLER( pia_ic4_ca2_w ) +{ + LOG_IC3(("%04x IC4 PIA Write CA (input MUX strobe /LED B), %02X\n", activecpu_get_previouspc(),data)); + + IC23GB = data; + ic23_update(); +} + +// IC4, 7 seg leds, 50Hz timer reel sensors, current sensors + +static const pia6821_interface pia_ic4_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ 0, pia_ic4_portb_r, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ pia_ic4_porta_w, 0, pia_ic4_ca2_w, 0, + /*irqs : A/B */ cpu0_irq, cpu0_irq +}; + +//IC5 +static READ8_HANDLER( pia_ic5_porta_r ) +{ + LOG(("%04x IC5 PIA Read of Port A (AUX1)\n",activecpu_get_previouspc())); +// popmessage("%d",(pia_get_output_a(2) & 0x01)); + return readinputportbytag("AUX1"); +} + +static READ8_HANDLER( pia_ic5_portb_r ) +{ + LOG(("%04x IC5 PIA Read of Port B (coin input AUX2)\n",activecpu_get_previouspc())); + coin_lockout_w(0, (pia_get_output_b(2) & 0x01) ); + coin_lockout_w(1, (pia_get_output_b(2) & 0x02) ); + coin_lockout_w(2, (pia_get_output_b(2) & 0x04) ); + coin_lockout_w(3, (pia_get_output_b(2) & 0x08) ); + return readinputportbytag("AUX2"); +} + +static WRITE8_HANDLER( pia_ic5_ca2_w ) +{ + LOG(("%04x IC5 PIA Write CA2 (Serial Tx) %2x\n",activecpu_get_previouspc(),data)); + serial_data = data; +} + +/* --------------------------------------- + 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 */ + +static void update_ay(void) +{ + if (!pia_get_output_cb2(2)) + { + switch (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",pia_get_output_a(3)&0x0f)); + break; + } + case 0x02: + {/* CA2 = 0 CB2 = 1? : Write to selected PSG register and write data to Port A */ + AY8910_write_port_0_w(0, pia_get_output_a(3)); + 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_control_port_0_w(0, pia_get_output_a(3)); + LOG(("AY Chip Select \n")); + break; + } + default: + { + LOG(("AY Chip error \n")); + } + } + } + +} + +static WRITE8_HANDLER( pia_ic5_cb2_w ) +{ + update_ay(); +} + +static const pia6821_interface pia_ic5_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ pia_ic5_porta_r, pia_ic5_portb_r, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ 0, 0, pia_ic5_ca2_w, pia_ic5_cb2_w, + /*irqs : A/B */ cpu0_irq, cpu0_irq +}; + +//IC6 +static WRITE8_HANDLER( pia_ic6_portb_w ) +{ + LOG(("%04x IC6 PIA Port B Set to %2x (Reel A and B)\n", activecpu_get_previouspc(),data)); + Stepper_update(0, data & 0x0F ); + Stepper_update(1, (data>>4) & 0x0F ); + +// if ( pia_get_output_cb2(1)) + { + if ( Stepper_optic_state(0) ) optic_pattern |= 0x01; + else optic_pattern &= ~0x01; + + if ( Stepper_optic_state(1) ) optic_pattern |= 0x02; + else optic_pattern &= ~0x02; + } + draw_reel((0)); + draw_reel((1)); +} + +static WRITE8_HANDLER( pia_ic6_porta_w ) +{ + LOG(("%04x IC6 PIA Write A %2x\n", activecpu_get_previouspc(),data)); + if (mod_number <4) + { + aydata = data; + update_ay(); + } +} + +static WRITE8_HANDLER( pia_ic6_ca2_w ) +{ + LOG(("%04x IC6 PIA write CA2 %2x (AY8913 BC1)\n", activecpu_get_previouspc(),data)); + if (mod_number <4) + { + if ( data ) ay8913_address |= 0x01; + else ay8913_address &= ~0x01; + update_ay(); + } +} + +static WRITE8_HANDLER( pia_ic6_cb2_w ) +{ + LOG(("%04x IC6 PIA write CB2 %2x (AY8913 BCDIR)\n", activecpu_get_previouspc(),data)); + if (mod_number <4) + { + if ( data ) ay8913_address |= 0x02; + else ay8913_address &= ~0x02; + update_ay(); + } +} + +static const pia6821_interface pia_ic6_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ 0, 0, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ pia_ic6_porta_w, pia_ic6_portb_w, pia_ic6_ca2_w, pia_ic6_cb2_w, + /*irqs : A/B */ cpu0_irq, cpu0_irq +}; + +//IC7 +static WRITE8_HANDLER( pia_ic7_porta_w ) +{ + LOG(("%04x IC7 PIA Port A Set to %2x (Reel C and D)\n", activecpu_get_previouspc(),data)); + Stepper_update(2, data & 0x0F ); + Stepper_update(3, (data >> 4)& 0x0F ); + +// if ( pia_get_output_cb2(1)) + { + if ( Stepper_optic_state(2) ) optic_pattern |= 0x04; + else optic_pattern &= ~0x04; + if ( Stepper_optic_state(3) ) optic_pattern |= 0x08; + else optic_pattern &= ~0x08; + } + draw_reel((2)); + draw_reel((3)); +} + +static WRITE8_HANDLER( pia_ic7_portb_w ) +{ + int i; + long cycles = ATTOTIME_TO_CYCLES(0, timer_get_time() ); + +// 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. +// 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. + + mmtr_data = data; + if (mmtr_data) + { + pia_set_input_b(4,mmtr_data|0x80); + for (i=0; i<8; i++) + if ( mmtr_data & (1 << i) ) Mechmtr_update(i, cycles, mmtr_data & (1 << i) ); + } + else + { + pia_set_input_b(4,mmtr_data&~0x80); + } + + LOG(("%04x IC7 PIA Port B Set to %2x (Meters, Reel E and F)\n", activecpu_get_previouspc(),data)); +} + +static WRITE8_HANDLER( pia_ic7_ca2_w ) +{ + LOG(("%04x IC7 PIA write CA2 %2x (input strobe bit 0 / LED A)\n", activecpu_get_previouspc(),data)); + + IC23GA = data; + ic24_setup(); + ic23_update(); +} + +static WRITE8_HANDLER( pia_ic7_cb2_w ) +{ +// The eighth meter is connected here, because the voltage sensor +// is on PB7. + long cycles = ATTOTIME_TO_CYCLES(0, timer_get_time() ); + if (data) + { + pia_set_input_b(4,mmtr_data|0x80); + Mechmtr_update(7, cycles, data ); + } + LOG(("%04x IC7 PIA write CB2 %2x \n", activecpu_get_previouspc(),data)); +} + +static const pia6821_interface pia_ic7_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ 0, 0, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ pia_ic7_porta_w, pia_ic7_portb_w, pia_ic7_ca2_w, pia_ic7_cb2_w, + /*irqs : A/B */ cpu0_irq, cpu0_irq +}; + +static READ8_HANDLER( pia_ic8_porta_r ) +{ + static const UINT8 ports[8] = { 0, 1, 2, 3, 0, 1, 4, 5 }; + int input_read = ports[input_strobe]; + + LOG_IC8(("%04x IC8 PIA Read of Port A (MUX input data)\n",activecpu_get_previouspc())); +// 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). + pia_set_input_cb1(2, (readinputportbytag("AUX2") & 0x80)); + return readinputport(input_read); +} + +static WRITE8_HANDLER( pia_ic8_portb_w ) +{ + int i; + LOG_IC8(("%04x IC8 PIA Port B Set to %2x (OUTPUT PORT, TRIACS)\n", activecpu_get_previouspc(),data)); + for (i=0; i<8; i++) + if ( data & (1 << i) ) output_set_indexed_value("triac", i, data & (1 << i)); +} + +static WRITE8_HANDLER( pia_ic8_ca2_w ) +{ + LOG_IC8(("%04x IC8 PIA write CA2 (input_strobe bit 2 / LED C) %02X\n", activecpu_get_previouspc(), data & 0xFF)); + + IC23GC = data; + ic23_update(); +} + +static WRITE8_HANDLER( pia_ic8_cb2_w ) +{ + LOG_IC8(("%04x IC8 PIA write CB2 (alpha clock) %02X\n", activecpu_get_previouspc(), data & 0xFF)); + + if ( !alpha_clock && (data) ) + { + ROC10937_shift_data(0, alpha_data_line&0x01?0:1); + } + alpha_clock = data; + ROC10937_draw_16seg(0); +} + +static const pia6821_interface pia_ic8_intf = +{ + /*inputs : A/B,CA/B1,CA/B2 */ pia_ic8_porta_r, 0, 0, 0, 0, 0, + /*outputs: A/B,CA/B2 */ 0, pia_ic8_portb_w, pia_ic8_ca2_w, pia_ic8_cb2_w, + /*irqs : A/B */ cpu0_irq, cpu0_irq +}; + + +// input ports for MPU4 board //////////////////////////////////////// + +static INPUT_PORTS_START( mpu4 ) + PORT_START_TAG("ORANGE1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("00") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("01") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("02") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("03") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("04") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("05") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("06") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("07") + + PORT_START_TAG("ORANGE2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("08") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("09") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("10") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("11") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("12") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("13") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("14") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("15") + + PORT_START_TAG("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 Door") PORT_CODE(KEYCODE_Q) PORT_TOGGLE + + PORT_START_TAG("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_TAG("DIL1") + PORT_DIPNAME( 0x01, 0x00, "DIL101" ) PORT_DIPLOCATION("DIL1:01") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "DIL102" ) PORT_DIPLOCATION("DIL1:02") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "DIL103" ) PORT_DIPLOCATION("DIL1:03") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "DIL104" ) PORT_DIPLOCATION("DIL1:04") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "DIL105" ) PORT_DIPLOCATION("DIL1:05") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "DIL106" ) PORT_DIPLOCATION("DIL1:06") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "DIL107" ) PORT_DIPLOCATION("DIL1:07") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "DIL108" ) PORT_DIPLOCATION("DIL1:08") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START_TAG("DIL2") + PORT_DIPNAME( 0x01, 0x00, "DIL201" ) PORT_DIPLOCATION("DIL2:01") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "DIL202" ) PORT_DIPLOCATION("DIL2:02") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "DIL203" ) PORT_DIPLOCATION("DIL2:03") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "DIL204" ) PORT_DIPLOCATION("DIL2:04") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "DIL205" ) PORT_DIPLOCATION("DIL2:05") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "DIL206" ) PORT_DIPLOCATION("DIL2:06") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "DIL207" ) PORT_DIPLOCATION("DIL2:07") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "DIL208" ) PORT_DIPLOCATION("DIL2:08") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START_TAG("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_TAG("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 + +static INPUT_PORTS_START( connect4 ) + PORT_START_TAG("ORANGE1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("00") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("01") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("02") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("03") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("04") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("05") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("06") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("07") + + PORT_START_TAG("ORANGE2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("08") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("09") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("10") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("11") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("12") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("13") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("14") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("15") + + PORT_START_TAG("BLACK1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("16") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("17") + 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 Switch") + 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_OTHER) PORT_NAME("Door Switch?") PORT_TOGGLE + + PORT_START_TAG("BLACK2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Select") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("25") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_START2) PORT_NAME("Pass") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_START1) PORT_NAME("Play") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("28") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("29") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("30") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Drop") + + PORT_START_TAG("DIL1") + PORT_DIPNAME( 0x01, 0x00, "DIL101" ) PORT_DIPLOCATION("DIL1:01") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "DIL102" ) PORT_DIPLOCATION("DIL1:02") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "DIL103" ) PORT_DIPLOCATION("DIL1:03") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "DIL104" ) PORT_DIPLOCATION("DIL1:04") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "DIL105" ) PORT_DIPLOCATION("DIL1:05") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "DIL106" ) PORT_DIPLOCATION("DIL1:06") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "DIL107" ) PORT_DIPLOCATION("DIL1:07") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "Invert Alpha?" ) PORT_DIPLOCATION("DIL1:08") + PORT_DIPSETTING( 0x00, DEF_STR( No ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Yes ) ) + + PORT_START_TAG("DIL2") + PORT_DIPNAME( 0x01, 0x00, "DIL201" ) PORT_DIPLOCATION("DIL2:01") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "DIL202" ) PORT_DIPLOCATION("DIL2:02") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "DIL203" ) PORT_DIPLOCATION("DIL2:03") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "DIL204" ) PORT_DIPLOCATION("DIL2:04") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "DIL205" ) PORT_DIPLOCATION("DIL2:05") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "DIL206" ) PORT_DIPLOCATION("DIL2:06") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "DIL207" ) PORT_DIPLOCATION("DIL2:07") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "DIL208" ) PORT_DIPLOCATION("DIL2:08") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START_TAG("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_TAG("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 + +static void mpu4_config_common(void) +{ + pia_config(0,&pia_ic3_intf); + pia_config(1,&pia_ic4_intf); + pia_config(2,&pia_ic5_intf); + pia_config(3,&pia_ic6_intf); + pia_config(4,&pia_ic7_intf); + pia_config(5,&pia_ic8_intf); + + ic24_timer = timer_alloc(ic24_timeout); + // setup ptm //////////////////////////////////////////////////////////// + ptm6840_config(0, &ptm_ic2_intf ); +} + +static MACHINE_START( mpu4mod2 ) +{ + mpu4_config_common(); + pia_reset(); + + serial_card_connected=0; + mod_number=2; + +// setup 8 mechanical meters //////////////////////////////////////////// + Mechmtr_init(8); + +// setup 4 default 96 half step reels /////////////////////////////////// + Stepper_init(0, BARCREST_48STEP_REEL); + Stepper_init(1, BARCREST_48STEP_REEL); + Stepper_init(2, BARCREST_48STEP_REEL); + Stepper_init(3, BARCREST_48STEP_REEL); + +// setup the standard oki MSC1937 display /////////////////////////////// + ROC10937_init(0, MSC1937,0); +} + +/* +Characteriser (CHR) + +I haven't been able to work out all the ways of finding the CHR data, but there must be a flag in the ROMs +somewhere to pick it out. 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 as such, only low level access can defeat their protection. + +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: + +To calculate the values necessary to program the CHR, we must first find the version string, taking +the example of an AWP called Club Celebration, this starts at 0xff28 and terminates at 0xff2f. +0xff2f then represents the CHR address. +For some reason, the tables always seem to start and end with '00 00'. + +From that point on, every word represents a call and response pair, until we have generated 8 8 byte rows of data. + +The call values appear to be fixed, so it would be possible to make a switch statement, but I believe the emulated +behaviour to be more likely. + +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. + +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. +*/ + +static WRITE8_HANDLER( characteriser_w ) +{ + UINT8 x; + int call=data; + LOG_CHR_FULL(("%04x Characteriser write offset %02X data %02X", activecpu_get_previouspc(),offset,data)); + if (offset == 0) + { + if (call == 0) + { + prot_col = 0; + } + else + { + for ( x = prot_col; x < 64; x++ ) + { + if (MPU4_chr_lut[(x)] == call) + { + prot_col = x; + LOG_CHR(("Characteriser find column %02X\n",prot_col)); + LOG_CHR(("Characteriser find data %02X\n",MPU4_chr_data[prot_col])); + break; + } + } + } + } + else if (offset == 2) + { + LOG_CHR(("Characteriser write 2 data %02X\n",data)); + for ( x = lamp_col; x < 16; x++ ) + { + if (MPU4_chr_lut[(64+x)] == call) + { + lamp_col = x; + LOG_CHR(("Characteriser find column %02X\n",lamp_col)); + break; + } + if (lamp_col > 7) + { + lamp_col = 0; + } + } + } +} + +static READ8_HANDLER( characteriser_r ) +{ + LOG_CHR(("Characteriser read offset %02X \n",offset)); + LOG_CHR_FULL(("%04x Characteriser read offset %02X", activecpu_get_previouspc(),offset)); + if (offset == 0) + { + LOG_CHR(("Characteriser read data %02X \n",MPU4_chr_data[prot_col])); + return MPU4_chr_data[prot_col]; + } + if (offset == 3) + { + LOG_CHR(("Characteriser read data %02X \n",MPU4_chr_data[lamp_col+64])); + return MPU4_chr_data[lamp_col+64]; + } + return 0; +} + +// generate a 50 Hz signal (based on an RC time) ////////////////////////// +static INTERRUPT_GEN( gen_50hz ) +{ + // Although reported as a '50Hz' signal, the fact that both rising and + // falling edges of the pulse are used, the timer actually gives a 100Hz + // oscillating signal. + signal_50hz = signal_50hz?0:1; + + pia_set_input_ca1(1,signal_50hz); // signal is connected to IC4 CA1 +} + +static ADDRESS_MAP_START( mod2_memmap, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x07ff) AM_RAM AM_BASE(&generic_nvram) AM_SIZE(&generic_nvram_size) + + AM_RANGE(0x0800, 0x0810) AM_WRITE(characteriser_w) + AM_RANGE(0x0800, 0x0810) AM_READ( characteriser_r) + + AM_RANGE(0x0850, 0x0850) AM_WRITE(bankswitch_w) // write bank (rom page select) + +// AM_RANGE(0x08E0, 0x08E7) AM_READ( 68681_duart_r) +// AM_RANGE(0x08E0, 0x08E7) AM_WRITE( 68681_duart_w) + + AM_RANGE(0x0900, 0x0907) AM_READ( ptm6840_0_r) // 6840PTM + AM_RANGE(0x0900, 0x0907) AM_WRITE(ptm6840_0_w) + + AM_RANGE(0x0A00, 0x0A03) AM_WRITE(pia_0_w) // PIA6821 IC3 + AM_RANGE(0x0A00, 0x0A03) AM_READ( pia_0_r) + + AM_RANGE(0x0B00, 0x0B03) AM_WRITE(pia_1_w) // PIA6821 IC4 + AM_RANGE(0x0B00, 0x0B03) AM_READ( pia_1_r) + + AM_RANGE(0x0C00, 0x0C03) AM_WRITE(pia_2_w) // PIA6821 IC5 + AM_RANGE(0x0C00, 0x0C03) AM_READ( pia_2_r) + + AM_RANGE(0x0D00, 0x0D03) AM_WRITE(pia_3_w) // PIA6821 IC6 + AM_RANGE(0x0D00, 0x0D03) AM_READ( pia_3_r) + + AM_RANGE(0x0E00, 0x0E03) AM_WRITE(pia_4_w) // PIA6821 IC7 + AM_RANGE(0x0E00, 0x0E03) AM_READ( pia_4_r) + + AM_RANGE(0x0F00, 0x0F03) AM_WRITE(pia_5_w) // PIA6821 IC8 + AM_RANGE(0x0F00, 0x0F03) AM_READ( pia_5_r) + + AM_RANGE(0x1000, 0xffff) AM_READ(MRA8_BANK1) // 64k paged ROM (4 pages) +ADDRESS_MAP_END + +// machine driver for barcrest mpu4 board ///////////////////////////////// + +static MACHINE_DRIVER_START( mpu4mod2 ) + + MDRV_MACHINE_START(mpu4mod2) + MDRV_MACHINE_RESET(mpu4) + MDRV_CPU_ADD_TAG("main", M6809, MPU4_MASTER_CLOCK/4) + MDRV_CPU_PROGRAM_MAP(mod2_memmap,0) + + MDRV_CPU_PERIODIC_INT(gen_50hz, 100) + + MDRV_SPEAKER_STANDARD_MONO("mono") + MDRV_SOUND_ADD_TAG("AY8913",AY8913, MPU4_MASTER_CLOCK/4) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) + + MDRV_NVRAM_HANDLER(generic_0fill) // load/save nv RAM + MDRV_DEFAULT_LAYOUT(layout_mpu4) + /* video hardware */ + MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER) + MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) + + MDRV_SCREEN_SIZE(288, 34) + MDRV_SCREEN_VISIBLE_AREA(0, 288-1, 0, 34-1) + MDRV_SCREEN_REFRESH_RATE(50) + + MDRV_PALETTE_LENGTH(16) + MDRV_COLORTABLE_LENGTH(16) + MDRV_PALETTE_INIT(mpu4) +MACHINE_DRIVER_END + + const UINT8 MPU4_chr_lut[72]= { 0x00,0x1A,0x04,0x10,0x18,0x0F,0x13,0x1B, + 0x03,0x07,0x17,0x1D,0x36,0x35,0x2B,0x28, + 0x39,0x21,0x22,0x25,0x2C,0x29,0x31,0x34, + 0x0A,0x1F,0x06,0x0E,0x1C,0x12,0x1E,0x0D, + 0x14,0x0A,0x19,0x15,0x06,0x0F,0x08,0x1B, + 0x1E,0x04,0x01,0x0C,0x18,0x1A,0x11,0x0B, + 0x03,0x17,0x10,0x1D,0x0E,0x07,0x12,0x09, + 0x0D,0x1F,0x16,0x05,0x13,0x1C,0x02,0x00, + 0x00,0x01,0x04,0x09,0x10,0x19,0x24,0x31}; + +#include "drivers/mpu4drvr.c" |