1 /* hp3000_cpu_base.c: HP 3000 CPU base set instruction simulator
2 
3    Copyright (c) 2016-2019, J. David Bryan
4 
5    Permission is hereby granted, free of charge, to any person obtaining a copy
6    of this software and associated documentation files (the "Software"), to deal
7    in the Software without restriction, including without limitation the rights
8    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9    copies of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18    AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22    Except as contained in this notice, the name of the author shall not be used
23    in advertising or otherwise to promote the sale, use or other dealings in
24    this Software without prior written authorization from the author.
25 
26    09-Dec-19    JDB     Replaced debugging macros with tracing macros
27    27-Dec-18    JDB     Revised fall through comments to comply with gcc 7
28    08-Jan-17    JDB     Fixed bug in SCAL 0/PCAL 0 if a stack overflow occurs
29    07-Nov-16    JDB     SETR doesn't set cpu_base_changed if no register change;
30                         renamed cpu_byte_to_word_ea to cpu_byte_ea
31    03-Nov-16    JDB     Added zero offsets to the cpu_call_procedure calls
32    24-Oct-16    JDB     Renamed SEXT macro to SEXT16
33    22-Oct-16    JDB     Changed "interrupt_pending" to global for use by CIS
34    07-Oct-16    JDB     Moved "extern cpu_dev" to hp3000_cpu.h where it belongs
35    22-Sep-16    JDB     Moved byte_to_word_address to hp3000_cpu.c
36    21-Sep-16    JDB     Added the COBOL II Extended Instruction Set dispatcher
37    12-Sep-16    JDB     Use the PCN_SERIES_II and PCN_SERIES_III constants
38    23-Aug-16    JDB     Implement the CMD instruction and module interrupts
39    11-Jun-16    JDB     Bit mask constants are now unsigned
40    13-Jan-16    JDB     First release version
41    11-Dec-12    JDB     Created
42 
43    References:
44      - HP 3000 Series II System Microprogram Listing
45          (30000-90023, August 1976)
46      - HP 3000 Series II/III System Reference Manual
47          (30000-90020, July 1978)
48      - Machine Instruction Set Reference Manual
49          (30000-90022, June 1984)
50 
51 
52    This module implements all of the HP 3000 Series II/III base set
53    instructions, except for the memory address instructions, which are
54    implemented in the main CPU module.
55 
56 
57    Implementation notes:
58 
59     1. Each instruction executor begins with a comment listing the instruction
60        mnemonic and, following in parentheses, the condition code setting, or
61        "none" if the condition code is not altered, and a list of any traps that
62        might be generated.  The condition code and trap mnemonics are those used
63        in the Machine Instruction Set manual.
64 
65     2. In the instruction executors, "TOS" refers to the top-of-the-stack value,
66        and "NOS" refers to the next-to-the-top-of-the-stack value.
67 
68     3. The order of operations in the executors follows the microcode so that
69        the registers, condition code, etc. have the expected values if stack
70        overflow or underflow traps occur.
71 
72     4. There is no common "cpu_div_16" routine, as each of the five base-set
73        division instructions (DIVI, DIV, LDIV, DIVL, and DDIV) has a different
74        overflow condition.  Therefore, they are all implemented inline.
75 */
76 
77 
78 
79 #include "hp3000_defs.h"
80 #include "hp3000_cpu.h"
81 #include "hp3000_cpu_fp.h"
82 #include "hp3000_cpu_ims.h"
83 #include "hp3000_mem.h"
84 
85 
86 
87 /* Program constants */
88 
89 #define SIO_OK              0100000u            /* TIO bit 0 = SIO OK */
90 #define DIO_OK              0040000u            /* TIO bit 1 = DIO OK */
91 
92 #define NORM_BIT            (D48_SIGN >> 6)     /* triple normalizing examines bit 6 */
93 #define NORM_MASK           (D48_MASK >> 6)     /* triple normalizing masks off bits 0-5 */
94 
95 #define TO_UPPERCASE(b)     ((b) & ~040u)       /* alphabetic byte upshift */
96 
97 
98 /* CPU base set global data structures */
99 
100 typedef enum {                                  /* types of shifts */
101     arithmetic,                                 /*   arithmetic shift */
102     logical,                                    /*   logical shift */
103     circular,                                   /*   circular shift (rotate) */
104     normalizing                                 /*   normalizing shift */
105     } SHIFT_TYPE;
106 
107 typedef enum {                                  /* shift operand sizes */
108     size_16,                                    /*   16-bit single word */
109     size_32,                                    /*   32-bit double word */
110     size_48,                                    /*   48-bit triple word */
111     size_64                                     /*   64-bit quad word */
112     } OPERAND_SIZE;
113 
114 
115 /* CPU base set local utility routines */
116 
117 static uint32 add_32               (uint32 augend,  uint32 addend);
118 static uint32 sub_32               (uint32 minuend, uint32 subtrahend);
119 static void   shift_16_32          (HP_WORD opcode, SHIFT_TYPE shift, OPERAND_SIZE op_size);
120 static void   shift_48_64          (HP_WORD opcode, SHIFT_TYPE shift, OPERAND_SIZE op_size);
121 static void   check_stack_bounds   (HP_WORD new_value);
122 static uint32 tcs_io               (IO_COMMAND command);
123 static uint32 srw_io               (IO_COMMAND command, HP_WORD ready_flag);
124 static void   decrement_stack      (uint32 decrement);
125 
126 static t_stat move_words           (ACCESS_CLASS source_class, uint32 source_base,
127                                     ACCESS_CLASS dest_class,   uint32 dest_base,
128                                     uint32 decrement);
129 
130 /* CPU base set local instruction execution routines */
131 
132 static t_stat move_spec          (void);
133 static t_stat firmware_extension (void);
134 static t_stat io_control         (void);
135 
136 
137 
138 /* CPU base set global utility routines */
139 
140 
141 /* Test for a pending interrupt.
142 
143    This routine is called from within an executor for an interruptible
144    instruction to test for a pending interrupt.  It counts an event tick and
145    returns TRUE if the instruction should yield, either for an interrupt or for
146    an event error, or FALSE if the instruction should continue.
147 
148    Instructions that potentially take a long time (e.g., MOVE, SCU, LLSH) test
149    for pending interrupts after each word or byte moved or scanned.  The design
150    of these instructions is such that an interrupt may be serviced and the
151    instruction resumed without disruption.  For example, the MOVE instruction
152    updates the source and target addresses and word count on the stack after
153    each word moved.  If the instruction is interrupted, the values on the stack
154    indicate where to resume after the interrupt handler completes.
155 
156 
157    Implementation notes:
158 
159     1. The routine is essentially the same sequence as is performed at the top
160        of the instruction execution loop in the "sim_instr" routine.  The
161        differences are that this routine backs up P to rerun the instruction
162        after the interrupt is serviced, and the interrupt holdoff test necessary
163        for the SED instruction isn't done here, as this routine is not called by
164        the SED executor.
165 
166     2. The event interval decrement that occurs in the main instruction loop
167        after each instruction execution is cancelled here if "sim_process_event"
168        returns an error code.  This is done so that a STEP command does not
169        decrement sim_interval twice.  Note that skipping the initial decrement
170        here does not help, as it's the sim_interval value AFTER the call to
171        sim_process_event that must be preserved.
172 */
173 
cpu_interrupt_pending(t_stat * status)174 t_bool cpu_interrupt_pending (t_stat *status)
175 {
176 uint32 device_number = 0;
177 
178 sim_interval = sim_interval - 1;                        /* count the cycle */
179 
180 if (sim_interval <= 0) {                                /* if an event timeout expired */
181     *status = sim_process_event ();                     /*   then process the event service */
182 
183     if (*status != SCPE_OK) {                           /* if the service failed */
184         P = P - 1 & R_MASK;                             /*   then back up to reenter the instruction */
185         sim_interval = sim_interval + 1;                /*     and cancel the instruction loop increment */
186 
187         return TRUE;                                    /* abort the instruction and stop the simulator */
188         }
189     }
190 
191 else                                                    /* otherwise */
192     *status = SCPE_OK;                                  /*   indicate good status from the service */
193 
194 if (sel_request)                                        /* if a selector channel request is pending */
195     sel_service (1);                                    /*   then service it */
196 
197 if (mpx_request_set)                                    /* if a multiplexer channel request is pending */
198     mpx_service (1);                                    /*   then service it */
199 
200 if (iop_interrupt_request_set && STA & STATUS_I)        /* if a hardware interrupt request is pending and enabled */
201     device_number = iop_poll ();                        /*   then poll to acknowledge the request */
202 
203 if (CPX1 & CPX1_IRQ_SET) {                              /* if an interrupt is pending */
204     P = P - 1 & R_MASK;                                 /*   then back up to reenter the instruction */
205     cpu_run_mode_interrupt (device_number);             /*     and set up the service routine */
206 
207     return TRUE;                                        /* abort the instruction */
208     }
209 
210 else                                                    /* otherwise */
211     return FALSE;                                       /*   continue with the current instruction */
212 }
213 
214 
215 /* Execute a short branch.
216 
217    The program counter is adjusted by the displacement specified in the CIR, and
218    the NIR is loaded with the target instruction.  If the "check_loop" parameter
219    is TRUE, an infinite loop check is made if the corresponding simulator stop
220    is enabled.  Branch instructions that cannot cause an infinite loop because
221    they modify the CPU state during execution will specify the parameter as
222    FALSE.
223 
224    On entry, the CIR must be loaded with a branch instruction having a short
225    (5-bit plus sign bit) displacement.  The instruction format is:
226 
227        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
228      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
229      | 0   0   0   1 | I |   branch opcode   |+/-|  P displacement   |  Branch
230      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
231 
232    On exit, the NIR and P registers are updated, and STOP_INFLOOP is returned if
233    an infinite loop is enabled and was detected, or SCPE_OK is returned if
234    simulation may continue.
235 */
236 
cpu_branch_short(t_bool check_loop)237 t_stat cpu_branch_short (t_bool check_loop)
238 {
239 HP_WORD displacement, address;
240 t_stat  status;
241 
242 displacement = CIR & DISPL_31_MASK;                     /* get the displacement */
243 
244 if (CIR & DISPL_31_SIGN)                                /* if the displacement is negative */
245     address = P - 2 - displacement & LA_MASK;           /*   then subtract the displacement from the base */
246 else                                                    /* otherwise */
247     address = P - 2 + displacement & LA_MASK;           /*   add the displacement to the base */
248 
249 if ((CIR & I_FLAG_BIT_4) != 0) {                                /* if the mode is indirect */
250     cpu_read_memory (program_checked, address, &displacement);  /*   then get the displacement value */
251 
252     address = address + displacement & LA_MASK;         /* add the displacement to the base */
253     }
254 
255 if (cpu_stop_flags & SS_LOOP                            /* if the infinite loop stop is active */
256   && check_loop                                         /*   and an infinite loop is possible */
257   && address == (P - 2 & LA_MASK))                      /*   and the target is the current instruction */
258     status = STOP_INFLOOP;                              /*     then stop the simulator */
259 else                                                    /* otherwise */
260     status = SCPE_OK;                                   /*   continue */
261 
262 cpu_read_memory (fetch_checked, address, &NIR);         /* load the next instruction register */
263 P = address + 1 & R_MASK;                               /*   and increment the program counter */
264 
265 return status;                                          /* return the execution status */
266 }
267 
268 
269 /* Add two 16-bit numbers.
270 
271    Two 16-bit values are added, and the 16-bit sum is returned.  The C (carry)
272    bit in the status register is set if the result is truncated and cleared
273    otherwise.  The O (overflow) bit is set if the result exceeds the maximum
274    positive or negative range, i.e., the result overflows into the sign bit.  In
275    addition, an integer overflow interrupt (ARITH trap) occurs if the user trap
276    bit is set.
277 */
278 
cpu_add_16(HP_WORD augend,HP_WORD addend)279 HP_WORD cpu_add_16 (HP_WORD augend, HP_WORD addend)
280 {
281 uint32 sum;
282 
283 sum = augend + addend;                                  /* sum the values */
284 
285 SET_CARRY (sum > D16_UMAX);                             /* set C if there's a carry out of the MSB */
286 
287 SET_OVERFLOW (D16_SIGN                                  /* set O if the signs */
288                 & (~augend ^ addend)                    /*   of the operands are the same */
289                 & (augend ^ sum));                      /*     but the sign of the result differs */
290 
291 return (HP_WORD) LOWER_WORD (sum);                      /* return the lower 16 bits of the sum */
292 }
293 
294 
295 /* Subtract two 16-bit numbers.
296 
297    Two 16-bit values are subtracted, and the 16-bit difference is returned.  The
298    C (carry) bit in the status register is set if the subtraction did not
299    require a borrow for the most-significant bit.  The O (overflow) bit is set
300    if the result exceeds the maximum positive or negative range, i.e., the
301    result borrows from the sign bit.  In addition, an integer overflow interrupt
302    (ARITH trap) occurs if the user trap bit is set.
303 
304 
305    Implementation notes:
306 
307     1. The carry bit is set to the complement of the borrow, i.e., carry = 0 if
308        there is a borrow and 1 is there is not.
309 */
310 
cpu_sub_16(HP_WORD minuend,HP_WORD subtrahend)311 HP_WORD cpu_sub_16 (HP_WORD minuend, HP_WORD subtrahend)
312 {
313 uint32 difference;
314 
315 difference = minuend - subtrahend;                      /* subtract the values */
316 
317 SET_CARRY (subtrahend <= minuend);                      /* set C if no borrow from the MSB was done */
318 
319 SET_OVERFLOW (D16_SIGN                                  /* set O if the signs */
320                & (minuend ^ subtrahend)                 /*   of the operands differ */
321                & (minuend ^ difference));               /*     as do the signs of the minuend and result */
322 
323 return (HP_WORD) LOWER_WORD (difference);               /* return the lower 16 bits of the difference */
324 }
325 
326 
327 /* Multiply two 16-bit numbers.
328 
329    Two 16-bit values are multiplied, and the 16-bit product is returned.  The O
330    (overflow) bit in the status register is set if the result exceeds the
331    maximum positive or negative range, i.e., if the top 17 bits of the 32-bit
332    result are not all zeros or ones.  In addition, an integer overflow interrupt
333    (ARITH trap) occurs if the user trap bit is set.
334 */
335 
cpu_mpy_16(HP_WORD multiplicand,HP_WORD multiplier)336 HP_WORD cpu_mpy_16 (HP_WORD multiplicand, HP_WORD multiplier)
337 {
338 int32  product;
339 uint32 check;
340 
341 product = SEXT16 (multiplicand) * SEXT16 (multiplier);  /* sign-extend the operands and multiply */
342 
343 check = (uint32) product & S16_OVFL_MASK;               /* check the top 17 bits and set overflow */
344 SET_OVERFLOW (check != 0 && check != S16_OVFL_MASK);    /*   if they are not all zeros or all ones */
345 
346 return (HP_WORD) LOWER_WORD (product);                  /* return the lower 16 bits of the product */
347 }
348 
349 
350 
351 /* CPU base set global instruction execution routines */
352 
353 
354 /* Execute a stack instruction (subopcode 00).
355 
356    This routine is called to execute a single stack instruction held in the CIR.
357    The instruction format is:
358 
359        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
360      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
361      | 0   0   0   0 |   1st stack opcode    |   2nd stack opcode    |  Stack
362      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
363 
364    As a single program word holds two stack opcodes, this routine is generally
365    called twice.  If the R (right-hand) bit in the status register is set, the
366    opcode in the lower six bits of the CIR is executed; otherwise, the opcode in
367    the upper six bits is executed.  The R bit is set when the left-hand opcode
368    is executing if the right-hand opcode is not a NOP.  This is an optimization
369    that causes the instruction loop to fetch the next instruction in lieu of
370    calling this routine again to execute the right-hand NOP.  The R bit also
371    marks a pending right-hand stack opcode execution when an interrupt is
372    detected after the left-hand stack opcode completes.
373 
374 
375    Implementation notes:
376 
377     1. The entry status must be saved so that it may be restored if the
378        unimplemented opcode 072 is executed with the SS_UNIMPL simulator stop
379        flag set.  This allows the instruction to be reexecuted and the
380        Unimplemented Instruction trap taken if the stop is subsequently
381        bypassed.
382 
383     2. In hardware, the NEXT microcode order present at the end of each
384        instruction transfers the NIR content to the CIR, reads the memory word
385        at P into the NIR, and increments P.  However, if an interrupt is
386        present, then this action is omitted, and a microcode jump is performed
387        to control store location 3, which then jumps to the microcoded interrupt
388        handler.  In simulation, the CIR/NIR/P update is performed before the
389        next instruction is executed, rather than after the last instruction
390        completes, so that interrupts are handled before updating.
391 
392        In addition, the NEXT action is modified in hardware if the NIR contains
393        a stack instruction with a non-NOP B (right-hand) stack opcode.  In this
394        case, NEXT transfers the NIR content to the CIR, reads the memory word at
395        P into the NIR, but does not increment P.  Instead, the R bit of the
396        status register is set to indicate that a B stackop is pending.  When the
397        NEXT at the completion of the A (left-hand) stackop is executed, the NIR
398        and CIR are untouched, but P is incremented, and the R bit is cleared.
399        This ensures that if an interrupt or trap occurs between the stackops, P
400        will point correctly at the next instruction to be executed.
401 
402        In simulation, following the hardware would require testing the NIR for a
403        non-NOP B stackop at every pass through the instruction execution loop.
404        To avoid this, the NEXT simulation unilaterally increments P, rather than
405        only when a B stackop is not present, and the stack instruction executor
406        tests for the B stackop and sets the R bit there.  However, by that time,
407        P has already been incremented, so we decrement it here to return it to
408        the correct value.
409 
410     3. Increments, decrements, and negates use the "cpu_add_16" and "cpu_sub_16"
411        instead of inline adds and subtracts in order to set the carry and
412        overflow status bits properly.
413 
414     4. On division by zero, the FDIV microcode sets condition code CCA before
415        trapping.  All other floating-point arithmetic traps are taken before
416        setting the condition code.
417 */
418 
cpu_stack_op(void)419 t_stat cpu_stack_op (void)
420 {
421 static const uint8 preadjustment [64] = {       /* stack preadjustment, indexed by operation */
422     0, 2, 2, 0, 0, 0, 0, 0,                     /*   NOP  DELB DDEL ZROX INCX DECX ZERO DZRO */
423     4, 4, 4, 2, 3, 2, 4, 2,                     /*   DCMP DADD DSUB MPYL DIVL DNEG DXCH CMP  */
424     2, 2, 2, 2, 1, 1, 2, 2,                     /*   ADD  SUB  MPY  DIV  NEG  TEST STBX DTST */
425     2, 1, 2, 1, 1, 1, 1, 1,                     /*   DFLT BTST XCH  INCA DECA XAX  ADAX ADXA */
426     1, 2, 2, 1, 0, 1, 2, 1,                     /*   DEL  ZROB LDXB STAX LDXA DUP  DDUP FLT  */
427     4, 4, 4, 4, 4, 2, 3, 2,                     /*   FCMP FADD FSUB FMPY FDIV FNEG CAB  LCMP */
428     2, 2, 2, 3, 1, 2, 2, 2,                     /*   LADD LSUB LMPY LDIV NOT  OR   XOR  AND  */
429     2, 2, 0, 2, 2, 2, 2, 2                      /*   FIXR FIXT  --  INCB DECB XBX  ADBX ADXB */
430     };
431 
432 HP_WORD entry_status, exchanger;
433 uint32  operation, sum, difference, uproduct, udividend, uquotient, uremainder, check;
434 int32   product, dividend, divisor, quotient, remainder;
435 FP_OPND operand_u, operand_v, operand_w;
436 t_stat  status = SCPE_OK;
437 
438 entry_status = STA;                                     /* save the entry status for a potential rollback */
439 
440 if (STA & STATUS_R) {                                   /* if right-hand stackop is pending */
441     operation = STACKOP_B (CIR);                        /*   then get the right-hand opcode */
442     STA &= ~STATUS_R;                                   /*     and flip the flag off */
443     }
444 
445 else {                                                  /* otherwise */
446     operation = STACKOP_A (CIR);                        /*   get the left-hand opcode */
447 
448     if (STACKOP_B (CIR) != NOP) {                       /* if the right-hand opcode is a not a NOP */
449         STA |= STATUS_R;                                /*   then set the right-hand stackop pending flag */
450         P = P - 1 & R_MASK;                             /*     and decrement P to cancel the later increment */
451         }
452     }
453 
454 PREADJUST_SR (preadjustment [operation]);               /* preadjust the TOS registers to the required number */
455 
456 switch (operation) {                                    /* dispatch the stack operation */
457 
458     case 000:                                           /* NOP (none; none)*/
459         break;                                          /* there is nothing to do for a no-operation */
460 
461 
462     case 001:                                           /* DELB (none; STUN) */
463         RB = RA;                                        /* copy the TOS into the NOS */
464         cpu_pop ();                                     /*   and pop the TOS, effectively deleting the NOS */
465         break;
466 
467 
468     case 002:                                           /* DDEL (none; STUN) */
469         cpu_pop ();                                     /* pop the TOS */
470         cpu_pop ();                                     /*   and the NOS */
471         break;
472 
473 
474     case 003:                                           /* ZROX (none; none) */
475         X = 0;                                          /* set X to zero */
476         break;
477 
478 
479     case 004:                                           /* INCX (CCA, C, O; ARITH) */
480         X = cpu_add_16 (X, 1);                          /* increment X */
481         SET_CCA (X, 0);                                 /*   and set the condition code */
482         break;
483 
484 
485     case 005:                                           /* DECX (CCA, C, O; ARITH) */
486         X = cpu_sub_16 (X, 1);                          /* decrement X */
487         SET_CCA (X, 0);                                 /*   and set the condition code */
488         break;
489 
490 
491     case 006:                                           /* ZERO (none; STOV) */
492         cpu_push ();                                    /* push the stack down */
493         RA = 0;                                         /*   and set the TOS to zero */
494         break;
495 
496 
497     case 007:                                           /* DZRO (none; STOV) */
498         cpu_push ();                                    /* push the stack */
499         cpu_push ();                                    /*   down twice */
500         RA = 0;                                         /* set the TOS */
501         RB = 0;                                         /*   and NOS to zero */
502         break;
503 
504 
505     case 010:                                           /* DCMP (CCC; STUN) */
506         SR = 0;                                         /* pop all four values from the stack */
507         SET_CCC (RD, RC, RB, RA);                       /*   and set the (integer) condition code */
508         break;
509 
510 
511     case 011:                                           /* DADD (CCA, C, O; STUN, ARTIH) */
512         sum = add_32 (TO_DWORD (RD, RC),                /* add the two 32-bit double words on the stack */
513                       TO_DWORD (RB, RA));
514 
515         RD = UPPER_WORD (sum);                          /* split the MSW */
516         RC = LOWER_WORD (sum);                          /*   and the LSW of the sum */
517 
518         cpu_pop ();                                     /* pop the old TOS */
519         cpu_pop ();                                     /*   and the old NOS */
520 
521         SET_CCA (RB, RA);                               /* set the condition code */
522         break;
523 
524 
525     case 012:                                           /* DSUB (CCA, C, O; STUN, ARTIH) */
526         difference = sub_32 (TO_DWORD (RD, RC),         /* subtract the two 32-bit double words on the stack */
527                              TO_DWORD (RB, RA));
528 
529         RD = UPPER_WORD (difference);                   /* split the MSW */
530         RC = LOWER_WORD (difference);                   /*   and the LSW of the difference */
531 
532         cpu_pop ();                                     /* pop the old TOS */
533         cpu_pop ();                                     /*   and the old NOS */
534 
535         SET_CCA (RB, RA);                               /* set the condition code */
536         break;
537 
538 
539     case 013:                                           /* MPYL (CCA, C, O; STUN, ARITH) */
540         product = SEXT16 (RA) * SEXT16 (RB);            /* sign-extend the 16-bit operands and multiply */
541 
542         RB = UPPER_WORD (product);                      /* split the MSW */
543         RA = LOWER_WORD (product);                      /*   and the LSW of the product */
544 
545         check = (uint32) product & S16_OVFL_MASK;           /* check the top 17 bits and set carry */
546         SET_CARRY (check != 0 && check != S16_OVFL_MASK);   /*   if they are not all zeros or all ones */
547 
548         STA &= ~STATUS_O;                               /* clear O as this operation cannot overflow */
549 
550         SET_CCA (RB, RA);                               /* set the condition code */
551         break;
552 
553 
554     case 014:                                           /* DIVL (CCA, O; STUN, ARITH) */
555         dividend = INT32 (TO_DWORD (RC, RB));           /* convert the 32-bit dividend to a signed value */
556         divisor  = SEXT16 (RA);                         /*   and sign-extend the 16-bit divisor */
557 
558         RB = RA;                                        /* delete the LSW from the stack now */
559         cpu_pop ();                                     /*   to conform with the microcode */
560 
561         if (RA == 0)                                    /* if dividing by zero */
562             MICRO_ABORT (trap_Integer_Zero_Divide);     /*   then trap or set the overflow flag */
563 
564         if (abs (divisor) <= abs (SEXT16 (RB)))         /* if the divisor is <= the MSW of the dividend */
565             SET_OVERFLOW (TRUE);                        /*   an overflow will occur on the division */
566 
567         else {                                          /* otherwise, the divisor might be large enough */
568             quotient  = dividend / divisor;             /* form the 32-bit signed quotient */
569             remainder = dividend % divisor;             /*   and 32-bit signed remainder */
570 
571             check = (uint32) quotient & S16_OVFL_MASK;              /* check the top 17 bits and set overflow */
572             SET_OVERFLOW (check != 0 && check != S16_OVFL_MASK);    /*   if they are not all zeros or all ones */
573 
574             RA = remainder & R_MASK;                    /* store the remainder on the TOS */
575             RB = quotient  & R_MASK;                    /*   and the quotient on the NOS */
576 
577             SET_CCA (RB, 0);                            /* set the condition code */
578             }
579         break;
580 
581 
582     case 015:                                           /* DNEG (CCA, O; STUN, ARITH) */
583         difference = sub_32 (0, TO_DWORD (RB, RA));     /* negate the 32-bit double word on the stack */
584 
585         RB = UPPER_WORD (difference);                   /* split the MSW */
586         RA = LOWER_WORD (difference);                   /*   and the LSW of the difference */
587 
588         SET_CCA (RB, RA);                               /* set the condition code */
589         break;
590 
591 
592     case 016:                                           /* DXCH (CCA; STUN) */
593         exchanger = RA;                                 /* exchange */
594         RA = RC;                                        /*   the TOS */
595         RC = exchanger;                                 /*     and the third stack word */
596 
597         exchanger = RB;                                 /* exchange */
598         RB = RD;                                        /*   the NOS */
599         RD = exchanger;                                 /*     and the fourth stack word */
600 
601         SET_CCA (RB, RA);                               /* set the condition code */
602         break;
603 
604 
605     case 017:                                           /* CMP (CCC; STUN) */
606         SET_CCC (RB, 0, RA, 0);                         /* set the (integer) condition code */
607         cpu_pop ();                                     /*   and pop the TOS */
608         cpu_pop ();                                     /*     and the NOS */
609         break;
610 
611 
612     case 020:                                           /* ADD (CCA, C, O; STUN, ARITH) */
613         RB = cpu_add_16 (RB, RA);                       /* add the NOS and TOS */
614 
615         SET_CCA (RB, 0);                                /* set the condition code */
616         cpu_pop ();                                     /*   and pop the old TOS */
617         break;
618 
619 
620     case 021:                                           /* SUB (CCA, C, O; STUN, ARITH) */
621         RB = cpu_sub_16 (RB, RA);                       /* subtract the NOS and TOS */
622 
623         SET_CCA (RB, 0);                                /* set the condition code */
624         cpu_pop ();                                     /*   and pop the old TOS */
625         break;
626 
627 
628     case 022:                                           /* MPY (CCA, O; STUN, ARITH) */
629         RB = cpu_mpy_16 (RA, RB);                       /* multiply the NOS and TOS */
630 
631         SET_CCA (RB, 0);                                /* set the condition code */
632         cpu_pop ();                                     /*   and pop the old TOS */
633         break;
634 
635 
636     case 023:                                           /* DIV (CCA, O; STUN, ARITH) */
637         if (RA == 0)                                    /* if dividing by zero */
638             MICRO_ABORT (trap_Integer_Zero_Divide);     /*   then trap or set the overflow flag */
639 
640         dividend = SEXT16 (RB);                         /* sign-extend the 16-bit dividend */
641         divisor  = SEXT16 (RA);                         /*   and the 16-bit divisor */
642 
643         quotient  = dividend / divisor;                 /* form the 32-bit signed quotient */
644         remainder = dividend % divisor;                 /*   and 32-bit signed remainder */
645 
646         SET_OVERFLOW (dividend == -32768 && divisor == -1); /* set overflow for -2**15 / -1 */
647 
648         RA = remainder & R_MASK;                        /* store the remainder on the TOS */
649         RB = quotient  & R_MASK;                        /*   and the quotient on the NOS */
650 
651         SET_CCA (RB, 0);                                /* set the condition code */
652         break;
653 
654 
655     case 024:                                           /* NEG (CCA, C, O; STUN, ARTIH) */
656         RA = cpu_sub_16 (0, RA);                        /* negate the TOS */
657         SET_CCA (RA, 0);                                /*   and set the condition code */
658         break;
659 
660 
661     case 025:                                           /* TEST (CCA; STUN) */
662         SET_CCA (RA, 0);                                /* set the condition code */
663         break;
664 
665 
666     case 026:                                           /* STBX (CCA; STUN) */
667         X = RB;                                         /* store the NOS into X */
668         SET_CCA (X, 0);                                 /*   and set the condition code */
669         break;
670 
671 
672     case 027:                                           /* DTST (CCA, C; STUN) */
673         SET_CCA (RB, RA);                               /* set the condition code */
674 
675         check = TO_DWORD (RB, RA) & S16_OVFL_MASK;          /* check the top 17 bits and set carry */
676         SET_CARRY (check != 0 && check != S16_OVFL_MASK);   /*   if they are not all zeros or all ones */
677         break;
678 
679 
680     case 030:                                           /* DFLT (CCA; none) */
681         operand_u.precision = in_d;                     /* set the operand precision to double integer */
682 
683         operand_u.words [0] = RB;                       /* load the MSW */
684         operand_u.words [1] = RA;                       /*   and LSW of the operand */
685 
686         operand_v = fp_exec (fp_flt, operand_u, FP_NOP);    /* convert the integer to floating point */
687 
688         RB = operand_v.words [0];                       /* unload the MSW */
689         RA = operand_v.words [1];                       /*   and the LSW of the result */
690 
691         SET_CCA (RB, RA);                               /* set the condition code */
692         break;
693 
694 
695     case 031:                                           /* BTST (CCB; STUN) */
696         SET_CCB (LOWER_BYTE (RA));                      /* set the condition code */
697         break;
698 
699 
700     case 032:                                           /* XCH (CCA; STUN) */
701         exchanger = RA;                                 /* exchange */
702         RA = RB;                                        /*   the TOS */
703         RB = exchanger;                                 /*     and the NOS */
704 
705         SET_CCA (RA, 0);                                /* set the condition code */
706         break;
707 
708 
709     case 033:                                           /* INCA (CCA, C, O; STUN, ARITH) */
710         RA = cpu_add_16 (RA, 1);                        /* increment the TOS */
711         SET_CCA (RA, 0);                                /*   and set the condition code */
712         break;
713 
714 
715     case 034:                                           /* DECA (CCA, C, O; STUN, ARITH) */
716         RA = cpu_sub_16 (RA, 1);                        /* decrement the TOS */
717         SET_CCA (RA, 0);                                /*   and set the condition code */
718         break;
719 
720 
721     case 035:                                           /* XAX (CCA; STUN) */
722         exchanger = X;                                  /* exchange */
723         X = RA;                                         /*   the TOS */
724         RA = exchanger;                                 /*     and X */
725 
726         SET_CCA (RA, 0);                                /* set the condition code */
727         break;
728 
729 
730     case 036:                                           /* ADAX (CCA, C, O; STUN, ARITH) */
731         X = cpu_add_16 (X, RA);                         /* add the TOS to X */
732         cpu_pop ();                                     /*   and pop the TOS */
733 
734         SET_CCA (X, 0);                                 /* set the condition code */
735         break;
736 
737 
738     case 037:                                           /* ADXA (CCA, C, O; STUN, ARITH) */
739         RA = cpu_add_16 (X, RA);                        /* add X to the TOS */
740         SET_CCA (RA, 0);                                /*   and set the condition code */
741         break;
742 
743 
744     case 040:                                           /* DEL (none; STUN) */
745         cpu_pop ();                                     /* pop the TOS */
746         break;
747 
748 
749     case 041:                                           /* ZROB (none; STUN) */
750         RB = 0;                                         /* set the NOS to zero */
751         break;
752 
753 
754     case 042:                                           /* LDXB (CCA; STUN) */
755         RB = X;                                         /* load X into the NOS */
756         SET_CCA (RB, 0);                                /*   and set the condition code */
757         break;
758 
759 
760     case 043:                                           /* STAX (CCA; STUN) */
761         X = RA;                                         /* store the TOS into X */
762         cpu_pop ();                                     /*   and pop the TOS */
763 
764         SET_CCA (X, 0);                                 /* set the condition code */
765         break;
766 
767 
768     case 044:                                           /* LDXA (CCA; STOV) */
769         cpu_push ();                                    /* push the stack down */
770         RA = X;                                         /*   and set the TOS to X */
771 
772         SET_CCA (RA, 0);                                /* set the condition code */
773         break;
774 
775 
776     case 045:                                           /* DUP (CCA; STUN, STOV) */
777         cpu_push ();                                    /* push the stack down */
778         RA = RB;                                        /*   and copy the old TOS to the new TOS */
779 
780         SET_CCA (RA, 0);                                /* set the condition code */
781         break;
782 
783 
784     case 046:                                           /* DDUP (CCA; STUN, STOV) */
785         cpu_push ();                                    /* push the stack */
786         cpu_push ();                                    /*   down twice */
787 
788         RA = RC;                                        /* copy the old TOS and NOS */
789         RB = RD;                                        /*   to the new TOS and NOS */
790 
791         SET_CCA (RB, RA);                               /* set the condition code */
792         break;
793 
794 
795     case 047:                                           /* FLT (CCA; none) */
796         operand_u.precision = in_s;                     /* set the operand precision to single integer */
797 
798         operand_u.words [0] = RA;                       /* load the operand */
799 
800         operand_v = fp_exec (fp_flt, operand_u, FP_NOP);    /* convert the integer to floating point */
801 
802         cpu_push ();                                    /* push the stack down */
803 
804         RB = operand_v.words [0];                       /* unload the MSW */
805         RA = operand_v.words [1];                       /*   and the LSW of the result */
806 
807         SET_CCA (RB, RA);                               /* set the condition code */
808         break;
809 
810 
811     case 050:                                           /* FCMP (CCC; STUN) */
812         if (RB & RD & D16_SIGN)                         /* if the operand signs are both negative */
813             SET_CCC (RB, RA, RD, RC);                   /*   then swap operands and compare the magnitudes */
814         else                                            /* otherwise */
815             SET_CCC (RD, RC, RB, RA);                   /*   compare them as they are */
816 
817         SR = 0;                                         /* pop all four values */
818         break;
819 
820 
821     case 051:                                           /* FADD (CCA, O; STUN, ARITH) */
822     case 052:                                           /* FSUB (CCA, O; STUN, ARITH) */
823     case 053:                                           /* FMPY (CCA, O; STUN, ARITH) */
824     case 054:                                           /* FDIV (CCA, O; STUN, ARITH) */
825         operand_u.precision = fp_f;                     /* set the operand precision to single_float */
826         operand_v.precision = fp_f;                     /*   and the result precision to single float */
827 
828         operand_u.words [0] = RD;                       /* load the MSW */
829         operand_u.words [1] = RC;                       /*   and LSW of the first operand */
830 
831         operand_v.words [0] = RB;                       /* load the MSW */
832         operand_v.words [1] = RA;                       /*   and LSW of the second operand */
833 
834         STA &= ~STATUS_O;                               /* clear the overflow flag */
835 
836         cpu_pop ();                                     /* delete two words */
837         cpu_pop ();                                     /*   from the stack */
838 
839         operand_w =                                         /* call the floating-point executor */
840            fp_exec ((FP_OPR) (operation - 051 + fp_add),    /*   and convert the opcode */
841                     operand_u, operand_v);                  /*     to an arithmetic operation */
842 
843         RB = operand_w.words [0];                       /* unload the MSW */
844         RA = operand_w.words [1];                       /*   and the LSW of the result */
845 
846         if (operand_w.trap != trap_None) {                  /* if an error occurred */
847             if (operand_w.trap == trap_Float_Zero_Divide)   /*   then if it is division by zero */
848                 SET_CCA (RB, RA);                           /*     then set the condition code */
849 
850             MICRO_ABORT (operand_w.trap);               /* trap or set overflow */
851             }
852 
853         SET_CCA (RB, RA);                               /* set the condition code */
854         break;
855 
856 
857     case 055:                                           /* FNEG (CCA; STUN) */
858         if ((RB | RA) == 0)                             /* if the floating point value is zero */
859             SET_CCE;                                    /*   then it remains zero after negation */
860 
861         else {                                          /* otherwise */
862             RB = RB ^ D16_SIGN;                         /*   flip the sign bit */
863             SET_CCA (RB, 1);                            /*     and set CCL or CCG from the sign bit */
864             }
865         break;
866 
867 
868     case 056:                                           /* CAB (CCA; STUN) */
869         exchanger = RC;                                 /* rotate */
870         RC = RB;                                        /*   the TOS */
871         RB = RA;                                        /*     the NOS */
872         RA = exchanger;                                 /*       and the third stack word */
873 
874         SET_CCA (RA, 0);                                /* set the condition code */
875         break;
876 
877 
878     case 057:                                           /* LCMP (CCC; STUN) */
879         SET_CCC (0, RB, 0, RA);                         /* set the (logical) condition code */
880 
881         cpu_pop ();                                     /* pop the TOS */
882         cpu_pop ();                                     /*   and the NOS */
883         break;
884 
885 
886     case 060:                                           /* LADD (CCA, C; STUN) */
887         sum = RB + RA;                                  /* add the values */
888 
889         SET_CARRY (sum > D16_UMAX);                     /* set C if there's a carry out of the MSB */
890 
891         RB = sum & R_MASK;                              /* store the sum in the NOS */
892         cpu_pop ();                                     /*   and pop the TOS */
893 
894         SET_CCA (RA, 0);                                /* set the (integer) condition code */
895         break;
896 
897 
898     case 061:                                           /* LSUB (CCA, C; STUN) */
899         SET_CARRY (RA <= RB);                           /* set C if there will not be a borrow by the MSB */
900 
901         RB = RB - RA & R_MASK;                          /* subtract the values */
902         cpu_pop ();                                     /*   and pop the TOS */
903 
904         SET_CCA (RA, 0);                                /* set the (integer) condition code */
905         break;
906 
907 
908     case 062:                                           /* LMPY (CCA, C; STUN) */
909         uproduct = RB * RA;                             /* multiply the operands */
910 
911         RA = LOWER_WORD (uproduct);                     /* split the MSW */
912         RB = UPPER_WORD (uproduct);                     /*   and the LSW of the product */
913 
914         SET_CARRY (RB > 0);                             /* set C if the product doesn't fit in one word */
915 
916         SET_CCA (RB, RA);                               /* set the (integer) condition code */
917         break;
918 
919 
920     case 063:                                           /* LDIV (CCA, O; STUN, ARITH) */
921         if (RA == 0)                                    /* if dividing by zero */
922             MICRO_ABORT (trap_Integer_Zero_Divide);     /*   then trap or set the overflow flag */
923 
924         udividend = TO_DWORD (RC, RB);                  /* form the 32-bit unsigned dividend */
925 
926         uquotient  = udividend / RA;                    /* form the 32-bit unsigned quotient */
927         uremainder = udividend % RA;                    /*   and 32-bit unsigned remainder */
928 
929         SET_OVERFLOW (uquotient & ~D16_MASK);           /* set O if the quotient needs more than 16 bits */
930 
931         cpu_pop ();                                     /* pop the TOS */
932 
933         RA = LOWER_WORD (uremainder);                   /* store the remainder on the TOS */
934         RB = LOWER_WORD (uquotient);                    /*   and the quotient on the NOS */
935 
936         SET_CCA (RB, 0);                                /* set the (integer) condition code */
937         break;
938 
939 
940     case 064:                                           /* NOT (CCA; STUN) */
941         RA = ~RA & R_MASK;                              /* complement the TOS */
942         SET_CCA (RA, 0);                                /*   and set the condition code */
943         break;
944 
945 
946     case 065:                                           /* OR (CCA; STUN) */
947         RB = RA | RB;                                   /* logically OR the TOS and NOS */
948 
949         SET_CCA (RB, 0);                                /* set the condition code */
950         cpu_pop ();                                     /*   and pop the TOS */
951         break;
952 
953 
954     case 066:                                           /* XOR (CCA; STUN) */
955         RB = RA ^ RB;                                   /* logically XOR the TOS and NOS */
956 
957         SET_CCA (RB, 0);                                /* set the condition code */
958         cpu_pop ();                                     /*   and pop the TOS */
959         break;
960 
961 
962     case 067:                                           /* AND (CCA; STUN) */
963         RB = RA & RB;                                   /* logically AND the TOS and NOS */
964 
965         SET_CCA (RB, 0);                                /* set the condition code */
966         cpu_pop ();                                     /*   and pop the TOS */
967         break;
968 
969 
970     case 070:                                           /* FIXR (CCA, C, O; STUN, ARITH) */
971     case 071:                                           /* FIXT (CCA, C, O; STUN, ARITH) */
972         operand_u.precision = fp_f;                     /* set the operand precision to single_float */
973 
974         operand_u.words [0] = RB;                       /* load the MSW */
975         operand_u.words [1] = RA;                       /*   and LSW of the operand */
976 
977         STA &= ~(STATUS_C | STATUS_O);                  /* the microcode clears the carry and overflow flags here */
978 
979         operand_v =                                         /* call the floating-point executor */
980            fp_exec ((FP_OPR) (operation - 070 + fp_fixr),   /*   and convert the opcode */
981                     operand_u, FP_NOP);                     /*     to a fix operation */
982 
983         if (operand_v.trap != trap_None) {              /* if an overflow occurs */
984             RB = RB & FRACTION_BITS | ASSUMED_BIT;      /*   then the microcode masks and restores */
985             MICRO_ABORT (operand_v.trap);               /*     the leading 1 to the mantissa before trapping */
986             }
987 
988         RB = operand_v.words [0];                       /* unload the MSW */
989         RA = operand_v.words [1];                       /*   and the LSW of the result */
990 
991         check = TO_DWORD (RB, RA) & S16_OVFL_MASK;          /* check the top 17 bits and set carry */
992         SET_CARRY (check != 0 && check != S16_OVFL_MASK);   /*   if they are not all zeros or all ones */
993 
994         SET_CCA (RB, RA);                               /* set the condition code */
995         break;
996 
997 
998     case 072:                                           /* unimplemented */
999         status = STOP_UNIMPL;                           /* report that the instruction was not executed */
1000         STA = entry_status;                             /*   and restore the status register entry value */
1001         break;
1002 
1003 
1004     case 073:                                           /* INCB (CCA, C, O; STUN, ARITH) */
1005         RB = cpu_add_16 (RB, 1);                        /* increment the NOS */
1006         SET_CCA (RB, 0);                                /*   and set the condition code */
1007         break;
1008 
1009 
1010     case 074:                                           /* DECB (CCA, C, O; STUN, ARITH) */
1011         RB = cpu_sub_16 (RB, 1);                        /* decrement the NOS */
1012         SET_CCA (RB, 0);                                /*   and set the condition code */
1013         break;
1014 
1015 
1016     case 075:                                           /* XBX (none; STUN) */
1017         exchanger = X;                                  /* exchange */
1018         X = RB;                                         /*   the NOS */
1019         RB = exchanger;                                 /*     and X */
1020         break;
1021 
1022 
1023     case 076:                                           /* ADBX (CCA, C, O; STUN, ARITH) */
1024         X = cpu_add_16 (X, RB);                         /* add the NOS to X */
1025         SET_CCA (X, 0);                                 /*   and set the condition code */
1026         break;
1027 
1028 
1029     case 077:                                           /* ADXB (CCA, C, O; STUN, ARITH) */
1030         RB = cpu_add_16 (X, RB);                        /* add X to the NOS */
1031         SET_CCA (RB, 0);                                /*   and set the condition code */
1032         break;
1033 
1034      }                                                  /* all cases are handled  */
1035 
1036 return status;                                          /* return the execution status */
1037 }
1038 
1039 
1040 /* Execute a shift, branch, or bit test instruction (subopcode 01).
1041 
1042    This routine is called to execute the shift, branch, or bit test instruction
1043    currently in the CIR.  The instruction formats are:
1044 
1045        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
1046      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1047      | 0   0   0   1 | X |   shift opcode    |      shift count      |  Shift
1048      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1049 
1050      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1051      | 0   0   0   1 | I |   branch opcode   |+/-|  P displacement   |  Branch
1052      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1053 
1054      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1055      | 0   0   0   1 | X |  bit test opcode  |     bit position      |  Bit Test
1056      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1057 
1058 
1059    Implementation notes:
1060 
1061     1. The BCY, BNCY, BOV, and BNOV instructions will enter infinite loops if
1062        their displacements are zero, so they call the "cpu_branch_short" routine
1063        with loop checking enabled.  The other branch instructions will not enter
1064        an infinite loop, even with zero displacements, as they modify registers
1065        or the stack during execution, so they call the routine with loop
1066        checking disabled.
1067 
1068     2. All of the shift instructions except QASL and QASR use bit 9 to indicate
1069        a left (0) or right (1) shift and bit 4 to indicate that the shift count
1070        includes the index register value.  Bit 9 is always on for QASL and QASR,
1071        which use bit 4 to indicate a left or right shift, and which always
1072        include the index register value.  To simplify handling in the shifting
1073        routine, the QASL and QASR executors move the left/right indication to
1074        bit 9 and set bit 4 on before calling.
1075 */
1076 
cpu_shift_branch_bit_op(void)1077 t_stat cpu_shift_branch_bit_op (void)
1078 {
1079 static const uint8 preadjustment [32] = {       /* stack preadjustment, indexed by operation */
1080     1, 1, 1, 1, 1, 1, 1, 1,                     /*   ASL  ASR  LSL  LSR  CSL  CSR  SCAN IABZ    */
1081     3, 3, 0, 0, 0, 0, 3, 4,                     /*   TASL TASR IXBZ DXBZ BCY  BNCY TNSL QAS(LR) */
1082     2, 2, 2, 2, 2, 2, 2, 1,                     /*   DASL DASR DLSL DLSR DCSL DCSR CPRB DABZ    */
1083     0, 0, 1, 1, 1, 1, 1, 1                      /*   BOV  BNOV TBC  TRBC TSBC TCBC BRO  BRE     */
1084     };
1085 
1086 HP_WORD opcode;
1087 uint32  operation, bit_position, bit_mask, count;
1088 t_stat  status = SCPE_OK;
1089 
1090 operation = SBBOP (CIR);                                /* get the opcode from the instruction */
1091 
1092 PREADJUST_SR (preadjustment [operation]);               /* preadjust the TOS registers to the required number */
1093 
1094 switch (operation) {                                    /* dispatch the shift/branch/bit operation */
1095 
1096     case 000:                                           /* ASL (CCA; STUN) */
1097     case 001:                                           /* ASR (CCA; STUN) */
1098         shift_16_32 (CIR, arithmetic, size_16);         /* do an arithmetic left or right shift */
1099         break;
1100 
1101 
1102     case 002:                                           /* LSL (CCA; STUN) */
1103     case 003:                                           /* LSR (CCA; STUN) */
1104         shift_16_32 (CIR, logical, size_16);            /* do a logical left or right shift */
1105         break;
1106 
1107 
1108     case 004:                                           /* CSL (CCA; STUN) */
1109     case 005:                                           /* CSR (CCA; STUN) */
1110         shift_16_32 (CIR, circular, size_16);           /* do a circular left or right shift */
1111         break;
1112 
1113 
1114     case 006:                                           /* SCAN (CCA; STUN) */
1115         if (RA == 0)                                    /* if the TOS is zero */
1116             if (CIR & X_FLAG)                           /*   then if the instruction is indexed */
1117                 X = X + 16 & R_MASK;                    /*     then add 16 to the index register value */
1118             else                                        /*   otherwise */
1119                 X = 16;                                 /*     set the index register value to 16 */
1120 
1121         else {                                          /* otherwise the TOS is not zero */
1122             count = 0;                                  /*   so set up to scan for the first "one" bit */
1123 
1124             while ((RA & D16_SIGN) == 0) {              /* while the MSB is clear */
1125                 RA = RA << 1;                           /*   shift the TOS left */
1126                 count = count + 1;                      /*     while counting the shifts */
1127                 }
1128 
1129             if (CIR & X_FLAG)                           /* if the instruction is indexed */
1130                 X = X + count + 1 & R_MASK;             /*   then return the count + 1 */
1131             else                                        /* otherwise */
1132                 X = count;                              /*   return the count */
1133 
1134             RA = RA << 1 & R_MASK;                      /* shift the leading "one" bit out of the TOS */
1135             }
1136 
1137         SET_CCA (RA, 0);                                /* set the condition code */
1138         break;
1139 
1140 
1141     case 007:                                           /* IABZ (CCA, C, O; STUN, BNDV) */
1142         RA = cpu_add_16 (RA, 1);                        /* increment the TOS */
1143         SET_CCA (RA, 0);                                /*   and set the condition code */
1144 
1145         if (RA == 0)                                    /* if the TOS is now zero */
1146             status = cpu_branch_short (FALSE);          /*   then branch to the target address */
1147         break;
1148 
1149 
1150     case 010:                                           /* TASL (CCA; STUN) */
1151     case 011:                                           /* TASR (CCA; STUN) */
1152         shift_48_64 (CIR, arithmetic, size_48);         /* do a triple arithmetic left or right shift */
1153         break;
1154 
1155 
1156     case 012:                                           /* IXBZ (CCA, C, O; BNDV) */
1157         X = cpu_add_16 (X, 1);                          /* increment X */
1158         SET_CCA (X, 0);                                 /*   and set the condition code */
1159 
1160         if (X == 0)                                     /* if X is now zero */
1161             status = cpu_branch_short (FALSE);          /*   then branch to the target address */
1162         break;
1163 
1164 
1165     case 013:                                           /* DXBZ (CCA, C, O; BNDV) */
1166         X = cpu_sub_16 (X, 1);                          /* decrement X */
1167         SET_CCA (X, 0);                                 /*   and set the condition code */
1168 
1169         if (X == 0)                                     /* if X is now zero */
1170             status = cpu_branch_short (FALSE);          /*   then branch to the target address */
1171         break;
1172 
1173 
1174     case 014:                                           /* BCY (C = 0; BNDV) */
1175         if (STA & STATUS_C) {                           /* if the carry bit is set */
1176             STA &= ~STATUS_C;                           /*   then clear it */
1177             status = cpu_branch_short (TRUE);           /*     and branch to the target address */
1178             }
1179         break;
1180 
1181 
1182     case 015:                                           /* BNCY (C = 0; BNDV) */
1183         if (STA & STATUS_C)                             /* if the carry bit is set */
1184             STA &= ~STATUS_C;                           /*   then clear it and do not branch */
1185         else                                            /* otherwise the carry bit is clear */
1186             status = cpu_branch_short (TRUE);           /*   so branch to the target address */
1187         break;
1188 
1189 
1190     case 016:                                           /* TNSL (CCA; STUN) */
1191         shift_48_64 (CIR, normalizing, size_48);        /* do a triple normalizing left shift */
1192         break;
1193 
1194 
1195     case 017:                                           /* QASL (CCA; STUN), QASR (CCA; STUN) */
1196         if ((CIR & ~SHIFT_COUNT_MASK) == QASR)          /* transfer the left/right flag */
1197             opcode = CIR | SHIFT_RIGHT_FLAG | X_FLAG;   /*   to the same position */
1198         else                                            /*     as the other shift instructions use */
1199             opcode = CIR & ~SHIFT_RIGHT_FLAG | X_FLAG;  /*       and set the indexed flag on */
1200 
1201         shift_48_64 (opcode, arithmetic, size_64);      /* do a quadruple arithmetic left or right shift */
1202         break;
1203 
1204 
1205     case 020:                                           /* DASL (CCA; STUN) */
1206     case 021:                                           /* DASR (CCA; STUN) */
1207         shift_16_32 (CIR, arithmetic, size_32);         /* do a double arithmetic left or right shift */
1208         break;
1209 
1210 
1211     case 022:                                           /* DLSL (CCA; STUN) */
1212     case 023:                                           /* DLSR (CCA; STUN) */
1213         shift_16_32 (CIR, logical, size_32);            /* do a double logical left or right shift */
1214         break;
1215 
1216 
1217     case 024:                                           /* DCSL (CCA; STUN) */
1218     case 025:                                           /* DCSR (CCA; STUN) */
1219         shift_16_32 (CIR, circular, size_32);           /* do a double circular left or right shift */
1220         break;
1221 
1222 
1223     case 026:                                           /* CPRB (CCE, CCL, CCG; STUN, BNDV) */
1224         if (SEXT16 (X) < SEXT16 (RB))                   /* if X is less than the lower bound */
1225             SET_CCL;                                    /*   then set CCL and continue */
1226 
1227         else if (SEXT16 (X) > SEXT16 (RA))              /* otherwise if X is greater than the upper bound */
1228             SET_CCG;                                    /*   then set CCG and continue */
1229 
1230         else {                                          /* otherwise lower bound <= X <= upper bound */
1231             SET_CCE;                                    /*   so set CCE */
1232             status = cpu_branch_short (FALSE);          /*     and branch to the target address */
1233             }
1234 
1235         cpu_pop ();                                     /* pop the TOS */
1236         cpu_pop ();                                     /*   and the NOS */
1237         break;
1238 
1239 
1240     case 027:                                           /* DABZ (CCA, C, O; STUN, BNDV) */
1241         RA = cpu_sub_16 (RA, 1);                        /* decrement the TOS */
1242         SET_CCA (RA, 0);                                /*   and set the condition code */
1243 
1244         if (RA == 0)                                    /* if the TOS is now zero */
1245             status = cpu_branch_short (FALSE);          /*   then branch to the target address */
1246         break;
1247 
1248 
1249     case 030:                                           /* BOV (O = 0; BNDV) */
1250         if (STA & STATUS_O) {                           /* if the overflow bit is set */
1251             STA &= ~STATUS_O;                           /*   then clear it */
1252             status = cpu_branch_short (TRUE);           /*     and branch to the target address */
1253             }
1254         break;
1255 
1256 
1257     case 031:                                           /* BNOV (O = 0; BNDV) */
1258         if (STA & STATUS_O)                             /* if the overflow bit is set */
1259             STA &= ~STATUS_O;                           /*   then clear it and do not branch */
1260         else                                            /* otherwise the overflow bit is clear */
1261             status = cpu_branch_short (TRUE);           /*   so branch to the target address */
1262         break;
1263 
1264 
1265     case 032:                                           /* TBC (CCA; STUN) */
1266     case 033:                                           /* TRBC (CCA; STUN) */
1267     case 034:                                           /* TSBC (CCA; STUN) */
1268     case 035:                                           /* TCBC (CCA; STUN) */
1269         bit_position = BIT_POSITION (CIR);              /* get the position of the bit to test */
1270 
1271         if (CIR & X_FLAG)                               /* if the instruction is indexed */
1272             bit_position = bit_position + X;            /*   then add the index register value */
1273 
1274         bit_mask = D16_SIGN >> bit_position % D16_WIDTH;    /* shift the bit mask to the desired location */
1275 
1276         SET_CCA (RA & bit_mask, 0);                     /* set the condition code */
1277 
1278         if (operation == 033)                           /* if the instruction is TRBC */
1279             RA = RA & ~bit_mask;                        /*   then reset the bit */
1280 
1281         else if (operation == 034)                      /* otherwise if the instruction is TSBC */
1282             RA = RA | bit_mask;                         /*   then set the bit */
1283 
1284         else if (operation == 035)                      /* otherwise if the instruction is TCBC */
1285             RA = RA ^ bit_mask;                         /*   then complement the bit */
1286         break;                                          /* or leave it alone for TBC */
1287 
1288 
1289     case 036:                                           /* BRO (none; STUN, BNDV) */
1290         if ((RA & 1) == 1)                              /* if the TOS is odd */
1291             status = cpu_branch_short (FALSE);          /*   then branch to the target address */
1292 
1293         cpu_pop ();                                     /* pop the TOS */
1294         break;
1295 
1296 
1297     case 037:                                           /* BRE (none; STUN, BNDV) */
1298         if ((RA & 1) == 0)                              /* if the TOS is even */
1299             status = cpu_branch_short (FALSE);          /*   then branch to the target address */
1300 
1301         cpu_pop ();                                     /* pop the TOS */
1302         break;
1303 
1304      }                                                  /* all cases are handled  */
1305 
1306 return status;                                          /* return the execution status */
1307 }
1308 
1309 
1310 /* Execute a move, special, firmware, immediate, field, or register instruction (subopcode 02).
1311 
1312    This routine is called to execute the move, special, firmware, immediate,
1313    field, or register instruction currently in the CIR.  The instruction formats
1314    are:
1315 
1316        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
1317      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1318      | 0   0   1   0 | 0   0   0   0 |  move op  | opts/S decrement  |  Move
1319      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1320 
1321      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1322      | 0   0   1   0 | 0   0   0   0 |  special op   | 0   0 | sp op |  Special
1323      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1324 
1325      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1326      | 0   0   1   0 | 0   0   0   1 |      firmware option op       |  Firmware
1327      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1328 
1329      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1330      | 0   0   1   0 |  imm opcode   |       immediate operand       |  Immediate
1331      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1332 
1333      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1334      | 0   0   1   0 | field opcode  |    J field    |    K field    |  Field
1335      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1336 
1337      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1338      | 0   0   1   0 |  register op  | SK| DB| DL| Z |STA| X | Q | S |  Register
1339      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1340 
1341 
1342    Implementation notes:
1343 
1344     1. The PSHR and SETR instructions follow the stack usage in the microcode
1345        so that SR contains the same value at the end of the instruction as in
1346        the hardware.  The sequence of stack flushes and queue-ups is therefore
1347        somewhat asymmetric.
1348 
1349     2. The microcode for the EXF and DPF instructions calculate the alignment
1350        shifts as 16 - (J + K) MOD 16 and then perform circular right and left
1351        shifts, respectively, to align the fields.  In simulation, the alignments
1352        are calculated as (J + K) MOD 16, and the opposite shifts (left and
1353        right, respectively) are employed.  This produces the same result, as a
1354        circular left shift of N bits is identical to a circular right shift of
1355        16 - N bits.
1356 */
1357 
cpu_move_spec_fw_imm_field_reg_op(void)1358 t_stat cpu_move_spec_fw_imm_field_reg_op (void)
1359 {
1360 static const uint8 preadjustment [16] = {       /* stack preadjustment, indexed by operation */
1361     0, 4, 0, 0, 1, 1, 1, 1,                     /*   ---- ---- LDI  LDXI CMPI ADDI SUBI MPYI */
1362     1, 0, 0, 0, 1, 1, 2, 4                      /*   DIVI PSHR LDNI LDXN CMPN EXF  DPF  SETR */
1363     };
1364 
1365 int32   divisor;
1366 uint32  operation;
1367 HP_WORD new_sbank, new_sm, new_q, start_bit, bit_count, bit_shift, bit_mask;
1368 t_stat  status = SCPE_OK;
1369 
1370 operation = MSFIFROP (CIR);                             /* get the opcode from the instruction */
1371 
1372 PREADJUST_SR (preadjustment [operation]);               /* preadjust the TOS registers to the required number */
1373 
1374 switch (operation) {                                    /* dispatch the operation */
1375 
1376     case 000:
1377         status = move_spec ();                          /* execute the move or special instruction */
1378         break;
1379 
1380 
1381     case 001:
1382         status = firmware_extension ();                 /* execute the DMUL, DDIV, or firmware extension instruction */
1383         break;
1384 
1385 
1386     case 002:                                           /* LDI (CCA; STOV) */
1387         cpu_push ();                                    /* push the stack down */
1388         RA = CIR & IMMED_MASK;                          /* store the immediate value on the TOS */
1389         SET_CCA (RA, 0);                                /*   and set the condition code */
1390         break;
1391 
1392 
1393     case 003:                                           /* LDXI (none; none) */
1394         X = CIR & IMMED_MASK;                           /* load the immediate value into X */
1395         break;
1396 
1397 
1398     case 004:                                           /* CMPI (CCC; STUN) */
1399         SET_CCC (RA, 0, CIR & IMMED_MASK, 0);           /* set the condition code */
1400         cpu_pop ();                                     /*   and pop the TOS */
1401         break;
1402 
1403 
1404     case 005:                                           /* ADDI (CCA, C, O; STUN, ARITH) */
1405         RA = cpu_add_16 (RA, CIR & IMMED_MASK);         /* sum the TOS and the immediate value */
1406         SET_CCA (RA, 0);                                /*   and set the condition code */
1407         break;
1408 
1409 
1410     case 006:                                           /* SUBI (CCA, C, O; STUN, ARITH) */
1411         RA = cpu_sub_16 (RA, CIR & IMMED_MASK);         /* difference the TOS and the immediate value */
1412         SET_CCA (RA, 0);                                /*   and set the condition code */
1413         break;
1414 
1415 
1416     case 007:                                           /* MPYI (CCA, O; STUN, STOV, ARITH) */
1417         cpu_push ();                                    /* the microcode does this for commonality with */
1418         cpu_pop ();                                     /*   MPY and MPYM, so we must too to get STOV */
1419 
1420         RA = cpu_mpy_16 (RA, CIR & IMMED_MASK);         /* multiply the TOS and the immediate value */
1421         SET_CCA (RA, 0);                                /*   and set the condition code */
1422         break;
1423 
1424 
1425     case 010:                                           /* DIVI (CCA; STUN, ARITH) */
1426         divisor = (int32) CIR & IMMED_MASK;             /* get the immediate (positive) divisor */
1427 
1428         if (divisor == 0)                               /* if dividing by zero */
1429             MICRO_ABORT (trap_Integer_Zero_Divide);     /*   then trap or set the overflow flag */
1430 
1431         RA = SEXT16 (RA) / divisor & R_MASK;            /* store the quotient (which cannot overflow) on the TOS */
1432         SET_CCA (RA, 0);                                /*   and set the condition code */
1433         break;
1434 
1435 
1436     case 011:                                           /* PSHR (none; STOV, MODE) */
1437         cpu_flush ();                                   /* flush the TOS register file */
1438 
1439         if (SM + 9 > Z)                                 /* check the stack for enough space */
1440             MICRO_ABORT (trap_Stack_Overflow);          /*   before pushing any of the registers */
1441 
1442         if (CIR & PSR_S) {                              /* if S is to be stored */
1443             cpu_push ();                                /*   then push the stack down */
1444             RA = SM - DB & R_MASK;                      /*     and store delta S on the TOS */
1445             }
1446 
1447         if (CIR & PSR_Q) {                              /* if Q is to be stored */
1448             cpu_push ();                                /*   then push the stack down */
1449             RA = Q - DB & R_MASK;                       /*     and store delta Q on the TOS */
1450             }
1451 
1452         if (CIR & PSR_X) {                              /* if X is to be stored */
1453             cpu_push ();                                /*   then push the stack down */
1454             RA = X;                                     /*     and store X on the TOS */
1455             }
1456 
1457         if (CIR & PSR_STA) {                            /* if STA is to be stored */
1458             cpu_push ();                                /*   then push the stack down */
1459             RA = STA;                                   /*     and store the status register on the TOS */
1460             cpu_flush ();                               /* flush the TOS register queue */
1461             }
1462 
1463         if (CIR & PSR_Z) {                              /* if Z is to be stored */
1464             cpu_push ();                                /*   then push the stack down */
1465             RA = Z - DB & R_MASK;                       /*     and store delta Z on the TOS */
1466             }
1467 
1468         cpu_flush ();                                   /* flush the TOS register queue */
1469 
1470         if (CIR & PSR_DL) {                             /* if DL is to be stored */
1471             cpu_push ();                                /*   then push the stack down */
1472             RA = DL - DB & R_MASK;                      /*     and store delta DL on the TOS */
1473             }
1474 
1475         if (CIR & (PSR_DB_DBANK | PSR_SBANK)) {         /* if a bank register is to be stored */
1476             if (NPRV)                                   /*   then if the mode is not privileged */
1477                 MICRO_ABORT (trap_Privilege_Violation); /*     then abort with a privilege violation */
1478 
1479             if (CIR & PSR_DB_DBANK) {                   /* if DBANK and DB are to be stored */
1480                 cpu_push ();                            /*   then push the stack */
1481                 cpu_push ();                            /*     down twice */
1482                 RA = DB;                                /*       and store DB on the TOS */
1483                 RB = DBANK;                             /*         and DBANK in the NOS */
1484                 }
1485 
1486             if (CIR & PSR_SBANK) {                      /* if SBANK is to be stored */
1487                 cpu_push ();                            /*   then push the stack down */
1488                 RA = SBANK;                             /*     and store SBANK on the TOS */
1489                 }
1490             }
1491         break;
1492 
1493 
1494     case 012:                                           /* LDNI (CCA; STOV) */
1495         cpu_push ();                                    /* push the stack down */
1496         RA = NEG16 (CIR & IMMED_MASK);                  /*   and store the negated immediate value on the TOS */
1497 
1498         SET_CCA (RA, 0);                                /* set the condition code */
1499         break;
1500 
1501 
1502     case 013:                                           /* LDXN (none; none) */
1503         X = NEG16 (CIR & IMMED_MASK);                   /* store the negated immediate value into X */
1504         break;
1505 
1506 
1507     case 014:                                           /* CMPN (CCC; STUN) */
1508         SET_CCC (RA, 0, NEG16 (CIR & IMMED_MASK), 0);   /* set the condition code */
1509         cpu_pop ();                                     /*   and pop the TOS */
1510         break;
1511 
1512 
1513     case 015:                                           /* EXF (CCA; STUN) */
1514         start_bit = START_BIT (CIR);                    /* get the starting bit number */
1515         bit_count = BIT_COUNT (CIR);                    /*   and the number of bits */
1516 
1517         bit_shift = (start_bit + bit_count) % D16_WIDTH;    /* calculate the alignment shift */
1518 
1519         bit_mask = (1 << bit_count) - 1;                    /* form a right-justified mask */
1520 
1521         RA = (RA << bit_shift | RA >> D16_WIDTH - bit_shift)    /* rotate the TOS to align with the mask */
1522                & bit_mask;                                      /*   and then mask to the desired field */
1523 
1524         SET_CCA (RA, 0);                                   /* set the condition code */
1525         break;
1526 
1527 
1528     case 016:                                           /* DPF (CCA; STUN) */
1529         start_bit = START_BIT (CIR);                    /* get the starting bit number */
1530         bit_count = BIT_COUNT (CIR);                    /*   and the number of bits */
1531 
1532         bit_shift = (start_bit + bit_count) % D16_WIDTH;    /* calculate the alignment shift */
1533 
1534         bit_mask = (1 << bit_count) - 1;                    /* form a right-justified mask */
1535 
1536         bit_mask = bit_mask >> bit_shift                    /* rotate it into the correct position */
1537                      | bit_mask << D16_WIDTH - bit_shift;   /*   to mask the target field */
1538 
1539         RB = (RB & ~bit_mask                                /* mask the NOS and rotate and mask the TOS to fill */
1540                | (RA >> bit_shift | RA << D16_WIDTH - bit_shift) & bit_mask)
1541                & R_MASK;
1542 
1543         cpu_pop ();                                     /* pop the TOS */
1544         SET_CCA (RA, 0);                                /*   and set the condition code */
1545         break;
1546 
1547 
1548     case 017:                                           /* SETR (none; STUN, STOV, MODE)*/
1549         new_sbank = 0;                                  /* quell erroneous uninitialized use warning */
1550 
1551         if (CIR & PSR_PRIV) {                           /* setting SBANK, DB, DL, and Z are privileged */
1552             if (NPRV)                                   /* if the mode is not privileged */
1553                 MICRO_ABORT (trap_Privilege_Violation); /*   then abort with a privilege violation */
1554 
1555             if (CIR & PSR_SBANK) {                      /* if SBANK is to be set */
1556                 new_sbank = RA;                         /*   then change it after the parameters are retrieved */
1557                 cpu_pop ();                             /* pop the parameter */
1558                 }
1559 
1560             if (CIR & PSR_DB_DBANK) {                   /* if DBANK and DB are to be set */
1561                 DB = RA;                                /*   then set the */
1562                 DBANK = RB & BA_MASK;                   /*     new values */
1563                 cpu_pop ();                             /*       and pop the */
1564                 cpu_pop ();                             /*         parameters */
1565                 }
1566 
1567             if (CIR & PSR_DL) {                         /* if DL is to be set */
1568                 DL = RA + DB & R_MASK;                  /*   then set the new value as an offset from DB */
1569                 cpu_pop ();                             /*     and pop the parameter */
1570                 }
1571 
1572             if (SR == 0)                                /* queue up a parameter */
1573                 cpu_queue_up ();                        /*   if it is needed */
1574 
1575             if (CIR & PSR_Z) {                          /* if Z is to be set */
1576                 Z = RA + DB & R_MASK;                   /*   then set the new value as an offset from DB */
1577                 cpu_pop ();                             /*     and pop the parameter */
1578                 }
1579                                                         /* queue up another parameter */
1580             if (SR == 0)                                /*   if it is needed */
1581                 cpu_queue_up ();
1582             }
1583 
1584         if (CIR & PSR_STA) {                                    /* if STA is to be set */
1585             if (NPRV)                                           /*   then if the mode is not privileged */
1586                 STA = STA & ~STATUS_NPRV | RA & STATUS_NPRV;    /*     then only T, O, C, and CC can be set */
1587             else                                                /*   otherwise privileged mode */
1588                 STA = RA;                                       /*     allows the entire word to be set */
1589 
1590             if ((STA & STATUS_OVTRAP) == STATUS_OVTRAP) /* if overflow was set with trap enabled */
1591                 CPX1 |= cpx1_INTOVFL;                   /*   then an interrupt occurs */
1592 
1593             cpu_pop ();                                 /* pop the parameter */
1594 
1595             if (SR == 0)                                /* queue up another parameter */
1596                 cpu_queue_up ();                        /*   if it is needed */
1597             }
1598 
1599         if (CIR & PSR_X) {                              /* if X is to be set */
1600             X = RA;                                     /*   then set the new value */
1601             cpu_pop ();                                 /*     and pop the parameter */
1602             }
1603 
1604         if (CIR & PSR_Q) {                              /* if Q is to be set */
1605             if (SR == 0)                                /*   then queue up another parameter */
1606                 cpu_queue_up ();                        /*     if it is needed */
1607 
1608             new_q = RA + DB & R_MASK;                   /* set the new value as an offset from DB */
1609 
1610             check_stack_bounds (new_q);                 /* trap if the new value is outside of the stack */
1611 
1612             Q = new_q;                                  /* set the new value */
1613             cpu_pop ();                                 /*   and pop the parameter */
1614             }
1615 
1616         if (CIR & PSR_S) {                              /* if S is to be set */
1617             if (SR == 0)                                /*   then queue up another parameter */
1618                 cpu_queue_up ();                        /*     if it is needed */
1619 
1620             new_sm = RA + DB & R_MASK;                  /* set the new value as an offset from DB */
1621 
1622             check_stack_bounds (new_sm);                /* trap if the new value is outside of the stack */
1623 
1624             cpu_flush ();                               /* flush the TOS register file */
1625             SM = new_sm;                                /*   and set the new stack pointer value */
1626             }
1627 
1628         if (CIR & PSR_SBANK)                            /* if SBANK is to be set */
1629             SBANK = new_sbank & BA_MASK;                /*   then update the new value now */
1630 
1631         cpu_base_changed = (CIR != SETR && CIR != SETR_X);  /* set the flag if the base registers changed */
1632         break;
1633      }                                                  /* all cases are handled  */
1634 
1635 return status;                                          /* return the execution status */
1636 }
1637 
1638 
1639 /* Execute an I/O, control, program, immediate, or memory instruction (subopcode 03).
1640 
1641    This routine is called to execute the I/O, control, program, immediate, or
1642    memory instruction currently in the CIR.  The instruction formats are:
1643 
1644        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
1645      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1646      | 0   0   1   1 |  program op   |            N field            |  Program
1647      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1648 
1649      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1650      | 0   0   1   1 | immediate op  |       immediate operand       |  Immediate
1651      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1652 
1653      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1654      | 0   0   1   1 |   memory op   |        P displacement         |  Memory
1655      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1656 
1657    The "N field" of the program instructions contains an index that is used to
1658    locate the "program label" that describes the procedure or subroutine to call
1659    or exit.  Labels have this format:
1660 
1661        0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
1662      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1663      | 0 | U |                        address                        |  Local
1664      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1665 
1666      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1667      | M |        STT number         |        segment number         |  External
1668      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1669 
1670    Where:
1671 
1672      U (uncallable) = the procedure is callable from privileged mode only
1673      M (mapped)     = the segment number is physically mapped
1674      address        = the PB-relative address of the procedure entry
1675      STT number     = the Segment Transfer Table entry within the target segment
1676      segment number = the number of the target segment
1677 
1678    The label is located either on the top of the stack (N = 0) or by indexing
1679    into the STT of the current code segment (N > 0).  Labels may be either
1680    local, indicating a transfer within the current segment, or external,
1681    indicating a transfer to another segment.
1682 
1683 
1684    Implementation notes:
1685 
1686     1. In hardware, the LDPP and LDPN microcode performs the bounds test E >= PB
1687        on the effective address E, then does a queue down if necessary, then
1688        performs the bounds test E < PL (instead of <= to account for second
1689        word), and then does another queue down if necessary, before reading the
1690        two words and storing them in the RA and RB registers.  Therefore, the
1691        order of possible traps is BNDV, STOV, BNDV, and STOV.
1692 
1693        In simulation, the "cpu_read_memory" routine normally checks the upper
1694        and lower bounds together.  This would lead to a trap order of BNDV,
1695        BNDV, STOV, and STOV.  To implement the microcode order, explicit bounds
1696        checks are interleaved with the stack pushes, and then unchecked reads
1697        are done to obtain the operands.
1698 */
1699 
cpu_io_cntl_prog_imm_mem_op(void)1700 t_stat cpu_io_cntl_prog_imm_mem_op (void)
1701 {
1702 static const uint8 preadjustment [16] = {       /* stack preadjustment, indexed by operation */
1703     0, 0, 0, 0, 1, 0, 0, 0,                     /*   ---- SCAL PCAL EXIT SXIT ADXI SBXI LLBL */
1704     0, 0, 1, 1, 0, 1, 1, 1                      /*   LDPP LDPN ADDS SUBS ---- ORI  XORI ANDI */
1705     };
1706 
1707 ACCESS_CLASS class;
1708 uint32       operation;
1709 HP_WORD      field, operand, offset, new_p, new_q, new_sm, stt_length, label;
1710 t_stat       status = SCPE_OK;
1711 
1712 field = CIR & DISPL_255_MASK;                           /* get the N/immediate/displacement field value */
1713 
1714 operation = IOCPIMOP (CIR);                             /* get the opcode from the instruction */
1715 
1716 PREADJUST_SR (preadjustment [operation]);               /* preadjust the TOS registers to the required number */
1717 
1718 switch (operation) {                                    /* dispatch the operation */
1719 
1720     case 000:
1721         status = io_control ();                         /* execute the I/O or control instruction */
1722         break;
1723 
1724 
1725     case 001:                                           /* SCAL (none; STOV, STUN, STTV, BNDV) */
1726         if (field == 0) {                               /* if the label is on the TOS */
1727             PREADJUST_SR (1);                           /*   then ensure a valid TOS register */
1728             label = RA;                                 /*     before getting the label */
1729             cpu_pop ();                                 /*       and popping it from the stack */
1730             }
1731 
1732         else                                                /* otherwise, the label is at M [PL-N] */
1733             cpu_read_memory (program_checked,               /*   so check the bounds */
1734                              PL - field & LA_MASK, &label); /*     and then read the label */
1735 
1736         cpu_flush ();                                   /* flush the TOS registers to memory */
1737 
1738         if (SM > Z) {                                   /* if the stack limit was exceeded */
1739             if (field == 0) {                           /*   then if the label was on the TOS */
1740                 cpu_push ();                            /*     then push the stack down */
1741                 RA = label;                             /*       and restore the label to the TOS */
1742                 }
1743 
1744             MICRO_ABORT (trap_Stack_Overflow);          /* trap for a stack overflow */
1745             }
1746 
1747         if (label & LABEL_EXTERNAL)                     /* if the label is non-local */
1748             MICRO_ABORTP (trap_STT_Violation, STA);     /*   then trap for an STT violation */
1749 
1750         cpu_push ();                                    /* push the stack down */
1751         RA = P - 1 - PB & R_MASK;                       /*   and store the return address on the TOS */
1752 
1753         new_p = PB + (label & LABEL_ADDRESS_MASK);      /* get the subroutine entry address */
1754 
1755         cpu_read_memory (fetch_checked, new_p, &NIR);   /* check the bounds and get the first instruction */
1756         P = new_p + 1 & R_MASK;                         /*   and set P to point at the next instruction */
1757         break;
1758 
1759 
1760     case 002:                                           /* PCAL (none; STUN, STOV, CSTV, STTV, ABS CST, TRACE, UNCAL, BNDV) */
1761         if (field == 0) {                               /* if the label is on the TOS */
1762             PREADJUST_SR (1);                           /*   then ensure a valid TOS register */
1763             label = RA;                                 /*     before getting the label */
1764             cpu_pop ();                                 /*       and popping it from the stack */
1765             }
1766 
1767         else                                                /* otherwise, the label is at M [PL-N] */
1768             cpu_read_memory (program_checked,               /*   so check the bounds */
1769                              PL - field & LA_MASK, &label); /*     and then read the label */
1770 
1771         cpu_flush ();                                   /* flush the TOS registers to memory */
1772 
1773         if (SM > Z) {                                   /* if the stack limit was exceeded */
1774             if (field == 0) {                           /*   then if the label was on the TOS */
1775                 cpu_push ();                            /*     then push the stack down */
1776                 RA = label;                             /*       and restore the label to the TOS */
1777                 }
1778 
1779             MICRO_ABORT (trap_Stack_Overflow);          /* trap for a stack overflow */
1780             }
1781 
1782         cpu_mark_stack ();                              /* write a stack marker */
1783 
1784         cpu_call_procedure (label, 0);                  /* set up PB, P, PL, and STA to call the procedure */
1785         break;
1786 
1787 
1788     case 003:                                           /* EXIT (CC; STUN, STOV, MODE, CSTV, TRACE, ABSCST, BNDV) */
1789         if (SM < Q)                                     /* if the stack memory pointer is below the stack marker */
1790             cpu_flush ();                               /*   then flush the TOS registers to memory */
1791 
1792         SR = 0;                                         /* invalidate the TOS registers */
1793 
1794         new_sm = Q - 4 - field & R_MASK;                /* compute the new stack pointer value */
1795 
1796         cpu_read_memory (stack, Q, &operand);           /* read the delta Q value from the stack marker */
1797         new_q = Q - operand & R_MASK;                   /*  and determine the new Q value */
1798 
1799         cpu_exit_procedure (new_q, new_sm, field);      /* set up the return code segment and stack */
1800         break;
1801 
1802 
1803     case 004:                                           /* SXIT (none; STUN, STOV, BNDV) */
1804         new_p = RA + PB & R_MASK;                       /* get the return address */
1805         cpu_read_memory (fetch_checked, new_p, &NIR);   /* check the bounds and then load the NIR */
1806 
1807         cpu_pop ();                                     /* pop the return address from the stack */
1808 
1809         if (field > 0 && SR > 0)                        /* if an adjustment is wanted and the TOS registers are occupied */
1810             cpu_flush ();                               /*   then flush the registers to memory */
1811 
1812         new_sm = SM - field & R_MASK;                   /* adjust the stack pointer as requested */
1813 
1814         check_stack_bounds (new_sm);                    /* trap if the new value is outside of the stack */
1815         SM = new_sm;                                    /*   before setting the new stack pointer value */
1816 
1817         P = new_p + 1 & R_MASK;                         /* set the new P value for the return */
1818         break;
1819 
1820 
1821     case 005:                                           /* ADXI (CCA; none) */
1822         X = X + field & R_MASK;                         /* add the immediate value to X */
1823         SET_CCA (X, 0);                                 /*    and set the condition code */
1824         break;
1825 
1826 
1827     case 006:                                           /* SBXI (CCA; none) */
1828         X = X - field & R_MASK;                         /* subtract the immediate value from X */
1829         SET_CCA (X, 0);                                 /*   and set the condition code */
1830         break;
1831 
1832 
1833     case 007:                                               /* LLBL (none; STOV, STTV) */
1834         cpu_read_memory (program_checked, PL, &stt_length); /* read the STT length */
1835 
1836         if ((stt_length & STT_LENGTH_MASK) < field)     /* if the STT index is not within the STT */
1837             MICRO_ABORTP (trap_STT_Violation, STA);     /*   then trap for an STT violation */
1838 
1839         cpu_read_memory (program_checked,               /* check the bounds */
1840                          PL - field & LA_MASK, &label); /*   and then read the label */
1841 
1842         if ((label & LABEL_EXTERNAL) == 0)              /* if the label is a local label */
1843             if (field > LABEL_STTN_MAX)                 /*   then if the STT number is too big for an external */
1844                 MICRO_ABORTP (trap_STT_Violation, STA); /*     then trap for an STT violation */
1845 
1846             else                                        /*   otherwise */
1847                 label = LABEL_EXTERNAL                  /*     convert it to an external label */
1848                           | (field << LABEL_STTN_SHIFT) /*       by merging the STT number */
1849                           | STATUS_CS (STA);            /*         with the currently executing segment number */
1850 
1851         cpu_push ();                                    /* push the stack down */
1852         RA = label;                                     /*   and store the label on the TOS */
1853         break;
1854 
1855 
1856     case 010:                                           /* LDPP (CCA; STOV, BNDV) */
1857     case 011:                                           /* LDPN (CCA; STOV, BNDV) */
1858         cpu_ea (CIR & MODE_DISP_MASK,                   /* get the address of the first word */
1859                 &class, &offset, NULL);
1860 
1861         if (offset < PB && NPRV)                        /* if the offset is below PB and the mode is not privileged */
1862             MICRO_ABORT (trap_Bounds_Violation);        /*   then trap for a bounds violation */
1863 
1864         cpu_push ();                                    /* push the stack down */
1865 
1866         if (offset >= PL && NPRV)                       /* if the offset is at or above PL and the mode is not privileged */
1867             MICRO_ABORT (trap_Bounds_Violation);        /*   then trap for a bounds violation */
1868 
1869         cpu_push ();                                    /* push the stack down again */
1870 
1871         cpu_read_memory (program, offset, &operand);    /* read the first word */
1872         RB = operand;                                   /*   and store it in the NOS */
1873 
1874         offset = offset + 1 & LA_MASK;                  /* point at the second word */
1875 
1876         cpu_read_memory (program, offset, &operand);    /* read the second word */
1877         RA = operand;                                   /*   and store the on the TOS */
1878 
1879         SET_CCA (RB, RA);                               /* set the condition code */
1880         break;
1881 
1882 
1883     case 012:                                           /* ADDS (none; STUN, STOV) */
1884         if (field == 0)                                 /* if the immediate value is zero */
1885             field = RA - 1;                             /*   then use the TOS value - 1 instead */
1886 
1887         cpu_flush ();                                   /* empty the TOS registers */
1888 
1889         new_sm = SM + field & R_MASK;                   /* get the new stack pointer value */
1890 
1891         check_stack_bounds (new_sm);                    /* trap if the new value is outside of the stack */
1892         SM = new_sm;                                    /*   before setting the new stack pointer value */
1893         break;
1894 
1895 
1896     case 013:                                           /* SUBS (none; STUN, STOV) */
1897         if (field == 0)                                 /* if the immediate value is zero */
1898             field = RA + 1;                             /*   then use the TOS value + 1 instead */
1899 
1900         cpu_flush ();                                   /* empty the TOS registers */
1901 
1902         new_sm = SM - field & R_MASK;                   /* get the new stack pointer value */
1903 
1904         check_stack_bounds (new_sm);                    /* trap if the new value is outside of the stack */
1905         SM = new_sm;                                    /*   before setting the new stack pointer value */
1906         break;
1907 
1908 
1909     case 014:
1910         status = STOP_UNIMPL;                           /* opcodes 036000-036777 are unimplemented */
1911         break;
1912 
1913 
1914     case 015:                                           /* ORI (CCA; STUN) */
1915         RA = RA | field;                                /* logically OR the TOS and the immediate value */
1916         SET_CCA (RA, 0);                                /*   and set the condition code */
1917         break;
1918 
1919 
1920     case 016:                                           /* XORI (CCA; STUN) */
1921         RA = RA ^ field;                                /* logically XOR the TOS and the immediate value */
1922         SET_CCA (RA, 0);                                /*   and set the condition code */
1923         break;
1924 
1925 
1926     case 017:                                           /* ANDI (CCA; STUN) */
1927         RA = RA & field;                                /* logically AND the TOS and the immediate value */
1928         SET_CCA (RA, 0);                                /*   and set the condition code */
1929         break;
1930 
1931      }                                                  /* all cases are handled  */
1932 
1933 return status;                                          /* return the execution status */
1934 }
1935 
1936 
1937 
1938 /* CPU base set local utility routines */
1939 
1940 
1941 /* Add two 32-bit numbers.
1942 
1943    Two 32-bit values are added, and the 32-bit sum is returned.  The C (carry)
1944    bit in the status register is set if the result is truncated and cleared
1945    otherwise.  The O (overflow) bit is set if the result exceeds the maximum
1946    positive or negative range, i.e., the result overflows into the sign bit.  In
1947    addition, an integer overflow interrupt (ARITH trap) occurs if the user trap
1948    bit is set.
1949 */
1950 
add_32(uint32 augend,uint32 addend)1951 static uint32 add_32 (uint32 augend, uint32 addend)
1952 {
1953 t_uint64 sum;
1954 
1955 sum = (t_uint64) augend + (t_uint64) addend;            /* sum the values */
1956 
1957 SET_CARRY (sum > D32_UMAX);                             /* set C if there is a carry out of the MSB */
1958 
1959 SET_OVERFLOW (D32_SIGN                                  /* set O if the signs */
1960                 & (~augend ^ addend)                    /*   of the operands are the same */
1961                 & (augend ^ sum));                      /*     but the sign of the result differs */
1962 
1963 return (uint32) sum & D32_MASK;                         /* return the lower 32 bits of the sum */
1964 }
1965 
1966 
1967 /* Subtract two 32-bit numbers.
1968 
1969    Two 32-bit values are subtracted, and the 32-bit difference is returned.  The
1970    C (carry) bit in the status register is set if the subtraction did not
1971    require a borrow for the most-significant bit.  The O (overflow) bit is set
1972    if the result exceeds the maximum positive or negative range, i.e., the
1973    result borrows from the sign bit.  In addition, an integer overflow interrupt
1974    (ARITH trap) occurs if the user trap bit is set.
1975 
1976 
1977    Implementation notes:
1978 
1979     1. The carry bit is set to the complement of the borrow, i.e., carry = 0 if
1980        there is a borrow and 1 is there is not.
1981 */
1982 
sub_32(uint32 minuend,uint32 subtrahend)1983 static uint32 sub_32 (uint32 minuend, uint32 subtrahend)
1984 {
1985 t_uint64 difference;
1986 
1987 difference = (t_uint64) minuend - (t_uint64) subtrahend;    /* subtract the values */
1988 
1989 SET_CARRY (subtrahend <= minuend);                          /* set C if no borrow from the MSB was done */
1990 
1991 SET_OVERFLOW (D32_SIGN                                      /* set O if the signs */
1992                 & (minuend ^ subtrahend)                    /*   of the operands differ */
1993                 & (minuend ^ difference));                  /*     as do the signs of the minuend and result */
1994 
1995 return (uint32) difference & D32_MASK;                      /* return the lower 32 bits of the difference */
1996 }
1997 
1998 
1999 /* Shift single- and double-word operands.
2000 
2001    An arithmetic, logical, or circular left or right shift is performed in place
2002    on the 16-bit or 32-bit operand in RA or RB and RA, respectively.  Condition
2003    code A is set for the result.  The shift count and shift direction are
2004    derived from the instruction supplied.
2005 
2006    An arithmetic left shift retains the sign bit; an arithmetic right shift
2007    copies the sign bit.  Logical shifts fill zeros into the LSB or MSB.
2008    Circular shifts rotate bits out of the MSB and into the LSB, or vice versa.
2009 
2010    On entry, the shift count is extracted from the instruction.  If the
2011    instruction is indexed, the value in the X register is added to the count.
2012 
2013    For the type of shift selected, the fill bits are determined: sign bits fill
2014    for an arithmetic shift, zero bits fill for a logical shift, and operand bits
2015    fill for a circular shift.  The result of a shift in excess of the operand
2016    size is also determined.
2017 
2018    If the shift count is zero, then the result is the original operand.
2019    Otherwise, if the count is less than the operand size, the selected shift is
2020    performed.  A right shift of any type is done by shifting the operand and
2021    filling with bits of the appropriate type.  An arithmetic left shift is done
2022    by shifting the operand and restoring the sign.  A logical or circular shift
2023    is done by shifting the operand and filling with bits of the appropriate
2024    type.
2025 
2026    The result is restored to the TOS register(s), and CCA is set before
2027    returning.
2028 
2029 
2030    Implementation notes:
2031 
2032     1. An arithmetic left shift must be handled as a special case because the
2033        shifted operand bits "skip over" the sign bit.  That is, the bits are
2034        lost from the next-most-significant bit while preserving the MSB.  For
2035        all other shifts, including the arithmetic right shift, the operand may
2036        be shifted and then merged with the appropriate fill bits.
2037 
2038     2. The C standard specifies that the results of bitwise shifts with counts
2039        greater than the operand sizes are undefined, so we must handle excessive
2040        shifts explicitly.
2041 
2042     3. The C standard specifies that the results of bitwise shifts with negative
2043        signed operands are undefined (for left shifts) or implementation-defined
2044        (for right shifts).  Therefore, we must use unsigned operands and handle
2045        arithmetic shifts explicitly.
2046 
2047     4. The compiler requires a "default" case (instead of a "normalizing"
2048        case) for the switch statement.  Otherwise, it will complain that
2049        "fill" and "result" are potentially undefined, even though all
2050        enumeration values are covered.
2051 */
2052 
shift_16_32(HP_WORD opcode,SHIFT_TYPE shift,OPERAND_SIZE op_size)2053 static void shift_16_32 (HP_WORD opcode, SHIFT_TYPE shift, OPERAND_SIZE op_size)
2054 {
2055 typedef struct {
2056     uint32 sign;                                /* the sign bit of the operand */
2057     uint32 data;                                /* the data mask of the operand */
2058     uint32 width;                               /* the width of the operand in bits */
2059     } PROPERTY;
2060 
2061 static const PROPERTY prop [2] = {
2062     { D16_SIGN, D16_MASK & ~D16_SIGN, D16_WIDTH },      /* 16-bit operand properties */
2063     { D32_SIGN, D32_MASK & ~D32_SIGN, D32_WIDTH }       /* 32-bit operand properties */
2064     };
2065 
2066 uint32 count, operand, fill, result;
2067 
2068 count = SHIFT_COUNT (opcode);                           /* get the shift count from the instruction */
2069 
2070 if (opcode & X_FLAG)                                    /* if the instruction is indexed */
2071     count = count + X & SHIFT_COUNT_MASK;               /*   then add the index to the count modulo 64 */
2072 
2073 operand = RA;                                           /* get the (lower half of the) operand */
2074 
2075 if (op_size == size_32)                                 /* if the operand size is 32 bits */
2076     operand = RB << D16_WIDTH | operand;                /*   then merge the upper half of the operand */
2077 
2078 switch (shift) {                                        /* dispatch the shift operation */
2079 
2080     case arithmetic:                                    /* for an arithmetic shift */
2081         fill = operand & prop [op_size].sign ? ~0 : 0;  /*   fill with copies of the sign bit */
2082 
2083         if (opcode & SHIFT_RIGHT_FLAG)                  /* for a right shift */
2084             result = fill;                              /*   the excessive shift result is all fill bits */
2085         else                                            /* whereas for a left shift */
2086             result = prop [op_size].sign;               /*   the excessive shift result is just the sign bit */
2087         break;
2088 
2089     case logical:                                       /* for a logical shift */
2090         fill = 0;                                       /*   fill with zeros */
2091         result = 0;                                     /* the excessive shift result is all zeros */
2092         break;
2093 
2094     case circular:                                      /* for a circular shift */
2095         fill = operand;                                 /*   fill with the operand */
2096         count = count % prop [op_size].width;           /* an excessive shift count is reduced modulo the word width */
2097         result = 0;                                     /*   so there is no excessive shift result */
2098         break;
2099 
2100     default:                                            /* normalizing shifts are not used */
2101         return;
2102     }
2103 
2104 
2105 if (count == 0)                                             /* if the shift count is zero */
2106     result = operand;                                       /*   then the result is the operand value */
2107 
2108 else if (count < prop [op_size].width)                      /* otherwise if the shift count is not excessive */
2109     if (opcode & SHIFT_RIGHT_FLAG)                          /*   then if this is a right shift of any type */
2110         result = operand >> count                           /*     then shift the operand */
2111                    | fill << prop [op_size].width - count;  /*       and fill with fill bits */
2112 
2113     else if (shift == arithmetic)                           /* otherwise if this is an arithmetic left shift */
2114         result = operand << count & prop [op_size].data     /*   then shift the operand */
2115                    | fill & prop [op_size].sign;            /*     and restore the sign bit */
2116 
2117     else                                                    /* otherwise this is a logical or circular left shift */
2118         result = operand << count                           /*   so shift the operand */
2119                    | fill >> prop [op_size].width - count;  /*     and fill with fill bits */
2120 
2121 
2122 RA = LOWER_WORD (result);                               /* store the lower word on the TOS */
2123 
2124 if (op_size == size_16)                                 /* if the operand is a single word */
2125     SET_CCA (RA, 0);                                    /*   then set the condition code */
2126 
2127 else {                                                  /* otherwise the operand is a double word */
2128     RB = UPPER_WORD (result);                           /*   so store the upper word in the NOS */
2129     SET_CCA (RB, RA);                                   /*     and then set the condition code */
2130     }
2131 
2132 return;
2133 }
2134 
2135 
2136 /* Shift triple- and quad-word operands.
2137 
2138    An arithmetic left or right shift or normalizing left shift is performed
2139    in place on the 48-bit or 64-bit operand in RC/RB/RA or RD/RC/RB/RA,
2140    respectively.  Condition code A is set for the result.  The shift count and
2141    shift direction are derived from the instruction supplied.
2142 
2143    An arithmetic left shift retains the sign bit; an arithmetic right shift
2144    copies the sign bit.  A normalizing shift does not specify a shift count.
2145    Instead, the operand is shifted until bit 6 is set, bits 0-5 are cleared, and
2146    the shift count is returned in the X register.
2147 
2148    On entry for an arithmetic shift, the shift count is extracted from the
2149    instruction.  If the instruction is indexed, the value in the X register is
2150    added to the count.  If the shift count is zero, then the result is the
2151    original operand.  Otherwise, if the count is less than the operand size, the
2152    selected shift is performed.  A right shift is done by shifting the operand
2153    and filling with sign bits.  A left shift is done by shifting the operand and
2154    restoring the sign.
2155 
2156    For a normalizing shift with at least one bit set to the right of bit 5, the
2157    operand is left-shifted and X is incremented until bit 6 is set.  Bits 0-5
2158    are then masked off.  If no bits are set to the right of bit 5, X is set to,
2159    or incremented by, the maximum shift count, CCE is set, and the operand is
2160    not altered.
2161 
2162    After a successful shift, the result is restored to the TOS registers, and
2163    CCA is set before returning.
2164 
2165 
2166    Implementation notes:
2167 
2168     1. Logical and circular shifts are unsupported as they are not offered by
2169        the instruction set.
2170 
2171     2. All of the shift instructions except QASL and QASR use bit 9 to indicate
2172        a left (0) or right (1) shift and bit 4 to indicate that the shift count
2173        includes the index register value.  Bit 9 is always on for QASL and QASR,
2174        which use bit 4 to indicate a left or right shift, and which always
2175        include the index register value.  To simplify handling, the QASL and
2176        QASR executors move the left/right indication to bit 9 and set bit 4 on
2177        before calling this routine.
2178 */
2179 
shift_48_64(HP_WORD opcode,SHIFT_TYPE shift,OPERAND_SIZE op_size)2180 static void shift_48_64 (HP_WORD opcode, SHIFT_TYPE shift, OPERAND_SIZE op_size)
2181 {
2182 typedef struct {
2183     t_uint64 sign;                              /* the sign bit of the operand */
2184     t_uint64 data;                              /* the data mask of the operand */
2185     uint32   width;                             /* the width of the operand in bits */
2186     uint32   padding;                           /* unused padding to suppress an alignment warning */
2187     } PROPERTY;
2188 
2189 static const PROPERTY prop [4] = {
2190     { 0, 0, 0 },                                        /* (unused 16-bit properties) */
2191     { 0, 0, 0 },                                        /* (unused 32-bit properties) */
2192     { D48_SIGN, D48_MASK & ~D48_SIGN, D48_WIDTH },      /* 48-bit operand properties */
2193     { D64_SIGN, D64_MASK & ~D64_SIGN, D64_WIDTH }       /* 64-bit operand properties */
2194     };
2195 
2196 uint32   count;
2197 t_uint64 operand, fill, result;
2198 
2199 operand = (t_uint64) RC << D32_WIDTH | TO_DWORD (RB, RA);   /* merge the first three words of the operand */
2200 
2201 if (op_size == size_64)                                 /* if the operand size is 64 bits */
2202     operand = (t_uint64) RD << D48_WIDTH | operand;     /*   then merge the fourth word of the operand */
2203 
2204 if (shift == arithmetic) {                              /* if this is an arithmetic shift */
2205     count = SHIFT_COUNT (opcode);                       /*   then the instruction contains the shift count */
2206 
2207     if (opcode & X_FLAG)                                /* if the instruction is indexed */
2208         count = count + X & SHIFT_COUNT_MASK;           /*   then add the index to the count modulo 64 */
2209 
2210     fill = operand & prop [op_size].sign ? ~0 : 0;      /* filling will use copies of the sign bit */
2211 
2212     if (count == 0)                                     /* if the shift count is zero */
2213         result = operand;                               /*   then the result is the operand value */
2214 
2215     else if (count < prop [op_size].width)                      /* otherwise if the shift count is not excessive */
2216         if (opcode & SHIFT_RIGHT_FLAG)                          /*   then if this is a right shift */
2217             result = operand >> count                           /*     then shift the operand */
2218                        | fill << prop [op_size].width - count;  /*       and fill with fill bits */
2219         else                                                    /* otherwise it is a left shift */
2220             result = operand << count & prop [op_size].data     /*   so shift the operand */
2221                        | fill & prop [op_size].sign;            /*     and restore the sign bit */
2222 
2223     else                                                /* otherwise the shift count exceeds the operand size */
2224         if (opcode & SHIFT_RIGHT_FLAG)                  /*   so if this is a right shift */
2225             result = fill;                              /*     then the excessive shift result is all fill bits */
2226         else                                            /*   whereas for a left shift */
2227             result = prop [op_size].sign;               /*     the excessive shift result is just the sign bit */
2228     }
2229 
2230 else if (shift == normalizing) {                        /* otherwise if this is a (left) normalizing shift */
2231     if ((opcode & X_FLAG) == 0)                         /*   then if the instruction is not indexed */
2232         X = 0;                                          /*     then clear the shift count */
2233 
2234     if (operand & NORM_MASK) {                          /* if there's at least one unnormalized bit set */
2235         result = operand;                               /*   then start with the operand */
2236 
2237         while ((result & NORM_BIT) == 0) {              /* while the result is unnormalized */
2238             result = result << 1;                       /*   left-shift the result */
2239             X = X + 1;                                  /*     and increment the shift count */
2240             }
2241 
2242         result = result & NORM_MASK;                    /* mask off the leading bits */
2243         X = X & R_MASK;                                 /*   and wrap the count value */
2244         }
2245 
2246     else {                                              /* otherwise there are no bits to normalize */
2247         X = X + 42 & R_MASK;                            /*   so report the maximum shift count */
2248 
2249         SET_CCE;                                        /* set the condition code */
2250         return;                                         /*   and return with the operand unmodified */
2251         }
2252     }
2253 
2254 else                                                    /* otherwise the shift type */
2255     return;                                             /*   is not supported by this routine */
2256 
2257 RA = LOWER_WORD (result);                               /* restore the */
2258 RB = UPPER_WORD (result);                               /*   lower three words */
2259 RC = LOWER_WORD (result >> D32_WIDTH);                  /*     to the stack */
2260 
2261 if (op_size == size_48)                                 /* if the operand size is 48 bits */
2262     SET_CCA (RC, RB | RA);                              /*   then set the condition code */
2263 
2264 else {                                                  /* otherwise the size is 64 bits */
2265     RD = LOWER_WORD (result >> D48_WIDTH);              /*   so merge the upper word */
2266     SET_CCA (RD, RC | RB | RA);                         /*     and then set the condition code */
2267     }
2268 
2269 return;
2270 }
2271 
2272 
2273 /* Check a value against the stack bounds.
2274 
2275    This routine checks a new frame (Q) or stack memory (SM) pointer value to
2276    ensure that it is within the stack bounds.  If the value does not lie between
2277    DB and Z, a trap will occur.
2278 
2279    The SETR instruction sets the frame and stack pointers, and the SXIT, ADDS,
2280    and SUBS instructions adjust the stack pointer.  Each verifies that the new
2281    value is between DB and Z before storing the value in the Q or SM register.
2282    If the value is greater than Z, a stack overflow trap is taken; if the value
2283    is less than DB, a stack underflow trap is taken.
2284 
2285 
2286    Implementation notes:
2287 
2288     1. Conceptually, ADDS can only exceed Z, whereas SXIT and SUBS can only drop
2289        below DB.  However, the microcode for all three instructions checks that
2290        both Z - new_SM and new_SM - DB are positive; if not, the routine traps
2291        to stack overflow or underflow, respectively.  As the new SM value is
2292        calculated modulo 2^16, wraparound overflows and underflows are caught
2293        only if they are within 32K of the Z or DB values.  For full coverage,
2294        both tests are necessary for each call, as an ADDS wraparound of 48K,
2295        e.g., would be caught as a stack underflow.  Simulation performs the same
2296        tests to obtain the same behavior, rather than checking that new_SM <= Z
2297        and DB <= new_SM.
2298 
2299     2. 32-bit subtractions are performed to ensure that wraparound overflows are
2300        caught.
2301 */
2302 
check_stack_bounds(HP_WORD new_value)2303 static void check_stack_bounds (HP_WORD new_value)
2304 {
2305 if ((uint32) Z - new_value > D16_SMAX)                  /* if the new value is not within 32K below Z */
2306     MICRO_ABORT (trap_Stack_Overflow);                  /*   then trap for an overflow */
2307 
2308 else if ((uint32) new_value - DB > D16_SMAX && NPRV)    /* otherwise if the new value is not within 32K above DB */
2309     MICRO_ABORT (trap_Stack_Underflow);                 /*   then trap for an underflow unless the mode is privileged */
2310 
2311 else                                                    /* otherwise the new value */
2312     return;                                             /*   is within the stack bounds */
2313 }
2314 
2315 
2316 /* Perform a test, control, or set interrupt I/O operation.
2317 
2318    The I/O operation specified in the "command" parameter is sent to the device
2319    whose device number stored on the stack at location S - K.  The K-field of
2320    the I/O instruction present in the CIR is extracted and subtracted from the
2321    current stack pointer.  The resulting memory location is read, and the lower
2322    byte is used as the device number.  The I/O command is sent, along with the
2323    value in the TOS for a CIO instruction, and the result is obtained.
2324 
2325    If the device number is invalid, an I/O timeout will result.  If this occurs,
2326    the timeout flag in CPX1 is reset, condition code "less than" is set, and
2327    this routine returns 0.  Otherwise, condition code "equal" is set to indicate
2328    success, and the device and result values are merged and returned (which will
2329    be non-zero, because zero is not a valid device number).
2330 
2331 
2332    Implementation notes:
2333 
2334     1. A checked access to memory is requested to obtain the device number.  As
2335        privileged mode has been previously ascertained, the memory check serves
2336        only to return a TOS register value if the resulting address is between
2337        SM and SR.
2338 */
2339 
tcs_io(IO_COMMAND command)2340 static uint32 tcs_io (IO_COMMAND command)
2341 {
2342 uint32  address;
2343 HP_WORD device, result;
2344 
2345 if (NPRV)                                               /* if the mode is not privileged */
2346     MICRO_ABORT (trap_Privilege_Violation);             /*   then abort with a privilege violation */
2347 
2348 address = SM + SR - IO_K (CIR) & LA_MASK;               /* get the location of the device number */
2349 
2350 cpu_read_memory (stack, address, &device);              /* read it from the stack or TOS registers */
2351 device = LOWER_BYTE (device);                           /*   and use only the lower byte of the value */
2352 
2353 result = iop_direct_io (device, command,                /* send the I/O order to the device */
2354                         (command == ioCIO ? RA : 0));   /*   along with the control word for a CIO instruction */
2355 
2356 if (CPX1 & cpx1_IOTIMER) {                              /* if an I/O timeout occurred */
2357     CPX1 &= ~cpx1_IOTIMER;                              /*   then clear the timer */
2358     SET_CCL;                                            /*     and set condition code "less than" */
2359     return 0;                                           /*        and fail the instruction */
2360     }
2361 
2362 else {                                                  /* otherwise */
2363     SET_CCE;                                            /*   set the condition code for success */
2364     return TO_DWORD (device, result);                   /*     and return the (non-zero) device and result values */
2365     }
2366 }
2367 
2368 
2369 /* Perform a start, read, or write I/O operation.
2370 
2371    The I/O operation specified in the "command" parameter is sent to the device
2372    whose device number stored on the stack at location S - K, where K is the
2373    K-field value of the I/O instruction present in the CIR.  A Test I/O order is
2374    first sent to the device to determine if it is ready.  If the device number
2375    is invalid, the routine returns zero with condition code "less than" set to
2376    indicate failure.  If the Test I/O succeeded, the device number and test
2377    result are obtained.
2378 
2379    The test result is checked to see if the bit specified by the "ready_flag"
2380    parameter is set.  If it is not, then the device is not ready, so the test
2381    result is pushed onto the TOS, condition code "greater than" is set, and zero
2382    is returned to indicate failure.  If the bit is set, the device is ready for
2383    the operation.
2384 
2385    For a Start I/O order, the starting address of the I/O program, located on
2386    the TOS, is stored in the first word of the Device Reference Table entry
2387    corresponding to the device number.  The I/O command is sent, along with the
2388    value in the TOS for a WIO instruction, and the result is obtained.
2389    Condition code "equal" is set to indicate success, and the device and result
2390    values are merged and returned (which will be non-zero, because zero is not a
2391    valid device number).
2392 
2393 
2394    Implementation notes:
2395 
2396     1. The initial Test I/O order verifies that the mode is privileged and that
2397        the device number is valid.  Therefore, the result of the command
2398        operation need not be tested for validity.
2399 */
2400 
srw_io(IO_COMMAND command,HP_WORD ready_flag)2401 static uint32 srw_io (IO_COMMAND command, HP_WORD ready_flag)
2402 {
2403 uint32  test;
2404 HP_WORD device, result;
2405 
2406 test = tcs_io (ioTIO);                                  /* send a Test I/O order to the device */
2407 
2408 if (test == 0)                                          /* if an I/O timeout occurred */
2409     return 0;                                           /*   then return 0 with CCL set to fail the instruction */
2410 
2411 device = UPPER_WORD (test);                             /* split the returned value */
2412 result = LOWER_WORD (test);                             /*   into the device number and test result */
2413 
2414 if (result & ready_flag) {                              /* if the device is ready */
2415     if (command == ioSIO)                               /*   then if this is an SIO order */
2416         cpu_write_memory (absolute, device * 4, RA);    /*     then write the I/O program address to the DRT */
2417 
2418     result = iop_direct_io (device, command,                /* send the I/O order to the device */
2419                             (command == ioWIO ? RA : 0));   /*   along with the data word for a WIO instruction */
2420 
2421     SET_CCE;                                            /* set the condition code for success */
2422     return TO_DWORD (device, result);                   /*   and return the (non-zero) device and result values */
2423     }
2424 
2425 else {                                                  /* otherwise the device is not ready */
2426     cpu_push ();                                        /*   so push the stack down */
2427     RA = result;                                        /*     and store the TIO response on the TOS */
2428 
2429     SET_CCG;                                            /* set the condition code to indicate "not ready" */
2430     return 0;                                           /*   and fail the instruction */
2431     }
2432 }
2433 
2434 
2435 /* Decrement the stack pointer.
2436 
2437    Pop values from the stack until the stack pointer has been decremented by the
2438    amount indicated by the "decrement" parameter.
2439 
2440    The word and byte move and comparison instructions include a stack decrement
2441    field that may be zero or a positive value indicating the number of words to
2442    remove at the end of the instruction.  This routine is called to implement
2443    this feature.
2444 
2445    Note that the stack decrement is performed only at the completion of these
2446    instructions.  If an instruction is interrupted, the decrement is not done,
2447    as the parameters on the stack will be needed when execution of the
2448    instruction is resumed after the interrupt handler completes.
2449 */
2450 
decrement_stack(uint32 decrement)2451 static void decrement_stack (uint32 decrement)
2452 {
2453 while (decrement > 0) {                                 /* decrement the stack pointer */
2454     cpu_pop ();                                         /*   by the count specified */
2455     decrement = decrement - 1;                          /*     by the instruction */
2456     }
2457 
2458 return;
2459 }
2460 
2461 
2462 /* Move a block of words in memory.
2463 
2464    A block of words is moved from a source address to a destination address.  If
2465    a pending interrupt is detected during the move, the move is interrupted to
2466    service it.  Otherwise at the completion of the move, the stack is
2467    decremented by the amount indicated.
2468 
2469    On entry, the "source_class" parameter indicates the memory classification
2470    for source reads.  If the classification is absolute, the "source_base"
2471    parameter contains the physical address (i.e., memory bank and offset) of the
2472    base of the first word to move.  If it is not absolute, the parameter
2473    contains the offset within the bank implied by the classification.
2474    Similarly, the "dest_class" and "dest_base" parameters designate the base of
2475    the first word to write.  The "decrement" parameter contains the number of
2476    stack words to delete if the move completed successfully.
2477 
2478    If the source is absolute, the TOS registers RA, RB, and RD contain the
2479    count, source offset from the source base, and destination offset from the
2480    destination base, respectively.  Otherwise, the the TOS registers RA, RB, and
2481    RC contain the count and bases.
2482 
2483    Register RA contains an unsigned (positive) word count when called for the
2484    MTDS and MFDS instructions, and a signed word count otherwise.  If the word
2485    count is negative, the move is performed in reverse order, i.e., starting
2486    with the last word of the block and ending with the first word of the block.
2487    If the word count is zero on entry, the move is skipped, but the stack
2488    decrement is still performed.
2489 
2490    On exit, the TOS registers are updated for the block (or partial block, in
2491    the case of an intervening interrupt), and normal or error status from the
2492    interrupt check is returned.
2493 
2494 
2495    Implementation notes:
2496 
2497     1. This routine implements the MVWS microcode subroutine.
2498 
2499     2. The type of count (unsigned or signed) is determined by whether or not
2500        the CIR holds an MTDS or MFDS instruction.
2501 
2502     3. Incrementing and masking of the TOS registers must be done after each
2503        word is moved, rather than at loop completion, so that an interrupt will
2504        flush the correct TOS values to memory.
2505 */
2506 
move_words(ACCESS_CLASS source_class,uint32 source_base,ACCESS_CLASS dest_class,uint32 dest_base,uint32 decrement)2507 static t_stat move_words (ACCESS_CLASS source_class, uint32 source_base,
2508                           ACCESS_CLASS dest_class,   uint32 dest_base,
2509                           uint32 decrement)
2510 {
2511 HP_WORD operand, *RX;
2512 uint32  increment, source_bank, dest_bank;
2513 t_stat  status;
2514 
2515 if (RA & D16_SIGN && (CIR & MTFDS_MASK) != MTFDS)       /* if the count is signed and negative */
2516     increment = 0177777;                                /*   then the memory increment is negative */
2517 else                                                    /* otherwise */
2518     increment = 1;                                      /*   the increment is positive */
2519 
2520 source_bank = source_base & ~LA_MASK;                   /* extract the source bank */
2521 dest_bank   = dest_base   & ~LA_MASK;                   /*   and destination bank in case they are needed */
2522 
2523 if (source_class == absolute)                           /* if the source transfer is absolute */
2524     RX = & RD;                                          /*   then the destination offset is in RD */
2525 else                                                    /* otherwise */
2526     RX = & RC;                                          /*   it is in RC */
2527 
2528 while (RA != 0) {                                       /* while there are words to move */
2529     cpu_read_memory (source_class,                      /*   read a source word */
2530                      source_bank | source_base + RB & LA_MASK,
2531                      &operand);
2532 
2533     cpu_write_memory (dest_class,                       /* move it to the destination */
2534                       dest_bank | dest_base + *RX & LA_MASK,
2535                       operand);
2536 
2537     RA  = RA  - increment & R_MASK;                     /* update the count */
2538     RB  = RB  + increment & R_MASK;                     /*   and the source */
2539     *RX = *RX + increment & R_MASK;                     /*     and destination offsets */
2540 
2541     if (cpu_interrupt_pending (&status))                /* if an interrupt is pending */
2542         return status;                                  /*   then return with an interrupt set up or an error */
2543     }
2544 
2545 decrement_stack (decrement);                            /* decrement the stack as indicated */
2546 return SCPE_OK;                                         /*   and return the success of the move */
2547 }
2548 
2549 
2550 
2551 /* CPU base set local instruction execution routines */
2552 
2553 
2554 /* Execute a move or special instruction (subopcode 02, field 00).
2555 
2556    This routine is called to execute the move or register instruction currently
2557    in the CIR.  The instruction formats are:
2558 
2559        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
2560      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2561      | 0   0   1   0 | 0   0   0   0 |  move op  | opts/S decrement  |  Move
2562      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2563 
2564      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2565      | 0   0   1   0 | 0   0   0   0 |  special op   | 0   0 | sp op |  Special
2566      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2567 
2568    Byte move and compare instructions that specify byte counts (e.g., MVB, CMPB)
2569    bounds-check the starting and ending addresses to avoid checking each access
2570    separately.  Instructions that do not (e.g., SCW, MVBW) must bounds-check
2571    each access, as the counts are indeterminate.
2572 
2573 
2574    Implementation notes:
2575 
2576     1. CIR bits 8-12 are decoded to determine the instruction.  For some
2577        instructions, e.g., MOVE, bits 11 and 12 either designate options or are
2578        not decoded (i.e., are "don't care" bits).  These instructions are
2579        duplicated in the SR preadjustment table and carry multiple case labels
2580        in the instruction dispatcher.
2581 
2582     2. The IXIT, LOCK, PCN, and UNLK instructions decode bits 12-15, including
2583        the reserved bits 12 and 13.  The canonical forms have the reserved bits
2584        set to zero, but the hardware decodes bits 12-15 as IXIT = 0000, LOCK =
2585        nn01, PCN = nnn0, and UNLK = nn11 (where "n..." is any collective value
2586        other than 0).  If a non-canonical form is used, and the UNDEF stop is
2587        active, a simulation stop will occur.  If the stop is bypassed or not
2588        set, then the instruction will execute as in hardware.
2589 
2590        The LSEA, SSEA, LDEA, and SDEA instructions decode bits 14-15; the
2591        reserved bits 12-13 are not decoded and do not affect the instruction
2592        interpretation.
2593 
2594     3. Two methods of mapping non-canonical forms were examined: using a 16-way
2595        remapping table if SS_UNDEF was not set and a 4-way switch statement with
2596        the default returning STOP_UNDEF, or using a 16-way switch statement with
2597        the non-canonical values returning STOP_UNDEF if SS_UNDEF is set and
2598        falling into their respective executors otherwise.  The former required
2599        significantly more instructions and imposed a lookup penalty on canonical
2600        instructions for the non-stop case.  The latter used fewer instructions,
2601        imposed no penalty in the non-stop case, and the two extra tests required
2602        only three instructions each.  The latter method was adopted.
2603 
2604     4. The MVB and MVBW byte-move instructions perform read-modify-write actions
2605        for each byte moved.  This is inefficient -- each word is read and
2606        updated twice -- but it is necessary, as interrupts are checked after
2607        each byte is moved, and it is how the microcode handles these
2608        instructions.
2609 
2610     5. The MVBW instruction microcode performs bounds checks on the movement by
2611        determining the number of words from the source and target starting
2612        addresses to the address of the top of the stack (SM).  The smaller of
2613        these values is used as a count that is decremented within the move loop.
2614        When the count reaches zero, a bounds violation occurs if the mode is not
2615        privileged.  This is used instead of comparing the source and target
2616        addresses to SM to reduce the per-iteration checks from two to one.
2617 
2618     6. The IXIT microcode assumes that the machine is in privileged mode if the
2619        dispatcher-is-active flag is set.  In simulation, the privileged mode
2620        check is performed for all IXIT paths.
2621 
2622     7. When IXIT returns to a user process, the microcode sets the "trace flag"
2623        located at Q-13 in the ICS global area to -1.  The only description of
2624        this location is in the system tables manual, which says "flag set
2625        non-zero on IXIT away from ICS."  The action to set this value was added
2626        as a patch to the Series II microcode; however, this action is not
2627        present in the corresponding Series 64 microcode.  The description
2628        appears in the MPE V tables manual for version G.01.00 but is gone from
2629        the manual for version G.08.00.  No further information regarding the
2630        purpose of this flag has been found.
2631 
2632     8. The PCN microcode clears a TOS register via a queue-down operation, if
2633        necessary, before checking that the machine is in privileged mode.  In
2634        simulation, the check is performed before the register clear.  However,
2635        if a Mode Violation trap occurs, all of the TOS registers are flushed to
2636        memory, so the result is the same.
2637 */
2638 
move_spec(void)2639 static t_stat move_spec (void)
2640 {
2641 static const uint8 preadjustment [32] = {       /* stack preadjustment, indexed by operation */
2642     3, 3, 3, 3, 3, 3, 3, 3,                     /*   MOVE MOVE MOVE MOVE MVB  MVB  MVB  MVB  */
2643     4, 4, 2, 4, 4, 4, 2, 4,                     /*   MVBL MABS SCW  MTDS MVLB MDS  SCU  MFDS */
2644     2, 2, 2, 2, 3, 3, 3, 3,                     /*   MVBW MVBW MVBW MVBW CMPB CMPB CMPB CMPB */
2645     4, 4, 0, 0, 2, 2, 0, 0                      /*   RSW/LLSH  PLDA/PSTA xSEA/xDEA IXIT/etc. */
2646     };
2647 
2648 int32        byte_count;
2649 uint32       operation, address;
2650 HP_WORD      operand, bank, offset, base;
2651 HP_WORD      byte, test_byte, terminal_byte, increment, byte_class, loop_condition;
2652 HP_WORD      source_bank, source, source_end, target_bank, target, target_end;
2653 HP_WORD      stack_db, ics_q, delta_qi, disp_counter, delta_q, new_q, new_sm, device;
2654 t_bool       q_is_qi, disp_active;
2655 ACCESS_CLASS class;
2656 t_stat       status = SCPE_OK;
2657 
2658 operation = MSSUBOP (CIR);                              /* get the suboperation from the instruction */
2659 
2660 PREADJUST_SR (preadjustment [operation]);               /* preadjust the TOS registers to the required number */
2661 
2662 switch (operation) {                                    /* dispatch the move or special operation */
2663 
2664     case 000:                                           /* MOVE (none; STUN, STOV, BNDV) */
2665     case 001:
2666     case 002:
2667     case 003:
2668         if (RA != 0) {                                  /* if the word count is non-zero */
2669             if (RA & D16_SIGN)                          /*   then if it is negative */
2670                 increment = 0177777;                    /*     then the memory increment is negative */
2671             else                                        /*   otherwise */
2672                 increment = 1;                          /*     the increment is positive */
2673 
2674             while (SR > 3)                              /* if more than three TOS register are valid */
2675                 cpu_queue_down ();                      /*   then queue them down until exactly three are left */
2676 
2677             if (CIR & DB_FLAG) {                                /* if the move is from the data segment */
2678                 class = data;                                   /*   then set for data access */
2679                 base = DB;                                      /*     and base the offset on DB */
2680 
2681                 source = DB + RB & LA_MASK;                     /* determine the starting */
2682                 source_end = source + RA - increment & LA_MASK; /*   and ending data source addresses */
2683 
2684                 if (NPRV                                        /* if the mode is non-privileged */
2685                   && (source < DL || source > SM                /*   and the starting or ending address */
2686                   || source_end < DL || source_end > SM))       /*     is outside of the data segment */
2687                     MICRO_ABORT (trap_Bounds_Violation);        /*       then trap with a Bounds Violation */
2688                 }
2689 
2690             else {                                              /* otherwise the move is from the code segment */
2691                 class = program;                                /*   so set for program access */
2692                 base = PB;                                      /*     and base the offset on PB */
2693 
2694                 source = PB + RB & LA_MASK;                     /* determine the starting */
2695                 source_end = source + RA - increment & LA_MASK; /*   and ending program source addresses */
2696 
2697                 if (source < PB || source > PL                  /* if the starting or ending address */
2698                   || source_end < PB || source_end > PL)        /*   is outside of the code segment */
2699                     MICRO_ABORT (trap_Bounds_Violation);        /*     then trap with a Bounds Violation */
2700                 }
2701 
2702             target = DB + RC & LA_MASK;                         /* calculate the starting */
2703             target_end = target + RA - increment & LA_MASK;     /*   and ending data target addresses */
2704 
2705             if (NPRV                                            /* if the mode is non-privileged */
2706               && (target < DL || target > SM                    /*   and the starting or ending target address */
2707               || target_end < DL || target_end > SM))           /*     is outside of the data segment */
2708                 MICRO_ABORT (trap_Bounds_Violation);            /*       then trap with a Bounds Violation */
2709 
2710             status = move_words (class, base, data, DB,         /* move the words and adjust the stack */
2711                                  SDEC2 (CIR));
2712             }
2713 
2714         else                                            /* otherwise there are no words to move */
2715             decrement_stack (SDEC2 (CIR));              /*   so just adjust the stack as indicated */
2716         break;
2717 
2718 
2719     case 004:                                           /* MVB (none; STUN, STOV, BNDV) */
2720     case 005:
2721     case 006:
2722     case 007:
2723         while (SR > 3)                                  /* if more than three TOS register are valid */
2724             cpu_queue_down ();                          /*   then queue them down until exactly three are left */
2725 
2726         if (RA != 0) {                                  /* if the byte count is non-zero */
2727             if (RA & D16_SIGN)                          /*   then if it is negative */
2728                 increment = 0177777;                    /*     then the memory increment is negative */
2729             else                                        /*   otherwise */
2730                 increment = 1;                          /*     the increment is positive */
2731 
2732             if (CIR & DB_FLAG) {                                /* if the move is from the data segment */
2733                 class = data;                                   /*   then classify as a data access */
2734                 source = cpu_byte_ea (data_checked, RB, RA);    /*     and convert and check the byte address */
2735                 }
2736 
2737             else {                                              /* otherwise the move is from the code segment */
2738                 class = program;                                /*   so classify as a program access */
2739                 source = cpu_byte_ea (program_checked, RB, RA); /*     and convert and check the byte address */
2740                 }
2741 
2742             target = cpu_byte_ea (data_checked, RC, RA);    /* convert the target byte address and check the bounds */
2743 
2744             while (RA != 0) {                               /* while there are bytes to move */
2745                 cpu_read_memory (class, source, &operand);  /*   read a source word */
2746 
2747                 if (RB & 1)                                 /* if the byte address is odd */
2748                     byte = LOWER_BYTE (operand);            /*   then get the lower byte */
2749                 else                                        /* otherwise the address is even */
2750                     byte = UPPER_BYTE (operand);            /*   so get the upper byte */
2751 
2752                 if ((RB & 1) == (HP_WORD) (increment == 1)) /* if the last byte of the source word was accessed */
2753                     source = source + increment & LA_MASK;  /*   then update the word address */
2754 
2755                 cpu_read_memory (data, target, &operand);   /* read the target word */
2756 
2757                 if (RC & 1)                                     /* if the byte address is odd */
2758                     operand = REPLACE_LOWER (operand, byte);    /*   then replace the lower byte */
2759                 else                                            /* otherwise the address is even */
2760                     operand = REPLACE_UPPER (operand, byte);    /*   so replace the upper byte */
2761 
2762                 cpu_write_memory (data, target, operand);   /* write the word back */
2763 
2764                 if ((RC & 1) == (HP_WORD) (increment == 1)) /* if the last byte of the target word was accessed */
2765                     target = target + increment & LA_MASK;  /*   then update the word address */
2766 
2767                 RA = RA - increment & R_MASK;               /* update the count */
2768                 RB = RB + increment & R_MASK;               /*   and the source */
2769                 RC = RC + increment & R_MASK;               /*     and destination offsets */
2770 
2771                 if (cpu_interrupt_pending (&status))        /* if an interrupt is pending */
2772                     return status;                          /*   then return with an interrupt set up or an error */
2773                 }
2774             }
2775 
2776         decrement_stack (SDEC2 (CIR));                  /* adjust the stack as indicated by the instruction */
2777         break;
2778 
2779 
2780     case 010:                                           /* MVBL (none; STUN, STOV, MODE) */
2781         if (NPRV)                                       /* if the mode is not privileged */
2782             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
2783 
2784         if (RA != 0) {                                  /* if the word count is non-zero */
2785             cpu_queue_down ();                          /*   then queue down so exactly three TOS registers are left */
2786             status = move_words (data, DB, stack, DL,   /*     and move the words and adjust the stack */
2787                                  SDEC2 (CIR));
2788             }
2789 
2790         else                                            /* otherwise there are no words to move */
2791             decrement_stack (SDEC2 (CIR));              /*   so just adjust the stack as indicated */
2792         break;
2793 
2794 
2795     case 011:                                           /* MABS (none; MODE, STUN) */
2796         if (NPRV)                                       /* if the mode is not privileged */
2797             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
2798 
2799         if (RA != 0) {                                      /* if the word count is non-zero */
2800             cpu_read_memory (stack, SM, &target_bank);      /*   then get the target data bank number */
2801 
2802             status = move_words (absolute, TO_PA (RC, 0),   /* move the words and adjust the stack */
2803                                  absolute, TO_PA (target_bank, 0),
2804                                  SDEC3 (CIR));
2805             }
2806 
2807         else                                            /* otherwise there are no words to move */
2808             decrement_stack (SDEC3 (CIR));              /*   so just adjust the stack as indicated */
2809         break;
2810 
2811 
2812     case 012:                                           /* SCW (CCB, C; STUN, STOV, BNDV) */
2813     case 016:                                           /* SCU (C; STUN, STOV, BNDV) */
2814         while (SR > 2)                                  /* if more than two TOS register are valid */
2815             cpu_queue_down ();                          /*   then queue them down until exactly two are left */
2816 
2817         test_byte     = LOWER_BYTE (RA);                /* get the test byte */
2818         terminal_byte = UPPER_BYTE (RA);                /*   and the terminal byte */
2819 
2820         source = cpu_byte_ea (data_checked, RB, 0);     /* convert the source byte address and check the bounds */
2821 
2822         cpu_read_memory (data, source, &operand);       /* read the first word */
2823 
2824         while (TRUE) {
2825             if (RB & 1) {                               /* if the byte address is odd */
2826                 if (cpu_interrupt_pending (&status))    /*   then if an interrupt is pending */
2827                     return status;                      /*     then return with an interrupt set up or an error */
2828 
2829                 byte = LOWER_BYTE (operand);            /* get the lower byte */
2830                 source = source + 1 & LA_MASK;          /*   and update the word address */
2831 
2832                 if (NPRV && source > SM)                    /* if non-privileged and the address is out of range */
2833                     MICRO_ABORT (trap_Bounds_Violation);    /*   then trap for a bounds violation */
2834 
2835                 cpu_read_memory (data, source, &operand);   /* read the next word */
2836                 }
2837 
2838             else                                        /* otherwise the address is even */
2839                 byte = UPPER_BYTE (operand);            /*   so get the upper byte */
2840 
2841             if (operation == 012)                       /* if this is the "scan while" instruction */
2842                 if (byte == test_byte)                  /*   then if the byte matches the test byte */
2843                     RB = RB + 1 & R_MASK;               /*     then update the byte offset and continue */
2844 
2845                 else {                                  /*   otherwise the "while" condition fails */
2846                     SET_CARRY (byte == terminal_byte);  /*     so set carry if the byte matches the terminal byte */
2847                     SET_CCB (byte);                     /*       and set the condition code */
2848                     break;                              /*         and terminate the scan */
2849                     }
2850             else                                        /* otherwise this is the "scan until" instruction */
2851                 if (byte == terminal_byte) {            /*   so if the byte matches the terminal byte */
2852                     STA |= STATUS_C;                    /*     then set the carry flag */
2853                     break;                              /*       and terminate the scan */
2854                     }
2855 
2856                 else if (byte == test_byte) {           /*   otherwise if the byte matches the test byte */
2857                     STA &= ~STATUS_C;                   /*     then clear the carry flag */
2858                     break;                              /*       and terminate the scan */
2859                     }
2860 
2861                 else                                    /*   otherwise neither byte matches */
2862                     RB = RB + 1 & R_MASK;               /*    so update the byte offset and continue */
2863             }
2864 
2865         decrement_stack (SDEC2 (CIR));                  /* adjust the stack as indicated by the instruction */
2866         break;
2867 
2868 
2869     case 013:                                           /* MTDS (none; MODE, DSTB, STUN, ABSDST) */
2870         if (NPRV)                                       /* if the mode is not privileged */
2871             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
2872 
2873         if (RA != 0) {                                      /* if the word count is non-zero */
2874             cpu_setup_data_segment (RD, &bank, &offset);    /*   then get the target segment bank and address */
2875 
2876             status = move_words (data, DB,                  /* move the words and adjust the stack */
2877                                  absolute, TO_PA (bank, offset),
2878                                  SDEC3 (CIR));
2879             }
2880 
2881         else                                            /* otherwise there are no words to move */
2882             decrement_stack (SDEC3 (CIR));              /*   so just adjust the stack as indicated */
2883         break;
2884 
2885 
2886     case 014:                                           /* MVLB (none; STUN, STOV, MODE) */
2887         if (NPRV)                                       /* if the mode is not privileged */
2888             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
2889 
2890         if (RA != 0) {                                  /* if the word count is non-zero */
2891             cpu_queue_down ();                          /*   then queue down so exactly three TOS registers are left */
2892 
2893             status = move_words (stack, DL, data, DB,   /* move the words and adjust the stack */
2894                                  SDEC2 (CIR));
2895             }
2896 
2897         else                                            /* otherwise there are no words to move */
2898             decrement_stack (SDEC2 (CIR));              /*   so just adjust the stack as indicated */
2899         break;
2900 
2901 
2902     case 015:                                           /* MDS (none; MODE, DSTV, STUN, ABSDST) */
2903         if (NPRV)                                       /* if the mode is not privileged */
2904             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
2905 
2906         if (RA != 0) {                                      /* if the word count is non-zero */
2907             cpu_read_memory (stack, SM, &operand);          /*   then get the target data segment number */
2908 
2909             cpu_setup_data_segment (operand, &target_bank,  /* get the target segment bank and address */
2910                                     &target);
2911 
2912             cpu_setup_data_segment (RC, &source_bank,       /*   and the source segment bank and address */
2913                                     &source);
2914 
2915             status = move_words (absolute, TO_PA (source_bank, source), /* move the words and adjust the stack */
2916                                  absolute, TO_PA (target_bank, target),
2917                                  SDEC3 (CIR));
2918             }
2919 
2920         else                                            /* otherwise there are no words to move */
2921             decrement_stack (SDEC3 (CIR));              /*   so just adjust the stack as indicated */
2922         break;
2923 
2924 
2925     case 017:                                           /* MFDS (none; MODE, DSTV, STUN, ABSDST) */
2926         if (NPRV)                                       /* if the mode is not privileged */
2927             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
2928 
2929         if (RA != 0) {                                          /* if the word count is non-zero */
2930             cpu_setup_data_segment (RC, &bank, &offset);        /*   then get the source segment bank and address */
2931 
2932             status = move_words (absolute, TO_PA (bank, offset),    /* move the words and adjust the stack */
2933                                  data, DB, SDEC3 (CIR));
2934             }
2935 
2936         else                                            /* otherwise there are no words to move */
2937             decrement_stack (SDEC3 (CIR));              /*   so just adjust the stack as indicated */
2938         break;
2939 
2940 
2941     case 020:                                           /* MVBW (CCB; STUN, STOV, BNDV) */
2942     case 021:
2943     case 022:
2944     case 023:
2945         while (SR > 2)                                  /* if more than two TOS registers are valid */
2946             cpu_queue_down ();                          /*   then queue them down until exactly two are left */
2947 
2948         source = cpu_byte_ea (data_checked, RA, 0);     /* convert the source and target */
2949         target = cpu_byte_ea (data_checked, RB, 0);     /*   byte addresses and check the starting bounds */
2950 
2951         if (source > target) {                          /* if the source is closer to SM than the target */
2952             byte_count = (int32) (SM - source + 1) * 2; /*   then set the byte count from the source */
2953 
2954             if (RA & 1)                                 /* if starting with the lower byte */
2955                 byte_count = byte_count - 1;            /*   then decrease the count by 1 */
2956             }
2957 
2958         else {                                          /* otherwise the target is closer to SM */
2959             byte_count = (int32) (SM - target + 1) * 2; /*   so set the byte count from the target */
2960 
2961             if (RB & 1)                                 /* if starting with the lower byte */
2962                 byte_count = byte_count - 1;            /*   then decrease the count by 1 */
2963             }
2964 
2965         loop_condition = (CIR & MVBW_CCF) << MVBW_CCF_SHIFT;    /* get the loop condition code flags */
2966 
2967         while (TRUE) {                                  /* while the loop condition holds */
2968             cpu_read_memory (data, source, &operand);   /*   get the source word */
2969 
2970             if (RA & 1) {                               /* if the byte address is odd */
2971                 byte = LOWER_BYTE (operand);            /*   then get the lower byte */
2972                 source = source + 1 & LA_MASK;          /*     and update the word address */
2973                 }
2974 
2975             else                                        /* otherwise the address is even */
2976                 byte = UPPER_BYTE (operand);            /*   so get the upper byte */
2977 
2978             byte_class = cpu_ccb_table [byte];          /* classify the byte */
2979 
2980             if ((byte_class & loop_condition) == 0)     /* if the loop condition is false */
2981                 break;                                  /*   then terminate the move */
2982 
2983             if (byte_class == CFE && CIR & MVBW_S_FLAG) /* if it's alphabetic and upshift is requested */
2984                 byte = TO_UPPERCASE (byte);             /*   then upshift the character */
2985 
2986             if (byte_count == 0 && NPRV)                /* if source is beyond SM and not privileged */
2987                 MICRO_ABORT (trap_Bounds_Violation);    /*   then trap for a bounds violation */
2988 
2989             cpu_read_memory (data, target, &operand);   /* read the target word */
2990 
2991             if (RB & 1)                                     /* if the byte address is odd */
2992                 operand = REPLACE_LOWER (operand, byte);    /*   then replace the lower byte */
2993             else                                            /* otherwise the address is even */
2994                 operand = REPLACE_UPPER (operand, byte);    /*   so replace the upper byte */
2995 
2996             cpu_write_memory (data, target, operand);   /* write the word back */
2997 
2998             if (RB & 1)                                 /* if the byte address is odd */
2999                 target = target + 1 & LA_MASK;          /*   then update the word address */
3000 
3001             byte_count = byte_count - 1;                /* update the count */
3002             RA = RA + 1 & R_MASK;                       /*   and the source */
3003             RB = RB + 1 & R_MASK;                       /*     and destination offsets */
3004 
3005             if (cpu_interrupt_pending (&status))        /* if an interrupt is pending */
3006                 return status;                          /*   then return with an interrupt set up or an error */
3007             }
3008 
3009         SET_CCB (byte);                                 /* set the condition code */
3010 
3011         decrement_stack (SDEC2 (CIR));                  /* adjust the stack as indicated by the instruction */
3012         break;
3013 
3014 
3015     case 024:                                           /* CMPB (CCx; STUN, STOV, BNDV) */
3016     case 025:
3017     case 026:
3018     case 027:
3019         while (SR > 3)                                  /* if more than three TOS register are valid */
3020             cpu_queue_down ();                          /*   then queue them down until exactly three are left */
3021 
3022         if (RA != 0) {                                  /* if the byte count is non-zero */
3023             if (RA & D16_SIGN)                          /*   then if it is negative */
3024                 increment = 0177777;                    /*     then the memory increment is negative */
3025             else                                        /*   otherwise */
3026                 increment = 1;                          /*     the increment is positive */
3027 
3028             if (CIR & DB_FLAG) {                                /* if the comparison is from the data segment */
3029                 class = data;                                   /*   then classify as a data access */
3030                 source = cpu_byte_ea (data_checked, RB, RA);    /*     and convert and check the byte address */
3031                 }
3032 
3033             else {                                              /* otherwise the comparison is from the code segment */
3034                 class = program;                                /*   so classify as a program access */
3035                 source = cpu_byte_ea (program_checked, RB, RA); /*     and convert and check the byte address */
3036                 }
3037 
3038             target = cpu_byte_ea (data_checked, RC, RA);    /* convert the target byte address and check the bounds */
3039 
3040             while (RA != 0) {                               /* while there are bytes to compare */
3041                 cpu_read_memory (class, source, &operand);  /*   read a source word */
3042 
3043                 if (RB & 1)                                 /* if the byte address is odd */
3044                     byte = LOWER_BYTE (operand);            /*   then get the lower byte */
3045                 else                                        /* otherwise the address is even */
3046                     byte = UPPER_BYTE (operand);            /*   so get the upper byte */
3047 
3048                 if ((RB & 1) == (HP_WORD) (increment == 1)) /* if the last byte of the source word was accessed */
3049                     source = source + increment & LA_MASK;  /*   then update the word address */
3050 
3051                 cpu_read_memory (data, target, &operand);   /* read the target word */
3052 
3053                 if (RC & 1)                                 /* if the byte address is odd */
3054                     test_byte = LOWER_BYTE (operand);       /*   then get the lower byte */
3055                 else                                        /* otherwise the address is even */
3056                     test_byte = UPPER_BYTE (operand);       /*   so get the upper byte */
3057 
3058                 if (test_byte != byte)                      /* if the bytes do not compare */
3059                     break;                                  /*   then terminate the loop */
3060 
3061                 if ((RC & 1) == (HP_WORD) (increment == 1)) /* if the last byte of the target word was accessed */
3062                     target = target + increment & LA_MASK;  /*   then update the word address */
3063 
3064                 RA = RA - increment & R_MASK;               /* update the count */
3065                 RB = RB + increment & R_MASK;               /*   and the source */
3066                 RC = RC + increment & R_MASK;               /*     and destination offsets */
3067 
3068                 if (cpu_interrupt_pending (&status))        /* if an interrupt is pending */
3069                     return status;                          /*   then return with an interrupt set up or an error */
3070                 }
3071             }
3072 
3073         if (RA == 0)                                    /* if the count expired */
3074             SET_CCE;                                    /*   then set condition code "equal" */
3075 
3076         else if (test_byte > byte)                      /* otherwise if the target byte > the source byte */
3077             SET_CCG;                                    /*   set condition code "greater than" */
3078 
3079         else                                            /* otherwise the target byte < the source byte */
3080             SET_CCL;                                    /*   so set condition code "less than" */
3081 
3082         decrement_stack (SDEC2 (CIR));                  /* adjust the stack as indicated by the instruction */
3083         break;
3084 
3085 
3086     case 030:                                           /* RSW and LLSH */
3087     case 031:
3088         if (CIR & 1) {                                  /* LLSH (CCx; STUN, MODE) */
3089             if (NPRV)                                   /* if the mode is not privileged */
3090                 MICRO_ABORT (trap_Privilege_Violation); /*   then abort with a privilege violation */
3091 
3092             while (X > 0) {                             /* while the link count is non-zero */
3093                 cpu_read_memory (absolute,              /*   read the target value */
3094                                  TO_PA (RB, RA + RD & LA_MASK),
3095                                  &target);
3096 
3097                 if (target >= RC) {                     /* if the target is greater than or equal to the test word */
3098                     if (target == DV_UMAX)              /*   then if the target is the largest possible value */
3099                         SET_CCG;                        /*     then set condition code "greater than" */
3100                     else                                /*   otherwise */
3101                         SET_CCE;                        /*     set condition code "equal" */
3102                     break;                              /* end the search */
3103                     }
3104 
3105                 address = TO_PA (RB, RA + 1 & LA_MASK); /* otherwise save the link offset address */
3106 
3107                 cpu_read_memory (absolute, TO_PA (RB, RA), &RB);    /* read the next link bank */
3108                 cpu_read_memory (absolute, address, &RA);           /*   and link offset */
3109 
3110                 X = X - 1 & R_MASK;                     /* decrement the count */
3111 
3112                 if (cpu_interrupt_pending (&status))    /* if an interrupt is pending */
3113                     return status;                      /*   then return with an interrupt set up or an error */
3114                 }
3115 
3116             if (X == 0)                                 /* if the count expired */
3117                 SET_CCL;                                /*   then set condition code "less than" */
3118             }
3119 
3120         else {                                          /* RSW (CCA; STUN, STOV) */
3121             cpu_push ();                                /* push the stack down */
3122             RA = SWCH;                                  /*   and set the TOS from the switch register */
3123 
3124             SET_CCA (RA, 0);                            /* set the condition code */
3125             }
3126         break;
3127 
3128 
3129     case 032:                                           /* PLDA and PSTA */
3130     case 033:
3131         if (PRIV)                                       /* if the mode is privileged */
3132             if (CIR & 1) {                              /* PSTA (none; STUN, MODE) */
3133                 PREADJUST_SR (1);                       /* ensure a valid TOS register */
3134                 cpu_write_memory (absolute_mapped,      /*   before writing the TOS to memory */
3135                                   X, RA);               /*     at address X */
3136                 cpu_pop ();                             /*       and popping the stack */
3137                 }
3138 
3139             else {                                      /* PLDA (CCA; STOV, MODE) */
3140                 cpu_read_memory (absolute_mapped,       /* read the value at address X */
3141                                  X, &operand);
3142                 cpu_push ();                            /* push the stack down */
3143                 RA = operand;                           /*   and store the value on the TOS */
3144 
3145                 SET_CCA (RA, 0);                        /* set the condition code */
3146                 }
3147 
3148         else                                            /* otherwise the mode is not privileged */
3149             MICRO_ABORT (trap_Privilege_Violation);     /*   so abort with a privilege violation */
3150         break;
3151 
3152 
3153     case 034:                                           /* LSEA, SSEA, LDEA, and SDEA */
3154     case 035:
3155         if (NPRV)                                       /* if the mode is not privileged */
3156             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3157 
3158         switch (SPECOP (CIR) & 3) {                     /* dispatch the special operation (bits 12-13 are not decoded) */
3159 
3160             case 000:                                   /* LSEA (CCA; STUN, STOV, MODE) */
3161                 while (SR > 2)                          /* if more than two TOS register are valid */
3162                     cpu_queue_down ();                  /*   then queue them down until exactly two are left */
3163 
3164                 address = TO_PA (RB, RA);               /* form the physical address */
3165                 cpu_read_memory (absolute,              /*   and read the word from memory */
3166                                  address, &operand);
3167 
3168                 cpu_push ();                            /* push the stack down */
3169                 RA = operand;                           /*   and store the word on the TOS */
3170 
3171                 SET_CCA (RA, 0);                        /* set the condition code */
3172                 break;
3173 
3174 
3175             case 001:                                   /* SSEA (none; STUN, STOV, MODE) */
3176                 PREADJUST_SR (3);                       /* ensure there are three valid TOS registers */
3177 
3178                 while (SR > 3)                          /* if more than three TOS register are valid */
3179                     cpu_queue_down ();                  /*   then queue them down until exactly three are left */
3180 
3181                 address = TO_PA (RC, RB);               /* form the physical address */
3182                 cpu_write_memory (absolute,             /*   and write the word on the TOS to memory */
3183                                   address, RA);
3184 
3185                 cpu_pop ();                             /* pop the TOS */
3186                 break;
3187 
3188 
3189             case 002:                                   /* LDEA (CCA; STUN, STOV, MODE) */
3190                 while (SR > 2)                          /* if more than two TOS register are valid */
3191                     cpu_queue_down ();                  /*   then queue them down until exactly two are left */
3192 
3193                 address = TO_PA (RB, RA);               /* form the physical address */
3194                 cpu_read_memory (absolute,              /*   and read the MSW from memory */
3195                                  address, &operand);
3196 
3197                 cpu_push ();                            /* push the stack down */
3198                 RA = operand;                           /*   and store the MSW on the TOS */
3199 
3200                 address = TO_PA (RC, RB + 1 & LA_MASK); /* increment the physical address */
3201                 cpu_read_memory (absolute,              /*   and read the LSW from memory */
3202                                  address, &operand);
3203 
3204                 cpu_push ();                            /* push the stack down again */
3205                 RA = operand;                           /*   and store the LSW on the TOS */
3206 
3207                 SET_CCA (RB, RA);                       /* set the condition code */
3208                 break;
3209 
3210 
3211             case 003:                                   /* SDEA (none; STUN, MODE) */
3212                 PREADJUST_SR (4);                       /* ensure there are four valid TOS registers */
3213 
3214                 address = TO_PA (RD, RC);               /* form the physical address */
3215                 cpu_write_memory (absolute,             /* write the MSW from the NOS to memory */
3216                                   address, RB);
3217 
3218                 address = TO_PA (RD, RC + 1 & LA_MASK); /* increment the physical address */
3219                 cpu_write_memory (absolute,             /*   and write the LSW on the TOS to memory */
3220                                   address, RA);
3221 
3222                 cpu_pop ();                             /* pop the TOS */
3223                 cpu_pop ();                             /*   and the NOS */
3224                 break;
3225             }                                           /* all cases are handled */
3226         break;
3227 
3228 
3229     case 036:                                           /* IXIT, LOCK, PCN, and UNLK */
3230     case 037:
3231         if (NPRV)                                       /* if the mode is not privileged */
3232             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3233 
3234         switch (SPECOP (CIR)) {                         /* dispatch the special operation */
3235 
3236             case 000:                                   /* IXIT (none; MODE, STOV, CSTV, TRACE, ABS CST, BNDV) */
3237                 SR = 0;                                 /* invalidate the TOS registers */
3238 
3239                 cpu_read_memory (stack, Q, &delta_q);               /* read the stack marker link value */
3240                 cpu_read_memory (absolute, ICS_Q, &ics_q);          /*   the stack marker initial value */
3241                 cpu_read_memory (absolute, ics_q, &delta_qi);       /*     the dispatcher stack marker link */
3242                 cpu_read_memory (absolute, ics_q - 18 & LA_MASK,    /*       and the dispatcher counter */
3243                                  &disp_counter);
3244 
3245                 q_is_qi = (Q == ics_q);                     /* TRUE if Q = QI, i.e., a user process was interrupted */
3246                 disp_active = (CPX1 & cpx1_DISPFLAG) != 0;  /* TRUE if the dispatcher is currently active */
3247 
3248                 new_sm = 0;                                 /* these will be set by every path through IXIT */
3249                 new_q  = 0;                                 /*   but the compiler doesn't realize this and so warns */
3250 
3251                 if (!disp_active) {                         /* if not called by the dispatcher to start a process */
3252                     if (STATUS_CS (STA) > 1) {              /*   then if an external interrupt was serviced  */
3253                         cpu_read_memory (stack,             /*     then get the device number (parameter) */
3254                                          Q + 3 & LA_MASK,
3255                                          &device);
3256 
3257                         iop_direct_io (device, ioRIN, 0);   /* send a Reset Interrupt I/O order to the device */
3258 
3259                         if (CPX1 & cpx1_IOTIMER)                    /* if an I/O timeout occurred */
3260                             MICRO_ABORT (trap_SysHalt_IO_Timeout);  /*   then trap for a system halt */
3261 
3262                         if (iop_interrupt_request_set       /* if a hardware interrupt request is pending */
3263                           && STA & STATUS_I)                /*   and interrupts are enabled */
3264                             device = iop_poll ();           /*     then poll to see if it can be granted */
3265 
3266                         if (CPX1 & cpx1_EXTINTR) {          /* if a device is ready to interrupt */
3267                             CPX1 &= ~cpx1_EXTINTR;          /*   then handle it without exiting and restacking */
3268 
3269                             tprintf (cpu_dev, DEB_INSTR, BOV_FORMAT "  external interrupt\n",
3270                                      PBANK, P - 1 & R_MASK, device);
3271 
3272                             cpu_setup_irq_handler (irq_IXIT, device);   /* set up entry into the interrupt handler */
3273                             break;                                      /*   with the prior context still on the stack */
3274                             }
3275                         }
3276 
3277                     if (delta_q & STMK_D) {             /* if the dispatcher was interrupted */
3278                         CPX1 |= cpx1_DISPFLAG;          /*   then set the dispatcher-is-active flag */
3279 
3280                         new_q = ics_q;                  /* set the returning Q value */
3281                         new_sm = ics_q + 2 & R_MASK;    /*   and the returning SM value */
3282 
3283                         if (delta_qi & STMK_D           /* if the dispatcher is scheduled */
3284                           && disp_counter == 0) {       /*   and enabled */
3285                             cpu_start_dispatcher ();    /*     then restart it now */
3286                             break;                      /*       to redispatch */
3287                             }
3288                         }
3289                     }
3290 
3291                 if (disp_active                                             /* if the dispatcher is launching a process */
3292                   || q_is_qi && ((delta_q & STMK_D) == 0                    /*   or a process was interrupted */
3293                                    || disp_counter != 0)) {                 /*     or the dispatcher is disabled */
3294                     cpu_read_memory (absolute, Q - 4 & LA_MASK, &stack_db); /*       then read the DB and stack bank */
3295                     cpu_read_memory (absolute, Q - 5 & LA_MASK, &SBANK);    /*         for the return process */
3296 
3297                     cpu_read_memory (absolute, Q - 7 & LA_MASK, &operand);  /* read the stack-DB-relative data limit */
3298                     DL = stack_db + operand & R_MASK;                       /*   and restore it */
3299 
3300                     cpu_read_memory (absolute, Q - 8 & LA_MASK, &operand);  /* read the stack-DB-relative stack limit */
3301                     Z = stack_db + operand & R_MASK;                        /*   and restore it */
3302 
3303                     cpu_write_memory (absolute, Q - 13, D16_UMAX);          /* set the trace flag to a non-zero value */
3304 
3305                     cpu_read_memory (absolute, Q - 6 & LA_MASK, &operand);  /* read the stack-DB-relative stack pointer */
3306                     Q = stack_db + operand - 2 & R_MASK;                    /*   and restore it */
3307 
3308                     cpu_read_memory (stack, Q, &delta_q);       /* read the relative frame pointer */
3309 
3310                     CPX1 &= ~(cpx1_ICSFLAG | cpx1_DISPFLAG);    /* clear the ICS and dispatcher-is-running flags */
3311 
3312                     new_sm = Q - 4 & R_MASK;                    /* set up the return TOS pointer */
3313                     new_q = Q - delta_q & R_MASK;               /*   and frame pointer */
3314                     }
3315 
3316                 if (!disp_active                                /* if not launching a new process */
3317                   && !q_is_qi                                   /*   and returning */
3318                   && ((delta_q & STMK_D) == 0                   /*     to an interrupted interrupt handler */
3319                     || (delta_qi & STMK_D) == 0                 /*     or to the interrupted dispatcher */
3320                     || disp_counter != 0)) {                    /*     or to the dispatcher requesting a disabled redispatch */
3321                     new_sm = Q - 4 & R_MASK;                    /*       then set up the return TOS pointer */
3322                     new_q = Q - (delta_q & ~STMK_D) & R_MASK;   /*         and frame pointer */
3323                     }
3324 
3325                 cpu_read_memory (stack, Q + 1 & LA_MASK, &DBANK);   /* restore the data bank */
3326                 cpu_read_memory (stack, Q + 2 & LA_MASK, &DB);      /*   and data base values */
3327 
3328                 cpu_exit_procedure (new_q, new_sm, 0);  /* set up the return code segment and stack */
3329                 break;
3330 
3331 
3332             case 005:                                   /* these decode as LOCK in hardware */
3333             case 011:
3334             case 015:
3335                 if (cpu_stop_flags & SS_UNDEF) {        /* if the undefined instruction stop is active */
3336                     status = STOP_UNIMPL;               /*   then stop the simulator */
3337                     break;
3338                     }
3339 
3340             /* fall through into the LOCK executor */
3341 
3342             case 001:                                   /* LOCK (none; MODE) */
3343                 if (UNIT_CPU_MODEL == UNIT_SERIES_II) { /* if the CPU is a Series II */
3344                     status = STOP_UNIMPL;               /*   THIS INSTRUCTION IS NOT IMPLEMENTED YET */
3345                     }
3346 
3347                 else                                    /* otherwise the instruction */
3348                     status = STOP_UNIMPL;               /*   is not implemented on this machine */
3349                 break;
3350 
3351 
3352             case 004:                                   /* these decode as PCN in hardware */
3353             case 006:
3354             case 010:
3355             case 012:
3356             case 014:
3357             case 016:
3358                 if (cpu_stop_flags & SS_UNDEF) {        /* if the undefined instruction stop is active */
3359                     status = STOP_UNIMPL;               /*   then stop the simulator */
3360                     break;
3361                     }
3362 
3363             /* fall through into the PCN executor */
3364 
3365             case 002:                                       /* PCN (none; STOV, MODE) */
3366                 cpu_push ();                                /* push the stack down */
3367 
3368                 if (UNIT_CPU_MODEL == UNIT_SERIES_II)       /* if the CPU is a Series II */
3369                     RA = PCN_SERIES_II;                     /*   then the CPU number is 1 */
3370 
3371                 else if (UNIT_CPU_MODEL == UNIT_SERIES_III) /* if the CPU is a Series III */
3372                     RA = PCN_SERIES_III;                    /*   then the CPU number is 2 */
3373 
3374                 else                                        /* if it's anything else */
3375                     status = SCPE_IERR;                     /*   then there's a problem! */
3376                 break;
3377 
3378 
3379             case 007:                                   /* these decode as UNLK in hardware */
3380             case 013:
3381             case 017:
3382                 if (cpu_stop_flags & SS_UNDEF) {        /* if the undefined instruction stop is active */
3383                     status = STOP_UNIMPL;               /*   then stop the simulator */
3384                     break;
3385                     }                                   /* otherwise fall into the UNLK executor */
3386 
3387             /* fall through into the UNLK executor */
3388 
3389             case 003:                                   /* UNLK (none; MODE) */
3390                 if (UNIT_CPU_MODEL == UNIT_SERIES_II) { /* if the CPU is a Series II */
3391                     status = STOP_UNIMPL;               /*   THIS INSTRUCTION IS NOT IMPLEMENTED YET */
3392                     }
3393 
3394                 else                                    /* otherwise the instruction */
3395                     status = STOP_UNIMPL;               /*   is not implemented on this machine */
3396                 break;
3397             }                                           /* all cases are handled */
3398         break;
3399     }                                                   /* all cases are handled */
3400 
3401 return status;                                          /* return the execution status */
3402 }
3403 
3404 
3405 /* Execute a firmware extension instruction (subopcode 02, field 01).
3406 
3407    This routine is called to execute the DMUL, DDIV, or firmware extension
3408    instruction currently in the CIR.  Optional firmware extension instruction
3409    sets occupy instruction codes 020400-020777.  Two instructions in this range
3410    are base set instructions: DMUL (020570) and DDIV (020571).  The instruction
3411    formats are:
3412 
3413        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
3414      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3415      | 0   0   1   0 | 0   0   0   1 | 0   1   1   1 | 1   0   0 | x |  DMUL/DDIV
3416      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3417 
3418      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3419      | 0   0   1   0 | 0   0   0   1 | 0   0   0   0 | 1 | ext fp op |  Extended FP
3420      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3421 
3422      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3423      | 0   0   1   0 | 0   0   0   1 | 0   0   1   1 |   COBOL op    |  COBOL
3424      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3425 
3426      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3427      | 0   0   1   0 | 0   0   0   1 | 1 |  options  |  decimal op   |  Decimal
3428      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3429 
3430    In hardware, optional instructions depend on the presence of the microcode
3431    that implements them.  All extension instructions initially check the
3432    "firmware option present" bit in CPX1 before branching to a calculated
3433    address for the extension microcode.  This bit is set by comparing jumpers
3434    W1-W8 on the CIR PCA to CIR bits 8-11.  If the "present" bit is clear, the
3435    firmware takes an Unimplemented Instruction trap.
3436 
3437    A machine with no options has all jumpers installed.  Removing jumpers sets
3438    the "firmware option present" bit for specific CIR ranges, as follows:
3439 
3440      Jumper  CIR 8-11    CIR Range    Option
3441      ------  --------  -------------  -----------------------------------------
3442        W1      0000    020400-020417  Extended Instruction Set (Floating Point)
3443        W2      0001    020420-020437  32105A APL Instruction Set
3444        W3      0010    020440-020457
3445        W4      0011    020460-020477  32234A COBOL II Extended Instruction Set
3446        W5      0100    020500-020517
3447        W6      0101    020520-020537
3448        W7      0110    020540-020557
3449        --      0111    020560-020577  Base Set (DMUL/DDIV)
3450        W8      1xxx    020600-020777  Extended Instruction Set (Decimal Arith)
3451 
3452    The range occupied by the base set has no jumper and is hardwired as
3453    "present".  In simulation, presence is determined by the settings of the CPU
3454    unit flags.
3455 
3456 
3457    Implementation notes:
3458 
3459     1. In simulation, the DDIV instruction must check for 32-bit overflow before
3460        dividing.  Otherwise, an Integer Overflow Exception may occur on the
3461        underlying machine instruction, aborting the simulator.
3462 */
3463 
firmware_extension(void)3464 static t_stat firmware_extension (void)
3465 {
3466 int32    dividend, divisor, quotient, remainder;
3467 uint32   operation, suboperation;
3468 t_int64  product;
3469 t_uint64 check;
3470 t_stat   status = SCPE_OK;
3471 
3472 operation = FIRMEXTOP (CIR);                            /* get the operation from the instruction */
3473 
3474 switch (operation) {                                    /* dispatch the operation */
3475 
3476     case 003:                                           /* COBOL II Extended Instruction Set */
3477         if (cpu_unit [0].flags & UNIT_CIS)              /* if the firmware is installed */
3478             status = cpu_cis_op ();                     /*   then call the CIS dispatcher */
3479         else                                            /* otherwise */
3480             status = STOP_UNIMPL;                       /*   the instruction range decodes as unimplemented */
3481         break;
3482 
3483 
3484     case 007:                                           /* base set */
3485         suboperation = FMEXSUBOP (CIR);                 /* get the suboperation from the instruction */
3486 
3487         switch (suboperation) {                         /* dispatch the suboperation */
3488 
3489             case 010:                                   /* DMUL (CCA, O; STUN, ARITH) */
3490                 product =                               /* form a 64-bit product from a 32 x 32 multiplication */
3491                    INT32 (TO_DWORD (RD, RC)) * INT32 (TO_DWORD (RB, RA));
3492 
3493                 check = (t_uint64) product & S32_OVFL_MASK;             /* check the top 33 bits and set overflow */
3494                 SET_OVERFLOW (check != 0 && check != S32_OVFL_MASK);    /*   if they are not all zeros or all ones */
3495 
3496                 cpu_pop ();                             /* pop two words */
3497                 cpu_pop ();                             /*   from the stack */
3498 
3499                 RB = UPPER_WORD (product);              /* move the 32-bit product */
3500                 RA = LOWER_WORD (product);              /*   to the stack */
3501 
3502                 SET_CCA (RB, RA);                       /* set the condition code */
3503                 break;
3504 
3505 
3506             case 011:                                   /* DDIV (CCA, O; STUN, ARITH) */
3507                 dividend = INT32 (TO_DWORD (RD, RC));   /* get the 32-bit signed dividend */
3508                 divisor  = INT32 (TO_DWORD (RB, RA));   /*   and the 32-bit signed divisor from the stack */
3509 
3510                 if (divisor == 0)                           /* if dividing by zero */
3511                     MICRO_ABORT (trap_Integer_Zero_Divide); /*   then trap or set the overflow flag */
3512 
3513                 if (dividend == (int32) D32_SMIN && divisor == -1) {    /* if the division will overflow */
3514                     quotient  = dividend;                               /*   then set the quotient */
3515                     remainder = 0;                                      /*     and remainder explicitly */
3516                     SET_OVERFLOW (TRUE);                                /*       and trap or set overflow */
3517                     }
3518 
3519                 else {                                  /* otherwise */
3520                     quotient  = dividend / divisor;     /*   form the 32-bit signed quotient */
3521                     remainder = dividend % divisor;     /*     and 32-bit signed remainder */
3522                     }
3523 
3524                 RD = UPPER_WORD (quotient);             /* move the 32-bit quotient */
3525                 RC = LOWER_WORD (quotient);             /*   to the stack */
3526 
3527                 RB = UPPER_WORD (remainder);            /* move the 32-bit remainder */
3528                 RA = LOWER_WORD (remainder);            /*   to the stack */
3529 
3530                 SET_CCA (RD, RC);                       /* set the condition code */
3531                 break;
3532 
3533 
3534             default:
3535                 status = STOP_UNIMPL;                   /* the rest of the base set codes are unimplemented */
3536             }
3537         break;
3538 
3539 
3540     default:
3541         status = STOP_UNIMPL;                           /* the firmware extension instruction is unimplemented */
3542     }
3543 
3544 return status;                                          /* return the execution status */
3545 }
3546 
3547 
3548 /* Execute an I/O or control instruction (subopcode 03, field 00).
3549 
3550    This routine is called to execute the I/O or control instruction currently in
3551    the CIR.  The instruction formats are:
3552 
3553        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
3554      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3555      | 0   0   1   1 | 0   0   0   0 |  I/O opcode   |    K field    |  I/O
3556      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3557 
3558      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3559      | 0   0   1   1 | 0   0   0   0 |  cntl opcode  | 0   0 | cn op |  Control
3560      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3561 
3562 
3563 
3564    Implementation notes:
3565 
3566     1. The PAUS instruction suspends instruction execution until an interrupt
3567        occurs.  It is intended to idle the CPU while suspending instruction
3568        fetches from memory to allow full-bandwidth access to the selector and
3569        multiplexer channels.
3570 
3571        If the simulation is stopped while a PAUS instruction is executing, it
3572        may be resumed after the PAUS by adding the -B switch to the STEP,
3573        CONTINUE, GO, or RUN command.  This corresponds in hardware to pressing
3574        the RUN/HALT switch twice.  Without the switch, execution will resume at
3575        the PAUS instruction.
3576 
3577        The CNTR register is set to the value of the SR register when the
3578        micromachine pauses.  This allows the SR value to be accessed by the
3579        diagnostics.  The top-of-stack registers are flushed to main memory when
3580        this occurs, which clears SR.  Resuming into a PAUS and then stopping the
3581        simulation again will show CNTR = 0.
3582 
3583     2. The SED instruction decodes bits 12-15, including the reserved bits
3584        12-14.  The canonical form has the reserved bits set to zero, and in
3585        hardware SED works correctly only if opcodes 030040 and 030041 are used.
3586        Opcodes 030042-030057 also decode as SED, but the status register is set
3587        improperly (the I bit is cleared, bits 12-15 are rotated right twice and
3588        then ORed into the status register).  If a non-canonical form is used in
3589        simulation, and the UNDEF stop is active, a simulation stop will occur.
3590        If the stop is bypassed or not set, then the instruction will execute as
3591        though the reserved bits were zero.
3592 
3593     3. The CMD instruction is simulated by assuming that the addressed module
3594        will send a return message to the CPU, causing a module interrupt.  If
3595        the module is the CPU, then the "return message" is the originating
3596        message, including whatever MOP was specified.  Memory modules return a
3597        no-operation MOP in response to a read or read/write ones MOP.  Sending a
3598        read/write ones MOP to a Series II memory module sets the addressed
3599        location to 177777 before the read value is returned.
3600 
3601     4. The module interrupt signal is qualified by the I-bit of the status
3602        register.  This is simulated by setting the cpx1_MODINTR bit in the CMD
3603        executor if the I-bit is set, by clearing the cpx1_MODINTR bit in the SED
3604        0 executor, and by setting the bit in the SED 1 executor if the MOD
3605        register is non-zero (indicating a pending module interrupt that has not
3606        been serviced).
3607 */
3608 
io_control(void)3609 static t_stat io_control (void)
3610 {
3611 static const uint8 preadjustment [16] = {       /* stack preadjustment, indexed by operation */
3612     1, 0, 0, 2, 1, 0, 1, 1,                     /*   LST  PAUS SED  **** **** **** XEQ  SIO  */
3613     0, 1, 0, 1, 1, 2, 0, 0                      /*   RIO  WIO  TIO  CIO  CMD  SST  SIN  HALT */
3614     };
3615 
3616 uint32  operation, address, offset, module;
3617 HP_WORD operand, command, ics_q, delta_qi, disp_counter;
3618 t_stat  status = SCPE_OK;
3619 
3620 operation = IOCSUBOP (CIR);                             /* get the suboperation from the instruction */
3621 
3622 PREADJUST_SR (preadjustment [operation]);               /* preadjust the TOS registers to the required number */
3623 
3624 switch (operation) {                                    /* dispatch the I/O or control operation */
3625 
3626     case 000:                                           /* LST (CCA; STUN, STOV, MODE) */
3627         offset = IO_K (CIR);                            /* get the system table pointer offset */
3628 
3629         if (offset == 0) {                              /* if the specified offset is zero */
3630             cpu_read_memory (absolute,                  /*   then offset using the TOS */
3631                              RA + SGT_POINTER & LA_MASK,
3632                              &operand);
3633             cpu_pop ();                                 /* delete the TOS */
3634             }
3635 
3636         else                                            /* otherwise */
3637             cpu_read_memory (absolute,                  /*   use the specified offset */
3638                              offset + SGT_POINTER,      /*     which cannot overflow */
3639                              &operand);
3640 
3641         if (NPRV)                                       /* if the mode is not privileged */
3642             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3643 
3644         cpu_push ();                                    /* push the stack down */
3645         cpu_read_memory (absolute,                      /*   and read the table word onto the TOS */
3646                          X + operand + SGT_POINTER & LA_MASK,
3647                          &RA);
3648 
3649         SET_CCA (RA, 0);                                /* set the condition code */
3650       break;
3651 
3652 
3653     case 001:                                           /* PAUS (none; MODE) */
3654         if (NPRV)                                       /* if the mode is not privileged */
3655             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3656 
3657         CNTR = SR;                                      /* copy the stack register to the counter */
3658         cpu_flush ();                                   /*   and flush the TOS registers to memory */
3659 
3660         if (cpu_stop_flags & SS_PAUSE)                  /* if the pause stop is active */
3661             status = STOP_PAUS;                         /*   then stop the simulation */
3662 
3663         else if (!(cpu_stop_flags & SS_BYPASSED))       /* otherwise if stops are not bypassed */
3664             cpu_micro_state = paused;                   /*   then pause the micromachine */
3665         break;                                          /* otherwise bypass the pause */
3666 
3667 
3668     case 002:                                           /* SED (none; MODE) */
3669         if (NPRV)                                       /* if the mode is not privileged */
3670             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3671 
3672         if (IO_K (CIR) > 1                              /* if the K field is not 0 or 1 */
3673           && cpu_stop_flags & SS_UNDEF)                 /*   and the undefined instruction stop is active */
3674             status = STOP_UNIMPL;                       /*     then stop the simulator */
3675 
3676         else if (CIR & 1) {                             /* otherwise if bit 15 of the instruction is 1 */
3677             STA |= STATUS_I;                            /*   then enable interrupts */
3678 
3679             if (MOD != 0)                               /* if a module interrupt is pending */
3680                 CPX1 |= cpx1_MODINTR;                   /*   then request it now */
3681             }
3682 
3683         else {                                          /* otherwise */
3684             STA &= ~STATUS_I;                           /*   disable interrupts */
3685             CPX1 &= ~cpx1_MODINTR;                      /*     and clear any indicated module interrupt */
3686             }
3687         break;
3688 
3689 
3690     case 003:                                           /* XCHD, PSDB, DISP, and PSEB */
3691         if (NPRV)                                       /* if the mode is not privileged */
3692             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3693 
3694         switch (CNTLOP (CIR)) {                         /* dispatch the control operation */
3695 
3696             case 000:                                   /* XCHD (none; STUN, MODE) */
3697                 operand = RA;                           /* exchange the */
3698                 RA = DB;                                /*   RA and */
3699                 DB = operand;                           /*     DB values */
3700 
3701                 operand = RB;                           /* exchange the */
3702                 RB = DBANK;                             /*   RB and */
3703                 DBANK = operand & BA_MASK;              /*     DBANK values */
3704 
3705                 cpu_base_changed = TRUE;                /* this instruction changed the base registers */
3706                 break;
3707 
3708 
3709             case 005:                                   /* these decode as PSDB in hardware */
3710             case 011:
3711             case 015:
3712                 if (cpu_stop_flags & SS_UNDEF) {        /* if the undefined instruction stop is active */
3713                     status = STOP_UNIMPL;               /*   then stop the simulator */
3714                     break;
3715                     }
3716 
3717             /* fall through into the PSDB executor */
3718 
3719             case 001:                                   /* PSDB (none; MODE) */
3720                 cpu_read_memory (absolute, ICS_Q,       /* read the ICS stack marker pointer value */
3721                                  &ics_q);
3722 
3723                 cpu_read_memory (absolute, ics_q - 18 & LA_MASK,    /* read the dispatcher counter */
3724                                  &disp_counter);
3725 
3726                 cpu_write_memory (absolute, ics_q - 18 & LA_MASK,   /*  and increment it */
3727                                   disp_counter + 1 & DV_MASK);
3728                 break;
3729 
3730 
3731             case 004:                                   /* these decode as DISP in hardware */
3732             case 006:
3733             case 010:
3734             case 012:
3735             case 014:
3736             case 016:
3737                 if (cpu_stop_flags & SS_UNDEF) {        /* if the undefined instruction stop is active */
3738                     status = STOP_UNIMPL;               /*   then stop the simulator */
3739                     break;
3740                     }
3741 
3742             /* fall through into the DISP executor */
3743 
3744             case 002:                                   /* DISP (CCx; MODE, CSTV, TRACE, ABS CST, BNDV) */
3745                 cpu_read_memory (absolute, ICS_Q,       /* read the stack marker initial value */
3746                                  &ics_q);
3747 
3748                 cpu_read_memory (absolute, ics_q - 18 & LA_MASK,    /* read the dispatcher counter */
3749                                  &disp_counter);
3750 
3751                 cpu_write_memory (absolute, ics_q,                  /* set the dispatcher-is-scheduled flag */
3752                                   STMK_D);
3753 
3754                 if (CPX1 & (cpx1_ICSFLAG | cpx1_DISPFLAG)   /* if the dispatcher is currently running */
3755                   || disp_counter > 0)                      /*   or the dispatcher is inhibited */
3756                     SET_CCG;                                /*     then set condition code "greater than" */
3757 
3758                 else {                                      /* otherwise */
3759                     SET_CCE;                                /*   set condition code "equal" */
3760                     cpu_setup_ics_irq (irq_Dispatch, 0);    /*     and set up the ICS */
3761 
3762                     STA = STATUS_M;                         /* enter privileged mode with interrupts disabled */
3763                     cpu_start_dispatcher ();                /*   and start the dispatcher */
3764                     }
3765                 break;
3766 
3767 
3768             case 007:                                   /* these decode as PSEB in hardware */
3769             case 013:
3770             case 017:
3771                 if (cpu_stop_flags & SS_UNDEF) {        /* if the undefined instruction stop is active */
3772                     status = STOP_UNIMPL;               /*   then stop the simulator */
3773                     break;
3774                     }
3775 
3776             /* fall through into the PSEB executor */
3777 
3778             case 003:                                   /* PSEB (CCx; MODE, CSTV, TRACE, ABS CST, BNDV) */
3779                 cpu_read_memory (absolute, ICS_Q,       /* read the stack marker initial value */
3780                                  &ics_q);
3781 
3782                 cpu_read_memory (absolute, ics_q - 18 & LA_MASK,    /* read the dispatcher counter */
3783                                  &disp_counter);
3784 
3785                 cpu_write_memory (absolute, ics_q - 18 & LA_MASK,   /*  and decrement it */
3786                                   disp_counter - 1 & DV_MASK);
3787 
3788                 if (disp_counter == 0)                          /* if the dispatcher is already enabled */
3789                     MICRO_ABORT (trap_SysHalt_PSEB_Enabled);    /*   then trap for a system halt */
3790 
3791                 else if (disp_counter > 1)              /* otherwise if the dispatcher is still inhibited */
3792                     SET_CCG;                            /*   then set condition code "greater than" */
3793 
3794                 else if (CPX1 & cpx1_DISPFLAG) {            /* otherwise if the dispatcher is currently running */
3795                     cpu_write_memory (absolute, ics_q, 0);  /*   then clear any start dispatcher requests */
3796                     SET_CCG;                                /*     and set condition code "greater than" */
3797                     }
3798 
3799                 else {                                  /* otherwise the dispatcher is ready to run */
3800                     cpu_read_memory (absolute, ics_q,   /* read the dispatcher's stack marker */
3801                                      &delta_qi);
3802 
3803                     if ((delta_qi & STMK_D) == 0        /* if the dispatcher is not scheduled */
3804                       || (CPX1 & cpx1_ICSFLAG))         /*   or if we're currently executing on the ICS */
3805                         SET_CCG;                        /*     then set condition code "greater than" */
3806 
3807                     else {                                      /* otherwise */
3808                         SET_CCE;                                /*   set condition code "equal" */
3809                         cpu_setup_ics_irq (irq_Dispatch, 0);    /*     and set up the ICS */
3810 
3811                         STA = STATUS_M;                         /* enter privileged mode with interrupts disabled */
3812                         cpu_start_dispatcher ();                /*   and start the dispatcher */
3813                         }
3814                     }
3815                 break;
3816             }                                           /* all cases are handled */
3817         break;
3818 
3819 
3820     case 004:                                           /* SMSK and SCLK */
3821         if (NPRV)                                       /* if the mode is not privileged */
3822             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3823 
3824         if (CNTLOP (CIR) > 1                            /* if the reserved field is not 0 or 1 */
3825           && cpu_stop_flags & SS_UNDEF)                 /*   and the undefined instruction stop is active */
3826             status = STOP_UNIMPL;                       /*     then stop the simulator */
3827 
3828         else if (CNTLOP (CIR) == 0) {                   /* SMSK (CCx; STUN, MODE) */
3829             iop_direct_io (0, ioSMSK, RA);              /* send the "set mask" I/O order to all interfaces */
3830 
3831             if (CPX1 & cpx1_IOTIMER) {                  /* if an I/O timeout occurred */
3832                 CPX1 &= ~cpx1_IOTIMER;                  /*   then clear the timer */
3833                 SET_CCL;                                /*     and set condition code "greater than" */
3834                 }
3835 
3836             else {                                          /* otherwise the mask was set */
3837                 cpu_write_memory (absolute, INTERRUPT_MASK, /*   so write the interrupt mask to memory */
3838                                   RA);
3839                 cpu_pop ();                                 /* pop the TOS */
3840                 SET_CCE;                                    /*   and set condition code "equal" */
3841                 }
3842             }
3843 
3844         else {                                          /* SCLK (none; STUN, MODE) */
3845             cpu_update_pclk ();                         /* update the process clock counter */
3846             PCLK = RA;                                  /*   and then set it */
3847 
3848             cpu_pop ();                                 /* delete the TOS */
3849             }
3850         break;
3851 
3852 
3853     case 005:                                           /* RMSK and RCLK */
3854         cpu_push ();                                    /* push the stack down */
3855 
3856         if (CNTLOP (CIR) > 1                            /* if the reserved field is not 0 or 1 */
3857           && cpu_stop_flags & SS_UNDEF)                 /*   and the undefined instruction stop is active */
3858             status = STOP_UNIMPL;                       /*     then stop the simulator */
3859 
3860         else if (CNTLOP (CIR) == 0)                     /* RMSK (STOV) */
3861             cpu_read_memory (absolute, INTERRUPT_MASK,  /* read the interrupt mask from memory */
3862                              &RA);
3863 
3864         else {                                          /* RCLK (none; STOV) */
3865             cpu_update_pclk ();                         /* update the process clock counter */
3866             RA = PCLK;                                  /*   and then read it */
3867             }
3868         break;
3869 
3870 
3871     case 006:                                           /* XEQ (none; BNDV) */
3872         address = SM + SR - IO_K (CIR) & LA_MASK;       /* get the address of the target instruction */
3873 
3874         if (address >= DB || PRIV) {                    /* if the address is not below DB or the mode is privileged */
3875             cpu_read_memory (stack, address, &NIR);     /*   then read the word at S - K into the NIR */
3876 
3877             P = P - 1 & R_MASK;                         /* decrement P so the instruction after XEQ is next */
3878             sim_interval = sim_interval + 1;            /*   but don't count the XEQ against a STEP count */
3879             }
3880 
3881         else                                            /* otherwise the address is below DB and not privileged */
3882             MICRO_ABORT (trap_Bounds_Violation);        /*   so trap with a bounds violation */
3883         break;
3884 
3885 
3886     case 007:                                           /* SIO (CCx; STUN, STOV, MODE) */
3887         operand = srw_io (ioSIO, SIO_OK);               /* send the SIO order to the device */
3888 
3889         if (operand)                                    /* if the start I/O operation succeeded */
3890             cpu_pop ();                                 /*   then delete the I/O program address */
3891         break;
3892 
3893 
3894     case 010:                                           /* RIO (CCX; STOV, MODE) */
3895         operand = srw_io (ioRIO, DIO_OK);               /* send the RIO order to the device */
3896 
3897         if (operand) {                                  /* if the read I/O operation succeeded */
3898             cpu_push ();                                /*   then push the stack down */
3899             RA = LOWER_WORD (operand);                  /*     and save the RIO response on the TOS */
3900             }
3901         break;
3902 
3903 
3904     case 011:                                           /* WIO (CCX; STUN, STOV, MODE) */
3905         operand = srw_io (ioWIO, DIO_OK);               /* send the WIO order to the device */
3906 
3907         if (operand)                                    /* if the write I/O operation succeeded */
3908             cpu_pop ();                                 /*   then delete the write value */
3909         break;
3910 
3911 
3912     case 012:                                           /* TIO (CCx; STOV, MODE) */
3913         operand = tcs_io (ioTIO);                       /* send the TIO order to the device */
3914 
3915         if (operand) {                                  /* if the test I/O operation succeeded */
3916             cpu_push ();                                /*   then push the stack down */
3917             RA = LOWER_WORD (operand);                  /*     and save the I/O response on the TOS */
3918             }
3919         break;
3920 
3921 
3922     case 013:                                           /* CIO (CCx; STUN, MODE) */
3923         operand = tcs_io (ioCIO);                       /* send the CIO order to the device */
3924 
3925         if (operand)                                    /* if the control operation succeeded */
3926             cpu_pop ();                                 /*   then delete the control value */
3927         break;
3928 
3929 
3930     case 014:                                           /* CMD (none; STUN, MODE) */
3931         if (NPRV)                                       /* if the mode is not privileged */
3932             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3933 
3934         address = SM + SR - IO_K (CIR) & LA_MASK;       /* get the location of the command word */
3935         cpu_read_memory (stack, address, &command);     /*   and read it from the stack or TOS registers */
3936 
3937         module = CMD_TO (command);                      /* get the addressed (TO) module number */
3938 
3939         if (module == MODULE_PORT_CNTLR                 /* if the selector channel port controller */
3940           || module >= MODULE_UNDEFINED)                /*   or an undefined module is addressed */
3941             CPX1 |= cpx1_CPUTIMER;                      /*     then a module timeout occurs */
3942 
3943         else if (module == MODULE_CPU)                  /* otherwise if the CPU is addressing itself */
3944             MOD = MOD_CPU_1                             /*   then set the MOD register */
3945                     | TO_MOD_FROM (module)              /*     FROM field to the TO address */
3946                     | TO_MOD_MOP (CMD_MOP (command));   /*       and include the MOP field value */
3947 
3948         else if (UNIT_CPU_MODEL == UNIT_SERIES_II)      /* otherwise if a Series II memory module is addressed */
3949             if (module >= MODULE_MEMORY_UPPER           /*   then if the upper module is addressed */
3950               && MEMSIZE < 128 * 1024)                  /*     but it's not present */
3951                 CPX1 |= cpx1_CPUTIMER;                  /*       then it will not respond */
3952 
3953             else {                                                  /* otherwise the module address is valid */
3954                 if (CMD_MOP (command) == MOP_READ_WRITE_ONES) {     /* if the operation is read/write ones */
3955                     address = TO_PA (module, RA);                   /*   then get the bank and address */
3956                     cpu_write_memory (absolute, address, D16_UMAX); /*     and set the addressed word to all one bits */
3957                     }
3958 
3959                 MOD = MOD_CPU_1                         /* set the MOD register */
3960                         | TO_MOD_FROM (module)          /*   FROM field to the TO address */
3961                         | TO_MOD_MOP (MOP_NOP);         /*     and the module operation to NOP */
3962                 }
3963 
3964         else if (UNIT_CPU_MODEL == UNIT_SERIES_III)     /* otherwise if a Series III memory module is addressed */
3965             if (module >= MODULE_MEMORY_UPPER           /*   then if the upper module is addressed */
3966               && MEMSIZE < 512 * 1024)                  /*     but it's not present */
3967                 CPX1 |= cpx1_CPUTIMER;                  /*       then it will not respond */
3968 
3969             else                                        /* otherwise the module address is valid */
3970                 MOD = MOD_CPU_1                         /*   so set the MOD register */
3971                         | TO_MOD_FROM (module)          /*     FROM field to the TO address */
3972                         | TO_MOD_MOP (MOP_NOP);         /*       and the module operation to NOP */
3973 
3974         if (MOD != 0 && STA & STATUS_I)                 /* if a module interrupt is indicated and enabled */
3975             CPX1 |= cpx1_MODINTR;                       /*   then request it */
3976 
3977         cpu_pop ();                                     /* delete the TOS */
3978         break;
3979 
3980 
3981     case 015:                                           /* SST (none; STUN, MODE) */
3982         offset = IO_K (CIR);                            /* get the system table pointer offset */
3983 
3984         if (offset == 0) {                              /* if the specified offset is zero */
3985             cpu_read_memory (absolute,                  /*   then offset using the TOS */
3986                              RA + SGT_POINTER & LA_MASK,
3987                              &operand);
3988             cpu_pop ();                                 /* delete the TOS */
3989             }
3990 
3991         else                                            /* otherwise */
3992             cpu_read_memory (absolute,                  /*   use the specified offset */
3993                              offset + SGT_POINTER,      /*     which cannot overflow */
3994                              &operand);
3995 
3996         if (NPRV)                                       /* if the mode is not privileged */
3997             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
3998 
3999         cpu_write_memory (absolute,                     /* write the TOS value into the table */
4000                           X + operand + SGT_POINTER & LA_MASK,
4001                           RA);
4002 
4003         cpu_pop ();                                     /* delete the TOS */
4004         break;
4005 
4006 
4007     case 016:                                           /* SIN (CCx; MODE) */
4008         tcs_io (ioSIN);                                 /* send the SIN order to the device */
4009         break;
4010 
4011 
4012     case 017:                                           /* HALT (none; MODE) */
4013         if (NPRV)                                       /* if the mode is not privileged */
4014             MICRO_ABORT (trap_Privilege_Violation);     /*   then abort with a privilege violation */
4015 
4016         CNTR = SR;                                      /* copy the stack register to the counter */
4017         cpu_flush ();                                   /*   and flush the TOS registers to memory */
4018 
4019         CPX2 &= ~cpx2_RUN;                              /* clear the run flip-flop */
4020         status = STOP_HALT;                             /*   and stop the simulator */
4021         break;
4022     }                                                   /* all cases are handled */
4023 
4024 return status;                                          /* return the execution status */
4025 }
4026