1 // license:BSD-3-Clause
2 // copyright-holders: F. Ulivi
3 /*********************************************************************
4 
5     82919.cpp
6 
7     82919 module (RS232 interface)
8 
9     Main reference for this module is:
10     HP 82919-90009, feb 85, HP82919A Integral PC Serial Interface -
11     Component level service manual
12 
13 *********************************************************************/
14 
15 #include "emu.h"
16 #include "82919.h"
17 #include "coreutil.h"
18 
19 // Debugging
20 #define VERBOSE 0
21 #include "logmacro.h"
22 
23 // Bit manipulation
24 namespace {
BIT_MASK(unsigned n)25 	template<typename T> constexpr T BIT_MASK(unsigned n)
26 	{
27 		return (T)1U << n;
28 	}
29 
BIT_SET(T & w,unsigned n)30 	template<typename T> void BIT_SET(T& w , unsigned n)
31 	{
32 		w |= BIT_MASK<T>(n);
33 	}
34 }
35 
hp82919_io_card_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)36 hp82919_io_card_device::hp82919_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
37 	: device_t(mconfig , HP82919_IO_CARD , tag , owner , clock)
38 	, device_hp_ipc_io_interface(mconfig, *this)
39 	, m_rs232_prim(*this , "rs232_prim")
40 	, m_rs232_sec(*this , "rs232_sec")
41 	, m_uart(*this , "uart")
42 	, m_loopback_en(*this, "loop")
43 {
44 }
45 
~hp82919_io_card_device()46 hp82919_io_card_device::~hp82919_io_card_device()
47 {
48 }
49 
read(offs_t addr)50 uint8_t hp82919_io_card_device::read(offs_t addr)
51 {
52 	uint8_t res = 0;
53 	offs_t uart_addr = (addr ^ 0xc) & 0xf;
54 
55 	if (BIT(addr , 4)) {
56 		res = m_uart->read(uart_addr);
57 	} else {
58 		// 2 is 82919 ID code
59 		res = 2;
60 		res |= (m_int_level << 4);
61 		if (m_int_pending) {
62 			BIT_SET(res , 6);
63 		}
64 		if (m_int_en) {
65 			BIT_SET(res , 7);
66 		}
67 		m_uart->write(uart_addr , res);
68 	}
69 	LOG("RD %04x=%02x\n" , addr , res);
70 	return res;
71 }
72 
write(offs_t addr,uint8_t data)73 void hp82919_io_card_device::write(offs_t addr , uint8_t data)
74 {
75 	LOG("WR %04x=%02x\n" , addr , data);
76 	offs_t uart_addr = (addr ^ 0xc) & 0xf;
77 	m_uart->write(uart_addr , data);
78 	if (!BIT(addr , 4)) {
79 		m_int_level = (data >> 4) & 3;
80 		m_int_forced = BIT(data , 6);
81 		m_int_en = BIT(data , 7);
82 		update_irq();
83 	}
84 }
85 
WRITE_LINE_MEMBER(hp82919_io_card_device::uart_irq)86 WRITE_LINE_MEMBER(hp82919_io_card_device::uart_irq)
87 {
88 	m_uart_int = state;
89 	update_irq();
90 }
91 
WRITE_LINE_MEMBER(hp82919_io_card_device::uart_a_tx)92 WRITE_LINE_MEMBER(hp82919_io_card_device::uart_a_tx)
93 {
94 	m_rs232_prim->write_txd(state);
95 	if (m_loopback) {
96 		m_uart->rx_b_w(state);
97 	}
98 }
99 
WRITE_LINE_MEMBER(hp82919_io_card_device::uart_b_tx)100 WRITE_LINE_MEMBER(hp82919_io_card_device::uart_b_tx)
101 {
102 	m_rs232_sec->write_txd(state);
103 	if (m_loopback) {
104 		m_uart->rx_a_w(state);
105 	}
106 }
107 
uart_output(uint8_t data)108 void hp82919_io_card_device::uart_output(uint8_t data)
109 {
110 	m_rs232_prim->write_dtr(BIT(data , 0));
111 	m_rs232_prim->write_rts(BIT(data , 1));
112 	// b2 is TxClock
113 	m_rs232_prim->write_spds(BIT(data , 3));
114 	m_rs232_sec->write_rts(BIT(data , 4));
115 	if (m_loopback) {
116 		m_uart->ip0_w(BIT(data , 0));
117 		m_uart->ip1_w(BIT(data , 1));
118 		m_uart->ip2_w(BIT(data , 2));
119 		m_uart->ip3_w(BIT(data , 3));
120 		m_uart->ip4_w(BIT(data , 4));
121 		m_uart->ip5_w(BIT(data , 4));
122 	}
123 }
124 
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_rxd)125 WRITE_LINE_MEMBER(hp82919_io_card_device::prim_rxd)
126 {
127 	if (!m_loopback) {
128 		m_uart->rx_a_w(state);
129 	}
130 }
131 
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dcd)132 WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dcd)
133 {
134 	if (!m_loopback) {
135 		m_uart->ip3_w(state);
136 	}
137 }
138 
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dsr)139 WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dsr)
140 {
141 	if (!m_loopback) {
142 		m_uart->ip1_w(state);
143 	}
144 }
145 
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_ri)146 WRITE_LINE_MEMBER(hp82919_io_card_device::prim_ri)
147 {
148 	if (!m_loopback) {
149 		m_uart->ip2_w(state);
150 	}
151 }
152 
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_cts)153 WRITE_LINE_MEMBER(hp82919_io_card_device::prim_cts)
154 {
155 	if (!m_loopback) {
156 		m_uart->ip0_w(state);
157 	}
158 }
159 
WRITE_LINE_MEMBER(hp82919_io_card_device::sec_rxd)160 WRITE_LINE_MEMBER(hp82919_io_card_device::sec_rxd)
161 {
162 	if (!m_loopback) {
163 		m_uart->rx_b_w(state);
164 	}
165 }
166 
WRITE_LINE_MEMBER(hp82919_io_card_device::sec_dcd)167 WRITE_LINE_MEMBER(hp82919_io_card_device::sec_dcd)
168 {
169 	if (!m_loopback) {
170 		m_uart->ip5_w(state);
171 	}
172 }
173 
WRITE_LINE_MEMBER(hp82919_io_card_device::sec_cts)174 WRITE_LINE_MEMBER(hp82919_io_card_device::sec_cts)
175 {
176 	if (!m_loopback) {
177 		m_uart->ip4_w(state);
178 	}
179 }
180 
install_read_write_handlers(address_space & space,uint32_t base_addr)181 void hp82919_io_card_device::install_read_write_handlers(address_space& space , uint32_t base_addr)
182 {
183 	offs_t end_addr = base_addr + 0xffffU;
184 
185 	// Supervisor mode
186 	space.install_readwrite_handler(base_addr, end_addr, read8sm_delegate(*this, FUNC(hp82919_io_card_device::read)), write8sm_delegate(*this, FUNC(hp82919_io_card_device::write)), 0x00ff);
187 	// User mode
188 	space.install_readwrite_handler(base_addr + USER_SPACE_OFFSET, end_addr + USER_SPACE_OFFSET, read8sm_delegate(*this, FUNC(hp82919_io_card_device::read)), write8sm_delegate(*this, FUNC(hp82919_io_card_device::write)), 0x00ff);
189 }
190 
device_start()191 void hp82919_io_card_device::device_start()
192 {
193 }
194 
device_reset()195 void hp82919_io_card_device::device_reset()
196 {
197 	m_loopback = m_loopback_en->read() != 0;
198 	m_int_level = 0;
199 	m_int_forced = false;
200 	m_int_en = false;
201 	m_uart_int = false;
202 	m_irq = true;
203 	update_irq();
204 }
205 
device_add_mconfig(machine_config & config)206 void hp82919_io_card_device::device_add_mconfig(machine_config &config)
207 {
208 	RS232_PORT(config, m_rs232_prim, default_rs232_devices, nullptr);
209 	RS232_PORT(config, m_rs232_sec, default_rs232_devices, nullptr);
210 
211 	MC68681(config , m_uart , 3.6864_MHz_XTAL);
212 	m_uart->irq_cb().set(FUNC(hp82919_io_card_device::uart_irq));
213 	m_uart->a_tx_cb().set(FUNC(hp82919_io_card_device::uart_a_tx));
214 	m_uart->b_tx_cb().set(FUNC(hp82919_io_card_device::uart_b_tx));
215 	m_uart->outport_cb().set(FUNC(hp82919_io_card_device::uart_output));
216 
217 	m_rs232_prim->rxd_handler().set(FUNC(hp82919_io_card_device::prim_rxd));
218 	m_rs232_prim->dcd_handler().set(FUNC(hp82919_io_card_device::prim_dcd));
219 	m_rs232_prim->dsr_handler().set(FUNC(hp82919_io_card_device::prim_dsr));
220 	m_rs232_prim->ri_handler().set(FUNC(hp82919_io_card_device::prim_ri));
221 	m_rs232_prim->cts_handler().set(FUNC(hp82919_io_card_device::prim_cts));
222 
223 	m_rs232_sec->rxd_handler().set(FUNC(hp82919_io_card_device::sec_rxd));
224 	m_rs232_sec->dcd_handler().set(FUNC(hp82919_io_card_device::sec_dcd));
225 	m_rs232_sec->cts_handler().set(FUNC(hp82919_io_card_device::sec_cts));
226 }
227 
228 static INPUT_PORTS_START(hp82919_port)
229 	PORT_START("loop")
230 	PORT_CONFNAME(1 , 0 , "Test loopback")
DEF_STR(Off)231 	PORT_CONFSETTING(0 , DEF_STR(Off))
232 	PORT_CONFSETTING(1 , DEF_STR(On))
233 INPUT_PORTS_END
234 
235 ioport_constructor hp82919_io_card_device::device_input_ports() const
236 {
237 	return INPUT_PORTS_NAME(hp82919_port);
238 }
239 
update_irq()240 void hp82919_io_card_device::update_irq()
241 {
242 	m_int_pending = m_int_forced || m_uart_int;
243 	bool irq = m_int_en && m_int_pending;
244 	if (m_irq != irq) {
245 		m_irq = irq;
246 		LOG("IRQ %u=%d\n" , m_int_level , irq);
247 		irq_w(m_int_level , irq);
248 	}
249 }
250 
251 // device type definition
252 DEFINE_DEVICE_TYPE(HP82919_IO_CARD, hp82919_io_card_device, "hp82919", "HP82919 card")
253