Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /*************************************************************************\r |
2 | * *\r | |
3 | * $Id: mfdc.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 | * Micropolis FD Control module for SIMH. *\r | |
36 | * See the "Vector Using MDOS Revision 8.4" manual at: *\r | |
37 | * www.hartetechnologies.com/manuals in the Vector Graphic section *\r | |
38 | * for details of the on-disk sector format and programming information. *\r | |
39 | * *\r | |
40 | * Environment: *\r | |
41 | * User mode only *\r | |
42 | * *\r | |
43 | *************************************************************************/\r | |
44 | \r | |
45 | /*#define DBG_MSG */\r | |
46 | #define USE_VGI /* Use 275-byte VGI-format sectors (includes all metadata) */\r | |
47 | \r | |
48 | #include "altairz80_defs.h"\r | |
49 | #include "sim_imd.h"\r | |
50 | \r | |
51 | #if defined (_WIN32)\r | |
52 | #include <windows.h>\r | |
53 | #endif\r | |
54 | \r | |
55 | #ifdef DBG_MSG\r | |
56 | #define DBG_PRINT(args) printf args\r | |
57 | #else\r | |
58 | #define DBG_PRINT(args)\r | |
59 | #endif\r | |
60 | \r | |
61 | #define SEEK_MSG 0x01\r | |
62 | #define ORDERS_MSG 0x02\r | |
63 | #define CMD_MSG 0x04\r | |
64 | #define RD_DATA_MSG 0x08\r | |
65 | #define WR_DATA_MSG 0x10\r | |
66 | #define STATUS_MSG 0x20\r | |
67 | \r | |
68 | extern uint32 PCX;\r | |
69 | extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
70 | extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
71 | extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,\r | |
72 | int32 (*routine)(const int32, const int32, const int32), uint8 unmap);\r | |
73 | extern int32 find_unit_index(UNIT *uptr);\r | |
74 | \r | |
75 | static void MFDC_Command(uint8 cData);\r | |
76 | \r | |
77 | #define MFDC_MAX_DRIVES 4\r | |
78 | #define JUMPER_W9 1 /* Not Installed (0) = 2MHz, Installed (1) = 4MHz. */\r | |
79 | #define JUMPER_W10 0\r | |
80 | \r | |
81 | #define MFDC_SECTOR_LEN 275\r | |
82 | \r | |
83 | typedef union {\r | |
84 | struct {\r | |
85 | uint8 sync;\r | |
86 | uint8 header[2];\r | |
87 | uint8 unused[10];\r | |
88 | uint8 data[256];\r | |
89 | uint8 checksum;\r | |
90 | uint8 ecc[4];\r | |
91 | uint8 ecc_valid; /* Not used for Micropolis FDC, but is used by FDHD. */\r | |
92 | } u;\r | |
93 | uint8 raw[MFDC_SECTOR_LEN];\r | |
94 | \r | |
95 | } SECTOR_FORMAT;\r | |
96 | \r | |
97 | typedef struct {\r | |
98 | UNIT *uptr;\r | |
99 | DISK_INFO *imd;\r | |
100 | uint8 track;\r | |
101 | uint8 wp; /* Disk write protected */\r | |
102 | uint8 ready; /* Drive is ready */\r | |
103 | uint8 sector; /* Current Sector number */\r | |
104 | uint32 sector_wait_count;\r | |
105 | } MFDC_DRIVE_INFO;\r | |
106 | \r | |
107 | typedef struct {\r | |
108 | PNP_INFO pnp; /* Plug and Play */\r | |
109 | uint8 xfr_flag; /* Indicates controller is ready to send/receive data */\r | |
110 | uint8 sel_drive; /* Currently selected drive */\r | |
111 | uint8 selected; /* 1 if drive is selected */\r | |
112 | uint8 track0; /* Set it selected drive is on track 0 */\r | |
113 | uint8 head; /* Currently selected head */\r | |
114 | uint8 wr_latch; /* Write enable latch */\r | |
115 | uint8 int_enable; /* Interrupt Enable */\r | |
116 | uint32 datacount; /* Number of data bytes transferred from controller for current sector */\r | |
117 | uint8 read_in_progress; /* TRUE if a read is in progress */\r | |
118 | MFDC_DRIVE_INFO drive[MFDC_MAX_DRIVES];\r | |
119 | } MFDC_INFO;\r | |
120 | \r | |
121 | static MFDC_INFO mfdc_info_data = { { 0xF800, 1024, 0, 0 } };\r | |
122 | static MFDC_INFO *mfdc_info = &mfdc_info_data;\r | |
123 | \r | |
124 | static SECTOR_FORMAT sdata;\r | |
125 | \r | |
126 | #define UNIT_V_MFDC_WLK (UNIT_V_UF + 0) /* write locked */\r | |
127 | #define UNIT_MFDC_WLK (1 << UNIT_V_MFDC_WLK)\r | |
128 | #define UNIT_V_MFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */\r | |
129 | #define UNIT_MFDC_VERBOSE (1 << UNIT_V_MFDC_VERBOSE)\r | |
130 | #define MFDC_CAPACITY (77*16*MFDC_SECTOR_LEN) /* Default Micropolis Disk Capacity */\r | |
131 | #define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */\r | |
132 | #define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */\r | |
133 | #define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */\r | |
134 | \r | |
135 | static t_stat mfdc_reset(DEVICE *mfdc_dev);\r | |
136 | static t_stat mfdc_attach(UNIT *uptr, char *cptr);\r | |
137 | static t_stat mfdc_detach(UNIT *uptr);\r | |
138 | static uint8 MFDC_Read(const uint32 Addr);\r | |
139 | static uint8 MFDC_Write(const uint32 Addr, uint8 cData);\r | |
140 | \r | |
141 | static int32 mdskdev(const int32 Addr, const int32 rw, const int32 data);\r | |
142 | \r | |
143 | static int32 trace_level = 0;\r | |
144 | \r | |
145 | static UNIT mfdc_unit[] = {\r | |
146 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) },\r | |
147 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) },\r | |
148 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) },\r | |
149 | { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) }\r | |
150 | };\r | |
151 | \r | |
152 | static REG mfdc_reg[] = {\r | |
153 | { HRDATA (TRACELEVEL, trace_level, 16), },\r | |
154 | { NULL }\r | |
155 | };\r | |
156 | \r | |
157 | static MTAB mfdc_mod[] = {\r | |
158 | { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },\r | |
159 | { UNIT_MFDC_WLK, 0, "WRTENB", "WRTENB", NULL },\r | |
160 | { UNIT_MFDC_WLK, UNIT_MFDC_WLK, "WRTLCK", "WRTLCK", NULL },\r | |
161 | /* quiet, no warning messages */\r | |
162 | { UNIT_MFDC_VERBOSE, 0, "QUIET", "QUIET", NULL },\r | |
163 | /* verbose, show warning messages */\r | |
164 | { UNIT_MFDC_VERBOSE, UNIT_MFDC_VERBOSE, "VERBOSE", "VERBOSE", NULL },\r | |
165 | { 0 }\r | |
166 | };\r | |
167 | \r | |
168 | DEVICE mfdc_dev = {\r | |
169 | "MDSK", mfdc_unit, mfdc_reg, mfdc_mod,\r | |
170 | MFDC_MAX_DRIVES, 10, 31, 1, MFDC_MAX_DRIVES, MFDC_MAX_DRIVES,\r | |
171 | NULL, NULL, &mfdc_reset,\r | |
172 | NULL, &mfdc_attach, &mfdc_detach,\r | |
173 | &mfdc_info_data, (DEV_DISABLE | DEV_DIS), 0,\r | |
174 | NULL, NULL, NULL\r | |
175 | };\r | |
176 | \r | |
177 | /* Micropolis FD Control Boot ROM\r | |
178 | * This ROM code is runtime-relocatable. See Appendix F of the "Vector Using MDOS Revision 8.4"\r | |
179 | * manual at www.hartetechnologies.com/manuals in the Vector Graphic section.\r | |
180 | */\r | |
181 | static uint8 mfdc_rom[256] = {\r | |
182 | 0xF3, 0x21, 0xA2, 0x00, 0xF9, 0x36, 0xC9, 0xCD, 0xA2, 0x00, 0xEB, 0x2A, 0xA0, 0x00, 0x2E, 0x00, /* 0x00 */\r | |
183 | 0xE5, 0x01, 0x1D, 0x00, 0x09, 0xE5, 0xE1, 0x0E, 0x1A, 0x09, 0x06, 0xBD, 0xEB, 0x3B, 0x3B, 0x1A, /* 0x10 */\r | |
184 | 0x77, 0xBE, 0xC0, 0x23, 0x13, 0x05, 0xC0, 0xE1, 0x2A, 0xA0, 0x00, 0x11, 0x00, 0x02, 0x19, 0x22, /* 0x20 */\r | |
185 | 0xA2, 0x00, 0x36, 0xA0, 0xC3, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xA2, 0x00, 0x7E, 0xE6, /* 0x30 */\r | |
186 | 0x80, 0xCA, 0xA9, 0x00, 0x7E, 0xE6, 0x0F, 0xA8, 0xC2, 0xA9, 0x00, 0x23, 0xB6, 0xF2, 0xB7, 0x00, /* 0x40 */\r | |
187 | 0x23, 0x7E, 0xAF, 0xEB, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x77, 0x23, 0x88, 0x47, 0x1A, 0x77, 0x23, /* 0x50 */\r | |
188 | 0x88, 0x47, 0x0D, 0xC2, 0xC3, 0x00, 0x1A, 0xB8, 0xC9, 0x2A, 0xA2, 0x00, 0x36, 0x20, 0x23, 0x7E, /* 0x60 */\r | |
189 | 0x2B, 0xE6, 0x24, 0xEE, 0x20, 0xC2, 0xD4, 0x00, 0x0E, 0x5E, 0xCD, 0x49, 0x01, 0x23, 0x7E, 0x2B, /* 0x70 */\r | |
190 | 0xE6, 0x24, 0xEE, 0x20, 0xC2, 0xD4, 0x00, 0x23, 0x7E, 0xE6, 0x08, 0x2B, 0xCA, 0x07, 0x01, 0x06, /* 0x80 */\r | |
191 | 0x08, 0x36, 0x61, 0x0E, 0x0F, 0xCD, 0x49, 0x01, 0x05, 0xC2, 0xFC, 0x00, 0x23, 0x7E, 0xE6, 0x08, /* 0x90 */\r | |
192 | 0x2B, 0xC2, 0x19, 0x01, 0x36, 0x60, 0x0E, 0x0F, 0xCD, 0x49, 0x01, 0xC3, 0x07, 0x01, 0x21, 0x5F, /* 0xA0 */\r | |
193 | 0x01, 0xCD, 0x37, 0x01, 0xC2, 0xD4, 0x00, 0x2A, 0x69, 0x02, 0x22, 0xA4, 0x00, 0xCD, 0x37, 0x01, /* 0xB0 */\r | |
194 | 0xC2, 0xD4, 0x00, 0x2A, 0xA4, 0x00, 0x11, 0x0C, 0x00, 0x19, 0xD1, 0xE9, 0xE5, 0xEB, 0x01, 0x86, /* 0xC0 */\r | |
195 | 0x00, 0xCD, 0xA6, 0x00, 0xE1, 0xC2, 0x37, 0x01, 0xE5, 0x7E, 0x23, 0xB6, 0xE1, 0xC9, 0x7E, 0xE6, /* 0xD0 */\r | |
196 | 0x20, 0x79, 0xC2, 0x51, 0x01, 0x07, 0x4F, 0x3E, 0xFF, 0xD6, 0x01, 0xB7, 0xC2, 0x54, 0x01, 0x0D, /* 0xE0 */\r | |
197 | 0xC2, 0x52, 0x01, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xA6, 0x00 /* 0xF0 */\r | |
198 | };\r | |
199 | \r | |
200 | /* Reset routine */\r | |
201 | t_stat mfdc_reset(DEVICE *dptr)\r | |
202 | {\r | |
203 | uint8 i;\r | |
204 | PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;\r | |
205 | \r | |
206 | if(dptr->flags & DEV_DIS) {\r | |
207 | sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &mdskdev, TRUE);\r | |
208 | } else {\r | |
209 | /* Connect MFDC at base address */\r | |
210 | for(i = 0; i < MFDC_MAX_DRIVES; i++) {\r | |
211 | mfdc_info->drive[i].uptr = &mfdc_dev.units[i];\r | |
212 | }\r | |
213 | if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &mdskdev, FALSE) != 0) {\r | |
214 | printf("%s: error mapping resource at 0x%04x\n", __FUNCTION__, pnp->mem_base);\r | |
215 | dptr->flags |= DEV_DIS;\r | |
216 | return SCPE_ARG;\r | |
217 | }\r | |
218 | }\r | |
219 | return SCPE_OK;\r | |
220 | }\r | |
221 | \r | |
222 | /* Attach routine */\r | |
223 | t_stat mfdc_attach(UNIT *uptr, char *cptr)\r | |
224 | {\r | |
225 | char header[4];\r | |
226 | t_stat r;\r | |
227 | unsigned int i = 0;\r | |
228 | \r | |
229 | r = attach_unit(uptr, cptr); /* attach unit */\r | |
230 | if ( r != SCPE_OK) /* error? */\r | |
231 | return r;\r | |
232 | \r | |
233 | /* Determine length of this disk */\r | |
234 | if(sim_fsize(uptr->fileref) != 0) {\r | |
235 | uptr->capac = sim_fsize(uptr->fileref);\r | |
236 | } else {\r | |
237 | uptr->capac = MFDC_CAPACITY;\r | |
238 | }\r | |
239 | \r | |
240 | i = find_unit_index(uptr);\r | |
241 | \r | |
242 | /* Default for new file is DSK */\r | |
243 | uptr->u3 = IMAGE_TYPE_DSK;\r | |
244 | \r | |
245 | if(uptr->capac > 0) {\r | |
246 | fgets(header, 4, uptr->fileref);\r | |
247 | if(!strcmp(header, "IMD")) {\r | |
248 | uptr->u3 = IMAGE_TYPE_IMD;\r | |
249 | } else if(!strcmp(header, "CPT")) {\r | |
250 | printf("CPT images not yet supported\n");\r | |
251 | uptr->u3 = IMAGE_TYPE_CPT;\r | |
252 | mfdc_detach(uptr);\r | |
253 | return SCPE_OPENERR;\r | |
254 | } else {\r | |
255 | uptr->u3 = IMAGE_TYPE_DSK;\r | |
256 | }\r | |
257 | }\r | |
258 | \r | |
259 | if (uptr->flags & UNIT_MFDC_VERBOSE)\r | |
260 | printf("MDSK%d, attached to '%s', type=%s, len=%d\n", i, cptr,\r | |
261 | uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",\r | |
262 | uptr->capac);\r | |
263 | \r | |
264 | if(uptr->u3 == IMAGE_TYPE_IMD) {\r | |
265 | if(uptr->capac < 318000) {\r | |
266 | printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n");\r | |
267 | mfdc_detach(uptr);\r | |
268 | return SCPE_OPENERR;\r | |
269 | }\r | |
270 | \r | |
271 | if (uptr->flags & UNIT_MFDC_VERBOSE)\r | |
272 | printf("--------------------------------------------------------\n");\r | |
273 | mfdc_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_MFDC_VERBOSE));\r | |
274 | if (uptr->flags & UNIT_MFDC_VERBOSE)\r | |
275 | printf("\n");\r | |
276 | } else {\r | |
277 | mfdc_info->drive[i].imd = NULL;\r | |
278 | }\r | |
279 | \r | |
280 | return SCPE_OK;\r | |
281 | }\r | |
282 | \r | |
283 | \r | |
284 | /* Detach routine */\r | |
285 | t_stat mfdc_detach(UNIT *uptr)\r | |
286 | {\r | |
287 | t_stat r;\r | |
288 | int8 i;\r | |
289 | \r | |
290 | for(i = 0; i < MFDC_MAX_DRIVES; i++) {\r | |
291 | if(mfdc_dev.units[i].fileref == uptr->fileref) {\r | |
292 | break;\r | |
293 | }\r | |
294 | }\r | |
295 | \r | |
296 | if (i >= MFDC_MAX_DRIVES) return SCPE_ARG;\r | |
297 | \r | |
298 | DBG_PRINT(("Detach MFDC%d\n", i));\r | |
299 | diskClose(mfdc_info->drive[i].imd);\r | |
300 | \r | |
301 | r = detach_unit(uptr); /* detach unit */\r | |
302 | if ( r != SCPE_OK)\r | |
303 | return r;\r | |
304 | \r | |
305 | return SCPE_OK;\r | |
306 | }\r | |
307 | \r | |
308 | \r | |
309 | \r | |
310 | static uint8 cy;\r | |
311 | static uint8 adc(uint8 sum, uint8 a1)\r | |
312 | {\r | |
313 | uint32 total;\r | |
314 | \r | |
315 | total = sum + a1 + cy;\r | |
316 | \r | |
317 | if(total > 0xFF) {\r | |
318 | cy = 1;\r | |
319 | } else {\r | |
320 | cy = 0;\r | |
321 | }\r | |
322 | \r | |
323 | return(total & 0xFF);\r | |
324 | }\r | |
325 | \r | |
326 | /* Main Entry Point for Memory-Mapped I/O to the Micropolis FD Control Board\r | |
327 | *\r | |
328 | * The controller is typically located at 0xF800 in the Memory Map, and occupies\r | |
329 | * 1K of address space. Accesses are broken down as follows:\r | |
330 | *\r | |
331 | * 0xF800-0xF8FF: Bootstrap ROM\r | |
332 | * 0xF900-0xF9FF: Nothing (reads 0xFF)\r | |
333 | * 0xFA00-0xFBFF: Controller registers: there are four registers, which are shadowed\r | |
334 | * throughout this 512-byte range.\r | |
335 | *\r | |
336 | * The controller can be relocated on any 1K boundary in the memory map, and since the\r | |
337 | * boot ROM code is runtime relocatable, it moves with the controller registers.\r | |
338 | */\r | |
339 | static int32 mdskdev(const int32 Addr, const int32 rw, const int32 data)\r | |
340 | {\r | |
341 | switch(Addr & 0x300) {\r | |
342 | case 0x000: /* Boot ROM */\r | |
343 | if(rw == 0) { /* Read boot ROM */\r | |
344 | return(mfdc_rom[Addr & 0xFF]);\r | |
345 | } else {\r | |
346 | printf("MFDC: Attempt to write to boot ROM." NLP);\r | |
347 | return (-1);\r | |
348 | }\r | |
349 | break;\r | |
350 | case 0x100: /* Nothing */\r | |
351 | return(0xFF);\r | |
352 | break;\r | |
353 | case 0x200:\r | |
354 | case 0x300: /* Controller Registers */\r | |
355 | if(rw == 0) { /* Read Register */\r | |
356 | return(MFDC_Read(Addr));\r | |
357 | } else { /* Write Register */\r | |
358 | return(MFDC_Write(Addr, data));\r | |
359 | }\r | |
360 | break;\r | |
361 | }\r | |
362 | \r | |
363 | return(-1);\r | |
364 | }\r | |
365 | \r | |
366 | \r | |
367 | static uint8 MFDC_Read(const uint32 Addr)\r | |
368 | {\r | |
369 | uint8 cData;\r | |
370 | MFDC_DRIVE_INFO *pDrive;\r | |
371 | \r | |
372 | cData = 0x00;\r | |
373 | \r | |
374 | pDrive = &mfdc_info->drive[mfdc_info->sel_drive];\r | |
375 | \r | |
376 | switch(Addr & 0x3) {\r | |
377 | case 0:\r | |
378 | if(mfdc_info->read_in_progress == FALSE) {\r | |
379 | pDrive->sector_wait_count++;\r | |
380 | if(pDrive->sector_wait_count > 10) {\r | |
381 | pDrive->sector++;\r | |
382 | pDrive->sector &= 0x0F; /* Max of 16 sectors */\r | |
383 | mfdc_info->wr_latch = 0; /* on new sector, disable the write latch */\r | |
384 | DBG_PRINT(("Head over sector %d" NLP, pDrive->sector));\r | |
385 | pDrive->sector_wait_count = 0;\r | |
386 | }\r | |
387 | }\r | |
388 | \r | |
389 | cData = (pDrive->sector) & 0xF; /* [3:0] current sector */\r | |
390 | cData |= (JUMPER_W10 << 4);\r | |
391 | cData |= ((~JUMPER_W9) & 1) << 5;\r | |
392 | cData |= (0 << 6); /* Sector Interrupt Flag, reset by RESET command or Interrupt Disable */\r | |
393 | cData |= (1 << 7); /* Sector Flag */\r | |
394 | mfdc_info->xfr_flag = 1; /* Drive has data */\r | |
395 | mfdc_info->datacount = 0;\r | |
396 | TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x" NLP, PCX, cData));\r | |
397 | break;\r | |
398 | case 1:\r | |
399 | cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */\r | |
400 | cData |= (!mfdc_info->selected << 2); /* [2] drive is selected */\r | |
401 | cData |= (pDrive->track == 0) ? 0x08 : 0; /* [3] TK0 */\r | |
402 | pDrive->wp = ((pDrive->uptr)->flags & UNIT_MFDC_WLK) ? 1 : 0;\r | |
403 | cData |= (pDrive->wp << 4); /* [4] Write Protect */\r | |
404 | cData |= (pDrive->ready << 5); /* [5] Drive Ready */\r | |
405 | cData |= (0 << 6); /* [6] PINTE from S-100 Bus */\r | |
406 | cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */\r | |
407 | \r | |
408 | TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x" NLP, PCX, cData));\r | |
409 | break;\r | |
410 | case 2:\r | |
411 | case 3:\r | |
412 | if(mfdc_info->datacount == 0) {\r | |
413 | unsigned int i, checksum;\r | |
414 | unsigned long sec_offset;\r | |
415 | unsigned int flags;\r | |
416 | unsigned int readlen;\r | |
417 | \r | |
418 | /* Clear out unused portion of sector. */\r | |
419 | memset(&sdata.u.unused[0], 0x00, 10);\r | |
420 | \r | |
421 | sdata.u.sync = 0xFF;\r | |
422 | sdata.u.header[0] = pDrive->track;\r | |
423 | sdata.u.header[1] = pDrive->sector;\r | |
424 | \r | |
425 | TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]" NLP,\r | |
426 | PCX,\r | |
427 | pDrive->track,\r | |
428 | pDrive->sector));\r | |
429 | \r | |
430 | #ifdef USE_VGI\r | |
431 | sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \\r | |
432 | (pDrive->sector * MFDC_SECTOR_LEN);\r | |
433 | #else\r | |
434 | sec_offset = (pDrive->track * 4096) + \\r | |
435 | (pDrive->sector * 256);\r | |
436 | #endif /* USE_VGI */\r | |
437 | \r | |
438 | if (!(pDrive->uptr->flags & UNIT_ATT)) {\r | |
439 | if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE)\r | |
440 | printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX,\r | |
441 | mfdc_info->sel_drive);\r | |
442 | return 0x00;\r | |
443 | }\r | |
444 | \r | |
445 | switch((pDrive->uptr)->u3)\r | |
446 | {\r | |
447 | case IMAGE_TYPE_IMD:\r | |
448 | if(pDrive->imd == NULL) {\r | |
449 | printf(".imd is NULL!" NLP);\r | |
450 | }\r | |
451 | /* printf("%s: Read: imd=%p" NLP, __FUNCTION__, pDrive->imd); */\r | |
452 | sectRead(pDrive->imd,\r | |
453 | pDrive->track,\r | |
454 | mfdc_info->head,\r | |
455 | pDrive->sector,\r | |
456 | sdata.u.data,\r | |
457 | 256,\r | |
458 | &flags,\r | |
459 | &readlen);\r | |
460 | break;\r | |
461 | case IMAGE_TYPE_DSK:\r | |
462 | if(pDrive->uptr->fileref == NULL) {\r | |
463 | printf(".fileref is NULL!" NLP);\r | |
464 | } else {\r | |
465 | fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);\r | |
466 | #ifdef USE_VGI\r | |
467 | fread(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref);\r | |
468 | #else\r | |
469 | fread(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);\r | |
470 | #endif /* USE_VGI */\r | |
471 | }\r | |
472 | break;\r | |
473 | case IMAGE_TYPE_CPT:\r | |
474 | printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r | |
475 | break;\r | |
476 | default:\r | |
477 | printf("%s: Unknown image Format" NLP, __FUNCTION__);\r | |
478 | break;\r | |
479 | }\r | |
480 | \r | |
481 | /* printf("%d/%d @%04x Len=%04x" NLP, sdata.u.header[0], sdata.u.header[1], sdata.u.header[9]<<8|sdata.u.header[8], sdata.u.header[11]<<8|sdata.u.header[10]); */\r | |
482 | \r | |
483 | adc(0,0); /* clear Carry bit */\r | |
484 | checksum = 0;\r | |
485 | \r | |
486 | /* Checksum everything except the sync byte */\r | |
487 | for(i=1;i<269;i++) {\r | |
488 | checksum = adc(checksum, sdata.raw[i]);\r | |
489 | }\r | |
490 | \r | |
491 | sdata.u.checksum = checksum & 0xFF;\r | |
492 | /* DBG_PRINT(("Checksum=%x" NLP, sdata.u.checksum)); */\r | |
493 | mfdc_info->read_in_progress = TRUE;\r | |
494 | }\r | |
495 | \r | |
496 | cData = sdata.raw[mfdc_info->datacount];\r | |
497 | \r | |
498 | mfdc_info->datacount++;\r | |
499 | if(mfdc_info->datacount == 270) {\r | |
500 | TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " Read sector [%d] complete" NLP,\r | |
501 | PCX, pDrive->sector));\r | |
502 | mfdc_info->read_in_progress = FALSE;\r | |
503 | }\r | |
504 | \r | |
505 | /* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, mfdc_info->datacount, cData)); */\r | |
506 | break;\r | |
507 | }\r | |
508 | \r | |
509 | return (cData);\r | |
510 | }\r | |
511 | \r | |
512 | static uint8 MFDC_Write(const uint32 Addr, uint8 cData)\r | |
513 | {\r | |
514 | unsigned int sec_offset;\r | |
515 | unsigned int flags = 0;\r | |
516 | unsigned int writelen;\r | |
517 | MFDC_DRIVE_INFO *pDrive;\r | |
518 | \r | |
519 | pDrive = &mfdc_info->drive[mfdc_info->sel_drive];\r | |
520 | \r | |
521 | switch(Addr & 0x3) {\r | |
522 | case 0:\r | |
523 | case 1:\r | |
524 | MFDC_Command(cData);\r | |
525 | break;\r | |
526 | case 2:\r | |
527 | case 3:\r | |
528 | /* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " WR Data" NLP, PCX)); */\r | |
529 | if(mfdc_info->wr_latch == 0) {\r | |
530 | printf("MFDC: " ADDRESS_FORMAT " Error, attempt to write data when write latch is not set." NLP, PCX);\r | |
531 | } else {\r | |
532 | #ifdef USE_VGI\r | |
533 | sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \\r | |
534 | (pDrive->sector * MFDC_SECTOR_LEN);\r | |
535 | \r | |
536 | sdata.raw[mfdc_info->datacount] = cData;\r | |
537 | #else\r | |
538 | int data_index = mfdc_info->datacount - 13;\r | |
539 | \r | |
540 | sec_offset = (pDrive->track * 4096) + \\r | |
541 | (pDrive->sector * 256);\r | |
542 | \r | |
543 | if((data_index >= 0) && (data_index < 256)) {\r | |
544 | DBG_PRINT(("writing data [%03d]=%02x" NLP, data_index, cData));\r | |
545 | \r | |
546 | sdata.u.data[data_index] = cData;\r | |
547 | \r | |
548 | }\r | |
549 | \r | |
550 | #endif /* USE_VGI */\r | |
551 | \r | |
552 | mfdc_info->datacount ++;\r | |
553 | \r | |
554 | if(mfdc_info->datacount == 270) {\r | |
555 | TRACE_PRINT(WR_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]" NLP,\r | |
556 | PCX,\r | |
557 | pDrive->track,\r | |
558 | pDrive->sector));\r | |
559 | \r | |
560 | if (!(pDrive->uptr->flags & UNIT_ATT)) {\r | |
561 | if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE)\r | |
562 | printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX,\r | |
563 | mfdc_info->sel_drive);\r | |
564 | return 0x00;\r | |
565 | }\r | |
566 | \r | |
567 | switch((pDrive->uptr)->u3)\r | |
568 | {\r | |
569 | case IMAGE_TYPE_IMD:\r | |
570 | if(pDrive->imd == NULL) {\r | |
571 | printf(".imd is NULL!" NLP);\r | |
572 | }\r | |
573 | sectWrite(pDrive->imd,\r | |
574 | pDrive->track,\r | |
575 | mfdc_info->head,\r | |
576 | pDrive->sector,\r | |
577 | sdata.u.data,\r | |
578 | 256,\r | |
579 | &flags,\r | |
580 | &writelen);\r | |
581 | break;\r | |
582 | case IMAGE_TYPE_DSK:\r | |
583 | if(pDrive->uptr->fileref == NULL) {\r | |
584 | printf(".fileref is NULL!" NLP);\r | |
585 | } else {\r | |
586 | fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);\r | |
587 | #ifdef USE_VGI\r | |
588 | fwrite(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref);\r | |
589 | #else\r | |
590 | fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);\r | |
591 | #endif /* USE_VGI */\r | |
592 | }\r | |
593 | break;\r | |
594 | case IMAGE_TYPE_CPT:\r | |
595 | printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r | |
596 | break;\r | |
597 | default:\r | |
598 | printf("%s: Unknown image Format" NLP, __FUNCTION__);\r | |
599 | break;\r | |
600 | }\r | |
601 | }\r | |
602 | }\r | |
603 | break;\r | |
604 | }\r | |
605 | \r | |
606 | cData = 0x00;\r | |
607 | \r | |
608 | return (cData);\r | |
609 | }\r | |
610 | \r | |
611 | #define MFDC_CMD_NOP 0\r | |
612 | #define MFDC_CMD_SELECT 1\r | |
613 | #define MFDC_CMD_INTR 2\r | |
614 | #define MFDC_CMD_STEP 3\r | |
615 | #define MFDC_CMD_SET_WRITE 4\r | |
616 | #define MFDC_CMD_RESET 5\r | |
617 | \r | |
618 | static void MFDC_Command(uint8 cData)\r | |
619 | {\r | |
620 | uint8 cCommand;\r | |
621 | uint8 cModifier;\r | |
622 | MFDC_DRIVE_INFO *pDrive;\r | |
623 | \r | |
624 | pDrive = &mfdc_info->drive[mfdc_info->sel_drive];\r | |
625 | \r | |
626 | \r | |
627 | cCommand = cData >> 5;\r | |
628 | cModifier = cData & 0x1F;\r | |
629 | \r | |
630 | switch(cCommand) {\r | |
631 | case MFDC_CMD_NOP:\r | |
632 | TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " No Op." NLP, PCX));\r | |
633 | break;\r | |
634 | case MFDC_CMD_SELECT:\r | |
635 | mfdc_info->sel_drive = cModifier & 3;\r | |
636 | mfdc_info->head = (cModifier & 0x10) >> 4;\r | |
637 | mfdc_info->selected = TRUE;\r | |
638 | \r | |
639 | if(pDrive->uptr->fileref != NULL) {\r | |
640 | pDrive->ready = 1;\r | |
641 | } else {\r | |
642 | pDrive->ready = 0;\r | |
643 | }\r | |
644 | \r | |
645 | TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s" NLP,\r | |
646 | PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower"));\r | |
647 | break;\r | |
648 | case MFDC_CMD_INTR:\r | |
649 | mfdc_info->int_enable = cModifier & 1; /* 0=int disable, 1=enable */\r | |
650 | TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Interrupts %s." NLP,\r | |
651 | PCX, mfdc_info->int_enable ? "Enabled" : "Disabled"));\r | |
652 | break;\r | |
653 | case MFDC_CMD_STEP:\r | |
654 | if(cModifier & 1) { /* Step IN */\r | |
655 | pDrive->track++;\r | |
656 | }\r | |
657 | else { /* Step OUT */\r | |
658 | if(pDrive->track != 0) {\r | |
659 | pDrive->track--;\r | |
660 | }\r | |
661 | }\r | |
662 | \r | |
663 | TRACE_PRINT(SEEK_MSG, ("MFDC: " ADDRESS_FORMAT " Step %s, Track=%d." NLP,\r | |
664 | PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track));\r | |
665 | \r | |
666 | break;\r | |
667 | case MFDC_CMD_SET_WRITE:\r | |
668 | TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Set WRITE." NLP, PCX));\r | |
669 | mfdc_info->wr_latch = 1; /* Allow writes for the current sector */\r | |
670 | mfdc_info->datacount = 0; /* reset the byte counter */\r | |
671 | break;\r | |
672 | case MFDC_CMD_RESET:\r | |
673 | TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Reset Controller." NLP, PCX));\r | |
674 | mfdc_info->selected = 0; /* de-select the drive */\r | |
675 | mfdc_info->wr_latch = 0; /* Disable the write latch */\r | |
676 | mfdc_info->datacount = 0; /* reset the byte counter */\r | |
677 | break;\r | |
678 | default:\r | |
679 | TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Unsupported command." NLP, PCX));\r | |
680 | break;\r | |
681 | }\r | |
682 | }\r |