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