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