mirror of
https://github.com/holub/mame
synced 2025-04-25 17:56:43 +03:00
Merge pull request #54 from ramiropolla/lx810l
This commit is contained in:
commit
96f797009a
@ -13,7 +13,10 @@
|
||||
* SLA7020M (step motor driver)
|
||||
* uPC494C (pulse width modulation control)
|
||||
*
|
||||
* Devices boot and enter main input loop, but input is not yet implemented.
|
||||
* Devices boot and enter main input loop. Data is received through the
|
||||
* centronics bus and printed as expected. The actual paper output is
|
||||
* still not implemented, though. Look at the output from the fire signal
|
||||
* (epson_lx810l_t::co0_w()) to see what's actually being printed.
|
||||
*
|
||||
* It is possible to run the printers' self test with this procedure:
|
||||
* - Turn on device;
|
||||
@ -99,7 +102,7 @@ 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(0xc000, 0xdfff) AM_MIRROR(0x1ff0) AM_DEVREADWRITE("e05a30", e05a30_device, read, write)
|
||||
AM_RANGE(0xe000, 0xfeff) AM_NOP /* not used */
|
||||
AM_RANGE(0xff00, 0xffff) AM_RAM /* internal CPU RAM */
|
||||
ADDRESS_MAP_END
|
||||
@ -140,16 +143,20 @@ static MACHINE_CONFIG_FRAGMENT( epson_lx810l )
|
||||
|
||||
/* 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_DEVICE_ADD("e05a30", 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))
|
||||
MCFG_E05A30_CENTRONICS_ACK_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_ack))
|
||||
MCFG_E05A30_CENTRONICS_BUSY_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_busy))
|
||||
MCFG_E05A30_CENTRONICS_PERROR_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_perror))
|
||||
MCFG_E05A30_CENTRONICS_FAULT_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_fault))
|
||||
MCFG_E05A30_CENTRONICS_SELECT_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_select))
|
||||
|
||||
/* 256-bit eeprom */
|
||||
MCFG_EEPROM_SERIAL_93C06_ADD("eeprom")
|
||||
@ -273,12 +280,15 @@ epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, const char *tag, d
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_eeprom(*this, "eeprom"),
|
||||
m_speaker(*this, "speaker"),
|
||||
m_e05a30(*this, "e05a30"),
|
||||
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)
|
||||
m_real_cr_pos(200),
|
||||
m_real_cr_steps(0),
|
||||
m_real_cr_dir(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -288,12 +298,15 @@ epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, device_type type,
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_eeprom(*this, "eeprom"),
|
||||
m_speaker(*this, "speaker"),
|
||||
m_e05a30(*this, "e05a30"),
|
||||
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)
|
||||
m_real_cr_pos(200),
|
||||
m_real_cr_steps(0),
|
||||
m_real_cr_dir(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -341,6 +354,29 @@ void epson_lx810l_t::device_reset()
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - device-specific timer
|
||||
//-------------------------------------------------
|
||||
|
||||
void epson_lx810l_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id) {
|
||||
case TIMER_CR:
|
||||
/* The firmware issues two half-steps in sequence, one immediately
|
||||
* after the other. At full speed, the motor does two half-steps at
|
||||
* each 833 microseconds. A timer fires the printhead twice, with
|
||||
* the same period as each half-step (417 microseconds), but with
|
||||
* a 356 microseconds delay relative to the motor steps.
|
||||
*/
|
||||
m_real_cr_pos += param;
|
||||
m_real_cr_steps--;
|
||||
if (m_real_cr_steps)
|
||||
timer_set(attotime::from_usec(400), TIMER_CR, m_real_cr_dir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FAKEMEM READ/WRITE
|
||||
***************************************************************************/
|
||||
@ -487,9 +523,23 @@ WRITE8_MEMBER( epson_lx810l_t::pf_stepper )
|
||||
|
||||
WRITE8_MEMBER( epson_lx810l_t::cr_stepper )
|
||||
{
|
||||
int m_cr_pos_abs_prev = m_cr_pos_abs;
|
||||
|
||||
stepper_update(1, data);
|
||||
m_cr_pos_abs = 200 - stepper_get_absolute_position(1);
|
||||
|
||||
if (m_cr_pos_abs > m_cr_pos_abs_prev) {
|
||||
/* going right */
|
||||
m_real_cr_dir = 1;
|
||||
} else {
|
||||
/* going left */
|
||||
m_real_cr_dir = -1;
|
||||
}
|
||||
|
||||
if (!m_real_cr_steps)
|
||||
timer_set(attotime::from_usec(400), TIMER_CR, m_real_cr_dir);
|
||||
m_real_cr_steps++;
|
||||
|
||||
LX810LLOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_cr_pos_abs);
|
||||
}
|
||||
|
||||
@ -509,25 +559,18 @@ WRITE_LINE_MEMBER( epson_lx810l_t::co0_w )
|
||||
|
||||
/* 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.
|
||||
/* The firmware expects a 300 microseconds delay between the fire
|
||||
* signal and the impact of the printhead on the paper. This can be
|
||||
* verified by the timings of the steps and fire signals for the
|
||||
* same positions with different directions (left to right or right
|
||||
* to left). We don't simulate this delay since it is smaller than
|
||||
* the time it takes the printhead to travel one pixel (which would
|
||||
* be 417 microseconds), so it makes no difference to us.
|
||||
* It is interesting to note that the vertical alignment between
|
||||
* lines which are being printed in different directions is
|
||||
* noticeably off in the 20+ years old printer used for testing =).
|
||||
*/
|
||||
|
||||
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;
|
||||
LX810LLOG("FIRE0 %d %d %04x\n", m_pf_pos_abs, m_real_cr_pos, m_printhead);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "machine/e05a30.h"
|
||||
#include "machine/eepromser.h"
|
||||
#include "machine/steppers.h"
|
||||
#include "sound/beep.h"
|
||||
#include "sound/speaker.h"
|
||||
|
||||
|
||||
@ -74,6 +73,22 @@ public:
|
||||
DECLARE_WRITE8_MEMBER(cr_stepper);
|
||||
DECLARE_WRITE_LINE_MEMBER(e05a30_ready);
|
||||
|
||||
/* Centronics stuff */
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_strobe ) { if (m_e05a30) m_e05a30->centronics_input_strobe(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (m_e05a30) m_e05a30->centronics_input_data0(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (m_e05a30) m_e05a30->centronics_input_data1(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (m_e05a30) m_e05a30->centronics_input_data2(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (m_e05a30) m_e05a30->centronics_input_data3(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (m_e05a30) m_e05a30->centronics_input_data4(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (m_e05a30) m_e05a30->centronics_input_data5(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (m_e05a30) m_e05a30->centronics_input_data6(state); }
|
||||
virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (m_e05a30) m_e05a30->centronics_input_data7(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_ack) { output_ack(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_busy) { output_busy(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_perror) { output_perror(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_fault) { output_fault(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_select) { output_select(state); }
|
||||
|
||||
/* Panel buttons */
|
||||
DECLARE_INPUT_CHANGED_MEMBER(online_sw);
|
||||
|
||||
@ -81,19 +96,27 @@ protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
private:
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<eeprom_serial_93cxx_device> m_eeprom;
|
||||
required_device<speaker_sound_device> m_speaker;
|
||||
required_device<e05a30_device> m_e05a30;
|
||||
|
||||
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 */
|
||||
int m_real_cr_pos;
|
||||
int m_real_cr_steps;
|
||||
int m_real_cr_dir; /* 1 is going right, -1 is going left */
|
||||
UINT8 m_fakemem;
|
||||
|
||||
enum {
|
||||
TIMER_CR,
|
||||
};
|
||||
};
|
||||
|
||||
// ======================> epson_ap2000_t
|
||||
|
@ -28,6 +28,11 @@ e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, dev
|
||||
m_write_pf_stepper(*this),
|
||||
m_write_cr_stepper(*this),
|
||||
m_write_ready(*this),
|
||||
m_write_centronics_ack(*this),
|
||||
m_write_centronics_busy(*this),
|
||||
m_write_centronics_perror(*this),
|
||||
m_write_centronics_fault(*this),
|
||||
m_write_centronics_select(*this),
|
||||
m_printhead(0),
|
||||
m_pf_stepper(0),
|
||||
m_cr_stepper(0)
|
||||
@ -45,6 +50,11 @@ void e05a30_device::device_start()
|
||||
m_write_pf_stepper.resolve_safe();
|
||||
m_write_cr_stepper.resolve_safe();
|
||||
m_write_ready.resolve_safe();
|
||||
m_write_centronics_ack.resolve_safe();
|
||||
m_write_centronics_busy.resolve_safe();
|
||||
m_write_centronics_perror.resolve_safe();
|
||||
m_write_centronics_fault.resolve_safe();
|
||||
m_write_centronics_select.resolve_safe();
|
||||
|
||||
/* register for state saving */
|
||||
save_item(NAME(m_printhead));
|
||||
@ -62,6 +72,15 @@ void e05a30_device::device_reset()
|
||||
m_pf_stepper = 0x00;
|
||||
m_cr_stepper = 0x00;
|
||||
|
||||
/* centronics init */
|
||||
m_centronics_nack = FALSE;
|
||||
m_centronics_busy = FALSE;
|
||||
m_write_centronics_ack (!m_centronics_nack);
|
||||
m_write_centronics_busy ( m_centronics_busy);
|
||||
m_write_centronics_perror(FALSE);
|
||||
m_write_centronics_fault (TRUE);
|
||||
m_write_centronics_select(TRUE);
|
||||
|
||||
m_write_ready(1);
|
||||
}
|
||||
|
||||
@ -125,6 +144,25 @@ void e05a30_device::update_cr_stepper(UINT8 data)
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Centronics
|
||||
***************************************************************************/
|
||||
|
||||
WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe )
|
||||
{
|
||||
if (m_centronics_strobe == TRUE && state == FALSE && !m_centronics_busy) {
|
||||
|
||||
m_centronics_data_latch = m_centronics_data;
|
||||
|
||||
m_centronics_data_latched = TRUE;
|
||||
m_centronics_busy = TRUE;
|
||||
m_write_centronics_busy(m_centronics_busy);
|
||||
}
|
||||
|
||||
m_centronics_strobe = state;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
@ -134,6 +172,19 @@ WRITE8_MEMBER( e05a30_device::write )
|
||||
LOG("%s: e05a30_w([0xC0%02x]): %02x\n", space.machine().describe_context(), offset, data);
|
||||
|
||||
switch (offset) {
|
||||
case 0x04:
|
||||
m_centronics_nack = BIT(data,5);
|
||||
m_centronics_busy = BIT(data,0);
|
||||
/* The ActionPrinter 2000 firmware might overwrite the busy signal at
|
||||
* address 20AB if the host depends only on the busy signal and
|
||||
* doesn't wait for the ack pulse. To avoid skipping input data, we
|
||||
* assume the busy signal cannot be reset while the data hasn't been
|
||||
* read. */
|
||||
if (m_centronics_data_latched)
|
||||
m_centronics_busy = TRUE;
|
||||
m_write_centronics_ack (!m_centronics_nack);
|
||||
m_write_centronics_busy( m_centronics_busy);
|
||||
break;
|
||||
/* printhead */
|
||||
case 0x05: update_printhead(0, data); break;
|
||||
case 0x06: update_printhead(1, data); break;
|
||||
@ -151,6 +202,17 @@ READ8_MEMBER( e05a30_device::read )
|
||||
LOG("%s: e05a30_r([0xC0%02x]): ", space.machine().describe_context(), offset);
|
||||
|
||||
switch (offset) {
|
||||
case 0x02:
|
||||
result = m_centronics_data_latched << 7;
|
||||
break;
|
||||
case 0x03:
|
||||
result = m_centronics_data_latch;
|
||||
m_centronics_data_latched = FALSE;
|
||||
break;
|
||||
case 0x04:
|
||||
result |= m_centronics_busy << 0;
|
||||
result |= m_centronics_nack << 5;
|
||||
break;
|
||||
/* paper feed stepper motor */
|
||||
case 0x07: result = m_pf_stepper; break;
|
||||
/* carriage return stepper motor */
|
||||
|
@ -24,6 +24,21 @@
|
||||
#define MCFG_E05A30_READY_CALLBACK(_write) \
|
||||
devcb = &e05a30_device::set_ready_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_E05A30_CENTRONICS_ACK_CALLBACK(_write) \
|
||||
devcb = &e05a30_device::set_centronics_ack_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_E05A30_CENTRONICS_BUSY_CALLBACK(_write) \
|
||||
devcb = &e05a30_device::set_centronics_busy_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_E05A30_CENTRONICS_PERROR_CALLBACK(_write) \
|
||||
devcb = &e05a30_device::set_centronics_perror_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_E05A30_CENTRONICS_FAULT_CALLBACK(_write) \
|
||||
devcb = &e05a30_device::set_centronics_fault_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_E05A30_CENTRONICS_SELECT_CALLBACK(_write) \
|
||||
devcb = &e05a30_device::set_centronics_select_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
@ -38,10 +53,26 @@ public:
|
||||
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); }
|
||||
template<class _Object> static devcb_base &set_centronics_ack_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_centronics_ack.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_centronics_busy_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_centronics_busy.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_centronics_perror_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_centronics_perror.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_centronics_fault_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_centronics_fault.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_centronics_select_wr_callback(device_t &device, _Object object) { return downcast<e05a30_device &>(device).m_write_centronics_select.set_callback(object); }
|
||||
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
|
||||
/* Centronics stuff */
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_strobe );
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data0 ) { if (state) m_centronics_data |= 0x01; else m_centronics_data &= ~0x01; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data1 ) { if (state) m_centronics_data |= 0x02; else m_centronics_data &= ~0x02; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data2 ) { if (state) m_centronics_data |= 0x04; else m_centronics_data &= ~0x04; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data3 ) { if (state) m_centronics_data |= 0x08; else m_centronics_data &= ~0x08; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data4 ) { if (state) m_centronics_data |= 0x10; else m_centronics_data &= ~0x10; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data5 ) { if (state) m_centronics_data |= 0x20; else m_centronics_data &= ~0x20; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data6 ) { if (state) m_centronics_data |= 0x40; else m_centronics_data &= ~0x40; }
|
||||
DECLARE_WRITE_LINE_MEMBER( centronics_input_data7 ) { if (state) m_centronics_data |= 0x80; else m_centronics_data &= ~0x80; }
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
@ -53,6 +84,11 @@ private:
|
||||
devcb_write8 m_write_pf_stepper;
|
||||
devcb_write8 m_write_cr_stepper;
|
||||
devcb_write_line m_write_ready;
|
||||
devcb_write_line m_write_centronics_ack;
|
||||
devcb_write_line m_write_centronics_busy;
|
||||
devcb_write_line m_write_centronics_perror;
|
||||
devcb_write_line m_write_centronics_fault;
|
||||
devcb_write_line m_write_centronics_select;
|
||||
|
||||
void update_printhead(int pos, UINT8 data);
|
||||
void update_pf_stepper(UINT8 data);
|
||||
@ -64,6 +100,14 @@ private:
|
||||
UINT8 m_pf_stepper;
|
||||
/* port 0x08 (4-bit) */
|
||||
UINT8 m_cr_stepper;
|
||||
|
||||
/* Centronics stuff */
|
||||
UINT8 m_centronics_data;
|
||||
int m_centronics_busy;
|
||||
int m_centronics_nack;
|
||||
UINT8 m_centronics_strobe;
|
||||
UINT8 m_centronics_data_latch;
|
||||
UINT8 m_centronics_data_latched;
|
||||
};
|
||||
|
||||
extern const device_type E05A30;
|
||||
|
Loading…
Reference in New Issue
Block a user