summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/990_dk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/990_dk.c')
-rw-r--r--src/mess/machine/990_dk.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/src/mess/machine/990_dk.c b/src/mess/machine/990_dk.c
new file mode 100644
index 00000000000..ef95a3e5e71
--- /dev/null
+++ b/src/mess/machine/990_dk.c
@@ -0,0 +1,881 @@
+/*
+ 990_dk.c: emulation of a TI FD800 'Diablo' floppy disk controller
+ controller, for use with any TI990 system (and possibly any system which
+ implements the CRU bus).
+
+ This floppy disk controller supports IBM-format 8" SSSD and DSSD floppies.
+
+ Raphael Nabet 2003
+*/
+
+#include "emu.h"
+
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "990_dk.h"
+
+#define MAX_FLOPPIES 4
+
+enum buf_mode_t {
+ bm_off, bm_read, bm_write
+};
+static struct
+{
+ running_machine *machine;
+ UINT16 recv_buf;
+ UINT16 stat_reg;
+ UINT16 xmit_buf;
+ UINT16 cmd_reg;
+
+ int interrupt_f_f;
+ void (*interrupt_callback)(running_machine &, int state);
+
+ UINT8 buf[128];
+ int buf_pos;
+ buf_mode_t buf_mode;
+ int unit;
+ int head;
+ int sector;
+ /*int non_seq_mode;*/
+ int ddam;
+
+ struct
+ {
+ device_image_interface *img;
+ int phys_cylinder;
+ int log_cylinder[2];
+ int seclen;
+ } drv[MAX_FLOPPIES];
+} fd800;
+
+/* status bits */
+enum
+{
+ status_OP_complete = 1 << 0,
+ status_XFER_ready = 1 << 1,
+ status_drv_not_ready= 1 << 2,
+ status_dat_chk_err = 1 << 3,
+ status_seek_err = 1 << 4,
+ status_invalid_cmd = 1 << 5,
+ status_no_addr_mark = 1 << 6,
+ status_equ_chk_err = 1 << 7,
+ status_ID_chk_err = 1 << 8,
+ status_ID_not_found = 1 << 9,
+ status_ctlr_busy = 1 << 10,
+ status_write_prot = 1 << 11,
+ status_del_sector = 1 << 12,
+ status_interrupt = 1 << 15,
+
+ status_unit_shift = 13
+};
+
+LEGACY_FLOPPY_OPTIONS_START(fd800)
+#if 1
+ /* SSSD 8" */
+ LEGACY_FLOPPY_OPTION(fd800, "dsk", "TI990 8\" SSSD disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([77])
+ SECTORS([26])
+ SECTOR_LENGTH([128])
+ FIRST_SECTOR_ID([1]))
+#elif 0
+ /* DSSD 8" */
+ LEGACY_FLOPPY_OPTION(fd800, "dsk", "TI990 8\" DSSD disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([77])
+ SECTORS([26])
+ SECTOR_LENGTH([128])
+ FIRST_SECTOR_ID([1]))
+#endif
+LEGACY_FLOPPY_OPTIONS_END
+
+static void fd800_field_interrupt(void)
+{
+ if (fd800.interrupt_callback)
+ (*fd800.interrupt_callback)(*fd800.machine, (fd800.stat_reg & status_interrupt) && ! fd800.interrupt_f_f);
+}
+
+static void fd800_unload_proc(device_image_interface &image)
+{
+ int unit = floppy_get_drive(&image.device());
+
+ fd800.drv[unit].log_cylinder[0] = fd800.drv[unit].log_cylinder[1] = -1;
+}
+
+void fd800_machine_init(running_machine &machine, void (*interrupt_callback)(running_machine &machine, int state))
+{
+ int i;
+
+ fd800.machine = &machine;
+ fd800.interrupt_callback = interrupt_callback;
+
+ fd800.stat_reg = 0;
+ fd800.interrupt_f_f = 1;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_off;
+
+ for (i=0; i<MAX_FLOPPIES; i++)
+ {
+ fd800.drv[i].img = dynamic_cast<device_image_interface *>(floppy_get_device(machine, i));
+ fd800.drv[i].phys_cylinder = -1;
+ fd800.drv[i].log_cylinder[0] = fd800.drv[i].log_cylinder[1] = -1;
+ fd800.drv[i].seclen = 64;
+ floppy_install_unload_proc(&fd800.drv[i].img->device(), fd800_unload_proc);
+ }
+
+ fd800_field_interrupt();
+}
+
+/*
+ Read the first id field that can be found on the floppy disk.
+
+ unit: floppy drive index
+ head: selected head
+ cylinder_id: cylinder ID read
+ sector_id: sector ID read
+
+ Return TRUE if an ID was found
+*/
+static int fd800_read_id(int unit, int head, int *cylinder_id, int *sector_id)
+{
+ /*UINT8 revolution_count;*/
+ chrn_id id;
+
+ /*revolution_count = 0;*/
+
+ /*while (revolution_count < 2)*/
+ /*{*/
+ if (floppy_drive_get_next_id(&fd800.drv[unit].img->device(), head, &id))
+ {
+ if (cylinder_id)
+ *cylinder_id = id.C;
+ if (sector_id)
+ *sector_id = id.R;
+ return TRUE;
+ }
+ /*}*/
+
+ return FALSE;
+}
+
+/*
+ Find a sector by id.
+
+ unit: floppy drive index
+ head: selected head
+ sector: sector ID to search
+ data_id: data ID to be used when calling sector read/write functions
+
+ Return TRUE if the given sector ID was found
+*/
+static int fd800_find_sector(int unit, int head, int sector, int *data_id)
+{
+ UINT8 revolution_count;
+ chrn_id id;
+
+ revolution_count = 0;
+
+ while (revolution_count < 2)
+ {
+ if (floppy_drive_get_next_id(&fd800.drv[unit].img->device(), head, &id))
+ {
+ /* compare id */
+ if ((id.R == sector) && (id.N == 0))
+ {
+ *data_id = id.data_id;
+ /* get ddam status */
+ /*w->ddam = id.flags & ID_FLAG_DELETED_DATA;*/
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ Perform seek command
+
+ unit: floppy drive index
+ cylinder: track to seek for
+ head: head for which the seek is performed
+
+ Return FALSE if the seek was successful
+*/
+static int fd800_do_seek(int unit, int cylinder, int head)
+{
+ int retries;
+
+ if (cylinder > 76)
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ return TRUE;
+ }
+
+ if (!fd800.drv[unit].img->exists())
+ {
+ fd800.stat_reg |= status_drv_not_ready; /* right??? */
+ return TRUE;
+ }
+
+ if (fd800.drv[unit].log_cylinder[head] == -1)
+ { /* current track ID is unknown: read it */
+ if (!fd800_read_id(unit, head, &fd800.drv[unit].log_cylinder[head], NULL))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ return TRUE;
+ }
+ }
+ /* exit if we are already at the requested track */
+ if (fd800.drv[unit].log_cylinder[head] == cylinder)
+ {
+ /*fd800.stat_reg |= status_OP_complete;*/
+ return FALSE;
+ }
+ for (retries=0; retries<10; retries++)
+ { /* seek to requested track */
+ floppy_drive_seek(&fd800.drv[unit].img->device(), cylinder-fd800.drv[unit].log_cylinder[head]);
+ /* update physical track position */
+ if (fd800.drv[unit].phys_cylinder != -1)
+ fd800.drv[unit].phys_cylinder += cylinder-fd800.drv[unit].log_cylinder[head];
+ /* read new track ID */
+ if (!fd800_read_id(unit, head, &fd800.drv[unit].log_cylinder[head], NULL))
+ {
+ fd800.drv[unit].log_cylinder[head] = -1;
+ fd800.stat_reg |= status_ID_not_found;
+ return TRUE;
+ }
+ /* exit if we have reached the requested track */
+ if (fd800.drv[unit].log_cylinder[head] == cylinder)
+ {
+ /*fd800.stat_reg |= status_OP_complete;*/
+ return FALSE;
+ }
+ }
+ /* track not found */
+ fd800.stat_reg |= status_seek_err;
+ return TRUE;
+}
+
+/*
+ Perform restore command
+
+ unit: floppy drive index
+
+ Return FALSE if the restore was successful
+*/
+static int fd800_do_restore(int unit)
+{
+ int seek_count = 0;
+ int seek_complete;
+
+ if (!fd800.drv[unit].img->exists())
+ {
+ fd800.stat_reg |= status_drv_not_ready; /* right??? */
+ return TRUE;
+ }
+
+ /* limit iterations to 76 to prevent an endless loop if the disc is locked */
+ while (!(seek_complete = !floppy_tk00_r(&fd800.drv[unit].img->device())) && (seek_count < 76))
+ {
+ floppy_drive_seek(&fd800.drv[unit].img->device(), -1);
+ seek_count++;
+ }
+ if (! seek_complete)
+ {
+ fd800.drv[unit].phys_cylinder = -1;
+ fd800.stat_reg |= status_seek_err;
+ }
+ else
+ {
+ fd800.drv[unit].phys_cylinder = 0;
+ /*fd800.stat_reg |= status_OP_complete;*/
+ }
+
+ return ! seek_complete;
+}
+
+/*
+ Perform a read operation for one sector
+*/
+static void fd800_do_read(void)
+{
+ int data_id;
+
+ if ((fd800.sector == 0) || (fd800.sector > 26))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ return;
+ }
+
+ if (!fd800_find_sector(fd800.unit, fd800.head, fd800.sector, &data_id))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ return;
+ }
+
+ floppy_drive_read_sector_data(&fd800.drv[fd800.unit].img->device(), fd800.head, data_id, fd800.buf, 128);
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_read;
+ fd800.recv_buf = (fd800.buf[fd800.buf_pos<<1] << 8) | fd800.buf[(fd800.buf_pos<<1)+1];
+
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+}
+
+/*
+ Perform a write operation for one sector
+*/
+static void fd800_do_write(void)
+{
+ int data_id;
+
+ if (fd800.drv[fd800.unit].seclen < 64)
+ /* fill with 0s */
+ memset(fd800.buf+(fd800.drv[fd800.unit].seclen<<1), 0, (64-fd800.drv[fd800.unit].seclen)<<1);
+
+ if (!fd800_find_sector(fd800.unit, fd800.head, fd800.sector, &data_id))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ return;
+ }
+
+ floppy_drive_write_sector_data(&fd800.drv[fd800.unit].img->device(), fd800.head, data_id, fd800.buf, 128, fd800.ddam);
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_write;
+
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+}
+
+/*
+ Execute a fdc command
+*/
+static void fd800_do_cmd(void)
+{
+ int unit;
+ int cylinder;
+ int head;
+ int seclen;
+ int sector;
+
+
+ if (fd800.buf_mode != bm_off)
+ { /* All commands in the midst of read or write are interpreted as Stop */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_off;
+
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+
+ return;
+ }
+
+ switch (fd800.cmd_reg >> 12)
+ {
+ case 0: /* select
+ bits 16-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800.drv[unit].img->exists())
+ fd800.stat_reg |= status_drv_not_ready; /* right??? */
+ else if (fd800.drv[unit].img->is_readonly())
+ fd800.stat_reg |= status_write_prot;
+ else
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 1: /* seek
+ bits 16-22: cylinder number (0-76)
+ bits 23-24: 0s
+ bits 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ cylinder = fd800.cmd_reg & 0x7f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800_do_seek(unit, cylinder, head))
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 2: /* restore
+ bits 16-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800_do_restore(unit))
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 3: /* sector length
+ bits 16-22: sector word count (0-64)
+ bits 23-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ seclen = fd800.cmd_reg & 0x7f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if ((seclen > 64) || (seclen == 0))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else
+ {
+ fd800.drv[unit].seclen = seclen;
+ fd800.stat_reg |= status_OP_complete;
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 4: /* read
+ bits 16-20: sector number (1-26)
+ bits 21-23: 0s
+ bit 24: no sequential sectoring (1=active)
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ /*non_seq_mode = (fd800.cmd_reg >> 8) & 1;*/
+ sector = fd800.cmd_reg & 0x1f;
+
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = sector;
+ /*fd800.non_seq_mode = non_seq_mode;*/
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ fd800_do_read();
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 5: /* read ID
+ bits 16-24: 0s
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800_read_id(unit, head, &cylinder, &sector))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ }
+ else
+ {
+ fd800.recv_buf = (cylinder << 8) | sector;
+ fd800.stat_reg |= status_OP_complete;
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 6: /* read unformatted
+ bits 16-20: sector number (1-26)
+ bits 21-24: 0s
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ /* ... */
+ break;
+
+ case 7: /* write
+ bits 16-20: sector number (1-26)
+ bits 21-24: 0s
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ sector = fd800.cmd_reg & 0x1f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if ((fd800.sector == 0) || (fd800.sector > 26))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else
+ {
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = sector;
+ fd800.ddam = 0;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_write;
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 8: /* write delete
+ bits 16-20: sector number (1-26)
+ bits 21-24: 0s
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ sector = fd800.cmd_reg & 0x1f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if ((fd800.sector == 0) || (fd800.sector > 26))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else
+ {
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = sector;
+ fd800.ddam = 1;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_write;
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 9: /* format track
+ bits 16-23: track ID (0-255, normally current cylinder index, or 255 for bad track)
+ bit 24: verify only (1 - verify, 0 - format & verify)
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ /* ... */
+ break;
+
+ case 10: /* load int mask
+ bit 16: bad mask for interrupt (0 = unmask or enable interrupt)
+ bits 17-27: 0s */
+ fd800.interrupt_f_f = fd800.cmd_reg & 1;
+ fd800_field_interrupt();
+ break;
+
+ case 11: /* stop
+ bits 16-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 12: /* step head
+ bits 16-22: track number (0-76)
+ bits 23-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ cylinder = fd800.cmd_reg & 0x7f;
+
+ if (cylinder > 76)
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else if ((fd800.drv[unit].phys_cylinder != -1) || (!fd800_do_restore(unit)))
+ {
+ floppy_drive_seek(&fd800.drv[unit].img->device(), cylinder-fd800.drv[unit].phys_cylinder);
+ fd800.stat_reg |= status_OP_complete;
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 13: /* maintenance commands
+ bits 16-23: according to extended command code
+ bits 24-27: extended command code (0-7) */
+ switch ((fd800.cmd_reg >> 8) & 15)
+ {
+ case 0: /* reset
+ bits 16-23: 0s */
+ /* ... */
+ break;
+ case 1: /* retry inhibit
+ bits 16-23: 0s */
+ /* ... */
+ break;
+ case 2: /* LED test
+ bit 16: 1
+ bits 17-19: 0s
+ bit 20: LED #2 enable
+ bit 21: LED #3 enable
+ bit 22: LED #4 enable
+ bit 23: enable LEDs */
+ /* ... */
+ break;
+ case 3: /* program error (a.k.a. invalid command)
+ bits 16-23: 0s */
+ /* ... */
+ break;
+ case 4: /* memory read
+ bits 16-20: controller memory address (shifted left by 8 to generate 9900 address)
+ bits 21-23: 0s */
+ /* ... */
+ break;
+ case 5: /* RAM load
+ bit 16: 0
+ bits 17-23: RAM offset (shifted left by 1 and offset by >1800 to generate 9900 address) */
+ /* ... */
+ break;
+ case 6: /* RAM run
+ bit 16: 0
+ bits 17-23: RAM offset (shifted left by 1 and offset by >1800 to generate 9900 address) */
+ /* ... */
+ break;
+ case 7: /* power up simulation
+ bits 16-23: 0s */
+ /* ... */
+ break;
+ }
+ /* ... */
+ break;
+
+ case 14: /* IPL
+ bits 16-22: track number (0-76)
+ bit 23: 0
+ bit 24: no sequential sectoring (1=active)
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ /*non_seq_mode = (fd800.cmd_reg >> 8) & 1;*/
+ cylinder = fd800.cmd_reg & 0x7f;
+
+ if (!fd800_do_seek(unit, cylinder, head))
+ {
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = 1;
+ /*fd800.non_seq_mode = non_seq_mode;*/
+
+ fd800_do_read();
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 15: /* Clear Status port
+ bits 16-27: 0s */
+ fd800.stat_reg = 0;
+ fd800_field_interrupt();
+ break;
+ }
+}
+
+/*
+ read one CRU bit
+
+ 0-15: receive buffer
+ 16-31: status:
+ 16: OP complete (1 -> complete???)
+ 17: Xfer ready (XFER) (1 -> ready???)
+ 18: drive not ready
+ 19: data check error
+ 20: seek error/??????
+ 21 invalid command/??????
+ 22: no address mark found/??????
+ 23: equipment check error/??????
+ 24: ID check error
+ 25: ID not found
+ 26: Controller busy (CTLBSY) (0 -> controller is ready)
+ 27: write protect
+ 28: deleted sector detected
+ 29: unit LSB
+ 30: unit MSB
+ 31: Interrupt (CBUSY???) (1 -> controller is ready)
+*/
+ READ8_HANDLER(fd800_cru_r)
+{
+ int reply = 0;
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ /* receive buffer */
+ reply = fd800.recv_buf >> (offset*8);
+ break;
+
+ case 2:
+ case 3:
+ /* status register */
+ reply = fd800.stat_reg >> ((offset-2)*8);
+ break;
+ }
+
+ return reply;
+}
+
+/*
+ write one CRU bit
+
+ 0-15: controller data word (transmit buffer)
+ 16-31: controller command word (command register)
+ 16-23: parameter value
+ 24: flag bit/extended command code
+ 25: head select/extended command code
+ 26: FD unit number LSB/extended command code
+ 27: FD unit number MSB/extended command code
+ 28-31: command code
+*/
+WRITE8_HANDLER(fd800_cru_w)
+{
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ /* transmit buffer */
+ if (data)
+ fd800.xmit_buf |= 1 << offset;
+ else
+ fd800.xmit_buf &= ~(1 << offset);
+ if (offset == 15)
+ {
+ switch (fd800.buf_mode)
+ {
+ case bm_off:
+ break;
+ case bm_read:
+ fd800.buf_pos++;
+ if (fd800.buf_pos == fd800.drv[fd800.unit].seclen)
+ { /* end of sector */
+ if (fd800.sector == 26)
+ { /* end of track -> end command (right???) */
+ fd800.stat_reg &= ~status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete;
+ fd800.stat_reg |= status_interrupt;
+ fd800.buf_mode = bm_off;
+ fd800_field_interrupt();
+ }
+ else
+ { /* read next sector */
+ fd800.sector++;
+ fd800.stat_reg &= ~status_XFER_ready | status_OP_complete | status_interrupt;
+ fd800_do_read();
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ }
+ }
+ else
+ fd800.recv_buf = (fd800.buf[fd800.buf_pos<<1] << 8) | fd800.buf[(fd800.buf_pos<<1)+1];
+ break;
+
+ case bm_write:
+ fd800.buf[fd800.buf_pos<<1] = fd800.xmit_buf >> 8;
+ fd800.buf[(fd800.buf_pos<<1)+1] = fd800.xmit_buf & 0xff;
+ fd800.buf_pos++;
+ if (fd800.buf_pos == fd800.drv[fd800.unit].seclen)
+ { /* end of sector */
+ fd800_do_write();
+ if (fd800.sector == 26)
+ {
+ /* end of track -> end command (right???) */
+ fd800.stat_reg &= ~status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete;
+ fd800.stat_reg |= status_interrupt;
+ fd800.buf_mode = bm_off;
+ fd800_field_interrupt();
+ }
+ else
+ { /* increment to next sector */
+ fd800.sector++;
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ /* command register */
+ if (data)
+ fd800.cmd_reg |= 1 << (offset-16);
+ else
+ fd800.cmd_reg &= ~(1 << (offset-16));
+ if (offset == 31)
+ fd800_do_cmd();
+ break;
+ }
+}