1 // license:BSD-3-Clause
2 // copyright-holders:Ramiro Polla, Felipe Sanches
3 /*
4 * Epson LX-810L dot matrix printer emulation
5 *
6 * IC list:
7 * uPD7810HG (cpu)
8 * E05A30 (gate array)
9 * 2064C (8k RAM)
10 * ER59256 (EEP-ROM - serial nvram)
11 * SLA7020M (step motor driver)
12 * uPC494C (pulse width modulation control)
13 *
14 * Devices boot and enter main input loop. Data is received through the
15 * centronics bus and printed as expected in a separate screen.
16 *
17 * It is possible to run the printers' self test with this procedure:
18 * - Turn on device;
19 * - Toggle Line Feed button (press 'L');
20 * - Reset device;
21 * - Toggle Line Feed button again;
22 * - Press Online button (press 'O');
23 *
24 * The printer's carriage will seek home and it will start printing
25 * some test data. The Online LED will blink at each line.
26 */
27
28 #include "emu.h"
29 #include "epson_lx810l.h"
30 #include "speaker.h"
31
32 //#define VERBOSE 1
33 #include "logmacro.h"
34
35 //extern const char layout_lx800[]; /* use layout from lx800 */
36
37
38 /* The printer starts printing at x offset 44 and stops printing at x
39 * offset 1009, giving a total of 965 printable pixels. Supposedly, the
40 * border at the far right would be at x offset 1053. I've chosen the
41 * width for the paper as 1024, since it's a nicer number than 1053, so
42 * an offset must be used to centralize the pixels.
43 */
44 #define CR_OFFSET (-14)
45 #define PAPER_WIDTH 1024
46 #define PAPER_HEIGHT 576
47
48
49 //**************************************************************************
50 // DEVICE DEFINITIONS
51 //**************************************************************************
52
53 DEFINE_DEVICE_TYPE(EPSON_LX810L, epson_lx810l_device, "lx810l", "Espon LX-810L")
54 DEFINE_DEVICE_TYPE(EPSON_AP2000, epson_ap2000_device, "ap2000", "Epson ActionPrinter 2000")
55
56
57 //-------------------------------------------------
58 // ROM( lx810l )
59 //-------------------------------------------------
60
ROM_START(lx810l)61 ROM_START( lx810l )
62 ROM_REGION(0x8000, "maincpu", 0)
63 ROM_LOAD("lx810l.ic3c", 0x0000, 0x8000, CRC(a66454e1) SHA1(8e6f2f98abcbd8af6e34b9ba746edf0d18aef843) )
64 ROM_REGION16_BE(0x20, "eeprom", 0)
65 ROM_LOAD( "at93c06", 0x00, 0x20, NO_DUMP )
66 ROM_END
67
68
69 //-------------------------------------------------
70 // ROM( ap2000 )
71 //-------------------------------------------------
72
73 ROM_START( ap2000 )
74 ROM_REGION(0x8000, "maincpu", 0)
75 ROM_LOAD("ap2k.ic3c", 0x0000, 0x8000, CRC(ee7294b7) SHA1(219ffa6ff661ce95d5772c9fc1967093718f04e9) )
76 ROM_REGION16_BE(0x20, "eeprom", 0)
77 ROM_LOAD( "at93c06", 0x00, 0x20, NO_DUMP )
78 ROM_END
79
80
81 //-------------------------------------------------
82 // rom_region - device-specific ROM region
83 //-------------------------------------------------
84
85 const tiny_rom_entry *epson_lx810l_device::device_rom_region() const
86 {
87 return ROM_NAME( lx810l );
88 }
89
90
91 //-------------------------------------------------
92 // rom_region - device-specific ROM region
93 //-------------------------------------------------
94
device_rom_region() const95 const tiny_rom_entry *epson_ap2000_device::device_rom_region() const
96 {
97 return ROM_NAME( ap2000 );
98 }
99
100
101 //-------------------------------------------------
102 // ADDRESS_MAP( lx810l_mem )
103 //-------------------------------------------------
104
lx810l_mem(address_map & map)105 void epson_lx810l_device::lx810l_mem(address_map &map)
106 {
107 map(0x0000, 0x7fff).rom(); /* 32k firmware */
108 map(0x8000, 0x9fff).ram(); /* 8k external RAM */
109 map(0xa000, 0xbfff).rw(FUNC(epson_lx810l_device::fakemem_r), FUNC(epson_lx810l_device::fakemem_w)); /* fake memory, write one, set all */
110 map(0xc000, 0xc00f).mirror(0x1ff0).rw("e05a30", FUNC(e05a30_device::read), FUNC(e05a30_device::write));
111 map(0xe000, 0xfeff).noprw(); /* not used */
112 }
113
114
115 //-------------------------------------------------
116 // device_add_mconfig - add device configuration
117 //-------------------------------------------------
118
device_add_mconfig(machine_config & config)119 void epson_lx810l_device::device_add_mconfig(machine_config &config)
120 {
121 /* basic machine hardware */
122 upd7810_device &upd(UPD7810(config, m_maincpu, 14.7456_MHz_XTAL));
123 upd.set_addrmap(AS_PROGRAM, &epson_lx810l_device::lx810l_mem);
124 upd.pa_in_cb().set(FUNC(epson_lx810l_device::porta_r));
125 upd.pa_out_cb().set(FUNC(epson_lx810l_device::porta_w));
126 upd.pb_in_cb().set(FUNC(epson_lx810l_device::portb_r));
127 upd.pb_out_cb().set(FUNC(epson_lx810l_device::portb_w));
128 upd.pc_in_cb().set(FUNC(epson_lx810l_device::portc_r));
129 upd.pc_out_cb().set(FUNC(epson_lx810l_device::portc_w));
130 upd.an0_func().set(FUNC(epson_lx810l_device::an0_r));
131 upd.an1_func().set(FUNC(epson_lx810l_device::an1_r));
132 upd.an2_func().set(FUNC(epson_lx810l_device::an2_r));
133 upd.an3_func().set(FUNC(epson_lx810l_device::an3_r));
134 upd.an4_func().set(FUNC(epson_lx810l_device::an4_r));
135 upd.an5_func().set(FUNC(epson_lx810l_device::an5_r));
136 upd.an6_func().set(FUNC(epson_lx810l_device::an6_r));
137 upd.an7_func().set(FUNC(epson_lx810l_device::an7_r));
138 upd.co0_func().set(FUNC(epson_lx810l_device::co0_w));
139 upd.co1_func().set("dac", FUNC(dac_bit_interface::write));
140
141 // config.set_default_layout(layout_lx800);
142
143 /* video hardware (simulates paper) */
144 screen_device &screen(SCREEN(config, m_screen, SCREEN_TYPE_RASTER));
145 screen.set_refresh_hz(60);
146 screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
147 screen.set_size(PAPER_WIDTH, PAPER_HEIGHT);
148 screen.set_visarea(0, PAPER_WIDTH-1, 0, PAPER_HEIGHT-1);
149 screen.set_screen_update(FUNC(epson_lx810l_device::screen_update_lx810l));
150
151 /* audio hardware */
152 SPEAKER(config, "speaker").front_center();
153 DAC_1BIT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.25);
154
155 /* gate array */
156 e05a30_device &e05a30(E05A30(config, m_e05a30, 0));
157 e05a30.printhead().set(FUNC(epson_lx810l_device::printhead));
158 e05a30.pf_stepper().set(FUNC(epson_lx810l_device::pf_stepper));
159 e05a30.cr_stepper().set(FUNC(epson_lx810l_device::cr_stepper));
160 e05a30.ready().set(FUNC(epson_lx810l_device::e05a30_ready));
161 e05a30.centronics_ack().set(FUNC(epson_lx810l_device::e05a30_centronics_ack));
162 e05a30.centronics_busy().set(FUNC(epson_lx810l_device::e05a30_centronics_busy));
163 e05a30.centronics_perror().set(FUNC(epson_lx810l_device::e05a30_centronics_perror));
164 e05a30.centronics_fault().set(FUNC(epson_lx810l_device::e05a30_centronics_fault));
165 e05a30.centronics_select().set(FUNC(epson_lx810l_device::e05a30_centronics_select));
166
167 /* 256-bit eeprom */
168 EEPROM_93C06_16BIT(config, "eeprom");
169
170 STEPPER(config, m_pf_stepper, (uint8_t)4);
171 STEPPER(config, m_cr_stepper, (uint8_t)2);
172 }
173
174
175 /***************************************************************************
176 INPUT PORTS
177 ***************************************************************************/
178
179 static INPUT_PORTS_START( epson_lx810l )
180
181 /* Buttons on printer */
182 PORT_START("ONLINE")
PORT_CODE(KEYCODE_0_PAD)183 PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("On Line") PORT_CODE(KEYCODE_0_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, epson_lx810l_device, online_sw, 0)
184 PORT_START("FORMFEED")
185 PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Form Feed") PORT_CODE(KEYCODE_7_PAD)
186 PORT_START("LINEFEED")
187 PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_9_PAD)
188 PORT_START("LOADEJECT")
189 PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Load/Eject") PORT_CODE(KEYCODE_1_PAD)
190 PORT_START("PAPEREND")
191 PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Paper End Sensor") PORT_CODE(KEYCODE_6_PAD)
192
193 /* DIPSW1 */
194 PORT_START("DIPSW1")
195
196 PORT_DIPNAME(0x01, 0x01, "Character spacing")
197 PORT_DIPLOCATION("DIP:1")
198 PORT_DIPSETTING(0x01, "12 cpi") /* default */
199 PORT_DIPSETTING(0x00, "10 cpi")
200
201 PORT_DIPNAME(0x02, 0x00, "Shape of zero")
202 PORT_DIPLOCATION("DIP:2")
203 PORT_DIPSETTING(0x02, "Slashed")
204 PORT_DIPSETTING(0x00, "Not slashed") /* default */
205
206 PORT_DIPNAME(0x0c, 0x08, "Page length")
207 PORT_DIPLOCATION("DIP:3,4")
208 PORT_DIPSETTING(0x00, "11 inches")
209 PORT_DIPSETTING(0x04, "12 inches")
210 PORT_DIPSETTING(0x08, "8.5 inches") /* default */
211 PORT_DIPSETTING(0x0c, "11.7 inches")
212
213 PORT_DIPNAME(0x10, 0x10, "Character table")
214 PORT_DIPLOCATION("DIP:5")
215 PORT_DIPSETTING(0x10, "Graphics") /* default */
216 PORT_DIPSETTING(0x00, "Italics")
217
218 PORT_DIPNAME(0xe0, 0xe0, "International characters and PC selection")
219 PORT_DIPLOCATION("DIP:6,7,8")
220 PORT_DIPSETTING(0xe0, "United States") /* default */
221 PORT_DIPSETTING(0x60, "France")
222 PORT_DIPSETTING(0xa0, "Germany")
223 PORT_DIPSETTING(0x20, "United Kingdom")
224 PORT_DIPSETTING(0xc0, "Denmark")
225 PORT_DIPSETTING(0x40, "Sweden")
226 PORT_DIPSETTING(0x80, "Italy")
227 PORT_DIPSETTING(0x00, "Spain")
228
229 /* DIPSW2 */
230 PORT_START("DIPSW2")
231
232 PORT_DIPNAME(0x01, 0x01, "Short tear-off")
233 PORT_DIPLOCATION("DIP:1")
234 PORT_DIPSETTING(0x01, "Invalid") /* default */
235 PORT_DIPSETTING(0x00, "Valid")
236
237 PORT_DIPNAME(0x02, 0x00, "Cut-sheet feeder mode")
238 PORT_DIPLOCATION("DIP:2")
239 PORT_DIPSETTING(0x02, "ON")
240 PORT_DIPSETTING(0x00, "OFF") /* default */
241
242 PORT_DIPNAME(0x04, 0x00, "Skip-over-perforation")
243 PORT_DIPLOCATION("DIP:3")
244 PORT_DIPSETTING(0x04, "ON")
245 PORT_DIPSETTING(0x00, "OFF") /* default */
246
247 PORT_DIPNAME(0x08, 0x00, "Auto line feed")
248 PORT_DIPLOCATION("DIP:4")
249 PORT_DIPSETTING(0x08, "ON")
250 PORT_DIPSETTING(0x00, "OFF") /* default */
251
252 INPUT_PORTS_END
253
254
255 //-------------------------------------------------
256 // input_ports - device-specific input ports
257 //-------------------------------------------------
258
259 ioport_constructor epson_lx810l_device::device_input_ports() const
260 {
261 return INPUT_PORTS_NAME( epson_lx810l );
262 }
263
INPUT_CHANGED_MEMBER(epson_lx810l_device::online_sw)264 INPUT_CHANGED_MEMBER(epson_lx810l_device::online_sw)
265 {
266 m_maincpu->set_input_line(UPD7810_INTF2, newval ? CLEAR_LINE : ASSERT_LINE);
267 }
268
269
270 //**************************************************************************
271 // LIVE DEVICE
272 //**************************************************************************
273
274 //-------------------------------------------------
275 // epson_lx810l_device - constructor
276 //-------------------------------------------------
277
epson_lx810l_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)278 epson_lx810l_device::epson_lx810l_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
279 epson_lx810l_device(mconfig, EPSON_LX810L, tag, owner, clock)
280 {
281 }
282
epson_lx810l_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)283 epson_lx810l_device::epson_lx810l_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
284 device_t(mconfig, type, tag, owner, clock),
285 device_centronics_peripheral_interface(mconfig, *this),
286 m_maincpu(*this, "maincpu"),
287 m_pf_stepper(*this, "pf_stepper"),
288 m_cr_stepper(*this, "cr_stepper"),
289 m_eeprom(*this, "eeprom"),
290 m_e05a30(*this, "e05a30"),
291 m_screen(*this, "screen"),
292 m_online_led(*this, "online_led"),
293 m_93c06_clk(0),
294 m_93c06_cs(0),
295 m_printhead(0),
296 m_pf_pos_abs(1),
297 m_cr_pos_abs(1),
298 m_real_cr_pos(1),
299 m_real_cr_steps(0),
300 m_real_cr_dir(0), m_fakemem(0)
301 {
302 }
303
epson_ap2000_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)304 epson_ap2000_device::epson_ap2000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
305 : epson_lx810l_device(mconfig, EPSON_AP2000, tag, owner, clock)
306 { }
307
308
309 //-------------------------------------------------
310 // device_start - device-specific startup
311 //-------------------------------------------------
312
device_start()313 void epson_lx810l_device::device_start()
314 {
315 m_online_led.resolve();
316
317 m_cr_timer = timer_alloc(TIMER_CR);
318
319 m_screen->register_screen_bitmap(m_bitmap);
320 m_bitmap.fill(0xffffff); /* Start with a clean white piece of paper */
321 }
322
323
324 //-------------------------------------------------
325 // device_reset - device-specific reset
326 //-------------------------------------------------
327
device_reset()328 void epson_lx810l_device::device_reset()
329 {
330 }
331
332
333 //-------------------------------------------------
334 // device_timer - device-specific timer
335 //-------------------------------------------------
336
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)337 void epson_lx810l_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
338 {
339 switch (id) {
340 case TIMER_CR:
341 /* The firmware issues two half-steps in sequence, one immediately
342 * after the other. At full speed, the motor does two half-steps at
343 * each 833 microseconds. A timer fires the printhead twice, with
344 * the same period as each half-step (417 microseconds), but with
345 * a 356 microseconds delay relative to the motor steps.
346 */
347 m_real_cr_pos += param;
348 m_real_cr_steps--;
349 if (m_real_cr_steps)
350 m_cr_timer->adjust(attotime::from_usec(400), m_real_cr_dir);
351 break;
352 }
353 }
354
355
356 /***************************************************************************
357 FAKEMEM READ/WRITE
358 ***************************************************************************/
359
fakemem_r()360 uint8_t epson_lx810l_device::fakemem_r()
361 {
362 return m_fakemem;
363 }
364
fakemem_w(uint8_t data)365 void epson_lx810l_device::fakemem_w(uint8_t data)
366 {
367 m_fakemem = data;
368 }
369
370
371 /***************************************************************************
372 I/O PORTS
373 ***************************************************************************/
374
375 /*
376 * PA0 R CN7 sensor (Home Position, HP, active low)
377 * PA1 R CN6 sensor (Paper-End, PE, active low)
378 * PA2 R CN4 sensor (Release, low = tractor)
379 * PA3 W Stepper motor voltage reference (these 3 pins make up one voltage)
380 * PA4 W Stepper motor voltage reference (these 3 pins make up one voltage)
381 * PA5 W Stepper motor voltage reference (these 3 pins make up one voltage)
382 * PA6 R Line Feed SWITCH
383 * PA7 R Form Feed SWITCH
384 */
porta_r(offs_t offset)385 uint8_t epson_lx810l_device::porta_r(offs_t offset)
386 {
387 uint8_t result = 0;
388 uint8_t hp_sensor = m_cr_pos_abs <= 0 ? 0 : 1;
389 //uint8_t pe_sensor = m_pf_pos_abs <= 0 ? 1 : 0;
390
391 result |= hp_sensor; /* home position */
392 //result |= pe_sensor << 1; /* paper end */
393 result |= ioport("PAPEREND")->read() << 1; // simulate a paper out error
394 result |= ioport("LINEFEED")->read() << 6;
395 result |= ioport("FORMFEED")->read() << 7;
396
397 LOG("%s: lx810l_PA_r(%02x): result %02x\n", machine().describe_context(), offset, result);
398
399 return result;
400 }
401
porta_w(offs_t offset,uint8_t data)402 void epson_lx810l_device::porta_w(offs_t offset, uint8_t data)
403 {
404 LOG("%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));
405 }
406
407 /*
408 * PB0 R DIP1.0 & 93C06.DO
409 * PB1 RW DIP1.1 & 93C06.DI
410 * PB2 R DIP1.2
411 * PB3 R DIP1.3
412 * PB4 R DIP1.4
413 * PB5 R DIP1.5
414 * PB6 R DIP1.6
415 * PB7 R DIP1.7
416 */
portb_r(offs_t offset)417 uint8_t epson_lx810l_device::portb_r(offs_t offset)
418 {
419 uint8_t result = ~ioport("DIPSW1")->read();
420
421 /* if 93C06 is selected */
422 if (m_93c06_cs) {
423 uint8_t do_r = m_eeprom->do_read();
424 result &= 0xfe;
425 result |= do_r;
426 }
427
428 LOG("%s: lx810l_PB_r(%02x): result %02x\n", machine().describe_context(), offset, result);
429
430 return result;
431 }
432
portb_w(offs_t offset,uint8_t data)433 void epson_lx810l_device::portb_w(offs_t offset, uint8_t data)
434 {
435 uint8_t data_in = BIT(data, 1);
436
437 /* if 93C06 is selected */
438 if (m_93c06_cs)
439 m_eeprom->di_write(data_in);
440
441 LOG("%s: lx810l_PB_w(%02x): %02x: 93c06 data %d\n", machine().describe_context(), offset, data, data_in);
442 }
443
444 /*
445 * PC0 W TXD serial i/o txd, also TAMA.25
446 * PC1 R RXD serial i/o rxd, also E05A30.28
447 * PC2 W ONLINE LP online led
448 * PC3 R ONLINE SW online switch
449 * PC4 W 93C06.SK
450 * PC5 W 93C06.CS
451 * PC6 W FIRE drive pulse width signal, also E05A30.57
452 * PC7 W BUZZER buzzer signal
453 */
portc_r(offs_t offset)454 uint8_t epson_lx810l_device::portc_r(offs_t offset)
455 {
456 uint8_t result = 0;
457
458 /* result |= ioport("serial")->read() << 1; */
459 result |= !ioport("ONLINE")->read() << 3;
460 result |= m_93c06_clk << 4;
461 result |= m_93c06_cs << 5;
462
463 LOG("%s: lx810l_PC_r(%02x): %02x\n", machine().describe_context(), offset, result);
464
465 return result;
466 }
467
portc_w(offs_t offset,uint8_t data)468 void epson_lx810l_device::portc_w(offs_t offset, uint8_t data)
469 {
470 /* ioport("serial")->write(BIT(data, 0)); */
471
472 m_93c06_clk = BIT(data, 4);
473 m_93c06_cs = !BIT(data, 5);
474
475 LOG("%s: PC_w(%02x): %02x 93c06 clk: %d cs: %d\n", machine().describe_context(), offset, data, m_93c06_clk, m_93c06_cs);
476
477 m_eeprom->clk_write(m_93c06_clk ? ASSERT_LINE : CLEAR_LINE);
478 m_eeprom->cs_write (m_93c06_cs ? ASSERT_LINE : CLEAR_LINE);
479
480 m_online_led = !BIT(data, 2);
481 }
482
483
484 /***************************************************************************
485 GATE ARRAY
486 ***************************************************************************/
487
printhead(uint16_t data)488 void epson_lx810l_device::printhead(uint16_t data)
489 {
490 m_printhead = data;
491 }
492
pf_stepper(uint8_t data)493 void epson_lx810l_device::pf_stepper(uint8_t data)
494 {
495 int changed = m_pf_stepper->update(data);
496 m_pf_pos_abs = -m_pf_stepper->get_absolute_position();
497
498 /* clear last line of paper */
499 if (changed > 0) {
500 void *line = m_bitmap.raw_pixptr(bitmap_line(9), 0);
501 memset(line, 0xff, m_bitmap.width() * 4);
502 }
503
504 LOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_pf_pos_abs);
505 }
506
cr_stepper(uint8_t data)507 void epson_lx810l_device::cr_stepper(uint8_t data)
508 {
509 int m_cr_pos_abs_prev = m_cr_pos_abs;
510
511 m_cr_stepper->update(data);
512 m_cr_pos_abs = -m_cr_stepper->get_absolute_position();
513
514 if (m_cr_pos_abs > m_cr_pos_abs_prev) {
515 /* going right */
516 m_real_cr_dir = 1;
517 } else {
518 /* going left */
519 m_real_cr_dir = -1;
520 }
521
522 if (!m_real_cr_steps)
523 m_cr_timer->adjust(attotime::from_usec(400), m_real_cr_dir);
524 m_real_cr_steps++;
525
526 LOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_cr_pos_abs);
527 }
528
WRITE_LINE_MEMBER(epson_lx810l_device::e05a30_ready)529 WRITE_LINE_MEMBER( epson_lx810l_device::e05a30_ready )
530 {
531 // must be longer than attotime::zero - 0.09 is minimum to initialize properly
532 m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::from_double(0.09));
533 }
534
535
536 /***************************************************************************
537 Video hardware (simulates paper)
538 ***************************************************************************/
539
screen_update_lx810l(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)540 uint32_t epson_lx810l_device::screen_update_lx810l(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
541 {
542 int scrolly = -bitmap_line(9);
543 copyscrollbitmap(bitmap, m_bitmap, 0, nullptr, 1, &scrolly, cliprect);
544
545 /* draw "printhead" */
546 int bordersize = 1;
547 bitmap.plot_box(m_real_cr_pos + CR_OFFSET - 10 - bordersize, PAPER_HEIGHT - 36 - bordersize, 20 + bordersize * 2, 36 + bordersize * 2, 0x000000 );
548 bitmap.plot_box(m_real_cr_pos + CR_OFFSET - 10, PAPER_HEIGHT - 36, 20, 36, m_e05a30->ready_led() ? 0x55ff55 : 0x337733 );
549
550 return 0;
551 }
552
553
554 /***************************************************************************
555 Extended Timer Output
556 ***************************************************************************/
557
WRITE_LINE_MEMBER(epson_lx810l_device::co0_w)558 WRITE_LINE_MEMBER( epson_lx810l_device::co0_w )
559 {
560 /* Printhead is being fired on !state. */
561 if (!state) {
562 /* The firmware expects a 300 microseconds delay between the fire
563 * signal and the impact of the printhead on the paper. This can be
564 * verified by the timings of the steps and fire signals for the
565 * same positions with different directions (left to right or right
566 * to left). We don't simulate this delay since it is smaller than
567 * the time it takes the printhead to travel one pixel (which would
568 * be 417 microseconds), so it makes no difference to us.
569 * It is interesting to note that the vertical alignment between
570 * lines which are being printed in different directions is
571 * noticeably off in the 20+ years old printer used for testing =).
572 */
573 if (m_real_cr_pos < m_bitmap.width()) {
574 for (int i = 0; i < 9; i++) {
575 unsigned int const y = bitmap_line(i);
576 if ((m_printhead & (1<<(8-i))) != 0)
577 m_bitmap.pix(y, m_real_cr_pos + CR_OFFSET) = 0x000000;
578 }
579 }
580 }
581 }
582
583
584 /***************************************************************************
585 ADC
586 ***************************************************************************/
587
an0_r()588 uint8_t epson_lx810l_device::an0_r()
589 {
590 uint8_t res = !!(ioport("DIPSW2")->read() & 0x01);
591 return res - 1; /* DIPSW2.1 */
592 }
593
an1_r()594 uint8_t epson_lx810l_device::an1_r()
595 {
596 uint8_t res = !!(ioport("DIPSW2")->read() & 0x02);
597 return res - 1; /* DIPSW2.2 */
598 }
599
an2_r()600 uint8_t epson_lx810l_device::an2_r()
601 {
602 uint8_t res = !!(ioport("DIPSW2")->read() & 0x04);
603 return res - 1; /* DIPSW2.3 */
604 }
605
an3_r()606 uint8_t epson_lx810l_device::an3_r()
607 {
608 uint8_t res = !!(ioport("DIPSW2")->read() & 0x08);
609 return res - 1; /* DIPSW2.4 */
610 }
611
an4_r()612 uint8_t epson_lx810l_device::an4_r()
613 {
614 return 0xff;
615 }
616
an5_r()617 uint8_t epson_lx810l_device::an5_r()
618 {
619 return 0xCB; /* motor voltage, 0xcb = 24V */
620 }
621
an6_r()622 uint8_t epson_lx810l_device::an6_r()
623 {
624 uint8_t res = !ioport("LOADEJECT")->read();
625 return res - 1;
626 }
627
an7_r()628 uint8_t epson_lx810l_device::an7_r()
629 {
630 return 0xff;
631 }
632