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.
This commit is contained in:
Ramiro Polla 2014-11-07 05:26:06 +01:00
parent 755b2d6564
commit 32bfdf3752
13 changed files with 955 additions and 89 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

View File

@ -401,6 +401,7 @@ MACHINES += DS75160A
MACHINES += DS75161A
MACHINES += E0516
MACHINES += E05A03
MACHINES += E05A30
MACHINES += EEPROMDEV
MACHINES += ER2055
MACHINES += F3853

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