1 /*************************************************************************
3 * $Id: i8272.c 1773 2008-01-11 05:46:19Z 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 Intel 8272 Disk Controller module for SIMH. *
40 *************************************************************************/
43 - 19-Apr-2008, Tony Nicholson, added other .IMD formats
48 #include "altairz80_defs.h"
58 #define DBG_PRINT(args) printf args
60 #define DBG_PRINT(args)
65 #define RD_DATA_MSG 0x08
66 #define WR_DATA_MSG 0x10
67 #define STATUS_MSG 0x20
68 #define VERBOSE_MSG 0x80
70 #define I8272_MAX_DRIVES 4
71 #define I8272_SECTOR_LEN 8192
78 uint8 raw
[I8272_SECTOR_LEN
];
84 uint8 ntracks
; /* number of tracks */
85 uint8 nheads
; /* number of heads */
86 uint32 sectsize
; /* sector size, not including pre/postamble */
87 uint8 track
; /* Current Track */
88 uint8 ready
; /* Is drive ready? */
92 PNP_INFO pnp
; /* Plug-n-Play Information */
93 uint32 fdc_dma_addr
;/* DMA Transfer Address */
94 uint8 fdc_msr
; /* 8272 Main Status Register */
95 uint8 fdc_phase
; /* Phase that the 8272 is currently in */
96 uint8 fdc_srt
; /* Step Rate in ms */
97 uint8 fdc_hut
; /* Head Unload Time in ms */
98 uint8 fdc_hlt
; /* Head Load Time in ms */
99 uint8 fdc_nd
; /* Non-DMA Mode 1=Non-DMA, 0=DMA */
100 uint8 fdc_head
; /* H Head Number */
101 uint8 fdc_sector
; /* R Record (Sector) */
102 uint8 fdc_sec_len
; /* N Sector Length */
103 uint8 fdc_eot
; /* EOT End of Track (Final sector number of cyl) */
104 uint8 fdc_gpl
; /* GPL Gap3 Length */
105 uint8 fdc_dtl
; /* DTL Data Length */
106 uint8 fdc_mt
; /* Multiple sectors */
107 uint8 fdc_mfm
; /* MFM mode */
108 uint8 fdc_sk
; /* Skip Deleted Data */
109 uint8 fdc_hds
; /* Head Select */
110 uint8 fdc_fillbyte
; /* Fill-byte used for FORMAT TRACK */
111 uint8 fdc_sc
; /* Sector count for FORMAT TRACK */
112 uint8 fdc_status
[3];/* Status Register Bytes */
113 uint8 fdc_seek_end
; /* Seek was executed successfully */
114 uint8 cmd_index
; /* Index of command byte */
115 uint8 cmd
[10]; /* Storage for current command */
116 uint8 cmd_len
; /* FDC Command Length */
117 uint8 result_index
; /* Index of result byte */
118 uint8 result
[10]; /* Result data */
119 uint8 result_len
; /* FDC Result Length */
120 uint8 sel_drive
; /* Currently selected drive */
121 I8272_DRIVE_INFO drive
[I8272_MAX_DRIVES
];
124 static SECTOR_FORMAT sdata
;
126 extern t_stat
set_iobase(UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
127 extern t_stat
show_iobase(FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
128 extern uint32
sim_map_resource(uint32 baseaddr
, uint32 size
, uint32 resource_type
,
129 int32 (*routine
)(const int32
, const int32
, const int32
), uint8 unmap
);
131 /* These are needed for DMA. PIO Mode has not been implemented yet. */
132 extern void PutBYTEWrapper(const uint32 Addr
, const uint32 Value
);
133 extern uint8
GetBYTEWrapper(const uint32 Addr
);
135 #define UNIT_V_I8272_WLK (UNIT_V_UF + 0) /* write locked */
136 #define UNIT_I8272_WLK (1 << UNIT_V_I8272_WLK)
137 #define UNIT_V_I8272_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
138 #define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE)
139 #define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
140 #define I8272_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */
141 #define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
142 #define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
143 #define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
145 /* Intel 8272 Commands */
146 #define I8272_READ_TRACK 0x02
147 #define I8272_SPECIFY 0x03
148 #define I8272_SENSE_DRIVE_STATUS 0x04
149 #define I8272_WRITE_DATA 0x05
150 #define I8272_READ_DATA 0x06
151 #define I8272_RECALIBRATE 0x07
152 #define I8272_SENSE_INTR_STATUS 0x08
153 #define I8272_WRITE_DELETED_DATA 0x09
154 #define I8272_READ_ID 0x0A
155 #define I8272_READ_DELETED_DATA 0x0C
156 #define I8272_FORMAT_TRACK 0x0D
157 #define I8272_SEEK 0x0F
158 #define I8272_SCAN_EQUAL 0x11
159 #define I8272_SCAN_LOW_EQUAL 0x19
160 #define I8272_SCAN_HIGH_EQUAL 0x1D
162 /* SENSE DRIVE STATUS bit definitions */
163 #define DRIVE_STATUS_TWO_SIDED 0x08
164 #define DRIVE_STATUS_TRACK0 0x10
165 #define DRIVE_STATUS_READY 0x20
166 #define DRIVE_STATUS_WP 0x40
167 #define DRIVE_STATUS_FAULT 0x80
169 static int32 trace_level
= 0; /* Disable all tracing by default. */
170 static int32 bootstrap
= 0;
172 static int32
i8272dev(const int32 port
, const int32 io
, const int32 data
);
173 static t_stat
i8272_reset(DEVICE
*dptr
);
174 int32
find_unit_index (UNIT
*uptr
);
176 I8272_INFO i8272_info_data
= { { 0x0, 0, 0xC0, 2 } };
177 I8272_INFO
*i8272_info
= &i8272_info_data
;
179 static UNIT i8272_unit
[] = {
180 { UDATA (NULL
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, I8272_CAPACITY
) },
181 { UDATA (NULL
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, I8272_CAPACITY
) },
182 { UDATA (NULL
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, I8272_CAPACITY
) },
183 { UDATA (NULL
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, I8272_CAPACITY
) }
186 static REG i8272_reg
[] = {
187 { HRDATA (TRACELEVEL
, trace_level
, 16), },
188 { DRDATA (BOOTSTRAP
, bootstrap
, 10), },
192 static MTAB i8272_mod
[] = {
193 { MTAB_XTD
|MTAB_VDV
, 0, "IOBASE", "IOBASE", &set_iobase
, &show_iobase
, NULL
},
194 { UNIT_I8272_WLK
, 0, "WRTENB", "WRTENB", NULL
},
195 { UNIT_I8272_WLK
, UNIT_I8272_WLK
, "WRTLCK", "WRTLCK", NULL
},
196 /* quiet, no warning messages */
197 { UNIT_I8272_VERBOSE
, 0, "QUIET", "QUIET", NULL
},
198 /* verbose, show warning messages */
199 { UNIT_I8272_VERBOSE
, UNIT_I8272_VERBOSE
, "VERBOSE", "VERBOSE", NULL
},
204 "I8272", i8272_unit
, i8272_reg
, i8272_mod
,
205 I8272_MAX_DRIVES
, 10, 31, 1, I8272_MAX_DRIVES
, I8272_MAX_DRIVES
,
206 NULL
, NULL
, &i8272_reset
,
207 NULL
, &i8272_attach
, &i8272_detach
,
208 &i8272_info_data
, (DEV_DISABLE
| DEV_DIS
), 0,
212 static uint8
I8272_Setup_Cmd(uint8 fdc_cmd
);
216 static t_stat
i8272_reset(DEVICE
*dptr
)
218 PNP_INFO
*pnp
= (PNP_INFO
*)dptr
->ctxt
;
220 if(dptr
->flags
& DEV_DIS
) { /* Disconnect I/O Ports */
221 sim_map_resource(pnp
->io_base
, pnp
->io_size
, RESOURCE_TYPE_IO
, &i8272dev
, TRUE
);
223 /* Connect I/O Ports at base address */
224 if(sim_map_resource(pnp
->io_base
, pnp
->io_size
, RESOURCE_TYPE_IO
, &i8272dev
, FALSE
) != 0) {
225 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__
, pnp
->io_base
);
233 /* find_unit_index find index of a unit
236 uptr = pointer to unit
238 result = index of device
240 int32
find_unit_index (UNIT
*uptr
)
245 if (uptr
== NULL
) return (-1);
246 dptr
= find_dev_from_unit(uptr
);
247 for(i
=0; i
<dptr
->numunits
; i
++) {
248 if(dptr
->units
+ i
== uptr
) {
252 if(i
== dptr
->numunits
) {
259 t_stat
i8272_attach(UNIT
*uptr
, char *cptr
)
265 r
= attach_unit(uptr
, cptr
); /* attach unit */
266 if ( r
!= SCPE_OK
) /* error? */
269 /* Determine length of this disk */
270 uptr
->capac
= sim_fsize(uptr
->fileref
);
272 i
= find_unit_index(uptr
);
278 DBG_PRINT(("Attach I8272%d\n", i
));
279 i8272_info
->drive
[i
].uptr
= uptr
;
281 /* Default to drive not ready */
282 i8272_info
->drive
[i
].ready
= 0;
284 if(uptr
->capac
> 0) {
285 fgets(header
, 4, uptr
->fileref
);
286 if(!strcmp(header
, "IMD")) {
287 uptr
->u3
= IMAGE_TYPE_IMD
;
288 } else if(!strcmp(header
, "CPT")) {
289 printf("CPT images not yet supported\n");
290 uptr
->u3
= IMAGE_TYPE_CPT
;
294 printf("DSK images not yet supported\n");
295 uptr
->u3
= IMAGE_TYPE_DSK
;
300 /* creating file, must be DSK format. */
301 printf("Cannot create images, must start with a I8272 IMD image.\n");
302 uptr
->u3
= IMAGE_TYPE_DSK
;
307 if (uptr
->flags
& UNIT_I8272_VERBOSE
)
308 printf("I8272%d: attached to '%s', type=%s, len=%d\n", i
, cptr
,
309 uptr
->u3
== IMAGE_TYPE_IMD
? "IMD" : uptr
->u3
== IMAGE_TYPE_CPT
? "CPT" : "DSK",
312 if(uptr
->u3
== IMAGE_TYPE_IMD
) {
313 if(uptr
->capac
< I8272_CAPACITY_SSSD
) { /*was 318000 but changed to allow 8inch SSSD disks*/
314 printf("IMD file too small for use with SIMH.\nCopy an existing file and format it with CP/M.\n");
319 if (uptr
->flags
& UNIT_I8272_VERBOSE
)
320 printf("--------------------------------------------------------\n");
321 i8272_info
->drive
[i
].imd
= diskOpen((uptr
->fileref
), (uptr
->flags
& UNIT_I8272_VERBOSE
));
322 i8272_info
->drive
[i
].ready
= 1;
323 if (uptr
->flags
& UNIT_I8272_VERBOSE
)
326 i8272_info
->drive
[i
].imd
= NULL
;
334 t_stat
i8272_detach(UNIT
*uptr
)
339 i
= find_unit_index(uptr
);
345 DBG_PRINT(("Detach I8272%d\n", i
));
346 diskClose(i8272_info
->drive
[i
].imd
);
347 i8272_info
->drive
[i
].ready
= 0;
349 r
= detach_unit(uptr
); /* detach unit */
357 static int32
i8272dev(const int32 port
, const int32 io
, const int32 data
)
359 DBG_PRINT(("I8272: " ADDRESS_FORMAT
" %s, Port 0x%02x Data 0x%02x" NLP
,
360 PCX
, io
? "OUT" : " IN", port
, data
));
362 I8272_Write(port
, data
);
365 return(I8272_Read(port
));
369 uint8
I8272_Set_DMA(const uint32 dma_addr
)
371 i8272_info
->fdc_dma_addr
= dma_addr
& 0xFFFFFF;
376 static uint8
floorlog2(unsigned int n
)
378 /* Compute log2(n) */
380 if(n
>= 1<<16) { n
>>=16; r
+= 16; }
381 if(n
>= 1<< 8) { n
>>= 8; r
+= 8; }
382 if(n
>= 1<< 4) { n
>>= 4; r
+= 4; }
383 if(n
>= 1<< 2) { n
>>= 2; r
+= 2; }
384 if(n
>= 1<< 1) { r
+= 1; }
385 return ((n
== 0) ? (0xFF) : r
); /* 0xFF is error return value */
388 uint8
I8272_Read(const uint32 Addr
)
391 I8272_DRIVE_INFO
*pDrive
;
393 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
395 if(pDrive
->uptr
== NULL
) {
403 cData
= i8272_info
->fdc_msr
| 0x80;
404 if(i8272_info
->fdc_phase
== 0) {
410 TRACE_PRINT(STATUS_MSG
, ("I8272: " ADDRESS_FORMAT
" RD FDC MSR = 0x%02x" NLP
, PCX
, cData
));
413 if(i8272_info
->fdc_phase
== DATA_PHASE
) {
414 cData
= i8272_info
->result
[i8272_info
->result_index
];
415 i8272_info
->result_index
++;
416 if(i8272_info
->result_index
== i8272_info
->result_len
) {
417 TRACE_PRINT(VERBOSE_MSG
, ("I8272: " ADDRESS_FORMAT
" result phase complete." NLP
, PCX
));
418 i8272_info
->fdc_phase
= 0;
422 TRACE_PRINT(VERBOSE_MSG
, ("I8272: " ADDRESS_FORMAT
" RD Data, phase=%d, [%d]=0x%02x" NLP
, PCX
, i8272_info
->fdc_phase
, i8272_info
->result_index
-1, cData
));
426 TRACE_PRINT(VERBOSE_MSG
, ("I8272: " ADDRESS_FORMAT
" Cannot read register %x" NLP
, PCX
, Addr
));
433 static char *messages
[0x20] = {
435 "Undefined Command 0x0","Undefined Command 0x1","Read Track", "Specify",
437 "Sense Drive Status", "Write Data", "Read Data", "Recalibrate",
439 "Sense Interrupt Status", "Write Deleted Data", "Read ID", "Undefined Command 0xB",
441 "Read Deleted Data", "Format Track", "Undefined Command 0xE","Seek",
443 "Undefined Command 0x10","Scan Equal", "Undefined Command 0x12","Undefined Command 0x13",
445 "Undefined Command 0x14","Undefined Command 0x15","Undefined Command 0x16","Undefined Command 0x17",
447 "Undefined Command 0x18","Scan Low Equal", "Undefined Command 0x1A","Undefined Command 0x1B",
449 "Undefined Command 0x1C","Scan High Equal", "Undefined Command 0x1E","Undefined Command 0x1F"
452 uint8
I8272_Write(const uint32 Addr
, uint8 cData
)
454 I8272_DRIVE_INFO
*pDrive
;
456 unsigned int readlen
;
460 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
462 if(pDrive
->uptr
== NULL
) {
468 TRACE_PRINT(WR_DATA_MSG
, ("I8272: " ADDRESS_FORMAT
" WR Drive Select Reg=%02x" NLP
,
472 TRACE_PRINT(VERBOSE_MSG
, ("I8272: " ADDRESS_FORMAT
" WR Data, phase=%d, index=%d" NLP
,
473 PCX
, i8272_info
->fdc_phase
, i8272_info
->cmd_index
));
474 if(i8272_info
->fdc_phase
== CMD_PHASE
) {
475 i8272_info
->cmd
[i8272_info
->cmd_index
] = cData
;
477 if(i8272_info
->cmd_index
== 0) {
478 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" CMD=0x%02x[%s]" NLP
,
479 PCX
, cData
& 0x1F, messages
[cData
& 0x1F]));
480 I8272_Setup_Cmd(cData
& 0x1F);
482 i8272_info
->cmd_index
++;
484 if(i8272_info
->cmd_len
== i8272_info
->cmd_index
) {
485 i8272_info
->cmd_index
= 0;
486 i8272_info
->fdc_phase
= EXEC_PHASE
;
490 if(i8272_info
->fdc_phase
== EXEC_PHASE
) {
491 switch(i8272_info
->cmd
[0] & 0x1F) {
492 case I8272_READ_DATA
:
493 case I8272_WRITE_DATA
:
494 case I8272_READ_DELETED_DATA
:
495 case I8272_WRITE_DELETED_DATA
:
496 case I8272_READ_TRACK
:
497 case I8272_SCAN_LOW_EQUAL
:
498 case I8272_SCAN_HIGH_EQUAL
:
499 case I8272_SCAN_EQUAL
:
500 i8272_info
->fdc_mt
= (i8272_info
->cmd
[0] & 0x80) >> 7;
501 i8272_info
->fdc_mfm
= (i8272_info
->cmd
[0] & 0x40) >> 6;
502 i8272_info
->fdc_sk
= (i8272_info
->cmd
[0] & 0x20) >> 5;
503 i8272_info
->fdc_hds
= (i8272_info
->cmd
[1] & 0x04) >> 2;
504 i8272_info
->sel_drive
= (i8272_info
->cmd
[1] & 0x03);
505 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
506 if(pDrive
->uptr
== NULL
) {
510 if(pDrive
->track
!= i8272_info
->cmd
[2]) {
511 i8272_info
->fdc_seek_end
= 1;
513 i8272_info
->fdc_seek_end
= 0;
515 pDrive
->track
= i8272_info
->cmd
[2];
516 i8272_info
->fdc_head
= i8272_info
->cmd
[3];
517 i8272_info
->fdc_sector
= i8272_info
->cmd
[4];
518 i8272_info
->fdc_sec_len
= i8272_info
->cmd
[5];
519 i8272_info
->fdc_eot
= i8272_info
->cmd
[6];
520 i8272_info
->fdc_gpl
= i8272_info
->cmd
[7];
521 i8272_info
->fdc_dtl
= i8272_info
->cmd
[8];
523 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
524 " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x" NLP
,
526 i8272_info
->cmd
[0] & 0x1F,
527 messages
[i8272_info
->cmd
[0] & 0x1F],
528 i8272_info
->sel_drive
,
529 i8272_info
->fdc_mt
? "Multi" : "Single",
530 i8272_info
->fdc_mfm
? "MFM" : "FM",
532 i8272_info
->fdc_head
,
533 i8272_info
->fdc_sector
,
534 i8272_info
->fdc_sec_len
,
537 i8272_info
->fdc_dtl
));
539 i8272_info
->fdc_status
[0] = (i8272_info
->fdc_hds
& 1) << 2;
540 i8272_info
->fdc_status
[0] |= (i8272_info
->sel_drive
& 3);
541 i8272_info
->fdc_status
[0] |= 0x40;
543 i8272_info
->fdc_status
[1] = 0;
544 i8272_info
->fdc_status
[2] = 0;
546 i8272_info
->result
[0] = i8272_info
->fdc_status
[0];
547 i8272_info
->result
[1] = i8272_info
->fdc_status
[1];
548 i8272_info
->result
[2] = i8272_info
->fdc_status
[2];
549 i8272_info
->result
[3] = pDrive
->track
;
550 i8272_info
->result
[4] = i8272_info
->fdc_head
;
551 i8272_info
->result
[5] = i8272_info
->fdc_sector
;
552 i8272_info
->result
[6] = i8272_info
->fdc_sec_len
;
554 case I8272_READ_ID
: /* READ ID */
555 i8272_info
->fdc_mfm
= (i8272_info
->cmd
[0] & 0x40) >> 6;
556 i8272_info
->fdc_hds
= (i8272_info
->cmd
[1] & 0x04) >> 2;
557 i8272_info
->sel_drive
= (i8272_info
->cmd
[1] & 0x03);
558 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
559 if(pDrive
->uptr
== NULL
) {
562 /* Compute the i8272 "N" value from the sectorsize of this */
563 /* disk's current track - i.e. N = log2(sectsize) - log2(128) */
564 /* The calculation also works for non-standard format disk images with */
565 /* sectorsizes of 2048, 4096 and 8192 bytes */
566 i8272_info
->fdc_sec_len
= floorlog2(
567 pDrive
->imd
->track
[pDrive
->track
][i8272_info
->fdc_head
].sectsize
) - 7;
568 if(i8272_info
->fdc_sec_len
== 0xF8) { /*Error calculating N*/
571 i8272_info
->fdc_status
[0] = (i8272_info
->fdc_hds
& 1) << 2;
572 i8272_info
->fdc_status
[0] |= (i8272_info
->sel_drive
& 3);
574 i8272_info
->fdc_status
[1] = 0;
575 i8272_info
->fdc_status
[2] = 0;
577 i8272_info
->result
[0] = i8272_info
->fdc_status
[0];
578 i8272_info
->result
[1] = i8272_info
->fdc_status
[1];
579 i8272_info
->result
[2] = i8272_info
->fdc_status
[2];
580 i8272_info
->result
[3] = pDrive
->track
;
581 i8272_info
->result
[4] = i8272_info
->fdc_head
;
582 i8272_info
->result
[5] = i8272_info
->fdc_sector
;
583 i8272_info
->result
[6] = i8272_info
->fdc_sec_len
; /*was hardcoded to 0x3*/
585 case I8272_RECALIBRATE
: /* RECALIBRATE */
586 i8272_info
->sel_drive
= i8272_info
->cmd
[1] & 3;
587 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
588 if(pDrive
->uptr
== NULL
) {
593 i8272_info
->fdc_phase
= 0; /* No result phase */
595 i8272_info
->fdc_seek_end
= 1;
596 TRACE_PRINT(SEEK_MSG
, ("I8272: " ADDRESS_FORMAT
" Recalibrate: Drive 0x%02x" NLP
,
597 PCX
, i8272_info
->sel_drive
));
599 case I8272_FORMAT_TRACK
: /* FORMAT A TRACK */
600 i8272_info
->fdc_mfm
= (i8272_info
->cmd
[0] & 0x40) >> 6;
601 i8272_info
->fdc_hds
= (i8272_info
->cmd
[1] & 0x04) >> 2;
602 i8272_info
->fdc_head
= i8272_info
->fdc_hds
; /* psco added */
603 i8272_info
->sel_drive
= (i8272_info
->cmd
[1] & 0x03);
604 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
605 if(pDrive
->uptr
== NULL
) {
609 if(pDrive
->track
!= i8272_info
->cmd
[2]) {
610 i8272_info
->fdc_seek_end
= 1;
612 i8272_info
->fdc_seek_end
= 0;
614 i8272_info
->fdc_sec_len
= i8272_info
->cmd
[2];
615 i8272_info
->fdc_sc
= i8272_info
->cmd
[3];
616 i8272_info
->fdc_gpl
= i8272_info
->cmd
[4];
617 i8272_info
->fdc_fillbyte
= i8272_info
->cmd
[5];
619 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x" NLP
,
621 i8272_info
->sel_drive
,
622 i8272_info
->fdc_mfm
? "MFM" : "FM",
624 i8272_info
->fdc_head
,
625 i8272_info
->fdc_sec_len
,
628 i8272_info
->fdc_fillbyte
));
630 i8272_info
->fdc_status
[0] = (i8272_info
->fdc_hds
& 1) << 2;
631 i8272_info
->fdc_status
[0] |= (i8272_info
->sel_drive
& 3);
632 /*i8272_info->fdc_status[0] |= 0x40; psco removed */
634 i8272_info
->fdc_status
[1] = 0;
635 i8272_info
->fdc_status
[2] = 0;
637 i8272_info
->result
[0] = i8272_info
->fdc_status
[0];
638 i8272_info
->result
[1] = i8272_info
->fdc_status
[1];
639 i8272_info
->result
[2] = i8272_info
->fdc_status
[2];
640 i8272_info
->result
[3] = pDrive
->track
;
641 i8272_info
->result
[4] = i8272_info
->fdc_head
;
642 i8272_info
->result
[5] = i8272_info
->fdc_sector
;
643 i8272_info
->result
[6] = i8272_info
->fdc_sec_len
;
645 case I8272_SENSE_INTR_STATUS
: /* SENSE INTERRUPT STATUS */
646 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" Sense Interrupt Status" NLP
, PCX
));
647 i8272_info
->result
[0] = i8272_info
->fdc_seek_end
? 0x20 : 0x00; /* SEEK_END */
648 i8272_info
->result
[0] |= i8272_info
->sel_drive
;
649 i8272_info
->result
[1] = pDrive
->track
;
651 case I8272_SPECIFY
: /* SPECIFY */
652 i8272_info
->fdc_srt
= 16 - ((i8272_info
->cmd
[1] & 0xF0) >> 4);
653 i8272_info
->fdc_hut
= (i8272_info
->cmd
[1] & 0x0F) * 16;
654 i8272_info
->fdc_hlt
= ((i8272_info
->cmd
[2] & 0xFE) >> 1) * 2;
655 i8272_info
->fdc_nd
= (i8272_info
->cmd
[2] & 0x01);
656 i8272_info
->fdc_phase
= 0; /* No result phase */
657 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s" NLP
,
662 i8272_info
->fdc_nd
? "NON-DMA" : "DMA"));
664 case I8272_SENSE_DRIVE_STATUS
: /* Setup Status3 Byte */
665 i8272_info
->fdc_hds
= (i8272_info
->cmd
[1] & 0x04) >> 2;
666 i8272_info
->sel_drive
= (i8272_info
->cmd
[1] & 0x03);
667 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
668 if(pDrive
->uptr
== NULL
) {
672 i8272_info
->result
[0] = (pDrive
->ready
) ? DRIVE_STATUS_READY
: 0; /* Drive Ready */
673 if(imdGetSides(pDrive
->imd
) == 2) {
674 i8272_info
->result
[0] |= DRIVE_STATUS_TWO_SIDED
; /* Two-sided? */
676 if(imdIsWriteLocked(pDrive
->imd
)) {
677 i8272_info
->result
[0] |= DRIVE_STATUS_WP
; /* Write Protected? */
679 i8272_info
->result
[0] |= (i8272_info
->fdc_hds
& 1) << 2;
680 i8272_info
->result
[0] |= (i8272_info
->sel_drive
& 3);
681 i8272_info
->result
[0] |= (pDrive
->track
== 0) ? DRIVE_STATUS_TRACK0
: 0x00; /* Track 0 */
682 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" Sense Drive Status = %02x" NLP
,
683 PCX
, i8272_info
->result
[0]));
685 case I8272_SEEK
: /* SEEK */
686 i8272_info
->fdc_mt
= (i8272_info
->cmd
[0] & 0x80) >> 7;
687 i8272_info
->fdc_mfm
= (i8272_info
->cmd
[0] & 0x40) >> 6;
688 i8272_info
->fdc_sk
= (i8272_info
->cmd
[0] & 0x20) >> 5;
689 i8272_info
->fdc_hds
= (i8272_info
->cmd
[1] & 0x04) >> 2;
690 i8272_info
->sel_drive
= (i8272_info
->cmd
[1] & 0x03);
691 pDrive
= &i8272_info
->drive
[i8272_info
->sel_drive
];
692 if(pDrive
->uptr
== NULL
) {
696 pDrive
->track
= i8272_info
->cmd
[2];
697 i8272_info
->fdc_seek_end
= 1;
698 TRACE_PRINT(SEEK_MSG
, ("I8272: " ADDRESS_FORMAT
" Seek %d" NLP
,
699 PCX
, pDrive
->track
));
701 default: /* INVALID */
705 if(i8272_info
->fdc_phase
== EXEC_PHASE
) {
706 switch(i8272_info
->cmd
[0] & 0x1F) {
707 case I8272_READ_TRACK
:
708 printf("I8272: " ADDRESS_FORMAT
" Read a track (untested.)" NLP
, PCX
);
709 i8272_info
->fdc_sector
= 1; /* Read entire track from sector 1...eot */
710 case I8272_READ_DATA
:
711 case I8272_READ_DELETED_DATA
:
713 case I8272_WRITE_DATA
:
714 case I8272_WRITE_DELETED_DATA
:
715 for(;i8272_info
->fdc_sector
<=i8272_info
->fdc_eot
;i8272_info
->fdc_sector
++) {
716 TRACE_PRINT(RD_DATA_MSG
, ("I8272: " ADDRESS_FORMAT
" %s Data, sector: %d sector len=%d" NLP
,
717 PCX
, disk_read
? "RD" : "WR",
718 i8272_info
->fdc_sector
,
719 128 << i8272_info
->fdc_sec_len
));
720 switch((pDrive
->uptr
)->u3
)
723 if(pDrive
->imd
== NULL
) {
724 printf(".imd is NULL!" NLP
);
726 if(disk_read
) { /* Read sector */
727 sectRead(pDrive
->imd
,
729 i8272_info
->fdc_head
,
730 i8272_info
->fdc_sector
,
732 128 << i8272_info
->fdc_sec_len
,
736 for(i
=0;i
<(128 << i8272_info
->fdc_sec_len
);i
++) {
737 PutBYTEWrapper(i8272_info
->fdc_dma_addr
, sdata
.raw
[i
]);
738 i8272_info
->fdc_dma_addr
++;
740 TRACE_PRINT(RD_DATA_MSG
, ("I8272: " ADDRESS_FORMAT
" Data transferred to RAM at 0x%06x" NLP
,
741 PCX
, i8272_info
->fdc_dma_addr
));
743 for(i
=0;i
<(128 << i8272_info
->fdc_sec_len
);i
++) {
744 sdata
.raw
[i
] = GetBYTEWrapper(i8272_info
->fdc_dma_addr
);
745 i8272_info
->fdc_dma_addr
++;
747 TRACE_PRINT(WR_DATA_MSG
, ("I8272: " ADDRESS_FORMAT
" Data transferred from RAM at 0x%06x" NLP
,
748 PCX
, i8272_info
->fdc_dma_addr
));
749 sectWrite(pDrive
->imd
,
751 i8272_info
->fdc_head
,
752 i8272_info
->fdc_sector
,
754 128 << i8272_info
->fdc_sec_len
,
759 i8272_info
->result
[5] = i8272_info
->fdc_sector
;
760 i8272_info
->result
[1] = 0x80;
763 printf("%s: DSK Format not supported" NLP
, __FUNCTION__
);
766 printf("%s: CPT Format not supported" NLP
, __FUNCTION__
);
769 printf("%s: Unknown image Format" NLP
, __FUNCTION__
);
774 case I8272_FORMAT_TRACK
: /* FORMAT A TRACK */
775 for(i8272_info
->fdc_sector
= 1;i8272_info
->fdc_sector
<=i8272_info
->fdc_sc
;i8272_info
->fdc_sector
++) {
776 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" Format Track %d, Sector=%d, len=%d" NLP
,
779 i8272_info
->fdc_sector
,
780 128 << i8272_info
->fdc_sec_len
));
781 switch((pDrive
->uptr
)->u3
)
784 if(pDrive
->imd
== NULL
) {
785 printf(".imd is NULL!" NLP
);
787 TRACE_PRINT(WR_DATA_MSG
, ("%s: Write: imd=%p t=%i h=%i s=%i l=%i" NLP
,
788 __FUNCTION__
, pDrive
->imd
, pDrive
->track
, i8272_info
->fdc_head
,
789 i8272_info
->fdc_sector
, 128 << i8272_info
->fdc_sec_len
));
790 memset(sdata
.raw
, i8272_info
->fdc_fillbyte
, 128 << i8272_info
->fdc_sec_len
);
791 sectWrite(pDrive
->imd
,
793 i8272_info
->fdc_head
,
794 i8272_info
->fdc_sector
,
796 128 << i8272_info
->fdc_sec_len
,
799 i8272_info
->result
[1] = 0x80;
800 i8272_info
->result
[5] = i8272_info
->fdc_sector
;
803 printf("%s: DSK Format not supported" NLP
, __FUNCTION__
);
806 printf("%s: CPT Format not supported" NLP
, __FUNCTION__
);
809 printf("%s: Unknown image Format" NLP
, __FUNCTION__
);
815 case I8272_SCAN_LOW_EQUAL
: /* SCAN LOW OR EQUAL */
816 case I8272_SCAN_HIGH_EQUAL
: /* SCAN HIGH OR EQUAL */
817 case I8272_SCAN_EQUAL
: /* SCAN EQUAL */
818 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
" Scan Data" NLP
,
820 printf("I8272: " ADDRESS_FORMAT
" Scan not implemented." NLP
, PCX
);
822 case I8272_READ_ID
: /* READ ID */
823 TRACE_PRINT(CMD_MSG
, ("I8272: " ADDRESS_FORMAT
824 " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%02x H=%02x R=%02x N=%02x"
825 NLP
, PCX
, i8272_info
->sel_drive
, i8272_info
->result
[0],
826 i8272_info
->result
[1],i8272_info
->result
[2],i8272_info
->result
[3],
827 i8272_info
->result
[4],i8272_info
->result
[5],i8272_info
->result
[6]));
836 if(i8272_info
->result_len
!= 0) {
837 i8272_info
->fdc_phase
++;
839 i8272_info
->fdc_phase
= 0;
842 i8272_info
->result_index
= 0;
854 static uint8
I8272_Setup_Cmd(uint8 fdc_cmd
)
859 case I8272_READ_DATA
:
860 case I8272_WRITE_DATA
:
861 case I8272_READ_DELETED_DATA
:
862 case I8272_WRITE_DELETED_DATA
:
863 case I8272_READ_TRACK
:
864 case I8272_SCAN_LOW_EQUAL
:
865 case I8272_SCAN_HIGH_EQUAL
:
866 case I8272_SCAN_EQUAL
:
867 i8272_info
->cmd_len
= 9;
868 i8272_info
->result_len
= 7;
870 case I8272_READ_ID
: /* READ ID */
871 i8272_info
->cmd_len
= 2;
872 i8272_info
->result_len
= 7;
874 case I8272_RECALIBRATE
: /* RECALIBRATE */
875 i8272_info
->cmd_len
= 2;
876 i8272_info
->result_len
= 0;
878 case I8272_FORMAT_TRACK
: /* FORMAT A TRACK */
879 i8272_info
->cmd_len
= 6;
880 i8272_info
->result_len
= 7;
882 case I8272_SENSE_INTR_STATUS
: /* SENSE INTERRUPT STATUS */
883 i8272_info
->cmd_len
= 1;
884 i8272_info
->result_len
= 2;
886 case I8272_SPECIFY
: /* SPECIFY */
887 i8272_info
->cmd_len
= 3;
888 i8272_info
->result_len
= 0;
890 case I8272_SENSE_DRIVE_STATUS
: /* SENSE DRIVE STATUS */
891 i8272_info
->cmd_len
= 2;
892 i8272_info
->result_len
= 1;
894 case I8272_SEEK
: /* SEEK */
895 i8272_info
->cmd_len
= 3;
896 i8272_info
->result_len
= 0;
898 default: /* INVALID */
899 i8272_info
->cmd_len
= 1;
900 i8272_info
->result_len
= 1;