Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 1 | /*************************************************************************
|
| 2 | * *
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 3 | * $Id: wd179x.c 1999 2008-07-22 04:25:28Z hharte $ *
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 4 | * *
|
| 5 | * Copyright (c) 2007-2008 Howard M. Harte. *
|
| 6 | * http://www.hartetec.com *
|
| 7 | * *
|
| 8 | * Permission is hereby granted, free of charge, to any person obtaining *
|
| 9 | * a copy of this software and associated documentation files (the *
|
| 10 | * "Software"), to deal in the Software without restriction, including *
|
| 11 | * without limitation the rights to use, copy, modify, merge, publish, *
|
| 12 | * distribute, sublicense, and/or sell copies of the Software, and to *
|
| 13 | * permit persons to whom the Software is furnished to do so, subject to *
|
| 14 | * the following conditions: *
|
| 15 | * *
|
| 16 | * The above copyright notice and this permission notice shall be *
|
| 17 | * included in all copies or substantial portions of the Software. *
|
| 18 | * *
|
| 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
|
| 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
| 21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
|
| 22 | * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *
|
| 23 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
|
| 24 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
|
| 25 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
| 26 | * *
|
| 27 | * Except as contained in this notice, the name of Howard M. Harte shall *
|
| 28 | * not be used in advertising or otherwise to promote the sale, use or *
|
| 29 | * other dealings in this Software without prior written authorization *
|
| 30 | * Howard M. Harte. *
|
| 31 | * *
|
| 32 | * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *
|
| 33 | * *
|
| 34 | * Module Description: *
|
| 35 | * Generic WD179X Disk Controller module for SIMH. *
|
| 36 | * *
|
| 37 | * Environment: *
|
| 38 | * User mode only *
|
| 39 | * *
|
| 40 | *************************************************************************/
|
| 41 |
|
| 42 | /*#define DBG_MSG */
|
| 43 |
|
| 44 | #include "altairz80_defs.h"
|
| 45 |
|
| 46 | #if defined (_WIN32)
|
| 47 | #include <windows.h>
|
| 48 | #endif
|
| 49 |
|
| 50 | #include "sim_imd.h"
|
| 51 | #include "wd179x.h"
|
| 52 |
|
| 53 | #ifdef DBG_MSG
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 54 | #define DBG_PRINT(args) sim_printf args
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 55 | #else
|
| 56 | #define DBG_PRINT(args)
|
| 57 | #endif
|
| 58 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 59 | #define CROMFDC_SIM_100US 291 /* Number of "ticks" in 100uS, where does this come from? */
|
| 60 | #define CROMFDC_8IN_ROT (167 * CROMFDC_SIM_100US)
|
| 61 | #define CROMFDC_5IN_ROT (200 * CROMFDC_SIM_100US)
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 62 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 63 | /* Debug flags */
|
| 64 | #define ERROR_MSG (1 << 0)
|
| 65 | #define SEEK_MSG (1 << 1)
|
| 66 | #define CMD_MSG (1 << 2)
|
| 67 | #define RD_DATA_MSG (1 << 3)
|
| 68 | #define WR_DATA_MSG (1 << 4)
|
| 69 | #define STATUS_MSG (1 << 5)
|
| 70 | #define FMT_MSG (1 << 6)
|
| 71 | #define VERBOSE_MSG (1 << 7)
|
| 72 |
|
| 73 | #define WD179X_MAX_DRIVES 4
|
| 74 | #define WD179X_SECTOR_LEN 8192
|
| 75 | /* 2^(7 + WD179X_MAX_SEC_LEN) == WD179X_SECTOR_LEN */
|
| 76 | #define WD179X_MAX_SEC_LEN 6
|
| 77 | #define WD179X_MAX_SECTOR 26
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 78 |
|
| 79 | #define CMD_PHASE 0
|
| 80 | #define EXEC_PHASE 1
|
| 81 | #define DATA_PHASE 2
|
| 82 |
|
| 83 | /* Status Bits for Type I Commands */
|
| 84 | #define WD179X_STAT_NOT_READY (1 << 7)
|
| 85 | #define WD179X_STAT_WPROT (1 << 6)
|
| 86 | #define WD179X_STAT_HLD (1 << 5)
|
| 87 | #define WD179X_STAT_SEEK_ERROR (1 << 4)
|
| 88 | #define WD179X_STAT_CRC_ERROR (1 << 3)
|
| 89 | #define WD179X_STAT_TRACK0 (1 << 2)
|
| 90 | #define WD179X_STAT_INDEX (1 << 1)
|
| 91 | #define WD179X_STAT_BUSY (1 << 0)
|
| 92 |
|
| 93 | /* Status Bits for Type II, III Commands */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 94 | /*#define WD179X_STAT_NOT_READY (1 << 7) */
|
| 95 | /*#define WD179X_STAT_WPROT (1 << 6) */
|
| 96 | #define WD179X_STAT_REC_TYPE (1 << 5) /* Also Write Fault */
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 97 | #define WD179X_STAT_NOT_FOUND (1 << 4)
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 98 | /*#define WD179X_STAT_CRC_ERROR (1 << 3) */
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 99 | #define WD179X_STAT_LOST_DATA (1 << 2)
|
| 100 | #define WD179X_STAT_DRQ (1 << 1)
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 101 | /*#define WD179X_STAT_BUSY (1 << 0) */
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 102 |
|
| 103 | typedef union {
|
| 104 | uint8 raw[WD179X_SECTOR_LEN];
|
| 105 | } SECTOR_FORMAT;
|
| 106 |
|
| 107 | typedef struct {
|
| 108 | UNIT *uptr;
|
| 109 | DISK_INFO *imd;
|
| 110 | uint8 ntracks; /* number of tracks */
|
| 111 | uint8 nheads; /* number of heads */
|
| 112 | uint32 sectsize; /* sector size, not including pre/postamble */
|
| 113 | uint8 track; /* Current Track */
|
| 114 | uint8 ready; /* Is drive ready? */
|
| 115 | } WD179X_DRIVE_INFO;
|
| 116 |
|
| 117 | typedef struct {
|
| 118 | PNP_INFO pnp; /* Plug-n-Play Information */
|
| 119 | uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */
|
| 120 | uint8 hld; /* WD179X Head Load Output */
|
| 121 | uint8 drq; /* WD179X DMA Request Output */
|
| 122 | uint8 ddens; /* WD179X Double-Density Input */
|
| 123 | uint8 fdc_head; /* H Head Number */
|
| 124 | uint8 sel_drive; /* Currently selected drive */
|
| 125 | uint8 drivetype; /* 8 or 5 depending on disk type. */
|
| 126 | uint8 fdc_status; /* WD179X Status Register */
|
| 127 | uint8 verify; /* WD179X Type 1 command Verify flag */
|
| 128 | uint8 fdc_data; /* WD179X Data Register */
|
| 129 | uint8 fdc_read; /* TRUE when reading */
|
| 130 | uint8 fdc_write; /* TRUE when writing */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 131 | uint8 fdc_write_track; /* TRUE when writing an entire track */
|
| 132 | uint8 fdc_fmt_state; /* Format track statemachine state */
|
| 133 | uint8 fdc_gap[4]; /* Gap I - Gap IV lengths */
|
| 134 | uint8 fdc_fmt_sector_count; /* sector count for format track */
|
| 135 | uint8 fdc_sectormap[WD179X_MAX_SECTOR]; /* Physical to logical sector map */
|
| 136 | uint8 fdc_header_index; /* Index into header */
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 137 | uint8 fdc_read_addr; /* TRUE when READ ADDRESS command is in progress */
|
| 138 | uint8 fdc_multiple; /* TRUE for multi-sector read/write */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 139 | uint16 fdc_datacount; /* Read or Write data remaining transfer length */
|
| 140 | uint16 fdc_dataindex; /* index of current byte in sector data */
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 141 | uint8 index_pulse_wait; /* TRUE if waiting for interrupt on next index pulse. */
|
| 142 | uint8 fdc_sector; /* R Record (Sector) */
|
| 143 | uint8 fdc_sec_len; /* N Sector Length */
|
| 144 | int8 step_dir;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 145 | uint8 cmdtype; /* Type of current/former command */
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 146 | WD179X_DRIVE_INFO drive[WD179X_MAX_DRIVES];
|
| 147 | } WD179X_INFO;
|
| 148 |
|
| 149 | static SECTOR_FORMAT sdata;
|
| 150 | extern uint32 PCX;
|
| 151 | extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
| 152 | extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
| 153 | extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
| 154 | int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
Bob Supnik | 35eac70 | 2010-04-26 06:04:00 -0700 | [diff] [blame] | 155 | extern int32 find_unit_index (UNIT *uptr);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 156 |
|
| 157 | t_stat wd179x_svc (UNIT *uptr);
|
| 158 |
|
| 159 | /* These are needed for DMA. PIO Mode has not been implemented yet. */
|
| 160 | extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
| 161 | extern uint8 GetBYTEWrapper(const uint32 Addr);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 162 |
|
| 163 | #define UNIT_V_WD179X_WLK (UNIT_V_UF + 0) /* write locked */
|
| 164 | #define UNIT_WD179X_WLK (1 << UNIT_V_WD179X_WLK)
|
| 165 | #define UNIT_V_WD179X_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
| 166 | #define UNIT_WD179X_VERBOSE (1 << UNIT_V_WD179X_VERBOSE)
|
| 167 | #define WD179X_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
| 168 | #define WD179X_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 169 |
|
| 170 | /* Write Track (format) Statemachine states */
|
| 171 | #define FMT_GAP1 1
|
| 172 | #define FMT_GAP2 2
|
| 173 | #define FMT_GAP3 3
|
| 174 | #define FMT_GAP4 4
|
| 175 | #define FMT_HEADER 5
|
| 176 | #define FMT_DATA 6
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 177 |
|
| 178 | /* WD179X Commands */
|
| 179 | #define WD179X_RESTORE 0x00 /* Type I */
|
| 180 | #define WD179X_SEEK 0x10 /* Type I */
|
| 181 | #define WD179X_STEP 0x20 /* Type I */
|
| 182 | #define WD179X_STEP_U 0x30 /* Type I */
|
| 183 | #define WD179X_STEP_IN 0x40 /* Type I */
|
| 184 | #define WD179X_STEP_IN_U 0x50 /* Type I */
|
| 185 | #define WD179X_STEP_OUT 0x60 /* Type I */
|
| 186 | #define WD179X_STEP_OUT_U 0x70 /* Type I */
|
| 187 | #define WD179X_READ_REC 0x80 /* Type II */
|
| 188 | #define WD179X_READ_RECS 0x90 /* Type II */
|
| 189 | #define WD179X_WRITE_REC 0xA0 /* Type II */
|
| 190 | #define WD179X_WRITE_RECS 0xB0 /* Type II */
|
| 191 | #define WD179X_READ_ADDR 0xC0 /* Type III */
|
| 192 | #define WD179X_FORCE_INTR 0xD0 /* Type IV */
|
| 193 | #define WD179X_READ_TRACK 0xE0 /* Type III */
|
| 194 | #define WD179X_WRITE_TRACK 0xF0 /* Type III */
|
| 195 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 196 | static int32 wd179xdev(const int32 port, const int32 io, const int32 data);
|
| 197 | static t_stat wd179x_reset(DEVICE *dptr);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 198 | uint8 floorlog2(unsigned int n);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 199 |
|
| 200 | WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } };
|
| 201 | WD179X_INFO *wd179x_info = &wd179x_info_data;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 202 | WD179X_INFO_PUB *wd179x_infop = (WD179X_INFO_PUB *)&wd179x_info_data;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 203 |
|
| 204 | static UNIT wd179x_unit[] = {
|
| 205 | { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 },
|
| 206 | { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 },
|
| 207 | { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 },
|
| 208 | { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }
|
| 209 | };
|
| 210 |
|
Peter Schorn | 589aca1 | 2014-05-27 20:01:30 +0200 | [diff] [blame] | 211 | #define WD179X_NAME "Western Digital FDC Core WD179X"
|
| 212 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 213 | static MTAB wd179x_mod[] = {
|
Peter Schorn | 589aca1 | 2014-05-27 20:01:30 +0200 | [diff] [blame] | 214 | { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
| 215 | &set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
| 216 | { UNIT_WD179X_WLK, 0, "WRTENB", "WRTENB",
|
| 217 | NULL, NULL, NULL, "Enables " WD179X_NAME "n for writing" },
|
| 218 | { UNIT_WD179X_WLK, UNIT_WD179X_WLK, "WRTLCK", "WRTLCK",
|
| 219 | NULL, NULL, NULL, "Locks " WD179X_NAME "n for writing" },
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 220 | /* quiet, no warning messages */
|
Peter Schorn | 589aca1 | 2014-05-27 20:01:30 +0200 | [diff] [blame] | 221 | { UNIT_WD179X_VERBOSE, 0, "QUIET", "QUIET",
|
| 222 | NULL, NULL, NULL, "No verbose messages for unit " WD179X_NAME "n" },
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 223 | /* verbose, show warning messages */
|
Peter Schorn | 589aca1 | 2014-05-27 20:01:30 +0200 | [diff] [blame] | 224 | { UNIT_WD179X_VERBOSE, UNIT_WD179X_VERBOSE, "VERBOSE", "VERBOSE",
|
| 225 | NULL, NULL, NULL, "Verbose messages for unit " WD179X_NAME "n" },
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 226 | { 0 }
|
| 227 | };
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 228 |
|
| 229 | /* Debug Flags */
|
| 230 | static DEBTAB wd179x_dt[] = {
|
Peter Schorn | 589aca1 | 2014-05-27 20:01:30 +0200 | [diff] [blame] | 231 | { "ERROR", ERROR_MSG, "Error messages" },
|
| 232 | { "SEEK", SEEK_MSG, "Seek messages" },
|
| 233 | { "CMD", CMD_MSG, "Command messages" },
|
| 234 | { "READ", RD_DATA_MSG, "Read messages" },
|
| 235 | { "WRITE", WR_DATA_MSG, "Write messages" },
|
| 236 | { "STATUS", STATUS_MSG, "Status messages" },
|
| 237 | { "FMT", FMT_MSG, "Format messages" },
|
| 238 | { "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
| 239 | { NULL, 0 }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 240 | };
|
| 241 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 242 | DEVICE wd179x_dev = {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 243 | "WD179X", wd179x_unit, NULL, wd179x_mod,
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 244 | WD179X_MAX_DRIVES, 10, 31, 1, WD179X_MAX_DRIVES, WD179X_MAX_DRIVES,
|
| 245 | NULL, NULL, &wd179x_reset,
|
| 246 | NULL, &wd179x_attach, &wd179x_detach,
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 247 | &wd179x_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
Peter Schorn | 589aca1 | 2014-05-27 20:01:30 +0200 | [diff] [blame] | 248 | wd179x_dt, NULL, WD179X_NAME
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 249 | };
|
| 250 |
|
| 251 | /* Unit service routine */
|
| 252 | /* Used to generate INDEX pulses in response to a FORCE_INTR command */
|
| 253 | t_stat wd179x_svc (UNIT *uptr)
|
| 254 | {
|
| 255 |
|
| 256 | if(wd179x_info->index_pulse_wait == TRUE) {
|
| 257 | wd179x_info->index_pulse_wait = FALSE;
|
| 258 | wd179x_info->intrq = 1;
|
| 259 | }
|
| 260 |
|
| 261 | return SCPE_OK;
|
| 262 | }
|
| 263 |
|
| 264 |
|
| 265 | /* Reset routine */
|
| 266 | static t_stat wd179x_reset(DEVICE *dptr)
|
| 267 | {
|
| 268 | PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
|
| 269 |
|
| 270 | if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
|
| 271 | sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &wd179xdev, TRUE);
|
| 272 | } else {
|
| 273 | /* Connect I/O Ports at base address */
|
| 274 | if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &wd179xdev, FALSE) != 0) {
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 275 | sim_printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 276 | return SCPE_ARG;
|
| 277 | }
|
| 278 | }
|
| 279 | return SCPE_OK;
|
| 280 | }
|
| 281 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 282 | void wd179x_external_restore(void)
|
| 283 | {
|
| 284 | WD179X_DRIVE_INFO *pDrive;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 285 |
|
| 286 | if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 287 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 288 | " Illegal drive selected, cannot restore.\n", PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 289 | return;
|
| 290 | }
|
| 291 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 292 | pDrive = &wd179x_info->drive[wd179x_info->sel_drive];
|
| 293 |
|
| 294 | if(pDrive->uptr == NULL) {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 295 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 296 | " No drive selected, cannot restore.\n", PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 297 | return;
|
| 298 | }
|
| 299 |
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 300 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 301 | " External Restore drive to track 0\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 302 |
|
| 303 | pDrive->track = 0;
|
| 304 |
|
| 305 | }
|
| 306 |
|
| 307 | /* Attach routine */
|
| 308 | t_stat wd179x_attach(UNIT *uptr, char *cptr)
|
| 309 | {
|
| 310 | char header[4];
|
| 311 | t_stat r;
|
| 312 | int32 i = 0;
|
| 313 |
|
| 314 | r = attach_unit(uptr, cptr); /* attach unit */
|
| 315 | if ( r != SCPE_OK) /* error? */
|
| 316 | return r;
|
| 317 |
|
| 318 | /* Determine length of this disk */
|
| 319 | uptr->capac = sim_fsize(uptr->fileref);
|
| 320 |
|
| 321 | i = find_unit_index(uptr);
|
| 322 |
|
| 323 | if (i == -1) {
|
| 324 | return (SCPE_IERR);
|
| 325 | }
|
| 326 |
|
| 327 | DBG_PRINT(("Attach WD179X%d\n", i));
|
| 328 | wd179x_info->drive[i].uptr = uptr;
|
| 329 |
|
| 330 | /* Default to drive not ready */
|
| 331 | wd179x_info->drive[i].ready = 0;
|
| 332 |
|
| 333 | if(uptr->capac > 0) {
|
Bob Supnik | 35eac70 | 2010-04-26 06:04:00 -0700 | [diff] [blame] | 334 | char *rtn = fgets(header, 4, uptr->fileref);
|
| 335 | if ((rtn != NULL) && strncmp(header, "IMD", 3)) {
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 336 | sim_printf("WD179X: Only IMD disk images are supported\n");
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 337 | wd179x_info->drive[i].uptr = NULL;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 338 | return SCPE_OPENERR;
|
| 339 | }
|
| 340 | } else {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 341 | /* create a disk image file in IMD format. */
|
| 342 | if (diskCreate(uptr->fileref, "$Id: wd179x.c 1999 2008-07-22 04:25:28Z hharte $") != SCPE_OK) {
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 343 | sim_printf("WD179X: Failed to create IMD disk.\n");
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 344 | wd179x_info->drive[i].uptr = NULL;
|
| 345 | return SCPE_OPENERR;
|
| 346 | }
|
| 347 | uptr->capac = sim_fsize(uptr->fileref);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 348 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 349 |
|
| 350 | uptr->u3 = IMAGE_TYPE_IMD;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 351 |
|
| 352 | if (uptr->flags & UNIT_WD179X_VERBOSE)
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 353 | sim_printf("WD179X%d: attached to '%s', type=%s, len=%d\n", i, cptr,
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 354 | uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",
|
| 355 | uptr->capac);
|
| 356 |
|
| 357 | if(uptr->u3 == IMAGE_TYPE_IMD) {
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 358 | if (uptr->flags & UNIT_WD179X_VERBOSE)
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 359 | sim_printf("--------------------------------------------------------\n");
|
Peter Schorn | 977712b | 2014-09-21 09:42:26 +0200 | [diff] [blame] | 360 | wd179x_info->drive[i].imd = diskOpenEx(uptr->fileref, uptr->flags & UNIT_WD179X_VERBOSE,
|
| 361 | &wd179x_dev, VERBOSE_MSG, VERBOSE_MSG);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 362 | if (uptr->flags & UNIT_WD179X_VERBOSE)
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 363 | sim_printf("\n");
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 364 | if (wd179x_info->drive[i].imd == NULL) {
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 365 | sim_printf("WD179X: IMD disk corrupt.\n");
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 366 | wd179x_info->drive[i].uptr = NULL;
|
| 367 | return SCPE_OPENERR;
|
| 368 | }
|
| 369 |
|
| 370 | /* Write-protect the unit if IMD think's it's writelocked. */
|
| 371 | if(imdIsWriteLocked(wd179x_info->drive[i].imd)) {
|
| 372 | uptr->flags |= UNIT_WD179X_WLK;
|
| 373 | }
|
| 374 |
|
| 375 | wd179x_info->drive[i].ready = 1;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 376 | } else {
|
| 377 | wd179x_info->drive[i].imd = NULL;
|
| 378 | }
|
| 379 |
|
| 380 | wd179x_info->fdc_sec_len = 0; /* 128 byte sectors, fixme */
|
| 381 | wd179x_info->sel_drive = 0;
|
| 382 |
|
| 383 | return SCPE_OK;
|
| 384 | }
|
| 385 |
|
| 386 |
|
| 387 | /* Detach routine */
|
| 388 | t_stat wd179x_detach(UNIT *uptr)
|
| 389 | {
|
| 390 | t_stat r;
|
| 391 | int8 i;
|
| 392 |
|
| 393 | i = find_unit_index(uptr);
|
| 394 |
|
| 395 | if (i == -1) {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 396 | return SCPE_IERR;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 397 | }
|
| 398 |
|
| 399 | DBG_PRINT(("Detach WD179X%d\n", i));
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 400 | r = diskClose(&wd179x_info->drive[i].imd);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 401 | wd179x_info->drive[i].ready = 0;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 402 | if (r != SCPE_OK)
|
| 403 | return r;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 404 |
|
| 405 | r = detach_unit(uptr); /* detach unit */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 406 | if (r != SCPE_OK)
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 407 | return r;
|
| 408 |
|
| 409 | return SCPE_OK;
|
| 410 | }
|
| 411 |
|
| 412 |
|
| 413 | static int32 wd179xdev(const int32 port, const int32 io, const int32 data)
|
| 414 | {
|
| 415 | DBG_PRINT(("WD179X: " ADDRESS_FORMAT " %s, Port 0x%02x Data 0x%02x" NLP,
|
| 416 | PCX, io ? "OUT" : " IN", port, data));
|
| 417 | if(io) {
|
| 418 | WD179X_Write(port, data);
|
| 419 | return 0;
|
| 420 | } else {
|
| 421 | return(WD179X_Read(port));
|
| 422 | }
|
| 423 | }
|
| 424 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 425 | uint8 floorlog2(unsigned int n)
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 426 | {
|
| 427 | /* Compute log2(n) */
|
| 428 | uint8 r = 0;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 429 | if (n >= 1<<16) {
|
| 430 | n >>=16;
|
| 431 | r += 16;
|
| 432 | }
|
| 433 | if (n >= 1<< 8) {
|
| 434 | n >>= 8;
|
| 435 | r += 8;
|
| 436 | }
|
| 437 | if (n >= 1<< 4) {
|
| 438 | n >>= 4;
|
| 439 | r += 4;
|
| 440 | }
|
| 441 | if (n >= 1<< 2) {
|
| 442 | n >>= 2;
|
| 443 | r += 2;
|
| 444 | }
|
| 445 | if (n >= 1<< 1) {
|
| 446 | r += 1;
|
| 447 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 448 | return ((n == 0) ? (0xFF) : r); /* 0xFF is error return value */
|
| 449 | }
|
| 450 |
|
| 451 | uint8 WD179X_Read(const uint32 Addr)
|
| 452 | {
|
| 453 | uint8 cData;
|
| 454 | WD179X_DRIVE_INFO *pDrive;
|
Mark Pizzolato | cf280ad | 2012-03-20 18:55:45 -0700 | [diff] [blame] | 455 | uint32 flags = 0;
|
| 456 | uint32 readlen;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 457 | int status;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 458 |
|
| 459 | if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
|
| 460 | return 0xFF;
|
| 461 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 462 |
|
| 463 | pDrive = &wd179x_info->drive[wd179x_info->sel_drive];
|
| 464 |
|
| 465 | if(pDrive->uptr == NULL) {
|
| 466 | return 0xFF;
|
| 467 | }
|
| 468 |
|
| 469 | cData = 0x00;
|
| 470 |
|
| 471 | switch(Addr & 0x3) {
|
| 472 | case WD179X_STATUS:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 473 | /* Fix up status based on Command Type */
|
| 474 | if((wd179x_info->cmdtype == 1) || (wd179x_info->cmdtype == 4)) {
|
| 475 | wd179x_info->fdc_status ^= WD179X_STAT_INDEX; /* Generate Index pulses */
|
| 476 | wd179x_info->fdc_status &= ~WD179X_STAT_TRACK0;
|
| 477 | wd179x_info->fdc_status |= (pDrive->track == 0) ? WD179X_STAT_TRACK0 : 0;
|
| 478 | } else if(wd179x_info->cmdtype == 4) {
|
| 479 | }
|
| 480 | else {
|
| 481 | wd179x_info->fdc_status &= ~WD179X_STAT_INDEX; /* Mask index pulses */
|
| 482 | wd179x_info->fdc_status |= (wd179x_info->drq) ? WD179X_STAT_DRQ : 0;
|
| 483 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 484 | cData = (pDrive->ready == 0) ? WD179X_STAT_NOT_READY : 0;
|
| 485 | cData |= wd179x_info->fdc_status; /* Status Register */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 486 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 487 | " RD STATUS = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 488 | wd179x_info->intrq = 0;
|
| 489 | break;
|
| 490 | case WD179X_TRACK:
|
| 491 | cData = pDrive->track;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 492 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 493 | " RD TRACK = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 494 | break;
|
| 495 | case WD179X_SECTOR:
|
| 496 | cData = wd179x_info->fdc_sector;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 497 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 498 | " RD SECT = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 499 | break;
|
| 500 | case WD179X_DATA:
|
| 501 | cData = 0xFF; /* Return High-Z data */
|
| 502 | if(wd179x_info->fdc_read == TRUE) {
|
| 503 | if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) {
|
| 504 | cData = sdata.raw[wd179x_info->fdc_dataindex];
|
| 505 | if(wd179x_info->fdc_read_addr == TRUE) {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 506 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 507 | " READ_ADDR[%d] = 0x%02x\n",
|
| 508 | wd179x_info->sel_drive, PCX,
|
| 509 | wd179x_info->fdc_dataindex, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 510 | }
|
| 511 |
|
| 512 | wd179x_info->fdc_dataindex++;
|
| 513 | if(wd179x_info->fdc_dataindex == wd179x_info->fdc_datacount) {
|
| 514 | if(wd179x_info->fdc_multiple == FALSE) {
|
| 515 | wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */
|
| 516 | wd179x_info->drq = 0;
|
| 517 | wd179x_info->intrq = 1;
|
| 518 | wd179x_info->fdc_read = FALSE;
|
| 519 | wd179x_info->fdc_read_addr = FALSE;
|
| 520 | } else {
|
| 521 |
|
| 522 | /* Compute Sector Size */
|
| 523 | wd179x_info->fdc_sec_len = floorlog2(
|
| 524 | pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 525 | if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 526 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 527 | wd179x_info->fdc_sec_len = 0;
|
| 528 | return cData;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 529 | }
|
| 530 |
|
| 531 | wd179x_info->fdc_sector ++;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 532 | sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 533 |
|
| 534 | status = sectRead(pDrive->imd,
|
| 535 | pDrive->track,
|
| 536 | wd179x_info->fdc_head,
|
| 537 | wd179x_info->fdc_sector,
|
| 538 | sdata.raw,
|
| 539 | 128 << wd179x_info->fdc_sec_len,
|
| 540 | &flags,
|
| 541 | &readlen);
|
| 542 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 543 | if(status == SCPE_OK) {
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 544 | wd179x_info->fdc_status = (WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Set DRQ, BUSY */
|
| 545 | wd179x_info->drq = 1;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 546 | wd179x_info->intrq = 0;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 547 | wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len;
|
| 548 | wd179x_info->fdc_dataindex = 0;
|
| 549 | wd179x_info->fdc_read = TRUE;
|
| 550 | wd179x_info->fdc_read_addr = FALSE;
|
| 551 | } else {
|
| 552 | wd179x_info->fdc_status = 0; /* Clear DRQ, BUSY */
|
| 553 | wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND;
|
| 554 | wd179x_info->drq = 0;
|
| 555 | wd179x_info->intrq = 1;
|
| 556 | wd179x_info->fdc_read = FALSE;
|
| 557 | wd179x_info->fdc_read_addr = FALSE;
|
| 558 | }
|
| 559 | }
|
| 560 | }
|
| 561 | }
|
| 562 | }
|
| 563 | break;
|
| 564 | }
|
| 565 |
|
| 566 | return (cData);
|
| 567 | }
|
| 568 |
|
| 569 | /*
|
| 570 | * Command processing happens in three stages:
|
| 571 | * 1. Flags and initial conditions are set up based on the Type of the command.
|
| 572 | * 2. The execution phase takes place.
|
| 573 | * 3. Status is updated based on the Type and outcome of the command execution.
|
| 574 | *
|
| 575 | * See the WD179x-02 Datasheet available on www.hartetechnologies.com/manuals/
|
| 576 | *
|
| 577 | */
|
| 578 | static uint8 Do1793Command(uint8 cCommand)
|
| 579 | {
|
| 580 | uint8 result = 0;
|
| 581 | WD179X_DRIVE_INFO *pDrive;
|
Mark Pizzolato | cf280ad | 2012-03-20 18:55:45 -0700 | [diff] [blame] | 582 | uint32 flags = 0;
|
| 583 | uint32 readlen;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 584 | int status;
|
| 585 |
|
| 586 | if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
|
| 587 | return 0xFF;
|
| 588 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 589 |
|
| 590 | pDrive = &wd179x_info->drive[wd179x_info->sel_drive];
|
| 591 |
|
| 592 | if(pDrive->uptr == NULL) {
|
| 593 | return 0xFF;
|
| 594 | }
|
| 595 |
|
| 596 | if(wd179x_info->fdc_status & WD179X_STAT_BUSY) {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 597 | if(((cCommand & 0xF0) != WD179X_FORCE_INTR)) { /* && ((cCommand & 0xF0) != WD179X_RESTORE)) { */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 598 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 599 | " ERROR: Command 0x%02x ignored because controller is BUSY\n\n",
|
| 600 | wd179x_info->sel_drive, PCX, cCommand);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 601 | }
|
| 602 | return 0xFF;
|
| 603 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 604 |
|
| 605 | wd179x_info->fdc_status &= ~WD179X_STAT_NOT_READY;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 606 |
|
| 607 | /* Extract Type-specific command flags, and set initial conditions */
|
| 608 | switch(cCommand & 0xF0) {
|
| 609 | /* Type I Commands */
|
| 610 | case WD179X_RESTORE:
|
| 611 | case WD179X_SEEK:
|
| 612 | case WD179X_STEP:
|
| 613 | case WD179X_STEP_U:
|
| 614 | case WD179X_STEP_IN:
|
| 615 | case WD179X_STEP_IN_U:
|
| 616 | case WD179X_STEP_OUT:
|
| 617 | case WD179X_STEP_OUT_U:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 618 | wd179x_info->cmdtype = 1;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 619 | wd179x_info->fdc_status |= WD179X_STAT_BUSY; /* Set BUSY */
|
| 620 | wd179x_info->fdc_status &= ~(WD179X_STAT_CRC_ERROR | WD179X_STAT_SEEK_ERROR | WD179X_STAT_DRQ);
|
| 621 | wd179x_info->intrq = 0;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 622 | wd179x_info->hld = cCommand & 0x08;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 623 | wd179x_info->verify = cCommand & 0x04;
|
| 624 | break;
|
| 625 | /* Type II Commands */
|
| 626 | case WD179X_READ_REC:
|
| 627 | case WD179X_READ_RECS:
|
| 628 | case WD179X_WRITE_REC:
|
| 629 | case WD179X_WRITE_RECS:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 630 | wd179x_info->cmdtype = 2;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 631 | wd179x_info->fdc_status = WD179X_STAT_BUSY; /* Set BUSY, clear all others */
|
| 632 | wd179x_info->intrq = 0;
|
| 633 | wd179x_info->hld = 1; /* Load the head immediately, E Flag not checked. */
|
| 634 | break;
|
| 635 | /* Type III Commands */
|
| 636 | case WD179X_READ_ADDR:
|
| 637 | case WD179X_READ_TRACK:
|
| 638 | case WD179X_WRITE_TRACK:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 639 | wd179x_info->cmdtype = 3;
|
| 640 | break;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 641 | /* Type IV Commands */
|
| 642 | case WD179X_FORCE_INTR:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 643 | wd179x_info->cmdtype = 4;
|
| 644 | break;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 645 | default:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 646 | wd179x_info->cmdtype = 0;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 647 | break;
|
| 648 | }
|
| 649 |
|
| 650 | switch(cCommand & 0xF0) {
|
| 651 | /* Type I Commands */
|
| 652 | case WD179X_RESTORE:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 653 | sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 654 | " CMD=RESTORE %s\n", wd179x_info->sel_drive, PCX,
|
| 655 | wd179x_info->verify ? "[VERIFY]" : "");
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 656 | pDrive->track = 0;
|
| 657 | wd179x_info->intrq = 1;
|
| 658 | break;
|
| 659 | case WD179X_SEEK:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 660 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 661 | " CMD=SEEK, track=%d, new=%d\n", wd179x_info->sel_drive,
|
| 662 | PCX, pDrive->track, wd179x_info->fdc_data);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 663 | pDrive->track = wd179x_info->fdc_data;
|
| 664 | break;
|
| 665 | case WD179X_STEP:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 666 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 667 | " CMD=STEP\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 668 | break;
|
| 669 | case WD179X_STEP_U:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 670 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 671 | " CMD=STEP_U dir=%d\n", wd179x_info->sel_drive,
|
| 672 | PCX, wd179x_info->step_dir);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 673 | if(wd179x_info->step_dir == 1) {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 674 | if (pDrive->track < 255)
|
| 675 | pDrive->track++;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 676 | } else if (wd179x_info->step_dir == -1) {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 677 | if (pDrive->track > 0)
|
| 678 | pDrive->track--;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 679 | } else {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 680 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 681 | " ERROR: undefined direction for STEP\n",
|
| 682 | wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 683 | }
|
| 684 | break;
|
| 685 | case WD179X_STEP_IN:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 686 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 687 | " CMD=STEP_IN\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 688 | break;
|
| 689 | case WD179X_STEP_IN_U:
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 690 | if (pDrive->track < 255)
|
| 691 | pDrive->track++;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 692 | wd179x_info->step_dir = 1;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 693 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 694 | " CMD=STEP_IN_U, Track=%d\n", wd179x_info->sel_drive,
|
| 695 | PCX, pDrive->track);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 696 | break;
|
| 697 | case WD179X_STEP_OUT:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 698 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 699 | " CMD=STEP_OUT\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 700 | break;
|
| 701 | case WD179X_STEP_OUT_U:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 702 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 703 | " CMD=STEP_OUT_U\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 704 | if (pDrive->track > 0)
|
| 705 | pDrive->track--;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 706 | wd179x_info->step_dir = -1;
|
| 707 | break;
|
| 708 | /* Type II Commands */
|
| 709 | case WD179X_READ_REC:
|
| 710 | case WD179X_READ_RECS:
|
| 711 | /* Compute Sector Size */
|
| 712 | wd179x_info->fdc_sec_len = floorlog2(
|
| 713 | pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 714 | if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 715 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 716 | " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 717 | wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
|
| 718 | wd179x_info->fdc_status &= ~WD179X_STAT_BUSY;
|
| 719 | wd179x_info->intrq = 1;
|
| 720 | wd179x_info->drq = 0;
|
| 721 | wd179x_info->fdc_sec_len = 0;
|
| 722 | return 0xFF;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 723 | }
|
| 724 |
|
| 725 | wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 726 | sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 727 | " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d\n",
|
| 728 | wd179x_info->sel_drive, PCX, pDrive->track,
|
| 729 | wd179x_info->fdc_head, wd179x_info->fdc_sector,
|
| 730 | wd179x_info->fdc_multiple ? "Multiple" : "Single",
|
| 731 | wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 732 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 733 | if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) {
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 734 | wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 735 | wd179x_info->fdc_status &= ~WD179X_STAT_BUSY;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 736 | wd179x_info->intrq = 1;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 737 | wd179x_info->drq = 0;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 738 | } else {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 739 |
|
| 740 | status = sectRead(pDrive->imd,
|
| 741 | pDrive->track,
|
| 742 | wd179x_info->fdc_head,
|
| 743 | wd179x_info->fdc_sector,
|
| 744 | sdata.raw,
|
| 745 | 128 << wd179x_info->fdc_sec_len,
|
| 746 | &flags,
|
| 747 | &readlen);
|
| 748 |
|
| 749 | if(status == SCPE_OK) {
|
| 750 | wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */
|
| 751 | wd179x_info->drq = 1;
|
| 752 | wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len;
|
| 753 | wd179x_info->fdc_dataindex = 0;
|
| 754 | wd179x_info->fdc_write = FALSE;
|
| 755 | wd179x_info->fdc_write_track = FALSE;
|
| 756 | wd179x_info->fdc_read = TRUE;
|
| 757 | wd179x_info->fdc_read_addr = FALSE;
|
| 758 | } else {
|
| 759 | wd179x_info->fdc_status = 0; /* Clear DRQ, BUSY */
|
| 760 | wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND;
|
| 761 | wd179x_info->fdc_status &= ~WD179X_STAT_BUSY;
|
| 762 | wd179x_info->drq = 0;
|
| 763 | wd179x_info->intrq = 1;
|
| 764 | wd179x_info->fdc_read = FALSE;
|
| 765 | wd179x_info->fdc_read_addr = FALSE;
|
| 766 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 767 | }
|
| 768 | break;
|
| 769 | case WD179X_WRITE_RECS:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 770 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 771 | " Error: WRITE_RECS not implemented.\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 772 | break;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 773 | case WD179X_WRITE_REC:
|
| 774 | /* Compute Sector Size */
|
| 775 | wd179x_info->fdc_sec_len = floorlog2(
|
| 776 | pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 777 | if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 778 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 779 | " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 780 | wd179x_info->fdc_sec_len = 0;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 781 | }
|
| 782 |
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 783 | sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 784 | " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s.\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, (cCommand & 0x10) ? "Multiple" : "Single");
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 785 | wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */
|
| 786 | wd179x_info->drq = 1;
|
| 787 | wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len;
|
| 788 | wd179x_info->fdc_dataindex = 0;
|
| 789 | wd179x_info->fdc_write = TRUE;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 790 | wd179x_info->fdc_write_track = FALSE;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 791 | wd179x_info->fdc_read = FALSE;
|
| 792 | wd179x_info->fdc_read_addr = FALSE;
|
| 793 |
|
| 794 | sdata.raw[wd179x_info->fdc_dataindex] = wd179x_info->fdc_data;
|
| 795 | break;
|
| 796 | /* Type III Commands */
|
| 797 | case WD179X_READ_ADDR:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 798 | sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 799 | " CMD=READ_ADDR, T:%d/S:%d, %s\n", wd179x_info->sel_drive,
|
| 800 | PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->ddens ? "DD" : "SD");
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 801 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 802 | /* For some reason 86-DOS tries to use this track, force it to 0. Need to investigate this more. */
|
| 803 | if (pDrive->track == 0xFF)
|
| 804 | pDrive->track=0;
|
| 805 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 806 | /* Compute Sector Size */
|
| 807 | wd179x_info->fdc_sec_len = floorlog2(
|
| 808 | pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 809 | if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 810 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 811 | " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 812 | wd179x_info->fdc_sec_len = 0;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 813 | }
|
| 814 |
|
| 815 | if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) {
|
| 816 | wd179x_info->fdc_status = WD179X_STAT_NOT_FOUND; /* Sector not found */
|
| 817 | wd179x_info->intrq = 1;
|
| 818 | } else {
|
| 819 | wd179x_info->fdc_status = (WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Set DRQ, BUSY */
|
| 820 | wd179x_info->drq = 1;
|
| 821 | wd179x_info->fdc_datacount = 6;
|
| 822 | wd179x_info->fdc_dataindex = 0;
|
| 823 | wd179x_info->fdc_read = TRUE;
|
| 824 | wd179x_info->fdc_read_addr = TRUE;
|
| 825 |
|
| 826 | sdata.raw[0] = pDrive->track;
|
| 827 | sdata.raw[1] = wd179x_info->fdc_head;
|
| 828 | sdata.raw[2] = wd179x_info->fdc_sector;
|
| 829 | sdata.raw[3] = wd179x_info->fdc_sec_len;
|
| 830 | sdata.raw[4] = 0xAA; /* CRC1 */
|
| 831 | sdata.raw[5] = 0x55; /* CRC2 */
|
| 832 |
|
| 833 | wd179x_info->fdc_sector = pDrive->track;
|
| 834 | wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */
|
| 835 | wd179x_info->intrq = 1;
|
| 836 | }
|
| 837 | break;
|
| 838 | case WD179X_READ_TRACK:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 839 | sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 840 | " CMD=READ_TRACK\n", wd179x_info->sel_drive, PCX);
|
| 841 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 842 | " Error: READ_TRACK not implemented.\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 843 | break;
|
| 844 | case WD179X_WRITE_TRACK:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 845 | sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 846 | " CMD=WRITE_TRACK\n", wd179x_info->sel_drive, PCX);
|
| 847 | sim_debug(FMT_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 848 | " CMD=WRITE_TRACK, T:%d/S:%d.\n", wd179x_info->sel_drive,
|
| 849 | PCX, pDrive->track, wd179x_info->fdc_head);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 850 | wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */
|
| 851 | wd179x_info->drq = 1;
|
| 852 | wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len;
|
| 853 | wd179x_info->fdc_dataindex = 0;
|
| 854 | wd179x_info->fdc_write = FALSE;
|
| 855 | wd179x_info->fdc_write_track = TRUE;
|
| 856 | wd179x_info->fdc_read = FALSE;
|
| 857 | wd179x_info->fdc_read_addr = FALSE;
|
| 858 | wd179x_info->fdc_fmt_state = FMT_GAP1; /* TRUE when writing an entire track */
|
| 859 | wd179x_info->fdc_fmt_sector_count = 0;
|
| 860 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 861 | break;
|
| 862 | /* Type IV Commands */
|
| 863 | case WD179X_FORCE_INTR:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 864 | sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 865 | " CMD=FORCE_INTR\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 866 | if((cCommand & 0x0F) == 0) { /* I0-I3 == 0, no intr, but clear BUSY and terminate command */
|
| 867 | wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */
|
| 868 | wd179x_info->drq = 0;
|
| 869 | wd179x_info->fdc_write = FALSE;
|
| 870 | wd179x_info->fdc_read = FALSE;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 871 | wd179x_info->fdc_write_track = FALSE;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 872 | wd179x_info->fdc_read_addr = FALSE;
|
| 873 | wd179x_info->fdc_datacount = 0;
|
| 874 | wd179x_info->fdc_dataindex = 0;
|
| 875 | } else {
|
| 876 | if(wd179x_info->fdc_status & WD179X_STAT_BUSY) { /* Force Interrupt when command is pending */
|
| 877 | } else { /* Command not pending, clear status */
|
| 878 | wd179x_info->fdc_status = 0;
|
| 879 | }
|
| 880 |
|
| 881 | if(cCommand & 0x04) {
|
| 882 | wd179x_info->index_pulse_wait = TRUE;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 883 | if(wd179x_info->sel_drive < WD179X_MAX_DRIVES) {
|
| 884 | sim_activate (wd179x_unit, ((wd179x_info->drive[wd179x_info->sel_drive].imd->ntracks % 77) == 0) ? CROMFDC_8IN_ROT : CROMFDC_5IN_ROT); /* Generate INDEX pulse */
|
Peter Schorn | ebf53c9 | 2014-10-24 23:10:54 +0200 | [diff] [blame] | 885 | /* sim_printf("Drive %d Num tracks=%d\n", wd179x_info->sel_drive, wd179x_info->drive[wd179x_info->sel_drive].imd->ntracks); */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 886 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 887 | } else {
|
| 888 | wd179x_info->intrq = 1;
|
| 889 | }
|
| 890 | wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */
|
| 891 | }
|
| 892 | break;
|
| 893 | default:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 894 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 895 | " ERROR: Unknown command 0x%02x.\n\n", wd179x_info->sel_drive, PCX, cCommand);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 896 | break;
|
| 897 | }
|
| 898 |
|
| 899 | /* Post processing of Type-specific command */
|
| 900 | switch(cCommand & 0xF0) {
|
| 901 | /* Type I Commands */
|
| 902 | case WD179X_RESTORE:
|
| 903 | case WD179X_SEEK:
|
| 904 | case WD179X_STEP:
|
| 905 | case WD179X_STEP_U:
|
| 906 | case WD179X_STEP_IN:
|
| 907 | case WD179X_STEP_IN_U:
|
| 908 | case WD179X_STEP_OUT:
|
| 909 | case WD179X_STEP_OUT_U:
|
| 910 | if(wd179x_info->verify) { /* Verify the selected track/head is ok. */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 911 | sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 912 | " Verify ", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 913 | if(sectSeek(pDrive->imd, pDrive->track, wd179x_info->fdc_head) != SCPE_OK) {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 914 | sim_debug(SEEK_MSG, &wd179x_dev, "FAILED\n");
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 915 | wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 916 | } else if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) {
|
| 917 | wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 918 | sim_debug(SEEK_MSG, &wd179x_dev, "NOT FOUND\n");
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 919 | } else {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 920 | sim_debug(SEEK_MSG, &wd179x_dev, "Ok\n");
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 921 | }
|
| 922 | }
|
| 923 |
|
| 924 | if(pDrive->track == 0) {
|
| 925 | wd179x_info->fdc_status |= WD179X_STAT_TRACK0;
|
| 926 | } else {
|
| 927 | wd179x_info->fdc_status &= ~(WD179X_STAT_TRACK0);
|
| 928 | }
|
| 929 |
|
| 930 | wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */
|
| 931 | wd179x_info->intrq = 1;
|
| 932 | break;
|
| 933 | /* Type II Commands */
|
| 934 | case WD179X_READ_REC:
|
| 935 | case WD179X_READ_RECS:
|
| 936 | case WD179X_WRITE_REC:
|
| 937 | case WD179X_WRITE_RECS:
|
| 938 | /* Type III Commands */
|
| 939 | case WD179X_READ_ADDR:
|
| 940 | case WD179X_READ_TRACK:
|
| 941 | case WD179X_WRITE_TRACK:
|
| 942 | /* Type IV Commands */
|
| 943 | case WD179X_FORCE_INTR:
|
| 944 | default:
|
| 945 | break;
|
| 946 | }
|
| 947 |
|
| 948 |
|
| 949 | return result;
|
| 950 | }
|
| 951 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 952 | /* Maximum number of sectors per track for format */
|
| 953 | uint8 max_sectors_per_track[2][7] = {
|
| 954 | /* 128, 256, 512, 1024, 2048, 4096, 8192 */
|
| 955 | { 26, 15, 8, 4, 2, 1, 0 }, /* Single-density table */
|
| 956 | { 26, 26, 15, 8, 4, 2, 1 } /* Double-density table */
|
| 957 | };
|
| 958 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 959 | uint8 WD179X_Write(const uint32 Addr, uint8 cData)
|
| 960 | {
|
| 961 | WD179X_DRIVE_INFO *pDrive;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 962 | /* uint8 disk_read = 0; */
|
Mark Pizzolato | cf280ad | 2012-03-20 18:55:45 -0700 | [diff] [blame] | 963 | uint32 flags = 0;
|
| 964 | uint32 writelen;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 965 |
|
| 966 | if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
|
| 967 | return 0xFF;
|
| 968 | }
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 969 |
|
| 970 | pDrive = &wd179x_info->drive[wd179x_info->sel_drive];
|
| 971 |
|
| 972 | if(pDrive->uptr == NULL) {
|
| 973 | return 0xFF;
|
| 974 | }
|
| 975 |
|
| 976 | switch(Addr & 0x3) {
|
| 977 | case WD179X_STATUS:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 978 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 979 | " WR CMD = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 980 | wd179x_info->fdc_read = FALSE;
|
| 981 | wd179x_info->fdc_write = FALSE;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 982 | wd179x_info->fdc_write_track = FALSE;
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 983 | wd179x_info->fdc_datacount = 0;
|
| 984 | wd179x_info->fdc_dataindex = 0;
|
| 985 |
|
| 986 | Do1793Command(cData);
|
| 987 | break;
|
| 988 | case WD179X_TRACK:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 989 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 990 | " WR TRACK = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 991 | pDrive->track = cData;
|
| 992 | break;
|
| 993 | case WD179X_SECTOR: /* Sector Register */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 994 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 995 | " WR SECT = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 996 | wd179x_info->fdc_sector = cData;
|
| 997 | break;
|
| 998 | case WD179X_DATA:
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 999 | sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1000 | " WR DATA = 0x%02x\n", PCX, cData);
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 1001 | if(wd179x_info->fdc_write == TRUE) {
|
| 1002 | if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) {
|
| 1003 | sdata.raw[wd179x_info->fdc_dataindex] = cData;
|
| 1004 |
|
| 1005 | wd179x_info->fdc_dataindex++;
|
| 1006 | if(wd179x_info->fdc_dataindex == wd179x_info->fdc_datacount) {
|
| 1007 | wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */
|
| 1008 | wd179x_info->drq = 0;
|
| 1009 | wd179x_info->intrq = 1;
|
| 1010 |
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1011 | sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 1012 | " Writing sector, T:%d/S:%d/N:%d, Len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, 128 << wd179x_info->fdc_sec_len);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1013 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 1014 | sectWrite(pDrive->imd,
|
| 1015 | pDrive->track,
|
| 1016 | wd179x_info->fdc_head,
|
| 1017 | wd179x_info->fdc_sector,
|
| 1018 | sdata.raw,
|
| 1019 | 128 << wd179x_info->fdc_sec_len,
|
| 1020 | &flags,
|
| 1021 | &writelen);
|
| 1022 |
|
| 1023 | wd179x_info->fdc_write = FALSE;
|
| 1024 | }
|
| 1025 | }
|
| 1026 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1027 |
|
| 1028 | if(wd179x_info->fdc_write_track == TRUE) {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1029 | if(wd179x_info->fdc_fmt_state == FMT_GAP1) {
|
| 1030 | if(cData != 0xFC) {
|
| 1031 | wd179x_info->fdc_gap[0]++;
|
| 1032 | } else {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1033 | sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1034 | " FMT GAP1 Length = %d\n", PCX, wd179x_info->fdc_gap[0]);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1035 | wd179x_info->fdc_gap[1] = 0;
|
| 1036 | wd179x_info->fdc_fmt_state = FMT_GAP2;
|
| 1037 | }
|
| 1038 | } else if(wd179x_info->fdc_fmt_state == FMT_GAP2) {
|
| 1039 | if(cData != 0xFE) {
|
| 1040 | wd179x_info->fdc_gap[1]++;
|
| 1041 | } else {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1042 | sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1043 | " FMT GAP2 Length = %d\n", PCX, wd179x_info->fdc_gap[1]);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1044 | wd179x_info->fdc_gap[2] = 0;
|
| 1045 | wd179x_info->fdc_fmt_state = FMT_HEADER;
|
| 1046 | wd179x_info->fdc_header_index = 0;
|
| 1047 | }
|
| 1048 | } else if(wd179x_info->fdc_fmt_state == FMT_HEADER) {
|
| 1049 | if(wd179x_info->fdc_header_index == 5) {
|
| 1050 | wd179x_info->fdc_gap[2] = 0;
|
| 1051 | wd179x_info->fdc_fmt_state = FMT_GAP3;
|
| 1052 | } else {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1053 | sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1054 | " HEADER[%d]=%02x\n", PCX, wd179x_info->fdc_header_index, cData);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1055 | switch(wd179x_info->fdc_header_index) {
|
| 1056 | case 0:
|
| 1057 | pDrive->track = cData;
|
| 1058 | break;
|
| 1059 | case 1:
|
| 1060 | wd179x_info->fdc_head = cData;
|
| 1061 | break;
|
| 1062 | case 2:
|
| 1063 | wd179x_info->fdc_sector = cData;
|
| 1064 | break;
|
| 1065 | case 3:
|
| 1066 | if(cData != 0x00) {
|
| 1067 | }
|
| 1068 | break;
|
| 1069 | case 4:
|
| 1070 | if(cData != 0xF7) {
|
| 1071 | }
|
| 1072 | break;
|
| 1073 | }
|
| 1074 | wd179x_info->fdc_header_index++;
|
| 1075 | }
|
| 1076 | } else if(wd179x_info->fdc_fmt_state == FMT_GAP3) {
|
| 1077 | if(cData != 0xFB) {
|
| 1078 | wd179x_info->fdc_gap[2]++;
|
| 1079 | } else {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1080 | sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1081 | " FMT GAP3 Length = %d\n", PCX, wd179x_info->fdc_gap[2]);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1082 | wd179x_info->fdc_fmt_state = FMT_DATA;
|
| 1083 | wd179x_info->fdc_dataindex = 0;
|
| 1084 | }
|
| 1085 | } else if(wd179x_info->fdc_fmt_state == FMT_DATA) { /* data bytes */
|
| 1086 | if(cData != 0xF7) {
|
| 1087 | sdata.raw[wd179x_info->fdc_dataindex] = cData;
|
| 1088 | wd179x_info->fdc_dataindex++;
|
| 1089 | } else {
|
| 1090 | wd179x_info->fdc_sec_len = floorlog2(wd179x_info->fdc_dataindex) - 7;
|
| 1091 | if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1092 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
| 1093 | " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1094 | wd179x_info->fdc_sec_len = 0;
|
| 1095 | }
|
| 1096 | if(wd179x_info->fdc_fmt_sector_count >= WD179X_MAX_SECTOR) {
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1097 | sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1098 | " Illegal sector count\n", PCX);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1099 | wd179x_info->fdc_fmt_sector_count = 0;
|
| 1100 | }
|
| 1101 | wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count] = wd179x_info->fdc_sector;
|
| 1102 | wd179x_info->fdc_fmt_sector_count++;
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1103 | sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1104 | " FMT Data Length = %d\n", PCX, wd179x_info->fdc_dataindex);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1105 |
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 1106 | sim_debug(FMT_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
| 1107 | " FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x\n", PCX,
|
| 1108 | pDrive->track, wd179x_info->fdc_head,
|
| 1109 | wd179x_info->fdc_fmt_sector_count,
|
| 1110 | wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count],
|
| 1111 | wd179x_info->fdc_dataindex, wd179x_info->fdc_sec_len, sdata.raw[0]);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 1112 |
|
| 1113 | wd179x_info->fdc_gap[1] = 0;
|
| 1114 | wd179x_info->fdc_fmt_state = FMT_GAP2;
|
| 1115 |
|
| 1116 | if(wd179x_info->fdc_fmt_sector_count == max_sectors_per_track[wd179x_info->ddens & 1][wd179x_info->fdc_sec_len]) {
|
| 1117 | trackWrite(pDrive->imd,
|
| 1118 | pDrive->track,
|
| 1119 | wd179x_info->fdc_head,
|
| 1120 | wd179x_info->fdc_fmt_sector_count,
|
| 1121 | wd179x_info->fdc_sec_len,
|
| 1122 | wd179x_info->fdc_sectormap,
|
| 1123 | wd179x_info->ddens ? 3 : 0, /* data mode */
|
| 1124 | sdata.raw[0],
|
| 1125 | &flags);
|
| 1126 |
|
| 1127 | wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY | WD179X_STAT_LOST_DATA); /* Clear BUSY, LOST_DATA */
|
| 1128 | wd179x_info->drq = 0;
|
| 1129 | wd179x_info->intrq = 1;
|
| 1130 |
|
| 1131 | /* Recalculate disk size */
|
| 1132 | pDrive->uptr->capac = sim_fsize(pDrive->uptr->fileref);
|
| 1133 | }
|
| 1134 | }
|
| 1135 | }
|
| 1136 | }
|
| 1137 |
|
Bob Supnik | 59aa4a7 | 2008-06-24 14:21:00 -0700 | [diff] [blame] | 1138 | wd179x_info->fdc_data = cData;
|
| 1139 | break;
|
| 1140 | }
|
| 1141 |
|
| 1142 | return 0;
|
| 1143 | }
|
| 1144 |
|