1 // license:BSD-3-Clause
2 // copyright-holders: F. Ulivi
3 /*********************************************************************
4 
5     82937.cpp
6 
7     82937 module (HPIB interface)
8 
9     TODO: Implement Parallel Poll response
10 
11     Thanks to Tim Nye & Everett Kaser for dumping the 8049 ROM
12 
13     Main reference for this module is:
14     HP 82937-90007, oct 80, HP82937A HP-IB Installation and theory
15     of operation manual
16 
17 *********************************************************************/
18 
19 #include "emu.h"
20 #include "82937.h"
21 #include "coreutil.h"
22 
23 // Debugging
24 #define VERBOSE 0
25 #include "logmacro.h"
26 
27 // Bit manipulation
28 namespace {
BIT_MASK(unsigned n)29 	template<typename T> constexpr T BIT_MASK(unsigned n)
30 	{
31 		return (T)1U << n;
32 	}
33 
BIT_SET(T & w,unsigned n)34 	template<typename T> void BIT_SET(T& w , unsigned n)
35 	{
36 		w |= BIT_MASK<T>(n);
37 	}
38 }
39 
40 // Bits in U3 (m_latch)
41 constexpr unsigned LATCH_CA_BIT = 5; // Controller Active
42 constexpr unsigned LATCH_TA_BIT = 4; // Talker Active
43 constexpr unsigned LATCH_EN_IFC_INT_BIT = 3; // Enable IFC interrupt
44 constexpr unsigned LATCH_EN_REN_INT_BIT = 2; // Enable REN interrupt
45 constexpr unsigned LATCH_EN_ATN_INT_BIT = 1; // Enable ATN interrupt
46 constexpr unsigned LATCH_EN_NDAC_BIT = 0;    // Enable NDAC
47 
48 // Bits on P1 port of 8049
49 constexpr unsigned P1_IFC_BIT = 7;
50 constexpr unsigned P1_REN_BIT = 6;
51 constexpr unsigned P1_SRQ_BIT = 5;
52 constexpr unsigned P1_ATN_BIT = 4;
53 constexpr unsigned P1_EOI_BIT = 3;
54 constexpr unsigned P1_DAV_BIT = 2;
55 constexpr unsigned P1_NDAC_BIT = 1;
56 constexpr unsigned P1_NRFD_BIT = 0;
57 
hp82937_io_card_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)58 hp82937_io_card_device::hp82937_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
59 	: device_t(mconfig , HP82937_IO_CARD , tag , owner , clock),
60 	  device_hp80_io_interface(mconfig, *this),
61 	  m_cpu(*this , "cpu"),
62 	  m_translator(*this , "xlator"),
63 	  m_sw1(*this , "sw1"),
64 	  m_ieee488(*this , IEEE488_TAG)
65 {
66 }
67 
~hp82937_io_card_device()68 hp82937_io_card_device::~hp82937_io_card_device()
69 {
70 }
71 
install_read_write_handlers(address_space & space,uint16_t base_addr)72 void hp82937_io_card_device::install_read_write_handlers(address_space& space , uint16_t base_addr)
73 {
74 	space.install_readwrite_handler(base_addr, base_addr + 1, read8sm_delegate(*m_translator, FUNC(hp_1mb5_device::cpu_r)), write8sm_delegate(*m_translator, FUNC(hp_1mb5_device::cpu_w)));
75 }
76 
inten()77 void hp82937_io_card_device::inten()
78 {
79 	m_translator->inten();
80 }
81 
clear_service()82 void hp82937_io_card_device::clear_service()
83 {
84 	m_translator->clear_service();
85 }
86 
WRITE_LINE_MEMBER(hp82937_io_card_device::reset_w)87 WRITE_LINE_MEMBER(hp82937_io_card_device::reset_w)
88 {
89 	m_cpu->set_input_line(INPUT_LINE_RESET , state);
90 	if (state) {
91 		// When reset is asserted, clear state
92 		device_reset();
93 	}
94 }
95 
READ_LINE_MEMBER(hp82937_io_card_device::t0_r)96 READ_LINE_MEMBER(hp82937_io_card_device::t0_r)
97 {
98 	return m_iatn;
99 }
100 
p1_r()101 uint8_t hp82937_io_card_device::p1_r()
102 {
103 	uint8_t res = 0;
104 
105 	if (BIT(m_sw1->read() , 5)) {
106 		// System controller
107 		BIT_SET(res , P1_IFC_BIT);
108 		BIT_SET(res , P1_REN_BIT);
109 	} else {
110 		// Not system controller
111 		if (m_ieee488->ifc_r()) {
112 			BIT_SET(res , P1_IFC_BIT);
113 		}
114 		if (m_ieee488->ren_r()) {
115 			BIT_SET(res , P1_REN_BIT);
116 		}
117 	}
118 	if (!BIT(m_latch , LATCH_CA_BIT) || m_ieee488->srq_r()) {
119 		BIT_SET(res , P1_SRQ_BIT);
120 	}
121 	if (m_iatn) {
122 		BIT_SET(res , P1_ATN_BIT);
123 	}
124 	bool ndac = !BIT(m_latch , LATCH_EN_NDAC_BIT) || m_iatn;
125 	if (m_talker_out) {
126 		BIT_SET(res , P1_EOI_BIT);
127 		BIT_SET(res , P1_DAV_BIT);
128 		if (ndac && m_ieee488->ndac_r()) {
129 			BIT_SET(res , P1_NDAC_BIT);
130 		}
131 		if (m_ieee488->nrfd_r()) {
132 			BIT_SET(res , P1_NRFD_BIT);
133 		}
134 	} else {
135 		if (m_ieee488->eoi_r()) {
136 			BIT_SET(res , P1_EOI_BIT);
137 		}
138 		if (m_ieee488->dav_r()) {
139 			BIT_SET(res , P1_DAV_BIT);
140 		}
141 		if (ndac) {
142 			BIT_SET(res , P1_NDAC_BIT);
143 		}
144 		BIT_SET(res , P1_NRFD_BIT);
145 	}
146 
147 	return res;
148 }
149 
p1_w(uint8_t data)150 void hp82937_io_card_device::p1_w(uint8_t data)
151 {
152 	update_signals();
153 	update_data_out();
154 }
155 
dio_r()156 uint8_t hp82937_io_card_device::dio_r()
157 {
158 	if (m_dio_out) {
159 		return 0xff;
160 	} else {
161 		return m_ieee488->dio_r();
162 	}
163 }
164 
dio_w(uint8_t data)165 void hp82937_io_card_device::dio_w(uint8_t data)
166 {
167 	update_data_out();
168 }
169 
switch_r()170 uint8_t hp82937_io_card_device::switch_r()
171 {
172 	return m_sw1->read() | 0xc0;
173 }
174 
latch_w(uint8_t data)175 void hp82937_io_card_device::latch_w(uint8_t data)
176 {
177 	LOG("latch=%02x\n" , data);
178 	m_latch = data;
179 	update_signals();
180 	update_data_out();
181 }
182 
WRITE_LINE_MEMBER(hp82937_io_card_device::ieee488_ctrl_w)183 WRITE_LINE_MEMBER(hp82937_io_card_device::ieee488_ctrl_w)
184 {
185 	update_signals();
186 	update_data_out();
187 }
188 
189 static INPUT_PORTS_START(hp82937_port)
190 	PORT_HP80_IO_SC(7)
191 	PORT_START("sw1")
192 	PORT_DIPNAME(0x1f , 0x15 , "HPIB address")
193 	PORT_DIPLOCATION("S1:7,6,5,4,3")
194 	PORT_DIPSETTING(0x00 , "0")
195 	PORT_DIPSETTING(0x01 , "1")
196 	PORT_DIPSETTING(0x02 , "2")
197 	PORT_DIPSETTING(0x03 , "3")
198 	PORT_DIPSETTING(0x04 , "4")
199 	PORT_DIPSETTING(0x05 , "5")
200 	PORT_DIPSETTING(0x06 , "6")
201 	PORT_DIPSETTING(0x07 , "7")
202 	PORT_DIPSETTING(0x08 , "8")
203 	PORT_DIPSETTING(0x09 , "9")
204 	PORT_DIPSETTING(0x0a , "10")
205 	PORT_DIPSETTING(0x0b , "11")
206 	PORT_DIPSETTING(0x0c , "12")
207 	PORT_DIPSETTING(0x0d , "13")
208 	PORT_DIPSETTING(0x0e , "14")
209 	PORT_DIPSETTING(0x0f , "15")
210 	PORT_DIPSETTING(0x10 , "16")
211 	PORT_DIPSETTING(0x11 , "17")
212 	PORT_DIPSETTING(0x12 , "18")
213 	PORT_DIPSETTING(0x13 , "19")
214 	PORT_DIPSETTING(0x14 , "20")
215 	PORT_DIPSETTING(0x15 , "21")
216 	PORT_DIPSETTING(0x16 , "22")
217 	PORT_DIPSETTING(0x17 , "23")
218 	PORT_DIPSETTING(0x18 , "24")
219 	PORT_DIPSETTING(0x19 , "25")
220 	PORT_DIPSETTING(0x1a , "26")
221 	PORT_DIPSETTING(0x1b , "27")
222 	PORT_DIPSETTING(0x1c , "28")
223 	PORT_DIPSETTING(0x1d , "29")
224 	PORT_DIPSETTING(0x1e , "30")
225 	PORT_DIPSETTING(0x1f , "31")
226 	PORT_DIPNAME(0x20 , 0x20 , "Sys. controller")
227 	PORT_DIPLOCATION("S1:2")
DEF_STR(Off)228 	PORT_DIPSETTING(0x00 , DEF_STR(Off))
229 	PORT_DIPSETTING(0x20 , DEF_STR(On))
230 INPUT_PORTS_END
231 
232 ioport_constructor hp82937_io_card_device::device_input_ports() const
233 {
234 	return INPUT_PORTS_NAME(hp82937_port);
235 }
236 
device_start()237 void hp82937_io_card_device::device_start()
238 {
239 	save_item(NAME(m_dio_out));
240 	save_item(NAME(m_talker_out));
241 	save_item(NAME(m_iatn));
242 	save_item(NAME(m_latch));
243 }
244 
device_reset()245 void hp82937_io_card_device::device_reset()
246 {
247 	m_latch = 0;
248 	m_updating = false;
249 	update_signals();
250 	update_data_out();
251 }
252 
update_data_out()253 void hp82937_io_card_device::update_data_out()
254 {
255 	m_ieee488->host_dio_w(m_dio_out ? m_cpu->p2_r() : 0xff);
256 }
257 
update_signals()258 void hp82937_io_card_device::update_signals()
259 {
260 	// Avoid recursive re-enter when writing to IEEE488 signals
261 	if (m_updating) {
262 		return;
263 	}
264 	m_updating = true;
265 	bool ctrl_active = BIT(m_latch , LATCH_CA_BIT);
266 	uint8_t p1 = m_cpu->p1_r();
267 	m_iatn = BIT(p1 , P1_ATN_BIT);
268 	if (ctrl_active) {
269 		m_ieee488->host_atn_w(m_iatn);
270 		m_ieee488->host_srq_w(1);
271 	} else {
272 		m_ieee488->host_atn_w(1);
273 		m_iatn = m_iatn && m_ieee488->atn_r();
274 		m_ieee488->host_srq_w(BIT(p1 , P1_SRQ_BIT));
275 	}
276 	m_talker_out = (ctrl_active && !m_iatn) || (BIT(m_latch , LATCH_TA_BIT) && m_iatn);
277 	if (m_talker_out) {
278 		m_ieee488->host_nrfd_w(1);
279 		m_ieee488->host_dav_w(BIT(p1 , P1_DAV_BIT));
280 		m_ieee488->host_eoi_w(BIT(p1 , P1_EOI_BIT));
281 		m_ieee488->host_ndac_w(1);
282 
283 	} else {
284 		m_ieee488->host_nrfd_w(BIT(p1 , P1_NRFD_BIT));
285 		m_ieee488->host_dav_w(1);
286 		m_ieee488->host_eoi_w(1);
287 		bool ndac = BIT(p1 , P1_NDAC_BIT);
288 		if (BIT(m_latch , LATCH_EN_NDAC_BIT) && !m_iatn) {
289 			ndac = false;
290 		}
291 		m_ieee488->host_ndac_w(ndac);
292 	}
293 	bool iren = BIT(p1 , P1_REN_BIT);
294 	if (BIT(m_sw1->read() , 5)) {
295 		// System controller
296 		m_ieee488->host_ren_w(iren);
297 		m_ieee488->host_ifc_w(BIT(p1 , P1_IFC_BIT));
298 	} else {
299 		// Not system controller
300 		m_ieee488->host_ren_w(1);
301 		iren = iren && m_ieee488->ren_r();
302 		m_ieee488->host_ifc_w(1);
303 	}
304 	bool not_u8_1 = m_iatn || m_ieee488->eoi_r();
305 	m_dio_out = not_u8_1 && m_talker_out;
306 	bool irq = (BIT(m_latch , LATCH_EN_IFC_INT_BIT) && !m_ieee488->ifc_r()) ||
307 		(BIT(m_latch , LATCH_EN_REN_INT_BIT) && iren) ||
308 		(BIT(m_latch , LATCH_EN_ATN_INT_BIT) && !m_iatn);
309 	m_cpu->set_input_line(MCS48_INPUT_IRQ , irq);
310 	m_updating = false;
311 }
312 
313 ROM_START(hp82937)
314 	ROM_REGION(0x800 , "cpu" , 0)
315 	ROM_LOAD("1820-2437.bin" , 0 , 0x800 , CRC(687d1559) SHA1(44dfc8c3f431cd37a270b094f1db751214009214))
316 ROM_END
317 
cpu_io_map(address_map & map)318 void hp82937_io_card_device::cpu_io_map(address_map &map)
319 {
320 	map.unmap_value_high();
321 	map(0x00, 0x01).rw("xlator", FUNC(hp_1mb5_device::uc_r), FUNC(hp_1mb5_device::uc_w));
322 	map(0x03, 0x03).rw(FUNC(hp82937_io_card_device::switch_r), FUNC(hp82937_io_card_device::latch_w));
323 }
324 
device_rom_region() const325 const tiny_rom_entry *hp82937_io_card_device::device_rom_region() const
326 {
327 	return ROM_NAME(hp82937);
328 }
329 
device_add_mconfig(machine_config & config)330 void hp82937_io_card_device::device_add_mconfig(machine_config &config)
331 {
332 	I8049(config, m_cpu, XTAL(11'000'000));
333 	m_cpu->set_addrmap(AS_IO, &hp82937_io_card_device::cpu_io_map);
334 	m_cpu->t0_in_cb().set(FUNC(hp82937_io_card_device::t0_r));
335 	m_cpu->t1_in_cb().set("xlator", FUNC(hp_1mb5_device::int_r));
336 	m_cpu->p1_in_cb().set(FUNC(hp82937_io_card_device::p1_r));
337 	m_cpu->p1_out_cb().set(FUNC(hp82937_io_card_device::p1_w));
338 	m_cpu->p2_in_cb().set(FUNC(hp82937_io_card_device::dio_r));
339 	m_cpu->p2_out_cb().set(FUNC(hp82937_io_card_device::dio_w));
340 
341 	HP_1MB5(config, m_translator, 0);
342 	m_translator->irl_handler().set(FUNC(hp82937_io_card_device::irl_w));
343 	m_translator->halt_handler().set(FUNC(hp82937_io_card_device::halt_w));
344 	m_translator->reset_handler().set(FUNC(hp82937_io_card_device::reset_w));
345 
346 	ieee488_slot_device &ieee_dev(IEEE488_SLOT(config, "ieee_dev", 0));
347 	hp_ieee488_devices(ieee_dev);
348 	ieee488_slot_device &ieee_rem(IEEE488_SLOT(config, "ieee_rem", 0));
349 	remote488_devices(ieee_rem);
350 
351 	IEEE488(config, m_ieee488, 0);
352 	m_ieee488->ifc_callback().set(FUNC(hp82937_io_card_device::ieee488_ctrl_w));
353 	m_ieee488->atn_callback().set(FUNC(hp82937_io_card_device::ieee488_ctrl_w));
354 	m_ieee488->ren_callback().set(FUNC(hp82937_io_card_device::ieee488_ctrl_w));
355 	m_ieee488->eoi_callback().set(FUNC(hp82937_io_card_device::ieee488_ctrl_w));
356 }
357 
358 // device type definition
359 DEFINE_DEVICE_TYPE(HP82937_IO_CARD, hp82937_io_card_device, "hp82937", "HP82937 card")
360