1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /****************************************************************************
4 
5     TI-99 RS232 and Parallel interface card
6 
7     TI99 RS232 card ('rs232')
8     TMS9902 ('rs232:tms9902_0')
9     TMS9902 ('rs232:tms9902_1')
10     TI99 RS232 attached serial device ('rs232:serdev0')
11     TI99 RS232 attached serial device ('rs232:serdev1')
12     TI99 PIO attached parallel device ('rs232:piodev')
13 
14     Currently this emulation does not directly interact with the serial
15     interface on the host computer. However, using a socket connection it is
16     possible to attach an external bridge which interacts with a real UART.
17 
18     TI RS232 card wiring
19     --------------------
20     The card uses this wiring (inverters not included)
21 
22      +-----+         Pins of the connector
23      | 9902|          (common naming)
24      | RIN |---<-------  2  (TD)
25      | XOUT|--->-------  3  (RD)
26      | RTS |--->-------  8  (DCD)
27      | CTS |-<-+------- 20  (DTR)
28      | DSR |-<-+    H--> 6  (DSR)
29      +-----+     +-----> 5  (CTS)
30                 /
31      +-----+   /
32      | CRU |--+
33      +-----+
34 
35     This wiring is typical for a DCE, not a DTE. The TI RS232 was obviously
36     designed to look like a modem. The advantage is that you can use the same
37     cables for connecting a modem to the RS232 interface or for connecting
38     a second TI via its interface. To connect to a DTE you can use a 1-1
39     wiring cable (1 on 1, 2 on 2 ...)
40 
41     The TI manual for the RS232 card suggests the following cables:
42 
43     TI RS232   -    Modem or other TI RS232
44       2 -----<----- 3
45       3 ----->----- 2
46       6 ----->---- 20         (crossover cable)
47      20 -----<----- 6
48 
49     TI RS232   -    Terminal (DTE)
50       2 ----<------ 2
51       3 ---->------ 3
52       5 ---->------ 5
53       6 ---->------ 6         (1-1 cable)
54       8 ---->------ 8
55      20 ----<------20
56 
57     If we want to use a PC serial interface to play the role of the TI
58     interface we have to map the TI wiring to a suitable wiring for PC
59     interfaces which are designed as DTEs. This is achieved by the functions
60     map_lines_in, map_lines_out.
61 
62     Note that we now have to swap the cable types: Use a 1-1 cable to connect
63     another TI or a modem on the other end, and use a crossover cable for
64     another PC (the usual way of connecting).
65 
66     RS232 Over IP protocol
67     ----------------------
68     This implementation can make use of such an external bridge. Normal data
69     are forwarded to the bridge and back, while line control is organized via
70     special byte sequences. These sequences are introduced by a 0x1B byte (ESC).
71 
72     The protocol has two modes: normal and escape
73 
74     normal mode: transmit byte (!= 0x1b) unchanged
75     escape mode: entered by ESC, bytes following:
76        ESC = plain ESC byte
77        length byte[length] = control sequence (length != 0x1b)
78 
79        byte[]:
80           All configuration settings are related to a specified UART; UARTs may
81           differ in their capabilities and may require specific settings
82           (e.g. the TMS9902 specifies the line speed by a clock ratio, while
83           others may have indexed, fixed rates or use integers)
84 
85           (x=unused)
86 
87           1ccc xaaa = configuration of parameter ccc; UART type aaa
88              1111 xaaa rrrr rrrr rrrr 0000     = config receive rate on aaa
89              1110 xaaa rrrr rrrr rrrr 0000     = config transmit rate on aaa
90              1101 xaaa xxxx xxbb               = config databits bb (00=5 ... 11=8)
91              1100 xaaa xxxx xxss               = config stop bits ss (00=1.5, 01=2, 1x=1)
92              1011 xaaa xxxx xxpp               = config parity pp (1x=enable, x1=odd)
93 
94           00ab cdef = line state of RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f
95           01gh i000 = exception g=BRK, h=FRMERR, i=PARERR
96 
97     The protocol changes back to normal mode after transmitting the control
98     sequence.
99 
100     Michael Zapf
101     February 2012: Rewritten as class
102 
103 *****************************************************************************/
104 
105 #include "emu.h"
106 #include "ti_rs232.h"
107 
108 #define LOG_WARN        (1U<<1)    // Warnings
109 #define LOG_CONFIG      (1U<<2)
110 #define LOG_LINES       (1U<<3)
111 #define LOG_SETTING     (1U<<4)
112 #define LOG_STATE       (1U<<5)
113 #define LOG_MAP         (1U<<6)
114 #define LOG_IN          (1U<<7)
115 #define LOG_OUT         (1U<<8)
116 #define LOG_ILA         (1U<<9)
117 
118 #define VERBOSE ( LOG_CONFIG | LOG_WARN )
119 #include "logmacro.h"
120 
121 DEFINE_DEVICE_TYPE_NS(TI99_RS232,     bus::ti99::peb, ti_rs232_pio_device,      "ti99_rs232",           "TI-99 RS232/PIO interface")
122 DEFINE_DEVICE_TYPE_NS(TI99_RS232_DEV, bus::ti99::peb, ti_rs232_attached_device, "ti99_rs232_atttached", "TI-99 Serial attached device")
123 DEFINE_DEVICE_TYPE_NS(TI99_PIO_DEV,   bus::ti99::peb, ti_pio_attached_device,   "ti99_pio_attached",    "TI-99 Parallel attached device")
124 
125 namespace bus { namespace ti99 { namespace peb {
126 
127 #define SENILA_0_BIT 0x80
128 #define SENILA_1_BIT 0x40
129 
130 #define RECV_MODE_NORMAL 1
131 #define RECV_MODE_ESC 2
132 #define RECV_MODE_ESC_LINES 3
133 
134 #define ESC 0x1b
135 
136 #define UART0 "uart0"
137 #define UART1 "uart1"
138 
139 #define SERDEV0 "serdev0"
140 #define SERDEV1 "serdev1"
141 #define PIODEV "piodev"
142 
ti_rs232_pio_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)143 ti_rs232_pio_device::ti_rs232_pio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
144 	device_t(mconfig, TI99_RS232, tag, owner, clock),
145 	device_ti99_peribox_card_interface(mconfig, *this),
146 	m_crulatch(*this, "crulatch"),
147 	m_uart0(*this, UART0),
148 	m_uart1(*this, UART1),
149 	m_serdev0(*this, SERDEV0),
150 	m_serdev1(*this, SERDEV1),
151 	m_piodev(*this, PIODEV),
152 	m_dsrrom(nullptr),
153 	m_pio_direction_in(false),
154 	m_pio_handshakeout(false),
155 	m_pio_handshakein(false),
156 	m_pio_spareout(false),
157 	m_pio_sparein(false),
158 	m_flag0(false),
159 	m_led(false),
160 	m_pio_out_buffer(0),
161 	m_pio_in_buffer(0),
162 	m_pio_readable(false),
163 	m_pio_writable(false),
164 	m_pio_write(false),
165 	m_ila(0)
166 {
167 }
168 
169 
170 /**************************************************************************/
171 /* Ports */
172 
ti_rs232_attached_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)173 ti_rs232_attached_device::ti_rs232_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
174 	: device_t(mconfig, TI99_RS232_DEV, tag, owner, clock),
175 	device_image_interface(mconfig, *this),
176 	m_uart(nullptr)
177 {
178 }
179 
ti_pio_attached_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)180 ti_pio_attached_device::ti_pio_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
181 	: device_t(mconfig, TI99_PIO_DEV, tag, owner, clock),
182 	device_image_interface(mconfig, *this)
183 {
184 }
185 
186 /*
187     Initialize rs232 unit and open image
188 */
call_load()189 image_init_result ti_rs232_attached_device::call_load()
190 {
191 	m_uart->set_clock(true);
192 
193 	// The following line may cause trouble in the init phase
194 	// card->incoming_dtr(devnumber, (m_file!=nullptr)? ASSERT_LINE : CLEAR_LINE);
195 
196 	return image_init_result::PASS;  // OK
197 }
198 
call_unload()199 void ti_rs232_attached_device::call_unload()
200 {
201 	m_uart->set_clock(false);
202 }
203 
204 /*
205     Initialize pio unit and open image
206 */
call_load()207 image_init_result ti_pio_attached_device::call_load()
208 {
209 	ti_rs232_pio_device* card = static_cast<ti_rs232_pio_device*>(owner());
210 
211 	// tell whether the image is readable
212 	card->m_pio_readable = true;
213 	// tell whether the image is writable
214 	card->m_pio_writable = !is_readonly();
215 
216 	if (card->m_pio_write && card->m_pio_writable)
217 		card->m_pio_handshakein = false;    // receiver ready
218 	else
219 		card->m_pio_handshakein = true;
220 
221 	return image_init_result::PASS;  // OK
222 }
223 
224 /*
225     close a pio image
226 */
call_unload()227 void ti_pio_attached_device::call_unload()
228 {
229 	ti_rs232_pio_device* card = static_cast<ti_rs232_pio_device*>(owner());
230 
231 	card->m_pio_writable = false;
232 	card->m_pio_handshakein = true; /* receiver not ready */
233 	card->m_pio_sparein = false;
234 }
235 
236 /****************************************************************************/
237 
238 /*
239     CRU read
240 */
crureadz(offs_t offset,uint8_t * value)241 void ti_rs232_pio_device::crureadz(offs_t offset, uint8_t *value)
242 {
243 	if ((offset & 0xff00)==m_cru_base)
244 	{
245 		if ((offset & 0x00c0)==0x0000)
246 		{
247 			uint8_t reply = 0x00;
248 			if (m_pio_direction_in)         reply |= 0x02;
249 			if (m_pio_handshakein)          reply |= 0x04;
250 			if (m_pio_sparein)              reply |= 0x08;
251 			if (m_flag0)                    reply |= 0x10;
252 			// The CTS line is realized as CRU bits
253 			// Mind that this line is handled as an output going to the remote CTS
254 			if ((m_signals[0] & tms9902_device::CTS)!=0)    reply |= 0x20;
255 			if ((m_signals[1] & tms9902_device::CTS)!=0)    reply |= 0x40;
256 			if (m_led)                      reply |= 0x80;
257 			*value = BIT(reply, (offset>>1) & 7);
258 			return;
259 		}
260 		if ((offset & 0x00c0)==0x0040)
261 		{
262 			*value = m_uart0->cruread(offset>>1);
263 			return;
264 		}
265 		if ((offset & 0x00c0)==0x0080)
266 		{
267 			*value = m_uart1->cruread(offset>>1);
268 			return;
269 		}
270 	}
271 }
272 
273 /*
274     CRU write
275 */
cruwrite(offs_t offset,uint8_t data)276 void ti_rs232_pio_device::cruwrite(offs_t offset, uint8_t data)
277 {
278 	if ((offset & 0xff00)==m_cru_base)
279 	{
280 		if ((offset & 0x00c0)==0x0040)
281 		{
282 			m_uart0->cruwrite(offset>>1, data);
283 			return;
284 		}
285 		if ((offset & 0x00c0)==0x0080)
286 		{
287 			m_uart1->cruwrite(offset>>1, data);
288 			return;
289 		}
290 
291 		int bit = (offset & 0x00ff)>>1;
292 		m_crulatch->write_bit(bit, data);
293 	}
294 }
295 
WRITE_LINE_MEMBER(ti_rs232_pio_device::selected_w)296 WRITE_LINE_MEMBER(ti_rs232_pio_device::selected_w)
297 {
298 	m_selected = state;
299 }
300 
WRITE_LINE_MEMBER(ti_rs232_pio_device::pio_direction_in_w)301 WRITE_LINE_MEMBER(ti_rs232_pio_device::pio_direction_in_w)
302 {
303 	m_pio_direction_in = state;
304 }
305 
WRITE_LINE_MEMBER(ti_rs232_pio_device::pio_handshake_out_w)306 WRITE_LINE_MEMBER(ti_rs232_pio_device::pio_handshake_out_w)
307 {
308 	m_pio_handshakeout = state;
309 	if (m_pio_write && m_pio_writable && (!m_pio_direction_in))
310 	{   /* PIO in output mode */
311 		if (!m_pio_handshakeout)
312 		{   /* write data strobe */
313 			/* write data and acknowledge */
314 			uint8_t buf = m_pio_out_buffer;
315 			int ret = m_piodev->fwrite(&buf, 1);
316 			if (ret)
317 				m_pio_handshakein = 1;
318 		}
319 		else
320 		{
321 			/* end strobe */
322 			/* we can write some data: set receiver ready */
323 			m_pio_handshakein = 0;
324 		}
325 	}
326 	if ((!m_pio_write) && m_pio_readable /*&& pio_direction_in*/)
327 	{   /* PIO in input mode */
328 		if (!m_pio_handshakeout)
329 		{   /* receiver ready */
330 			/* send data and strobe */
331 			uint8_t buf;
332 			if (m_piodev->fread(&buf, 1))
333 				m_pio_in_buffer = buf;
334 			m_pio_handshakein = 0;
335 		}
336 		else
337 		{
338 			/* data acknowledge */
339 			/* we can send some data: set transmitter ready */
340 			m_pio_handshakein = 1;
341 		}
342 	}
343 }
344 
WRITE_LINE_MEMBER(ti_rs232_pio_device::pio_spareout_w)345 WRITE_LINE_MEMBER(ti_rs232_pio_device::pio_spareout_w)
346 {
347 	m_pio_spareout = state;
348 }
349 
WRITE_LINE_MEMBER(ti_rs232_pio_device::flag0_w)350 WRITE_LINE_MEMBER(ti_rs232_pio_device::flag0_w)
351 {
352 	m_flag0 = state;
353 }
354 
WRITE_LINE_MEMBER(ti_rs232_pio_device::cts0_w)355 WRITE_LINE_MEMBER(ti_rs232_pio_device::cts0_w)
356 {
357 	// Set the CTS line for RS232/1
358 	LOGMASKED(LOG_LINES, "(1/3) Setting CTS* via CRU to %d\n", state);
359 	output_line_state(0, tms9902_device::CTS, state ? 0 : tms9902_device::CTS);
360 }
361 
WRITE_LINE_MEMBER(ti_rs232_pio_device::cts1_w)362 WRITE_LINE_MEMBER(ti_rs232_pio_device::cts1_w)
363 {
364 	// Set the CTS line for RS232/2
365 	LOGMASKED(LOG_LINES, "(2/4) Setting CTS* via CRU to %d\n", state);
366 	output_line_state(1, tms9902_device::CTS, state ? 0 : tms9902_device::CTS);
367 }
368 
WRITE_LINE_MEMBER(ti_rs232_pio_device::led_w)369 WRITE_LINE_MEMBER(ti_rs232_pio_device::led_w)
370 {
371 	m_led = state;
372 }
373 
374 /*
375     Memory read
376 */
readz(offs_t offset,uint8_t * value)377 void ti_rs232_pio_device::readz(offs_t offset, uint8_t *value)
378 {
379 	if (m_senila==ASSERT_LINE)
380 	{
381 		LOGMASKED(LOG_ILA, "Sensing ILA\n");
382 		*value = m_ila;
383 		// The card ROM must be unselected, or we get two values
384 		// on the data bus
385 
386 		// Not sure whether this is correct; there is no software that makes
387 		// use of it
388 		m_ila = 0;
389 	}
390 	if (in_dsr_space(offset, true) && m_selected)
391 	{
392 		if ((offset & 0x1000)==0x0000)
393 		{
394 			*value = m_dsrrom[offset&0x0fff];
395 		}
396 		else
397 		{
398 			*value = m_pio_direction_in ? m_pio_in_buffer : m_pio_out_buffer;
399 		}
400 	}
401 }
402 
403 /*
404     Memory write
405 */
write(offs_t offset,uint8_t data)406 void ti_rs232_pio_device::write(offs_t offset, uint8_t data)
407 {
408 	if (in_dsr_space(offset, true) && m_selected)
409 	{
410 		if ((offset & 0x1001)==0x1000)
411 		{
412 			m_pio_out_buffer = data;
413 		}
414 	}
415 }
416 
417 /**************************************************************************/
418 
419 /*
420     The DTR line of the interface card is wired to the CTS and DSR
421     of the UART.
422 */
incoming_dtr(int uartind,line_state value)423 void ti_rs232_pio_device::incoming_dtr(int uartind, line_state value)
424 {
425 	LOGMASKED(LOG_LINES, "(RS232/%d) Incoming DTR = %d\n", uartind+1, (value==ASSERT_LINE)? 1:0);
426 
427 	if (uartind==0)
428 	{
429 		m_uart0->rcv_cts(value);
430 		m_uart0->rcv_dsr(value);
431 	}
432 	else
433 	{
434 		m_uart1->rcv_cts(value);
435 		m_uart1->rcv_dsr(value);
436 	}
437 }
438 
439 /*
440     Data transmission
441 */
transmit_data(int uartind,uint8_t value)442 void ti_rs232_pio_device::transmit_data(int uartind, uint8_t value)
443 {
444 	uint8_t buf = value;
445 	ti_rs232_attached_device *serial = (uartind==0)? m_serdev0 : m_serdev1;
446 
447 	if (!serial->exists())
448 	{
449 		LOGMASKED(LOG_CONFIG, "(RS232/%d) No serial output attached\n", uartind+1);
450 		return;
451 	}
452 
453 	// Send a double ESC if this is not a control operation
454 	if (buf==0x1b)
455 	{
456 		LOGMASKED(LOG_OUT, "(RS232/%d) send ESC (requires another ESC)\n", uartind+1);
457 		serial->fwrite(&buf, 1);
458 	}
459 	char cbuf = (buf < 0x20 || buf > 0x7e)? '.' : (char)buf;
460 	LOGMASKED(LOG_OUT, "(RS232/%d) send %c <%02x>\n", uartind+1, cbuf, buf);
461 	serial->fwrite(&buf, 1);
462 }
463 
464 /*
465     Map the DCE-like wiring to a DTE-like wiring and vice versa (mapping==0)
466     No handshake
467 
468        Emulated           PC serial
469        TI RS232           interface
470      XOUT  2 TXD ----->-----( 3) ---> TXD
471       RIN  3 RXD -----<-----( 2) <--- RXD
472       CRU  5 CTS -|       |-( 8) <--- DCD  (cable)
473      +12V  6 DSR ----->-----(20) ---> DTR
474       RTS  8 DCD ----->-----( 4) ---> RTS
475   DSR+CTS 20 DTR -----<-----( 6) <--- DSR
476                           |-( 5) <--- CTS
477 
478     Alternative mapping: (mapping==1)
479     RTS/CTS handshake
480 
481        Emulated           PC serial
482        TI RS232           interface
483      XOUT  2 TXD ----->-----( 3) ---> TXD
484       RIN  3 RXD -----<-----( 2) <--- RXD
485       CRU  5 CTS ----->-----( 4) ---> RTS
486       +12V 6 DSR -|       |-( 6) <--- DSR
487       RTS  8 DCD ----->-----(20) ---> DTR
488   DSR+CTS 20 DTR -----<-----( 8) <--- DCD
489                           |-( 5) <--- CTS
490 
491     Yet another mapping: (mapping==2)
492     CRU-based handshake
493 
494        Emulated           PC serial
495        TI RS232           interface
496      XOUT  2 TXD ----->-----( 3) ---> TXD
497       RIN  3 RXD -----<-----( 2) <--- RXD
498       CRU  5 CTS ----->-----(20) ---> DTR
499       +12V 6 DSR -|       |-( 6) <--- DSR
500       RTS  8 DCD ----->-----( 4) ---> RTS
501   DSR+CTS 20 DTR -----<-----( 5) <--- CTS  (cable)
502                           |-( 8) <--- DCD
503 
504 */
map_lines_out(int uartind,uint8_t value)505 uint8_t ti_rs232_pio_device::map_lines_out(int uartind, uint8_t value)
506 {
507 	uint8_t ret = 0;
508 	int mapping = ioport("SERIALMAP")->read();
509 
510 	//    00ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f
511 
512 	LOGMASKED(LOG_LINES, "(RS232/%d) out connector pins = 0x%02x; translate for DTE\n", uartind+1, value);
513 
514 	if (value & tms9902_device::BRK)
515 	{
516 		LOGMASKED(LOG_MAP, "(RS232/%d) Sending BRK\n", uartind+1);
517 		ret |= tms9902_device::EXCEPT | tms9902_device::BRK;
518 	}
519 
520 	if (mapping==0)
521 	{
522 		// V1
523 		if (value & tms9902_device::CTS)
524 		{
525 			LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map CTS line, ignoring\n", uartind+1);
526 		}
527 		if (value & tms9902_device::DSR)
528 		{
529 			ret |= tms9902_device::DTR;
530 			LOGMASKED(LOG_MAP, "(RS232/%d) Setting DTR line\n", uartind+1);
531 		}
532 		if (value & tms9902_device::DCD)
533 		{
534 			ret |= tms9902_device::RTS;
535 			LOGMASKED(LOG_MAP, "(RS232/%d) Setting RTS line\n", uartind+1);
536 		}
537 	}
538 	else
539 	{
540 		if (mapping==1)
541 		{
542 			// V2
543 			if (value & tms9902_device::CTS)
544 			{
545 				ret |= tms9902_device::RTS;
546 				LOGMASKED(LOG_MAP, "(RS232/%d) Setting RTS line\n", uartind+1);
547 			}
548 			if (value & tms9902_device::DCD)
549 			{
550 				ret |= tms9902_device::DTR;
551 				LOGMASKED(LOG_MAP, "(RS232/%d) Setting DTR line\n", uartind+1);
552 			}
553 		}
554 		else
555 		{
556 			// v3
557 			if (value & tms9902_device::CTS)
558 			{
559 				ret |= tms9902_device::DTR;
560 				LOGMASKED(LOG_MAP, "(RS232/%d) Setting DTR line\n", uartind+1);
561 			}
562 			if (value & tms9902_device::DSR)
563 			{
564 				LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map DSR line, ignoring\n", uartind+1);
565 			}
566 			if (value & tms9902_device::DCD)
567 			{
568 				ret |= tms9902_device::RTS;
569 				LOGMASKED(LOG_MAP, "(RS232/%d) Setting RTS line\n", uartind+1);
570 			}
571 		}
572 	}
573 
574 	return ret;
575 }
576 
map_lines_in(int uartind,uint8_t value)577 uint8_t ti_rs232_pio_device::map_lines_in(int uartind, uint8_t value)
578 {
579 	uint8_t ret = 0;
580 	int mapping = ioport("SERIALMAP")->read();
581 
582 	//    00ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f
583 
584 	LOGMASKED(LOG_LINES, "(RS232/%d) in connector pins = 0x%02x; translate from DTE\n", uartind+1, value);
585 
586 	if (value & tms9902_device::BRK)
587 	{
588 		LOGMASKED(LOG_MAP, "(RS232/%d) Getting BRK\n", uartind+1);
589 		ret |= tms9902_device::EXCEPT | tms9902_device::BRK;
590 	}
591 
592 	if (mapping==0)
593 	{
594 		// V1
595 		if (value & tms9902_device::CTS)
596 		{
597 			LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map CTS line, ignoring\n", uartind+1);
598 		}
599 		if (value & tms9902_device::DSR)
600 		{
601 			ret |= tms9902_device::DTR;
602 			LOGMASKED(LOG_MAP, "(RS232/%d) Setting DTR line\n", uartind+1);
603 		}
604 		if (value & tms9902_device::DCD)
605 		{
606 			LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map DCD line, ignoring\n", uartind+1);
607 		}
608 	}
609 	else
610 	{
611 		if (mapping==1)
612 		{
613 			if (value & tms9902_device::DCD)
614 			{
615 				ret |= tms9902_device::DTR;
616 				LOGMASKED(LOG_MAP, "(RS232/%d) Setting DTR line\n", uartind+1);
617 			}
618 			if (value & tms9902_device::DSR)
619 			{
620 				LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map DSR line, ignoring\n", uartind+1);
621 			}
622 			if (value & tms9902_device::CTS)
623 			{
624 				LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map CTS line, ignoring\n", uartind+1);
625 			}
626 		}
627 		else
628 		{
629 			if (value & tms9902_device::CTS)
630 			{
631 				ret |= tms9902_device::DTR;
632 				LOGMASKED(LOG_MAP, "(RS232/%d) Setting DTR line\n", uartind+1);
633 			}
634 			if (value & tms9902_device::DSR)
635 			{
636 				LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map DSR line, ignoring\n", uartind+1);
637 			}
638 			if (value & tms9902_device::DCD)
639 			{
640 				LOGMASKED(LOG_MAP, "(RS232/%d) Cannot map DCD line, ignoring\n", uartind+1);
641 			}
642 		}
643 	}
644 
645 	return ret;
646 }
647 /*
648     Receive a character or a line state from the remote site. This method
649     is called by a timer with some sufficiently high polling frequency. Note
650     that the control lines are not subject to baud rates.
651     The higher polling frequency will cause overloads in the TMS9902 which has
652     a one-byte buffer only: Since the data source (e.g. the PC UART and the
653     socket connection) may be buffered, we may get a cluster of bytes in rapid
654     succession. In order to avoid this, this function uses the parameter
655     "baudpoll" which is the ratio of the characters/second and the polling
656     frequency. (char/sec is baud rate divided by 10.)
657     Whenever we receive a character that is passed to the UART, we have to
658     pause for 1/baudpoll iterations before getting the next byte from the
659     data source.
660 
661     FIXME: This may fail when the emulated system tries to stop the remote
662     system by deactivating RTS or DTR, but there are still incoming
663     bytes in the socket or PC UART buffer. The buffered bytes may then cause
664     an overflow in the emulated UART, since the application program expects
665     the remote system to stop sending instantly.
666     The only way to handle this is to mirror the activity within the serial
667     bridge: Whenever a RTS=0 or DTR=0 is transmitted to the remote site, the
668     serial bridge must stop delivering data bytes until the handshake opens the
669     channel again.
670 */
receive_data_or_line_state(int uartind)671 void ti_rs232_pio_device::receive_data_or_line_state(int uartind)
672 {
673 	uint8_t buffer;
674 
675 	ti_rs232_attached_device *serial = (uartind==0)? m_serdev0 : m_serdev1;
676 	tms9902_device *uart = (uartind==0)? m_uart0 : m_uart1;
677 
678 	if (!serial->exists())
679 	{
680 		LOGMASKED(LOG_CONFIG, "(RS232/%d) No serial input attached\n", uartind+1);
681 		return;
682 	}
683 
684 	double baudpoll = uart->get_baudpoll();
685 
686 	// If more than the minimum waiting time since the last data byte has
687 	// elapsed, we can get a new value.
688 	if (m_time_hold[uartind] > 1.0)
689 	{
690 		// Buffer empty?
691 		if (m_bufpos[uartind] == m_buflen[uartind])
692 		{
693 			// Get all out of sdlsocket
694 			m_buflen[uartind] = serial->fread(m_recvbuf[uartind].get(), 512);
695 			m_bufpos[uartind] = 0;
696 			if (m_buflen[uartind]==0) return;
697 		}
698 		buffer = m_recvbuf[uartind][m_bufpos[uartind]++];
699 	}
700 	else
701 	{
702 		// number of polls has not yet elapsed; we have to wait.
703 		m_time_hold[uartind] += baudpoll;
704 		return;
705 	}
706 
707 	char cbuf = (buffer < 0x20 || buffer > 0x7e)? '.' : (char)buffer;
708 
709 	// No config parameters here, only data or line setting
710 	switch (m_recv_mode[uartind])
711 	{
712 	case RECV_MODE_NORMAL:
713 		if (buffer==0x1b)
714 		{
715 			LOGMASKED(LOG_IN, "(RS232/%d) Received: %c <%02x>, switch to ESC mode\n", uartind+1, cbuf, buffer);
716 			m_recv_mode[uartind] = RECV_MODE_ESC;
717 		}
718 		else
719 		{
720 			LOGMASKED(LOG_IN, "(RS232/%d) Received: %c <%02x>, pass to UART\n", uartind+1, cbuf, buffer);
721 			uart->rcv_data(buffer);
722 			m_time_hold[uartind] = 0.0;
723 		}
724 		break;
725 	case RECV_MODE_ESC:
726 		if (buffer==0x1b)
727 		{
728 			m_recv_mode[uartind] = RECV_MODE_NORMAL;
729 			LOGMASKED(LOG_STATE, "(RS232/%d) Received another ESC, passing to UART, leaving ESC mode\n", uartind+1);
730 			uart->rcv_data(buffer);
731 			m_time_hold[uartind] = 0.0;
732 		}
733 		else
734 		{
735 			// the byte in buffer is the length byte
736 			LOGMASKED(LOG_STATE, "(RS232/%d) Received length byte <%02x> in ESC mode\n", uartind+1, buffer);
737 			if (buffer != 1)
738 			{
739 				LOGMASKED(LOG_WARN, "(RS232/%d) ** ERROR: Expected length byte 1 but got 0x%02x, leaving ESC mode.\n", uartind+1, buffer);
740 				m_recv_mode[uartind] = RECV_MODE_NORMAL;
741 			}
742 			else
743 				m_recv_mode[uartind] = RECV_MODE_ESC_LINES;
744 		}
745 		break;
746 
747 	case RECV_MODE_ESC_LINES:
748 		// Map the real serial interface lines to our emulated connector
749 		// The mapping is the same for both directions, so we use the same function
750 		if (buffer & tms9902_device::EXCEPT)
751 		{
752 			// Exception states: BRK, FRMERR, PARERR
753 			LOGMASKED(LOG_LINES, "(RS232/%d) Received BRK or ERROR <%02x>\n", uartind+1, buffer);
754 			uart->rcv_break(((buffer & tms9902_device::BRK)!=0));
755 
756 			if (buffer & tms9902_device::FRMERR)
757 				uart->rcv_framing_error();
758 			if (buffer & tms9902_device::PARERR)
759 				uart->rcv_parity_error();
760 		}
761 		else
762 		{
763 			buffer = map_lines_in(uartind, buffer);
764 			LOGMASKED(LOG_LINES, "(RS232/%d) Received (remapped) <%02x> in ESC mode\n", uartind+1, buffer);
765 
766 			// The DTR line on the RS232 connector of the board is wired to both the
767 			// CTS and the DSR pin of the TMS9902
768 			// Apart from the data line, DTR is the only input line
769 			incoming_dtr(uartind,  (buffer & tms9902_device::DTR)? ASSERT_LINE : CLEAR_LINE);
770 		}
771 
772 		m_recv_mode[uartind] = RECV_MODE_NORMAL;
773 		break;
774 
775 	default:
776 		LOGMASKED(LOG_WARN, "(RS232/%d) Unknown mode: %d\n", uartind+1, m_recv_mode[uartind]);
777 	}
778 }
779 
780 /*
781     Control operations like configuration or line changes
782 */
configure_interface(int uartind,int type,int value)783 void ti_rs232_pio_device::configure_interface(int uartind, int type, int value)
784 {
785 	uint8_t bufctrl[4];
786 	ti_rs232_attached_device *serial = (uartind==0)? m_serdev0 : m_serdev1;
787 	uint8_t esc = ESC;
788 
789 	if (!serial->exists())
790 	{
791 		LOGMASKED(LOG_CONFIG, "(RS232/%d) No serial output attached\n", uartind+1);
792 		return;
793 	}
794 
795 	serial->fwrite(&esc, 1);
796 	bufctrl[0] = 0x02;
797 	bufctrl[1] = tms9902_device::CONFIG | tms9902_device::TYPE_TMS9902;
798 
799 	switch (type) {
800 	case tms9902_device::RATERECV:
801 		LOGMASKED(LOG_SETTING, "(RS232/%d) Send receive rate %04x\n", uartind+1, value);
802 		// value has 12 bits
803 		// 1ccc xaaa                         = config adapter type a
804 		// 1111 xaaa rrrr rrrr rrrr 0000     = config receive rate on a
805 		// 1110 xaaa rrrr rrrr rrrr 0000     = config transmit rate on a
806 		bufctrl[0] = 0x03; // length
807 		bufctrl[1] |= tms9902_device::RATERECV;
808 		bufctrl[2] = (value & 0x0ff0)>>4;
809 		bufctrl[3] = (value & 0x0f)<<4;
810 		break;
811 	case tms9902_device::RATEXMIT:
812 		LOGMASKED(LOG_SETTING, "(RS232/%d) Send transmit rate %04x\n", uartind+1, value);
813 		bufctrl[0] = 0x03; // length
814 		bufctrl[1] |= tms9902_device::RATEXMIT;
815 		bufctrl[2] = (value & 0x0ff0)>>4;
816 		bufctrl[3] = (value & 0x0f)<<4;
817 		break;
818 	case tms9902_device::STOPBITS:
819 		LOGMASKED(LOG_SETTING, "(RS232/%d) Send stop bit config %02x\n", uartind+1, value&0x03);
820 		bufctrl[1] |= tms9902_device::STOPBITS;
821 		bufctrl[2] = (value & 0x03);
822 		break;
823 	case tms9902_device::DATABITS:
824 		LOGMASKED(LOG_SETTING, "(RS232/%d) Send data bit config %02x\n", uartind+1, value&0x03);
825 		bufctrl[1] |= tms9902_device::DATABITS;
826 		bufctrl[2] = (value & 0x03);
827 		break;
828 	case tms9902_device::PARITY:
829 		LOGMASKED(LOG_SETTING, "(RS232/%d) Send parity config %02x\n", uartind+1, value&0x03);
830 		bufctrl[1] |= tms9902_device::PARITY;
831 		bufctrl[2] = (value & 0x03);
832 		break;
833 	default:
834 		LOGMASKED(LOG_WARN, "(RS232/%d) Error - unknown config type %02x\n", uartind+1, type);
835 	}
836 
837 	serial->fwrite(bufctrl, bufctrl[0]+1);
838 }
839 
set_bit(int uartind,int line,int value)840 void ti_rs232_pio_device::set_bit(int uartind, int line, int value)
841 {
842 	switch (line)
843 	{
844 	case tms9902_device::CTS:
845 		LOGMASKED(LOG_LINES, "(RS232/%d) Set CTS(out)=%s\n", uartind+1, (value!=0)? "asserted" : "cleared");
846 		break;
847 	case tms9902_device::DCD:
848 		LOGMASKED(LOG_LINES, "(RS232/%d) Set DCD(out)=%s\n", uartind+1, (value!=0)? "asserted" : "cleared");
849 		break;
850 	case tms9902_device::BRK:
851 		LOGMASKED(LOG_LINES, "(RS232/%d) Set BRK(out)=%s\n", uartind+1, (value!=0)? "asserted" : "cleared");
852 		break;
853 	}
854 
855 	if (value!=0)
856 		m_signals[uartind] |= line;
857 	else
858 		m_signals[uartind] &= ~line;
859 }
860 
861 /*
862    Line changes
863 */
output_exception(int uartind,int param,uint8_t value)864 void ti_rs232_pio_device::output_exception(int uartind, int param, uint8_t value)
865 {
866 	ti_rs232_attached_device *serial = (uartind==0)? m_serdev0 : m_serdev1;
867 	uint8_t bufctrl[2];
868 	uint8_t esc = ESC;
869 
870 	if (!serial->exists())
871 	{
872 		LOGMASKED(LOG_CONFIG, "(RS232/%d) No serial output attached\n", uartind+1);
873 		return;
874 	}
875 
876 	serial->fwrite(&esc, 1);
877 
878 	bufctrl[0] = 1;
879 	// 0100 0xxv = exception xx: 02=BRK, 04=FRMERR, 06=PARERR; v=0,1 (only for BRK)
880 	// BRK is the only output exception
881 	bufctrl[1] = tms9902_device::EXCEPT | param | (value&1);
882 	serial->fwrite(bufctrl, 2);
883 }
884 
885 /*
886    Line changes
887 */
output_line_state(int uartind,int mask,uint8_t value)888 void ti_rs232_pio_device::output_line_state(int uartind, int mask, uint8_t value)
889 {
890 	ti_rs232_attached_device *serial = (uartind==0)? m_serdev0 : m_serdev1;
891 	uint8_t bufctrl[2];
892 	uint8_t esc = ESC;
893 
894 	if (!serial->exists())
895 	{
896 		LOGMASKED(LOG_CONFIG, "(RS232/%d) No serial output attached\n", uartind+1);
897 		return;
898 	}
899 
900 	// Send ESC to serial bridge
901 	// FIXME: When the socket cannot be set up, MAME crashes here
902 	serial->fwrite(&esc, 1);
903 
904 	// Length 1
905 	bufctrl[0] = 1;
906 
907 	// 01ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f
908 
909 	// The CTS line (coming from a CRU bit) is connected to the CTS pin
910 	if (mask & tms9902_device::CTS) set_bit(uartind, tms9902_device::CTS, value & tms9902_device::CTS);
911 
912 	// The RTS line (from 9902) is connected to the DCD pin
913 	if (mask & tms9902_device::RTS) set_bit(uartind, tms9902_device::DCD, value & tms9902_device::RTS);
914 
915 	// The DSR pin is hardwired to +5V
916 	set_bit(uartind, tms9902_device::DSR, 1);
917 
918 	// As of here, the lines are set according to the schematics of the
919 	// serial interface.
920 
921 	// Now translate the signals of the board to those of a DTE-like device
922 	// so that we can pass the signal to the real PC serial interface
923 	// (can be imagined as if we emulated the cable)
924 	bufctrl[1] = map_lines_out(uartind, m_signals[uartind]);
925 	serial->fwrite(bufctrl, 2);
926 }
927 
928 /***********************************************************************
929     callbacks
930 ************************************************************************/
931 /*
932     Propagates the /INT signal of the UARTs to the /INT line of the pbox.
933 */
WRITE_LINE_MEMBER(ti_rs232_pio_device::int0_callback)934 WRITE_LINE_MEMBER( ti_rs232_pio_device::int0_callback )
935 {
936 	int senila_bit = SENILA_0_BIT;
937 
938 	if (state==ASSERT_LINE) m_ila |= senila_bit;
939 	else m_ila &= ~senila_bit;
940 
941 	m_slot->set_inta(state);
942 }
943 
WRITE_LINE_MEMBER(ti_rs232_pio_device::int1_callback)944 WRITE_LINE_MEMBER( ti_rs232_pio_device::int1_callback )
945 {
946 	int senila_bit = SENILA_1_BIT;
947 
948 	if (state==ASSERT_LINE) m_ila |= senila_bit;
949 	else m_ila &= ~senila_bit;
950 
951 	m_slot->set_inta(state);
952 }
953 
954 /*
955     Called from the UART when it wants to receive a character
956     However, characters are not passed to it at this point
957     Instead, we check for signal line change or data transmission
958     and call the respective function
959 */
WRITE_LINE_MEMBER(ti_rs232_pio_device::rcv0_callback)960 WRITE_LINE_MEMBER( ti_rs232_pio_device::rcv0_callback )
961 {
962 	receive_data_or_line_state(0);
963 }
964 
WRITE_LINE_MEMBER(ti_rs232_pio_device::rcv1_callback)965 WRITE_LINE_MEMBER( ti_rs232_pio_device::rcv1_callback )
966 {
967 	receive_data_or_line_state(1);
968 }
969 
xmit0_callback(uint8_t data)970 void ti_rs232_pio_device::xmit0_callback(uint8_t data)
971 {
972 	transmit_data(0, data);
973 }
974 
xmit1_callback(uint8_t data)975 void ti_rs232_pio_device::xmit1_callback(uint8_t data)
976 {
977 	transmit_data(1, data);
978 }
979 
ctrl_callback(int uartind,int offset,uint8_t data)980 void ti_rs232_pio_device::ctrl_callback(int uartind, int offset, uint8_t data)
981 {
982 	if ((offset & tms9902_device::CONFIG)!=0)
983 	{
984 		// We cannot pass the configuration data as they need more than 8 bits.
985 		// Could be done by a write16 function as well.
986 		configure_interface(uartind, data, (uartind==0)? m_uart0->get_config_value() : m_uart1->get_config_value());
987 	}
988 	else
989 	{
990 		if ((offset & tms9902_device::EXCEPT)!=0)
991 		{
992 			output_exception(uartind, offset & ~tms9902_device::EXCEPT, data);
993 		}
994 		else
995 		{
996 			output_line_state(uartind, offset, data);
997 		}
998 	}
999 }
1000 
ctrl0_callback(offs_t offset,uint8_t data)1001 void ti_rs232_pio_device::ctrl0_callback(offs_t offset, uint8_t data)
1002 {
1003 	ctrl_callback(0, offset, data);
1004 }
1005 
ctrl1_callback(offs_t offset,uint8_t data)1006 void ti_rs232_pio_device::ctrl1_callback(offs_t offset, uint8_t data)
1007 {
1008 	ctrl_callback(1, offset, data);
1009 }
1010 
device_start()1011 void ti_rs232_pio_device::device_start()
1012 {
1013 	m_dsrrom = memregion(TI99_DSRROM)->base();
1014 
1015 	// Prepare the receive buffers
1016 	m_recvbuf[0] = std::make_unique<uint8_t[]>(512);
1017 	m_recvbuf[1] = std::make_unique<uint8_t[]>(512);
1018 
1019 	m_pio_write = true; // required for call_load of pio_attached_device
1020 	m_pio_writable = false;
1021 	m_pio_handshakein = false;
1022 
1023 	// We don't save the receive buffers for persistent state
1024 	save_pointer(NAME(m_signals),2);
1025 	save_pointer(NAME(m_recv_mode),2);
1026 	save_pointer(NAME(m_time_hold),2);
1027 	save_item(NAME(m_pio_direction_in));
1028 	save_item(NAME(m_pio_handshakeout));
1029 	save_item(NAME(m_pio_handshakein));
1030 	save_item(NAME(m_pio_spareout));
1031 	save_item(NAME(m_pio_sparein));
1032 	save_item(NAME(m_flag0));
1033 	save_item(NAME(m_led));
1034 	save_item(NAME(m_pio_out_buffer));
1035 	save_item(NAME(m_pio_in_buffer));
1036 	save_item(NAME(m_pio_readable));
1037 	save_item(NAME(m_pio_writable));
1038 	save_item(NAME(m_pio_write));
1039 	save_item(NAME(m_ila));
1040 }
1041 
device_stop()1042 void ti_rs232_pio_device::device_stop()
1043 {
1044 	m_recvbuf[0] = nullptr;
1045 	m_recvbuf[1] = nullptr;
1046 }
1047 
device_reset()1048 void ti_rs232_pio_device::device_reset()
1049 {
1050 	m_pio_direction_in = false;
1051 	m_pio_handshakeout = false;
1052 	m_pio_spareout = false;
1053 	m_flag0 = false;
1054 
1055 	set_bit(0, tms9902_device::CTS, 0);
1056 	set_bit(1, tms9902_device::CTS, 0);
1057 
1058 	m_led = false;
1059 	m_recv_mode[0] = RECV_MODE_NORMAL;
1060 	m_recv_mode[1] = RECV_MODE_NORMAL;
1061 
1062 	m_bufpos[0] = m_bufpos[1] = m_buflen[0] = m_buflen[1] = 0;
1063 
1064 	m_selected = false;
1065 
1066 	m_cru_base = (ioport("CRURS232")->read()==0)? 0x1300 : 0x1500;
1067 
1068 	m_time_hold[0] = m_time_hold[1] = 0.0;
1069 
1070 	// Both DTRs are pulled up
1071 	incoming_dtr(0, ASSERT_LINE);
1072 	incoming_dtr(1, ASSERT_LINE);
1073 }
1074 
1075 ROM_START( ti_rs232 )
1076 	ROM_REGION(0x1000, TI99_DSRROM, 0)
CRC(eab382fb)1077 	ROM_LOAD("rs232pio_dsr.u1", 0x0000, 0x1000, CRC(eab382fb) SHA1(ee609a18a21f1a3ddab334e8798d5f2a0fcefa91)) /* TI rs232 DSR ROM */
1078 ROM_END
1079 
1080 INPUT_PORTS_START( ti_rs232 )
1081 	PORT_START( "CRURS232"  )
1082 	PORT_DIPNAME( 0x01, 0x00, "TI-RS232 CRU base" )
1083 		PORT_DIPSETTING(    0x00, "1300" )
1084 		PORT_DIPSETTING(    0x01, "1500" )
1085 
1086 	PORT_START( "SERIALMAP" )
1087 	PORT_CONFNAME( 0x03, 0x00, "Serial cable pin mapping" )
1088 		PORT_CONFSETTING(    0x00, "6-20" )
1089 		PORT_CONFSETTING(    0x01, "8-20" )
1090 		PORT_CONFSETTING(    0x02, "5-20" )
1091 INPUT_PORTS_END
1092 
1093 void ti_rs232_pio_device::device_add_mconfig(machine_config &config)
1094 {
1095 	TMS9902(config, m_uart0, 3000000);
1096 	m_uart0->int_cb().set(FUNC(ti_rs232_pio_device::int0_callback));
1097 	m_uart0->rcv_cb().set(FUNC(ti_rs232_pio_device::rcv0_callback));
1098 	m_uart0->xmit_cb().set(FUNC(ti_rs232_pio_device::xmit0_callback));
1099 	m_uart0->ctrl_cb().set(FUNC(ti_rs232_pio_device::ctrl0_callback));
1100 	TMS9902(config, m_uart1, 3000000);
1101 	m_uart1->int_cb().set(FUNC(ti_rs232_pio_device::int1_callback));
1102 	m_uart1->rcv_cb().set(FUNC(ti_rs232_pio_device::rcv1_callback));
1103 	m_uart1->xmit_cb().set(FUNC(ti_rs232_pio_device::xmit1_callback));
1104 	m_uart1->ctrl_cb().set(FUNC(ti_rs232_pio_device::ctrl1_callback));
1105 	TI99_RS232_DEV(config, m_serdev0, 0);
1106 	m_serdev0->connect(m_uart0);
1107 	TI99_RS232_DEV(config, m_serdev1, 0);
1108 	m_serdev1->connect(m_uart1);
1109 
1110 	TI99_PIO_DEV(config, m_piodev, 0);
1111 
1112 	LS259(config, m_crulatch); // U12
1113 	m_crulatch->q_out_cb<0>().set(FUNC(ti_rs232_pio_device::selected_w));
1114 	m_crulatch->q_out_cb<1>().set(FUNC(ti_rs232_pio_device::pio_direction_in_w));
1115 	m_crulatch->q_out_cb<2>().set(FUNC(ti_rs232_pio_device::pio_handshake_out_w));
1116 	m_crulatch->q_out_cb<3>().set(FUNC(ti_rs232_pio_device::pio_spareout_w));
1117 	m_crulatch->q_out_cb<4>().set(FUNC(ti_rs232_pio_device::flag0_w));
1118 	m_crulatch->q_out_cb<5>().set(FUNC(ti_rs232_pio_device::cts0_w));
1119 	m_crulatch->q_out_cb<6>().set(FUNC(ti_rs232_pio_device::cts1_w));
1120 	m_crulatch->q_out_cb<7>().set(FUNC(ti_rs232_pio_device::led_w));
1121 }
1122 
device_rom_region() const1123 const tiny_rom_entry *ti_rs232_pio_device::device_rom_region() const
1124 {
1125 	return ROM_NAME( ti_rs232 );
1126 }
1127 
device_input_ports() const1128 ioport_constructor ti_rs232_pio_device::device_input_ports() const
1129 {
1130 	return INPUT_PORTS_NAME(ti_rs232);
1131 }
1132 
1133 } } } // end namespace bus::ti99::peb
1134