Merge pull request #50 from ramiropolla/lx810l

Added working Epson LX-810L and Epson ActionPrinter2000 printers
This commit is contained in:
Miodrag Milanović 2014-11-20 15:36:56 +01:00
commit 90a9ea5210
15 changed files with 965 additions and 91 deletions

View File

@ -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
#-------------------------------------------------

View File

@ -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"

View File

@ -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<epson_lx800_t>;
const device_type EPSON_LX810L = &device_creator<epson_lx810l_t>;
const device_type EPSON_AP2000 = &device_creator<epson_ap2000_t>;
//-------------------------------------------------
@ -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

View File

@ -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;

View File

@ -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<epson_lx810l_t>;
const device_type EPSON_AP2000 = &device_creator<epson_ap2000_t>;
//-------------------------------------------------
// 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;
}

View File

@ -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<cpu_device> m_maincpu;
required_device<eeprom_serial_93cxx_device> m_eeprom;
required_device<speaker_sound_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

163
src/emu/machine/e05a30.c Normal file
View File

@ -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::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;
}

71
src/emu/machine/e05a30.h Normal file
View File

@ -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<class _Object> static devcb_base &set_printhead_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_printhead.set_callback(object); }
template<class _Object> static devcb_base &set_pf_stepper_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_pf_stepper.set_callback(object); }
template<class _Object> static devcb_base &set_cr_stepper_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_cr_stepper.set_callback(object); }
template<class _Object> static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(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__ */

View File

@ -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
@ -1890,6 +1899,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

View File

@ -401,6 +401,7 @@ MACHINES += DS75160A
MACHINES += DS75161A
MACHINES += E0516
MACHINES += E05A03
MACHINES += E05A30
MACHINES += EEPROMDEV
MACHINES += ER2055
MACHINES += F3853
@ -564,6 +565,7 @@ MACHINES += FDC37C665GT
#MACHINES += SMC92X4
#MACHINES += TI99_HD
#MACHINES += STRATA
MACHINES += STEPPERS
#MACHINES += CORVUSHD
#MACHINES += WOZFDC
#MACHINES += DIABLO_HD
@ -954,7 +956,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 +1290,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 \

View File

@ -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"

View File

@ -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

View File

@ -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