1 /* vax_cpu1.c: VAX complex instructions
3 Copyright (c) 1998-2008, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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)
41 This module contains the instruction simulators for
44 - BBS, BBC, BBSSI, BBCCI
45 - BBSC, BBCC, BBCS, BBSS
46 - EXTV, EXTZV, CMPV, CMPZV
49 Call/return and push/pop instructions:
55 - INSQHI, INSQTI, REMQHI, REMQTI
58 - MOVC3, MOVC5, CMPC3, CMPC5
59 - LOCC, SKPC, SCANC, SPANC
61 Operating system interface instructions:
62 - CHMK, CHME, CHMS, CHMU
66 - (interrupt and exception routine)
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 */
85 extern const uint32 byte_mask
[33];
89 extern int32 SCBB
, PCBB
, SBR
, SLR
;
90 extern int32 P0BR
, P0LR
, P1BR
, P1LR
;
91 extern int32 ASTLVL
, SISR
, mapen
;
95 extern int32 fault_PC
;
96 extern int32 pcq
[PCQ_SIZE
];
99 extern int32 sim_interval
;
100 extern int32 ibcnt
, ppc
;
101 extern FILE *sim_deb
;
102 extern DEVICE cpu_dev
;
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
);
114 extern jmp_buf save_env
;
116 /* Branch on bit and no modify
117 Branch on bit and modify
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
125 int32
op_bb_n (int32
*opnd
, int32 acc
)
131 if (rn
>= 0) { /* register? */
132 if (((uint32
) pos
) > 31) RSVD_OPND_FAULT
; /* pos > 31? fault */
133 return (R
[rn
] >> pos
) & 1; /* get bit */
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 */
141 int32
op_bb_x (int32
*opnd
, int32 newb
, int32 acc
)
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
));
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 */
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
169 If the field is in a register, rn + 1 is in vfldrp1
172 int32
op_extv (int32
*opnd
, int32 vfldrp1
, int32 acc
)
175 int32 size
= opnd
[1];
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
));
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
));
196 return wd
& byte_mask
[size
];
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
207 If the field is in a register, rn + 1 is in vfldrp1
210 void op_insv (int32
*opnd
, int32 vfldrp1
, int32 acc
)
212 uint32 ins
= opnd
[0];
214 int32 size
= opnd
[2];
216 int32 val
, mask
, ba
, wd
, wd1
;
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
);
228 mask
= byte_mask
[size
] << pos
; /* insert field */
230 R
[rn
] = (R
[rn
] & ~mask
) | (val
& mask
);
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
);
243 mask
= byte_mask
[size
] << pos
; /* insert field */
245 Write (ba
, (wd
& ~mask
) | (val
& mask
), L_LONG
, WA
);
252 int32
op_ffs (uint32 wd
, int32 size
)
256 for (i
= 0; wd
; i
++, wd
= wd
>> 1) if (wd
& 1) return i
;
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) { \
271 Write (tsp, R[n], L_LONG, WA); \
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); \
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); \
286 opnd[0] = argument (arg.rx)
287 opnd[1] = procedure address (adr.ab)
288 flg = CALLG (0), CALLS (1)
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:
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 +---+-+-+-----------------------+--------------------+----------+
302 +---------------------------------------------------------------+
304 +---------------------------------------------------------------+
306 +---------------------------------------------------------------+
308 +---------------------------------------------------------------+
310 . (according to entry mask<11:0>) .
312 +---------------------------------------------------------------+
314 +---------------+-----------------------------------------------+
315 | #args (CALLS) | (0-3 bytes needed to align stack) |
316 +---------------+-----------------------------------------------+
318 +---------------+-----------------------------------------------+
320 RET expects to find this structure based at the frame pointer (FP).
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:
326 +--+--+-----+----------------------------------+
327 |DV|IV| MBZ | register mask |
328 +--+--+-----+----------------------------------+
330 CALLG/CALLS operation:
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
342 int32
op_call (int32
*opnd
, t_bool gs
, int32 acc
)
344 int32 addr
= opnd
[1];
345 int32 mask
, stklen
, tsp
, wd
;
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 */
352 Write (SP
- 4, opnd
[0], L_LONG
, WA
); /* if S, push #arg */
353 SP
= SP
- 4; /* stack is valid */
355 tsp
= SP
& ~CALL_M_SPA
; /* lw align stack */
356 CALL_PUSH (11); /* check mask bits, */
357 CALL_PUSH (10); /* push sel reg */
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 */
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 */
385 int32
op_ret (int32 acc
)
387 int32 spamask
, stklen
, newpc
, nargs
;
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 */
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 */
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 */
424 void op_pushr (int32
*opnd
, int32 acc
)
426 int32 mask
= opnd
[0] & 0x7FFF;
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 */
449 SP
= tsp
; /* update stk ptr */
453 void op_popr (int32
*opnd
, int32 acc
)
455 int32 mask
= opnd
[0] & 0x7FFF;
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 */
476 if (mask
& 0x4000) SP
= Read (SP
, L_LONG
, RA
); /* if pop SP, no inc */
482 opnd[0] = entry address (ent.ab)
483 opnd[1] = predecessor address (pred.ab)
485 Condition codes returned to caller on comparison of (ent):(ent+4).
486 All writes must be checked before any writes are done.
493 P+4: (n/a) P+4: (n/a)
501 s+4 must be tested with a read modify rather than a probe, as it
505 int32
op_insque (int32
*opnd
, int32 acc
)
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 */
524 opnd[0] = entry address (ent.ab)
525 opnd[1:2] = destination address (dst.wl)
527 Condition codes returned to caller based on (ent):(ent+4).
528 All writes must be checked before any writes are done.
535 P+4: (n/a) P+4: (n/a)
545 int32
op_remque (int32
*opnd
, int32 acc
)
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 */
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
);
565 /* Interlocked insert instructions
567 opnd[0] = entry (ent.ab)
568 opnd[1] = header (hdr.aq)
572 BEFORE AFTER INSQHI AFTER INSQTI
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
578 A+4: H-A A+4: D-A W A+4: H-A
581 B+4: A-B B+4: A-B B+4: A-B
583 C: H-C C: H-C C: D-C W
584 C+4: B-C C+4: B-C C+4: B-C
586 D: --- D: A-D W D: H-D W
587 D+4: --- D+4: H-D W D+4: C-D W
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
595 int32
op_insqhi (int32
*opnd
, int32 acc
)
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 */
616 int32
op_insqti (int32
*opnd
, int32 acc
)
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 */
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 */
643 /* Interlocked remove instructions
645 opnd[0] = header (hdr.aq)
646 opnd[1:2] = destination address (dst.al)
650 BEFORE AFTER REMQHI AFTER REMQTI
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
655 A: B-A A: B-A R A: B-A
656 A+4: H-A A+4: H-A A+4: H-A
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
662 C+4: B-C C+4: B-C C+4: B-C R
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.
669 int32
op_remqhi (int32
*opnd
, int32 acc
)
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 */
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 */
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 */
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 */
703 int32
op_remqti (int32
*opnd
, int32 acc
)
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 */
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 */
723 if (c
& 07) { /* c quad aligned? */
724 Write (h
, ar
, L_LONG
, WA
); /* release interlock */
725 RSVD_OPND_FAULT
; /* fault */
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 */
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 */
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 */
748 /* String instructions */
750 #define MVC_FRWD 0 /* movc state codes */
752 #define MVC_FILL 3 /* must be 3 */
753 #define MVC_M_STATE 3
758 if PSL<fpd> = 0 and MOVC3,
760 opnd[1] = source address
761 opnd[2] = dest address
763 if PSL<fpd> = 0 and MOVC5,
764 opnd[0] = source length
765 opnd[1] = source address
767 opnd[3] = dest length
768 opnd[4] = dest address
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)
779 int32
op_movc (int32
*opnd
, int32 movc5
, int32 acc
)
781 int32 i
, cc
, fill
, wd
;
782 int32 j
, lnt
, mlnt
[3];
783 static const int32 looplnt
[3] = { L_BYTE
, L_LONG
, L_BYTE
};
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
;
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 */
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 */
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 */
813 else R
[5] = MVC_FRWD
; /* fwd, set state */
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 */
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
830 switch (R
[5] & MVC_M_STATE
) { /* case on state */
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 */
847 goto FILL
; /* check for fill */
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 */
864 R
[1] = R
[1] + (R
[0] & STR_LNMASK
); /* final src addr */
865 R
[3] = R
[3] + (R
[0] & STR_LNMASK
); /* final dst addr */
867 case MVC_FILL
: /* 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 */
888 default: /* bad state */
889 RSVD_OPND_FAULT
; /* you lose */
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 */
901 if PSL<fpd> = 0 and CMPC3,
903 opnd[1] = source1 address
904 opnd[2] = source2 address
906 if PSL<fpd> = 0 and CMPC5,
907 opnd[0] = source1 length
908 opnd[1] = source1 address
910 opnd[3] = source2 length
911 opnd[4] = source2 address
914 R0 = delta-PC/fill/source1 length
920 int32
op_cmpc (int32
*opnd
, int32 cmpc5
, int32 acc
)
922 int32 cc
, s1
, s2
, fill
;
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 */
929 R
[1] = opnd
[1]; /* src1len */
930 if (cmpc5
) { /* CMPC5? */
931 R
[2] = opnd
[3]; /* get src2 opnds */
936 R
[2] = opnd
[0]; /* src2len = src1len */
940 R
[0] = STR_PACK (fill
, opnd
[0]); /* src1len + FPD data */
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
);
954 if (R
[2]) { /* if src2, decr */
955 R
[2] = (R
[2] - 1) & STR_LNMASK
;
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 */
968 opnd[0] = match character
969 opnd[1] = source length
970 opnd[2] = source address
973 R0 = delta-PC/match/source length
977 int32
op_locskp (int32
*opnd
, int32 skpc
, int32 acc
)
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 */
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 */
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 */
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 */
1005 opnd[0] = source length
1006 opnd[1] = source address
1007 opnd[2] = table address
1011 R0 = delta-PC/char/source length
1016 int32
op_scnspn (int32
*opnd
, int32 spanc
, int32 acc
)
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 */
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
;
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
);
1038 PSL
= PSL
& ~PSL_FPD
;
1039 R
[0] = R
[0] & STR_LNMASK
; /* clear packup */
1041 return (R
[0]? 0: CC_Z
);
1044 /* Operating system interfaces */
1046 /* Interrupt or exception
1049 cc = condition codes
1050 ipl = new IPL if interrupt
1051 ei = -1: severe exception
1056 int32
intexc (int32 vec
, int32 cc
, int32 ipl
, int ei
)
1058 int32 oldpsl
= PSL
| cc
;
1059 int32 oldcur
= PSL_GETCUR (oldpsl
);
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? */
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 */
1078 newpsl
= 0; /* to ker stk */
1079 SP
= KSP
; /* new stack */
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 */
1098 /* CHMK, CHME, CHMS, CHMU
1103 int32
op_chm (int32
*opnd
, int32 cc
, int32 opc
)
1105 int32 mode
= opc
& PSL_M_MODE
;
1106 int32 cur
= PSL_GETCUR (PSL
);
1107 int32 tsp
, newpc
, acc
, sta
;
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
);
1119 if (Test (p2
= tsp
- 12, WA
, &sta
) < 0) {
1120 p1
= MM_WRITE
| (sta
& MM_EMASK
);
1121 ABORT ((sta
& 4)? ABORT_TNV
: ABORT_ACV
);
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 */
1134 /* REI - return from exception or interrupt
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:
1139 let tmp = new PSL popped off the stack
1140 let PSL = current PSL
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
1155 int32
op_rei (int32 acc
)
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
);
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 */
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
;
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 */
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
;
1198 JUMP (newpc
); /* set new PC */
1199 return newpsl
& CC_MASK
; /* set new cc */
1202 /* LDCPTX - load process context */
1204 void op_ldpctx (int32 acc
)
1206 int32 newpc
, newpsl
, pcbpa
, t
;
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);
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 */
1250 zap_tb (0); /* clear process TB */
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 */
1258 Write (SP
, newpc
, L_LONG
, WA
); /* push PC, PSL */
1259 Write (SP
+ 4, newpsl
, L_LONG
, WA
);
1263 /* SVPCTX - save processor context */
1265 void op_svpctx (int32 acc
)
1267 int32 savpc
, savpsl
, pcbpa
;
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? */
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> */
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
);
1307 /* PROBER and PROBEW
1311 opnd[2] = base address
1314 int32
op_probe (int32
*opnd
, int32 rw
)
1316 int32 mode
= opnd
[0] & PSL_M_MODE
; /* mask mode */
1317 int32 length
= opnd
[1];
1319 int32 prv
= PSL_GETPRV (PSL
);
1320 int32 acc
, sta
, sta1
;
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 */
1327 case PR_PTNV
: /* pte TNV */
1328 p1
= MM_PARAM (rw
, PR_PTNV
);
1330 ABORT (ABORT_TNV
); /* force TNV */
1332 case PR_TNV
: case PR_OK
: /* TNV or ok */
1333 break; /* continue */
1335 default: /* other */
1336 return CC_Z
; /* lose */
1339 Test (ba
+ length
- 1, acc
, &sta1
); /* probe end addr */
1340 switch (sta1
) { /* case on status */
1342 case PR_PTNV
: /* pte TNV */
1343 p1
= MM_PARAM (rw
, PR_PTNV
);
1344 p2
= ba
+ length
- 1;
1345 ABORT (ABORT_TNV
); /* force TNV */
1347 case PR_TNV
: case PR_OK
: /* TNV or ok */
1350 default: /* other */
1351 return CC_Z
; /* lose */
1357 /* MTPR - move to processor register
1360 opnd[1] = register number
1363 int32
op_mtpr (int32
*opnd
)
1365 int32 val
= opnd
[0];
1366 int32 prn
= opnd
[1];
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 # */
1374 case MT_KSP
: /* KSP */
1375 if (PSL
& PSL_IS
) KSP
= val
; /* on IS? store KSP */
1376 else SP
= val
; /* else store SP */
1379 case MT_ESP
: case MT_SSP
: case MT_USP
: /* ESP, SSP, USP */
1380 STK
[prn
] = val
; /* store stack */
1383 case MT_IS
: /* IS */
1384 if (PSL
& PSL_IS
) SP
= val
; /* on IS? store SP */
1385 else IS
= val
; /* else store IS */
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 */
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 */
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 */
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 */
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 */
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 */
1430 case MT_SCBB
: /* SCBB */
1431 ML_PA_TEST (val
); /* validate */
1432 SCBB
= val
& BR_MASK
; /* lw aligned */
1435 case MT_PCBB
: /* PCBB */
1436 ML_PA_TEST (val
); /* validate */
1437 PCBB
= val
& BR_MASK
; /* lw aligned */
1440 case MT_IPL
: /* IPL */
1441 PSL
= (PSL
& ~PSL_IPL
) | ((val
& PSL_M_IPL
) << PSL_V_IPL
);
1444 case MT_ASTLVL
: /* ASTLVL */
1445 if (val
> AST_MAX
) RSVD_OPND_FAULT
; /* > 4? fault */
1449 case MT_SIRR
: /* SIRR */
1450 if ((val
> 0xF) || (val
== 0)) RSVD_OPND_FAULT
;
1451 SISR
= SISR
| (1 << val
); /* set bit in SISR */
1454 case MT_SISR
: /* SISR */
1455 SISR
= val
& SISR_MASK
;
1458 case MT_MAPEN
: /* MAPEN */
1460 case MT_TBIA
: /* TBIA */
1461 zap_tb (1); /* clr entire TLB */
1464 case MT_TBIS
: /* TBIS */
1468 case MT_TBCHK
: /* TBCHK */
1469 if (chk_tb_ent (val
)) cc
= cc
| CC_V
;
1472 case MT_PME
: /* PME */
1477 WriteIPR (prn
, val
); /* others */
1484 int32
op_mfpr (int32
*opnd
)
1486 int32 prn
= opnd
[0];
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# */
1493 case MT_KSP
: /* KSP */
1494 val
= (PSL
& PSL_IS
)? KSP
: SP
; /* return KSP or SP */
1497 case MT_ESP
: case MT_SSP
: case MT_USP
: /* ESP, SSP, USP */
1498 val
= STK
[prn
]; /* return stk ptr */
1501 case MT_IS
: /* IS */
1502 val
= (PSL
& PSL_IS
)? SP
: IS
; /* return SP or IS */
1505 case MT_P0BR
: /* P0BR */
1509 case MT_P0LR
: /* P0LR */
1513 case MT_P1BR
: /* P1BR */
1517 case MT_P1LR
: /* P1LR */
1521 case MT_SBR
: /* SBR */
1525 case MT_SLR
: /* SLR */
1529 case MT_SCBB
: /* SCBB */
1533 case MT_PCBB
: /* PCBB */
1537 case MT_IPL
: /* IPL */
1538 val
= PSL_GETIPL (PSL
);
1541 case MT_ASTLVL
: /* ASTLVL */
1545 case MT_SISR
: /* SISR */
1546 val
= SISR
& SISR_MASK
;
1549 case MT_MAPEN
: /* MAPEN */
1561 RSVD_OPND_FAULT
; /* write only */
1563 default: /* others */
1564 val
= ReadIPR (prn
); /* read from SSC */