1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-13 15:27:04 +00:00

SEL32: Update console device to pass SEL diags.

SEL32: Update disk devices to hold current STAR in UNIT structure.
SEL32: Add new disk geometry macros.
SEL32: Revise disk formatting support for UTX.
SEL32: Revise INCH command support for all devices.
This commit is contained in:
AZBevier 2020-02-17 12:45:22 -07:00
parent 6d219d06f8
commit 7e3d17ef2c
14 changed files with 1630 additions and 1541 deletions

View File

@ -1,6 +1,6 @@
/* sel32_chan.c: SEL 32 Channel functions.
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
@ -119,6 +119,7 @@ t_stat rsctlxio(uint16 chsa, uint32 *status); /* reset controller XIO */
uint32 find_int_icb(uint16 chsa);
uint32 find_int_lev(uint16 chsa);
uint32 scan_chan(int *ilev);
t_stat set_inch(UNIT *uptr, uint32 inch_addr); /* set channel inch address */
t_stat chan_boot(uint16 chsa, DEVICE *dptr);
t_stat chan_set_devs();
t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
@ -167,6 +168,53 @@ int FIFO_Get(uint16 chsa, uint32 *old)
return 0; /* all OK */
}
/* Set INCH buffer address for channel */
/* return SCPE_OK or SCPE_MEM if invalid address or SCPE_ARG if already defined */
t_stat set_inch(UNIT *uptr, uint32 inch_addr) {
uint16 chsa = GET_UADDR(uptr->u3); /* get channel & sub address */
uint32 chan = chsa & 0x7f00; /* get just channel address */
CHANP *pchp = find_chanp_ptr(chan); /* get channel channel prog ptr */
DIB *dibp; /* get DIB pointer for channel */
CHANP *chp;
int i;
sim_debug(DEBUG_XIO, &cpu_dev,
"set_inch chan %04x inch addr %06x\n", chan, inch_addr);
/* must be valid channel pointer */
if (pchp == NULL)
return SCPE_MEM; /* return memory error */
/* see if valid memory address */
if (inch_addr >= (MEMSIZE*4)) /* see if mem addr >= MEMSIZE */
return SCPE_MEM; /* return memory error */
#ifdef NOT_YET
/* see if inch_addr is already defined */
if (pchp->chan_inch_addr != 0)
return SCPE_ARG; /* inch already defined */
#endif
/* set parent */
pchp->chan_inch_addr = inch_addr; /* set the inch addr */
/* now go through all the sub addresses for the channel and set inch addr */
for (i=0; i<256; i++) {
chsa = chan | i; /* merge sa to real channel */
dibp = dev_unit[chsa]; /* get the device information pointer */
if (dibp == 0)
continue; /* must have a DIB, so not used */
chp = find_chanp_ptr(chsa); /* find the chanp pointer */
if (chp == 0)
continue; /* not used */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"set_inch2 chsa %04x inch addr %06x\n", chsa, inch_addr);
/* set the inch buffer addr */
chp->chan_inch_addr = inch_addr; /* set inch buffer address */
}
return SCPE_OK; /* All OK */
}
/* Find interrupt level for the given device (ch/sa) */
/* return 0 if not found, otherwise level number */
uint32 find_int_lev(uint16 chsa)
@ -297,13 +345,18 @@ CHANP *find_chanp_ptr(uint16 chsa)
int readfull(CHANP *chp, uint32 maddr, uint32 *word)
{
maddr &= MASK24; /* mask addr to 24 bits */
if (maddr > (MEMSIZE*4)) { /* see if mem addr > MEMSIZE */
if (maddr >= (MEMSIZE*4)) { /* see if mem addr >= MEMSIZE */
chp->chan_status |= STATUS_PCHK; /* program check error */
sim_debug(DEBUG_EXP, &cpu_dev, "readfull read %08x from addr %08x ERROR\n", *word, maddr<<2);
return 1; /* show we have error */
}
#define TEST
#ifdef TEST
maddr >>= 2; /* get 32 bit word index */
*word = M[maddr]; /* get the contents */
#else
*word = RMW(maddr&MASK24); /* get 1 word */
#endif
sim_debug(DEBUG_EXP, &cpu_dev, "READFULL read %08x from addr %08x\n", *word, maddr<<2);
return 0; /* return OK */
}
@ -318,16 +371,21 @@ int readbuff(CHANP *chp)
uint32 addr = chp->ccw_addr; /* channel buffer address */
uint16 chan = get_chan(chp->chan_dev); /* our channel */
if ((addr & MASK24) > (MEMSIZE*4)) { /* see if memory address invalid */
if ((addr & MASK24) >= (MEMSIZE*4)) { /* see if memory address invalid */
chp->chan_status |= STATUS_PCHK; /* bad, program check */
chp->chan_byte = BUFF_CHNEND; /* force channel end */
irq_pend = 1; /* and we have an interrupt */
return 1; /* done, with error */
}
#ifdef TEST
addr &= MASK24; /* address only */
addr >>= 2; /* byte to word address */
chp->chan_buf = M[addr]; /* get 4 bytes */
#else
chp->chan_buf = RMB(addr&MASK24); /* get 1 byte */
#endif
#ifdef TEST
sim_debug(DEBUG_DETAIL, &cpu_dev, "readbuff read memory bytes into buffer %02x %06x %06x %04x [",
chan, chp->ccw_addr & 0xFFFFFC, chp->chan_buf, chp->ccw_count);
for(k = 24; k >= 0; k -= 8) {
@ -337,6 +395,7 @@ int readbuff(CHANP *chp)
sim_debug(DEBUG_DETAIL, &cpu_dev, "%c", ch);
}
sim_debug(DEBUG_DETAIL, &cpu_dev, "]\n");
#endif
return 0;
}
@ -348,7 +407,7 @@ int writebuff(CHANP *chp)
{
uint32 addr = chp->ccw_addr;
if ((addr & MASK24) > (MEMSIZE*4)) {
if ((addr & MASK24) >= (MEMSIZE*4)) {
chp->chan_status |= STATUS_PCHK;
sim_debug(DEBUG_DETAIL, &cpu_dev,
"writebuff PCHK addr %08x to big mem %08x status %04x\n",
@ -361,7 +420,11 @@ int writebuff(CHANP *chp)
sim_debug(DEBUG_DETAIL, &cpu_dev,
"writebuff WRITE addr %06x DATA %08x status %04x\n",
addr, chp->chan_buf, chp->chan_status);
#ifdef TEST
M[addr>>2] = chp->chan_buf;
#else
WMB(addr, chp->chan_buf); /* write byte to bebory */
#endif
return 0;
}
@ -371,10 +434,10 @@ int writebuff(CHANP *chp)
int load_ccw(CHANP *chp, int tic_ok)
{
uint32 word;
// uint8 devstat;
int docmd = 0;
UNIT *uptr;
UNIT *uptr = find_unit_ptr(chp->chan_dev); /* find the unit pointer */
uint16 chan = get_chan(chp->chan_dev); /* our channel */
CHANP *pchp;
loop:
sim_debug(DEBUG_XIO, &cpu_dev,
@ -403,14 +466,6 @@ loop:
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw read ccw chan %02x caw %06x IOCD wd 1 %08x\n",
chan, chp->chan_caw, word);
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw read data @ IOCD wd 1 %08x data wd 1 %08x\n",
word, M[(word & 0xffffff)>>2]);
#ifdef DO_DYNAMIC_DEBUG
if ((M[(word & 0xffffff)>>2]) == 0x440a0d61)
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
/* TIC can't follow TIC or be first in command chain */
if (((word >> 24) & 0xf) == CMD_TIC) {
@ -420,7 +475,8 @@ loop:
goto loop; /* restart the IOCD processing */
}
chp->chan_status |= STATUS_PCHK; /* program check for invalid tic */
sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw ERROR chan_status[%04x] %04x\n", chan, chp->chan_status);
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw ERROR chan_status[%04x] %04x\n", chan, chp->chan_status);
irq_pend = 1; /* status pending */
return 1; /* error return */
}
@ -430,20 +486,68 @@ loop:
if ((chp->ccw_flags & FLAG_DC) == 0) {
chp->ccw_cmd = (word >> 24) & 0xff; /* not DC, so set command from IOCD wd 1 */
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw No DC, flags %04x cmd %02x\n", chp->ccw_flags, chp->ccw_cmd);
"load_ccw No DC, flags %04x cmd %02x\n",
chp->ccw_flags, chp->ccw_cmd);
docmd = 1; /* show we have a command */
}
/* Set up for this command */
/* make a 24 bit address */
chp->ccw_addr = word & MASK24; /* set the data address */
readfull(chp, chp->chan_caw, &word); /* get IOCD WD 2 */
if (readfull(chp, chp->chan_caw, &word) != 0) { /* read word from memory */
chp->chan_status |= STATUS_PCHK; /* memory read error, program check */
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw data addr ERROR chan_status[%04x] %04x\n",
chan, chp->chan_status);
return 1; /* error return */
}
sim_debug(DEBUG_XIO, &cpu_dev, "load_ccw read ccw chan %02x caw %06x IOCD wd 2 %08x\n",
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw read ccw chan %02x caw %06x IOCD wd 2 %08x\n",
chan, chp->chan_caw, word);
chp->chan_caw += 4; /* next IOCD address */
chp->ccw_count = word & 0xffff; /* get 16 bit byte count from IOCD WD 2*/
chp->ccw_flags = (word >> 16) & 0xffff; /* get flags from bits 0-7 of WD 2 of IOCD */
chp->chan_byte = BUFF_EMPTY; /* no bytes transferred yet */
#ifdef INVALID_FOR_INCH
/* see if buffer count 0 or < 0x8000 */
/* diags want the count from IOCD2 in status */
if (chp->ccw_count == 0) { /* see if count is zero */
chp->chan_status |= STATUS_PCHK; /* program check error */
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw excess data count %08x ERROR chan_status[%04x] %04x\n",
chp->ccw_count, chan, chp->chan_status);
irq_pend = 1; /* status pending */
return 1; /* show we have error */
}
#endif
/* only test if non tic command */
if ((chp->ccw_cmd & 0xFF) != CMD_TIC) {
/* see if buffer address is in real memory */
/* diags want the count from IOCD2 in status */
if (chp->ccw_addr >= (MEMSIZE*4)) { /* see if mem addr >= MEMSIZE */
chp->chan_status |= STATUS_PCHK; /* program check error */
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw data start addr %08x ERROR chan_status[%04x] %04x\n",
chp->ccw_addr, chan, chp->chan_status);
irq_pend = 1; /* status pending */
return 1; /* show we have error */
}
/* see if buffer end address is in real memory */
/* diags want the count from IOCD2 in status */
if ((chp->ccw_addr + chp->ccw_count) > (MEMSIZE*4)) { /* see if mem addr > MEMSIZE */
chp->chan_status |= STATUS_PCHK; /* program check error */
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw data end addr %08x ERROR chan_status[%04x] %04x\n",
chp->ccw_addr, chan, chp->chan_status);
irq_pend = 1; /* status pending */
return 1; /* show we have error */
}
}
chp->ccw_flags = (word >> 16) & 0xffff; /* get flags from bits 0-7 of WD 2 of IOCD */
if (chp->ccw_flags & FLAG_PCI) { /* do we have prog controlled int? */
chp->chan_status |= STATUS_PCI; /* set PCI flag in status */
irq_pend = 1; /* interrupt pending */
@ -452,6 +556,7 @@ loop:
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw read docmd %02x irq_flag %04x count %04x chan %04x ccw_flags %04x\n",
docmd, irq_pend, chp->ccw_count, chan, chp->ccw_flags);
/* LPR sends CC cmd only without data addr/count */
#ifdef HACK_FOR_LPR
/* Check invalid count */
@ -462,61 +567,29 @@ loop:
}
#endif
if (docmd) { /* see if we need to process command */
// DEVICE *dptr = get_dev(uptr); /* find the device from unit pointer */
DIB *dibp = dev_unit[chp->chan_dev]; /* get the device pointer */
uptr = find_unit_ptr(chp->chan_dev); /* find the unit pointer */
if (uptr == 0)
return 1; /* if none, error */
#ifdef DO_DYNAMIC_DEBUG
// if ((chp->chan_dev == 0x1000) && ((chp->ccw_cmd & 0xff) == 0x80)) {
// if ((chp->chan_dev == 0x0800) && ((chp->ccw_cmd & 0xff) == 0x04) &&
// (chp->ccw_count == 0x0e)) {
if ((chp->chan_dev == 0x0800) && ((chp->ccw_cmd & 0xff) == 0xff))
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
if ((chp->chan_dev == 0x0800) && ((chp->ccw_cmd & 0xff) == 0x00) &&
(chp->ccw_count == 0x24)) {
uint32 addr = chp->ccw_addr; /* set the data address */
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
// sim_debug(DEBUG_CMD, &cpu_dev, "cmd 80 MT wds @ addr %08x %08x %08x %08x %08x\n",
sim_debug(DEBUG_CMD, &cpu_dev, "cmd 04 DP wds @ addr %08x %08x %08x %08x %08x\n",
addr, M[addr>>2], M[(addr+4)>>2], M[(addr+8)>>2], M[(addr+12)>>2]);
}
#endif
#ifndef CON_BUG
#ifdef DO_DYNAMIC_DEBUG
// if ((chp->chan_dev == 0x7efc) && ((chp->ccw_cmd & 0xff) == 0x03) && (chp->ccw_count == 0))
if ((chp->chan_dev == 0x0800) && ((chp->ccw_cmd & 0xff) == 0x00) && (chp->ccw_count == 0x24))
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
#endif
/* Check if this is INCH command */
if ((chp->ccw_cmd & 0xFF) == 0) { /* see if this is an initialize channel cmd */
uptr->u4 = (uint32)chp->ccw_addr; /* save the memory address in wd 1 of iocd */
if ((chp->ccw_count&0xffff) == 0) /* see if user said 0 count for INCH */
uptr->us9 = 1; /* make non zero for later test */
else
uptr->us9 = chp->ccw_count & 0xffff; /* get count from IOCD wd 2 */
/* just drop through and call the device startcmd function */
/* the INCH buffer will be returned in uptr->u4 and uptr->us9 will be non-zero */
/* it should just return SNS_CHNEND and SNS_DEVEND status */
/*052619*/ chp->chan_inch_addr = uptr->u4; /* save INCH buffer address */
pchp = find_chanp_ptr(chp->chan_dev&0x7f00); /* get parent channel prog pointer */
/*091119*/ pchp->chan_inch_addr = uptr->u4; /* save INCH buffer address */
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw INCH buffer save %08x chan %04x status %04x count %04x\n",
uptr->u4, chan, chp->chan_status, chp->ccw_count);
}
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw before start_cmd chan %04x status %04x count %04x\n",
// chan, chp->chan_status, chp->ccw_count, dptr->name);
chan, chp->chan_status, chp->ccw_count);
sim_debug(DEBUG_XIO, &cpu_dev, "load_ccw before start_cmd chan %04x status %04x count %04x\n",
chan, chp->chan_status, chp->ccw_count);
/* call the device startcmd function to process command */
/* call the device startcmd function to process the current command */
#ifndef TRY_THIS_TUESDAY
chp->chan_status = dibp->start_cmd(uptr, chan, chp->ccw_cmd);
#else
/* just replace device status bits */
devstat = dibp->start_cmd(uptr, chan, chp->ccw_cmd);
chp->chan_status = (chp->chan_status & 0xffffff00) | (devstat & 0xff);
#endif
sim_debug(DEBUG_XIO, &cpu_dev, "load_ccw after start_cmd chan %04x status %08x count %04x\n",
chan, chp->chan_status, chp->ccw_count);
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw after start_cmd chan %04x status %08x count %04x\n",
chan, chp->chan_status, chp->ccw_count);
/* see if bad status */
if (chp->chan_status & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) {
@ -524,30 +597,12 @@ loop:
chp->ccw_flags = 0; /* no flags */
chp->ccw_cmd = 0; /* stop IOCD processing */
irq_pend = 1; /* int coming */
sim_debug(DEBUG_CMD, &cpu_dev, "load_ccw bad status chan %04x status %04x\n",
sim_debug(DEBUG_EXP, &cpu_dev,
"load_ccw bad status chan %04x status %04x\n",
chan, chp->chan_status);
return 1; /* error return */
}
#ifndef TRY_THIS
/* INCH cmd will return here too, get INCH buffer addr from uptr->u4 */
/* see if this is an initialize channel cmd */
if ((chp->ccw_cmd & 0xFF) == 0 && (uptr->us9 != 0)) {
/// if ((chp->ccw_cmd & 0xFF) == 0 && (uptr->us9 >= 0)) {
chp->chan_inch_addr = uptr->u4; /* save INCH buffer address */
pchp = find_chanp_ptr(chp->chan_dev&0x7f00); /* get parent channel prog pointer */
pchp->chan_inch_addr = uptr->u4; /* save INCH buffer address */
chp->chan_status &= STATUS_DEND; /* inch has only channel end status */
sim_debug(DEBUG_XIO, &cpu_dev, "load_ccw INCH %08x saved chan %04x\n",
chp->chan_inch_addr, chan);
#ifdef DO_DYNAMIC_DEBUG
if (chp->chan_inch_addr == 0x8580)
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
}
#endif
/* see if command completed */
if (chp->chan_status & (STATUS_DEND|STATUS_CEND)) {
chp->chan_status |= STATUS_CEND; /* set channel end status */
@ -559,7 +614,8 @@ loop:
chan, chp->chan_status, chp->ccw_count);
}
}
sim_debug(DEBUG_XIO, &cpu_dev, "load_ccw return, chan %04x status %04x count %04x irq %02x\n",
sim_debug(DEBUG_XIO, &cpu_dev,
"load_ccw return, chan %04x status %04x count %04x irq %02x\n",
chan, chp->chan_status, chp->ccw_count, irq_pend);
return 0; /* good return */
}
@ -582,11 +638,12 @@ int chan_read_byte(uint16 chsa, uint8 *data)
if ((chp->ccw_flags & FLAG_DC) == 0) { /* see if Data Chain */
chp->chan_status |= STATUS_CEND; /* no, end of data */
chp->chan_byte = BUFF_CHNEND; /* buffer end too */
sim_debug(DEBUG_DATA, &cpu_dev, "chan_read_byte end status %04x\n", chp->chan_status);
sim_debug(DEBUG_EXP, &cpu_dev,
"chan_read_byte no DC chan end, cnt %04x addr %06x chan %04x\n",
chp->ccw_count, chp->ccw_addr, chan);
return 1; /* return error */
} else {
/* we have data chaining, process iocl */
sim_debug(DEBUG_DATA, &cpu_dev, "chan_read_byte calling load_ccw chan %04x\n", chan);
if (load_ccw(chp, 1)) /* process data chaining */
return 1; /* return error */
}
@ -594,13 +651,24 @@ int chan_read_byte(uint16 chsa, uint8 *data)
if (chp->chan_byte == BUFF_EMPTY) { /* is buffer empty? */
if (readbuff(chp)) /* read next 4 chars */
return 1; /* return error */
#ifdef TEST
chp->chan_byte = chp->ccw_addr & 0x3; /* get byte number from address */
chp->ccw_addr += 4 - chp->chan_byte; /* next byte address */
#else
chp->chan_byte = 0; /* show that we have data byte */
chp->ccw_addr += 1; /* next byte address */
#endif
}
chp->ccw_count--; /* one char less to process */
/* get the byte of data */
#ifdef TEST
byte = (chp->chan_buf >> (8 * (3 - (chp->chan_byte & 0x3)))) & 0xff;
chp->chan_byte++; /* next byte offset in word */
#else
/* get the byte of data */
byte = chp->chan_buf; /* read byte from memory */
chp->chan_byte = BUFF_EMPTY; /* buffer empty too */
#endif
*data = byte; /* return the data */
sim_debug(DEBUG_DATA, &cpu_dev, "chan_read_byte transferred %02x\n", byte);
return 0; /* good return */
@ -642,30 +710,35 @@ int chan_write_byte(uint16 chsa, uint8 *data)
/* see if at end of buffer */
if (chp->chan_byte == BUFF_CHNEND) {
sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte BUFF_CHNEND\n");
sim_debug(DEBUG_EXP, &cpu_dev, "chan_write_byte BUFF_CHNEND\n");
/* if SLI not set, we have incorrect length */
if ((chp->ccw_flags & FLAG_SLI) == 0) {
sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte 4 setting SLI ret\n");
sim_debug(DEBUG_EXP, &cpu_dev, "chan_write_byte 4 setting SLI ret\n");
chp->chan_status |= STATUS_LENGTH; /* set SLI */
}
return 1; /* return error */
}
if (chp->ccw_count == 0) {
sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_write_byte ccw_count is zero ccw_count[%04x] %04x\n",
chan, chp->ccw_count);
sim_debug(DEBUG_EXP, &cpu_dev,
"chan_write_byte ZERO ccw_count[%04x] %04x addr %06x\n",
chan, chp->ccw_count, chp->ccw_addr);
if (chp->chan_byte & BUFF_DIRTY) {
sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte 2 BUF DIRTY ret\n");
sim_debug(DEBUG_EXP, &cpu_dev, "chan_write_byte 2 BUF DIRTY ret\n");
if (writebuff(chp)) /* write it */
return 1; /* return error */
#ifndef TEST
chp->chan_byte = BUFF_EMPTY; /* no data now */
#endif
}
if ((chp->ccw_flags & FLAG_DC) == 0) { /* see if we have data chaining */
sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte no DC\n");
sim_debug(DEBUG_EXP, &cpu_dev, "chan_write_byte no DC\n");
chp->chan_status |= STATUS_CEND; /* no, end of data */
chp->chan_byte = BUFF_CHNEND; /* thats all the data we want */
return 1; /* return error */
} else {
/* we have data chaining, process iocl */
sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte calling load_ccw chan %04x\n", chan);
sim_debug(DEBUG_EXP, &cpu_dev,
"chan_write_byte got DC, calling load_ccw chan %04x\n", chan);
if (load_ccw(chp, 1)) /* process data chaining */
return 1; /* return error */
}
@ -687,12 +760,20 @@ int chan_write_byte(uint16 chsa, uint8 *data)
if (writebuff(chp))
return 1;
sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte BUF EMPTY|DIRTY ret\n");
#ifdef TEST
if ((chp->ccw_cmd & 0xff) == CMD_RDBWD)
chp->ccw_addr -= (1 + (chp->ccw_addr & 0x3));
else
chp->ccw_addr += (4 - (chp->ccw_addr & 0x3));
#else
if ((chp->ccw_cmd & 0xff) == CMD_RDBWD)
chp->ccw_addr -= 1;
else
chp->ccw_addr += 1;
#endif
chp->chan_byte = BUFF_EMPTY;
}
#ifdef TEST
if (chp->chan_byte == BUFF_EMPTY)
chp->chan_byte = chp->ccw_addr & 0x3;
chp->ccw_count--;
@ -709,6 +790,11 @@ int chan_write_byte(uint16 chsa, uint8 *data)
} else
chp->chan_byte++; /* next byte */
chp->chan_byte |= BUFF_DIRTY; /* we are used */
#else
chp->chan_buf = *data; /* get data byte */
chp->ccw_count--;
chp->chan_byte |= BUFF_DIRTY; /* we are used */
#endif
return 0;
}
@ -747,8 +833,8 @@ void chan_end(uint16 chsa, uint16 flags) {
CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */
sim_debug(DEBUG_EXP, &cpu_dev,
"chan_end entry chsa %04x flags %04x chan_icb %06x status %04x\n",
chsa, flags, chan_icb, chp->chan_status);
"chan_end entry chsa %04x flags %04x chan_icb %06x status %04x cmd %02x\n",
chsa, flags, chan_icb, chp->chan_status, chp->ccw_cmd);
if (chp->chan_byte & BUFF_DIRTY) {
if (writebuff(chp)) /* write remaining data */
return; /* error */
@ -758,8 +844,8 @@ void chan_end(uint16 chsa, uint16 flags) {
chp->chan_status |= ((uint16)flags); /* add in the callers flags */
// chp->ccw_cmd = 0; /* reset the completed channel command */
sim_debug(DEBUG_EXP, &cpu_dev,
"chan_end SLI test chsa %04x ccw_flags %04x count %04x status %04x\n",
sim_debug(DEBUG_XIO, &cpu_dev,
"chan_end SLI test1 chsa %04x ccw_flags %04x count %04x status %04x\n",
chsa, chp->ccw_flags, chp->ccw_count, chp->chan_status);
#ifdef HACK_HACK
/* hack - rewind had byte count of 1, so triggered this error when it is not */
@ -771,23 +857,36 @@ void chan_end(uint16 chsa, uint16 flags) {
chp->ccw_flags = 0; /* no flags */
}
#else
if (((chp->ccw_cmd & 0xF) == 0x02) || ((chp->ccw_cmd & 0xf) == 0x01)) { /* see if this is a read/write cmd */
/* see if this is a read/write cmd */
if (((chp->ccw_cmd & 0x7) == 0x02) || ((chp->ccw_cmd & 0x7) == 0x01)) {
/* test for incorrect transfer length */
if (chp->ccw_count != 0 && ((chp->ccw_flags & FLAG_SLI) == 0)) {
chp->chan_status |= STATUS_LENGTH; /* show incorrect length status */
sim_debug(DEBUG_XIO, &cpu_dev,
"chan_end setting SLI chsa %04x count %04x ccw_flags %04x status %04x\n",
chsa, chp->ccw_count, chp->ccw_flags, chp->chan_status);
chp->ccw_flags = 0; /* no flags */
}
}
#endif
sim_debug(DEBUG_EXP, &cpu_dev, "chan_end SLI test chsa %04x ccw_flags %04x status %04x\n",
chsa, chp->ccw_flags, chp->chan_status);
sim_debug(DEBUG_XIO, &cpu_dev,
"chan_end SLI2 test chsa %04x ccw_flags %04x status %04x\n",
chsa, chp->ccw_flags, chp->chan_status);
chp->ccw_cmd = 0; /* reset the completed channel command */
/* Diags dos not want SLI if we have no device end status */
if ((chp->chan_status & FLAG_SLI) && ((chp->chan_status & STATUS_DEND) == 0))
chp->chan_status &= ~FLAG_SLI;
/* no flags for attention status */
if (flags & (SNS_ATTN|SNS_UNITCHK|SNS_UNITEXP)) {
chp->ccw_flags = 0; /* no flags */
}
sim_debug(DEBUG_EXP, &cpu_dev, "chan_end test end chsa %04x, flags %04x\n", chsa, flags);
sim_debug(DEBUG_XIO, &cpu_dev,
"chan_end test end chsa %04x ccw_flags %04x status %04x\n",
chsa, chp->ccw_flags, chp->chan_status);
/* test for device or controller end */
if (chp->chan_status & (STATUS_DEND|STATUS_CEND)) {
chp->chan_byte = BUFF_NEWCMD; /* clear byte flag */
@ -914,7 +1013,7 @@ t_stat checkxio(uint16 lchsa, uint32 *status) {
return SCPE_OK; /* just busy or something, CC3|CC4 */
}
}
*status = CC1BIT; /* CCs = 1, CMD accepted & queued, will not echo status */
*status = CC1BIT; /* CCs = 1, CMD accepted & queued, no echo status */
sim_debug(DEBUG_XIO, &cpu_dev, "checkxio done CC1 status %08x\n", *status);
return SCPE_OK; /* No CC's all OK */
}
@ -964,17 +1063,20 @@ t_stat startxio(uint16 lchsa, uint32 *status) {
chan_ivl = SPAD[0xf1] + (inta<<2); /* contents of spad f1 points to chan ivl in mem */
chan_ivl = M[chan_ivl >> 2]; /* get the interrupt context block addr in memory */
iocla = M[(chan_ivl+16)>>2]; /* iocla is in wd 4 of ICB */
sim_debug(DEBUG_XIO, &cpu_dev,
"startxio test chsa %04x cmd %02x iocla %08x flags %04x IOCD1 %08x IOCD2 %08x\n",
chsa, chp->ccw_cmd, iocla, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]);
sim_debug(DEBUG_CMD, &cpu_dev, "$$$ SIO %04x %04x cmd %02x flags %04x\n",
chsa, chan, chp->ccw_cmd, chp->ccw_flags);
/* check for a Command or data chain operation in progresss */
if (chp->ccw_cmd != 0 || (chp->ccw_flags & (FLAG_DC|FLAG_CC)) != 0) {
sim_debug(DEBUG_XIO, &cpu_dev, "startxio busy return CC4 chsa %04x chan %04x\n", chsa, chan);
*status = CC4BIT; /* busy, so CC4 */
return SCPE_OK; /* just busy CC4 */
sim_debug(DEBUG_XIO, &cpu_dev,
"startxio busy return CC3&CC4 chsa %04x chan %04x\n", chsa, chan);
*status = CC4BIT|CC3BIT; /* busy, so CC3&CC4 */
return SCPE_OK; /* just busy CC3&CC4 */
}
/* determine if channel DIB has a pre startio command processor */
@ -990,7 +1092,7 @@ t_stat startxio(uint16 lchsa, uint32 *status) {
return SCPE_OK; /* just busy or something, CC3|CC4 */
}
sim_debug(DEBUG_XIO, &cpu_dev,
"startxio pre_io call return not busy chan %04x cstat %08x\n",
"startxio pre_io call return not busy ctan %04x cstat %08x\n",
chan, tempa);
}
@ -1001,16 +1103,26 @@ t_stat startxio(uint16 lchsa, uint32 *status) {
/* set status words in memory to first IOCD information */
tempa = chp->chan_inch_addr; /* get inch status buffer address */
sim_debug(DEBUG_XIO, &cpu_dev, "@ startxio 4 chsa %04x iocla %08x tempa %08x\n",
sim_debug(DEBUG_XIO, &cpu_dev,
"$$ SIO start IOCL processing chsa %04x iocla %08x incha %08x\n",
chsa, iocla, tempa);
sim_debug(DEBUG_XIO, &cpu_dev, "$$ SIO starting IOCL processing chsa %04x iocla %08x\n", chsa, iocla);
/* start processing the IOCL */
if (load_ccw(chp, 0) || (chp->chan_status & STATUS_PCI)) {
/* we have an error or user requested interrupt, return status */
sim_debug(DEBUG_EXP, &cpu_dev, "startxio store csw CC2 chan %04x status %08x\n",
chan, chp->chan_status);
/* DIAG's want CC1 with memory access error */
if (chp->chan_status & STATUS_PCHK) {
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* show I/O complete */
chp->chan_status &= ~STATUS_LENGTH; /* clear incorrect length */
store_csw(chp); /* store the status in the inch status dw */
dev_status[chsa] = 0; /* no device status */
//DIAG *status = CC2BIT; /* status stored, so CC2 */
*status = CC1BIT; /* CCs = 1, SIO accepted & queued, no echo status */
irq_pend = 1; /* still pending int */
return SCPE_OK; /* CC2 (0x20) status stored */
}
store_csw(chp); /* store the status in the inch status dw */
chp->chan_status &= ~STATUS_PCI; /* remove PCI status bit */
dev_status[chsa] = 0; /* no device status */
@ -1019,14 +1131,14 @@ t_stat startxio(uint16 lchsa, uint32 *status) {
return SCPE_OK; /* CC2 (0x20) status stored */
}
*status = CC1BIT; /* CCs = 1, SIO accepted & queued, will not echo status */
*status = CC1BIT; /* CCs = 1, SIO accepted & queued, no echo status */
sim_debug(DEBUG_CMD, &cpu_dev, "$$$ SIO done chsa %04x status %08x iocla %08x\n",
chsa, chp->chan_status, iocla);
return SCPE_OK; /* No CC's all OK */
}
/* TIO - I/O status */
t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */
t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */
// uint32 chan = get_chan(lchsa);
int lchan = get_chan(lchsa); /* get the logical channel number */
DIB *dibp;
@ -1036,7 +1148,7 @@ t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */
uint32 tempa, inta, spadent, chan;
uint16 chsa; /* chan/subaddr */
CHANP *chp, *pchp; /* Channel prog pointers */
uint32 sw1, sw2; /* status word 1 & 2 */
uint32 sw1=0, sw2=0; /* status word 1 & 2 */
/* get the device entry for the logical channel in SPAD */
spadent = SPAD[lchan]; /* get spad device entry for logical channel */
@ -1080,7 +1192,8 @@ t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */
/* check for a Command or data chain operation in progresss */
if (chp->ccw_cmd != 0 || (chp->ccw_flags & (FLAG_DC|FLAG_CC)) != 0) {
sim_debug(DEBUG_CMD, &cpu_dev, "testxio busy return CC4 chsa %04x chan %04x\n", chsa, chan);
sim_debug(DEBUG_CMD, &cpu_dev,
"testxio busy return CC4 chsa %04x chan %04x\n", chsa, chan);
*status = CC4BIT; /* busy, so CC4 */
goto tioret; /* just busy CC4 */
}
@ -1088,12 +1201,13 @@ t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */
if ((FIFO_Get(chsa, &sw1) == 0) && (FIFO_Get(chsa, &sw2) == 0)) {
uint32 chan_icb = find_int_icb(chsa); /* get icb address */
sim_debug(DEBUG_IRQ, &cpu_dev, "testxio FIFO status stored OK, sw1 %08x sw2 %08x\n", sw1, sw2);
sim_debug(DEBUG_IRQ, &cpu_dev,
"testxio FIFO status stored OK, sw1 %08x sw2 %08x\n", sw1, sw2);
/* we have status to return, do it now */
tempa = pchp->chan_inch_addr; /* get inch status buffer address */
M[tempa >> 2] = sw1; /* save sa & IOCD address in status WD 1 loc */
/* save the status to memory */
M[(tempa+4) >> 2] = sw2; /* save status and residual count in status WD 2 loc */
M[(tempa+4) >> 2] = sw2; /* save status and residual cnt in status WD 2 loc */
/* now store the status dw address into word 5 of the ICB for the channel */
M[(chan_icb + 20) >> 2] = tempa | BIT1; /* post sw addr in ICB+5w & set CC2 in INCH addr */
*status = CC2BIT; /* status stored from SIO, so CC2 */
@ -1141,7 +1255,7 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */
sim_debug(DEBUG_CMD, &cpu_dev, "stopxio dev spad %08x chsa %04x\n", spadent, chsa);
/* the startio opcode processing software has already checked for F class */
inta = ((spadent & 0x007f0000) >> 16); /* 1's complement of chan int level */
inta = ((spadent & 0x007f0000) >> 16); /* 1's complement of chan int level */
inta = 127 - inta; /* get positive int level */
spadent = SPAD[inta + 0x80]; /* get interrupt spad entry */
sim_debug(DEBUG_CMD, &cpu_dev, "stopxio int spad %08x inta %08x chsa %04x\n", spadent, inta, chsa);
@ -1163,7 +1277,7 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */
/* reset the DC or CC bits to force completion after current IOCD */
chp->ccw_flags &= ~(FLAG_DC|FLAG_CC); /* reset chaining bits */
dev_status[chsa] |= STATUS_ECHO; /* show we stopped the cmd */
*status = CC4BIT; /* busy, so CC4 */
*status = CC1BIT; /* request accepted, no status, so CC1 */
return SCPE_OK; /* just busy CC4 */
}
/* the channel is not busy, so return OK */
@ -1192,12 +1306,12 @@ t_stat rschnlxio(uint16 lchsa, uint32 *status) { /* reset channel XIO */
chp = find_chanp_ptr(chsa); /* find the chanp pointer */
uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */
sim_debug(DEBUG_CMD, &cpu_dev, "rschnlxio 1 chan %04x SPAD %08x\n", chsa, spadent);
sim_debug(DEBUG_XIO, &cpu_dev, "rschnlxio 1 chan %04x SPAD %08x\n", chsa, spadent);
if (dibp == 0 || uptr == 0) { /* if no dib or unit ptr, CC3 on return */
*status = CC3BIT; /* not found, so CC3 */
return SCPE_OK; /* not found, CC3 */
}
sim_debug(DEBUG_CMD, &cpu_dev, "rschnlxio 2 chan %04x, spad %08x\r\n", chsa, spadent);
sim_debug(DEBUG_XIO, &cpu_dev, "rschnlxio 2 chan %04x, spad %08x\r\n", chsa, spadent);
if ((uptr->flags & UNIT_ATTABLE) && ((uptr->flags & UNIT_ATT) == 0)) { /* is unit attached? */
*status = CC3BIT; /* not attached, so error CC3 */
return SCPE_OK; /* not found, CC3 */
@ -1232,14 +1346,15 @@ t_stat rschnlxio(uint16 lchsa, uint32 *status) { /* reset channel XIO */
chp->ccw_count = 0; /* channel byte count 0 bytes*/
chp->ccw_flags = 0; /* clear flags */
chp->ccw_cmd = 0; /* read command */
chp->chan_inch_addr = 0; /* clear inch addr */
}
sim_debug(DEBUG_CMD, &cpu_dev, "rschnlxio return CC1 chan %04x lev %04x\n", chan, lev);
sim_debug(DEBUG_XIO, &cpu_dev, "rschnlxio return CC1 chan %04x lev %04x\n", chan, lev);
*status = CC1BIT; /* request accepted, no status, so CC1 TRY THIS */
return SCPE_OK; /* All OK */
}
/* HIO - Halt I/O */
t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */
t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */
int chan = get_chan(lchsa);
DIB *dibp;
UNIT *uptr;
@ -1248,7 +1363,7 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */
uint32 inta, spadent;
uint16 chsa;
CHANP *chp, *pchp; /* Channel prog pointers */
uint32 sw1, sw2; /* status word 1 & 2 */
uint32 sw1=0, sw2=0; /* status word 1 & 2 */
/* get the device entry for the logical channel in SPAD */
spadent = SPAD[chan]; /* get spad device entry for logical channel */
@ -1257,7 +1372,7 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */
dibp = dev_unit[chsa]; /* get the device information pointer */
chp = find_chanp_ptr(chsa); /* find the chanp pointer */
uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */
pchp = find_chanp_ptr(chsa & 0x7f00); /* find the channel chanp pointer */
pchp = find_chanp_ptr(chsa & 0x7f00); /* find the parent channel pointer */
sim_debug(DEBUG_XIO, &cpu_dev, "haltxio 1 chsa %04x chan %04x\n", chsa, chan);
if (dibp == 0 || uptr == 0) { /* if no dib or unit ptr, CC3 on return */
@ -1283,16 +1398,39 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */
chan_ivl = M[chan_ivl >> 2]; /* get the interrupt context block addr in memory */
iocla = M[(chan_ivl+16)>>2]; /* iocla is in wd 4 of ICB */
sim_debug(DEBUG_XIO, &cpu_dev,
"haltxio busy test chsa %04x chan %04x cmd %02x flags %04x IOCD1 %8x IOCD2 %08x\n",
"haltxio busy test chsa %04x chan %04x cmd %02x flags %04x IOCD1 %08x IOCD2 %08x\n",
chsa, chan, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]);
sim_debug(DEBUG_XIO, &cpu_dev, "$$$ HIO %04x %04x %02x %04x\n",
chsa, chan, chp->ccw_cmd, chp->ccw_flags);
if (chp->ccw_cmd == 0 && (chp->ccw_flags & (FLAG_DC|FLAG_CC)) == 0) {
/* the channel is not busy, so return OK */
#ifdef DIAGTUE
*status = CC1BIT; /* request accepted, no status, so CC1 */
sim_debug(DEBUG_CMD, &cpu_dev,
"$$$ HIO END chsa %04x chan %04x cmd %02x flags %04x status %04x\n",
chsa, chan, chp->ccw_cmd, chp->ccw_flags, *status);
return SCPE_OK; /* No CC's all OK */
#else
/* diag wants an interrupt for a non busy HIO ??? */
dev_status[chsa] |= STATUS_ECHO; /* show we stopped the cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* show I/O complete */
store_csw(chp); /* store the status in the inch status dw */
dev_status[chsa] = 0; /* no device status */
irq_pend = 1; /* still pending int */
// *status = CC2BIT; /* sub channel status posted, CC2BIT */
*status = CC1BIT; /* request accepted, no status, so CC1 */
goto hioret; /* CC2 and OK */
#endif
}
chp->chan_byte = BUFF_CHNEND; /* thats all the data we want */
/* see if we have a haltio device entry */
if (dibp->halt_io != NULL) { /* NULL if no haltio function */
/* call the device controller to get halt_io status */
uint32 tempa = dibp->halt_io(uptr); /* get status from device */
#ifdef BAD_TUE
if (tempa == SNS_BSY) {
*status = CC3BIT|CC4BIT; /* sub channel busy, CC3BIT & CC4BIT */
irq_pend = 1; /* still pending int */
@ -1300,40 +1438,59 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */
"haltxio halt_io return busy chan %04x CC3|CC4\n", chan);
goto hioret; /* just return */
}
#endif
/* test for SCPE_IOERR */
if (tempa != 0) { /* sub channel has status ready */
/* The device I/O has been terminated and status stored. */
sim_debug(DEBUG_CMD, &cpu_dev,
"haltxio halt_io call return busy chan %04x cstat %08x\n",
chan, tempa);
chp->ccw_count = 0; /* force zero count */
chp->chan_status &= ~STATUS_LENGTH; /* remove PCI status bit */
store_csw(chp); /* store the status in the inch status dw */
"haltxio halt_io call return ERROR chan %04x retstat %08x cstat %08x\n",
chan, tempa, chp->chan_status);
/*TUE*/ chp->chan_status &= ~STATUS_LENGTH; /* remove SLI status bit */
chp->chan_status &= ~STATUS_PCI; /* remove PCI status bit */
//TUE dev_status[chsa] |= STATUS_ECHO; /* show we stopped the cmd */
/* chan_end called in hio device service routine */
store_csw(chp); /* store the status in the inch status dw */
chp->ccw_count = 0; /* force zero count */
dev_status[chsa] = 0; /* no device status */
/* the channel is not busy, see if any status to post */
if ((FIFO_Get(chsa, &sw1) == 0) && (FIFO_Get(chsa, &sw2) == 0)) {
uint32 chan_icb = find_int_icb(chsa); /* get icb address */
if (CPU_MODEL >= MODEL_V6) {
/* UTX wants the status posted now, MPX wants interrupt */
/* the channel is not busy, see if any status to post */
if ((FIFO_Get(chsa, &sw1) == 0) && (FIFO_Get(chsa, &sw2) == 0)) {
uint32 chan_icb = find_int_icb(chsa); /* get icb address */
sim_debug(DEBUG_IRQ, &cpu_dev,
"haltxio 0 FIFO status stored OK, sw1 %08x sw2 %08x\n", sw1, sw2);
/* we have status to return, do it now */
tempa = pchp->chan_inch_addr; /* get inch status buffer address */
M[tempa >> 2] = sw1; /* save sa & IOCD address in status WD 1 loc */
/* save the status to memory */
M[(tempa+4) >> 2] = sw2; /* save status and count in status WD 2 loc */
/* now store the status dw address into word 5 of the ICB for the channel */
/* post sw addr in ICB+5w & set CC2 in INCH addr */
M[(chan_icb + 20) >> 2] = tempa | BIT2;
sim_debug(DEBUG_IRQ, &cpu_dev,
"haltxio 1 FIFO status stored OK, sw1 %08x sw2 %08x\n", sw1, sw2);
irq_pend = 1; /* still pending int */
// UTX likes this return and does not panic */
// The diag's want an interrupt generated, so want
*status = CC2BIT; /* status stored from SIO, so CC2 */
goto hioret; /* CC2 and OK */
}
/* nothing going on, so say all OK */
*status = CC1BIT; /* request accepted, no status, so CC1 */
goto hioret; /* CC2 and OK */
} else {
sim_debug(DEBUG_IRQ, &cpu_dev,
"haltxio FIFO status stored OK, sw1 %08x sw2 %08x\n", sw1, sw2);
/* we have status to return, do it now */
tempa = pchp->chan_inch_addr; /* get inch status buffer address */
M[tempa >> 2] = sw1; /* save sa & IOCD address in status WD 1 loc */
/* save the status to memory */
M[(tempa+4) >> 2] = sw2; /* save status and residual count in status WD 2 loc */
/* now store the status dw address into word 5 of the ICB for the channel */
M[(chan_icb + 20) >> 2] = tempa | BIT2; /* post sw addr in ICB+5w & set CC2 in INCH addr */
"haltxio FIFO 2 status stored OK, sw1 %08x sw2 %08x\n", sw1, sw2);
irq_pend = 1; /* still pending int */
*status = CC2BIT; /* status stored from SIO, so CC2 */
//TUE *status = 0; /* request accepted, no status, so CC1 */
/*TUE*/ *status = CC1BIT; /* request accepted, no status, so CC1 */
goto hioret; /* CC2 and OK */
}
/* nothing going on, so say all OK */
*status = CC1BIT; /* request accepted, no status, so CC1 */
}
else {
/* we have completed the i/o without error */
} else {
/* we have completed the I/O without error */
/* the channel is not busy, so return OK */
*status = 0; /* CCs = 0, accepted */
sim_debug(DEBUG_CMD, &cpu_dev,
@ -1462,7 +1619,7 @@ t_stat rsctlxio(uint16 lchsa, uint32 *status) { /* reset controller XIO */
t_stat chan_boot(uint16 chsa, DEVICE *dptr) {
int chan = get_chan(chsa);
DIB *dibp = dev_unit[chsa];
CHANP *chp = dibp->chan_prg;
CHANP *chp = 0;
sim_debug(DEBUG_EXP, &cpu_dev, "Channel Boot chan/device addr %04x\n", chsa);
if (dibp == 0) /* if no channel or device, error */
@ -1508,14 +1665,12 @@ uint32 scan_chan(int *ilev) {
uint32 chan; /* channel num 0-7f */
uint32 tempa; /* icb address */
uint32 chan_ivl; /* int level table address */
// int lev; /* interrupt level */
uint32 chan_icba; /* int level context block address */
CHANP *chp; /* channel prog pointer */
DIB *dibp; /* DIB pointer */
if (irq_pend == 1) { /* pending int? */
/* see if we have a channel completed */
// irq_pend = 0; /* not pending anymore */
/* loop through all the channels/units for channel with pending I/O completion */
for (i = 0; sim_devices[i] != NULL; i++) {
DEVICE *dptr = sim_devices[i]; /* get pointer to configured device */
@ -1574,7 +1729,6 @@ uint32 scan_chan(int *ilev) {
irq_pend = 1; /* still pending int */
//WAS goto trythis;
return 0; /* just return */
// keep looking return 0; /* just return */
}
}
uptr++; /* next UNIT pointer */
@ -1611,17 +1765,18 @@ uint32 scan_chan(int *ilev) {
chp = find_chanp_ptr(chan); /* find the chanp pointer for channel */
/* get the address of the interrupt IVL table in main memory */
chan_ivl = SPAD[0xf1] + (i<<2); /* contents of spad f1 points to chan ivl in mem */
chan_icba = M[chan_ivl >> 2]; /* get the interrupt context block addr in memory */
chan_icba = M[chan_ivl >> 2]; /* get the interrupt context blk addr in memory */
tempa = chp->chan_inch_addr; /* get inch status buffer address */
M[tempa >> 2] = sw1; /* save sa & IOCD address in status WD 1 loc */
/* save the status to memory */
M[(tempa+4) >> 2] = sw2; /* save status and residual count in status WD 2 loc */
M[(tempa+4) >> 2] = sw2; /* save status and count in status WD 2 loc */
/* now store the status dw address into word 5 of the ICB for the channel */
M[(chan_icba + 20) >> 2] = tempa | BIT1; /* post sw addr in ICB+5w & set CC2 in SW */
/* post sw addr in ICB+5w & set CC2 in SW */
M[(chan_icba + 20) >> 2] = tempa | BIT1;
INTS[i] |= INTS_REQ; /* turn on channel interrupt request */
sim_debug(DEBUG_IRQ, &cpu_dev,
"scan_chan %04x FIFO read, set irq %04x inch %06x chan_icba %06x sw1 %08x sw2 %08x\n",
chan, i, tempa, chan_icba, sw1, sw2);
sim_debug(DEBUG_IRQ, &cpu_dev,
"scan_chan %04x FIFO read, set irq %04x inch %06x chan_icba %06x sw1 %08x sw2 %08x\n",
chan, i, tempa, chan_icba, sw1, sw2);
}
}
}
@ -1634,13 +1789,14 @@ uint32 scan_chan(int *ilev) {
INTS[i] |= INTS_ACT; /* turn on active */
SPAD[i+0x80] |= SINT_ACT; /* show active in SPAD too */
/* make sure both enabled too */
/* should already be enabled */
/* should already be enabled */
// INTS[i] |= INTS_ENAB; /* turn on enable */
// SPAD[i+0x80] |= SINT_ENAB; /* show enabled in SPAD too */
/* get the address of the interrupt IVL table in main memory */
chan_ivl = SPAD[0xf1] + (i<<2); /* contents of spad f1 points to chan ivl in mem */
chan_icba = M[chan_ivl >> 2]; /* get the interrupt context block addr in memory */
sim_debug(DEBUG_IRQ, &cpu_dev, "scan_chan INTS REQ irq %04x found chan_icba %08x INTS %08x\n",
sim_debug(DEBUG_IRQ, &cpu_dev,
"scan_chan INTS REQ irq %04x found chan_icba %08x INTS %08x\n",
i, chan_icba, INTS[i]);
*ilev = i; /* return interrupt level */
irq_pend = 0; /* not pending anymore */
@ -1648,10 +1804,6 @@ uint32 scan_chan(int *ilev) {
}
}
}
// if (irq_pend == 0) /* pending int? */
// return 0; /* no, so just return */
// irq_pend = 0; /* not pending anymore */
return 0; /* done */
}
@ -1661,7 +1813,7 @@ uint32 scan_chan(int *ilev) {
*/
DEVICE *get_dev(UNIT *uptr)
{
DEVICE *dptr;
DEVICE *dptr = NULL;
uint32 i, j;
if (uptr == NULL) /* must be valid unit */
@ -1768,11 +1920,7 @@ t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc) {
chan = get_uint(cptr, 16, 0xffff, &r); /* get new device address */
if (r != SCPE_OK) /* need good number */
return r; /* number error, return error */
//printf("finding chan %s (%x) with unit address %04x dptr %x\n",
// cptr, chan, GET_UADDR(uptr->u3), uptr->dptr);
// if ((chan == 0) || ((chan & 0x7f00) != chan)) /* is chan 1-7f */
// return SCPE_ARG; /* no, bad channel # */
chan &= 0x7f00; /* clean channel address */
dibp->chan_addr = chan; /* set new parent channel addr */

View File

@ -1,6 +1,6 @@
/* sel32_clk.c: SEL 32 Class F IOP processor RTOM functions.
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a

View File

@ -1,6 +1,6 @@
/* sel32_com.c: SEL 32 8-Line IOP communications controller
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a

View File

@ -1,6 +1,6 @@
/* sel32_con.c: SEL 32 Class F IOP processor console.
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
@ -49,6 +49,8 @@ extern void post_extirq(void);
extern uint32 attention_trap; /* set when trap is requested */
extern void set_devwake(uint16 addr, uint8 flags);
extern DEVICE *get_dev(UNIT *uptr);
extern t_stat set_inch(UNIT *uptr, uint32 inch_addr); /* set channel inch address */
extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */
#define CMD u3
/* Held in u3 is the device command and status */
@ -123,8 +125,8 @@ MTAB con_mod[] = {
};
UNIT con_unit[] = {
{UDATA(con_srvi, UNIT_IDLE, 0), 0, UNIT_ADDR(0x7EFC)}, /* Input */
{UDATA(con_srvo, UNIT_IDLE, 0), 0, UNIT_ADDR(0x7EFD)}, /* Output */
{UDATA(&con_srvi, UNIT_IDLE, 0), 0, UNIT_ADDR(0x7EFC)}, /* Input */
{UDATA(&con_srvo, UNIT_IDLE, 0), 0, UNIT_ADDR(0x7EFD)}, /* Output */
};
//DIB con_dib = {NULL, con_startcmd, NULL, NULL, NULL, con_ini, con_unit, con_chp, NUM_UNITS_CON, 0xf, 0x7e00, 0, 0, 0};
@ -157,12 +159,13 @@ DEVICE con_dev = {
*/
/* initialize the console chan/unit */
void con_ini(UNIT *uptr, t_bool f) {
// int unit = (uptr - con_unit); /* unit 0 */
int unit = (uptr - con_unit); /* unit 0 */
// DEVICE *dptr = get_dev(uptr);
// con_data[unit].incnt = 0; /* no input data */
con_data[0].incnt = 0; /* no input data */
con_data[1].incnt = 0; /* no output data */
uptr->u4 = 0; /* no input cpunt */
con_data[unit].incnt = 0; /* no input data */
// con_data[0].incnt = 0; /* no input data */
// con_data[1].incnt = 0; /* no output data */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 1000); /* time increment */
}
@ -206,10 +209,6 @@ uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
case CON_RWD: /* 0x37 */ /* TOF and write line */
case CON_WR: /* 0x01 */ /* Write command */
/* if input requested for output device, give error */
if (unit == 0) {
uptr->SNS |= SNS_CMDREJ; /* command rejected */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
}
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
@ -221,10 +220,6 @@ uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
case CON_RD: /* 0x02 */ /* Read command */
case CON_ECHO: /* 0x0a */ /* Read command w/ECHO */
/* if output requested for input device, give error */
if (unit == 1) {
uptr->SNS |= SNS_CMDREJ; /* command rejected */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
}
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
if (cmd == CON_ECHO) /* echo command? */
@ -242,15 +237,16 @@ uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
// uptr->u4 = 0; /* no I/O yet */
// con_data[unit].incnt = 0; /* clear any input data */
sim_activate(uptr, 10); /* start us off */
//TRIED sim_activate(uptr, 2); /* start us off */
return 0; /* no status change */
break;
#ifdef JUNK
case 0x0c: /* 0x0C */ /* Unknown command */
#ifndef JUNK
case 0x0C: /* 0x0C */ /* Unknown command */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
uptr->CND &= LMASK; /* leave only chsa */
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
sim_activate(uptr, 10); /* start us off */
return 0; /* no status change */
@ -269,9 +265,6 @@ uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
#ifdef JUNK
case 0x0c: /* 0x0C */ /* Unknown command */
#endif
case CON_SNS: /* 0x04 */ /* Sense */
sim_debug(DEBUG_CMD, &con_dev,
"con_startcmd %04x: Cmd Sense %02x\n", chan, uptr->SNS);
@ -284,6 +277,8 @@ uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
default: /* invalid command */
uptr->SNS |= SNS_CMDREJ; /* command rejected */
// uptr->u4 = 0; /* no I/O yet */
// con_data[unit].incnt = 0; /* clear any input data */
sim_debug(DEBUG_CMD, &con_dev,
"con_startcmd %04x: Invalid command %02x Sense %02x\n",
chan, cmd, uptr->SNS);
@ -299,35 +294,59 @@ uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
/* Handle output transfers for console */
t_stat con_srvo(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->CMD);
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int cmd = uptr->CMD & CON_MSK;
CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
uint8 ch, cp;
sim_debug(DEBUG_DETAIL, &con_dev, "con_srvo enter chsa %04x cmd = %02x\n", chsa, cmd);
if (cmd == 0x0C) { /* unknown has to do nothing */
sim_debug(DEBUG_CMD, &con_dev, "con_srvo Unknown (0x0C) chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
return SCPE_OK;
/* if input tried from output device, error */
if ((cmd == CON_RD) || (cmd == CON_ECHO) || (cmd == 0xC0)) { /* check for output */
/* CON_RD: 0x02 */ /* Read command */
/* CON_ECHO: 0x0a */ /* Read command w/ECHO */
/* if input requested for output device, give error */
if (unit == 1) {
uptr->SNS |= SNS_CMDREJ; /* command rejected */
uptr->CMD &= LMASK; /* nothing left, command complete */
//DIAG_TUE chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* unit check */
chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* unit check */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo Read to output device chsa %04x cmd = %02x\n", chsa, cmd);
return SCPE_OK;
}
}
if ((cmd == CON_NOP) || (cmd == CON_INCH2)) { /* NOP has to do nothing */
uptr->CMD &= LMASK; /* nothing left, command complete */
if (cmd == CON_INCH2) { /* Channel end only for INCH */
sim_debug(DEBUG_CMD, &con_dev, "con_srvo INCH chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND); /* done */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo INCH/NOP unit %02x: cmd %02x incnt %02x u4 %02x\n",
unit, cmd, con_data[unit].incnt, uptr->u4);
if (cmd == CON_INCH2) { /* Channel end only for INCH */
int len = chp->ccw_count; /* INCH command count */
uint32 mema = chp->ccw_addr; /* get inch or buffer addr */
// int i = set_inch(uptr, mema); /* new address */
set_inch(uptr, mema); /* new address */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo INCH chsa %04x len %02x inch %06x\n", chsa, len, mema);
chan_end(chsa, SNS_CHNEND); /* INCH done */
} else {
sim_debug(DEBUG_CMD, &con_dev, "con_srvo NOP chsa %04x cmd = %02x\n", chsa, cmd);
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo NOP chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
}
return SCPE_OK;
}
// static uint32 lastch = 0;
if ((cmd == CON_WR) || (cmd == CON_RWD)) {
/* Write to device */
if (chan_read_byte(chsa, &ch)) { /* get byte from memory */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo write %02x chsa %04x cmd %02x complete\n",
ch, chsa, cmd);
} else {
/* HACK HACK HACK */
ch &= 0x7f; /* make 7 bit w/o parity */
@ -339,15 +358,11 @@ t_stat con_srvo(UNIT *uptr) {
cp = ch;
else
cp = '^';
sim_debug(DEBUG_CMD, &con_dev, "con_srvo write %01x: putch 0x%02x %c\n", unit, ch, cp);
#ifdef DO_DYNAMIC_DEBUG
lastch = (lastch << 8) | cp;
if ((lastch & 0xffff) == 0x6e29) /* check for ion) */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo write %01x: putch 0x%02x %c\n", unit, ch, cp);
//WAS sim_putchar(ch); /* output next char to device */
sim_putchar(cp); /* output next char to device */
sim_activate(uptr, 20); /* start us off */
sim_activate(uptr, 20); /* keep going */
}
}
return SCPE_OK;
@ -358,11 +373,27 @@ t_stat con_srvi(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->CMD);
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int cmd = uptr->CMD & CON_MSK;
CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
uint8 ch;
t_stat r;
sim_debug(DEBUG_DETAIL, &con_dev, "con_srvi enter chsa %04x cmd = %02x\n", chsa, cmd);
/* if output tried to input device, error */
if ((cmd == CON_RWD) || (cmd == CON_WR) || (cmd == 0x0C)) { /* check for output */
/* CON_RWD: 0x37 */ /* TOF and write line */
/* CON_WR: 0x01 */ /* Write command */
/* if input requested for output device, give error */
if (unit == 0) {
uptr->SNS |= SNS_CMDREJ; /* command rejected */
uptr->CMD &= LMASK; /* nothing left, command complete */
//DIAGTUE chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* unit check */
chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* unit check */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi Write to input device chsa %04x cmd = %02x\n", chsa, cmd);
//fall thru return SCPE_OK;
}
}
#ifdef JUNK
if (cmd == 0x0C) { /* unknown has to do nothing */
sim_debug(DEBUG_CMD, &con_dev, "con_srvi Unknown (0x0C) chsa %04x cmd = %02x\n", chsa, cmd);
@ -373,14 +404,23 @@ t_stat con_srvi(UNIT *uptr) {
if ((cmd == CON_NOP) || (cmd == CON_INCH2)) { /* NOP is do nothing */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi INCH/NOP unit %02x: cmd %02x incnt %02x u4 %02x\n",
unit, cmd, con_data[unit].incnt, uptr->u4);
if (cmd == CON_INCH2) { /* Channel end only for INCH */
sim_debug(DEBUG_CMD, &con_dev, "con_srvi INCH chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND); /* done */
int len = chp->ccw_count; /* INCH command count */
uint32 mema = chp->ccw_addr; /* get inch or buffer addr */
// int i = set_inch(uptr, mema); /* new address */
set_inch(uptr, mema); /* new address */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi INCH chsa %04x len %02x inch %06x\n", chsa, len, mema);
chan_end(chsa, SNS_CHNEND); /* INCH done */
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
} else {
sim_debug(DEBUG_CMD, &con_dev, "con_srvi NOP chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
// chan_end(chsa, SNS_CHNEND); /* done */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi NOP chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* NOP done */
}
/* drop through to poll input */
}
@ -390,25 +430,31 @@ t_stat con_srvi(UNIT *uptr) {
case CON_RD: /* 0x02 */ /* read from device */
case CON_ECHO: /* 0x0a */ /* read from device w/ECHO */
if (uptr->CMD & CON_INPUT) { /* input waiting? */
int len = chp->ccw_count; /* get command count */
ch = con_data[unit].ibuff[uptr->u4++]; /* get char from read buffer */
#ifdef DO_DYNAMIC_DEBUG
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
sim_debug(DEBUG_CMD, &con_dev, "con_srvi unit %02x: read %02x\n", unit, ch);
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi unit %02x: read %02x incnt %02x u4 %02x len %02x\n",
unit, ch, con_data[unit].incnt, uptr->u4, len);
if (chan_write_byte(chsa, &ch)) { /* write byte to memory */
con_data[unit].incnt = 0; /* buffer empty */
cmd = 0; /* no cmd either */
// uptr->u4 = 0; /* no I/O yet */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
} else {
// len = chp->ccw_count; /* INCH command count */
// if ((len==0) && uptr->u4 == con_data[unit].incnt) { /* read completed */
if (uptr->u4 == con_data[unit].incnt) { /* read completed */
con_data[unit].incnt = 0; /* buffer is empty */
cmd = 0; /* no cmd either */
// uptr->u4 = 0; /* no I/O yet */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
}
}
}
// default:
break;
}
@ -471,7 +517,8 @@ t_stat con_srvi(UNIT *uptr) {
atbuf = 0; /* reset attention buffer */
sim_putchar('\r'); /* return char */
sim_putchar('\n'); /* line feed char */
sim_debug(DEBUG_CMD, &con_dev, "con_srvi unit %02x: read @@A Console Trap\n", unit);
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi unit %02x: read @@A Console Trap\n", unit);
}
} else {
if (ch == '?') {
@ -484,8 +531,10 @@ t_stat con_srvi(UNIT *uptr) {
}
if ((r & SCPE_KFLAG) && /* got something and */
((cmd == CON_RD) || (cmd == CON_ECHO))) /* looking for input */
return sim_activate (uptr, 20);
return tmxr_clock_coschedule_tmr (uptr, TMR_RTC, 1); /* come back soon */
//WAS return sim_activate (uptr, 20);
return sim_activate (uptr, 100);
return sim_activate (uptr, 500);
//WAS return tmxr_clock_coschedule_tmr (uptr, TMR_RTC, 1); /* come back soon */
}
t_stat con_reset(DEVICE *dptr) {
@ -497,22 +546,46 @@ t_stat con_reset(DEVICE *dptr) {
uint8 con_haltio(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->CMD);
int cmd = uptr->CMD & CON_MSK;
// int unit = (uptr - con_unit); /* unit # */
int unit = (uptr - con_unit); /* unit # 0 is read, 1 is write */
uint8 ch;
sim_debug(DEBUG_EXP, &con_dev, "con_haltio enter chsa %04x cmd = %02x\n", chsa, cmd);
// if ((unit == 0) && ((uptr->CMD & 0xff00) != 0)) { /* just return if busy */
// return SNS_BSY;
// }
#ifdef DO_DYNAMIC_DEBUG
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
con_dev.dctrl |= (DEBUG_CMD | DEBUG_EXP | DEBUG_DETAIL);
#endif
/* terminate any input command */
if ((uptr->CMD & CON_MSK) != 0) { /* is unit busy */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio HIO chsa %04x cmd = %02x\n", chsa, cmd);
if (unit == 0) {
if (chan_write_byte(chsa, &ch)) { /* write byte to memory */
con_data[unit].incnt = 0; /* buffer empty */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio HIO I/O stop chsa %04x cmd = %02x\n", chsa, cmd);
// return SCPE_OK; /* not busy anymore */
return SCPE_IOERR;
}
} else {
if (chan_read_byte(chsa, &ch)) { /* get byte from memory */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio HIO I/O stop chsa %04x cmd = %02x\n", chsa, cmd);
// return SCPE_OK; /* not busy anymore */
return SCPE_IOERR;
}
}
uptr->CMD &= LMASK; /* make non-busy */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_debug(DEBUG_CMD, &con_dev, "con_haltio HIO chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* done bit 14 */ /* bad status */
return SCPE_OK; /* not busy */
//no work chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* write terminated */
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* write terminated */
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); /* done bit 15 */ /* bad status */
return SCPE_IOERR;
// return SCPE_IOERR;
}
return SCPE_OK; /* not busy */
}

View File

@ -1,6 +1,6 @@
/* sel32_cpu.c: Sel 32 CPU simulator
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
@ -316,7 +316,7 @@ UNIT cpu_unit =
REG cpu_reg[] = {
{HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT},
{BRDATAD(PSD, PSD, 16, 32, 2, "Progtam Status Doubleword"), REG_FIT},
{BRDATAD(PSD, PSD, 16, 32, 2, "Program Status Doubleword"), REG_FIT},
{BRDATAD(GPR, GPR, 16, 32, 8, "Index registers"), REG_FIT},
{BRDATAD(BR, BR, 16, 32, 8, "Base registers"), REG_FIT},
{BRDATAD(BOOTR, BOOTR, 16, 32, 8, "Boot registers"), REG_FIT},
@ -1458,6 +1458,9 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access)
else
*prot = offset; /* return memory write protection status */
// if (addr != word)
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At RealAddr Hit convert %06x to addr %08x\n", addr, word);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"RealAddrX address %06x, TLB %06x MAPC[%03x] %08x wprot %02x prot %02x\n",
word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
@ -1554,7 +1557,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access)
sim_debug(DEBUG_TRAP, &cpu_dev,
"AddrMa %06x RealAddr %06x Map0 HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
addr, word, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
/* do a demand page request for the reqired page */
/* do a demand page request for the required page */
pfault = nix; /* save page number */
sim_debug(DEBUG_TRAP, &cpu_dev,
"Mem_write Daddr2 %06x page %04x demand page bits set TLB %08x map %04x\n",
@ -1592,6 +1595,9 @@ cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ | DEBUG_XIO);
#endif
*realaddr = word; /* return the real address */
raddr = TLB[nix]; /* get the base address & bits */
// if (addr != word)
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At RealAddr Miss convert %06x to addr %08x\n", addr, word);
if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97)) {
/* get protection status of map */
@ -1708,6 +1714,9 @@ t_stat Mem_read(uint32 addr, uint32 *data)
uint32 status, realaddr, prot, page, map, mix, nix, msdl, mpl, nmap;
status = RealAddr(addr, &realaddr, &prot, MEM_RD); /* convert address to real physical address */
// if (addr != realaddr)
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At Mem_read convert %06x to addr %08x\n", addr, realaddr);
if (status == ALLOK) {
// *data = M[realaddr >> 2]; /* valid address, get physical address contents */
@ -2044,9 +2053,17 @@ redo:
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
sim_debug(DEBUG_IRQ, &cpu_dev,
"Interrupt %04x OPSD1 %08x OPSD2 %08x NPSD1 %08x NPSD2 %08x ICBA %08x\n",
il, RMW(int_icb), RMW(int_icb+4), PSD1, PSD2, int_icb);
// il, M[int_icb>>2], M[(int_icb>>2)+1], PSD1, PSD2, int_icb);
"Inter %03x OPSD1 %08x OPSD2 %08x NPSD1 %08x NPSD2 %08x\n",
il, RMW(int_icb), RMW(int_icb+4), PSD1, PSD2);
bc = RMW(int_icb+20) & 0xffffff;
if (RMW(int_icb+16) == 0)
sim_debug(DEBUG_IRQ, &cpu_dev,
"Inter2 %03x ICBA %06x IOCLA %06x\n",
il, int_icb, RMW(int_icb+16));
else
sim_debug(DEBUG_IRQ, &cpu_dev,
"Inter2 %03x ICBA %06x IOCLA %06x STAT %08x SW1 %08x SW2 %08x\n",
il, int_icb, RMW(int_icb+16), RMW(int_icb+20), RMW(bc), RMW(bc+4));
wait4int = 0; /* wait is over for int */
irq_pend = 1; /* scan for interrupts again */
skipinstr = 1; /* skip next inter test after this instr */
@ -2091,14 +2108,6 @@ redo:
/* Check for external interrupt here */
/* see if we have an attention request from console */
if (!skipinstr && attention_trap) {
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_EXP | DEBUG_IRQ | DEBUG_XIO);
sim_debug(DEBUG_EXP, &cpu_dev, "Attention TRAP %04x skip %01x wait4int %01x irq_pend %01x\n",
TRAPME, skipinstr, wait4int, irq_pend);
sim_debug(DEBUG_EXP, &cpu_dev, "Attention TRAPME %04x PSD %08x %08x\n",
TRAPME, PSD1, PSD2);
#endif
TRAPME = attention_trap; /* get trap number */
attention_trap = 0; /* clear flag */
sim_debug(DEBUG_XIO, &cpu_dev, "Attention TRAP %04x\n", TRAPME);
@ -2110,17 +2119,9 @@ skipi:
i_flags = 0; /* do not update pc if MF or NPM */
skipinstr = 0; /* skip only once */
TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */
//WAS if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
//WAS reason = STOP_IBKPT;
//WAS break;
//WAS }
/* fill IR from logical memory address */
if ((TRAPME = read_instruction(PSD, &IR))) {
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
sim_debug(DEBUG_TRAP, &cpu_dev,
"read_instr TRAPME %04x PSD %08x %08x i_flags %04x drop_nop %01x\n",
TRAPME, PSD1, PSD2, i_flags, drop_nop);
@ -2698,8 +2699,8 @@ exec:
break;
case 0x9: /* RDSTS */
GPR[reg] = CPUSTATUS; /* get CPU status word */
sim_debug(DEBUG_CMD, &cpu_dev,
"RDSTS CPUSTATUS %08x SPAD[0xf9] %08x\n", CPUSTATUS, SPAD[0xf9]);
//sim_debug(DEBUG_CMD, &cpu_dev,
//"RDSTS CPUSTATUS %08x SPAD[0xf9] %08x\n", CPUSTATUS, SPAD[0xf9]);
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_TRAP | DEBUG_EXP | DEBUG_IRQ);
@ -3689,8 +3690,8 @@ tbr: /* handle basemode TBR too *
t = (GPR[reg] >> 16) & 0xff; /* get SPAD address from Rd (6-8) */
temp2 = SPAD[t]; /* get old SPAD data */
SPAD[t] = GPR[sreg]; /* store Rs into SPAD */
sim_debug(DEBUG_CMD, &cpu_dev,
"At TRSC with spad[%02x] %08x old %08x\n", t, SPAD[t], temp2);
//sim_debug(DEBUG_CMD, &cpu_dev,
//"At TRSC with spad[%02x] %08x old %08x\n", t, SPAD[t], temp2);
break;
case 0xF: /* TSCR */ /* Transfer scratchpad to register */
@ -3704,8 +3705,8 @@ tbr: /* handle basemode TBR too *
}
t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (9-11) */
temp = SPAD[t]; /* get SPAD data into Rd (6-8) */
sim_debug(DEBUG_CMD, &cpu_dev,
"At TSCR with spad[%02x] %08x\n", t, SPAD[t]);
//sim_debug(DEBUG_CMD, &cpu_dev,
//"At TSCR with spad[%02x] %08x\n", t, SPAD[t]);
break;
}
GPR[reg] = temp; /* save the temp value to Rd reg */
@ -4013,6 +4014,8 @@ skipit:
break;
}
td = (t_int64)dest % (t_int64)source; /* remainder */
// dbl = !(td >= 0); /* double reg is neg remainder */
// dbl = ((t_int64)td < 0); /* double reg is neg remainder */
dbl = (td < 0); /* double reg is neg remainder */
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
td = NEGATE32(td); /* dividend and remainder must be same sign */
@ -4641,6 +4644,8 @@ doovr3:
case 0x80>>2: /* 0x80 SD|ADR - SD|ADR */ /* LEAR */
/* convert address to real physical address */
TRAPME = RealAddr(addr, &temp, &t, MEM_RD);
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At LEAR convert %06x to addr %08x\n", addr, temp);
// diag allows any addr if mapped
if (TRAPME != ALLOK) {
sim_debug(DEBUG_TRAP, &cpu_dev,
@ -4687,7 +4692,7 @@ doovr3:
WMR((nix<<1), map); /* store the map reg contents into cache */
TLB[nix] |= 0x0c000000; /* set the accessed & hit bits in TLB too */
WMH(msdl+(mix<<1), mmap); /* save modified memory map with access bit set */
sim_debug(DEBUG_CMD, &cpu_dev,
sim_debug(DEBUG_EXP, &cpu_dev,
"LEAR Laddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n",
addr, nix, TLB[nix], map, mmap);
}
@ -4697,6 +4702,8 @@ doovr3:
/* DIAGS needs it, so put it back */
if (FC & 4) /* see if F bit was set */
temp |= 0x01000000; /* set bit 7 of address */
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At LEAR convert %06x to addr %08x\n", addr, temp);
dest = temp; /* put in dest to go out */
break;
@ -5022,6 +5029,11 @@ meoa: /* merge point for eor, and, or */
"\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
sim_debug(DEBUG_INST, &cpu_dev,
" R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"EXM skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
#endif
/*DIAG*/ skipinstr = 0; /* only test this once */
goto exec; /* go execute the instruction */
break;
@ -5320,7 +5332,7 @@ doovr2:
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
goto newpsd; /* program error */
}
temp2 = ((IR>>12) & 0x0f) << 2; /* get SVC index from IR */
temp2 = ((IR>>12) & 0x0f) << 2; /* get SVC index from IR */
t = M[(temp+temp2)>>2]; /* get secondary trap vector address ICB address */
if (t == 0 || t == 0xffffffff) { /* see if ICB set up */
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
@ -5403,6 +5415,11 @@ doovr2:
"\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
sim_debug(DEBUG_INST, &cpu_dev,
" R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"EXR skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
#endif
/*DIAG*/ skipinstr = 0; /* only test this once */
goto exec; /* go execute the instruction */
break;
@ -6347,9 +6364,6 @@ mcheck:
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO SIO ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
sim_debug(DEBUG_IRQ, &cpu_dev,
"SIO skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
break;
case 0x03: /* Test I/O TIO */
@ -6364,6 +6378,10 @@ mcheck:
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO TIO ret chan %04x sa %04x status %08x spad %08x INTS[%02x] %08x\n",
chan, suba, status, t, ix, INTS[ix]);
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
break;
case 0x04: /* Stop I/O STPIO */

View File

@ -1,6 +1,6 @@
/* sel32_defs.h: SEL-32 Concept/32 simulator definitions
Copyright (c) 2018-2019, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
@ -417,6 +417,8 @@ extern DEBTAB dev_debug[];
#define WMW(a,d) (M[(a)>>2]=d) /* write memory addressed word */
/* write halfword to memory address */
#define WMH(a,d) ((a)&2?(M[(a)>>2]=(M[(a)>>2]&LMASK)|((d)&RMASK)):(M[(a)>>2]=(M[(a)>>2]&RMASK)|((d)<<16)))
/* write byte to memory */
#define WMB(a,d) (M[(a)>>2]=(M[(a)>>2]&(~(0xff<<(8*(7-(a&3)))))|((d&0xff)<<(8*(7-(a&3))))))
/* map register access macros */
/* The RMR and WMR macros are used to read/write the MAPC cache registers */

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* sel32_fltpt.c: SEL 32 floating point instructions processing.
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* sel32_iop.c: SEL-32 Model 8000/8001/8002 IOP processor controller
Copyright (c) 2018-2019, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -44,6 +44,8 @@ extern void set_devattn(uint16 addr, uint8 flags);
extern void post_extirq(void);
extern uint32 attention_trap; /* set when trap is requested */
extern void set_devwake(uint16 addr, uint8 flags);
extern t_stat set_inch(UNIT *uptr, uint32 inch_addr); /* set channel inch address */
extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */
/* forward definitions */
uint8 iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd);
@ -68,7 +70,7 @@ const char *iop_desc(DEVICE *dptr);
#define CON_OUTPUT 0x1000 /* Output ready for unit */
#define CON_READ 0x2000 /* Read mode selected */
/* Input buffer pointer held in u4 */
/* not used u4 */
/* in u5 packs sense byte 0,1 and 3 */
/* Sense byte 0 */
@ -91,18 +93,19 @@ struct _iop_data
uint8 ibuff[145]; /* Input line buffer */
uint8 incnt; /* char count */
}
iop_data[NUM_UNITS_CON];
iop_data[NUM_UNITS_IOP];
/* channel program information */
CHANP iop_chp[NUM_UNITS_MT] = {0};
CHANP iop_chp[NUM_UNITS_IOP] = {0};
MTAB iop_mod[] = {
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL},
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV",
&set_dev_addr, &show_dev_addr, NULL, "Device address"},
{0}
};
UNIT iop_unit[] = {
{UDATA(iop_srv, UNIT_IDLE, 0), 0, UNIT_ADDR(0x7E00)}, /* Channel controlller */
{UDATA(&iop_srv, UNIT_IDLE, 0), 0, UNIT_ADDR(0x7E00)}, /* Channel controller */
};
//DIB iop_dib = {NULL, iop_startcmd, NULL, NULL, NULL, iop_ini, iop_unit, iop_chp, NUM_UNITS_IOP, 0xff, 0x7e00,0,0,0};
@ -115,7 +118,7 @@ DIB iop_dib = {
iop_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
iop_unit, /* UNIT* units */ /* Pointer to units structure */
iop_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
NUM_UNITS_IOP, /* uint8 numunits */ /* number of units defined */
NUM_UNITS_IOP, /* uint8 numunits */ /* number of units defined */
0xff, /* uint8 mask */ /* 16 devices - device mask */
0x7e00, /* uint16 chan_addr */ /* parent channel address */
0, /* uint32 chan_fifo_in */ /* fifo input index */
@ -129,8 +132,8 @@ DEVICE iop_dev = {
NULL, NULL, &iop_reset, /* examine, deposit, reset */
NULL, NULL, NULL, /* boot, attach, detach */
&iop_dib, DEV_UADDR|DEV_DISABLE|DEV_DEBUG, 0, dev_debug, /* dib, dev flags, debug flags, debug */
NULL, NULL, &iop_help, /* ?, ?, help */
NULL, NULL, &iop_desc /* ?, ?, description */
// NULL, NULL, &iop_help, /* ?, ?, help */
// NULL, NULL, &iop_desc /* ?, ?, description */
};
/* IOP controller routines */
@ -140,7 +143,9 @@ void iop_ini(UNIT *uptr, t_bool f)
int unit = (uptr - iop_unit); /* unit 0 */
DEVICE *dptr = &iop_dev; /* one and only dummy device */
sim_debug(DEBUG_CMD, &iop_dev, "IOP init device %s controller/device %04x\n", dptr->name, GET_UADDR(uptr->u3));
sim_debug(DEBUG_CMD, &iop_dev,
"IOP init device %s controller/device %04x\n",
dptr->name, GET_UADDR(uptr->u3));
iop_data[unit].incnt = 0; /* no input data */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
}
@ -148,6 +153,9 @@ void iop_ini(UNIT *uptr, t_bool f)
/* start an I/O operation */
uint8 iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
{
sim_debug(DEBUG_CMD, &iop_dev,
"IOP startcmd %02x controller/device %04x\n",
cmd, GET_UADDR(uptr->u3));
if ((uptr->u3 & IOP_MSK) != 0) /* is unit busy */
return SNS_BSY; /* yes, return busy */
@ -158,9 +166,16 @@ uint8 iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
case IOP_INCH: /* INCH command */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
uptr->u3 &= LMASK; /* leave only chsa */
sim_debug(DEBUG_CMD, &iop_dev, "iop_startcmd %04x: Cmd INCH\n", chan);
sim_debug(DEBUG_CMD, &iop_dev,
"iop_startcmd %04x: Cmd INCH iptr %06x INCHa %06x\n",
chan, iop_chp[0].ccw_addr, /* set inch buffer addr */
iop_chp[0].chan_inch_addr); /* set inch buffer addr */
iop_chp[0].chan_inch_addr = iop_chp[0].ccw_addr; /* set inch buffer addr */
// set_inch(uptr, iop_chp[0].ccw_addr); /* new address */
uptr->u3 |= IOP_INCH2; /* save INCH command as 0xf0 */
sim_activate(uptr, 20); /* TRY 07-13-19 */
sim_activate(uptr, 20); /* go on */
return 0; /* no status change */
break;
@ -190,44 +205,48 @@ uint8 iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
/* Handle transfers for other sub-channels on IOP */
t_stat iop_srv(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3);
int cmd = uptr->u3 & IOP_MSK;
uint16 chsa = GET_UADDR(uptr->u3);
int cmd = uptr->u3 & IOP_MSK;
// CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
CHANP *chp = &iop_chp[0]; /* find the chanp pointer */
// int i;
// int len = chp->ccw_count; /* INCH command count */
uint32 mema = chp->ccw_addr; /* get inch or buffer addr */
/* test for NOP or INCH cmds */
if ((cmd == IOP_NOP) || (cmd == IOP_INCH2)) { /* NOP has do nothing */
uptr->u3 &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &iop_dev, "iop_srv INCH/NOP chan %02x: chnend|devend\n", chsa);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
} else
if (cmd) {
if ((cmd != IOP_NOP) && (cmd != IOP_INCH2)) { /* NOP or INCH */
uptr->u3 &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &iop_dev,
"iop_srv Unknown cmd %02x chan %02x: chnend|devend|unitexp\n", cmd, chsa);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); /* done */
return SCPE_OK;
} else
if (cmd == IOP_NOP) { /* NOP do nothing */
uptr->u3 &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &iop_dev, "iop_srv INCH/NOP chan %02x: chnend|devend\n", chsa);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
return SCPE_OK;
} else
/* test for INCH cmd */
if (cmd == IOP_INCH2) { /* INCH */
sim_debug(DEBUG_CMD, &iop_dev,
"iop_srv starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n",
mema, chsa, chp->ccw_addr, chp->ccw_count);
/* the chp->ccw_addr location contains the inch address */
/* call set_inch() to setup inch buffer */
// i = set_inch(uptr, mema); /* new address */
set_inch(uptr, mema); /* new address */
// chp->chan_inch_addr = mema; /* set inch buffer addr */
uptr->u3 &= LMASK; /* clear the cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we are done dev|chan end */
// chan_end(chsa, SNS_CHNEND); /* we are done dev|chan end */
}
return SCPE_OK;
}
/* Handle output transfers for console */
t_stat iop_srvo(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3);
int cmd = uptr->u3 & IOP_MSK;
sim_debug(DEBUG_CMD, &iop_dev, "iop_srvo start %04x: cmd %02x \n", chsa, cmd);
return SCPE_OK;
}
/* Handle input transfers for console */
t_stat iop_srvi(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3);
int cmd = uptr->u3 & IOP_MSK;
sim_debug(DEBUG_CMD, &iop_dev, "iop_srv start %04x: cmd %02x \n", chsa, cmd);
return SCPE_OK;
}
t_stat iop_reset(DEVICE *dptr)
{
/* add reset code here */

View File

@ -1,6 +1,6 @@
/* sel32_lpr.c: SEL 32 Line Printer
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
@ -161,9 +161,9 @@ MTAB lpr_mod[] = {
};
UNIT lpr_unit[] = {
{UDATA(lpr_srv, UNIT_LPR, 66), 300, UNIT_ADDR(0x7EF8)}, /* A */
{UDATA(&lpr_srv, UNIT_LPR, 66), 300, UNIT_ADDR(0x7EF8)}, /* A */
#if NUM_DEVS_LPR > 1
{UDATA(lpr_srv, UNIT_LPR, 66), 300, UNIT_ADDR(0x7EF9)}, /* B */
{UDATA(&lpr_srv, UNIT_LPR, 66), 300, UNIT_ADDR(0x7EF9)}, /* B */
#endif
};
@ -217,6 +217,7 @@ uint8 lpr_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
/* process the command */
switch (cmd & LPR_CMDMSK) {
case 0x00: /* INCH command */
/* the IOP should already have the inch buffer set, so ignore */
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %04x: Cmd INCH\n", chan);
//fprintf(stderr, "lpr_startcmd %04x: Cmd INCH\n", chan);
return SNS_CHNEND|SNS_DEVEND; /* all is well */

View File

@ -1,6 +1,6 @@
/* sel32_mt.c: SEL-32 8051 Buffered Tape Processor
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
@ -47,8 +47,11 @@ extern int chan_write_byte(uint16 chan, uint8 *data);
extern void set_devattn(uint16 addr, uint8 flags);
extern t_stat chan_boot(uint16 addr, DEVICE *dptr);
extern DEVICE *get_dev(UNIT *uptr);
extern t_stat set_inch(UNIT *uptr, uint32 inch_addr); /* set channel inch address */
extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */
extern uint32 SPAD[]; /* cpu SPAD */
extern uint32 M[]; /* our memory */
extern uint32 SPAD[]; /* cpu SPAD */
#ifdef NUM_DEVS_MT
#define BUFFSIZE (64 * 1024)
@ -56,70 +59,6 @@ extern uint32 SPAD[]; /* cpu SPAD */
#define DEV_BUF_NUM(x) (((x) & 07) << DEV_V_UF)
#define GET_DEV_BUF(x) (((x) >> DEV_V_UF) & 07)
#if 0
CMNDCODE EQU $-1B
/* IOCD cmd bits 0-7 OP */
DATAB X'23' 1 REW
DATAB X'02' 2 READ
DATAB X'01' 3 WRITE
DATAB X'93' 4 WEOF
DATAB X'FF' 5 XCHANP
DATAB X'43' 6 ADVR
DATAB X'63' 7 ADVF
DATAB X'53' 8 BKSR
DATAB X'73' 9 BKXF
DATAB X'01' A UPSPACE (REALLY A WRITE)
DATAB X'A3' B ERASE
SPACE 3
* TIMER TABLE VALUES
*
* ENTRIES CORRESPOND ONE-FOR-ONE WITH ENTRIES IN OTAB
* AND REPRESENT THE MAXIMUM NUMBER OF SECONDS WHICH THE
* CORRESPONDING FUNCTION WOULD REQUIRE TO COMPLETE ON A 25 IPS
* TAPE DRIVE ON WHICH WAS MOUNTED A 2400 ft REEL OF TAPE.
BOUND 1W
TIMETBL DATAH 0 OPEN
DATAH 2 REWIND
DATAH 128 READ ASSUME TRANSFER OF 128K
DATAH 128 WRITE ASSUME TRANSFER OF 128K
DATAH 2 WRITE END-OF-FILE
DATAH 0 EXECUTE CHANNEL PROGRAM
DATAH 2 ADVANCE RECORD
DATAH 1152 SPACE FORWARD TO END-OF-FILE
DATAH 2 BACKSPACE RECORD
DATAH 1152 SPACE BACKWARD TO END-OF-FILE
DATAH 2 UPSPACE
DATAH 2 ERASE
DATAH 0 EJECT
DATAH 0 CLOSE
DATAH 0 TERM
DATAH 0 TEST
TOENTS EQU $-TIMETBL/2 NUMBER OF ENTRIES IN TABLE
SPACE 2
*
* HANDLER OP CODE VECTOR TABLE
*
BOUND 1W
OTAB EQU $
ACH OPEN 0 OPEN
ACH RWND 1 RWND
ACH READ 2 READ
ACH WRITE 3 WRITE
ACH WEOF 4 WEOF
ACH XCHANP 5 EXECUTE CHANNEL PROGRAM
ACH ADVR 6 ADVR
ACH ADVF 7 ADVF
ACH BKSR 8 BKSR
ACH BKSF 9 BKSF
ACH UPSP A UPSP
ACH ERASE B ERASE
ACH EJCT C EJCT
ACH CLOSE D CLOSE
ACH TERM E TERM
ACH TEST F TEST
SPACE 3
#endif
#define CMD u3
/* BTP tape commands */
#define MT_INCH 0x00 /* Initialize channel command */
@ -436,8 +375,10 @@ DEVICE mtb_dev = {
/* start an I/O operation */
uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
{
uint16 chsa = GET_UADDR(uptr->CMD);
DEVICE *dptr = get_dev(uptr);
int unit = (uptr - dptr->units);
CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd entry chan %04x cmd %02x\n", chan, cmd);
if (mt_busy[GET_DEV_BUF(dptr->flags)] != 0 || (uptr->CMD & MT_CMDMSK) != 0) {
@ -450,10 +391,12 @@ uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
switch (cmd & 0xFF) {
case 0x00: /* INCH command */
/* POS has INCH buffer address and us9 the count */
/* just return OK and channel software will use POS as status buffer */
sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd INCH done unit %04x cmd %02x\n",
unit, cmd);
sim_debug(DEBUG_CMD, dptr, "start INCH command\n");
sim_debug(DEBUG_CMD, dptr,
"mt_startcmd starting INCH %06x cmd, chsa %04x MemBuf %08x cnt %04x\n",
uptr->u4, chsa, chp->ccw_addr, chp->ccw_count);
/* UTX_needs_interrupt */
cmd = MT_CMDMSK; /* insert INCH cmd as 0xff */
/* fall through */
@ -477,7 +420,6 @@ uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
uptr->SNS = (uptr->SNS & 0x0000ff00); /* clear all but byte 2 */
uptr->SNS |= (SNS_RDY|SNS_ONLN); /* set ready status */
/* Fall through */
// case 0x4: /* Sense */
if (sim_tape_wrp(uptr))
uptr->SNS |= (SNS_WRP); /* write protected */
if (sim_tape_bot(uptr))
@ -572,28 +514,71 @@ t_stat mt_srv(UNIT *uptr)
int unit = (uptr - dptr->units);
int cmd = uptr->CMD & MT_CMDMSK;
int bufnum = GET_DEV_BUF(dptr->flags);
CHANP *chp = find_chanp_ptr(addr); /* find the chanp pointer */
t_mtrlnt reclen;
t_stat r = SCPE_ARG; /* Force error if not set */
t_stat r = SCPE_ARG; /* Force error if not set */
int i;
uint32 mema;
uint16 len;
uint8 ch;
uint8 zc = 0;
uint8 buf[1024];
sim_debug(DEBUG_DETAIL, &mta_dev, "mt_srv unit %04x cmd %02x\n", unit, cmd);
if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */
uptr->SNS |= SNS_INTVENT; /* unit intervention required */
mt_busy[bufnum] &= ~1; /* make our buffer not busy */
if (cmd != MT_SENSE) { /* we are completed with unit check status */
if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */
uptr->SNS |= SNS_INTVENT; /* unit intervention required */
mt_busy[bufnum] &= ~1; /* make our buffer not busy */
if (cmd != MT_SENSE) { /* we are completed with unit check status */
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
return SCPE_OK;
}
}
switch (cmd) {
case MT_CMDMSK: /* 0x0ff for inch 0x00 */ /* INCH is for channel, nothing for us */
case MT_CMDMSK: /* 0x0ff for inch 0x00 */ /* INCH is for channel, nothing for us */
len = chp->ccw_count; /* INCH command count */
mema = chp->ccw_addr; /* get inch or buffer addr */
sim_debug(DEBUG_CMD, dptr,
"mt_srv starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n",
mema, addr, chp->ccw_addr, chp->ccw_count);
if (len == 0) {
/* we have invalid count, error, bail out */
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
for (i=0; i < len; i++) {
if (chan_read_byte(addr, &buf[i])) {
/* we have error, bail out */
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
/* just dump data */
}
/* uptr->POS has INCH buffer address, just leave it */
sim_debug(DEBUG_CMD, &mta_dev, "mt_srv cmd 0 INCH unit=%04x\n", unit);
uptr->CMD &= ~MT_CMDMSK; /* clear the cmd */
mt_busy[bufnum] &= ~1; /* make our buffer not busy */
chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* we are done dev|chan end */
/* the chp->ccw_addr location contains the inch address */
/* call set_inch() to setup inch buffer */
i = set_inch(uptr, mema); /* new address */
#ifdef NOTYET
if ((i == SCPE_MEM) || (i == SCPE_ARG)) { /* any error */
/* we have error, bail out */
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
#endif
sim_debug(DEBUG_CMD, dptr,
"mt_srv cmd INCH chsa %04x addr %06x count %04x completed\n",
addr, mema, chp->ccw_count);
uptr->CMD &= ~MT_CMDMSK; /* clear the cmd */
mt_busy[bufnum] &= ~1; /* make our buffer not busy */
chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* we are done dev|chan end */
break;
#ifndef FIX_DIAG
@ -976,7 +961,7 @@ t_stat mt_srv(UNIT *uptr)
uptr->CMD &= ~(MT_CMDMSK);
mt_busy[bufnum] &= ~1;
sim_debug(DEBUG_CMD, &mta_dev, "Skip record at EOT\n");
//BAD chan_end(addr, SNS_DEVEND|SNS_UNITCHK); //NEW chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
//BAD chan_end(addr, SNS_DEVEND|SNS_UNITCHK);
chan_end(addr, SNS_DEVEND|SNS_UNITEXP);
break;
}
@ -1019,7 +1004,7 @@ t_stat mt_srv(UNIT *uptr)
uptr->SNS &= ~SNS_LOAD; /* reset BOT */
mt_busy[bufnum] &= ~1;
sim_debug(DEBUG_CMD, &mta_dev, "Skip file got EOT sense %08x unit %02x\n", uptr->SNS, unit);
//BAD chan_end(addr, SNS_DEVEND|SNS_UNITCHK); //NEW chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
//BAD chan_end(addr, SNS_DEVEND|SNS_UNITCHK);
chan_end(addr, SNS_DEVEND|SNS_UNITEXP);
break;
}
@ -1032,7 +1017,8 @@ t_stat mt_srv(UNIT *uptr)
uptr->SNS |= SNS_CMDREJ;
uptr->CMD &= ~MT_CMDMSK;
mt_busy[bufnum] &= ~1;
chan_end(addr, SNS_DEVEND|SNS_UNITCHK); //NEW chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
//BAD chan_end(addr, SNS_DEVEND|SNS_UNITCHK);
chan_end(addr, SNS_DEVEND|SNS_UNITEXP);
} else {
uptr->POS ++;
sim_activate(uptr, 500);
@ -1048,7 +1034,7 @@ t_stat mt_srv(UNIT *uptr)
uptr->CMD &= ~(MT_CMDMSK);
mt_busy[bufnum] &= ~1;
/* we are done dev|chan end */
chan_end(addr, SNS_DEVEND); //NEW chan_end(addr, SNS_CHNEND|SNS_DEVEND);
chan_end(addr, SNS_DEVEND);
break;
}
break;
@ -1118,6 +1104,9 @@ t_stat mt_attach(UNIT *uptr, CONST char *file)
return r; /* report any error */
}
sim_debug(DEBUG_EXP, &mta_dev, "mt_attach complete filename %s\n", file);
uptr->CMD &= ~0xffff; /* clear out the flags but leave ch/sa */
uptr->POS = 0; /* clear position data */
uptr->SNS = 0; /* clear sense data */
set_devattn(addr, SNS_DEVEND); /* ready int???? */
return SCPE_OK; /* return good status */
}
@ -1127,6 +1116,8 @@ t_stat mt_detach(UNIT *uptr)
{
sim_debug(DEBUG_EXP, &mta_dev, "mt_detach\n");
uptr->CMD &= ~0xffff; /* clear out the flags but leave ch/sa */
uptr->POS = 0; /* clear position data */
uptr->SNS = 0; /* clear sense data */
return sim_tape_detach(uptr);
}

View File

@ -32,6 +32,8 @@ extern void set_devattn(uint16 addr, uint8 flags);
extern t_stat chan_boot(uint16 addr, DEVICE *dptr);
extern int test_write_byte_end(uint16 chsa);
extern DEVICE *get_dev(UNIT *uptr);
extern t_stat set_inch(UNIT *uptr, uint32 inch_addr); /* set channel inch address */
extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */
extern uint32 M[]; /* our memory */
extern uint32 SPAD[]; /* cpu SPAD memory */
@ -40,6 +42,34 @@ extern uint32 SPAD[]; /* cpu SPAD memory */
#define UNIT_SCFI UNIT_ATTABLE | UNIT_IDLE | UNIT_DISABLE
/* useful conversions */
/* Fill STAR value from cyl, trk, sec data */
#define CHS2STAR(c,h,s) (((c<<16) & 0xffff0000)|((h<<8) & 0xff00)|(s & 0xff))
/* convert STAR value to number of sectors */
#define STAR2SEC(star,spt,spc) ((star&0xff)+(((star>>8)&0xff)*spt)+((star>>16)*spc))
/* convert STAR value to number of heads or tracks */
#define STAR2TRK(star,tpc) ((star >> 16) * tpc + ((star >> 8) & 0x0ff))
/* convert STAR value to number of cylinders */
#define STAR2CYL(star) ((star >> 16) & 0xffff)
/* convert byte value to number of sectors mod sector size */
#define BYTES2SEC(bytes,ssize) (((bytes) + (ssize-1)) >> 10)
/* get sectors per track for specified type */
#define SPT(type) (scfi_type[type].spt)
/* get sectors per cylinderfor specified type */
#define SPC(type) (scfi_type[type].spt*scfi_type[type].nhds)
/* get number of cylinders for specified type */
#define CYL(type) (scfi_type[type].cyl)
/* get number of heads for specified type */
#define HDS(type) (scfi_type[type].nhds)
/* get disk capacity in sectors for specified type */
#define CAP(type) (CYL(type)*HDS(type)*SPT(type))
/* get number of bytes per sector for specified type */
#define SSB(type) (scfi_type[type].ssiz*4)
/* get disk capacity in bytes for specified type */
#define CAPB(type) (CAP(type)*SSB(type))
/* get disk geometry as STAR value for specified type */
#define GEOM(type) (CHS2STAR(CYL(type),HDS(type),SPT(type)))
/* INCH command information */
/*
WD 0 - Data address
@ -165,10 +195,12 @@ bits 24-31 - FHD head count (number of heads on FHD or number head on FHD option
#define SNS_RTAE 0x02 /* Reserve track access error */
#define SNS_UESS 0x01 /* Uncorrectable ECC error */
#define ATTR u6
/* u6 */
/* u6 holds drive attribute entry */
/* provided by inch command for controller */
#define CHS u6
/* u6 holds the current cyl, hd, sec for the drive */
/* this attribute information is provided by the INCH command */
/* for each device and is not used. It is reconstructed from */
/* the disk_t structure data for the assigned disk */
/*
bits 0-7 - Flags
bits 0&1 - 00=Reserved, 01=MHD, 10=FHD, 11=MHD with FHD option
@ -176,24 +208,15 @@ bits 0-7 - Flags
bit 3 - 0=Reserved
bit 4 - 1=Drive not present
bit 5 - 1=Dual Port
bit 6 - 0=Reserved
bit 7 - 0=Reserved
bit 6 - 0=Reserved 00 768 byte sec
bit 7 - 0=Reserved 01 1024 byte sec
bits 8-15 - sector count (sectors per track)(F16=16, F20=20)
bits 16-23 - MHD Head count (number of heads on MHD)
bits 24-31 - FHD head count (number of heads on FHD or number head on FHD option of
mini-module)
*/
#define DDATA up7
/* Pointer held in up7 */
/* sects/cylinder = sects/track * numhds */
/* allocated during attach command for each unit defined */
struct ddata_t
{
uint16 cyl; /* Cylinder head at */
uint16 tpos; /* Track position */
uint16 spos; /* Sector position */
};
/* Not Used up7 */
/* disk definition structure */
struct scfi_t
@ -205,7 +228,9 @@ struct scfi_t
uint16 ucyl; /* Number of cylinders used */
uint16 cyl; /* Number of cylinders on disk */
uint8 type; /* Device type code */
uint32 geom; /* disk star geometry cyl(16) hsd(8) sec(8) */
/* bit 1 mhd */
/* bits 6/7 = 0 768 byte blk */ /* not used on UDP/DPII */
/* = 1 1024 byte blk */ /* not used on UDP/DPII */
}
scfi_type[] =
@ -219,49 +244,6 @@ scfi_type[] =
{NULL, 0}
};
#if 0
*****************************************************************
* DEVICE ID TABLE
*****************************************************************
SPACE
BOUND 1W
DID.TBL EQU $
*
*DEVICE ID NAME..................................................
*TOTAL ALLOC. UNITS..................................... :
*BIT MAP SIZE .............................. : :
*NO. OF HEADS ........................ : : :
*SECTOR SIZE ................... : : : :
*SECTORS/TRACK .............. : : : : :
*SECTORS/ALOC. UNIT.......... : : : : : :
*SECTORS/BLOCK ....... : : : : : : :
*OLD DEVICE ID NAME.... : : : : : : : :
* : : : : : : : : :
* ......:..:..:...:....:....:.....:......:........:
DID FORM 32, 8, 8, 8, 8, 16, 16, 32, 64
SPACE
* CLASS 'F' EXTENDED I/O DISC DEVICES
DID C'DF01', 3, 3, 26, 64, 2, , 1334, C'FL001'
DID C'DF02', 1, 2, 20, 192, 5, 625, 20000, C'MH040'
DID C'DF03', 1, 2, 20, 192, 5, 1250, 40000, C'MH080'
DID C'DF04', 1, 4, 20, 192, 19, 2375, 76000, C'MH300'
DID C'DF0E', 1,16, 20, 192, 1, 2732, 87400, C'MH1GB'
DID C'DF05', 1, 1, 20, 192, 4, 184, 5120, C'FH005'
DID C'DF06', 1, 2, 20, 192, 1, 250, 8000, C'CD032'
DID C'DF07', 1, 2, 20, 192, 3, 750, 24000, C'CD064'
DID C'DF08', 1, 2, 20, 192, 1, 250, 8000, C'CD096'
DID C'DF08', 1, 2, 20, 192, 5, 1250, 40000, C'CD096'
DID C'DF09', 1, 8, 20, 192, 40, 2500, 80000, C'MH600'
DID C'DF0A', 1, 8, 20, 192, 40, 2500, 80000, C'FM600'
DID C'DF0B', 1, 8, 20, 192, 1, 1711, 5472, C'SG038'
DID C'DF0C', 1, 8, 20, 192, 1, 5464,174848, C'SG120'
DID C'DF0D', 1, 8, 20, 192, 1, 3491,116808, C'SG076'
DID C'DF0B', 1, 8, 20, 192, 1, 1711, 54752, C'SG038'
DID C'DF0C', 1, 8, 20, 192, 1, 5464,174848, C'SG120'
DID C'DF0D', 1, 8, 20, 192, 1, 3491,116808, C'SG076'
*
#endif
uint8 scfi_preio(UNIT *uptr, uint16 chan);
uint8 scfi_startcmd(UNIT *uptr, uint16 chan, uint8 cmd);
uint8 scfi_haltio(uint16 addr);
@ -370,17 +352,30 @@ DEVICE sdb_dev = {
};
#endif
/* convert sector disk address to star values (c,h,s) */
uint32 scfisec2star(uint32 daddr, int type)
{
int32 sec = daddr % scfi_type[type].spt; /* get sector value */
int32 spc = scfi_type[type].nhds * scfi_type[type].spt; /* sec per cyl */
int32 cyl = daddr / spc; /* cylinders */
int32 hds = (daddr % spc) / scfi_type[type].spt; /* heads */
/* now return the star value */
return (CHS2STAR(cyl,hds,sec)); /* return STAR */
}
/* start a disk operation */
uint8 scfi_preio(UNIT *uptr, uint16 chan)
{
DEVICE *dptr = get_dev(uptr);
int unit = (uptr - dptr->units);
DEVICE *dptr = get_dev(uptr);
uint16 chsa = GET_UADDR(uptr->CMD);
int unit = (uptr - dptr->units);
sim_debug(DEBUG_CMD, dptr, "scfi_preio CMD %08x unit=%02x\n", uptr->CMD, unit);
if ((uptr->CMD & 0xff00) != 0) { /* just return if busy */
return SNS_BSY;
}
sim_debug(DEBUG_CMD, dptr, "scfi_preio unit=%02x\n", unit);
sim_debug(DEBUG_CMD, dptr, "scfi_preio unit %02x chsa %04x OK\n", unit, chsa);
return 0; /* good to go */
}
@ -389,9 +384,11 @@ uint8 scfi_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
uint16 addr = GET_UADDR(uptr->CMD);
DEVICE *dptr = get_dev(uptr);
int unit = (uptr - dptr->units);
uint8 ch;
CHANP *chp = find_chanp_ptr(addr); /* find the chanp pointer */
sim_debug(DEBUG_CMD, dptr, "scfi_startcmd unit %02x cmd %04x CMD %08x\n", unit, cmd, uptr->CMD);
sim_debug(DEBUG_CMD, dptr,
"scfi_startcmd unit %02x cmd %04x CMD %08x\n",
unit, cmd, uptr->CMD);
if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */
uptr->SNS |= SNS_INTVENT; /* unit intervention required */
if (cmd != DSK_SNS) /* we are completed with unit check status */
@ -407,114 +404,21 @@ uint8 scfi_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
}
sim_debug(DEBUG_CMD, dptr, "scfi_startcmd CMD 2 unit=%02x cmd %02x\n", unit, cmd);
if ((uptr->flags & UNIT_ATT) == 0) { /* see if unit is attached */
if (cmd == DSK_SNS) { /* not attached, is cmd Sense 0x04 */
sim_debug(DEBUG_CMD, dptr, "scfi_startcmd CMD sense\n");
/* bytes 0,1 - Cyl entry from STAR reg in STAR */
ch = (uptr->STAR >> 24) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b0 unit=%02x 1 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
ch = (uptr->STAR >> 16) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b1 unit=%02x 1 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
/* byte 2 - Track entry from STAR reg in STAR */
ch = (uptr->STAR >> 8) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b2 unit=%02x 1 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
/* byte 3 - Sector entry from STAR reg in STAR */
ch = (uptr->STAR) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b3 unit=%02x 1 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
/* bytes 4 - mode reg, byte 0 of SNS */
ch = (uptr->SNS >> 24) & 0xff; /* return the sense data for device */
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%02x 1 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
/* bytes 5-7 - status bytes, bytes 1-3 of SNS */
ch = (uptr->SNS >> 16) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%02x 2 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
ch = (uptr->SNS >> 8) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%02x 3 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
ch = (uptr->SNS) & 0xff;
sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%02x 4 %02x\n",
unit, ch);
chan_write_byte(addr, &ch) ;
/* bytes 8-11 - drive attribute register (DATR) entries from uptr->ATTR
* via INCH cmd */
ch = (uptr->ATTR >> 24) & 0xff;
chan_write_byte(addr, &ch) ;
ch = (uptr->ATTR >> 16) & 0xff;
chan_write_byte(addr, &ch) ;
ch = (uptr->ATTR >> 8 ) & 0xff;
chan_write_byte(addr, &ch) ;
ch = (uptr->ATTR >> 0) & 0xff;
chan_write_byte(addr, &ch) ;
/* bytes 12 & 13 contain drive related status */
ch = 0; /* zero for now */
chan_write_byte(addr, &ch) ;
chan_write_byte(addr, &ch) ;
uptr->SNS &= 0xff000000; /* clear status bytes, but leave mode data */
return SNS_CHNEND|SNS_DEVEND;
}
if (cmd == 0x0) /* INCH cmd gives unit check */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
uptr->SNS |= (SNS_INTVENT|SNS_CMDREJ); /* set new error status */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* we done */
}
/* Unit is online, so process a command */
switch (cmd) {
case DSK_INCH: /* INCH 0x00 */
{
uint32 mema; /* memory address */
uint32 i;
UNIT *up = dptr->units; /* first unit for this device */
case DSK_INCH: /* INCH 0x00 */
sim_debug(DEBUG_CMD, dptr,
"scfi_startcmd starting inch cmd addr %04x STAR %08x\n",
addr, uptr->STAR);
/* STAR (u4) has IOCD word 1 contents. For the disk processor it contains */
/* a pointer to the INCH buffer followed by 8 drive attribute words that */
/* contains the flags, sector count, MHD head count, and FHD count */
/* us9 has the byte count from IOCD wd2 and should be 0x24 (36) */
/* the INCH buffer address must be returned in STAR and us9 left non-zero */
/* just return OK and channel software will use up8 as status buffer */
mema = (uint32)uptr->STAR; /* get memory address of buffer */
uptr->STAR = M[mema>>2]; /* get status buffer address for XIO return status */
sim_debug(DEBUG_CMD, dptr,
"scfi_startcmd starting inch cmd addr %04x STAR %08x mema %08x units %02x\n",
addr, uptr->STAR, mema, dptr->numunits);
/* the next 8 words have drive data for each unit */
/* WARNING 8 drives must be defined for this controller */
/* so we will not have a map fault */
for (i=0; i<dptr->numunits && i<8; i++) { /* process all drives */
up->ATTR = M[(mema>>2)+i+1]; /* save each unit's drive data */
sim_debug(DEBUG_CMD, dptr,
"scfi_startcmd ATTR data %08x unit %02x flags %02x sec %02x MHD %02x FHD %02x\n",
up->ATTR, i, (up->ATTR >> 24)&0xff, (up->ATTR >> 16)&0xff,
(up->ATTR >> 8)&0xff, (up->ATTR&0xff));
up++; /* next unit for this device */
}
sim_debug(DEBUG_CMD, dptr, "scfi_startcmd done INCH cmd addr %04x\n", addr);
"scfi_startcmd starting INCH %06x cmd, chsa %04x MemBuf %08x cnt %04x\n",
uptr->u4, addr, chp->ccw_addr, chp->ccw_count);
uptr->CMD |= DSK_INCH2; /* use 0xf0 for inch, just need int */
sim_activate(uptr, 20); /* start things off */
return 0;
break;
}
case DSK_SCK: /* Seek command 0x07 */
case DSK_XEZ: /* Rezero & Read IPL record 0x1f */
uptr->CMD &= ~(DSK_STAR); /* show we do not have seek STAR in STAR */
case DSK_WD: /* Write command 0x01 */
case DSK_RD: /* Read command 0x02 */
case DSK_LMR: /* read mode register */
@ -554,25 +458,23 @@ t_stat scfi_srv(UNIT *uptr)
DEVICE *dptr = get_dev(uptr);
/* get pointer to Dev Info Blk for this device */
DIB *dibp = (DIB *)dptr->ctxt;
CHANP *chp = (CHANP *)dibp->chan_prg; /* get pointer to channel program */
struct ddata_t *data = (struct ddata_t *)(uptr->up7);
CHANP *chp = (CHANP *)dibp->chan_prg; /* get pointer to channel program */
int cmd = uptr->CMD & DSK_CMDMSK;
int type = GET_TYPE(uptr->flags);
uint32 trk, cyl;
uint32 trk, cyl, sec;
int unit = (uptr - dptr->units);
int len;
int dlen = 0; /* total bytes processed */
int len=0;
int i;
uint8 ch;
uint16 ssize = scfi_type[type].ssiz*4; /* Size of one sector in bytes */
int tsize = scfi_type[type].spt * ssize; /* get track size in bytes */
int32 tstart = 0; /* Location of start of cyl/track/sect in data */
uint16 ssize = scfi_type[type].ssiz*4; /* Size of one sector in bytes */
int32 tstart = 0; /* Location of start of cyl/track/sect in data */
uint8 buf2[1024];
uint8 buf[1024];
sim_debug(DEBUG_DETAIL, &sda_dev,
"scfi_srv entry unit %02x cmd %02x chsa %04x chan %04x count %04x\n",
unit, cmd, chsa, chsa>>8, chp->ccw_count);
"scfi_srv entry unit %02x CMD %08x chsa %04x count %04x %x/%x/%x \n",
unit, uptr->CMD, chsa, chp->ccw_count,
STAR2CYL(uptr->CHS), (uptr->CHS >> 8)&0xff, (uptr->CHS&0xff));
if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */
uptr->SNS |= SNS_INTVENT; /* unit intervention required */
@ -581,17 +483,92 @@ t_stat scfi_srv(UNIT *uptr)
}
sim_debug(DEBUG_CMD, dptr,
"scfi_srv cmd=%02x chsa %04x count %04x\n",
cmd, chsa, chp->ccw_count);
"scfi_srv cmd=%02x chsa %04x count %04x\n", cmd, chsa, chp->ccw_count);
switch (cmd) {
case 0: /* No command, stop disk */
break;
case DSK_INCH2: /* use 0xff for inch, just need int */
{
uint32 mema; /* memory address */
// uint32 daws[8]; /* drive attribute registers */
// uint32 i, j;
uint32 i;
len = chp->ccw_count; /* INCH command count */
mema = chp->ccw_addr; /* get inch or buffer addr */
sim_debug(DEBUG_CMD, dptr,
"scfi_srv starting INCH cmd, chsa %04x MemBuf %06x cnt %04x\n",
chsa, chp->ccw_addr, chp->ccw_count);
/* mema has IOCD word 1 contents. For the disk processor it contains */
/* a pointer to the INCH buffer followed by 8 drive attribute words that */
/* contains the flags, sector count, MHD head count, and FHD count */
/* len has the byte count from IOCD wd2 and should be 0x24 (36) */
/* the INCH buffer address must be set for the parrent channel as well */
/* as all other devices on the channel. Call set_inch() to do this for us */
/* just return OK and channel software will use u4 as status buffer addr */
len = chp->ccw_count; /* INCH command count */
if (len != 36) {
/* we have invalid count, error, bail out */
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
/* read all 36 bytes, stopping every 4 bytes to make words */
/* the first word has the inch buffer address */
/* the next 8 words have drive data for each unit */
/* WARNING 8 drives must be defined for this controller */
/* so we will not have a map fault */
// for (i=0, j=0; i < 36; i++) {
for (i=0; i < 36; i++) {
if (chan_read_byte(chsa, &buf[i])) {
/* we have error, bail out */
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
if (((i+1)%4) == 0) { /* see if we have a word yet */
if (i == 3)
/* inch buffer address */
mema = (buf[0]<<24) | (buf[1]<<16) |
(buf[2]<<8) | (buf[3]);
else
/* drive attribute registers */
// daws[j++] = (buf[i-3]<<24) | (buf[i-2]<<16)
// | (buf[i-1]<<8) | (buf[i]);
/* may want to use this later */
/* clear warning errors */
tstart = (buf[i-3]<<24) | (buf[i-2]<<16)
| (buf[i-1]<<8) | (buf[i]);
}
}
/* now call set_inch() function to write and test inch bybber addresses */
i = set_inch(uptr, mema); /* new address */
#ifdef NOTYET
if ((i == SCPE_MEM) || (i == SCPE_ARG)) { /* any error */
/* we have error, bail out */
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
#endif
uptr->CMD &= ~(0xffff); /* remove old cmd */
sim_debug(DEBUG_CMD, dptr,
"scfi_srv cmd INCH chsa %04x count %04x completed\n", chsa, chp->ccw_count);
chan_end(chsa, SNS_CHNEND); /* return just channel end */
"scfi_srv cmd INCH chsa %04x addr %06x count %04x completed\n",
chsa, mema, chp->ccw_count);
#ifdef FIX4MPX
chan_end(chsa, SNS_CHNEND); /* return just channel end OK */
#else
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */
#endif
}
break;
case DSK_NOP: /* NOP 0x03 */
@ -623,58 +600,23 @@ t_stat scfi_srv(UNIT *uptr)
break;
case DSK_SCK: /* Seek cylinder, track, sector 0x07 */
/* If we are waiting on seek to finish, check if there yet. */
if (uptr->CMD & DSK_SEEKING) {
/* see if on cylinder yet */
if ((uptr->STAR >> 16) == data->cyl) {
if (STAR2CYL(uptr->STAR) == STAR2CYL(uptr->CHS)) {
/* we are on cylinder, seek is done */
sim_debug(DEBUG_CMD, dptr, "scfi_srv seek on cylinder unit=%02x %04x %04x\n",
unit, uptr->STAR >> 16, data->cyl);
unit, uptr->STAR >> 16, uptr->CHS >> 16);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
set_devattn(chsa, SNS_DEVEND); /* start the operation */
sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek end unit=%02x %04x %04x\n",
unit, uptr->STAR >> 16, data->cyl);
/* we have already seeked to the required sector */
/* we do not need to seek again, so move on */
chan_end(chsa, SNS_DEVEND|SNS_CHNEND);
sim_activate(uptr, 20);
break;
} else {
/* Compute delay based of difference. */
/* Set next state = index */
i = (uptr->STAR >> 16) - data->cyl;
sim_debug(DEBUG_CMD, dptr, "scfi_srv seek unit=%02x %04x %04x\n",
unit, uptr->STAR >> 16, i);
if (i > 0 ) {
if (i > 50) {
data->cyl += 50; /* seek 50 cyl */
sim_activate(uptr, 800);
} else
if (i > 20) {
data->cyl += 20; /* seek 20 cyl */
sim_activate(uptr, 400);
} else {
data->cyl++; /* Seek 1 cyl */
sim_activate(uptr, 200);
}
if (data->cyl >= scfi_type[type].cyl) /* test for over max */
data->cyl = scfi_type[type].cyl-1; /* make max */
} else {
if (i < -50) {
data->cyl -= 50; /* seek 50 cyl */
sim_activate(uptr, 800);
} else
if (i < -20) {
data->cyl -= 20; /* seek 20 cyl */
sim_activate(uptr, 400);
} else {
data->cyl--; /* seek 1 cyl */
sim_activate(uptr, 200);
}
if ((int32)data->cyl < 0) /* test for less than zero */
data->cyl = 0; /* make zero */
}
sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek next unit=%02x %04x %04x\n",
unit, uptr->STAR >> 16, data->cyl);
sim_activate(uptr, 2);
/* we have wasted enough time, we there */
uptr->CHS = uptr->STAR; /* we are there */
sim_activate(uptr, 10);
break;
}
}
@ -690,26 +632,35 @@ t_stat scfi_srv(UNIT *uptr)
break;
}
}
rezero:
sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek unit=%02x star %02x %02x %02x %02x\n",
/* the value is really a sector offset for the disk */
/* but will treat as c/h/s for processing */
/* the cyl, trk, and sect are ready to update */
sim_debug(DEBUG_CMD, dptr,
"scfi_srv STAR unit=%02x star %02x %02x %02x %02x\n",
unit, buf[0], buf[1], buf[2], buf[3]);
rezero:
sim_debug(DEBUG_DETAIL, dptr,
"scfi_srv seek unit=%02x star %02x %02x %02x %02x\n",
unit, buf[0], buf[1], buf[2], buf[3]);
/* save STAR (target sector) data in STAR */
uptr->STAR = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
cyl = uptr->STAR >> 16; /* get the cylinder */
cyl = STAR2CYL(uptr->STAR); /* get the cylinder */
trk = buf[2]; /* get the track */
sim_debug(DEBUG_DETAIL, dptr, "scfi_srv SEEK %08x cyl %04x trk %02x sec %02x unit=%02x\n",
uptr->CMD, cyl&0xffff, trk, buf[3], unit);
sim_debug(DEBUG_DETAIL, dptr, "scfi_srv Disk %s cyl %04x hds %02x sec/trk %02x unit=%02x\n",
scfi_type[type].name, scfi_type[type].cyl, scfi_type[type].nhds, scfi_type[type].spt, unit);
/* FIXME do something with FHD here */
sim_debug(DEBUG_DETAIL, dptr,
"scfi_srv SEEK %08x cyl %04x trk %02x sec %02x unit=%02x\n",
uptr->CMD, cyl&0xffff, trk, buf[3], unit);
/* Check if seek valid */
if (cyl >= scfi_type[type].cyl ||
trk >= scfi_type[type].nhds ||
buf[3] >= scfi_type[type].spt) {
sim_debug(DEBUG_CMD, dptr,
"dsk_srv seek ERROR cyl %04x trk %02x sec %02x unit=%02x\n",
cyl, trk, buf[3], unit);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK; /* set error status */
@ -718,35 +669,36 @@ rezero:
break;
}
uptr->CMD |= DSK_STAR; /* show we have seek STAR in CMD */
/* calc the sector address of data */
/* calc the new sector address of data */
/* calculate file position in bytes of requested sector */
/* file offset in bytes */
tstart = (((cyl * scfi_type[type].nhds * tsize) + (trk * tsize) + buf[3]) * ssize);
data->tpos = trk; /* save the track/head number */
data->spos = buf[3]; /* save the sector number */
tstart = STAR2SEC(uptr->STAR, SPT(type), SPC(type)) * SSB(type);
uptr->CHS = CHS2STAR(STAR2CYL(uptr->CHS), trk, buf[3]);
sim_debug(DEBUG_DETAIL, dptr,
"scfi_srv seek start %08x trk %04x sec %02x\n",
tstart, trk, buf[3]);
/* just seek to the location where we will r/w data */
if ((sim_fseek(uptr->fileref, tstart, SEEK_SET)) != 0) { /* seek home */
sim_debug(DEBUG_DETAIL, dptr, "scfi_srv Error on seek to %08x\n", tstart);
}
/* Check if already on correct cylinder */
if (cyl != data->cyl) {
/* No, Do seek */
/* if not, do a delay to slow things down */
if (STAR2CYL(uptr->STAR) != STAR2CYL(uptr->CHS)) {
/* Do a fake seek to kill time */
uptr->CMD |= DSK_SEEKING; /* show we are seeking */
sim_debug(DEBUG_DETAIL, dptr,
"scfi_srv seek unit=%02x cyl %04x trk %04x sec %04x\n",
"scfi_srv seeking unit=%02x to cyl %04x trk %04x sec %04x\n",
unit, cyl, trk, buf[3]);
sim_activate(uptr, 20);
// chan_end(chsa, SNS_CHNEND);
} else {
/* we are on cylinder/track/sector, so go on */
sim_debug(DEBUG_DETAIL, dptr,
"scfi_srv calc sect addr seek start %08x cyl %04x trk %04x sec %02x\n",
tstart, cyl, trk, buf[3]);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
// sim_activate(uptr, 20);
chan_end(chsa, SNS_DEVEND|SNS_CHNEND);
}
return SCPE_OK;
@ -756,10 +708,10 @@ rezero:
sim_debug(DEBUG_CMD, dptr, "RD REZERO IPL unit=%02x seek 0\n", unit);
/* Do a seek to 0 */
uptr->STAR = 0; /* set STAR to 0, 0, 0 */
uptr->CHS = 0; /* set current CHS to 0, 0, 0 */
uptr->CMD &= ~(0xffff); /* remove old cmd */
uptr->CMD |= DSK_SCK; /* show as seek command */
tstart = 0; /* byte offset is 0 */
dlen = 0; /* no data written yet */
/* Read in 1 dummy character for length to inhibit SLI posting */
if (chan_read_byte(chsa, &buf[0])) {
/* we have error, bail out */
@ -770,7 +722,7 @@ rezero:
}
/* zero stuff */
buf[0] = buf[1] = buf[2] = buf[3] = 0;
goto rezero; /* murge with seek code */
goto rezero; /* merge with seek code */
break;
case DSK_LMR:
@ -783,6 +735,8 @@ rezero:
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
sim_debug(DEBUG_CMD, dptr, "Load Mode Reg unit=%02x old %x new %x\n",
unit, (uptr->SNS)&0xff, buf[0]);
uptr->CMD &= ~(0xffff); /* remove old cmd */
uptr->SNS &= 0x00ffffff; /* clear old mode data */
uptr->SNS |= (buf[0] << 24); /* save mode value */
@ -793,17 +747,24 @@ rezero:
/* tstart has start of sector address in bytes */
if ((uptr->CMD & DSK_READING) == 0) { /* see if we are reading data */
uptr->CMD |= DSK_READING; /* read from disk starting */
dlen = 0; /* no data read yet */
sim_debug(DEBUG_CMD, dptr, "DISK READ starting unit=%02x CMD %08x count %04x\n",
sim_debug(DEBUG_CMD, dptr,
"DISK READ starting unit=%02x CMD %08x count %04x\n",
unit, uptr->CMD, chp->ccw_count);
}
if (uptr->CMD & DSK_READING) { /* see if we are reading data */
cyl = STAR2CYL(uptr->CHS); /* get current cyl */
trk = (uptr->CHS >> 8) & 0xff; /* get trk/head */
sec = uptr->CHS & 0xff; /* get sec */
/* get sector offset */
// tstart = STAR2SEC(uptr->STAR, SPT(type), SPC(type));
tstart = STAR2SEC(uptr->CHS, SPT(type), SPC(type));
/* read in a sector of data from disk */
if ((len=sim_fread(buf, 1, ssize, uptr->fileref)) != ssize) {
sim_debug(DEBUG_CMD, dptr,
"Error %08x on read %04x of diskfile cyl %04x hds %02x sec %02x\n",
len, ssize, data->cyl, data->tpos, data->spos);
len, ssize, cyl, trk, sec);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
@ -811,33 +772,53 @@ rezero:
sim_debug(DEBUG_CMD, dptr, "scfi_srv after READ chsa %04x count %04x\n",
chsa, chp->ccw_count);
/* process the next sector of data */
for (i=0; i<len; i++) {
ch = buf[i]; /* get a char from buffer */
if (chan_write_byte(chsa, &ch)) { /* put a byte to memory */
sim_debug(DEBUG_DATA, dptr,
"DISK Read %04x bytes from diskfile cyl %04x hds %02x sec %02x tstart %08x\n",
dlen+i, data->cyl, data->tpos, data->spos, tstart);
"DISK Read %04x bytes from diskfile /%04x/%02x/%02x tstart %08x\n",
len, cyl, trk, sec, tstart);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
goto rddone;
}
}
dlen += len; /* add byte read to total count */
sim_debug(DEBUG_CMD, dptr,
"DISK READ from sec end %04x bytes end %04x from diskfile cyl %04x hds %02x sec %02x tstart %08x\n",
dlen, ssize, data->cyl, data->tpos, data->spos, tstart);
data->spos++;
"DISK READ from sec end %04x bytes end %04x from diskfile /%04x/%02x/%02x tstart %08x\n",
len, ssize, cyl, trk, sec, tstart);
/* tstart has file offset in sectors */
tstart++; /* bump to next sector */
/* convert sect back to chs value */
uptr->CHS = scfisec2star(tstart, type);
/* see of over end of disk */
// if (tstart >= CAPB(type)) {
if (tstart >= CAP(type)) {
/* EOM reached, abort */
sim_debug(DEBUG_CMD, dptr,
"DISK Read reached EOM for read from disk @ /%04x/%02x/%02x\n",
STAR2CYL(uptr->CHS), (uptr->CHS >> 8)&0xff, (uptr->CHS&0xff));
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->CHS = 0; /* reset cylinder position */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
/* see if we are done reading data */
if (test_write_byte_end(chsa)) {
sim_debug(DEBUG_DATA, dptr,
"DISK Read complete Read %04x bytes from diskfile cyl %04x hds %02x sec %02x tstart %08x\n",
dlen, data->cyl, data->tpos, data->spos, tstart);
"DISK Read complete Read %04x bytes from diskfile /%04x/%02x/%02x tstart %08x\n",
ssize, cyl, trk, sec, tstart);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
break;
} else {
sim_debug(DEBUG_DATA, dptr,
"DISK sector read complete, %x bytes to go from diskfile /%04x/%02x/%02x\n",
chp->ccw_count, STAR2CYL(uptr->CHS), ((uptr->CHS) >> 8)&0xff, (uptr->CHS&0xff));
sim_activate(uptr, 10); /* wait to read next sector */
break;
}
@ -848,14 +829,21 @@ rddone:
case DSK_WD: /* Write Data */
/* tstart has start of sector address in bytes */
if ((uptr->CMD & DSK_WRITING) == 0) { /* see if we are writing data */
uptr->CMD |= DSK_WRITING; /* write to disk starting */
dlen = 0; /* no data written yet */
sim_debug(DEBUG_CMD, dptr,
"DISK WRITE starting unit=%02x CMD %08x bytes %04x\n",
unit, uptr->CMD, dlen);
unit, uptr->CMD, len);
}
if (uptr->CMD & DSK_WRITING) { /* see if we are writing data */
if (uptr->CMD & DSK_WRITING) { /* see if we are writing data */
cyl = STAR2CYL(uptr->CHS); /* get current cyl */
trk = (uptr->CHS >> 8) & 0xff; /* get trk/head */
sec = uptr->CHS & 0xff; /* get sec */
/* get sector offset */
// tstart = STAR2SEC(uptr->STAR, SPT(type), SPC(type));
tstart = STAR2SEC(uptr->CHS, SPT(type), SPC(type));
/* process the next sector of data */
len = 0; /* used here as a flag for short read */
for (i=0; i<ssize; i++) {
@ -865,7 +853,7 @@ rddone:
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
sim_debug(DEBUG_DATA, dptr,
"DISK Wrote %04x bytes to diskfile cyl %04x hds %02x sec %02x tstart %08x\n",
ssize, data->cyl, data->tpos, data->spos, tstart);
ssize, cyl, trk, sec, tstart);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
goto wrdone;
}
@ -874,12 +862,12 @@ rddone:
}
buf2[i] = ch; /* save the char */
}
dlen += ssize; /* add 1 sector of bytes */
/* write the sector to disk */
if ((i=sim_fwrite(buf2, 1, ssize, uptr->fileref)) != ssize) {
sim_debug(DEBUG_CMD, dptr,
"Error %08x on write %04x to diskfile cyl %04x hds %02x sec %02x\n",
i, ssize, data->cyl, data->tpos, data->spos);
i, ssize, cyl, trk, sec);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
@ -887,16 +875,32 @@ rddone:
if (len != 0) { /* see if done with write command */
sim_debug(DEBUG_DATA, dptr,
"DISK WroteB %04x bytes to diskfile cyl %04x hds %02x sec %02x tstart %08x\n",
ssize, data->cyl, data->tpos, data->spos, tstart);
ssize, cyl, trk, sec, tstart);
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
break;
}
sim_debug(DEBUG_CMD, dptr,
"DISK WR to sec end %04x bytes end %04x to diskfile cyl %04x hds %02x sec %02x tstart %08x\n",
dlen, ssize, data->cyl, data->tpos, data->spos, tstart);
data->spos++;
sim_activate(uptr, 10);
len, ssize, cyl, trk, sec, tstart);
/* tstart has file offset in sectors */
tstart++; /* bump to next sector */
/* convert sect back to chs value */
uptr->CHS = scfisec2star(tstart, type);
/* see of over end of disk */
// if (tstart >= CAPB(type)) {
if (tstart >= CAP(type)) {
/* EOM reached, abort */
sim_debug(DEBUG_CMD, dptr,
"DISK Write reached EOM for write to disk @ /%04x/%02x/%02x\n",
STAR2CYL(uptr->CHS), (uptr->CHS >> 8)&0xff, (uptr->CHS&0xff));
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
uptr->CHS = 0; /* reset cylinder position */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
break;
}
sim_activate(uptr, 10); /* keep writing */
break;
wrdone:
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
@ -904,7 +908,7 @@ wrdone:
break;
default:
sim_debug(DEBUG_DETAIL, dptr, "invalid command %02x unit %02x\n", cmd, unit);
sim_debug(DEBUG_CMD, dptr, "invalid command %02x unit %02x\n", cmd, unit);
uptr->SNS |= SNS_CMDREJ;
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
@ -919,16 +923,12 @@ wrdone:
void scfi_ini(UNIT *uptr, t_bool f)
{
DEVICE *dptr = get_dev(uptr);
uint32 i = GET_TYPE(uptr->flags);
// uint32 ssize = scfi_type[i].ssiz * 4; /* disk sector size in bytes */
uint32 tsize = scfi_type[i].spt; /* get track size in sectors */
uint32 csize = scfi_type[i].nhds * tsize; /* get cylinder size in sectors */
/* capacity is total cylinders time sectors per cylinder */
uint32 tdisk = scfi_type[i].cyl * csize; /* get total disk size in sectors */
int i = GET_TYPE(uptr->flags);
uptr->CMD &= ~0xffff; /* clear out the flags but leave ch/sa */
uptr->SNS = ((uptr->SNS & 0x00ffffff) | (scfi_type[i].type << 24)); /* save mode value */
/* total sectors on disk */
uptr->capac = tdisk; /* disk size in sectors */
uptr->capac = CAP(i); /* disk size in sectors */
sim_debug(DEBUG_EXP, &sda_dev, "SDA init device %s on unit SDA%.1x cap %x\n",
dptr->name, GET_UADDR(uptr->CMD), uptr->CMD);
@ -976,7 +976,7 @@ int scfi_format(UNIT *uptr) {
buff[2] = 'R';
buff[3] = 'O';
sim_debug(DEBUG_CMD, dptr,
"Creating disk file of trk size %04x capacity %d\n",
"Creating disk file of trk size %04x bytes, capacity %d\n",
tsize*ssize, cap*ssize);
/* write zeros to each track of the disk */
for (cyl = 0; cyl < cylv; cyl++) {
@ -991,7 +991,7 @@ int scfi_format(UNIT *uptr) {
buff[3] = 0;
}
}
if ((cyl % 400) == 0)
if ((cyl % 100) == 0)
fputc('.', stderr);
fputc('\r', stderr);
fputc('\n', stderr);
@ -1006,41 +1006,27 @@ int scfi_format(UNIT *uptr) {
t_stat scfi_attach(UNIT *uptr, CONST char *file) {
uint16 addr = GET_UADDR(uptr->CMD);
int type = GET_TYPE(uptr->flags);
// DEVICE *dptr = get_dev(uptr);
DEVICE *dptr = get_dev(uptr);
t_stat r;
uint32 tsize; /* track size in bytes */
uint32 ssize; /* sector size in bytes */
uint32 csize, tdisk;
struct ddata_t *data;
uint8 buff[1024];
/* have simulator attach the file to the unit */
if ((r = attach_unit(uptr, file)) != SCPE_OK)
return r;
if (scfi_type[type].name == 0) { /* does the assigned disk have a name */
detach_unit(uptr); /* no, reject */
return SCPE_FMT; /* error */
}
/* get a buffer to hold scfi_t structure */
/* extended data structure per unit */
if ((data = (struct ddata_t *)calloc(1, sizeof(struct ddata_t))) == 0) {
detach_unit(uptr);
return SCPE_FMT;
}
/* have simulator attach the file to the unit */
if ((r = attach_unit(uptr, file)) != SCPE_OK)
return r;
uptr->up7 = (void *)data; /* save pointer to structure in up7 */
/* track size in bytes is sectors/track times words/sector time 4 bytse/word */
ssize = scfi_type[type].ssiz * 4; /* disk sector size in bytes */
tsize = scfi_type[type].spt; /* get track size in sectors */
csize = scfi_type[type].nhds * tsize; /* get cylinder size in sectors */
/* capacity is total cylinders time sectors per cylinder */
tdisk = scfi_type[type].cyl * csize; /* get total disk size in sectors */
uptr->capac = tdisk; /* disk capacity in sectors */
uptr->capac = CAP(type); /* disk capacity in sectors */
ssize = SSB(type); /* get sector size in bytes */
sim_debug(DEBUG_CMD, dptr, "Disk %s cyl %d hds %d sec %d ssiz %d capacity %d\n",
scfi_type[type].name, scfi_type[type].cyl, scfi_type[type].nhds,
scfi_type[type].spt, ssize, uptr->capac); /* disk capacity */
sim_debug(DEBUG_CMD, &sda_dev, "Disk cyl %d spt %d ssiz %d capacity %d\n",
csize, tsize, ssize, uptr->capac*ssize); /* disk capacity */
if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */
detach_unit(uptr); /* if no space, error */
@ -1070,18 +1056,12 @@ fmt:
return SCPE_FMT; /* error */
}
/* set the max configuration geometry */
scfi_type[type].geom = (scfi_type[type].cyl << 16) |
(scfi_type[type].nhds << 8) | (scfi_type[type].spt);
data->cyl = 0; /* current cylinder position */
data->tpos = 0; /* current track position */
data->spos = 0; /* current sector position */
uptr->CHS = 0; /* set CHS to cyl/hd/sec = 0 */
sim_debug(DEBUG_CMD, &sda_dev,
"Attach %8s hds %d spt %d spc %d cyl %d capacity %d\n",
scfi_type[type].name, scfi_type[type].nhds, scfi_type[type].spt,
scfi_type[type].nhds * scfi_type[type].spt,
scfi_type[type].cyl, uptr->capac);
"Attach %s cyl %d hds %d spt %d spc %d cap sec %d cap bytes %d\n",
scfi_type[type].name, CYL(type), HDS(type), SPT(type), SPC(type),
CAP(type), CAPB(type));
sim_debug(DEBUG_CMD, &sda_dev, "File %s attached to %s\r\n",
file, scfi_type[type].name);
@ -1092,12 +1072,7 @@ fmt:
/* detach a disk device */
t_stat scfi_detach(UNIT *uptr) {
struct ddata_t *data = (struct ddata_t *)uptr->up7;
if (data != 0) {
free(data); /* free disk data structure */
}
uptr->up7 = 0; /* no pointer to disk data */
uptr->SNS = 0; /* clear sense data */
uptr->CMD &= ~0xffff; /* no cmd and flags */
return detach_unit(uptr); /* tell simh we are done with disk */
}
@ -1125,14 +1100,14 @@ t_stat scfi_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
return SCPE_IERR; /* no, error */
if (uptr->flags & UNIT_ATT) /* is unit attached? */
return SCPE_ALATT; /* no, error */
/* now loop through the units and find named disk */
for (i = 0; scfi_type[i].name != 0; i++) {
if (strcmp(scfi_type[i].name, cptr) == 0) {
uptr->flags &= ~UNIT_TYPE; /* clear the old UNIT type */
uptr->flags |= SET_TYPE(i); /* set the new type */
/* set capacity of disk in sectors */
uptr->capac = scfi_type[i].cyl * scfi_type[i].nhds *
scfi_type[i].spt;
uptr->capac = CAP(i);
return SCPE_OK;
}
}
@ -1164,13 +1139,11 @@ t_stat scfi_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
}
fprintf (st, ".\nEach drive has the following storage capacity:\r\n");
for (i = 0; scfi_type[i].name != 0; i++) {
/* disk capacity in sectors */
int32 capac = scfi_type[i].cyl * scfi_type[i].nhds * scfi_type[i].spt;
int32 ssize = scfi_type[i].ssiz * 4; /* disk sector size in bytes */
int32 size = capac * ssize; /* disk capacity in bytes */
int32 size = CAPB(i); /* disk capacity in bytes */
size /= 1024; /* make KB */
size = (10 * size) / 1024; /* size in MB * 10 */
fprintf(st, " %-8s %4d.%1d MB\r\n", scfi_type[i].name, size/10, size%10);
fprintf(st, " %-8s %4d.%1d MB cyl %3d hds %3d sec %3d blk %3d\r\n",
scfi_type[i].name, size/10, size%10, CYL(i), HDS(i), SPT(i), SSB(i));
}
fprint_set_help(st, dptr);
fprint_show_help(st, dptr);

View File

@ -1,6 +1,6 @@
/* sel32_sys.c: SEL-32 Gould Concept/32 (orignal SEL-32) Simulator system interface.
Copyright (c) 2018, James C. Bevier
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a