summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/micropolis.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/micropolis.c')
-rw-r--r--src/mame/machine/micropolis.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/src/mame/machine/micropolis.c b/src/mame/machine/micropolis.c
new file mode 100644
index 00000000000..73b1b58178e
--- /dev/null
+++ b/src/mame/machine/micropolis.c
@@ -0,0 +1,344 @@
+// license:BSD-3-Clause
+// copyright-holders:Robbbert
+/***************************************************************************
+
+ micropolis.c
+
+ by Robbbert, August 2011.
+
+This is a rough implementation of the Micropolis floppy-disk controller
+as used for the Exidy Sorcerer. Since there is no documentation, coding
+was done by looking at the Z80 code, and supplying the expected values.
+
+Currently, only reading of disks is supported.
+
+ToDo:
+- Rewrite to be a standard device able to be used in a general way
+- Fix bug where if you run a program on drive B,C,D then exit, you
+ get a disk error.
+- Enable the ability to write to disk when above bug gets fixed.
+- When the controller is reset via command 5, what exactly gets reset?
+
+
+Ports:
+BE00 and BE01 can be used as command registers (they are identical),
+ and they are also used as status registers (different).
+
+BE02 and BE03 - read data, write data
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "machine/micropolis.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+
+#define STAT_RFC 0x20
+#define STAT_TRACK0 0x08
+#define STAT_READY 0x80
+
+#define VERBOSE 0 /* General logging */
+#define VERBOSE_DATA 0 /* Logging of each byte during read and write */
+
+/* structure describing a single density track */
+#define TRKSIZE_SD 16*270
+
+#if 0
+static const UINT8 track_SD[][2] = {
+ { 1, 0xff}, /* 1 * FF (marker) */
+ { 1, 0x00}, /* 1 byte, track number (00-4C) */
+ { 1, 0x01}, /* 1 byte, sector number (00-0F) */
+ {10, 0x00}, /* 10 bytes of zeroes */
+ {256, 0xe5}, /* 256 bytes of sector data */
+ { 1, 0xb7}, /* 1 byte, CRC */
+};
+#endif
+
+/***************************************************************************
+ MAME DEVICE INTERFACE
+***************************************************************************/
+
+const device_type MICROPOLIS = &device_creator<micropolis_device>;
+
+micropolis_device::micropolis_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MICROPOLIS, "MICROPOLIS", tag, owner, clock, "micropolis", __FILE__),
+ m_read_dden(*this),
+ m_write_intrq(*this),
+ m_write_drq(*this),
+ m_data(0),
+ m_drive_num(0),
+ m_track(0),
+ m_sector(0),
+ m_command(0),
+ m_status(0),
+ m_write_cmd(0),
+ m_data_offset(0),
+ m_data_count(0),
+ m_sector_length(0),
+ m_drive(NULL)
+{
+ for (int i = 0; i < 6144; i++)
+ m_buffer[i] = 0;
+
+ for (int i = 0; i < 4; i++)
+ m_floppy_drive_tags[i] = NULL;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void micropolis_device::device_start()
+{
+ m_read_dden.resolve_safe(1);
+ m_write_intrq.resolve_safe();
+ m_write_drq.resolve_safe();
+
+ save_item(NAME(m_data));
+ save_item(NAME(m_drive_num));
+ save_item(NAME(m_track));
+ save_item(NAME(m_sector));
+ save_item(NAME(m_command));
+ save_item(NAME(m_status));
+ save_item(NAME(m_write_cmd));
+ save_item(NAME(m_buffer));
+ save_item(NAME(m_data_offset));
+ save_item(NAME(m_data_count));
+ save_item(NAME(m_sector_length));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void micropolis_device::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (m_floppy_drive_tags[i])
+ {
+ legacy_floppy_image_device *img = siblingdevice<legacy_floppy_image_device>(m_floppy_drive_tags[i]);
+
+ if (img)
+ {
+ img->floppy_drive_set_controller(this);
+ //img->floppy_drive_set_index_pulse_callback(wd17xx_index_pulse_callback);
+ img->floppy_drive_set_rpm(300.);
+ }
+ }
+ }
+
+ set_drive(0);
+
+ m_drive_num = 0;
+ m_sector = 0;
+ m_track = 0;
+ m_sector_length = 270;
+ m_status = STAT_TRACK0;
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+
+/* read a sector */
+void micropolis_device::read_sector()
+{
+ m_data_offset = 0;
+ m_data_count = m_sector_length;
+
+ /* read data */
+ m_drive->floppy_drive_read_sector_data(0, m_sector, (char *)m_buffer, m_sector_length);
+}
+
+
+void micropolis_device::write_sector()
+{
+#if 0
+ /* at this point, the disc is write enabled, and data
+ * has been transfered into our buffer - now write it to
+ * the disc image or to the real disc
+ */
+
+ /* find sector */
+ m_data_count = m_sector_length;
+
+ /* write data */
+ m_drive->floppy_drive_write_sector_data(0, m_sector, (char *)m_buffer, m_sector_length, m_write_cmd & 0x01);
+#endif
+}
+
+
+
+
+/***************************************************************************
+ INTERFACE
+***************************************************************************/
+
+/* select a drive */
+void micropolis_device::set_drive(UINT8 drive)
+{
+ if (VERBOSE)
+ logerror("micropolis_set_drive: $%02x\n", drive);
+
+ if (m_floppy_drive_tags[drive])
+ m_drive = siblingdevice<legacy_floppy_image_device>(m_floppy_drive_tags[drive]);
+}
+
+
+/***************************************************************************
+ DEVICE HANDLERS
+***************************************************************************/
+
+
+/* read the FDC status register. */
+READ8_MEMBER( micropolis_device::status_r )
+{
+ static int inv = 0;
+
+ if (offset)
+ return m_status | m_drive_num;
+ else
+ {
+ // FIXME - find out what controls current sector
+ m_sector = (m_sector + 3 + inv) & 15;
+ read_sector();
+ inv ^= 1;
+ return (m_status & STAT_READY) | m_sector;
+ }
+}
+
+
+/* read the FDC data register */
+READ8_MEMBER( micropolis_device::data_r )
+{
+ if (m_data_offset >= m_sector_length)
+ m_data_offset = 0;
+
+ return m_buffer[m_data_offset++];
+}
+
+/* write the FDC command register */
+WRITE8_MEMBER( micropolis_device::command_w )
+{
+/* List of commands:
+Command (bits 5,6,7) Options (bits 0,1,2,3,4)
+0 Not used
+1 Drive/head select bits 0,1 select drive 0-3; bit 4 chooses a side
+2 INT sector control bit 0 LO = disable; HI = enable
+3 Step bit 0 LO step out; HI = step in (increment track number)
+4 Set Write
+5 Reset controller
+6 Not used
+7 Not used */
+
+ int direction = 0;
+
+ switch (data >> 5)
+ {
+ case 1:
+ m_drive_num = data & 3;
+ m_drive->floppy_mon_w(1); // turn off the old drive
+ set_drive(m_drive_num); // select new drive
+ m_drive->floppy_mon_w(0); // turn it on
+ break;
+ case 2: // not emulated, not used in sorcerer
+ break;
+ case 3:
+ if (BIT(data, 0))
+ {
+ if (m_track < 77)
+ {
+ m_track++;
+ direction = 1;
+ }
+ }
+ else
+ {
+ if (m_track)
+ {
+ m_track--;
+ direction = -1;
+ }
+ }
+ break;
+ case 4: // not emulated, to be done
+ break;
+ case 5: // not emulated, to be done
+ break;
+ }
+
+
+ m_status = STAT_RFC;
+
+ if (BIT(data, 5))
+ m_status |= STAT_READY;
+
+ m_drive->floppy_drive_set_ready_state(1,0);
+
+
+ if (!m_track)
+ m_status |= STAT_TRACK0;
+
+ m_drive->floppy_drive_seek(direction);
+}
+
+
+/* write the FDC data register */
+WRITE8_MEMBER( micropolis_device::data_w )
+{
+ if (m_data_count > 0)
+ {
+ /* put byte into buffer */
+ if (VERBOSE_DATA)
+ logerror("micropolis_info buffered data: $%02X at offset %d.\n", data, m_data_offset);
+
+ m_buffer[m_data_offset++] = data;
+
+ if (--m_data_count < 1)
+ {
+ write_sector();
+
+ m_data_offset = 0;
+ }
+ }
+ else
+ {
+ if (VERBOSE)
+ logerror("%s: micropolis_data_w $%02X\n", space.machine().describe_context(), data);
+ }
+ m_data = data;
+}
+
+READ8_MEMBER( micropolis_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset & 0x03)
+ {
+ case 0: data = status_r(space, 0); break;
+ case 1: data = status_r(space, 1); break;
+ case 2:
+ case 3: data = data_r(space, 0); break;
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( micropolis_device::write )
+{
+ switch (offset & 0x03)
+ {
+ case 0:
+ case 1: command_w(space, 0, data); break;
+ case 2:
+ case 3: data_w(space, 0, data); break;
+ }
+}