1 // license:BSD-3-Clause
2 // copyright-holders:Dirk Best
3 /**********************************************************************
4 
5    Epson LX-800 dot matrix printer
6 
7     Skeleton driver
8 
9     - CPU type uPD7810HG
10     - CPU PORTD and PORTF are connected to the Gate Array
11     - processing gets stuck in a loop, and never gets to scan the
12       input buttons and switches.
13     - CPU disassembly doesn't seem to indicate conditional JR or RET.
14 
15 **********************************************************************/
16 
17 #include "emu.h"
18 #include "epson_lx800.h"
19 #include "speaker.h"
20 #include "lx800.lh"
21 
22 
23 
24 //**************************************************************************
25 //  DEVICE DEFINITIONS
26 //**************************************************************************
27 
28 DEFINE_DEVICE_TYPE(EPSON_LX800, epson_lx800_device, "lx800", "Epson LX-800")
29 
30 
31 //-------------------------------------------------
32 //  ROM( lx800 )
33 //-------------------------------------------------
34 
ROM_START(lx800)35 ROM_START( lx800 )
36 	ROM_REGION(0x8000, "maincpu", 0)
37 	ROM_LOAD("lx800.ic3c", 0x0000, 0x8000, CRC(da06c45b) SHA1(9618c940dd10d5b43cd1edd5763b90e6447de667) )
38 ROM_END
39 
40 
41 //-------------------------------------------------
42 //  rom_region - device-specific ROM region
43 //-------------------------------------------------
44 
45 const tiny_rom_entry *epson_lx800_device::device_rom_region() const
46 {
47 	return ROM_NAME( lx800 );
48 }
49 
50 
51 //-------------------------------------------------
52 //  ADDRESS_MAP( lx800_mem )
53 //-------------------------------------------------
54 
lx800_mem(address_map & map)55 void epson_lx800_device::lx800_mem(address_map &map)
56 {
57 	map(0x0000, 0x7fff).rom(); /* 32k firmware */
58 	map(0x8000, 0x9fff).ram(); /* 8k external RAM */
59 	map(0xa000, 0xbfff).noprw(); /* not used */
60 	map(0xc000, 0xc007).mirror(0x1ff8).rw("ic3b", FUNC(e05a03_device::read), FUNC(e05a03_device::write));
61 	map(0xe000, 0xfeff).noprw(); /* not used */
62 }
63 
64 
65 //-------------------------------------------------
66 //  device_add_mconfig - add device configuration
67 //-------------------------------------------------
68 
device_add_mconfig(machine_config & config)69 void epson_lx800_device::device_add_mconfig(machine_config &config)
70 {
71 	/* basic machine hardware */
72 	upd7810_device &upd(UPD7810(config, m_maincpu, 14.7456_MHz_XTAL));
73 	upd.set_addrmap(AS_PROGRAM, &epson_lx800_device::lx800_mem);
74 	upd.pa_in_cb().set(FUNC(epson_lx800_device::porta_r));
75 	upd.pa_out_cb().set(FUNC(epson_lx800_device::porta_w));
76 	upd.pb_in_cb().set_ioport("DIPSW1");
77 	upd.pc_in_cb().set(FUNC(epson_lx800_device::portc_r));
78 	upd.pc_out_cb().set(FUNC(epson_lx800_device::portc_w));
79 	upd.an0_func().set(FUNC(epson_lx800_device::an0_r));
80 	upd.an1_func().set(FUNC(epson_lx800_device::an1_r));
81 	upd.an2_func().set(FUNC(epson_lx800_device::an2_r));
82 	upd.an3_func().set(FUNC(epson_lx800_device::an3_r));
83 	upd.an4_func().set(FUNC(epson_lx800_device::an4_r));
84 	upd.an5_func().set(FUNC(epson_lx800_device::an5_r));
85 
86 	config.set_default_layout(layout_lx800);
87 
88 	/* audio hardware */
89 	SPEAKER(config, "mono").front_center();
90 	BEEP(config, m_beep, 4000); // ?
91 	m_beep->add_route(ALL_OUTPUTS, "mono", 0.05);
92 
93 	/* gate array */
94 	e05a03_device &ic3b(E05A03(config, "ic3b", 0));
95 	ic3b.pe_lp_wr_callback().set_output("paperout_led");
96 	ic3b.reso_wr_callback().set(FUNC(epson_lx800_device::reset_w));
97 	ic3b.pe_wr_callback().set(FUNC(epson_lx800_device::centronics_pe_w));
98 	ic3b.data_rd_callback().set(FUNC(epson_lx800_device::centronics_data_r));
99 }
100 
101 
102 //-------------------------------------------------
103 //  INPUT_PORTS( epson_lx800 )
104 //-------------------------------------------------
105 
106 INPUT_PORTS_START( epson_lx800 )
107 	PORT_START("ONLINE")
PORT_CODE(KEYCODE_O)108 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("On Line") PORT_CODE(KEYCODE_O)
109 
110 	PORT_START("FORMFEED")
111 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Form Feed") PORT_CODE(KEYCODE_F)
112 
113 	PORT_START("LINEFEED")
114 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_L)
115 
116 	PORT_START("DIPSW1")
117 	PORT_DIPNAME(0x01, 0x00, "Typeface")
118 	PORT_DIPLOCATION("DIP:8")
119 	PORT_DIPSETTING(0x01, "Condensed")
120 	PORT_DIPSETTING(0x00, DEF_STR(Normal))
121 	PORT_DIPNAME(0x02, 0x00, "ZERO font")
122 	PORT_DIPLOCATION("DIP:7")
123 	PORT_DIPSETTING(0x02, "0")
124 	PORT_DIPSETTING(0x00, "0")
125 	PORT_DIPNAME(0x04, 0x00, "Character Table")
126 	PORT_DIPLOCATION("DIP:6")
127 	PORT_DIPSETTING(0x04, "Graphic")
128 	PORT_DIPSETTING(0x00, "Italic")
129 	PORT_DIPNAME(0x08, 0x00, "Paper-out detection")
130 	PORT_DIPLOCATION("DIP:5")
131 	PORT_DIPSETTING(0x08, "Valid")
132 	PORT_DIPSETTING(0x00, "Invalid")
133 	PORT_DIPNAME(0x10, 0x00, "Printing quality")
134 	PORT_DIPLOCATION("DIP:4")
135 	PORT_DIPSETTING(0x10, "NLQ")
136 	PORT_DIPSETTING(0x00, "Draft")
137 	PORT_DIPNAME(0xe0, 0xe0, "International character set")
138 	PORT_DIPLOCATION("DIP:3,2,1")
139 	PORT_DIPSETTING(0xe0, "U.S.A.")
140 	PORT_DIPSETTING(0x60, "France")
141 	PORT_DIPSETTING(0xa0, "Germany")
142 	PORT_DIPSETTING(0x20, "U.K.")
143 	PORT_DIPSETTING(0xc0, "Denmark")
144 	PORT_DIPSETTING(0x40, "Sweden")
145 	PORT_DIPSETTING(0x80, "Italy")
146 	PORT_DIPSETTING(0x00, "Spain")
147 
148 	PORT_START("DIPSW2")
149 	PORT_DIPNAME(0x01, 0x00, "Page length")
150 	PORT_DIPLOCATION("DIP:4")
151 	PORT_DIPSETTING(0x01, "12\"")
152 	PORT_DIPSETTING(0x00, "11\"")
153 	PORT_DIPNAME(0x02, 0x00, "Cut sheet feeder mode")
154 	PORT_DIPLOCATION("DIP:3")
155 	PORT_DIPSETTING(0x02, "Valid")
156 	PORT_DIPSETTING(0x00, "Invalid")
157 	PORT_DIPNAME(0x04, 0x00, "1\" skip over perforation")
158 	PORT_DIPLOCATION("DIP:2")
159 	PORT_DIPSETTING(0x04, "Valid")
160 	PORT_DIPSETTING(0x00, "Invalid")
161 	PORT_DIPNAME(0x08, 0x00, "AUTO FEED XT control")
162 	PORT_DIPLOCATION("DIP:1")
163 	PORT_DIPSETTING(0x08, "Fix to LOW")
164 	PORT_DIPSETTING(0x00, "Depends on external signal")
165 INPUT_PORTS_END
166 
167 
168 //-------------------------------------------------
169 //  input_ports - device-specific input ports
170 //-------------------------------------------------
171 
172 ioport_constructor epson_lx800_device::device_input_ports() const
173 {
174 	return INPUT_PORTS_NAME( epson_lx800 );
175 }
176 
177 
178 
179 //**************************************************************************
180 //  LIVE DEVICE
181 //**************************************************************************
182 
183 //-------------------------------------------------
184 //  epson_lx800_device - constructor
185 //-------------------------------------------------
186 
epson_lx800_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)187 epson_lx800_device::epson_lx800_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
188 	epson_lx800_device(mconfig, EPSON_LX800, tag, owner, clock)
189 {
190 }
191 
epson_lx800_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)192 epson_lx800_device::epson_lx800_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
193 	device_t(mconfig, type, tag, owner, clock),
194 	device_centronics_peripheral_interface(mconfig, *this),
195 	m_maincpu(*this, "maincpu"),
196 	m_beep(*this, "beeper"),
197 	m_online_led(*this, "online_led")
198 {
199 }
200 
201 
202 //-------------------------------------------------
203 //  device_start - device-specific startup
204 //-------------------------------------------------
205 
device_start()206 void epson_lx800_device::device_start()
207 {
208 	m_online_led.resolve();
209 }
210 
211 
212 //-------------------------------------------------
213 //  device_reset - device-specific reset
214 //-------------------------------------------------
215 
device_reset()216 void epson_lx800_device::device_reset()
217 {
218 	m_beep->set_state(0);
219 }
220 
221 
222 /***************************************************************************
223     I/O PORTS
224 ***************************************************************************/
225 
226 /* PA0   W  CRCOM  carriage motor, 0 = holding voltage, 1 = drive voltage
227  * PA1             not used
228  * PA2   W  PFCOM  paper feed motor, 0 = holding voltage, 1 = drive voltage
229  * PA3  R   LF SW  line feed switch
230  * PA4  R   FF SW  form feed switch
231  * PA5  R   PE SW  paper end sensor, 0 = no paper, 1 = paper
232  * PA6             not used
233  * PA7  R   P/S    P/S signal from the optional interface
234  */
porta_r(offs_t offset)235 uint8_t epson_lx800_device::porta_r(offs_t offset)
236 {
237 	uint8_t result = 0;
238 
239 	logerror("%s: lx800_porta_r(%02x)\n", machine().describe_context(), offset);
240 
241 	result |= ioport("LINEFEED")->read() << 3;
242 	result |= ioport("FORMFEED")->read() << 4;
243 	result |= 1 << 5;
244 
245 	result |= 1 << 7;
246 
247 	return result;
248 }
249 
porta_w(offs_t offset,uint8_t data)250 void epson_lx800_device::porta_w(offs_t offset, uint8_t data)
251 {
252 	logerror("%s: lx800_porta_w(%02x): %02x\n", machine().describe_context(), offset, data);
253 	logerror("--> carriage: %d, paper feed: %d\n", BIT(data, 0), BIT(data, 2));
254 }
255 
256 /* PC0   W  TXD        serial i/o txd
257  * PC1  R   RXD        serial i/o rxd
258  * PC2   W  ONLINE LP  online led
259  * PC3  R   ONLINE SW  online switch
260  * PC4   W  ERR        centronics error
261  * PC5   W  ACK        centronics acknowledge
262  * PC6   W  FIRE       drive pulse width signal
263  * PC7   W  BUZZER     buzzer signal
264  */
portc_r(offs_t offset)265 uint8_t epson_lx800_device::portc_r(offs_t offset)
266 {
267 	uint8_t result = 0;
268 
269 	logerror("%s: lx800_portc_r(%02x)\n", machine().describe_context(), offset);
270 
271 	result |= ioport("ONLINE")->read() << 3;
272 
273 	return result;
274 }
275 
portc_w(offs_t offset,uint8_t data)276 void epson_lx800_device::portc_w(offs_t offset, uint8_t data)
277 {
278 	logerror("%s: lx800_portc_w(%02x): %02x\n", machine().describe_context(), offset, data);
279 	logerror("--> err: %d, ack: %d, fire: %d, buzzer: %d\n", BIT(data, 4), BIT(data, 5), BIT(data, 6), BIT(data, 7));
280 
281 	m_online_led = !BIT(data, 2);
282 	m_beep->set_state(!BIT(data, 7));
283 }
284 
READ_LINE_MEMBER(epson_lx800_device::an0_r)285 READ_LINE_MEMBER( epson_lx800_device::an0_r )
286 {
287 	return BIT(ioport("DIPSW2")->read(), 0);
288 }
289 
READ_LINE_MEMBER(epson_lx800_device::an1_r)290 READ_LINE_MEMBER( epson_lx800_device::an1_r )
291 {
292 	return BIT(ioport("DIPSW2")->read(), 1);
293 }
294 
READ_LINE_MEMBER(epson_lx800_device::an2_r)295 READ_LINE_MEMBER( epson_lx800_device::an2_r )
296 {
297 	return BIT(ioport("DIPSW2")->read(), 2);
298 }
299 
READ_LINE_MEMBER(epson_lx800_device::an3_r)300 READ_LINE_MEMBER( epson_lx800_device::an3_r )
301 {
302 	return BIT(ioport("DIPSW2")->read(), 3); // can also read an external line AUTO_FEED_XT
303 }
304 
READ_LINE_MEMBER(epson_lx800_device::an4_r)305 READ_LINE_MEMBER( epson_lx800_device::an4_r )
306 {
307 	return 0; // Printer select line (0=always selected)
308 }
309 
READ_LINE_MEMBER(epson_lx800_device::an5_r)310 READ_LINE_MEMBER( epson_lx800_device::an5_r )
311 {
312 	return 1; // Monitors 24v line, should return 4.08 volts
313 }
314 
315 
316 /***************************************************************************
317     GATE ARRAY
318 ***************************************************************************/
319 
centronics_data_r()320 uint8_t epson_lx800_device::centronics_data_r()
321 {
322 	logerror("centronics: data read\n");
323 	return 0x55;
324 }
325 
WRITE_LINE_MEMBER(epson_lx800_device::centronics_pe_w)326 WRITE_LINE_MEMBER( epson_lx800_device::centronics_pe_w )
327 {
328 	logerror("centronics: pe = %d\n", state);
329 }
330 
WRITE_LINE_MEMBER(epson_lx800_device::reset_w)331 WRITE_LINE_MEMBER( epson_lx800_device::reset_w )
332 {
333 	logerror("cpu reset");
334 	m_maincpu->reset();
335 }
336