First Commit of my working state
[simh.git] / AltairZ80 / i8272.c
... / ...
CommitLineData
1/*************************************************************************\r
2 * *\r
3 * $Id: i8272.c 1773 2008-01-11 05:46:19Z hharte $ *\r
4 * *\r
5 * Copyright (c) 2007-2008 Howard M. Harte. *\r
6 * http://www.hartetec.com *\r
7 * *\r
8 * Permission is hereby granted, free of charge, to any person obtaining *\r
9 * a copy of this software and associated documentation files (the *\r
10 * "Software"), to deal in the Software without restriction, including *\r
11 * without limitation the rights to use, copy, modify, merge, publish, *\r
12 * distribute, sublicense, and/or sell copies of the Software, and to *\r
13 * permit persons to whom the Software is furnished to do so, subject to *\r
14 * the following conditions: *\r
15 * *\r
16 * The above copyright notice and this permission notice shall be *\r
17 * included in all copies or substantial portions of the Software. *\r
18 * *\r
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *\r
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *\r
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *\r
22 * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *\r
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *\r
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *\r
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *\r
26 * *\r
27 * Except as contained in this notice, the name of Howard M. Harte shall *\r
28 * not be used in advertising or otherwise to promote the sale, use or *\r
29 * other dealings in this Software without prior written authorization *\r
30 * Howard M. Harte. *\r
31 * *\r
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *\r
33 * *\r
34 * Module Description: *\r
35 * Generic Intel 8272 Disk Controller module for SIMH. *\r
36 * *\r
37 * Environment: *\r
38 * User mode only *\r
39 * *\r
40 *************************************************************************/\r
41\r
42/* Change log:\r
43 - 19-Apr-2008, Tony Nicholson, added other .IMD formats\r
44*/\r
45\r
46/*#define DBG_MSG */\r
47\r
48#include "altairz80_defs.h"\r
49\r
50#if defined (_WIN32)\r
51#include <windows.h>\r
52#endif\r
53\r
54#include "sim_imd.h"\r
55#include "i8272.h"\r
56\r
57#ifdef DBG_MSG\r
58#define DBG_PRINT(args) printf args\r
59#else\r
60#define DBG_PRINT(args)\r
61#endif\r
62\r
63#define SEEK_MSG 0x01\r
64#define CMD_MSG 0x04\r
65#define RD_DATA_MSG 0x08\r
66#define WR_DATA_MSG 0x10\r
67#define STATUS_MSG 0x20\r
68#define VERBOSE_MSG 0x80\r
69\r
70#define I8272_MAX_DRIVES 4\r
71#define I8272_SECTOR_LEN 8192\r
72\r
73#define CMD_PHASE 0\r
74#define EXEC_PHASE 1\r
75#define DATA_PHASE 2\r
76\r
77typedef union {\r
78 uint8 raw[I8272_SECTOR_LEN];\r
79} SECTOR_FORMAT;\r
80\r
81typedef struct {\r
82 UNIT *uptr;\r
83 DISK_INFO *imd;\r
84 uint8 ntracks; /* number of tracks */\r
85 uint8 nheads; /* number of heads */\r
86 uint32 sectsize; /* sector size, not including pre/postamble */\r
87 uint8 track; /* Current Track */\r
88 uint8 ready; /* Is drive ready? */\r
89} I8272_DRIVE_INFO;\r
90\r
91typedef struct {\r
92 PNP_INFO pnp; /* Plug-n-Play Information */\r
93 uint32 fdc_dma_addr;/* DMA Transfer Address */\r
94 uint8 fdc_msr; /* 8272 Main Status Register */\r
95 uint8 fdc_phase; /* Phase that the 8272 is currently in */\r
96 uint8 fdc_srt; /* Step Rate in ms */\r
97 uint8 fdc_hut; /* Head Unload Time in ms */\r
98 uint8 fdc_hlt; /* Head Load Time in ms */\r
99 uint8 fdc_nd; /* Non-DMA Mode 1=Non-DMA, 0=DMA */\r
100 uint8 fdc_head; /* H Head Number */\r
101 uint8 fdc_sector; /* R Record (Sector) */\r
102 uint8 fdc_sec_len; /* N Sector Length */\r
103 uint8 fdc_eot; /* EOT End of Track (Final sector number of cyl) */\r
104 uint8 fdc_gpl; /* GPL Gap3 Length */\r
105 uint8 fdc_dtl; /* DTL Data Length */\r
106 uint8 fdc_mt; /* Multiple sectors */\r
107 uint8 fdc_mfm; /* MFM mode */\r
108 uint8 fdc_sk; /* Skip Deleted Data */\r
109 uint8 fdc_hds; /* Head Select */\r
110 uint8 fdc_fillbyte; /* Fill-byte used for FORMAT TRACK */\r
111 uint8 fdc_sc; /* Sector count for FORMAT TRACK */\r
112 uint8 fdc_status[3];/* Status Register Bytes */\r
113 uint8 fdc_seek_end; /* Seek was executed successfully */\r
114 uint8 cmd_index; /* Index of command byte */\r
115 uint8 cmd[10]; /* Storage for current command */\r
116 uint8 cmd_len; /* FDC Command Length */\r
117 uint8 result_index; /* Index of result byte */\r
118 uint8 result[10]; /* Result data */\r
119 uint8 result_len; /* FDC Result Length */\r
120 uint8 sel_drive; /* Currently selected drive */\r
121 I8272_DRIVE_INFO drive[I8272_MAX_DRIVES];\r
122} I8272_INFO;\r
123\r
124static SECTOR_FORMAT sdata;\r
125extern uint32 PCX;\r
126extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);\r
127extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);\r
128extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,\r
129 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);\r
130\r
131/* These are needed for DMA. PIO Mode has not been implemented yet. */\r
132extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);\r
133extern uint8 GetBYTEWrapper(const uint32 Addr);\r
134\r
135#define UNIT_V_I8272_WLK (UNIT_V_UF + 0) /* write locked */\r
136#define UNIT_I8272_WLK (1 << UNIT_V_I8272_WLK)\r
137#define UNIT_V_I8272_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */\r
138#define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE)\r
139#define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */\r
140#define I8272_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */\r
141#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */\r
142#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */\r
143#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */\r
144\r
145/* Intel 8272 Commands */\r
146#define I8272_READ_TRACK 0x02\r
147#define I8272_SPECIFY 0x03\r
148#define I8272_SENSE_DRIVE_STATUS 0x04\r
149#define I8272_WRITE_DATA 0x05\r
150#define I8272_READ_DATA 0x06\r
151#define I8272_RECALIBRATE 0x07\r
152#define I8272_SENSE_INTR_STATUS 0x08\r
153#define I8272_WRITE_DELETED_DATA 0x09\r
154#define I8272_READ_ID 0x0A\r
155#define I8272_READ_DELETED_DATA 0x0C\r
156#define I8272_FORMAT_TRACK 0x0D\r
157#define I8272_SEEK 0x0F\r
158#define I8272_SCAN_EQUAL 0x11\r
159#define I8272_SCAN_LOW_EQUAL 0x19\r
160#define I8272_SCAN_HIGH_EQUAL 0x1D\r
161\r
162/* SENSE DRIVE STATUS bit definitions */\r
163#define DRIVE_STATUS_TWO_SIDED 0x08\r
164#define DRIVE_STATUS_TRACK0 0x10\r
165#define DRIVE_STATUS_READY 0x20\r
166#define DRIVE_STATUS_WP 0x40\r
167#define DRIVE_STATUS_FAULT 0x80\r
168\r
169static int32 trace_level = 0; /* Disable all tracing by default. */\r
170static int32 bootstrap = 0;\r
171\r
172static int32 i8272dev(const int32 port, const int32 io, const int32 data);\r
173static t_stat i8272_reset(DEVICE *dptr);\r
174int32 find_unit_index (UNIT *uptr);\r
175\r
176I8272_INFO i8272_info_data = { { 0x0, 0, 0xC0, 2 } };\r
177I8272_INFO *i8272_info = &i8272_info_data;\r
178\r
179static UNIT i8272_unit[] = {\r
180 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) },\r
181 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) },\r
182 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) },\r
183 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) }\r
184};\r
185\r
186static REG i8272_reg[] = {\r
187 { HRDATA (TRACELEVEL, trace_level, 16), },\r
188 { DRDATA (BOOTSTRAP, bootstrap, 10), },\r
189 { NULL }\r
190};\r
191\r
192static MTAB i8272_mod[] = {\r
193 { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },\r
194 { UNIT_I8272_WLK, 0, "WRTENB", "WRTENB", NULL },\r
195 { UNIT_I8272_WLK, UNIT_I8272_WLK, "WRTLCK", "WRTLCK", NULL },\r
196 /* quiet, no warning messages */\r
197 { UNIT_I8272_VERBOSE, 0, "QUIET", "QUIET", NULL },\r
198 /* verbose, show warning messages */\r
199 { UNIT_I8272_VERBOSE, UNIT_I8272_VERBOSE, "VERBOSE", "VERBOSE", NULL },\r
200 { 0 }\r
201};\r
202\r
203DEVICE i8272_dev = {\r
204 "I8272", i8272_unit, i8272_reg, i8272_mod,\r
205 I8272_MAX_DRIVES, 10, 31, 1, I8272_MAX_DRIVES, I8272_MAX_DRIVES,\r
206 NULL, NULL, &i8272_reset,\r
207 NULL, &i8272_attach, &i8272_detach,\r
208 &i8272_info_data, (DEV_DISABLE | DEV_DIS), 0,\r
209 NULL, NULL, NULL\r
210};\r
211\r
212static uint8 I8272_Setup_Cmd(uint8 fdc_cmd);\r
213\r
214\r
215/* Reset routine */\r
216static t_stat i8272_reset(DEVICE *dptr)\r
217{\r
218 PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;\r
219\r
220 if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */\r
221 sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &i8272dev, TRUE);\r
222 } else {\r
223 /* Connect I/O Ports at base address */\r
224 if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &i8272dev, FALSE) != 0) {\r
225 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);\r
226 return SCPE_ARG;\r
227 }\r
228 }\r
229 return SCPE_OK;\r
230}\r
231\r
232\r
233/* find_unit_index find index of a unit\r
234\r
235 Inputs:\r
236 uptr = pointer to unit\r
237 Outputs:\r
238 result = index of device\r
239*/\r
240int32 find_unit_index (UNIT *uptr)\r
241{\r
242 DEVICE *dptr;\r
243 uint32 i;\r
244\r
245 if (uptr == NULL) return (-1);\r
246 dptr = find_dev_from_unit(uptr);\r
247 for(i=0; i<dptr->numunits; i++) {\r
248 if(dptr->units + i == uptr) {\r
249 break;\r
250 }\r
251 }\r
252 if(i == dptr->numunits) {\r
253 return (-1);\r
254 }\r
255 return (i);\r
256}\r
257\r
258/* Attach routine */\r
259t_stat i8272_attach(UNIT *uptr, char *cptr)\r
260{\r
261 char header[4];\r
262 t_stat r;\r
263 int32 i = 0;\r
264\r
265 r = attach_unit(uptr, cptr); /* attach unit */\r
266 if ( r != SCPE_OK) /* error? */\r
267 return r;\r
268\r
269 /* Determine length of this disk */\r
270 uptr->capac = sim_fsize(uptr->fileref);\r
271\r
272 i = find_unit_index(uptr);\r
273\r
274 if (i == -1) {\r
275 return (SCPE_IERR);\r
276 }\r
277\r
278 DBG_PRINT(("Attach I8272%d\n", i));\r
279 i8272_info->drive[i].uptr = uptr;\r
280\r
281 /* Default to drive not ready */\r
282 i8272_info->drive[i].ready = 0;\r
283\r
284 if(uptr->capac > 0) {\r
285 fgets(header, 4, uptr->fileref);\r
286 if(!strcmp(header, "IMD")) {\r
287 uptr->u3 = IMAGE_TYPE_IMD;\r
288 } else if(!strcmp(header, "CPT")) {\r
289 printf("CPT images not yet supported\n");\r
290 uptr->u3 = IMAGE_TYPE_CPT;\r
291 i8272_detach(uptr);\r
292 return SCPE_OPENERR;\r
293 } else {\r
294 printf("DSK images not yet supported\n");\r
295 uptr->u3 = IMAGE_TYPE_DSK;\r
296 i8272_detach(uptr);\r
297 return SCPE_OPENERR;\r
298 }\r
299 } else {\r
300 /* creating file, must be DSK format. */\r
301 printf("Cannot create images, must start with a I8272 IMD image.\n");\r
302 uptr->u3 = IMAGE_TYPE_DSK;\r
303 i8272_detach(uptr);\r
304 return SCPE_OPENERR;\r
305 }\r
306\r
307 if (uptr->flags & UNIT_I8272_VERBOSE)\r
308 printf("I8272%d: attached to '%s', type=%s, len=%d\n", i, cptr,\r
309 uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",\r
310 uptr->capac);\r
311\r
312 if(uptr->u3 == IMAGE_TYPE_IMD) {\r
313 if(uptr->capac < I8272_CAPACITY_SSSD) { /*was 318000 but changed to allow 8inch SSSD disks*/\r
314 printf("IMD file too small for use with SIMH.\nCopy an existing file and format it with CP/M.\n");\r
315 i8272_detach(uptr);\r
316 return SCPE_OPENERR;\r
317 }\r
318\r
319 if (uptr->flags & UNIT_I8272_VERBOSE)\r
320 printf("--------------------------------------------------------\n");\r
321 i8272_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_I8272_VERBOSE));\r
322 i8272_info->drive[i].ready = 1;\r
323 if (uptr->flags & UNIT_I8272_VERBOSE)\r
324 printf("\n");\r
325 } else {\r
326 i8272_info->drive[i].imd = NULL;\r
327 }\r
328\r
329 return SCPE_OK;\r
330}\r
331\r
332\r
333/* Detach routine */\r
334t_stat i8272_detach(UNIT *uptr)\r
335{\r
336 t_stat r;\r
337 int8 i;\r
338\r
339 i = find_unit_index(uptr);\r
340\r
341 if (i == -1) {\r
342 return (SCPE_IERR);\r
343 }\r
344\r
345 DBG_PRINT(("Detach I8272%d\n", i));\r
346 diskClose(i8272_info->drive[i].imd);\r
347 i8272_info->drive[i].ready = 0;\r
348\r
349 r = detach_unit(uptr); /* detach unit */\r
350 if ( r != SCPE_OK)\r
351 return r;\r
352\r
353 return SCPE_OK;\r
354}\r
355\r
356\r
357static int32 i8272dev(const int32 port, const int32 io, const int32 data)\r
358{\r
359 DBG_PRINT(("I8272: " ADDRESS_FORMAT " %s, Port 0x%02x Data 0x%02x" NLP,\r
360 PCX, io ? "OUT" : " IN", port, data));\r
361 if(io) {\r
362 I8272_Write(port, data);\r
363 return 0;\r
364 } else {\r
365 return(I8272_Read(port));\r
366 }\r
367}\r
368\r
369uint8 I8272_Set_DMA(const uint32 dma_addr)\r
370{\r
371 i8272_info->fdc_dma_addr = dma_addr & 0xFFFFFF;\r
372\r
373 return 0;\r
374}\r
375\r
376static uint8 floorlog2(unsigned int n)\r
377{\r
378 /* Compute log2(n) */\r
379 uint8 r = 0;\r
380 if(n >= 1<<16) { n >>=16; r += 16; }\r
381 if(n >= 1<< 8) { n >>= 8; r += 8; }\r
382 if(n >= 1<< 4) { n >>= 4; r += 4; }\r
383 if(n >= 1<< 2) { n >>= 2; r += 2; }\r
384 if(n >= 1<< 1) { r += 1; }\r
385 return ((n == 0) ? (0xFF) : r); /* 0xFF is error return value */\r
386}\r
387\r
388uint8 I8272_Read(const uint32 Addr)\r
389{\r
390 uint8 cData;\r
391 I8272_DRIVE_INFO *pDrive;\r
392\r
393 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
394\r
395 if(pDrive->uptr == NULL) {\r
396 return 0xFF;\r
397 }\r
398\r
399 cData = 0x00;\r
400\r
401 switch(Addr & 0x3) {\r
402 case I8272_FDC_MSR:\r
403 cData = i8272_info->fdc_msr | 0x80;\r
404 if(i8272_info->fdc_phase == 0) {\r
405 cData &= ~0x40;\r
406 } else {\r
407 cData |= 0x40;\r
408 }\r
409\r
410 TRACE_PRINT(STATUS_MSG, ("I8272: " ADDRESS_FORMAT " RD FDC MSR = 0x%02x" NLP, PCX, cData));\r
411 break;\r
412 case I8272_FDC_DATA:\r
413 if(i8272_info->fdc_phase == DATA_PHASE) {\r
414 cData = i8272_info->result[i8272_info->result_index];\r
415 i8272_info->result_index ++;\r
416 if(i8272_info->result_index == i8272_info->result_len) {\r
417 TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " result phase complete." NLP, PCX));\r
418 i8272_info->fdc_phase = 0;\r
419 }\r
420 }\r
421\r
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));\r
423\r
424 break;\r
425 default:\r
426 TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " Cannot read register %x" NLP, PCX, Addr));\r
427 cData = 0xFF;\r
428 }\r
429\r
430 return (cData);\r
431}\r
432\r
433static char *messages[0x20] = {\r
434/* 0 1 2 3 */\r
435 "Undefined Command 0x0","Undefined Command 0x1","Read Track", "Specify",\r
436/* 4 5 6 7 */\r
437 "Sense Drive Status", "Write Data", "Read Data", "Recalibrate",\r
438/* 8 9 A B */\r
439 "Sense Interrupt Status", "Write Deleted Data", "Read ID", "Undefined Command 0xB",\r
440/* C D E F */\r
441 "Read Deleted Data", "Format Track", "Undefined Command 0xE","Seek",\r
442/* 10 11 12 13 */\r
443 "Undefined Command 0x10","Scan Equal", "Undefined Command 0x12","Undefined Command 0x13",\r
444/* 14 15 16 17 */\r
445 "Undefined Command 0x14","Undefined Command 0x15","Undefined Command 0x16","Undefined Command 0x17",\r
446/* 18 19 1A 1B */\r
447 "Undefined Command 0x18","Scan Low Equal", "Undefined Command 0x1A","Undefined Command 0x1B",\r
448/* 1C 1D 1E 1F */\r
449 "Undefined Command 0x1C","Scan High Equal", "Undefined Command 0x1E","Undefined Command 0x1F"\r
450};\r
451\r
452uint8 I8272_Write(const uint32 Addr, uint8 cData)\r
453{\r
454 I8272_DRIVE_INFO *pDrive;\r
455 unsigned int flags;\r
456 unsigned int readlen;\r
457 uint8 disk_read = 0;\r
458 int32 i;\r
459\r
460 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
461\r
462 if(pDrive->uptr == NULL) {\r
463 return 0xFF;\r
464 }\r
465\r
466 switch(Addr & 0x3) {\r
467 case I8272_FDC_MSR:\r
468 TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x" NLP,\r
469 PCX, cData));\r
470 break;\r
471 case I8272_FDC_DATA:\r
472 TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " WR Data, phase=%d, index=%d" NLP,\r
473 PCX, i8272_info->fdc_phase, i8272_info->cmd_index));\r
474 if(i8272_info->fdc_phase == CMD_PHASE) {\r
475 i8272_info->cmd[i8272_info->cmd_index] = cData;\r
476\r
477 if(i8272_info->cmd_index == 0) {\r
478 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]" NLP,\r
479 PCX, cData & 0x1F, messages[cData & 0x1F]));\r
480 I8272_Setup_Cmd(cData & 0x1F);\r
481 }\r
482 i8272_info->cmd_index ++;\r
483\r
484 if(i8272_info->cmd_len == i8272_info->cmd_index) {\r
485 i8272_info->cmd_index = 0;\r
486 i8272_info->fdc_phase = EXEC_PHASE;\r
487 }\r
488 }\r
489\r
490 if(i8272_info->fdc_phase == EXEC_PHASE) {\r
491 switch(i8272_info->cmd[0] & 0x1F) {\r
492 case I8272_READ_DATA:\r
493 case I8272_WRITE_DATA:\r
494 case I8272_READ_DELETED_DATA:\r
495 case I8272_WRITE_DELETED_DATA:\r
496 case I8272_READ_TRACK:\r
497 case I8272_SCAN_LOW_EQUAL:\r
498 case I8272_SCAN_HIGH_EQUAL:\r
499 case I8272_SCAN_EQUAL:\r
500 i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7;\r
501 i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6;\r
502 i8272_info->fdc_sk = (i8272_info->cmd[0] & 0x20) >> 5;\r
503 i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2;\r
504 i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03);\r
505 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
506 if(pDrive->uptr == NULL) {\r
507 return 0xFF;\r
508 }\r
509\r
510 if(pDrive->track != i8272_info->cmd[2]) {\r
511 i8272_info->fdc_seek_end = 1;\r
512 } else {\r
513 i8272_info->fdc_seek_end = 0;\r
514 }\r
515 pDrive->track = i8272_info->cmd[2];\r
516 i8272_info->fdc_head = i8272_info->cmd[3];\r
517 i8272_info->fdc_sector = i8272_info->cmd[4];\r
518 i8272_info->fdc_sec_len = i8272_info->cmd[5];\r
519 i8272_info->fdc_eot = i8272_info->cmd[6];\r
520 i8272_info->fdc_gpl = i8272_info->cmd[7];\r
521 i8272_info->fdc_dtl = i8272_info->cmd[8];\r
522\r
523 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT\r
524 " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x" NLP,\r
525 PCX,\r
526 i8272_info->cmd[0] & 0x1F,\r
527 messages[i8272_info->cmd[0] & 0x1F],\r
528 i8272_info->sel_drive,\r
529 i8272_info->fdc_mt ? "Multi" : "Single",\r
530 i8272_info->fdc_mfm ? "MFM" : "FM",\r
531 pDrive->track,\r
532 i8272_info->fdc_head,\r
533 i8272_info->fdc_sector,\r
534 i8272_info->fdc_sec_len,\r
535 i8272_info->fdc_eot,\r
536 i8272_info->fdc_gpl,\r
537 i8272_info->fdc_dtl));\r
538\r
539 i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2;\r
540 i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3);\r
541 i8272_info->fdc_status[0] |= 0x40;\r
542\r
543 i8272_info->fdc_status[1] = 0;\r
544 i8272_info->fdc_status[2] = 0;\r
545\r
546 i8272_info->result[0] = i8272_info->fdc_status[0];\r
547 i8272_info->result[1] = i8272_info->fdc_status[1];\r
548 i8272_info->result[2] = i8272_info->fdc_status[2];\r
549 i8272_info->result[3] = pDrive->track;\r
550 i8272_info->result[4] = i8272_info->fdc_head;\r
551 i8272_info->result[5] = i8272_info->fdc_sector;\r
552 i8272_info->result[6] = i8272_info->fdc_sec_len;\r
553 break;\r
554 case I8272_READ_ID: /* READ ID */\r
555 i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6;\r
556 i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2;\r
557 i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03);\r
558 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
559 if(pDrive->uptr == NULL) {\r
560 return 0xFF;\r
561 }\r
562 /* Compute the i8272 "N" value from the sectorsize of this */\r
563 /* disk's current track - i.e. N = log2(sectsize) - log2(128) */\r
564 /* The calculation also works for non-standard format disk images with */\r
565 /* sectorsizes of 2048, 4096 and 8192 bytes */\r
566 i8272_info->fdc_sec_len = floorlog2(\r
567 pDrive->imd->track[pDrive->track][i8272_info->fdc_head].sectsize) - 7;\r
568 if(i8272_info->fdc_sec_len == 0xF8) { /*Error calculating N*/\r
569 return 0xFF;\r
570 }\r
571 i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2;\r
572 i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3);\r
573\r
574 i8272_info->fdc_status[1] = 0;\r
575 i8272_info->fdc_status[2] = 0;\r
576\r
577 i8272_info->result[0] = i8272_info->fdc_status[0];\r
578 i8272_info->result[1] = i8272_info->fdc_status[1];\r
579 i8272_info->result[2] = i8272_info->fdc_status[2];\r
580 i8272_info->result[3] = pDrive->track;\r
581 i8272_info->result[4] = i8272_info->fdc_head;\r
582 i8272_info->result[5] = i8272_info->fdc_sector;\r
583 i8272_info->result[6] = i8272_info->fdc_sec_len; /*was hardcoded to 0x3*/\r
584 break;\r
585 case I8272_RECALIBRATE: /* RECALIBRATE */\r
586 i8272_info->sel_drive = i8272_info->cmd[1] & 3;\r
587 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
588 if(pDrive->uptr == NULL) {\r
589 return 0xFF;\r
590 }\r
591\r
592 pDrive->track = 0;\r
593 i8272_info->fdc_phase = 0; /* No result phase */\r
594 pDrive->track = 0;\r
595 i8272_info->fdc_seek_end = 1;\r
596 TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Recalibrate: Drive 0x%02x" NLP,\r
597 PCX, i8272_info->sel_drive));\r
598 break;\r
599 case I8272_FORMAT_TRACK: /* FORMAT A TRACK */\r
600 i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6;\r
601 i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2;\r
602 i8272_info->fdc_head = i8272_info->fdc_hds; /* psco added */\r
603 i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03);\r
604 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
605 if(pDrive->uptr == NULL) {\r
606 return 0xFF;\r
607 }\r
608\r
609 if(pDrive->track != i8272_info->cmd[2]) {\r
610 i8272_info->fdc_seek_end = 1;\r
611 } else {\r
612 i8272_info->fdc_seek_end = 0;\r
613 }\r
614 i8272_info->fdc_sec_len = i8272_info->cmd[2];\r
615 i8272_info->fdc_sc = i8272_info->cmd[3];\r
616 i8272_info->fdc_gpl = i8272_info->cmd[4];\r
617 i8272_info->fdc_fillbyte = i8272_info->cmd[5];\r
618\r
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,\r
620 PCX,\r
621 i8272_info->sel_drive,\r
622 i8272_info->fdc_mfm ? "MFM" : "FM",\r
623 pDrive->track,\r
624 i8272_info->fdc_head,\r
625 i8272_info->fdc_sec_len,\r
626 i8272_info->fdc_sc,\r
627 i8272_info->fdc_gpl,\r
628 i8272_info->fdc_fillbyte));\r
629\r
630 i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2;\r
631 i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3);\r
632 /*i8272_info->fdc_status[0] |= 0x40; psco removed */\r
633\r
634 i8272_info->fdc_status[1] = 0;\r
635 i8272_info->fdc_status[2] = 0;\r
636\r
637 i8272_info->result[0] = i8272_info->fdc_status[0];\r
638 i8272_info->result[1] = i8272_info->fdc_status[1];\r
639 i8272_info->result[2] = i8272_info->fdc_status[2];\r
640 i8272_info->result[3] = pDrive->track;\r
641 i8272_info->result[4] = i8272_info->fdc_head;\r
642 i8272_info->result[5] = i8272_info->fdc_sector;\r
643 i8272_info->result[6] = i8272_info->fdc_sec_len;\r
644 break;\r
645 case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */\r
646 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Interrupt Status" NLP, PCX));\r
647 i8272_info->result[0] = i8272_info->fdc_seek_end ? 0x20 : 0x00; /* SEEK_END */\r
648 i8272_info->result[0] |= i8272_info->sel_drive;\r
649 i8272_info->result[1] = pDrive->track;\r
650 break;\r
651 case I8272_SPECIFY: /* SPECIFY */\r
652 i8272_info->fdc_srt = 16 - ((i8272_info->cmd[1] & 0xF0) >> 4);\r
653 i8272_info->fdc_hut = (i8272_info->cmd[1] & 0x0F) * 16;\r
654 i8272_info->fdc_hlt = ((i8272_info->cmd[2] & 0xFE) >> 1) * 2;\r
655 i8272_info->fdc_nd = (i8272_info->cmd[2] & 0x01);\r
656 i8272_info->fdc_phase = 0; /* No result phase */\r
657 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s" NLP,\r
658 PCX,\r
659 i8272_info->fdc_srt,\r
660 i8272_info->fdc_hut,\r
661 i8272_info->fdc_hlt,\r
662 i8272_info->fdc_nd ? "NON-DMA" : "DMA"));\r
663 break;\r
664 case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */\r
665 i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2;\r
666 i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03);\r
667 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
668 if(pDrive->uptr == NULL) {\r
669 return 0xFF;\r
670 }\r
671\r
672 i8272_info->result[0] = (pDrive->ready) ? DRIVE_STATUS_READY : 0; /* Drive Ready */\r
673 if(imdGetSides(pDrive->imd) == 2) {\r
674 i8272_info->result[0] |= DRIVE_STATUS_TWO_SIDED; /* Two-sided? */\r
675 }\r
676 if(imdIsWriteLocked(pDrive->imd)) {\r
677 i8272_info->result[0] |= DRIVE_STATUS_WP; /* Write Protected? */\r
678 }\r
679 i8272_info->result[0] |= (i8272_info->fdc_hds & 1) << 2;\r
680 i8272_info->result[0] |= (i8272_info->sel_drive & 3);\r
681 i8272_info->result[0] |= (pDrive->track == 0) ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */\r
682 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Drive Status = %02x" NLP,\r
683 PCX, i8272_info->result[0]));\r
684 break;\r
685 case I8272_SEEK: /* SEEK */\r
686 i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7;\r
687 i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6;\r
688 i8272_info->fdc_sk = (i8272_info->cmd[0] & 0x20) >> 5;\r
689 i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2;\r
690 i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03);\r
691 pDrive = &i8272_info->drive[i8272_info->sel_drive];\r
692 if(pDrive->uptr == NULL) {\r
693 return 0xFF;\r
694 }\r
695\r
696 pDrive->track = i8272_info->cmd[2];\r
697 i8272_info->fdc_seek_end = 1;\r
698 TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Seek %d" NLP,\r
699 PCX, pDrive->track));\r
700 break;\r
701 default: /* INVALID */\r
702 break;\r
703 }\r
704\r
705 if(i8272_info->fdc_phase == EXEC_PHASE) {\r
706 switch(i8272_info->cmd[0] & 0x1F) {\r
707 case I8272_READ_TRACK:\r
708 printf("I8272: " ADDRESS_FORMAT " Read a track (untested.)" NLP, PCX);\r
709 i8272_info->fdc_sector = 1; /* Read entire track from sector 1...eot */\r
710 case I8272_READ_DATA:\r
711 case I8272_READ_DELETED_DATA:\r
712 disk_read = 1;\r
713 case I8272_WRITE_DATA:\r
714 case I8272_WRITE_DELETED_DATA:\r
715 for(;i8272_info->fdc_sector<=i8272_info->fdc_eot;i8272_info->fdc_sector++) {\r
716 TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " %s Data, sector: %d sector len=%d" NLP,\r
717 PCX, disk_read ? "RD" : "WR",\r
718 i8272_info->fdc_sector,\r
719 128 << i8272_info->fdc_sec_len));\r
720 switch((pDrive->uptr)->u3)\r
721 {\r
722 case IMAGE_TYPE_IMD:\r
723 if(pDrive->imd == NULL) {\r
724 printf(".imd is NULL!" NLP);\r
725 }\r
726 if(disk_read) { /* Read sector */\r
727 sectRead(pDrive->imd,\r
728 pDrive->track,\r
729 i8272_info->fdc_head,\r
730 i8272_info->fdc_sector,\r
731 sdata.raw,\r
732 128 << i8272_info->fdc_sec_len,\r
733 &flags,\r
734 &readlen);\r
735\r
736 for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) {\r
737 PutBYTEWrapper(i8272_info->fdc_dma_addr, sdata.raw[i]);\r
738 i8272_info->fdc_dma_addr++;\r
739 }\r
740 TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred to RAM at 0x%06x" NLP,\r
741 PCX, i8272_info->fdc_dma_addr));\r
742 } else { /* Write */\r
743 for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) {\r
744 sdata.raw[i] = GetBYTEWrapper(i8272_info->fdc_dma_addr);\r
745 i8272_info->fdc_dma_addr++;\r
746 }\r
747 TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred from RAM at 0x%06x" NLP,\r
748 PCX, i8272_info->fdc_dma_addr));\r
749 sectWrite(pDrive->imd,\r
750 pDrive->track,\r
751 i8272_info->fdc_head,\r
752 i8272_info->fdc_sector,\r
753 sdata.raw,\r
754 128 << i8272_info->fdc_sec_len,\r
755 &flags,\r
756 &readlen);\r
757 }\r
758\r
759 i8272_info->result[5] = i8272_info->fdc_sector;\r
760 i8272_info->result[1] = 0x80;\r
761 break;\r
762 case IMAGE_TYPE_DSK:\r
763 printf("%s: DSK Format not supported" NLP, __FUNCTION__);\r
764 break;\r
765 case IMAGE_TYPE_CPT:\r
766 printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r
767 break;\r
768 default:\r
769 printf("%s: Unknown image Format" NLP, __FUNCTION__);\r
770 break;\r
771 }\r
772 }\r
773 break;\r
774 case I8272_FORMAT_TRACK: /* FORMAT A TRACK */\r
775 for(i8272_info->fdc_sector = 1;i8272_info->fdc_sector<=i8272_info->fdc_sc;i8272_info->fdc_sector++) {\r
776 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Format Track %d, Sector=%d, len=%d" NLP,\r
777 PCX,\r
778 pDrive->track,\r
779 i8272_info->fdc_sector,\r
780 128 << i8272_info->fdc_sec_len));\r
781 switch((pDrive->uptr)->u3)\r
782 {\r
783 case IMAGE_TYPE_IMD:\r
784 if(pDrive->imd == NULL) {\r
785 printf(".imd is NULL!" NLP);\r
786 }\r
787 TRACE_PRINT(WR_DATA_MSG, ("%s: Write: imd=%p t=%i h=%i s=%i l=%i" NLP,\r
788 __FUNCTION__, pDrive->imd, pDrive->track, i8272_info->fdc_head,\r
789 i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len));\r
790 memset(sdata.raw, i8272_info->fdc_fillbyte, 128 << i8272_info->fdc_sec_len);\r
791 sectWrite(pDrive->imd,\r
792 pDrive->track,\r
793 i8272_info->fdc_head,\r
794 i8272_info->fdc_sector,\r
795 sdata.raw,\r
796 128 << i8272_info->fdc_sec_len,\r
797 &flags,\r
798 &readlen);\r
799 i8272_info->result[1] = 0x80;\r
800 i8272_info->result[5] = i8272_info->fdc_sector;\r
801 break;\r
802 case IMAGE_TYPE_DSK:\r
803 printf("%s: DSK Format not supported" NLP, __FUNCTION__);\r
804 break;\r
805 case IMAGE_TYPE_CPT:\r
806 printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r
807 break;\r
808 default:\r
809 printf("%s: Unknown image Format" NLP, __FUNCTION__);\r
810 break;\r
811 }\r
812 }\r
813 break;\r
814\r
815 case I8272_SCAN_LOW_EQUAL: /* SCAN LOW OR EQUAL */\r
816 case I8272_SCAN_HIGH_EQUAL: /* SCAN HIGH OR EQUAL */\r
817 case I8272_SCAN_EQUAL: /* SCAN EQUAL */\r
818 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Scan Data" NLP,\r
819 PCX));\r
820 printf("I8272: " ADDRESS_FORMAT " Scan not implemented." NLP, PCX);\r
821 break;\r
822 case I8272_READ_ID: /* READ ID */\r
823 TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT\r
824 " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%02x H=%02x R=%02x N=%02x"\r
825 NLP, PCX, i8272_info->sel_drive, i8272_info->result[0],\r
826 i8272_info->result[1],i8272_info->result[2],i8272_info->result[3],\r
827 i8272_info->result[4],i8272_info->result[5],i8272_info->result[6]));\r
828 break;\r
829\r
830 default:\r
831 break;\r
832 }\r
833 }\r
834\r
835\r
836 if(i8272_info->result_len != 0) {\r
837 i8272_info->fdc_phase ++;\r
838 } else {\r
839 i8272_info->fdc_phase = 0;\r
840 }\r
841\r
842 i8272_info->result_index = 0;\r
843 }\r
844\r
845\r
846 break;\r
847 }\r
848\r
849 cData = 0x00;\r
850\r
851 return (cData);\r
852}\r
853\r
854static uint8 I8272_Setup_Cmd(uint8 fdc_cmd)\r
855{\r
856 uint8 result = 0;\r
857\r
858 switch(fdc_cmd) {\r
859 case I8272_READ_DATA:\r
860 case I8272_WRITE_DATA:\r
861 case I8272_READ_DELETED_DATA:\r
862 case I8272_WRITE_DELETED_DATA:\r
863 case I8272_READ_TRACK:\r
864 case I8272_SCAN_LOW_EQUAL:\r
865 case I8272_SCAN_HIGH_EQUAL:\r
866 case I8272_SCAN_EQUAL:\r
867 i8272_info->cmd_len = 9;\r
868 i8272_info->result_len = 7;\r
869 break;\r
870 case I8272_READ_ID: /* READ ID */\r
871 i8272_info->cmd_len = 2;\r
872 i8272_info->result_len = 7;\r
873 break;\r
874 case I8272_RECALIBRATE: /* RECALIBRATE */\r
875 i8272_info->cmd_len = 2;\r
876 i8272_info->result_len = 0;\r
877 break;\r
878 case I8272_FORMAT_TRACK: /* FORMAT A TRACK */\r
879 i8272_info->cmd_len = 6;\r
880 i8272_info->result_len = 7;\r
881 break;\r
882 case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */\r
883 i8272_info->cmd_len = 1;\r
884 i8272_info->result_len = 2;\r
885 break;\r
886 case I8272_SPECIFY: /* SPECIFY */\r
887 i8272_info->cmd_len = 3;\r
888 i8272_info->result_len = 0;\r
889 break;\r
890 case I8272_SENSE_DRIVE_STATUS: /* SENSE DRIVE STATUS */\r
891 i8272_info->cmd_len = 2;\r
892 i8272_info->result_len = 1;\r
893 break;\r
894 case I8272_SEEK: /* SEEK */\r
895 i8272_info->cmd_len = 3;\r
896 i8272_info->result_len = 0;\r
897 break;\r
898 default: /* INVALID */\r
899 i8272_info->cmd_len = 1;\r
900 i8272_info->result_len = 1;\r
901 result = -1;\r
902 break;\r
903 }\r
904 return (result);\r
905}\r
906\r