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