1 /*************************************************************************
3 * $Id: s100_mdsad.c 1773 2008-01-11 05:46:19Z hharte $ *
5 * Copyright (c) 2007-2008 Howard M. Harte. *
6 * http://www.hartetec.com *
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: *
16 * The above copyright notice and this permission notice shall be *
17 * included in all copies or substantial portions of the Software. *
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. *
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 *
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *
34 * Module Description: *
35 * Northstar MDS-AD Disk Controller module for SIMH *
36 * Only Double-Density is supported for now. *
41 *************************************************************************/
44 #include "altairz80_defs.h"
53 #define DBG_PRINT(args) printf args
55 #define DBG_PRINT(args)
59 #define ORDERS_MSG 0x02
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
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
);
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)
84 uint8 data
[MDSAD_SECTOR_LEN
];
87 uint8 raw
[MDSAD_RAW_LEN
];
95 uint8 wp
; /* Disk write protected */
96 uint8 sector
; /* Current Sector number */
97 uint32 sector_wait_count
;
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
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. */
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. */
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. */
136 uint8 sc
; /* Sector Counter: indicates the current sector position. */
140 PNP_INFO pnp
; /* Plug and Play */
143 COM_STATUS com_status
;
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
];
153 static MDSAD_INFO mdsad_info_data
= { { 0xE800, 1024, 0, 0 } };
154 static MDSAD_INFO
*mdsad_info
= &mdsad_info_data
;
156 static SECTOR_FORMAT sdata
;
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. */
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
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
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
189 /* MDS-AD status byte masks */
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
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
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
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
);
224 static int32
mdsaddev(const int32 Addr
, const int32 rw
, const int32 data
);
226 static int32 trace_level
= 0;
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
) }
235 static REG mdsad_reg
[] = {
236 { HRDATA (TRACELEVEL
, trace_level
, 16), },
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
},
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,
261 t_stat
mdsad_reset(DEVICE
*dptr
)
263 PNP_INFO
*pnp
= (PNP_INFO
*)dptr
->ctxt
;
265 if(dptr
->flags
& DEV_DIS
) {
266 sim_map_resource(pnp
->mem_base
, pnp
->mem_size
,
267 RESOURCE_TYPE_MEMORY
, &mdsaddev
, TRUE
);
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
;
282 t_stat
mdsad_attach(UNIT
*uptr
, char *cptr
)
288 r
= attach_unit(uptr
, cptr
); /* attach unit */
289 if(r
!= SCPE_OK
) /* error? */
292 /* Determine length of this disk */
293 if(sim_fsize(uptr
->fileref
) != 0) {
294 uptr
->capac
= sim_fsize(uptr
->fileref
);
296 uptr
->capac
= MDSAD_CAPACITY
;
299 for(i
= 0; i
< MDSAD_MAX_DRIVES
; i
++) {
300 mdsad_info
->drive
[i
].uptr
= &mdsad_dev
.units
[i
];
303 for(i
= 0; i
< MDSAD_MAX_DRIVES
; i
++) {
304 if(mdsad_dev
.units
[i
].fileref
== uptr
->fileref
) {
309 /* Default for new file is DSK */
310 uptr
->u3
= IMAGE_TYPE_DSK
;
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
;
322 uptr
->u3
= IMAGE_TYPE_DSK
;
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",
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");
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
)
344 mdsad_info
->drive
[i
].imd
= NULL
;
352 t_stat
mdsad_detach(UNIT
*uptr
)
357 for(i
= 0; i
< MDSAD_MAX_DRIVES
; i
++) {
358 if(mdsad_dev
.units
[i
].fileref
== uptr
->fileref
) {
363 if (i
>= MDSAD_MAX_DRIVES
) return SCPE_ARG
;
365 DBG_PRINT(("Detach MDSAD%d\n", i
));
366 diskClose(mdsad_info
->drive
[i
].imd
);
368 r
= detach_unit(uptr
); /* detach unit */
372 mdsad_dev
.units
[i
].fileref
= NULL
; /* psco check if ok */
376 static t_stat
mdsad_boot(int32 unitno
, DEVICE
*dptr
)
379 PNP_INFO
*pnp
= (PNP_INFO
*)dptr
->ctxt
;
381 DBG_PRINT(("Booting MDSAD Controller at 0x%04x, unit %d" NLP
,
382 pnp
->mem_base
+1+(unitno
&3), unitno
& 3));
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);
389 static int32
mdsaddev(const int32 Addr
, const int32 rw
, const int32 data
)
391 if(rw
== 0) { /* Read */
392 return(MDSAD_Read(Addr
));
394 DBG_PRINT(("MDSAD: write attempt at 0x%04x ignored." NLP
, Addr
));
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 */
426 static void showdata(int32 isRead
) {
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");
437 static uint32 sec_offset
;
439 static uint8
MDSAD_Read(const uint32 Addr
)
443 MDSAD_DRIVE_INFO
*pDrive
;
447 pDrive
= &mdsad_info
->drive
[mdsad_info
->orders
.ds
];
449 switch( (Addr
& 0x300) >> 8 ) {
451 cData
= mdsad_rom
[Addr
& 0xFF];
453 case MDSAD_WRITE_DATA
:
455 unsigned int flags
= 0;
456 unsigned int writelen
;
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
,
462 mdsad_info
->orders
.ds
,
464 mdsad_info
->orders
.ss
,
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
);
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;
480 if(mdsad_info
->datacount
== (MDSAD_RAW_LEN
- 1)) {
481 TRACE_PRINT(WR_DATA_MSG
, ("MDSAD: " ADDRESS_FORMAT
482 " Write Complete" NLP
, PCX
));
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
));
490 if(trace_level
& WR_DATA_DETAIL_MSG
) showdata(FALSE
);
491 switch((pDrive
->uptr
)->u3
)
494 if(pDrive
->imd
== NULL
) {
495 printf(".imd is NULL!" NLP
);
497 sectWrite(pDrive
->imd
,
499 mdsad_info
->orders
.ss
,
507 if(pDrive
->uptr
->fileref
== NULL
) {
508 printf(".fileref is NULL!" NLP
);
510 fseek((pDrive
->uptr
)->fileref
, sec_offset
, SEEK_SET
);
511 fwrite(sdata
.u
.data
, MDSAD_SECTOR_LEN
, 1,
512 (pDrive
->uptr
)->fileref
);
516 printf("%s: CPT Format not supported" NLP
, __FUNCTION__
);
519 printf("%s: Unknown image Format" NLP
, __FUNCTION__
);
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);
532 ds
= mdsad_info
->orders
.ds
;
533 switch(mdsad_info
->orders
.ds
) {
536 mdsad_info
->orders
.ds
= 0;
539 mdsad_info
->orders
.ds
= 1;
542 mdsad_info
->orders
.ds
= 2;
545 mdsad_info
->orders
.ds
= 3;
549 TRACE_PRINT(ORDERS_MSG
, ("MDSAD: " ADDRESS_FORMAT
550 " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d" NLP
,
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
));
558 /* use latest selected drive */
559 pDrive
= &mdsad_info
->drive
[mdsad_info
->orders
.ds
];
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? */
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? */
577 /* always update t0 */
578 mdsad_info
->b_status
.t0
= (pDrive
->track
== 0);
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 */
590 pDrive
->sector_wait_count
++;
591 switch(pDrive
->sector_wait_count
) {
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;
600 if(pDrive
->sector
>= MDSAD_SECTORS_PER_TRACK
) {
602 mdsad_info
->com_status
.ix
= 1;
604 mdsad_info
->com_status
.ix
= 0;
609 mdsad_info
->a_status
.wi
= 1;
612 mdsad_info
->a_status
.re
= 1;
613 mdsad_info
->a_status
.bd
= 1;
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;
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;
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;
635 case MDSAD_CMD_SET_BODY
:
636 TRACE_PRINT(CMD_MSG
, ("MDSAD: " ADDRESS_FORMAT
637 " CMD=Set Body (Diagnostic)" NLP
, PCX
));
639 case MDSAD_CMD_BEGIN_WR
:
640 TRACE_PRINT(CMD_MSG
, ("MDSAD: " ADDRESS_FORMAT
641 " CMD=Begin Write" NLP
, PCX
));
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 */
649 TRACE_PRINT(CMD_MSG
, ("MDSAD: " ADDRESS_FORMAT
650 " Unsupported CMD=0x%x" NLP
, PCX
, Addr
& 0x0F));
654 /* Always Double-Density for now... */
655 mdsad_info
->com_status
.dd
= 1;
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;
662 mdsad_info
->c_status
.sc
= pDrive
->sector
;
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" : " "));
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" : " "));
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
));
706 case MDSAD_READ_DATA
: /* READ DATA */
709 unsigned int readlen
;
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
,
715 mdsad_info
->orders
.ds
,
717 mdsad_info
->orders
.ss
,
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
);
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
));
734 switch((pDrive
->uptr
)->u3
)
737 if(pDrive
->imd
== NULL
) {
738 printf(".imd is NULL!" NLP
);
740 /* DBG_PRINT(("%s: Read: imd=%p" NLP, __FUNCTION__, mdsad_info->drive[mdsad_info->sel_drive].imd)); */
741 sectRead(pDrive
->imd
,
743 mdsad_info
->orders
.ss
,
751 if(pDrive
->uptr
->fileref
== NULL
) {
752 printf(".fileref is NULL!" NLP
);
754 fseek((pDrive
->uptr
)->fileref
,
755 sec_offset
, SEEK_SET
);
756 fread(&sdata
.u
.data
[0], MDSAD_SECTOR_LEN
,
757 1, (pDrive
->uptr
)->fileref
);
761 printf("%s: CPT Format not supported"
765 printf("%s: Unknown image Format"
769 if(trace_level
& RD_DATA_DETAIL_MSG
) showdata(TRUE
);
772 if(mdsad_info
->datacount
< 0x200) {
773 cData
= sdata
.u
.data
[mdsad_info
->datacount
];
777 /* Rotate Left Circular */
778 checksum
= ((checksum
<< 1) | ((checksum
& 0x80) != 0)) & 0xff;
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 */
785 TRACE_PRINT(RD_DATA_MSG
, ("MDSAD: " ADDRESS_FORMAT
786 " READ-DATA: Checksum is: 0x%02x" NLP
,
790 mdsad_info
->datacount
++;
794 DBG_PRINT(("MDSAD: " ADDRESS_FORMAT
795 " Invalid DM=%x" NLP
, PCX
, Addr
& 0xF));