blob: c4cc5461fce581d30ce7bc7433584a247b59ad91 [file] [log] [blame] [raw]
Bob Supnik59aa4a72008-06-24 14:21:00 -07001/*************************************************************************
2 * *
Bob Supnik9c4779c2009-02-08 09:06:00 -08003 * $Id: wd179x.c 1999 2008-07-22 04:25:28Z hharte $ *
Bob Supnik59aa4a72008-06-24 14:21:00 -07004 * *
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 Schornebf53c92014-10-24 23:10:54 +020054#define DBG_PRINT(args) sim_printf args
Bob Supnik59aa4a72008-06-24 14:21:00 -070055#else
56#define DBG_PRINT(args)
57#endif
58
Bob Supnik9c4779c2009-02-08 09:06:00 -080059#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 Supnik59aa4a72008-06-24 14:21:00 -070062
Bob Supnik9c4779c2009-02-08 09:06:00 -080063/* 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 Supnik59aa4a72008-06-24 14:21:00 -070078
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 Supnik9c4779c2009-02-08 09:06:00 -080094/*#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 Supnik59aa4a72008-06-24 14:21:00 -070097#define WD179X_STAT_NOT_FOUND (1 << 4)
Bob Supnik9c4779c2009-02-08 09:06:00 -080098/*#define WD179X_STAT_CRC_ERROR (1 << 3) */
Bob Supnik59aa4a72008-06-24 14:21:00 -070099#define WD179X_STAT_LOST_DATA (1 << 2)
100#define WD179X_STAT_DRQ (1 << 1)
Bob Supnik9c4779c2009-02-08 09:06:00 -0800101/*#define WD179X_STAT_BUSY (1 << 0) */
Bob Supnik59aa4a72008-06-24 14:21:00 -0700102
103typedef union {
104 uint8 raw[WD179X_SECTOR_LEN];
105} SECTOR_FORMAT;
106
107typedef 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
117typedef 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 Supnik9c4779c2009-02-08 09:06:00 -0800131 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 Supnik59aa4a72008-06-24 14:21:00 -0700137 uint8 fdc_read_addr; /* TRUE when READ ADDRESS command is in progress */
138 uint8 fdc_multiple; /* TRUE for multi-sector read/write */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800139 uint16 fdc_datacount; /* Read or Write data remaining transfer length */
140 uint16 fdc_dataindex; /* index of current byte in sector data */
Bob Supnik59aa4a72008-06-24 14:21:00 -0700141 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 Supnik9c4779c2009-02-08 09:06:00 -0800145 uint8 cmdtype; /* Type of current/former command */
Bob Supnik59aa4a72008-06-24 14:21:00 -0700146 WD179X_DRIVE_INFO drive[WD179X_MAX_DRIVES];
147} WD179X_INFO;
148
149static SECTOR_FORMAT sdata;
150extern uint32 PCX;
151extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
152extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
153extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
154 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
Bob Supnik35eac702010-04-26 06:04:00 -0700155extern int32 find_unit_index (UNIT *uptr);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700156
157t_stat wd179x_svc (UNIT *uptr);
158
159/* These are needed for DMA. PIO Mode has not been implemented yet. */
160extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
161extern uint8 GetBYTEWrapper(const uint32 Addr);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700162
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 Supnik9c4779c2009-02-08 09:06:00 -0800169
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 Supnik59aa4a72008-06-24 14:21:00 -0700177
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 Supnik59aa4a72008-06-24 14:21:00 -0700196static int32 wd179xdev(const int32 port, const int32 io, const int32 data);
197static t_stat wd179x_reset(DEVICE *dptr);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800198uint8 floorlog2(unsigned int n);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700199
200WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } };
201WD179X_INFO *wd179x_info = &wd179x_info_data;
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700202WD179X_INFO_PUB *wd179x_infop = (WD179X_INFO_PUB *)&wd179x_info_data;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700203
204static 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 Schorn589aca12014-05-27 20:01:30 +0200211#define WD179X_NAME "Western Digital FDC Core WD179X"
212
Bob Supnik59aa4a72008-06-24 14:21:00 -0700213static MTAB wd179x_mod[] = {
Peter Schorn589aca12014-05-27 20:01:30 +0200214 { 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 Supnik59aa4a72008-06-24 14:21:00 -0700220 /* quiet, no warning messages */
Peter Schorn589aca12014-05-27 20:01:30 +0200221 { UNIT_WD179X_VERBOSE, 0, "QUIET", "QUIET",
222 NULL, NULL, NULL, "No verbose messages for unit " WD179X_NAME "n" },
Bob Supnik59aa4a72008-06-24 14:21:00 -0700223 /* verbose, show warning messages */
Peter Schorn589aca12014-05-27 20:01:30 +0200224 { UNIT_WD179X_VERBOSE, UNIT_WD179X_VERBOSE, "VERBOSE", "VERBOSE",
225 NULL, NULL, NULL, "Verbose messages for unit " WD179X_NAME "n" },
Bob Supnik59aa4a72008-06-24 14:21:00 -0700226 { 0 }
227};
Bob Supnik9c4779c2009-02-08 09:06:00 -0800228
229/* Debug Flags */
230static DEBTAB wd179x_dt[] = {
Peter Schorn589aca12014-05-27 20:01:30 +0200231 { "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 Supnik9c4779c2009-02-08 09:06:00 -0800240};
241
Bob Supnik59aa4a72008-06-24 14:21:00 -0700242DEVICE wd179x_dev = {
Bob Supnik9c4779c2009-02-08 09:06:00 -0800243 "WD179X", wd179x_unit, NULL, wd179x_mod,
Bob Supnik59aa4a72008-06-24 14:21:00 -0700244 WD179X_MAX_DRIVES, 10, 31, 1, WD179X_MAX_DRIVES, WD179X_MAX_DRIVES,
245 NULL, NULL, &wd179x_reset,
246 NULL, &wd179x_attach, &wd179x_detach,
Bob Supnik9c4779c2009-02-08 09:06:00 -0800247 &wd179x_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
Peter Schorn589aca12014-05-27 20:01:30 +0200248 wd179x_dt, NULL, WD179X_NAME
Bob Supnik59aa4a72008-06-24 14:21:00 -0700249};
250
251/* Unit service routine */
252/* Used to generate INDEX pulses in response to a FORCE_INTR command */
253t_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 */
266static 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 Schornebf53c92014-10-24 23:10:54 +0200275 sim_printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700276 return SCPE_ARG;
277 }
278 }
279 return SCPE_OK;
280}
281
Bob Supnik59aa4a72008-06-24 14:21:00 -0700282void wd179x_external_restore(void)
283{
284 WD179X_DRIVE_INFO *pDrive;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800285
286 if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700287 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
288 " Illegal drive selected, cannot restore.\n", PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800289 return;
290 }
291
Bob Supnik59aa4a72008-06-24 14:21:00 -0700292 pDrive = &wd179x_info->drive[wd179x_info->sel_drive];
293
294 if(pDrive->uptr == NULL) {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700295 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
296 " No drive selected, cannot restore.\n", PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700297 return;
298 }
299
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700300 sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
301 " External Restore drive to track 0\n", wd179x_info->sel_drive, PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700302
303 pDrive->track = 0;
304
305}
306
307/* Attach routine */
308t_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 Supnik35eac702010-04-26 06:04:00 -0700334 char *rtn = fgets(header, 4, uptr->fileref);
335 if ((rtn != NULL) && strncmp(header, "IMD", 3)) {
Peter Schornebf53c92014-10-24 23:10:54 +0200336 sim_printf("WD179X: Only IMD disk images are supported\n");
Bob Supnik9c4779c2009-02-08 09:06:00 -0800337 wd179x_info->drive[i].uptr = NULL;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700338 return SCPE_OPENERR;
339 }
340 } else {
Bob Supnik9c4779c2009-02-08 09:06:00 -0800341 /* 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 Schornebf53c92014-10-24 23:10:54 +0200343 sim_printf("WD179X: Failed to create IMD disk.\n");
Bob Supnik9c4779c2009-02-08 09:06:00 -0800344 wd179x_info->drive[i].uptr = NULL;
345 return SCPE_OPENERR;
346 }
347 uptr->capac = sim_fsize(uptr->fileref);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700348 }
Bob Supnik9c4779c2009-02-08 09:06:00 -0800349
350 uptr->u3 = IMAGE_TYPE_IMD;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700351
352 if (uptr->flags & UNIT_WD179X_VERBOSE)
Peter Schornebf53c92014-10-24 23:10:54 +0200353 sim_printf("WD179X%d: attached to '%s', type=%s, len=%d\n", i, cptr,
Bob Supnik59aa4a72008-06-24 14:21:00 -0700354 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 Supnik59aa4a72008-06-24 14:21:00 -0700358 if (uptr->flags & UNIT_WD179X_VERBOSE)
Peter Schornebf53c92014-10-24 23:10:54 +0200359 sim_printf("--------------------------------------------------------\n");
Peter Schorn977712b2014-09-21 09:42:26 +0200360 wd179x_info->drive[i].imd = diskOpenEx(uptr->fileref, uptr->flags & UNIT_WD179X_VERBOSE,
361 &wd179x_dev, VERBOSE_MSG, VERBOSE_MSG);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700362 if (uptr->flags & UNIT_WD179X_VERBOSE)
Peter Schornebf53c92014-10-24 23:10:54 +0200363 sim_printf("\n");
Bob Supnik9c4779c2009-02-08 09:06:00 -0800364 if (wd179x_info->drive[i].imd == NULL) {
Peter Schornebf53c92014-10-24 23:10:54 +0200365 sim_printf("WD179X: IMD disk corrupt.\n");
Bob Supnik9c4779c2009-02-08 09:06:00 -0800366 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 Supnik59aa4a72008-06-24 14:21:00 -0700376 } 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 */
388t_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 Supnik9c4779c2009-02-08 09:06:00 -0800396 return SCPE_IERR;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700397 }
398
399 DBG_PRINT(("Detach WD179X%d\n", i));
Bob Supnik9c4779c2009-02-08 09:06:00 -0800400 r = diskClose(&wd179x_info->drive[i].imd);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700401 wd179x_info->drive[i].ready = 0;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800402 if (r != SCPE_OK)
403 return r;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700404
405 r = detach_unit(uptr); /* detach unit */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800406 if (r != SCPE_OK)
Bob Supnik59aa4a72008-06-24 14:21:00 -0700407 return r;
408
409 return SCPE_OK;
410}
411
412
413static 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 Supnik9c4779c2009-02-08 09:06:00 -0800425uint8 floorlog2(unsigned int n)
Bob Supnik59aa4a72008-06-24 14:21:00 -0700426{
427 /* Compute log2(n) */
428 uint8 r = 0;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800429 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 Supnik59aa4a72008-06-24 14:21:00 -0700448 return ((n == 0) ? (0xFF) : r); /* 0xFF is error return value */
449}
450
451uint8 WD179X_Read(const uint32 Addr)
452{
453 uint8 cData;
454 WD179X_DRIVE_INFO *pDrive;
Mark Pizzolatocf280ad2012-03-20 18:55:45 -0700455 uint32 flags = 0;
456 uint32 readlen;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700457 int status;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800458
459 if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
460 return 0xFF;
461 }
Bob Supnik59aa4a72008-06-24 14:21:00 -0700462
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 Supnik9c4779c2009-02-08 09:06:00 -0800473 /* 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 Supnik59aa4a72008-06-24 14:21:00 -0700484 cData = (pDrive->ready == 0) ? WD179X_STAT_NOT_READY : 0;
485 cData |= wd179x_info->fdc_status; /* Status Register */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700486 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
487 " RD STATUS = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700488 wd179x_info->intrq = 0;
489 break;
490 case WD179X_TRACK:
491 cData = pDrive->track;
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700492 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
493 " RD TRACK = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700494 break;
495 case WD179X_SECTOR:
496 cData = wd179x_info->fdc_sector;
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700497 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
498 " RD SECT = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700499 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 Pizzolatofffad7c2012-03-19 16:05:24 -0700506 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 Supnik59aa4a72008-06-24 14:21:00 -0700510 }
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 Supnik9c4779c2009-02-08 09:06:00 -0800525 if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700526 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800527 wd179x_info->fdc_sec_len = 0;
528 return cData;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700529 }
530
531 wd179x_info->fdc_sector ++;
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700532 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 Supnik59aa4a72008-06-24 14:21:00 -0700533
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 Supnik9c4779c2009-02-08 09:06:00 -0800543 if(status == SCPE_OK) {
Bob Supnik59aa4a72008-06-24 14:21:00 -0700544 wd179x_info->fdc_status = (WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Set DRQ, BUSY */
545 wd179x_info->drq = 1;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800546 wd179x_info->intrq = 0;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700547 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 */
578static uint8 Do1793Command(uint8 cCommand)
579{
580 uint8 result = 0;
581 WD179X_DRIVE_INFO *pDrive;
Mark Pizzolatocf280ad2012-03-20 18:55:45 -0700582 uint32 flags = 0;
583 uint32 readlen;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800584 int status;
585
586 if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
587 return 0xFF;
588 }
Bob Supnik59aa4a72008-06-24 14:21:00 -0700589
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 Supnik9c4779c2009-02-08 09:06:00 -0800597 if(((cCommand & 0xF0) != WD179X_FORCE_INTR)) { /* && ((cCommand & 0xF0) != WD179X_RESTORE)) { */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700598 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 Supnik59aa4a72008-06-24 14:21:00 -0700601 }
602 return 0xFF;
603 }
Bob Supnik9c4779c2009-02-08 09:06:00 -0800604
605 wd179x_info->fdc_status &= ~WD179X_STAT_NOT_READY;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700606
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 Supnik9c4779c2009-02-08 09:06:00 -0800618 wd179x_info->cmdtype = 1;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700619 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 Pizzolatofffad7c2012-03-19 16:05:24 -0700622 wd179x_info->hld = cCommand & 0x08;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700623 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 Supnik9c4779c2009-02-08 09:06:00 -0800630 wd179x_info->cmdtype = 2;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700631 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 Supnik9c4779c2009-02-08 09:06:00 -0800639 wd179x_info->cmdtype = 3;
640 break;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700641 /* Type IV Commands */
642 case WD179X_FORCE_INTR:
Bob Supnik9c4779c2009-02-08 09:06:00 -0800643 wd179x_info->cmdtype = 4;
644 break;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700645 default:
Bob Supnik9c4779c2009-02-08 09:06:00 -0800646 wd179x_info->cmdtype = 0;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700647 break;
648 }
649
650 switch(cCommand & 0xF0) {
651 /* Type I Commands */
652 case WD179X_RESTORE:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700653 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 Supnik59aa4a72008-06-24 14:21:00 -0700656 pDrive->track = 0;
657 wd179x_info->intrq = 1;
658 break;
659 case WD179X_SEEK:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700660 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 Supnik59aa4a72008-06-24 14:21:00 -0700663 pDrive->track = wd179x_info->fdc_data;
664 break;
665 case WD179X_STEP:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700666 sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
667 " CMD=STEP\n", wd179x_info->sel_drive, PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700668 break;
669 case WD179X_STEP_U:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700670 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 Supnik59aa4a72008-06-24 14:21:00 -0700673 if(wd179x_info->step_dir == 1) {
Bob Supnik9c4779c2009-02-08 09:06:00 -0800674 if (pDrive->track < 255)
675 pDrive->track++;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700676 } else if (wd179x_info->step_dir == -1) {
Bob Supnik9c4779c2009-02-08 09:06:00 -0800677 if (pDrive->track > 0)
678 pDrive->track--;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700679 } else {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700680 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
681 " ERROR: undefined direction for STEP\n",
682 wd179x_info->sel_drive, PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700683 }
684 break;
685 case WD179X_STEP_IN:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700686 sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
687 " CMD=STEP_IN\n", wd179x_info->sel_drive, PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700688 break;
689 case WD179X_STEP_IN_U:
Bob Supnik9c4779c2009-02-08 09:06:00 -0800690 if (pDrive->track < 255)
691 pDrive->track++;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700692 wd179x_info->step_dir = 1;
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700693 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 Supnik59aa4a72008-06-24 14:21:00 -0700696 break;
697 case WD179X_STEP_OUT:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700698 sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
699 " CMD=STEP_OUT\n", wd179x_info->sel_drive, PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700700 break;
701 case WD179X_STEP_OUT_U:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700702 sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
703 " CMD=STEP_OUT_U\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800704 if (pDrive->track > 0)
705 pDrive->track--;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700706 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 Supnik9c4779c2009-02-08 09:06:00 -0800714 if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700715 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
716 " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800717 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 Supnik59aa4a72008-06-24 14:21:00 -0700723 }
724
725 wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE;
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700726 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 Supnik59aa4a72008-06-24 14:21:00 -0700732
Bob Supnik59aa4a72008-06-24 14:21:00 -0700733 if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) {
Bob Supnik59aa4a72008-06-24 14:21:00 -0700734 wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800735 wd179x_info->fdc_status &= ~WD179X_STAT_BUSY;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700736 wd179x_info->intrq = 1;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800737 wd179x_info->drq = 0;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700738 } else {
Bob Supnik9c4779c2009-02-08 09:06:00 -0800739
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 Supnik59aa4a72008-06-24 14:21:00 -0700767 }
768 break;
769 case WD179X_WRITE_RECS:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700770 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
771 " Error: WRITE_RECS not implemented.\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800772 break;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700773 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 Supnik9c4779c2009-02-08 09:06:00 -0800777 if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700778 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
779 " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800780 wd179x_info->fdc_sec_len = 0;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700781 }
782
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700783 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 Supnik59aa4a72008-06-24 14:21:00 -0700785 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 Supnik9c4779c2009-02-08 09:06:00 -0800790 wd179x_info->fdc_write_track = FALSE;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700791 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 Pizzolatofffad7c2012-03-19 16:05:24 -0700798 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 Supnik59aa4a72008-06-24 14:21:00 -0700801
Bob Supnik9c4779c2009-02-08 09:06:00 -0800802 /* 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 Supnik59aa4a72008-06-24 14:21:00 -0700806 /* Compute Sector Size */
807 wd179x_info->fdc_sec_len = floorlog2(
808 pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800809 if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700810 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
811 " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800812 wd179x_info->fdc_sec_len = 0;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700813 }
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 Pizzolatofffad7c2012-03-19 16:05:24 -0700839 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 Supnik59aa4a72008-06-24 14:21:00 -0700843 break;
844 case WD179X_WRITE_TRACK:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700845 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 Supnik9c4779c2009-02-08 09:06:00 -0800850 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 Supnik59aa4a72008-06-24 14:21:00 -0700861 break;
862 /* Type IV Commands */
863 case WD179X_FORCE_INTR:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700864 sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
865 " CMD=FORCE_INTR\n", wd179x_info->sel_drive, PCX);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700866 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 Supnik9c4779c2009-02-08 09:06:00 -0800871 wd179x_info->fdc_write_track = FALSE;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700872 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 Supnik9c4779c2009-02-08 09:06:00 -0800883 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 Schornebf53c92014-10-24 23:10:54 +0200885/* sim_printf("Drive %d Num tracks=%d\n", wd179x_info->sel_drive, wd179x_info->drive[wd179x_info->sel_drive].imd->ntracks); */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800886 }
Bob Supnik59aa4a72008-06-24 14:21:00 -0700887 } else {
888 wd179x_info->intrq = 1;
889 }
890 wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */
891 }
892 break;
893 default:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700894 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 Supnik59aa4a72008-06-24 14:21:00 -0700896 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 Pizzolatofffad7c2012-03-19 16:05:24 -0700911 sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
912 " Verify ", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -0800913 if(sectSeek(pDrive->imd, pDrive->track, wd179x_info->fdc_head) != SCPE_OK) {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700914 sim_debug(SEEK_MSG, &wd179x_dev, "FAILED\n");
Bob Supnik59aa4a72008-06-24 14:21:00 -0700915 wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800916 } 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 Pizzolatofffad7c2012-03-19 16:05:24 -0700918 sim_debug(SEEK_MSG, &wd179x_dev, "NOT FOUND\n");
Bob Supnik59aa4a72008-06-24 14:21:00 -0700919 } else {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700920 sim_debug(SEEK_MSG, &wd179x_dev, "Ok\n");
Bob Supnik59aa4a72008-06-24 14:21:00 -0700921 }
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 Supnik9c4779c2009-02-08 09:06:00 -0800952/* Maximum number of sectors per track for format */
953uint8 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 Supnik59aa4a72008-06-24 14:21:00 -0700959uint8 WD179X_Write(const uint32 Addr, uint8 cData)
960{
961 WD179X_DRIVE_INFO *pDrive;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800962/* uint8 disk_read = 0; */
Mark Pizzolatocf280ad2012-03-20 18:55:45 -0700963 uint32 flags = 0;
964 uint32 writelen;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800965
966 if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) {
967 return 0xFF;
968 }
Bob Supnik59aa4a72008-06-24 14:21:00 -0700969
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 Pizzolatofffad7c2012-03-19 16:05:24 -0700978 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
979 " WR CMD = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700980 wd179x_info->fdc_read = FALSE;
981 wd179x_info->fdc_write = FALSE;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800982 wd179x_info->fdc_write_track = FALSE;
Bob Supnik59aa4a72008-06-24 14:21:00 -0700983 wd179x_info->fdc_datacount = 0;
984 wd179x_info->fdc_dataindex = 0;
985
986 Do1793Command(cData);
987 break;
988 case WD179X_TRACK:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700989 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
990 " WR TRACK = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700991 pDrive->track = cData;
992 break;
993 case WD179X_SECTOR: /* Sector Register */
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700994 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
995 " WR SECT = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -0700996 wd179x_info->fdc_sector = cData;
997 break;
998 case WD179X_DATA:
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700999 sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1000 " WR DATA = 0x%02x\n", PCX, cData);
Bob Supnik59aa4a72008-06-24 14:21:00 -07001001 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 Pizzolatofffad7c2012-03-19 16:05:24 -07001011 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 Supnik9c4779c2009-02-08 09:06:00 -08001013
Bob Supnik59aa4a72008-06-24 14:21:00 -07001014 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 Supnik9c4779c2009-02-08 09:06:00 -08001027
1028 if(wd179x_info->fdc_write_track == TRUE) {
Bob Supnik9c4779c2009-02-08 09:06:00 -08001029 if(wd179x_info->fdc_fmt_state == FMT_GAP1) {
1030 if(cData != 0xFC) {
1031 wd179x_info->fdc_gap[0]++;
1032 } else {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -07001033 sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1034 " FMT GAP1 Length = %d\n", PCX, wd179x_info->fdc_gap[0]);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001035 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 Pizzolatofffad7c2012-03-19 16:05:24 -07001042 sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1043 " FMT GAP2 Length = %d\n", PCX, wd179x_info->fdc_gap[1]);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001044 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 Pizzolatofffad7c2012-03-19 16:05:24 -07001053 sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1054 " HEADER[%d]=%02x\n", PCX, wd179x_info->fdc_header_index, cData);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001055 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 Pizzolatofffad7c2012-03-19 16:05:24 -07001080 sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1081 " FMT GAP3 Length = %d\n", PCX, wd179x_info->fdc_gap[2]);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001082 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 Pizzolatofffad7c2012-03-19 16:05:24 -07001092 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
1093 " Invalid sector size!\n", wd179x_info->sel_drive, PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001094 wd179x_info->fdc_sec_len = 0;
1095 }
1096 if(wd179x_info->fdc_fmt_sector_count >= WD179X_MAX_SECTOR) {
Mark Pizzolatofffad7c2012-03-19 16:05:24 -07001097 sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1098 " Illegal sector count\n", PCX);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001099 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 Pizzolatofffad7c2012-03-19 16:05:24 -07001103 sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
1104 " FMT Data Length = %d\n", PCX, wd179x_info->fdc_dataindex);
Bob Supnik9c4779c2009-02-08 09:06:00 -08001105
Mark Pizzolatofffad7c2012-03-19 16:05:24 -07001106 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 Supnik9c4779c2009-02-08 09:06:00 -08001112
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 Supnik59aa4a72008-06-24 14:21:00 -07001138 wd179x_info->fdc_data = cData;
1139 break;
1140 }
1141
1142 return 0;
1143}
1144