AltairZ80: Add MDS-AD support for single-density

The North Star MDS-AD disk controller supports both single- and
double-density operation.  While mixed-density is supported by the
controller, it is not supported by AltairZ80 due to a limitation of the
.nsi image file format.  The .nsi image file format requires all sectors
to be of the same density.
This commit is contained in:
Howard M. Harte 2021-02-15 13:26:28 -08:00
parent f0dd8184d8
commit 6c72231177

View file

@ -31,7 +31,8 @@
* * * *
* Module Description: * * Module Description: *
* Northstar MDS-AD Disk Controller module for SIMH * * Northstar MDS-AD Disk Controller module for SIMH *
* Only Double-Density is supported for now. * * Single- and Double-density disks are supported, but the entire disk *
* must be the same density. *
* * * *
*************************************************************************/ *************************************************************************/
@ -56,6 +57,7 @@
#define RD_DATA_DETAIL_MSG (1 << 7) #define RD_DATA_DETAIL_MSG (1 << 7)
#define WR_DATA_DETAIL_MSG (1 << 8) #define WR_DATA_DETAIL_MSG (1 << 8)
extern uint32 PCX; extern uint32 PCX;
extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc); 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 t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
@ -63,19 +65,37 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ
int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap); int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
#define MDSAD_MAX_DRIVES 4 #define MDSAD_MAX_DRIVES 4
#define MDSAD_SECTOR_LEN 512 #define MDSAD_SECTOR_LEN_DD 512
#define MDSAD_SECTOR_LEN_SD 256
#define MDSAD_SECTORS_PER_TRACK 10 #define MDSAD_SECTORS_PER_TRACK 10
#define MDSAD_TRACKS 35 #define MDSAD_TRACKS 35
#define MDSAD_RAW_LEN (32 + 2 + MDSAD_SECTOR_LEN + 1) #define MDSAD_ZEROS_LEN_DD 32
#define MDSAD_ZEROS_LEN_SD 16
#define MDSAD_SYNC_LEN_DD 2
#define MDSAD_SYNC_LEN_SD 1
#define MDSAD_CHECKSUM_LEN 1
#define MDSAD_RAW_LEN_DD (MDSAD_ZEROS_LEN_DD + MDSAD_SYNC_LEN_DD + MDSAD_SECTOR_LEN_DD + MDSAD_CHECKSUM_LEN)
#define MDSAD_RAW_LEN_SD (MDSAD_ZEROS_LEN_SD + MDSAD_SYNC_LEN_SD + MDSAD_SECTOR_LEN_SD + MDSAD_CHECKSUM_LEN)
#define IS_DOUBLE_DENSITY (pDrive->sector_len == MDSAD_SECTOR_LEN_DD)
#define MDSAD_SECTOR_DATA (IS_DOUBLE_DENSITY ? sdata.u_dd.data : sdata.u_sd.data)
#define MDSAD_RAW_LEN (IS_DOUBLE_DENSITY ? MDSAD_RAW_LEN_DD : MDSAD_RAW_LEN_SD)
#define MDSAD_SECTOR_LEN (pDrive->sector_len)
typedef union { typedef union {
struct { struct {
uint8 zeros[32]; uint8 zeros[MDSAD_ZEROS_LEN_DD];
uint8 sync[2]; uint8 sync[MDSAD_SYNC_LEN_DD];
uint8 data[MDSAD_SECTOR_LEN]; uint8 data[MDSAD_SECTOR_LEN_DD];
uint8 checksum; uint8 checksum;
} u; } u_dd;
uint8 raw[MDSAD_RAW_LEN]; struct {
uint8 zeros[MDSAD_ZEROS_LEN_SD];
uint8 sync[MDSAD_SYNC_LEN_SD];
uint8 data[MDSAD_SECTOR_LEN_SD];
uint8 checksum;
} u_sd;
uint8 raw[MDSAD_RAW_LEN_DD];
} SECTOR_FORMAT; } SECTOR_FORMAT;
@ -85,6 +105,7 @@ typedef struct {
uint8 wp; /* Disk write protected */ uint8 wp; /* Disk write protected */
uint8 sector; /* Current Sector number */ uint8 sector; /* Current Sector number */
uint32 sector_wait_count; uint32 sector_wait_count;
uint16 sector_len;
} MDSAD_DRIVE_INFO; } MDSAD_DRIVE_INFO;
typedef struct { typedef struct {
@ -148,7 +169,7 @@ static SECTOR_FORMAT sdata;
#define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE) #define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE)
#define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */ #define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN_DD) /* Default North Star Disk Capacity */
/* MDS-AD Controller Subcases */ /* MDS-AD Controller Subcases */
#define MDSAD_READ_ROM 0 #define MDSAD_READ_ROM 0
@ -307,10 +328,15 @@ static t_stat mdsad_attach(UNIT *uptr, CONST char *cptr)
for(i = 0; i < MDSAD_MAX_DRIVES; i++) { for(i = 0; i < MDSAD_MAX_DRIVES; i++) {
if(mdsad_dev.units[i].fileref == uptr->fileref) { if(mdsad_dev.units[i].fileref == uptr->fileref) {
mdsad_info->orders.st = 0; /* ensure valid state */
if (uptr->capac > 89600) { /* Double-density */
mdsad_info->drive[i].sector_len = MDSAD_SECTOR_LEN_DD;
} else { /* Single-density */
mdsad_info->drive[i].sector_len = MDSAD_SECTOR_LEN_SD;
}
break; break;
} }
mdsad_info->orders.st = 0; /* ensure valid state */
} }
/* Default for new file is DSK */ /* Default for new file is DSK */
@ -414,9 +440,12 @@ static uint8 mdsad_rom[] = {
static void showdata(int32 isRead) { static void showdata(int32 isRead) {
int32 i; int32 i;
MDSAD_DRIVE_INFO* pDrive;
pDrive = &mdsad_info->drive[mdsad_info->orders.ds];
sim_printf("MDSAD: " ADDRESS_FORMAT " %s Sector =\n\t", PCX, isRead ? "Read" : "Write"); sim_printf("MDSAD: " ADDRESS_FORMAT " %s Sector =\n\t", PCX, isRead ? "Read" : "Write");
for(i=0; i < MDSAD_SECTOR_LEN; i++) { for(i=0; i < MDSAD_SECTOR_LEN; i++) {
sim_printf("%02X ", sdata.u.data[i]); sim_printf("%02X ", MDSAD_SECTOR_DATA);
if(((i+1) & 0xf) == 0) if(((i+1) & 0xf) == 0)
sim_printf("\n\t"); sim_printf("\n\t");
} }
@ -428,9 +457,13 @@ static uint32 sec_offset;
static uint32 calculate_mdsad_sec_offset(uint8 track, uint8 head, uint8 sector) static uint32 calculate_mdsad_sec_offset(uint8 track, uint8 head, uint8 sector)
{ {
if(mdsad_info->orders.ss == 0) { MDSAD_DRIVE_INFO* pDrive;
pDrive = &mdsad_info->drive[mdsad_info->orders.ds];
if(mdsad_info->orders.ss == 0) { /* Side 0 */
return ((track * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) + (sector * MDSAD_SECTOR_LEN)); return ((track * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) + (sector * MDSAD_SECTOR_LEN));
} else { } else { /* Side 1 */
return ((((MDSAD_TRACKS-1) - track) * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) + return ((((MDSAD_TRACKS-1) - track) * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) +
((MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK) * MDSAD_TRACKS) + /* Skip over side 0 */ ((MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK) * MDSAD_TRACKS) + /* Skip over side 0 */
(sector * MDSAD_SECTOR_LEN)); /* Sector offset from beginning of track. */ (sector * MDSAD_SECTOR_LEN)); /* Sector offset from beginning of track. */
@ -454,6 +487,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
break; break;
case MDSAD_WRITE_DATA: case MDSAD_WRITE_DATA:
{ {
pDrive->sector_len = (mdsad_info->orders.dd == 1) ? MDSAD_SECTOR_LEN_DD : MDSAD_SECTOR_LEN_SD;
if(mdsad_info->datacount == 0) { if(mdsad_info->datacount == 0) {
sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
" WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n",
@ -491,7 +525,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
sim_printf(".fileref is NULL!\n"); sim_printf(".fileref is NULL!\n");
} else { } else {
if (sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET) == 0) { if (sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET) == 0) {
sim_fwrite(sdata.u.data, 1, MDSAD_SECTOR_LEN, sim_fwrite(MDSAD_SECTOR_DATA, 1, MDSAD_SECTOR_LEN,
(pDrive->uptr)->fileref); (pDrive->uptr)->fileref);
} else { } else {
sim_printf("%s: sim_fseek error\n", __FUNCTION__); sim_printf("%s: sim_fseek error\n", __FUNCTION__);
@ -514,10 +548,9 @@ static uint8 MDSAD_Read(const uint32 Addr)
mdsad_info->orders.dp = (Addr & 0x20) >> 5; mdsad_info->orders.dp = (Addr & 0x20) >> 5;
mdsad_info->orders.pst = mdsad_info->orders.st; /* save previous state of st */ mdsad_info->orders.pst = mdsad_info->orders.st; /* save previous state of st */
mdsad_info->orders.st = (Addr & 0x10) >> 4; mdsad_info->orders.st = (Addr & 0x10) >> 4;
mdsad_info->orders.ds = (Addr & 0x0F); ds = Addr & 0x0F;
ds = mdsad_info->orders.ds; switch(ds) {
switch(mdsad_info->orders.ds) {
case 0: case 0:
case 1: case 1:
mdsad_info->orders.ds = 0; mdsad_info->orders.ds = 0;
@ -640,8 +673,8 @@ static uint8 MDSAD_Read(const uint32 Addr)
break; break;
} }
/* Always Double-Density for now... */ /* Set density based on sector length. */
mdsad_info->com_status.dd = 1; mdsad_info->com_status.dd = (MDSAD_SECTOR_LEN == MDSAD_SECTOR_LEN_DD) ? 1 : 0;
cData = (mdsad_info->com_status.sf & 1) << 7; cData = (mdsad_info->com_status.sf & 1) << 7;
cData |= (mdsad_info->com_status.ix & 1) << 6; cData |= (mdsad_info->com_status.ix & 1) << 6;
@ -661,7 +694,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
PCX, PCX,
cData & MDSAD_A_SF ? "SF" : " ", cData & MDSAD_A_SF ? "SF" : " ",
cData & MDSAD_A_IX ? "IX" : " ", cData & MDSAD_A_IX ? "IX" : " ",
cData & MDSAD_A_DD ? "DD" : " ", cData & MDSAD_A_DD ? "DD" : "SD",
cData & MDSAD_A_MO ? "MO" : " ", cData & MDSAD_A_MO ? "MO" : " ",
cData & MDSAD_A_WI ? "WI" : " ", cData & MDSAD_A_WI ? "WI" : " ",
cData & MDSAD_A_RE ? "RE" : " ", cData & MDSAD_A_RE ? "RE" : " ",
@ -678,7 +711,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
PCX, PCX,
cData & MDSAD_B_SF ? "SF" : " ", cData & MDSAD_B_SF ? "SF" : " ",
cData & MDSAD_B_IX ? "IX" : " ", cData & MDSAD_B_IX ? "IX" : " ",
cData & MDSAD_B_DD ? "DD" : " ", cData & MDSAD_B_DD ? "DD" : "SD",
cData & MDSAD_B_MO ? "MO" : " ", cData & MDSAD_B_MO ? "MO" : " ",
cData & MDSAD_B_WR ? "WR" : " ", cData & MDSAD_B_WR ? "WR" : " ",
cData & MDSAD_B_SP ? "SP" : " ", cData & MDSAD_B_SP ? "SP" : " ",
@ -692,7 +725,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
PCX, PCX,
cData & MDSAD_C_SF ? "SF" : " ", cData & MDSAD_C_SF ? "SF" : " ",
cData & MDSAD_C_IX ? "IX" : " ", cData & MDSAD_C_IX ? "IX" : " ",
cData & MDSAD_C_DD ? "DD" : " ", cData & MDSAD_C_DD ? "DD" : "SD",
cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_MO ? "MO" : " ",
cData & MDSAD_C_SC); cData & MDSAD_C_SC);
break; break;
@ -729,7 +762,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
} else { } else {
if (sim_fseek((pDrive->uptr)->fileref, if (sim_fseek((pDrive->uptr)->fileref,
sec_offset, SEEK_SET) == 0) { sec_offset, SEEK_SET) == 0) {
rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN, rtn = sim_fread(MDSAD_SECTOR_DATA, 1, MDSAD_SECTOR_LEN,
(pDrive->uptr)->fileref); (pDrive->uptr)->fileref);
if (rtn != MDSAD_SECTOR_LEN) { if (rtn != MDSAD_SECTOR_LEN) {
sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT
@ -753,7 +786,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
} }
if(mdsad_info->datacount < MDSAD_SECTOR_LEN) { if(mdsad_info->datacount < MDSAD_SECTOR_LEN) {
cData = sdata.u.data[mdsad_info->datacount]; cData = MDSAD_SECTOR_DATA[mdsad_info->datacount];
/* Exclusive OR */ /* Exclusive OR */
checksum ^= cData; checksum ^= cData;