First Commit of my working state
[simh.git] / AltairZ80 / s100_mdsad.c
CommitLineData
196ba1fc
PH
1/*************************************************************************\r
2 * *\r
3 * $Id: s100_mdsad.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 * Northstar MDS-AD Disk Controller module for SIMH *\r
36 * Only Double-Density is supported for now. *\r
37 * *\r
38 * Environment: *\r
39 * User mode only *\r
40 * *\r
41 *************************************************************************/\r
42\r
43/*#define DBG_MSG*/\r
44#include "altairz80_defs.h"\r
45\r
46#if defined (_WIN32)\r
47#include <windows.h>\r
48#endif\r
49\r
50#include "sim_imd.h"\r
51\r
52#ifdef DBG_MSG\r
53#define DBG_PRINT(args) printf args\r
54#else\r
55#define DBG_PRINT(args)\r
56#endif\r
57\r
58#define SEEK_MSG 0x01\r
59#define ORDERS_MSG 0x02\r
60#define CMD_MSG 0x04\r
61#define RD_DATA_MSG 0x08\r
62#define WR_DATA_MSG 0x10\r
63#define STATUS_MSG 0x20\r
64#define RD_DATA_DETAIL_MSG 0x40\r
65#define WR_DATA_DETAIL_MSG 0x80\r
66\r
67extern uint32 PCX;\r
68extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);\r
69extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc);\r
70extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,\r
71 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);\r
72extern REG *sim_PC;\r
73\r
74#define MDSAD_MAX_DRIVES 4\r
75#define MDSAD_SECTOR_LEN 512\r
76#define MDSAD_SECTORS_PER_TRACK 10\r
77#define MDSAD_TRACKS 35\r
78#define MDSAD_RAW_LEN (32 + 2 + MDSAD_SECTOR_LEN + 1)\r
79\r
80typedef union {\r
81 struct {\r
82 uint8 zeros[32];\r
83 uint8 sync[2];\r
84 uint8 data[MDSAD_SECTOR_LEN];\r
85 uint8 checksum;\r
86 } u;\r
87 uint8 raw[MDSAD_RAW_LEN];\r
88\r
89} SECTOR_FORMAT;\r
90\r
91typedef struct {\r
92 UNIT *uptr;\r
93 DISK_INFO *imd;\r
94 uint8 track;\r
95 uint8 wp; /* Disk write protected */\r
96 uint8 sector; /* Current Sector number */\r
97 uint32 sector_wait_count;\r
98} MDSAD_DRIVE_INFO;\r
99\r
100typedef struct {\r
101 uint8 dd; /* Controls density on write DD=1 for double density and DD=0 for single density. */\r
102 uint8 ss; /* Specifies the side of a double-sided diskette. The bottom side (and only side of a single-sided diskette) is selected when SS=0. The second (top) side is selected when SS=1. */\r
103 uint8 dp; /* has shared use. During stepping operations, DP=O specifies a step out and DP=1 specifies a step in. During write operations, write procompensation is invoked if and only if DP=1. */\r
104 uint8 st; /* controls the level of the head step signal to the disk drives. */\r
105 uint8 ds; /* is the drive select field, encoded as follows: */\r
106 /* 0=no drive selected\r
107 * 1=drive 1 selected\r
108 * 2=drive 2 selected\r
109 * 4=drive 3 selected\r
110 * 8=drive 4 selected\r
111 */\r
112} ORDERS;\r
113\r
114typedef struct {\r
115 uint8 sf; /* Sector Flag: set when sector hole detected, reset by software. */\r
116 uint8 ix; /* Index Detect: true if index hole detected during previous sector. */\r
117 uint8 dd; /* Double Density Indicator: true if data being read is encoded in double density. */\r
118 uint8 mo; /* Motor On: true while motor(s) are on. */\r
119} COM_STATUS;\r
120\r
121typedef struct {\r
122 uint8 wi; /* Window: true during 96-microsecond window at beginning of sector. */\r
123 uint8 re; /* Read Enable: true while phase-locked loop is enabled. */\r
124 uint8 sp; /* Spare: reserved for future use. */\r
125 uint8 bd; /* Body: set when sync character is detected. */\r
126} A_STATUS;\r
127\r
128typedef struct {\r
129 uint8 wr; /* Write: true during valid write operation. */\r
130 uint8 sp; /* Spare: reserved for future use. */\r
131 uint8 wp; /* Write Protect: true while the diskette installed in the selected drive is write protected. */\r
132 uint8 t0; /* Track 0: true if selected drive is at track zero. */\r
133} B_STATUS;\r
134\r
135typedef struct {\r
136 uint8 sc; /* Sector Counter: indicates the current sector position. */\r
137} C_STATUS;\r
138\r
139typedef struct {\r
140 PNP_INFO pnp; /* Plug and Play */\r
141\r
142 ORDERS orders;\r
143 COM_STATUS com_status;\r
144 A_STATUS a_status;\r
145 B_STATUS b_status;\r
146 C_STATUS c_status;\r
147\r
148 uint8 int_enable; /* Interrupt Enable */\r
149 uint32 datacount; /* Number of data bytes transferred from controller for current sector */\r
150 MDSAD_DRIVE_INFO drive[MDSAD_MAX_DRIVES];\r
151} MDSAD_INFO;\r
152\r
153static MDSAD_INFO mdsad_info_data = { { 0xE800, 1024, 0, 0 } };\r
154static MDSAD_INFO *mdsad_info = &mdsad_info_data;\r
155\r
156static SECTOR_FORMAT sdata;\r
157\r
158#define UNIT_V_MDSAD_WLK (UNIT_V_UF + 0) /* write locked */\r
159#define UNIT_MDSAD_WLK (1 << UNIT_V_MDSAD_WLK)\r
160#define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */\r
161#define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE)\r
162#define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */\r
163#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */\r
164#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */\r
165#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */\r
166\r
167/* MDS-AD Controller Subcases */\r
168#define MDSAD_READ_ROM 0\r
169#define MDSAD_WRITE_DATA 1\r
170#define MDSAD_CTLR_ORDERS 2\r
171#define MDSAD_CTLR_COMMAND 3\r
172\r
173/* MDS-AD Controller Commands */\r
174#define MDSAD_CMD_NOP 0\r
175#define MDSAD_CMD_RESET_SF 1\r
176#define MDSAD_CMD_INTR_DIS 2\r
177#define MDSAD_CMD_INTR_ARM 3\r
178#define MDSAD_CMD_SET_BODY 4\r
179#define MDSAD_CMD_MOTORS_ON 5\r
180#define MDSAD_CMD_BEGIN_WR 6\r
181#define MDSAD_CMD_RESET 7\r
182\r
183/* MDS-AD Data returned on DI bus */\r
184#define MDSAD_A_STATUS 1\r
185#define MDSAD_B_STATUS 2\r
186#define MDSAD_C_STATUS 3\r
187#define MDSAD_READ_DATA 4\r
188\r
189/* MDS-AD status byte masks */\r
190/* A-Status */\r
191#define MDSAD_A_SF 0x80\r
192#define MDSAD_A_IX 0x40\r
193#define MDSAD_A_DD 0x20\r
194#define MDSAD_A_MO 0x10\r
195#define MDSAD_A_WI 0x08\r
196#define MDSAD_A_RE 0x04\r
197#define MDSAD_A_SP 0x02\r
198#define MDSAD_A_BD 0x01\r
199\r
200/* B-Status */\r
201#define MDSAD_B_SF 0x80\r
202#define MDSAD_B_IX 0x40\r
203#define MDSAD_B_DD 0x20\r
204#define MDSAD_B_MO 0x10\r
205#define MDSAD_B_WR 0x08\r
206#define MDSAD_B_SP 0x04\r
207#define MDSAD_B_WP 0x02\r
208#define MDSAD_B_T0 0x01\r
209\r
210/* C-Status */\r
211#define MDSAD_C_SF 0x80\r
212#define MDSAD_C_IX 0x40\r
213#define MDSAD_C_DD 0x20\r
214#define MDSAD_C_MO 0x10\r
215#define MDSAD_C_SC 0x0f\r
216\r
217/* Local function prototypes */\r
218static t_stat mdsad_reset(DEVICE *mdsad_dev);\r
219static t_stat mdsad_attach(UNIT *uptr, char *cptr);\r
220static t_stat mdsad_detach(UNIT *uptr);\r
221static t_stat mdsad_boot(int32 unitno, DEVICE *dptr);\r
222static uint8 MDSAD_Read(const uint32 Addr);\r
223\r
224static int32 mdsaddev(const int32 Addr, const int32 rw, const int32 data);\r
225\r
226static int32 trace_level = 0;\r
227\r
228static UNIT mdsad_unit[] = {\r
229 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) },\r
230 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) },\r
231 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) },\r
232 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) }\r
233};\r
234\r
235static REG mdsad_reg[] = {\r
236 { HRDATA (TRACELEVEL, trace_level, 16), },\r
237 { NULL }\r
238};\r
239\r
240static MTAB mdsad_mod[] = {\r
241 { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },\r
242 { UNIT_MDSAD_WLK, 0, "WRTENB", "WRTENB", NULL },\r
243 { UNIT_MDSAD_WLK, UNIT_MDSAD_WLK, "WRTLCK", "WRTLCK", NULL },\r
244 /* quiet, no warning messages */\r
245 { UNIT_MDSAD_VERBOSE, 0, "QUIET", "QUIET", NULL },\r
246 /* verbose, show warning messages */\r
247 { UNIT_MDSAD_VERBOSE, UNIT_MDSAD_VERBOSE, "VERBOSE", "VERBOSE", NULL },\r
248 { 0 }\r
249};\r
250\r
251DEVICE mdsad_dev = {\r
252 "MDSAD", mdsad_unit, mdsad_reg, mdsad_mod,\r
253 MDSAD_MAX_DRIVES, 10, 31, 1, MDSAD_MAX_DRIVES, MDSAD_MAX_DRIVES,\r
254 NULL, NULL, &mdsad_reset,\r
255 &mdsad_boot, &mdsad_attach, &mdsad_detach,\r
256 &mdsad_info_data, (DEV_DISABLE | DEV_DIS), 0,\r
257 NULL, NULL, NULL\r
258};\r
259\r
260/* Reset routine */\r
261t_stat mdsad_reset(DEVICE *dptr)\r
262{\r
263 PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;\r
264\r
265 if(dptr->flags & DEV_DIS) {\r
266 sim_map_resource(pnp->mem_base, pnp->mem_size,\r
267 RESOURCE_TYPE_MEMORY, &mdsaddev, TRUE);\r
268 } else {\r
269 /* Connect MDSAD at base address */\r
270 if(sim_map_resource(pnp->mem_base, pnp->mem_size,\r
271 RESOURCE_TYPE_MEMORY, &mdsaddev, FALSE) != 0) {\r
272 printf("%s: error mapping resource at 0x%04x\n",\r
273 __FUNCTION__, pnp->mem_base);\r
274 dptr->flags |= DEV_DIS;\r
275 return SCPE_ARG;\r
276 }\r
277 }\r
278 return SCPE_OK;\r
279}\r
280\r
281/* Attach routine */\r
282t_stat mdsad_attach(UNIT *uptr, char *cptr)\r
283{\r
284 char header[4];\r
285 t_stat r;\r
286 unsigned int i = 0;\r
287\r
288 r = attach_unit(uptr, cptr); /* attach unit */\r
289 if(r != SCPE_OK) /* error? */\r
290 return r;\r
291\r
292 /* Determine length of this disk */\r
293 if(sim_fsize(uptr->fileref) != 0) {\r
294 uptr->capac = sim_fsize(uptr->fileref);\r
295 } else {\r
296 uptr->capac = MDSAD_CAPACITY;\r
297 }\r
298\r
299 for(i = 0; i < MDSAD_MAX_DRIVES; i++) {\r
300 mdsad_info->drive[i].uptr = &mdsad_dev.units[i];\r
301 }\r
302\r
303 for(i = 0; i < MDSAD_MAX_DRIVES; i++) {\r
304 if(mdsad_dev.units[i].fileref == uptr->fileref) {\r
305 break;\r
306 }\r
307 }\r
308\r
309 /* Default for new file is DSK */\r
310 uptr->u3 = IMAGE_TYPE_DSK;\r
311\r
312 if(uptr->capac > 0) {\r
313 fgets(header, 4, uptr->fileref);\r
314 if(!strcmp(header, "IMD")) {\r
315 uptr->u3 = IMAGE_TYPE_IMD;\r
316 } else if(!strcmp(header, "CPT")) {\r
317 printf("CPT images not yet supported\n");\r
318 uptr->u3 = IMAGE_TYPE_CPT;\r
319 mdsad_detach(uptr);\r
320 return SCPE_OPENERR;\r
321 } else {\r
322 uptr->u3 = IMAGE_TYPE_DSK;\r
323 }\r
324 }\r
325\r
326 if (uptr->flags & UNIT_MDSAD_VERBOSE)\r
327 printf("MDSAD%d, attached to '%s', type=%s, len=%d\n", i, cptr,\r
328 uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",\r
329 uptr->capac);\r
330\r
331 if(uptr->u3 == IMAGE_TYPE_IMD) {\r
332 if(uptr->capac < 318000) {\r
333 printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n");\r
334 mdsad_detach(uptr);\r
335 return SCPE_OPENERR;\r
336 }\r
337\r
338 if (uptr->flags & UNIT_MDSAD_VERBOSE)\r
339 printf("--------------------------------------------------------\n");\r
340 mdsad_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_MDSAD_VERBOSE));\r
341 if (uptr->flags & UNIT_MDSAD_VERBOSE)\r
342 printf("\n");\r
343 } else {\r
344 mdsad_info->drive[i].imd = NULL;\r
345 }\r
346\r
347 return SCPE_OK;\r
348}\r
349\r
350\r
351/* Detach routine */\r
352t_stat mdsad_detach(UNIT *uptr)\r
353{\r
354 t_stat r;\r
355 int8 i;\r
356\r
357 for(i = 0; i < MDSAD_MAX_DRIVES; i++) {\r
358 if(mdsad_dev.units[i].fileref == uptr->fileref) {\r
359 break;\r
360 }\r
361 }\r
362\r
363 if (i >= MDSAD_MAX_DRIVES) return SCPE_ARG;\r
364\r
365 DBG_PRINT(("Detach MDSAD%d\n", i));\r
366 diskClose(mdsad_info->drive[i].imd);\r
367\r
368 r = detach_unit(uptr); /* detach unit */\r
369 if(r != SCPE_OK)\r
370 return r;\r
371\r
372 mdsad_dev.units[i].fileref = NULL; /* psco check if ok */\r
373 return SCPE_OK;\r
374}\r
375\r
376static t_stat mdsad_boot(int32 unitno, DEVICE *dptr)\r
377{\r
378\r
379 PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;\r
380\r
381 DBG_PRINT(("Booting MDSAD Controller at 0x%04x, unit %d" NLP,\r
382 pnp->mem_base+1+(unitno&3), unitno & 3));\r
383\r
384 /* Unit 3 can't be booted yet. This involves modifying the A register. */\r
385 *((int32 *) sim_PC->loc) = pnp->mem_base+1+(unitno&3);\r
386 return SCPE_OK;\r
387}\r
388\r
389static int32 mdsaddev(const int32 Addr, const int32 rw, const int32 data)\r
390{\r
391 if(rw == 0) { /* Read */\r
392 return(MDSAD_Read(Addr));\r
393 } else { /* Write */\r
394 DBG_PRINT(("MDSAD: write attempt at 0x%04x ignored." NLP, Addr));\r
395 return (-1);\r
396 }\r
397}\r
398\r
399/* This ROM image is taken from the Solace Emulator, which uses */\r
400/* a ROM from a "Micro Complex Phase Lock II" dual- */\r
401/* density controller card. It is supposedly compatible with the */\r
402/* Northstar-designed dual density floppy controller. It has the */\r
403/* interesting property that by jumping to base_addr+0 (or +1) and */\r
404/* it boots from floppy 0; jump to base_addr+2 you boot from floppy 1; */\r
405/* jump to base_addr+3 and you boot from floppy 2. You can boot from */\r
406/* floppy 3 by loading A with 08H and jumping to base_addr+7. */\r
407static uint8 mdsad_rom[] = {\r
408 0x44, 0x01, 0x01, 0x01, 0x82, 0x84, 0x78, 0xE6, 0x07, 0x4F, 0x00, 0x31, 0x30, 0x00, 0x21, 0x29, /* 0x00 */\r
409 0x00, 0xE5, 0x21, 0x2C, 0xC2, 0xE5, 0x21, 0x77, 0x13, 0xE5, 0x21, 0xC9, 0x1A, 0xE5, 0xCD, 0x28, /* 0x10 */\r
410 0x00, 0x21, 0x30, 0x00, 0x5B, 0x52, 0x44, 0x54, 0x5D, 0x3A, 0x27, 0x00, 0x57, 0xC3, 0x29, 0x00, /* 0x20 */\r
411 0x14, 0x14, 0x1E, 0x15, 0x1A, 0x26, 0x30, 0xCD, 0xD9, 0x00, 0x42, 0x05, 0x0A, 0xCD, 0xD4, 0x00, /* 0x30 */\r
412 0x2E, 0x0D, 0x2D, 0xCA, 0x43, 0x00, 0xCD, 0xD7, 0x00, 0x1A, 0xE6, 0x40, 0xCA, 0x42, 0x00, 0x3E, /* 0x40 */\r
413 0x0A, 0xF5, 0xCD, 0xC1, 0x00, 0x1E, 0x20, 0x1A, 0xE6, 0x01, 0xC2, 0x63, 0x00, 0xCD, 0xC5, 0x00, /* 0x50 */\r
414 0xC3, 0x55, 0x00, 0x2E, 0x04, 0xCD, 0xE7, 0x00, 0x1E, 0x10, 0x1A, 0xE6, 0x04, 0xCA, 0x68, 0x00, /* 0x60 */\r
415 0x3E, 0x09, 0x3D, 0xC2, 0x72, 0x00, 0x1A, 0xE6, 0x20, 0xC2, 0x84, 0x00, 0xCD, 0xC1, 0x00, 0x2E, /* 0x70 */\r
416 0x08, 0xCD, 0xE7, 0x00, 0x06, 0xA3, 0x1E, 0x10, 0x05, 0xCA, 0xF4, 0x00, 0x1A, 0x0F, 0xD2, 0x88, /* 0x80 */\r
417 0x00, 0x1E, 0x40, 0x1A, 0x67, 0x2E, 0x00, 0x36, 0x59, 0x07, 0x47, 0x23, 0x1A, 0x77, 0xA8, 0x07, /* 0x90 */\r
418 0x47, 0x2C, 0xC2, 0x9C, 0x00, 0x24, 0x1A, 0x77, 0xA8, 0x07, 0x47, 0x2C, 0xC2, 0xA6, 0x00, 0x1A, /* 0xA0 */\r
419 0xA8, 0xC2, 0xF4, 0x00, 0x25, 0x2E, 0x03, 0x71, 0x2D, 0x36, 0x59, 0xC2, 0xB8, 0x00, 0x2E, 0x0A, /* 0xB0 */\r
420 0xE9, 0x3E, 0x20, 0x81, 0x4F, 0x0A, 0x3E, 0x10, 0x81, 0x4F, 0x0A, 0x3E, 0xF0, 0x81, 0x4F, 0x0A, /* 0xC0 */\r
421 0x79, 0xE6, 0x0F, 0x4F, 0xCD, 0xD7, 0x00, 0x26, 0x01, 0x1E, 0x11, 0x1A, 0x1D, 0x1A, 0xB7, 0xF2, /* 0xD0 */\r
422 0xDD, 0x00, 0x25, 0xC2, 0xD9, 0x00, 0xC9, 0xCD, 0xD7, 0x00, 0x1E, 0x35, 0x1A, 0xE6, 0x0F, 0xBD, /* 0xE0 */\r
423 0xC2, 0xE7, 0x00, 0xC9, 0xF1, 0x3D, 0xF5, 0xC2, 0x55, 0x00, 0xC3, 0xFA, 0x00, 0x52, 0x44, 0x54 /* 0xF0 */\r
424};\r
425\r
426static void showdata(int32 isRead) {\r
427 int32 i;\r
428 printf("MDSAD: " ADDRESS_FORMAT " %s Sector =" NLP "\t", PCX, isRead ? "Read" : "Write");\r
429 for(i=0; i < MDSAD_SECTOR_LEN; i++) {\r
430 printf("%02X ", sdata.u.data[i]);\r
431 if(((i+1) & 0xf) == 0) printf(NLP "\t");\r
432 }\r
433 printf(NLP);\r
434}\r
435\r
436static int checksum;\r
437static uint32 sec_offset;\r
438\r
439static uint8 MDSAD_Read(const uint32 Addr)\r
440{\r
441 uint8 cData;\r
442 uint8 ds;\r
443 MDSAD_DRIVE_INFO *pDrive;\r
444\r
445 cData = 0x00;\r
446\r
447 pDrive = &mdsad_info->drive[mdsad_info->orders.ds];\r
448\r
449 switch( (Addr & 0x300) >> 8 ) {\r
450 case MDSAD_READ_ROM:\r
451 cData = mdsad_rom[Addr & 0xFF];\r
452 break;\r
453 case MDSAD_WRITE_DATA:\r
454 {\r
455 unsigned int flags = 0;\r
456 unsigned int writelen;\r
457\r
458 if(mdsad_info->datacount == 0) {\r
459 TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT\r
460 " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP,\r
461 PCX,\r
462 mdsad_info->orders.ds,\r
463 pDrive->track,\r
464 mdsad_info->orders.ss,\r
465 pDrive->sector));\r
466\r
467 sec_offset = (pDrive->track * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) +\r
468 (mdsad_info->orders.ss * ((MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK) * MDSAD_TRACKS)) +\r
469 (pDrive->sector * MDSAD_SECTOR_LEN);\r
470\r
471 }\r
472\r
473 DBG_PRINT(("MDSAD: " ADDRESS_FORMAT\r
474 " WRITE-DATA[offset:%06x+%03x]=%02x" NLP,\r
475 PCX, sec_offset, mdsad_info->datacount, Addr & 0xFF));\r
476 mdsad_info->datacount++;\r
477 if(mdsad_info->datacount < MDSAD_RAW_LEN)\r
478 sdata.raw[mdsad_info->datacount] = Addr & 0xFF;\r
479\r
480 if(mdsad_info->datacount == (MDSAD_RAW_LEN - 1)) {\r
481 TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT\r
482 " Write Complete" NLP, PCX));\r
483\r
484 if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) {\r
485 TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT\r
486 " Drive: %d not attached - write ignored." NLP,\r
487 PCX, mdsad_info->orders.ds));\r
488 return 0x00;\r
489 }\r
490 if(trace_level & WR_DATA_DETAIL_MSG) showdata(FALSE);\r
491 switch((pDrive->uptr)->u3)\r
492 {\r
493 case IMAGE_TYPE_IMD:\r
494 if(pDrive->imd == NULL) {\r
495 printf(".imd is NULL!" NLP);\r
496 }\r
497 sectWrite(pDrive->imd,\r
498 pDrive->track,\r
499 mdsad_info->orders.ss,\r
500 pDrive->sector,\r
501 sdata.u.data,\r
502 MDSAD_SECTOR_LEN,\r
503 &flags,\r
504 &writelen);\r
505 break;\r
506 case IMAGE_TYPE_DSK:\r
507 if(pDrive->uptr->fileref == NULL) {\r
508 printf(".fileref is NULL!" NLP);\r
509 } else {\r
510 fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);\r
511 fwrite(sdata.u.data, MDSAD_SECTOR_LEN, 1,\r
512 (pDrive->uptr)->fileref);\r
513 }\r
514 break;\r
515 case IMAGE_TYPE_CPT:\r
516 printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r
517 break;\r
518 default:\r
519 printf("%s: Unknown image Format" NLP, __FUNCTION__);\r
520 break;\r
521 }\r
522 }\r
523 break;\r
524 }\r
525 case MDSAD_CTLR_ORDERS:\r
526 mdsad_info->orders.dd = (Addr & 0x80) >> 7;\r
527 mdsad_info->orders.ss = (Addr & 0x40) >> 6;\r
528 mdsad_info->orders.dp = (Addr & 0x20) >> 5;\r
529 mdsad_info->orders.st = (Addr & 0x10) >> 4;\r
530 mdsad_info->orders.ds = (Addr & 0x0F);\r
531\r
532 ds = mdsad_info->orders.ds;\r
533 switch(mdsad_info->orders.ds) {\r
534 case 0:\r
535 case 1:\r
536 mdsad_info->orders.ds = 0;\r
537 break;\r
538 case 2:\r
539 mdsad_info->orders.ds = 1;\r
540 break;\r
541 case 4:\r
542 mdsad_info->orders.ds = 2;\r
543 break;\r
544 case 8:\r
545 mdsad_info->orders.ds = 3;\r
546 break;\r
547 }\r
548\r
549 TRACE_PRINT(ORDERS_MSG, ("MDSAD: " ADDRESS_FORMAT\r
550 " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d" NLP,\r
551 PCX,\r
552 mdsad_info->orders.ds, ds,\r
553 mdsad_info->orders.dd,\r
554 mdsad_info->orders.ss,\r
555 mdsad_info->orders.dp,\r
556 mdsad_info->orders.st));\r
557\r
558 /* use latest selected drive */\r
559 pDrive = &mdsad_info->drive[mdsad_info->orders.ds];\r
560\r
561 if(mdsad_info->orders.st == 1) {\r
562 if(mdsad_info->orders.dp == 0) {\r
563 TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT\r
564 " Step out: Track=%d%s" NLP, PCX, pDrive->track,\r
565 pDrive->track == 0 ? "[Warn: already at 0]" : ""));\r
566 if(pDrive->track > 0) /* anything to do? */\r
567 pDrive->track--;\r
568 } else {\r
569 TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT\r
570 " Step in: Track=%d%s" NLP, PCX, pDrive->track,\r
571 pDrive->track == (MDSAD_TRACKS - 1) ?\r
572 "[Warn: already at highest track]" : ""));\r
573 if(pDrive->track < (MDSAD_TRACKS - 1)) /* anything to do? */\r
574 pDrive->track++;\r
575 }\r
576 }\r
577 /* always update t0 */\r
578 mdsad_info->b_status.t0 = (pDrive->track == 0);\r
579 break;\r
580 case MDSAD_CTLR_COMMAND:\r
581/* TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT " DM=%x" NLP, PCX, (Addr & 0xF0) >> 4)); */\r
582 switch(Addr & 0x0F) {\r
583 case MDSAD_CMD_MOTORS_ON:\r
584 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
585 " CMD=Motors On" NLP, PCX));\r
586 mdsad_info->com_status.mo = 1; /* Turn motors on */\r
587 break;\r
588\r
589 case MDSAD_CMD_NOP:\r
590 pDrive->sector_wait_count++;\r
591 switch(pDrive->sector_wait_count) {\r
592 case 10:\r
593 {\r
594 mdsad_info->com_status.sf = 1;\r
595 mdsad_info->a_status.wi = 0;\r
596 mdsad_info->a_status.re = 0;\r
597 mdsad_info->a_status.bd = 0;\r
598 pDrive->sector_wait_count = 0;\r
599 pDrive->sector++;\r
600 if(pDrive->sector >= MDSAD_SECTORS_PER_TRACK) {\r
601 pDrive->sector = 0;\r
602 mdsad_info->com_status.ix = 1;\r
603 } else {\r
604 mdsad_info->com_status.ix = 0;\r
605 }\r
606 break;\r
607 }\r
608 case 2:\r
609 mdsad_info->a_status.wi = 1;\r
610 break;\r
611 case 3:\r
612 mdsad_info->a_status.re = 1;\r
613 mdsad_info->a_status.bd = 1;\r
614 break;\r
615 default:\r
616 break;\r
617 }\r
618 break;\r
619 case MDSAD_CMD_RESET_SF:\r
620 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
621 " CMD=Reset Sector Flag" NLP, PCX));\r
622 mdsad_info->com_status.sf = 0;\r
623 mdsad_info->datacount = 0;\r
624 break;\r
625 case MDSAD_CMD_INTR_DIS:\r
626 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
627 " CMD=Disarm Interrupt" NLP, PCX));\r
628 mdsad_info->int_enable = 0;\r
629 break;\r
630 case MDSAD_CMD_INTR_ARM:\r
631 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
632 " CMD=Arm Interrupt" NLP, PCX));\r
633 mdsad_info->int_enable = 1;\r
634 break;\r
635 case MDSAD_CMD_SET_BODY:\r
636 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
637 " CMD=Set Body (Diagnostic)" NLP, PCX));\r
638 break;\r
639 case MDSAD_CMD_BEGIN_WR:\r
640 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
641 " CMD=Begin Write" NLP, PCX));\r
642 break;\r
643 case MDSAD_CMD_RESET:\r
644 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
645 " CMD=Reset Controller" NLP, PCX));\r
646 mdsad_info->com_status.mo = 0; /* Turn motors off */\r
647 break;\r
648 default:\r
649 TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT\r
650 " Unsupported CMD=0x%x" NLP, PCX, Addr & 0x0F));\r
651 break;\r
652 }\r
653\r
654 /* Always Double-Density for now... */\r
655 mdsad_info->com_status.dd = 1;\r
656\r
657 cData = (mdsad_info->com_status.sf & 1) << 7;\r
658 cData |= (mdsad_info->com_status.ix & 1) << 6;\r
659 cData |= (mdsad_info->com_status.dd & 1) << 5;\r
660 cData |= (mdsad_info->com_status.mo & 1) << 4;\r
661\r
662 mdsad_info->c_status.sc = pDrive->sector;\r
663\r
664 switch( (Addr & 0xF0) >> 4) {\r
665 case MDSAD_A_STATUS: /* A-STATUS */\r
666 cData |= (mdsad_info->a_status.wi & 1) << 3;\r
667 cData |= (mdsad_info->a_status.re & 1) << 2;\r
668 cData |= (mdsad_info->a_status.sp & 1) << 1;\r
669 cData |= (mdsad_info->a_status.bd & 1);\r
670 TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT\r
671 " A-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX,\r
672 cData & MDSAD_A_SF ? "SF" : " ",\r
673 cData & MDSAD_A_IX ? "IX" : " ",\r
674 cData & MDSAD_A_DD ? "DD" : " ",\r
675 cData & MDSAD_A_MO ? "MO" : " ",\r
676 cData & MDSAD_A_WI ? "WI" : " ",\r
677 cData & MDSAD_A_RE ? "RE" : " ",\r
678 cData & MDSAD_A_SP ? "SP" : " ",\r
679 cData & MDSAD_A_BD ? "BD" : " "));\r
680 break;\r
681 case MDSAD_B_STATUS: /* B-STATUS */\r
682 cData |= (mdsad_info->b_status.wr & 1) << 3;\r
683 cData |= (mdsad_info->b_status.sp & 1) << 2;\r
684 cData |= (mdsad_info->b_status.wp & 1) << 1;\r
685 cData |= (mdsad_info->b_status.t0 & 1);\r
686 TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT\r
687 " B-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX,\r
688 cData & MDSAD_B_SF ? "SF" : " ",\r
689 cData & MDSAD_B_IX ? "IX" : " ",\r
690 cData & MDSAD_B_DD ? "DD" : " ",\r
691 cData & MDSAD_B_MO ? "MO" : " ",\r
692 cData & MDSAD_B_WR ? "WR" : " ",\r
693 cData & MDSAD_B_SP ? "SP" : " ",\r
694 cData & MDSAD_B_WP ? "WP" : " ",\r
695 cData & MDSAD_B_T0 ? "T0" : " "));\r
696 break;\r
697 case MDSAD_C_STATUS: /* C-STATUS */\r
698 cData |= (mdsad_info->c_status.sc & 0xF);\r
699 TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT\r
700 " C-Status = <%s %s %s %s %i>" NLP, PCX,\r
701 cData & MDSAD_C_SF ? "SF" : " ",\r
702 cData & MDSAD_C_IX ? "IX" : " ",\r
703 cData & MDSAD_C_DD ? "DD" : " ",\r
704 cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_SC));\r
705 break;\r
706 case MDSAD_READ_DATA: /* READ DATA */\r
707 {\r
708 unsigned int flags;\r
709 unsigned int readlen;\r
710\r
711 if(mdsad_info->datacount == 0) {\r
712 TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT\r
713 " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP,\r
714 PCX,\r
715 mdsad_info->orders.ds,\r
716 pDrive->track,\r
717 mdsad_info->orders.ss,\r
718 pDrive->sector));\r
719\r
720 checksum = 0;\r
721\r
722 sec_offset = (pDrive->track * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) +\r
723 (mdsad_info->orders.ss * ((MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK) * MDSAD_TRACKS)) +\r
724 (pDrive->sector * MDSAD_SECTOR_LEN);\r
725\r
726 if ((pDrive->uptr == NULL) ||\r
727 (pDrive->uptr->fileref == NULL)) {\r
728 TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT\r
729 " Drive: %d not attached - read ignored." NLP,\r
730 PCX, mdsad_info->orders.ds));\r
731 return 0xe5;\r
732 }\r
733\r
734 switch((pDrive->uptr)->u3)\r
735 {\r
736 case IMAGE_TYPE_IMD:\r
737 if(pDrive->imd == NULL) {\r
738 printf(".imd is NULL!" NLP);\r
739 }\r
740/* DBG_PRINT(("%s: Read: imd=%p" NLP, __FUNCTION__, mdsad_info->drive[mdsad_info->sel_drive].imd)); */\r
741 sectRead(pDrive->imd,\r
742 pDrive->track,\r
743 mdsad_info->orders.ss,\r
744 pDrive->sector,\r
745 sdata.u.data,\r
746 MDSAD_SECTOR_LEN,\r
747 &flags,\r
748 &readlen);\r
749 break;\r
750 case IMAGE_TYPE_DSK:\r
751 if(pDrive->uptr->fileref == NULL) {\r
752 printf(".fileref is NULL!" NLP);\r
753 } else {\r
754 fseek((pDrive->uptr)->fileref,\r
755 sec_offset, SEEK_SET);\r
756 fread(&sdata.u.data[0], MDSAD_SECTOR_LEN,\r
757 1, (pDrive->uptr)->fileref);\r
758 }\r
759 break;\r
760 case IMAGE_TYPE_CPT:\r
761 printf("%s: CPT Format not supported"\r
762 NLP, __FUNCTION__);\r
763 break;\r
764 default:\r
765 printf("%s: Unknown image Format"\r
766 NLP, __FUNCTION__);\r
767 break;\r
768 }\r
769 if(trace_level & RD_DATA_DETAIL_MSG) showdata(TRUE);\r
770 }\r
771\r
772 if(mdsad_info->datacount < 0x200) {\r
773 cData = sdata.u.data[mdsad_info->datacount];\r
774\r
775 /* Exclusive OR */\r
776 checksum ^= cData;\r
777 /* Rotate Left Circular */\r
778 checksum = ((checksum << 1) | ((checksum & 0x80) != 0)) & 0xff;\r
779\r
780 DBG_PRINT(("MDSAD: " ADDRESS_FORMAT\r
781 " READ-DATA[offset:%06x+%03x]=%02x" NLP,\r
782 PCX, sec_offset, mdsad_info->datacount, cData));\r
783 } else { /* checksum */\r
784 cData = checksum;\r
785 TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT\r
786 " READ-DATA: Checksum is: 0x%02x" NLP,\r
787 PCX, cData));\r
788 }\r
789\r
790 mdsad_info->datacount++;\r
791 break;\r
792 }\r
793 default:\r
794 DBG_PRINT(("MDSAD: " ADDRESS_FORMAT\r
795 " Invalid DM=%x" NLP, PCX, Addr & 0xF));\r
796 break;\r
797 }\r
798\r
799 break;\r
800 }\r
801 return (cData);\r
802}\r