summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/a2bus/agat840k_hle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/a2bus/agat840k_hle.cpp')
-rw-r--r--src/devices/bus/a2bus/agat840k_hle.cpp449
1 files changed, 449 insertions, 0 deletions
diff --git a/src/devices/bus/a2bus/agat840k_hle.cpp b/src/devices/bus/a2bus/agat840k_hle.cpp
new file mode 100644
index 00000000000..72217fbe464
--- /dev/null
+++ b/src/devices/bus/a2bus/agat840k_hle.cpp
@@ -0,0 +1,449 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/*********************************************************************
+
+ agat840k_hle.cpp
+
+ High-level simulation of the Agat 840K floppy controller card
+
+ http://agatcomp.ru/Reading/docs/es5323.txt
+ https://github.com/sintech/AGAT/blob/master/docs/agat-840k-format.txt
+ http://www.torlus.com/floppy/forum/viewtopic.php?f=19&t=1385
+
+*********************************************************************/
+
+#include "emu.h"
+#include "agat840k_hle.h"
+
+#include "formats/agat840k_hle_dsk.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(A2BUS_AGAT840K_HLE, a2bus_agat840k_hle_device, "agat840k_hle", "Agat 840K floppy card")
+
+#define AGAT840K_ROM_REGION "agat840k_hle_rom"
+
+
+ROM_START( agat840k_hle )
+ ROM_REGION(0x100, AGAT840K_ROM_REGION, 0)
+ // "Zagorsk" variant
+ ROM_LOAD( "teac.rom", 0x0000, 0x0100, CRC(94266928) SHA1(5d369bad6cdd6a70b0bb16480eba69640de87a2e) )
+ROM_END
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+static const floppy_interface agat840k_hle_floppy_interface =
+{
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(agat840k_hle),
+ "floppy_5_25"
+};
+
+MACHINE_CONFIG_MEMBER( a2bus_agat840k_hle_device::device_add_mconfig )
+ MCFG_DEVICE_ADD(FLOPPY_0, LEGACY_FLOPPY, 0)
+ MCFG_LEGACY_FLOPPY_CONFIG(agat840k_hle_floppy_interface)
+ MCFG_LEGACY_FLOPPY_IDX_CB(WRITELINE(a2bus_agat840k_hle_device, index_0_w))
+ MCFG_DEVICE_ADD(FLOPPY_1, LEGACY_FLOPPY, 0)
+ MCFG_LEGACY_FLOPPY_CONFIG(agat840k_hle_floppy_interface)
+ MCFG_LEGACY_FLOPPY_IDX_CB(WRITELINE(a2bus_agat840k_hle_device, index_1_w))
+
+ MCFG_DEVICE_ADD("d14", I8255, 0)
+ // PA not connected
+ MCFG_I8255_IN_PORTB_CB(READ8(a2bus_agat840k_hle_device, d14_i_b)) // status signals from drive
+ MCFG_I8255_OUT_PORTC_CB(WRITE8(a2bus_agat840k_hle_device, d14_o_c)) // control
+
+ MCFG_DEVICE_ADD("d15", I8255, 0)
+ MCFG_I8255_IN_PORTA_CB(READ8(a2bus_agat840k_hle_device, d15_i_a)) // read data
+// MCFG_I8255_OUT_PORTB_CB(WRITE8(a2bus_agat840k_hle_device, d15_o_b)) // write data
+ MCFG_I8255_IN_PORTC_CB(READ8(a2bus_agat840k_hle_device, d15_i_c))
+ MCFG_I8255_OUT_PORTC_CB(WRITE8(a2bus_agat840k_hle_device, d15_o_c))
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const tiny_rom_entry *a2bus_agat840k_hle_device::device_rom_region() const
+{
+ return ROM_NAME(agat840k_hle);
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+a2bus_agat840k_hle_device::a2bus_agat840k_hle_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_a2bus_card_interface(mconfig, *this)
+ , m_d14(*this, "d14")
+ , m_d15(*this, "d15")
+ , m_rom(nullptr)
+{
+}
+
+a2bus_agat840k_hle_device::a2bus_agat840k_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ a2bus_agat840k_hle_device(mconfig, A2BUS_AGAT840K_HLE, tag, owner, clock)
+{
+}
+
+WRITE_LINE_MEMBER(a2bus_agat840k_hle_device::index_0_w)
+{
+ index_callback(0, state);
+}
+
+WRITE_LINE_MEMBER(a2bus_agat840k_hle_device::index_1_w)
+{
+ index_callback(1, state);
+}
+
+void a2bus_agat840k_hle_device::index_callback(int unit, int state)
+{
+ if (unit != m_unit) return;
+
+ LOG("index: unit %d state %d (%s)\n", unit, state, m_seen_magic ? "MAGIC" : "magic");
+
+#if 0
+ if (!state && !m_seen_magic)
+ {
+ m_seen_magic = true;
+ m_count_read = 0;
+ m_count_write = 0;
+ m_d15->pc4_w(0); // latch data into port A
+ m_d15->pc4_w(1);
+ m_timer_wait->adjust(attotime::from_usec(m_waittime), 0, attotime::from_usec(m_waittime));
+ }
+#endif
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_agat840k_hle_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ m_rom = device().machine().root_device().memregion(this->subtag(AGAT840K_ROM_REGION).c_str())->base();
+
+ m_mxcs = MXCSR_SYNC;
+
+ m_timer_wait = timer_alloc(TIMER_ID_WAIT);
+ m_timer_seek = timer_alloc(TIMER_ID_SEEK);
+
+ m_seektime = 6000; // 6 ms, per es5323.txt
+ m_waittime = 32; // 16 bits x 2 us
+}
+
+void a2bus_agat840k_hle_device::device_reset()
+{
+ u8 buf[256];
+
+ for (int i = 0; i < 2; i++)
+ {
+ legacy_floppy_image_device *img = floppy_image(i);
+ if (img)
+ {
+ img->floppy_drive_set_ready_state(FLOPPY_DRIVE_READY, 0);
+ img->floppy_drive_set_rpm(300.);
+ img->floppy_drive_seek(-img->floppy_drive_get_current_track());
+ }
+ }
+ m_floppy = floppy_image(0);
+
+ // generate track images in memory, using default volume ID and gap padding bytes
+ int t = 0;
+ for (auto &elem : m_tracks)
+ {
+ elem = std::make_unique<uint16_t[]>(6250);
+
+ for (int i = 0; i < 13; i++)
+ {
+ elem[i] = 0xaa;
+ }
+ for (int j = 0; j < 21; j++)
+ {
+ const int s = (j * 1) % 21;
+ int cksum = 0;
+
+ m_floppy->floppy_drive_read_sector_data(t & 1, s, buf, 256);
+
+ enum
+ {
+ BAUX = 22,
+ BLOB = 256 + 19 + BAUX
+ };
+
+ for (int k = 0; k < 256; k++)
+ {
+ if (cksum > 255) { cksum++; cksum &= 255; }
+ cksum += buf[k];
+ elem[13 + (BLOB * j) + 17 + k] = buf[k];
+ }
+ cksum &= 255;
+
+ elem[13 + (BLOB * j) + 0] = 0xa4;
+ elem[13 + (BLOB * j) + 1] = 0x80ff; // desync
+ elem[13 + (BLOB * j) + 2] = 0x95;
+ elem[13 + (BLOB * j) + 3] = 0x6a;
+ elem[13 + (BLOB * j) + 4] = 0x40fe; // volume id
+ elem[13 + (BLOB * j) + 5] = t;
+ elem[13 + (BLOB * j) + 6] = s;
+ elem[13 + (BLOB * j) + 7] = 0x5a;
+ elem[13 + (BLOB * j) + 8] = 0xaa;
+ elem[13 + (BLOB * j) + 9] = 0xaa;
+ elem[13 + (BLOB * j) + 10] = 0xaa;
+ elem[13 + (BLOB * j) + 11] = 0xaa;
+ elem[13 + (BLOB * j) + 12] = 0xaa;
+ elem[13 + (BLOB * j) + 13] = 0xa4;
+ elem[13 + (BLOB * j) + 14] = 0x80ff; // desync
+ elem[13 + (BLOB * j) + 15] = 0x6a;
+ elem[13 + (BLOB * j) + 16] = 0x95;
+ elem[13 + (BLOB * j) + 17 + 256] = cksum + 0x2000;
+ elem[13 + (BLOB * j) + 17 + 257] = 0x5a;
+
+ // gap3
+ for (int k = 0; k < BAUX; k++)
+ {
+ elem[13 + (BLOB * j) + 17 + 258 + k] = 0xaa;
+ }
+ }
+
+ t++;
+ if ((t & 1) == 0)
+ {
+ m_floppy->floppy_drive_seek(1);
+ }
+ }
+ m_floppy->floppy_drive_seek(-m_floppy->floppy_drive_get_current_track());
+
+ m_mxcs |= MXCSR_SYNC;
+ m_mxcs &= ~MXCSR_TR;
+}
+
+void a2bus_agat840k_hle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_WAIT:
+ {
+ m_count_read++;
+ m_count_read %= 6250;
+ m_d15->pc4_w(0);
+ m_d15->pc4_w(1);
+ if (BIT(m_tracks[(2 * m_floppy->floppy_drive_get_current_track()) + m_side][m_count_read], 15))
+ m_mxcs &= ~MXCSR_SYNC;
+ }
+ break;
+
+ case TIMER_ID_SEEK:
+ m_floppy->floppy_stp_w(1);
+ m_floppy->floppy_stp_w(0);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ read_c0nx - called for reads from this card's c0nx space
+-------------------------------------------------*/
+
+uint8_t a2bus_agat840k_hle_device::read_c0nx(address_space &space, uint8_t offset)
+{
+ u8 data;
+
+ switch (offset)
+ {
+ case 0: case 1: case 2: case 3:
+ data = m_d14->read(space, offset);
+ break;
+
+ case 4: case 5: case 6: case 7:
+ data = m_d15->read(space, offset - 4);
+ break;
+
+ default:
+ data = 0xff;
+ break;
+ }
+
+ return data;
+}
+
+
+/*-------------------------------------------------
+ write_c0nx - called for writes to this card's c0nx space
+-------------------------------------------------*/
+
+void a2bus_agat840k_hle_device::write_c0nx(address_space &space, uint8_t offset, uint8_t data)
+{
+ switch (offset)
+ {
+ case 0: case 1: case 2: case 3:
+ m_d14->write(space, offset, data);
+ break;
+
+ case 4: case 5: case 6: case 7:
+ m_d15->write(space, offset - 4, data);
+ break;
+
+ case 8: // write desync
+ break;
+
+ case 9: // step
+ LOG("step at %11.6f\n", machine().time().as_double());
+ m_seen_magic = false;
+ m_timer_wait->adjust(attotime::from_usec(m_seektime), 0, attotime::from_usec(m_waittime));
+ m_floppy->floppy_stp_w(1);
+ m_floppy->floppy_stp_w(0);
+ break;
+
+ case 10: // reset desync flipflop
+ m_mxcs |= MXCSR_SYNC;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ read_cnxx - called for reads from this card's c0nx space
+-------------------------------------------------*/
+
+uint8_t a2bus_agat840k_hle_device::read_cnxx(address_space &space, uint8_t offset)
+{
+ return m_rom[offset];
+}
+
+legacy_floppy_image_device *a2bus_agat840k_hle_device::floppy_image(int drive)
+{
+ const char *floppy_name = nullptr;
+
+ switch (drive)
+ {
+ case 0:
+ floppy_name = FLOPPY_0;
+ break;
+ case 1:
+ floppy_name = FLOPPY_1;
+ break;
+ }
+ return subdevice<legacy_floppy_image_device>(floppy_name);
+}
+
+// all signals active low. write support not implemented; WPT is always active.
+READ8_MEMBER(a2bus_agat840k_hle_device::d14_i_b)
+{
+ u8 data = 0x03; // one drive present, because drive select is broken
+
+ m_floppy->floppy_drive_set_ready_state(FLOPPY_DRIVE_READY, 1);
+
+ data |= (m_floppy->floppy_index_r() << 4) ^ 0x10;
+// data |= m_floppy->floppy_wpt_r() << 5;
+ data |= m_floppy->floppy_tk00_r() << 6;
+ data |= m_floppy->floppy_ready_r() << 7;
+
+ LOG("status A: %s %s (t %d) %s %s\n", BIT(data, 7) ? "ready" : "READY", BIT(data, 6) ? "tk00" : "TK00",
+ m_floppy->floppy_drive_get_current_track(),
+ BIT(data, 5) ? "wpt" : "WPT", BIT(data, 4) ? "index" : "INDEX");
+
+ return data;
+}
+
+/*
+ * b0 AH strong write precomp
+ * b1 -- NC
+ * b2 -- step direction (1 - inward, 0 - outward)
+ * b3 -- drive select (0 - drive 1, 1 - drive 2)
+ * b4 -- head select (0 - bottom, 1 - top)
+ * b5 AH write precomp off
+ * b6 AH write enable
+ * b7 AH motor on
+ *
+ * C0x2
+ */
+WRITE8_MEMBER(a2bus_agat840k_hle_device::d14_o_c)
+{
+ // drive select is broken in legacy flopdrv.cpp -- floppy_get_drive
+ m_unit = BIT(data, 3);
+ m_floppy = floppy_image(m_unit);
+ if (m_unit)
+ m_floppy->floppy_ds1_w(m_unit != 1);
+ else
+ m_floppy->floppy_ds0_w(m_unit != 0);
+
+ m_floppy->floppy_drtn_w(!BIT(data, 2));
+ m_side = BIT(data, 4);
+ m_floppy->floppy_wtg_w(!BIT(data, 6));
+ m_floppy->floppy_mon_w(!BIT(data, 7)); // tied to 'drive select', 'motor on' and 'head load'
+
+ if (!BIT(data, 7))
+ {
+ m_seen_magic = false;
+ m_timer_wait->adjust(attotime::never);
+ }
+ else
+ {
+ m_d15->pc4_w(0);
+ m_d15->pc4_w(1);
+ m_timer_wait->adjust(attotime::from_usec(m_waittime), 0, attotime::from_usec(m_waittime));
+ }
+
+ LOG("D14 C <- %02X (unit %d side %d drtn %d wtg %d mon %d)\n",
+ data, m_unit, m_side, !BIT(data, 2), !BIT(data, 6), !BIT(data, 7));
+}
+
+// data are latched in by write to PC4
+READ8_MEMBER(a2bus_agat840k_hle_device::d15_i_a)
+{
+ const u16 data = m_tracks[(2 * m_floppy->floppy_drive_get_current_track()) + m_side][m_count_read];
+ LOG("sector data: %02x @ %4d (head %d track %2d)%s\n", data & 0xff, m_count_read,
+ m_side, m_floppy->floppy_drive_get_current_track(),
+ BIT(data, 14) ? " volume" : (BIT(data, 13) ? " cksum" : ""));
+
+ return data & 0xff;
+}
+
+// C0x6
+//
+// b6 AL desync detected
+// b7 AH read or write data ready
+READ8_MEMBER(a2bus_agat840k_hle_device::d15_i_c)
+{
+ LOG("status B: @ %4d %s %s (%s)\n", m_count_read,
+ BIT(m_mxcs, 7) ? "ready" : "READY", BIT(m_mxcs, 6) ? "SYNC" : "sync",
+ m_seen_magic ? "MAGIC" : "magic");
+
+ return m_mxcs;
+}
+
+// C0x7
+//
+// b0 -- connected to b7, set if m_intr[PORT_B]
+// b2 AH b7 = ready for write data
+// b3 -- connected to b7, set if m_intr[PORT_A]
+// b4 AH b7 = read data ready
+WRITE8_MEMBER(a2bus_agat840k_hle_device::d15_o_c)
+{
+ if (BIT(data, 0) || BIT(data, 3))
+ {
+ m_mxcs |= MXCSR_TR;
+ }
+ else
+ {
+ m_mxcs &= ~MXCSR_TR;
+ }
+}