blob: d2898dc1884c4153e914f1491251df1acf090fce [file] [log] [blame] [raw]
/*************************************************************************
* s100_mdsa.c: North Star Single Density Controller Emulation
*
* Created by Mike Douglas
* Based on s100_mdsad.c written by Howard Harte
*
* Module Description:
* Northstar MDS-A Single Density Disk Controller module for SIMH
*
* Environment:
* User mode only
*
*************************************************************************/
/*#define DBG_MSG*/
#include "altairz80_defs.h"
#include "sim_imd.h"
#if defined (_WIN32)
#include <windows.h>
#endif
#ifdef DBG_MSG
#define DBG_PRINT(args) printf args
#else
#define DBG_PRINT(args)
#endif
/* Debug flags */
#define ERROR_MSG (1 << 0)
#define SEEK_MSG (1 << 1)
#define CMD_MSG (1 << 2)
#define RD_DATA_MSG (1 << 3)
#define WR_DATA_MSG (1 << 4)
#define STATUS_MSG (1 << 5)
#define RD_DATA_DETAIL_MSG (1 << 6)
#define WR_DATA_DETAIL_MSG (1 << 7)
extern uint32 PCX;
extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
#define MDSA_MAX_DRIVES 3
#define MDSA_SECTOR_LEN 256
#define MDSA_SECTORS_PER_TRACK 10
#define MDSA_TRACKS 35
#define MDSA_RAW_LEN (16 + 1 + MDSA_SECTOR_LEN + 1)
typedef union {
struct {
uint8 zeros[16];
uint8 sync[1];
uint8 data[MDSA_SECTOR_LEN];
uint8 checksum;
} u;
uint8 raw[MDSA_RAW_LEN];
} SECTOR_FORMAT;
typedef struct {
UNIT *uptr;
uint8 track;
uint8 wp; /* Disk write protected */
uint8 sector; /* Current Sector number */
uint32 sector_wait_count;
} MDSA_DRIVE_INFO;
typedef struct {
uint8 sf; /* Sector Flag: set when sector hole detected, reset by software. */
uint8 wi; /* Window: true during 96-microsecond window at beginning of sector. */
uint8 mo; /* Motor On: true while motor(s) are on. */
} COM_STATUS;
typedef struct {
uint8 wr; /* Write: controller ready to receive write data */
uint8 bd; /* Body: set when sync character is detected. */
uint8 wp; /* Write Protect: true while the diskette installed in the selected drive is write protected. */
uint8 t0; /* Track 0: true if selected drive is at track zero. */
} A_STATUS;
typedef struct {
uint8 sc; /* Sector Counter: indicates the current sector position. */
} B_STATUS;
typedef struct {
PNP_INFO pnp; /* Plug and Play */
COM_STATUS com_status;
A_STATUS a_status;
B_STATUS b_status;
uint8 int_enable; /* Interrupt Enable */
uint8 stepState; /* state of step flip-flop*/
uint8 stepDir; /* state of step direction flip-flop */
uint8 currentDrive; /* currently selected drive */
uint32 datacount; /* Number of data bytes transferred from controller for current sector */
MDSA_DRIVE_INFO drive[MDSA_MAX_DRIVES];
} MDSA_INFO;
static MDSA_INFO mdsa_info_data = { { 0xE800, 1024, 0, 0 } };
static MDSA_INFO *mdsa_info = &mdsa_info_data;
static SECTOR_FORMAT sdata;
static uint32 stepCleared = TRUE; /* true when step bit has returned to zero */
#define UNIT_V_MDSA_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_MDSA_VERBOSE (1 << UNIT_V_MDSA_VERBOSE)
#define MDSA_CAPACITY (35*10*MDSA_SECTOR_LEN) /* Default North Star Disk Capacity */
/* MDS-AD Controller Subcases */
#define MDSA_READ_ROM0 0
#define MDSA_READ_ROM1 1
#define MDSA_WRITE_DATA 2
#define MDSA_CTLR_COMMAND 3
/* MDS_AD Controller Command Bits */
#define MDSA_MOTORS_ON 0x80 /* 1 = motor on */
#define MDSA_READ_DATA 0x40 /* 1 = return byte read from disk */
#define MDSA_B_STATUS 0x20 /* 1 = return B status, else A status */
/* MDS-AD Enumerated Controller Commands */
#define MDSA_CMD_DRIVE 0 /* select drive in M1,M0 */
#define MDSA_CMD_BEGIN_WR 1 /* start write */
#define MDSA_CMD_STEP 2 /* load step bit from M0 */
#define MDSA_CMD_INTR 3 /* load interrupt enable from M0 */
#define MDSA_CMD_NOP 4
#define MDSA_CMD_RESET_SF 5 /* reset sector flag */
#define MDSA_CMD_RESET 6 /* reset controller, raise heads, stop motors */
#define MDSA_CMD_STEP_DIR 7 /* load step direction from M0, 1=in, 0=out */
/* MDS-AD status byte masks */
/* A-Status */
#define MDSA_A_SF 0x80
#define MDSA_A_WI 0x40
#define MDSA_A_MO 0x10
#define MDSA_A_WR 0x08
#define MDSA_A_BD 0x04
#define MDSA_A_WP 0x02
#define MDSA_A_T0 0x01
/* B-Status */
#define MDSA_B_SF 0x80
#define MDSA_B_WI 0x40
#define MDSA_B_MO 0x10
#define MDSA_B_SC 0x0f
/* Local function prototypes */
static t_stat mdsa_reset(DEVICE *mdsa_dev);
static t_stat mdsa_attach(UNIT *uptr, CONST char *cptr);
static t_stat mdsa_detach(UNIT *uptr);
static t_stat mdsa_boot(int32 unitno, DEVICE *dptr);
static uint8 MDSA_Read(const uint32 Addr);
static const char* mdsa_description(DEVICE *dptr);
static int32 mdsadev(const int32 Addr, const int32 rw, const int32 data);
static UNIT mdsa_unit[] = {
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSA_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSA_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSA_CAPACITY) },
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSA_CAPACITY) }
};
static REG mdsa_reg[] = {
{ NULL }
};
#define MDSA_NAME "North Star Single Density Controller"
static const char* mdsa_description(DEVICE *dptr) {
return MDSA_NAME;
}
static MTAB mdsa_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
&set_membase, &show_membase, NULL, "Sets disk controller memory base address" },
/* quiet, no warning messages */
{ UNIT_MDSA_VERBOSE, 0, "QUIET", "QUIET",
NULL, NULL, NULL, "No verbose messages for unit " MDSA_NAME "n" },
/* verbose, show warning messages */
{ UNIT_MDSA_VERBOSE, UNIT_MDSA_VERBOSE, "VERBOSE", "VERBOSE",
NULL, NULL, NULL, "Verbose messages for unit " MDSA_NAME "n" },
{ 0 }
};
/* Debug Flags */
static DEBTAB mdsa_dt[] = {
{ "ERROR", ERROR_MSG, "Error messages" },
{ "SEEK", SEEK_MSG, "Seek messages" },
{ "CMD", CMD_MSG, "Command messages" },
{ "READ", RD_DATA_MSG, "Read messages" },
{ "WRITE", WR_DATA_MSG, "Write messages" },
{ "STATUS", STATUS_MSG, "Status messages" },
{ "RDDETAIL", RD_DATA_DETAIL_MSG, "Read detail messages" },
{ "WRDETAIL", WR_DATA_DETAIL_MSG, "Write detail messags" },
{ NULL, 0 }
};
DEVICE mdsa_dev = {
"MDSA", mdsa_unit, mdsa_reg, mdsa_mod,
MDSA_MAX_DRIVES, 10, 31, 1, MDSA_MAX_DRIVES, MDSA_MAX_DRIVES,
NULL, NULL, &mdsa_reset,
&mdsa_boot, &mdsa_attach, &mdsa_detach,
&mdsa_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
mdsa_dt, NULL, NULL, NULL, NULL, NULL, &mdsa_description
};
/* Reset routine */
t_stat mdsa_reset(DEVICE *dptr)
{
PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
if(dptr->flags & DEV_DIS) {
sim_map_resource(pnp->mem_base, pnp->mem_size,
RESOURCE_TYPE_MEMORY, &mdsadev, TRUE);
} else {
/* Connect MDSA at base address */
if(sim_map_resource(pnp->mem_base, pnp->mem_size,
RESOURCE_TYPE_MEMORY, &mdsadev, FALSE) != 0) {
printf("%s: error mapping resource at 0x%04x\n",
__FUNCTION__, pnp->mem_base);
dptr->flags |= DEV_DIS;
return SCPE_ARG;
}
}
return SCPE_OK;
}
/* Attach routine */
t_stat mdsa_attach(UNIT *uptr, CONST char *cptr)
{
char header[4];
t_stat r;
unsigned int i = 0;
r = attach_unit(uptr, cptr); /* attach unit */
if(r != SCPE_OK) /* error? */
return r;
/* Determine length of this disk */
if(sim_fsize(uptr->fileref) != 0) {
uptr->capac = sim_fsize(uptr->fileref);
} else {
uptr->capac = MDSA_CAPACITY;
}
for(i = 0; i < MDSA_MAX_DRIVES; i++) {
mdsa_info->drive[i].uptr = &mdsa_dev.units[i];
}
for(i = 0; i < MDSA_MAX_DRIVES; i++) {
if(mdsa_dev.units[i].fileref == uptr->fileref) {
break;
}
}
/* Default for new file is DSK */
uptr->u3 = IMAGE_TYPE_DSK;
if(uptr->capac > 0) {
char *rtn = fgets(header, 4, uptr->fileref);
if((rtn != NULL) && (strncmp(header, "CPT", 3) == 0)) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
mdsa_detach(uptr);
return SCPE_OPENERR;
} else {
uptr->u3 = IMAGE_TYPE_DSK;
}
}
if (uptr->flags & UNIT_MDSA_VERBOSE)
printf("MDSA%d, attached to '%s', type=%s, len=%d\n", i, cptr,
uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",
uptr->capac);
return SCPE_OK;
}
/* Detach routine */
t_stat mdsa_detach(UNIT *uptr)
{
t_stat r;
int8 i;
for(i = 0; i < MDSA_MAX_DRIVES; i++) {
if(mdsa_dev.units[i].fileref == uptr->fileref) {
break;
}
}
if (i >= MDSA_MAX_DRIVES)
return SCPE_ARG;
DBG_PRINT(("Detach MDSA%d\n", i));
r = detach_unit(uptr); /* detach unit */
if(r != SCPE_OK)
return r;
mdsa_dev.units[i].fileref = NULL;
return SCPE_OK;
}
static t_stat mdsa_boot(int32 unitno, DEVICE *dptr)
{
PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
DBG_PRINT(("Booting MDSA Controller at 0x%04x" NLP, pnp->mem_base));
*((int32 *) sim_PC->loc) = pnp->mem_base;
return SCPE_OK;
}
static int32 mdsadev(const int32 Addr, const int32 rw, const int32 data)
{
if(rw == 0) { /* Read */
return(MDSA_Read(Addr));
} else { /* Write */
DBG_PRINT(("MDSA: write attempt at 0x%04x ignored." NLP, Addr));
return (-1);
}
}
/* This ROM image is taken from the ROMs on the single density controller. This is an
older version of the ROM which retries forever. Newer ROMs give up after 10 tries. */
static uint8 mdsa_rom[] = {
0x31,0x14,0x21,0x3E,0x59,0x32,0x00,0x20,0x32,0x03,0x20,0x01,0x01,0x00,0x79,0x16, /* 00 */
0x04,0x59,0x21,0x00,0x20,0xCD,0x1E,0xE9,0xC2,0x00,0xE9,0xC3,0x04,0x20,0xF5,0xE5, /* 10 */
0xD5,0xC5,0x06,0xEB,0x3A,0x90,0xEB,0xE6,0x10,0xC2,0x34,0xE9,0x16,0x32,0xCD,0xD0, /* 20 */
0xE9,0xC3,0x3B,0xE9,0x3A,0x03,0x20,0xB9,0xCA,0x45,0xE9,0x0A,0x79,0x32,0x03,0x20, /* 30 */
0x16,0x0D,0xCD,0xD0,0xE9,0x21,0xFF,0x34,0x09,0xF1,0x57,0x96,0x72,0xCA,0x81,0xE9, /* 40 */
0x21,0x1D,0xEB,0x4F,0xF2,0x65,0xE9,0x2F,0x3C,0x4F,0x3A,0x10,0xEB,0xE6,0x01,0xC2, /* 40 */
0x81,0xE9,0x21,0x1C,0xEB,0x7E,0x3A,0x09,0xEB,0xE3,0xE3,0x3A,0x08,0xEB,0x16,0x02, /* 60 */
0xCD,0xD0,0xE9,0x3A,0x10,0xEB,0xE6,0x01,0xCA,0x7D,0xE9,0x0E,0x01,0x0D,0xC2,0x66, /* 70 */
0xE9,0xC1,0xCD,0xCE,0xE9,0x3A,0x30,0xEB,0xE6,0x0F,0xB8,0xC2,0x82,0xE9,0xE1,0x0D, /* 80 */
0xFA,0x0A,0x20,0xC2,0x07,0x20,0x06,0x46,0x11,0x50,0xEB,0x0E,0x00,0x3A,0x10,0xEB, /* 90 */
0xE6,0x04,0xC2,0xAE,0xE9,0x05,0xC2,0x9D,0xE9,0x3E,0x01,0xC1,0xB7,0xC9,0x41,0x1A, /* A0 */
0x77,0xA8,0x07,0x47,0x23,0x0D,0xC2,0xAF,0xE9,0x1A,0xA8,0xCA,0xC4,0xE9,0x78,0x3E, /* B0 */
0x02,0xC3,0xAB,0xE9,0xF1,0x3D,0xC8,0xF5,0xCD,0xCE,0xE9,0xC3,0x96,0xE9,0x16,0x01, /* C0 */
0x3A,0x14,0xEB,0x3A,0x90,0xEB,0xE6,0x80,0xCA,0xD3,0xE9,0x15,0xC8,0xC3,0xD0,0xE9, /* D0 */
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* E0 */
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* F0 */
};
static void showdata(int32 isRead) {
int32 i;
printf("MDSA: " ADDRESS_FORMAT " %s Sector =" NLP "\t", PCX, isRead ? "Read" : "Write");
for(i=0; i < MDSA_SECTOR_LEN; i++) {
printf("%02X ", sdata.u.data[i]);
if(((i+1) & 0xf) == 0)
printf(NLP "\t");
}
printf(NLP);
}
static int checksum;
static uint32 sec_offset;
static uint32 calculate_mdsa_sec_offset(uint8 track, uint8 sector)
{
return ((track * (MDSA_SECTOR_LEN * MDSA_SECTORS_PER_TRACK)) + (sector * MDSA_SECTOR_LEN));
}
static uint8 MDSA_Read(const uint32 Addr)
{
uint8 cData;
uint8 driveNum;
MDSA_DRIVE_INFO *pDrive;
int32 rtn;
cData = 0;
pDrive = &mdsa_info->drive[mdsa_info->currentDrive];
switch( (Addr & 0x300) >> 8 ) {
case MDSA_READ_ROM0: /* respond to ROM at E800 or E900 */
case MDSA_READ_ROM1:
cData = mdsa_rom[Addr & 0xFF];
break;
case MDSA_WRITE_DATA:
if(mdsa_info->datacount == 0) {
sim_debug(WR_DATA_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" WRITE Start: Drive: %d, Track=%d, Sector=%d\n",
PCX, mdsa_info->currentDrive, pDrive->track, pDrive->sector);
sec_offset = calculate_mdsa_sec_offset(pDrive->track, pDrive->sector);
}
DBG_PRINT(("MDSA: " ADDRESS_FORMAT " WRITE-DATA[offset:%06x+%03x]=%02x" NLP,
PCX, sec_offset, mdsa_info->datacount, Addr & 0xFF));
mdsa_info->datacount++;
if(mdsa_info->datacount < MDSA_RAW_LEN)
sdata.raw[mdsa_info->datacount] = Addr & 0xFF;
if(mdsa_info->datacount == (MDSA_RAW_LEN - 1)) {
sim_debug(WR_DATA_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT " Write Complete\n", PCX);
if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) {
sim_debug(WR_DATA_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" Drive: %d not attached - write ignored.\n", PCX, mdsa_info->currentDrive);
return 0x00;
}
if(mdsa_dev.dctrl & WR_DATA_DETAIL_MSG)
showdata(FALSE);
switch((pDrive->uptr)->u3)
{
case IMAGE_TYPE_DSK:
if(pDrive->uptr->fileref == NULL) {
printf(".fileref is NULL!" NLP);
} else {
if (sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET) == 0) {
sim_fwrite(sdata.u.data, 1, MDSA_SECTOR_LEN, (pDrive->uptr)->fileref);
} else {
printf("%s: sim_fseek error" NLP, __FUNCTION__);
}
}
break;
case IMAGE_TYPE_CPT:
printf("%s: CPT Format not supported" NLP, __FUNCTION__);
break;
default:
printf("%s: Unknown image Format" NLP, __FUNCTION__);
break;
}
}
break;
case MDSA_CTLR_COMMAND:
if (Addr & MDSA_MOTORS_ON) {
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT " CMD=Motors On\n", PCX);
mdsa_info->com_status.mo = 1; /* Turn motors on */
}
/* If read data bit is set, return data from disk and ignore command field */
if (Addr & MDSA_READ_DATA) {
if(mdsa_info->datacount == 0) {
sim_debug(RD_DATA_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" READ Start: Drive: %d, Track=%d, Sector=%d\n",
PCX, mdsa_info->currentDrive, pDrive->track, pDrive->sector);
checksum = 0;
sec_offset = calculate_mdsa_sec_offset(pDrive->track, pDrive->sector);
if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) {
sim_debug(RD_DATA_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" Drive: %d not attached - read ignored.\n",
PCX, mdsa_info->currentDrive);
return 0xe5;
}
switch((pDrive->uptr)->u3) {
case IMAGE_TYPE_DSK:
if(pDrive->uptr->fileref == NULL) {
printf(".fileref is NULL!" NLP);
}
else {
if (sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET) == 0) {
rtn = sim_fread(&sdata.u.data[0], 1, MDSA_SECTOR_LEN,
(pDrive->uptr)->fileref);
if (rtn != MDSA_SECTOR_LEN) {
sim_debug(ERROR_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" READ: sim_fread error.\n", PCX);
}
} else {
sim_debug(ERROR_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" READ: sim_fseek error.\n", PCX);
}
}
break;
case IMAGE_TYPE_CPT:
printf("%s: CPT Format not supported"
NLP, __FUNCTION__);
break;
default:
printf("%s: Unknown image Format"
NLP, __FUNCTION__);
break;
}
if(mdsa_dev.dctrl & RD_DATA_DETAIL_MSG)
showdata(TRUE);
}
if(mdsa_info->datacount < MDSA_SECTOR_LEN) {
cData = sdata.u.data[mdsa_info->datacount];
/* Exclusive OR */
checksum ^= cData;
/* Rotate Left Circular */
checksum = ((checksum << 1) | ((checksum & 0x80) != 0)) & 0xff;
DBG_PRINT(("MDSA: " ADDRESS_FORMAT
" READ-DATA[offset:%06x+%03x]=%02x" NLP,
PCX, sec_offset, mdsa_info->datacount, cData));
}
else { /* checksum */
cData = checksum;
sim_debug(RD_DATA_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" READ-DATA: Checksum is: 0x%02x\n",
PCX, cData);
}
mdsa_info->datacount++;
}
/* Not a read from disk, process the command field */
else {
switch((Addr & 0x1c) >> 2) { /* switch based on 3-bit command field */
case MDSA_CMD_DRIVE: /* select drive in M1, M0 */
driveNum = Addr & 0x03; /* drive number in two lsbits */
if (driveNum == 0) /* force drive numbers to 1-3 */
driveNum++;
mdsa_info->currentDrive = driveNum - 1; /* map NS drive 1-3 to 0-2 */
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Select Drive: Drive=%x\n", PCX, mdsa_info->currentDrive);
pDrive = &mdsa_info->drive[mdsa_info->currentDrive];
mdsa_info->a_status.t0 = (pDrive->track == 0);
break;
case MDSA_CMD_NOP:
pDrive->sector_wait_count++;
switch(pDrive->sector_wait_count) {
case 10:
mdsa_info->com_status.sf = 1; /* new sector */
mdsa_info->com_status.wi = 1; /* in the 96us window at sector start */
mdsa_info->a_status.wr = 0; /* not ready to write */
mdsa_info->a_status.bd = 0; /* not body (not ready to read) */
pDrive->sector_wait_count = 0;
pDrive->sector++;
if(pDrive->sector >= MDSA_SECTORS_PER_TRACK)
pDrive->sector = 0;
break;
case 2: /* end 96us window, set ready to write */
mdsa_info->com_status.wi = 0;
mdsa_info->a_status.wr = 1;
break;
case 4: /* start of body - ready to read */
mdsa_info->a_status.bd = 1;
break;
default:
break;
}
break;
case MDSA_CMD_RESET_SF: /* reset sector flag */
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Reset Sector Flag\n", PCX);
mdsa_info->com_status.sf = 0;
mdsa_info->datacount = 0;
break;
case MDSA_CMD_INTR: /* load interrupt enable/disable */
mdsa_info->int_enable = Addr & 0x01; /* enable bit is M0 */
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Enable/Disable Interrupt: %d\n", PCX, mdsa_info->int_enable);
break;
case MDSA_CMD_STEP: /* load step flip-flop */
mdsa_info->stepState = Addr & 0x01;
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Set step flip-flop to %d\n", PCX, mdsa_info->stepState);
if((mdsa_info->stepState == 1) && stepCleared) {
if(mdsa_info->stepDir == 0) {
sim_debug(SEEK_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" Step out from track %d%s\n", PCX, pDrive->track,
pDrive->track == 0 ? "[Warn: already at 0]" : "");
if(pDrive->track > 0)
pDrive->track--;
}
else {
sim_debug(SEEK_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" Step in from track %d%s\n", PCX, pDrive->track,
pDrive->track == (MDSA_TRACKS - 1) ? "[Warn: already at highest track]" : "");
if(pDrive->track < (MDSA_TRACKS - 1))
pDrive->track++;
}
}
stepCleared = (mdsa_info->stepState == 0);
mdsa_info->a_status.t0 = (pDrive->track == 0);
break;
case MDSA_CMD_STEP_DIR: /* load step direction flip-flop*/
mdsa_info->stepDir = Addr & 0x01; /* direction is in M0 */
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Step direction: %s\n", PCX, mdsa_info->stepDir == 1 ? "In" : "Out");
break;
case MDSA_CMD_BEGIN_WR: /* begin write */
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Begin Write\n", PCX);
break;
case MDSA_CMD_RESET: /* reset controller */
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" CMD=Reset Controller\n", PCX);
mdsa_info->com_status.mo = 0; /* Turn motors off */
break;
default:
sim_debug(CMD_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" Unsupported CMD=0x%x\n", PCX, Addr & 0x0F);
break;
}
/* Return status register A or B based on the B Status bit in Addr */
cData = (mdsa_info->com_status.sf & 1) << 7; /* form common status bits */
cData |= (mdsa_info->com_status.wi & 1) << 6;
cData |= (mdsa_info->com_status.mo & 1) << 4;
mdsa_info->b_status.sc = pDrive->sector;
if (Addr & MDSA_B_STATUS) { /* return B status register */
cData |= (mdsa_info->b_status.sc & 0x0f);
sim_debug(STATUS_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" B-Status = <%s %s %s %i>\n", PCX,
cData & MDSA_B_SF ? "SF" : " ",
cData & MDSA_B_WI ? "WI" : " ",
cData & MDSA_B_MO ? "MO" : " ",
cData & MDSA_B_SC);
}
else { /* return A status register */
cData |= (mdsa_info->a_status.wr & 1) << 3;
cData |= (mdsa_info->a_status.bd & 1) << 2;
cData |= (mdsa_info->a_status.wp & 1) << 1;
cData |= (mdsa_info->a_status.t0 & 1);
sim_debug(STATUS_MSG, &mdsa_dev, "MDSA: " ADDRESS_FORMAT
" A-Status = <%s %s %s %s %s %s %s>\n",
PCX,
cData & MDSA_A_SF ? "SF" : " ",
cData & MDSA_A_WI ? "WI" : " ",
cData & MDSA_A_MO ? "MO" : " ",
cData & MDSA_A_WR ? "WR" : " ",
cData & MDSA_A_BD ? "BD" : " ",
cData & MDSA_A_WP ? "WP" : " ",
cData & MDSA_A_T0 ? "T0" : " ");
}
}
}
return (cData);
}