diff --git a/3B2/3b2_cpu.c b/3B2/3b2_cpu.c
index 5a095a6c..dc9f1e5b 100644
--- a/3B2/3b2_cpu.c
+++ b/3B2/3b2_cpu.c
@@ -355,11 +355,15 @@ static const char *att3b2_clock_precalibrate_commands[] = {
MTAB cpu_mod[] = {
#if defined(REV2)
- { UNIT_MSIZE, (1u << 20), NULL, "1M",
+ { UNIT_MSIZE, MSIZ_512K, NULL, "512K",
+ &cpu_set_size, NULL, NULL, "Set Memory to 512K bytes" },
+ { UNIT_MSIZE, MSIZ_1M, NULL, "1M",
&cpu_set_size, NULL, NULL, "Set Memory to 1M bytes" },
- { UNIT_MSIZE, (1u << 21), NULL, "2M",
+ { UNIT_MSIZE, MSIZ_2M, NULL, "2M",
&cpu_set_size, NULL, NULL, "Set Memory to 2M bytes" },
- { UNIT_MSIZE, (1u << 22), NULL, "4M",
+ { UNIT_MSIZE, MSIZ_3M, NULL, "3M",
+ &cpu_set_size, NULL, NULL, "Set Memory to 3M bytes" },
+ { UNIT_MSIZE, MSIZ_4M, NULL, "4M",
&cpu_set_size, NULL, NULL, "Set Memory to 4M bytes" },
#endif
#if defined(REV3)
diff --git a/3B2/3b2_ctc.c b/3B2/3b2_ctc.c
index 657e427c..4a247ccc 100644
--- a/3B2/3b2_ctc.c
+++ b/3B2/3b2_ctc.c
@@ -52,15 +52,18 @@
#define DELAY_UNK 1000
#define DELAY_CATCHUP 10000
-#define CTC_DIAG_CRC1 0xa4a5752f
-#define CTC_DIAG_CRC2 0xd3d20eb3
-#define CTC_DIAG_CRC3 0x0f387ce3 /* Used by SVR 2.0.5 */
-
#define TAPE_DEV 0 /* CTAPE device */
#define XMF_DEV 1 /* XM Floppy device */
#define VTOC_BLOCK 0
+static uint32 diag_crc[] = {
+ 0xa4a5752f,
+ 0xd3d20eb3,
+ 0x668e4b3e, /* Used by SVR 3.1 */
+ 0x0f387ce3 /* Used by SVR 2.0.5 */
+};
+
static uint8 int_slot; /* Interrupting card ID */
static uint8 int_subdev; /* Interrupting subdevice */
static t_bool ctc_conf = FALSE; /* Has a CTC card been configured? */
@@ -299,14 +302,17 @@ static void ctc_cmd(uint8 slot,
/* If the currently running program is a diagnostic program,
* we are expected to write results into memory at address
* 0x200f000 */
- if (ctc_crc == CTC_DIAG_CRC1 ||
- ctc_crc == CTC_DIAG_CRC2 ||
- ctc_crc == CTC_DIAG_CRC3) {
- pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */
- pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */
- pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */
- pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */
- pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */
+ for (i = 0; i < (sizeof(diag_crc) / sizeof(diag_crc[0])); i++) {
+ if (ctc_crc == diag_crc[i]) {
+ sim_debug(TRACE_DBG, &ctc_dev,
+ "[ctc_cmd] CIO_FCF found CRC==%08x\n", ctc_crc);
+ pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */
+ pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */
+ pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */
+ pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */
+ pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */
+ break;
+ }
}
/* An interesting (?) side-effect of FORCE FUNCTION CALL is
diff --git a/3B2/3b2_defs.h b/3B2/3b2_defs.h
index bad3923a..8306f561 100644
--- a/3B2/3b2_defs.h
+++ b/3B2/3b2_defs.h
@@ -97,6 +97,7 @@
#define MSIZ_512K 0x80000
#define MSIZ_1M 0x100000
#define MSIZ_2M 0x200000
+#define MSIZ_3M 0x300000
#define MSIZ_4M 0x400000
#define MSIZ_8M 0x800000
#define MSIZ_16M 0x1000000
@@ -146,6 +147,7 @@ extern DEVICE cpu_dev;
extern DEVICE csr_dev;
extern DEVICE ctc_dev;
extern DEVICE dmac_dev;
+extern DEVICE ha_dev;
extern DEVICE id_dev;
extern DEVICE if_dev;
extern DEVICE iu_timer_dev;
@@ -161,7 +163,6 @@ extern DEVICE tto_dev;
extern DEVICE lpt_dev;
#if defined(REV3)
extern DEVICE flt_dev;
-extern DEVICE ha_dev;
#endif /* defined(REV3) */
#endif /* _3B2_DEFS_H_ */
diff --git a/3B2/3b2_id.c b/3B2/3b2_id.c
index 3b83d96a..00443082 100644
--- a/3B2/3b2_id.c
+++ b/3B2/3b2_id.c
@@ -48,71 +48,58 @@
#include "3b2_cpu.h"
-#define ID_SEEK_WAIT 50
-#define ID_SEEK_BASE 700
-#define ID_RECAL_WAIT 6000
-#define ID_RW_WAIT 1000
-#define ID_SUS_WAIT 200
-#define ID_SPEC_WAIT 1250
-#define ID_SIS_WAIT 142
-#define ID_CMD_WAIT 140
+#define ID_STEP_WAIT 4000 /* Delay per track step */
+#define ID_STEP_MIN 10000 /* Minimum delay for RECAL/SEEK command */
+#define ID_RW_WAIT 5000
+#define ID_SUS_WAIT 1000
+#define ID_SPEC_WAIT 1000
+#define ID_SIS_WAIT 1000
+#define ID_CMD_WAIT 2000
+
+#define POLLING(id) ((id_dtlh & ID_DTLH_POLL) == 0)
/* Static function declarations */
static SIM_INLINE t_lba id_lba(uint16 cyl, uint8 head, uint8 sec);
-/* Data FIFO pointer - Read */
-uint8 id_dpr = 0;
-/* Data FIFO pointer - Write */
-uint8 id_dpw = 0;
-/* Controller Status Register */
-uint8 id_status = 0;
-/* Unit Interrupt Status */
-uint8 id_int_status = 0;
-/* Last command received */
-uint8 id_cmd = 0;
/* DMAC request */
-t_bool id_drq = FALSE;
+t_bool id_drq = FALSE;
+
+struct id_state id_state[ID_NUM_UNITS] = {0};
+
+/* Enable support for disks with > 1024 cylinders */
+static t_bool id_large = FALSE;
+/* Data FIFO pointer - Read */
+static uint8 id_dpr = 0;
+/* Data FIFO pointer - Write */
+static uint8 id_dpw = 0;
+/* Controller Status Register */
+static uint8 id_status = 0;
+/* Unit Interrupt Status */
+static uint8 id_int_status = 0;
+/* Last command received */
+static uint8 id_cmd = 0;
/* 8-byte FIFO */
-uint8 id_data[ID_FIFO_LEN] = {0};
+static uint8 id_data[ID_FIFO_LEN] = {0};
/* SRQM bit */
-t_bool id_srqm = FALSE;
+static t_bool id_srqm = FALSE;
/* The logical unit number (0-1) */
-uint8 id_unit_num = 0;
+static uint8 id_unit_num = 0;
/* The physical unit number (0-3) */
-uint8 id_ua = 0;
-/* Cylinder the drive is positioned on */
-uint16 id_cyl[ID_NUM_UNITS] = {0};
-/* Ending Track Number (from Specify) */
-uint8 id_etn = 0;
-/* Ending Sector Number (from Specify) */
-uint8 id_esn = 0;
-/* DTLH word (from Specify) */
-uint8 id_dtlh = 0;
-/* Physical sector number */
-uint8 id_psn = 0;
-/* Physical head number */
-uint8 id_phn = 0;
-/* Logical cylinder number, high byte */
-uint8 id_lcnh = 0;
-/* Logical cylinder number, low byte */
-uint8 id_lcnl = 0;
-/* Logical head number */
-uint8 id_lhn = 0;
-/* Logical sector number */
-uint8 id_lsn = 0;
-/* Number of sectors to transfer, decremented after each sector */
-uint8 id_scnt = 0;
-/* Whether we are using polling mode or not */
-t_bool id_polling = FALSE;
+static uint8 id_ua = 0;
+/* Whether we are using buffered SEEK/RECAL or not */
+static t_bool id_buffered = FALSE;
/* Sector buffer */
-uint8 id_buf[ID_SEC_SIZE];
+static uint8 id_buf[ID_SEC_SIZE];
/* Buffer pointer */
-size_t id_buf_ptr = 0;
+static size_t id_buf_ptr = 0;
-uint8 id_idfield[ID_IDFIELD_LEN];
-uint8 id_idfield_ptr = 0;
+/* SPECIFY parameters */
+static uint8 id_esn;
+static uint8 id_etn;
+static uint8 id_dtlh;
-int8 id_seek_state[ID_NUM_UNITS] = {ID_SEEK_NONE};
+static uint8 id_idfield[ID_IDFIELD_LEN];
+static uint8 id_idfield_ptr = 0;
struct id_dtype {
uint8 hd; /* Number of heads */
@@ -125,14 +112,14 @@ static struct id_dtype id_dtab[] = {
ID_DRV(HD72),
ID_DRV(HD72C),
ID_DRV(HD135),
- ID_DRV(HD161),
+ ID_DRV(HD161), /* Only enabled if 'id_large' is set */
{ 0 }
};
UNIT id_unit[] = {
- { UDATA (&id_unit_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+ID_AUTOSIZE+
+ { UDATA (&id_unit_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+DKUF_NOAUTOSIZE+
(ID_HD72_DTYPE << ID_V_DTYPE), ID_DSK_SIZE(HD72)), 0, ID0, 0 },
- { UDATA (&id_unit_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+ID_AUTOSIZE+
+ { UDATA (&id_unit_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+DKUF_NOAUTOSIZE+
(ID_HD72_DTYPE << ID_V_DTYPE), ID_DSK_SIZE(HD72)), 0, ID1, 0 },
{ UDATA (&id_ctlr_svc, 0, 0) },
{ NULL }
@@ -146,15 +133,14 @@ UNIT *id_sel_unit = &id_unit[ID0];
REG id_reg[] = {
{ HRDATAD(CMD, id_cmd, 8, "Command") },
{ HRDATAD(STAT, id_status, 8, "Status") },
- { BRDATAD(CYL, id_cyl, 8, 8, ID_NUM_UNITS, "Track") },
{ NULL }
};
-/* HD161 and HD135 are identical; the difference is only in the
- * software being run on the emulator. SVR 2.0 will support a maximum
- * of 1024 cylinders, so can only format the first 1024 cylinders of
- * the HD135. SVR 3.0+ can support all 1224 cylinders of the HD161. */
MTAB id_mod[] = {
+ { MTAB_XTD|MTAB_VDV, 1, NULL, "LARGE",
+ &id_set_large, NULL, NULL, "Enable support for disks with > 1024 cylinders" },
+ { MTAB_XTD|MTAB_VDV, 0, NULL, "NOLARGE",
+ &id_set_large, NULL, NULL, "Disable support disks with > 1024 cylinders" },
{ MTAB_XTD|MTAB_VUN, ID_HD30_DTYPE, NULL, "HD30",
&id_set_type, NULL, NULL, "Set HD30 Disk Type" },
{ MTAB_XTD|MTAB_VUN, ID_HD72_DTYPE, NULL, "HD72",
@@ -167,10 +153,6 @@ MTAB id_mod[] = {
&id_set_type, NULL, NULL, "Set HD161 Disk Type" },
{ MTAB_XTD|MTAB_VUN, 0, "TYPE", NULL,
NULL, &id_show_type, NULL, "Display device type" },
- { ID_AUTOSIZE, ID_AUTOSIZE, "autosize", "AUTOSIZE",
- NULL, NULL, NULL, "Set type based on file size at attach" },
- { ID_AUTOSIZE, 0, "noautosize", "NOAUTOSIZE",
- NULL, NULL, NULL, "Disable disk autosize on attach" },
{ 0 }
};
@@ -184,15 +166,12 @@ DEVICE id_dev = {
&id_description
};
-/* Function implementation */
-
-#define UPDATE_INT { \
- if ((id_status & (ID_STAT_CEL|ID_STAT_CEH)) || \
- ((id_status & ID_STAT_SRQ) && !id_srqm)) { \
- CPU_SET_INT(INT_DISK); \
- } else { \
- CPU_CLR_INT(INT_DISK); \
- } \
+#define UPDATE_INT { \
+ if ((id_status & ID_IRQ_MASK) && !id_srqm) { \
+ CPU_SET_INT(INT_DISK); \
+ } else { \
+ CPU_CLR_INT(INT_DISK); \
+ } \
}
static SIM_INLINE void id_set_status(uint8 flags)
@@ -264,12 +243,15 @@ t_stat id_ctlr_svc(UNIT *uptr)
*/
t_stat id_unit_svc(UNIT *uptr)
{
- uint8 unit, other, cmd;
+ t_bool recal_error;
+ uint8 unit, other, cmd, end_flags;
unit = uptr->u3; /* The unit number that needs an interrupt */
cmd = uptr->u4; /* The command that caused the activity */
other = unit ^ 1; /* The number of the other unit */
+ recal_error = FALSE;
+
/* If the other unit is active, we cannot interrupt, so we delay
* here */
if (id_unit[other].u4 == ID_CMD_RDATA ||
@@ -279,62 +261,35 @@ t_stat id_unit_svc(UNIT *uptr)
}
id_set_srqm(FALSE);
- id_clr_status(ID_STAT_CB);
- /* Note that we don't set CEH, in case this is a SEEK/RECAL ID_SEEK_1 */
switch (cmd) {
- case ID_CMD_SEEK: /* fall-through */
case ID_CMD_RECAL:
- /* In POLLING mode, SEEK and RECAL actually interrupt twice.
- *
- * 1. Immediately after the correct number of stepping pulses
- * have been issued (SRQ is not set)
- *
- * 2. After the drive has completed seeking and is ready
- * for a new command (SRQ is set)
- */
- if (id_polling) {
- switch (id_seek_state[unit]) {
- case ID_SEEK_0:
- id_set_status(ID_STAT_CEH);
- sim_debug(EXECUTE_MSG, &id_dev,
- "INTR\t\tCOMPLETING Recal/Seek SEEK_0 UNIT %d\n",
- unit);
- id_seek_state[unit] = ID_SEEK_1;
- id_activate(uptr, 8000); /* TODO: Correct Delay based on steps */
- break;
- case ID_SEEK_1:
- sim_debug(EXECUTE_MSG, &id_dev,
- "INTR\t\tCOMPLETING Recal/Seek SEEK_1 UNIT %d\n",
- unit);
- id_seek_state[unit] = ID_SEEK_NONE;
- id_set_status(ID_STAT_SRQ);
- uptr->u4 = 0; /* Only clear out the command on a SEEK_1, never a SEEK_0 */
- if (uptr->flags & UNIT_ATT) {
- id_int_status |= (ID_IST_SEN|unit);
- } else {
- id_int_status |= (ID_IST_NR|unit);
- }
- break;
- default:
- sim_debug(EXECUTE_MSG, &id_dev,
- "INTR\t\tERROR, NOT SEEK_0 OR SEEK_1, UNIT %d\n",
- unit);
- break;
- }
+ /* Recalibrate ends in an error condition if we were never able to
+ reach track 0 */
+ recal_error = (id_state[unit].cyl != 0);
+ /* intentional fall-through */
+ case ID_CMD_SEEK:
+ id_int_status = 0;
+ uptr->u4 = 0;
+
+ sim_debug(EXECUTE_MSG, &id_dev,
+ "INTR\t\tCOMPLETING Recal/Seek UNIT %d (polling=%d)\n",
+ unit, POLLING(unit));
+
+ if (recal_error) {
+ end_flags = 0;
} else {
- sim_debug(EXECUTE_MSG, &id_dev,
- "INTR\t\tCOMPLETING NON-POLLING Recal/Seek UNIT %d\n",
- unit);
- id_set_status(ID_STAT_CEH);
- uptr->u4 = 0;
- if (uptr->flags & UNIT_ATT) {
- id_int_status |= (ID_IST_SEN|unit);
- } else {
- id_int_status |= (ID_IST_NR|unit);
- }
+ end_flags = POLLING(unit) ? ID_STAT_SRQ : ID_STAT_CEH;
}
+ if (uptr->flags & UNIT_ATT) {
+ id_set_status(end_flags);
+ id_int_status |= (ID_IST_SEN|unit);
+ } else {
+ id_int_status |= (ID_IST_NR|unit);
+ }
+
+ id_data[0] = id_int_status;
break;
case ID_CMD_SUS:
sim_debug(EXECUTE_MSG, &id_dev,
@@ -349,7 +304,7 @@ t_stat id_unit_svc(UNIT *uptr)
} else {
/* Put Unit Status into byte 0 */
id_data[0] = (ID_UST_DSEL|ID_UST_SCL|ID_UST_RDY);
- if (id_cyl[unit] == 0) {
+ if (id_state[unit].cyl == 0) {
id_data[0] |= ID_UST_TK0;
}
}
@@ -363,6 +318,23 @@ t_stat id_unit_svc(UNIT *uptr)
break;
}
+ /* In all conditions except on a RECALIBRATE failure, CB is cleared */
+ if (!recal_error) {
+ id_clr_status(ID_STAT_CB);
+ }
+
+ return SCPE_OK;
+}
+
+t_stat id_set_large(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ id_large = (t_bool)val;
+
+ if (!id_large && (ID_GET_DTYPE(id_unit[0].flags) > ID_HD135_DTYPE ||
+ ID_GET_DTYPE(id_unit[1].flags) > ID_HD135_DTYPE)) {
+ return sim_messagef(SCPE_OK, "Large disk support disabled, but at least one attached disk is large!\n");
+ }
+
return SCPE_OK;
}
@@ -379,12 +351,22 @@ t_stat id_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
uptr->flags = (uptr->flags & ~ID_DTYPE) | (val << ID_V_DTYPE);
uptr->capac = (t_addr)id_dtab[val].capac;
+ /*
+ * Warn the user after setting the type, so we can guard against accidentally
+ * attaching to a disk we can't use.
+ */
+ if (val == ID_HD161_DTYPE && !id_large) {
+ return sim_messagef(SCPE_OK, "HD161 disks can only be used if large disk support is enabled (SET IDISK LARGE)\n");
+ }
+
return SCPE_OK;
}
t_stat id_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
- fprintf (st, "%s", id_dtab[ID_GET_DTYPE(uptr->flags)].name);
+ fprintf(st, "%s%s",
+ id_dtab[ID_GET_DTYPE(uptr->flags)].name,
+ id_large ? " (Large Disk Support Enabled)" : "");
return SCPE_OK;
}
@@ -396,10 +378,12 @@ t_stat id_reset(DEVICE *dptr)
t_stat id_attach(UNIT *uptr, CONST char *cptr)
{
- static const char *drives[] = {"HD30", "HD72", "HD72C", "HD135", "HD161", NULL};
- return sim_disk_attach_ex(uptr, cptr, 512, 1, TRUE, 0, id_dtab[ID_GET_DTYPE(uptr->flags)].name,
- 0, 0, (uptr->flags & ID_AUTOSIZE) ? drives : NULL);
+ if (ID_GET_DTYPE(uptr->flags) == ID_HD161_DTYPE && !id_large) {
+ return sim_messagef(SCPE_ARG, "HD161 disks can only be used if large disk support is enabled (SET IDISK LARGE)\n");
+ }
+
+ return sim_disk_attach_ex(uptr, cptr, 512, 1, TRUE, 0, id_dtab[ID_GET_DTYPE(uptr->flags)].name, 0, 0, NULL);
}
t_stat id_detach(UNIT *uptr)
@@ -423,29 +407,33 @@ static t_lba id_lba(uint16 cyl, uint8 head, uint8 sec)
* with the correct return parameters. */
static void SIM_INLINE id_end_rw(uint8 est)
{
+ uint8 id = id_sel_unit->u3;
+
id_clear_fifo();
id_data[0] = est;
- id_data[1] = id_phn;
- id_data[2] = ~(id_lcnh);
- id_data[3] = id_lcnl;
- id_data[4] = id_lhn;
- id_data[5] = id_lsn;
- id_data[6] = id_scnt;
+ id_data[1] = id_state[id].phn;
+ id_data[2] = ~(id_state[id].lcnh);
+ id_data[3] = id_state[id].lcnl;
+ id_data[4] = id_state[id].lhn;
+ id_data[5] = id_state[id].lsn;
+ id_data[6] = id_state[id].scnt;
}
/* The controller wraps id_lsn, id_lhn, and id_lcnl on each sector
* read, so that they point to the next C/H/S */
static void SIM_INLINE id_update_chs()
{
- if (id_lsn++ >= id_esn) {
- id_lsn = 0;
- if (id_lhn++ >= id_etn) {
- id_lhn = 0;
- if (id_lcnl == 0xff) {
- id_lcnl = 0;
- id_lcnh++;
+ uint8 id = id_sel_unit->u3;
+
+ if (id_state[id].lsn++ >= id_esn) {
+ id_state[id].lsn = 0;
+ if (id_state[id].lhn++ >= id_etn) {
+ id_state[id].lhn = 0;
+ if (id_state[id].lcnl == 0xff) {
+ id_state[id].lcnl = 0;
+ id_state[id].lcnh++;
} else {
- id_lcnl++;
+ id_state[id].lcnl++;
}
}
}
@@ -453,12 +441,13 @@ static void SIM_INLINE id_update_chs()
uint32 id_read(uint32 pa, size_t size)
{
- uint8 reg;
+ uint8 reg, id;
uint16 cyl;
t_lba lba;
uint32 data;
t_seccnt sectsread;
+ id = id_sel_unit->u3;
reg = (uint8) (pa - IDBASE);
switch(reg) {
@@ -482,7 +471,7 @@ uint32 id_read(uint32 pa, size_t size)
if (CMD_NUM == ID_CMD_RDATA) {
/* If we're still in DRQ but we've read all our sectors,
* that's an error state. */
- if (id_scnt == 0) {
+ if (id_state[id].scnt == 0) {
sim_debug(READ_MSG, &id_dev,
"ERROR\tid_scnt = 0 but still in dma\n");
id_end_rw(ID_EST_OVR);
@@ -493,9 +482,9 @@ uint32 id_read(uint32 pa, size_t size)
if (id_buf_ptr == 0 || id_buf_ptr >= ID_SEC_SIZE) {
/* It's time to read a new sector into our sector buf */
id_buf_ptr = 0;
- cyl = (uint16) (((uint16)id_lcnh << 8)|(uint16)id_lcnl);
- id_cyl[id_unit_num] = cyl;
- lba = id_lba(cyl, id_lhn, id_lsn);
+ cyl = (uint16) (((uint16)id_state[id].lcnh << 8)|(uint16)id_state[id].lcnl);
+ id_state[id_unit_num].cyl = cyl;
+ lba = id_lba(cyl, id_state[id].lhn, id_state[id].lsn);
if (sim_disk_rdsect(id_sel_unit, lba, id_buf, §sread, 1) == SCPE_OK) {
if (sectsread !=1) {
sim_debug(READ_MSG, &id_dev,
@@ -517,17 +506,17 @@ uint32 id_read(uint32 pa, size_t size)
/* Done with this current sector, update id_scnt */
if (id_buf_ptr >= ID_SEC_SIZE) {
- if (--id_scnt == 0) {
+ if (--id_state[id].scnt == 0) {
id_end_rw(0);
}
}
} else if (CMD_NUM == ID_CMD_RID) {
/* We have to return the ID bytes for the current C/H/S */
if (id_idfield_ptr == 0 || id_idfield_ptr >= ID_IDFIELD_LEN) {
- id_idfield[0] = ~(id_lcnh);
- id_idfield[1] = id_lcnl;
- id_idfield[2] = id_lhn;
- id_idfield[3] = id_lsn;
+ id_idfield[0] = ~(id_state[id].lcnh);
+ id_idfield[1] = id_state[id].lcnl;
+ id_idfield[2] = id_state[id].lhn;
+ id_idfield[3] = id_state[id].lsn;
id_idfield_ptr = 0;
}
@@ -537,14 +526,14 @@ uint32 id_read(uint32 pa, size_t size)
data);
if (id_idfield_ptr >= ID_IDFIELD_LEN) {
- if (id_scnt-- > 0) {
+ if (id_state[id].scnt-- > 0) {
/* Another sector to ID */
id_idfield_ptr = 0;
} else {
/* All done, set return codes */
id_clear_fifo();
id_data[0] = 0;
- id_data[1] = id_scnt;
+ id_data[1] = id_state[id].scnt;
}
}
} else {
@@ -584,12 +573,13 @@ uint32 id_read(uint32 pa, size_t size)
void id_write(uint32 pa, uint32 val, size_t size)
{
- uint8 reg;
+ uint8 reg, id;
uint16 cyl;
t_lba lba;
t_seccnt sectswritten;
reg = (uint8) (pa - IDBASE);
+ id = id_sel_unit->u3;
switch(reg) {
case ID_DATA_REG:
@@ -599,7 +589,7 @@ void id_write(uint32 pa, uint32 val, size_t size)
if (id_drq) {
/* If we're still in DRQ but we've written all our sectors,
* that's an error state. */
- if (id_scnt == 0) {
+ if (id_state[id].scnt == 0) {
sim_debug(WRITE_MSG, &id_dev,
"ERROR\tid_scnt = 0 but still in dma\n");
id_end_rw(ID_EST_OVR);
@@ -623,9 +613,9 @@ void id_write(uint32 pa, uint32 val, size_t size)
if (id_buf_ptr >= ID_SEC_SIZE) {
/* It's time to start the next sector, and flush the old. */
id_buf_ptr = 0;
- cyl = (uint16) (((uint16) id_lcnh << 8)|(uint16)id_lcnl);
- id_cyl[id_unit_num] = cyl;
- lba = id_lba(cyl, id_lhn, id_lsn);
+ cyl = (uint16) (((uint16) id_state[id].lcnh << 8)|(uint16)id_state[id].lcnl);
+ id_state[id].cyl = cyl;
+ lba = id_lba(cyl, id_state[id].lhn, id_state[id].lsn);
if (sim_disk_wrsect(id_sel_unit, lba, id_buf, §swritten, 1) == SCPE_OK) {
if (sectswritten !=1) {
sim_debug(WRITE_MSG, &id_dev,
@@ -633,7 +623,7 @@ void id_write(uint32 pa, uint32 val, size_t size)
sectswritten);
}
id_update_chs();
- if (--id_scnt == 0) {
+ if (--id_state[id].scnt == 0) {
id_end_rw(0);
}
} else {
@@ -668,7 +658,7 @@ void id_write(uint32 pa, uint32 val, size_t size)
void id_handle_command(uint8 val)
{
- uint8 cmd, aux_cmd, sec, pattern;
+ uint8 cmd, aux_cmd, sec, pattern, id;
uint16 cyl;
uint32 time;
t_lba lba;
@@ -709,8 +699,7 @@ void id_handle_command(uint8 val)
sim_cancel(id_sel_unit);
sim_cancel(id_ctlr_unit);
id_status = 0;
- id_srqm = FALSE;
- UPDATE_INT;
+ id_set_srqm(FALSE);
}
/* Just return early */
@@ -721,7 +710,7 @@ void id_handle_command(uint8 val)
* nothing */
if (id_status & ID_STAT_CB) {
sim_debug(EXECUTE_MSG, &id_dev,
- "!!! Controller Busy. Skipping command byte %02x\n",
+ "Controller Busy. Skipping command byte %02x\n",
val);
return;
}
@@ -733,17 +722,14 @@ void id_handle_command(uint8 val)
id_cmd = val;
cmd = (id_cmd >> 4) & 0xf;
- /* Now that we know it's not an aux command, we can get the unit
- * number. Note that we don't update the unit in the case of three
- * special commands. */
- if (cmd != ID_CMD_SIS && cmd != ID_CMD_SPEC && cmd != ID_CMD_DERR) {
- if ((id_cmd & 3) != id_ua) {
- id_unit_num = id_cmd & 1;
- id_ua = id_cmd & 3;
- id_sel_unit = &id_unit[id_unit_num];
- }
+ if ((id_cmd & 3) != id_ua) {
+ id_unit_num = id_cmd & 1;
+ id_ua = id_cmd & 3;
+ id_sel_unit = &id_unit[id_unit_num];
}
+ id = id_unit_num;
+
/* TODO: Fix this hack */
if (cmd == ID_CMD_SIS || cmd == ID_CMD_SPEC || cmd == ID_CMD_DERR) {
id_ctlr_unit->u4 = cmd;
@@ -768,7 +754,6 @@ void id_handle_command(uint8 val)
id_dtlh = id_data[1];
id_etn = id_data[3];
id_esn = id_data[4];
- id_polling = (id_dtlh & ID_DTLH_POLL) == 0;
id_activate(id_ctlr_unit, ID_SPEC_WAIT);
break;
case ID_CMD_SUS:
@@ -784,48 +769,56 @@ void id_handle_command(uint8 val)
id_activate(id_ctlr_unit, ID_CMD_WAIT);
break;
case ID_CMD_RECAL:
- time = id_cyl[id_unit_num];
- id_cyl[id_unit_num] = 0;
- id_seek_state[id_unit_num] = ID_SEEK_0;
- if (id_polling) {
- sim_debug(WRITE_MSG, &id_dev,
- "COMMAND\t%02x\tRecalibrate - %d - POLLING\n",
- val, id_ua);
- id_activate(id_sel_unit, 1000);
- } else {
- sim_debug(WRITE_MSG, &id_dev,
- "COMMAND\t%02x\tRecalibrate - %d - NORMAL\n",
- val, id_ua);
- id_activate(id_sel_unit, (ID_RECAL_WAIT + (time * ID_SEEK_WAIT)));
+ id_buffered = (val & 0x08) == 0x08;
+ time = MAX(ID_STEP_MIN, id_state[id].cyl * ID_STEP_WAIT);
+
+ sim_debug(WRITE_MSG, &id_dev,
+ "COMMAND\t%02x\tRecalibrate - %d - (buffered=%d, polling=%d, delay=%u)\n",
+ val, id_ua, id_buffered, POLLING(id), time);
+
+ if (POLLING(id)) {
+ id_set_status(ID_STAT_CEH);
}
+
+ /* If large disk support hasn't been enabled, and the starting cylinder we're
+ * recalibrating from is > 1023, we can't reach track 0! */
+ if (!id_large && id_state[id].cyl > 1023) {
+ sim_debug(WRITE_MSG, &id_dev,
+ "WARNING: RECALIBRATE - Starting cylinder %d is > 1023!\n",
+ id_state[id].cyl);
+
+ id_state[id].cyl -= 1023;
+ } else {
+ id_state[id].cyl = 0;
+ }
+
+ id_activate(id_sel_unit, time);
break;
case ID_CMD_SEEK:
- id_lcnh = id_data[0];
- id_lcnl = id_data[1];
- cyl = id_lcnh << 8 | id_lcnl;
- time = (uint32) abs(id_cyl[id_unit_num] - cyl);
- id_cyl[id_unit_num] = cyl;
- id_seek_state[id_unit_num] = ID_SEEK_0;
+ id_buffered = (val & 0x08) == 0x08;
+ id_state[id].lcnh = id_data[0];
+ id_state[id].lcnl = id_data[1];
+ cyl = ((uint16)id_state[id].lcnh) << 8 | (uint16)id_state[id].lcnl;
+ time = MAX(ID_STEP_MIN, ID_STEP_WAIT * (cyl > id_state[id].cyl ? cyl - id_state[id].cyl : id_state[id].cyl - cyl));
- if (id_polling) {
- sim_debug(WRITE_MSG, &id_dev,
- "COMMAND\t%02x\tSeek - %d - POLLING\n",
- val, id_ua);
- id_activate(id_sel_unit, 4000);
- } else {
- sim_debug(WRITE_MSG, &id_dev,
- "COMMAND\t%02x\tSeek - %d - NORMAL\n",
- val, id_ua);
- id_activate(id_sel_unit, ID_SEEK_BASE + (time * ID_SEEK_WAIT));
+ sim_debug(WRITE_MSG, &id_dev,
+ "COMMAND\t%02x\tSeek - %d - CYL=%u BUF=%d POL=%d DELAY=%u\n",
+ val, id_ua, cyl, id_buffered, POLLING(id), time);
+
+ if (POLLING(id)) {
+ id_set_status(ID_STAT_CEH);
}
+
+ id_state[id].cyl = cyl;
+ id_activate(id_sel_unit, time);
break;
case ID_CMD_FMT:
sim_debug(WRITE_MSG, &id_dev,
"COMMAND\t%02x\tFormat - %d\n",
val, id_ua);
- id_phn = id_data[0];
- id_scnt = id_data[1];
+ id_state[id].phn = id_data[0];
+ id_state[id].scnt = id_data[1];
pattern = id_data[2];
/* Format scnt sectors with the given pattern, if attached */
@@ -833,20 +826,20 @@ void id_handle_command(uint8 val)
/* Formatting soft-sectored disks always begins at sector 0 */
sec = 0;
- while (id_scnt-- > 0) {
+ while (id_state[id].scnt-- > 0) {
/* Write one sector of pattern */
for (id_buf_ptr = 0; id_buf_ptr < ID_SEC_SIZE; id_buf_ptr++) {
id_buf[id_buf_ptr] = pattern;
}
- lba = id_lba(id_cyl[id_unit_num], id_phn, sec++);
+ lba = id_lba(id_state[id].cyl, id_state[id].phn, sec++);
if (sim_disk_wrsect(id_sel_unit, lba, id_buf, NULL, 1) == SCPE_OK) {
sim_debug(EXECUTE_MSG, &id_dev,
"FORMAT: PHN=%d SCNT=%d PAT=%02x LBA=%04x\n",
- id_phn, id_scnt, pattern, lba);
+ id_state[id].phn, id_state[id].scnt, pattern, lba);
} else {
sim_debug(EXECUTE_MSG, &id_dev,
"FORMAT FAILED! PHN=%d SCNT=%d PAT=%02x LBA=%04x\n",
- id_phn, id_scnt, pattern, lba);
+ id_state[id].phn, id_state[id].scnt, pattern, lba);
break;
}
}
@@ -857,7 +850,7 @@ void id_handle_command(uint8 val)
id_data[0] = ID_EST_NR;
}
- id_data[1] = id_scnt;
+ id_data[1] = id_state[id].scnt;
id_activate(id_sel_unit, ID_CMD_WAIT);
break;
@@ -877,12 +870,12 @@ void id_handle_command(uint8 val)
id_drq = TRUE;
/* Grab our arguments */
- id_phn = id_data[0];
- id_scnt = id_data[1];
+ id_state[id].phn = id_data[0];
+ id_state[id].scnt = id_data[1];
/* Compute logical values used by ID verification */
- id_lhn = id_phn;
- id_lsn = 0;
+ id_state[id]. lhn = id_state[id].phn;
+ id_state[id].lsn = 0;
} else {
sim_debug(EXECUTE_MSG, &id_dev,
"UNIT %d NOT ATTACHED, CANNOT READ ID.\n",
@@ -897,25 +890,29 @@ void id_handle_command(uint8 val)
id_activate(id_sel_unit, ID_CMD_WAIT);
break;
case ID_CMD_RDATA:
+ /* Grab our arguments */
+ id_state[id].phn = id_data[0];
+ id_state[id].lcnh = ~(id_data[1]);
+ id_state[id].lcnl = id_data[2];
+ id_state[id].lhn = id_data[3];
+ id_state[id].lsn = id_data[4];
+ id_state[id].scnt = id_data[5];
+
sim_debug(WRITE_MSG, &id_dev,
- "COMMAND\t%02x\tRead Data - %d\n",
- val, id_ua);
+ "COMMAND\t%02x\tRead Data - %d - CYL=%u PH=%u LH=%u SEC=%u SCNT=%u\n",
+ val, id_ua,
+ (uint16)id_state[id].lcnh << 8 | (uint16)id_state[id].lcnl,
+ id_data[0], id_data[3], id_data[4], id_data[5]);
+
if (id_sel_unit->flags & UNIT_ATT) {
id_drq = TRUE;
id_buf_ptr = 0;
-
- /* Grab our arguments */
- id_phn = id_data[0];
- id_lcnh = ~(id_data[1]);
- id_lcnl = id_data[2];
- id_lhn = id_data[3];
- id_lsn = id_data[4];
- id_scnt = id_data[5];
} else {
sim_debug(EXECUTE_MSG, &id_dev,
"UNIT %d NOT ATTACHED, CANNOT READ DATA.\n",
id_ua);
}
+
id_activate(id_sel_unit, ID_RW_WAIT);
break;
case ID_CMD_CHECK:
@@ -937,20 +934,23 @@ void id_handle_command(uint8 val)
id_activate(id_sel_unit, ID_CMD_WAIT);
break;
case ID_CMD_WDATA:
+ /* Grab our arguments */
+ id_state[id].phn = id_data[0];
+ id_state[id].lcnh = ~(id_data[1]);
+ id_state[id].lcnl = id_data[2];
+ id_state[id].lhn = id_data[3];
+ id_state[id].lsn = id_data[4];
+ id_state[id].scnt = id_data[5];
+
sim_debug(WRITE_MSG, &id_dev,
- "COMMAND\t%02x\tWrite Data - %d\n",
- val, id_ua);
+ "COMMAND\t%02x\tWrite Data - %d - CYL=%u PH=%u LH=%u SEC=%u SCNT=%u\n",
+ val, id_ua,
+ (uint16)id_state[id].lcnh << 8 | (uint16)id_state[id].lcnl,
+ id_data[0], id_data[3], id_data[4], id_data[5]);
+
if (id_sel_unit->flags & UNIT_ATT) {
id_drq = TRUE;
id_buf_ptr = 0;
-
- /* Grab our arguments */
- id_phn = id_data[0];
- id_lcnh = ~(id_data[1]);
- id_lcnl = id_data[2];
- id_lhn = id_data[3];
- id_lsn = id_data[4];
- id_scnt = id_data[5];
} else {
sim_debug(EXECUTE_MSG, &id_dev,
"UNIT %d NOT ATTACHED, CANNOT WRITE.\n",
@@ -983,8 +983,10 @@ t_stat id_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
fprintf(st, " HD30 30.6 MB 3 697 5 18 512 CDC Wren 94155-36\n");
fprintf(st, " HD72 73.2 MB 5 925 9 18 512 CDC Wren II 94156-86\n");
fprintf(st, " HD72C 72.9 MB 8 754 11 18 512 Fujitsu M2243AS\n");
- fprintf(st, " HD135 135.0 MB 11 1024 15 18 512 Maxtor XT1190 (SVR2)\n");
- fprintf(st, " HD161 161.4 MB 11 1224 15 18 512 Maxtor XT1190 (SVR3+)\n\n");
+ fprintf(st, " HD135 135.0 MB 11 1024 15 18 512 Maxtor XT-2190\n");
+ if (id_large) {
+ fprintf(st, " HD161 161.4 MB 11 1224 15 18 512 Maxtor XT-2190\n\n");
+ }
fprintf(st, "The drive ID and geometry values are used when low-level formatting a\n");
fprintf(st, "drive using the AT&T 'idtools' utility.\n");
diff --git a/3B2/3b2_id.h b/3B2/3b2_id.h
index 81f78e31..3eabbc70 100644
--- a/3B2/3b2_id.h
+++ b/3B2/3b2_id.h
@@ -69,6 +69,7 @@
#define ID_STAT_CEL 0x20
#define ID_STAT_CEH 0x40
#define ID_STAT_CB 0x80
+#define ID_IRQ_MASK (ID_STAT_CEL|ID_STAT_CEH|ID_STAT_SRQ)
#define ID_IST_SEN 0x80 /* Seek End */
#define ID_IST_RC 0x40 /* Ready Change */
@@ -105,7 +106,7 @@
#define ID_CYL_SIZE ID_SEC_SIZE * ID_SEC_CNT
/* Specific to each drive type */
-#define ID_MAX_DTYPE 3
+#define ID_MAX_DTYPE 4
#define ID_HD30_DTYPE 0
#define ID_HD30_CYL 697
@@ -122,24 +123,19 @@
#define ID_HD72C_HEADS 11
#define ID_HD72C_LBN 149292
-/* The HD135 is actually just an HD161 with only 1024 cylinders
- * formatted. This is a software limitation, not hardware. */
-
#define ID_HD135_DTYPE 3
-#define ID_HD135_CYL 1224
+#define ID_HD135_CYL 1024
#define ID_HD135_HEADS 15
-#define ID_HD135_LBN 330480
+#define ID_HD135_LBN 276480
-#define ID_HD161_DTYPE 3
+#define ID_HD161_DTYPE 4
#define ID_HD161_CYL 1224
#define ID_HD161_HEADS 15
#define ID_HD161_LBN 330480
#define ID_V_DTYPE (DKUF_V_UF + 0)
-#define ID_M_DTYPE 3
+#define ID_M_DTYPE 7
#define ID_DTYPE (ID_M_DTYPE << ID_V_DTYPE)
-#define ID_V_AUTOSIZE (ID_V_DTYPE + 2)
-#define ID_AUTOSIZE (1 << ID_V_AUTOSIZE)
#define ID_GET_DTYPE(x) (((x) >> ID_V_DTYPE) & ID_M_DTYPE)
#define ID_DRV(d) { ID_##d##_HEADS, ID_##d##_LBN, #d }
@@ -156,11 +152,22 @@
#define CMD_NUM ((id_cmd >> 4) & 0xf)
+struct id_state {
+ uint16 cyl; /* Cylinder the drive is positioned on */
+ uint8 phn; /* Physical head number */
+ uint8 lhn; /* Logical head number */
+ uint8 lsn; /* Logical sector number */
+ uint8 scnt; /* Sector count */
+ uint8 lcnh; /* Logical Cylinder Number, high byte */
+ uint8 lcnl; /* Logical Cylinder Number, low byte */
+};
+
/* Function prototypes */
t_stat id_ctlr_svc(UNIT *uptr);
t_stat id_unit_svc(UNIT *uptr);
t_stat id_reset(DEVICE *dptr);
+t_stat id_set_large(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat id_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat id_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat id_attach(UNIT *uptr, CONST char *cptr);
diff --git a/3B2/3b2_io.c b/3B2/3b2_io.c
index 80d2df51..326770b7 100644
--- a/3B2/3b2_io.c
+++ b/3B2/3b2_io.c
@@ -461,22 +461,45 @@ uint32 io_read(uint32 pa, size_t size)
}
#else
if (pa == MEMSIZE_REG) {
+ /* The memsize register at 0x4c003 maps its lower two bits to the
+ * SIZE64K and ONEBANK signals from the first DPDRAM slot. This
+ * determines what kind of memory module is installed in that
+ * slot.
+ *
+ * SIZE64K | ONEBANK | Module Size
+ * --------+---------+----------
+ * 0 | 0 | 256 KB
+ * 0 | 1 | 1 MB
+ * 1 | 1 | 2 MB
+ *
+ * After determining the size of the module in slot 1, the firmware
+ * then tries to write to higher memory addresses to see if more
+ * than one memory module is installed.
+ *
+ * In a real 3B2/300, /310, or /400, if two memory modules are
+ * installed, the module in slot 2 should be the same size or
+ * smaller than the module in slot 1, otherwise it won't all get
+ * used. For example, if a 1 MB module is in slot 1 and a 2 MB
+ * card is in slot 2, only 1 MB of the second module would be
+ * used!
+ *
+ * Since the 3B2 simulator doesn't let you do this, we just assume
+ * the configuration of the two modules based on the total memory
+ * configured.
+ *
+ * N.B.: A 512 KB configuration was only supported through SVR 2.
+ * A single 256 KB memory module was never supported.
+ */
- /* The following values map to memory sizes:
- 0x00: 512KB ( 524,288 B)
- 0x01: 2MB (2,097,152 B)
- 0x02: 1MB (1,048,576 B)
- 0x03: 4MB (4,194,304 B)
- */
switch(MEM_SIZE) {
- case 0x80000: /* 512KB */
+ case MSIZ_512K: /* slot 1=256 KB, slot 2=256 KB */
return 0;
- case 0x100000: /* 1MB */
- return 2;
- case 0x200000: /* 2MB */
- return 1;
- case 0x400000: /* 4MB */
- return 3;
+ case MSIZ_1M: /* slot 1=1 MB, slot 2=empty */
+ return 0x1;
+ case MSIZ_2M: /* slot 1=2 MB, slot 2=empty */
+ case MSIZ_3M: /* slot 1=2 MB, slot 2=1 MB */
+ case MSIZ_4M: /* slot 1=2 MB, slot 2=2 MB */
+ return 0x3;
default:
return 0;
}
diff --git a/3B2/3b2_mau.c b/3B2/3b2_mau.c
index ff88050e..fcac8cda 100644
--- a/3B2/3b2_mau.c
+++ b/3B2/3b2_mau.c
@@ -305,7 +305,7 @@ DEVICE mau_dev = {
NULL, /* attach routine */
NULL, /* detach routine */
NULL, /* context */
-#ifdef REV3
+#if defined(REV3)
DEV_DEBUG, /* Rev 3 flags: Always required */
#else
DEV_DISABLE|DEV_DEBUG, /* Rev 2 flags: Can be disabled */
diff --git a/3B2/3b2_ports.c b/3B2/3b2_ports.c
index 9dd78841..d8e5a9cc 100644
--- a/3B2/3b2_ports.c
+++ b/3B2/3b2_ports.c
@@ -91,17 +91,25 @@
#define DELAY_DEVICE 25
#define DELAY_STD 100
-#define PORTS_DIAG_CRC1 0x7ceec900
-#define PORTS_DIAG_CRC2 0x77a1ea56
-#define PORTS_DIAG_CRC3 0x84cf938b
-#define PORTS_DIAG_CRC4 0x31b32383 /* Used by SVR 2.0.5 */
-#define PORTS_DIAG_CRC5 0x4be7bccc /* Used by SVR 2.0.5 */
-#define PORTS_DIAG_CRC6 0x3197f6dd /* Used by SVR 2.0.5 */
-
#define LN(slot,port) (ports_slot_ln[(slot)] + (port))
#define LSLOT(ln) (ports_ln_slot[ln])
#define LPORT(ln) ((ln) % PORTS_LINES)
+static uint32 diag_crc[] = {
+ 0x7ceec900, /* Used by SVR 3.2 and up */
+ 0x77a1ea56, /* Used by SVR 3.2 and up */
+ 0x84cf938b, /* Used by SVR 3.2 and up */
+ 0xd9d56d23, /* Used by SVR 3.1 */
+ 0x17c6c722, /* Used by SVR 3.1 */
+ 0xeaf367fa, /* Used by SVR 3.1 */
+ 0x5805145e, /* Used by SVR 3.1 */
+ 0x18d72e94, /* Used by SVR 3.1 */
+ 0x3b8706b1, /* Used by SVR 2.0.5 */
+ 0x31b32383, /* Used by SVR 2.0.5 */
+ 0x4be7bccc, /* Used by SVR 2.0.5 */
+ 0x3197f6dd /* Used by SVR 2.0.5 */
+};
+
int8 ports_base_slot; /* First slot in our contiguous block */
uint8 ports_int_slot; /* Interrupting card ID */
uint8 ports_int_subdev; /* Interrupting subdevice */
@@ -367,17 +375,18 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
/* If the currently running program is a diagnostics program,
* we are expected to write results into memory at address
* 0x200f000 */
- if (ports_crc == PORTS_DIAG_CRC1 ||
- ports_crc == PORTS_DIAG_CRC2 ||
- ports_crc == PORTS_DIAG_CRC3 ||
- ports_crc == PORTS_DIAG_CRC4 ||
- ports_crc == PORTS_DIAG_CRC5 ||
- ports_crc == PORTS_DIAG_CRC6) {
- pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */
- pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */
- pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */
- pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */
- pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */
+ for (i = 0 ; i < (sizeof(diag_crc) / sizeof(diag_crc[0])); i++) {
+ if (ports_crc == diag_crc[i]) {
+ sim_debug(TRACE_DBG, &ports_dev,
+ "[ports_cmd] CIO_FCF found CRC==%08x\n",
+ ports_crc);
+ pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */
+ pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */
+ pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */
+ pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */
+ pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */
+ break;
+ }
}
/* An interesting (?) side-effect of FORCE FUNCTION CALL is
diff --git a/3B2/3b2_rev2_mmu.c b/3B2/3b2_rev2_mmu.c
index 88383cb3..e7476fc6 100644
--- a/3B2/3b2_rev2_mmu.c
+++ b/3B2/3b2_rev2_mmu.c
@@ -275,7 +275,7 @@ static SIM_INLINE t_stat mmu_check_perm(uint8 flags, uint8 r_acc)
return SCPE_NXM;
}
return SCPE_OK;
- default:
+ default: /* Read / Write / Execute */
return SCPE_OK;
}
}
@@ -670,14 +670,14 @@ t_stat mmu_decode_paged(uint32 va, uint8 r_acc, t_bool fc,
/* If this is a write, modify the M bit */
if (SHOULD_UPDATE_PD_M_BIT(pd)) {
sim_debug(EXECUTE_MSG, &mmu_dev,
- "Updating M bit in PD\n");
+ "Updating M bit in PD [va=%08x, pd=%08x, r_acc=%d]\n", va, pd, r_acc);
mmu_update_pd(va, PD_LOC(sd1, va), PD_M_MASK);
}
/* Modify the R bit and write it back */
if (SHOULD_UPDATE_PD_R_BIT(pd)) {
sim_debug(EXECUTE_MSG, &mmu_dev,
- "Updating R bit in PD\n");
+ "Updating R bit in PD [va=%08x, pd=%08x, r_acc=%d]\n", va, pd, r_acc);
mmu_update_pd(va, PD_LOC(sd1, va), PD_R_MASK);
}
}
diff --git a/3B2/3b2_rev2_sys.c b/3B2/3b2_rev2_sys.c
index 0ee5b559..03401f7f 100644
--- a/3B2/3b2_rev2_sys.c
+++ b/3B2/3b2_rev2_sys.c
@@ -38,6 +38,7 @@
#include "3b2_iu.h"
#include "3b2_ni.h"
#include "3b2_ports.h"
+#include "3b2_scsi.h"
#include "3b2_mau.h"
#include "3b2_stddev.h"
#include "3b2_timer.h"
@@ -60,6 +61,7 @@ DEVICE *sim_devices[] = {
&if_dev,
&id_dev,
&ports_dev,
+ &ha_dev,
&lpt_dev,
&ctc_dev,
&ni_dev,
@@ -78,6 +80,7 @@ void full_reset()
id_reset(&id_dev);
csr_reset(&csr_dev);
ports_reset(&ports_dev);
+ ha_reset(&ha_dev);
lpt_reset(&lpt_dev);
ctc_reset(&ctc_dev);
ni_reset(&ni_dev);
diff --git a/3B2/3b2_scsi.c b/3B2/3b2_scsi.c
index 622b4c8f..66ff3c40 100644
--- a/3B2/3b2_scsi.c
+++ b/3B2/3b2_scsi.c
@@ -37,9 +37,6 @@
#include "3b2_io.h"
#include "3b2_mem.h"
-#define DIAG_CRC_1 0x271b114c
-#define PUMP_CRC 0x201b3617
-
#define HA_SCSI_ID 0
#define HA_MAXFR (1u << 16)
@@ -48,6 +45,16 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr,
static void ha_build_req(uint8 tc, uint8 subdev, t_bool express);
static void ha_ctrl(uint8 tc);
+static uint32 diag_crc[] = {
+ 0x271b114c, /* BOOT DIAG CRC under SVR 3.2.3 */
+ 0x4bf2592f, /* BOOT DIAG CRC under SVR 3.2 (SCSI HA Utilities 1.0) */
+ 0x23fc023c /* dgmon phase 1 DIAG CRC under Maintenance Utilities 4.0 */
+};
+
+static uint32 pump_crc[] = {
+ 0x6ec6932d, /* SCSI HA Utilities 1.0 pump CRC */
+ 0x201b3617 /* SVR 3.2.3 pump CRC */
+};
HA_STATE ha_state;
SCSI_BUS ha_bus;
@@ -136,7 +143,11 @@ DEVICE ha_dev = {
&ha_attach, /* attach routine */
&ha_detach, /* detach routine */
NULL, /* context */
+#if defined(REV3)
DEV_DEBUG|DEV_DISK|DEV_SECTORS, /* flags */
+#else
+ DEV_DISABLE|DEV_DIS|DEV_DEBUG|DEV_DISK|DEV_SECTORS, /* flags */
+#endif
0, /* debug control flags */
ha_debug, /* debug flag names */
NULL, /* memory size change */
@@ -163,31 +174,7 @@ t_stat ha_reset(DEVICE *dptr)
t_stat r;
ha_state.pump_state = PUMP_NONE;
-
- if (ha_buf == NULL) {
- ha_buf = (uint8 *)calloc(HA_MAXFR, sizeof(uint8));
- }
-
- r = scsi_init(&ha_bus, HA_MAXFR);
-
- if (r != SCPE_OK) {
- return r;
- }
-
- ha_bus.dptr = dptr;
-
- scsi_reset(&ha_bus);
-
- for (t = 0; t < 8; t++) {
- uptr = dptr->units + t;
- if (t == HA_SCSI_ID) {
- uptr->flags = UNIT_DIS;
- }
- scsi_add_unit(&ha_bus, t, uptr);
- dtyp = GET_DTYPE(uptr->flags);
- scsi_set_unit(&ha_bus, uptr, &ha_tab[dtyp]);
- scsi_reset_unit(uptr);
- }
+ ha_crc = 0;
if (dptr->flags & DEV_DIS) {
cio_remove_all(HA_ID);
@@ -195,13 +182,46 @@ t_stat ha_reset(DEVICE *dptr)
return SCPE_OK;
}
+ if (ha_buf == NULL) {
+ ha_buf = (uint8 *)calloc(HA_MAXFR, sizeof(uint8));
+ }
+
if (!ha_conf) {
- r = cio_install(HA_ID, "SCSI", HA_IPL,
- &ha_express, &ha_full, &ha_sysgen, &ha_cio_reset,
- &slot);
+ r = scsi_init(&ha_bus, HA_MAXFR);
+
if (r != SCPE_OK) {
return r;
}
+
+ ha_bus.dptr = dptr;
+
+ scsi_reset(&ha_bus);
+
+ for (t = 0; t < 8; t++) {
+ uptr = dptr->units + t;
+ if (t == HA_SCSI_ID) {
+ uptr->flags = UNIT_DIS;
+ }
+ scsi_add_unit(&ha_bus, t, uptr);
+ dtyp = GET_DTYPE(uptr->flags);
+ scsi_set_unit(&ha_bus, uptr, &ha_tab[dtyp]);
+ scsi_reset_unit(uptr);
+ }
+
+ if (dptr->flags & DEV_DIS) {
+ cio_remove_all(HA_ID);
+ ha_conf = FALSE;
+ return SCPE_OK;
+ }
+
+ r = cio_install(HA_ID, "SCSI", HA_IPL,
+ &ha_express, &ha_full, &ha_sysgen, &ha_cio_reset,
+ &slot);
+
+ if (r != SCPE_OK) {
+ return r;
+ }
+
ha_state.slot = slot;
ha_conf = TRUE;
}
@@ -331,6 +351,7 @@ void ha_sysgen(uint8 slot)
{
uint32 sysgen_p;
uint32 alert_buf_p;
+ uint32 i;
cq_offset = 0;
@@ -355,14 +376,17 @@ void ha_sysgen(uint8 slot)
ha_state.ts[HA_SCSI_ID].rep.op = 0;
ha_state.ts[HA_SCSI_ID].pending = TRUE;
- if (ha_crc == PUMP_CRC) {
- sim_debug(HA_TRACE, &ha_dev,
- "[ha_sysgen] PUMP: NEW STATE = PUMP_SYSGEN\n");
- ha_state.pump_state = PUMP_SYSGEN;
- } else {
- sim_debug(HA_TRACE, &ha_dev,
- "[ha_sysgen] PUMP: NEW STATE = PUMP_NONE\n");
- ha_state.pump_state = PUMP_NONE;
+ ha_state.pump_state = PUMP_NONE;
+
+ for (i = 0; i < sizeof(pump_crc) / sizeof(pump_crc[0]); i++) {
+ if (ha_crc == pump_crc[i]) {
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_sysgen] PUMP: NEW STATE = PUMP_SYSGEN\n");
+
+ ha_state.pump_state = PUMP_SYSGEN;
+
+ break;
+ }
}
sim_activate_abs(cio_unit, 1000);
@@ -396,15 +420,21 @@ void ha_express(uint8 slot)
cio_entry rqe;
uint8 rapp_data[RAPP_LEN] = {0};
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_express] Handling Express Request. pump_state=%d, ha_state.frq=%d, subdev=%02x\n",
+ ha_state.pump_state, ha_state.frq, rqe.subdevice);
+
+ if (ha_state.pump_state == PUMP_SYSGEN) {
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_full] PUMP: NEW STATE = PUMP_COMPLETE\n");
+
+ ha_state.pump_state = PUMP_COMPLETE;
+ }
+
if (ha_state.frq) {
ha_fast_queue_check();
} else {
cio_rexpress(slot, SCQRESIZE, &rqe, rapp_data);
-
- sim_debug(HA_TRACE, &ha_dev,
- "[ha_express] Handling Express Request. subdev=%02x\n",
- rqe.subdevice);
-
ha_cmd(rqe.opcode, rqe.subdevice, rqe.address, rqe.byte_count, TRUE);
}
}
@@ -815,12 +845,18 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres
sim_debug(HA_TRACE, &ha_dev,
"[ha_cmd] SCSI Force Function Call. (CRC=%08x)\n",
ha_crc);
- if (ha_crc == DIAG_CRC_1) {
- pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */
- pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */
- pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */
- pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */
- pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */
+ for (i = 0; i < sizeof(diag_crc) / sizeof(diag_crc[0]); i++) {
+ if (ha_crc == diag_crc[i]) {
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_cmd] Found matching diagnostics CRC at position %d (%08x==%08x).\n",
+ i, ha_crc, diag_crc[i]);
+ pwrite_h(0x200f000, 0x1, BUS_PER); /* Test success */
+ pwrite_h(0x200f002, 0x0, BUS_PER); /* Test Number */
+ pwrite_h(0x200f004, 0x0, BUS_PER); /* Actual */
+ pwrite_h(0x200f006, 0x0, BUS_PER); /* Expected */
+ pwrite_b(0x200f008, 0x1, BUS_PER); /* Success flag again */
+ break;
+ }
}
cio[ha_state.slot].sysgen_s = 0;
@@ -1077,12 +1113,21 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres
tc = HA_SCSI_ID;
ha_cmd_prep(tc, op, subdev, express);
+ if (len > HA_EDT_LEN) {
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_cmd] SCSI DOWNLOAD EDT: Requested to download %d bytes; downloading only %d byte\n",
+ len, HA_EDT_LEN);
+ len = HA_EDT_LEN;
+ }
+
sim_debug(HA_TRACE, &ha_dev,
"[ha_cmd] SCSI DOWNLOAD EDT (%d bytes to address %08x)\n",
len, addr);
for (i = 0; i < len; i++) {
pwrite_b(addr + i, ha_state.edt[i], BUS_PER);
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_cmd] SCSI DOWNLOAD EDT: edt[%i] = %02x\n", i, ha_state.edt[i]);
}
ha_state.ts[tc].rep.status = CIO_SUCCESS;
@@ -1099,12 +1144,21 @@ static void ha_cmd(uint8 op, uint8 subdev, uint32 addr, int32 len, t_bool expres
tc = HA_SCSI_ID;
ha_cmd_prep(tc, op, subdev, express);
+ if (len > HA_EDT_LEN) {
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_cmd] SCSI UPLOAD EDT: Requested to upload %d bytes; uploading only %d byte\n",
+ len, HA_EDT_LEN);
+ len = HA_EDT_LEN;
+ }
+
sim_debug(HA_TRACE, &ha_dev,
"[ha_cmd] SCSI UPLOAD EDT (%d bytes from address %08x)\n",
len, addr);
for (i = 0; i < len; i++) {
ha_state.edt[i] = pread_b(addr + i, BUS_PER);
+ sim_debug(HA_TRACE, &ha_dev,
+ "[ha_cmd] SCSI UPLOAD EDT: edt[%i] = %02x\n", i, ha_state.edt[i]);
}
ha_state.ts[tc].rep.status = CIO_SUCCESS;
diff --git a/3B2/CMakeLists.txt b/3B2/CMakeLists.txt
index c8610689..6c2f70ec 100644
--- a/3B2/CMakeLists.txt
+++ b/3B2/CMakeLists.txt
@@ -32,6 +32,7 @@ add_simulator(3b2
3b2_io.c
3b2_ports.c
3b2_ctc.c
+ 3b2_scsi.c
3b2_ni.c
INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/3B2/README.md b/3B2/README.md
index dc3fb474..5a04c086 100644
--- a/3B2/README.md
+++ b/3B2/README.md
@@ -8,7 +8,7 @@ This module contains the source for two simulators:
Full documentation for the 3B2 simulator is available here:
- - https://loomcom.com/3b2/emulator.html
+ - https://loomcom.com/3b2/emulator/
3B2/400 Simulator Devices
-------------------------
@@ -31,6 +31,7 @@ devices are given in parentheses:
- CM195A Ethernet Network Interface (NI)
- CM195B 4-port Serial MUX (PORTS)
- CM195H Cartridge Tape Controller (CTC)
+ - CM195W SCSI Host Adapter (SCSI)
3B2/700 Simulator Devices
-------------------------
@@ -49,6 +50,6 @@ devices are given in parentheses:
- TMS2793 Integrated Floppy Controller (IFLOPPY)
- Non-Volatile Memory (NVRAM)
- MM58274C Time Of Day Clock (TOD)
- - CM195W SCSI Host Adapter (SCSI)
- CM195A Ethernet Network Interface (NI)
- CM195B 4-port Serial MUX (PORTS)
+ - CM195W SCSI Host Adapter (SCSI)
diff --git a/Visual Studio Projects/3B2-400.vcproj b/Visual Studio Projects/3B2-400.vcproj
index 511dd3e2..81c6e913 100644
--- a/Visual Studio Projects/3B2-400.vcproj
+++ b/Visual Studio Projects/3B2-400.vcproj
@@ -249,6 +249,10 @@
RelativePath="..\3B2\3b2_rev2_sys.c"
>
+
+
@@ -304,6 +308,10 @@
RelativePath="..\sim_fio.c"
>
+
+
diff --git a/Visual Studio Projects/3B2-400.vcxproj b/Visual Studio Projects/3B2-400.vcxproj
index 4b35400e..6fb8c0bd 100755
--- a/Visual Studio Projects/3B2-400.vcxproj
+++ b/Visual Studio Projects/3B2-400.vcxproj
@@ -263,6 +263,7 @@
+
@@ -271,6 +272,7 @@
+
diff --git a/Visual Studio Projects/3B2-400.vcxproj.filters b/Visual Studio Projects/3B2-400.vcxproj.filters
index 5c7f1087..0a41e8bf 100755
--- a/Visual Studio Projects/3B2-400.vcxproj.filters
+++ b/Visual Studio Projects/3B2-400.vcxproj.filters
@@ -60,6 +60,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -87,6 +90,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/makefile b/makefile
index 79755eb2..4b634d9f 100644
--- a/makefile
+++ b/makefile
@@ -2129,7 +2129,7 @@ ATT3B2M400 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
${ATT3B2D}/3b2_if.c ${ATT3B2D}/3b2_id.c \
${ATT3B2D}/3b2_dmac.c ${ATT3B2D}/3b2_io.c \
${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_ctc.c \
- ${ATT3B2D}/3b2_ni.c
+ ${ATT3B2D}/3b2_scsi.c ${ATT3B2D}/3b2_ni.c
ATT3B2M400_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV2 -I ${ATT3B2D} ${NETWORK_OPT} ${AIO_CCDEFS}
ATT3B2M700 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
@@ -2878,7 +2878,7 @@ endif
${BIN}3b2${EXE} : ${ATT3B2M400} ${SIM}
${MKDIRBIN}
- ${CC} ${ATT3B2M400} ${SIM} ${ATT3B2M400_OPT} ${CC_OUTSPEC} ${LDFLAGS}
+ ${CC} ${ATT3B2M400} ${SCSI} ${SIM} ${ATT3B2M400_OPT} ${CC_OUTSPEC} ${LDFLAGS}
ifeq (${WIN32},)
cp ${BIN}3b2${EXE} ${BIN}3b2-400${EXE}
else