summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/ieee488/grid2102.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/ieee488/grid2102.cpp')
-rw-r--r--src/devices/bus/ieee488/grid2102.cpp315
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)
+{
+
+}