diff options
Diffstat (limited to 'src/devices/bus/ieee488/grid2102.cpp')
-rw-r--r-- | src/devices/bus/ieee488/grid2102.cpp | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/devices/bus/ieee488/grid2102.cpp b/src/devices/bus/ieee488/grid2102.cpp new file mode 100644 index 00000000000..4e6bc92c391 --- /dev/null +++ b/src/devices/bus/ieee488/grid2102.cpp @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:usernameak +/********************************************************************** + + GRiD 2102 Portable Floppy emulation + + http://deltacxx.insomnia247.nl/gridcompass/disk_info.txt for some protocol info + http://deltacxx.insomnia247.nl/gridcompass/fdd_boards.jpg for floppy drive boards photo + +**********************************************************************/ + +#include "emu.h" +#include "grid2102.h" + +// device type definition +DEFINE_DEVICE_TYPE(GRID2102, grid2102_device, "grid2102", "GRID2102") +DEFINE_DEVICE_TYPE(GRID2101_FLOPPY, grid2101_floppy_device, "grid2101_floppy", "GRID2101_FLOPPY") +DEFINE_DEVICE_TYPE(GRID2101_HDD, grid2101_hdd_device, "grid2101_hdd", "GRID2101_HDD") + +#define LOG_BYTES_MASK (LOG_GENERAL << 1) +#define LOG_BYTES(...) LOGMASKED(LOG_BYTES_MASK, __VA_ARGS__) +#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +#define GRID2102_FETCH32(Array, Offset) ((uint32_t)(\ + (Array[Offset] << 0) |\ + (Array[Offset + 1] << 8) |\ + (Array[Offset + 2] << 16) |\ + (Array[Offset + 3] << 24)\ +)) + +#define GRID2102_FETCH16(Array, Offset) ((uint16_t)(\ + (Array[Offset] << 0) |\ + (Array[Offset + 1] << 8)\ +)) + +#define GRID2101_HARDDISK_DEV_ADDR 4 +#define GRID2102_DEV_ADDR 6 + +#define GRID210X_GPIB_STATE_IDLE 0 +#define GRID210X_GPIB_STATE_WAIT_DAV_FALSE 1 +#define GRID210X_GPIB_STATE_SEND_DATA_START 2 +#define GRID210X_GPIB_STATE_WAIT_NDAC_FALSE 3 + +#define GRID210X_STATE_IDLE 0 +#define GRID210X_STATE_READING_DATA 1 +#define GRID210X_STATE_WRITING_DATA 2 +#define GRID210X_STATE_WRITING_DATA_WAIT 3 + +uint8_t grid2102_device::identify_response[56] = {0x00, 0x02, 0xf8, 0x01, 0xD0, 0x02, 0x01, 0x20, 0x01, 0x21, 0x01, 0x01, 0x00, 0x00, + 0x34, 0x38, 0x20, 0x54, 0x50, 0x49, 0x20, 0x44, 0x53, 0x20, 0x44, 0x44, 0x20, 0x46, + 0x4c, 0x4f, 0x50, 0x50, 0x59, 0x20, 0x20, 0x20, 0x20, 0x33, 0x30, 0x32, 0x33, 0x37, + 0x2d, 0x30, 0x30, 0x00, 0x02, 0x09, 0x00}; + +uint8_t grid2101_floppy_device::identify_response[56] = {0x00, 0x02, 0xf8, 0x01, 0xD0, 0x02, 0x01, 0x20, 0x01, 0x21, 0x01, 0x01, 0x00, 0x00, + 0x34, 0x38, 0x20, 0x54, 0x50, 0x49, 0x20, 0x44, 0x53, 0x20, 0x44, 0x44, 0x20, 0x46, + 0x4c, 0x4f, 0x50, 0x50, 0x59, 0x20, 0x20, 0x20, 0x20, 0x33, 0x30, 0x32, 0x33, 0x37, + 0x2d, 0x30, 0x30, 0x00, 0x02, 0x09, 0x00}; + +uint8_t grid2101_hdd_device::identify_response[56] = { + 0x00, 0x02, 0xF8, 0x01, 0x8C, 0x51, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4D, 0x41, + 0x4D, 0x45, 0x20, 0x48, 0x41, 0x52, 0x44, 0x44, 0x49, 0x53, 0x4B, 0x20, 0x44, 0x52, 0x49, 0x56, + 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x47, 0x52, 0x49, 0x44, 0x32, 0x31, 0x30, 0x31, 0x00, 0x02, + 0x11, 0x00, 0x33, 0x01, 0x00, 0x00, 0x04, 0x00 +}; + + +grid210x_device::grid210x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int bus_addr, uint8_t *identify_response, attotime read_delay) + : device_t(mconfig, type, tag, owner, clock), + device_ieee488_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_gpib_loop_state(GRID210X_GPIB_STATE_IDLE), + m_floppy_loop_state(GRID210X_STATE_IDLE), + listening(false), + talking(false), + serial_polling(false), + has_srq(false), + serial_poll_byte(0), + bus_addr(bus_addr), + identify_response_ptr(identify_response), + read_delay(read_delay) +{ + +} + +void grid210x_device::device_start() { + m_bus->ndac_w(this, 1); + m_bus->nrfd_w(this, 1); + m_delay_timer = timer_alloc(FUNC(grid210x_device::delay_tick), this); +} + +TIMER_CALLBACK_MEMBER(grid210x_device::delay_tick) { + if (m_floppy_loop_state == GRID210X_STATE_READING_DATA) { + std::unique_ptr<uint8_t[]> data(new uint8_t[io_size]); + fseek(floppy_sector_number * 512, SEEK_SET); + fread(data.get(), io_size); + for (int i = 0; i < io_size; i++) { + m_output_data_buffer.push(data[i]); + } + serial_poll_byte = 0x0F; + has_srq = true; + m_bus->srq_w(this, 0); + m_floppy_loop_state = GRID210X_STATE_IDLE; + } else if (m_floppy_loop_state == GRID210X_STATE_WRITING_DATA_WAIT) { + // send an srq as success flag + for (int i = 0; i < 7; i++) { // FIXME: + m_output_data_buffer.push(0); + } + serial_poll_byte = 0x0F; + has_srq = true; + m_bus->srq_w(this, 0); + m_floppy_loop_state = GRID210X_STATE_IDLE; + } +} + +void grid210x_device::ieee488_eoi(int state) { + // logerror("grid210x_device eoi state set to %d\n", state); +} + +void grid210x_device::accept_transfer() { + if (m_floppy_loop_state == GRID210X_STATE_IDLE) { + if (m_data_buffer.size() >= 0xA) { + uint8_t command = m_data_buffer[0]; + uint32_t sector_number = GRID2102_FETCH32(m_data_buffer, 3); + uint16_t data_size = GRID2102_FETCH16(m_data_buffer, 7); + LOG("grid210x_device command %u, data size %u, sector no %u\n", (unsigned)command, (unsigned)data_size, (unsigned)sector_number); + (void)(sector_number); + if (command == 0x1) { // ddGetStatus + for (int i = 0; i < 56 && i < data_size; i++) { + m_output_data_buffer.push(identify_response_ptr[i]); + } + } else if (command == 0x4) { // ddRead + floppy_sector_number = sector_number; + io_size = data_size; + m_floppy_loop_state = GRID210X_STATE_READING_DATA; + m_delay_timer->adjust(read_delay); + } else if (command == 0x5) { + floppy_sector_number = sector_number; + io_size = data_size; + m_floppy_loop_state = GRID210X_STATE_WRITING_DATA; + } + } // else something is wrong, ignore + } else if (m_floppy_loop_state == GRID210X_STATE_WRITING_DATA) { + // write + if (floppy_sector_number != 0xFFFFFFFF) { + fseek(floppy_sector_number * 512, SEEK_SET); + fwrite(m_data_buffer.data(), m_data_buffer.size()); + } else { + // TODO: set status + } + // logerror("grid210x_device write sector %d\n", floppy_sector_number); + // wait + m_floppy_loop_state = GRID210X_STATE_WRITING_DATA_WAIT; + m_delay_timer->adjust(read_delay); + } +} + +void grid210x_device::ieee488_dav(int state) { + if(state == 0 && m_gpib_loop_state == GRID210X_GPIB_STATE_IDLE) { + // read data and wait for transfer end + int atn = m_bus->atn_r() ^ 1; + m_bus->nrfd_w(this, 0); + uint8_t data = m_bus->dio_r() ^ 0xFF; + int eoi = m_bus->eoi_r() ^ 1; + LOG_BYTES("grid210x_device byte recv %02x atn %d eoi %d\n", data, atn, eoi); + m_last_recv_byte = data; + m_last_recv_atn = atn; + m_last_recv_eoi = eoi; + m_bus->ndac_w(this, 1); + m_gpib_loop_state = GRID210X_GPIB_STATE_WAIT_DAV_FALSE; + } else if (state == 1 && m_gpib_loop_state == GRID210X_GPIB_STATE_WAIT_DAV_FALSE) { + // restore initial state + // m_bus->ndac_w(this, 0); + m_bus->nrfd_w(this, 1); + m_gpib_loop_state = GRID210X_GPIB_STATE_IDLE; + update_ndac(m_bus->atn_r() ^ 1); + + if (m_last_recv_atn) { + if ((m_last_recv_byte & 0xE0) == 0x20) { + if ((m_last_recv_byte & 0x1F) == bus_addr) { + // dev-id = 5 + listening = true; + LOG("grid210x_device now listening\n"); + } else if((m_last_recv_byte & 0x1F) == 0x1F) { + // reset listen + listening = false; + LOG("grid210x_device now not listening\n"); + } + } else if ((m_last_recv_byte & 0xE0) == 0x40) { + if ((m_last_recv_byte & 0x1F) == bus_addr) { + // dev-id = 5 + talking = true; + LOG("grid210x_device now talking\n"); + } else { + // reset talk + talking = false; + LOG("grid210x_device now not talking\n"); + } + } else if (m_last_recv_byte == 0x18) { + // serial poll enable + serial_polling = true; + } else if (m_last_recv_byte == 0x19) { + // serial poll disable + serial_polling = false; + } + } else if (listening) { + m_data_buffer.push_back(m_last_recv_byte); + if (m_last_recv_eoi) { + accept_transfer(); + m_data_buffer.clear(); + } + } + + if (talking) { + if (serial_polling) { + bool had_srq = has_srq; + if (has_srq) { + has_srq = false; + m_bus->srq_w(this, 1); + } + m_byte_to_send = serial_poll_byte | (had_srq ? 0x40 : 0); + serial_poll_byte = 0; + m_send_eoi = 1; + m_gpib_loop_state = GRID210X_GPIB_STATE_SEND_DATA_START; + } else if (!m_output_data_buffer.empty()) { + m_byte_to_send = m_output_data_buffer.front(); + m_output_data_buffer.pop(); + m_send_eoi = m_output_data_buffer.empty() ? 1 : 0; + m_gpib_loop_state = GRID210X_GPIB_STATE_SEND_DATA_START; + } + } + } +} + +void grid210x_device::ieee488_nrfd(int state) { + if (state == 1 && m_gpib_loop_state == GRID210X_GPIB_STATE_SEND_DATA_START) { + // set dio and assert dav + m_bus->host_dio_w(m_byte_to_send ^ 0xFF); + m_bus->eoi_w(this, m_send_eoi ^ 1); + m_bus->dav_w(this, 0); + m_bus->ndac_w(this, 1); + m_gpib_loop_state = GRID210X_GPIB_STATE_WAIT_NDAC_FALSE; + LOG_BYTES("grid210x_device byte send %02x eoi %d\n", m_byte_to_send, m_send_eoi); + ieee488_ndac(m_bus->ndac_r()); + } + // logerror("grid210x_device nrfd state set to %d\n", state); +} + +void grid210x_device::ieee488_ndac(int state) { + if (state == 1 && m_gpib_loop_state == GRID210X_GPIB_STATE_WAIT_NDAC_FALSE) { + // restore initial state + // logerror("grid210x_device restore ndac nrfd dav eoi\n"); + m_bus->nrfd_w(this, 1); + m_bus->dav_w(this, 1); + m_bus->eoi_w(this, 1); + m_gpib_loop_state = GRID210X_GPIB_STATE_IDLE; + if (serial_polling) { + talking = false; + } + update_ndac(m_bus->atn_r() ^ 1); + + if (!serial_polling && talking && !m_output_data_buffer.empty()) { + m_byte_to_send = m_output_data_buffer.front(); + m_output_data_buffer.pop(); + m_send_eoi = m_output_data_buffer.empty() ? 1 : 0; + m_gpib_loop_state = GRID210X_GPIB_STATE_SEND_DATA_START; + } + } + // logerror("grid210x_device ndac state set to %d\n", state); +} + +void grid210x_device::ieee488_ifc(int state) { + // logerror("grid210x_device ifc state set to %d\n", state); +} + +void grid210x_device::ieee488_srq(int state) { + // logerror("grid210x_device srq state set to %d\n", state); +} + +void grid210x_device::ieee488_atn(int state) { + // logerror("grid210x_device atn state set to %d\n", state); + update_ndac(state ^ 1); +} + +void grid210x_device::update_ndac(int atn) { + if (m_gpib_loop_state == GRID210X_GPIB_STATE_IDLE) { + if (atn) { + // pull NDAC low + m_bus->ndac_w(this, 0); + } else { + // pull NDAC high if not listener and low if listener + m_bus->ndac_w(this, listening ? 0 : 1); + } + } +} + +void grid210x_device::ieee488_ren(int state) { + LOG("grid210x_device ren state set to %d\n", state); +} + +grid2101_hdd_device::grid2101_hdd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : grid210x_device(mconfig, GRID2101_HDD, tag, owner, clock, 4, identify_response, attotime::from_usec(150)) +{ + +} + +grid2101_floppy_device::grid2101_floppy_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : grid210x_device(mconfig, GRID2101_FLOPPY, tag, owner, clock, 5, identify_response) +{ + +} + +grid2102_device::grid2102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : grid210x_device(mconfig, GRID2102, tag, owner, clock, 6, identify_response) +{ + +} |