From 4e159a04ed6291509b685dc06f620389b3373cce Mon Sep 17 00:00:00 2001 From: Jim Bevier Date: Wed, 4 Jan 2023 13:22:12 -0700 Subject: [PATCH] SEL32: Add IPU device support using pthreads on Linux and Windows. SEL32: Update makefile and SEL32.vsproj file to add IPU device. SEL32: Update README.md file. SEL32: Do a general code cleanup. --- SEL32/README.md | 21 +- SEL32/sel32_chan.c | 805 +-- SEL32/sel32_clk.c | 46 +- SEL32/sel32_com.c | 2 +- SEL32/sel32_con.c | 364 +- SEL32/sel32_cpu.c | 3225 +++++++----- SEL32/sel32_defs.h | 208 +- SEL32/sel32_disk.c | 16 +- SEL32/sel32_ec.c | 6 +- SEL32/sel32_fltpt.c | 2 +- SEL32/sel32_hsdp.c | 30 +- SEL32/sel32_iop.c | 7 +- SEL32/sel32_ipu.c | 7214 +++++++++++++++++++++++++++ SEL32/sel32_lpr.c | 2 +- SEL32/sel32_mfp.c | 10 +- SEL32/sel32_mt.c | 15 +- SEL32/sel32_scfi.c | 22 +- SEL32/sel32_scsi.c | 8 +- SEL32/sel32_sys.c | 173 +- Visual Studio Projects/SEL32.vcproj | 4 + makefile | 2 +- 21 files changed, 10185 insertions(+), 1997 deletions(-) create mode 100644 SEL32/sel32_ipu.c diff --git a/SEL32/README.md b/SEL32/README.md index 83d9bf0b..61c65529 100644 --- a/SEL32/README.md +++ b/SEL32/README.md @@ -5,7 +5,10 @@ This is a working simulator for the SEL Concept/32 computer. The current version is for the SEL 32/27, 32/67, 32/77, 32/87, 32/97, V6, and V9 computers. All of the processors except for the 32/77 can run the Gould diags. Operational support for the 32/77 computers may be added in the -future. +future. Additional processors are now supported. The 32/6780, 32/8780, +32/9780, V6/IPU, and V9/IPU processors with an IPU able to run an +additional instruction stream. Threads are used so support is provided +by both Windows and Linux. # SEL Concept/32 @@ -19,9 +22,10 @@ can be used to access MPX or UTX via Telnet port 4747. The sumulator has support for excess 64 floating point arithmetic and passes the 32/27 and 32/67 FP diags. UTX is the SEL version of System V Unix and BSD Unix ported to the V6 and V9 processors. UTX utilizes the basemode instruction -set and a virtual memory system supported by the V6 & V9 CPUs. The system -needs further testing to solidify the SEL32 simulator code in all of the -supported environmenets and hardware configurations. +set and a virtual memory system supported by the V6 & V9 CPUs. The IPU is +also supported by UTX and MPX-32. The system needs further testing to +solidify the SEL32 simulator code in all of the supported environmenets +and hardware configurations. # SEL32 installation configuration files in the installs directory: @@ -95,6 +99,13 @@ diag.tap - bootable level one diagnostic tape w/auto testing. Testing is extremely difficult without any source for the diagnostics. Updates to follow as tests are corrected. +# SEL32 tap tools available in the taptools directory: + +Available tap tools in taptools directory: +./taptools - set of tools to work with .tap formatted tapes. Also tools + to convert between MPX and UNIX file formats. See README + file in the taptools directory and source for descriptions. + Other MPX versions support: I have recently received some old MPX 3.X save tapes. Using these I have been able to hand build a MPX3.6 SDT tape that @@ -109,4 +120,4 @@ Other MPX versions support: thankfull. Please keep looking. James C. Bevier -02/28/2022 +01/03/2023 diff --git a/SEL32/sel32_chan.c b/SEL32/sel32_chan.c index db4d1b0d..e8d17a3f 100644 --- a/SEL32/sel32_chan.c +++ b/SEL32/sel32_chan.c @@ -1,6 +1,6 @@ /* sel32_chan.c: SEL 32 Channel functions. - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -80,12 +80,13 @@ uint32 channels = MAX_CHAN; /* maximum number of channels */ int subchannels = SUB_CHANS; /* maximum number of subchannel devices */ -int irq_pend = 0; /* pending interrupt flag */ +//int irq_pend = 0; /* pending interrupt flag */ +//extern uint32 *M; /* cpu/ipu main memory */ +extern uint32 SPAD[]; /* cpu SPAD memory */ extern uint32 CPUSTATUS; /* CPU status word */ extern uint32 INTS[]; /* Interrupt status flags */ extern uint32 TPSD[]; /* Temp save of PSD from memory 0&4 */ -extern uint8 waitqcnt; /* # of instructions to xeq b4 int */ extern uint32 inbusy; extern uint32 outbusy; @@ -296,15 +297,13 @@ t_stat set_inch(UNIT *uptr, uint32 inch_addr, uint32 num_inch) { uint16 chsa = GET_UADDR(uptr->u3); /* get channel & sub address */ uint32 chan = chsa & 0x7f00; /* get just channel address */ uint32 last = inch_addr + (num_inch-1)*8; /* last inch address to use */ - CHANP *chp; - int i, j; - DIB *dibp = dib_chan[chan>>8]; /* get channel dib ptr */ - CHANP *pchp = 0; /* for channel prog ptr */ + DIB *pdibp = dib_chan[chan>>8]; /* get parent channel dib ptr */ + CHANP *pchp; /* for parent channel prog ptr */ /* must be valid DIB pointer */ - if (dibp == NULL) + if (pdibp == NULL) return SCPE_MEM; /* return memory error */ - pchp = dibp->chan_prg; /* get parent channel prog ptr */ + pchp = pdibp->chan_prg; /* get parent channel prog ptr */ /* must be valid channel pointer */ if (pchp == NULL) @@ -318,36 +317,15 @@ t_stat set_inch(UNIT *uptr, uint32 inch_addr, uint32 num_inch) { if (!MEM_ADDR_OK(last)) /* see if mem addr >= MEMSIZE */ return SCPE_MEM; /* return memory error */ - /* set INCH address for all units on master channel */ - chp = pchp; - for (i=0; inumunits; i++) { - chp->chan_inch_addr = inch_addr; /* set the current inch addr */ - chp->base_inch_addr = inch_addr; /* set the base inch addr */ - chp->max_inch_addr = last; /* set the last inch addr */ - chp++; /* next unit channel */ - } + /* set INCH address only for parent channel */ + /* for integrated controller, like disk, use 1st unit on channel */ + pchp->chan_inch_addr = inch_addr; /* set the current inch addr */ + pchp->base_inch_addr = inch_addr; /* set the base inch addr */ + pchp->max_inch_addr = last; /* set the last inch addr */ sim_debug(DEBUG_XIO, &cpu_dev, - "set_inch chan %04x inch addr %06x last %06x chp %p\n", - chan, inch_addr, last, chp); - - /* now go through all the sub addresses for the channel and set inch addr */ - for (i=0; ichan_prg; /* get first unit channel prog ptr */ - /* set INCH address for all units on channel */ - for (j=0; jnumunits; j++) { - chp->chan_inch_addr = inch_addr; /* set the inch addr */ - chp->base_inch_addr = inch_addr; /* set the base inch addr */ - chp->max_inch_addr = last; /* set the last inch addr */ - chp++; /* next unit channel */ - } - } + "set_inch chan %04x inch addr %06x last %06x pchp %p\n", + chan, inch_addr, last, pchp); return SCPE_OK; /* All OK */ } @@ -399,7 +377,7 @@ uint32 find_int_icb(uint16 chsa) /* Find unit pointer for given device (ch/sa) */ UNIT *find_unit_ptr(uint16 chsa) { - struct dib *dibp; /* DIB pointer */ + DIB *dibp; /* DIB pointer */ UNIT *uptr; /* UNIT pointer */ int i; @@ -697,7 +675,7 @@ loop: /* Check if we had data chaining in previous iocd */ if ((chp->chan_info & INFO_SIOCD) || /* see if 1st IOCD in channel prog */ (((chp->chan_info & INFO_SIOCD) == 0) && /* see if 1st IOCD in channel prog */ - ((chp->ccw_flags & FLAG_DC) == 0))) { /* last IOCD have DC set? */ + ((chp->ccw_flags & FLAG_DC) == 0))) { /* last IOCD have DC set? */ sim_debug(DEBUG_XIO, &cpu_dev, "load_ccw @%06x DO CMD No DC, ccw_flags %04x cmd %02x\n", chp->chan_caw, chp->ccw_flags, chp->ccw_cmd); @@ -772,7 +750,7 @@ loop: if (chp->chan_status & (STATUS_ATTN|STATUS_ERROR)) { chp->chan_status |= STATUS_CEND; /* channel end status */ chp->ccw_flags = 0; /* no flags */ - chp->chan_byte = BUFF_NEXT; /* have main pick us up */ + chp->chan_byte = BUFF_NEXT; /* have main pick us up */ sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw bad status chsa %04x status %04x cmd %02x\n", chsa, chp->chan_status, chp->ccw_cmd); @@ -780,7 +758,7 @@ loop: sim_debug(DEBUG_EXP, &cpu_dev, "load_ccw ERROR return chsa %04x status %08x\n", chp->chan_dev, chp->chan_status); - return 1; /* error return */ + return 1; /* error return */ } /* NOTE this code needed for MPX 1.X to run! */ /* see if command completed */ @@ -819,7 +797,7 @@ int chan_read_byte(uint16 chsa, uint8 *data) if (chp->ccw_count == 0) { /* see if more data required */ if ((chp->ccw_flags & FLAG_DC) == 0) { /* see if Data Chain */ chp->chan_byte = BUFF_CHNEND; /* buffer end too */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_CMD, &cpu_dev, "chan_read_byte no DC chan end, cnt %04x addr %06x chsa %04x\n", chp->ccw_count, chp->ccw_addr, chsa); return 1; /* return error */ @@ -951,7 +929,6 @@ void set_devattn(uint16 chsa, uint16 flags) /* can not do anything, so just return */ sim_debug(DEBUG_EXP, &cpu_dev, "set_devattn chsa %04x, flags %04x\n", chsa, flags); fprintf(stdout, "set_devattn chsa %04x invalid configured device\n", chsa); -// fflush(stdout); return; } @@ -970,7 +947,6 @@ void chan_end(uint16 chsa, uint16 flags) { sim_debug(DEBUG_CMD, &cpu_dev, "chan_end entry chsa %04x flags %04x status %04x cmd %02x cpustatus %08x\n", chsa, flags, chp->chan_status, chp->ccw_cmd, CPUSTATUS); -// fflush(sim_deb); /* see if already called */ if (chp->chan_info & INFO_CEND) { @@ -1009,7 +985,7 @@ void chan_end(uint16 chsa, uint16 flags) { chp->ccw_flags = 0; /* no flags */ } - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_CMD, &cpu_dev, "chan_end test end chsa %04x ccw_flags %04x status %04x byte %02x\n", chsa, chp->ccw_flags, chp->chan_status, chp->chan_byte); @@ -1075,12 +1051,12 @@ void chan_end(uint16 chsa, uint16 flags) { /* handle case where we are loading the O/S on boot */ /* if loading, store status to be discovered by scan_chan */ if (!loading) { - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_CMD, &cpu_dev, "chan_end call store_csw dev/chan end chsa %04x cpustat %08x iocla %08x\n", chsa, CPUSTATUS, chp->chan_caw); } else { /* we are loading, so keep moving */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_CMD, &cpu_dev, "chan_end we are loading O/S with DE & CE, keep status chsa %04x status %08x\n", chsa, chp->chan_status); } @@ -1132,7 +1108,6 @@ void chan_end(uint16 chsa, uint16 flags) { sim_debug(DEBUG_CMD, &cpu_dev, "CHEND SIOQ queued chsa %04x iocla %06x IOCD1 %08x IOCD2 %08x\n", chsa, iocla, RMW(iocla), RMW(iocla+4)); - } } } @@ -1150,7 +1125,9 @@ goout: int16 post_csw(CHANP *chp, uint32 rstat) { uint32 chsa = chp->chan_dev; /* get ch/sa information */ - uint32 incha = chp->chan_inch_addr; /* get inch status buffer address */ + DIB *dibp = dib_chan[chsa>>8]; /* get parent channel dib ptr */ + CHANP *pchp = dibp->chan_prg; /* for parent channel prog ptr */ + uint32 incha = pchp->chan_inch_addr; /* get inch status buffer address */ uint32 sw1, sw2; /* status words */ irq_pend = 1; /* flag to test for int condition */ @@ -1189,11 +1166,13 @@ int16 post_csw(CHANP *chp, uint32 rstat) WMW(incha+4, sw2); /* save status and residual cnt in status WD 2 loc */ /* now store the status dw address into word 5 of the ICB for the channel */ WMW(chan_icb+20, incha|BIT1); /* post sw addr in ICB+5w & set CC2 in INCH addr */ + incha += 8; /* next inch addr */ + pchp->chan_inch_addr = incha; /* set to next inch addr */ + if ((incha + 8) > pchp->max_inch_addr) /* see if next inch addr OK */ + pchp->chan_inch_addr = pchp->base_inch_addr; /* reset to first inch addr */ sim_debug(DEBUG_IRQ, &cpu_dev, "post_csw %04x READ1 FIFO #%1x inch %06x chan_icb %06x sw1 %08x sw2 %08x\n", chsa, FIFO_Num(chsa), incha, chan_icb, sw1, sw2); - if ((incha + 8) > chp->max_inch_addr) /* see if next inch addr OK */ - chp->chan_inch_addr = chp->base_inch_addr; /* reset to first inch addr */ } return 1; /* show we posted status */ } @@ -1220,11 +1199,8 @@ void store_csw(CHANP *chp) "store_csw FIFO Overflow ERROR on chsa %04x\n", chsa); } sim_debug(DEBUG_XIO, &cpu_dev, - "store_csw FIFO #%1x write chsa %04x sw1 %08x sw2 %08x incha %08x cmd %02x\n", - FIFO_Num(chsa), chsa, stwd1, stwd2, chp->chan_inch_addr, chp->ccw_cmd); - /* added 011321 */ - /* removed 112421 */ -// INTS[chp->chan_int] |= INTS_REQ; /* request an interrupt for channel */ + "store_csw FIFO #%1x write chsa %04x sw1 %08x sw2 %08x cmd %02x\n", + FIFO_Num(chsa), chsa, stwd1, stwd2, chp->ccw_cmd); irq_pend = 1; /* wakeup controller */ } @@ -1246,11 +1222,8 @@ void push_csw(CHANP *chp) "push_csw FIFO Overflow ERROR on chsa %04x\n", chsa); } sim_debug(DEBUG_XIO, &cpu_dev, - "push_csw FIFO #%1x write chsa %04x sw1 %08x sw2 %08x incha %08x cmd %02x\n", - FIFO_Num(chsa), chsa, stwd1, stwd2, chp->chan_inch_addr, chp->ccw_cmd); - /* added 011321 */ - /* removed 112421 */ -// INTS[chp->chan_int] |= INTS_REQ; /* request an interrupt for channel */ + "push_csw FIFO #%1x write chsa %04x sw1 %08x sw2 %08x cmd %02x\n", + FIFO_Num(chsa), chsa, stwd1, stwd2, chp->ccw_cmd); irq_pend = 1; /* wakeup controller */ } @@ -1266,20 +1239,20 @@ t_stat checkxio(uint16 lchsa, uint32 *status) { DEVICE *dptr; /* DEVICE pointer */ uint32 inta; uint32 spadent; - uint16 rchan, rchsa; /* the real channel number */ + uint16 rchan, chsa; /* the real channel number */ /* get the device entry for the logical channel in SPAD */ spadent = SPAD[lchan]; /* get spad device entry for logical channel */ rchan = (spadent & 0x7f00) >> 8; /* get real channel */ - rchsa = (rchan << 8) | (lchsa & 0xff); /* get the read chan & suba */ + chsa = (rchan << 8) | (lchsa & 0xff); /* get the read chan & suba */ dibp = dib_chan[rchan]; /* get DIB pointer for channel */ if (dibp == 0) goto nothere; - chp = dibp->chan_prg; /* find the chanp pointer */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ if (chp == 0) goto nothere; - uptr = dibp->units; /* find pointer to 1st unit on channel */ + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ nothere: *status = CC3BIT; /* not found, so CC3 */ @@ -1300,13 +1273,13 @@ nothere: (DEV_TYPE(dptr) == DEV_TAPE)) { /* see if this is a tape */ *status = CC1BIT; /* CCs = 1, not busy */ sim_debug(DEBUG_EXP, &cpu_dev, - "checkxio rchsa %04x device/unit not enabled, CC1 returned\n", - rchsa); + "checkxio chsa %04x device/unit not enabled, CC1 returned\n", + chsa); } else { *status = CC3BIT; /* not attached, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "checkxio rchsa %04x device/unit not enabled, CC3 returned\n", - rchsa); + "checkxio chsa %04x device/unit not enabled, CC3 returned\n", + chsa); } return SCPE_OK; /* Not found CC3/CC1 */ } @@ -1316,10 +1289,10 @@ nothere: *status = 0; /* CCs = 0, OK return */ else /* return CC1 for non iop/mfp devices */ - *status = 0; /* CCs = 0, OK return */ + *status = 0; /* CCs = 0, OK return */ sim_debug(DEBUG_DETAIL, &cpu_dev, - "checkxio lchsa %04x rchsa %04x done CC status %08x\n", - lchsa, rchsa, *status); + "checkxio lchsa %04x chsa %04x done CC status %08x\n", + lchsa, chsa, *status); return SCPE_OK; /* No CC's all OK */ } @@ -1351,52 +1324,60 @@ nothere: /* Condition codes to return 0-f as specified above */ t_stat startxio(uint16 lchsa, uint32 *status) { DIB *dibp; /* device information pointer */ + DIB *pdibp; /* parent DIB pointer */ UNIT *uptr; /* pointer to unit in channel */ uint32 chan_icb; /* Interrupt level context block address */ uint32 iocla; /* I/O channel IOCL address int ICB */ int32 stat; /* return status 0/1 from loadccw */ CHANP *chp; /* channel program pointer */ - uint16 lchan = get_chan(lchsa); /* get the logical channel number */ + CHANP *pchp; /* for parent channel prog ptr */ + DEVICE *dptr; /* Device ptr */ uint16 chsa; uint32 tempa, inta, spadent, chan, incha; uint32 word1, word2, cmd; - DEVICE *dptr; /* get the device entry for the logical channel in SPAD */ - spadent = SPAD[lchan]; /* get spad device entry for logical channel */ + spadent = SPAD[get_chan(lchsa)]; /* get spad device entry for logical channel */ inta = ((~spadent)>>16)&0x7f; /* get interrupt level */ chan = (spadent & 0x7f00) >> 8; /* get real channel */ chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - sim_debug(DEBUG_XIO, &cpu_dev, - "startxio entry inta %02x lchan %04x spadent %08x rchsa %04x\n", - inta, lchan, spadent, chsa); - - dibp = dib_unit[chsa & 0x7f00]; /* get the device information pointer */ - uptr = find_unit_ptr(chsa & 0x7f00); /* get unit 0 unit pointer */ - chan_icb = find_int_icb(lchsa); /* Interrupt level context block address */ - incha = RMW(chan_icb+20); /* post inch addr in ICB+5w */ /* check if we have a valid unit */ - chp = find_chanp_ptr(chsa); /* find the chanp pointer */ - if (chp == 0) goto missing; + pdibp = dib_chan[chan]; /* for parent DIB ptr */ + if (pdibp == 0) goto missing; + pchp = pdibp->chan_prg; /* for parent channel prog ptr */ + if (pchp == 0) goto missing; + + /* we must have a valid ICB for the interrupt */ + chan_icb = find_int_icb(chsa); /* Interrupt level context block address */ + if (chan_icb == 0) goto missing; + + /* check if we have a valid dib for the unit */ dibp = dib_unit[chsa]; /* get the DIB pointer */ if (dibp == 0) goto missing; - uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ + if (chp == 0) goto missing; + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ missing: *status = CC3BIT; /* not found, so CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "startxio chsa %04x is not found, CC3 returned\n", chsa); + "startxio chsa %04x is not found or invalid, CC3 returned\n", lchsa); return SCPE_OK; /* not found, CC3 */ } + incha = pchp->chan_inch_addr; /* get inch status buffer address for channel */ - inta = ((~spadent)>>16)&0x7f; /* get channel interrupt level */ + /* save interrupt level number in channel & parent channel */ chp->chan_int = inta; /* make sure it is set in channel */ + pchp->chan_int = inta; /* make sure it is set in parent channel */ + sim_debug(DEBUG_XIO, &cpu_dev, + "startxio entry inta %02x chan %04x spadent %08x chsa %04x\n", + inta, chan, spadent, chsa); - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_CMD, &cpu_dev, "startxio chsa %04x chp %p flags UNIT_ATTABLE %1x UNIT_ATT %1x UNIT_DIS %1x\n", chsa, chp, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0, (uptr->flags & UNIT_DIS)?1:0); @@ -1420,7 +1401,6 @@ missing: } #endif - incha = chp->chan_inch_addr; /* get inch address */ /* 05122021 cpu halts in diag if this code is enabled */ /* disabling this code allows TE to be echoed at debugger prompt */ #ifndef TEST_FOR_HSDP_PUT_BACK_05122021 @@ -1444,7 +1424,6 @@ missing: "SIOT END status stored incha %06x chan_icba+20 %08x chsa %04x sw1 %08x sw2 %08x\n", incha, RMW(chan_icb+20), chsa, RMW(incha), RMW(incha+4)); INTS[inta] &= ~INTS_REQ; /* clear level request for no status */ -// INTS[inta] |= INTS_REQ; /* set level request if no status */ *status = CC2BIT; /* status stored from SIO, so CC2 */ return SCPE_OK; /* No CC's all OK */ } else { @@ -1457,17 +1436,15 @@ missing: return SCPE_OK; /* No CC's all OK */ } } -//TRY WMW(chan_icb+20, 0); /* post sw addr 0 in ICB+5w & reset CCs */ sim_debug(DEBUG_IRQ, &cpu_dev, - "SIOT chsa %04x Nothing to post FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - chsa, FIFO_Num(chsa), inta, incha, chan_icb, chp->chan_byte); + "SIOT chsa %04x Nothing to post FIFO #%1x irq %02x inch %06x chan_icba %06x icb+20 %08x\n", + chsa, FIFO_Num(chsa), inta, incha, chan_icb, RMW(chan_icb+20)); #endif /* check for a Command or data chain operation in progresss */ if ((chp->chan_byte & BUFF_BUSY) && (chp->chan_byte != BUFF_POST)) { uint16 tstat = chp->chan_status; /* save status */ uint16 tcnt = chp->ccw_count; /* save count */ - DEVICE *dptr = get_dev(uptr); sim_debug(DEBUG_EXP, &cpu_dev, "startxio busy return CC3&CC4 chsa %04x chp %p cmd %02x flags %04x byte %02x\n", @@ -1514,14 +1491,11 @@ missing: word1 = RMW(iocla & MASK24); /* get 1st IOCL word */ word2 = RMW((iocla + 4) & MASK24); /* get 2nd IOCL word */ cmd = (word1 >> 24) & 0xff; /* get channel cmd from IOCL */ - chp = find_chanp_ptr(chsa&0x7f00); /* find the parent chanp pointer */ - incha = chp->chan_inch_addr; /* get inch address */ sim_debug(DEBUG_XIO, &cpu_dev, "startxio do normal chsa %04x iocla %06x incha %06x IOCD1 %08x IOCD2 %08x\n", chsa, iocla, incha, RMW(iocla), RMW(iocla+4)); - chp = find_chanp_ptr(chsa); /* find the chanp pointer */ #ifdef TEST_FOR_IOCL_CHANGE chp->new_iocla = iocla; /* save iocla */ chp->new_iocd1 = word1; /* save iocd word 1 */ @@ -1536,7 +1510,6 @@ missing: /* determine if channel DIB has a pre startio command processor */ if (dibp->pre_io != NULL) { /* NULL if no startio function */ - DEVICE *dptr = get_dev(uptr); /* get device ptr */ int unit = uptr-dptr->units; /* get unit number */ /* call the device controller to get prestart_io status */ @@ -1546,7 +1519,7 @@ missing: /* SNS_SMS if unit IOCLQ is not full, but device is busy */ /* SNS_CTLEND if waiting for INCH command */ if (tempa == SNS_CTLEND) { /* see if sub channel status is ready */ - /* manual says to just return OK nad do nother if inch is required */ + /* manual says to just return OK and do nother if inch is required */ sim_debug(DEBUG_XIO, &cpu_dev, "SIO pre_io call return NO INCH %04x chsa %04x cstat %02x cmd %02x cnt %02x\n", incha, chsa, tempa, cmd, word2); @@ -1607,7 +1580,6 @@ missing: } /* channel not busy and ready to go, so start a new command */ - chp->chan_int = inta; /* save interrupt level in channel */ chp->chan_status = 0; /* no channel status yet */ chp->chan_caw = iocla; /* get iocla address in memory */ /* added 09/25/20 to fix hangs in iocl processing */ @@ -1655,7 +1627,7 @@ missing: chsa, chp->chan_status, chp->chan_caw, chp->chan_byte); } sim_debug(DEBUG_XIO, &cpu_dev, - "SIO started chsa %04x iocla %06x IOCD1 %08x IOCD2 %08x incha %06x icb+20 %08x\n", + "SIO xit chsa %04x iocla %06x IOCD1 %08x IOCD2 %08x incha %06x icb+20 %08x\n", chsa, iocla, RMW(iocla), RMW(iocla+4), incha, RMW(chan_icb+20)); *status = CC1BIT; /* CCs = 1, SIO accepted & queued, no echo status */ @@ -1667,67 +1639,84 @@ missing: /* TIO - I/O status */ t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */ DIB *dibp; /* device information pointer */ + DIB *pdibp; /* parent DIB pointer */ UNIT *uptr; /* pointer to unit in channel */ uint32 chan_icb; /* Interrupt level context block address */ CHANP *chp; /* Channel prog pointers */ + CHANP *pchp; /* for parent channel prog ptr */ DEVICE *dptr; /* Device ptr */ - uint32 inta, incha, itva; - uint16 lchan = get_chan(lchsa); /* get the logical channel number */ + uint32 inta, incha; uint32 spadent; - uint16 rchan, rchsa; /* the real channel number, chsa */ + uint16 chan, chsa; /* the real channel number, chsa */ - lchsa &= 0x7f00; /* use just chan and sa of 0 */ - /* get the real channel entry for the logical channel in SPAD */ - spadent = SPAD[lchan]; /* get spad device entry for logical channel */ - rchsa = (spadent & 0x7f00); /* get real channel suba of zero */ - rchan = rchsa >> 8; /* get real channel */ + /* get the device entry for the logical channel in SPAD */ + spadent = SPAD[get_chan(lchsa)]; /* get spad device entry for logical channel */ + inta = ((~spadent)>>16)&0x7f; /* get interrupt level */ + chan = (spadent & 0x7f00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - /* get the device entry for the channel in SPAD */ - dibp = dib_chan[rchan]; /* get the DIB pointer */ - chp = find_chanp_ptr(rchan << 8); /* find the device chanp pointer */ + /* check if we have a valid unit */ + pdibp = dib_chan[chan]; /* for parent DIB ptr */ + if (pdibp == 0) goto missing; - if (dibp == 0 || chp == 0) { /* if no dib or channel ptr, CC3 return */ + pchp = pdibp->chan_prg; /* for parent channel prog ptr */ + if (pchp == 0) goto missing; + + /* we must have a valid ICB for the interrupt */ + chan_icb = find_int_icb(chsa); /* Interrupt level context block address */ + if (chan_icb == 0) goto missing; + + /* check if we have a valid dib for the unit */ + dibp = dib_unit[chsa]; /* get the DIB pointer */ + if (dibp == 0) goto missing; + + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ + if (chp == 0) goto missing; + + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ +missing: *status = CC3BIT; /* not found, so CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "TIO lchsa %04x rchsa %04x device not present, CC3 returned\n", lchsa, rchsa); - return SCPE_OK; /* Not found, CC3 */ + "TIO chsa %04x is not found or invalid, CC3 returned\n", lchsa); + return SCPE_OK; /* not found, CC3 */ } + incha = pchp->chan_inch_addr; /* get inch status buffer address for channel */ + + /* save interrupt level number in channel & parent channel */ + chp->chan_int = inta; /* make sure it is set in channel */ + pchp->chan_int = inta; /* make sure it is set in parent channel */ + sim_debug(DEBUG_XIO, &cpu_dev, + "TIO entry inta %02x lchan %04x spadent %08x chsa %04x\n", + inta, chan, spadent, chsa); + + sim_debug(DEBUG_CMD, &cpu_dev, + "TIO chsa %04x chp %p flags UNIT_ATTABLE %1x UNIT_ATT %1x UNIT_DIS %1x\n", + chsa, chp, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0, + (uptr->flags & UNIT_DIS)?1:0); - uptr = chp->unitptr; /* get the unit 0 ptr */ /* is device or unit marked disabled? */ dptr = get_dev(uptr); if ((dptr->flags & DEV_DIS) || ((uptr->flags & UNIT_DIS) && ((uptr->flags & UNIT_SUBCHAN) == 0))) { - /* is device/unit disabled? */ - *status = CC3BIT; /* not enabled, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "TIO rchsa %04x device/unit not enabled, CC3 returned\n", rchsa); - return SCPE_OK; /* Not found, CC3 */ + "TIO chsa %04x device/unit disabled, CC3 returned flags %08x\n", chsa, uptr->flags); + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ } - /* the XIO opcode processing software has already checked for F class */ - inta = ((~spadent)>>16)&0x7f; /* get channel interrupt level */ - chp->chan_int = inta; /* make sure it is set in channel */ - itva = SPAD[0xf1] + (inta<<2); /* int vector address */ - chan_icb = RMW(itva); /* Interrupt context block addr */ - sim_debug(DEBUG_XIO, &cpu_dev, - "TIO int spad %08x icb %06x inta %04x rchsa %04x\n", - SPAD[inta+0x80], chan_icb, inta, rchsa); - - incha = chp->chan_inch_addr; /* get inch address */ - /* see if any status ready to post */ - if (FIFO_Num(rchsa)) { + if (FIFO_Num(chsa)) { sim_debug(DEBUG_IRQ, &cpu_dev, - "TIO rchsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chp, chan_icb, chp->chan_byte); + "TIO chsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, incha, chp, chan_icb, chp->chan_byte); if (chp->chan_byte == BUFF_DONE) { chp->chan_byte = BUFF_POST; /* if done, show post for post_csw() */ } if (post_csw(chp, 0)) { sim_debug(DEBUG_IRQ, &cpu_dev, - "TIO rchsa %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); + "TIO chsa %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); /* change status from BUFF_POST to BUFF_DONE */ /* if not BUFF_POST we have a PPCI or channel busy interrupt */ /* so leave the channel status alone */ @@ -1735,15 +1724,15 @@ t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */ chp->chan_byte = BUFF_DONE; /* show done & not busy */ } sim_debug(DEBUG_XIO, &cpu_dev, - "TIO END incha %06x chan_icba+20 %08x rchsa %04x sw1 %08x sw2 %08x\n", - incha, RMW(chan_icb+20), rchsa, RMW(incha), RMW(incha+4)); + "TIO END incha %06x chan_icba+20 %08x chsa %04x sw1 %08x sw2 %08x\n", + incha, RMW(chan_icb+20), chsa, RMW(incha), RMW(incha+4)); INTS[inta] &= ~INTS_REQ; /* clear any level request if no status */ *status = CC2BIT; /* status stored from SIO, so CC2 */ return SCPE_OK; /* No CC's all OK */ } else { sim_debug(DEBUG_IRQ, &cpu_dev, - "TIO rchsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, chp->chan_inch_addr, chan_icb, chp->chan_byte); + "TIO chsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, chp->chan_inch_addr, chan_icb, chp->chan_byte); /* now store the status dw address into word 5 of the ICB for the channel */ WMW(chan_icb+20, 0); /* post sw addr 0 in ICB+5w & reset CCs */ *status = 0; /* no status stored from TIO, so no CC */ @@ -1762,62 +1751,87 @@ t_stat testxio(uint16 lchsa, uint32 *status) { /* test XIO */ WMW(chan_icb+20, 0x80000000); /* post sw addr 0 in ICB+5w & reset CCs */ *status = CC1BIT; /* request accepted, no status, so CC1 */ #endif -// INTS[inta] &= ~INTS_REQ; /* clear any level request if no status */ sim_debug(DEBUG_XIO, &cpu_dev, - "TIO END rchsa %04x rchan %04x ccw_flags %04x chan_stat %04x CCs %08x\n", - rchsa, rchan, chp->ccw_flags, chp->chan_status, *status); + "TIO END chsa %04x rchan %04x ccw_flags %04x chan_stat %04x CCs %08x\n", + chsa, chan, chp->ccw_flags, chp->chan_status, *status); return SCPE_OK; /* No CC's all OK */ } /* Stop XIO */ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */ DIB *dibp; /* device information pointer */ + DIB *pdibp; /* parent DIB pointer */ UNIT *uptr; /* pointer to unit in channel */ uint32 chan_icb; /* Interrupt level context block address */ - uint32 iocla, inta, itva; /* I/O channel IOCL address int ICB */ + uint32 iocla; /* I/O channel IOCL address int ICB */ CHANP *chp; /* Channel prog pointers */ + CHANP *pchp; /* for parent channel prog ptr */ DEVICE *dptr; /* Device ptr */ - uint16 lchan = get_chan(lchsa); /* get the logical channel number */ + uint32 inta, incha; uint32 spadent; - uint16 rchan, rchsa; /* the real channel number, chsa */ + uint16 chan, chsa; /* the real channel number, chsa */ /* get the device entry for the logical channel in SPAD */ - spadent = SPAD[lchan]; /* get spad device entry for logical channel */ - rchan = (spadent & 0x7f00) >> 8; /* get real channel */ - rchsa = (rchan << 8) | (lchsa & 0xff); /* get the read chan & suba */ + spadent = SPAD[get_chan(lchsa)]; /* get spad device entry for logical channel */ + inta = ((~spadent)>>16)&0x7f; /* get interrupt level */ + chan = (spadent & 0x7f00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - /* get the device entry for the logical channel in SPAD */ - dibp = dib_unit[rchsa]; /* get the DIB pointer */ - chp = find_chanp_ptr(rchsa); /* find the device chanp pointer */ + /* check if we have a valid unit */ + pdibp = dib_chan[chan]; /* for parent DIB ptr */ + if (pdibp == 0) goto missing; - if (dibp == 0 || chp == 0) { /* if no dib or channel ptr, CC3 return */ + pchp = pdibp->chan_prg; /* for parent channel prog ptr */ + if (pchp == 0) goto missing; + + /* we must have a valid ICB for the interrupt */ + chan_icb = find_int_icb(chsa); /* Interrupt level context block address */ + if (chan_icb == 0) goto missing; + + /* check if we have a valid dib for the unit */ + dibp = dib_unit[chsa]; /* get the DIB pointer */ + if (dibp == 0) goto missing; + + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ + if (chp == 0) goto missing; + + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ +missing: *status = CC3BIT; /* not found, so CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "STPIO test 1 rchsa %04x device not present, CC3 returned\n", rchsa); - return SCPE_OK; /* not found CC3 */ + "STPIO chsa %04x is not found or invalid, CC3 returned\n", lchsa); + return SCPE_OK; /* not found, CC3 */ } + incha = pchp->chan_inch_addr; /* get inch status buffer address for channel */ + iocla = RMW(chan_icb+16); /* iocla is in wd 4 of ICB */ + + /* save interrupt level number in channel & parent channel */ + chp->chan_int = inta; /* make sure it is set in channel */ + pchp->chan_int = inta; /* make sure it is set in parent channel */ + sim_debug(DEBUG_EXP, &cpu_dev, + "STPIO entry inta %02x lchan %04x spadent %08x chsa %04x\n", + inta, chan, spadent, chsa); + + sim_debug(DEBUG_CMD, &cpu_dev, + "STPIO chsa %04x chp %p flags UNIT_ATTABLE %1x UNIT_ATT %1x UNIT_DIS %1x\n", + chsa, chp, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0, + (uptr->flags & UNIT_DIS)?1:0); - uptr = chp->unitptr; /* get the unit ptr */ /* is device or unit marked disabled? */ dptr = get_dev(uptr); if ((dptr->flags & DEV_DIS) || ((uptr->flags & UNIT_DIS) && ((uptr->flags & UNIT_SUBCHAN) == 0))) { - /* is device/unit disabled? */ - *status = CC3BIT; /* not enabled, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "STPIO rchsa %04x device/unit not enabled, CC3 returned\n", rchsa); - return SCPE_OK; /* Not found, CC3 */ + "STPIO chsa %04x device/unit disabled, CC3 returned flags %08x\n", chsa, uptr->flags); + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ } - /* the XIO opcode processing software has already checked for F class */ - inta = ((~spadent)>>16)&0x7f; /* get channel interrupt level */ - chp->chan_int = inta; /* make sure it is set in channel */ - itva = SPAD[0xf1] + (inta<<2); /* int vector address */ - chan_icb = RMW(itva); /* Interrupt context block addr */ - iocla = RMW(chan_icb+16); /* iocla is in wd 4 of ICB */ sim_debug(DEBUG_CMD, &cpu_dev, - "STPIO busy test rchsa %04x cmd %02x ccw_flags %04x IOCD1 %08x IOCD2 %08x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); + "STPIO busy test chsa %04x cmd %02x ccw_flags %04x IOCD1 %08x IOCD2 %08x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, M[iocla>>2], M[(iocla+4)>>2]); + /* reset the CC bit to force completion after current IOCD */ chp->ccw_flags &= ~FLAG_CC; /* reset chaining bits */ @@ -1832,9 +1846,9 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */ /* SCPR_IOERR is 2 */ if ((tempa & RMASK) != SCPE_OK) { /* sub channel has status ready */ /* The device I/O has been terminated and status stored. */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_EXP, &cpu_dev, "STPIO stop_io call return ERROR FIFO #%1x rchan %04x retstat %08x cstat %08x\n", - FIFO_Num(rchsa), rchan, tempa, chp->chan_status); + FIFO_Num(chsa), chan, tempa, chp->chan_status); /* chan_end is called in stop device service routine */ /* the device is no longer busy, post status */ @@ -1846,8 +1860,8 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */ INTS[inta] &= ~INTS_REQ; /* clear any level request */ *status = CC2BIT; /* status stored */ sim_debug(DEBUG_CMD, &cpu_dev, - "STPIO END2 rchsa %04x rchan %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, rchan, chp->ccw_cmd, chp->ccw_flags, *status); + "STPIO END2 chsa %04x rchan %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chan, chp->ccw_cmd, chp->ccw_flags, *status); /* change status from BUFF_POST to BUFF_DONE */ if (chp->chan_byte == BUFF_POST) { chp->chan_byte = BUFF_DONE; /* show done & not busy */ @@ -1859,26 +1873,26 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */ /* The diags want the interrupt for the disk */ *status = CC1BIT; /* request accepted, no status, so CC1 */ sim_debug(DEBUG_CMD, &cpu_dev, - "STPIO END2 ECHO rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "STPIO END2 ECHO chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); return SCPE_OK; /* CC1 & all OK */ } } /* the channel is not busy, so return OK */ *status = CC1BIT; /* request accepted, no status, so CC1 */ sim_debug(DEBUG_CMD, &cpu_dev, - "STPIO END3 rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "STPIO END3 chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); return SCPE_OK; /* No CC's all OK */ } if ((chp->chan_byte & BUFF_BUSY) == 0) { /* the channel is not busy, so return OK */ sim_debug(DEBUG_CMD, &cpu_dev, - "STPIO not busy return rchsa %04x cmd %02x ccw_flags %04x status %04x byte %02x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status, chp->chan_byte); + "STPIO not busy return chsa %04x cmd %02x ccw_flags %04x status %04x byte %02x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status, chp->chan_byte); sim_debug(DEBUG_IRQ, &cpu_dev, - "STPIO rchsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, chp->chan_inch_addr, chan_icb, chp->chan_byte); + "STPIO chsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, chp->chan_inch_addr, chan_icb, chp->chan_byte); /* now store the status dw address into word 5 of the ICB for the channel */ WMW(chan_icb+20, 0x80000000); /* post sw addr 0 in ICB+5w & set CC 1*/ *status = CC1BIT; /* show not busy, post no status with CC1 */ @@ -1891,34 +1905,32 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */ /* restore code to old CC1BIT return 12/21/2020 */ // try using CC4 on MPX3X when still busy if (chp->chan_byte == BUFF_POST) { - uint32 incha = chp->chan_inch_addr; /* get inch address */ *status = CC1BIT; /* request accepted, no status, so CC1 */ /* see if any status ready to post */ - if (FIFO_Num(rchsa)) { + if (FIFO_Num(chsa)) { sim_debug(DEBUG_IRQ, &cpu_dev, "STPIO chsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chp, chan_icb, chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, chp, chan_icb, chp->chan_byte); if (post_csw(chp, 0)) { sim_debug(DEBUG_IRQ, &cpu_dev, "STPIO chsa %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); /* change status from BUFF_POST to BUFF_DONE */ /* if not BUFF_POST we have a PPCI or channel busy interrupt */ /* so leave the channel status alone */ chp->chan_byte = BUFF_DONE; /* show done & not busy */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_IRQ, &cpu_dev, "STPIO END incha %06x chan_icba+20 %08x chsa %04x sw1 %08x sw2 %08x\n", - incha, RMW(chan_icb+20), rchsa, RMW(incha), RMW(incha+4)); + incha, RMW(chan_icb+20), chsa, RMW(incha), RMW(incha+4)); INTS[inta] &= ~INTS_REQ; /* clear any level request if no status */ *status = CC2BIT; /* status stored from SIO, so CC2 */ return SCPE_OK; /* No CC's all OK */ } else { - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_EXP, &cpu_dev, "STPIOX chsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chan_icb, chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, chan_icb, chp->chan_byte); /* now store the status dw address into word 5 of the ICB for the channel */ WMW(chan_icb+20, 0x80000000); /* post CC1 & sw addr 0 in ICB+5w & reset CCs */ -// WMW(chan_icb+20, 0); /* post sw addr 0 in ICB+5w & reset CCs */ *status = CC1BIT; /* show not busy, post no status with CC1 */ return SCPE_OK; /* No CC's all OK */ } @@ -1928,83 +1940,107 @@ t_stat stopxio(uint16 lchsa, uint32 *status) { /* stop XIO */ /* having it set to CC1 allows diags to work, but not MPX 3X boot! */ // This check allows DBUG2 and DIAGS to both work if (chp->chan_byte == BUFF_NEXT) -//BAD?? *status = CC1BIT; /* request accepted, no status, so CC1 */ - *status = CC4BIT; /* BAD FOR DIAG *//* request accepted, busy, so CC4 */ + *status = CC4BIT; /* BAD FOR DIAG */ /* request accepted, busy, so CC4 */ else - *status = CC4BIT; /* BAD FOR DIAG *//* request accepted, busy, so CC4 */ + *status = CC4BIT; /* BAD FOR DIAG */ /* request accepted, busy, so CC4 */ sim_debug(DEBUG_IRQ, &cpu_dev, "STPIO2 chsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, chp->chan_inch_addr, chan_icb, chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, chan_icb, chp->chan_byte); } /* reset the CC bit to force completion after current IOCD */ chp->ccw_flags &= ~FLAG_CC; /* reset chaining bits */ sim_debug(DEBUG_CMD, &cpu_dev, - "STPIO busy return CC1/4 rchsa %04x status %08x cmd %02x flags %04x byte %02x\n", - rchsa, *status, chp->ccw_cmd, chp->ccw_flags, chp->chan_byte); + "STPIO busy return CC1/4 chsa %04x status %08x cmd %02x flags %04x byte %02x\n", + chsa, *status, chp->ccw_cmd, chp->ccw_flags, chp->chan_byte); return SCPE_OK; /* go wait CC1 */ } /* Reset Channel XIO */ t_stat rschnlxio(uint16 lchsa, uint32 *status) { /* reset channel XIO */ DIB *dibp; /* device information pointer */ + DIB *pdibp; /* parent DIB pointer */ UNIT *uptr; /* pointer to unit in channel */ + uint32 chan_icb; /* Interrupt level context block address */ CHANP *chp; /* Channel prog pointers */ + CHANP *pchp; /* for parent channel prog ptr */ DEVICE *dptr; /* Device ptr */ - int i; - uint16 lchan = get_chan(lchsa); /* get the logical channel number */ uint32 inta; uint32 spadent; - uint16 rchan, rchsa; /* the real channel number */ + uint16 chan, chsa; /* the real channel number, chsa */ + int i; /* get the device entry for the logical channel in SPAD */ - spadent = SPAD[lchan]; /* get spad device entry for logical channel */ - rchan = (spadent & 0x7f00) >> 8; /* get real channel */ - rchsa = rchan << 8; /* get the real chan & zero suba */ + spadent = SPAD[get_chan(lchsa)]; /* get spad device entry for logical channel */ + inta = ((~spadent)>>16)&0x7f; /* get interrupt level */ + chan = (spadent & 0x7f00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - /* get the device entry for the logical channel in SPAD */ - dibp = dib_unit[rchsa]; /* get the channel device information pointer */ - chp = find_chanp_ptr(rchsa); /* find the channel chanp pointer */ + /* check if we have a valid unit */ + pdibp = dib_chan[chan]; /* for parent DIB ptr */ + if (pdibp == 0) goto missing; - if (dibp == 0 || chp == 0) { /* if no dib or channel ptr, CC3 return */ + pchp = pdibp->chan_prg; /* for parent channel prog ptr */ + if (pchp == 0) goto missing; + + /* we must have a valid ICB for the interrupt */ + chan_icb = find_int_icb(chsa); /* Interrupt level context block address */ + if (chan_icb == 0) goto missing; + + /* check if we have a valid dib for the unit */ + dibp = dib_unit[chsa]; /* get the DIB pointer */ + if (dibp == 0) goto missing; + + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ + if (chp == 0) goto missing; + + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ +missing: *status = CC3BIT; /* not found, so CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "rschnlxio test 1 dibp %p chp %p lchsa %04x rchsa %04x device not present, CC3 returned\n", - dibp, chp, lchsa, rchsa); - return SCPE_OK; /* not found CC3 */ + "RSCHNL chsa %04x is not found or invalid, CC3 returned\n", lchsa); + return SCPE_OK; /* not found, CC3 */ } - uptr = chp->unitptr; /* get the unit ptr */ + /* save interrupt level number in channel & parent channel */ + chp->chan_int = inta; /* make sure it is set in channel */ + pchp->chan_int = inta; /* make sure it is set in parent channel */ + sim_debug(DEBUG_XIO, &cpu_dev, + "RSCHNL entry inta %02x lchan %04x spadent %08x chsa %04x\n", + inta, chan, spadent, chsa); + + sim_debug(DEBUG_CMD, &cpu_dev, + "RSCHNL chsa %04x chp %p flags UNIT_ATTABLE %1x UNIT_ATT %1x UNIT_DIS %1x\n", + chsa, chp, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0, + (uptr->flags & UNIT_DIS)?1:0); + /* is device or unit marked disabled? */ dptr = get_dev(uptr); if ((dptr->flags & DEV_DIS) || ((uptr->flags & UNIT_DIS) && ((uptr->flags & UNIT_SUBCHAN) == 0))) { - /* is device/unit disabled? */ - *status = CC3BIT; /* not enabled, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "RSCHNL rchsa %04x device/unit not enabled, CC3 returned\n", rchsa); - return SCPE_OK; /* Not found, CC3 */ + "RSCHNL chsa %04x device/unit disabled, CC3 returned flags %08x\n", chsa, uptr->flags); + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ } - inta = ((~spadent)>>16)&0x7f; /* get channel interrupt level */ - chp->chan_int = inta; /* make sure it is set in channel */ - /* reset this channel */ dibp->chan_fifo_in = 0; /* reset the FIFO pointers */ dibp->chan_fifo_out = 0; /* reset the FIFO pointers */ - chp->chan_inch_addr = 0; /* remove inch status buffer address */ - chp->base_inch_addr = 0; /* clear the base inch addr */ - chp->max_inch_addr = 0; /* clear the last inch addr */ + pchp->chan_inch_addr = 0; /* remove inch status buffer address */ + pchp->base_inch_addr = 0; /* clear the base inch addr */ + pchp->max_inch_addr = 0; /* clear the last inch addr */ INTS[inta] &= ~INTS_ACT; /* clear level active */ SPAD[inta+0x80] &= ~SINT_ACT; /* clear in spad too */ /* now go through all the sa for the channel and stop any IOCLs */ for (i=0; iunitptr; /* get the unit ptr */ @@ -2013,9 +2049,11 @@ t_stat rschnlxio(uint16 lchsa, uint32 *status) { /* reset channel XIO */ if (dibp->rschnl_io != NULL) { /* NULL if no rschnl_io function */ /* call the device controller to process rschnl */ j = dibp->rschnl_io(uptr); /* get status from device */ - sim_debug(DEBUG_EXP, &cpu_dev, - "rschnl_io returned %02x chsa %04x\n", j, rchsa); + sim_debug(DEBUG_CMD, &cpu_dev, + "RSCHNL rschnl_io returned %02x chsa %04x\n", j, chsa); } + dibp->chan_fifo_in = 0; /* reset the FIFO pointers (unused) */ + dibp->chan_fifo_out = 0; /* reset the FIFO pointers (unused) */ chp->chan_status = 0; /* clear the channel status */ chp->chan_byte = BUFF_EMPTY; /* no data yet */ chp->ccw_addr = 0; /* clear buffer address */ @@ -2027,113 +2065,133 @@ t_stat rschnlxio(uint16 lchsa, uint32 *status) { /* reset channel XIO */ chp->base_inch_addr = 0; /* clear the base inch addr */ chp->max_inch_addr = 0; /* clear the last inch addr */ } - sim_debug(DEBUG_XIO, &cpu_dev, "rschnlxio return CC1 lchan %02x lchan %02x inta %04x\n", - lchan, rchan, inta); + sim_debug(DEBUG_XIO, &cpu_dev, "RSCHNL return CC1 lchsa %02x chan %02x inta %04x\n", + lchsa, chan, inta); *status = CC1BIT; /* request accepted, no status, so CC1 TRY THIS */ return SCPE_OK; /* All OK */ } /* HIO - Halt I/O */ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ - DIB *dibp; - UNIT *uptr; + DIB *dibp; /* device information pointer */ + DIB *pdibp; /* parent DIB pointer */ + UNIT *uptr; /* pointer to unit in channel */ uint32 chan_icb; /* Interrupt level context block address */ uint32 iocla; /* I/O channel IOCL address int ICB */ - uint32 inta, spadent, tempa, itva; - uint16 lchan = get_chan(lchsa); - uint16 rchan, rchsa; CHANP *chp; /* Channel prog pointers */ - DEVICE *dptr; /* DEVICE pointer */ + CHANP *pchp; /* for parent channel prog ptr */ + DEVICE *dptr; /* Device ptr */ + uint32 inta, incha; + uint32 spadent; + uint16 chan, chsa; /* the real channel number, chsa */ /* get the device entry for the logical channel in SPAD */ - spadent = SPAD[lchan]; /* get spad device entry for logical channel */ - rchan = (spadent & 0x7f00) >> 8; /* get real channel */ - rchsa = (rchan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - dibp = dib_unit[rchsa]; /* get the device DIB pointer */ - chp = find_chanp_ptr(rchsa); /* find the chanp pointer */ + spadent = SPAD[get_chan(lchsa)]; /* get spad device entry for logical channel */ + inta = ((~spadent)>>16)&0x7f; /* get interrupt level */ + chan = (spadent & 0x7f00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - if (dibp == 0 || chp == 0) { /* if no dib or chan ptr, CC3 on return */ + /* check if we have a valid unit */ + pdibp = dib_chan[chan]; /* for parent DIB ptr */ + if (pdibp == 0) goto missing; + + pchp = pdibp->chan_prg; /* for parent channel prog ptr */ + if (pchp == 0) goto missing; + + /* we must have a valid ICB for the interrupt */ + chan_icb = find_int_icb(chsa); /* Interrupt level context block address */ + if (chan_icb == 0) goto missing; + + /* check if we have a valid dib for the unit */ + dibp = dib_unit[chsa]; /* get the DIB pointer */ + if (dibp == 0) goto missing; + + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ + if (chp == 0) goto missing; + + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ +missing: *status = CC3BIT; /* not found, so CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO lchsa %04x rchsa %04x device not present, CC3 returned\n", lchsa, rchsa); + "HIO chsa %04x is not found or invalid, CC3 returned\n", lchsa); return SCPE_OK; /* not found, CC3 */ } - uptr = chp->unitptr; /* get the unit ptr */ + incha = pchp->chan_inch_addr; /* get inch status buffer address for channel */ + + /* save interrupt level number in channel & parent channel */ + chp->chan_int = inta; /* make sure it is set in channel */ + pchp->chan_int = inta; /* make sure it is set in parent channel */ + sim_debug(DEBUG_CMD, &cpu_dev, + "HIO entry inta %02x lchan %04x spadent %08x chsa %04x\n", + inta, chan, spadent, chsa); + + sim_debug(DEBUG_CMD, &cpu_dev, + "HIO chsa %04x chp %p flags UNIT_ATTABLE %1x UNIT_ATT %1x UNIT_DIS %1x\n", + chsa, chp, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0, + (uptr->flags & UNIT_DIS)?1:0); + /* is device or unit marked disabled? */ dptr = get_dev(uptr); if ((dptr->flags & DEV_DIS) || ((uptr->flags & UNIT_DIS) && ((uptr->flags & UNIT_SUBCHAN) == 0))) { - /* is device/unit disabled? */ - *status = CC3BIT; /* not enabled, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO rchsa %04x device/unit not enabled, CC3 returned\n", rchsa); - return SCPE_OK; /* Not found, CC3 */ + "HIO chsa %04x device/unit disabled, CC3 returned flags %08x\n", chsa, uptr->flags); + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ } - /* see if interrupt is setup in SPAD and determine IVL for channel */ - sim_debug(DEBUG_EXP, &cpu_dev, "HIO dev spad %08x lchsa %04x rchsa %04x\n", spadent, lchsa, rchsa); - - /* the haltio opcode processing software has already checked for F class */ - inta = ((~spadent)>>16)&0x7f; /* get channel interrupt level */ - chp->chan_int = inta; /* make sure it is set in channel */ - sim_debug(DEBUG_EXP, &cpu_dev, "HIO int spad %08x inta %02x rchan %02x\n", spadent, inta, rchan); - - /* get the address of the interrupt IVL in main memory */ - itva = SPAD[0xf1] + (inta<<2); /* int vector address */ - chan_icb = RMW(itva); /* Interrupt context block addr */ iocla = RMW(chan_icb+16); /* iocla is in wd 4 of ICB */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO busy test byte %02x rchsa %04x cmd %02x ccw_flags %04x IOCD1 %08x IOCD2 %08x\n", - chp->chan_byte, rchsa, chp->ccw_cmd, chp->ccw_flags, RMW(iocla), RMW(iocla+4)); + "HIO busy test byte %02x chsa %04x cmd %02x ccw_flags %04x IOCD1 %08x IOCD2 %08x\n", + chp->chan_byte, chsa, chp->ccw_cmd, chp->ccw_flags, RMW(iocla), RMW(iocla+4)); /* the channel is busy, so process */ /* see if we have a haltio device entry */ if (dibp->halt_io != NULL) { /* NULL if no haltio function */ /* call the device controller to get halt_io status */ - tempa = dibp->halt_io(uptr); /* get status from device */ + uint32 tempa = dibp->halt_io(uptr); /* get status from device */ /* CC's are returned in bits 1-4. Bits 16-31 has SCPE code */ /* SCPE_IOERR is 2 */ /* SCPE_OK is 0 */ if ((tempa & RMASK) != SCPE_OK) { /* sub channel has status ready */ - uint32 incha = chp->chan_inch_addr; /* get inch address */ /* The device I/O has been terminated and status stored. */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO halt_io call return ERROR FIFO #%1x rchsa %04x retstat %08x cstat %08x\n", - FIFO_Num(rchsa), rchsa, tempa, chp->chan_status); + "HIO halt_io call return ERROR FIFO #%1x chsa %04x retstat %08x cstat %08x\n", + FIFO_Num(chsa), chsa, tempa, chp->chan_status); /* chan_end is called in hio device service routine */ /* the device is no longer busy, post status */ /* The diags want the interrupt for the disk */ *status = CC1BIT; /* request accepted, no status, so CC1 */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO END2X ECHO rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); -// irq_pend = 1; /* flag to test for int condition */ + "HIO END2X ECHO chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); sim_debug(DEBUG_IRQ, &cpu_dev, - "HIO rchsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chp, chan_icb, chp->chan_byte); + "HIO chsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, incha, chp, chan_icb, chp->chan_byte); - /* see if user wants to have status posted and setting CC2 in return value */ + /* see if user wants to have status posted by setting CC2 in return value */ if ((tempa & LMASK) == CC2BIT) { sim_debug(DEBUG_IRQ, &cpu_dev, - "HIO rchsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chp, chan_icb, chp->chan_byte); + "HIO chsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, incha, chp, chan_icb, chp->chan_byte); /* post any status */ if (post_csw(chp, 0)) { sim_debug(DEBUG_IRQ, &cpu_dev, - "HIO rchsa %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); + "HIO chsa %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); /* change status from BUFF_POST to BUFF_DONE */ /* if not BUFF_POST we have a PPCI or channel busy interrupt */ /* so leave the channel status alone */ if (chp->chan_byte == BUFF_POST) { chp->chan_byte = BUFF_DONE; /* show done & not busy */ } - sim_debug(DEBUG_XIO, &cpu_dev, - "HIO END incha %06x chan_icba+20 %08x rchsa %04x sw1 %08x sw2 %08x\n", - incha, RMW(chan_icb+20), rchsa, RMW(incha), RMW(incha+4)); + sim_debug(DEBUG_IRQ, &cpu_dev, + "HIO END incha %06x chan_icba+20 %08x chsa %04x sw1 %08x sw2 %08x\n", + incha, RMW(chan_icb+20), chsa, RMW(incha), RMW(incha+4)); /*ADDED 111921 to disable int request after data posted */ INTS[inta] &= ~INTS_REQ; /* clear any level request */ *status = CC2BIT; /* status stored from SIO, so CC2 */ @@ -2143,12 +2201,12 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ /* see if user wants to have status posted by setting CC4 in return value */ if ((tempa & LMASK) == CC4BIT) { sim_debug(DEBUG_IRQ, &cpu_dev, - "HIO rchsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chp, chan_icb, chp->chan_byte); + "HIO chsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", + chsa, FIFO_Num(chsa), inta, incha, chp, chan_icb, chp->chan_byte); } sim_debug(DEBUG_EXP, &cpu_dev, - "HIO END2Y rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "HIO END2Y chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); return SCPE_OK; /* CC1 & all OK */ } /* the device is not busy, so cmd is completed */ @@ -2157,13 +2215,13 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ /* the channel is not busy, so return OK */ *status = CC1BIT; /* request accepted, post good status, so CC1 */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO END3 rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "HIO END3 chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); #ifndef GIVE_INT_ON_NOT_BUSY_121420_03082021 chp->chan_byte = BUFF_DONE; /* we are done */ sim_debug(DEBUG_EXP, &cpu_dev, - "haltxio BUFF_DONE2 chp %p chan_byte %04x\n", chp, chp->chan_byte); + "HIO BUFF_DONE2 chp %p chan_byte %04x\n", chp, chp->chan_byte); if ((dptr != NULL) && (DEV_TYPE(dptr) == DEV_ETHER)) { /* see if this is ethernet */ /* Ethernet does not want SNS_UNITEXP */ @@ -2186,8 +2244,8 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ /* the channel is not busy, so return OK */ *status = CC1BIT; /* request accepted, no status, so CC1 */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO END1 not busy return rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "HIO END1 not busy return chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); chp->chan_byte = BUFF_DONE; /* we are done */ chp->chan_status = (STATUS_DEND|STATUS_CEND|STATUS_EXPT); store_csw(chp); /* store the status */ @@ -2203,14 +2261,14 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ /* a haltxio entry should be provided for a device so busy can be cleared */ /* check for a Command or data chain operation in progresss */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO device busy lchsa %04x rchsa %04x\n", lchsa, rchsa); + "HIO device busy lchsa %04x chsa %04x\n", lchsa, chsa); /* reset the DC or CC bits to force completion */ chp->ccw_flags &= ~(FLAG_DC|FLAG_CC); /* reset chaining bits */ chp->chan_byte = BUFF_BUSY; /* wait for post_csw to be done */ sim_cancel(uptr); /* cancel timer service */ chp->chan_status &= ~STATUS_BUSY; /* remove BUSY status bit */ - chan_end(rchsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); /* show I/O complete */ + chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); /* show I/O complete */ /* post the channel status */ chp->ccw_count = 0; /* zero the count */ @@ -2219,8 +2277,8 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ INTS[inta] &= ~INTS_REQ; /* clear any level request */ *status = CC2BIT; /* status stored from SIO, so CC2 */ sim_debug(DEBUG_EXP, &cpu_dev, - "HIO END4 rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "HIO END4 chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); /* change status from BUFF_POST to BUFF_DONE */ if (chp->chan_byte == BUFF_POST) { chp->chan_byte = BUFF_DONE; /* show done & not busy */ @@ -2228,8 +2286,8 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ return SCPE_OK; /* CC2 & all OK */ } sim_debug(DEBUG_EXP, &cpu_dev, - "HIO END5 rchsa %04x cmd %02x ccw_flags %04x status %04x\n", - rchsa, chp->ccw_cmd, chp->ccw_flags, *status); + "HIO END5 chsa %04x cmd %02x ccw_flags %04x status %04x\n", + chsa, chp->ccw_cmd, chp->ccw_flags, *status); return SCPE_OK; /* No CC's all OK */ } @@ -2237,51 +2295,78 @@ t_stat haltxio(uint16 lchsa, uint32 *status) { /* halt XIO */ /* TODO return unimplemented function error, not busy */ t_stat grabxio(uint16 lchsa, uint32 *status) { /* grab controller XIO n/u */ DIB *dibp; /* device information pointer */ + DIB *pdibp; /* parent DIB pointer */ UNIT *uptr; /* pointer to unit in channel */ - CHANP *chp; + uint32 chan_icb; /* Interrupt level context block address */ + CHANP *chp; /* Channel prog pointers */ + CHANP *pchp; /* for parent channel prog ptr */ DEVICE *dptr; /* Device ptr */ - uint16 lchan = get_chan(lchsa); /* get the logical channel number */ + uint32 inta, incha; uint32 spadent; - uint16 rchan, rchsa; /* the real channel number, chsa */ + uint16 chan, chsa; /* the real channel number, chsa */ /* get the device entry for the logical channel in SPAD */ - spadent = SPAD[lchan]; /* get spad device entry for logical channel */ - rchan = (spadent & 0x7f00) >> 8; /* get real channel */ - rchsa = (rchan << 8) | (lchsa & 0xff); /* merge sa to real channel */ + spadent = SPAD[get_chan(lchsa)]; /* get spad device entry for logical channel */ + inta = ((~spadent)>>16)&0x7f; /* get interrupt level */ + chan = (spadent & 0x7f00) >> 8; /* get real channel */ + chsa = (chan << 8) | (lchsa & 0xff); /* merge sa to real channel */ - /* get the device entry for the logical channel in SPAD */ - dibp = dib_unit[rchsa]; /* get the DIB pointer */ - chp = find_chanp_ptr(rchsa); /* find the device chanp pointer */ + /* check if we have a valid unit */ + pdibp = dib_chan[chan]; /* for parent DIB ptr */ + if (pdibp == 0) goto missing; - if (dibp == 0 || chp == 0) { /* if no dib or channel ptr, CC3 return */ + pchp = pdibp->chan_prg; /* for parent channel prog ptr */ + if (pchp == 0) goto missing; + + /* we must have a valid ICB for the interrupt */ + chan_icb = find_int_icb(chsa); /* Interrupt level context block address */ + if (chan_icb == 0) goto missing; + + /* check if we have a valid dib for the unit */ + dibp = dib_unit[chsa]; /* get the DIB pointer */ + if (dibp == 0) goto missing; + + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ + if (chp == 0) goto missing; + + uptr = find_unit_ptr(chsa); /* find pointer to unit on channel */ + if (uptr == 0) { /* if no dib or unit ptr, CC3 on return */ +missing: *status = CC3BIT; /* not found, so CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "GRIO test 1 rchsa %04x device not present, CC3 returned\n", rchsa); - return SCPE_OK; /* not found CC3 */ + "GRIO chsa %04x is not found or invalid, CC3 returned\n", lchsa); + return SCPE_OK; /* not found, CC3 */ } + incha = pchp->chan_inch_addr; /* get inch status buffer address for channel */ + + /* save interrupt level number in channel & parent channel */ + chp->chan_int = inta; /* make sure it is set in channel */ + pchp->chan_int = inta; /* make sure it is set in parent channel */ + sim_debug(DEBUG_XIO, &cpu_dev, + "GRIO entry inta %02x lchan %04x spadent %08x chsa %04x\n", + inta, chan, spadent, chsa); sim_debug(DEBUG_CMD, &cpu_dev, - "GRIO entry rchsa %04x status %08x cmd %02x flags %02x byte %02x\n", - rchsa, *status, chp->ccw_cmd, chp->ccw_flags, chp->chan_byte); + "GRIO chsa %04x chp %p flags UNIT_ATTABLE %1x UNIT_ATT %1x UNIT_DIS %1x\n", + chsa, chp, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0, + (uptr->flags & UNIT_DIS)?1:0); - uptr = chp->unitptr; /* get the unit ptr */ /* is device or unit marked disabled? */ dptr = get_dev(uptr); if ((dptr->flags & DEV_DIS) || ((uptr->flags & UNIT_DIS) && ((uptr->flags & UNIT_SUBCHAN) == 0))) { - /* is device/unit disabled? */ - *status = CC3BIT; /* not enabled, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "GRIO rchsa %04x device/unit not enabled, CC3 returned\n", rchsa); - return SCPE_OK; /* Not found, CC3 */ + "GRIO chsa %04x device/unit disabled, CC3 returned flags %08x\n", chsa, uptr->flags); + *status = CC3BIT; /* not attached, so error CC3 */ + return SCPE_OK; /* not found, CC3 */ } /* check for a Command or data chain operation in progresss */ if (chp->ccw_cmd != 0 || (chp->ccw_flags & (FLAG_DC|FLAG_CC)) != 0) { *status = CC4BIT; /* busy, so CC4 */ sim_debug(DEBUG_CMD, &cpu_dev, - "GRIO busy return CC4 lchsa %04x rchsa %04x status %08x\n", - lchsa, rchsa, *status); + "GRIO busy return CC4 lchsa %04x chsa %04x status %08x\n", + lchsa, chsa, *status); return SCPE_OK; /* CC4 all OK */ } @@ -2299,29 +2384,28 @@ t_stat grabxio(uint16 lchsa, uint32 *status) { /* grab controller XIO n/u */ chan_icb = RMW(itva); /* Interrupt context block addr */ *status = CC1BIT; /* request accepted, no status, so CC1 */ /* see if any status ready to post */ - if (FIFO_Num(rchsa)) { - uint32 incha = chp->chan_inch_addr; /* get inch address */ + if (FIFO_Num(chsa)) { sim_debug(DEBUG_IRQ, &cpu_dev, "GRIO chsa %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chp, chan_icb, chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, chp, chan_icb, chp->chan_byte); if (post_csw(chp, 0)) { sim_debug(DEBUG_IRQ, &cpu_dev, "GRIO chsa %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, RMW(chan_icb+20), chp->chan_byte); /* change status from BUFF_POST to BUFF_DONE */ /* if not BUFF_POST we have a PPCI or channel busy interrupt */ /* so leave the channel status alone */ chp->chan_byte = BUFF_DONE; /* show done & not busy */ sim_debug(DEBUG_XIO, &cpu_dev, "GRIO END incha %06x chan_icba+20 %08x chsa %04x sw1 %08x sw2 %08x\n", - incha, RMW(chan_icb+20), rchsa, RMW(incha), RMW(incha+4)); + incha, RMW(chan_icb+20), chsa, RMW(incha), RMW(incha+4)); INTS[inta] &= ~INTS_REQ; /* clear any level request if no status */ *status = CC2BIT; /* status stored from SIO, so CC2 */ return SCPE_OK; /* No CC's all OK */ } else { sim_debug(DEBUG_IRQ, &cpu_dev, "GRIO chsa %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - rchsa, FIFO_Num(rchsa), inta, incha, chan_icb, chp->chan_byte); + chsa, FIFO_Num(chsa), inta, incha, chan_icb, chp->chan_byte); /* now store the status dw address into word 5 of the ICB for the channel */ WMW(chan_icb+20, 0); /* post sw addr 0 in ICB+5w & reset CCs */ *status = 0; /* no status stored from STPIO, so no CC */ @@ -2331,7 +2415,7 @@ t_stat grabxio(uint16 lchsa, uint32 *status) { /* grab controller XIO n/u */ } /* If this is console, debugger wants CC3 & CC4 = 0 */ - if (rchan == 0x7e) { + if (chan == 0x7e) { /* returning No CC's causes MPX1X to loop forever */ /* so restore returning CC1 */ *status = 0; /* return no CC's */ @@ -2340,7 +2424,7 @@ t_stat grabxio(uint16 lchsa, uint32 *status) { /* grab controller XIO n/u */ *status = CC2BIT|CC4BIT; /* unsupported transaction */ } sim_debug(DEBUG_CMD, &cpu_dev, - "GRIO lchsa %04x rchsa %04x status %08x\n", lchsa, rchsa, *status); + "GRIO lchsa %04x chsa %04x status %08x\n", lchsa, chsa, *status); return SCPE_OK; /* dono */ } @@ -2377,7 +2461,7 @@ t_stat rsctlxio(uint16 lchsa, uint32 *status) { /* reset controller XIO */ ((uptr->flags & UNIT_SUBCHAN) == 0))) { *status = CC3BIT; /* not enabled, so error CC3 */ sim_debug(DEBUG_EXP, &cpu_dev, - "RSCTL rchsa %04x device/unit not enabled, CC3 returned\n", chsa); + "RSCTL chsa %04x device/unit not enabled, CC3 returned\n", chsa); return SCPE_OK; /* Not found, CC3 */ } lev = find_int_lev(chan); /* get our int level */ @@ -2448,6 +2532,8 @@ t_stat chan_boot(uint16 chsa, DEVICE *dptr) { CHANP *chp = 0; sim_debug(DEBUG_EXP, &cpu_dev, "Channel Boot chan/device addr %04x SNS %08x\n", chsa, uptr->u5); + fflush(sim_deb); + if (dibp == 0) /* if no channel or device, error */ return SCPE_IOERR; /* error */ if (dibp->chan_prg == NULL) /* must have channel information for each device */ @@ -2472,6 +2558,9 @@ t_stat chan_boot(uint16 chsa, DEVICE *dptr) { return SCPE_UNATT; /* error */ } + fflush(sim_deb); + fflush(stdout); + chp->chan_status = 0; /* clear the channel status */ chp->chan_dev = chsa; /* save our address (ch/sa) */ chp->chan_byte = BUFF_EMPTY; /* no data yet */ @@ -2481,7 +2570,7 @@ t_stat chan_boot(uint16 chsa, DEVICE *dptr) { chp->ccw_flags = 0; /* Command chain and supress incorrect length */ chp->chan_info = INFO_SIOCD; /* show first IOCD in channel prog */ chp->ccw_cmd = 0; /* read command */ - /* moved here to not destry loc 0-0x14 on reset/go cmds */ + /* moved here to not destroy loc 0-0x14 on reset/go cmds */ M[0] = 0x02000000; /* 0x00 IOCD 1 read into address 0 */ M[1] = 0x60000078; /* 0x04 IOCD 1 CMD Chain, Suppress incor length, 120 bytes */ M[2] = 0x53000000; /* 0x08 IOCD 2 BKSR or RZR to re-read boot code */ @@ -2502,7 +2591,7 @@ t_stat chan_boot(uint16 chsa, DEVICE *dptr) { loading = 0; /* show we are done loading from the boot device */ return SCPE_IOERR; /* return error */ } - sim_debug(DEBUG_XIO, &cpu_dev, "Channel Boot OK return from load_ccw chsa %04x status %04x\n", + sim_debug(DEBUG_EXP, &cpu_dev, "Channel Boot OK return from load_ccw chsa %04x status %04x\n", chsa, chp->chan_status); return SCPE_OK; /* all OK */ } @@ -2577,45 +2666,52 @@ uint32 cont_chan(uint16 chsa) uint32 scan_chan(uint32 *ilev) { int i; uint32 chsa; /* No device */ - uint32 chan; /* channel num 0-7f */ + uint32 chsa0; /* channel num with sa=0 */ uint32 tempa; /* icb address */ uint32 incha; /* inch address */ uint32 chan_ivl; /* int level table address */ uint32 chan_icba; /* Interrupt level context block address */ CHANP *chp; /* channel prog pointer */ + CHANP *pchp; /* for parent channel prog ptr */ DIB *dibp; /* DIB pointer */ + DIB *pdibp; /* parent DIB pointer */ uint32 sw1, sw2; /* status words */ /* see if we are loading */ if (loading) { + chsa = loading; /* get device we are loading from */ /* we are loading see if chan prog complete */ /* get the device entry for the logical channel in SPAD */ - chan = loading & 0x7f00; /* get real channel and zero sa */ - dibp = dib_unit[chan]; /* get the IOP/MFP DIB pointer */ + pdibp = dib_chan[get_chan(chsa)]; /* get DIB pointer for boot device */ + if (pdibp == 0) + return 0; /* skip unconfigured channel */ + pchp = pdibp->chan_prg; /* get parent channel prog address */ + chsa0 = chsa & 0x7f00; /* get channel and zero sa */ + dibp = dib_unit[chsa]; /* get the boot device DIB pointer */ if (dibp == 0) return 0; /* skip unconfigured channel */ + chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ /* see if status is stored in FIFO */ /* see if the FIFO is empty */ - if ((FIFO_Num(chan)) && ((FIFO_Get(chan, &sw1) == 0) && - (FIFO_Get(chan, &sw2) == 0))) { + if ((FIFO_Num(chsa)) && ((FIFO_Get(chsa, &sw1) == 0) && + (FIFO_Get(chsa, &sw2) == 0))) { /* the SPAD entries are not set up, so no access to icb or ints */ /* get the status from the FIFO and throw it away */ /* we really should post it to the current inch address */ /* there is really no need to post, but it might be helpfull */ - chp = find_chanp_ptr(chan); /* find the chanp pointer for channel */ /* this address most likely will be zero here */ - tempa = chp->chan_inch_addr; /* get inch status buffer address */ + incha = pchp->chan_inch_addr; /* get inch status buffer address */ /* before overwriting memory loc 0+4, save PSD for caller in TPSD[] locations */ TPSD[0] = M[0]; /* save PSD from loc 0&4 */ TPSD[1] = M[1]; /* save the status double word to memory */ /* set BIT 1 to show status stored */ - WMW(tempa, sw1|BIT1); /* save sa & IOCD address in status WD 1 loc */ - WMW(tempa+4, sw2); /* save status and residual cnt in status WD 2 loc */ + WMW(incha, sw1|BIT1); /* save sa & IOCD address in status WD 1 loc */ + WMW(incha+4, sw2); /* save status and residual cnt in status WD 2 loc */ chp->chan_byte = BUFF_DONE; /* we are done */ sim_debug(DEBUG_IRQ, &cpu_dev, "LOADING %06x %04x FIFO #%1x read inch %06x sw1 %08x sw2 %08x\n", - chp->chan_caw, chan, FIFO_Num(chan), tempa, sw1|BIT1, sw2); + chp->chan_caw, chsa, FIFO_Num(chsa), incha, sw1|BIT1, sw2); return loading; } return 0; /* not ready, return */ @@ -2633,21 +2729,18 @@ uint32 scan_chan(uint32 *ilev) { /* see if there is pending status for this channel */ /* if there is and the level is not requesting, do it */ /* get the device entry for the logical channel in SPAD */ - chan = (SPAD[i+0x80] & 0x7f00); /* get real channel and zero sa */ - dibp = dib_chan[get_chan(chan)]; /* get the channel device information pointer */ - if (dibp == 0) /* we have a channel to check */ + chsa0 = (SPAD[i+0x80] & 0x7f00); /* get real channel and zero sa */ + pdibp = dib_chan[get_chan(chsa0)]; /* get the channel device information pointer */ + if (pdibp == 0) /* do we have a channel to check */ continue; /* not defined, skip this one */ /* we have a channel to check */ /* check for pending status */ - if (FIFO_Num(chan)) { + if (FIFO_Num(chsa0)) { INTS[i] |= INTS_REQ; /* turn on channel interrupt request */ sim_debug(DEBUG_EXP, &cpu_dev, "scan_chan FIFO REQ FIFO #%1x irq %02x SPAD %08x INTS %08x\n", FIFO_Num(SPAD[i+0x80] & 0x7f00), i, SPAD[i+0x80], INTS[i]); -#ifdef TRY_DEBUG_01172021 - irq_pend = 1; /* we have pending interrupt */ -#endif continue; } } @@ -2695,29 +2788,31 @@ uint32 scan_chan(uint32 *ilev) { /* see if there is pending status for this channel */ /* get the device entry for the logical channel in SPAD */ - chan = (SPAD[i+0x80] & 0x7f00); /* get real channel and zero sa */ - dibp = dib_chan[get_chan(chan)]; /* get the channel device information pointer */ - if (dibp == 0) { /* see if we have a channel to check */ + chsa0 = (SPAD[i+0x80] & 0x7f00); /* get real channel and zero sa */ + pdibp = dib_chan[get_chan(chsa0)]; /* get the channel device information pointer */ + if (pdibp == 0) { /* see if we have a channel to check */ /* not a channel, must be clk or ext int */ *ilev = i; /* return interrupt level */ irq_pend = 0; /* not pending anymore */ sim_debug(DEBUG_IRQ, &cpu_dev, "scan_chan %04x POST NON FIFO irq %02x chan_icba %06x SPAD[%02x] %08x\n", - chan, i, chan_icba, i+0x80, SPAD[i+0x80]); + chsa0, i, chan_icba, i+0x80, SPAD[i+0x80]); return(chan_icba); /* return ICB address */ } /* must be a device, get status ready to post */ - if (FIFO_Num(chan)) { + if (FIFO_Num(chsa0)) { /* new 051020 find actual device with the channel program */ /* not the channel, that is not correct most of the time */ - tempa = dibp->chan_fifo[dibp->chan_fifo_out]; /* get SW1 of FIFO entry */ - chsa = chan | (tempa >> 24); /* find device address for requesting chan prog */ + tempa = pdibp->chan_fifo[pdibp->chan_fifo_out]; /* get SW1 of FIFO entry */ + chsa = chsa0 | (tempa >> 24); /* find device address for requesting chan prog */ chp = find_chanp_ptr(chsa); /* find the chanp pointer for channel */ - incha = chp->chan_inch_addr; /* get inch status buffer address */ + pchp = pdibp->chan_prg; /* get parent channel prog address */ + incha = pchp->chan_inch_addr; /* get inch status buffer address */ sim_debug(DEBUG_IRQ, &cpu_dev, "scan_chan %04x LOOK FIFO #%1x irq %02x inch %06x chp %p icba %06x chan_byte %02x\n", - chsa, FIFO_Num(chan), i, incha, chp, chan_icba, chp->chan_byte); + chsa, FIFO_Num(chsa), i, incha, chp, chan_icba, chp->chan_byte); if (post_csw(chp, 0)) { + /* The next inch address will be set in post_csw after posting status */ /* change status from BUFF_POST to BUFF_DONE */ /* if not BUFF_POST we have a PPCI or channel busy interrupt */ /* so leave the channel status alone */ @@ -2726,11 +2821,11 @@ uint32 scan_chan(uint32 *ilev) { } sim_debug(DEBUG_IRQ, &cpu_dev, "scan_chanx %04x POST FIFO #%1x irq %02x inch %06x chan_icba+20 %08x chan_byte %02x\n", - chan, FIFO_Num(chan), i, incha, RMW(chan_icba+20), chp->chan_byte); + chsa, FIFO_Num(chsa), i, incha, RMW(chan_icba+20), chp->chan_byte); } else { sim_debug(DEBUG_IRQ, &cpu_dev, "scan_chanx %04x NOT POSTED FIFO #%1x irq %02x inch %06x chan_icba %06x chan_byte %02x\n", - chan, FIFO_Num(chan), i, incha, chan_icba, chp->chan_byte); + chsa, FIFO_Num(chsa), i, incha, chan_icba, chp->chan_byte); } *ilev = i; /* return interrupt level */ irq_pend = 0; /* not pending anymore */ @@ -2914,13 +3009,13 @@ t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc) { return SCPE_IERR; /* no, arg error */ dptr = get_dev(uptr); /* find the device from unit pointer */ if (dptr == NULL) { /* device not found, so error */ - fprintf(stderr, "Set dev no DEVICE cptr %s uptr %p\r\n", cptr, uptr); + sim_printf("Set dev no DEVICE cptr %s uptr %p\r\n", cptr, uptr); return SCPE_IERR; /* error */ } dibp = (DIB *)dptr->ctxt; /* get dib pointer from device struct */ if (dibp == NULL) { /* we need a DIB */ - fprintf(stderr, "Set dev no DIB ptr %s uptr %p\r\n", cptr, uptr); + sim_printf("Set dev no DIB ptr %s uptr %p\r\n", cptr, uptr); return SCPE_IERR; /* no DIB, so error */ } @@ -2942,9 +3037,9 @@ t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc) { dib_unit[ochsa&0x7f00] = NULL; /* clear the channel dib address */ chan &= ~mask; /* remove the unit number */ chsa = chan | (ochsa & mask); /* put in new sa */ - if (chsa != ochsa) { - fprintf(stderr, "Set unit %x new chsa %04x old chsa %04x\r\n", i, chsa, ochsa); - } +// if (chsa != ochsa) { +// sim_printf("Set unit %x new chsa %04x old chsa %04x\r\n", i, chsa, ochsa); +// } tuptr->u3 &= ~UNIT_ADDR_MASK; /* clear old chsa for this unit */ tuptr->u3 |= UNIT_ADDR(chsa); /* set new chsa for this unit */ dib_unit[chan&0x7f00] = dibp; /* set the channel dib address */ diff --git a/SEL32/sel32_clk.c b/SEL32/sel32_clk.c index 5d533bf1..e61ac927 100644 --- a/SEL32/sel32_clk.c +++ b/SEL32/sel32_clk.c @@ -1,6 +1,6 @@ /* sel32_clk.c: SEL 32 Class F IOP processor RTOM functions. - Copyright (c) 2018-2021, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -44,12 +44,11 @@ t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat rtc_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); const char *rtc_desc(DEVICE *dptr); -extern int irq_pend; /* go scan for pending int or I/O */ -extern uint32 INTS[]; /* interrupt control flags */ -extern uint32 SPAD[]; /* computer SPAD */ -extern uint32 M[]; /* system memory */ -extern uint32 outbusy; /* output waiting on timeout */ -extern uint32 inbusy; /* input waiting on timeout */ +extern int irq_pend; /* go scan for pending int or I/O */ +extern uint32 INTS[]; /* interrupt control flags */ +extern uint32 SPAD[]; /* computer SPAD */ +extern uint32 outbusy; /* output waiting on timeout */ +extern uint32 inbusy; /* input waiting on timeout */ int32 rtc_pie = 0; /* rtc pulse ie */ int32 rtc_tps = 60; /* rtc ticks/sec */ @@ -112,7 +111,7 @@ t_stat rtc_srv (UNIT *uptr) #endif /* if clock disabled, do not do interrupts */ if (((rtc_dev.flags & DEV_DIS) == 0) && rtc_pie) { - int lev = 0x13; + int lev = rtc_lvl; sim_debug(DEBUG_CMD, &rtc_dev, "RT Clock mfp INTS[%02x] %08x SPAD[%02x] %08x\n", lev, INTS[lev], lev+0x80, SPAD[lev+0x80]); @@ -127,22 +126,24 @@ t_stat rtc_srv (UNIT *uptr) /* HACK for console I/O stopping */ /* This reduces the number of console I/O stopping errors */ /* need to find real cause of I/O stopping on clock interrupt */ - if ((outbusy==0) && (inbusy==0)) /* skip interrupt if con I/O in busy wait */ + if ((outbusy==0) && (inbusy==0)) { /* skip interrupt if con I/O in busy wait */ INTS[rtc_lvl] |= INTS_REQ; /* request the interrupt */ - else - sim_debug(DEBUG_CMD, &rtc_dev, - "RT Clock int console busy\n"); + irq_pend = 1; /* make sure we scan for int */ + } else { + sim_debug(DEBUG_CMD, &rtc_dev, + "RT Clock int console busy\n"); + } #else INTS[rtc_lvl] |= INTS_REQ; /* request the interrupt */ -#endif irq_pend = 1; /* make sure we scan for int */ +#endif } sim_debug(DEBUG_CMD, &rtc_dev, "RT Clock int INTS[%02x] %08x SPAD[%02x] %08x\n", rtc_lvl, INTS[rtc_lvl], rtc_lvl+0x80, SPAD[rtc_lvl+0x80]); } -// temp = sim_rtcn_calb(rtc_tps, TMR_RTC); /* timer 0 for RTC */ - sim_rtcn_calb(rtc_tps, TMR_RTC); /* timer 0 for RTC */ +// temp = sim_rtcn_calb(rtc_tps, TMR_RTC); /* timer 0 for RTC */ + sim_rtcn_calb(rtc_tps, TMR_RTC); /* timer 0 for RTC */ sim_activate_after(uptr, 1000000/rtc_tps); /* reactivate 16666 tics / sec */ return SCPE_OK; } @@ -243,6 +244,7 @@ t_stat itm_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat itm_reset (DEVICE *dptr); t_stat itm_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat itm_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); +void itm_setup(uint32 ss, uint32 level); const char *itm_desc(DEVICE *dptr); /* Clock data structures @@ -370,6 +372,9 @@ int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level) cmd &= 0x7f; /* just need the cmd */ itm_cmd = cmd; /* save last cmd */ + if (itm_pie == 0) { /* timer enabled? */ + itm_setup(1, level); /* no, initialize it */ + } switch (cmd) { case 0x20: /* stop timer */ /* stop the timer and save the curr value for later */ @@ -637,6 +642,13 @@ int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level) /* level = interrupt level */ void itm_setup(uint32 ss, uint32 level) { + if (ss && itm_pie && (level == itm_lvl)) { /* timer enabled? */ + /* already setup, just return */ + sim_debug(DEBUG_CMD, &itm_dev, + "Intv Timer setup call already enabled int %02x value %08x itm_pie %01x ss %01x\n", + itm_lvl, itm_cnt, itm_pie, ss); + return; + } itm_lvl = level; /* save the interrupt level */ itm_load = 0; /* not loaded */ itm_src = 0; /* use itm for freq */ @@ -645,14 +657,18 @@ void itm_setup(uint32 ss, uint32 level) itm_cnt = 0; /* no count reset value */ sim_cancel (&itm_unit); /* not running yet */ if (ss == 1) { /* starting? */ +#ifdef NOT_HERE_112422 INTS[level] |= INTS_ENAB; /* make sure enabled */ SPAD[level+0x80] |= SINT_ENAB; /* in spad too */ +#endif sim_debug(DEBUG_CMD, &itm_dev, "Intv Timer setup enable int %02x value %08x itm_pie %01x ss %01x\n", itm_lvl, itm_cnt, itm_pie, ss); } else { +#ifdef NOT_HERE_112422 INTS[level] &= ~INTS_ENAB; /* make sure disabled */ SPAD[level+0x80] &= ~SINT_ENAB; /* in spad too */ +#endif sim_debug(DEBUG_CMD, &itm_dev, "Intv Timer setup disable int %02x value %08x itm_pie %01x ss %01x\n", itm_lvl, itm_cnt, itm_pie, ss); diff --git a/SEL32/sel32_com.c b/SEL32/sel32_com.c index 99547523..88d043bc 100644 --- a/SEL32/sel32_com.c +++ b/SEL32/sel32_com.c @@ -1,6 +1,6 @@ /* sel32_com.c: SEL 32 8-Line IOP communications controller - Copyright (c) 2018-2021, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a diff --git a/SEL32/sel32_con.c b/SEL32/sel32_con.c index 5c9b3083..d18ac331 100644 --- a/SEL32/sel32_con.c +++ b/SEL32/sel32_con.c @@ -1,6 +1,6 @@ /* sel32_con.c: SEL 32 Class F IOP processor console. - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -34,8 +34,11 @@ #if NUM_DEVS_CON > 0 -#define UNIT_CON UNIT_IDLE | UNIT_DISABLE +extern uint32 CPUSTATUS; +extern uint32 attention_trap; +#define UNIT_CON UNIT_IDLE | UNIT_DISABLE +#define CON_WAIT 1000 #define CMD u3 /* Held in u3 is the device command and status */ #define CON_INCH 0x00 /* Initialize channel command */ @@ -113,8 +116,8 @@ MTAB con_mod[] = { }; UNIT con_unit[] = { - {UDATA(&con_srvi, UNIT_CON, 0), 0, UNIT_ADDR(0x7EFC)}, /* 0 Input */ - {UDATA(&con_srvo, UNIT_CON, 0), 0, UNIT_ADDR(0x7EFD)}, /* 1 Output */ + {UDATA(&con_srvi, UNIT_CON, 0), CON_WAIT, UNIT_ADDR(0x7EFC)}, /* 0 Input */ + {UDATA(&con_srvo, UNIT_CON, 0), CON_WAIT, UNIT_ADDR(0x7EFD)}, /* 1 Output */ }; DIB con_dib = { @@ -179,52 +182,133 @@ t_stat con_preio(UNIT *uptr, uint16 chan) { /* start an I/O operation */ t_stat con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { - DEVICE *dptr = uptr->dptr; + DEVICE *dptr = uptr->dptr; int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */ + uint16 chsa = GET_UADDR(uptr->CMD); + CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + uint8 ch; if ((uptr->CMD & CON_MSK) != 0) { /* is unit busy */ - sim_debug(DEBUG_EXP, dptr, + sim_debug(DEBUG_CMD, dptr, "con_startcmd unit %01x chan %02x cmd %02x BUSY cmd %02x uptr %p\n", unit, chan, cmd, uptr->CMD, uptr); return SNS_BSY; /* yes, return busy */ } - sim_debug(DEBUG_DETAIL, dptr, - "con_startcmd unit %01x chan %02x cmd %02x enter\n", unit, chan, cmd); + sim_debug(DEBUG_CMD, dptr, + "con_startcmd @%s unit %01x chan %04x cmd %02x CMD %04x enter\n", + (CPUSTATUS & ONIPU)?"IPU":"CPU", unit, chsa, cmd, uptr->CMD); - /* substitute CON_INCH2 for CON_INCH for pprocessing */ + /* substitute CON_INCH2 for CON_INCH for processing */ if (cmd == CON_INCH) cmd = CON_INCH2; /* save INCH command as 0xf0 */ /* process the commands */ switch (cmd & 0xFF) { - case CON_ECHO: /* 0x0a */ /* Read command w/ECHO */ - uptr->CMD |= CON_EKO; /* save echo status */ - case CON_RD: /* 0x02 */ /* Read command */ - atbuf = 0; /* reset attention buffer */ - uptr->CMD |= CON_READ; /* show read mode */ - /* fall through */ - case CON_INCH2: /* 0xf0 */ /* INCH command */ - case CON_RWD: /* 0x37 */ /* TOF and write line */ - case CON_WR: /* 0x01 */ /* Write command */ - case CON_NOP: /* 0x03 */ /* NOP has do nothing */ - case CON_RDBWD: /* 0x0c */ /* Read Backward */ - uptr->SNS |= (SNS_RDY|SNS_ONLN); /* status is online & ready */ + case CON_CON: /* 0x1f */ /* Connect, return Data Set ready */ + uptr->SNS |= (SNS_DSR|SNS_DCD); /* Data set ready, Data Carrier detected */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd CON CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); + uptr->CMD &= LMASK; /* nothing left, command complete */ + return SNS_CHNEND|SNS_DEVEND; + break; + case CON_DIS: /* 0x23 */ /* Disconnect has do nothing */ + uptr->SNS &= ~(SNS_DSR|SNS_DCD); /* Data set not ready */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd DIS CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); + uptr->CMD &= LMASK; /* nothing left, command complete */ + return SNS_CHNEND|SNS_DEVEND; + break; + case CON_SNS: /* 0x04 */ /* Sense */ + /* value 4 is Data Set Ready */ + /* value 5 is Data carrier detected n/u */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd cmd %04x: Cmd Sense %02x\n", chsa, uptr->SNS); + ch = uptr->SNS & 0xff; /* Sense byte 3 */ + if (chan_write_byte(chsa, &ch)) { /* write byte to memory */ + /* write error */ + cmd = 0; /* no cmd now */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd write error unit %02x: CMD %08x read %02x u4 %02x ccw_count %02x\n", + unit, uptr->CMD, ch, uptr->u4, chp->ccw_count); + } + uptr->CMD &= LMASK; /* nothing left, command complete */ + return SNS_CHNEND|SNS_DEVEND; + break; + + /* if input tried from output device, error */ + case CON_RD: /* 0x02 */ /* Read command */ + case CON_ECHO: /* 0x0a */ /* Read command w/ECHO */ + case CON_RDBWD: /* 0x0c */ /* Read Backward */ + if (unit == 1) { + /* if input requested for output device, give error */ + uptr->SNS |= SNS_CMDREJ; /* command rejected */ + uptr->CMD &= LMASK; /* nothing left, command complete */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd Read to output device CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + break; + } + sim_debug(DEBUG_CMD, dptr, + "con_startcmd READ %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); uptr->CMD &= ~CON_MSK; /* remove old CMD */ uptr->CMD |= (cmd & CON_MSK); /* save command */ + if (cmd == CON_ECHO) /* 0x0a */ + uptr->CMD |= CON_EKO; /* save echo status */ + atbuf = 0; /* reset attention buffer */ + uptr->CMD |= CON_READ; /* show read mode */ + uptr->SNS |= (SNS_RDY|SNS_ONLN); /* status is online & ready */ + /* input is polled, so no start needed */ + sim_cancel(uptr); /* stop input poll */ + sim_activate(uptr, 250); /* start us off */ + return SCPE_OK; /* no status change */ + break; + + case CON_RWD: /* 0x37 */ /* TOF and write line */ + case CON_WR: /* 0x01 */ /* Write command */ if (unit == 0) { - sim_cancel(uptr); /* stop input poll */ - sim_activate(uptr, 300); /* start us off */ -// sim_activate(uptr, 1000); /* start us off */ + /* if output requested for input device, give error */ + uptr->SNS |= SNS_CMDREJ; /* command rejected */ + uptr->CMD &= LMASK; /* nothing left, command complete */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd Write to input device CMD %08x chsa %04x cmd = %02x\n", + uptr->CMD, chsa, cmd); + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */ + break; } - else + uptr->SNS |= (SNS_RDY|SNS_ONLN); /* status is online & ready */ + uptr->CMD &= ~CON_MSK; /* remove old CMD */ + uptr->CMD |= (cmd & CON_MSK); /* save command */ /* using value 500 or larger causes diag to fail on 32/27 */ -// sim_activate(uptr, 500); /* start us off */ -// sim_activate(uptr, 200); /* start us off */ - sim_activate(uptr, 30); /* start us off */ + /* using value 230 or larger causes UTX21B to fail on 32/67 */ + /* 32/67 error sequence */ + /* Starting Syslog Daemon */ + /* ioi: sio at 801 failed, cc=2, retry=0 */ + /* panic: ioi: sio - bad cc */ + sim_activate(uptr, 200); /* start us off */ +//fail sim_activate(uptr, 230); /* start us off */ +//fail sim_activate(uptr, 250); /* start us off */ + return SCPE_OK; /* no status change */ + break; + + case CON_INCH2: /* 0xf0 */ /* INCH command */ + case CON_NOP: /* 0x03 */ /* NOP has do nothing */ + uptr->SNS |= (SNS_RDY|SNS_ONLN); /* status is online & ready */ + uptr->CMD &= ~CON_MSK; /* remove old CMD */ + uptr->CMD |= (cmd & CON_MSK); /* save command */ + sim_debug(DEBUG_CMD, dptr, + "con_startcmd @%s INCH/NOP cmd CMD %08x chsa %04x cmd = %02x\n", + (CPUSTATUS & ONIPU)?"IPU":"CPU", uptr->CMD, chsa, cmd); + /* input is polled, so no start needed */ + if (unit == 1) { /* doing output */ + sim_activate(uptr, 250); /* start us off */ + } else { + sim_cancel(uptr); /* stop input poll */ + sim_activate(uptr, 250); /* start us off */ + } return SCPE_OK; /* no status change */ break; @@ -233,7 +317,7 @@ t_stat con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { } /* invalid command */ uptr->SNS |= SNS_CMDREJ; /* command rejected */ - sim_debug(DEBUG_EXP, dptr, + sim_debug(DEBUG_CMD, dptr, "con_startcmd %04x: Invalid command %02x Sense %02x\n", chan, cmd, uptr->SNS); return SNS_CHNEND|SNS_DEVEND|STATUS_PCHK; @@ -259,43 +343,16 @@ t_stat con_srvo(UNIT *uptr) { switch (cmd) { - /* if input tried from output device, error */ - case CON_RD: /* 0x02 */ /* Read command */ - case CON_ECHO: /* 0x0a */ /* Read command w/ECHO */ - case CON_RDBWD: /* 0x0c */ /* Read Backward */ - /* if input requested for output device, give error */ - uptr->SNS |= SNS_CMDREJ; /* command rejected */ - uptr->CMD &= LMASK; /* nothing left, command complete */ - sim_debug(DEBUG_CMD, dptr, - "con_srvo Read to output device CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); - chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* unit check */ - break; - - case CON_CON: /* 0x1f */ /* Connect, return Data Set ready */ - uptr->SNS |= (SNS_DSR|SNS_DCD); /* Data set ready, Data Carrier detected */ - sim_debug(DEBUG_CMD, dptr, - "con_srvo CON CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); - uptr->CMD &= ~CON_MSK; /* remove old CMD */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ - break; - - case CON_DIS: /* 0x23 */ /* Disconnect has do nothing */ - uptr->SNS &= ~(SNS_DSR|SNS_DCD); /* Data set not ready */ - sim_debug(DEBUG_CMD, dptr, - "con_srvo DIS CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); - uptr->CMD &= ~CON_MSK; /* remove old CMD */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ - break; - case CON_INCH2: /* 0xf0 */ /* INCH command */ uptr->CMD &= LMASK; /* nothing left, command complete */ sim_debug(DEBUG_CMD, dptr, - "con_srvo INCH unit %02x: CMD %08x cmd %02x incnt %02x u4 %02x\n", - unit, uptr->CMD, cmd, con_data[unit].incnt, uptr->u4); + "con_srvo INCH unit %02x: CMD %08x cmd %02x incnt %02x u4 %02x inch %06x in2 %06x\n", + unit, uptr->CMD, cmd, con_data[unit].incnt, uptr->u4, mema, M[mema>>2]); /* now call set_inch() function to write and test inch buffer addresses */ /* 1-256 wd buffer is provided for 128 status dbl words */ - tstart = set_inch(uptr, mema, 128); /* new address & 128 entries */ +//TRY tstart = set_inch(uptr, mema, 128); /* new address & 128 entries */ + tstart = set_inch(uptr, mema, 1); /* new address & 128 entries */ if ((tstart == SCPE_MEM) || (tstart == SCPE_ARG)) { /* any error */ /* we have error, bail out */ uptr->SNS |= SNS_CMDREJ; @@ -306,94 +363,21 @@ t_stat con_srvo(UNIT *uptr) { break; } sim_debug(DEBUG_CMD, dptr, - "con_srvo INCH CMD %08x chsa %04x len %02x inch %06x\n", uptr->CMD, chsa, len, mema); + "con_srvo INCH CMD %08x chsa %04x len %02x inch %06x in2 %06x\n", uptr->CMD, chsa, len, mema, M[mema>>2]); /* WARNING, if SNS_DEVEND is not set, diags fail by looping in CON diag */ chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ break; case CON_NOP: /* 0x03 */ /* NOP has do nothing */ - uptr->CMD &= ~CON_MSK; /* remove old CMD */ +//ZZ uptr->CMD &= ~CON_MSK; /* remove old CMD */ + uptr->CMD &= LMASK; /* nothing left, command complete */ sim_debug(DEBUG_CMD, dptr, "con_srvo NOP CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ break; - case CON_SNS: /* 0x04 */ /* Sense */ - /* value 4 is Data Set Ready */ - /* value 5 is Data carrier detected n/u */ - sim_debug(DEBUG_CMD, dptr, - "con_srvo cmd %04x: Cmd Sense %02x\n", chsa, uptr->SNS); - /* value 4 is Data Set Ready */ - /* value 5 is Data carrier detected n/u */ - ch = uptr->SNS & 0xff; /* Sense byte 3 */ - if (chan_write_byte(chsa, &ch)) { /* write byte to memory */ - /* write error */ - cmd = 0; /* no cmd now */ - sim_debug(DEBUG_CMD, dptr, - "con_srvo write error unit %02x: CMD %08x read %02x u4 %02x ccw_count %02x\n", - unit, uptr->CMD, ch, uptr->u4, chp->ccw_count); - uptr->CMD &= LMASK; /* nothing left, command complete */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ - break; - } - uptr->CMD &= LMASK; /* nothing left, command complete */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* good return */ - break; - case CON_RWD: /* 0x37 */ /* TOF and write line */ case CON_WR: /* 0x01 */ /* Write command */ -#ifdef DO_OLDWAY - /* see if write complete */ - if (uptr->CMD & CON_OUTPUT) { - /* write is complete, post status */ - sim_debug(DEBUG_CMD, &con_dev, - "con_srvo write CMD %08x chsa %04x cmd %02x complete\n", - uptr->CMD, chsa, cmd); - uptr->CMD &= ~CON_MSK; /* remove old CMD */ - uptr->CMD &= ~CON_OUTPUT; /* remove output command */ -/*RTC*/ outbusy = 0; /* output done */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */ - break; - } -/*RTC*/ outbusy = 1; /* tell clock output waiting */ - if (chan_read_byte(chsa, &ch) == SCPE_OK) { /* get byte from memory */ - /* Write to device */ - ch &= 0x7f; /* make 7 bit w/o parity */ - dexp = dexp<<8; /* move up last chars */ - dexp |= ch; /* insert new char */ -#ifdef DO_DYNAMIC_DEBUG -// if ((cnt == 3) && (dexp == 0x4458503e)) { /* test for "DXP>" */ - if ((cnt == 13) && (dexp == 0x4E542E48)) { /* test for "NT.H" */ - cpu_dev.dctrl |= (DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ - con_dev.dctrl |= DEBUG_XIO|DEBUG_CMD; -// sim_debug(DEBUG_INST, &cpu_dev, "|con_srvo DXP> received|\n"); - sim_debug(DEBUG_INST, &cpu_dev, "con_srvo CV.INT.H received start debug\n"); - } - if ((cnt == 13) && (dexp == 0x52502E48)) { /* test for "RP.H" */ - /* turn of debug trace because we are already hung */ - sim_debug(DEBUG_INST, &cpu_dev, "con_srvo got CV.TRP.H stopping debug\n"); - cpu_dev.dctrl &= ~(DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ - con_dev.dctrl &= ~(DEBUG_XIO|DEBUG_CMD); - } -#endif - sim_putchar(ch); /* output next char to device */ - sim_debug(DEBUG_CMD, dptr, - "con_srvo write wait %03x CMD %08x chsa %04x cmd %02x byte %d = %02x\n", - 1000, uptr->CMD, chsa, cmd, cnt, ch); - cnt++; /* count chars output */ -//01132022 sim_activate(uptr, 500); /* wait for a while before next write */ - sim_activate(uptr, 50); /* wait for a while before next write */ - break; - } - /* nothing left, finish up */ - cnt = 0; /* zero for next output */ - uptr->CMD |= CON_OUTPUT; /* output command complete */ - sim_debug(DEBUG_CMD, &con_dev, - "con_srvo write wait %03x CMD %08x chsa %04x cmd %02x to complete\n", - 1000, uptr->CMD, chsa, cmd); - sim_activate(uptr, 500); /* wait for a while */ - break; -#else cnt = 0; /* zero count */ /*RTC*/ outbusy = 1; /* tell clock output waiting */ mema = chp->ccw_addr; /* get buffer addr */ @@ -403,16 +387,6 @@ t_stat con_srvo(UNIT *uptr) { ch &= 0x7f; /* make 7 bit w/o parity */ dexp = dexp<<8; /* move up last chars */ dexp |= ch; /* insert new char */ -#ifdef DO_DYNAMIC_DEBUG -// if ((cnt == 3) && (dexp == 0x4458503e)) { /* test for "DXP>" */ - if ((cnt == 3) && (dexp == 0x44454641)) { /* test for "DEFA" */ -// cpu_dev.dctrl |= (DEBUG_INST|DEBUG_IRQ); /* start instruction trace */ - cpu_dev.dctrl |= (DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ -// con_dev.dctrl |= DEBUG_CMD; -// sim_debug(DEBUG_INST, &cpu_dev, "|con_srvo DXP> received|\n"); - sim_debug(DEBUG_INST, &cpu_dev, "|con_srvo DEFA received|\n"); - } -#endif sim_putchar(ch); /* output next char to device */ if (isprint(ch)) sim_debug(DEBUG_CMD, dptr, @@ -433,7 +407,6 @@ t_stat con_srvo(UNIT *uptr) { /*RTC*/ outbusy = 0; /* output done */ chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */ break; -#endif } return SCPE_OK; } @@ -450,29 +423,18 @@ t_stat con_srvi(UNIT *uptr) { uint32 tstart; uint8 ch; t_stat r; - int32 wait_time=10000; switch (cmd) { - /* if output tried to input device, error */ - case CON_RWD: /* 0x37 */ /* TOF and write line */ - case CON_WR: /* 0x01 */ /* Write command */ - /* if input requested for output device, give error */ - uptr->SNS |= SNS_CMDREJ; /* command rejected */ - uptr->CMD &= LMASK; /* nothing left, command complete */ - sim_debug(DEBUG_CMD, dptr, - "con_srvi Write to input device CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); - chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* unit check */ - break; - case CON_INCH2: /* 0xf0 */ /* INCH command */ uptr->CMD &= LMASK; /* nothing left, command complete */ sim_debug(DEBUG_CMD, dptr, - "con_srvi INCH unit %02x: CMD %08x cmd %02x incnt %02x u4 %02x inch %06x\n", - unit, uptr->CMD, cmd, con_data[unit].incnt, uptr->u4, mema); + "con_srvi INCH unit %02x: CMD %08x cmd %02x incnt %02x u4 %02x inch %06x in2 %06x\n", + unit, uptr->CMD, cmd, con_data[unit].incnt, uptr->u4, mema, M[mema>>2]); /* now call set_inch() function to write and test inch buffer addresses */ - tstart = set_inch(uptr, mema, 128); /* new address & 128 entries */ +//TRY tstart = set_inch(uptr, mema, 128); /* new address & 128 entries */ + tstart = set_inch(uptr, mema, 1); /* new address & 128 entries */ if ((tstart == SCPE_MEM) || (tstart == SCPE_ARG)) { /* any error */ /* we have error, bail out */ uptr->SNS |= SNS_CMDREJ; @@ -485,56 +447,21 @@ t_stat con_srvi(UNIT *uptr) { con_data[unit].incnt = 0; /* buffer empty */ uptr->u4 = 0; /* no I/O yet */ sim_debug(DEBUG_CMD, dptr, - "con_srvi INCH CMD %08x chsa %04x len %02x inch %06x\n", uptr->CMD, chsa, len, mema); + "con_srvi INCH CMD %08x chsa %04x len %02x inch %06x in2 %06x\n", uptr->CMD, chsa, len, mema, M[mema>>2]); /* WARNING, if SNS_DEVEND is not set, diags fail by looping in CON diag */ chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ /* drop through to poll input */ break; case CON_NOP: /* 0x03 */ /* NOP has do nothing */ - uptr->CMD &= ~CON_MSK; /* remove old CMD */ +//ZZ uptr->CMD &= ~CON_MSK; /* remove old CMD */ + uptr->CMD &= LMASK; /* nothing left, command complete */ sim_debug(DEBUG_CMD, dptr, "con_srvi NOP CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ /* drop through to poll input */ break; - case CON_CON: /* 0x1f */ /* Connect, return Data Set ready */ - uptr->SNS |= (SNS_DSR|SNS_DCD); /* Data set ready, Data Carrier detected */ - sim_debug(DEBUG_CMD, dptr, - "con_srvi CON CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); - uptr->CMD &= ~CON_MSK; /* remove old CMD */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ - break; - - case CON_DIS: /* 0x23 */ /* Disconnect has do nothing */ - uptr->SNS &= ~(SNS_DSR|SNS_DCD); /* Data set not ready */ - sim_debug(DEBUG_CMD, dptr, - "con_srvi DIS CMD %08x chsa %04x cmd = %02x\n", uptr->CMD, chsa, cmd); - uptr->CMD &= ~CON_MSK; /* remove old CMD */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ - break; - - case CON_SNS: /* 0x04 */ /* Sense */ - sim_debug(DEBUG_CMD, dptr, - "con_srvi cmd %04x: Cmd Sense %02x\n", chsa, uptr->SNS); - /* value 4 is Data Set Ready */ - /* value 5 is Data carrier detected n/u */ - ch = uptr->SNS & 0xff; /* Sense byte 3 */ - if (chan_write_byte(chsa, &ch)) { /* write byte to memory */ - /* write error */ - cmd = 0; /* no cmd now */ - sim_debug(DEBUG_CMD, dptr, - "con_srvi write error unit %02x: CMD %08x read %02x u4 %02x ccw_count %02x\n", - unit, uptr->CMD, ch, uptr->u4, chp->ccw_count); - uptr->CMD &= LMASK; /* nothing left, command complete */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ - break; - } - uptr->CMD &= LMASK; /* nothing left, command complete */ - chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */ - break; - case CON_ECHO: /* 0x0a */ /* read from device w/ECHO */ uptr->CMD |= CON_EKO; /* save echo status */ case CON_RD: /* 0x02 */ /* read from device */ @@ -551,10 +478,6 @@ t_stat con_srvi(UNIT *uptr) { sim_debug(DEBUG_IRQ, dptr, "con_srvi readbuf unit %02x: CMD %08x read %02x incnt %02x u4 %02x len %02x\n", unit, uptr->CMD, ch, con_data[unit].incnt, uptr->u4, chp->ccw_count); -#ifdef DO_DYNAMIC_DEBUG - /* turn on instruction trace */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ -#endif /* process any characters */ if (uptr->u4 != con_data[unit].incnt) { /* input available */ @@ -593,9 +516,6 @@ t_stat con_srvi(UNIT *uptr) { if (uptr->u4 == con_data[unit].incnt) { /* input empty */ uptr->CMD &= ~CON_INPUT; /* no input available */ } -// wait_time = 200; /* process next time */ -// wait_time = 400; /* process next time */ - wait_time = 800; /* process next time */ break; } /* command is completed */ @@ -607,10 +527,6 @@ t_stat con_srvi(UNIT *uptr) { sim_debug(DEBUG_CMD, dptr, "con_srvi read done unit %02x CMD %08x read %02x u4 %02x ccw_count %02x incnt %02x\n", unit, uptr->CMD, ch, uptr->u4, chp->ccw_count, con_data[unit].incnt); -#ifdef DO_DYNAMIC_DEBUG - /* turn on instruction trace */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ -#endif cmd = 0; /* no cmd now */ uptr->CMD &= LMASK; /* nothing left, command complete */ if (uptr->u4 != con_data[unit].incnt) { /* input empty */ @@ -648,10 +564,6 @@ t_stat con_srvi(UNIT *uptr) { sim_debug(DEBUG_CMD, dptr, "con_srvi handle readch unit %02x: CMD %08x read %02x u4 %02x incnt %02x r %x\n", unit, uptr->CMD, ch, uptr->u4, con_data[unit].incnt, r); -#ifdef DO_DYNAMIC_DEBUG - /* turn on instruction trace */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ -#endif /* put char in buffer */ con_data[unit].ibuff[con_data[unit].incnt++] = ch; @@ -669,7 +581,10 @@ t_stat con_srvi(UNIT *uptr) { sim_debug(DEBUG_CMD, dptr, "con_srvi readch unit %02x: CMD %08x read %02x u4 %02x incnt %02x\n", unit, uptr->CMD, ch, uptr->u4, con_data[unit].incnt); - sim_activate(uptr, 30); /* do this again */ +//JB sim_clock_coschedule(uptr, 1000); +//JB sim_activate(uptr, 30); /* do this again */ +//?? sim_activate(uptr, 300); /* do this again */ + sim_activate(uptr, 500); /* do this again */ //01172021 sim_activate(uptr, 400); /* do this again */ // sim_activate(uptr, 800); /* do this again */ return SCPE_OK; @@ -700,7 +615,9 @@ t_stat con_srvi(UNIT *uptr) { con_data[unit].incnt = 0; /* no input data */ } // sim_activate(uptr, wait_time); /* do this again */ - sim_activate(uptr, 400); /* do this again */ +//?? sim_activate(uptr, 400); /* do this again */ + sim_activate(uptr, 500); /* do this again */ +//JB sim_clock_coschedule(uptr, 1000); // sim_activate(uptr, 4000); /* do this again */ return SCPE_OK; } @@ -731,14 +648,10 @@ t_stat con_srvi(UNIT *uptr) { sim_debug(DEBUG_CMD, dptr, "con_srvi readch2 unit %02x: CMD %08x read %02x u4 %02x incnt %02x r %x\n", unit, uptr->CMD, ch, uptr->u4, con_data[unit].incnt, r); -#ifdef DO_DYNAMIC_DEBUG - /* turn off debug trace because we are already hung */ - sim_debug(DEBUG_INST, &cpu_dev, "con_srvi readch3 stopping debug\n"); - cpu_dev.dctrl &= ~(DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ - con_dev.dctrl &= ~(DEBUG_XIO|DEBUG_CMD); -#endif } - sim_activate(uptr, wait_time); /* do this again */ +//X sim_activate(uptr, wait_time); /* do this again */ + sim_clock_coschedule(uptr, 1000); /* continue poll */ +//JBsim_clock_coschedule(uptr, 1000); return SCPE_OK; } @@ -753,7 +666,6 @@ t_stat con_rschnlio(UNIT *uptr) { int cmd = uptr->CMD & CON_MSK; con_ini(uptr, 0); /* reset the unit */ sim_debug(DEBUG_EXP, &con_dev, "con_rschnl chsa %04x cmd = %02x\n", chsa, cmd); -// cpu_dev.dctrl |= (DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ return SCPE_OK; } @@ -795,5 +707,5 @@ t_stat con_haltio(UNIT *uptr) { chsa, cmd, chp->ccw_count); return CC1BIT | SCPE_OK; /* not busy */ } -#endif +#endif /* #if NUM_DEVS_CON > 0 */ diff --git a/SEL32/sel32_cpu.c b/SEL32/sel32_cpu.c index 67a09238..11b06320 100644 --- a/SEL32/sel32_cpu.c +++ b/SEL32/sel32_cpu.c @@ -1,6 +1,6 @@ /* sel32_cpu.c: Sel 32 CPU simulator - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -24,116 +24,88 @@ #include "sel32_defs.h" -/* Concept 32 PSD Mode Trap/Interrupt Priorities */ -/* Relative|Logical |Int Vect|TCW |IOCD|Description */ -/* Priority|Priority|Location|Addr|Addr */ -/* - 080 Power Fail Safe Trap */ -/* - 084 Power On Trap */ -/* - 088 Memory Parity Trap */ -/* - 08C Nonpresent Memory Trap */ -/* - 090 Undefined Instruction Trap */ -/* - 094 Privilege Violation Trap */ -/* - 098 Supervisor Call Trap (SVC) */ -/* - 09C Machine Check Trap */ -/* - 0A0 System Check Trap */ -/* - 0A4 Map Fault Trap */ -/* - 0A8 CALM or Undefined IPU Instruction Trap */ -/* - 0AC Signal CPU or Signal IPU Trap */ -/* - 0B0 Address Specification Trap */ -/* - 0B4 Console Attention Trap */ -/* - 0B8 Privlege Mode Halt Trap */ -/* - 0BC Arithmetic Exception Trap */ -/* - 0C0 Cache Error Trap (V9 Only) */ -/* - 0C4 Demand Page Fault Trap (V6&V9 Only) */ -/* */ -/* 0 00 100 External/software Interrupt 0 */ -/* 1 01 104 External/software Interrupt 1 */ -/* 2 02 108 External/software Interrupt 2 */ -/* 3 03 10C External/software Interrupt 3 */ -/* 4 04 110 704 700 I/O Channel 0 interrupt */ -/* 5 05 114 70C 708 I/O Channel 1 interrupt */ -/* 6 06 118 714 710 I/O Channel 2 interrupt */ -/* 7 07 11C 71C 718 I/O Channel 3 interrupt */ -/* 8 08 120 724 720 I/O Channel 4 interrupt */ -/* 9 09 124 72C 728 I/O Channel 5 interrupt */ -/* A 0A 128 734 730 I/O Channel 6 interrupt */ -/* B 0B 12C 73C 738 I/O Channel 7 interrupt */ -/* C 0C 130 744 740 I/O Channel 8 interrupt */ -/* D 0D 134 74C 748 I/O Channel 9 interrupt */ -/* E 0E 138 754 750 I/O Channel A interrupt */ -/* F 0F 13C 75C 758 I/O Channel B interrupt */ -/* 10 10 140 764 760 I/O Channel C interrupt */ -/* 11 11 144 76C 768 I/O Channel D interrupt */ -/* 12 12 148 774 770 I/O Channel E interrupt */ -/* 13 13 14c 77C 778 I/O Channel F interrupt */ -/* 14 14 150 External/Software Interrupt */ -/* 15 15 154 External/Software Interrupt */ -/* 16 16 158 External/Software Interrupt */ -/* 17 17 15C External/Software Interrupt */ -/* 18 18 160 Real-Time Clock Interrupt */ -/* 19 19 164 External/Software Interrupt */ -/* 1A 1A 1A8 External/Software Interrupt */ -/* 1B 1B 1AC External/Software Interrupt */ -/* 1C 1C 1B0 External/Software Interrupt */ -/* THRU THRU THRU THRU */ -/* 6C 6C 2B0 External/Software Interrupt */ -/* 6D 6D 2B4 External/Software Interrupt */ -/* 6E 6E 2B8 External/Software Interrupt */ -/* 6F 6F 2BC Interval Timer Interrupt */ +extern uint32 sim_idle_ms_sleep(unsigned int); /* wait 1 ms */ -/* IVL ------------> ICB Trap/Interrupt Vector Location points to Interrupt Context Block */ -/* Wd 0 - Old PSD Word 1 points to return location */ -/* Wd 1 - Old PSD Word 2 */ -/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ -/* Wd 3 - New PSD Word 2 */ -/* Wd 4 - CPU Status word at time of interrupt/trap */ -/* Wd 5 - N/U For Traps/Interrupts */ +#ifndef CPUONLY +#ifndef USE_IPU_THREAD +/* running IPU FORK on CPU, n/u in IPU thread */ +int MyIndex; +int PeerIndex; +extern int fork(); +extern int getpid(); +uint32 *M = 0; /* Memory when we have IPU fork */ +struct ipcom *IPC = 0; +#else +/* running IPU thread on CPU, n/u in IPU fork */ +/* this is different than IPU defines */ +extern void *ipu_sim_instr(void *value); +int MyIndex; +int PeerIndex; +pthread_t ipuThread; /* thread structure */ +uint32 M[MAXMEMSIZE] = { 0 }; /* Memory */ +struct ipcom myipc = {0}; +//struct ipcom *IPC = &myipc; /* local structure */ +struct ipcom *IPC = 0; +//uint32 *M = 0; /* Memory when we have thread IPU */ +//extern DEVICE ipu_dev; /* IPU device structure */ +uint32 cpustop = 0; /* to stop reason for IPU */ +#endif +#else +//uint32 *M = 0; /* Memory when we have no IPU */ +uint32 M[MAXMEMSIZE] = { 0 }; /* Memory */ +//struct ipcom *IPC = 0; +#endif -/* IVL ------------> ICB XIO Interrupt Vector Location */ -/* Wd 0 - Old PSD Word 1 points to return location */ -/* Wd 1 - Old PSD Word 2 */ -/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ -/* Wd 3 - New PSD Word 2 */ -/* Wd 4 - Input/Output Command List Address (IOCL) for the Class F I/O CHannel */ -/* Wd 5 - 24 bit real address of the channel status word */ +LOCAL DEVICE* my_dev = &cpu_dev; /* current DEV pointer CPU or IPU */ + +LOCAL uint32 OIR=0; /* Original Instruction register */ +LOCAL uint32 OPSD1=0; /* Original PSD1 */ +LOCAL uint32 OPSD2=0; /* Original PSD2 */ /* CPU registers, map cache, spad, and other variables */ -int cpu_index; /* Current CPU running */ -uint32 PSD[2]; /* the PC for the instruction */ +LOCAL uint32 PSD[2]; /* the PC for the instruction */ #define PSD1 PSD[0] /* word 1 of PSD */ #define PSD2 PSD[1] /* word 2 of PSD */ -uint32 M[MAXMEMSIZE] = { 0 }; /* Memory */ -uint32 GPR[8]; /* General Purpose Registers */ -uint32 BR[8]; /* Base registers */ -uint32 PC; /* Program counter */ -uint32 CC; /* Condition codes, bits 1-4 of PSD1 */ -uint32 CPUSTATUS; /* cpu status word */ -uint32 TRAPSTATUS; /* trap status word */ -uint32 SPAD[256]; /* Scratch pad memory */ -uint32 INTS[128]; /* Interrupt status flags */ -uint32 pad[16]; /* In case of wrong access */ -uint32 CMCR; /* Cache Memory Control Register */ -uint32 SMCR; /* Shared Memory Control Register */ -uint32 CMSMC; /* V9 Cache/Shadow Memory Configuration */ -uint32 CSMCW; /* CPU Shadow Memory Configuration Word */ -uint32 ISMCW; /* IPU Shadow Memory Configuration Word */ -uint32 CCW; /* Computer Configuration Word */ -uint32 CSW = 0; /* Console switches going to 0x780 */ -uint32 BOOTR[8] = {0}; /* Boot registers settings */ -/* CPU mapping cache entries */ +LOCAL uint32 GPR[8]; /* General Purpose Registers */ +LOCAL uint32 BR[8]; /* Base registers */ +LOCAL uint32 BOOTR[8] = {0}; /* Boot registers settings */ +LOCAL uint32 SPAD[256]; /* Scratch pad memory */ +/* IPU mapping cache entries */ /* 32/55 has none */ /* 32/7x has 32 8KW maps per task */ /* Concept 32/27 has 256 2KW maps per task */ /* Concept 32/X7 has 2048 2KW maps per task */ -uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */ -uint32 dummy=0; -uint32 pfault; /* page # of fault from read/write */ -uint32 BPIX=0; /* # pages loaded for O/S */ -uint32 CPIXPL=0; /* highest page loaded for User */ -uint32 CPIX=0; /* CPIX user MPL offset */ -uint32 HIWM=0; /* max maps loaded so far */ -uint32 MODES=0; /* Operating modes, bits 0, 5, 6, 7 of PSD1 */ -uint32 TLB[2048]; /* Translated addresses for each map entry */ +LOCAL uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */ +LOCAL uint32 TLB[2048]; /* Translated addresses for each map entry */ +LOCAL uint32 PC; /* Program counter */ +LOCAL uint32 IR; /* Last Instruction */ +LOCAL uint32 HIWM=0; /* max maps loaded so far */ +LOCAL uint32 BPIX=0; /* # pages loaded for O/S */ +LOCAL uint32 CPIXPL=0; /* highest page loaded for User */ +LOCAL uint32 CPIX=0; /* CPIX user MPL offset */ +LOCAL uint32 CPUSTATUS; /* cpu status word */ +LOCAL uint32 TRAPSTATUS; /* trap status word */ +LOCAL uint32 CC; /* Condition codes, bits 1-4 of PSD1 */ +LOCAL uint32 MODES=0; /* Operating modes, bits 0, 5, 6, 7 of PSD1 */ +LOCAL uint16 OPR; /* Top half of Instruction register */ +LOCAL uint16 OP; /* Six bit instruction opcode */ +LOCAL uint32 INTS[128]; /* Interrupt status flags */ +LOCAL uint32 CMCR; /* Cache Memory Control Register */ +LOCAL uint32 SMCR; /* Shared Memory Control Register */ +LOCAL uint32 CMSMC; /* V9 Cache/Shadow Memory Configuration */ +LOCAL uint32 CSMCW; /* CPU Shadow Memory Configuration Word */ +LOCAL uint32 ISMCW; /* IPU Shadow Memory Configuration Word */ +LOCAL uint32 CCW = 0; /* Computer Configuration Word */ +LOCAL uint32 CSW = 0; /* Console switches going to 0x780 */ +/* end of CPU simh registers */ + +#ifndef CPUONLY +#ifndef USE_IPU_THREAD +LOCAL int pid; /* our PID */ +#endif +#endif +LOCAL uint32 pfault; /* page # of fault from read/write */ + /* bits 0-4 are bits 0-4 from map entry */ /* bit 0 valid */ /* bit 1 p1 write access if set */ @@ -146,45 +118,36 @@ uint32 TLB[2048]; /* Translated addresses for each map /* bits 8-18 has map reg contents for this page (Map << 13) */ /* bit 19-31 is zero for page offset of zero */ -uint32 dummy2=0; -uint8 wait4int = 0; /* waiting for interrupt if set */ -int32 irq_auto = 0; /* auto reset interrupt processing flag */ +LOCAL uint8 wait4int = 0; /* waiting for interrupt if set */ +#ifndef CPUONLY +LOCAL uint8 wait4sipu = 0; /* waiting for sipu in IPU if set */ +#endif /* define traps */ -uint32 TRAPME = 0; /* trap to be executed */ -uint32 attention_trap = 0; /* set when trap is requested */ - -uint32 RDYQIN; /* fifo input index */ -uint32 RDYQOUT; /* fifo output index */ -uint32 RDYQ[128]; /* channel ready queue */ -uint8 waitqcnt = 0; /* # instructions before start */ - -struct InstHistory -{ - uint32 opsd1; /* original PSD1 */ - uint32 opsd2; /* original PSD2 */ - uint32 npsd1; /* new PSD1 after instruction */ - uint32 npsd2; /* new PSD2 after instruction */ - uint32 oir; /* the instruction itself */ - uint32 modes; /* current cpu mode bits */ - uint32 reg[16]; /* regs/bregs for operation */ -}; +LOCAL uint32 TRAPME = 0; /* trap to be executed */ +LOCAL uint32 attention_trap = 0; /* set when trap is requested */ /* forward definitions */ +void* create_shared_memory(size_t size) ; 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); +#ifdef DEFINE_IPU_MODELS +t_stat cpu_set_ipu(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat cpu_clr_ipu(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat cpu_show_ipu(FILE *st, UNIT *uptr, int32 val, CONST void *desc); +#endif t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc); t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc); uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev); t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); const char *cpu_description (DEVICE *dptr); -t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access); -t_stat load_maps(uint32 thepsd[2], uint32 lmap); -t_stat read_instruction(uint32 thepsd[2], uint32 *instr); -t_stat Mem_read(uint32 addr, uint32 *data); -t_stat Mem_write(uint32 addr, uint32 *data); +LOCAL t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access); +LOCAL t_stat load_maps(uint32 thepsd[2], uint32 lmap); +LOCAL t_stat read_instruction(uint32 thepsd[2], uint32 *instr); +LOCAL t_stat Mem_read(uint32 addr, uint32 *data); +LOCAL t_stat Mem_write(uint32 addr, uint32 *data); /* external definitions */ extern t_stat checkxio(uint16 addr, uint32 *status); /* XIO check in chan.c */ @@ -200,7 +163,7 @@ extern uint32 scan_chan(uint32 *ilev); /* go scan for I/O int p extern uint32 cont_chan(uint16 chsa); /* continue channel program */ extern uint16 loading; /* set when doing IPL */ extern int fprint_inst(FILE *of, uint32 val, int32 sw); /* instruction print function */ -extern int irq_pend; /* go scan for pending interrupt */ +LOCAL int irq_pend = 0; /* go scan for pending interrupt */ extern void rtc_setup(uint32 ss, uint32 level); /* tell rtc to start/stop */ extern void itm_setup(uint32 ss, uint32 level); /* tell itm to start/stop */ extern int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level); /* read/write the interval timer */ @@ -226,9 +189,9 @@ extern uint32 s_normfw(uint32 mem, uint32 *cc); extern t_uint64 s_normfd(t_uint64 mem, uint32 *cc); /* History information */ -int32 hst_p = 0; /* History pointer */ -int32 hst_lnt = 0; /* History length */ -struct InstHistory *hst = NULL; /* History stack */ +LOCAL int32 hst_p = 0; /* History pointer */ +LOCAL int32 hst_lnt = 0; /* History length */ +LOCAL struct InstHistory *hst = NULL; /* History stack */ /* CPU data structures @@ -261,7 +224,6 @@ UNIT cpu_unit = }; REG cpu_reg[] = { - {HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT}, {BRDATAD(PSD, PSD, 16, 32, 2, "Program Status Doubleword"), REG_FIT}, {BRDATAD(GPR, GPR, 16, 32, 8, "Index registers"), REG_FIT}, {BRDATAD(BR, BR, 16, 32, 8, "Base registers"), REG_FIT}, @@ -269,6 +231,8 @@ REG cpu_reg[] = { {BRDATAD(SPAD, SPAD, 16, 32, 256, "CPU Scratchpad memory"), REG_FIT}, {BRDATAD(MAPC, MAPC, 16, 32, 1024, "CPU map cache"), REG_FIT}, {BRDATAD(TLB, TLB, 16, 32, 2048, "CPU Translation Lookaside Buffer"), REG_FIT}, + {HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT}, + {HRDATAD(IR, IR, 32, "Last Instruction Loaded"), REG_FIT}, {HRDATAD(HIWM, HIWM, 32, "Max Maps Loaded"), REG_FIT}, {HRDATAD(BPIX, BPIX, 32, "# Maps Loaded for O/S"), REG_FIT}, {HRDATAD(CPIXPL, CPIXPL, 32, "Maximum Map # Loaded for User"), REG_FIT}, @@ -277,6 +241,8 @@ REG cpu_reg[] = { {HRDATAD(TRAPSTATUS, TRAPSTATUS, 32, "TRAP Status Word"), REG_FIT}, {HRDATAD(CC, CC, 32, "Condition Codes"), REG_FIT}, {HRDATAD(MODES, MODES, 32, "Mode bits"), REG_FIT}, + {HRDATAD(OPR, OPR, 16, "Top half of Instruction Register"), REG_FIT}, + {HRDATAD(OP, OP, 16, "Six bit Instruction Opcode"), REG_FIT}, {BRDATAD(INTS, INTS, 16, 32, 128, "Interrupt Status"), REG_FIT}, {HRDATAD(CMCR, CMCR, 32, "Cache Memory Control Register"), REG_FIT}, {HRDATAD(SMCR, SMCR, 32, "Shared Memory Control Register"), REG_FIT}, @@ -285,9 +251,11 @@ REG cpu_reg[] = { {HRDATAD(ISMCW, ISMCW, 32, "V9 IPU Shadow Memory Configuration Word"), REG_FIT}, {HRDATAD(CCW, CCW, 32, "Computer Configuration Word"), REG_FIT}, {HRDATAD(CSW, CSW, 32, "Console Switches"), REG_FIT}, +#ifdef NOT_USED {BRDATAD(RDYQ, RDYQ, 16, 32, 128, "Channel Program Completon Status"), REG_FIT}, {HRDATAD(RDYQIN, RDYQIN, 32, "RDYQ input index"), REG_FIT}, {HRDATAD(RDYQOUT, RDYQOUT, 32, "RDYQ output index"), REG_FIT}, +#endif {NULL} }; @@ -312,6 +280,14 @@ MTAB cpu_mod[] = { {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"}, +#ifdef DEFINE_IPU_MODELS + {UNIT_MODEL, MODEL(MODEL_6780), "32/6780", "32/6780", NULL, NULL, NULL, "Concept 32/6780"}, + {UNIT_MODEL, MODEL(MODEL_7780), "32/7780", "32/7780", NULL, NULL, NULL, "Concept 32/7780"}, + {UNIT_MODEL, MODEL(MODEL_8780), "32/8780", "32/8780", NULL, NULL, NULL, "Concept 32/8780"}, + {UNIT_MODEL, MODEL(MODEL_9780), "32/9780", "32/9780", NULL, NULL, NULL, "Concept 32/9780"}, + {UNIT_MODEL, MODEL(MODEL_V6IPU), "V6/IPU", "V6/IPU", NULL, NULL, NULL, "Concept V6 w/IPU"}, + {UNIT_MODEL, MODEL(MODEL_V9IPU), "V9/IPU", "V9/IPU", NULL, NULL, NULL, "Concept V9 w/IPU"}, +#endif { /* MTAB table layout for cpu memory size */ /* {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &cpu_set_size}, */ @@ -338,6 +314,10 @@ MTAB cpu_mod[] = { {MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL}, {MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist}, +#ifdef DEFINE_IPU_MODELS + {MTAB_XTD|MTAB_VDV, 0, "IPU", "USEIPU", &cpu_set_ipu, &cpu_show_ipu}, + {MTAB_XTD|MTAB_VDV, 0, "NULL", "NOIPU", &cpu_clr_ipu, NULL}, +#endif {0} }; @@ -396,7 +376,7 @@ DEVICE cpu_dev = { #define BT 0x4000 /* Branch taken, no PC incr */ #define SF 0x8000 /* Special flag */ -int nobase_mode[] = { +LOCAL int nobase_mode[] = { /* 00 04 08 0C */ /* 00 ANR, ORR, EOR */ HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, @@ -462,7 +442,7 @@ int nobase_mode[] = { ADR, RR|SD|WRD, ADR, IMM, }; -int base_mode[] = { +LOCAL int base_mode[] = { /* 00 04 08 0C */ /* 00 AND, OR, EOR */ HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, @@ -528,98 +508,92 @@ int base_mode[] = { ADR, RR|SD|WRD, ADR, IMM, }; -/* Map image descriptor 32/77 */ -/* |--------------------------------------| */ -/* |0|1|2|3 4 5 6|7 8 9 10 11 12 13 14 15| */ -/* |N|V|P| n/u | 9 bit map block entry | */ -/* |U| | | | 32kb/block | */ -/* | | 32 8kb maps per task | */ -/* | | 1 mb address space | */ -/* |--------------------------------------| */ - -/* Map image descriptor 32/27 */ -/* |--------------------------------------| */ -/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */ -/* |V|P|P|P|P| 11 bit map block entry | */ -/* | |1|2|3|4| 8kb/block | */ -/* | | 256 8kb maps per task | */ -/* | | 2 mb address space | */ -/* |--------------------------------------| */ - -/* Map image descriptor 32/67, 32/87, 32/97 */ -/* |--------------------------------------| */ -/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */ -/* |V|P|P|P|P| 11 bit map block entry | */ -/* | |1|2|3|4| 2kb/block | */ -/* | | 2048 8kb maps per task | */ -/* | | 16 mb address space | */ -/* |--------------------------------------| */ -/* BIT 0 = 0 Invalid map block (page) entry */ -/* = 1 Valid map block (page) entry */ -/* 1 = 0 000-7ff of 8kb page is not write protected */ -/* = 1 000-7ff of 8kb page is write protected */ -/* 2 = 0 800-fff of 8kb page is not write protected */ -/* = 1 800-fff of 8kb page is write protected */ -/* 3 = 0 1000-17ff of 8kb page is not write protected */ -/* = 1 1000-17ff of 8kb page is write protected */ -/* 4 = 0 1800-1fff of 8kb page is not write protected */ -/* = 1 1800-1fff of 8kb page is write protected */ -/* 5-15 = 11 most significant bits of the 24 bit real address for page */ - -/* Map image descriptor V6 & V9 */ -/* |--------------------------------------| */ -/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */ -/* |V|P|P|M|M| 11 bit map block entry | */ -/* | |1|2|M|A| 2kb/map | */ -/* | | 2048 8kb maps per task | */ -/* | | 16 mb address space | */ -/* |--------------------------------------| */ -/* BIT 0 = 0 Invalid map block (page) entry */ -/* = 1 Valid map block (page) entry */ -/* */ -/* PSD 1 BIT 0 - Map Bit 1 - Map Bit 2 - Access state */ -/* Priv Bits with ECO for Access Protection change */ -/* 0 0 0 No access allowed to page */ -/* 0 0 1 No access allowed to page */ -/* 0 1 0 Read/Write/Execute access */ -/* 0 1 1 Read/Execute access only */ -/*O/S*/ -/* 1 0 0 Read/Write/Execute access */ -/* 1 0 1 Read/Execute access only */ -/* 1 1 0 Read/Write/Execute access */ -/* 1 1 1 Read/Execute access only */ -/* Priv Bits without ECO for Access Protection change */ -/* 0 0 0 No access allowed to page */ -/* 0 0 1 Read/Execute access only */ -/* 0 1 0 Read//Execute access only */ -/* 0 1 1 Read/Write/Execute access */ -/*O/S*/ -/* 1 0 0 Read/Write/Execute only */ -/* 1 0 1 Read/Execute access only */ -/* 1 1 0 Read/Write/Execute access */ -/* 1 1 1 Read/Write/Execute access */ -/* */ -/* BIT 3 = 0 (MM) A first write (modify) to the map block (page) has not occurred */ -/* = 1 (MM) A first write (modify) to the map block (page) has occurred */ -/* BIT 4 = 0 (MA) A first read or write (access) to the map block (page) has not occurred */ -/* = 1 (MA) A first read or write (access) to the map block (page) has occurred */ -/* 5-15 = 11 most significant bits of the 24 bit real address for page */ - -/* Note */ -/* If a map is valid, a MAP (page) hit occurs and logical to physical translation occures */ -/* If the map is not valid, a demand MAP (page) fault occures and the faulting page is provided */ -/* P1 and P2 are used with Bit 0 of PSD to define the access rights */ -/* A privilege violation trap occurres if access it denied */ -/* Bits 5-15 contain the 11 most-significant bits of the physical address */ -/* MSD 0 page limit is used to verify access to O/S pages */ -/* CPIXPL page limit is used to verify access to user pages and page faults */ -/* CPIX CPIX of user MPL offset */ -/* Access to pages outside the limit registers results in a map fault */ - #define MAX32 32 /* 32/77 map limit */ #define MAX256 256 /* 32/27 and 32/87 map limit */ #define MAX2048 2048 /* 32/67, V6, and V9 map limit */ +#ifdef DEBUG4IPU +/* Dump instruction history */ +static void DumpHist() +{ + /* dump instruction history */ +// cpu_show_hist(stdout, (UNIT *)0, (int32)0, (void *)0); +// fflush(stdout); + cpu_show_hist(sim_deb, (UNIT *)0, (int32)0, (void *)0); + fflush(sim_deb); +} +#endif + +#ifdef USE_POSIX_SEM +LOCAL void set_simsem() +{ + if (IPC != 0) { + if (sem_trywait((sem_t *)&(IPC->simsem)) == 0) { + IPC->pass[MyIndex]++; + } else { + IPC->wait[MyIndex]++; + sem_wait((sem_t *)&(IPC->simsem)); + IPC->pass[MyIndex]++; + } + } +} + +LOCAL void clr_simsem() +{ + // in case simsem > 0 the peer process has broken the semaphore + if (IPC) { + sem_post((sem_t *)&(IPC->simsem)); + } +} +#else +/* use pthread mutexs */ +LOCAL void lock_mutex() +{ + if (IPC != 0) { + if (pthread_mutex_trylock((pthread_mutex_t *)&(IPC->mutex)) == 0) { + IPC->pass[MyIndex]++; + } else { + IPC->wait[MyIndex]++; + pthread_mutex_lock((pthread_mutex_t *)&(IPC->mutex)); + IPC->pass[MyIndex]++; + } + } +} + +LOCAL void unlock_mutex() +{ + if (IPC) { + pthread_mutex_unlock((pthread_mutex_t *)&(IPC->mutex)); + } +} +#endif + +#ifdef NOT_USED +/* this function is used to extract mode bits from PSD 1 & 2 */ +LOCAL uint32 set_modes(uint32 psd[2]) +{ + uint32 modes = 0; + modes = psd[0] & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + + if (psd[1] & MAPBIT) /* is bit 0 of PSD2 set, we are mapped */ + modes |= MAPMODE; /* set mapped mode */ + + if ((psd[1] & RETBBIT) == 0) { /* is it retain blocking state, bit 48(15) set */ + /* retain blocking state is off, use bit 49(16) to set new blocking state */ + if (psd[1] & SETBBIT) { /* no, is it set blocking state bit 49(16) set*/ + /* new blocking state is blocked when bits 48=0 & bit 49=1 */ + modes |= BLKMODE; /* set blocked mode */ + } + } else { + /* set retained blocking state in PSD2 */ + if (SPAD[0xf9] & BIT24) { /* see if old mode is blocked in CPUSTATUS */ + modes |= BLKMODE; /* set blocked mode */ + } + } + return modes; +} +#endif + /* set up the map registers for the current task in the cpu */ /* the PSD bpix and cpix are used to setup the maps */ /* return non-zero if mapping error */ @@ -629,14 +603,14 @@ int base_mode[] = { /* The RMR and WMR macros are used to read/write the MAPC cache registers */ /* RMR(addr) or WMR(addr, data) where addr is a half word alligned address */ /* We will only get here if the retain maps bit is not set in PSD word 2 */ -t_stat load_maps(uint32 thepsd[2], uint32 lmap) +LOCAL t_stat load_maps(uint32 thepsd[2], uint32 lmap) { uint32 num, sdc, spc, onlyos=0; uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl; uint32 cpix, bpix, i, j, map, osmsdl, osmidl; uint32 MAXMAP = MAX2048; /* default to 2048 maps */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "Load Maps Entry PSD %08x %08x STATUS %08x lmap %1x CPU Mode %2x\n", thepsd[0], thepsd[1], CPUSTATUS, lmap, CPU_MODEL); @@ -658,7 +632,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* diags want the mpl entries checked to make sure valid dbl wowrd address */ if (mpl & 0x7) { /* test for double word address */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MPL not on double word boundry %06x\n", mpl); TRAPSTATUS |= BIT20; /* set bit 20 of trap status */ return MAPFLT; /* not dbl bound, map fault error */ @@ -666,7 +640,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* check if valid real address */ if ((mpl == 0) || !MEM_ADDR_OK(mpl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE7 %06x mpl %06x invalid\n", MEMSIZE, mpl); TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ @@ -684,7 +658,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* check for valid bpix msdl addr */ if (!MEM_ADDR_OK(bpixmsdl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE8 %06x bpix msdl %08x invalid\n", MEMSIZE, bpixmsdl); return NPMEM; /* no, none present memory error */ @@ -694,7 +668,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) msdl = bpixmsdl & MASK24; /* get 24 bit real address of msdl */ /* check for valid msdl addr */ if (!MEM_ADDR_OK(msdl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE9 %06x msdl %08x invalid\n", MEMSIZE, msdl); return NPMEM; /* no, none present memory error */ } @@ -706,7 +680,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* check for valid midl addr */ if (!MEM_ADDR_OK(midl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZEa %06x midl %08x invalid\n", MEMSIZE, midl); return NPMEM; /* no, none present memory error */ } @@ -727,7 +701,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* now load cpix maps */ /* check for valid cpix msdl addr */ if (MEM_ADDR_OK(cpixmsdl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZEb %06x cpix msdl %08x invalid\n", MEMSIZE, cpixmsdl); return NPMEM; /* no, none present memory error */ } @@ -736,7 +710,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) msdl = cpixmsdl & 0xffffff; /* get 24 bit real address of msdl */ /* check for valid msdl addr */ if (!MEM_ADDR_OK(msdl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZEc %06x msdl %08x invalid\n", MEMSIZE, msdl); return NPMEM; /* no, none present memory error */ } @@ -748,7 +722,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* check for valid midl addr */ if (!MEM_ADDR_OK(midl & MASK24)) { /* see if in memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZEd %06x midl %08x invalid\n", MEMSIZE, midl); return NPMEM; /* no, none present memory error */ } @@ -800,7 +774,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* diags want the mpl entries checked to make sure valid dbl word address */ if (mpl & 0x7) { /* test for double word address */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MPL not on double word boundry %06x\n", mpl); if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT6; /* set bit 6 of trap status */ @@ -812,7 +786,7 @@ t_stat load_maps(uint32 thepsd[2], uint32 lmap) /* check if valid real address */ mpl &= MASK24; /* clean mpl address */ if (!MEM_ADDR_OK(mpl)) { /* see if in our real memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE1 %06x mpl %06x invalid\n", MEMSIZE, mpl); npmem: BPIX = 0; /* no os maps loaded */ @@ -826,11 +800,13 @@ npmem: } /* output O/S and User MPL entries */ - sim_debug(DEBUG_DETAIL, &cpu_dev, +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_CMD, my_dev, "#MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix, RMW(cpix+mpl), RMW(cpix+mpl+4)); - sim_debug(DEBUG_DETAIL, &cpu_dev, +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_CMD, my_dev, "MEMORY2 %06x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n", MEMSIZE, BPIX, cpix, CPIX, CPIXPL, HIWM); @@ -861,9 +837,9 @@ npmem: loados: /* merge point for loading O/S first */ /* to be followed by user maps */ /* the retain bit is not set so load the O/S */ - if (spc > MAXMAP) { - sim_debug(DEBUG_TRAP, &cpu_dev, - "load_maps bad O/S page count %04x, map fault\n", spc); + if ((osmidl == 0) || (spc > MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps bad O/S map count %04x, map fault\n", spc); nomaps: /* Bad map load count specified. */ BPIX = 0; /* no os maps loaded */ @@ -880,7 +856,7 @@ nomaps: /* we have a valid count, load the O/S map list address */ osmsdl &= MASK24; /* get 24 bit real address from mpl 0 wd2 */ if (!MEM_ADDR_OK(osmsdl)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE2 %06x os page list address %06x invalid\n", MEMSIZE, osmsdl); goto npmem; /* non present memory trap */ @@ -892,12 +868,12 @@ nomaps: /* see if map overflow */ if (num >= MAXMAP) { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps O/S page count overflow %04x, map fault\n", num); goto nomaps; /* map overflow, map fault trap */ } if (!MEM_ADDR_OK(pad)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE3 %06x os page address %06x invalid\n", MEMSIZE, pad); goto npmem; /* non present memeory trap */ @@ -943,7 +919,7 @@ nomaps: /* no retain bit, load user maps only, or after O/S */ /* validate O/S map count */ if (spc > MAXMAP) { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps bad O/S page count %04x, map fault\n", spc); goto nomaps; /* we have error, make way out */ } @@ -974,12 +950,12 @@ loaduser: HIWM = num; /* set new high water mark */ CPIXPL = 0; /* no user pages */ if ((midl & BIT0) && (spc == 0)) { /* see if the user had borrow bit on */ - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "load_maps @loaduser num %04x BPIX loaded %04x load done\n", num, BPIX); return ALLOK; /* all cache is loaded, return OK */ } else { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps map overflow BPIX %04x count %04x, map fault\n", BPIX, spc); goto nomaps; /* we have error, make way out */ } @@ -991,7 +967,7 @@ loaduser: /* This test fails cn.mmm diag at test 46, subtest 2 with unexpected error */ /* Do this test if we are a LMAP instruction and not a 32/27 or 32/87 */ if (lmap && !MEM_ADDR_OK(msdl)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE4 %06x user page list address %06x invalid\n", MEMSIZE, msdl); if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { @@ -1006,7 +982,7 @@ loaduser: /* it is OK here to have no O/S maps loaded, num can be 0 */ if ((spc > MAXMAP) || ((spc+BPIX) > MAXMAP)) { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps bad User page count %04x num %04x bpix %04x, map fault\n", spc, num, BPIX); /* Bad map load count specified. */ @@ -1026,7 +1002,7 @@ loaduser: /* Load maps for 32/27 aand 32/87 */ if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) { - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "load_maps Processing 32/27 & 32/87 Model# %02x\n", CPU_MODEL); /* handle non virtual page loading or diag LMAP instruction */ @@ -1037,14 +1013,14 @@ loaduser: /* see if map overflow */ if (num >= MAXMAP) { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps User page count overflow %04x, map fault\n", num); TRAPSTATUS |= BIT16; /* set bit 16 of trap status */ TRAPSTATUS |= (BIT5|BIT9); /* set bit 5 of trap status */ goto nomaps; /* map overflow, map fault trap */ } if (!MEM_ADDR_OK(pad)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE5 %06x User page address %06x invalid\n", MEMSIZE, pad); goto npmem; /* non present memeory trap */ @@ -1064,7 +1040,7 @@ loaduser: WMR((num<<1), map); /* store map unmodified into cache */ } if (num == 0) { /* see if any maps loaded */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps1 No maps loaded %04x, map fault\n", num); goto nomaps; /* return map fault error */ } @@ -1078,7 +1054,7 @@ loaduser: } /**************END-OF-NON-VIRTUAL-USER-MAPPING-FOR-27-87************/ - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "load_maps Processing 32/67 & 32/97 Model# %02x\n", CPU_MODEL); /* handle load on memory access case for 67, 97, V6 & V9 */ @@ -1092,7 +1068,7 @@ loaduser: map = RMH(pad); /* get page descriptor from memory */ TLB[num] = 0; /* clear the TLB for non valid maps */ if ((num < 0x20) || (num > (spc+BPIX) - 0x10)) - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "UserV pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n", pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000, TLB[num], MAPC[num/2]); @@ -1102,7 +1078,7 @@ loaduser: /* only do the following tests for LMAP instruction, not LPSDCM */ /* see if map overflow */ if (num >= MAXMAP) { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps User page count overflow %04x, map fault\n", num); if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= (BIT5|BIT9); /* set bit 5/9 of trap status */ @@ -1112,7 +1088,7 @@ loaduser: } if (!MEM_ADDR_OK(pad)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps MEM SIZE6 %06x User page address %06x non present\n", MEMSIZE, pad); goto npmem; /* non present memeory trap */ @@ -1129,14 +1105,14 @@ loaduser: } if ((num < 0x20) || (num > (spc+BPIX) - 0x10)) - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "UserV2 pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n", pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000, TLB[num], MAPC[num/2]); } if (num == 0) { /* see if any maps loaded */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "load_maps2 No maps loaded %04x, map fault\n", num); goto nomaps; } @@ -1157,10 +1133,11 @@ loaduser: * For 67, 97, V6, & V9 return all protection bits. * Addr is a byte address. */ -t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) +LOCAL t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) { - uint32 word, index, map, raddr, mpl, offset; + uint32 word, index, map, raddr, mpl, offset; uint32 nix, msdl, mix; + uint32 MAXMAP = MAX2048; /* default to 2048 maps */ *prot = 0; /* show unprotected memory as default */ /* unmapped mode is unprotected */ @@ -1168,6 +1145,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) /*****************START-7X-ADDRESS-PROCESSING****************/ /* see what machine we have */ if (CPU_MODEL < MODEL_27) { + MAXMAP = MAX32; /* 32 maps for 32/77 */ /* 32/7x machine with 8KW maps */ if (MODES & EXTDBIT) word = addr & 0xfffff; /* get 20 bit logical word address */ @@ -1233,14 +1211,28 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) mpl = SPAD[0xf3] & MASK24; /* get 24 bit dbl wd mpl from spad address */ + /* set maximum maps for 32/27 and 32/87 processors */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) + MAXMAP = MAX256; /* only 256 2KW (8kb) maps */ + +#if 0 + // FIXME trapstatus bits + if ((mpl == 0) || (RMW(mpl) == 0) || ((RMW(mpl) & MASK16) >= MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr Bad MPL Count or Memory Address for O/S MPL %06x MPL[0] %04x MPL[1] %06x\n", + mpl, RMW(mpl), RMW(mpl+4)); + return MACHINECHK_TRAP; /* diags want machine check error */ + } +#endif + /* did not get expected machine check trap for */ /* 27, 87, 67 in test 37/0 if code removed */ /* unexpected machine check trap for 67 in test 37/0 cn.mmm */ /* now check the O/S midl pointer for being valid */ /* we may want to delay checking until we actually use it */ if (!MEM_ADDR_OK((RMW(mpl+4) & MASK24))) { /* check OS midl */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "RealAddr Non Present Memory O/S msdl MPL %06x MPL[1] %06x\n", + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr Bad MPL Memory Address O/S msdl MPL %06x MPL[1] %06x\n", mpl, RMW(mpl+4)); if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) { @@ -1266,11 +1258,31 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) index = (word >> 13) & 0x7ff; /* get 11 bit page value */ offset = word & 0x1fff; /* get 13 bit page offset */ + //FIXME 112522 + if (MODES & MAPMODE) { + uint32 mpl = SPAD[0xf3]; /* get mpl from spad address */ + uint32 cpix = CPIX; /* get cpix 11 bit offset from psd wd 2 */ + uint32 midl = RMW(mpl+cpix); /* get midl entry for given user cpix */ + uint32 spc = midl & MASK16; /* get 16 bit user segment description count */ + /* output O/S and User MPL entries */ + sim_debug(DEBUG_DETAIL, my_dev, +// sim_debug(DEBUG_TRAP, my_dev, + "+MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", + MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix, + RMW(cpix+mpl), RMW(cpix+mpl+4)); + sim_debug(DEBUG_DETAIL, my_dev, +// sim_debug(DEBUG_TRAP, my_dev, + "+MEMORY spc %x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n", + spc, BPIX, cpix, CPIX, CPIXPL, HIWM); + } + /* make sure map index is valid */ - if (index >= (BPIX + CPIXPL)) { - sim_debug(DEBUG_TRAP, &cpu_dev, - "RealAddr %06x word %06x loadmap gets mapfault index %04x B(%x)+C(%x) %04x\n", + if ((index >= (BPIX + CPIXPL)) || (index >= MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr %.6x word %06x loadmap gets mapfault index %04x B(%x)+C(%x) %04x\n", word, addr, index, BPIX, CPIXPL, BPIX+CPIXPL); + fflush(stdout); + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= (BIT5|BIT9); /* set bit 5/9 of trap status */ else @@ -1286,7 +1298,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) raddr = TLB[index]; /* get the base address & bits */ if (!MEM_ADDR_OK(RMW(mpl+CPIX+4) & MASK24)) { /* check user midl */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "RealAddr 27 & 87 map fault index %04x B+C %04x map %04x TLB %08x\n", index, BPIX+CPIXPL, map, TLB[index]); // 32/27 & 32/87 want MACHINECHK for test 37/1 in CN.MMM @@ -1295,7 +1307,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) } if (((map & 0x8000) == 0) || ((raddr & BIT0) == 0)) { /* see if valid map */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "RealAddr loadmap 0a map fault index %04x B+C %04x map %04x TLB %08x\n", index, BPIX+CPIXPL, map, TLB[index]); TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ @@ -1305,7 +1317,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) // needed for 32/27 & 32/87 /* check if valid real address */ if (!MEM_ADDR_OK(raddr & MASK24)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "RealAddr loadmap 0c non present memory fault addr %06x raddr %08x index %04x\n", word, raddr, index); TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ @@ -1321,7 +1333,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) if ((BIT1 >> offset) & raddr) { /* is 1/4 page write protected */ *prot = 1; /* return memory write protection status */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "RealAddrRa address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n", word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot); return ALLOK; /* all OK, return instruction */ @@ -1338,7 +1350,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) raddr = TLB[index]; /* get the base address & bits */ /* check if valid real address */ if (!MEM_ADDR_OK(raddr & MASK24)) { /* see if address is within our memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "RealAddr loadmap 2a non present memory fault addr %08x raddr %08x index %04x\n", addr, raddr, index); if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { @@ -1367,7 +1379,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) if ((BIT1 >> offset) & raddr) { /* is 1/4 page write protected */ *prot = 1; /* return memory write protection status */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "RealAddrR address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n", word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot); return ALLOK; /* all OK, return instruction */ @@ -1381,21 +1393,21 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) else *prot = offset; /* return memory write protection status */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "RealAddrX address %06x, TLB %06x MAPC[%03x] %08x wprot %02x prot %02x\n", word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot); return ALLOK; /* all OK, return instruction */ } /* Hit bit is off in TLB, so lets go get some maps */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "$MEMORY %06x HIT MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), CPIX, RMW(CPIX+mpl), RMW(CPIX+mpl+4)); /* check user msdl address now that we are going to access it */ msdl = RMW(mpl+CPIX+4); /* get msdl entry for given CPIX */ if (!MEM_ADDR_OK(msdl & MASK24)) { /* check user midl */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "RealAddr User CPIX Non Present Memory User msdl %06x CPIX %04x\n", msdl, CPIX); @@ -1444,7 +1456,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) else mix = nix-BPIX; /* get map index in memory */ map = RMH(msdl+(mix<<1)); /* map content from memory */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Addr %06x RealAddr %06x Map0[%04x] HIT %04x TLB[%3x] %08x MAPC[%03x] %08x\n", addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]); @@ -1454,12 +1466,12 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) /* for V6 & V9 handle demand paging */ if (CPU_MODEL >= MODEL_V6) { /* map is not valid, so we have map fault */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "AddrMa %06x RealAddr %06x Map0 MISS %04x, TLB[%3x] %08x MAPC[%03x] %08x\n", addr, word, map, nix, TLB[nix], nix/2, MAPC[nix/2]); /* do a demand page request for the required page */ pfault = nix; /* save page number */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "Mem_write Daddr2 %06x page %04x demand page bits set TLB %08x map %04x\n", addr, nix, TLB[nix], map); return DMDPG; /* demand page request */ @@ -1480,11 +1492,11 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000; word = (TLB[nix] & 0xffe000) | offset; /* combine map and offset */ WMR((nix<<1), map); /* store the map reg contents into MAPC cache */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "RealAddrm RMH %04x mix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n", map, mix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1)); - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Addr1c %06x RealAddr %06x Map1[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n", addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1)); @@ -1527,13 +1539,13 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) nix -= 1; /* point to last map in MAPC */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "RealAddrp mix %04x nix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n", mix, nix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1)); /* allow the excess map entry to be loaded, even though bad */ if (nix <= (BPIX+CPIXPL)) { /* needs to be a mapped reg */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Addr1d BPIX %03x CPIXPL %03x RealAddr %06x TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n", BPIX, CPIXPL, word, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1)); @@ -1543,7 +1555,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) /* allow the excess map entry to be loaded, even though bad */ if (nix <= (BPIX+CPIXPL)) { /* needs to be a mapped reg */ map = RMH(msdl+(mix<<1)); /* map content from memory */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Addr2a %06x MapX[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n", addr, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]); @@ -1552,7 +1564,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000; word = (TLB[nix] & 0xffe000); /* combine map and offset */ WMR((nix<<1), map); /* store the map reg contents into MAPC cache */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Addr2b %06x RealAddr %06x Map2[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n", addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]); } @@ -1565,7 +1577,7 @@ t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) } /* fetch the current instruction from the PC address */ -t_stat read_instruction(uint32 thepsd[2], uint32 *instr) +LOCAL t_stat read_instruction(uint32 thepsd[2], uint32 *instr) { uint32 status, addr; @@ -1592,7 +1604,7 @@ t_stat read_instruction(uint32 thepsd[2], uint32 *instr) } else if (status == DMDPG) pfault |= 0x80000000; /* set instruction fetch paging error */ - sim_debug(DEBUG_DETAIL, &cpu_dev, "read_instr status %02x @ %06x\n", status, addr); + sim_debug(DEBUG_DETAIL, my_dev, "read_instr status %02x @ %06x\n", status, addr); return status; /* return ALLOK or ERROR status */ } @@ -1601,9 +1613,9 @@ t_stat read_instruction(uint32 thepsd[2], uint32 *instr) * Return error type if failure, ALLOK if * success. Addr is logical byte address. */ -t_stat Mem_read(uint32 addr, uint32 *data) +LOCAL t_stat Mem_read(uint32 addr, uint32 *data) { - uint32 status, realaddr, prot, page, map, mix, nix, msdl, mpl, nmap; + uint32 status, realaddr=0, prot, page, map, mix, nix, msdl, mpl, nmap; status = RealAddr(addr, &realaddr, &prot, MEM_RD); /* convert address to real physical address */ @@ -1618,7 +1630,7 @@ t_stat Mem_read(uint32 addr, uint32 *data) switch (prot & 0x0e) { case 0x0: case 0x2: /* O/S or user has no read/execute access, do protection violation */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "Mem_readA protect error @ %06x prot %02x modes %08x page %04x\n", addr, prot, MODES, page); if (CPU_MODEL == MODEL_V9) @@ -1628,7 +1640,7 @@ t_stat Mem_read(uint32 addr, uint32 *data) return MPVIOL; /* return memory protection violation */ case 0x4: case 0x6: case 0x8: case 0xa: case 0xc: case 0xe: /* O/S or user has read/execute access, no protection violation */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_readB protect is ok @ %06x prot %02x modes %08x page %04x\n", addr, prot, MODES, page); } @@ -1649,19 +1661,19 @@ t_stat Mem_read(uint32 addr, uint32 *data) WMR((page<<1), map); /* store the map reg contents into cache */ TLB[page] |= 0x0c000000; /* set the accessed bit in TLB too */ WMH(msdl+(mix<<1), map); /* save modified map with access bit set */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_read Yaddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n", addr, page, TLB[page], map, nmap); } } /* everybody else has read access */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_read addr %06x realaddr %06x data %08x prot %02x\n", addr, realaddr, *data, prot); } else { /* RealAddr returned an error */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "Mem_read error addr %06x realaddr %06x data %08x prot %02x status %04x\n", addr, realaddr, *data, prot, status); if (status == NPMEM) { /* operand nonpresent memory error */ @@ -1676,7 +1688,7 @@ t_stat Mem_read(uint32 addr, uint32 *data) else TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ } - sim_debug(DEBUG_EXP, &cpu_dev, "Mem_read MISS %02x @ %06x TRAPSTATUS %08x\n", + sim_debug(DEBUG_EXP, my_dev, "Mem_read MISS %02x @ %06x TRAPSTATUS %08x\n", status, addr, TRAPSTATUS); } return status; /* return ALLOK or ERROR status */ @@ -1687,14 +1699,14 @@ t_stat Mem_read(uint32 addr, uint32 *data) * and alignment restrictions. Return 1 if failure, 0 if * success. Addr is logical byte address, data is 32bit word */ -t_stat Mem_write(uint32 addr, uint32 *data) +LOCAL t_stat Mem_write(uint32 addr, uint32 *data) { uint32 status, realaddr=0, prot=0, raddr, page, nmap, msdl, mpl, map, nix, mix; status = RealAddr(addr, &realaddr, &prot, MEM_WR); /* convert address to real physical address */ if (prot) { - sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %02x\n", + sim_debug(DEBUG_DETAIL, my_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %02x\n", addr, realaddr, *data, prot); } @@ -1707,7 +1719,7 @@ t_stat Mem_write(uint32 addr, uint32 *data) switch (prot &0x0e) { case 0x0: case 0x2: case 0x6: case 0xa: case 0xe: /* O/S or user has read/execute access, do protection violation */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_writeA protect error @ %06x prot %02x modes %08x\n", addr, prot, MODES); if (CPU_MODEL == MODEL_V9) @@ -1717,7 +1729,7 @@ t_stat Mem_write(uint32 addr, uint32 *data) return MPVIOL; /* return memory protection violation */ case 0x4: case 0x8: case 0xc: /* O/S or user has write access, no protection violation */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_writeB protect is ok @ %06x prot %02x modes %08x\n", addr, prot, MODES); } @@ -1738,16 +1750,16 @@ t_stat Mem_write(uint32 addr, uint32 *data) WMR((page<<1), nmap); /* store the map reg contents into cache */ TLB[page] |= 0x18000000; /* set the modify/accessed bits in TLB too */ WMH((msdl+(mix << 1)), nmap); /* save modified map with access bit set */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_write Waddr %06x page %04x set access bit TLB %08x map %04x nmap %04x raddr %08x\n", addr, page, TLB[page], map, nmap, raddr); } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Mem_write Xaddr %06x page %04x MA bits set TLB %08x map %04x prot %04x modes %04x\n", addr, page, TLB[page], map, prot, MODES); } else { if (prot) { /* check for write protected memory */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "Mem_writeB 32/67 protect error @ %06x prot %02x page %04x\n", addr, prot, page); if (CPU_MODEL == MODEL_97) @@ -1760,7 +1772,7 @@ t_stat Mem_write(uint32 addr, uint32 *data) /* everything else has write access */ } else { if (prot) { /* check for write protected memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "Mem_writeC protect error @ %06x prot %02x\n", addr, prot); TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ return MPVIOL; /* return memory protection violation */ @@ -1769,7 +1781,7 @@ t_stat Mem_write(uint32 addr, uint32 *data) WMW(realaddr, *data); /* valid address, put physical address contents */ } else { /* RealAddr returned an error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "Mem_write error addr %.8x realaddr %.8x data %.8x prot %02x status %04x\n", addr, realaddr, *data, prot, status); if (status == NPMEM) { /* operand nonpresent memory error */ @@ -1784,7 +1796,7 @@ t_stat Mem_write(uint32 addr, uint32 *data) else TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ } - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "Mem_write error %02x @ %06x TRAPSTATUS %08x pfaualt %04x\n", status, addr, TRAPSTATUS, pfault); } @@ -1793,7 +1805,7 @@ t_stat Mem_write(uint32 addr, uint32 *data) /* function to set the CCs in PSD1 */ /* ovr is setting for CC1 */ -void set_CCs(uint32 value, int ovr) +LOCAL void set_CCs(uint32 value, int ovr) { PSD1 &= 0x87FFFFFE; /* clear the old CC's */ if (ovr) @@ -1810,12 +1822,11 @@ void set_CCs(uint32 value, int ovr) } /* retain these values across calls to sim_instr */ -uint32 skipinstr = 0; /* Skip test for interrupt on this instruction */ -uint32 drop_nop = 0; /* Set if right hw instruction is a nop */ -uint32 OIR=0; /* Original Instruction register */ -uint32 OPSD1=0; /* Original PSD1 */ -uint32 OPSD2=0; /* Original PSD2 */ -uint32 TPSD[2]; /* Temp PSD */ +LOCAL uint32 skipinstr = 0; /* Skip test for interrupt on this instruction */ +LOCAL uint32 drop_nop = 0; /* Set if right hw instruction is a nop */ +LOCAL uint32 TPSD[2]; /* Temp PSD */ +#define TPSD1 TPSD[0] /* word 1 of PSD */ +#define TPSD2 TPSD[1] /* word 2 of PSD */ /* Opcode definitions */ /* called from simulator */ @@ -1829,13 +1840,13 @@ t_stat sim_instr(void) { t_int64 int64c; /* temp int */ uint32 addr; /* Holds address of last access */ uint32 temp; /* General holding place for stuff */ - uint32 IR; /* Instruction register */ +// uint32 IR; /* Instruction register */ uint32 i_flags=0; /* Instruction description flags from table */ uint32 t; /* Temporary */ uint32 temp2; /* Temporary */ uint32 bc=0; /* Temporary bit count */ - uint16 opr; /* Top half of Instruction register */ - uint16 OP; /* Six bit instruction opcode */ +// uint16 OPR; /* Top half of Instruction register */ +// uint16 OP; /* Six bit instruction opcode */ uint16 chan; /* I/O channel address */ uint16 lchan; /* Logical I/O channel address */ uint16 suba; /* I/O subaddress */ @@ -1850,54 +1861,39 @@ t_stat sim_instr(void) { uint32 dbl; /* Double word */ uint32 ovr=0; /* Overflow flag */ //FORSTEP uint32 stopnext = 0; /* Stop on next instruction */ - uint32 int_icb; /* interrupt context block address */ +// uint32 int_icb; /* interrupt context block address */ uint32 rstatus; /* temp return status */ int32 int32a; /* temp int */ int32 int32b; /* temp int */ int32 int32c; /* temp int */ -// uint32 uint32a; /* temp uint */ -// uint32 uint32b; /* temp uint */ -// uint32 uint32c; /* temp uint */ -//#define MPXTEST -//#define LOOK_MAP_05272021 -#ifdef MPXTEST - int32 ii; /* temp int */ -#endif + reason = SCPE_OK; + /* loop here until time out or error found */ wait_loop: - while (reason == 0) { /* loop until halted */ + while (reason == SCPE_OK) { /* loop until halted */ +// i_flags = 0; /* clear flags for next instruction */ - // wait_loop: if (sim_interval <= 0) { /* event queue? */ reason = sim_process_event(); /* process */ if (reason != SCPE_OK) { - if (reason == SCPE_STEP) { - sim_debug(DEBUG_EXP, &cpu_dev, - "Process Event step reason %08x interval %08x\n", - reason, sim_interval); - return reason; - break; - } - else { - sim_debug(DEBUG_EXP, &cpu_dev, - "Process Event other reason %08x interval %08x\n", - reason, sim_interval); - return reason; - break; /* process */ - } + sim_debug(DEBUG_EXP, my_dev, + "Process Event any reason %08x interval %08x\n", + reason, sim_interval); + fflush(sim_deb); +#ifdef DEBUG4IPU + DumpHist(); +#endif + return reason; + break; /* process */ } } - if (sim_brk_summ) - sim_debug(DEBUG_EXP, &cpu_dev, "Process Event sim_brk_summ = %08x\n", - sim_brk_summ); - PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ /* stop simulator if user break requested */ if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) { reason = STOP_IBKPT; // reason = SCPE_STEP; - sim_debug(DEBUG_EXP, &cpu_dev, "Process Event test reason %08x interval %08x\n", + sim_debug(DEBUG_EXP, my_dev, "Process Event test reason %08x interval %08x\n", reason, sim_interval); sim_interval= 0; /* count down */ break; @@ -1905,69 +1901,310 @@ wait_loop: sim_interval--; /* count down */ - if (drop_nop) { /* need to drop a nop? */ - drop_nop = 0; /* we dropped the nop */ - sim_debug(DEBUG_EXP, &cpu_dev, - "CPU Drop NOP PSD1 %08x\n", PSD1); - } - if (skipinstr) { /* need to skip interrupt test? */ skipinstr = 0; /* skip only once */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "CPU Skip instruction PSD %08x %08x irq_pend %d wait4int %d irq_auto %x\n", - PSD1, PSD2, irq_pend, wait4int, irq_auto); + sim_debug(DEBUG_IRQ, my_dev, + "%s Skip instruction PSD %08x %08x irq_pend %d wait4int %d\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, irq_pend, wait4int); + sim_debug(DEBUG_IRQ, my_dev, + "Skip instruction OPSD %08x %08x PSD %08x %08x CPUSTATUS %08x\n", + OPSD1, OPSD2, PSD1, PSD2, CPUSTATUS); goto skipi; /* skip int test */ } - if (waitqcnt > 0) { /* test for UTX delay */ - waitqcnt--; /* wait b4 ints */ - if (waitqcnt == 0) - irq_pend = 1; /* start scanning interrupts again */ - } - /* we are booting the system, so see if boot channel prog is completed */ if (loading) { +#ifdef USE_IPU_THREAD + int rstat; +#endif uint32 il; uint32 chsa = scan_chan(&il); /* go scan for load complete pending */ - if (chsa != 0) { /* see if a boot channel/subaddress were returned */ + if (chsa != 0) { /* see if a boot channel/subaddress was returned */ /* take interrupt, store the PSD, fetch new PSD */ PSD1 = TPSD[0]; /* PSD1 from location 0 */ PSD2 = TPSD[1]; /* PSD2 from location 4 */ CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert into CPUSTATUS */ - sim_debug(DEBUG_IRQ, &cpu_dev, "Boot Loading PSD1 %.8x PSD2 %.8x\n", PSD1, PSD2); - - /* set interrupt blocking state in CPUSTATUS */ - CPUSTATUS |= BIT24; /* set blocked state in cpu status, bit 24 too */ - MODES |= BLKMODE; /* set blocked in mode to0 */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ + sim_debug(DEBUG_TRAP, my_dev, "Boot Loading PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n", + PSD1, PSD2, CPUSTATUS, CCW); PSD2 &= ~RETMBIT; /* turn off retain map bit in PSD2 */ PSD2 &= ~RETBBIT; /* turn off retain block mode bit in PSD2 */ - SPAD[0xf5] = PSD2; /* save the current PSD2 */ + /* set interrupt blocking state in CPUSTATUS */ + CPUSTATUS |= BIT24; /* set blocked state in cpu status, bit 24 too */ + MODES |= BLKMODE; /* set blocked in mode too */ + if (IPU_MODEL) /* see if loading an IPU model */ + CCW |= HASIPU; /* this is BIT19 for IPU configured */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ + if (!IPU_MODEL) { /* done loading if not an IPU model */ + sim_debug(DEBUG_TRAP, my_dev, "Boot Non IPU PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n", + PSD1, PSD2, CPUSTATUS, CCW); + goto loadend; /* done with cpu */ + } + sim_debug(DEBUG_TRAP, my_dev, "Boot use IPU PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n", + PSD1, PSD2, CPUSTATUS, CCW); +#ifndef CPUONLY +#ifndef USE_IPU_THREAD + /* Process IPU fork model */ + /* now fork another copy of simh for ipu */ + /* Create InterProcessor Com data */ + /* we piggyback on the main memory that we created larger */ + IPC = (struct ipcom *)&M[MAXMEMSIZE]; +#else + /* IPC set in reset code for thread IPU */ +#endif + +#ifndef CPUONLY + /* init semaphore */ +#ifndef USE_IPU_THREAD + /* shared by forked tasks */ + if (sem_init((sem_t *)&(IPC->simsem), 1, 1) != 0) { + if (errno == ENOSYS) + fprintf(stderr,"POSIX semaphores not valid for this processsor\r\n"); + } +#else +#ifdef USE_POSIX_SEM + /* shared by threads */ + if (sem_init((sem_t *)&(IPC->simsem), 0, 1) != 0) { + if (errno == ENOSYS) + fprintf(stderr,"POSIX semaphores not valid for this processsor\r\n"); + } + fprintf(stderr,"POSIX semaphores completed for this processsor\r\n"); + fflush(stdout); +#else + /* the pthread mutex is initialized in the CPU */ + sim_debug(DEBUG_TRAP, my_dev, + "IPU pthread mutex completed for this processsor\n"); +#endif +#endif +#endif + +#ifndef USE_IPU_THREAD + pid = fork(); +#else + rstat = pthread_create(&ipuThread, NULL, ipu_sim_instr, NULL); + if (rstat) { + sim_printf("IPU thread create failed rstat = %x\n", rstat); + exit(1); + } else { + sim_printf("IPU thread created successfully\n"); + } +#endif + /* + * right now we are two processes with copy of variables + * M is shared as main memory by CPU and IPU + * IPC structure also shared to signal SIPU traps + */ + +#ifndef USE_IPU_THREAD + /* the newly created child process in IPU */ + if (pid == 0) { + /* running on IPU */ + MyIndex = 1; + PeerIndex = 0; + /* both CPU and IPU */ + IPC->pid[MyIndex] = getpid(); + + /* we will be running with an ipu, set it up */ + /* clear I/O and interrupt entries in SPAD. */ + /* They are not used in the IPU */ + for (il=0; il<0xf0; il++) + SPAD[il] = 0; + SPAD[0xf7] = 0x13254768; /* set SPAD key for IPU */ + SPAD[0xf0] = 0x20; /* default Trap Table Address (TTA) */ + CPUSTATUS |= ONIPU; /* set ipu state in cpu status, BIT27 */ + CPUSTATUS |= BIT25; /* set ipu traps enabled status, BIT25 */ + TRAPSTATUS |= ONIPU; /* set IPU in trap status too */ + /* This would be BIT20 set to 0 for V9 IPU iconfigured status */ + /* If no IPU configured, BIT19 is set */ + /* FIXME */ + CCW |= HASIPU; /* this is BIT19 for IPU configured */ + SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ + PSD1 = 0x80000000; /* PSD1 privledged */ + PSD2 = 0x00000000; /* PSD2 unmapped, unblocked */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ + sim_debug(DEBUG_TRAP, my_dev, + "IPU Boot Loading PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n", + PSD1, PSD2, CPUSTATUS, CCW); + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + /* set interrupt blocking state in CPUSTATUS */ + CPUSTATUS &= ~BIT24; /* clear blocked state in cpu status, bit 24 */ + wait4sipu = 1; /* now wait for 1st sipu */ + loading = 0; /* we are done loading */ + fclose(stdin); /* close stdin for terminal */ + + sim_debug(DEBUG_TRAP, my_dev, + "Starting IPU WAIT in fork\n"); +#ifdef USE_POSIX_SEM + sim_idle_ms_sleep(1); /* wait 1 ms */ +// millinap(1); /* wait 1 ms */ +#endif + goto wait_loop; /* continue waiting */ + } +#endif /* USE_IPU_THREAD */ +#endif /* CPUONLY */ + { + /* running on CPU with forked IPU */ +#ifndef CPUONLY + MyIndex = 0; + PeerIndex = 1; +#endif + CPUSTATUS &= ~BIT27; /* This a CPU, not IPU */ + SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ +#ifndef CPUONLY +#ifndef USE_IPU_THREAD + /* both CPU and IPU */ + IPC->pid[MyIndex] = getpid(); +#else + IPC->pid[MyIndex] = 0; +#endif +#endif + /* This would be BIT20 set to 0 for V9 IPU iconfigured status */ + /* If no IPU configured, BIT19 is set. Backward of other models */ + /* FIXME */ + sim_debug(DEBUG_TRAP, my_dev, + "CPU Boot Loading PSD1 %.8x PSD2 %.8x CPUSTATUS %08x CCW %.8x\n", + PSD1, PSD2, CPUSTATUS, CCW); + CCW |= HASIPU; /* this is BIT19 for IPU present */ + } +loadend: loading = 0; /* we are done loading */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "Load Skipinstr %1x set loading PSD1 %08x PSD2 %08x CPUSTATUS %08x\n", - skipinstr, PSD1, PSD2, CPUSTATUS); +#ifdef CPUONLY + sim_debug(DEBUG_EXP, my_dev, + "Load complete, start @PSD %08x %08x CPUSTATUS %08x\n", + PSD1, PSD2, CPUSTATUS); +#endif goto skipi; /* skip int test */ } goto wait_loop; /* continue waiting */ } /* we get here when not booting */ +#ifndef CPUONLY + /* process SIPU if IPU present */ + if (IPU_MODEL) { +#ifdef USE_POSIX_SEM + /* process any pending sipu traps from the ipu here on cpu */ + /* interrupts must be unblocked to take the sipu trap */ + if (((CPUSTATUS & ONIPU) == 0) && IPC && ((CPUSTATUS & BIT24) == 0) && + IPC->atrap[MyIndex]) { + TRAPME = IPC->atrap[MyIndex]; + IPC->atrap[MyIndex] = 0; + IPC->received[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x Index %x PeerIndex %x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, MyIndex, PeerIndex); + sim_debug(DEBUG_TRAP, my_dev, + "%s: PC %08x PSD1 %08x PSD2 %08x 0x20 %x 0x80 %x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PC, PSD1, PSD2, M[0x20>2], M[0x80>>2]); + wait4int = 0; /* wait is over for int */ + skipinstr = 1; /* skip interrupt test */ + goto newpsd; /* go process trap */ + } + /* wait for sipu to start us on ipu */ + /* interrupts must be unblocked on IPU too! */ + if ((CPUSTATUS & ONIPU) && ((CPUSTATUS & BIT24) == 0)) { + if (IPC && IPC->atrap[MyIndex]) { + wait4sipu = 0; /* wait is over for sipu */ + TRAPME = IPC->atrap[MyIndex]; /* get trap number */ + IPC->atrap[MyIndex] = 0; /* clear flag */ + IPC->received[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x SPAD[0xf0] %08x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, SPAD[0xf0]); + sim_debug(DEBUG_TRAP, my_dev, + "%s: PC %08x PSD1 %08x PSD2 %08x 0x20 %x 0x80 %x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PC, PSD1, PSD2, M[0x20>2], M[0x80>>2]); + skipinstr = 1; /* skip interrupt test */ + goto newpsd; /* go process trap */ + } + if (wait4sipu) { + sim_idle_ms_sleep(1); /* wait 1 ms */ +// millinap(1); /* wait 1 ms */ + goto wait_loop; /* continue waiting */ + } + } +#else /* USE_POSIX_SEM */ + /* process any pending sipu traps from the ipu here on cpu */ + /* interrupts must be unblocked to take the sipu trap */ + if (((CPUSTATUS & ONIPU) == 0) && IPC && ((CPUSTATUS & BIT24) == 0) && + IPC->atrap[MyIndex]) { + TRAPME = IPC->atrap[MyIndex]; + IPC->atrap[MyIndex] = 0; + IPC->received[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x Index %x PeerIndex %x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, MyIndex, PeerIndex); + sim_debug(DEBUG_TRAP, my_dev, + "%s: PC %08x PSD1 %08x PSD2 %08x 0x20 %x 0x80 %x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PC, PSD1, PSD2, M[0x20>2], M[0x80>>2]); + wait4int = 0; /* wait is over for int */ + skipinstr = 1; /* skip interrupt test */ + goto newpsd; /* go process trap */ + } + /* we may or may not be waiting for sipu */ + /* wait for sipu to start us on ipu */ + /* interrupts must be unblocked on IPU to receive SIPU */ + if ((CPUSTATUS & ONIPU) && ((CPUSTATUS & BIT24) == 0) && IPC && + (IPC->atrap[MyIndex] != 0)) { + /* we are unblocked, look for SIPU */ + /* we have a trap available, lock and get it */ +#ifdef MAYBE_BAD +cond_go: +#endif +// lock_mutex(); /* lock mutex */ +cond_ok: + if (IPC && IPC->atrap[MyIndex]) { + lock_mutex(); /* lock mutex */ + TRAPME = IPC->atrap[MyIndex]; /* get trap number */ + IPC->atrap[MyIndex] = 0; /* clear trap value location */ + unlock_mutex(); /* unlock mutex */ + IPC->received[MyIndex]++; /* count it received */ + wait4sipu = 0; /* wait is over for sipu */ + sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x SPAD[0xf0] %08x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, SPAD[0xf0]); + sim_debug(DEBUG_TRAP, my_dev, + "%s: PC %08x PSD %08x %08x 0x20 %x 0x80 %x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PC, PSD1, PSD2, M[0x20>2], M[0x80>>2]); + skipinstr = 1; /* skip interrupt test */ + goto newpsd; /* go process trap */ + } + /* unblocked and locked and no async trap */ + if (wait4sipu) { /* are we to wait */ + lock_mutex(); /* lock mutex */ + while (IPC->atrap[MyIndex]==0) /* sleep on the condition */ + pthread_cond_wait(&IPC->cond, &IPC->mutex); /* wait for wakeup */ + unlock_mutex(); /* unlock mutex and continue */ + goto cond_ok; /* go process */ + } + /* not waiting for sipu, so continue processing */ +// unlock_mutex(); /* unlock mutex and continue */ + } + /* we are blocked or no pending sipu, contine */ + /* continue processing */ +#endif /* USE_POSIX_SEM */ + } +#endif /* CPU_ONLY*/ + /* process any pending interrupts */ - if ((irq_pend || wait4int) && (irq_auto == 0)) { + if (irq_pend || wait4int) { /* see if ints are pending */ + uint32 int_icb; /* interrupt context block address */ uint32 ilev; - uint32 oldstatus = CPUSTATUS; /* keep for retain blocking state */ + int32 oldstatus = CPUSTATUS; /* keep for retain blocking state */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ int_icb = scan_chan(&ilev); /* no, go scan for I/O int pending */ if (int_icb != 0) { /* was ICB returned for an I/O or interrupt */ uint32 il = ilev; /* get the interrupt level */ - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_IRQ, my_dev, "<|>Normal int return icb %06x level %02x irq_pend %1x wait4int %1x\n", int_icb, il, irq_pend, wait4int); @@ -1975,102 +2212,114 @@ wait_loop: bc = PSD2 & 0x3ff8; /* get copy of cpix */ M[int_icb>>2] = PSD1&0xfffffffe; /* store PSD 1 */ M[(int_icb>>2)+1] = PSD2; /* store PSD 2 */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>Normal int cpix %04x OPSD1 %08x OPSD2 %08x\n", - bc, PSD1, PSD2); -#ifdef DUMP_REGS - for (ix=0; ix<8; ix+=2) { - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|> GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); - } -#endif + TPSD1 = PSD1; /* save the current PSD */ + TPSD2 = PSD2; PSD1 = M[(int_icb>>2)+2]; /* get new PSD 1 */ PSD2 = (M[(int_icb>>2)+3] & ~0x3fff) | bc; /* get new PSD 2 w/old cpix */ + sim_debug(DEBUG_IRQ, my_dev, + "<|>Normal int cpix %04x OPSD %08x %08x NPSD %08x %08x CPUSTATUS %08x\n", + bc, TPSD1, TPSD2, PSD1, PSD2, CPUSTATUS); +#ifdef DUMP_REGS + for (ix=0; ix<8; ix+=2) { + sim_debug(DEBUG_IRQ, my_dev, + "<|> GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } +#endif + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + CPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ + } + + if (PSD2 & SETBBIT) { /* no, is it set blocking state bit 49 set*/ + /* new blocking state is blocked when bits 48=0 & bit 49=1 */ + /* This test fixed the hangs on terminal input for diags & UTX! */ + t = SPAD[il+0x80]; /* get spad entry for interrupt */ + /* Class F I/O spec says to reset active interrupt if user's */ + /* interrupt service routine runs with interrupts blocked */ + if (((t & 0x0f800000) == 0x0f000000) || /* if class F clear interrupt */ + ((t & 0x0f80ffff) == 0x00807f06) || /* RT Clock */ + ((t & 0x0f00ffff) == 0x03007f04)) { /* Interval timer */ + /* if this is F class I/O interrupt, clear the active level */ + /* SPAD entries for interrupts begin at 0x80 */ + sim_debug(DEBUG_IRQ, my_dev, + "<|>Auto-reset interrupt INTS[%02x] %08x SPAD[%02x] %08x\n", + il, INTS[il], il+0x80, SPAD[il+0x80]); + INTS[il] &= ~INTS_ACT; /* deactivate specified int level */ + SPAD[il+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ + } + } else { + sim_debug(DEBUG_IRQ, my_dev, + "<|>RUN ACTIVE interrupt INTS[%02x] %08x SPAD[%02x] %08x\n", + il, INTS[il], il+0x80, SPAD[il+0x80]); + } + + /* set new map mode and interrupt blocking state in CPUSTATUS & MODES */ /* I/O status DW address will be in WD 6 */ /* set new map mode and interrupt blocking state in CPUSTATUS */ CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ CPUSTATUS &= ~0x87000080; /* reset bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert into CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ + + if (PSD2 & SETBBIT) { /* is it set blocking state bit 49 set*/ + /* set new blocking state bit 49=1 */ + CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ + MODES |= BLKMODE; /* set blocked mode */ + } else { + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + MODES &= ~BLKMODE; /* reset block mode bits */ + } + /* bit 0 of PSD wd 2 sets new mapping state */ if (PSD2 & MAPBIT) { CPUSTATUS |= BIT8; /* set bit 8 of cpu status to mapped */ MODES |= MAPMODE; /* set mapped mode */ } else { CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ - MODES &= ~MAPMODE; /* reset set mapped mode */ - } - - if ((PSD2 & RETBBIT) == 0) { /* is it retain blocking state, bit 48 set */ - /* retain blocking state is off, use bit 49 to set new blocking state */ - if (PSD2 & SETBBIT) { /* no, is it set blocking state bit 49 set*/ - /* new blocking state is blocked when bits 48=0 & bit 49=1 */ - CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ - MODES |= BLKMODE; /* set blocked mode */ - - /* This test fixed the hangs on terminal input for diags & UTX! */ - t = SPAD[il+0x80]; /* get spad entry for interrupt */ - /* Class F I/O spec says to reset active interrupt if user's */ - /* interrupt service routine runs with interrupts blocked */ - if (((t & 0x0f800000) == 0x0f000000) || /* if class F clear interrupt */ - ((t & 0x0000ffff) == 0x00007f06) || /* RT Clock */ - ((t & 0x0f00ffff) == 0x03007f04)) { /* Interval timer */ - /* if this is F class I/O interrupt, clear the active level */ - /* SPAD entries for interrupts begin at 0x80 */ - if ((irq_auto) != 0) { - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>Auto-reset irq_auto NOT zero %x INTS[%02x] %08x SPAD[%02x] %08x\n", - irq_auto, il, INTS[il], il+0x80, SPAD[il+0x80]); - } - irq_auto = il; /* show processing in blocked mode */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>Auto-reset interrupt INTS[%02x] %08x SPAD[%02x] %08x simi %02x\n", - il, INTS[il], il+0x80, SPAD[il+0x80], sim_interval); -#define LEAVE_ACTIVE -#ifndef LEAVE_ACTIVE -/*AIR*/ INTS[irq_auto] &= ~INTS_ACT; /* deactivate specified int level */ -/*AIR*/ SPAD[irq_auto+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ - irq_auto = 0; -#endif - } - } else { - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>RUN ACTIVE interrupt INTS[%02x] %08x SPAD[%02x] %08x\n", - il, INTS[il], il+0x80, SPAD[il+0x80]); - CPUSTATUS &= ~BIT24; /* no, reset blk state in cpu status bit 24 */ - MODES &= ~BLKMODE; /* reset blocked mode */ - } - } else { - /* handle retain blocking state */ - PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ - /* set new blocking state in PSD2 */ - PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ - MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ - if (oldstatus & BIT24) { /* see if old mode is blocked */ - PSD2 |= SETBBIT; /* set to blocked state */ - MODES |= BLKMODE; /* set blocked mode */ - } + MODES &= ~MAPMODE; /* reset mapped mode */ } SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>Int %02x OPSD1 %08x OPSD2 %08x NPSD1 %08x NPSD2 %08x\n", + sim_debug(DEBUG_IRQ, my_dev, + "<|>Int %02x OPSD %08x %08x NPSD %08x %08x\n", il, RMW(int_icb), RMW(int_icb+4), PSD1, PSD2); - bc = RMW(int_icb+20) & 0xffffff; - if (RMW(int_icb+16) == 0) - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>Int2 %02x ICBA %06x ICBA %06x IOCLA %06x\n", il, int_icb, - RMW(int_icb+16), RMW(int_icb+20)); - else - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>Int2 %02x ICBA %06x IOCLA %06x STAT %08x SW1 %08x SW2 %08x\n", - il, int_icb, RMW(int_icb+16), RMW(int_icb+20), RMW(bc), RMW(bc+4)); -#ifdef DYNAMIC_DEBUG_01172021 - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ +#ifndef DUMP_REGS + for (ix=0; ix<8; ix+=2) { + sim_debug(DEBUG_IRQ, my_dev, + "<|> GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } #endif + bc = RMW(int_icb+20) & 0xffffff; + t = SPAD[il+0x80]; /* get spad entry for interrupt */ + if (t & 0x00800000) { /* is this a non I/O interrupt */ + // non-I/O interrupt + sim_debug(DEBUG_IRQ, my_dev, + "<|>Int2 %02x ICBA %06x IOCLA %06x STAT %06x\n", + il, int_icb, RMW(int_icb+16), RMW(int_icb+20)); + } else { + // I/O interrupt ICB + sim_debug(DEBUG_IRQ, my_dev, + "<|>Int3 %02x ICBA %06x IOCLA %06x STAT %08x SW1 %08x SW2 %08x\n", + il, int_icb, RMW(int_icb+16), RMW(int_icb+20), RMW(bc), RMW(bc+4)); + } + if (wait4int) + sim_debug(DEBUG_IRQ, my_dev, + "End %s WAIT OPSD %.8x %.8x NPSD %.8x %.8x OSTAT %08x NSTAT %08x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + RMW(int_icb), RMW(int_icb+4), PSD1, PSD2, oldstatus, CPUSTATUS); + wait4int = 0; /* wait is over for int */ - drop_nop = 0; /* no nop skipping */ goto skipi; /* skip int test */ } } @@ -2079,7 +2328,7 @@ wait_loop: if (wait4int) { /* keep waiting */ /* tell simh we will be waiting */ sim_idle(TMR_RTC, 1); /* wait for clock tick */ - irq_pend = 1; /* start scanning interrupts again */ + PC = OPSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ goto wait_loop; /* continue waiting */ } @@ -2088,25 +2337,23 @@ wait_loop: if (!skipinstr && attention_trap) { TRAPME = attention_trap; /* get trap number */ attention_trap = 0; /* clear flag */ - sim_debug(DEBUG_XIO, &cpu_dev, "Attention TRAP %04x\n", TRAPME); - goto newpsd; /* got process trap */ + sim_debug(DEBUG_TRAP, my_dev, "Attention TRAP %04x\n", TRAPME); + goto newpsd; /* go process trap */ } skipi: i_flags = 0; /* do not update pc if MF or NPM */ TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */ - - /* check for breakpoint request */ - if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) { - reason = STOP_IBKPT; - break; - } + PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ + //FIXME added change 112922 + OPSD1 = PSD1; /* save the old PSD1 */ + OPSD2 = PSD2; /* save the old PSD2 */ /* fill IR from logical memory address */ if ((TRAPME = read_instruction(PSD, &IR))) { - sim_debug(DEBUG_TRAP, &cpu_dev, - "read_instr TRAPME %04x PSD %08x %08x i_flags %04x drop_nop %1x\n", - TRAPME, PSD1, PSD2, i_flags, drop_nop); + sim_debug(DEBUG_TRAP, my_dev, + "read_instr TRAPME %02x PSD %08x %08x i_flags %04x\n", + TRAPME, PSD1, PSD2, i_flags); if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) { if ((TRAPME == MAPFLT) || (TRAPME == NPMEM)) { @@ -2116,20 +2363,19 @@ skipi: if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_67)) i_flags |= BT; /* do not update pc if MF or NPM */ else - i_flags &= ~BT; /* do not update pc if MF or NPM */ + i_flags &= ~BT; /* update pc */ } } else { if ((TRAPME == PRIVVIOL_TRAP) && (CPU_MODEL == MODEL_V9)) { i_flags |= HLF; /* assume half word instr */ - drop_nop = 0; i_flags &= ~BT; /* no branch taken */ PSD1 &= ~BIT31; /* force off last right */ } } - sim_debug(DEBUG_TRAP, &cpu_dev, - "read_instr2 TRAPME %04x PSD %08x %08x i_flags %04x drop_nop %1x\n", - TRAPME, PSD1, PSD2, i_flags, drop_nop); - goto newpsd; /* got process trap */ + sim_debug(DEBUG_TRAP, my_dev, + "read_instr2 TRAPME %02x PSD %08x %08x i_flags %04x\n", + TRAPME, PSD1, PSD2, i_flags); + goto newpsd; /* go process trap */ } if (PSD1 & 2) { /* see if executing right half */ @@ -2137,20 +2383,19 @@ skipi: IR <<= 16; /* put instruction in left hw */ if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { - drop_nop = 0; /* not dropping nop for these machines */ goto exec; /* machine does not drop nop instructions */ } /* We have 67 or V6 and have a rt hw instruction */ if (IR == 0x00020000) { /* is this a NOP from rt hw? */ PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); /* skip this instruction */ if (skipinstr) - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_IRQ, my_dev, "2Rt HW instruction skipinstr %1x is set PSD1 %08x PSD2 %08x CPUSTATUS %08x\n", skipinstr, PSD1, PSD2, CPUSTATUS); goto skipi; /* go read next instruction */ } if (skipinstr) - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_IRQ, my_dev, "3Rt HW instruction skipinstr %1x is set PSD1 %08x PSD2 %08x CPUSTATUS %08x\n", skipinstr, PSD1, PSD2, CPUSTATUS); } else { @@ -2164,29 +2409,61 @@ skipi: i_flags = base_mode[OP>>2]; /* set the BM instruction processing flags */ else i_flags = nobase_mode[OP>>2]; /* set the NBM instruction processing flags */ - if ((i_flags & 0xf) == HLF) { /* this is left HW instruction */ +//FIX112922 if ((i_flags & 0xf) == HLF) { /* this is left HW instruction */ + if (i_flags & HLF) { /* this is left HW instruction */ if ((IR & 0xffff) == 0x0002) { /* see if rt hw is a nop */ /* treat this as a fw instruction */ drop_nop = 1; /* we need to skip nop next time */ - sim_debug(DEBUG_DETAIL, &cpu_dev, - "CPU setting Drop NOP PSD1 %08x IR %08x\n", PSD1, IR); +// sim_debug(DEBUG_IRQ, my_dev, + sim_debug(DEBUG_DETAIL, my_dev, + "CPU setting Drop NOP OPSD1 %08x PSD1 %08x PC %08x IR %08x\n", OPSD1, PSD1, PC, IR); + goto exec2; } } } -exec: +exec: /* we re-enter here for EXR, EXRR, or EXM op */ + OP = (IR >> 24) & 0xFC; /* get OP */ + if (PSD1 & BASEBIT) + i_flags = base_mode[OP>>2]; /* set the BM instruction processing flags */ + else + i_flags = nobase_mode[OP>>2]; /* set the NBM instruction processing flags */ +exec2: /* temp saves for debugging */ OIR = IR; /* save the instruction */ OPSD1 = PSD1; /* save the old PSD1 */ OPSD2 = PSD2; /* save the old PSD2 */ TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */ +// bc = 0; +// EXM_EXR = 0; +// source = 0; /* Split instruction into pieces */ PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "-----Instr @ PC %08x PSD1 %08x PSD2 %08x IR %08x drop_nop %x\n", PC, PSD1, PSD2, IR, drop_nop); + OPR = (IR >> 16) & MASK16; /* use upper half of instruction */ + OP = (OPR >> 8) & 0xFC; /* Get opcode (bits 0-5) left justified */ + FC = ((IR & F_BIT) ? 0x4 : 0) | (IR & 3); /* get F & C bits for addressing */ + reg = (OPR >> 7) & 0x7; /* dest reg or xr on base mode */ + sreg = (OPR >> 4) & 0x7; /* src reg for reg-reg instructions or BR instr */ + dbl = 0; /* no doubleword instruction */ + ovr = 0; /* no overflow or arithmetic exception either */ + dest = (t_uint64)IR; /* assume memory address specified */ + CC = PSD1 & 0x78000000; /* save CC's if any */ + MODES = PSD1 & 0x87000000; /* insert bits 0, 5, 6, 7 from PSD 1 */ + CPUSTATUS &= ~0x87000000; /* reset those bits in CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ + if (PSD2 & MAPBIT) { + CPUSTATUS |= BIT8; /* set bit 8 of cpu status to mapped */ + MODES |= MAPMODE; /* set mapped mode */ + } else { + CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ + MODES &= ~MAPMODE; /* reset mapped mode */ + } + /* Update history for this instruction */ if (hst_lnt) { hst_p += 1; /* next history location */ @@ -2195,32 +2472,20 @@ exec: hst[hst_p].opsd1 = OPSD1; /* set original psd1 */ hst[hst_p].opsd2 = OPSD2; /* set original psd2 */ hst[hst_p].oir = OIR; /* set original instruction */ - } - - opr = (IR >> 16) & MASK16; /* use upper half of instruction */ - OP = (opr >> 8) & 0xFC; /* Get opcode (bits 0-5) left justified */ - FC = ((IR & F_BIT) ? 0x4 : 0) | (IR & 3); /* get F & C bits for addressing */ - reg = (opr >> 7) & 0x7; /* dest reg or xr on base mode */ - sreg = (opr >> 4) & 0x7; /* src reg for reg-reg instructions or BR instr */ - dbl = 0; /* no doubleword instruction */ - ovr = 0; /* no overflow or arithmetic exception either */ - dest = (t_uint64)IR; /* assume memory address specified */ - CC = PSD1 & 0x78000000; /* save CC's if any */ - MODES = PSD1 & 0x87000000; /* insert bits 0, 5, 6, 7 from PSD 1 */ - CPUSTATUS &= ~0x87000000; /* reset those bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert them into CPUSTATUS */ - if (PSD2 & MAPBIT) { - CPUSTATUS |= BIT8; /* set bit 8 of cpu status to mapped */ - MODES |= MAPMODE; /* set mapped mode */ - } else { - CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ - MODES &= ~MAPMODE; /* reset mapped mode */ + hst[hst_p].modes = MODES; /* save current mode bits */ + hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */ + if (CPUSTATUS & BIT24) + hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */ + if (CPUSTATUS & BIT27) + hst[hst_p].modes |= IPUMODE; /* save cpu/ipu status bit */ } if (MODES & BASEBIT) { +#ifdef NONOP i_flags = base_mode[OP>>2]; /* set the instruction processing flags */ +#endif addr = IR & RMASK; /* get address offset from instruction */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Base OP %04x i_flags %04x addr %08x\n", OP, i_flags, addr); switch(i_flags & 0xf) { case HLF: @@ -2229,7 +2494,7 @@ exec: case IMM: if (PC & 02) { /* if pc is on HW boundry, bad address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC1 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -2241,7 +2506,7 @@ exec: case WRD: if (PC & 02) { /* if pc is on HW boundry, bad address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC2 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -2260,7 +2525,9 @@ exec: break; } } else { +#ifdef NONOP i_flags = nobase_mode[OP>>2]; /* set the instruction processing flags */ +#endif addr = IR & 0x7ffff; /* get 19 bit address from instruction */ if (PC >= 0x80000) { TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */ @@ -2283,7 +2550,7 @@ exec: } else { PSD1 &= 0xff0fffff; /* leave overflow bit for trap addr */ } - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "PC over 80000 PC %08x Base OP %02x i_flags %04x addr %06x PSD %08x %08x\n", PC, OP, i_flags, addr, PSD1, PSD2); if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) @@ -2292,7 +2559,7 @@ exec: TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ goto newpsd; /* handle trap */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "Non Based i_flags %04x addr %08x\n", i_flags, addr); /* non base mode instructions have bit 0 of the instruction set */ /* for word length instructions and zero for halfword instructions */ @@ -2314,7 +2581,7 @@ exec: case IMM: /* Immediate mode */ if (PC & 02) { /* if pc is on HW boundry, bad address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC3 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -2344,7 +2611,7 @@ exec: addr &= MASK24; /* make pure 24 bit addr */ while ((t & IND) != 0) { /* process indirection */ if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "case WRD Mem_read status %02x @ %08x OP %04x\n", TRAPME, addr, OP); if (CPU_MODEL == MODEL_V9) /* V9 wants bit0 set in pfault */ if (TRAPME == DMDPG) /* demand page request */ @@ -2384,7 +2651,7 @@ exec: /* Read memory operand */ if (i_flags & RM) { if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "case RM Mem_read status %02x @ %08x\n", TRAPME, addr); // DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails if ((TRAPME == MAPFLT) || (TRAPME == NPMEM) || (TRAPME == MPVIOL)) @@ -2410,13 +2677,13 @@ exec: case 2: /* double word address */ if ((addr & 7) != 2) { /* must be double word adddress */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC4 case RM wd 1/3 Mem_read DW status %02x @ %08x src %08x\n", TRAPME, addr, (uint32)source); goto newpsd; /* go execute the trap now */ } if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "case RM wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4); goto newpsd; /* memory read error or map fault */ } @@ -2435,7 +2702,7 @@ exec: /* Read memory operand without doing sign extend for EOMX/ANMX/ORMX/ARMX */ if (i_flags & RNX) { if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "case RNX 2 Mem_read status %02x @ %08x\n", TRAPME, addr); goto newpsd; /* memory read error or map fault */ } @@ -2453,12 +2720,12 @@ exec: case 2: /* double word address */ if ((addr & 7) != 2) { /* must be double word adddress */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC5 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "case RNX wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4); goto newpsd; /* memory read error or map fault */ } @@ -2482,7 +2749,7 @@ exec: if (dbl) { /* is it double regs */ if (reg & 1) { /* check for odd reg load */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC6 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -2505,7 +2772,7 @@ exec: if (dbl) { if (sreg & 1) { TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC7 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -2518,7 +2785,7 @@ exec: } /* process instruction op code */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "PSD %08x %08x SW OP %04x IR %08x addr %08x\n", PSD1, PSD2, OP, IR, addr); @@ -2535,9 +2802,8 @@ exec: /* | Op Code | DReg | SReg | Aug Code | */ /* |--------------------------------------| */ case 0x00>>2: /* HLF - HLF */ /* CPU General operations */ - switch(opr & 0xF) { /* switch on aug code */ + switch(OPR & 0xF) { /* switch on aug code */ case 0x0: /* HALT */ -#ifndef TEMP4DEBUG if ((MODES & PRIVBIT) == 0) { /* must be privileged to halt */ TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) @@ -2550,21 +2816,53 @@ exec: TRAPME = PRIVHALT_TRAP; /* set the trap to take */ goto newpsd; /* Privlege mode halt trap */ } + +#ifndef CPUONLY + /* if on the IPU simulate a wait instead */ + if (CPUSTATUS & ONIPU) { + /* wait for any trap, knowing there will be no interrupts */ + if (wait4sipu == 0) { + time_t result = time(NULL); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_TRAP, my_dev, + "Starting %s HALT PSD %.8x %.8x TRAPME %02x CPUSTATUS %08x time %.8x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, CPUSTATUS, (uint32)result); + } +#ifdef MAYBE_BAD + else { +#ifdef USE_POSIX_SEM + sim_idle_ms_sleep(1); /* wait 1 ms */ +// millinap(1); /* wait 1 ms */ + goto wait_loop; /* continue waiting */ +#else + wait4sipu = 1; /* show we are waiting for SIPU */ + goto cond_go; /* start waiting for sipu */ #endif - sim_debug(DEBUG_EXP, &cpu_dev, - "\n[][][][][][][][][][] HALT [][][][][][][][][][]\n"); - sim_debug(DEBUG_EXP, &cpu_dev, - "PSD1 %.8x PSD2 %.8x TRAPME %.4x CPUSTATUS %08x\n", + } +#endif + wait4sipu = 1; /* show we are waiting for SIPU */ + i_flags |= BT; /* keep PC from being incremented while waiting */ + break; /* keep going */ + } +#endif + /* we need to do an actual halt here if on CPU */ + sim_debug(DEBUG_EXP, my_dev, + "\n[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\n"); + sim_debug(DEBUG_EXP, my_dev, + "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", PSD1, PSD2, TRAPME, CPUSTATUS); for (ix=0; ix<8; ix+=2) { - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); } - sim_debug(DEBUG_EXP, &cpu_dev, - "[][][][][][][][][][] HALT [][][][][][][][][][]\n"); + sim_debug(DEBUG_EXP, my_dev, + "[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\n"); - fprintf(stdout, "\r\n[][][][][][][][][][] HALT [][][][][][][][][][]\r\n"); - fprintf(stdout, "PSD1 %.8x PSD2 %.8x TRAPME %.4x CPUSTATUS %08x\r\n", + fprintf(stdout, "\r\n[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\r\n"); + fprintf(stdout, "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x\r\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", PSD1, PSD2, TRAPME, CPUSTATUS); for (ix=0; ix<8; ix+=2) { fprintf(stdout, "GPR[%d] %.8x GPR[%d] %.8x\r\n", @@ -2572,12 +2870,27 @@ exec: } if (MODES & BASEBIT) { /* see if based */ for (ix=0; ix<8; ix+=2) { - fprintf(stdout, "BR[%d] %.8x BR[%d] %.8x\r\n", + fprintf(stdout, " BR[%d] %.8x BR[%d] %.8x\r\n", ix, BR[ix], ix+1, BR[ix+1]); } } - fprintf(stdout, "[][][][][][][][][][] HALT [][][][][][][][][][]\r\n"); + fprintf(stdout, "[][][][][][][][][][] CPU HALT [1][][][][][][][][][]\r\n"); +#ifdef CPUDEBUG + DumpHist(); +#endif +#ifndef CPUONLY +#ifndef USE_IPU_THREAD + if ((IPU_MODEL) && (IPC->pid[1] != 0)) { + /* If we have an forked IPU model, and we are on the CPU: destroy the IPU */ + kill(IPC->pid[1], SIGKILL); /* destroy the IPU */ + } +#endif +#endif /*TEST DIAG*/reason = STOP_HALT; /* do halt for now */ +#ifdef USE_IPU_THREAD + cpustop = reason; /* tell the IPU */ +#endif + return STOP_HALT; /* exit to simh for halt */ break; case 0x1: /* WAIT */ @@ -2596,18 +2909,53 @@ exec: TRAPSTATUS |= BIT12; /* set bit 0 of trap status */ else TRAPSTATUS |= BIT20; /* set bit 20 of trap status */ - goto newpsd; /* system check trap */ + goto newpsd; /* System check trap */ } - if (wait4int == 0) { - time_t result = time(NULL); - sim_debug(DEBUG_DETAIL, &cpu_dev, - "Starting WAIT mode %08x\n", (uint32)result); +#if 0 +do_ipu_wait: +#endif + PC = OPSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ +#ifndef CPUONLY + if (IPU_MODEL && (CPUSTATUS & ONIPU)) { + /* Hack around it when on IPU side: wait by expensive method */ + /* wait for any trap, knowing there will be no interrupts */ + if (wait4sipu == 0) { + time_t result = time(NULL); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_TRAP, my_dev, + "Starting %s WAIT1 PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x time %.8x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, CPUSTATUS, (uint32)result); + } +#ifdef MAYBE_BAD + else { +#ifdef USE_POSIX_SEM + sim_idle_ms_sleep(1); /* wait 1 ms */ +// millinap(1); /* wait 1 ms */ + goto wait_loop; /* continue waiting */ +#else + wait4sipu = 1; /* show we are waiting for SIPU */ + goto cond_go; /* start waiting for sipu */ +#endif /* USE_POSIX_SEM */ + } +#endif /* MAYBE_BAD */ + wait4sipu = 1; /* show we are waiting for SIPU */ + i_flags |= BT; /* keep PC from being incremented while waiting */ + } else +#endif /* CPU_ONLY */ + { + if (wait4int == 0) { + time_t result = time(NULL); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_TRAP, my_dev, + "Starting %s WAIT2 PSD1 %.8x PSD2 %.8x TRAPME %02x CPUSTATUS %08x time %.8x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, CPUSTATUS, (uint32)result); + } + /* tell simh we will be waiting */ + wait4int = 1; /* show we are waiting for interrupt */ + i_flags |= BT; /* keep PC from being incremented while waiting */ } - wait4int = 1; /* show we are waiting for interrupt */ - /* tell simh we will be waiting */ - sim_idle(TMR_RTC, 0); /* wait for next pending device event */ - irq_pend = 1; /* start scanning interrupts again */ - i_flags |= BT; /* keep PC from being incremented while waiting */ break; case 0x2: /* NOP */ break; @@ -2620,6 +2968,8 @@ exec: case 0x4: /* ES */ if (reg & 1) { /* see if odd reg specified */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7a OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } /* reg is reg to extend sign into from reg+1 */ @@ -2629,6 +2979,8 @@ exec: case 0x5: /* RND */ if (reg & 1) { /* see if odd reg specified */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7b OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } temp = GPR[reg]; /* save the current contents of specified reg */ @@ -2664,23 +3016,23 @@ exec: TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ goto newpsd; /* Privlege violation trap */ } -#ifdef DYNAMIC_DEBUG -TPSD[0] = PSD1; -TPSD[1] = PSD2; -#endif - CPUSTATUS |= BIT24; /* into status word bit 24 too */ + if (IPU_MODEL && (CPUSTATUS & ONIPU)) { + /* on IPU : */ + TRAPME = IPUUNDEFI_TRAP; + sim_debug(DEBUG_TRAP, my_dev, + "IPU BEI PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", + PSD1, PSD2, SPAD[0xf5], CPUSTATUS); +//112522 i_flags |= BT; /* leave PC unchanged, so we point at BEI */ + goto newpsd; + } PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 */ MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ PSD2 |= SETBBIT; /* set to blocked state */ + CPUSTATUS |= BIT24; /* into status word bit 24 too */ MODES |= BLKMODE; /* set blocked mode */ SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ -#ifdef DYNAMIC_DEBUG -sim_debug(DEBUG_IRQ, &cpu_dev, - "BEI OPSD %.8x %.8x NPSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", - TPSD[0], TPSD[1], PSD1, PSD2, SPAD[0xf5], CPUSTATUS); -#endif break; case 0x7: /* UEI */ @@ -2692,33 +3044,15 @@ sim_debug(DEBUG_IRQ, &cpu_dev, TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ goto newpsd; /* Privlege violation trap */ } -#ifdef DYNAMIC_DEBUG -TPSD[0] = PSD1; -TPSD[1] = PSD2; -#endif if (CPUSTATUS & BIT24) { /* see if old mode is blocked */ - irq_pend = 1; /* start scanning interrupts again */ -#ifdef LEAVE_ACTIVE - if (irq_auto) { -/*AIR*/ INTS[irq_auto] &= ~INTS_ACT; /* deactivate specified int level */ -/*AIR*/ SPAD[irq_auto+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>IntX deactivate level %02x at UEI PSD1 %08x PSD2 %08x\n", - irq_auto, PSD1, PSD2); -/*AIR*/ irq_auto = 0; /* show done processing in blocked mode */ - } -#endif + if (!(CPUSTATUS & ONIPU)) + irq_pend = 1; /* start scanning interrupts again */ } CPUSTATUS &= ~BIT24; /* clear status word bit 24 */ MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ PSD2 &= ~(SETBBIT|RETBBIT); /* clear bits 48 & 49 to be unblocked */ SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ -#ifdef DYNAMIC_DEBUG -sim_debug(DEBUG_IRQ, &cpu_dev, - "UEI OPSD %.8x %.8x NPSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", - TPSD[0], TPSD[1], PSD1, PSD2, SPAD[0xf5], CPUSTATUS); -#endif break; case 0x8: /* EAE */ PSD1 |= AEXPBIT; /* set the enable AEXP flag in PSD 1 */ @@ -2728,10 +3062,80 @@ sim_debug(DEBUG_IRQ, &cpu_dev, break; case 0x9: /* RDSTS */ GPR[reg] = CPUSTATUS; /* get CPU status word */ + sim_debug(DEBUG_EXP, my_dev, "RDSTS CCW %08x CPUSTATUS %8x\n", CCW, CPUSTATUS); break; case 0xA: /* SIPU */ /* ignore for now */ - sim_debug(DEBUG_CMD, &cpu_dev, - "SIPU CPUSTATUS %08x SPAD[0xf9] %08x\n", CPUSTATUS, SPAD[0xf9]); + /* if we have an IPU, process SIPU instruction */ + sim_debug(DEBUG_TRAP, my_dev, + "SIPU @%s CPUSTATUS %08x SPAD[0xf9] %08x CCW %0x PSD %08x %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", + CPUSTATUS, SPAD[0xf9], CCW, PSD1, PSD2); + +#ifndef CPUONLY + if (CCW & HASIPU) { + /* CPU side = [0] IPU side = [1] */ + //GR if (IPC && IPC->atrap[PeerIndex]) { +#ifdef USE_POSIX_SEM + if (IPC->atrap[PeerIndex]) { + /* previous atrap not yet handled */ + IPC->blocked[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU blocked CPUSTATUS %08x CCW %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW); + + //GR Give it a millisec to unblock the atrap + sim_idle_ms_sleep(1); /* wait 1 ms */ +// millinap(1); /* wait 1 ms */ + } + + if (IPC->atrap[PeerIndex] == 0) { + IPC->sent[MyIndex]++; + IPC->atrap[PeerIndex] = SIGNALIPU_TRAP; + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU sent CPUSTATUS %08x CCW %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW); + } + else + IPC->dropped[MyIndex]++; +#else + if (IPC->atrap[PeerIndex]) { + /* previous atrap not yet handled if not zero */ + IPC->blocked[MyIndex]++; /* count as blocked */ + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU blocked IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW, SPAD[0xf0]); + //GR Give it a millisec to unblock the atrap + sim_idle_ms_sleep(1); /* wait 1 ms */ +// millinap(1); /* wait 1 ms */ + } + if (IPC->atrap[PeerIndex] == 0) { + lock_mutex(); /* lock mutex */ + IPC->atrap[PeerIndex] = SIGNALIPU_TRAP; + pthread_cond_signal(&IPC->cond); /* wake any waiters */ + unlock_mutex(); /* unlock mutex */ + IPC->sent[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW, SPAD[0xf0]); + } else { +// unlock_mutex(); /* unlock mutex */ + IPC->dropped[MyIndex]++; /* count dropped SIPU */ + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", CPUSTATUS, CCW, SPAD[0xf0]); + } +#endif /* USE_POSIX_SEM */ + } else +#endif + { + sim_debug(DEBUG_TRAP, my_dev, + "SIPU CPUSTATUS %08x CCW %08x\n", CPUSTATUS, CCW); +//HANGS TRAPME = IPUUNDEFI_TRAP; /* undefined IPU instruction */ +//HANGS TRAPME = SYSTEMCHK_TRAP; /* trap condition */ +//HANGS TRAPME = MACHINECHK_TRAP; /* trap condition */ +//HANGS TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ +//FIXME goto newpsd; /* handle trap */ + } break; case 0xB: /* RWCS */ /* RWCS ignore for now */ /* reg = specifies reg containing the ACS/WCS address */ @@ -2743,6 +3147,8 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* if bit 20 set, WCS enables, else addr spec error */ if ((CPUSTATUS & 0x00000800) == 0) { TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7c OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } /* Maybe TODO copy something from WCS */ @@ -2756,6 +3162,8 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* if bit 20 set, WCS enables, else addr spec error */ if ((CPUSTATUS & 0x00000800) == 0) { TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7d OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } /* Maybe TODO copy something to WCS */ @@ -2763,6 +3171,9 @@ sim_debug(DEBUG_IRQ, &cpu_dev, case 0xD: /* SEA */ if (MODES & BASEBIT) /* see if based */ goto inv; /* invalid instruction in based mode */ + sim_debug(DEBUG_IRQ, my_dev, + "SEA for extended mode PSD %08x %08x STATUS %08x\r\n", + PSD1, PSD2, CPUSTATUS); MODES |= EXTDBIT; /* set new extended flag (bit 5) in modes & PSD */ PSD1 |= EXTDBIT; /* set the enable AEXP flag in PSD1 */ CPUSTATUS |= EXTDBIT; /* into status word too */ @@ -2787,7 +3198,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, break; case 0x04>>2: /* 0x04 RR|R1|SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */ i_flags &= ~SCC; /* make sure we do not set CC's for dest value */ - switch(opr & 0xF) { + switch(OPR & 0xF) { case 0x0: /* ANR */ dest &= source; /* just an and reg to reg */ if (dest & MSIGN) @@ -2816,14 +3227,14 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* 29 - Enable Operand Cache Bank 0 On = 1 Off = 0 */ /* 30 - Enable Operand Cache Bank 1 On = 1 Off = 0 */ /* 31 - Bypass Instruction Cache Bank 1 On = 1 Off = 0 */ - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "CMC V6/67 GPR[%02x] = %04x CMCR = %08x CPU STATUS SPAD[f9] = %08x\r\n", reg, GPR[reg], CMCR, SPAD[0xf9]); CMCR = GPR[reg]; /* write reg bits 23-31 to cache memory controller */ i_flags &= ~SD; /* turn off store dest for this instruction */ } else if (CPU_MODEL == MODEL_V9) { - sim_debug(DEBUG_EXP, &cpu_dev, + sim_debug(DEBUG_EXP, my_dev, "CMC V9 GPR[%02x] = %08x CMCR = %08x CPU STATUS SPAD[f9] = %08x\r\n", reg, GPR[reg], CMCR, SPAD[0xf9]); CMCR = GPR[reg]; /* write reg bits 23-31 to cache memory controller */ @@ -2845,7 +3256,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* 7 - Read & Lock Enabled (=1)/Disabled (=0) */ /* 8-12 - Lower Bound of Shared Memory */ /* 3-31 - Reserved and must be zero */ - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "SMC V6/67 GPR[%02x] = %08x SMCR = %08x CPU STATUS SPAD[f9] = %08x\n", reg, GPR[reg], SMCR, SPAD[0xf9]); SMCR = GPR[reg]; /* write reg bits 0-12 to shared memory controller */ @@ -2939,31 +3350,36 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((GPR[reg] & 0x80000000) && (CPU_MODEL < MODEL_V9)) { /* if bit 0 of reg set, return (default 0) CPU Configuration Word */ dest = CCW; /* no cache or shared memory */ - /* make sure bit 19 is zero saying IPU not present */ - dest &= ~0x00001000; /* reset IPU bit for DIAGS */ /* bit 22 set for access ECO present */ dest |= 0x00000200; /* set ECO bit for DIAGS */ /* Try setting cache on bits 27-31 */ dest |= 0x0000001f; /* set SIM bit for DIAGS */ } else + /* FIXME */ if ((GPR[reg] & 0x80000000) && (CPU_MODEL == MODEL_V9)) { /* if bit 0 of reg set, return Cache/Shadow Configuration Word */ CMSMC = 0xffff0000; /* no CPU/IPU Cache/Shadow unit present */ CMSMC |= 0x00000000; /* CPU Cache/Shadow unit present */ - CMSMC |= 0x00000800; /* bit 20, IPU not present */ + if (CCW & BIT27) + /* IPU is present, reset the status bit */ + dest &= ~BIT20; /* reset IPU status bit */ + else + /* IPU is not present, set the status bit */ + CMSMC |= BIT20; /* set IPU status bit */ +// CMSMC |= 0x00000800; /* bit 20, IPU not present */ CMSMC |= 0x00000200; /* bit 22, Access Protection ECO present */ CMSMC |= 0x0000001f; /* CPU Firmware Version 1/Rev level 0 */ - dest = CMSMC; /* return starus */ + dest = CMSMC; /* return status */ } else if ((GPR[reg] & 0x40000000) && (CPU_MODEL == MODEL_V9)) { /* if bit 1 of reg set, return CPU Shadow Memory Configuration Word */ CSMCW = 0x00000000; /* no Shadow unit present */ - dest = CSMCW; /* return starus */ + dest = CSMCW; /* return status */ } else if ((GPR[reg] & 0x20000000) && (CPU_MODEL == MODEL_V9)) { /* if bit 2 of reg set, return Cache Memory Configuration Word */ ISMCW = 0x00000000; /* no Shadow unit present */ - dest = ISMCW; /* return starus */ + dest = ISMCW; /* return status */ } else if ((GPR[reg] & BIT0) == 0x00000000) { /* if bit 0 of reg not set, return PSD2 */ @@ -2994,7 +3410,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, case 0x08>>2: /* 0x08 SCC|RR|R1|SD|HLF - */ /* ORR or ORRM */ dest |= source; /* or the regs into dest reg */ - switch(opr & 0x0f) { + switch(OPR & 0x0f) { case 0x8: /* this is ORRM op */ dest &= GPR[4]; /* mask with reg 4 contents */ /* drop thru */ @@ -3012,7 +3428,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, case 0x0C>>2: /* 0x0c SCC|RR|R1|SD|HLF - SCC|SD|HLF */ /* EOR or EORM */ dest ^= source; /* exclusive or the regs into dest reg */ - switch(opr & 0x0f) { + switch(OPR & 0x0f) { case 0x8: /* this is EORM op */ dest &= GPR[4]; /* mask with reg 4 contents */ /* drop thru */ @@ -3029,7 +3445,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, break; case 0x10>>2: /* 0x10 HLF - HLF */ /* CAR or (basemode SACZ ) */ - if ((opr & 0xF) == 0) { /* see if CAR instruction */ + if ((OPR & 0xF) == 0) { /* see if CAR instruction */ /* handle non basemode/basemode CAR instr */ if ((int32)GPR[reg] < (int32)GPR[sreg]) CC = CC3BIT; /* Rd < Rs; negative */ @@ -3080,7 +3496,7 @@ sacz: /* non basemode SCZ enters here */ break; case 0x14>>2: /* 0x14 HLF - HLF */ /* CMR compare masked with reg */ - if (opr & 0xf) { /* any subop not zero is error */ + if (OPR & 0xf) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -3097,13 +3513,13 @@ sacz: /* non basemode SCZ enters here */ case 0x18>>2: /* 0x18 HLF - HLF */ /* SBR, (basemode ZBR, ABR, TBR */ if (MODES & BASEBIT) { /* handle basemode ZBR, ABR, TBR */ - if ((opr & 0xC) == 0x0) /* SBR instruction */ + if ((OPR & 0xC) == 0x0) /* SBR instruction */ goto sbr; /* use nonbase SBR code */ - if ((opr & 0xC) == 0x4) /* ZBR instruction */ + if ((OPR & 0xC) == 0x4) /* ZBR instruction */ goto zbr; /* use nonbase ZBR code */ - if ((opr & 0xC) == 0x8) /* ABR instruction */ + if ((OPR & 0xC) == 0x8) /* ABR instruction */ goto abr; /* use nonbase ABR code */ - if ((opr & 0xC) == 0xC) /* TBR instruction */ + if ((OPR & 0xC) == 0xC) /* TBR instruction */ goto tbr; /* use nonbase TBR code */ inv: TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ @@ -3112,7 +3528,7 @@ inv: goto newpsd; /* handle trap */ } else { /* handle non basemode SBR */ - if (opr & 0xc) { /* any subop not zero is error */ + if (OPR & 0xc) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -3121,7 +3537,7 @@ inv: sbr: /* handle basemode too */ /* move the byte field bits 14-15 to bits 27-28 */ /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = (((OPR << 3) & 0x18) | reg); /* get # bits to shift right */ bc = BIT0 >> bc; /* make a bit mask of bit number */ t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -3134,8 +3550,8 @@ sbr: /* handle basemode too */ case 0x1C>>2: /* 0x1C HLF - HLF */ /* ZBR (basemode SRA, SRL, SLA, SLL) */ if (MODES & BASEBIT) { /* handle basemode SRA, SRL, SLA, SLL */ - bc = opr & 0x1f; /* get bit shift count */ - if ((opr & 0x60) == 0x00) { /* SRA instruction */ + bc = OPR & 0x1f; /* get bit shift count */ + if ((OPR & 0x60) == 0x00) { /* SRA instruction */ temp = GPR[reg]; /* get reg value to shift */ t = temp & FSIGN; /* sign value */ for (ix=0; ix>= bc; /* value to be output */ break; } - if ((opr & 0x60) == 0x40) { /* SLA instruction */ + if ((OPR & 0x60) == 0x40) { /* SLA instruction */ temp = GPR[reg]; /* get reg value to shift */ t = temp & FSIGN; /* sign value */ ovr = 0; /* set ovr off */ @@ -3173,13 +3589,13 @@ sbr: /* handle basemode too */ } break; } - if ((opr & 0x60) == 0x60) { /* SLL instruction */ + if ((OPR & 0x60) == 0x60) { /* SLL instruction */ GPR[reg] <<= bc; /* value to be output */ break; } break; } else { /* handle nonbase ZBR */ - if (opr & 0xc) { /* any subop not zero is error */ + if (OPR & 0xc) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -3188,7 +3604,7 @@ sbr: /* handle basemode too */ zbr: /* handle basemode too */ /* move the byte field bits 14-15 to bits 27-28 */ /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = (((OPR << 3) & 0x18) | reg); /* get # bits to shift right */ bc = BIT0 >> bc; /* make a bit mask of bit number */ t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -3203,13 +3619,15 @@ zbr: /* handle basemode too */ if (MODES & BASEBIT) { /* handle basemode SRAD, SRLD, SLAD, SLLD */ if (reg & 1) { /* see if odd reg specified */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7e OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ - bc = opr & 0x1f; /* get bit shift count */ + bc = OPR & 0x1f; /* get bit shift count */ source = dest & DMSIGN; /* 64 bit sign value */ - switch (opr & 0x60) { + switch (OPR & 0x60) { case 0x00: /* SRAD instruction */ for (ix=0; ix>= 1; /* shift bit 0 right one bit */ @@ -3253,7 +3671,7 @@ zbr: /* handle basemode too */ break; } else { /* handle nonbase mode ABR */ - if (opr & 0xc) { /* any subop not zero is error */ + if (OPR & 0xc) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -3262,7 +3680,7 @@ zbr: /* handle basemode too */ abr: /* basemode ABR too */ /* move the byte field bits 14-15 to bits 27-28 */ /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ - bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = (((OPR << 3) & 0x18) | reg); /* get # bits to shift right */ bc = BIT0 >> bc; /* make a bit mask of bit number */ temp = GPR[sreg]; /* get reg value to add bit to */ t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ @@ -3288,9 +3706,9 @@ abr: /* basemode ABR too */ case 0x24>>2: /* 0x24 HLF - HLF */ /* TBR (basemode SRC) */ if (MODES & BASEBIT) { /* handle SRC basemode */ - bc = opr & 0x1f; /* get bit shift count */ + bc = OPR & 0x1f; /* get bit shift count */ temp = GPR[reg]; /* get reg value to shift */ - if ((opr & 0x60) == 0x40) { /* SLCBR instruction */ + if ((OPR & 0x60) == 0x40) { /* SLCBR instruction */ for (ix=0; ix> bc; /* make a bit mask of bit number */ t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -3327,7 +3745,7 @@ tbr: /* handle basemode TBR too * break; case 0x28>>2: /* 0x28 HLF - HLF */ /* Misc OP REG instructions */ - switch(opr & 0xF) { + switch(OPR & 0xF) { case 0x0: /* TRSW */ if (MODES & BASEBIT) temp = 0x78FFFFFE; /* bits 1-4 and 24 bit addr for based mode */ @@ -3338,7 +3756,7 @@ tbr: /* handle basemode TBR too * /* update the PSD with new address from reg */ PSD1 &= ~temp; /* clean the bits to be changed */ PSD1 |= (addr & temp); /* insert the CC's and address */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "TRSW REG %01x PSD %08x %08x modes %08x temp %06x\n", reg, PSD1, PSD2, MODES, temp); i_flags |= BT; /* we branched, so no PC update */ @@ -3377,6 +3795,8 @@ tbr: /* handle basemode TBR too * if ((BR[2] & 0x7) != 0) { /* Fault, must be dw bounded address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7f OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } cfp = BR[2] & 0x00fffff8; /* clean the cfp address to 24 bit dw */ @@ -3397,6 +3817,8 @@ tbr: /* handle basemode TBR too * /* if cfp and cfp+15w are in different maps, then addr exception error */ if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) { TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7g OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -3486,7 +3908,7 @@ tbr: /* handle basemode TBR too * addr = GPR[sreg]; /* reg contents specified by Rs */ bc = 0; - switch(opr & 0xF) { + switch(OPR & 0xF) { case 0x0: /* TRR */ /* SCC|SD|R1 */ temp = addr; /* set value to go to GPR[reg] */ bc = 1; /* set CC's at end */ @@ -3553,7 +3975,7 @@ tbr: /* handle basemode TBR too * /* get PSD pointed to by real addr in Rd (temp) */ DPSD[0] = RMW(temp); /* get word one of psd */ DPSD[1] = RMW(temp+4); /* get word two of psd */ - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp %06x\n", PSD1, PSD2, DPSD[0], DPSD[1], MODES, temp); if ((DPSD[1] & MAPBIT) == 0) /* if PSD2 is unmapped, treat as NOP */ @@ -3563,13 +3985,13 @@ tbr: /* handle basemode TBR too * temp2 = MODES; /* save modes bits through load_maps call */ MODES = DPSD[0] & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ MODES |= MAPMODE; /* set mapped mode flag for load_maps call */ - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp2 %08x\n", PSD1, PSD2, DPSD[0], DPSD[1], MODES, temp2); /* we need to load the new maps */ TRAPME = load_maps(DPSD, 1); /* load maps for new PSD */ - sim_debug(DEBUG_CMD, &cpu_dev, - "LMAP TRAPME %08x MAPC[8-c] %08x %08x %08x %08x %08x %08x\n", + sim_debug(DEBUG_CMD, my_dev, + "LMAP TRAPME %02x MAPC[8-c] %08x %08x %08x %08x %08x %08x\n", TRAPME, MAPC[7], MAPC[8], MAPC[9], MAPC[10], MAPC[11], MAPC[12]); MODES = temp2; /* restore modes flags */ if (TRAPME) { @@ -3618,7 +4040,7 @@ tbr: /* handle basemode TBR too * CPUSTATUS |= BIT22; /* HS Floating is set to off */ /* make sure WCS is off and prom mode set to 0 (on) */ CPUSTATUS &= ~(BIT20|BIT21); /* make zero */ - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "SETCPU orig %08x user bits %08x New CPUSTATUS %08x SPAD[f9] %08x\n", temp2, temp, CPUSTATUS, SPAD[0xf9]); SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ @@ -3660,7 +4082,7 @@ tbr: /* handle basemode TBR too * temp |= 0x80000000; /* show hit BIT is set */ temp |= ((TLB[addr] & 0xf8000000) >> 16); /* add in protect bits */ if ((addr < 0x26) || (addr > 0x7f8)) - sim_debug(DEBUG_CMD, &cpu_dev, + sim_debug(DEBUG_CMD, my_dev, "TMAPR #%4x val %08x TLB %08x RMR %04x MAPC %08x\n", addr, temp, TLB[addr], RMR(addr<<1), MAPC[addr/2]); } @@ -3704,6 +4126,8 @@ tbr: /* handle basemode TBR too * t = (GPR[reg] >> 16) & 0xff; /* get SPAD address from Rd (6-8) */ temp2 = SPAD[t]; /* get old SPAD data */ SPAD[t] = GPR[sreg]; /* store Rs into SPAD */ +// sim_debug(DEBUG_TRAP, my_dev, +// "TRSC SPAD[%04x] B4 %08x New %08x\n", t, temp2, GPR[sreg]); break; case 0xF: /* TSCR */ /* Transfer scratchpad to register */ @@ -3717,6 +4141,8 @@ tbr: /* handle basemode TBR too * } t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (9-11) */ temp = SPAD[t]; /* get SPAD data into Rd (6-8) */ +// sim_debug(DEBUG_TRAP, my_dev, +// "TSCR SPAD[%04x] Val %08x\n", t, temp); break; } GPR[reg] = temp; /* save the temp value to Rd reg */ @@ -3736,7 +4162,7 @@ skipit: case 0x30>>2: /* 0x30 */ /* CALM */ /* Process CALM for 32/27 when in left hw, else invalid */ if ((CPU_MODEL <= MODEL_87) && (CPU_MODEL != MODEL_67)) { - uint32 oldstatus = CPUSTATUS; /* keep for retain blocking state */ +// uint32 oldstatus = CPUSTATUS; /* keep for retain blocking state */ /* DIAG error for 32/27 or 32/87 only */ if ((PSD1 & 2) != 0) /* is it lf hw instruction */ goto inv; /* invalid instr if in rt hw */ @@ -3756,61 +4182,50 @@ skipit: PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); /* bump pc by 1 wd */ M[t>>2] = PSD1 & 0xfffffffe; /* store PSD 1 + 1HW to point to next instruction */ M[(t>>2)+1] = PSD2; /* store PSD 2 */ + TPSD1 = PSD1; /* save old PSD1 */ + TPSD2 = PSD2; /* save old PSD2 */ PSD1 = M[(t>>2)+2]; /* get new PSD 1 */ PSD2 = (M[(t>>2)+3] & ~0x3fff) | bc; /* get new PSD 2 w/old cpix */ - M[(t>>2)+4] = opr & 0x03FF; /* store calm number in bits 6-15 */ + M[(t>>2)+4] = OPR & 0x03FF; /* store calm number in bits 6-15 */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + sim_debug(DEBUG_IRQ, my_dev, + "CALM @ %.6x NPSD %08x %04x OPSD %08x %04x SPAD %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, SPAD[0xf5], CPUSTATUS); + + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + CPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ + } /* set the mode bits and CCs from the new PSD */ CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert into CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ - /* set new map mode and interrupt blocking state in CPUSTATUS */ - if (PSD2 & MAPBIT) { - CPUSTATUS |= BIT8; /* set bit 8 of cpu status */ - MODES |= MAPMODE; /* set mapped mode */ - } else { - CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ -/*TRY_01072022*/ MODES &= ~MAPMODE; /* reset mapped mode */ - } - - /* set interrupt blocking state */ - if ((PSD2 & RETBBIT) == 0) { /* is it retain blocking state */ - if (PSD2 & SETBBIT) { /* no, is it set blocking state */ - CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ - MODES |= BLKMODE; /* set blocked mode */ - } else { - CPUSTATUS &= ~BIT24; /* no, reset blk state in cpu status bit 24 */ - MODES &= ~BLKMODE; /* reset blocked mode */ - irq_pend = 1; /* start scanning interrupts again */ -#ifdef LEAVE_ACTIVE - if (irq_auto) { -/*AIR*/ INTS[irq_auto] &= ~INTS_ACT; /* deactivate specified int level */ -/*AIR*/ SPAD[irq_auto+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>IntX deactivate level %02x at CALM PSD1 %08x\n", - irq_auto, PSD1); -/*AIR*/ irq_auto = 0; /* show done processing in blocked mode */ - } -#endif - } - } else { - /* handle retain blocking state */ - PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ - /* set new blocking state in PSD2 */ - PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ - MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ - if (oldstatus & BIT24) { /* see if old mode is blocked */ - PSD2 |= SETBBIT; /* set to blocked state */ - MODES |= BLKMODE; /* set blocked mode */ + if ((PSD2 & SETBBIT) == 0) { /* see if new mode is unblocked */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + /* we changed from blocked to unblocked */ + if (!(CPUSTATUS & ONIPU)) + irq_pend = 1; /* start scanning interrupts again */ } } SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ TRAPME = 0; /* not to be processed as trap */ - goto newpsd; /* new psd loaded */ + drop_nop = 0; /* nothing to drop */ + i_flags |= BT; /* do not update pc */ } else { // fprintf(stderr, "got CALM trap\r\n"); goto inv; /* invalid instr */ @@ -3828,7 +4243,7 @@ skipit: break; case 0x38>>2: /* 0x38 HLF - HLF */ /* REG - REG floating point */ - switch(opr & 0xF) { + switch(OPR & 0xF) { case 0x0: /* ADR */ temp = GPR[reg]; /* reg contents specified by Rd */ addr = GPR[sreg]; /* reg contents specified by Rs */ @@ -3849,13 +4264,13 @@ skipit: temp = GPR[reg]; /* reg contents specified by Rd */ addr = GPR[sreg]; /* reg contents specified by Rs */ /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */ - if ((opr & 0xF) == 0x3) { + if ((OPR & 0xF) == 0x3) { addr = NEGATE32(addr); /* subtract, so negate source */ } temp2 = s_adfw(temp, addr, &CC); /* do ADFW */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "%s GPR[%d] %08x addr %08x result %08x CC %08x\n", - (opr&0xf)==3 ? "SURFW":"ADRFW", + (OPR&0xf)==3 ? "SURFW":"ADRFW", reg, GPR[reg], GPR[sreg], temp2, CC); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ @@ -3898,7 +4313,7 @@ skipit: addr = GPR[sreg]; /* reg contents specified by Rs */ /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */ temp2 = (uint32)s_dvfw(temp, addr, &CC); /* divide reg by sreg */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "DVRFW GPR[%d] %08x src %08x result %08x\n", reg, GPR[reg], addr, temp2); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -3921,7 +4336,7 @@ skipit: /* convert from 32 bit float to 32 bit fixed */ addr = GPR[sreg]; /* reg contents specified by Rs */ temp2 = s_fixw(addr, &CC); /* do conversion */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "FIXW GPR[%d] %08x result %08x\n", sreg, GPR[sreg], temp2); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -3945,7 +4360,7 @@ skipit: addr = GPR[sreg]; /* reg contents specified by Rs */ /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */ temp2 = s_mpfw(temp, addr, &CC); /* mult reg by sreg */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "MPRFW GPR[%d] %08x src %08x result %08x\n", reg, GPR[reg], addr, temp2); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -3968,7 +4383,7 @@ skipit: /* convert from 32 bit integer to 32 bit float */ addr = GPR[sreg]; /* reg contents specified by Rs */ GPR[reg] = s_fltw(addr, &CC); /* do conversion & set CC's */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "FLTW GPR[%d] %08x result %08x\n", sreg, GPR[sreg], GPR[reg]); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -4001,14 +4416,14 @@ skipit: td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ - if ((opr & 0xF) == 0xb) { + if ((OPR & 0xF) == 0xb) { source = NEGATE32(source); /* make negative for subtract */ } dest = s_adfd(td, source, &CC); /* do ADFD */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "%s GPR[%d] %08x %08x src %016llx result %016llx\n", - (opr&0xf)==8 ? "ADRFD":"SURFD", reg, GPR[reg], GPR[reg+1], source, dest); + (OPR&0xf)==8 ? "ADRFD":"SURFD", reg, GPR[reg], GPR[reg+1], source, dest); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ if (CC & CC1BIT) { /* check for arithmetic exception */ @@ -4076,7 +4491,7 @@ doovr4: source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ dest = s_dvfd(td, source, &CC); /* divide double values */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "DVRFD GPR[%d] %08x %08x src %016llx result %016llx\n", reg, GPR[reg], GPR[reg+1], source, dest); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -4106,7 +4521,7 @@ doovr4: source = (((t_uint64)GPR[sreg]) << 32) | ((t_uint64)GPR[sreg+1]); /* convert from 64 bit double to 64 bit int */ dest = s_fixd(source, &CC); - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "FIXD GPR[%d] %08x %08x result %016llx\n", sreg, GPR[sreg], GPR[sreg+1], dest); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -4136,7 +4551,7 @@ doovr4: source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ dest = s_mpfd(td, source, &CC); /* multiply double values */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "MPRFD GPR[%d] %08x %08x src %016llx result %016llx\n", reg, GPR[reg], GPR[reg+1], source, dest); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -4165,7 +4580,7 @@ doovr4: source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ dest = s_fltd(source, &CC); /* do conversion & set CC's */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "FLTD GPR[%d] %08x %08x result %016llx\n", sreg, GPR[sreg], GPR[sreg+1], dest); PSD1 &= 0x87FFFFFE; /* clear the old CC's */ @@ -4191,7 +4606,7 @@ doovr4: temp = GPR[reg]; /* get negative value to add */ temp2 = GPR[sreg]; /* get negative value to add */ addr = NEGATE32(GPR[sreg]); /* reg contents specified by Rs */ - switch(opr & 0xF) { + switch(OPR & 0xF) { case 0x0: /* SUR */ t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ @@ -4251,7 +4666,7 @@ doovr4: TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ goto newpsd; /* go execute the trap now */ } - if (opr & 0xf) { /* any subop not zero is error */ + if (OPR & 0xf) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -4281,7 +4696,7 @@ doovr4: TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ goto newpsd; /* go execute the trap now */ } - if (opr & 0xf) { /* any subop not zero is error */ + if (OPR & 0xf) { /* any subop not zero is error */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ @@ -4352,7 +4767,7 @@ doovr3: goto inv; /* invalid instruction in nonbased mode */ if (FC != 0) { /* word address only */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC8 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -4374,7 +4789,7 @@ doovr3: goto inv; /* invalid instruction in nonbased mode */ if ((FC & 3) != 0) { /* word address only */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "ADDRSPEC9 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -4391,6 +4806,8 @@ doovr3: if ((BR[2] & 0x7) != 0) { /* Fault, must be dw bounded address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9a OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -4408,6 +4825,8 @@ doovr3: if ((temp & 0x3) != 0) { /* check for word aligned */ /* Fault, must be word bounded address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9b OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -4429,6 +4848,8 @@ doovr3: /* if cfp and cfp+15w are in different maps, then addr exception error */ if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) { TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9c OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -4460,6 +4881,8 @@ doovr3: if ((temp & 0x3) != 0) { /* check for word aligned */ /* Fault, must be word bounded address */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9d OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } @@ -4484,7 +4907,7 @@ doovr3: TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ goto newpsd; /* handle trap */ } - if (opr & 0xf) { /* any subop not zero is error */ + if (OPR & 0xf) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -4493,7 +4916,7 @@ doovr3: /* exponent must not be zero or all 1's */ /* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */ temp = s_nor(GPR[reg], &GPR[sreg]); - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "NOR GPR[%d] %08x result %08x exp %02x\n", reg, GPR[reg], temp, GPR[sreg]); GPR[reg] = temp; @@ -4510,7 +4933,7 @@ doovr3: TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ goto newpsd; /* go execute the trap now */ } - if (opr & 0xf) { /* any subop not zero is error */ + if (OPR & 0xf) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -4521,7 +4944,7 @@ doovr3: td = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]); /* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */ dest = s_nord(td, &GPR[sreg]); - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "NORD GPR[%d] %08x %08x result %016llx exp %02x\n", reg, GPR[reg], GPR[reg+1], dest, GPR[sreg]); GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ @@ -4531,7 +4954,7 @@ doovr3: case 0x68>>2: /* 0x68 HLF - INV */ /* non basemode SCZ */ if (MODES & BASEBIT) goto inv; /* invalid instruction */ - if (opr & 0xf) { /* any subop not zero is error */ + if (OPR & 0xf) { /* any subop not zero is error */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ @@ -4542,10 +4965,10 @@ doovr3: case 0x6C>>2: /* 0x6C HLF - INV */ /* non basemode SRA & SLA */ if (MODES & BASEBIT) goto inv; /* invalid instruction */ - bc = opr & 0x1f; /* get bit shift count */ + bc = OPR & 0x1f; /* get bit shift count */ temp = GPR[reg]; /* get reg value to shift */ t = temp & FSIGN; /* sign value */ - if (opr & 0x0040) { /* is this SLA */ + if (OPR & 0x0040) { /* is this SLA */ ovr = 0; /* set ovr off */ for (ix=0; ix>2: /* 0x70 SD|HLF - INV */ /* non-basemode SRL & SLL */ if (MODES & BASEBIT) goto inv; /* invalid instruction in basemode */ - bc = opr & 0x1f; /* get bit shift count */ - if (opr & 0x0040) /* is this SLL, bit 9 set */ + bc = OPR & 0x1f; /* get bit shift count */ + if (OPR & 0x0040) /* is this SLL, bit 9 set */ GPR[reg] <<= bc; /* shift left #bits */ else GPR[reg] >>= bc; /* shift right #bits */ @@ -4587,9 +5010,9 @@ doovr3: case 0x74>>2: /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */ if (MODES & BASEBIT) goto inv; /* invalid instruction in basemode */ - bc = opr & 0x1f; /* get bit shift count */ + bc = OPR & 0x1f; /* get bit shift count */ temp = GPR[reg]; /* get reg value to shift */ - if (opr & 0x0040) { /* is this SLC, bit 9 set */ + if (OPR & 0x0040) { /* is this SLC, bit 9 set */ for (ix=0; ix>= bc; /* shift right #bits */ @@ -4672,31 +5095,32 @@ doovr3: TRAPME = RealAddr(addr, &temp, &t, MEM_RD); // diag allows any addr if mapped if (TRAPME != ALLOK) { - sim_debug(DEBUG_TRAP, &cpu_dev, - "At LEAR with TRAPME %04x addr %08x\n", TRAPME, addr); + sim_debug(DEBUG_TRAP, my_dev, + "At LEAR with TRAPME %02x addr %08x\n", TRAPME, addr); goto newpsd; /* memory read error or map fault */ } /* set access bit for mapped addresses */ if ((CPU_MODEL >= MODEL_V6) && (MODES & MAPMODE)) { - uint32 map, mix, nix, msdl, mpl, mmap; + uint32 map, mix, nix, msdl, mpl, Mmap; nix = (addr >> 13) & 0x7ff; /* get 11 bit map value */ /* check our access to the memory */ switch (t & 0x0e) { case 0x0: case 0x2: /* O/S or user has no read/execute access, do protection violation */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "LEAR readI protect error @ %06x prot %02x modes %08x page %04x\n", + sim_debug(DEBUG_TRAP, my_dev, + "LEAR read protect error @ %06x prot %02x modes %08x page %04x\n", addr, t, MODES, nix); if (CPU_MODEL == MODEL_V9) TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ else TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ - return MPVIOL; /* return memory protection violation */ + TRAPME = MPVIOL; /* memory protection violation */ + goto newpsd; /* process error */ case 0x4: case 0x6: case 0x8: case 0xc: case 0xa: case 0xe: /* O/S or user has read/execute access, no protection violation */ - sim_debug(DEBUG_DETAIL, &cpu_dev, - "LEAR readJ protect is ok @ %06x prot %02x modes %08x page %04x\n", + sim_debug(DEBUG_DETAIL, my_dev, + "LEAR read protect is ok @ %06x prot %02x modes %08x page %04x\n", addr, t, MODES, nix); } /* we have read access, so go set the access bit in the map entry */ @@ -4708,17 +5132,17 @@ doovr3: mix = nix-BPIX; /* get map index in memory */ msdl = RMW(mpl+CPIX+4); /* get mpl entry for given CPIX */ } - mmap = RMH(msdl+(mix<<1)); /* map content from memory */ + Mmap = RMH(msdl+(mix<<1)); /* map content from memory */ map = RMR((nix<<1)); /* read the map cache contents */ if (((map & 0x800) == 0)) { /* see if access bit is already on */ - mmap |= 0x800; /* set the accessed bit in the map cache entry */ + Mmap |= 0x800; /* set the accessed bit in the map cache entry */ map |= 0x800; /* set the accessed bit in the memory map entry */ WMR((nix<<1), map); /* store the map reg contents into cache */ TLB[nix] |= 0x0c000000; /* set the accessed & hit bits in TLB too */ - WMH(msdl+(mix<<1), mmap); /* save modified memory map with access bit set */ - sim_debug(DEBUG_EXP, &cpu_dev, + WMH(msdl+(mix<<1), Mmap); /* save modified memory map with access bit set */ + sim_debug(DEBUG_EXP, my_dev, "LEAR Laddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n", - addr, nix, TLB[nix], map, mmap); + addr, nix, TLB[nix], map, Mmap); } } @@ -4909,9 +5333,29 @@ meoa: /* merge point for eor, and, or */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ goto newpsd; /* go execute the trap now */ } +#ifndef CPUONLY + /* if we have an IPU set the semaphore or wait */ + if (CCW & HASIPU) { +#ifdef USE_POSIX_SEM + set_simsem(); +#else + lock_mutex(); +#endif + } +#endif if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + { +#ifndef CPUONLY + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif +#endif goto newpsd; /* memory read error or map fault */ - + } t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ /* use C bits and bits 6-8 (reg) to generate shift bit count */ bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ @@ -4922,8 +5366,26 @@ meoa: /* merge point for eor, and, or */ PSD1 |= t; /* update the CC's in the PSD */ temp |= bc; /* set the bit in temp */ if ((TRAPME = Mem_write(addr, &temp))) { /* put word back into memory */ +#ifndef CPUONLY + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif +#endif goto newpsd; /* memory write error or map fault */ } +#ifndef CPUONLY + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif +#endif break; case 0x9C>>2: /* 0x9C ADR - ADR */ /* ZBM */ @@ -4932,8 +5394,29 @@ meoa: /* merge point for eor, and, or */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ goto newpsd; /* go execute the trap now */ } +#ifndef CPUONLY + /* if we have an IPU set the semaphore or wait */ + if (CCW & HASIPU) { +#ifdef USE_POSIX_SEM + set_simsem(); +#else + lock_mutex(); +#endif + } +#endif if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + { +#ifndef CPUONLY + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif +#endif goto newpsd; /* memory read error or map fault */ + } t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ /* use C bits and bits 6-8 (reg) to generate shift bit count */ @@ -4945,8 +5428,26 @@ meoa: /* merge point for eor, and, or */ PSD1 |= t; /* update the CC's in the PSD */ temp &= ~bc; /* reset the bit in temp */ if ((TRAPME = Mem_write(addr, &temp))) { /* put word into memory */ +#ifndef CPUONLY + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif +#endif goto newpsd; /* memory write error or map fault */ } +#ifndef CPUONLY + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif +#endif break; case 0xA0>>2: /* 0xA0 ADR - ADR */ /* ABM */ @@ -5018,59 +5519,31 @@ meoa: /* merge point for eor, and, or */ IR = temp; /* get instruction from memory */ if (FC == 3) /* see if right halfword specified */ IR <<= 16; /* move over the HW instruction */ + if (IPU_MODEL && (CPUSTATUS & ONIPU)) { + /* on IPU : */ + sim_debug(DEBUG_INST, my_dev, + "IPU EXM IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + if ((IR & 0xFC000000) == 0xFC000000 || /* No I/O targets */ + (IR & 0xFFFF0000) == 0x00060000) { /* No BEI target */ + TRAPME = IPUUNDEFI_TRAP; + i_flags |= BT; /* leave PC unchanged, so no PC update */ + goto newpsd; + } + } else { + sim_debug(DEBUG_INST, my_dev, + "CPU EXM IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + } #ifdef DIAG_SAYS_OK_TO_EXECUTE_ANOTHER_EXECUTE - if ((IR & 0xFC7F0000) == 0xC8070000 || /* No EXR target */ - (IR & 0xFF800000) == 0xA8000000 || /* No EXM target */ - (IR & 0xFC000000) == 0x80000000) { -#else /* 32/67 diag says execute of execute is OK */ - if ((IR & 0xFC000000) == 0x80000000) { -#endif - /* Fault, attempt to execute another EXR, EXRR, EXM, or LEAR */ + if ((IR & 0xFC7F0000) == 0xC8070000 || /* No EXR target */ + (IR & 0xFF800000) == 0xA8000000) { /* No EXM target */ + /* Fault, attempt to execute another EXR, EXRR, or EXM */ goto inv; /* invalid instruction */ } - EXM_EXR = 4; /* set PC increment for EXM */ - - OPSD1 &= 0x87FFFFFE; /* clear the old PSD CC's */ - OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the old PSD */ - /* TODO Update other history information for this instruction */ - if (hst_lnt) { - hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */ - hst[hst_p].npsd1 = PSD1; /* save new psd1 */ - hst[hst_p].npsd2 = PSD2; /* save new psd2 */ - hst[hst_p].modes = MODES; /* save current mode bits */ - hst[hst_p].modes |= (CPUSTATUS & BIT24); /* save blocking mode bit */ - for (ix=0; ix<8; ix++) { - hst[hst_p].reg[ix] = GPR[ix]; /* save reg */ - hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */ - } - } - - /* DEBUG_INST support code */ - OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ - OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ - /* output mapped/unmapped */ - if (MODES & BASEBIT) - BM = 'B'; - else - BM = 'N'; - if (MODES & MAPMODE) - MM = 'M'; - else - MM = 'U'; - if (CPUSTATUS & BIT24) - BK = 'B'; - else - BK = 'U'; - sim_debug(DEBUG_INST, &cpu_dev, "%c%c%c %.8x %.8x %.8x ", - BM, MM, BK, OPSD1, PSD2, OIR); - if (cpu_dev.dctrl & DEBUG_INST) - fprint_inst(sim_deb, OIR, 0); /* display instruction */ - sim_debug(DEBUG_INST, &cpu_dev, - "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_INST, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - goto exec; /* go execute the instruction */ +#endif + goto dohist; /* merge with EXR code */ break; case 0xAC>>2: /* 0xAC SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* Lx */ @@ -5249,8 +5722,8 @@ doovr: if (addr & 0x8000) /* negative */ addr |= LMASK; /* extend sign */ - switch(opr & 0xF) { /* switch on aug code */ - case 0x0: /* LI */ /* SCC | SD */ + switch(OPR & 0xF) { /* switch on aug code */ + case 0x0: /* LI */ /* SCC | SD */ GPR[reg] = addr; /* put immediate value into reg */ set_CCs(addr, ovr); /* set the CC's, CC1 = ovr */ break; @@ -5259,22 +5732,22 @@ doovr: addr = NEGATE32(addr); /* just make value a negative add */ /* drop through */ case 0x1: /* ADI */ - t = (temp & FSIGN) != 0; /* set flag for sign bit not set in reg value */ - t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the extended immediate value */ - temp = temp + addr; /* now add the numbers */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in reg value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the extended immediate value */ + temp = temp + addr; /* now add the numbers */ /* if both signs are neg and result sign is positive, overflow */ /* if both signs are pos and result sign is negative, overflow */ if ((t == 3 && (temp & FSIGN) == 0) || (t == 0 && (temp & FSIGN) != 0)) ovr = 1; /* we have an overflow */ - GPR[reg] = temp; /* save the result */ - set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + GPR[reg] = temp; /* save the result */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ /* the arithmetic exception will be handled */ /* after instruction is completed */ /* check for arithmetic exception trap enabled */ if (ovr && (MODES & AEXPBIT)) { - TRAPME = AEXPCEPT_TRAP; /* set the trap type */ - goto newpsd; /* go execute the trap now */ + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* go execute the trap now */ } break; @@ -5358,157 +5831,137 @@ doovr2: /* */ case 0x6: /* SVC none - none */ /* Supervisor Call Trap */ { -#ifdef MPXTEST /* set to 1 for traceme in MPX to work */ - /* get current MPX task name */ - int j; - char n[9]; - uint32 sq59 = M[0x930>>2]; /* get C.SQ59 headcell */ - uint32 dqe = M[0x8e8>>2]; /* get DQE of current task */ - - sim_debug(DEBUG_IRQ, &cpu_dev, - "SVC start sq59 %04x dqe %04x\n",sq59, dqe); - if (sq59 != 0x930) - goto skipdqe2; /* not running on mpx, skip */ - for (j=0; j<8; j++) { /* get the task name */ - n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff; - if (n[j] == 0) - n[j] = 0x20; - } - n[8] = 0; -skipdqe2: -#endif int32c = CPUSTATUS; /* keep for retain blocking state */ - addr = SPAD[0xf0]; /* get trap table memory address from SPAD (def 80) */ + addr = SPAD[0xf0]; /* get trap table memory addr from SPAD (def 80, 20) */ int32a = addr; if (addr == 0 || ((addr&MASK24) == MASK24)) { /* see if secondary vector table set up */ TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS1 OP %04x addr %08x\n", OP, addr); goto newpsd; /* program error */ } - addr = addr + (0x06 << 2); /* addr has mem addr of SVC trap vector (def 98) */ + addr = addr + (0x06 << 2); /* addr has mem addr of SVC trap vector (def 98, 38) */ temp = M[addr >> 2]; /* get the secondary trap table address from memory */ if (temp == 0 || ((temp&MASK24) == MASK24)) { /* see if ICB set up */ TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS2 OP %04x addr %08x\n", OP, addr); goto newpsd; /* program error */ } temp2 = ((IR>>12) & 0x0f) << 2; /* get SVC index from IR */ t = M[(temp+temp2)>>2]; /* get secondary trap vector address ICB address */ - if (temp == 0 || ((temp&MASK24) == MASK24)) { /* see if ICB set up */ + if (t == 0 || ((t&MASK24) == MASK24)) { /* see if ICB set up */ TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS3 OP %04x addr %08x\n", OP, addr); goto newpsd; /* program error */ } bc = PSD2 & 0x3ff8; /* get copy of cpix */ M[t>>2] = (PSD1+4) & 0xfffffffe; /* store PSD 1 + 1W to point to next instruction */ M[(t>>2)+1] = PSD2; /* store PSD 2 */ - PSD1 = M[(t>>2)+2]; /* get new PSD 1 */ - PSD2 = (M[(t>>2)+3] & ~0x3ff8) | bc; /* get new PSD 2 w/old cpix */ M[(t>>2)+4] = IR&0xFFF; /* store call number */ -#ifdef MPXTEST /* set to 1 for traceme to work */ - if (sq59 == 0x930) { /* running on MPX? */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "SVC %x,%x @ %.8x PSD %.8x %.8x SPAD PSD2 %x C.CURR %x LMN %8s\n", - temp2>>2, IR&0xFFF, OPSD1, PSD1, PSD2, SPAD[0xf5], dqe, n); - sim_debug(DEBUG_IRQ, &cpu_dev, - " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_IRQ, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + TPSD1 = PSD1; /* save the PSD for the instruction */ + TPSD2 = PSD2; + PSD1 = M[(t>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(t>>2)+3] & ~0x3ff8) | bc; /* get new PSD 2 w/old cpix */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + + if (PSD2 & MAPBIT) { /* see if new PSD is mapped */ + uint32 mpl = SPAD[0xf3]; /* get mpl from spad address */ + uint32 osmidl = RMW(mpl); /* get midl entry for O/S */ + uint32 MAXMAP = MAX2048; /* default to 2048 maps */ + + if (CPU_MODEL < MODEL_27) + MAXMAP = MAX32; /* 32 maps for 32/77 */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) + MAXMAP = MAX256; /* only 256 2KW (8kb) maps */ + + /* New PSD is mapped, check for valid msd and mpl counts */ + if ((mpl != 0) && (osmidl != 0) && ((osmidl & MASK16) <= MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "OK SVC %x,%x @ %.8x %.8x mpl %.6x osmidl %06x MAPS %04x MAXMAPS %04x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, mpl, osmidl, osmidl & MASK16, MAXMAP); + sim_debug(DEBUG_TRAP, my_dev, + "OK SVC %x,%x @ %.8x %.8x PSD %.8x %.8x SPADF5 PSD2 %x CPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + } else { + sim_debug(DEBUG_TRAP, my_dev, + "Error SVC %x,%x @ %.8x %.8x mpl %.6x osmidl %06x MAPS %04x MAXMAPS %04x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, mpl, osmidl, osmidl & MASK16, MAXMAP); + sim_debug(DEBUG_TRAP, my_dev, + "Error SVC %x,%x @ %.8x %.8x PSD %.8x %.8x SPADF5 PSD2 %x CPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + TRAPME = MACHINECHK_TRAP; /* trap condition */ + PSD1 = TPSD1; /* restore PSD 1 */ +//FIX121222 PSD2 = TPSD2; /* restore PSD 2 */ + PSD2 = PSD2; /* diag wants new PSD 2, not old?? */ + goto newpsd; /* program error */ + } } -#if DYNAMIC_DEBUG - if (((temp2>>2) == 1) && ((IR&0xFFF) == 0x03f)) { /* SVC 1,3f */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif -#else - sim_debug(DEBUG_IRQ, &cpu_dev, - "SVC %x,%x @ %.8x PSD %.8x %.8x SPADF5 PSD2 %x CPUSTATUS %08x\n", - temp2>>2, IR&0xFFF, OPSD1, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, + "SVC %x,%x @ %.8x %.8x NPSD %.8x %.8x SPADF5 %x CPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + sim_debug(DEBUG_TRAP, my_dev, " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); -#endif -#if DYNAMIC_DEBUG - if (((temp2>>2) == 0) && ((IR&0xFFF) == 0xb01)) { /* SVC 0,VOMM,1 */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif -#ifdef DO_DYNAMIC_DEBUG - if (((temp2>>2) == 0) && ((IR&0xFFF) == 0x303)) { /* SVC 0,TAMM,1 */ - if (GPR[3] == 0x3a000) - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif -#ifdef DO_DYNAMIC_DEBUG - if (((temp2>>2) == 2) && ((IR&0xFFF) == 0x028)) { /* SVC 2,28 H.VOMM,9 */ - if (cpu_dev.dctrl & DEBUG_INST) - cpu_dev.dctrl &= ~DEBUG_INST; /* stop instruction trace */ - else - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif -#ifdef DO_DYNAMIC_DEBUG - if (((temp2>>2) == 0) && ((IR&0xFFF) == 0xa11)) { /* SVC 0,REMM,17 */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif -#ifdef DO_DYNAMIC_DEBUG - if (((temp2>>2) == 0) && ((IR&0xFFF) == 0x910)) { /* SVC 0,REXS,16 */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } - if (((temp2>>2) == 0) && ((IR&0xFFF) == 0x925)) { /* SVC 0,REXS,40 */ - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif + + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + CPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ + } + /* set the mode bits and CCs from the new PSD */ CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + MODES &= ~RETMODE; /* reset retain map mode bit in status */ CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert into CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ - /* set new map mode and interrupt blocking state in CPUSTATUS */ + if (PSD2 & SETBBIT) { /* is it set blocking state bit 49 set*/ + /* set new blocking state bit 49=1 */ + CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ + MODES |= BLKMODE; /* set blocked mode */ + } else { + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + MODES &= ~BLKMODE; /* reset block mode bits */ + } + + /* bit 0 of PSD wd 2 sets new mapping state */ if (PSD2 & MAPBIT) { - CPUSTATUS |= BIT8; /* set bit 8 of cpu status */ + CPUSTATUS |= BIT8; /* set bit 8 of cpu status to mapped */ MODES |= MAPMODE; /* set mapped mode */ } else { CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ -/*TRY_01072022*/ MODES &= ~MAPMODE; /* reset mapped mode */ + MODES &= ~MAPMODE; /* reset mapped mode */ } - /* set interrupt blocking state */ - if ((PSD2 & RETBBIT) == 0) { /* is it retain blocking state */ - if (PSD2 & SETBBIT) { /* no, is it set blocking state */ - CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ - MODES |= BLKMODE; /* set blocked mode */ - } else { - CPUSTATUS &= ~BIT24; /* no, reset blk state in cpu status bit 24 */ - MODES &= ~BLKMODE; /* reset blocked mode */ - irq_pend = 1; /* start scanning interrupts again */ -#ifdef LEAVE_ACTIVE - if (irq_auto) { -/*AIR*/ INTS[irq_auto] &= ~INTS_ACT; /* deactivate specified int level */ -/*AIR*/ SPAD[irq_auto+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>IntX deactivate level %02x at SVC #%2x PSD1 %08x\n", - irq_auto, temp2, PSD1); -/*AIR*/ irq_auto = 0; /* show done processing in blocked mode */ - } -#endif - } - } else { - /* handle retain blocking state */ - PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ - /* set new blocking state in PSD2 */ - PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ - MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ - if (int32c & BIT24) { /* see if old mode is blocked */ - PSD2 |= SETBBIT; /* set to blocked state */ - MODES |= BLKMODE; /* set blocked mode */ + if ((PSD2 & SETBBIT) == 0) { /* see if new mode is unblocked */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + /* we changed from blocked to unblocked */ + if (!(CPUSTATUS & ONIPU)) + irq_pend = 1; /* start scanning interrupts again */ } } + sim_debug(DEBUG_TRAP, my_dev, + "SVCX %x,%x @ %.8x %.8x NPSD %.8x %.8x SPADF5 %x CPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, OPSD1, OPSD2, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ TRAPME = 0; /* not to be processed as trap */ - goto newpsd; /* new psd loaded */ + drop_nop = 0; /* nothing to drop */ + i_flags |= BT; /* do not update pc */ } break; @@ -5517,6 +5970,25 @@ skipdqe2: /* if bit 30 set, instruction is in right hw, do EXRR */ if (addr & 2) IR <<= 16; /* move instruction to left HW */ + if (IPU_MODEL && (CPUSTATUS & ONIPU)) { + /* on IPU : */ + sim_debug(DEBUG_INST, my_dev, + "IPU EXR IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + if ((IR & 0xFC000000) == 0xFC000000 || /* No I/O targets */ + (IR & 0xFFFF0000) == 0x00060000) { /* No BEI target */ + TRAPME = IPUUNDEFI_TRAP; + i_flags |= BT; /* leave PC unchanged, so no PC update */ + goto newpsd; + } + } +#ifndef USE_IPU_THREAD + else { + sim_debug(DEBUG_INST, my_dev, + "CPU EXR IR %08x PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], CPUSTATUS); + } +#endif #ifdef DIAG_SAYS_OK_TO_EXECUTE_ANOTHER_EXECUTE /* 32/67 diag says execute of execute is OK */ if ((IR & 0xFC7F0000) == 0xC8070000 || @@ -5525,7 +5997,8 @@ skipdqe2: goto inv; /* invalid instruction */ } #endif - EXM_EXR = 4; /* set PC increment for EXR */ +dohist: + EXM_EXR = 4; /* set PC increment for EXR/EXP */ OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ /* TODO Update other history information for this instruction */ @@ -5534,7 +6007,14 @@ skipdqe2: hst[hst_p].npsd1 = PSD1; /* save new psd1 */ hst[hst_p].npsd2 = PSD2; /* save new psd2 */ hst[hst_p].modes = MODES; /* save current mode bits */ - hst[hst_p].modes |= (CPUSTATUS & BIT24); /* save blocking mode bit */ + hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */ + if (CPUSTATUS & BIT24) + hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */ + if (CPUSTATUS & BIT27) + hst[hst_p].modes |= IPUMODE; /* save cpu/ipu status bit */ +//113022 hst[hst_p].modes &= ~(BIT24|BIT27); /* clear blocked and ipu bits */ +//113022 hst[hst_p].modes |= (CPUSTATUS & BIT24);/* save blocking mode bit */ +//113022 hst[hst_p].modes |= (CPUSTATUS & BIT27);/* save cpu/ipu status bit */ for (ix=0; ix<8; ix++) { hst[hst_p].reg[ix] = GPR[ix]; /* save reg */ hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */ @@ -5556,20 +6036,23 @@ skipdqe2: BK = 'B'; else BK = 'U'; - sim_debug(DEBUG_INST, &cpu_dev, "%c%c%c %.8x %.8x %.8x ", + sim_debug(DEBUG_INST, my_dev, "%s %c%c%c %.8x %.8x %.8x ", + (CPUSTATUS & BIT27) ? "IPU": "CPU", + BM, MM, BK, OPSD1, PSD2, OIR); + sim_debug(DEBUG_INST, my_dev, "%c%c%c %.8x %.8x %.8x ", BM, MM, BK, OPSD1, PSD2, OIR); if (cpu_dev.dctrl & DEBUG_INST) { fprint_inst(sim_deb, OIR, 0); /* display instruction */ - sim_debug(DEBUG_INST, &cpu_dev, + sim_debug(DEBUG_INST, my_dev, "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_INST, &cpu_dev, + sim_debug(DEBUG_INST, my_dev, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - if (MODES & BASEBIT) { - sim_debug(DEBUG_INST, &cpu_dev, - "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); - sim_debug(DEBUG_INST, &cpu_dev, - " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); - } + if (MODES & BASEBIT) { + sim_debug(DEBUG_INST, my_dev, + "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); + sim_debug(DEBUG_INST, my_dev, + " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); + } } goto exec; /* go execute the instruction */ break; @@ -5595,6 +6078,8 @@ skipdqe2: /* For machines with Base mode 0xCC08 stores base registers */ if ((FC & 3) != 0) { /* must be word address */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS4 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } temp = addr & 0xffe000; /* get 11 bit map # */ @@ -5603,12 +6088,16 @@ skipdqe2: if (bc != (addr & 0x20)) { /* test for crossing file boundry */ if (CPU_MODEL < MODEL_27) { TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS5 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } } if (temp != (addr & 0xffe000)) { /* test for crossing map boundry */ if (CPU_MODEL >= MODEL_V6) { TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS6 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } } @@ -5653,8 +6142,6 @@ skipdqe2: if ((FC & 0x4) && (CPU_MODEL <= MODEL_27)) { /* basemode undefined for 32/7x & 32/27 */ TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ - if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) - TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ goto newpsd; /* handle trap */ } /* For machines with Base mode 0xDC08 stores base registers */ @@ -5710,13 +6197,13 @@ skipdqe2: /* do ADFW or SUFW instructions */ temp2 = GPR[reg]; /* dest - reg contents specified by Rd */ addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */ - if ((opr & 8) == 0) { /* Was it SUFW? */ + if ((OPR & 8) == 0) { /* Was it SUFW? */ addr = NEGATE32(addr); /* take negative for add */ } temp = s_adfw(temp2, addr, &CC); /* do ADFW */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "%s GPR[%d] %08x addr %08x result %08x CC %08x\n", - (opr&8) ? "ADFW":"SUFW", reg, GPR[reg], addr, temp, CC); + (OPR&8) ? "ADFW":"SUFW", reg, GPR[reg], addr, temp, CC); ovr = 0; if (CC & CC1BIT) ovr = 1; @@ -5740,13 +6227,13 @@ skipdqe2: td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ /* source has 64 bit memory data */ - if ((opr & 8) == 0) { /* Was it SUFD? */ + if ((OPR & 8) == 0) { /* Was it SUFD? */ source = NEGATE32(source); /* make negative for subtract */ } dest = s_adfd(td, source, &CC); /* do ADFD */ - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "%s GPR[%d] %08x %08x src %016llx result %016llx CC %08x\n", - (opr&8) ? "ADFD":"SUFD", reg, GPR[reg], GPR[reg+1], source, dest, CC); + (OPR&8) ? "ADFD":"SUFD", reg, GPR[reg], GPR[reg+1], source, dest, CC); ovr = 0; if (CC & CC1BIT) /* test for overflow detection */ ovr = 1; @@ -5787,14 +6274,14 @@ skipdqe2: /* do MPFW or DVFW instructions */ temp2 = GPR[reg]; /* dest - reg contents specified by Rd */ addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */ - if (opr & 8) { /* Was it MPFW? */ + if (OPR & 8) { /* Was it MPFW? */ temp = s_mpfw(temp2, addr, &CC); /* do MPFW */ } else { temp = (uint32)s_dvfw(temp2, addr, &CC); /* do DVFW */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "%s GPR[%d] %08x addr %08x result %08x\n", - (opr&8) ? "MPFW":"DVFW", reg, GPR[reg], addr, temp); + (OPR&8) ? "MPFW":"DVFW", reg, GPR[reg], addr, temp); if (CC & CC1BIT) ovr = 1; PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ @@ -5817,14 +6304,14 @@ skipdqe2: td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ /* source has 64 bit memory data */ - if (opr & 8) { /* Was it MPFD? */ + if (OPR & 8) { /* Was it MPFD? */ dest = s_mpfd(td, source, &CC); /* do MPFD */ } else { dest = s_dvfd(td, source, &CC); /* do DVFD */ } - sim_debug(DEBUG_DETAIL, &cpu_dev, + sim_debug(DEBUG_DETAIL, my_dev, "%s GPR[%d] %08x %08x src %016llx result %016llx\n", - (opr&8) ? "MPFD":"DVFD", reg, GPR[reg], GPR[reg+1], source, dest); + (OPR&8) ? "MPFD":"DVFD", reg, GPR[reg], GPR[reg+1], source, dest); if (CC & CC1BIT) /* test for overflow detection */ ovr = 1; PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ @@ -5925,14 +6412,15 @@ skipdqe2: } break; - case 0xEC>>2: /* 0xEC ADR - ADR */ /* Branch unconditional or Branch True */ + case 0xEC>>2: /* 0xEC ADR - ADR */ /* Branch unconditional BU or Branch True BCT */ /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ /* so just test for F bit and go on */ /* if ((FC & 5) != 0) { */ if ((FC & 4) != 0) { TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "ADDRSPEC10 OP %04x addr %08x\n", OP, addr); + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC10 OP %04x addr %08x FC %02x PSD %08x %08x\n", + OP, addr, FC, PSD1, PSD2); goto newpsd; /* go execute the trap now */ } temp2 = CC; /* save the old CC's */ @@ -5948,6 +6436,12 @@ skipdqe2: case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) != 0; break; } if (t) { /* see if we are going to branch */ +#if 0 /* set #if to 1 to stop branch to self while ipu tracing, for now */ + if (PC == (addr & 0xFFFFFC)) { /* BU to current PC, go to wait */ + fprintf(stderr, "BR stopping BU $ addr %x PC %x\r\n", addr, PC); + goto do_ipu_wait; + } +#endif /* we are taking the branch, set CC's if indirect, else leave'm */ /* update the PSD with new address */ PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ @@ -5960,14 +6454,15 @@ skipdqe2: /* branch not taken, go do next instruction */ break; - case 0xF0>>2: /* 0xF0 ADR - ADR */ /* Branch False or Branch Function True BFT */ + case 0xF0>>2: /* 0xF0 ADR - ADR */ /* Branch False BCF or Branch Function True BFT */ /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ /* so just test for F bit and go on */ /* if ((FC & 5) != 0) { */ if ((FC & 4) != 0) { TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "ADDRSPEC11 OP %04x addr %08x\n", OP, addr); + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC11 OP %04x addr %08x FC %02x PSD %08x %08x\n", + OP, addr, FC, PSD1, PSD2); goto newpsd; /* go execute the trap now */ } temp2 = CC; /* save the old CC's */ @@ -6017,7 +6512,7 @@ skipdqe2: break; case 0xF8>>2: /* 0xF8 SM|ADR - SM|ADR */ /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, TRP */ - switch((opr >> 7) & 0x7) { /* use bits 6-8 to determine instruction */ + switch((OPR >> 7) & 0x7) { /* use bits 6-8 to determine instruction */ case 0x0: /* ZMx F80x */ /* SM */ dest = 0; /* destination value is zero */ i_flags |= SM; /* SM not set so set it to store value */ @@ -6040,7 +6535,6 @@ skipdqe2: case 0x3: /* LPSD F980 */ /* fall through */; case 0x5: /* LPSDCM FA80 */ - irq_pend = 1; /* start scanning interrupts again */ if ((MODES & PRIVBIT) == 0) { /* must be privileged */ TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) @@ -6055,21 +6549,26 @@ skipdqe2: if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */ /* Fault */ TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "ADDRSPEC12 OP %04x addr %08x\n", OP, addr); + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n", + OP, addr, FC, PSD1, PSD2); goto newpsd; /* go execute the trap now */ } if ((TRAPME = Mem_read(addr, &temp))) { /* get PSD1 from memory */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ TRAPSTATUS |= BIT7; /* set bit 7 of trap status */ - } else + } else { TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSD TRAP1 %02x SPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n", + TRAPME, OP, addr, FC, PSD1, PSD2); + } goto newpsd; /* memory read error or map fault */ } bc = CPUSTATUS; /* save the CPU STATUS */ - TPSD[0] = PSD1; /* save the PSD for the instruction */ - TPSD[1] = PSD2; + TPSD1 = PSD1; /* save the PSD for the instruction */ + TPSD2 = PSD2; t = MODES; /* save modes too */ ix = SPAD[0xf5]; /* save the current PSD2 */ reg = irq_pend; /* save intr status */ @@ -6078,167 +6577,97 @@ skipdqe2: if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ TRAPSTATUS |= BIT7; /* set bit 7 of trap status */ - } else + } else { TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSD TRAP2 %02x SPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n", + TRAPME, OP, addr, FC, PSD1, PSD2); + } goto newpsd; /* memory read error or map fault */ } - if (opr & 0x0200) { /* Was it LPSDCM? */ + if (OPR & 0x0200) { /* Was it LPSDCM? */ /* LPSDCM */ + PSD1 = temp; /* PSD1 good, so set it */ PSD2 = temp2 & 0xfffffff8; /* PSD2 access good, clean & save it */ + if (PSD2 & RETMBIT) /* is retain mapping bit set */ + PSD2 = ((PSD2 & 0x3ff8) | (temp2 & 0xffffc000)); /* use current cpix */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS); } else { /* LPSD */ + PSD1 = temp; /* PSD1 good, so set it */ /* lpsd can not change cpix, so keep it */ PSD2 = ((PSD2 & 0x3ff8) | (temp2 & 0xffffc000)); /* use current cpix */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 n/u */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSD %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS); } - PSD1 = temp; /* PSD1 good, so set it */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSD(CM) load [%06x] New PSD1 %08x %08x OPSD2 %08x SPAD %08x CPUSTATUS %08x\n", - addr, PSD1, PSD2, TPSD[1], ix, CPUSTATUS); -#ifdef MPXTEST - for (ii=0; ii<8; ii+=4) { - sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSD(CM) GPR[%d] %.8x GPR[%d] %.8x GPR[%d] %.8x GPR[%d] %.8x\n", - ii, GPR[ii], ii+1, GPR[ii+1], ii+2, GPR[ii+2], ii+3, GPR[ii+3]); + + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + CPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ } - /* DYNAMIC 05282021 */ -#endif + /* set the mode bits and CCs from the new PSD */ CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + MODES &= ~RETMODE; /* reset retain map mode bit in status */ CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert into CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ - /* set new map mode and interrupt blocking state in CPUSTATUS */ + if (PSD2 & SETBBIT) { /* is it set blocking state bit 49 set*/ + /* set new blocking state bit 49=1 */ + CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ + MODES |= BLKMODE; /* set blocked mode */ + } else { + CPUSTATUS &= ~BIT24; /* reset block state in cpu status bit 8 */ + MODES &= ~BLKMODE; /* reset block mode bits */ + } + + /* bit 0 of PSD wd 2 sets new mapping state */ if (PSD2 & MAPBIT) { - CPUSTATUS |= BIT8; /* set bit 8 of cpu status */ + CPUSTATUS |= BIT8; /* set bit 8 of cpu status to mapped */ MODES |= MAPMODE; /* set mapped mode */ } else { CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ -/*TRY_01072022*/ MODES &= ~MAPMODE; /* reset mapped mode */ + MODES &= ~MAPMODE; /* reset mapped mode */ } - /* set interrupt blocking state */ - if ((PSD2 & RETBBIT) == 0) { /* is it retain blocking state */ - if (PSD2 & SETBBIT) { /* no, is it set blocking state */ - CPUSTATUS |= BIT24; /* yes, set blk state in cpu status bit 24 */ - MODES |= BLKMODE; /* set blocked mode */ - } else { - CPUSTATUS &= ~BIT24; /* no, reset blk state in cpu status bit 24 */ - MODES &= ~BLKMODE; /* reset blocked mode */ - irq_pend = 1; /* start scanning interrupts again */ -#ifdef LEAVE_ACTIVE - if (irq_auto) { -/*AIR*/ INTS[irq_auto] &= ~INTS_ACT; /* deactivate specified int level */ -/*AIR*/ SPAD[irq_auto+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "<|>IntX deactivate level %02x at LPSD(CM) %08x %08x R[3] %08x\n", - irq_auto, PSD1, PSD2, GPR[3]); -/*AIR*/ irq_auto = 0; /* show done processing in blocked mode */ -#ifdef DYNAMIC_DEBUG_01172021 - cpu_dev.dctrl &= ~DEBUG_INST; /* end instruction trace */ -#endif - } -#endif - } - } else { - /* set new blocking state in PSD2 */ - PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ - MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ - if (bc & BIT24) { /* see if old mode is blocked */ - PSD2 |= SETBBIT; /* set to blocked state */ - MODES |= BLKMODE; /* set blocked mode */ + if ((PSD2 & SETBBIT) == 0) { /* see if new mode is unblocked */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + /* we changed from blocked to unblocked */ + if (!(CPUSTATUS & ONIPU)) + irq_pend = 1; /* start scanning interrupts again */ } } -#ifdef MPXTEST /* set to 1 for traceme to work */ - /* get current MPX task name */ - { - int j; - char n[9]; - uint32 sq59 = M[0x930>>2]; /* get C.SQ59 headcell */ - uint32 dqe = M[0x8e8>>2]; /* get DQE of current task */ - if (sq59 != 0x930) - goto skipdqe; /* not running on mpx, skip */ - for (j=0; j<8; j++) { /* get the task name */ - n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff; - if (n[j] == 0) - n[j] = 0x20; - } - n[8] = 0; -#if 0 -#if DYNAMIC_DEBUG - if (dqe == 0x56e0) { - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ - } -#endif -#endif - if (opr & 0x0200) { /* Was it LPSDCM? */ -sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSDCM OPSD %.8x %.8x NPSD %.8x %.8x SPDF5 %.8x DQE %x LMN %8s\n", - TPSD[0], TPSD[1], PSD1, PSD2, SPAD[0xf5], dqe, n); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - } else { -sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSD OPSD %.8x %.8x NPSD %.8x %.8x SPDF5 %.8x DQE %x LMN %8s\n", - TPSD[0], TPSD[1], PSD1, PSD2, SPAD[0xf5], dqe, n); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - } -// cpu_dev.dctrl |= DEBUG_DETAIL; /* start instruction trace */ - } -skipdqe: -#else - if (opr & 0x0200) { /* Was it LPSDCM? */ -sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSDCM OPSD %.8x %.8x NPSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", - TPSD[0], TPSD[1], PSD1, PSD2, SPAD[0xf5], CPUSTATUS); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - } else { -sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSD OPSD %.8x %.8x NPSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", - TPSD[0], TPSD[1], PSD1, PSD2, SPAD[0xf5], CPUSTATUS); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); -sim_debug(DEBUG_IRQ, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - } -#endif - if (opr & 0x0200) { /* Was it LPSDCM? */ - /* map bit must be on to load maps */ + /* see what mapping we are to do if LPSDCM */ + if (OPR & 0x0200) { /* Was it LPSDCM? */ if (PSD2 & MAPBIT) { - /* set mapped mode in cpu status */ - CPUSTATUS |= BIT8; /* set bit 8 of cpu status */ -#ifdef LOOK_MAP_05272021 - sim_debug(DEBUG_IRQ, &cpu_dev, - "B4 LPSDCM temp %06x TPSD %08x %08x PSD %08x %08x\n", - temp, TPSD[0], TPSD[1], PSD1, PSD2); - sim_debug(DEBUG_IRQ, &cpu_dev, - "B4 LPSDCM BPIX %04x CPIX %04x CPIXPL %04x\n", - BPIX, CPIX, CPIXPL); - sim_debug(DEBUG_IRQ, &cpu_dev, - "B4 LPSDCM OS MAPC[0-7] %08x %08x %08x %08x %08x %08x %08x %08x\n", - MAPC[0], MAPC[1], MAPC[2], MAPC[3], MAPC[4], MAPC[5], MAPC[6], MAPC[7]); - sim_debug(DEBUG_IRQ, &cpu_dev, - "B4 LPSDCM US MAPC[%x-%x] %08x %08x %08x %08x %08x %08x %08x %08x\n", - BPIX, BPIX+5, MAPC[BPIX], MAPC[BPIX+1], MAPC[BPIX+2], - MAPC[BPIX+3], MAPC[BPIX+4], MAPC[BPIX+5], - MAPC[BPIX+6], MAPC[BPIX+7]); -#endif +//FIXME TRYING FOR DEXP FIX? +#ifndef DEXP_TRY_FIX /* this mod fixes MPX 1.X 1st swapr load */ /* any O/S or user maps yet? */ if (((CPIX != 0) && (CPIXPL == 0)) && (PSD2 & RETMBIT)) { PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */ - sim_debug(DEBUG_EXP, &cpu_dev, "Turn off retain bit\n"); + sim_debug(DEBUG_TRAP, my_dev, "Turn off retain bit\n"); } +#endif +//FIXME TRYING FOR DEXP FIX? +#ifndef DEXP_TRY_FIX /* test if user count is equal to CPIXPL, if not load maps */ /* this fixes software error in MPX3X where count is changed */ /* but the retain bit was left set, so new maps were not loaded */ @@ -6247,79 +6676,62 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((PSD2 & RETMBIT)) { /* don't load maps if retain bit set */ uint32 mpl = SPAD[0xf3]; /* get mpl from spad address */ uint32 cpix = PSD2 & 0x3ff8; /* get cpix 11 bit offset from psd wd 2 */ + uint32 osmidl = RMW(mpl); /* get midl entry for given O/S */ uint32 midl = RMW(mpl+cpix); /* get midl entry for given user cpix */ uint32 spc = midl & MASK16; /* get 16 bit user segment description count */ -#ifdef TRY_TEST_05182021 - /* output O/S and User MPL entries */ - sim_debug(DEBUG_EXP, &cpu_dev, - "#LPSDCM MEM %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", - MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix, - RMW(cpix+mpl), RMW(cpix+mpl+4)); - sim_debug(DEBUG_EXP, &cpu_dev, - "#LPSDCM2 MEM %06x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n", - MEMSIZE, BPIX, cpix, CPIX, CPIXPL, HIWM); -#endif + + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM FIX %.8x %.8x mpl %.6x osmidl %06x umidl %06x OSMAPS %04x UMAPS %04x CPIXPL %04x\n", + TPSD1, TPSD2, mpl, osmidl, midl, osmidl & MASK16, spc, CPIXPL); /* if this code is not present, MPX3X will not boot correctly */ if (spc != CPIXPL) { PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */ - } - /* if this code is not present MPX3X will abort */ - /* when trying to mount a secondary disk */ - else - { + } else { + /* if this code is not present MPX3X will abort */ + /* when trying to mount a secondary disk */ if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V6) || (CPU_MODEL == MODEL_V9)) { PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */ } } - sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSDCM FIX MAP TRAPME %02x PSD1 %08x PSD2 %08x spc %02x BPIX %02x CPIXPL %02x retain %01x\n", - TRAPME, PSD1, PSD2, spc, BPIX, CPIXPL, PSD2&RETMBIT?1:0); + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM FIX MAP TRAPME %02x PSD %08x %08x spc %02x BPIX %02x CPIXPL %02x retain %01x\n", + TRAPME, PSD1, PSD2, spc, BPIX, CPIXPL, PSD2&RETMBIT?1:0); } - +#endif + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCML %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS); + /* load the new maps and test for errors */ if ((PSD2 & RETMBIT) == 0) { /* don't load maps if retain bit set */ /* we need to load the new maps */ TRAPME = load_maps(PSD, 0); /* load maps for new PSD */ -#ifdef LOOK_MAP_05272021 - sim_debug(DEBUG_IRQ, &cpu_dev, - "AF LPSDCM TPSD %08x %08x PSD %08x %08x TRAPME %02x\n", - TPSD[0], TPSD[1], PSD1, PSD2, TRAPME); - sim_debug(DEBUG_IRQ, &cpu_dev, - "AF LPSDCM BPIX %04x CPIX %04x CPIXPL %04x\n", - BPIX, CPIX, CPIXPL); - sim_debug(DEBUG_IRQ, &cpu_dev, - "AF LPSDCM OS MAPC[0-7] %08x %08x %08x %08x %08x %08x %08x %08x\n", - MAPC[0], MAPC[1], MAPC[2], MAPC[3], MAPC[4], MAPC[5], MAPC[6], MAPC[7]); - sim_debug(DEBUG_IRQ, &cpu_dev, - "AF LPSDCM US MAPC[%x-%x] %08x %08x %08x %08x %08x %08x %08x %08x\n", - BPIX, BPIX+5, MAPC[BPIX], MAPC[BPIX+1], MAPC[BPIX+2], - MAPC[BPIX+3], MAPC[BPIX+4], MAPC[BPIX+5], - MAPC[BPIX+6], MAPC[BPIX+7]); -#endif } - PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ - SPAD[0xf5] = PSD2; /* save the current PSD2 */ - SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ - sim_debug(DEBUG_IRQ, &cpu_dev, - "LPSDCM MAPS LOADED TRAPME %02x PSD1 %08x PSD2 %08x BPIX %02x CPIXPL %02x retain %01x\n", + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM MAPS LOADED TRAPME %02x PSD %08x %08x BPIX %02x CPIXPL %02x retain %01x\n", TRAPME, PSD1, PSD2, BPIX, CPIXPL, PSD2&RETMBIT?1:0); } - PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ } else { /* LPSD */ /* if cpix is zero, copy cpix from PSD2 in SPAD[0xf5] */ if ((PSD2 & 0x3ff8) == 0) { PSD2 |= (SPAD[0xf5] & 0x3ff8); /* use new cpix */ } + sim_debug(DEBUG_TRAP, my_dev, + "LPSDL @ %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, CPUSTATUS); } + /* TRAPME can be error from LPSDCM or OK here */ if (TRAPME) { /* if we have an error, restore old PSD */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "LPSDCM MAPS2 LOADED TRAPME = %02x PSD1 %08x PSD2 %08x CPUSTAT %08x SPAD[f9] %08x\n", + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM BAD MAPS LOAD TRAPME %02x PSD %08x %08x CPUSTAT %08x SPAD[f9] %08x\n", TRAPME, PSD1, PSD2, CPUSTATUS, SPAD[0xf9]); - PSD1 = TPSD[0]; /* restore PSD1 */ + PSD1 = TPSD1; /* restore PSD1 */ +//NO, USE NEW PSD2 = TPSD2; /* restore PSD2 */ /* HACK HACK HACK */ - /* Diags wants the new PSD2, not the original??? */ + /* Diags wants the new PSD2, not the original on error??? */ /* if old one was used, we fail test 21/0 in cn.mmm for 32/67 */ CPUSTATUS = bc; /* restore the CPU STATUS */ MODES = t; /* restore modes too */ @@ -6336,11 +6748,11 @@ sim_debug(DEBUG_IRQ, &cpu_dev, SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ drop_nop = 0; /* nothing to drop */ - goto newpsd; /* load the new psd, or process error */ - break; + i_flags |= BT; /* do not update pc */ + break; /* load the new psd, or process error */ case 0x4: /* JWCS */ /* not used in simulator */ - sim_debug(DEBUG_EXP, &cpu_dev, "Got JWCS\n"); + sim_debug(DEBUG_EXP, my_dev, "Got JWCS\n"); break; case 0x2: /* BRI */ /* TODO - only for 32/55 or 32/7X in PSW mode */ case 0x6: /* TRP */ @@ -6366,9 +6778,6 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ /* */ case 0xFC>>2: /* 0xFC IMM - IMM */ /* XIO, CD, TD, Interrupt Control */ -#ifdef MAYBE_NO - irq_pend = 1; /* start scanning interrupts again */ -#endif if ((MODES & PRIVBIT) == 0) { /* must be privileged to do I/O */ TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) @@ -6377,10 +6786,19 @@ sim_debug(DEBUG_IRQ, &cpu_dev, TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ goto newpsd; /* Privlege violation trap */ } - if ((opr & 0x7) != 0x07) { /* aug is 111 for XIO instruction */ + if (IPU_MODEL && (CPUSTATUS & ONIPU)) { + /* on IPU : */ + TRAPME = IPUUNDEFI_TRAP; + sim_debug(DEBUG_TRAP, my_dev, + "IPU SIO PSD %.8x %.8x SPDF5 %.8x CPUSTATUS %08x\n", + PSD1, PSD2, SPAD[0xf5], CPUSTATUS); +//DIAGS FIX i_flags |= BT; /* leave PC unchanged, so no PC update */ + goto newpsd; + } + if ((OPR & 0x7) != 0x07) { /* aug is 111 for XIO instruction */ /* Process Non-XIO instructions */ uint32 status = 0; /* status returned from device */ - uint32 device = (opr >> 3) & 0x7f; /* get device code */ + uint32 device = (OPR >> 3) & 0x7f; /* get device code */ uint32 prior = device; /* interrupt priority */ uint32 maxlev = 0x5f; /* max lev for all but 32/27 in diags */ //MAYBEBAD uint32 maxlev = 0x6f; /* max lev for all but 32/27 in diags */ @@ -6388,12 +6806,12 @@ sim_debug(DEBUG_IRQ, &cpu_dev, t = SPAD[prior+0x80]; /* get spad entry for interrupt */ addr = SPAD[0xf1] + (prior<<2); /* vector address in SPAD */ addr = M[addr>>2]; /* get the interrupt context block addr */ - prior = (opr >> 3) & 0x7f; /* get priority level */ + prior = (OPR >> 3) & 0x7f; /* get priority level */ if (CPU_MODEL <= MODEL_27) { maxlev = 0x6f; /* 27 uses 112 */ } - switch(opr & 0x7) { /* use bits 13-15 to determine instruction */ + switch(OPR & 0x7) { /* use bits 13-15 to determine instruction */ case 0x0: /* EI FC00 Enable Interrupt */ if (prior > maxlev) /* ignore for invalid levels */ break; /* ignore */ @@ -6405,37 +6823,22 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */ break; /* ignore for F class */ + sim_debug(DEBUG_IRQ, my_dev, + "EI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); /* does not effect REQ status */ INTS[prior] |= INTS_ENAB; /* enable specified int level */ SPAD[prior+0x80] |= SINT_ENAB; /* enable in SPAD too */ irq_pend = 1; /* start scanning interrupts again */ -#ifdef TRY_ME_01072022 - sim_debug(DEBUG_IRQ, &cpu_dev, - "EI skipinstr %d PSD1 %08x irq_pend %d wait4int %d irq_auto %x\n", - skipinstr, PSD1, irq_pend, wait4int, irq_auto); - sim_debug(DEBUG_IRQ, &cpu_dev, - "EI INTS[%d] = %08x SPAD[%d] %08x CPUSTATUS %08x\n", - prior, INTS[prior], 0x80+prior, SPAD[prior+0x80], CPUSTATUS); -#endif /* test for clock at address 0x7f06 and interrupt level 0x18 */ /* the diags want the type to be 0 */ /* UTX wants the type to be 3?? */ /* UTX would be 0x03807f06 Diags would be 0x00807f06 */ if ((SPAD[prior+0x80] & 0x0000ffff) == 0x00007f06) { - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_IRQ, my_dev, "Clock EI %02x SPAD %08x Turn on\n", prior, t); rtc_setup(1, prior); /* tell clock to start */ } - /* the diags want the type to be 3 */ - if ((SPAD[prior+0x80] & 0x0f00ffff) == 0x03007f04) { - sim_debug(DEBUG_IRQ, &cpu_dev, - "Intv Timer EI %02x SPAD %08x Turn on\n", prior, t); - itm_setup(1, prior); /* tell timer to start */ -#ifdef DO_DYNAMIC_INSTR - cpu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ -#endif - } break; case 0x1: /* DI FC01 */ @@ -6450,6 +6853,8 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */ break; /* ignore for F class */ + sim_debug(DEBUG_IRQ, my_dev, + "DI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); /* active state is left alone */ INTS[prior] &= ~INTS_ENAB; /* disable specified int level */ SPAD[prior+0x80] &= ~SINT_ENAB; /* disable in SPAD too */ @@ -6461,19 +6866,10 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* UTX wants the type to be 3?? */ /* UTX would be 0x03807f06 Diags would be 0x00807f06 */ if ((SPAD[prior+0x80] & 0x0000ffff) == 0x00007f06) { - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_IRQ, my_dev, "Clock DI %02x SPAD %08x Turn off\n", prior, t); rtc_setup(0, prior); /* tell clock to stop */ } - /* the diags want the type to be 3 */ - if ((SPAD[prior+0x80] & 0x0f00ffff) == 0x03007f04) { - sim_debug(DEBUG_IRQ, &cpu_dev, - "Intv Timer DI %02x SPAD %08x Turn off\n", prior, t); -#ifdef DO_DYNAMIC_INSTR - cpu_dev.dctrl &= ~DEBUG_INST; /* stop instruction trace */ -#endif - itm_setup(0, prior); /* tell timer to stop */ - } break; case 0x2: /* RI FC02 */ @@ -6487,6 +6883,8 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */ break; /* ignore for F class */ + sim_debug(DEBUG_IRQ, my_dev, + "RI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); INTS[prior] |= INTS_REQ; /* set the request flag for this level */ irq_pend = 1; /* start scanning interrupts again */ break; @@ -6502,6 +6900,8 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */ break; /* ignore for F class */ + sim_debug(DEBUG_IRQ, my_dev, + "AI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); INTS[prior] |= INTS_ACT; /* activate specified int level */ SPAD[prior+0x80] |= SINT_ACT; /* activate in SPAD too */ irq_pend = 1; /* start scanning interrupts again */ @@ -6514,11 +6914,11 @@ sim_debug(DEBUG_IRQ, &cpu_dev, t = SPAD[prior+0x80]; /* get spad entry for interrupt */ if ((t == 0) || ((t&MASK24) == MASK24)) /* if unused, ignore instruction */ break; /* ignore */ - + if ((t & 0x0f800000) == 0x0f000000) /* if class F ignore instruction */ break; /* ignore for F class */ - sim_debug(DEBUG_IRQ, &cpu_dev, + sim_debug(DEBUG_IRQ, my_dev, "DAI spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); INTS[prior] &= ~INTS_ACT; /* deactivate specified int level */ SPAD[prior+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ @@ -6526,20 +6926,6 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* instruction following a DAI can not be interrupted */ /* skip tests for interrupts if this is the case */ skipinstr = 1; /* skip interrupt test */ -#ifdef DO_DYNAMIC_DEBUG - /* test for DAI 0x03 */ - if ((prior == 3) && (GPR[5] == 0xfc1c0000) && (GPR[6] == 0x44a4)) { - cpu_dev.dctrl |= (DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ - con_dev.dctrl |= DEBUG_XIO|DEBUG_CMD; - sim_debug(DEBUG_IRQ, &cpu_dev, "DAI 0x03 received start debug\n"); - } - if ((prior == 0x0a) && (GPR[5] == 0xfc540000)) { /* test for DAI 0x0A */ - /* turn off debug trace because we are already hung */ - sim_debug(DEBUG_IRQ, &cpu_dev, "DAI 0x0A received stopping debug\n"); - cpu_dev.dctrl &= ~(DEBUG_INST|DEBUG_TRAP|DEBUG_IRQ); /* start instruction trace */ - con_dev.dctrl &= ~(DEBUG_XIO|DEBUG_CMD); - } -#endif break; case 0x5: /* TD FC05 */ /* bits 13-15 is test code type */ @@ -6557,7 +6943,9 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* t has spad entry for device */ /* get the 1's comp of interrupt address from bits 9-15 SPAD entry */ ix = ((~t)>>16)&0x7f; /* get positive number for interrupt */ - if (opr & 0x1) { /* see if CD or TD */ + if (OPR & 0x1) { /* see if CD or TD */ + sim_debug(DEBUG_IRQ, my_dev, + "TD spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); /* TODO process a TD */ if (device == 0x7f) { /* if this is for the interval timer check cmd type */ @@ -6589,6 +6977,8 @@ sim_debug(DEBUG_IRQ, &cpu_dev, if ((TRAPME = startEIO(device, &status))) goto newpsd; /* error returned, trap cpu */ #endif + sim_debug(DEBUG_IRQ, my_dev, + "CD spad %08x INTS[%02x] %08x\n", t, prior, INTS[prior]); if (device == 0x7f) { temp = (IR & 0x7f); /* get cmd from instruction */ status = itm_rdwr(temp, GPR[0], ix); /* read/write the interval timer */ @@ -6603,6 +6993,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, } break; case 0x7: /* XIO FC07*/ /* should never get here */ + goto inv; /* invalid instruction until I fix it */ break; } break; /* skip over XIO code */ @@ -6611,7 +7002,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, /* Process XIO instructions */ /* see if valid instruction */ /* DIAGS wants this tested first */ - switch((opr >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */ + switch((OPR >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */ case 0x00: /* Unassigned */ case 0x01: /* Unassigned */ case 0x0A: /* Unassigned */ @@ -6637,7 +7028,7 @@ sim_debug(DEBUG_IRQ, &cpu_dev, TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */ TRAPSTATUS |= BIT0; /* class F error bit */ TRAPSTATUS &= ~BIT1; /* I/O processing error */ - goto newpsd; /* undefined instruction trap */ + goto newpsd; /* system check trap */ } /* get real channel from spad device entry */ chan = (t & 0x7f00) >> 8; /* real channel */ @@ -6647,10 +7038,10 @@ sim_debug(DEBUG_IRQ, &cpu_dev, bc = SPAD[ix+0x80]; /* get interrupt spad entry for channel */ /* SPAD address F1 has interrupt table address */ temp = SPAD[0xf1] + (ix<<2); /* vector address in SPAD */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "$$ XIO chsa %04x spad %08x BLK %1x INTS[%02x] %08x\n", rchsa, t, CPUSTATUS&0x80?1:0, ix, INTS[ix]); - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "$$ XIO chsa %04x PSD1 %08x PSD2 %08x IR %08x ICBA %06x\n", rchsa, PSD1, PSD2, IR, temp); if ((TRAPME = Mem_read(temp, &addr))) { /* get interrupt context block addr */ @@ -6670,11 +7061,11 @@ mcheck: goto mcheck; /* machine check if not there */ } /* iocla must be valid addr if it is a SIO instruction */ - if (((temp & MASK24) == 0) && (((opr >> 2) & 0xf) == 2)) { + if (((temp & MASK24) == 0) && (((OPR >> 2) & 0xf) == 2)) { goto mcheck; /* bad iocl address */ } - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "XIO rdy PSD1 %08x chan %02x irq %02x icb %06x iocla %06x iocd %08x %08x\n", PSD1, chan, ix, addr, addr+16, RMW(temp), RMW(temp+4)); /* at this point, the channel has a valid SPAD channel entry */ @@ -6688,30 +7079,22 @@ mcheck: /* ix - positive interrupt level */ /* addr - ICBA for specified interrupt level, points to 6 wd block */ /* temp - First IOCD address */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "XIO switch %02x lchan %02x irq %02x rchsa %04x IOCDa %08x CPUSTATUS %08x BLK %1x\n", - ((opr>>3)&0x0f), lchan, ix, rchsa, temp, CPUSTATUS, CPUSTATUS&0x80?1:0); - - switch((opr >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */ - case 0x00: /* Unassigned */ - case 0x01: /* Unassigned */ - case 0x0A: /* Unassigned */ - TRAPME = UNDEFINSTR_TRAP; /* trap condition */ - if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) - TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ - goto newpsd; /* undefined instruction trap */ - break; + ((OPR>>3)&0x0f), lchan, ix, rchsa, temp, CPUSTATUS, CPUSTATUS&0x80?1:0); + /* 0x00, 0x01, & 0x0A already tested above */ + switch((OPR >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */ case 0x09: /* Enable write channel ECWCS */ case 0x0B: /* Write channel WCS WCWCS */ /* TODO, provide support code */ /* for now or maybe forever, return unsupported transaction */ PSD1 = ((PSD1 & 0x87fffffe) | (CC2BIT|CC4BIT)); /* insert status 5 */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "XIO unsupported WCS chan %04x chsa %04x status %08x\n", chan, rchsa, rstatus); - /* just give unsupported transaction */ #ifdef JUST_RETURN_STATUS + /* just give unsupported transaction */ TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */ TRAPSTATUS |= BIT0; /* class F error bit */ TRAPSTATUS &= ~BIT1; /* I/O processing error */ @@ -6720,26 +7103,26 @@ mcheck: break; case 0x02: /* Start I/O SIO */ - sim_debug(DEBUG_XIO, &cpu_dev, - "SIO b4 call PSD1 %08x rchsa %04x lchsa %04x BLK %1x\n", - PSD1, rchsa, lchsa, CPUSTATUS&0x80?1:0); + sim_debug(DEBUG_XIO, my_dev, + "SIO b4 call PSD1 %08x %08x rchsa %04x lchsa %04x BLK %1x\n", + PSD1, PSD2, rchsa, lchsa, CPUSTATUS&0x80?1:0); if ((TRAPME = startxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, - "SIO ret PSD1 %08x chsa %04x status %08x BLK %1x\n", - PSD1, lchsa, rstatus, CPUSTATUS&0x80?1:0); + sim_debug(DEBUG_XIO, my_dev, + "SIO ret PSD1 %08x %08x chsa %04x status %08x BLK %1x\n", + PSD1, PSD2, lchsa, rstatus, CPUSTATUS&0x80?1:0); break; case 0x03: /* Test I/O TIO */ if ((TRAPME = testxio(lchsa, &rstatus))) { - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "TIO ret PSD1 %x rchsa %x lchsa %x status %x BLK %1x\n", PSD1, rchsa, lchsa, rstatus, CPUSTATUS&0x80?1:0); goto newpsd; /* error returned, trap cpu */ } PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "TIO ret PSD1 %08x lchsa %04x stat %08x spad %08x INTS[%02x] %08x BLK %1x\n", PSD1, lchsa, rstatus, t, ix, INTS[ix], CPUSTATUS&0x80?1:0); break; @@ -6748,7 +7131,7 @@ mcheck: if ((TRAPME = stopxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, "STPIO ret rchsa %04x lchsa %04x status %08x\n", + sim_debug(DEBUG_XIO, my_dev, "STPIO ret rchsa %04x lchsa %04x status %08x\n", rchsa, lchsa, rstatus); break; @@ -6760,7 +7143,7 @@ mcheck: INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */ SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, "RSCHNL rschnlxio ret rchsa %04x lchsa %04x status %08x\n", + sim_debug(DEBUG_XIO, my_dev, "RSCHNL rschnlxio ret rchsa %04x lchsa %04x status %08x\n", rchsa, lchsa, rstatus); break; @@ -6768,7 +7151,7 @@ mcheck: if ((TRAPME = haltxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "HIO haltxio ret rchsa %04x lchsa %04x status %08x\n", rchsa, lchsa, rstatus); break; @@ -6777,7 +7160,7 @@ mcheck: if ((TRAPME = grabxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, "GRIO ret rchsa %04x lchsa %04x status %08x\n", + sim_debug(DEBUG_XIO, my_dev, "GRIO ret rchsa %04x lchsa %04x status %08x\n", rchsa, lchsa, rstatus); break; @@ -6785,23 +7168,23 @@ mcheck: if ((TRAPME = rsctlxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, "RSCTL ret rchsa %04x lchsa %04x status %08x\n", + sim_debug(DEBUG_XIO, my_dev, "RSCTL ret rchsa %04x lchsa %04x status %08x\n", rchsa, lchsa, rstatus); break; case 0x0C: /* Enable channel interrupt ECI */ /* disable int only */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "ECI chsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n", rchsa, lchsa, t, ix, INTS[ix]); if ((TRAPME = checkxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "ECI after checkxio rchsa %04x suba %04x status %08x\n", rchsa, suba, rstatus); if ((INTS[ix] & INTS_ACT) == 0) - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "ECI INT %02x is NOT set rchsa %04x lchsa %04x status %08x\n", ix, rchsa, lchsa, rstatus); /* SPAD entries for interrupts begin at 0x80 */ @@ -6814,17 +7197,17 @@ mcheck: case 0x0D: /* Disable channel interrupt DCI */ /* disable int, leave req */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "DCI rchsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n", rchsa, lchsa, t, ix, INTS[ix]); if ((TRAPME = checkxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "DCI After checkxio call rstatus %08x\n", rstatus); /* doc says we need to drop 1 queued status entry too */ if ((INTS[ix] & INTS_ACT) == 0) - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "DCI INT %02x is NOT set rchsa %04x lchsa %04x status %08x\n", ix, rchsa, lchsa, rstatus); /* SPAD entries for interrupts begin at 0x80 */ @@ -6835,14 +7218,14 @@ mcheck: case 0x0E: /* Activate channel interrupt ACI */ /* Set int active, clear request */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "ACI rchsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n", rchsa, lchsa, t, ix, INTS[ix]); if ((TRAPME = checkxio(lchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ if ((INTS[ix] & INTS_ACT) == 0) - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "ACI INT %02x is NOT set rchsa %04x lchsa %04x status %08x\n", ix, rchsa, lchsa, rstatus); /* SPAD entries for interrupts begin at 0x80 */ @@ -6854,14 +7237,14 @@ mcheck: case 0x0F: /* Deactivate channel interrupt DACI */ /* Clear active and leave any request */ /* Note, instruction following DACI is not interruptable */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "DACI rchsa %04x lchsa %04x spad %08x INTS[%02x] %08x\n", rchsa, lchsa, t, ix, INTS[ix]); if ((TRAPME = checkxio(rchsa, &rstatus))) goto newpsd; /* error returned, trap cpu */ if ((INTS[ix] & INTS_ACT) == 0) - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "DACI INT %02x is NOT set chan %04x suba %04x status %08x\n", ix, chan, suba, rstatus); /* SPAD entries for interrupts begin at 0x80 */ @@ -6870,7 +7253,7 @@ mcheck: irq_pend = 1; /* start scanning interrupts again */ skipinstr = 1; /* skip interrupt test */ PSD1 = ((PSD1 & 0x87fffffe) | (rstatus & 0x78000000)); /* insert status */ - sim_debug(DEBUG_XIO, &cpu_dev, + sim_debug(DEBUG_XIO, my_dev, "DACI ret lchsa %04x status %08x spad %08x INTS[%02x] %08x BLK %1x\n", lchsa, rstatus, t, ix, INTS[ix], CPUSTATUS&0x80?1:0); break; @@ -6889,8 +7272,8 @@ mcheck: if (dbl) { /* if double reg, store 2nd reg */ if (reg & 1) { /* is it double regs into odd reg */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "ADDRSPEC13 OP %04x addr %08x\n", OP, addr); + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC13 OP %04x addr %08x reg %x\n", OP, addr, reg); goto newpsd; /* go execute the trap now */ } GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ @@ -6904,6 +7287,8 @@ mcheck: if (i_flags & SB) { if (dbl) { /* no dbl wd store to base regs */ TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC14 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } BR[reg] = (uint32)(dest & FMASK); /* save the base reg */ @@ -6921,6 +7306,8 @@ mcheck: case 2: /* double word store */ if ((addr & 7) != 2) { TRAPME = ADDRSPEC_TRAP; /* address not on dbl wd boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC14 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } temp = (uint32)(dest & MASK32);/* get lo 32 bit */ @@ -6934,6 +7321,8 @@ mcheck: if ((addr & 3) != 0) { /* Address fault */ TRAPME = ADDRSPEC_TRAP; /* address not on wd boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC15 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } break; @@ -6944,6 +7333,8 @@ mcheck: if ((addr & 1) != 1) { /* Address fault */ TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC16 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } break; @@ -6953,6 +7344,8 @@ mcheck: temp |= (uint32)(dest & RMASK); /* put into right most 16 bits */ if ((addr & 3) != 3) { TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC17 OP %04x addr %08x\n", OP, addr); goto newpsd; /* go execute the trap now */ } break; @@ -7000,8 +7393,7 @@ mcheck: EXM_EXR = 0; /* reset PC increment for EXR */ } else if (i_flags & HLF) { /* if nop in rt hw, bump pc a word */ - if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6))) - { + if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6))) { PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); } else { PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); @@ -7009,11 +7401,10 @@ mcheck: } else { PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); } - drop_nop = 0; /* no NOP to drop */ } else { EXM_EXR = 0; /* reset PC increment for EXR */ - drop_nop = 0; /* no NOP to drop */ } + drop_nop = 0; /* no NOP to drop */ OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ @@ -7023,7 +7414,11 @@ mcheck: hst[hst_p].npsd1 = PSD1; /* save new psd1 */ hst[hst_p].npsd2 = PSD2; /* save new psd2 */ hst[hst_p].modes = MODES; /* save current mode bits */ - hst[hst_p].modes |= (CPUSTATUS & BIT24); /* save blocking mode bit */ + hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */ + if (CPUSTATUS & BIT24) + hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */ + if (CPUSTATUS & BIT27) + hst[hst_p].modes |= IPUMODE; /* save cpu/ipu status bit */ for (ix=0; ix<8; ix++) { hst[hst_p].reg[ix] = GPR[ix]; /* save reg */ hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */ @@ -7044,32 +7439,25 @@ mcheck: BK = 'B'; else BK = 'U'; - sim_debug(DEBUG_INST, &cpu_dev, "%c%c%c %.8x %.8x %.8x ", + sim_debug(DEBUG_INST, my_dev, "%s %c%c%c %.8x %.8x %.8x ", + (CPUSTATUS & BIT27) ? "IPU": "CPU", BM, MM, BK, OPSD1, PSD2, OIR); if (cpu_dev.dctrl & DEBUG_INST) { fprint_inst(sim_deb, OIR, 0); /* display instruction */ - sim_debug(DEBUG_INST, &cpu_dev, + sim_debug(DEBUG_INST, my_dev, "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_INST, &cpu_dev, + sim_debug(DEBUG_INST, my_dev, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - if (MODES & BASEBIT) { - sim_debug(DEBUG_INST, &cpu_dev, - "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); - sim_debug(DEBUG_INST, &cpu_dev, - " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); + if (MODES & BASEBIT) { + sim_debug(DEBUG_INST, my_dev, + "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); + sim_debug(DEBUG_INST, my_dev, + " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); + } } - } -#ifdef BAD_02102022 - SPAD[0xf5] = PSD2; /* save the current PSD2 */ - SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ -#endif continue; /* keep running */ newpsd: -#ifndef BAD_02102022 - SPAD[0xf5] = PSD2; /* save the current PSD2 */ - SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ -#endif /* Trap Context Block - 6 words */ /* WD1 Old PSD Wd 1 */ /* WD2 Old PSD Wd 2 */ @@ -7099,8 +7487,13 @@ newpsd: /* SPAD location 0xf0 has trap vector base address */ uint32 tta = SPAD[0xf0]; /* get trap table address in memory */ uint32 tvl; /* trap vector location */ - if ((tta == 0) || ((tta&MASK24) == MASK24)) - tta = 0x80; /* if not set, assume 0x80 FIXME */ + if ((tta == 0) || ((tta&MASK24) == MASK24)) { + if (CPUSTATUS & ONIPU) { + tta = 0x20; /* if not set, assume 0x20 FIXME */ + } else { + tta = 0x80; /* if not set, assume 0x80 FIXME */ + } + } /* Trap Table Address in memory is pointed to by SPAD 0xF0 */ /* TODO update cpu status and trap status words with reason too */ switch(TRAPME) { @@ -7114,9 +7507,11 @@ newpsd: case MACHINECHK_TRAP: /* 0x9C PL07 Machine Check Trap */ case SYSTEMCHK_TRAP: /* 0xA0 PL08 System Check Trap */ case MAPFAULT_TRAP: /* 0xA4 PL09 Map Fault Trap */ +//MOVED case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */ case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */ //MOVED case CALM_TRAP: /* 0xA8 PL0A Call Monitor Instruction Trap */ - case SIGNALIPU_TRAP: /* 0xAC PL0B Signal IPU/CPU Trap */ +//MOVED case SIGNALIPU_TRAP: /* 0xAC PL0B Signal IPU/CPU Trap */ + case ADDRSPEC_TRAP: /* 0xB0 PL0C Address Specification Trap */ //BAD HERE case CONSOLEATN_TRAP: /* 0xB4 PL0D Console Attention Trap */ case PRIVHALT_TRAP: /* 0xB8 PL0E Privlege Mode Halt Trap */ @@ -7124,9 +7519,10 @@ newpsd: case CACHEERR_TRAP: /* 0xC0 PL10 Cache Error Trap (V9 Only) */ /* drop through */ default: - sim_debug(DEBUG_TRAP, &cpu_dev, - "##TRAPME %02x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %1x i_flags %04x\n", - TRAPME, PSD1, PSD2, CPUSTATUS, drop_nop, i_flags); + sim_debug(DEBUG_EXP, my_dev, + "##TRAPME @%s %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %1x i_flags %04x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + TRAPME, PSD1, PSD2, CPUSTATUS, drop_nop, i_flags); /* adjust PSD1 to next instruction */ /* Update instruction pointer to next instruction */ if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */ @@ -7141,7 +7537,6 @@ newpsd: } else { PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); } - drop_nop = 0; } else { PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); //DIAG fix for test 34/10 in MMM diag, reset bit 31 @@ -7153,11 +7548,11 @@ newpsd: EXM_EXR = 0; /* reset PC increment for EXR */ if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL >= MODEL_V6))) PSD1 &= ~BIT31; /* force off last right */ - drop_nop = 0; - sim_debug(DEBUG_TRAP, &cpu_dev, - "##GOT BT TRAPME %04x LOAD MAPS PSD1 %08x PSD2 %08x\n", + sim_debug(DEBUG_TRAP, my_dev, + "##GOT BT TRAPME %02x LOAD MAPS PSD1 %08x PSD2 %08x\n", TRAPME, PSD1, PSD2); } + drop_nop = 0; /* fall through */ /* do not update pc for page fault */ case DEMANDPG_TRAP: /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ @@ -7166,32 +7561,37 @@ newpsd: if (CPU_MODEL >= MODEL_V9) PSD1 &= ~BIT31; /* force off last right */ /* pfault will have 11 bit page number and bit 0 set if op fetch */ - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "##PAGEFAULT TRAPS %02x page# %04x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTATUS %08x\n", TRAPME, pfault, PSD1, PSD2, CPUSTATUS); } - /* Moved here 05/28/2021 so PC gets incremented incorrectly */ + /* Moved here 05/28/2021 so PC gets incremented correctly */ /* This caused the 2nd instruction of an int service routine to be skipped */ /* The attn trap had to be on 2nd instruction */ case CONSOLEATN_TRAP: /* 0xB4 PL0D Console Attention Trap */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "At TRAPME %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %02x\n", - TRAPME, PSD1, PSD2, CPUSTATUS, drop_nop); - sim_debug(DEBUG_TRAP, &cpu_dev, - "At TRAP %02x IR %08x PSD1 %08x PSD2 %08x CPUSTATUS %08x ovr %01x drop_nop %01x\n", - TRAPME, IR, PSD1, PSD2, CPUSTATUS, ovr, drop_nop); - sim_debug(DEBUG_TRAP, &cpu_dev, +//112522 case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */ + case SIGNALIPU_TRAP: /* 0xAC PL0B Signal IPU/CPU Trap */ + sim_debug(DEBUG_TRAP, my_dev, + "At %s TRAPME %02x PC %08x PSD1 %08x PSD2 %08x CPUSTATUS %08x tta %02x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", + TRAPME, PC, PSD1, PSD2, CPUSTATUS, tta); + sim_debug(DEBUG_TRAP, my_dev, + "At %s TRAP %02x IR %08x PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %01x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", + TRAPME, IR, PSD1, PSD2, CPUSTATUS, drop_nop); + sim_debug(DEBUG_TRAP, my_dev, "R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_TRAP, &cpu_dev, + sim_debug(DEBUG_TRAP, my_dev, "R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); tta = tta + (TRAPME - 0x80); /* tta has mem addr of trap vector */ - if (MODES & (BASEBIT | EXTDBIT)) - tvl = M[tta>>2] & 0xFFFFFC; /* get 24 bit trap address from trap vector loc */ - else - tvl = M[tta>>2] & 0x7FFFC; /* get 19 bit trap address from trap vector loc */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "tvl %08x, tta %08x status %08x page# %04x\n", tvl, tta, CPUSTATUS, pfault); + tvl = M[tta>>2] & 0xFFFFFC; /* get 24 bit trap address from trap vector loc */ + sim_debug(DEBUG_TRAP, my_dev, + "tvl %08x, tta %02x CCW %08x status %08x\n", + tvl, tta, CCW, CPUSTATUS); + sim_debug(DEBUG_TRAP, my_dev, + "M[tta] %08x M[tvl] %08x M[tvl+1] %08x M[tvl+2] %08x M[tvl+3]] %08x\n", + M[tta>>2], M[(tvl>>2)+0], M[(tvl>>2)+1], M[(tvl>>2)+2], M[(tvl>>2)+3]); #ifndef TEMP_CHANGE_FOR_MPX3X_DEBUG if (tvl == 0 || (CPUSTATUS & 0x40) == 0) { #else @@ -7203,14 +7603,29 @@ newpsd: /* vector is zero or software has not enabled traps yet */ /* execute a trap halt */ /* set the PSD to trap vector location */ - fprintf(stderr, "[][][][][][][][][][] HALT TRAP [][][][][][][][][][]\r\n"); - fprintf(stderr, "PSD1 %08x PSD2 %08x TRAPME %04x\r\n", PSD1, PSD2, TRAPME); - PSD1 = 0x80000000 + TRAPME; /* just priv and PC to trap vector */ + fprintf(stderr, "[][][][][][][][][][] HALT TRAP [2][][][][][][][][][]\r\n"); + fprintf(stderr, "PSD1 %08x PSD2 %08x TRAPME %02x\r\n", PSD1, PSD2, TRAPME); +//FIX PSD1 = 0x80000000 + TRAPME; /* just priv and PC to trap vector */ + PSD1 = 0x80000000 + tta; /* just priv and PC to trap vector */ PSD2 = 0x00004000; /* unmapped, blocked interrupts mode */ - M[0x680>>2] = PSD1; /* store PSD 1 */ - M[0x684>>2] = PSD2; /* store PSD 2 */ - M[0x688>>2] = TRAPSTATUS; /* store trap status */ - M[0x68C>>2] = 0; /* This will be device table entry later TODO */ + /* + * Some illegal traps result in automatic TRAP HALT + * as per V6 TM page 2-50 locations for saving status + * obviously differ for CPU and IPU + */ + if (CPUSTATUS & ONIPU) { + /* for IPU */ + M[0x690>>2] = PSD1; /* store PSD 1 */ + M[0x694>>2] = PSD2; /* store PSD 2 */ + M[0x698>>2] = TRAPSTATUS; /* store trap status */ + M[0x69C>>2] = 0; /* This will be device table entry later TODO */ + } else { + /* for CPU */ + M[0x680>>2] = PSD1; /* store PSD 1 */ + M[0x684>>2] = PSD2; /* store PSD 2 */ + M[0x688>>2] = TRAPSTATUS; /* store trap status */ + M[0x68C>>2] = 0; /* This will be device table entry later TODO */ + } for (ix=0; ix<8; ix+=2) { fprintf(stderr, "GPR[%d] %08x GPR[%d] %08x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]); } @@ -7219,8 +7634,33 @@ newpsd: fprintf(stderr, "BR[%d] %08x BR[%d] %08x\r\n", ix, BR[ix], ix+1, BR[ix+1]); } } - fprintf(stderr, "[][][][][][][][][][] HALT TRAP [][][][][][][][][][]\r\n"); + fprintf(stderr, "[][][][][][][][][][] HALT TRAP [2][][][][][][][][][]\r\n"); + if (IPU_MODEL && (CPUSTATUS & ONIPU)) { + sim_debug(DEBUG_TRAP, my_dev, + "%s: Halt TRAP CPUSTATUS %08x CCW %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", + CPUSTATUS, CCW); + +#ifndef CPUONLY +#ifdef NO_KILL_112422 + /* If we have an IPU, and we are on the CPU: destroy the IPU */ + if ((CCW & HASIPU) && IPC != 0 && !(CPUSTATUS & ONIPU)) { + kill(IPC->pid[1], SIGKILL); /* destroy the IPU */ + } +#endif +#endif + } +#ifndef USE_IPU_THREAD +/*TEST DIAG*/reason = STOP_HALT; /* do halt for now */ return STOP_HALT; /* exit to simh for halt */ +#else +/*TEST DIAG*/ reason = STOP_HALT; /* do halt for now */ + cpustop = reason; /* tell IPU our state */ + sim_debug(DEBUG_TRAP, my_dev, + "[][][][][][][][][][] Send HALT to IPU [][][][][][][][][][]\n"); + fflush(sim_deb); + return STOP_HALT; /* exit to simh for halt */ +#endif } else { uint32 oldstatus = CPUSTATUS; /* keep for retain blocking state */ /* valid vector, so store the PSD, fetch new PSD */ @@ -7236,8 +7676,8 @@ newpsd: M[(tvl>>2)+4] = TRAPSTATUS; /* store trap status */ if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ M[(tvl>>2)+5] = pfault; /* store page fault number */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "DPAGE tvl %06x PSD1 %08x PSD2 %08x TRAPME %04x TRAPSTATUS %08x\n", + sim_debug(DEBUG_TRAP, my_dev, + "DPAGE tvl %06x PSD1 %08x PSD2 %08x TRAPME %02x TRAPSTATUS %08x\n", tvl, PSD1, PSD2, TRAPME, pfault); } @@ -7245,7 +7685,7 @@ newpsd: CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */ - CPUSTATUS |= MODES; /* now insert into CPUSTATUS */ + CPUSTATUS |= (MODES & 0x87000000); /* now insert into CPUSTATUS */ /* set new map mode and interrupt blocking state in CPUSTATUS */ if (PSD2 & MAPBIT) { @@ -7253,7 +7693,7 @@ newpsd: MODES |= MAPMODE; /* set mapped mode */ } else { CPUSTATUS &= ~BIT8; /* reset bit 8 of cpu status */ -/*TRY_01072022*/ MODES &= ~MAPMODE; /* reset mapped mode */ + MODES &= ~MAPMODE; /* reset mapped mode */ } /* set interrupt blocking state */ @@ -7267,7 +7707,7 @@ newpsd: } } else { /* handle retain blocking state */ - PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + PSD2 &= ~RETMBIT; /* turn off retain map bit in PSD2 */ /* set new blocking state in PSD2 */ PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ MODES &= ~(BLKMODE|RETBLKM);/* reset blocked & retain mode bits */ @@ -7280,82 +7720,69 @@ newpsd: SPAD[0xf5] = PSD2; /* save the current PSD2 */ SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "Process TRAPME %04x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n", - TRAPME, PSD1, PSD2, CPUSTATUS); + sim_debug(DEBUG_TRAP, my_dev, + "Process %s TRAPME %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x MODE %08x\n", + (CPUSTATUS & ONIPU)? "IPU": "CPU", +//FIX TRAPME, PSD1, PSD2, CPUSTATUS, MODES); + tta, PSD1, PSD2, CPUSTATUS, MODES); /* TODO provide page fault data to word 6 */ if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ /* Set map number */ /* pfault will have 11 bit page number and bit 0 set if op fetch */ - sim_debug(DEBUG_TRAP, &cpu_dev, - "PAGE TRAP %04x TSTAT %08x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTAT %08x pfault %08x\n", - TRAPME, TRAPSTATUS, PSD1, PSD2, CPUSTATUS, pfault); + sim_debug(DEBUG_TRAP, my_dev, + "PAGE TRAP %02x TSTAT %08x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTAT %08x pfault %08x\n", + TRAPME, TRAPSTATUS, PSD1, PSD2, CPUSTATUS, pfault); } TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */ + TRAPME = 0; /* to be safe */ break; /* Go execute the trap */ } break; } } - /* we have a new PSD loaded via a LPSD or LPSDCM */ - /* finish instruction history, then continue */ - /* update cpu status word too */ - OPSD1 &= 0x87FFFFFF; /* clear the old CC's */ - OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ - /* Update other history information for this instruction */ - if (hst_lnt) { - hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */ - hst[hst_p].npsd1 = PSD1; /* save new psd1 */ - hst[hst_p].npsd2 = PSD2; /* save new psd2 */ - hst[hst_p].modes = MODES; /* save current mode bits */ - hst[hst_p].modes |= (CPUSTATUS & BIT24); /* save blocking mode bit */ - for (ix=0; ix<8; ix++) { - hst[hst_p].reg[ix] = GPR[ix]; /* save reg */ - hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */ - } - } - - /* DEBUG_INST support code */ - /* output mapped/unmapped */ - if (MODES & BASEBIT) - BM = 'B'; - else - BM = 'N'; - if (MODES & MAPMODE) - MM = 'M'; - else - MM = 'U'; - if (CPUSTATUS & BIT24) - BK = 'B'; - else - BK = 'U'; - sim_debug(DEBUG_INST, &cpu_dev, "%c%c%c %.8x %.8x %.8x ", - BM, MM, BK, OPSD1, PSD2, OIR); - if (cpu_dev.dctrl & DEBUG_INST) { - fprint_inst(sim_deb, OIR, 0); /* display instruction */ - sim_debug(DEBUG_INST, &cpu_dev, - "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]); - sim_debug(DEBUG_INST, &cpu_dev, - " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); - if (MODES & BASEBIT) { - sim_debug(DEBUG_INST, &cpu_dev, - "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); - sim_debug(DEBUG_INST, &cpu_dev, - " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); - } - } continue; /* single step cpu just for now */ - } /* end while */ + } /* end wait loop while */ /* Simulation halted */ - return reason; + sim_debug(DEBUG_EXP, my_dev, + "Process Event other reason %08x interval %08x\n", + reason, sim_interval); + + /* we need to do an actual halt here if on IPU */ + sim_debug(DEBUG_EXP, my_dev, + "\n[][][][][][][][][][] HALT [3][][][][][][][][][]\n"); + sim_debug(DEBUG_EXP, my_dev, + "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x\n", + (CPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, CPUSTATUS); + for (ix=0; ix<8; ix+=2) { + sim_debug(DEBUG_EXP, my_dev, + "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } + sim_debug(DEBUG_EXP, my_dev, + "[][][][][][][][][][] HALT [3][][][][][][][][][]\n"); + fflush(sim_deb); + +#ifndef USE_IPU_THREAD +#ifdef DEBUG4IPU + DumpHist(); +#endif +#endif + fprintf(stdout, "[][][][][][][][][][] IPU HALT3 [3][][][][][][][][][]\r\n"); + fflush(stdout); +#ifdef USE_IPU_THREAD + pthread_exit((void *)&reason); +#endif + return reason; /* exit to simh for halt */ } /* these are the default ipl devices defined by the CPU jumpers */ /* they can be overridden by specifying IPL device at ipl time */ -uint32 def_disk = 0x0800; /* disk channel 8, device 0 */ -uint32 def_tape = 0x1000; /* tape device 10, device 0 */ -uint32 def_floppy = 0x7ef0; /* IOP floppy disk channel 7e, device f0 */ +#ifndef USE_IPU_THREAD +LOCAL uint32 def_disk = 0x0800; /* disk channel 8, device 0 */ +LOCAL uint32 def_floppy = 0x7ef0; /* IOP floppy disk channel 7e, device f0 */ +#endif +LOCAL uint32 def_tape = 0x1000; /* tape device 10, device 0 */ /* Reset routine */ /* do any one time initialization here for cpu */ @@ -7373,26 +7800,64 @@ t_stat cpu_reset(DEVICE *dptr) CPUSTATUS |= PRIVBIT; /* set privleged state bit 0 */ CPUSTATUS |= BIT24; /* set blocked mode state bit 24 */ CPUSTATUS |= BIT22; /* set HS floating point unit not present bit 22 */ +#ifdef USE_IPU_THREAD +// IPUSTATUS |= ONIPU; /* set ipu state in ipu status, BIT27 */ +#endif TRAPSTATUS = CPU_MODEL; /* clear all trap status except cpu type */ CMCR = 0; /* No Cache Enabled */ SMCR = 0; /* No Shared Memory Enabled */ CMSMC = 0x00ff0a10; /* No V9 Cache/Shadow Memory Configuration */ CSMCW = 0; /* No V9 CPU Shadow Memory Configuration */ ISMCW = 0; /* No V9 IPU Shadow Memory Configuration */ +#ifdef NOT_USED RDYQIN = RDYQOUT = 0; /* initialize channel ready queue */ +#endif + +#ifndef CPUONLY +#ifndef USE_IPU_THREAD + /* allocate the memory here and now, but only once */ + /* add extra for IPU structure for IPU when running forked */ + if (M == 0) { + /* first pass of cpu_reset: alloc our SELbus memory */ + M = (uint32 *)create_shared_memory(4 * MAXMEMSIZE + sizeof(struct ipcom)); + for (i = 0; i < MAXMEMSIZE + ((sizeof(struct ipcom)+3)/4) - 1; i++) + M[i] = 0; /* zero all of the new memory & IPC */ + /* Create InterProcessor Com data */ + /* we piggyback on the main memory that we created larger */ + IPC = (struct ipcom *)&M[MAXMEMSIZE]; + } +#else + /* local memory is shared, and is defined as M[MAXMEMSIZE] */ + /* no special allocation is required for 2nd thread */ + IPC = (struct ipcom *)&myipc; +#endif +#else /* CPUONLY */ + /* local memory is not shared, and is defined as M[MAXMEMSIZE] */ + /* no special allocation is required on CPU only */ +#endif /* CPUONLY */ + +#ifdef USE_IPU_THREAD + ipu_unit.flags = cpu_unit.flags; /* tell ipu about cpu flags */ + ipu_unit.capac = cpu_unit.capac; /* tell ipu about memory */ +#endif + + if (IPU_MODEL) + CCW |= HASIPU; /* this is BIT19 */ devs = chan_set_devs(); /* set up the defined devices on the simulator */ /* set default breaks to execution tracing */ sim_brk_types = sim_brk_dflt = SWMASK('E'); + /* zero regs */ for (i = 0; i < 8; i++) { GPR[i] = BOOTR[i]; /* set boot register values */ BR[i] = 0; /* clear the registers */ } - +#ifndef USE_IPU_THREAD /* set console switch settings */ M[0x780>>2] = CSW; /* set console switch settings */ +#endif /* zero interrupt status words */ for (i = 0; i < 112; i++) @@ -7403,10 +7868,31 @@ t_stat cpu_reset(DEVICE *dptr) /* otherwise set the default values into the spad */ /* CPU key is 0xECDAB897, IPU key is 0x13254768 */ /* Keys are loaded by the O/S software during the boot loading sequence */ - if (SPAD[0xf7] != 0xecdab897) - { + /* + * SPAD init for both CPU and IPU unless they have the right key + */ + if (SPAD[0xf7] != 0xecdab897 && SPAD[0xf7] != 0x13254768) { int ival = 0; /* init value for concept 32 */ +#ifndef CPUONLY +#ifndef USE_IPU_THREAD + /* If we have a forked IPU, and we are on the CPU: destroy the IPU */ + if ((CCW & HASIPU) && IPC != 0 && !(CPUSTATUS & ONIPU) && (IPC->pid[1] != 0)) { + fprintf(stdout,"CCW %x IPC %p CPUSTATUS %x\r\n", CCW, IPC, CPUSTATUS); + fprintf(stdout,"Killing IPU pid=%d 0x80=%x\r\n", IPC->pid[1], SPAD[0xf0]); + fflush(stdout); + kill(IPC->pid[1], SIGKILL); /* destroy the IPU */ + } +#else +#ifndef USE_POSIX_SEM + /* intialize the pthread mutex and cond on thread IPU/CPU */ +// IPC->mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_init(&IPC->mutex, NULL); +// IPC->cond = PTHREAD_COND_INITIALIZER; + pthread_cond_init(&IPC->cond, NULL); +#endif +#endif +#endif if (CPU_MODEL < MODEL_27) ival = 0xfffffff; /* init value for 32/7x int and dev entries */ for (i = 0; i < 1024; i++) @@ -7415,18 +7901,34 @@ t_stat cpu_reset(DEVICE *dptr) SPAD[i] = ival; /* init 128 devices and 96 ints in the spad */ for (i = 224; i < 256; i++) /* clear the last 32 extries */ SPAD[i] = 0; /* clear the spad */ +#ifndef CPUONLY + if (CPUSTATUS & ONIPU) + SPAD[0xf0] = 0x20; /* default Trap Table Address (TTA) */ + else + SPAD[0xf0] = 0x80; /* default Trap Table Address (TTA) */ +#else SPAD[0xf0] = 0x80; /* default Trap Table Address (TTA) */ +#endif SPAD[0xf1] = 0x100; /* Interrupt Table Address (ITA) */ SPAD[0xf2] = 0x700; /* IOCD Base Address */ SPAD[0xf3] = 0x788; /* Master Process List (MPL) table address */ SPAD[0xf4] = def_tape; /* Default IPL address from console IPL command or jumper */ SPAD[0xf5] = PSD2; /* current PSD2 defaults to blocked */ SPAD[0xf6] = 0; /* reserved (PSD1 ??) */ +#ifndef CPUONLY + if (CPUSTATUS & ONIPU) + SPAD[0xf7] = 0x13254768; /* set SPAD key for IPU */ + else + SPAD[0xf7] = 0xecdab897; /* load the CPU key */ +#else SPAD[0xf7] = 0xecdab897; /* load the CPU key */ - SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */ +#endif +//120822SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */ + SPAD[0xf8] = 0x0f000000; /* set DRT to class f (anything else is E) */ SPAD[0xf9] = CPUSTATUS; /* set default cpu type in cpu status word */ SPAD[0xff] = 0x00ffffff; /* interrupt level 7f 1's complament */ } + #if 0 /* set low memory bootstrap code */ /* moved to boot code in sel32_chan.c so we can reset system and not destroy memory */ @@ -7437,6 +7939,33 @@ t_stat cpu_reset(DEVICE *dptr) M[4] = 0x02000000; /* 0x10 IOCD 3 Read into address 0 */ M[5] = 0x000006EC; /* 0x14 IOCD 3 Read 0x6EC bytes */ #endif + +#ifndef LEAVE_THIS_CODE_FOR_AWHILE +#ifndef CPUONLY +#ifndef USE_IPU_THREAD + /* the IPU should never get to this code! */ +// fprintf(stdout,"LEAVE CCW %x IPC %p CPUSTATUS %x\r\n", CCW, IPC, CPUSTATUS); + if (CPUSTATUS & ONIPU) { + /* I am the IPU */ + if (IPC != 0) { + fprintf(stdout,"IPU IPC %p pid=%d 0x80=%x\r\n", IPC, IPC->pid[1], SPAD[0xf0]); + fflush(stdout); + } + } else { + /* I am the CPU */ +// if (IPC != 0) { + if (IPC != 0 && !(CPUSTATUS & ONIPU) && (IPC->pid[1] != 0)) { + fprintf(stdout,"CPU IPC %p pid=%d IPU pid %d 0x80=%x\r\n", IPC, IPC->pid[0], IPC->pid[1], SPAD[0xf0]); + fflush(stdout); + fprintf(stdout,"Killing IPU pid=%d 0x80=%xi\r\n", IPC->pid[1], SPAD[0xf0]); + fflush(stdout); + kill(IPC->pid[1], SIGKILL); /* destroy the IPU */ + } + } +#endif +#endif +#endif + fflush(sim_deb); loading = 0; /* not loading yet */ /* we are good to go or error from device setup */ if (devs != SCPE_OK) @@ -7454,7 +7983,7 @@ t_stat cpu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw) if (sw & SWMASK('V')) { /* convert address to real physical address */ status = RealAddr(addr, &realaddr, &prot, MEM_RD); - sim_debug(DEBUG_CMD, &cpu_dev, "cpu_ex Mem_read status = %02x\n", status); + sim_debug(DEBUG_CMD, my_dev, "cpu_ex Mem_read status = %02x\n", status); if (status == ALLOK) { *vptr = (M[realaddr] >> (8 * (3 - (baddr & 0x3)))); /* return memory contents */ return SCPE_OK; /* we are all ok */ @@ -7509,13 +8038,19 @@ t_stat cpu_set_size(UNIT *uptr, int32 sval, CONST char *cptr, void *desc) int32 val = (int32)sval; t_addr msize; +// sim_printf("cpu_set_size sval %x cptr %s desc %s\n", sval, cptr, (char *)desc); val >>= UNIT_V_MSIZE; /* shift index right 19 bits */ + +// fprintf(stdout, "at cpu_set_size sval %x val %x\r\n", sval, val); +// fflush (stdout); + if (val >= (int32)(sizeof(memwds)/sizeof(uint32))) /* is size valid */ return SCPE_ARG; /* nope, argument error */ sz = memwds[val]; /* (128KB/4) << index == memory size in KW */ if ((sz <= 0) || (sz > MAXMEMSIZE)) /* is size valid */ return SCPE_ARG; /* nope, argument error */ msize = sz << 2; /* Convert to words */ + if (msize < MEMSIZE) { /* is size smaller */ uint32 mc = 0; /* yes, see if larger memory was used */ for (i = sz-1; i < (MEMSIZE>>2); i++) @@ -7526,11 +8061,57 @@ t_stat cpu_set_size(UNIT *uptr, int32 sval, CONST char *cptr, void *desc) for (i = (MEMSIZE>>2) - 1; i < sz; i++) M[i] = 0; /* zero all of the new memory */ cpu_unit.flags &= ~UNIT_MSIZE; /* clear old size value 0-31 */ - cpu_unit.flags |= val << UNIT_V_MSIZE; /* set new memory size index value (0-31) */ + cpu_unit.flags |= (val << UNIT_V_MSIZE); /* set new memory size index value (0-31) */ cpu_unit.capac = (t_addr)msize; /* set new size */ +#ifdef USE_IPU_THREAD + ipu_unit.flags = cpu_unit.flags; /* tell ipu about cpu flags */ + ipu_unit.capac = cpu_unit.capac; /* tell ipu about memory */ +#endif return SCPE_OK; /* we done */ } +#ifdef DEFINE_IPU_MODELS +t_stat cpu_set_ipu(UNIT *uptr, int32 sval, CONST char *cptr, void *desc) +{ +// sim_printf("cpu_set_ipu sval %x cptr %s desc %s\n", sval, cptr, (char *)desc); +#ifdef CPUONLY + sim_printf("IPU not available for this version of sel32\n"); +// return SCPE_OK; /* we done */ + return SCPE_ARG; /* error, we done */ +#endif + if ((CPU_MODEL == MODEL_55) || (CPU_MODEL == MODEL_27)) { + sim_printf("IPU not available for model 32/55 or 32/27\n"); + return SCPE_ARG; /* error, we done */ + } else { + cpu_unit.flags |= (1 << UNIT_V_IPU); /* enable IPU for this MODEL */ +#ifdef USE_IPU_THREAD + ipu_unit.flags = cpu_unit.flags; /* tell ipu about cpu flags */ +#endif + sim_printf("IPU enabled\n"); + } + return SCPE_OK; /* we done */ +} + +t_stat cpu_clr_ipu(UNIT *uptr, int32 sval, CONST char *cptr, void *desc) +{ + cpu_unit.flags &= ~UNIT_IPU; /* disable IPU for this MODEL */ +#ifdef USE_IPU_THREAD + ipu_unit.flags = cpu_unit.flags; /* tell ipu about cpu flags */ +#endif + sim_printf("IPU disabled\n"); + return SCPE_OK; /* we done */ +} + +t_stat cpu_show_ipu(FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + if (IPU_MODEL) + sim_printf("IPU enabled\n"); + else + sim_printf("IPU disabled\n"); + return SCPE_OK; /* we done */ +} +#endif + /* Handle execute history */ /* Set history */ @@ -7540,6 +8121,7 @@ cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc) int32 i, lnt; t_stat r; +// sim_printf("cpu_set_hist val %x cptr %s desc %s\n", val, cptr, (char *)desc); if (cptr == NULL) { /* check for any user options */ for (i = 0; i < hst_lnt; i++) /* none, so just zero the history */ hst[i].opsd1 = 0; /* just psd1 for now */ @@ -7588,23 +8170,26 @@ t_stat cpu_show_hist(FILE *st, UNIT *uptr, int32 val, CONST void *desc) for (k = 0; k < lnt; k++) { /* print specified entries */ h = &hst[(++di) % hst_lnt]; /* entry pointer */ /* display the instruction and results */ - if (MODES & BASEBIT) + if (h->modes & BASEBIT) /* basemode? */ BM = 'B'; else BM = 'N'; - if (MODES & MAPMODE) + if (h->modes & MAPMODE) /* copy of PSD2 bit 0 */ MM = 'M'; else MM = 'U'; - if (MODES & 0x80) /* get blocked bit */ + if (h->modes & INTBLKD) /* get blocked bit 0x10 */ BK = 'B'; else BK = 'U'; - fprintf(st, "%c%c%c %.8x %.8x %.8x ", BM, MM, BK, h->opsd1, h->npsd2, h->oir); + fprintf(st, "%s %c%c%c %.8x %.8x %.8x ", + (h->modes & IPUMODE)? "IPU": "CPU", + BM, MM, BK, h->opsd1, h->npsd2, h->oir); if (h->modes & BASEBIT) fprint_inst(st, h->oir, SWMASK('M')); /* display basemode instruction */ else fprint_inst(st, h->oir, SWMASK('N')); /* display non basemode instruction */ + fprintf(st, " --->NPSD %.8x %.8x", h->npsd1, h->npsd2); fprintf(st, "\n"); fprintf(st, "\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", h->reg[0], h->reg[1], h->reg[2], h->reg[3]); fprintf(st, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x", h->reg[4], h->reg[5], h->reg[6], h->reg[7]); @@ -7634,3 +8219,23 @@ t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cpt fprintf(st, " sim> SHOW CPU HISTORY print CPU history\n"); return SCPE_OK; } + +#ifndef CPUONLY +#ifndef USE_IPU_THREAD +#include + +void* create_shared_memory(size_t size) { + // Our memory buffer will be readable and writable: + int protection = PROT_READ | PROT_WRITE; + + // The buffer will be shared (meaning other processes can access it), but + // anonymous (meaning third-party processes cannot obtain an address for it), + // so only this process and its children will be able to use it: + int visibility = MAP_SHARED | MAP_ANONYMOUS; + + // The remaining parameters to `mmap()` are not important for this use case, + // but the manpage for `mmap` explains their purpose. + return mmap(NULL, size, protection, visibility, -1, 0); +} +#endif +#endif diff --git a/SEL32/sel32_defs.h b/SEL32/sel32_defs.h index ce5574ab..6805e5e1 100644 --- a/SEL32/sel32_defs.h +++ b/SEL32/sel32_defs.h @@ -1,6 +1,6 @@ /* sel32_defs.h: SEL-32 Concept/32 simulator definitions - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -21,9 +21,99 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/********************Attention************************/ +/* define the environment wanted for sel32 execution */ +/* */ +/* define CPUONLY to only run with CPU model */ +/* undef CPUONLY to run with an IPU (2nd CPU) */ +/* */ +/* for IPU models, define the IPU support method */ +/* define USE_IPU_THREAD to run IPU in a thread */ +/* undef USE_IPU_THREAD to run IPU in forked task */ +/* */ +/* for threaded IPU models, select thread locking */ +/* define USE_POSIX_SEM for POSIX semaphores */ +/* undef USE_POSIX_SEM to use pthread mutexs */ +/********************Attention************************/ + +/* define CPUONLY to run without IPU */ +//#define CPUONLY /* run on CPU only */ +#undef CPUONLY /* run with cpu/ipu on system */ + +/* undefine CPUONLY to run with IPU */ +/* define USE_IPU_THREAD to use IPU thread code instead of fork code */ +/* define USE_POSIX_SEM for POSIX semaphores otherwise use pthread mutex */ +/* forked mode IPU must only use semaphores */ +#ifndef CPUONLY +//#define USE_POSIX_SEM /* use POSIX semaphores, else pthread mutex */ +//#undef USE_IPU_THREAD /* run IPU as a forked sel32 */ +#define USE_IPU_THREAD /* run IPU in sel32_ipu.c thread */ +#endif + +/* enforce proper option combinations for CPU/IPU */ +#ifndef CPUONLY +#define DEFINE_IPU_MODELS /* IPU devices must be define for IPU */ +#ifndef USE_IPU_THREAD +#define USE_POSIX_SEM /* forked mode IPU can only use semaphores */ +#endif +#else /* CPUONLY */ +#undef USE_IPU_THREAD /* make sure IPU code undefined for CPUONLY */ +#undef DEFINE_IPU_MODELS /* make sure IPU models undefine too */ +#endif /* CPU_ONLY */ + +/* use correct variable type for thread IPU */ +#ifdef USE_IPU_THREAD +#ifdef USE_IPU_CODE +#define LOCAL static /* IPU in thread needs static variables */ +#else /* USE_IPU_CODE */ +#define LOCAL /* IPU in fork needs regular variables */ +#endif /* USE_IPU_CODE */ +#else /* USE_IPU_THREAD */ +#define LOCAL /* IPU in fork needs regular variables */ +#endif /* USE_IPU_THREAD */ + +#define HASIPU 0x1000 /* BIT19 */ +#define ONIPU 0x0010 /* BIT27 */ #include "sim_defs.h" /* simh simulator defns */ +#ifndef CPUONLY +#ifdef USE_POSIX_SEM +#include + +/* shared Interprocessor Com for SIPU [0] for CPU [1] for IPU */ +struct ipcom { + int pid[2]; /* process id for each */ + int atrap[2]; /* any Async TRAP to peer */ + int sent[2]; /* counting send calls */ + int received[2]; /* counting received calls */ + int blocked[2]; /* counting blocked calls */ + int dropped[2]; /* counting dropped calls */ + /* anything for semaphores here */ + sem_t simsem; /* the semaphore */ + int pass[2]; /* count passing */ + int wait[2]; /* count waiting */ +}; +#else +/* Use pthread mutexs */ +#include +/* shared Interprocessor Com for SIPU [0] for CPU [1] for IPU */ +struct ipcom { + int pid[2]; /* process id for each */ + int atrap[2]; /* any Async TRAP to peer */ + int sent[2]; /* counting send calls */ + int received[2]; /* counting received calls */ + int blocked[2]; /* counting blocked calls */ + int dropped[2]; /* counting dropped calls */ + /* anything for mutexs here */ + pthread_mutex_t mutex; /* the mutex for controlling access */ + pthread_cond_t cond; /* conditional wait condition */ + int pass[2]; /* count passing */ + int wait[2]; /* count waiting */ +}; +#endif +#endif + /* Simulator stop codes */ #define STOP_IONRDY 1 /* I/O dev not ready */ #define STOP_HALT 2 /* HALT */ @@ -142,6 +232,10 @@ extern DEVICE cpu_dev; /* cpu device */ extern UNIT cpu_unit; /* the cpu unit */ +#ifdef USE_IPU_THREAD +extern DEVICE ipu_dev; /* cpu device */ +extern UNIT ipu_unit; /* the cpu unit */ +#endif #ifdef NUM_DEVS_IOP extern DEVICE iop_dev; /* IOP channel controller */ #endif @@ -344,14 +438,17 @@ extern DEBTAB dev_debug[]; #define DSEXT32(x) (x&0x8000?(l_uint64)(((l_uint64)x&D32RMASK)|D32LMASK):(t_uint64)x) #define NEGATE32(val) ((~val) + 1) /* negate a value 16/32/64 bits */ -/* defined in rightmost 8 bits of upper 16 bits of uptr->flags */ +/* defined in rightmost 9 bits of upper 16 bits of uptr->flags */ #define UNIT_V_MODEL (UNIT_V_UF + 0) -#define UNIT_MODEL (7 << UNIT_V_MODEL) +#define UNIT_MODEL (0xf << UNIT_V_MODEL) #define MODEL(x) (x << UNIT_V_MODEL) -#define UNIT_V_MSIZE (UNIT_V_MODEL + 3) +#define UNIT_V_MSIZE (UNIT_V_MODEL + 4) +#define UNIT_V_IPU (UNIT_V_MODEL + 4) #define UNIT_MSIZE (0x1F << UNIT_V_MSIZE) +#define UNIT_IPU (0x1 << UNIT_V_IPU) #define MEMAMOUNT(x) (x << UNIT_V_MSIZE) -#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_MODEL) & 0x7) /* cpu model 0-7 */ +#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_MODEL) & 0x7)/* cpu model 0-7 */ +#define IPU_MODEL ((cpu_unit.flags >> UNIT_V_IPU) & 0x1) /* ipu model 1 */ #define MODEL_55 0 /* 512K Mode Only */ #define MODEL_75 1 /* Extended */ @@ -361,6 +458,12 @@ extern DEBTAB dev_debug[]; #define MODEL_97 5 /* */ #define MODEL_V6 6 /* V6 CPU */ #define MODEL_V9 7 /* V9 CPU */ +#define MODEL_7780 9 /* */ +#define MODEL_6780 11 /* */ +#define MODEL_8780 12 /* */ +#define MODEL_9780 13 /* */ +#define MODEL_V6IPU 14 /* */ +#define MODEL_V9IPU 15 /* */ #define TMR_RTC 1 /* RTC will not work if set to 0!! */ //#define TMR_RTC 0 @@ -375,10 +478,12 @@ extern DEBTAB dev_debug[]; #define CC3BIT 0x10000000 /* CC3 in PSD1 */ #define CC4BIT 0x08000000 /* CC4 in PSD1 */ -#define MAPMODE 0x40 /* Map mode, PSD 2 bit 0 */ -#define RETMODE 0x20 /* Retain current maps, PSD 2 bit 15 */ -#define RETBLKM 0x10 /* Set retain blocked mode, PSD 2 bit 16 */ +#define IPUMODE 0x20 /* This is running on IPU, bit 27 of CPUSTATUS */ +#define INTBLKD 0x10 /* bit 24 of CPUSTATUS word, set if ints blocked */ #define BLKMODE 0x08 /* Set blocked mode, PSD 2 bit 17 */ +#define MAPMODE 0x04 /* Map mode, PSD 2 bit 0 */ +#define RETMODE 0x02 /* Retain current maps, PSD 2 bit 15 */ +#define RETBLKM 0x01 /* Set retain blocked mode, PSD 2 bit 16 */ /* PSD mode bits in PSD words 1&2 variable */ #define PRIVBIT 0x80000000 /* Privileged mode PSD 1 bit 0 */ @@ -482,6 +587,64 @@ extern DEBTAB dev_debug[]; /* Rename of global PC variable to avoid namespace conflicts on some platforms */ #define PC PC_Global +/* Definitions for commonly used functions */ +extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_dev_addr(FILE * st, UNIT *uptr, int32 v, CONST void *desc); +extern void chan_end(uint16 chan, uint16 flags); +extern int chan_read_byte(uint16 chsa, uint8 *data); +extern int chan_write_byte(uint16 chsa, uint8 *data); +extern void set_devattn(uint16 addr, uint16 flags); +extern void set_devwake(uint16 chsa, uint16 flags); +extern t_stat chan_boot(uint16 addr, DEVICE *dptr); +extern int test_write_byte_end(uint16 chsa); +extern DEVICE *get_dev(UNIT *uptr); +extern t_stat set_inch(UNIT *uptr, uint32 inch_addr, uint32 num_inch); /* set inch addr */ +extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */ + +#ifndef CPUONLY +#ifndef USE_IPU_THREAD +extern struct ipcom *IPC; +extern uint32 *M; /* our memory shared with fork IPU */ +#else +extern struct ipcom *IPC; +extern uint32 M[]; /* our local memory with thread IPU */ +#endif +#else +extern uint32 M[]; /* our local memory without IPU */ +#endif + +#ifndef USE_IPU_CODE +extern uint32 SPAD[]; /* cpu SPAD memory */ +#endif +extern uint32 attention_trap; +extern int irq_pend; /* pending interrupt flag */ + +#ifdef NOT_USED +extern uint32 RDYQ[]; /* ready queue */ +extern uint32 RDYQIN; /* input index */ +extern uint32 RDYQOUT; /* output index */ +extern int32 RDYQ_Put(uint32 entry); +extern int32 RDYQ_Get(uint32 *old); +extern int32 RDYQ_Num(void); +#define RDYQ_SIZE 128 +#endif + +struct InstHistory +{ + uint32 opsd1; /* original PSD1 */ + uint32 opsd2; /* original PSD2 */ + uint32 npsd1; /* new PSD1 after instruction */ + uint32 npsd2; /* new PSD2 after instruction */ + uint32 oir; /* the instruction itself */ + uint32 modes; /* current ipu mode bits */ + uint32 reg[16]; /* regs/bregs for operation */ +}; + +extern char *dump_mem(uint32 mp, int cnt); +extern char *dump_buf(uint8 *mp, int32 off, int cnt); + +#define get_chan(chsa) ((chsa>>8)&0x7f) /* get channel number from ch/sa */ + /* memory access macros */ /* The RMW and WMW macros are used to read/write memory words */ /* RMW(addr) or WMW(addr, data) where addr is a byte alligned word address */ @@ -503,33 +666,4 @@ extern DEBTAB dev_debug[]; /* write halfword map register to MAP cache address */ #define WMR(a,d) ((a)&2?(MAPC[(a)>>2]=(MAPC[(a)>>2]&LMASK)|((d)&RMASK)):(MAPC[(a)>>2]=(MAPC[(a)>>2]&RMASK)|((d)<<16))) -/* Definitions for commonly used functions */ -extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); -extern t_stat show_dev_addr(FILE * st, UNIT *uptr, int32 v, CONST void *desc); -extern void chan_end(uint16 chan, uint16 flags); -extern int chan_read_byte(uint16 chsa, uint8 *data); -extern int chan_write_byte(uint16 chsa, uint8 *data); -extern void set_devattn(uint16 addr, uint16 flags); -extern void set_devwake(uint16 chsa, uint16 flags); -extern t_stat chan_boot(uint16 addr, DEVICE *dptr); -extern int test_write_byte_end(uint16 chsa); -extern DEVICE *get_dev(UNIT *uptr); -extern t_stat set_inch(UNIT *uptr, uint32 inch_addr, uint32 num_inch); /* set inch addr */ -extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */ - -extern uint32 M[]; /* our memory */ -extern uint32 SPAD[]; /* cpu SPAD memory */ -extern uint32 attention_trap; -extern uint32 RDYQ[]; /* ready queue */ -extern uint32 RDYQIN; /* input index */ -extern uint32 RDYQOUT; /* output index */ -#define RDYQ_SIZE 128 -extern int32 RDYQ_Put(uint32 entry); -extern int32 RDYQ_Get(uint32 *old); -extern int32 RDYQ_Num(void); - -extern char *dump_mem(uint32 mp, int cnt); -extern char *dump_buf(uint8 *mp, int32 off, int cnt); - -#define get_chan(chsa) ((chsa>>8)&0x7f) /* get channel number from ch/sa */ diff --git a/SEL32/sel32_disk.c b/SEL32/sel32_disk.c index ca66aad9..fc46b2a6 100644 --- a/SEL32/sel32_disk.c +++ b/SEL32/sel32_disk.c @@ -1,6 +1,6 @@ /* sel32_disk.c: SEL-32 2311/2314 Disk Processor II - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -32,6 +32,8 @@ #define UNIT_DISK UNIT_ATTABLE | UNIT_IDLE | UNIT_DISABLE +extern uint32 SPAD[]; /* cpu SPAD memory */ + /* useful conversions */ /* Fill STAR value from cyl, trk, sec data */ #define CHS2STAR(c,h,s) (((c<<16) & LMASK)|((h<<8) & 0xff00)|(s & 0xff)) @@ -963,6 +965,8 @@ t_stat disk_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) DEVICE *dptr = get_dev(uptr); int32 unit = (uptr - dptr->units); CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ sim_debug(DEBUG_DETAIL, dptr, "disk_startcmd chsa %04x unit %02x cmd %02x CMD %08x\n", @@ -990,7 +994,7 @@ t_stat disk_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) case DSK_INCH: /* INCH cmd 0x0 */ sim_debug(DEBUG_CMD, dptr, "disk_startcmd starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n", - chp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); + pchp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); uptr->SNS &= ~SNS_CMDREJ; /* not rejected yet */ uptr->CMD |= DSK_INCH2; /* use 0xF0 for inch, just need int */ @@ -1105,6 +1109,8 @@ t_stat disk_srv(UNIT *uptr) uint16 chsa = GET_UADDR(uptr->CMD); DEVICE *dptr = get_dev(uptr); CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ int cmd = uptr->CMD & DSK_CMDMSK; int type = GET_TYPE(uptr->flags); uint32 tcyl=0, trk=0, cyl=0, sec=0, tempt=0; @@ -1146,7 +1152,7 @@ t_stat disk_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "disk_srv cmd CONT INCH %06x chsa %04x addr %06x count %04x completed\n", - chp->chan_inch_addr, chsa, mema, chp->ccw_count); + pchp->chan_inch_addr, chsa, mema, chp->ccw_count); /* to use this inch method, byte count must be 896 */ if (len != 896) { /* we have invalid count, error, bail out */ @@ -1172,7 +1178,7 @@ t_stat disk_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "disk_srv starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n", - chp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); + pchp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); /* mema has IOCD word 1 contents. For the disk processor it contains */ /* a pointer to the INCH buffer followed by 8 drive attribute words that */ @@ -1232,7 +1238,7 @@ t_stat disk_srv(UNIT *uptr) uptr->CMD &= LMASK; /* remove old status bits & cmd */ sim_debug(DEBUG_CMD, dptr, "disk_srv cmd INCH %06x chsa %04x addr %06x count %04x completed\n", - chp->chan_inch_addr, chsa, mema, chp->ccw_count); + pchp->chan_inch_addr, chsa, mema, chp->ccw_count); chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ break; diff --git a/SEL32/sel32_ec.c b/SEL32/sel32_ec.c index 5c49ba7d..28aa557e 100644 --- a/SEL32/sel32_ec.c +++ b/SEL32/sel32_ec.c @@ -1,6 +1,6 @@ /* sel32_ec.c: SEL-32 8516 Ethernet controller. - Copyright (c) 2020-2022, Richard Cornwell + Copyright (c) 2020-2023, Richard Cornwell Portions provided by James C. Bevier and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -770,6 +770,8 @@ t_stat ec_srv(UNIT *uptr) uint8 buf[1520]; uint8 *pck; struct ec_eth_hdr *hdr; + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ sim_debug(DEBUG_CMD, dptr, "ec_srv chp %p cmd=%02x chsa %04x count %04x SNS %08x\n", @@ -782,7 +784,7 @@ t_stat ec_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "ec_srv starting INCH %06x cmd, chsa %04x addr %06x cnt %04x\n", - chp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); + pchp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); /* now call set_inch() function to write and test inch buffer addresses */ /* Ethernet uses 1 dbl wd */ i = set_inch(uptr, mema, 1); /* new address */ diff --git a/SEL32/sel32_fltpt.c b/SEL32/sel32_fltpt.c index c9f09b9a..b08d66c5 100644 --- a/SEL32/sel32_fltpt.c +++ b/SEL32/sel32_fltpt.c @@ -1,6 +1,6 @@ /* sel32_fltpt.c: SEL 32 floating point instructions processing. - Copyright (c) 2018-2021, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a diff --git a/SEL32/sel32_hsdp.c b/SEL32/sel32_hsdp.c index be0f19c7..437c7a3c 100644 --- a/SEL32/sel32_hsdp.c +++ b/SEL32/sel32_hsdp.c @@ -1,6 +1,6 @@ /* sel32_hsdp.c: SEL-32 8064 High Speed Disk Processor - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -32,6 +32,8 @@ #define UNIT_HSDP UNIT_ATTABLE | UNIT_IDLE | UNIT_DISABLE +extern uint32 SPAD[]; /* cpu SPAD memory */ + /* useful conversions */ /* Fill STAR value from cyl, trk, sec data */ #define CHS2STAR(c,h,s) (((c<<16) & LMASK)|((h<<8) & 0xff00)|(s & 0xff)) @@ -1226,19 +1228,19 @@ t_stat hsdp_rsctl(UNIT *uptr) { int cmd = uptr->CMD & DSK_CMDMSK; CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */ - if ((uptr->CMD & DSK_CMDMSK) != 0) { /* is unit busy */ + if ((uptr->CMD & DSK_CMDMSK) != 0) { /* is unit busy */ sim_debug(DEBUG_CMD, dptr, "hsdp_rsctl RSCTL chsa %04x cmd %02x ccw_count %02x\n", chsa, cmd, chp->ccw_count); - sim_cancel(uptr); /* clear the input timer */ - chp->ccw_count = 0; /* zero the count */ - chp->chan_caw = 0; /* zero iocd address for diags */ - chp->ccw_flags &= ~(FLAG_DC|FLAG_CC);/* stop any chaining */ + sim_cancel(uptr); /* clear the input timer */ + chp->ccw_count = 0; /* zero the count */ + chp->chan_caw = 0; /* zero iocd address for diags */ + chp->ccw_flags &= ~(FLAG_DC|FLAG_CC); /* stop any chaining */ } - uptr->CMD &= LMASK; /* make non-busy */ - uptr->SNS2 |= (SNS_ONC|SNS_UNR); /* on cylinder & ready */ + uptr->CMD &= LMASK; /* make non-busy */ + uptr->SNS2 |= (SNS_ONC|SNS_UNR); /* on cylinder & ready */ sim_debug(DEBUG_CMD, dptr, "hsdp_rsctl RSCTL I/O not busy chsa %04x cmd %02x\n", chsa, cmd); - return SCPE_OK; /* not busy */ + return SCPE_OK; /* not busy */ } /* Handle processing of hsdp requests. */ @@ -1247,13 +1249,15 @@ t_stat hsdp_srv(UNIT *uptr) uint16 chsa = GET_UADDR(uptr->CMD); DEVICE *dptr = get_dev(uptr); CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ int cmd = uptr->CMD & DSK_CMDMSK; int type = GET_TYPE(uptr->flags); uint32 tcyl=0, trk=0, cyl=0, sec=0, tempt=0; int unit = (uptr - dptr->units); int len = chp->ccw_count; int i,j,k; - uint32 mema, ecc, cecc, tstar; /* memory address */ + uint32 mema, ecc, cecc, tstar; /* memory address */ uint8 ch; uint16 ssize = hsdp_type[type].ssiz * 4; /* disk sector size in bytes */ uint32 tstart; @@ -1298,7 +1302,7 @@ t_stat hsdp_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "hsdp_srv cmd CONT INC %06x chsa %04x addr %06x count %04x completed\n", - chp->chan_inch_addr, chsa, mema, chp->ccw_count); + pchp->chan_inch_addr, chsa, mema, chp->ccw_count); /* to use this inch method, byte count must be 0x20 */ if (len != 0x20) { /* we have invalid count, error, bail out */ @@ -1357,7 +1361,7 @@ t_stat hsdp_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "hsdp_srv starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n", - chp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); + pchp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); /* mema has IOCD word 1 contents. For the disk processor it contains */ /* a pointer to the INCH buffer followed by 8 drive attribute words that */ @@ -1434,7 +1438,7 @@ t_stat hsdp_srv(UNIT *uptr) uptr->CMD &= LMASK; /* remove old cmd */ sim_debug(DEBUG_CMD, dptr, "hsdp_srv cmd INCH %06x chsa %04x addr %06x count %04x mode %08x completed\n", - chp->chan_inch_addr, chsa, mema, chp->ccw_count, tcyl); + pchp->chan_inch_addr, chsa, mema, chp->ccw_count, tcyl); chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ break; diff --git a/SEL32/sel32_iop.c b/SEL32/sel32_iop.c index 707de588..0cd3463e 100644 --- a/SEL32/sel32_iop.c +++ b/SEL32/sel32_iop.c @@ -198,7 +198,9 @@ t_stat iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) iop_chp[0].chan_inch_addr = iop_chp[0].ccw_addr; /* set inch buffer addr */ iop_chp[0].base_inch_addr = iop_chp[0].ccw_addr; /* set inch buffer addr */ - iop_chp[0].max_inch_addr = iop_chp[0].ccw_addr + (128 * 8); /* set last inch buffer addr */ +//??? iop_chp[0].max_inch_addr = iop_chp[0].ccw_addr + (127 * 8); /* set last inch buffer addr */ + /* IOP manual says it uses 128 dbl wds (256 wds) but diag aborts if gtr than 1 dbl wd */ + iop_chp[0].max_inch_addr = iop_chp[0].ccw_addr; /* set last inch buffer addr */ uptr->u3 |= IOP_INCH2; /* save INCH command as 0xf0 */ sim_activate(uptr, 40); /* go on */ @@ -262,7 +264,8 @@ t_stat iop_srv(UNIT *uptr) /* now call set_inch() function to write and test inch buffer addresses */ /* the chp->ccw_addr location contains the inch address */ /* 1-256 wd buffer is provided for 128 status dbl words */ - tstart = set_inch(uptr, mema, 128); /* new address of 128 entries */ +//?? tstart = set_inch(uptr, mema, 128); /* new address of 128 entries */ + tstart = set_inch(uptr, mema, 1); /* new address of 128 entries */ if ((tstart == SCPE_MEM) || (tstart == SCPE_ARG)) { /* any error */ /* we have error, bail out */ uptr->u5 |= SNS_CMDREJ; diff --git a/SEL32/sel32_ipu.c b/SEL32/sel32_ipu.c new file mode 100644 index 00000000..ba548035 --- /dev/null +++ b/SEL32/sel32_ipu.c @@ -0,0 +1,7214 @@ +/* sel32_ipu.c: Sel 32 IPU simulator + + Copyright (c) 2018-2023, James C. Bevier + Portions provided by Geert Rolf + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#define USE_IPU_CODE + +#include "sel32_defs.h" + +#ifdef USE_IPU_THREAD + +extern uint32 sim_idle_ms_sleep(unsigned int); /* wait 1 ms */ +extern UNIT cpu_unit; /* The CPU */ + +/* running IPU thread on CPU, n/u in IPU fork */ +/* this is different than CPU defines */ +static uint8 wait4sipu = 0; /* waiting for sipu in IPU if set */ +static int MyIndex; +static int PeerIndex; +extern uint32 M[]; /* Memory */ +//extern uint32 *M; /* Memory when we have IPU using threads */ +extern struct ipcom *IPC; /* TRAPS & flags */ +extern pthread_t ipuThread; +extern DEVICE cpu_dev; /* cpu device structure */ +extern uint32 cpustop; /* cpu is stopping */ + +LOCAL DEVICE* my_dev = &ipu_dev; /* current DEV pointer CPU or IPU */ +LOCAL uint32 OIR=0; /* Original Instruction register */ +LOCAL uint32 OPSD1=0; /* Original PSD1 */ +LOCAL uint32 OPSD2=0; /* Original PSD2 */ + +/* IPU registers, map cache, spad, and other variables */ +LOCAL uint32 PSD[2]; /* the PC for the instruction */ +#define PSD1 PSD[0] /* word 1 of PSD */ +#define PSD2 PSD[1] /* word 2 of PSD */ +LOCAL uint32 GPR[8]; /* General Purpose Registers */ +LOCAL uint32 BR[8]; /* Base registers */ +LOCAL uint32 BOOTR[8] = {0}; /* Boot registers settings */ +LOCAL uint32 SPAD[256]; /* Scratch pad memory */ +/* IPU mapping cache entries */ +/* 32/55 has none */ +/* 32/7x has 32 8KW maps per task */ +/* Concept 32/27 has 256 2KW maps per task */ +/* Concept 32/X7 has 2048 2KW maps per task */ +LOCAL uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */ +LOCAL uint32 TLB[2048]; /* Translated addresses for each map entry */ +LOCAL uint32 PC; /* Program counter */ +LOCAL uint32 IR; /* Last Instruction */ +LOCAL uint32 HIWM=0; /* max maps loaded so far */ +LOCAL uint32 BPIX=0; /* # pages loaded for O/S */ +LOCAL uint32 CPIXPL=0; /* highest page loaded for User */ +LOCAL uint32 CPIX=0; /* CPIX user MPL offset */ +LOCAL uint32 IPUSTATUS; /* ipu status word */ +LOCAL uint32 TRAPSTATUS; /* trap status word */ +LOCAL uint32 CC; /* Condition codes, bits 1-4 of PSD1 */ +LOCAL uint32 MODES=0; /* Operating modes, bits 0, 5, 6, 7 of PSD1 */ +LOCAL uint16 OPR; /* Top half of Instruction register */ +LOCAL uint16 OP; /* Six bit instruction opcode */ +LOCAL uint32 INTS[128]; /* Interrupt status flags */ +LOCAL uint32 CMCR; /* Cache Memory Control Register */ +LOCAL uint32 SMCR; /* Shared Memory Control Register */ +LOCAL uint32 CMSMC; /* V9 Cache/Shadow Memory Configuration */ +LOCAL uint32 CSMCW; /* CPU Shadow Memory Configuration Word */ +LOCAL uint32 ISMCW; /* IPU Shadow Memory Configuration Word */ +LOCAL uint32 CCW = 0; /* Computer Configuration Word */ +LOCAL uint32 CSW = 0; /* Console switches going to 0x780 */ +/* end of IPU simh registers */ + +LOCAL uint32 pfault; /* page # of fault from read/write */ + +/* bits 0-4 are bits 0-4 from map entry */ +/* bit 0 valid */ +/* bit 1 p1 write access if set */ +/* bit 2 p2 write access if set */ +/* bit 3 p3 write access if set MM - memory modify */ +/* bit 4 p4 write access if set MA - memory accessed */ +/* bit 5 hit bit means entry is setup, even if not valid map */ +/* if hit bit is set and entry not valid, we will do a page fault */ +/* bit 6 dirty bit, set when written to, page update required */ +/* bits 8-18 has map reg contents for this page (Map << 13) */ +/* bit 19-31 is zero for page offset of zero */ + +LOCAL uint8 wait4int = 0; /* waiting for interrupt if set */ + +/* define traps */ +LOCAL uint32 TRAPME = 0; /* trap to be executed */ + +/* forward definitions */ +t_stat ipu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw); +t_stat ipu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw); +t_stat ipu_reset(DEVICE * dptr); +t_stat ipu_set_ipu(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat ipu_clr_ipu(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat ipu_show_ipu(FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat ipu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc); +t_stat ipu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +uint32 ipu_cmd(UNIT * uptr, uint16 cmd, uint16 dev); +t_stat ipu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *ipu_description (DEVICE *dptr); +LOCAL t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access); +LOCAL t_stat load_maps(uint32 thepsd[2], uint32 lmap); +LOCAL t_stat read_instruction(uint32 thepsd[2], uint32 *instr); +LOCAL t_stat Mem_read(uint32 addr, uint32 *data); +LOCAL t_stat Mem_write(uint32 addr, uint32 *data); + +/* external definitions */ +extern t_stat checkxio(uint16 addr, uint32 *status); /* XIO check in chan.c */ +extern t_stat startxio(uint16 addr, uint32 *status); /* XIO start in chan.c */ +extern t_stat testxio(uint16 addr, uint32 *status); /* XIO test in chan.c */ +extern t_stat stopxio(uint16 addr, uint32 *status); /* XIO stop in chan.c */ +extern t_stat rschnlxio(uint16 addr, uint32 *status); /* reset channel XIO */ +extern t_stat haltxio(uint16 addr, uint32 *status); /* halt XIO */ +extern t_stat grabxio(uint16 addr, uint32 *status); /* grab XIO n/u */ +extern t_stat rsctlxio(uint16 addr, uint32 *status); /* reset controller XIO */ +extern t_stat chan_set_devs(); /* set up the defined devices on the simulator */ +extern uint32 scan_chan(uint32 *ilev); /* go scan for I/O int pending */ +extern uint32 cont_chan(uint16 chsa); /* continue channel program */ +extern uint16 loading; /* set when doing IPL */ +extern int fprint_inst(FILE *of, uint32 val, int32 sw); /* instruction print function */ +extern void rtc_setup(uint32 ss, uint32 level); /* tell rtc to start/stop */ +extern void itm_setup(uint32 ss, uint32 level); /* tell itm to start/stop */ +extern int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level); /* read/write the interval timer */ +extern int16 post_csw(CHANP *chp, uint32 rstat); +extern DIB *dib_chan[MAX_CHAN]; + +/* floating point subroutines definitions */ +extern uint32 s_fixw(uint32 val, uint32 *cc); +extern uint32 s_fltw(uint32 val, uint32 *cc); +extern t_uint64 s_fixd(t_uint64 val, uint32 *cc); +extern t_uint64 s_fltd(t_uint64 val, uint32 *cc); +extern uint32 s_nor(uint32 reg, uint32 *exp); +extern t_uint64 s_nord(t_uint64 reg, uint32 *exp); +extern uint32 s_adfw(uint32 reg, uint32 mem, uint32 *cc); +extern uint32 s_sufw(uint32 reg, uint32 mem, uint32 *cc); +extern t_uint64 s_adfd(t_uint64 reg, t_uint64 mem, uint32 *cc); +extern t_uint64 s_sufd(t_uint64 reg, t_uint64 mem, uint32 *cc); +extern uint32 s_mpfw(uint32 reg, uint32 mem, uint32 *cc); +extern uint32 s_dvfw(uint32 reg, uint32 mem, uint32 *cc); +extern t_uint64 s_mpfd(t_uint64 reg, t_uint64 mem, uint32 *cc); +extern t_uint64 s_dvfd(t_uint64 reg, t_uint64 mem, uint32 *cc); +extern uint32 s_normfw(uint32 mem, uint32 *cc); +extern t_uint64 s_normfd(t_uint64 mem, uint32 *cc); + +/* History information */ +LOCAL int32 hst_p = 0; /* History pointer */ +LOCAL int32 hst_lnt = 0; /* History length */ +LOCAL struct InstHistory *hst = NULL; /* History stack */ + +/* IPU data structures + + ipu_dev IPU device descriptor + ipu_unit IPU unit descriptor + ipu_reg IPU register list + ipu_mod IPU modifiers list +*/ + +UNIT ipu_unit = + /* Unit data layout for IPU */ +/* { UDATA(rtc_srv, UNIT_BINK | MODEL(MODEL_27) | MEMAMOUNT(0), + * MAXMEMSIZE ), 120 }; */ + { + NULL, /* UNIT *next */ /* next active */ + NULL, /* t_stat (*action) */ /* action routine */ + NULL, /* char *filename */ /* open file name */ + NULL, /* FILE *fileref */ /* file reference */ + NULL, /* void *filebuf */ /* memory buffer */ + 0, /* uint32 hwmark */ /* high water mark */ + 0, /* int32 time */ /* time out */ + UNIT_IDLE|UNIT_FIX|UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(4), /* flags */ + 0, /* uint32 dynflags */ /* dynamic flags */ + 0x800000, /* t_addr capac */ /* capacity */ + 0, /* t_addr pos */ /* file position */ + 0, /* void (*io_flush) */ /* io flush routine */ + 0, /* uint32 iostarttime */ /* I/O start time */ + 0, /* int32 buf */ /* buffer */ + 80, /* int32 wait */ /* wait */ +}; + +REG ipu_reg[] = { + {BRDATAD(PSD, PSD, 16, 32, 2, "Program Status Doubleword"), REG_FIT}, + {BRDATAD(GPR, GPR, 16, 32, 8, "Index registers"), REG_FIT}, + {BRDATAD(BR, BR, 16, 32, 8, "Base registers"), REG_FIT}, + {BRDATAD(BOOTR, BOOTR, 16, 32, 8, "Boot registers"), REG_FIT}, + {BRDATAD(SPAD, SPAD, 16, 32, 256, "IPU Scratchpad memory"), REG_FIT}, + {BRDATAD(MAPC, MAPC, 16, 32, 1024, "IPU map cache"), REG_FIT}, + {BRDATAD(TLB, TLB, 16, 32, 2048, "IPU Translation Lookaside Buffer"), REG_FIT}, + {HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT}, + {HRDATAD(IR, IR, 32, "Last Instruction Loaded"), REG_FIT}, + {HRDATAD(HIWM, HIWM, 32, "Max Maps Loaded"), REG_FIT}, + {HRDATAD(BPIX, BPIX, 32, "# Maps Loaded for O/S"), REG_FIT}, + {HRDATAD(CPIXPL, CPIXPL, 32, "Maximum Map # Loaded for User"), REG_FIT}, + {HRDATAD(CPIX, CPIX, 32, "Current CPIX user MPL offset"), REG_FIT}, + {HRDATAD(IPUSTATUS, IPUSTATUS, 32, "IPU Status Word"), REG_FIT}, + {HRDATAD(TRAPSTATUS, TRAPSTATUS, 32, "TRAP Status Word"), REG_FIT}, + {HRDATAD(CC, CC, 32, "Condition Codes"), REG_FIT}, + {HRDATAD(MODES, MODES, 32, "Mode bits"), REG_FIT}, + {HRDATAD(OPR, OPR, 16, "Top half of Instruction Register"), REG_FIT}, + {HRDATAD(OP, OP, 16, "Six bit Instruction Opcode"), REG_FIT}, + {BRDATAD(INTS, INTS, 16, 32, 128, "Interrupt Status"), REG_FIT}, + {HRDATAD(CMCR, CMCR, 32, "Cache Memory Control Register"), REG_FIT}, + {HRDATAD(SMCR, SMCR, 32, "Shared Memory Control Register"), REG_FIT}, + {HRDATAD(CMSMC, CMSMC, 32, "V9 Cache/Shadow Memory Configuration Word"), REG_FIT}, + {HRDATAD(CSMCW, CSMCW, 32, "V9 CPU Shadow Memory Configuration Word"), REG_FIT}, + {HRDATAD(ISMCW, ISMCW, 32, "V9 IPU Shadow Memory Configuration Word"), REG_FIT}, + {HRDATAD(CCW, CCW, 32, "Computer Configuration Word"), REG_FIT}, + {HRDATAD(CSW, CSW, 32, "Console Switches"), REG_FIT}, +#ifdef NOT_USED + {BRDATAD(RDYQ, RDYQ, 16, 32, 128, "Channel Program Completon Status"), REG_FIT}, + {HRDATAD(RDYQIN, RDYQIN, 32, "RDYQ input index"), REG_FIT}, + {HRDATAD(RDYQOUT, RDYQOUT, 32, "RDYQ output index"), REG_FIT}, +#endif + {NULL} +}; + +/* Modifier table layout (MTAB) - only extended entries have disp, reg, or flags */ +MTAB ipu_mod[] = { + { + /* MTAB table layout for ipu type */ + /* {UNIT_MODEL, MODEL(MODEL_55), "32/55", "32/55", NULL, NULL, NULL, "Concept 32/55"}, */ + UNIT_MODEL, /* uint32 mask */ /* mask */ + MODEL(MODEL_55), /* uint32 match */ /* match */ + "32/55", /* cchar *pstring */ /* print string */ + "32/55", /* cchar *mstring */ /* match string */ + NULL, /* t_stat (*valid) */ /* validation routine */ + NULL, /* t_stat (*disp) */ /* display routine */ + NULL, /* void *desc */ /* value desc, REG* if MTAB_VAL, int* if not */ + "Concept 32/55", /* cchar *help */ /* help string */ + }, + {UNIT_MODEL, MODEL(MODEL_75), "32/75", "32/75", NULL, NULL, NULL, "Concept 32/75"}, + {UNIT_MODEL, MODEL(MODEL_27), "32/27", "32/27", NULL, NULL, NULL, "Concept 32/27"}, + {UNIT_MODEL, MODEL(MODEL_67), "32/67", "32/67", NULL, NULL, NULL, "Concept 32/67"}, + {UNIT_MODEL, MODEL(MODEL_87), "32/87", "32/87", NULL, NULL, NULL, "Concept 32/87"}, + {UNIT_MODEL, MODEL(MODEL_97), "32/97", "32/97", NULL, NULL, NULL, "Concept 32/97"}, + {UNIT_MODEL, MODEL(MODEL_V6), "V6", "V6", NULL, NULL, NULL, "Concept V6"}, + {UNIT_MODEL, MODEL(MODEL_V9), "V9", "V9", NULL, NULL, NULL, "Concept V9"}, + {UNIT_MODEL, MODEL(MODEL_6780), "32/6780", "32/6780", NULL, NULL, NULL, "Concept 32/6780"}, + {UNIT_MODEL, MODEL(MODEL_7780), "32/7780", "32/7780", NULL, NULL, NULL, "Concept 32/7780"}, + {UNIT_MODEL, MODEL(MODEL_8780), "32/8780", "32/8780", NULL, NULL, NULL, "Concept 32/8780"}, + {UNIT_MODEL, MODEL(MODEL_9780), "32/9780", "32/9780", NULL, NULL, NULL, "Concept 32/9780"}, + {UNIT_MODEL, MODEL(MODEL_V6IPU), "V6/IPU", "V6/IPU", NULL, NULL, NULL, "Concept V6 w/IPU"}, + {UNIT_MODEL, MODEL(MODEL_V9IPU), "V9/IPU", "V9/IPU", NULL, NULL, NULL, "Concept V9 w/IPU"}, + { + /* MTAB table layout for ipu memory size */ + /* {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &ipu_set_size}, */ + UNIT_MSIZE, /* uint32 mask */ /* mask */ + MEMAMOUNT(0), /* uint32 match */ /* match */ + NULL, /* cchar *pstring */ /* print string */ + "128K", /* cchar *mstring */ /* match string */ +/// &ipu_set_size, /* t_stat (*valid) */ /* validation routine */ + NULL, /* t_stat (*valid) */ /* validation routine */ + NULL, /* t_stat (*disp) */ /* display routine */ + NULL, /* void *desc */ /* value desc, REG* if MTAB_VAL, int* if not */ + NULL, /* cchar *help */ /* help string */ + }, + {UNIT_MSIZE, MEMAMOUNT(1), NULL, "256K", NULL}, + {UNIT_MSIZE, MEMAMOUNT(2), NULL, "512K", NULL}, + {UNIT_MSIZE, MEMAMOUNT(3), NULL, "1M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(4), NULL, "2M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(5), NULL, "3M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(6), NULL, "4M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(7), NULL, "6M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(8), NULL, "8M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(9), NULL, "12M", NULL}, + {UNIT_MSIZE, MEMAMOUNT(10), NULL, "16M", NULL}, + {MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle}, + {MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL}, + {MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY", + &ipu_set_hist, &ipu_show_hist}, + {MTAB_XTD|MTAB_VDV, 0, "IPU", "USEIPU", &ipu_set_ipu, &ipu_show_ipu}, + {MTAB_XTD|MTAB_VDV, 0, "NULL", "NOIPU", &ipu_clr_ipu, NULL}, + {0} +}; + +/* IPU device descriptor */ +DEVICE ipu_dev = { + /* "IPU", &ipu_unit, ipu_reg, ipu_mod, + 1, 8, 24, 1, 8, 32, + &ipu_ex, &ipu_dep, &ipu_reset, NULL, NULL, NULL, + NULL, DEV_DEBUG, 0, dev_debug, + NULL, NULL, &ipu_help, NULL, NULL, &ipu_description */ + "IPU", /* cchar *name */ /* device name */ + &ipu_unit, /* UNIT *units */ /* unit array */ + ipu_reg, /* REG *registers */ /* register array */ + ipu_mod, /* MTAB *modifiers */ /* modifier array */ + 1, /* uint32 numunits */ /* number of units */ + 16, /* uint32 aradix */ /* address radix */ + 32, /* uint32 awidth */ /* address width */ + 1, /* uint32 aincr */ /* address increment */ + 16, /* uint32 dradix */ /* data radix */ + 8, /* uint32 dwidth */ /* data width */ + &ipu_ex, /* t_stat (*examine) */ /* examine routine */ + &ipu_dep, /* t_stat (*deposit) */ /* deposit routine */ + &ipu_reset, /* t_stat (*reset) */ /* reset routine */ + NULL, /* t_stat (*boot) */ /* boot routine */ + NULL, /* t_stat (*attach) */ /* attach routine */ + NULL, /* t_stat (*detach) */ /* detach routine */ + NULL, /* void *ctxt */ /* (context) device information block pointer */ + DEV_DEBUG, /* uint32 flags */ /* device flags */ + 0, /* uint32 dctrl */ /* debug control flags */ + dev_debug, /* DEBTAB *debflags */ /* debug flag name array */ + NULL, /* t_stat (*msize) */ /* memory size change routine */ + NULL, /* char *lname */ /* logical device name */ + &ipu_help, /* t_stat (*help) */ /* help function */ + NULL, /* t_stat (*attach_help) *//* attach help function */ + NULL, /* void *help_ctx */ /* Context available to help routines */ + &ipu_description, /* cchar *(*description) *//* Device description */ + NULL, /* BRKTYPTB *brk_types */ /* Breakpoint types */ +}; + +/* IPU Instruction decode flags */ +#define INV 0x0000 /* Instruction is invalid */ +#define HLF 0x0001 /* Half word instruction */ +#define ADR 0x0002 /* Normal addressing mode */ +#define IMM 0x0004 /* Immediate mode */ +#define WRD 0x0008 /* Word addressing, no index */ +#define SCC 0x0010 /* Sets CC */ +#define RR 0x0020 /* Read source register */ +#define R1 0x0040 /* Read destination register */ +#define RB 0x0080 /* Read base register into dest */ +#define SD 0x0100 /* Stores into destination register */ +#define RNX 0x0200 /* Reads memory without sign extend */ +#define RM 0x0400 /* Reads memory */ +#define SM 0x0800 /* Stores memory */ +#define DBL 0x1000 /* Double word operation */ +#define SB 0x2000 /* Store Base register */ +#define BT 0x4000 /* Branch taken, no PC incr */ +#define SF 0x8000 /* Special flag */ + +LOCAL int nobase_mode[] = { + /* 00 04 08 0C */ + /* 00 ANR, ORR, EOR */ + HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, + + /* 10 14 18 1C */ + /* CAR, CMR, SBR ZBR */ + HLF, HLF, HLF, HLF, + + /* 20 24 28 2C */ + /* ABR TBR REG TRR */ + HLF, HLF, HLF, HLF, + + /* 30 34 38 3C */ + /* CALM LA ADR SUR */ + HLF, SD|ADR, HLF, HLF, + + /* 40 44 48 4C */ + /* MPR DVR */ + SCC|SD|HLF, HLF, HLF|INV, HLF|INV, + + /* 50 54 58 5C */ + /* */ + HLF|INV, HLF|INV, HLF|INV, HLF|INV, + + /* 60 64 68 6C */ + /* NOR NORD SCZ SRA */ + HLF, HLF, HLF, HLF, + + /* 70 74 78 7C */ + /* SRL SRC SRAD SRLD */ + HLF, HLF, HLF, HLF, + + /* 80 84 88 8C */ + /* LEAR ANM ORM EOM */ + SD|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR, + + /* 90 94 98 9C */ + /* CAM CMM SBM ZBM */ + SCC|RR|RM|ADR, RR|RM|ADR, ADR, ADR, + + /* A0 A4 A8 AC */ + /* ABM TBM EXM L */ + ADR, ADR, ADR, SCC|SD|RM|ADR, + + /* B0 B4 B8 BC */ + /* LM LN ADM SUM */ + SCC|SD|RM|ADR, SCC|SD|RM|ADR, SD|RR|RM|ADR, SD|RR|RM|ADR, + + /* C0 C4 C8 CC */ + /* MPM DVM IMM LF */ + SCC|SD|RM|ADR, RM|ADR, IMM, ADR, + + /* D0 D4 D8 DC */ + /* LEA ST STM STF */ + SD|ADR, RR|SM|ADR, RR|SM|ADR, ADR, + + /* E0 E4 E8 EC */ + /* ADF MPF ARM BCT */ + ADR, ADR, SM|RR|RNX|ADR, ADR, + + /* F0 F4 F8 FC */ + /* BCF BI MISC IO */ + ADR, RR|SD|WRD, ADR, IMM, +}; + +LOCAL int base_mode[] = { + /* 00 04 08 0C */ + /* 00 AND, OR, EOR */ + HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, + + /* 10 14 18 1C */ + /* SACZ CMR xBR SRx */ + HLF, HLF, HLF, HLF, + + /* 20 24 28 2C */ + /* SRxD SRC REG TRR */ + HLF, HLF, HLF, HLF, + + /* 30 34 38 3C */ + /* LA FLRop SUR */ + INV, INV, HLF, HLF, + + /* 40 44 48 4C */ + /* */ + INV, INV, INV, INV, + + /* 50 54 58 5C */ + /* LA BASE BASE CALLM */ + SD|ADR, SM|ADR, SB|ADR, RM|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|RR|RNX|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR, + + /* CAM CMM SBM ZBM */ + /* 90 94 98 9C */ + SCC|RR|RM|ADR, RR|RM|ADR, ADR, ADR, + + /* A0 A4 A8 AC */ + /* ABM TBM EXM L */ + ADR, ADR, ADR, SCC|SD|RM|ADR, + + /* B0 B4 B8 BC */ + /* LM LN ADM SUM */ + SCC|SD|RM|ADR, SCC|SD|RM|ADR, SD|RR|RM|ADR, SD|RR|RM|ADR, + + /* C0 C4 C8 CC */ + /* MPM DVM IMM LF */ + SCC|SD|RM|ADR, RM|ADR, IMM, ADR, + + /* D0 D4 D8 DC */ + /* LEA ST STM STFBR */ + INV, RR|SM|ADR, RR|SM|ADR, ADR, + + /* E0 E4 E8 EC */ + /* ADF MPF ARM BCT */ + ADR, ADR, SM|RR|RNX|ADR, ADR, + + /* F0 F4 F8 FC */ + /* BCF BI MISC IO */ + ADR, RR|SD|WRD, ADR, IMM, +}; + +#define MAX32 32 /* 32/77 map limit */ +#define MAX256 256 /* 32/27 and 32/87 map limit */ +#define MAX2048 2048 /* 32/67, V6, and V9 map limit */ + +#if !defined(_WIN32) +#include +/* + * sleep for n msec. + */ +void millinap(int msec) +{ + struct timespec starttimer, remaining; + int secs; + int msecs; + + secs = msec / 1000; + msecs = msec % 1000; + + starttimer.tv_sec = secs; +// starttimer.tv_nsec = msecs * 2000000; /* 2M nanosecs = 2ms */ + starttimer.tv_nsec = msecs * 1000000; /* 1M nanosecs = 1ms */ +// starttimer.tv_nsec = msecs * 100000; /* 100K nanosecs = 100us */ +// starttimer.tv_nsec = msecs * 10000; /* 10K nanosecs = 10us */ + + nanosleep(&starttimer, & remaining); +} +#else +/* + * sleep for n msec. + */ +void millinap(int msec) +{ + Sleep(msec); +} +#endif + +#ifdef DEBUG4IPU +/* Dump instruction history */ +static void DumpHist() +{ + /* dump instruction history */ +// ipu_show_hist(stdout, (UNIT *)0, (int32)0, (void *)0); +// fflush(stdout); + ipu_show_hist(sim_deb, (UNIT *)0, (int32)0, (void *)0); + fflush(sim_deb); +} +#endif + +#ifdef USE_POSIX_SEM +LOCAL void set_simsem() +{ + if (IPC != 0) { + if (sem_trywait((sem_t *)&(IPC->simsem)) == 0) { + IPC->pass[MyIndex]++; + } else { + IPC->wait[MyIndex]++; + sem_wait((sem_t *)&(IPC->simsem)); + IPC->pass[MyIndex]++; + } + } +} + +LOCAL void clr_simsem() +{ + // in case simsem > 0 the peer process has broken the semaphore + if (IPC) { + sem_post((sem_t *)&(IPC->simsem)); + } +} +#else +/* use pthread mutexs */ +LOCAL void lock_mutex() +{ + if (IPC != 0) { + if (pthread_mutex_trylock((pthread_mutex_t *)&(IPC->mutex)) == 0) { + IPC->pass[MyIndex]++; + } else { + IPC->wait[MyIndex]++; + pthread_mutex_lock((pthread_mutex_t *)&(IPC->mutex)); + IPC->pass[MyIndex]++; + } + } +} + +LOCAL void unlock_mutex() +{ + if (IPC) { + pthread_mutex_unlock((pthread_mutex_t *)&(IPC->mutex)); + } +} +#endif + +#ifdef NOT_USED +/* this function is used to extract mode bits from PSD 1 & 2 */ +LOCAL uint32 set_modes(uint32 psd[2]) +{ + uint32 modes = 0; + modes = psd[0] & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + + if (psd[1] & MAPBIT) /* is bit 0 of PSD2 set, we are mapped */ + modes |= MAPMODE; /* set mapped mode */ + + if ((psd[1] & RETBBIT) == 0) { /* is it retain blocking state, bit 48(15) set */ + /* retain blocking state is off, use bit 49(16) to set new blocking state */ + if (psd[1] & SETBBIT) { /* no, is it set blocking state bit 49(16) set*/ + /* new blocking state is blocked when bits 48=0 & bit 49=1 */ + modes |= BLKMODE; /* set blocked mode */ + } + } else { + /* set retained blocking state in PSD2 */ + if (SPAD[0xf9] & BIT24) { /* see if old mode is blocked in IPUSTATUS */ + modes |= BLKMODE; /* set blocked mode */ + } + } + return modes; +} +#endif + +/* set up the map registers for the current task in the ipu */ +/* the PSD bpix and cpix are used to setup the maps */ +/* return non-zero if mapping error */ +/* if lmap set, always load maps on 67, 97, V6, and V7 */ +/* The RMW and WMW macros are used to read/write memory words */ +/* RMW(addr) or WMW(addr, data) where addr is a byte alligned word address */ +/* The RMR and WMR macros are used to read/write the MAPC cache registers */ +/* RMR(addr) or WMR(addr, data) where addr is a half word alligned address */ +/* We will only get here if the retain maps bit is not set in PSD word 2 */ +LOCAL t_stat load_maps(uint32 thepsd[2], uint32 lmap) +{ + uint32 num, sdc, spc, onlyos=0; + uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl; + uint32 cpix, bpix, i, j, map, osmsdl, osmidl; + uint32 MAXMAP = MAX2048; /* default to 2048 maps */ + + sim_debug(DEBUG_CMD, my_dev, + "Load Maps Entry PSD %08x %08x STATUS %08x lmap %1x IPU Mode %2x\n", + thepsd[0], thepsd[1], IPUSTATUS, lmap, CPU_MODEL); + + /* process 32/7X computers */ + if (CPU_MODEL < MODEL_27) { + MAXMAP = MAX32; /* 32 maps for 32/77 */ + /* 32/7x machine, 8KW maps 32 maps total */ + MODES &= ~BASEBIT; /* no basemode on 7x */ + if ((thepsd[1] & 0xc0000000) == 0) /* mapped mode? */ + return ALLOK; /* no, all OK, no mapping required */ + + /* we are mapped, so load the maps for this task into the ipu map cache */ + cpix = (thepsd[1]) & 0x3ff8; /* get cpix 12 bit offset from psd wd 2 */ + bpix = (thepsd[1] >> 16) & 0x3ff8; /* get bpix 12 bit offset from psd wd 2 */ + num = 0; /* working map number */ + + /* master process list is in 0x83 of spad for 7x */ + mpl = SPAD[0x83]; /* get mpl from spad address */ + + /* diags want the mpl entries checked to make sure valid dbl wowrd address */ + if (mpl & 0x7) { /* test for double word address */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MPL not on double word boundry %06x\n", mpl); + TRAPSTATUS |= BIT20; /* set bit 20 of trap status */ + return MAPFLT; /* not dbl bound, map fault error */ + } + + /* check if valid real address */ + if ((mpl == 0) || !MEM_ADDR_OK(mpl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE7 %06x mpl %06x invalid\n", + MEMSIZE, mpl); + TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ + return MAPFLT; /* no, map fault error */ + } + + /* mpl is ok, get the msdl for given cpix */ + cpixmsdl = RMW(mpl+cpix); /* get msdl from mpl for given cpix */ + + /* if bit zero of mpl entry is set, use bpix first to load maps */ + if (cpixmsdl & BIT0) { + + /* load bpix maps first */ + bpixmsdl = RMW(mpl+bpix); /* get bpix msdl word address */ + + /* check for valid bpix msdl addr */ + if (!MEM_ADDR_OK(bpixmsdl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE8 %06x bpix msdl %08x invalid\n", + MEMSIZE, bpixmsdl); + return NPMEM; /* no, none present memory error */ + } + + sdc = (bpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */ + msdl = bpixmsdl & MASK24; /* get 24 bit real address of msdl */ + /* check for valid msdl addr */ + if (!MEM_ADDR_OK(msdl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE9 %06x msdl %08x invalid\n", MEMSIZE, msdl); + return NPMEM; /* no, none present memory error */ + } + + /* process all of the msdl's */ + for (i = 0; i < sdc; i++) { /* loop through the msd's */ + spc = (RMW(msdl+i) >> 24) & 0xff; /* get segment page count from msdl */ + midl = RMW(msdl+i) & MASK24; /* get 24 bit real word address of midl */ + + /* check for valid midl addr */ + if (!MEM_ADDR_OK(midl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZEa %06x midl %08x invalid\n", MEMSIZE, midl); + return NPMEM; /* no, none present memory error */ + } + + for (j = 0; j < spc; j++, num++) { /* loop throught the midl's */ + uint32 pad = RMW(midl+(j<<1)); /* get page descriptor address */ + if (num >= MAXMAP) { + TRAPSTATUS |= BIT5; /* set bit 5 of trap status */ + return MAPFLT; /* map loading overflow, map fault error */ + } + /* load 16 bit map descriptors */ + map = RMH(pad); /* get 16 bit map entries */ + WMR((num<<1), map); /* store the map reg contents into cache */ + } + } + } + + /* now load cpix maps */ + /* check for valid cpix msdl addr */ + if (MEM_ADDR_OK(cpixmsdl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZEb %06x cpix msdl %08x invalid\n", MEMSIZE, cpixmsdl); + return NPMEM; /* no, none present memory error */ + } + + sdc = (cpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */ + msdl = cpixmsdl & 0xffffff; /* get 24 bit real address of msdl */ + /* check for valid msdl addr */ + if (!MEM_ADDR_OK(msdl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZEc %06x msdl %08x invalid\n", MEMSIZE, msdl); + return NPMEM; /* no, none present memory error */ + } + + /* process all of the msdl's */ + for (i = 0; i < sdc; i++) { + spc = (RMW(msdl+i) >> 24) & 0xff; /* get segment page count from msdl */ + midl = RMW(msdl+i) & MASK24; /* get 24 bit real word address of midl */ + + /* check for valid midl addr */ + if (!MEM_ADDR_OK(midl & MASK24)) { /* see if in memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZEd %06x midl %08x invalid\n", MEMSIZE, midl); + return NPMEM; /* no, none present memory error */ + } + + for (j = 0; j < spc; j++, num++) { /* loop through the midl's */ + uint32 pad = RMW(midl+(j<<1)); /* get page descriptor address */ + if (num >= MAXMAP) { + TRAPSTATUS |= (BIT16|BIT9); /* set bit 5 of trap status */ + return MAPFLT; /* map loading overflow, map fault error */ + } + /* load 16 bit map descriptors */ + map = RMH(pad); /* get 16 bit map entries */ + WMR((num<<1), map); /* store the map reg unmodified into cache */ + } + } + /* if none loaded, map fault */ + if (num == 0) { + TRAPSTATUS |= (BIT16|BIT9); /* set bit 5 of trap status */ + return MAPFLT; /* attempt to load 0 maps, map fault error */ + } + /* clear the rest of the previously used maps */ + for (i = num; i < HIWM; i++) /* zero any remaining entries */ + WMR((i<<1), 0); /* clear the map entry to make not valid */ + HIWM = num; /* set new high water mark */ + return ALLOK; /* all cache is loaded, return OK */ + } + /****************** END-OF-32/7X-MAPPING ********************/ + + /* process a 32/27, 32/67, 32/87, 32/97, V6, or V9 here with 2KW (8kb) maps */ + /* 32/27 & 32/87 have 256 maps. Others have 2048 maps */ + /* 32/27 & 32/87 must have all maps preallocated and loaded */ + /* 32/67 & 32/97 must load O/S maps and have user preallocated maps loaded on access */ + /* V6 and V9 must load O/S maps and have user maps allocated and loaded on access */ + + /* See if any mapping to take place */ + if ((MODES & MAPMODE) == 0) /* mapped mode? */ + return ALLOK; /* no, all OK, no mapping required */ + + /* set maximum maps for 32/27 and 32/87 processors */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) + MAXMAP = MAX256; /* only 256 2KW (8kb) maps */ + + /* we are mapped, so load the map definitions */ + cpix = thepsd[1] & 0x3ff8; /* get cpix 11 bit offset from psd wd 2 */ + num = 0; /* no maps loaded yet */ + + /* master process list is in 0xf3 of spad for concept machines */ + mpl = SPAD[0xf3]; /* get mpl from spad address */ + + /* diags want the mpl entries checked to make sure valid dbl word address */ + if (mpl & 0x7) { /* test for double word address */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MPL not on double word boundry %06x\n", mpl); + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT6; /* set bit 6 of trap status */ + else + TRAPSTATUS |= BIT20; /* set bit 20 of trap status */ + return MAPFLT; /* no, map fault error */ + } + + /* check if valid real address */ + mpl &= MASK24; /* clean mpl address */ + if (!MEM_ADDR_OK(mpl)) { /* see if in our real memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE1 %06x mpl %06x invalid\n", MEMSIZE, mpl); +npmem: + BPIX = 0; /* no os maps loaded */ + CPIXPL = 0; /* no user pages */ + CPIX = cpix; /* save user CPIX */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + } else + TRAPSTATUS |= BIT10; /* set bit 8 of trap status */ + return NPMEM; /* non present memory error */ + } + + /* output O/S and User MPL entries */ +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_CMD, my_dev, + "#MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", + MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix, + RMW(cpix+mpl), RMW(cpix+mpl+4)); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_CMD, my_dev, + "MEMORY2 %06x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n", + MEMSIZE, BPIX, cpix, CPIX, CPIXPL, HIWM); + + /* load the users regs first or the O/S. Verify the User MPL entry too. */ + /* If bit zero of cpix mpl entry is set, use msd entry 0 first to load maps */ + /* Then load the user maps after the O/S */ + /* If the cpix is zero, then only load the O/S. */ + /* This test must be made to allow sysgen to run with a zero cpix */ + /* If bit 0 of MPL[0] is 0, load the O/S maps. */ + /* Do not load O/S if bit 0 of O/S MPL[0] is set. It is set by the */ + /* swapper on MPX startup */ + + /* mpl is valid, get msdls for O/S and User */ + osmidl = RMW(mpl); /* get O/S map count & retain flag from MPL[0] */ + osmsdl = RMW(mpl+4); /* get msdl pointer for OS from MPL[1] */ + midl = RMW(mpl+cpix); /* get midl entry for given user cpix */ + msdl = RMW(mpl+cpix+4); /* get mpl entry wd 1 for given cpix */ + spc = osmidl & MASK16; /* get 16 bit O/S segment description count */ + + /* see if we are to only load the O/S */ + if (cpix == 0) { + CPIX = cpix; /* save CPIX */ + onlyos = 1; /* flag to only load O/S, nothing else */ + if (osmidl & BIT0) { /* see if the O/S retain bit 0 is on */ + return ALLOK; /* O/S retain bit is set, no mapping required */ + } + +loados: /* merge point for loading O/S first */ + /* to be followed by user maps */ + /* the retain bit is not set so load the O/S */ + if ((osmidl == 0) || (spc > MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps bad O/S map count %04x, map fault\n", spc); +nomaps: + /* Bad map load count specified. */ + BPIX = 0; /* no os maps loaded */ + CPIXPL = 0; /* no user pages */ + CPIX = cpix; /* save CPIX */ + HIWM = 0; /* reset high water mark */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= (BIT5|BIT9); /* set bit 5/9 of trap status */ + else + TRAPSTATUS |= BIT16; /* set bit 16 of trap status */ + return MAPFLT; /* map loading overflow, map fault error */ + } + + /* we have a valid count, load the O/S map list address */ + osmsdl &= MASK24; /* get 24 bit real address from mpl 0 wd2 */ + if (!MEM_ADDR_OK(osmsdl)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE2 %06x os page list address %06x invalid\n", + MEMSIZE, osmsdl); + goto npmem; /* non present memory trap */ + } + + /* load the O/S maps */ + for (j = 0; j < spc; j++, num++) { /* copy maps from msdl to map cache */ + uint32 pad = osmsdl+(j<<1); /* get page descriptor address */ + + /* see if map overflow */ + if (num >= MAXMAP) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps O/S page count overflow %04x, map fault\n", num); + goto nomaps; /* map overflow, map fault trap */ + } + if (!MEM_ADDR_OK(pad)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE3 %06x os page address %06x invalid\n", + MEMSIZE, pad); + goto npmem; /* non present memeory trap */ + } + /* load 16 bit map descriptors */ + map = RMH(pad); /* get page descriptor from memory */ + + /* for valid maps translate the map number to a real address */ + /* put this address in the TLB for later translation */ + /* copy the map status bits too and set hit bit in the TLB */ + if (map & 0x8000) { /* see if map is valid */ + TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000)); + TLB[num] |= 0x04000000; /* set HIT bit for non lmap */ + WMR((num<<1), map); /* store the map unmodified into cache */ + } else { + TLB[num] = 0; /* clear the TLB for non valid maps */ + } + } + BPIX = num; /* save the # maps loaded in O/S */ + CPIXPL = 0; /* no user pages */ + + if (!onlyos) /* see if only O/S to be loaded */ + goto loaduser; /* no, go load the user maps */ + + for (i = BPIX; i < MAXMAP; i++) /* zero any remaining entries */ + TLB[i] = 0; /* clear look aside buffer */ + + /* Only the O/S is to be loaded, finish up & return */ + HIWM = num; /* set new high water mark */ + return ALLOK; /* all cache is loaded, return OK */ + } + + /* The csect is not zero here, so see what we have to do */ + /* See if O/S is to be loaded first because user MPL entry has BIT 0 set */ + if (midl & BIT0) { + /* the user wants the O/S to load first, if the O/S retain bit set? */ + if (osmidl & BIT0) { /* see if the O/S retain bit 0 is on */ + num = spc; /* yes, set the number of O/S maps loaded */ + BPIX = spc; /* save the # maps in O/S */ + goto loaduser; /* load user map only or after O/S */ + } + + /* no retain bit, load user maps only, or after O/S */ + /* validate O/S map count */ + if (spc > MAXMAP) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps bad O/S page count %04x, map fault\n", spc); + goto nomaps; /* we have error, make way out */ + } + + /* see if any O/S maps to load */ + if (spc == 0) { + BPIX = 0; /* no os maps loaded */ + /* O/S page count is zero, so just load the user */ + goto loaduser; /* load user map only or after O/S */ + } + /* user wants to have O/S loaded first */ + onlyos = 0; /* return to loaduser after loading O/S */ + goto loados; /* go load the O/S */ + } + + /* the user wants to only load the user maps, no O/S maps are to be retained */ + BPIX = 0; /* clear O/S loaded page count */ + num = 0; /* nothing loaded yet */ + /****************** END-OF-O/S-MAPPING ********************/ + +loaduser: + spc = midl & MASK16; /* get 16 bit User page count */ + + /* see if O/S has already loaded the MAXMAPS */ + /* if borrow bit is on and cpix count is zero, return ok */ + /* if borrow bit is on and cpix count not zero, map overflow error */ + if (BPIX == MAXMAP) { + HIWM = num; /* set new high water mark */ + CPIXPL = 0; /* no user pages */ + if ((midl & BIT0) && (spc == 0)) { /* see if the user had borrow bit on */ + sim_debug(DEBUG_CMD, my_dev, + "load_maps @loaduser num %04x BPIX loaded %04x load done\n", num, BPIX); + return ALLOK; /* all cache is loaded, return OK */ + } + else { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps map overflow BPIX %04x count %04x, map fault\n", BPIX, spc); + goto nomaps; /* we have error, make way out */ + } + } + + /* the O/S has been loaded if requested or retained, so now load the user */ + msdl &= MASK24; /* get 24 bit real word address of msdl */ + + /* This test fails cn.mmm diag at test 46, subtest 2 with unexpected error */ + /* Do this test if we are a LMAP instruction and not a 32/27 or 32/87 */ + if (lmap && !MEM_ADDR_OK(msdl)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE4 %06x user page list address %06x invalid\n", + MEMSIZE, msdl); + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + } else + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + return NPMEM; /* non present memory error */ + } + + /* We have a valid user MPL[cpix] address, msdl */ + spc = midl & MASK16; /* get 16 bit User page count */ + + /* it is OK here to have no O/S maps loaded, num can be 0 */ + if ((spc > MAXMAP) || ((spc+BPIX) > MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps bad User page count %04x num %04x bpix %04x, map fault\n", + spc, num, BPIX); + /* Bad map load count specified. */ + BPIX = 0; /* no os maps loaded */ + CPIXPL = 0; /* no user pages */ + CPIX = cpix; /* save CPIX */ + HIWM = 0; /* reset high water mark */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= (BIT5|BIT9); /* set bit 5/9 of trap status */ + else + TRAPSTATUS |= BIT16; /* set bit 16 of trap status */ + return MAPFLT; /* map overflow fault error */ + } + CPIX = cpix; /* save user MPL offset (cpix) */ + CPIXPL = spc; /* save user map load count */ + + /* Load maps for 32/27 aand 32/87 */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) { + + sim_debug(DEBUG_CMD, my_dev, + "load_maps Processing 32/27 & 32/87 Model# %02x\n", CPU_MODEL); + + /* handle non virtual page loading or diag LMAP instruction */ + /* do 32/27 and 32/87 that force load all maps */ + /* now load user maps specified by the cpix value */ + for (j = 0; j < spc; j++, num++) { /* copy maps from midl to map cache */ + uint32 pad = msdl+(j<<1); /* get page descriptor address */ + + /* see if map overflow */ + if (num >= MAXMAP) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps User page count overflow %04x, map fault\n", num); + TRAPSTATUS |= BIT16; /* set bit 16 of trap status */ + TRAPSTATUS |= (BIT5|BIT9); /* set bit 5 of trap status */ + goto nomaps; /* map overflow, map fault trap */ + } + if (!MEM_ADDR_OK(pad)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE5 %06x User page address %06x invalid\n", + MEMSIZE, pad); + goto npmem; /* non present memeory trap */ + } + /* load 16 bit map descriptors */ + map = RMH(pad); /* get page descriptor from memory */ + + /* for valid maps translate the map number to a real address */ + /* put this address in the TLB for later translation */ + /* copy the map status bits too and set hit bit in the TLB */ + /* leaving out diags in next statment fails test3/1 of vm.mmm */ + if ((map & 0x8000)) { /* see if map is valid */ + TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000)); + TLB[num] |= 0x04000000; /* set HIT bit on */ + } else + TLB[num] = 0; /* clear the TLB for non valid maps */ + WMR((num<<1), map); /* store map unmodified into cache */ + } + if (num == 0) { /* see if any maps loaded */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps1 No maps loaded %04x, map fault\n", num); + goto nomaps; /* return map fault error */ + } + + /* All maps are now loaded, finish up & return */ + for (i = num; i < MAXMAP; i++) /* zero any remaining TLB entries */ + TLB[i] = 0; /* clear look aside buffer */ + + HIWM = num; /* set new high water mark */ + return ALLOK; /* all cache is loaded, return OK */ + } + /**************END-OF-NON-VIRTUAL-USER-MAPPING-FOR-27-87************/ + + sim_debug(DEBUG_CMD, my_dev, + "load_maps Processing 32/67 & 32/97 Model# %02x\n", CPU_MODEL); + + /* handle load on memory access case for 67, 97, V6 & V9 */ + /* now clear TLB & maps specified by the cpix value */ + for (j = 0; j < spc; j++, num++) { /* clear maps in map cache */ + uint32 pad = msdl+(j<<1); /* get page descriptor address */ + + /* if this is a LPSDCM instruction, just clear the TLB entry */ + if (!lmap) { + /* load 16 bit map descriptors */ + map = RMH(pad); /* get page descriptor from memory */ + TLB[num] = 0; /* clear the TLB for non valid maps */ + if ((num < 0x20) || (num > (spc+BPIX) - 0x10)) + sim_debug(DEBUG_DETAIL, my_dev, + "UserV pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n", + pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000, + TLB[num], MAPC[num/2]); + continue; /* just clear the TLBs */ + } + + /* only do the following tests for LMAP instruction, not LPSDCM */ + /* see if map overflow */ + if (num >= MAXMAP) { + sim_debug(DEBUG_TRAP, my_dev, + "load_maps User page count overflow %04x, map fault\n", num); + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= (BIT5|BIT9); /* set bit 5/9 of trap status */ + else + TRAPSTATUS |= BIT16; /* set bit 16 of trap status */ + goto nomaps; /* map overflow, map fault trap */ + } + + if (!MEM_ADDR_OK(pad)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps MEM SIZE6 %06x User page address %06x non present\n", + MEMSIZE, pad); + goto npmem; /* non present memeory trap */ + } + + /* load 16 bit map descriptors */ + map = RMH(pad); /* get page descriptor from memory */ + + if (lmap) { + TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000)); + TLB[num] |= 0x04000000; /* set HIT bit for lmap */ + /* removing this store of map fails test 2 on 97 */ + WMR((num<<1), map); /* store the map unmodified into cache */ + } + + if ((num < 0x20) || (num > (spc+BPIX) - 0x10)) + sim_debug(DEBUG_DETAIL, my_dev, + "UserV2 pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n", + pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000, + TLB[num], MAPC[num/2]); + } + + if (num == 0) { /* see if any maps loaded */ + sim_debug(DEBUG_TRAP, my_dev, + "load_maps2 No maps loaded %04x, map fault\n", num); + goto nomaps; + } + + /* All maps are now loaded, finish up & return */ + /* removing this code causes diag to stop at 17/0 for 97 in cn.mmm */ + for (i = num; i < MAXMAP; i++) /* zero any remaining entries */ + TLB[i] = 0; /* clear look aside buffer */ + + HIWM = num; /* set new high water mark */ + return ALLOK; /* all cache is loaded, return OK */ + /****************** END-OF-VIRTUAL-USER-MAP-LOADING ********************/ +} + +/* + * Return the real memory address from the logical address + * Also return the protection status, 1 if write protected address. + * For 67, 97, V6, & V9 return all protection bits. + * Addr is a byte address. + */ +LOCAL t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access) +{ + uint32 word, index, map, raddr, mpl, offset; + uint32 nix, msdl, mix; + uint32 MAXMAP = MAX2048; /* default to 2048 maps */ + + *prot = 0; /* show unprotected memory as default */ + /* unmapped mode is unprotected */ + + /*****************START-7X-ADDRESS-PROCESSING****************/ + /* see what machine we have */ + if (CPU_MODEL < MODEL_27) { + MAXMAP = MAX32; /* 32 maps for 32/77 */ + /* 32/7x machine with 8KW maps */ + if (MODES & EXTDBIT) + word = addr & 0xfffff; /* get 20 bit logical word address */ + else + word = addr & 0x7ffff; /* get 19 bit logical word address */ + if ((MODES & MAPMODE) == 0) { + /* check if valid real address */ + if (!MEM_ADDR_OK(word)) { /* see if address is within our memory */ + return NPMEM; /* no, none present memory error */ + } + *realaddr = word; /* return the real address */ + return ALLOK; /* all OK, return instruction */ + } + + /* we are mapped, so calculate real address from map information */ + /* 32/7x machine, 8KW maps */ + index = word >> 15; /* get 4 or 5 bit value */ + map = RMR((index<<1)); /* read the map reg cache contents */ + + /* see if map is valid */ + if ((map & 0x4000) == 0) + /* map is invalid, so return map fault error */ + return MAPFLT; /* map fault error */ + + /* required map is valid, get 9 bit address and merge with 15 bit page offset */ + word = ((map & 0x1ff) << 15) | (word & 0x7fff); + /* check if valid real address */ + if (!MEM_ADDR_OK(word)) /* see if address is within our memory */ + return NPMEM; /* no, none present memory error */ + if ((MODES & PRIVBIT) == 0) { /* see if we are in unprivileged mode */ + if (map & 0x2000) /* check if protect bit is set in map entry */ + *prot = 1; /* return memory write protection status */ + } + *realaddr = word; /* return the real address */ + return ALLOK; /* all OK, return instruction */ + } + /*****************END-OF-7X-ADDRESS-PROCESSING****************/ + + /* Everyone else has 2KW maps */ + /* do common processing */ + /* diag wants the address to be 19 or 24 bit, use masked address */ + if (MODES & (BASEBIT | EXTDBIT)) + word = addr & 0xffffff; /* get 24 bit address */ + else + word = addr & 0x7ffff; /* get 19 bit address */ + + if ((MODES & MAPMODE) == 0) { + /* we are in unmapped mode, check if valid real address */ + if (!MEM_ADDR_OK(word)) { /* see if address is within our memory */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + if (access == MEM_RD) + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + if (access == MEM_WR) + TRAPSTATUS |= BIT2; /* set bit 2 of trap status */ + } else { + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + } + return NPMEM; /* no, none present memory error */ + } + *realaddr = word; /* return the real address */ + return ALLOK; /* all OK, return instruction */ + } + + mpl = SPAD[0xf3] & MASK24; /* get 24 bit dbl wd mpl from spad address */ + + /* set maximum maps for 32/27 and 32/87 processors */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) + MAXMAP = MAX256; /* only 256 2KW (8kb) maps */ + +#if 0 + // FIXME trapstatus bits + if ((mpl == 0) || (RMW(mpl) == 0) || ((RMW(mpl) & MASK16) >= MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr Bad MPL Count or Memory Address for O/S MPL %06x MPL[0] %04x MPL[1] %06x\n", + mpl, RMW(mpl), RMW(mpl+4)); + return MACHINECHK_TRAP; /* diags want machine check error */ + } +#endif + + /* did not get expected machine check trap for */ + /* 27, 87, 67 in test 37/0 if code removed */ + /* unexpected machine check trap for 67 in test 37/0 cn.mmm */ + /* now check the O/S midl pointer for being valid */ + /* we may want to delay checking until we actually use it */ + if (!MEM_ADDR_OK((RMW(mpl+4) & MASK24))) { /* check OS midl */ + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr Bad MPL Memory Address O/S msdl MPL %06x MPL[1] %06x\n", + mpl, RMW(mpl+4)); + + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) { + // 32/27, 32/87 want MACHINECHK for test 37/1 in CN.MMM + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + return MACHINECHK_TRAP; /* diags want machine check error */ + } else + if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6)) { + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + return MAPFLT; /* map fault error */ + } + else + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + // V9 & 32/97 wants MACHINECHK for test 37/1 in CN.MMM & VM.MMM + TRAPSTATUS |= (BIT7|BIT9); /* set bit 7 of trap status */ + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + return MACHINECHK_TRAP; /* diags want machine check error */ + } + } + + /* we are mapped, so calculate real address from map information */ + /* get 11 bit page number from address bits 8-18 */ + index = (word >> 13) & 0x7ff; /* get 11 bit page value */ + offset = word & 0x1fff; /* get 13 bit page offset */ + + //FIXME 112522 + if (MODES & MAPMODE) { + uint32 mpl = SPAD[0xf3]; /* get mpl from spad address */ + uint32 cpix = CPIX; /* get cpix 11 bit offset from psd wd 2 */ + uint32 midl = RMW(mpl+cpix); /* get midl entry for given user cpix */ + uint32 spc = midl & MASK16; /* get 16 bit user segment description count */ + /* output O/S and User MPL entries */ + sim_debug(DEBUG_DETAIL, my_dev, +// sim_debug(DEBUG_TRAP, my_dev, + "+MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", + MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), cpix, + RMW(cpix+mpl), RMW(cpix+mpl+4)); + sim_debug(DEBUG_DETAIL, my_dev, +// sim_debug(DEBUG_TRAP, my_dev, + "+MEMORY spc %x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n", + spc, BPIX, cpix, CPIX, CPIXPL, HIWM); + } + + /* make sure map index is valid */ + if ((index >= (BPIX + CPIXPL)) || (index >= MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr %.6x word %06x loadmap gets mapfault index %04x B(%x)+C(%x) %04x\n", + word, addr, index, BPIX, CPIXPL, BPIX+CPIXPL); + fflush(stdout); + + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= (BIT5|BIT9); /* set bit 5/9 of trap status */ + else + TRAPSTATUS |= BIT16; /* set bit 16 of trap status */ + return MAPFLT; /* map fault error */ + } + + /* continue processing non virtual machines here 32/27 & 32/87 */ + /* at this point all maps have been force loaded in load_maps */ + /* just do the conversion from logical to real address */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) { + map = RMR((index<<1)); /* read the map reg cache contents */ + raddr = TLB[index]; /* get the base address & bits */ + + if (!MEM_ADDR_OK(RMW(mpl+CPIX+4) & MASK24)) { /* check user midl */ + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr 27 & 87 map fault index %04x B+C %04x map %04x TLB %08x\n", + index, BPIX+CPIXPL, map, TLB[index]); + // 32/27 & 32/87 want MACHINECHK for test 37/1 in CN.MMM + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + return MACHINECHK_TRAP; /* diags want machine check error */ + } + + if (((map & 0x8000) == 0) || ((raddr & BIT0) == 0)) { /* see if valid map */ + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr loadmap 0a map fault index %04x B+C %04x map %04x TLB %08x\n", + index, BPIX+CPIXPL, map, TLB[index]); + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + return MAPFLT; /* no, map fault error */ + } + + // needed for 32/27 & 32/87 + /* check if valid real address */ + if (!MEM_ADDR_OK(raddr & MASK24)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr loadmap 0c non present memory fault addr %06x raddr %08x index %04x\n", + word, raddr, index); + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + return NPMEM; /* no, none present memory error */ + } + word = (raddr & 0xffe000) | offset; /* combine real addr and offset */ + *realaddr = word; /* return the real address */ + if (MODES & PRIVBIT) /* all OK if privledged */ + return ALLOK; /* all OK, return instruction */ + + /* get user protection status of map */ + offset = (word >> 11) & 0x3; /* see which 1/4 page we are in */ + if ((BIT1 >> offset) & raddr) { /* is 1/4 page write protected */ + *prot = 1; /* return memory write protection status */ + } + sim_debug(DEBUG_DETAIL, my_dev, + "RealAddrRa address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n", + word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot); + return ALLOK; /* all OK, return instruction */ + } + /*****************END-OF-27-87-ADDRESS-PROCESSING****************/ + + /* handle 32/67, 32/97 and V6 & V9 here */ + /* Concept 32 machine, 2KW maps */ + /* the index is less than B+C, so setup to get a map */ + if (TLB[index] & 0x04000000) { /* is HIT bit on in TLB */ + /* handle HIT bit already on in TLB here */ + /* diags wants a NPMEM error if physical addr is exceeded */ + index &= 0x7ff; /* map # */ + raddr = TLB[index]; /* get the base address & bits */ + /* check if valid real address */ + if (!MEM_ADDR_OK(raddr & MASK24)) { /* see if address is within our memory */ + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr loadmap 2a non present memory fault addr %08x raddr %08x index %04x\n", + addr, raddr, index); + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + if (access == MEM_RD) + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + else + if (access == MEM_WR) + TRAPSTATUS |= BIT2; /* set bit 2 of trap status */ + } else + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + return NPMEM; /* none present memory error */ + } + map = RMR((index<<1)); /* read the map reg contents */ + word = (raddr & 0xffe000) | offset; /* combine map and offset */ + *realaddr = word; /* return the real address */ + + /* handle 32/67 & 32/97 protection here */ + if (CPU_MODEL < MODEL_V6) { + /* process 32/67 & 32/97 load map on access */ + /* handle 32/67 & 32/97 */ + if (MODES & PRIVBIT) /* all OK if privledged */ + return ALLOK; /* all OK, return instruction */ + + /* get protection status of map */ + offset = (word >> 11) & 0x3; /* see which 1/4 page we are in */ + if ((BIT1 >> offset) & raddr) { /* is 1/4 page write protected */ + *prot = 1; /* return memory write protection status */ + } + sim_debug(DEBUG_DETAIL, my_dev, + "RealAddrR address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n", + word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot); + return ALLOK; /* all OK, return instruction */ + } + + /* handle valid V6 & V9 HIT bit on */ + /* get protection status of map */ + offset = ((map >> 12) & 0x6); /* get bits p1 & p2 from map into bits 13 & 14 */ + if (MODES & PRIVBIT) /* all access if privledged */ + *prot = offset | 0x8; /* set priv bit */ + else + *prot = offset; /* return memory write protection status */ + + sim_debug(DEBUG_DETAIL, my_dev, + "RealAddrX address %06x, TLB %06x MAPC[%03x] %08x wprot %02x prot %02x\n", + word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot); + return ALLOK; /* all OK, return instruction */ + } + + /* Hit bit is off in TLB, so lets go get some maps */ + sim_debug(DEBUG_DETAIL, my_dev, + "$MEMORY %06x HIT MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n", + MEMSIZE, mpl, RMW(mpl), RMW(mpl+4), CPIX, RMW(CPIX+mpl), RMW(CPIX+mpl+4)); + + /* check user msdl address now that we are going to access it */ + msdl = RMW(mpl+CPIX+4); /* get msdl entry for given CPIX */ + if (!MEM_ADDR_OK(msdl & MASK24)) { /* check user midl */ + sim_debug(DEBUG_TRAP, my_dev, + "RealAddr User CPIX Non Present Memory User msdl %06x CPIX %04x\n", + msdl, CPIX); + + if (CPU_MODEL == MODEL_67) { + /* test 37/0 wants MAPFLT trap for 67 */ + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + return MAPFLT; /* map fault error on memory access */ + } else + if (CPU_MODEL == MODEL_97) { + // 32/97 wants MAPFLT for test 37/1 in CN.MMM + TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ + TRAPSTATUS |= (BIT7|BIT9); /* set bit 7/9 of trap status */ + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + return MAPFLT; /* no, map fault error */ + } else + if (CPU_MODEL == MODEL_V6) { + // V6 wants MAPFLT for test 37/1 in CN.MMM & VM.MMM */ + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + /* OK for V6 */ + return MAPFLT; /* map fault error */ + } + else + if (CPU_MODEL == MODEL_V9) { + /* V9 wants MAPFLT for test 37/1 in CN.MMM & VM.MMM */ + /* V9 fails test 46/subtest 2 with "did not get expected map trap */ + TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ + TRAPSTATUS |= (BIT7|BIT9); /* set bit 7 of trap status */ + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + return MAPFLT; /* map fault error */ + } + } + + /* get os or user msdl, index < BPIX; os, else user */ + if (index < BPIX) + msdl = RMW(mpl+4); /* get mpl entry wd 1 for os */ + else + /* check user msdl address now that we are going to access it */ + msdl = RMW(mpl+CPIX+4); /* get mpl entry wd 1 for given cpix */ + + /* HIT bit is off, we must load the map entries from memory */ + /* turn on the map hit flag if valid and set maps real base addr */ + nix = index & 0x7ff; /* map # or mapc index */ + word = (TLB[nix] & 0xffe000) | offset; /* combine map and offset */ + if (index < BPIX) + mix = nix; /* get map index in memory */ + else + mix = nix-BPIX; /* get map index in memory */ + map = RMH(msdl+(mix<<1)); /* map content from memory */ + sim_debug(DEBUG_DETAIL, my_dev, + "Addr %06x RealAddr %06x Map0[%04x] HIT %04x TLB[%3x] %08x MAPC[%03x] %08x\n", + addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]); + + /* process HIT bit off V6 & V9 here */ + if ((map & 0x8000) == 0) { + *realaddr = word; /* return the real address */ + /* for V6 & V9 handle demand paging */ + if (CPU_MODEL >= MODEL_V6) { + /* map is not valid, so we have map fault */ + sim_debug(DEBUG_EXP, my_dev, + "AddrMa %06x RealAddr %06x Map0 MISS %04x, TLB[%3x] %08x MAPC[%03x] %08x\n", + addr, word, map, nix, TLB[nix], nix/2, MAPC[nix/2]); + /* do a demand page request for the required page */ + pfault = nix; /* save page number */ + sim_debug(DEBUG_EXP, my_dev, + "Mem_write Daddr2 %06x page %04x demand page bits set TLB %08x map %04x\n", + addr, nix, TLB[nix], map); + return DMDPG; /* demand page request */ + } + /* handle 67 & 97 map invalid here */ + if (CPU_MODEL == MODEL_97) { + if (access == MEM_RD) + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + else + if (access == MEM_WR) + TRAPSTATUS |= BIT2; /* set bit 2 of trap status */ + } else + TRAPSTATUS |= BIT28; /* set bit 28 of trap status */ + return MAPFLT; /* map fault error */ + } + + /* map is valid, process it */ + TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000; + word = (TLB[nix] & 0xffe000) | offset; /* combine map and offset */ + WMR((nix<<1), map); /* store the map reg contents into MAPC cache */ + sim_debug(DEBUG_DETAIL, my_dev, + "RealAddrm RMH %04x mix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n", + map, mix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1)); + + sim_debug(DEBUG_DETAIL, my_dev, + "Addr1c %06x RealAddr %06x Map1[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n", + addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1)); + + *realaddr = word; /* return the real address */ + raddr = TLB[nix]; /* get the base address & bits */ + + if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97)) { + /* get protection status of map */ + if ((MODES & PRIVBIT) == 0) { /* OK if privledged */ + /* otherwise check protection bit */ + offset = (word >> 11) & 0x3; /* see which 1/4 page we are in */ + if ((BIT1 >> offset) & raddr) /* is 1/4 page write protected */ + *prot = 1; /* return memory write protection status */ + } + } else { + /* get protection status of map */ + offset = ((map >> 12) & 0x6); /* get bits p1 & p2 from map into bits 13 & 14 */ + if (MODES & PRIVBIT) /* all access if privledged */ + *prot = offset | 0x8; /* set priv bit */ + else + *prot = offset; /* return memory write protection status */ + } + + /* now do the other halfword of the memory map pair */ + /* calc index of previous or next halfword */ + if ((mix & 1) == 0) { + mix += 1; /* we are at lf hw, so do next hw */ + nix += 1; /* point to next map in MAPC */ + /* This is really a firmware error where the CPU loads the */ + /* right halfword map information even though it exceeds */ + /* the allowed map count. It does not hurt anything, so OK */ + /* 32/67 & V6 allow loading the extra rt hw map entry */ + if ((nix == BPIX) || (nix > (BPIX+CPIXPL))) + return ALLOK; /* no other map is valid, we are done */ + } else + if ((mix & 1) == 1) { + if (nix == BPIX) + return ALLOK; /* no other map is valid, we are done */ + mix -= 1; /* we are at rt hw, so backup hw */ + nix -= 1; /* point to last map in MAPC */ + } + + sim_debug(DEBUG_DETAIL, my_dev, + "RealAddrp mix %04x nix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n", + mix, nix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1)); + + /* allow the excess map entry to be loaded, even though bad */ + if (nix <= (BPIX+CPIXPL)) { /* needs to be a mapped reg */ + sim_debug(DEBUG_DETAIL, my_dev, + "Addr1d BPIX %03x CPIXPL %03x RealAddr %06x TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n", + BPIX, CPIXPL, word, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1)); + + /* mix & nix has other map correct index */ + if ((TLB[nix] & 0x04000000) == 0) { /* is HIT bit already on */ + /* hit not on, so load the map */ + /* allow the excess map entry to be loaded, even though bad */ + if (nix <= (BPIX+CPIXPL)) { /* needs to be a mapped reg */ + map = RMH(msdl+(mix<<1)); /* map content from memory */ + sim_debug(DEBUG_DETAIL, my_dev, + "Addr2a %06x MapX[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n", + addr, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]); + + if (map & 0x8000) { /* must be valid to load */ + /* setting access bit fails test 15/0 in vm.mmm diag */ + TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000; + word = (TLB[nix] & 0xffe000); /* combine map and offset */ + WMR((nix<<1), map); /* store the map reg contents into MAPC cache */ + sim_debug(DEBUG_DETAIL, my_dev, + "Addr2b %06x RealAddr %06x Map2[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n", + addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]); + } + } + } + } + /*****************END-OF-V6-V9-ADDRESS-HIT-PROCESSING****************/ + /*****************END-OF-67-97-ADDRESS-HIT-PROCESSING****************/ + return ALLOK; /* all OK, return instruction */ +} + +/* fetch the current instruction from the PC address */ +LOCAL t_stat read_instruction(uint32 thepsd[2], uint32 *instr) +{ + uint32 status, addr; + + if (CPU_MODEL < MODEL_27) { + /* 32/7x machine with 8KW maps */ + /* instruction must be in first 512KB of address space */ + addr = thepsd[0] & 0x7fffc; /* get 19 bit logical word address */ + } else { + /* 32/27, 32/67, 32/87, 32/97 2KW maps */ + /* Concept 32 machine, 2KW maps */ + if (thepsd[0] & BASEBIT) { /* bit 6 is base mode? */ + addr = thepsd[0] & 0xfffffc; /* get 24 bit address */ + } + else + addr = thepsd[0] & 0x7fffc; /* get 19 bit address */ + } + + /* go read the memory location */ + status = Mem_read(addr, instr); + if ((status == MAPFLT) && (TRAPSTATUS == BIT1)) { + /* if map fault on read, change code to read instruction */ + TRAPSTATUS &= ~BIT1; /* clear error on read memory */ + TRAPSTATUS |= BIT0; /* set error on instruction read */ + } else + if (status == DMDPG) + pfault |= 0x80000000; /* set instruction fetch paging error */ + sim_debug(DEBUG_DETAIL, my_dev, "read_instr status %02x @ %06x\n", status, addr); + return status; /* return ALLOK or ERROR status */ +} + +/* + * Read a full word from memory + * Return error type if failure, ALLOK if + * success. Addr is logical byte address. + */ +LOCAL t_stat Mem_read(uint32 addr, uint32 *data) +{ + uint32 status, realaddr=0, prot, page, map, mix, nix, msdl, mpl, nmap; + + status = RealAddr(addr, &realaddr, &prot, MEM_RD); /* convert address to real physical address */ + + if (status == ALLOK) { + *data = RMW(realaddr); /* valid address, get physical address contents */ + if (((CPU_MODEL >= MODEL_V6) || (CPU_MODEL == MODEL_97) || + (CPU_MODEL == MODEL_67)) && (MODES & MAPMODE)) { + + page = (addr >> 13) & 0x7ff; /* get 11 bit value */ + if (CPU_MODEL >= MODEL_V6) { + /* check for v6 & v9 if we have read access */ + switch (prot & 0x0e) { + case 0x0: case 0x2: + /* O/S or user has no read/execute access, do protection violation */ + sim_debug(DEBUG_EXP, my_dev, + "Mem_readA protect error @ %06x prot %02x modes %08x page %04x\n", + addr, prot, MODES, page); + if (CPU_MODEL == MODEL_V9) + TRAPSTATUS |= BIT2; /* set bit 2 of trap status */ + else + TRAPSTATUS &= ~BIT12; /* clear bit 12 of trap status */ + return MPVIOL; /* return memory protection violation */ + case 0x4: case 0x6: case 0x8: case 0xa: case 0xc: case 0xe: + /* O/S or user has read/execute access, no protection violation */ + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_readB protect is ok @ %06x prot %02x modes %08x page %04x\n", + addr, prot, MODES, page); + } + mpl = SPAD[0xf3]; /* get mpl from spad address */ + nix = page & 0x7ff; /* map # or mapc index */ + if (page < BPIX) { + mix = nix; /* get map index in memory */ + msdl = RMW(mpl+4); /* get mpl entry for o/s */ + } else { + mix = nix-BPIX; /* get map index in memory */ + msdl = RMW(mpl+CPIX+4); /* get mpl entry for given cpix */ + } + nmap = RMH(msdl+(mix<<1)); /* map content from memory */ + map = RMR((page<<1)); /* read the map reg contents */ + /* if I remove this test, we fail at test 14/0 */ + if (((map & 0x800) == 0)) { + map |= 0x800; /* set the accessed bit in the map cache entry */ + WMR((page<<1), map); /* store the map reg contents into cache */ + TLB[page] |= 0x0c000000; /* set the accessed bit in TLB too */ + WMH(msdl+(mix<<1), map); /* save modified map with access bit set */ + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_read Yaddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n", + addr, page, TLB[page], map, nmap); + } + } + /* everybody else has read access */ + } + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_read addr %06x realaddr %06x data %08x prot %02x\n", + addr, realaddr, *data, prot); + } else { + /* RealAddr returned an error */ + sim_debug(DEBUG_EXP, my_dev, + "Mem_read error addr %06x realaddr %06x data %08x prot %02x status %04x\n", + addr, realaddr, *data, prot, status); + if (status == NPMEM) { /* operand nonpresent memory error */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + } else + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + } + if (status == MAPFLT) { + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= (BIT12|BIT16); /* set bit 12 of trap status */ + else + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + } + sim_debug(DEBUG_EXP, my_dev, "Mem_read MISS %02x @ %06x TRAPSTATUS %08x\n", + status, addr, TRAPSTATUS); + } + return status; /* return ALLOK or ERROR status */ +} + +/* + * Write a full word to memory, checking protection + * and alignment restrictions. Return 1 if failure, 0 if + * success. Addr is logical byte address, data is 32bit word + */ +LOCAL t_stat Mem_write(uint32 addr, uint32 *data) +{ + uint32 status, realaddr=0, prot=0, raddr, page, nmap, msdl, mpl, map, nix, mix; + + status = RealAddr(addr, &realaddr, &prot, MEM_WR); /* convert address to real physical address */ + + if (prot) { + sim_debug(DEBUG_DETAIL, my_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %02x\n", + addr, realaddr, *data, prot); + } + + if (status == ALLOK) { + if (((CPU_MODEL >= MODEL_V6) || (CPU_MODEL == MODEL_97) || + (CPU_MODEL == MODEL_67)) && (MODES & MAPMODE)) { + page = (addr >> 13) & 0x7ff; /* get 11 bit value */ + if (CPU_MODEL >= MODEL_V6) { + /* check for v6 & v9 if we have write access */ + switch (prot &0x0e) { + case 0x0: case 0x2: case 0x6: case 0xa: case 0xe: + /* O/S or user has read/execute access, do protection violation */ + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_writeA protect error @ %06x prot %02x modes %08x\n", + addr, prot, MODES); + if (CPU_MODEL == MODEL_V9) + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + else + TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ + return MPVIOL; /* return memory protection violation */ + case 0x4: case 0x8: case 0xc: + /* O/S or user has write access, no protection violation */ + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_writeB protect is ok @ %06x prot %02x modes %08x\n", + addr, prot, MODES); + } + map = RMR((page<<1)); /* read the map reg contents */ + raddr = TLB[page]; /* get the base address & bits */ + nix = page & 0x7ff; /* map # or mapc index */ + mpl = SPAD[0xf3]; /* get mpl from spad address */ + if (page < BPIX) { + mix = nix; /* get map index in memory */ + msdl = RMW(mpl+4); /* get mpl entry for o/s */ + } else { + mix = nix-BPIX; /* get map index in memory */ + msdl = RMW(mpl+CPIX+4); /* get mpl entry for given cpix */ + } + nmap = RMH(msdl+(mix<<1)); /* map content from memory */ + if ((nmap & 0x1000) == 0) { + nmap |= 0x1800; /* set the modify/accessed bit in the map cache entry */ + WMR((page<<1), nmap); /* store the map reg contents into cache */ + TLB[page] |= 0x18000000; /* set the modify/accessed bits in TLB too */ + WMH((msdl+(mix << 1)), nmap); /* save modified map with access bit set */ + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_write Waddr %06x page %04x set access bit TLB %08x map %04x nmap %04x raddr %08x\n", + addr, page, TLB[page], map, nmap, raddr); + } + sim_debug(DEBUG_DETAIL, my_dev, + "Mem_write Xaddr %06x page %04x MA bits set TLB %08x map %04x prot %04x modes %04x\n", + addr, page, TLB[page], map, prot, MODES); + } else { + if (prot) { /* check for write protected memory */ + sim_debug(DEBUG_EXP, my_dev, + "Mem_writeB 32/67 protect error @ %06x prot %02x page %04x\n", + addr, prot, page); + if (CPU_MODEL == MODEL_97) + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + else + TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ + return MPVIOL; /* return memory protection violation */ + } + } + /* everything else has write access */ + } else { + if (prot) { /* check for write protected memory */ + sim_debug(DEBUG_TRAP, my_dev, + "Mem_writeC protect error @ %06x prot %02x\n", addr, prot); + TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ + return MPVIOL; /* return memory protection violation */ + } + } + WMW(realaddr, *data); /* valid address, put physical address contents */ + } else { + /* RealAddr returned an error */ + sim_debug(DEBUG_TRAP, my_dev, + "Mem_write error addr %.8x realaddr %.8x data %.8x prot %02x status %04x\n", + addr, realaddr, *data, prot, status); + if (status == NPMEM) { /* operand nonpresent memory error */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT2; /* set bit 2 of trap status */ + } else + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + } + if (status == MAPFLT) { + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= (BIT12|BIT16); /* set bit 12 of trap status */ + else + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + } + sim_debug(DEBUG_TRAP, my_dev, + "Mem_write error %02x @ %06x TRAPSTATUS %08x pfaualt %04x\n", + status, addr, TRAPSTATUS, pfault); + } + return status; /* return ALLOK or ERROR */ +} + +/* function to set the CCs in PSD1 */ +/* ovr is setting for CC1 */ +LOCAL void set_CCs(uint32 value, int ovr) +{ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (ovr) + CC = CC1BIT; /* CC1 value */ + else + CC = 0; /* CC1 off */ + if (value & FSIGN) + CC |= CC3BIT; /* CC3 for neg */ + else if (value == 0) + CC |= CC4BIT; /* CC4 for zero */ + else + CC |= CC2BIT; /* CC2 for greater than zero */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ +} + +/* retain these values across calls to sim_instr */ +LOCAL uint32 skipinstr = 0; /* Skip test for interrupt on this instruction */ +LOCAL uint32 drop_nop = 0; /* Set if right hw instruction is a nop */ +LOCAL uint32 TPSD[2]; /* Temp PSD */ +#define TPSD1 TPSD[0] /* word 1 of PSD */ +#define TPSD2 TPSD[1] /* word 2 of PSD */ + +/* Opcode definitions */ +/* called from IPU thread */ +void *ipu_sim_instr(void *value) { + t_stat reason = 0; /* reason for stopping */ + t_uint64 dest = 0; /* Holds destination/source register */ + t_uint64 source = 0; /* Holds source or memory data */ + t_uint64 td; /* Temporary */ + t_int64 int64a; /* temp int */ + t_int64 int64b; /* temp int */ + t_int64 int64c; /* temp int */ + uint32 addr; /* Holds address of last access */ + uint32 temp; /* General holding place for stuff */ +// uint32 IR; /* Instruction register */ + uint32 i_flags = 0; /* Instruction description flags from table */ + uint32 t; /* Temporary */ + uint32 temp2; /* Temporary */ + uint32 bc=0; /* Temporary bit count */ +// uint16 OPR; /* Top half of Instruction register */ +// uint16 OP; /* Six bit instruction opcode */ +// uint16 chan; /* I/O channel address */ +// uint16 lchan; /* Logical I/O channel address */ +// uint16 suba; /* I/O subaddress */ +// uint16 lchsa; /* logical I/O channel & subaddress */ +// uint16 rchsa; /* real I/O channel & subaddress */ + uint8 FC; /* Current F&C bits */ + uint8 EXM_EXR=0; /* PC Increment for EXM/EXR instructions */ + uint8 BM, MM, BK; /* basemode, mapped mode, blocked mode */ + uint32 reg; /* GPR or Base register bits 6-8 */ + uint32 sreg; /* Source reg in from bits 9-11 reg-reg instructions */ + uint32 ix = 0; /* index register */ + uint32 dbl; /* Double word */ + uint32 ovr=0; /* Overflow flag */ +//FORSTEP uint32 stopnext = 0; /* Stop on next instruction */ +// uint32 int_icb; /* interrupt context block address */ +// uint32 rstatus; /* temp return status */ + int32 int32a; /* temp int */ + int32 int32b; /* temp int */ + int32 int32c; /* temp int */ +#ifdef NOT_NEEDED + int32 counter=0; /* temp int */ +#endif + + /* the newly created child process in IPU */ + /* running on IPU */ + MyIndex = 1; + PeerIndex = 0; + IPC->pid[MyIndex] = 1; + + /* we will be running with an ipu, set it up */ + /* clear I/O and interrupt entries in SPAD. */ + /* They are not used in the IPU */ + for (ix=0; ix<0xf0; ix++) + SPAD[ix] = 0; + SPAD[0xf7] = 0x13254768; /* set SPAD key for IPU */ + SPAD[0xf0] = 0x20; /* default Trap Table Address (TTA) */ + IPUSTATUS |= ONIPU; /* set ipu state in ipu status, BIT27 */ + IPUSTATUS |= BIT25; /* set ipu traps enabled status, BIT25 */ + TRAPSTATUS |= ONIPU; /* set IPU in trap status too */ + /* This would be BIT20 set to 0 for V9 IPU iconfigured status */ + /* If no IPU configured, BIT19 is set */ + /* FIXME */ + CCW |= HASIPU; /* this is BIT19 for IPU configured */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + PSD1 = 0x80000000; /* PSD1 privledged */ + PSD2 = 0x00000000; /* PSD2 unmapped, unblocked */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + IPUSTATUS &= ~0x87000000; /* reset bits in IPUSTATUS */ + IPUSTATUS |= (MODES & 0x87000000); /* now insert into IPUSTATUS */ + sim_debug(DEBUG_TRAP, my_dev, + "IPU Start Loading PSD1 %.8x PSD2 %.8x IPUSTATUS %08x CCW %.8x\n", + PSD1, PSD2, IPUSTATUS, CCW); + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + /* set interrupt blocking state in IPUSTATUS */ + IPUSTATUS &= ~BIT24; /* clear blocked state in ipu status, bit 24 */ + /* shared by threads */ +#ifdef USE_POSIX_SEM + if (sem_init((sem_t *)&(IPC->simsem), 0, 1) != 0) { + if (errno == ENOSYS) + sim_debug(DEBUG_TRAP, my_dev, + "IPU POSIX semaphores not valid for this processsor %x\n", ix); + } + sim_debug(DEBUG_TRAP, my_dev, + "IPU POSIX semaphores completed for this processsor %x\n", ix); +#else + /* the pthread mutex is initialized in the CPU */ + sim_debug(DEBUG_TRAP, my_dev, + "IPU pthread mutex initialization completed for this processsor\n"); +#endif + wait4sipu = 1; /* now wait for 1st sipu */ + /* IPU thread setup complete */ + + sim_debug(DEBUG_TRAP, my_dev, + "Starting at ipu wait_loop 1 %p 0 %08x 4 %08x\n", (void *)M, M[0], M[1]); + fflush(sim_deb); + reason = SCPE_OK; + cpustop = reason; /* tell IPU our state */ + + /* loop here until time out or error found */ +#ifdef USE_POSIX_SEM +wait_loop: +#endif + while (reason == SCPE_OK) { /* loop until halted */ + i_flags = 0; /* clear flags for next instruction */ + + if (cpustop != SCPE_OK) + break; /* quit running */ + +#ifdef NOT_NEEDED + if (counter++ > 4000) { + sim_debug(DEBUG_EXP, my_dev, + "4000 loops in IPU PeerIndex %x atrap[%x] = %x wait4sipu %x\r\n", + PeerIndex, MyIndex, IPC->atrap[MyIndex], wait4sipu); + fflush(sim_deb); + counter = 0; + } +#endif + + if (skipinstr) { /* need to skip interrupt test? */ + skipinstr = 0; /* skip only once */ + sim_debug(DEBUG_IRQ, my_dev, + "%s Skip instruction PSD %08x %08x wait4sipu %d wait4int %x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, wait4sipu, wait4int); + sim_debug(DEBUG_IRQ, my_dev, + "Skip instruction OPSD %08x %08x PSD %08x %08x IPUSTATUS %08x\n", + OPSD1, OPSD2, PSD1, PSD2, IPUSTATUS); + goto skipi; /* skip int test */ + } + +#ifdef USE_POSIX_SEM + /* we get here when not booting */ + /* process SIPU if IPU present */ + if (IPU_MODEL) { + /* process any pending sipu traps from the ipu here on cpu */ + /* interrupts must be unblocked to take the sipu trap */ + if (((IPUSTATUS & ONIPU) == 0) && IPC && ((IPUSTATUS & BIT24) == 0) && + IPC->atrap[MyIndex]) { + TRAPME = IPC->atrap[MyIndex]; + IPC->atrap[MyIndex] = 0; + IPC->received[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, SPAD[0xf0]); + sim_debug(DEBUG_TRAP, my_dev, + "%s: PC %08x PSD1 %08x PSD2 %08x 0x20 %x 0x80 %x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PC, PSD1, PSD2, M[0x20>2], M[0x80>>2]); +// wait4sipu = 0; /* wait is over for sipu */ + wait4int = 0; /* wait is over for int */ + goto newpsd; /* go process trap */ + } + /* wait for sipu to start us on ipu */ + /* interrupts must be unblocked on IPU too! */ + if ((IPUSTATUS & ONIPU) && ((IPUSTATUS & BIT24) == 0)) { + if (IPC && IPC->atrap[MyIndex]) { + wait4sipu = 0; /* wait is over for sipu */ + TRAPME = IPC->atrap[MyIndex]; /* get trap number */ + IPC->atrap[MyIndex] = 0; /* clear flag */ + IPC->received[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, "%s: (%d) Async TRAP %02x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", __LINE__, TRAPME, SPAD[0xf0]); + sim_debug(DEBUG_TRAP, my_dev, + "%s: PC %08x PSD1 %08x PSD2 %08x 0x20 %x 0x80 %x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PC, PSD1, PSD2, M[0x20>2], M[0x80>>2]); + goto newpsd; /* go process trap */ + } + if (wait4sipu) { +// sim_idle_ms_sleep(1); /* wait 1 ms */ + millinap(1); /* wait 1 ms */ + goto wait_loop; /* continue waiting */ + } + } + } +#else /* USE_POSIX_SEM */ + /* we may or may not be waiting for sipu */ + /* wait for sipu to start us on ipu */ + /* interrupts must be unblocked on IPU to receive SIPU */ + if ((IPUSTATUS & BIT24) == 0) { +cond_go: +// lock_mutex(); /* lock mutex */ +cond_ok: + if (IPC && (IPC->atrap[MyIndex] != 0)) { + /* we are unblocked, look for SIPU */ + /* we have a trap available, lock and get it */ + if (IPC && IPC->atrap[MyIndex]) { + lock_mutex(); /* lock mutex */ + TRAPME = IPC->atrap[MyIndex]; /* get trap number */ + IPC->atrap[MyIndex] = 0; /* clear trap value location */ + unlock_mutex(); /* unlock mutex */ + IPC->received[MyIndex]++; /* count it received */ + wait4sipu = 0; /* wait is over for sipu */ + sim_debug(DEBUG_TRAP, my_dev, "IPU: (%d) Async TRAP %02x SPAD[0xf0] %08x\n", + __LINE__, TRAPME, SPAD[0xf0]); + sim_debug(DEBUG_TRAP, my_dev, "IPU: PC %08x PSD %08x %08x 0x20 %x\n", + PC, PSD1, PSD2, M[0x20>2]); + goto newpsd; /* go process trap */ + } + } + /* unblocked and locked and no async trap */ + if (wait4sipu) { /* are we to wait */ + lock_mutex(); /* lock mutex */ + while (IPC->atrap[MyIndex]==0) /* sleep on the condition */ + pthread_cond_wait(&IPC->cond, &IPC->mutex); /* wait for wakeup */ + unlock_mutex(); /* unlock mutex and continue */ + goto cond_ok; /* continue waiting */ + } + /* not waiting for sipu, so continue processing */ +// unlock_mutex(); /* unlock mutex and continue */ + } + /* we are blocked, continue */ + /* continue processing */ +#endif /* USE_POSIX_SEM */ + +skipi: + i_flags = 0; /* do not update pc if MF or NPM */ + TRAPSTATUS = IPUSTATUS & 0x57; /* clear all trap status except ipu type */ + PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ + //FIXME added change 112922 + OPSD1 = PSD1; /* save the old PSD1 */ + OPSD2 = PSD2; /* save the old PSD2 */ + + /* fill IR from logical memory address */ + if ((TRAPME = read_instruction(PSD, &IR))) { + sim_debug(DEBUG_TRAP, my_dev, + "read_instr TRAPME %02x PSD %08x %08x i_flags %04x\n", + TRAPME, PSD1, PSD2, i_flags); + if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) || + (CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) { + if ((TRAPME == MAPFLT) || (TRAPME == NPMEM)) { + i_flags |= HLF; /* assume half word instr */ + PSD1 &= ~BIT31; /* force off last right */ + // fix for 32/67 test 32/3 in MMM diag + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_67)) + i_flags |= BT; /* do not update pc if MF or NPM */ + else + i_flags &= ~BT; /* update pc */ + } + } else { + if ((TRAPME == PRIVVIOL_TRAP) && (CPU_MODEL == MODEL_V9)) { + i_flags |= HLF; /* assume half word instr */ + i_flags &= ~BT; /* no branch taken */ + PSD1 &= ~BIT31; /* force off last right */ + } + } + sim_debug(DEBUG_TRAP, my_dev, + "read_instr2 TRAPME %02x PSD %08x %08x i_flags %04x\n", + TRAPME, PSD1, PSD2, i_flags); + goto newpsd; /* go process trap */ + } + + if (PSD1 & 2) { /* see if executing right half */ + /* we have a rt hw instruction */ + IR <<= 16; /* put instruction in left hw */ + if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) || + (CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + goto exec; /* machine does not drop nop instructions */ + } + /* We have 67 or V6 and have a rt hw instruction */ + if (IR == 0x00020000) { /* is this a NOP from rt hw? */ + PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); /* skip this instruction */ + if (skipinstr) + sim_debug(DEBUG_IRQ, my_dev, + "2Rt HW instruction skipinstr %1x is set PSD1 %08x PSD2 %08x IPUSTATUS %08x\n", + skipinstr, PSD1, PSD2, IPUSTATUS); + goto skipi; /* go read next instruction */ + } + if (skipinstr) + sim_debug(DEBUG_IRQ, my_dev, + "3Rt HW instruction skipinstr %1x is set PSD1 %08x PSD2 %08x IPUSTATUS %08x\n", + skipinstr, PSD1, PSD2, IPUSTATUS); + } else { + /* we have a left hw or fullword instruction */ + /* see if we can drop a rt hw nop instruction */ + OP = (IR >> 24) & 0xFC; /* this is a 32/67 or above, get OP */ + if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) || + (CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + goto exec; /* old machines did not drop nop instructions */ + if (PSD1 & BASEBIT) + i_flags = base_mode[OP>>2]; /* set the BM instruction processing flags */ + else + i_flags = nobase_mode[OP>>2]; /* set the NBM instruction processing flags */ +//FIX112922 if ((i_flags & 0xf) == HLF) { /* this is left HW instruction */ + if (i_flags & HLF) { /* this is left HW instruction */ + if ((IR & 0xffff) == 0x0002) { /* see if rt hw is a nop */ + /* treat this as a fw instruction */ + drop_nop = 1; /* we need to skip nop next time */ +// sim_debug(DEBUG_IRQ, my_dev, + sim_debug(DEBUG_DETAIL, my_dev, + "IPU setting Drop NOP OPSD1 %08x PSD1 %08x PC %08x IR %08x\n", OPSD1, PSD1, PC, IR); + goto exec2; + } + } + } + +exec: /* we re-enter here for EXR, EXRR, or EXM op */ + OP = (IR >> 24) & 0xFC; /* get OP */ + if (PSD1 & BASEBIT) + i_flags = base_mode[OP>>2]; /* set the BM instruction processing flags */ + else + i_flags = nobase_mode[OP>>2]; /* set the NBM instruction processing flags */ +exec2: + /* temp saves for debugging */ + OIR = IR; /* save the instruction */ + OPSD1 = PSD1; /* save the old PSD1 */ + OPSD2 = PSD2; /* save the old PSD2 */ + TRAPSTATUS = IPUSTATUS & 0x57; /* clear all trap status except ipu type */ +// bc = 0; +// EXM_EXR = 0; +// source = 0; + + /* Split instruction into pieces */ + PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ + sim_debug(DEBUG_DETAIL, my_dev, + "-----Instr @ PC %08x PSD1 %08x PSD2 %08x IR %08x drop_nop %x\n", + PC, PSD1, PSD2, IR, drop_nop); + + OPR = (IR >> 16) & MASK16; /* use upper half of instruction */ + OP = (OPR >> 8) & 0xFC; /* Get opcode (bits 0-5) left justified */ + FC = ((IR & F_BIT) ? 0x4 : 0) | (IR & 3); /* get F & C bits for addressing */ + reg = (OPR >> 7) & 0x7; /* dest reg or xr on base mode */ + sreg = (OPR >> 4) & 0x7; /* src reg for reg-reg instructions or BR instr */ + dbl = 0; /* no doubleword instruction */ + ovr = 0; /* no overflow or arithmetic exception either */ + dest = (t_uint64)IR; /* assume memory address specified */ + CC = PSD1 & 0x78000000; /* save CC's if any */ + MODES = PSD1 & 0x87000000; /* insert bits 0, 5, 6, 7 from PSD 1 */ + IPUSTATUS &= ~0x87000000; /* reset those bits in IPUSTATUS */ + IPUSTATUS |= (MODES & 0x87000000); /* now insert into IPUSTATUS */ + if (PSD2 & MAPBIT) { + IPUSTATUS |= BIT8; /* set bit 8 of ipu status to mapped */ + MODES |= MAPMODE; /* set mapped mode */ + } else { + IPUSTATUS &= ~BIT8; /* reset bit 8 of ipu status */ + MODES &= ~MAPMODE; /* reset mapped mode */ + } + + /* Update history for this instruction */ + if (hst_lnt) { + hst_p += 1; /* next history location */ + if (hst_p >= hst_lnt) /* check for wrap */ + hst_p = 0; /* start over at beginning */ + hst[hst_p].opsd1 = OPSD1; /* set original psd1 */ + hst[hst_p].opsd2 = OPSD2; /* set original psd2 */ + hst[hst_p].oir = OIR; /* set original instruction */ + hst[hst_p].modes = MODES; /* save current mode bits */ + hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */ + if (IPUSTATUS & BIT24) + hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */ + if (IPUSTATUS & BIT27) + hst[hst_p].modes |= IPUMODE; /* save ipu/ipu status bit */ + } + + if (MODES & BASEBIT) { +#ifdef NONOP + i_flags = base_mode[OP>>2]; /* set the instruction processing flags */ +#endif + addr = IR & RMASK; /* get address offset from instruction */ + sim_debug(DEBUG_DETAIL, my_dev, + "Base OP %04x i_flags %04x addr %08x\n", OP, i_flags, addr); + switch(i_flags & 0xf) { + case HLF: + source = GPR[sreg]; /* get the src reg from instruction */ + break; + case IMM: + if (PC & 02) { /* if pc is on HW boundry, bad address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC1 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + break; + case ADR: + ix = (IR >> 20) & 7; /* get index reg from instruction */ + if (ix != 0) + addr += (GPR[ix] & MASK24); /* if not zero, add in reg contents */ + case WRD: + if (PC & 02) { /* if pc is on HW boundry, bad address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC2 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + ix = (IR >> 16) & 7; /* get base reg from instruction */ + if (ix != 0) + addr += (BR[ix] & MASK24); /* if not zero, add to base reg contents */ + FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */ + FC |= addr & 3; /* set new C bits to address from orig or regs */ + addr &= MASK24; /* make pure 24 bit addr */ + break; + case INV: + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + break; + } + } else { +#ifdef NONOP + i_flags = nobase_mode[OP>>2]; /* set the instruction processing flags */ +#endif + addr = IR & 0x7ffff; /* get 19 bit address from instruction */ + if (PC >= 0x80000) { + TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */ + // DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails + if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) || + (CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) { + // DIAG fix for 32/87 test 33/2, clear psd bit 31 + if ((CPU_MODEL == MODEL_87)) + PSD1 &= ~BIT31; /* force off last right */ + // DIAG fix 32/27 32/67 for diag MMM test 33/2 + if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67)) + i_flags |= BT; /* do not update pc if MAPFAULT on 27 */ + else + i_flags &= ~BT; /* do not update pc if MF or NPM */ + i_flags |= HLF; /* assume half word instr */ + } + if ((CPU_MODEL <= MODEL_27)) { + /* 77, 27 rolls to zero, not 80000 */ + PSD1 &= 0xff07ffff; /* remove overflow bits */ + } else { + PSD1 &= 0xff0fffff; /* leave overflow bit for trap addr */ + } + sim_debug(DEBUG_TRAP, my_dev, + "PC over 80000 PC %08x Base OP %02x i_flags %04x addr %06x PSD %08x %08x\n", + PC, OP, i_flags, addr, PSD1, PSD2); + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + sim_debug(DEBUG_DETAIL, my_dev, + "Non Based i_flags %04x addr %08x\n", i_flags, addr); + /* non base mode instructions have bit 0 of the instruction set */ + /* for word length instructions and zero for halfword instructions */ + /* the LA (op=0x34) is the only exception. So test for PC on a halfword */ + /* address and trap if word opcode is in right hw */ + /* if pc is on HW boundry, addr trap if bit zero set */ + if (PC & 02) { + if ((OP == 0x34) || (OP & 0x80)) { + i_flags |= HLF; /* diags treats these as hw instructions */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* go execute the trap now */ + } + } + switch(i_flags & 0xf) { + case HLF: /* halfword instruction */ + source = GPR[sreg]; /* get the src reg contents */ + break; + + case IMM: /* Immediate mode */ + if (PC & 02) { /* if pc is on HW boundry, bad address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC3 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + break; + + case ADR: /* Normal addressing mode */ + ix = (IR >> 21) & 3; /* get the index reg if specified */ + if (ix != 0) { + addr += GPR[ix]; /* if not zero, add in reg contents */ + FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */ + FC |= addr & 3; /* set new C bits to address from orig or regs */ + } + + /* wart alert! */ + /* the lea instruction requires special handling for indirection. */ + /* Bits 0,1 are set to 1 in result addr if indirect bit is zero in */ + /* instruction. Bits 0 & 1 are set to the last word */ + /* or instruction in the chain bits 0 & 1 if indirect bit set */ + /* if IX == 00 => dest = IR */ + /* if IX == 0x => dest = IR + reg */ + /* if IX == Ix => dest = ind + reg */ + + /* fall through */ + case WRD: /* Word addressing, no index */ + bc = 0xC0000000; /* set bits 0, 1 for instruction if not indirect */ + t = IR; /* get current IR */ + addr &= MASK24; /* make pure 24 bit addr */ + while ((t & IND) != 0) { /* process indirection */ + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + sim_debug(DEBUG_TRAP, my_dev, + "case WRD Mem_read status %02x @ %08x OP %04x\n", TRAPME, addr, OP); + if (CPU_MODEL == MODEL_V9) /* V9 wants bit0 set in pfault */ + if (TRAPME == DMDPG) /* demand page request */ + pfault |= 0x80000000; /* set instruction fetch paging error */ + goto newpsd; /* memory read error or map fault */ + } + bc = temp & 0xC0000000; /* save new bits 0, 1 from indirect location */ + CC = (temp & 0x78000000); /* save CC's from the last indirect word */ + /* process new X, I, ADDR fields */ + addr = temp & MASK19; /* get just the addr */ + ix = (temp >> 21) & 3; /* get the index reg from indirect word */ + if (ix != 0) + addr += (GPR[ix] & MASK19); /* add the register to the address */ + /* if no F or C bits set, use original, else new */ + if ((temp & F_BIT) || (addr & 3)) + FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3); + else { + addr |= (IR & F_BIT); /* copy F bit from instruction */ + addr |= (FC & 3); /* copy in last C bits */ + } + t = temp; /* go process next indirect location */ + temp &= MASK19; /* go process next indirect location */ + addr &= ~F_BIT; /* turn off F bit */ + } + dest = (t_uint64)addr; /* make into 64 bit variable */ + break; + + case INV: /* Invalid instruction */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + break; + } + } + + /* Read memory operand */ + if (i_flags & RM) { + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + sim_debug(DEBUG_TRAP, my_dev, + "case RM Mem_read status %02x @ %08x\n", TRAPME, addr); + // DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails + if ((TRAPME == MAPFLT) || (TRAPME == NPMEM) || (TRAPME == MPVIOL)) + PSD1 &= ~BIT31; /* force off last right */ + goto newpsd; /* memory read error or map fault */ + } + source = (t_uint64)temp; /* make into 64 bit value */ + switch(FC) { + case 0: /* word address, extend sign */ + source |= (source & MSIGN) ? D32LMASK : 0; + break; + case 1: /* left hw */ + source >>= 16; /* move left hw to right hw*/ + /* Fall through */ + case 3: /* right hw or right shifted left hw */ + source &= RMASK; /* use just the right hw */ + if (source & 0x8000) { /* check sign of 16 bit value */ + /* sign extend the value to leftmost 48 bits */ + source = LMASK | (source & RMASK); /* extend low 32 bits */ + source |= (D32LMASK); /* extend hi bits */ + } + break; + case 2: /* double word address */ + if ((addr & 7) != 2) { /* must be double word adddress */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC4 case RM wd 1/3 Mem_read DW status %02x @ %08x src %08x\n", + TRAPME, addr, (uint32)source); + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ + sim_debug(DEBUG_TRAP, my_dev, + "case RM wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4); + goto newpsd; /* memory read error or map fault */ + } + source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */ + dbl = 1; /* double word instruction */ + break; + case 4: /* byte mode, byte 0 */ + case 5: /* byte mode, byte 1 */ + case 6: /* byte mode, byte 2 */ + case 7: /* byte mode, byte 3 */ + source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */ + break; + } + } + + /* Read memory operand without doing sign extend for EOMX/ANMX/ORMX/ARMX */ + if (i_flags & RNX) { + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + sim_debug(DEBUG_TRAP, my_dev, + "case RNX 2 Mem_read status %02x @ %08x\n", TRAPME, addr); + goto newpsd; /* memory read error or map fault */ + } + source = (t_uint64)temp; /* make into 64 bit value */ + switch(FC) { + case 0: /* word address and no sign extend */ + source &= D32RMASK; /* just l/o 32 bits */ + break; + case 1: /* left hw */ + source >>= 16; /* move left hw to right hw*/ + /* Fall through */ + case 3: /* right hw or right shifted left hw */ + source &= RMASK; /* use just the right hw */ + break; + case 2: /* double word address */ + if ((addr & 7) != 2) { /* must be double word adddress */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC5 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ + sim_debug(DEBUG_TRAP, my_dev, + "case RNX wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4); + goto newpsd; /* memory read error or map fault */ + } + source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */ + dbl = 1; /* double word instruction */ + break; + case 4: /* byte mode, byte 0 */ + case 5: /* byte mode, byte 1 */ + case 6: /* byte mode, byte 2 */ + case 7: /* byte mode, byte 3 */ + source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */ + break; + } + } + + /* Read in if from register */ + if (i_flags & RR) { + if (FC == 2 && (i_flags & HLF) == 0) /* double dest? */ + dbl = 1; /* src must be dbl for dbl dest */ + dest = (t_uint64)GPR[reg]; /* get the register content */ + if (dbl) { /* is it double regs */ + if (reg & 1) { /* check for odd reg load */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC6 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + /* merge the regs into the 64bit value */ + dest = (((t_uint64)dest) << 32) | ((t_uint64)GPR[reg+1]); + } else { + /* sign extend the data value */ + dest |= (dest & MSIGN) ? D32LMASK : 0; + } + } + + /* For Base mode */ + if (i_flags & RB) { + dest = (t_uint64)BR[reg]; /* get base reg contents */ + } + + /* For register instructions */ + if (i_flags & R1) { + source = (t_uint64)GPR[sreg]; + if (dbl) { + if (sreg & 1) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + /* merge the regs into the 64bit value */ + source = (source << 32) | ((t_uint64)GPR[reg+1]); + } else { + /* sign extend the data value */ + source |= (source & MSIGN) ? ((t_uint64)MASK32) << 32: 0; + } + } + + /* process instruction op code */ + sim_debug(DEBUG_DETAIL, my_dev, + "PSD %08x %08x SW OP %04x IR %08x addr %08x\n", + PSD1, PSD2, OP, IR, addr); + + /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + /* start processing the opcodes */ + /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + switch (OP>>2) { + /* + * For op-codes=00,04,08,0c,10,14,28,2c,38,3c,40,44,60,64,68 + */ + /* Reg - Reg instruction Format (16 bit) */ + /* |--------------------------------------| */ + /* |0 1 2 3 4 5|6 7 8 |9 10 11|12 13 14 15| */ + /* | Op Code | DReg | SReg | Aug Code | */ + /* |--------------------------------------| */ + case 0x00>>2: /* HLF - HLF */ /* IPU General operations */ + switch(OPR & 0xF) { /* switch on aug code */ + case 0x0: /* HALT */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged to halt */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* Privlege violation trap */ + } + if (IPUSTATUS & BIT23) { /* Priv mode halt must be enabled */ + TRAPME = PRIVHALT_TRAP; /* set the trap to take */ + goto newpsd; /* Privlege mode halt trap */ + } + + /* if on the IPU simulate a wait instead */ + if ((IPUSTATUS & ONIPU) && (cpustop == SCPE_OK)) { + /* wait for any trap, knowing there will be no interrupts */ + if (wait4sipu == 0) { + time_t result = time(NULL); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_TRAP, my_dev, + "Starting %s HALT PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x time %.8x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, IPUSTATUS, (uint32)result); + } +#ifndef DO_A_HALT + else { +#ifdef USE_POSIX_SEM +// sim_idle_ms_sleep(1); /* wait 1 ms */ + millinap(1); /* wait 1 ms */ + goto wait_loop; /* continue waiting */ +#else + wait4sipu = 1; /* show we are waiting for SIPU */ + goto cond_go; /* start waiting for sipu */ +#endif + } + wait4sipu = 1; /* show we are waiting for SIPU */ + i_flags |= BT; /* keep PC from being incremented while waiting */ + break; /* keep going */ +#endif + } + +#ifndef NOT_ON_IPU_FOR_NOW + /* we need to do an actual halt here if on IPU */ + sim_debug(DEBUG_EXP, my_dev, + "\n[][][][][][][][][][] IPU HALT [1][][][][][][][][][]\n"); + sim_debug(DEBUG_EXP, my_dev, + "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, IPUSTATUS); + for (ix=0; ix<8; ix+=2) { + sim_debug(DEBUG_EXP, my_dev, + "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } + sim_debug(DEBUG_EXP, my_dev, + "[][][][][][][][][][] IPU HALT [1][][][][][][][][][]\n"); + + fprintf(stdout, "\r\n[][][][][][][][][][] IPU HALT [1][][][][][][][][][]\r\n"); + fprintf(stdout, "PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x\r\n", + PSD1, PSD2, TRAPME, IPUSTATUS); + for (ix=0; ix<8; ix+=2) { + fprintf(stdout, "GPR[%d] %.8x GPR[%d] %.8x\r\n", + ix, GPR[ix], ix+1, GPR[ix+1]); + } + if (MODES & BASEBIT) { /* see if based */ + for (ix=0; ix<8; ix+=2) { + fprintf(stdout, "BR[%d] %.8x BR[%d] %.8x\r\n", + ix, BR[ix], ix+1, BR[ix+1]); + } + } + fprintf(stdout, "[][][][][][][][][][] IPU HALT [1][][][][][][][][][]\r\n"); +#endif +/*TEST DIAG*/reason = STOP_HALT; /* do halt for now */ + cpustop = reason; /* tell IPU our state */ + fprintf(stdout, "[][][][][][][][][][] IPU HALT [1][][][][][][][][][]\r\n"); + fflush(stdout); + fflush(sim_deb); + pthread_exit((void *)&reason); + break; + + case 0x1: /* WAIT */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged to wait */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* Privlege violation trap */ + } + /* if interrupts are blocked, system check trap */ + if (IPUSTATUS & BIT24) { /* status word bit 24 says blocked */ + TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT12; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT20; /* set bit 20 of trap status */ + goto newpsd; /* System check trap */ + } +#if 0 +do_ipu_wait: +#endif + PC = OPSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */ + if (IPU_MODEL && (IPUSTATUS & ONIPU)) { + /* Hack around it when on IPU side: wait by expensive method */ + /* wait for any trap, knowing there will be no interrupts */ + if (wait4sipu == 0) { + time_t result = time(NULL); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_TRAP, my_dev, + "Starting %s WAIT1 PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x time %.8x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, IPUSTATUS, (uint32)result); + } else { +#ifdef USE_POSIX_SEM +// sim_idle_ms_sleep(1); /* wait 1 ms */ + millinap(1); /* wait 1 ms */ + goto wait_loop; /* continue waiting */ +#else + wait4sipu = 1; /* show we are waiting for SIPU */ + goto cond_go; /* start waiting for sipu */ +#endif + } + wait4sipu = 1; /* show we are waiting for SIPU */ + i_flags |= BT; /* keep PC from being incremented while waiting */ + } +#ifdef ONLY_FOR_CPU_CODE + else { + if (wait4int == 0) { + time_t result = time(NULL); +// sim_debug(DEBUG_DETAIL, my_dev, + sim_debug(DEBUG_TRAP, my_dev, + "Starting %s WAIT2 PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x time %.8x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, IPUSTATUS, (uint32)result); + } + /* tell simh we will be waiting */ + wait4int = 1; /* show we are waiting for interrupt */ + i_flags |= BT; /* keep PC from being incremented while waiting */ + } +#endif + break; + case 0x2: /* NOP */ + break; + case 0x3: /* LCS */ + /* get console switches from memory loc 0x780 */ + if ((TRAPME = Mem_read(0x780, &GPR[reg]))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + set_CCs(GPR[reg], 0); /* set the CC's, CC1 = 0 */ + break; + case 0x4: /* ES */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7a OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + /* reg is reg to extend sign into from reg+1 */ + GPR[reg] = (GPR[reg+1] & FSIGN) ? FMASK : 0; + set_CCs(GPR[reg], 0); /* set CCs, CC2 & CC3 */ + break; + case 0x5: /* RND */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7b OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + temp = GPR[reg]; /* save the current contents of specified reg */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + bc = 1; + t |= ((bc & FSIGN) != 0) ? 2 : 0; /* ditto for the bit value */ + if (GPR[reg+1] & FSIGN) { /* if sign of R+1 is set, incr R by 1 */ + temp += bc; /* add the bit value to the reg */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) { + ovr = 1; /* we have an overflow */ + } + GPR[reg] = temp; /* update the R value */ + } else + ovr = 0; + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* handle trap */ + } + break; + case 0x6: /* BEI */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged to BEI */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* Privlege violation trap */ + } + if (IPU_MODEL && (IPUSTATUS & ONIPU)) { + /* on IPU : */ + TRAPME = IPUUNDEFI_TRAP; + sim_debug(DEBUG_TRAP, my_dev, + "IPU BEI PSD %.8x %.8x SPDF5 %.8x IPUSTATUS %08x\n", + PSD1, PSD2, SPAD[0xf5], IPUSTATUS); +//112522 i_flags |= BT; /* leave PC unchanged, so we point at BEI */ + goto newpsd; + } + PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 */ + MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ + PSD2 |= SETBBIT; /* set to blocked state */ + IPUSTATUS |= BIT24; /* into status word bit 24 too */ + MODES |= BLKMODE; /* set blocked mode */ + + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + + case 0x7: /* UEI */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged to UEI */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* Privlege violation trap */ + } + IPUSTATUS &= ~BIT24; /* clear status word bit 24 */ + MODES &= ~(BLKMODE|RETBLKM); /* reset blocked & retain mode bits */ + PSD2 &= ~(SETBBIT|RETBBIT); /* clear bits 48 & 49 to be unblocked */ + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + case 0x8: /* EAE */ + PSD1 |= AEXPBIT; /* set the enable AEXP flag in PSD 1 */ + MODES |= AEXPBIT; /* enable arithmetic exception in modes & PSD 1 */ + IPUSTATUS |= AEXPBIT; /* into status word too */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + case 0x9: /* RDSTS */ + GPR[reg] = IPUSTATUS; /* get IPU status word */ + sim_debug(DEBUG_EXP, my_dev, "RDSTS CCW %08x IPUSTATUS %8x\n", CCW, IPUSTATUS); + break; + case 0xA: /* SIPU */ /* ignore for now */ + /* if we have an IPU, process SIPU instruction */ + sim_debug(DEBUG_TRAP, my_dev, + "SIPU @%s IPUSTATUS %08x SPAD[0xf9] %08x CCW %0x PSD %08x %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", + IPUSTATUS, SPAD[0xf9], CCW, PSD1, PSD2); + + if (CCW & HASIPU) { + /* CPU side = [0] IPU side = [1] */ + //GR if (IPC && IPC->atrap[PeerIndex]) { +#ifdef USE_POSIX_SEM + if (IPC->atrap[PeerIndex]) { + /* previous atrap not yet handled */ + IPC->blocked[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU blocked IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", IPUSTATUS, CCW, SPAD[0xf0]); + + //GR Give it a millisec to unblock the atrap +// sim_idle_ms_sleep(1); /* wait 1 ms */ + millinap(1); /* wait 1 ms */ + } + + if (IPC->atrap[PeerIndex] == 0) { + IPC->sent[MyIndex]++; + IPC->atrap[PeerIndex] = SIGNALIPU_TRAP; + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", IPUSTATUS, CCW, SPAD[0xf0]); + } + else + IPC->dropped[MyIndex]++; +#else + if (IPC->atrap[PeerIndex]) { + /* previous atrap not yet handled if not zero */ + IPC->blocked[MyIndex]++; /* count as blocked */ + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU blocked IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", IPUSTATUS, CCW, SPAD[0xf0]); + //GR Give it a millisec to unblock the atrap +// sim_idle_ms_sleep(1); /* wait 1 ms */ + millinap(1); /* wait 1 ms */ + } + if (IPC->atrap[PeerIndex] == 0) { + lock_mutex(); /* lock mutex */ + IPC->atrap[PeerIndex] = SIGNALIPU_TRAP; + pthread_cond_signal(&IPC->cond); /* wake any waiters */ + unlock_mutex(); /* unlock mutex */ + IPC->sent[MyIndex]++; + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", IPUSTATUS, CCW, SPAD[0xf0]); + } else { +// unlock_mutex(); /* unlock mutex */ + IPC->dropped[MyIndex]++; /* count dropped SIPU */ + sim_debug(DEBUG_TRAP, my_dev, + "%s: Async SIPU sent IPUSTATUS %08x CCW %08x SPAD[0xf0] %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", IPUSTATUS, CCW, SPAD[0xf0]); + } +#endif /* USE_POSIX_SEM */ + } else { + sim_debug(DEBUG_TRAP, my_dev, + "SIPU IPUSTATUS %08x CCW %08x\n", IPUSTATUS, CCW); + goto newpsd; /* handle trap */ +//HANGS TRAPME = IPUUNDEFI_TRAP; /* undefined IPU instruction */ +//HANGS TRAPME = SYSTEMCHK_TRAP; /* trap condition */ +//HANGS TRAPME = MACHINECHK_TRAP; /* trap condition */ +//HANGS TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ +//FIXME goto newpsd; /* handle trap */ + } + break; + case 0xB: /* RWCS */ /* RWCS ignore for now */ + /* reg = specifies reg containing the ACS/WCS address */ + /* sreg = specifies the ACS/WCS address */ + /* if the WCS option is not present, address spec error */ + /* if the mem addr is not a DW, address spec error */ + /* If 0<-Rs<=fff and Rs bit 0=0, then PROM address */ + /* If 0<-Rs<=fff and Rs bit 0=1, then ACS address */ + /* if bit 20 set, WCS enables, else addr spec error */ + if ((IPUSTATUS & 0x00000800) == 0) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7c OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + /* Maybe TODO copy something from WCS */ + break; + case 0xC: /* WWCS */ /* WWCS ignore for now */ + /* reg = specifies the logical address in memory that */ + /* is to receive the ACS/WCS contents */ + /* sreg = specifies the ACS/WCS address */ + /* bit 20 of ipu stat must be set=1 to to write to ACS or WCS */ + /* bit 21 of IPU stat must be 0 to write to ACS */ + /* if bit 20 set, WCS enables, else addr spec error */ + if ((IPUSTATUS & 0x00000800) == 0) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7d OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + /* Maybe TODO copy something to WCS */ + break; + case 0xD: /* SEA */ + if (MODES & BASEBIT) /* see if based */ + goto inv; /* invalid instruction in based mode */ + sim_debug(DEBUG_IRQ, my_dev, + "SEA for extended mode PSD %08x %08x STATUS %08x\r\n", + PSD1, PSD2, IPUSTATUS); + MODES |= EXTDBIT; /* set new extended flag (bit 5) in modes & PSD */ + PSD1 |= EXTDBIT; /* set the enable AEXP flag in PSD1 */ + IPUSTATUS |= EXTDBIT; /* into status word too */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + case 0xE: /* DAE */ + MODES &= ~AEXPBIT; /* disable arithmetic exception in modes & PSD */ + PSD1 &= ~AEXPBIT; /* disable AEXP flag in PSD */ + IPUSTATUS &= ~AEXPBIT; /* into status word too */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + + case 0xF: /* CEA */ + if (MODES & BASEBIT) /* see if based */ + goto inv; /* invalid instruction in based mode */ + MODES &= ~EXTDBIT; /* disable extended mode in modes and PSD */ + PSD1 &= ~EXTDBIT; /* disable extended mode (bit 5) flag in PSD */ + IPUSTATUS &= ~EXTDBIT; /* into status word too */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + } + break; + case 0x04>>2: /* 0x04 RR|R1|SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */ + i_flags &= ~SCC; /* make sure we do not set CC's for dest value */ + switch(OPR & 0xF) { + case 0x0: /* ANR */ + dest &= source; /* just an and reg to reg */ + if (dest & MSIGN) + dest |= D32LMASK; /* force upper word to all ones */ + i_flags |= SCC; /* make sure we set CC's for dest value */ + break; + + case 0xA: /* CMC */ /* Cache Memory Control - Diag use only */ + if (CPU_MODEL == MODEL_87) + break; /* just ignore */ + if (CPU_MODEL < MODEL_67) { + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + if (CPU_MODEL <= MODEL_V6) { + /* Cache memory control bit assignments for reg */ + /* 0-22 reserved, must be zero */ + /* 23 - Initialize Instruction Cache Bank 0 On = 1 Off = 0 */ + /* 24 - Initialize Instruction Cache Bank 1 On = 1 Off = 0 */ + /* 25 - Initialize Operand Cache Bank 0 On = 1 Off = 0 */ + /* 26 - Initialize Operand Cache Bank 1 On = 1 Off = 0 */ + /* 27 - Enable Instruction Cache Bank 0 On = 1 Off = 0 */ + /* 28 - Enable Instruction Cache Bank 1 On = 1 Off = 0 */ + /* 29 - Enable Operand Cache Bank 0 On = 1 Off = 0 */ + /* 30 - Enable Operand Cache Bank 1 On = 1 Off = 0 */ + /* 31 - Bypass Instruction Cache Bank 1 On = 1 Off = 0 */ + sim_debug(DEBUG_EXP, my_dev, + "CMC V6/67 GPR[%02x] = %04x CMCR = %08x IPU STATUS SPAD[f9] = %08x\r\n", + reg, GPR[reg], CMCR, SPAD[0xf9]); + CMCR = GPR[reg]; /* write reg bits 23-31 to cache memory controller */ + i_flags &= ~SD; /* turn off store dest for this instruction */ + } else + if (CPU_MODEL == MODEL_V9) { + sim_debug(DEBUG_EXP, my_dev, + "CMC V9 GPR[%02x] = %08x CMCR = %08x IPU STATUS SPAD[f9] = %08x\r\n", + reg, GPR[reg], CMCR, SPAD[0xf9]); + CMCR = GPR[reg]; /* write reg bits 23-31 to cache memory controller */ + i_flags &= ~SD; /* turn off store dest for this instruction */ + } + break; + + case 0x7: /* SMC */ /* Shared Memory Control - Diag use only */ + if (CPU_MODEL < MODEL_67) { + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + /* Shared memory control bit assignments for reg */ + /* 0 - Reserved */ + /* 1 - Shared Memory Enabled (=1)/Disabled (=0) */ + /* 2-6 - Upper Bound of Shared Memory */ + /* 7 - Read & Lock Enabled (=1)/Disabled (=0) */ + /* 8-12 - Lower Bound of Shared Memory */ + /* 3-31 - Reserved and must be zero */ + sim_debug(DEBUG_CMD, my_dev, + "SMC V6/67 GPR[%02x] = %08x SMCR = %08x IPU STATUS SPAD[f9] = %08x\n", + reg, GPR[reg], SMCR, SPAD[0xf9]); + SMCR = GPR[reg]; /* write reg bits 0-12 to shared memory controller */ + i_flags &= ~SD; /* turn off store dest for this instruction */ + break; + +/* 67, 97, V6 Computer Configuration Word is copied when bit zero of Rd set to one (0x80000000) */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00|01|02 03 04 05 06|07|08 09 10 11 12|13 14 15|16|17|18|19|20 21|22|23 24 25 26|27|28|29|30|31| */ +/* | | S| Upper Bound |RL| Lower Bound |Reserved|4k|8k|SM|P2| Res |AP| Reserved |I0|I1|D0|D1|BY| */ +/* | 0| x| x x x x x| x| x x x x x| 0 0 0| x| x| x| x| 0 0| 0| 0 0 0 0| x| x| x| x| x| */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ +/* Bits: 0 Reserved */ +/* 1 Shared Memory Enabled (=1)/Disabled (=0) */ +/* 2-6 Upper Bound of Shared Memory */ +/* 7 Read & Lock Enabled (=1)/Disabled (=0) */ +/* 8-12 Lower Bound of Shared Memory */ +/* 13-15 Reserved */ +/* 16 4K WCS Option Present (=1)/Not Present (=0) */ +/* 17 8K WCS Option Present (=1)/Not Present (=0) */ +/* 18 Firmware Control Store Mode ROMSIM (=1)/PROM (=0) */ +/* 19 IPU Present (=1)/Not Present (=0) */ +/* 20-21 Reserved */ +/* 22 Access Protection ECO Present (=0)/No Access Protection (=0) V6 & V9 */ +/* 23-26 Reserved */ +/* 27 Instruction Cache Bank 0 on (=1)/Off (=0) */ +/* 28 Instruction Cache Bank 1 on (=1)/Off (=0) */ +/* 29 Data Cache Bank 0 on (=1)/Off (=0) */ +/* 30 Data Cache Bank 1 on (=1)/Off (=0) */ +/* 31 Instruction Cache Enabled (=1)/Disabled (=0) */ +/* */ +/* V9 Computer Configuration Word when bit zero of Rd set to one (0x80000000) */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02 03|04 05 06 07|08 09 10 11|12 13 14 15|16|17|18|19|20|21|22|23|24 25 26 27|28 29 30 31| */ +/* | CPU Bank1 | CPU Bank2 | IPU Bank0 | IPU Bank1 |M1|M2|C1|C2|P2|SM|AP| | CPU FW Ver| CPU FW Rev| */ +/* | x x x x| x x x x| x x x x| x x x x| x| x| x| x| x| x| x| x| x x x x| x x x x| */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ +/* Bits: 0-15 Cache/Shadow Unit Present (=1)/Not Present (=0) */ +/* 16 MACC Present in CP1 (=1)/Not Present (=0) */ +/* 17 MACC Present in CP2 (=1)/Not Present (=0) */ +/* 18 CP1 Present (=1)/CP1 Not Present (=0) */ +/* 19 CP2 Present (=1)/CP2 Not Present (=0) */ +/* 20 IPU Present (=1)/Not Present (=0) */ +/* 21 Shared Memory Present (=1)/Not Present (=0) */ +/* 22 Access Protection ECO Present (=0)/No Access Protection (=0) V6 & V9 */ +/* 23 Reserved */ +/* 24-27 CPU Firmware Version */ +/* 28-31 CPU Formware Revision Level */ +/* */ +/* V9 CPU Shadow Memory Configuration Word when bit one of Rd set to one (0x40000000) */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02|03 04 05 06 07|08 09 10 11 12 13 14 15|16 17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */ +/* | SMU # | Not Used | CPU Unit 1 Base Addr | CPU Unit 2 Base Addr | CPU Unit 3 Base Addr | */ +/* | x x x| 0 0 0 0 0| x x x x x x x 0| x x x x x x x 0| x x x x x x x 0| */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ +/* Bits: 0 Shadow Memory Unit 1 Present (=1)/Not Present (=0) */ +/* 1 Shadow Memory Unit 2 Present (=1)/Not Present (=0) */ +/* 2 Shadow Memory Unit 3 Present (=1)/Not Present (=0) */ +/* 3-7 Not Used */ +/* 8-14 Shadow Memory Unit 1 Base Address (bits 08-14 of address) */ +/* 15 Always zero */ +/* 16-22 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */ +/* 23 Always zero */ +/* 24-30 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */ +/* 31 Always zero */ +/* */ +/* V9 IPU Shadow Memory Configuration Word when bit two of Rd set to one (0x20000000) */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02|03 04 05 06 07|08 09 10 11 12 13 14 15|16 17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */ +/* | SMU # | Not Used | IPU Unit 1 Base Addr | IPU Unit 2 Base Addr | IPU Unit 3 Base Addr | */ +/* | x x x| 0 0 0 0 0| x x x x x x x 0| x x x x x x x 0| x x x x x x x 0| */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ +/* Bits: 0 Shadow Memory Unit 1 Present (=1)/Not Present (=0) */ +/* 1 Shadow Memory Unit 2 Present (=1)/Not Present (=0) */ +/* 2 Shadow Memory Unit 3 Present (=1)/Not Present (=0) */ +/* 3-7 Not Used */ +/* 8-14 Shadow Memory Unit 1 Base Address (bits 08-14 of address) */ +/* 15 Always zero */ +/* 16-22 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */ +/* 23 Always zero */ +/* 24-30 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */ +/* 31 Always zero */ +/* */ +/* When bit zero of Rd is zero, PSW word 2 is copies to Rd (0x00000000) */ +/* */ + case 0xB: /* RPSWT */ /* Read Processor Status Word 2 (PSD2) */ + if ((GPR[reg] & 0x80000000) && (CPU_MODEL < MODEL_V9)) { + /* if bit 0 of reg set, return (default 0) CPU Configuration Word */ + dest = CCW; /* no cache or shared memory */ + /* bit 22 set for access ECO present */ + dest |= 0x00000200; /* set ECO bit for DIAGS */ + /* Try setting cache on bits 27-31 */ + dest |= 0x0000001f; /* set SIM bit for DIAGS */ + } else + /* FIXME */ + if ((GPR[reg] & 0x80000000) && (CPU_MODEL == MODEL_V9)) { + /* if bit 0 of reg set, return Cache/Shadow Configuration Word */ + CMSMC = 0xffff0000; /* no CPU/IPU Cache/Shadow unit present */ + CMSMC |= 0x00000000; /* IPU Cache/Shadow unit present */ + if (CCW & BIT27) + /* IPU is present, reset the status bit */ + dest &= ~BIT20; /* reset IPU status bit */ + else + /* IPU is not present, set the status bit */ + CMSMC |= BIT20; /* set IPU status bit */ +// CMSMC |= 0x00000800; /* bit 20, IPU not present */ + CMSMC |= 0x00000200; /* bit 22, Access Protection ECO present */ + CMSMC |= 0x0000001f; /* CPU Firmware Version 1/Rev level 0 */ + dest = CMSMC; /* return status */ + } else + if ((GPR[reg] & 0x40000000) && (CPU_MODEL == MODEL_V9)) { + /* if bit 1 of reg set, return CPU Shadow Memory Configuration Word */ + CSMCW = 0x00000000; /* no Shadow unit present */ + dest = CSMCW; /* return status */ + } else + if ((GPR[reg] & 0x20000000) && (CPU_MODEL == MODEL_V9)) { + /* if bit 2 of reg set, return Cache Memory Configuration Word */ + ISMCW = 0x00000000; /* no Shadow unit present */ + dest = ISMCW; /* return status */ + } else + if ((GPR[reg] & BIT0) == 0x00000000) { + /* if bit 0 of reg not set, return PSD2 */ + /* make sure bit 49 (block state is current state */ + dest = SPAD[0xf5]; /* get PSD2 for user from SPAD 0xf5 */ + dest &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ + if (IPUSTATUS & BIT24) { /* see if old mode is blocked */ + dest |= SETBBIT; /* set bit 49 for blocked */ + } + } + break; + + case 0x08: /* 0x0408 INV (Diag Illegal instruction) */ + /* HACK HACK HACK for DIAGS */ + if (CPU_MODEL <= MODEL_27) { /* DIAG error for 32/27 only */ + if ((PSD1 & 2) == 0) /* if lf hw instruction */ + i_flags |= HLF; /* if nop in rt hw, bump pc a word */ + } + /* drop through */ + default: /* INV */ /* everything else is invalid instruction */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + break; + } + break; + + case 0x08>>2: /* 0x08 SCC|RR|R1|SD|HLF - */ /* ORR or ORRM */ + dest |= source; /* or the regs into dest reg */ + switch(OPR & 0x0f) { + case 0x8: /* this is ORRM op */ + dest &= GPR[4]; /* mask with reg 4 contents */ + /* drop thru */ + case 0x0: /* this is ORR op */ + if (dest & MSIGN) /* see if we need to sign extend */ + dest |= D32LMASK; /* force upper word to all ones */ + break; + default: /* INV */ /* everything else is invalid instruction */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + break; + + case 0x0C>>2: /* 0x0c SCC|RR|R1|SD|HLF - SCC|SD|HLF */ /* EOR or EORM */ + dest ^= source; /* exclusive or the regs into dest reg */ + switch(OPR & 0x0f) { + case 0x8: /* this is EORM op */ + dest &= GPR[4]; /* mask with reg 4 contents */ + /* drop thru */ + case 0x0: /* this is EOR op */ + if (dest & MSIGN) /* see if we need to sign extend */ + dest |= D32LMASK; /* force upper word to all ones */ + break; + default: /* INV */ /* everything else is invalid instruction */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + break; + + case 0x10>>2: /* 0x10 HLF - HLF */ /* CAR or (basemode SACZ ) */ + if ((OPR & 0xF) == 0) { /* see if CAR instruction */ + /* handle non basemode/basemode CAR instr */ + if ((int32)GPR[reg] < (int32)GPR[sreg]) + CC = CC3BIT; /* Rd < Rs; negative */ + else + if (GPR[reg] == GPR[sreg]) + CC = CC4BIT; /* Rd == Rs; zero */ + else + CC = CC2BIT; /* Rd > Rs; positive */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + } else { + if ((MODES & BASEBIT) == 0) { /* if not basemode, error */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + } + /* handle basemode SACZ instruction */ +sacz: /* non basemode SCZ enters here */ + temp = GPR[reg]; /* get destination reg contents to shift */ + CC = 0; /* zero the CC's */ + t = 0; /* start with zero shift count */ + if (temp == 0) { + CC = CC4BIT; /* set CC4 showing dest is zero & cnt is zero too */ + } +#ifdef NOT_FOR_DIAG + /* The doc says the reg is not shifted if bit 0 is set on entry. */ + /* diags says it does, so that is what we will do */ + /* set count to zero, but shift reg 1 left */ + else + if (temp & BIT0) { + CC = 0; /* clear CC4 & set count to zero */ + } +#endif + else + if (temp != 0) { /* shift non zero values */ + while ((temp & FSIGN) == 0) { /* shift the reg until bit 0 is set */ + temp <<= 1; /* shift left 1 bit */ + t++; /* increment shift count */ + } + temp <<= 1; /* shift the sign bit out */ + } + GPR[reg] = temp; /* save the shifted values */ + GPR[sreg] = t; /* set the shift cnt into the src reg */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + } + break; + + case 0x14>>2: /* 0x14 HLF - HLF */ /* CMR compare masked with reg */ + if (OPR & 0xf) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + temp = GPR[reg] ^ GPR[sreg]; /* exclusive or src and destination values */ + temp &= GPR[4]; /* and with mask reg (GPR 4) */ + CC = 0; /* set all CCs zero */ + if (temp == 0) /* if result is zero, set CC4 */ + CC = CC4BIT; /* set CC4 to show result 0 */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + break; + + case 0x18>>2: /* 0x18 HLF - HLF */ /* SBR, (basemode ZBR, ABR, TBR */ + if (MODES & BASEBIT) { /* handle basemode ZBR, ABR, TBR */ + if ((OPR & 0xC) == 0x0) /* SBR instruction */ + goto sbr; /* use nonbase SBR code */ + if ((OPR & 0xC) == 0x4) /* ZBR instruction */ + goto zbr; /* use nonbase ZBR code */ + if ((OPR & 0xC) == 0x8) /* ABR instruction */ + goto abr; /* use nonbase ABR code */ + if ((OPR & 0xC) == 0xC) /* TBR instruction */ + goto tbr; /* use nonbase TBR code */ +inv: + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + + } else { /* handle non basemode SBR */ + if (OPR & 0xc) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } +sbr: /* handle basemode too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((OPR << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (GPR[sreg] & bc) /* test the bit in src reg */ + t |= CC1BIT; /* set CC1 to the bit value */ + GPR[sreg] |= bc; /* set the bit in src reg */ + PSD1 |= t; /* update the CC's in the PSD */ + } + break; + + case 0x1C>>2: /* 0x1C HLF - HLF */ /* ZBR (basemode SRA, SRL, SLA, SLL) */ + if (MODES & BASEBIT) { /* handle basemode SRA, SRL, SLA, SLL */ + bc = OPR & 0x1f; /* get bit shift count */ + if ((OPR & 0x60) == 0x00) { /* SRA instruction */ + temp = GPR[reg]; /* get reg value to shift */ + t = temp & FSIGN; /* sign value */ + for (ix=0; ix>= 1; /* shift bit 0 right one bit */ + temp |= t; /* restore original sign bit */ + } + GPR[reg] = temp; /* save the new value */ + break; + } + if ((OPR & 0x60) == 0x20) { /* SRL instruction */ + GPR[reg] >>= bc; /* value to be output */ + break; + } + if ((OPR & 0x60) == 0x40) { /* SLA instruction */ + temp = GPR[reg]; /* get reg value to shift */ + t = temp & FSIGN; /* sign value */ + ovr = 0; /* set ovr off */ + for (ix=0; ix> bc; /* make a bit mask of bit number */ + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (GPR[sreg] & bc) /* test the bit in src reg */ + t |= CC1BIT; /* set CC1 to the bit value */ + GPR[sreg] &= ~bc; /* reset the bit in src reg */ + PSD1 |= t; /* update the CC's in the PSD */ + } + break; + + case 0x20>>2: /* 0x20 HLF - HLF */ /* ABR (basemode SRAD, SRLD, SLAD, SLLD) */ + if (MODES & BASEBIT) { /* handle basemode SRAD, SRLD, SLAD, SLLD */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7e OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ + dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + bc = OPR & 0x1f; /* get bit shift count */ + source = dest & DMSIGN; /* 64 bit sign value */ + switch (OPR & 0x60) { + case 0x00: /* SRAD instruction */ + for (ix=0; ix>= 1; /* shift bit 0 right one bit */ + dest |= source; /* restore original sign bit */ + } + break; + + case 0x20: /* SRLD */ + dest >>= bc; /* shift right #bits */ + break; + + case 0x40: /* SLAD instruction */ + ovr = 0; /* set ovr off */ + for (ix=0; ix>32) & FMASK);/* save the hi order reg */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (ovr) + PSD1 |= BIT1; /* CC1 in PSD */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* go execute the trap now */ + } + break; + + case 0x60: /* SLLD */ + dest <<= bc; /* shift left #bits */ + break; + } + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + } else { /* handle nonbase mode ABR */ + if (OPR & 0xc) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } +abr: /* basemode ABR too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((OPR << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + temp = GPR[sreg]; /* get reg value to add bit to */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((bc & FSIGN) != 0) ? 2 : 0; /* ditto for the bit value */ + temp += bc; /* add the bit value to the reg */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) { + ovr = 1; /* we have an overflow */ + } + GPR[sreg] = temp; /* save the new value */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* handle trap */ + } + } + break; + + case 0x24>>2: /* 0x24 HLF - HLF */ /* TBR (basemode SRC) */ + if (MODES & BASEBIT) { /* handle SRC basemode */ + bc = OPR & 0x1f; /* get bit shift count */ + temp = GPR[reg]; /* get reg value to shift */ + if ((OPR & 0x60) == 0x40) { /* SLCBR instruction */ + for (ix=0; ix>= 1; /* shift the bit out */ + if (t) + temp |= BIT0; /* put in new sign bit */ + } + } + GPR[reg] = temp; /* shift result */ + } else { /* handle TBR non basemode */ + if (OPR & 0xc) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } +tbr: /* handle basemode TBR too */ + /* move the byte field bits 14-15 to bits 27-28 */ + /* or in the bit# from dest reg field bits 6-8 into bit 29-31 */ + bc = (((OPR << 3) & 0x18) | reg); /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (GPR[sreg] & bc) /* test the bit in src reg */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ + } + break; + + case 0x28>>2: /* 0x28 HLF - HLF */ /* Misc OP REG instructions */ + switch(OPR & 0xF) { + case 0x0: /* TRSW */ + if (MODES & BASEBIT) + temp = 0x78FFFFFE; /* bits 1-4 and 24 bit addr for based mode */ + else + temp = 0x7807FFFE; /* bits 1-4 and 19 bit addr for non based mode */ + addr = GPR[reg]; /* get reg value */ + /* we are returning to the addr in reg, set CC's from reg */ + /* update the PSD with new address from reg */ + PSD1 &= ~temp; /* clean the bits to be changed */ + PSD1 |= (addr & temp); /* insert the CC's and address */ + sim_debug(DEBUG_DETAIL, my_dev, + "TRSW REG %01x PSD %08x %08x modes %08x temp %06x\n", + reg, PSD1, PSD2, MODES, temp); + i_flags |= BT; /* we branched, so no PC update */ + break; + + case 0x2: /* XCBR */ /* Exchange base registers */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + temp = BR[reg]; /* get dest reg value */ + BR[reg] = BR[sreg]; /* put source reg value int dest reg */ + BR[sreg] = temp; /* put dest reg value into src reg */ + break; + + case 0x4: /* TCCR */ /* Transfer condition codes to GPR bits 28-31 */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + temp = CC >> 27; /* right justify CC's in reg */ + GPR[reg] = temp; /* put dest reg value into src reg */ + break; + + case 0x5: /* TRCC */ /* Transfer GPR bits 28-31 to condition codes */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + PSD1 = ((PSD1 & 0x87fffffe)|((GPR[reg] & 0xf) << 27)); /* insert CCs from reg */ + break; + + case 0x8: /* BSUB */ /* Procedure call */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + + /* if Rd field is 0 (reg is b6-b8), this is a BSUB instruction */ + /* otherwise it is a CALL instruction (Rd != 0) */ + if (reg == 0) { + /* BSUB instruction */ + uint32 cfp = BR[2]; /* get dword bounded frame pointer from BR2 */ + if ((BR[2] & 0x7) != 0) { + /* Fault, must be dw bounded address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7f OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + cfp = BR[2] & 0x00fffff8; /* clean the cfp address to 24 bit dw */ + + M[cfp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC into frame */ + M[(cfp>>2)+1] = 0x80000000; /* show frame created by BSUB instr */ + BR[1] = BR[sreg] & MASK24; /* Rs reg to BR 1 */ + PSD1 = (PSD1 & 0xff000000) | (BR[1] & MASK24); /* New PSD address */ + BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */ + BR[0] = cfp; /* set frame pointer from BR 2 into BR 0 */ + i_flags |= BT; /* we changed the PC, so no PC update */ + } else + { + /* CALL instruction */ + /* get frame pointer from BR2-16 words & make it a dword addr */ + uint32 cfp = ((BR[2]-0x40) & 0x00fffff8); + + /* if cfp and cfp+15w are in different maps, then addr exception error */ + if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC7g OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + + temp = (PSD1+2) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */ + if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */ + goto newpsd; /* memory write error or map fault */ + } + + temp = 0x00000000; /* show frame created by CALL instr */ + if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */ + goto newpsd; /* memory write error or map fault */ + } + + /* Save BR 0-7 to stack */ + for (ix=0; ix<8; ix++) { + if ((TRAPME = Mem_write(cfp+(4*ix)+8, &BR[ix]))) { /* Save into memory */ + goto newpsd; /* memory write error or map fault */ + } + } + + /* save GPR 2-8 to stack */ + for (ix=2; ix<8; ix++) { + if ((TRAPME = Mem_write(cfp+(4*ix)+32, &GPR[ix]))) { /* Save into memory */ + goto newpsd; /* memory write error or map fault */ + } + } + + /* keep bits 0-7 from old PSD */ + PSD1 = (PSD1 & 0xff000000) | ((BR[sreg]) & MASK24); /* New PSD address */ + BR[1] = BR[sreg]; /* Rs reg to BR 1 */ + BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */ + BR[0] = cfp; /* set current frame pointer into BR[0] */ + BR[2] = cfp; /* set current frame pointer into BR[2] */ + i_flags |= BT; /* we changed the PC, so no PC update */ + } + break; + + case 0xC: /* TPCBR */ /* Transfer program Counter to Base Register */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + BR[reg] = PSD1 & 0xfffffe; /* save PC from PSD1 into BR */ + break; + + case 0xE: /* RETURN */ /* procedure return for basemode calls */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + t = BR[0]; /* get frame pointer from BR[0] */ + if ((TRAPME = Mem_read(t+4, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + /* if Bit0 set, restore all saved regs, else restore only BRs */ + if ((temp & BIT0) == 0) { /* see if GPRs are to be restored */ + /* Bit 0 is not set, so restore all GPRs */ + for (ix=2; ix<8; ix++) + if ((TRAPME = Mem_read(t+ix*4+32, &GPR[ix]))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + for (ix=0; ix<8; ix++) { + if ((TRAPME = Mem_read(t+ix*4+8, &BR[ix]))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + PSD1 &= ~0x1fffffe; /* leave everything except AEXP bit and PC */ + if ((TRAPME = Mem_read(t, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + PSD1 |= (temp & 0x01fffffe); /* restore AEXP bit and PC from call frame */ + i_flags |= BT; /* we changed the PC, so no PC update */ + break; + + case 0x1: /* INV */ + case 0x3: /* INV */ + case 0x6: /* INV */ + case 0x7: /* INV */ + case 0x9: /* INV */ + case 0xA: /* INV */ + case 0xB: /* INV */ + case 0xD: /* INV */ + case 0xF: /* INV */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + break; + } + break; + + case 0x2C>>2: /* 0x2C HLF - HLF */ /* Reg-Reg instructions */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + bc = 0; + + switch(OPR & 0xF) { + case 0x0: /* TRR */ /* SCC|SD|R1 */ + temp = addr; /* set value to go to GPR[reg] */ + bc = 1; /* set CC's at end */ + break; + + case 0x1: /* TRBR */ /* Transfer GPR to BR */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + BR[reg] = GPR[sreg]; /* copy GPR to BR */ + break; + + case 0x2: /* TBRR */ /* transfer BR to GPR */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + temp = BR[sreg]; /* set base reg value */ + bc = 1; /* set CC's at end */ + break; + + case 0x3: /* TRC */ /* Transfer register complement */ + temp = addr ^ FMASK; /* complement Rs */ + bc = 1; /* set CC's at end */ + break; + + case 0x4: /* TRN */ /* Transfer register negative */ + temp = NEGATE32(addr); /* negate Rs value */ + if (temp == addr) /* overflow if nothing changed */ + ovr = 1; /* set overflow flag */ + /* reset ovr if val == 0, not set for DIAGS */ + if ((temp == 0) & ovr) + ovr = 0; + bc = 1; /* set the CC's */ + break; + + case 0x5: /* XCR */ /* exchange registers Rd & Rs */ + GPR[sreg] = temp; /* Rd to Rs */ + set_CCs(temp, ovr); /* set the CC's from original Rd */ + temp = addr; /* save the Rs value to Rd reg */ + break; + + case 0x6: /* INV */ + goto inv; + break; + + case 0x7: /* LMAP */ /* Load map reg - Diags only */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + /* ipu must be unmapped */ + if (MODES & MAPMODE) { /* must be unmapped ipu */ + TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT8; /* set bit 8 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + { /* load the ipu maps using diag psd */ + uint32 DPSD[2]; /* the PC for the instruction */ + /* get PSD pointed to by real addr in Rd (temp) */ + DPSD[0] = RMW(temp); /* get word one of psd */ + DPSD[1] = RMW(temp+4); /* get word two of psd */ + sim_debug(DEBUG_CMD, my_dev, + "LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp %06x\n", + PSD1, PSD2, DPSD[0], DPSD[1], MODES, temp); + if ((DPSD[1] & MAPBIT) == 0) /* if PSD2 is unmapped, treat as NOP */ + goto skipit; + if (PSD2 & RETMBIT) /* don't load maps if retain bit set */ + goto skipit; + temp2 = MODES; /* save modes bits through load_maps call */ + MODES = DPSD[0] & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + MODES |= MAPMODE; /* set mapped mode flag for load_maps call */ + sim_debug(DEBUG_CMD, my_dev, + "LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp2 %08x\n", + PSD1, PSD2, DPSD[0], DPSD[1], MODES, temp2); + /* we need to load the new maps */ + TRAPME = load_maps(DPSD, 1); /* load maps for new PSD */ + sim_debug(DEBUG_CMD, my_dev, + "LMAP TRAPME %02x MAPC[8-c] %08x %08x %08x %08x %08x %08x\n", + TRAPME, MAPC[7], MAPC[8], MAPC[9], MAPC[10], MAPC[11], MAPC[12]); + MODES = temp2; /* restore modes flags */ + if (TRAPME) { + /* DIAGS wants the cpix for the psd to be the requested one */ + PSD2 = (PSD2 & 0xffffc000) | (DPSD[1] & 0x3ff8); + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + goto newpsd; /* handle trap */ + } + goto skipit; + break; + } + break; + + case 0x8: /* TRRM */ /* SCC|SD|R1 */ + temp = addr & GPR[4]; /* transfer reg-reg masked */ + bc = 1; /* set CC's at end */ + break; + + /* CPUSTATUS bits */ + /* Bits 0-19 reserved */ + /* Bit 20 =0 Write to writable control store is disabled */ + /* =1 Write to writable control store is enabled */ + /* Bit 21 =0 Enable PROM mode */ + /* =1 Enable Alterable Control Store Mode */ + /* Bit 22 =0 Enable High Speed Floating Point Accelerator */ + /* =1 Disable High Speed Floating Point Accelerator */ + /* Bit 23 =0 Disable privileged mode halt trap */ + /* =1 Enable privileged mode halt trap */ + /* Bit 24 is reserved */ + /* bit 25 =0 Disable software trap handling (enable automatic trap handling) */ + /* =1 Enable software trap handling */ + /* Bits 26-31 reserved */ + case 0x9: /* SETCPU */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + temp2 = IPUSTATUS; /* save original */ + /* bits 20-23 and bit 25 can change */ + IPUSTATUS &= 0xfffff0bf; /* zero bits that can change */ + IPUSTATUS |= (temp & 0x0f40); /* or in the new status bits */ + IPUSTATUS |= BIT22; /* HS Floating is set to off */ + /* make sure WCS is off and prom mode set to 0 (on) */ + IPUSTATUS &= ~(BIT20|BIT21); /* make zero */ + sim_debug(DEBUG_CMD, my_dev, + "SETIPU orig %08x user bits %08x New IPUSTATUS %08x SPAD[f9] %08x\n", + temp2, temp, IPUSTATUS, SPAD[0xf9]); + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + break; + + case 0xA: /* TMAPR */ /* Transfer map to Reg - Diags only */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + if (CPU_MODEL <= MODEL_27) { /* 7X & 27 must be unmapped */ + if (MODES & MAPMODE) { /* must be unmapped ipu */ + TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */ + goto newpsd; /* handle trap */ + } + } + /* Rs has map number for even/odd pair loading */ + if (CPU_MODEL < MODEL_27) { + /* 32/77 with 32 map regs */ + addr &= 0x1e; /* make 0-15 */ + temp = MAPC[addr>>1]; /* get even/odd maps */ + } else + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) { + /* 32/27 & 32/87 have 256 maps */ + addr &= 0xfe; /* make 0-255 */ + temp = MAPC[addr>>1]; /* get even/odd maps */ + } else { + /* 32/67, 32/97, V6 & V9 have 2048 maps demand paging */ + addr &= 0x7ff; /* make 0-2047 */ + temp = MAPC[addr>>1]; /* get even/odd maps */ + if ((addr & 1) == 0) /* if even reg, use left hw */ + temp >>= 16; /* move over reg value */ + temp &= 0xffff; /* just 16 bits */ + if (TLB[addr] & 0x04000000) /* see if HIT bit set */ + temp |= 0x80000000; /* show hit BIT is set */ + temp |= ((TLB[addr] & 0xf8000000) >> 16); /* add in protect bits */ + if ((addr < 0x26) || (addr > 0x7f8)) + sim_debug(DEBUG_CMD, my_dev, + "TMAPR #%4x val %08x TLB %08x RMR %04x MAPC %08x\n", + addr, temp, TLB[addr], RMR(addr<<1), MAPC[addr/2]); + } + GPR[reg] = temp; /* save the temp value to Rd reg */ + goto skipit; + break; + + case 0xB: /* TRCM */ /* Transfer register complemented masked */ + temp = (addr ^ FMASK) & GPR[4]; /* compliment & mask */ + bc = 1; /* set the CC's */ + break; + + case 0xC: /* TRNM */ /* Transfer register negative masked */ + temp = NEGATE32(addr); /* complement GPR[reg] */ + if (temp == addr) /* check for overflow */ + ovr = 1; /* overflow */ + /* reset ovr if val == 0, not set for DIAGS */ + if ((temp == 0) & ovr) + ovr = 0; + temp &= GPR[4]; /* and with negative reg */ + bc = 1; /* set the CC's */ + break; + + case 0xD: /* XCRM */ /* Exchange registers masked */ + addr &= GPR[4]; /* and Rs with mask reg */ + temp &= GPR[4]; /* and Rd with mask reg */ + GPR[sreg] = temp; /* Rs to get Rd masked value */ + set_CCs(temp, ovr); /* set the CC's from original Rd */ + temp = addr; /* save the Rs value to Rd reg */ + break; + + case 0xE: /* TRSC */ /* transfer reg to SPAD */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + t = (GPR[reg] >> 16) & 0xff; /* get SPAD address from Rd (6-8) */ + temp2 = SPAD[t]; /* get old SPAD data */ + SPAD[t] = GPR[sreg]; /* store Rs into SPAD */ +// sim_debug(DEBUG_TRAP, my_dev, +// "TRSC SPAD[%04x] B4 %08x New %08x\n", t, temp2, GPR[sreg]); + break; + + case 0xF: /* TSCR */ /* Transfer scratchpad to register */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* handle trap */ + } + t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (9-11) */ + temp = SPAD[t]; /* get SPAD data into Rd (6-8) */ +// sim_debug(DEBUG_TRAP, my_dev, +// "TSCR SPAD[%04x] Val %08x\n", t, temp); + break; + } + GPR[reg] = temp; /* save the temp value to Rd reg */ + if (bc) /* set cc's if bc set */ + set_CCs(temp, ovr); /* set the CC's */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* handle trap */ + } +skipit: + /* for retain, leave PSD2 alone */ + break; + + case 0x30>>2: /* 0x30 */ /* CALM */ + /* Process CALM for 32/27 when in left hw, else invalid */ + if ((CPU_MODEL <= MODEL_87) && (CPU_MODEL != MODEL_67)) { +// uint32 oldstatus = IPUSTATUS; /* keep for retain blocking state */ + /* DIAG error for 32/27 or 32/87 only */ + if ((PSD1 & 2) != 0) /* is it lf hw instruction */ + goto inv; /* invalid instr if in rt hw */ + addr = SPAD[0xf0]; /* get trap table memory address from SPAD (def 80) */ + if ((addr == 0) || ((addr&MASK24) == MASK24)) { /* see if secondary vector table set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + goto newpsd; /* program error */ + } + addr = addr + (0x0A << 2); /* addr has mem addr of CALM trap vector (def A8) */ + t = M[addr >> 2]; /* get the ICB address from memory */ + if ((t == 0) || ((t&MASK24) == MASK24)) { /* see if ICB set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + goto newpsd; /* program error */ + } + bc = PSD2 & 0x3ff8; /* get copy of cpix */ + /* this will skip over rt hw instruction if any */ + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); /* bump pc by 1 wd */ + M[t>>2] = PSD1 & 0xfffffffe; /* store PSD 1 + 1HW to point to next instruction */ + M[(t>>2)+1] = PSD2; /* store PSD 2 */ + TPSD1 = PSD1; /* save old PSD1 */ + TPSD2 = PSD2; /* save old PSD2 */ + PSD1 = M[(t>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(t>>2)+3] & ~0x3fff) | bc; /* get new PSD 2 w/old cpix */ + M[(t>>2)+4] = OPR & 0x03FF; /* store calm number in bits 6-15 */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + sim_debug(DEBUG_IRQ, my_dev, + "CALM @ %.6x NPSD %08x %04x OPSD %08x %04x SPAD %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, SPAD[0xf5], IPUSTATUS); + + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + IPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + IPUSTATUS &= ~BIT24; /* reset block state in ipu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ + } + + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + IPUSTATUS &= ~0x87000000; /* reset bits in IPUSTATUS */ + IPUSTATUS |= (MODES & 0x87000000); /* now insert into IPUSTATUS */ + + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + TRAPME = 0; /* not to be processed as trap */ + drop_nop = 0; /* nothing to drop */ + i_flags |= BT; /* do not update pc */ + } else { +// fprintf(stderr, "got CALM trap\r\n"); + goto inv; /* invalid instr */ + } + break; + + case 0x34>>2: /* 0x34 SD|ADR - inv */ /* LA non-basemode */ + if (MODES & BASEBIT) /* see if based */ + goto inv; /* invalid instruction in based mode */ + if (MODES & EXTDBIT) { /* see if extended mode */ + dest = (t_uint64)(addr&MASK24); /* just pure 24 bit address */ + } else { /* use bits 13-31 */ + dest = (t_uint64)((addr&0x7ffff) | ((FC & 4) << 17)); /* F bit to bit 12 */ + } + break; + + case 0x38>>2: /* 0x38 HLF - HLF */ /* REG - REG floating point */ + switch(OPR & 0xF) { + case 0x0: /* ADR */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || (t == 0 && (temp & FSIGN) != 0)) { + ovr = 1; /* we have an overflow */ + } + i_flags |= SF; /* special processing */ + break; + + case 0x1: /* ADRFW */ + case 0x3: /* SURFW */ + /* TODO not on 32/27 */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */ + if ((OPR & 0xF) == 0x3) { + addr = NEGATE32(addr); /* subtract, so negate source */ + } + temp2 = s_adfw(temp, addr, &CC); /* do ADFW */ + sim_debug(DEBUG_DETAIL, my_dev, + "%s GPR[%d] %08x addr %08x result %08x CC %08x\n", + (OPR&0xf)==3 ? "SURFW":"ADRFW", + reg, GPR[reg], GPR[sreg], temp2, CC); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg] = temp2; /* dest - reg contents specified by Rd */ + break; + + case 0x2: /* MPRBR */ + /* TODO not on 32/27 */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if (reg & 1) { + /* Spec fault if not even reg */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + temp = GPR[reg+1]; /* get multiplicand */ + addr = GPR[sreg]; /* multiplier */ + + /* change value into a 64 bit value */ + dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); + source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0); + dest = dest * source; /* do the multiply */ + i_flags |= (SD|SCC); /* save dest reg and set CC's */ + dbl = 1; /* double reg save */ + break; + + case 0x4: /* DVRFW */ + /* TODO not on 32/27 */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */ + temp2 = (uint32)s_dvfw(temp, addr, &CC); /* divide reg by sreg */ + sim_debug(DEBUG_DETAIL, my_dev, + "DVRFW GPR[%d] %08x src %08x result %08x\n", + reg, GPR[reg], addr, temp2); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg] = temp2; /* dest - reg contents specified by Rd */ + break; + + case 0x5: /* FIXW */ + /* TODO not on 32/27 */ + /* convert from 32 bit float to 32 bit fixed */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + temp2 = s_fixw(addr, &CC); /* do conversion */ + sim_debug(DEBUG_DETAIL, my_dev, + "FIXW GPR[%d] %08x result %08x\n", + sreg, GPR[sreg], temp2); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg] = temp2; /* dest - reg contents specified by Rd */ + break; /* go set CC's */ + + case 0x6: /* MPRFW */ + /* TODO not on 32/27 */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + /* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */ + temp2 = s_mpfw(temp, addr, &CC); /* mult reg by sreg */ + sim_debug(DEBUG_DETAIL, my_dev, + "MPRFW GPR[%d] %08x src %08x result %08x\n", + reg, GPR[reg], addr, temp2); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg] = temp2; /* dest - reg contents specified by Rd */ + break; + + case 0x7: /* FLTW */ + /* TODO not on 32/27 */ + /* convert from 32 bit integer to 32 bit float */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + GPR[reg] = s_fltw(addr, &CC); /* do conversion & set CC's */ + sim_debug(DEBUG_DETAIL, my_dev, + "FLTW GPR[%d] %08x result %08x\n", + sreg, GPR[sreg], GPR[reg]); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + break; + + case 0x8: /* ADRM */ + temp = GPR[reg]; /* reg contents specified by Rd */ + addr = GPR[sreg]; /* reg contents specified by Rs */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + temp &= GPR[4]; /* mask the destination reg */ + i_flags |= SF; /* special processing */ + break; + + case 0x9: /* ADRFD */ + case 0xB: /* SURFD */ + /* TODO not on 32/27 */ + if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ + source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ + if ((OPR & 0xF) == 0xb) { + source = NEGATE32(source); /* make negative for subtract */ + } + dest = s_adfd(td, source, &CC); /* do ADFD */ + + sim_debug(DEBUG_DETAIL, my_dev, + "%s GPR[%d] %08x %08x src %016llx result %016llx\n", + (OPR&0xf)==8 ? "ADRFD":"SURFD", reg, GPR[reg], GPR[reg+1], source, dest); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0xA: /* DVRBR */ + /* TODO not on 32/27 */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if (reg & 1) { + /* Spec fault if not even reg */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* get Rs divisor value */ + source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0); + /* merge the dividend regs into the 64bit value */ + dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]); + if (source == 0) { + goto doovr4; + break; + } + td = (t_int64)dest % (t_int64)source; /* remainder */ + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = NEGATE32(td); /* dividend and remainder must be same sign */ + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ + /* test for overflow */ + if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { +doovr4: + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + /* the original regs must be returned unchanged if aexp */ + set_CCs(temp, ovr); /* set the CC's */ + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ + } + break; + + case 0xC: /* DVRFD */ + /* TODO not on 32/27 */ + if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ + source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ + dest = s_dvfd(td, source, &CC); /* divide double values */ + sim_debug(DEBUG_DETAIL, my_dev, + "DVRFD GPR[%d] %08x %08x src %016llx result %016llx\n", + reg, GPR[reg], GPR[reg+1], source, dest); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0xD: /* FIXD */ + /* dest - reg contents specified by Rd & Rd+1 */ + /* source - reg contents specified by Rs & Rs+1 */ + if (sreg & 1) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + /* merge the sregs into the 64bit value */ + source = (((t_uint64)GPR[sreg]) << 32) | ((t_uint64)GPR[sreg+1]); + /* convert from 64 bit double to 64 bit int */ + dest = s_fixd(source, &CC); + sim_debug(DEBUG_DETAIL, my_dev, + "FIXD GPR[%d] %08x %08x result %016llx\n", + sreg, GPR[sreg], GPR[sreg+1], dest); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0xE: /* MPRFD */ + /* TODO not on 32/27 */ + if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ + source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ + dest = s_mpfd(td, source, &CC); /* multiply double values */ + sim_debug(DEBUG_DETAIL, my_dev, + "MPRFD GPR[%d] %08x %08x src %016llx result %016llx\n", + reg, GPR[reg], GPR[reg+1], source, dest); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + if (CC & CC1BIT) { /* check for arithmetic exception */ + ovr = 1; /* exception */ + /* leave Rd & Rs unchanged if AEXPBIT is set */ + if (MODES & AEXPBIT) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + } + /* AEXPBIT not set, so save the fixed return value */ + /* return result to destination reg */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0xF: /* FLTD */ + /* TODO not on 32/27 */ + /* convert from 64 bit integer to 64 bit float */ + if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */ + source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */ + dest = s_fltd(source, &CC); /* do conversion & set CC's */ + sim_debug(DEBUG_DETAIL, my_dev, + "FLTD GPR[%d] %08x %08x result %016llx\n", + sreg, GPR[sreg], GPR[sreg+1], dest); + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + } + if (i_flags & SF) { /* see if special processing */ + GPR[reg] = temp; /* temp has destination reg value */ + set_CCs(temp, ovr); /* set the CC's */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* go execute the trap now */ + } + } + break; + + case 0x3C>>2: /* 0x3C HLF - HLF */ /* SUR and SURM */ + temp = GPR[reg]; /* get negative value to add */ + temp2 = GPR[sreg]; /* get negative value to add */ + addr = NEGATE32(GPR[sreg]); /* reg contents specified by Rs */ + switch(OPR & 0xF) { + case 0x0: /* SUR */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + if (addr == FSIGN) + ovr = 1; /* we have an overflow */ + break; + + case 0x8: /* SURM */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */ + temp = temp + addr; /* add the values */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + temp &= GPR[4]; /* mask the destination reg */ + if (addr == FSIGN) + ovr = 1; /* we have an overflow */ + break; + default: + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + break; + } + GPR[reg] = temp; /* save the result */ + set_CCs(temp, ovr); /* set CCs for result */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* go execute the trap now */ + } + break; + + case 0x40>>2: /* 0x40 SCC|SD|HLF - INV */ /* MPR */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction in basemode */ + if (reg & 1) { /* odd reg specified? */ + /* Spec fault */ + /* HACK HACK HACK for DIAGS */ + if (CPU_MODEL <= MODEL_27) { /* DIAG error for 32/27 only */ + if ((PSD1 & 2) == 0) /* if lf hw instruction */ + i_flags &= ~HLF; /* if nop in rt hw, bump pc a word */ + else + PSD1 &= ~3; /* fake out 32/27 diag error */ + } + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (OPR & 0xf) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + temp = GPR[reg+1]; /* get multiplicand */ + addr = GPR[sreg]; /* multiplier */ + + /* change immediate value into a 64 bit value */ + dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); + source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0); + dest = dest * source; /* do the multiply */ + dbl = 1; /* double reg save */ + break; + + case 0x44>>2: /* 0x44 ADR - ADR */ /* DVR */ + /* sreg has Rs */ + if (reg & 1) { + /* Spec fault */ + /* HACK HACK HACK for DIAGS */ + if (CPU_MODEL <= MODEL_27) { /* DIAG error for 32/27 only */ + if ((PSD1 & 2) == 0) /* if lf hw instruction */ + i_flags &= ~HLF; /* if nop in rt hw, bump pc a word */ + else + PSD1 &= ~3; /* fake out 32/27 diag error */ + } + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (OPR & 0xf) { /* any subop not zero is error */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + } + /* get Rs divisor value */ + source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0); + /* merge the dividend regs into the 64bit value */ + dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]); + if (source == 0) + goto doovr3; + td = (t_int64)dest % (t_int64)source; /* remainder */ + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = NEGATE32(td); /* dividend and remainder must be same sign */ + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ + int64a = dest; + if (int64a < 0) + int64a = -int64a; + if (int64a > 0x7fffffff) /* if more than 31 bits, we have an error */ + goto doovr3; + if (((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) || + (((dest & D32LMASK) == D32LMASK) && ((dest & D32RMASK) == 0))) { /* test for overflow */ +doovr3: + dest = (((t_uint64)GPR[reg]) << 32);/* insert upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */ + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + /* the original regs must be returned unchanged if aexp */ + CC = CC1BIT; /* set ovr CC bit */ + if (dest == 0) + CC |= CC4BIT; /* dw is zero, so CC4 */ + else + if (dest & DMSIGN) + CC |= CC3BIT; /* it is neg dw, so CC3 */ + else + CC |= CC2BIT; /* then dest > 0, so CC2 */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ + } + break; + + case 0x48>>2: /* 0x48 INV - INV */ /* unused opcodes */ + case 0x4C>>2: /* 0x4C INV - INV */ /* unused opcodes */ + default: + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + break; + + case 0x50>>2: /* 0x50 INV - SD|ADR */ /* LA basemode LABRM */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + dest = (t_uint64)(addr&MASK24); /* just pure 24 bit address */ + break; + + case 0x54>>2: /* 0x54 SM|ADR - INV */ /* (basemode STWBR) */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if (FC != 0) { /* word address only */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC8 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + dest = BR[reg]; /* save the BR to memory */ + break; + + case 0x58>>2: /* 0x58 SB|ADR - INV */ /* (basemode SUABR and LABR) */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if ((FC & 4) == 0) { /* see if SUABR F=0 0x5800 */ + dest = BR[reg] - addr; /* subtract addr from the BR and store back to BR */ + } else { /* LABR if F=1 0x5808 */ + dest = addr; /* addr goes to specified BR */ + } + break; + + case 0x5C>>2: /* 0x5C RM|ADR - INV */ /* (basemode LWBR and BSUBM) */ + if ((MODES & BASEBIT) == 0) /* see if nonbased */ + goto inv; /* invalid instruction in nonbased mode */ + if ((FC & 3) != 0) { /* word address only */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + if ((FC & 0x4) == 0) { /* this is a LWBR 0x5C00 instruction */ + BR[reg] = (uint32)source; /* load memory location into BR */ + } else + { /* this is a CALLM/BSUBM instruction */ + /* if Rd field is 0 (reg is b6-8), this is a BSUBM instruction */ + /* otherwise it is a CALLM instruction (Rd != 0) */ + if (reg == 0) { + /* BSUBM instruction */ + uint32 cfp = BR[2]; /* get dword bounded frame pointer from BR2 */ + + if ((BR[2] & 0x7) != 0) { + /* Fault, must be dw bounded address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9a OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + + temp = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC from PSD1 into frame */ + if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */ + goto newpsd; /* memory write error or map fault */ + } + + temp = 0x80000000; /* show frame created by BSUBM instr */ + if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */ + goto newpsd; /* memory write error or map fault */ + } + + temp = addr & 0xfffffe; /* CALL memory address */ + if ((temp & 0x3) != 0) { /* check for word aligned */ + /* Fault, must be word bounded address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9b OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + + if ((TRAPME = Mem_read(temp, &addr))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + BR[1] = addr; /* effective address contents to BR 1 */ + /* keep bits 0-7 from old PSD */ + PSD1 = ((PSD1 & 0xff000000) | (BR[1] & 0x01fffffe)); /* New PSD address */ + BR[3] = GPR[0]; /* GPR[0] to BR[3] (AP) */ + BR[0] = cfp; /* set current frame pointer into BR[0] */ + i_flags |= BT; /* we changed the PC, so no PC update */ + } else { + /* CALLM instruction */ + + /* get frame pointer from BR2 - 16 words & make it a dword addr */ + uint32 cfp = ((BR[2]-0x40) & 0x00fffff8); + + /* if cfp and cfp+15w are in different maps, then addr exception error */ + if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9c OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + + temp = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */ + if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */ + goto newpsd; /* memory write error or map fault */ + } + + temp = 0x00000000; /* show frame created by CALL instr */ + if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */ + goto newpsd; /* memory write error or map fault */ + } + + /* save the BRs 0-7 on stack */ + for (ix=0; ix<8; ix++) { + if ((TRAPME = Mem_write(cfp+(4*ix)+8, &BR[ix]))) { /* Save into memory */ + goto newpsd; /* memory write error or map fault */ + } + } + + /* save GPRs 2-7 on stack */ + for (ix=2; ix<8; ix++) { + if ((TRAPME = Mem_write(cfp+(4*ix)+32, &GPR[ix]))) { /* Save into memory */ + goto newpsd; /* memory write error or map fault */ + } + } + + temp = addr & 0xfffffe; /* CALL memory address */ + if ((temp & 0x3) != 0) { /* check for word aligned */ + /* Fault, must be word bounded address */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC9d OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + + if ((TRAPME = Mem_read(temp, &addr))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + BR[1] = addr; /* effective address contents to BR 1 */ + /* keep bits 0-6 from old PSD */ + PSD1 = (PSD1 & 0xff000000) | ((BR[1]) & 0x01fffffe); /* New PSD address */ + BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */ + BR[0] = cfp; /* set current frame pointer into BR[0] */ + BR[2] = cfp; /* set current frame pointer into BR[2] */ + i_flags |= BT; /* we changed the PC, so no PC update */ + } + } + break; + + case 0x60>>2: /* 0x60 HLF - INV */ /* NOR Rd,Rs */ + if ((MODES & BASEBIT)) { /* only for nonbased mode */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + if (OPR & 0xf) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + /* exponent must not be zero or all 1's */ + /* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */ + temp = s_nor(GPR[reg], &GPR[sreg]); + sim_debug(DEBUG_DETAIL, my_dev, + "NOR GPR[%d] %08x result %08x exp %02x\n", + reg, GPR[reg], temp, GPR[sreg]); + GPR[reg] = temp; + break; + + case 0x64>>2: /* 0x64 SD|HLF - INV */ /* NORD */ + if ((MODES & BASEBIT)) { /* only for nonbased mode */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (OPR & 0xf) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + /* shift until upper 5 bits are neither 0 or all 1's */ + /* merge the GPR[reg] & GPR[reg+1] into a 64bit value */ + td = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]); + /* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */ + dest = s_nord(td, &GPR[sreg]); + sim_debug(DEBUG_DETAIL, my_dev, + "NORD GPR[%d] %08x %08x result %016llx exp %02x\n", + reg, GPR[reg], GPR[reg+1], dest, GPR[sreg]); + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0x68>>2: /* 0x68 HLF - INV */ /* non basemode SCZ */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction */ + if (OPR & 0xf) { /* any subop not zero is error */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* handle trap */ + } + goto sacz; /* use basemode sacz instruction */ + + case 0x6C>>2: /* 0x6C HLF - INV */ /* non basemode SRA & SLA */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction */ + bc = OPR & 0x1f; /* get bit shift count */ + temp = GPR[reg]; /* get reg value to shift */ + t = temp & FSIGN; /* sign value */ + if (OPR & 0x0040) { /* is this SLA */ + ovr = 0; /* set ovr off */ + for (ix=0; ix>= 1; /* shift bit 0 right one bit */ + temp |= t; /* restore original sign bit */ + } + GPR[reg] = temp; /* save the new value */ + } + break; + + case 0x70>>2: /* 0x70 SD|HLF - INV */ /* non-basemode SRL & SLL */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction in basemode */ + bc = OPR & 0x1f; /* get bit shift count */ + if (OPR & 0x0040) /* is this SLL, bit 9 set */ + GPR[reg] <<= bc; /* shift left #bits */ + else + GPR[reg] >>= bc; /* shift right #bits */ + break; + + case 0x74>>2: /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction in basemode */ + bc = OPR & 0x1f; /* get bit shift count */ + temp = GPR[reg]; /* get reg value to shift */ + if (OPR & 0x0040) { /* is this SLC, bit 9 set */ + for (ix=0; ix>= 1; /* shift the bit out */ + if (t) + temp |= BIT0; /* put in new sign bit */ + } + } + GPR[reg] = temp; /* shift result */ + break; + + case 0x78>>2: /* 0x78 HLF - INV */ /* non-basemode SRAD & SLAD */ + if (MODES & BASEBIT) /* Base mode? */ + goto inv; /* invalid instruction in basemode */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + bc = OPR & 0x1f; /* get bit shift count */ + dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ + dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + source = dest & DMSIGN; /* 64 bit sign value */ + if (OPR & 0x0040) { /* is this SLAD */ + ovr = 0; /* set ovr off */ + for (ix=0; ix>32) & FMASK);/* save the hi order reg */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (ovr) + PSD1 |= BIT1; /* CC1 in PSD */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* go execute the trap now */ + } + } else { /* this is a SRAD */ + for (ix=0; ix>= 1; /* shift bit 0 right one bit */ + dest |= source; /* restore original sign bit */ + } + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + } + break; + + case 0x7C>>2: /* 0x7C HLF - INV */ /* non-basemode SRLD & SLLD */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction in basemode */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + dest = (t_uint64)GPR[reg+1]; /* get low order reg value */ + dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + bc = OPR & 0x1f; /* get bit shift count */ + if (OPR & 0x0040) /* is this SLL, bit 9 set */ + dest <<= bc; /* shift left #bits */ + else + dest >>= bc; /* shift right #bits */ + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + break; + + case 0x80>>2: /* 0x80 SD|ADR - SD|ADR */ /* LEAR */ + /* convert address to real physical address */ + TRAPME = RealAddr(addr, &temp, &t, MEM_RD); + // diag allows any addr if mapped + if (TRAPME != ALLOK) { + sim_debug(DEBUG_TRAP, my_dev, + "At LEAR with TRAPME %02x addr %08x\n", TRAPME, addr); + goto newpsd; /* memory read error or map fault */ + } + /* set access bit for mapped addresses */ + if ((CPU_MODEL >= MODEL_V6) && (MODES & MAPMODE)) { + uint32 map, mix, nix, msdl, mpl, Mmap; + + nix = (addr >> 13) & 0x7ff; /* get 11 bit map value */ + /* check our access to the memory */ + switch (t & 0x0e) { + case 0x0: case 0x2: + /* O/S or user has no read/execute access, do protection violation */ + sim_debug(DEBUG_TRAP, my_dev, + "LEAR read protect error @ %06x prot %02x modes %08x page %04x\n", + addr, t, MODES, nix); + if (CPU_MODEL == MODEL_V9) + TRAPSTATUS |= BIT1; /* set bit 1 of trap status */ + else + TRAPSTATUS |= BIT12; /* set bit 12 of trap status */ + TRAPME = MPVIOL; /* memory protection violation */ + goto newpsd; /* process error */ + case 0x4: case 0x6: case 0x8: case 0xc: case 0xa: case 0xe: + /* O/S or user has read/execute access, no protection violation */ + sim_debug(DEBUG_DETAIL, my_dev, + "LEAR read protect is ok @ %06x prot %02x modes %08x page %04x\n", + addr, t, MODES, nix); + } + /* we have read access, so go set the access bit in the map entry */ + mpl = SPAD[0xf3]; /* get mpl from spad address */ + if (nix < BPIX) { + mix = nix; /* get map index in memory */ + msdl = RMW(mpl+4); /* get mpl entry for O/S */ + } else { + mix = nix-BPIX; /* get map index in memory */ + msdl = RMW(mpl+CPIX+4); /* get mpl entry for given CPIX */ + } + Mmap = RMH(msdl+(mix<<1)); /* map content from memory */ + map = RMR((nix<<1)); /* read the map cache contents */ + if (((map & 0x800) == 0)) { /* see if access bit is already on */ + Mmap |= 0x800; /* set the accessed bit in the map cache entry */ + map |= 0x800; /* set the accessed bit in the memory map entry */ + WMR((nix<<1), map); /* store the map reg contents into cache */ + TLB[nix] |= 0x0c000000; /* set the accessed & hit bits in TLB too */ + WMH(msdl+(mix<<1), Mmap); /* save modified memory map with access bit set */ + sim_debug(DEBUG_EXP, my_dev, + "LEAR Laddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n", + addr, nix, TLB[nix], map, Mmap); + } + } + + /* OS code says F bit is not transferred, so just ignore it */ + /* DIAGS needs it, so put it back */ + if (FC & 4) /* see if F bit was set */ + temp |= 0x01000000; /* set bit 7 of address */ + dest = temp; /* put in dest to go out */ + break; + + case 0x84>>2: /* 0x84 SD|RR|RNX|ADR - SD|RNX|ADR */ /* ANMx */ + td = dest & source; /* DO ANMX */ + CC = 0; + switch(FC) { /* adjust for hw or bytes */ + case 4: case 5: case 6: case 7: /* byte address */ + /* ANMB */ + td &= 0xff; /* mask out right most byte */ + dest &= 0xffffff00; /* make place for byte */ + if (td == 0) + CC |= CC4BIT; /* byte is zero, so CC4 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + case 1: /* left halfword addr */ + case 3: /* right halfword addr */ + /* ANMH */ + td &= RMASK; /* mask out right most 16 bits */ + dest &= LMASK; /* make place for halfword */ + if (td == 0) + CC |= CC4BIT; /* hw is zero, so CC4 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + case 0: /* 32 bit word */ + /* ANMW */ + td &= D32RMASK; /* mask out right most 32 bits */ + dest = 0; /* make place for 64 bits */ + if (td == 0) + CC |= CC4BIT; /* word is zero, so CC4 */ + else + if (td & 0x80000000) + CC |= CC3BIT; /* it is neg wd, so CC3 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + case 2: /* 64 bit double */ + /* ANMD */ + dest = 0; /* make place for 64 bits */ + if (td == 0) + CC |= CC4BIT; /* dw is zero, so CC4 */ + else + if (td & DMSIGN) + CC |= CC3BIT; /* it is neg dw, so CC3 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + } + dest |= td; /* insert result into dest */ + if (FC != 2) { /* do not sign extend DW */ + if (dest & 0x80000000) /* see if we need to sign extend */ + dest |= D32LMASK; /* force upper word to all ones */ + } + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + break; + + case 0x88>>2: /* 0x88 SD|RR|RNX|ADR - SD|RNX|ADR */ /* ORMx */ + td = dest | source; /* DO ORMX */ +meoa: /* merge point for eor, and, or */ + CC = 0; + switch(FC) { /* adjust for hw or bytes */ + case 4: case 5: case 6: case 7: /* byte address */ + /* ORMB */ + td &= 0xff; /* mask out right most byte */ + dest &= 0xffffff00; /* make place for byte */ + dest |= td; /* insert result into dest */ + if (dest == 0) + CC |= CC4BIT; /* byte is zero, so CC4 */ + else + if (dest & MSIGN) { + CC |= CC3BIT; /* assume negative */ + dest |= D32LMASK; /* force upper word to all ones */ + } + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + case 1: /* left halfword addr */ + case 3: /* right halfword addr */ + /* ORMH */ + td &= RMASK; /* mask out right most 16 bits */ + dest &= LMASK; /* make place for halfword */ + dest |= td; /* insert result into dest */ + if (dest == 0) + CC |= CC4BIT; /* byte is zero, so CC4 */ + else + if (dest & MSIGN) { + CC |= CC3BIT; /* assume negative */ + dest |= D32LMASK; /* force upper word to all ones */ + } + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + case 0: /* 32 bit word */ + /* ORMW */ + td &= D32RMASK; /* mask out right most 32 bits */ + dest = 0; /* make place for 64 bits */ + dest |= td; /* insert result into dest */ + if (dest == 0) + CC |= CC4BIT; /* byte is zero, so CC4 */ + else + if (dest & MSIGN) { + CC |= CC3BIT; /* assume negative */ + dest |= D32LMASK; /* force upper word to all ones */ + } + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + case 2: /* 64 bit double */ + /* ORMD */ + dest = 0; /* make place for 64 bits */ + dest |= td; /* insert result into dest */ + if (dest == 0) + CC |= CC4BIT; /* byte is zero, so CC4 */ + else + if (dest & DMSIGN) + CC |= CC3BIT; /* assume negative */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + break; + } + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + break; + + case 0x8C>>2: /* 0x8C SD|RR|RNX|ADR - SD|RNX|ADR */ /* EOMx */ + /* must special handle because we are getting bit difference */ + /* for word, halfword, & byte zero the upper 32 bits of dest */ + /* Diags require CC's to be set on result value of byte, hw, wd, or dw */ + td = dest ^ source; /* DO EOMX */ + goto meoa; + break; + + case 0x90>>2: /* 0x90 SCC|RR|RM|ADR - RM|ADR */ /* CAMx */ + if (dbl == 0) { + int32a = dest & D32RMASK; /* mask out right most 32 bits */ + int32b = source & D32RMASK; /* mask out right most 32 bits */ + int32c = int32a - int32b; /* signed diff */ + td = int32c; + if (int32a > int32b) dest = 1; + else + if (int32a == int32b) dest = 0; + else dest = -1; + } else { + int64a = dest; /* mask out right most 32 bits */ + int64b = source; /* mask out right most 32 bits */ + int64c = int64a - int64b; /* signed diff */ + td = int64c; + if (int64a > int64b) dest = 1; + else + if (int64a == int64b) dest = 0; + else dest = -1; + } + break; + + case 0x94>>2: /* 0x94 RR|RM|ADR - RM|ADR */ /* CMMx */ + /* CMMD needs both regs to be masked with R4 */ + if (dbl) { + /* we need to and both regs with R4 */ + t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK); + td = dest; /* save dest */ + dest ^= source; + dest &= nm; /* mask both regs with reg 4 contents */ + } else { + td = dest; /* save dest */ + dest ^= source; /* <= 32 bits, so just do lower 32 bits */ + dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */ + } + CC = 0; + if (dest == 0ll) + CC |= CC4BIT; + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + break; + + case 0x98>>2: /* 0x98 ADR - ADR */ /* SBM */ + if ((FC & 04) == 0) { + /* Fault, f-bit must be set for SBM instruction */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* if we have an IPU set the semaphore or wait */ + if (CCW & HASIPU) { +#ifdef USE_POSIX_SEM + set_simsem(); +#else + lock_mutex(); +#endif + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + { + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif + goto newpsd; /* memory read error or map fault */ + } + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + if (temp & bc) /* test the bit in memory */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ + temp |= bc; /* set the bit in temp */ + if ((TRAPME = Mem_write(addr, &temp))) { /* put word back into memory */ + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif + goto newpsd; /* memory write error or map fault */ + } + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif + break; + + case 0x9C>>2: /* 0x9C ADR - ADR */ /* ZBM */ + if ((FC & 04) == 0) { + /* Fault, byte address not allowed */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* if we have an IPU set the semaphore or wait */ + if (CCW & HASIPU) { +#ifdef USE_POSIX_SEM + set_simsem(); +#else + lock_mutex(); +#endif + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + { + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif + goto newpsd; /* memory read error or map fault */ + } + + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + if (temp & bc) /* test the bit in memory */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ + temp &= ~bc; /* reset the bit in temp */ + if ((TRAPME = Mem_write(addr, &temp))) { /* put word into memory */ + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif + goto newpsd; /* memory write error or map fault */ + } + /* unlock the semaphore */ + if (CCW & HASIPU) +#ifdef USE_POSIX_SEM + clr_simsem(); +#else + unlock_mutex(); +#endif + break; + + case 0xA0>>2: /* 0xA0 ADR - ADR */ /* ABM */ + if ((FC & 04) == 0) { + /* Fault, byte address not allowed */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */ + t |= ((bc & FSIGN) != 0) ? 2 : 0; /* ditto for the bit value */ + temp += bc; /* add the bit value to the reg */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) { + ovr = 1; /* we have an overflow */ + } + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + if ((TRAPME = Mem_write(addr, &temp))) { /* put word into memory */ + goto newpsd; /* memory write error or map fault */ + } + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* handle trap */ + } + break; + + case 0xA4>>2: /* 0xA4 ADR - ADR */ /* TBM */ + if ((FC & 04) == 0) { + /* Fault, byte address not allowed */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + + t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/ + /* use C bits and bits 6-8 (reg) to generate shift bit count */ + bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */ + bc = BIT0 >> bc; /* make a bit mask of bit number */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + if (temp & bc) /* test the bit in memory */ + t |= CC1BIT; /* set CC1 to the bit value */ + PSD1 |= t; /* update the CC's in the PSD */ + break; + + case 0xA8>>2: /* 0xA8 RM|ADR - RM|ADR */ /* EXM */ + if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */ + /* Fault */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + if (CPU_MODEL == MODEL_V9) /* V9 wants bit0 set in pfault */ + if (TRAPME == DMDPG) /* demand page request */ + pfault |= 0x80000000; /* set instruction fetch paging error */ + goto newpsd; /* memory read error or map fault */ + } + + IR = temp; /* get instruction from memory */ + if (FC == 3) /* see if right halfword specified */ + IR <<= 16; /* move over the HW instruction */ + if (IPU_MODEL && (IPUSTATUS & ONIPU)) { + /* on IPU : */ + sim_debug(DEBUG_INST, my_dev, + "IPU EXM IR %08x PSD %.8x %.8x SPDF5 %.8x IPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + if ((IR & 0xFC000000) == 0xFC000000 || /* No I/O targets */ + (IR & 0xFFFF0000) == 0x00060000) { /* No BEI target */ + TRAPME = IPUUNDEFI_TRAP; + i_flags |= BT; /* leave PC unchanged, so no PC update */ + goto newpsd; + } + } else { + sim_debug(DEBUG_INST, my_dev, + "CPU EXM IR %08x PSD %.8x %.8x SPDF5 %.8x IPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + } +#ifdef DIAG_SAYS_OK_TO_EXECUTE_ANOTHER_EXECUTE + /* 32/67 diag says execute of execute is OK */ + if ((IR & 0xFC7F0000) == 0xC8070000 || /* No EXR target */ + (IR & 0xFF800000) == 0xA8000000) { /* No EXM target */ + /* Fault, attempt to execute another EXR, EXRR, or EXM */ + goto inv; /* invalid instruction */ + } +#endif + goto dohist; /* merge with EXR code */ + break; + + case 0xAC>>2: /* 0xAC SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* Lx */ + dest = source; /* set value to load into reg */ + break; + + case 0xB0>>2: /* 0xB0 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* LMx */ + /* LMD needs both regs to be masked with R4 */ + if (dbl) { + /* we need to and both regs with R4 */ + t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK); + dest = source & nm; /* mask both regs with reg 4 contents */ + } else { + dest = source; /* <= 32 bits, so just do lower 32 bits */ + dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */ + if (dest & 0x80000000) /* see if we need to sign extend */ + dest |= D32LMASK; /* force upper word to all ones */ + } + break; + + case 0xB4>>2: /* 0xB4 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* LNx */ + dest = NEGATE32(source); /* set the value to load into reg */ + td = dest; + if (dest != 0 && (dest == source || dest == 0x80000000)) + ovr = 1; /* set arithmetic exception status */ + if (FC != 2) { /* do not sign extend DW */ + if (dest & 0x80000000) /* see if we need to sign extend */ + dest |= D32LMASK; /* force upper word to all ones */ + } + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (dest != 0 && ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0xBC>>2: /* 0xBC SD|RR|RM|ADR - SD|RR|RM|ADR */ /* SUMx */ + source = NEGATE32(source); + /* Fall through */ + + case 0xB8>>2: /* 0xB8 SD|RR|RM|ADR - SD|RR|RM|ADR */ /* ADMx */ + ovr = 0; + CC = 0; + /* DIAG fixs */ + if (dbl == 0) { + source &= D32RMASK; /* just 32 bits */ + dest &= D32RMASK; /* just 32 bits */ + t = (source & MSIGN) != 0; + t |= ((dest & MSIGN) != 0) ? 2 : 0; + td = dest + source; /* DO ADMx*/ + td &= D32RMASK; /* mask out right most 32 bits */ + dest = 0; /* make place for 64 bits */ + dest |= td; /* insert 32 bit result into dest */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if (((t == 3) && ((dest & MSIGN) == 0)) || + ((t == 0) && ((dest & MSIGN) != 0))) + ovr = 1; + if ((td == 0) && ((source & MSIGN) == MSIGN) && ovr) + ovr = 0; /* Diags want 0 and no ovr on MSIGN - MSIGN */ + if (dest & MSIGN) + dest = (D32LMASK | dest); /* sign extend */ + else + dest = (D32RMASK & dest); /* zero fill */ + if (td == 0) + CC |= CC4BIT; /* word is zero, so CC4 */ + else + if (td & 0x80000000) + CC |= CC3BIT; /* it is neg wd, so CC3 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + } else { + /* ADMD */ + t = (source & DMSIGN) != 0; + t |= ((dest & DMSIGN) != 0) ? 2 : 0; + td = dest + source; /* get sum */ + dest = td; /* insert 64 bit result into dest */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if (((t == 3) && ((dest & DMSIGN) == 0)) || + ((t == 0) && ((dest & DMSIGN) != 0))) + ovr = 1; + if (td == 0) + CC |= CC4BIT; /* word is zero, so CC4 */ + else + if (td & DMSIGN) + CC |= CC3BIT; /* it is neg wd, so CC3 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + } + if (ovr) + CC |= CC1BIT; /* set overflow CC */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0xC0>>2: /* 0xC0 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* MPMx */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (FC == 2) { /* must not be double word adddress */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + td = dest; + dest = GPR[reg+1]; /* get low order reg value */ + if (dest & MSIGN) + dest = (D32LMASK | dest); /* sign extend */ + dest = (t_uint64)((t_int64)dest * (t_int64)source); + dbl = 1; + break; + + case 0xC4>>2: /* 0xC4 RM|ADR - RM|ADR */ /* DVMx */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + if (FC == 2) { /* must not be double word adddress */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + goto newpsd; /* go execute the trap now */ + } + if (source == 0) + goto doovr; /* we have div by zero */ + dest = (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */ + td = ((t_int64)dest % (t_int64)source); /* remainder */ + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = NEGATE32(td); /* dividend and remainder must be same sign */ + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ + int64a = dest; + if (int64a < 0) + int64a = -int64a; + if (int64a > 0x7fffffff) /* if more than 31 bits, we have an error */ + goto doovr; + if (((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) || + (((dest & D32LMASK) == D32LMASK) && ((dest & D32RMASK) == 0))) { /* test for overflow */ +doovr: + dest = (((t_uint64)GPR[reg]) << 32);/* insert upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */ + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the original regs must be returned unchanged if aexp */ + CC = CC1BIT; /* set ovr CC bit */ + if (dest == 0) + CC |= CC4BIT; /* dw is zero, so CC4 */ + else + if (dest & DMSIGN) + CC |= CC3BIT; /* it is neg dw, so CC3 */ + else + CC |= CC2BIT; /* then dest > 0, so CC2 */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (MODES & AEXPBIT) + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ + } + break; + + case 0xC8>>2: /* 0xC8 IMM - IMM */ /* Immedate */ + temp = GPR[reg]; /* get reg contents */ + addr = IR & RMASK; /* sign extend 16 bit imm value from IR */ + if (addr & 0x8000) /* negative */ + addr |= LMASK; /* extend sign */ + + switch(OPR & 0xF) { /* switch on aug code */ + case 0x0: /* LI */ /* SCC | SD */ + GPR[reg] = addr; /* put immediate value into reg */ + set_CCs(addr, ovr); /* set the CC's, CC1 = ovr */ + break; + + case 0x2: /* SUI */ + addr = NEGATE32(addr); /* just make value a negative add */ + /* drop through */ + case 0x1: /* ADI */ + t = (temp & FSIGN) != 0; /* set flag for sign bit not set in reg value */ + t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the extended immediate value */ + temp = temp + addr; /* now add the numbers */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if ((t == 3 && (temp & FSIGN) == 0) || + (t == 0 && (temp & FSIGN) != 0)) + ovr = 1; /* we have an overflow */ + GPR[reg] = temp; /* save the result */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + goto newpsd; /* go execute the trap now */ + } + break; + + case 0x3: /* MPI */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* change immediate value into a 64 bit value */ + source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); + temp = GPR[reg+1]; /* get reg multiplier */ + dest = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0); + dest = dest * source; /* do the multiply */ + i_flags |= (SD|SCC); /* save regs and set CC's */ + dbl = 1; /* double reg save */ + break; + + case 0x4: /* DVI */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* change immediate value into a 64 bit value */ + source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0); + if (source == 0) { + goto doovr2; + } + dest = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + td = ((t_int64)dest % (t_int64)source); /* remainder */ + /* fix double reg if neg remainder */ + if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */ + td = NEGATE32(td); /* dividend and remainder must be same sign */ + dest = (t_int64)dest / (t_int64)source; /* now do the divide */ + int64a = dest; + if (int64a < 0) + int64a = -int64a; + if (int64a > 0x7fffffff) /* if more than 31 bits, we have an error */ + goto doovr2; + if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */ +doovr2: + dest = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + dest |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + ovr = 1; /* the quotient exceeds 31 bit, overflow */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (MODES & AEXPBIT) + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + /* the original regs must be returned unchanged if aexp */ + /* put reg values back in dest for CC test */ + CC = CC1BIT; /* set ovr CC bit */ + if (dest == 0) + CC |= CC4BIT; /* dw is zero, so CC4 */ + else + if (dest & DMSIGN) + CC |= CC3BIT; /* it is neg dw, so CC3 */ + else + CC |= CC2BIT; /* then dest > 0, so CC2 */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + } else { + GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */ + GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */ + set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */ + } + break; + + case 0x5: /* CI */ /* SCC */ + temp = ((int)temp - (int)addr); /* subtract imm value from reg value */ + set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */ + break; + +/* SVC instruction format C806 */ +/* |-------+-------+-------+-------+-------+-------+-------+-------| */ +/* |0 0 0 0 0 0|0 0 0|0 1 1|1 1 1 1|1 1 1 1|2 2 2 2 2 2 2 2 2 2 3 3| */ +/* |0 1 2 3 4 5|6 7 8|8 0 1|2 3 4 5|6 7 8 9|0 1 2 3 4 5 6 7 8 9 0 1| */ +/* | Op Code | N/U | N/U | Aug |SVC num| SVC Call Number | */ +/* |1 1 0 0 1 0|0 0 0|0 0 0|0 1 1 0|x x x x|x x x x x x x x x x x x| */ +/* |-------+-------+-------+-------+-------+-------+-------+-------| */ +/* */ + case 0x6: /* SVC none - none */ /* Supervisor Call Trap */ + { + int32c = IPUSTATUS; /* keep for retain blocking state */ + addr = SPAD[0xf0]; /* get trap table memory addr from SPAD (def 80, 20) */ + int32a = addr; + if (addr == 0 || ((addr&MASK24) == MASK24)) { /* see if secondary vector table set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS1 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* program error */ + } + addr = addr + (0x06 << 2); /* addr has mem addr of SVC trap vector (def 98, 38) */ + temp = M[addr >> 2]; /* get the secondary trap table address from memory */ + if (temp == 0 || ((temp&MASK24) == MASK24)) { /* see if ICB set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS2 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* program error */ + } + temp2 = ((IR>>12) & 0x0f) << 2; /* get SVC index from IR */ + t = M[(temp+temp2)>>2]; /* get secondary trap vector address ICB address */ + if (t == 0 || ((t&MASK24) == MASK24)) { /* see if ICB set up */ + TRAPME = ADDRSPEC_TRAP; /* Not setup, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS3 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* program error */ + } + bc = PSD2 & 0x3ff8; /* get copy of cpix */ + M[t>>2] = (PSD1+4) & 0xfffffffe; /* store PSD 1 + 1W to point to next instruction */ + M[(t>>2)+1] = PSD2; /* store PSD 2 */ + M[(t>>2)+4] = IR&0xFFF; /* store call number */ + TPSD1 = PSD1; /* save the PSD for the instruction */ + TPSD2 = PSD2; + PSD1 = M[(t>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(t>>2)+3] & ~0x3ff8) | bc; /* get new PSD 2 w/old cpix */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + + if (PSD2 & MAPBIT) { /* see if new PSD is mapped */ + uint32 mpl = SPAD[0xf3]; /* get mpl from spad address */ + uint32 osmidl = RMW(mpl); /* get midl entry for O/S */ + uint32 MAXMAP = MAX2048; /* default to 2048 maps */ + + if (CPU_MODEL < MODEL_27) + MAXMAP = MAX32; /* 32 maps for 32/77 */ + if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) + MAXMAP = MAX256; /* only 256 2KW (8kb) maps */ + + /* New PSD is mapped, check for valid msd and mpl counts */ + if ((mpl != 0) && (osmidl != 0) && ((osmidl & MASK16) <= MAXMAP)) { + sim_debug(DEBUG_TRAP, my_dev, + "OK SVC %x,%x @ %.8x %.8x mpl %.6x osmidl %06x MAPS %04x MAXMAPS %04x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, mpl, osmidl, osmidl & MASK16, MAXMAP); + sim_debug(DEBUG_TRAP, my_dev, + "OK SVC %x,%x @ %.8x %.8x PSD %.8x %.8x SPADF5 PSD2 %x IPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + } else { + sim_debug(DEBUG_TRAP, my_dev, + "Error SVC %x,%x @ %.8x %.8x mpl %.6x osmidl %06x MAPS %04x MAXMAPS %04x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, mpl, osmidl, osmidl & MASK16, MAXMAP); + sim_debug(DEBUG_TRAP, my_dev, + "Error SVC %x,%x @ %.8x %.8x PSD %.8x %.8x SPADF5 PSD2 %x IPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + TRAPME = MACHINECHK_TRAP; /* trap condition */ + PSD1 = TPSD1; /* restore PSD 1 */ +//FIX121222 PSD2 = TPSD2; /* restore PSD 2 */ + PSD2 = PSD2; /* diag wants new PSD 2, not old?? */ + goto newpsd; /* program error */ + } + } + sim_debug(DEBUG_TRAP, my_dev, + "SVC %x,%x @ %.8x %.8x NPSD %.8x %.8x SPADF5 %x IPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, TPSD1, TPSD2, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + sim_debug(DEBUG_TRAP, my_dev, + " R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); + sim_debug(DEBUG_TRAP, my_dev, + " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + IPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + IPUSTATUS &= ~BIT24; /* reset block state in ipu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ + } + + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + MODES &= ~RETMODE; /* reset retain map mode bit in status */ + IPUSTATUS &= ~0x87000000; /* reset bits in IPUSTATUS */ + IPUSTATUS |= (MODES & 0x87000000); /* now insert into IPUSTATUS */ + + if (PSD2 & SETBBIT) { /* is it set blocking state bit 49 set*/ + /* set new blocking state bit 49=1 */ + IPUSTATUS |= BIT24; /* yes, set blk state in ipu status bit 24 */ + MODES |= BLKMODE; /* set blocked mode */ + } else { + IPUSTATUS &= ~BIT24; /* reset block state in ipu status bit 8 */ + MODES &= ~BLKMODE; /* reset block mode bits */ + } + + /* bit 0 of PSD wd 2 sets new mapping state */ + if (PSD2 & MAPBIT) { + IPUSTATUS |= BIT8; /* set bit 8 of ipu status to mapped */ + MODES |= MAPMODE; /* set mapped mode */ + } else { + IPUSTATUS &= ~BIT8; /* reset bit 8 of ipu status */ + MODES &= ~MAPMODE; /* reset mapped mode */ + } + + sim_debug(DEBUG_TRAP, my_dev, + "SVCX %x,%x @ %.8x %.8x NPSD %.8x %.8x SPADF5 %x IPUSTATUS %08x\n", + temp2>>2, IR&0xFFF, OPSD1, OPSD2, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + TRAPME = 0; /* not to be processed as trap */ + drop_nop = 0; /* nothing to drop */ + i_flags |= BT; /* do not update pc */ + } + break; + + case 0x7: /* EXR */ + IR = temp; /* get instruction to execute */ + /* if bit 30 set, instruction is in right hw, do EXRR */ + if (addr & 2) + IR <<= 16; /* move instruction to left HW */ + if (IPU_MODEL && (IPUSTATUS & ONIPU)) { + /* on IPU : */ + sim_debug(DEBUG_INST, my_dev, + "IPU EXR IR %08x PSD %.8x %.8x SPDF5 %.8x IPUSTATUS %08x\n", + IR, PSD1, PSD2, SPAD[0xf5], IPUSTATUS); + if ((IR & 0xFC000000) == 0xFC000000 || /* No I/O targets */ + (IR & 0xFFFF0000) == 0x00060000) { /* No BEI target */ + TRAPME = IPUUNDEFI_TRAP; + i_flags |= BT; /* leave PC unchanged, so no PC update */ + goto newpsd; + } + } +#ifdef DIAG_SAYS_OK_TO_EXECUTE_ANOTHER_EXECUTE + /* 32/67 diag says execute of execute is OK */ + if ((IR & 0xFC7F0000) == 0xC8070000 || + (IR & 0xFF800000) == 0xA8000000) { + /* Fault, attempt to execute another EXR, EXRR, or EXM */ + goto inv; /* invalid instruction */ + } +#endif +dohist: + EXM_EXR = 4; /* set PC increment for EXR/EXP */ + OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ + OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ + /* TODO Update other history information for this instruction */ + if (hst_lnt) { + hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */ + hst[hst_p].npsd1 = PSD1; /* save new psd1 */ + hst[hst_p].npsd2 = PSD2; /* save new psd2 */ + hst[hst_p].modes = MODES; /* save current mode bits */ + hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */ + if (IPUSTATUS & BIT24) + hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */ + if (IPUSTATUS & BIT27) + hst[hst_p].modes |= IPUMODE; /* save ipu/ipu status bit */ +//113022 hst[hst_p].modes &= ~(BIT24|BIT27); /* clear blocked and ipu bits */ +//113022 hst[hst_p].modes |= (IPUSTATUS & BIT24);/* save blocking mode bit */ +//113022 hst[hst_p].modes |= (IPUSTATUS & BIT27);/* save ipu/ipu status bit */ + for (ix=0; ix<8; ix++) { + hst[hst_p].reg[ix] = GPR[ix]; /* save reg */ + hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */ + } + } + /* DEBUG_INST support code */ + OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ + OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ + /* output mapped/unmapped */ + if (MODES & BASEBIT) + BM = 'B'; + else + BM = 'N'; + if (MODES & MAPMODE) + MM = 'M'; + else + MM = 'U'; + if (IPUSTATUS & BIT24) + BK = 'B'; + else + BK = 'U'; + sim_debug(DEBUG_INST, my_dev, "%s %c%c%c %.8x %.8x %.8x ", + (IPUSTATUS & BIT27) ? "IPU": "CPU", + BM, MM, BK, OPSD1, PSD2, OIR); + sim_debug(DEBUG_INST, my_dev, "%c%c%c %.8x %.8x %.8x ", + BM, MM, BK, OPSD1, PSD2, OIR); + if (ipu_dev.dctrl & DEBUG_INST) { + fprint_inst(sim_deb, OIR, 0); /* display instruction */ + sim_debug(DEBUG_INST, my_dev, + "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]); + sim_debug(DEBUG_INST, my_dev, + " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + if (MODES & BASEBIT) { + sim_debug(DEBUG_INST, my_dev, + "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); + sim_debug(DEBUG_INST, my_dev, + " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); + } + } + goto exec; /* go execute the instruction */ + break; + + /* these instruction were never used by MPX, only diags */ + /* diags treat them as invalid halfword instructions */ + /* so set the HLF flag to get proper PC increment */ + case 0x8: /* SEM */ + case 0x9: /* LEM */ + case 0xA: /* CEMA */ + case 0xB: /* INV */ + case 0xC: /* INV */ + case 0xD: /* INV */ + case 0xE: /* INV */ + case 0xF: /* INV */ + default: + goto inv; /* invalid instruction */ + break; + } + break; + + case 0xCC>>2: /* 0xCC ADR - ADR */ /* LF */ + /* For machines with Base mode 0xCC08 stores base registers */ + if ((FC & 3) != 0) { /* must be word address */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS4 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + temp = addr & 0xffe000; /* get 11 bit map # */ + bc = addr & 0x20; /* bit 26 initial value */ + while (reg < 8) { + if (bc != (addr & 0x20)) { /* test for crossing file boundry */ + if (CPU_MODEL < MODEL_27) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS5 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + } + if (temp != (addr & 0xffe000)) { /* test for crossing map boundry */ + if (CPU_MODEL >= MODEL_V6) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPECS6 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + } + if (FC & 0x4) /* LFBR? 0xCC08 */ + TRAPME = Mem_read(addr, &BR[reg]); /* read the base reg */ + else /* LF? 0xCC00 */ + TRAPME = Mem_read(addr, &GPR[reg]); /* read the GPR reg */ + if (TRAPME) /* TRAPME has error */ + goto newpsd; /* go execute the trap now */ + reg++; /* next reg to write */ + addr += 4; /* next addr */ + } + break; + + case 0xD0>>2: /* 0xD0 SD|ADR - INV */ /* LEA none basemode only */ + if (MODES & BASEBIT) + goto inv; /* invalid instruction in basemode */ + /* bc has last bits 0,1 for indirect addr of both 1 for no indirection */ + addr &= 0x3fffffff; /* clear bits 0-1 */ + addr |= bc; /* insert bits 0,1 values into address */ + if (FC & 0x4) + addr |= F_BIT; /* copy F bit from instruction */ + dest = (t_uint64)(addr); + break; + + case 0xD4>>2: /* 0xD4 RR|SM|ADR - RR|SM|ADR */ /* STx */ + break; + + case 0xD8>>2: /* 0xD8 RR|SM|ADR - RR|SM|ADR */ /* STMx */ + /* STMD needs both regs to be masked with R4 */ + if (dbl) { + /* we need to and both regs */ + t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK); + dest &= nm; /* mask both regs with reg 4 contents */ + } else { + dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */ + } + break; + + case 0xDC>>2: /* 0xDC INV - ADR */ /* INV nonbasemode (STFx basemode) */ + /* DC00 STF */ /* DC08 STFBR */ + if ((FC & 0x4) && (CPU_MODEL <= MODEL_27)) { + /* basemode undefined for 32/7x & 32/27 */ + TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */ + goto newpsd; /* handle trap */ + } + /* For machines with Base mode 0xDC08 stores base registers */ + if ((FC & 3) != 0) { /* must be word address */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + bc = addr & 0x20; /* bit 26 initial value */ + temp = addr & 0xffe000; /* get 11 bit map # */ + while (reg < 8) { + if (bc != (addr & 0x20)) { /* test for crossing file boundry */ + if (CPU_MODEL < MODEL_27) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + } + if (temp != (addr & 0xffe000)) { /* test for crossing map boundry */ + if (CPU_MODEL >= MODEL_V6) { + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + } + if (FC & 0x4) /* STFBR? */ + TRAPME = Mem_write(addr, &BR[reg]); /* store the base reg */ + else /* STF */ + TRAPME = Mem_write(addr, &GPR[reg]); /* store the GPR reg */ + if (TRAPME) /* TRAPME has error */ + goto newpsd; /* go execute the trap now */ + reg++; /* next reg to write */ + addr += 4; /* next addr */ + } + break; + + case 0xE0>>2: /* 0xE0 ADR - ADR */ /* ADFx, SUFx */ + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + source = (t_uint64)temp; /* make into 64 bit value */ + if (FC & 2) { /* see if double word addr */ + if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ + goto newpsd; /* memory read error or map fault */ + } + source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */ + dbl = 1; /* double word instruction */ + } else { + source |= (source & MSIGN) ? D32LMASK : 0; + dbl = 0; /* not double wd */ + } + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + CC = 0; /* clear the CC'ss */ + /* handle float or double add/sub instructions */ + if (dbl == 0) { + /* do ADFW or SUFW instructions */ + temp2 = GPR[reg]; /* dest - reg contents specified by Rd */ + addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */ + if ((OPR & 8) == 0) { /* Was it SUFW? */ + addr = NEGATE32(addr); /* take negative for add */ + } + temp = s_adfw(temp2, addr, &CC); /* do ADFW */ + sim_debug(DEBUG_DETAIL, my_dev, + "%s GPR[%d] %08x addr %08x result %08x CC %08x\n", + (OPR&8) ? "ADFW":"SUFW", reg, GPR[reg], addr, temp, CC); + ovr = 0; + if (CC & CC1BIT) + ovr = 1; + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + /* check if we had an arithmetic exception on the last instruction*/ + if (ovr && (MODES & AEXPBIT)) { + /* leave regs unchanged */ + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + /* AEXP not enabled, so apply fix here */ + /* return temp to destination reg */ + GPR[reg] = temp; /* dest - reg contents specified by Rd */ + } else { + /* handle ADFD or SUFD */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* do ADFD or SUFD instructions */ + td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + /* source has 64 bit memory data */ + if ((OPR & 8) == 0) { /* Was it SUFD? */ + source = NEGATE32(source); /* make negative for subtract */ + } + dest = s_adfd(td, source, &CC); /* do ADFD */ + sim_debug(DEBUG_DETAIL, my_dev, + "%s GPR[%d] %08x %08x src %016llx result %016llx CC %08x\n", + (OPR&8) ? "ADFD":"SUFD", reg, GPR[reg], GPR[reg+1], source, dest, CC); + ovr = 0; + if (CC & CC1BIT) /* test for overflow detection */ + ovr = 1; + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + /* check if we had an arithmetic exception on the last instruction */ + if (ovr && (MODES & AEXPBIT)) { + /* leave regs unchanged */ + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + /* dest will be returned to destination regs */ + /* if AEXP not enabled, apply fix here */ + /* return dest to destination reg */ + GPR[reg] = (uint32)((dest & D32LMASK) >> 32); /* get upper reg value */ + GPR[reg+1] = (uint32)(dest & D32RMASK); /* get lower reg value */ + } + break; + + case 0xE4>>2: /* 0xE4 ADR - ADR */ /* MPFx, DVFx */ + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + source = (t_uint64)temp; /* make into 64 bit value */ + if (FC & 2) { /* see if double word addr */ + if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */ + goto newpsd; /* memory read error or map fault */ + } + source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */ + dbl = 1; /* double word instruction */ + } else { + source |= (source & MSIGN) ? D32LMASK : 0; + dbl = 0; /* not double wd */ + } + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + CC = 0; /* clear the CC'ss */ + /* handle float or double mul/div instructions */ + if (dbl == 0) { + /* do MPFW or DVFW instructions */ + temp2 = GPR[reg]; /* dest - reg contents specified by Rd */ + addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */ + if (OPR & 8) { /* Was it MPFW? */ + temp = s_mpfw(temp2, addr, &CC); /* do MPFW */ + } else { + temp = (uint32)s_dvfw(temp2, addr, &CC); /* do DVFW */ + } + sim_debug(DEBUG_DETAIL, my_dev, + "%s GPR[%d] %08x addr %08x result %08x\n", + (OPR&8) ? "MPFW":"DVFW", reg, GPR[reg], addr, temp); + if (CC & CC1BIT) + ovr = 1; + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + /* check if we had an arithmetic exception on the last instruction*/ + if (ovr && (MODES & AEXPBIT)) { + /* leave regs unchanged */ + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + /* if AEXP not enabled, apply fix here */ + /* return temp to destination reg */ + GPR[reg] = temp; /* dest - reg contents specified by Rd */ + } else { + /* handle MPFD or DVFD */ + if (reg & 1) { /* see if odd reg specified */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + goto newpsd; /* go execute the trap now */ + } + /* do MPFD or DVFD instructions */ + td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */ + td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */ + /* source has 64 bit memory data */ + if (OPR & 8) { /* Was it MPFD? */ + dest = s_mpfd(td, source, &CC); /* do MPFD */ + } else { + dest = s_dvfd(td, source, &CC); /* do DVFD */ + } + sim_debug(DEBUG_DETAIL, my_dev, + "%s GPR[%d] %08x %08x src %016llx result %016llx\n", + (OPR&8) ? "MPFD":"DVFD", reg, GPR[reg], GPR[reg+1], source, dest); + if (CC & CC1BIT) /* test for overflow detection */ + ovr = 1; + PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */ + /* check if we had an arithmetic exception on the last instruction*/ + if (ovr && (MODES & AEXPBIT)) { + /* leave regs unchanged */ + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + /* dest will be returned to destination regs */ + /* if AEXP not enabled, apply fix here */ + /* return dest to destination reg */ + GPR[reg] = (uint32)((dest & D32LMASK) >> 32); /* get upper reg value */ + GPR[reg+1] = (uint32)(dest & D32RMASK); /* get lower reg value */ + } + break; + + case 0xE8>>2: /* 0xE8 SM|RR|RNX|ADR - SM|RM|ADR */ /* ARMx */ + ovr = 0; + CC = 0; + switch(FC) { /* adjust for hw or bytes */ + case 4: case 5: case 6: case 7: /* byte address */ + /* ARMB */ + td = dest + source; /* DO ARMB */ + td &= 0xff; /* mask out right most byte */ + dest &= 0xffffff00; /* make place for byte */ + dest |= td; /* insert result into dest */ + if (td == 0) + CC |= CC4BIT; /* byte is zero, so CC4 */ + break; + case 1: /* left halfword addr */ + case 3: /* right halfword addr */ + /* ARMH */ + td = dest + source; /* DO ARMH */ + td &= RMASK; /* mask out right most 16 bits */ + dest &= LMASK; /* make place for halfword */ + dest |= td; /* insert result into dest */ + if (td == 0) + CC |= CC4BIT; /* hw is zero, so CC4 */ + break; + case 0: /* 32 bit word */ + /* ARMW */ + /* dest and source are really 32 bit values */ + t = (source & MSIGN) != 0; + t |= ((dest & MSIGN) != 0) ? 2 : 0; + td = dest + source; /* DO ARMW */ + td &= D32RMASK; /* mask out right most 32 bits */ + dest = 0; /* make place for 64 bits */ + dest |= td; /* insert result into dest */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if (((t == 3) && ((dest & MSIGN) == 0)) || + ((t == 0) && ((dest & MSIGN) != 0))) + ovr = 1; + if (dest & MSIGN) + dest = (D32LMASK | dest); /* sign extend */ + else + dest = (D32RMASK & dest); /* zero fill */ + if (td == 0) + CC |= CC4BIT; /* word is zero, so CC4 */ + else { + if (td & 0x80000000) + CC |= CC3BIT; /* it is neg wd, so CC3 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + } + break; + case 2: /* 64 bit double */ + /* ARMD */ + t = (source & DMSIGN) != 0; + t |= ((dest & DMSIGN) != 0) ? 2 : 0; + td = dest + source; /* DO ARMD */ + dest = td; /* insert result into dest */ + /* if both signs are neg and result sign is positive, overflow */ + /* if both signs are pos and result sign is negative, overflow */ + if (((t == 3) && ((dest & DMSIGN) == 0)) || + ((t == 0) && ((dest & DMSIGN) != 0))) + ovr = 1; + if (td == 0) + CC |= CC4BIT; /* dw is zero, so CC4 */ + else { + if (td & DMSIGN) + CC |= CC3BIT; /* it is neg dw, so CC3 */ + else + CC |= CC2BIT; /* then td > 0, so CC2 */ + } + break; + } + if (ovr) + CC |= CC1BIT; /* set overflow CC */ + PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */ + PSD1 |= CC; /* update the CC's in the PSD */ + /* the arithmetic exception will be handled */ + /* after instruction is completed */ + /* check for arithmetic exception trap enabled */ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* set the trap type */ + } + break; + + case 0xEC>>2: /* 0xEC ADR - ADR */ /* Branch unconditional or Branch True BCT */ + /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ + /* so just test for F bit and go on */ + /* if ((FC & 5) != 0) { */ + if ((FC & 4) != 0) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC10 OP %04x addr %08x FC %02x PSD %08x %08x\n", + OP, addr, FC, PSD1, PSD2); + goto newpsd; /* go execute the trap now */ + } + temp2 = CC; /* save the old CC's */ + CC = PSD1 & 0x78000000; /* get CC's if any */ + switch(reg) { + case 0: t = 1; break; + case 1: t = (CC & CC1BIT) != 0; break; + case 2: t = (CC & CC2BIT) != 0; break; + case 3: t = (CC & CC3BIT) != 0; break; + case 4: t = (CC & CC4BIT) != 0; break; + case 5: t = (CC & (CC2BIT|CC4BIT)) != 0; break; + case 6: t = (CC & (CC3BIT|CC4BIT)) != 0; break; + case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) != 0; break; + } + if (t) { /* see if we are going to branch */ +#if 0 /* set #if to 1 to stop branch to self while ipu tracing, for now */ + if (PC == (addr & 0xFFFFFC)) { /* BU to current PC, go to wait */ + fprintf(stderr, "BR stopping BU $ addr %x PC %x\r\n", addr, PC); + goto do_ipu_wait; + } +#endif + /* we are taking the branch, set CC's if indirect, else leave'm */ + /* update the PSD with new address */ + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + i_flags |= BT; /* we branched, so no PC update */ + if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */ + PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */ +/*FIX F77*/ if ((MODES & (BASEBIT|EXTDBIT)) == 0) /* see if basemode */ +/*FIX F77*/ PSD1 &= 0xff07ffff; /* only 19 bit address allowed */ + } + /* branch not taken, go do next instruction */ + break; + + case 0xF0>>2: /* 0xF0 ADR - ADR */ /* Branch False or Branch Function True BFT */ + /* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/ + /* so just test for F bit and go on */ + /* if ((FC & 5) != 0) { */ + if ((FC & 4) != 0) { + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC11 OP %04x addr %08x FC %02x PSD %08x %08x\n", + OP, addr, FC, PSD1, PSD2); + goto newpsd; /* go execute the trap now */ + } + temp2 = CC; /* save the old CC's */ + CC = PSD1 & 0x78000000; /* get CC's if any */ + switch(reg) { + case 0: t = (GPR[4] & (0x8000 >> ((CC >> 27) & 0xf))) != 0; break; + case 1: t = (CC & CC1BIT) == 0; break; + case 2: t = (CC & CC2BIT) == 0; break; + case 3: t = (CC & CC3BIT) == 0; break; + case 4: t = (CC & CC4BIT) == 0; break; + case 5: t = (CC & (CC2BIT|CC4BIT)) == 0; break; + case 6: t = (CC & (CC3BIT|CC4BIT)) == 0; break; + case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) == 0; break; + } + if (t) { /* see if we are going to branch */ + /* we are taking the branch, set CC's if indirect, else leave'm */ + /* update the PSD with new address */ + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + i_flags |= BT; /* we branched, so no PC update */ + if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */ + PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */ +/*FIX F77*/ if ((MODES & (BASEBIT|EXTDBIT)) == 0) /* see if basemode */ +/*FIX F77*/ PSD1 &= 0xff07ffff; /* only 19 bit address allowed */ + } + break; + + case 0xF4>>2: /* 0xF4 RR|SD|ADR - RR|SB|WRD */ /* Branch increment */ + dest += ((t_uint64)1) << ((IR >> 21) & 3); /* use bits 9 & 10 to incr reg */ + if (dest != 0) { /* if reg is not 0, take the branch */ + /* we are taking the branch, set CC's if indirect, else leave'm */ + /* update the PSD with new address */ + +#if 0 /* set #if to 1 to stop branch to self while tracing, for now */ + if (PC == (addr & 0xFFFFFC)) { /* BIB to current PC, bump branch addr */ + addr += 4; +// fprintf(stderr, "BI? stopping BIB $ addr %x PC %x\r\n", addr, PC); + dest = 0; /* force reg to zero */ + } +#endif + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */ + if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */ + PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */ + i_flags |= BT; /* we branched, so no PC update */ +/*FIX F77*/ if ((MODES & (BASEBIT|EXTDBIT)) == 0) /* see if basemode */ +/*FIX F77*/ PSD1 &= 0xff07ffff; /* only 19 bit address allowed */ + } + break; + + case 0xF8>>2: /* 0xF8 SM|ADR - SM|ADR */ /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, TRP */ + switch((OPR >> 7) & 0x7) { /* use bits 6-8 to determine instruction */ + case 0x0: /* ZMx F80x */ /* SM */ + dest = 0; /* destination value is zero */ + i_flags |= SM; /* SM not set so set it to store value */ + break; + case 0x1: /* BL F880 */ + /* copy CC's from instruction and PC incremented by 4 */ + GPR[0] = ((PSD1 & 0xff000000) | ((PSD1 + 4) & 0xfffffe)); + if (((MODES & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect wanted */ + PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */ + /* update the PSD with new address */ + if (MODES & BASEBIT) + PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* bit 8-30 */ + else + PSD1 = (PSD1 & 0xff000000) | (addr & 0x07fffe); /* bit 13-30 */ + i_flags |= BT; /* we branched, so no PC update */ +/*FIX F77*/ if ((MODES & (BASEBIT|EXTDBIT)) == 0) /* see if basemode */ +/*FIX F77*/ PSD1 &= 0xff07ffff; /* only 19 bit address allowed */ + break; + + case 0x3: /* LPSD F980 */ + /* fall through */; + case 0x5: /* LPSDCM FA80 */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* Privlege violation trap */ + } + IPUSTATUS |= BIT25; /* enable software traps */ + /* this will allow attn and */ + /* power fail traps */ + if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */ + /* Fault */ + TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n", + OP, addr, FC, PSD1, PSD2); + goto newpsd; /* go execute the trap now */ + } + if ((TRAPME = Mem_read(addr, &temp))) { /* get PSD1 from memory */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + TRAPSTATUS |= BIT7; /* set bit 7 of trap status */ + } else + TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSD TRAP1 %02x SPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n", + TRAPME, OP, addr, FC, PSD1, PSD2); + goto newpsd; /* memory read error or map fault */ + } + bc = IPUSTATUS; /* save the IPU STATUS */ + TPSD1 = PSD1; /* save the PSD for the instruction */ + TPSD2 = PSD2; + t = MODES; /* save modes too */ + ix = SPAD[0xf5]; /* save the current PSD2 */ + + if ((TRAPME = Mem_read(addr+4, &temp2))) { /* get PSD2 from memory */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + TRAPSTATUS |= BIT7; /* set bit 7 of trap status */ + } else { + TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSD TRAP2 %02x SPEC12 OP %04x addr %08x FC %02x PSD %08x %08x\n", + TRAPME, OP, addr, FC, PSD1, PSD2); + } + goto newpsd; /* memory read error or map fault */ + } + if (OPR & 0x0200) { /* Was it LPSDCM? */ + /* LPSDCM */ + PSD1 = temp; /* PSD1 good, so set it */ + PSD2 = temp2 & 0xfffffff8; /* PSD2 access good, clean & save it */ + if (PSD2 & RETMBIT) /* is retain mapping bit set */ + PSD2 = ((PSD2 & 0x3ff8) | (temp2 & 0xffffc000)); /* use current cpix */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, IPUSTATUS); + } else { + /* LPSD */ + PSD1 = temp; /* PSD1 good, so set it */ + /* lpsd can not change cpix, so keep it */ + PSD2 = ((PSD2 & 0x3ff8) | (temp2 & 0xffffc000)); /* use current cpix */ + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 n/u */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSD %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, IPUSTATUS); + } + + /* test for retain blocking state */ + if (PSD2 & RETBBIT) { /* is it retain blocking state */ + /* BIT 49 has new blocking state */ + if (TPSD2 & SETBBIT) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* yes, set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + IPUSTATUS |= BIT24; /* set blocked mode */ + } else { + PSD2 &= ~SETBBIT; /* set to unblocked state */ + MODES &= ~RETMODE; /* reset retain block mode bit */ + IPUSTATUS &= ~BIT24; /* reset block state in ipu status bit 8 */ + } + PSD2 &= ~RETBBIT; /* clear bit 48 retain blocking bit */ + } + + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + MODES &= ~RETMODE; /* reset retain map mode bit in status */ + IPUSTATUS &= ~0x87000000; /* reset bits in IPUSTATUS */ + IPUSTATUS |= (MODES & 0x87000000); /* now insert into IPUSTATUS */ + + if (PSD2 & SETBBIT) { /* is it set blocking state bit 49 set*/ + /* set new blocking state bit 49=1 */ + IPUSTATUS |= BIT24; /* yes, set blk state in ipu status bit 24 */ + MODES |= BLKMODE; /* set blocked mode */ + } else { + IPUSTATUS &= ~BIT24; /* reset block state in ipu status bit 8 */ + MODES &= ~BLKMODE; /* reset block mode bits */ + } + + /* bit 0 of PSD wd 2 sets new mapping state */ + if (PSD2 & MAPBIT) { + IPUSTATUS |= BIT8; /* set bit 8 of ipu status to mapped */ + MODES |= MAPMODE; /* set mapped mode */ + } else { + IPUSTATUS &= ~BIT8; /* reset bit 8 of ipu status */ + MODES &= ~MAPMODE; /* reset mapped mode */ + } + + /* see what mapping we are to do if LPSDCM */ + if (OPR & 0x0200) { /* Was it LPSDCM? */ + if (PSD2 & MAPBIT) { +//FIXME TRYING FOR DEXP FIX? +#ifndef DEXP_TRY_FIX + /* this mod fixes MPX 1.X 1st swapr load */ + /* any O/S or user maps yet? */ + if (((CPIX != 0) && (CPIXPL == 0)) && (PSD2 & RETMBIT)) { + PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */ + sim_debug(DEBUG_TRAP, my_dev, "Turn off retain bit\n"); + } +#endif + +//FIXME TRYING FOR DEXP FIX? +#ifndef DEXP_TRY_FIX + /* test if user count is equal to CPIXPL, if not load maps */ + /* this fixes software error in MPX3X where count is changed */ + /* but the retain bit was left set, so new maps were not loaded */ + /* until the next context switch and causes loading error */ + /* CHANGED 041420 maybe not right */ + if ((PSD2 & RETMBIT)) { /* don't load maps if retain bit set */ + uint32 mpl = SPAD[0xf3]; /* get mpl from spad address */ + uint32 cpix = PSD2 & 0x3ff8; /* get cpix 11 bit offset from psd wd 2 */ + uint32 osmidl = RMW(mpl); /* get midl entry for given O/S */ + uint32 midl = RMW(mpl+cpix); /* get midl entry for given user cpix */ + uint32 spc = midl & MASK16; /* get 16 bit user segment description count */ + + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM FIX %.8x %.8x mpl %.6x osmidl %06x umidl %06x OSMAPS %04x UMAPS %04x CPIXPL %04x\n", + TPSD1, TPSD2, mpl, osmidl, midl, osmidl & MASK16, spc, CPIXPL); + /* if this code is not present, MPX3X will not boot correctly */ + if (spc != CPIXPL) { + PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */ + } else { + /* if this code is not present MPX3X will abort */ + /* when trying to mount a secondary disk */ + if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97) || + (CPU_MODEL == MODEL_V6) || (CPU_MODEL == MODEL_V9)) { + PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */ + } + } + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM FIX MAP TRAPME %02x PSD %08x %08x spc %02x BPIX %02x CPIXPL %02x retain %01x\n", + TRAPME, PSD1, PSD2, spc, BPIX, CPIXPL, PSD2&RETMBIT?1:0); + } +#endif + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCML %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, IPUSTATUS); + /* load the new maps and test for errors */ + if ((PSD2 & RETMBIT) == 0) { /* don't load maps if retain bit set */ + /* we need to load the new maps */ + TRAPME = load_maps(PSD, 0); /* load maps for new PSD */ + } + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM MAPS LOADED TRAPME %02x PSD %08x %08x BPIX %02x CPIXPL %02x retain %01x\n", + TRAPME, PSD1, PSD2, BPIX, CPIXPL, PSD2&RETMBIT?1:0); + } + PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */ + } else { + /* LPSD */ + /* if cpix is zero, copy cpix from PSD2 in SPAD[0xf5] */ + if ((PSD2 & 0x3ff8) == 0) { + PSD2 |= (SPAD[0xf5] & 0x3ff8); /* use new cpix */ + } + sim_debug(DEBUG_TRAP, my_dev, + "LPSDL @ %.6x NPSD %08x %08x OPSD %08x %08x SPADF5 %x STATUS %08x\n", + addr, PSD1, PSD2, TPSD1, TPSD2, ix, IPUSTATUS); + } + + /* TRAPME can be error from LPSDCM or OK here */ + if (TRAPME) { /* if we have an error, restore old PSD */ + sim_debug(DEBUG_TRAP, my_dev, + "LPSDCM BAD MAPS LOAD TRAPME %02x PSD %08x %08x IPUSTAT %08x SPAD[f9] %08x\n", + TRAPME, PSD1, PSD2, IPUSTATUS, SPAD[0xf9]); + PSD1 = TPSD1; /* restore PSD1 */ +//NO, USE NEW PSD2 = TPSD2; /* restore PSD2 */ + /* HACK HACK HACK */ + /* Diags wants the new PSD2, not the original on error??? */ + /* if old one was used, we fail test 21/0 in cn.mmm for 32/67 */ + IPUSTATUS = bc; /* restore the IPU STATUS */ + MODES = t; /* restore modes too */ + SPAD[0xf5] = ix; /* restore the current PSD2 to SPAD */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) { + TRAPSTATUS |= BIT10; /* set bit 10 of trap status */ + TRAPSTATUS |= BIT7; /* set bit 7 of trap status */ + } else + TRAPSTATUS |= BIT18; /* set bit 18 of trap status */ + goto newpsd; /* go process error */ + } + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + drop_nop = 0; /* nothing to drop */ + i_flags |= BT; /* do not update pc */ + break; /* load the new psd, or process error */ + + case 0x4: /* JWCS */ /* not used in simulator */ + sim_debug(DEBUG_EXP, my_dev, "Got JWCS\n"); + break; + case 0x2: /* BRI */ /* TODO - only for 32/55 or 32/7X in PSW mode */ + case 0x6: /* TRP */ + case 0x7: /* TPR */ + TRAPME = UNDEFINSTR_TRAP; /* trap condition */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + goto newpsd; /* undefined instruction trap */ + break; + } + break; + +/* F Class I/O device instruction format */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02 03 04 05|06 07 08|09 10 11 12|13 14 15|16|17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */ +/* | Op Code | Reg | I/O type | Aug |0 | Channel Address | Device Sub-address | */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ +/* E Class I/O device instruction format */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* |00 01 02 03 04 05|06 07 08 09 10 11 12|13 14 15|16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| */ +/* | Op Code | Device Number | Aug | Command Code | */ +/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */ +/* */ + case 0xFC>>2: /* 0xFC IMM - IMM */ /* XIO, CD, TD, Interrupt Control */ + if ((MODES & PRIVBIT) == 0) { /* must be privileged to do I/O */ + TRAPME = PRIVVIOL_TRAP; /* set the trap to take */ + if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) + TRAPSTATUS |= BIT0; /* set bit 0 of trap status */ + else + TRAPSTATUS |= BIT19; /* set bit 19 of trap status */ + goto newpsd; /* Privlege violation trap */ + } + if (IPU_MODEL && (IPUSTATUS & ONIPU)) { + /* on IPU : */ + TRAPME = IPUUNDEFI_TRAP; + sim_debug(DEBUG_TRAP, my_dev, + "IPU SIO PSD %.8x %.8x SPDF5 %.8x IPUSTATUS %08x\n", + PSD1, PSD2, SPAD[0xf5], IPUSTATUS); +//DIAGS FIX i_flags |= BT; /* leave PC unchanged, so no PC update */ + goto newpsd; + } + break; + } /* End of Instruction Switch */ + + /* [*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*] */ + + /* any instruction with an arithmetic exception will still end up here */ + /* after the instruction is done and before incrementing the PC, */ + /* we will trap the ipu if ovl is set nonzero by an instruction */ + + /* Store result to register */ + if (i_flags & SD) { + if (dbl) { /* if double reg, store 2nd reg */ + if (reg & 1) { /* is it double regs into odd reg */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC13 OP %04x addr %08x reg %x\n", OP, addr, reg); + goto newpsd; /* go execute the trap now */ + } + GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */ + GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */ + } else { + GPR[reg] = (uint32)(dest & FMASK); /* save the reg */ + } + } + + /* Store result to base register */ + if (i_flags & SB) { + if (dbl) { /* no dbl wd store to base regs */ + TRAPME = ADDRSPEC_TRAP; /* bad address, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC14 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + BR[reg] = (uint32)(dest & FMASK); /* save the base reg */ + } + + /* Store result to memory */ + if (i_flags & SM) { + /* Check if byte of half word */ + if (((FC & 04) || (FC & 5) == 1)) { /* hw or byte requires read first */ + if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */ + goto newpsd; /* memory read error or map fault */ + } + } + switch(FC) { + case 2: /* double word store */ + if ((addr & 7) != 2) { + TRAPME = ADDRSPEC_TRAP; /* address not on dbl wd boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC14 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + temp = (uint32)(dest & MASK32);/* get lo 32 bit */ + if ((TRAPME = Mem_write(addr + 4, &temp))) + goto newpsd; /* memory write error or map fault */ + temp = (uint32)(dest >> 32); /* move upper 32 bits to lo 32 bits */ + break; + + case 0: /* word store */ + temp = (uint32)(dest & FMASK); /* mask 32 bit of reg */ + if ((addr & 3) != 0) { + /* Address fault */ + TRAPME = ADDRSPEC_TRAP; /* address not on wd boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC15 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + break; + + case 1: /* left halfword write */ + temp &= RMASK; /* mask out 16 left most bits */ + temp |= (uint32)(dest & RMASK) << 16; /* put into left most 16 bits */ + if ((addr & 1) != 1) { + /* Address fault */ + TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC16 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + break; + + case 3: /* right halfword write */ + temp &= LMASK; /* mask out 16 right most bits */ + temp |= (uint32)(dest & RMASK); /* put into right most 16 bits */ + if ((addr & 3) != 3) { + TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */ + sim_debug(DEBUG_TRAP, my_dev, + "ADDRSPEC17 OP %04x addr %08x\n", OP, addr); + goto newpsd; /* go execute the trap now */ + } + break; + + case 4: + case 5: + case 6: + case 7: /* byte store operation */ + temp &= ~(0xFF << (8 * (7 - FC))); /* clear the byte to store */ + temp |= (uint32)(dest & 0xFF) << (8 * (7 - FC)); /* insert new byte */ + break; + } + /* store back the modified memory location */ + if ((TRAPME = Mem_write(addr, &temp))) /* store back to memory */ + goto newpsd; /* memory write error or map fault */ + } + + /* Update condition code registers */ + if (i_flags & SCC) { + PSD1 &= 0x87FFFFFE; /* clear the old CC's */ + if (ovr) /* if overflow, set CC1 */ + CC = CC1BIT; /* show we had AEXP */ + else + CC = 0; /* no CC's yet */ + if (dest & DMSIGN) /* if neg, set CC3 */ + CC |= CC3BIT; /* if neg, set CC3 */ + else if (dest == 0) + CC |= CC4BIT; /* if zero, set CC4 */ + else + CC |= CC2BIT; /* if gtr than zero, set CC2 */ + PSD1 |= CC & 0x78000000; /* update the CC's in the PSD */ + } + + /* check if we had an arithmetic exception on the last instruction*/ + if (ovr && (MODES & AEXPBIT)) { + TRAPME = AEXPCEPT_TRAP; /* trap the system now */ + goto newpsd; /* process the trap */ + } + + /* Update instruction pointer to next instruction */ + if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */ + /* branch not taken, so update the PC */ + if (EXM_EXR != 0) { /* special handling for EXM, EXR, EXRR */ + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + EXM_EXR = 0; /* reset PC increment for EXR */ + } else + if (i_flags & HLF) { /* if nop in rt hw, bump pc a word */ + if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6))) { + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + } else { + PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); + } + } else { + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + } + } else { + EXM_EXR = 0; /* reset PC increment for EXR */ + } + drop_nop = 0; /* no NOP to drop */ + + OPSD1 &= 0x87FFFFFE; /* clear the old CC's */ + OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */ + /* TODO Update other history information for this instruction */ + if (hst_lnt) { + hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */ + hst[hst_p].npsd1 = PSD1; /* save new psd1 */ + hst[hst_p].npsd2 = PSD2; /* save new psd2 */ + hst[hst_p].modes = MODES; /* save current mode bits */ + hst[hst_p].modes &= ~(INTBLKD|IPUMODE); /* clear blocked and ipu bits */ + if (IPUSTATUS & BIT24) + hst[hst_p].modes |= INTBLKD; /* save blocking mode bit */ + if (IPUSTATUS & BIT27) + hst[hst_p].modes |= IPUMODE; /* save ipu/ipu status bit */ + for (ix=0; ix<8; ix++) { + hst[hst_p].reg[ix] = GPR[ix]; /* save reg */ + hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */ + } + } + + /* DEBUG_INST support code */ + /* output mapped/unmapped */ + if (MODES & BASEBIT) + BM = 'B'; + else + BM = 'N'; + if (MODES & MAPMODE) + MM = 'M'; + else + MM = 'U'; + if (IPUSTATUS & BIT24) + BK = 'B'; + else + BK = 'U'; + sim_debug(DEBUG_INST, my_dev, "%s %c%c%c %.8x %.8x %.8x ", + (IPUSTATUS & BIT27) ? "IPU": "CPU", + BM, MM, BK, OPSD1, PSD2, OIR); + if (ipu_dev.dctrl & DEBUG_INST) { + fprint_inst(sim_deb, OIR, 0); /* display instruction */ + sim_debug(DEBUG_INST, my_dev, + "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]); + sim_debug(DEBUG_INST, my_dev, + " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + if (MODES & BASEBIT) { + sim_debug(DEBUG_INST, my_dev, + "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]); + sim_debug(DEBUG_INST, my_dev, + " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]); + } + } + continue; /* keep running */ + +newpsd: + /* Trap Context Block - 6 words */ + /* WD1 Old PSD Wd 1 */ + /* WD2 Old PSD Wd 2 */ + /* WD3 New PSD WD 1 */ + /* WD4 New PSD Wd 2 */ + /* WD5 Multi Use */ /* N/U for Interrupts */ + /* WD6 Multi Use */ /* N/U for Interrupts */ + + /* WD5 Multi Use */ /* IOCL address for I/O */ + /* WD6 Multi Use */ /* Status address for I/O */ + + /* WD5 Multi Use */ /* Secondary vector table for SVC */ + /* WD6 Multi Use */ /* N/U for SVC */ + + /* WD5 Multi Use */ /* Trap status word for traps */ + /* WD6 Multi Use */ /* N/U for traps */ + + /* WD5 Multi Use */ /* Trap status word for page faults */ + /* WD6 Multi Use */ /* Page fault status word */ + /* Bit 0 = 0 The map fault was caused by an instruction fetch */ + /* = 1 The mp fault was caused by an operand access */ + /* Bits 1-20 Always zero */ + /* Map register number (logical map block number) */ + + /* we get here from a LPSD, LPSDCM, INTR, or TRAP */ + if (TRAPME) { + /* SPAD location 0xf0 has trap vector base address */ + uint32 tta = SPAD[0xf0]; /* get trap table address in memory */ + uint32 tvl; /* trap vector location */ + if ((tta == 0) || ((tta&MASK24) == MASK24)) { + if (IPUSTATUS & ONIPU) { + tta = 0x20; /* if not set, assume 0x20 FIXME */ + } else { + tta = 0x80; /* if not set, assume 0x80 FIXME */ + } + } + /* Trap Table Address in memory is pointed to by SPAD 0xF0 */ + /* TODO update ipu status and trap status words with reason too */ + switch(TRAPME) { + case POWERFAIL_TRAP: /* 0x80 PL00/PL01 power fail trap */ + case POWERON_TRAP: /* 0x84 PL00/PL01 Power-On trap */ + case MEMPARITY_TRAP: /* 0x88 PL02 Memory Parity Error trap */ + case NONPRESMEM_TRAP: /* 0x8C PL03 Non Present Memory trap */ + case UNDEFINSTR_TRAP: /* 0x90 PL04 Undefined Instruction Trap */ + case PRIVVIOL_TRAP: /* 0x94 PL05 Privlege Violation Trap */ +//MOVED case SVCCALL_TRAP: /* 0x98 PL06 Supervisor Call Trap */ + case MACHINECHK_TRAP: /* 0x9C PL07 Machine Check Trap */ + case SYSTEMCHK_TRAP: /* 0xA0 PL08 System Check Trap */ + case MAPFAULT_TRAP: /* 0xA4 PL09 Map Fault Trap */ +//MOVED case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */ + case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */ +//MOVED case CALM_TRAP: /* 0xA8 PL0A Call Monitor Instruction Trap */ +//MOVED case SIGNALIPU_TRAP: /* 0xAC PL0B Signal IPU/CPU Trap */ + + case ADDRSPEC_TRAP: /* 0xB0 PL0C Address Specification Trap */ +//BAD HERE case CONSOLEATN_TRAP: /* 0xB4 PL0D Console Attention Trap */ + case PRIVHALT_TRAP: /* 0xB8 PL0E Privlege Mode Halt Trap */ + case AEXPCEPT_TRAP: /* 0xBC PL0F Arithmetic Exception Trap */ + case CACHEERR_TRAP: /* 0xC0 PL10 Cache Error Trap (V9 Only) */ + /* drop through */ + default: + sim_debug(DEBUG_EXP, my_dev, + "##TRAPME @%s %02x PSD1 %08x PSD2 %08x IPUSTATUS %08x drop_nop %1x i_flags %04x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + TRAPME, PSD1, PSD2, IPUSTATUS, drop_nop, i_flags); + /* adjust PSD1 to next instruction */ + /* Update instruction pointer to next instruction */ + if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */ + /* branch not taken, so update the PC */ + if (EXM_EXR != 0) { /* special handling for EXM, EXR, EXRR */ + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + EXM_EXR = 0; /* reset PC increment for EXR */ + } else + if (i_flags & HLF) { /* if nop in rt hw, bump pc a word */ + if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6))) { + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + } else { + PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); + } + } else { + PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); + //DIAG fix for test 34/10 in MMM diag, reset bit 31 + if ((CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97) || + (CPU_MODEL == MODEL_V9)) + PSD1 &= ~BIT31; /* force off last right */ + } + } else { + EXM_EXR = 0; /* reset PC increment for EXR */ + if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL >= MODEL_V6))) + PSD1 &= ~BIT31; /* force off last right */ + sim_debug(DEBUG_TRAP, my_dev, + "##GOT BT TRAPME %02x LOAD MAPS PSD1 %08x PSD2 %08x\n", + TRAPME, PSD1, PSD2); + } + drop_nop = 0; + /* fall through */ + /* do not update pc for page fault */ + case DEMANDPG_TRAP: /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ + if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ + /* Set map number */ + if (CPU_MODEL >= MODEL_V9) + PSD1 &= ~BIT31; /* force off last right */ + /* pfault will have 11 bit page number and bit 0 set if op fetch */ + sim_debug(DEBUG_TRAP, my_dev, + "##PAGEFAULT TRAPS %02x page# %04x LOAD MAPS PSD1 %08x PSD2 %08x IPUSTATUS %08x\n", + TRAPME, pfault, PSD1, PSD2, IPUSTATUS); + } + /* Moved here 05/28/2021 so PC gets incremented correctly */ + /* This caused the 2nd instruction of an int service routine to be skipped */ + /* The attn trap had to be on 2nd instruction */ + case CONSOLEATN_TRAP: /* 0xB4 PL0D Console Attention Trap */ +//112522 case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */ + case SIGNALIPU_TRAP: /* 0xAC PL0B Signal IPU/CPU Trap */ +#ifdef TRACE_SIPU + if ((TRAPME == SIGNALIPU_TRAP) || (TRAPME == IPUUNDEFI_TRAP)) + ipu_dev.dctrl |= DEBUG_INST; /* start instruction trace */ +#endif + sim_debug(DEBUG_TRAP, my_dev, + "At %s TRAPME %02x PC %08x PSD1 %08x PSD2 %08x IPUSTATUS %08x tta %02x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", + TRAPME, PC, PSD1, PSD2, IPUSTATUS, tta); + sim_debug(DEBUG_TRAP, my_dev, + "At %s TRAP %02x IR %08x PSD1 %08x PSD2 %08x IPUSTATUS %08x drop_nop %01x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", + TRAPME, IR, PSD1, PSD2, IPUSTATUS, drop_nop); + sim_debug(DEBUG_TRAP, my_dev, + "R0=%.8x R1=%.8x R2=%.8x R3=%.8x\n", GPR[0], GPR[1], GPR[2], GPR[3]); + sim_debug(DEBUG_TRAP, my_dev, + "R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]); + + tta = tta + (TRAPME - 0x80); /* tta has mem addr of trap vector */ + tvl = M[tta>>2] & 0xFFFFFC; /* get 24 bit trap address from trap vector loc */ + sim_debug(DEBUG_TRAP, my_dev, + "tvl %08x, tta %02x CCW %08x status %08x\n", + tvl, tta, CCW, IPUSTATUS); + sim_debug(DEBUG_TRAP, my_dev, + "M[tta] %08x M[tvl] %08x M[tvl+1] %08x M[tvl+2] %08x M[tvl+3]] %08x\n", + M[tta>>2], M[(tvl>>2)+0], M[(tvl>>2)+1], M[(tvl>>2)+2], M[(tvl>>2)+3]); +#ifndef TEMP_CHANGE_FOR_MPX3X_DEBUG + if (tvl == 0 || (IPUSTATUS & 0x40) == 0) { +#else + /* next line changed to force halt on halt trap */ + /* TRIED 041320 for MPX3.X install and testing */ + if (((tvl == 0) || (IPUSTATUS & 0x40) == 0) || + (TRAPME == PRIVHALT_TRAP)) { /* 0xB8 PL0E Privlege Mode Halt Trap */ +#endif + /* vector is zero or software has not enabled traps yet */ + /* execute a trap halt */ + /* set the PSD to trap vector location */ + fprintf(stderr, "[][][][][][][][][][] IPU HALT TRAP [2][][][][][][][][][]\r\n"); + fprintf(stderr, "PSD1 %08x PSD2 %08x TRAPME %02x\r\n", PSD1, PSD2, TRAPME); +//FIX PSD1 = 0x80000000 + TRAPME; /* just priv and PC to trap vector */ + PSD1 = 0x80000000 + tta; /* just priv and PC to trap vector */ + PSD2 = 0x00004000; /* unmapped, blocked interrupts mode */ + /* + * Some illegal traps result in automatic TRAP HALT + * as per V6 TM page 2-50 locations for saving status + * obviously differ for CPU and IPU + */ + if (IPUSTATUS & ONIPU) { + /* for IPU */ + M[0x690>>2] = PSD1; /* store PSD 1 */ + M[0x694>>2] = PSD2; /* store PSD 2 */ + M[0x698>>2] = TRAPSTATUS; /* store trap status */ + M[0x69C>>2] = 0; /* This will be device table entry later TODO */ + } else { + /* for IPU */ + M[0x680>>2] = PSD1; /* store PSD 1 */ + M[0x684>>2] = PSD2; /* store PSD 2 */ + M[0x688>>2] = TRAPSTATUS; /* store trap status */ + M[0x68C>>2] = 0; /* This will be device table entry later TODO */ + } + for (ix=0; ix<8; ix+=2) { + fprintf(stderr, "GPR[%d] %08x GPR[%d] %08x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } + if (MODES & BASEBIT) { + for (ix=0; ix<8; ix+=2) { + fprintf(stderr, "BR[%d] %08x BR[%d] %08x\r\n", ix, BR[ix], ix+1, BR[ix+1]); + } + } + fprintf(stderr, "[][][][][][][][][][] IPU HALT TRAP [2][][][][][][][][][]\r\n"); + if (IPU_MODEL && (IPUSTATUS & ONIPU)) { + sim_debug(DEBUG_TRAP, my_dev, + "%s: Halt TRAP IPUSTATUS %08x CCW %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "IPU", + IPUSTATUS, CCW); + } +/*TEST DIAG*/ reason = STOP_HALT; /* do halt for now */ + cpustop = reason; /* tell IPU our state */ + sim_debug(DEBUG_TRAP, my_dev, + "[][][][][][][][][][] IPU HALT2 [2][][][][][][][][][]\n"); + fflush(sim_deb); + pthread_exit((void *)&reason); + } else { + uint32 oldstatus = IPUSTATUS; /* keep for retain blocking state */ + /* valid vector, so store the PSD, fetch new PSD */ + bc = PSD2 & 0x3ff8; /* get copy of cpix */ + if ((TRAPME) && ((CPU_MODEL <= MODEL_27))) { + /* Traps on 27 have bit 31 reset */ + M[tvl>>2] = PSD1 & 0xfffffffe; /* store PSD 1 */ + } else + M[tvl>>2] = PSD1 & 0xffffffff; /* store PSD 1 */ + M[(tvl>>2)+1] = PSD2; /* store PSD 2 */ + PSD1 = M[(tvl>>2)+2]; /* get new PSD 1 */ + PSD2 = (M[(tvl>>2)+3] & ~0x3ff8) | bc; /* get new PSD 2 w/old cpix */ + M[(tvl>>2)+4] = TRAPSTATUS; /* store trap status */ + if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ + M[(tvl>>2)+5] = pfault; /* store page fault number */ + sim_debug(DEBUG_TRAP, my_dev, + "DPAGE tvl %06x PSD1 %08x PSD2 %08x TRAPME %02x TRAPSTATUS %08x\n", + tvl, PSD1, PSD2, TRAPME, pfault); + } + + /* set the mode bits and CCs from the new PSD */ + CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */ + MODES = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */ + IPUSTATUS &= ~0x87000000; /* reset bits in IPUSTATUS */ + IPUSTATUS |= (MODES & 0x87000000); /* now insert into IPUSTATUS */ + + /* set new map mode and interrupt blocking state in IPUSTATUS */ + if (PSD2 & MAPBIT) { + IPUSTATUS |= BIT8; /* set bit 8 of ipu status */ + MODES |= MAPMODE; /* set mapped mode */ + } else { + IPUSTATUS &= ~BIT8; /* reset bit 8 of ipu status */ + MODES &= ~MAPMODE; /* reset mapped mode */ + } + + /* set interrupt blocking state */ + if ((PSD2 & RETBBIT) == 0) { /* is it retain blocking state */ + if (PSD2 & SETBBIT) { /* no, is it set blocking state */ + IPUSTATUS |= BIT24; /* yes, set blk state in ipu status bit 24 */ + MODES |= BLKMODE; /* set blocked mode */ + } else { + IPUSTATUS &= ~BIT24; /* no, reset blk state in ipu status bit 24 */ + MODES &= ~BLKMODE; /* reset blocked mode */ + } + } else { + /* handle retain blocking state */ + PSD2 &= ~RETMBIT; /* turn off retain map bit in PSD2 */ + /* set new blocking state in PSD2 */ + PSD2 &= ~(SETBBIT|RETBBIT); /* clear bit 48 & 49 to be unblocked */ + MODES &= ~(BLKMODE|RETBLKM);/* reset blocked & retain mode bits */ + if (oldstatus & BIT24) { /* see if old mode is blocked */ + PSD2 |= SETBBIT; /* set to blocked state */ + MODES |= BLKMODE; /* set blocked mode */ + } + } + + SPAD[0xf5] = PSD2; /* save the current PSD2 */ + SPAD[0xf9] = IPUSTATUS; /* save the ipu status in SPAD */ + + sim_debug(DEBUG_TRAP, my_dev, + "Process %s TRAPME %02x PSD1 %08x PSD2 %08x IPUSTATUS %08x MODE %08x\n", + (IPUSTATUS & ONIPU)? "IPU": "CPU", +//FIX TRAPME, PSD1, PSD2, IPUSTATUS, MODES); + tta, PSD1, PSD2, IPUSTATUS, MODES); + /* TODO provide page fault data to word 6 */ + if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */ + /* Set map number */ + /* pfault will have 11 bit page number and bit 0 set if op fetch */ + sim_debug(DEBUG_TRAP, my_dev, + "PAGE TRAP %02x TSTAT %08x LOAD MAPS PSD1 %08x PSD2 %08x IPUSTAT %08x pfault %08x\n", + TRAPME, TRAPSTATUS, PSD1, PSD2, IPUSTATUS, pfault); + } + TRAPSTATUS = IPUSTATUS & 0x57; /* clear all trap status except ipu type */ + TRAPME = 0; /* to be safe */ + break; /* Go execute the trap */ + } + break; + } + } + continue; /* single step ipu just for now */ + } /* end wait loop while */ + + /* Simulation halted */ + sim_debug(DEBUG_EXP, my_dev, + "Process Event other reason %08x interval %08x\n", + reason, sim_interval); + + /* we need to do an actual halt here if on IPU */ + sim_debug(DEBUG_EXP, my_dev, + "\n[][][][][][][][][][] HALT [3][][][][][][][][][]\n"); + sim_debug(DEBUG_EXP, my_dev, + "AT %s: PSD1 %.8x PSD2 %.8x TRAPME %02x IPUSTATUS %08x\n", + (IPUSTATUS & ONIPU) ? "IPU" : "CPU", + PSD1, PSD2, TRAPME, IPUSTATUS); + for (ix=0; ix<8; ix+=2) { + sim_debug(DEBUG_EXP, my_dev, + "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]); + } + sim_debug(DEBUG_EXP, my_dev, + "[][][][][][][][][][] HALT [3][][][][][][][][][]\n"); + fflush(sim_deb); + +#ifdef DEBUG4IPU + DumpHist(); +#endif + fprintf(stdout, "[][][][][][][][][][] IPU HALT3 [3][][][][][][][][][]\r\n"); + fflush(stdout); + pthread_exit((void *)&reason); + return (0); /* dummy return for Windows */ +} + +/* these are the default ipl devices defined by the CPU jumpers */ +/* they can be overridden by specifying IPL device at ipl time */ +#ifndef USE_IPU_CODE +LOCAL uint32 def_disk = 0x0800; /* disk channel 8, device 0 */ +LOCAL uint32 def_floppy = 0x7ef0; /* IOP floppy disk channel 7e, device f0 */ +#endif +LOCAL uint32 def_tape = 0x1000; /* tape device 10, device 0 */ + +/* Reset routine */ +/* do any one time initialization here for ipu */ +t_stat ipu_reset(DEVICE *dptr) +{ + int i; + t_stat devs = SCPE_OK; + + /* leave regs alone so values can be passed to boot code */ + PSD1 = 0x80000000; /* privileged, non mapped, non extended, address 0 */ + PSD2 = 0x00004000; /* blocked interrupts mode */ + MODES = (PRIVBIT | BLKMODE); /* set modes to privileged and blocked interrupts */ + CC = 0; /* no CCs too */ + IPUSTATUS = CPU_MODEL; /* clear all ipu status except ipu type */ + IPUSTATUS |= PRIVBIT; /* set privleged state bit 0 */ + IPUSTATUS |= BIT24; /* set blocked mode state bit 24 */ + IPUSTATUS |= BIT22; /* set HS floating point unit not present bit 22 */ + IPUSTATUS |= ONIPU; /* set ipu state in ipu status, BIT27 */ + TRAPSTATUS = CPU_MODEL; /* clear all trap status except ipu type */ + CMCR = 0; /* No Cache Enabled */ + SMCR = 0; /* No Shared Memory Enabled */ + CMSMC = 0x00ff0a10; /* No V9 Cache/Shadow Memory Configuration */ + CSMCW = 0; /* No V9 CPU Shadow Memory Configuration */ + ISMCW = 0; /* No V9 IPU Shadow Memory Configuration */ +#ifdef NOT_USED + RDYQIN = RDYQOUT = 0; /* initialize channel ready queue */ +#endif + + ipu_unit.flags = cpu_unit.flags; /* tell ipu about cpu flags */ + ipu_unit.capac = cpu_unit.capac; /* tell ipu about memory */ + + if (IPU_MODEL) + CCW |= HASIPU; /* this is BIT19 */ + + /* zero regs */ + for (i = 0; i < 8; i++) { + GPR[i] = BOOTR[i]; /* set boot register values */ + BR[i] = 0; /* clear the registers */ + } + + /* zero interrupt status words */ + for (i = 0; i < 112; i++) + INTS[i] = 0; /* clear interrupt status flags */ + + /* add code here to initialize the SEL32 ipu scratchpad on initial start */ + /* see if spad setup by software, if yes, leave spad alone */ + /* otherwise set the default values into the spad */ + /* CPU key is 0xECDAB897, IPU key is 0x13254768 */ + /* Keys are loaded by the O/S software during the boot loading sequence */ + /* + * SPAD init for both CPU and IPU unless they have the right key + */ + if (SPAD[0xf7] != 0xecdab897 && SPAD[0xf7] != 0x13254768) { + int ival = 0; /* init value for concept 32 */ + if (CPU_MODEL < MODEL_27) + ival = 0xfffffff; /* init value for 32/7x int and dev entries */ + for (i = 0; i < 1024; i++) + MAPC[i] = 0; /* clear 2048 halfword map cache */ + for (i = 0; i < 224; i++) + SPAD[i] = ival; /* init 128 devices and 96 ints in the spad */ + for (i = 224; i < 256; i++) /* clear the last 32 extries */ + SPAD[i] = 0; /* clear the spad */ + SPAD[0xf0] = 0x20; /* default IPU Trap Table Address (TTA) */ + SPAD[0xf1] = 0x100; /* Interrupt Table Address (ITA) */ + SPAD[0xf2] = 0x700; /* IOCD Base Address */ + SPAD[0xf3] = 0x788; /* Master Process List (MPL) table address */ + SPAD[0xf4] = def_tape; /* Default IPL address from console IPL command or jumper */ + SPAD[0xf5] = PSD2; /* current PSD2 defaults to blocked */ + SPAD[0xf6] = 0; /* reserved (PSD1 ??) */ + SPAD[0xf7] = 0x13254768; /* set SPAD key for IPU */ +//120822SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */ + SPAD[0xf8] = 0x0f000000; /* set DRT to class f (anything else is E) */ + SPAD[0xf9] = IPUSTATUS; /* set default ipu type in ipu status word */ + SPAD[0xff] = 0x00ffffff; /* interrupt level 7f 1's complament */ + } + +#if 0 + /* set low memory bootstrap code */ + /* moved to boot code in sel32_chan.c so we can reset system and not destroy memory */ + M[0] = 0x02000000; /* 0x00 IOCD 1 read into address 0 */ + M[1] = 0x60000078; /* 0x04 IOCD 1 CMD Chain, Suppress incor len, 120 bytes */ + M[2] = 0x53000000; /* 0x08 IOCD 2 BKSR or RZR to re-read boot code */ + M[3] = 0x60000001; /* 0x0C IOCD 2 CMD chain,Supress incor length, 1 byte */ + M[4] = 0x02000000; /* 0x10 IOCD 3 Read into address 0 */ + M[5] = 0x000006EC; /* 0x14 IOCD 3 Read 0x6EC bytes */ +#endif + + fflush(sim_deb); + loading = 0; /* not loading yet */ + /* we are good to go or error from device setup */ + if (devs != SCPE_OK) + return devs; + return SCPE_OK; +} + +/* Memory examine */ +/* examine a 32bit memory location and return a byte */ +t_stat ipu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw) +{ + uint32 status, realaddr, prot; + uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */ + + if (sw & SWMASK('V')) { + /* convert address to real physical address */ + status = RealAddr(addr, &realaddr, &prot, MEM_RD); + sim_debug(DEBUG_CMD, my_dev, "ipu_ex Mem_read status = %02x\n", status); + if (status == ALLOK) { + *vptr = (M[realaddr] >> (8 * (3 - (baddr & 0x3)))); /* return memory contents */ + return SCPE_OK; /* we are all ok */ + } + return SCPE_NXM; /* no, none existant memory error */ + } + /* MSIZE is in 32 bit words */ + if (!MEM_ADDR_OK(addr)) /* see if address is within our memory */ + return SCPE_NXM; /* no, none existant memory error */ + if (vptr == NULL) /* any address specified by user */ + return SCPE_OK; /* no, just ignore the request */ + *vptr = (M[addr] >> (8 * (3 - (baddr & 0x3)))); /* return memory contents */ + return SCPE_OK; /* we are all ok */ +} + +/* Memory deposit */ +/* modify a byte specified by a 32bit memory location */ +/* address is byte address with bits 30,31 = 0 */ +t_stat ipu_dep(t_value val, t_addr baddr, UNIT *uptr, int32 sw) +{ + uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */ + static const uint32 bmasks[4] = {0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00}; + + /* MSIZE is in 32 bit words */ + if (!MEM_ADDR_OK(addr)) /* see if address is within our memory */ + return SCPE_NXM; /* no, none existant memory error */ + val = (M[addr] & bmasks[baddr & 0x3]) | (val << (8 * (3 - (baddr & 0x3)))); + M[addr] = val; /* set new value */ + return SCPE_OK; /* all OK */ +} + +t_stat ipu_set_ipu(UNIT *uptr, int32 sval, CONST char *cptr, void *desc) +{ + sim_printf("ipu_set_ipu sval %x cptr %s desc %s\n", sval, cptr, (char *)desc); + if ((CPU_MODEL == MODEL_55) || (CPU_MODEL == MODEL_27)) + sim_printf("IPU not available for model 32/55 or 32/27\n"); + else { + ipu_unit.flags |= (1 << UNIT_V_IPU); /* enable IPU for this MODEL */ + sim_printf("IPU enabled\n"); + } + return SCPE_OK; /* we done */ +} + +t_stat ipu_clr_ipu(UNIT *uptr, int32 sval, CONST char *cptr, void *desc) +{ +// sim_printf("ipu_clr_ipu sval %x cptr %s desc %s\n", sval, cptr, (char *)desc); + ipu_unit.flags &= ~UNIT_IPU; /* disable IPU for this MODEL */ + sim_printf("IPU disabled\n"); + return SCPE_OK; /* we done */ +} + +t_stat ipu_show_ipu(FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + if (IPU_MODEL) + sim_printf("IPU enabled\n"); + else + sim_printf("IPU disabled\n"); + return SCPE_OK; /* we done */ +} + +/* Handle execute history */ + +/* Set history */ +t_stat +ipu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int32 i, lnt; + t_stat r; + + if (cptr == NULL) { /* check for any user options */ + for (i = 0; i < hst_lnt; i++) /* none, so just zero the history */ + hst[i].opsd1 = 0; /* just psd1 for now */ + hst_p = 0; /* start at the beginning */ + return SCPE_OK; /* all OK */ + } + /* the user has specified options, process them */ + lnt = (int32)get_uint(cptr, 10, HIST_MAX, &r); + if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; /* arg error for bad input or too small a value */ + hst_p = 0; /* start at beginning */ + if (hst_lnt) { /* if a new length was input, resize history buffer */ + free(hst); /* out with the old */ + hst_lnt = 0; /* no length anymore */ + hst = NULL; /* and no pointer either */ + } + if (lnt) { /* see if new size specified, if so get new resized bfer */ + hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt); + if (hst == NULL) + return SCPE_MEM; /* allocation error, so tell user */ + hst_lnt = lnt; /* set new length */ + } + return SCPE_OK; /* we are good to go */ +} + +/* Show history */ +t_stat ipu_show_hist(FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + int32 k, di, lnt; + char *cptr = (char *) desc; + t_stat r; + uint8 BM, MM, BK; /* basemode, mapped mode, blocked mode */ + struct InstHistory *h; + + if (hst_lnt == 0) /* see if show history is enabled */ + return SCPE_NOFNC; /* no, so we are out of here */ + if (cptr) { /* see if user provided a display count */ + lnt = (int32)get_uint(cptr, 10, hst_lnt, &r); /* get the count */ + if ((r != SCPE_OK) || (lnt == 0)) /* if error or 0 count */ + return SCPE_ARG; /* report argument error */ + } else + lnt = hst_lnt; /* dump all the entries */ + di = hst_p - lnt; /* work forward */ + if (di < 0) + di = di + hst_lnt; /* wrap */ + for (k = 0; k < lnt; k++) { /* print specified entries */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + /* display the instruction and results */ + if (h->modes & BASEBIT) /* basemode? */ + BM = 'B'; + else + BM = 'N'; + if (h->modes & MAPMODE) /* copy of PSD2 bit 0 */ + MM = 'M'; + else + MM = 'U'; + if (h->modes & INTBLKD) /* get blocked bit 0x10 */ + BK = 'B'; + else + BK = 'U'; + fprintf(st, "%s %c%c%c %.8x %.8x %.8x ", + (h->modes & IPUMODE)? "IPU": "IPU", + BM, MM, BK, h->opsd1, h->npsd2, h->oir); + if (h->modes & BASEBIT) + fprint_inst(st, h->oir, SWMASK('M')); /* display basemode instruction */ + else + fprint_inst(st, h->oir, SWMASK('N')); /* display non basemode instruction */ + fprintf(st, " --->NPSD %.8x %.8x", h->npsd1, h->npsd2); + fprintf(st, "\n"); + fprintf(st, "\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", h->reg[0], h->reg[1], h->reg[2], h->reg[3]); + fprintf(st, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x", h->reg[4], h->reg[5], h->reg[6], h->reg[7]); + if (h->modes & BASEBIT) { + fprintf(st, "\n"); + fprintf(st, "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", h->reg[8], h->reg[9], h->reg[10], h->reg[11]); + fprintf(st, " B4=%.8x B5=%.8x B6=%.8x B7=%.8x", h->reg[12], h->reg[13], h->reg[14], h->reg[15]); + } + fprintf(st, "\n"); + } /* end for */ + return SCPE_OK; /* all is good */ +} + +/* return description for the specified device */ +const char *ipu_description (DEVICE *dptr) +{ + return "SEL 32 IPU"; /* return description */ +} + +t_stat ipu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ + fprintf(st, "The IPU can maintain a history of the most recently executed instructions.\n"); + fprintf(st, "This is controlled by the SET IPU HISTORY and SHOW IPU HISTORY commands:\n\n"); + fprintf(st, " sim> SET IPU HISTORY clear history buffer\n"); + fprintf(st, " sim> SET IPU HISTORY=0 disable history\n"); + fprintf(st, " sim> SET IPU HISTORY=n{:file} enable history, length = n\n"); + fprintf(st, " sim> SHOW IPU HISTORY print IPU history\n"); + return SCPE_OK; +} +#endif /* USE_IPU_THREAD */ diff --git a/SEL32/sel32_lpr.c b/SEL32/sel32_lpr.c index 91ea9345..62f8a3f4 100644 --- a/SEL32/sel32_lpr.c +++ b/SEL32/sel32_lpr.c @@ -1,6 +1,6 @@ /* sel32_lpr.c: SEL32 922x & 924x High Speed Line Printer - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a diff --git a/SEL32/sel32_mfp.c b/SEL32/sel32_mfp.c index c46a893b..a1951cce 100644 --- a/SEL32/sel32_mfp.c +++ b/SEL32/sel32_mfp.c @@ -1,6 +1,6 @@ /* sel32_mfp.c: SEL-32 Model 8002 MFP processor controller - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -202,8 +202,9 @@ t_stat mfp_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) mfp_chp[0].chan_inch_addr = mfp_chp[0].ccw_addr; /* set inch buffer addr */ mfp_chp[0].base_inch_addr = mfp_chp[0].ccw_addr; /* set inch buffer addr */ - mfp_chp[0].max_inch_addr = mfp_chp[0].ccw_addr + (128 * 8); /* set last inch buffer addr */ - + //??? mfp_chp[0].max_inch_addr = mfp_chp[0].ccw_addr + (127 * 8); /* set last inch buffer addr */ + /* MFP manual says it uses 128 dbl wds (256 wds) but diag aborts if gtr than 1 dbl wd */ + mfp_chp[0].max_inch_addr = mfp_chp[0].ccw_addr; /* set last inch buffer addr */ uptr->u3 |= MFP_INCH2; /* save INCH command as 0xf0 */ sim_activate(uptr, 40); /* go on */ return 0; /* no status change */ @@ -318,7 +319,8 @@ t_stat mfp_srv(UNIT *uptr) /* now call set_inch() function to write and test inch buffer addresses */ /* the chp->ccw_addr location contains the inch address */ /* 1-256 wd buffer is provided for 128 status dbl words */ - tstart = set_inch(uptr, mema, 128); /* new address of 128 entries */ +///?? tstart = set_inch(uptr, mema, 128); /* new address of 128 entries */ + tstart = set_inch(uptr, mema, 1); /* new address of 1 entrie */ if ((tstart == SCPE_MEM) || (tstart == SCPE_ARG)) { /* any error */ /* we have error, bail out */ uptr->u5 |= SNS_CMDREJ; diff --git a/SEL32/sel32_mt.c b/SEL32/sel32_mt.c index 33f7be68..b6b7bf92 100644 --- a/SEL32/sel32_mt.c +++ b/SEL32/sel32_mt.c @@ -1,6 +1,6 @@ /* sel32_mt.c: SEL-32 8051 Buffered Tape Processor - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -41,6 +41,8 @@ #if NUM_DEVS_MT > 0 +extern uint32 SPAD[]; /* cpu SPAD memory */ + #define BUFFSIZE (64 * 1024) #define UNIT_MT UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE @@ -389,6 +391,8 @@ t_stat mt_iocl(CHANP *chp, int32 tic_ok) uint16 chsa = chp->chan_dev; uint16 devstat = 0; DEVICE *dptr = get_dev(uptr); + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ /* check for valid iocd address if 1st iocd */ if (chp->chan_info & INFO_SIOCD) { /* see if 1st IOCD in channel prog */ @@ -461,7 +465,7 @@ loop: case MT_RDBK: case MT_RDCMP: case MT_REW: case MT_RUN: case MT_FSR: case MT_BSR: case MT_FSF: case MT_BSF: case MT_SETM: case MT_WTM: case MT_ERG: /* the inch command must be first command issued */ - if ((!loading) && (chp->chan_inch_addr == 0)) { + if ((!loading) && (pchp->chan_inch_addr == 0)) { chp->chan_status |= STATUS_PCHK; /* program check for invalid cmd */ uptr->SNS |= SNS_CMDREJ; /* cmd rejected */ sim_debug(DEBUG_EXP, dptr, @@ -628,11 +632,12 @@ t_stat mt_preio(UNIT *uptr, uint16 chan) { DEVICE *dptr = get_dev(uptr); int unit = (uptr - dptr->units); uint16 chsa = GET_UADDR(uptr->CMD); - CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ sim_debug(DEBUG_CMD, dptr, "mt_preio CMD %08x unit %02x chsa %04x incha %08x\n", - uptr->CMD, unit, chsa, chp->chan_inch_addr); - if ((!loading) && (chp->chan_inch_addr == 0)) { + uptr->CMD, unit, chsa, pchp->chan_inch_addr); + if ((!loading) && (pchp->chan_inch_addr == 0)) { sim_debug(DEBUG_CMD, dptr, "mt_preio unit %02x chsa %04x NO INCH\n", unit, chsa); /* no INCH yet, so do nothing */ diff --git a/SEL32/sel32_scfi.c b/SEL32/sel32_scfi.c index 8785a199..b286af9a 100644 --- a/SEL32/sel32_scfi.c +++ b/SEL32/sel32_scfi.c @@ -1,6 +1,6 @@ /* sel32_scfi.c: SEL-32 SCFI SCSI Disk Controller - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -32,6 +32,8 @@ #define UNIT_SCFI UNIT_ATTABLE | UNIT_IDLE | UNIT_DISABLE +extern uint32 SPAD[]; /* cpu SPAD memory */ + /* useful conversions */ /* Fill STAR value from cyl, trk, sec data */ #define CHS2STAR(c,h,s) (((c<<16) & LMASK)|((h<<8) & 0xff00)|(s & 0xff)) @@ -671,6 +673,8 @@ t_stat scfi_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) DEVICE *dptr = get_dev(uptr); int32 unit = (uptr - dptr->units); CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */ + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ sim_debug(DEBUG_CMD, dptr, "scfi_startcmd chsa %04x unit %02x cmd %02x CMD %08x\n", @@ -698,7 +702,7 @@ t_stat scfi_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) case DSK_INCH: /* INCH cmd 0x0 */ sim_debug(DEBUG_CMD, dptr, "scfi_startcmd starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n", - chp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); + pchp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); uptr->SNS &= ~SNS_CMDREJ; /* not rejected yet */ uptr->CMD |= DSK_INCH2; /* use 0xF0 for inch, just need int */ @@ -797,7 +801,9 @@ t_stat scfi_srv(UNIT *uptr) { uint16 chsa = GET_UADDR(uptr->CMD); DEVICE *dptr = get_dev(uptr); - CHANP *chp = find_chanp_ptr(chsa);/* get channel prog pointer */ + CHANP *chp = find_chanp_ptr(chsa); /* get channel prog pointer */ + DIB *pdibp = dib_chan[get_chan(chsa)]; /* channel DIB */ + CHANP *pchp = pdibp->chan_prg; /* get channel chp */ int cmd = uptr->CMD & DSK_CMDMSK; int type = GET_TYPE(uptr->flags); uint32 tcyl=0, trk=0, cyl=0, sec=0; @@ -837,7 +843,7 @@ t_stat scfi_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "scfi_srv cmd CONT ICH %06x chsa %04x addr %06x count %04x completed\n", - chp->chan_inch_addr, chsa, mema, chp->ccw_count); + pchp->chan_inch_addr, chsa, mema, chp->ccw_count); if (len == 0x14) { /* read all 20 bytes, stopping every 4 bytes to make words */ /* the first word has the inch buffer address */ @@ -860,7 +866,7 @@ t_stat scfi_srv(UNIT *uptr) mema = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | (buf[3]); sim_debug(DEBUG_CMD, dptr, "scfi_srv cmd CONT ICH %06x chsa %04x mema %06x completed\n", - chp->chan_inch_addr, chsa, mema); + pchp->chan_inch_addr, chsa, mema); } else { /* drive attribute registers */ /* may want to use this later */ @@ -868,7 +874,7 @@ t_stat scfi_srv(UNIT *uptr) tstart = (buf[i-3]<<24) | (buf[i-2]<<16) | (buf[i-1]<<8) | (buf[i]); sim_debug(DEBUG_CMD, dptr, "scfi_srv cmd CONT ICH %06x chsa %04x data %06x completed\n", - chp->chan_inch_addr, chsa, tstart); + pchp->chan_inch_addr, chsa, tstart); } } } @@ -899,7 +905,7 @@ t_stat scfi_srv(UNIT *uptr) mema = chp->ccw_addr; /* get inch or buffer addr */ sim_debug(DEBUG_CMD, dptr, "scfi_srv starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n", - chp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); + pchp->chan_inch_addr, chsa, chp->ccw_addr, chp->ccw_count); /* mema has IOCD word 1 contents. For the disk processor it contains */ /* a pointer to the INCH buffer followed by 8 drive attribute words that */ @@ -979,7 +985,7 @@ gohere: uptr->CMD &= LMASK; /* remove old status bits & cmd */ sim_debug(DEBUG_CMD, dptr, "scfi_srv cmd INCH %06x chsa %04x addr %06x count %04x completed\n", - chp->chan_inch_addr, chsa, mema, chp->ccw_count); + pchp->chan_inch_addr, chsa, mema, chp->ccw_count); chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */ break; diff --git a/SEL32/sel32_scsi.c b/SEL32/sel32_scsi.c index 8540f9a5..41bddf3b 100644 --- a/SEL32/sel32_scsi.c +++ b/SEL32/sel32_scsi.c @@ -1,6 +1,6 @@ /* sel32_scsi.c: SEL-32 MFP SCSI Disk controller - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -32,6 +32,8 @@ #define UNIT_SCSI UNIT_ATTABLE | UNIT_IDLE | UNIT_DISABLE +extern uint32 SPAD[]; /* cpu SPAD memory */ + /* useful conversions */ /* Fill STAR value from cyl, trk, sec data */ #define CHS2STAR(c,h,s) (((c<<16) & LMASK)|((h<<8) & 0xff00)|(s & 0xff)) @@ -565,7 +567,9 @@ t_stat scsi_srv(UNIT *uptr) /* now call set_inch() function to write and test inch buffer addresses */ /* 1-256 wd buffer is provided for 128 status dbl words */ - i = set_inch(uptr, mema, 128); /* new address of 33 entries */ + /* manual says 128 entries, but diag aborts if more than 1 */ +///?? i = set_inch(uptr, mema, 128); /* new address of 33 entries */ + i = set_inch(uptr, mema, 1); /* new address of 1 entrie */ if ((i == SCPE_MEM) || (i == SCPE_ARG)) { /* any error */ /* we have error, bail out */ uptr->CMD &= LMASK; /* remove old status bits & cmd */ diff --git a/SEL32/sel32_sys.c b/SEL32/sel32_sys.c index 66d9c801..47e61cf4 100644 --- a/SEL32/sel32_sys.c +++ b/SEL32/sel32_sys.c @@ -1,6 +1,6 @@ /* sel32_sys.c: SEL-32 Gould Concept/32 (orignal SEL-32) Simulator system interface. - Copyright (c) 2018-2022, James C. Bevier + Copyright (c) 2018-2023, James C. Bevier Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers Permission is hereby granted, free of charge, to any person obtaining a @@ -21,11 +21,175 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/* Concept 32 PSD Mode Trap/Interrupt Priorities */ +/* Relative|Logical |Int Vect|TCW |IOCD|Description */ +/* Priority|Priority|Location|Addr|Addr */ +/* - 080 Power Fail Safe Trap */ +/* - 084 Power On Trap */ +/* - 088 Memory Parity Trap */ +/* - 08C Nonpresent Memory Trap */ +/* - 090 Undefined Instruction Trap */ +/* - 094 Privilege Violation Trap */ +/* - 098 Supervisor Call Trap (SVC) */ +/* - 09C Machine Check Trap */ +/* - 0A0 System Check Trap */ +/* - 0A4 Map Fault Trap */ +/* - 0A8 CALM or Undefined IPU Instruction Trap */ +/* - 0AC Signal CPU or Signal IPU Trap */ +/* - 0B0 Address Specification Trap */ +/* - 0B4 Console Attention Trap */ +/* - 0B8 Privlege Mode Halt Trap */ +/* - 0BC Arithmetic Exception Trap */ +/* - 0C0 Cache Error Trap (V9 Only) */ +/* - 0C4 Demand Page Fault Trap (V6&V9 Only) */ +/* */ +/* 0 00 100 External/software Interrupt 0 */ +/* 1 01 104 External/software Interrupt 1 */ +/* 2 02 108 External/software Interrupt 2 */ +/* 3 03 10C External/software Interrupt 3 */ +/* 4 04 110 704 700 I/O Channel 0 interrupt */ +/* 5 05 114 70C 708 I/O Channel 1 interrupt */ +/* 6 06 118 714 710 I/O Channel 2 interrupt */ +/* 7 07 11C 71C 718 I/O Channel 3 interrupt */ +/* 8 08 120 724 720 I/O Channel 4 interrupt */ +/* 9 09 124 72C 728 I/O Channel 5 interrupt */ +/* A 0A 128 734 730 I/O Channel 6 interrupt */ +/* B 0B 12C 73C 738 I/O Channel 7 interrupt */ +/* C 0C 130 744 740 I/O Channel 8 interrupt */ +/* D 0D 134 74C 748 I/O Channel 9 interrupt */ +/* E 0E 138 754 750 I/O Channel A interrupt */ +/* F 0F 13C 75C 758 I/O Channel B interrupt */ +/* 10 10 140 764 760 I/O Channel C interrupt */ +/* 11 11 144 76C 768 I/O Channel D interrupt */ +/* 12 12 148 774 770 I/O Channel E interrupt */ +/* 13 13 14c 77C 778 I/O Channel F interrupt */ +/* 14 14 150 External/Software Interrupt */ +/* 15 15 154 External/Software Interrupt */ +/* 16 16 158 External/Software Interrupt */ +/* 17 17 15C External/Software Interrupt */ +/* 18 18 160 Real-Time Clock Interrupt */ +/* 19 19 164 External/Software Interrupt */ +/* 1A 1A 1A8 External/Software Interrupt */ +/* 1B 1B 1AC External/Software Interrupt */ +/* 1C 1C 1B0 External/Software Interrupt */ +/* THRU THRU THRU THRU */ +/* 6C 6C 2B0 External/Software Interrupt */ +/* 6D 6D 2B4 External/Software Interrupt */ +/* 6E 6E 2B8 External/Software Interrupt */ +/* 6F 6F 2BC Interval Timer Interrupt */ + +/* IVL ------------> ICB Trap/Interrupt Vector Location points to Interrupt Context Block */ +/* Wd 0 - Old PSD Word 1 points to return location */ +/* Wd 1 - Old PSD Word 2 */ +/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ +/* Wd 3 - New PSD Word 2 */ +/* Wd 4 - CPU Status word at time of interrupt/trap */ +/* Wd 5 - N/U For Traps/Interrupts */ + +/* IVL ------------> ICB XIO Interrupt Vector Location */ +/* Wd 0 - Old PSD Word 1 points to return location */ +/* Wd 1 - Old PSD Word 2 */ +/* Wd 2 - New PSD Word 1 points to first instruction of service routine */ +/* Wd 3 - New PSD Word 2 */ +/* Wd 4 - Input/Output Command List Address (IOCL) for the Class F I/O CHannel */ +/* Wd 5 - 24 bit real address of the channel status word */ + +/*-----------------------------------------------------------------------------------------------*/ + +/* Map image descriptor 32/77 */ +/* |--------------------------------------| */ +/* |0|1|2|3 4 5 6|7 8 9 10 11 12 13 14 15| */ +/* |N|V|P| n/u | 9 bit map block entry | */ +/* |U| | | | 32kb/block | */ +/* | | 32 8kb maps per task | */ +/* | | 1 mb address space | */ +/* |--------------------------------------| */ + +/* Map image descriptor 32/27 */ +/* |--------------------------------------| */ +/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */ +/* |V|P|P|P|P| 11 bit map block entry | */ +/* | |1|2|3|4| 8kb/block | */ +/* | | 256 8kb maps per task | */ +/* | | 2 mb address space | */ +/* |--------------------------------------| */ + +/* Map image descriptor 32/67, 32/87, 32/97 */ +/* |--------------------------------------| */ +/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */ +/* |V|P|P|P|P| 11 bit map block entry | */ +/* | |1|2|3|4| 2kb/block | */ +/* | | 2048 8kb maps per task | */ +/* | | 16 mb address space | */ +/* |--------------------------------------| */ +/* BIT 0 = 0 Invalid map block (page) entry */ +/* = 1 Valid map block (page) entry */ +/* 1 = 0 000-7ff of 8kb page is not write protected */ +/* = 1 000-7ff of 8kb page is write protected */ +/* 2 = 0 800-fff of 8kb page is not write protected */ +/* = 1 800-fff of 8kb page is write protected */ +/* 3 = 0 1000-17ff of 8kb page is not write protected */ +/* = 1 1000-17ff of 8kb page is write protected */ +/* 4 = 0 1800-1fff of 8kb page is not write protected */ +/* = 1 1800-1fff of 8kb page is write protected */ +/* 5-15 = 11 most significant bits of the 24 bit real address for page */ + +/* Map image descriptor V6 & V9 */ +/* |--------------------------------------| */ +/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */ +/* |V|P|P|M|M| 11 bit map block entry | */ +/* | |1|2|M|A| 2kb/map | */ +/* | | 2048 8kb maps per task | */ +/* | | 16 mb address space | */ +/* |--------------------------------------| */ +/* BIT 0 = 0 Invalid map block (page) entry */ +/* = 1 Valid map block (page) entry */ +/* */ +/* PSD 1 BIT 0 - Map Bit 1 - Map Bit 2 - Access state */ +/* Priv Bits with ECO for Access Protection change */ +/* 0 0 0 No access allowed to page */ +/* 0 0 1 No access allowed to page */ +/* 0 1 0 Read/Write/Execute access */ +/* 0 1 1 Read/Execute access only */ +/*O/S*/ +/* 1 0 0 Read/Write/Execute access */ +/* 1 0 1 Read/Execute access only */ +/* 1 1 0 Read/Write/Execute access */ +/* 1 1 1 Read/Execute access only */ +/* Priv Bits without ECO for Access Protection change */ +/* 0 0 0 No access allowed to page */ +/* 0 0 1 Read/Execute access only */ +/* 0 1 0 Read//Execute access only */ +/* 0 1 1 Read/Write/Execute access */ +/*O/S*/ +/* 1 0 0 Read/Write/Execute only */ +/* 1 0 1 Read/Execute access only */ +/* 1 1 0 Read/Write/Execute access */ +/* 1 1 1 Read/Write/Execute access */ +/* */ +/* BIT 3 = 0 (MM) A first write (modify) to the map block (page) has not occurred */ +/* = 1 (MM) A first write (modify) to the map block (page) has occurred */ +/* BIT 4 = 0 (MA) A first read or write (access) to the map block (page) has not occurred */ +/* = 1 (MA) A first read or write (access) to the map block (page) has occurred */ +/* 5-15 = 11 most significant bits of the 24 bit real address for page */ + +/* Note */ +/* If a map is valid, a MAP (page) hit occurs and logical to physical translation occures */ +/* If the map is not valid, a demand MAP (page) fault occures and the faulting page is provided */ +/* P1 and P2 are used with Bit 0 of PSD to define the access rights */ +/* A privilege violation trap occurres if access it denied */ +/* Bits 5-15 contain the 11 most-significant bits of the physical address */ +/* MSD 0 page limit is used to verify access to O/S pages */ +/* CPIXPL page limit is used to verify access to user pages and page faults */ +/* CPIX CPIX of user MPL offset */ +/* Access to pages outside the limit registers results in a map fault */ + +/*-----------------------------------------------------------------------------------------------*/ + #include "sel32_defs.h" #include extern REG cpu_reg[]; -extern uint32 M[MAXMEMSIZE]; extern uint32 SPAD[]; extern uint32 PSD[]; char *dump_mem(uint32 mp, int cnt); @@ -59,6 +223,9 @@ int32 sim_emax = 4; /* maximum number of instructions/wo DEVICE *sim_devices[] = { &cpu_dev, +#ifdef USE_IPU_THREAD + &ipu_dev, +#endif #ifdef NUM_DEVS_IOP &iop_dev, /* IOP channel controller */ #endif @@ -231,8 +398,6 @@ char *dump_buf(uint8 *mp, int32 off, int cnt) return (line); /* return pointer to caller */ } - - /* * get_word - function to load a 32 bit word from the input file * return 1 - OK diff --git a/Visual Studio Projects/SEL32.vcproj b/Visual Studio Projects/SEL32.vcproj index 4ece5e67..f073469d 100755 --- a/Visual Studio Projects/SEL32.vcproj +++ b/Visual Studio Projects/SEL32.vcproj @@ -242,6 +242,10 @@ RelativePath="..\SEL32\sel32_iop.c" > + + diff --git a/makefile b/makefile index c63a60b2..d0c7bd53 100644 --- a/makefile +++ b/makefile @@ -2124,7 +2124,7 @@ SEL32 = ${SEL32D}/sel32_cpu.c ${SEL32D}/sel32_sys.c ${SEL32D}/sel32_chan.c \ ${SEL32D}/sel32_clk.c ${SEL32D}/sel32_mt.c ${SEL32D}/sel32_lpr.c \ ${SEL32D}/sel32_scfi.c ${SEL32D}/sel32_fltpt.c ${SEL32D}/sel32_disk.c \ ${SEL32D}/sel32_hsdp.c ${SEL32D}/sel32_mfp.c ${SEL32D}/sel32_scsi.c \ - ${SEL32D}/sel32_ec.c + ${SEL32D}/sel32_ec.c ${SEL32D}/sel32_ipu.c SEL32_OPT = -I $(SEL32D) -DUSE_INT32 -DSEL32 ${NETWORK_OPT} ###