/********************************************************************** IEEE-488.1 General Purpose Interface Bus emulation (aka HP-IB, GPIB, CBM IEEE) Copyright MESS Team. Visit http://mamedev.org for licensing and usage restrictions. **********************************************************************/ #include "ieee488.h" //************************************************************************** // MACROS / CONSTANTS //************************************************************************** #define LOG 0 static const char *const SIGNAL_NAME[] = { "EOI", "DAV", "NRFD", "NDAC", "IFC", "SRQ", "ATN", "REN" }; //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** const device_type IEEE488 = &device_creator; const device_type IEEE488_SLOT = &device_creator; //************************************************************************** // DEVICE INTERFACE //************************************************************************** //------------------------------------------------- // device_ieee488_interface - constructor //------------------------------------------------- device_ieee488_interface::device_ieee488_interface(const machine_config &mconfig, device_t &device) : device_slot_card_interface(mconfig, device) { } //------------------------------------------------- // ~device_ieee488_interface - destructor //------------------------------------------------- device_ieee488_interface::~device_ieee488_interface() { } //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // ieee488_slot_device - constructor //------------------------------------------------- ieee488_slot_device::ieee488_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, IEEE488_SLOT, "IEEE-488 slot", tag, owner, clock), device_slot_interface(mconfig, *this) { } //------------------------------------------------- // static_set_slot - //------------------------------------------------- void ieee488_slot_device::static_set_slot(device_t &device, int address) { ieee488_slot_device &ieee488_card = dynamic_cast(device); ieee488_card.m_address = address; } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void ieee488_slot_device::device_start() { ieee488_device* bus = owner()->subdevice(IEEE488_TAG); device_ieee488_interface *dev = dynamic_cast(get_card_device()); if (dev) bus->add_device(get_card_device(), m_address); } //************************************************************************** // INLINE HELPERS //************************************************************************** //------------------------------------------------- // set_signal - //------------------------------------------------- inline void ieee488_device::set_signal(device_t *device, int signal, int state) { bool changed = false; if (device == this) { if (m_line[signal] != state) { if (LOG) logerror("%s IEEE488: '%s' %s %u\n", machine().describe_context(), tag(), SIGNAL_NAME[signal], state); m_line[signal] = state; changed = true; } } else { daisy_entry *entry = m_device_list.first(); while (entry) { if (!strcmp(entry->m_device->tag(), device->tag())) { if (entry->m_line[signal] != state) { if (LOG) logerror("%s IEEE488: '%s' %s %u\n", machine().describe_context(), device->tag(), SIGNAL_NAME[signal], state); entry->m_line[signal] = state; changed = true; } } entry = entry->next(); } } if (changed) { switch (signal) { case EOI: m_write_eoi(state); break; case DAV: m_write_dav(state); break; case NRFD: m_write_nrfd(state); break; case NDAC: m_write_ndac(state); break; case IFC: m_write_ifc(state); break; case SRQ: m_write_srq(state); break; case ATN: m_write_atn(state); break; case REN: m_write_ren(state); break; } daisy_entry *entry = m_device_list.first(); while (entry) { switch (signal) { case EOI: entry->m_interface->ieee488_eoi(state); break; case DAV: entry->m_interface->ieee488_dav(state); break; case NRFD: entry->m_interface->ieee488_nrfd(state); break; case NDAC: entry->m_interface->ieee488_ndac(state); break; case IFC: entry->m_interface->ieee488_ifc(state); break; case SRQ: entry->m_interface->ieee488_srq(state); break; case ATN: entry->m_interface->ieee488_atn(state); break; case REN: entry->m_interface->ieee488_ren(state); break; } entry = entry->next(); } if (LOG) logerror("IEEE488: EOI %u DAV %u NRFD %u NDAC %u IFC %u SRQ %u ATN %u REN %u DIO %02x\n", get_signal(EOI), get_signal(DAV), get_signal(NRFD), get_signal(NDAC), get_signal(IFC), get_signal(SRQ), get_signal(ATN), get_signal(REN), get_data()); } } //------------------------------------------------- // get_signal - //------------------------------------------------- inline int ieee488_device::get_signal(int signal) { int state = m_line[signal]; if (state) { daisy_entry *entry = m_device_list.first(); while (entry) { if (!entry->m_line[signal]) { state = 0; break; } entry = entry->next(); } } return state; } //------------------------------------------------- // set_data - //------------------------------------------------- inline void ieee488_device::set_data(device_t *device, UINT8 data) { if (device == this) { if (LOG) logerror("%s IEEE488: '%s' DIO %02x\n", machine().describe_context(), tag(), data); m_dio = data; } else { daisy_entry *entry = m_device_list.first(); while (entry) { if (!strcmp(entry->m_device->tag(), device->tag())) { if (entry->m_dio != data) { if (LOG) logerror("%s IEEE488: '%s' DIO %02x\n", machine().describe_context(), device->tag(), data); entry->m_dio = data; } } entry = entry->next(); } } } //------------------------------------------------- // get_data - //------------------------------------------------- inline UINT8 ieee488_device::get_data() { UINT8 data = m_dio; daisy_entry *entry = m_device_list.first(); while (entry) { data &= entry->m_dio; entry = entry->next(); } return data; } //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // ieee488_device - constructor //------------------------------------------------- ieee488_device::ieee488_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, IEEE488, "IEEE488 bus", tag, owner, clock), m_write_eoi(*this), m_write_dav(*this), m_write_nrfd(*this), m_write_ndac(*this), m_write_ifc(*this), m_write_srq(*this), m_write_atn(*this), m_write_ren(*this), m_dio(0xff) { for (int i = 0; i < SIGNAL_COUNT; i++) { m_line[i] = 1; } } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void ieee488_device::device_start() { // resolve callbacks m_write_eoi.resolve_safe(); m_write_dav.resolve_safe(); m_write_nrfd.resolve_safe(); m_write_ndac.resolve_safe(); m_write_ifc.resolve_safe(); m_write_srq.resolve_safe(); m_write_atn.resolve_safe(); m_write_ren.resolve_safe(); } //------------------------------------------------- // device_stop - device-specific stop //------------------------------------------------- void ieee488_device::device_stop() { m_device_list.reset(); } //------------------------------------------------- // add_device - //------------------------------------------------- void ieee488_device::add_device(device_t *target, int address) { daisy_entry *entry = auto_alloc(machine(), daisy_entry(target)); entry->m_interface->m_bus = this; entry->m_interface->m_address = address; m_device_list.append(*entry); } //------------------------------------------------- // daisy_entry - constructor //------------------------------------------------- ieee488_device::daisy_entry::daisy_entry(device_t *device) : m_next(NULL), m_device(device), m_interface(NULL), m_dio(0xff) { for (int i = 0; i < SIGNAL_COUNT; i++) { m_line[i] = 1; } device->interface(m_interface); } //------------------------------------------------- // dio_r - //------------------------------------------------- UINT8 ieee488_device::dio_r() { return get_data(); } //------------------------------------------------- // dio_r - //------------------------------------------------- READ8_MEMBER( ieee488_device::dio_r ) { return get_data(); } //------------------------------------------------- // eoi_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::eoi_r ) { return get_signal(EOI); } //------------------------------------------------- // dav_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::dav_r ) { return get_signal(DAV); } //------------------------------------------------- // nrfd_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::nrfd_r ) { return get_signal(NRFD); } //------------------------------------------------- // ndac_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::ndac_r ) { return get_signal(NDAC); } //------------------------------------------------- // ifc_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::ifc_r ) { return get_signal(IFC); } //------------------------------------------------- // srq_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::srq_r ) { return get_signal(SRQ); } //------------------------------------------------- // atn_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::atn_r ) { return get_signal(ATN); } //------------------------------------------------- // ren_r - //------------------------------------------------- READ_LINE_MEMBER( ieee488_device::ren_r ) { return get_signal(REN); } //------------------------------------------------- // dio_w - //------------------------------------------------- void ieee488_device::dio_w(UINT8 data) { return set_data(this, data); } //------------------------------------------------- // dio_w - //------------------------------------------------- WRITE8_MEMBER( ieee488_device::dio_w ) { return set_data(this, data); } //------------------------------------------------- // eoi_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::eoi_w ) { set_signal(this, EOI, state); } //------------------------------------------------- // dav_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::dav_w ) { set_signal(this, DAV, state); } //------------------------------------------------- // nrfd_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::nrfd_w ) { set_signal(this, NRFD, state); } //------------------------------------------------- // ndac_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::ndac_w ) { set_signal(this, NDAC, state); } //------------------------------------------------- // ifc_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::ifc_w ) { set_signal(this, IFC, state); } //------------------------------------------------- // srq_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::srq_w ) { set_signal(this, SRQ, state); } //------------------------------------------------- // atn_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::atn_w ) { set_signal(this, ATN, state); } //------------------------------------------------- // ren_w - //------------------------------------------------- WRITE_LINE_MEMBER( ieee488_device::ren_w ) { set_signal(this, REN, state); } //------------------------------------------------- // dio_w - //------------------------------------------------- void ieee488_device::dio_w(device_t *device, UINT8 data) { return set_data(device, data); } //------------------------------------------------- // eoi_w - //------------------------------------------------- void ieee488_device::eoi_w(device_t *device, int state) { set_signal(device, EOI, state); } //------------------------------------------------- // dav_w - //------------------------------------------------- void ieee488_device::dav_w(device_t *device, int state) { set_signal(device, DAV, state); } //------------------------------------------------- // nrfd_w - //------------------------------------------------- void ieee488_device::nrfd_w(device_t *device, int state) { set_signal(device, NRFD, state); } //------------------------------------------------- // ndac_w - //------------------------------------------------- void ieee488_device::ndac_w(device_t *device, int state) { set_signal(device, NDAC, state); } //------------------------------------------------- // ifc_w - //------------------------------------------------- void ieee488_device::ifc_w(device_t *device, int state) { set_signal(device, IFC, state); } //------------------------------------------------- // srq_w - //------------------------------------------------- void ieee488_device::srq_w(device_t *device, int state) { set_signal(device, SRQ, state); } //------------------------------------------------- // atn_w - //------------------------------------------------- void ieee488_device::atn_w(device_t *device, int state) { set_signal(device, ATN, state); } //------------------------------------------------- // ren_w - //------------------------------------------------- void ieee488_device::ren_w(device_t *device, int state) { set_signal(device, REN, state); }