1 /*************************************************************************
3 * $Id: wd179x.c 1907 2008-05-21 07:04:17Z hharte $ *
5 * Copyright (c) 2007-2008 Howard M. Harte. *
6 * http://www.hartetec.com *
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: *
16 * The above copyright notice and this permission notice shall be *
17 * included in all copies or substantial portions of the Software. *
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. *
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 *
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *
34 * Module Description: *
35 * Generic WD179X Disk Controller module for SIMH. *
40 *************************************************************************/
44 #include "altairz80_defs.h"
54 #define DBG_PRINT(args) printf args
56 #define DBG_PRINT(args)
61 #define RD_DATA_MSG 0x08
62 #define WR_DATA_MSG 0x10
63 #define STATUS_MSG 0x20
64 #define VERBOSE_MSG 0x80
66 #define WD179X_MAX_DRIVES 4
67 #define WD179X_SECTOR_LEN 8192
73 /* Status Bits for Type I Commands */
74 #define WD179X_STAT_NOT_READY (1 << 7)
75 #define WD179X_STAT_WPROT (1 << 6)
76 #define WD179X_STAT_HLD (1 << 5)
77 #define WD179X_STAT_SEEK_ERROR (1 << 4)
78 #define WD179X_STAT_CRC_ERROR (1 << 3)
79 #define WD179X_STAT_TRACK0 (1 << 2)
80 #define WD179X_STAT_INDEX (1 << 1)
81 #define WD179X_STAT_BUSY (1 << 0)
83 /* Status Bits for Type II, III Commands */
84 #define WD179X_STAT_REC_TYPE (1 << 5)
85 #define WD179X_STAT_NOT_FOUND (1 << 4)
86 #define WD179X_STAT_LOST_DATA (1 << 2)
87 #define WD179X_STAT_DRQ (1 << 1)
91 uint8 raw
[WD179X_SECTOR_LEN
];
97 uint8 ntracks
; /* number of tracks */
98 uint8 nheads
; /* number of heads */
99 uint32 sectsize
; /* sector size, not including pre/postamble */
100 uint8 track
; /* Current Track */
101 uint8 ready
; /* Is drive ready? */
105 PNP_INFO pnp
; /* Plug-n-Play Information */
106 uint8 intrq
; /* WD179X Interrupt Request Output (EOJ) */
107 uint8 hld
; /* WD179X Head Load Output */
108 uint8 drq
; /* WD179X DMA Request Output */
109 uint8 ddens
; /* WD179X Double-Density Input */
110 uint8 fdc_head
; /* H Head Number */
111 uint8 sel_drive
; /* Currently selected drive */
112 uint8 drivetype
; /* 8 or 5 depending on disk type. */
113 uint8 fdc_status
; /* WD179X Status Register */
114 uint8 verify
; /* WD179X Type 1 command Verify flag */
115 uint8 fdc_data
; /* WD179X Data Register */
116 uint8 fdc_read
; /* TRUE when reading */
117 uint8 fdc_write
; /* TRUE when writing */
118 uint8 fdc_read_addr
; /* TRUE when READ ADDRESS command is in progress */
119 uint8 fdc_multiple
; /* TRUE for multi-sector read/write */
120 uint16 fdc_datacount
; /* Read or Write data remaining transfer length */
121 uint16 fdc_dataindex
; /* index of current byte in sector data */
122 uint8 index_pulse_wait
; /* TRUE if waiting for interrupt on next index pulse. */
123 uint8 fdc_sector
; /* R Record (Sector) */
124 uint8 fdc_sec_len
; /* N Sector Length */
126 WD179X_DRIVE_INFO drive
[WD179X_MAX_DRIVES
];
129 static SECTOR_FORMAT sdata
;
131 extern t_stat
set_iobase(UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
132 extern t_stat
show_iobase(FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
133 extern uint32
sim_map_resource(uint32 baseaddr
, uint32 size
, uint32 resource_type
,
134 int32 (*routine
)(const int32
, const int32
, const int32
), uint8 unmap
);
136 t_stat
wd179x_svc (UNIT
*uptr
);
138 /* These are needed for DMA. PIO Mode has not been implemented yet. */
139 extern void PutBYTEWrapper(const uint32 Addr
, const uint32 Value
);
140 extern uint8
GetBYTEWrapper(const uint32 Addr
);
141 static uint8
Do1793Command(uint8 cCommand
);
143 #define UNIT_V_WD179X_WLK (UNIT_V_UF + 0) /* write locked */
144 #define UNIT_WD179X_WLK (1 << UNIT_V_WD179X_WLK)
145 #define UNIT_V_WD179X_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
146 #define UNIT_WD179X_VERBOSE (1 << UNIT_V_WD179X_VERBOSE)
147 #define WD179X_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
148 #define WD179X_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */
149 #define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
150 #define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
151 #define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
153 /* WD179X Commands */
154 #define WD179X_RESTORE 0x00 /* Type I */
155 #define WD179X_SEEK 0x10 /* Type I */
156 #define WD179X_STEP 0x20 /* Type I */
157 #define WD179X_STEP_U 0x30 /* Type I */
158 #define WD179X_STEP_IN 0x40 /* Type I */
159 #define WD179X_STEP_IN_U 0x50 /* Type I */
160 #define WD179X_STEP_OUT 0x60 /* Type I */
161 #define WD179X_STEP_OUT_U 0x70 /* Type I */
162 #define WD179X_READ_REC 0x80 /* Type II */
163 #define WD179X_READ_RECS 0x90 /* Type II */
164 #define WD179X_WRITE_REC 0xA0 /* Type II */
165 #define WD179X_WRITE_RECS 0xB0 /* Type II */
166 #define WD179X_READ_ADDR 0xC0 /* Type III */
167 #define WD179X_FORCE_INTR 0xD0 /* Type IV */
168 #define WD179X_READ_TRACK 0xE0 /* Type III */
169 #define WD179X_WRITE_TRACK 0xF0 /* Type III */
171 static int32 trace_level
= 0xff; /* Disable all tracing by default. */
172 static int32 bootstrap
= 0;
174 static int32
wd179xdev(const int32 port
, const int32 io
, const int32 data
);
175 static t_stat
wd179x_reset(DEVICE
*dptr
);
176 int32
find_unit_index (UNIT
*uptr
);
178 WD179X_INFO wd179x_info_data
= { { 0x0, 0, 0x30, 4 } };
179 WD179X_INFO
*wd179x_info
= &wd179x_info_data
;
181 static UNIT wd179x_unit
[] = {
182 { UDATA (&wd179x_svc
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, WD179X_CAPACITY
), 58200 },
183 { UDATA (&wd179x_svc
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, WD179X_CAPACITY
), 58200 },
184 { UDATA (&wd179x_svc
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, WD179X_CAPACITY
), 58200 },
185 { UDATA (&wd179x_svc
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, WD179X_CAPACITY
), 58200 }
188 static REG wd179x_reg
[] = {
189 { HRDATA (TRACELEVEL
, trace_level
, 16), },
190 { DRDATA (BOOTSTRAP
, bootstrap
, 10), },
194 static MTAB wd179x_mod
[] = {
195 { MTAB_XTD
|MTAB_VDV
, 0, "IOBASE", "IOBASE", &set_iobase
, &show_iobase
, NULL
},
196 { UNIT_WD179X_WLK
, 0, "WRTENB", "WRTENB", NULL
},
197 { UNIT_WD179X_WLK
, UNIT_WD179X_WLK
, "WRTLCK", "WRTLCK", NULL
},
198 /* quiet, no warning messages */
199 { UNIT_WD179X_VERBOSE
, 0, "QUIET", "QUIET", NULL
},
200 /* verbose, show warning messages */
201 { UNIT_WD179X_VERBOSE
, UNIT_WD179X_VERBOSE
, "VERBOSE", "VERBOSE", NULL
},
205 DEVICE wd179x_dev
= {
206 "WD179X", wd179x_unit
, wd179x_reg
, wd179x_mod
,
207 WD179X_MAX_DRIVES
, 10, 31, 1, WD179X_MAX_DRIVES
, WD179X_MAX_DRIVES
,
208 NULL
, NULL
, &wd179x_reset
,
209 NULL
, &wd179x_attach
, &wd179x_detach
,
210 &wd179x_info_data
, (DEV_DISABLE
| DEV_DIS
), 0,
214 /* Unit service routine */
215 /* Used to generate INDEX pulses in response to a FORCE_INTR command */
216 t_stat
wd179x_svc (UNIT
*uptr
)
219 if(wd179x_info
->index_pulse_wait
== TRUE
) {
220 wd179x_info
->index_pulse_wait
= FALSE
;
221 wd179x_info
->intrq
= 1;
229 static t_stat
wd179x_reset(DEVICE
*dptr
)
231 PNP_INFO
*pnp
= (PNP_INFO
*)dptr
->ctxt
;
233 if(dptr
->flags
& DEV_DIS
) { /* Disconnect I/O Ports */
234 sim_map_resource(pnp
->io_base
, pnp
->io_size
, RESOURCE_TYPE_IO
, &wd179xdev
, TRUE
);
236 /* Connect I/O Ports at base address */
237 if(sim_map_resource(pnp
->io_base
, pnp
->io_size
, RESOURCE_TYPE_IO
, &wd179xdev
, FALSE
) != 0) {
238 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__
, pnp
->io_base
);
245 extern int32
find_unit_index (UNIT
*uptr
);
247 void wd179x_external_restore(void)
249 WD179X_DRIVE_INFO
*pDrive
;
250 pDrive
= &wd179x_info
->drive
[wd179x_info
->sel_drive
];
252 if(pDrive
->uptr
== NULL
) {
253 TRACE_PRINT(SEEK_MSG
,
254 ("WD179X: " ADDRESS_FORMAT
" No drive selected, cannot restore." NLP
, PCX
))
258 TRACE_PRINT(SEEK_MSG
,
259 ("WD179X[%d]: " ADDRESS_FORMAT
" External Restore drive to track 0" NLP
, wd179x_info
->sel_drive
, PCX
))
266 t_stat
wd179x_attach(UNIT
*uptr
, char *cptr
)
272 r
= attach_unit(uptr
, cptr
); /* attach unit */
273 if ( r
!= SCPE_OK
) /* error? */
276 /* Determine length of this disk */
277 uptr
->capac
= sim_fsize(uptr
->fileref
);
279 i
= find_unit_index(uptr
);
285 DBG_PRINT(("Attach WD179X%d\n", i
));
286 wd179x_info
->drive
[i
].uptr
= uptr
;
288 /* Default to drive not ready */
289 wd179x_info
->drive
[i
].ready
= 0;
291 if(uptr
->capac
> 0) {
292 fgets(header
, 4, uptr
->fileref
);
293 if(!strcmp(header
, "IMD")) {
294 uptr
->u3
= IMAGE_TYPE_IMD
;
295 } else if(!strcmp(header
, "CPT")) {
296 printf("CPT images not yet supported\n");
297 uptr
->u3
= IMAGE_TYPE_CPT
;
301 printf("DSK images not yet supported\n");
302 uptr
->u3
= IMAGE_TYPE_DSK
;
307 /* creating file, must be DSK format. */
308 printf("Cannot create images, must start with a WD179X IMD image.\n");
309 uptr
->u3
= IMAGE_TYPE_DSK
;
314 if (uptr
->flags
& UNIT_WD179X_VERBOSE
)
315 printf("WD179X%d: attached to '%s', type=%s, len=%d\n", i
, cptr
,
316 uptr
->u3
== IMAGE_TYPE_IMD
? "IMD" : uptr
->u3
== IMAGE_TYPE_CPT
? "CPT" : "DSK",
319 if(uptr
->u3
== IMAGE_TYPE_IMD
) {
320 if(uptr
->capac
< WD179X_CAPACITY_SSSD
) { /*was 318000 but changed to allow 8inch SSSD disks*/
321 printf("IMD file too small for use with SIMH.\nCopy an existing file and format it with CP/M.\n");
324 if (uptr
->flags
& UNIT_WD179X_VERBOSE
)
325 printf("--------------------------------------------------------\n");
326 wd179x_info
->drive
[i
].imd
= diskOpen((uptr
->fileref
), (uptr
->flags
& UNIT_WD179X_VERBOSE
));
327 wd179x_info
->drive
[i
].ready
= 1;
328 if (uptr
->flags
& UNIT_WD179X_VERBOSE
)
331 wd179x_info
->drive
[i
].imd
= NULL
;
334 wd179x_info
->fdc_sec_len
= 0; /* 128 byte sectors, fixme */
335 wd179x_info
->sel_drive
= 0;
342 t_stat
wd179x_detach(UNIT
*uptr
)
347 i
= find_unit_index(uptr
);
353 DBG_PRINT(("Detach WD179X%d\n", i
));
354 diskClose(wd179x_info
->drive
[i
].imd
);
355 wd179x_info
->drive
[i
].ready
= 0;
357 r
= detach_unit(uptr
); /* detach unit */
365 static int32
wd179xdev(const int32 port
, const int32 io
, const int32 data
)
367 DBG_PRINT(("WD179X: " ADDRESS_FORMAT
" %s, Port 0x%02x Data 0x%02x" NLP
,
368 PCX
, io
? "OUT" : " IN", port
, data
));
370 WD179X_Write(port
, data
);
373 return(WD179X_Read(port
));
377 static uint8
floorlog2(unsigned int n
)
379 /* Compute log2(n) */
381 if(n
>= 1<<16) { n
>>=16; r
+= 16; }
382 if(n
>= 1<< 8) { n
>>= 8; r
+= 8; }
383 if(n
>= 1<< 4) { n
>>= 4; r
+= 4; }
384 if(n
>= 1<< 2) { n
>>= 2; r
+= 2; }
385 if(n
>= 1<< 1) { r
+= 1; }
386 return ((n
== 0) ? (0xFF) : r
); /* 0xFF is error return value */
389 uint8
WD179X_Read(const uint32 Addr
)
392 WD179X_DRIVE_INFO
*pDrive
;
394 unsigned int readlen
;
397 pDrive
= &wd179x_info
->drive
[wd179x_info
->sel_drive
];
399 if(pDrive
->uptr
== NULL
) {
407 cData
= (pDrive
->ready
== 0) ? WD179X_STAT_NOT_READY
: 0;
408 cData
|= wd179x_info
->fdc_status
; /* Status Register */
409 TRACE_PRINT(STATUS_MSG
,
410 ("WD179X: " ADDRESS_FORMAT
" RD STATUS = 0x%02x" NLP
, PCX
, cData
))
411 wd179x_info
->intrq
= 0;
414 cData
= pDrive
->track
;
415 TRACE_PRINT(STATUS_MSG
,
416 ("WD179X: " ADDRESS_FORMAT
" RD TRACK = 0x%02x" NLP
, PCX
, cData
))
419 cData
= wd179x_info
->fdc_sector
;
420 TRACE_PRINT(STATUS_MSG
,
421 ("WD179X: " ADDRESS_FORMAT
" RD SECT = 0x%02x" NLP
, PCX
, cData
))
424 cData
= 0xFF; /* Return High-Z data */
425 if(wd179x_info
->fdc_read
== TRUE
) {
426 if(wd179x_info
->fdc_dataindex
< wd179x_info
->fdc_datacount
) {
427 cData
= sdata
.raw
[wd179x_info
->fdc_dataindex
];
428 if(wd179x_info
->fdc_read_addr
== TRUE
) {
429 TRACE_PRINT(STATUS_MSG
,
430 ("WD179X[%d]: " ADDRESS_FORMAT
" READ_ADDR[%d] = 0x%02x" NLP
, wd179x_info
->sel_drive
, PCX
, wd179x_info
->fdc_dataindex
, cData
))
433 wd179x_info
->fdc_dataindex
++;
434 if(wd179x_info
->fdc_dataindex
== wd179x_info
->fdc_datacount
) {
435 if(wd179x_info
->fdc_multiple
== FALSE
) {
436 wd179x_info
->fdc_status
&= ~(WD179X_STAT_DRQ
| WD179X_STAT_BUSY
); /* Clear DRQ, BUSY */
437 wd179x_info
->drq
= 0;
438 wd179x_info
->intrq
= 1;
439 wd179x_info
->fdc_read
= FALSE
;
440 wd179x_info
->fdc_read_addr
= FALSE
;
443 /* Compute Sector Size */
444 wd179x_info
->fdc_sec_len
= floorlog2(
445 pDrive
->imd
->track
[pDrive
->track
][wd179x_info
->fdc_head
].sectsize
) - 7;
446 if(wd179x_info
->fdc_sec_len
== 0xF8) { /*Error calculating N*/
447 printf("Invalid sector size!\n");
450 wd179x_info
->fdc_sector
++;
451 TRACE_PRINT(RD_DATA_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d" NLP
,
452 wd179x_info
->sel_drive
,
455 wd179x_info
->fdc_head
,
456 wd179x_info
->fdc_sector
,
457 wd179x_info
->ddens
? "DD" : "SD",
458 128 << wd179x_info
->fdc_sec_len
));
460 status
= sectRead(pDrive
->imd
,
462 wd179x_info
->fdc_head
,
463 wd179x_info
->fdc_sector
,
465 128 << wd179x_info
->fdc_sec_len
,
470 wd179x_info
->fdc_status
= (WD179X_STAT_DRQ
| WD179X_STAT_BUSY
); /* Set DRQ, BUSY */
471 wd179x_info
->drq
= 1;
472 wd179x_info
->fdc_datacount
= 128 << wd179x_info
->fdc_sec_len
;
473 wd179x_info
->fdc_dataindex
= 0;
474 wd179x_info
->fdc_read
= TRUE
;
475 wd179x_info
->fdc_read_addr
= FALSE
;
477 wd179x_info
->fdc_status
= 0; /* Clear DRQ, BUSY */
478 wd179x_info
->fdc_status
|= WD179X_STAT_NOT_FOUND
;
479 wd179x_info
->drq
= 0;
480 wd179x_info
->intrq
= 1;
481 wd179x_info
->fdc_read
= FALSE
;
482 wd179x_info
->fdc_read_addr
= FALSE
;
495 * Command processing happens in three stages:
496 * 1. Flags and initial conditions are set up based on the Type of the command.
497 * 2. The execution phase takes place.
498 * 3. Status is updated based on the Type and outcome of the command execution.
500 * See the WD179x-02 Datasheet available on www.hartetechnologies.com/manuals/
503 static uint8
Do1793Command(uint8 cCommand
)
506 WD179X_DRIVE_INFO
*pDrive
;
508 unsigned int readlen
;
510 pDrive
= &wd179x_info
->drive
[wd179x_info
->sel_drive
];
512 if(pDrive
->uptr
== NULL
) {
516 if(wd179x_info
->fdc_status
& WD179X_STAT_BUSY
) {
517 if((cCommand
& 0xF0) != WD179X_FORCE_INTR
) {
518 printf("WD179X[%d]: ERROR: Command 0x%02x ignored because controller is BUSY\n", wd179x_info
->sel_drive
, cCommand
);
523 /* Extract Type-specific command flags, and set initial conditions */
524 switch(cCommand
& 0xF0) {
525 /* Type I Commands */
531 case WD179X_STEP_IN_U
:
532 case WD179X_STEP_OUT
:
533 case WD179X_STEP_OUT_U
:
534 wd179x_info
->fdc_status
|= WD179X_STAT_BUSY
; /* Set BUSY */
535 wd179x_info
->fdc_status
&= ~(WD179X_STAT_CRC_ERROR
| WD179X_STAT_SEEK_ERROR
| WD179X_STAT_DRQ
);
536 wd179x_info
->intrq
= 0;
537 wd179x_info
->hld
= cCommand
&& 0x08;
538 wd179x_info
->verify
= cCommand
& 0x04;
540 /* Type II Commands */
541 case WD179X_READ_REC
:
542 case WD179X_READ_RECS
:
543 case WD179X_WRITE_REC
:
544 case WD179X_WRITE_RECS
:
545 wd179x_info
->fdc_status
= WD179X_STAT_BUSY
; /* Set BUSY, clear all others */
546 wd179x_info
->intrq
= 0;
547 wd179x_info
->hld
= 1; /* Load the head immediately, E Flag not checked. */
549 /* Type III Commands */
550 case WD179X_READ_ADDR
:
551 case WD179X_READ_TRACK
:
552 case WD179X_WRITE_TRACK
:
553 /* Type IV Commands */
554 case WD179X_FORCE_INTR
:
559 switch(cCommand
& 0xF0) {
560 /* Type I Commands */
562 TRACE_PRINT(CMD_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=RESTORE" NLP
, wd179x_info
->sel_drive
, PCX
));
564 wd179x_info
->intrq
= 1;
567 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=SEEK, track=%d, new=%d" NLP
, wd179x_info
->sel_drive
, PCX
, pDrive
->track
, wd179x_info
->fdc_data
));
568 pDrive
->track
= wd179x_info
->fdc_data
;
571 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP" NLP
, wd179x_info
->sel_drive
, PCX
));
574 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_U dir=%d" NLP
, wd179x_info
->sel_drive
, PCX
, wd179x_info
->step_dir
));
575 if(wd179x_info
->step_dir
== 1) {
576 if(pDrive
->track
< 255) pDrive
->track
++;
577 } else if (wd179x_info
->step_dir
== -1) {
578 if(pDrive
->track
> 0) pDrive
->track
--;
580 printf("WD179X[%d]: Error, undefined direction for STEP\n", wd179x_info
->sel_drive
);
584 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_IN" NLP
, wd179x_info
->sel_drive
, PCX
));
586 case WD179X_STEP_IN_U
:
587 if(pDrive
->track
< 255) pDrive
->track
++;
588 wd179x_info
->step_dir
= 1;
589 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_IN_U, Track=%d" NLP
,
590 wd179x_info
->sel_drive
, PCX
, pDrive
->track
));
592 case WD179X_STEP_OUT
:
593 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_OUT" NLP
,
594 wd179x_info
->sel_drive
, PCX
));
596 case WD179X_STEP_OUT_U
:
597 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=STEP_OUT_U" NLP
,
598 wd179x_info
->sel_drive
, PCX
));
599 if(pDrive
->track
> 0) pDrive
->track
--;
600 wd179x_info
->step_dir
= -1;
602 /* Type II Commands */
603 case WD179X_READ_REC
:
604 case WD179X_READ_RECS
:
605 /* Compute Sector Size */
606 wd179x_info
->fdc_sec_len
= floorlog2(
607 pDrive
->imd
->track
[pDrive
->track
][wd179x_info
->fdc_head
].sectsize
) - 7;
608 if(wd179x_info
->fdc_sec_len
== 0xF8) { /*Error calculating N*/
609 printf("Invalid sector size!\n");
612 wd179x_info
->fdc_multiple
= (cCommand
& 0x10) ? TRUE
: FALSE
;
613 TRACE_PRINT(RD_DATA_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d" NLP
,
614 wd179x_info
->sel_drive
,
616 wd179x_info
->fdc_head
,
617 wd179x_info
->fdc_sector
,
618 wd179x_info
->fdc_multiple
? "Multiple" : "Single",
619 wd179x_info
->ddens
? "DD" : "SD",
620 128 << wd179x_info
->fdc_sec_len
));
622 sectRead(pDrive
->imd
,
624 wd179x_info
->fdc_head
,
625 wd179x_info
->fdc_sector
,
627 128 << wd179x_info
->fdc_sec_len
,
631 if(IMD_MODE_MFM(pDrive
->imd
->track
[pDrive
->track
][wd179x_info
->fdc_head
].mode
) != (wd179x_info
->ddens
)) {
632 printf("Sector not found\n");
633 wd179x_info
->fdc_status
|= WD179X_STAT_NOT_FOUND
; /* Sector not found */
634 wd179x_info
->intrq
= 1;
636 wd179x_info
->fdc_status
|= (WD179X_STAT_DRQ
); /* Set DRQ */
637 wd179x_info
->drq
= 1;
638 wd179x_info
->fdc_datacount
= 128 << wd179x_info
->fdc_sec_len
;
639 wd179x_info
->fdc_dataindex
= 0;
640 wd179x_info
->fdc_write
= FALSE
;
641 wd179x_info
->fdc_read
= TRUE
;
642 wd179x_info
->fdc_read_addr
= FALSE
;
645 case WD179X_WRITE_RECS
:
646 printf("-->> Error: WRITE_RECS not implemented." NLP
);
647 case WD179X_WRITE_REC
:
648 /* Compute Sector Size */
649 wd179x_info
->fdc_sec_len
= floorlog2(
650 pDrive
->imd
->track
[pDrive
->track
][wd179x_info
->fdc_head
].sectsize
) - 7;
651 if(wd179x_info
->fdc_sec_len
== 0xF8) { /*Error calculating N*/
652 printf("Invalid sector size!\n");
655 TRACE_PRINT(WR_DATA_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=WRITE_REC, T:%d/S:%d/N:%d, %s." NLP
,
656 wd179x_info
->sel_drive
,
660 wd179x_info
->fdc_sector
,
661 (cCommand
& 0x10) ? "Multiple" : "Single"));
662 wd179x_info
->fdc_status
|= (WD179X_STAT_DRQ
); /* Set DRQ */
663 wd179x_info
->drq
= 1;
664 wd179x_info
->fdc_datacount
= 128 << wd179x_info
->fdc_sec_len
;
665 wd179x_info
->fdc_dataindex
= 0;
666 wd179x_info
->fdc_write
= TRUE
;
667 wd179x_info
->fdc_read
= FALSE
;
668 wd179x_info
->fdc_read_addr
= FALSE
;
670 sdata
.raw
[wd179x_info
->fdc_dataindex
] = wd179x_info
->fdc_data
;
672 /* Type III Commands */
673 case WD179X_READ_ADDR
:
674 TRACE_PRINT(RD_DATA_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=READ_ADDR, T:%d/S:%d, %s" NLP
,
675 wd179x_info
->sel_drive
,
678 wd179x_info
->fdc_head
,
679 wd179x_info
->ddens
? "DD" : "SD"));
681 /* Compute Sector Size */
682 wd179x_info
->fdc_sec_len
= floorlog2(
683 pDrive
->imd
->track
[pDrive
->track
][wd179x_info
->fdc_head
].sectsize
) - 7;
684 if(wd179x_info
->fdc_sec_len
== 0xF8) { /*Error calculating N*/
685 printf("Invalid sector size!\n");
688 if(IMD_MODE_MFM(pDrive
->imd
->track
[pDrive
->track
][wd179x_info
->fdc_head
].mode
) != (wd179x_info
->ddens
)) {
689 wd179x_info
->fdc_status
= WD179X_STAT_NOT_FOUND
; /* Sector not found */
690 wd179x_info
->intrq
= 1;
692 wd179x_info
->fdc_status
= (WD179X_STAT_DRQ
| WD179X_STAT_BUSY
); /* Set DRQ, BUSY */
693 wd179x_info
->drq
= 1;
694 wd179x_info
->fdc_datacount
= 6;
695 wd179x_info
->fdc_dataindex
= 0;
696 wd179x_info
->fdc_read
= TRUE
;
697 wd179x_info
->fdc_read_addr
= TRUE
;
699 sdata
.raw
[0] = pDrive
->track
;
700 sdata
.raw
[1] = wd179x_info
->fdc_head
;
701 sdata
.raw
[2] = wd179x_info
->fdc_sector
;
702 sdata
.raw
[3] = wd179x_info
->fdc_sec_len
;
703 sdata
.raw
[4] = 0xAA; /* CRC1 */
704 sdata
.raw
[5] = 0x55; /* CRC2 */
706 wd179x_info
->fdc_sector
= pDrive
->track
;
707 wd179x_info
->fdc_status
&= ~(WD179X_STAT_BUSY
); /* Clear BUSY */
708 wd179x_info
->intrq
= 1;
711 case WD179X_READ_TRACK
:
712 TRACE_PRINT(RD_DATA_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=READ_TRACK" NLP
, wd179x_info
->sel_drive
, PCX
));
713 printf("-->> Error: READ_TRACK not implemented." NLP
);
715 case WD179X_WRITE_TRACK
:
716 TRACE_PRINT(WR_DATA_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=WRITE_TRACK" NLP
, wd179x_info
->sel_drive
, PCX
));
717 printf("-->> Error: WRITE_TRACK not implemented." NLP
);
719 /* Type IV Commands */
720 case WD179X_FORCE_INTR
:
721 TRACE_PRINT(CMD_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" CMD=FORCE_INTR" NLP
, wd179x_info
->sel_drive
, PCX
));
722 if((cCommand
& 0x0F) == 0) { /* I0-I3 == 0, no intr, but clear BUSY and terminate command */
723 wd179x_info
->fdc_status
&= ~(WD179X_STAT_DRQ
| WD179X_STAT_BUSY
); /* Clear DRQ, BUSY */
724 wd179x_info
->drq
= 0;
725 wd179x_info
->fdc_write
= FALSE
;
726 wd179x_info
->fdc_read
= FALSE
;
727 wd179x_info
->fdc_read_addr
= FALSE
;
728 wd179x_info
->fdc_datacount
= 0;
729 wd179x_info
->fdc_dataindex
= 0;
731 if(wd179x_info
->fdc_status
& WD179X_STAT_BUSY
) { /* Force Interrupt when command is pending */
732 } else { /* Command not pending, clear status */
733 wd179x_info
->fdc_status
= 0;
736 if(cCommand
& 0x04) {
737 wd179x_info
->index_pulse_wait
= TRUE
;
738 sim_activate (wd179x_unit
, wd179x_info
->drivetype
== 8 ? 48500 : 58200); /* Generate INDEX pulse */
740 wd179x_info
->intrq
= 1;
742 wd179x_info
->fdc_status
&= ~(WD179X_STAT_BUSY
); /* Clear BUSY */
746 printf("WD179X[%d]: Unknown WD179X command 0x%02x.\n", wd179x_info
->sel_drive
, cCommand
);
750 /* Post processing of Type-specific command */
751 switch(cCommand
& 0xF0) {
752 /* Type I Commands */
758 case WD179X_STEP_IN_U
:
759 case WD179X_STEP_OUT
:
760 case WD179X_STEP_OUT_U
:
761 if(wd179x_info
->verify
) { /* Verify the selected track/head is ok. */
762 TRACE_PRINT(SEEK_MSG
, ("WD179X[%d]: " ADDRESS_FORMAT
" Verify ", wd179x_info
->sel_drive
, PCX
));
763 if(sectSeek(pDrive
->imd
, pDrive
->track
, wd179x_info
->fdc_head
) != 0) {
764 TRACE_PRINT(SEEK_MSG
, ("FAILED" NLP
));
765 wd179x_info
->fdc_status
|= WD179X_STAT_NOT_FOUND
;
767 TRACE_PRINT(SEEK_MSG
, ("Ok" NLP
));
771 if(pDrive
->track
== 0) {
772 wd179x_info
->fdc_status
|= WD179X_STAT_TRACK0
;
774 wd179x_info
->fdc_status
&= ~(WD179X_STAT_TRACK0
);
777 wd179x_info
->fdc_status
&= ~(WD179X_STAT_BUSY
); /* Clear BUSY */
778 wd179x_info
->intrq
= 1;
780 /* Type II Commands */
781 case WD179X_READ_REC
:
782 case WD179X_READ_RECS
:
783 case WD179X_WRITE_REC
:
784 case WD179X_WRITE_RECS
:
785 /* Type III Commands */
786 case WD179X_READ_ADDR
:
787 case WD179X_READ_TRACK
:
788 case WD179X_WRITE_TRACK
:
789 /* Type IV Commands */
790 case WD179X_FORCE_INTR
:
799 uint8
WD179X_Write(const uint32 Addr
, uint8 cData
)
801 WD179X_DRIVE_INFO
*pDrive
;
803 unsigned int writelen
;
805 pDrive
= &wd179x_info
->drive
[wd179x_info
->sel_drive
];
807 if(pDrive
->uptr
== NULL
) {
813 TRACE_PRINT(STATUS_MSG
,
814 ("WD179X: " ADDRESS_FORMAT
" WR CMD = 0x%02x" NLP
, PCX
, cData
))
815 wd179x_info
->fdc_read
= FALSE
;
816 wd179x_info
->fdc_write
= FALSE
;
817 wd179x_info
->fdc_datacount
= 0;
818 wd179x_info
->fdc_dataindex
= 0;
820 Do1793Command(cData
);
823 TRACE_PRINT(STATUS_MSG
,
824 ("WD179X: " ADDRESS_FORMAT
" WR TRACK = 0x%02x" NLP
, PCX
, cData
))
825 pDrive
->track
= cData
;
827 case WD179X_SECTOR
: /* Sector Register */
828 TRACE_PRINT(STATUS_MSG
,
829 ("WD179X: " ADDRESS_FORMAT
" WR SECT = 0x%02x" NLP
, PCX
, cData
))
830 wd179x_info
->fdc_sector
= cData
;
833 TRACE_PRINT(STATUS_MSG
,
834 ("WD179X: " ADDRESS_FORMAT
" WR DATA = 0x%02x" NLP
, PCX
, cData
))
835 if(wd179x_info
->fdc_write
== TRUE
) {
836 if(wd179x_info
->fdc_dataindex
< wd179x_info
->fdc_datacount
) {
837 sdata
.raw
[wd179x_info
->fdc_dataindex
] = cData
;
839 wd179x_info
->fdc_dataindex
++;
840 if(wd179x_info
->fdc_dataindex
== wd179x_info
->fdc_datacount
) {
841 wd179x_info
->fdc_status
&= ~(WD179X_STAT_DRQ
| WD179X_STAT_BUSY
); /* Clear DRQ, BUSY */
842 wd179x_info
->drq
= 0;
843 wd179x_info
->intrq
= 1;
845 sectWrite(pDrive
->imd
,
847 wd179x_info
->fdc_head
,
848 wd179x_info
->fdc_sector
,
850 128 << wd179x_info
->fdc_sec_len
,
854 wd179x_info
->fdc_write
= FALSE
;
858 wd179x_info
->fdc_data
= cData
;