diff --git a/SEL32/sel32_chan.c b/SEL32/sel32_chan.c new file mode 100644 index 0000000..b295c68 --- /dev/null +++ b/SEL32/sel32_chan.c @@ -0,0 +1,733 @@ +/* sel32_chan.c: Sel 32 Channel functions. + + Copyright (c) 2018, Richard Cornwell + + 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. + + +*/ + + +/* Handle Class E and F channel I/O operations */ +#include "sel32_defs.h" +#include "sim_defs.h" + +/* Class F channel bits */ +#define CCMDMSK 0xff000000 /* Mask for command */ +#define CDADRMSK 0x00ffffff /* Mask for data address */ +#define CCNTMSK 0x0000ffff /* Mask for data count */ +#define CD 0x80000000 /* Chain data */ +#define CC 0x40000000 /* Chain command */ +#define SLI 0x20000000 /* Suppress length indication */ +#define SKIP 0x10000000 /* Skip flag */ +#define PCI 0x08000000 /* Program controlled interuption */ + +/* Command masks */ +#define CMD_TYPE 0x3 /* Type mask */ +#define CMD_CHAN 0x0 /* Channel command */ +#define CMD_WRITE 0x1 /* Write command */ +#define CMD_READ 0x2 /* Read command */ +#define CMD_CTL 0x3 /* Control command */ +#define CMD_SENSE 0x4 /* Sense channel command */ +#define CMD_TIC 0x8 /* Transfer in channel */ +#define CMD_RDBWD 0xc /* Read backward */ + +#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 */ + +#define FLAG_CD 0x8000 /* Chain data */ +#define FLAG_CC 0x4000 /* Chain command */ +#define FLAG_SLI 0x2000 /* Suppress length indicator */ +#define FLAG_SKIP 0x1000 /* Suppress memory write */ +#define FLAG_PCI 0x0800 /* Program controled interrupt */ + +#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 AMASK 0x00ffffff +#define PMASK 0xf0000000 /* Storage protection mask */ +extern uint32 *M; + +int irq_pend = 0; +uint32 caw[256]; /* Channel command address word */ +uint32 ccw_addr[256]; /* Channel address */ +uint16 ccw_count[256]; /* Channel count */ +uint8 ccw_cmd[256]; /* Channel command and flags */ +uint16 ccw_flags[256]; /* Channel flags */ +uint16 chan_status[256]; /* Channel status */ +uint16 chan_dev[256]; /* Device on channel */ +uint32 chan_buf[256]; /* Channel data buffer */ +uint8 chan_byte[256]; /* Current byte, dirty/full */ +DIB *dev_unit[256]; /* Pointer to Device info block */ +uint8 dev_status[256]; /* last device status flags */ + +/* Find unit pointer for given device */ +UNIT * +find_chan_dev(uint16 addr) { + struct dib *dibp; + UNIT *uptr; + int i; + + dibp = dev_unit[addr]; + if (dibp == 0) + return NULL; + uptr = dibp->units; + if (dibp->mask == 0) { + for (i = 0; i < dibp->numunits; i++) { + if (addr == GET_UADDR(uptr->u3)) + return uptr; + uptr++; + } + } else { + return uptr + (addr & ~dibp->mask & 0xff); + } + return NULL; +} + + +/* 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; +} + +/* Read a word into the channel buffer. + * Return 1 if fail. + * Return 0 if success. + */ +int +readbuff(int chan) { + 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; + } + 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]); + 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"); + return 0; +} + +/* Write channel buffer to memory. + * Return 1 if fail. + * Return 0 if success. + */ +int +writebuff(int chan) { + 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; + } + 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"); + return 0; +} + +int +load_ccw(uint16 chan, int tic_ok) { + uint32 word; + int cmd = 0; + UNIT *uptr; + +loop: + /* Abort if channel not on double boundry */ + if ((caw[chan] & 0x7) != 0) { + chan_status[chan] |= STATUS_PCHK; + return 1; + } + /* Abort if we have any errors */ + if (chan_status[chan] & 0x7f) + return 1; + /* Check if we have status modifier set */ + if (chan_status[chan] & STATUS_MOD) { + caw[chan]+=8; + caw[chan] &= PMASK|AMASK; /* Mask overflow bits */ + chan_status[chan] &= ~STATUS_MOD; + } + /* Read in next CCW */ + readfull(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); + tic_ok = 0; + goto loop; + } + chan_status[chan] |= STATUS_PCHK; + irq_pend = 1; + return 1; + } + caw[chan] += 4; + caw[chan] &= PMASK|AMASK; /* Mask overflow bits */ + /* Check if not chaining data */ + if ((ccw_flags[chan] & FLAG_CD) == 0) { + ccw_cmd[chan] = (word >> 24) & 0xff; + cmd = 1; + } + /* Set up for this command */ + ccw_addr[chan] = word & AMASK; + ccw_addr[chan] |= caw[chan] & PMASK; /* Copy key */ + readfull(chan, caw[chan], &word); + sim_debug(DEBUG_CMD, &cpu_dev, "Channel read ccw2 %02x %06x %08x\n", + chan, caw[chan], word); + caw[chan]+=4; + caw[chan] &= PMASK|AMASK; /* Mask overflow bits */ + ccw_count[chan] = word & 0xffff; + ccw_flags[chan] = (word >> 16) & 0xffff; + chan_byte[chan] = BUFF_EMPTY; + if (ccw_flags[chan] & FLAG_PCI) { + chan_status[chan] |= STATUS_PCI; + irq_pend = 1; + } + /* Check invalid count */ + if (ccw_count[chan] == 0) { + chan_status[chan] |= STATUS_PCHK; + irq_pend = 1; + return 1; + } + if (cmd) { + DIB *dibp = dev_unit[chan_dev[chan]]; + /* Check if invalid command */ + if ((ccw_cmd[chan] & 0xF) == 0) { + chan_status[chan] |= STATUS_PCHK; + irq_pend = 1; + return 1; + } + uptr = find_chan_dev(chan_dev[chan]); + if (uptr == 0) + return 1; + chan_status[chan] &= 0xff; + chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8; + if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) { + chan_status[chan] |= STATUS_CEND; + ccw_flags[chan] = 0; + ccw_cmd[chan] = 0; + irq_pend = 1; + return 1; + } + if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) { + chan_status[chan] |= STATUS_CEND; + chan_byte[chan] = BUFF_NEWCMD; + ccw_cmd[chan] = 0; + irq_pend = 1; + } + } + return 0; +} + + +/* read byte from memory */ +int +chan_read_byte(uint16 addr, uint8 *data) { + int chan = find_subchan(addr); + int byte; + int k; + + /* 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_CD) == 0) { + chan_status[chan] |= STATUS_CEND; + chan_byte[chan] = BUFF_CHNEND; + sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_read_end\n"); + return 1; + } else { + if (load_ccw(chan, 1)) + return 1; + } + } + 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]; + } + ccw_count[chan]--; + byte = (chan_buf[chan] >> (8 * (3 - (chan_byte[chan] & 0x3)))) & 0xff; + chan_byte[chan]++; + *data = byte; + return 0; +} + +/* write byte to memory */ +int +chan_write_byte(uint16 addr, uint8 *data) { + int chan = find_subchan(addr); + int byte; + int offset; + int k; + 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; + } + return 1; + } + if (ccw_count[chan] == 0) { + if (chan_byte[chan] & BUFF_DIRTY) { + if (writebuff(chan)) + return 1; + } + if ((ccw_flags[chan] & FLAG_CD) == 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 (ccw_flags[chan] & FLAG_SKIP) { + ccw_count[chan]--; + chan_byte[chan] = BUFF_EMPTY; + if ((ccw_cmd[chan] & 0xf) == CMD_RDBWD) + ccw_addr[chan]--; + else + ccw_addr[chan]++; + 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]--; + else + chan_byte[chan] = BUFF_EMPTY; + } else + chan_byte[chan]++; + chan_byte[chan] |= BUFF_DIRTY; + return 0; +} + +void +set_devattn(uint16 addr, uint8 flags) { + int chan = find_subchan(addr); + + 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; +} + +void +chan_end(uint16 addr, uint8 flags) { + int chan = find_subchan(addr); + + if (chan < 0) + return; + + 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; + } + + if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) { + chan_byte[chan] = BUFF_NEWCMD; + + while ((ccw_flags[chan] & FLAG_CD)) { + 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; +} + + +int startio(uint16 addr) { + int chan = find_subchan(addr); + DIB *dibp = dev_unit[addr]; + UNIT *uptr; + uint8 status; + + /* Needs to be redone for Sel32 */ + return 0; +} + +int testio(uint16 addr) { + int chan = find_subchan(addr); + DIB *dibp = dev_unit[addr]; + UNIT *uptr; + uint8 status; + + return 0; +} + +int haltio(uint16 addr) { + int chan = find_subchan(addr); + DIB *dibp = dev_unit[addr]; + UNIT *uptr; + uint8 status; + + return 0; +} + + +t_stat chan_boot(uint16 addr, DEVICE *dptyr) { + int chan = find_subchan(addr); + DIB *dibp = dev_unit[addr]; + UNIT *uptr; + uint8 status; + int i; + + if (chan < 0 || dibp == 0) + return SCPE_IOERR; + for (i = 0; i < MAX_DEV; i++) { + dev_status[i] = 0; + } + for (i = 0; i < 256; i++) { + ccw_cmd[i] = 0; + ccw_flags[i] = 0; + } + uptr = find_chan_dev(addr); + chan_status[chan] = 0; + dev_status[addr] = 0; + caw[chan] = 0x8; + chan_dev[chan] = addr; + ccw_count[chan] = 24; + ccw_flags[chan] = FLAG_CC|FLAG_SLI; + ccw_addr[chan] = 0; + chan_byte[chan] = BUFF_EMPTY; + ccw_cmd[chan] = 0x2; + chan_status[chan] &= 0xff; + chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8; + if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) { + ccw_flags[chan] = 0; + return SCPE_IOERR; + } + loading = addr; + return SCPE_OK; +} + +/* Scan all channels and see if one is ready to start or has + interrupt pending. +*/ +uint16 scan_chan(uint8 mask) { + int i; + int pend = 0; /* No device */ + int imask = 0x80; + + if (irq_pend == 0) + return 0; + irq_pend = 0; + for (i = 0; i < subchannels + channels; i++) { + if (i >= subchannels) + imask = imask / 2; + + /* If channel end, check if we should continue */ + if (chan_status[i] & STATUS_CEND) { + if (ccw_flags[i] & FLAG_CC) { + if (chan_status[i] & STATUS_DEND) + (void)load_ccw(i, 1); + else + irq_pend = 1; + } else { + sim_debug(DEBUG_EXP, &cpu_dev, "Scan(%x %x %x %x) end\n", i, + chan_status[i], imask, mask); + if ((imask & mask) != 0 || loading != 0) { + pend = chan_dev[i]; + break; + } + } + } + } + if (pend) { + irq_pend = 1; + i = find_subchan(pend); + if (i >= 0) { + sim_debug(DEBUG_EXP, &cpu_dev, "Scan end (%x %x)\n", chan_dev[i], pend); + store_csw(i); + } + dev_status[pend] = 0; + } else { + for (pend = 0; pend < MAX_DEV; pend++) { + if (dev_status[pend] != 0) { + i = find_subchan(pend); + if (i >= 0 && ccw_cmd[i] == 0 && mask & (0x80 >> (pend >> 8))) { + irq_pend = 1; + M[0x44 >> 2] = (((uint32)dev_status[pend]) << 24); + M[0x40>>2] = 0; + sim_debug(DEBUG_EXP, &cpu_dev, + "Set atten %03x %02x [%08x] %08x\n", + i, dev_status[pend], M[0x40 >> 2], M[0x44 >> 2]); + dev_status[pend] = 0; + return pend; + } + } + } + pend = 0; + } + /* Only return loading unit on loading */ + if (loading != 0 && loading != pend) + return 0; + return pend; +} + + +t_stat +chan_set_devs() +{ + int i, j; + + for(i = 0; i < MAX_DEV; i++) { + dev_unit[i] = NULL; /* Device pointer */ + } + /* Build channel array */ + for (i = 0; sim_devices[i] != NULL; i++) { + DEVICE *dptr = sim_devices[i]; + UNIT *uptr = dptr->units; + DIB *dibp = (DIB *) dptr->ctxt; + int addr; + int chan; + + /* If no DIB, not channel device */ + if (dibp == NULL) + continue; + /* Skip disabled devices */ + if (dptr->flags & DEV_DIS) + continue; + /* Check if address is in unit or dev entry */ + for (j = 0; j < dptr->numunits; j++) { + addr = GET_UADDR(uptr->u3); + if ((uptr->flags & UNIT_DIS) == 0) + dev_unit[addr] = dibp; + if (dibp->dev_ini != NULL) + dibp->dev_ini(uptr, 1); + uptr++; + + } + } + return SCPE_OK; +} + +/* Sets the device onto a given channel */ +t_stat +set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + t_value newdev; + t_stat r; + int num; + int type; + int i; + int devaddr; + + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + + dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + + newdev = get_uint (cptr, 16, 0xfff, &r); + + if (r != SCPE_OK) + return r; + + if ((newdev >> 8) > channels) + return SCPE_ARG; + + if (newdev >= MAX_DEV) + return SCPE_ARG; + + devaddr = GET_UADDR(uptr->u3); + + /* Clear out existing entry */ + if (dptr->flags & DEV_UADDR) { + dev_unit[devaddr] = NULL; + } else { + devaddr &= dibp->mask | 0x700; + for (i = 0; i < dibp->numunits; i++) + dev_unit[devaddr + i] = NULL; + } + + /* Check if device already at newdev */ + if (dptr->flags & DEV_UADDR) { + if (dev_unit[newdev] != NULL) + r = SCPE_ARG; + } else { + newdev &= dibp->mask | 0x700; + for (i = 0; i < dibp->numunits; i++) { + if (dev_unit[newdev + i] != NULL) + r = SCPE_ARG; + } + } + + /* If not, point to new dev, else restore old */ + if (r == SCPE_OK) + devaddr = newdev; + + /* Update device entry */ + if (dptr->flags & DEV_UADDR) { + dev_unit[devaddr] = dibp; + uptr->u3 &= ~UNIT_ADDR(0x7ff); + uptr->u3 |= UNIT_ADDR(devaddr); + fprintf(stderr, "Set dev %x\n\r", GET_UADDR(uptr->u3)); + } else { + for (i = 0; i < dibp->numunits; i++) { + dev_unit[devaddr + i] = dibp; + uptr = &((dibp->units)[i]); + uptr->u3 &= ~UNIT_ADDR(0x7ff); + uptr->u3 |= UNIT_ADDR(devaddr + i); + fprintf(stderr, "Set dev %x\n\r", GET_UADDR(uptr->u3)); + } + } + return r; +} + +t_stat +show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc) +{ + DEVICE *dptr; + DIB *dibp; + int addr; + + + 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; +} + diff --git a/SEL32/sel32_cpu.c b/SEL32/sel32_cpu.c new file mode 100644 index 0000000..dc89e7b --- /dev/null +++ b/SEL32/sel32_cpu.c @@ -0,0 +1,1759 @@ +/* sel32_cpu.c: Sel 32 CPU simulator + + Copyright (c) 2017, Richard Cornwell + + 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" + +#define UNIT_V_MODEL (UNIT_V_UF + 0) +#define UNIT_MODEL (7 << UNIT_V_MODEL) +#define MODEL(x) (x << UNIT_V_MODEL) +#define UNIT_V_MSIZE (UNIT_V_MODEL + 3) +#define UNIT_MSIZE (0x1F << UNIT_V_MSIZE) +#define MEMAMOUNT(x) (x << UNIT_V_MSIZE) + +#define MODEL_55 0 /* 512K Mode Only */ +#define MODEL_75 1 /* Extended */ +#define MODEL_27 2 /* */ +#define MODEL_67 3 /* */ +#define MODEL_87 4 /* */ +#define MODEL_97 5 /* */ +#define MODEL_V6 6 /* V6 CPU */ +#define MODEL_V9 7 /* V9 CPU */ + +#define TMR_RTC 1 + +#define HIST_MIN 64 +#define HIST_MAX 10000 +#define HIST_PC 0x80000000 + +int cpu_index; /* Current CPU running */ +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 */ +#define CC1 0x40 +#define CC2 0x20 +#define CC3 0x10 +#define CC4 0x08 +#define AEXP 0x01 /* Arithmetic exception PSD 1 bit 7 */ + /* Held in CC */ + +uint8 modes; /* Operating modes */ +#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 MAP 0x40 /* Map mode, PSD 2 bit 0 */ +#define RET 0x20 /* Retain current map, PSD 2 bit 15 */ + +uint8 irq_flags; /* Interrupt control flags PSD 2 bits 16&17 */ +uint16 cpix; /* Current Process index */ +uint16 bpix; /* Base process index */ + +struct InstHistory +{ + uint32 pc; + uint32 inst; + uint32 ea; + uint64 dest; + uint64 source; + uint64 res; + uint8 cc; +}; + +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); + +/* 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 +*/ + +UNIT cpu_unit = + { UDATA(rtc_srv, UNIT_BINK | MODEL(MODEL_27) | MEMAMOUNT(0), + MAXMEMSIZE ), 120 }; + +REG cpu_reg[] = { + {ORDATAD(IC, IC, 15, "Instruction Counter"), REG_FIT}, + {ORDATAD(AC, AC, 38, "Accumulator"), REG_FIT, 0}, + {ORDATAD(MQ, MQ, 36, "Multiplier Quotent"), REG_FIT, 0}, + {BRDATAD(XR, XR, 8, 15, 8, "Index registers"), REG_FIT}, + {ORDATAD(ID, ID, 36, "Indicator Register")}, +#ifdef EXTRA_SL + {ORDATAD(SL, SL, 8, "Sense Lights"), REG_FIT}, +#else + {ORDATAD(SL, SL, 4, "Sense Lights"), REG_FIT}, +#endif +#ifdef EXTRA_SW + {ORDATAD(SW, SW, 12, "Sense Switches"), REG_FIT}, +#else + {ORDATAD(SW, SW, 6, "Sense Switches"), REG_FIT}, +#endif +#endif + {ORDATAD(KEYS, KEYS, 36, "Console Key Register"), REG_FIT}, + {ORDATAD(MTM, MTM, 1, "Multi Index registers"), REG_FIT}, + {ORDATAD(TM, TM, 1, "Trap mode"), REG_FIT}, + {ORDATAD(STM, STM, 1, "Select trap mode"), REG_FIT}, + {ORDATAD(CTM, CTM, 1, "Copy Trap Mode"), REG_FIT}, + {ORDATAD(FTM, FTM, 1, "Floating trap mode"), REG_FIT}, + {ORDATAD(NMODE, nmode, 1, "Storage null mode"), REG_FIT}, + {ORDATAD(ACOVF, acoflag, 1, "AC Overflow Flag"), REG_FIT}, + {ORDATAD(MQOVF, mqoflag, 1, "MQ Overflow Flag"), REG_FIT}, + {ORDATAD(IOC, iocheck, 1, "I/O Check flag"), REG_FIT}, + {ORDATAD(DVC, dcheck, 1, "Divide Check flag"), REG_FIT}, + {ORDATAD(RELOC, relocaddr, 14, "Relocation offset"), REG_FIT}, + {ORDATAD(BASE, baseaddr, 14, "Relocation base"), REG_FIT}, + {ORDATAD(LIMIT, limitaddr, 14, "Relocation limit"), REG_FIT}, + {ORDATAD(ENB, ioflags, 36, "I/O Trap Flags"), REG_FIT}, + {FLDATA(INST_BASE, bcore, 0), REG_FIT}, + {FLDATA(DATA_BASE, bcore, 1), REG_FIT}, + {NULL} +}; + +MTAB cpu_mod[] = { + {UNIT_MODEL, MODEL(MODEL_55), "32/55", "32/55", NULL, NULL, NULL, "Concept 32/55"}, + {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"}, + {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &cpu_set_size}, + {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} +}; + +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 +}; + +#define IND 0x00100000 +#define F_BIT 0x00080000 + +/* CPU Instruction decode flags */ +#define INV 0x0000 /* Instruction is invalid */ +#define HLF 0x0001 /* Half word instruction */ +#define ADR 0x0002 /* Normal addressing mode */ +#define IMM 0x0003 /* Immediate mode */ +#define WRD 0x0004 /* Word addressing, no index */ +#define SCC 0x0008 /* Sets CC */ +#define RR 0x0010 /* Read source register */ +#define R1 0x0020 /* Read register 1 */ +#define RB 0x0040 /* Read base register into dest */ +#define SD 0x0080 /* Stores into destination register */ +#define SDD 0x0100 /* Stores double into destination */ +#define RM 0x0200 /* Reads memory */ +#define SM 0x0400 /* Stores memory */ +#define DBL 0x0800 /* Double word operation */ +#define SB 0x1000 /* Store Base register */ + +int nobase_mode[] = { + /* 00 04 08 0C */ + /* 00 ANR, ORR, EOR */ + HLF, SCC|SD|HLF, SCC|SD|HLF, SCC|SD|HLF, + /* 10 14 18 1C */ + /* CAR, CMR, SBR ZBR */ + SCC|RR|R1|HLF, RR|R1| HLF, SD|HLF, SD|HLF, + /* 20 24 28 2C */ + /* ABR TBR TRR */ + SD|HLF, HLF, INV, SCC|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, SDD|HLF, SDD|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, SM|RM|ADR, SM|RM|ADR, + /* A0 A4 A8 AC */ + /* ABM TBM EXM L */ + SD|RM|ADR, RM|ADR, RM|ADR, SCC|SD|RM|ADR, + /* B0 B4 B8 BC */ + /* LM LN ADM SUM */ + SCC|SD|RM|ADR, SCC|SD|RM|ADR, CC|SD|RM|ADR, SCC|SD|RM|ADR, + /* C0 C4 C8 CC */ + /* MPM DVM IMMD LF */ + SCC|SD|RM|ADR, SCC|RM|ADR, IMM, ADR, + /* D0 D4 D8 DC */ + /* LEA ST STM */ + SD|ADR, SM|ADR, SM|ADR, INV, + /* 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, SD|HLF, SD|HLF, SD|HLF, + /* 10 14 18 1C */ + /* SACZ xBR SRx */ + SD|HLF, INV, SD|HLF, SD|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, ADR, 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, SM|RM|ADR, SM|RM|ADR, + /* A0 A4 A8 AC */ + /* ABM TBM EXM L */ + SD|RM|ADR, RM|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 IMMD LF */ + SD|RM|ADR, RM|ADR, IMM, ADR, + /* D0 D4 D8 DC */ + /* LEA ST STM */ + SD|ADR, SM|ADR, SM|ADR, INV, + /* 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|SR|WRD, ADR, IMM, +}; + +int page_lookup(uint32 addr, uint32 *loc, int wr) { +} + +int Mem_read(uint32 addr, uint32 *data) { + addr &= (modes & EXTD) ? 0xFFFFFC : 0x7FFFF; + if (modes & MAP && page_lookup(addr, &addr, 0)) + return 1; + if (addr > MSIZE) { + /* Set NXM fault */ + return 1; + } + *data = M[addr >> 2]; + return 0; +} + +int Mem_write(uint32 addr, uint32 *data) { + addr &= (modes & EXTD) ? 0xFFFFFC : 0x7FFFF; + if (modes & MAP && page_lookup(addr, &addr, 1)) + return 1; + if (addr > MSIZE) { + /* Set NXM fault */ + return 1; + } + M[addr >> 2] = *data; + return 0; +} +/* Opcode definitions */ + +t_stat +sim_instr(void) +{ + t_stat reason; + uint64 dest; /* Holds destination/source register */ + 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 */ + uint16 opr; /* Top half of Instruction register */ + uint8 fc; /* Current F&C bits */ + int reg; /* GPR or Base register */ + int dbl; /* Double word */ + int ovr; /* Overflow flag */ + int t; /* Temporary */ + reason = 0; + + + 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 */ + } + } + + if (iowait == 0 && sim_brk_summ && + sim_brk_test(((bcore & 2)? CORE_B:0)|IC, SWMASK('E'))) { + reason = STOP_IBKPT; + break; + } + +/* Check if we need to take any traps */ + /* fill IR */ + if (Mem_read(PC, &IR)) { + /* Fault on Fetch read */ + } + + /* If executing right half */ + if (PC & 2) + IR <<= 16; +exec: +/* Update history for this instruction */ + + /* Split instruction into pieces */ + opr = (IR >> 16) & 0xFFFF; + op = (opr >> 26) & 03F; + FC = (IR & F_BIT) ? 0x4 : 0; + reg = (opr >> 23) & 0x7; + dest = (uint64)IR; + dbl = 0; + ovr = 0; + if (mode & BASE) { + i_flags = base_mode[op]; + addr = IR & 0xFF00FFFF; + switch(i_flags & 07) { + case HLF: + source = GPR[(IR >> 20) & 07]; + break; + case IMMD: + if (PC & 02) { + /* Error */ + } + break; + case ADR: + case WRD: + if (PC & 02) { + /* Error */ + } + ix = (IR >> 21) & 7; + if (ix != 0) { + addr += GPR[ix]; + } + ix = (IR >> 16) & 7; + if (ix != 0) + addr += BR[ix]; + FC |= addr & 3; + break; + if (PC & 02) { + /* Error */ + } + case INV: + break; + } + } else { + i_flags = nobase_mode[op]; + addr = IR & 0xFF07FFFF; + switch(i_flags & 07) { + case HLF: + source = GPR[(IR >> 20) & 07]; + break; + case IMMD: + if (PC & 02) { + /* Error */ + } + break; + case ADR: + if (PC & 02) { + /* Error */ + } + ix = (IR >> 21) & 3; + if (ix != 0) { + addr += GPR[ix]; + } + FC |= addr & 3; + while (IR & IND) { + if (Mem_read(addr, &temp)) { + /* Fault */ + } + addr = temp & 0xFF07FFFF; + dest = (uint64)temp; + ix = (temp >> 21) & 3; + if (ix != 0) + addr += GPR[ix]; + if ((temp & F_BIT) || (addr & 3)) + FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3); + } + break; + case WRD: + if (PC & 02) { + /* Error */ + } + FC |= addr & 3; + while (IR & IND) { + if (Mem_read(addr, &temp)) { + /* Fault */ + } + addr = temp & 0xFF07FFFF; + dest = (uint64)temp; + ix = (temp >> 21) & 3; + if (ix != 0) + addr += GPR[ix]; + if ((temp & F_BIT) || (addr & 3)) + FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3); + } + break; + case INV: + } + } + + /* Read into memory operand */ + if (i_flags & RM) { + if (Mem_read(addr, &temp)) { + /* Fault */ + } + source = (uint64)temp; + switch(FC) { + case 0: if ((addr & 3) != 0) { + /* Address fault */ + } + break; + case 1: source >>= 16; + /* Fall through */ + case 3: + if ((addr & 1) != 0) { + /* Address Fault */ + } + source = EXT(source); + break; + case 2: if ((addr & 7) != 0) { + } + if (Mem_read(addr + 4, &temp)) { + } + source |= ((uint64)temp) << 32; + dbl = 1; + break; + case 4: + case 5: + case 6: + source >>= 8 * (7 - FC); + case 7: + break; + } + } + + /* Read in if from register */ + if (i_flags & RR) { + dest = (uint64)GPR[reg]; + if (dbl) { + if (reg & 1) { + /* Spec fault */ + } + dest |= ((uint64)GPR[reg|1]) << 32; + } else { + dest |= (dest & FSIGN) ? 0xFFFFFFFF << 32: 0; + } + } + + /* For Base mode */ + if (i_flags & RB) { + dest = (uint64)BR[reg]; + } + + /* For register instructions */ + if (i_flags & R1) { + int r = (IR >> 20) & 07; + source = (uint64)GPR[r]; + if (dbl) { + if (r & 1) { + /* Spec fault */ + } + source |= ((uint64)GPR[r|1]) << 32; + } else { + source |= (source & FSIGN) ? 0xFFFFFFFF << 32: 0; + } + } + + switch (op) { + case 0x00: /* CPU General operations */ + switch(IR & 0xF) { + case 0x0: /* HALT */ + break; + case 0x1: /* WAIT */ + break; + case 0x2: /* NOP */ + break; + case 0x3: /* LCS */ + break; + case 0x4: /* ES */ + temp = GPR[reg]; + GPR[(reg+1)&7] = (temp & FSIGN) ? FMASK : 0; + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + break; + case 0x5: /* RND */ + temp = GPR[reg]; + if (GPR[(reg+1)&7] & FSIGN) { + temp ++; + if (temp < GPR[reg]) + ovr = 1; + GPR[reg] = temp; + } + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + break; + case 0x6: /* BEI */ + break; + case 0x7: /* UEI */ + break; + case 0x8: /* EAE */ + CC |= AEXP; + break; + case 0x9: /* RDSTS */ + break; + case 0xA: /* SIPU */ + break; + case 0xB: /* INV */ + case 0xC: /* INV */ + break; + case 0xD: /* SEA */ + modes |= EXTD; + break; + case 0xE: /* DAE */ + CC &= ~AEXP; + break; + + case 0xF: /* CEA */ + modes &= ~EXTD; + break; + } + break; + case 0x01: /* 0x04 */ + switch(IR & 0xF) { + case 0x0: /* ANR */ /* SCC|SD */ + dest &= source; + break; + case 0xA: /* CMC */ + break; + case 0x7: /* SMC */ + break; + case 0xB: /* RPSWT */ + break; + default: /* INV */ + break; + } + break; + case 0x02: /* 0x08 */ /* ORR or ORRM */ + dest |= source; + if (IR & 0x8) + dest &= GPR[4]; + break; + case 0x03: /* 0x0c */ /* EOR or EORM */ + dest ^= source; + if (IR & 0x8) + dest &= GPR[4]; + break; + case 0x04: /* 0x10 */ /* CAR or (basemode SACZ ) */ + if (modes & BASE) { + temp = GPR[reg]; + t = (IR >> 20) & 7; + temp = temp - GPR[t]; + CC &= AEXP; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + } else { +scaz: + temp = GPR[reg]; + t = 0; + CC &= AEXP; + if (temp != 0) { + while((temp & FSIGN) == 0) { + temp <<= 1; + t++; + } + temp <<= 1; + } else { + CC |= CC4; + } + GPR[(IR >> 20) & 7] = t; + } + break; + + case 0x05: /* 0x14 */ /* SBR, (basemode ZBR, ABR, TBR */ + case 0x06: /* 0x18 */ /* SRABR, SRLBR, SLABR, SLLBR */ + if ((mode & BASE) == 0) { + int r = (IR >> 20) & 7; + int b = 31 - (((IR >> 13) & 030) | reg); + temp = GPR[r]; + ovr = ((1 << b) & temp) != 0; + GPR[r] |= (1 << temp); + CC = ((ovr)?CC1:0) | ((CC >> 1) & (CC2|CC3|CC4)) | (CC & AEXP); + } + break; + + case 0x07: /* 0x1C */ /* ZBR non-basemode */ + if ((mode & BASE) == 0) { + int r = (IR >> 20) & 7; + int b = 31 - (((IR >> 13) & 030) | reg); + temp = GPR[r]; + ovr = ((1 << b) & temp) != 0; + GPR[r] &= ~(1 << temp); + CC = ((ovr)?CC1:0) | ((CC >> 1) & (CC2|CC3|CC4)) | (CC & AEXP); + } + break; + + case 0x08: /* 0x20 */ /* ABR (basemode SRADBR, SRLDBR, SLADBR, SLLDBR) */ + if ((mode & BASE) == 0) { + int r = (IR >> 20) & 7; + int b = 31 - (((IR >> 13) & 030) | reg); + temp = GPR[r]; + ovr = (temp & FSIGN) != 0; + temp += b; + ovr ^= (temp & FSIGN) != 0; + GPR[r] = temp; + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + } + break; + + case 0x09: /* 0x24 */ /* TBR (basemode SRCBR) */ + if ((mode & BASE) == 0) { + int r = (IR >> 20) & 7; + int b = 31 - (((IR >> 13) & 030) | reg); + temp = GPR[r]; + ovr = ((1 << b) & temp) != 0; + CC = ((ovr)?CC1:0) | ((CC >> 1) & (CC2|CC3|CC4)) | (CC & AEXP); + } + break; + + case 0x0A: /* 0x28 */ + temp = GPR[reg]; + switch(IR & 0xF) { + case 0x0: /* TRSW */ + PC = temp & FMASK; + CC = ((CC1|CC2|CC3|CC4) & ((uint8)(temp >> 24))) | + CC | AEXP; + break; + + case 0x1: /* TRBR */ + if (modes & BASE) { + t = (IR >> 20) & 7; + BR[reg] = GPR[t]; + } else { + /* Fault */ + } + break; + + case 0x2: /* XCBR */ + if (modes & BASE) { + temp = BR[reg]; + t = (IR >> 20) & 7; + addr = BR[t]; + BR[t] = temp; + temp = addr; + BR[reg] = temp;; + } else { + /* Fault */ + } + break; + + case 0x3: /* TCCR */ + temp = (CC & (CC1|CC2|CC3|CC4)) >> 3; + break; + + case 0x4: /* TRCC */ + CC = ((CC1|CC2|CC3|CC4) & ((uint8)(temp << 3))) | + CC | AEXP; + break; + + case 0x5: /* BSUB */ + break; + case 0x8: /* CALL */ + break; + case 0xC: /* PTCBR */ + if (mode & BASE) { + BR[reg] = PC; + break; + } else { + /* Fault */ + } + break; + + case 0xE: /* RETURN */ + break; + case 0xD: /* INV */ + case 0x6: /* INV */ + case 0x7: /* INV */ + case 0x9: /* INV */ + case 0xA: /* INV */ + case 0xB: /* INV */ + case 0xF: /* INV */ + } + GPR[reg] = temp;; + break; + case 0x0B: /* 0x2C */ + temp = GPR[reg]; + t = (IR >> 20) & 7; + addr = GPR[t]; + switch(IR & 0xF) { + case 0x0: /* TRR */ /* SCC|SD|R1 */ + temp = addr; + break; + case 0x1: /* TRDR */ + break; + case 0x2: /* TBRR */ + if (modes & BASE) { + t = (IR >> 20) & 7; + GPR[reg] = BR[t]; + } else { + /* Fault */ + } + break; + + case 0x3: /* TRC */ + temp = addr ^ FMASK; + break; + case 0x4: /* TRN */ + temp = -addr; + if (temp == addr) + ovr = 1; + break; + case 0x5: /* XCR */ + GPR[t] = temp; + temp = addr; + ovr = 0; + break; + + case 0x6: /* INV */ + break; + case 0x7: /* LMAP */ + break; + case 0x8: /* TRRM */ /* SCC|SD|R1 */ + temp = addr & GPR[4]; + break; + case 0x9: /* SETCPU */ + break; + case 0xA: /* TMAPR */ + break; + case 0xB: /* TRCM */ + temp = (addr ^ FMASK) & GPR[4]; + break; + case 0xC: /* TRNM */ + temp = -addr; + if (temp == addr) + ovr = 1; + temp &= GPR[4]; + break; + case 0xD: /* XCRM */ + addr &= GPR[4]; + GPR[t] = temp & GPR[4]; + temp = addr; + ovr = 0; + break; + case 0xE: /* TRSC */ + case 0xF: /* TSCR */ + } + GPR[reg] = temp; + if ((IR & 0xF) < 6) { + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + } + break; + case 0x0C: /* 0x30 */ /* CALM */ + break; + case 0x0D: /* 0x34 */ /* LA non-basemode */ + break; + case 0x0E: /* 0x38 */ + temp = GPR[reg]; + t = (IR >> 20) & 7; + addr = GPR[t]; + switch(IR & 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; + 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; + 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 ((IR & 0xF) < 6) { + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + } + break; + case 0x0F: /* 0x3C */ /* SUR and SURM */ + temp = -GPR[reg]; + t = (IR >> 20) & 7; + addr = GPR[t]; + switch(IR & 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; + 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; + 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 ((IR & 0xF) < 6) { + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + } + break; + case 0x10: /* 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 0x11: /* 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; + 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; + if (dest & MSIGN) + CC |= CC3; + else if (dest == 0) + CC |= CC4; + else + CC |= CC2; + break; + case 0x12: /* 0x48 */ + case 0x13: /* 0x4C */ + case 0x14: /* 0x50 */ /* (basemode LA) */ + if (modes & (BASE|EXTD)) { + dest = addr; + } else { + dest = addr | ((FC & 4) << 18); + } + break; + + case 0x15: /* 0x54 */ /* (basemode STWBR) */ + if (FC != 0) { + /* Fault */ + } + break; + case 0x16: /* 0x58 */ /* (basemode SUABR and LABR) */ + if ((FC & 4) != 0) { + dest = addr; + } else { + dest += addr; + } + break; + case 0x17: /* 0x5C */ /* (basemode LWBR and BSUBM) */ + if (FC != 0) { + /* Fault */ + } + break; + case 0x18: /* 0x60 */ /* NOR */ + if ((modes & BASE) == 0) { + temp = GPR[reg]; + t = 0; + if (temp != 0 && temp != FMASK) { + uint32 m = temp & 0xF8000000; + while ((m == 0) || (m == 0xF8000000)) { + temp <<= 4; + m = temp & 0xF8000000; + t++; + } + GPR[reg] = temp; + } + GPR[(IR >> 20) & 7] = t; + } + break; + + case 0x19: /* 0x64 */ /* NORD */ + if ((modes & BASE) == 0) { + if (reg & 1) { + /* Fault */ + } + temp = GPR[reg|1]; + addr = GPR[reg]; + t = 0; + if ((temp|addr) != 0 && (temp&addr) != FMASK) { + uint32 m = temp & 0xF8000000; + while ((m == 0) || (m == 0xF8000000)) { + temp <<= 4; + m = temp & 0xF8000000; + temp |= (addr >> 28) & 0xf; + addr <<= 4; + t++; + } + GPR[reg|1] = temp; + GPR[reg] = addr; + } + GPR[(IR >> 20) & 7] = t; + } + break; + + case 0x1A: /* 0x68 */ /* SCZ */ + if ((modes & BASE) == 0) + goto scaz; + + case 0x1B: /* 0x6C */ /* non-basemode SRA & SLA */ + case 0x1C: /* 0x70 */ /* non-basemode SRL & SLL */ + case 0x1D: /* 0x74 */ /* non-basemode SRC & SLC */ + case 0x1E: /* 0x78 */ /* non-basemode SRAD & SLAD */ + case 0x1F: /* 0x7C */ /* non-basemode SRLD & SLLD */ + case 0x20: /* 0x80 */ /* LEAR */ + case 0x21: /* 0x84 */ /* ANMx */ + dest &= source; + break; + + case 0x22: /* 0x88 */ /* ORMx */ + dest |= source; + break; + + case 0x23: /* 0x8C */ /* EOMx */ + dest ^= source; + break; + + case 0x24: /* 0x90 */ /* CAMx */ + dest -= source; + break; + + case 0x25: /* 0x94 */ /* CMMx */ + dest ^= source; + CC = CC & AEXP; + if (dest == 0) + CC |= CC4; + break; + + case 0x26: /* 0x98 */ /* SBM */ + if ((FC & 04) != 0) { + /* Fault */ + } + if (Mem_read(addr, &temp)) { + /* Fault */ + } + t = 1 << (31 - (((FC & 3) << 3) | reg)); + ovr = (temp & t) != 0; + temp |= t; + if (Mem_write(addr, &temp)) { + /* Fault */ + } + CC = ((ovr)?CC1:0) | ((CC >> 1) & (CC2|CC3|CC4)) | (CC & AEXP); + break; + + case 0x27: /* 0x9C */ /* ZBM */ + if ((FC & 04) != 0) { + /* Fault */ + } + if (Mem_read(addr, &temp)) { + /* Fault */ + } + t = 1 << (31 - (((FC & 3) << 3) | reg)); + ovr = (temp & t) != 0; + temp &= ~t; + if (Mem_write(addr, &temp)) { + /* Fault */ + } + CC = ((ovr)?CC1:0) | ((CC >> 1) & (CC2|CC3|CC4)) | (CC & AEXP); + break; + + case 0x28: /* 0xA0 */ /* ABM */ + if ((FC & 04) != 0) { + /* Fault */ + } + if (Mem_read(addr, &temp)) { + /* Fault */ + } + t = 1 << (31 - (((FC & 3) << 3) | reg)); + ovr = (temp & FSIGN) != 0; + temp += t; + ovr ^= (temp & FSIGN) != 0; + if (Mem_write(addr, &temp)) { + /* Fault */ + } + dest = (uint64)temp | (temp & FSIGN) ? 0xFFFFFFFFLL << 32: 0; + break; + + case 0x29: /* 0xA4 */ /* TBM */ + if ((FC & 04) != 0) { + /* Fault */ + } + if (Mem_read(addr, &temp)) { + /* Fault */ + } + t = 1 << (31 - (((FC & 3) << 3) | reg)); + ovr = (temp & t) != 0; + CC = ((ovr)?CC1:0) | ((CC >> 1) & (CC2|CC3|CC4)) | (CC & AEXP); + break; + + case 0x2A: /* 0xA8 */ /* EXM */ + if ((FC & 04) != 0 || FC == 2) { + /* Fault */ + } + IR = (uint32)source; + if (FC == 3) + IR <<= 16; + if ((IR & 0xFC7F0000) == 0xC8070000 || + (IR & 0xFF800000) == 0xA8000000) { + /* Fault */ + } + goto exec; + + case 0x2B: /* 0xAC */ /* Lx */ + dest = source; + break; + + case 0x2C: /* 0xB0 */ /* LMx */ + dest = source & GPR[4]; + break; + + case 0x2D: /* 0xB4 */ /* LNx */ + dest = (source ^ DMASK) + 1; + if (dest == source) + ovr = 1; + break; + + case 0x2F: /* 0xBC */ /* SUMx */ + source = -source; + /* Fall through */ + + case 0x3A: /* 0xE8 */ /* ARMx */ + case 0x2E: /* 0xB8 */ /* 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; + break; + case 0x30: /* 0xC0 */ /* MPMx */ + if (FC == 3) { + /* Fault */ + } + if (reg & 1) { + /* Spec fault */ + } + dest = (uint64)((int64)dest * (int64)source); + dbl = 1; + break; + + case 0x31: /* 0xC4 */ /* DVMx */ + if (FC == 3) { + /* Fault */ + } + if (reg & 1) { + /* Spec fault */ + } + if (source == 0) { + ovr = 1; + 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; + reg|=1; + break; + + case 0x32: /* 0xC8 */ /* Immedate */ + temp = GPR[reg]; + addr = SEXT(IR); + switch(IR & 0xF) { + case 0x0: /* LI */ /* SCC | SR */ + temp = addr; + GPR[reg] = temp; + CC &= AEXP; + if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + break; + case 0x2: /* SUI */ + addr = -addr; + case 0x1: /* ADI */ + t = (temp & FSIGN) != 0; + t |= ((addr & FSIGN) != 0) ? 2 : 0; + temp = temp + addr; + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; + GPR[reg] = temp; + CC &= AEXP; + if (ovr) + CC |= CC1; + else if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + break; + case 0x3: /* MPI */ + if (reg & 1) { + /* Spec fault */ + } + 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 0x4: /* DVI */ + if (reg & 1) { + /* Spec fault */ + } + source = (uint64)addr | (addr & FSIGN) ? FMASK << 32: 0; + if (source == 0) { + ovr = 1; + 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; + if (dest & MSIGN) + CC |= CC3; + else if (dest == 0) + CC |= CC4; + else + CC |= CC2; + break; + + case 0x5: /* CI */ /* SCC */ + temp -= addr; + CC &= AEXP; + if (temp & FSIGN) + CC |= CC3; + else if (temp == 0) + CC |= CC4; + else + CC |= CC2; + break; + case 0x6: /* SVC */ + break; + case 0x7: /* EXR */ + IR = temp; + if (addr & 2) + IR <<= 16; + if ((IR & 0xFC7F0000) == 0xC8070000 || + (IR & 0xFF800000) == 0xA8000000) { + /* Fault */ + } + goto exec; + + case 0x8: /* SEM */ + break; + case 0x9: /* LEM */ + break; + case 0xA: /* CEMA */ + break; + case 0xB: /* INV */ + case 0xC: /* INV */ + case 0xD: /* INV */ + case 0xE: /* INV */ + case 0xF: /* INV */ + break; + } + break; + + case 0x33: /* 0xCC */ /* LF */ + /* For machines with Base mode 0xCC08 stores base registers */ + /* Validate access read addr to 8 - reg */ + temp = addr + (8 - reg); + if ((temp & 0x1f) != (addr & 0x1f)) { + /* Fault? */ + } + while (reg < 8) { + (void)Mem_read(addr, &GPR[reg]); + reg++; + addr += 4; + } + break; + + case 0x34: /* 0xD0 */ /* LEA */ + dest = (uint64)(addr); + /* if IX == 00 => dest = IR */ + /* if IX == 0g => dest = IR + reg */ + /* if IX == Ix => dest = ind + reg */ + break; + + case 0x35: /* 0xD4 */ /* STx */ + break; + + case 0x36: /* 0xD8 */ /* STMx */ + dest &= GPR[4]; + break; + + case 0x37: /* 0xDC */ /* STFx */ + /* For machines with Base mode 0xDC08 stores base registers */ + /* Validate access write addr to 8 - reg */ + temp = addr + (8 - reg); + if ((temp & 0x1f) != (addr & 0x1f)) { + /* Fault? */ + } + while (reg < 8) { + (void)Mem_write(addr, &GPR[reg]); + reg++; + addr += 4; + } + break; + + case 0x38: /* 0xE0 */ /* ADFx, SUFx */ + case 0x39: /* 0xE4 */ /* MPFx, DVFx */ + case 0x3B: /* 0xEC */ /* Branch True */ + switch(reg) { + case 0: ovr = 1; break; + case 1: ovr = (CC & CC1) != 0; break; + case 2: ovr = (CC & CC2) != 0; break; + case 3: ovr = (CC & CC3) != 0; break; + case 4: ovr = (CC & CC4) != 0; break; + case 5: ovr = (CC & (CC2|CC4)) != 0; break; + case 6: ovr = (CC & (CC3)|CC4) != 0; break; + case 7: ovr = (CC & (CC1|CC2|CC3|CC4)) != 0; break; + } + if (ovr) { + PC = addr; + CC = ((CC1|CC2|CC3|CC4) & (addr >> 24)) | (AEXP & CC); + } + break; + + case 0x3C: /* 0xF0 */ /* Branch False */ + if ((FC & 5) != 0) { + /* Fault */ + } + switch(reg) { + case 0: ovr = (GPR[4] & (1 << ((CC >> 3) + 16))) == 0; break; + case 1: ovr = (CC & CC1) == 0; break; + case 2: ovr = (CC & CC2) == 0; break; + case 3: ovr = (CC & CC3) == 0; break; + case 4: ovr = (CC & CC4) == 0; break; + case 5: ovr = (CC & (CC2|CC4)) == 0; break; + case 6: ovr = (CC & (CC3)|CC4) == 0; break; + case 7: ovr = (CC & (CC1|CC2|CC3|CC4)) == 0; break; + } + if (ovr) { + PC = addr; + CC = ((CC1|CC2|CC3|CC4) & (addr >> 24)) | (AEXP & CC); + } + break; + + case 0x3D: /* 0xF4 */ /* Branch increment */ + dest += 1 << (IR >> 21); + if (dest == 0) + PC = addr; + break; + + case 0x3E: /* 0xF8 */ /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, RRP */ + switch((IR >> 7) & 0x7) { + case 0x0: /* ZMx */ /* SM */ + dest = 0; + break; + case 0x1: /* BL */ + GPR[0] = (CC << 24) | PC; + PC = addr; + CC = ((CC1|CC2|CC3|CC4) & (addr >> 24)) | (AEXP & CC); + break; + + case 0x2: /* BRI */ + break; + case 0x3: /* LPSD */ + break; + case 0x4: /* INV */ + break; + case 0x5: /* LPSDCM */ + break; + case 0x6: /* TRP */ + break; + case 0x7: /* TPR */ + } + break; + + case 0x3F: /* 0xFC */ /* IO */ + } + + /* Store result to register */ + if (i_flags & SD) { + if (dbl) + GPR[reg|1] = (uint32)(dest>>32); + GPR[reg] = (uint32)(dest & FMASK); + } + + /* Store result to base register */ + if (i_flags & SBR) { + if (dbl) { + /* Fault */ + } + BR[reg] = (uint32)(dest & FMASK); + } + + /* Store result to memory */ + if (i_flags & SM) { + /* Check if byte of half word */ + if (((FC & 04) || (FC & 5) == 1) && Mem_read(addr, &temp)) { + /* Fault */ + } + switch(FC) { + case 2: if ((addr & 7) != 0) { + } + temp = (uint32)(dest >> 32); + if (Mem_write(addr + 4, &temp)) { + } + /* Fall through */ + + case 0: temp = (uint32)(dest & FMASK); + if ((addr & 3) != 0) { + /* Address fault */ + } + break; + + case 1: temp &= RMASK; + temp |= (uint32)(dest & RMASK) << 16; + if ((addr & 1) != 0) { + /* Address Fault */ + } + break; + + case 3: temp &= LMASK; + temp |= (uint32)(dest & RMASK); + if ((addr & 1) != 0) { + /* Address Fault */ + } + break; + + case 4: + case 5: + case 6: + case 7: + temp &= ~(0xFF << (8 * (7 - FC))); + temp |= (uint32)(dest & 0xFF) << (8 * (7 - FC)); + break; + } + if (Mem_write(addr, &temp)) { + /* Fault */ + } + } + + /* Update condition code registers */ + if (i_flags & SCC) { + CC = CC & AEXP; + if (ovr) + CC |= CC1; + else if (dest & MSIGN) + CC |= CC3; + else if (dest == 0) + CC |= CC4; + else + CC |= CC2; + } + + /* 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 & EXTD) ? 0xFFFFFF : 0x7FFFF; + } /* end while */ + +/* Simulation halted */ + + return reason; +} + + +/* Reset routine */ + +t_stat +cpu_reset(DEVICE * dptr) +{ + int i; + + sim_brk_types = sim_brk_dflt = SWMASK('E'); + + return SCPE_OK; +} + +/* Interval timer routines */ +t_stat +rtc_srv(UNIT * uptr) +{ + return SCPE_OK; +} + +/* Memory examine */ + +t_stat +cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw) +{ + uint32 wrd; + if (addr >= MSIZE) + return SCPE_NXM; + if (vptr == NULL) + return SCPE_OK; + wrd = M[addr >> 2]; + wrd >>= 8 * (3 - (addr & 3)); + *vptr = wrd; + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat +cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw) +{ + uint32 wrd; + uint32 msk; + int of; + if (addr >= MSIZE) + return SCPE_NXM; + if (vptr == NULL) + return SCPE_OK; + of = 8 * (3 - (addr & 3)); + addr >>= 2; + wrd = M[addr]; + msk = 0xFF << of; + wrd &= ~msk; + wrd |= (*vptr * 0xFF) << of; + return SCPE_OK; +} + +t_stat +cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc) +{ + t_uint64 mc = 0; + uint32 i; + + cpu_unit.flags &= ~UNIT_MSIZE; + cpu_unit.flags |= val; + val >>= UNIT_V_MSIZE; + val = (val + 1) * 128 * 1024; + if ((val < 0) || (val > MAXMEMSIZE)) + return SCPE_ARG; + for (i = val; i < MEMSIZE; i++) + mc |= M[i]; + if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE))) + return SCPE_OK; + MEMSIZE = val; + memmask = val - 1; + for (i = MEMSIZE; i < MAXMEMSIZE; i++) + M[i] = 0; + return SCPE_OK; +} + +/* 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) { + for (i = 0; i < hst_lnt; i++) + hst[i].ic = 0; + hst_p = 0; + return SCPE_OK; + } + lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r); + if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; + hst_p = 0; + if (hst_lnt) { + free(hst); + hst_lnt = 0; + hst = NULL; + } + if (lnt) { + hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt); + + if (hst == NULL) + return SCPE_MEM; + hst_lnt = lnt; + } + return SCPE_OK; +} + +/* 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) + return SCPE_NOFNC; /* enabled? */ + if (cptr) { + lnt = (int32) get_uint(cptr, 10, hst_lnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) + return SCPE_ARG; + } else + lnt = hst_lnt; + di = hst_p - lnt; /* work forward */ + if (di < 0) + di = di + hst_lnt; + fprintf(st, " \n\n"); + for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->ic & HIST_PC) { /* instruction? */ + fputc('\n', st); /* end line */ + } /* end else instruction */ + } /* end for */ + return SCPE_OK; +} + +const char * +cpu_description (DEVICE *dptr) +{ + return "SEL 32 CPU"; +} + +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 new file mode 100644 index 0000000..5df8bc8 --- /dev/null +++ b/SEL32/sel32_defs.h @@ -0,0 +1,259 @@ +/* sel32_defs.h: Gould Concept/32 (orignal SEL32) simulator definitions + + Copyright (c) 2017, Richard Cornwell + + 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 + ROBERT M SUPNIK 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 */ + +/* 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 */ + +/* Conditional error returns */ + +/* 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) + +/* Device information block */ +typedef struct dib { + uint8 dev_addr; /* Device address */ + uint8 dev_class; /* Device class */ +/* 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); +} DIB; + + +/* Opcode definitions */ +#define OP_HALT 0x0000 /* Halt # * */ +#define OP_WAIT 0x0001 /* Wait # * */ +#define OP_NOP 0x0002 /* Nop # */ +#define OP_LCS 0x0003 /* Load Control Switches */ +#define OP_ES 0x0004 /* Extend Sign # */ +#define OP_RND 0x0005 /* Round Register # */ +#define OP_BEI 0x0006 /* Block External Interrupts # */ +#define OP_UEI 0x0007 /* Unblock External Interrupts # */ +#define OP_EAE 0x0008 /* Enable Arithmetic Exception Trap # */ +#define OP_RDSTS 0x0009 /* Read CPU Status Word * */ +#define OP_SIPU 0x000A /* Signal IPU # */ +#define OP_SEA 0x000D /* Set Extended Addressing # NBR */ +#define OP_DAE 0x000E /* Disable Arithmetic Exception Trap # */ +#define OP_CEA 0x000F /* Clear Extended Addressing # NBR */ +#define OP_ANR 0x0400 /* And Register # */ +#define OP_CMC 0x040A /* Cache Memory Control # */ +#define OP_SMC 0x0407 /* Shared Memory Control # */ +#define OP_RPSWT 0x040B /* Read Processor Status Word two # */ +#define OP_ORR 0x0800 /* Or Register # */ +#define OP_ORRM 0x0808 /* Or Register Masked # */ +#define OP_ZR 0x0C00 /* Zero Register # */ +#define OP_EOR 0x0C00 /* Exclusive Or Register # */ +#define OP_EORM 0x0C08 /* Exclusive Or Register Masked # */ +#define OP_CAR 0x1000 /* Compare Register # */ +#define OP_SACZ 0x1008 /* Shift and Count Zeros # BR */ +#define OP_CMR 0x1400 /* Compare masked with register */ +#define OP_SBR 0x1800 /* Set Bit in Register # */ +#define OP_ZBR 0x1804 /* Zero Bit In register # BR */ +#define OP_ABR 0x1808 /* Add Bit In Register # BR */ +#define OP_TBR 0x180C /* Test Bit in Register # BR */ +#define OP_SRABR 0x1C00 /* Shift Right Arithmetic # BR */ +#define OP_SRLBR 0x1C20 /* Shift Right Logical # BR */ +#define OP_SLABR 0x1C40 /* Shift Left Arithmetic # BR */ +#define OP_SLLBR 0x1C60 /* Shift Left Logical # BR */ +#define OP_SRADBR 0x2000 /* Shift Right Arithmetic Double # BR */ +#define OP_SRLDBR 0x2020 /* Shift Left Logical Double # BR */ +#define OP_SLADBR 0x2040 /* Shift Right Arithmetic Double # BR */ +#define OP_SLLDBR 0x2060 /* Shift Left Logical Double # BR */ +#define OP_SRCBR 0x2400 /* Shift Right Circular # BR */ +#define OP_ZBM 0x1C00 /* Zero Bit in Register # NBR */ +#define OP_ABR 0x2000 /* Add Bit in Register # NBR */ +#define OP_TBR 0x2400 /* Test Bit in Register # NBR */ +#define OP_TRSW 0x2800 /* Transfer GPR to PSD */ +#define OP_TRBR 0x2801 /* Transfer GPR to BR # BR */ +#define OP_XCBR 0x2802 /* Exchange Base Registers # BR */ +#define OP_TCCR 0x2802 /* Transfer CC to GPR # BR */ +#define OP_TRCC 0x2804 /* Transfer GPR to CC # BR */ +#define OP_BSUB 0x2805 /* Branch Subroutine # BR */ +#define OP_CALL 0x2808 /* Procedure Call # BR */ +#define OP_TPCBR 0x280C /* Transfer Program Counter to Base # BR */ +#define OP_RETURN 0x280E /* Procedure Return # BR */ +#define OP_TRR 0x2C00 /* Transfer Register to Register # */ +#define OP_TRDR 0x2C01 /* Transfer GPR to BR # */ +#define OP_TBRR 0x2C02 /* Transfer BR to GPR BR # */ +#define OP_TRC 0x2C03 /* Transfer Register Complement # */ +#define OP_TRN 0x2C04 /* Transfer Register Negative # */ +#define OP_XCR 0x2C05 /* Exchange Registers # */ +#define OP_LMAP 0x2C07 /* Load MAP * */ +#define OP_TRRM 0x2C08 /* Transfer Register to Register Masked # */ +#define OP_SETCPU 0x2C09 /* Set CPU Mode # * */ +#define OP_TMAPR 0x2C0A /* Transfer MAP to Register # * */ +#define OP_XCRM 0x2C0D /* Exchange Registers Masked # */ +#define OP_TRCM 0x2C0B /* Transfer Register Complement Masked # */ +#define OP_TRNM 0x2C0C /* Transfer Register Negative Masked # */ +#define OP_TRSC 0x2C0E /* Transfer Register to Scratchpad # * */ +#define OP_TSCR 0x2C0F /* Transfer Scratchpad to Register # * */ +#define OP_CALM 0x3000 /* Call Monitor # */ +#define OP_LA 0x3400 /* Load Address NBR */ +#define OP_ADR 0x3800 /* Add Register to Register # */ +#define OP_ADRFW 0x3801 /* Add Floating Point to Register # BR? */ +#define OP_MPRBR 0x3802 /* Multiply Register BR # */ +#define OP_SURFW 0x3803 /* Subtract Floating Point Register BR? # */ +#define OP_DVRFW 0x3804 /* Divide Floating Point Register BR? # */ +#define OP_FIXW 0x3805 /* Fix Floating Point Register BR? # */ +#define OP_MPRFW 0x3806 /* Multiply Floating Point Register BR? # */ +#define OP_FLTW 0x3807 /* Float Floating Point Register BR? # */ +#define OP_ADRM 0x3808 /* Add Register to Register Masked # */ +#define OP_DVRBR 0x380A /* Divide Register by Registier BR # */ +#define OP_SURFD 0x380B /* Subtract Floating Point Double # BR? */ +#define OP_DVRFD 0x380C /* Divide Floating Point Double # BR? */ +#define OP_FIXD 0x380D /* Fix Double Register # BR? */ +#define OP_MPRFD 0x380E /* Multiply Double Register # BR? */ +#define OP_FLTD 0x380F /* Float Double # BR? */ +#define OP_SUR 0x3C00 /* Subtract Register to Register # */ +#define OP_SURM 0x3C08 /* Subtract Register to Register Masked # */ +#define OP_MPR 0x4000 /* Multiply Register to Register # NBR */ +#define OP_DVR 0x4400 /* Divide Register to Register # NBR */ +#define OP_LA 0x5000 /* Load Address BR */ +#define OP_STWBR 0x5400 /* Store Base Register BR */ +#define OP_SUABR 0x5800 /* Subtract Base Register BR */ +#define OP_LABR 0x5808 /* Load Address Base Register BR */ +#define OP_LWBR 0x5C00 /* Load Base Register BR */ +#define OP_BSUBM 0x5C08 /* Branch Subroutine Memory BR */ +#define OP_CALLM 0x5C08 /* Call Memory BR */ +#define OP_NOR 0x6000 /* Normalize # NBR */ +#define OP_NORD 0x6400 /* Normalize Double # NBR*/ +#define OP_SCZ 0x6800 /* Shift and Count Zeros # */ +#define OP_SRA 0x6C00 /* Shift Right Arithmetic # NBR */ +#define OP_SLA 0x6C40 /* Shift Left Arithmetic # NBR */ +#define OP_SRL 0x7000 /* Shift Right Logical # NBR */ +#define OP_SLL 0x7040 /* Shift Left Logical # NBR */ +#define OP_SRC 0x7400 /* Shift Right Circular # NBR */ +#define OP_SLC 0x7440 /* Shift Left Circular # NBR */ +#define OP_SRAD 0x7800 /* Shift Right Arithmetic Double # NBR */ +#define OP_SLAD 0x7840 /* Shift Left Arithmetic Double # NBR */ +#define OP_SRLD 0x7C00 /* Shift Right Logical Double # NBR */ +#define OP_SLLD 0x7C40 /* Shift Left Logical Double # NBR */ +#define OP_LEAR 0x8000 /* Load Effective Address Real * */ +#define OP_ANMx 0x8400 /* And Memory B,H,W,D */ +#define OP_ORMx 0x8800 /* Or Memory B,H,W,D */ +#define OP_EOMx 0x8C00 /* Exclusive Or Memory */ +#define OP_CAMx 0x9000 /* Compare Arithmetic with Memory */ +#define OP_CMMx 0x9400 /* Compare Masked with Memory */ +#define OP_SBM 0x9800 /* Set Bit in Memory */ +#define OP_ZBM 0x9C00 /* Zero Bit in Memory */ +#define OP_ABM 0xA000 /* Add Bit in Memory */ +#define OP_TBM 0xA400 /* Test Bit in Memory */ +#define OP_EXM 0xA800 /* Execute Memory */ +#define OP_Lx 0xAC00 /* Load B,H,W,D */ +#define OP_LMx 0xB000 /* Load Masked B,H,W,D */ +#define OP_LNx 0xB400 /* Load Negative B,H,W,D */ +#define OP_ADMx 0xB800 /* Add Memory B,H,W,D */ +#define OP_SUMx 0xBC00 /* Subtract Memory B,H,W,D */ +#define OP_MPMx 0xC000 /* Multiply Memory B,H,W,D */ +#define OP_DVMx 0xC400 /* Divide Memory B,H,W,D */ +#define OP_LI 0xC800 /* Load Immediate */ +#define OP_ADI 0xC801 /* Add Immediate */ +#define OP_SUI 0xC802 /* Subtract Immediate */ +#define OP_MPI 0xC803 /* Multiply Immediate */ +#define OP_DVI 0xC804 /* Divide Immediate */ +#define OP_CI 0xC805 /* Compare Immediate */ +#define OP_SVC 0xC806 /* Supervisor Call */ +#define OP_EXR 0xC807 /* Execute Register/ Right */ +#define OP_SEM 0xC808 /* Store External Map * */ +#define OP_LEM 0xC809 /* Load External Map * */ +#define OP_CEMA 0xC80A /* Convert External Map * */ +#define OP_LF 0xCC00 /* Load File */ +#define OP_LEA 0xD000 /* Load Effective Address */ +#define OP_STx 0xD400 /* Store B,H,W,D */ +#define OP_STMx 0xD800 /* Store Masked B,H,W,D */ +#define OP_ADFx 0xE008 /* Add Floating Memory D,W */ +#define OP_SUFx 0xE000 /* Subtract Floating Memory D,W */ +#define OP_MPFx 0xE408 /* Multiply Floating Memory D,W */ +#define OP_DVFx 0xE400 /* Divide Floating Memory D,W */ +#define OP_ARMx 0xE800 /* Add Register to Memory B,H,W,D */ +#define OP_BU 0xEC00 /* Branch Unconditional */ +#define OP_BCT 0xEC00 /* Branch Condition True */ +#define OP_BCF 0xF000 /* Branch Condition False */ +#define OP_BIB 0xF400 /* Branch after Incrementing Byte */ +#define OP_BIW 0xF420 /* Branch after Incrementing Word */ +#define OP_BIH 0xF440 /* Branch after Incrementing Half */ +#define OP_BID 0xF460 /* Branch after Incrementing Double */ +#define OP_ZMx 0xF800 /* Zero Memory B,H,W,D */ +#define OP_BL 0xF880 /* Branch and Link */ +#define OP_BRI 0xF900 /* Branch and Reset Interrupt * */ +#define OP_LPSD 0xF980 /* Load Program Status Double * */ +#define OP_LPSDCM 0xFA80 /* LPSD and Change Map * */ +#define OP_TPR 0xFB80 /* Transfer Protect Register to Register */ +#define OP_TRP 0xFB00 /* Transfer Register to Protect Register */ +#define OP_EI 0xFC00 /* Enable Interrupt */ +#define OP_DI 0xFC01 /* Disable Interrupt */ +#define OP_RI 0xFC02 /* Request Interrupt */ +#define OP_AI 0xFC03 /* Activate Interrupt */ +#define OP_DAI 0xFC04 /* Deactivate Interrupt */ +#define OP_TD 0xFC05 /* Test Device */ +#define OP_CD 0xFC06 /* Command Device */ +#define OP_SIO 0xFC17 /* Start I/O */ +#define OP_TIO 0xFC1F /* Test I/O */ +#define OP_STPIO 0xFC27 /* Stop I/O */ +#define OP_RSCHNL 0xFC2F /* Reset Channel */ +#define OP_HIO 0xFC37 /* Halt I/O */ +#define OP_GRIO 0xFC3F /* Grab Controller */ +#define OP_RSCTL 0xFC47 /* Reset Controller */ +#define OP_ECI 0xFC67 /* Enable Channel Interrupt */ +#define OP_DCI 0xFC6F /* Disable Channel Interrupt */ +#define OP_ACI 0xFC77 /* Activate Channel Interrupt */ +#define OP_DACI 0xFC7F /* Deactivate Channel Interrupt */ + + + +/* Debuging controls */ +#define DEBUG_CMD 0x0000001 /* Show device commands */ +#define DEBUG_DATA 0x0000002 /* Show data transfers */ +#define DEBUG_DETAIL 0x0000004 /* Show details */ +#define DEBUG_EXP 0x0000008 /* Show error conditions */ +#define DEBUG_CONI 0x0000020 /* Show CONI instructions */ +#define DEBUG_CONO 0x0000040 /* Show CONO instructions */ +#define DEBUG_DATAIO 0x0000080 /* Show DATAI/O instructions */ +#define DEBUG_IRQ 0x0000100 /* Show IRQ requests */ + +extern DEBTAB dev_debug[]; + + +extern DEVICE cpu_dev; diff --git a/SEL32/sel32_sys.c b/SEL32/sel32_sys.c new file mode 100644 index 0000000..5c3dc28 --- /dev/null +++ b/SEL32/sel32_sys.c @@ -0,0 +1,876 @@ +/* sel32_sys.c: SEL 32 Gould Concept/32 (orignal SEL32) Simulator system interface. + + Copyright (c) 2018, Richard Cornwell + + 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 + ROBERT M SUPNIK 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 + +extern DEVICE cpu_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern uint32 M[MAXMEMSIZE]; + +/* SCP data structures and interface routines + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "SEL 32"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 16; + +DEVICE *sim_devices[] = { + &cpu_dev, +#ifdef NUM_DEVS_CON + &con_dev, +#endif +#ifdef NUM_DEVS_CDR + &cdr_dev, +#endif +#ifdef NUM_DEVS_CDP + &cdp_dev, +#endif +#ifdef NUM_DEVS_LPR + &lpr_dev, +#endif +#ifdef NUM_DEVS_MT + &mta_dev, +#if NUM_DEVS_MT > 1 + &mtb_dev, +#endif +#endif +#ifdef NUM_DEVS_DASD + &dda_dev, +#if NUM_DEVS_DASD > 1 + &ddb_dev, +#endif +#endif +#ifdef NUM_DEVS_COM + &com_dev, +#endif + NULL }; + + +/* Simulator debug controls */ +DEBTAB dev_debug[] = { + {"CMD", DEBUG_CMD, "Show command execution to devices"}, + {"DATA", DEBUG_DATA, "Show data transfers"}, + {"DETAIL", DEBUG_DETAIL, "Show details about device"}, + {"EXP", DEBUG_EXP, "Show exception information"}, + {"INST", DEBUG_INST, "Show instruction execution"}, + {0, 0} +}; + + +const char *sim_stop_messages[] = { + }; + + + +/* Load a card image file into memory. */ + +t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ +return SCPE_NOFNC; +} + +/* Symbol tables */ + +/* + * The SEL 32 supports the following instruction formats. + * + * TYPE Format Normal Base Mode + * A ADR d,[*]o,x d,o[(b)],x FC = extra + * B BRA [*]o,x o[(b)],x + * C IMM d,o d,o + * D BIT d,[*]o,x d,o[(b)],x + * E ADR [*]o,x o[(b)],x FC = extra + * F REG s,d s,d Half Word + * G RG1 s s + * H HLF + * I SHF d,v d,v + * K RBT d,b d,b + * L EXR s s + * M IOP n,b n,b + */ + +#define TYPE_A 0 +#define TYPE_B 1 +#define TYPE_C 2 +#define TYPE_D 3 +#define TYPE_E 4 +#define TYPE_F 5 +#define TYPE_G 6 +#define TYPE_H 7 +#define TYPE_I 8 +#define TYPE_K 9 +#define TYPE_L 10 +#define TYPE_M 11 +#define H 0x10 + +typedef struct _opcode { + uint16 opbase; + uint16 mask; + uint8 type; + char *name; +} t_opcode; + + +t_opcode optab[] { + { OP_HALT, 0xFFFF, H|TYPE_H, "HALT", }, /* Halt # * */ + { OP_WAIT, 0xFFFF, H|TYPE_H, "WAIT", }, /* Wait # * */ + { OP_NOP, 0xFFFF, H|TYPE_H, "NOP", }, /* Nop # */ + { OP_LCS, 0xFFFF, H|TYPE_G, "LCS", }, /* Load Control Switches */ + { OP_ES, 0xFC0F, H|TYPE_G, "ES", }, /* Extend Sign # */ + { OP_SIPU, 0xFFFF, H|TYPE_H, "SIPU", }, /* Signal IPU # */ + { OP_RND, 0xFC0F, H|TYPE_G, "RND", }, /* Round Register # */ + { OP_BEI, 0xFC0F, H|TYPE_H, "BEI", }, /* Block External Interrupts # */ + { OP_UEI, 0xFC0F, H|TYPE_H, "UEI", }, /* Unblock External Interrupts # */ + { OP_EAE, 0xFC0F, H|TYPE_H, "EAE", }, /* Enable Arithmetic Exception Trap # */ + { OP_RDSTS, 0xFC0F, H|TYPE_G, "RDSTS", }, /* Read CPU Status Word * */ + { OP_SEA, 0xFFFF, H|TYPE_H, "SEA", }, /* Set Extended Addressing # NBR */ + { OP_DAE, 0xFC0F, H|TYPE_H, "DAE", }, /* Disable Arithmetic Exception Trap # */ + { OP_CEA, 0xFFFF, H|TYPE_H, "CEA", }, /* Clear Extended Addressing # NBR */ + { OP_CMC, 0xFC0F, H|TYPE_G, "CMC", }, /* Cache Memory Control # */ + { OP_SMC, 0xFC0F, H|TYPE_G, "SMC", }, /* Shared Memory Control # */ + { OP_ANR, 0xFC0F, H|TYPE_F, "ANR", }, /* And Register # */ + { OP_RPSWT, 0xFC0F, H|TYPE_G, "RPSWT", }, /* Read Processor Status Word Two # */ + { OP_ORR, 0xFC0F, H|TYPE_F, "ORR", }, /* Or Register # */ + { OP_ORRM, 0xFC0F, H|TYPE_F, "ORRM", }, /* Or Register Masked # */ + { OP_EOR, 0xFC0F, H|TYPE_F, "EOR", }, /* Exclusive Or Register # */ + { OP_EORM, 0xFC0F, H|TYPE_F, "EORM", }, /* Exclusive Or Register Masked # */ + { OP_CAR, 0xFC0F, H|TYPE_F, "CAR", }, /* Compare Register # */ + { OP_CMR, 0xFC0F, H|TYPE_F, "CMR", }, /* Compare masked with register */ + { OP_SACZ, 0xFC0F, H|TYPE_F, "SACZ", }, /* Shift and Count Zeros # BR */ + { OP_SBR, 0xFC0F, H|TYPE_K, "SBR", }, /* Set Bit in Register # */ + { OP_ZBR, 0xFC0F, H|TYPE_K, "ZBR", }, /* Zero Bit In register # BR */ + { OP_ABR, 0xFC0F, H|TYPE_K, "ABR", }, /* Add Bit In Register # BR */ + { OP_TBR, 0xFC0F, H|TYPE_K, "TBR", }, /* Test Bit in Register # BR */ + { OP_SRABR, 0xFC0F, H|TYPE_I, "SRABR", }, /* Shift Right Arithmetic # BR */ + { OP_SRLBR, 0xFC0F, H|TYPE_I, "SRLBR", }, /* Shift Right Logical # BR */ + { OP_SLABR, 0xFC0F, H|TYPE_I, "SLABR", }, /* Shift Left Arithmetic # BR */ + { OP_SLLBR, 0xFC0F, H|TYPE_I, "SLLBR", }, /* Shift Left Logical # BR */ + { OP_SRADBR, 0xFC0F, H|TYPE_I, "SRADBR", }, /* Shift Right Arithmetic Double # BR */ + { OP_SRLDBR, 0xFC0F, H|TYPE_I, "SRLDBR", }, /* Shift Left Logical Double # BR */ + { OP_SLADBR, 0xFC0F, H|TYPE_I, "SLADBR", }, /* Shift Right Arithmetic Double # BR */ + { OP_SLLDBR, 0xFC0F, H|TYPE_I, "SLLDBR", }, /* Shift Left Logical Double # BR */ + { OP_SRCBR, 0xFC0F, H|TYPE_I, "SRCBR", }, /* Shift Right Circular # BR */ + { OP_ZBR, 0xFC0F, H|TYPE_K, "ZBR", }, /* Zero Bit in Register # NBR */ + { OP_ABR, 0xFC0F, H|TYPE_K, "ABR", }, /* Add Bit in Register # NBR */ + { OP_TBR, 0xFC0F, H|TYPE_K, "TBR", }, /* Test Bit in Register # NBR */ + { OP_TRSW, 0xFC0F, H|TYPE_F, "TRSW", }, /* Transfer GPR to PSD */ + { OP_TRBR, 0xFC0F, H|TYPE_F, "TRBR", }, /* Transfer GPR to BR # BR */ + { OP_XCBR, 0xFC0F, H|TYPE_F, "XCBR", }, /* Exchange Base Registers # BR */ + { OP_TCCR, 0xFC0F, H|TYPE_G, "TCCR", }, /* Transfer CC to GPR # BR */ + { OP_TRCC, 0xFC0F, H|TYPE_G, "TRCC", }, /* Transfer GPR to CC # BR */ + { OP_BSUB, 0xFC0F, H|TYPE_F, "BSUB", }, /* Branch Subroutine # BR */ + { OP_CALL, 0xFC0F, H|TYPE_F, "CALL", }, /* Procedure Call # BR */ + { OP_TPCBR, 0xFC0F, H|TYPE_G, "TPCBR", }, /* Transfer Program Counter to Base # BR */ + { OP_RETURN, 0xFC7F, H|TYPE_G, "RETURN", }, /* Procedure Return # BR */ + { OP_TRR, 0xFC0F, H|TYPE_F, "TRR", }, /* Transfer Register to Register # */ + { OP_TRDR, 0xFC0F, H|TYPE_F, "TRDR", }, /* Transfer GPR to BR # */ + { OP_TBRR, 0xFC0F, H|TYPE_A, "TBRR", }, /* Transfer BR to GPR BR # */ + { OP_TRC, 0xFC0F, H|TYPE_F, "TRC", }, /* Transfer Register Complement # */ + { OP_TRN, 0xFC0F, H|TYPE_F, "TRN", }, /* Transfer Register Negative # */ + { OP_XCR, 0xFC0F, H|TYPE_F, "XCR", }, /* Exchange Registers # */ + { OP_LMAP, 0xFC0F, H|TYPE_G, "LMAP", }, /* Load MAP * */ + { OP_TRRM, 0xFC0F, H|TYPE_F, "TRRM", }, /* Transfer Register to Register Masked # */ + { OP_SETCPU, 0xFC0F, H|TYPE_G, "SETCPU", }, /* Set CPU Mode # * */ + { OP_TMAPR, 0xFC0F, H|TYPE_F, "TMAPR", }, /* Transfer MAP to Register # * */ + { OP_XCRM, 0xFC0F, H|TYPE_F, "XCRM", }, /* Exchange Registers Masked # */ + { OP_TRCM, 0xFC0F, H|TYPE_F, "TRCM", }, /* Transfer Register Complement Masked # */ + { OP_TRNM, 0xFC0F, H|TYPE_F, "TRNM", }, /* Transfer Register Negative Masked # */ + { OP_TRSC, 0xFC0F, H|TYPE_F, "TRSC", }, /* Transfer Register to Scratchpad # * */ + { OP_TSCR, 0xFC0F, H|TYPE_F, "TSCR", }, /* Transfer Scratchpad to Register # * */ + { OP_CALM, 0xFC0F, H|TYPE_F, "CALM", }, /* Call Monitor # */ + { OP_LA, 0xFC0F, H|TYPE_F, "LA", }, /* Load Address NBR */ + { OP_ADR, 0xFC0F, H|TYPE_F, "ADR", }, /* Add Register to Register # */ + { OP_ADRFW, 0xFC0F, H|TYPE_F, "ADRFW", }, /* Add Floating Point to Register # BR? */ + { OP_MPRBR, 0xFC0F, H|TYPE_F, "MPRBR", }, /* Multiply Register BR # */ + { OP_SURFW, 0xFC0F, H|TYPE_F, "SURFW", }, /* Subtract Floating Point Register BR? # */ + { OP_DVRFW, 0xFC0F, H|TYPE_F, "DVRFW", }, /* Divide Floating Point Register BR? # */ + { OP_FIXW, 0xFC0F, H|TYPE_F, "FIXW", /* Fix Floating Point Register BR? # */ + { OP_MPRFW, 0xFC0F, H|TYPE_F, "MPRFW", }, /* Multiply Floating Point Register BR? # */ + { OP_FLTW, 0xFC0F, H|TYPE_F, "FLTW", }, /* Float Floating Point Register BR? # */ + { OP_ADRM, 0xFC0F, H|TYPE_F, "ADRM", /* Add Register to Register Masked # */ + { OP_DVRBR, 0xFC0F, H|TYPE_F, "DVRBR", /* Divide Register by Registier BR # */ + { OP_SURFD, 0xFC0F, H|TYPE_F, "SURFD", }, /* Subtract Floating Point Double # BR? */ + { OP_DVRFD, 0xFC0F, H|TYPE_F, "DVRFD", }, /* Divide Floating Point Double # BR? */ + { OP_FIXD, 0xFC0F, H|TYPE_F, "FIXD", }, /* Fix Double Register # BR? */ + { OP_MPRFD, 0xFC0F, H|TYPE_F, "MPRFD", }, /* Multiply Double Register # BR? */ + { OP_FLTD, 0xFC0F, H|TYPE_F, "FLTD", }, /* Float Double # BR? */ + { OP_SUR, 0xFC0F, H|TYPE_F, "SUR", }, /* Subtract Register to Register # */ + { OP_SURM, 0xFC0F, H|TYPE_F, "SURM", }, /* Subtract Register to Register Masked # */ + { OP_MPR, 0xFC0F, H|TYPE_F, "MPR", }, /* Multiply Register to Register # NBR */ + { OP_DVR, 0xFC0F, H|TYPE_F, "DVR", /* Divide Register to Register # NBR */ + { OP_LA, 0xFC0F, H|TYPE_F, "LA", }, /* Load Address BR */ + { OP_STWBR, 0xFC0F, H|TYPE_F, "STWBR", }, /* Store Base Register BR */ + { OP_SUABR, 0xFC0F, H|TYPE_F, "SUABR", }, /* Subtract Base Register BR */ + { OP_LABR, 0xFC0F, H|TYPE_F, "LABR", }, /* Load Address Base Register BR */ + { OP_LWBR, 0xFC0F, H|TYPE_F, "WBR", }, /* Load Base Register BR */ + { OP_BSUBM, 0xFC0F, H|TYPE_F, "BSUBM", }, /* Branch Subroutine Memory BR */ + { OP_CALLM, 0xFC0F, H|TYPE_F, "CALLM", }, /* Call Memory BR */ + { OP_NOR, 0xFC0F, H|TYPE_F, "NOR", }, /* Normalize # NBR */ + { OP_NORD, 0xFC0F, H|TYPE_F, "NORD", }, /* Normalize Double # NBR*/ + { OP_SCZ, 0xFC0F, H|TYPE_F, "SCZ", }, /* Shift and Count Zeros # */ + { OP_SRA, 0xFC0F, H|TYPE_I, "SRA", }, /* Shift Right Arithmetic # NBR */ + { OP_SLA, 0xFC40, H|TYPE_I, "SLA", }, /* Shift Left Arithmetic # NBR */ + { OP_SRL, 0xFC40, H|TYPE_I, "SRL", }, /* Shift Right Logical # NBR */ + { OP_SLL, 0xFC40, H|TYPE_I, "SLL", }, /* Shift Left Logical # NBR */ + { OP_SRC, 0xFC40, H|TYPE_I, "SRC", }, /* Shift Right Circular # NBR */ + { OP_SLC, 0xFC40, H|TYPE_I, "SLC", }, /* Shift Left Circular # NBR */ + { OP_SRAD, 0xFC40, H|TYPE_I, "SRAD", }, /* Shift Right Arithmetic Double # NBR */ + { OP_SLAD, 0xFC40, H|TYPE_I, "SLAD", }, /* Shift Left Arithmetic Double # NBR */ + { OP_SRLD, 0xFC40, H|TYPE_I, "SRLD", }, /* Shift Right Logical Double # NBR */ + { OP_SLLD, 0xFC40, H|TYPE_I, "SLLD", }, /* Shift Left Logical Double # NBR */ + { OP_LEAR, 0xFC00, TYPE_A, "LEAR", }, /* Load Effective Address Real * */ + { OP_ANMx, 0xFC00, TYPE_A, "ANM", }, /* And Memory B,H,W,D */ + { OP_ORMx, 0xFC00, TYPE_A, "ORM", }, /* Or Memory B,H,W,D */ + { OP_EOMx, 0xFC00, TYPE_A, "EOM", }, /* Exclusive Or Memory */ + { OP_CAMx, 0xFC00, TYPE_A, "CAM", }, /* Compare Arithmetic with Memory */ + { OP_CMMx, 0xFC00, TYPE_A, "CMM", }, /* Compare Masked with Memory */ + { OP_SBM, 0xFC00, TYPE_A, "SBM", }, /* Set Bit in Memory */ + { OP_ZBM, 0xFC00, TYPE_A, "ZBM", }, /* Zero Bit in Memory */ + { OP_ABM, 0xFC00, TYPE_A, "ABM", }, /* Add Bit in Memory */ + { OP_TBM, 0xFC00, TYPE_A, "TBM", }, /* Test Bit in Memory */ + { OP_EXM, 0xFC00, TYPE_B, "EXM", }, /* Execute Memory */ + { OP_Lx, 0xFC00, TYPE_A, "L", }, /* Load B,H,W,D */ + { OP_LMx, 0xFC00, TYPE_A, "LM", }, /* Load Masked B,H,W,D */ + { OP_LNx, 0xFC00, TYPE_A, "LN", }, /* Load Negative B,H,W,D */ + { OP_ADMx, 0xFC00, TYPE_A, "ADM", }, /* Add Memory B,H,W,D */ + { OP_SUMx, 0xFC00, TYPE_A, "SUM", }, /* Subtract Memory B,H,W,D */ + { OP_MPMx, 0xFC00, TYPE_A, "MPM", }, /* Multiply Memory B,H,W,D */ + { OP_DVMx, 0xFC00, TYPE_A, "DVM", }, /* Divide Memory B,H,W,D */ + { OP_LI, 0xFC0F, TYPE_C, "LI", }, /* Load Immediate */ + { OP_ADI, 0xFC0F, TYPE_C, "ADI", }, /* Add Immediate */ + { OP_SUI, 0xFC0F, TYPE_C, "SUI", }, /* Subtract Immediate */ + { OP_MPI, 0xFC0F, TYPE_C, "MPI", }, /* Multiply Immediate */ + { OP_DVI, 0xFC0F, TYPE_C, "DVI", }, /* Divide Immediate */ + { OP_CI, 0xFC0F, TYPE_C, "CI", }, /* Compare Immediate */ + { OP_SVC, 0xFC0F, TYPE_C, "SVC", }, /* Supervisor Call */ + { OP_EXR, 0xFC0F, TYPE_L, "EXR", }, /* Execute Register/ Right */ + { OP_SEM, 0xFC0F, TYPE_A, "SEM", }, /* Store External Map * */ + { OP_LEM, 0xFC0F, TYPE_A, "LEM", }, /* Load External Map * */ + { OP_CEMA, 0xFC0F, TYPE_A, "CEMA", }, /* Convert External Map * */ + { OP_LF, 0xFC00, TYPE_A, "LF", }, /* Load File */ + { OP_LEA, 0xFC00, TYPE_A, "LEA", }, /* Load Effective Address */ + { OP_STx, 0xFC00, TYPE_A, "ST", }, /* Store B,H,W,D */ + { OP_STMx, 0xFC00, TYPE_A, "STM", }, /* Store Masked B,H,W,D */ + { OP_ADFx, 0xFC0F, TYPE_A, "ADF", }, /* Add Floating Memory D,W */ + { OP_SUFx, 0xFC0F, TYPE_A, "SUF", }, /* Subtract Floating Memory D,W */ + { OP_MPFx, 0xFC0F, TYPE_A, "MPF", }, /* Multiply Floating Memory D,W */ + { OP_DVFx, 0xFC0F, TYPE_A, "DVF", }, /* Divide Floating Memory D,W */ + { OP_ARMx, 0xFC00, TYPE_A, "ARM", }, /* Add Register to Memory B,H,W,D */ + { OP_BU, 0xFC00, TYPE_F, "BU", }, /* Branch Unconditional */ + { 0xF000, 0XFF80, TYPE_B, "BFT", }, /* Branch Function True */ + { 0xEC80, 0xFF80, TYPE_B, "BS", }, /* Branch Condition True CC1 = 1 */ + { 0xED00, 0xFF80, TYPE_B, "BGT", }, /* Branch Condition True CC2 = 1 */ + { 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*/ + { 0xEF80, 0xFF80, TYPE_B, "BANY", }, /* Branch Condition True CC1|CC2|CC3|CC4 */ + { 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 */ + { 0xF380, 0xFF80, TYPE_B, "BAZ", }, /* Branch Condition False CC1|CC2|CC3|CC4=0*/ + { OP_BCT, 0xFC00, TYPE_A, "BCT", }, /* Branch Condition True CC1 == 1 */ + { OP_BCF, 0xFC00, TYPE_A, "BCF", }, /* Branch Condition False */ + { OP_BIB, 0xFC70, TYPE_D, "BIB", }, /* Branch after Incrementing Byte */ + { OP_BIW, 0xFC70, TYPE_D, "BIW", }, /* Branch after Incrementing Word */ + { OP_BIH, 0xFC70, TYPE_D, "BIH", }, /* Branch after Incrementing Half */ + { OP_BID, 0xFC70, TYPE_D, "BID", }, /* Branch after Incrementing Double */ + { OP_ZMx, 0xFCC0, TYPE_E, "ZM", }, /* Zero Memory B,H,W,D */ + { OP_BL, 0xFF80, TYPE_B, "BL", }, /* Branch and Link */ + { OP_BRI, 0xFCC0, TYPE_A, "BRI", }, /* Branch and Reset Interrupt * */ + { OP_LPSD, 0xFCC0, TYPE_A, "LPSD", }, /* Load Program Status Double * */ + { OP_LPSDCM, 0xFCC0, TYPE_A, "LPSDCM", }, /* LPSD and Change Map * */ + { OP_TPR, 0xFCC0, TYPE_A, "TPR", }, /* Transfer Protect Register to Register */ + { OP_TRP, 0xFCC0, TYPE_A, "TRP", }, /* Transfer Register to Protect Register */ + { OP_EI, 0xFC0F, TYPE_L, "EI", }, /* Enable Interrupt */ + { OP_DI, 0xFC0F, TYPE_L, "DI", }, /* Disable Interrupt */ + { OP_RI, 0xFC0F, TYPE_L, "RI", }, /* Request Interrupt */ + { OP_AI, 0xFC0F, TYPE_L, "AI", }, /* Activate Interrupt */ + { OP_DAI, 0xFC0F, TYPE_L, "DAI", }, /* Deactivate Interrupt */ + { OP_TD, 0xFC0F, TYPE_M, "TD", }, /* Test Device */ + { OP_CD, 0xFC0F, TYPE_M, "CD", }, /* Command Device */ + { OP_SIO, 0xFC7F, TYPE_C, "SIO", }, /* Start I/O */ + { OP_TIO, 0xFC7F, TYPE_C, "TIO", }, /* Test I/O */ + { OP_STPIO, 0xFC7F, TYPE_C, "STPIO", }, /* Stop I/O */ + { OP_RSCHNL, 0xFC7F, TYPE_C, "RSCHNL", }, /* Reset Channel */ + { OP_HIO, 0xFC7F, TYPE_C, "HIO", }, /* Halt I/O */ + { OP_GRIO, 0xFC7F, TYPE_C, "GRIO", }, /* Grab Controller */ + { OP_RSCTL, 0xFC7F, TYPE_C, "RSCTL", }, /* Reset Controller */ + { OP_ECI, 0xFC7F, TYPE_C, "ECI", }, /* Enable Channel Interrupt */ + { OP_DCI, 0xFC7F, TYPE_C, "DCI", }, /* Disable Channel Interrupt */ + { OP_ACI, 0xFC7F, TYPE_C, "ACI", }, /* Activate Channel Interrupt */ + { OP_DACI, 0xFC7F, TYPE_C, "DACI", }, /* Deactivate Channel Interrupt */ +}; + + +/* Register change decode + + Inputs: + *of = output stream + inst = mask bits +*/ +char *fc_type = "WHHDBBBB"; + +int fprint_inst(FILE *of, uint32 val, int32 sw) { +uint16 inst = (val >> 16) & 0xFFFF; +uint32 v = 0;; +int i; +int l = 1; +int mode = 0; + + + if (sw & SWMASK ('M')) /* Base mode printing */ + mode = 1; + for (tab = optab; tab->name != NULL; tab++) { + if (tab->opbase == (inst & tab->mask)) { + fputs(tab->name, of); + switch(tab->type & 0xF) { + case TYPE_A: /* c r,[*]o[,x] or r,o[(b)][,x] */ + case TYPE_E: /* c [*]o[,x] or o[(b)][,x] */ + i = (*val & 3) | ((inst >> 1) & 04); + fputc(fc_type[i], of); + /* Fall through */ + + case TYPE_F: /* r,[*]o[,x] or r,o[(b)],[,x] */ + fputc(' ', of); + if ((tab->type & 0xf) != TYPE_E) { + fputc('0'+((inst>>7) & 07), of); + fputc(',', of); + } + /* Fall through */ + + case TYPE_B: /* [*]o[,x] or o[(b)],[,x] */ + if (mode) { + fprint_val(of, *val, 16, 16, PV_RZRO); + if (inst & 07) { + fputc('(', of); + fputc('0' + (inst & 07)); + fputc(')', of); + } + if (inst & 0x70) { + fputc(',', of); + fputc('0'+(inst >> 4) & 07); + } + } else { + if (inst & 0x10) + fputc('*', of); + fprint_val(of, *val, 16, 19, PV_RZRO); + if (inst & 0x60) { + fputc(',', of); + fputc('0'+(inst >> 5) & 03); + } + } + break; + + case TYPE_C: /* r,v */ + i = (*val & 3) | ((inst >> 1) & 04); + fputc(fc_type[i], of); + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); + fputc(',', of); + fprint_val(of, *val, 16, 16, PV_RZRO); + break; + + case TYPE_D: /* r,r */ + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); + fputc(',', of); + fputc('0'+((inst>>4) & 07), of); + break; + + case TYPE_G: /* r */ + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); + break; + + case TYPE_H: /* empty */ + break; + + case TYPE_I: /* r,b */ + fputc(' ', of); + fputc('0'+((inst>>7) & 07), of); + fputc(',', of); + fprint_val(of, inst, 16, 5, PV_RZRO); + break; + + case TYPE_K: /* r,rb */ + fputc(' ', of); + fputc('0'+((inst>>4) & 07), of); + fputc(',', of); + i = ((inst & 3) << 3) | ((inst >> 7) & 07); + fprint_val(of, i, 16, 5, PV_RZRO); + break; + + case TYPE_L: /* i */ + fputc(' ', of); + fprint_val(of, inst>>3, 16, 7, PV_RZRO); + break; + + case TYPE_M: /* i,v */ + fputc(' ', of); + fprint_val(of, inst>>3, 16, 7, PV_RZRO); + fputc(',', of); + fprint_val(of, *val, 16, 16, PV_RZRO); + break; + + } + return (tab->type & H) ? 2 : 4; + } + } +} + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + return = status code +*/ + +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; + +if (sw & SWMASK ('D')) + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('H')) + rdx = 16; +if (sw & SWMASK ('M')) { + sw &= ~ SWMASK('F'); /* Can't do F and M at same time */ +} else if (sw & SWMASK('F')) { + l = 4; +} else if (sw & SWMASK('W')) { + l = 2; +} else if (sw & SWMASK('B')) { + l = 1; +} + +if (sw & SWMASK ('C')) { + fputc('\'', of); + for(i = 0; i < l; i++) { + char ch = val[i] & 0xff; + if (ch >= 0x20 && ch <= 0x7f) + fprintf(of, "%c", ch); + else + fputc('_', of); + } + fputc('\'', of); +} else if ((addr & 1) == 0 && sw & (SWMASK ('M')|SWMASK('N'))) { + num = 0; + for (i = 0; i < 4; i++) + num |= (uint32)val[i] << ((3-i) * 8); + l = fprint_inst(of, num, sw); +} else { + num = 0; + for (i = 0; i < l && i < 4; i++) + num |= (uint32)val[i] << ((l-i-1) * 8); + fprint_val(of, num, rdx, l*8, PV_RZRO); +} + +return -(l-1); +} + +/* + * Collect offset in radix. + */ +t_stat get_off (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val, char *m) +{ +t_stat r; + +r = SCPE_OK; +*m = 0; +*val = (uint32)strtotv (cptr, tptr, radix); +if (cptr == *tptr) + r = SCPE_ARG; +else { + cptr = *tptr; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ == '(') { + *m = 1; + while (sim_isspace (*cptr)) cptr++; + } + *tptr = cptr; +} +return r; +} + +/* + * Collect immediate in radix. + */ +t_stat get_imm (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val) +{ +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; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ + +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 val; +uint32 max[5] = { 0, 0xff, 0xffff, 0, 0xffffffff }; +CONST char *tptr; +char gbuf[CBUFSIZE]; + +if (sw & SWMASK ('D')) + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('H')) + rdx = 16; +if (sw & SWMASK('F')) { + l = 4; +} else if (sw & SWMASK('W')) { + l = 2; +} + +if (sw & SWMASK ('C')) { + cptr = get_glyph_quoted(cptr, gbuf, 0); /* Get string */ + for(i = 0; gbuf[i] != 0; i++) { + val[i] = gbuf[i]; + } + return -(i - 1); +} + +if (sw & SWMASK ('N')) { + cptr = get_glyph(cptr, gbuf, 0); /* Get opcode */ + l = strlen(gbuf); + for (tab = optab; tab->name != NULL; tab++) { + i = tab->type & 0xf; + if (i == TYPE_A || i == TYPE_E) { + if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0) + break; + } else if (sim_strcasecmp(tab->name, gbuf) == 0) + break; + } + if (tab->name == NULL) + return SCPE_ARG; + num = tab->opbase; + switch(i) { + case TYPE_A: /* c r,[*]o[,x] */ + case TYPE_E: /* c [*]o[,x] */ + switch(gbuf[l]) { + case 'B': num |= 0x80000; break; + case 'H': num |= 0x00001; break; + case 'W': num |= 0x00000; break; + case 'D': num |= 0x00002; break; + default: + return SCPE_ARG; + } + /* Fall through */ + + case TYPE_F: /* r,[*]o[,x] */ + while (sim_isspace (*cptr)) cptr++; + if (i != TYPE_E) { + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + } + /* Fall through */ + + case TYPE_B: /* [*]o[,x] */ + if (*cptr == '*') { + num |= 0x100000; + cptr++; + while (sim_isspace (*cptr)) cptr++; + } + if (r = get_off (cptr, &tptr, 16, &val, &mod)) + return r; + cptr = tptr; + if (val > 0x7FFFF) + return SCPE_ARG; + num |= val; + if (mod) { + return SCPE_ARG; + } + if (*cptr++ == ",") { + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + num |= x << 20; + } else + return SCPE_ARG; + } + break; + + case TYPE_C: /* r,v */ + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + while (sim_isspace (*cptr)) cptr++; + if (r = get_imm (cptr, &tptr, rd, &val)) + return r; + num |= val; + break; + + case TYPE_D: /* r,r */ + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 20; + } else + return SCPE_ARG; + break; + + case TYPE_G: /* r */ + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + break; + + case TYPE_H: + break; + + case TYPE_I: + break; + + case TYPE_K: + break; + + case TYPE_L: + break; + + case TYPE_M: + break; + + } + return (tab->type & H) ? 2 : 4; +} +if (sw & SWMASK ('M')) { + cptr = get_glyph(cptr, gbuf, 0); /* Get opcode */ + l = strlen(gbuf); + for (tab = optab; tab->name != NULL; tab++) { + i = tab->type & 0xf; + if (i == TYPE_A || i == TYPE_E) { + if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0) + break; + } else if (sim_strcasecmp(tab->name, gbuf) == 0) + break; + } + if (tab->name == NULL) + return SCPE_ARG; + num = tab->opbase << 16; + switch(i) { + case TYPE_A: /* c r,o[(b)][,x] */ + case TYPE_E: /* c o[(b)][,x] */ + switch(gbuf[l]) { + case 'B': num |= 0x80000; break; + case 'H': num |= 0x00001; break; + case 'W': num |= 0x00000; break; + case 'D': num |= 0x00002; break; + default: + return SCPE_ARG; + } + /* Fall through */ + + case TYPE_F: /* r,o[(b)],[,x] */ + while (sim_isspace (*cptr)) cptr++; + if (i != TYPE_E) { + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + } + /* Fall through */ + + case TYPE_B: /* o[(b)],[,x] */ + if (r = get_off (cptr, &tptr, 16, &val, &mod)) + return r; + cptr = tptr; + if (val > 0xFFFF) + return SCPE_ARG; + num |= val; + if (mod) { + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ')') + return SCPE_ARG; + num |= x << 16; + } else + return SCPE_ARG; + } + if (*cptr++ == ",") { + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + num |= x << 20; + } else + return SCPE_ARG; + } + break; + + case TYPE_C: /* r,v */ + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + while (sim_isspace (*cptr)) cptr++; + if (r = get_imm (cptr, &tptr, rd, &val)) + return r; + num |= val; + break; + + case TYPE_D: /* r,r */ + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 20; + } else + return SCPE_ARG; + break; + + case TYPE_G: /* r */ + while (sim_isspace (*cptr)) cptr++; + if (*cptr >= '0' || *cptr <= '7') { + x = *cptr++ - '0'; + while (sim_isspace (*cptr)) cptr++; + if (*cptr++ != ',') + return SCPE_ARG; + num |= x << 23; + } else + return SCPE_ARG; + break; + + case TYPE_H: + break; + + case TYPE_I: + break; + + case TYPE_K: + break; + + case TYPE_L: + break; + + case TYPE_M: + break; + } + return (tab->type & H) ? 2 : 4; +} +num = get_uint(cptr, rdx, max[l], &r); +for (i = 0; i < l && i < 4; i++) + val[i] = (num >> (i * 8)) & 0xff; +return -(l-1); +} +