First Commit of my working state
[simh.git] / VAX / vax_cpu1.c
1 /* vax_cpu1.c: VAX complex instructions
2
3 Copyright (c) 1998-2008, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is 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
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 28-May-08 RMS Inlined physical memory routines
27 29-Apr-07 RMS Separated base register access checks for 11/780
28 10-May-06 RMS Added access check on system PTE for 11/780
29 Added mbz check in LDPCTX for 11/780
30 22-Sep-06 RMS Fixed declarations (from Sterling Garwood)
31 30-Sep-04 RMS Added conditionals for full VAX
32 Moved emulation to vax_cis.c
33 Moved model-specific IPRs to system module
34 27-Jan-04 RMS Added device logging support
35 Fixed EXTxV, INSV double register PC reference fault
36 30-Apr-02 RMS Fixed interrupt/exception handler to clear traps
37 17-Apr-02 RMS Fixed pos > 31 test in bit fields (should be unsigned)
38 14-Apr-02 RMS Fixed prv_mode handling for interrupts (found by Tim Stark)
39 Fixed PROBEx to mask mode to 2b (found by Kevin Handy)
40
41 This module contains the instruction simulators for
42
43 Field instructions:
44 - BBS, BBC, BBSSI, BBCCI
45 - BBSC, BBCC, BBCS, BBSS
46 - EXTV, EXTZV, CMPV, CMPZV
47 - FFS, FFC, INSV
48
49 Call/return and push/pop instructions:
50 - CALLS, CALLG, RET
51 - PUSHR, POPR
52
53 Queue instructions:
54 - INSQUE, REMQUE
55 - INSQHI, INSQTI, REMQHI, REMQTI
56
57 String instructions:
58 - MOVC3, MOVC5, CMPC3, CMPC5
59 - LOCC, SKPC, SCANC, SPANC
60
61 Operating system interface instructions:
62 - CHMK, CHME, CHMS, CHMU
63 - PROBER, PROBEW, REI
64 - MTPR, MFPR
65 - LDPCTX, SVPCTX
66 - (interrupt and exception routine)
67 */
68
69 #include "vax_defs.h"
70
71 static const uint8 rcnt[128] = {
72 0, 4, 4, 8, 4, 8, 8,12, 4, 8, 8,12, 8,12,12,16, /* 00 - 0F */
73 4, 8, 8,12, 8,12,12,16, 8,12,12,16,12,16,16,20, /* 10 - 1F */
74 4, 8, 8,12, 8,12,12,16, 8,12,12,16,12,16,16,20, /* 20 - 2F */
75 8,12,12,16,12,16,16,20,12,16,16,20,16,20,20,24, /* 30 - 3F */
76 4, 8, 8,12, 8,12,12,16, 8,12,12,16,12,16,16,20, /* 40 - 4F */
77 8,12,12,16,12,16,16,20,12,16,16,20,16,20,20,24, /* 50 - 5F */
78 8,12,12,16,12,16,16,20,12,16,16,20,16,20,20,24, /* 60 - 6F */
79 12,16,16,20,16,20,20,24,16,20,20,24,20,24,24,28 /* 70 - 7F */
80 };
81
82 int32 last_chm = 0;
83
84 extern uint32 *M;
85 extern const uint32 byte_mask[33];
86 extern int32 R[16];
87 extern int32 STK[5];
88 extern int32 PSL;
89 extern int32 SCBB, PCBB, SBR, SLR;
90 extern int32 P0BR, P0LR, P1BR, P1LR;
91 extern int32 ASTLVL, SISR, mapen;
92 extern int32 pme;
93 extern int32 trpirq;
94 extern int32 p1, p2;
95 extern int32 fault_PC;
96 extern int32 pcq[PCQ_SIZE];
97 extern int32 pcq_p;
98 extern int32 in_ie;
99 extern int32 sim_interval;
100 extern int32 ibcnt, ppc;
101 extern FILE *sim_deb;
102 extern DEVICE cpu_dev;
103
104 extern int32 Test (uint32 va, int32 acc, int32 *status);
105 extern void set_map_reg (void);
106 extern void zap_tb (int stb);
107 extern void zap_tb_ent (uint32 va);
108 extern t_bool chk_tb_ent (uint32 va);
109 extern int32 ReadIPR (int32 rg);
110 extern void WriteIPR (int32 rg, int32 val);
111 extern t_bool BadCmPSL (int32 newpsl);
112 extern int32 cpu_psl_ipl_idle (int32 newpsl);
113
114 extern jmp_buf save_env;
115
116 /* Branch on bit and no modify
117 Branch on bit and modify
118
119 opnd[0] = position (pos.rl)
120 opnd[1] = register number/memory flag
121 opnd[2] = memory address, if memory
122 Returns bit to be tested
123 */
124
125 int32 op_bb_n (int32 *opnd, int32 acc)
126 {
127 int32 pos = opnd[0];
128 int32 rn = opnd[1];
129 int32 ea, by;
130
131 if (rn >= 0) { /* register? */
132 if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */
133 return (R[rn] >> pos) & 1; /* get bit */
134 }
135 ea = opnd[2] + (pos >> 3); /* base byte addr */
136 pos = pos & 07; /* pos in byte */
137 by = Read (ea, L_BYTE, RA); /* read byte */
138 return ((by >> pos) & 1); /* get bit */
139 }
140
141 int32 op_bb_x (int32 *opnd, int32 newb, int32 acc)
142 {
143 int32 pos = opnd[0];
144 int32 rn = opnd[1];
145 int32 ea, by, bit;
146
147 if (rn >= 0) { /* register? */
148 if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */
149 bit = (R[rn] >> pos) & 1; /* get bit */
150 R[rn] = newb? (R[rn] | (1u << pos)): (R[rn] & ~(1u << pos));
151 return bit;
152 }
153 ea = opnd[2] + (pos >> 3); /* base byte addr */
154 pos = pos & 07; /* pos in byte */
155 by = Read (ea, L_BYTE, WA); /* read byte */
156 bit = (by >> pos) & 1; /* get bit */
157 by = newb? (by | (1u << pos)): (by & ~(1u << pos)); /* change bit */
158 Write (ea, by, L_BYTE, WA); /* rewrite byte */
159 return bit;
160 }
161
162 /* Extract field
163
164 opnd[0] = position (pos.rl)
165 opnd[1] = size (size.rb)
166 opnd[2] = register number/memory flag
167 opnd[3] = register content/memory address
168
169 If the field is in a register, rn + 1 is in vfldrp1
170 */
171
172 int32 op_extv (int32 *opnd, int32 vfldrp1, int32 acc)
173 {
174 int32 pos = opnd[0];
175 int32 size = opnd[1];
176 int32 rn = opnd[2];
177 uint32 wd = opnd[3];
178 int32 ba, wd1 = 0;
179
180 if (size == 0) return 0; /* size 0? field = 0 */
181 if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */
182 if (rn >= 0) { /* register? */
183 if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */
184 if (((pos + size) > 32) && (rn >= nSP)) /* span 2 reg, PC? */
185 RSVD_ADDR_FAULT; /* fault */
186 if (pos) wd = (wd >> pos) | (((uint32) vfldrp1) << (32 - pos));
187 }
188 else {
189 ba = wd + (pos >> 3); /* base byte addr */
190 pos = (pos & 07) | ((ba & 03) << 3); /* bit offset */
191 ba = ba & ~03; /* lw align base */
192 wd = Read (ba, L_LONG, RA); /* read field */
193 if ((size + pos) > 32) wd1 = Read (ba + 4, L_LONG, RA);
194 if (pos) wd = (wd >> pos) | (((uint32) wd1) << (32 - pos));
195 }
196 return wd & byte_mask[size];
197 }
198
199 /* Insert field
200
201 opnd[0] = field (src.rl)
202 opnd[1] = position (pos.rl)
203 opnd[2] = size (size.rb)
204 opnd[3] = register number/memory flag
205 opnd[4] = register content/memory address
206
207 If the field is in a register, rn + 1 is in vfldrp1
208 */
209
210 void op_insv (int32 *opnd, int32 vfldrp1, int32 acc)
211 {
212 uint32 ins = opnd[0];
213 int32 pos = opnd[1];
214 int32 size = opnd[2];
215 int32 rn = opnd[3];
216 int32 val, mask, ba, wd, wd1;
217
218 if (size == 0) return; /* size = 0? done */
219 if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */
220 if (rn >= 0) { /* in registers? */
221 if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */
222 if ((pos + size) > 32) { /* span two reg? */
223 if (rn >= nSP) RSVD_ADDR_FAULT; /* if PC, fault */
224 mask = byte_mask[pos + size - 32]; /* insert fragment */
225 val = ins >> (32 - pos);
226 R[rn + 1] = (vfldrp1 & ~mask) | (val & mask);
227 }
228 mask = byte_mask[size] << pos; /* insert field */
229 val = ins << pos;
230 R[rn] = (R[rn] & ~mask) | (val & mask);
231 }
232 else {
233 ba = opnd[4] + (pos >> 3); /* base byte addr */
234 pos = (pos & 07) | ((ba & 03) << 3); /* bit offset */
235 ba = ba & ~03; /* lw align base */
236 wd = Read (ba, L_LONG, WA); /* read field */
237 if ((size + pos) > 32) { /* field span lw? */
238 wd1 = Read (ba + 4, L_LONG, WA); /* read 2nd lw */
239 mask = byte_mask[pos + size - 32]; /* insert fragment */
240 val = ins >> (32 - pos);
241 Write (ba + 4, (wd1 & ~mask) | (val & mask), L_LONG, WA);
242 }
243 mask = byte_mask[size] << pos; /* insert field */
244 val = ins << pos;
245 Write (ba, (wd & ~mask) | (val & mask), L_LONG, WA);
246 }
247 return;
248 }
249
250 /* Find first */
251
252 int32 op_ffs (uint32 wd, int32 size)
253 {
254 int32 i;
255
256 for (i = 0; wd; i++, wd = wd >> 1) if (wd & 1) return i;
257 return size;
258 }
259
260 #define CALL_DV 0x8000 /* DV set */
261 #define CALL_IV 0x4000 /* IV set */
262 #define CALL_MBZ 0x3000 /* MBZ */
263 #define CALL_MASK 0x0FFF /* mask */
264 #define CALL_V_SPA 30 /* SPA */
265 #define CALL_M_SPA 03
266 #define CALL_V_S 29 /* S flag */
267 #define CALL_S (1 << CALL_V_S)
268 #define CALL_V_MASK 16
269 #define CALL_PUSH(n) if ((mask >> (n)) & 1) { \
270 tsp = tsp - 4; \
271 Write (tsp, R[n], L_LONG, WA); \
272 }
273 #define CALL_GETSPA(x) (((x) >> CALL_V_SPA) & CALL_M_SPA)
274 #define RET_POP(n) if ((spamask >> (n + CALL_V_MASK)) & 1) { \
275 R[n] = Read (tsp, L_LONG, RA); \
276 tsp = tsp + 4; \
277 }
278 #define PUSHR_PUSH(n) CALL_PUSH(n)
279 #define POPR_POP(n) if ((mask >> (n)) & 1) { \
280 R[n] = Read (SP, L_LONG, RA); \
281 SP = SP + 4; \
282 }
283
284 /* CALLG, CALLS
285
286 opnd[0] = argument (arg.rx)
287 opnd[1] = procedure address (adr.ab)
288 flg = CALLG (0), CALLS (1)
289 acc = access mask
290
291 These instructions implement a generalized procedure call and return facility.
292 The principal data structure involved is the stack frame.
293 CALLS and CALLG build a stack frame in the following format:
294
295
296 +---------------------------------------------------------------+
297 | condition handler (initially 0) |
298 +---+-+-+-----------------------+--------------------+----------+
299 |SPA|S|0| entry mask<11:0> | saved PSW<15:5> | 0 0 0 0 0|
300 +---+-+-+-----------------------+--------------------+----------+
301 | saved AP |
302 +---------------------------------------------------------------+
303 | saved FP |
304 +---------------------------------------------------------------+
305 | saved PC |
306 +---------------------------------------------------------------+
307 | saved R0 (...) |
308 +---------------------------------------------------------------+
309 . .
310 . (according to entry mask<11:0>) .
311 . .
312 +---------------------------------------------------------------+
313 | saved R11 (...) |
314 +---------------+-----------------------------------------------+
315 | #args (CALLS) | (0-3 bytes needed to align stack) |
316 +---------------+-----------------------------------------------+
317 | | 0 0 0 (CALLS) |
318 +---------------+-----------------------------------------------+
319
320 RET expects to find this structure based at the frame pointer (FP).
321
322 For CALLG and CALLS, the entry mask specifies the new settings of
323 DV and IV, and also which registers are to be saved on entry:
324
325 15 14 13 12 11 0
326 +--+--+-----+----------------------------------+
327 |DV|IV| MBZ | register mask |
328 +--+--+-----+----------------------------------+
329
330 CALLG/CALLS operation:
331
332 read the procedure entry mask
333 make sure that the stack frame will be accessible
334 if CALLS, push the number of arguments onto the stack
335 align the stack to the next lower longword boundary
336 push the registers specified by the procedure entry mask
337 push PC, AP, FP, saved SPA/S0/mask/PSW, condition handler
338 update PC, SP, FP, AP
339 update PSW traps, clear condition codes
340 */
341
342 int32 op_call (int32 *opnd, t_bool gs, int32 acc)
343 {
344 int32 addr = opnd[1];
345 int32 mask, stklen, tsp, wd;
346
347 mask = Read (addr, L_WORD, RA); /* get proc mask */
348 if (mask & CALL_MBZ) RSVD_OPND_FAULT; /* test mbz */
349 stklen = rcnt[mask & 077] + rcnt[(mask >> 6) & 077] + (gs? 24: 20);
350 Read (SP - stklen, L_BYTE, WA); /* wchk stk */
351 if (gs) {
352 Write (SP - 4, opnd[0], L_LONG, WA); /* if S, push #arg */
353 SP = SP - 4; /* stack is valid */
354 }
355 tsp = SP & ~CALL_M_SPA; /* lw align stack */
356 CALL_PUSH (11); /* check mask bits, */
357 CALL_PUSH (10); /* push sel reg */
358 CALL_PUSH (9);
359 CALL_PUSH (8);
360 CALL_PUSH (7);
361 CALL_PUSH (6);
362 CALL_PUSH (5);
363 CALL_PUSH (4);
364 CALL_PUSH (3);
365 CALL_PUSH (2);
366 CALL_PUSH (1);
367 CALL_PUSH (0);
368 Write (tsp - 4, PC, L_LONG, WA); /* push PC */
369 Write (tsp - 8, FP, L_LONG, WA); /* push AP */
370 Write (tsp - 12, AP, L_LONG, WA); /* push FP */
371 wd = ((SP & CALL_M_SPA) << CALL_V_SPA) | (gs << CALL_V_S) |
372 ((mask & CALL_MASK) << CALL_V_MASK) | (PSL & 0xFFE0);
373 Write (tsp - 16, wd, L_LONG, WA); /* push spa/s/mask/psw */
374 Write (tsp - 20, 0, L_LONG, WA); /* push cond hdlr */
375 if (gs) AP = SP; /* update AP */
376 else AP = opnd[0];
377 SP = FP = tsp - 20; /* update FP, SP */
378 PSL = (PSL & ~(PSW_DV | PSW_FU | PSW_IV)) | /* update PSW */
379 ((mask & CALL_DV)? PSW_DV: 0) |
380 ((mask & CALL_IV)? PSW_IV: 0);
381 JUMP (addr + 2); /* new PC */
382 return 0; /* new cc's */
383 }
384
385 int32 op_ret (int32 acc)
386 {
387 int32 spamask, stklen, newpc, nargs;
388 int32 tsp = FP;
389
390 spamask = Read (tsp + 4, L_LONG, RA); /* spa/s/mask/psw */
391 if (spamask & PSW_MBZ) RSVD_OPND_FAULT; /* test mbz */
392 stklen = rcnt[(spamask >> CALL_V_MASK) & 077] +
393 rcnt[(spamask >> (CALL_V_MASK + 6)) & 077] + ((spamask & CALL_S)? 23: 19);
394 Read (tsp + stklen, L_BYTE, RA); /* rchk stk end */
395 AP = Read (tsp + 8, L_LONG, RA); /* restore AP */
396 FP = Read (tsp + 12, L_LONG, RA); /* restore FP */
397 newpc = Read (tsp + 16, L_LONG, RA); /* get new PC */
398 tsp = tsp + 20; /* update stk ptr */
399 RET_POP (0); /* chk mask bits, */
400 RET_POP (1); /* pop sel regs */
401 RET_POP (2);
402 RET_POP (3);
403 RET_POP (4);
404 RET_POP (5);
405 RET_POP (6);
406 RET_POP (7);
407 RET_POP (8);
408 RET_POP (9);
409 RET_POP (10);
410 RET_POP (11);
411 SP = tsp + CALL_GETSPA (spamask); /* dealign stack */
412 if (spamask & CALL_S) { /* CALLS? */
413 nargs = Read (SP, L_LONG, RA); /* read #args */
414 SP = SP + 4 + ((nargs & BMASK) << 2); /* pop arg list */
415 }
416 PSL = (PSL & ~(PSW_DV | PSW_FU | PSW_IV | PSW_T)) | /* reset PSW */
417 (spamask & (PSW_DV | PSW_FU | PSW_IV | PSW_T));
418 JUMP (newpc); /* set new PC */
419 return spamask & (CC_MASK); /* return cc's */
420 }
421
422 /* PUSHR and POPR */
423
424 void op_pushr (int32 *opnd, int32 acc)
425 {
426 int32 mask = opnd[0] & 0x7FFF;
427 int32 stklen, tsp;
428
429 if (mask == 0) return;
430 stklen = rcnt[(mask >> 7) & 0177] + rcnt[mask & 0177] +
431 ((mask & 0x4000)? 4: 0);
432 Read (SP - stklen, L_BYTE, WA); /* wchk stk end */
433 tsp = SP; /* temp stk ptr */
434 PUSHR_PUSH (14); /* check mask bits, */
435 PUSHR_PUSH (13); /* push sel reg */
436 PUSHR_PUSH (12);
437 PUSHR_PUSH (11);
438 PUSHR_PUSH (10);
439 PUSHR_PUSH (9);
440 PUSHR_PUSH (8);
441 PUSHR_PUSH (7);
442 PUSHR_PUSH (6);
443 PUSHR_PUSH (5);
444 PUSHR_PUSH (4);
445 PUSHR_PUSH (3);
446 PUSHR_PUSH (2);
447 PUSHR_PUSH (1);
448 PUSHR_PUSH (0);
449 SP = tsp; /* update stk ptr */
450 return;
451 }
452
453 void op_popr (int32 *opnd, int32 acc)
454 {
455 int32 mask = opnd[0] & 0x7FFF;
456 int32 stklen;
457
458 if (mask == 0) return;
459 stklen = rcnt[(mask >> 7) & 0177] + rcnt[mask & 0177] +
460 ((mask & 0x4000)? 4: 0);
461 Read (SP + stklen - 1, L_BYTE, RA); /* rchk stk end */
462 POPR_POP (0); /* check mask bits, */
463 POPR_POP (1); /* pop sel regs */
464 POPR_POP (2);
465 POPR_POP (3);
466 POPR_POP (4);
467 POPR_POP (5);
468 POPR_POP (6);
469 POPR_POP (7);
470 POPR_POP (8);
471 POPR_POP (9);
472 POPR_POP (10);
473 POPR_POP (11);
474 POPR_POP (12);
475 POPR_POP (13);
476 if (mask & 0x4000) SP = Read (SP, L_LONG, RA); /* if pop SP, no inc */
477 return;
478 }
479
480 /* INSQUE
481
482 opnd[0] = entry address (ent.ab)
483 opnd[1] = predecessor address (pred.ab)
484
485 Condition codes returned to caller on comparison of (ent):(ent+4).
486 All writes must be checked before any writes are done.
487
488 Pictorially:
489
490 BEFORE AFTER
491
492 P: S P: E W
493 P+4: (n/a) P+4: (n/a)
494
495 E: --- E: S W
496 E+4: --- E+4: P W
497
498 S: (n/a) S: (n/a)
499 S+4: P S+4: E W
500
501 s+4 must be tested with a read modify rather than a probe, as it
502 might be misaligned.
503 */
504
505 int32 op_insque (int32 *opnd, int32 acc)
506 {
507 int32 p = opnd[1];
508 int32 e = opnd[0];
509 int32 s, cc;
510
511 s = Read (p, L_LONG, WA); /* s <- (p), wchk */
512 Read (s + 4, L_LONG, WA); /* wchk s+4 */
513 Read (e + 4, L_LONG, WA); /* wchk e+4 */
514 Write (e, s, L_LONG, WA); /* (e) <- s */
515 Write (e + 4, p, L_LONG, WA); /* (e+4) <- p */
516 Write (s + 4, e, L_LONG, WA); /* (s+4) <- ent */
517 Write (p, e, L_LONG, WA); /* (p) <- e */
518 CC_CMP_L (s, p); /* set cc's */
519 return cc;
520 }
521
522 /* REMQUE
523
524 opnd[0] = entry address (ent.ab)
525 opnd[1:2] = destination address (dst.wl)
526
527 Condition codes returned to caller based on (ent):(ent+4).
528 All writes must be checked before any writes are done.
529
530 Pictorially:
531
532 BEFORE AFTER
533
534 P: E P: S W
535 P+4: (n/a) P+4: (n/a)
536
537 E: S W E: S
538 E+4: P W E+4: P
539
540 S: (n/a) S: (n/a)
541 S+4: E W S+4: P
542
543 */
544
545 int32 op_remque (int32 *opnd, int32 acc)
546 {
547 int32 e = opnd[0];
548 int32 s, p, cc;
549
550 s = Read (e, L_LONG, RA); /* s <- (e) */
551 p = Read (e + 4, L_LONG, RA); /* p <- (e+4) */
552 CC_CMP_L (s, p); /* set cc's */
553 if (e != p) { /* queue !empty? */
554 Read (s + 4, L_LONG, WA); /* wchk (s+4) */
555 if (opnd[1] < 0) Read (opnd[2], L_LONG, WA); /* wchk dest */
556 Write (p, s, L_LONG, WA); /* (p) <- s */
557 Write (s + 4, p, L_LONG, WA); /* (s+4) <- p */
558 }
559 else cc = cc | CC_V; /* else set v */
560 if (opnd[1] >= 0) R[opnd[1]] = e; /* store result */
561 else Write (opnd[2], e, L_LONG, WA);
562 return cc;
563 }
564
565 /* Interlocked insert instructions
566
567 opnd[0] = entry (ent.ab)
568 opnd[1] = header (hdr.aq)
569
570 Pictorially:
571
572 BEFORE AFTER INSQHI AFTER INSQTI
573
574 H: A-H H: D-H W H: A-H W for interlock
575 H+4: C-H H+4: C-H H+4: D-H W
576
577 A: B-A A: B-A A: B-A
578 A+4: H-A A+4: D-A W A+4: H-A
579
580 B: C-B B: C-B B: C-B
581 B+4: A-B B+4: A-B B+4: A-B
582
583 C: H-C C: H-C C: D-C W
584 C+4: B-C C+4: B-C C+4: B-C
585
586 D: --- D: A-D W D: H-D W
587 D+4: --- D+4: H-D W D+4: C-D W
588
589 Note that the queue header, the entry to be inserted, and all
590 the intermediate entries that are "touched" in any way must be
591 QUADWORD aligned. In addition, the header and the entry must
592 not be equal.
593 */
594
595 int32 op_insqhi (int32 *opnd, int32 acc)
596 {
597 int32 h = opnd[1];
598 int32 d = opnd[0];
599 int32 a, t;
600
601 if ((h == d) || ((h | d) & 07)) RSVD_OPND_FAULT; /* h, d quad align? */
602 Read (d, L_BYTE, WA); /* wchk ent */
603 a = Read (h, L_LONG, WA); /* a <- (h), wchk */
604 if (a & 06) RSVD_OPND_FAULT; /* chk quad align */
605 if (a & 01) return CC_C; /* busy, cc = 0001 */
606 Write (h, a | 1, L_LONG, WA); /* get interlock */
607 a = a + h; /* abs addr of a */
608 if (Test (a, WA, &t) < 0) Write (h, a - h, L_LONG, WA); /* wtst a, rls if err */
609 Write (a + 4, d - a, L_LONG, WA); /* (a+4) <- d-a, flt ok */
610 Write (d, a - d, L_LONG, WA); /* (d) <- a-d */
611 Write (d + 4, h - d, L_LONG, WA); /* (d+4) <- h-d */
612 Write (h, d - h, L_LONG, WA); /* (h) <- d-h, rls int */
613 return (a == h)? CC_Z: 0; /* Z = 1 if a = h */
614 }
615
616 int32 op_insqti (int32 *opnd, int32 acc)
617 {
618 int32 h = opnd[1];
619 int32 d = opnd[0];
620 int32 a, c, t;
621
622 if ((h == d) || ((h | d) & 07)) RSVD_OPND_FAULT; /* h, d quad align? */
623 Read (d, L_BYTE, WA); /* wchk ent */
624 a = Read (h, L_LONG, WA); /* a <- (h), wchk */
625 if (a == 0) return op_insqhi (opnd, acc); /* if empty, ins hd */
626 if (a & 06) RSVD_OPND_FAULT; /* chk quad align */
627 if (a & 01) return CC_C; /* busy, cc = 0001 */
628 Write (h, a | 1, L_LONG, WA); /* acquire interlock */
629 c = Read (h + 4, L_LONG, RA) + h; /* c <- (h+4) + h */
630 if (c & 07) { /* c quad aligned? */
631 Write (h, a, L_LONG, WA); /* release interlock */
632 RSVD_OPND_FAULT; /* fault */
633 }
634 if (Test (c, WA, &t) < 0) Write (h, a, L_LONG, WA); /* wtst c, rls if err */
635 Write (c, d - c, L_LONG, WA); /* (c) <- d-c, flt ok */
636 Write (d, h - d, L_LONG, WA); /* (d) <- h-d */
637 Write (d + 4, c - d, L_LONG, WA); /* (d+4) <- c-d */
638 Write (h + 4, d - h, L_LONG, WA); /* (h+4) <- d-h */
639 Write (h, a, L_LONG, WA); /* release interlock */
640 return 0; /* q >= 2 entries */
641 }
642
643 /* Interlocked remove instructions
644
645 opnd[0] = header (hdr.aq)
646 opnd[1:2] = destination address (dst.al)
647
648 Pictorially:
649
650 BEFORE AFTER REMQHI AFTER REMQTI
651
652 H: A-H H: B-H W H: A-H W for interlock
653 H+4: C-H H+4: C-H H+4: B-H W
654
655 A: B-A A: B-A R A: B-A
656 A+4: H-A A+4: H-A A+4: H-A
657
658 B: C-B B: C-B B: H-B W
659 B+4: A-B B+4: H-B W B+4: A-B
660
661 C: H-C C: H-C C: H-C
662 C+4: B-C C+4: B-C C+4: B-C R
663
664 Note that the queue header and all the entries that are
665 "touched" in any way must be QUADWORD aligned. In addition,
666 the header and the destination must not be equal.
667 */
668
669 int32 op_remqhi (int32 *opnd, int32 acc)
670 {
671 int32 h = opnd[0];
672 int32 ar, a, b, t;
673
674 if (h & 07) RSVD_OPND_FAULT; /* h quad aligned? */
675 if (opnd[1] < 0) { /* mem destination? */
676 if (h == opnd[2]) RSVD_OPND_FAULT; /* hdr = dst? */
677 Read (opnd[2], L_LONG, WA); /* wchk dst */
678 }
679 ar = Read (h, L_LONG, WA); /* ar <- (h) */
680 if (ar & 06) RSVD_OPND_FAULT; /* a quad aligned? */
681 if (ar & 01) return CC_V | CC_C; /* busy, cc = 0011 */
682 a = ar + h; /* abs addr of a */
683 if (ar) { /* queue not empty? */
684 Write (h, ar | 1, L_LONG, WA); /* acquire interlock */
685 if (Test (a, RA, &t) < 0) /* read tst a */
686 Write (h, ar, L_LONG, WA); /* release if error */
687 b = Read (a, L_LONG, RA) + a; /* b <- (a)+a, flt ok */
688 if (b & 07) { /* b quad aligned? */
689 Write (h, ar, L_LONG, WA); /* release interlock */
690 RSVD_OPND_FAULT; /* fault */
691 }
692 if (Test (b, WA, &t) < 0) /* write test b */
693 Write (h, ar, L_LONG, WA); /* release if err */
694 Write (b + 4, h - b, L_LONG, WA); /* (b+4) <- h-b, flt ok */
695 Write (h, b - h, L_LONG, WA); /* (h) <- b-h, rls int */
696 }
697 if (opnd[1] >= 0) R[opnd[1]] = a; /* store result */
698 else Write (opnd[2], a, L_LONG, WA);
699 if (ar == 0) return CC_Z | CC_V; /* empty, cc = 0110 */
700 return (b == h)? CC_Z: 0; /* if b = h, q empty */
701 }
702
703 int32 op_remqti (int32 *opnd, int32 acc)
704 {
705 int32 h = opnd[0];
706 int32 ar, b, c, t;
707
708 if (h & 07) RSVD_OPND_FAULT; /* h quad aligned? */
709 if (opnd[1] < 0) { /* mem destination? */
710 if (h == opnd[2]) RSVD_OPND_FAULT; /* hdr = dst? */
711 Read (opnd[2], L_LONG, WA); /* wchk dst */
712 }
713 ar = Read (h, L_LONG, WA); /* a <- (h) */
714 if (ar & 06) RSVD_OPND_FAULT; /* a quad aligned? */
715 if (ar & 01) return CC_V | CC_C; /* busy, cc = 0011 */
716 if (ar) { /* queue not empty */
717 Write (h, ar | 1, L_LONG, WA); /* acquire interlock */
718 c = Read (h + 4, L_LONG, RA); /* c <- (h+4) */
719 if (ar == c) { /* single entry? */
720 Write (h, ar, L_LONG, WA); /* release interlock */
721 return op_remqhi (opnd, acc); /* treat as remqhi */
722 }
723 if (c & 07) { /* c quad aligned? */
724 Write (h, ar, L_LONG, WA); /* release interlock */
725 RSVD_OPND_FAULT; /* fault */
726 }
727 c = c + h; /* abs addr of c */
728 if (Test (c + 4, RA, &t) < 0) /* read test c+4 */
729 Write (h, ar, L_LONG, WA); /* release if error */
730 b = Read (c + 4, L_LONG, RA) + c; /* b <- (c+4)+c, flt ok */
731 if (b & 07) { /* b quad aligned? */
732 Write (h, ar, L_LONG, WA); /* release interlock */
733 RSVD_OPND_FAULT; /* fault */
734 }
735 if (Test (b, WA, &t) < 0) /* write test b */
736 Write (h, ar, L_LONG, WA); /* release if error */
737 Write (b, h - b, L_LONG, WA); /* (b) <- h-b */
738 Write (h + 4, b - h, L_LONG, WA); /* (h+4) <- b-h */
739 Write (h, ar, L_LONG, WA); /* release interlock */
740 }
741 else c = h; /* empty, result = h */
742 if (opnd[1] >= 0) R[opnd[1]] = c; /* store result */
743 else Write (opnd[2], c, L_LONG, WA);
744 if (ar == 0) return CC_Z | CC_V; /* empty, cc = 0110 */
745 return 0; /* q can't be empty */
746 }
747
748 /* String instructions */
749
750 #define MVC_FRWD 0 /* movc state codes */
751 #define MVC_BACK 1
752 #define MVC_FILL 3 /* must be 3 */
753 #define MVC_M_STATE 3
754 #define MVC_V_CC 2
755
756 /* MOVC3, MOVC5
757
758 if PSL<fpd> = 0 and MOVC3,
759 opnd[0] = length
760 opnd[1] = source address
761 opnd[2] = dest address
762
763 if PSL<fpd> = 0 and MOVC5,
764 opnd[0] = source length
765 opnd[1] = source address
766 opnd[2] = fill
767 opnd[3] = dest length
768 opnd[4] = dest address
769
770 if PSL<fpd> = 1,
771 R0 = delta-PC/fill/initial move length
772 R1 = current source address
773 R2 = current move length
774 R3 = current dest address
775 R4 = dstlen - srclen (loop count if fill state)
776 R5 = cc/state
777 */
778
779 int32 op_movc (int32 *opnd, int32 movc5, int32 acc)
780 {
781 int32 i, cc, fill, wd;
782 int32 j, lnt, mlnt[3];
783 static const int32 looplnt[3] = { L_BYTE, L_LONG, L_BYTE };
784
785 if (PSL & PSL_FPD) { /* FPD set? */
786 SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */
787 fill = STR_GETCHR (R[0]); /* get fill */
788 R[2] = R[2] & STR_LNMASK; /* mask lengths */
789 if (R[4] > 0) R[4] = R[4] & STR_LNMASK;
790 }
791 else {
792 R[1] = opnd[1]; /* src addr */
793 if (movc5) { /* MOVC5? */
794 R[2] = (opnd[0] < opnd[3])? opnd[0]: opnd[3];
795 R[3] = opnd[4]; /* dst addr */
796 R[4] = opnd[3] - opnd[0]; /* dstlen - srclen */
797 fill = opnd[2]; /* set fill */
798 CC_CMP_W (opnd[0], opnd[3]); /* set cc's */
799 }
800 else {
801 R[2] = opnd[0]; /* mvlen = srclen */
802 R[3] = opnd[2]; /* dst addr */
803 R[4] = fill = 0; /* no fill */
804 cc = CC_Z; /* set cc's */
805 }
806 R[0] = STR_PACK (fill, R[2]); /* initial mvlen */
807 if (R[2]) { /* any move? */
808 if (((uint32) R[1]) < ((uint32) R[3])) {
809 R[1] = R[1] + R[2]; /* backward, adjust */
810 R[3] = R[3] + R[2]; /* addr to end */
811 R[5] = MVC_BACK; /* set state */
812 }
813 else R[5] = MVC_FRWD; /* fwd, set state */
814 }
815 else R[5] = MVC_FILL; /* fill, set state */
816 R[5] = R[5] | (cc << MVC_V_CC); /* pack with state */
817 PSL = PSL | PSL_FPD; /* set FPD */
818 }
819
820 /* At this point,
821
822 R0 = delta PC'fill'initial move length
823 R1 = current src addr
824 R2 = current move length
825 R3 = current dst addr
826 R4 = dst length - src length
827 R5 = cc'state
828 */
829
830 switch (R[5] & MVC_M_STATE) { /* case on state */
831
832 case MVC_FRWD: /* move forward */
833 mlnt[0] = (4 - R[3]) & 3; /* length to align */
834 if (mlnt[0] > R[2]) mlnt[0] = R[2]; /* cant exceed total */
835 mlnt[1] = (R[2] - mlnt[0]) & ~03; /* aligned length */
836 mlnt[2] = R[2] - mlnt[0] - mlnt[1]; /* tail */
837 for (i = 0; i < 3; i++) { /* head, align, tail */
838 lnt = looplnt[i]; /* length for loop */
839 for (j = 0; j < mlnt[i]; j = j + lnt, sim_interval--) {
840 wd = Read (R[1], lnt, RA); /* read src */
841 Write (R[3], wd, lnt, WA); /* write dst */
842 R[1] = R[1] + lnt; /* inc src addr */
843 R[3] = R[3] + lnt; /* inc dst addr */
844 R[2] = R[2] - lnt; /* dec move lnt */
845 }
846 }
847 goto FILL; /* check for fill */
848
849 case MVC_BACK: /* move backward */
850 mlnt[0] = R[3] & 03; /* length to align */
851 if (mlnt[0] > R[2]) mlnt[0] = R[2]; /* cant exceed total */
852 mlnt[1] = (R[2] - mlnt[0]) & ~03; /* aligned length */
853 mlnt[2] = R[2] - mlnt[0] - mlnt[1]; /* tail */
854 for (i = 0; i < 3; i++) { /* head, align, tail */
855 lnt = looplnt[i]; /* length for loop */
856 for (j = 0; j < mlnt[i]; j = j + lnt, sim_interval--) {
857 wd = Read (R[1] - lnt, lnt, RA); /* read src */
858 Write (R[3] - lnt, wd, lnt, WA); /* write dst */
859 R[1] = R[1] - lnt; /* dec src addr */
860 R[3] = R[3] - lnt; /* dec dst addr */
861 R[2] = R[2] - lnt; /* dec move lnt */
862 }
863 }
864 R[1] = R[1] + (R[0] & STR_LNMASK); /* final src addr */
865 R[3] = R[3] + (R[0] & STR_LNMASK); /* final dst addr */
866
867 case MVC_FILL: /* fill */
868 FILL:
869 if (R[4] <= 0) break; /* any fill? */
870 R[5] = R[5] | MVC_FILL; /* set state */
871 mlnt[0] = (4 - R[3]) & 3; /* length to align */
872 if (mlnt[0] > R[4]) mlnt[0] = R[4]; /* cant exceed total */
873 mlnt[1] = (R[4] - mlnt[0]) & ~03; /* aligned length */
874 mlnt[2] = R[4] - mlnt[0] - mlnt[1]; /* tail */
875 for (i = 0; i < 3; i++) { /* head, align, tail */
876 lnt = looplnt[i]; /* length for loop */
877 fill = fill & BMASK; /* fill for loop */
878 if (lnt == L_LONG) fill =
879 (((uint32) fill) << 24) | (fill << 16) | (fill << 8) | fill;
880 for (j = 0; j < mlnt[i]; j = j + lnt, sim_interval--) {
881 Write (R[3], fill, lnt, WA); /* write fill */
882 R[3] = R[3] + lnt; /* inc dst addr */
883 R[4] = R[4] - lnt; /* dec fill lnt */
884 }
885 }
886 break;
887
888 default: /* bad state */
889 RSVD_OPND_FAULT; /* you lose */
890 }
891
892 PSL = PSL & ~PSL_FPD; /* clear FPD */
893 cc = (R[5] >> MVC_V_CC) & CC_MASK; /* get cc's */
894 R[0] = NEG (R[4]); /* set R0 */
895 R[2] = R[4] = R[5] = 0; /* clear reg */
896 return cc;
897 }
898
899 /* CMPC3, CMPC5
900
901 if PSL<fpd> = 0 and CMPC3,
902 opnd[0] = length
903 opnd[1] = source1 address
904 opnd[2] = source2 address
905
906 if PSL<fpd> = 0 and CMPC5,
907 opnd[0] = source1 length
908 opnd[1] = source1 address
909 opnd[2] = fill
910 opnd[3] = source2 length
911 opnd[4] = source2 address
912
913 if PSL<fpd> = 1,
914 R0 = delta-PC/fill/source1 length
915 R1 = source1 address
916 R2 = source2 length
917 R3 = source2 address
918 */
919
920 int32 op_cmpc (int32 *opnd, int32 cmpc5, int32 acc)
921 {
922 int32 cc, s1, s2, fill;
923
924 if (PSL & PSL_FPD) { /* FPD set? */
925 SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */
926 fill = STR_GETCHR (R[0]); /* get fill */
927 }
928 else {
929 R[1] = opnd[1]; /* src1len */
930 if (cmpc5) { /* CMPC5? */
931 R[2] = opnd[3]; /* get src2 opnds */
932 R[3] = opnd[4];
933 fill = opnd[2];
934 }
935 else {
936 R[2] = opnd[0]; /* src2len = src1len */
937 R[3] = opnd[2];
938 fill = 0;
939 }
940 R[0] = STR_PACK (fill, opnd[0]); /* src1len + FPD data */
941 PSL = PSL | PSL_FPD;
942 }
943 R[2] = R[2] & STR_LNMASK; /* mask src2len */
944 for (s1 = s2 = 0; ((R[0] | R[2]) & STR_LNMASK) != 0; sim_interval--) {
945 if (R[0] & STR_LNMASK) s1 = Read (R[1], L_BYTE, RA); /* src1? read */
946 else s1 = fill; /* no, use fill */
947 if (R[2]) s2 = Read (R[3], L_BYTE, RA); /* src2? read */
948 else s2 = fill; /* no, use fill */
949 if (s1 != s2) break; /* src1 = src2? */
950 if (R[0] & STR_LNMASK) { /* if src1, decr */
951 R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK);
952 R[1] = R[1] + 1;
953 }
954 if (R[2]) { /* if src2, decr */
955 R[2] = (R[2] - 1) & STR_LNMASK;
956 R[3] = R[3] + 1;
957 }
958 }
959 PSL = PSL & ~PSL_FPD; /* clear FPD */
960 CC_CMP_B (s1, s2); /* set cc's */
961 R[0] = R[0] & STR_LNMASK; /* clear packup */
962 return cc;
963 }
964
965 /* LOCC, SKPC
966
967 if PSL<fpd> = 0,
968 opnd[0] = match character
969 opnd[1] = source length
970 opnd[2] = source address
971
972 if PSL<fpd> = 1,
973 R0 = delta-PC/match/source length
974 R1 = source address
975 */
976
977 int32 op_locskp (int32 *opnd, int32 skpc, int32 acc)
978 {
979 int32 c, match;
980
981 if (PSL & PSL_FPD) { /* FPD set? */
982 SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */
983 match = STR_GETCHR (R[0]); /* get match char */
984 }
985 else {
986 match = opnd[0]; /* get operands */
987 R[0] = STR_PACK (match, opnd[1]); /* src len + FPD data */
988 R[1] = opnd[2]; /* src addr */
989 PSL = PSL | PSL_FPD;
990 }
991 for ( ; (R[0] & STR_LNMASK) != 0; sim_interval-- ) { /* loop thru string */
992 c = Read (R[1], L_BYTE, RA); /* get src byte */
993 if ((c == match) ^ skpc) break; /* match & locc? */
994 R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK);
995 R[1] = R[1] + 1; /* incr src1adr */
996 }
997 PSL = PSL & ~PSL_FPD; /* clear FPD */
998 R[0] = R[0] & STR_LNMASK; /* clear packup */
999 return (R[0]? 0: CC_Z); /* set cc's */
1000 }
1001
1002 /* SCANC, SPANC
1003
1004 if PSL<fpd> = 0,
1005 opnd[0] = source length
1006 opnd[1] = source address
1007 opnd[2] = table address
1008 opnd[3] = mask
1009
1010 if PSL<fpd> = 1,
1011 R0 = delta-PC/char/source length
1012 R1 = source address
1013 R3 = table address
1014 */
1015
1016 int32 op_scnspn (int32 *opnd, int32 spanc, int32 acc)
1017 {
1018 int32 c, t, mask;
1019
1020 if (PSL & PSL_FPD) { /* FPD set? */
1021 SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */
1022 mask = STR_GETCHR (R[0]); /* get mask */
1023 }
1024 else {
1025 R[1] = opnd[1]; /* src addr */
1026 R[3] = opnd[2]; /* tblad */
1027 mask = opnd[3]; /* mask */
1028 R[0] = STR_PACK (mask, opnd[0]); /* srclen + FPD data */
1029 PSL = PSL | PSL_FPD;
1030 }
1031 for ( ; (R[0] & STR_LNMASK) != 0; sim_interval-- ) { /* loop thru string */
1032 c = Read (R[1], L_BYTE, RA); /* get byte */
1033 t = Read (R[3] + c, L_BYTE, RA); /* get table ent */
1034 if (((t & mask) != 0) ^ spanc) break; /* test vs instr */
1035 R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK);
1036 R[1] = R[1] + 1;
1037 }
1038 PSL = PSL & ~PSL_FPD;
1039 R[0] = R[0] & STR_LNMASK; /* clear packup */
1040 R[2] = 0;
1041 return (R[0]? 0: CC_Z);
1042 }
1043
1044 /* Operating system interfaces */
1045
1046 /* Interrupt or exception
1047
1048 vec = SCB vector
1049 cc = condition codes
1050 ipl = new IPL if interrupt
1051 ei = -1: severe exception
1052 0: normal exception
1053 1: interrupt
1054 */
1055
1056 int32 intexc (int32 vec, int32 cc, int32 ipl, int ei)
1057 {
1058 int32 oldpsl = PSL | cc;
1059 int32 oldcur = PSL_GETCUR (oldpsl);
1060 int32 oldsp = SP;
1061 int32 newpsl;
1062 int32 newpc;
1063 int32 acc;
1064
1065 in_ie = 1; /* flag int/exc */
1066 CLR_TRAPS; /* clear traps */
1067 newpc = ReadLP ((SCBB + vec) & PAMASK); /* read new PC */
1068 if (ei < 0) newpc = newpc | 1; /* severe? on istk */
1069 if (newpc & 2) ABORT (STOP_ILLVEC); /* bad flags? */
1070 if (oldpsl & PSL_IS) newpsl = PSL_IS; /* on int stk? */
1071 else {
1072 STK[oldcur] = SP; /* no, save cur stk */
1073 if (newpc & 1) { /* to int stk? */
1074 newpsl = PSL_IS; /* flag */
1075 SP = IS; /* new stack */
1076 }
1077 else {
1078 newpsl = 0; /* to ker stk */
1079 SP = KSP; /* new stack */
1080 }
1081 }
1082 if (ei > 0) /* if int, new IPL */
1083 PSL = cpu_psl_ipl_idle (newpsl | (ipl << PSL_V_IPL));
1084 else PSL = cpu_psl_ipl_idle (newpsl | /* exc, old IPL/1F */
1085 ((newpc & 1)? PSL_IPL1F: (oldpsl & PSL_IPL)) | (oldcur << PSL_V_PRV));
1086 if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb,
1087 ">>IEX: PC=%08x, PSL=%08x, SP=%08x, VEC=%08x, nPSL=%08x, nSP=%08x\n",
1088 PC, oldpsl, oldsp, vec, PSL, SP);
1089 acc = ACC_MASK (KERN); /* new mode is kernel */
1090 Write (SP - 4, oldpsl, L_LONG, WA); /* push old PSL */
1091 Write (SP - 8, PC, L_LONG, WA); /* push old PC */
1092 SP = SP - 8; /* update stk ptr */
1093 JUMP (newpc & ~3); /* change PC */
1094 in_ie = 0; /* out of flows */
1095 return 0;
1096 }
1097
1098 /* CHMK, CHME, CHMS, CHMU
1099
1100 opnd[0] = operand
1101 */
1102
1103 int32 op_chm (int32 *opnd, int32 cc, int32 opc)
1104 {
1105 int32 mode = opc & PSL_M_MODE;
1106 int32 cur = PSL_GETCUR (PSL);
1107 int32 tsp, newpc, acc, sta;
1108
1109 if (PSL & PSL_IS) ABORT (STOP_CHMFI);
1110 newpc = ReadLP ((SCBB + SCB_CHMK + (mode << 2)) & PAMASK);
1111 if (cur < mode) mode = cur; /* only inward */
1112 STK[cur] = SP; /* save stack */
1113 tsp = STK[mode]; /* get new stk */
1114 acc = ACC_MASK (mode); /* set new mode */
1115 if (Test (p2 = tsp - 1, WA, &sta) < 0) { /* probe stk */
1116 p1 = MM_WRITE | (sta & MM_EMASK);
1117 ABORT ((sta & 4)? ABORT_TNV: ABORT_ACV);
1118 }
1119 if (Test (p2 = tsp - 12, WA, &sta) < 0) {
1120 p1 = MM_WRITE | (sta & MM_EMASK);
1121 ABORT ((sta & 4)? ABORT_TNV: ABORT_ACV);
1122 }
1123 Write (tsp - 12, SXTW (opnd[0]), L_LONG, WA); /* push argument */
1124 Write (tsp - 8, PC, L_LONG, WA); /* push PC */
1125 Write (tsp - 4, PSL | cc, L_LONG, WA); /* push PSL */
1126 SP = tsp - 12; /* set new stk */
1127 PSL = (mode << PSL_V_CUR) | (PSL & PSL_IPL) | /* set new PSL */
1128 (cur << PSL_V_PRV); /* IPL unchanged */
1129 last_chm = fault_PC;
1130 JUMP (newpc & ~03); /* set new PC */
1131 return 0; /* cc = 0 */
1132 }
1133
1134 /* REI - return from exception or interrupt
1135
1136 The lengthiest part of the REI instruction is the validity checking of the PSL
1137 popped off the stack. The new PSL is checked against the following eight rules:
1138
1139 let tmp = new PSL popped off the stack
1140 let PSL = current PSL
1141
1142 Rule SRM formulation Comment
1143 ---- --------------- -------
1144 1 tmp<25:24> GEQ PSL<25:24> tmp<cur_mode> GEQ PSL<cur_mode>
1145 2 tmp<26> LEQ PSL<26> tmp<is> LEQ PSL<is>
1146 3 tmp<26> = 1 => tmp<25:24> = 0 tmp<is> = 1 => tmp<cur_mode> = ker
1147 4 tmp<26> = 1 => tmp<20:16> > 0 tmp<is> = 1 => tmp<ipl> > 0
1148 5 tmp<20:16> > 0 => tmp<25:24> = 0 tmp<ipl> > 0 => tmp<cur_mode> = ker
1149 6 tmp<25:24> LEQ tmp<23:22> tmp<cur_mode> LEQ tmp<prv_mode>
1150 7 tmp<20:16> LEQ PSL<20:16> tmp<ipl> LEQ PSL<ipl>
1151 8 tmp<31,29:28,21,15:8> = 0 tmp<mbz> = 0
1152 9 tmp<31> = 1 => tmp<cur_mode> = 3, tmp<prv_mode> = 3>, tmp<fpd,is,ipl> = 0
1153 */
1154
1155 int32 op_rei (int32 acc)
1156 {
1157 int32 newpc = Read (SP, L_LONG, RA);
1158 int32 newpsl = Read (SP + 4, L_LONG, RA);
1159 int32 newcur = PSL_GETCUR (newpsl);
1160 int32 oldcur = PSL_GETCUR (PSL);
1161 int32 newipl, i;
1162
1163 if ((newpsl & PSL_MBZ) || /* rule 8 */
1164 (newcur < oldcur)) RSVD_OPND_FAULT; /* rule 1 */
1165 if (newcur) { /* to esu, skip 2,4,7 */
1166 if ((newpsl & (PSL_IS | PSL_IPL)) || /* rules 3,5 */
1167 (newcur > PSL_GETPRV (newpsl))) /* rule 6 */
1168 RSVD_OPND_FAULT; /* end rei to esu */
1169 }
1170 else { /* to k, skip 3,5,6 */
1171 newipl = PSL_GETIPL (newpsl); /* get new ipl */
1172 if ((newpsl & PSL_IS) && /* setting IS? */
1173 (((PSL & PSL_IS) == 0) || (newipl == 0))) /* test rules 2,4 */
1174 RSVD_OPND_FAULT; /* else skip 2,4 */
1175 if (newipl > PSL_GETIPL (PSL)) RSVD_OPND_FAULT; /* test rule 7 */
1176 } /* end if kernel */
1177 if (newpsl & PSL_CM) { /* setting cmode? */
1178 if (BadCmPSL (newpsl)) RSVD_OPND_FAULT; /* validate PSL */
1179 for (i = 0; i < 7; i++) R[i] = R[i] & WMASK; /* mask R0-R6, PC */
1180 newpc = newpc & WMASK;
1181 }
1182 SP = SP + 8; /* pop stack */
1183 if (PSL & PSL_IS) IS = SP; /* save stack */
1184 else STK[oldcur] = SP;
1185 if (DEBUG_PRI (cpu_dev, LOG_CPU_R)) fprintf (sim_deb,
1186 ">>REI: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n",
1187 PC, PSL, SP - 8, newpc, newpsl, ((newpsl & IS)? IS: STK[newcur]));
1188 PSL = cpu_psl_ipl_idle ((PSL & PSL_TP) | (newpsl & ~CC_MASK)); /* set PSL */
1189 if (PSL & PSL_IS) SP = IS; /* set new stack */
1190 else {
1191 SP = STK[newcur]; /* if ~IS, chk AST */
1192 if (newcur >= ASTLVL) {
1193 if (DEBUG_PRI (cpu_dev, LOG_CPU_R)) fprintf (sim_deb,
1194 ">>REI: AST delivered\n");
1195 SISR = SISR | SISR_2;
1196 }
1197 }
1198 JUMP (newpc); /* set new PC */
1199 return newpsl & CC_MASK; /* set new cc */
1200 }
1201
1202 /* LDCPTX - load process context */
1203
1204 void op_ldpctx (int32 acc)
1205 {
1206 int32 newpc, newpsl, pcbpa, t;
1207
1208 if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */
1209 pcbpa = PCBB & PAMASK; /* phys address */
1210 KSP = ReadLP (pcbpa); /* restore stk ptrs */
1211 ESP = ReadLP (pcbpa + 4);
1212 SSP = ReadLP (pcbpa + 8);
1213 USP = ReadLP (pcbpa + 12);
1214 R[0] = ReadLP (pcbpa + 16); /* restore registers */
1215 R[1] = ReadLP (pcbpa + 20);
1216 R[2] = ReadLP (pcbpa + 24);
1217 R[3] = ReadLP (pcbpa + 28);
1218 R[4] = ReadLP (pcbpa + 32);
1219 R[5] = ReadLP (pcbpa + 36);
1220 R[6] = ReadLP (pcbpa + 40);
1221 R[7] = ReadLP (pcbpa + 44);
1222 R[8] = ReadLP (pcbpa + 48);
1223 R[9] = ReadLP (pcbpa + 52);
1224 R[10] = ReadLP (pcbpa + 56);
1225 R[11] = ReadLP (pcbpa + 60);
1226 R[12] = ReadLP (pcbpa + 64);
1227 R[13] = ReadLP (pcbpa + 68);
1228 newpc = ReadLP (pcbpa + 72); /* get PC, PSL */
1229 newpsl = ReadLP (pcbpa + 76);
1230
1231 t = ReadLP (pcbpa + 80);
1232 ML_PXBR_TEST (t); /* validate P0BR */
1233 P0BR = t & BR_MASK; /* restore P0BR */
1234 t = ReadLP (pcbpa + 84);
1235 LP_MBZ84_TEST (t); /* test mbz */
1236 ML_LR_TEST (t & LR_MASK); /* validate P0LR */
1237 P0LR = t & LR_MASK; /* restore P0LR */
1238 t = (t >> 24) & AST_MASK;
1239 LP_AST_TEST (t); /* validate AST */
1240 ASTLVL = t; /* restore AST */
1241 t = ReadLP (pcbpa + 88);
1242 ML_PXBR_TEST (t + 0x800000); /* validate P1BR */
1243 P1BR = t & BR_MASK; /* restore P1BR */
1244 t = ReadLP (pcbpa + 92);
1245 LP_MBZ92_TEST (t); /* test MBZ */
1246 ML_LR_TEST (t & LR_MASK); /* validate P1LR */
1247 P1LR = t & LR_MASK; /* restore P1LR */
1248 pme = (t >> 31) & 1; /* restore PME */
1249
1250 zap_tb (0); /* clear process TB */
1251 set_map_reg ();
1252 if (DEBUG_PRI (cpu_dev, LOG_CPU_P)) fprintf (sim_deb,
1253 ">>LDP: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n",
1254 PC, PSL, SP, newpc, newpsl, KSP);
1255 if (PSL & PSL_IS) IS = SP; /* if istk, */
1256 PSL = PSL & ~PSL_IS; /* switch to kstk */
1257 SP = KSP - 8;
1258 Write (SP, newpc, L_LONG, WA); /* push PC, PSL */
1259 Write (SP + 4, newpsl, L_LONG, WA);
1260 return;
1261 }
1262
1263 /* SVPCTX - save processor context */
1264
1265 void op_svpctx (int32 acc)
1266 {
1267 int32 savpc, savpsl, pcbpa;
1268
1269 if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */
1270 savpc = Read (SP, L_LONG, RA); /* pop PC, PSL */
1271 savpsl = Read (SP + 4, L_LONG, RA);
1272 if (DEBUG_PRI (cpu_dev, LOG_CPU_P)) fprintf (sim_deb,
1273 ">>SVP: PC=%08x, PSL=%08x, SP=%08x, oPC=%08x, oPSL=%08x\n",
1274 PC, PSL, SP, savpc, savpsl);
1275 if (PSL & PSL_IS) SP = SP + 8; /* int stack? */
1276 else {
1277 KSP = SP + 8; /* pop kernel stack */
1278 SP = IS; /* switch to int stk */
1279 if ((PSL & PSL_IPL) == 0) /* make IPL > 0 */
1280 PSL = PSL | PSL_IPL1;
1281 PSL = PSL | PSL_IS; /* set PSL<is> */
1282 }
1283 pcbpa = PCBB & PAMASK;
1284 WriteLP (pcbpa, KSP); /* save stk ptrs */
1285 WriteLP (pcbpa + 4, ESP);
1286 WriteLP (pcbpa + 8, SSP);
1287 WriteLP (pcbpa + 12, USP);
1288 WriteLP (pcbpa + 16, R[0]); /* save registers */
1289 WriteLP (pcbpa + 20, R[1]);
1290 WriteLP (pcbpa + 24, R[2]);
1291 WriteLP (pcbpa + 28, R[3]);
1292 WriteLP (pcbpa + 32, R[4]);
1293 WriteLP (pcbpa + 36, R[5]);
1294 WriteLP (pcbpa + 40, R[6]);
1295 WriteLP (pcbpa + 44, R[7]);
1296 WriteLP (pcbpa + 48, R[8]);
1297 WriteLP (pcbpa + 52, R[9]);
1298 WriteLP (pcbpa + 56, R[10]);
1299 WriteLP (pcbpa + 60, R[11]);
1300 WriteLP (pcbpa + 64, R[12]);
1301 WriteLP (pcbpa + 68, R[13]);
1302 WriteLP (pcbpa + 72, savpc); /* save PC, PSL */
1303 WriteLP (pcbpa + 76, savpsl);
1304 return;
1305 }
1306
1307 /* PROBER and PROBEW
1308
1309 opnd[0] = mode
1310 opnd[1] = length
1311 opnd[2] = base address
1312 */
1313
1314 int32 op_probe (int32 *opnd, int32 rw)
1315 {
1316 int32 mode = opnd[0] & PSL_M_MODE; /* mask mode */
1317 int32 length = opnd[1];
1318 int32 ba = opnd[2];
1319 int32 prv = PSL_GETPRV (PSL);
1320 int32 acc, sta, sta1;
1321
1322 if (prv > mode) mode = prv; /* maximize mode */
1323 acc = ACC_MASK (mode) << (rw? TLB_V_WACC: 0); /* set acc mask */
1324 Test (ba, acc, &sta); /* probe */
1325 switch (sta) { /* case on status */
1326
1327 case PR_PTNV: /* pte TNV */
1328 p1 = MM_PARAM (rw, PR_PTNV);
1329 p2 = ba;
1330 ABORT (ABORT_TNV); /* force TNV */
1331
1332 case PR_TNV: case PR_OK: /* TNV or ok */
1333 break; /* continue */
1334
1335 default: /* other */
1336 return CC_Z; /* lose */
1337 }
1338
1339 Test (ba + length - 1, acc, &sta1); /* probe end addr */
1340 switch (sta1) { /* case on status */
1341
1342 case PR_PTNV: /* pte TNV */
1343 p1 = MM_PARAM (rw, PR_PTNV);
1344 p2 = ba + length - 1;
1345 ABORT (ABORT_TNV); /* force TNV */
1346
1347 case PR_TNV: case PR_OK: /* TNV or ok */
1348 break; /* win */
1349
1350 default: /* other */
1351 return CC_Z; /* lose */
1352 }
1353
1354 return 0;
1355 }
1356
1357 /* MTPR - move to processor register
1358
1359 opnd[0] = data
1360 opnd[1] = register number
1361 */
1362
1363 int32 op_mtpr (int32 *opnd)
1364 {
1365 int32 val = opnd[0];
1366 int32 prn = opnd[1];
1367 int32 cc;
1368
1369 if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */
1370 if (prn > 63) RSVD_OPND_FAULT; /* reg# > 63? fault */
1371 CC_IIZZ_L (val); /* set cc's */
1372 switch (prn) { /* case on reg # */
1373
1374 case MT_KSP: /* KSP */
1375 if (PSL & PSL_IS) KSP = val; /* on IS? store KSP */
1376 else SP = val; /* else store SP */
1377 break;
1378
1379 case MT_ESP: case MT_SSP: case MT_USP: /* ESP, SSP, USP */
1380 STK[prn] = val; /* store stack */
1381 break;
1382
1383 case MT_IS: /* IS */
1384 if (PSL & PSL_IS) SP = val; /* on IS? store SP */
1385 else IS = val; /* else store IS */
1386 break;
1387
1388 case MT_P0BR: /* P0BR */
1389 ML_PXBR_TEST (val); /* validate */
1390 P0BR = val & BR_MASK; /* lw aligned */
1391 zap_tb (0); /* clr proc TLB */
1392 set_map_reg ();
1393 break;
1394
1395 case MT_P0LR: /* P0LR */
1396 ML_LR_TEST (val & LR_MASK); /* validate */
1397 P0LR = val & LR_MASK;
1398 zap_tb (0); /* clr proc TLB */
1399 set_map_reg ();
1400 break;
1401
1402 case MT_P1BR: /* P1BR */
1403 ML_PXBR_TEST (val + 0x800000); /* validate */
1404 P1BR = val & BR_MASK; /* lw aligned */
1405 zap_tb (0); /* clr proc TLB */
1406 set_map_reg ();
1407 break;
1408
1409 case MT_P1LR: /* P1LR */
1410 ML_LR_TEST (val & LR_MASK); /* validate */
1411 P1LR = val & LR_MASK;
1412 zap_tb (0); /* clr proc TLB */
1413 set_map_reg ();
1414 break;
1415
1416 case MT_SBR: /* SBR */
1417 ML_SBR_TEST (val); /* validate */
1418 SBR = val & BR_MASK; /* lw aligned */
1419 zap_tb (1); /* clr entire TLB */
1420 set_map_reg ();
1421 break;
1422
1423 case MT_SLR: /* SLR */
1424 ML_LR_TEST (val & LR_MASK); /* validate */
1425 SLR = val & LR_MASK;
1426 zap_tb (1); /* clr entire TLB */
1427 set_map_reg ();
1428 break;
1429
1430 case MT_SCBB: /* SCBB */
1431 ML_PA_TEST (val); /* validate */
1432 SCBB = val & BR_MASK; /* lw aligned */
1433 break;
1434
1435 case MT_PCBB: /* PCBB */
1436 ML_PA_TEST (val); /* validate */
1437 PCBB = val & BR_MASK; /* lw aligned */
1438 break;
1439
1440 case MT_IPL: /* IPL */
1441 PSL = (PSL & ~PSL_IPL) | ((val & PSL_M_IPL) << PSL_V_IPL);
1442 break;
1443
1444 case MT_ASTLVL: /* ASTLVL */
1445 if (val > AST_MAX) RSVD_OPND_FAULT; /* > 4? fault */
1446 ASTLVL = val;
1447 break;
1448
1449 case MT_SIRR: /* SIRR */
1450 if ((val > 0xF) || (val == 0)) RSVD_OPND_FAULT;
1451 SISR = SISR | (1 << val); /* set bit in SISR */
1452 break;
1453
1454 case MT_SISR: /* SISR */
1455 SISR = val & SISR_MASK;
1456 break;
1457
1458 case MT_MAPEN: /* MAPEN */
1459 mapen = val & 1;
1460 case MT_TBIA: /* TBIA */
1461 zap_tb (1); /* clr entire TLB */
1462 break;
1463
1464 case MT_TBIS: /* TBIS */
1465 zap_tb_ent (val);
1466 break;
1467
1468 case MT_TBCHK: /* TBCHK */
1469 if (chk_tb_ent (val)) cc = cc | CC_V;
1470 break;
1471
1472 case MT_PME: /* PME */
1473 pme = val & 1;
1474 break;
1475
1476 default:
1477 WriteIPR (prn, val); /* others */
1478 break;
1479 }
1480
1481 return cc;
1482 }
1483
1484 int32 op_mfpr (int32 *opnd)
1485 {
1486 int32 prn = opnd[0];
1487 int32 val;
1488
1489 if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */
1490 if (prn > 63) RSVD_OPND_FAULT; /* reg# > 63? fault */
1491 switch (prn) { /* case on reg# */
1492
1493 case MT_KSP: /* KSP */
1494 val = (PSL & PSL_IS)? KSP: SP; /* return KSP or SP */
1495 break;
1496
1497 case MT_ESP: case MT_SSP: case MT_USP: /* ESP, SSP, USP */
1498 val = STK[prn]; /* return stk ptr */
1499 break;
1500
1501 case MT_IS: /* IS */
1502 val = (PSL & PSL_IS)? SP: IS; /* return SP or IS */
1503 break;
1504
1505 case MT_P0BR: /* P0BR */
1506 val = P0BR;
1507 break;
1508
1509 case MT_P0LR: /* P0LR */
1510 val = P0LR;
1511 break;
1512
1513 case MT_P1BR: /* P1BR */
1514 val = P1BR;
1515 break;
1516
1517 case MT_P1LR: /* P1LR */
1518 val = P1LR;
1519 break;
1520
1521 case MT_SBR: /* SBR */
1522 val = SBR;
1523 break;
1524
1525 case MT_SLR: /* SLR */
1526 val = SLR;
1527 break;
1528
1529 case MT_SCBB: /* SCBB */
1530 val = SCBB;
1531 break;
1532
1533 case MT_PCBB: /* PCBB */
1534 val = PCBB;
1535 break;
1536
1537 case MT_IPL: /* IPL */
1538 val = PSL_GETIPL (PSL);
1539 break;
1540
1541 case MT_ASTLVL: /* ASTLVL */
1542 val = ASTLVL;
1543 break;
1544
1545 case MT_SISR: /* SISR */
1546 val = SISR & SISR_MASK;
1547 break;
1548
1549 case MT_MAPEN: /* MAPEN */
1550 val = mapen & 1;
1551 break;
1552
1553 case MT_PME:
1554 val = pme & 1;
1555 break;
1556
1557 case MT_SIRR:
1558 case MT_TBIA:
1559 case MT_TBIS:
1560 case MT_TBCHK:
1561 RSVD_OPND_FAULT; /* write only */
1562
1563 default: /* others */
1564 val = ReadIPR (prn); /* read from SSC */
1565 break;
1566 }
1567
1568 return val;
1569 }