home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Boot_Images / 2.11_on_rl02 / pdpsim.tz / pdpsim / nova_cpu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-29  |  19.4 KB  |  652 lines

  1. /* nova_cpu.c: NOVA CPU simulator
  2.  
  3.    Copyright (c) 1993, 1994, 1995,
  4.    Robert M Supnik, Digital Equipment Corporation
  5.    Commercial use prohibited
  6.  
  7.    The register state for the NOVA CPU is:
  8.  
  9.    AC[0:3]<0:15>    general registers
  10.    C            carry flag
  11.    PC<0:14>        program counter
  12.    
  13.    The NOVA has three instruction formats: memory reference, I/O transfer,
  14.    and operate.  The memory reference format is:
  15.  
  16.      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  17.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  18.    | 0| op  | AC  |in| mode|     displacement      |    memory reference
  19.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  20.  
  21.    <0:4>    mnemonic    action
  22.  
  23.    00000    JMP        PC = MA
  24.    00001    JMS        AC3 = PC, PC = MA
  25.    00010    ISZ        M[MA] = M[MA] + 1, skip if M[MA] == 0
  26.    00011    DSZ        M[MA] = M[MA] - 1, skip if M[MA] == 0
  27.    001'n    LDA        ACn = M[MA]
  28.    010'n    STA        M[MA] = ACn
  29.  
  30.    <5:7>    mode        action
  31.  
  32.    000    page zero direct    MA = zext (IR<8:15>)
  33.    001    PC relative direct    MA = PC + sext (IR<8:15>)
  34.    010    AC2 relative direct    MA = AC2 + sext (IR<8:15>)
  35.    011    AC3 relative direct    MA = AC3 + sext (IR<8:15>)
  36.    100    page zero indirect    MA = M[zext (IR<8:15>)]
  37.    101    PC relative dinirect    MA = M[PC + sext (IR<8:15>)]
  38.    110    AC2 relative indirect    MA = M[AC2 + sext (IR<8:15>)]
  39.    111    AC3 relative indirect    MA = M[AC3 + sext (IR<8:15>)]
  40.  
  41.    Memory reference instructions can access an address space of 32K words.
  42.    An instruction can directly reference the first 256 words of memory
  43.    (called page zero), as well as 256 words relative to the PC, AC2, or
  44.    AC3; it can indirectly access all 32K words.  If an indirect address
  45.    is in locations 00020-00027, the indirect address is incremented and
  46.    rewritten to memory before use; if in 00030-00037, decremented and
  47.    rewritten.
  48. */
  49.  
  50. /*  The I/O transfer format is:
  51.  
  52.      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  53.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  54.    | 0  1  1| AC  | opcode |pulse|      device     |    I/O transfer
  55.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  56.  
  57.    The IOT instruction sends the opcode, pulse, and specified AC to the
  58.    specified I/O device.  The device may accept data, provide data,
  59.    initiate or cancel operations, or skip on status.
  60.  
  61.    The operate format is:
  62.  
  63.      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  64.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  65.    | 1|srcAC|dstAC| opcode |shift|carry|nl|  skip  |    operate
  66.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  67.                    \______/ \___/ \___/  |  |  |  |
  68.                |      |     |    |  |  |  +--- reverse skip sense
  69.                |      |     |    |  |  +--- skip if C == 0
  70.                |      |     |    |  +--- skip if result == 0
  71.                |      |     |    +--- don't load result
  72.                |      |     +--- carry in (load as is,
  73.                |      |               set to Zero,
  74.                |      |               set to One,
  75.                |      |               load Complement)
  76.                |      +--- shift (none,
  77.                |          left one,
  78.                |          right one,
  79.                |          byte swap)
  80.                +--- operation (complement,
  81.                        negate,
  82.                        move,
  83.                        increment,
  84.                        add complement,
  85.                        subtract,
  86.                        add,
  87.                        and)
  88.  
  89.    The operate instruction can be microprogrammed to perform operations
  90.    on the source and destination AC's and the Carry flag.
  91. */
  92.  
  93. /* This routine is the instruction decode routine for the NOVA.
  94.    It is called from the simulator control program to execute
  95.    instructions in simulated memory, starting at the simulated PC.
  96.    It runs until 'reason' is set non-zero.
  97.  
  98.    General notes:
  99.  
  100.    1. Reasons to stop.  The simulator can be stopped by:
  101.  
  102.     HALT instruction
  103.     breakpoint encountered
  104.     infinite indirection loop
  105.     unknown I/O device and STOP_DEV flag set
  106.     I/O error in I/O simulator
  107.  
  108.    2. Interrupts.  Interrupts are maintained by four parallel variables:
  109.  
  110.     dev_done     device done flags
  111.     dev_disable    device interrupt disable flags
  112.     dev_busy    device busy flags
  113.     int_req        interrupt requests
  114.  
  115.       In addition, int_req contains the interrupt enable and ION pending
  116.       flags.  If ION and ION pending are set, and at least one interrupt
  117.       request is pending, then an interrupt occurs.  Note that the 16b PIO
  118.       mask must be mapped to the simulator's device bit mapping.
  119.  
  120.    3. Non-existent memory.  On the NOVA, reads to non-existent memory
  121.       return zero, and writes are ignored.  In the simulator, the
  122.       largest possible memory is instantiated and initialized to zero.
  123.       Thus, only writes need be checked against actual memory size.
  124.  
  125.    4. Adding I/O devices.  These modules must be modified:
  126.  
  127.     nova_defs.h    add interrupt request definition
  128.     nova_cpu.c    add IOT mask, PI mask, and routine to dev_table
  129.     nova_sys.c    add pointer to data structures to sim_devices
  130. */
  131.  
  132. #include "nova_defs.h"
  133.  
  134. #define ILL_ADR_FLAG    0100000
  135. #define save_ibkpt    (cpu_unit.u3)
  136. #define UNIT_V_MDV    (UNIT_V_UF)            /* MDV absent */
  137. #define UNIT_MDV    (1 << UNIT_V_MDV)
  138. #define UNIT_V_MSIZE    (UNIT_V_UF+1)            /* dummy mask */
  139. #define UNIT_MSIZE    (1 << UNIT_V_MSIZE)
  140.  
  141. unsigned short M[MAXMEMSIZE] = { 0 };            /* memory */
  142. int AC[4] = { 0 };                    /* accumulators */
  143. int C = 0;                        /* carry flag */
  144. int saved_PC = 0;                    /* program counter */
  145. int SR = 0;                        /* switch register */
  146. int dev_done = 0;                    /* device done flags */
  147. int dev_busy = 0;                    /* device busy flags */
  148. int dev_disable = 0;                    /* int disable flags */
  149. int int_req = 0;                    /* interrupt requests */
  150. int pimask = 0;                        /* priority int mask */
  151. int pwr_low = 0;                    /* power fail flag */
  152. int ind_max = 16;                    /* iadr nest limit */
  153. int stop_dev = 0;                    /* stop on ill dev */
  154. int ibkpt_addr = ILL_ADR_FLAG | ADDRMASK;        /* breakpoint addr */
  155. int old_PC = 0;                        /* previous PC */
  156.  
  157. extern int sim_int_char;
  158. int cpu_ex (int *vptr, int addr, UNIT *uptr, int sw);
  159. int cpu_dep (int val, int addr, UNIT *uptr, int sw);
  160. int cpu_reset (DEVICE *dptr);
  161. int cpu_svc (UNIT *uptr);
  162. int cpu_set_size (UNIT *uptr, int value);
  163. extern int ptr (int pulse, int code, int AC);
  164. extern int ptp (int pulse, int code, int AC);
  165. extern int tti (int pulse, int code, int AC);
  166. extern int tto (int pulse, int code, int AC);
  167. extern int clk (int pulse, int code, int AC);
  168. extern int lpt (int pulse, int code, int AC);
  169. extern int dsk (int pulse, int code, int AC);
  170. extern int dkp (int pulse, int code, int AC);
  171. extern int mta (int pulse, int code, int AC);
  172. int nulldev (int pulse, int code, int AC);
  173.  
  174. /* IOT dispatch table */
  175.  
  176. struct ndev dev_table[64] = {
  177.     { 0, 0, &nulldev }, { 0, 0, &nulldev },            /* 0 - 7 */
  178.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  179.     { 0, 0, &nulldev }, { 0, 0, &nulldev },
  180.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  181.     { INT_TTI, PI_TTI, &tti }, { INT_TTO, PI_TTO, &tto },    /* 10 - 17 */
  182.     { INT_PTR, PI_PTR, &ptr }, { INT_PTP, PI_PTP, &ptp }, 
  183.     { INT_CLK, PI_CLK, &clk }, { 0, 0, &nulldev },
  184.     { 0, 0, &nulldev }, { INT_LPT, PI_LPT, &lpt },
  185.     { INT_DSK, PI_DSK, &dsk }, { 0, 0, &nulldev },        /* 20 - 27 */
  186.     { INT_MTA, PI_MTA, &mta }, { 0, 0, &nulldev }, 
  187.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  188.     { 0, 0, &nulldev }, { 0, 0, &nulldev },
  189.     { 0, 0, &nulldev }, { 0, 0, &nulldev },            /* 30 - 37 */
  190.     { 0, 0, &nulldev }, {INT_DKP, PI_DKP, &dkp },
  191.     { 0, 0, &nulldev }, { 0, 0, &nulldev },
  192.     { 0, 0, &nulldev }, { 0, 0, &nulldev },
  193.     { 0, 0, &nulldev }, { 0, 0, &nulldev },            /* 40 - 47 */
  194.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  195.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  196.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  197.     { 0, 0, &nulldev }, { 0, 0, &nulldev },            /* 50 - 57 */
  198.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  199.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  200.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  201.     { 0, 0, &nulldev }, { 0, 0, &nulldev },            /* 60 - 67 */
  202.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  203.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  204.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  205.     { 0, 0, &nulldev }, { 0, 0, &nulldev },            /* 70 - 77 */
  206.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  207.     { 0, 0, &nulldev }, { 0, 0, &nulldev }, 
  208.     { 0, 0, &nulldev }, { 0, 0, &nulldev } };
  209.  
  210. /* CPU data structures
  211.  
  212.    cpu_dev    CPU device descriptor
  213.    cpu_unit    CPU unit descriptor
  214.    cpu_reg    CPU register list
  215.    cpu_mod    CPU modifiers list
  216. */
  217.  
  218. UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX+UNIT_MDV, MAXMEMSIZE) };
  219.  
  220. REG cpu_reg[] = {
  221.     { ORDATA (PC, saved_PC, 15) },
  222.     { ORDATA (AC0, AC[0], 16) },
  223.     { ORDATA (AC1, AC[1], 16) },
  224.     { ORDATA (AC2, AC[2], 16) },
  225.     { ORDATA (AC3, AC[3], 16) },
  226.     { FLDATA (C, C, 16) },
  227.     { ORDATA (SR, SR, 16) },
  228.     { ORDATA (PI, pimask, 16) },
  229.     { FLDATA (ION, int_req, INT_V_ION) },
  230.     { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) },
  231.     { FLDATA (PWR, pwr_low, 0) },
  232.     { ORDATA (INT, int_req, INT_V_ION+1), REG_RO },
  233.     { ORDATA (BUSY, dev_busy, INT_V_ION+1), REG_RO },
  234.     { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO },
  235.     { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO },
  236.     { FLDATA (STOP_DEV, stop_dev, 0) },
  237.     { FLDATA (MDV, cpu_unit.flags, UNIT_V_MDV), REG_HRO },
  238.     { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
  239.     { ORDATA (OLDPC, old_PC, 15), REG_RO },
  240.     { ORDATA (BREAK, ibkpt_addr, 16) },
  241.     { ORDATA (WRU, sim_int_char, 8) },
  242.     { NULL }  };
  243.  
  244. MTAB cpu_mod[] = {
  245.     { UNIT_MDV, UNIT_MDV, "MDV", "MDV", NULL },
  246.     { UNIT_MDV, 0, "no MDV", "NOMDV", NULL },
  247.     { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
  248.     { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
  249.     { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
  250.     { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
  251.     { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },
  252.     { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
  253.     { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
  254.     { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
  255.     { 0 }  };
  256.  
  257. DEVICE cpu_dev = {
  258.     "CPU", &cpu_unit, cpu_reg, cpu_mod,
  259.     1, 8, 15, 1, 8, 16,
  260.     &cpu_ex, &cpu_dep, &cpu_reset,
  261.     NULL, NULL, NULL };
  262.  
  263. int sim_instr (void)
  264. {
  265. extern int sim_interval;
  266. register int PC, IR, i, t, reason;
  267. extern int sim_process_event (void);
  268. extern int sim_activate (UNIT *uptr, int interval);
  269. extern int reset_all (int starting_device);
  270. void mask_out (int mask);
  271.  
  272. /* Restore register state */
  273.  
  274. PC = saved_PC & ADDRMASK;                /* load local PC */
  275. C = C & 0200000;
  276. mask_out (pimask);                    /* reset int system */
  277. reason = 0;
  278.  
  279. /* Main instruction fetch/decode loop */
  280.  
  281. while (reason == 0) {                    /* loop until halted */
  282. if (sim_interval <= 0) {                /* check clock queue */
  283.     if (reason = sim_process_event ()) break;  }
  284.  
  285. if (int_req > INT_PENDING) {                /* interrupt? */
  286.     register int MA;
  287.     int_req = int_req & ~INT_ION;
  288.     old_PC = M[0] = PC;
  289.     MA = M[1];
  290.     for (i = 0; i < ind_max; i++) {            /* count indirects */
  291.         if ((MA & 0100000) == 0) break;
  292.         if ((MA & 077770) == 020)
  293.             MA = (M[MA] = (M[MA] + 1) & 0177777);
  294.         else if ((MA & 077770) == 030)
  295.             MA = (M[MA] = (M[MA] - 1) & 0177777);
  296.         else MA = M[MA];  }
  297.     if (i >= ind_max) {
  298.         reason = STOP_IND_INT;
  299.         break;  }
  300.     PC = MA;  }                    /* end interrupt */
  301.  
  302. if (PC == ibkpt_addr) {                    /* breakpoint? */
  303.     save_ibkpt = ibkpt_addr;            /* save address */
  304.     ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG;        /* disable */
  305.     sim_activate (&cpu_unit, 1);            /* sched re-enable */
  306.     reason = STOP_IBKPT;                /* stop simulation */
  307.     break;  }
  308.  
  309. IR = M[PC];                        /* fetch instr */
  310. PC = (PC + 1) & ADDRMASK;
  311. int_req = int_req | INT_NO_ION_PENDING;            /* clear ION delay */
  312. sim_interval = sim_interval - 1;
  313. t = IR >> 11;                        /* prepare to decode */
  314.  
  315. /* Memory reference instructions */
  316.  
  317. if (t < 014) {                        /* mem ref? */
  318.     register int src, MA;
  319.     MA = IR & 0377;
  320.     switch ((IR >> 8) & 03) {            /* decode IR<6:7> */
  321.     case 0:                        /* page zero */
  322.         break;
  323.     case 1:                        /* PC relative */
  324.         if (MA & 0200) MA = 077400 | MA;
  325.         MA = (MA + PC - 1) & ADDRMASK;
  326.         break;
  327.     case 2:                        /* AC2 relative */
  328.         if (MA & 0200) MA = 077400 | MA;
  329.         MA = (MA + AC[2]) & ADDRMASK;
  330.         break;
  331.     case 3:                        /* AC3 relative */
  332.         if (MA & 0200) MA = 077400 | MA;
  333.         MA = (MA + AC[3]) & ADDRMASK;
  334.         break;  }                /* end switch mode */
  335.  
  336.     if (IR & 002000) {                /* indirect? */
  337.         for (i = 0; i < ind_max; i++) {        /* count indirects */
  338.             if ((MA & 077770) == 020)
  339.                 MA = (M[MA] = (M[MA] + 1) & 0177777);
  340.             else if ((MA & 077770) == 030)
  341.                 MA = (M[MA] = (M[MA] - 1) & 0177777);
  342.             else MA = M[MA];
  343.             if ((MA & 0100000) == 0) break;  }
  344.         if (i >= ind_max) {
  345.             reason = STOP_IND;
  346.             break;  }  }
  347.  
  348. /* Memory reference, continued */
  349.  
  350.     switch (t) {                    /* decode IR<1:4> */
  351.     case 001:                    /* JSR */
  352.         AC[3] = PC;
  353.     case 000:                    /* JMP */
  354.         old_PC = PC;
  355.         PC = MA;
  356.         break;
  357.     case 002:                    /* ISZ */
  358.         src = (M[MA] + 1) & 0177777;
  359.         if (MEM_ADDR_OK (MA)) M[MA] = src;
  360.         if (src == 0) PC = (PC + 1) & ADDRMASK;
  361.         break;
  362.     case 003:                    /* DSZ */
  363.         src = (M[MA] - 1) & 0177777;
  364.         if (MEM_ADDR_OK (MA)) M[MA] = src;
  365.         if (src == 0) PC = (PC + 1) & ADDRMASK;
  366.         break;
  367.     case 004:                    /* LDA 0 */
  368.         AC[0] = M[MA];
  369.         break;
  370.     case 005:                    /* LDA 1 */
  371.         AC[1] = M[MA];
  372.         break;
  373.     case 006:                    /* LDA 2 */
  374.         AC[2] = M[MA];
  375.         break;
  376.     case 007:                    /* LDA 3 */
  377.         AC[3] = M[MA];
  378.         break;
  379.     case 010:                    /* STA 0 */
  380.         if (MEM_ADDR_OK (MA)) M[MA] = AC[0];
  381.         break;
  382.     case 011:                    /* STA 1 */
  383.         if (MEM_ADDR_OK (MA)) M[MA] = AC[1];
  384.         break;
  385.     case 012:                    /* STA 2 */
  386.         if (MEM_ADDR_OK (MA)) M[MA] = AC[2];
  387.         break;
  388.     case 013:                    /* STA 3 */
  389.         if (MEM_ADDR_OK (MA)) M[MA] = AC[3];
  390.         break;  }                /* end switch */
  391.     }                        /* end mem ref */
  392.  
  393. /* Operate instruction */
  394.  
  395. else if (t & 020) {                    /* operate? */
  396.     register int src, srcAC, dstAC;
  397.     srcAC = (t >> 2) & 3;                /* get reg decodes */
  398.     dstAC = t & 03;
  399.     switch ((IR >> 4) & 03) {            /* decode IR<10:11> */
  400.     case 0:                        /* load */
  401.         src = AC[srcAC] | C;
  402.         break;
  403.     case 1:                        /* clear */
  404.         src = AC[srcAC];
  405.         break;
  406.     case 2:                        /* set */
  407.         src = AC[srcAC] | 0200000;
  408.         break;
  409.     case 3:                        /* complement */
  410.         src = AC[srcAC] | (C ^ 0200000);
  411.         break;  }                /* end switch carry */
  412.     switch ((IR >> 8) & 07) {            /* decode IR<5:7> */
  413.     case 0:                        /* COM */
  414.         src = src ^ 0177777;
  415.         break;
  416.     case 1:                        /* NEG */
  417.         src = ((src ^ 0177777) + 1) & 0377777;
  418.         break;
  419.     case 2:                        /* MOV */
  420.         break;
  421.     case 3:                        /* INC */
  422.         src = (src + 1) & 0377777;
  423.         break;
  424.     case 4:                        /* ADC */
  425.         src = ((src ^ 0177777) + AC[dstAC]) & 0377777;
  426.         break;
  427.     case 5:                        /* SUB */
  428.         src = ((src ^ 0177777) + AC[dstAC] + 1) & 0377777;
  429.         break;
  430.     case 6:                        /* ADD */
  431.         src = (src + AC[dstAC]) & 0377777;
  432.         break;
  433.     case 7:                        /* AND */
  434.         src = src & (AC[dstAC] | 0200000);
  435.         break;  }                /* end switch oper */
  436.  
  437. /* Operate, continued */
  438.  
  439.     switch ((IR >> 6) & 03) {            /* decode IR<8:9> */
  440.     case 0:                        /* nop */
  441.         break;
  442.     case 1:                        /* L */
  443.         src = ((src << 1) | (src >> 16)) & 0377777;
  444.         break;
  445.     case 2:                        /* R */
  446.         src = ((src >> 1) | (src << 16)) & 0377777;
  447.         break;
  448.     case 3:                        /* S */
  449.         src = ((src & 0377) << 8) | ((src >> 8) & 0377) |
  450.             (src & 0200000);
  451.         break;  }                /* end switch shift */
  452.     switch (IR & 07) {                /* decode IR<13:15> */
  453.     case 0:                        /* nop */
  454.         break;
  455.     case 1:                        /* SKP */
  456.         PC = (PC + 1) & ADDRMASK;
  457.         break;
  458.     case 2:                     /* SZC */
  459.         if (src < 0200000) PC = (PC + 1) & ADDRMASK;
  460.         break;
  461.     case 3:                        /* SNC */
  462.         if (src >= 0200000) PC = (PC + 1) & ADDRMASK;
  463.         break;
  464.     case 4:                        /* SZR */
  465.         if ((src & 0177777) == 0) PC = (PC + 1) & ADDRMASK;
  466.         break;
  467.     case 5:                        /* SNR */
  468.         if ((src & 0177777) != 0) PC = (PC + 1) & ADDRMASK;
  469.         break;
  470.     case 6:                        /* SEZ */
  471.         if (src <= 0200000) PC = (PC + 1) & ADDRMASK;
  472.         break;
  473.     case 7:                        /* SBN */
  474.         if (src > 0200000) PC = (PC + 1) & ADDRMASK;
  475.         break;  }                /* end switch skip */
  476.     if ((IR & 000010) == 0) {            /* load? */
  477.         AC[dstAC] = src & 0177777;
  478.         C = src & 0200000;  }            /* end if load */
  479.     }                        /* end if operate */
  480.  
  481. /* IOT instruction */
  482.  
  483. else {                            /* IOT */
  484.     register int dstAC, pulse, code, device, iodata;
  485.     dstAC = t & 03;                    /* decode fields */
  486.     code = (IR >> 8) & 07;
  487.     pulse = (IR >> 6) & 03;
  488.     device = IR & 077;
  489.     if (code == ioSKP) {                /* IO skip? */
  490.         switch (pulse) {            /* decode IR<8:9> */
  491.         case 0:                    /* skip if busy */
  492.             if ((device == 077)? (int_req & INT_ION) != 0:
  493.                 (dev_busy & dev_table[device].mask) != 0)
  494.                 PC = (PC + 1) & ADDRMASK;
  495.             break;
  496.         case 1:                    /* skip if not busy */
  497.             if ((device == 077)? (int_req & INT_ION) == 0:
  498.                 (dev_busy & dev_table[device].mask) == 0)
  499.                 PC = (PC + 1) & ADDRMASK;
  500.             break;
  501.         case 2:                    /* skip if done */
  502.             if ((device == 077)? pwr_low != 0:
  503.                 (dev_done & dev_table[device].mask) != 0)
  504.                 PC = (PC + 1) & ADDRMASK;
  505.             break;
  506.         case 3:                    /* skip if not done */
  507.             if ((device == 077)? pwr_low == 0:
  508.                 (dev_done & dev_table[device].mask) == 0)
  509.                 PC = (PC + 1) & ADDRMASK;
  510.             break;  }            /* end switch */
  511.         }                    /* end IO skip */
  512.  
  513.     else if ((device == DEV_MDV) && (dstAC == 2) && 
  514.          (code == ioDOC) && (cpu_unit.flags && UNIT_MDV)) {
  515.         register unsigned int mddata, uAC0, uAC1, uAC2;
  516.         uAC0 = (unsigned int) AC[0];
  517.         uAC1 = (unsigned int) AC[1];
  518.         uAC2 = (unsigned int) AC[2];
  519.  
  520.         if (pulse == iopP) {            /* mul */
  521.             mddata = (uAC1 * uAC2) + uAC0;
  522.             AC[0] = (mddata >> 16) & 0177777;
  523.             AC[1] = mddata & 0177777;  }
  524.         else if (pulse == iopS) {        /* divide */
  525.             if (uAC0 >= uAC2) C = 0200000;
  526.             else {    C = 0;
  527.                 mddata = (uAC0 << 16) | uAC1;
  528.                 AC[1] = mddata / uAC2;
  529.                 AC[0] = mddata % uAC2;  }  }
  530.         }                    /* end mul/div */
  531.  
  532. /* IOT, continued */
  533.  
  534.     else if (device == DEV_CPU) {            /* CPU control */
  535.         switch (code) {                /* decode IR<5:7> */
  536.         case ioDIA:                /* read switches */
  537.             AC[dstAC] = SR;
  538.             break;
  539.         case ioDIB:                /* int ack */
  540.             AC[dstAC] = 0;
  541.             int_req = (int_req & ~INT_DEV) |
  542.                 (dev_done & ~dev_disable);
  543.             iodata = int_req & (-int_req);
  544.             for (i = DEV_LOW; i <= DEV_HIGH; i++)  {
  545.                 if (iodata & dev_table[i].mask) {
  546.                     AC[dstAC] = i; break;   }  }
  547.             break;
  548.         case ioDOB:                /* mask out */
  549.             mask_out (pimask = AC[dstAC]);
  550.             break;
  551.         case ioDIC:                /* io reset */
  552.             reset_all (0);            /* reset devices */
  553.             break;
  554.         case ioDOC:                /* halt */
  555.             reason = STOP_HALT;
  556.             break;  }            /* end switch code */
  557.         switch (pulse) {            /* decode IR<8:9> */
  558.         case iopS:                /* ion */
  559.             int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING;
  560.             break;
  561.         case iopC:                /* iof */
  562.             int_req = int_req & ~INT_ION;
  563.             break;  }            /* end switch pulse */
  564.         }                    /* end CPU control */
  565.     else {                        /* normal device */
  566.         iodata = dev_table[device].routine (pulse, code, AC[dstAC]);
  567.         reason = iodata >> IOT_V_REASON;
  568.         if (code & 1) AC[dstAC] = iodata & 0177777;  }
  569.     }                        /* end if IOT */
  570. }                            /* end while */
  571.  
  572. /* Simulation halted */
  573.  
  574. saved_PC = PC;
  575. return reason;
  576. }
  577.  
  578. /* Null device */
  579.  
  580. int nulldev (int pulse, int code, int AC)
  581. {
  582. return stop_dev << IOT_V_REASON;
  583. }
  584.  
  585. /* New priority mask out */
  586.  
  587. void mask_out (int newmask)
  588. {
  589. int i;
  590.  
  591. dev_disable = 0;
  592. for (i = DEV_LOW; i <= DEV_HIGH; i++)  {
  593.     if (newmask & dev_table[i].pi)
  594.         dev_disable = dev_disable | dev_table[i].mask;  }
  595. int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  596. return;
  597. }
  598.  
  599. /* Reset routine */
  600.  
  601. int cpu_reset (DEVICE *dptr)
  602. {
  603. C = 0;
  604. int_req = int_req & ~INT_ION;
  605. pimask = 0;
  606. dev_disable = 0;
  607. pwr_low = 0;
  608. return cpu_svc (&cpu_unit);
  609. }
  610.  
  611. /* Memory examine */
  612.  
  613. int cpu_ex (int *vptr, int addr, UNIT *uptr, int sw)
  614. {
  615. if (addr >= MEMSIZE) return SCPE_NXM;
  616. if (vptr != NULL) *vptr = M[addr] & 0177777;
  617. return SCPE_OK;
  618. }
  619.  
  620. /* Memory deposit */
  621.  
  622. int cpu_dep (int val, int addr, UNIT *uptr, int sw)
  623. {
  624. if (addr >= MEMSIZE) return SCPE_NXM;
  625. M[addr] = val & 0177777;
  626. return SCPE_OK;
  627. }
  628.  
  629. /* Breakpoint service */
  630.  
  631. int cpu_svc (UNIT *uptr)
  632. {
  633. if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
  634. save_ibkpt = -1;
  635. return SCPE_OK;
  636. }
  637.  
  638. int cpu_set_size (UNIT *uptr, int value)
  639. {
  640. int i, mc = 0;
  641. extern int get_yn (char *ques, int deflt);
  642.  
  643. if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
  644.     return SCPE_ARG;
  645. for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
  646. if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
  647.     return SCPE_OK;
  648. MEMSIZE = value;
  649. for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
  650. return SCPE_OK;
  651. }
  652.