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