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