From 755b2d65645cd59004221d1534a386e88b7cd0db Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Wed, 12 Nov 2014 03:22:56 +0100 Subject: steppers: move to emu/machine --- src/emu/machine/machine.mak | 9 + src/emu/machine/steppers.c | 581 ++++++++++++++++++++++++++++++++++++++++++++ src/emu/machine/steppers.h | 65 +++++ src/mame/machine/steppers.c | 581 -------------------------------------------- src/mame/machine/steppers.h | 65 ----- src/mame/mame.mak | 3 +- 6 files changed, 656 insertions(+), 648 deletions(-) create mode 100644 src/emu/machine/steppers.c create mode 100644 src/emu/machine/steppers.h delete mode 100644 src/mame/machine/steppers.c delete mode 100644 src/mame/machine/steppers.h diff --git a/src/emu/machine/machine.mak b/src/emu/machine/machine.mak index 98ffdd4c8b1..9dbb6f8d854 100644 --- a/src/emu/machine/machine.mak +++ b/src/emu/machine/machine.mak @@ -1890,6 +1890,15 @@ ifneq ($(filter STRATA,$(MACHINES)),) MACHINEOBJS += $(MACHINEOBJ)/strata.o endif +#------------------------------------------------- +# +#@src/emu/machine/steppers.h,MACHINES += STEPPERS +#------------------------------------------------- + +ifneq ($(filter STEPPERS,$(MACHINES)),) +MACHINEOBJS += $(MACHINEOBJ)/steppers.o +endif + #------------------------------------------------- # #@src/emu/machine/corvushd.h,MACHINES += CORVUSHD diff --git a/src/emu/machine/steppers.c b/src/emu/machine/steppers.c new file mode 100644 index 00000000000..70dfe688d92 --- /dev/null +++ b/src/emu/machine/steppers.c @@ -0,0 +1,581 @@ +/////////////////////////////////////////////////////////////////////////// +// // +// steppers.c steppermotor emulation // +// // +// Emulates : Stepper motors driven with full step or half step // +// also emulates the index optic // +// // +// 26-05-2012: J. Wallace - Implemented proper phase alignment, we no // +// longer need reverse interfaces here, the // +// layout will suffice. Added belt reel handler.// +// 09-04-2012: J. Wallace - Studied some old reel motors and added a // +// number of new stepper types. I am yet to // +// add them to drivers, but barring some init // +// stuff, they should work. // +// 15-01-2012: J. Wallace - Total internal rewrite to remove the table // +// hoodoo that stops anyone but me actually // +// updating this. In theory, we should be able // +// to adapt the phase code to any reel type by // +// studying a game's startup // +// Documentation is much better now. // +// 04-04-2011: J. Wallace - Added reverse spin (this is necessary for // +// accuracy), and improved wraparound logic // +// 03-2011: New 2D array to remove reel bounce and // +// make more realistic // +// 26-01-2007: J. Wallace - Rewritten to make it more flexible // +// and to allow indices to be set in drivers // +// 29-12-2006: J. Wallace - Added state save support // +// 05-03-2004: Re-Animator // +// // +// TODO: add further types of stepper motors if needed (Konami/IGT?) // +// Someone who understands the device system may want to convert // +// this // +// 200 Step reels can alter their relative opto tab position, // +// may be worth adding the phase setting to the interface // +// There are reports that some games use a pulse that is too short// +// to give a 'judder' effect for holds, etc. We'll need to time // +// the pulses to keep tack of this without going out of sync. // +// Check 20RM and Starpoint 200 step // +/////////////////////////////////////////////////////////////////////////// + +#include "emu.h" +#include "steppers.h" + +/* local prototypes */ + +static void update_optic(int which); + +/* local vars */ + +struct stepper +{ + const stepper_interface *intf; + UINT8 pattern, /* coil pattern */ + old_pattern, /* old coil pattern */ + initphase, + phase, /* motor phase */ + old_phase, /* old phase */ + type; /* reel type */ + INT16 step_pos, /* step position 0 - max_steps */ + max_steps; /* maximum step position */ + INT32 abs_step_pos; /* absolute step position */ + + INT16 index_start, /* start position of index (in half steps) */ + index_end, /* end position of index (in half steps) */ + index_patt; /* pattern needed on coils (0=don't care) */ + + UINT8 optic; +}; + +static stepper step[MAX_STEPPERS]; + +/* useful interfaces (Starpoint is a very common setup)*/ +const stepper_interface starpoint_interface_48step = +{ + STARPOINT_48STEP_REEL, + 1, + 3, + 0x09, + 4 +}; + +const stepper_interface starpointrm20_interface_48step = +{ + STARPOINT_48STEP_REEL, + 16, + 24, + 0x09, + 7 +}; +const stepper_interface starpoint_interface_200step_reel = +{ + STARPOINT_200STEP_REEL, + 12, + 24, + 0x09, + 7 +}; +// guess +const stepper_interface ecoin_interface_200step_reel = +{ + ECOIN_200STEP_REEL, + 12, + 24, + 0x09, + 7 +}; + + + +/////////////////////////////////////////////////////////////////////////// +void stepper_config(running_machine &machine, int which, const stepper_interface *intf) +{ + assert_always(machine.phase() == MACHINE_PHASE_INIT, "Can only call stepper_config at init time!"); + assert_always((which >= 0) && (which < MAX_STEPPERS), "stepper_config called on an invalid stepper motor!"); + assert_always(intf, "stepper_config called with an invalid interface!"); + + step[which].intf = intf; + + step[which].type = intf->type; + step[which].index_start = intf->index_start;/* location of first index value in half steps */ + step[which].index_end = intf->index_end; /* location of last index value in half steps */ + step[which].index_patt = intf->index_patt; /* hex value of coil pattern (0 if not needed)*/ + step[which].initphase = intf->initphase; /* Phase at 0 steps, for alignment) */ + + + step[which].pattern = 0; + step[which].old_pattern = 0; + step[which].step_pos = 0; + step[which].abs_step_pos= 0; + step[which].phase = step[which].initphase; + step[which].old_phase = step[which].initphase; + + + switch ( step[which].type ) + { default: + case STARPOINT_48STEP_REEL: /* STARPOINT RMxxx */ + case BARCREST_48STEP_REEL : /* Barcrest Reel unit */ + case MPU3_48STEP_REEL : + case GAMESMAN_48STEP_REEL : /* Gamesman GMxxxx */ + case PROJECT_48STEP_REEL : + step[which].max_steps = (48*2); + break; + case GAMESMAN_100STEP_REEL : + step[which].max_steps = (100*2); + break; + case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */ + //Dice reels are 48 step motors, but complete three full cycles between opto updates + step[which].max_steps = ((48*3)*2); + break; + case STARPOINT_200STEP_REEL : + case GAMESMAN_200STEP_REEL : + case ECOIN_200STEP_REEL : + step[which].max_steps = (200*2); + break; + } + + state_save_register_item(machine, "stepper", NULL, which, step[which].index_start); + state_save_register_item(machine, "stepper", NULL, which, step[which].index_end); + state_save_register_item(machine, "stepper", NULL, which, step[which].index_patt); + state_save_register_item(machine, "stepper", NULL, which, step[which].initphase); + state_save_register_item(machine, "stepper", NULL, which, step[which].phase); + state_save_register_item(machine, "stepper", NULL, which, step[which].old_phase); + state_save_register_item(machine, "stepper", NULL, which, step[which].pattern); + state_save_register_item(machine, "stepper", NULL, which, step[which].old_pattern); + state_save_register_item(machine, "stepper", NULL, which, step[which].step_pos); + state_save_register_item(machine, "stepper", NULL, which, step[which].abs_step_pos); + state_save_register_item(machine, "stepper", NULL, which, step[which].max_steps); + state_save_register_item(machine, "stepper", NULL, which, step[which].type); +} + +/////////////////////////////////////////////////////////////////////////// +int stepper_get_position(int which) +{ + return step[which].step_pos; +} + +/////////////////////////////////////////////////////////////////////////// +int stepper_get_absolute_position(int which) +{ + return step[which].abs_step_pos; +} + +/////////////////////////////////////////////////////////////////////////// + +int stepper_get_max(int which) +{ + return step[which].max_steps; +} + +/////////////////////////////////////////////////////////////////////////// + +static void update_optic(int which) +{ + int pos = step[which].step_pos, + start = step[which].index_start, + end = step[which].index_end; + + if (start > end) // cope with index patterns that wrap around + { + if ( (( pos > start ) || ( pos < end )) && + ( ( step[which].pattern == step[which].index_patt || step[which].index_patt==0) || + ( step[which].pattern == 0 && + (step[which].old_pattern == step[which].index_patt || step[which].index_patt==0) + ) ) ) + { + step[which].optic = 1; + } + else step[which].optic = 0; + } + else + { + if ( (( pos > start ) && ( pos < end )) && + ( ( step[which].pattern == step[which].index_patt || step[which].index_patt==0) || + ( step[which].pattern == 0 && + (step[which].old_pattern == step[which].index_patt || step[which].index_patt==0) + ) ) ) + { + step[which].optic = 1; + } + else step[which].optic = 0; + } +} +/////////////////////////////////////////////////////////////////////////// + +void stepper_reset_position(int which) +{ + step[which].step_pos = 0x00; + step[which].abs_step_pos= 0x00; + step[which].pattern = 0x00; + step[which].old_pattern = 0x00; + step[which].phase = step[which].initphase; + step[which].old_phase = step[which].initphase; + update_optic(which); +} + +/////////////////////////////////////////////////////////////////////////// + +int stepper_optic_state(int which) +{ + int result = 0; + + if ( which < MAX_STEPPERS ) + { + result = step[which].optic; + } + + return result; +} + +/////////////////////////////////////////////////////////////////////////// + +int stepper_update(int which, UINT8 pattern) +{ + int changed = 0; + + /* This code probably makes more sense if you visualise what is being emulated, namely + a spinning drum with two electromagnets inside. Essentially, the CPU + activates a pair of windings on these magnets leads as necessary to attract and repel the drum to pull it round and + display as appropriate. To attempt to visualise the rotation effect, take a look at the compass rose below, representing a side on view of the reel, + the numbers indicate the phase information as used + + 7 + N + 1 W E 5 + S + 3 + + For sake of accuracy, we're representing all possible phases of the motor, effectively moving the motor one half step at a time, so a 48 step motor becomes + 96 half steps. This is necessary because of some programs running the wiring in series with a distinct delay between the pair being completed. This causes + a small movement that may trigger the optic tab. + */ + + int pos,steps=0; + step[which].pattern = pattern; + switch ( step[which].type ) + { + default: + logerror("No reel type specified for %x!\n",which); + break; + case STARPOINT_48STEP_REEL : /* STARPOINT RMxxx */ + case GAMESMAN_200STEP_REEL : /* Gamesman GMxxxx */ + case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */ + case STARPOINT_200STEP_REEL :/* STARPOINT 1DCU DICE mechanism */ + //Standard drive table is 2,6,4,5,1,9,8,a + //NOTE: This runs through the stator patterns in such a way as to drive the reel forward (downwards from the player's view, clockwise on our rose) + //The Heber 'Pluto' controller runs this in reverse + switch (pattern) + { //Black Blue Red Yellow + case 0x02:// 0 0 1 0 + step[which].phase = 7; + break; + case 0x06:// 0 1 1 0 + step[which].phase = 6; + break; + case 0x04:// 0 1 0 0 + step[which].phase = 5; + break; + case 0x05:// 0 1 0 1 + step[which].phase = 4; + break; + case 0x01:// 0 0 0 1 + step[which].phase = 3; + break; + case 0x09:// 1 0 0 1 + step[which].phase = 2; + break; + case 0x08:// 1 0 0 0 + step[which].phase = 1; + break; + case 0x0A:// 1 0 1 0 + step[which].phase = 0; + break; + // Black Blue Red Yellow + case 0x03:// 0 0 1 1 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + step[which].phase = 7; + } + else //otherwise it will line up due south + { + step[which].phase = 3; + } + } + break; + case 0x0C:// 1 1 0 0 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + step[which].phase = 5; + } + else //otherwise it will line up due west + { + step[which].phase = 1; + } + } + break; + } + break; + + case BARCREST_48STEP_REEL : + case GAMESMAN_48STEP_REEL : + case GAMESMAN_100STEP_REEL : + //Standard drive table is 1,3,2,6,4,C,8,9 + //Gamesman 48 step uses this pattern shifted one place forward, though this shouldn't matter + switch (pattern) + { + // Yellow Brown Orange Black + case 0x01:// 0 0 0 1 + step[which].phase = 7; + break; + case 0x03:// 0 0 1 1 + step[which].phase = 6; + break; + case 0x02:// 0 0 1 0 + step[which].phase = 5; + break; + case 0x06:// 0 1 1 0 + step[which].phase = 4; + break; + case 0x04:// 0 1 0 0 + step[which].phase = 3; + break; + case 0x0C:// 1 1 0 0 + step[which].phase = 2; + break; + case 0x08:// 1 0 0 0 + step[which].phase = 1; + break;//YOLB + case 0x09:// 1 0 0 1 + step[which].phase = 0; + break; + + // The below values should not be used by anything sane, as they effectively ignore one stator side entirely + // Yellow Brown Orange Black + case 0x05:// 0 1 0 1 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + step[which].phase = 7; + } + else //otherwise it will line up due south + { + step[which].phase = 3; + } + } + break; + + case 0x0A:// 1 0 1 0 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + step[which].phase = 5; + } + else //otherwise it will line up due west + { + step[which].phase = 1; + } + } + break; + } + break; + + case MPU3_48STEP_REEL : + /* The MPU3 interface is actually the same as the MPU4 setup, but with two active lines instead of four + Inverters are used so if a pin is low, the higher bit of the pair is activated, and if high the lower bit is activated. + TODO:Check this, 2 and 1 could be switched over. + */ + switch (pattern) + { + // Yellow(2) Brown(1) Orange(!2) Black(!1) + case 0x00 :// 0 0 1 1 + step[which].phase = 6; + break; + case 0x01 :// 0 1 1 0 + step[which].phase = 4; + break; + case 0x03 :// 1 1 0 0 + step[which].phase = 2; + break; + case 0x02 :// 1 0 0 1 + step[which].phase = 0; + break; + } + break; + + case ECOIN_200STEP_REEL : + //While the 48 and 100 step models appear to be reverse driven Starpoint reels, the 200 step model seems bespoke, certainly in terms of wiring. + //On a Proconn machine this same pattern is seen but running in reverse + //Standard drive table is 8,c,4,6,2,3,1,9 + switch (pattern) + { + case 0x08:// 0 0 1 0 + step[which].phase = 7; + break; + case 0x0c:// 0 1 1 0 + step[which].phase = 6; + break; + case 0x04:// 0 1 0 0 + step[which].phase = 5; + break; + case 0x06:// 0 1 0 1 + step[which].phase = 4; + break; + case 0x02:// 0 0 0 1 + step[which].phase = 3; + break; + case 0x03:// 1 0 0 1 + step[which].phase = 2; + break; + case 0x01:// 1 0 0 0 + step[which].phase = 1; + break; + case 0x09:// 1 0 1 0 + step[which].phase = 0; + break; + case 0x0a:// 0 0 1 1 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + step[which].phase = 7; + } + else //otherwise it will line up due south + { + step[which].phase = 3; + } + } + break; + case 0x07:// 1 1 0 0 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + step[which].phase = 5; + } + else //otherwise it will line up due west + { + step[which].phase = 1; + } + } + break; + } + break; + + case PROJECT_48STEP_REEL : + //Standard drive table is 8,c,4,5,1,3,2,a + //This appears to be basically a rewired Gamesman (the reel PCB looks like it does some shuffling) + //TODO: Not sure if this should be represented as a type here, or by defining it as a Gamesman in the driver and bitswapping. + switch (pattern) + { + case 0x08:// 0 0 1 0 + step[which].phase = 7; + break; + case 0x0c:// 0 1 1 0 + step[which].phase = 6; + break; + case 0x04:// 0 1 0 0 + step[which].phase = 5; + break; + case 0x05:// 0 1 0 1 + step[which].phase = 4; + break; + case 0x01:// 0 0 0 1 + step[which].phase = 3; + break; + case 0x03:// 1 0 0 1 + step[which].phase = 2; + break; + case 0x02:// 1 0 0 0 + step[which].phase = 1; + break; + case 0x0a:// 1 0 1 0 + step[which].phase = 0; + break; + case 0x09:// 0 0 1 1 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + step[which].phase = 7; + } + else //otherwise it will line up due south + { + step[which].phase = 3; + } + } + break; + case 0x06:// 1 1 0 0 + { + if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + step[which].phase = 5; + } + else //otherwise it will line up due west + { + step[which].phase = 1; + } + } + break; + } + break; + + + + } + + steps = step[which].old_phase - step[which].phase; + + if (steps < -4) + { + steps = steps +8; + } + if (steps > 4) + { + steps = steps -8; + } + + step[which].old_phase = step[which].phase; + step[which].old_pattern = step[which].pattern; + + int max = step[which].max_steps; + pos = 0; + + if (max!=0) + { + step[which].abs_step_pos += steps; + pos = (step[which].step_pos + steps + max) % max; + } + else + { + logerror("step[%x].max_steps == 0\n",which); + } + + if (pos != step[which].step_pos) + { + changed++; + } + + step[which].step_pos = pos; + update_optic(which); + + return changed; +} diff --git a/src/emu/machine/steppers.h b/src/emu/machine/steppers.h new file mode 100644 index 00000000000..db1b30cb1e9 --- /dev/null +++ b/src/emu/machine/steppers.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////// +// // +// steppers.c steppermotor emulation // +// // +// Emulates : stepper motors driven with full step or half step // +// also emulates the index optic // +// // +// // +// TODO: add further types of stepper motors if needed (Konami/IGT?) // +// Someone who understands the device system may want to convert // +// this // +/////////////////////////////////////////////////////////////////////////// + + +#ifndef INC_STEPPERS +#define INC_STEPPERS + +#define MAX_STEPPERS 8 /* maximum number of steppers */ + +#define STARPOINT_48STEP_REEL 0 /* STARPOINT RMXXX reel unit */ +#define STARPOINT_144STEP_DICE 1 /* STARPOINT 1DCU DICE mechanism */ +#define STARPOINT_200STEP_REEL 2 + +#define BARCREST_48STEP_REEL 3 /* Barcrest bespoke reel unit */ +#define MPU3_48STEP_REEL 4 + +#define ECOIN_200STEP_REEL 5 /* Probably not bespoke, but can't find a part number */ + +#define GAMESMAN_48STEP_REEL 6 +#define GAMESMAN_100STEP_REEL 7 +#define GAMESMAN_200STEP_REEL 8 + +#define PROJECT_48STEP_REEL 9 + +/*------------- Stepper motor interface structure -----------------*/ + +struct stepper_interface +{ + UINT8 type; /* Reel unit type */ + INT16 index_start;/* start position of index (in half steps) */ + INT16 index_end; /* end position of index (in half steps) */ + INT16 index_patt; /* pattern needed on coils (0=don't care) */ + UINT8 initphase; /* Phase at 0, for opto linkage */ +}; + +extern const stepper_interface starpoint_interface_48step; +extern const stepper_interface starpointrm20_interface_48step; + +extern const stepper_interface starpoint_interface_200step_reel; +extern const stepper_interface ecoin_interface_200step_reel; + +void stepper_config(running_machine &machine, int which, const stepper_interface *intf); + +void stepper_reset_position(int id); /* reset a motor to position 0 */ + +int stepper_optic_state( int id); /* read a motor's optics */ + +int stepper_update(int id, UINT8 pattern); /* update a motor */ + +int stepper_get_position(int id); /* get current position in half steps */ + +int stepper_get_absolute_position(int id); /* get current absolute position in half steps */ + +int stepper_get_max(int id); /* get maximum position in half steps */ +#endif diff --git a/src/mame/machine/steppers.c b/src/mame/machine/steppers.c deleted file mode 100644 index 70dfe688d92..00000000000 --- a/src/mame/machine/steppers.c +++ /dev/null @@ -1,581 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// // -// steppers.c steppermotor emulation // -// // -// Emulates : Stepper motors driven with full step or half step // -// also emulates the index optic // -// // -// 26-05-2012: J. Wallace - Implemented proper phase alignment, we no // -// longer need reverse interfaces here, the // -// layout will suffice. Added belt reel handler.// -// 09-04-2012: J. Wallace - Studied some old reel motors and added a // -// number of new stepper types. I am yet to // -// add them to drivers, but barring some init // -// stuff, they should work. // -// 15-01-2012: J. Wallace - Total internal rewrite to remove the table // -// hoodoo that stops anyone but me actually // -// updating this. In theory, we should be able // -// to adapt the phase code to any reel type by // -// studying a game's startup // -// Documentation is much better now. // -// 04-04-2011: J. Wallace - Added reverse spin (this is necessary for // -// accuracy), and improved wraparound logic // -// 03-2011: New 2D array to remove reel bounce and // -// make more realistic // -// 26-01-2007: J. Wallace - Rewritten to make it more flexible // -// and to allow indices to be set in drivers // -// 29-12-2006: J. Wallace - Added state save support // -// 05-03-2004: Re-Animator // -// // -// TODO: add further types of stepper motors if needed (Konami/IGT?) // -// Someone who understands the device system may want to convert // -// this // -// 200 Step reels can alter their relative opto tab position, // -// may be worth adding the phase setting to the interface // -// There are reports that some games use a pulse that is too short// -// to give a 'judder' effect for holds, etc. We'll need to time // -// the pulses to keep tack of this without going out of sync. // -// Check 20RM and Starpoint 200 step // -/////////////////////////////////////////////////////////////////////////// - -#include "emu.h" -#include "steppers.h" - -/* local prototypes */ - -static void update_optic(int which); - -/* local vars */ - -struct stepper -{ - const stepper_interface *intf; - UINT8 pattern, /* coil pattern */ - old_pattern, /* old coil pattern */ - initphase, - phase, /* motor phase */ - old_phase, /* old phase */ - type; /* reel type */ - INT16 step_pos, /* step position 0 - max_steps */ - max_steps; /* maximum step position */ - INT32 abs_step_pos; /* absolute step position */ - - INT16 index_start, /* start position of index (in half steps) */ - index_end, /* end position of index (in half steps) */ - index_patt; /* pattern needed on coils (0=don't care) */ - - UINT8 optic; -}; - -static stepper step[MAX_STEPPERS]; - -/* useful interfaces (Starpoint is a very common setup)*/ -const stepper_interface starpoint_interface_48step = -{ - STARPOINT_48STEP_REEL, - 1, - 3, - 0x09, - 4 -}; - -const stepper_interface starpointrm20_interface_48step = -{ - STARPOINT_48STEP_REEL, - 16, - 24, - 0x09, - 7 -}; -const stepper_interface starpoint_interface_200step_reel = -{ - STARPOINT_200STEP_REEL, - 12, - 24, - 0x09, - 7 -}; -// guess -const stepper_interface ecoin_interface_200step_reel = -{ - ECOIN_200STEP_REEL, - 12, - 24, - 0x09, - 7 -}; - - - -/////////////////////////////////////////////////////////////////////////// -void stepper_config(running_machine &machine, int which, const stepper_interface *intf) -{ - assert_always(machine.phase() == MACHINE_PHASE_INIT, "Can only call stepper_config at init time!"); - assert_always((which >= 0) && (which < MAX_STEPPERS), "stepper_config called on an invalid stepper motor!"); - assert_always(intf, "stepper_config called with an invalid interface!"); - - step[which].intf = intf; - - step[which].type = intf->type; - step[which].index_start = intf->index_start;/* location of first index value in half steps */ - step[which].index_end = intf->index_end; /* location of last index value in half steps */ - step[which].index_patt = intf->index_patt; /* hex value of coil pattern (0 if not needed)*/ - step[which].initphase = intf->initphase; /* Phase at 0 steps, for alignment) */ - - - step[which].pattern = 0; - step[which].old_pattern = 0; - step[which].step_pos = 0; - step[which].abs_step_pos= 0; - step[which].phase = step[which].initphase; - step[which].old_phase = step[which].initphase; - - - switch ( step[which].type ) - { default: - case STARPOINT_48STEP_REEL: /* STARPOINT RMxxx */ - case BARCREST_48STEP_REEL : /* Barcrest Reel unit */ - case MPU3_48STEP_REEL : - case GAMESMAN_48STEP_REEL : /* Gamesman GMxxxx */ - case PROJECT_48STEP_REEL : - step[which].max_steps = (48*2); - break; - case GAMESMAN_100STEP_REEL : - step[which].max_steps = (100*2); - break; - case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */ - //Dice reels are 48 step motors, but complete three full cycles between opto updates - step[which].max_steps = ((48*3)*2); - break; - case STARPOINT_200STEP_REEL : - case GAMESMAN_200STEP_REEL : - case ECOIN_200STEP_REEL : - step[which].max_steps = (200*2); - break; - } - - state_save_register_item(machine, "stepper", NULL, which, step[which].index_start); - state_save_register_item(machine, "stepper", NULL, which, step[which].index_end); - state_save_register_item(machine, "stepper", NULL, which, step[which].index_patt); - state_save_register_item(machine, "stepper", NULL, which, step[which].initphase); - state_save_register_item(machine, "stepper", NULL, which, step[which].phase); - state_save_register_item(machine, "stepper", NULL, which, step[which].old_phase); - state_save_register_item(machine, "stepper", NULL, which, step[which].pattern); - state_save_register_item(machine, "stepper", NULL, which, step[which].old_pattern); - state_save_register_item(machine, "stepper", NULL, which, step[which].step_pos); - state_save_register_item(machine, "stepper", NULL, which, step[which].abs_step_pos); - state_save_register_item(machine, "stepper", NULL, which, step[which].max_steps); - state_save_register_item(machine, "stepper", NULL, which, step[which].type); -} - -/////////////////////////////////////////////////////////////////////////// -int stepper_get_position(int which) -{ - return step[which].step_pos; -} - -/////////////////////////////////////////////////////////////////////////// -int stepper_get_absolute_position(int which) -{ - return step[which].abs_step_pos; -} - -/////////////////////////////////////////////////////////////////////////// - -int stepper_get_max(int which) -{ - return step[which].max_steps; -} - -/////////////////////////////////////////////////////////////////////////// - -static void update_optic(int which) -{ - int pos = step[which].step_pos, - start = step[which].index_start, - end = step[which].index_end; - - if (start > end) // cope with index patterns that wrap around - { - if ( (( pos > start ) || ( pos < end )) && - ( ( step[which].pattern == step[which].index_patt || step[which].index_patt==0) || - ( step[which].pattern == 0 && - (step[which].old_pattern == step[which].index_patt || step[which].index_patt==0) - ) ) ) - { - step[which].optic = 1; - } - else step[which].optic = 0; - } - else - { - if ( (( pos > start ) && ( pos < end )) && - ( ( step[which].pattern == step[which].index_patt || step[which].index_patt==0) || - ( step[which].pattern == 0 && - (step[which].old_pattern == step[which].index_patt || step[which].index_patt==0) - ) ) ) - { - step[which].optic = 1; - } - else step[which].optic = 0; - } -} -/////////////////////////////////////////////////////////////////////////// - -void stepper_reset_position(int which) -{ - step[which].step_pos = 0x00; - step[which].abs_step_pos= 0x00; - step[which].pattern = 0x00; - step[which].old_pattern = 0x00; - step[which].phase = step[which].initphase; - step[which].old_phase = step[which].initphase; - update_optic(which); -} - -/////////////////////////////////////////////////////////////////////////// - -int stepper_optic_state(int which) -{ - int result = 0; - - if ( which < MAX_STEPPERS ) - { - result = step[which].optic; - } - - return result; -} - -/////////////////////////////////////////////////////////////////////////// - -int stepper_update(int which, UINT8 pattern) -{ - int changed = 0; - - /* This code probably makes more sense if you visualise what is being emulated, namely - a spinning drum with two electromagnets inside. Essentially, the CPU - activates a pair of windings on these magnets leads as necessary to attract and repel the drum to pull it round and - display as appropriate. To attempt to visualise the rotation effect, take a look at the compass rose below, representing a side on view of the reel, - the numbers indicate the phase information as used - - 7 - N - 1 W E 5 - S - 3 - - For sake of accuracy, we're representing all possible phases of the motor, effectively moving the motor one half step at a time, so a 48 step motor becomes - 96 half steps. This is necessary because of some programs running the wiring in series with a distinct delay between the pair being completed. This causes - a small movement that may trigger the optic tab. - */ - - int pos,steps=0; - step[which].pattern = pattern; - switch ( step[which].type ) - { - default: - logerror("No reel type specified for %x!\n",which); - break; - case STARPOINT_48STEP_REEL : /* STARPOINT RMxxx */ - case GAMESMAN_200STEP_REEL : /* Gamesman GMxxxx */ - case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */ - case STARPOINT_200STEP_REEL :/* STARPOINT 1DCU DICE mechanism */ - //Standard drive table is 2,6,4,5,1,9,8,a - //NOTE: This runs through the stator patterns in such a way as to drive the reel forward (downwards from the player's view, clockwise on our rose) - //The Heber 'Pluto' controller runs this in reverse - switch (pattern) - { //Black Blue Red Yellow - case 0x02:// 0 0 1 0 - step[which].phase = 7; - break; - case 0x06:// 0 1 1 0 - step[which].phase = 6; - break; - case 0x04:// 0 1 0 0 - step[which].phase = 5; - break; - case 0x05:// 0 1 0 1 - step[which].phase = 4; - break; - case 0x01:// 0 0 0 1 - step[which].phase = 3; - break; - case 0x09:// 1 0 0 1 - step[which].phase = 2; - break; - case 0x08:// 1 0 0 0 - step[which].phase = 1; - break; - case 0x0A:// 1 0 1 0 - step[which].phase = 0; - break; - // Black Blue Red Yellow - case 0x03:// 0 0 1 1 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now - { - step[which].phase = 7; - } - else //otherwise it will line up due south - { - step[which].phase = 3; - } - } - break; - case 0x0C:// 1 1 0 0 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now - { - step[which].phase = 5; - } - else //otherwise it will line up due west - { - step[which].phase = 1; - } - } - break; - } - break; - - case BARCREST_48STEP_REEL : - case GAMESMAN_48STEP_REEL : - case GAMESMAN_100STEP_REEL : - //Standard drive table is 1,3,2,6,4,C,8,9 - //Gamesman 48 step uses this pattern shifted one place forward, though this shouldn't matter - switch (pattern) - { - // Yellow Brown Orange Black - case 0x01:// 0 0 0 1 - step[which].phase = 7; - break; - case 0x03:// 0 0 1 1 - step[which].phase = 6; - break; - case 0x02:// 0 0 1 0 - step[which].phase = 5; - break; - case 0x06:// 0 1 1 0 - step[which].phase = 4; - break; - case 0x04:// 0 1 0 0 - step[which].phase = 3; - break; - case 0x0C:// 1 1 0 0 - step[which].phase = 2; - break; - case 0x08:// 1 0 0 0 - step[which].phase = 1; - break;//YOLB - case 0x09:// 1 0 0 1 - step[which].phase = 0; - break; - - // The below values should not be used by anything sane, as they effectively ignore one stator side entirely - // Yellow Brown Orange Black - case 0x05:// 0 1 0 1 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now - { - step[which].phase = 7; - } - else //otherwise it will line up due south - { - step[which].phase = 3; - } - } - break; - - case 0x0A:// 1 0 1 0 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now - { - step[which].phase = 5; - } - else //otherwise it will line up due west - { - step[which].phase = 1; - } - } - break; - } - break; - - case MPU3_48STEP_REEL : - /* The MPU3 interface is actually the same as the MPU4 setup, but with two active lines instead of four - Inverters are used so if a pin is low, the higher bit of the pair is activated, and if high the lower bit is activated. - TODO:Check this, 2 and 1 could be switched over. - */ - switch (pattern) - { - // Yellow(2) Brown(1) Orange(!2) Black(!1) - case 0x00 :// 0 0 1 1 - step[which].phase = 6; - break; - case 0x01 :// 0 1 1 0 - step[which].phase = 4; - break; - case 0x03 :// 1 1 0 0 - step[which].phase = 2; - break; - case 0x02 :// 1 0 0 1 - step[which].phase = 0; - break; - } - break; - - case ECOIN_200STEP_REEL : - //While the 48 and 100 step models appear to be reverse driven Starpoint reels, the 200 step model seems bespoke, certainly in terms of wiring. - //On a Proconn machine this same pattern is seen but running in reverse - //Standard drive table is 8,c,4,6,2,3,1,9 - switch (pattern) - { - case 0x08:// 0 0 1 0 - step[which].phase = 7; - break; - case 0x0c:// 0 1 1 0 - step[which].phase = 6; - break; - case 0x04:// 0 1 0 0 - step[which].phase = 5; - break; - case 0x06:// 0 1 0 1 - step[which].phase = 4; - break; - case 0x02:// 0 0 0 1 - step[which].phase = 3; - break; - case 0x03:// 1 0 0 1 - step[which].phase = 2; - break; - case 0x01:// 1 0 0 0 - step[which].phase = 1; - break; - case 0x09:// 1 0 1 0 - step[which].phase = 0; - break; - case 0x0a:// 0 0 1 1 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now - { - step[which].phase = 7; - } - else //otherwise it will line up due south - { - step[which].phase = 3; - } - } - break; - case 0x07:// 1 1 0 0 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now - { - step[which].phase = 5; - } - else //otherwise it will line up due west - { - step[which].phase = 1; - } - } - break; - } - break; - - case PROJECT_48STEP_REEL : - //Standard drive table is 8,c,4,5,1,3,2,a - //This appears to be basically a rewired Gamesman (the reel PCB looks like it does some shuffling) - //TODO: Not sure if this should be represented as a type here, or by defining it as a Gamesman in the driver and bitswapping. - switch (pattern) - { - case 0x08:// 0 0 1 0 - step[which].phase = 7; - break; - case 0x0c:// 0 1 1 0 - step[which].phase = 6; - break; - case 0x04:// 0 1 0 0 - step[which].phase = 5; - break; - case 0x05:// 0 1 0 1 - step[which].phase = 4; - break; - case 0x01:// 0 0 0 1 - step[which].phase = 3; - break; - case 0x03:// 1 0 0 1 - step[which].phase = 2; - break; - case 0x02:// 1 0 0 0 - step[which].phase = 1; - break; - case 0x0a:// 1 0 1 0 - step[which].phase = 0; - break; - case 0x09:// 0 0 1 1 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now - { - step[which].phase = 7; - } - else //otherwise it will line up due south - { - step[which].phase = 3; - } - } - break; - case 0x06:// 1 1 0 0 - { - if ((step[which].old_phase ==6)||(step[which].old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now - { - step[which].phase = 5; - } - else //otherwise it will line up due west - { - step[which].phase = 1; - } - } - break; - } - break; - - - - } - - steps = step[which].old_phase - step[which].phase; - - if (steps < -4) - { - steps = steps +8; - } - if (steps > 4) - { - steps = steps -8; - } - - step[which].old_phase = step[which].phase; - step[which].old_pattern = step[which].pattern; - - int max = step[which].max_steps; - pos = 0; - - if (max!=0) - { - step[which].abs_step_pos += steps; - pos = (step[which].step_pos + steps + max) % max; - } - else - { - logerror("step[%x].max_steps == 0\n",which); - } - - if (pos != step[which].step_pos) - { - changed++; - } - - step[which].step_pos = pos; - update_optic(which); - - return changed; -} diff --git a/src/mame/machine/steppers.h b/src/mame/machine/steppers.h deleted file mode 100644 index db1b30cb1e9..00000000000 --- a/src/mame/machine/steppers.h +++ /dev/null @@ -1,65 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// // -// steppers.c steppermotor emulation // -// // -// Emulates : stepper motors driven with full step or half step // -// also emulates the index optic // -// // -// // -// TODO: add further types of stepper motors if needed (Konami/IGT?) // -// Someone who understands the device system may want to convert // -// this // -/////////////////////////////////////////////////////////////////////////// - - -#ifndef INC_STEPPERS -#define INC_STEPPERS - -#define MAX_STEPPERS 8 /* maximum number of steppers */ - -#define STARPOINT_48STEP_REEL 0 /* STARPOINT RMXXX reel unit */ -#define STARPOINT_144STEP_DICE 1 /* STARPOINT 1DCU DICE mechanism */ -#define STARPOINT_200STEP_REEL 2 - -#define BARCREST_48STEP_REEL 3 /* Barcrest bespoke reel unit */ -#define MPU3_48STEP_REEL 4 - -#define ECOIN_200STEP_REEL 5 /* Probably not bespoke, but can't find a part number */ - -#define GAMESMAN_48STEP_REEL 6 -#define GAMESMAN_100STEP_REEL 7 -#define GAMESMAN_200STEP_REEL 8 - -#define PROJECT_48STEP_REEL 9 - -/*------------- Stepper motor interface structure -----------------*/ - -struct stepper_interface -{ - UINT8 type; /* Reel unit type */ - INT16 index_start;/* start position of index (in half steps) */ - INT16 index_end; /* end position of index (in half steps) */ - INT16 index_patt; /* pattern needed on coils (0=don't care) */ - UINT8 initphase; /* Phase at 0, for opto linkage */ -}; - -extern const stepper_interface starpoint_interface_48step; -extern const stepper_interface starpointrm20_interface_48step; - -extern const stepper_interface starpoint_interface_200step_reel; -extern const stepper_interface ecoin_interface_200step_reel; - -void stepper_config(running_machine &machine, int which, const stepper_interface *intf); - -void stepper_reset_position(int id); /* reset a motor to position 0 */ - -int stepper_optic_state( int id); /* read a motor's optics */ - -int stepper_update(int id, UINT8 pattern); /* update a motor */ - -int stepper_get_position(int id); /* get current position in half steps */ - -int stepper_get_absolute_position(int id); /* get current absolute position in half steps */ - -int stepper_get_max(int id); /* get maximum position in half steps */ -#endif diff --git a/src/mame/mame.mak b/src/mame/mame.mak index b6755456c98..cb5a4bb0cfc 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -564,6 +564,7 @@ MACHINES += FDC37C665GT #MACHINES += SMC92X4 #MACHINES += TI99_HD #MACHINES += STRATA +MACHINES += STEPPERS #MACHINES += CORVUSHD #MACHINES += WOZFDC #MACHINES += DIABLO_HD @@ -954,7 +955,6 @@ $(MAMEOBJ)/barcrest.a: \ $(DRIVERS)/mpu5hw.o $(DRIVERS)/mpu5.o \ $(VIDEO)/awpvid.o \ $(MACHINE)/meters.o \ - $(MACHINE)/steppers.o \ $(MAMEOBJ)/bfm.a: \ $(DRIVERS)/bfcobra.o \ @@ -1289,7 +1289,6 @@ $(MAMEOBJ)/jpm.a: \ $(DRIVERS)/jpmsys7.o \ $(VIDEO)/awpvid.o \ $(MACHINE)/meters.o \ - $(MACHINE)/steppers.o \ $(MAMEOBJ)/kaneko.a: \ $(DRIVERS)/airbustr.o $(VIDEO)/airbustr.o \ -- cgit v1.2.3 From 32bfdf37522b29c15899b1e445044c8973787b34 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 7 Nov 2014 05:26:06 +0100 Subject: lx810l, ap2000: implement working devices Improve Epson LX-810L and ActionPrinter 2000 up to a point where they actually work. Devices boot and enter main input loop, but input is not yet implemented. It is possible to run the printers' self test. The code has also been split from lx800. --- src/emu/bus/bus.mak | 2 + src/emu/bus/centronics/ctronics.c | 1 + src/emu/bus/centronics/epson_lx800.c | 61 ---- src/emu/bus/centronics/epson_lx800.h | 28 -- src/emu/bus/centronics/epson_lx810l.c | 587 ++++++++++++++++++++++++++++++++++ src/emu/bus/centronics/epson_lx810l.h | 117 +++++++ src/emu/machine/e05a30.c | 163 ++++++++++ src/emu/machine/e05a30.h | 71 ++++ src/emu/machine/machine.mak | 9 + src/mame/mame.mak | 1 + src/mess/includes/amstrad.h | 1 + src/mess/mess.mak | 2 + src/targets/mess.lst | 1 + 13 files changed, 955 insertions(+), 89 deletions(-) create mode 100644 src/emu/bus/centronics/epson_lx810l.c create mode 100644 src/emu/bus/centronics/epson_lx810l.h create mode 100644 src/emu/machine/e05a30.c create mode 100644 src/emu/machine/e05a30.h diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak index 77b9facce09..c9bf3b24006 100644 --- a/src/emu/bus/bus.mak +++ b/src/emu/bus/bus.mak @@ -956,10 +956,12 @@ BUSOBJS += $(BUSOBJ)/centronics/covox.o BUSOBJS += $(BUSOBJ)/centronics/dsjoy.o BUSOBJS += $(BUSOBJ)/centronics/epson_ex800.o BUSOBJS += $(BUSOBJ)/centronics/epson_lx800.o +BUSOBJS += $(BUSOBJ)/centronics/epson_lx810l.o BUSOBJS += $(BUSOBJ)/centronics/printer.o BUSOBJS += $(BUSOBJ)/centronics/digiblst.o $(BUSOBJ)/centronics/epson_ex800.o: $(EMUOBJ)/layout/ex800.lh $(BUSOBJ)/centronics/epson_lx800.o: $(EMUOBJ)/layout/lx800.lh +$(BUSOBJ)/centronics/epson_lx810l.o: $(EMUOBJ)/layout/lx800.lh endif #------------------------------------------------- diff --git a/src/emu/bus/centronics/ctronics.c b/src/emu/bus/centronics/ctronics.c index b7c87a3b79b..58329364b0a 100644 --- a/src/emu/bus/centronics/ctronics.c +++ b/src/emu/bus/centronics/ctronics.c @@ -119,6 +119,7 @@ device_centronics_peripheral_interface::~device_centronics_peripheral_interface( #include "comxpl80.h" #include "epson_ex800.h" #include "epson_lx800.h" +#include "epson_lx810l.h" #include "printer.h" #include "covox.h" diff --git a/src/emu/bus/centronics/epson_lx800.c b/src/emu/bus/centronics/epson_lx800.c index 96aa229a462..e46f6f18baf 100644 --- a/src/emu/bus/centronics/epson_lx800.c +++ b/src/emu/bus/centronics/epson_lx800.c @@ -15,19 +15,6 @@ input buttons and switches. - CPU disassembly doesn't seem to indicate conditional JR or RET. - - 2014-06-10 Added LX810L, gets caught in a loop almost immediately. - IC list: - * uPD7810HG (cpu) - * E05A30 (gate array) - * 2064C (8k RAM) - * ER59256 (EEP-ROM - serial nvram) - * SLA7020M (step motor driver) - * uPC494C (pulse width modulation control) - May need to be split off to another driver. - - 2014-06-10 Added AP2000, gets caught in the same place as LX810L. - **********************************************************************/ #include "epson_lx800.h" @@ -40,8 +27,6 @@ //************************************************************************** const device_type EPSON_LX800 = &device_creator; -const device_type EPSON_LX810L = &device_creator; -const device_type EPSON_AP2000 = &device_creator; //------------------------------------------------- @@ -54,26 +39,6 @@ ROM_START( lx800 ) ROM_END -//------------------------------------------------- -// ROM( lx810l ) -//------------------------------------------------- - -ROM_START( lx810l ) - ROM_REGION(0x8000, "maincpu", 0) - ROM_LOAD("lx810l.ic3c", 0x0000, 0x8000, CRC(a66454e1) SHA1(8e6f2f98abcbd8af6e34b9ba746edf0d18aef843) ) -ROM_END - - -//------------------------------------------------- -// ROM( ap2000 ) -//------------------------------------------------- - -ROM_START( ap2000 ) - ROM_REGION(0x8000, "maincpu", 0) - ROM_LOAD("ap2k.ic3c", 0x0000, 0x8000, CRC(ee7294b7) SHA1(219ffa6ff661ce95d5772c9fc1967093718f04e9) ) -ROM_END - - //------------------------------------------------- // rom_region - device-specific ROM region //------------------------------------------------- @@ -84,26 +49,6 @@ const rom_entry *epson_lx800_t::device_rom_region() const } -//------------------------------------------------- -// rom_region - device-specific ROM region -//------------------------------------------------- - -const rom_entry *epson_lx810l_t::device_rom_region() const -{ - return ROM_NAME( lx810l ); -} - - -//------------------------------------------------- -// rom_region - device-specific ROM region -//------------------------------------------------- - -const rom_entry *epson_ap2000_t::device_rom_region() const -{ - return ROM_NAME( ap2000 ); -} - - //------------------------------------------------- // ADDRESS_MAP( lx800_mem ) //------------------------------------------------- @@ -273,12 +218,6 @@ epson_lx800_t::epson_lx800_t(const machine_config &mconfig, device_type type, co { } -epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : epson_lx800_t(mconfig, EPSON_LX810L, "Epson LX-810L", tag, owner, clock, "lx810l", __FILE__) { } - -epson_ap2000_t::epson_ap2000_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : epson_lx800_t(mconfig, EPSON_AP2000, "Epson ActionPrinter 2000", tag, owner, clock, "ap2000", __FILE__) { } - //------------------------------------------------- // device_start - device-specific startup diff --git a/src/emu/bus/centronics/epson_lx800.h b/src/emu/bus/centronics/epson_lx800.h index 258aeb3230d..1507b34b4d5 100644 --- a/src/emu/bus/centronics/epson_lx800.h +++ b/src/emu/bus/centronics/epson_lx800.h @@ -67,37 +67,9 @@ private: }; -// ======================> epson_lx810l_t - -class epson_lx810l_t : public epson_lx800_t -{ -public: - // construction/destruction - epson_lx810l_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - // optional information overrides - virtual const rom_entry *device_rom_region() const; -}; - - -// ======================> epson_ap2000_t - -class epson_ap2000_t : public epson_lx800_t -{ -public: - // construction/destruction - epson_ap2000_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - // optional information overrides - virtual const rom_entry *device_rom_region() const; -}; - - // device type definition extern const device_type EPSON_LX800; -extern const device_type EPSON_LX810L; -extern const device_type EPSON_AP2000; diff --git a/src/emu/bus/centronics/epson_lx810l.c b/src/emu/bus/centronics/epson_lx810l.c new file mode 100644 index 00000000000..2882e7cfbc8 --- /dev/null +++ b/src/emu/bus/centronics/epson_lx810l.c @@ -0,0 +1,587 @@ +/* + * Epson LX-810L dot matrix printer emulation + * + * Copyright: 2014 Ramiro Polla + * Felipe Sanches + * License: BSD-3-Clause + * + * IC list: + * uPD7810HG (cpu) + * E05A30 (gate array) + * 2064C (8k RAM) + * ER59256 (EEP-ROM - serial nvram) + * SLA7020M (step motor driver) + * uPC494C (pulse width modulation control) + * + * Devices boot and enter main input loop, but input is not yet implemented. + * + * It is possible to run the printers' self test with this procedure: + * - Turn on device; + * - Toggle Line Feed button (press 'L'); + * - Reset device; + * - Toggle Line Feed button again; + * - Press Online button (press 'O'); + * - Press Online button again; + * + * The printer's carriage will seek home, it will pull in paper for a while, + * and it will start printing some test data. The Online LED will blink at + * each line. Look at the output from the fire signal to see what's actually + * being printed (epson_lx810l_t::co0_w()). + */ + +#include "epson_lx810l.h" +extern const char layout_lx800[]; /* use layout from lx800 */ + +//#define LX810LDEBUG +#ifdef LX810LDEBUG +#define LX810LLOG(...) fprintf(stderr, __VA_ARGS__) +#else +#define LX810LLOG(...) +#endif + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EPSON_LX810L = &device_creator; +const device_type EPSON_AP2000 = &device_creator; + + +//------------------------------------------------- +// ROM( lx810l ) +//------------------------------------------------- + +ROM_START( lx810l ) + ROM_REGION(0x8000, "maincpu", 0) + ROM_LOAD("lx810l.ic3c", 0x0000, 0x8000, CRC(a66454e1) SHA1(8e6f2f98abcbd8af6e34b9ba746edf0d18aef843) ) + ROM_REGION(0x20, "eeprom", 0) + ROM_LOAD( "at93c06", 0x00, 0x20, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( ap2000 ) +//------------------------------------------------- + +ROM_START( ap2000 ) + ROM_REGION(0x8000, "maincpu", 0) + ROM_LOAD("ap2k.ic3c", 0x0000, 0x8000, CRC(ee7294b7) SHA1(219ffa6ff661ce95d5772c9fc1967093718f04e9) ) + ROM_REGION(0x20, "eeprom", 0) + ROM_LOAD( "at93c06", 0x00, 0x20, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *epson_lx810l_t::device_rom_region() const +{ + return ROM_NAME( lx810l ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *epson_ap2000_t::device_rom_region() const +{ + return ROM_NAME( ap2000 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( lx810l_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( lx810l_mem, AS_PROGRAM, 8, epson_lx810l_t ) + AM_RANGE(0x0000, 0x7fff) AM_ROM /* 32k firmware */ + AM_RANGE(0x8000, 0x9fff) AM_RAM /* 8k external RAM */ + AM_RANGE(0xa000, 0xbfff) AM_READWRITE(fakemem_r, fakemem_w) /* fake memory, write one, set all */ + AM_RANGE(0xc000, 0xdfff) AM_MIRROR(0x1ff0) AM_DEVREADWRITE("ic3b", e05a30_device, read, write) + AM_RANGE(0xe000, 0xfeff) AM_NOP /* not used */ + AM_RANGE(0xff00, 0xffff) AM_RAM /* internal CPU RAM */ +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( lx810l_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( lx810l_io, AS_IO, 8, epson_lx810l_t ) + AM_RANGE(UPD7810_PORTA, UPD7810_PORTA) AM_READWRITE(porta_r, porta_w) + AM_RANGE(UPD7810_PORTB, UPD7810_PORTB) AM_READWRITE(portb_r, portb_w) + AM_RANGE(UPD7810_PORTC, UPD7810_PORTC) AM_READWRITE(portc_r, portc_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( epson_lx810l ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( epson_lx810l ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", UPD7810, XTAL_14_7456MHz) + MCFG_CPU_PROGRAM_MAP(lx810l_mem) + MCFG_CPU_IO_MAP(lx810l_io) + MCFG_UPD7810_AN0(READ8(epson_lx810l_t, an0_r)) + MCFG_UPD7810_AN1(READ8(epson_lx810l_t, an1_r)) + MCFG_UPD7810_AN2(READ8(epson_lx810l_t, an2_r)) + MCFG_UPD7810_AN3(READ8(epson_lx810l_t, an3_r)) + MCFG_UPD7810_AN4(READ8(epson_lx810l_t, an4_r)) + MCFG_UPD7810_AN5(READ8(epson_lx810l_t, an5_r)) + MCFG_UPD7810_AN6(READ8(epson_lx810l_t, an6_r)) + MCFG_UPD7810_AN7(READ8(epson_lx810l_t, an7_r)) + MCFG_UPD7810_CO0(WRITELINE(epson_lx810l_t, co0_w)) + MCFG_UPD7810_CO1(WRITELINE(epson_lx810l_t, co1_w)) + + MCFG_DEFAULT_LAYOUT(layout_lx800) + + /* audio hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("beeper", BEEP, 0) + MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + /* gate array */ + MCFG_DEVICE_ADD("ic3b", E05A30, 0) + MCFG_E05A30_PRINTHEAD_CALLBACK(WRITE16(epson_lx810l_t, printhead)) + MCFG_E05A30_PF_STEPPER_CALLBACK(WRITE8(epson_lx810l_t, pf_stepper)) + MCFG_E05A30_CR_STEPPER_CALLBACK(WRITE8(epson_lx810l_t, cr_stepper)) + MCFG_E05A30_READY_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_ready)) + + /* 256-bit eeprom */ + MCFG_EEPROM_SERIAL_93C06_ADD("eeprom") +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor epson_lx810l_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( epson_lx810l ); +} + + +/*************************************************************************** + INPUT PORTS +***************************************************************************/ + +static INPUT_PORTS_START( epson_lx810l ) + + /* Buttons on printer */ + PORT_START("ONLINE") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("On Line") PORT_CODE(KEYCODE_O) PORT_CHANGED_MEMBER(DEVICE_SELF, epson_lx810l_t, online_sw, NULL) + PORT_START("FORMFEED") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Form Feed") PORT_CODE(KEYCODE_F) PORT_TOGGLE + PORT_START("LINEFEED") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_L) PORT_TOGGLE + PORT_START("LOADEJECT") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Load/Eject") PORT_CODE(KEYCODE_E) + + /* DIPSW1 */ + PORT_START("DIPSW1") + + PORT_DIPNAME(0x01, 0x01, "Character spacing") + PORT_DIPLOCATION("DIP:1") + PORT_DIPSETTING(0x01, "12 cpi") /* default */ + PORT_DIPSETTING(0x00, "10 cpi") + + PORT_DIPNAME(0x02, 0x00, "Shape of zero") + PORT_DIPLOCATION("DIP:2") + PORT_DIPSETTING(0x02, "Slashed") + PORT_DIPSETTING(0x00, "Not slashed") /* default */ + + PORT_DIPNAME(0x0c, 0x08, "Page length") + PORT_DIPLOCATION("DIP:3,4") + PORT_DIPSETTING(0x00, "11 inches") + PORT_DIPSETTING(0x04, "12 inches") + PORT_DIPSETTING(0x08, "8.5 inches") /* default */ + PORT_DIPSETTING(0x0c, "11.7 inches") + + PORT_DIPNAME(0x10, 0x10, "Character table") + PORT_DIPLOCATION("DIP:5") + PORT_DIPSETTING(0x10, "Graphics") /* default */ + PORT_DIPSETTING(0x00, "Italics") + + PORT_DIPNAME(0xe0, 0xe0, "International characters and PC selection") + PORT_DIPLOCATION("DIP:6,7,8") + PORT_DIPSETTING(0xe0, "United States") /* default */ + PORT_DIPSETTING(0x60, "France") + PORT_DIPSETTING(0xa0, "Germany") + PORT_DIPSETTING(0x20, "United Kingdom") + PORT_DIPSETTING(0xc0, "Denmark") + PORT_DIPSETTING(0x40, "Sweden") + PORT_DIPSETTING(0x80, "Italy") + PORT_DIPSETTING(0x00, "Spain") + + /* DIPSW2 */ + PORT_START("DIPSW2") + + PORT_DIPNAME(0x01, 0x01, "Short tear-off") + PORT_DIPLOCATION("DIP:1") + PORT_DIPSETTING(0x01, "Invalid") /* default */ + PORT_DIPSETTING(0x00, "Valid") + + PORT_DIPNAME(0x02, 0x00, "Cut-sheet feeder mode") + PORT_DIPLOCATION("DIP:2") + PORT_DIPSETTING(0x02, "ON") + PORT_DIPSETTING(0x00, "OFF") /* default */ + + PORT_DIPNAME(0x04, 0x00, "Skip-over-perforation") + PORT_DIPLOCATION("DIP:3") + PORT_DIPSETTING(0x04, "ON") + PORT_DIPSETTING(0x00, "OFF") /* default */ + + PORT_DIPNAME(0x08, 0x00, "Auto line feed") + PORT_DIPLOCATION("DIP:4") + PORT_DIPSETTING(0x08, "ON") + PORT_DIPSETTING(0x00, "OFF") /* default */ + +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor epson_lx810l_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( epson_lx810l ); +} + +INPUT_CHANGED_MEMBER(epson_lx810l_t::online_sw) +{ + m_maincpu->set_input_line(UPD7810_INTF2, newval ? CLEAR_LINE : ASSERT_LINE); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_lx810l_t - constructor +//------------------------------------------------- + +epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_LX810L, "Epson LX-810L", tag, owner, clock, "lx810l", __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_eeprom(*this, "eeprom"), + m_speaker(*this, "speaker"), + m_93c06_clk(0), + m_93c06_cs(0), + m_printhead(0), + m_pf_pos_abs(200), + m_cr_pos_abs(200), + m_last_fire(0) +{ +} + +epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_eeprom(*this, "eeprom"), + m_speaker(*this, "speaker"), + m_93c06_clk(0), + m_93c06_cs(0), + m_printhead(0), + m_pf_pos_abs(200), + m_cr_pos_abs(200), + m_last_fire(0) +{ +} + +epson_ap2000_t::epson_ap2000_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : epson_lx810l_t(mconfig, EPSON_AP2000, "Epson ActionPrinter 2000", tag, owner, clock, "ap2000", __FILE__) +{ } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +static const stepper_interface lx810l_pf_stepper = +{ + STARPOINT_48STEP_REEL, + 16, + 24, + 0x00, + 0 +}; + +static const stepper_interface lx810l_cr_stepper = +{ + STARPOINT_48STEP_REEL, + 16, + 24, + 0x00, + 2 +}; + +void epson_lx810l_t::device_start() +{ + stepper_config(machine(), 0, &lx810l_pf_stepper); + stepper_config(machine(), 1, &lx810l_cr_stepper); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_lx810l_t::device_reset() +{ + m_speaker->level_w(0); +} + + +/*************************************************************************** + FAKEMEM READ/WRITE +***************************************************************************/ + +READ8_MEMBER(epson_lx810l_t::fakemem_r) +{ + return m_fakemem; +} + +WRITE8_MEMBER(epson_lx810l_t::fakemem_w) +{ + m_fakemem = data; +} + + +/*************************************************************************** + I/O PORTS +***************************************************************************/ + +/* + * PA0 R CN7 sensor (Home Position, HP, active low) + * PA1 R CN6 sensor (Paper-End, PE, active low) + * PA2 R CN4 sensor (Release, low = tractor) + * PA3 W Stepper motor voltage reference (these 3 pins make up one voltage) + * PA4 W Stepper motor voltage reference (these 3 pins make up one voltage) + * PA5 W Stepper motor voltage reference (these 3 pins make up one voltage) + * PA6 R Line Feed SWITCH + * PA7 R Form Feed SWITCH + */ +READ8_MEMBER( epson_lx810l_t::porta_r ) +{ + UINT8 result = 0; + UINT8 hp_sensor = m_cr_pos_abs <= 0 ? 0 : 1; + UINT8 pe_sensor = m_pf_pos_abs <= 0 ? 1 : 0; + + result |= hp_sensor; /* home position */ + result |= pe_sensor << 1; /* paper end */ + result |= ioport("LINEFEED")->read() << 6; + result |= ioport("FORMFEED")->read() << 7; + + LX810LLOG("%s: lx810l_PA_r(%02x): result %02x\n", machine().describe_context(), offset, result); + + return result; +} + +WRITE8_MEMBER( epson_lx810l_t::porta_w ) +{ + LX810LLOG("%s: lx810l_PA_w(%02x): %02x: stepper vref %d\n", machine().describe_context(), offset, data, BIT(data, 3) | (BIT(data, 4)<<1) | (BIT(data, 5)<<2)); +} + +/* + * PB0 R DIP1.0 & 93C06.DO + * PB1 RW DIP1.1 & 93C06.DI + * PB2 R DIP1.2 + * PB3 R DIP1.3 + * PB4 R DIP1.4 + * PB5 R DIP1.5 + * PB6 R DIP1.6 + * PB7 R DIP1.7 + */ +READ8_MEMBER( epson_lx810l_t::portb_r ) +{ + UINT8 result = ~ioport("DIPSW1")->read(); + + /* if 93C06 is selected */ + if (m_93c06_cs) { + UINT8 do_r = m_eeprom->do_read(); + result &= 0xfe; + result |= do_r; + } + + LX810LLOG("%s: lx810l_PB_r(%02x): result %02x\n", machine().describe_context(), offset, result); + + return result; +} + +WRITE8_MEMBER( epson_lx810l_t::portb_w ) +{ + UINT8 data_in = BIT(data, 1); + + /* if 93C06 is selected */ + if (m_93c06_cs) + m_eeprom->di_write(data_in); + + LX810LLOG("%s: lx810l_PB_w(%02x): %02x: 93c06 data %d\n", machine().describe_context(), offset, data, data_in); +} + +/* + * PC0 W TXD serial i/o txd, also TAMA.25 + * PC1 R RXD serial i/o rxd, also E05A30.28 + * PC2 W ONLINE LP online led + * PC3 R ONLINE SW online switch + * PC4 W 93C06.SK + * PC5 W 93C06.CS + * PC6 W FIRE drive pulse width signal, also E05A30.57 + * PC7 W BUZZER buzzer signal + */ +READ8_MEMBER( epson_lx810l_t::portc_r ) +{ + UINT8 result = 0; + + /* result |= ioport("serial")->read() << 1; */ + result |= !ioport("ONLINE")->read() << 3; + result |= m_93c06_clk << 4; + result |= m_93c06_cs << 5; + + LX810LLOG("%s: lx810l_PC_r(%02x): %02x\n", machine().describe_context(), offset, result); + + return result; +} + +WRITE8_MEMBER( epson_lx810l_t::portc_w ) +{ + /* ioport("serial")->write(BIT(data, 0)); */ + + m_93c06_clk = BIT(data, 4); + m_93c06_cs = !BIT(data, 5); + + LX810LLOG("%s: PC_w(%02x): %02x 93c06 clk: %d cs: %d\n", machine().describe_context(), offset, data, m_93c06_clk, m_93c06_cs); + + m_eeprom->clk_write(m_93c06_clk ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->cs_write (m_93c06_cs ? ASSERT_LINE : CLEAR_LINE); + + output_set_value("online_led", !BIT(data, 2)); +} + + +/*************************************************************************** + GATE ARRAY +***************************************************************************/ + +WRITE16_MEMBER( epson_lx810l_t::printhead ) +{ + m_printhead = data; +} + +WRITE8_MEMBER( epson_lx810l_t::pf_stepper ) +{ + stepper_update(0, data); + m_pf_pos_abs = 200 - stepper_get_absolute_position(0); + + LX810LLOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_pf_pos_abs); +} + +WRITE8_MEMBER( epson_lx810l_t::cr_stepper ) +{ + stepper_update(1, data); + m_cr_pos_abs = 200 - stepper_get_absolute_position(1); + + LX810LLOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_cr_pos_abs); +} + +WRITE_LINE_MEMBER( epson_lx810l_t::e05a30_ready ) +{ + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); +} + + +/*************************************************************************** + Extended Timer Output +***************************************************************************/ + +WRITE_LINE_MEMBER( epson_lx810l_t::co0_w ) +{ + /* TODO Draw the dots on the paper using this information. */ + + /* Printhead is being fired on !state. */ + if (!state) { + int pos = m_cr_pos_abs; + + /* HACK to get fire positions for motor in movement. The firmware + * issues two half-steps one immediately after the other. A timer + * fires the printhead twice. Supposedly, the first time the + * printhead is fired, it is midway between one step and the other. + * Ideally, the stepper motor interface should model the physics + * of the motors. For the moment, we adjust pos to get the + * intermediate position. + */ + + if (m_cr_pos_abs > m_last_fire + 1) + pos--; + else if (m_cr_pos_abs < m_last_fire - 1) + pos++; + + LX810LLOG("FIRE0 %d %d %04x\n", m_pf_pos_abs, pos, m_printhead); + + m_last_fire = pos; + } +} + +WRITE_LINE_MEMBER( epson_lx810l_t::co1_w ) +{ + m_speaker->level_w(state); +} + + +/*************************************************************************** + ADC +***************************************************************************/ + +READ8_MEMBER(epson_lx810l_t::an0_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x01); + return res - 1; /* DIPSW2.1 */ +} + +READ8_MEMBER(epson_lx810l_t::an1_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x02); + return res - 1; /* DIPSW2.2 */ +} + +READ8_MEMBER(epson_lx810l_t::an2_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x04); + return res - 1; /* DIPSW2.3 */ +} + +READ8_MEMBER(epson_lx810l_t::an3_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x08); + return res - 1; /* DIPSW2.4 */ +} + +READ8_MEMBER(epson_lx810l_t::an4_r) +{ + return 0xff; +} + +READ8_MEMBER(epson_lx810l_t::an5_r) +{ + return 0xCB; /* motor voltage, 0xcb = 24V */ +} + +READ8_MEMBER(epson_lx810l_t::an6_r) +{ + UINT8 res = !ioport("LOADEJECT")->read(); + return res - 1; +} + +READ8_MEMBER(epson_lx810l_t::an7_r) +{ + return 0xff; +} diff --git a/src/emu/bus/centronics/epson_lx810l.h b/src/emu/bus/centronics/epson_lx810l.h new file mode 100644 index 00000000000..29f80e803e4 --- /dev/null +++ b/src/emu/bus/centronics/epson_lx810l.h @@ -0,0 +1,117 @@ +/* + * Epson LX-810L dot matrix printer emulation + * + * Copyright: 2014 Ramiro Polla + * Felipe Sanches + * License: BSD-3-Clause + */ + +#pragma once + +#ifndef __EPSON_LX810L__ +#define __EPSON_LX810L__ + +#include "emu.h" +#include "ctronics.h" +#include "cpu/upd7810/upd7810.h" +#include "machine/e05a30.h" +#include "machine/eepromser.h" +#include "machine/steppers.h" +#include "sound/beep.h" +#include "sound/speaker.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> epson_lx810l_t + +class epson_lx810l_t : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + epson_lx810l_t(const machine_config &mconfig, const char *tag, + device_t *owner, UINT32 clock); + epson_lx810l_t(const machine_config &mconfig, device_type type, + const char *name, const char *tag, device_t *owner, + UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER(porta_r); + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_READ8_MEMBER(portb_r); + DECLARE_WRITE8_MEMBER(portb_w); + DECLARE_READ8_MEMBER(portc_r); + DECLARE_WRITE8_MEMBER(portc_w); + + /* Extended Timer Output */ + DECLARE_WRITE_LINE_MEMBER(co0_w); + DECLARE_WRITE_LINE_MEMBER(co1_w); + + /* ADC */ + DECLARE_READ8_MEMBER(an0_r); + DECLARE_READ8_MEMBER(an1_r); + DECLARE_READ8_MEMBER(an2_r); + DECLARE_READ8_MEMBER(an3_r); + DECLARE_READ8_MEMBER(an4_r); + DECLARE_READ8_MEMBER(an5_r); + DECLARE_READ8_MEMBER(an6_r); + DECLARE_READ8_MEMBER(an7_r); + + /* fake memory I/O to get past memory reset check */ + DECLARE_READ8_MEMBER(fakemem_r); + DECLARE_WRITE8_MEMBER(fakemem_w); + + /* GATE ARRAY */ + DECLARE_WRITE16_MEMBER(printhead); + DECLARE_WRITE8_MEMBER(pf_stepper); + DECLARE_WRITE8_MEMBER(cr_stepper); + DECLARE_WRITE_LINE_MEMBER(e05a30_ready); + + /* Panel buttons */ + DECLARE_INPUT_CHANGED_MEMBER(online_sw); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_maincpu; + required_device m_eeprom; + required_device m_speaker; + + int m_93c06_clk; + int m_93c06_cs; + UINT16 m_printhead; + int m_pf_pos_abs; + int m_cr_pos_abs; + int m_last_fire; /* HACK to get fire positions for motor in movement */ + UINT8 m_fakemem; +}; + +// ======================> epson_ap2000_t + +class epson_ap2000_t : public epson_lx810l_t +{ +public: + // construction/destruction + epson_ap2000_t(const machine_config &mconfig, const char *tag, + device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type EPSON_LX810L; +extern const device_type EPSON_AP2000; + +#endif diff --git a/src/emu/machine/e05a30.c b/src/emu/machine/e05a30.c new file mode 100644 index 00000000000..d080da38006 --- /dev/null +++ b/src/emu/machine/e05a30.c @@ -0,0 +1,163 @@ +/* + * E05A30 Gate Array (used in the Epson ActionPrinter 2000) + * + * Copyright: 2014 Ramiro Polla + * License: BSD-3-Clause + */ + +#include "emu.h" +#include "e05a30.h" + +//#define E05A30DEBUG +#ifdef E05A30DEBUG +#define LOG(...) fprintf(stderr, __VA_ARGS__) +#else +#define LOG(...) +#endif + + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +const device_type E05A30 = &device_creator; + +e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, E05A30, "E05A30", tag, owner, clock, "e05a30", __FILE__), + m_write_printhead(*this), + m_write_pf_stepper(*this), + m_write_cr_stepper(*this), + m_write_ready(*this), + m_printhead(0), + m_pf_stepper(0), + m_cr_stepper(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e05a30_device::device_start() +{ + /* resolve callbacks */ + m_write_printhead.resolve_safe(); + m_write_pf_stepper.resolve_safe(); + m_write_cr_stepper.resolve_safe(); + m_write_ready.resolve_safe(); + + /* register for state saving */ + save_item(NAME(m_printhead)); + save_item(NAME(m_pf_stepper)); + save_item(NAME(m_cr_stepper)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e05a30_device::device_reset() +{ + m_printhead = 0x00; + m_pf_stepper = 0x00; + m_cr_stepper = 0x00; + + m_write_ready(1); +} + + +/*************************************************************************** + PRINT HEAD +***************************************************************************/ + +/* The e05a30 controls the printhead through MMIOs 0xC005 and 0xC006. + * MMIO 0xC006 keeps the first 8 pins. + * MMIO 0xC005 keeps the 9th pin in the MSB. + */ + +void e05a30_device::update_printhead(int pos, UINT8 data) +{ + if (pos == 0) { + m_printhead &= 0x00ff; + m_printhead |= (UINT16) !!data << 8; + } else { + m_printhead &= 0xff00; + m_printhead |= data; + } + m_write_printhead(m_printhead); +} + +/*************************************************************************** + STEPPER MOTORS +***************************************************************************/ + +/* The e05a30 controls two stepper motors: + * - The Paper Feed stepper motor is controlled through MMIO 0xC007 + * - The Carriage Return stepper motor is controlled through MMIO 0xC008 + * The Carriage Return stepper motor is used throug the SLA7020M driver. It + * is therefore necessary to translate the input data from the SLA7020M + * format to a format describing the 4 phases of a stepper motor. + * For the PF motor, the output data is fed directly to the stepper motor. + */ + +void e05a30_device::update_pf_stepper(UINT8 data) +{ + m_pf_stepper = data & 0x0f; + m_write_pf_stepper(m_pf_stepper); +} + +static UINT8 cr_sla7020m(UINT8 data) +{ + bool ina = BIT(data, 0); + bool inb = BIT(data, 1); + bool tda = BIT(data, 2); + bool tdb = BIT(data, 3); + bool outa0 = ina && tda; + bool outa1 = !ina && tda; + bool outb0 = inb && tdb; + bool outb1 = !inb && tdb; + return (outb1<<3)|(outb0<<2)|(outa1<<1)|(outa0<<0); +} +void e05a30_device::update_cr_stepper(UINT8 data) +{ + m_cr_stepper = data & 0x0f; + m_write_cr_stepper(cr_sla7020m(m_cr_stepper)); +} + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +WRITE8_MEMBER( e05a30_device::write ) +{ + LOG("%s: e05a30_w([0xC0%02x]): %02x\n", space.machine().describe_context(), offset, data); + + switch (offset) { + /* printhead */ + case 0x05: update_printhead(0, data); break; + case 0x06: update_printhead(1, data); break; + /* paper feed stepper motor */ + case 0x07: update_pf_stepper(data); break; + /* carriage return stepper motor */ + case 0x08: update_cr_stepper(data); break; + } +} + +READ8_MEMBER( e05a30_device::read ) +{ + UINT8 result = 0; + + LOG("%s: e05a30_r([0xC0%02x]): ", space.machine().describe_context(), offset); + + switch (offset) { + /* paper feed stepper motor */ + case 0x07: result = m_pf_stepper; break; + /* carriage return stepper motor */ + case 0x08: result = m_cr_stepper; break; + } + + LOG("0x%02x\n", result); + + return result; +} diff --git a/src/emu/machine/e05a30.h b/src/emu/machine/e05a30.h new file mode 100644 index 00000000000..ab32eb21314 --- /dev/null +++ b/src/emu/machine/e05a30.h @@ -0,0 +1,71 @@ +/* + * E05A30 Gate Array (used in the Epson ActionPrinter 2000) + * + * Copyright: 2014 Ramiro Polla + * License: BSD-3-Clause + */ + +#ifndef __E05A30_H__ +#define __E05A30_H__ + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_E05A30_PRINTHEAD_CALLBACK(_write) \ + devcb = &e05a30_device::set_printhead_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_PF_STEPPER_CALLBACK(_write) \ + devcb = &e05a30_device::set_pf_stepper_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CR_STEPPER_CALLBACK(_write) \ + devcb = &e05a30_device::set_cr_stepper_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_READY_CALLBACK(_write) \ + devcb = &e05a30_device::set_ready_wr_callback(*device, DEVCB_##_write); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class e05a30_device : public device_t +{ +public: + e05a30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~e05a30_device() {} + + template static devcb_base &set_printhead_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_printhead.set_callback(object); } + template static devcb_base &set_pf_stepper_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pf_stepper.set_callback(object); } + template static devcb_base &set_cr_stepper_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_cr_stepper.set_callback(object); } + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ready.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + /* callbacks */ + devcb_write16 m_write_printhead; + devcb_write8 m_write_pf_stepper; + devcb_write8 m_write_cr_stepper; + devcb_write_line m_write_ready; + + void update_printhead(int pos, UINT8 data); + void update_pf_stepper(UINT8 data); + void update_cr_stepper(UINT8 data); + + /* port 0x05 and 0x06 (9-bit) */ + UINT16 m_printhead; + /* port 0x07 (4-bit) */ + UINT8 m_pf_stepper; + /* port 0x08 (4-bit) */ + UINT8 m_cr_stepper; +}; + +extern const device_type E05A30; + +#endif /* __E05A30_H__ */ diff --git a/src/emu/machine/machine.mak b/src/emu/machine/machine.mak index 9dbb6f8d854..bb71176b4b7 100644 --- a/src/emu/machine/machine.mak +++ b/src/emu/machine/machine.mak @@ -519,6 +519,15 @@ ifneq ($(filter E05A03,$(MACHINES)),) MACHINEOBJS += $(MACHINEOBJ)/e05a03.o endif +#------------------------------------------------- +# +#@src/emu/machine/e05a30.h,MACHINES += E05A30 +#------------------------------------------------- + +ifneq ($(filter E05A30,$(MACHINES)),) +MACHINEOBJS += $(MACHINEOBJ)/e05a30.o +endif + #------------------------------------------------- # #@src/emu/machine/eeprom.h,MACHINES += EEPROMDEV diff --git a/src/mame/mame.mak b/src/mame/mame.mak index cb5a4bb0cfc..84b500cd810 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -401,6 +401,7 @@ MACHINES += DS75160A MACHINES += DS75161A MACHINES += E0516 MACHINES += E05A03 +MACHINES += E05A30 MACHINES += EEPROMDEV MACHINES += ER2055 MACHINES += F3853 diff --git a/src/mess/includes/amstrad.h b/src/mess/includes/amstrad.h index 69bad9589d2..707eb8d157d 100644 --- a/src/mess/includes/amstrad.h +++ b/src/mess/includes/amstrad.h @@ -29,6 +29,7 @@ #include "bus/centronics/comxpl80.h" #include "bus/centronics/epson_ex800.h" #include "bus/centronics/epson_lx800.h" +#include "bus/centronics/epson_lx810l.h" #include "bus/centronics/printer.h" #include "bus/centronics/digiblst.h" #include "bus/generic/slot.h" diff --git a/src/mess/mess.mak b/src/mess/mess.mak index a53c511769c..ba413c73516 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -387,6 +387,7 @@ MACHINES += DS75160A MACHINES += DS75161A MACHINES += E0516 MACHINES += E05A03 +MACHINES += E05A30 MACHINES += EEPROMDEV MACHINES += ER2055 MACHINES += F3853 @@ -552,6 +553,7 @@ MACHINES += SMC92X4 MACHINES += HDC9234 MACHINES += TI99_HD MACHINES += STRATA +MACHINES += STEPPERS MACHINES += CORVUSHD MACHINES += WOZFDC MACHINES += DIABLO_HD diff --git a/src/targets/mess.lst b/src/targets/mess.lst index 51d297f2636..a1649c51b1f 100644 --- a/src/targets/mess.lst +++ b/src/targets/mess.lst @@ -285,6 +285,7 @@ /mess/drivers/ex800 /mess/drivers/hx20 /mess/drivers/lx800 +/mess/drivers/lx810l /mess/drivers/px4 /mess/drivers/px8 /mess/drivers/qx10 -- cgit v1.2.3