1
0
mirror of https://github.com/PDP-10/klh10.git synced 2026-02-05 16:05:30 +00:00
Files
PDP-10.klh10/src/injrst.c
Olaf Seibert 58b59dbaa1 Overlay panda-dist/klh10-2.0h
by the late MRC, Mark Crispin.
Source: probably the former http://panda.com/tops-20/ .
panda-dist.tar.gz dated Mar 30  2007.
2015-04-27 23:07:21 +02:00

762 lines
23 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* INJRST.C - Jump (and Stack) instruction routines
*/
/* $Id: injrst.c,v 2.4 2002/03/21 09:50:55 klh Exp $
*/
/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien
** All Rights Reserved
**
** This file is part of the KLH10 Distribution. Use, modification, and
** re-distribution is permitted subject to the terms in the file
** named "LICENSE", which contains the full text of the legal notices
** and should always accompany this Distribution.
**
** This software is provided "AS IS" with NO WARRANTY OF ANY KIND.
**
** This notice (including the copyright and warranty disclaimer)
** must be included in all copies or derivations of this software.
*/
/*
* $Log: injrst.c,v $
* Revision 2.4 2002/03/21 09:50:55 klh
* Fixed refs of fe_debug to use mr_debug
*
* Revision 2.3 2001/11/10 21:28:59 klh
* Final 2.0 distribution checkin
*
*/
/* See CODING.TXT for guidelines to coding instruction routines. */
#include "klh10.h"
#include "kn10def.h"
#include "kn10ops.h"
#include <stdio.h> /* For debug output */
#ifdef RCSID
RCSID(injrst_c,"$Id: injrst.c,v 2.4 2002/03/21 09:50:55 klh Exp $")
#endif
/* Imported functions */
extern void pishow(FILE *);
extern void pcfshow(FILE *, h10_t flags);
insdef(i_jffo) /* JFFO */
{
register int i = op10ffo(ac_get(ac));
if (i < 36) { /* Found a bit? */
ac_setlrh(ac_off(ac,1), 0, i); /* Yep, set AC+1 */
PC_JUMP(e); /* and take the jump! */
return PCINC_0;
}
ac_setlrh(ac_off(ac,1), 0, 0); /* Empty, don't jump */
return PCINC_1;
}
insdef(i_jfcl)
{
if (ac) { /* See which flags we're asking for */
register h10_t flags;
flags = (h10_t)ac << (18-4); /* Shift to match PC flags */
if (PCFTEST(flags)) { /* Any of them match? */
PCFCLEAR(flags); /* Yes, clear them */
PC_JUMP(e); /* and take the jump! */
return PCINC_0;
}
}
return PCINC_1;
}
insdef(i_jsr) /* JSR */
{
register w10_t w;
PC_1WORD(w); /* Make PC-word in w (PC+1, plus flags if sect 0) */
vm_write(e, w); /* Store it at E */
PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */
va_inc(e); /* Jump to E+1 (local or global) */
PC_JUMP(e);
return PCINC_0;
}
insdef(i_jsp) /* JSP */
{
register w10_t w;
PC_1WORD(w); /* Cons up PC+1 word in w */
ac_set(ac, w); /* Store it in AC */
PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */
PC_JUMP(e); /* Jump to E */
return PCINC_0;
}
/* Note for JSA and JRA that there is no difference in their behavior
** when executed in non-zero sections.
*/
insdef(i_jsa) /* JSA */
{
register w10_t w;
vm_write(e, ac_get(ac)); /* Store c(AC) into E */
PC_XWDPC1(w, va_insect(e)); /* Cons up word: <e>,,<PC+1> */
ac_set(ac, w); /* Store that JSA-word in AC */
va_inc(e); /* Jump to E+1 */
PC_JUMP(e);
return PCINC_0;
}
insdef(i_jra) /* JRA */
{
register vaddr_t va;
va_lmake(va, PC_SECT,ac_getlh(ac)); /* Make AC.lh a local address */
ac_set(ac, vm_read(va)); /* Get c(AC.lh) into AC */
va_lmake(va, PC_SECT, va_insect(e));
PC_JUMP(va); /* Jump to PC section,,RH(E) */
return PCINC_0;
}
/* JRST hackery */
/* Declare subvariants of JRST */
pcinc_t ij_jrstf (int, int, vaddr_t);
pcinc_t ij_halt (int, int, vaddr_t);
pcinc_t ij_jen (int, int, vaddr_t);
pcinc_t ij_jrst10(int, int, vaddr_t);
#if !KLH10_SYS_ITS
pcinc_t ij_portal(int, int, vaddr_t);
pcinc_t ij_xjrstf(int, int, vaddr_t);
pcinc_t ij_xjen (int, int, vaddr_t);
pcinc_t ij_xpcw (int, int, vaddr_t);
pcinc_t ij_sfm (int, int, vaddr_t);
#endif
#if KLH10_CPU_KLX
pcinc_t ij_xjrst (int, int, vaddr_t);
#endif
insdef(i_jrst)
{
switch (ac) {
case 0: /* JRST */
PC_JUMP(e);
return PCINC_0;
#if !KLH10_SYS_ITS
case 1: return ij_portal(op, ac, e); /* PORTAL - not used by ITS */
#endif /* DEC */
case 2: return ij_jrstf(op, ac, e); /* JRSTF - Used */
case 4: return ij_halt(op, ac, e); /* HALT - Used */
#if !KLH10_SYS_ITS && (KLH10_CPU_KS||KLH10_CPU_KLX)
case 5: return ij_xjrstf(op, ac, e); /* XJRSTF - not used by ITS */
case 6: return ij_xjen(op, ac, e); /* XJEN - not used by ITS */
case 7: return ij_xpcw(op, ac, e); /* XPCW - not used by ITS */
#endif /* DEC KS || KLX */
case 010: return ij_jrst10(op, ac, e); /* JRST 10, - used once (?) */
case 012: return ij_jen(op, ac, e); /* JEN - used frequently */
#if !KLH10_SYS_ITS && (KLH10_CPU_KS||KLH10_CPU_KLX)
case 014: return ij_sfm(op, ac, e); /* SFM - not used by ITS */
# if KLH10_CPU_KLX
case 015: return ij_xjrst(op, ac, e); /* XJRST - not used by ITS */
# endif /* KLX */
#endif /* DEC */
#if KLH10_SYS_ITS
case 017: break; /* - used once by KL10 ITS */
#endif
}
/* Illegal - MUUO (3,11,13,16,17) */
return i_muuo(op, ac, e);
}
/* DORSTF - Actually carry out flag restoration for JRSTF/XJRSTF/XJEN/XPCW.
** Restore flags from the top 12 bits of the word in w.
**
** All flags are restored verbatim with these exceptions:
** USER cannot be cleared by a new setting of 0 (no effect), although
** a 1 will always set it.
** UIO can always be cleared, but new setting of 1 will only have
** an effect if the old mode is EXEC. (Note that if old
** mode is user, 1 merely has no effect; the bit may already
** be set and will remain so.)
** PUBLIC can always be set by a 1, but a 0 only has effect if
** old mode is EXEC and new mode is USER.
**
** No special actions are taken for PrevCtxtPublic or PrevCtxtUser.
**
** The wording of the DEC PRM (6/82 p.2-71) is a little misleading, as it
** implies that bit 6 (User-IO) cannot be set to 1 while in user mode; however,
** it appears in reality that it *can* be, if it was *already* 1.
** This is a rather subtle point.
*/
/* LH(w) contains flags to restore */
#if KLH10_EXTADR
static pcinc_t dorstf(register w10_t w, vaddr_t e, int pcsf)
# define IJ_DO_RSTF(w, e, pcsf) dorstf(w, e, pcsf)
#else
static pcinc_t dorstf(register w10_t w, vaddr_t e)
# define IJ_DO_RSTF(w, e, pcsf) dorstf(w, e)
#endif
{
register uint18 newf; /* New flags to restore */
#if KLH10_DEBUG
if (cpu.mr_debug) {
putc('[', stderr);
pishow(stderr); pcfshow(stderr, cpu.mr_pcflags);
#if KLH10_EXTADR
if (pcsf) fprintf(stderr, "(PCS:%o)", pag_pcsget());
#endif
fprintf(stderr,"%lo: -> ", (long) PC_30);
}
#endif
newf = LHGET(w); /* Get flags into easy-access reg */
if (PCFTEST(PCF_USR)) { /* Currently in user mode? */
newf |= PCF_USR; /* Never permit USR clearing */
if (!PCFTEST(PCF_UIO)) /* If not already in UIO, */
newf &= ~PCF_UIO; /* don't permit UIO setting */
}
#if KLH10_CPU_KL || KLH10_CPU_KI
if (PCFTEST(PCF_PUB) /* If trying to clear Public, */
&& (newf & PCF_PUB)==0) { /* Must be EXEC, setting USER too. */
if (PCFTEST(PCF_USR) || !(newf&PCF_USR))
newf |= PCF_PUB; /* Nope, don't clear it */
}
#endif /* KL || KI */
/* For XJRSTF/XJEN, a new PCS is loaded from the flag word only if
** the new flags specify EXEC mode.
** (PRM 2-66, 2nd sentence from bottom).
*/
#if KLH10_EXTADR /* If going into EXEC mode, restore PCS */
if (pcsf && !(newf & PCF_USR)) {
pag_pcsset(RHGET(w) & UBR_PCS); /* For now, ignore too-big PCS */
}
#endif
cpu.mr_pcflags = newf & PCF_MASK; /* Set new flags!! */
PC_JUMP(e); /* Take the jump... */
apr_pcfcheck(); /* Check flags for any changes. */
/* NOTE! It is important to check AFTER the PC has changed, so that
** if there is a user/exec context change, the saved JPC will be the
** appropriate one for the previous context.
*/
#if KLH10_DEBUG
if (cpu.mr_debug) {
pishow(stderr); pcfshow(stderr, cpu.mr_pcflags);
#if KLH10_EXTADR
if (pcsf) fprintf(stderr, "(PCS:%o)", pag_pcsget());
#endif
fprintf(stderr,"%lo:]\r\n", (long) PC_30);
}
#endif
return PCINC_0;
}
#if !KLH10_SYS_ITS
/* PORTAL (JRST 1,) - Clear Public and jump to E
** On KS10, equivalent to JRST.
*/
insdef(ij_portal)
{
#if KLH10_CPU_KI || KLH10_CPU_KL
PCFCLEAR(PCF_PUB); /* Always clear public, nothing else needed */
#endif
PC_JUMP(e);
return PCINC_0;
}
#endif /* !KLH10_SYS_ITS */
/* JRSTF (JRST 2,)- Jump and Restore Flags from final word used in calc of E.
**
** Because this word isn't saved by the normal instruction loop,
** it needs to be recomputed. This is painful, but I judged that
** it was better to make JRSTF slower so that every other instruction could
** be slightly faster.
**
** The "mr_injrstf" flag is set solely so any page faults which occur can
** avoid being faked out. No faults should in fact happen at this point;
** if any do there is a horrible error somewhere.
*/
insdef(ij_jrstf)
{
register w10_t w;
register vaddr_t ea;
#if KLH10_EXTADR
if (PC_ISEXT) /* A JRSTF in non-zero section is a MUUO */
return i_muuo(op, ac, e);
#endif
cpu.mr_injrstf = TRUE;
/* Assume that our execution started at mr_PC. This will be untrue
** only if we're being executed as a trap or interrupt instruction.
** XCT is allowed, but PXCT is fortunately illegal.
*/
ea = PC_VADDR; /* Get PC as a virtual address */
for (;;) {
w = vm_fetch(ea); /* Get instr */
if (iw_op(w) != I_XCT)
break;
ea = ea_calc(w); /* Is XCT, track chain */
}
if (iw_op(w) != op /* Must match original instr */
|| iw_ac(w) != ac) /* both in OP and AC */
panic("ij_jrstf: cannot duplicate op");
/* Now get to the point of this stupid exercise! */
w = ea_wcalc(w, cpu.acblk.xea, cpu.vmap.xea); /* Do full EA calc */
if (RHGET(w) != va_insect(e)) /* One more check... */
panic("ij_jrstf: cannot duplicate E");
cpu.mr_injrstf = FALSE; /* No more pagefault risk */
return IJ_DO_RSTF(w, e, FALSE);
}
/* JEN (JRST 12,) - Combination of JRST10 and JRSTF.
** Lets those routines do the work. JRSTF's hack to find the PC flags
** will work, because the opcode & AC are all passed along to it.
** If user mode, only legal if User-IOT is set.
*/
insdef(ij_jen)
{
#if KLH10_EXTADR
if (PC_ISEXT)
return i_muuo(op, ac, e);
#endif
#if KLH10_CPU_KS || KLH10_CPU_KA
if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO))
#elif KLH10_CPU_KL
if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */
|| (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB)))
#elif KLH10_CPU_KI
if (PCFTEST(PCF_USR | PCF_PUB)) /* Kernel mode only */
#endif
return i_muuo(op, ac, e);
pi_dismiss(); /* Tell PI to dismiss current int */
return ij_jrstf(op, ac, e);
}
/* JRST 10, - Dismisses current interrupt ("restores the level on which the
** highest priority interrupt is currently being held").
** If user mode, only legal if User-IOT is set.
*/
insdef(ij_jrst10)
{
#if KLH10_CPU_KS || KLH10_CPU_KA
if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Exec */
#elif KLH10_CPU_KL
if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */
|| (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB)))
#elif KLH10_CPU_KI
if (PCFTEST(PCF_USR | PCF_PUB)) /* Kernel mode only */
#endif
return i_muuo(op, ac, e);
pi_dismiss(); /* Tell PI to dismiss current int */
PC_JUMP(e); /* Take the jump... */
#if KLH10_DEBUG
if (cpu.mr_debug) {
fprintf(stderr,"[ -> ");
pishow(stderr); pcfshow(stderr, cpu.mr_pcflags);
fprintf(stderr,"%lo:]\r\n", (long) PC_30);
}
#endif
return PCINC_0;
}
/* HALT (JRST 4,) - Halt the processor.
*/
insdef(ij_halt)
{
#if KLH10_CPU_KS || KLH10_CPU_KA
if (!PCFTEST(PCF_USR)) /* Exec mode can halt */
#elif KLH10_CPU_KL || KLH10_CPU_KI
if (!PCFTEST(PCF_USR|PCF_PUB)) /* Only Kernel mode can halt */
#endif
{
cpu.mr_haltpc = cpu.mr_PC; /* Remember loc of the HALT instr */
PC_JUMP(e); /* Update PC as if jumped */
apr_halt(HALT_PROG); /* Halt processor! */
/* Never returns */
}
return i_muuo(op, ac, e);
}
/* DEC extended variants of JRST, never used on ITS or a single-section KL */
#if !KLH10_SYS_ITS && (KLH10_CPU_KS||KLH10_CPU_KLX)
/* XJRSTF (JRST 5,)
** Pretty much the same as JRSTF except the flags and PC come from
** a pair of memory locations. On the KS10 no section addressing
** is possible (wonder what happens if tried on a real KS10?)
**
** XJRSTF and XJEN don't save anything.
** A new PCS is loaded from the flag word only if a KLX and the new
** flags specify exec mode (PRM 2-66, 2nd sentence from bottom).
** The new flags are used verbatim, except for the same restrictions
** as JRSTF (that is, USER, UIO, PUBLIC flags are special-cased).
** (PRM 2-71)
** See dorstf() for more comments.
*/
insdef(ij_xjrstf)
{
register dw10_t dpcw;
vm_dread(e, dpcw); /* Fetch double-wd from E, E+1 (may pageflt) */
va_lfrword(e, LOGET(dpcw)); /* New PC from c(E+1) */
return IJ_DO_RSTF(HIGET(dpcw), e, TRUE); /* Use flags from c(E) */
}
/* XJEN (JRST 6,)
** See comments for XJRSTF -- essentially the same.
** To XJRSTF as JEN is to JRSTF, but only allowed in Exec mode.
** However, one special precaution is taken; the PCW at E, E+1 is fetched
** prior to restoring an interrupt level, to ensure any page fault
** happens before clobbering the PI status!
** This is why the XJRSTF code is duplicated, rather than calling
** it after dismissing the interrupt.
*/
insdef(ij_xjen)
{
register dw10_t dpcw;
#if KLH10_CPU_KS
if (PCFTEST(PCF_USR)) /* Ensure we're in exec mode */
#elif KLH10_CPU_KLX
if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */
|| (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB)))
#endif
return i_muuo(op, ac, e);
vm_dread(e, dpcw); /* Fetch double-wd from E, E+1 (may pageflt) */
pi_dismiss(); /* Tell PI to dismiss current int */
va_lfrword(e, LOGET(dpcw)); /* New PC from E+1 */
return IJ_DO_RSTF(HIGET(dpcw), e, TRUE); /* Use flags from E */
}
/* XPCW (JRST 7,)
** Note special precaution as for XJEN to ensure any page faults happen
** prior to changing flags or PC.
**
** PCS is saved in the flag word ONLY if old mode was exec (the flag
** test is on old flags, not new ones).
** No new PCS is set.
** The new flags are taken from the new flag word, subject to
** same restrictions as JRSTF. It doesn't appear that
** either PCP or PCU is specially set.
** PRM says XPCW should only be used as interrupt instr, but T20
** monitor does use it as regular instr (in SCHED).
** This code only implements its "regular" behavior; the KLH10
** PI interrupt code special-cases XPCW itself and never calls
** this routine.
*/
insdef(ij_xpcw)
{
register w10_t w;
register vaddr_t e2;
dw10_t dpcw;
#if KLH10_CPU_KS
if (PCFTEST(PCF_USR)) /* Ensure we're in exec mode */
#elif KLH10_CPU_KLX
if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */
|| (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB)))
#endif
return i_muuo(op, ac, e);
e2 = e;
va_add(e2, 2); /* Get E+2 */
vm_dread(e2, dpcw); /* Fetch double from E+2, E+3 (may pageflt) */
LRHSET(w, cpu.mr_pcflags, 0); /* Set up 1st word of PCW */
#if KLH10_EXTADR
if (!PCFTEST(PCF_USR)) /* If in exec mode */
RHSET(w, pag_pcsget()); /* then OK to add pager's PrevContextSection */
#endif
vm_write(e, w); /* Store in E */
PC_1TOWORD(w); /* Set up PC+1 word */
va_inc(e);
vm_write(e, w); /* Store in E+1 */
va_lfrword(e2, LOGET(dpcw)); /* New PC from E+3 */
return IJ_DO_RSTF(HIGET(dpcw), e2, FALSE); /* Use flags from E+2 */
}
/* SFM (JRST 14,)
** This is now legal in user mode, but the PCS info is only stored if in
** exec mode. (PRM 2-72)
** Additionally, PRM 2-73 says on an extended KL, SFM is only legal in
** NZ section. However, this was changed as of KL ucode 331 to
** allow 0-section as well, and there is no IO-legal test;
** PCS is still only saved if in exec mode, though.
*/
insdef(ij_sfm)
{
register w10_t w;
#if KLH10_CPU_KS /* KS10 requires exec mode (kernel) */
if (PCFTEST(PCF_USR)) /* Ensure we're in exec mode */
return i_muuo(op, ac, e);
#endif
/* Don't need to mung flags since not changing modes */
LRHSET(w, cpu.mr_pcflags, 0); /* Set up 1st word of PCW */
#if KLH10_EXTADR
if (!PCFTEST(PCF_USR)) /* If in exec mode, */
RHSET(w, pag_pcsget()); /* add PCS to the flag word */
#endif
vm_write(e, w); /* Store in E */
return PCINC_1; /* That's all, no jump! */
}
#if KLH10_CPU_KLX
/* XJRST (JRST 15,)
** This is yet another late addition to the KL that was never
** documented in the PRM. It seems to have been added as of ucode
** 301 and is used extensively in the T20 monitor.
** Basically appears to jump to c(E) rather than E, treating
** the contents of E as a full 30-bit global virtual address. It's
** not clear whether the high 6 bits matter, but I'll assume they are
** ignored.
** This also appears to be legal in any section, in any mode.
** Not a bad idea, actually.
*/
insdef(ij_xjrst)
{
register w10_t w;
register vaddr_t va;
w = vm_read(e); /* Fetch c(E) */
va_gfrword(va, w); /* Turn into a virtual address */
PC_JUMP(va); /* Jump there! */
return PCINC_0;
}
#endif /* KLX */
#endif /* !ITS && (KS || KLX) */
/* Stack instructions */
/* Note: on the KA10 the push and pop operations are done by
** adding or subtracting 1,,1 as a word entity (ie not independent halves).
** Also, there are no trap flags, so Pushdown Overflow is set instead.
** These actions are not yet coded for, to avoid clutter.
*/
/* Note special page map context references for stack instructions.
** These are so PXCT can work by twiddling the context pointers.
** For:
** Computing E - normal ea_calc() using XEA map
** R/W of c(E) for PUSH, POP - normal XRW map
** R/W of stack data - special XBRW map
*/
#define vm_stkread(a) (vm_pget(vm_xbrwmap((a), VMF_READ)))
#define vm_stkwrite(a, w) (vm_pset(vm_xbrwmap((a), VMF_WRITE), (w)))
#define vm_stkmap(a, f) vm_xbrwmap((a), (f))
/* No other special actions are needed for PXCT; the test for running
** extended is always made using PC section (regardless of context).
** However, on an extended KL Uhler claims stack references should
** always be made in the current context. What isn't clear is whether
** a KLX is expected to ignore the stack-context AC bit (12), or if it
** does undefined things as a result.
** For generality this code does implement stack reference mapping even
** on a KLX, which corresponds to the latter option. As long as the
** monitor only uses valid AC bit combinations we'll be fine.
**
** HOWEVER - it appears from the DFKED diagnostic that bit 12 DOES
** operate in a real KL and it affects both the test for PC section AND the
** mapping used for the stack pointer. Ugh!!!!
** Don't know yet whether it is used by a real monitor.
*/
insdef(i_push)
{
register w10_t w;
register vaddr_t sloc;
w = ac_get(ac);
#if KLH10_EXTADR
/* Determine if stack pointer is local or global */
if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) {
/* Global format */
op10m_inc(w); /* Increment entire word */
va_gfrword(sloc, w); /* Get global addr from wd */
vm_stkwrite(sloc, vm_read(e)); /* Push c(E) on stack */
} else
#endif
{
/* Local format */
RHSET(w, (RHGET(w)+1)&H10MASK); /* Increment RH only */
va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */
vm_stkwrite(sloc, vm_read(e)); /* Push c(E) on stack */
/* All mem refs won, safe to store AC and test for setting Trap 2 */
LHSET(w, (LHGET(w)+1)&H10MASK); /* Increment LH */
if (LHGET(w) == 0) /* If became 0, */
PCFTRAPSET(PCF_TR2); /* set Trap 2! */
}
ac_set(ac, w);
return PCINC_1;
}
insdef(i_pushj)
{
register w10_t pcw, w;
register vaddr_t sloc;
w = ac_get(ac);
PC_1WORD(pcw); /* Make PC+1 word */
#if KLH10_EXTADR
/* Determine if stack pointer is local or global */
if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) {
/* Global format */
op10m_inc(w); /* Increment entire word */
va_gfrword(sloc, w); /* Get global addr from wd */
vm_stkwrite(sloc, pcw); /* Push PC word on stack */
PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */
} else
#endif
{
/* Local format */
RHSET(w, (RHGET(w)+1)&H10MASK); /* Increment RH only */
va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */
vm_stkwrite(sloc, pcw); /* Push PC word on stack */
/* All mem refs won, safe to store AC and test for setting Trap 2 */
PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */
LHSET(w, (LHGET(w)+1)&H10MASK); /* Increment LH */
if (LHGET(w) == 0) /* If became 0, */
PCFTRAPSET(PCF_TR2); /* set Trap 2! */
}
ac_set(ac, w);
PC_JUMP(e); /* Jump to new PC */
return PCINC_0;
}
insdef(i_pop)
{
register w10_t w;
register vaddr_t sloc;
w = ac_get(ac);
#if KLH10_EXTADR
/* Determine if stack pointer is local or global */
if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) {
/* Global format */
va_gfrword(sloc, w); /* Get global addr from wd */
vm_write(e, vm_stkread(sloc)); /* Pop stack to c(E) */
op10m_dec(w); /* Decrement entire word */
} else
#endif
{
/* Local format */
va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */
vm_write(e, vm_stkread(sloc)); /* Pop stack to c(E) */
/* All mem refs won, safe to store AC and test for setting Trap 2 */
RHSET(w, (RHGET(w)-1)&H10MASK); /* Decrement RH only */
if (LHGET(w) == 0) { /* If decrement will wrap, */
PCFTRAPSET(PCF_TR2); /* set Trap 2! */
LHSET(w, H10MASK);
} else
LHSET(w, LHGET(w)-1); /* Decr LH, no mask needed */
}
ac_set(ac, w);
return PCINC_1;
}
insdef(i_popj)
{
register w10_t pcw, w;
register vaddr_t sloc;
w = ac_get(ac);
#if KLH10_EXTADR
/* Determine if stack pointer is local or global */
if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) {
/* Global format */
va_gfrword(sloc, w); /* Get global addr from wd */
pcw = vm_stkread(sloc); /* Pop PC word off stack */
op10m_dec(w); /* Decrement entire word */
} else
#endif
{
/* Local format */
va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */
pcw = vm_stkread(sloc); /* Pop PC word off stack */
/* All mem refs won, safe to store AC and test for setting Trap 2 */
RHSET(w, (RHGET(w)-1)&H10MASK); /* Decrement RH only */
if (LHGET(w) == 0) { /* If decrement will wrap, */
PCFTRAPSET(PCF_TR2); /* set Trap 2! */
LHSET(w, H10MASK);
} else
LHSET(w, LHGET(w)-1); /* Decr LH, no mask needed */
}
/* Build correct new PC from PC word popped off */
if (PC_ISEXT)
va_lfrword(e, pcw);
else va_lmake(e, PC_SECT, RHGET(pcw));
ac_set(ac, w);
PC_JUMP(e); /* Now jump to restored PC */
return PCINC_0;
}
insdef(i_adjsp)
{
register w10_t w;
register h10_t h;
w = ac_get(ac); /* Get stack pointer */
#if KLH10_EXTADR
/* Determine if stack pointer is local or global */
if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) {
/* Global format */
if (H10SIGN & va_insect(e)) { /* Negative adjustment? */
register w10_t wadj;
LRHSET(wadj, H10MASK, va_insect(e)); /* Set up word */
op10m_add(w, wadj); /* Add negative adj */
} else
op10m_addi(w, va_insect(e)); /* Can just add immediately */
} else
#endif
{
/* Local format */
register h10_t adj = va_insect(e);
RHSET(w, (RHGET(w)+adj)&H10MASK); /* Add offset to RH */
if ((h = LHGET(w)+adj) & H10SIGN) { /* New count negative? */
if ((adj & H10SIGN) && (LHGET(w) & H10SIGN)==0)
PCFTRAPSET(PCF_TR2); /* Neg E made cnt pos -> neg */
} else { /* New count positive */
if ((adj & H10SIGN)==0 && (LHGET(w) & H10SIGN))
PCFTRAPSET(PCF_TR2); /* Pos E made cnt neg -> pos */
}
LHSET(w, (h & H10MASK)); /* Store new count */
}
ac_set(ac, w);
return PCINC_1;
}