From d3d4e808cc5af08906b1a9993f008d60e16f85be Mon Sep 17 00:00:00 2001 From: "James C. Bevier" Date: Wed, 17 Jul 2019 21:39:18 -0400 Subject: [PATCH] SEL32: Initial commit of working simulator. --- SEL32/sel32_chan.c | 2077 +++++++----- SEL32/sel32_clk.c | 367 +++ SEL32/sel32_com.c | 899 ++++++ SEL32/sel32_con.c | 370 +++ SEL32/sel32_cpu.c | 7634 ++++++++++++++++++++++++-------------------- SEL32/sel32_defs.h | 343 +- SEL32/sel32_disk.c | 1165 +++++++ SEL32/sel32_iop.c | 199 ++ SEL32/sel32_lpr.c | 465 +++ SEL32/sel32_mt.c | 1118 +++---- SEL32/sel32_scfi.c | 1137 +++++++ SEL32/sel32_sys.c | 1984 ++++++------ 12 files changed, 11793 insertions(+), 5965 deletions(-) create mode 100644 SEL32/sel32_clk.c create mode 100644 SEL32/sel32_com.c create mode 100644 SEL32/sel32_con.c create mode 100644 SEL32/sel32_disk.c create mode 100644 SEL32/sel32_iop.c create mode 100644 SEL32/sel32_lpr.c create mode 100644 SEL32/sel32_scfi.c diff --git a/SEL32/sel32_chan.c b/SEL32/sel32_chan.c index 47dd36d..0d29db2 100644 --- a/SEL32/sel32_chan.c +++ b/SEL32/sel32_chan.c @@ -1,6 +1,7 @@ -/* sel32_chan.c: Sel 32 Channel functions. +/* sel32_chan.c: SEL 32 Channel functions. - Copyright (c) 2018, Richard Cornwell, James C. Bevier + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,13 +16,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - /* Handle Class E and F channel I/O operations */ #include "sel32_defs.h" @@ -42,9 +41,9 @@ /* Bits 13-15 - Aug code = 5 - TD */ /* Bits 16-18 - TD Level 2000, 4000, 8000 */ -/* 01 - TD 2000 Level Status Testing */ -/* 02 - TD 4000 Level Status Testing */ -/* 04 - TD 8000 Level Status Testing */ +/* 01 - TD 2000 Level Status Testing */ +/* 02 - TD 4000 Level Status Testing */ +/* 04 - TD 8000 Level Status Testing */ /* CC1 CC2 CC3 CC4 */ /* TD8000 Undefined I/O Activ I/O Error Dev Stat Present */ /* TD4000 Invd Mem Acc Mem Parity Prog Viol Data Ovr/Undr */ @@ -59,496 +58,722 @@ /* Bits 00-06 - Op code 0xFC */ /* Bits 09-12 - I/O type */ -/* 00 - Unassigned */ -/* 01 - Unassigned */ -/* 02 - Start I/O (SIO) */ -/* 03 - Test I/O (TIO) */ -/* 04 - Stop I/O (STPIO */ -/* 05 - Reset channel (RSCHNL) */ -/* 06 - Halt I/O (HIO) */ -/* 07 - Grab controller (GRIO) Not supported */ -/* 08 - Reset channel (RSCTL) */ -/* 09 - Enable write channel WCS (ECWCS) Not supported */ -/* 0A - Unassigned */ -/* 0B - Write channel WCS (WCWCS) Not supported */ -/* 0C - Enable channel interrupt (ECI) */ -/* 0D - Disable channel interrupt (DCI) */ -/* 0E - Activate channel interrupt (ACI) */ -/* 0F - Deactivate channel interrupt (DACI) */ +/* 00 - Unassigned */ +/* 01 - Unassigned */ +/* 02 - Start I/O (SIO) */ +/* 03 - Test I/O (TIO) */ +/* 04 - Stop I/O (STPIO */ +/* 05 - Reset channel (RSCHNL) */ +/* 06 - Halt I/O (HIO) */ +/* 07 - Grab controller (GRIO) Not supported */ +/* 08 - Reset channel (RSCTL) */ +/* 09 - Enable write channel WCS (ECWCS) Not supported */ +/* 0A - Unassigned */ +/* 0B - Write channel WCS (WCWCS) Not supported */ +/* 0C - Enable channel interrupt (ECI) */ +/* 0D - Disable channel interrupt (DCI) */ +/* 0E - Activate channel interrupt (ACI) */ +/* 0F - Deactivate channel interrupt (DACI) */ /* Bits 13-15 - Aug Code */ /* Bit 16 - unused - must be zero */ /* Bits 16-23 - Channel address (0-127) */ /* Bits 24-31 - Device Sub address (0-255) */ -int channels = MAX_CHAN; /* maximum number of channels */ -int subchannels = SUB_CHANS; /* maximum number of subchannel devices */ -int irq_pend = 0; /* pending interrupt flag */ +int channels = MAX_CHAN; /* maximum number of channels */ +int subchannels = SUB_CHANS; /* maximum number of subchannel devices */ +int irq_pend = 0; /* pending interrupt flag */ -#define AMASK 0x00ffffff -#define PMASK 0xf0000000 /* Storage protection mask */ +#define AMASK 0x00ffffff /* 24 bit mask */ -extern uint32 M[]; /* our memory */ -extern uint32 SPAD[]; /* CPU scratchpad memory */ +extern uint32 M[]; /* our memory */ +extern uint32 SPAD[]; /* CPU scratchpad memory */ +extern uint32 CPUSTATUS; /* CPU status word */ +extern uint32 INTS[]; /* Interrupt status flags */ +extern uint16 ccw_count[]; +extern int traceme, trstart; -uint32 chan_icb[MAX_CHAN]; /* Interrupt Context Block address in memory */ -uint32 chan_inch_addr[MAX_CHAN]; /* Channel status dw in memory */ -uint32 caw[MAX_CHAN]; /* Channel command address word */ -uint32 ccw_addr[MAX_CHAN]; /* Channel address */ -uint16 ccw_count[MAX_CHAN]; /* Channel count */ -uint8 ccw_cmd[MAX_CHAN]; /* Channel command and flags */ -uint16 ccw_flags[MAX_CHAN]; /* Channel flags */ -uint16 chan_status[MAX_CHAN]; /* Channel status */ -uint16 chan_dev[MAX_CHAN]; /* Device on channel */ -uint32 chan_buf[MAX_CHAN]; /* Channel data buffer */ -uint8 chan_byte[MAX_CHAN]; /* Current byte, dirty/full */ -DIB *dev_unit[MAX_DEV]; /* Pointer to Device info block */ -uint8 dev_status[MAX_DEV]; /* last device status flags */ -uint16 loading; /* set when booting */ +#if 0 +#define FIFO_SIZE 256 +/* FIFO structure */ +uint32 chan_fifo[MAX_CHAN][FIFO_SIZE]; /* interrupt status fifo each channel */ +uint32 chan_fifo_in[MAX_CHAN]; /* fifo input index */ +uint32 chan_fifo_out[MAX_CHAN]; /* fifo output index */ +/* channel values defined in CHANP structure */ +uint32 chan_inch_addr[MAX_CHAN]; /* Channel status dw in memory */ +uint32 chan_caw[MAX_CHAN]; /* Channel command address word */ +uint32 ccw_addr[MAX_CHAN]; /* Channel address */ +uint16 ccw_count[MAX_CHAN]; /* Channel count */ +uint8 ccw_cmd[MAX_CHAN]; /* Channel command and flags */ +uint16 ccw_flags[MAX_CHAN]; /* Channel flags */ +uint16 chan_status[MAX_CHAN]; /* Channel status */ +uint16 chan_dev[MAX_CHAN]; /* Device on channel */ +uint32 chan_buf[MAX_CHAN]; /* Channel data buffer */ +uint8 chan_byte[MAX_CHAN]; /* Current byte, dirty/full */ +#endif +/* device status */ +DIB *dev_unit[MAX_DEV]; /* Pointer to Device info block */ +uint16 dev_status[MAX_DEV]; /* last device status flags */ +uint16 loading; /* set when booting */ + +#define get_chan(chsa) ((chsa>>8)&0x7f) /* get channel number from ch/sa */ /* forward definitions */ -int find_subchan(uint16 device); /* look up device to find subchannel device is on */ +CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */ +UNIT *find_unit_ptr(uint16 chsa); /* find unit pointer */ int chan_read_byte(uint16 chan, uint8 *data); int chan_write_byte(uint16 chan, uint8 *data); -void set_devattn(uint16 addr, uint8 flags); -void chan_end(uint16 chan, uint8 flags); -t_stat startxio(uint16 addr, uint32 *status); -t_stat testxio(uint16 addr, uint32 *status); -t_stat stoptxio(uint16 addr, uint32 *status); -int testchan(uint16 channel); +void set_devattn(uint16 chsa, uint16 flags); +void set_devwake(uint16 chsa, uint16 flags); /* wakeup O/S for async line */ +void chan_end(uint16 chan, uint16 flags); +int test_write_byte_end(uint16 chsa); +t_stat startxio(uint16 chsa, uint32 *status); /* start XIO */ +t_stat testxio(uint16 chsa, uint32 *status); /* test XIO */ +t_stat stoptxio(uint16 chsa, uint32 *status); /* stop XIO */ +t_stat rschnlxio(uint16 chsa, uint32 *status); /* reset channel XIO */ +t_stat haltxio(uint16 chsa, uint32 *status); /* halt XIO */ +t_stat grabxio(uint16 chsa, uint32 *status); /* grab XIO n/u */ +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(void); -t_stat chan_boot(uint16 addr, DEVICE *dptr); +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); -t_stat show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc); +t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat show_dev_addr(FILE *st, UNIT *uptr, int32 v, CONST void *desc); -/* Find unit pointer for given device (ch/sa) */ -UNIT *find_chan_dev(uint16 addr) { - struct dib *dibp; /* DIB pointer */ - UNIT *uptr; /* UNIT pointer */ - int i; +/* FIFO support */ +/* These are FIFO queues which return an error when full. + * + * FIFO is empty when in == out. + * If in != out, then + * - items are placed into in before incrementing in + * - items are removed from out before incrementing out + * FIFO is full when in == (out-1 + FIFO_SIZE) % FIFO_SIZE; + * + * The queue will hold FIFO_SIZE items before the calls + * to FIFO_Put fails. + */ -fprintf(stderr, "find_chan_dev addr %0x\r\n", addr); - dibp = dev_unit[addr]; /* get DIB pointer from device pointers */ - if (dibp == 0) /* if zero, not defined on system */ - return NULL; /* tell caller */ +/* initialize FIFO to empty in boot channel code */ - uptr = dibp->units; /* get the pointer to the units on this channel */ -fprintf(stderr, "find_chan_dev addr %x units %x \r\n", addr, dibp->numunits); - for (i = 0; i < dibp->numunits; i++) { /* search through units to get a match */ - if (addr == GET_UADDR(uptr->u3)) /* does ch/sa match? */ - return uptr; /* return the pointer */ - uptr++; /* next unit */ - } - return NULL; /* device not found on system */ +/* add an entry to the FIFO */ +int32 FIFO_Put(uint16 chsa, uint32 entry) +{ + DIB *dibp = dev_unit[chsa & 0x7f00]; /* get DIB pointer for channel */ + if (dibp->chan_fifo_in == ((dibp->chan_fifo_out-1+FIFO_SIZE) % FIFO_SIZE)) { + return -1; /* FIFO Full */ + } +// fprintf(stderr, "FIFO PUT chsa %x entry %x index %x\r\n", chsa, entry, dibp->chan_fifo_in); + dibp->chan_fifo[dibp->chan_fifo_in] = entry; /* add new entry */ + dibp->chan_fifo_in += 1; /* next entry */ + dibp->chan_fifo_in %= FIFO_SIZE; /* modulo FIFO size */ + return 0; /* all OK */ } -/* extract channel from device definition (ch/sa) */ -/* ret chan = OK */ -/* ret -1 = error */ -int find_subchan(uint16 device) { - int chan; +/* get the next entry from the FIFO */ +int FIFO_Get(uint16 chsa, uint32 *old) +{ + DIB *dibp = dev_unit[chsa & 0x7f00]; /* get DIB pointer for channel */ + /* see if the FIFO is empty */ + if (dibp->chan_fifo_in == dibp->chan_fifo_out) { + return -1; /* FIFO is empty, tell caller */ + } + *old = dibp->chan_fifo[dibp->chan_fifo_out]; /* get the next entry */ +// fprintf(stderr, "FIFO GET chsa %x entry %x index %x\r\n", chsa, *old, dibp->chan_fifo_out); + dibp->chan_fifo_out += 1; /* next entry */ + dibp->chan_fifo_out %= FIFO_SIZE; /* modulo FIFO size */ + return 0; /* all OK */ +} -//fprintf(stderr, "find_subchan device %0x\r\n", device); - if (device > MAX_DEV) /* if overlimit of system, error */ - return -1; /* error */ - chan = (device >> 8) & 0x7F; /* channel is in upper nibble */ - if (chan > channels) /* should not happen */ - return -1; /* error */ - return chan; /* return chan 0-7f */ +/* Find interrupt level for the given device (ch/sa) */ +/* return 0 if not found, otherwise leve number */ +uint32 find_int_lev(uint16 chsa) +{ + uint32 chan, level, val; + int i; + + chan = (chsa >> 8) & 0x7f; /* get channel number */ + /* scan the channel entries for our chan */ + for (i=0; i<128; i++) { + val = SPAD[i]; /* get spad entry */ + if ((val == 0) || (val == 0xffffffff)) + continue; /* not valid entry */ + /* look for class F devices */ + if ((val & 0x0f000000) == 0x0f000000) { + /* F class only uses chan entry */ + if (((val >> 8 ) & 0x7f) == chan) { + /* channel matches, now get interrupt level number */ + level = ((val >> 16) & 0x7f); /* 1's comp of int level */ + level = 127 - level; /* get positive number level */ + sim_debug(DEBUG_EXP, &cpu_dev, + "find_int_lev F SPAD %x chan %x chsa %x level %x\n", val, chan, chsa, level); + return(level); /* return the level*/ + } + } + /* look for E class or class 3 device */ + if (((val & 0x0f000000) == 0x0e000000) || /* E class */ + ((val & 0x0f800000) == 0x03800000)) { /* class 3 (interval timer) */ + /* E class uses chan and device address */ + if ((val & 0x7f00) == (chsa & 0x7f00)) { /* check chan/subaddress */ + /* channel/subaddress matches, now get interrupt level number */ + level = ((val >> 16) & 0x7f); /* 1's comp of int level */ + level = 127 - level; /* get positive number level */ + sim_debug(DEBUG_EXP, &cpu_dev, + "find_int_lev E SPAD %x chan %x chsa %x level %x\n", val, chan, chsa, level); + return(level); /* return the level*/ + } + } + } + /* not a real device, so check interrupt entries for match */ + /* scan the entries for our channel/subaddress */ + for (i=0; i<112; i++) { + val = SPAD[i+0x80]; /* get spade entry */ + if (val == 0 || val == 0xffffffff) + continue; /* not valid entry */ + /* look for class 3 device or non device entries */ + if (((val & 0x0f800000) == 0x00800000) || /* clock or external interrupt */ + ((val & 0x0f800000) == 0x03800000)) { /* class 3 (interval timer) */ + /* E class or non I/O uses chan and device address */ + if ((val & 0x7f00) == (chsa & 0x7f00)) { /* check chan/sub address */ + /* channel/subaddress matches, now get interrupt level number */ + level = ((val >> 16) & 0x7f); /* 1's comp of int level */ + level = 127 - level; /* get positive number level */ + return(level); /* return the level*/ + } + } + } + return 0; /* not found */ +} + +/* Find interrupt context block address for given device (ch/sa) */ +/* return 0 if not found, otherwise ICB memory address */ +uint32 find_int_icb(uint16 chsa) +{ + uint32 level, icba; + + level = find_int_lev(chsa); /* find the int level */ + if (level == 0) + return 0; /* not found */ + icba = SPAD[0xf1] + (level<<2); /* interrupt vector address in memory */ + icba = M[icba>>2]; /* get address of ICB from memory */ + return(icba); /* return the address */ +} + +/* Find unit pointer for given device (ch/sa) */ +UNIT *find_unit_ptr(uint16 chsa) +{ + struct dib *dibp; /* DIB pointer */ + UNIT *uptr; /* UNIT pointer */ + int i; + + dibp = dev_unit[chsa]; /* get DIB pointer from device pointers */ + if (dibp == 0) { /* if zero, not defined on system */ +//fprintf(stderr, "find_unit_ptr NULL DIB PTR chsa %0x\r\n", chsa); + return NULL; /* tell caller */ + } + + uptr = dibp->units; /* get the pointer to the units on this channel */ + for (i = 0; i < dibp->numunits; i++) { /* search through units to get a match */ + if (chsa == GET_UADDR(uptr->u3)) { /* does ch/sa match? */ + return uptr; /* return the pointer */ + } + uptr++; /* next unit */ + } + return NULL; /* device not found on system */ +} + +/* Find chanp pointer for given device (ch/sa) */ +CHANP *find_chanp_ptr(uint16 chsa) +{ + struct dib *dibp; /* DIB pointer */ + UNIT *uptr; /* UNIT pointer */ + CHANP *chp; /* CHANP pointer */ + int i; + + dibp = dev_unit[chsa]; /* get DIB pointer from device pointers */ + if (dibp == 0) /* if zero, not defined on system */ + return NULL; /* tell caller */ + if ((chp = (CHANP *)dibp->chan_prg) == NULL) { /* must have channel information for each device */ +//fprintf(stderr, "find_chanp_ptr NULL DIB PTR chsa %0x\r\n", chsa); + return NULL; /* tell caller */ + } + + uptr = dibp->units; /* get the pointer to the units on this channel */ + for (i = 0; i < dibp->numunits; i++) { /* search through units to get a match */ + if (chsa == GET_UADDR(uptr->u3)) { /* does ch/sa match? */ + return chp; /* return the pointer */ + } + uptr++; /* next UNIT */ + chp++; /* next CHANP */ + } + return NULL; /* device not found on system */ } /* Read a full word into memory. * Return 1 if fail. * Return 0 if success. */ -int -readfull(int chan, uint32 addr, uint32 *word) { - int sk, k; - if ((addr & AMASK) > MEMSIZE) { - chan_status[chan] |= STATUS_PCHK; - return 1; - } - addr &= AMASK; - addr >>= 2; - *word = M[addr]; - return 0; +int readfull(CHANP *chp, uint32 maddr, uint32 *word) +{ + maddr &= AMASK; /* mask addr to 24 bits */ + if (maddr > MEMSIZE) { /* see if mem addr > MEMSIZE */ + chp->chan_status |= STATUS_PCHK; /* program check error */ + return 1; /* show we have error */ + } + maddr >>= 2; /* get 32 bit word index */ + *word = M[maddr]; /* get the contents */ + sim_debug(DEBUG_EXP, &cpu_dev, "readfull read %x from addr %x\n", *word, maddr<<2); + return 0; /* return OK */ } /* Read a word into the channel buffer. * Return 1 if fail. * Return 0 if success. */ -int -readbuff(int chan) { +int readbuff(CHANP *chp) +{ int k; - uint32 addr = ccw_addr[chan]; - if ((addr & AMASK) > MEMSIZE) { - chan_status[chan] |= STATUS_PCHK; - chan_byte[chan] = BUFF_CHNEND; - irq_pend = 1; - return 1; + uint32 addr = chp->ccw_addr; /* channel buffer address */ + uint16 chan = get_chan(chp->chan_dev); /* our channel */ + + if ((addr & AMASK) > MEMSIZE) { /* 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 */ } - addr &= AMASK; - addr >>= 2; - chan_buf[chan] = M[addr]; - sim_debug(DEBUG_DATA, &cpu_dev, "Channel write %02x %06x %08x %08x '", - chan, ccw_addr[chan] & 0xFFFFFC, chan_buf[chan], ccw_count[chan]); + addr &= AMASK; /* address only */ + addr >>= 2; /* byte to word address */ + chp->chan_buf = M[addr]; /* get 4 bytes */ + + sim_debug(DEBUG_DATA, &cpu_dev, "readbuff read memory bytes into buffer %02x %06x %08x %08x [", + chan, chp->ccw_addr & 0xFFFFFC, chp->chan_buf, chp->ccw_count); for(k = 24; k >= 0; k -= 8) { - char ch = (chan_buf[chan] >> k) & 0xFF; + char ch = (chp->chan_buf >> k) & 0xFF; if (ch < 0x20 || ch == 0xff) ch = '.'; - sim_debug(DEBUG_DATA, &cpu_dev, "%c", ch); + sim_debug(DEBUG_DATA, &cpu_dev, "%c", ch); } - - sim_debug(DEBUG_DATA, & cpu_dev, "'\n"); + sim_debug(DEBUG_DATA, &cpu_dev, "]\n"); return 0; } -/* Write channel buffer to memory. +/* Write 32 bit channel buffer to memory. * Return 1 if fail. * Return 0 if success. */ -int -writebuff(int chan) { - int k; - uint32 addr = ccw_addr[chan]; +int writebuff(CHANP *chp) +{ + uint32 addr = chp->ccw_addr; + if ((addr & AMASK) > MEMSIZE) { - chan_status[chan] |= STATUS_PCHK; - chan_byte[chan] = BUFF_CHNEND; + chp->chan_status |= STATUS_PCHK; + chp->chan_byte = BUFF_CHNEND; irq_pend = 1; return 1; } addr &= AMASK; - addr >>= 2; - M[addr] = chan_buf[chan]; - sim_debug(DEBUG_DATA, &cpu_dev, "Channel readf %02x %06x %08x %08x '", - chan, ccw_addr[chan] & 0xFFFFFC, chan_buf[chan], ccw_count[chan]); - for(k = 24; k >= 0; k -= 8) { - char ch = (chan_buf[chan] >> k) & 0xFF; - if (ch < 0x20 || ch == 0xff) - ch = '.'; - sim_debug(DEBUG_DATA, &cpu_dev, "%c", ch); - } - sim_debug(DEBUG_DATA, &cpu_dev, "'\n"); + M[addr>>2] = chp->chan_buf; return 0; } /* load in the IOCD and process the commands */ /* return = 0 OK */ /* return = 1 error, chan_status will have reason */ -int load_ccw(uint16 chan, int tic_ok) { - uint32 word; - int cmd = 0; - UNIT *uptr; +int load_ccw(CHANP *chp, int tic_ok) +{ + uint32 word; + int docmd = 0; + UNIT *uptr; + uint16 chan = get_chan(chp->chan_dev); /* our channel */ loop: - /* Abort if channel not on double boundry */ - if ((caw[chan] & 0x7) != 0) { - chan_status[chan] |= STATUS_PCHK; /* Not dbl WD bounded, program check */ - return 1; - } - /* Abort if we have any errors */ - if (chan_status[chan] & 0x7f) /* check channel status */ - return 1; + /* Abort if we have any errors */ + if (chp->chan_status & 0x3f03) { /* check channel status */ + sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw ERROR chan_status[%x] %x\n", chan, chp->chan_status); +// fprintf(stderr, "load_ccw ERROR chan_status[%x] %x\r\n", chan, chp->chan_status); + return 1; + } - /* Check if we have status modifier set */ - if (chan_status[chan] & STATUS_MOD) { - caw[chan]+=8; /* move to next IOCD */ - caw[chan] &= PMASK|AMASK; /* Mask overflow bits (4-7) */ - chan_status[chan] &= ~STATUS_MOD; /* turn off status modifier flag */ - } + /* Check if we have status modifier set */ + if (chp->chan_status & STATUS_MOD) { + chp->chan_caw += 8; /* move to next IOCD */ + chp->chan_status &= ~STATUS_MOD; /* turn off status modifier flag */ + } - /* Read in first or next CCW */ - if (readfull(chan, caw[chan], &word) != 0) { /* read word from memory */ - chan_status[chan] |= STATUS_PCHK; /* memory read error, program check */ - return 1; /* error return */ - } + /* Read in first or next CCW */ + 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 ERROR chan_status[%x] %x\n", chan, chp->chan_status); +// fprintf(stderr, "load_ccw ERROR chan_status[%x] %x\r\n", chan, chp->chan_status); + return 1; /* error return */ + } -fprintf(stderr, "Channel read ccw %02x %06x %08x\r\n", chan, caw[chan], word); -sim_debug(DEBUG_CMD, &cpu_dev, "Channel read ccw %02x %06x %08x\n", chan, caw[chan], word); - /* TIC can't follow TIC nor be first in chain */ - if (((word >> 24) & 0xf) == CMD_TIC) { - if (tic_ok) { - caw[chan] = (caw[chan] & PMASK) | (word & AMASK); /* get new IOCD address */ - tic_ok = 0; /* another tic not allowed */ - goto loop; /* restart the IOCD processing */ - } - chan_status[chan] |= STATUS_PCHK; /* program check for invalid tic */ - irq_pend = 1; /* status pending */ - return 1; /* error return */ - } - caw[chan] += 4; /* point to 2nd word of the IOCD */ - caw[chan] &= PMASK|AMASK; /* Mask overflow bits */ + sim_debug(DEBUG_CMD, &cpu_dev, "load_ccw read ccw chan %02x caw %06x IOCD wd 1 %08x\n", + chan, chp->chan_caw, word); +// fprintf(stderr, "load_ccw read ccw chan %02x caw %06x IOCD wd 1 %08x\r\n", +// chan, chp->chan_caw, word); + /* TIC can't follow TIC or be first in command chain */ + if (((word >> 24) & 0xf) == CMD_TIC) { + if (tic_ok) { + chp->chan_caw = word & AMASK; /* get new IOCD address */ + tic_ok = 0; /* another tic not allowed */ + 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[%x] %x\n", chan, chp->chan_status); +// fprintf(stderr, "load_ccw ERROR chan_status[%x] %x\r\n", chan, chp->chan_status); + irq_pend = 1; /* status pending */ + return 1; /* error return */ + } + chp->chan_caw += 4; /* point to 2nd word of the IOCD */ - /* Check if not chaining data */ - if ((ccw_flags[chan] & FLAG_DC) == 0) { - ccw_cmd[chan] = (word >> 24) & 0xff; /* not DC, so set command from IOCD WD 1 */ - cmd = 1; /* show we have a command */ - } - /* Set up for this command */ - ccw_addr[chan] = word & AMASK; /* set the data address */ - ccw_addr[chan] |= caw[chan] & PMASK; /* Copy bits 0-3 from old IOCD pointer into data address ?? */ - readfull(chan, caw[chan], &word); /* get IOCD WD 2 */ + /* Check if not chaining data */ + 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_EXP, &cpu_dev, "load_ccw No DC, flags %x cmd %x\n", + chp->ccw_flags, chp->ccw_cmd); +// fprintf(stderr, "load_ccw No DC, flags %x cmd %x\r\n", +// chp->ccw_flags, chp->ccw_cmd); + docmd = 1; /* show we have a command */ + } + /* Set up for this command */ + chp->ccw_addr = word & AMASK; /* set the data address */ + readfull(chp, chp->chan_caw, &word); /* get IOCD WD 2 */ -fprintf(stderr, "Channel read ccw2 %02x %06x %08x\r\n", chan, caw[chan], word); -sim_debug(DEBUG_CMD, &cpu_dev, "Channel read ccw2 %02x %06x %08x\n", chan, caw[chan], word); - caw[chan]+=4; /* next IOCD address */ - caw[chan] &= PMASK|AMASK; /* Mask overflow bits */ - ccw_count[chan] = word & 0xffff; /* get 16 bit byte count from IOCD WD 2*/ - ccw_flags[chan] = (word >> 16) & 0xffff; /* get flags from bits 0-7 of WD 2 of IOCD */ - chan_byte[chan] = BUFF_EMPTY; /* no bytes transferred yet */ - if (ccw_flags[chan] & FLAG_PCI) { /* do we have prog controlled int? */ - chan_status[chan] |= STATUS_PCI; /* set PCI flag in status */ - irq_pend = 1; /* interrupt pending */ - } + sim_debug(DEBUG_CMD, &cpu_dev, "load_ccw read ccw chan %02x caw %06x IOCD wd 2 %08x\n", + chan, chp->chan_caw, word); +// fprintf(stderr, "load_ccw read ccw chan %02x caw %06x IOCD wd 2 %08x\r\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 */ + 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 */ + } - /* Check invalid count */ - if (ccw_count[chan] == 0) { /* see if byte count is zero */ - chan_status[chan] |= STATUS_PCHK; /* program check if it is */ - irq_pend = 1; /* status pending int */ - return 1; /* error return */ - } - if (cmd) { /* see if we need to process command */ - DIB *dibp = dev_unit[chan_dev[chan]]; /* get the device pointer */ - /* Check if INCH command */ - if ((ccw_cmd[chan] & 0xF) == 0) { /* see if this an initialize channel cmd */ -fprintf(stderr, "load_ccw inch %x saved chan %0x status %0.8x\r\n", ccw_addr[chan], chan, chan_status[chan]); - chan_inch_addr[chan] = ccw_addr[chan]; /* save channel status dw address in memory */ - /* just drop through and call the device startcmd function */ - /* it should just return SEN_CHNEND and SNS_DEVEND status */ - } - uptr = find_chan_dev(chan_dev[chan]); /* find the unit pointer */ - if (uptr == 0) - return 1; /* if none, error */ - chan_status[chan] &= 0xff; /* clear device sense status */ - /* call the device startcmd function to process command */ - /* store sense status in upper byte of status */ - chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8; -fprintf(stderr, "load_ccw after start_cmd chan %0x status %0.8x\r\n", chan, chan_status[chan]); - /* see if bad status */ - if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) { - chan_status[chan] |= STATUS_CEND; /* channel end status */ - ccw_flags[chan] = 0; /* no flags */ - ccw_cmd[chan] = 0; /* stop IOCD processing */ - irq_pend = 1; /* int coming */ -fprintf(stderr, "load_ccw bad1 chan %0x status %0.8x\r\n", chan, chan_status[chan]); - return 1; /* error return */ - } - /* see if command completed */ - if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) { - chan_status[chan] |= STATUS_CEND; /* set channel end status */ - chan_byte[chan] = BUFF_NEWCMD; /* ready for new cmd */ - ccw_cmd[chan] = 0; /* stop IOCD processing */ - irq_pend = 1; /* int coming */ -fprintf(stderr, "load_ccw good chan %0x status %0.8x %x\r\n", chan, chan_status[chan]); - } - } - return 0; /* good return */ + sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw read docmd %x irq_flag %x count %x chan %x\n", + docmd, irq_pend, chp->ccw_count, chan); +// fprintf(stderr, "load_ccw read docmd %x irq_flag %x count %x chan %x\r\n", +// docmd, irq_pend, chp->ccw_count, chan); + /* Check invalid count */ + /* HACK HACK - LPR sends CC cmd only without data addr/count */ + if ((chp->ccw_count == 0) && (chp->ccw_addr != 0)) { /* see if byte count is zero */ + chp->chan_status |= STATUS_PCHK; /* program check if it is */ + irq_pend = 1; /* status pending int */ + return 1; /* error return */ + } + if (docmd) { /* see if we need to process command */ + 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 */ + + /* 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 */ + 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 */ + } + + sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw before start_cmd chan %0x status %.8x count %x\n", + chan, chp->chan_status, chp->ccw_count); + + /* call the device startcmd function to process command */ + chp->chan_status = dibp->start_cmd(uptr, chan, chp->ccw_cmd); + + sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw after start_cmd chan %0x status %.8x count %x\n", + chan, chp->chan_status, chp->ccw_count); + + /* see if bad status */ + if (chp->chan_status & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) { + chp->chan_status |= STATUS_CEND; /* channel end status */ + 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 %0x status %.8x\n", + chan, chp->chan_status); + return 1; /* error return */ + } + + /* see if command completed */ + if (chp->chan_status & (STATUS_DEND|STATUS_CEND)) { + /* 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)) { + chp->chan_inch_addr = uptr->u4; /* save INCH buffer address */ +// fprintf(stderr, "load_ccw INCH %x saved for chan %0x\r\n", +// chp->chan_inch_addr, chan); + sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw INCH %x saved chan %0x\n", + chp->chan_inch_addr, chan); + } + chp->chan_status |= STATUS_CEND; /* set channel end status */ + chp->chan_byte = BUFF_NEWCMD; /* ready for new cmd */ + chp->ccw_cmd = 0; /* stop IOCD processing */ + irq_pend = 1; /* int coming */ + sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw cmd complete chan %0x status %.8x count %x\n", + chan, chp->chan_status, chp->ccw_count); +// fprintf(stderr, "load_ccw cmd complete chan %0x status %.8x count %x\r\n", +// chan, chp->chan_status, chp->ccw_count); + } + } +// fprintf(stderr, "load_ccw return, chan %0x status %.8x count %x\r\n", +// chan, chp->chan_status, chp->ccw_count); +// sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw return, chan %0x status %.8x count %x\n", +// chan, chp->chan_status, chp->ccw_count); + return 0; /* good return */ } /* read byte from memory */ -int -chan_read_byte(uint16 addr, uint8 *data) { - int chan = find_subchan(addr); /* get the channel number */ - int byte; - int k; +/* write to device */ +int chan_read_byte(uint16 chsa, uint8 *data) +{ + int chan = get_chan(chsa); /* get the channel number */ + CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + int byte; /* Abort if we have any errors */ - if (chan < 0) - return 1; - if (chan_status[chan] & 0x7f) - return 1; - if ((ccw_cmd[chan] & 0x1) == 0) { - return 1; - } - if (chan_byte[chan] == BUFF_CHNEND) - return 1; - if (ccw_count[chan] == 0) { - if ((ccw_flags[chan] & FLAG_DC) == 0) { - chan_status[chan] |= STATUS_CEND; - chan_byte[chan] = BUFF_CHNEND; - sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_read_end\n"); - return 1; + if (chp->chan_status & 0x3f03) /* check channel status */ + return 1; /* return error */ + + if (chp->chan_byte == BUFF_CHNEND) + return 1; /* return error */ + if (chp->ccw_count == 0) { /* see if more data required */ + 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 %x\n", chp->chan_status); + return 1; /* return error */ } else { - if (load_ccw(chan, 1)) - return 1; + /* we have data chaining, process iocl */ + sim_debug(DEBUG_DATA, &cpu_dev, "chan_read_byte calling load_ccw chan %x\n", chan); + if (load_ccw(chp, 1)) /* process data chaining */ + return 1; /* return error */ } } - if (chan_byte[chan] == BUFF_EMPTY) { - if (readbuff(chan)) - return 1; - chan_byte[chan] = ccw_addr[chan] & 0x3; - ccw_addr[chan] += 4 - chan_byte[chan]; + if (chp->chan_byte == BUFF_EMPTY) { /* is buffer empty? */ + if (readbuff(chp)) /* read next 4 chars */ + return 1; /* return error */ + chp->chan_byte = chp->ccw_addr & 0x3; /* get byte number from address */ + chp->ccw_addr += 4 - chp->chan_byte; /* next byte address */ } - ccw_count[chan]--; - byte = (chan_buf[chan] >> (8 * (3 - (chan_byte[chan] & 0x3)))) & 0xff; - chan_byte[chan]++; - *data = byte; - return 0; + chp->ccw_count--; /* one char less to process */ + /* get the byte of data */ + byte = (chp->chan_buf >> (8 * (3 - (chp->chan_byte & 0x3)))) & 0xff; + chp->chan_byte++; /* next byte offset in word */ + *data = byte; /* return the data */ + sim_debug(DEBUG_DATA, &cpu_dev, "chan_read_byte transferred %x\n", byte); + return 0; /* good return */ +} + +/* test end of write byte I/O (device read) */ +int test_write_byte_end(uint16 chsa) +{ + int chan = get_chan(chsa); /* get the channel number */ + CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + + /* see if at end of buffer */ + if (chp->chan_byte == BUFF_CHNEND) + return 1; /* return done */ + if (chp->ccw_count == 0) { + if (chp->chan_byte & BUFF_DIRTY) { + writebuff(chp); /* write it */ + } + if ((chp->ccw_flags & FLAG_DC) == 0) { /* see if we have data chaining */ + chp->chan_status |= STATUS_CEND; /* no, end of data */ + chp->chan_byte = BUFF_CHNEND; /* thats all the data we want */ + return 1; /* return done */ + } + } + return 0; /* not done yet */ } /* write byte to memory */ -int -chan_write_byte(uint16 addr, uint8 *data) { - int chan = find_subchan(addr); /* get the channel number */ - int byte; - int offset; - int k; - uint32 mask; +/* read from device */ +int chan_write_byte(uint16 chsa, uint8 *data) +{ + int chan = get_chan(chsa); /* get the channel number */ + CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + int offset; + uint32 mask; /* Abort if we have any errors */ - if (chan < 0) - return 1; - if (chan_status[chan] & 0x7f) - return 1; - if ((ccw_cmd[chan] & 0x1) != 0) { - return 1; - } - if (chan_byte[chan] == BUFF_CHNEND) { - if ((ccw_flags[chan] & FLAG_SLI) == 0) { - chan_status[chan] |= STATUS_LENGTH; + if (chp->chan_status & 0x3f03) /* check channel status */ + return 1; /* return error */ + + /* see if at end of buffer */ + if (chp->chan_byte == BUFF_CHNEND) { + sim_debug(DEBUG_CMD, &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_CMD, &cpu_dev, "chan_write_byte 4 setting SLI ret\n"); + chp->chan_status |= STATUS_LENGTH; /* set SLI */ } - return 1; + return 1; /* return error */ } - if (ccw_count[chan] == 0) { - if (chan_byte[chan] & BUFF_DIRTY) { - if (writebuff(chan)) - return 1; + if (chp->ccw_count == 0) { + sim_debug(DEBUG_CMD, &cpu_dev, "chan_write_byte cccw_count is zero ccw_count[%x] %x\n", + chan, chp->ccw_count); + if (chp->chan_byte & BUFF_DIRTY) { + sim_debug(DEBUG_CMD, &cpu_dev, "chan_write_byte 2 BUF DIRTY ret\n"); + if (writebuff(chp)) /* write it */ + return 1; /* return error */ } - if ((ccw_flags[chan] & FLAG_DC) == 0) { - chan_byte[chan] = BUFF_CHNEND; - if ((ccw_flags[chan] & FLAG_SLI) == 0) { - sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_write_ length\n"); - chan_status[chan] |= STATUS_LENGTH; - } - sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_write_end\n"); - return 1; - } - if (load_ccw(chan, 1)) - return 1; + if ((chp->ccw_flags & FLAG_DC) == 0) { /* see if we have data chaining */ + sim_debug(DEBUG_CMD, &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 %x\n", chan); + if (load_ccw(chp, 1)) /* process data chaining */ + return 1; /* return error */ + } } - if (ccw_flags[chan] & FLAG_SKIP) { - ccw_count[chan]--; - chan_byte[chan] = BUFF_EMPTY; - if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD) - ccw_addr[chan]--; + sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte non zero ccw_count[%x] %x\n", chan, chp->ccw_count); + if (chp->ccw_flags & FLAG_SKIP) { + chp->ccw_count--; + chp->chan_byte = BUFF_EMPTY; + if ((chp->ccw_cmd & 0xff) == CMD_RDBWD) + chp->ccw_addr--; else - ccw_addr[chan]++; + chp->ccw_addr++; + sim_debug(DEBUG_CMD, &cpu_dev, "chan_write_byte SKIP ret\n"); return 0; } - if (chan_byte[chan] == (BUFF_EMPTY|BUFF_DIRTY)) { - if (writebuff(chan)) - return 1; - if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD) - ccw_addr[chan] -= 1 + (ccw_addr[chan] & 0x3); - else - ccw_addr[chan] += 4 - (ccw_addr[chan] & 0x3); - chan_byte[chan] = BUFF_EMPTY; - } - if (chan_byte[chan] == BUFF_EMPTY) { - if (readbuff(chan)) - return 1; - chan_byte[chan] = ccw_addr[chan] & 0x3; - } - ccw_count[chan]--; - offset = 8 * (chan_byte[chan] & 0x3); - mask = 0xff000000 >> offset; - chan_buf[chan] &= ~mask; - chan_buf[chan] |= ((uint32)(*data)) << (24 - offset); - if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD) { - if (chan_byte[chan] & 0x3) - chan_byte[chan]--; + if (chp->chan_byte == (BUFF_EMPTY|BUFF_DIRTY)) { + if (writebuff(chp)) + return 1; + sim_debug(DEBUG_DATA, &cpu_dev, "chan_write_byte BUF EMPTY|DIRTY ret\n"); + if ((chp->ccw_cmd & 0xff) == CMD_RDBWD) + chp->ccw_addr -= (1 + (chp->ccw_addr & 0x3)); + else + chp->ccw_addr += (4 - (chp->ccw_addr & 0x3)); + chp->chan_byte = BUFF_EMPTY; + } + if (chp->chan_byte == BUFF_EMPTY) + chp->chan_byte = chp->ccw_addr & 0x3; + chp->ccw_count--; + offset = 8 * (chp->chan_byte & 0x3); /* calc byte offset in word */ + mask = 0xff000000 >> offset; /* build char mask */ + chp->chan_buf &= ~mask; /* zero out the old byte */ + chp->chan_buf |= ((uint32)(*data)) << (24 - offset); /* or in the new one */ + + if ((chp->ccw_cmd & 0xff) == CMD_RDBWD) { + if (chp->chan_byte & 0x3) + chp->chan_byte--; else - chan_byte[chan] = BUFF_EMPTY; + chp->chan_byte = BUFF_EMPTY; } else - chan_byte[chan]++; - chan_byte[chan] |= BUFF_DIRTY; + chp->chan_byte++; /* next byte */ + chp->chan_byte |= BUFF_DIRTY; /* we are used */ return 0; } -/* post interrupt for specified channel */ -void set_devattn(uint16 addr, uint8 flags) { - int chan = find_subchan(addr); /* get the channel number */ +/* post wakeup interrupt for specified async line */ +void set_devwake(uint16 chsa, uint16 flags) +{ + uint32 stwd1, stwd2; /* words 1&2 of stored status */ + /* put sub address in byte 0 */ + stwd1 = (chsa & 0xff) << 24; /* subaddress and IOCD address to SW 1 */ + /* save 16 bit channel status and residual byte count in SW 2 */ + stwd2 = (uint32)flags << 16; + if ((FIFO_Put(chsa, stwd1) == -1) || (FIFO_Put(chsa, stwd2) == -1)) { + fprintf(stderr, "FIFO Overflow ERROR on chsa %x\r\n", chsa); + } + irq_pend = 1; /* wakeup controller */ +} -fprintf(stderr, "set_devattn addr %0x flags %x\r\n", addr, flags); - if (chan < 0) - return; - if (chan_dev[chan] == addr && (chan_status[chan] & STATUS_CEND) != 0 && - (flags & SNS_DEVEND) != 0) { - chan_status[chan] |= ((uint16)flags) << 8; - } else - dev_status[addr] = flags; - sim_debug(DEBUG_EXP, &cpu_dev, "set_devattn(%x, %x) %x\n", - addr, flags, chan_dev[chan]); - irq_pend = 1; +/* post interrupt for specified channel */ +void set_devattn(uint16 chsa, uint16 flags) +{ + int chan = get_chan(chsa); /* get the channel number */ + CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + + sim_debug(DEBUG_EXP, &cpu_dev, "set_devattn chsa %x, flags %x\n", chsa, flags); +// fprintf(stderr, "set_devattn chsa %x, flags %x\r\n", chsa, flags); + + if (chp->chan_dev == chsa && (chp->chan_status & STATUS_CEND) != 0 && (flags & SNS_DEVEND) != 0) { + chp->chan_status |= ((uint16)flags); + } else + dev_status[chsa] = flags; /* save device status flags */ + sim_debug(DEBUG_CMD, &cpu_dev, "set_devattn(%x, %x) %x\n", chsa, flags, chp->chan_dev); +// fprintf(stderr, "set_devattn2(%x, %x) %x\r\n", chsa, flags, chp->chan_dev); + irq_pend = 1; } /* channel operation completed */ -void chan_end(uint16 addr, uint8 flags) { - int chan = find_subchan(addr); /* get the channel number */ +void chan_end(uint16 chsa, uint16 flags) { + int chan = get_chan(chsa); /* get the channel number */ + uint32 chan_icb = find_int_icb(chsa); /* get icb address */ + CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ -fprintf(stderr, "chan_end addr %0x flags %x\r\n", addr, flags); - if (chan < 0) - return; +//fprintf(stderr, "chan_end addr %0x flags %x\r\n", chsa, flags); + if (chp->chan_byte & BUFF_DIRTY) { + if (writebuff(chp)) /* write remaining data */ + return; /* error */ + chp->chan_byte = BUFF_EMPTY; /* we are empty now */ + } + chp->chan_status |= STATUS_CEND; /* set channel end */ + chp->chan_status |= ((uint16)flags); /* add in the callers flags */ + chp->ccw_cmd = 0; /* reset the completed channel command */ - sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_end(%x, %x) %x\n", addr, flags, ccw_count[chan]); - if (chan_byte[chan] & BUFF_DIRTY) { - if (writebuff(chan)) - return; - chan_byte[chan] = BUFF_EMPTY; - } - chan_status[chan] |= STATUS_CEND; - chan_status[chan] |= ((uint16)flags) << 8; - ccw_cmd[chan] = 0; - if (ccw_count[chan] != 0 && (ccw_flags[chan] & FLAG_SLI) == 0) { - sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_end length\n"); - chan_status[chan] |= STATUS_LENGTH; - ccw_flags[chan] = 0; - } - if (flags & (SNS_ATTN|SNS_UNITCHK|SNS_UNITEXP)) { - ccw_flags[chan] = 0; - } + /* 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 */ + chp->ccw_flags = 0; /* no flags */ + } + /* no flags for attention status */ + if (flags & (SNS_ATTN|SNS_UNITCHK|SNS_UNITEXP)) { +// fprintf(stderr, "chan_end attention status chsa %x status flags %x\r\n", chsa, flags); + chp->ccw_flags = 0; /* no flags */ + } - if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) { - chan_byte[chan] = BUFF_NEWCMD; - - while ((ccw_flags[chan] & FLAG_DC)) { - if (load_ccw(chan, 1)) - break; - if ((ccw_flags[chan] & FLAG_SLI) == 0) { - sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_end length\n"); - chan_status[chan] |= STATUS_LENGTH; - ccw_flags[chan] = 0; - } - } - } - - irq_pend = 1; + /* test for device or controller end */ + if (chp->chan_status & (STATUS_DEND|STATUS_CEND)) { + chp->chan_byte = BUFF_NEWCMD; /* clear byte flag */ +// fprintf(stderr, "chan_end chsa %x status DEND|CEND\n", chsa); + while ((chp->ccw_flags & FLAG_DC)) { /* handle data chaining */ +// fprintf(stderr, "chan_end test for ccw flags %x chsa %x\n", chp->ccw_flags, chsa); + if (load_ccw(chp, 1)) /* continue channel program */ + break; /* error */ + if ((chp->ccw_flags & FLAG_SLI) == 0) { /* suppress incorrect length? */ + chp->chan_status |= STATUS_LENGTH; /* no, show incorrect length */ + chp->ccw_flags = 0; /* no flags */ + } + } + } + irq_pend = 1; /* flag to test for int condition */ +// fprintf(stderr, "chan_end END chsa %x status %x\r\n", chsa, chp->chan_status); } /* store the device status into the status DW in memory */ /* the INCH command provides the status address in memory */ -int store_csw(uint16 chan) { - uint32 maddr = chan_inch_addr[chan]; /* get address of stat dw */ - uint32 addr = chan_dev[chan]; /* get ch/sa information */ +/* return the icb address */ +void store_csw(CHANP *chp) +{ + uint32 stwd1, stwd2; /* words 1&2 of stored status */ + uint32 chsa = chp->chan_dev; /* get ch/sa information */ -fprintf(stderr, "store_csw chan %x maddr %x addr %x\r\n", chan, maddr, addr); - addr = (addr & 0xff) << 24; /* put sub address in byte 0 */ - M[maddr >> 2] = caw[chan] | addr; /* IOCD address and sub address */ - /* save 16 bit channel status and residual byte count in SW 2 */ - M[(maddr+4) >> 2] = (((uint32)ccw_count[chan])) | ((uint32)chan_status[chan]<<16); - chan_status[chan] = 0; /* no status anymore */ - chan_dev[chan] = 0; /* no ch/sa device definition */ -sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %06x %08x\n", - chan, M[maddr>>2], M[(maddr+4)>>2]); - /* now store the status dw address into word 5 of the ICB for the channel */ - M[(chan_icb[chan] + 20) >> 2] = maddr; /* post sw addr in ICB+5w */ - return chan_dev[chan]; + /* put sub address in byte 0 */ + stwd1 = ((chsa & 0xff) << 24) | chp->chan_caw; /* subaddress and IOCD address to SW 1 */ + /* save 16 bit channel status and residual byte count in SW 2 */ + stwd2 = ((uint32)chp->chan_status << 16) | ((uint32)chp->ccw_count); + if ((FIFO_Put(chsa, stwd1) == -1) || (FIFO_Put(chsa, stwd2) == -1)) { + fprintf(stderr, "FIFO Overflow ERROR on chsa %x\r\n", chsa); + } + + chp->chan_status = 0; /* no status anymore */ + irq_pend = 1; /* wakeup controller */ } /* SIO CC status returned to caller */ /* val condition */ -/* 0 command accepted - no CC's */ +/* 0 command accepted, will echo status - no CC's */ /* 1 channel busy - CC4 */ /* 2 channel inop or undefined (operator intervention required) - CC3 */ /* 3 sub channel busy CC3 + CC4 */ @@ -556,7 +781,7 @@ sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %06x %08x\n", /* 5 unsupported transaction CC2 + CC4 */ /* 6 unassigned CC2 + CC3 */ /* 7 unassigned CC2 + CC3 + CC4 */ -/* 8 command accepted - CC1 */ +/* 8 command accepted/queued, no echo status - CC1 */ /* 9 unassigned */ /* a unassigned */ /* b unassigned */ @@ -569,358 +794,738 @@ sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %06x %08x\n", /* chan channel number 0-7f */ /* suba unit address within channel 0-ff */ /* Condition codes to return 0-f as specified above */ -t_stat startxio(uint16 addr, uint32 *status) { - int chan = find_subchan(addr); /* get the channel number */ - DIB *dibp = dev_unit[addr]; /* get the device information pointer */ - UNIT *uptr; - uint32 chan_ivl; /* Interrupt Level ICB address for channel */ - uint32 iocla; /* I/O channel IOCL address int ICB */ - uint32 stata; /* I/O channel status location in ICB */ - uint32 tempa, inta, spadent; +t_stat startxio(uint16 lchsa, uint32 *status) +{ + int lchan = get_chan(lchsa); /* get the logical channel number */ + DIB *dibp; /* device information pointer */ + UNIT *uptr; /* pointer to unit in channel */ + uint32 chan_ivl; /* Interrupt Level ICB address for channel */ + uint32 iocla; /* I/O channel IOCL address int ICB */ + uint32 tempa, inta, spadent, chan; + uint16 chsa; + CHANP *chp; -fprintf(stderr, "chan startxio 1 addr %0x chan %x\r\n", addr, chan); - if (chan < 0 || dibp == 0) { /* no channel found, CC3 return */ - *status = CC3BIT; /* not found, so CC3 */ - return SCPE_OK; /* not found, CC3 */ - } - uptr = find_chan_dev(addr); /* find pointer to unit on channel */ - if (uptr == 0) { /* if non found, CC3 on return */ - *status = CC3BIT; /* not found, so CC3 */ - return SCPE_OK; /* not found, CC3 */ - } -fprintf(stderr, "chan startxio 2 addr %0x chan %x\r\n", addr, chan); - if ((uptr->flags & UNIT_ATT) == 0) { /* is unit already attached? */ - *status = CC3BIT; /* not attached, so error CC3 */ - return SCPE_OK; /* not found, CC3 */ - } - /* see if interrupt is setup in SPAD and determine IVL for channel */ - spadent = SPAD[chan]; /* get spad device entry for channel */ -fprintf(stderr, "startxio dev spad %0.8x addr %x chan %x\r\n", spadent, addr, chan); - /* the startio opcode processing software has already checked for F class */ -// if (spadent & 0x0f000000 != 0x0f000000) { /* I/O class in bits 4-7 */ -// *status = CC3BIT; /* not valid entry, so CC3 */ -// return SYSTEMCHK_TRP; /* not found, CC3 */ -// } - 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 */ -fprintf(stderr, "startxio int spad %0.8x inta %x chan %x\r\n", spadent, inta, chan); - /* get the address of the interrupt IVL in main memory */ - 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 */ - chan_icb[chan] = chan_ivl; /* point to 6 wd ICB, iocla is in wd4 and status addr in w5 */ - iocla = M[(chan_ivl+16)>>2]; /* iocla is in wd 4 of ICB */ -fprintf(stderr, "chan startxio busy test addr %0x chan %x cmd %x flags %x\r\n", - addr, chan, ccw_cmd[chan], ccw_flags[chan]); + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[lchan]; /* get spad device entry for logical channel */ + chan = (spadent & 0xff00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + 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 */ -sim_debug(DEBUG_CMD, &cpu_dev, "SIO %x %x %x %x\n", addr, chan, ccw_cmd[chan], ccw_flags[chan]); - /* check for a Command or data chain operation in progresss */ - if (ccw_cmd[chan] != 0 || (ccw_flags[chan] & (FLAG_DC|FLAG_CC)) != 0) { -fprintf(stderr, "startxio busy return CC4\r\n"); - *status = CC4BIT; /* busy, so CC4 */ - return SCPE_OK; /* just busy CC4 */ - } +// fprintf(stderr, "SIO chan startxio 1 spad[%x] %x lchsa %x chsa %0x chan %x\r\n", +// lchan, spadent, lchsa, chsa, chan); + sim_debug(DEBUG_CMD, &cpu_dev, "startxio 1 chsa %x chan %x\n", chsa, chan); + 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 */ + } +// fprintf(stderr, "SIO chan startxio 2 spad[%x] %x lchsa %x chsa %0x chan %x\r\n", +// lchan, spadent, lchsa, chsa, chan); + sim_debug(DEBUG_CMD, &cpu_dev, "startxio 2 chsa %x chan %x\n", chsa, chan); + if ((uptr->flags & UNIT_ATT) == 0) { /* is unit attached? */ + fprintf(stderr, "startxio chsa %x is not attached, error return\r\n", chsa); + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ + } + /* see if interrupt is setup in SPAD and determine IVL for channel */ +// fprintf(stderr, "startxio dev spad %.8x chsa %x chan %x\r\n", spadent, chsa, chan); + sim_debug(DEBUG_CMD, &cpu_dev, "startxio dev spad %.8x chsa %x chan %x\n", spadent, chsa, chan); - /* not busy, so start a new command */ - chan_status[chan] = 0; /* no channel status yet */ - dev_status[addr] = 0; /* no unit status either */ - caw[chan] = iocla; /* get iocla address in memory */ - chan_dev[chan] = addr; /* save the ch/sa too */ - /* set status words in memory to first IOCD information */ - tempa = chan_inch_addr[chan]; /* get inch status buffer address */ - M[tempa >> 2] = (addr & 0xff) << 24 | iocla; /* sa & IOCD address to status */ - M[(tempa+2) >> 2] = 0; /* null status and residual byte count */ + 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, "startxio int spad %.8x inta %x chan %x\n", spadent, inta, chan); - /* determine if channel DIB has a startio command processor */ - if (dibp->start_io != NULL) { /* NULL if no startio function */ - chan_status[chan] = dibp->start_io(uptr, chan) << 8; /* get status from device */ - if (chan_status[chan] != 0) { /* see if channel status is ready */ - /* save the status double word to memory */ - /* for SEL32, this memory address must be supplied by software using */ - /* the SIO cmd 0 (INCH) to set the status memory doublewd location */ - store_csw(chan); /* store the status in the inch status dw */ -sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %08x\r\n", chan, chan_status[chan]); -fprintf(stderr, "startxio status store csw CC4 chan %x cstat %x\r\n", chan, chan_status[chan]); - chan_status[chan] = 0; /* no status anymore */ - *status = CC2BIT; /* status stored, so CC2 */ - return SCPE_OK; /* CC2 (0x4) status stored */ - } - } - /* start processing the IOCD */ - if (load_ccw(chan, 0) || (chan_status[chan] & (STATUS_PCI))) { -fprintf(stderr, "chan startxio after load_ccw addr %0x status %x\r\n", addr, chan_status[chan]); - store_csw(chan); /* store the status in the inch status dw */ -sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %08x\n", chan, chan_status[chan]); - chan_status[chan] &= ~STATUS_PCI; /* remove PCI status bit */ - dev_status[addr] = 0; /* no device status */ - *status = CC4BIT; /* channel busy, so CC4 */ - return SCPE_OK; /* CC4 (0x01) channel busy */ - } - if (chan_status[chan] & STATUS_BUSY) { -fprintf(stderr, "chan startxio busy addr %0x status %x\r\n", addr, chan_status[chan]); -sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %08x\n", chan, chan_status[chan]); - store_csw(chan); /* store the status in the inch status dw */ - M[tempa >> 2] = 0; /* zero sa & IOCD address in status WD 1 */ - chan_dev[chan] = 0; /* zero device info */ - chan_status[chan] = 0; /* no channel status */ - dev_status[addr] = 0; /* not unit status */ - ccw_cmd[chan] = 0; /* no cmd either */ - *status = CC4BIT; /* channel busy, so CC4 */ - return SCPE_OK; /* CC4 (0x01) channel busy */ - } + /* get the address of the interrupt IVL in main memory */ + 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_CMD, &cpu_dev, "startxio busy test chsa %0x chan %x cmd %x flags %x IOCD1 %x IOCD2 %x\n", + chsa, chan, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); +// fprintf(stderr, "startxio busy test chsa %0x chan %x cmd %x flags %x iocla %x IOCD1 %x IOCD2 %x\r\n", +// chsa, chan, chp->ccw_cmd, chp->ccw_flags, iocla, M[iocla>>2], M[(iocla+4)>>2]); -fprintf(stderr, "chan startxio done addr %0x status %x\r\n", addr, chan_status[chan]); - *status = 0; /* CCs = 0, SIO accepted */ - return SCPE_OK; /* No CC's all OK */ -} + sim_debug(DEBUG_CMD, &cpu_dev, "$$$ SIO %x %x cmd %x flags %x\n", + chsa, chan, chp->ccw_cmd, chp->ccw_flags); +// fprintf(stderr, "$$$ SIO %x %x cmd %x flags %x iocla %x\r\n", +// chsa, chan, chp->ccw_cmd, chp->ccw_flags, iocla); + /* check for a Command or data chain operation in progresss */ + if (chp->ccw_cmd != 0 || (chp->ccw_flags & (FLAG_DC|FLAG_CC)) != 0) { +// fprintf(stderr, "startxio busy return CC4 cmd %x flags %x\r\n", chp->ccw_cmd, chp->ccw_flags); + sim_debug(DEBUG_CMD, &cpu_dev, "startxio busy return CC4 chsa %x chan %x\n", chsa, chan); + *status = CC4BIT; /* busy, so CC4 */ + return SCPE_OK; /* just busy CC4 */ + } -t_stat testxio(uint16 addr, uint32 *status) { - int chan = find_subchan(addr); - DIB *dibp = dev_unit[addr]; - UNIT *uptr; -// uint8 status; + /* determine if channel DIB has a pre startio command processor */ + if (dibp->pre_io != NULL) { /* NULL if no startio function */ + /* call the device controller to get prestart_io status */ + tempa = dibp->pre_io(uptr, chan); /* get status from device */ + if (tempa != 0) { /* see if sub channel status is ready */ + /* The device must be busy or something, but it is not ready. Return busy */ + sim_debug(DEBUG_CMD, &cpu_dev, "startxio start_io call return busy chan %x cstat %08x\n", + chan, tempa); + chp->chan_status = 0; /* no status anymore */ + *status = CC3BIT|CC4BIT; /* sub channel busy, so CC3|CC4 */ + return SCPE_OK; /* just busy or something, CC3|CC4 */ + } + } -fprintf(stderr, "chan testxio addr %0x chan %x\r\n", addr, chan); -#if 0 - if (chan < 0 || dibp == 0) - return 3; - uptr = find_chan_dev(addr); - if (uptr == 0) - return 3; - if ((uptr->flags & UNIT_ATT) == 0) - return 3; - if (ccw_cmd[chan] != 0 || (ccw_flags[chan] & (FLAG_DC|FLAG_CC)) != 0) - return 2; - if (chan_dev[chan] != 0 && chan_dev[chan] != addr) - return 2; - if (ccw_cmd[chan] == 0 && chan_status[chan] != 0) { - store_csw(chan); - dev_status[addr] = 0; - return 1; - } - if (dev_status[addr] != 0) { - M[0x40 >> 2] = 0; - M[0x44 >> 2] = ((uint32)dev_status[addr]) << 24; - dev_status[addr] = 0; - return 1; - } - chan_status[chan] = dibp->start_cmd(uptr, chan, 0) << 8; - if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) { - M[0x44 >> 2] = ((uint32)chan_status[chan]<<16) | M[0x44 >> 2] & 0xffff; - chan_status[chan] = 0; - dev_status[addr] = 0; - return 1; - } - chan_status[chan] = 0; + /* channel not busy and ready to go, so start a new command */ + chp->chan_status = 0; /* no channel status yet */ + dev_status[chsa] = 0; /* no unit status either */ + chp->chan_caw = iocla; /* get iocla address in memory */ + /* set status words in memory to first IOCD information */ + tempa = chp->chan_inch_addr; /* get inch status buffer address */ + if (tempa != 0) { + M[tempa >> 2] = (chsa & 0xff) << 24 | iocla; /* suba & IOCD address to status */ + M[(tempa+4) >> 2] = 0; /* null status and residual byte count */ + } + + sim_debug(DEBUG_CMD, &cpu_dev, "$$ SIO starting IOCL processing chsa %02x\n", chsa); +// fprintf(stderr, "$$ SIO starting IOCL processsing chsa %0x\r\n", chsa); + + /* start processing the IOCL */ + if (load_ccw(chp, 0) || (chp->chan_status & STATUS_PCI)) { + /* we have an error or user requested interrupt, return status */ +// fprintf(stderr, "chan startxio after load_ccw chsa %0x status %x\r\n", chsa, chp->chan_status); + store_csw(chp); /* store the status in the inch status dw */ + sim_debug(DEBUG_CMD, &cpu_dev, "startxio store csw CC1 chan %02x status %08x\n", chan, chp->chan_status); +// fprintf(stderr, "startxio store csw CC1 chan %02x status %08x\n", chan, chp->chan_status); + chp->chan_status &= ~STATUS_PCI; /* remove PCI status bit */ + dev_status[chsa] = 0; /* no device status */ + *status = CC1BIT; /* status stored, so CC1 */ + return SCPE_OK; /* CC1 (0x40) status stored */ + } + +#if NOT_NEEDED + if (chp->chan_status & STATUS_BUSY) { + fprintf(stderr, "chan startxio busy chan %0x status %x\r\n", chsa, chp->chan_status); + sim_debug(DEBUG_CMD, &cpu_dev, "startxio store busy chan %x status %08x\n", chan, chp->chan_status); + store_csw(chp); /* store the status in the inch status dw */ + M[tempa >> 2] = 0; /* zero sa & IOCD address in status WD 1 */ + chp->chan_status = 0; /* no channel status */ + dev_status[chsa] = 0; /* no unit status */ + chp->ccw_cmd = 0; /* no cmd either */ + *status = CC4BIT; /* channel busy, so CC4 */ + return SCPE_OK; /* CC4 (0x01) channel busy */ + } #endif - - return 0; + if ((chp->ccw_cmd & 0xFF) == 0) /* see if this is an initialize channel cmd */ + *status = CC1BIT; /* request accepted, no status, so CC1 TRY THIS */ + else + *status = 0; /* CCs = 0, SIO accepted, will echo status */ +// fprintf(stderr, "$$$ SIO done chsa %0x status %x\r\n", chsa, chp->chan_status); + sim_debug(DEBUG_CMD, &cpu_dev, "$$$ SIO done chsa %x status %08x\n", chsa, chp->chan_status); + return SCPE_OK; /* No CC's all OK */ } -t_stat stopxio(uint16 addr, uint32 *status) { - int chan = find_subchan(addr); - DIB *dibp = dev_unit[addr]; - UNIT *uptr; -// uint8 status; +/* TIO - I/O status */ +t_stat testxio(uint16 lchsa, uint32 *status) /* test XIO */ +{ + uint32 chan = get_chan(lchsa); + DIB *dibp; + UNIT *uptr; + uint32 chan_ivl; /* Interrupt Level ICB address for channel */ + uint32 iocla; /* I/O channel IOCL address int ICB */ + uint32 stata; /* I/O channel status location in ICB */ + uint32 tempa, inta, spadent; + uint16 chsa; /* chan/subaddr */ + CHANP *chp, *pchp; /* Channel prog pointers */ + uint32 sw1, sw2; /* status word 1 & 2 */ -fprintf(stderr, "chan stopxio addr %0x chan %x\r\n", addr, chan); -#if 0 - if (chan < 0 || dibp == 0) - return 3; - uptr = find_chan_dev(chan_dev[chan]); - if (uptr == 0) - return 3; - if (ccw_cmd[chan]) { - chan_byte[chan] = BUFF_CHNEND; - return 2; - } - if (dibp->halt_io != NULL) - chan_status[chan] = dibp->halt_io(uptr) << 8; -#endif + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[chan]; /* get spad device entry for logical channel */ + chan = (spadent & 0xff00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + dibp = dev_unit[chsa]; /* get the device information pointer */ + chp = find_chanp_ptr(chsa); /* find the device chanp pointer */ + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + pchp = find_chanp_ptr(chsa & 0x7f00); /* find the channel chanp pointer */ - return 0; +// fprintf(stderr, "TIO chan testxio 1 spad[%x] %x lchsa %x chsa %0x chan %x\r\n", +// lchsa, spadent, lchsa, chsa, chan); + sim_debug(DEBUG_CMD, &cpu_dev, "testxio 1 chsa %x chan %x\n", chsa, chan); + if ((dibp == 0) || (uptr == 0)) { /* if non found, CC3 on return */ + *status = CC3BIT; /* not found, so CC3 */ + goto tioret; /* not found, CC3 */ + } + sim_debug(DEBUG_CMD, &cpu_dev, "testxio 2 chsa %x chan %x\n", chsa, chan); + if ((uptr->flags & UNIT_ATT) == 0) { /* is unit already attached? */ + *status = CC3BIT; /* not attached, so error CC3 */ + goto tioret; /* not found, CC3 */ + } + /* see if interrupt is setup in SPAD and determine IVL for channel */ + sim_debug(DEBUG_CMD, &cpu_dev, "testxio dev spad %.8x chsa %x chan %x\n", spadent, chsa, chan); + + /* the startio opcode processing software has already checked for F class */ + 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, "testxio int spad %.8x inta %x chan %x\n", spadent, inta, chan); + + /* get the address of the interrupt IVL in main memory */ + 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_CMD, &cpu_dev, "testxio busy test chsa %0x chan %x cmd %x flags %x IOCD1 %x IOCD2 %x\n", + chsa, chan, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); +// fprintf(stderr, "testxio busy test chsa %0x chan %x cmd %x flags %x IOCD1 %x IOCD2 %x\r\n", +// chsa, chan, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); + + sim_debug(DEBUG_CMD, &cpu_dev, "$$$ TIO %x %x %x %x\n", chsa, chan, chp->ccw_cmd, chp->ccw_flags); +// fprintf(stderr, "$$$ TIO chsa %x chan %x cmd %x flags %x\r\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_CMD, &cpu_dev, "testxio busy return CC4 chsa %x chan %x\n", chsa, chan); + *status = CC4BIT; /* busy, so CC4 */ + goto tioret; /* just busy CC4 */ + } + /* 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_CMD, &cpu_dev, "testxio status stored OK, sw1 %x sw2 %x\n", sw1, sw2); +// fprintf(stderr, "testxio status stored OK, sw1 %x sw2 %x\r\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 | BIT1; /* post sw addr in ICB+5w & set CC2 in INCH addr */ + *status = CC2BIT; /* status stored from SIO, so CC2 */ + goto tioret; /* CC2 and OK */ + } + /* nothing going on, so say all OK */ + *status = CC1BIT; /* request accepted, no status, so CC1 TRY THIS */ +tioret: +// fprintf(stderr, "$$$ TIO END chsa %x chan %x cmd %x flags %x chan_stat %x CCs %x\r\n", +// chsa, chan, chp->ccw_cmd, chp->ccw_flags, chp->chan_status, *status); + return SCPE_OK; /* No CC's all OK */ } -int testchan(uint16 channel) { - uint16 st = 0; - channel >>= 8; - if (channel == 0) - return 0; - if (channel > channels) - return 3; - st = chan_status[subchannels + channel]; - if (st & STATUS_BUSY) - return 2; - if (st & (STATUS_ATTN|STATUS_PCI|STATUS_EXPT|STATUS_CHECK| - STATUS_PROT|STATUS_CDATA|STATUS_CCNTL|STATUS_INTER| - STATUS_CHAIN)) - return 1; - return 0; +/* Stop XIO */ +t_stat stopxio(uint16 lchsa, uint32 *status) /* stop XIO */ +{ + int chan = get_chan(lchsa); + DIB *dibp; + UNIT *uptr; + uint32 chan_ivl; /* Interrupt Level ICB address for channel */ + uint32 iocla; /* I/O channel IOCL address int ICB */ + uint32 inta, spadent; + uint16 chsa; + CHANP *chp; + + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[chan]; /* get spad device entry for logical channel */ + chan = (spadent & 0xff00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + 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 */ + + sim_debug(DEBUG_CMD, &cpu_dev, "stopxio 1 chsa %x chan %x\n", chsa, chan); + 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, "stopxio 2 chsa %x chan %x\n", chsa, chan); + if ((uptr->flags & UNIT_ATT) == 0) { /* is unit already attached? */ + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ + } + /* see if interrupt is setup in SPAD and determine IVL for channel */ + sim_debug(DEBUG_CMD, &cpu_dev, "stopxio dev spad %.8x chsa %x chan %x\n", spadent, chsa, chan); + + /* the startio opcode processing software has already checked for F class */ + 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 %.8x inta %x chan %x\n", spadent, inta, chan); + + /* get the address of the interrupt IVL in main memory */ + 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_CMD, &cpu_dev, "stopxio busy test chsa %0x chan %x cmd %x flags %x IOCD1 %x IOCD2 %x\n", + chsa, chan, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); + +// sim_debug(DEBUG_CMD, &cpu_dev, "$$$ STOPIO %x %x %x %x\n", chsa, chan, chp->ccw_cmd, chp->ccw_flags); +// fprintf(stderr, "$$$ STOPIO %x %x %x %x\r\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_CMD, &cpu_dev, "stopxio busy return CC4 chsa %x chan %x\n", chsa, chan); +// fprintf(stderr, "stopxio busy return CC4 chsa %x chan %x\r\n", chsa, chan); + /* 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 */ + return SCPE_OK; /* just busy CC4 */ + } + /* the channel is not busy, so return OK */ + *status = 0; /* CCs = 0, accepted */ +// fprintf(stderr, "$$$ STOPIO good return chsa %x chan %x cmd %x flags %x status %x\r\n", +// chsa, chan, chp->ccw_cmd, chp->ccw_flags, *status); + return SCPE_OK; /* No CC's all OK */ +} + +/* Reset Channel XIO */ +t_stat rschnlxio(uint16 lchsa, uint32 *status) /* reset channel XIO */ +{ + DIB *dibp; + UNIT *uptr; + uint32 spadent; + uint16 chsa; + CHANP *chp; + int lev, i; + uint32 chan = get_chan(lchsa); + + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[chan]; /* get spad device entry for logical channel */ + chan = spadent & 0x7f00; /* get real channel */ + chsa = chan; /* use just channel */ + 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 */ + + sim_debug(DEBUG_CMD, &cpu_dev, "rschnlxio 1 chan %x SPAD %x\n", chsa, spadent); +// fprintf(stderr, "rschnlxio 1 chan %x spad %x\r\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 %x, spad %x\r\n", chsa, spadent); +// fprintf(stderr, "rschnlxio 2 chan %x, spad %x\n", chsa, spadent); + if ((uptr->flags & UNIT_ATT) == 0) { /* is unit already attached? */ + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ + } + /* reset the FIFO pointers */ + dibp->chan_fifo_in = 0; + dibp->chan_fifo_out = 0; + dev_status[chan] = 0; /* clear the channel status location */ + chp->chan_inch_addr = 0; /* remove inch status buffer address */ + lev = find_int_lev(chan); /* get our int level */ + INTS[lev] &= ~INTS_ACT; /* clear level active */ + INTS[lev] &= ~INTS_REQ; /* clear level request */ + SPAD[lev+0x80] &= ~SINT_ACT; /* clear spad too */ + + /* now go through all the sa for the channel and stop any IOCLs */ + 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; /* not used */ + } + chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + if (chp == 0) { +// fprintf(stderr, "rschnl found dib without valid chp for chsa %x, ignoring\r\n", chsa); + continue; /* not used */ + } +// fprintf(stderr, "rschnl found dib and chp for chsa %x, resetting\r\n", chsa); + dev_status[chsa] = 0; /* clear device status */ + chp->chan_status = 0; /* clear the channel status */ + chp->chan_byte = BUFF_EMPTY; /* no data yet */ + chp->ccw_addr = 0; /* clear buffer address */ + chp->chan_caw = 0x0; /* clear IOCD address */ + chp->ccw_count = 0; /* channel byte count 0 bytes*/ + chp->ccw_flags = 0; /* clear flags */ + chp->ccw_cmd = 0; /* read command */ + } + sim_debug(DEBUG_CMD, &cpu_dev, "rschnlxio return CC1 chan %x lev %x\n", chan, lev); +// fprintf(stderr, "RSCHNL rschnlxio return CC1 chan %x lev %x\r\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 */ +{ + int chan = get_chan(lchsa); + DIB *dibp; + UNIT *uptr; + uint32 chan_ivl; /* Interrupt Level ICB address for channel */ + uint32 iocla; /* I/O channel IOCL address int ICB */ + uint32 inta, spadent; + uint16 chsa; + CHANP *chp; + + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[chan]; /* get spad device entry for logical channel */ + chan = (spadent & 0xff00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + 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 */ + + sim_debug(DEBUG_CMD, &cpu_dev, "haltxio 1 chsa %x chan %x\n", chsa, chan); + 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, "haltxio 2 chsa %x chan %x\n", chsa, chan); + if ((uptr->flags & UNIT_ATT) == 0) { /* is unit already attached? */ + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ + } + /* see if interrupt is setup in SPAD and determine IVL for channel */ + sim_debug(DEBUG_CMD, &cpu_dev, "haltxio dev spad %.8x chsa %x chan %x\n", spadent, chsa, chan); + + /* the startio opcode processing software has already checked for F class */ + 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, "haltxio int spad %.8x inta %x chan %x\n", spadent, inta, chan); + + /* get the address of the interrupt IVL in main memory */ + 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_CMD, &cpu_dev, "haltxio busy test chsa %0x chan %x cmd %x flags %x IOCD1 %x IOCD2 %x\n", + chsa, chan, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); + + sim_debug(DEBUG_CMD, &cpu_dev, "$$$ HIO %x %x %x %x\n", chsa, chan, chp->ccw_cmd, chp->ccw_flags); +// fprintf(stderr, "$$$ HIO %x %x %x %x\r\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_CMD, &cpu_dev, "haltxio busy return CC4 chsa %x chan %x\n", chsa, chan); + fprintf(stderr, "HIO haltxio busy return CC4 chsa %x chan %x\r\n", chsa, chan); + /* 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 = 0; /* not busy, no CC */ + goto hioret; /* just busy CC4 */ + } + /* the channel is not busy, so return OK */ + *status = CC2BIT; /* INCH status stored, so CC2 TRY */ +hioret: +// fprintf(stderr, "$$$ HIO END chsa %x chan %x cmd %x flags %x status %x\r\n", +// chsa, chan, chp->ccw_cmd, chp->ccw_flags, *status); + return SCPE_OK; /* No CC's all OK */ +} + +/* grab controller n/u */ +/* TODO return unimplemented function error, not busy */ +t_stat grabxio(uint16 lchsa, uint32 *status) /* grab controller XIO n/u */ +{ + int chan = get_chan(lchsa); + uint32 spadent; + uint16 chsa; + CHANP *chp; + + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[chan]; /* get spad device entry for logical channel */ + chan = (spadent & 0xff00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + + /* 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, "grabxio busy return CC4 chsa %x chan %x\n", chsa, chan); + *status = CC4BIT; /* busy, so CC4 */ + return SCPE_OK; /* CC4 all OK */ + } + *status = 0; /* not busy, no CC */ +// fprintf(stderr, "chan grabxio chsa %0x chan %x\r\n", chsa, chan); + sim_debug(DEBUG_CMD, &cpu_dev, "grabxio chsa %x chan %08x\n", chsa, chan); + return 0; +} + +/* reset controller XIO */ +t_stat rsctlxio(uint16 lchsa, uint32 *status) /* reset controller XIO */ +{ + int chan = get_chan(lchsa); + uint32 spadent; + uint16 chsa; + CHANP *chp; + + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[chan]; /* get spad device entry for logical channel */ + chan = (spadent & 0xff00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + + *status = 0; /* not busy, no CC */ +// fprintf(stderr, "chan rsctlxio chsa %0x chan %x\r\n", chsa, chan); + sim_debug(DEBUG_CMD, &cpu_dev, "rsctlxio chsa %x chan %08x\n", chsa, chan); + return 0; } /* boot from the device (ch/sa) the caller specified */ -t_stat chan_boot(uint16 addr, DEVICE *dptyr) { - int chan = find_subchan(addr); - DIB *dibp = dev_unit[addr]; - UNIT *uptr; - uint8 status; - int i; +/* on CPU reset, the cpu has set the IOCD data at location 0-4 */ +t_stat chan_boot(uint16 chsa, DEVICE *dptr) +{ + int chan = get_chan(chsa); + DIB *dibp = dev_unit[chsa]; + CHANP *chp = dibp->chan_prg; + int i,j; -fprintf(stderr, "chan_boot addr %0x\r\n", addr); - if (chan < 0 || dibp == 0) /* if no channel or device, error */ - return SCPE_IOERR; /* error */ - for (i = 0; i < MAX_DEV; i++) { - dev_status[i] = 0; /* clear all of the device status locations */ - } - for (i = 0; i < MAX_CHAN; i++) { /* loop through all the channels */ - ccw_cmd[i] = 0; /* clear channel command and flags */ - ccw_flags[i] = 0; /* clear channel flags */ -// chan_icb[i] = 0; /* Interrupt Context Block address in memory */ -// chan_inch_addr[i] = 0; /* Channel status dw in memory */ - } - uptr = find_chan_dev(addr); /* find the unit pointer */ - chan_status[chan] = 0; /* clear the channel status */ - dev_status[addr] = 0; /* device status too */ - caw[chan] = 0x8; /* set IOCD address to memory location 8 */ - chan_dev[chan] = addr; /* save our address (ch/sa) */ - ccw_count[chan] = 24; /* channel byte count */ - ccw_flags[chan] = FLAG_CC|FLAG_SLI; /* Command chain and supress incorrect length */ - ccw_addr[chan] = 0; /* start loading at loc 0 */ - chan_byte[chan] = BUFF_EMPTY; /* do data yet */ - ccw_cmd[chan] = 0x2; /* read command */ - chan_status[chan] &= 0xff; /* zero all but status bits */ - /* now call the controller to boot the device */ - /* sense status is returned */ - chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8; -fprintf(stderr, "chan_boot after start chan %0x status %0.8x\r\n", chan, chan_status[chan]); - /* any bad bits set ? */ - if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) { - ccw_flags[chan] = 0; /* clear the command flags */ - return SCPE_IOERR; /* return error */ - } - loading = addr; /* show we are loading from the boot device */ - return SCPE_OK; /* all OK */ + sim_debug(DEBUG_EXP, &cpu_dev, "Channel Boot chan/device addr %x\n", chsa); +// fprintf(stderr, "chan_boot chsa %0x\r\n", chsa); + if (dibp == 0) /* if no channel or device, error */ + return SCPE_IOERR; /* error */ + if (dibp->chan_prg == NULL) /* must have channel information for each device */ + return SCPE_IOERR; /* error */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + + dev_status[chsa&0x7f00] = 0; /* clear the channel status location */ + dev_status[chsa] = 0; /* device status too */ + chp->chan_status = 0; /* clear the channel status */ + chp->chan_dev = chsa; /* save our address (ch/sa) */ + chp->chan_byte = BUFF_EMPTY; /* no data yet */ + chp->ccw_addr = 0; /* start loading at loc 0 */ + chp->chan_caw = 0x0; /* set IOCD address to memory location 0 */ + chp->ccw_count = 0; /* channel byte count 0 bytes*/ + chp->ccw_flags = 0; /* Command chain and supress incorrect length */ + chp->ccw_cmd = 0; /* read command */ + + sim_debug(DEBUG_CMD, &cpu_dev, "Channel Boot calling load_ccw chan %02x status %08x\n", + chan, chp->chan_status); +// fprintf(stderr, "Channel Boot calling load_ccw chan %02x status %08x\r\n", +// chan, chp->chan_status); + + /* start processing the boot IOCL at loc 0 */ + if (load_ccw(chp, 0)) { /* load IOCL starting from location 0 */ + sim_debug(DEBUG_CMD, &cpu_dev, "Channel Boot Error return from load_ccw chan %02x status %08x\n", + chan, chp->chan_status); +// fprintf(stderr, "Channel Boot Error return from load_ccw chan %02x status %08x\r\n", +// chan, chp->chan_status); + dev_status[chsa] = 0; /* no device status */ + chp->ccw_flags = 0; /* clear the command flags */ + return SCPE_IOERR; /* return error */ + } +// fprintf(stderr, "Channel Boot OK return from load_ccw chsa %02x status %08x\r\n", +// chsa, chp->chan_status); + loading = chsa; /* show we are loading from the boot device */ + return SCPE_OK; /* all OK */ } /* Scan all channels and see if one is ready to start or has interrupt pending. */ -uint32 scan_chan(void) { - int i; - int pend = 0; /* No device */ - uint32 tempa; /* icb address */ +uint32 scan_chan(void) +{ + int i,j; + uint32 chsa = 0; /* No device */ + 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 */ -fprintf(stderr, "scan_chan start irq_pending %x\r\n", irq_pend); - if (irq_pend == 0) /* pending int? */ - return 0; /* no, so just return */ - irq_pend = 0; /* not pending anymore */ + /* see if we are able to look for ints */ + if ((CPUSTATUS & 0x80) == 0) { /* are interrupts blocked */ + /* ints not blocked, so look for highest requesting interrupt */ + for (i=0; i<112; i++) { + if (INTS[i]&INTS_ACT) /* look for level active */ + break; /* this level active, so stop looking */ + if (SPAD[i+0x80] == 0) /* not initialize? */ + continue; /* skip this one */ + if (SPAD[i+0x80] == 0xffffffff) /* not initialize? */ + continue; /* skip this one */ + /* see if there is pending status for this channel */ + /* if there is and the level is not requesting, do it */ + if ((INTS[i] & INTS_ENAB) && !(INTS[i] & INTS_REQ)) { + /* get the device entry for the logical channel in SPAD */ + chan = (SPAD[i+0x80] & 0xff00); /* get real channel and zero sa */ + dibp = dev_unit[chan]; /* get the device information pointer */ + if (dibp == 0) + continue; /* skip unconfigured channel */ + /* see if the FIFO is empty */ + if (dibp->chan_fifo_in != dibp->chan_fifo_out) { + uint32 sw1, sw2; + /* fifo is not empty, so post status and request an interrupt */ + if ((FIFO_Get(chan, &sw1) == 0) && (FIFO_Get(chan, &sw2) == 0)) { + /* we have status to return, do it now */ + 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 */ + tempa = chp->chan_inch_addr; /* get inch status buffer address */ +// fprintf(stderr, "FOUND INT %x SPAD %x chan %x icb %x inch %x\r\n", i, SPAD[i+0x80], chan, chan_icba, tempa); + 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 */ + //FIXME - TEST for IOP device here + /* 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 */ + INTS[i] |= INTS_REQ; /* turn on channel interrupt request */ + } + } + } + /* look for the highest requesting interrupt */ + /* that is enabled */ + if (((INTS[i] & INTS_ENAB) && (INTS[i] & INTS_REQ)) || + ((SPAD[i+0x80] & INTS_ENAB) && (INTS[i] & INTS_REQ))) { + /* requesting, make active and turn off request flag */ + INTS[i] &= ~INTS_REQ; /* turn off request */ + INTS[i] |= INTS_ACT; /* turn on active */ + SPAD[i+0x80] |= SINT_ACT; /* show active in SPAD too */ + /* make sure both enabled too */ + 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_EXP, &cpu_dev, "scan_chan INTS REQ irq %x found chan_icba %x INTS %x\n", + i, chan_icba, INTS[i]); + return(chan_icba); /* return ICB address */ + } + } + } + if (irq_pend == 0) /* pending int? */ + return 0; /* no, so just return */ + irq_pend = 0; /* not pending anymore */ - /* loop through all the channels/units for channel with pending interrupt */ - for (i = 0; i < MAX_CHAN; i++) { - /* If channel end, check if we should continue */ - if (chan_status[i] & STATUS_CEND) { /* do we have channel end */ - if (ccw_flags[i] & FLAG_CC) { /* command chain flag */ - if (chan_status[i] & STATUS_DEND) /* device end? */ - (void)load_ccw(i, 1); /* go load the next IOCB */ - else - irq_pend = 1; /* still pending int */ - } else { - /* we have channel end and no CC flag, end it */ -sim_debug(DEBUG_EXP, &cpu_dev, "Scan(%x %x) end\n", i, chan_status[i]); - if (loading != 0) /* boot loading? */ - pend = chan_dev[i]; /* get the chan number */ - break; - } - } - } -fprintf(stderr, "scan_chan pend %x\r\n", pend); - /* process any pending channel */ - if (pend) { - irq_pend = 1; /* int still pending */ - i = find_subchan(pend); /* find channel */ -fprintf(stderr, "scan_chan pend %x chan %x\r\n", pend, i); - if (i >= 0) { -sim_debug(DEBUG_EXP, &cpu_dev, "Scan end (%x %x)\n", chan_dev[i], pend); - store_csw(i); /* store the status */ - } - dev_status[pend] = 0; - } else { - for (pend = 0; pend < MAX_DEV; pend++) { /* loop through all the channels/units */ - if (dev_status[pend] != 0) { /* any pending status */ - i = find_subchan(pend); /* get channel from device number */ -// if (i >= 0 && ccw_cmd[i] == 0 && mask & (0x80 >> (pend >> 8))) { -fprintf(stderr, "scan_chan 3 pend %x chan %x inch %x\r\n", pend, i, chan_inch_addr[i]); - if (i >= 0 && ccw_cmd[i] == 0 && chan_inch_addr[i] != 0) { -fprintf(stderr, "scan_chan 3a pend %x chan %x inch %x\r\n", pend, i, chan_inch_addr[i]); - tempa = chan_inch_addr[i]; /* get inch status buffer address */ - irq_pend = 1; /* int still pending */ - M[tempa >> 2] = 0; /* zero sa & IOCD address in status WD 1 */ - /* save the status to memory */ - M[(tempa+4) >> 2] = (((uint32)dev_status[pend]) << 24); -fprintf(stderr, "scan_chan 4b pend %x chan %x tempa %x\r\n", pend, i, tempa); -sim_debug(DEBUG_EXP, &cpu_dev, "Set atten %03x %02x [%08x] %08x\n", - i, dev_status[pend], M[tempa >> 2], M[(tempa+4) >> 2]); - dev_status[pend] = 0; - pend = chan_icb[i]; /* Interrupt Context Block address in memory */ -fprintf(stderr, "scan_chan 5 icb %x chan %x\r\n", pend, i); - return pend; - } - } - } - pend = 0; - } - /* Only return loading unit on loading */ - if (loading != 0 && loading != pend) - return 0; - if (pend) { - i = find_subchan(pend); /* get channel from device number */ -fprintf(stderr, "scan_chan end pend=%x chan %x\r\n", pend, i); - pend = chan_icb[i]; /* Interrupt Context Block address in memory */ - return pend; - } - return 0; + /* 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 */ + DIB *dibp = (DIB *)dptr->ctxt; /* get pointer to Device Information Block for this device */ + UNIT *uptr = dptr->units; /* get pointer to units defined for this device */ + + if (dibp == NULL) /* If no DIB, not channel device */ + continue; + if (dptr->flags & DEV_DIS) { /* Skip disabled devices */ + continue; + } + if ((chp = (CHANP *)dibp->chan_prg) == NULL)/* must have channel information for each device */ + continue; + /* Check if address is in unit or dev entry */ + for (j = 0; j < dibp->numunits; j++) { /* loop through unit entries */ + chsa = GET_UADDR(uptr->u3); /* ch/sa value */ + + /* If channel end, check if we should continue */ + if (chp->chan_status & STATUS_CEND) { /* do we have channel end */ + if (chp->ccw_flags & FLAG_CC) { /* command chain flag */ + /* we have channel end and CC flag, continue channel prog */ + if (chp->chan_status & STATUS_DEND) { /* device end? */ +// fprintf(stderr, "scan_chan found channel end w/CC @ chsa %x flags %x do load_ccw\r\n", +// chp->chan_dev, chp->ccw_flags); + (void)load_ccw(chp, 1); /* go load the next IOCB */ + } else + irq_pend = 1; /* still pending int */ + } else { + /* we have channel end and no CC flag, end command */ + chsa = chp->chan_dev; /* get the chan/sa */ +// fprintf(stderr, "scan_chan found channel end wo/CC @ chsa %x do load_ccw loading %x\r\n", +// chp->chan_dev, loading); + dev_status[chsa] = 0; /* no device status anymore */ + /* handle case where we are loading the O/S on boot */ + if (loading) { + if (chp->chan_status & 0x3f03) { /* check if any channel errors */ + return 0; /* yes, just return */ + } + irq_pend = 0; /* no pending int */ + chp->chan_status = 0; /* no channel status */ + return chsa; /* if loading, just channel number */ + } + /* we are not loading, but have completed channel program */ + store_csw(chp); /* store the status */ + lev = find_int_lev(chsa); /* get interrupt level */ + if (lev == 0) { + irq_pend = 1; /* still pending int */ + return 0; /* just return */ + } + irq_pend = 1; /* still pending int */ + return 0; /* just return */ + } + } + uptr++; /* next UNIT pointer */ + chp++; /* next CHANP pointer */ + } + } + +#if NOT_SURE_NEEDED + /* process any pending channel */ + for (chsa = 0; chsa < MAX_DEV; chsa++) { /* loop through all the channels/units */ + if (dev_status[chsa] != 0) { /* any pending status */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer */ +// chan = get_chan(chsa); /* get channel from device number */ + if (chp->ccw_cmd == 0) { + CHANP *pchp = find_chanp_ptr(chsa&0x7f00); /* find the chanp pointer for channel */ + fprintf(stderr, "scan_chan Found dev_status %x for chsa %x\r\n", dev_status[chsa], chsa); + if (pchp->chan_inch_addr != 0) { + tempa = pchp->chan_inch_addr; /* get inch status buffer address */ + M[tempa >> 2] = 0; /* zero sa & IOCD address in status WD 1 */ + /* save the status to memory */ + M[(tempa+4) >> 2] = (((uint32)dev_status[chsa]) << 24); + } + irq_pend = 1; /* int still pending */ + dev_status[chsa] = 0; /* no status anymore */ + lev = find_int_lev(chsa); /* get interrupt level */ + if (lev == 0) { + fprintf(stderr, "scan_chan SCAN END ERROR LEV=0 chsa %x place 2\r\n", chsa); + return 0; /* just return */ + } + chan_icba = find_int_icb(chsa); /* get icb address */ + INTS[lev] |= INTS_REQ; /* turn on channel interrupt request */ + return 0; /* just return */ + } + } + } +#endif + return 0; } - /* set up the devices configured into the simulator */ /* only devices with a DIB will be processed */ t_stat chan_set_devs() { - int i, j; + int i, j; -fprintf(stderr, "chan_set_devs entry\r\n"); - for(i = 0; i < MAX_DEV; i++) { - dev_unit[i] = NULL; /* clear Device pointer array */ - } - /* Build channel array */ - for (i = 0; sim_devices[i] != NULL; i++) { - DEVICE *dptr = sim_devices[i]; /* get pointer to next configured device */ - UNIT *uptr = dptr->units; /* get pointer to units defined for this device */ - DIB *dibp = (DIB *)dptr->ctxt; /* get pointer to Device Information Block for this device */ - int addr; /* addr of device addr & subaddress */ - int chan; /* channel address 0-7f */ + for(i = 0; i < MAX_DEV; i++) { + dev_unit[i] = NULL; /* clear Device pointer array */ + } + /* Build channel array */ + for (i = 0; sim_devices[i] != NULL; i++) { + DEVICE *dptr = sim_devices[i]; /* get pointer to next configured device */ + UNIT *uptr = dptr->units; /* get pointer to units defined for this device */ + DIB *dibp = (DIB *)dptr->ctxt; /* get pointer to Device Information Block for this device */ + CHANP *chp; /* channel program pointer */ + int chsa; /* addr of device chan & subaddress */ - if (dibp == NULL) /* If no DIB, not channel device */ - continue; - if (dptr->flags & DEV_DIS) /* Skip disabled devices */ - continue; - /* Check if address is in unit or dev entry */ - for (j = 0; j < dptr->numunits; j++) { /* loop through unit entries */ - addr = GET_UADDR(uptr->u3); /* ch/sa value */ - dev_status[addr] = 0; /* zero device status flags */ - chan = (addr >> 8) & 0x7f; /* get the chan address */ -fprintf(stderr, "chan_set_devs check %s u3 %x addr %0x\r\n", dptr->name, GET_UADDR(uptr->u3), addr); - if ((uptr->flags & UNIT_DIS) == 0) /* is unit marked disabled? */ - dev_unit[addr] = dibp; /* no, save the dib address */ - if (dibp->dev_ini != NULL) /* if there is an init routine, call it now */ - dibp->dev_ini(uptr, 1); /* init the channel */ - /* zero some channel data loc's for device */ - chan_inch_addr[chan] = 0; /* clear address of stat dw in memory */ - chan_icb[chan] = 0; /* Interrupt Context Block address in memory */ - uptr++; /* next UNIT pointer */ - } - } - return SCPE_OK; /* all is OK */ + if (dibp == NULL) /* If no DIB, not channel device */ + continue; + if (dptr->flags & DEV_DIS) { /* Skip disabled devices */ +// fprintf(stderr, "chan_set_devs DISABLED check %s u3 %x\r\n", dptr->name, GET_UADDR(uptr->u3)); + continue; + } + if ((chp = (CHANP *)dibp->chan_prg) == NULL)/* must have channel information for each device */ + continue; + /* Check if address is in unit or dev entry */ + for (j = 0; j < dptr->numunits; j++) { /* loop through unit entries */ + chsa = GET_UADDR(uptr->u3); /* ch/sa value */ + /* zero some channel data loc's for device */ + dev_status[chsa] = 0; /* zero device status flags */ + dev_status[chsa&0x7f00] = 0; /* clear the channel status location */ + dev_status[chsa] = 0; /* device status too */ + chp->chan_status = 0; /* clear the channel status */ + chp->chan_dev = chsa; /* save our address (ch/sa) */ + chp->chan_byte = BUFF_EMPTY; /* no data yet */ + chp->ccw_addr = 0; /* start loading at loc 0 */ + chp->chan_caw = 0; /* set IOCD address to memory location 0 */ + chp->ccw_count = 0; /* channel byte count 0 bytes*/ + chp->ccw_flags = 0; /* Command chain and supress incorrect length */ + chp->ccw_cmd = 0; /* read command */ + chp->chan_inch_addr = 0; /* clear address of stat dw in memory */ + if ((uptr->flags & UNIT_DIS) == 0) /* is unit marked disabled? */ + dev_unit[chsa] = dibp; /* no, save the dib address */ + if (dibp->dev_ini != NULL) /* if there is an init routine, call it now */ + dibp->dev_ini(uptr, 1); /* init the channel */ + uptr++; /* next UNIT pointer */ + chp++; /* next CHANP pointer */ + } + } + return SCPE_OK; /* all is OK */ } /* Validate and set the device onto a given channel */ @@ -930,25 +1535,23 @@ t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc) DIB *dibp; t_value newdev; t_stat r; - int num; - int type; int i; int devaddr; -fprintf(stderr, "set_dev_addr val %x cprt %s desc %s\r\n", val, cptr, desc); - if (cptr == NULL) /* is there a UNIT name specified */ - return SCPE_ARG; /* no, arg error */ - if (uptr == NULL) /* is there a UNIT pointer */ - return SCPE_IERR; /* no, arg error */ - dptr = find_dev_from_unit(uptr); /* find the device from unit pointer */ - if (dptr == NULL) /* device not found, so error */ - return SCPE_IERR; /* error */ +fprintf(stderr, "set_dev_addr val %x cptr %s desc %s\r\n", val, cptr, (char *)desc); + if (cptr == NULL) /* is there a UNIT name specified */ + return SCPE_ARG; /* no, arg error */ + if (uptr == NULL) /* is there a UNIT pointer */ + return SCPE_IERR; /* no, arg error */ + dptr = find_dev_from_unit(uptr); /* find the device from unit pointer */ + if (dptr == NULL) /* device not found, so error */ + return SCPE_IERR; /* error */ dibp = (DIB *)dptr->ctxt; if (dibp == NULL) return SCPE_IERR; - newdev = get_uint (cptr, 16, 0xfff, &r); + newdev = get_uint(cptr, 16, 0xfff, &r); if (r != SCPE_OK) return r; @@ -1004,21 +1607,19 @@ fprintf(stderr, "set_dev_addr val %x cprt %s desc %s\r\n", val, cptr, desc); return r; } -t_stat -show_dev_addr(FILE *st, UNIT *uptr, int32 v, CONST void *desc) +t_stat show_dev_addr(FILE *st, UNIT *uptr, int32 v, CONST void *desc) { - DEVICE *dptr; - DIB *dibp; - int addr; + DEVICE *dptr; + int chsa; -fprintf(stderr, "show_dev_addr val %x desc %s\r\n", v, desc); - if (uptr == NULL) - return SCPE_IERR; - dptr = find_dev_from_unit(uptr); - if (dptr == NULL) - return SCPE_IERR; - addr = GET_UADDR(uptr->u3); - fprintf(st, "%03x", addr); - return SCPE_OK; +// fprintf(stderr, "show_dev_addr val %x desc %s\r\n", v, (char *)desc); + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + chsa = GET_UADDR(uptr->u3); + fprintf(st, "%04x", chsa); + return SCPE_OK; } diff --git a/SEL32/sel32_clk.c b/SEL32/sel32_clk.c new file mode 100644 index 0000000..a9c850b --- /dev/null +++ b/SEL32/sel32_clk.c @@ -0,0 +1,367 @@ +/* sel32_clk.c: SEL 32 Class F IOP processor RTOM functions. + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This module support the real-time clock and the interval timer. + These are CD/TD class 3 devices. The RTC can be programmed to + 50/100 HZ or 60/120 HZ rates and creates an interrupt at the + requested rate. The interval timer is a 32 bit register that is + loaded with a value to be down counted. An interrupt is generated + when the count reaches zero, The clock continues down counting + until read/reset by the programmer. The rate can be external or + 38.4 microseconds per count. + +*/ + +#include "sel32_defs.h" +#include "sim_defs.h" + +#ifdef NUM_DEVS_RTOM + +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chan, uint8 *data); +extern int chan_write_byte(uint16 chan, uint8 *data); +extern void set_devattn(uint16 addr, uint8 flags); +extern void post_extirq(void); + +void rtc_setup (uint32 ss, uint32 level); +t_stat rtc_srv (UNIT *uptr); +t_stat rtc_reset (DEVICE *dptr); +t_stat rtc_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc); + +extern int irq_pend; /* go scan for pending int or I/O */ +extern uint32 INTS[]; /* interrupt control flags */ +extern uint32 SPAD[]; /* computer SPAD */ +extern uint32 M[]; /* system memory */ + +int32 rtc_pie = 0; /* rtc pulse ie */ +int32 rtc_tps = 60; /* rtc ticks/sec */ +int32 rtc_lvl = 0x18; /* rtc interrupt level */ + +/* Clock data structures + + rtc_dev RTC device descriptor + rtc_unit RTC unit + rtc_reg RTC register list +*/ + +/* clock is attached all the time */ +/* defailt to 60 HZ RTC */ +UNIT rtc_unit = { UDATA (&rtc_srv, UNIT_ATT, 0), 16666, UNIT_ADDR(0x7F06)}; + +REG rtc_reg[] = { + { FLDATA (PIE, rtc_pie, 0) }, + { DRDATA (TIME, rtc_unit.wait, 32), REG_NZ + PV_LEFT }, + { DRDATA (TPS, rtc_tps, 8), PV_LEFT + REG_HRO }, + { NULL } + }; + +MTAB rtc_mod[] = { + { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ", + &rtc_set_freq, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ", + &rtc_set_freq, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 100, NULL, "100HZ", + &rtc_set_freq, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 120, NULL, "120HZ", + &rtc_set_freq, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL, + NULL, &rtc_show_freq, NULL }, + { 0 } + }; + +DEVICE rtc_dev = { + "RTC", &rtc_unit, rtc_reg, rtc_mod, + 1, 8, 8, 1, 8, 8, + NULL, NULL, &rtc_reset, + NULL, NULL, NULL + }; + +/* The real time clock runs continuously; therefore, it only has + a unit service routine and a reset routine. The service routine + sets an interrupt that invokes the clock counter. +*/ + +/* service clock signal from simulator */ +t_stat rtc_srv (UNIT *uptr) +{ + if (rtc_pie) { /* set pulse intr */ + INTS[rtc_lvl] |= INTS_REQ; /* request the interrupt */ + irq_pend = 1; /* make sure we scan for int */ + } +// rtc_unit.wait = sim_rtcn_calb (rtc_tps, TMR_RTC); /* calibrate */ +// sim_activate (&rtc_unit, rtc_unit.wait); /* reactivate */ + sim_activate (&rtc_unit, 16667); /* reactivate */ + return SCPE_OK; +} + +/* Clock interrupt start/stop */ +/* ss = 1 - starting clock */ +/* ss = 0 - stopping clock */ +/* level = interrupt level */ +void rtc_setup(uint ss, uint32 level) +{ + uint32 val = SPAD[level+0x80]; /* get SPAD value for interrupt vector */ + rtc_lvl = level; /* save the interrupt level */ + uint32 addr = SPAD[0xf1] + (level<<2); /* vector address in SPAD */ + addr = M[addr>>2]; /* get the interrupt context block addr */ +//fprintf(stderr, "rtc_setup called ss %x level %x SPAD %x icba %x\r\n", ss, level, val, addr); + if (ss == 1) { /* starting? */ + INTS[level] |= INTS_ENAB; /* make sure enabled */ + SPAD[level+0x80] |= SINT_ENAB; /* in spad too */ + INTS[level] |= INTS_REQ; /* request the interrupt */ + sim_activate(&rtc_unit, 20); /* start us off */ + } else { + INTS[level] &= ~INTS_ENAB; /* make sure disabled */ + SPAD[level+0x80] &= ~SINT_ENAB; /* in spad too */ + } + rtc_pie = ss; /* set new state */ +} + +/* Clock reset */ +t_stat rtc_reset(DEVICE *dptr) +{ + rtc_pie = 0; /* disable pulse */ + rtc_unit.wait = sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* initialize clock calibration */ + sim_activate (&rtc_unit, rtc_unit.wait); /* activate unit */ + return SCPE_OK; +} + +/* Set frequency */ +t_stat rtc_set_freq(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + if (cptr) /* if chars, bad */ + return SCPE_ARG; /* ARG error */ + if ((val != 50) && (val != 60) && (val != 100) && (val != 120)) + return SCPE_IERR; /* scope error */ + rtc_tps = val; /* set the new frequency */ + return SCPE_OK; /* we done */ +} + +/* Show frequency */ +t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + /* print the cirrent frequency setting */ + if (rtc_tps < 100) + fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz"); + else + fprintf (st, (rtc_tps == 100)? "100Hz": "120Hz"); + return SCPE_OK; +} + +/************************************************************************/ + +/* Interval Timer support */ +int32 itm_pie = 0; /* itm pulse enable */ +//int32 itm_tps = 38; /* itm 26041 ticks/sec = 38.4 us per tic */ +///int32 itm_tps = 48; /* itm 26041 ticks/sec = 38.4 us per tic */ +int32 itm_tps = 64; /* itm 26041 ticks/sec = 38.4 us per tic */ +int32 itm_lvl = 0x5f; /* itm interrupt level */ +int32 itm_cnt = 26041; /* value that we are downcounting */ +int32 itm_run = 0; /* set when timer running */ +t_stat itm_srv (UNIT *uptr); +t_stat itm_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat itm_reset (DEVICE *dptr); +t_stat itm_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc); + +#define TMR_ITM 2 + +/* Clock data structures + + itm_dev Interval Timer ITM device descriptor + itm_unit Interval Timer ITM unit + itm_reg Interval Timer ITM register list +*/ + +/* clock is attached all the time */ +/* defailt to 60 HZ RTC */ +//UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 38, UNIT_ADDR(0x7F04)}; +//UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 48, UNIT_ADDR(0x7F04)}; +//UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 26042, UNIT_ADDR(0x7F04)}; +UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 26042, UNIT_ADDR(0x7F04)}; + +REG itm_reg[] = { + { FLDATA (PIE, itm_pie, 0) }, + { DRDATA (TIME, itm_unit.wait, 32), REG_NZ + PV_LEFT }, + { DRDATA (TPS, itm_tps, 32), PV_LEFT + REG_HRO }, + { NULL } + }; + +MTAB itm_mod[] = { + { MTAB_XTD|MTAB_VDV, 384, NULL, "38.4us", + &itm_set_freq, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 768, NULL, "76.86us", + &itm_set_freq, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL, + NULL, &itm_show_freq, NULL }, + { 0 } + }; + +DEVICE itm_dev = { + "ITM", &itm_unit, itm_reg, itm_mod, + 1, 8, 8, 1, 8, 8, + NULL, NULL, &itm_reset, + NULL, NULL, NULL + }; + +/* The interval timer downcounts the value it is loaded with and + runs continuously; therefore, it has a read/write routine, + a unit service routine and a reset routine. The service routine + sets an interrupt that invokes the clock counter. +*/ + +/* service clock signal from simulator */ +/* for 38.4 us/tic we get 26041 ticks per second */ +/* downcount the loaded value until zero and then cause interrupt */ +t_stat itm_srv (UNIT *uptr) +{ +// uint32 val = SPAD[itm_lvl+0x80]; /* get SPAD value for interrupt vector */ +// uint32 addr = SPAD[0xf1] + (itm_lvl<<2); /* vector address in SPAD */ +// addr = M[addr>>2]; /* get the interrupt context block addr */ +//fprintf(stderr, "itm_srv level %x itm_pie %x wait %x spad %x icba %x\r\n", +// itm_lvl, itm_pie, itm_unit.wait, val, addr); + + /* count down about 48 instructions per tick ~38.4 us */ + /* we will be called once for each instructon */ + itm_unit.wait -= 1; /* subtract 1 from wait count */ + if (itm_unit.wait > 0) + return SCPE_OK; /* not time yet */ + itm_unit.wait = itm_tps; /* reset wait count */ + + if (itm_run) { /* see if timer running */ + itm_cnt--; /* down count by one */ + if ((itm_cnt == 0) && itm_pie) { /* see if reached 0 yet */ +// if (itm_cnt == 0) { /* see if reached 0 yet */ +//fprintf(stderr, "itm_srv REQ itm_pie %x wait %x itm_cnt %x\r\n", itm_pie, itm_unit.wait, itm_cnt); + INTS[itm_lvl] |= INTS_REQ; /* request the interrupt on zero value */ + irq_pend = 1; /* make sure we scan for int */ + } + } +#if 0 + itm_unit.wait = sim_rtcn_calb (itm_tps, TMR_ITM); /* calibrate */ + sim_activate (&itm_unit, itm_unit.wait); /* reactivate */ +#endif + return SCPE_OK; +} + +/* ITM read/load function called from CD command processing */ +/* level = interrupt level */ +/* cmd = 0x39 load and enable interval timer, no return value */ +/* = 0x40 read timer value */ +/* = 0x60 read timer value and stop timer */ +/* = 0x79 read/reload and start timer */ +/* cnt = value to write to timer */ +/* ret = return value read from timer */ +int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level) +{ + uint32 temp; +// uint32 val = SPAD[level+0x80]; /* get SPAD value for interrupt vector */ + +// itm_lvl = level; /* save the interrupt level */ +// uint32 addr = SPAD[0xf1] + (level<<2); /* vector address in SPAD */ +// addr = M[addr>>2]; /* get the interrupt context block addr */ +//fprintf(stderr, "itm_rdwr called ss %x level %x SPAD %x icba %x\r\n", ss, level, val, addr); +//fprintf(stderr, "itm_rdwr called cmd %x count %x (%d) level %x return cnt %x (%d)\r\n", +// cmd, cnt, cnt, level, itm_cnt, itm_cnt); + switch (cmd) { + case 0x39: /* load timer with new value and start*/ + if (cnt < 0) + cnt = 26042; /* TRY ??*/ + itm_cnt = cnt; /* load timer with value from user to down count */ + itm_run = 1; /* start timer */ + return 0; /* does not matter, no value returned */ + case 0x60: /* read and stop timer */ + temp = itm_cnt; /* get timer value and stop timer */ + itm_run = 0; /* stop timer */ +// itm_cnt = 0; /* reset with timer value from user to down count */ + return temp; /* return current count value */ + case 0x79: /* read the current timer value */ + temp = itm_cnt; /* get timer value, load new value and start timer */ + itm_cnt = cnt; /* load timer with value from user to down count */ + itm_run = 1; /* start timer */ + return temp; /* return current count value */ + case 0x40: /* read the current timer value */ + return itm_cnt; /* return current count value */ + break; + } + return 0; /* does not matter, no value returned */ +} + +/* Clock interrupt start/stop */ +/* ss = 1 - clock interrupt enabled */ +/* ss = 0 - clock interrupt disabled */ +/* level = interrupt level */ +void itm_setup(uint ss, uint32 level) +{ + itm_lvl = level; /* save the interrupt level */ +// fprintf(stderr, "itm_setup called ss %x level %x\r\n", ss, level); + if (ss == 1) { /* starting? */ + INTS[level] |= INTS_ENAB; /* make sure enabled */ + SPAD[level+0x80] |= SINT_ENAB; /* in spad too */ + INTS[level] |= INTS_REQ; /* request the interrupt */ + itm_cnt = 26042; /* start with 1 sec */ + itm_run = 0; /* not running yet */ +/// sim_activate(&itm_unit, 48); /* start us off */ + } else { + INTS[level] &= ~INTS_ENAB; /* make sure disabled */ + SPAD[level+0x80] &= ~SINT_ENAB; /* in spad too */ + } + itm_pie = ss; /* set new state */ +} + +/* Clock reset */ +t_stat itm_reset (DEVICE *dptr) +{ +// int intlev = 0x5f; /* interrupt level for itm */ +//fprintf(stderr, "itm_reset called\r\n"); + itm_pie = 0; /* disable pulse */ + itm_cnt = 26042; /* start with 1 sec */ + itm_run = 0; /* not running yet */ +#if 0 + rtc_unit.wait = sim_rtcn_init (itm_unit.wait, TMR_ITM); /* initialize clock calibration */ + sim_activate (&itm_unit, itm_unit.wait); /* activate unit */ +#endif + return SCPE_OK; +} + +/* Set frequency */ +t_stat itm_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + if (cptr) /* if chars, bad */ + return SCPE_ARG; /* ARG error */ + if ((val != 384) && (val != 768)) + return SCPE_IERR; /* scope error */ + itm_tps = val/10; /* set the new frequency */ + return SCPE_OK; /* we done */ +} + +/* Show frequency */ +t_stat itm_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + /* print the cirrent frequency setting */ + fprintf (st, (itm_tps == 38)? "38.4us": "76.8us"); + return SCPE_OK; +} +#endif + diff --git a/SEL32/sel32_com.c b/SEL32/sel32_com.c new file mode 100644 index 0000000..4952223 --- /dev/null +++ b/SEL32/sel32_com.c @@ -0,0 +1,899 @@ +/* sel32_com.c: SEL 32 8-Line IOP communications controller + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include "sel32_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#ifdef NUM_DEVS_COM + +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chan, uint8 *data); +extern int chan_write_byte(uint16 chan, uint8 *data); +extern void set_devwake(uint16 addr, uint8 flags); +extern int traceme, trstart; + +/* Constants */ +#define COM_LINES 8 /* max lines */ +//#define COM_LINES 16 /* max lines */ +#define COM_LINES_DFLT 8 /* default lines */ +#define COM_INIT_POLL 8000 +#define COML_WAIT 500 +#define COM_WAIT 500 +#define COM_NUMLIN com_desc.lines /* curr # lines */ + +#define COMC 0 /* channel thread */ +#define COMI 1 /* input thread */ + +/* Line status */ +#define COML_XIA 0x01 /* xmt intr armed */ +#define COML_XIR 0x02 /* xmt intr req */ +#define COML_REP 0x04 /* rcv enable pend */ +#define COML_RBP 0x10 /* rcv break pend */ + +/* Channel state */ +#define COMC_IDLE 0 /* idle */ +#define COMC_INIT 1 /* init */ +#define COMC_RCV 2 /* receive */ +#define COMC_END 3 /* end */ + +uint8 com_rbuf[COM_LINES]; /* rcv buf */ +uint8 com_xbuf[COM_LINES]; /* xmt buf */ +uint8 com_sta[COM_LINES]; /* status */ +uint32 com_lstat[COM_LINES][2] = { 0 }; /* 8 bytes of line settings status */ +uint32 com_tps = 2; /* polls/second */ +uint32 com_scan = 0; /* scanner */ +uint32 com_slck = 0; /* scanner locked */ +uint32 comc_cmd = COMC_IDLE; /* channel state */ + +TMLN com_ldsc[COM_LINES] = { 0 }; /* line descrs */ +TMXR com_desc = { COM_LINES_DFLT, 0, 0, com_ldsc }; /* com descr */ + +/* Held in u3 is the device command and status */ +#define COM_INCH 0x00 /* Initialize channel command */ +#define COM_WR 0x01 /* Write terminal */ +#define COM_RD 0x02 /* Read terminal */ +#define COM_NOP 0x03 /* No op command */ +#define COM_SNS 0x04 /* Sense command */ +#define COM_WRSCM 0x05 /* Write w/Sub chan monitor */ +#define COM_RDECHO 0x06 /* Read with Echo */ +#define COM_RDFC 0x0A /* Read w/flow control */ +#define COM_DEFSC 0x0B /* Define special char */ +#define COM_WRHFC 0x0D /* Write hardware flow control */ +#define COM_RDTR 0x13 /* Reset DTR (ADVR) */ +#define COM_SDTR 0x17 /* Set DTR (ADVF) */ +#define COM_RRTS 0x1B /* Reset RTS */ +#define COM_SRTS 0x1F /* Set RTS */ +#define COM_RBRK 0x33 /* Reset BREAK */ +#define COM_SBRK 0x37 /* Set BREAK */ +#define COM_RDHFC 0x8E /* Read w/hardware flow control only */ +#define COM_SACE 0xFF /* Set ACE parameters */ + +#define COM_MSK 0xFF /* Command mask */ + +/* Status held in u3 */ +/* controller/unit address in upper 16 bits */ +#define COM_INPUT 0x100 /* Input ready for unit */ +#define COM_CR 0x200 /* Output at beginning of line */ +#define COM_REQ 0x400 /* Request key pressed */ +#define COM_EKO 0x800 /* Echo input character */ +#define COM_OUTPUT 0x1000 /* Output ready for unit */ +#define COM_READ 0x2000 /* Read mode selected */ + +/* ACE data kept in u4 */ + +/* in u5 packs sense byte 0, 1, 2 and 3 */ +/* Sense byte 0 */ +#define SNS_CMDREJ 0x80000000 /* Command reject */ +#define SNS_INTVENT 0x40000000 /* Unit intervention required (N/U) */ +#define SNS_BOCHK 0x20000000 /* Bus out check (IOP parity error */ +#define SNS_EQUIPCK 0x10000000 /* Equipment check (device error) */ +#define SNS_DATACK 0x08000000 /* Data check */ +#define SNS_OVERRN 0x04000000 /* Overrun (N/U) */ +#define SNS_NUB01 0x02000000 /* Zero (N/U) */ +#define SNS_NUB02 0x01000000 /* Zero (N/U) */ +/* Sense byte 1 */ +#define SNS_ASCIICD 0x00800000 /* ASCII control char detected interrupt */ +#define SNS_SPCLCD 0x00400000 /* Special char detected interrupt */ +#define SNS_ETX 0x00200000 /* ETX interrupt */ +#define SNS_BREAK 0x00100000 /* BREAK interrupt */ +#define SNS_ACEFE 0x00080000 /* ACE framing error interrupt */ +#define SNS_ACEPEI 0x00040000 /* ACE parity error interrupt */ +#define SNS_ACEOVR 0x00020000 /* ACE overrun error interrupt */ +#define SNS_RING 0x00010000 /* Ring character interrupt */ +/* Sense byte 2 Modem status */ +#define SNS_RLSDS 0x00008000 /* Received line signal detect status */ +#define SNS_RINGST 0x00004000 /* Ring indicator line status */ +#define SNS_DSRS 0x00002000 /* DSR Data set ready line status */ +#define SNS_CTSS 0x00001000 /* CTS Clear to send line status */ +#define SNS_DELTA 0x00000800 /* Delta receive line signal detect failure interrupt */ +#define SNS_MRING 0x00000400 /* RI Modem ring interrupt */ +#define SNS_DELDSR 0x00000200 /* Delta data set ready interrupt */ +#define SNS_DELCLR 0x00000100 /* Ring character interrupt */ +/* Sense byte 3 Modem Control/Operation status */ +#define SNS_HALFD 0x00000080 /* Half-duplix operation set */ +#define SNS_MRINGE 0x00000040 /* Modem ring enabled (1) */ +#define SNS_ACEDEF 0x00000020 /* ACE parameters defined */ +#define SNS_DIAGM 0x00000010 /* Diagnostic mode set */ +#define SNS_AUXOL2 0x00000008 /* Auxiliary output level 2 */ +#define SNS_AUXOL1 0x00000004 /* Auxiliary output level 1 */ +#define SNS_RTS 0x00000002 /* RTS Request to send set */ +#define SNS_DTR 0x00000001 /* DTR Data terminal ready set */ +/* Sense byte 4 ACE Parameters status */ +#define SNS_ACEDLE 0x80000000 /* Divisor latch enable 0=dis, 1=enb */ +#define SNS_ACEBS 0x40000000 /* Break set 0=reset, 1=set */ +#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */ +#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */ +#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */ +#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */ +#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 11=7, 11=8 */ +#define SNS_ACECL2 0x01000000 /* 2nd bit for above */ +/* Sense byte 5 Baud rate */ +#define SNS_NUB50 0x00800000 /* Zero N/U */ +#define SNS_NUB51 0x00400000 /* Zero N/U */ +#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */ +#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */ +#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */ +#define BAUD50 0x00000000 /* 50 baud */ +#define BAUD75 0x00010000 /* 75 baud */ +#define BAUD110 0x00020000 /* 110 baud */ +#define BAUD114 0x00030000 /* 134 baud */ +#define BAUD150 0x00040000 /* 150 baud */ +#define BAUD300 0x00050000 /* 300 baud */ +#define BAUD600 0x00060000 /* 600 baud */ +#define BAUD1200 0x00070000 /* 1200 baud */ +#define BAUD1800 0x00080000 /* 1800 baud */ +#define BAUD2000 0x00090000 /* 2000 baud */ +#define BAUD2400 0x000A0000 /* 2400 baud */ +#define BAUD3600 0x000B0000 /* 3600 baud */ +#define BAUD4800 0x000C0000 /* 4800 baud */ +#define BAUD7200 0x000D0000 /* 7200 baud */ +#define BAUD9600 0x000E0000 /* 9600 baud */ +#define BAUD19200 0x000F0000 /* 19200 baud */ +/* Sense byte 6 Firmware ID, Revision Level */ +#define SNS_FID 0x00006200 /* ID part 1 */ +/* Sense byte 7 Firmware ID, Revision Level */ +#define SNS_REV 0x0000004f /* ID part 2 plus 4 bit rev # */ + +/* ACE information in u4 */ +#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character */ + +/* in u5 packs sense byte 0,1 and 3 */ +/* Sense byte 0 */ +#define SNS_CMDREJ 0x80000000 /* Command reject */ +#define SNS_INTVENT 0x40000000 /* Unit intervention required */ +/* sense byte 3 */ +#define SNS_RDY 0x80 /* device ready */ +#define SNS_ONLN 0x40 /* device online */ +#define SNS_DSR 0x04 /* data set ready */ + +/* u6 */ + +uint8 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd); +uint8 com_haltio(uint16 addr); +void com_ini(UNIT *, t_bool); +void coml_ini(UNIT *, t_bool); +t_stat com_reset(DEVICE *); +t_stat com_attach(UNIT *, CONST char *); +t_stat com_detach(UNIT *); +t_stat comc_srv(UNIT *uptr); +t_stat como_srv(UNIT *uptr); +t_stat comi_srv(UNIT *uptr); +t_stat com_reset(DEVICE *dptr); +t_stat com_attach(UNIT *uptr, CONST char *cptr); +t_stat com_detach(UNIT *uptr); +void com_reset_ln(int32 ln); +const char *com_description(DEVICE *dptr); /* device description */ + +/* COM data structures + com_chp COM channel program information + com_dev COM device descriptor + com_unit COM unit descriptor + com_reg COM register list + com_mod COM modifieers list +*/ + +//#define COM_UNITS 2 +#define COM_UNITS 1 + +/* channel program information */ +CHANP com_chp[COM_UNITS] = {0}; + +/* dummy mux for 16 lines */ +MTAB com_mod[] = { + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL}, + {MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &com_desc}, + {UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tmxr_show_summ, (void *) &com_desc}, + {MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat,(void *)&com_desc}, + {MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, (void *)&com_desc}, +// {MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", &io_set_dvc, &io_show_dvc, NULL}, +// {MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", &io_set_dva, &io_show_dva, NULL}, +// {MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", &com_vlines, &tmxr_show_lines, (void *)&com_desc}, +// {MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, NULL, &io_show_cst, NULL}, +// {MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "POLL", "POLL", &rtc_set_tps, &rtc_show_tps,(void *)&com_tps}, +/// { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, +/// { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, +/// { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, +/// { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, +/// { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &com_desc }, +/// { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &com_desc }, +/// { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &com_desc }, + { 0 } +}; + +UNIT com_unit[] = { + {UDATA(&comi_srv, UNIT_ATTABLE, 0), COM_WAIT, UNIT_ADDR(0x0000)}, /* 0 */ +}; + +//DIB com_dib = {NULL, com_startcmd, NULL, NULL, com_ini, com_unit, com_chp, COM_UNITS, 0x0f, 0x7e00, 0, 0, 0}; + +DIB com_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + com_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + com_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + com_unit, /* UNIT* units */ /* Pointer to units structure */ + com_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + COM_UNITS, /* uint8 numunits */ /* number of units defined */ + 0x0f, /* uint8 mask */ /* 16 devices - device mask */ + 0x7E00, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +REG com_reg[] = { + { BRDATAD (STA, com_sta, 16, 8, COM_LINES, "status buffers, lines 0 to 8") }, + { BRDATAD (RBUF, com_rbuf, 16, 8, COM_LINES, "input buffer, lines 0 to 8") }, + { BRDATAD (XBUF, com_xbuf, 16, 8, COM_LINES, "output buffer, lines 0 to 8") }, + { ORDATAD (SCAN, com_scan, 6, "scanner line number") }, + { FLDATAD (SLCK, com_slck, 0, "scanner lock") }, + { DRDATA (TPS, com_tps, 8), REG_HRO}, + { NULL } + }; + +/* devices for channel 0x7ecx */ +DEVICE com_dev = { + "COMC", com_unit, com_reg, com_mod, + COM_UNITS, 8, 15, 1, 8, 8, + &tmxr_ex, &tmxr_dep, &com_reset, NULL, &com_attach, &com_detach, + &com_dib, DEV_NET | DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, NULL, NULL, NULL, &com_description +}; + +/* COML data structures + coml_dev COM device descriptor + coml_unit COM unit descriptor + coml_reg COM register list + coml_mod COM modifieers list +*/ + +#define UNIT_COML UNIT_ATTABLE|UNIT_DISABLE|UNIT_ATT +//#define UNIT_COML UNIT_ATTABLE|UNIT_DISABLE + +/* channel program information */ +CHANP coml_chp[COM_LINES*2] = {0}; + +UNIT coml_unit[] = { + /* 0-7 is input, 8-f is output */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC0)}, /* 0 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC1)}, /* 1 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC2)}, /* 2 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC3)}, /* 3 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC4)}, /* 4 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC5)}, /* 5 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC6)}, /* 6 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC7)}, /* 7 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC8)}, /* 8 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC9)}, /* 9 */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECA)}, /* A */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECB)}, /* B */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECC)}, /* C */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECD)}, /* D */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECE)}, /* E */ + {UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECF)}, /* F */ +}; + +//DIB coml_dib = { NULL, com_startcmd, NULL, NULL, NULL, coml_ini, coml_unit, coml_chp, COM_LINES*2, 0x0f, 0x7E00}; +DIB coml_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + com_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + coml_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + coml_unit, /* UNIT* units */ /* Pointer to units structure */ + coml_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + COM_LINES*2, /* uint8 numunits */ /* number of units defined */ + 0x0f, /* uint8 mask */ /* 16 devices - device mask */ + 0x7E00, /* uint16 chan_addr */ /* parent channel address */ +}; + +REG coml_reg[] = { + { URDATA (TIME, coml_unit[0].wait, 10, 24, 0, COM_LINES, REG_NZ + PV_LEFT) }, + { NULL } +}; + +MTAB coml_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &com_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &com_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &com_desc }, + { 0 } + }; + +DEVICE coml_dev = { + "COML", coml_unit, coml_reg, coml_mod, + COM_LINES*2, 10, 31, 1, 8, 8, + NULL, NULL, &com_reset, + NULL, NULL, NULL, + &coml_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, NULL, NULL, NULL, &com_description +}; + +/* 8-line serial routines */ +void coml_ini(UNIT *uptr, t_bool f) +{ + int unit; + uint16 chsa; + + unit = uptr - coml_unit; /* unit # */ + chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */ + + /* maybe do someting here on master channel init */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ +} + +/* 8-line serial routines */ +void com_ini(UNIT *uptr, t_bool f) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + + sim_debug(DEBUG_CMD, &com_dev, "COM init device %s controller 0x7e00\n", dptr->name); + sim_activate(uptr, 1000); /* time increment */ +} + +/* called from sel32_chan to start an I/O operation */ +uint8 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + uint8 ch; + + if ((uptr->u3 & COM_MSK) != 0) { /* is unit busy */ + return SNS_BSY; /* yes, return busy */ + } + + sim_debug(DEBUG_CMD, dptr, "CMD unit %x chan %x cmd %x", unit, chan, cmd); + + /* process the commands */ + switch (cmd & 0xFF) { + case COM_INCH: /* 00 */ /* INCH command */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: CMD INCH\n", chan); + return SNS_CHNEND|SNS_DEVEND; /* all is well */ + break; + + /* write commands must use address 8-f */ + case COM_WR: /* 0x01 */ /* Write command */ + case COM_WRSCM: /* 0x05 */ /* Write w/sub channel monitor */ + case COM_WRHFC: /* 0x0D */ /* Write w/hardware flow control */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd WRITE %x\n", chan, cmd); + + uptr->u3 &= LMASK; /* leave only chsa */ + uptr->u3 |= (cmd & COM_MSK); /* save command */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + sim_activate(uptr, 150); /* TRY 08-13-18 */ + return 0; /* no status change */ + break; + + /* read commands must use address 0-7 */ + /* DSR must be set when a read command is issued, else it is unit check */ + /* bit 1-3 (ASP) of command has more definition */ + /* bit 1 A=1 ASCII control character detect (7-char mode only) */ + /* bit 2 S=1 Special character detect (7-char mode only) */ + /* bit 3 P=1 Purge input buffer */ + case COM_RD: /* 0x02 */ /* Read command */ + case COM_RDECHO: /* 0x06 */ /* Read command w/ECHO */ + case 0x46: /* 0x46 */ /* Read command w/ECHO & ASCII */ + case 0x56: /* 0x56 */ /* Read command w/ECHO & ASCII & Purge input */ + /* if bit 0 set for COM_RDFC, use DTR for flow, else use RTS for flow control */ + case COM_RDFC: /* 0x0A */ /* Read command w/flow control */ + case COM_RDHFC: /* 0x8E */ /* Read command w/hardware flow control only */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd read\n", chan); + uptr->u3 &= LMASK; /* leave only chsa */ + uptr->u3 |= (cmd & COM_MSK); /* save command */ + if ((cmd & 0x06) == COM_RDECHO) /* echo command? */ + uptr->u3 |= COM_EKO; /* save echo status */ + uptr->u3 |= COM_READ; /* show read mode */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + return 0; + break; + + case COM_NOP: /* 0x03 */ /* NOP has do nothing */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x NOP\n", chan, cmd); + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_SNS: /* 0x04 */ /* Sense (8 bytes) */ + com_lstat[unit][0] = 0; /* Clear status wd 0 */ + com_lstat[unit][1] = 0; /* Clear status wd 1 */ + /* value 4 is Data Set Ready */ + /* value 5 is Data carrier detected n/u */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: unit %x Cmd Sense %02x\n", chan, unit, uptr->u5); +/* Sense byte 0 */ +//#define SNS_CMDREJ 0x80000000 /* Command reject */ +//#define SNS_INTVENT 0x40000000 /* Unit intervention required (N/U) */ +//#define SNS_BOCHK 0x20000000 /* Bus out check (IOP parity error */ +//#define SNS_EQUIPCK 0x10000000 /* Equipment check (device error) */ +//#define SNS_DATACK 0x08000000 /* Data check */ +//#define SNS_OVERRN 0x04000000 /* Overrun (N/U) */ +//#define SNS_NUB01 0x02000000 /* Zero (N/U) */ +//#define SNS_NUB02 0x01000000 /* Zero (N/U) */ +// com_lstat[unit][0] |= (SNS_ASCIICD | SNS_SPCLCD|SNS_RING); /* set char detect status */ +// com_lstat[unit][0] |= (SNS_ASCIICD | SNS_SPCLCD); /* set char detect status */ +// com_lstat[unit][0] |= (SNS_RING); /* set char detect status */ + ch = (com_lstat[unit][0] >> 24) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ +/* Sense byte 1 */ +//#define SNS_ASCIICD 0x00800000 /* ASCII control char detected interrupt */ +//#define SNS_SPCLCD 0x00400000 /* Special char detected interrupt */ +//#define SNS_ETX 0x00200000 /* ETX interrupt */ +//#define SNS_BREAK 0x00100000 /* X BREAK interrupt */ +//#define SNS_ACEFE 0x00080000 /* ACE framing error interrupt */ +//#define SNS_ACEPEI 0x00040000 /* ACE parity error interrupt */ +//#define SNS_ACEOVR 0x00020000 /* ACE overrun error interrupt */ +//#define SNS_RING 0x00010000 /* X Ring character interrupt */ + com_lstat[unit][0] |= (SNS_RING); /* set char detect status */ + com_lstat[unit][0] |= (SNS_ASCIICD); /* set char detect status */ + ch = (com_lstat[unit][0] >> 16) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ +/* Sense byte 2 Modem status */ +//#define SNS_RLSDS 0x00008000 /* S Received line signal detect status */ +//#define SNS_RINGST 0x00004000 /* Ring indicator line status */ +//#define SNS_DSRS 0x00002000 /* C DSR Data set ready line status */ +//#define SNS_CTSS 0x00001000 /* C CTS Clear to send line status */ +//#define SNS_DELTA 0x00000800 /* BS Delta receive line signal detect failure interrupt */ +//#define SNS_MRING 0x00000400 /* X RI Modem ring interrupt */ +//#define SNS_DELDSR 0x00000200 /* BS Delta data set ready interrupt */ +//#define SNS_DELCLR 0x00000100 /* B Delta data set CTS failure interrupt */ + com_lstat[unit][0] |= (SNS_CTSS|SNS_DSRS); /* set CTS & DSR status */ + com_lstat[unit][0] |= (SNS_MRING); /* set char detect status */ + ch = (com_lstat[unit][0] >> 8) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ +/* Sense byte 3 Modem Control/Operation status */ +//#define SNS_HALFD 0x00000080 /* Half-duplix operation set */ +//#define SNS_MRINGE 0x00000040 /* Modem ring enabled (1) */ +//#define SNS_ACEDEF 0x00000020 /* ACE parameters defined */ +//#define SNS_DIAGM 0x00000010 /* Diagnostic mode set */ +//#define SNS_AUXOL2 0x00000008 /* Auxiliary output level 2 */ +//#define SNS_AUXOL1 0x00000004 /* Auxiliary output level 1 */ +//#define SNS_RTS 0x00000002 /* RTS Request to send set */ +//#define SNS_DTR 0x00000001 /* DTR Data terminal ready set */ +// com_lstat[unit][0] |= (SNS_RTS|SNS_DTR); /* set RTS & DTR status */ + com_lstat[unit][0] |= (SNS_DTR); /* set DTR status */ + ch = (com_lstat[unit][0] >> 0) & 0xff; + + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ + ch = (com_lstat[unit][1] >> 24) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ + ch = (com_lstat[unit][1] >> 16) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ + ch = (com_lstat[unit][1] >> 8) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ + ch = (com_lstat[unit][1] >> 0) & 0xff; + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ + sim_debug(DEBUG_CMD, &com_dev, + "com_startcmd Cmd SENSE return chan %x u5-status %x ls0 %x ls1 %x\n", + chan, uptr->u5, com_lstat[unit][0], com_lstat[unit][1]); + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_DEFSC: /* 0x0B */ /* Define special char */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x DEFSC\n", chan, cmd); + chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char */ + uptr->u5 = ~SNS_RTS; /* Request to send not ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_RRTS: /* 0x1B */ /* Reset RTS */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x RRTS\n", chan, cmd); + uptr->u5 &= ~SNS_RTS; /* Request to send not ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_SRTS: /* 0x1F */ /* Set RTS */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SRTS\n", chan, cmd); + uptr->u5 |= SNS_RTS; /* Requestd to send ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_RBRK: /* 0x33 */ /* Reset BREAK */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x RBRK\n", chan, cmd); + uptr->u5 &= ~SNS_BREAK; /* Request to send not ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_SBRK: /* 0x37 */ /* Set BREAK */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SBRK\n", chan, cmd); + uptr->u5 |= SNS_BREAK; /* Requestd to send ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_RDTR: /* 0x13 */ /* Reset DTR (ADVR) */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x DTR\n", chan, cmd); + uptr->u5 &= ~SNS_DTR; /* Data terminal not ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case COM_SDTR: /* 0x17 */ /* Set DTR (ADVF) */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x NOP\n", chan, cmd); + uptr->u5 |= SNS_DTR; /* Data terminal ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + +#if 0 +/* ACE byte 0 Modem Control/Operation status */ +/* stored in u4 bytes 0-3 */ +#define SNS_HALFD 0x80000000 /* Half-duplix operation set */ +#define SNS_MRINGE 0x40000000 /* Modem ring enabled */ +#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */ +#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */ +#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */ +#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */ +#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 11=7, 11=8 */ +#define SNS_ACECL2 0x01000000 /* 2nd bit for above */ + +/* ACE byte 1 Baud rate */ +#define SNS_NUB50 0x00800000 /* Zero N/U */ +#define SNS_NUB51 0x00400000 /* Zero N/U */ +#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */ +#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */ +#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */ +#define BAUD50 0x00000000 /* 50 baud */ +#define BAUD75 0x00010000 /* 75 baud */ +#define BAUD110 0x00020000 /* 110 baud */ +#define BAUD114 0x00030000 /* 134 baud */ +#define BAUD150 0x00040000 /* 150 baud */ +#define BAUD300 0x00050000 /* 300 baud */ +#define BAUD600 0x00060000 /* 600 baud */ +#define BAUD1200 0x00070000 /* 1200 baud */ +#define BAUD1800 0x00080000 /* 1800 baud */ +#define BAUD2000 0x00090000 /* 2000 baud */ +#define BAUD2400 0x000A0000 /* 2400 baud */ +#define BAUD3600 0x000B0000 /* 3600 baud */ +#define BAUD4800 0x000C0000 /* 4800 baud */ +#define BAUD7200 0x000D0000 /* 7200 baud */ +#define BAUD9600 0x000E0000 /* 9600 baud */ +#define BAUD19200 0x000F0000 /* 19200 baud */ + +/* ACE byte 2 Wake-up character */ +#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character */ +#endif + case COM_SACE: /* 0xff */ /* Set ACE parameters (3 chars) */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SACE\n", chan, cmd); + chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char 0 */ + uptr->u4 = ((uint32)ch)<<24; /* byte 0 of ACE data */ + chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char 1 */ + uptr->u4 |= ((uint32)ch)<<16; /* byte 1 of ACE data */ + chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char 2 */ + uptr->u4 |= ((uint32)ch)<<8; /* byte 2 of ACE data */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SACE bytes %x\n", chan, cmd, uptr->u4); + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + default: /* invalid command */ + uptr->u5 |= SNS_CMDREJ; /* command rejected */ + sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd Invald %x status %02x\n", chan, cmd, uptr->u5); + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + break; + } + + if (uptr->u5 & 0xff) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + return SNS_CHNEND|SNS_DEVEND; +} + +/* Unit service - polled input + Poll for new connections + Poll all connected lines for input +*/ +t_stat comi_srv(UNIT *uptr) +{ + uint8 ch; + int32 newln, ln, c; + uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */ + int cmd = uptr->u3 & 0xff; + uint32 cln = (uptr - coml_unit) & 0x7; /* use line # 0-7 for 8-15 */ + UNIT *comlp; + + ln = uptr - com_unit; /* line # */ + if ((com_unit[COMC].flags & UNIT_ATT) == 0){ /* attached? */ + return SCPE_OK; + } + newln = tmxr_poll_conn(&com_desc); /* look for connect */ + if (newln >= 0) { /* rcv enb pending? */ + uint16 chsa = GET_UADDR(coml_unit[newln].u3); /* get channel/sub-addr */ + int chan = ((chsa >> 8) & 0x7f); /* get the channel number */ + UNIT *comlp = coml_unit+ln; /* get uptr for coml line */ + int cmd = comlp->u3 & 0xff; /* get the active cmd */ +//fprintf(stderr, "comi_srv poll chsa %x new line %x\r\n", chsa, newln); + com_ldsc[newln].rcve = 1; /* enable rcv */ + com_ldsc[newln+8].xmte = 1; /* enable xmt for output line */ + com_sta[newln] &= ~COML_REP; /* clr pending */ + /* send attention to OS here for this channel */ + /* need to get chsa here for the channel */ +//fprintf(stderr, "comi_srv chsa %x chan %x\r\n", chsa, chan); + set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */ + } + /* poll all devices for input */ + tmxr_poll_rx(&com_desc); /* poll for input */ + for (ln = 0; ln < COM_NUMLIN; ln++) { /* loop thru lines */ + UNIT *comlp = coml_unit+ln; /* get uptr for coml line */ + int cmd = comlp->u3 & 0xff; /* get the active cmd */ + uint16 chsa = GET_UADDR(comlp->u3); /* get channel/sub-addr */ + if (com_ldsc[ln].conn) { /* connected? */ + if ((c = tmxr_getc_ln(&com_ldsc[ln]))) { /* get char */ +//fprintf(stderr, "comi_srv chsa %x input %x cmd %x\r\n", chsa, c, cmd); + ch = c; /* just the char */ + /* echo the char out */ + tmxr_putc_ln(&com_ldsc[ln], ch); /* output char */ + tmxr_poll_tx(&com_desc); /* poll xmt */ + if (c & SCPE_BREAK) /* break? */ + com_sta[ln] |= COML_RBP; /* set rcv brk */ + else { /* normal char */ + com_sta[ln] &= ~COML_RBP; /* clr rcv brk */ + c = sim_tt_inpcvt(c, TT_GET_MODE(coml_unit[ln].flags)); + com_rbuf[ln] = c; /* save char */ + if ((cmd & COM_RD) == COM_RD) { /* read active? */ + ch = c; /* clean the char */ + if (ch == '\n') /* convert newline */ + ch = '\r'; /* to C/R */ + /* write byte to memory */ + if (chan_write_byte(chsa, &ch)) { + /* done, reading chars */ +//fprintf(stderr, "comi_srv chsa %x input %x complete cmd %x\r\n", chsa, c, cmd); + comlp->u3 &= LMASK; /* nothing left, clear cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ + } else { + /* more to go, continue */ +//fprintf(stderr, "comi_srv chsa %x input %x cnt %x cmd %x\r\n", chsa, c, cmd); + if (ch == '\r') { /* see if done */ + comlp->u3 &= LMASK; /* nothing left, clear cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ + } + } + } + else { + /* see if user hit the wakeup key */ + if (((comlp->u4 & ACE_WAKE) >> 8) == ch) { + /* send attention to OS here for this channel */ + /* need to get chsa here for the channel */ +// fprintf(stderr, "comi_srv WAKEUP chsa %x ch %x wake %x\r\n", chsa, ch, (comlp->u4 & ACE_WAKE)>>8); + set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */ + } + } + } /* end else char */ + } /* end if char */ + } /* end if conn */ + else + com_sta[ln] &= ~COML_RBP; /* disconnected */ + } /* end for */ + return sim_clock_coschedule(uptr, 200); /* continue poll */ +} + +/* Unit service - output transfers */ +t_stat como_srv(UNIT *uptr) +{ + uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */ + uint32 ln = (uptr - coml_unit) & 0x7; /* use line # 0-7 for 8-15 */ + uint32 done; + int cmd = uptr->u3 & 0xff; /* get active cmd */ + uint8 ch; + + +//fprintf(stderr, "como_srv entry 1 chsa %x line %x cmd %x\r\n", chsa, ln, cmd); + if (cmd) { + /* get a user byte from memory */ + done = chan_read_byte(chsa, &ch); /* get byte from memory */ +#if 0 + if (!done) + fprintf(stderr, "como_srv mem_read chsa %x line %x char %c %x\r\n", chsa, ln, ch, ch); + else + uptr->u3 &= LMASK; /* leave only chsa */ +#else + if (done) + uptr->u3 &= LMASK; /* leave only chsa */ +#endif + } else + return SCPE_OK; + + if (com_dev.flags & DEV_DIS) { /* disabled */ +//fprintf(stderr, "como_srv chsa %x line %x DEV_DIS set\r\n", chsa, ln); + if (done) { +//fprintf(stderr, "como_srv Write DONE %d status %x\r\n", ln, SNS_CHNEND|SNS_DEVEND); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */ + } + return SCPE_OK; /* return */ + } +//fprintf(stderr, "como_srv poll chsa %x line %x\r\n", chsa, ln); + + if (com_ldsc[ln].conn) { /* connected? */ + if (com_ldsc[ln].xmte) { /* xmt enabled? */ + if (done) { /* are we done writing */ +endit: + uptr->u3 &= LMASK; /* nothing left, command complete */ + sim_debug(DEBUG_CMD, &com_dev, "com_srvo write %d: chnend|devend\n", ln); +//fprintf(stderr, "como_srv Write DONE %d status %x\r\n", ln, SNS_CHNEND|SNS_DEVEND); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */ + return SCPE_OK; + } + /* send the next char out */ + tmxr_putc_ln(&com_ldsc[ln], ch); /* output char */ +//fprintf(stderr, "como_srv writing char %c to ln %d\r\n", ch, ln); + tmxr_poll_tx(&com_desc); /* poll xmt */ + sim_activate(uptr, uptr->wait); /* wait */ + return SCPE_OK; + } else { /* buf full */ + if (done) /* are we done writing */ + goto endit; /* done */ + /* just dump the char */ +// /* xmt disabled, just wait around */ +//fprintf(stderr, "como_srv Write dumping %x on line %d\r\n", ch, ln); + tmxr_poll_tx(&com_desc); /* poll xmt */ +//?? sim_activate(uptr, coml_unit[ln].wait); /* wait */ + sim_activate(uptr, uptr->wait); /* wait */ + return SCPE_OK; + } + } else { + /* not connected, so dump char on ground */ + if (done) { +//fprintf(stderr, "como_srv Write dump DONE %d status %x\r\n", ln, SNS_CHNEND|SNS_DEVEND); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */ + uptr->u3 &= LMASK; /* nothing left, command complete */ + } + sim_activate(uptr, uptr->wait); /* wait */ + return SCPE_OK; + } +} + +/* Reset routine */ +t_stat com_reset (DEVICE *dptr) +{ + int32 i; + + if (com_dev.flags & DEV_DIS) /* master disabled? */ + com_dev.flags |= DEV_DIS; /* disable lines */ + else + com_dev.flags &= ~DEV_DIS; + if (com_unit[COMC].flags & UNIT_ATT) /* master att? */ + sim_clock_coschedule(&com_unit[0], 200); /* activate */ + for (i = 0; i < COM_LINES; i++) /* reset lines */ + com_reset_ln(i); + return SCPE_OK; +} + + +/* attach master unit */ +t_stat com_attach(UNIT *uptr, CONST char *cptr) +{ + uint16 chsa = GET_UADDR(com_unit[COMC].u3); /* get channel/subaddress */ + t_stat r; + + chsa = GET_UADDR(com_unit[COMC].u3); /* get channel/subaddress */ +//fprintf(stderr, "com_attach chsa %x\r\n", chsa); + r = tmxr_attach(&com_desc, uptr, cptr); /* attach */ + if (r != SCPE_OK) /* error? */ + return r; /* return error */ + sim_activate(uptr, 0); /* start poll at once */ +//fprintf(stderr, "com_attach chsa %x\r\n", chsa); + return SCPE_OK; +} + +/* detach master unit */ +t_stat com_detach(UNIT *uptr) +{ + int32 i; + t_stat r; + + r = tmxr_detach(&com_desc, uptr); /* detach */ + for (i = 0; i < COM_LINES; i++) /* disable rcv */ + com_reset_ln(i); /* reset the line */ + sim_cancel(uptr); /* stop poll, cancel timer */ + return r; +} + +/* Reset an individual line */ +void com_reset_ln (int32 ln) +{ + sim_cancel(&coml_unit[ln]); + com_sta[ln] = 0; + com_rbuf[ln] = 0; /* clear read buffer */ + com_xbuf[ln] = 0; /* clear write buffer */ + com_ldsc[ln].rcve = 0; + return; +} + +t_stat com_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "SEL32 8-Line Async Controller Terminal Interfaces\n\n"); +fprintf (st, "For very early system programs, the PDP-11 simulator supports up to sixteen\n"); +fprintf (st, "additional DC11 terminal interfaces. The additional terminals consist of two\n"); +fprintf (st, "independent devices, DCI and COML. The entire set is modeled as a terminal\n"); +fprintf (st, "multiplexer, with DCI as the master controller. The additional terminals\n"); +fprintf (st, "perform input and output through Telnet sessions connected to a user-specified\n"); +fprintf (st, "port.\n\n"); +fprintf (st, "The ATTACH command specifies the port to be used:\n\n"); +tmxr_attach_help (st, dptr, uptr, flag, cptr); +fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n"); +fprintf (st, " mode input characters output characters\n\n"); +fprintf (st, " UC lower case converted lower case converted to upper case,\n"); +fprintf (st, " to upper case, high-order bit cleared,\n"); +fprintf (st, " high-order bit cleared non-printing characters suppressed\n"); +fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n"); +fprintf (st, " non-printing characters suppressed\n"); +fprintf (st, " 7B high-order bit cleared high-order bit cleared\n"); +fprintf (st, " 8B no changes no changes\n\n"); +fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n"); +fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n"); +fprintf (st, " sim> SET COMLn DATASET simulate attachment to a dataset (modem)\n"); +fprintf (st, " sim> SET COMLn NODATASET simulate direct attachment to a terminal\n\n"); +fprintf (st, "Finally, each line supports output logging. The SET COMLn LOG command enables\n"); +fprintf (st, "logging on a line:\n\n"); +fprintf (st, " sim> SET COMLn LOG=filename log output of line n to filename\n\n"); +fprintf (st, "The SET COMLn NOLOG command disables logging and closes the open log file,\n"); +fprintf (st, "if any.\n\n"); +fprintf (st, "Once DCI is attached and the simulator is running, the terminals listen for\n"); +fprintf (st, "connections on the specified port. They assume that the incoming connections\n"); +fprintf (st, "are Telnet connections. The connections remain open until disconnected either\n"); +fprintf (st, "by the Telnet client, a SET DCI DISCONNECT command, or a DETACH DCI command.\n\n"); +fprintf (st, "Other special commands:\n\n"); +fprintf (st, " sim> SHOW COMC CONNECTIONS show current connections\n"); +fprintf (st, " sim> SHOW COMC STATISTICS show statistics for active connections\n"); +fprintf (st, " sim> SET COMLn DISCONNECT disconnects the specified line.\n"); +fprintf (st, "\nThe additional terminals do not support save and restore. All open connections\n"); +fprintf (st, "are lost when the simulator shuts down or DCI is detached.\n"); + fprint_set_help (st, dptr); + fprint_show_help (st, dptr); + return SCPE_OK; +} + +/* description of controller */ +const char *com_description (DEVICE *dptr) +{ + return "SEL 32 8-Line async communications controller"; +} + +#endif diff --git a/SEL32/sel32_con.c b/SEL32/sel32_con.c new file mode 100644 index 0000000..cf670c3 --- /dev/null +++ b/SEL32/sel32_con.c @@ -0,0 +1,370 @@ +/* sel32_con.c: SEL 32 Class F IOP processor console. + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This is the standard console interface. It is subchannel of the IOP 7e00. + + These units each buffer one record in local memory and signal + ready when the buffer is full or empty. The channel must be + ready to recieve/transmit data when they are activated since + they will transfer their block during chan_cmd. All data is + transmitted as ASCII characters. + +*/ + +#include "sel32_defs.h" +#include "sim_defs.h" + +#ifdef NUM_DEVS_CON + +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chan, uint8 *data); +extern int chan_write_byte(uint16 chan, uint8 *data); +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); + +/* Held in u3 is the device command and status */ +#define CON_INCH 0x00 /* Initialize channel command */ +#define CON_WR 0x01 /* Write console */ +#define CON_RD 0x02 /* Read console */ +#define CON_NOP 0x03 /* No op command */ +#define CON_SNS 0x04 /* Sense command */ +#define CON_ECHO 0x0a /* Read with Echo */ +#define CON_CON 0x1f /* connect line */ +#define CON_DIS 0x23 /* disconnect line */ +#define CON_RWD 0x37 /* TOF and write line */ + +#define CON_MSK 0xff /* Command mask */ + +/* Status held in u3 */ +/* controller/unit address in upper 16 bits */ +#define CON_INPUT 0x100 /* Input ready for unit */ +#define CON_CR 0x200 /* Output at beginning of line */ +#define CON_REQ 0x400 /* Request key pressed */ +#define CON_EKO 0x800 /* Echo input character */ +#define CON_OUTPUT 0x1000 /* Output ready for unit */ +#define CON_READ 0x2000 /* Read mode selected */ + +/* Input buffer pointer held in u4 */ + +/* in u5 packs sense byte 0,1 and 3 */ +/* Sense byte 0 */ +#define SNS_CMDREJ 0x80000000 /* Command reject */ +#define SNS_INTVENT 0x40000000 /* Unit intervention required */ +/* sense byte 3 */ +#define SNS_RDY 0x80 /* device ready */ +#define SNS_ONLN 0x40 /* device online */ +//#define SNS_DSR 0x04 /* data set ready */ +#define SNS_DSR 0x08 /* data set ready */ +#define SNS_DCD 0x04 /* data carrier detect */ + +/* std devices. data structures + con_dev Console device descriptor + con_unit Console unit descriptor + con_reg Console register list + con_mod Console modifiers list +*/ + +struct _con_data +{ + uint8 ibuff[145]; /* Input line buffer */ + uint8 incnt; /* char count */ +} +con_data[NUM_UNITS_CON]; + +uint32 atbuf=0; /* attention buffer */ + +/* forward definitions */ +uint8 con_startcmd(UNIT *, uint16, uint8); +void con_ini(UNIT *, t_bool); +t_stat con_srvi(UNIT *); +t_stat con_srvo(UNIT *); +t_stat con_reset(DEVICE *); +t_stat con_attach(UNIT *, char *); +t_stat con_detach(UNIT *); + +/* channel program information */ +CHANP con_chp[NUM_UNITS_CON] = {0}; + +MTAB con_mod[] = { + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL}, + {0} +}; + +UNIT con_unit[] = { + {UDATA(con_srvi, UNIT_ATT, 0), 0, UNIT_ADDR(0x7EFC)}, /* Input */ + {UDATA(con_srvo, UNIT_ATT, 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}; +DIB con_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */ + con_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + con_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + con_unit, /* UNIT* units */ /* Pointer to units structure */ + con_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_CON, /* uint8 numunits */ /* number of units defined */ + 0x0f, /* uint8 mask */ /* 2 devices - device mask */ + 0x7e00, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE con_dev = { + "CON", con_unit, NULL, con_mod, + NUM_UNITS_CON, 8, 15, 1, 8, 8, + NULL, NULL, NULL, NULL, NULL, NULL, + &con_dib, DEV_UADDR|DEV_DISABLE|DEV_DEBUG, 0, dev_debug +}; + +/* + * Console print routines. + */ +/* initialize the console chan/unit */ +void con_ini(UNIT *uptr, t_bool f) { + int unit = (uptr - con_unit); /* unit 0 */ + DEVICE *dptr = find_dev_from_unit(uptr); + + con_data[unit].incnt = 0; /* no input data */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + sim_activate(uptr, 1000); /* time increment */ +} + +/* start an I/O operation */ +uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { + int unit = (uptr - con_unit); /* unit 0,1 */ + uint8 ch; + + if ((uptr->u3 & CON_MSK) != 0) /* is unit busy */ + return SNS_BSY; /* yes, return busy */ + + /* process the commands */ + switch (cmd & 0xFF) { + case CON_INCH: /* 0x00 */ /* INCH command */ + sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd INCH\n", chan); + return SNS_CHNEND|SNS_DEVEND; /* all is well */ + break; + + 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->u5 |= SNS_CMDREJ; /* command rejected */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + } + uptr->u3 &= LMASK; /* leave only chsa */ + uptr->u3 |= (cmd & CON_MSK); /* save command */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + sim_activate(uptr, 20); /* TRY 06-09-18 */ + return 0; /* no status change */ + break; + + case CON_RD: /* Read command */ + case CON_ECHO: /* Read command w/ECHO */ + /* if output requested for input device, give error */ + if (unit == 1) { + uptr->u5 |= SNS_CMDREJ; /* command rejected */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + } + uptr->u3 &= LMASK; /* leave only chsa */ + uptr->u3 |= (cmd & CON_MSK); /* save command */ + if (cmd == CON_ECHO) /* echo command? */ + uptr->u3 |= CON_EKO; /* save echo status */ + uptr->u3 |= CON_READ; /* show read mode */ + atbuf = 0; /* reset attention buffer */ + uptr->u4 = 0; /* no I/O yet */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + return 0; + break; + + case CON_NOP: /* NOP has do nothing */ + uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case CON_CON: /* Connect, return Data Set ready */ + sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd %x NOP\n", chan, cmd); + uptr->u5 |= (SNS_DSR|SNS_DCD); /* Data set ready, Data Carrier detected */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case CON_DIS: /* NOP has do nothing */ + sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd %x NOP\n", chan, cmd); + uptr->u5 &= ~(SNS_DSR|SNS_DCD); /* Data set not ready */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + case CON_SNS: /* Sense */ + sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd Sense %02x\n", chan, uptr->u5); + /* value 4 is Data Set Ready */ + /* value 5 is Data carrier detected n/u */ + ch = uptr->u5; /* status */ + chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */ + return SNS_CHNEND|SNS_DEVEND; /* good return */ + break; + + default: /* invalid command */ + uptr->u5 |= SNS_CMDREJ; /* command rejected */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + break; + } + + if (uptr->u5 & (~(SNS_RDY|SNS_ONLN|SNS_DSR))) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + return SNS_CHNEND|SNS_DEVEND; +} + +/* Handle output transfers for console */ +t_stat con_srvo(UNIT *uptr) { + uint16 chsa = GET_UADDR(uptr->u3); + int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */ + int cmd = uptr->u3 & CON_MSK; + uint8 ch; + + if ((cmd == CON_WR) || (cmd == CON_RWD)) { + /* Write to device */ + if (chan_read_byte(chsa, &ch)) { /* get byte from memory */ + uptr->u3 &= LMASK; /* nothing left, command complete */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */ + } else { + sim_debug(DEBUG_CMD, &con_dev, "con_srvo write %d: putch %0.2x %c\n", unit, ch, ch); + sim_putchar(ch); /* output next char to device */ + sim_activate(uptr, 20); /* TRY 07-18-18 */ + } + } + return SCPE_OK; +} + +/* Handle input transfers for console */ +t_stat con_srvi(UNIT *uptr) { + uint16 chsa = GET_UADDR(uptr->u3); + int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */ + int cmd = uptr->u3 & CON_MSK; + t_stat r = SCPE_ARG; /* Force error if not set */ + uint8 ch; + int i; + + switch (cmd) { + + case CON_RD: /* read from device */ + case CON_ECHO: /* read from device w/ECHO */ + if (uptr->u3 & CON_INPUT) { /* input waiting? */ + ch = con_data[unit].ibuff[uptr->u4++]; /* get char from read buffer */ + sim_debug(DEBUG_CMD, &con_dev, "con_srvi %d: read %02x\n", unit, ch); + if (chan_write_byte(chsa, &ch)) { /* write byte to memory */ + con_data[unit].incnt = 0; /* buffer empty */ + cmd = 0; /* no cmd either */ + uptr->u3 &= LMASK; /* nothing left, command complete */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ + } else { + if (uptr->u4 == con_data[unit].incnt) { /* read completed */ + con_data[unit].incnt = 0; /* buffer is empty */ + cmd = 0; /* no cmd either */ + uptr->u3 &= LMASK; /* nothing left, command complete */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ + } + } + } + break; + } + + /* poll for next input if reading or @@A sequence */ + r = sim_poll_kbd(); /* poll for ready */ + if (r & SCPE_KFLAG) { /* got a char */ + ch = r & 0377; /* drop any extra bits */ + if ((cmd == CON_RD) || (cmd == CON_ECHO)) { /* looking for input */ + atbuf = 0; /* reset attention buffer */ + if (ch == '\n') /* convert newline */ + ch = '\r'; /* make newline into carriage return */ + /* Handle end of buffer */ + switch (ch) { + + case 0x7f: /* Delete */ + case '\b': /* backspace */ + if (con_data[unit].incnt != 0) { + con_data[unit].incnt--; + sim_putchar('\b'); + sim_putchar(' '); + sim_putchar('\b'); + } + break; + case 03: /* ^C */ + case 025: /* ^U clear line */ + for (i = con_data[unit].incnt; i> 0; i--) { + sim_putchar('\b'); + sim_putchar(' '); + sim_putchar('\b'); + } + con_data[unit].incnt = 0; + break; + + case '\r': /* return */ + case '\n': /* newline */ + uptr->u3 |= CON_CR; /* C/R received */ + /* fall through */ + default: + if (con_data[unit].incnt < sizeof(con_data[unit].ibuff)) { + if (uptr->u3 & CON_EKO) /* ECHO requested */ + sim_putchar(ch); /* ECHO the char */ + con_data[unit].ibuff[con_data[unit].incnt++] = ch; + uptr->u3 |= CON_INPUT; /* we have a char available */ + } + break; + } + } else { + /* look for attention sequence '@@A' */ + if (ch == '@' || ch == 'A' || ch == 'a') { + if (ch == 'a') + ch = 'A'; + atbuf = (atbuf|ch)<<8; + sim_putchar(ch); /* ECHO the char */ + if (atbuf == 0x40404100) { + attention_trap = CONSOLEATN_TRAP; /* console attn (0xb4) */ + atbuf = 0; /* reset attention buffer */ + sim_putchar('\r'); /* return char */ + sim_putchar('\n'); /* line feed char */ + } + } else { + if (ch == '?') { + int chan = ((chsa >> 8) & 0x7f); /* get the channel number */ + /* set ring bit? */ + set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */ + } + } + } + } + if ((cmd == CON_RD) || (cmd == CON_ECHO)) /* looking for input */ + sim_activate(uptr, 200); /* keep going */ + else + sim_activate(uptr, 400); /* keep going */ + return SCPE_OK; +} + +#endif + diff --git a/SEL32/sel32_cpu.c b/SEL32/sel32_cpu.c index 080bc55..e8f42d8 100644 --- a/SEL32/sel32_cpu.c +++ b/SEL32/sel32_cpu.c @@ -1,3520 +1,4114 @@ -/* sel32_cpu.c: Sel 32 CPU simulator - - Copyright (c) 2017-2018, Richard Cornwell, 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"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#include "sel32_defs.h" - -/* 32/7x PSW/PSD Mode Trap/Interrupt Priorities */ -/* Relative Logical Int Vect TCW IOCD Description */ -/* Priority Priority Location Addr Addr */ -/* 0 0F4 Power Fail Safe Trap */ -/* 1 0FC System Override Trap (Not Used) */ -/* 2 0E8* Memory Parity Trap */ -/* 3 190 Nonpresent Memory Trap */ -/* 4 194 Undefined Instruction Trap */ -/* 5 198 Privilege Violation Trap */ -/* 6 180 Supervisor Call Trap (SVC) */ -/* 7 184 Machine Check Trap */ -/* 8 188 System Check Trap */ -/* 9 18C Map Fault Trap */ -/* A Not Used */ -/* B Not Used */ -/* C Not Used */ -/* D Not Used */ -/* E 0E4 Block Mode Timeout Trap */ -/* F 1A4* Arithmetic Exception Trap */ -/* 10 00 0F0 Power Fail Safe Interrupt */ -/* 11 01 0F8 System Override Interrupt */ -/* 12 12 0E8* Memory Parity Trap */ -/* 13 13 0EC Attention Interrupt */ -/* 14 14 140 100 700 I/O Channel 0 interrupt */ -/* 15 15 144 104 708 I/O Channel 1 interrupt */ -/* 16 16 148 108 710 I/O Channel 2 interrupt */ -/* 17 17 14C 10C 718 I/O Channel 3 interrupt */ -/* 18 18 150 110 720 I/O Channel 4 interrupt */ -/* 19 19 154 114 728 I/O Channel 5 interrupt */ -/* 1A 1A 158 118 730 I/O Channel 6 interrupt */ -/* 1B 1B 15C 11C 738 I/O Channel 7 interrupt */ -/* 1C 1C 160 120 740 I/O Channel 8 interrupt */ -/* 1D 1D 164 124 748 I/O Channel 9 interrupt */ -/* 1E 1E 168 128 750 I/O Channel A interrupt */ -/* 1F 1F 16C 12C 758 I/O Channel B interrupt */ -/* 20 20 170 130 760 I/O Channel C interrupt */ -/* 21 21 174 134 768 I/O Channel D interrupt */ -/* 22 22 178 138 770 I/O Channel E interrupt */ -/* 23 23 17C 13C 778 I/O Channel F interrupt */ -/* 24 24 190* Nonpresent Memory Trap */ -/* 25 25 194* Undefined Instruction Trap */ -/* 26 26 198* Privlege Violation Trap */ -/* 27 27 19C Call Monitor Interrupt */ -/* 28 28 1A0 Real-Time Clock Interrupt */ -/* 29 29 1A4* Arithmetic Exception Interrupt */ -/* 2A 2A 1A8 External/Software Interrupt */ -/* 2B 2B 1AC External/Software Interrupt */ -/* 2C 2C 1B0 External/Software Interrupt */ -/* 2D 2D 1B4 External/Software Interrupt */ -/* 2E 2E 1B8 External/Software Interrupt */ -/* 2F 2F 1BC External/Software Interrupt */ -/* 30 30 1C0 External/Software Interrupt */ -/* 31 31 1C4 External/Software Interrupt */ -/* THRU THRU THRU THRU */ -/* 77 77 2DC External/Software Interrupt */ -/* 78 2E0 End of IPU Processing Trap (CPU) */ -/* 79 2E4 Start IPU Processing Trap (IPU) */ -/* 7A 2E8 Supervisor Call Trap (IPU) */ -/* 7B 2EC Error Trap (IPU) */ -/* 7C 2F0 Call Monitor Trap (IPU) */ -/* 7D 7D 2F4 Stop IPU Processing Trap (IPU) */ -/* 7E 7E 2F8 External/Software Interrupt */ -/* 7F 7F 2FC External/Software Interrupt */ - -/* Concept 32 PSD Mode Trap/Interrupt Priorities */ -/* Relative|Logical |Int Vect|TCW |IOCD|Description */ -/* Priority|Priority|Location|Addr|Addr */ -/* - 080 Power Fail Safe Trap */ -/* - 084 Power On Trap */ -/* - 088 Memory Parity Trap */ -/* - 08C Nonpresent Memory Trap */ -/* - 090 Undefined Instruction Trap */ -/* - 094 Privilege Violation Trap */ -/* - 098 Supervisor Call Trap (SVC) */ -/* - 09C Machine Check Trap */ -/* - 0A0 System Check Trap */ -/* - 0A4 Map Fault Trap */ -/* - 0A8 Undefined IPU Instruction Trap */ -/* - 0AC Signal CPU or Signal IPU Trap */ -/* - 0B0 Address Specification Trap */ -/* - 0B4 Console Attention Trap */ -/* - 0B8 Privlege Mode Halt Trap */ -/* - 0BC Arithmetic Exception Trap */ -/* */ -/* 0 00 100 External/software Interrupt 0 */ -/* 1 01 104 External/software Interrupt 1 */ -/* 2 02 108 External/software Interrupt 2 */ -/* 3 03 10C External/software Interrupt 3 */ -/* 4 04 110 704 700 I/O Channel 0 interrupt */ -/* 5 05 114 70C 708 I/O Channel 1 interrupt */ -/* 6 06 118 714 710 I/O Channel 2 interrupt */ -/* 7 07 11C 71C 718 I/O Channel 3 interrupt */ -/* 8 08 120 724 720 I/O Channel 4 interrupt */ -/* 9 09 124 72C 728 I/O Channel 5 interrupt */ -/* A 0A 128 734 730 I/O Channel 6 interrupt */ -/* B 0B 12C 73C 738 I/O Channel 7 interrupt */ -/* C 0C 130 744 740 I/O Channel 8 interrupt */ -/* D 0D 134 74C 748 I/O Channel 9 interrupt */ -/* E 0E 138 754 750 I/O Channel A interrupt */ -/* F 0F 13C 75C 758 I/O Channel B interrupt */ -/* 10 10 140 764 760 I/O Channel C interrupt */ -/* 11 11 144 76C 768 I/O Channel D interrupt */ -/* 12 12 148 774 770 I/O Channel E interrupt */ -/* 13 13 14c 77C 778 I/O Channel F interrupt */ -/* 14 14 150 External/Software Interrupt */ -/* 15 15 154 External/Software Interrupt */ -/* 16 16 158 External/Software Interrupt */ -/* 17 17 15C External/Software Interrupt */ -/* 18 18 160 Real-Time Clock Interrupt */ -/* 19 19 164 External/Software Interrupt */ -/* 1A 1A 1A8 External/Software Interrupt */ -/* 1B 1B 1AC External/Software Interrupt */ -/* 1C 1C 1B0 External/Software Interrupt */ -/* THRU THRU THRU THRU */ -/* 6C 6C 2B0 External/Software Interrupt */ -/* 6D 6D 2B4 External/Software Interrupt */ -/* 6E 6E 2B8 External/Software Interrupt */ -/* 6F 6F 2BC Interval Timer Interrupt */ - -/* IVL ------------> ICB Trap/Interrupt Vector Location points to Interrupt Context Block */ -/* Wd 0 - Old PSD Word 1 points to return location */ -/* Wd 1 - Old PSD Word 2 */ -/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ -/* Wd 3 - New PSD Word 2 */ -/* Wd 4 - CPU Status word at time of interrupt/trap */ -/* Wd 5 - N/U For Traps/Interrupts */ - -/* IVL ------------> ICB XIO Interrupt Vector Location */ -/* Wd 0 - Old PSD Word 1 points to return location */ -/* Wd 1 - Old PSD Word 2 */ -/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ -/* Wd 3 - New PSD Word 2 */ -/* Wd 4 - Input/Output Command List Address (IOCL) for the Class F I/O CHannel */ -/* Wd 5 - 24 bit real address of the channel status word */ - -/* CPU registers, map cache, spad, and other variables */ -int cpu_index; /* Current CPU running */ -uint32 PSD[2]; /* the PC for the instruction */ -#define PSD1 PSD[0] /* word 1 of PSD */ -#define PSD2 PSD[1] /* word 2 of PSD */ -uint32 M[MAXMEMSIZE] = { 0 }; /* Memory */ -uint32 GPR[8]; /* General Purpose Registers */ -uint32 BR[8]; /* Base registers */ -uint32 PC; /* Program counter */ -uint8 CC; /* Condition code register */ -uint32 SPAD[256]; /* Scratch pad memory */ -uint32 CPUSTATUS; /* cpu status word */ -uint32 TRAPSTATUS; /* trap status word */ -/* CPU mapping cache entries */ -/* 32/55 has none */ -/* 32/7x has 32 8KW maps per task */ -/* Concept/32 has 2048 2KW maps per task */ -uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */ - -uint8 modes; /* Operating modes */ - -uint8 irq_flags; /* Interrupt control flags PSD 2 bits 16&17 */ -uint16 cpix; /* Current Process index */ -uint16 bpix; /* Base process index */ -uint8 iowait; /* waiting for I/O */ - -/* define traps */ -uint32 TRAPME; /* trap to be executed */ -struct InstHistory -{ - uint32 psd1; /* the PC for the instruction */ - uint32 psd2; /* the PC for the instruction */ - uint32 inst; /* the instruction itself */ - uint32 ea; /* computed effective address of data */ - uint32 reg; /* reg for operation */ - t_uint64 dest; /* destination value */ - t_uint64 src; /* source value */ -// uint32 flags; /* status flags */ -// t_uint64 res; /* ?? */ - uint8 cc; /* cc's */ -}; - -/* forward definitions */ -t_stat cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw); -t_stat cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw); -t_stat cpu_reset(DEVICE * dptr); -t_stat cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc); -t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc); -t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc); -uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev); -t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); -const char *cpu_description (DEVICE *dptr); -t_stat rtc_srv(UNIT * uptr); -t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot); -t_stat load_maps(uint32 thepsd[2]); -t_stat read_instruction(uint32 thepsd[2], uint32 *instr); -t_stat Mem_read(uint32 addr, uint32 *data); -t_stat Mem_write(uint32 addr, uint32 *data); -/* external definitions */ -extern t_stat startxio(uint16 addr, uint32 *status); /* XIO start in chan.c */ -extern t_stat testxio(uint16 addr, uint32 *status); /* XIO test in chan.c */ -extern t_stat stopxio(uint16 addr, uint32 *status); /* XIO stio in chan.c */ -extern t_stat chan_set_devs(); /* set up the defined devices on the simulator */ -extern uint32 scan_chan(void); /* go scan for I/O int pending */ -extern uint16 loading; /* set when booting */ - -/* History information */ -int32 hst_p = 0; /* History pointer */ -int32 hst_lnt = 0; /* History length */ -struct InstHistory *hst = NULL; /* History stack */ - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -#ifdef DEFINED_IN_SIM_DEFS_H -/* Unit data structure from sim_defs.h - - Parts of the unit structure are device specific, that is, they are - not referenced by the simulator control package and can be freely - used by device simulators. Fields starting with 'buf', and flags - starting with 'UF', are device specific. The definitions given here - are for a typical sequential device. -*/ - -struct UNIT { - UNIT *next; /* next active */ - t_stat (*action)(UNIT *up); /* action routine */ - char *filename; /* open file name */ - FILE *fileref; /* file reference */ - void *filebuf; /* memory buffer */ - uint32 hwmark; /* high water mark */ - int32 time; /* time out */ - uint32 flags; /* flags */ - uint32 dynflags; /* dynamic flags */ - t_addr capac; /* capacity */ - t_addr pos; /* file position */ - void (*io_flush)(UNIT *up); /* io flush routine */ - uint32 iostarttime; /* I/O start time */ - int32 buf; /* buffer */ - int32 wait; /* wait */ - int32 u3; /* device specific */ - int32 u4; /* device specific */ - int32 u5; /* device specific */ - int32 u6; /* device specific */ - void *up7; /* device specific */ - void *up8; /* device specific */ - uint16 us9; /* device specific */ - uint16 us10; /* device specific */ - void *tmxr; /* TMXR linkage */ - t_bool (*cancel)(UNIT *); - double usecs_remaining; /* time balance for long delays */ - char *uname; /* Unit name */ -#ifdef SIM_ASYNCH_IO - void (*a_check_completion)(UNIT *); - t_bool (*a_is_active)(UNIT *); - UNIT *a_next; /* next asynch active */ - int32 a_event_time; - ACTIVATE_API a_activate_call; - /* Asynchronous Polling control */ - /* These fields should only be referenced when holding the sim_tmxr_poll_lock */ - t_bool a_polling_now; /* polling active flag */ - int32 a_poll_waiter_count; /* count of polling threads */ - /* waiting for this unit */ - /* Asynchronous Timer control */ - double a_due_time; /* due time for timer event */ - double a_due_gtime; /* due time (in instructions) for timer event */ - double a_usec_delay; /* time delay for timer event */ -#endif /* SIM_ASYNCH_IO */ - }; - -/* Unit flags */ - -#define UNIT_V_UF_31 12 /* dev spec, V3.1 */ -#define UNIT_V_UF 16 /* device specific */ -#define UNIT_V_RSV 31 /* reserved!! */ - -#define UNIT_ATTABLE 0000001 /* attachable */ -#define UNIT_RO 0000002 /* read only */ -#define UNIT_FIX 0000004 /* fixed capacity */ -#define UNIT_SEQ 0000010 /* sequential */ -#define UNIT_ATT 0000020 /* attached */ -#define UNIT_BINK 0000040 /* K = power of 2 */ -#define UNIT_BUFABLE 0000100 /* bufferable */ -#define UNIT_MUSTBUF 0000200 /* must buffer */ -#define UNIT_BUF 0000400 /* buffered */ -#define UNIT_ROABLE 0001000 /* read only ok */ -#define UNIT_DISABLE 0002000 /* disable-able */ -#define UNIT_DIS 0004000 /* disabled */ -#define UNIT_IDLE 0040000 /* idle eligible */ -#endif /* DEFINED_IN_SIM_DEFS_H */ - -UNIT cpu_unit = - /* Unit data layout for CPU */ -/* { UDATA(rtc_srv, UNIT_BINK | MODEL(MODEL_27) | MEMAMOUNT(0), MAXMEMSIZE ), 120 }; */ - { - NULL, /* UNIT *next */ /* next active */ - rtc_srv, /* t_stat (*action) */ /* action routine */ - NULL, /* char *filename */ /* open file name */ - NULL, /* FILE *fileref */ /* file reference */ - NULL, /* void *filebuf */ /* memory buffer */ - 0, /* uint32 hwmark */ /* high water mark */ - 0, /* int32 time */ /* time out */ - UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(0), /* uint32 flags */ /* flags */ - 0, /* uint32 dynflags */ /* dynamic flags */ - MAXMEMSIZE, /* t_addr capac */ /* capacity */ - 0, /* t_addr pos */ /* file position */ - NULL, /* void (*io_flush) */ /* io flush routine */ - 0, /* uint32 iostarttime */ /* I/O start time */ - 0, /* int32 buf */ /* buffer */ - 120, /* int32 wait */ /* wait */ -}; - -/* Register data structure definition from sim_defs.h */ -#ifdef DEFINED_IN_SIM_DEFS_H -struct REG { - CONST char *name; /* name */ - void *loc; /* location */ - uint32 radix; /* radix */ - uint32 width; /* width */ - uint32 offset; /* starting bit */ - uint32 depth; /* save depth */ - const char *desc; /* description */ - BITFIELD *fields; /* bit fields */ - uint32 qptr; /* circ q ptr */ - size_t str_size; /* structure size */ - /* NOTE: Flags MUST always be last since it is initialized outside of macro definitions */ - uint32 flags; /* flags */ - }; - -/* Register flags from sim_defs.h */ -#define REG_FMT 00003 /* see PV_x */ -#define REG_RO 00004 /* read only */ -#define REG_HIDDEN 00010 /* hidden */ -#define REG_NZ 00020 /* must be non-zero */ -#define REG_UNIT 00040 /* in unit struct */ -#define REG_STRUCT 00100 /* in structure array */ -#define REG_CIRC 00200 /* circular array */ -#define REG_VMIO 00400 /* use VM data print/parse */ -#define REG_VMAD 01000 /* use VM addr print/parse */ -#define REG_FIT 02000 /* fit access to size */ -#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ - -#define REG_V_UF 16 /* device specific */ -#define REG_UFMASK (~((1u << REG_V_UF) - 1)) /* user flags mask */ -#define REG_VMFLAGS (REG_VMIO | REG_UFMASK) /* call VM routine if any of these are set */ -#endif /* DEFINED_IN_SIM_DEFS_H */ - -REG cpu_reg[] = { - {HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT}, - {BRDATAD(PSD, PSD, 16, 32, 2, "Progtam 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(SPAD, SPAD, 16, 32, 256, "CPU Scratchpad memory"), REG_FIT}, - {HRDATAD(CPUSTATUS, CPUSTATUS, 32, "CPU Status"), REG_FIT}, - {HRDATAD(TRAPSTATUS, TRAPSTATUS, 32, "TRAP Status"), REG_FIT}, - {HRDATAD(CC, CC, 16, "Condition Codes"), REG_FIT}, -// {ORDATAD(BASE, baseaddr, 16, "Relocation base"), REG_FIT}, - {NULL} -}; - -/* Modifier table layout (MTAB) - only extended entries have disp, reg, or flags */ -MTAB cpu_mod[] = { - { - /* MTAB table layout for cpu type */ - /* {UNIT_MODEL, MODEL(MODEL_55), "32/55", "32/55", NULL, NULL, NULL, "Concept 32/55"}, */ - UNIT_MODEL, /* uint32 mask */ /* mask */ - MODEL(MODEL_55), /* uint32 match */ /* match */ - "32/55", /* cchar *pstring */ /* print string */ - "32/55", /* cchar *mstring */ /* match string */ - NULL, /* t_stat (*valid) */ /* validation routine */ - NULL, /* t_stat (*disp) */ /* display routine */ - NULL, /* void *desc */ /* value descriptor, REG* if MTAB_VAL, int* if not */ - "Concept 32/55", /* cchar *help */ /* help string */ - }, - {UNIT_MODEL, MODEL(MODEL_75), "32/75", "32/75", NULL, NULL, NULL, "Concept 32/75"}, - {UNIT_MODEL, MODEL(MODEL_27), "32/27", "32/27", NULL, NULL, NULL, "Concept 32/27"}, - {UNIT_MODEL, MODEL(MODEL_67), "32/67", "32/67", NULL, NULL, NULL, "Concept 32/67"}, - {UNIT_MODEL, MODEL(MODEL_87), "32/87", "32/87", NULL, NULL, NULL, "Concept 32/87"}, - {UNIT_MODEL, MODEL(MODEL_97), "32/97", "32/97", NULL, NULL, NULL, "Concept 32/97"}, - {UNIT_MODEL, MODEL(MODEL_V6), "V6", "V6", NULL, NULL, NULL, "Concept V6"}, - {UNIT_MODEL, MODEL(MODEL_V9), "V9", "V9", NULL, NULL, NULL, "Concept V9"}, - { - /* MTAB table layout for cpu memory size */ - /* {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &cpu_set_size}, */ - UNIT_MSIZE, /* uint32 mask */ /* mask */ - MEMAMOUNT(0), /* uint32 match */ /* match */ - "128K", /* cchar *pstring */ /* print string */ - "128K", /* cchar *mstring */ /* match string */ - &cpu_set_size, /* t_stat (*valid) */ /* validation routine */ - NULL, /* t_stat (*disp) */ /* display routine */ - NULL, /* void *desc */ /* value descriptor, REG* if MTAB_VAL, int* if not */ - NULL, /* cchar *help */ /* help string */ - }, - {UNIT_MSIZE, MEMAMOUNT(1), "256K", "256K", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(2), "512K", "512K", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(3), "1M", "1M", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(4), "2M", "2M", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(5), "3M", "3M", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(6), "4M", "4M", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(7), "8M", "8M", &cpu_set_size}, - {UNIT_MSIZE, MEMAMOUNT(8), "16M", "16M", &cpu_set_size}, - {MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist}, - {0} -}; - -/* CPU device descriptpr */ -DEVICE cpu_dev = { - /* "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 24, 1, 8, 32, - &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL, - NULL, DEV_DEBUG, 0, dev_debug, - NULL, NULL, &cpu_help, NULL, NULL, &cpu_description */ - "CPU", /* cchar *name */ /* device name */ - &cpu_unit, /* UNIT *units */ /* unit array */ - cpu_reg, /* REG *registers */ /* register array */ - cpu_mod, /* MTAB *modifiers */ /* modifier array */ - 1, /* uint32 numunits */ /* number of units */ - 16, /* uint32 aradix */ /* address radix */ - 24, /* uint32 awidth */ /* address width */ - 4, /* uint32 aincr */ /* address increment */ - 16, /* uint32 dradix */ /* data radix */ - 32, /* uint32 dwidth */ /* data width */ - &cpu_ex, /* t_stat (*examine) */ /* examine routine */ - &cpu_dep, /* t_stat (*deposit) */ /* deposit routine */ - &cpu_reset, /* t_stat (*reset) */ /* reset routine */ - NULL, /* t_stat (*boot) */ /* boot routine */ - NULL, /* t_stat (*attach) */ /* attach routine */ - NULL, /* t_stat (*detach) */ /* detach routine */ - NULL, /* void *ctxt */ /* (context) device information block pointer */ - DEV_DEBUG, /* uint32 flags */ /* device flags */ - 0, /* uint32 dctrl */ /* debug control flags */ - dev_debug, /* DEBTAB *debflags */ /* debug flag name array */ - NULL, /* t_stat (*msize) */ /* memory size change routine */ - NULL, /* char *lname */ /* logical device name */ - &cpu_help, /* t_stat (*help) */ /* help function */ - NULL, /* t_stat (*attach_help) */ /* attach help function */ - NULL, /* void *help_ctx */ /* Context available to help routines */ - &cpu_description, /* cchar *(*description) */ /* Device description */ - NULL, /* BRKTYPTB *brk_types */ /* Breakpoint types */ -}; - -/* CPU Instruction decode flags */ -#define INV 0x0000 /* Instruction is invalid */ -#define HLF 0x0001 /* Half word instruction */ -#define ADR 0x0002 /* Normal addressing mode */ -#define IMM 0x0004 /* Immediate mode */ -#define WRD 0x0008 /* Word addressing, no index */ -#define SCC 0x0010 /* Sets CC */ -#define RR 0x0020 /* Read source register */ -#define R1 0x0040 /* Read destination register */ -#define RB 0x0080 /* Read base register into dest */ -#define SD 0x0100 /* Stores into destination register */ -#define SDD 0x0200 /* Stores double into destination */ -#define RM 0x0400 /* Reads memory */ -#define SM 0x0800 /* Stores memory */ -#define DBL 0x1000 /* Double word operation */ -#define SB 0x2000 /* Store Base register */ -#define BT 0x4000 /* Branch taken, no PC incr */ - -int nobase_mode[] = { - /* 00 04 08 0C */ - /* 00 ANR, ORR, EOR */ - HLF, SCC|RR|SD|HLF, SCC|RR|SD|HLF, SCC|RR|SD|HLF, - /* 10 14 18 1C */ - /* CAR, CMR, SBR ZBR */ - HLF, HLF, HLF, HLF, - /* 20 24 28 2C */ - /* ABR TBR REG TRR */ - HLF, HLF, HLF, HLF, - /* 30 34 38 3C */ - /* CALM LA ADR SUR */ - HLF, SD|ADR, SCC|SD|HLF, SCC|SD|HLF, - /* 40 44 48 4C */ - /* MPR DVR */ - SD|HLF, SD|HLF, INV, INV, - /* 50 54 58 5C */ - /* */ - INV, INV, INV, INV, - - /* 60 64 68 6C */ - /* NOR NORD SCZ SRA */ - SD|HLF, SDD|HLF, SCC|SD|HLF, SD|HLF, - - /* 70 74 78 7C */ - /* SRL SRC SRAD SRLD */ - SD|HLF, SD|HLF, HLF, HLF, - - /* 80 84 88 8C */ - /* LEAR ANM ORM EOM */ - SD|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR, - - /* 90 94 98 9C */ - /* CAM CMM SBM ZBM */ - SCC|RM|ADR, RM|ADR, ADR, ADR, - - /* A0 A4 A8 AC */ - /* ABM TBM EXM L */ - ADR, ADR, RM|ADR, SCC|SD|RM|ADR, - - /* B0 B4 B8 BC */ - /* LM LN ADM SUM */ - SCC|SD|RM|ADR, SCC|SD|RM|ADR, SCC|SD|RM|ADR, SCC|SD|RM|ADR, - - /* C0 C4 C8 CC */ - /* MPM DVM IMM LF */ - SCC|SD|RM|ADR, SCC|RM|ADR, IMM, ADR, - - /* D0 D4 D8 DC */ - /* LEA ST STM STF */ - SD|ADR, RR|SM|ADR, RR|SM|ADR, ADR, - - /* E0 E4 E8 EC */ - /* ADF MPF ARM BCT */ - SCC|SD|RM|ADR, SCC|RM|ADR, SM|RM|ADR, ADR, - - /* F0 F4 F8 FC */ - /* BCF BI MISC IO */ - ADR, SD|ADR, ADR, IMM, -}; - -int base_mode[] = { - /* 00 04 08 0C */ - /* 00 AND, OR, EOR */ - HLF, SCC|RR|SD|HLF, SCC|RR|SD|HLF, SCC|RR|SD|HLF, - /* 10 14 18 1C */ - /* SACZ CMR xBR SRx */ - HLF, HLF, HLF, HLF, - /* 20 24 28 2C */ - /* SRxD SRC REG TRR */ - SD|HLF, SD|HLF, HLF, HLF, - /* 30 34 38 3C */ - /* LA FLRop SUR */ - INV, INV, SD|HLF, SD|HLF, - /* 40 44 48 4C */ - /* */ - INV, INV, INV, INV, - - /* 50 54 58 5C */ - /* LA BASE BASE CALLM */ - SD|ADR, SM,ADR, SB|RM|ADR, ADR, - - /* 60 64 68 6C */ - /* */ - INV, INV, INV, INV, - /* 70 74 78 7C */ - /* */ - INV, INV, INV, INV, - /* LEAR ANM ORM EOM */ - /* 80 84 88 8C */ - SD|ADR, SD|RM|ADR, SD|RM|ADR, SD|RM|ADR, - - /* CAM CMM SBM ZBM */ - /* 90 94 98 9C */ - RM|ADR, RM|ADR, ADR, ADR, - - /* A0 A4 A8 AC */ - /* ABM TBM EXM L */ - ADR, ADR, RM|ADR, SD|RM|ADR, - - /* B0 B4 B8 BC */ - /* LM LN ADM SUM */ - SD|RM|ADR,SD|RM|ADR, SD|RM|ADR, SD|RM|ADR, - - /* C0 C4 C8 CC */ - /* MPM DVM IMM LF */ - SD|RM|ADR, RM|ADR, IMM, ADR, - - /* D0 D4 D8 DC */ - /* LEA ST STM STFBR */ - SD|ADR, SM|ADR, SM|ADR, ADR, - /* E0 E4 E8 EC */ - /* ADF MPF ARM BCT */ - SD|RM|ADR, RM|ADR, SM|RM|ADR, ADR, - /* F0 F4 F8 FC */ - /* BCF BI MISC IO */ - ADR, RR|SB|WRD, ADR, IMM, -}; - -/* set up the map registers for the current task in the cpu */ -/* the PSD bpix and cpix are used to setup the maps */ -/* return 1 if mapping error */ -t_stat load_maps(uint32 thepsd[2]) -{ - uint32 num, sdc, spc; - uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl; - uint32 cpix, bpix, i, j, map, osmidl; - - if (CPU_MODEL < MODEL_27) - { - /* 32/7x machine, 8KW maps */ - modes &= ~BASE; /* no basemode on 7x */ - if (thepsd[1] & 0xc0000000) /* mapped mode? */ - modes |= MAP; /* show as mapped */ - else { - modes &= ~MAP; /* show as unmapped */ - return ALLOK; /* all OK, no mapping required */ - } - /* we are mapped, so load the maps for this task into the cpu map cache */ - cpix = (thepsd[1] >> 2) & 0xfff; /* get cpix 12 bit offset from psd wd 2 */ - bpix = (thepsd[1] >> 18) & 0xfff; /* get bpix 12 bit offset from psd wd 2 */ - num = 0; /* working map number */ - /* master process list is in 0x83 of spad for 7x */ - mpl = SPAD[0x83] >> 2; /* get mpl from spad address */ - cpixmsdl = M[mpl + cpix]; /* get msdl from mpl for given cpix */ - /* if bit zero of mpl entry is set, use bpix first to load maps */ - if (cpixmsdl & BIT0) - { - /* load bpix maps first */ - bpixmsdl = M[mpl + bpix]; /* get bpix msdl word address */ - sdc = (bpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */ - msdl = (bpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */ - for (i = 0; i < sdc; i++) /* loop through the msd's */ - { - spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */ - midl = (M[msdl + i] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */ - for (j = 0; j < spc; j++) - { - /* load 16 bit map descriptors */ - map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ - if (j & 1) - map = (map & RMASK); /* use right half word map entry */ - else - map = ((map >> 16) & RMASK); /* use left half word map entry */ - /* the map register contents is now in right 16 bits */ - /* now load a 32 bit word with both maps from memory */ - /* and or in the new map entry data */ - if (num & 1) { - /* entry going to rt hw, clean it first */ - map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ - } - else { - /* entry going to left hw, clean it first */ - map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ - } - MAPC[num++/2] = map; /* store the map reg contents into cache */ - if (num >= 32) - return MAPFLT; /* map loading overflow, map fault error */ - } - } - } - /* now load cpix maps */ - cpixmsdl = M[mpl + cpix]; /* get cpix msdl word address */ - sdc = (cpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */ - msdl = (cpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */ - for (i = 0; i < sdc; i++) - { - spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */ - midl = (M[msdl + i] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */ - for (j = 0; j < spc; j++) - { - /* load 16 bit map descriptors */ - map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ - if (j & 1) - map = (map & RMASK); /* use right half word map entry */ - else - map = ((map >> 16) & RMASK); /* use left half word map entry */ - /* the map register contents is now in right 16 bits */ - /* now load a 32 bit word with both maps from memory */ - /* and or in the new map entry data */ - if (num & 1) { - /* entry going to rt hw, clean it first */ - map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ - } - else { - /* entry going to left hw, clean it first */ - map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ - } - MAPC[num++/2] = map; /* store the map reg contents into cache */ - if (num >= 32) - return MAPFLT; /* map loading overflow, map fault error */ - } - } - /* if none loaded, map fault */ - if (num == 0) - return MAPFLT; /* map fault error */ - if (num & 1) { /* clear rest of maps */ - /* left hw of map is good, zero right */ - map = (MAPC[num/2] & LMASK); /* clean rt hw */ - MAPC[num++/2] = map; /* store the map reg contents into cache */ - } - /* num should be even at this point, so zero 32 bit word for remaining maps */ - for (i = num/2; i < 32/2; i++) /* zero any remaining entries */ - MAPC[i] = 0; /* clear the map entry to make not valid */ - return ALLOK; /* all cache is loaded, return OK */ - } - else - { - /* 32/27, 32/67, 32/87, 32/97 2KW maps */ - /* Concept/32 machine, 2KW maps */ - if (thepsd[0] & BASEBIT) /* bit 6 is base mode? */ - modes |= BASE; /* show as basemode */ - else - modes &= ~BASE; /* show as non basemode */ - if (thepsd[1] & MAPBIT) /* mapped mode? */ - modes |= MAP; /* show as mapped */ - else { - modes &= ~MAP; /* show as unmapped */ - return ALLOK; /* all OK, no mapping required */ - } - /* we are mapped, so calculate real address from map information */ -// cpix = (thepsd[1] >> 3) & 0x7ff; /* get double word cpix 11 bit offset from psd wd 2 */ - cpix = (thepsd[1] >> 2) & 0xfff; /* get word cpix 11 bit offset from psd wd 2 */ - num = 0; /* no maps loaded yet */ - /* master process list is in 0xf3 of spad for concept */ - mpl = SPAD[0xf3] >> 2; /* get mpl from spad address */ - midl = M[mpl + cpix]; /* get mpl entry wd 0 for given cpix */ - /* if bit zero of mpl entry is set, use msd entry 0 first to load maps */ - if (midl & BIT0) - { - /* load msd 0 maps first (O/S) */ - osmidl = M[mpl]; /* get midl 0 word address */ - spc = osmidl & MASK16; /* get 16 bit segment description count */ - midl = M[mpl] & MASK24; /* get 24 bit real address from mpl wd2 */ - for (j = 0; j < spc; j++) - { - /* load 16 bit map descriptors */ - map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ - if (j & 1) - map = (map & RMASK); /* use right half word map entry */ - else - map = ((map >> 16) & RMASK); /* use left half word map entry */ - /* the map register contents is now in right 16 bits */ - /* now load a 32 bit word with both maps from memory */ - /* and or in the new map entry data */ - if (num & 1) { - /* entry going to rt hw, clean it first */ - map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ - } - else { - /* entry going to left hw, clean it first */ - map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ - } - MAPC[num++/2] = map; /* store the map reg contents into cache */ - if (num >= 2048) - return MAPFLT; /* map loading overflow, map fault error */ - } - } - /* now load cpix maps */ - msdl = M[mpl + cpix]; /* get cpix msdl word address */ - spc = M[msdl] & RMASK; /* get segment page count from msdl */ - midl = (M[msdl + 1] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */ - for (j = 0; j < spc; j++) - { - /* load 16 bit map descriptors */ - map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ - if (j & 1) - map = (map & RMASK); /* use right half word map entry */ - else - map = ((map >> 16) & RMASK); /* use left half word map entry */ - /* the map register contents is now in right 16 bits */ - /* now load a 32 bit word with both maps from memory */ - /* and or in the new map entry data */ - if (num & 1) { - /* entry going to rt hw, clean it first */ - map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ - } - else { - /* entry going to left hw, clean it first */ - map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ - } - MAPC[num++/2] = map; /* store the map reg contents into cache */ - if (num >= 2048) - return MAPFLT; /* map loading overflow, map fault error */ - } - /* if none loaded, map fault */ - /* we got here without map block found, return map fault error */ - if (num == 0) - return MAPFLT; /* map fault error */ - if (num & 1) { - /* left hw of map is good, zero right */ - map = (MAPC[num/2] & LMASK); /* clean rt hw */ - MAPC[num++/2] = map; /* store the map reg contents into cache */ - } - /* num should be even at this point, so zero 32 bit words for remaining maps */ - for (i = num/2; i < 2048/2; i++) /* zero any remaining entries */ - MAPC[i] = 0; /* clear the map entry to make not valid */ - return ALLOK; /* all cache is loaded, retun OK */ - } -} - -/* - * Return the real memory address from the logical address - * Also return the protection status, 1 if write protected address - */ -t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot) -{ - uint32 word, mem, index, map, mask; - - *prot = 0; /* show unprotected memory as default */ - /* unmapped mode is unprotected */ - - /* see what machine we have */ - if (CPU_MODEL < MODEL_27) - { - /* 32/7x machine with 8KW maps */ - if (modes & EXTD) - word = addr & 0xffffc; /* get 20 bit logical word address */ - else - word = addr & 0x7fffc; /* get 19 bit logical word address */ - if ((modes & MAP) == 0) - { - /* check if valid real address */ - if (word >= MEMSIZE) /* see if address is within our memory */ - return NPMEM; /* no, none present memory error */ - *realaddr = word; /* return the real address */ - return ALLOK; /* all OK, return instruction */ - } - /* we are mapped, so calculate real address from map information */ - /* 32/7x machine, 8KW maps */ - index = word >> 15; /* get 4 or 5 bit value */ - map = MAPC[index/2]; /* get two hw map entries */ - if (index & 1) - /* entry is in rt hw, clear left hw */ - map &= RMASK; /* map is in rt hw */ - else - /* entry is in left hw, move to rt hw */ - map >>= 16; /* map is in left hw */ - /* see if map is valid */ - if (map & 0x4000) - { - /* required map is valid, get 9 bit address and merge with 15 bit page offset */ - word = ((map & 0x1ff) << 15) | (word & 0x7fff); - /* check if valid real address */ - if (word >= MEMSIZE) /* see if address is within our memory */ - return NPMEM; /* no, none present memory error */ - if ((modes & PRIV) == 0) /* see if we are in unprivileged mode */ - { - if (map & 0x2000) /* check if protect bit is set in map entry */ - *prot = 1; /* return memory write protection status */ - } - *realaddr = word; /* return the real address */ - return ALLOK; /* all OK, return instruction */ - } - /* map is invalid, so return map fault error */ - return MAPFLT; /* map fault error */ - } - else - { - /* 32/27, 32/67, 32/87, 32/97 2KW maps */ - /* Concept 32 machine, 2KW maps */ - if (modes & (BASE | EXTD)) - word = addr & 0xfffffc; /* get 24 bit address */ - else - word = addr & 0x7fffc; /* get 19 bit address */ - if ((modes & MAP) == 0) - { - /* check if valid real address */ - if (word >= MEMSIZE) /* see if address is within our memory */ - return NPMEM; /* no, none present memory error */ - *realaddr = word; /* return the real address */ - return ALLOK; /* all OK, return instruction */ - } - /* replace bits 8-18 with 11 bits from memory map register */ - /* we are mapped, so calculate real address from map information */ - index = word >> 11; /* get 11 bit value */ - map = MAPC[index/2]; /* get two hw map entries */ - if (index & 1) - /* entry is in rt hw, clear left hw */ - map &= RMASK; /* map is in rt hw */ - else - /* entry is in left hw, move to rt hw */ - map >>= 16; /* map is in left hw */ - if (map & 0x8000) /* see if map is valid */ - { - /* required map is valid, get 11 bit address and merge with 13 bit page offset */ - word = ((map & 0x7ff) << 15) | (word & 0x1fff); - /* check if valid real address */ - if (word >= MEMSIZE) /* see if address is within our memory */ - return NPMEM; /* no, none present memory error */ - if ((modes & PRIV) == 0) /* see if we are in unprivileged mode */ - { - mask = (word & 0x1800) >> 11; /* get offset of 2kb block for map being addressed */ - if (map & (0x4000 >> mask)) /* check if protect bit is set in map entry */ - *prot = 1; /* return memory write protection status */ - } - *realaddr = word; /* return the real address */ - return ALLOK; /* all OK, return instruction */ - } - /* map is invalid, so return map fault error */ - return MAPFLT; /* map fault error */ - } -} - -/* fetch the current instruction from the PC address */ -/* also sets the privileged, extended, basemode, and mapped flags */ -/* also set status of AEXP bit in modes flags */ -t_stat read_instruction(uint32 thepsd[2], uint32 *instr) -{ - uint32 addr, status; - - modes &= (~(PRIV|EXTD|BASE|MAP|AEXP)); /* clear the mode flags */ - if (thepsd[0] & PRIVBIT) /* bit 0 privileged? */ - modes |= PRIV; - if (thepsd[0] & EXTDBIT) /* bit 5 extended mode? */ - modes |= EXTD; - if (thepsd[0] & AEXPBIT) /* bit 7 arithmetic exception enabled? */ - modes |= AEXP; - - if (CPU_MODEL < MODEL_27) - { - /* 32/7x machine with 8KW maps */ - if (thepsd[1] & 0xc0000000) /* mapped mode? */ - modes |= MAP; /* show as mapped */ - /* instruction must be in first 512KB of address space */ - addr = thepsd[0] & 0x7fffc; /* get 19 bit logical word address */ - } - else - { - /* 32/27, 32/67, 32/87, 32/97 2KW maps */ - /* Concept 32 machine, 2KW maps */ - if (thepsd[0] & BASEBIT) { /* bit 6 is base mode? */ - modes |= BASE; /* show as base mode */ - addr = thepsd[0] & 0xfffffc; /* get 24 bit address */ - } - else - addr = thepsd[0] & 0x7fffc; /* get 19 bit address */ - if (thepsd[1] & MAPBIT) /* mapped mode? */ - modes |= MAP; /* show as mapped */ - } - status = Mem_read(addr, instr); /* get the instruction at the specified address */ - return status; /* return ALLOK or ERROR */ -} - -/* - * Read a full word from memory - * Return error type if failure, ALLOK if - * success. Addr is logical address. - */ -t_stat Mem_read(uint32 addr, uint32 *data) -{ - uint32 status, realaddr, prot; - - status = RealAddr(addr, &realaddr, &prot); /* convert address to real physical address */ - if (status == ALLOK) { - *data = M[realaddr >> 2]; /* valid address, get physical address contents */ - status = ALLOK; /* good status return */ - } - return status; /* return ALLOK or ERROR */ -} - -/* - * Write a full word to memory, checking protection - * and alignment restrictions. Return 1 if failure, 0 if - * success. Addr is logical address, data is 32bit word - */ -t_stat Mem_write(uint32 addr, uint32 *data) -{ - uint32 status, realaddr, prot; - - status = RealAddr(addr, &realaddr, &prot); /* convert address to real physical address */ -//fprintf(stderr, "Mem_write addr %0.8x, realaddr %0.8x data %0.8x prot %d\r\n", addr, realaddr, *data, prot); - if (status == ALLOK) { - if (prot) /* check for write protected memory */ - return MPVIOL; /* return memory protection violation */ - M[realaddr >> 2] = *data; /* valid address, put physical address contents */ - status = ALLOK; /* good status return */ - } - return status; /* return ALLOK or ERROR */ -} - -/* function to set the CCs in PSD1 */ -/* ovr is setting for CC1 */ -void set_CCs(uint32 value, int ovr) -{ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - if (ovr) - CC = CC1; /* CC1 value */ - else - CC = 0; /* CC1 off */ - if (value & FSIGN) - CC |= CC3; /* CC3 for neg */ - else if (value == 0) - CC |= CC4; /* CC4 for zero */ - else - CC |= CC2; /* CC2 for greater than zero */ -//fprintf(stderr, "set_CC value %0.8x CC %0.2x PSD1 %0.8x\r\n", value, CC, PSD1); - PSD1 |= ((CC & 0x78)<<24); /* update the CC's in the PSD */ -} - -/* FIXME - How to wait? */ -/* Opcode definitions */ -/* called from simulator */ -t_stat -sim_instr(void) -{ - t_stat reason = 0; /* reason for stopping */ - t_uint64 dest; /* Holds destination/source register */ - t_uint64 source; /* Holds source or memory data */ - uint32 addr; /* Holds address of last access */ - uint32 temp; /* General holding place for stuff */ - uint32 IR; /* Instruction register */ - uint32 i_flags; /* Instruction description flags from table */ - uint32 t; /* Temporary */ - uint32 bc; /* Temporary bit count */ - uint16 opr; /* Top half of Instruction register */ - uint16 OP; /* Six bit instruction opcode */ - uint16 chan; /* I/O channel address */ - uint16 suba; /* I/O subaddress */ - uint8 FC; /* Current F&C bits */ - int reg; /* GPR or Base register */ - int sreg; /* Source reg in from bits 9-11 reg-reg instructions */ - int ix; /* index register */ - int dbl; /* Double word */ - int ovr; /* Overflow flag */ - int stopnext = 0; /* Stop on next instruction */ - uint32 int_icb; /* interrupt context block address */ - -#if 0 - /* Enable timer if option set */ - if (cpu_unit.flags & FEAT_TIMER) { - sim_activate(&cpu_unit, 100); - } - interval_irq = 0; -#endif - - while (reason == 0) { /* loop until halted */ - - if (sim_interval <= 0) { /* event queue? */ - reason = sim_process_event(); - if (reason != SCPE_OK) { - if (reason == SCPE_STEP && iowait) - stopnext = 1; - else - break; /* process */ - } - } - - /* process pending I/O interrupts */ - if ((CPUSTATUS & 0x80) == 0) { /* see if ints are blocked */ - int_icb = scan_chan(); /* go scan for I/O int pending */ - if (int_icb != 0) { /* see if an ICB was returned for the interrupt */ -fprintf(stderr, "scan return icb %x\r\n", int_icb); - if (loading) { /* if loading, we are done */ - /* start execution at location 0 */ - /* set PC to start at loc 0 with interrupts blocked and privleged */ - PSD1 = 0x80000000; /* privileged, non mapped, non extended, address 0 */ - PSD2 = 0x00004000; /* blocked interrupts mode */ - loading = 0; /* not loading anymore */ - } else { - /* take interrupt, store the PSD, fetch new PSD */ - M[int_icb>>2] = PSD1; /* store PSD 1 */ - M[(int_icb>>2)+1] = PSD2; /* store PSD 2 */ - PSD1 = M[(int_icb>>2)+2]; /* get new PSD 1 */ - PSD2 = M[(int_icb>>2)+3]; /* get new PSD 2 */ - } - /* I/O status DW address will be in WD 6 */ - /* set new map mode and interrupt blocking state in CPUSTATUS */ - if (PSD2 & MAPBIT) - CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ - else - CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */ - if ((PSD2 & 0xc000) == 0) /* get int requested status */ - CPUSTATUS &= ~0x80; /* reset blk state in cpu status bit 24 */ - else if ((PSD2 & 0xc000) != 0) /* is it block int */ - CPUSTATUS |= 0x80; /* set state in cpu status bit 24 too */ - iowait = 0; - } - } - - if (iowait == 0 && sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) { - reason = STOP_IBKPT; - break; - } - - /* fill IR from logical memory address */ - if (TRAPME = read_instruction(PSD, &IR)) { - goto newpsd; /* Fault on instruction read */ - } - - /* If executing right half */ - if (PSD1 & 2) - IR <<= 16; -exec: -//fprintf(stderr, "start @ PSD %0.8x IR %0.8x\r\n", PSD1, IR); - /* TODO Update history for this instruction */ - if(hst_lnt) - { -//fprintf(stderr, "history is on at start\r\n"); - hst_p += 1; /* next history location */ - if (hst_p >= hst_lnt) /* check for wrap */ - hst_p = 0; /* start over at beginning */ - hst[hst_p].psd1 = PSD1; /* set execution address */ - hst[hst_p].psd2 = PSD2; /* set mapping/blocking status */ - } - - /* Split instruction into pieces */ - opr = (IR >> 16) & MASK16; /* use upper half of instruction */ - OP = (opr >> 8) & 0xFC; /* Get opcode (bits 0-5) left justified */ - FC = ((IR & F_BIT) ? 0x4 : 0) | (IR & 3); /* get F & C bits for addressing */ - reg = (opr >> 7) & 0x7; /* dest reg or xr on base mode */ - sreg = (opr >> 4) & 0x7; /* src reg for reg-reg instructions or BR instr */ - dbl = 0; /* no doubleword instruction */ - ovr = 0; /* no overflow or arithmetic exception either */ - PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ - dest = (t_uint64)IR; /* assume memory address specified */ - CC = (PSD1 >> 24) & 0x78; /* save CC's if any */ - - if (modes & BASE) { - i_flags = base_mode[OP>>2]; /* set the instruction processing flags */ - addr = IR & RMASK; /* get address offset from instruction */ - switch(i_flags & 0xf) { - case HLF: - source = GPR[sreg]; /* get the src reg from instruction */ - break; - case IMM: - if (PC & 02) { /* if pc is on HW boundry, bad address */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - break; - case ADR: - case WRD: - if (PC & 02) { /* if pc is on HW boundry, bad address */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - ix = (IR >> 20) & 7; /* get index reg from instruction */ - if (ix != 0) - addr += GPR[ix]; /* if not zero, add in reg contents */ - ix = (IR >> 16) & 7; /* get base reg from instruction */ - if (ix != 0) - addr += BR[ix]; /* if not zero, add to base reg contents */ - FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */ - FC |= addr & 3; /* set new C bits to address from orig or regs */ - break; - case INV: - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - break; - } - } else { - i_flags = nobase_mode[OP>>2]; /* set the instruction processing flags */ - addr = IR & 0x7fffc; /* get 19 bit address from instruction */ - - /* non base mode instructions have bit 0 of the instruction set */ - /* for word length instructions and zero for halfword instructions */ - /* the LA (op=0x34) is the only exception. So test for PC on a halfword */ - /* address and trap if word opcode is in right hw */ - if (PC & 02) { /* if pc is on HW boundry, addr trap if bit zero set */ - if ((OP == 0x34) || (OP & 0x8000)) { - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - } - switch(i_flags & 0xf) { - case HLF: /* halfword instruction */ - source = GPR[sreg]; /* get the src reg contents */ - break; - - case IMM: /* Immediate mode */ - if (PC & 02) { /* if pc is on HW boundry, bad address */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - break; - - case ADR: /* Normal addressing mode */ - ix = (IR >> 21) & 3; /* get the index reg if specified */ - if (ix != 0) - addr += GPR[ix]; /* if not zero, add in reg contents */ - - /* wort alert! */ - /* the lea instruction requires special handling for indirection. */ - /* defer processing until the lea (op = 0xD0) is handled later */ - - if (OP == 0xD0) /* test for lea op */ - break; /* skip indirection */ - /* fall through */ - - case WRD: /* Word addressing, no index */ - t = IR; /* get current IR */ - while (t & IND) { /* process indirection */ - if (TRAPME = Mem_read(addr, &temp)) /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - if (modes & EXTD) { /* check if in extended mode */ - /* extended mode, so location has 24 bit addr, not X,I ADDR */ - addr = temp & MASK24; /* get 24 bit addr */ - /* if no C bits set, use original, else new */ - if ((IR & F_BIT) || (addr & 3)) - FC = ((IR & F_BIT) ? 0x4 : 0) | (addr & 3); - CC = (temp >> 24) & 0x78; /* save CC's from the last indirect word */ - t &= ~IND; /* turn off IND bit to stop while loop */ - } else { - /* non-extended mode, process new X, I, ADDR fields */ - addr = temp & MASK19; /* get just the addr */ - ix = (temp >> 21) & 3; /* get the index reg from indirect word */ - if (ix != 0) - addr += GPR[ix] & MASK19; /* add the register to the address */ - /* if no F or C bits set, use original, else new */ - if ((temp & F_BIT) || (addr & 3)) - FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3); - CC = (temp >> 24) & 0x78; /* save CC's from the last indirect word */ - t = temp; /* go process next indirect location */ - } - dest = (t_uint64)addr; /* make into 64 bit variable */ - } - break; - case INV: /* Invalid instruction */ - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - break; - } - } - - /* Read memory operand */ - if (i_flags & RM) { - if (TRAPME = Mem_read(addr, &temp)) { /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - } - source = (t_uint64)temp; /* make into 64 bit value */ - switch(FC) { - case 0: /* word address, just continue */ - break; - case 1: /* left hw */ - source >>= 16; /* move left hw to right hw*/ - /* Fall through */ - case 3: /* right hw or right shifted left hw */ - if (source & 0x8000) { /* check sign of 16 bit value */ - /* sign extend the value to leftmost 48 bits */ - source = 0xFFFF0000 | (source & 0xFFFF); /* extend low 32 bits */ - source |= (((t_uint64)0xFFFFFFFF) << 32) | source; /* extend hi bits */ - } - break; - case 2: /* double word address */ - if ((addr & 7) != 0) { /* must be double word adddress */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - if (TRAPME = Mem_read(addr+4, &temp)) { /* get the 2nd word from memory */ - goto newpsd; /* memory read error or map fault */ - } - source |= ((t_uint64)temp) << 32; /* merge in the low order 32 bits */ - source = (source << 32) | (0xFFFFFFFF & (t_uint64)temp); - dbl = 1; /* double word instruction */ - break; - case 4: /* byte mode, byte 0 */ - case 5: /* byte mode, byte 1 */ - case 6: /* byte mode, byte 2 */ - case 7: /* byte mode, byte 3 */ - source >>= 8 * (7 - FC); /* right justify addressed byte */ - break; - } - } - - /* Read in if from register */ - if (i_flags & RR) { - dest = (t_uint64)GPR[reg]; /* get the register content */ - if (dbl) { /* is it double regs */ - if (reg & 1) { /* check for odd reg load */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - /* merge the regs into the 64bit value */ - dest = (dest << 32) | ((t_uint64)GPR[reg+1]); - } else { - /* sign extend the data value */ - dest |= (dest & MSIGN) ? ((t_uint64)MASK32) << 32: 0; - } - } - - /* For Base mode */ - if (i_flags & RB) { - dest = (t_uint64)BR[reg]; /* get base reg contents */ - } - - /* For register instructions */ - if (i_flags & R1) { - source = (t_uint64)GPR[sreg]; - if (dbl) { - if (sreg & 1) { - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - /* merge the regs into the 64bit value */ - source = (source << 32) | ((t_uint64)GPR[reg+1]); - } else { - /* sign extend the data value */ - source |= (source & MSIGN) ? ((t_uint64)MASK32) << 32: 0; - } - } - - /* TODO Update other history information for this instruction */ - if(hst_lnt) - { -//fprintf(stderr, "history is on at place 6\r\n"); - hst[hst_p].inst = IR; /* save the instruction */ - hst[hst_p].dest = dest; /* save the destination */ - hst[hst_p].src = source; /* save the source */ - hst[hst_p].reg = reg; /* save the src/dst reg */ - } - -//fprintf(stderr, "switch op = %x PC %0.6x\r\n", OP, PC); - switch (OP) { -/* - * For op-codes=00,04,08,0c,10,14,28,2c,38,3c,40,44,60,64,68 - */ - /* Reg - Reg instruction Format (16 bit) */ - /* |--------------------------------------| */ - /* |0 1 2 3 4 5|6 7 8 |9 10 11|12 13 14 15| */ - /* | Op Code | DReg | SReg | Aug Code | */ - /* |--------------------------------------| */ - case 0x00: /* HLF - HLF */ /* CPU General operations */ - switch(opr & 0xF) { /* switch on aug code */ - case 0x0: /* HALT */ - if (modes & PRIV == 0) { /* must be privileged to halt */ - TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ - goto newpsd; /* Privlege violation trap */ - } - if (CPUSTATUS & 0x00000100) { /* Priv mode halt must be enabled */ - TRAPME = PRIVHALT_TRAP; /* set the trap to take */ - goto newpsd; /* Privlege mode halt trap */ - } -/*FIXME*/ reason = STOP_HALT; /* do halt for now */ - break; - case 0x1: /* WAIT */ -/* FIXME - How to wait? */ - if (modes & PRIV == 0) { /* must be privileged to wait */ - TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ - goto newpsd; /* Privlege violation trap */ - } -/*FIXME*/ reason = STOP_HALT; /* do halt for now */ - break; - case 0x2: /* NOP */ - break; - case 0x3: /* LCS */ - dest = M[0x780 >> 2]; /* get console switches from memory loc 0x780 */ - set_CCs(dest, 0); /* set the CC's, CC1 = 0 */ - break; - case 0x4: /* ES */ - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - /* reg is reg to extend sign into from reg+1 */ - GPR[reg] = (GPR[reg+1] & FSIGN) ? FMASK : 0; - set_CCs(GPR[reg], 0); /* set CCs, CC2 & CC3 */ - break; - case 0x5: /* RND */ - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - temp = GPR[reg]; /* save the current contents of specified reg */ - if (GPR[reg+1] & FSIGN) { /* if sign of R+1 is set, incr R by 1 */ - temp++; /* incr temp R value */ - if (temp < GPR[reg]) /* if temp R less than R, we have overflow */ - ovr = 1; /* show we have overflow */ - GPR[reg] = temp; /* update the R value */ - } - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - } - break; - case 0x6: /* BEI */ - if (modes & PRIV == 0) { /* must be privileged to BEI */ - TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ - goto newpsd; /* Privlege violation trap */ - } - CPUSTATUS |= 0x80; /* into status word bit 24 too */ - break; - case 0x7: /* UEI */ - if (modes & PRIV == 0) { /* must be privileged to UEI */ - TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ - goto newpsd; /* Privlege violation trap */ - } - CPUSTATUS &= ~0x80; /* into status word bit 24 too */ - break; - case 0x8: /* EAE */ - PSD1 |= AEXPBIT; /* set the enable AEXP flag in PSD */ - CPUSTATUS |= AEXPBIT; /* into status word too */ - break; - case 0x9: /* RDSTS */ - i_flags |= SD; /* make sure we store into reg */ - dest = CPUSTATUS; /* get CPU status word */ - break; - case 0xA: /* SIPU */ /* ignore for now */ - break; - case 0xB: /* INV */ /* RWCS ignore for now */ - case 0xC: /* INV */ /* WWCS ignore for now */ - break; - case 0xD: /* SEA */ - modes |= EXTD; /* set new Extended flag in modes & PSD */ - PSD1 |= EXTDBIT; /* set the enable AEXP flag in PSD */ - CPUSTATUS |= EXTDBIT; /* into status word too */ - break; - case 0xE: /* DAE */ - modes &= AEXP; /* set new extended flag in modes & PSD */ - PSD1 &= ~AEXPBIT; /* disable AEXP flag in PSD */ - CPUSTATUS &= ~AEXPBIT; /* into status word too */ - break; - - case 0xF: /* CEA */ - modes &= ~EXTD; /* disable extended mode in modes and PSD */ - PSD1 &= ~EXTDBIT; /* disable extended mode flag in PSD */ - CPUSTATUS &= ~EXTDBIT; /* into status word too */ - break; - } - break; - case 0x04: /* 0x04 SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */ - switch(opr & 0xF) { - case 0x0: /* ANR */ - dest &= source; /* just an and reg to reg */ - i_flags |= SCC; /* make sure we set CC's for dest value */ - break; - case 0xA: /* CMC */ /* Cache Memory Control - Diag use only */ - /* write reg to cache memory controller */ - break; - case 0x7: /* SMC */ /* Shared Memory Control Not Used */ - /* write reg to shared memory controller */ - break; - case 0xB: /* RPSWT */ /* Read Processor Status Word 2 (PSD2) */ - dest = PSD2; /* get PSD2 for user */ - break; - default: /* INV */ /* everything else is invalid instruction */ - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - break; - } - break; - - case 0x08: /* 0x08 SCC|SD|HLF - */ /* ORR or ORRM */ - dest |= source; /* or the regs into dest reg */ - if (IR & 0x8) /* is this ORRM op? */ - dest &= GPR[4]; /* mask with reg 4 contents */ - break; - - case 0x0C: /* 0x0c SCC|SD|HLF - SCC|SD|HLF */ /* EOR or EORM */ -//fprintf(stderr, "@EOR dest %0.8x source %0.8x\r\n", (uint32)dest, (uint32)source); - dest ^= source; /* exclusive or the regs into dest reg */ - if (IR & 0x8) /* is this EORM op? */ - dest &= GPR[4]; /* mask with reg 4 contents */ -//fprintf(stderr, "@EOR dest %0.8x source %0.8x\r\n", (uint32)dest, (uint32)source); - break; - - case 0x10: /* 0x10 HLF - HLF */ /* CAR or (basemode SACZ ) */ - if (modes & BASE) { /* handle basemode SACZ instruction */ -sacz: /* non basemode SCZ enters here */ - temp = GPR[reg]; /* get destination reg contents to shift */ - CC = 0; /* zero the CC's */ - t = 0; /* start with zero shift count */ - if (temp != 0) { /* shift non zero values */ - while ((temp & FSIGN) == 0) { /* shift the reg until bit 0 is set */ - temp << 1; /* shift left 1 bit */ - t++; /* increment shift count */ - } - temp << 1; /* shift the sign bit out */ - } else { - CC = CC4; /* set CC4 showing dest is zero & cnt is zero too */ - } - dest = temp; /* set shifted value to be returned */ - GPR[sreg] = t; /* set the shift cnt into the src reg */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= ((CC & 0x78)<<24); /* update the CC's in the PSD */ - } else { - /* handle non basemode CAR instr */ - temp = GPR[reg]; /* get destination reg value */ - temp = GPR[reg] - GPR[sreg]; /* subtract src from destination value */ - temp &= GPR[4]; /* and with mask reg (GPR 4) */ - CC = 0; /* set all CCs zero */ - if (temp == 0) /* if result is zero, set CC4 */ - CC = CC4; /* set CC4 to show result 0 */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= ((CC & 0x78)<<24); /* update the CC's in the PSD */ - } - break; - - case 0x14: /* 0x14 HLF - HLF */ /* CMR compare masked with reg */ - temp = GPR[reg] ^ GPR[sreg]; /* exclusive or src and destination values */ - temp &= GPR[4]; /* and with mask reg (GPR 4) */ - CC = 0; /* set all CCs zero */ - if (temp == 0) /* if result is zero, set CC4 */ - CC = CC4; /* set CC4 to show result 0 */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= ((CC & 0x78)<<24); /* update the CC's in the PSD */ - break; - - case 0x18: /* 0x18 SD|HLF - SD|HLF */ /* SBR, (basemode ZBR, ABR, TBR */ - if (modes & BASE) { /* handle basemode ZBR, ABR, TBR */ - if ((opr & 0xC) == 0x4) /* ZBR instruction */ - goto zbr; /* use nonbase ZBR code */ - if ((opr & 0xC) == 0x8) /* ABR instruction */ - goto abr; /* use nonbase ABR code */ - if ((opr & 0xC) == 0xC) /* TBR instruction */ - goto tbr; /* use nonbase ZBR code */ -inv: - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - - } else { /* handle non basemode SBR */ -sbr: /* handle basemode too */ - /* move the byte field bits 14-15 to bits 27-28 */ - /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = 31 - (((IR >> 13) & 0x18) | reg); /* get # bits to shift left */ - t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ - if (GPR[sreg] & (1 << bc)) /* test the bit in src reg */ - t |= CC1BIT; /* set CC1 to the bit value */ - GPR[sreg] |= (1 << bc); /* set the bit in src reg */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= t; /* update the CC's in the PSD */ - } - break; - - case 0x1C: /* 0x1C SD|HLF - SD|HLF */ /* ZBR (basemode SRA, SRL, SLA, SLL) */ - if (modes & BASE) { /* handle basemode SRA, SRL, SLA, SLL */ - if ((opr & 0x60) == 0x00) /* SRA instruction */ - goto sra; /* use nonbase SRA code */ - if ((opr & 0x60) == 0x20) /* SRL instruction */ - goto srl; /* use nonbase SRL code */ - if ((opr & 0x60) == 0x40) /* SLA instruction */ - goto sla; /* use nonbase SLA code */ - if ((opr & 0x60) == 0x60) /* SLL instruction */ - goto sll; /* use nonbase SLL code */ - } else { /* handle nonbase ZBR */ -zbr: /* handle basemode too */ - /* move the byte field bits 14-15 to bits 27-28 */ - /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = 31 - (((IR >> 13) & 0x18) | reg); /* get # bits to shift left */ - t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ - if (GPR[sreg] & (1 << bc)) /* test the bit in src reg */ - t |= CC1BIT; /* set CC1 to the bit value */ - GPR[sreg] &= ~(1 << bc); /* reset the bit in src reg */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= t; /* update the CC's in the PSD */ - } - break; - - case 0x20: /* 0x20 HLF - HLF */ /* ABR (basemode SRAD, SRLD, SLAD, SLLD) */ - if (modes & BASE) { /* handle basemode SRA, SRL, SLA, SLL */ - if ((opr & 0x60) == 0x00) /* SRAD instruction */ - goto sra; /* use nonbase SRAD code */ - if ((opr & 0x60) == 0x20) /* SRLd instruction */ - goto srl; /* use nonbase SRLD code */ - if ((opr & 0x60) == 0x40) /* SLAD instruction */ - goto sla; /* use nonbase SLAD code */ - if ((opr & 0x60) == 0x60) /* SLLD instruction */ - goto sll; /* use nonbase SLLD code */ - } else { /* handle nonbase mode ABR */ -abr: /* basemode ABR too */ - /* move the byte field bits 14-15 to bits 27-28 */ - /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = 31 - (((IR >> 13) & 0x18) | reg); /* get # bits to shift left */ - temp = GPR[sreg]; /* get reg value to add bit to */ -//fprintf(stderr, "@ABR temp %0.8x addr %0.8x bc %0.8x\r\n", temp, addr, bc); - ovr = (temp & FSIGN) != 0; /* set ovr to status of sign bit 0 */ - temp += (1 << bc); /* add the bit value to the reg */ - ovr ^= (temp & FSIGN) != 0; /* set ovr if sign bit changed */ -//fprintf(stderr, "@ABR temp %0.8x addr %0.8x bc %0.8x\r\n", temp, addr, bc); - GPR[sreg] = temp; /* save the new value */ - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - } - } - break; - - case 0x24: /* 0x24 HLF - SD|HLF */ /* TBR (basemode SRC) */ - if (modes & BASE) { /* handle SRC basemode */ - if ((opr & 0x60) == 0x00) /* SRC instruction */ - goto src; /* use nonbase code */ - if ((opr & 0x60) == 0x40) /* SLC instruction */ - goto slc; /* use nonbase code */ - goto inv; /* else invalid */ - } else { /* handle TBR non basemode */ -tbr: /* handle basemode TBR too */ - /* move the byte field bits 14-15 to bits 27-28 */ - /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = 31 - (((IR >> 13) & 0x18) | reg); /* get # bits to shift left */ - t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ - if (GPR[sreg] & (1 << bc)) /* test the bit in src reg */ - t |= CC1BIT; /* set CC1 to the bit value */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= t; /* update the CC's in the PSD */ - } - break; - - case 0x28: /* 0x28 HLF - HLF */ /* Misc OP REG instructions */ - temp = GPR[reg]; /* get reg value */ - switch(opr & 0xF) { - - case 0x0: /* TRSW */ - if (modes & BASE) - addr = temp & MASK24; /* 24 bits for based mode */ - else - addr = temp & 0x7FFFC; /* 19 bits for non based mode */ - /* we are returning to the addr in reg, set CC's from reg */ - /* update the PSD with new address */ - PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ - PSD1 = ((PSD1 & 0x87ffffff) | (temp & 0x78000000)); /* insert CCs from reg */ - i_flags |= BT; /* we branched, so no PC update */ - break; - - case 0x2: /* XCBR */ /* Exchange base registers */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - temp = BR[reg]; /* get dest reg value */ - BR[reg] = BR[sreg]; /* put source reg value int dest reg */ - BR[sreg] = temp; /* put dest reg value into src reg */ - break; - - case 0x4: /* TCCR */ /* Transfer condition codes to GPR */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - temp = ((uint32)CC) >> 3; /* right justify CC's in reg */ - break; - - case 0x5: /* TRCC */ /* Transfer condition codes to GPR */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - PSD1 = ((PSD1 & 0x87ffffff) | (GPR[reg] << 27)); /* insert CCs from reg */ - break; - - case 0x8: /* BSUB */ /* Procedure call */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - /* if Rd field is 0 (reg is b6-8), this is a BSUB instruction */ - /* otherwise it is a CALL instruction (Rd != 0) */ - if (reg == 0) { - /* BSUB instruction */ - uint32 *fp = (uint32 *)BR[2]; /* get dword bounded frame pointer from BR2 */ - if ((BR[2] & 0x7) != 0) { - /* Fault, must be dw bounded address */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - fp[0] = PSD1 & 0x01fffffe; /* save AEXP bit and PC into frame */ - fp[0] += 2; /* generate return address */ - fp[1] = 0x80000000; /* show frame created by BSUB instr */ - BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */ - BR[0] = BR[2]; /* set frame pointer from BR 2 into BR 0 */ - BR[1] = BR[sreg]; /* Rs reg to BR 1 */ - PSD1 = (PSD1 & 0xff000000) | (BR[sreg] & 0xffffff); /* New PSD address */ - } else { - /* CALL instruction */ - /* get frame pointer from BR2 - 16 words & make it a dword addr */ - uint32 *cfp = (uint32 *)((BR[2]-0x40) & 0xfffffff8); - cfp[0] = PSD1 & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */ - cfp[0] += 2; /* generate return address */ - cfp[1] = 0x00000000; /* show frame created by CALL instr */ - for (ix=0; ix<8; ix++) - cfp[ix+2] = BR[ix]; /* save BRs 0-7 to call frame */ - for (ix=2; ix<8; ix++) - cfp[ix+10] = GPR[ix]; /* save GPRs 2-7 to call frame */ - BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */ - BR[0] = (uint32)cfp; /* set current frame pointer into BR[0] */ - BR[2] = (uint32)cfp; /* set current frame pointer into BR[2] */ - BR[1] = BR[sreg]; /* Rs reg to BR 1 */ - PSD1 = (PSD1 & 0xff000000) | (BR[sreg] & 0xffffff); /* New PSD address */ - } - break; - - case 0xC: /* TPCBR */ /* Transfer program Counter to Base Register */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - BR[reg] = PSD1 & 0xfffffe; /* save PC from PSD1 into BR */ - break; - - case 0x1: /* INV */ - case 0x3: /* INV */ - case 0x6: /* INV */ - case 0x7: /* INV */ - case 0x9: /* INV */ - case 0xA: /* INV */ - case 0xB: /* INV */ - case 0xD: /* INV */ - case 0xE: /* INV */ - case 0xF: /* INV */ - break; - } - break; - - case 0x2C: /* 0x2C HLF - HLF */ /* Reg-Reg instructions */ - temp = GPR[reg]; /* reg contents specified bye Rd */ - addr = GPR[sreg]; /* reg contents specified by Rs */ - bc = 0; -//fprintf(stderr, "@0x2c temp %0.8x addr %0.8x\r\n", temp, addr); - - switch(opr & 0xF) { - case 0x0: /* TRR */ /* SCC|SD|R1 */ - temp = addr; /* set value to go to GPR[reg] */ - bc = 1; /* set CC's at end */ - break; - - case 0x1: /* TRBR */ /* Transfer GPR to BR */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - BR[reg] = GPR[sreg]; /* copy GPR to BR */ - break; - - case 0x2: /* TBRR */ /* transfer BR to GPR */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - temp = BR[sreg]; /* set base reg value */ - break; - - case 0x3: /* TRC */ /* Transfer register complement */ - temp = addr ^ FMASK; /* complement Rs */ - bc = 1; /* set CC's at end */ - break; - - case 0x4: /* TRN */ /* Transfer register negative */ - temp = -addr; /* negate Rs value */ - if (temp == addr) /* overflow if nothing changed */ - ovr = 1; /* set overflow flag */ - break; - - case 0x5: /* XCR */ /* exchange registers Rd & Rs */ - GPR[sreg] = temp; /* Rs to Rd */ - temp = addr; /* Rd to get Rs value */ - ovr = 0; /* CC1 always zero */ - break; - - case 0x6: /* INV */ - goto inv; - break; - - case 0x7: /* LMAP */ /* Load map reg - Diags only */ - goto inv; - break; - - case 0x8: /* TRRM */ /* SCC|SD|R1 */ - temp = addr & GPR[4]; /* transfer reg-reg masked */ - bc = 1; /* set CC's at end */ - break; - - case 0x9: /* SETCPU */ - break; - - case 0xA: /* TMAPR */ - goto inv; - break; - - case 0xB: /* TRCM */ /* Transfer register complemented masked */ - temp = (addr ^ FMASK) & GPR[4]; /* compliment & mask */ - bc = 1; /* set the CC's */ - break; - - case 0xC: /* TRNM */ /* Transfer register negative masked */ - temp = -addr; /* complement GPR[reg] */ - if (temp == addr) /* checck for overflow */ - ovr = 1; /* overflow */ - temp &= GPR[4]; /* and with negative reg */ - bc = 1; /* set the CC's */ - break; - - case 0xD: /* XCRM */ /* Exchange registers masked */ - addr &= GPR[4]; /* and Rs with mask reg */ - GPR[sreg] = temp & GPR[4]; /* mask Rd and store to Rs */ - temp = addr; /* Rd new value */ - set_CCs(GPR[sreg], ovr); /* set the CC's */ - break; - - case 0xE: /* TRSC */ /* transfer reg to SPAD */ - t = (GPR[reg] >> 16) & 0xff; /* get SPAD address from Rd (6-8) */ - SPAD[t] = GPR[sreg]; /* store Rs into SPAD */ -//fprintf(stderr, "TRSC SPAD %0.8x temp %0.8x\r\n", SPAD[t], temp); - break; - - case 0xF: /* TSCR */ /* Transfer scratchpad to register */ - t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (6-8) */ - temp = SPAD[t]; /* get SPAD data */ -//fprintf(stderr, "TSCR temp %0.8x\r\n", temp); - break; - } - GPR[reg] = temp; /* save the value to Rd reg */ - if (bc) /* set cc's if bc set */ - set_CCs(temp, ovr); /* set the CC's */ - break; - - case 0x30: /* 0x30 */ /* CALM */ - break; - - case 0x34: /* 0x34 */ /* LA non-basemode */ - if (FC & 4) /* see if F bit was set */ - dest = (t_uint64)(addr | 0x01000000); /* set bit 7 of address */ - else - dest = (t_uint64)addr; /* just pure 24 bit address */ - break; - -#ifdef SIMPLE_MODE - case 0x38: /* 0x38 */ /* REG - REG floating point instructions */ - temp = GPR[reg]; - /* t = (IR >> 20) & 7; this is sreg */ - addr = GPR[t]; - switch(opr & 0xF) { - case 0x0: /* ADR */ - t = (temp & FSIGN) != 0; - t |= ((addr & FSIGN) != 0) ? 2 : 0; - temp = temp + addr; - if ((t == 3 && (temp & FSIGN) == 0) || - (t == 0 && (addr & FSIGN) != 0)) - ovr = 1; -// aexp = ovr; /* set arithmetic exception status */ - break; - - case 0x1: /* ADRFW */ - break; - case 0x2: /* MPRBR */ - break; - case 0x3: /* SURFW */ - break; - case 0x4: /* DVRFW */ - break; - case 0x5: /* FIXW */ - break; - case 0x6: /* MPRFW */ - break; - case 0x7: /* FLTW */ - break; - case 0x8: /* ADRM */ - t = (temp & FSIGN) != 0; - t |= ((addr & FSIGN) != 0) ? 2 : 0; - temp = temp + addr; - if ((t == 3 && (temp & FSIGN) == 0) || - (t == 0 && (addr & FSIGN) != 0)) - ovr = 1; -// aexp = ovr; /* set arithmetic exception status */ - temp &= GPR[4]; - break; - case 0x9: /* INV */ - break; - case 0xA: /* DVRBR */ - break; - case 0xB: /* SURFD */ - break; - case 0xC: /* DVRFD */ - break; - case 0xD: /* FIXD */ - break; - case 0xE: /* MPRFD */ - break; - case 0xF: /* FLTD */ - break; - } - GPR[reg] = temp; - if ((opr & 0xF) < 6) { - CC &= AEXP; -// aexp = ovr; /* set arithmetic exception status */ - if (ovr) - CC |= CC1; - else if (temp & FSIGN) - CC |= CC3; - else if (temp == 0) - CC |= CC4; - else - CC |= CC2; - } - break; - - case 0x3C: /* 0x3C */ /* SUR and SURM */ - temp = -GPR[reg]; - t = (IR >> 20) & 7; - addr = GPR[t]; - switch(opr & 0xF) { - case 0x0: /* SUR */ - - t = (temp & FSIGN) != 0; - t |= ((addr & FSIGN) != 0) ? 2 : 0; - temp = temp + addr; - if ((t == 3 && (temp & FSIGN) == 0) || - (t == 0 && (addr & FSIGN) != 0)) - ovr = 1; -// aexp = ovr; /* set arithmetic exception status */ - break; - case 0x8: /* SURM */ - t = (temp & FSIGN) != 0; - t |= ((addr & FSIGN) != 0) ? 2 : 0; - temp = addr + temp; - if ((t == 3 && (temp & FSIGN) == 0) || - (t == 0 && (temp & FSIGN) != 0)) - ovr = 1; -// aexp = ovr; /* set arithmetic exception status */ - temp &= GPR[4]; - break; - case 0x9: /* INV */ - break; - case 0xA: /* DVRBR */ - break; - case 0xB: /* SURFD */ - break; - case 0xC: /* DVRFD */ - break; - case 0xD: /* FIXD */ - break; - case 0xE: /* MPRFD */ - break; - case 0xF: /* FLTD */ - break; - } - GPR[reg] = temp; - if ((opr & 0xF) < 6) { - CC &= AEXP; -// aexp = ovr; /* set arithmetic exception status */ - if (ovr) - CC |= CC1; - else if (temp & FSIGN) - CC |= CC3; - else if (temp == 0) - CC |= CC4; - else - CC |= CC2; - } - break; - case 0x40: /* 0x40 */ /* MPR */ - if (reg & 1) { - /* Spec fault */ - } - temp = GPR[reg]; - t = (IR >> 20) & 7; - addr = GPR[t]; - dest = (uint64)temp | (temp & FSIGN) ? FMASK << 32: 0; - source = (uint64)addr | (addr & FSIGN) ? FMASK << 32: 0; - GPR[reg] = (uint32)(dest & FMASK); - GPR[reg|1] = (uint32)((dest >> 32) & FMASK); - CC &= AEXP; - if (dest & MSIGN) - CC |= CC3; - else if (dest == 0) - CC |= CC4; - else - CC |= CC2; - break; - - case 0x44: /* 0x44 */ /* DVR */ - if (reg & 1) { - /* Spec fault */ - } - t = (IR >> 20) & 7; - source = (uint64)GPR[t]; - source |= (source & FSIGN) ? FMASK << 32: 0; - if (source == 0) { - ovr = 1; -// aexp = ovr; /* set arithmetic exception status */ - break; - } - dest = (uint64)GPR[reg]; - dest |= ((uint64)GPR[reg|1]) << 32; - t = (int64)dest % (int64)source; - dbl = (t < 0); - if ((t ^ (dest & MSIGN)) != 0) /* Fix sign if needed */ - t = -t; - dest = (int64)dest / (int64)source; - if ((dest & LMASK) != 0 && (dest & LMASK) != LMASK) - ovr = 1; - GPR[reg] = (uint32)t; - GPR[reg|1] = (uint32)(dest & FMASK); - CC &= AEXP; -// aexp = ovr; /* set arithmetic exception status */ - if (dest & MSIGN) - CC |= CC3; - else if (dest == 0) - CC |= CC4; - else - CC |= CC2; - break; -#endif /* SIMPLE_MODE*/ - - case 0x48: /* 0x48 INV - INV */ /* unused opcodes */ - case 0x4C: /* 0x4C INV - INV */ /* unused opcodes */ - default: -fprintf(stderr, "place UI op = %0.8x\r\n", IR); - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - break; - - case 0x50: /* 0x50 */ /* (basemode LA) */ - if (modes & (BASE|EXTD)) { - dest = addr; - } else { - dest = addr | ((FC & 4) << 18); - } - break; - - case 0x54: /* 0x54 SM|ADR - INV */ /* (basemode STWBR) */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - if (FC != 0) { /* word address only */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - dest = BR[reg]; /* save the BR to memory */ - break; - - case 0x58: /* 0x58 SB|ADR - INV */ /* (basemode SUABR and LABR) */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - if ((FC & 4) != 0) { /* see if SUABR F=0 */ - dest = BR[reg] - addr; /* subtract addr from the BR and store back to BR */ - } else { /* LABR if F=1 */ - dest = addr; /* addr goes to specified BR */ - } - break; - case 0x5C: /* 0x5C RM|SB|ADR - INV */ /* (basemode LWBR and BSUBM) */ - if ((modes & BASE) == 0) /* see if nonbased */ - goto inv; /* invalid instruction in nonbased mode */ - if (FC != 0) { /* word address only */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if ((FC & 0x4) != 0x4) { /* this is a LWBR instruction */ - BR[reg] = source; /* load memory location in BR */ - } else { /* this is a CALLM/BSUBM instruction */ - /* if Rd field is 0 (reg is b6-8), this is a BSUBM instruction */ - /* otherwise it is a CALLM instruction (Rd != 0) */ - if (reg == 0) { - /* BSUBM instruction */ - uint32 *fp = (uint32 *)BR[2]; /* get dword bounded frame pointer from BR2 */ - if ((BR[2] & 0x7) != 0) { - /* Fault, must be dw bounded address */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - fp[0] = PSD1 & 0x01fffffe; /* save AEXP bit and PC into frame */ - fp[0] += 4; /* generate return address */ - fp[1] = 0x80000000; /* show frame created by BSUB instr */ - BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */ - BR[0] = BR[2]; /* set frame pointer from BR 2 into BR 0 */ - BR[1] = addr & 0xfffffe; /* effective address to BR 1 */ - PSD1 = (PSD1 & 0xff000000) | BR[1]; /* New PSD address */ - } else { - /* CALLM instruction */ - /* get frame pointer from BR2 - 16 words & make it a dword addr */ - uint32 *cfp = (uint32 *)((BR[2]-0x40) & 0xfffffff8); - cfp[0] = PSD1 & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */ - cfp[0] += 4; /* generate return address */ - cfp[1] = 0x00000000; /* show frame created by CALL instr */ - for (ix=0; ix<8; ix++) - cfp[ix+2] = BR[ix]; /* save BRs 0-7 to call frame */ - for (ix=2; ix<8; ix++) - cfp[ix+10] = GPR[ix]; /* save GPRs 2-7 to call frame */ - BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */ - BR[0] = (uint32)cfp; /* set current frame pointer into BR[0] */ - BR[2] = (uint32)cfp; /* set current frame pointer into BR[2] */ - BR[1] = addr & 0xfffffe; /* effective address to BR 1 */ - PSD1 = (PSD1 & 0xff000000) | BR[1]; /* New PSD address */ - } - } - break; - - case 0x60: /* 0x60 SH|HLF - INV */ /* NOR Rd,Rs */ - if ((modes & BASE)) { /* only for nonbased mode */ - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - } - temp = GPR[reg]; /* Rd */ - t = 0; /* no shifts yet */ - /* exponent must not be zero or all 1's */ - if (temp != 0 && temp != FMASK) { - /* non zero value or not all 1's, so normalize */ - uint32 m = temp & 0xF8000000; - /* shift left 4 bits at a time while left most 5 bits are not zero or all 1's */ - while ((m == 0) || (m == 0xF8000000)) { - temp <<= 4; /* move left 4 bits */ - t++; /* increment number times shifted */ - m = temp & 0xF8000000; /* get left most 5 bits again */ - } - /* temp value is now normalized with non zero nor all 1's value */ - GPR[reg] = temp; /* save the normalized value */ - GPR[(IR >> 20) & 7] = 0x40 - t; /* subtract shift count from 0x40 into Rs */ - } else { - GPR[(IR >> 20) & 7] = 0; /* set exponent to zero for zero value */ - } - break; - - case 0x64: /* 0x64 SD|HLF - INV */ /* NORD */ - if ((modes & BASE)) { /* only for nonbased mode */ - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - } - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - addr = GPR[reg]; /* high order 32 bits */ - temp = GPR[reg+1]; /* low order 32 bits */ - t = 0; /* zero shift count */ - if ((temp|addr) != 0 && (temp&addr) != FMASK) { - uint32 m = temp & 0xF8000000; /* upper 5 bit mask */ - /* shift until upper 5 bits are neither 0 or all 1's */ - while ((m == 0) || (m == 0xF8000000)) { - temp <<= 4; /* shift over 4 bits at a time */ - m = temp & 0xF8000000; /* upper 5 bits */ - temp |= (addr >> 28) & 0xf; /* copy in upper 4 bits from R+1 */ - addr <<= 4; /* shift 4 bits of zero int R+1 */ - t++; /* bump shift count */ - } - GPR[reg] = addr; /* save the new values */ - GPR[reg|1] = temp; - } - if (t != 0) - t = 0x40 - t; /* set the shift cnt */ - GPR[(IR >> 20) & 7] = t; /* put 0x40 - shift count or 0 into RS */ - break; - - case 0x68: /* 0x68 SCC|SD|HLF - INV */ /* non basemode SCZ */ - if ((modes & BASE) == 0) - goto inv; /* invalid instruction */ - goto sacz; /* use basemode sacz instruction */ - - case 0x6C: /* 0x6C SD|HLF - INV */ /* non basemode SRA & SLA */ - if ((modes & BASE) == 0) - goto inv; /* invalid instruction */ -sra: -sla: - bc = opr & 0x1f; /* get bit shift count */ - temp = GPR[reg]; /* get reg value to shift */ - t = GPR[reg] & FSIGN; /* sign value */ - if (opr & 0x0040) { /* is this SLA */ - ovr = 0; /* set ovr off */ - for (ix=0; ix>= 1; /* shift bit 0 right one bit */ - temp |= t; /* restore original sign bit */ - } - GPR[reg] = temp; /* save the new value */ - } - break; - - case 0x70: /* 0x70 SD|HLF - INV */ /* non-basemode SRL & SLL */ - if (modes & BASE) - goto inv; /* invalid instruction in basemode */ -sll: -srl: - bc = opr & 0x1f; /* get bit shift count */ - temp = GPR[reg]; /* get reg value to shift */ -//fprintf(stderr, "before SLL/SRL dest %0.8x cnt %d\r\n", temp, bc); - if (opr & 0x0040) /* is this SLL, bit 9 set */ - temp <<= bc; /* shift left #bits */ - else - temp >>= bc; /* shift right #bits */ - dest = temp; /* value to be output */ -//fprintf(stderr, "SLL/SRL dest %0.8x cnt %d\r\n", (uint32)dest, bc); - break; - - case 0x74: /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */ - if (modes & BASE) - goto inv; /* invalid instruction in basemode */ -slc: -src: - bc = opr & 0x1f; /* get bit shift count */ - temp = GPR[reg]; /* get reg value to shift */ - if (opr & 0x0040) { /* is this SLC, bit 9 set */ - for (ix=0; ix> 1; /* shift the bit out */ - if (t) - temp |= BIT0; /* put in new sign bit */ - } - } - dest = temp; /* shift result */ - break; - -/*TODO*/ - case 0x78: /* 0x78 HLF - INV */ /* non-basemode SRAD & SLAD */ - if (modes & BASE) - goto inv; /* invalid instruction in basemode */ - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - bc = opr & 0x1f; /* get bit shift count */ - dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ - dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - source = dest & DMSIGN; /* 64 bit sign value */ - if (opr & 0x0040) { /* is this SLAD */ - ovr = 0; /* set ovr off */ - for (ix=0; ix>32) & FMASK);/* save the hi order reg */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - if (ovr) - PSD1 |= BIT1; /* CC1 in PSD */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - } - } else { /* this is a SRAD */ - for (ix=0; ix>= 1; /* shift bit 0 right one bit */ - dest |= source; /* restore original sign bit */ - } - GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ - GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ - } - break; - - case 0x7C: /* 0x7C SDD|HLF - INV */ /* non-basemode SRLD & SLLD */ - if (modes & BASE) - goto inv; /* invalid instruction in basemode */ - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ - dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - bc = opr & 0x1f; /* get bit shift count */ - if (opr & 0x0040) /* is this SLL, bit 9 set */ - dest <<= bc; /* shift left #bits */ - else - dest >>= bc; /* shift right #bits */ - GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ - GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ - break; - - case 0x80: /* 0x80 SD|ADR - SD|ADR */ /* LEAR */ - /* convert address to real physical address */ - TRAPME = RealAddr(addr, &temp, &t); - if (TRAPME != ALLOK) - goto newpsd; /* memory read error or map fault */ - if (FC & 4) /* see if F bit was set */ - temp |= 0x01000000; /* set bit 7 of address */ - dest = temp; /* put in dest to go out */ - break; - - case 0x84: /* 0x84 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ANMx */ -//fprintf(stderr, "before ANM? dest %0.8x source %0.8x\r\n", (uint32)dest, (uint32)source); - dest &= source; -//fprintf(stderr, "after ANM? dest %0.8x source %0.8x\r\n", (uint32)dest, (uint32)source); - break; - - case 0x88: /* 0x88 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ORMx */ - dest |= source; - break; - - case 0x8C: /* 0x8C SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* EOMx */ - dest ^= source; - break; - - case 0x90: /* 0x90 SCC|RM|ADR - RM|ADR */ /* CAMx */ - dest -= source; - break; - - case 0x94: /* 0x94 RM|ADR - RM|ADR */ /* CMMx */ - dest ^= source; - CC = 0; - if (dest == 0) - CC |= CC4; - break; - - case 0x98: /* 0x98 ADR - ADR */ /* SBM */ - if ((FC & 04) == 0) { - /* Fault, f-bit must be set for SBM instruction */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (TRAPME = Mem_read(addr, &temp)) /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - /* use C bits and bits 6-8 (reg) to generate shift bit count */ - bc = 31 - (((FC & 3) << 3) | reg); /* get # bits to shift left */ - t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ -//fprintf(stderr, "SBM bc %0.8x addr %0.8x CC %0.2x PSD1 %0.8x temp %0.8x\r\n", bc, addr, CC, PSD1, temp); - if (temp & (1 << bc)) /* test the bit in memory */ - t |= CC1BIT; /* set CC1 to the bit value */ - temp |= (1 << bc); /* set the bit in temp */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= t; /* update the CC's in the PSD */ -//fprintf(stderr, "SBM bc %0.8x addr %0.8x CC %0.2x PSD1 %0.8x temp %0.8x\r\n", bc, addr, CC, PSD1, temp); - if (TRAPME = Mem_write(addr, &temp)) /* put word into memory */ - goto newpsd; /* memory write error or map fault */ - break; - - case 0x9C: /* 0x9C ADR - ADR */ /* ZBM */ - if ((FC & 04) == 0) { - /* Fault, byte address not allowed */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (TRAPME = Mem_read(addr, &temp)) /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - /* use C bits and bits 6-8 (reg) to generate shift bit count */ - bc = 31 - (((FC & 3) << 3) | reg); /* get # bits to shift left */ - t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ - if (temp & (1 << bc)) /* test the bit in memory */ - t |= CC1BIT; /* set CC1 to the bit value */ - temp &= ~(1 << bc); /* reset the bit in temp */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= t; /* update the CC's in the PSD */ - if (TRAPME = Mem_write(addr, &temp)) /* put word into memory */ - goto newpsd; /* memory write error or map fault */ - break; - - case 0xA0: /* 0xA0 ADR - ADR */ /* ABM */ - if ((FC & 04) == 0) { - /* Fault, byte address not allowed */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (TRAPME = Mem_read(addr, &temp)) /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - /* use C bits and bits 6-8 (reg) to generate shift bit count */ - bc = 31 - (((FC & 3) << 3) | reg); /* get # bits to shift left */ - ovr = (temp & FSIGN) != 0; /* set ovr to status of sign bit 0 */ - temp += (1 << bc); /* add the bit value to the reg */ - ovr ^= (temp & FSIGN) != 0; /* set ovr if sign bit changed */ - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ - if (TRAPME = Mem_write(addr, &temp)) /* put word into memory */ - goto newpsd; /* memory write error or map fault */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - break; - - case 0xA4: /* 0xA4 ADR - ADR */ /* TBM */ - if ((FC & 04) == 0) { - /* Fault, byte address not allowed */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (TRAPME = Mem_read(addr, &temp)) /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - /* use C bits and bits 6-8 (reg) to generate shift bit count */ - bc = 31 - (((FC & 3) << 3) | reg); /* get # bits to shift left */ - t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ - if (temp & (1 << bc)) /* test the bit in memory */ - t |= CC1BIT; /* set CC1 to the bit value */ - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - PSD1 |= t; /* update the CC's in the PSD */ - break; - - case 0xA8: /* 0xA8 RM|ADR - RM|ADR */ /* EXM */ - if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */ - /* Fault */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - IR = (uint32)source; /* get instruction from memory */ - if (FC == 3) /* see if right halfword specified */ - IR <<= 16; /* move over the HW instruction */ - if ((IR & 0xFC7F0000) == 0xC8070000 || - (IR & 0xFF800000) == 0xA8000000 || - (IR & 0xFC000000) == 0x80000000) { - /* Fault, attempt to execute another EXR, EXRR, EXM, or LEAR */ - goto inv; /* invalid instruction */ - } - goto exec; /* go execute the instruction */ - - case 0xAC: /* 0xAC SCC|SD|RM|ADR - SD|RM|ADR */ /* Lx */ - dest = source; /* set value to load into reg */ -//fprintf(stderr, "Lx dest %x addr %0.8x\r\n", dest, addr); - break; - - case 0xB0: /* 0xB0 SCC|SD|RM|ADR - SD|RM|ADR */ /* LMx */ - dest = source & GPR[4]; /* set value to load into reg */ - break; - - case 0xB4: /* 0xB4 SCC|SD|RM|ADR - SD|RM|ADR */ /* LNx */ - dest = (source ^ DMASK) + 1; /* set the value to load into reg */ - if (dest == source) - ovr = 1; /* set arithmetic exception status */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - } - break; - - case 0xBC: /* 0xBC SCC|SD|RM|ADR - SD|RM|ADR */ /* SUMx */ - source = -source; - /* Fall through */ - - case 0xE8: /* 0xE8 SM|RM|ADR - SM|RM|ADR */ /* ARMx */ - case 0xB8: /* 0xB8 SCC|SD|RM|ADR - SD|RM|ADR */ /* ADMx */ - t = (source & MSIGN) != 0; - t |= ((dest & MSIGN) != 0) ? 2 : 0; - dest = dest + source; - if ((t == 3 && (dest & MSIGN) == 0) || - (t == 0 && (dest & MSIGN) != 0)) - ovr = 1; - if (dbl == 0 && (dest & LMASK) != 0 && (dest & LMASK) != LMASK) - ovr = 1; - - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - } - break; - - case 0xC0: /* 0xC0 SCC|SD|RM|ADR - SD|RM|ADR */ /* MPMx */ - if (FC == 3) { /* see if byte address specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - dest = (t_uint64)((t_int64)dest * (t_int64)source); - dbl = 1; - break; - - case 0xC4: /* 0xC4 SCC|RM|ADR - RM|ADR */ /* DVMx */ - if (FC == 3) { /* see if byte address specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (source == 0) { - ovr = 1; /* divide by zero attempted */ - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - goto newpsd; /* go execute the trap now */ - } - dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ - dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - t = (t_int64)dest % (t_int64)source; /* remainder */ - dbl = (t < 0); /* double reg if neg remainder */ - if ((t ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ - t = -t; /* dividend and remainder must be same sign */ - dest = (t_int64)dest / (t_int64)source; /* now do the divide */ - if ((dest & LMASK) != 0 && (dest & LMASK) != LMASK) { /* test for overflow */ - ovr = 1; /* the quotient exceeds 31 bit, overflow */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (modes & AEXP) - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - /* the original regs must be returned unchanged if aexp */ - i_flags &= ~SD; /* remove the store to reg flag */ - dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ - dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - } else { - GPR[reg] = (uint32)t; /* reg gets remainder, reg+1 quotient */ - reg|=1; /* store the quotient in reg+1 */ - } - break; - - case 0xC8: /* 0xC8 IMM - IMM */ /* Immedate */ - temp = GPR[reg]; /* get reg contents */ - addr = SEXT16(IR&RMASK); /* sign extend 16 bit imm value from IR */ -//fprintf(stderr, "C8 IMM temp %0.8x addr %0.8x\r\n", temp, addr); - - switch(opr & 0xF) { /* switch on aug code */ - case 0x0: /* LI */ /* SCC | SD */ - GPR[reg] = addr; /* put immediate value into reg */ - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ - break; - - case 0x2: /* SUI */ - addr = -addr; /* just make value a negative add */ - /* drop through */ - case 0x1: /* ADI */ - t = (temp & FSIGN) != 0; /* set flag for sign bit not set in reg value */ - t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the extended immediate value */ - temp = temp + addr; /* now add the numbers */ - if ((t == 3 && (temp & FSIGN) == 0) || - (t == 0 && (temp & FSIGN) != 0)) - ovr = 1; /* we have an overflow */ - GPR[reg] = temp; /* save the result */ - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (ovr && (modes & AEXP)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - } - break; - - case 0x3: /* MPI */ - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - dest = (t_uint64)(temp & FMASK) | (temp & FSIGN) ? DMASK << 32: 0; - source = (t_uint64)(addr & FMASK) | (addr & FSIGN) ? DMASK << 32: 0; - dest = (t_uint64)((t_int64)dest * (t_int64)source); /* do the multiply */ - i_flags |= SD|SCC; /* save regs and set CC's */ - dbl = 1; /* double reg save */ - break; - - case 0x4: /* DVI */ - if (reg & 1) { /* see if odd reg specified */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - /* change immediate value into a 64 bit value */ - source = (t_uint64)(addr & FMASK) | (addr & FSIGN) ? DMASK << 32: 0; - if (source == 0) { - ovr = 1; /* divide by zero attempted */ - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - goto newpsd; /* go execute the trap now */ - } - dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ - dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - t = (t_int64)dest % (t_int64)source; /* remainder */ - dbl = (t < 0); /* double reg if neg remainder */ - if ((t ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ - t = -t; /* dividend and remainder must be same sign */ - dest = (t_int64)dest / (t_int64)source; /* now do the divide */ - if ((dest & LMASK) != 0 && (dest & LMASK) != LMASK) { /* test for overflow */ - ovr = 1; /* the quotient exceeds 31 bit, overflow */ - /* the arithmetic exception will be handled */ - /* after instruction is completed */ - /* check for arithmetic exception trap enabled */ - if (modes & AEXP) - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - /* the original regs must be returned unchanged if aexp */ - /* put reg values back in dest for CC test */ - dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ - dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - i_flags |= SCC; /* set CC's */ - } else { - GPR[reg] = (uint32)(t & FMASK); /* reg gets remainder, reg+1 quotient */ - GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ - set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ - } - break; - - case 0x5: /* CI */ /* SCC */ - temp -= addr; /* subtract imm value from reg value */ - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ -//fprintf(stderr, "CI IMM temp %0.8x addr %0.8x PSD1 %0.8x flags %0.8x\r\n", temp, addr, PSD1, i_flags); - break; - - case 0x6: /* SVC */ /*TODO*/ -fprintf(stderr, "SVC IMM temp %0.8x addr %0.8x PSD1 %0.8x flags %0.8x\r\n", temp, addr, PSD1, i_flags); - break; - - case 0x7: /* EXR */ - IR = temp; /* get instruction to execute */ - if (addr & 2) /* if bit 31 set, instruction is in right hw, do EXRR */ - IR <<= 16; /* move instruction to left HW */ - if ((IR & 0xFC7F0000) == 0xC8070000 || - (IR & 0xFF800000) == 0xA8000000) { - /* Fault, attempt to execute another EXR, EXRR, or EXM */ - goto inv; /* invalid instruction */ - } - goto exec; - break; - - /* these instruction were never used by MPX, only diags */ - case 0x8: /* SEM */ - case 0x9: /* LEM */ - case 0xA: /* CEMA */ - case 0xB: /* INV */ - case 0xC: /* INV */ - case 0xD: /* INV */ - case 0xE: /* INV */ - case 0xF: /* INV */ - goto inv; /* invalid instruction */ - break; - } - break; - - case 0xCC: /* 0xCC ADR - ADR */ /* LF */ - /* For machines with Base mode 0xCC08 stores base registers */ - if ((FC & 3) != 0) { /* must be word address */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - /* Validate access read addr to 8 - reg */ - temp = addr + (8 - reg); - if ((temp & 0x1f) != (addr & 0x1f)) { - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - bc = addr & 0x20; /* bit 26 initial value */ - while (reg < 8) { - if (bc != (addr & 0x20)) { /* test for crossing file boundry */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (FC & 0x4) /* LFBR? */ - TRAPME = Mem_read(addr, &BR[reg]); /* read the base reg */ - else /* LF */ - TRAPME = Mem_write(addr, &GPR[reg]); /* read the GPR reg */ - if (TRAPME) /* TRAPME has error */ - goto newpsd; /* go execute the trap now */ - reg++; /* next reg to write */ - addr += 4; /* next addr */ - } - break; - -#ifdef SIMPLE_MODE - case 0xD0: /* 0xD0 SD|ADR - INV */ /* LEA none basemode only */ -// FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */ -// FC |= addr & 3; /* set new C bits to address from orig or regs */ - /* Wort alert for lea instruction. Bit 0,1 are set to 0 of result addr if */ - /* indirect bit is zero in instruction. Bits 0 & 1 are set to the last word */ - /* or instruction in the chain bits 0 & 1 if indirect bit set */ - dest = (t_uint64)(addr); - /* if IX == 00 => dest = IR */ - /* if IX == 0g => dest = IR + reg */ - /* if IX == Ix => dest = ind + reg */ - break; - while (IR & IND) { /* process indirection */ - if (TRAPME = Mem_read(addr, &temp)) /* get the word from memory */ - goto newpsd; /* memory read error or map fault */ - addr = temp & 0x7FFFC; /* get just the addr */ - ix = (temp >> 21) & 3; /* get the index reg from indirect word */ - if (ix != 0) - addr += GPR[ix]; /* add the register to the address */ - dest = (t_uint64)addr; /* make into 64 bit variable */ - /* if no F or C bits set, use original, else new */ - if ((temp & F_BIT) || (addr & 3)) - FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3); - CC = (temp >> 24) & 0x78; /* save CC's from the last indirect word */ - } - -#endif /* SIMPLE_MODE*/ - case 0xD4: /* 0xD4 SM|ADR - SM|ADR */ /* STx */ -//fprintf(stderr, "ST? dest %0.8x\r\n", (uint32)dest); - break; - - case 0xD8: /* 0xD8 SM|ADR - SM|ADR */ /* STMx */ - dest &= GPR[4]; - break; - - case 0xDC: /* 0xDC INV - */ /* INV nonbasemode (STFx basemode) */ - /* DC00 STF */ /* DC08 STFBR */ - if ((FC & 0x4) && (CPU_MODEL <= MODEL_27)) { - /* basmode undefined for 32/7x & 32/27 */ /* TODO check this */ - TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - goto newpsd; /* handle trap */ - } - /* For machines with Base mode 0xDC08 stores base registers */ - if ((FC & 3) != 0) { /* must be word address */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - /* Validate access write addr to 8 - reg */ - temp = addr + (8 - reg); - if ((temp & 0x1f) != (addr & 0x1f)) { - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - bc = addr & 0x20; /* bit 26 initial value */ - while (reg < 8) { - if (bc != (addr & 0x20)) { /* test for crossing file boundry */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (FC & 0x4) /* STFBR? */ - TRAPME = Mem_write(addr, &BR[reg]); /* store the base reg */ - else /* STF */ - TRAPME = Mem_write(addr, &GPR[reg]); /* store the GPR reg */ - if (TRAPME) /* TRAPME has error */ - goto newpsd; /* go execute the trap now */ - reg++; /* next reg to write */ - addr += 4; /* next addr */ - } - break; - - /* TODO */ - case 0xE0: /* 0xE0 SCC|SD|RM|ADR - SD|RM|ADR */ /* ADFx, SUFx */ - if ((FC & 3) != 0) { /* must be word address */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (opr & 0x0008) { /* Was it ADFx? */ - /* TODO ADF? call here */ - } else { - /* TODO SUF? call here */ - } /* it is SUFx */ - break; - - /* TODO */ - case 0xE4: /* 0xE4 SCC|RM|ADR - RM|ADR */ /* MPFx, DVFx */ - if ((FC & 3) != 0) { /* must be word address */ - TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - goto newpsd; /* go execute the trap now */ - } - if (opr & 0x0008) { /* Was it MPFx? */ - /* TODO MPF? call here */ - } else { - /* TODO DVF? call here */ - } /* it is DVFx */ - break; - - case 0xEC: /* 0xEC ADR - ADR */ /* Branch unconditional or Branch True */ - /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ - /* so just test for F bit and go on */ - /* if ((FC & 5) != 0) { */ - if ((FC & 4) != 0) { - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - CC = (PSD1 >> 24) & 0x78; /* get CC's if any */ - switch(reg) { - case 0: t = 1; break; - case 1: t = (CC & CC1) != 0; break; - case 2: t = (CC & CC2) != 0; break; - case 3: t = (CC & CC3) != 0; break; - case 4: t = (CC & CC4) != 0; break; - case 5: t = (CC & (CC2|CC4)) != 0; break; - case 6: t = (CC & (CC3)|CC4) != 0; break; - case 7: t = (CC & (CC1|CC2|CC3|CC4)) != 0; break; - } -//fprintf(stderr, "BCT t %0.8x addr %0.8x CC %0.2x PSD1 %0.8x\r\n", t, addr, CC, PSD1); - if (t) { /* see if we are going to branch */ - /* we are taking the branch, set CC's if indirect, else leave'm */ - /* update the PSD with new address */ - PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ - if (IR & IND) /* see if CCs from last indirect location are wanted */ - PSD1 = ((PSD1 & 0x87ffffff) | (CC << 24)); /* insert last CCs */ - i_flags |= BT; /* we branched, so no PC update */ -//fprintf(stderr, "BR t %0.8x addr %0.8x PSD1 %0.8x\r\n", t, addr, PSD1); - } - /* branch not taken, go do next instruction */ - break; - - case 0xF0: /* 0xF0 ADR - ADR */ /* Branch False or Branch Function True */ - /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ - /* so just test for F bit and go on */ - /* if ((FC & 5) != 0) { */ - if ((FC & 4) != 0) { - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - CC = (PSD1 >> 24) & 0x78; /* get CC's if any */ - switch(reg) { - case 0: t = (GPR[4] & (1 << ((CC >> 3) + 16))) == 0; break; - case 1: t = (CC & CC1) == 0; break; - case 2: t = (CC & CC2) == 0; break; - case 3: t = (CC & CC3) == 0; break; - case 4: t = (CC & CC4) == 0; break; - case 5: t = (CC & (CC2|CC4)) == 0; break; - case 6: t = (CC & (CC3)|CC4) == 0; break; - case 7: t = (CC & (CC1|CC2|CC3|CC4)) == 0; break; - } -fprintf(stderr, "BCF reg %d t %0.8x addr %0.8x CC %0.2x PSD1 %0.8x\r\n", reg, t, addr, CC, PSD1); - if (t) { /* see if we are going to branch */ - /* we are taking the branch, set CC's if indirect, else leave'm */ - /* update the PSD with new address */ - PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ - if (IR & IND) /* see if CCs from last indirect location are wanted */ - PSD1 = ((PSD1 & 0x87ffffff) | (CC << 24)); /* insert last CCs */ - i_flags |= BT; /* we branched, so no PC update */ -fprintf(stderr, "BR t %0.8x addr %0.8x PSD1 %0.8x\r\n", t, addr, PSD1); - } - break; - - case 0xF4: /* 0xF4 SD|ADR - RR|SB|WRD */ /* Branch increment */ - dest += 1 << ((IR >> 21) & 3); /* use bits 9 & 10 to incr reg */ - if (dest == 0) { /* if reg is 0, take the branch */ - /* we are taking the branch, set CC's if indirect, else leave'm */ - /* update the PSD with new address */ - PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ - if (IR & IND) /* see if CCs from last indirect location are wanted */ - PSD1 = ((PSD1 & 0x87ffffff) | (CC << 24)); /* insert last CCs */ - i_flags |= BT; /* we branched, so no PC update */ - } - break; - - case 0xF8: /* 0xF8 ADR - ADR */ /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, TRP */ - switch((opr >> 7) & 0x7) { /* use bits 6-8 to determine instruction */ - case 0x0: /* ZMx F80x */ /* SM */ - dest = 0; /* destination value is zero */ - break; - case 0x1: /* BL F880 */ - /* copy CC's from instruction and PC incremented by 4 */ - GPR[0] = ((PSD1 & 0x78000000) | (PSD1 & 0x7fffe)) + 4; - if (IR & IND) /* see if CC from last indirect loacation are wanted */ - GPR[0] = (CC << 24) | (PSD1 & 0x7fffe) + 4; /* set CC's and incremented PC */ - /* update the PSD with new address */ - PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); - i_flags |= BT; /* we branched, so no PC update */ - break; - - case 0x3: /* LPSD F980 */ - /* fall through */; - case 0x5: /* LPSDCM FA80 */ - CPUSTATUS |= 0x40; /* enable software traps */ - /* this will allow attn and */ - /* power fail traps */ - if (TRAPME = Mem_read(addr, &PSD1)) { /* get PSD1 from memory */ - goto newpsd; /* memory read error or map fault */ - } - if (TRAPME = Mem_read(addr+4, &PSD2)) { /* get PSD2 from memory */ - goto newpsd; /* memory read error or map fault */ - } - if (opr & 0x0200) { /* Was it LPSDCM? */ - /* map bit must be on and retain bit off to load maps */ - if ((PSD2 & MAPBIT) && ((PSD2 & RETBIT == 0))) { - /* set mapped mode in cpu status */ - CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ - /* we need to load the new maps */ - TRAPME = load_maps(&PSD1); /* load maps for new PSD */ - } - } - /* set new map mode and interrupt blocking state in CPUSTATUS */ - if (PSD2 & MAPBIT) - CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ - else - CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */ - if ((PSD2 & 0xc000) == 0) /* get int requested status */ - CPUSTATUS &= ~0x80; /* reset blk state in cpu status bit 24 */ - else if ((PSD2 & 0xc000) != 0) /* is it block int */ - CPUSTATUS |= 0x80; /* set state in cpu status bit 24 too */ - /* TRAPME can be error from LPSDCM or OK here */ - goto newpsd; /* load the new psd */ - break; - - case 0x4: /* JWCS */ /* not used in simulator */ - case 0x2: /* BRI */ /* TODO - only for 32/55 or 32/7X in PSW mode */ - case 0x6: /* TRP */ - case 0x7: /* TPR */ - TRAPME = UNDEFINSTR_TRAP; /* trap condition */ - goto newpsd; /* undefined instruction trap */ - break; - } - break; - -/* F Class I/O device instruction format */ -/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ -/* |00 01 02 03 04 05|06 07 08|09 10 11 12|13 14 15|16|17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */ -/* | Op Code | Reg | I/O type | Aug |0 | Channel Address | Device Sub-address | */ -/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ -/* */ -/* E Class I/O device instruction format */ -/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ -/* |00 01 02 03 04 05|06 07 08 09 10 11 12|13 14 15|16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| */ -/* | Op Code | Device Number | Aug | Command Code | */ -/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ -/* */ - case 0xFC: /* 0xFC IMM - IMM */ /* XIO, CD, TD, Interrupt Control */ - if (modes & PRIV == 0) { /* must be privileged to do I/O */ - TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ - TRAPSTATUS |= 0x1000; /* set Bit 19 of Trap Status word */ - goto newpsd; /* Privlege violation trap */ - } - if ((opr & 0x7) != 0x07) { /* aug is 111 for XIO instruction */ - /* Process Non-XIO instructions */ - uint32 status = 0; /* status returned from device */ - uint32 device = (opr >> 3) & 0x7f; /* get device code */ - uint32 prior = device; /* interrupt priority */ - - switch(opr & 0x7) { /* use bits 13-15 to determine instruction */ - case 0x0: /* EI FC00 Enable Interrupt */ - prior = (opr >> 3) & 0x7f; /* get priority level */ - /* SPAD entries for interrupts begin at 0x80 */ - t = SPAD[prior+0x80]; /* get spad entry for interrupt */ -fprintf(stderr, "EIO EI intr %0.2x SPAD %0.8x\r\n", prior, t); - break; - - case 0x1: /* DI FC01 */ - prior = (opr >> 3) & 0x7f; /* get priority level */ - /* SPAD entries for interrupts begin at 0x80 */ - t = SPAD[prior+0x80]; /* get spad entry for interrupt */ -fprintf(stderr, "EIO DI intr %0.2x SPAD %0.8x\r\n", prior, t); - - case 0x2: /* RI FC02 */ - prior = (opr >> 3) & 0x7f; /* get priority level */ - /* SPAD entries for interrupts begin at 0x80 */ - t = SPAD[prior+0x80]; /* get spad entry for interrupt */ -fprintf(stderr, "EIO RI intr %0.2x SPAD %0.8x\r\n", prior, t); - break; - - case 0x3: /* AI FC03 */ - prior = (opr >> 3) & 0x7f; /* get priority level */ - /* SPAD entries for interrupts begin at 0x80 */ - t = SPAD[prior+0x80]; /* get spad entry for interrupt */ -fprintf(stderr, "EIO AI intr %0.2x SPAD %0.8x\r\n", prior, t); - break; - - case 0x4: /* DAI FC04 */ - prior = (opr >> 3) & 0x7f; /* get priority level */ - /* SPAD entries for interrupts begin at 0x80 */ - t = SPAD[prior+0x80]; /* get spad entry for interrupt */ -fprintf(stderr, "EIO DAI intr %0.2x SPAD %0.8x\r\n", prior, t); - /* instruction following a DAI can not be interrupted */ - /* skip tests for interrupts if this is the case */ - break; - - case 0x5: /* TD FC05 */ /* bits 13-15 is test code type */ - case 0x6: /* CD FC06 */ - /* If CD or TD, make sure device is not F class device */ - /* the channel must be defined as a non class F I/O channel in SPAD */ - /* if class F, the system will generate a system check trap */ - t = SPAD[device]; /* get spad entry for channel */ -fprintf(stderr, "EIO chan %0.4x spad %0.8x\r\n", device, t); - if (t & 0x0f000000 == 0x0f000000) { /* class in bits 4-7 */ - TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */ - TRAPSTATUS &= ~BIT0; /* class E error bit */ - TRAPSTATUS &= ~BIT1; /* I/O processing error */ - goto newpsd; /* machine check trap */ - } - if (opr & 0x1) { /* see if CD or TD */ -// if (TRAPME = testEIO(device, testcode, &status)) -// goto newpsd; /* error returned, trap cpu */ - /* return status has new CC's in bits 1-4 of status word */ - PSD1 = ((PSD1 & 0x87ffffff) | (status & 0x78000000)); /* insert status CCs */ - } else { -// if (TRAPME = startEIO(device, &status)) -// goto newpsd; /* error returned, trap cpu */ - /* No CC's going out */ - } - break; - case 0x7: /* XIO FC07*/ /* should never get here */ - break; - } - break; /* skip over XIO code */ - } - - /* Process Non-XIO instructions */ - /* if reg is non-zero, add reg to 15 bits from instruction */ - if (reg) - IR = (IR & 0x7fff) + (GPR[reg] & 0x7fff); /* set new chan/suba into IR */ - chan = (IR & 0x7F00) >> 8; /* get 7 bit channel address */ - suba = IR & 0xFF; /* get 8 bit subaddress */ - /* the channel must be defined as a class F I/O channel in SPAD */ - /* if not class F, the system will generate a system check trap */ - t = SPAD[chan]; /* get spad entry for channel */ -fprintf(stderr, "XIO chan %x sa %x spad %0.8x\r\n", chan, suba, t); - if (t & 0x0f000000 != 0x0f000000) { /* class in bits 4-7 */ -mcheck: - TRAPME = SYSTEMCHK_TRAP; /* trap condition */ - TRAPSTATUS |= BIT0; /* class F error bit */ - TRAPSTATUS &= ~BIT1; /* I/O processing error */ - goto newpsd; /* machine check trap */ - } - /* get the 1's comp of interrupt address from bits 9-15 SPAD entry */ - ix = (t & 0x007f0000) >> 16; /* get the 1's comp of int level */ -//fprintf(stderr, "XIO1 chan %8x intr %8x spad %0.8x\r\n", chan, ix, bc); - ix = 127 - ix; /* get positive number for interrupt */ -//fprintf(stderr, "XIO2 chan %x intr %x spad %0.8x\r\n", chan, ix, bc); - bc = SPAD[ix+0x80]; /* get interrupt entry for channel */ -//fprintf(stderr, "XIO chan %x intr %x spad %0.8x\r\n", chan, ix, bc); - /* SPAD address F1 has interrupt table address */ - addr = SPAD[0xf1] + (ix<<2); /* vector address in SPAD */ -//fprintf(stderr, "XIOa spad %x intr %x spad %0.8x addr %x\r\n", SPAD[0xf1], ix, bc, addr); - addr = M[addr>>2]; /* get the interrupt context block addr */ -//fprintf(stderr, "XIOb chan %x intr %x spad %0.8x addr %x\r\n", chan, ix, bc, addr); - /* the context block contains the old PSD, */ - /* new PSD, IOCL address, and I/O status address */ - if (addr == 0) /* must be initialized address */ - goto mcheck; /* bad int icb address */ -//fprintf(stderr, "XIO chan %x intr %x addr %x iocla %x\r\n", chan, ix, addr, addr + 16); - if (TRAPME = Mem_read(addr+16, &temp)) { /* get iocl address from icb wd 4 */ - goto mcheck; /* machine check if not there */ - } -//fprintf(stderr, "XIOx chan %x intr %x addr %x temp %x\r\n", chan, ix, addr, temp); - /* iocla must be valid addr */ - if ((temp & MASK24) == 0) - goto mcheck; /* bad iocl address */ - -fprintf(stderr, "XIO ready chan %x intr %x icb %x iocla %x iocd1 %0.8x iocd2 %0.x8\r\n", - chan, ix, addr, addr+16, M[temp>>2], M[(temp+4)>>2]); - /* at this point, the channel has a valid SPAD channel entry */ - /* t is SPAD entry contents for chan device */ - /* IR has IR + reg contents if reg!+ 0 */ - /* chan - channel address */ - /* suba - channel device subaddress */ - /* ix - positive interrupt level */ - /* addr - ICB for specified interrupt level, points to 6 wd block */ - /* temp - First IOCD address */ -fprintf(stderr, "XIO switch chan %x intr %x chsa %x IOCDa %x\r\n", chan, ix, (chan<<8)|suba, temp); - switch((opr >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */ - uint32 status; /* status returned by various functions */ - uint16 chsa; /* device address */ - - case 0x00: /* Unassigned */ - case 0x01: /* Unassigned */ - case 0x0A: /* Unassigned */ - TRAPME = UNDEFINSTR_TRAP; /* trap condition */ - goto newpsd; /* undefined instruction trap */ - break; - - case 0x09: /* Enable write channel ECWCS */ - case 0x0B: /* Write channel WCS WCWCS */ - /* for now or maybe forever, return unsupported transaction */ - PSD1 = ((PSD1 & 0x87ffffff) | (CC2BIT|CC2BIT)); /* insert status 5 */ - break; - - case 0x02: /* Start I/O SIO */ - chsa = IR & 0x7FFF; /* get device address */ - if (TRAPME = startxio(chsa, &status)) - goto newpsd; /* error returned, trap cpu */ - PSD1 = ((PSD1 & 0x87ffffff) | (status & 0x78000000)); /* insert status */ -fprintf(stderr, "XIO SIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); - break; - - case 0x03: /* Test I/O TIO */ - chsa = IR & 0x7FFF; /* get device address */ - if (TRAPME = testxio(chsa, &status)) - goto newpsd; /* error returned, trap cpu */ - PSD1 = ((PSD1 & 0x87ffffff) | (status & 0x78000000)); /* insert status */ -fprintf(stderr, "XIO TIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); - break; - - case 0x04: /* Stop I/O STPIO */ - chsa = IR & 0x7FFF; /* get device address */ - if (TRAPME = stopxio(chsa, &status)) - goto newpsd; /* error returned, trap cpu */ - PSD1 = ((PSD1 & 0x87ffffff) | (status & 0x78000000)); /* insert status */ -fprintf(stderr, "XIO STPIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); - break; - - /* TODO Finish XIO */ - case 0x05: /* Reset channel RSCHNL */ - case 0x06: /* Halt I/O HIO */ - case 0x07: /* Grab controller GRIO n/u */ - case 0x08: /* Reset channel RSCTL */ - - /* TODO Finish XIO interrupts */ - case 0x0C: /* Enable channel interrupt ECI */ - case 0x0D: /* Disable channel interrupt DCI */ - case 0x0E: /* Activate channel interrupt ACI */ - case 0x0F: /* Deactivate channel interrupt DACI */ - /* Note, instruction following DACI is not interruptable */ - break; - } /* end of XIO switch */ - break; - } /* End of Instruction Switch */ - - /* any instruction with an arithmetic exception will still end up here */ - /* after the instruction is done and before incrementing the PC, */ - /* we will trap the cpu if ovl is set nonzero by an instruction */ - - /* Store result to register */ - if (i_flags & SD) { - if (dbl) { /* if double reg, store 2nd reg */ - GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ - GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ -//fprintf(stderr, "SD double FC %x reg %x dest(R) %0.8x, dest(R+1) %0.8x\r\n", FC, reg, GPR[reg], GPR[reg+1]); - } else { - GPR[reg] = (uint32)(dest & FMASK); /* save the reg */ -//fprintf(stderr, "SD single FC %x reg %x dest(%d)=%0.8x\r\n", FC, reg, reg, GPR[reg]); - } - } - - /* Store result to base register */ - if (i_flags & SB) { - if (dbl) { /* no dbl wd store to base regs */ - TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - goto newpsd; /* go execute the trap now */ - } - BR[reg] = (uint32)(dest & FMASK); /* save the base reg */ -//fprintf(stderr, "SB base reg %x dest(BR) %0.8x\r\n", reg, BR[reg]); - } - - /* Store result to memory */ - if (i_flags & SM) { - /* Check if byte of half word */ - if (((FC & 04) || (FC & 5) == 1)) { /* hw or byte requires read first */ - if (TRAPME = Mem_read(addr, &temp)) { -//fprintf(stderr, "SM FAULT addr %0.8x, FC %0.4x dest %0.8x\r\n", addr, FC, (uint32)dest); - goto newpsd; /* memory read error or map fault */ - } - } -//fprintf(stderr, "SM addr %0.8x, FC %0.4x dest %0.8x\r\n", addr, FC, (uint32)dest); - switch(FC) { - case 2: /* double word store */ - if ((addr & 7) != 0) { - TRAPME = ADDRSPEC_TRAP; /* address not on dbl wd boundry, error */ - goto newpsd; /* go execute the trap now */ - } - temp = (uint32)(dest && MASK32);/* get lo 32 bit */ - if (TRAPME = Mem_write(addr + 4, &temp)) - goto newpsd; /* memory write error or map fault */ - temp = dest >> 32; /* move upper 32 bits to lo 32 bits */ - /* Fall through to write upper 32 bits */ - - case 0: /* word store */ - temp = (uint32)(dest & FMASK); /* mask 32 bit of reg */ -//fprintf(stderr, "SM temp %0.8x, FC %0.4x dest %0.8x\r\n", temp, FC, (uint32)dest); - if ((addr & 3) != 0) { - /* Address fault */ - TRAPME = ADDRSPEC_TRAP; /* address not on wd boundry, error */ - goto newpsd; /* go execute the trap now */ - } - break; - - case 1: /* left halfword write */ - temp &= RMASK; /* mask out 16 left most bits */ - temp |= (uint32)(dest & RMASK) << 16; /* put into left most 16 bits */ - if ((addr & 1) != 0) { - /* Address fault */ - TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ - goto newpsd; /* go execute the trap now */ - } - break; - - case 3: /* right halfword write */ - temp &= LMASK; /* mask out 16 right most bits */ - temp |= (uint32)(dest & RMASK); /* put into right most 16 bits */ - if ((addr & 1) != 0) { - TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ - goto newpsd; /* go execute the trap now */ - } - break; - - case 4: - case 5: - case 6: - case 7: /* byte store operation */ - temp &= ~(0xFF << (8 * (7 - FC))); /* clear the byte to store */ - temp |= (uint32)(dest & 0xFF) << (8 * (7 - FC)); /* insert new byte */ - break; - } - /* store back the modified memory location */ -//fprintf(stderr, "SM write addr %0.8x, FC %0.4x temp %0.8x\r\n", addr, FC, temp); - if (TRAPME = Mem_write(addr, &temp)) /* store back to memory */ - goto newpsd; /* memory write error or map fault */ - } - - /* Update condition code registers */ - if (i_flags & SCC) { - PSD1 &= 0x87FFFFFF; /* clear the old CC's */ - CC = 0; /* no CC's yet */ -// aexp = ovr; /* set arithmetic exception status */ - if (ovr) /* if overflow, set CC1 */ - CC |= CC1; /* show we had AEXP */ - else if (dest & MSIGN) /* is it neg */ - CC |= CC3; /* if neg, set CC3 */ - else if (dest == 0) - CC |= CC4; /* if zero, set CC4 */ - else - CC |= CC2; /* if gtr than zero, set CC2 */ - PSD1 |= ((CC & 0x78)<<24); /* update the CC's in the PSD */ - } - - /* Update instruction pointer to next instruction */ -/* - if (i_flags & HLF) { - PC = (PC + 2) | (((PC & 2) >> 1) & 1); - } else { - PC = (PC + 4) | (((PC & 2) >> 1) & 1); - } - PC &= (modes & BASE) ? 0xFFFFFF : 0x7FFFF; -*/ - - /* Update instruction pointer to next instruction */ - if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */ -//fprintf(stderr, "@PCI1 temp %0.8x addr %0.8x PSD1 %0.8x flags %0.8x\r\n", temp, addr, PSD1, i_flags); - /* branch not taken, so update the PC */ - if (i_flags & HLF) { - PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); - } else { - PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); - } -//fprintf(stderr, "@PCI2 temp %0.8x addr %0.8x PSD1 %0.8x flags %0.8x\r\n", temp, addr, PSD1, i_flags); - } -// PSD1 &= (modes & BASE) ? 0xFFFFFFFF : 0xFC07FFFF; - - /* check if we had an arithmetic exception on the last instruction*/ - if (modes & AEXP && ovr) { - TRAPME = AEXPCEPT_TRAP; /* trap the system now */ - goto newpsd; /* process the trap */ - } - /* no trap, so continue with next instruction */ -// continue; /* keep running */ - break; /* quit for now after each instruction */ - -newpsd: -//fprintf(stderr, "place @ newpsd PSD1 %0.8x PSD2 %0.8x TRAPME %0.4x\r\n", PSD1, PSD2, TRAPME); - /* we get here from a LPSD, LPSDCM, INTR, or TRAP */ - if (TRAPME) { - /* SPAD location 0xf0 has trap vector base address */ - uint32 tta = SPAD[0xf0]; /* get trap table address in memory */ - uint32 tvl; /* trap vector location */ - if (tta == 0) - tta = 0x80; /* if not set, assume 0x80 FIXME */ - /* Trap Table Address in memory is pointed to by SPAD 0xF0 */ - /* TODO update cpu status and trap status words with reason too */ - switch(TRAPME) { - case POWERFAIL_TRAP: /* 0x80 power fail trap */ - case POWERON_TRAP: /* 0x84 Power-On trap */ - case MEMPARITY_TRAP: /* 0x88 Memory Parity Error trap */ - case NONPRESMEM_TRAP: /* 0x8C Non Present Memory trap */ - case UNDEFINSTR_TRAP: /* 0x90 Undefined Instruction Trap */ - case PRIVVIOL_TRAP: /* 0x94 Privlege Violation Trap */ -//TODO case SVCCALL_TRAP: /* 0x98 Supervisor Call Trap */ - case MACHINECHK_TRAP: /* 0x9C Machine Check Trap */ - case SYSTEMCHK_TRAP: /* 0xA0 System Check Trap */ - case MAPFAULT_TRAP: /* 0xA4 Map Fault Trap */ - case IPUUNDEFI_TRAP: /* 0xA8 IPU Undefined Instruction Trap */ - case SIGNALIPU_TRAP: /* 0xAC Signal IPU/CPU Trap */ - case ADDRSPEC_TRAP: /* 0xB0 Address Specification Trap */ - case CONSOLEATN_TRAP: /* 0xB4 Console Attention Trap */ - case PRIVHALT_TRAP: /* 0xB8 Privlege Mode Halt Trap */ - case AEXPCEPT_TRAP: /* 0xBC Arithmetic Exception Trap */ - default: - tta = tta + (TRAPME - 0x80); /* tta has mem addr of trap vector */ - tvl = M[tta>>2] & 0x7FFFC; /* get trap vector address from trap vector loc */ -//fprintf(stderr, "tvl %0.8x, tta %0.8x status %0.8x\r\n", tvl, tta, CPUSTATUS); - if (tvl == 0 || (CPUSTATUS & 0x40) == 0) { - /* vector is zero or software has not enabled traps yet */ - /* execute a trap halt */ - /* set the PSD to trap vector location */ - PSD1 = 0x80000000 + TRAPME; /* just priv and PC to trap vector */ - PSD2 = 0x00004000; /* unmapped, blocked interrupts mode */ - M[0x680>>2] = PSD1; /* store PSD 1 */ - M[0x684>>2] = PSD2; /* store PSD 2 */ - M[0x688>>2] = TRAPSTATUS; /* store trap status */ - M[0x68C>>2] = 0; /* This will be device table entry later TODO */ -fprintf(stderr, "[][][][][][][][][][][] HALT TRAP [][][][][][][][][][][][]\r\n"); -fprintf(stderr, "PSD1 %0.8x PSD2 %0.8x TRAPME %0.4x\r\n", PSD1, PSD2, TRAPME); - for (ix=0; ix<8; ix+=2) { - fprintf(stderr, "GPR[%d] %0.8x GPR[%d] %0.8x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]); - } -fprintf(stderr, "[][][][][][][][][][][] HALT TRAP [][][][][][][][][][][][]\r\n"); - return STOP_HALT; /* exit to simh for halt */ - } else { - /* valid vector, so store the PSD, fetch new PSD */ - M[tvl>>2] = PSD1; /* store PSD 1 */ - M[(tvl>>2)+1] = PSD2; /* store PSD 2 */ -fprintf(stderr, "[][][][][][][][][][][] ERROR TRAP [][][][][][][][][][][][]\r\n"); -fprintf(stderr, "PSD1 %0.8x PSD2 %0.8x TRAPME %0.4x\r\n", PSD1, PSD2, TRAPME); - for (ix=0; ix<8; ix+=2) { - fprintf(stderr, "GPR[%d] %0.8x GPR[%d] %0.8x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]); - } - PSD1 = M[(tvl>>2)+2]; /* get new PSD 1 */ - PSD2 = M[(tvl>>2)+3]; /* get new PSD 1 */ - M[(tvl>>2)+4] = TRAPSTATUS; /* store trap status */ -fprintf(stderr, "NEWPSD1 %0.8x NEWPSD2 %0.8x TRAPME %0.4x TRAPSTATUS %08x\r\n", - PSD1, PSD2, TRAPME, TRAPSTATUS); -fprintf(stderr, "[][][][][][][][][][][] ERROR TRAP [][][][][][][][][][][][]\r\n"); - reason = STOP_HALT; /* exit to simh for now */ -/*FIXME*/ break; /* Go execute the trap */ - } - break; - } - } - /* we have a new PSD loaded via a LPSD or LPSDCM */ - /* TODO finish instruction history, then continue */ - /* update cpu status word too */ -// continue; /* single step cpu just for now */ - break; /* quit for now after each instruction */ - } /* end while */ - - /* Simulation halted */ -//fprintf(stderr, "@end PSD1 %0.8x PSD2 %0.8x addr %0.8x\r\n", PSD1, PSD2, addr); - return reason; -} - -/* these are the default ipl devices defined by the CPU jumpers */ -/* they can be overridden by specifying IPL devide at ipl time */ -uint32 def_disk = 0x0800; /* disk channel 8, device 0 */ -uint32 def_tape = 0x1000; /* tape device 10, device 0 */ -uint32 def_floppy = 0x7ef0; /* IOP floppy disk channel 7e, device f0 */ - -/* Reset routine */ -/* do any one time initialization here for cpu */ -t_stat cpu_reset(DEVICE * dptr) -{ - int i; - - /* leave regs alone so values can be passed to boot code */ - PSD1 = 0x80000000; /* privileged, non mapped, non extended, address 0 */ - PSD2 = 0x00004000; /* blocked interrupts mode */ - modes = (PRIV | BLKED); /* set modes to privileged and blocked interrupts */ - CPUSTATUS = CPU_MODEL; /* clear all cpu status except cpu type */ - CPUSTATUS |= 0x80000000; /* set privleged state bit 0 */ - CPUSTATUS |= 0x00000080; /* set blocked mode state bit 24 */ - TRAPSTATUS = CPU_MODEL; /* clear all trap status except cpu type */ - - chan_set_devs(); /* set up the defined devices on the simulator */ - - /* set default breaks to execution tracing */ - sim_brk_types = sim_brk_dflt = SWMASK('E'); - /* zero regs */ - for (i = 0; i < 8; i++) { - GPR[i] = 0; /* clear the registers */ - BR[i] = 0; /* clear the registers */ - } - /* set PC to start at loc 0 with interrupts blocked and privleged */ - PSD1 = 0x80000000; /* privileged, non mapped, non extended, address 0 */ - PSD2 = 0x00004000; /* blocked interrupts mode */ - - /* add code here to initialize the SEL32 cpu scratchpad on initial start */ - /* see if spad setup by software, if yes, leave spad alone */ - /* otherwise set the default values into the spad */ - /* CPU key is 0xECDAB897, IPU key is 0x13254768 */ - /* Keys are loaded by the O/S software during the boot loading sequence */ - if (SPAD[0xf7] != 0xecdab897) - { - int ival = 0; /* init value for concept 32 */ - - if (CPU_MODEL < MODEL_27) - ival = 0xfffffff; /* init value for 32/7x int and dev entries */ - for (i = 0; i < 224; i++) - SPAD[i] = ival; /* init 128 devices and 96 ints in the spad */ - for (i = 224; i < 256; i++) /* clear the last 32 extries */ - SPAD[i] = 0; /* clear the spad */ - SPAD[0xf0] = 0x80; /* default Trap Table Address (TTA) */ - SPAD[0xf1] = 0x100; /* Interrupt Table Address (ITA) */ - SPAD[0Xf2] = 0x700; /* IOCD Base Address */ - SPAD[0xf3] = 0x788; /* Master Process List (MPL) table address */ - SPAD[0xf4] = def_tape; /* Default IPL address from console IPL command or jumper */ - SPAD[0xf5] = 0x00004000; /* current PSD2 defaults to blocked */ - SPAD[0xf6] = 0; /* reserved (PSD1 ??) */ - SPAD[0xf7] = 0; /* make sure key is zero */ - SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */ - SPAD[0xf9] = CPU_MODEL; /* set default cpu type in cpu status word */ - SPAD[0xff] = 0x00ffffff; /* interrupt level 7f 1's complament */ - } -#ifdef PUT_SOMETHING_IN_MEMORY - M[0] = 0x00020002; /* 0x00 nop */ - M[1] = 0x01030289; /* 0x04 lcs, rdsts 0 */ - M[2] = 0x00060007; /* 0x08 beu/uei */ - M[3] = 0xF9800020; /* 0x0C lpsd 0x20 */ - M[4] = 0xAC800004; /* 0x10 lw R1,0x4 */ - M[5] = 0xAD000009; /* 0x14 lh R2,0x8 */ - M[6] = 0xAF000020; /* 0x18 ld r6,0x20 */ - M[7] = 0xEC000000; /* 0x1C bu 0 */ - M[8] = 0x80000010; /* 0x20 go to lw at 0x10 */ - M[9] = 0x00004000; /* 0x24 PSD2 block ints */ -#endif - /* we are good to go */ - return SCPE_OK; -} - -/* Interval timer routines */ -t_stat rtc_srv(UNIT * uptr) -{ -fprintf(stderr, "WE are here 2 \n"); - return SCPE_OK; -} - -/* Memory examine */ -/* examine a 32bit memory location */ -/* address is byte address with bits 30,31 = 0 */ -t_stat cpu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw) -{ - uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */ - - /* MSIZE is in 32 bit words */ - if (addr >= MEMSIZE) /* see if address is within our memory */ - return SCPE_NXM; /* no, none existant memory error */ - if (vptr == NULL) /* any address specified by user */ - return SCPE_OK; /* no, just ignore the request */ - *vptr = M[addr]; /* return memory contents */ - return SCPE_OK; /* we are all ok */ -} - -/* Memory deposit */ -/* modify a 32bit memory location */ -/* address is byte address with bits 30,31 = 0 */ -t_stat cpu_dep(t_value val, t_addr baddr, UNIT *uptr, int32 sw) -{ - uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */ - -//fprintf(stderr, "cpu_dep baddr %0x, sw %x\b\n", baddr, sw); - /* MSIZE is in 32 bit words */ - if (addr >= MEMSIZE) /* see if address is within our memory */ - return SCPE_NXM; /* no, none existant memory error */ - M[addr] = val; /* set the new data value */ - return SCPE_OK; /* all OK */ -} - -/* set the CPU memory size */ -t_stat cpu_set_size(UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ - t_uint64 mc = 0; - uint32 i; - -//fprintf(stderr, "WE are here 4 \b\n"); - cpu_unit.flags &= ~UNIT_MSIZE; - cpu_unit.flags |= val; /* set new memory size */ - val >>= UNIT_V_MSIZE; /* set size in 32bit words */ - val = (val + 1) * 128 * 1024; /* KW's */ - if ((val < 0) || (val > MAXMEMSIZE)) /* is size valid */ - return SCPE_ARG; /* nope, argument error */ - for (i = val; i < MEMSIZE; i++) /* see if memory contains anything */ - mc |= M[i]; /* or in any bits in memory */ - if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE))) - return SCPE_OK; /* return OK if user says no */ - MEMSIZE = val; /* set new size */ -// memmask = val-1; /* and addr mask */ - for (i = MEMSIZE; i < MAXMEMSIZE; i++) - M[i] = 0; /* zero all of the new memory */ - return SCPE_OK; /* we done */ -} - -/* Handle execute history */ - -/* Set history */ -t_stat -cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ - int32 i, lnt; - t_stat r; - - if (cptr == NULL) { /* check for any user options */ - for (i = 0; i < hst_lnt; i++) /* none, so just zero the history */ - hst[i].psd1 = 0; /* just psd1 for now */ - hst_p = 0; /* start at teh beginning */ - return SCPE_OK; /* all OK */ - } - /* the user has specified options, process them */ - lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r); - if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; /* arg error for bad input or too small a value */ - hst_p = 0; /* start at beginning */ - if (hst_lnt) { /* if a new length was input, resize history buffer */ - free(hst); /* out with the old */ - hst_lnt = 0; /* no length anymore */ - hst = NULL; /* and no pointer either */ - } - if (lnt) { /* see if new size specified, if so get new resized buffer */ - hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt); - if (hst == NULL) - return SCPE_MEM; /* allocation error, so tell user */ - hst_lnt = lnt; /* set new length */ - } - return SCPE_OK; /* we are good to go */ -} - -/* Show history */ -t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc) -{ - int32 k, di, lnt; - char *cptr = (char *) desc; - t_stat r; - t_value sim_eval; - struct InstHistory *h; - - if (hst_lnt == 0) /* see if show history is enabled */ - return SCPE_NOFNC; /* no, so are out of here */ - if (cptr) { /* see if user provided a display count */ - lnt = (int32) get_uint(cptr, 10, hst_lnt, &r); /* get the count */ - if ((r != SCPE_OK) || (lnt == 0)) /* if error or 0 count */ - return SCPE_ARG; /* report argument error */ - } else - lnt = hst_lnt; /* dump all the entries */ - di = hst_p - lnt; /* work forward */ - if (di < 0) - di = di + hst_lnt; /* wrap */ - fprintf(st, "PSD1 PSD2 INST DEST SRC CC\n"); - for (k = 0; k < lnt; k++) { /* print specified entries */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - /* display the instruction and results */ - fprintf(st, "%08x %08x %08x %08x %08x %1x", - h->psd1, h->psd2, h->inst, h->dest, h->src, h->cc); - fputc('\n', st); /* end line */ - } /* end for */ - return SCPE_OK; /* all is good */ -} - -/* return description for the specified device */ -const char *cpu_description (DEVICE *dptr) -{ -//fprintf(stderr, "WE are here 5 \n"); - return "SEL 32 CPU"; /* return description */ -} - -t_stat -cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) -{ - fprintf (st, "The CPU can be set to \n"); - fprintf (st, "The CPU can maintain a history of the most recently executed instructions.\n"); - fprintf (st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n"); - fprintf (st, " sim> SET CPU HISTORY clear history buffer\n"); - fprintf (st, " sim> SET CPU HISTORY=0 disable history\n"); - fprintf (st, " sim> SET CPU HISTORY=n{:file} enable history, length = n\n"); - fprintf (st, " sim> SHOW CPU HISTORY print CPU history\n"); - return SCPE_OK; -} - +/* sel32_cpu.c: Sel 32 CPU simulator + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include "sel32_defs.h" + +/* 32/7x PSW/PSD Mode Trap/Interrupt Priorities */ +/* Relative Logical Int Vect TCW IOCD Description */ +/* Priority Priority Location Addr Addr */ +/* 0 0F4 Power Fail Safe Trap */ +/* 1 0FC System Override Trap (Not Used) */ +/* 2 0E8* Memory Parity Trap */ +/* 3 190 Nonpresent Memory Trap */ +/* 4 194 Undefined Instruction Trap */ +/* 5 198 Privilege Violation Trap */ +/* 6 180 Supervisor Call Trap (SVC) */ +/* 7 184 Machine Check Trap */ +/* 8 188 System Check Trap */ +/* 9 18C Map Fault Trap */ +/* A Not Used */ +/* B Not Used */ +/* C Not Used */ +/* D Not Used */ +/* E 0E4 Block Mode Timeout Trap */ +/* F 1A4* Arithmetic Exception Trap */ +/* 10 00 0F0 Power Fail Safe Interrupt */ +/* 11 01 0F8 System Override Interrupt */ +/* 12 12 0E8* Memory Parity Trap */ +/* 13 13 0EC Attention Interrupt */ +/* 14 14 140 100 700 I/O Channel 0 interrupt */ +/* 15 15 144 104 708 I/O Channel 1 interrupt */ +/* 16 16 148 108 710 I/O Channel 2 interrupt */ +/* 17 17 14C 10C 718 I/O Channel 3 interrupt */ +/* 18 18 150 110 720 I/O Channel 4 interrupt */ +/* 19 19 154 114 728 I/O Channel 5 interrupt */ +/* 1A 1A 158 118 730 I/O Channel 6 interrupt */ +/* 1B 1B 15C 11C 738 I/O Channel 7 interrupt */ +/* 1C 1C 160 120 740 I/O Channel 8 interrupt */ +/* 1D 1D 164 124 748 I/O Channel 9 interrupt */ +/* 1E 1E 168 128 750 I/O Channel A interrupt */ +/* 1F 1F 16C 12C 758 I/O Channel B interrupt */ +/* 20 20 170 130 760 I/O Channel C interrupt */ +/* 21 21 174 134 768 I/O Channel D interrupt */ +/* 22 22 178 138 770 I/O Channel E interrupt */ +/* 23 23 17C 13C 778 I/O Channel F interrupt */ +/* 24 24 190* Nonpresent Memory Trap */ +/* 25 25 194* Undefined Instruction Trap */ +/* 26 26 198* Privlege Violation Trap */ +/* 27 27 19C Call Monitor Interrupt */ +/* 28 28 1A0 Real-Time Clock Interrupt */ +/* 29 29 1A4* Arithmetic Exception Interrupt */ +/* 2A 2A 1A8 External/Software Interrupt */ +/* 2B 2B 1AC External/Software Interrupt */ +/* 2C 2C 1B0 External/Software Interrupt */ +/* 2D 2D 1B4 External/Software Interrupt */ +/* 2E 2E 1B8 External/Software Interrupt */ +/* 2F 2F 1BC External/Software Interrupt */ +/* 30 30 1C0 External/Software Interrupt */ +/* 31 31 1C4 External/Software Interrupt */ +/* THRU THRU THRU THRU */ +/* 77 77 2DC External/Software Interrupt */ +/* 78 2E0 End of IPU Processing Trap (CPU) */ +/* 79 2E4 Start IPU Processing Trap (IPU) */ +/* 7A 2E8 Supervisor Call Trap (IPU) */ +/* 7B 2EC Error Trap (IPU) */ +/* 7C 2F0 Call Monitor Trap (IPU) */ +/* 7D 7D 2F4 Stop IPU Processing Trap (IPU) */ +/* 7E 7E 2F8 External/Software Interrupt */ +/* 7F 7F 2FC External/Software Interrupt */ + +/* Concept 32 PSD Mode Trap/Interrupt Priorities */ +/* Relative|Logical |Int Vect|TCW |IOCD|Description */ +/* Priority|Priority|Location|Addr|Addr */ +/* - 080 Power Fail Safe Trap */ +/* - 084 Power On Trap */ +/* - 088 Memory Parity Trap */ +/* - 08C Nonpresent Memory Trap */ +/* - 090 Undefined Instruction Trap */ +/* - 094 Privilege Violation Trap */ +/* - 098 Supervisor Call Trap (SVC) */ +/* - 09C Machine Check Trap */ +/* - 0A0 System Check Trap */ +/* - 0A4 Map Fault Trap */ +/* - 0A8 Undefined IPU Instruction Trap */ +/* - 0AC Signal CPU or Signal IPU Trap */ +/* - 0B0 Address Specification Trap */ +/* - 0B4 Console Attention Trap */ +/* - 0B8 Privlege Mode Halt Trap */ +/* - 0BC Arithmetic Exception Trap */ +/* */ +/* 0 00 100 External/software Interrupt 0 */ +/* 1 01 104 External/software Interrupt 1 */ +/* 2 02 108 External/software Interrupt 2 */ +/* 3 03 10C External/software Interrupt 3 */ +/* 4 04 110 704 700 I/O Channel 0 interrupt */ +/* 5 05 114 70C 708 I/O Channel 1 interrupt */ +/* 6 06 118 714 710 I/O Channel 2 interrupt */ +/* 7 07 11C 71C 718 I/O Channel 3 interrupt */ +/* 8 08 120 724 720 I/O Channel 4 interrupt */ +/* 9 09 124 72C 728 I/O Channel 5 interrupt */ +/* A 0A 128 734 730 I/O Channel 6 interrupt */ +/* B 0B 12C 73C 738 I/O Channel 7 interrupt */ +/* C 0C 130 744 740 I/O Channel 8 interrupt */ +/* D 0D 134 74C 748 I/O Channel 9 interrupt */ +/* E 0E 138 754 750 I/O Channel A interrupt */ +/* F 0F 13C 75C 758 I/O Channel B interrupt */ +/* 10 10 140 764 760 I/O Channel C interrupt */ +/* 11 11 144 76C 768 I/O Channel D interrupt */ +/* 12 12 148 774 770 I/O Channel E interrupt */ +/* 13 13 14c 77C 778 I/O Channel F interrupt */ +/* 14 14 150 External/Software Interrupt */ +/* 15 15 154 External/Software Interrupt */ +/* 16 16 158 External/Software Interrupt */ +/* 17 17 15C External/Software Interrupt */ +/* 18 18 160 Real-Time Clock Interrupt */ +/* 19 19 164 External/Software Interrupt */ +/* 1A 1A 1A8 External/Software Interrupt */ +/* 1B 1B 1AC External/Software Interrupt */ +/* 1C 1C 1B0 External/Software Interrupt */ +/* THRU THRU THRU THRU */ +/* 6C 6C 2B0 External/Software Interrupt */ +/* 6D 6D 2B4 External/Software Interrupt */ +/* 6E 6E 2B8 External/Software Interrupt */ +/* 6F 6F 2BC Interval Timer Interrupt */ + +/* IVL ------------> ICB Trap/Interrupt Vector Location points to Interrupt Context Block */ +/* Wd 0 - Old PSD Word 1 points to return location */ +/* Wd 1 - Old PSD Word 2 */ +/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ +/* Wd 3 - New PSD Word 2 */ +/* Wd 4 - CPU Status word at time of interrupt/trap */ +/* Wd 5 - N/U For Traps/Interrupts */ + +/* IVL ------------> ICB XIO Interrupt Vector Location */ +/* Wd 0 - Old PSD Word 1 points to return location */ +/* Wd 1 - Old PSD Word 2 */ +/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ +/* Wd 3 - New PSD Word 2 */ +/* Wd 4 - Input/Output Command List Address (IOCL) for the Class F I/O CHannel */ +/* Wd 5 - 24 bit real address of the channel status word */ + +/* CPU registers, map cache, spad, and other variables */ +int traceme = 0; /* dynamic trace function */ +int trstart = 9981910; /* count of when to start tracing */ +//int trstart = 37; /* count of when to start tracing */ +int cpu_index; /* Current CPU running */ +uint32 PSD[2]; /* the PC for the instruction */ +#define PSD1 PSD[0] /* word 1 of PSD */ +#define PSD2 PSD[1] /* word 2 of PSD */ +uint32 M[MAXMEMSIZE] = { 0 }; /* Memory */ +uint32 GPR[8]; /* General Purpose Registers */ +uint32 BR[8]; /* Base registers */ +uint32 PC; /* Program counter */ +uint32 CC; /* Condition codes, bits 1-4 of PSD1 */ +uint32 SPAD[256]; /* Scratch pad memory */ +uint32 INTS[112]; /* Interrupt status flags */ +uint32 CPUSTATUS; /* cpu status word */ +uint32 TRAPSTATUS; /* trap status word */ +/* CPU mapping cache entries */ +/* 32/55 has none */ +/* 32/7x has 32 8KW maps per task */ +/* Concept/32 has 2048 2KW maps per task */ +uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */ +uint32 HIWM = 0; /* max maps loaded so far */ + +uint32 modes; /* Operating modes, bits 0, 5, 6, 7 of PSD1 */ +uint8 wait4int = 0; /* waiting for interrupt if set */ + +/* define traps */ +uint32 TRAPME = 0; /* trap to be executed */ +uint32 attention_trap = 0; /* set when trap is requested */ + +struct InstHistory +{ + uint32 psd1; /* the PC for the instruction */ + uint32 psd2; /* the PC for the instruction */ + uint32 inst; /* the instruction itself */ + uint32 ea; /* computed effective address of data */ + uint32 reg; /* reg for operation */ + uint32 dest; /* destination value */ + uint32 src; /* source value */ + uint8 cc; /* cc's */ +}; + +/* forward definitions */ +t_stat cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw); +t_stat cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw); +t_stat cpu_reset(DEVICE * dptr); +t_stat cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc); +t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev); +t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *cpu_description (DEVICE *dptr); +t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot); +t_stat load_maps(uint32 thepsd[2]); +t_stat read_instruction(uint32 thepsd[2], uint32 *instr); +t_stat Mem_read(uint32 addr, uint32 *data); +t_stat Mem_write(uint32 addr, uint32 *data); + +/* external definitions */ +extern t_stat startxio(uint16 addr, uint32 *status); /* XIO start in chan.c */ +extern t_stat testxio(uint16 addr, uint32 *status); /* XIO test in chan.c */ +extern t_stat stopxio(uint16 addr, uint32 *status); /* XIO stop in chan.c */ +extern t_stat rschnlxio(uint16 addr, uint32 *status); /* reset channel XIO */ +extern t_stat haltxio(uint16 addr, uint32 *status); /* halt XIO */ +extern t_stat grabxio(uint16 addr, uint32 *status); /* grab XIO n/u */ +extern t_stat rsctlxio(uint16 addr, uint32 *status); /* reset controller XIO */ +extern t_stat chan_set_devs(); /* set up the defined devices on the simulator */ +extern uint32 scan_chan(void); /* go scan for I/O int pending */ +extern uint16 loading; /* set when doing IPL */ +extern int fprint_inst(FILE *of, uint32 val, int32 sw); /* instruction print function */ +extern int irq_pend; /* go scan for pending interrupt */ +extern void rtc_setup(int ss, uint32 level); /* tell rtc to start/stop */ +extern void itm_setup(int ss, uint32 level); /* tell itm to start/stop */ +extern int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level); /* read/write the interval timer */ +extern int32 itm_srv(UNIT *uptr); /* read/write the interval timer */ +extern UNIT itm_unit; /* fake interval timer */ + +/* History information */ +int32 hst_p = 0; /* History pointer */ +int32 hst_lnt = 0; /* History length */ +struct InstHistory *hst = NULL; /* History stack */ + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + pu_mod CPU modifiers list +*/ + +#ifdef DEFINED_IN_SIM_DEFS_H +/* Unit data structure from sim_defs.h + + Parts of the unit structure are device specific, that is, they are + not referenced by the simulator control package and can be freely + used by device simulators. Fields starting with 'buf', and flags + starting with 'UF', are device specific. The definitions given here + are for a typical sequential device. +*/ + +struct UNIT { + UNIT *next; /* next active */ + t_stat (*action)(UNIT *up); /* action routine */ + char *filename; /* open file name */ + FILE *fileref; /* file reference */ + void *filebuf; /* memory buffer */ + uint32 hwmark; /* high water mark */ + int32 time; /* time out */ + uint32 flags; /* flags */ + uint32 dynflags; /* dynamic flags */ + t_addr capac; /* capacity */ + t_addr pos; /* file position */ + void (*io_flush)(UNIT *up); /* io flush routine */ + uint32 iostarttime; /* I/O start time */ + int32 buf; /* buffer */ + int32 wait; /* wait */ + int32 u3; /* device specific */ + int32 u4; /* device specific */ + int32 u5; /* device specific */ + int32 u6; /* device specific */ + void *up7; /* device specific */ + void *up8; /* device specific */ + uint16 us9; /* device specific */ + uint16 us10; /* device specific */ + void *tmxr; /* TMXR linkage */ + t_bool (*cancel)(UNIT *); + double usecs_remaining; /* time balance for long delays */ + char *uname; /* Unit name */ +#ifdef SIM_ASYNCH_IO + void (*a_check_completion)(UNIT *); + t_bool (*a_is_active)(UNIT *); + UNIT *a_next; /* next asynch active */ + int32 a_event_time; + ACTIVATE_API a_activate_call; + /* Asynchronous Polling control */ + /* These fields should only be referenced when holding the sim_tmxr_poll_lock */ + t_bool a_polling_now; /* polling active flag */ + int32 a_poll_waiter_count; /* count of polling threads */ + /* waiting for this unit */ + /* Asynchronous Timer control */ + double a_due_time; /* due time for timer event */ + double a_due_gtime; /* due time (in instructions) for timer event */ + double a_usec_delay; /* time delay for timer event */ +#endif /* SIM_ASYNCH_IO */ + }; + +/* Unit flags */ + +#define UNIT_V_UF_31 12 /* dev spec, V3.1 */ +#define UNIT_V_UF 16 /* device specific */ +#define UNIT_V_RSV 31 /* reserved!! */ +#define FEAT_TIMER (1<<(UNIT_V_UF+12)) /* interval timer */ +#define TMR_RTC 0 + +#define UNIT_ATTABLE 0000001 /* attachable */ +#define UNIT_RO 0000002 /* read only */ +#define UNIT_FIX 0000004 /* fixed capacity */ +#define UNIT_SEQ 0000010 /* sequential */ +#define UNIT_ATT 0000020 /* attached */ +#define UNIT_BINK 0000040 /* K = power of 2 */ +#define UNIT_BUFABLE 0000100 /* bufferable */ +#define UNIT_MUSTBUF 0000200 /* must buffer */ +#define UNIT_BUF 0000400 /* buffered */ +#define UNIT_ROABLE 0001000 /* read only ok */ +#define UNIT_DISABLE 0002000 /* disable-able */ +#define UNIT_DIS 0004000 /* disabled */ +#define UNIT_IDLE 0040000 /* idle eligible */ +#endif /* DEFINED_IN_SIM_DEFS_H */ + +UNIT cpu_unit = + /* Unit data layout for CPU */ +/* { UDATA(rtc_srv, UNIT_BINK | MODEL(MODEL_27) | MEMAMOUNT(0), MAXMEMSIZE ), 120 }; */ + { + NULL, /* UNIT *next */ /* next active */ + NULL, /* t_stat (*action) */ /* action routine */ + NULL, /* char *filename */ /* open file name */ + NULL, /* FILE *fileref */ /* file reference */ + NULL, /* void *filebuf */ /* memory buffer */ + 0, /* uint32 hwmark */ /* high water mark */ + 0, /* int32 time */ /* time out */ + UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(1), /* uint32 flags */ /* flags */ + 0, /* uint32 dynflags */ /* dynamic flags */ + MAXMEMSIZE, /* t_addr capac */ /* capacity */ + 0, /* t_addr pos */ /* file position */ + NULL, /* void (*io_flush) */ /* io flush routine */ + 0, /* uint32 iostarttime */ /* I/O start time */ + 0, /* int32 buf */ /* buffer */ + 80, /* int32 wait */ /* wait */ +}; + +/* Register data structure definition from sim_defs.h */ +#ifdef DEFINED_IN_SIM_DEFS_H +struct REG { + CONST char *name; /* name */ + void *loc; /* location */ + uint32 radix; /* radix */ + uint32 width; /* width */ + uint32 offset; /* starting bit */ + uint32 depth; /* save depth */ + const char *desc; /* description */ + BITFIELD *fields; /* bit fields */ + uint32 qptr; /* circ q ptr */ + size_t str_size; /* structure size */ + /* NOTE: Flags MUST always be last since it is initialized outside of macro definitions */ + uint32 flags; /* flags */ + }; + +/* Register flags from sim_defs.h */ +#define REG_FMT 00003 /* see PV_x */ +#define REG_RO 00004 /* read only */ +#define REG_HIDDEN 00010 /* hidden */ +#define REG_NZ 00020 /* must be non-zero */ +#define REG_UNIT 00040 /* in unit struct */ +#define REG_STRUCT 00100 /* in structure array */ +#define REG_CIRC 00200 /* circular array */ +#define REG_VMIO 00400 /* use VM data print/parse */ +#define REG_VMAD 01000 /* use VM addr print/parse */ +#define REG_FIT 02000 /* fit access to size */ +#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ + +#define REG_V_UF 16 /* device specific */ +#define REG_UFMASK (~((1u << REG_V_UF) - 1)) /* user flags mask */ +#define REG_VMFLAGS (REG_VMIO | REG_UFMASK) /* call VM routine if any of these are set */ +#endif /* DEFINED_IN_SIM_DEFS_H */ + +//UNIT cpu_unit = { UDATA (&rtc_srv, UNIT_BINK, MAXMEMSIZE) }; + +REG cpu_reg[] = { + {HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT}, + {BRDATAD(PSD, PSD, 16, 32, 2, "Progtam 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(SPAD, SPAD, 16, 32, 256, "CPU Scratchpad memory"), REG_FIT}, + {BRDATAD(MAPC, MAPC, 16, 32, 1024, "CPU mape cache"), REG_FIT}, + {HRDATAD(CPUSTATUS, CPUSTATUS, 32, "CPU Status Word"), REG_FIT}, + {HRDATAD(TRAPSTATUS, TRAPSTATUS, 32, "TRAP Status Word"), REG_FIT}, + {HRDATAD(CC, CC, 32, "Condition Codes"), REG_FIT}, + {BRDATAD(INTS, INTS, 16, 32, 112, "Interrupt Status"), REG_FIT}, +// {ORDATAD(BASE, baseaddr, 16, "Relocation base"), REG_FIT}, + {NULL} +}; + +/* Modifier table layout (MTAB) - only extended entries have disp, reg, or flags */ +MTAB cpu_mod[] = { + { + /* MTAB table layout for cpu type */ + /* {UNIT_MODEL, MODEL(MODEL_55), "32/55", "32/55", NULL, NULL, NULL, "Concept 32/55"}, */ + UNIT_MODEL, /* uint32 mask */ /* mask */ + MODEL(MODEL_55), /* uint32 match */ /* match */ + "32/55", /* cchar *pstring */ /* print string */ + "32/55", /* cchar *mstring */ /* match string */ + NULL, /* t_stat (*valid) */ /* validation routine */ + NULL, /* t_stat (*disp) */ /* display routine */ + NULL, /* void *desc */ /* value descriptor, REG* if MTAB_VAL, int* if not */ + "Concept 32/55", /* cchar *help */ /* help string */ + }, + {UNIT_MODEL, MODEL(MODEL_75), "32/75", "32/75", NULL, NULL, NULL, "Concept 32/75"}, + {UNIT_MODEL, MODEL(MODEL_27), "32/27", "32/27", NULL, NULL, NULL, "Concept 32/27"}, + {UNIT_MODEL, MODEL(MODEL_67), "32/67", "32/67", NULL, NULL, NULL, "Concept 32/67"}, + {UNIT_MODEL, MODEL(MODEL_87), "32/87", "32/87", NULL, NULL, NULL, "Concept 32/87"}, + {UNIT_MODEL, MODEL(MODEL_97), "32/97", "32/97", NULL, NULL, NULL, "Concept 32/97"}, + {UNIT_MODEL, MODEL(MODEL_V6), "V6", "V6", NULL, NULL, NULL, "Concept V6"}, + {UNIT_MODEL, MODEL(MODEL_V9), "V9", "V9", NULL, NULL, NULL, "Concept V9"}, + { + /* MTAB table layout for cpu memory size */ + /* {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &cpu_set_size}, */ + UNIT_MSIZE, /* uint32 mask */ /* mask */ + MEMAMOUNT(0), /* uint32 match */ /* match */ + "128K", /* cchar *pstring */ /* print string */ + "128K", /* cchar *mstring */ /* match string */ + &cpu_set_size, /* t_stat (*valid) */ /* validation routine */ + NULL, /* t_stat (*disp) */ /* display routine */ + NULL, /* void *desc */ /* value descriptor, REG* if MTAB_VAL, int* if not */ + NULL, /* cchar *help */ /* help string */ + }, + {UNIT_MSIZE, MEMAMOUNT(1), "256K", "256K", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(2), "512K", "512K", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(3), "1M", "1M", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(4), "2M", "2M", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(5), "3M", "3M", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(6), "4M", "4M", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(7), "8M", "8M", &cpu_set_size}, + {UNIT_MSIZE, MEMAMOUNT(8), "16M", "16M", &cpu_set_size}, + {MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY", + &cpu_set_hist, &cpu_show_hist}, + {0} +}; + +/* CPU device descriptor */ +DEVICE cpu_dev = { + /* "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 24, 1, 8, 32, + &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL, + NULL, DEV_DEBUG, 0, dev_debug, + NULL, NULL, &cpu_help, NULL, NULL, &cpu_description */ + "CPU", /* cchar *name */ /* device name */ + &cpu_unit, /* UNIT *units */ /* unit array */ + cpu_reg, /* REG *registers */ /* register array */ + cpu_mod, /* MTAB *modifiers */ /* modifier array */ + 1, /* uint32 numunits */ /* number of units */ + 16, /* uint32 aradix */ /* address radix */ + 24, /* uint32 awidth */ /* address width */ + 2, /* uint32 aincr */ /* address increment */ + 16, /* uint32 dradix */ /* data radix */ + 32, /* uint32 dwidth */ /* data width */ + &cpu_ex, /* t_stat (*examine) */ /* examine routine */ + &cpu_dep, /* t_stat (*deposit) */ /* deposit routine */ + &cpu_reset, /* t_stat (*reset) */ /* reset routine */ + NULL, /* t_stat (*boot) */ /* boot routine */ + NULL, /* t_stat (*attach) */ /* attach routine */ + NULL, /* t_stat (*detach) */ /* detach routine */ + NULL, /* void *ctxt */ /* (context) device information block pointer */ + DEV_DEBUG, /* uint32 flags */ /* device flags */ + 0, /* uint32 dctrl */ /* debug control flags */ + dev_debug, /* DEBTAB *debflags */ /* debug flag name array */ + NULL, /* t_stat (*msize) */ /* memory size change routine */ + NULL, /* char *lname */ /* logical device name */ + &cpu_help, /* t_stat (*help) */ /* help function */ + NULL, /* t_stat (*attach_help) */ /* attach help function */ + NULL, /* void *help_ctx */ /* Context available to help routines */ + &cpu_description, /* cchar *(*description) */ /* Device description */ + NULL, /* BRKTYPTB *brk_types */ /* Breakpoint types */ +}; + +/* CPU Instruction decode flags */ +#define INV 0x0000 /* Instruction is invalid */ +#define HLF 0x0001 /* Half word instruction */ +#define ADR 0x0002 /* Normal addressing mode */ +#define IMM 0x0004 /* Immediate mode */ +#define WRD 0x0008 /* Word addressing, no index */ +#define SCC 0x0010 /* Sets CC */ +#define RR 0x0020 /* Read source register */ +#define R1 0x0040 /* Read destination register */ +#define RB 0x0080 /* Read base register into dest */ +#define SD 0x0100 /* Stores into destination register */ +#define SDD 0x0200 /* Stores double into destination */ +#define RM 0x0400 /* Reads memory */ +#define SM 0x0800 /* Stores memory */ +#define DBL 0x1000 /* Double word operation */ +#define SB 0x2000 /* Store Base register */ +#define BT 0x4000 /* Branch taken, no PC incr */ + +int nobase_mode[] = { + /* 00 04 08 0C */ + /* 00 ANR, ORR, EOR */ + HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, + /* 10 14 18 1C */ + /* CAR, CMR, SBR ZBR */ + HLF, HLF, HLF, HLF, + /* 20 24 28 2C */ + /* ABR TBR REG TRR */ + HLF, HLF, HLF, HLF, + /* 30 34 38 3C */ + /* CALM LA ADR SUR */ + HLF, SD|ADR, HLF, HLF, + /* 40 44 48 4C */ + /* MPR DVR */ + SD|HLF, HLF, INV, INV, + /* 50 54 58 5C */ + /* */ + INV, INV, INV, INV, + + /* 60 64 68 6C */ + /* NOR NORD SCZ SRA */ + SD|HLF, SDD|HLF, HLF, HLF, + + /* 70 74 78 7C */ + /* SRL SRC SRAD SRLD */ + SD|HLF, SD|HLF, HLF, HLF, + + /* 80 84 88 8C */ + /* LEAR ANM ORM EOM */ + SD|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR, + + /* 90 94 98 9C */ + /* CAM CMM SBM ZBM */ + SCC|RR|RM|ADR, RR|RM|ADR, ADR, ADR, + + /* A0 A4 A8 AC */ + /* ABM TBM EXM L */ + ADR, ADR, ADR, SCC|SD|RM|ADR, + + /* B0 B4 B8 BC */ + /* LM LN ADM SUM */ + SCC|SD|RM|ADR, SCC|SD|RM|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR, + + /* C0 C4 C8 CC */ + /* MPM DVM IMM LF */ + SCC|SD|RM|ADR, RM|ADR, IMM, ADR, + + /* D0 D4 D8 DC */ + /* LEA ST STM STF */ + SD|ADR, RR|SM|ADR, RR|SM|ADR, ADR, + + /* E0 E4 E8 EC */ + /* ADF MPF ARM BCT */ + SCC|SD|RM|ADR, SCC|RM|ADR, SCC|SM|RR|RM|ADR, ADR, + + /* F0 F4 F8 FC */ + /* BCF BI MISC IO */ + ADR, RR|SD|WRD, ADR, IMM, +}; + +int base_mode[] = { + /* 00 04 08 0C */ + /* 00 AND, OR, EOR */ + HLF, SCC|RR|SD|HLF, SCC|RR|SD|HLF, SCC|RR|SD|HLF, + /* 10 14 18 1C */ + /* SACZ CMR xBR SRx */ + HLF, HLF, HLF, HLF, + /* 20 24 28 2C */ + /* SRxD SRC REG TRR */ + SD|HLF, SD|HLF, HLF, HLF, + /* 30 34 38 3C */ + /* LA FLRop SUR */ + INV, INV, SD|HLF, SD|HLF, + /* 40 44 48 4C */ + /* */ + INV, INV, INV, INV, + + /* 50 54 58 5C */ + /* LA BASE BASE CALLM */ + SD|ADR, SM,ADR, SB|RM|ADR, ADR, + + /* 60 64 68 6C */ + /* */ + INV, INV, INV, INV, + /* 70 74 78 7C */ + /* */ + INV, INV, INV, INV, + /* LEAR ANM ORM EOM */ + /* 80 84 88 8C */ + SD|ADR, SD|RM|ADR, SD|RM|ADR, SD|RM|ADR, + + /* CAM CMM SBM ZBM */ + /* 90 94 98 9C */ + RM|ADR, RM|ADR, ADR, ADR, + + /* A0 A4 A8 AC */ + /* ABM TBM EXM L */ + ADR, ADR, ADR, SD|RM|ADR, + + /* B0 B4 B8 BC */ + /* LM LN ADM SUM */ + SD|RM|ADR,SD|RM|ADR, SD|RM|ADR, SD|RM|ADR, + + /* C0 C4 C8 CC */ + /* MPM DVM IMM LF */ + SD|RM|ADR, RM|ADR, IMM, ADR, + + /* D0 D4 D8 DC */ + /* LEA ST STM STFBR */ + SD|ADR, SM|ADR, SM|ADR, ADR, + /* E0 E4 E8 EC */ + /* ADF MPF ARM BCT */ + SD|RM|ADR, RM|ADR, SM|RM|ADR, ADR, + /* F0 F4 F8 FC */ + /* BCF BI MISC IO */ + ADR, RR|SB|WRD, ADR, IMM, +}; + +/* set up the map registers for the current task in the cpu */ +/* the PSD bpix and cpix are used to setup the maps */ +/* return non-zero if mapping error */ +t_stat load_maps(uint32 thepsd[2]) +{ + uint32 num, sdc, spc; + uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl; + uint32 cpix, bpix, i, j, map, osmidl; + + if (CPU_MODEL < MODEL_27) + { + /* 32/7x machine, 8KW maps */ + modes &= ~BASEBIT; /* no basemode on 7x */ + if ((thepsd[1] & 0xc0000000) == 0) { /* mapped mode? */ + return ALLOK; /* no, all OK, no mapping required */ + } + /* we are mapped, so load the maps for this task into the cpu map cache */ + cpix = (thepsd[1] >> 2) & 0xfff; /* get cpix 12 bit offset from psd wd 2 */ + bpix = (thepsd[1] >> 18) & 0xfff; /* get bpix 12 bit offset from psd wd 2 */ + num = 0; /* working map number */ + /* master process list is in 0x83 of spad for 7x */ + mpl = SPAD[0x83] >> 2; /* get mpl from spad address */ + cpixmsdl = M[mpl + cpix]; /* get msdl from mpl for given cpix */ + /* if bit zero of mpl entry is set, use bpix first to load maps */ + if (cpixmsdl & BIT0) + { + /* load bpix maps first */ + bpixmsdl = M[mpl + bpix]; /* get bpix msdl word address */ + sdc = (bpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */ + msdl = (bpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */ + for (i = 0; i < sdc; i++) /* loop through the msd's */ + { + spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */ + midl = (M[msdl + i] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */ + for (j = 0; j < spc; j++) + { + /* load 16 bit map descriptors */ + map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ + if (j & 1) + map = (map & RMASK); /* use right half word map entry */ + else + map = ((map >> 16) & RMASK); /* use left half word map entry */ + /* the map register contents is now in right 16 bits */ + /* now load a 32 bit word with both maps from memory */ + /* and or in the new map entry data */ + if (num & 1) { + /* entry going to rt hw, clean it first */ + map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ + } + else { + /* entry going to left hw, clean it first */ + map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ + } + MAPC[num++/2] = map; /* store the map reg contents into cache */ + if (num >= 32) + return MAPFLT; /* map loading overflow, map fault error */ + } + } + } + /* now load cpix maps */ + cpixmsdl = M[mpl + cpix]; /* get cpix msdl word address */ + sdc = (cpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */ + msdl = (cpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */ + for (i = 0; i < sdc; i++) + { + spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */ + midl = (M[msdl + i] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */ + for (j = 0; j < spc; j++) + { + /* load 16 bit map descriptors */ + map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ + if (j & 1) + map = (map & RMASK); /* use right half word map entry */ + else + map = ((map >> 16) & RMASK); /* use left half word map entry */ + /* the map register contents is now in right 16 bits */ + /* now load a 32 bit word with both maps from memory */ + /* and or in the new map entry data */ + if (num & 1) { + /* entry going to rt hw, clean it first */ + map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ + } + else { + /* entry going to left hw, clean it first */ + map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ + } + MAPC[num++/2] = map; /* store the map reg contents into cache */ + if (num >= 32) + return MAPFLT; /* map loading overflow, map fault error */ + } + } + /* if none loaded, map fault */ + if (num == 0) + return MAPFLT; /* map fault error */ + if (num & 1) { /* clear rest of maps */ + /* left hw of map is good, zero right */ + map = (MAPC[num/2] & LMASK); /* clean rt hw */ + MAPC[num++/2] = map; /* store the map reg contents into cache */ + } + /* num should be even at this point, so zero 32 bit word for remaining maps */ + if ((num/2) > HIWM) /* largerst number of maps loaded so far* */ + HIWM = num/2; /* yes, set new high watter mark */ +// for (i = num/2; i < 32/2; i++) /* zero any remaining entries */ + for (i = num/2; i < HIWM; i++) /* zero any remaining entries */ + MAPC[i] = 0; /* clear the map entry to make not valid */ + return ALLOK; /* all cache is loaded, return OK */ + } + else + { + char n[9]; + uint32 dqe; + /* 32/27, 32/67, 32/87, 32/97 2KW maps */ + /* Concept/32 machine, 2KW maps */ + if ((modes & MAPMODE) == 0) { /* mapped mode? */ +// fprintf(stderr, "not mapping PSD2 %x\r\n", PSD2); + return ALLOK; /* no, all OK, no mapping required */ + } + /* we are mapped, so calculate real address from map information */ + cpix = (thepsd[1] >> 2) & 0xfff; /* get word cpix 11 bit offset from psd wd 2 */ + num = 0; /* no maps loaded yet */ + /* master process list is in 0xf3 of spad for concept */ + mpl = SPAD[0xf3] >> 2; /* get mpl from spad address */ + midl = M[mpl+cpix]; /* get mpl entry wd 0 for given cpix */ + msdl = M[mpl+cpix+1]; /* get mpl entry wd 0 for given cpix */ + dqe = M[0x8e8>>2]; + for (j=0; j<8; j++) { + n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff; + if (n[j] == 0) + n[j] = 0x20; + } + n[8] = 0; +// fprintf(stderr, "mapping SPAD PSD2 %.8x PSD2 %x mpl %x osmidl %x umidl %x C.CURR %x LMN %s\r\n", +// SPAD[0xf5], PSD2, mpl, M[mpl], midl, dqe, n); + /* if bit zero of mpl entry is set, use msd entry 0 first to load maps */ + if (midl & BIT0) + { +/* TODO do not load O/S if already loaded. Bit zero of O/S midl will be set by swapper */ + /* load msd 0 maps first (O/S) */ + osmidl = M[mpl]; /* get midl 0 word address */ + spc = osmidl & MASK16; /* get 16 bit segment description count */ + if (osmidl & BIT0) { /* see f O/S already loaded */ + num = spc; /* set the number of o/s maps loaded */ + goto skipos; /* skip load */ + } + midl = M[mpl+1] & MASK24; /* get 24 bit real address from mpl wd2 */ + midl = midl>>2; /* make word address */ + for (j = 0; j < spc; j++) + { + /* load 16 bit map descriptors */ + map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */ + if (j & 1) + map = (map & RMASK); /* use right half word map entry */ + else + map = ((map >> 16) & RMASK); /* use left half word map entry */ + /* the map register contents is now in right 16 bits */ + /* now load a 32 bit word with both maps from memory */ + /* and or in the new map entry data */ + if (num & 1) { + /* entry going to rt hw, clean it first */ + map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ +// fprintf(stderr, "mapping 0x%x O/S num 0x%x midl %x MAPC[%d] %x\r\n", +// spc, num-1, (midl+(j/2))<<2, num/2, map); + } + else { + /* entry going to left hw, clean it first */ + map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ + } + MAPC[num/2] = map; /* store the map reg contents into cache */ + if (++num >= 2048) + return MAPFLT; /* map loading overflow, map fault error */ + } +#if 0 + if (num & 1) + fprintf(stderr, "mapping 0x%x O/S num 0x%x midl %x MAPC[%d] %x\r\n", + spc, num-1, (midl+((spc-1)/2))<<2, num/2, map); +#endif + } +skipos: + /* now load cpix maps */ + midl = M[mpl+cpix]; /* get cpix midl word address */ + msdl = M[mpl+cpix+1]; /* get 24 bit real word address of midl */ + spc = midl & RMASK; /* get segment page count from msdl */ + midl = M[mpl+cpix+1] & MASK24; /* get 24 bit real word address of midl */ + midl = midl>>2; /* get word address of midl */ + for (j = 0; j < spc; j++) + { + /* load 16 bit map descriptors */ + map = M[midl + (j / 2)]; /* get 2 16 bit map entries */ + if (j & 1) + map = (map & RMASK); /* use right half word map entry */ + else + map = ((map >> 16) & RMASK); /* use left half word map entry */ + /* the map register contents is now in right 16 bits */ + /* now load a 32 bit word with both maps from memory */ + /* and or in the new map entry data */ + if (num & 1) { + /* entry going to rt hw, clean it first */ + map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */ +// fprintf(stderr, "mapping 0x%x USER num 0x%x midl %x MAPC[%d] %x\r\n", +// spc, num-1, (midl+(j/2))<<2, num/2, map); + } + else { + /* entry going to left hw, clean it first */ + map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */ + } + MAPC[num/2] = map; /* store the map reg contents into cache */ + if (++num >= 2048) + return MAPFLT; /* map loading overflow, map fault error */ + } + /* if none loaded, map fault */ + /* we got here without map block found, return map fault error */ + if (num == 0) + return MAPFLT; /* map fault error */ + if (num & 1) { + /* left hw of map is good, zero right */ + map = (MAPC[num/2] & LMASK); /* clean rt hw */ +// if (spc != 0) +// fprintf(stderr, "mapping 0x%x USER num 0x%x midl %x MAPC[%d] %x\r\n", +// spc, num-1, (midl+((spc-1)/2))<<2, num/2, map); + MAPC[num++/2] = map; /* store the map reg contents into cache */ + } + /* num should be even at this point, so zero 32 bit words for remaining maps */ + if ((num/2) > HIWM) /* largerst number of maps loaded so far* */ + HIWM = num/2; /* yes, set new high watter mark */ +// for (i = num/2; i < 2048/2; i++) /* zero any remaining entries */ + for (i = num/2; i < HIWM; i++) /* zero any remaining entries */ + MAPC[i] = 0; /* clear the map entry to make not valid */ + return ALLOK; /* all cache is loaded, retun OK */ + } +} + +/* + * Return the real memory address from the logical address + * Also return the protection status, 1 if write protected address + */ +t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot) +{ + uint32 word, index, map, mask; + + *prot = 0; /* show unprotected memory as default */ + /* unmapped mode is unprotected */ + + /* see what machine we have */ + if (CPU_MODEL < MODEL_27) + { + /* 32/7x machine with 8KW maps */ + if (modes & EXTDBIT) + word = addr & 0xfffff; /* get 20 bit logical word address */ + else + word = addr & 0x7ffff; /* get 19 bit logical word address */ + if ((modes & MAPMODE) == 0) { + /* check if valid real address */ + if (word >= MEMSIZE) /* see if address is within our memory */ + return NPMEM; /* no, none present memory error */ + *realaddr = word; /* return the real address */ + return ALLOK; /* all OK, return instruction */ + } + /* we are mapped, so calculate real address from map information */ + /* 32/7x machine, 8KW maps */ + index = word >> 15; /* get 4 or 5 bit value */ + map = MAPC[index/2]; /* get two hw map entries */ + if (index & 1) + /* entry is in rt hw, clear left hw */ + map &= RMASK; /* map is in rt hw */ + else + /* entry is in left hw, move to rt hw */ + map >>= 16; /* map is in left hw */ + /* see if map is valid */ + if (map & 0x4000) { + /* required map is valid, get 9 bit address and merge with 15 bit page offset */ + word = ((map & 0x1ff) << 15) | (word & 0x7fff); + /* check if valid real address */ + if (word >= MEMSIZE) /* see if address is within our memory */ + return NPMEM; /* no, none present memory error */ + if ((modes & PRIVBIT) == 0) { /* see if we are in unprivileged mode */ + if (map & 0x2000) /* check if protect bit is set in map entry */ + *prot = 1; /* return memory write protection status */ + } + *realaddr = word; /* return the real address */ + return ALLOK; /* all OK, return instruction */ + } + /* map is invalid, so return map fault error */ + return MAPFLT; /* map fault error */ + } + else { + /* 32/27, 32/67, 32/87, 32/97 2KW maps */ + /* Concept 32 machine, 2KW maps */ + if (modes & (BASEBIT | EXTDBIT)) + word = addr & 0xffffff; /* get 24 bit address */ + else + word = addr & 0x7ffff; /* get 19 bit address */ + if ((modes & MAPMODE) == 0) { + /* check if valid real address */ + if (word >= MEMSIZE) /* see if address is within our memory */ + return NPMEM; /* no, none present memory error */ + *realaddr = word; /* return the real address */ +//fprintf(stderr, "Read Real unmapped addr %x\r\n", addr, index, map); + return ALLOK; /* all OK, return instruction */ + } + /* replace bits 8-18 with 11 bits from memory map register */ + /* we are mapped, so calculate real address from map information */ + index = (word >> 13) & 0x7ff; /* get 11 bit value */ + map = MAPC[index/2]; /* get two hw map entries */ +//fprintf(stderr, "read addr %x index %x map %x\r\n", addr, index, map); + if (index & 1) + /* entry is in rt hw, clear left hw */ + map &= RMASK; /* map is in rt hw */ + else + /* entry is in left hw, move to rt hw */ + map >>= 16; /* map is in left hw */ +//fprintf(stderr, "read 2 addr %x index %x map %x\r\n", word, index, map); + if (map & 0x8000) { /* see if map is valid */ + /* required map is valid, get 11 bit address and merge with 13 bit page offset */ + word = ((map & 0x7ff) << 13) | (word & 0x1fff); + /* check if valid real address */ + if (word >= MEMSIZE) /* see if address is within our memory */ + return NPMEM; /* no, none present memory error */ + if ((modes & PRIVBIT) == 0) { /* see if we are in unprivileged mode */ + mask = (word & 0x1800) >> 11; /* get offset of 2kb block for map being addressed */ + if (map & (0x4000 >> mask)) /* check if protect bit is set in map entry */ + *prot = 1; /* return memory write protection status */ + } +//fprintf(stderr, "Read Real addr %x index %x map %x reala %x PSD2 %x\r\n", addr, index, map, word, SPAD[0xf5]); + *realaddr = word; /* return the real address */ + return ALLOK; /* all OK, return instruction */ + } + /* map is invalid, so return map fault error */ +// fprintf(stderr, "RealAddr MAP FAIL %x MAPC %x word %x addr %x index %x\n", +// map, MAPC[index/2], word, addr, index); + sim_debug(DEBUG_CMD, &cpu_dev, "RealAddr MAP FAIL %x MAPC %x word %x addr %x index %x\n", + map, MAPC[index/2], word, addr, index); + return MAPFLT; /* map fault error */ + } +} + +/* fetch the current instruction from the PC address */ +t_stat read_instruction(uint32 thepsd[2], uint32 *instr) +{ + uint32 addr, status; + + if (CPU_MODEL < MODEL_27) + { + /* 32/7x machine with 8KW maps */ + /* instruction must be in first 512KB of address space */ + addr = thepsd[0] & 0x7fffc; /* get 19 bit logical word address */ + } + else + { + /* 32/27, 32/67, 32/87, 32/97 2KW maps */ + /* Concept 32 machine, 2KW maps */ + if (thepsd[0] & BASEBIT) { /* bit 6 is base mode? */ + addr = thepsd[0] & 0xfffffc; /* get 24 bit address */ + } + else + addr = thepsd[0] & 0x7fffc; /* get 19 bit address */ + } + status = Mem_read(addr, instr); /* get the instruction at the specified address */ + sim_debug(DEBUG_DETAIL, &cpu_dev, "read_instr status = %x\n", status); + return status; /* return ALLOK or ERROR */ +} + +/* + * Read a full word from memory + * Return error type if failure, ALLOK if + * success. Addr is logical address. + */ +t_stat Mem_read(uint32 addr, uint32 *data) +{ + uint32 status, realaddr, prot; + + status = RealAddr(addr, &realaddr, &prot); /* convert address to real physical address */ + sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_read status = %x\n", status); + if (status == ALLOK) { + *data = M[realaddr >> 2]; /* valid address, get physical address contents */ + status = ALLOK; /* good status return */ + sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_read addr %.8x realaddr %.8x data %.8x prot %d\n", + addr, realaddr, *data, prot); + } + return status; /* return ALLOK or ERROR */ +} + +/* + * Write a full word to memory, checking protection + * and alignment restrictions. Return 1 if failure, 0 if + * success. Addr is logical address, data is 32bit word + */ +t_stat Mem_write(uint32 addr, uint32 *data) +{ + uint32 status, realaddr, prot; + + status = RealAddr(addr, &realaddr, &prot); /* convert address to real physical address */ + sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %d\n", + addr, realaddr, *data, prot); + if (status == ALLOK) { + if (prot) /* check for write protected memory */ + return MPVIOL; /* return memory protection violation */ + M[realaddr >> 2] = *data; /* valid address, put physical address contents */ + status = ALLOK; /* good status return */ + } + return status; /* return ALLOK or ERROR */ +} + +/* function to set the CCs in PSD1 */ +/* ovr is setting for CC1 */ +void set_CCs(uint32 value, int ovr) +{ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (ovr) + CC = CC1BIT; /* CC1 value */ + else + CC = 0; /* CC1 off */ + if (value & FSIGN) + CC |= CC3BIT; /* CC3 for neg */ + else if (value == 0) + CC |= CC4BIT; /* CC4 for zero */ + else + CC |= CC2BIT; /* CC2 for greater than zero */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ +} + +/* Opcode definitions */ +/* called from simulator */ +t_stat +sim_instr(void) +{ + t_stat reason = 0; /* reason for stopping */ + t_uint64 dest; /* Holds destination/source register */ + t_uint64 source; /* Holds source or memory data */ + t_uint64 td; /* Temporary */ + uint32 addr; /* Holds address of last access */ + uint32 temp; /* General holding place for stuff */ + uint32 IR; /* Instruction register */ + uint32 i_flags; /* Instruction description flags from table */ + uint32 t; /* Temporary */ + uint32 temp2; /* Temporary */ + uint32 bc; /* Temporary bit count */ + uint16 opr; /* Top half of Instruction register */ + uint16 OP; /* Six bit instruction opcode */ + uint16 chan; /* I/O channel address */ + uint16 lchan; /* Logical I/O channel address */ + uint16 suba; /* I/O subaddress */ + uint8 FC; /* Current F&C bits */ + uint8 EXM_EXR=0; /* PC Increment for EXM/EXR instructions */ + int reg; /* GPR or Base register bits 6-8 */ + int sreg; /* Source reg in from bits 9-11 reg-reg instructions */ + int ix; /* index register */ + int dbl; /* Double word */ + int ovr; /* Overflow flag */ + int stopnext = 0; /* Stop on next instruction */ + int skipinstr = 0; /* Skip test for interrupt on this instruction */ + uint32 int_icb; /* interrupt context block address */ + uint32 OIR; /* Original Instruction register */ + uint32 OPSD1; /* Original PSD1 */ + uint32 OPC; /* Original PC */ + +wait_loop: + while (reason == 0) { /* loop until halted */ + + // wait_loop: + if (sim_interval <= 0) { /* event queue? */ + reason = sim_process_event(); /* process */ + if (reason != SCPE_OK) { + if (reason == SCPE_STEP) + stopnext = 1; + else + break; /* process */ + } + } + + if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) { + reason = STOP_IBKPT; + break; + } + + /* call our fake interval timer to count down 64 instructions per count */ + itm_srv(&itm_unit); /* service interval timer */ + sim_interval--; /* count down */ + + if (skipinstr) { /* need to skip interrupt test? */ + skipinstr = 0; /* skip only once */ + goto skipi; /* skip int test */ + } + + /* process pending I/O interrupts */ + if (!loading && (wait4int || irq_pend)) { /* see if ints are pending */ + int_icb = scan_chan(); /* no, go scan for I/O int pending */ + if (int_icb != 0) { /* was ICB returned for an I/O or interrupt */ + int il; + /* find interrupt level for icb address */ + for (il=0; il<112; il++) { + /* get the address of the interrupt IVL table in main memory */ + uint32 civl = SPAD[0xf1] + (il<<2); /* contents of spad f1 points to chan ivl in mem */ + civl = M[civl >> 2]; /* get the interrupt context block addr in memory */ + if (civl == int_icb) + break; + } +//sim_debug(DEBUG_EXP, &cpu_dev, "Normal int scan return icb %x\n", int_icb); +//fprintf(stderr, "Normal Interrupt scan return icb %x irq_pend %x wait4int %x\r\n", int_icb, irq_pend, wait4int); + /* take interrupt, store the PSD, fetch new PSD */ + bc = PSD2 & 0x3ffc; /* get copy of cpix */ + M[int_icb>>2] = PSD1&0xfffffffe; /* store PSD 1 */ + M[(int_icb>>2)+1] = PSD2; /* store PSD 2 */ + PSD1 = M[(int_icb>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(int_icb>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */ + /* I/O status DW address will be in WD 6 */ + /* set new map mode and interrupt blocking state in CPUSTATUS */ + modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + if (PSD2 & MAPBIT) { + CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ + modes |= MAPMODE; /* set mapped mode */ + } else + CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */ + if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */ + if (PSD2 & 0x4000) /* no, is it set blocking state */ + CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */ + else + CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */ + } + PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */ + if (CPUSTATUS & 0x80) /* see if old mode is blocked */ + PSD2 |= 0x00004000; /* set to blocked state */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + sim_debug(DEBUG_INST, &cpu_dev, + "Interrupt %x OPSD1 %.8x OPSD2 %.8x NPSD1 %.8x NPSD2 %.8x ICBA %x\r\n", + il, M[int_icb>>2], M[(int_icb>>2)+1], PSD1, PSD2, int_icb); + wait4int = 0; /* wait is over for int */ + skipinstr = 1; /* skip next interrupt test only once */ + } + /* see if waiting at a wait instruction */ + if (wait4int || loading) { +// ???? sim_interval++; /* restore count */ + goto wait_loop; /* continue waiting */ + } + } else { + if (loading) { + uint32 chsa = scan_chan(); /* go scan for load complete pending */ + if (chsa != 0) { /* see if a boot channel/subaddress were returned */ + /* take interrupt, store the PSD, fetch new PSD */ + PSD1 = 0x80000000; /* get new PSD 1, priv and addr is 0 */ + PSD2 = 0x00004000; /* get new PSD 2, blocked */ + modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + sim_debug(DEBUG_INST, &cpu_dev, "Boot Loading PSD1 %.8x PSD2 %.8x\n", PSD1, PSD2); + /* set interrupt blocking state in CPUSTATUS */ + CPUSTATUS |= 0x80; /* set blocked state in cpu status, bit 24 too */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + loading = 0; /* we are done loading */ + skipinstr = 1; /* skip next interrupt test only once */ + } + goto wait_loop; /* continue waiting */ + } + /* see if in wait instruction */ + if (wait4int) /* TRY this */ + goto wait_loop; /* continue waiting */ + } + + /* Check for external interrupt here */ + /* see if we have an attention request from console */ + if (!skipinstr && attention_trap) { + TRAPME = attention_trap; /* get trap number */ + attention_trap = 0; /* do only once */ +// fprintf(stderr, "Attention TRAP %x\r\n", TRAPME); + skipinstr = 1; /* skip next interrupt test only once */ + goto newpsd; /* got process trap */ + } + +skipi: + if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) { + reason = STOP_IBKPT; + break; + } + + /* fill IR from logical memory address */ + if ((TRAPME = read_instruction(PSD, &IR))) { + sim_debug(DEBUG_INST, &cpu_dev, "read_instr TRAPME = %x\n", TRAPME); + goto newpsd; /* got process trap */ + } + + /* If executing right half */ + if (PSD1 & 2) + IR <<= 16; +exec: +/*FIXME temp saves */ + OIR = IR; + OPSD1 = PSD1; + OPC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ + + /* TODO Update history for this instruction */ + if (hst_lnt) + { + hst_p += 1; /* next history location */ + if (hst_p >= hst_lnt) /* check for wrap */ + hst_p = 0; /* start over at beginning */ + hst[hst_p].psd1 = PSD1; /* set execution address */ + hst[hst_p].psd2 = PSD2; /* set mapping/blocking status */ + } + + /* Split instruction into pieces */ + PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ + sim_debug(DEBUG_DATA, &cpu_dev, "-----Instr @ PC %x PSD1 %.8x PSD2 %.8x IR %.8x\n", PC, PSD1, PSD2, IR); + opr = (IR >> 16) & MASK16; /* use upper half of instruction */ + OP = (opr >> 8) & 0xFC; /* Get opcode (bits 0-5) left justified */ + FC = ((IR & F_BIT) ? 0x4 : 0) | (IR & 3); /* get F & C bits for addressing */ + reg = (opr >> 7) & 0x7; /* dest reg or xr on base mode */ + sreg = (opr >> 4) & 0x7; /* src reg for reg-reg instructions or BR instr */ + dbl = 0; /* no doubleword instruction */ + ovr = 0; /* no overflow or arithmetic exception either */ + dest = (t_uint64)IR; /* assume memory address specified */ + CC = PSD1 & 0x78000000; /* save CC's if any */ + + if (modes & BASEBIT) { + i_flags = base_mode[OP>>2]; /* set the instruction processing flags */ + addr = IR & RMASK; /* get address offset from instruction */ +// sim_debug(DEBUG_INST, &cpu_dev, "Base i_flags %x addr %.8x\n", i_flags, addr); + switch(i_flags & 0xf) { + case HLF: + source = GPR[sreg]; /* get the src reg from instruction */ + break; + case IMM: + if (PC & 02) { /* if pc is on HW boundry, bad address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + break; + case ADR: + case WRD: + if (PC & 02) { /* if pc is on HW boundry, bad address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + ix = (IR >> 20) & 7; /* get index reg from instruction */ + if (ix != 0) + addr += GPR[ix]; /* if not zero, add in reg contents */ + ix = (IR >> 16) & 7; /* get base reg from instruction */ + if (ix != 0) + addr += BR[ix]; /* if not zero, add to base reg contents */ + FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */ + FC |= addr & 3; /* set new C bits to address from orig or regs */ + break; + case INV: + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + break; + } + } else { + i_flags = nobase_mode[OP>>2]; /* set the instruction processing flags */ + addr = IR & 0x7ffff; /* get 19 bit address from instruction */ + +// sim_debug(DEBUG_INST, &cpu_dev, "Non Based i_flags %x addr %.8x\n", i_flags, addr); + /* non base mode instructions have bit 0 of the instruction set */ + /* for word length instructions and zero for halfword instructions */ + /* the LA (op=0x34) is the only exception. So test for PC on a halfword */ + /* address and trap if word opcode is in right hw */ + if (PC & 02) { /* if pc is on HW boundry, addr trap if bit zero set */ + if ((OP == 0x34) || (OP & 0x80)) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + } + switch(i_flags & 0xf) { + case HLF: /* halfword instruction */ + source = GPR[sreg]; /* get the src reg contents */ + break; + + case IMM: /* Immediate mode */ + if (PC & 02) { /* if pc is on HW boundry, bad address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + break; + + case ADR: /* Normal addressing mode */ + ix = (IR >> 21) & 3; /* get the index reg if specified */ + if (ix != 0) { + addr += GPR[ix]; /* if not zero, add in reg contents */ + FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */ + FC |= addr & 3; /* set new C bits to address from orig or regs */ + } + + /* wart alert! */ + /* the lea instruction requires special handling for indirection. */ + /* Bit 0,1 are set to 1 of result addr if indirect bit is zero in */ + /* instruction. Bits 0 & 1 are set to the last word */ + /* or instruction in the chain bits 0 & 1 if indirect bit set */ + /* if IX == 00 => dest = IR */ + /* if IX == 0x => dest = IR + reg */ + /* if IX == Ix => dest = ind + reg */ + + /* fall through */ + + case WRD: /* Word addressing, no index */ + bc = 0xC0000000; /* set bits 0, 1 for instruction if not indirect */ + t = IR; /* get current IR */ + while (t & IND) { /* process indirection */ + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + bc = temp & 0xC0000000; /* save new bits 0, 1 from indirect location */ + CC = (temp & 0x78000000); /* save CC's from the last indirect word */ + if (modes & EXTDBIT) { /* check if in extended mode */ + /* extended mode, so location has 24 bit addr, not X,I ADDR */ +// fprintf(stderr, "Indirect EXT before addr %x contents %x\n", addr, temp); + addr = temp & MASK24; /* get 24 bit addr */ + /* if no C bits set, use original, else new */ + if ((IR & F_BIT) || (addr & 3)) + FC = ((IR & F_BIT) ? 0x4 : 0) | (addr & 3); +// fprintf(stderr, "Indirect EXT after addr %x temp %x\n", addr, temp); + t &= ~IND; /* turn off IND bit to stop while loop */ + } else { + /* non-extended mode, process new X, I, ADDR fields */ +// fprintf(stderr, "Indirect NE before addr %x contents %x\n", addr, temp); + addr = temp & MASK19; /* get just the addr */ + ix = (temp >> 21) & 3; /* get the index reg from indirect word */ + if (ix != 0) + addr += (GPR[ix] & MASK19); /* add the register to the address */ + /* if no F or C bits set, use original, else new */ + if ((temp & F_BIT) || (addr & 3)) + FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3); +// fprintf(stderr, "Indirect NE after addr %x temp %x\n", addr, temp); + t = temp; /* go process next indirect location */ + } + } + if (OP == 0xD0) /* test for LEA op */ + addr |= bc; /* insert bits 0,1 values into address */ + dest = (t_uint64)addr; /* make into 64 bit variable */ + break; + case INV: /* Invalid instruction */ + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + break; + } + } + + /* Read memory operand */ + if (i_flags & RM) { + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + source = (t_uint64)temp; /* make into 64 bit value */ + switch(FC) { + case 0: /* word address, extend sign */ + source |= (source & MSIGN) ? D32LMASK : 0; + break; + case 1: /* left hw */ + source >>= 16; /* move left hw to right hw*/ + /* Fall through */ + case 3: /* right hw or right shifted left hw */ + source &= 0xffff; /* use just the right hw */ + if (source & 0x8000) { /* check sign of 16 bit value */ + /* sign extend the value to leftmost 48 bits */ + source = 0xFFFF0000 | (source & 0xFFFF); /* extend low 32 bits */ + source |= (D32LMASK); /* extend hi bits */ + } + break; + case 2: /* double word address */ + if ((addr & 2) != 2) { /* must be double word adddress */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ + goto newpsd; /* memory read error or map fault */ + } + source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */ + dbl = 1; /* double word instruction */ + break; + case 4: /* byte mode, byte 0 */ + case 5: /* byte mode, byte 1 */ + case 6: /* byte mode, byte 2 */ + case 7: /* byte mode, byte 3 */ + source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */ + break; + } + } + + /* Read in if from register */ + if (i_flags & RR) { + if (FC == 2 && (i_flags & HLF) == 0) /* double dest? */ + dbl = 1; /* src must be dbl for dbl dest */ + dest = (t_uint64)GPR[reg]; /* get the register content */ + if (dbl) { /* is it double regs */ + if (reg & 1) { /* check for odd reg load */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + /* merge the regs into the 64bit value */ + dest = (((t_uint64)dest) << 32) | ((t_uint64)GPR[reg+1]); + } else { + /* sign extend the data value */ + dest |= (dest & MSIGN) ? D32LMASK : 0; + } + } + + /* For Base mode */ + if (i_flags & RB) { + dest = (t_uint64)BR[reg]; /* get base reg contents */ + } + + /* For register instructions */ + if (i_flags & R1) { + source = (t_uint64)GPR[sreg]; + if (dbl) { + if (sreg & 1) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + /* merge the regs into the 64bit value */ + source = (source << 32) | ((t_uint64)GPR[reg+1]); + } else { + /* sign extend the data value */ + source |= (source & MSIGN) ? ((t_uint64)MASK32) << 32: 0; + } + } + + /* TODO Update other history information for this instruction */ + if(hst_lnt) { + hst[hst_p].inst = IR; /* save the instruction */ + hst[hst_p].dest = dest; /* save the destination */ + hst[hst_p].src = source; /* save the source */ + hst[hst_p].reg = reg; /* save the src/dst reg */ + } + +// sim_debug(DEBUG_INST, &cpu_dev, "SW OP %x Non Based i_flags %x addr %.8x\n", OP, i_flags, addr); + switch (OP>>2) { +/* + * For op-codes=00,04,08,0c,10,14,28,2c,38,3c,40,44,60,64,68 + */ + /* Reg - Reg instruction Format (16 bit) */ + /* |--------------------------------------| */ + /* |0 1 2 3 4 5|6 7 8 |9 10 11|12 13 14 15| */ + /* | Op Code | DReg | SReg | Aug Code | */ + /* |--------------------------------------| */ + case 0x00>>2: /* HLF - HLF */ /* CPU General operations */ + switch(opr & 0xF) { /* switch on aug code */ + case 0x0: /* HALT */ + if ((modes & PRIVBIT) == 0) { /* must be privileged to halt */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + goto newpsd; /* Privlege violation trap */ + } + if (CPUSTATUS & 0x00000100) { /* Priv mode halt must be enabled */ + TRAPME = PRIVHALT_TRAP; /* set the trap to take */ + goto newpsd; /* Privlege mode halt trap */ + } +/*FIXME*/ reason = STOP_HALT; /* do halt for now */ + break; + case 0x1: /* WAIT */ + if (modes & PRIVBIT == 0) { /* must be privileged to wait */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + goto newpsd; /* Privlege violation trap */ + } + if (wait4int == 0) { + time_t result = time(NULL); +// fprintf(stderr, "Starting WAIT mode @%ju\r\n", (intmax_t)result); + sim_debug(DEBUG_CMD, &cpu_dev, "Starting WAIT mode %ju\n", (intmax_t)result); + } + wait4int = 1; /* show we are waiting for interrupt */ + i_flags |= BT; /* keep PC from being incremented while waiting */ + break; + case 0x2: /* NOP */ + break; + case 0x3: /* LCS */ + GPR[reg] = M[0x780 >> 2]; /* get console switches from memory loc 0x780 */ + set_CCs(GPR[reg], 0); /* set the CC's, CC1 = 0 */ + break; + case 0x4: /* ES */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* reg is reg to extend sign into from reg+1 */ + GPR[reg] = (GPR[reg+1] & FSIGN) ? FMASK : 0; + set_CCs(GPR[reg], 0); /* set CCs, CC2 & CC3 */ + break; + case 0x5: /* RND */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + temp = GPR[reg]; /* save the current contents of specified reg */ + if (GPR[reg+1] & FSIGN) { /* if sign of R+1 is set, incr R by 1 */ + temp++; /* incr temp R value */ + if (temp < GPR[reg]) /* if temp R less than R, we have overflow */ + ovr = 1; /* show we have overflow */ + GPR[reg] = temp; /* update the R value */ + } + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + case 0x6: /* BEI */ + if ((modes & PRIVBIT) == 0) { /* must be privileged to BEI */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + goto newpsd; /* Privlege violation trap */ + } + CPUSTATUS |= 0x80; /* into status word bit 24 too */ + PSD2 &= ~0x0000c000; /* clear bit 48 & 49 */ + PSD2 |= 0x00004000; /* set bit 49 only */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + break; + case 0x7: /* UEI */ + if ((modes & PRIVBIT) == 0) { /* must be privileged to UEI */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + goto newpsd; /* Privlege violation trap */ + } + CPUSTATUS &= ~0x80; /* into status word bit 24 too */ + PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + irq_pend = 1; /* start scanning interrupts again */ + break; + case 0x8: /* EAE */ + PSD1 |= AEXPBIT; /* set the enable AEXP flag in PSD */ + CPUSTATUS |= AEXPBIT; /* into status word too */ + break; + case 0x9: /* RDSTS */ + GPR[reg] = CPUSTATUS; /* get CPU status word */ + break; + case 0xA: /* SIPU */ /* ignore for now */ + break; + case 0xB: /* INV */ /* RWCS ignore for now */ + case 0xC: /* INV */ /* WWCS ignore for now */ + break; + case 0xD: /* SEA */ + modes |= EXTDBIT; /* set new Extended flag in modes & PSD */ + PSD1 |= EXTDBIT; /* set the enable AEXP flag in PSD */ + CPUSTATUS |= EXTDBIT; /* into status word too */ + break; + case 0xE: /* DAE */ + modes &= AEXPBIT; /* set new extended flag in modes & PSD */ + PSD1 &= ~AEXPBIT; /* disable AEXP flag in PSD */ + CPUSTATUS &= ~AEXPBIT; /* into status word too */ + break; + + case 0xF: /* CEA */ + modes &= ~EXTDBIT; /* disable extended mode in modes and PSD */ + PSD1 &= ~EXTDBIT; /* disable extended mode flag in PSD */ + CPUSTATUS &= ~EXTDBIT; /* into status word too */ + break; + } + break; + case 0x04>>2: /* 0x04 SCC|RR|R1|SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */ + switch(opr & 0xF) { + case 0x0: /* ANR */ + dest &= source; /* just an and reg to reg */ + i_flags |= SCC; /* make sure we set CC's for dest value */ + break; + case 0xA: /* CMC */ /* Cache Memory Control - Diag use only */ + /* write reg to cache memory controller */ + break; + case 0x7: /* SMC */ /* Shared Memory Control Not Used */ + /* write reg to shared memory controller */ + break; + case 0xB: /* RPSWT */ /* Read Processor Status Word 2 (PSD2) */ + dest = PSD2; /* get PSD2 for user */ + break; + default: /* INV */ /* everything else is invalid instruction */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + break; + } + break; + + case 0x08>>2: /* 0x08 SCC|RR|R1|SD|HLF - */ /* ORR or ORRM */ + dest |= source; /* or the regs into dest reg */ + if (opr & 0x8) /* is this ORRM op? */ + dest &= GPR[4]; /* mask with reg 4 contents */ + break; + + case 0x0C>>2: /* 0x0c SCC|RR|R1|SD|HLF - SCC|SD|HLF */ /* EOR or EORM */ +//fprintf(stderr, "@EOR dest %.8x source %.8x\r\n", (uint32)dest, (uint32)source); + dest ^= source; /* exclusive or the regs into dest reg */ + if (opr & 0x8) /* is this EORM op? */ + dest &= GPR[4]; /* mask with reg 4 contents */ +//fprintf(stderr, "@EOR dest %.8x source %.8x\r\n", (uint32)dest, (uint32)source); + break; + + case 0x10>>2: /* 0x10 HLF - HLF */ /* CAR or (basemode SACZ ) */ + if (modes & BASEBIT) { /* handle basemode SACZ instruction */ +sacz: /* non basemode SCZ enters here */ + temp = GPR[reg]; /* get destination reg contents to shift */ + CC = 0; /* zero the CC's */ + t = 0; /* start with zero shift count */ + if (temp == 0) { + CC = CC4BIT; /* set CC4 showing dest is zero & cnt is zero too */ + } + else + if (temp & BIT0) { + CC = 0; /* clear CC4 & set count to zero */ + } + else + if (temp != 0) { /* shift non zero values */ + while ((temp & FSIGN) == 0) { /* shift the reg until bit 0 is set */ + temp <<= 1; /* shift left 1 bit */ + t++; /* increment shift count */ + } + temp <<= 1; /* shift the sign bit out */ + } + GPR[reg] = temp; /* save the shifted values */ + GPR[sreg] = t; /* set the shift cnt into the src reg */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + } else { + /* handle non basemode CAR instr */ + temp = GPR[reg] - GPR[sreg]; /* subtract src from destination value */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + } + break; + + case 0x14>>2: /* 0x14 HLF - HLF */ /* CMR compare masked with reg */ + //FIXME CMD needs both regs to be masked with R4 + temp = GPR[reg] ^ GPR[sreg]; /* exclusive or src and destination values */ + temp &= GPR[4]; /* and with mask reg (GPR 4) */ + CC = 0; /* set all CCs zero */ + if (temp == 0) /* if result is zero, set CC4 */ + CC = CC4BIT; /* set CC4 to show result 0 */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + break; + + case 0x18>>2: /* 0x18 SD|HLF - SD|HLF */ /* SBR, (basemode ZBR, ABR, TBR */ + if (modes & BASEBIT) { /* handle basemode ZBR, ABR, TBR */ + if ((opr & 0xC) == 0x0) /* SBR instruction */ + goto sbr; /* use nonbase SBR code */ + if ((opr & 0xC) == 0x4) /* ZBR instruction */ + goto zbr; /* use nonbase ZBR code */ + if ((opr & 0xC) == 0x8) /* ABR instruction */ + goto abr; /* use nonbase ABR code */ + if ((opr & 0xC) == 0xC) /* TBR instruction */ + goto tbr; /* use nonbase TBR code */ +inv: + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + + } else { /* handle non basemode SBR */ +sbr: /* handle basemode too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ +//fprintf(stderr, "SBR1 bc %.8x PSD1 %.8x GPR[%d] %.8x\r\n", bc, PSD1, sreg, GPR[sreg]); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (GPR[sreg] & bc) /* test the bit in src reg */ + t |= CC1BIT; /* set CC1 to the bit value */ + GPR[sreg] |= bc; /* set the bit in src reg */ + PSD1 |= t; /* update the CC's in the PSD */ +//fprintf(stderr, "SBR2 bc %.8x PSD1 %.8x GPR[%d] %.8x\r\n", bc, PSD1, sreg, GPR[sreg]); + } + break; + + case 0x1C>>2: /* 0x1C SD|HLF - SD|HLF */ /* ZBR (basemode SRA, SRL, SLA, SLL) */ + if (modes & BASEBIT) { /* handle basemode SRA, SRL, SLA, SLL */ + if ((opr & 0x60) == 0x00) /* SRA instruction */ + goto sra; /* use nonbase SRA code */ + if ((opr & 0x60) == 0x20) /* SRL instruction */ + goto srl; /* use nonbase SRL code */ + if ((opr & 0x60) == 0x40) /* SLA instruction */ + goto sla; /* use nonbase SLA code */ + if ((opr & 0x60) == 0x60) /* SLL instruction */ + goto sll; /* use nonbase SLL code */ + } else { /* handle nonbase ZBR */ +zbr: /* handle basemode too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ +//fprintf(stderr, "ZBR1 bc %.8x PSD1 %.8x GPR[%d] %.8x\r\n", bc, PSD1, sreg, GPR[sreg]); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (GPR[sreg] & bc) /* test the bit in src reg */ + t |= CC1BIT; /* set CC1 to the bit value */ + GPR[sreg] &= ~bc; /* reset the bit in src reg */ + PSD1 |= t; /* update the CC's in the PSD */ +//fprintf(stderr, "ZBR2 bc %.8x PSD1 %.8x GPR[%d] %.8x\r\n", bc, PSD1, sreg, GPR[sreg]); + } + break; + + case 0x20>>2: /* 0x20 HLF - HLF */ /* ABR (basemode SRAD, SRLD, SLAD, SLLD) */ + if (modes & BASEBIT) { /* handle basemode SRA, SRL, SLA, SLL */ + if ((opr & 0x60) == 0x00) /* SRAD instruction */ + goto sra; /* use nonbase SRAD code */ + if ((opr & 0x60) == 0x20) /* SRLD instruction */ + goto srl; /* use nonbase SRLD code */ + if ((opr & 0x60) == 0x40) /* SLAD instruction */ + goto sla; /* use nonbase SLAD code */ + if ((opr & 0x60) == 0x60) /* SLLD instruction */ + goto sll; /* use nonbase SLLD code */ + } else { /* handle nonbase mode ABR */ +abr: /* basemode ABR too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + temp = GPR[sreg]; /* get reg value to add bit to */ +//fprintf(stderr, "ABR bc %.8x addr %.8x PSD1 %.8x temp %.8x\r\n", bc, addr, PSD1, temp); + ovr = ((temp & FSIGN) != 0); /* set ovr to status of sign bit 0 */ + temp += bc; /* add the bit value to the reg */ + ovr ^= ((temp & FSIGN) != 0); /* set ovr if sign bit changed */ +//fprintf(stderr, "ABR bc %.8x addr %.8x PSD1 %.8x temp %.8x ovr %d\r\n", bc, addr, PSD1, temp, ovr); + GPR[sreg] = temp; /* save the new value */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + } + break; + + case 0x24>>2: /* 0x24 HLF - SD|HLF */ /* TBR (basemode SRC) */ + if (modes & BASEBIT) { /* handle SRC basemode */ + if ((opr & 0x60) == 0x00) /* SRC instruction */ + goto src; /* use nonbase code */ + if ((opr & 0x60) == 0x40) /* SLC instruction */ + goto slc; /* use nonbase code */ + goto inv; /* else invalid */ + } else { /* handle TBR non basemode */ +tbr: /* handle basemode TBR too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ +//fprintf(stderr, "TBR1 bc %.8x PSD1 %.8x GPR[%d] %.8x\r\n", bc, PSD1, sreg, GPR[sreg]); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (GPR[sreg] & bc) /* test the bit in src reg */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ +//fprintf(stderr, "TBR2 bc %.8x PSD1 %.8x GPR[%d] %.8x\r\n", bc, PSD1, sreg, GPR[sreg]); + } + break; + + case 0x28>>2: /* 0x28 HLF - HLF */ /* Misc OP REG instructions */ + temp = GPR[reg]; /* get reg value */ + switch(opr & 0xF) { + + case 0x0: /* TRSW */ + if (modes & BASEBIT) + addr = temp & MASK24; /* 24 bits for based mode */ + else + addr = temp & 0x7FFFE; /* 19 bits for non based mode */ + /* we are returning to the addr in reg, set CC's from reg */ + /* update the PSD with new address */ + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + PSD1 = ((PSD1 & 0x87ffffff) | (temp & 0x78000000)); /* insert CCs from reg */ + i_flags |= BT; /* we branched, so no PC update */ + break; + + case 0x2: /* XCBR */ /* Exchange base registers */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + temp = BR[reg]; /* get dest reg value */ + BR[reg] = BR[sreg]; /* put source reg value int dest reg */ + BR[sreg] = temp; /* put dest reg value into src reg */ + break; + + case 0x4: /* TCCR */ /* Transfer condition codes to GPR */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + temp = CC >> 27; /* right justify CC's in reg */ + break; + + case 0x5: /* TRCC */ /* Transfer GPR to condition codes */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + PSD1 = ((PSD1 & 0x87fffffe) | (GPR[reg] << 27)); /* insert CCs from reg */ + break; + + case 0x8: /* BSUB */ /* Procedure call */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + /* if Rd field is 0 (reg is b6-8), this is a BSUB instruction */ + /* otherwise it is a CALL instruction (Rd != 0) */ + if (reg == 0) { + /* BSUB instruction */ + uint32 fp = BR[2]; /* get dword bounded frame pointer from BR2 */ + if ((BR[2] & 0x7) != 0) { + /* Fault, must be dw bounded address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + M[fp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC into frame */ + M[(fp>>2)+1] = 0x80000000; /* show frame created by BSUB instr */ + BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */ + BR[0] = BR[2]; /* set frame pointer from BR 2 into BR 0 */ + BR[1] = BR[sreg]; /* Rs reg to BR 1 */ + PSD1 = (PSD1 & 0xff000000) | (BR[sreg] & 0xffffff); /* New PSD address */ + } else { + /* CALL instruction */ + /* get frame pointer from BR2 - 16 words & make it a dword addr */ + uint32 cfp = ((BR[2]-0x40) & 0xfffffff8); + M[cfp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */ + M[(cfp>>2)+1] = 0x00000000; /* show frame created by CALL instr */ + for (ix=0; ix<8; ix++) + M[(cfp>>2)+ix+2] = BR[ix]; /* save BRs 0-7 to call frame */ + for (ix=2; ix<8; ix++) + M[(cfp>>2)+ix+10] = GPR[ix]; /* save GPRs 2-7 to call frame */ + BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */ + BR[0] = cfp; /* set current frame pointer into BR[0] */ + BR[2] = cfp; /* set current frame pointer into BR[2] */ + BR[1] = BR[sreg]; /* Rs reg to BR 1 */ + PSD1 = (PSD1 & 0xff000000) | (BR[sreg] & 0xffffff); /* New PSD address */ + } + break; + + case 0xC: /* TPCBR */ /* Transfer program Counter to Base Register */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + BR[reg] = PSD1 & 0xfffffe; /* save PC from PSD1 into BR */ + break; + + case 0x1: /* INV */ + case 0x3: /* INV */ + case 0x6: /* INV */ + case 0x7: /* INV */ + case 0x9: /* INV */ + case 0xA: /* INV */ + case 0xB: /* INV */ + case 0xD: /* INV */ + case 0xE: /* INV */ + case 0xF: /* INV */ + break; + } + break; + + case 0x2C>>2: /* 0x2C HLF - HLF */ /* Reg-Reg instructions */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + bc = 0; +//fprintf(stderr, "@0x2c temp %.8x addr %.8x\r\n", temp, addr); + + switch(opr & 0xF) { + case 0x0: /* TRR */ /* SCC|SD|R1 */ + temp = addr; /* set value to go to GPR[reg] */ + bc = 1; /* set CC's at end */ + break; + + case 0x1: /* TRBR */ /* Transfer GPR to BR */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + BR[reg] = GPR[sreg]; /* copy GPR to BR */ + break; + + case 0x2: /* TBRR */ /* transfer BR to GPR */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + temp = BR[sreg]; /* set base reg value */ + bc = 1; /* set CC's at end */ + break; + + case 0x3: /* TRC */ /* Transfer register complement */ + temp = addr ^ FMASK; /* complement Rs */ + bc = 1; /* set CC's at end */ + break; + + case 0x4: /* TRN */ /* Transfer register negative */ + temp = -addr; /* negate Rs value */ + if (temp == addr) /* overflow if nothing changed */ + ovr = 1; /* set overflow flag */ + bc = 1; /* set the CC's */ + break; + + case 0x5: /* XCR */ /* exchange registers Rd & Rs */ + GPR[sreg] = temp; /* Rd to Rs */ + set_CCs(temp, ovr); /* set the CC's from original Rd */ + temp = addr; /* save the Rs value to Rd reg */ + break; + + case 0x6: /* INV */ + goto inv; + break; + + case 0x7: /* LMAP */ /* Load map reg - Diags only */ + goto inv; + break; + + case 0x8: /* TRRM */ /* SCC|SD|R1 */ + temp = addr & GPR[4]; /* transfer reg-reg masked */ + bc = 1; /* set CC's at end */ + break; + + /* CPUSTATUS bits */ + /* Bits 0-19 reserved */ + /* Bit 20 =0 Write to writable control store is disabled */ + /* =1 Write to writable control store is enabled */ + /* Bit 21 =0 Enable PROM mode */ + /* =1 Enable Alterable Control Store Mode */ + /* Bit 22 =0 Enable High Speed Floating Point Accelerator */ + /* =1 Disable High Speed Floating Point Accelerator */ + /* Bit 23 =0 Disable privileged mode halt trap */ + /* =1 Enable privileged mode halt trap */ + /* Bit 24 is reserved */ + /* bit 25 =0 Disable software trap handling (enable automatic trap handling) */ + /* =1 Enable software trap handling */ + /* Bits 26-31 reserved */ + case 0x9: /* SETCPU */ + CPUSTATUS &= 0xfffff0bf; /* zero bits that can change */ + CPUSTATUS |= (temp & 0x0f40); /* or in the new status bits */ + break; + + case 0xA: /* TMAPR */ /* Transfer map to Reg - Diags only */ + goto inv; /* not used */ + break; + + case 0xB: /* TRCM */ /* Transfer register complemented masked */ + temp = (addr ^ FMASK) & GPR[4]; /* compliment & mask */ + bc = 1; /* set the CC's */ + break; + + case 0xC: /* TRNM */ /* Transfer register negative masked */ + temp = -addr; /* complement GPR[reg] */ + if (temp == addr) /* check for overflow */ + ovr = 1; /* overflow */ + temp &= GPR[4]; /* and with negative reg */ + bc = 1; /* set the CC's */ + break; + + case 0xD: /* XCRM */ /* Exchange registers masked */ + addr &= GPR[4]; /* and Rs with mask reg */ + temp &= GPR[4]; /* and Rd with mask reg */ + GPR[sreg] = temp; /* Rs to get Rd masked value */ + set_CCs(temp, ovr); /* set the CC's from original Rd */ + temp = addr; /* save the Rs value to Rd reg */ + break; + + case 0xE: /* TRSC */ /* transfer reg to SPAD */ + 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 */ +//fprintf(stderr, "TRSC SPAD[%x] old %.8x new %.8x INTS[%x] %.8x\r\n", t, temp2, SPAD[t], t, INTS[t]); + break; + + case 0xF: /* TSCR */ /* Transfer scratchpad to register */ + t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (9-11) */ + temp = SPAD[t]; /* get SPAD data into Rd (6-8) */ +//fprintf(stderr, "TSCR SPAD[%x] %.8x\r\n", t, temp); + break; + } + GPR[reg] = temp; /* save the temp value to Rd reg */ + if (bc) /* set cc's if bc set */ + set_CCs(temp, ovr); /* set the CC's */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + +/*TODO*/ case 0x30>>2: /* 0x30 */ /* CALM */ + fprintf(stderr, "ERROR - CALM called\r\n"); + goto inv; /* TODO */ + break; + + case 0x34>>2: /* 0x34 SD|ADR - inv */ /* LA non-basemode */ + if (modes & BASEBIT) /* see if based */ + goto inv; /* invalid instruction in based mode */ + if (modes & EXTDBIT) { /* see if extended mode */ + dest = (t_uint64)addr; /* just pure 24 bit address */ + } else { /* use bits 13-31 */ + dest = (t_uint64)(addr | ((FC & 4) << 17)); /* F bit to bit 12 */ + } + break; + + case 0x38>>2: /* 0x38 SCC|SD|HLF - SD|HLF */ /* REG - REG floating point instructions */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + switch(opr & 0xF) { + case 0x0: /* ADR */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (addr & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + break; + + case 0x1: /* ADRFW */ + goto inv; /* TODO */ + break; + case 0x2: /* MPRBR */ + goto inv; /* TODO */ + break; + case 0x3: /* SURFW */ + goto inv; /* TODO */ + break; + case 0x4: /* DVRFW */ + goto inv; /* TODO */ + break; + case 0x5: /* FIXW */ + goto inv; /* TODO */ + break; + case 0x6: /* MPRFW */ + goto inv; /* TODO */ + break; + case 0x7: /* FLTW */ + goto inv; /* TODO */ + break; + case 0x8: /* ADRM */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + temp &= GPR[4]; /* mask the destination reg */ + break; + case 0x9: /* INV */ + goto inv; /* TODO */ + break; + case 0xA: /* DVRBR */ + goto inv; /* TODO */ + break; + case 0xB: /* SURFD */ + goto inv; /* TODO */ + break; + case 0xC: /* DVRFD */ + goto inv; /* TODO */ + break; + case 0xD: /* FIXD */ + goto inv; /* TODO */ + break; + case 0xE: /* MPRFD */ + goto inv; /* TODO */ + break; + case 0xF: /* FLTD */ + goto inv; /* TODO */ + break; + } + GPR[reg] = temp; /* temp has destination reg value */ + if ((opr & 0xF) < 6) { + set_CCs(temp, ovr); /* set the CC's */ + } + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0x3C>>2: /* 0x3C HLF - HLF */ /* SUR and SURM */ + temp = GPR[reg]; /* get negative value to add */ + addr = -GPR[sreg]; /* reg contents specified by Rs */ + switch(opr & 0xF) { + case 0x0: /* SUR */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (addr & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + break; + case 0x8: /* SURM */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + temp &= GPR[4]; /* mask the destination reg */ + break; + case 0x9: /* INV */ + goto inv; /* TODO */ + break; + case 0xA: /* DVRBR */ + goto inv; /* TODO */ + break; + case 0xB: /* SURFD */ + goto inv; /* TODO */ + break; + case 0xC: /* DVRFD */ + goto inv; /* TODO */ + break; + case 0xD: /* FIXD */ + goto inv; /* TODO */ + break; + case 0xE: /* MPRFD */ + goto inv; /* TODO */ + break; + case 0xF: /* FLTD */ + goto inv; /* TODO */ + break; + } + GPR[reg] = temp; /* save the result */ + if ((opr & 0xF) < 6) { + set_CCs(temp, ovr); /* set CCs for result */ + } + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0x40>>2: /* 0x40 */ /* MPR */ + if (reg & 1) { + /* Spec fault */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + temp = GPR[reg+1]; /* get multiplicand */ + addr = GPR[sreg]; /* multiplier */ + + /* change immediate value into a 64 bit value */ + dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); +//fprintf(stderr, "MPR reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", reg, GPR[reg], GPR[reg+1], dest); + source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0); +//fprintf(stderr, "MPR reg %d GPR[reg] %.8x GPR[reg+1] %.8x source %llx\r\n", reg, GPR[reg], GPR[reg+1], source); + dest = dest * source; /* do the multiply */ +//fprintf(stderr, "MPR dest result %llx\r\n", dest); + i_flags |= SD|SCC; /* save regs and set CC's */ + dbl = 1; /* double reg save */ + break; + + case 0x44>>2: /* 0x44 ADR - ADR */ /* DVR */ + /* sreg has Rs */ + if (reg & 1) { + /* Spec fault */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* get Rs divisor value */ + source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0); +//fprintf(stderr, "DVR reg %d GPR[reg] %.8x GPR[reg+1] %.8x source %llx\r\n", reg, GPR[reg], GPR[reg+1], source); + /* merge the dividend regs into the 64bit value */ + dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]); +//fprintf(stderr, "DVR reg %d GPR[reg] %.8x GPR[reg+1] %.8x source %llx\r\n", reg, GPR[reg], GPR[reg+1], dest); + if (source == 0) { + goto doovr3; + break; + } + td = (t_int64)dest % (t_int64)source; /* remainder */ + dbl = (td < 0); /* double reg is neg remainder */ +//fprintf(stderr, "DVR remainder %llx dbl %x \r\n", td, dbl); + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = -td; /* dividend and remainder must be same sign */ +//fprintf(stderr, "DVR fix sign %llx dbl %x source %llx dest %llx\r\n", td, dbl, source, dest); + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ +//fprintf(stderr, "DVR dest %llx\r\n", dest); + if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */ +doovr3: + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + /* the original regs must be returned unchanged if aexp */ + set_CCs(temp, ovr); /* set the CC's */ +//fprintf(stderr, "DVR ovr %d reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", ovr, reg, GPR[reg], GPR[reg+1], dest); + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ +//fprintf(stderr, "DVR good reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx rem %llx\r\n", reg, GPR[reg], GPR[reg+1], dest, td); + } + break; +//#endif /* SIMPLE_MODE*/ + + case 0x48>>2: /* 0x48 INV - INV */ /* unused opcodes */ + case 0x4C>>2: /* 0x4C INV - INV */ /* unused opcodes */ + default: +fprintf(stderr, "place @ UI op = %.8x\r\n", IR); + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + break; + + case 0x50>>2: /* 0x50 INV - SD|ADR */ /* LA basemode */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if (modes & (BASEBIT|EXTDBIT)) { + dest = (t_uint64)addr; /* just pure 24 bit address */ + } else { + dest = (t_uint64)(addr | ((FC & 4) << 17)); /* F bit to bit 12 */ + } + break; + + case 0x54>>2: /* 0x54 SM|ADR - INV */ /* (basemode STWBR) */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if (FC != 0) { /* word address only */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + dest = BR[reg]; /* save the BR to memory */ + break; + + case 0x58>>2: /* 0x58 SB|ADR - INV */ /* (basemode SUABR and LABR) */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if ((FC & 4) != 0) { /* see if SUABR F=0 */ + dest = BR[reg] - addr; /* subtract addr from the BR and store back to BR */ + } else { /* LABR if F=1 */ + dest = addr; /* addr goes to specified BR */ + } + break; + case 0x5C>>2: /* 0x5C RM|SB|ADR - INV */ /* (basemode LWBR and BSUBM) */ + if ((modes & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if (FC != 0) { /* word address only */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((FC & 0x4) != 0x4) { /* this is a LWBR instruction */ + BR[reg] = source; /* load memory location in BR */ + } else { /* this is a CALLM/BSUBM instruction */ + /* if Rd field is 0 (reg is b6-8), this is a BSUBM instruction */ + /* otherwise it is a CALLM instruction (Rd != 0) */ + if (reg == 0) { + /* BSUBM instruction */ + uint32 fp = BR[2]; /* get dword bounded frame pointer from BR2 */ + if ((BR[2] & 0x7) != 0) { + /* Fault, must be dw bounded address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + M[fp>>2] = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC into frame */ + M[(fp>>2)+1] = 0x80000000; /* show frame created by BSUB instr */ + BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */ + BR[0] = BR[2]; /* set frame pointer from BR 2 into BR 0 */ + BR[1] = (addr+0x80) & 0xfffffe; /* effective address to BR 1 */ + PSD1 = (PSD1 & 0xff000000) | BR[1]; /* New PSD address */ + } else { + /* CALM instruction */ + /* get frame pointer from BR2 - 16 words & make it a dword addr */ + uint32 cfp = ((BR[2]-0x40) & 0xfffffff8); + M[cfp>>2] = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */ + M[(cfp>>2)+1] = 0x00000000; /* show frame created by CALL instr */ + for (ix=0; ix<8; ix++) + M[(cfp>>2)+ix+2] = BR[ix]; /* save BRs 0-7 to call frame */ + for (ix=2; ix<8; ix++) + M[(cfp>>2)+ix+10] = GPR[ix];/* save GPRs 2-7 to call frame */ + BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */ + BR[0] = (uint32)cfp; /* set current frame pointer into BR[0] */ + BR[2] = (uint32)cfp; /* set current frame pointer into BR[2] */ + BR[1] = (addr + 0x80) & 0xfffffe; /* effective address to BR 1 */ + PSD1 = (PSD1 & 0xff000000) | BR[1]; /* New PSD address */ + } + } + break; + + case 0x60>>2: /* 0x60 SH|HLF - INV */ /* NOR Rd,Rs */ + if ((modes & BASEBIT)) { /* only for nonbased mode */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + } + temp = GPR[reg]; /* Rd */ + t = 0; /* no shifts yet */ + /* exponent must not be zero or all 1's */ + if (temp != 0 && temp != FMASK) { + /* non zero value or not all 1's, so normalize */ + uint32 m = temp & 0xF8000000; + /* shift left 4 bits at a time while left most 5 bits are not zero or all 1's */ + while ((m == 0) || (m == 0xF8000000)) { + temp <<= 4; /* move left 4 bits */ + t++; /* increment number times shifted */ + m = temp & 0xF8000000; /* get left most 5 bits again */ + } + /* temp value is now normalized with non zero nor all 1's value */ + GPR[reg] = temp; /* save the normalized value */ + GPR[(IR >> 20) & 7] = 0x40 - t; /* subtract shift count from 0x40 into Rs */ + } else { + GPR[(IR >> 20) & 7] = 0; /* set exponent to zero for zero value */ + } + break; + + case 0x64>>2: /* 0x64 SD|HLF - INV */ /* NORD */ + if ((modes & BASEBIT)) { /* only for nonbased mode */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + } + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + addr = GPR[reg]; /* high order 32 bits */ + temp = GPR[reg+1]; /* low order 32 bits */ + t = 0; /* zero shift count */ + if ((temp|addr) != 0 && (temp&addr) != FMASK) { + uint32 m = temp & 0xF8000000; /* upper 5 bit mask */ + /* shift until upper 5 bits are neither 0 or all 1's */ + while ((m == 0) || (m == 0xF8000000)) { + temp <<= 4; /* shift over 4 bits at a time */ + m = temp & 0xF8000000; /* upper 5 bits */ + temp |= (addr >> 28) & 0xf; /* copy in upper 4 bits from R+1 */ + addr <<= 4; /* shift 4 bits of zero int R+1 */ + t++; /* bump shift count */ + } + GPR[reg] = addr; /* save the new values */ + GPR[reg|1] = temp; + } + if (t != 0) + t = 0x40 - t; /* set the shift cnt */ + GPR[(IR >> 20) & 7] = t; /* put 0x40 - shift count or 0 into RS */ + break; + + case 0x68>>2: /* 0x68 SCC|SD|HLF - INV */ /* non basemode SCZ */ + if (modes & BASEBIT) + goto inv; /* invalid instruction */ + goto sacz; /* use basemode sacz instruction */ + + case 0x6C>>2: /* 0x6C SD|HLF - INV */ /* non basemode SRA & SLA */ + if (modes & BASEBIT) + goto inv; /* invalid instruction */ +sra: +sla: + bc = opr & 0x1f; /* get bit shift count */ + temp = GPR[reg]; /* get reg value to shift */ + t = temp & FSIGN; /* sign value */ + if (opr & 0x0040) { /* is this SLA */ + ovr = 0; /* set ovr off */ + for (ix=0; ix>= 1; /* shift bit 0 right one bit */ + temp |= t; /* restore original sign bit */ + } + GPR[reg] = temp; /* save the new value */ + } + break; + + case 0x70>>2: /* 0x70 SD|HLF - INV */ /* non-basemode SRL & SLL */ + if (modes & BASEBIT) + goto inv; /* invalid instruction in basemode */ +sll: +srl: + bc = opr & 0x1f; /* get bit shift count */ + temp = GPR[reg]; /* get reg value to shift */ +//fprintf(stderr, "before SLL/SRL dest %.8x cnt %d\r\n", temp, bc); + if (opr & 0x0040) /* is this SLL, bit 9 set */ + temp <<= bc; /* shift left #bits */ + else + temp >>= bc; /* shift right #bits */ + dest = temp; /* value to be output */ +//fprintf(stderr, "SLL/SRL dest %.8x cnt %d\r\n", (uint32)dest, bc); + break; + + case 0x74>>2: /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */ + if (modes & BASEBIT) + goto inv; /* invalid instruction in basemode */ +slc: +src: + bc = opr & 0x1f; /* get bit shift count */ + temp = GPR[reg]; /* get reg value to shift */ + if (opr & 0x0040) { /* is this SLC, bit 9 set */ + for (ix=0; ix>= 1; /* shift the bit out */ + if (t) + temp |= BIT0; /* put in new sign bit */ + } + } + dest = temp; /* shift result */ + break; + +/*TODO*/ + case 0x78>>2: /* 0x78 HLF - INV */ /* non-basemode SRAD & SLAD */ + if (modes & BASEBIT) /* Base mode? */ + goto inv; /* invalid instruction in basemode */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + bc = opr & 0x1f; /* get bit shift count */ + dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ + dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + source = dest & DMSIGN; /* 64 bit sign value */ + if (opr & 0x0040) { /* is this SLAD */ + ovr = 0; /* set ovr off */ + for (ix=0; ix>32) & FMASK);/* save the hi order reg */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (ovr) + PSD1 |= BIT1; /* CC1 in PSD */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + } else { /* this is a SRAD */ + for (ix=0; ix>= 1; /* shift bit 0 right one bit */ + dest |= source; /* restore original sign bit */ + } + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + } + break; + + case 0x7C>>2: /* 0x7C SDD|HLF - INV */ /* non-basemode SRLD & SLLD */ + if (modes & BASEBIT) + goto inv; /* invalid instruction in basemode */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ + dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + bc = opr & 0x1f; /* get bit shift count */ + if (opr & 0x0040) /* is this SLL, bit 9 set */ + dest <<= bc; /* shift left #bits */ + else + dest >>= bc; /* shift right #bits */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0x80>>2: /* 0x80 SD|ADR - SD|ADR */ /* LEAR */ + /* convert address to real physical address */ + TRAPME = RealAddr(addr, &temp, &t); + if (TRAPME != ALLOK) + goto newpsd; /* memory read error or map fault */ + /* OS code says F bit is not transferred, so just ignore it */ +// if (FC & 4) /* see if F bit was set */ +// temp |= 0x01000000; /* set bit 7 of address */ + dest = temp; /* put in dest to go out */ +// fprintf(stderr, "LEAR Inst %.8x addr %.8x raddr %.8x PSD %.8x %.8x SPAD PSD@ %x\r\n", +// IR, addr, temp, PSD1, PSD2, SPAD[0xf5]); +// sim_debug(DEBUG_CMD, &cpu_dev, "LEAR Inst %.8x addr %.8x raddr %.8x PSD %.8x %.8x\n", +// IR, addr, temp, PSD1, PSD2); + break; + + case 0x84>>2: /* 0x84 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ANMx */ + dest &= source; + break; + + case 0x88>>2: /* 0x88 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ORMx */ + dest |= source; + break; + + case 0x8C>>2: /* 0x8C SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* EOMx */ + dest ^= source; + break; + + case 0x90>>2: /* 0x90 SCC|RR|RM|ADR - RM|ADR */ /* CAMx */ +//fprintf(stderr, "CAMW src %llx dest %llx\r\n", source, dest); + dest -= source; + break; + + case 0x94>>2: /* 0x94 RR|RM|ADR - RM|ADR */ /* CMMx */ + //FIXME CMMD need both regs to be masked with R4 + if (dbl) { + /* we need to and both regs */ + t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK); + td = dest; /* save dest */ + dest ^= source; + dest &= nm; /* mask both regs with reg 4 contents */ +// fprintf(stderr, "CMMD PSD %x src %llx dst %llx GPR[4] %llx result %llx CC4 %x\r\n", +// PSD1, source, td, nm, dest, dest==0ll?1:0); + } else { + td = dest; /* save dest */ + dest ^= source; /* <= 32 bits, so just do lower 32 bits */ + dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */ +// fprintf(stderr, "CMMW PSD %x src %llx dst %llx GPR[4] %llx result %llx CC4 %x\r\n", +// PSD1, source, td, ((t_uint64)GPR[4]), dest, dest==0ll?1:0); + } + CC = 0; + if (dest == 0ll) + CC |= CC4BIT; + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + break; + + case 0x98>>2: /* 0x98 ADR - ADR */ /* SBM */ + if ((FC & 04) == 0) { + /* Fault, f-bit must be set for SBM instruction */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + t = (CC & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ +//fprintf(stderr, "SBM bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + if (temp & bc) /* test the bit in memory */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ + temp |= bc; /* set the bit in temp */ +//fprintf(stderr, "SBM bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + if ((TRAPME = Mem_write(addr, &temp))) /* put word back into memory */ + goto newpsd; /* memory write error or map fault */ + break; + + case 0x9C>>2: /* 0x9C ADR - ADR */ /* ZBM */ + if ((FC & 04) == 0) { + /* Fault, byte address not allowed */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + t = (CC & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ +//fprintf(stderr, "ZBM bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + if (temp & bc) /* test the bit in memory */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ + temp &= ~bc; /* reset the bit in temp */ +//fprintf(stderr, "ZBM bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + if ((TRAPME = Mem_write(addr, &temp))) /* put word into memory */ + goto newpsd; /* memory write error or map fault */ + break; + + case 0xA0>>2: /* 0xA0 ADR - ADR */ /* ABM */ + if ((FC & 04) == 0) { + /* Fault, byte address not allowed */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ +//fprintf(stderr, "ABM B4 bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + ovr = (temp & FSIGN) != 0; /* set ovr to status of sign bit 0 */ + temp += bc; /* add the bit value to the reg */ + ovr ^= (temp & FSIGN) != 0; /* set ovr if sign bit changed */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ +//fprintf(stderr, "ABM AF bc %.8x addr %.8x CC %0.2x ovr %x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, ovr, PSD1, temp); + if ((TRAPME = Mem_write(addr, &temp))) /* put word into memory */ + goto newpsd; /* memory write error or map fault */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + break; + + case 0xA4>>2: /* 0xA4 ADR - ADR */ /* TBM */ + if ((FC & 04) == 0) { + /* Fault, byte address not allowed */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + t = (CC & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ +//fprintf(stderr, "TBM bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + if (temp & bc) /* test the bit in memory */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ +//fprintf(stderr, "TBM bc %.8x addr %.8x CC %0.2x PSD1 %.8x temp %.8x\r\n", bc, addr, CC, PSD1, temp); + break; + + case 0xA8>>2: /* 0xA8 RM|ADR - RM|ADR */ /* EXM */ + if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */ + /* Fault */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + IR = temp; /* get instruction from memory */ + if (FC == 2) /* see if right halfword specified */ + IR <<= 16; /* move over the HW instruction */ + if ((IR & 0xFC7F0000) == 0xC8070000 || + (IR & 0xFF800000) == 0xA8000000 || + (IR & 0xFC000000) == 0x80000000) { + /* Fault, attempt to execute another EXR, EXRR, EXM, or LEAR */ + goto inv; /* invalid instruction */ + } + EXM_EXR = 4; /* set PC increment for EXM */ + goto exec; /* go execute the instruction */ + + case 0xAC>>2: /* 0xAC SCC|SD|RM|ADR - SD|RM|ADR */ /* Lx */ + dest = source; /* set value to load into reg */ + break; + + case 0xB0>>2: /* 0xB0 SCC|SD|RM|ADR - SD|RM|ADR */ /* LMx */ + //FIXME LMD need both regs to be masked with R4 + if (dbl) { + /* we need to and both regs */ + t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK); + dest = source & nm; /* mask both regs with reg 4 contents */ +// fprintf(stderr, "LMD PSD %x src %llx GPR[4] %llx result %llx\r\n", PSD1, source, nm, dest); + } else { + dest = source; /* <= 32 bits, so just do lower 32 bits */ + dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */ +// fprintf(stderr, "LMW PSD %x src %llx GPR[4] %llx result %llx\r\n", PSD1, source, ((t_uint64)GPR[4]), dest); + } + break; + + case 0xB4>>2: /* 0xB4 SCC|SD|RM|ADR - SD|RM|ADR */ /* LNx */ + dest = -source; /* set the value to load into reg */ + if (dest == source) + ovr = 1; /* set arithmetic exception status */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0xBC>>2: /* 0xBC SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* SUMx */ + source = -source; + /* Fall through */ + + case 0xE8>>2: /* 0xE8 SCC|SM|RR|RM|ADR - SM|RM|ADR */ /* ARMx */ + case 0xB8>>2: /* 0xB8 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ADMx */ + t = (source & DMSIGN) != 0; + t |= ((dest & DMSIGN) != 0) ? 2 : 0; +//fprintf(stderr, "ARMW t %x src %llx dest %llx", t, source, dest); + dest = dest + source; + if ((t == 3) && ((dest & DMSIGN) == 0)) { + ovr = 1; +//fprintf(stderr, " @ovr0 %d", ovr); + } + if ((t == 0) && ((dest & DMSIGN) != 0)) { + ovr = 1; +//fprintf(stderr, " @ovr1 %d", ovr); + } + if ((dbl == 0) && ((dest & D32LMASK) != 0) && ((dest & D32LMASK) != D32LMASK)) { + ovr = 1; +//fprintf(stderr, " @ovr2 %d", ovr); + } + +//fprintf(stderr, " result %llx\r\n", dest); + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0xC0>>2: /* 0xC0 SCC|SD|RM|ADR - SD|RM|ADR */ /* MPMx */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ +//fprintf(stderr, "MPM? before src %llx dest %llx\r\n", source, dest); + dest = (t_uint64)((t_int64)dest * (t_int64)source); +//fprintf(stderr, "MPM? after src %llx dest %llx\r\n", source, dest); + dbl = 1; + break; + + case 0xC4>>2: /* 0xC4 RM|ADR - RM|ADR */ /* DVMx */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } +//fprintf(stderr, "DVM reg %d GPR[reg] %.8x GPR[reg+1] %.8x source %llx\r\n", reg, GPR[reg], GPR[reg+1], source); + dest = (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */ +//fprintf(stderr, "DVM reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", reg, GPR[reg], GPR[reg+1], dest); + if (source == 0) { + goto doovr; /* we have div by zero */ + } + td = ((t_int64)dest % (t_int64)source); /* remainder */ + dbl = (td < 0); /* double reg if neg remainder */ +//fprintf(stderr, "DVM remainder %llx dbl %x \r\n", td, dbl); + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = -td; /* dividend and remainder must be same sign */ +//fprintf(stderr, "DVM fix sign %llx dbl %x source %llx dest %llx\r\n", td, dbl, source, dest); + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ +//fprintf(stderr, "DVM dest %llx\r\n", dest); + if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */ +doovr: + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (modes & AEXPBIT) + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + /* the original regs must be returned unchanged if aexp */ +// i_flags &= ~SD; /* remove the store to reg flag */ +// dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ +// dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ +//fprintf(stderr, "DVM ovr %d reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", ovr, reg, GPR[reg], GPR[reg+1], dest); + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ +//fprintf(stderr, "DVM good reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx rem %llx\r\n", reg, GPR[reg], GPR[reg+1], dest, td); + } + break; + + case 0xC8>>2: /* 0xC8 IMM - IMM */ /* Immedate */ + temp = GPR[reg]; /* get reg contents */ + addr = IR & RMASK; /* sign extend 16 bit imm value from IR */ + if (addr & 0x8000) /* negative */ + addr |= LMASK; /* extend sign */ +//fprintf(stderr, "C8 IMM temp %.8x addr %.8x\r\n", temp, addr); + + switch(opr & 0xF) { /* switch on aug code */ + case 0x0: /* LI */ /* SCC | SD */ + GPR[reg] = addr; /* put immediate value into reg */ + set_CCs(addr, ovr); /* set the CC's, CC1 = ovr */ + break; + + case 0x2: /* SUI */ + addr = -addr; /* just make value a negative add */ + /* drop through */ + case 0x1: /* ADI */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in reg value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the extended immediate value */ + temp = temp + addr; /* now add the numbers */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + GPR[reg] = temp; /* save the result */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0x3: /* MPI */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* change immediate value into a 64 bit value */ + source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); +//fprintf(stderr, "MPI reg %d GPR[reg] %.8x GPR[reg+1] %.8x source %llx\r\n", reg, GPR[reg], GPR[reg+1], source); + temp = GPR[reg+1]; /* get reg multiplier */ + dest = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0); +//fprintf(stderr, "MPI reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", reg, GPR[reg], GPR[reg+1], dest); + dest = dest * source; /* do the multiply */ +//fprintf(stderr, "MPI dest result %llx\r\n", dest); + i_flags |= SD|SCC; /* save regs and set CC's */ + dbl = 1; /* double reg save */ + break; + + case 0x4: /* DVI */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* change immediate value into a 64 bit value */ + source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); +//fprintf(stderr, "DVI reg %d GPR[reg] %.8x GPR[reg+1] %.8x source %llx\r\n", reg, GPR[reg], GPR[reg+1], source); + if (source == 0) { + goto doovr2; + } + dest = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ +//fprintf(stderr, "DVI reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", reg, GPR[reg], GPR[reg+1], dest); + td = ((t_int64)dest % (t_int64)source); /* remainder */ + dbl = (td < 0); /* double reg if neg remainder */ +//fprintf(stderr, "DVI remainder %llx dbl %x \r\n", td, dbl); + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = -td; /* dividend and remainder must be same sign */ +//fprintf(stderr, "DVI fix sign %llx dbl %x source %llx dest %llx\r\n", td, dbl, source, dest); + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ +//fprintf(stderr, "DVI dest %llx\r\n", dest); + if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */ +doovr2: + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (modes & AEXPBIT) + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + /* the original regs must be returned unchanged if aexp */ + /* put reg values back in dest for CC test */ +// dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ +// dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ +// i_flags |= SCC; /* set CC's */ +//fprintf(stderr, "DVI ovr %d reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx\r\n", ovr, reg, GPR[reg], GPR[reg+1], dest); + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ +//fprintf(stderr, "DVI good reg %d GPR[reg] %.8x GPR[reg+1] %.8x dest %llx rem %llx\r\n", reg, GPR[reg], GPR[reg+1], dest, td); + } + break; + + case 0x5: /* CI */ /* SCC */ + temp = ((int)temp - (int)addr); /* subtract imm value from reg value */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ +//fprintf(stderr, "CI IMM temp %.8x addr %.8x PSD1 %.8x flags %.8x\r\n", temp, addr, PSD1, i_flags); + break; + +/* SVC instruction format C806 */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02 03 04 05|06 07 08|09 10 11|12 13 14 15|16 17 18 19|20 21 22 23 24 25 26 27 28 29 30 31| */ +/* | Op Code | N/U | N/U | Aug | SVC Index | SVC Call Number | */ +/* | 1 1 0 0 1 0| 0 0 0| 0 0 0| 0 1 1 0| x x x x| x x x x x x x x x x x x| */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ + case 0x6: /* SVC none - none */ /* Supervisor Call Trap */ + { +#if 0 + int j; + char n[9]; + uint32 dqe = M[0x8e8>>2]; + for (j=0; j<8; j++) { + n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff; + if (n[j] == 0) + n[j] = 0x20; + } + n[8] = 0; +#endif + addr = SPAD[0xf0]; /* get trap table memory address from SPAD (def 80) */ +//fprintf(stderr, "SVC 1 IMM temp %.8x addr %.8x PSD1 %.8x flags %.8x\r\n", temp, addr, PSD1, i_flags); + if (addr == 0 || addr == 0xffffffff) { /* see if secondary vector table set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + goto newpsd; /* program error */ + } + addr = addr + (0x06 << 2); /* addr has mem addr of SVC trap vector (def 98) */ + temp = M[addr >> 2]; /* get the secondary trap table address from memory */ +//fprintf(stderr, "SVC 2 IMM temp %.8x addr %.8x PSD1 %.8x temp2 %.8x\r\n", temp, addr, PSD1, temp2); + if (temp == 0 || temp == 0xffffffff) { /* see if ICB set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + goto newpsd; /* program error */ + } + temp2 = ((IR>>12) & 0x0f) << 2; /* get SVC index from IR */ +//fprintf(stderr, "SVC 2a IMM temp %.8x addr %.8x PSD1 %.8x temp2 %.8x\r\n", temp, addr, PSD1, temp2>>2); + 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 */ + goto newpsd; /* program error */ + } +//fprintf(stderr, "SVC 3 IMM temp %.8x svca %.8x PSD1 %.8x temp2 %.8x\r\n", temp+temp2, t, PSD1, temp2); + bc = PSD2 & 0x3ffc; /* get copy of cpix */ + M[t>>2] = (PSD1+4) & 0xfffffffe; /* store PSD 1 + 1W to point to next instruction */ + M[(t>>2)+1] = PSD2; /* store PSD 2 */ + PSD1 = M[(t>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(t>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */ + M[(t>>2)+4] = IR&0xFFF; /* store call number */ +#if 0 +fprintf(stderr, "SVC @ %.8x SVC %x,%x PSD1 %.8x PSD2 %.8x SPAD PSD@ %x C.CURR %x LMN %s\r\n", OPSD1, temp2>>2, IR&0xFFF, PSD1, PSD2, SPAD[0xf5], dqe, n); +fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]); +fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]); +fprintf(stderr, "\r\n"); + if (((temp2>>2) == 1) && ((IR&0xfff) == 0x75)) +fprintf(stderr, "SVC %x,%x GPR[6] %x GPR[6] %x\r\n", temp2>>2, IR&0xfff, GPR[6], GPR[7]); +#endif + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + /* set new map mode and interrupt blocking state in CPUSTATUS */ + if (PSD2 & MAPBIT) { + CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ + modes |= MAPMODE; /* set mapped mode */ + } else + CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */ + /* set interrupt blocking state */ + if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */ + if (PSD2 & 0x4000) /* no, is it set blocking state */ + CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */ + else { + CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */ + irq_pend = 1; /* start scanning interrupts again */ + } + } + PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */ + if (CPUSTATUS & 0x80) /* see if old mode is blocked */ + PSD2 |= 0x00004000; /* set to blocked state */ + + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + goto newpsd; /* new psd loaded */ + } + break; + + case 0x7: /* EXR */ + IR = temp; /* get instruction to execute */ + if (addr & 2) /* if bit 30 set, instruction is in right hw, do EXRR */ + IR <<= 16; /* move instruction to left HW */ + if ((IR & 0xFC7F0000) == 0xC8070000 || + (IR & 0xFF800000) == 0xA8000000) { + /* Fault, attempt to execute another EXR, EXRR, or EXM */ + goto inv; /* invalid instruction */ + } + EXM_EXR = 4; /* set PC increment for EXR */ + goto exec; + break; + + /* these instruction were never used by MPX, only diags */ + case 0x8: /* SEM */ + case 0x9: /* LEM */ + case 0xA: /* CEMA */ + case 0xB: /* INV */ + case 0xC: /* INV */ + case 0xD: /* INV */ + case 0xE: /* INV */ + case 0xF: /* INV */ + goto inv; /* invalid instruction */ + break; + } + break; + + case 0xCC>>2: /* 0xCC ADR - ADR */ /* LF */ + /* For machines with Base mode 0xCC08 stores base registers */ + if ((FC & 3) != 0) { /* must be word address */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + bc = addr & 0x20; /* bit 26 initial value */ + while (reg < 8) { + if (bc != (addr & 0x20)) { /* test for crossing file boundry */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (FC & 0x4) /* LFBR? */ + TRAPME = Mem_read(addr, &BR[reg]); /* read the base reg */ + else /* LF */ + TRAPME = Mem_read(addr, &GPR[reg]); /* read the GPR reg */ + if (TRAPME) /* TRAPME has error */ + goto newpsd; /* go execute the trap now */ + reg++; /* next reg to write */ + addr += 4; /* next addr */ + } + break; + + case 0xD0>>2: /* 0xD0 SD|ADR - INV */ /* LEA none basemode only */ +//fprintf(stderr, "Got LEA @ addr %x\\r\n", addr); + dest = (t_uint64)(addr); + break; + + case 0xD4>>2: /* 0xD4 SM|ADR - SM|ADR */ /* STx */ + break; + + case 0xD8>>2: /* 0xD8 SM|ADR - SM|ADR */ /* STMx */ + //FIXME STMD needs both regs to be masked with R4 + if (dbl) { + /* we need to and both regs */ + td = dest; + t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK); + dest &= nm; /* mask both regs with reg 4 contents */ +// fprintf(stderr, "STMD PSD %x src %llx GPR[4] %llx result %llx\r\n", +// PSD1, td, nm, dest); + } else { + td = dest; + dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */ +// fprintf(stderr, "STMW PSD %x src %llx GPR[4] %llx result %llx\r\n", +// PSD1, td, ((t_uint64)GPR[4]), dest); + } + break; + + case 0xDC>>2: /* 0xDC INV - */ /* INV nonbasemode (STFx basemode) */ + /* DC00 STF */ /* DC08 STFBR */ + if ((FC & 0x4) && (CPU_MODEL <= MODEL_27)) { + /* basemode undefined for 32/7x & 32/27 */ /* TODO check this */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + } + /* For machines with Base mode 0xDC08 stores base registers */ + if ((FC & 3) != 0) { /* must be word address */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + bc = addr & 0x20; /* bit 26 initial value */ + while (reg < 8) { + if (bc != (addr & 0x20)) { /* test for crossing file boundry */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (FC & 0x4) /* STFBR? */ + TRAPME = Mem_write(addr, &BR[reg]); /* store the base reg */ + else /* STF */ + TRAPME = Mem_write(addr, &GPR[reg]); /* store the GPR reg */ + if (TRAPME) /* TRAPME has error */ + goto newpsd; /* go execute the trap now */ + reg++; /* next reg to write */ + addr += 4; /* next addr */ + } + break; + + /* TODO */ + case 0xE0>>2: /* 0xE0 SCC|SD|RM|ADR - SD|RM|ADR */ /* ADFx, SUFx */ + if ((FC & 3) != 0) { /* must be word address */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (opr & 0x0008) { /* Was it ADFx? */ + /* TODO ADF? call here */ + goto inv; + } else { + /* TODO SUF? call here */ + goto inv; + } /* it is SUFx */ + break; + + /* TODO */ + case 0xE4>>2: /* 0xE4 SCC|RM|ADR - RM|ADR */ /* MPFx, DVFx */ + if ((FC & 3) != 0) { /* must be word address */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (opr & 0x0008) { /* Was it MPFx? */ + /* TODO MPF? call here */ + goto inv; + } else { + /* TODO DVF? call here */ + goto inv; + } /* it is DVFx */ + break; + + case 0xEC>>2: /* 0xEC ADR - ADR */ /* Branch unconditional or Branch True */ + /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ + /* so just test for F bit and go on */ + /* if ((FC & 5) != 0) { */ + if ((FC & 4) != 0) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + CC = PSD1 & 0x78000000; /* get CC's if any */ + switch(reg) { + case 0: t = 1; break; + case 1: t = (CC & CC1BIT) != 0; break; + case 2: t = (CC & CC2BIT) != 0; break; + case 3: t = (CC & CC3BIT) != 0; break; + case 4: t = (CC & CC4BIT) != 0; break; + case 5: t = (CC & (CC2BIT|CC4BIT)) != 0; break; + case 6: t = (CC & (CC3BIT|CC4BIT)) != 0; break; + case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) != 0; break; + } +//fprintf(stderr, "BCT t %.8x addr %.8x CC %.8x PSD1 %.8x\r\n", t, addr, CC, PSD1); + if (t) { /* see if we are going to branch */ + /* we are taking the branch, set CC's if indirect, else leave'm */ + if (IR & IND) /* see if CCs from last indirect location are wanted */ + PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */ + /* update the PSD with new address */ + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + i_flags |= BT; /* we branched, so no PC update */ +//fprintf(stderr, "BR t %.8x addr %.8x PSD1 %.8x\r\n", t, addr, PSD1); + } + /* branch not taken, go do next instruction */ + break; + + case 0xF0>>2: /* 0xF0 ADR - ADR */ /* Branch False or Branch Function True */ + /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ + /* so just test for F bit and go on */ + /* if ((FC & 5) != 0) { */ + if ((FC & 4) != 0) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + CC = PSD1 & 0x78000000; /* get CC's if any */ + switch(reg) { + case 0: t = (GPR[4] & (0x8000 >> ((CC >> 27) & 0xf))) != 0; break; + case 1: t = (CC & CC1BIT) == 0; break; + case 2: t = (CC & CC2BIT) == 0; break; + case 3: t = (CC & CC3BIT) == 0; break; + case 4: t = (CC & CC4BIT) == 0; break; + case 5: t = (CC & (CC2BIT|CC4BIT)) == 0; break; + case 6: t = (CC & (CC3BIT|CC4BIT)) == 0; break; + case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) == 0; break; + } +//fprintf(stderr, "BCF reg %d t %.8x addr %.8x CC %.8x PSD1 %.8x\r\n", reg, t, addr, CC, PSD1); + if (t) { /* see if we are going to branch */ + /* we are taking the branch, set CC's if indirect, else leave'm */ + /* update the PSD with new address */ + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + i_flags |= BT; /* we branched, so no PC update */ + if (IR & IND) /* see if CCs from last indirect location are wanted */ + PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */ +//fprintf(stderr, "BR t %.8x addr %.8x PSD1 %.8x\r\n", t, addr, PSD1); + } + break; + + case 0xF4>>2: /* 0xF4 RR|SD|ADR - RR|SB|WRD */ /* Branch increment */ + dest += 1 << ((IR >> 21) & 3); /* use bits 9 & 10 to incr reg */ + if (dest != 0) { /* if reg is not 0, take the branch */ + /* we are taking the branch, set CC's if indirect, else leave'm */ + /* update the PSD with new address */ +#if 1 +/* FIXME */ if (PC == (addr & 0x7FFFC)) { /* BIB to current PC, bump branch addr */ + addr += 4; +// fprintf(stderr, "BI? stopping BIB $ addr %x PC %x\r\n", addr, PC); + } +#endif + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + if (IR & IND) /* see if CCs from last indirect location are wanted */ + PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */ + i_flags |= BT; /* we branched, so no PC update */ + } + break; + + case 0xF8>>2: /* 0xF8 SM|ADR - SM|ADR */ /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, TRP */ + switch((opr >> 7) & 0x7) { /* use bits 6-8 to determine instruction */ + case 0x0: /* ZMx F80x */ /* SM */ + dest = 0; /* destination value is zero */ + i_flags |= SM; /* SM not set so set it to store value */ + break; + case 0x1: /* BL F880 */ + /* copy CC's from instruction and PC incremented by 4 */ + GPR[0] = ((PSD1 & 0x78000000) | (PSD1 & 0x7fffe)) + 4; + if (IR & IND) /* see if CC from last indirect loacation are wanted */ + GPR[0] = (CC | (PSD1 & 0x7fffe)) + 4; /* set CC's and incremented PC */ + /* update the PSD with new address */ + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); + i_flags |= BT; /* we branched, so no PC update */ + break; + + case 0x3: /* LPSD F980 */ + /* fall through */; + case 0x5: /* LPSDCM FA80 */ + { +#if 0 +int j; +char n[9]; +uint32 dqe = M[0x8e8>>2]; +for (j=0; j<8; j++) { + n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff; + if (n[j] == 0) + n[j] = 0x20; +} +n[8] = 0; +#endif + CPUSTATUS |= 0x40; /* enable software traps */ + /* this will allow attn and */ + /* power fail traps */ + if ((TRAPME = Mem_read(addr, &PSD1))) { /* get PSD1 from memory */ + goto newpsd; /* memory read error or map fault */ + } + if ((TRAPME = Mem_read(addr+4, &PSD2))) { /* get PSD2 from memory */ + goto newpsd; /* memory read error or map fault */ + } + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + /* set new map mode and interrupt blocking state in CPUSTATUS */ + if (PSD2 & MAPBIT) { + CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ + modes |= MAPMODE; /* set mapped mode */ + } else + CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */ + /* set interrupt blocking state */ + if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */ + if (PSD2 & 0x4000) /* no, is it set blocking state */ + CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */ + else { + CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */ + irq_pend = 1; /* start scanning interrupts again */ + } + } + PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */ + if (CPUSTATUS & 0x80) /* see if old mode is blocked */ + PSD2 |= 0x00004000; /* set to blocked state */ + + /* TRY if cpix is zero, copy cpix from PSD2 in SPAD[0xf5] */ + if ((PSD2 & 0x3fff) == 0) + PSD2 |= (SPAD[0xf5] & 0x3fff); /* use new cpix */ + + if (opr & 0x0200) { /* Was it LPSDCM? */ + /* map bit must be on to load maps */ + if (PSD2 & MAPBIT) { +#if 0 + // FIXME DEBUG EDIT +// if (n[0] == 'E' && n[1] == 'D' && n[2] == 'I' && n[3] == 'T') +// traceme = trstart; /* start tracing */ +traceme++; /* start trace */ +//if (traceme >= trstart) { +fprintf(stderr, "LPSDCM #%d LOAD MAPS PSD1 %x PSD2 %x SPAD PSD2 %x CPUSTATUS %x C.CURR %x LMN %s\r\n", traceme, PSD1, PSD2, SPAD[0xf5], CPUSTATUS, dqe, n); +fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]); +fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]); +fprintf(stderr, "\r\n"); +//reason = STOP_HALT; /* do halt for now */ +//} +#endif + /* set mapped mode in cpu status */ + CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ + /* we need to load the new maps */ + TRAPME = load_maps(&PSD1); /* load maps for new PSD */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + sim_debug(DEBUG_EXP, &cpu_dev, + "LPSDCM MAPS LOADED TRAPME = %x PSD1 %x PSD2 %x CPUSTATUS %x\n", + TRAPME, PSD1, PSD2, CPUSTATUS); + } + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + } else { + /* LPSD */ +//traceme++; /* start trace */ +#if 0 +sim_debug(DEBUG_EXP, &cpu_dev, "LPSD PSD1 %x PSD2 %x CPUSTATUS %x\n", PSD1, PSD2, CPUSTATUS); +fprintf(stderr, "LPSD PSD1 %x PSD2 %x SPAD PSD2 %x CPUSTATUS %x C.CURR %x LMN %s\r\n", + PSD1, PSD2, SPAD[0xf5], CPUSTATUS, dqe, n); +fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]); +fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]); +fprintf(stderr, "\r\n"); +#endif + } +} + /* TRAPME can be error from LPSDCM or OK here */ + skipinstr = 1; /* skip next interrupt test only once */ + goto newpsd; /* load the new psd */ + break; + + case 0x4: /* JWCS */ /* not used in simulator */ + case 0x2: /* BRI */ /* TODO - only for 32/55 or 32/7X in PSW mode */ + case 0x6: /* TRP */ + case 0x7: /* TPR */ + TRAPME = UNDEFINSTR_TRAP; /* trap condition */ + goto newpsd; /* undefined instruction trap */ + break; + } + break; + +/* F Class I/O device instruction format */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02 03 04 05|06 07 08|09 10 11 12|13 14 15|16|17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */ +/* | Op Code | Reg | I/O type | Aug |0 | Channel Address | Device Sub-address | */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ +/* E Class I/O device instruction format */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02 03 04 05|06 07 08 09 10 11 12|13 14 15|16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| */ +/* | Op Code | Device Number | Aug | Command Code | */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ + case 0xFC>>2: /* 0xFC IMM - IMM */ /* XIO, CD, TD, Interrupt Control */ + if ((modes & PRIVBIT) == 0) { /* must be privileged to do I/O */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + TRAPSTATUS |= 0x1000; /* set Bit 19 of Trap Status word */ + goto newpsd; /* Privlege violation trap */ + } + if ((opr & 0x7) != 0x07) { /* aug is 111 for XIO instruction */ + /* Process Non-XIO instructions */ + uint32 status = 0; /* status returned from device */ + uint32 device = (opr >> 3) & 0x7f; /* get device code */ + uint32 prior = device; /* interrupt priority */ + t = SPAD[prior+0x80]; /* get spad entry for interrupt */ + addr = SPAD[0xf1] + (prior<<2); /* vector address in SPAD */ + addr = M[addr>>2]; /* get the interrupt context block addr */ +//fprintf(stderr, "CD/TD etc device %x intr %x spad %.8x addr %x\r\n", device, prior, t, addr); + + switch(opr & 0x7) { /* use bits 13-15 to determine instruction */ + case 0x0: /* EI FC00 Enable Interrupt */ + prior = (opr >> 3) & 0x7f; /* get priority level */ + /* SPAD entries for interrupts begin at 0x80 */ + t = SPAD[prior+0x80]; /* get spad entry for interrupt */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* system check */ + INTS[prior] |= INTS_ENAB; /* enable specified int level */ + SPAD[prior+0x80] |= SINT_ENAB; /* enable in SPAD too */ + irq_pend = 1; /* start scanning interrupts again */ +//fprintf(stderr, "EIO EI intr %.2x SPAD %.8x\r\n", prior, t); + if (prior == 0x18) /* is this the clock starting */ + rtc_setup(1, prior); /* tell clock to start */ + if (prior == 0x5f) /* is this the initerval timer starting */ + itm_setup(1, prior); /* tell timer to start */ + break; + + case 0x1: /* DI FC01 */ + prior = (opr >> 3) & 0x7f; /* get priority level */ + /* SPAD entries for interrupts begin at 0x80 */ + t = SPAD[prior+0x80]; /* get spad entry for interrupt */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* system check */ + INTS[prior] &= ~INTS_ENAB; /* disable specified int level */ + INTS[prior] &= ~INTS_REQ; /* clears any requests also */ + SPAD[prior+0x80] &= ~SINT_ENAB; /* disable in SPAD too */ +//fprintf(stderr, "EIO DI intr %.2x SPAD %.8x\r\n", prior, t); + if (prior == 0x18) /* is this the clock stopping */ + rtc_setup(0, prior); /* tell clock to stop */ + if (prior == 0x5f) /* is this the initerval timer stopping */ + itm_setup(0, prior); /* tell timer to stop */ + break; + + case 0x2: /* RI FC02 */ + prior = (opr >> 3) & 0x7f; /* get priority level */ + /* SPAD entries for interrupts begin at 0x80 */ + t = SPAD[prior+0x80]; /* get spad entry for interrupt */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* system check */ + INTS[prior] |= INTS_REQ; /* set the request flag for this level */ + irq_pend = 1; /* start scanning interrupts again */ +//fprintf(stderr, "EIO RI intr %.2x SPAD %.8x\r\n", prior, t); + break; + + case 0x3: /* AI FC03 */ + prior = (opr >> 3) & 0x7f; /* get priority level */ + /* SPAD entries for interrupts begin at 0x80 */ + t = SPAD[prior+0x80]; /* get spad entry for interrupt */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* system check */ + INTS[prior] |= INTS_ACT; /* activate specified int level */ +//fprintf(stderr, "EIO AI intr %.2x SPAD %.8x\r\n", prior, t); + break; + + case 0x4: /* DAI FC04 */ + prior = (opr >> 3) & 0x7f; /* get priority level */ + /* SPAD entries for interrupts begin at 0x80 */ + t = SPAD[prior+0x80]; /* get spad entry for interrupt */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* system check */ + INTS[prior] &= ~INTS_ACT; /* deactivate specified int level */ + SPAD[prior+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ +//fprintf(stderr, "EIO DAI intr %.2x SPAD %.8x INTS[%x] %x\r\n", prior, t, prior, INTS[prior]); + irq_pend = 1; /* start scanning interrupts again */ + skipinstr = 1; /* skip interrupt test */ + /* instruction following a DAI can not be interrupted */ + /* skip tests for interrupts if this is the case */ + break; + + case 0x5: /* TD FC05 */ /* bits 13-15 is test code type */ + case 0x6: /* CD FC06 */ + /* If CD or TD, make sure device is not F class device */ + /* the channel must be defined as a non class F I/O channel in SPAD */ + /* if class F, the system will generate a system check trap */ + t = SPAD[device]; /* get spad entry for channel */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* system check */ +//fprintf(stderr, "EIO TD/CD chan %.4x spad %.8x\r\n", device, t); + if ((t & 0x0f000000) == 0x0f000000) { /* class in bits 4-7 */ +syscheck: + TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */ + TRAPSTATUS &= ~BIT0; /* class E error bit */ + TRAPSTATUS &= ~BIT1; /* I/O processing error */ + goto newpsd; /* machine check trap */ + } + if (opr & 0x1) { /* see if CD or TD */ + /* process a TD */ +// if ((TRAPME = testEIO(device, testcode, &status))) +// goto newpsd; /* error returned, trap cpu */ + /* return status has new CC's in bits 1-4 of status word */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status CCs */ +//fprintf(stderr, "EIO TD chan %.4x spad %.8x\r\n", device, t); + goto inv; /* invalid instruction until I fix it */ + } else { + /* process a CD */ +// if ((TRAPME = startEIO(device, &status))) +// goto newpsd; /* error returned, trap cpu */ +// t = SPAD[device]; /* get spad entry for channel */ + /* t has spad entry for device */ + /* get the 1's comp of interrupt address from bits 9-15 SPAD entry */ + ix = (t & 0x007f0000) >> 16; /* get the 1's comp of int level */ +//fprintf(stderr, "XIO1 chan %8x intr %8x spad %.8x\r\n", chan, ix, bc); + ix = 127 - ix; /* get positive number for interrupt */ +//fprintf(stderr, "XIO2 chan %x intr %x spad %.8x\r\n", chan, ix, bc); + temp = (IR & 0x7f); /* get cmd from instruction */ + if (device == 0x7f) { +//fprintf(stderr, "Interval Timer CD call cmd %x GPR[0] %x intr %x\r\n", temp, GPR[0], ix); + status = itm_rdwr(temp, GPR[0], ix); /* read/write the interval timer */ +//fprintf(stderr, "Interval Timer CD return status %x cmd %x GPR[0] %x intr %x\r\n", status, temp, GPR[0], ix); + if (temp != 0x39) /* this cmd does not return value */ + GPR[0] = status; /* return count in reg 0 */ + /* No CC's going out */ + } else { + goto inv; /* invalid instruction until I fix it */ + } + } + break; + case 0x7: /* XIO FC07*/ /* should never get here */ + break; + } + break; /* skip over XIO code */ + } + + /* Process XIO instructions */ + /* if reg is non-zero, add reg to 15 bits from instruction */ + if (reg) + temp2 = (IR & 0x7fff) + (GPR[reg] & 0x7fff); /* set new chan/suba into IR */ + else + temp2 = (IR & 0x7fff); /* set new chan/suba into IR */ + lchan = (temp2 & 0x7F00) >> 8; /* get 7 bit logical channel address */ + suba = temp2 & 0xFF; /* get 8 bit subaddress */ + /* the channel must be defined as a class F I/O channel in SPAD */ + /* if not class F, the system will generate a system check trap */ + t = SPAD[lchan]; /* get spad entry for channel */ + if (t == 0 || t == 0xffffffff) /* if not set up, die */ + goto syscheck; /* machine check */ +//fprintf(stderr, "XIO chan %x sa %x spad %.8x\r\n", chan, suba, t); +//sim_debug(DEBUG_EXP, &cpu_dev, "$$ XIO lchan %x sa %x spad %.8x\n", lchan, suba, t); + if ((t & 0x0f000000) != 0x0f000000) { /* class in bits 4-7 */ +mcheck: + TRAPME = MACHINECHK_TRAP; /* trap condition */ + TRAPSTATUS |= BIT0; /* class F error bit */ + TRAPSTATUS &= ~BIT1; /* I/O processing error */ + goto newpsd; /* machine check trap */ + } + /* get real channel from spad device entry */ + chan = (t & 0x7f00) >> 8; /* real channel */ + /* get the 1's comp of interrupt address from bits 9-15 SPAD entry */ + ix = (t & 0x007f0000) >> 16; /* get the 1's comp of int level */ +//fprintf(stderr, "XIO1 chan %8x intr %8x spad %.8x\r\n", chan, ix, bc); + ix = 127 - ix; /* get positive number for interrupt */ +//fprintf(stderr, "XIO2 chan %x intr %x spad %.8x\r\n", chan, ix, bc); + bc = SPAD[ix+0x80]; /* get interrupt entry for channel */ +//fprintf(stderr, "XIO chan %x intr %x spad %.8x\r\n", chan, ix, bc); + /* SPAD address F1 has interrupt table address */ + addr = SPAD[0xf1] + (ix<<2); /* vector address in SPAD */ +//fprintf(stderr, "XIOa spad %x intr %x spad %.8x addr %x\r\n", SPAD[0xf1], ix, bc, addr); + addr = M[addr>>2]; /* get the interrupt context block addr */ +//fprintf(stderr, "XIOb chan %x intr %x spad %.8x addr %x\r\n", chan, ix, bc, addr); + /* the context block contains the old PSD, */ + /* new PSD, IOCL address, and I/O status address */ + if (addr == 0) /* must be initialized address */ + goto mcheck; /* bad int icb address */ +//fprintf(stderr, "XIO chan %x intr %x addr %x iocla %x\r\n", chan, ix, addr, addr + 16); + if ((TRAPME = Mem_read(addr+16, &temp))) { /* get iocl address from icb wd 4 */ + goto mcheck; /* machine check if not there */ + } +//fprintf(stderr, "XIOx chan %x intr %x addr %x temp %x\r\n", chan, ix, addr, temp); + /* iocla must be valid addr if it is a SIO instruction */ + if (((temp & MASK24) == 0) && (((opr >> 2) & 0xf) == 2)) + goto mcheck; /* bad iocl address */ + +//fprintf(stderr, "XIO ready chan %x intr %x icb %x iocla %x iocd1 %.8x iocd2 %0.x8\r\n", +// chan, ix, addr, addr+16, M[temp>>2], M[(temp+4)>>2]); +//sim_debug(DEBUG_EXP, &cpu_dev, "XIO ready chan %x intr %x icb %x iocla %x iocd1 %.8x iocd2 %.8x\n", +// chan, ix, addr, addr+16, M[temp>>2], M[(temp+4)>>2]); + /* at this point, the channel has a valid SPAD channel entry */ + /* t is SPAD entry contents for chan device */ + /* temp2 has IR + reg contents if reg != 0 */ + /* lchan - logical channel address */ + /* chan - channel address */ + /* suba - channel device subaddress */ + /* ix - positive interrupt level */ + /* addr - ICB for specified interrupt level, points to 6 wd block */ + /* temp - First IOCD address */ +//fprintf(stderr, "XIO switch %x lchan %x chan %x intr %x chsa %x IOCDa %x\r\n", ((opr>>3)&0xf), lchan, chan, ix, (chan<<8)|suba, temp); +//sim_debug(DEBUG_EXP, &cpu_dev, "XIO switch chan %x intr %x chsa %x IOCDa %.8x\n", chan, ix, (chan<<8)|suba, temp); + switch((opr >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */ + uint32 status; /* status returned by various functions */ + uint16 chsa; /* logical device address */ + + case 0x00: /* Unassigned */ + case 0x01: /* Unassigned */ + case 0x0A: /* Unassigned */ + TRAPME = UNDEFINSTR_TRAP; /* trap condition */ + goto newpsd; /* undefined instruction trap */ + break; + + case 0x09: /* Enable write channel ECWCS */ + case 0x0B: /* Write channel WCS WCWCS */ + /* for now or maybe forever, return unsupported transaction */ + PSD1 = ((PSD1 & 0x87fffffe) | (CC2BIT|CC4BIT)); /* insert status 5 */ + TRAPME = UNDEFINSTR_TRAP; /* trap condition */ + goto newpsd; /* undefined instruction trap */ + break; + + case 0x02: /* Start I/O SIO */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + if ((TRAPME = startxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "@@XIO SIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO SIO ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + case 0x03: /* Test I/O TIO */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + if ((TRAPME = testxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "@@XIO TIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO TIO ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + case 0x04: /* Stop I/O STPIO */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + if ((TRAPME = stopxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + /* SPAD entries for interrupts begin at 0x80 */ +/* 07-16-18 chg */ INTS[ix] &= ~INTS_REQ; /* clears any requests also */ + INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */ + SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "@@XIO STPIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO STPIO ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + /* TODO Finish XIO */ + case 0x05: /* Reset channel RSCHNL */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + /* SPAD entries for interrupts begin at 0x80 */ + INTS[ix] &= ~INTS_REQ; /* clears any requests */ + INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */ + SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ +//fprintf(stderr, "RSCHNL intr %.2x SPAD %.8x INTS[%x] %x\r\n", ix, bc, ix, INTS[ix]); + if ((TRAPME = rschnlxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "XIO RSCHNL ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO RSCHNL ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + case 0x06: /* Halt I/O HIO */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + if ((TRAPME = haltxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "@@XIO HALTXIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "HIO HALTXIO ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + case 0x07: /* Grab controller GRIO n/u */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + if ((TRAPME = grabxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "XIO GRIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO GRIO ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + case 0x08: /* Reset controller RSCTL */ + chsa = temp2 & 0x7FFF; /* get logical device address */ + if ((TRAPME = stopxio(chsa, &status))) + goto newpsd; /* error returned, trap cpu */ + PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */ +//fprintf(stderr, "XIO STPIO ret chan %x chsa %x status %x\r\n", chan, (chan<<8)|suba, status); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO RSCTL ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status); + break; + + /* TODO Finish XIO interrupts */ + case 0x0C: /* Enable channel interrupt ECI */ + chsa = temp2 & 0x7FFF; /* get logical device address */ +//fprintf(stderr, "XIO ECI chan %x sa %x spad %.8x INTS %x SPAD %x\r\n", chan, suba, t, INTS[ix], SPAD[ix+0x80]); +sim_debug(DEBUG_EXP, &cpu_dev, "XIO ECI chan %x sa %x spad %.8x\n", chan, suba, t); + /* SPAD entries for interrupts begin at 0x80 */ + INTS[ix] |= INTS_ENAB; /* enable specified int level */ + SPAD[ix+0x80] |= SINT_ENAB; /* enable in SPAD too */ + INTS[ix] &= ~INTS_REQ; /* clears any requests also TRY 06-09-18 */ +//TRY 06-09-18 irq_pend = 1; /* start scanning interrupts again */ +//fprintf(stderr, "ECI intr %.2x SPAD %.8x INTS[%x] %x\r\n", ix, bc, ix, INTS[ix]); + break; + + case 0x0D: /* Disable channel interrupt DCI */ + chsa = temp2 & 0x7FFF; /* get logical device address */ +sim_debug(DEBUG_EXP, &cpu_dev, "XIO DCI chan %x sa %x spad %.8x\n", chan, suba, t); + /* SPAD entries for interrupts begin at 0x80 */ + INTS[ix] &= ~INTS_ENAB; /* disable specified int level */ + INTS[ix] &= ~INTS_REQ; /* clears any requests also */ + SPAD[ix+0x80] &= ~SINT_ENAB; /* disable in SPAD too */ +//fprintf(stderr, "DCI intr %.2x SPAD %.8x INTS[%x] %x\r\n", ix, bc, ix, INTS[ix]); + break; + + case 0x0E: /* Activate channel interrupt ACI */ + chsa = temp2 & 0x7FFF; /* get logical device address */ +sim_debug(DEBUG_EXP, &cpu_dev, "XIO ACI chan %x sa %x spad %.8x\n", chan, suba, t); + /* SPAD entries for interrupts begin at 0x80 */ + INTS[ix] |= INTS_ACT; /* activate specified int level */ +//fprintf(stderr, "ACI intr %.2x SPAD %.8x INTS[%x] %x\r\n", ix, bc, ix, INTS[ix]); + break; + + case 0x0F: /* Deactivate channel interrupt DACI */ + /* Note, instruction following DACI is not interruptable */ + chsa = temp2 & 0x7FFF; /* get logical device address */ +sim_debug(DEBUG_EXP, &cpu_dev, "XIO DACI chan %x sa %x spad %.8x\n", chan, suba, t); + /* SPAD entries for interrupts begin at 0x80 */ +/* 07-16-18 chg */ INTS[ix] &= ~INTS_REQ; /* clears any requests also */ + INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */ + SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ +//fprintf(stderr, "DACI intr %.2x SPAD %.8x INTS[%x] %x\r\n", ix, bc, ix, INTS[ix]); + irq_pend = 1; /* start scanning interrupts again */ + skipinstr = 1; /* skip interrupt test */ +//NOTE CC must be returned */ + break; + } /* end of XIO switch */ + break; + } /* End of Instruction Switch */ + + /* any instruction with an arithmetic exception will still end up here */ + /* after the instruction is done and before incrementing the PC, */ + /* we will trap the cpu if ovl is set nonzero by an instruction */ + + /* Store result to register */ + if (i_flags & SD) { + if (dbl) { /* if double reg, store 2nd reg */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + } else { + GPR[reg] = (uint32)(dest & FMASK); /* save the reg */ + } + } + + /* Store result to base register */ + if (i_flags & SB) { + if (dbl) { /* no dbl wd store to base regs */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + BR[reg] = (uint32)(dest & FMASK); /* save the base reg */ +//fprintf(stderr, "SB base reg %x dest(BR) %.8x\r\n", reg, BR[reg]); + } + + /* Store result to memory */ + if (i_flags & SM) { + /* Check if byte of half word */ + if (((FC & 04) || (FC & 5) == 1)) { /* hw or byte requires read first */ + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + } + switch(FC) { + case 2: /* double word store */ + if ((addr & 2) != 2) { + TRAPME = ADDRSPEC_TRAP; /* address not on dbl wd boundry, error */ + goto newpsd; /* go execute the trap now */ + } + temp = (uint32)(dest & MASK32);/* get lo 32 bit */ + if ((TRAPME = Mem_write(addr + 4, &temp))) + goto newpsd; /* memory write error or map fault */ + temp = (uint32)(dest >> 32); /* move upper 32 bits to lo 32 bits */ + break; + + case 0: /* word store */ + temp = (uint32)(dest & FMASK); /* mask 32 bit of reg */ + if ((addr & 3) != 0) { + /* Address fault */ + TRAPME = ADDRSPEC_TRAP; /* address not on wd boundry, error */ + goto newpsd; /* go execute the trap now */ + } + break; + + case 1: /* left halfword write */ + temp &= RMASK; /* mask out 16 left most bits */ + temp |= (uint32)(dest & RMASK) << 16; /* put into left most 16 bits */ + if ((addr & 1) != 1) { + /* Address fault */ + TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ + goto newpsd; /* go execute the trap now */ + } + break; + + case 3: /* right halfword write */ + temp &= LMASK; /* mask out 16 right most bits */ + temp |= (uint32)(dest & RMASK); /* put into right most 16 bits */ + if ((addr & 3) != 3) { + TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ + goto newpsd; /* go execute the trap now */ + } + break; + + case 4: + case 5: + case 6: + case 7: /* byte store operation */ + temp &= ~(0xFF << (8 * (7 - FC))); /* clear the byte to store */ + temp |= (uint32)(dest & 0xFF) << (8 * (7 - FC)); /* insert new byte */ + break; + } + /* store back the modified memory location */ + if ((TRAPME = Mem_write(addr, &temp))) /* store back to memory */ + goto newpsd; /* memory write error or map fault */ + } + + /* Update condition code registers */ + if (i_flags & SCC) { + PSD1 &= 0x87FFFFFe; /* clear the old CC's */ + if (ovr) /* if overflow, set CC1 */ + CC |= CC1BIT; /* show we had AEXP */ + else + CC = 0; /* no CC's yet */ + if (dest & MSIGN) /* is it neg */ + CC |= CC3BIT; /* if neg, set CC3 */ + else if (dest == 0) + CC |= CC4BIT; /* if zero, set CC4 */ + else + CC |= CC2BIT; /* if gtr than zero, set CC2 */ + PSD1 |= CC & 0x78000000; /* update the CC's in the PSD */ + } + + /* Update instruction pointer to next instruction */ + if (EXM_EXR != 0) { /* special handling for EXM, EXR, EXRR */ + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + EXM_EXR = 0; /* reset PC increment for EXR */ + } else + if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */ +//fprintf(stderr, "@PCI1 temp %.8x addr %.8x PSD1 %.8x flags %.8x\r\n", temp, addr, PSD1, i_flags); + /* branch not taken, so update the PC */ + if (i_flags & HLF) { + PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); + } else { + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + } +//fprintf(stderr, "@PCI2 temp %.8x addr %.8x PSD1 %.8x flags %.8x\r\n", temp, addr, PSD1, i_flags); + } + + /* check if we had an arithmetic exception on the last instruction*/ + if (ovr && (modes & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } +#if 0 + /* no trap, so continue with next instruction */ +//PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ +// Get CCs from PSD1 and PC from original instruction */ +//if (traceme >= 4) { +if (traceme >= trstart) { +OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ +OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ +if (modes & MAPMODE) + fprintf(stderr, "M%.8x %.8x ", OPSD1, OIR); +else + fprintf(stderr, "U%.8x %.8x ", OPSD1, OIR); +fprint_inst(stderr, OIR, 0); /* display instruction */ +fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]); +fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]); +fprintf(stderr, "\r\n"); +} +#endif +sim_debug(DEBUG_DATA, &cpu_dev, "R0=%08x R1=%08x R2=%08x R3=%08x\n", GPR[0], GPR[1], GPR[2], GPR[3]); +sim_debug(DEBUG_DATA, &cpu_dev, "R4=%08x R5=%08x R6=%08x R7=%08x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + continue; /* keep running */ +// break; /* quit for now after each instruction */ + +newpsd: +//fprintf(stderr, "place @ newpsd PSD1 %.8x PSD2 %.8x TRAPME %.4x\r\n", PSD1, PSD2, TRAPME); + /* we get here from a LPSD, LPSDCM, INTR, or TRAP */ + if (TRAPME) { + /* SPAD location 0xf0 has trap vector base address */ + uint32 tta = SPAD[0xf0]; /* get trap table address in memory */ + uint32 tvl; /* trap vector location */ + if (tta == 0 || tta == 0xffffffff) + tta = 0x80; /* if not set, assume 0x80 FIXME */ + /* Trap Table Address in memory is pointed to by SPAD 0xF0 */ + /* TODO update cpu status and trap status words with reason too */ + switch(TRAPME) { + case POWERFAIL_TRAP: /* 0x80 power fail trap */ + case POWERON_TRAP: /* 0x84 Power-On trap */ + case MEMPARITY_TRAP: /* 0x88 Memory Parity Error trap */ + case NONPRESMEM_TRAP: /* 0x8C Non Present Memory trap */ + case UNDEFINSTR_TRAP: /* 0x90 Undefined Instruction Trap */ + case PRIVVIOL_TRAP: /* 0x94 Privlege Violation Trap */ +//TODO case SVCCALL_TRAP: /* 0x98 Supervisor Call Trap */ + case MACHINECHK_TRAP: /* 0x9C Machine Check Trap */ + case SYSTEMCHK_TRAP: /* 0xA0 System Check Trap */ + case MAPFAULT_TRAP: /* 0xA4 Map Fault Trap */ + case IPUUNDEFI_TRAP: /* 0xA8 IPU Undefined Instruction Trap */ + case SIGNALIPU_TRAP: /* 0xAC Signal IPU/CPU Trap */ + case ADDRSPEC_TRAP: /* 0xB0 Address Specification Trap */ + case CONSOLEATN_TRAP: /* 0xB4 Console Attention Trap */ + case PRIVHALT_TRAP: /* 0xB8 Privlege Mode Halt Trap */ + case AEXPCEPT_TRAP: /* 0xBC Arithmetic Exception Trap */ + default: + tta = tta + (TRAPME - 0x80); /* tta has mem addr of trap vector */ + tvl = M[tta>>2] & 0x7FFFC; /* get trap vector address from trap vector loc */ +//fprintf(stderr, "tvl %.8x, tta %.8x status %.8x\r\n", tvl, tta, CPUSTATUS); + if (tvl == 0 || tvl == 0x7FFFC || (CPUSTATUS & 0x40) == 0) { + /* vector is zero or software has not enabled traps yet */ + /* execute a trap halt */ + /* set the PSD to trap vector location */ + PSD1 = 0x80000000 + TRAPME; /* just priv and PC to trap vector */ + PSD2 = 0x00004000; /* unmapped, blocked interrupts mode */ + M[0x680>>2] = PSD1; /* store PSD 1 */ + M[0x684>>2] = PSD2; /* store PSD 2 */ + M[0x688>>2] = TRAPSTATUS; /* store trap status */ + M[0x68C>>2] = 0; /* This will be device table entry later TODO */ +fprintf(stderr, "[][][][][][][][][][][] HALT TRAP [][][][][][][][][][][][]\r\n"); +fprintf(stderr, "PSD1 %.8x PSD2 %.8x TRAPME %.4x\r\n", PSD1, PSD2, TRAPME); + for (ix=0; ix<8; ix+=2) { + fprintf(stderr, "GPR[%d] %.8x GPR[%d] %.8x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } +fprintf(stderr, "[][][][][][][][][][][] HALT TRAP [][][][][][][][][][][][]\r\n"); + return STOP_HALT; /* exit to simh for halt */ + } else { + /* valid vector, so store the PSD, fetch new PSD */ + bc = PSD2 & 0x3ffc; /* get copy of cpix */ + M[tvl>>2] = PSD1 & 0xfffffffe; /* store PSD 1 */ + M[(tvl>>2)+1] = PSD2; /* store PSD 2 */ + PSD1 = M[(tvl>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(tvl>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */ + M[(tvl>>2)+4] = TRAPSTATUS; /* store trap status */ + + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + /* set new map mode and interrupt blocking state in CPUSTATUS */ + if (PSD2 & MAPBIT) { + CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */ + modes |= MAPMODE; /* set mapped mode */ + } else + CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */ + /* set interrupt blocking state */ + if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */ + if (PSD2 & 0x4000) /* no, is it set blocking state */ + CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */ + else + CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */ + } + PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */ + if (CPUSTATUS & 0x80) /* see if old mode is blocked */ + PSD2 |= 0x00004000; /* set to blocked state */ + + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ +#if 0 +if (TRAPME == UNDEFINSTR_TRAP) { +sim_debug(DEBUG_EXP, &cpu_dev, "TRAP PSD1 %x PSD2 %x CPUSTATUS %x\n", PSD1, PSD2, CPUSTATUS); +fprintf(stderr, "TRAPS %x LOAD MAPS PSD1 %x PSD2 %x CPUSTATUS %x\r\n", TRAPME, PSD1, PSD2, CPUSTATUS); +goto dumpi; +} +#endif + break; /* Go execute the trap */ + } + break; + } + } + skipinstr = 1; /* skip next instruction */ + /* we have a new PSD loaded via a LPSD or LPSDCM */ + /* TODO finish instruction history, then continue */ + /* update cpu status word too */ +#if 0 +if (traceme >= trstart) { +dumpi: +OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ +OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ +if (modes & MAPMODE) + fprintf(stderr, "M%.8x %.8x ", OPSD1, OIR); +else + fprintf(stderr, "U%.8x %.8x ", OPSD1, OIR); +fprint_inst(stderr, OIR, 0); /* display instruction */ +fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]); +fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]); +fprintf(stderr, "\r\n"); +} +#endif +sim_debug(DEBUG_DATA, &cpu_dev, "R0=%08x R1=%08x R2=%08x R3=%08x\n", GPR[0], GPR[1], GPR[2], GPR[3]); +sim_debug(DEBUG_DATA, &cpu_dev, "R4=%08x R5=%08x R6=%08x R7=%08x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + continue; /* single step cpu just for now */ +// break; /* quit for now after each instruction */ + } /* end while */ + + /* Simulation halted */ +//fprintf(stderr, "@end PSD1 %.8x PSD2 %.8x addr %.8x\r\n", PSD1, PSD2, addr); + return reason; +} + +/* these are the default ipl devices defined by the CPU jumpers */ +/* they can be overridden by specifying IPL device at ipl time */ +uint32 def_disk = 0x0800; /* disk channel 8, device 0 */ +uint32 def_tape = 0x1000; /* tape device 10, device 0 */ +uint32 def_floppy = 0x7ef0; /* IOP floppy disk channel 7e, device f0 */ +//int once = 0; /* one time inits */ + +/* Reset routine */ +/* do any one time initialization here for cpu */ +t_stat cpu_reset(DEVICE * dptr) +{ + int i; + + /* leave regs alone so values can be passed to boot code */ + PSD1 = 0x80000000; /* privileged, non mapped, non extended, address 0 */ + PSD2 = 0x00004000; /* blocked interrupts mode */ + modes = (PRIVBIT | BLKMODE); /* set modes to privileged and blocked interrupts */ + CC = 0; /* no CCs too */ + CPUSTATUS = CPU_MODEL; /* clear all cpu status except cpu type */ + CPUSTATUS |= 0x80000000; /* set privleged state bit 0 */ + CPUSTATUS |= 0x00000080; /* set blocked mode state bit 24 */ + TRAPSTATUS = CPU_MODEL; /* clear all trap status except cpu type */ + + chan_set_devs(); /* set up the defined devices on the simulator */ + + /* set default breaks to execution tracing */ + sim_brk_types = sim_brk_dflt = SWMASK('E'); + /* zero regs */ + for (i = 0; i < 8; i++) { + GPR[i] = 0; /* clear the registers */ + BR[i] = 0; /* clear the registers */ + } + /* zero interrupt status words */ + for (i = 0; i < 112; i++) + INTS[i] = 0; /* clear interrupt status flags */ + + /* add code here to initialize the SEL32 cpu scratchpad on initial start */ + /* see if spad setup by software, if yes, leave spad alone */ + /* otherwise set the default values into the spad */ + /* CPU key is 0xECDAB897, IPU key is 0x13254768 */ + /* Keys are loaded by the O/S software during the boot loading sequence */ + if (SPAD[0xf7] != 0xecdab897) + { + int ival = 0; /* init value for concept 32 */ + + if (CPU_MODEL < MODEL_27) + ival = 0xfffffff; /* init value for 32/7x int and dev entries */ + for (i = 0; i < 1024; i++) + MAPC[i] = 0; /* clear 2048 halfword map cache */ + for (i = 0; i < 224; i++) + SPAD[i] = ival; /* init 128 devices and 96 ints in the spad */ + for (i = 224; i < 256; i++) /* clear the last 32 extries */ + SPAD[i] = 0; /* clear the spad */ + SPAD[0xf0] = 0x80; /* default Trap Table Address (TTA) */ + SPAD[0xf1] = 0x100; /* Interrupt Table Address (ITA) */ + SPAD[0Xf2] = 0x700; /* IOCD Base Address */ + SPAD[0xf3] = 0x788; /* Master Process List (MPL) table address */ + SPAD[0xf4] = def_tape; /* Default IPL address from console IPL command or jumper */ + SPAD[0xf5] = 0x00004000; /* current PSD2 defaults to blocked */ + SPAD[0xf6] = 0; /* reserved (PSD1 ??) */ + SPAD[0xf7] = 0; /* make sure key is zero */ + SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */ + SPAD[0xf9] = CPU_MODEL; /* set default cpu type in cpu status word */ + SPAD[0xff] = 0x00ffffff; /* interrupt level 7f 1's complament */ + } + M[0] = 0x02000000; /* 0x00 IOCD 1 read into address 0 */ + M[1] = 0x60000078; /* 0x04 IOCD 1 CMD Chain, Suppress incor length, 120 bytes */ + M[2] = 0x53000000; /* 0x08 IOCD 2 BKSR or RZR to re-read boot code */ + M[3] = 0x60000001; /* 0x0C IOCD 2 CMD chain,Supress incor length, 1 byte */ + M[4] = 0x02000000; /* 0x10 IOCD 3 Read into address 0 */ + M[5] = 0x000006EC; /* 0x14 IOCD 3 Read 0x6EC bytes */ + loading = 0; /* not loading yet */ + /* we are good to go */ + return SCPE_OK; +} + +/* Memory examine */ +/* examine a 32bit memory location */ +/* address is byte address with bits 30,31 = 0 */ +t_stat cpu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw) +{ + uint32 temp, t; + uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */ + + /* MSIZE is in 32 bit words */ + if (addr >= MEMSIZE) /* see if address is within our memory */ + return SCPE_NXM; /* no, none existant memory error */ + if (vptr == NULL) /* any address specified by user */ + return SCPE_OK; /* no, just ignore the request */ + *vptr = M[addr]; /* return memory contents */ + return SCPE_OK; /* we are all ok */ +} + +/* Memory deposit */ +/* modify a 32bit memory location */ +/* address is byte address with bits 30,31 = 0 */ +t_stat cpu_dep(t_value val, t_addr baddr, UNIT *uptr, int32 sw) +{ + uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */ + +//fprintf(stderr, "cpu_dep baddr %0x, sw %x\b\n", baddr, sw); + /* MSIZE is in 32 bit words */ + if (addr >= MEMSIZE) /* see if address is within our memory */ + return SCPE_NXM; /* no, none existant memory error */ + M[addr] = val; /* set the new data value */ + return SCPE_OK; /* all OK */ +} + +/* set the CPU memory size */ +t_stat cpu_set_size(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + t_uint64 mc = 0; + uint32 i; + +//fprintf(stderr, "WE are here 4 \b\n"); + cpu_unit.flags &= ~UNIT_MSIZE; + cpu_unit.flags |= val; /* set new memory size */ + val >>= UNIT_V_MSIZE; /* set size in 32bit words */ + val = (val + 1) * 128 * 1024; /* KW's */ + if ((val < 0) || (val > MAXMEMSIZE)) /* is size valid */ + return SCPE_ARG; /* nope, argument error */ + for (i = val; i < MEMSIZE; i++) /* see if memory contains anything */ + mc |= M[i]; /* or in any bits in memory */ + if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE))) + return SCPE_OK; /* return OK if user says no */ + MEMSIZE = val; /* set new size */ + for (i = MEMSIZE; i < MAXMEMSIZE; i++) + M[i] = 0; /* zero all of the new memory */ + return SCPE_OK; /* we done */ +} + +/* Handle execute history */ + +/* Set history */ +t_stat +cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int32 i, lnt; + t_stat r; + + if (cptr == NULL) { /* check for any user options */ + for (i = 0; i < hst_lnt; i++) /* none, so just zero the history */ + hst[i].psd1 = 0; /* just psd1 for now */ + hst_p = 0; /* start at teh beginning */ + return SCPE_OK; /* all OK */ + } + /* the user has specified options, process them */ + lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r); + if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; /* arg error for bad input or too small a value */ + hst_p = 0; /* start at beginning */ + if (hst_lnt) { /* if a new length was input, resize history buffer */ + free(hst); /* out with the old */ + hst_lnt = 0; /* no length anymore */ + hst = NULL; /* and no pointer either */ + } + if (lnt) { /* see if new size specified, if so get new resized buffer */ + hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt); + if (hst == NULL) + return SCPE_MEM; /* allocation error, so tell user */ + hst_lnt = lnt; /* set new length */ + } + return SCPE_OK; /* we are good to go */ +} + +/* Show history */ +t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc) +{ + int32 k, di, lnt; + char *cptr = (char *) desc; + t_stat r; + struct InstHistory *h; + + if (hst_lnt == 0) /* see if show history is enabled */ + return SCPE_NOFNC; /* no, so are out of here */ + if (cptr) { /* see if user provided a display count */ + lnt = (int32)get_uint(cptr, 10, hst_lnt, &r); /* get the count */ + if ((r != SCPE_OK) || (lnt == 0)) /* if error or 0 count */ + return SCPE_ARG; /* report argument error */ + } else + lnt = hst_lnt; /* dump all the entries */ + di = hst_p - lnt; /* work forward */ + if (di < 0) + di = di + hst_lnt; /* wrap */ + fprintf(st, "PSD1 PSD2 INST DEST SRC CC\n"); + for (k = 0; k < lnt; k++) { /* print specified entries */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + /* display the instruction and results */ + fprintf(st, "%08x %08x %08x %08x %08x %1x", + h->psd1, h->psd2, h->inst, h->dest, h->src, h->cc); + fputc('\n', st); /* end line */ + } /* end for */ + return SCPE_OK; /* all is good */ +} + +/* return description for the specified device */ +const char *cpu_description (DEVICE *dptr) +{ + return "SEL 32 CPU"; /* return description */ +} + +t_stat +cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ + fprintf (st, "The CPU can be set to \n"); + fprintf (st, "The CPU can maintain a history of the most recently executed instructions.\n"); + fprintf (st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n"); + fprintf (st, " sim> SET CPU HISTORY clear history buffer\n"); + fprintf (st, " sim> SET CPU HISTORY=0 disable history\n"); + fprintf (st, " sim> SET CPU HISTORY=n{:file} enable history, length = n\n"); + fprintf (st, " sim> SHOW CPU HISTORY print CPU history\n"); + return SCPE_OK; +} + diff --git a/SEL32/sel32_defs.h b/SEL32/sel32_defs.h index 8122a35..42b2103 100644 --- a/SEL32/sel32_defs.h +++ b/SEL32/sel32_defs.h @@ -1,7 +1,7 @@ -/* sel32_defs.h: Gould Concept/32 (orignal SEL32) simulator definitions +/* sel32_defs.h: SEL 32 Concept/32 simulator definitions - Copyright (c) 2017, Richard Cornwell Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -16,37 +16,37 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "sim_defs.h" /* simulator defns */ +#include "sim_defs.h" /* simh simulator defns */ /* Simulator stop codes */ -#define STOP_IONRDY 1 /* I/O dev not ready */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_UUO 4 /* invalid opcode */ -#define STOP_INVINS 5 /* invalid instr */ -#define STOP_INVIOP 6 /* invalid I/O op */ -#define STOP_INDLIM 7 /* indirect limit */ -#define STOP_XECLIM 8 /* XEC limit */ -#define STOP_IOCHECK 9 /* IOCHECK */ -#define STOP_MMTRP 10 /* mm in trap */ -#define STOP_TRPINS 11 /* trap inst not BRM */ -#define STOP_RTCINS 12 /* rtc inst not MIN/SKR */ -#define STOP_ILLVEC 13 /* zero vector */ -#define STOP_CCT 14 /* runaway CCT */ +#define STOP_IONRDY 1 /* I/O dev not ready */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_UUO 4 /* invalid opcode */ +#define STOP_INVINS 5 /* invalid instr */ +#define STOP_INVIOP 6 /* invalid I/O op */ +#define STOP_INDLIM 7 /* indirect limit */ +#define STOP_XECLIM 8 /* XEC limit */ +#define STOP_IOCHECK 9 /* IOCHECK */ +#define STOP_MMTRP 10 /* mm in trap */ +#define STOP_TRPINS 11 /* trap inst not BRM */ +#define STOP_RTCINS 12 /* rtc inst not MIN/SKR */ +#define STOP_ILLVEC 13 /* zero vector */ +#define STOP_CCT 14 /* runaway CCT */ /* I/O equates */ -/* Channel sense bytes */ -#define SNS_ATTN 0x80 /* Unit attention */ -#define SNS_SMS 0x40 /* Status modifier */ +/* Channel sense bytes set by device */ +#define SNS_BSY 0x80 /* Unit Busy */ +#define SNS_SMS 0x40 /* Status modified */ #define SNS_CTLEND 0x20 /* Control unit end */ -#define SNS_BSY 0x10 /* Unit Busy */ +#define SNS_ATTN 0x10 /* Unit attention */ #define SNS_CHNEND 0x08 /* Channel end */ #define SNS_DEVEND 0x04 /* Device end */ #define SNS_UNITCHK 0x02 /* Unit check */ @@ -64,22 +64,23 @@ #define CMD_READ 0x02 /* Read command */ #define CMD_CTL 0x03 /* Control command */ -#define STATUS_ATTN 0x8000 /* Device raised attention */ -#define STATUS_MOD 0x4000 /* Status modifier */ -#define STATUS_CTLEND 0x2000 /* Control end */ -#define STATUS_BUSY 0x1000 /* Device busy */ -#define STATUS_CEND 0x0800 /* Channel end */ -#define STATUS_DEND 0x0400 /* Device end */ -#define STATUS_CHECK 0x0200 /* Unit check */ -#define STATUS_EXPT 0x0100 /* Unit excpetion */ -#define STATUS_PCI 0x0080 /* Program interupt */ -#define STATUS_LENGTH 0x0040 /* Incorrect lenght */ -#define STATUS_PCHK 0x0020 /* Program check */ -#define STATUS_PROT 0x0010 /* Protection check */ -#define STATUS_CDATA 0x0008 /* Channel data check */ -#define STATUS_CCNTL 0x0004 /* Channel control check */ -#define STATUS_INTER 0x0002 /* Channel interface check */ -#define STATUS_CHAIN 0x0001 /* Channel chain check */ +/* IOCD word 2 status bits */ +#define STATUS_ECHO 0x8000 /* Halt I/O and Stop I/O function */ +#define STATUS_PCI 0x4000 /* Program controlled interrupt */ +#define STATUS_LENGTH 0x2000 /* Incorrect length */ +#define STATUS_PCHK 0x1000 /* Channel program check */ +#define STATUS_CDATA 0x0800 /* Channel data check */ +#define STATUS_CCNTL 0x0400 /* Channel control check */ +#define STATUS_INTER 0x0200 /* Channel interface check */ +#define STATUS_CHAIN 0x0100 /* Channel chain check */ +#define STATUS_BUSY 0x0080 /* Device busy */ +#define STATUS_MOD 0x0040 /* Status modified */ +#define STATUS_CTLEND 0x0020 /* Controller end */ +#define STATUS_ATTN 0x0010 /* Device raised attention */ +#define STATUS_CEND 0x0008 /* Channel end */ +#define STATUS_DEND 0x0004 /* Device end */ +#define STATUS_CHECK 0x0002 /* Unit check */ +#define STATUS_EXPT 0x0001 /* Unit exception */ /* Class F channel bits */ /* bit 32 - 37 of IOCD word 2 (0-5) */ @@ -90,34 +91,45 @@ #define FLAG_PCI 0x0800 /* Program controlled interrupt */ #define FLAG_RTO 0x0400 /* Real-Time Option */ -#if 0 -#define CCMDMSK 0xff000000 /* Mask for command */ -#define CDADRMSK 0x00ffffff /* Mask for data address */ -#define CCNTMSK 0x0000ffff /* Mask for data count */ -#define CHD 0x80000000 /* Chain data */ -#define CHC 0x40000000 /* Chain command */ -#define SLI 0x20000000 /* Suppress length indication */ -#define SKIP 0x10000000 /* Skip flag */ -#define PCI 0x08000000 /* Program controlled interuption */ -#endif - #define BUFF_EMPTY 0x4 /* Buffer is empty */ #define BUFF_DIRTY 0x8 /* Buffer is dirty flag */ #define BUFF_NEWCMD 0x10 /* Channel ready for new command */ #define BUFF_CHNEND 0x20 /* Channel end */ -#define MAX_CHAN 128 /* max channels that can be defined */ -#define SUB_CHANS 256 /* max sub channels that can be defined */ -#define MAX_DEV (MAX_CHAN * SUB_CHANS) /* max possible */ +#define MAX_CHAN 128 /* max channels that can be defined */ +#define SUB_CHANS 256 /* max sub channels that can be defined */ +#define MAX_DEV (MAX_CHAN * SUB_CHANS) /* max possible */ /* simulator devices configuration */ -#define NUM_DEVS_MT 1 /* mag tape units */ -#define NUM_UNITS_MT 8 /* 8 devices */ -#define NUM_DEVS_DISK 2 /* disk drive devices */ -#define NUM_UNITS_DISK 2 /* 2 devices */ +#define NUM_DEVS_IOP 1 /* 1 device IOP channel controller */ +#define NUM_UNITS_IOP 1 /* 1 master IOP channel device */ +#define NUM_DEVS_COM 2 /* 8-Line async controller */ +#define NUM_UNITS_COM 16 /* 8-Line async units */ +#define NUM_DEVS_CON 1 /* 1 I/O console controller */ +#define NUM_UNITS_CON 2 /* 2 console input & output */ +#define NUM_DEVS_MT 1 /* 1 mag tape controllers */ +#define NUM_UNITS_MT 4 /* 4 of 8 devices */ +#define NUM_DEVS_DISK 1 /* 1 DP02 disk drive controller */ +#define NUM_UNITS_DISK 4 /* 4 disk drive devices */ +#define NUM_DEVS_SCFI 2 /* 2 scfi (SCSI) disk drive units */ +#define NUM_UNITS_SCFI 2 /* 2 of 4 disk drive devices */ +#define NUM_DEVS_RTOM 1 /* 1 IOP RTOM channel */ +#define NUM_UNITS_RTOM 1 /* 1 IOP RTOM device (clock & interval timer) */ +#define NUM_DEVS_LPR 1 /* 1 IOP Line printer */ +#define NUM_UNITS_LPR 1 /* 1 IOP Line printer device */ -extern DEVICE cpu_dev; /* cpu device */ -extern UNIT cpu_unit; /* the cpu unit */ +extern DEVICE cpu_dev; /* cpu device */ +extern UNIT cpu_unit; /* the cpu unit */ +#ifdef NUM_DEVS_IOP +extern DEVICE iop_dev; /* IOP channel controller */ +#endif +#ifdef NUM_DEVS_RTOM +extern DEVICE rtc_dev; /* RTOM rtc */ +extern DEVICE itm_dev; /* RTOM itm */ +#endif +#ifdef NUM_DEVS_CON +extern DEVICE con_dev; +#endif #ifdef NUM_DEVS_MT extern DEVICE mta_dev; #endif @@ -130,29 +142,65 @@ extern DEVICE dda_dev; #if NUM_DEVS_DISK > 1 extern DEVICE ddb_dev; #endif - +#ifdef NUM_DEVS_SCFI +extern DEVICE sda_dev; +#endif +#if NUM_DEVS_SCFI > 1 +extern DEVICE sdb_dev; +#endif +#ifdef NUM_DEVS_COM +extern DEVICE coml_dev; +extern DEVICE com_dev; +#endif +#ifdef NUM_DEVS_LPR +extern DEVICE lpr_dev; +#endif /* Memory */ -#define MAXMEMSIZE ((16*1024*1024)/4) /* max memory size */ -#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define MEM_ADDR_OK(x) (((x)) < MEMSIZE) +#define MAXMEMSIZE ((16*1024*1024)/4) /* max memory size */ +#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define MEM_ADDR_OK(x) (((x)) < MEMSIZE) + +/* channel program data for a chan/sub-address */ +typedef struct chp { + /* channel program values */ + uint32 chan_inch_addr; /* Channel status dw in memory */ + uint32 chan_caw; /* Channel command address word */ + uint32 ccw_addr; /* Channel address */ + uint16 ccw_count; /* Channel count */ + uint8 ccw_cmd; /* Channel command and flags */ + uint16 ccw_flags; /* Channel flags */ + uint16 chan_status; /* Channel status */ + uint16 chan_dev; /* Device on channel */ + uint32 chan_buf; /* Channel data buffer */ + uint8 chan_byte; /* Current byte, dirty/full */ +} CHANP; /* Device information block */ +#define FIFO_SIZE 256 /* fifo to hold 128 double words of status */ typedef struct dib { - uint8 mask; /* device mask */ - uint8 numunits; /* number of units */ - /* Start I/O */ - uint8 (*start_io)(UNIT *uptr, uint16 chan); - /* Start a command */ - uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd); - /* Stop I/O */ - uint8 (*halt_io)(UNIT *uptr); - UNIT *units; /* Pointer to units structure */ - void (*dev_ini)(UNIT *, t_bool); /* init function */ - uint8 dev_addr; /* Device address */ - uint8 dev_class; /* Device class */ + /* Pre start I/O operation */ + uint8 (*pre_io)(UNIT *uptr, uint16 chan); + /* Start a channel command SIO */ + uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd); + /* Halt I/O HIO */ + uint8 (*halt_io)(UNIT *uptr); + /* Test I/O TESTIO */ + uint8 (*test_io)(UNIT *uptr); + /* Post I/O processing */ + uint8 (*post_io)(UNIT *uptr); + /* Controller init */ + void (*dev_ini)(UNIT *, t_bool); /* init function */ + UNIT *units; /* Pointer to units structure */ + CHANP *chan_prg; /* Pointer to channel program */ + uint8 numunits; /* number of units */ + uint8 mask; /* device mask */ + uint16 chan_addr; /* parent channel address */ + uint32 chan_fifo_in; /* fifo input index */ + uint32 chan_fifo_out; /* fifo output index */ + uint32 chan_fifo[FIFO_SIZE]; /* interrupt status fifo for each channel */ } DIB; /* DEV 0x7F000000 UNIT 0x00ff0000 */ @@ -186,22 +234,22 @@ typedef struct dib { extern DEBTAB dev_debug[]; /* defines for all programs */ -#define RMASK 0x0000FFFF /* right hw 16 bit mask */ -#define LMASK 0xFFFF0000 /* left hw 16 bit mask */ -#define FMASK 0xFFFFFFFF /* 32 bit mask */ -#define DMASK 0xFFFFFFFFFFFFFFFFLL /* 64 bit all bits mask */ -#define D48LMASK 0xFFFFFFFFFFFF0000LL /* 64 bit left 48 bits mask */ -#define D32LMASK 0xFFFFFFFF00000000LL /* 64 bit left 32 bits mask */ -#define D32RMASK 0x00000000FFFFFFFFLL /* 64 bit right 32 bits mask */ -#define MSIGN 0x80000000 /* 32 bit minus sign */ -#define DMSIGN 0x8000000000000000LL /* 64 bit minus sign */ -#define FSIGN 0x80000000 /* 32 bit minus sign */ +#define RMASK 0x0000FFFF /* right hw 16 bit mask */ +#define LMASK 0xFFFF0000 /* left hw 16 bit mask */ +#define FMASK 0xFFFFFFFF /* 32 bit mask */ +#define DMASK 0xFFFFFFFFFFFFFFFFLL /* 64 bit all bits mask */ +#define D48LMASK 0xFFFFFFFFFFFF0000LL /* 64 bit left 48 bits mask */ +#define D32LMASK 0xFFFFFFFF00000000LL /* 64 bit left 32 bits mask */ +#define D32RMASK 0x00000000FFFFFFFFLL /* 64 bit right 32 bits mask */ +#define MSIGN 0x80000000 /* 32 bit minus sign */ +#define DMSIGN 0x8000000000000000LL /* 64 bit minus sign */ +#define FSIGN 0x80000000 /* 32 bit minus sign */ /* sign extend 16 bit value to uint32 */ -#define SEXT16(x) (x&MSIGN?(uint32)(((uint32)x&RMASK)|LMASK):(uint32)x) +#define SEXT16(x) (x&0x8000?(uint32)(((uint32)x&RMASK)|LMASK):(uint32)x) /* sign extend 16 bit value to uint64 */ -#define DSEXT16(x) (x&MSIGN?(l_uint64)(((l_uint64)x&RMASK)|D48LMASK):(t_uint64)x) +#define DSEXT16(x) (x&0x8000?(l_uint64)(((l_uint64)x&RMASK)|D48LMASK):(t_uint64)x) /* sign extend 32 bit value to uint64 */ -#define DSEXT32(x) (x&MSIGN?(l_uint64)(((l_uint64)x&D32RMASK)|D32LMASK):(t_uint64)x) +#define DSEXT32(x) (x&0x8000?(l_uint64)(((l_uint64)x&D32RMASK)|D32LMASK):(t_uint64)x) #define UNIT_V_MODEL (UNIT_V_UF + 0) #define UNIT_MODEL (7 << UNIT_V_MODEL) @@ -209,7 +257,7 @@ extern DEBTAB dev_debug[]; #define UNIT_V_MSIZE (UNIT_V_MODEL + 3) #define UNIT_MSIZE (0x1F << UNIT_V_MSIZE) #define MEMAMOUNT(x) (x << UNIT_V_MSIZE) -#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_MODEL) & 0x7) /* cpu model 0-7 */ +#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_MODEL) & 0x7) /* cpu model 0-7 */ #define MODEL_55 0 /* 512K Mode Only */ #define MODEL_75 1 /* Extended */ @@ -227,70 +275,75 @@ extern DEBTAB dev_debug[]; #define HIST_PC 0x80000000 /* CC defs Held in CC */ -#define CC1 0x40 /* CC1 in CC */ -#define CC2 0x20 /* CC2 in CC */ -#define CC3 0x10 /* CC3 in CC */ -#define CC4 0x08 /* CC4 in CC */ +#define CC1BIT 0x40000000 /* CC1 in PSD1 */ +#define CC2BIT 0x20000000 /* CC2 in PSD1 */ +#define CC3BIT 0x10000000 /* CC3 in PSD1 */ +#define CC4BIT 0x08000000 /* CC4 in PSD1 */ -#define CC1BIT 0x40000000 /* CC1 in PSD1 */ -#define CC2BIT 0x20000000 /* CC2 in PSD1 */ -#define CC3BIT 0x10000000 /* CC3 in PSD1 */ -#define CC4BIT 0x08000000 /* CC4 in PSD1 */ - -/* PSD mode bits in 'modes' variable */ -#define PRIV 0x80 /* Privileged mode PSD 1 bit 0 */ -#define EXTD 0x04 /* Extended Addressing PSD 1 bit 5 */ -#define BASE 0x02 /* Base Mode PSD 1 bit 6 */ -#define AEXP 0x01 /* Arithmetic exception PSD 1 bit 7 */ - -#define MAP 0x40 /* Map mode, PSD 2 bit 0 */ -#define RET 0x20 /* Retain current maps, PSD 2 bit 15 */ -#define BLKED 0x10 /* Set blocked mode, PSD 2 bit 17 */ -#define BLKRET 0x08 /* Set retain blocked mode, PSD 2 bit 16 */ +#define MAPMODE 0x40 /* Map mode, PSD 2 bit 0 */ +#define RETMODE 0x20 /* Retain current maps, PSD 2 bit 15 */ +#define BLKMODE 0x10 /* Set blocked mode, PSD 2 bit 17 */ +#define RETBLKM 0x08 /* Set retain blocked mode, PSD 2 bit 16 */ /* PSD mode bits in PSD words 1&2 variable */ -#define PRIVBIT 0x80000000 /* Privileged mode PSD 1 bit 0 */ -#define EXTDBIT 0x04000000 /* Extended Addressing PSD 1 bit 5 */ -#define BASEBIT 0x02000000 /* Base Mode PSD 1 bit 6 */ -#define AEXPBIT 0x01000000 /* Arithmetic exception PSD 1 bit 7 */ +#define PRIVBIT 0x80000000 /* Privileged mode PSD 1 bit 0 */ +#define EXTDBIT 0x04000000 /* Extended Addressing PSD 1 bit 5 */ +#define BASEBIT 0x02000000 /* Base Mode PSD 1 bit 6 */ +#define AEXPBIT 0x01000000 /* Arithmetic exception PSD 1 bit 7 */ -#define BLKEDBIT 0x00004000 /* Set blocked mode, PSD 2 bit 17 */ -#define RETBIT 0x00010000 /* Retain current maps, PSD 2 bit 15 */ -#define MAPBIT 0x80000000 /* Map mode, PSD 2 bit 0 */ +#define BLKEDBIT 0x00004000 /* Set blocked mode, PSD 2 bit 17 */ +#define RETBBIT 0x00008000 /* Retain current blocking state, PSD 2 bit 16 */ +#define RETMBIT 0x00010000 /* Retain current maps, PSD 2 bit 15 */ +#define MAPBIT 0x80000000 /* Map mode, PSD 2 bit 0 */ /* Trap Table Address in memory is pointed to by SPAD 0xF0 */ -#define POWERFAIL_TRAP 0x80 /* Power fail trap */ -#define POWERON_TRAP 0x84 /* Power-On trap */ -#define MEMPARITY_TRAP 0x88 /* Memory Parity Error trap */ -#define NONPRESMEM_TRAP 0x8C /* Non Present Memory trap */ -#define UNDEFINSTR_TRAP 0x90 /* Undefined Instruction Trap */ -#define PRIVVIOL_TRAP 0x94 /* Privlege Violation Trap */ -#define SVCCALL_TRAP 0x98 /* Supervisor Call Trap */ -#define MACHINECHK_TRAP 0x9C /* Machine Check Trap */ -#define SYSTEMCHK_TRAP 0xA0 /* System Check Trap */ -#define MAPFAULT_TRAP 0xA4 /* Map Fault Trap */ -#define IPUUNDEFI_TRAP 0xA8 /* IPU Undefined Instruction Trap */ -#define SIGNALIPU_TRAP 0xAC /* Signal IPU/CPU Trap */ -#define ADDRSPEC_TRAP 0xB0 /* Address Specification Trap */ -#define CONSOLEATN_TRAP 0xB4 /* Console Attention Trap */ -#define PRIVHALT_TRAP 0xB8 /* Privlege Mode Halt Trap */ -#define AEXPCEPT_TRAP 0xBC /* Arithmetic Exception Trap */ +#define POWERFAIL_TRAP 0x80 /* Power fail trap */ +#define POWERON_TRAP 0x84 /* Power-On trap */ +#define MEMPARITY_TRAP 0x88 /* Memory Parity Error trap */ +#define NONPRESMEM_TRAP 0x8C /* Non Present Memory trap */ +#define UNDEFINSTR_TRAP 0x90 /* Undefined Instruction Trap */ +#define PRIVVIOL_TRAP 0x94 /* Privlege Violation Trap */ +#define SVCCALL_TRAP 0x98 /* Supervisor Call Trap */ +#define MACHINECHK_TRAP 0x9C /* Machine Check Trap */ +#define SYSTEMCHK_TRAP 0xA0 /* System Check Trap */ +#define MAPFAULT_TRAP 0xA4 /* Map Fault Trap */ +#define IPUUNDEFI_TRAP 0xA8 /* IPU Undefined Instruction Trap */ +#define SIGNALIPU_TRAP 0xAC /* Signal IPU/CPU Trap */ +#define ADDRSPEC_TRAP 0xB0 /* Address Specification Trap */ +#define CONSOLEATN_TRAP 0xB4 /* Console Attention Trap */ +#define PRIVHALT_TRAP 0xB8 /* Privlege Mode Halt Trap */ +#define AEXPCEPT_TRAP 0xBC /* Arithmetic Exception Trap */ /* Errors returned from various functions */ -#define ALLOK 0x0000 /* no error, all is OK */ -#define MAPFLT MAPFAULT_TRAP /* map fault error */ -#define NPMEM NONPRESMEM_TRAP /* non present memory */ -#define MPVIOL PRIVVIOL_TRAP /* memory protection violation */ +#define ALLOK 0x0000 /* no error, all is OK */ +#define MAPFLT MAPFAULT_TRAP /* map fault error */ +#define NPMEM NONPRESMEM_TRAP /* non present memory */ +#define MPVIOL PRIVVIOL_TRAP /* memory protection violation */ /* general instruction decode equates */ -#define IND 0x00100000 /* indirect bit in instruction, bit 11 */ -#define F_BIT 0x00080000 /* byte flag addressing bit 11 in instruction */ -#define C_BITS 0x00000003 /* byte number or hw, dw, dw flags bits 20 & 31 */ -#define BIT0 0x80000000 /* general use for bit 0 testing */ -#define BIT1 0x40000000 /* general use for bit 1 testing */ -#define MASK16 0x0000FFFF /* 16 bit address mask */ -#define MASK19 0x0007FFFF /* 19 bit address mask */ -#define MASK20 0x000FFFFF /* 20 bit address mask */ -#define MASK24 0x00FFFFFF /* 24 bit address mask */ -#define MASK32 0xFFFFFFFF /* 32 bit address mask */ +#define IND 0x00100000 /* indirect bit in instruction, bit 11 */ +#define F_BIT 0x00080000 /* byte flag addressing bit 11 in instruction */ +#define C_BITS 0x00000003 /* byte number or hw, dw, dw flags bits 20 & 31 */ +#define BIT0 0x80000000 /* general use for bit 0 testing */ +#define BIT1 0x40000000 /* general use for bit 1 testing */ +#define MASK16 0x0000FFFF /* 16 bit address mask */ +#define MASK19 0x0007FFFF /* 19 bit address mask */ +#define MASK20 0x000FFFFF /* 20 bit address mask */ +#define MASK24 0x00FFFFFF /* 24 bit address mask */ +#define MASK32 0xFFFFFFFF /* 32 bit address mask */ + +/* SPAD int entry equates, entries accessed by interrupt level number */ +#define SINT_RAML 0x80000000 /* ram loaded (n/u) */ +#define SINT_EWCS 0x40000000 /* Enabled channel WCS executed (XIO) */ +#define SINT_ACT 0x20000000 /* Interrupt active when set (copy is in INTS */ +#define SINT_ENAB 0x10000000 /* Interrupt enabled when set (copy is in INTS */ +#define SINT_EXTL 0x08000000 /* IOP/RTOM ext interrupt if set, I/O if not set (copy in INTS) */ + +/* INTS int entry equates, entries accessed by interrupt level number */ +#define INTS_NU1 0x80000000 /* Not used */ +#define INTS_NU2 0x40000000 /* Not used */ +#define INTS_ACT 0x20000000 /* Interrupt active when set (copy is of SPAD */ +#define INTS_ENAB 0x10000000 /* Interrupt enabled when set (copy is of SPAD */ +#define INTS_EXTL 0x08000000 /* IOP/RTOM ext interrupt if set, I/O if not set (copy of SPAD) */ +#define INTS_REQ 0x04000000 /* Interrupt is requesting */ diff --git a/SEL32/sel32_disk.c b/SEL32/sel32_disk.c new file mode 100644 index 0000000..b1490d0 --- /dev/null +++ b/SEL32/sel32_disk.c @@ -0,0 +1,1165 @@ +/* sel32_disk.c: SEL 32 2311/2314 Disk controller + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "sel32_defs.h" + +extern t_stat set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chsa, uint8 *data); +extern int chan_write_byte(uint16 chsa, uint8 *data); +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 uint32 M[]; /* our memory */ +extern uint32 SPAD[]; /* cpu SPAD memory */ + +#ifdef NUM_DEVS_DISK +#define UNIT_V_TYPE (UNIT_V_UF + 0) +#define UNIT_TYPE (0xf << UNIT_V_TYPE) + +#define GET_TYPE(x) ((UNIT_TYPE & (x)) >> UNIT_V_TYPE) +#define SET_TYPE(x) (UNIT_TYPE & ((x) << UNIT_V_TYPE)) +#define UNIT_DISK UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_FIX + +/* INCH command information */ +/* +WD 0 - Data address +WD 1 - Flags - 0 -36 byte count + +Data - 224 word INCH buffer address +WD 1 Drive 0 Attribute register +WD 2 Drive 1 Attribute register +WD 3 Drive 2 Attribute register +WD 4 Drive 3 Attribute register +WD 5 Drive 4 Attribute register +WD 6 Drive 5 Attribute register +WD 7 Drive 6 Attribute register +WD 8 Drive 7 Attribute register + +Memory attribute register layout +bits 0-7 - Flags + bits 0&1 - 00=Reserved, 01=MHD, 10=FHD, 11=MHD with FHD option + bit 2 - 1=Cartridge module drive + bit 3 - 0=Reserved + bit 4 - 1=Drive not present + bit 5 - 1=Dual Port + bit 6 - 0=Reserved + bit 7 - 0=Reserved +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) +*/ + + +/* 224 word INCH Buffer layout */ +/* 128 word subchannel status storage (SST) */ +/* 66 words of program status queue (PSQ) */ +/* 26 words of scratchpad */ +/* 4 words of label buffer registers */ + +/* u3 */ +/* in u3 is device command code and status */ +#define DSK_CMDMSK 0x00ff /* Command being run */ +#define DSK_STAR 0x0100 /* STAR value in u4 */ +#define DSK_NU2 0x0200 /* */ +#define DSK_READDONE 0x0400 /* Read finished, end channel */ +#define DSK_ENDDSK 0x0800 /* Sensed end of disk */ +#define DSK_SEEKING 0x1000 /* Disk is currently seeking */ +#define DSK_READING 0x2000 /* Disk is reading data */ +#define DSK_WRITING 0x4000 /* Disk is writing data */ +#define DSK_BUSY 0x8000 /* Flag to send a CUE */ +/* commands */ +#define DSK_INCH 0x00 /* Initialize channel */ +#define DSK_WD 0x01 /* Write data */ +#define DSK_RD 0x02 /* Read data */ +#define DSK_NOP 0x03 /* No operation */ +#define DSK_SNS 0x04 /* Sense */ +#define DSK_SCK 0x07 /* Seek cylinder, track, sector */ +#define DSK_TIC 0x08 /* Transfer in channel */ +#define DSK_FNSK 0x0B /* Format for no skip */ +#define DSK_LPL 0x13 /* Lock protected label */ +#define DSK_LMR 0x1F /* Load mode register */ +#define DSK_RES 0x23 /* Reserve */ +#define DSK_WSL 0x31 /* Write sector label */ +#define DSK_RSL 0x32 /* Read sector label */ +#define DSK_REL 0x33 /* Release */ +#define DSK_XEZ 0x37 /* Rezero */ +#define DSK_POR 0x43 /* Priority Override */ +#define DSK_IHA 0x47 /* Increment head address */ +#define DSK_SRM 0x4F /* Set reserve track mode */ +#define DSK_WTL 0x51 /* Write track label */ +#define DSK_RTL 0x52 /* Read track label */ +#define DSK_XRM 0x5F /* Reset reserve track mode */ +#define DSK_RAP 0xA2 /* Read angular positions */ +#define DSK_TESS 0xAB /* Test STAR (subchannel target address register) */ +#define DSK_ICH 0xFF /* Initialize Controller */ + +/* u4 - sector target address register (STAR) */ +/* Holds the current cylinder, head(track), sector */ +#define DISK_CYL 0xFFFF0000 /* cylinder mask */ +#define DISK_TRACK 0x0000FF00 /* track mask */ +#define DISK_SECTOR 0x000000ff /* sector mask */ + +/* u5 */ +/* Sense byte 0 - mode register */ +#define SNS_DROFF 0x80000000 /* Drive Carriage will be offset */ +#define SNS_TRKOFF 0x40000000 /* Track offset: 0=positive, 1=negative */ +#define SNS_RDTMOFF 0x20000000 /* Read timing offset = 1 */ +#define SNS_RDSTRBT 0x10000000 /* Read strobe timing: 1=positive, 0=negative */ +#define SNS_DIAGMOD 0x08000000 /* Diagnostic Mode ECC Code generation and checking */ +#define SNS_RSVTRK 0x04000000 /* Reserve Track mode: 1=OK to write, 0=read only */ +#define SNS_FHDOPT 0x02000000 /* FHD or FHD option = 1 */ +#define SNS_RESERV 0x01000000 /* Reserved */ + +/* Sense byte 1 */ +#define SNS_CMDREJ 0x800000 /* Command reject */ +#define SNS_INTVENT 0x400000 /* Unit intervention required */ +#define SNS_SPARE1 0x200000 /* Spare */ +#define SNS_EQUCHK 0x100000 /* Equipment check */ +#define SNS_DATCHK 0x080000 /* Data Check */ +#define SNS_OVRRUN 0x040000 /* Data overrun/underrun */ +#define SNS_DSKFERR 0x020000 /* Disk format error */ +#define SNS_DEFTRK 0x010000 /* Defective track encountered */ + +/* Sense byte 2 */ +#define SNS_LAST 0x8000 /* Last track flag encountered */ +#define SNS_AATT 0x4000 /* At Alternate track */ +#define SNS_WPER 0x2000 /* Write protection error */ +#define SNS_WRL 0x1000 /* Write lock error */ +#define SNS_MOCK 0x0800 /* Mode check */ +#define SNS_INAD 0x0400 /* Invalid memory address */ +#define SNS_RELF 0x0200 /* Release fault */ +#define SNS_CHER 0x0100 /* Chaining error */ + +/* Sense byte 3 */ +#define SNS_REVL 0x80 /* Revolution lost */ +#define SNS_DADE 0x40 /* Disc addressing or seek error */ +#define SNS_BUCK 0x20 /* Buffer check */ +#define SNS_ECCS 0x10 /* ECC error in sector label */ +#define SNS_ECCD 0x08 /* ECC error iin data */ +#define SNS_ECCT 0x04 /* ECC error in track label */ +#define SNS_RTAE 0x02 /* Reserve track access error */ +#define SNS_UESS 0x01 /* Uncorrectable ECC error */ + +/* u6 */ +/* u6 holds drive attribute entry */ +/* provided by inch command for controller */ +/* +bits 0-7 - Flags + bits 0&1 - 00=Reserved, 01=MHD, 10=FHD, 11=MHD with FHD option + bit 2 - 1=Cartridge module drive + bit 3 - 0=Reserved + bit 4 - 1=Drive not present + bit 5 - 1=Dual Port + bit 6 - 0=Reserved + bit 7 - 0=Reserved +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) +*/ + +/* Pointer held in up7 */ +/* sects/cylinder = sects/track * numhds */ +/* allocated during attach command for each unit defined */ +struct ddata_t +{ + uint8 rbuf[1024]; /* read buffer, Sector buffer 768 or 1024 */ + uint8 wbuf[1024]; /* write buffer, Sector buffer 768 or 1024 */ + uint32 cpos; /* Position of head of cylinder in file */ + uint32 tstart; /* Location of start of cyl/track/sect in data */ + uint32 spare; /* drive register spare */ + uint16 tsize; /* Size of one track in byte */ + uint16 ssize; /* Size of one sector in bytes */ + uint16 ccyl; /* Current Cylinder number */ + uint16 cyl; /* Cylinder head at */ + uint16 tpos; /* Track position */ + uint16 spos; /* Sector position */ + uint16 dlen; /* remaining in data */ + uint16 rec; /* Current record number */ + uint16 count; /* Remaining in current operation */ +}; + +/* disk definition structure */ +struct disk_t +{ + char *name; /* Device ID Name */ + uint32 taus; /* total allocation units */ + uint16 bms; /* bit map size */ + uint16 nhds; /* Number of heads */ + uint16 ssiz; /* sector size in words */ + uint16 spt; /* # sectors per track(cylinder) */ + uint8 spau; /* # sectors per allocation unit */ + uint8 spb; /* # sectors per block (192 WDS)*/ + uint32 cyl; /* Number of cylinders */ + uint8 type; /* Device type code */ +} +disk_type[] = +{ + /* Class E Disc Devices */ + {"FE004", 5888, 184, 256, 192, 23, 1, 1, 1, 0x80}, /* 4 M */ + {"CE010", 12800, 200, 2, 96, 16, 1, 2, 400, 0x60}, /* 10 M */ + {"ME040", 23000, 719, 5, 192, 23, 2, 1, 400, 0x40}, /* 40 M */ + {"ME080", 46000, 1438, 5, 192, 23, 2, 1, 800, 0x40}, /* 80 M */ + {"ME300", 87400, 2732, 19, 192, 23, 4, 1, 800, 0x40}, /* 300 M */ + {"FE005", 5888, 184, 4, 192, 23, 1, 1, 64, 0x80}, /* 5 M */ + + /* Class F Disc Devices */ + {"FL001", 1334, 0, 2, 64, 26, 3, 3, 26, 0x40}, /* 1 M */ + {"MH040", 20000, 625, 5, 192, 20, 2, 1, 40, 0x40}, /* 40 M */ + {"MH080", 40000, 1250, 5, 192, 20, 2, 1, 80, 0x40}, /* 80 M */ + {"MH300", 76000, 2375, 19, 192, 20, 4, 1, 800, 0x40}, /* 300 M */ + {"FH005", 5120, 184, 4, 192, 20, 1, 1, 64, 0x80}, /* 5 M */ + {"CD032", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /* 32 M */ + {"CD032", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /* 32 M */ + {"CD064", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /* 64 M */ + {"CD064", 24000, 750, 3, 192, 20, 2, 1, 800, 0x60}, /* 64 M */ + {"CD096", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /* 96 M */ + {"CD096", 40000, 1250, 5, 192, 20, 2, 1, 800, 0x60}, /* 96 M */ + {"MH600", 80000, 2500, 40, 192, 20, 8, 1, 80, 0x40}, /* 600 M */ + {"FM600", 80000, 2500, 40, 192, 20, 8, 1, 80, 0x40}, /* 600 M */ + {"FM600", 1600, 50, 40, 192, 20, 1, 1, 2, 0x80}, /* 600 M */ + {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 'E' DISC DEVICES + DID C'DE01', 1, 1, 23, 192, 256, 184, 5888, C'FE004' + DID C'DE02', 2, 1, 16, 96, 2, 200, 12800, C'CE010' + DID C'DE04', 1, 2, 23, 192, 5, 719, 23000, C'ME040' + DID C'DE05', 1, 2, 23, 192, 5, 1438, 46000, C'ME080' + DID C'DE06', 1, 4, 23, 192, 19, 2732, 87400, C'ME300' + DID C'DE07', 1, 1, 23, 192, 4, 184, 5888, C'FE005' +* 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'DF05', 1, 1, 20, 192, 4, 184, 5120, C'FH005' + DID C'DF06', 1, 2, 20, 192, 1, 250, 8000, C'CD032' + DID C'DF06', 1, 2, 20, 192, 1, 250, 8000, C'CD032' + DID C'DF07', 1, 2, 20, 192, 1, 250, 8000, C'CD064' + 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'DF0A', 1, 1, 20, 192, 40, 50, 1600, C'FM600' +* +#endif + +uint8 disk_preio(UNIT *uptr, uint16 chan) ; +uint8 disk_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) ; +uint8 disk_haltio(uint16 addr); +t_stat disk_srv(UNIT *); +t_stat disk_boot(int32, DEVICE *); +void disk_ini(UNIT *, t_bool); +t_stat disk_reset(DEVICE *); +t_stat disk_attach(UNIT *, CONST char *); +t_stat disk_detach(UNIT *); +t_stat disk_set_type(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat disk_get_type(FILE * st, UNIT * uptr, int32 v, CONST void *desc); +t_stat disk_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *disk_description (DEVICE *dptr); + +/* channel program information */ +CHANP dda_chp[NUM_UNITS_DISK] = {0}; + +MTAB disk_mod[] = { + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "TYPE", "TYPE", + &disk_set_type, &disk_get_type, NULL, "Type of disk"}, + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, + &show_dev_addr, NULL}, + {0} +}; + +UNIT dda_unit[] = { +/* SET_TYPE(9) DM300 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x800)}, /* 0 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x801)}, /* 1 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x802)}, /* 2 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x803)}, /* 3 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x804)}, /* 4 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x805)}, /* 5 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x806)}, /* 6 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0x807)}, /* 7 */ +}; + +//DIB dda_dib = {NULL, disk_startcmd, NULL, NULL, disk_ini, dda_unit, dda_chp, NUM_UNITS_DISK, 0x0f, 0x0800, 0, 0, 0}; + +DIB dda_dib = { + disk_preio, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre start I/O */ + disk_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + disk_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + dda_unit, /* UNIT* units */ /* Pointer to units structure */ + dda_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_DISK, /* uint8 numunits */ /* number of units defined */ + 0x0f, /* uint8 mask */ /* 16 devices - device mask */ + 0x0800, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE dda_dev = { + "DMA", dda_unit, NULL, disk_mod, + NUM_UNITS_DISK, 16, 24, 4, 16, 32, + NULL, NULL, &disk_reset, &disk_boot, &disk_attach, &disk_detach, +// &dda_dib, DEV_BUF_NUM(0)|DEV_DISABLE|DEV_DEBUG, 0, dev_debug, + &dda_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug, + NULL, NULL, &disk_help, NULL, NULL, &disk_description +}; + +#if NUM_DEVS_DISK > 1 +/* channel program information */ +CHANP ddb_chp[NUM_UNITS_DISK] = {0}; + +UNIT ddb_unit[] = { +/* SET_TYPE(9) DM300 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC00)}, /* 0 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC01)}, /* 1 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC02)}, /* 2 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC03)}, /* 3 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC04)}, /* 4 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC05)}, /* 5 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC06)}, /* 6 */ + {UDATA(&disk_srv, UNIT_DISK|SET_TYPE(9), 0), 0, UNIT_ADDR(0xC07)}, /* 7 */ +}; + +//DIB ddb_dib = {disk_startcmd, NULL, NULL, NULL, disk_ini, ddb_unit, ddb_chp, NUM_UNITS_DISK, 0x0f, 0x0C00, 0, 0, 0}; + +DIB ddb_dib = { + disk_preio, /* uint8 (*start_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + disk_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command SIO */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O HIO */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O TIO */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + disk_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + ddb_unit, /* UNIT* units */ /* Pointer to units structure */ + ddb_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_DISK, /* uint8 numunits */ /* number of units defined */ + 0x0f, /* uint8 mask */ /* 16 devices - device mask */ + 0x0C00, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE ddb_dev = { + "DMB", ddb_unit, NULL, disk_mod, + NUM_UNITS_DISK, 16, 24, 4, 16, 32, + NULL, NULL, &disk_reset, &disk_boot, &disk_attach, &disk_detach, +// &ddb_dib, DEV_BUF_NUM(1)|DEV_DISABLE|DEV_DEBUG, 0, dev_debug, + &ddb_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug, + NULL, NULL, &disk_help, NULL, NULL, &disk_description +}; +#endif + +/* start a disk operation */ +uint8 disk_preio(UNIT *uptr, uint16 chan) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + + if ((uptr->u3 & 0xff00) != 0) { /* just return if busy */ + return SNS_BSY; + } + + sim_debug(DEBUG_CMD, dptr, "dsk_preio unit=%d\n", unit); + return 0; /* good to go */ +} + +uint8 disk_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) +{ + uint16 addr = GET_UADDR(uptr->u3); + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + uint8 ch; + + sim_debug(DEBUG_CMD, dptr, "disk_startcmd unit %d cmd %x u3 %x\n", unit, cmd, uptr->u3); + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + uptr->u5 |= SNS_INTVENT; /* unit intervention required */ + if (cmd != DSK_SNS) /* we are completed with unit check status */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + } + + if ((uptr->u3 & DSK_CMDMSK) != 0) { + uptr->u3 |= DSK_BUSY; /* Flag we we are busy */ + return SNS_BSY; + } + if ((uptr->u3 & 0xff00) != 0) { /* if any status info, we are busy */ + return SNS_BSY; + } + sim_debug(DEBUG_CMD, dptr, "disk_startcmd CMD 2 unit=%d %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 */ +dosns: + sim_debug(DEBUG_CMD, dptr, "disk_startcmd CMD sense\n"); + /* bytes 0,1 - Cyl entry from STAR reg in u4 */ + ch = (uptr->u4 >> 24) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense STAR b0 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + ch = (uptr->u4 >> 16) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense STAR b1 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* byte 2 - Track entry from STAR reg in u4 */ + ch = (uptr->u4 >> 8) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense STAR b2 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* byte 3 - Sector entry from STAR reg in u4 */ + ch = (uptr->u4) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense STAR b3 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* bytes 4 - mode reg, byte 0 of u5 */ + ch = (uptr->u5 >> 24) & 0xff; /* return the sense data for device */ + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* bytes 5-7 - status bytes, bytes 1-3 of u5 */ + ch = (uptr->u5 >> 16) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense unit=%d 2 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + ch = (uptr->u5 >> 8) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense unit=%d 3 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + ch = (uptr->u5) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd sense unit=%d 4 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* bytes 8-11 - drive attribute register (DATR) entries from uptr->u6 via INCH cmd */ + ch = (uptr->u6 >> 24) & 0xff; + chan_write_byte(addr, &ch) ; + ch = (uptr->u6 >> 16) & 0xff; + chan_write_byte(addr, &ch) ; + ch = (uptr->u6 >> 8 ) & 0xff; + chan_write_byte(addr, &ch) ; + ch = (uptr->u6 >> 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->u5 &= 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->u5 |= (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 */ + int i; + UNIT *up = dptr->units; /* first unit for this device */ + sim_debug(DEBUG_CMD, dptr, "disk_startcmd starting inch cmd addr %x u4 %x\n", addr, uptr->u4); + /* 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 u4 and us9 left non-zero */ + /* just return OK and channel software will use up8 as status buffer */ + mema = (uint32)uptr->u4; /* get memory address of buffer */ + uptr->u4 = M[mema>>2]; /* get status buffer address for XIO return status */ + sim_debug(DEBUG_CMD, dptr, "disk_startcmd starting inch cmd addr %x u4 %x mema %x units %d\n", + addr, uptr->u4, 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; inumunits && i<8; i++) { /* process all drives */ + up->u6 = M[(mema>>2)+i+1]; /* save each unit's drive data */ + up++; /* next unit for this device */ + } + sim_debug(DEBUG_CMD, dptr, "disk_startcmd done inch cmd addr %x\n", addr); + return SNS_CHNEND|SNS_DEVEND; + break; + } + + case DSK_SCK: /* Seek command 0x07 */ + case DSK_XEZ: /* Rezero & Read IPL record 0x1f */ + uptr->u3 &= ~(DSK_STAR); /* show we do not have seek STAR in u4 */ + case DSK_WD: /* Write command 0x01 */ + case DSK_RD: /* Read command 0x02 */ + case DSK_LMR: /* read mode register */ + + uptr->u3 |= cmd; /* save cmd */ + sim_debug(DEBUG_CMD, dptr, "disk_startcmd done with disk seek r/w cmd %x addr %x\n", cmd, addr); + sim_activate(uptr, 20); /* start things off */ + return 0; + + case DSK_NOP: /* NOP 0x03 */ + return SNS_CHNEND|SNS_DEVEND; /* return OK */ + + case DSK_SNS: /* Sense 0x04 */ + goto dosns; /* use code above */ + break; + } + sim_debug(DEBUG_CMD, dptr, "disk_startcmd done with disk_startcmd %x addr %x u5 %x\n", cmd, addr, uptr->u5); + if (uptr->u5 & 0xff) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + sim_activate(uptr, 20); /* start things off */ + return SNS_CHNEND|SNS_DEVEND; +} + +/* Handle processing of disk requests. */ +t_stat disk_srv(UNIT * uptr) +{ + uint16 chsa = GET_UADDR(uptr->u3); + DEVICE *dptr = find_dev_from_unit(uptr); + DIB *dibp = (DIB *)dptr->ctxt; /* get pointer to Dev Info Blk for this device */ + CHANP *chp = (CHANP *)dibp->chan_prg; /* get pointer to channel program */ + struct ddata_t *data = (struct ddata_t *)(uptr->up7); + int cmd = uptr->u3 & DSK_CMDMSK; + int type = GET_TYPE(uptr->flags); + int count = data->count; + int trk, cyl; + int unit = (uptr - dptr->units); + int i; + uint8 ch; + uint8 buf2[768]; + uint8 buf[768]; + + sim_debug(DEBUG_DETAIL, &dda_dev, "disk_srv entry unit %d cmd %x chsa %x chan %x count %x\n", + unit, cmd, chsa, chsa>>8, chp->ccw_count); + + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + return SCPE_OK; + } + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + uptr->u5 |= SNS_INTVENT; /* unit intervention required */ + if (cmd != DSK_SNS) /* we are completed with unit check status */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + } + + sim_debug(DEBUG_CMD, dptr, "disk_srv cmd=%x chsa %04x count %x\n", cmd, chsa, chp->ccw_count); + switch (cmd) { + case 0: /* No command, stop disk */ + break; + + case DSK_SNS: /* 0x4 */ + ch = uptr->u5 & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv sense unit=%d 1 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = (uptr->u5 >> 8) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv sense unit=%d 2 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = 0; + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv sense unit=%d 3 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = unit; + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv sense unit=%d 4 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = 4; + uptr->u3 &= ~(0xff00); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + break; + + case DSK_SCK: /* Seek cylinder, track, sector 0x07 */ + + /* If we are waiting on seek to finish, check if there yet. */ + if (uptr->u3 & DSK_SEEKING) { + /* see if on cylinder yet */ + if ((uptr->u4 >> 16) == data->cyl) { + /* we are on cylinder, seek is done */ + sim_debug(DEBUG_CMD, dptr, "dsk_srv seek on cylinder unit=%d %d %d\n", + unit, uptr->u4 >> 16, data->cyl); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + set_devattn(chsa, SNS_DEVEND); /* start the operation */ + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv seek end unit=%d %x %x\n", + unit, uptr->u4 >> 16, data->cyl); + sim_activate(uptr, 20); + break; + } else { + /* Compute delay based of difference. */ + /* Set next state = index */ + i = (uptr->u4 >> 16) - data->cyl; + sim_debug(DEBUG_CMD, dptr, "dsk_srv seek unit=%d %x %x\n", unit, uptr->u4 >> 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 >= disk_type[type].cyl) /* test for over max */ + data->cyl = disk_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 (data->cyl < 0) /* test for less than zero */ + data->cyl = 0; /* make zero */ + } + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv seek next unit=%d %d %d\n", unit, uptr->u4 >> 16, + data->cyl); + sim_activate(uptr, 2); + break; + } + } + + /* not seeking, so start a new seek */ + /* Read in 4 character seek code */ + for (i = 0; i < 4; i++) { + if (chan_read_byte(chsa, &buf[i])) { + /* we have error, bail out */ + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + } +rezero: + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv seek unit=%d star %02d%02d %02d %02d\n", + unit, buf[0], buf[1], buf[2], buf[3]); + /* save STAR (target sector) data in u4 */ + uptr->u4 = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); + cyl = uptr->u4 >> 16; /* get the cylinder */ + trk = buf[2]; /* get the track */ + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv SEEK cyl %d trk %d sec %d unit=%d\n", cyl&0xffff, trk, buf[3], unit); + + /* FIXME do something with FHD here */ + /* Check if seek valid */ + if (cyl > disk_type[type].cyl || trk >= disk_type[type].nhds || buf[3] > disk_type[type].spt) { + sim_debug(DEBUG_CMD, dptr, "dsk_srv seek ERROR cyl %x trk %x sec %x unit=%d\n", cyl, trk, buf[3], unit); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; /* set error status */ + + /* we have an error, tell user */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* end command */ + break; + } + + uptr->u3 |= DSK_STAR; /* show we have seek STAR in u4 */ + /* calc the sector address of data */ + /* calculate file position in bytes of requested sector */ + data->tstart = (cyl * disk_type[type].nhds * data->tsize) + + (trk * data->tsize) + (buf[3] * 0x300); + data->tpos = trk; /* save the track/head number */ + data->spos = buf[3]; /* save the sector number */ + data->count = 0; /* no data seen yet */ + data->rec = 0; /* number of bytes in this sector */ + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv seek start %x trk %x sec %x\n", data->tstart, trk, buf[3]); + if ((sim_fseek(uptr->fileref, data->tstart, SEEK_SET)) != 0) { /* seek home */ + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv Error on seek to %x\n", data->tstart); + } + + /* Check if already on correct cylinder */ + if (trk != data->cyl) { + /* Do seek */ + uptr->u3 |= DSK_SEEKING; /* show we are seeking */ + sim_debug(DEBUG_DETAIL, dptr, "dsk_srv seek unit=%d trk %x cyl %x\n", unit, trk, data->cyl); + sim_activate(uptr, 20); + chan_end(chsa, SNS_CHNEND); + } else { + sim_debug(DEBUG_DETAIL, dptr, + "dsk_srv calc sect addr seek start %x trk %x sec %x\n", data->tstart, trk, buf[3]); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + sim_activate(uptr, 20); + chan_end(chsa, SNS_DEVEND|SNS_CHNEND); + } + return SCPE_OK; + + case DSK_XEZ: /* Rezero & Read IPL record */ + + sim_debug(DEBUG_CMD, dptr, "RD REZERO IPL unit=%d seek 0\n", unit); + /* Do a seek to 0 */ + uptr->u4 = 0; /* set STAR to 0, 0, 0 */ + uptr->u3 &= ~(0xffff); /* remove old cmd */ + uptr->u3 |= DSK_SCK; /* show as seek command */ + data->tstart = 0; /* byte offset is 0 */ + data->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 */ + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + /* zero stuff */ + buf[0] = buf[1] = buf[2] = buf[3] = 0; + goto rezero; /* murge with seek code */ + break; + + case DSK_LMR: + sim_debug(DEBUG_CMD, dptr, "Load Mode Reg unit=%d\n", unit); + /* Read in 1 character of mode data */ + if (chan_read_byte(chsa, &buf[0])) { + /* we have error, bail out */ + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + uptr->u3 &= ~(0xffff); /* remove old cmd */ + uptr->u5 &= 0x00ffffff; /* clear old mode data */ + uptr->u5 |= (buf[0] << 24); /* save mode value */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + break; + + case DSK_RD: /* Read Data */ + /* data->tstart has start of sector address in bytes */ + if ((uptr->u3 & DSK_READING) == 0) { /* see if we are reading data */ + uptr->u3 |= DSK_READING; /* read from disk starting */ + data->dlen = 0; /* no data read yet */ + sim_debug(DEBUG_CMD, dptr, + "DISK READ starting unit=%d u3 %x count %d rec %d\n", unit, uptr->u3, count, data->rec); + } + + if (uptr->u3 & DSK_READING) { /* see if we are reading data */ + /* read in a sector of data from disk */ + if ((count=sim_fread(buf, 1, data->ssize, uptr->fileref)) != data->ssize) { + sim_debug(DEBUG_CMD, dptr, "Error %d on read %d of diskfile cyl %d hds %d sec %d\n", + count, data->ssize, data->cyl, data->tpos, data->spos); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ +// sim_activate(uptr, 20); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + + sim_debug(DEBUG_CMD, dptr, "disk_srv after READ chsa %04x count %x\n", chsa, chp->ccw_count); + /* process the next sector of data */ + data->rec = count; /* no bytes in sector yet */ + count = 0; /* used here as a flag for short write */ + for (i=0; i<(data->rec); i++) { + ch = buf[i]; /* get a char from buffer */ + if (chan_write_byte(chsa, &ch)) { /* put a byte to memory */ + sim_debug(DEBUG_DATAIO, dptr, + "DISK Read %d bytes from dskfile cyl %d hds %d sec %d tstart %x\r\n", + data->dlen+i, data->cyl, data->tpos, data->spos, data->tstart); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + goto rddone; } + } + data->dlen += data->rec; /* add byte read to total count */ + + sim_debug(DEBUG_CMD, dptr, + "DISK READ from sec end %d bytes end %d from diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->ssize, data->cyl, data->tpos, data->spos, data->tstart); + data->spos++; + /* set sector to read next one */ + if (data->spos >= (disk_type[type].spt)) { + data->spos = 0; /* number of sectors per track */ + data->tpos++; /* track position */ + if (data->tpos >= (disk_type[type].nhds)) { + data->tpos = 0; /* number of tracks per cylinder */ + data->cyl++; /* cylinder position */ + if (data->cyl >= (disk_type[type].cyl)) { + /* EOM reached, abort */ +// sim_debug(DEBUG_CMD, dptr, "Error %d on read %d from diskfile cyl %d hds %d sec %d\n", +// i, data->ssize, data->cyl, data->tpos, data->spos); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ +// sim_activate(uptr, 20); + 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_DATAIO, dptr, + "DISK Read complete Read %d bytes from diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->cyl, data->tpos, data->spos, data->tstart); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + } +rddone: +// sim_activate(uptr, 20); + sim_activate(uptr, 10); /* wait to read next sector */ + break; + } + break; + + case DSK_WD: /* Write Data */ + /* data->tstart has start of sector address in bytes */ + if ((uptr->u3 & DSK_WRITING) == 0) { /* see if we are writing data */ + uptr->u3 |= DSK_WRITING; /* write to disk starting */ + data->dlen = 0; /* no data written yet */ + sim_debug(DEBUG_CMD, dptr, "DISK WRITE starting unit=%d u3 %x bytes %d rec %d\n", + unit, uptr->u3, data->dlen, data->rec); + } + if (uptr->u3 & DSK_WRITING) { /* see if we are writing data */ + /* process the next sector of data */ + data->rec = 0; /* no bytes in sector yet */ + count = 0; /* used here as a flag for short read */ + for (i=0; i<(data->ssize); i++) { + if (chan_read_byte(chsa, &ch)) { /* get a byte from memory */ + /* if error on reading 1st byte, we are done writing */ + if (i == 0) { + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + sim_debug(DEBUG_CMD, dptr, + "DISK Wrote %d bytes to diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->cyl, data->tpos, data->spos, data->tstart); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + goto wrdone; + } + ch = 0; /* finish out the sector with zero */ + count++; /* show we have no more data to write */ + } + buf2[i] = ch; /* save the char */ + } + data->dlen += data->ssize; /* add 1 sector of bytes */ + /* write the sector to disk */ + if ((i=sim_fwrite(buf2, 1, data->ssize, uptr->fileref)) != data->ssize) { + sim_debug(DEBUG_CMD, dptr, "Error %d on write %d to diskfile cyl %d hds %d sec %d\n", + i, data->ssize, data->cyl, data->tpos, data->spos); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + if (count != 0) { /* see if done with write command */ + sim_debug(DEBUG_DATAIO, dptr, + "DISK WroteB %d bytes to diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->cyl, data->tpos, data->spos, data->tstart); + uptr->u3 &= ~(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 %d bytes end %d to diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->ssize, data->cyl, data->tpos, data->spos, data->tstart); + data->spos++; + if (data->spos >= (disk_type[type].spt)) { + data->spos = 0; /* number of sectors per track */ + data->tpos++; /* track position */ + if (data->tpos >= (disk_type[type].nhds)) { + data->tpos = 0; /* number of tracks per cylinder */ + data->cyl++; /* cylinder position */ + if (data->cyl >= (disk_type[type].cyl)) { + /* EOM reached, abort */ + sim_debug(DEBUG_DETAIL, dptr, "Error %d on write %d to diskfile cyl %d hds %d sec %d\n", + i, data->ssize, data->cyl, data->tpos, data->spos); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + } + } +wrdone: +// sim_activate(uptr, 20); + sim_activate(uptr, 10); + break; + } + break; + + default: + sim_debug(DEBUG_DETAIL, dptr, "invalid command=%d %x\n", unit, cmd); + uptr->u5 |= SNS_CMDREJ; + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + sim_debug(DEBUG_DETAIL, dptr, "disk_srv done cmd=%x chsa %04x count %x\n", cmd, chsa, chp->ccw_count); + return SCPE_OK; +} + +/* initialize the disk */ +void disk_ini(UNIT *uptr, t_bool f) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + int i = GET_TYPE(uptr->flags); + + uptr->u3 &= ~0xffff; /* clear out the flags but leave ch/sa */ + /* capacity is tracks per allocation unit time sectors per allocation unit */ + uptr->capac = disk_type[i].taus * disk_type[i].spau; + + sim_debug(DEBUG_EXP, &dda_dev, "DMA init device %s on unit DMA%.1x cap %x\n", + dptr->name, GET_UADDR(uptr->u3), uptr->capac); +} + +t_stat disk_reset(DEVICE * dptr) +{ + return SCPE_OK; +} + +/* create the disk file for the specified device */ +int disk_format(UNIT *uptr) { + struct ddata_t *data = (struct ddata_t *)uptr->up7; + uint16 addr = GET_UADDR(uptr->u3); + int type = GET_TYPE(uptr->flags); + DEVICE *dptr = find_dev_from_unit(uptr); + uint16 tsize = data->tsize; /* get track size in bytes */ + uint16 cyl; + uint16 hds; + uint16 spc = disk_type[type].nhds * disk_type[type].spt; /* sectors/cyl */ + uint8 *buff; + + /* see if user wants to initialize the disk */ + if (!get_yn("Initialize disk? [Y] ", TRUE)) { + return 1; + } + + /* seek to sector 0 */ + if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */ + fprintf(stderr, "Error on seek to 0\r\n"); + } + + /* get buffer for track data */ + if ((buff = (uint8 *)calloc(tsize, sizeof(uint8))) == 0) { + detach_unit(uptr); + return SCPE_ARG; + } + sim_debug(DEBUG_CMD, dptr, "Creating disk file of capacity %d\n", + data->tsize * disk_type[type].cyl * disk_type[type].nhds); + /* write zeros to each track of the disk */ + for (cyl = 0; cyl < disk_type[type].cyl; cyl++) { + for (hds=0; hds < disk_type[type].nhds; hds++) { + if ((sim_fwrite(buff, 1, data->tsize, uptr->fileref)) != data->tsize) { + sim_debug(DEBUG_CMD, dptr, "Error on write to diskfile cyl %d hds %d\n", cyl, hds); + } + } + if ((cyl % 20) == 0) + fputc('.', stderr); + } + /* seek home again */ + sim_fseek(uptr->fileref, 0, SEEK_SET); /* seek home */ + free(buff); /* free cylinder buffer */ + data->cpos = 0; + data->ccyl = 0; + set_devattn(addr, SNS_DEVEND); /* start us up */ +// sim_activate(uptr, 100); + return 0; +} + +/* attach the selected file to the disk */ +t_stat disk_attach(UNIT *uptr, CONST char *file) +{ + uint16 addr = GET_UADDR(uptr->u3); + int type = GET_TYPE(uptr->flags); + DEVICE *dptr = find_dev_from_unit(uptr); + t_stat r; + uint16 tsize; /* track size in bytes */ + uint16 ssize; /* sector size in bytes */ + struct ddata_t *data; + uint8 buff[1024]; +// int i; + + /* have simulator attach the file to the unit */ + if ((r = attach_unit(uptr, file)) != SCPE_OK) + return r; + + if (disk_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 disk_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; + } + + uptr->up7 = (void *)data; /* save pointer to structure in up7 */ + /* track size in bytes is sectors/track times words/sector time 4 bytse/word */ + tsize = disk_type[type].spt * disk_type[type].ssiz * 4; /* get track size in bytes */ + data->tsize = tsize; /* save size of track in bytes */ + uptr->capac = disk_type[type].taus * disk_type[type].spau; /* disk capacity in sectors */ + ssize = disk_type[type].ssiz * 4; /* disk sector size in bytes */ + uptr->capac *= ssize; /* disk capacity in bytes */ + data->ssize = ssize; /* save sector size bytes */ + + sim_debug(DEBUG_CMD, dptr, "Disk taus %d spau %d ssiz %d cap %d\n", + disk_type[type].taus, disk_type[type].spau, disk_type[type].ssiz * 4, uptr->capac); /* disk capacity */ + + if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */ + detach_unit(uptr); /* if no space, error */ + return SCPE_FMT; /* error */ + } + + /* read in the 1st sector of the 'disk' */ + if ((r = sim_fread(&buff[0], sizeof(uint8), ssize, uptr->fileref) != ssize)) { + sim_debug(DEBUG_CMD, &dda_dev, "Disk format fread ret = %x\n", r); + goto fmt; + } + + if ((buff[0] | buff[1] | buff[2] | buff[3]) == 0) { + sim_debug(DEBUG_CMD, &dda_dev, "Disk format buf0 %x buf1 %x buf2 %x buf3 %x\n", + buff[0], buff[1], buff[2], buff[3]); +fmt: + /* format the drive */ + if (disk_format(uptr)) { + detach_unit(uptr); /* if no space, error */ + return SCPE_FMT; /* error */ + } + } + + if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */ + detach_unit(uptr); /* if no space, error */ + return SCPE_FMT; /* error */ + } + + data->ssize = ssize; /* save sector size in bytes */ + data->tsize = tsize; /* save track size in bytes */ + data->cpos = 0; /* current read/write position in cylinder*/ + data->ccyl = 0; /* current cylinder number */ + data->tpos = 0; /* current track position */ + data->spos = 0; /* current sector position */ + data->rec = 0; /* record length */ + data->count = 0; /* clear count value */ + +// sim_debug(DEBUG_CMD, &dda_dev, "Attach %8s hds %d spt %d spc %d cyl %d capacity %d\n", +// disk_type[type].name, disk_type[type].nhds, disk_type[type].spt, +// disk_type[type].nhds * disk_type[type].spt, +// disk_type[type].cyl, uptr->capac); +// sim_debug(DEBUG_CMD, &dda_dev, "File %s attached to %s\r\n", file, disk_type[type].name); + + set_devattn(addr, SNS_DEVEND); +// sim_activate(uptr, 100); + return SCPE_OK; +} + +/* detach a disk device */ +t_stat disk_detach(UNIT * uptr) { + struct ddata_t *data = (struct ddata_t *)uptr->up7; + + if (data != 0) { +#ifdef CALLOC_BUFF + free(data->cbuf); /* free cylinder buffer */ +#endif + free(data); /* free disk data structure */ + } + uptr->up7 = 0; /* no pointer to disk data */ + uptr->u3 &= ~0xffff; /* no cmd and flags */ + return detach_unit(uptr); /* tell simh we are done with disk */ +} + +/* boot from the specified disk unit */ +t_stat disk_boot(int32 unit_num, DEVICE * dptr) { + UNIT *uptr = &dptr->units[unit_num]; /* find disk unit number */ + + sim_debug(DEBUG_CMD, &dda_dev, "Disk Boot dev/unit %x\n", GET_UADDR(uptr->u3)); + SPAD[0xf4] = GET_UADDR(uptr->u3); /* put boot device chan/sa into spad */ + SPAD[0xf8] = 0xF000; /* show as F class device */ + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; /* attached? */ + return chan_boot(GET_UADDR(uptr->u3), dptr); /* boot the ch/sa */ +} + +/* Disk option setting commands */ +t_stat disk_set_type(UNIT * uptr, int32 val, CONST char *cptr, void *desc) +{ + int i; + + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; + for (i = 0; disk_type[i].name != 0; i++) { + if (strcmp(disk_type[i].name, cptr) == 0) { + uptr->flags &= ~UNIT_TYPE; + uptr->flags |= SET_TYPE(i); +// uptr->capac = disk_type[i].bpt * disk_type[i].heads * disk_type[i].cyl; + uptr->capac = disk_type[i].taus * disk_type[i].spau; + return SCPE_OK; + } + } + return SCPE_ARG; +} + +t_stat +disk_get_type(FILE * st, UNIT * uptr, int32 v, CONST void *desc) +{ + if (uptr == NULL) + return SCPE_IERR; + fputs("TYPE=", st); + fputs(disk_type[GET_TYPE(uptr->flags)].name, st); + return SCPE_OK; +} + +/* help information for disk */ +t_stat disk_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr) +{ + int i; + fprintf (st, "SEL 2314 Disk Processor\r\n"); + fprintf (st, "Use:\r\n"); + fprintf (st, " sim> SET %sn TYPE=type\r\n", dptr->name); + fprintf (st, "Type can be: "); + for (i = 0; disk_type[i].name != 0; i++) { + fprintf(st, "%s", disk_type[i].name); + if (disk_type[i+1].name != 0) + fprintf(st, ", "); + } + fprintf (st, ".\nEach drive has the following storage capacity:\r\n"); + for (i = 0; disk_type[i].name != 0; i++) { + int32 size = disk_type[i].taus * disk_type[i].spau; + size /= 1024; + size = (10 * size) / 1024; + fprintf(st, " %-8s %4d.%1dMB\r\n", disk_type[i].name, size/10, size%10); + } + fprint_set_help (st, dptr); + fprint_show_help (st, dptr); + return SCPE_OK; +} + +const char *disk_description (DEVICE *dptr) +{ + return "SEL 2314 Disk Processor"; +} + +#endif diff --git a/SEL32/sel32_iop.c b/SEL32/sel32_iop.c new file mode 100644 index 0000000..52247d2 --- /dev/null +++ b/SEL32/sel32_iop.c @@ -0,0 +1,199 @@ +/* sel32_iop.c: SEL 32 Class F IOP processor channel. + + Copyright (c) 2018, 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"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This channel is the interrupt fielder for all of the IOP sub channels. It's + channel address is 7E00. This code handles the INCH command for the IOP + devices and controls the status FIFO for the iop devices on interrupts and + TIO instructions.. + + Possible devices: + The f8iop communication controller (TY7EA0), (TY7EB0), (TY7EC0) + The ctiop console communications controller (CT7EFC & CT7EFD) + The lpiop line printer controller (LP7EF8), (LP7EF9) + +*/ + +#include "sel32_defs.h" +#include "sim_defs.h" + +#ifdef NUM_DEVS_IOP + +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chan, uint8 *data); +extern int chan_write_byte(uint16 chan, uint8 *data); +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); + +/* Held in u3 is the device command and status */ +#define IOP_INCH 0x00 /* Initialize channel command */ +#define IOP_MSK 0xff /* Command mask */ + +/* Status held in u3 */ +/* controller/unit address in upper 16 bits */ +#define CON_INPUT 0x100 /* Input ready for unit */ +#define CON_CR 0x200 /* Output at beginning of line */ +#define CON_REQ 0x400 /* Request key pressed */ +#define CON_EKO 0x800 /* Echo input character */ +#define CON_OUTPUT 0x1000 /* Output ready for unit */ +#define CON_READ 0x2000 /* Read mode selected */ + +/* Input buffer pointer held in u4 */ + +/* in u5 packs sense byte 0,1 and 3 */ +/* Sense byte 0 */ +#define SNS_CMDREJ 0x80000000 /* Command reject */ +#define SNS_INTVENT 0x40000000 /* Unit intervention required */ +/* sense byte 3 */ +#define SNS_RDY 0x80 /* device ready */ +#define SNS_ONLN 0x40 /* device online */ + +/* std devices. data structures + + iop_dev Console device descriptor + iop_unit Console unit descriptor + iop_reg Console register list + iop_mod Console modifiers list +*/ + +struct _iop_data +{ + uint8 ibuff[145]; /* Input line buffer */ + uint8 incnt; /* char count */ +} +iop_data[NUM_UNITS_CON]; + +/* forward definitions */ +uint8 iop_startcmd(UNIT *, uint16, uint8); +void iop_ini(UNIT *, t_bool); +t_stat iop_srv(UNIT *); + +/* channel program information */ +CHANP iop_chp[NUM_UNITS_MT] = {0}; + +MTAB iop_mod[] = { + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL}, + {0} +}; + +UNIT iop_unit[] = { + {UDATA(iop_srv, UNIT_ATT, 0), 0, UNIT_ADDR(0x7E00)}, /* Channel controlller */ +}; + +//DIB iop_dib = {NULL, iop_startcmd, NULL, NULL, NULL, iop_ini, iop_unit, iop_chp, NUM_UNITS_IOP, 0xff, 0x7e00,0,0,0}; +DIB iop_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */ + iop_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command SIO */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O HIO */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O TIO */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + 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 */ + 0xff, /* uint8 mask */ /* 16 devices - device mask */ + 0x7e00, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE iop_dev = { + "IOP", iop_unit, NULL, iop_mod, + NUM_UNITS_IOP, 8, 15, 1, 8, 8, + NULL, NULL, NULL, NULL, NULL, NULL, + &iop_dib, DEV_UADDR|DEV_DISABLE|DEV_DEBUG, 0, dev_debug +}; + +/* IOP controller routines */ +/* initialize the console chan/unit */ +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 %x\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 */ +} + +/* start an I/O operation */ +uint8 iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) +{ + if ((uptr->u3 & IOP_MSK) != 0) /* is unit busy */ + return SNS_BSY; /* yes, return busy */ + + /* process the commands */ + switch (cmd & 0xFF) { + case IOP_INCH: /* INCH command */ + sim_debug(DEBUG_CMD, &iop_dev, "iop_startcmd %x: Cmd INCH\n", chan); + return SNS_CHNEND|SNS_DEVEND; /* all is well */ + break; + + default: /* invalid command */ + uptr->u5 |= SNS_CMDREJ; /* command rejected */ + sim_debug(DEBUG_CMD, &iop_dev, "iop_startcmd %x: Cmd Invald %x status %02x\n", chan, cmd, uptr->u5); + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + break; + } + + if (uptr->u5 & (~(SNS_RDY|SNS_ONLN))) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + return SNS_CHNEND|SNS_DEVEND; +} + +/* Handle transfers for other sub-channels on IOP */ +t_stat iop_srv(UNIT *uptr) +{ + uint16 chsa = GET_UADDR(uptr->u3); + int unit = (uptr - iop_unit); /* unit 0 is channel */ + + uptr->u3 &= LMASK; /* nothing left, command complete */ + sim_debug(DEBUG_CMD, &iop_dev, "iop_srv chan %d: devend|devend\n", unit); +// chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* TRY 6/12/18 done */ + 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 %x: cmd %x \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 %x: cmd %x \n", chsa, cmd); + return SCPE_OK; +} + +#endif + diff --git a/SEL32/sel32_lpr.c b/SEL32/sel32_lpr.c new file mode 100644 index 0000000..6407d08 --- /dev/null +++ b/SEL32/sel32_lpr.c @@ -0,0 +1,465 @@ +/* sel32_lpr.c: SEL 32 Line Printer + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This is the standard line printer. + + These units each buffer one record in local memory and signal + ready when the buffer is full or empty. The channel must be + ready to recieve/transmit data when they are activated since + they will transfer their block during chan_cmd. All data is + transmitted as BCD characters. +*/ + +#include "sel32_defs.h" +#include "sim_defs.h" +#include + +/**** COMMANDS TO PRINT BUFFER THEN DO FORMS CONTROL */ +/* +LP.CMD1 DATAW X'01000000' PRINT ONLY - NO FORMS CONTROL +LP.CMD2 DATAW X'05000000' PRINT BUFFER, +LP.CMD3 DATAW X'15000000' PRINT BUFFER, +LP.CMD4 DATAW X'25000000' PRINT BUFFER, +LP.CMD5 DATAW X'35000000' PRINT BUFFER, +LP.CMD6 DATAW X'45000000' PRINT BUFFER, +LP.CMD7 DATAW X'85000000' PRINT BUFFER, , THEN CLEAR BUFFER +* +**** COMMANDS TO DO FORMS CONTROL AND THEN PRINT BUFFER. +**** NOTE: THESE COMMANDS ARE ARRANGED SO THAT BY USING THE INDEX +**** OF THE FORMS CONTROL TABLE AND A OFFSET INTO THIS TABLE +**** YOU CAN GET THE APPROPRIATE COMMAND FOR THE FC CHAR. +* +LP.CMD8 DATAW X'0D000000' , PRINT BUFFER, +LP.CMD9 DATAW X'4D000000' , PRINT BUFFER, + DATAW X'4D000000' , PRINT BUFFER, +LP.CMD10 DATAW X'2D000000' , PRINT BUFFER +LP.CMD11 DATAW X'1D000000' , PRINT BUFFER, +LP.CMD12 DATAW X'3D000000' , PRINT, (SPARE) +* +**** COMMANDS THAT DO ONLY FORMS CONTROL (NO PRINTING) +* +LP.CMD13 DATAW X'03000000' +LP.CMD14 DATAW X'47000000' + DATAW X'47000000' +LP.CMD15 DATAW X'27000000' +LP.CMD16 DATAW X'17000000' +LP.CMD17 DATAW X'37000000' (SPARE) +* +** LINE PRINTER FORMS CONTROL TABLE +* +LPFCTBL EQU $ +P0006C 2B DATAB C'+' 0x2b FORMS CONTROL FOR CR THEN PRINT +P0006D 31 DATAB C'1' 0x31 FORMS CONTROL FOR FF THEN PRINT +P0006E 2D DATAB C'-' 0x2d FORMS CONTROL FOR FF THEN PRINT +P0006F 30 DATAB C'0' 0x30 FORMS CONTROL FOR 2 LF'S THEN PRINT +P00070 20 DATAB C' ' 0x20 FORMS CONTROL FOR LF THEN PRINT +*/ + +#ifdef NUM_DEVS_LPR +#define UNIT_LPR UNIT_ATTABLE | UNIT_DISABLE + +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chan, uint8 *data); +extern int chan_write_byte(uint16 chan, uint8 *data); +extern void set_devattn(uint16 addr, uint8 flags); + +/* u3 hold command and status information */ +#define LPR_INCH 0x00 /* INCH command */ +/* print buffer then CC commands */ +#define LPR_PBNCC 0x01 /* print only, no forms control */ +#define LPR_PBC 0x05 /* print buffer, then */ +#define LPR_PBL 0x15 /* print buffer, then */ +#define LPR_PBLL 0x25 /* print buffer, then */ +#define LPR_PBLLL 0x35 /* print buffer, then */ +#define LPR_PBF 0x45 /* print buffer, then */ +#define LPR_PBCCB 0x85 /* print buffer, then */ + /* Do CC then print commands then CC */ +#define LPR_CPBC 0x0d /* print buffer */ +#define LPR_LPBC 0x1d /* print buffer */ +#define LPR_LLPBC 0x2d /* print buffer */ +#define LPR_LLLPBC 0x3d /* print buffer */ +#define LPR_FPBC 0x4d /* print buffer */ + /* Do CC only, no print */ +#define LPR_NPC 0x03 /* */ +#define LPR_NPL 0x17 /* */ +#define LPR_NPLL 0x27 /* */ +#define LPR_NPLLL 0x37 /* */ +#define LPR_NPF 0x47 /* */ + +#define LPR_SNS 0x04 /* Sense command */ +#define LPR_CMDMSK 0xff /* Mask command part. */ +#define LPR_FULL 0x100 /* Buffer full (BOF) */ +#define LPR_PRE 0x200 /* Apply pre CC */ +#define LPR_POST 0x400 /* Apply post CC */ + +/* u4 holds current line */ +/* in u5 packs sense byte 0,1 and 3 */ +/* Sense byte 0 */ +#define SNS_CMDREJ 0x80 /* Command reject */ +#define SNS_INTVENT 0x40 /* Unit intervention required */ +#define SNS_BUSCHK 0x20 /* Parity error on bus */ +#define SNS_EQUCHK 0x10 /* Equipment check */ +#define SNS_DATCHK 0x08 /* Data Check */ +#define SNS_OVRRUN 0x04 /* Data overrun */ +#define SNS_SEQUENCE 0x02 /* Unusual sequence */ +#define SNS_BOF 0x01 /* BOF on printer */ +/* u6 hold buffer position */ + +/* std devices. data structures + lpr_dev Line Printer device descriptor + lpr_unit Line Printer unit descriptor + lpr_reg Line Printer register list + lpr_mod Line Printer modifiers list +*/ + +struct _lpr_data +{ + uint8 lbuff[160]; /* Output line buffer */ +} + +lpr_data[NUM_DEVS_LPR]; + +uint8 lpr_startcmd(UNIT *, uint16, uint8); +void lpr_ini(UNIT *, t_bool); +t_stat lpr_srv(UNIT *); +t_stat lpr_reset(DEVICE *); +t_stat lpr_attach(UNIT *, CONST char *); +t_stat lpr_detach(UNIT *); +t_stat lpr_setlpp(UNIT *, int32, CONST char *, void *); +t_stat lpr_getlpp(FILE *, UNIT *, int32, CONST void *); + +/* channel program information */ +CHANP lpr_chp[NUM_DEVS_LPR] = {0}; + +MTAB lpr_mod[] = { + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE", + &lpr_setlpp, &lpr_getlpp, NULL, "Number of lines per page"}, + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, + &show_dev_addr, NULL}, + {0} +}; + +UNIT lpr_unit[] = { + {UDATA(lpr_srv, UNIT_LPR, 55), 300, UNIT_ADDR(0x7EF8)}, /* A */ +#if NUM_DEVS_LPR > 1 + {UDATA(lpr_srv, UNIT_LPR, 55), 300, UNIT_ADDR(0x7EF9)}, /* B */ +#endif +}; + +/* Device Information Block */ +//DIB lpr_dib = {NULL, lpr_startcmd, NULL, NULL, lpr_ini, lpr_unit, lpr_chp, NUM_DEVS_LPR, 0xff, 0x7e00, 0, 0, 0}; +DIB lpr_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */ + lpr_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + lpr_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + lpr_unit, /* UNIT* units */ /* Pointer to units structure */ + lpr_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_DEVS_LPR, /* uint8 numunits */ /* number of units defined */ + 0xff, /* uint8 mask */ /* 2 devices - device mask */ + 0x7e00, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE lpr_dev = { + "LPR", lpr_unit, NULL, lpr_mod, + NUM_DEVS_LPR, 8, 15, 1, 8, 8, + NULL, NULL, NULL, NULL, &lpr_attach, &lpr_detach, + &lpr_dib, DEV_UADDR | DEV_DISABLE | DEV_DEBUG, 0, dev_debug +}; + +/* initialize the line printer */ +void lpr_ini(UNIT *uptr, t_bool f) { + /* do nothing for now */ +} + +/* start an I/O operation */ +uint8 lpr_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) +{ + uint8 ch; + + if ((uptr->u3 & LPR_CMDMSK) != 0) { /* unit busy */ + return SNS_BSY; /* yes, busy (already tested) */ + } + + uptr->u3 &= ~(LPR_POST|LPR_PRE); /* set no CC */ + if (((cmd & 0x03) == 0x03) || (cmd & 0x0d) == 0x0d) { + uptr->u3 |= LPR_PRE; /* apply pre CC */ + } + if (((cmd & 0x05) == 0x05) || (cmd & 0x0d) == 0x0d) { + uptr->u3 |= LPR_POST; /* apply post CC */ + } + sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd Cmd %02x\n", cmd); + + /* process the command */ + switch (cmd & LPR_CMDMSK) { + case 0x00: /* INCH command */ + sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd INCH\n", chan); + return SNS_CHNEND|SNS_DEVEND; /* all is well */ + break; + + /* No CC */ + case 0x01: /* print only, no forms control */ + /* print buffer then CC commands */ + case 0x05: /* print buffer, then */ + case 0x15: /* print buffer, then */ + case 0x25: /* print buffer, then */ + case 0x35: /* print buffer, then */ + case 0x45: /* print buffer, then */ + case 0x85: /* print buffer, then */ + /* Do CC then print commands then CC */ + case 0x0d: /* print buffer */ + case 0x1d: /* print buffer */ + case 0x2d: /* print buffer */ + case 0x3d: /* print buffer */ + case 0x4d: /* print buffer */ + /* Do CC only, no print */ + case 0x03: /* */ + case 0x17: /* */ + case 0x27: /* */ + case 0x37: /* */ + case 0x47: /* */ + /* process the command */ + sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd %x print\n", chan, cmd&LPR_CMDMSK); + uptr->u3 &= ~(LPR_CMDMSK); /* zero cmd */ + uptr->u3 |= (cmd & LPR_CMDMSK); /* save new command in u3 */ + sim_activate(uptr, 10); /* Start unit off */ + uptr->u5 = 0; /* no status */ + uptr->u6 = 0; /* start of buffer */ + return 0; /* we are good to go */ + + case 0x4: /* Sense Status */ + sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd %x sense\n", chan, cmd&LPR_CMDMSK); + uptr->u3 &= ~(LPR_CMDMSK); /* zero cmd */ + uptr->u3 |= (cmd & LPR_CMDMSK); /* save new command in u3 */ + sim_activate(uptr, 10); /* Start unit off */ + uptr->u5 = 0; /* no status */ + uptr->u6 = 0; /* start of buffer */ + return 0; /* we are good to go */ + + default: /* invalid command */ + sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd %x INVALID \r\n", chan, cmd&LPR_CMDMSK); + uptr->u5 |= SNS_CMDREJ; + break; + } + if (uptr->u5 & 0xff) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + return SNS_CHNEND|SNS_DEVEND; +} + +/* Handle transfer of data for printer */ +t_stat lpr_srv(UNIT *uptr) { + int chsa = GET_UADDR(uptr->u3); + int u = (uptr - lpr_unit); + int cmd = (uptr->u3 & 0xff); + + sim_debug(DEBUG_CMD, &lpr_dev, "lpr_srv called chsa %x cmd %x u3 %x cnt %x\r\n", chsa, cmd, uptr->u3, uptr->u6); + + /* FIXME, need IOP lp status bit assignments */ + if (cmd == 0x04) { /* sense? */ + uint8 ch = uptr->u5; /* get current status */ + uptr->u3 &= ~(LPR_CMDMSK); /* clear command */ + chan_write_byte(chsa, &ch); /* write the status to memory */ + uptr->u6 = 0; /* reset to beginning of buffer */ + chan_end(chsa, SNS_DEVEND|SNS_CHNEND); /* we are done */ + return SCPE_OK; + } + + /* process any CC before printing buffer */ + if ((uptr->u3 & LPR_PRE) && (((cmd & 0x03) == 0x03) || (cmd & 0x0d) == 0x0d)) { + uptr->u3 &= ~LPR_PRE; /* remove pre flag */ + /* we have CC to do */ + switch ((cmd & 0xf0) >> 4) { + case 0: /* (0x0d) */ + lpr_data[u].lbuff[uptr->u6++] = 0x0d; + break; + case 3: /* */ + lpr_data[u].lbuff[uptr->u6++] = 0x0a; + uptr->u4++; /* increment the line count */ + /* drop thru */ + case 2: /* */ + lpr_data[u].lbuff[uptr->u6++] = 0x0a; + uptr->u4++; /* increment the line count */ + /* drop thru */ + case 1: /* (0x0a) */ + lpr_data[u].lbuff[uptr->u6++] = 0x0a; + uptr->u4++; /* increment the line count */ + break; + case 4: /* (0x0c) */ + lpr_data[u].lbuff[uptr->u6++] = 0x0c; + uptr->u4 = 0; /* restart line count */ + break; + } + } + + /* Copy next byte from users buffer */ + if ((uptr->u3 & LPR_FULL) == 0) { /* copy in a char if not full */ + if(chan_read_byte(chsa, &lpr_data[u].lbuff[uptr->u6])) { + uptr->u3 |= LPR_FULL; /* end of buffer or error */ + } else { + sim_activate(uptr, 20); /* got a char, wait for a while */ + uptr->u6++; /* next buffer loc */ + return SCPE_OK; /* done til next char */ + } + } + + /* process any CC after printing buffer */ + if ((uptr->u3 & LPR_FULL) && (uptr->u3 & LPR_POST) && ((cmd & 0x0d) == 0x0d)) { + /* we have CC to do */ + uptr->u3 &= ~LPR_POST; /* remove post flag */ + lpr_data[u].lbuff[uptr->u6++] = 0x0d; /* just a */ + } + + /* process any CC after printing buffer */ + if ((uptr->u3 & LPR_FULL) && (uptr->u3 & LPR_POST) && ((cmd & 0x05) == 0x05)) { + /* we have CC to do */ + uptr->u3 &= ~LPR_POST; /* remove post flag */ + switch ((cmd & 0xf0) >> 4) { + case 0: /* (0x0d) */ + lpr_data[u].lbuff[uptr->u6++] = 0x0d; + break; + case 3: /* */ + lpr_data[u].lbuff[uptr->u6++] = 0x0a; + /* drop thru */ + case 2: /* */ + lpr_data[u].lbuff[uptr->u6++] = 0x0a; + /* drop thru */ + case 1: /* (0x0a) */ + lpr_data[u].lbuff[uptr->u6++] = 0x0a; + break; + case 4: /* (0x0c) */ + lpr_data[u].lbuff[uptr->u6++] = 0x0c; + uptr->u4 = 0; /* restart line count */ + break; + } + } + + /* print the line if buffer is full */ + if (uptr->u3 & LPR_FULL || uptr->u6 >= 156) { + lpr_data[u].lbuff[uptr->u6] = 0x00; /* NULL terminate */ + sim_fwrite(&lpr_data[u].lbuff, 1, uptr->u6, uptr->fileref); /* Print our buffer */ + sim_debug(DEBUG_DETAIL, &lpr_dev, "LPR %s", &lpr_data[u].lbuff); + uptr->u3 &= ~(LPR_FULL|LPR_CMDMSK); /* clear old status */ + uptr->u6 = 0; /* start at beginning of buffer */ + uptr->u4++; /* increment the line count */ + if (uptr->u4 > uptr->capac) { /* see if at max lines/page */ + uptr->u4 = 0; /* yes, restart count */ + chan_end(chsa, SNS_DEVEND|SNS_CHNEND|SNS_UNITEXP); /* we are done */ + } else + chan_end(chsa, SNS_DEVEND|SNS_CHNEND); /* we are done */ + sim_activate(uptr, 3000); /* wait a long time for next look */ + return SCPE_OK; + } + + sim_activate(uptr, 20); /* got a char, wait for a while */ + return SCPE_OK; +} + +/* print a line to the "printer" */ +void print_line(UNIT *uptr) +{ + char out[150]; /* Temp conversion buffer */ + int i; + int u = (uptr - lpr_unit); + + /* Try to convert to text */ + memset(out, ' ', sizeof(out)); + + /* Scan each column */ + for (i = 0; i < uptr->u6; i++) { + int ch = lpr_data[u].lbuff[i]; + + if (!isprint(ch)) /* make sure char is printable */ + ch = '.'; /* not printable, make it a '.' */ + out[i] = ch; /* save to buffer */ + } + + for (--i; i > 0 && out[i] == ' '; i--) /* Trim trailing spaces */ + ; + out[++i] = '\r'; /* output CR, LF. NULL */ + out[++i] = '\n'; + out[++i] = '\0'; + + sim_fwrite(&out, 1, i, uptr->fileref); /* Print our buffer */ + sim_debug(DEBUG_DETAIL, &lpr_dev, "%s", out); + + memset(&lpr_data[u].lbuff[0], 0, 144); /* clear the output buffer */ +} + +/* Set the number of lines per page on printer */ +t_stat lpr_setlpp(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int i; + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + i = 0; + while(*cptr != '\0') { + if (*cptr < '0' || *cptr > '9') + return SCPE_ARG; + i = (i * 10) + (*cptr++) - '0'; + } + if (i < 20 || i > 100) + return SCPE_ARG; + uptr->capac = i; + uptr->u4 = 0; + return SCPE_OK; +} + +/* display the number of lines per page */ +t_stat lpr_getlpp(FILE *st, UNIT *uptr, int32 v, CONST void *desc) +{ + if (uptr == NULL) + return SCPE_IERR; + fprintf(st, "linesperpage=%d", uptr->capac); + return SCPE_OK; +} + +/* attach a file to the line printer device */ +t_stat lpr_attach(UNIT * uptr, CONST char *file) +{ + t_stat r; + + if ((r = attach_unit(uptr, file)) != SCPE_OK) + return r; + uptr->u3 &= ~(LPR_FULL|LPR_CMDMSK); + uptr->u4 = 0; + uptr->u5 = 0; + return SCPE_OK; +} + +/* detach a file from the line printer */ +t_stat lpr_detach(UNIT * uptr) +{ + if (uptr->u3 & LPR_FULL) + print_line(uptr); + return detach_unit(uptr); +} + +#endif diff --git a/SEL32/sel32_mt.c b/SEL32/sel32_mt.c index 26fab47..bd94572 100644 --- a/SEL32/sel32_mt.c +++ b/SEL32/sel32_mt.c @@ -1,6 +1,7 @@ /* sel32_mt.c: SEL 32 2400 Magnetic tape controller - Copyright (c) 2016, Richard Cornwell + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,7 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,7 +34,7 @@ If the byte count is odd, the record is padded with an extra byte of junk. File marks are represented by a byte count of 0. */ - + #include "sel32_defs.h" #include "sim_tape.h" @@ -44,6 +45,7 @@ extern int chan_read_byte(uint16 chan, uint8 *data); 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 uint32 SPAD[]; /* cpu SPAD */ #ifdef NUM_DEVS_MT #define BUFFSIZE (64 * 1024) @@ -120,25 +122,29 @@ OTAB EQU $ #define MT_INCH 0x00 /* Initialize channel command */ #define MT_WRITE 0x01 /* Write command */ #define MT_READ 0x02 /* Read command */ -#define MT_RDBK 0x0c /* Read Backward */ +#define MT_NOP 0x03 /* Control command */ #define MT_SENSE 0x04 /* Sense command */ +#define MT_RDBK 0x0c /* Read Backward */ +#define MT_RDCMP 0x13 /* Read and compare command */ #define MT_REW 0x23 /* Rewind command */ #define MT_RUN 0x33 /* Rewind and unload */ -#define MT_ERG 0x17 /* Erase 3.5 of tape (maybe 0xA3) */ -#define MT_WTM 0x93 /* Write Tape filemark */ -#define MT_BSR 0x53 /* Backspace record */ -#define MT_BSF 0x73 /* Backspace filemark */ #define MT_FSR 0x43 /* Advance record */ +#define MT_BSR 0x53 /* Backspace record */ #define MT_FSF 0x63 /* Advance filemark */ -#define MT_MODE 0x83 /* Mode command */ -#define MT_MODEMSK 0xC3 /* Mode Mask */ +#define MT_BSF 0x73 /* Backspace filemark */ +#define MT_SETM 0x83 /* Set Mode command */ +#define MT_WTM 0x93 /* Write Tape filemark */ +#define MT_ERG 0xA3 /* Erase 3.5 of tape */ +#define MT_MODEMSK 0xFF /* Mode Mask */ -/* FIXME */ /* set correct bits for BTP */ -#define MT_MDEN_200 0x00 /* 200 BPI mode 7 track only */ -#define MT_MDEN_556 0x40 /* 556 BPI mode 7 track only */ -#define MT_MDEN_800 0x80 /* 800 BPI mode 7 track only */ -#define MT_MDEN_1600 0xc0 /* 1600 BPI mode 9 track only */ -#define MT_MDEN_6250 0x10 /* 6250 BPI mode 9 track only */ +/* set mode bits for BTP (MT_SETM) */ +#define MT_MODE_AUTO 0x80 /* =0 Perform auto error recodery on read */ +#define MT_MODE_FORCE 0x80 /* =1 Read regardless if error recovery fails */ +#define MT_MDEN_800 0x40 /* =0 select 800 BPI NRZI mode 9 track only */ +#define MT_MDEN_1600 0x40 /* =1 select 1600 BPI PE mode 9 track only */ +#define MT_MDEN_6250 0x20 /* =0 Use mode from bit one for NRZI/PE */ +#define MT_MDEN_6250 0x20 /* =1 6250 BPI GCR mode 9 track only */ +#define MT_MDEN_SCATGR 0x01 /* =1 HSTP scatter/gather mode */ #define MT_MDEN_MSK 0xc0 /* Density mask */ #define MT_CTL_MSK 0x38 /* Mask for control flags */ @@ -146,10 +152,6 @@ OTAB EQU $ #define MT_CTL_NRZI 0x08 /* 9 track 800 bpi mode */ #define MT_CTL_RST 0x10 /* Set density, odd, convert on, trans off */ #define MT_CTL_NOP2 0x18 /* 9 track 1600 NRZI mode */ -#define MT_CTL_MD0 0x20 /* Set density, even, convert off, trans off */ -#define MT_CTL_MD1 0x28 /* Set density, even, convert off, trans on */ -#define MT_CTL_MD2 0x30 /* Set density, odd, convert off, trans off */ -#define MT_CTL_MD3 0x38 /* Set density, odd, convert off, trans on */ /* in u3 is device command code and status */ #define MT_CMDMSK 0x00ff /* Command being run */ @@ -162,38 +164,46 @@ OTAB EQU $ /* in u4 is current buffer position */ -/* in u5 packs sense byte 0,1 and 3 */ +/* in u5 packs sense byte 0, 1, 2 and 3 */ /* Sense byte 0 */ -#define SNS_CMDREJ 0x80 /* Command reject */ -#define SNS_INTVENT 0x40 /* Unit intervention required */ -#define SNS_BUSCHK 0x20 /* Parity error on bus */ -#define SNS_EQUCHK 0x10 /* Equipment check */ -#define SNS_DATCHK 0x08 /* Data Check */ -#define SNS_OVRRUN 0x04 /* Data overrun */ -#define SNS_WCZERO 0x02 /* Write with no data */ -#define SNS_CVTCHK 0x01 /* Data conversion error */ +#define SNS_CMDREJ 0x80000000 /* Command reject */ +#define SNS_INTVENT 0x40000000 /* Unit intervention required */ +#define SNS_SPARE1 0x20000000 /* Spare */ +#define SNS_EQUCHK 0x10000000 /* Equipment check */ +#define SNS_DATCHK 0x08000000 /* Data Check */ +#define SNS_OVRRUN 0x04000000 /* Data overrun */ +#define SNS_SPARE2 0x02000000 /* Spare */ +#define SNS_LOOKER 0x01000000 /* lookahead error */ /* Sense byte 1 */ -#define SNS_NOISE 0x80 /* Noise record */ -#define SNS_TUASTA 0x40 /* Selected and ready */ -#define SNS_TUBSTA 0x20 /* Not ready, rewinding. */ -#define SNS_7TRACK 0x10 /* Seven track unit */ -#define SNS_LOAD 0x08 /* Load Point */ -#define SNS_WR 0x04 /* Unit write */ -#define SNS_WRP 0x02 /* No write ring */ -#define SNS_DENS 0x01 /* Density error 9tr only */ +#define SNS_PEMODER 0x800000 /* PE tape mode error */ +#define SNS_TPECHK 0x400000 /* Tape PE mode check */ +#define SNS_FMRKDT 0x200000 /* File mark detected EOR */ +#define SNS_CORERR 0x100000 /* Corrected Error */ +#define SNS_HARDER 0x080000 /* Hard Error */ +#define SNS_MRLDER 0x040000 /* Mode register load error */ +#define SNS_DATAWR 0x020000 /* Data written */ +#define SNS_SPARE3 0x010000 /* Spare */ -/* Sense byte 2 */ -#define SNS_BYTE2 0xc0 /* Not supported feature */ +/* Sense byte 2 mode bits */ +#define SNS_MREG0 0x8000 /* Mode register bit 0 */ +#define SNS_MREG1 0x4000 /* Mode register bit 1 */ +#define SNS_MREG2 0x2000 /* Mode register bit 2 */ +#define SNS_MREG3 0x1000 /* Mode register bit 3 */ +#define SNS_MREG4 0x0800 /* Mode register bit 4 */ +#define SNS_MREG5 0x0400 /* Mode register bit 5 */ +#define SNS_MREG6 0x0200 /* Mode register bit 6 */ +#define SNS_MREG7 0x0100 /* Mode register bit 7 */ /* Sense byte 3 */ -#define SNS_VRC 0x80 /* Veritical parity error */ -#define SNS_LRCR 0x40 /* Logituntial parity error */ -#define SNS_SKEW 0x20 /* Skew */ -#define SNS_CRC 0x10 /* CRC error. 9t only */ -#define SNS_SKEWVRC 0x08 /* VRC Skew */ -#define SNS_PE 0x04 /* Phase encoding */ -#define SNS_BACK 0x01 /* tape in backward status */ +#define SNS_RDY 0x80 /* Drive Ready */ +#define SNS_ONLN 0x40 /* Drive Online */ +#define SNS_WRP 0x20 /* Drive is file protected (write ring missing) */ +#define SNS_NRZI 0x10 /* Drive is NRZI */ +#define SNS_SPARE4 0x08 /* Spare */ +#define SNS_LOAD 0x04 /* Drive is at load point */ +#define SNS_EOT 0x02 /* Drive is at EOT */ +#define SNS_SPARE5 0x01 /* Spare */ #define SNS_BYTE4 0x00 /* Hardware errors not supported */ #define SNS_BYTE5 0x00 /* Hardware errors not supported */ @@ -228,14 +238,14 @@ uint8 mt_busy[NUM_DEVS_MT]; /* | Cond Code | 0 0 0 0 | Address of status doubleword or zero | */ /* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ /* */ -/* BIts 0-3 - Condition codes */ -/* 0000 - operation accepted with echo */ +/* Bits 0-3 - Condition codes */ +/* 0000 - operation accepted will echo status not sent by the channel */ /* 0001 - channel busy */ /* 0010 - channel inop or undefined */ /* 0011 - subchannel busy */ /* 0100 - status stored */ /* 0101 - unsupported transaction */ -/* 1000 - Operation accepted */ +/* 1000 - Operation accepted/queued, no echo status */ /* Status Doubleword */ /* Word 1 */ @@ -250,25 +260,25 @@ uint8 mt_busy[NUM_DEVS_MT]; /* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ /* Status Bits */ -/* Bit 00 - ECHO Halt I/O and Stop I/O function */ -/* Bit 01 - PCI Program Controlled Interrupt */ -/* Bit 02 - IL Incorrect Length */ -/* Bit 03 - CPC Channel Program Check */ -/* Bit 04 - CDC Channel Data Check */ -/* Bit 05 - CCC Channel Control Check */ -/* Bit 06 - IC Interface Check */ -/* Bit 07 - CHC Chaining Check */ -/* Bit 08 - DB Device Busy */ -/* Bit 09 - SM Status Modifier */ -/* Bit 10 - CNTE Controller End */ -/* Bit 11 - ATTN Attention */ -/* Bit 12 - CE Channel End */ -/* Bit 13 - DE Device End */ -/* Bit 14 - UC Unit Check */ -/* Bit 15 - UE Unit Exception */ +/* Bit 00 - ECHO Halt I/O and Stop I/O function */ +/* Bit 01 - PCI Program Controlled Interrupt */ +/* Bit 02 - IL Incorrect Length */ +/* Bit 03 - CPC Channel Program Check */ +/* Bit 04 - CDC Channel Data Check */ +/* Bit 05 - CCC Channel Control Check */ +/* Bit 06 - IC Interface Check */ +/* Bit 07 - CHC Chaining Check */ +/* Bit 08 - DB Device Busy */ +/* Bit 09 - SM Status Modifier */ +/* Bit 10 - CNTE Controller End */ +/* Bit 11 - ATTN Attention */ +/* Bit 12 - CE Channel End */ +/* Bit 13 - DE Device End */ +/* Bit 14 - UC Unit Check */ +/* Bit 15 - UE Unit Exception */ /* 41 Word Main memory channel buffer provided by INCH command */ -/* when software is initializing the hannel */ +/* when software is initializing the channel */ /* Word 01 - Status Doubleword 1 - Word 1 */ /* Word 02 - Status Doubleword 1 - Word 2 */ /* Word 03 - Status Doubleword 2 - Word 1 */ @@ -276,8 +286,8 @@ uint8 mt_busy[NUM_DEVS_MT]; /* Word 05 - BTP Error Recovery IOCD Address */ /* Word 06 - Queue Command List Doubleword - Word 1 */ /* Word 07 - Queue Command List Doubleword - Word 2 */ -/* Word 08 - 16 but Logical Q-pointer | 16 bit Physical Q-pointer */ -/* Word 09 - 16 Active Retry Count | 16 bit Constant Retry Count */ +/* Word 08 - 16 bit Logical Q-pointer | 16 bit Physical Q-pointer */ +/* Word 09 - 16 bit Active Retry Count | 16 bit Constant Retry Count */ /* Word 10 - Accumulated Write Count - Drive 0 */ /* Word 11 - Accumulated Read Count - Drive 0 */ /* Word 12 - Write Error Count - Drive 0 */ @@ -315,7 +325,6 @@ uint8 mt_busy[NUM_DEVS_MT]; MTAB mt_mod[] = { {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL}, {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL}, - {MTUF_9TR, 0, "7 track", "7T", NULL}, {MTUF_9TR, MTUF_9TR, "9 track", "9T", NULL}, {MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL}, @@ -402,9 +411,9 @@ struct UNIT { #endif /* DEFINED_IN_SIM_DEFS_H */ UNIT mta_unit[] = { - /* Unit data layout for MT devices */ + /* Unit data layout for MT devices */ // {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1000)}, /* 0 */ - { + { NULL, /* UNIT *next */ /* next active */ mt_srv, /* t_stat (*action) */ /* action routine */ NULL, /* char *filename */ /* open file name */ @@ -412,7 +421,7 @@ UNIT mta_unit[] = { NULL, /* void *filebuf */ /* memory buffer */ 0, /* uint32 hwmark */ /* high water mark */ 0, /* int32 time */ /* time out */ - UNIT_MT, /* uint32 flags */ /* flags */ + UNIT_MT, /* uint32 flags */ /* flags */ 0, /* uint32 dynflags */ /* dynamic flags */ 0, /* t_addr capac */ /* capacity */ 0, /* t_addr pos */ /* file position */ @@ -422,7 +431,7 @@ UNIT mta_unit[] = { 0, /* int32 wait */ /* wait */ UNIT_ADDR(0x1000), /* int32 u3 */ /* unit address */ 0, /* int32 u4 */ /* currrent buffer position */ - 0, /* int32 u5 */ /* pack sense bytes 0, 1 and 3 */ + 0, /* int32 u5 */ /* pack sense bytes 0, 1, mode bits, and 3 */ 0, /* int32 u6 */ /* packed chars and unpack count */ NULL, /* void *up7 */ /* device specific */ NULL, /* void *up8 */ /* device specific */ @@ -430,9 +439,9 @@ UNIT mta_unit[] = { 0, /* uint16 us10 */ /* device specific */ NULL, /* void *tmxr */ /* TMXR linkage */ NULL, /* t_bool(*cancel)(UNIT *) *//* Cancel I/O routine */ - 0, /* double usecs_remaining */ /* time balance for long delays */ + 0, /* double usecs_remaining */ /* time balance for long delays */ NULL, /* char *uname */ /* Unit name */ - }, + }, {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1001)}, /* 1 */ {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1002)}, /* 2 */ {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1003)}, /* 3 */ @@ -445,25 +454,33 @@ UNIT mta_unit[] = { #if DEFINED_IN_SEL32_DEFS_H /* Device information block */ typedef struct dib { - uint8 mask; /* device mask */ - uint8 numunits; /* number of units */ - /* Start I/O */ - uint8 (*start_io)(UNIT *uptr, uint16 chan); - /* Start a command */ - uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd); - /* Stop I/O */ - uint8 (*halt_io)(UNIT *uptr); - UNIT *units; /* Pointer to units structure */ - void (*dev_ini)(UNIT *, t_bool); /* init function */ - uint8 dev_addr; /* Device address */ - uint8 dev_class; /* Device class */ + /* Pre Start I/O */ + uint8 (*pre_io)(UNIT *uptr, uint16 chan); + /* Start a command */ + uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd); + /* Halt I/O */ + uint8 (*halt_io)(UNIT *uptr); + /* Test I/O */ + uint8 (*test_io)(UNIT *uptr); + /* Post I/O */ + uint8 (*post_io)(UNIT *uptr); + /* Controller init */ + void (*dev_ini)(UNIT *, t_bool); /* init function */ + UNIT *units; /* Pointer to units structure */ + CHANP *chan_prg; /* Pointer to channel program */ + uint8 numunits; /* number of units */ + uint8 mask; /* device mask */ + uint16 chan_addr; /* parent channel address */ + uint32 chan_fifo_in; /* fifo input index */ + uint32 chan_fifo_out; /* fifo output index */ + uint32 chan_fifo[FIFO_SIZE]; /* interrupt status fifo for each channel */ } DIB; /* CHAN 0x7F000000 UNIT 0x00ff0000 */ -#define DEV_V_ADDR DEV_V_UF /* Pointer to device address (16) */ -#define DEV_V_DADDR (DEV_V_UF + 8) /* Device address */ -#define DEV_ADDR_MASK (0x7f << DEV_V_DADDR) /* 24 bits shift */ -#define DEV_V_UADDR (DEV_V_UF) /* Device address in Unit */ +#define DEV_V_ADDR DEV_V_UF /* Pointer to device address (16) */ +#define DEV_V_DADDR (DEV_V_UF + 8) /* Device address */ +#define DEV_ADDR_MASK (0x7f << DEV_V_DADDR) /* 24 bits shift */ +#define DEV_V_UADDR (DEV_V_UF) /* Device address in Unit */ #define DEV_UADDR (1 << DEV_V_UADDR) #define GET_DADDR(x) (0x7f & ((x) >> DEV_V_ADDR)) #define DEV_ADDR(x) ((x) << DEV_V_ADDR) @@ -474,29 +491,35 @@ typedef struct dib { #define UNIT_ADDR(x) ((x) << UNIT_V_ADDR) #endif -//struct dib mta_dib = { 0xF8, NUM_UNITS_MT, NULL, mt_startcmd, NULL, mta_unit, mt_ini}; +/* channel program information */ +CHANP mta_chp[NUM_UNITS_MT] = {0}; -struct dib mta_dib = { - 0xFF, /* uint8 mask */ /* 256 devices - device mask */ - NUM_UNITS_MT, /* uint8 numunits */ /* number of units defined */ - NULL, /* uint8 (*start_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */ - mt_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ - NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ - mta_unit, /* UNIT* units */ /* Pointer to units structure */ - mt_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ - 0, /* uint8 dev_addr */ /* Device address */ - 0, /* uint8 dev_class */ /* Device class */ +//DIB mta_dib = {NULL, mt_startcmd, NULL, NULL, mt_ini, mta_unit, mta_chp, NUM_UNITS_MT, 0x0f, 0x1000, 0,0,0}; +DIB mta_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + mt_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + mt_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + mta_unit, /* UNIT* units */ /* Pointer to units structure */ + mta_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_MT, /* uint8 numunits */ /* number of units defined */ + 0xFF, /* uint8 mask */ /* 256 devices - device mask */ + 0x1000, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ }; -DEVICE mta_dev = { +DEVICE mta_dev = { #if 0 "MTA", mta_unit, NULL, mt_mod, -// NUM_UNITS_MT, 8, 15, 1, 8, 8, NUM_UNITS_MT, 16, 24, 4, 16, 32, NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach, &mta_dib, DEV_BUF_NUM(0) | DEV_DISABLE | DEV_DEBUG, 0, dev_debug #endif - "MTA", /* cchar *name */ /* device name */ + "MTA", /* char *name */ /* device name */ mta_unit, /* UNIT *units */ /* unit array */ NULL, /* REG *registers */ /* register array */ mt_mod, /* MTAB *modifiers */ /* modifier array */ @@ -521,12 +544,15 @@ DEVICE mta_dev = { NULL, /* t_stat (*help) */ /* help function */ NULL, /* t_stat (*attach_help) */ /* attach help function */ NULL, /* void *help_ctx */ /* Context available to help routines */ - NULL, /* cchar *(*description) */ /* Device description */ - NULL, /* BRKTYPTB *brk_types */ /* Breakpoint types */ + NULL, /* cchar *(*description) */ /* Device description */ + NULL, /* BRKTYPTB *brk_types */ /* Breakpoint types */ }; #if NUM_DEVS_MT > 1 -UNIT mtb_unit[] = { +/* channel program information */ +CHANP mtb_chp[NUM_UNITS_MT] = {0}; + +UNIT mtb_unit[] = { {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1800)}, /* 0 */ {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1801)}, /* 1 */ {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1802)}, /* 2 */ @@ -537,321 +563,280 @@ UNIT mtb_unit[] = { {UDATA(&mt_srv, UNIT_MT, 0), 0, UNIT_ADDR(0x1807)}, /* 7 */ }; -struct dib mtb_dib = { 0xF8, NUM_UNITS_MT, NULL, mt_startcmd, NULL, mtb_unit, mt_ini}; +/* device information block */ +//DIB mtb_dib = { NULL, mt_startcmd, NULL, NULL, mt_ini, mtb_unit, mtb_chp, NUM_UNITS_MT, 0x0f, 0x1800, 0, 0, 0}; +DIB mtb_dib = { + NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + mt_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + mt_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + mtb_unit, /* UNIT* units */ /* Pointer to units structure */ + mtb_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_MT, /* uint8 numunits */ /* number of units defined */ + 0xFF, /* uint8 mask */ /* 256 devices - device mask */ + 0x1000, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; -DEVICE mtb_dev = { +DEVICE mtb_dev = { "MTB", mtb_unit, NULL, mt_mod, NUM_UNITS_MT, 8, 15, 1, 8, 8, NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach, &mtb_dib, DEV_BUF_NUM(1) | DEV_DISABLE | DEV_DEBUG, 0, dev_debug }; #endif - -uint8 parity_table[64] = { - /* 0 1 2 3 4 5 6 7 */ - 0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100, - 0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000, - 0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000, - 0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100, - 0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000, - 0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100, - 0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100, - 0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000 -}; - -uint8 bcd_to_ebcdic[64] = { - 0x40, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xf0, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x7a, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xe0, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x60, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xd0, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x50, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xc0, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}; - /* start an I/O operation */ -uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { - uint16 addr = GET_UADDR(uptr->u3); - DEVICE *dptr = find_dev_from_unit(uptr); - int unit = (uptr - dptr->units); - uint8 ch; +uint8 mt_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); -fprintf(stderr, "mt_startcmd chan %0.4x cmd %x\r\n", chan, cmd); + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd entry chan %x cmd %x\n", chan, cmd); if (mt_busy[GET_DEV_BUF(dptr->flags)] != 0 || (uptr->u3 & MT_CMDMSK) != 0) { - sim_debug(DEBUG_CMD, dptr, "CMD busy unit=%d %x\n", unit, cmd); - uptr->flags |= MT_BUSY; /* Flag we need to send CUE */ -// mt_busy[GET_DEV_BUF(dptr->flags)] |= 2; -fprintf(stderr, "mt_startcmd busy chan %0.4x cmd %x\r\n", chan, cmd); + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd busy chan %d cmd %x\n", chan, cmd); + uptr->flags |= MT_BUSY; /* Flag we need to send CUE */ return SNS_BSY; } -fprintf(stderr, "mt_startcmd processing chan %0.4x cmd %x\r\n", chan, cmd); - sim_debug(DEBUG_CMD, dptr, "CMD unit=%d %x\n", unit, cmd); + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd processing unit %x cmd %x\n", unit, cmd); - switch (cmd & 0xF) { - case 0x7: /* Tape motion */ - case 0xf: /* Tape motion */ - case 0x1: /* Write command */ - case 0x2: /* Read command */ - case 0xc: /* Read backward */ - uptr->u5 = 0; - uptr->u5 |= SNS_TUASTA << 8; - if ((uptr->flags & MTUF_9TR) == 0) - uptr->u5 |= (SNS_7TRACK << 8); - if (sim_tape_wrp(uptr)) - uptr->u5 |= (SNS_WRP << 8); - if (sim_tape_bot(uptr)) - uptr->u5 |= (SNS_LOAD << 8); - /* Fall through */ + switch (cmd & 0xF) { + case 0x0: /* INCH command */ + /* u4 has INCH buffer address and us9 the count */ + /* just return OK and channel software will use u4 as status buffer */ + return SNS_CHNEND|SNS_DEVEND; + break; - case 0x4: /* Sense */ - uptr->u3 &= ~(MT_CMDMSK); - uptr->u3 |= cmd & MT_CMDMSK; - sim_activate(uptr, 1000); /* Start unit off */ - CLR_BUF(uptr); - uptr->u4 = 0; - uptr->u6 = 0; - mt_busy[GET_DEV_BUF(dptr->flags)] = 1; - if ((cmd & 0x7) == 0x7) { /* Quick end channel on control */ -// if ((cmd & 0x30) == 0) { - // mt_busy[GET_DEV_BUF(dptr->flags)] = 0; - // } -fprintf(stderr, "mt_startcmd ret CHNEND chan %0.4x cmd %x\r\n", chan, cmd); - return SNS_CHNEND; - } -fprintf(stderr, "mt_startcmd ret 0 chan %0.4x cmd %x\r\n", chan, cmd); - return 0; + case 0x3: /* Tape motion commands */ + if (cmd == MT_NOP) { /* nop */ + return SNS_CHNEND|SNS_DEVEND; /* done doing nothing */ + } + /* fall through */ + case 0x1: /* Write command */ + case 0x2: /* Read command */ + case 0xc: /* Read backward */ + uptr->u5 = (uptr->u5 & 0x0000ff00); /* clear all but byte 2 */ + uptr->u5 |= (SNS_RDY|SNS_ONLN); /* set ready status */ + if (sim_tape_wrp(uptr)) + uptr->u5 |= (SNS_WRP); /* write protected */ + if (sim_tape_bot(uptr)) + uptr->u5 |= (SNS_LOAD); /* tape at load point */ + if (sim_tape_eot(uptr)) { +// fprintf(stderr, "mt_startcmd EOT "); + uptr->u5 |= (SNS_EOT); /* tape at EOM */ + } + /* Fall through */ - case 0x3: /* Control */ - case 0xb: /* Control */ - if ((uptr->flags & MTUF_9TR) == 0) { - uptr->u5 |= (SNS_7TRACK << 8); - if ((cmd & 0xc0) == 0xc0) { - uptr->u5 |= SNS_CMDREJ; - return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; - } - switch((cmd >> 3) & 07) { - case 0: /* NOP */ - case 1: /* Diagnostics */ - case 3: - return SNS_CHNEND|SNS_DEVEND ; - case 2: /* Reset condition */ - uptr->u3 &= ~(MT_ODD|MT_TRANS|MT_CONV|MT_MDEN_MSK); - uptr->u3 |= (cmd & MT_MDEN_MSK) | MT_ODD | MT_CONV; - break; - case 4: - uptr->u3 &= ~(MT_ODD|MT_TRANS|MT_CONV|MT_MDEN_MSK); - uptr->u3 |= (cmd & MT_MDEN_MSK); - break; - case 5: - uptr->u3 &= ~(MT_ODD|MT_TRANS|MT_CONV|MT_MDEN_MSK); - uptr->u3 |= (cmd & MT_MDEN_MSK) | MT_TRANS; - break; - case 6: - uptr->u3 &= ~(MT_ODD|MT_TRANS|MT_CONV|MT_MDEN_MSK); - uptr->u3 |= (cmd & MT_MDEN_MSK) | MT_ODD; - break; - case 7: - uptr->u3 &= ~(MT_ODD|MT_TRANS|MT_CONV|MT_MDEN_MSK); - uptr->u3 |= (cmd & MT_MDEN_MSK) | MT_ODD | MT_TRANS; - break; - } - } else { -// if ((cmd & 0xf0) != 0xc0) { - // uptr->u5 |= SNS_CMDREJ; - // } - uptr->u3 &= ~MT_MDEN_MSK; - if (cmd & 0x8) - uptr->u3 |= MT_MDEN_800; /* NRZI */ - else - uptr->u3 |= MT_MDEN_1600; /* PE */ -/* else /* FIXME */ -// uptr->u3 |= MT_MDEN_6250; /* GCR */ - } - uptr->u5 = 0; - break; + case 0x4: /* Sense */ + uptr->u3 &= ~(MT_CMDMSK); /* clear out last cmd */ + uptr->u3 |= cmd & MT_CMDMSK; /* insert new cmd */ + sim_activate(uptr, 100); /* Start unit off */ + CLR_BUF(uptr); /* buffer is empty */ + uptr->u4 = 0; /* reset buffer position pointer */ + mt_busy[GET_DEV_BUF(dptr->flags)] = 1; /* show we are busy */ + if ((cmd & 0x3) == 0x3) { /* Quick end channel on control */ + if (cmd != MT_SETM) { /* mode set command */ + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd ret CHNEND chan %x unit %x cmd %x\n", chan, unit, cmd); + return SNS_CHNEND; + } + } + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd return 0 chan %x cmd %x\n", chan, cmd); + return 0; - case 0x0: /* INCH command */ - break; - - default: /* invalid command */ - uptr->u5 |= SNS_CMDREJ; - break; - } - if (uptr->u5 & 0xff) - return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; -fprintf(stderr, "mt_startcmd ret CHNEND DEVEND chan %0.4x cmd %x\r\n", chan, cmd); - return SNS_CHNEND|SNS_DEVEND; + default: /* invalid command */ + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd CMDREJ return chan %d cmd %x\n", chan, cmd); + uptr->u5 |= SNS_CMDREJ; + break; + } + if (uptr->u5 & 0xff000000) /* errors? */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + sim_debug(DEBUG_EXP, &mta_dev, "mt_startcmd ret CHNEND|DEVEND chan %d unit %x cmd %x\n", chan, unit, cmd); + return SNS_CHNEND|SNS_DEVEND; } /* Map simH errors into machine errors */ t_stat mt_error(UNIT *uptr, uint16 addr, t_stat r, DEVICE *dptr) { -fprintf(stderr, "mt_error status %x\r\n", r); - mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1; - switch (r) { - case MTSE_OK: /* no error */ - break; + sim_debug(DEBUG_CMD, &mta_dev, "mt_error status %x\n", r); + mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1; /* not busy anymore */ - case MTSE_TMK: /* tape mark */ - sim_debug(DEBUG_EXP, dptr, "MARK "); - chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); - return SCPE_OK; + switch (r) { /* switch on return value */ + case MTSE_OK: /* no error */ + break; - case MTSE_WRP: /* write protected */ - case MTSE_UNATT: /* unattached */ - sim_debug(DEBUG_EXP, dptr, "ATTENTION %d ", r); - break; + case MTSE_TMK: /* tape mark */ + sim_debug(DEBUG_CMD, &mta_dev, "mt_error FILE MARK\n"); + uptr->u5 |= SNS_FMRKDT; /* file mark detected */ + break; - case MTSE_IOERR: /* IO error */ - case MTSE_FMT: /* invalid format */ - case MTSE_RECE: /* error in record */ - sim_debug(DEBUG_EXP, dptr, "ERROR %d ", r); - break; - case MTSE_BOT: /* beginning of tape */ - sim_debug(DEBUG_EXP, dptr, "BOT "); - break; - case MTSE_INVRL: /* invalid rec lnt */ - case MTSE_EOM: /* end of medium */ - sim_debug(DEBUG_EXP, dptr, "EOT "); - break; - } - chan_end(addr, SNS_CHNEND|SNS_DEVEND); - return SCPE_OK; + case MTSE_WRP: /* write protected */ + uptr->u5 |= SNS_WRP; /* write protected */ + sim_debug(DEBUG_CMD, &mta_dev, "WRITE PROTECT %d ", r); /* operator intervention */ + break; + + case MTSE_UNATT: /* unattached */ + uptr->u5 |= SNS_INTVENT; /* unit intervention required */ + sim_debug(DEBUG_CMD, &mta_dev, "ATTENTION %d ", r); /* operator intervention */ + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); + break; + + case MTSE_IOERR: /* IO error */ + case MTSE_FMT: /* invalid format */ + case MTSE_RECE: /* error in record */ + sim_debug(DEBUG_CMD, &mta_dev, "ERROR %d ", r); + break; + + case MTSE_BOT: /* beginning of tape */ + uptr->u5 |= SNS_LOAD; /* tape at BOT */ + sim_debug(DEBUG_CMD, &mta_dev, "BOT "); + break; + + case MTSE_INVRL: /* invalid rec lnt */ + case MTSE_EOM: /* end of medium */ + uptr->u5 |= SNS_EOT; /* tape at EOT */ + sim_debug(DEBUG_CMD, &mta_dev, "EOT "); + break; + } + chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* we are done with command */ + return SCPE_OK; } /* Handle processing of tape requests. */ t_stat mt_srv(UNIT * uptr) { - uint16 addr = GET_UADDR(uptr->u3); - DEVICE *dptr = find_dev_from_unit(uptr); - int unit = (uptr - dptr->units); - int cmd = uptr->u3 & MT_CMDMSK; - int bufnum = GET_DEV_BUF(dptr->flags); - t_mtrlnt reclen; - t_stat r = SCPE_ARG; /* Force error if not set */ - uint8 ch; - int mode = 0; + uint16 addr = GET_UADDR(uptr->u3); + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + int cmd = uptr->u3 & MT_CMDMSK; + int bufnum = GET_DEV_BUF(dptr->flags); + t_mtrlnt reclen; + t_stat r = SCPE_ARG; /* Force error if not set */ + uint8 ch; -fprintf(stderr, "mt_srv unit %d\r\n", unit); - if ((uptr->flags & UNIT_ATT) == 0) { - uptr->u5 |= SNS_INTVENT; - if (cmd != MT_SENSE) - return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; - } + sim_debug(DEBUG_DATA, &mta_dev, "mt_srv unit %d cmd %x\n", unit, cmd); + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + uptr->u5 |= SNS_INTVENT; /* unit intervention required */ + if (cmd != MT_SENSE) /* we are completed with unit check status */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + } - switch (cmd) { - case 0: /* No command, stop tape */ - sim_debug(DEBUG_DETAIL, dptr, "Idle unit=%d\n", unit); - break; + switch (cmd) { + case MT_INCH: /* 0x00 */ /* INCH is for channel, nothing for us */ + sim_debug(DEBUG_CMD, &mta_dev, "mt_srv cmd 0 INCH unit=%d\n", unit); + //NEWCODE follows, but not ever executed! + uptr->u3 &= ~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; - case MT_SENSE: - ch = uptr->u5 & 0xff; - sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 1 %x\n", unit, ch); - chan_write_byte(addr, &ch) ; - ch = (uptr->u5 >> 8) & 0xff; - sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 2 %x\n", unit, ch); - chan_write_byte(addr, &ch) ; - ch = 0xc0; - sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 3 %x\n", unit, ch); - chan_write_byte(addr, &ch) ; - ch = (uptr->u5 >> 16) & 0xff; - sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 4 %x\n", unit, ch); - chan_write_byte(addr, &ch) ; - ch = 0; - chan_write_byte(addr, &ch) ; - chan_write_byte(addr, &ch); - uptr->u3 &= ~MT_CMDMSK; - mt_busy[bufnum] &= ~1; - chan_end(addr, SNS_CHNEND|SNS_DEVEND); - break; + case MT_SENSE: /* 0x04 */ /* get sense data */ + sim_debug(DEBUG_CMD, &mta_dev, "mt_srv cmd 4 SENSE unit=%d\n", unit); + ch = (uptr->u5 >> 24) & 0xff; /* get sense byte 0 status */ + sim_debug(DEBUG_DETAIL, &mta_dev, "sense unit %d byte 0 %x\n", unit, ch); + chan_write_byte(addr, &ch); /* write byte 0 */ + ch = (uptr->u5 >> 16) & 0xff; /* get sense byte 1 status */ + sim_debug(DEBUG_DETAIL, &mta_dev, "sense unit %d byte 1 %x\n", unit, ch); + chan_write_byte(addr, &ch); /* write byte 1 */ + ch = (uptr->u5 >> 8) & 0xff; /* get sense byte 2 status */ + sim_debug(DEBUG_DETAIL, &mta_dev, "sense unit %d byte 2 %x\n", unit, ch); + chan_write_byte(addr, &ch); /* write byte 2 */ + ch = (uptr->u5 >> 0) & 0xff; /* get sense byte 3 status */ + sim_debug(DEBUG_DETAIL, &mta_dev, "sense unit %d byte 3 %x\n", unit, ch); + chan_write_byte(addr, &ch); /* write byte 3 */ + ch = 4; + uptr->u3 &= ~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; - case MT_READ: + case MT_READ: /* 0x02 */ /* read a record from the device */ + sim_debug(DEBUG_DATA, &mta_dev, "mt_srv cmd 2 READ unit=%d\n", unit); + if (uptr->u3 & MT_READDONE) { /* is the read complete */ + uptr->u5 &= ~(SNS_LOAD|SNS_EOT); /* reset BOT & EOT */ + if (sim_tape_eot(uptr)) { /* see if at EOM */ + uptr->u5 |= SNS_EOT; /* set EOT status */ + } + uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); /* clear all but readdone & cmd */ + mt_busy[bufnum] &= ~1; /* not busy anymore */ + sim_debug(DEBUG_CMD, &mta_dev, "mt_srv READ %x char complete unit=%d\n", uptr->u4, unit); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* set chan end, dev end status */ + break; + } + /* read is not completed, get an input char */ + /* If empty buffer, fill */ + if (BUF_EMPTY(uptr)) { + /* buffer is empty, so fill it with next record data */ + if ((r = sim_tape_rdrecf(uptr, &mt_buffer[bufnum][0], &reclen, BUFFSIZE)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, &mta_dev, "mt_srv READ fill buffer unit=%d\n", unit); + uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); /* clear all but readdone & cmd */ + return mt_error(uptr, addr, r, dptr); /* process any error & return status */ + } + uptr->u4 = 0; /* reset buffer position */ + uptr->hwmark = reclen; /* set buffer chars read in */ + sim_debug(DEBUG_DETAIL, &mta_dev, "mt_srv READ fill buffer complete count %x\n", reclen); + } + /* get a char from the buffer */ + ch = mt_buffer[bufnum][uptr->u4++]; - if (uptr->u3 & MT_READDONE) { - uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); - mt_busy[bufnum] &= ~1; - chan_end(addr, SNS_CHNEND|SNS_DEVEND); - break; - } + /* Send character over to channel */ + if (chan_write_byte(addr, &ch)) { + sim_debug(DEBUG_CMD, &mta_dev, "Read unit %d EOR\n", unit); + /* If not read whole record, skip till end */ + if (uptr->u4 < uptr->hwmark) { + /* Send dummy character to force SLI */ + chan_write_byte(addr, &ch); /* write the byte */ + sim_debug(DEBUG_CMD, &mta_dev, "Read unit %d send dump SLI\n", unit); + sim_activate(uptr, (uptr->hwmark-uptr->u4) * 20); /* wait again */ + uptr->u3 |= MT_READDONE; /* read is done */ + break; + } + sim_debug(DEBUG_CMD, &mta_dev, + "Read data @1 unit %d cnt %x ch %02x hwm %x\n", unit, uptr->u4, ch, uptr->hwmark); + uptr->u3 &= ~MT_CMDMSK; /* clear the cmd */ + mt_busy[bufnum] &= ~1; /* set not busy */ + chan_end(addr, SNS_DEVEND); /* return end status */ + } else { + sim_debug(DEBUG_DATA, &mta_dev, + "Read data @2 unit %d cnt %x ch %02x hwm %x\n", unit, uptr->u4, ch, uptr->hwmark); + if (uptr->u4 >= uptr->hwmark) { /* In IRG */ + /* Handle end of record */ + uptr->u3 &= ~MT_CMDMSK; /* clear the cmd */ + mt_busy[bufnum] &= ~1; /* set not busy */ + chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* return end status */ + } else + sim_activate(uptr, 20); /* wait again */ + } + break; - /* If empty buffer, fill */ - if (BUF_EMPTY(uptr)) { - sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d ", unit); - if ((r = sim_tape_rdrecf(uptr, &mt_buffer[bufnum][0], &reclen, - BUFFSIZE)) != MTSE_OK) { - uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); - return mt_error(uptr, addr, r, dptr); - } - uptr->u4 = 0; - uptr->hwmark = reclen; - sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); - } + case MT_SETM: /* 0x83 */ /* set mode byte */ + sim_debug(DEBUG_CMD, &mta_dev, "mt_srv cmd 0x83 SETM unit=%d\n", unit); + /* Grab data until channel has no more */ + if (chan_read_byte(addr, &ch)) { + if (uptr->u4 > 0) { /* Only if data in record */ + reclen = uptr->hwmark; /* set record length */ + ch = mt_buffer[bufnum][0]; /* get the first byte read */ + sim_debug(DEBUG_CMD, &mta_dev, "Write mode data done unit %d chars %d char %x\n", unit, reclen, ch); + /* put mode bits into byte 2 of u5 */ + uptr->u5 = (uptr->u5 & 0xffff00ff) | (ch << 8); + uptr->u4 = 0; /* no bytes anymore */ + uptr->u3 &= ~MT_CMDMSK; /* no cmd to do */ + mt_busy[bufnum] &= ~1; /* set not busy */ + chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* return end status */ + } + } else { + mt_buffer[bufnum][uptr->u4++] = ch; /* save the character read in */ + sim_debug(DEBUG_CMD, &mta_dev, "Write mode data in unit %d u4 %d ch %0x\n", unit, uptr->u4, ch); + uptr->hwmark = uptr->u4; /* set high water mark */ + sim_activate(uptr, 20); /* wait time */ + } + break; - ch = mt_buffer[bufnum][uptr->u4++]; - /* if we are a 7track tape, handle conversion */ - if ((uptr->flags & MTUF_9TR) == 0) { - mode = (uptr->u3 & MT_ODD) ? 0 : 0100; - if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { - sim_debug(DEBUG_DETAIL, dptr, "Parity error unit=%d %d %03o\n", - unit, uptr->u4-1, ch); - uptr->u5 |= (SNS_VRC << 16) | SNS_DATCHK; - } - ch &= 077; - if (uptr->u3 & MT_TRANS) - ch = bcd_to_ebcdic[ch]; - if (uptr->u3 & MT_CONV) { - sim_debug(DEBUG_DATA, dptr, "Read raw data unit=%d %d %02x %02x\n", - unit, uptr->u4, ch, uptr->u6); - if (uptr->u6 == 0 && uptr->u4 < uptr->hwmark) { - uptr->u6 = MT_CONV1 | ch; - sim_activate(uptr, 20); - return SCPE_OK; - } else if ((uptr->u6 & 0xc0) == MT_CONV1) { - int t = uptr->u6 & 0x3F; - uptr->u6 = MT_CONV2 | ch; - ch = (t << 2) | ((ch >> 4) & 03); - } else if ((uptr->u6 & 0xc0) == MT_CONV2) { - int t = uptr->u6 & 0xf; - uptr->u6 = MT_CONV3 | ch; - ch = (t << 4) | ((ch >> 2) & 0xf); - } else if ((uptr->u6 & 0xc0) == MT_CONV3) { - ch |= ((uptr->u6 & 0x3) << 6); - uptr->u6 = 0; - } - } - } - - /* Send character over to channel */ - if (chan_write_byte(addr, &ch)) { - sim_debug(DEBUG_DATA, dptr, "Read unit=%d EOR\n\r", unit); - /* If not read whole record, skip till end */ - if (uptr->u4 < uptr->hwmark) { - /* Send dummy character to force SLI */ - chan_write_byte(addr, &ch); - sim_activate(uptr, (uptr->hwmark-uptr->u4) * 20); - uptr->u3 |= MT_READDONE; - break; - } - uptr->u3 &= ~MT_CMDMSK; - mt_busy[bufnum] &= ~1; - chan_end(addr, SNS_DEVEND); - } else { - sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %02x\n\r", - unit, uptr->u4, ch); - if (uptr->u4 >= uptr->hwmark) { /* In IRG */ - /* Handle end of record */ - uptr->u3 &= ~MT_CMDMSK; - mt_busy[bufnum] &= ~1; - chan_end(addr, SNS_CHNEND|SNS_DEVEND); - } else - sim_activate(uptr, 20); - } - break; - - - case MT_WRITE: + case MT_WRITE: /* 0x01 */ /* write record */ /* Check if write protected */ if (sim_tape_wrp(uptr)) { uptr->u5 |= SNS_CMDREJ; @@ -863,51 +848,24 @@ fprintf(stderr, "mt_srv unit %d\r\n", unit); /* Grab data until channel has no more */ if (chan_read_byte(addr, &ch)) { - if (uptr->u4 > 0) { /* Only if data in record */ + if (uptr->u4 > 0) { /* Only if data in record */ reclen = uptr->hwmark; - sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d chars\n", - unit, reclen); + sim_debug(DEBUG_DETAIL, &mta_dev, "Write unit=%d Block %d chars\n", unit, reclen); r = sim_tape_wrrecf(uptr, &mt_buffer[bufnum][0], reclen); uptr->u4 = 0; uptr->u3 &= ~MT_CMDMSK; - mt_error(uptr, addr, r, dptr); /* Record errors */ - } else { - uptr->u5 |= SNS_WCZERO; /* Write with no data */ + mt_error(uptr, addr, r, dptr); /* Record errors */ } - } else { - if ((uptr->flags & MTUF_9TR) == 0) { - mode = (uptr->u3 & MT_ODD) ? 0 : 0100; - if (uptr->u3 & MT_TRANS) - ch = (ch & 0xf) | ((ch & 0x30) ^ 0x30); - if (uptr->u3 & MT_CONV) { - if (uptr->u6 == 0) { - uptr->u6 = MT_CONV1 | (ch & 0x3); - ch >>= 2; - } else if ((uptr->u6 & 0xc0) == MT_CONV1) { - int t = uptr->u6 & 0x3; - uptr->u6 = MT_CONV2 | (ch & 0xf); - ch = (t << 4) | ((ch >> 4) & 0xf); - } else if ((uptr->u6 & 0xc0) == MT_CONV2) { - int t = uptr->u6 & 0xf; - ch = (t << 2) | ((ch >> 6) & 0x3); - ch ^= parity_table[ch & 077] ^ mode; - mt_buffer[bufnum][uptr->u4++] = ch; - uptr->u6 = 0; - } - } - ch &= 077; - ch |= parity_table[ch] ^ mode; - } - mt_buffer[bufnum][uptr->u4++] = ch; - sim_debug(DEBUG_DATA, dptr, "Write data unit=%d %d %02o\n\r", - unit, uptr->u4, ch); - uptr->hwmark = uptr->u4; - break; - } - sim_activate(uptr, 20); - break; + } else { + mt_buffer[bufnum][uptr->u4++] = ch; + sim_debug(DEBUG_DATA, &mta_dev, "Write data unit=%d %d %02o\n", unit, uptr->u4, ch); + uptr->hwmark = uptr->u4; + break; + } + sim_activate(uptr, 20); + break; - case MT_RDBK: + case MT_RDBK: /* 0x0C */ /* Read Backwards */ if (uptr->u3 & MT_READDONE) { uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); mt_busy[bufnum] &= ~1; @@ -917,54 +875,26 @@ fprintf(stderr, "mt_srv unit %d\r\n", unit); /* If at end of record, fill buffer */ if (BUF_EMPTY(uptr)) { - if (sim_tape_bot(uptr)) { - uptr->u3 &= ~MT_CMDMSK; - mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1; - chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); - return SCPE_OK; - } - sim_debug(DEBUG_DETAIL, dptr, "Read backward unit=%d ", unit); - if ((r = sim_tape_rdrecr(uptr, &mt_buffer[bufnum][0], &reclen, - BUFFSIZE)) != MTSE_OK) { - uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); - return mt_error(uptr, addr, r, dptr); - } - uptr->u4 = reclen; - uptr->hwmark = reclen; - sim_debug(DEBUG_DETAIL, dptr, "Binary Block %d chars\n", reclen); + if (sim_tape_bot(uptr)) { + uptr->u3 &= ~MT_CMDMSK; + mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1; + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + return SCPE_OK; + } + sim_debug(DEBUG_DETAIL, &mta_dev, "Read backward unit=%d\n", unit); + if ((r = sim_tape_rdrecr(uptr, &mt_buffer[bufnum][0], &reclen, BUFFSIZE)) != MTSE_OK) { + uptr->u3 &= ~(MT_CMDMSK|MT_READDONE); + return mt_error(uptr, addr, r, dptr); + } + uptr->u4 = reclen; + uptr->hwmark = reclen; + sim_debug(DEBUG_DETAIL, &mta_dev, "Binary Block %d chars\n", reclen); } ch = mt_buffer[bufnum][--uptr->u4]; - if ((uptr->flags & MTUF_9TR) == 0) { - mode = (uptr->u3 & MT_ODD) ? 0 : 0100; - ch &= 077; - if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { - uptr->u5 |= (SNS_VRC << 16) | SNS_DATCHK; - } - if (uptr->u3 & MT_TRANS) - ch = bcd_to_ebcdic[ch]; - if (uptr->u3 & MT_CONV) { - if (uptr->u6 == 0 && uptr->u4 < uptr->hwmark) { - uptr->u6 = MT_CONV1 | ch; - sim_activate(uptr, 20); - return SCPE_OK; - } else if ((uptr->u6 & 0xc0) == MT_CONV1) { - int t = uptr->u6 & 0x3F; - uptr->u6 = MT_CONV2 | ch; - ch = t | ((ch << 6) & 0xc0); - } else if ((uptr->u6 & 0xc0) == MT_CONV2) { - int t = uptr->u6 & 0x3C; - uptr->u6 = MT_CONV3 | ch; - ch = (t >> 2) | ((ch << 4) & 0xf0); - } else if ((uptr->u6 & 0xc0) == MT_CONV3) { - ch |= ((uptr->u6 & 0x30) >> 4); - uptr->u6 = 0; - } - } - } if (chan_write_byte(addr, &ch)) { - sim_debug(DEBUG_DATA, dptr, "Read unit=%d EOR\n\r", unit); + sim_debug(DEBUG_DATA, &mta_dev, "Read unit=%d EOR\n", unit); /* If not read whole record, skip till end */ if (uptr->u4 >= 0) { sim_activate(uptr, (uptr->u4) * 20); @@ -975,8 +905,7 @@ fprintf(stderr, "mt_srv unit %d\r\n", unit); mt_busy[bufnum] &= ~1; chan_end(addr, SNS_CHNEND|SNS_DEVEND); } else { - sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %02o\n\r", - unit, uptr->u4, ch); + sim_debug(DEBUG_DATA, &mta_dev, "Read data unit=%d %d %02o\n", unit, uptr->u4, ch); if (uptr->u4 == 0) { /* In IRG */ uptr->u3 &= ~MT_CMDMSK; mt_busy[bufnum] &= ~1; @@ -986,21 +915,19 @@ fprintf(stderr, "mt_srv unit %d\r\n", unit); } break; - case MT_WTM: + case MT_WTM: /* 0x93 */ /* Write tape filemark */ if (uptr->u4 == 0) { if (sim_tape_wrp(uptr)) { uptr->u5 |= SNS_CMDREJ; uptr->u3 &= ~MT_CMDMSK; mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1; - set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); -// chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); return SCPE_OK; } uptr->u4 ++; sim_activate(uptr, 500); - // chan_end(addr, SNS_CHNEND); } else { - sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit); + sim_debug(DEBUG_DETAIL, &mta_dev, "Write Mark unit=%d\n", unit); uptr->u3 &= ~(MT_CMDMSK); r = sim_tape_wrtmk(uptr); set_devattn(addr, SNS_DEVEND); @@ -1008,183 +935,180 @@ fprintf(stderr, "mt_srv unit %d\r\n", unit); } break; - case MT_BSR: + case MT_BSR: /* 0x53 */ /* Backspace record */ + sim_debug(DEBUG_DETAIL, &mta_dev, "mt_srv cmd 0x53 BSR unit %d u4 %x\n", unit, uptr->u4); switch (uptr->u4 ) { case 0: if (sim_tape_bot(uptr)) { uptr->u3 &= ~MT_CMDMSK; mt_busy[GET_DEV_BUF(dptr->flags)] &= ~1; - set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); -// chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); return SCPE_OK; } uptr->u4 ++; - sim_activate(uptr, 500); -// chan_end(addr, SNS_CHNEND); + sim_activate(uptr, 50); break; case 1: - uptr->u4++; - sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit); - r = sim_tape_sprecr(uptr, &reclen); - /* We don't set EOF on BSR */ - if (r == MTSE_TMK) { - uptr->u4++; - sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); + uptr->u4++; + sim_debug(DEBUG_DETAIL, &mta_dev, "Backspace rec unit %x u4 %x\n", unit, uptr->u4); + r = sim_tape_sprecr(uptr, &reclen); + /* We don't set EOF on BSR */ + if (r == MTSE_TMK) { + uptr->u4++; + sim_debug(DEBUG_DETAIL, &mta_dev, "MARK\n"); + sim_activate(uptr, 50); + } else { + sim_debug(DEBUG_DETAIL, &mta_dev, "reclen %x\n", reclen); +// sim_activate(uptr, 10 + (10 * reclen)); sim_activate(uptr, 50); - } else { - sim_debug(DEBUG_DETAIL, dptr, "%d \n", reclen); - sim_activate(uptr, 10 + (10 * reclen)); } break; case 2: uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND); + chan_end(addr, SNS_CHNEND); mt_busy[bufnum] &= ~1; break; case 3: uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND|SNS_UNITEXP); + chan_end(addr, SNS_DEVEND|SNS_UNITEXP); mt_busy[bufnum] &= ~1; break; } break; - case MT_BSF: + case MT_BSF: /* 0x73 */ /* Backspace file */ + sim_debug(DEBUG_DETAIL, &mta_dev, "mt_srv cmd 0x73 BSF unit %d\n", unit); switch(uptr->u4) { case 0: if (sim_tape_bot(uptr)) { uptr->u3 &= ~MT_CMDMSK; mt_busy[bufnum] &= ~1; - set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); -// chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); break; } -// chan_end(addr, SNS_CHNEND); - uptr->u4 ++; + uptr->u4++; sim_activate(uptr, 500); break; case 1: - sim_debug(DEBUG_DETAIL, dptr, "Backspace file unit=%d\n", unit); + sim_debug(DEBUG_DETAIL, &mta_dev, "Backspace file unit=%d\n", unit); r = sim_tape_sprecr(uptr, &reclen); if (r == MTSE_TMK) { uptr->u4++; - sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); + sim_debug(DEBUG_DETAIL, &mta_dev, "MARK\n"); sim_activate(uptr, 50); } else if (r == MTSE_BOT) { uptr->u4+= 2; sim_activate(uptr, 50); } else { - sim_activate(uptr, 10 + (10 * reclen)); +// sim_activate(uptr, 10 + (10 * reclen)); + sim_activate(uptr, 20); } break; - case 2: + case 2: /* File Mark */ uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND|SNS_UNITEXP); + chan_end(addr, SNS_DEVEND); mt_busy[bufnum] &= ~1; break; - case 3: + case 3: /* BOT */ uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); + chan_end(addr, SNS_DEVEND); mt_busy[bufnum] &= ~1; break; } break; - case MT_FSR: + case MT_FSR: /* 0x43 */ /* Advance record */ switch(uptr->u4) { case 0: - uptr->u4 ++; + uptr->u4++; sim_activate(uptr, 500); - // chan_end(addr, SNS_CHNEND); break; case 1: uptr->u4++; - sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit); + sim_debug(DEBUG_DETAIL, &mta_dev, "Skip rec unit=%d ", unit); r = sim_tape_sprecf(uptr, &reclen); if (r == MTSE_TMK) { uptr->u4 = 3; - sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); + sim_debug(DEBUG_DETAIL, &mta_dev, "MARK\n"); sim_activate(uptr, 50); } else if (r == MTSE_EOM) { uptr->u4 = 4; sim_activate(uptr, 50); } else { - sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen); + sim_debug(DEBUG_DETAIL, &mta_dev, "%d\n", reclen); sim_activate(uptr, 10 + (10 * reclen)); } break; case 2: uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND); +// set_devattn(addr, SNS_DEVEND); + chan_end(addr, SNS_DEVEND); mt_busy[bufnum] &= ~1; break; case 3: uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND|SNS_UNITEXP); + chan_end(addr, SNS_DEVEND|SNS_UNITEXP); mt_busy[bufnum] &= ~1; break; case 4: uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); + chan_end(addr, SNS_DEVEND|SNS_UNITCHK); mt_busy[bufnum] &= ~1; break; } break; - case MT_FSF: - switch(uptr->u4) { - case 0: - uptr->u4 ++; - sim_activate(uptr, 500); -// chan_end(addr, SNS_CHNEND); - break; - case 1: - sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit); - r = sim_tape_sprecf(uptr, &reclen); - if (r == MTSE_TMK) { - uptr->u4++; - sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); - sim_activate(uptr, 50); - } else if (r == MTSE_EOM) { - uptr->u4+= 2; - sim_activate(uptr, 50); - } else { - sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen); - sim_activate(uptr, 10 + (10 * reclen)); - } - break; - case 2: - uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND); - mt_busy[bufnum] &= ~1; - sim_debug(DEBUG_DETAIL, dptr, "Skip done unit=%d\n", unit); - break; - case 3: - uptr->u3 &= ~(MT_CMDMSK); - set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); - mt_busy[bufnum] &= ~1; - break; - } - break; + case MT_FSF: /* 0x63 */ /* advance filemark */ + switch(uptr->u4) { + case 0: + uptr->u4 ++; + sim_activate(uptr, 500); + break; + case 1: + sim_debug(DEBUG_DETAIL, &mta_dev, "Skip rec unit=%d\n", unit); + r = sim_tape_sprecf(uptr, &reclen); + if (r == MTSE_TMK) { + uptr->u4++; + sim_debug(DEBUG_DETAIL, &mta_dev, "MARK\n"); + sim_activate(uptr, 50); + } else if (r == MTSE_EOM) { + uptr->u5 |= SNS_EOT; /* set EOT status */ + uptr->u4+= 2; + sim_activate(uptr, 50); + } else { + sim_debug(DEBUG_DETAIL, &mta_dev, "%d\n", reclen); + sim_activate(uptr, 10 + (10 * reclen)); + } + break; + case 2: + uptr->u3 &= ~(MT_CMDMSK); + chan_end(addr, SNS_DEVEND); + mt_busy[bufnum] &= ~1; + sim_debug(DEBUG_DETAIL, &mta_dev, "Skip done unit=%d\n", unit); + break; + case 3: + uptr->u3 &= ~(MT_CMDMSK); + chan_end(addr, SNS_DEVEND|SNS_UNITCHK); + mt_busy[bufnum] &= ~1; + break; + } + break; - - case MT_ERG: + case MT_ERG: /* 0xA3 */ /* Erace 3.5 in tape */ switch (uptr->u4) { case 0: if (sim_tape_wrp(uptr)) { uptr->u5 |= SNS_CMDREJ; uptr->u3 &= ~MT_CMDMSK; mt_busy[bufnum] &= ~1; -// chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); set_devattn(addr, SNS_DEVEND|SNS_UNITCHK); } else { uptr->u4 ++; sim_activate(uptr, 500); -// chan_end(addr, SNS_CHNEND); } break; case 1: - sim_debug(DEBUG_DETAIL, dptr, "Erase unit=%d\n", unit); + sim_debug(DEBUG_DETAIL, &mta_dev, "Erase unit=%d\n", unit); r = sim_tape_wrgap(uptr, 35); sim_activate(uptr, 5000); uptr->u4++; @@ -1196,74 +1120,76 @@ fprintf(stderr, "mt_srv unit %d\r\n", unit); } break; - case MT_REW: - if (uptr->u4 == 0) { - uptr->u4 ++; - sim_activate(uptr, 30000); -// chan_end(addr, SNS_CHNEND); - mt_busy[bufnum] &= ~1; - } else { - sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d\n", unit); - uptr->u3 &= ~(MT_CMDMSK); - r = sim_tape_rewind(uptr); - set_devattn(addr, SNS_DEVEND); + case MT_REW: /* 0x23 */ /* rewind tape */ + if (uptr->u4 == 0) { + uptr->u4 ++; + sim_activate(uptr, 30000); + mt_busy[bufnum] &= ~1; + } else { + sim_debug(DEBUG_DETAIL, &mta_dev, "Rewind unit=%d\n", unit); + uptr->u3 &= ~(MT_CMDMSK); + r = sim_tape_rewind(uptr); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); /* we are done dev|chan end */ + uptr->u5 |= SNS_LOAD; /* set BOT */ } break; - case MT_RUN: + case MT_RUN: /* 0x33 */ /* Rewind and unload tape */ if (uptr->u4 == 0) { uptr->u4 ++; mt_busy[bufnum] &= ~1; sim_activate(uptr, 30000); -// chan_end(addr, SNS_CHNEND); } else { - sim_debug(DEBUG_DETAIL, dptr, "Unload unit=%d\n", unit); + sim_debug(DEBUG_DETAIL, &mta_dev, "Unload unit=%d\n", unit); uptr->u3 &= ~(MT_CMDMSK); r = sim_tape_detach(uptr); } break; } - return SCPE_OK; + return SCPE_OK; } /* initialize the tape chan/unit */ void mt_ini(UNIT *uptr, t_bool f) { - DEVICE *dptr = find_dev_from_unit(uptr); + DEVICE *dptr = find_dev_from_unit(uptr); - uptr->u3 &= ~0xffff; /* clear out the flags but leave ch/sa */ - if ((uptr->flags & MTUF_9TR) == 0) /* if not 9 track tape, make 800 bpi */ - uptr->u3 |= MT_ODD|MT_CONV|MT_MDEN_800; /* set 800 bpi options */ - mt_busy[GET_DEV_BUF(dptr->flags)] = 0; /* set not busy */ -fprintf(stderr, "mt_int device %s unit %x\r\n", dptr->name, GET_UADDR(uptr->u3)); + uptr->u3 &= ~0xffff; /* clear out the flags but leave ch/sa */ + if ((uptr->flags & MTUF_9TR) == 0) /* if not 9 track tape, make 800 bpi */ + uptr->u3 |= MT_ODD|MT_CONV|MT_MDEN_800; /* set 800 bpi options */ + uptr->u5 = 0; /* clear sense data */ + uptr->u5 |= (SNS_RDY|SNS_ONLN|SNS_LOAD); /* set initial status */ + mt_busy[GET_DEV_BUF(dptr->flags)] = 0; /* set not busy */ + sim_debug(DEBUG_EXP, &mta_dev, "MT init device %s unit %x\n", dptr->name, GET_UADDR(uptr->u3)); } /* reset the mag tape */ t_stat mt_reset(DEVICE *dptr) { - /* nothing to do?? */ -fprintf(stderr, "mt_reset name %s\r\n", dptr->name); + /* nothing to do?? */ + sim_debug(DEBUG_EXP, &mta_dev, "MT reset name %s\n", dptr->name); return SCPE_OK; } /* attach the specified file to the tape device */ -t_stat mt_attach(UNIT * uptr, CONST char *file) +t_stat mt_attach(UNIT *uptr, CONST char *file) { - uint16 addr = GET_UADDR(uptr->u3); /* get address of mt device */ + uint16 addr = GET_UADDR(uptr->u3); /* get address of mt device */ t_stat r; -fprintf(stderr, "mt_attach1 filename %s\r\n", file); - if ((r = sim_tape_attach(uptr, file)) != SCPE_OK) /* mount the specified file to the MT */ - return r; /* report any error */ -fprintf(stderr, "mt_attach2 status %x\r\n", r); - set_devattn(addr, SNS_DEVEND); /* ready int???? */ - return SCPE_OK; /* return good status */ + if ((r = sim_tape_attach(uptr, file)) != SCPE_OK) { /* mount the specified file to the MT */ + sim_debug(DEBUG_EXP, &mta_dev, "mt_attach ERROR filename %s status %x\n", file, r); + return r; /* report any error */ + } + sim_debug(DEBUG_EXP, &mta_dev, "mt_attach complete filename %s\n", file); + set_devattn(addr, SNS_DEVEND); /* ready int???? */ + return SCPE_OK; /* return good status */ } /* detach the MT device and unload any tape */ t_stat mt_detach(UNIT *uptr) { -fprintf(stderr, "mt_detach MT\r\n"); + sim_debug(DEBUG_EXP, &mta_dev, "mt_detach\n"); uptr->u3 = 0; return sim_tape_detach(uptr); } @@ -1271,17 +1197,21 @@ fprintf(stderr, "mt_detach MT\r\n"); /* boot from the specified tape unit */ t_stat mt_boot(int32 unit_num, DEVICE *dptr) { - UNIT *uptr = &dptr->units[unit_num]; /* find tape unit pointer */ - t_stat r; + UNIT *uptr = &dptr->units[unit_num]; /* find tape unit pointer */ -fprintf(stderr, "mt_boot MT Unit number %0.8x\r\n", unit_num); - if ((uptr->flags & UNIT_ATT) == 0) /* Is MT device already attached? */ - return SCPE_UNATT; /* not attached, return error */ - if ((uptr->flags & MTUF_9TR) == 0) { /* is tape a 9 track? */ - uptr->u3 &= ~0xffff; /* clear out old status */ - uptr->u3 |= MT_ODD|MT_CONV|MT_MDEN_800; /* set 800bpi & odd parity */ - } - return chan_boot(GET_UADDR(uptr->u3), dptr); /* boot the ch/sa */ + sim_debug(DEBUG_EXP, &mta_dev, "MT Boot dev/unit %x\n", GET_UADDR(uptr->u3)); + if ((uptr->flags & UNIT_ATT) == 0) { /* Is MT device already attached? */ + sim_debug(DEBUG_EXP, &mta_dev, "MT Boot attach error dev/unit %x\n", GET_UADDR(uptr->u3)); + return SCPE_UNATT; /* not attached, return error */ + } + SPAD[0xf4] = GET_UADDR(uptr->u3); /* put boot device chan/sa into spad */ + SPAD[0xf8] = 0xF000; /* show as F class device */ + + if ((uptr->flags & MTUF_9TR) == 0) { /* is tape a 9 track? */ + uptr->u3 &= ~0xffff; /* clear out old status */ + uptr->u3 |= MT_ODD|MT_CONV|MT_MDEN_800; /* set 800bpi & odd parity */ + } + return chan_boot(GET_UADDR(uptr->u3), dptr); /* boot the ch/sa */ } #endif /* NUM_DEVS_MT */ diff --git a/SEL32/sel32_scfi.c b/SEL32/sel32_scfi.c new file mode 100644 index 0000000..b381429 --- /dev/null +++ b/SEL32/sel32_scfi.c @@ -0,0 +1,1137 @@ +/* sel32_scfi.c: SEL 32 SCFI SCSI Disk controller + + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "sel32_defs.h" + +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE * st, UNIT *uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint8 flags); +extern int chan_read_byte(uint16 chsa, uint8 *data); +extern int chan_write_byte(uint16 chsa, uint8 *data); +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 uint32 M[]; /* our memory */ +extern uint32 SPAD[]; /* cpu SPAD memory */ + +#ifdef NUM_DEVS_SCFI +#define UNIT_V_TYPE (UNIT_V_UF + 0) +#define UNIT_TYPE (0xf << UNIT_V_TYPE) + +#define GET_TYPE(x) ((UNIT_TYPE & (x)) >> UNIT_V_TYPE) +#define SET_TYPE(x) (UNIT_TYPE & ((x) << UNIT_V_TYPE)) +#define UNIT_SCFI UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_FIX + +/* INCH command information */ +/* +WD 0 - Data address +WD 1 - Flags - 0 -36 byte count + +Data - 224 word INCH buffer address +WD 1 Drive 0 Attribute register +WD 2 Drive 1 Attribute register +WD 3 Drive 2 Attribute register +WD 4 Drive 3 Attribute register +WD 5 Drive 4 Attribute register +WD 6 Drive 5 Attribute register +WD 7 Drive 6 Attribute register +WD 8 Drive 7 Attribute register + +Memory attribute register layout +bits 0-7 - Flags + bits 0&1 - 00=Reserved, 01=MHD, 10=FHD, 11=MHD with FHD option + bit 2 - 1=Cartridge module drive + bit 3 - 0=Reserved + bit 4 - 1=Drive not present + bit 5 - 1=Dual Port + bit 6 - 0=Reserved + bit 7 - 0=Reserved +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) +*/ + + +/* 224 word INCH Buffer layout */ +/* 128 word subchannel status storage (SST) */ +/* 66 words of program status queue (PSQ) */ +/* 26 words of scratchpad */ +/* 4 words of label buffer registers */ + +/* u3 */ +/* in u3 is device command code and status */ +#define DSK_CMDMSK 0x00ff /* Command being run */ +#define DSK_STAR 0x0100 /* STAR value in u4 */ +#define DSK_NU2 0x0200 /* */ +#define DSK_READDONE 0x0400 /* Read finished, end channel */ +#define DSK_ENDDSK 0x0800 /* Sensed end of disk */ +#define DSK_SEEKING 0x1000 /* Disk is currently seeking */ +#define DSK_READING 0x2000 /* Disk is reading data */ +#define DSK_WRITING 0x4000 /* Disk is writing data */ +#define DSK_BUSY 0x8000 /* Flag to send a CUE */ +/* commands */ +#define DSK_INCH 0x00 /* Initialize channel */ +#define DSK_WD 0x01 /* Write data */ +#define DSK_RD 0x02 /* Read data */ +#define DSK_NOP 0x03 /* No operation */ +#define DSK_SNS 0x04 /* Sense */ +#define DSK_SCK 0x07 /* Seek cylinder, track, sector */ +#define DSK_TIC 0x08 /* Transfer in channel */ +#define DSK_FNSK 0x0B /* Format for no skip */ +#define DSK_LPL 0x13 /* Lock protected label */ +#define DSK_LMR 0x1F /* Load mode register */ +#define DSK_RES 0x23 /* Reserve */ +#define DSK_WSL 0x31 /* Write sector label */ +#define DSK_RSL 0x32 /* Read sector label */ +#define DSK_REL 0x33 /* Release */ +#define DSK_XEZ 0x37 /* Rezero */ +#define DSK_POR 0x43 /* Priority Override */ +#define DSK_IHA 0x47 /* Increment head address */ +#define DSK_SRM 0x4F /* Set reserve track mode */ +#define DSK_WTL 0x51 /* Write track label */ +#define DSK_RTL 0x52 /* Read track label */ +#define DSK_XRM 0x5F /* Reset reserve track mode */ +#define DSK_RAP 0xA2 /* Read angular positions */ +#define DSK_TESS 0xAB /* Test STAR (subchannel target address register) */ +#define DSK_ICH 0xFF /* Initialize Controller */ + +/* u4 - sector target address register (STAR) */ +/* Holds the current cylinder, head(track), sector */ +#define DISK_CYL 0xFFFF0000 /* cylinder mask */ +#define DISK_TRACK 0x0000FF00 /* track mask */ +#define DISK_SECTOR 0x000000ff /* sector mask */ + +/* u5 */ +/* Sense byte 0 - mode register */ +#define SNS_DROFF 0x80000000 /* Drive Carriage will be offset */ +#define SNS_TRKOFF 0x40000000 /* Track offset: 0=positive, 1=negative */ +#define SNS_RDTMOFF 0x20000000 /* Read timing offset = 1 */ +#define SNS_RDSTRBT 0x10000000 /* Read strobe timing: 1=positive, 0=negative */ +#define SNS_DIAGMOD 0x08000000 /* Diagnostic Mode ECC Code generation and checking */ +#define SNS_RSVTRK 0x04000000 /* Reserve Track mode: 1=OK to write, 0=read only */ +#define SNS_FHDOPT 0x02000000 /* FHD or FHD option = 1 */ +#define SNS_RESERV 0x01000000 /* Reserved */ + +/* Sense byte 1 */ +#define SNS_CMDREJ 0x800000 /* Command reject */ +#define SNS_INTVENT 0x400000 /* Unit intervention required */ +#define SNS_SPARE1 0x200000 /* Spare */ +#define SNS_EQUCHK 0x100000 /* Equipment check */ +#define SNS_DATCHK 0x080000 /* Data Check */ +#define SNS_OVRRUN 0x040000 /* Data overrun/underrun */ +#define SNS_DSKFERR 0x020000 /* Disk format error */ +#define SNS_DEFTRK 0x010000 /* Defective track encountered */ + +/* Sense byte 2 */ +#define SNS_LAST 0x8000 /* Last track flag encountered */ +#define SNS_AATT 0x4000 /* At Alternate track */ +#define SNS_WPER 0x2000 /* Write protection error */ +#define SNS_WRL 0x1000 /* Write lock error */ +#define SNS_MOCK 0x0800 /* Mode check */ +#define SNS_INAD 0x0400 /* Invalid memory address */ +#define SNS_RELF 0x0200 /* Release fault */ +#define SNS_CHER 0x0100 /* Chaining error */ + +/* Sense byte 3 */ +#define SNS_REVL 0x80 /* Revolution lost */ +#define SNS_DADE 0x40 /* Disc addressing or seek error */ +#define SNS_BUCK 0x20 /* Buffer check */ +#define SNS_ECCS 0x10 /* ECC error in sector label */ +#define SNS_ECCD 0x08 /* ECC error iin data */ +#define SNS_ECCT 0x04 /* ECC error in track label */ +#define SNS_RTAE 0x02 /* Reserve track access error */ +#define SNS_UESS 0x01 /* Uncorrectable ECC error */ + +/* u6 */ +/* u6 holds drive attribute entry */ +/* provided by inch command for controller */ +/* +bits 0-7 - Flags + bits 0&1 - 00=Reserved, 01=MHD, 10=FHD, 11=MHD with FHD option + bit 2 - 1=Cartridge module drive + bit 3 - 0=Reserved + bit 4 - 1=Drive not present + bit 5 - 1=Dual Port + bit 6 - 0=Reserved + bit 7 - 0=Reserved +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) +*/ + +/* Pointer held in up7 */ +/* sects/cylinder = sects/track * numhds */ +/* allocated during attach command for each unit defined */ +struct ddata_t +{ + uint8 rbuf[1024]; /* read buffer, Sector buffer 768 or 1024 */ + uint8 wbuf[1024]; /* write buffer, Sector buffer 768 or 1024 */ + uint32 cpos; /* Position of head of cylinder in file */ + uint32 tstart; /* Location of start of cyl/track/sect in data */ + uint32 spare; /* drive register spare */ + uint16 tsize; /* Size of one track in byte */ + uint16 ssize; /* Size of one sector in bytes */ + uint16 ccyl; /* Current Cylinder number */ + uint16 cyl; /* Cylinder head at */ + uint16 tpos; /* Track position */ + uint16 spos; /* Sector position */ + uint16 dlen; /* remaining in data */ +// uint16 tsize; /* Size of one track in byte */ +// uint16 ssize; /* Size of one sector in bytes */ + uint16 rec; /* Current record number */ + uint16 count; /* Remaining in current operation */ +}; + +/* disk definition structure */ +struct scfi_t +{ + char *name; /* Device ID Name */ + uint32 taus; /* total allocation units */ + uint16 bms; /* bit map size */ + uint16 nhds; /* Number of heads */ + uint16 ssiz; /* sector size in words */ + uint16 spt; /* # sectors per track(cylinder) */ + uint8 spau; /* # sectors per allocation unit */ + uint8 spb; /* # sectors per block (192 WDS)*/ + uint32 cyl; /* Number of cylinders */ + uint8 type; /* Device type code */ +} + +scfi_type[] = +{ + /* Class E Disc Devices */ + {"FE004", 5888, 184, 256, 192, 23, 1, 1, 1, 0x80}, /*0 4 M */ + {"CE010", 12800, 200, 2, 96, 16, 1, 2, 400, 0x60}, /*1 10 M */ + {"ME040", 23000, 719, 5, 192, 23, 2, 1, 400, 0x40}, /*2 40 M */ + {"ME080", 46000, 1438, 5, 192, 23, 2, 1, 800, 0x40}, /*3 80 M */ + {"ME300", 87400, 2732, 19, 192, 23, 4, 1, 800, 0x40}, /*4 300 M */ + {"FE005", 5888, 184, 4, 192, 23, 1, 1, 64, 0x80}, /*5 5 M */ + + /* Class F Disc Devices */ + {"FL001", 1334, 0, 2, 64, 26, 3, 3, 26, 0x40}, /*6 1 M */ + {"MH040", 20000, 625, 5, 192, 20, 2, 1, 40, 0x40}, /*7 40 M */ + {"MH080", 40000, 1250, 5, 192, 20, 2, 1, 80, 0x40}, /*8 80 M */ + {"MH300", 76000, 2375, 19, 192, 20, 4, 1, 800, 0x40}, /*9 300 M */ + {"MH1GB", 87400, 2732, 1, 192, 20,16, 1,69920, 0x40}, /*10 1000 M */ + {"SG038", 54752, 1711, 1, 192, 20, 8, 1,21900, 0x40}, /*11 38 M */ + {"SG120", 174848, 5464, 1, 192, 20, 8, 1,69939, 0x40}, /*12 120 M */ + {"SG076", 116808, 3491, 1, 192, 20, 8, 1,46723, 0x40}, /*13 76 M */ + {"FH005", 5120, 184, 4, 192, 20, 1, 1, 64, 0x80}, /*14 5 M */ + {"CD032", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /*15 32 M */ + {"CD032", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /*16 32 M */ + {"CD064", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /*17 64 M */ + {"CD064", 24000, 750, 3, 192, 20, 2, 1, 800, 0x60}, /*18 64 M */ + {"CD096", 8000, 250, 1, 192, 20, 2, 1, 800, 0x60}, /*19 96 M */ + {"CD096", 40000, 1250, 5, 192, 20, 2, 1, 800, 0x60}, /*20 96 M */ + {"MH600", 80000, 2500, 40, 192, 20, 8, 1, 80, 0x40}, /*21 600 M */ + {"FM600", 80000, 2500, 40, 192, 20, 8, 1, 80, 0x40}, /*22 600 M */ + {"FM600", 1600, 50, 40, 192, 20, 1, 1, 2, 0x80}, /*23 600 M */ + {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 'E' DISC DEVICES + DID C'DE01', 1, 1, 23, 192, 256, 184, 5888, C'FE004' + DID C'DE02', 2, 1, 16, 96, 2, 200, 12800, C'CE010' + DID C'DE04', 1, 2, 23, 192, 5, 719, 23000, C'ME040' + DID C'DE05', 1, 2, 23, 192, 5, 1438, 46000, C'ME080' + DID C'DE06', 1, 4, 23, 192, 19, 2732, 87400, C'ME300' + DID C'DE07', 1, 1, 23, 192, 4, 184, 5888, C'FE005' +* 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); +t_stat scfi_srv(UNIT *); +t_stat scfi_boot(int32, DEVICE *); +void scfi_ini(UNIT *, t_bool); +t_stat scfi_reset(DEVICE *); +t_stat scfi_attach(UNIT *, CONST char *); +t_stat scfi_detach(UNIT *); +t_stat scfi_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat scfi_get_type(FILE * st, UNIT *uptr, int32 v, CONST void *desc); +t_stat scfi_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *scfi_description (DEVICE *dptr); + +/* channel program information */ +CHANP sda_chp[NUM_UNITS_SCFI] = {0}; + +MTAB scfi_mod[] = { + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "TYPE", "TYPE", + &scfi_set_type, &scfi_get_type, NULL, "Type of disk"}, + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, + &show_dev_addr, NULL}, + {0} +}; + +UNIT sda_unit[] = { +/* SET_TYPE(12) SG120 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x400)}, /* 0 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x410)}, /* 1 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x420)}, /* 2 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x430)}, /* 3 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x440)}, /* 4 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x450)}, /* 5 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x460)}, /* 6 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(12), 0), 0, UNIT_ADDR(0x470)}, /* 7 */ +}; + +//DIB sda_dib = {scfi_preio, scfi_startcmd, NULL, NULL, NULL, scfi_ini, sda_unit, sda_chp, NUM_UNITS_SCFI, 0x0f, 0x0400, 0, 0, 0}; + +DIB sda_dib = { + scfi_preio, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + scfi_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + scfi_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + sda_unit, /* UNIT* units */ /* Pointer to units structure */ + sda_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_SCFI, /* uint8 numunits */ /* number of units defined */ + 0xF0, /* uint8 mask */ /* 16 devices - device mask */ + 0x0400, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE sda_dev = { + "SDA", sda_unit, NULL, scfi_mod, + NUM_UNITS_SCFI, 16, 24, 4, 16, 32, + NULL, NULL, &scfi_reset, &scfi_boot, &scfi_attach, &scfi_detach, + &sda_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug, + NULL, NULL, &scfi_help, NULL, NULL, &scfi_description +}; + +#if NUM_DEVS_SCFI > 1 +/* channel program information */ +CHANP sdb_chp[NUM_UNITS_SCFI] = {0}; + +UNIT sdb_unit[] = { +/* SET_TYPE(10) DM1GB */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC00)}, /* 0 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC10)}, /* 1 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC20)}, /* 2 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC30)}, /* 3 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC40)}, /* 4 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC50)}, /* 5 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC60)}, /* 6 */ + {UDATA(&scfi_srv, UNIT_SCFI|SET_TYPE(10), 0), 0, UNIT_ADDR(0xC70)}, /* 7 */ +}; + +//DIB sdb_dib = {scfi_preio, scfi_startcmd, NULL, NULL, NULL, scfi_ini, sdb_unit, sdb_chp, NUM_UNITS_SCFI, 0x0f, 0x0c00, 0, 0, 0}; + +DIB sdb_dib = { + scfi_preio, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */ + scfi_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */ + NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */ + NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */ + NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */ + scfi_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */ + sdb_unit, /* UNIT* units */ /* Pointer to units structure */ + sdb_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */ + NUM_UNITS_SCFI, /* uint8 numunits */ /* number of units defined */ + 0xF0, /* uint8 mask */ /* 16 devices - device mask */ + 0x0c00, /* uint16 chan_addr */ /* parent channel address */ + 0, /* uint32 chan_fifo_in */ /* fifo input index */ + 0, /* uint32 chan_fifo_out */ /* fifo output index */ + 0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */ +}; + +DEVICE sdb_dev = { + "SDB", sdb_unit, NULL, scfi_mod, + NUM_UNITS_SCFI, 16, 24, 4, 16, 32, + NULL, NULL, &scfi_reset, &scfi_boot, &scfi_attach, &scfi_detach, + &sdb_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug, + NULL, NULL, &scfi_help, NULL, NULL, &scfi_description +}; +#endif + +/* start a disk operation */ +uint8 scfi_preio(UNIT *uptr, uint16 chan) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + + sim_debug(DEBUG_CMD, dptr, "scfi_preio u3 %x unit=%d\n", uptr->u3, unit); + if ((uptr->u3 & 0xff00) != 0) { /* just return if busy */ + return SNS_BSY; + } + sim_debug(DEBUG_CMD, dptr, "scfi_preio unit=%d\n", unit); + return 0; /* good to go */ +} + +uint8 scfi_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { + uint16 addr = GET_UADDR(uptr->u3); + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + uint8 ch; + + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd unit %d cmd %x u3 %x\n", unit, cmd, uptr->u3); + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + uptr->u5 |= SNS_INTVENT; /* unit intervention required */ + if (cmd != DSK_SNS) /* we are completed with unit check status */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + } + + if ((uptr->u3 & DSK_CMDMSK) != 0) { + uptr->u3 |= DSK_BUSY; /* Flag we we are busy */ + return SNS_BSY; + } + if ((uptr->u3 & 0xff00) != 0) { /* if any status info, we are busy */ + return SNS_BSY; + } + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd CMD 2 unit=%d %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 */ +dosns: + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd CMD sense\n"); + /* bytes 0,1 - Cyl entry from STAR reg in u4 */ + ch = (uptr->u4 >> 24) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b0 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + ch = (uptr->u4 >> 16) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b1 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* byte 2 - Track entry from STAR reg in u4 */ + ch = (uptr->u4 >> 8) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b2 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* byte 3 - Sector entry from STAR reg in u4 */ + ch = (uptr->u4) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense STAR b3 unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* bytes 4 - mode reg, byte 0 of u5 */ + ch = (uptr->u5 >> 24) & 0xff; /* return the sense data for device */ + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* bytes 5-7 - status bytes, bytes 1-3 of u5 */ + ch = (uptr->u5 >> 16) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%d 2 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + ch = (uptr->u5 >> 8) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%d 3 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + ch = (uptr->u5) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_startcmd sense unit=%d 4 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + /* bytes 8-11 - drive attribute register (DATR) entries from uptr->u6 via INCH cmd */ + ch = (uptr->u6 >> 24) & 0xff; + chan_write_byte(addr, &ch) ; + ch = (uptr->u6 >> 16) & 0xff; + chan_write_byte(addr, &ch) ; + ch = (uptr->u6 >> 8 ) & 0xff; + chan_write_byte(addr, &ch) ; + ch = (uptr->u6 >> 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->u5 &= 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->u5 |= (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 */ + int i; + UNIT *up = dptr->units; /* first unit for this device */ + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd starting inch cmd addr %x u4 %x\r\n", addr, uptr->u4); + /* 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 u4 and us9 left non-zero */ + /* just return OK and channel software will use up8 as status buffer */ + mema = (uint32)uptr->u4; /* get memory address of buffer */ + uptr->u4 = M[mema>>2]; /* get status buffer address for XIO return status */ + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd starting inch cmd addr %x u4 %x mema %x units %d\r\n", + addr, uptr->u4, 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; inumunits && i<8; i++) { /* process all drives */ + up->u6 = M[(mema>>2)+i+1]; /* save each unit's drive data */ + up++; /* next unit for this device */ + } + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd done inch cmd addr %x\n", addr); + return SNS_CHNEND|SNS_DEVEND; + break; + } + + case DSK_SCK: /* Seek command 0x07 */ + case DSK_XEZ: /* Rezero & Read IPL record 0x1f */ + uptr->u3 &= ~(DSK_STAR); /* show we do not have seek STAR in u4 */ + case DSK_WD: /* Write command 0x01 */ + case DSK_RD: /* Read command 0x02 */ + case DSK_LMR: /* read mode register */ + + uptr->u3 |= cmd; /* save cmd */ + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd done with disk seek r/w cmd %x addr %x\n", cmd, addr); + sim_activate(uptr, 20); /* start things off */ + return 0; + + case DSK_NOP: /* NOP 0x03 */ + return SNS_CHNEND|SNS_DEVEND; /* return OK */ + + case DSK_SNS: /* Sense 0x04 */ + goto dosns; /* use code above */ + break; + } + sim_debug(DEBUG_CMD, dptr, "scfi_startcmd done with scfi_startcmd %x addr %x u5 %x\n", cmd, addr, uptr->u5); + if (uptr->u5 & 0xff) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + sim_activate(uptr, 20); /* start things off */ + return SNS_CHNEND|SNS_DEVEND; +} + +/* Handle processing of disk requests. */ +t_stat scfi_srv(UNIT *uptr) +{ + uint16 chsa = GET_UADDR(uptr->u3); + DEVICE *dptr = find_dev_from_unit(uptr); + DIB *dibp = (DIB *)dptr->ctxt; /* get pointer to Dev Info Blk for this device */ + CHANP *chp = (CHANP *)dibp->chan_prg; /* get pointer to channel program */ + struct ddata_t *data = (struct ddata_t *)(uptr->up7); + int cmd = uptr->u3 & DSK_CMDMSK; + int type = GET_TYPE(uptr->flags); + int count = data->count; + int trk, cyl; + int unit = (uptr - dptr->units); + int i; + uint8 ch; + uint8 buf2[768]; + uint8 buf[768]; + + sim_debug(DEBUG_DETAIL, &sda_dev, "scfi_srv entry unit %d cmd %x chsa %x chan %x count %x\n", + unit, cmd, chsa, chsa>>8, chp->ccw_count); + + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + return SCPE_OK; + } + if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */ + uptr->u5 |= SNS_INTVENT; /* unit intervention required */ + if (cmd != DSK_SNS) /* we are completed with unit check status */ + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + } + + sim_debug(DEBUG_CMD, dptr, "scfi_srv cmd=%x chsa %04x count %x\n", cmd, chsa, chp->ccw_count); + switch (cmd) { + case 0: /* No command, stop disk */ + break; + + case DSK_SNS: /* 0x4 */ + ch = uptr->u5 & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv sense unit=%d 1 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = (uptr->u5 >> 8) & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv sense unit=%d 2 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = 0; + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv sense unit=%d 3 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = unit; + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv sense unit=%d 4 %x\n", unit, ch); + chan_write_byte(chsa, &ch) ; + ch = 4; + sim_debug(DEBUG_CMD, dptr, "DISK SENSE %x chars complete %.8x, unit %d\n", ch, uptr->u5, unit); + uptr->u3 &= ~(0xff00); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + break; + + case DSK_SCK: /* Seek cylinder, track, sector 0x07 */ + + /* If we are waiting on seek to finish, check if there yet. */ + if (uptr->u3 & DSK_SEEKING) { + /* see if on cylinder yet */ + if ((uptr->u4 >> 16) == data->cyl) { + /* we are on cylinder, seek is done */ + sim_debug(DEBUG_CMD, dptr, "scfi_srv seek on cylinder unit=%d %d %d\n", + unit, uptr->u4 >> 16, data->cyl); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + set_devattn(chsa, SNS_DEVEND); /* start the operation */ + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek end unit=%d %x %x\n", + unit, uptr->u4 >> 16, data->cyl); + sim_activate(uptr, 20); + break; + } else { + /* Compute delay based of difference. */ + /* Set next state = index */ + i = (uptr->u4 >> 16) - data->cyl; + sim_debug(DEBUG_CMD, dptr, "scfi_srv seek unit=%d %x %x\n", unit, uptr->u4 >> 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 (data->cyl < 0) /* test for less than zero */ + data->cyl = 0; /* make zero */ + } + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek next unit=%d %d %d\n", unit, uptr->u4 >> 16, + data->cyl); + sim_activate(uptr, 2); + break; + } + } + + /* not seeking, so start a new seek */ + /* Read in 4 character seek code */ + for (i = 0; i < 4; i++) { + if (chan_read_byte(chsa, &buf[i])) { + /* we have error, bail out */ + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + } +rezero: + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek unit=%d star %02d%02d %02d %02d\n", + unit, buf[0], buf[1], buf[2], buf[3]); + /* save STAR (target sector) data in u4 */ + uptr->u4 = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); + cyl = uptr->u4 >> 16; /* get the cylinder */ + trk = buf[2]; /* get the track */ + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv SEEK %x cyl %d trk %d sec %d unit=%d\n", + uptr->u4, cyl&0xffff, trk, buf[3], unit); + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv Disk %s cyl %d hds %d sec/trk %d unit=%d\n", + scfi_type[type].name, scfi_type[type].cyl, scfi_type[type].nhds, scfi_type[type].spt, unit); + + uptr->u3 |= DSK_STAR; /* show we have seek STAR in u4 */ + /* calc the sector address of data */ + /* calculate file position in bytes of requested sector */ + data->tstart = uptr->u4 * (scfi_type[type].spb * scfi_type[type].ssiz * 4); /* file offset in bytes */ + data->tpos = trk; /* save the track/head number */ + data->spos = buf[3]; /* save the sector number */ + data->count = 0; /* no data seen yet */ + data->rec = 0; /* number of bytes in this sector */ + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek start %x trk %x sec %x\n", data->tstart, trk, buf[3]); + if ((sim_fseek(uptr->fileref, data->tstart, SEEK_SET)) != 0) { /* seek home */ + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv Error on seek to %x\n", data->tstart); + } + + /* Check if already on correct cylinder */ + if (trk != data->cyl) { + /* Do seek */ + uptr->u3 |= DSK_SEEKING; /* show we are seeking */ + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv seek unit=%d trk %x cyl %x\n", + unit, trk, data->cyl); + sim_activate(uptr, 20); + chan_end(chsa, SNS_CHNEND); + } else { + sim_debug(DEBUG_DETAIL, dptr, "scfi_srv calc sect addr seek start %x trk %x sec %x\n", + data->tstart, trk, buf[3]); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + sim_activate(uptr, 20); + chan_end(chsa, SNS_DEVEND|SNS_CHNEND); + } + return SCPE_OK; + + case DSK_XEZ: /* Rezero & Read IPL record */ + + sim_debug(DEBUG_CMD, dptr, "RD REZERO IPL unit=%d seek 0\n", unit); + /* Do a seek to 0 */ + uptr->u4 = 0; /* set STAR to 0, 0, 0 */ + uptr->u3 &= ~(0xffff); /* remove old cmd */ + uptr->u3 |= DSK_SCK; /* show as seek command */ + data->tstart = 0; /* byte offset is 0 */ + data->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 */ + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + /* zero stuff */ + buf[0] = buf[1] = buf[2] = buf[3] = 0; + goto rezero; /* murge with seek code */ + break; + + case DSK_LMR: + sim_debug(DEBUG_CMD, dptr, "Load Mode Reg unit=%d\n", unit); + /* Read in 1 character of mode data */ + if (chan_read_byte(chsa, &buf[0])) { + /* we have error, bail out */ + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + uptr->u5 |= SNS_CMDREJ|SNS_EQUCHK; + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + uptr->u3 &= ~(0xffff); /* remove old cmd */ + uptr->u5 &= 0x00ffffff; /* clear old mode data */ + uptr->u5 |= (buf[0] << 24); /* save mode value */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + break; + + case DSK_RD: /* Read Data */ + /* data->tstart has start of sector address in bytes */ + if ((uptr->u3 & DSK_READING) == 0) { /* see if we are reading data */ + uptr->u3 |= DSK_READING; /* read from disk starting */ + data->dlen = 0; /* no data read yet */ + sim_debug(DEBUG_CMD, dptr, "DISK READ starting unit=%d u3 %x count %d rec %d\r\n", + unit, uptr->u3, count, data->rec); + } + + if (uptr->u3 & DSK_READING) { /* see if we are reading data */ + /* read in a sector of data from disk */ + if ((count=sim_fread(buf, 1, data->ssize, uptr->fileref)) != data->ssize) { + sim_debug(DEBUG_CMD, dptr, "Error %d on read %d of diskfile cyl %d hds %d sec %d\n", + count, data->ssize, data->cyl, data->tpos, data->spos); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ +// sim_activate(uptr, 20); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + + sim_debug(DEBUG_CMD, dptr, "scfi_srv after READ chsa %04x count %x\n", chsa, chp->ccw_count); + /* process the next sector of data */ + data->rec = count; /* no bytes in sector yet */ + count = 0; /* used here as a flag for short write */ + for (i=0; i<(data->rec); i++) { + ch = buf[i]; /* get a char from buffer */ + if (chan_write_byte(chsa, &ch)) { /* put a byte to memory */ + sim_debug(DEBUG_DATAIO, dptr, "DISK Read %d bytes from diskfile cyl %d hds %d sec %d tstart %d\n", + data->dlen+i, data->cyl, data->tpos, data->spos, data->tstart); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + goto rddone; + } + } + data->dlen += data->rec; /* add byte read to total count */ + + sim_debug(DEBUG_CMD, dptr, + "DISK READ from sec end %d bytes end %d from diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->ssize, data->cyl, data->tpos, data->spos, data->tstart); + data->spos++; + /* see if we are done reading data */ + if (test_write_byte_end(chsa)) { + sim_debug(DEBUG_DATAIO, dptr, + "DISK Read complete Read %d bytes from diskfile cyl %d hds %d sec %d tstart %x\r\n", + data->dlen, data->cyl, data->tpos, data->spos, data->tstart); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + } +rddone: +// sim_activate(uptr, 20); + sim_activate(uptr, 10); /* wait to read next sector */ + break; + } + break; + + case DSK_WD: /* Write Data */ + /* data->tstart has start of sector address in bytes */ + if ((uptr->u3 & DSK_WRITING) == 0) { /* see if we are writing data */ + uptr->u3 |= DSK_WRITING; /* write to disk starting */ + data->dlen = 0; /* no data written yet */ + sim_debug(DEBUG_CMD, dptr, "DISK WRITE starting unit=%d u3 %x bytes %d rec %d\n", + unit, uptr->u3, data->dlen, data->rec); + } + if (uptr->u3 & DSK_WRITING) { /* see if we are writing data */ + /* process the next sector of data */ + data->rec = 0; /* no bytes in sector yet */ + count = 0; /* used here as a flag for short read */ + for (i=0; i<(data->ssize); i++) { + if (chan_read_byte(chsa, &ch)) { /* get a byte from memory */ + /* if error on reading 1st byte, we are done writing */ + if (i == 0) { + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + sim_debug(DEBUG_DATAIO, dptr, + "DISK Wrote %d bytes to diskfile cyl %d hds %d sec %d tstart %d\r\n", + data->dlen, data->cyl, data->tpos, data->spos, data->tstart); + chan_end(chsa, SNS_CHNEND|SNS_DEVEND); + goto wrdone; + } + ch = 0; /* finish out the sector with zero */ + count++; /* show we have no more data to write */ + } + buf2[i] = ch; /* save the char */ + } + data->dlen += data->ssize; /* add 1 sector of bytes */ + /* write the sector to disk */ + if ((i=sim_fwrite(buf2, 1, data->ssize, uptr->fileref)) != data->ssize) { + sim_debug(DEBUG_CMD, dptr, "Error %d on write %d to diskfile cyl %d hds %d sec %d\n", + i, data->ssize, data->cyl, data->tpos, data->spos); + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + if (count != 0) { /* see if done with write command */ + sim_debug(DEBUG_DATAIO, dptr, + "DISK WroteB %d bytes to diskfile cyl %d hds %d sec %d tstart %d\r\n", + data->dlen, data->cyl, data->tpos, data->spos, data->tstart); + uptr->u3 &= ~(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 %d bytes end %d to diskfile cyl %d hds %d sec %d tstart %x\n", + data->dlen, data->ssize, data->cyl, data->tpos, data->spos, data->tstart); + data->spos++; +wrdone: +// sim_activate(uptr, 20); + sim_activate(uptr, 10); + break; + } + break; + + default: + sim_debug(DEBUG_DETAIL, dptr, "invalid command=%d %x\n", unit, cmd); + uptr->u5 |= SNS_CMDREJ; + uptr->u3 &= ~(0xffff); /* remove old status bits & cmd */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); + break; + } + sim_debug(DEBUG_DATAIO, dptr, "scfi_srv done cmd=%x chsa %04x count %x\n", cmd, chsa, chp->ccw_count); + return SCPE_OK; +} + +/* initialize the disk */ +void scfi_ini(UNIT *uptr, t_bool f) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + int i = GET_TYPE(uptr->flags); + + uptr->u3 &= ~0xffff; /* clear out the flags but leave ch/sa */ + /* capacity is tracks per allocation unit times sectors per allocation unit */ + uptr->capac = scfi_type[i].taus * scfi_type[i].spau; + + sim_debug(DEBUG_EXP, &sda_dev, "SDA init device %s on unit SDA%.1x cap %x\n", + dptr->name, GET_UADDR(uptr->u3), uptr->u3); +} + +t_stat scfi_reset(DEVICE * dptr) +{ + return SCPE_OK; +} + +/* create the disk file for the specified device */ +int scfi_format(UNIT *uptr) { + struct ddata_t *data = (struct ddata_t *)uptr->up7; + uint16 addr = GET_UADDR(uptr->u3); + int type = GET_TYPE(uptr->flags); + DEVICE *dptr = find_dev_from_unit(uptr); + uint16 tsize = data->tsize; /* get track size in bytes */ + uint32 cyl; + uint16 spc = scfi_type[type].nhds * scfi_type[type].spt; /* sectors/cyl */ + uint32 cap = scfi_type[type].taus * scfi_type[type].spau; /* disk capacity in sectors */ + uint32 cylv = cap / spc; /* calc number of cylinders */ + uint8 *buff; + + /* see if user wants to initialize the disk */ + if (!get_yn("Initialize disk? [Y] ", TRUE)) { + return 1; + } + + /* seek to sector 0 */ + if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */ + fprintf (stderr, "Error on seek to 0\r\n"); + } + + /* get buffer for track data */ + if ((buff = (uint8 *)calloc(tsize, sizeof(uint8))) == 0) { + detach_unit(uptr); + return SCPE_ARG; + } + /* put dummy data in first word of disk */ + buff[0] = 'Z'; + buff[1] = 'E'; + buff[2] = 'R'; + buff[3] = 'O'; + sim_debug(DEBUG_CMD, dptr, "Creating disk file of trk size %x capacity %d\r\n", tsize, cap * data->ssize); + /* write zeros to each track of the disk */ + for (cyl = 0; cyl < cylv; cyl++) { + if ((sim_fwrite(buff, 1, data->tsize, uptr->fileref)) != data->tsize) { + sim_debug(DEBUG_CMD, dptr, "Error on write to diskfile cyl %d\r\n", cyl); + } + if (cyl == 0) { + buff[0] = 0; + buff[1] = 0; + buff[2] = 0; + buff[3] = 0; + } + } + if ((cyl % 400) == 0) + fputc('.', stderr); + fputc('\r', stderr); + fputc('\n', stderr); + /* seek home again */ + sim_fseek(uptr->fileref, 0, SEEK_SET); /* seek home */ + free(buff); /* free cylinder buffer */ + data->cpos = 0; + data->ccyl = 0; + set_devattn(addr, SNS_DEVEND); /* start us up */ +// sim_activate(uptr, 100); + return 0; +} + +/* attach the selected file to the disk */ +t_stat scfi_attach(UNIT *uptr, CONST char *file) +{ + uint16 addr = GET_UADDR(uptr->u3); + int type = GET_TYPE(uptr->flags); + DEVICE *dptr = find_dev_from_unit(uptr); + t_stat r; + uint16 tsize; /* track size in bytes */ + uint16 ssize; /* sector size in bytes */ + 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; + } + + uptr->up7 = (void *)data; /* save pointer to structure in up7 */ + /* track size in bytes is sectors/track times words/sector time 4 bytse/word */ + tsize = scfi_type[type].spt * scfi_type[type].ssiz * 4; /* get track size in bytes */ + data->tsize = tsize; /* save size of track in bytes */ + uptr->capac = scfi_type[type].taus * scfi_type[type].spau; /* disk capacity in sectors */ + ssize = scfi_type[type].ssiz * 4; /* disk sector size in bytes */ + uptr->capac *= ssize; /* disk capacity in bytes */ + data->ssize = ssize; /* save sector size bytes */ + + sim_debug(DEBUG_CMD, dptr, "Disk taus %d spau %d ssiz %d cap %d\n", + scfi_type[type].taus, scfi_type[type].spau, scfi_type[type].ssiz * 4, uptr->capac); /* disk capacity */ + + if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */ + detach_unit(uptr); /* if no space, error */ + return SCPE_FMT; /* error */ + } + + /* read in the 1st sector of the 'disk' */ + if ((r = sim_fread(&buff[0], sizeof(uint8), ssize, uptr->fileref) != ssize)) { + sim_debug(DEBUG_CMD, &sda_dev, "Disk format fread ret = %x\n", r); + goto fmt; + } + + if ((buff[0] | buff[1] | buff[2] | buff[3]) == 0) { + sim_debug(DEBUG_CMD, &sda_dev, "Disk format buf0 %x buf1 %x buf2 %x buf3 %x\n", + buff[0], buff[1], buff[2], buff[3]); +fmt: + /* format the drive */ + if (scfi_format(uptr)) { + detach_unit(uptr); /* if no space, error */ + return SCPE_FMT; /* error */ + } + } + + if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */ + detach_unit(uptr); /* if no space, error */ + return SCPE_FMT; /* error */ + } + + data->ssize = ssize; /* save sector size in bytes */ + data->tsize = tsize; /* save track size in bytes */ + data->cpos = 0; /* current read/write position in cylinder*/ + data->ccyl = 0; /* current cylinder number */ + data->tpos = 0; /* current track position */ + data->spos = 0; /* current sector position */ + data->rec = 0; /* record length */ + data->count = 0; /* clear count value */ + + 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); + sim_debug(DEBUG_CMD, &sda_dev, "File %s attached to %s\r\n", file, scfi_type[type].name); + + set_devattn(addr, SNS_DEVEND); + return SCPE_OK; +} + +/* 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->u3 &= ~0xffff; /* no cmd and flags */ + return detach_unit(uptr); /* tell simh we are done with disk */ +} + +/* boot from the specified disk unit */ +t_stat scfi_boot(int32 unit_num, DEVICE *dptr) +{ + UNIT *uptr = &dptr->units[unit_num]; /* find disk unit number */ + + sim_debug(DEBUG_CMD, &sda_dev, "SCFI Disk Boot dev/unit %x\n", GET_UADDR(uptr->u3)); + SPAD[0xf4] = GET_UADDR(uptr->u3); /* put boot device chan/sa into spad */ + SPAD[0xf8] = 0xF000; /* show as F class device */ + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; /* attached? */ + return chan_boot(GET_UADDR(uptr->u3), dptr); /* boot the ch/sa */ +} + +/* Disk option setting commands */ +t_stat scfi_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int i; + + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; + for (i = 0; scfi_type[i].name != 0; i++) { + if (strcmp(scfi_type[i].name, cptr) == 0) { + uptr->flags &= ~UNIT_TYPE; + uptr->flags |= SET_TYPE(i); + uptr->capac = scfi_type[i].taus * scfi_type[i].spau; + return SCPE_OK; + } + } + return SCPE_ARG; +} + +t_stat scfi_get_type(FILE * st, UNIT *uptr, int32 v, CONST void *desc) +{ + if (uptr == NULL) + return SCPE_IERR; + fputs("TYPE=", st); + fputs(scfi_type[GET_TYPE(uptr->flags)].name, st); + return SCPE_OK; +} + +/* help information for disk */ +t_stat scfi_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr) +{ + int i; + fprintf (st, "SEL 32 SCFI Disk Processor\r\n"); + fprintf (st, "Use:\r\n"); + fprintf (st, " sim> SET %sn TYPE=type\r\n", dptr->name); + fprintf (st, "Type can be: "); + for (i = 0; scfi_type[i].name != 0; i++) { + fprintf(st, "%s", scfi_type[i].name); + if (scfi_type[i+1].name != 0) + fprintf(st, ", "); + } + fprintf (st, ".\nEach drive has the following storage capacity:\r\n"); + for (i = 0; scfi_type[i].name != 0; i++) { + int32 size = scfi_type[i].taus * scfi_type[i].spau; + size /= 1024; + size = (10 * size) / 1024; + fprintf(st, " %-8s %4d.%1dMB\r\n", scfi_type[i].name, size/10, size%10); + } + fprint_set_help (st, dptr); + fprint_show_help (st, dptr); + return SCPE_OK; +} + +const char *scfi_description (DEVICE *dptr) +{ + return "SEL 32 SCFI Disk Processor"; +} + +#endif diff --git a/SEL32/sel32_sys.c b/SEL32/sel32_sys.c index bca9d4d..07ceff7 100644 --- a/SEL32/sel32_sys.c +++ b/SEL32/sel32_sys.c @@ -1,6 +1,7 @@ /* sel32_sys.c: SEL 32 Gould Concept/32 (orignal SEL32) Simulator system interface. - Copyright (c) 2018, Richard Cornwell + Copyright (c) 2018, James C. Bevier + Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,7 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -24,8 +25,6 @@ #include "sel32_defs.h" #include -extern DEVICE cpu_dev; -extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint32 M[MAXMEMSIZE]; extern uint32 SPAD[]; @@ -53,14 +52,20 @@ extern uint32 PSD[]; */ -char sim_name[] = "SEL 32"; /* our simulator name */ +char sim_name[] = "SEL 32"; /* our simulator name */ REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; /* maximum number of instructions/words to examine */ +int32 sim_emax = 1; /* maximum number of instructions/words to examine */ DEVICE *sim_devices[] = { - &cpu_dev, + &cpu_dev, +#ifdef NUM_DEVS_IOP + &iop_dev, /* IOP channel controller */ +#endif +#ifdef NUM_DEVS_RTOM + &rtc_dev, + &itm_dev, +#endif #ifdef NUM_DEVS_CON &con_dev, #endif @@ -85,12 +90,18 @@ DEVICE *sim_devices[] = { &ddb_dev, #endif #endif +#ifdef NUM_DEVS_SCFI + &sda_dev, +#if NUM_DEVS_SCFI > 1 + &sdb_dev, +#endif +#endif #ifdef NUM_DEVS_COM + &coml_dev, &com_dev, #endif NULL }; - /* Simulator debug controls */ DEBTAB dev_debug[] = { {"CMD", DEBUG_CMD, "Show command execution to devices"}, @@ -104,7 +115,6 @@ DEBTAB dev_debug[] = { {0, 0} }; - const char *sim_stop_messages[] = { "Unknown error", "IO device not ready", @@ -116,7 +126,7 @@ const char *sim_stop_messages[] = { "Nested indirects exceed limit", "I/O Check opcode", "Memory management trap during trap", - }; +}; /* * get_word - function to load a 32 bit word from the input file @@ -125,23 +135,17 @@ const char *sim_stop_messages[] = { */ int get_word(FILE *fileref, uint32 *word) { - unsigned char cbuf[4]; + unsigned char cbuf[4]; -#ifndef DO_BYTESWAP - /* read in the 4 chars */ - if (sim_fread(cbuf, 1, 4, fileref) != 4) - return 1; /* read error or eof */ - /* byte swap while reading data */ - *word = ((cbuf[0]) << 24) | + /* read in the 4 chars */ + if (sim_fread(cbuf, 1, 4, fileref) != 4) + return 1; /* read error or eof */ + /* byte swap while reading data */ + *word = ((cbuf[0]) << 24) | ((cbuf[1]) << 16) | ((cbuf[2]) << 8) | ((cbuf[3])); -#else - /* read in 32 bits */ - if (sim_fread((void *)word, 4, 1, fileref) != 1) - return 1; /* read error or eof */ -#endif - return 0; /* all OK */ + return 0; /* all OK */ } #ifdef NO_TAP_FOR_NOW @@ -152,20 +156,14 @@ int get_word(FILE *fileref, uint32 *word) */ int get_halfword(FILE *fileref, uint16 *word) { - unsigned char cbuf[2]; + unsigned char cbuf[2]; -#ifndef DO_BYTESWAP - /* read in the 2 chars */ - if (sim_fread(cbuf, 1, 2, fileref) != 2) - return 1; /* read error or eof */ - /* byte swap while reading data */ - *word = ((uint16)(cbuf[0]) << 8) | ((uint16)(cbuf[1])); -#else - /* read in 16 bits */ - if (sim_fread((void *)word, 2, 1, fileref) != 1) - return 1; /* read error or eof */ -#endif - return 0; /* all OK */ + /* read in the 2 chars */ + if (sim_fread(cbuf, 1, 2, fileref) != 2) + return 1; /* read error or eof */ + /* byte swap while reading data */ + *word = ((uint16)(cbuf[0]) << 8) | ((uint16)(cbuf[1])); + return 0; /* all OK */ } #endif @@ -174,15 +172,15 @@ int get_halfword(FILE *fileref, uint16 *word) t_stat load_mem (FILE *fileref) { uint32 data; - uint32 ma = 0; /* start at mem add 0 */ + uint32 ma = 0; /* start at mem add 0 */ - /* read the file until the end */ + /* read the file until the end */ for ( ;; ) { - if (get_word(fileref, &data)) /* get 32 bits of data */ - return SCPE_OK; /* load is complete, return */ - M[ma++] = data; /* put data in memory */ + if (get_word(fileref, &data)) /* get 32 bits of data */ + return SCPE_OK; /* load is complete, return */ + M[ma++] = data; /* put data in memory */ } - return SCPE_OK; /* never here */ + return SCPE_OK; /* never here */ } #ifdef NO_TAP_FOR_NOW @@ -190,33 +188,33 @@ t_stat load_mem (FILE *fileref) /* return SCPE_OK on load complete */ t_stat load_tap (FILE *fileref) { - uint32 bdata, edata; - uint16 hdata; - uint32 ma = 0; /* start loading at loc 0 */ - int32 wc; + uint32 bdata, edata; + uint16 hdata; + uint32 ma = 0; /* start loading at loc 0 */ + int32 wc; - for ( ;; ) { /* loop until EOF read */ - /* look for record byte count or zero for EOF */ - if (get_word(fileref, &bdata)) /* read 4 bytes of data */ - return SCPE_FMT; /* must be error, exit */ - wc = (int32)(bdata); /* byte count in tape record */ - wc = (wc + 1)/2; /* change byte count into hw count */ - if (wc == 0) - return SCPE_OK; /* eof found, return */ - /* copy data to memory in 16 bit halfwords */ - while (wc-- != 0) { - if (get_halfword(fileref, &hdata)) /* get 16 bits of data */ - return SCPE_FMT; /* must be error, exit */ - ((uint16*)M)[ma++] = hdata; /* put the hw into memory */ + for ( ;; ) { /* loop until EOF read */ + /* look for record byte count or zero for EOF */ + if (get_word(fileref, &bdata)) /* read 4 bytes of data */ + return SCPE_FMT; /* must be error, exit */ + wc = (int32)(bdata); /* byte count in tape record */ + wc = (wc + 1)/2; /* change byte count into hw count */ + if (wc == 0) + return SCPE_OK; /* eof found, return */ + /* copy data to memory in 16 bit halfwords */ + while (wc-- != 0) { + if (get_halfword(fileref, &hdata)) /* get 16 bits of data */ + return SCPE_FMT; /* must be error, exit */ + ((uint16*)M)[ma++] = hdata; /* put the hw into memory */ } - /* look only for record byte count */ - if (get_word(fileref, &edata)) /* read 4 bytes of data */ - return SCPE_FMT; /* must be error, exit */ - /* the before and after byte count must be equal */ - if (bdata != edata) - return SCPE_FMT; /* must be error, exit */ + /* look only for record byte count */ + if (get_word(fileref, &edata)) /* read 4 bytes of data */ + return SCPE_FMT; /* must be error, exit */ + /* the before and after byte count must be equal */ + if (bdata != edata) + return SCPE_FMT; /* must be error, exit */ } - return SCPE_OK; /* never here */ + return SCPE_OK; /* never here */ } #endif @@ -225,103 +223,103 @@ t_stat load_tap (FILE *fileref) * * *DEVXX=FCILCASA (,N) * - * *DEV defines a controller definition entry - * XX hex address that will be used by I/O instructions to address controller - * = required delimiter for following 8 hex characters - * F flag used for I/O emulation by CPU, not used but must be zero. - * C defines the class of controller: - * 0 = Line Printer - * 1 = Card Reader - * 2 = Teletype - * 3 = Interval Timer - * 4 = Panel - * 5-D Unassigned - * E = All Others - * F = Extended I/O - * IL Controller interrupt priority level of Service Interrupt (0x14 - 0x23) - * CA Controller address defined by hardware switches on controller - * SA Lowest controller device subaddress. Usually zero when only 1 device configured - * The subaddress field (SA) must reflect the following for TLC controller: - * 00 = Card Reader - * 01 = Teletype - * 02 = Line Printer - * () denotes optional parameter - * ,NN 2 digit hexx number of devices configured on the controller` + * *DEV defines a controller definition entry + * XX hex address that will be used by I/O instructions to address controller + * = required delimiter for following 8 hex characters + * F flag used for I/O emulation by CPU, not used but must be zero. + * C defines the class of controller: + * 0 = Line Printer + * 1 = Card Reader + * 2 = Teletype + * 3 = Interval Timer + * 4 = Panel + * 5-D Unassigned + * E = All Others + * F = Extended I/O + * IL Controller interrupt priority level of Service Interrupt (0x14 - 0x23) + * CA Controller address defined by hardware switches on controller + * SA Lowest controller device subaddress. Usually zero when only 1 device configured + * The subaddress field (SA) must reflect the following for TLC controller: + * 00 = Card Reader + * 01 = Teletype + * 02 = Line Printer + * () denotes optional parameter + * ,NN 2 digit hexx number of devices configured on the controller` * *********************************************** * * *INTXX=RS - * *INT defines interrupt definition entry - * XX Hex interrupt priority level to be defined - * = required delimiter for following 2 hex characters - * R Hex RTOM board number to which the interrupt XX is assigned - * S 1's complement of the hex subaddress of the RTOM board - * assigned to the interrupt XX + * *INT defines interrupt definition entry + * XX Hex interrupt priority level to be defined + * = required delimiter for following 2 hex characters + * R Hex RTOM board number to which the interrupt XX is assigned + * S 1's complement of the hex subaddress of the RTOM board + * assigned to the interrupt XX * - * RTOM physical controller address 0x79 is RTOM board number 1, RTOM - * address 0x7A is board number 2, etc. - * Real-Time Clock is connected tp subaddress 6 on RTOM board - * Interval Timer is connected to subaddress 4 on RTOM board - * RTOM physical address must be 0x79 or above to be able to - * support up to seven RTOM boards for maximum configuration - * of 112 interrupt levels (7 x 16). + * RTOM physical controller address 0x79 is RTOM board number 1, RTOM + * address 0x7A is board number 2, etc. + * Real-Time Clock is connected tp subaddress 6 on RTOM board + * Interval Timer is connected to subaddress 4 on RTOM board + * RTOM physical address must be 0x79 or above to be able to + * support up to seven RTOM boards for maximum configuration + * of 112 interrupt levels (7 x 16). * *********************************************** * * *END - * *END Defines the last record of the Initial Configuration Load file. + * *END Defines the last record of the Initial Configuration Load file. * *********************************************** */ /* Example device entry * *DEV04=0E140100,04 - * The controller is "E" class - * CPU command device address will be 0x04 - * The priority of the Service Interrupt is 0x14 - * The first device has suaddress of 00 and there are 4 devices defined - * There will be four devices defined in SPAD. The I/O commands (CD and TD) - * will address the devices as 0x04, 0x05, 0x06, and 0x07. - * The physical address of the controller is 0x10. - * Assigning SI address of 0x14 means: - * The transfer Interrupt location for priority 0x14 is 0x100. - * The Service Interrupt vector location for priority 0x14 is 0x140. - * The emulation IOCD will be stored at loation 0x700. - * The interrupt control instructions (DI, DI, RI, AI, DAI) will control - * the interrupt of the controller by addressing priority 0x14. + * The controller is "E" class + * CPU command device address will be 0x04 + * The priority of the Service Interrupt is 0x14 + * The first device has suaddress of 00 and there are 4 devices defined + * There will be four devices defined in SPAD. The I/O commands (CD and TD) + * will address the devices as 0x04, 0x05, 0x06, and 0x07. + * The physical address of the controller is 0x10. + * Assigning SI address of 0x14 means: + * The transfer Interrupt location for priority 0x14 is 0x100. + * The Service Interrupt vector location for priority 0x14 is 0x140. + * The emulation IOCD will be stored at loation 0x700. + * The interrupt control instructions (DI, DI, RI, AI, DAI) will control + * the interrupt of the controller by addressing priority 0x14. * - * Example interrupt entry (RTOM) - * *INT28=16 - * The interrupt control instructions (DI, EI, RI, AI, DAI) will control - * the interrupt on the RTOM by addressing priority 0x28. - * The RTOM board is 1 - * The subaddress on the board is 0x06 (jumpered locic subaddress is 9) + * Example interrupt entry (RTOM) + * *INT28=16 + * The interrupt control instructions (DI, EI, RI, AI, DAI) will control + * the interrupt on the RTOM by addressing priority 0x28. + * The RTOM board is 1 + * The subaddress on the board is 0x06 (jumpered locic subaddress is 9) */ /* * Example ICL file - * *DEV04=0E150400,02 Cartridge disc with two platters - * *DEV08=0E160800,04 Moving head disc - * *DEV10=0E181000,04 9-Track magnetic tape - * *DEV20=0E1A2000,10 GPMC with 16 terminals - * *DEV60=0E1E6000,08 ADS - * *DEV78=01207800 Primary card reader - * *DEV7A=00217802 Primary line printer - * *DEV7E=02237801 Primary Teletype - * *INT00=1F Power fail/Auto restart - * *INT01=1E System Overide - * *INT12=1D Memory parity - * *INT13=1C Console Interrupt - * *INT24=1B Nonpresent memory - * *INT25=1A Undefined instruction trap - * *INT26=19 Privlege violation - * *INT27=18 Call Monitor - * *INT28=16 Real-time clock - * *INT29=17 Arithmetic exception - * *INT2A=15 External interrupt - * *INT2B=14 External interrupt - * *INT2C=13 External interrupt - * *INT2D=12 External interrupt + * *DEV04=0E150400,02 Cartridge disc with two platters + * *DEV08=0E160800,04 Moving head disc + * *DEV10=0E181000,04 9-Track magnetic tape + * *DEV20=0E1A2000,10 GPMC with 16 terminals + * *DEV60=0E1E6000,08 ADS + * *DEV78=01207800 Primary card reader + * *DEV7A=00217802 Primary line printer + * *DEV7E=02237801 Primary Teletype + * *INT00=1F Power fail/Auto restart + * *INT01=1E System Overide + * *INT12=1D Memory parity + * *INT13=1C Console Interrupt + * *INT24=1B Nonpresent memory + * *INT25=1A Undefined instruction trap + * *INT26=19 Privlege violation + * *INT27=18 Call Monitor + * *INT28=16 Real-time clock + * *INT29=17 Arithmetic exception + * *INT2A=15 External interrupt + * *INT2B=14 External interrupt + * *INT2C=13 External interrupt + * *INT2D=12 External interrupt * *END */ @@ -333,154 +331,154 @@ t_stat load_tap (FILE *fileref) */ t_value get_2hex(char *pt, uint32 *val) { - int32 hexval; - uint32 c1 = sim_toupper((uint32)pt[0]); /* first hex char */ - uint32 c2 = sim_toupper((uint32)pt[1]); /* next hex char */ + int32 hexval; + uint32 c1 = sim_toupper((uint32)pt[0]); /* first hex char */ + uint32 c2 = sim_toupper((uint32)pt[1]); /* next hex char */ - if (isdigit(c1)) /* digit */ - hexval = c1 - (uint32)'0'; /* get value */ - else - if (isxdigit(c1)) /* hex digit */ - hexval = c1 - (uint32)'A' + 10; /* get hex value */ - else - return SCPE_ARG; /* oops, error */ - hexval <<= 4; /* move to upper nibble */ - if (isdigit(c2)) /* digit */ - hexval += c2 - (uint32)'0'; /* get value */ - else - if (isxdigit(c2)) /* hex digit */ - hexval += c2 - (uint32)'A' + 10; /* get hex value */ - else - return SCPE_ARG; /* oops, error */ - *val = hexval; /* return value to caller */ - return SCPE_OK; /* all OK */ + if (isdigit(c1)) /* digit */ + hexval = c1 - (uint32)'0'; /* get value */ + else + if (isxdigit(c1)) /* hex digit */ + hexval = c1 - (uint32)'A' + 10; /* get hex value */ + else + return SCPE_ARG; /* oops, error */ + hexval <<= 4; /* move to upper nibble */ + if (isdigit(c2)) /* digit */ + hexval += c2 - (uint32)'0'; /* get value */ + else + if (isxdigit(c2)) /* hex digit */ + hexval += c2 - (uint32)'A' + 10; /* get hex value */ + else + return SCPE_ARG; /* oops, error */ + *val = hexval; /* return value to caller */ + return SCPE_OK; /* all OK */ } /* load an ICL file and configure SPAD interupt and device entries */ /* SPAD keyword will not be set and will be set when MPX or UTX is loaded */ /* return SCPE_OK on load complete */ -t_stat load_icl (FILE *fileref) +t_stat load_icl(FILE *fileref) { - char *cp; /* work pointer in buf[] */ - uint32 sa; /* spad address */ - uint32 dev; /* device entry */ - uint32 intr; /* interrupt entry */ - uint32 data; /* entry data */ - uint32 cls; /* device class */ - uint32 ivl; /* Interrupt Vector Location */ - int i; /* just a tmp */ - char buf[120]; /* input buffer */ + char *cp; /* work pointer in buf[] */ + uint32 sa; /* spad address */ + uint32 dev; /* device entry */ + uint32 intr; /* interrupt entry */ + uint32 data; /* entry data */ + uint32 cls; /* device class */ + uint32 ivl; /* Interrupt Vector Location */ + int i; /* just a tmp */ + char buf[120]; /* input buffer */ - /* read file input records until the end */ - while (fgets(&buf[0], 120, fileref) != 0) { - /* skip any white spaces */ - for(cp = &buf[0]; *cp == ' ' || *cp == '\t'; cp++); - if (*cp++ != '*') - continue; /* if line does not start with *, ignore */ - if(sim_strncasecmp(cp, "END", 3) == 0) { - return SCPE_OK; /* we are done */ - } - else - if(sim_strncasecmp(cp, "DEV", 3) == 0) { - /* process device entry */ - /* - |----+----+----+----+----+----+----+----| - |Flgs|CLS |0|Int Lev|0|Phy Adr|Sub Addr | - |----+----+----+----+----+----+----+----| - */ - for(cp += 3; *cp == ' ' || *cp == '\t'; cp++); /* skip white spaces */ - if (get_2hex(cp, &dev) != SCPE_OK) /* get the device address */ - return SCPE_ARG; /* unknown input, argument error */ - if (dev > 0x7f) /* devices are 0-7f (0-127) */ - return SCPE_ARG; /* argument error */ - sa = dev + 0x00; /* device entry spad address is dev# + 0x00 */ - cp += 2; /* skip the 2 processed chars */ - if (*cp++ != '=') /* must have = sign */ - return SCPE_ARG; /* unknown input, argument error */ - if (get_2hex(cp, &cls) != SCPE_OK) /* get unused '0" and class */ - return SCPE_ARG; /* unknown input, argument error */ - cp += 2; /* skip the 2 processed chars */ - if (get_2hex(cp, &intr) != SCPE_OK) /* get the interrupt level value */ - return SCPE_ARG; /* unknown input, argument error */ - if (intr > 0x6f) /* ints are 0-6f (0-111) */ - return SCPE_ARG; /* argument error */ - dev = ((~intr & 0x7f) << 16) | ((cls & 0x0f) << 24); /* put class and 1's intr in place */ - cp += 2; /* skip the 2 processed chars */ - if (get_2hex(cp, &data) != SCPE_OK) /* get the selbus physical address */ - return SCPE_ARG; /* unknown input, argument error */ - if (data > 0x7f) /* address is 0-7f (0-127) */ - return SCPE_ARG; /* argument error */ - dev |= (data & 0x7f) << 8; /* insert the physical address */ - cp += 2; /* skip the 2 processed chars */ - if (get_2hex(cp, &data) != SCPE_OK) /* get the starting sub address 0-ff (255) */ - return SCPE_ARG; /* unknown input, argument error */ - if (data > 0x7f) /* sub address is 0-ff (0-256) */ - return SCPE_ARG; /* argument error */ - if ((cls & 0xf) != 0xf) /* sub addr must be zero for class F */ - dev |= (data & 0xff); /* insert the starting sub address for non f class */ - SPAD[sa] = dev; /* put the first device entry into the spad */ - /* see if there is an optional device count for class 'E' I/O */ - if ((cls & 0xf) == 0xe) { - cp += 2; /* skip the 2 processed chars */ - if (*cp++ == ',') { /* must have comma if optional parameters */ - /* check for optional sub addr cnt */ - if (get_2hex(cp, &data) != SCPE_OK) /* get the count */ - return SCPE_ARG; /* unknown input, argument error */ - if (data > 0x10) /* sub address is max of 16 */ - return SCPE_ARG; /* argument error */ - for (i=0; i 0x7f) /* devices are 0-7f (0-127) */ + return SCPE_ARG; /* argument error */ + sa = dev + 0x00; /* device entry spad address is dev# + 0x00 */ + cp += 2; /* skip the 2 processed chars */ + if (*cp++ != '=') /* must have = sign */ + return SCPE_ARG; /* unknown input, argument error */ + if (get_2hex(cp, &cls) != SCPE_OK) /* get unused '0" and class */ + return SCPE_ARG; /* unknown input, argument error */ + cp += 2; /* skip the 2 processed chars */ + if (get_2hex(cp, &intr) != SCPE_OK) /* get the interrupt level value */ + return SCPE_ARG; /* unknown input, argument error */ + if (intr > 0x6f) /* ints are 0-6f (0-111) */ + return SCPE_ARG; /* argument error */ + dev = ((~intr & 0x7f) << 16) | ((cls & 0x0f) << 24); /* put class and 1's intr in place */ + cp += 2; /* skip the 2 processed chars */ + if (get_2hex(cp, &data) != SCPE_OK) /* get the selbus physical address */ + return SCPE_ARG; /* unknown input, argument error */ + if (data > 0x7f) /* address is 0-7f (0-127) */ + return SCPE_ARG; /* argument error */ + dev |= (data & 0x7f) << 8; /* insert the physical address */ + cp += 2; /* skip the 2 processed chars */ + if (get_2hex(cp, &data) != SCPE_OK) /* get the starting sub address 0-ff (255) */ + return SCPE_ARG; /* unknown input, argument error */ + if (data > 0x7f) /* sub address is 0-ff (0-256) */ + return SCPE_ARG; /* argument error */ + if ((cls & 0xf) != 0xf) /* sub addr must be zero for class F */ + dev |= (data & 0xff); /* insert the starting sub address for non f class */ + SPAD[sa] = dev; /* put the first device entry into the spad */ + /* see if there is an optional device count for class 'E' I/O */ + if ((cls & 0xf) == 0xe) { + cp += 2; /* skip the 2 processed chars */ + if (*cp++ == ',') { /* must have comma if optional parameters */ + /* check for optional sub addr cnt */ + if (get_2hex(cp, &data) != SCPE_OK) /* get the count */ + return SCPE_ARG; /* unknown input, argument error */ + if (data > 0x10) /* sub address is max of 16 */ + return SCPE_ARG; /* argument error */ + for (i=0; i 0x6f) /* ints are 0-6f (0-111) */ - return SCPE_ARG; /* argument error */ - sa = intr + 0x80; /* interrupt entry spad address is int# + 0x80 */ + sa = intr + 0x80; /* interrupt entry spad address is int# + 0x80 */ + ivl = (intr << 2) + 0x100; /* default IVL base is 0x100 for Concept machines */ + intr = (intr << 16) | ivl; /* combine int level and ivl */ + SPAD[sa] = intr; /* put the device interrupt entry into the spad */ + } + else + if(sim_strncasecmp(cp, "INT", 3) == 0) { + /* process interrupt entry */ + /* + |----+----+----+----+----+----+----+----| + | Flags |1RRR|SSSS| Int IVL | + |----+----+----+----+----+----+----+----| + */ + for(cp += 3; *cp == ' ' || *cp == '\t'; cp++); /* skip white spaces */ + if (get_2hex(cp, &intr) != SCPE_OK) /* get the interrupt level value */ + return SCPE_ARG; /* unknown input, argument error */ + if (intr > 0x6f) /* ints are 0-6f (0-111) */ + return SCPE_ARG; /* argument error */ + sa = intr + 0x80; /* interrupt entry spad address is int# + 0x80 */ /* TODO call function here to create 32/7x IVL location for interrupt */ /* if (CPU_MODEL < MODEL_27) get_IVL(intr, &ivl); */ - ivl = (intr << 2) + 0x100; /* default IVL base is 0x100 for Concept machines */ - cp += 2; /* skip the 2 processed chars */ - if (*cp++ != '=') /* must have = sign */ - return SCPE_ARG; /* unknown input, argument error */ - if (get_2hex(cp, &data) != SCPE_OK) - return SCPE_ARG; /* unknown input, argument error */ - /* first digit is 3 ls bits of RTOM addr 0x79 is 001 */ - intr = 0x00800000 | ((data & 0x70) << 16); /* put the RTOM 3 LSBs into entry */ - /* second digit is subaddress on RTOM board for interrupt connection, ~6 = 9 */ - intr |= (data & 0xf) << 16; /* put in 1's comp of RTOM subaddress */ - /* add in the correct IVL for 32/7x or concelt machines */ - intr |= ivl; /* set the IVL location */ - SPAD[sa] = intr; /* put the interrupt entry into the spad */ - } - else - return SCPE_ARG; /* unknown input, argument error */ - } - return SCPE_OK; /* file done */ + ivl = (intr << 2) + 0x100; /* default IVL base is 0x100 for Concept machines */ + cp += 2; /* skip the 2 processed chars */ + if (*cp++ != '=') /* must have = sign */ + return SCPE_ARG; /* unknown input, argument error */ + if (get_2hex(cp, &data) != SCPE_OK) + return SCPE_ARG; /* unknown input, argument error */ + /* first digit is 3 ls bits of RTOM addr 0x79 is 001 */ + intr = 0x00800000 | ((data & 0x70) << 16); /* put the RTOM 3 LSBs into entry */ + /* second digit is subaddress on RTOM board for interrupt connection, ~6 = 9 */ + intr |= (data & 0xf) << 16; /* put in 1's comp of RTOM subaddress */ + /* add in the correct IVL for 32/7x or concelt machines */ + intr |= ivl; /* set the IVL location */ + SPAD[sa] = intr; /* put the interrupt entry into the spad */ + } + else + return SCPE_ARG; /* unknown input, argument error */ + } + return SCPE_OK; /* file done */ } @@ -499,46 +497,44 @@ t_stat load_icl (FILE *fileref) #define FMT_ICL 3 t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) { - uint32 data; - int32 fmt, wc; + int32 fmt; - fmt = FMT_NONE; /* no format */ - /* match the extension to .mem for this file */ - if (match_ext(fnam, "MEM")) - fmt = FMT_MEM; /* we have binary format */ - else + fmt = FMT_NONE; /* no format */ + /* match the extension to .mem for this file */ + if (match_ext(fnam, "MEM")) + fmt = FMT_MEM; /* we have binary format */ + else #ifdef NO_TAP_FOR_NOW - if (match_ext(fnam, "TAP")) - fmt = FMT_TAP; /* we have tap tape format */ - else + if (match_ext(fnam, "TAP")) + fmt = FMT_TAP; /* we have tap tape format */ + else #endif - /* match the extension to .icl for this file */ - if (match_ext(fnam, "ICL")) - fmt = FMT_ICL; /* we have initial configuration load (ICL) format */ - else - SCPE_FMT; /* we have format error */ + /* match the extension to .icl for this file */ + if (match_ext(fnam, "ICL")) + fmt = FMT_ICL; /* we have initial configuration load (ICL) format */ + else + return SCPE_FMT; /* format error */ - switch (fmt) { + switch (fmt) { - case FMT_MEM: /* binary memory image */ - return load_mem(fileref); + case FMT_MEM: /* binary memory image */ + return load_mem(fileref); #ifdef NO_TAP_FOR_NOW - case FMT_TAP: /* tape file image */ - return load_tap(fileref); + case FMT_TAP: /* tape file image */ + return load_tap(fileref); #endif - case FMT_ICL: /* icl file image */ - return load_icl(fileref); + case FMT_ICL: /* icl file image */ + return load_icl(fileref); - case FMT_NONE: /* nothing */ - default: - break; - } - return SCPE_FMT; /* format error */ + case FMT_NONE: /* nothing */ + default: + break; + } + return SCPE_FMT; /* format error */ } - /* Symbol tables */ /* @@ -558,6 +554,7 @@ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) * K RBT d,b d,b * L EXR s s * M IOP n,b n,b + * N SVC n,b n,b */ #define TYPE_A 0 @@ -572,11 +569,12 @@ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) #define TYPE_K 9 #define TYPE_L 10 #define TYPE_M 11 -#define H 0x10 /* halfword instruction */ +#define TYPE_N 12 +#define H 0x10 /* halfword instruction */ /* all instruction unless specified as base/nobase only will be either */ -#define B 0x20 /* base register mode only */ -#define N 0x40 /* non base register mode only */ -#define X 0x80 /* 32/55 or 32/75 only */ +#define B 0x20 /* base register mode only */ +#define N 0x40 /* non base register mode only */ +#define X 0x80 /* 32/55 or 32/75 only */ typedef struct _opcode { uint16 opbase; @@ -655,7 +653,7 @@ t_opcode optab[] = { { 0x2C0E, 0xFC0F, H|TYPE_F, "TRSC", }, /* Transfer Register to Scratchpad # * */ { 0x2C0F, 0xFC0F, H|TYPE_F, "TSCR", }, /* Transfer Scratchpad to Register # * */ { 0x3000, 0xFC0F, X|H|TYPE_F, "CALM", }, /* Call Monitor 32/55 # */ - { 0x3400, 0xFC0F, N|TYPE_D, "LA", }, /* Load Address NBR Note! FW instruction */ + { 0x3400, 0xFC08, N|TYPE_D, "LA", }, /* Load Address NBR Note! FW instruction */ { 0x3800, 0xFC0F, H|TYPE_F, "ADR", }, /* Add Register to Register # */ { 0x3801, 0xFC0F, H|TYPE_F, "ADRFW", }, /* Add Floating Point to Register # */ { 0x3802, 0xFC0F, B|H|TYPE_F, "MPR", }, /* Multiply Register BR # */ @@ -686,7 +684,7 @@ t_opcode optab[] = { { 0x6000, 0xFC0F, N|H|TYPE_F, "NOR", }, /* Normalize # NBR Only */ { 0x6400, 0xFC0F, N|H|TYPE_F, "NORD", }, /* Normalize Double # NBR Only */ { 0x6800, 0xFC0F, N|H|TYPE_F, "SCZ", }, /* Shift and Count Zeros # */ - { 0x6C00, 0xFC0F, N|H|TYPE_I, "SRA", }, /* Shift Right Arithmetic # NBR */ + { 0x6C00, 0xFC40, N|H|TYPE_I, "SRA", }, /* Shift Right Arithmetic # NBR */ { 0x6C40, 0xFC40, N|H|TYPE_I, "SLA", }, /* Shift Left Arithmetic # NBR */ { 0x7000, 0xFC40, N|H|TYPE_I, "SRL", }, /* Shift Right Logical # NBR */ { 0x7040, 0xFC40, N|H|TYPE_I, "SLL", }, /* Shift Left Logical # NBR */ @@ -720,7 +718,7 @@ t_opcode optab[] = { { 0xC803, 0xFC0F, TYPE_C, "MPI", }, /* Multiply Immediate */ { 0xC804, 0xFC0F, TYPE_C, "DVI", }, /* Divide Immediate */ { 0xC805, 0xFC0F, TYPE_C, "CI", }, /* Compare Immediate */ - { 0xC806, 0xFC0F, TYPE_C, "SVC", }, /* Supervisor Call */ + { 0xC806, 0xFC0F, TYPE_N, "SVC", }, /* Supervisor Call */ { 0xC807, 0xFC0F, TYPE_G, "EXR", }, /* Execute Register/ Right */ { 0xC808, 0xFC0F, X|TYPE_A, "SEM", }, /* Store External Map 32/7X * */ { 0xC809, 0xFC0F, X|TYPE_A, "LEM", }, /* Load External Map 32/7X * */ @@ -744,20 +742,22 @@ t_opcode optab[] = { { 0xED80, 0xFF80, TYPE_B, "BLT", }, /* Branch Condition True CC3 = 1 */ { 0xEE00, 0xFF80, TYPE_B, "BEQ", }, /* Branch Condition True CC4 = 1 */ { 0xEE80, 0xFF80, TYPE_B, "BGE", }, /* Branch Condition True CC2|CC4 = 1 */ - { 0xEF00, 0xFF80, TYPE_B, "BLE", }, /* Branch Condition True CC3|CC4 = 1*/ + { 0xEF00, 0xFF80, TYPE_B, "BLE", }, /* Branch Condition True CC3|CC4 = 1 */ { 0xEF80, 0xFF80, TYPE_B, "BANY", }, /* Branch Condition True CC1|CC2|CC3|CC4 */ { 0xF000, 0XFF80, TYPE_B, "BFT", }, /* Branch Function True */ + { 0xF000, 0xFF80, TYPE_A, "BCF", }, /* Branch Condition False */ { 0xF080, 0xFF80, TYPE_B, "BNS", }, /* Branch Condition False CC1 = 0 */ { 0xF100, 0xFF80, TYPE_B, "BNP", }, /* Branch Condition False CC2 = 0 */ { 0xF180, 0xFF80, TYPE_B, "BNN", }, /* Branch Condition False CC3 = 0 */ { 0xF200, 0xFF80, TYPE_B, "BNE", }, /* Branch Condition False CC4 = 0 */ + { 0xF280, 0xFF80, TYPE_B, "BCF 5,", }, /* Branch Condition False CC2|CC4 = 0 */ + { 0xF300, 0xFF80, TYPE_B, "BCF 6,", }, /* Branch Condition False CC3|CC4 = 0 */ { 0xF380, 0xFF80, TYPE_B, "BAZ", }, /* Branch Condition False CC1|CC2|CC3|CC4=0*/ - { 0xF000, 0xFF80, TYPE_A, "BCF", }, /* Branch Condition False */ { 0xF400, 0xFC70, TYPE_D, "BIB", }, /* Branch after Incrementing Byte */ - { 0xF420, 0xFC70, TYPE_D, "BIW", }, /* Branch after Incrementing Word */ - { 0xF440, 0xFC70, TYPE_D, "BIH", }, /* Branch after Incrementing Half */ + { 0xF420, 0xFC70, TYPE_D, "BIH", }, /* Branch after Incrementing Half */ + { 0xF440, 0xFC70, TYPE_D, "BIW", }, /* Branch after Incrementing Word */ { 0xF460, 0xFC70, TYPE_D, "BID", }, /* Branch after Incrementing Double */ - { 0xF800, 0xFCC0, TYPE_E, "ZM", }, /* Zero Memory B,H,W,D */ + { 0xF800, 0xFF80, TYPE_E, "ZM", }, /* Zero Memory B,H,W,D */ { 0xF880, 0xFF80, TYPE_B, "BL", }, /* Branch and Link */ { 0xF900, 0xFCC0, X|TYPE_B, "BRI", }, /* Branch and Reset Interrupt 32/55 * */ { 0xF980, 0xFF80, TYPE_B, "LPSD", }, /* Load Program Status Double * */ @@ -765,13 +765,13 @@ t_opcode optab[] = { { 0xFA80, 0xFF80, TYPE_B, "LPSDCM", }, /* LPSD and Change Map * */ { 0xFB00, 0xFCC0, X|TYPE_A, "TRP", }, /* Transfer Register to Protect Register 32/7X */ { 0xFB80, 0xFCC0, X|TYPE_A, "TPR", }, /* Transfer Protect Register to Register 32/7X */ - { 0xFC00, 0xFC0F, TYPE_L, "EI", }, /* Enable Interrupt */ - { 0xFC01, 0xFC0F, TYPE_L, "DI", }, /* Disable Interrupt */ - { 0xFC02, 0xFC0F, TYPE_L, "RI", }, /* Request Interrupt */ - { 0xFC03, 0xFC0F, TYPE_L, "AI", }, /* Activate Interrupt */ - { 0xFC04, 0xFC0F, TYPE_L, "DAI", }, /* Deactivate Interrupt */ - { 0xFC05, 0xFC0F, TYPE_M, "TD", }, /* Test Device */ - { 0xFC06, 0xFC0F, TYPE_M, "CD", }, /* Command Device */ + { 0xFC00, 0xFC07, TYPE_L, "EI", }, /* Enable Interrupt */ + { 0xFC01, 0xFC07, TYPE_L, "DI", }, /* Disable Interrupt */ + { 0xFC02, 0xFC07, TYPE_L, "RI", }, /* Request Interrupt */ + { 0xFC03, 0xFC07, TYPE_L, "AI", }, /* Activate Interrupt */ + { 0xFC04, 0xFC07, TYPE_L, "DAI", }, /* Deactivate Interrupt */ + { 0xFC05, 0xFC07, TYPE_M, "TD", }, /* Test Device */ + { 0xFC06, 0xFC07, TYPE_M, "CD", }, /* Command Device */ { 0xFC17, 0xFC7F, TYPE_C, "SIO", }, /* Start I/O */ { 0xFC1F, 0xFC7F, TYPE_C, "TIO", }, /* Test I/O */ { 0xFC27, 0xFC7F, TYPE_C, "STPIO", }, /* Stop I/O */ @@ -787,172 +787,179 @@ t_opcode optab[] = { { 0xFC7F, 0xFC7F, TYPE_C, "DACI", }, /* Deactivate Channel Interrupt */ }; - /* Instruction decode printing routine Inputs: *of = output stream - val = 16/32 bit instruction to print left justified + val = 16/32 bit instruction to print left justified sw = mode switches, 'M'=base mode, 'N'=nonbase mode */ -char *fc_type = "WHDHBBBB"; /* F & C bit values */ +char *fc_type = "WHDHBBBB"; /* F & C bit values */ -int fprint_inst(FILE *of, uint32 val, int32 sw) { -uint16 inst = (val >> 16) & 0xFFFF; -uint32 v = 0;; -int i; -int mode = 0; /* assume non base mode instructions */ -t_opcode *tab; +int fprint_inst(FILE *of, uint32 val, int32 sw) +{ + uint16 inst = (val >> 16) & 0xFFFF; + int i; + int mode = 0; /* assume non base mode instructions */ + t_opcode *tab; #ifdef DO_THIS_UNTIL_FIGURE_IT_OUT - if (sw & SWMASK('M')) /* Base mode printing */ - mode = 1; + if (sw & SWMASK('M')) /* Base mode printing */ + mode = 1; #else - if (PSD[0] & 0x02000000) /* bit 6 is base mode */ - mode = 1; + if (PSD[0] & 0x02000000) /* bit 6 is base mode */ + mode = 1; #endif - /* loop through the instruction table for an opcode match and get the type */ - for (tab = optab; tab->name != NULL; tab++) { - if (tab->opbase == (inst & tab->mask)) { - if (mode && (tab->type & (X | N))) - continue; /* non basemode instruction in base mode, skip */ - if (!mode && (tab->type & B)) - continue; /* basemode instruction in nonbase mde, skip */ + /* loop through the instruction table for an opcode match and get the type */ + for (tab = optab; tab->name != NULL; tab++) { + if (tab->opbase == (inst & tab->mask)) { + if (mode && (tab->type & (X | N))) + continue; /* non basemode instruction in base mode, skip */ + if (!mode && (tab->type & B)) + continue; /* basemode instruction in nonbase mde, skip */ - /* TODO? Maybe want to make sure MODEL is 32/7X for X type instructions */ + /* TODO? Maybe want to make sure MODEL is 32/7X for X type instructions */ - /* match found */ - fputs(tab->name, of); /* output the base opcode */ + /* match found */ + fputs(tab->name, of); /* output the base opcode */ - /* process the other fields of the instruction */ - switch(tab->type & 0xF) { - /* memory reference instruction */ - case TYPE_A: /* r,[*]o[,x] or r,o[(b)][,x] */ - /* zero memory instruction */ - case TYPE_E: /* [*]o[,x] or o[(b)][,x] */ - /* append B, H, W, D to base instruction using F & C bits */ - i = (val & 3) | ((inst >> 1) & 04); - fputc(fc_type[i], of); - /* Fall through */ + /* process the other fields of the instruction */ + switch(tab->type & 0xF) { + /* memory reference instruction */ + case TYPE_A: /* r,[*]o[,x] or r,o[(b)][,x] */ + /* zero memory instruction */ + case TYPE_E: /* [*]o[,x] or o[(b)][,x] */ + /* append B, H, W, D to base instruction using F & C bits */ + i = (val & 3) | ((inst >> 1) & 04); + if (((inst&0xfc00) != 0xdc00) && ((inst&0xfc00) != 0xcc00) && + ((inst&0xfc00) != 0x8000)) + fputc(fc_type[i], of); + /* Fall through */ - /* BIx instructions or memory reference instructions */ - case TYPE_D: /* r,[*]o[,x] or r,o[(b)],[,x] */ - fputc(' ', of); - if ((tab->type & 0xf) != TYPE_E) { - /* output the reg or bit number */ - fputc('0'+((inst>>7) & 07), of); - fputc(',', of); - } - /* Fall through */ + /* BIx instructions or bit in memory reference instructions */ + case TYPE_D: /* r,[*]o[,x] or r,o[(b)],[,x] */ + if ((tab->type & 0xF) != TYPE_E) { + fputc(' ', of); + /* output the reg or bit number */ + fputc('0'+((inst>>7) & 07), of); + fputc(',', of); + } + /* Fall through */ - /* branch instruction */ - case TYPE_B: /* [*]o[,x] or o[(b)],[,x] */ - if (((tab->type & 0xf) != TYPE_A) && ((tab->type & 0xf) != TYPE_D)) - fputc(' ', of); - if (mode) { - /* base reg mode */ - fprint_val(of, val&0xffff, 16, 16, PV_RZRO); /* output 16 bit offset */ - if (inst & 07) { - fputc('(', of); - fputc('0' + (inst & 07), of); /* output the base reg number */ - fputc(')', of); - } - if (inst & 0x70) { - fputc(',', of); - fputc('0'+(inst >> 4) & 07, of); /* output the index reg number */ - } - } else { - /* nonbase reg mode */ - if (inst & 0x10) - fputc('*', of); /* show indirection */ -// fprint_val(of, val, 16, 19, PV_RZRO); /* 19 bit offset */ -// fprint_val(of, val&0x7ffff, 16, 19, PV_RZRO); /* 19 bit offset */ -// fprint_val(of, val&0x7ffff, 16, 19, PV_RSPC); /* 19 bit offset */ - fprint_val(of, val&0x7ffff, 16, 19, PV_LEFT); /* 19 bit offset */ - if (inst & 0x60) { - fputc(',', of); -// fputc('0'+((inst & 0x60) >> 5) & 03, of); /* output the index reg number */ - fputc('0'+((inst & 0x60) >> 5), of); /* output the index reg number */ - } - } - break; + /* branch instruction */ + case TYPE_B: /* [*]o[,x] or o[(b)],[,x] */ + if (((tab->type & 0xf) != TYPE_A) && ((tab->type & 0xf) != TYPE_D)) + fputc(' ', of); + if (mode) { + /* base reg mode */ + fprint_val(of, val&0xffff, 16, 16, PV_RZRO); /* output 16 bit offset */ + if (inst & 07) { + fputc('(', of); + fputc(('0'+(inst & 07)), of); /* output the base reg number */ + fputc(')', of); + } + if (inst & 0x70) { + fputc(',', of); + fputc(('0'+((inst >> 4) & 07)), of); /* output the index reg number */ + } + } else { + /* nonbase reg mode */ + if (inst & 0x10) + fputc('*', of); /* show indirection */ + fprint_val(of, val&0x7ffff, 16, 19, PV_LEFT); /* 19 bit offset */ + if (inst & 0x60) { + fputc(',', of); /* register coming */ + if (tab->type != TYPE_D) + fputc('0'+((inst & 0x60) >> 5), of); /* output the index reg number */ + else { + if ((inst & 0xfc00) != 0xf400) + fputc('0'+((inst & 0x60) >> 5), of); /* output the index reg number */ + } + } + } + break; - /* immediate or XIO instructions */ - case TYPE_C: /* r,v */ - fputc(' ', of); - fputc('0'+((inst>>7) & 07), of); /* index reg number */ - fputc(',', of); -// fprint_val(of, val&0xffff, 16, 16, PV_RZRO); /* 16 bit imm val or chan/suba */ - fprint_val(of, val&0xffff, 16, 16, PV_LEFT); /* 16 bit imm val or chan/suba */ - break; + /* immediate or XIO instructions */ + case TYPE_C: /* r,v */ + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); /* index reg number */ + fputc(',', of); + fprint_val(of, val&0xffff, 16, 16, PV_LEFT); /* 16 bit imm val or chan/suba */ + break; - /* reg - reg instructions */ - case TYPE_F: /* rs,rd */ - fputc(' ', of); - fputc('0'+((inst>>4) & 07), of); /* src reg */ - fputc(',', of); - fputc('0'+((inst>>7) & 07), of); /* dest reg */ - break; + /* reg - reg instructions */ + case TYPE_F: /* rs,rd */ + fputc(' ', of); + fputc('0'+((inst>>4) & 07), of); /* src reg */ + fputc(',', of); + fputc('0'+((inst>>7) & 07), of); /* dest reg */ + break; - /* single reg instructions */ - case TYPE_G: /* op r */ - fputc(' ', of); - fputc('0'+((inst>>7) & 07), of); /* output src/dest reg num */ - break; + /* single reg instructions */ + case TYPE_G: /* op r */ + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); /* output src/dest reg num */ + break; - /* just output the instruction */ - case TYPE_H: /* empty */ - break; + /* just output the instruction */ + case TYPE_H: /* empty */ + break; - /* reg and bit shift cnt */ - case TYPE_I: /* r,b */ - fputc(' ', of); - fputc('0'+((inst>>7) & 07), of); /* reg number */ - fputc(',', of); -// fprint_val(of, inst&0x1f, 10, 5, PV_RZRO); /* 5 bit shift count */ - fprint_val(of, inst&0x1f, 10, 5, PV_LEFT); /* 5 bit shift count */ - break; + /* reg and bit shift cnt */ + case TYPE_I: /* r,b */ + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); /* reg number */ + fputc(',', of); + fprint_val(of, inst&0x1f, 10, 5, PV_LEFT); /* 5 bit shift count */ + break; - /* register bit operations */ - case TYPE_K: /* r,rb */ - fputc(' ', of); - fputc('0'+((inst>>4) & 07), of); /* register number */ - fputc(',', of); - i = ((inst & 3) << 3) | ((inst >> 7) & 07); -// fprint_val(of, i, 16, 5, PV_RZRO); /* reg bit number to operate on */ - fprint_val(of, i, 10, 5, PV_LEFT); /* reg bit number to operate on */ - break; + /* register bit operations */ + case TYPE_K: /* r,rb */ + fputc(' ', of); + fputc('0'+((inst>>4) & 07), of); /* register number */ + fputc(',', of); + i = ((inst & 3) << 3) | ((inst >> 7) & 07); + fprint_val(of, i, 10, 5, PV_LEFT); /* reg bit number to operate on */ + break; - /* interrupt control instructions */ - case TYPE_L: /* i */ - fputc(' ', of); - fprint_val(of, inst>>3, 16, 7, PV_RZRO); /* output 7 bit priority level value */ - break; + /* interrupt control instructions */ + case TYPE_L: /* i */ + fputc(' ', of); + fprint_val(of, (inst>>3)&0x7f, 16, 7, PV_RZRO); /* output 7 bit priority level value */ + break; - /* CD/TD Class E I/O instructions */ - case TYPE_M: /* i,v */ - fputc(' ', of); - fprint_val(of, inst>>3, 16, 7, PV_RZRO); /* output 7 bit device address */ - fputc(',', of); - fprint_val(of, val, 16, 16, PV_RZRO); /* output 16 bit command code */ - break; + /* CD/TD Class E I/O instructions */ + case TYPE_M: /* i,v */ + fputc(' ', of); + fprint_val(of, (inst>>3)&0x7f, 16, 7, PV_RZRO); /* output 7 bit device address */ + fputc(',', of); + fprint_val(of, (val&0xffff), 16, 16, PV_RZRO); /* output 16 bit command code */ + break; - default: - /* FIXME - return error code here? */ -// /* fputs(" unknown type", of); /* output error message */ -// return SCPE_ARG; /* unknown type */ - break; - } - /* return the size of the instruction */ - return (tab->type & H) ? 2 : 4; - } - } - /* FIXME - should we just return error here? or dump as hex data? */ - /* we get here if opcode not found, print data value */ - fputs(" invld ", of); /* output error message */ - fprint_val(of, val, 16, 32, PV_RZRO); /* output unknown 32 bit instruction code */ - return 4; /* show as full word size */ -// return SCPE_UNK; /* unknown opcode */ + /* SVC instructions */ + case TYPE_N: /* i,v */ + fputc(' ', of); + fprint_val(of, (val>>12)&0xf, 16, 4, PV_RZRO); /* output 4 bit svc number */ + fputc(',', of); + fprint_val(of, (val & 0xFFF), 16, 12, PV_LEFT); /* output 12 bit command code */ + break; + + default: + /* FIXME - return error code here? */ +// /* fputs(" unknown type", of); /* output error message */ +// return SCPE_ARG; /* unknown type */ + break; + } + /* return the size of the instruction */ + return (tab->type & H) ? 2 : 4; + } + } + /* FIXME - should we just return error here? or dump as hex data? */ + /* we get here if opcode not found, print data value */ + fputs(" invld ", of); /* output error message */ + fprint_val(of, val, 16, 32, PV_RZRO); /* output unknown 32 bit instruction code */ + return 4; /* show as full word size */ +// return SCPE_UNK; /* unknown opcode */ } /* Symbolic decode @@ -968,67 +975,64 @@ t_opcode *tab; */ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { - int i; - int l = 1; - int rdx = 16; - t_opcode *tab; - uint32 num, tmp=*val; + int i; + int l = 1; + int rdx = 16; + uint32 num, tmp=*val; - /* determine base for number output */ - if (sw & SWMASK ('D')) - rdx = 10; /* decimal */ - else - if (sw & SWMASK ('O')) - rdx = 8; /* octal */ - else - if (sw & SWMASK ('H')) - rdx = 16; /* hex */ + /* determine base for number output */ + if (sw & SWMASK ('D')) + rdx = 10; /* decimal */ + else + if (sw & SWMASK ('O')) + rdx = 8; /* octal */ + else + if (sw & SWMASK ('H')) + rdx = 16; /* hex */ - if (sw & SWMASK ('M')) { /* machine base mode? */ - sw &= ~ SWMASK('F'); /* Can't do F and M at same time */ - } else - if (sw & SWMASK('F')) { - l = 4; /* words are 4 bytes */ - } else - if (sw & SWMASK('W')) { - l = 2; /* halfwords are 2 bytes */ - } else - if (sw & SWMASK('B')) { - l = 1; /* bytes */ - } + if (sw & SWMASK ('M')) { /* machine base mode? */ + sw &= ~ SWMASK('F'); /* Can't do F and M at same time */ + } else + if (sw & SWMASK('F')) { + l = 4; /* words are 4 bytes */ + } else + if (sw & SWMASK('W')) { + l = 2; /* halfwords are 2 bytes */ + } else + if (sw & SWMASK('B')) { + l = 1; /* bytes */ + } - if (sw & SWMASK ('C')) { - fputc('\'', of); /* opening apostorphe */ - for(i = 0; i < l; i++) { - char ch = val[i] & 0xff; /* get the char */ - if (ch >= 0x20 && ch <= 0x7f) /* see if printable */ - fprintf(of, "%c", ch); /* output the ascii char */ - else - fputc('_', of); /* use underscore for unprintable char */ - } - fputc('\'', of); /* closing apostorphe */ - } else - /* go print the symbolic instruction for base or nonbase mode */ -// if ((addr & 1) == 0 && sw & (SWMASK('M') | SWMASK('N'))) { - if (sw & (SWMASK('M') | SWMASK('N'))) { - unsigned char ch; - num = 0; - for (i = 0; i < 4; i++) { - ch = tmp & 0xff; /* get the char */ - num |= (uint32)ch << ((3-i) * 8); /* get byte swapped 16/32 bit instruction */ -// tmp >>= 8; /* next char */ - } - if (addr & 0x02) - tmp <<= 16; /* use rt hw */ - l = fprint_inst(of, tmp, sw); /* go print the instruction */ - } else { - /* print the numeric value of the memory data */ - num = 0; - for (i = 0; i < l && i < 4; i++) - num |= (uint32)val[i] << ((l-i-1) * 8); /* collect 8-32 bit data value to print */ - fprint_val(of, num, rdx, l*8, PV_RZRO); /* print it in requested radix */ - } - return -(l-1); /* will be negative if we did anything */ + if (sw & SWMASK ('C')) { + fputc('\'', of); /* opening apostorphe */ + for(i = 0; i < l; i++) { + char ch = val[i] & 0xff; /* get the char */ + if (ch >= 0x20 && ch <= 0x7f) /* see if printable */ + fprintf(of, "%c", ch); /* output the ascii char */ + else + fputc('_', of); /* use underscore for unprintable char */ + } + fputc('\'', of); /* closing apostorphe */ + } else + /* go print the symbolic instruction for base or nonbase mode */ + if (sw & (SWMASK('M') | SWMASK('N'))) { + unsigned char ch; + num = 0; + for (i = 0; i < 4; i++) { + ch = tmp & 0xff; /* get the char */ + num |= (uint32)ch << ((3-i) * 8); /* get byte swapped 16/32 bit instruction */ + } + if (addr & 0x02) + tmp <<= 16; /* use rt hw */ + l = fprint_inst(of, tmp, sw); /* go print the instruction */ + } else { + /* print the numeric value of the memory data */ + num = 0; + for (i = 0; i < l && i < 4; i++) + num |= (uint32)val[i] << ((l-i-1) * 8); /* collect 8-32 bit data value to print */ + fprint_val(of, num, rdx, l*8, PV_RZRO); /* print it in requested radix */ + } + return -(l-1); /* will be negative if we did anything */ } /* @@ -1036,22 +1040,24 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) */ t_stat get_off (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val, char *m) { - t_stat r = SCPE_OK; /* assume OK return */ + t_stat r = SCPE_OK; /* assume OK return */ - *m = 0; /* left parend found flag if set */ - *val = (uint32)strtotv (cptr, tptr, radix); /* convert to value */ - if (cptr == *tptr) - r = SCPE_ARG; /* no argument found error */ - else { - cptr = *tptr; /* where to start looking */ - while (sim_isspace (*cptr)) cptr++; /* skip any spaces */ - if (*cptr++ == '(') { - *m = 1; /* show we found a left parend */ - while (sim_isspace (*cptr)) cptr++; /* skip any spaces */ - } - *tptr = cptr; /* reteurn next char pointer */ - } - return r; /* return status */ + *m = 0; /* left parend found flag if set */ + *val = (uint32)strtotv(cptr, tptr, radix); /* convert to value */ + if (cptr == *tptr) + r = SCPE_ARG; /* no argument found error */ + else { + cptr = *tptr; /* where to start looking */ + while (sim_isspace(*cptr)) + cptr++; /* skip any spaces */ + if (*cptr++ == '(') { + *m = 1; /* show we found a left parend */ + while (sim_isspace(*cptr)) + cptr++; /* skip any spaces */ + } + *tptr = cptr; /* return next char pointer */ + } + return r; /* return status */ } /* @@ -1059,18 +1065,18 @@ t_stat get_off (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val, */ t_stat get_imm (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val) { - t_stat r; + t_stat r; - r = SCPE_OK; - *val = (uint32)strtotv (cptr, tptr, radix); - if ((cptr == *tptr) || (*val > 0xffff)) - r = SCPE_ARG; - else { - cptr = *tptr; - while (sim_isspace (*cptr)) cptr++; - *tptr = cptr; - } - return r; + r = SCPE_OK; + *val = (uint32)strtotv (cptr, tptr, radix); + if ((cptr == *tptr) || (*val > 0xffff)) + r = SCPE_ARG; + else { + cptr = *tptr; + while (sim_isspace (*cptr)) cptr++; + *tptr = cptr; + } + return r; } /* Symbolic input @@ -1087,450 +1093,492 @@ t_stat get_imm (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val) t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { - int i; - int x; - int l = 1; - int rdx = 16; - char mod = 0; - t_opcode *tab; - t_stat r; - uint32 num; - uint32 max[5] = { 0, 0xff, 0xffff, 0, 0xffffffff }; - CONST char *tptr; - char gbuf[CBUFSIZE]; + int i; + int x; + int l = 1; + int rdx = 16; + char mod = 0; + t_opcode *tab; + t_stat r; + uint32 num; + uint32 max[5] = {0, 0xff, 0xffff, 0, 0xffffffff}; + CONST char *tptr; + char gbuf[CBUFSIZE]; - /* determine base for numbers */ - if (sw & SWMASK ('D')) - rdx = 10; /* decimal */ - else - if (sw & SWMASK ('O')) - rdx = 8; /* octal */ - else - if (sw & SWMASK ('H')) - rdx = 16; /* hex */ + /* determine base for numbers */ + if (sw & SWMASK ('D')) + rdx = 10; /* decimal */ + else + if (sw & SWMASK ('O')) + rdx = 8; /* octal */ + else + if (sw & SWMASK ('H')) + rdx = 16; /* hex */ - /* set instruction size */ - if (sw & SWMASK('F')) { - l = 4; - } else - if (sw & SWMASK('W')) { - l = 2; - } + /* set instruction size */ + if (sw & SWMASK('F')) { + l = 4; + } else + if (sw & SWMASK('W')) { + l = 2; + } - /* process a character string */ - if (sw & SWMASK ('C')) { - cptr = get_glyph_quoted(cptr, gbuf, 0); /* Get string */ - for(i = 0; gbuf[i] != 0; i++) { - val[i] = gbuf[i]; /* copy in the string */ - } - return -(i - 1); - } + /* process a character string */ + if (sw & SWMASK ('C')) { + cptr = get_glyph_quoted(cptr, gbuf, 0); /* Get string */ + for(i = 0; gbuf[i] != 0; i++) { + val[i] = gbuf[i]; /* copy in the string */ + } + return -(i - 1); + } - /* see if we are processing a nonbase instruction */ - if (sw & SWMASK ('N')) { - /* process nonbased instruction */ - cptr = get_glyph(cptr, gbuf, 0); /* Get uppercase opcode */ - l = strlen(gbuf); /* opcode length */ - /* try to find the opcode in the table */ - for (tab = optab; tab->name != NULL; tab++) { - i = tab->type & 0xf; /* get the instruction type */ - /* check for memory reference instruction */ - if (i == TYPE_A || i == TYPE_E) { - /* test for base opcode name without B, H, W, D applied */ - if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0) - break; /* found */ - } else - /* test the full opcode name */ - if (sim_strcasecmp(tab->name, gbuf) == 0) - break; /* found */ - } - if (tab->name == NULL) /* see if anything found */ - return SCPE_ARG; /* no, return invalid argument error */ - num = tab->opbase<<16; /* get the base opcode value */ + /* see if we are processing a nonbase instruction */ + if (sw & SWMASK ('N')) { + /* process nonbased instruction */ + cptr = get_glyph(cptr, gbuf, 0); /* Get uppercase opcode */ + l = strlen(gbuf); /* opcode length */ + /* try to find the opcode in the table */ + for (tab = optab; tab->name != NULL; tab++) { + i = tab->type & 0xf; /* get the instruction type */ + /* check for memory reference instruction */ + if (i == TYPE_A || i == TYPE_E) { + /* test for base opcode name without B, H, W, D applied */ + if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0) + break; /* found */ + } else + /* test the full opcode name */ + if (sim_strcasecmp(tab->name, gbuf) == 0) + break; /* found */ + } + if (tab->name == NULL) /* see if anything found */ + return SCPE_ARG; /* no, return invalid argument error */ + num = tab->opbase<<16; /* get the base opcode value */ - /* process each instruction type */ - switch(i) { - /* mem ref instruction */ - case TYPE_A: /* c r,[*]o[,x] */ - /* zero memory instruction */ - case TYPE_E: /* c [*]o[,x] */ - switch(gbuf[l]) { - case 'B': num |= 0x80000; break; /* byte, set F bit */ - case 'H': num |= 0x00001; break; /* halfword */ - case 'W': num |= 0x00000; break; /* word */ - case 'D': num |= 0x00002; break; /* doubleword */ - default: - return SCPE_ARG; /* base op suffix error */ - } - /* Fall through */ + /* process each instruction type */ + switch(i) { + /* mem ref instruction */ + case TYPE_A: /* c r,[*]o[,x] */ + /* zero memory instruction */ + case TYPE_E: /* c [*]o[,x] */ + switch(gbuf[l]) { + case 'B': num |= 0x80000; break; /* byte, set F bit */ + case 'H': num |= 0x00001; break; /* halfword */ + case 'W': num |= 0x00000; break; /* word */ + case 'D': num |= 0x00002; break; /* doubleword */ + default: + return SCPE_ARG; /* base op suffix error */ + } + /* Fall through */ - /* BIx instructions or memory reference */ - case TYPE_D: /* r,[*]o[,x] */ - while (sim_isspace (*cptr)) cptr++; /* skip leading blanks */ - if (i != TYPE_E) { - /* get reg number except for zero memory instruction */ - if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ - x = *cptr++ - '0'; /* get the reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (*cptr++ != ',') /* check for required comma */ - return SCPE_ARG; /* anything else is an argument error */ - num |= x << 23; /* position reg number in instruction */ - } else - return SCPE_ARG; /* invalid reg number is an argument error */ - } - /* Fall through */ + /* BIx instructions or memory reference */ + case TYPE_D: /* r,[*]o[,x] */ + while (sim_isspace(*cptr)) + cptr++; /* skip leading blanks */ + if (i != TYPE_E) { + /* get reg number except for zero memory instruction */ + if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ + x = *cptr++ - '0'; /* get the reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if (*cptr++ != ',') /* check for required comma */ + return SCPE_ARG; /* anything else is an argument error */ + num |= x << 23; /* position reg number in instruction */ + } else + return SCPE_ARG; /* invalid reg number is an argument error */ + } + /* Fall through */ - /* branch instruction */ - case TYPE_B: /* [*]o[,x] */ - if (*cptr == '*') { /* test for indirection */ - num |= 0x100000; /* set indirect flag */ - cptr++; /* skip past the '*' */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - } - if (r = get_off (cptr, &tptr, 16, val, &mod)) /* get operand address */ - return r; /* argument error if a problem */ - cptr = tptr; /* set pointer to returned next char pointer */ - if (*val > 0x7FFFF) /* 19 bit address max */ - return SCPE_ARG; /* argument error */ - num |= *val; /* or our address into instruction */ - if (mod) { - return SCPE_ARG; /* if a '(' found, that is an arg error */ - } - if (cptr++ == ",") { /* test for optional index reg number */ - if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ - x = *cptr++ - '0'; /* get reg number */ - num |= x << 20; /* position and put into instruction */ - } else - return SCPE_ARG; /* reg# not 0-7, so arg error */ - } - break; + /* branch instruction */ + case TYPE_B: /* [*]o[,x] */ + if (*cptr == '*') { /* test for indirection */ + num |= 0x100000; /* set indirect flag */ + cptr++; /* skip past the '*' */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + } + if ((r = get_off(cptr, &tptr, 16, val, &mod))) /* get operand address */ + return r; /* argument error if a problem */ + cptr = tptr; /* set pointer to returned next char pointer */ + if (*val > 0x7FFFF) /* 19 bit address max */ + return SCPE_ARG; /* argument error */ + num |= *val; /* or our address into instruction */ + if (mod) { + return SCPE_ARG; /* if a '(' found, that is an arg error */ + } + if (*cptr++ == ',') { /* test for optional index reg number */ + if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ + x = *cptr++ - '0'; /* get reg number */ + num |= x << 20; /* position and put into instruction */ + } else + return SCPE_ARG; /* reg# not 0-7, so arg error */ + } + break; - /* immediate or XIO instruction */ - case TYPE_C: /* r,v */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* get reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* next char need to be a comma */ - return SCPE_ARG; /* it's not, so arg error */ - num |= x << 23; /* position and put into instruction */ - } else - return SCPE_ARG; /* invalid reg#, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 16 bit immediate value */ - return r; /* return error from conversion */ - num |= *val; /* or in the 16 bit value */ - break; + /* immediate or XIO instruction */ + case TYPE_C: /* r,v */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* get reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* next char need to be a comma */ + return SCPE_ARG; /* it's not, so arg error */ + num |= x << 23; /* position and put into instruction */ + } else + return SCPE_ARG; /* invalid reg#, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit immediate value */ + return r; /* return error from conversion */ + num |= *val; /* or in the 16 bit value */ + break; - /* reg-reg instructions */ - case TYPE_F: /* r,r */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* test for required ',' */ - return SCPE_ARG; /* it's not there, so error */ - num |= x << 23; /* insert first reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip more spaces */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip any spaces */ - num |= x << 20; /* insert 2nd reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - break; + /* reg-reg instructions */ + case TYPE_F: /* r,r */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* test for required ',' */ + return SCPE_ARG; /* it's not there, so error */ + num |= x << 23; /* insert first reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip more spaces */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip any spaces */ + num |= x << 20; /* insert 2nd reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + break; - /* single reg instructions */ - case TYPE_G: /* r */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - num |= x << 23; /* insert first reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - break; + /* single reg instructions */ + case TYPE_G: /* r */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + num |= x << 23; /* insert first reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + break; - /* opcode only instructions */ - case TYPE_H: /* empty */ - break; + /* opcode only instructions */ + case TYPE_H: /* empty */ + break; - /* reg and bit shift instructions */ - case TYPE_I: /* r,b */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* test for required ',' */ - return SCPE_ARG; /* it's not there, so error */ - num |= (x << 23); /* insert first reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, 10, val)) /* get 5 bit shift value */ - return r; /* return error from conversion */ - if (*val > 0x1f) /* 5 bit max count */ - return SCPE_ARG; /* invalid shift count */ - num |= (*val << 16); /* or in the 5 bit value */ - break; + /* reg and bit shift instructions */ + case TYPE_I: /* r,b */ + while (sim_isspace (*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* test for required ',' */ + return SCPE_ARG; /* it's not there, so error */ + num |= (x << 23); /* insert first reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit shift value */ + return r; /* return error from conversion */ + if (*val > 0x1f) /* 5 bit max count */ + return SCPE_ARG; /* invalid shift count */ + num |= (*val << 16); /* or in the 5 bit value */ + break; - /* register bit operations */ - case TYPE_K: /* r,rb */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* test for required ',' */ - return SCPE_ARG; /* it's not there, so error */ - num |= (x << 20); /* insert reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, 10, val)) /* get 5 bit bit number */ - return r; /* return error from conversion */ - if (*val > 0x1f) /* 5 bit max count */ - return SCPE_ARG; /* invalid bit count */ - x = *val / 8; /* get 2 bit byte number */ - num |= (x & 3) << 16; /* insert 2 bit byte code into instruction */ - x = *val % 8; /* get bit in byte value */ - num |= (x & 7) << 23; /* or in the bit value */ - break; + /* register bit operations */ + case TYPE_K: /* r,rb */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* test for required ',' */ + return SCPE_ARG; /* it's not there, so error */ + num |= (x << 20); /* insert reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit bit number */ + return r; /* return error from conversion */ + if (*val > 0x1f) /* 5 bit max count */ + return SCPE_ARG; /* invalid bit count */ + x = *val / 8; /* get 2 bit byte number */ + num |= (x & 3) << 16; /* insert 2 bit byte code into instruction */ + x = *val % 8; /* get bit in byte value */ + num |= (x & 7) << 23; /* or in the bit value */ + break; - /* interrupt control instructions */ - case TYPE_L: /* i */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 7 bit bit number */ - return r; /* return error from conversion */ - if (*val > 0x7f) /* 7 bit max count */ - return SCPE_ARG; /* invalid value */ - num |= (*val & 0x7f) << 19; /* or in the interrupt level */ - break; + /* interrupt control instructions */ + case TYPE_L: /* i */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */ + return r; /* return error from conversion */ + if (*val > 0x7f) /* 7 bit max count */ + return SCPE_ARG; /* invalid value */ + num |= (*val & 0x7f) << 19; /* or in the interrupt level */ + break; - /* CD/TD Class E I/O instructions */ - case TYPE_M: /* d,v */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 7 bit bit number */ - return r; /* return error from conversion */ - if (*val > 0x7f) /* 7 bit max count */ - return SCPE_ARG; /* invalid value */ - num |= (*val & 0x7f) << 19; /* or in the device address */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 16 bit command code */ - return r; /* return error from conversion */ - num |= *val; /* or in the 16 bit value */ - break; - } - return (tab->type & H) ? 2 : 4; /* done with nonbased instructions */ - } + /* CD/TD Class E I/O instructions */ + case TYPE_M: /* d,v */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */ + return r; /* return error from conversion */ + if (*val > 0x7f) /* 7 bit max count */ + return SCPE_ARG; /* invalid value */ + num |= (*val & 0x7f) << 19; /* or in the device address */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit command code */ + return r; /* return error from conversion */ + num |= *val; /* or in the 16 bit value */ + break; + } + return (tab->type & H) ? 2 : 4; /* done with nonbased instructions */ + } - /* see if we are processing a base mode instruction */ - if (sw & SWMASK ('M')) { /* base mode? */ - /* process base mode instruction */ - cptr = get_glyph(cptr, gbuf, 0); /* Get uppercase opcode */ - l = strlen(gbuf); /* save the num of char in opcode */ - /* loop through the instruction table for an opcode match and get the type */ - for (tab = optab; tab->name != NULL; tab++) { - i = tab->type & 0xf; /* get the type */ - /* check for memory reference instruction */ - if (i == TYPE_A || i == TYPE_E) { - /* test for base opcode name without B, H, W, D applied */ - if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0) - break; /* found */ - } else - /* test the full opcode name */ - if (sim_strcasecmp(tab->name, gbuf) == 0) - break; /* found */ - } - if (tab->name == NULL) /* see if anything found */ - return SCPE_ARG; /* no, return invalid argument error */ - num = tab->opbase<<16; /* get the base opcode value */ + /* see if we are processing a base mode instruction */ + if (sw & SWMASK ('M')) { /* base mode? */ + /* process base mode instruction */ + cptr = get_glyph(cptr, gbuf, 0); /* Get uppercase opcode */ + l = strlen(gbuf); /* save the num of char in opcode */ + /* loop through the instruction table for an opcode match and get the type */ + for (tab = optab; tab->name != NULL; tab++) { + i = tab->type & 0xf; /* get the type */ + /* check for memory reference instruction */ + if (i == TYPE_A || i == TYPE_E) { + /* test for base opcode name without B, H, W, D applied */ + if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0) + break; /* found */ + } else + /* test the full opcode name */ + if (sim_strcasecmp(tab->name, gbuf) == 0) + break; /* found */ + } + if (tab->name == NULL) /* see if anything found */ + return SCPE_ARG; /* no, return invalid argument error */ + num = tab->opbase<<16; /* get the base opcode value */ - /* process each instruction type */ - switch(i) { - /* mem ref instruction */ - case TYPE_A: /* c r,o[(b)][,x] */ - /* zero memory instruction */ - case TYPE_E: /* c o[(b)][,x] */ - switch(gbuf[l]) { - case 'B': num |= 0x80000; break; /* byte, set F bit */ - case 'H': num |= 0x00001; break; /* halfword */ - case 'W': num |= 0x00000; break; /* word */ - case 'D': num |= 0x00002; break; /* doubleword */ - default: - return SCPE_ARG; /* base op suffix error */ - } - /* Fall through */ + /* process each instruction type */ + switch(i) { + /* mem ref instruction */ + case TYPE_A: /* c r,o[(b)][,x] */ + /* zero memory instruction */ + case TYPE_E: /* c o[(b)][,x] */ + switch(gbuf[l]) { + case 'B': num |= 0x80000; break; /* byte, set F bit */ + case 'H': num |= 0x00001; break; /* halfword */ + case 'W': num |= 0x00000; break; /* word */ + case 'D': num |= 0x00002; break; /* doubleword */ + default: + return SCPE_ARG; /* base op suffix error */ + } + /* Fall through */ - /* BIx instructions or memory reference */ - case TYPE_D: /* r,o[(b)],[,x] */ - while (sim_isspace (*cptr)) cptr++; /* skip leading blanks */ - if (i != TYPE_E) { - /* get reg number except for zero memory instruction */ - if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ - x = *cptr++ - '0'; /* get the reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (*cptr++ != ',') /* check for required comma */ - return SCPE_ARG; /* anything else is an argument error */ - num |= x << 23; /* position reg number in instruction */ - } else - return SCPE_ARG; /* invalid reg number is an argument error */ - } + /* BIx instructions or memory reference */ + case TYPE_D: /* r,o[(b)],[,x] */ + while (sim_isspace(*cptr)) + cptr++; /* skip leading blanks */ + if (i != TYPE_E) { + /* get reg number except for zero memory instruction */ + if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ + x = *cptr++ - '0'; /* get the reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if (*cptr++ != ',') /* check for required comma */ + return SCPE_ARG; /* anything else is an argument error */ + num |= x << 23; /* position reg number in instruction */ + } else + return SCPE_ARG; /* invalid reg number is an argument error */ + } /* Fall through */ - /* branch instruction */ - case TYPE_B: /* o[(b)],[,x] */ - if (r = get_off (cptr, &tptr, 16, val, &mod)) /* get offset */ - return r; /* argument error if a problem */ - cptr = tptr; /* set pointer to returned next char pointer */ - if (*val > 0xFFFF) /* 16 bit offset max */ - return SCPE_ARG; /* argument error */ - num |= *val; /* or offset into instruction */ - if (mod) { /* see if '(' found in input */ - if (*cptr >= '0' || *cptr <= '7') { /* base reg# 0-7 */ - x = *cptr++ - '0'; /* get reg number */ - while (sim_isspace (*cptr)) cptr++; /* skip any spaces */ - if (*cptr++ != ')') /* test for closing right parend */ - return SCPE_ARG; /* arg error if not found */ - num |= x << 16; /* put base reg number into instruction */ - } else - return SCPE_ARG; /* no '(' found, so arg error */ - } - if (cptr++ == ",") { /* test for optional index reg number */ - if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ - x = *cptr++ - '0'; /* get reg number */ - num |= x << 20; /* position and put into instruction */ - } else - return SCPE_ARG; /* reg# not 0-7, so arg error */ - } - break; + /* branch instruction */ + case TYPE_B: /* o[(b)],[,x] */ + if ((r = get_off(cptr, &tptr, 16, val, &mod))) /* get offset */ + return r; /* argument error if a problem */ + cptr = tptr; /* set pointer to returned next char pointer */ + if (*val > 0xFFFF) /* 16 bit offset max */ + return SCPE_ARG; /* argument error */ + num |= *val; /* or offset into instruction */ + if (mod) { /* see if '(' found in input */ + if (*cptr >= '0' || *cptr <= '7') { /* base reg# 0-7 */ + x = *cptr++ - '0'; /* get reg number */ + while (sim_isspace(*cptr)) + cptr++; /* skip any spaces */ + if (*cptr++ != ')') /* test for closing right parend */ + return SCPE_ARG; /* arg error if not found */ + num |= x << 16; /* put base reg number into instruction */ + } else + return SCPE_ARG; /* no '(' found, so arg error */ + } + if (*cptr++ == ',') { /* test for optional index reg number */ + if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */ + x = *cptr++ - '0'; /* get reg number */ + num |= x << 20; /* position and put into instruction */ + } else + return SCPE_ARG; /* reg# not 0-7, so arg error */ + } + break; - /* immediate or XIO instruction */ - case TYPE_C: /* r,v */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* get reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* next char need to be a comma */ - return SCPE_ARG; /* it's not, so arg error */ - num |= x << 23; /* position and put into instruction */ - } else - return SCPE_ARG; /* invalid reg#, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 16 bit immediate value */ - return r; /* return error from conversion */ - num |= *val; /* or in the 16 bit value */ - break; + /* immediate or XIO instruction */ + case TYPE_C: /* r,v */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* get reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* next char need to be a comma */ + return SCPE_ARG; /* it's not, so arg error */ + num |= x << 23; /* position and put into instruction */ + } else + return SCPE_ARG; /* invalid reg#, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit immediate value */ + return r; /* return error from conversion */ + num |= *val; /* or in the 16 bit value */ + break; - /* reg-reg instructions */ - case TYPE_F: /* r,r */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* test for required ',' */ - return SCPE_ARG; /* it's not there, so error */ - num |= x << 23; /* insert first reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip more spaces */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip any spaces */ - num |= x << 20; /* insert 2nd reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - break; + /* reg-reg instructions */ + case TYPE_F: /* r,r */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* test for required ',' */ + return SCPE_ARG; /* it's not there, so error */ + num |= x << 23; /* insert first reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip more spaces */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip any spaces */ + num |= x << 20; /* insert 2nd reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + break; - /* single reg instructions */ - case TYPE_G: /* r */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - num |= x << 23; /* insert first reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - break; + /* single reg instructions */ + case TYPE_G: /* r */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + num |= x << 23; /* insert first reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + break; - /* opcode only instructions */ - case TYPE_H: /* empty */ - break; + /* opcode only instructions */ + case TYPE_H: /* empty */ + break; - /* reg and bit shift instructions */ - case TYPE_I: /* r,b */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* test for required ',' */ - return SCPE_ARG; /* it's not there, so error */ - num |= (x << 23); /* insert first reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, 10, val)) /* get 5 bit shift value */ - return r; /* return error from conversion */ - if (*val > 0x1f) /* 5 bit max count */ - return SCPE_ARG; /* invalid shift count */ - num |= (*val << 16); /* or in the 5 bit value */ - break; + /* reg and bit shift instructions */ + case TYPE_I: /* r,b */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* test for required ',' */ + return SCPE_ARG; /* it's not there, so error */ + num |= (x << 23); /* insert first reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit shift value */ + return r; /* return error from conversion */ + if (*val > 0x1f) /* 5 bit max count */ + return SCPE_ARG; /* invalid shift count */ + num |= (*val << 16); /* or in the 5 bit value */ + break; - /* register bit operations */ - case TYPE_K: /* r,rb */ - while (sim_isspace (*cptr)) cptr++; /* skip blanks */ - if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ - x = *cptr++ - '0'; /* calc reg# */ - while (sim_isspace (*cptr)) cptr++; /* skip spaces */ - if (*cptr++ != ',') /* test for required ',' */ - return SCPE_ARG; /* it's not there, so error */ - num |= (x << 20); /* insert reg# into instruction */ - } else - return SCPE_ARG; /* reg# invalid, so arg error */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, 10, val)) /* get 5 bit bit number */ - return r; /* return error from conversion */ - if (*val > 0x1f) /* 5 bit max count */ - return SCPE_ARG; /* invalid bit count */ - x = *val / 8; /* get 2 bit byte number */ - num |= (x & 3) << 16; /* insert 2 bit byte code into instruction */ - x = *val % 8; /* get bit in byte value */ - num |= (x & 7) << 23; /* or in the bit value */ - break; + /* register bit operations */ + case TYPE_K: /* r,rb */ + while (sim_isspace(*cptr)) + cptr++; /* skip blanks */ + if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */ + x = *cptr++ - '0'; /* calc reg# */ + while (sim_isspace(*cptr)) + cptr++; /* skip spaces */ + if (*cptr++ != ',') /* test for required ',' */ + return SCPE_ARG; /* it's not there, so error */ + num |= (x << 20); /* insert reg# into instruction */ + } else + return SCPE_ARG; /* reg# invalid, so arg error */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit bit number */ + return r; /* return error from conversion */ + if (*val > 0x1f) /* 5 bit max count */ + return SCPE_ARG; /* invalid bit count */ + x = *val / 8; /* get 2 bit byte number */ + num |= (x & 3) << 16; /* insert 2 bit byte code into instruction */ + x = *val % 8; /* get bit in byte value */ + num |= (x & 7) << 23; /* or in the bit value */ + break; - /* interrupt control instructions */ - case TYPE_L: /* i */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 7 bit bit number */ - return r; /* return error from conversion */ - if (*val > 0x7f) /* 7 bit max count */ - return SCPE_ARG; /* invalid value */ - num |= (*val & 0x7f) << 19; /* or in the interrupt level */ - break; + /* interrupt control instructions */ + case TYPE_L: /* i */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */ + return r; /* return error from conversion */ + if (*val > 0x7f) /* 7 bit max count */ + return SCPE_ARG; /* invalid value */ + num |= (*val & 0x7f) << 19; /* or in the interrupt level */ + break; - /* CD/TD Class E I/O instructions */ - case TYPE_M: /* d,v */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 7 bit bit number */ - return r; /* return error from conversion */ - if (*val > 0x7f) /* 7 bit max count */ - return SCPE_ARG; /* invalid value */ - num |= (*val & 0x7f) << 19; /* or in the device address */ - while (sim_isspace (*cptr)) cptr++; /* skip any blanks */ - if (r = get_imm (cptr, &tptr, rdx, val)) /* get 16 bit command code */ - return r; /* return error from conversion */ - num |= *val; /* or in the 16 bit value */ - break; - } - return (tab->type & H) ? 2 : 4; /* done with base mode insrructions */ - } + /* CD/TD Class E I/O instructions */ + case TYPE_M: /* d,v */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */ + return r; /* return error from conversion */ + if (*val > 0x7f) /* 7 bit max count */ + return SCPE_ARG; /* invalid value */ + num |= (*val & 0x7f) << 19; /* or in the device address */ + while (sim_isspace(*cptr)) + cptr++; /* skip any blanks */ + if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit command code */ + return r; /* return error from conversion */ + num |= *val; /* or in the 16 bit value */ + break; + } + return (tab->type & H) ? 2 : 4; /* done with base mode insrructions */ + } - /* get here for any other switch value */ - /* this code will get a value based on length specified in switches */ - num = get_uint(cptr, rdx, max[l], &r); /* get the unsigned value */ - for (i = 0; i < l && i < 4; i++) - val[i] = (num >> (i * 8)) & 0xff; /* get 1-4 bytes of data */ - return -(l-1); + /* get here for any other switch value */ + /* this code will get a value based on length specified in switches */ + num = get_uint(cptr, rdx, max[l], &r); /* get the unsigned value */ + for (i = 0; i < l && i < 4; i++) + val[i] = (num >> (i * 8)) & 0xff; /* get 1-4 bytes of data */ + return -(l-1); }