3b2: Support for multiple integrated disks
This commit improves the integrated disk (ID) controller's behavior, enabling full support for up to two 72MB (emulated WREN II) integrated winchester disks.
This commit is contained in:
parent
d99b12b412
commit
5a19a6b12c
5 changed files with 298 additions and 212 deletions
|
@ -3114,7 +3114,7 @@ static SIM_INLINE uint8 cpu_ipl()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CSRDISK is cleared when the floppy "if_irq" goes low */
|
/* CSRDISK is cleared when the floppy "if_irq" goes low */
|
||||||
if (id_irq || (csr_data & CSRDISK)) {
|
if (id_int() || (csr_data & CSRDISK)) {
|
||||||
return 11;
|
return 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,7 +303,7 @@ noret __libc_longjmp (jmp_buf buf, int val);
|
||||||
/* Calculate delays (in simulator steps) for times */
|
/* Calculate delays (in simulator steps) for times */
|
||||||
/* System clock runs at 10MHz; 100ns period. */
|
/* System clock runs at 10MHz; 100ns period. */
|
||||||
|
|
||||||
#define US_PER_INST 1.0
|
#define US_PER_INST 1.6
|
||||||
|
|
||||||
#define INST_PER_MS (1000.0 / US_PER_INST)
|
#define INST_PER_MS (1000.0 / US_PER_INST)
|
||||||
|
|
||||||
|
|
450
3B2/3b2_id.c
450
3B2/3b2_id.c
|
@ -65,8 +65,7 @@
|
||||||
#define ID_SEEK_BASE 700 /* us */
|
#define ID_SEEK_BASE 700 /* us */
|
||||||
#define ID_RECAL_WAIT 6000 /* us */
|
#define ID_RECAL_WAIT 6000 /* us */
|
||||||
|
|
||||||
/* Reading data takes about 8ms per sector, plus time to seek if not
|
/* Reading data takes about 8ms per sector */
|
||||||
on cylinder */
|
|
||||||
#define ID_RW_WAIT 8000 /* us */
|
#define ID_RW_WAIT 8000 /* us */
|
||||||
|
|
||||||
/* Sense Unit Status completes in about 200 us */
|
/* Sense Unit Status completes in about 200 us */
|
||||||
|
@ -90,37 +89,30 @@
|
||||||
uint8 id_dpr = 0;
|
uint8 id_dpr = 0;
|
||||||
/* Data FIFO pointer - Write */
|
/* Data FIFO pointer - Write */
|
||||||
uint8 id_dpw = 0;
|
uint8 id_dpw = 0;
|
||||||
/* Selected unit */
|
|
||||||
uint8 id_sel = 0;
|
|
||||||
/* Controller Status Register */
|
/* Controller Status Register */
|
||||||
uint8 id_status = 0;
|
uint8 id_status = 0;
|
||||||
/* Unit Interrupt Status */
|
/* Unit Interrupt Status */
|
||||||
uint8 id_int_status;
|
uint8 id_int_status = 0;
|
||||||
/* Last command received */
|
/* Last command received */
|
||||||
uint8 id_cmd = 0;
|
uint8 id_cmd = 0;
|
||||||
/* DMAC request */
|
/* DMAC request */
|
||||||
t_bool id_drq = FALSE;
|
t_bool id_drq = FALSE;
|
||||||
/* 8-byte FIFO */
|
/* 8-byte FIFO */
|
||||||
uint8 id_data[ID_FIFO_LEN] = {0};
|
uint8 id_data[ID_FIFO_LEN] = {0};
|
||||||
/* INT output pin */
|
/* SRQM bit */
|
||||||
t_bool id_irq = FALSE;
|
t_bool id_srqm = FALSE;
|
||||||
/* Special flag for seek end SIS */
|
/* The logical unit number (0-1) */
|
||||||
t_bool id_seek_sis = FALSE;
|
uint8 id_unit_num = 0;
|
||||||
|
/* The physical unit number (0-3) */
|
||||||
/* State of each drive */
|
uint8 id_ua = 0;
|
||||||
|
|
||||||
/* Cylinder the drive is positioned on */
|
/* Cylinder the drive is positioned on */
|
||||||
uint16 id_cyl[ID_NUM_UNITS] = {0};
|
uint16 id_cyl[ID_NUM_UNITS] = {0};
|
||||||
|
|
||||||
/* DTLH byte for each drive */
|
|
||||||
uint8 id_dtlh[ID_NUM_UNITS] = {0};
|
|
||||||
|
|
||||||
/* Arguments of last READ, WRITE, VERIFY ID, or READ ID command */
|
|
||||||
|
|
||||||
/* Ending Track Number (from Specify) */
|
/* Ending Track Number (from Specify) */
|
||||||
uint8 id_etn = 0;
|
uint8 id_etn = 0;
|
||||||
/* Ending Sector Number (from Specify) */
|
/* Ending Sector Number (from Specify) */
|
||||||
uint8 id_esn = 0;
|
uint8 id_esn = 0;
|
||||||
|
/* DTLH word (from Specify) */
|
||||||
|
uint8 id_dtlh = 0;
|
||||||
/* Physical sector number */
|
/* Physical sector number */
|
||||||
uint8 id_psn = 0;
|
uint8 id_psn = 0;
|
||||||
/* Physical head number */
|
/* Physical head number */
|
||||||
|
@ -135,6 +127,8 @@ uint8 id_lhn = 0;
|
||||||
uint8 id_lsn = 0;
|
uint8 id_lsn = 0;
|
||||||
/* Number of sectors to transfer, decremented after each sector */
|
/* Number of sectors to transfer, decremented after each sector */
|
||||||
uint8 id_scnt = 0;
|
uint8 id_scnt = 0;
|
||||||
|
/* Whether we are using polling mode or not */
|
||||||
|
t_bool id_polling = FALSE;
|
||||||
/* Sector buffer */
|
/* Sector buffer */
|
||||||
uint8 id_buf[ID_SEC_SIZE];
|
uint8 id_buf[ID_SEC_SIZE];
|
||||||
/* Buffer pointer */
|
/* Buffer pointer */
|
||||||
|
@ -143,22 +137,19 @@ size_t id_buf_ptr = 0;
|
||||||
uint8 id_idfield[ID_IDFIELD_LEN];
|
uint8 id_idfield[ID_IDFIELD_LEN];
|
||||||
uint8 id_idfield_ptr = 0;
|
uint8 id_idfield_ptr = 0;
|
||||||
|
|
||||||
/*
|
uint8 id_seek_state[ID_NUM_UNITS] = {ID_SEEK_NONE};
|
||||||
* TODO: Macros used for debugging timers. Remove when debugging is complete.
|
|
||||||
*/
|
|
||||||
double id_start_time;
|
|
||||||
|
|
||||||
#define ID_START_TIME() { id_start_time = sim_gtime(); }
|
|
||||||
#define ID_DIFF_MS() ((sim_gtime() - id_start_time) / INST_PER_MS)
|
|
||||||
|
|
||||||
UNIT id_unit[] = {
|
UNIT id_unit[] = {
|
||||||
{UDATA (&id_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK, ID_DSK_SIZE), 0, 0 },
|
{ UDATA (&id_unit_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK, ID_DSK_SIZE), 0, ID0, 0 },
|
||||||
{UDATA (&id_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK, ID_DSK_SIZE), 0, 1 },
|
{ UDATA (&id_unit_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK, ID_DSK_SIZE), 0, ID1, 0 },
|
||||||
|
{ UDATA (&id_ctlr_svc, UNIT_FIX+UNIT_BINK, 0) },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UNIT *id_ctlr_unit = &id_unit[ID_CTLR];
|
||||||
|
|
||||||
/* The currently selected drive number */
|
/* The currently selected drive number */
|
||||||
UNIT *id_sel_unit = &id_unit[0];
|
UNIT *id_sel_unit = &id_unit[ID0];
|
||||||
|
|
||||||
REG id_reg[] = {
|
REG id_reg[] = {
|
||||||
{ HRDATAD(CMD, id_cmd, 8, "Command") },
|
{ HRDATAD(CMD, id_cmd, 8, "Command") },
|
||||||
|
@ -179,10 +170,11 @@ DEVICE id_dev = {
|
||||||
|
|
||||||
/* Function implementation */
|
/* Function implementation */
|
||||||
|
|
||||||
static SIM_INLINE void id_activate(uint32 delay)
|
t_bool id_int()
|
||||||
{
|
{
|
||||||
ID_START_TIME();
|
return (((id_status & ID_STAT_CEL) ||
|
||||||
sim_activate_abs(id_sel_unit, (int32) delay);
|
(id_status & ID_STAT_CEH) ||
|
||||||
|
((id_status & ID_STAT_SRQ) && !id_srqm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIM_INLINE void id_clear_fifo()
|
static SIM_INLINE void id_clear_fifo()
|
||||||
|
@ -191,55 +183,152 @@ static SIM_INLINE void id_clear_fifo()
|
||||||
id_dpw = 0;
|
id_dpw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat id_svc(UNIT *uptr)
|
/* TODO: Remove after debugging */
|
||||||
|
static SIM_INLINE void id_activate(UNIT *uptr, int32 delay)
|
||||||
{
|
{
|
||||||
/* Complete the last command */
|
sim_activate(uptr, delay);
|
||||||
id_status = ID_STAT_CEH;
|
}
|
||||||
|
|
||||||
switch (CMD_NUM) {
|
/*
|
||||||
|
* Service routine for ID controller.
|
||||||
|
*
|
||||||
|
* The simulated HD controller must service Sense Interrupt Status,
|
||||||
|
* Specify, and Detect Error independent of the operation of either ID
|
||||||
|
* unit, which may be in the middle of a seek or other operation.
|
||||||
|
*/
|
||||||
|
t_stat id_ctlr_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
uint8 cmd;
|
||||||
|
|
||||||
|
cmd = uptr->u4; /* The command that caused the activity */
|
||||||
|
|
||||||
|
id_srqm = FALSE;
|
||||||
|
id_status &= ~(ID_STAT_CB);
|
||||||
|
id_status |= ID_STAT_CEH;
|
||||||
|
uptr->u4 = 0;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case ID_CMD_SIS:
|
||||||
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
|
"[%08x]\tINTR\t\tCOMPLETING Sense Interrupt Status.\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
id_data[0] = id_int_status;
|
||||||
|
id_int_status = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
|
"[%08x]\tINTR\t\tCOMPLETING OTHER COMMAND 0x%x (CONTROLLER)\n",
|
||||||
|
R[NUM_PC], cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Service routine for ID0 and ID1 units.
|
||||||
|
*/
|
||||||
|
t_stat id_unit_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
uint8 unit, other, cmd;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
/* If the other unit is active, we cannot interrupt, so we delay
|
||||||
|
* here */
|
||||||
|
if (id_unit[other].u4 == ID_CMD_RDATA ||
|
||||||
|
id_unit[other].u4 == ID_CMD_WDATA) {
|
||||||
|
id_activate(uptr, 1000);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
id_srqm = FALSE;
|
||||||
|
id_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_SEEK: /* fall-through */
|
||||||
case ID_CMD_RECAL:
|
case ID_CMD_RECAL:
|
||||||
/* SRQ is only set in polling mode (POL bit is 0) */
|
/* In POLLING mode, SEEK and RECAL actually interrupt twice.
|
||||||
if ((id_dtlh[UNIT_NUM] & ID_DTLH_POLL) == 0) {
|
*
|
||||||
|
* 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_status |= ID_STAT_CEH;
|
||||||
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
|
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_0 UNIT %d\n",
|
||||||
|
R[NUM_PC], unit);
|
||||||
|
id_seek_state[unit] = ID_SEEK_1;
|
||||||
|
id_activate(uptr, DELAY_US(8000)); /* TODO: Correct Delay based on steps */
|
||||||
|
break;
|
||||||
|
case ID_SEEK_1:
|
||||||
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
|
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_1 UNIT %d\n",
|
||||||
|
R[NUM_PC], unit);
|
||||||
|
id_seek_state[unit] = ID_SEEK_NONE;
|
||||||
id_status |= ID_STAT_SRQ;
|
id_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) {
|
if (uptr->flags & UNIT_ATT) {
|
||||||
id_int_status = ID_IST_SEN|(uint8)uptr->ID_UNIT_NUM;
|
id_int_status |= (ID_IST_SEN|unit);
|
||||||
} else {
|
} else {
|
||||||
id_int_status = ID_IST_NR|(uint8)uptr->ID_UNIT_NUM;
|
id_int_status |= (ID_IST_NR|unit);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SIS:
|
default:
|
||||||
if (!id_seek_sis) {
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
id_status = ID_STAT_CEL;
|
"[%08x]\tINTR\t\tERROR, NOT SEEK_0 OR SEEK_1, UNIT %d\n",
|
||||||
|
R[NUM_PC], unit);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
id_seek_sis = FALSE;
|
} else {
|
||||||
id_data[0] = id_int_status;
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
id_status &= ~ID_STAT_SRQ;
|
"[%08x]\tINTR\t\tCOMPLETING NON-POLLING Recal/Seek UNIT %d\n",
|
||||||
|
R[NUM_PC], unit);
|
||||||
|
id_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SUS:
|
case ID_CMD_SUS:
|
||||||
if ((id_sel_unit->flags & UNIT_ATT) == 0) {
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
|
"[%08x]\tINTR\t\tCOMPLETING Sense Unit Status UNIT %d\n",
|
||||||
|
R[NUM_PC], unit);
|
||||||
|
id_status |= ID_STAT_CEH;
|
||||||
|
uptr->u4 = 0;
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
/* If no HD is attached, SUS puts 0x00 into the data
|
/* If no HD is attached, SUS puts 0x00 into the data
|
||||||
buffer */
|
buffer */
|
||||||
id_data[0] = 0;
|
id_data[0] = 0;
|
||||||
} else {
|
} else {
|
||||||
/* Put Unit Status into byte 0 */
|
/* Put Unit Status into byte 0 */
|
||||||
id_data[0] = (ID_UST_DSEL|ID_UST_SCL|ID_UST_RDY);
|
id_data[0] = (ID_UST_DSEL|ID_UST_SCL|ID_UST_RDY);
|
||||||
if (id_cyl[UNIT_NUM] == 0) {
|
if (id_cyl[unit] == 0) {
|
||||||
id_data[0] |= ID_UST_TK0;
|
id_data[0] |= ID_UST_TK0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
|
"[%08x]\tINTR\t\tCOMPLETING OTHER COMMAND 0x%x UNIT %d\n",
|
||||||
|
R[NUM_PC], cmd, unit);
|
||||||
|
id_status |= ID_STAT_CEH;
|
||||||
|
uptr->u4 = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
|
||||||
"[%08x] \tINTR\t\tDELTA=%f ms\n",
|
|
||||||
R[NUM_PC], ID_DIFF_MS());
|
|
||||||
|
|
||||||
id_irq = TRUE;
|
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,12 +358,9 @@ static SIM_INLINE t_lba id_lba(uint16 cyl, uint8 head, uint8 sec)
|
||||||
|
|
||||||
/* At the end of each sector read or write, we update the FIFO
|
/* At the end of each sector read or write, we update the FIFO
|
||||||
* with the correct return parameters. */
|
* with the correct return parameters. */
|
||||||
static void SIM_INLINE id_end_rw(uint8 est) {
|
static void SIM_INLINE id_end_rw(uint8 est)
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
{
|
||||||
">>> ending R/W with status: %02x\n",
|
id_clear_fifo();
|
||||||
est);
|
|
||||||
id_dpr = 0;
|
|
||||||
id_dpw = 0;
|
|
||||||
id_data[0] = est;
|
id_data[0] = est;
|
||||||
id_data[1] = id_phn;
|
id_data[1] = id_phn;
|
||||||
id_data[2] = ~(id_lcnh);
|
id_data[2] = ~(id_lcnh);
|
||||||
|
@ -286,20 +372,11 @@ static void SIM_INLINE id_end_rw(uint8 est) {
|
||||||
|
|
||||||
/* The controller wraps id_lsn, id_lhn, and id_lcnl on each sector
|
/* The controller wraps id_lsn, id_lhn, and id_lcnl on each sector
|
||||||
* read, so that they point to the next C/H/S */
|
* read, so that they point to the next C/H/S */
|
||||||
static void SIM_INLINE id_update_chs() {
|
static void SIM_INLINE id_update_chs()
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
{
|
||||||
">>> id_update_chs(): id_esn=%02x id_etn=%02x\n",
|
|
||||||
id_esn, id_etn);
|
|
||||||
|
|
||||||
if (id_lsn++ >= id_esn) {
|
if (id_lsn++ >= id_esn) {
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
|
||||||
">>> id_update_chs(): id_lsn reset to 0. id_lhn is %02x\n",
|
|
||||||
id_lhn);
|
|
||||||
id_lsn = 0;
|
id_lsn = 0;
|
||||||
if (id_lhn++ >= id_etn) {
|
if (id_lhn++ >= id_etn) {
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
|
||||||
">>> id_update_chs(): id_lhn reset to 0. id_lcnl is %02x\n",
|
|
||||||
id_lcnl);
|
|
||||||
id_lhn = 0;
|
id_lhn = 0;
|
||||||
if (id_lcnl == 0xff) {
|
if (id_lcnl == 0xff) {
|
||||||
id_lcnl = 0;
|
id_lcnl = 0;
|
||||||
|
@ -311,7 +388,8 @@ static void SIM_INLINE id_update_chs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 id_read(uint32 pa, size_t size) {
|
uint32 id_read(uint32 pa, size_t size)
|
||||||
|
{
|
||||||
uint8 reg;
|
uint8 reg;
|
||||||
uint16 cyl;
|
uint16 cyl;
|
||||||
t_lba lba;
|
t_lba lba;
|
||||||
|
@ -354,7 +432,7 @@ uint32 id_read(uint32 pa, size_t size) {
|
||||||
/* It's time to read a new sector into our sector buf */
|
/* It's time to read a new sector into our sector buf */
|
||||||
id_buf_ptr = 0;
|
id_buf_ptr = 0;
|
||||||
cyl = (uint16) (((uint16)id_lcnh << 8)|(uint16)id_lcnl);
|
cyl = (uint16) (((uint16)id_lcnh << 8)|(uint16)id_lcnl);
|
||||||
id_cyl[UNIT_NUM] = cyl;
|
id_cyl[id_unit_num] = cyl;
|
||||||
lba = id_lba(cyl, id_lhn, id_lsn);
|
lba = id_lba(cyl, id_lhn, id_lsn);
|
||||||
if (sim_disk_rdsect(id_sel_unit, lba, id_buf, §sread, 1) == SCPE_OK) {
|
if (sim_disk_rdsect(id_sel_unit, lba, id_buf, §sread, 1) == SCPE_OK) {
|
||||||
if (sectsread !=1) {
|
if (sectsread !=1) {
|
||||||
|
@ -362,11 +440,6 @@ uint32 id_read(uint32 pa, size_t size) {
|
||||||
"[%08x]\tERROR: ASKED TO READ ONE SECTOR, READ: %d\n",
|
"[%08x]\tERROR: ASKED TO READ ONE SECTOR, READ: %d\n",
|
||||||
R[NUM_PC], sectsread);
|
R[NUM_PC], sectsread);
|
||||||
}
|
}
|
||||||
sim_debug(READ_MSG, &id_dev,
|
|
||||||
"[%08x] \tRDATA\tCYL=%d PHN=%d LCNH=%02x "
|
|
||||||
"LCNL=%02x LHN=%d LSN=%d SCNT=%d LBA=%04x\n",
|
|
||||||
R[NUM_PC], cyl, id_phn, id_lcnh, id_lcnl,
|
|
||||||
id_lhn, id_lsn, id_scnt-1, lba);
|
|
||||||
id_update_chs();
|
id_update_chs();
|
||||||
} else {
|
} else {
|
||||||
/* Uh-oh! */
|
/* Uh-oh! */
|
||||||
|
@ -379,10 +452,9 @@ uint32 id_read(uint32 pa, size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
data = id_buf[id_buf_ptr++];
|
data = id_buf[id_buf_ptr++];
|
||||||
|
|
||||||
sim_debug(READ_MSG, &id_dev,
|
sim_debug(READ_MSG, &id_dev,
|
||||||
"[%08x]\tSECTOR DATA\t%02x\t(%c)\n",
|
"[%08x]\tDATA\t%02x\n",
|
||||||
R[NUM_PC], data, (data >= 0x20 && data < 0x7f) ? data : '.');
|
R[NUM_PC], data);
|
||||||
|
|
||||||
/* Done with this current sector, update id_scnt */
|
/* Done with this current sector, update id_scnt */
|
||||||
if (id_buf_ptr >= ID_SEC_SIZE) {
|
if (id_buf_ptr >= ID_SEC_SIZE) {
|
||||||
|
@ -411,8 +483,7 @@ uint32 id_read(uint32 pa, size_t size) {
|
||||||
id_idfield_ptr = 0;
|
id_idfield_ptr = 0;
|
||||||
} else {
|
} else {
|
||||||
/* All done, set return codes */
|
/* All done, set return codes */
|
||||||
id_dpr = 0;
|
id_clear_fifo();
|
||||||
id_dpw = 0;
|
|
||||||
id_data[0] = 0;
|
id_data[0] = 0;
|
||||||
id_data[1] = id_scnt;
|
id_data[1] = id_scnt;
|
||||||
}
|
}
|
||||||
|
@ -478,13 +549,13 @@ void id_write(uint32 pa, uint32 val, size_t size)
|
||||||
|
|
||||||
/* Write to the disk buffer */
|
/* Write to the disk buffer */
|
||||||
if (id_buf_ptr < ID_SEC_SIZE) {
|
if (id_buf_ptr < ID_SEC_SIZE) {
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
|
||||||
"[%08x]\tSECTOR DATA\t%02x\t(%c)\n",
|
|
||||||
R[NUM_PC], val, (val >= 0x20 && val < 0x7f) ? val : '.');
|
|
||||||
id_buf[id_buf_ptr++] = (uint8)(val & 0xff);
|
id_buf[id_buf_ptr++] = (uint8)(val & 0xff);
|
||||||
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
|
"[%08x]\tDATA\t%02x\n",
|
||||||
|
R[NUM_PC], (uint8)(val & 0xff));
|
||||||
} else {
|
} else {
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x] ERROR\tWDATA OVERRUN\n",
|
"[%08x]\tERROR\tWDATA OVERRUN\n",
|
||||||
R[NUM_PC]);
|
R[NUM_PC]);
|
||||||
id_end_rw(ID_EST_OVR);
|
id_end_rw(ID_EST_OVR);
|
||||||
return;
|
return;
|
||||||
|
@ -495,7 +566,7 @@ void id_write(uint32 pa, uint32 val, size_t size)
|
||||||
/* It's time to start the next sector, and flush the old. */
|
/* It's time to start the next sector, and flush the old. */
|
||||||
id_buf_ptr = 0;
|
id_buf_ptr = 0;
|
||||||
cyl = (uint16) (((uint16) id_lcnh << 8)|(uint16)id_lcnl);
|
cyl = (uint16) (((uint16) id_lcnh << 8)|(uint16)id_lcnl);
|
||||||
id_cyl[UNIT_NUM] = cyl;
|
id_cyl[id_unit_num] = cyl;
|
||||||
lba = id_lba(cyl, id_lhn, id_lsn);
|
lba = id_lba(cyl, id_lhn, id_lsn);
|
||||||
if (sim_disk_wrsect(id_sel_unit, lba, id_buf, §swritten, 1) == SCPE_OK) {
|
if (sim_disk_wrsect(id_sel_unit, lba, id_buf, §swritten, 1) == SCPE_OK) {
|
||||||
if (sectswritten !=1) {
|
if (sectswritten !=1) {
|
||||||
|
@ -503,11 +574,6 @@ void id_write(uint32 pa, uint32 val, size_t size)
|
||||||
"[%08x]\tERROR: ASKED TO WRITE ONE SECTOR, WROTE: %d\n",
|
"[%08x]\tERROR: ASKED TO WRITE ONE SECTOR, WROTE: %d\n",
|
||||||
R[NUM_PC], sectswritten);
|
R[NUM_PC], sectswritten);
|
||||||
}
|
}
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
|
||||||
"[%08x]\tWDATA\tCYL=%d PHN=%d LCNH=%02x "
|
|
||||||
"LCNL=%02x LHN=%d LSN=%d SCNT=%d LBA=%04x\n",
|
|
||||||
R[NUM_PC], cyl, id_phn, id_lcnh, id_lcnl,
|
|
||||||
id_lhn, id_lsn, id_scnt, lba);
|
|
||||||
id_update_chs();
|
id_update_chs();
|
||||||
if (--id_scnt == 0) {
|
if (--id_scnt == 0) {
|
||||||
id_end_rw(0);
|
id_end_rw(0);
|
||||||
|
@ -521,13 +587,11 @@ void id_write(uint32 pa, uint32 val, size_t size)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tDATA\t%02x\n",
|
"[%08x]\tDATA\t%02x\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
|
|
||||||
if (id_dpw < ID_FIFO_LEN) {
|
if (id_dpw < ID_FIFO_LEN) {
|
||||||
id_data[id_dpw++] = (uint8) val;
|
id_data[id_dpw++] = (uint8) val;
|
||||||
} else {
|
} else {
|
||||||
|
@ -552,38 +616,25 @@ void id_handle_command(uint8 val)
|
||||||
uint32 time;
|
uint32 time;
|
||||||
t_lba lba;
|
t_lba lba;
|
||||||
|
|
||||||
/* Save the full command byte */
|
|
||||||
id_cmd = val;
|
|
||||||
|
|
||||||
/* Reset the FIFO pointer */
|
/* Reset the FIFO pointer */
|
||||||
id_dpr = 0;
|
id_clear_fifo();
|
||||||
id_dpw = 0;
|
|
||||||
|
|
||||||
/* Writing a command always de-asserts INT output, UNLESS
|
|
||||||
the SRQ bit is set. */
|
|
||||||
if ((id_status & ID_STAT_SRQ) != ID_STAT_SRQ) {
|
|
||||||
id_irq = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is this an aux command or a full command? */
|
/* Is this an aux command or a full command? */
|
||||||
if ((val & 0xf0) == 0) {
|
if ((val & 0xf0) == 0) {
|
||||||
aux_cmd = val & 0x0f;
|
aux_cmd = val & 0x0f;
|
||||||
id_status &= ~(ID_STAT_CB);
|
|
||||||
|
|
||||||
if (aux_cmd & ID_AUX_CLCE) {
|
if (aux_cmd & ID_AUX_CLCE) {
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x] \tCOMMAND\t%02x\tAUX:CLCE\n",
|
"[%08x] \tCOMMAND\t%02x\tAUX:CLCE\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
id_status &= ~(ID_STAT_CEL|ID_STAT_CEH);
|
id_status &= ~(ID_STAT_CEH|ID_STAT_CEL);
|
||||||
sim_cancel(id_sel_unit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aux_cmd & ID_AUX_HSRQ) {
|
if (aux_cmd & ID_AUX_HSRQ) {
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x] \tCOMMAND\t%02x\tAUX:HSRQ\n",
|
"[%08x] \tCOMMAND\t%02x\tAUX:HSRQ\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
id_status &= ~ID_STAT_SRQ;
|
id_srqm = TRUE;
|
||||||
sim_cancel(id_sel_unit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aux_cmd & ID_AUX_CLB) {
|
if (aux_cmd & ID_AUX_CLB) {
|
||||||
|
@ -597,83 +648,123 @@ void id_handle_command(uint8 val)
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tAUX:RESET\n",
|
"[%08x]\tCOMMAND\t%02x\tAUX:RESET\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
sim_cancel(id_sel_unit);
|
|
||||||
id_clear_fifo();
|
id_clear_fifo();
|
||||||
|
sim_cancel(id_sel_unit);
|
||||||
|
sim_cancel(id_ctlr_unit);
|
||||||
|
id_status = 0;
|
||||||
|
id_srqm = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just return early */
|
/* Just return early */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now that we know it's not an aux command, get the unit number
|
/* If the controller is busy and this isn't an AUX command, do
|
||||||
this command is for */
|
* nothing */
|
||||||
id_sel_unit = &id_unit[UNIT_NUM];
|
if (id_status & ID_STAT_CB) {
|
||||||
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
cmd = (id_cmd >> 4) & 0xf;
|
"!!! Controller Busy. Skipping command byte %02x\n",
|
||||||
|
val);
|
||||||
/* If this command is anything BUT a sense interrupt status, set
|
return;
|
||||||
* the seek flag to false.
|
|
||||||
*/
|
|
||||||
if (cmd != ID_CMD_SIS) {
|
|
||||||
id_seek_sis = FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
id_status = ID_STAT_CB;
|
/* A full command always resets CEH and CEL */
|
||||||
|
id_status &= ~(ID_STAT_CEH|ID_STAT_CEL);
|
||||||
|
|
||||||
|
/* Save the full command byte */
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Fix this hack */
|
||||||
|
if (cmd == ID_CMD_SIS || cmd == ID_CMD_SPEC || cmd == ID_CMD_DERR) {
|
||||||
|
id_ctlr_unit->u4 = cmd;
|
||||||
|
} else {
|
||||||
|
id_sel_unit->u4 = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
id_status |= ID_STAT_CB;
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case ID_CMD_SIS:
|
case ID_CMD_SIS:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tSense Int. Status - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tSense Int. Status\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val);
|
||||||
id_activate(DELAY_US(ID_SIS_WAIT));
|
id_status &= ~ID_STAT_SRQ; /* SIS immediately de-asserts SRQ */
|
||||||
|
id_activate(id_ctlr_unit, DELAY_US(ID_SIS_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SPEC:
|
case ID_CMD_SPEC:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tSpecify - %d - ETN=%02x ESN=%02x\n",
|
"[%08x]\tCOMMAND\t%02x\tSpecify - ETN=%02x ESN=%02x\n",
|
||||||
R[NUM_PC], val, UNIT_NUM, id_data[3], id_data[4]);
|
R[NUM_PC], val, id_data[3], id_data[4]);
|
||||||
id_dtlh[UNIT_NUM] = id_data[1];
|
id_dtlh = id_data[1];
|
||||||
id_etn = id_data[3];
|
id_etn = id_data[3];
|
||||||
id_esn = id_data[4];
|
id_esn = id_data[4];
|
||||||
id_activate(DELAY_US(ID_SPEC_WAIT));
|
id_polling = (id_dtlh & ID_DTLH_POLL) == 0;
|
||||||
|
id_activate(id_ctlr_unit, DELAY_US(ID_SPEC_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SUS:
|
case ID_CMD_SUS:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tSense Unit Status - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tSense Unit Status - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_activate(DELAY_US(ID_SUS_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_SUS_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_DERR:
|
case ID_CMD_DERR:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tDetect Error - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tDetect Error\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val);
|
||||||
id_status |= ID_STAT_CEH;
|
id_activate(id_ctlr_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
|
||||||
break;
|
break;
|
||||||
case ID_CMD_RECAL:
|
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,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tRecalibrate - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tRecalibrate - %d - POLLING\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_cyl[UNIT_NUM] = 0;
|
id_activate(id_sel_unit, DELAY_US(1000));
|
||||||
time = id_cyl[UNIT_NUM];
|
} else {
|
||||||
id_activate(DELAY_US(ID_RECAL_WAIT + (time * ID_SEEK_WAIT)));
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
id_seek_sis = TRUE;
|
"[%08x]\tCOMMAND\t%02x\tRecalibrate - %d - NORMAL\n",
|
||||||
|
R[NUM_PC], val, id_ua);
|
||||||
|
id_activate(id_sel_unit, DELAY_US(ID_RECAL_WAIT + (time * ID_SEEK_WAIT)));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SEEK:
|
case ID_CMD_SEEK:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
|
||||||
"[%08x]\tCOMMAND\t%02x\tSeek - %d\n",
|
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
|
||||||
id_lcnh = id_data[0];
|
id_lcnh = id_data[0];
|
||||||
id_lcnl = id_data[1];
|
id_lcnl = id_data[1];
|
||||||
cyl = id_lcnh << 8 | id_lcnl;
|
cyl = id_lcnh << 8 | id_lcnl;
|
||||||
time = (uint32) abs(id_cyl[UNIT_NUM] - cyl);
|
time = (uint32) abs(id_cyl[id_unit_num] - cyl);
|
||||||
id_activate(DELAY_US(ID_SEEK_BASE + (ID_SEEK_WAIT * time)));
|
id_cyl[id_unit_num] = cyl;
|
||||||
id_cyl[UNIT_NUM] = cyl;
|
id_seek_state[id_unit_num] = ID_SEEK_0;
|
||||||
id_seek_sis = TRUE;
|
|
||||||
|
if (id_polling) {
|
||||||
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
|
"[%08x]\tCOMMAND\t%02x\tSeek - %d - POLLING\n",
|
||||||
|
R[NUM_PC], val, id_ua);
|
||||||
|
id_activate(id_sel_unit, DELAY_US(1000));
|
||||||
|
} else {
|
||||||
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
|
"[%08x]\tCOMMAND\t%02x\tSeek - %d - NORMAL\n",
|
||||||
|
R[NUM_PC], val, id_ua);
|
||||||
|
id_activate(id_sel_unit, DELAY_US(ID_SEEK_BASE + (time * ID_SEEK_WAIT)));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ID_CMD_FMT:
|
case ID_CMD_FMT:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tFormat - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tFormat - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
|
|
||||||
id_phn = id_data[0];
|
id_phn = id_data[0];
|
||||||
id_scnt = id_data[1];
|
id_scnt = id_data[1];
|
||||||
|
@ -689,7 +780,7 @@ void id_handle_command(uint8 val)
|
||||||
for (id_buf_ptr = 0; id_buf_ptr < ID_SEC_SIZE; id_buf_ptr++) {
|
for (id_buf_ptr = 0; id_buf_ptr < ID_SEC_SIZE; id_buf_ptr++) {
|
||||||
id_buf[id_buf_ptr] = pattern;
|
id_buf[id_buf_ptr] = pattern;
|
||||||
}
|
}
|
||||||
lba = id_lba(id_cyl[UNIT_NUM], id_phn, sec++);
|
lba = id_lba(id_cyl[id_unit_num], id_phn, sec++);
|
||||||
if (sim_disk_wrsect(id_sel_unit, lba, id_buf, NULL, 1) == SCPE_OK) {
|
if (sim_disk_wrsect(id_sel_unit, lba, id_buf, NULL, 1) == SCPE_OK) {
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tFORMAT: PHN=%d SCNT=%d PAT=%02x LBA=%04x\n",
|
"[%08x]\tFORMAT: PHN=%d SCNT=%d PAT=%02x LBA=%04x\n",
|
||||||
|
@ -710,20 +801,20 @@ void id_handle_command(uint8 val)
|
||||||
|
|
||||||
id_data[1] = id_scnt;
|
id_data[1] = id_scnt;
|
||||||
|
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_VID:
|
case ID_CMD_VID:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tVerify ID - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tVerify ID - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_data[0] = 0;
|
id_data[0] = 0;
|
||||||
id_data[1] = 0x05; /* What do we put here? */
|
id_data[1] = 0x05; /* What do we put here? */
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_RID:
|
case ID_CMD_RID:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tRead ID - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tRead ID - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
if (id_sel_unit->flags & UNIT_ATT) {
|
if (id_sel_unit->flags & UNIT_ATT) {
|
||||||
id_drq = TRUE;
|
id_drq = TRUE;
|
||||||
|
|
||||||
|
@ -737,20 +828,20 @@ void id_handle_command(uint8 val)
|
||||||
} else {
|
} else {
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tUNIT %d NOT ATTACHED, CANNOT READ ID.\n",
|
"[%08x]\tUNIT %d NOT ATTACHED, CANNOT READ ID.\n",
|
||||||
R[NUM_PC], UNIT_NUM);
|
R[NUM_PC], id_ua);
|
||||||
}
|
}
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_RDIAG:
|
case ID_CMD_RDIAG:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tRead Diag - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tRead Diag - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_RDATA:
|
case ID_CMD_RDATA:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tRead Data - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tRead Data - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
if (id_sel_unit->flags & UNIT_ATT) {
|
if (id_sel_unit->flags & UNIT_ATT) {
|
||||||
id_drq = TRUE;
|
id_drq = TRUE;
|
||||||
id_buf_ptr = 0;
|
id_buf_ptr = 0;
|
||||||
|
@ -765,38 +856,32 @@ void id_handle_command(uint8 val)
|
||||||
} else {
|
} else {
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tUNIT %d NOT ATTACHED, CANNOT READ DATA.\n",
|
"[%08x]\tUNIT %d NOT ATTACHED, CANNOT READ DATA.\n",
|
||||||
R[NUM_PC], UNIT_NUM);
|
R[NUM_PC], id_ua);
|
||||||
}
|
}
|
||||||
|
id_activate(id_sel_unit, DELAY_US(ID_RW_WAIT));
|
||||||
time = (uint32) abs(id_cyl[UNIT_NUM] - ((id_lcnh<<8)|id_lcnl));
|
|
||||||
if (time == 0) {
|
|
||||||
time++;
|
|
||||||
}
|
|
||||||
time = time * ID_SEEK_WAIT;
|
|
||||||
id_activate(DELAY_US(time + ID_RW_WAIT));
|
|
||||||
break;
|
break;
|
||||||
case ID_CMD_CHECK:
|
case ID_CMD_CHECK:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tCheck - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tCheck - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SCAN:
|
case ID_CMD_SCAN:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tScan - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tScan - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_VDATA:
|
case ID_CMD_VDATA:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tVerify Data - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tVerify Data - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
id_activate(DELAY_US(ID_CMD_WAIT));
|
id_activate(id_sel_unit, DELAY_US(ID_CMD_WAIT));
|
||||||
break;
|
break;
|
||||||
case ID_CMD_WDATA:
|
case ID_CMD_WDATA:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tWrite Data - %d\n",
|
"[%08x]\tCOMMAND\t%02x\tWrite Data - %d\n",
|
||||||
R[NUM_PC], val, UNIT_NUM);
|
R[NUM_PC], val, id_ua);
|
||||||
if (id_sel_unit->flags & UNIT_ATT) {
|
if (id_sel_unit->flags & UNIT_ATT) {
|
||||||
id_drq = TRUE;
|
id_drq = TRUE;
|
||||||
id_buf_ptr = 0;
|
id_buf_ptr = 0;
|
||||||
|
@ -811,14 +896,9 @@ void id_handle_command(uint8 val)
|
||||||
} else {
|
} else {
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tUNIT %d NOT ATTACHED, CANNOT WRITE.\n",
|
"[%08x]\tUNIT %d NOT ATTACHED, CANNOT WRITE.\n",
|
||||||
R[NUM_PC], UNIT_NUM);
|
R[NUM_PC], id_ua);
|
||||||
}
|
}
|
||||||
time = (uint32) abs(id_cyl[UNIT_NUM] - ((id_lcnh<<8)|id_lcnl));
|
id_activate(id_sel_unit, DELAY_US(ID_RW_WAIT));
|
||||||
if (time == 0) {
|
|
||||||
time++;
|
|
||||||
}
|
|
||||||
time = time * ID_SEEK_WAIT;
|
|
||||||
id_activate(DELAY_US(time + ID_RW_WAIT));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -836,9 +916,9 @@ CONST char *id_description(DEVICE *dptr)
|
||||||
|
|
||||||
t_stat id_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
t_stat id_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
{
|
{
|
||||||
fprintf(st, "71MB MFM Integrated Hard Disk (ID)\n\n");
|
fprintf(st, "72MB MFM Integrated Hard Disk (ID)\n\n");
|
||||||
fprintf(st,
|
fprintf(st,
|
||||||
"The ID controller implements the integrated MFM hard disk controller\n"
|
"The ID controller implements the integrated MFM hard disk controller\n"
|
||||||
"of the 3B2/400. Up to four drives are supported on a single controller.\n");
|
"of the 3B2/400. Up to two drives are supported on a single controller.\n");
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
42
3B2/3b2_id.h
42
3B2/3b2_id.h
|
@ -35,11 +35,15 @@
|
||||||
#include "3b2_sysdev.h"
|
#include "3b2_sysdev.h"
|
||||||
#include "sim_disk.h"
|
#include "sim_disk.h"
|
||||||
|
|
||||||
/* Command Codes (bits 3-7 of command byte) */
|
#define ID0 0
|
||||||
|
#define ID1 1
|
||||||
|
#define ID_CTLR 2
|
||||||
|
|
||||||
#define ID_DATA_REG 0
|
#define ID_DATA_REG 0
|
||||||
#define ID_CMD_STAT_REG 1
|
#define ID_CMD_STAT_REG 1
|
||||||
|
|
||||||
|
/* Command Codes (bits 3-7 of command byte) */
|
||||||
|
|
||||||
#define ID_CMD_AUX 0x00 /* Auxiliary Command */
|
#define ID_CMD_AUX 0x00 /* Auxiliary Command */
|
||||||
#define ID_CMD_SIS 0x01 /* Sense int. status */
|
#define ID_CMD_SIS 0x01 /* Sense int. status */
|
||||||
#define ID_CMD_SPEC 0x02 /* Specify */
|
#define ID_CMD_SPEC 0x02 /* Specify */
|
||||||
|
@ -71,17 +75,17 @@
|
||||||
#define ID_STAT_CEH 0x40
|
#define ID_STAT_CEH 0x40
|
||||||
#define ID_STAT_CB 0x80
|
#define ID_STAT_CB 0x80
|
||||||
|
|
||||||
#define ID_IST_SEN 0x80
|
#define ID_IST_SEN 0x80 /* Seek End */
|
||||||
#define ID_IST_RC 0x40
|
#define ID_IST_RC 0x40 /* Ready Change */
|
||||||
#define ID_IST_SER 0x20
|
#define ID_IST_SER 0x20 /* Seek Error */
|
||||||
#define ID_IST_EQC 0x10
|
#define ID_IST_EQC 0x10 /* Equipment Check */
|
||||||
#define ID_IST_NR 0x08
|
#define ID_IST_NR 0x08 /* Not Ready */
|
||||||
|
|
||||||
#define ID_UST_DSEL 0x10
|
#define ID_UST_DSEL 0x10 /* Drive Selected */
|
||||||
#define ID_UST_SCL 0x08
|
#define ID_UST_SCL 0x08 /* Seek Complete */
|
||||||
#define ID_UST_TK0 0x04
|
#define ID_UST_TK0 0x04 /* Track 0 */
|
||||||
#define ID_UST_RDY 0x02
|
#define ID_UST_RDY 0x02 /* Ready */
|
||||||
#define ID_UST_WFL 0x01
|
#define ID_UST_WFL 0x01 /* Write Fault */
|
||||||
|
|
||||||
#define ID_EST_ENC 0x80
|
#define ID_EST_ENC 0x80
|
||||||
#define ID_EST_OVR 0x40
|
#define ID_EST_OVR 0x40
|
||||||
|
@ -94,13 +98,17 @@
|
||||||
|
|
||||||
#define ID_DTLH_POLL 0x10
|
#define ID_DTLH_POLL 0x10
|
||||||
|
|
||||||
|
#define ID_SEEK_NONE -1
|
||||||
|
#define ID_SEEK_0 0
|
||||||
|
#define ID_SEEK_1 1
|
||||||
|
|
||||||
/* Geometry */
|
/* Geometry */
|
||||||
|
|
||||||
#define ID_CYL 925
|
#define ID_CYL 925
|
||||||
#define ID_SEC_SIZE 512 /* Bytes per sector */
|
#define ID_SEC_SIZE 512 /* Bytes per sector */
|
||||||
#define ID_SEC_CNT 18 /* Sectors per track */
|
#define ID_SEC_CNT 18 /* Sectors per track */
|
||||||
#define ID_HEADS 9
|
#define ID_HEADS 9
|
||||||
#define ID_CYL_SIZE 512 * 18
|
#define ID_CYL_SIZE ID_SEC_SIZE * ID_SEC_CNT
|
||||||
|
|
||||||
/* Unit, Register, Device descriptions */
|
/* Unit, Register, Device descriptions */
|
||||||
|
|
||||||
|
@ -109,13 +117,10 @@
|
||||||
|
|
||||||
#define ID_NUM_UNITS 2
|
#define ID_NUM_UNITS 2
|
||||||
|
|
||||||
/* Unit number field in UNIT structure */
|
|
||||||
#define ID_UNIT_NUM u3
|
|
||||||
|
|
||||||
extern DEVICE id_dev;
|
extern DEVICE id_dev;
|
||||||
extern DEBTAB sys_deb_tab[];
|
extern DEBTAB sys_deb_tab[];
|
||||||
extern t_bool id_drq;
|
extern t_bool id_drq;
|
||||||
extern t_bool id_irq;
|
extern t_bool id_int();
|
||||||
|
|
||||||
#define IDBASE 0x4a000
|
#define IDBASE 0x4a000
|
||||||
#define IDSIZE 0x2
|
#define IDSIZE 0x2
|
||||||
|
@ -124,11 +129,12 @@ extern t_bool id_irq;
|
||||||
#define ID_DSK_SIZE ID_CYL * ID_SEC_CNT * ID_HEADS
|
#define ID_DSK_SIZE ID_CYL * ID_SEC_CNT * ID_HEADS
|
||||||
|
|
||||||
#define CMD_NUM ((id_cmd >> 4) & 0xf)
|
#define CMD_NUM ((id_cmd >> 4) & 0xf)
|
||||||
#define UNIT_NUM (id_cmd & 1) /* We intentionally ignore the top unit address bit */
|
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
|
||||||
t_stat id_svc(UNIT *uptr);
|
t_bool id_int();
|
||||||
|
t_stat id_ctlr_svc(UNIT *uptr);
|
||||||
|
t_stat id_unit_svc(UNIT *uptr);
|
||||||
t_stat id_reset(DEVICE *dptr);
|
t_stat id_reset(DEVICE *dptr);
|
||||||
t_stat id_attach(UNIT *uptr, CONST char *cptr);
|
t_stat id_attach(UNIT *uptr, CONST char *cptr);
|
||||||
t_stat id_detach(UNIT *uptr);
|
t_stat id_detach(UNIT *uptr);
|
||||||
|
|
|
@ -393,7 +393,7 @@ t_stat iu_svc_contty(UNIT *uptr)
|
||||||
if ((iu_contty.stat & STS_FFL) == 0) {
|
if ((iu_contty.stat & STS_FFL) == 0) {
|
||||||
iu_contty.rxbuf[iu_contty.w_p] = (temp & 0xff);
|
iu_contty.rxbuf[iu_contty.w_p] = (temp & 0xff);
|
||||||
iu_contty.w_p = (iu_contty.w_p + 1) % IU_BUF_SIZE;
|
iu_contty.w_p = (iu_contty.w_p + 1) % IU_BUF_SIZE;
|
||||||
if (iu_contty.w_p == iu_contty.w_p) {
|
if (iu_contty.w_p == iu_contty.r_p) {
|
||||||
iu_contty.stat |= STS_FFL;
|
iu_contty.stat |= STS_FFL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -558,7 +558,7 @@ void iu_write(uint32 pa, uint32 val, size_t size)
|
||||||
if ((iu_console.stat & STS_FFL) == 0) {
|
if ((iu_console.stat & STS_FFL) == 0) {
|
||||||
iu_console.rxbuf[iu_console.w_p] = (uint8) val;
|
iu_console.rxbuf[iu_console.w_p] = (uint8) val;
|
||||||
iu_console.w_p = (iu_console.w_p + 1) % IU_BUF_SIZE;
|
iu_console.w_p = (iu_console.w_p + 1) % IU_BUF_SIZE;
|
||||||
if (iu_console.w_p == iu_contty.r_p) {
|
if (iu_console.w_p == iu_console.r_p) {
|
||||||
iu_console.stat |= STS_FFL;
|
iu_console.stat |= STS_FFL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue