First Commit of my working state
[simh.git] / AltairZ80 / i8272.c
1 /*************************************************************************
2 * *
3 * $Id: i8272.c 1773 2008-01-11 05:46:19Z hharte $ *
4 * *
5 * Copyright (c) 2007-2008 Howard M. Harte. *
6 * http://www.hartetec.com *
7 * *
8 * Permission is hereby granted, free of charge, to any person obtaining *
9 * a copy of this software and associated documentation files (the *
10 * "Software"), to deal in the Software without restriction, including *
11 * without limitation the rights to use, copy, modify, merge, publish, *
12 * distribute, sublicense, and/or sell copies of the Software, and to *
13 * permit persons to whom the Software is furnished to do so, subject to *
14 * the following conditions: *
15 * *
16 * The above copyright notice and this permission notice shall be *
17 * included in all copies or substantial portions of the Software. *
18 * *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
22 * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
26 * *
27 * Except as contained in this notice, the name of Howard M. Harte shall *
28 * not be used in advertising or otherwise to promote the sale, use or *
29 * other dealings in this Software without prior written authorization *
30 * Howard M. Harte. *
31 * *
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *
33 * *
34 * Module Description: *
35 * Generic Intel 8272 Disk Controller module for SIMH. *
36 * *
37 * Environment: *
38 * User mode only *
39 * *
40 *************************************************************************/
41
42 /* Change log:
43 - 19-Apr-2008, Tony Nicholson, added other .IMD formats
44 */
45
46 /*#define DBG_MSG */
47
48 #include "altairz80_defs.h"
49
50 #if defined (_WIN32)
51 #include <windows.h>
52 #endif
53
54 #include "sim_imd.h"
55 #include "i8272.h"
56
57 #ifdef DBG_MSG
58 #define DBG_PRINT(args) printf args
59 #else
60 #define DBG_PRINT(args)
61 #endif
62
63 #define SEEK_MSG 0x01
64 #define CMD_MSG 0x04
65 #define RD_DATA_MSG 0x08
66 #define WR_DATA_MSG 0x10
67 #define STATUS_MSG 0x20
68 #define VERBOSE_MSG 0x80
69
70 #define I8272_MAX_DRIVES 4
71 #define I8272_SECTOR_LEN 8192
72
73 #define CMD_PHASE 0
74 #define EXEC_PHASE 1
75 #define DATA_PHASE 2
76
77 typedef union {
78 uint8 raw[I8272_SECTOR_LEN];
79 } SECTOR_FORMAT;
80
81 typedef struct {
82 UNIT *uptr;
83 DISK_INFO *imd;
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? */
89 } I8272_DRIVE_INFO;
90
91 typedef struct {
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];
122 } I8272_INFO;
123
124 static SECTOR_FORMAT sdata;
125 extern uint32 PCX;
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);
130
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);
134
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. */
144
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
161
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
168
169 static int32 trace_level = 0; /* Disable all tracing by default. */
170 static int32 bootstrap = 0;
171
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);
175
176 I8272_INFO i8272_info_data = { { 0x0, 0, 0xC0, 2 } };
177 I8272_INFO *i8272_info = &i8272_info_data;
178
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) }
184 };
185
186 static REG i8272_reg[] = {
187 { HRDATA (TRACELEVEL, trace_level, 16), },
188 { DRDATA (BOOTSTRAP, bootstrap, 10), },
189 { NULL }
190 };
191
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 },
200 { 0 }
201 };
202
203 DEVICE i8272_dev = {
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,
209 NULL, NULL, NULL
210 };
211
212 static uint8 I8272_Setup_Cmd(uint8 fdc_cmd);
213
214
215 /* Reset routine */
216 static t_stat i8272_reset(DEVICE *dptr)
217 {
218 PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
219
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);
222 } else {
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);
226 return SCPE_ARG;
227 }
228 }
229 return SCPE_OK;
230 }
231
232
233 /* find_unit_index find index of a unit
234
235 Inputs:
236 uptr = pointer to unit
237 Outputs:
238 result = index of device
239 */
240 int32 find_unit_index (UNIT *uptr)
241 {
242 DEVICE *dptr;
243 uint32 i;
244
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) {
249 break;
250 }
251 }
252 if(i == dptr->numunits) {
253 return (-1);
254 }
255 return (i);
256 }
257
258 /* Attach routine */
259 t_stat i8272_attach(UNIT *uptr, char *cptr)
260 {
261 char header[4];
262 t_stat r;
263 int32 i = 0;
264
265 r = attach_unit(uptr, cptr); /* attach unit */
266 if ( r != SCPE_OK) /* error? */
267 return r;
268
269 /* Determine length of this disk */
270 uptr->capac = sim_fsize(uptr->fileref);
271
272 i = find_unit_index(uptr);
273
274 if (i == -1) {
275 return (SCPE_IERR);
276 }
277
278 DBG_PRINT(("Attach I8272%d\n", i));
279 i8272_info->drive[i].uptr = uptr;
280
281 /* Default to drive not ready */
282 i8272_info->drive[i].ready = 0;
283
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;
291 i8272_detach(uptr);
292 return SCPE_OPENERR;
293 } else {
294 printf("DSK images not yet supported\n");
295 uptr->u3 = IMAGE_TYPE_DSK;
296 i8272_detach(uptr);
297 return SCPE_OPENERR;
298 }
299 } else {
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;
303 i8272_detach(uptr);
304 return SCPE_OPENERR;
305 }
306
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",
310 uptr->capac);
311
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");
315 i8272_detach(uptr);
316 return SCPE_OPENERR;
317 }
318
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)
324 printf("\n");
325 } else {
326 i8272_info->drive[i].imd = NULL;
327 }
328
329 return SCPE_OK;
330 }
331
332
333 /* Detach routine */
334 t_stat i8272_detach(UNIT *uptr)
335 {
336 t_stat r;
337 int8 i;
338
339 i = find_unit_index(uptr);
340
341 if (i == -1) {
342 return (SCPE_IERR);
343 }
344
345 DBG_PRINT(("Detach I8272%d\n", i));
346 diskClose(i8272_info->drive[i].imd);
347 i8272_info->drive[i].ready = 0;
348
349 r = detach_unit(uptr); /* detach unit */
350 if ( r != SCPE_OK)
351 return r;
352
353 return SCPE_OK;
354 }
355
356
357 static int32 i8272dev(const int32 port, const int32 io, const int32 data)
358 {
359 DBG_PRINT(("I8272: " ADDRESS_FORMAT " %s, Port 0x%02x Data 0x%02x" NLP,
360 PCX, io ? "OUT" : " IN", port, data));
361 if(io) {
362 I8272_Write(port, data);
363 return 0;
364 } else {
365 return(I8272_Read(port));
366 }
367 }
368
369 uint8 I8272_Set_DMA(const uint32 dma_addr)
370 {
371 i8272_info->fdc_dma_addr = dma_addr & 0xFFFFFF;
372
373 return 0;
374 }
375
376 static uint8 floorlog2(unsigned int n)
377 {
378 /* Compute log2(n) */
379 uint8 r = 0;
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 */
386 }
387
388 uint8 I8272_Read(const uint32 Addr)
389 {
390 uint8 cData;
391 I8272_DRIVE_INFO *pDrive;
392
393 pDrive = &i8272_info->drive[i8272_info->sel_drive];
394
395 if(pDrive->uptr == NULL) {
396 return 0xFF;
397 }
398
399 cData = 0x00;
400
401 switch(Addr & 0x3) {
402 case I8272_FDC_MSR:
403 cData = i8272_info->fdc_msr | 0x80;
404 if(i8272_info->fdc_phase == 0) {
405 cData &= ~0x40;
406 } else {
407 cData |= 0x40;
408 }
409
410 TRACE_PRINT(STATUS_MSG, ("I8272: " ADDRESS_FORMAT " RD FDC MSR = 0x%02x" NLP, PCX, cData));
411 break;
412 case I8272_FDC_DATA:
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;
419 }
420 }
421
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));
423
424 break;
425 default:
426 TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " Cannot read register %x" NLP, PCX, Addr));
427 cData = 0xFF;
428 }
429
430 return (cData);
431 }
432
433 static char *messages[0x20] = {
434 /* 0 1 2 3 */
435 "Undefined Command 0x0","Undefined Command 0x1","Read Track", "Specify",
436 /* 4 5 6 7 */
437 "Sense Drive Status", "Write Data", "Read Data", "Recalibrate",
438 /* 8 9 A B */
439 "Sense Interrupt Status", "Write Deleted Data", "Read ID", "Undefined Command 0xB",
440 /* C D E F */
441 "Read Deleted Data", "Format Track", "Undefined Command 0xE","Seek",
442 /* 10 11 12 13 */
443 "Undefined Command 0x10","Scan Equal", "Undefined Command 0x12","Undefined Command 0x13",
444 /* 14 15 16 17 */
445 "Undefined Command 0x14","Undefined Command 0x15","Undefined Command 0x16","Undefined Command 0x17",
446 /* 18 19 1A 1B */
447 "Undefined Command 0x18","Scan Low Equal", "Undefined Command 0x1A","Undefined Command 0x1B",
448 /* 1C 1D 1E 1F */
449 "Undefined Command 0x1C","Scan High Equal", "Undefined Command 0x1E","Undefined Command 0x1F"
450 };
451
452 uint8 I8272_Write(const uint32 Addr, uint8 cData)
453 {
454 I8272_DRIVE_INFO *pDrive;
455 unsigned int flags;
456 unsigned int readlen;
457 uint8 disk_read = 0;
458 int32 i;
459
460 pDrive = &i8272_info->drive[i8272_info->sel_drive];
461
462 if(pDrive->uptr == NULL) {
463 return 0xFF;
464 }
465
466 switch(Addr & 0x3) {
467 case I8272_FDC_MSR:
468 TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x" NLP,
469 PCX, cData));
470 break;
471 case I8272_FDC_DATA:
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;
476
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);
481 }
482 i8272_info->cmd_index ++;
483
484 if(i8272_info->cmd_len == i8272_info->cmd_index) {
485 i8272_info->cmd_index = 0;
486 i8272_info->fdc_phase = EXEC_PHASE;
487 }
488 }
489
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) {
507 return 0xFF;
508 }
509
510 if(pDrive->track != i8272_info->cmd[2]) {
511 i8272_info->fdc_seek_end = 1;
512 } else {
513 i8272_info->fdc_seek_end = 0;
514 }
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];
522
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,
525 PCX,
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",
531 pDrive->track,
532 i8272_info->fdc_head,
533 i8272_info->fdc_sector,
534 i8272_info->fdc_sec_len,
535 i8272_info->fdc_eot,
536 i8272_info->fdc_gpl,
537 i8272_info->fdc_dtl));
538
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;
542
543 i8272_info->fdc_status[1] = 0;
544 i8272_info->fdc_status[2] = 0;
545
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;
553 break;
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) {
560 return 0xFF;
561 }
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*/
569 return 0xFF;
570 }
571 i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2;
572 i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3);
573
574 i8272_info->fdc_status[1] = 0;
575 i8272_info->fdc_status[2] = 0;
576
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*/
584 break;
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) {
589 return 0xFF;
590 }
591
592 pDrive->track = 0;
593 i8272_info->fdc_phase = 0; /* No result phase */
594 pDrive->track = 0;
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));
598 break;
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) {
606 return 0xFF;
607 }
608
609 if(pDrive->track != i8272_info->cmd[2]) {
610 i8272_info->fdc_seek_end = 1;
611 } else {
612 i8272_info->fdc_seek_end = 0;
613 }
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];
618
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,
620 PCX,
621 i8272_info->sel_drive,
622 i8272_info->fdc_mfm ? "MFM" : "FM",
623 pDrive->track,
624 i8272_info->fdc_head,
625 i8272_info->fdc_sec_len,
626 i8272_info->fdc_sc,
627 i8272_info->fdc_gpl,
628 i8272_info->fdc_fillbyte));
629
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 */
633
634 i8272_info->fdc_status[1] = 0;
635 i8272_info->fdc_status[2] = 0;
636
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;
644 break;
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;
650 break;
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,
658 PCX,
659 i8272_info->fdc_srt,
660 i8272_info->fdc_hut,
661 i8272_info->fdc_hlt,
662 i8272_info->fdc_nd ? "NON-DMA" : "DMA"));
663 break;
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) {
669 return 0xFF;
670 }
671
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? */
675 }
676 if(imdIsWriteLocked(pDrive->imd)) {
677 i8272_info->result[0] |= DRIVE_STATUS_WP; /* Write Protected? */
678 }
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]));
684 break;
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) {
693 return 0xFF;
694 }
695
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));
700 break;
701 default: /* INVALID */
702 break;
703 }
704
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:
712 disk_read = 1;
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)
721 {
722 case IMAGE_TYPE_IMD:
723 if(pDrive->imd == NULL) {
724 printf(".imd is NULL!" NLP);
725 }
726 if(disk_read) { /* Read sector */
727 sectRead(pDrive->imd,
728 pDrive->track,
729 i8272_info->fdc_head,
730 i8272_info->fdc_sector,
731 sdata.raw,
732 128 << i8272_info->fdc_sec_len,
733 &flags,
734 &readlen);
735
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++;
739 }
740 TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred to RAM at 0x%06x" NLP,
741 PCX, i8272_info->fdc_dma_addr));
742 } else { /* Write */
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++;
746 }
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,
750 pDrive->track,
751 i8272_info->fdc_head,
752 i8272_info->fdc_sector,
753 sdata.raw,
754 128 << i8272_info->fdc_sec_len,
755 &flags,
756 &readlen);
757 }
758
759 i8272_info->result[5] = i8272_info->fdc_sector;
760 i8272_info->result[1] = 0x80;
761 break;
762 case IMAGE_TYPE_DSK:
763 printf("%s: DSK Format not supported" NLP, __FUNCTION__);
764 break;
765 case IMAGE_TYPE_CPT:
766 printf("%s: CPT Format not supported" NLP, __FUNCTION__);
767 break;
768 default:
769 printf("%s: Unknown image Format" NLP, __FUNCTION__);
770 break;
771 }
772 }
773 break;
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,
777 PCX,
778 pDrive->track,
779 i8272_info->fdc_sector,
780 128 << i8272_info->fdc_sec_len));
781 switch((pDrive->uptr)->u3)
782 {
783 case IMAGE_TYPE_IMD:
784 if(pDrive->imd == NULL) {
785 printf(".imd is NULL!" NLP);
786 }
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,
792 pDrive->track,
793 i8272_info->fdc_head,
794 i8272_info->fdc_sector,
795 sdata.raw,
796 128 << i8272_info->fdc_sec_len,
797 &flags,
798 &readlen);
799 i8272_info->result[1] = 0x80;
800 i8272_info->result[5] = i8272_info->fdc_sector;
801 break;
802 case IMAGE_TYPE_DSK:
803 printf("%s: DSK Format not supported" NLP, __FUNCTION__);
804 break;
805 case IMAGE_TYPE_CPT:
806 printf("%s: CPT Format not supported" NLP, __FUNCTION__);
807 break;
808 default:
809 printf("%s: Unknown image Format" NLP, __FUNCTION__);
810 break;
811 }
812 }
813 break;
814
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,
819 PCX));
820 printf("I8272: " ADDRESS_FORMAT " Scan not implemented." NLP, PCX);
821 break;
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]));
828 break;
829
830 default:
831 break;
832 }
833 }
834
835
836 if(i8272_info->result_len != 0) {
837 i8272_info->fdc_phase ++;
838 } else {
839 i8272_info->fdc_phase = 0;
840 }
841
842 i8272_info->result_index = 0;
843 }
844
845
846 break;
847 }
848
849 cData = 0x00;
850
851 return (cData);
852 }
853
854 static uint8 I8272_Setup_Cmd(uint8 fdc_cmd)
855 {
856 uint8 result = 0;
857
858 switch(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;
869 break;
870 case I8272_READ_ID: /* READ ID */
871 i8272_info->cmd_len = 2;
872 i8272_info->result_len = 7;
873 break;
874 case I8272_RECALIBRATE: /* RECALIBRATE */
875 i8272_info->cmd_len = 2;
876 i8272_info->result_len = 0;
877 break;
878 case I8272_FORMAT_TRACK: /* FORMAT A TRACK */
879 i8272_info->cmd_len = 6;
880 i8272_info->result_len = 7;
881 break;
882 case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */
883 i8272_info->cmd_len = 1;
884 i8272_info->result_len = 2;
885 break;
886 case I8272_SPECIFY: /* SPECIFY */
887 i8272_info->cmd_len = 3;
888 i8272_info->result_len = 0;
889 break;
890 case I8272_SENSE_DRIVE_STATUS: /* SENSE DRIVE STATUS */
891 i8272_info->cmd_len = 2;
892 i8272_info->result_len = 1;
893 break;
894 case I8272_SEEK: /* SEEK */
895 i8272_info->cmd_len = 3;
896 i8272_info->result_len = 0;
897 break;
898 default: /* INVALID */
899 i8272_info->cmd_len = 1;
900 i8272_info->result_len = 1;
901 result = -1;
902 break;
903 }
904 return (result);
905 }
906