mirror of
https://github.com/prirun/p50em.git
synced 2026-01-21 17:55:28 +00:00
5997 lines
159 KiB
C
5997 lines
159 KiB
C
/* Pr1me Computer emulator, Jim Wilcoxson (jim@meritnet.com), April 4, 2005
|
|
Copyright (C) 2005, Jim Wilcoxson (jim@meritnet.com). All Rights Reserved.
|
|
|
|
Restores a Prime R-mode .save image from stdin to memory and
|
|
emulates execution.
|
|
|
|
PLEASE NOTE: this is a very rough prototype still in development.
|
|
The main goal for the prototype is to get an understanding of the
|
|
kinds of design issues faced by an emulator, before doing a "real"
|
|
Prime 50-series emulator.
|
|
|
|
You are welcome to pass this along to friends for fun and
|
|
amusement, but please don't publish it. Comments, suggestions,
|
|
corrections, and general notes that you're interested in a Prime
|
|
emulation project are also welcome and appreciated.
|
|
|
|
Usage:
|
|
|
|
$ ./em <smad.save 2>/dev/null
|
|
|
|
Lots of instruction details are spewed to stderr.
|
|
|
|
|
|
Left to do (way more to do ... this just gives an idea):
|
|
|
|
- only runs on a big-endian machine, like the Prime
|
|
|
|
- svc doesn't handle alternate returns, LOC(blah) args might not be
|
|
handled correctly, and it doesn't handle missing or extra arguments
|
|
correctly (by looking for the terminating zero)
|
|
|
|
- not all C-bit, L-bit, and condition code updates are correct
|
|
|
|
- restricted-mode instruction checking is missing
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <setjmp.h>
|
|
#include <sys/time.h>
|
|
#include "syscom/keys.ins.cc"
|
|
#include "syscom/errd.ins.cc"
|
|
|
|
/* Prime CPU registers are mapped to memory locations 0-'37, but only
|
|
0-7 are accessible in SR user mode. In VI user mode, locations
|
|
0-'17 are trapped and map to the live register file (p 5-17, Sys Arch),
|
|
though only 0-7 are accessible in user mode.
|
|
|
|
Locations '40-'57 are reserved for 8 DMC channels, 2 words each.
|
|
Locations '60-'77 are interrupt vectors
|
|
Locations '100-'177 are for external device interrupts
|
|
see p. A-8 of Sys Arch
|
|
*/
|
|
|
|
#include "regs.h"
|
|
typedef unsigned int ea_t;
|
|
typedef unsigned int pa_t;
|
|
|
|
/* the live program counter register is aka microcode scratch register TR7 */
|
|
|
|
#define RP regs.sym.tr7
|
|
#define RPH regs.u16[14]
|
|
#define RPL regs.u16[15]
|
|
|
|
#define SETCC_A \
|
|
crs[KEYS] &= ~0300; \
|
|
if (crs[A] == 0) \
|
|
crs[KEYS] |= 0100; \
|
|
else if (*(short *)(crs+A) < 0) \
|
|
crs[KEYS] |= 0200;
|
|
|
|
#define SETCC_X \
|
|
crs[KEYS] &= ~0300; \
|
|
if (crs[X] == 0) \
|
|
crs[KEYS] |= 0100; \
|
|
else if (*(short *)(crs+X) < 0) \
|
|
crs[KEYS] |= 0200;
|
|
|
|
#define SETCC_L \
|
|
crs[KEYS] &= ~0300; \
|
|
if (*(int *)(crs+L) == 0) \
|
|
crs[KEYS] |= 0100; \
|
|
else if (*(int *)(crs+L) < 0) \
|
|
crs[KEYS] |= 0200;
|
|
|
|
#define SETCC_LE \
|
|
crs[KEYS] &= ~0300; \
|
|
if (*(int *)(crs+L) == 0 && *(int *)(crs+E) == 0) \
|
|
crs[KEYS] |= 0100; \
|
|
else if (*(int *)(crs+L) < 0) \
|
|
crs[KEYS] |= 0200;
|
|
|
|
/* NOTE: in previous versions, exponent must be zero for 0.0, but DIAG
|
|
test CPU.FLOAT.V considers a zero fraction and non-zero exponent to
|
|
also be 0.0 */
|
|
|
|
#define SETCC_F \
|
|
crs[KEYS] &= ~0300; \
|
|
if (*(short *)(crs+FLTH) < 0) \
|
|
crs[KEYS] |= 0200; \
|
|
else if (*(int *)(crs+FLTH) == 0) \
|
|
crs[KEYS] |= 0100;
|
|
|
|
#define SETCC_D SETCC_F
|
|
|
|
/* XEXPC is a dummy to indicate that the C-bit may not be set correctly */
|
|
|
|
#define XEXPC(onoff) \
|
|
if ((onoff)) crs[KEYS] |= 0100000; \
|
|
else crs[KEYS] &= 077777
|
|
|
|
#define EXPC(onoff) \
|
|
if ((onoff)) crs[KEYS] |= 0100000; \
|
|
else crs[KEYS] &= 077777
|
|
|
|
#define SETC crs[KEYS] |= 0100000
|
|
#define CLEARC crs[KEYS] &= 077777
|
|
|
|
/* XSETL is a dummy to indicate that the L-bit may not be set correctly */
|
|
|
|
#define XSETL(onoff) \
|
|
if ((onoff)) crs[KEYS] |= 020000; \
|
|
else crs[KEYS] &= ~020000;
|
|
|
|
#define SETL(onoff) \
|
|
if ((onoff)) crs[KEYS] |= 020000; \
|
|
else crs[KEYS] &= ~020000;
|
|
|
|
/* macro for restricted instructions */
|
|
|
|
#define RESTRICT() if (RP & RINGMASK32) fault(RESTRICTFAULT, 0, 0);
|
|
|
|
|
|
/* Table for unusual instructions that aren't implemented but we want to
|
|
print something when they're encountered */
|
|
|
|
unsigned short gen0tab[] = {
|
|
000302, /* SSSN? (store system serial number); occurs early in hard drive boot */
|
|
001172, /* ? */
|
|
000764, /* ? */
|
|
000615, /* ITLB */
|
|
001367, /* ? */
|
|
000503, /* EMCM */
|
|
000501, /* LMCM */
|
|
001304, /* MDEI */
|
|
001305, /* MDII */
|
|
001324, /* MDIW */
|
|
001306, /* MDRS */
|
|
001307, /* MDWC */
|
|
000021, /* RMC */
|
|
0101200, /* SMCS */
|
|
000311, /* VIFY */
|
|
001113, /* XVFY */
|
|
000411}; /* CAI */
|
|
|
|
#define GEN0TABSIZE sizeof(gen0tab)/sizeof(unsigned short)
|
|
|
|
char gen0nam[][5] = {
|
|
"302",
|
|
"1172",
|
|
"764",
|
|
"ITLB",
|
|
"1367",
|
|
"EMCM",
|
|
"LMCM",
|
|
"MDEI",
|
|
"MDII",
|
|
"MDIW",
|
|
"MDRS",
|
|
"MDWC",
|
|
"RMC",
|
|
"SMCS",
|
|
"VIFY",
|
|
"XVFY",
|
|
"CAI"};
|
|
|
|
|
|
/* trace flags to control various aspects of emulator tracing:
|
|
|
|
T_EAR trace R-mode effective address calculation
|
|
T_EAV trace V-mode effective address calculation
|
|
T_EAI trace I-mode effective address calculation
|
|
T_FLOW instruction summary
|
|
T_INST detailed instruction trace
|
|
T_MODE trace CPU mode changes
|
|
T_EAAP AP effective address calculation
|
|
T_DIO disk I/O
|
|
T_MAP segmentation
|
|
T_PCL PCL instructions
|
|
T_FAULT Faults
|
|
T_PX Process exchange
|
|
*/
|
|
|
|
#define TB_EAR 0x00000001
|
|
#define TB_EAV 0x00000002
|
|
#define TB_EAI 0x00000004
|
|
#define TB_INST 0x00000008
|
|
#define TB_FLOW 0x00000010
|
|
#define TB_MODE 0x00000020
|
|
#define TB_EAAP 0x00000040
|
|
#define TB_DIO 0x00000080
|
|
#define TB_MAP 0x00000100
|
|
#define TB_PCL 0x00000200
|
|
#define TB_FAULT 0x00000400
|
|
#define TB_PX 0x00000800
|
|
|
|
#define T_EAR (traceflags & TB_EAR)
|
|
#define T_EAV (traceflags & TB_EAV)
|
|
#define T_EAI (traceflags & TB_EAI)
|
|
#define T_INST (traceflags & TB_INST)
|
|
#define T_FLOW (traceflags & TB_FLOW)
|
|
#define T_MODE (traceflags & TB_MODE)
|
|
#define T_EAAP (traceflags & TB_EAAP)
|
|
#define T_DIO (traceflags & TB_DIO)
|
|
#define T_MAP (traceflags & TB_MAP)
|
|
#define T_PCL (traceflags & TB_PCL)
|
|
#define T_FAULT (traceflags & TB_FAULT)
|
|
#define T_PX (traceflags & TB_PX)
|
|
|
|
int traceflags=0; /* each bit is a trace flag */
|
|
|
|
int intvec=0;
|
|
|
|
/* NOTE: Primos II gives "NOT FOUND" on startup 2460 if sense switches
|
|
are set to 014114. But DIAGS like this sense switch setting. :( */
|
|
|
|
unsigned short sswitch = 0;
|
|
|
|
unsigned short cpuid = 0;
|
|
|
|
unsigned long instcount=0;
|
|
|
|
jmp_buf jmpbuf;
|
|
|
|
/* define a 4 million 16-bit word system memory; later systems seem to
|
|
have had more memory, like 32MB, but I'm not sure how this was
|
|
implemented since it would require more bits in the page map entry
|
|
for the physical page number. If the page size was made larger,
|
|
like 8K instead of 2K, the number of entries in a page table would
|
|
change from 64 to 16, which also seems drastic... */
|
|
|
|
#if 0
|
|
#define MEMSIZE 07776*64*1024
|
|
#else
|
|
#define MEMSIZE 4*1024*1024
|
|
#endif
|
|
unsigned short mem[MEMSIZE]; /* system's physical memory */
|
|
|
|
#define MAKEVA(seg,word) (((int)(seg))<<16) | (word)
|
|
|
|
/* returns the incremented value of a virtual address, wrapping to word
|
|
zero at the end of a segment (word portion = 0177777) */
|
|
|
|
#define INCVA(ea,n) (((ea) & 0xFFFF0000) | ((ea)+(n)) & 0xFFFF)
|
|
|
|
unsigned int bitmask32[33] = {0,
|
|
0x80000000, 0x40000000, 0x20000000, 0x10000000,
|
|
0x08000000, 0x04000000, 0x02000000, 0x01000000,
|
|
0x00800000, 0x00400000, 0x00200000, 0x00100000,
|
|
0x00080000, 0x00040000, 0x00020000, 0x00010000,
|
|
0x00008000, 0x00004000, 0x00002000, 0x00001000,
|
|
0x00000800, 0x00000400, 0x00000200, 0x00000100,
|
|
0x00000080, 0x00000040, 0x00000020, 0x00000010,
|
|
0x00000008, 0x00000004, 0x00000002, 0x00000001};
|
|
|
|
unsigned int bitmask16[17] = {0,
|
|
0x8000, 0x4000, 0x2000, 0x1000,
|
|
0x0800, 0x0400, 0x0200, 0x0100,
|
|
0x0080, 0x0040, 0x0020, 0x0010,
|
|
0x0008, 0x0004, 0x0002, 0x0001};
|
|
|
|
unsigned int prevpc; /* backed program counter */
|
|
|
|
unsigned short amask; /* address mask */
|
|
#define FAULTMASK32 0x80000000 /* fault bit */
|
|
#define RINGMASK32 0x60000000 /* ring bits */
|
|
#define EXTMASK32 0x10000000 /* E-bit */
|
|
#define SEGMASK32 0x0FFF0000 /* segment number */
|
|
#define RINGMASK16 0x6000 /* ring bits */
|
|
#define EXTMASK16 0x1000 /* E-bit */
|
|
|
|
/* Fault/interrupt vectors */
|
|
|
|
#define RESTRICTFAULT 062
|
|
#define PROCESSFAULT 063
|
|
#define PAGEFAULT 064
|
|
#define SVCFAULT 065
|
|
#define UIIFAULT 066
|
|
#define PARITYCHECK 067
|
|
#define MACHCHECK 070
|
|
#define MISSMEMCHECK 071
|
|
#define ILLINSTFAULT 072
|
|
#define ACCESSFAULT 073
|
|
#define ARITHFAULT 074
|
|
#define STACKFAULT 075
|
|
#define SEGFAULT 076
|
|
#define POINTERFAULT 077
|
|
|
|
int verbose;
|
|
int domemdump; /* -memdump arg */
|
|
int boot; /* true if reading a boot record */
|
|
|
|
#define DTAR(ea) (((ea)>>26) & 3)
|
|
#define SEGNO(ea) (((ea)>>16) & 07777)
|
|
#define PAGENO(ea) (((ea)>>10) & 077)
|
|
|
|
/* intended memory access types:
|
|
1 = PCL (PACC)
|
|
2 = read (RACC)
|
|
3 = write (WACC)
|
|
4 = execute (XACC)
|
|
*/
|
|
#define PACC 0
|
|
#define RACC 2
|
|
#define WACC 3
|
|
#define XACC 4
|
|
|
|
void fault(unsigned short fvec, unsigned short fcode, ea_t faddr);
|
|
|
|
|
|
/* maps a Prime 28-bit virtual address to a physical memory
|
|
address, checks access, returns actual access (for PCL)
|
|
May cause:
|
|
- segment fault if segment number is too big
|
|
- segment fault if segment's fault bit is set
|
|
- access fault if intended access isn't permitted
|
|
- page fault if page isn't resident
|
|
*/
|
|
|
|
pa_t mapva(ea_t ea, short intacc, short *access) {
|
|
short relseg,seg,nsegs,ring;
|
|
unsigned short pte;
|
|
unsigned int dtar,sdw,staddr,ptaddr,pmaddr;
|
|
pa_t pa;
|
|
|
|
seg = SEGNO(ea);
|
|
if ((seg > 0 && (crs[MODALS] & 4)) || (seg == 0 && (crs[MODALS] & 020))) {
|
|
dtar = *(unsigned int *)(crs+DTAR0-2*DTAR(ea)); /* get dtar register */
|
|
nsegs = 1024-(dtar>>22);
|
|
relseg = seg & 0x3FF; /* segment within segment table */
|
|
if (T_MAP) fprintf(stderr,"MAP: ea=%o/%o, seg=%o, dtar=%o, nsegs=%d, relseg=%d, page=%d\n", ea>>16, ea&0xFFFF, seg, dtar, nsegs, relseg, PAGENO(ea));
|
|
if (relseg >= nsegs)
|
|
fault(SEGFAULT, 1, ea); /* fcode = segment too big */
|
|
staddr = (dtar & 0x003F0000) | ((dtar & 0x7FFF)<<1);
|
|
sdw = *(unsigned int *)(mem+staddr+relseg*2);
|
|
if (T_MAP) fprintf(stderr," staddr=%o, sdw=%o\n", staddr, sdw);
|
|
if (sdw & 0x8000)
|
|
fault(SEGFAULT, 2, ea); /* fcode = sdw fault bit set */
|
|
|
|
/* XXX: should ring be weakened with ea ring? */
|
|
|
|
ring = (RPH>>13) & 3; /* current ring */
|
|
if (ring == 0)
|
|
*access = 7;
|
|
else
|
|
*access = (sdw >> (3-ring)*3+6) & 7;
|
|
if (((intacc & *access) != intacc) || (intacc == PACC && ((*access & 3) == 0)))
|
|
fault(ACCESSFAULT, 0, ea);
|
|
ptaddr = (((sdw & 0x3F)<<10) | (sdw>>22)) << 6;
|
|
pmaddr = ptaddr + PAGENO(ea);
|
|
pte = mem[pmaddr];
|
|
if (T_MAP) fprintf(stderr," ptaddr=%o, pmaddr=%o, pte=%o\n", ptaddr, pmaddr, pte);
|
|
if (!(pte & 0x8000))
|
|
fault(PAGEFAULT, 0, ea);
|
|
mem[pmaddr] |= 020000; /* set referenced bit */
|
|
if (intacc == WACC)
|
|
mem[pmaddr] &= ~020000; /* reset unmodified bit */
|
|
pa = ((pte & 0xFFF) << 10) | (ea & 0x3FF);
|
|
} else {
|
|
pa = ea & 0x3FFFFF;
|
|
}
|
|
if (pa <= MEMSIZE)
|
|
return pa;
|
|
printf(" map: Memory address %o (%o/%o) is out of range!\n", ea, ea>>16, ea & 0xffff);
|
|
exit(1);
|
|
/* NOTE: should we take a fault here or return zeroes instead? */
|
|
}
|
|
|
|
|
|
/* Can V-mode do JMP# 4 to start executing from the register file?
|
|
Might need to "or" 0x80000000 with PBH to indicate this?? */
|
|
|
|
unsigned short get16(ea_t ea) {
|
|
pa_t pa;
|
|
unsigned short access;
|
|
|
|
/* check for live register access */
|
|
|
|
if (ea & 0x80000000 || (!(crs[KEYS] & 010000) && (ea & 0xFFFF) <= 037)) {
|
|
ea = ea & 0xFFFF;
|
|
if (ea < 7)
|
|
return crs[memtocrs[ea]];
|
|
if (ea == 7) /* PC */
|
|
return RPL;
|
|
RESTRICT();
|
|
if (ea <= 017) /* CRS */
|
|
return crs[memtocrs[ea]];
|
|
if (ea <= 037) /* DMX */
|
|
return regs.sym.regdmx[((ea & 036) << 1) | (ea & 1)];
|
|
printf(" Live register address %o too big!\n", ea);
|
|
fatal(NULL);
|
|
}
|
|
return mem[mapva(ea, RACC, &access)];
|
|
}
|
|
|
|
unsigned int get32(ea_t ea) {
|
|
pa_t pa;
|
|
unsigned short access;
|
|
unsigned short m[2];
|
|
|
|
pa = mapva(ea, RACC, &access);
|
|
|
|
if ((pa & 01777) <= 01776)
|
|
return *(unsigned int *)(mem+pa);
|
|
else {
|
|
m[0] = mem[pa];
|
|
m[1] = get16(INCVA(ea,1));
|
|
return *(unsigned int *)m;
|
|
}
|
|
}
|
|
|
|
double get64(ea_t ea) {
|
|
pa_t pa;
|
|
unsigned short access;
|
|
unsigned short m[4];
|
|
|
|
pa = mapva(ea, RACC, &access);
|
|
if ((pa & 01777) <= 01774)
|
|
return *(double *)(mem+pa);
|
|
else {
|
|
m[0] = mem[pa];
|
|
m[1] = get16(INCVA(ea,1));
|
|
m[2] = get16(INCVA(ea,2));
|
|
m[3] = get16(INCVA(ea,3));
|
|
return *(double *)m;
|
|
}
|
|
}
|
|
|
|
|
|
put16(unsigned short value, ea_t ea) {
|
|
pa_t pa;
|
|
unsigned short access;
|
|
|
|
if (ea & 0x80000000) { /* flag for live register address */
|
|
ea = ea & 0x7FFFFFFF;
|
|
if (ea < 7)
|
|
crs[memtocrs[ea]] = value;
|
|
else if (ea == 7) {
|
|
RPL = value;
|
|
} else {
|
|
RESTRICT();
|
|
if (ea <= 017) /* CRS */
|
|
crs[memtocrs[ea]] = value;
|
|
else if (ea <= 037) /* DMX */
|
|
regs.sym.regdmx[((ea & 036) << 1) | (ea & 1)] = value;
|
|
else {
|
|
printf(" Live register store address %o too big!\n", ea);
|
|
exit(1);
|
|
}
|
|
}
|
|
} else {
|
|
pa = mapva(ea, WACC, &access);
|
|
mem[pa] = value;
|
|
}
|
|
}
|
|
|
|
put32(unsigned int value, ea_t ea) {
|
|
pa_t pa;
|
|
unsigned short access;
|
|
unsigned short *m;
|
|
|
|
pa = mapva(ea, WACC, &access);
|
|
if ((pa & 01777) <= 01776)
|
|
*(unsigned int *)(mem+pa) = value;
|
|
else {
|
|
m = (void *)&value;
|
|
mem[pa] = m[0];
|
|
put16(m[1], INCVA(ea,1));
|
|
}
|
|
}
|
|
|
|
put64(double value, ea_t ea) {
|
|
pa_t pa;
|
|
unsigned short access;
|
|
unsigned short *m;
|
|
|
|
pa = mapva(ea, WACC, &access);
|
|
if ((pa & 01777) <= 01774)
|
|
*(double *)(mem+pa) = value;
|
|
else {
|
|
m = (void *)&value;
|
|
mem[pa] = m[0];
|
|
put16(m[1], INCVA(ea,1));
|
|
put16(m[2], INCVA(ea,2));
|
|
put16(m[3], INCVA(ea,3));
|
|
}
|
|
}
|
|
|
|
|
|
void calf(ea_t ea) {
|
|
ea_t pcbp, stackfp, csea;
|
|
unsigned short first,next,last,this;
|
|
unsigned short cs[6];
|
|
|
|
pcbp = *(ea_t *)(crs+OWNER); /* my pcb pointer */
|
|
|
|
/* make sure the concealed stack isn't empty or full */
|
|
|
|
first = get16(pcbp+PCBCSFIRST);
|
|
next = get16(pcbp+PCBCSNEXT);
|
|
last = get16(pcbp+PCBCSLAST);
|
|
if (T_FAULT) fprintf(stderr,"CALF: first=%o, next=%o, last=%o\n", first, next, last);
|
|
if (next == first)
|
|
this = last;
|
|
else
|
|
this = next-6;
|
|
csea = MAKEVA(crs[OWNERH], this);
|
|
if (T_FAULT) fprintf(stderr,"CALF: cs frame is at %o/%o\n", csea>>16, csea&0xFFFF);
|
|
|
|
/* make sure ecb specifies zero arguments */
|
|
|
|
if (get16(ea+5) !=0) {
|
|
printf("CALF ecb at %o/%o has arguments!\n", ea>>16, ea&0xFFFF);
|
|
fatal(NULL);
|
|
}
|
|
|
|
pcl(ea);
|
|
|
|
/* get the concealed stack entries and adjust the new stack frame */
|
|
|
|
*(unsigned int *)(cs+0) = get32(csea+0);
|
|
*(double *)(cs+2) = get64(csea+2);
|
|
|
|
if (T_FAULT) fprintf(stderr,"CALF: cs entry: retpb=%o/%o, retkeys=%o, fcode=%o, faddr=%o/%o\n", cs[0], cs[1], cs[2], cs[3], cs[4], cs[5]);
|
|
|
|
stackfp = *(unsigned int *)(crs+SB);
|
|
put16(1, stackfp+0); /* flag it as CALF frame */
|
|
put32(*(unsigned int *)(cs+0), stackfp+2); /* return PB */
|
|
put16(cs[2], stackfp+8); /* return keys */
|
|
put16(cs[3], stackfp+10); /* fault code */
|
|
put32(*(unsigned int *)(cs+4), stackfp+11); /* fault address */
|
|
|
|
/* pop the concealed stack */
|
|
|
|
put16(this, pcbp+PCBCSNEXT);
|
|
}
|
|
|
|
|
|
void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
|
ea_t pcbp, pxfvec, csea;
|
|
unsigned short first, next, last;
|
|
unsigned short m;
|
|
unsigned short ring;
|
|
ea_t faultrp;
|
|
|
|
if (fvec == PROCESSFAULT || fvec == SVCFAULT || fvec == ARITHFAULT)
|
|
faultrp = RP;
|
|
else
|
|
faultrp = prevpc;
|
|
|
|
/* save RP and keys in regfile */
|
|
|
|
regs.sym.pswpb = faultrp;
|
|
regs.sym.pswkeys = crs[KEYS];
|
|
|
|
if (T_FAULT) printf("#%d: fault '%o, fcode=%o, faddr=%o/%o, faultrp=%o/%o\n", instcount, fvec, fcode, faddr>>16, faddr&0xFFFF, faultrp>>16, faultrp&0xFFFF);
|
|
if (T_FAULT) fprintf(stderr,"fault '%o, fcode=%o, faddr=%o/%o, faultrp=%o/%o\n", fvec, fcode, faddr>>16, faddr&0xFFFF, faultrp>>16, faultrp&0xFFFF);
|
|
crs[FCODE] = fcode;
|
|
*(unsigned int *)(crs+FADDR) = faddr;
|
|
|
|
if (crs[MODALS] & 010) { /* process exchange is enabled */
|
|
pcbp = *(ea_t *)(crs+OWNER);
|
|
if (fvec == PROCESSFAULT || fvec == ACCESSFAULT || fvec == STACKFAULT || fvec == SEGFAULT)
|
|
pxfvec = get32(pcbp+PCBFVR0); /* use R0 handler */
|
|
else if (fvec == PAGEFAULT)
|
|
pxfvec = get32(pcbp+PCBFVPF);
|
|
else {
|
|
ring = (RPH>>13) & 3; /* use current ring handler */
|
|
pxfvec = get32(pcbp+PCBFVEC+2*ring);
|
|
}
|
|
|
|
/* push a concealed stack entry */
|
|
|
|
first = get16(pcbp+PCBCSFIRST);
|
|
next = get16(pcbp+PCBCSNEXT);
|
|
last = get16(pcbp+PCBCSLAST);
|
|
if (T_FAULT) fprintf(stderr,"fault: PX enabled, pcbp=%o/%o, cs first=%o, next=%o, last=%o\n", pcbp>>16, pcbp&0xFFFF, first, next, last);
|
|
if (next > last) {
|
|
if (T_FAULT) fprintf(stderr, "CALF: Concealed stack wraparound to first");
|
|
next = first;
|
|
}
|
|
csea = MAKEVA(crs[OWNERH], next);
|
|
put32(faultrp, csea);
|
|
put16(crs[KEYS], csea+2);
|
|
put16(fcode, csea+3);
|
|
put32(faddr, csea+4);
|
|
put16(next+6, pcbp+PCBCSNEXT);
|
|
if (T_FAULT) fprintf(stderr,"fault: updated cs next=%o\n", get16(pcbp+PCBCSNEXT));
|
|
|
|
/* update RP to jump to the fault vector in the fault table */
|
|
|
|
RP = pxfvec + (fvec-062)*4;
|
|
crs[KEYS] = 014000; /* V-mode */
|
|
|
|
if (T_FAULT) fprintf(stderr, "fault: jumping to fault table entry at RP=%o/%o\n", RPH, RPL);
|
|
|
|
} else { /* process exchange is disabled */
|
|
/* need to check for standard/vectored interrupt mode here... */
|
|
m = get16(fvec);
|
|
if (m != 0) {
|
|
if (1 || T_FLOW) fprintf(stderr," JST* '%o [%o]\n", fvec, m);
|
|
put16(faultrp & 0xFFFF, m);
|
|
RP = m;
|
|
RPL++;
|
|
} else {
|
|
printf("#%d: fault '%o, fcode=%o, faddr=%o/%o, faultrp=%o/%o\n", instcount, fvec, fcode, faddr>>16, faddr&0xFFFF, faultrp>>16, faultrp&0xFFFF);
|
|
fatal("Fault vector is zero, process exchange is disabled.");
|
|
}
|
|
}
|
|
|
|
longjmp(jmpbuf, 1);
|
|
fatal("fault: returned after longjmp\n");
|
|
}
|
|
|
|
|
|
fatal(char *msg) {
|
|
printf("Fatal error: instruction #%d at %o/%o: %o %o\n", instcount, prevpc >> 16, prevpc & 0xFFFF, get16(prevpc), get16(prevpc+1));
|
|
if (msg)
|
|
printf("%s\n", msg);
|
|
printf("keys = %o\n", crs[KEYS]);
|
|
/* should do a register dump here... */
|
|
exit(1);
|
|
}
|
|
|
|
/* I/O device map table, containing function pointers to handle device I/O */
|
|
|
|
#include "emdev.h"
|
|
|
|
void (*devmap[64])(short, short, short) = {
|
|
0,0,0,0,devasr,0,0,0,
|
|
0,0,0,devmt,devmt,0,0,0,
|
|
devcp,0,0,0,0,0,devdisk,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0};
|
|
|
|
|
|
/* read a short (16-bit) integer in big-endian from stdin */
|
|
|
|
unsigned short readshort () {
|
|
|
|
return getchar()<<8 | getchar();
|
|
}
|
|
|
|
|
|
/* set new processor keys */
|
|
|
|
newkeys (unsigned short new) {
|
|
|
|
switch ((new & 016000) >> 10) {
|
|
case 0: /* 16S */
|
|
if (T_MODE) fprintf(stderr,"Entering 16S mode, keys=%o\n", new);
|
|
amask = 037777;
|
|
break;
|
|
case 1: /* 32S */
|
|
if (T_MODE) fprintf(stderr,"Entering 32S mode, keys=%o\n", new);
|
|
amask = 077777;
|
|
break;
|
|
case 2: /* 64R */
|
|
if (T_MODE) fprintf(stderr,"Entering 64R mode, keys=%o\n", new);
|
|
amask = 0177777;
|
|
break;
|
|
case 3: /* 32R */
|
|
if (T_MODE) fprintf(stderr,"Entering 32R mode, keys=%o\n", new);
|
|
amask = 077777;
|
|
break;
|
|
case 4: /* 32I */
|
|
if (T_MODE) fprintf(stderr,"Entering 32I mode, keys=%o\n", new);
|
|
amask = 0177777;
|
|
break;
|
|
case 6: /* 64V */
|
|
if (T_MODE) fprintf(stderr,"Entering 64V mode, keys=%o\n", new);
|
|
amask = 0177777;
|
|
break;
|
|
default: /* invalid */
|
|
printf("Invalid CPU mode: %o\n", new);
|
|
fatal(NULL);
|
|
}
|
|
crs[KEYS] = new;
|
|
}
|
|
|
|
|
|
|
|
/* NOTE: This code is untested! Unclear whether RPL (advanced) or
|
|
prevpc (backed) should be used for address calculations... */
|
|
|
|
ea_t ea16s (unsigned short inst, short i, short x) {
|
|
|
|
unsigned short ea,m;
|
|
|
|
if (inst & 001000)
|
|
ea = (RPL & 037000) | (inst & 0777); /* current sector */
|
|
else
|
|
ea = (inst & 0777); /* sector 0 */
|
|
while (1) {
|
|
if (x) /* indexed */
|
|
ea += crs[X];
|
|
if (!i) /* not indirect */
|
|
break;
|
|
/* NOTE: this test is already in get16... */
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
i = m & 0100000;
|
|
x = m & 040000;
|
|
ea = m & 037777; /* go indirect */
|
|
}
|
|
if (ea < 040) /* flag live register ea */
|
|
return ea | 0x80000000;
|
|
return ea;
|
|
}
|
|
|
|
|
|
/* NOTE: This code is untested! */
|
|
|
|
ea_t ea32s (unsigned short inst, short i, short x) {
|
|
|
|
unsigned short ea,m;
|
|
|
|
if (inst & 001000)
|
|
ea = (RPL & 077000) | (inst & 0777); /* current sector */
|
|
else {
|
|
ea = (inst & 0777); /* sector 0 */
|
|
if (ea < 0100 && x) { /* preindex by X */
|
|
ea += crs[X];
|
|
x = 0;
|
|
}
|
|
}
|
|
while (i) {
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
i = m & 0100000;
|
|
ea = m & 077777; /* go indirect */
|
|
}
|
|
if (x) /* postindex */
|
|
ea += crs[X];
|
|
ea &= amask;
|
|
if (ea < 040) /* flag live register ea */
|
|
return ea | 0x80000000;
|
|
return ea;
|
|
}
|
|
|
|
|
|
/* NOTE: the difference between 32R and 64R, besides the extra address
|
|
bit, is that 32R indirect words have an indirect bit for multi-level
|
|
indirects */
|
|
|
|
ea_t ea32r64r (ea_t earp, unsigned short inst, short i, short x, short *opcode) {
|
|
|
|
short class;
|
|
unsigned short ea,m,rpl;
|
|
|
|
rpl = earp;
|
|
if (T_EAR) fprintf(stderr," ea32r64r: i=%o, x=%o\n", i!= 0, x!=0);
|
|
if (inst & 001000) /* sector bit 7 set? */
|
|
if ((inst & 0760) != 0400) { /* PC relative? */
|
|
ea = RPL + (((short) (inst << 7)) >> 7); /* yes, sign extend D */
|
|
if (T_EAR) fprintf(stderr," PC relative, P=%o, new ea=%o\n", rpl, ea);
|
|
}
|
|
else
|
|
goto special; /* special cases */
|
|
else {
|
|
ea = (inst & 0777); /* sector 0 */
|
|
if (T_EAR) fprintf(stderr," Sector 0, new ea=%o\n", ea);
|
|
if (ea < 0100 && x) { /* preindex by X */
|
|
if (T_EAR) fprintf(stderr," Preindex, ea=%o, X='%o/%d\n", ea, crs[X], *(short *)(crs+X));
|
|
ea += crs[X];
|
|
if (T_EAR) fprintf(stderr," Preindex, new ea=%o\n", ea);
|
|
x = 0;
|
|
}
|
|
}
|
|
while (i) {
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
if (T_EAR) fprintf(stderr," Indirect, old ea=%o, [ea]=%o\n", ea, m);
|
|
if ((crs[KEYS] & 016000) == 06000)
|
|
i = m & 0100000;
|
|
else
|
|
i = 0;
|
|
ea = m & amask; /* go indirect */
|
|
if (T_EAR) fprintf(stderr," Indirect, new i=%d, new ea=%o\n", i!=0, ea);
|
|
}
|
|
if (x) {
|
|
if (T_EAR) fprintf(stderr," Postindex, old ea=%o, X='%o/%d\n", ea, crs[X], *(short *)(crs+X));
|
|
ea += crs[X];
|
|
if (T_EAR) fprintf(stderr," Postindex, new ea=%o\n", ea);
|
|
}
|
|
ea &= amask;
|
|
if (ea < 040) /* flag live register ea */
|
|
return ea | 0x80000000;
|
|
return ea;
|
|
|
|
special:
|
|
class = inst & 3; /* class bits = 15 & 16 */
|
|
*opcode = *opcode | ((inst >> 2) & 3); /* opcode extension */
|
|
if (T_EAR) fprintf(stderr," special, new opcode=%5#0o, class=%d\n", *opcode, class);
|
|
|
|
if (class < 2) { /* class 0/1 */
|
|
ea = get16(RPL++); /* get A from next word */
|
|
if (T_EAR) fprintf(stderr," Class %d, new ea=%o\n", class, ea);
|
|
if (class == 1)
|
|
ea += crs[S];
|
|
if (x) {
|
|
if (T_EAR) fprintf(stderr," Preindex, ea=%o, X='%o/%d\n", ea, crs[X], *(short *)(crs+X));
|
|
ea += crs[X];
|
|
if (T_EAR) fprintf(stderr," Preindex, new ea=%o\n", ea);
|
|
}
|
|
while (i) {
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
if (T_EAR) fprintf(stderr," Indirect, old ea=%o, [ea]=%o\n", ea, m);
|
|
if ((crs[KEYS] & 016000) == 06000)
|
|
i = m & 0100000;
|
|
else
|
|
i = 0;
|
|
ea = m & amask;
|
|
if (T_EAR) fprintf(stderr," Indirect, new i=%d, new ea=%o\n", i!=0, ea);
|
|
}
|
|
|
|
} else if (i && x) { /* class 2/3, ix=11 */
|
|
if (T_EAR) fprintf(stderr," class 2/3, ix=11\n");
|
|
ea = get16(RPL++); /* get A from next word */
|
|
if (T_EAR) fprintf(stderr," ea=%o\n", ea);
|
|
if (class == 3)
|
|
ea += (short) crs[S];
|
|
while (i) {
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
if (T_EAR) fprintf(stderr," Indirect, ea=%o, [ea]=%o\n", ea, m);
|
|
if ((crs[KEYS] & 016000) == 06000)
|
|
i = m & 0100000;
|
|
else
|
|
i = 0;
|
|
ea = m & amask;
|
|
if (T_EAR) fprintf(stderr," Indirect, new i=%d, new ea=%o\n", i!=0, ea);
|
|
}
|
|
if (T_EAR) fprintf(stderr," Postindex, old ea=%o, X='%o/%d\n", ea, crs[X], *(short *)(crs+X));
|
|
ea += (short) crs[X];
|
|
if (T_EAR) fprintf(stderr," Postindex, new ea=%o\n", ea);
|
|
|
|
} else { /* class 2/3, ix != 11 */
|
|
if (class == 2)
|
|
ea = crs[S]++;
|
|
else
|
|
ea = --crs[S];
|
|
if (T_EAR) fprintf(stderr," Class 2/3, new ea=%o, new S=%o\n", ea, crs[S]);
|
|
if (x) {
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
if ((crs[KEYS] & 016000) == 06000)
|
|
i = m & 0100000;
|
|
ea = m & amask;
|
|
}
|
|
while (i) {
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
if ((crs[KEYS] & 016000) == 06000)
|
|
i = m & 0100000;
|
|
else
|
|
i = 0;
|
|
ea = m & amask;
|
|
}
|
|
if (x)
|
|
ea += crs[X];
|
|
}
|
|
ea &= amask;
|
|
if (ea < 040) /* flag live register ea */
|
|
return ea | 0x80000000;
|
|
return ea;
|
|
}
|
|
|
|
|
|
ea_t ea64v (ea_t earp, unsigned short inst, short i, short x, short *opcode, short *bit) {
|
|
|
|
ea_t ea; /* full seg/word va */
|
|
unsigned short ea_s; /* eff address segno */
|
|
unsigned short ea_r; /* eff address ring */
|
|
unsigned short ea_w; /* eff address wordno */
|
|
unsigned short br;
|
|
unsigned short live; /* max live register addr */
|
|
unsigned short y;
|
|
unsigned short xok;
|
|
unsigned short a;
|
|
unsigned short ixy;
|
|
unsigned short m;
|
|
unsigned short rph,rpl;
|
|
|
|
*bit = 0;
|
|
|
|
/* rph/rpl (and earp) are usually = RPH/RPL in the register file,
|
|
except for the case of an XEC instruction; in that case, these
|
|
will point to 1 after the instruction being executed */
|
|
|
|
rph = earp >> 16;
|
|
rpl = earp & 0xFFFF;
|
|
//if (T_EAV) fprintf(stderr," inst=%o, rph=%o, rpl=%o\n", inst, rph, rpl);
|
|
|
|
if (crs[MODALS] & 4)
|
|
live = 010;
|
|
else
|
|
live = 040;
|
|
|
|
ea_s = rph;
|
|
ea_w = rpl;
|
|
if (inst & 001000) /* sector bit 7 set? */
|
|
if ((inst & 0740) != 0400) { /* PC relative? */
|
|
ea_w = rpl + (((short) (inst << 7)) >> 7); /* yes, sign extend D */
|
|
if (T_EAV) fprintf(stderr," PC relative, P=%o, new ea_w=%o\n", rpl, ea_w);
|
|
}
|
|
else
|
|
goto labB; /* special cases */
|
|
else if (i) {
|
|
ea_w = (inst & 0777); /* sector 0 */
|
|
if (T_EAV) fprintf(stderr," Sector 0, new ea_w=%o\n", ea_w);
|
|
if (ea_w < 0100 && x) { /* preindex by X */
|
|
if (T_EAV) fprintf(stderr," Preindex, ea_w=%o, X='%o/%d\n", ea_w, crs[X], *(short *)(crs+X));
|
|
ea_w += crs[X];
|
|
if (T_EAV) fprintf(stderr," Preindex, new ea_w=%o\n", ea_w);
|
|
x = 0;
|
|
}
|
|
} else
|
|
goto labA;
|
|
|
|
if (i) {
|
|
if (ea_w < live) {
|
|
if (T_EAV) fprintf(stderr," Indirect through live register '%o\n", ea_w);
|
|
ea_w = get16(0x80000000 | ea_w);
|
|
} else {
|
|
if (T_EAV) fprintf(stderr," Indirect, ea_s=%o, ea_w=%o\n", ea_s, ea_w);
|
|
ea_w = get16(MAKEVA(ea_s, ea_w));
|
|
}
|
|
if (T_EAV) fprintf(stderr," After indirect, new ea_w=%o\n", ea_w);
|
|
}
|
|
if (x) {
|
|
if (T_EAV) fprintf(stderr," Postindex, old ea_w=%o, X='%o/%d\n", ea_w, crs[X], *(short *)(crs+X));
|
|
ea_w += crs[X];
|
|
if (T_EAV) fprintf(stderr," Postindex, new ea_w=%o\n", ea_w);
|
|
}
|
|
|
|
if (ea_w < live) {
|
|
if (T_EAV) fprintf(stderr," Live register '%o\n", ea_w);
|
|
return 0x80000000 | ea_w;
|
|
}
|
|
return MAKEVA(ea_s, ea_w);
|
|
|
|
|
|
labA:
|
|
ea_w = (inst & 0777);
|
|
if (x) {
|
|
if (T_EAV) fprintf(stderr," Postindex, old ea_w=%o, X='%o/%d\n", ea_w, crs[X], *(short *)(crs+X));
|
|
ea_w += crs[X];
|
|
if (T_EAV) fprintf(stderr," Postindex, new ea_w=%o\n", ea_w);
|
|
}
|
|
if ((inst & 0777) >= 0400) {
|
|
ea_s = crs[LBH] | (ea_s & RINGMASK16);
|
|
ea_w += crs[LBL];
|
|
if (T_EAV) fprintf(stderr," Short LB relative, LB=%o/%o\n", crs[LBH], crs[LBL]);
|
|
return MAKEVA(ea_s, ea_w);
|
|
}
|
|
if (ea_w < live) {
|
|
if (T_EAV) fprintf(stderr," Live register '%o\n", ea_w);
|
|
return 0x80000000 | ea_w;
|
|
}
|
|
ea_s = crs[SBH] | (ea_s & RINGMASK16);
|
|
ea_w += crs[SBL];
|
|
if (T_EAV) fprintf(stderr," Short SB relative, SB=%o/%o\n", crs[SBH], crs[SBL]);
|
|
return MAKEVA(ea_s, ea_w);
|
|
|
|
|
|
/* here for long, 2-word, V-mode memory reference */
|
|
|
|
labB:
|
|
if (T_EAV) fprintf(stderr," 2-word format\n");
|
|
y = (inst & 020);
|
|
ixy = ((i != 0)<<2) | ((x != 0)<<1) | (y != 0);
|
|
xok = ((*opcode & 01700) != 01500); /* true if indexing is okay */
|
|
|
|
*opcode = *opcode | ((inst >> 2) & 3); /* opcode extension */
|
|
br = (inst & 3);
|
|
a = get16(RP);
|
|
if (T_EAV) fprintf(stderr," new opcode=%5#0o, y=%d, br=%d, ixy=%d, xok=%d, a=%o\n", *opcode, (y != 0), br, ixy, xok, a);
|
|
RPL++;
|
|
|
|
ea_s = crs[PBH+br*2] | (ea_s & RINGMASK16);
|
|
ea_w = crs[PBL+br*2] + a;
|
|
|
|
if (xok)
|
|
if (ixy == 1 || ixy == 4)
|
|
ea_w += crs[Y];
|
|
else if (ixy == 2 || ixy == 6)
|
|
ea_w += crs[X];
|
|
|
|
if (ixy >= 3) {
|
|
ea = MAKEVA(ea_s, ea_w);
|
|
if (T_EAV) fprintf(stderr," Long indirect, ea=%o/%o, ea_s=%o, ea_w=%o\n", ea>>16, ea&0xFFFF, ea_s, ea_w);
|
|
m = get16(ea);
|
|
if (m & 0x8000) {
|
|
printf(" Pointer fault, ea_s=%o, ea_w=%o, [ea]=%o\n", ea_s, ea_w, m);
|
|
fault(POINTERFAULT, m, ea);
|
|
}
|
|
ea_s = m | (ea_s & RINGMASK16);
|
|
ea_w = get16(INCVA(ea,1));
|
|
if (ea_s & EXTMASK16)
|
|
*bit = get16(INCVA(ea,2)) >> 12;
|
|
if (T_EAV) fprintf(stderr," After indirect, ea_s=%o, ea_w=%o, bit=%d\n", ea_s, ea_w, *bit);
|
|
if (xok)
|
|
if (ixy == 5)
|
|
ea_w += crs[Y];
|
|
else if (ixy == 7)
|
|
ea_w += crs[X];
|
|
}
|
|
return MAKEVA(ea_s, ea_w);
|
|
}
|
|
|
|
unsigned int ea32i (ea_t earp, unsigned short inst, short i, short x) {
|
|
if (T_EAI) fprintf(stderr,"Mode 32I not implemented\n");
|
|
}
|
|
|
|
|
|
ea_t apea(unsigned short *bitarg) {
|
|
unsigned short ibr, ea_s, ea_w, bit, br;
|
|
ea_t ea;
|
|
|
|
ibr = get16(RP);
|
|
RPL++;
|
|
bit = (ibr >> 12) & 0xF;
|
|
br = (ibr >> 8) & 3;
|
|
if (T_EAAP) fprintf(stderr," AP ibr=%o, br=%d, i=%d, bit=%d\n", ibr, br, (ibr & 004000) != 0, bit);
|
|
|
|
/* XXX: should ea ring be weakened with RP ring? */
|
|
|
|
ea_s = crs[PBH + 2*br];
|
|
ea_w = crs[PBL + 2*br];
|
|
ea_w += get16(RP);
|
|
RPL++;
|
|
ea = MAKEVA(ea_s, ea_w);
|
|
if (T_EAAP) fprintf(stderr," AP ea = %o/%o\n", ea_s, ea_w);
|
|
if (ibr & 004000) {
|
|
if (ea & 0x80000000)
|
|
fault(POINTERFAULT, ea>>16, 0);
|
|
ea = get32(ea);
|
|
if (ea & EXTMASK32)
|
|
bit = get16(INCVA(ea,2)) >> 12;
|
|
else
|
|
bit = 0;
|
|
if (T_EAAP) fprintf(stderr," After indirect, AP ea = %o/%o, bit=%d\n", ea>>16, ea & 0xFFFF, bit);
|
|
}
|
|
if (bit)
|
|
ea |= EXTMASK32;
|
|
if (bitarg != NULL)
|
|
*bitarg = bit;
|
|
return ea;
|
|
}
|
|
|
|
#define GETFLR(n) (((crsl[FLR0+2*(n)] >> 11) & 0x1FFFE0) | (crsl[FLR0+2*(n)] & 0x1F))
|
|
#define PUTFLR(n,v) crsl[FLR0+2*(n)] = (((v) << 11) & 0xFFFF0000) | (crsl[FLR0+2*(n)] & 0xF000) | ((v) & 0x1F);
|
|
|
|
/* exception handler types:
|
|
|
|
'i' = integer exception
|
|
'd' = decimal exception
|
|
'f' = floating point exception
|
|
|
|
Depending on the keys settings, either set the C-bit or take the
|
|
appropriate fault.
|
|
|
|
Questions:
|
|
|
|
1. Should the C-bit always get set, even if a fault is taken?
|
|
2. Should the operation occur first, updating all registers, then
|
|
the exception occurs? (see PIMA)
|
|
*/
|
|
|
|
#define FC_SFP_OFLOW 0400
|
|
#define FC_SFP_ZDIV 0401
|
|
#define FC_SFP_STORE 0402
|
|
#define FC_SFP_INT 0403
|
|
#define FC_DFP_OFLOW 01000
|
|
#define FC_DFP_ZDIV 01001
|
|
#define FC_INT_OFLOW 01400
|
|
#define FC_INT_ZDIV 01401
|
|
#define FC_DEC_OFLOW 03400
|
|
#define FC_DEC_ZDIV 03401
|
|
#define FC_DEC_CONV 03402
|
|
|
|
mathexception(unsigned char extype, unsigned short fcode, ea_t faddr)
|
|
{
|
|
crs[KEYS] |= 0x8000;
|
|
switch (extype) {
|
|
case 'i':
|
|
if (crs[KEYS] & 0400)
|
|
fault(ARITHFAULT, fcode, faddr);
|
|
break;
|
|
case 'd':
|
|
if (crs[KEYS] & 40)
|
|
fault(ARITHFAULT, fcode, faddr);
|
|
break;
|
|
case 'f':
|
|
if (!(crs[KEYS] & 01000))
|
|
fault(ARITHFAULT, fcode, faddr);
|
|
break;
|
|
default:
|
|
printf(" Unrecognized exception type '%c'\n", extype);
|
|
fatal(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
memdump(int start, int end) {
|
|
int ea;
|
|
|
|
/* dump sector zero for debugging */
|
|
|
|
fprintf(stderr,"\nSector 0:\n");
|
|
for (ea=0; ea<01000; ea=ea+8)
|
|
if (mem[ea]|mem[ea+1]|mem[ea+2]|mem[ea+3]|mem[ea+4]|mem[ea+5]|mem[ea+6]|mem[ea+7])
|
|
fprintf(stderr,"%3o: %6o %6o %6o %6o %6o %6o %6o %6o\n", ea, mem[ea], mem[ea+1], mem[ea+2], mem[ea+3], mem[ea+4], mem[ea+5], mem[ea+6], mem[ea+7]);
|
|
|
|
/* dump main memory for debugging */
|
|
|
|
fprintf(stderr,"\nMain memory:\n");
|
|
for (ea=start; ea<=end; ea=ea+8)
|
|
if (mem[ea]|mem[ea+1]|mem[ea+2]|mem[ea+3]|mem[ea+4]|mem[ea+5]|mem[ea+6]|mem[ea+7])
|
|
fprintf(stderr,"%o: %6o %6o %6o %6o %6o %6o %6o %6o\n", ea, mem[ea], mem[ea+1], mem[ea+2], mem[ea+3], mem[ea+4], mem[ea+5], mem[ea+6], mem[ea+7]);
|
|
}
|
|
|
|
|
|
dumpsegs() {
|
|
short seg,nsegs,i,page,segno;
|
|
unsigned short pte,xxx;
|
|
unsigned int dtar,staddr,sdw,ptaddr,pmaddr;
|
|
|
|
for (i=0; i<4; i++) {
|
|
dtar = *(unsigned int *)(crs+DTAR0-2*i); /* get dtar register */
|
|
nsegs = 1024-(dtar>>22);
|
|
staddr = (dtar & 0x003F0000) | ((dtar & 0xFFFF)<<1);
|
|
fprintf(stderr,"DTAR %d: register=%o, size=%d, seg table addr=%o\n", i, dtar, nsegs, staddr);
|
|
for (seg=0; seg<nsegs; seg++) {
|
|
segno = (i<<10)+seg;
|
|
sdw = *(unsigned int *)(mem+staddr);
|
|
#if 1
|
|
/* according to mapgen.ftn (rev18):
|
|
|
|
C CALCULATE THE MAPS PHYSICAL ADDRESS.
|
|
C
|
|
L=LS(RT(HMAP(J,HMHM),12),4) + RS(RT((I-1)*64+HOFF,10),6)
|
|
C
|
|
C NOW PLUG THAT ADDRESS INTO THE SDW.
|
|
C
|
|
SDW(1)=RT(SDW(1),6) + LS(RT(L,10),6)
|
|
SDW(2)=LT(SDW(2),10) + RS(LT(L,6),10)
|
|
*/
|
|
ptaddr = ((sdw & 0x3F)<<10) | (sdw>>22);
|
|
#else
|
|
ptaddr = ((sdw>>16) & 0xFFC0) | (sdw & 0x3F);
|
|
#endif
|
|
fprintf(stderr,"Segment '%o: F=%d, R1:%o R3:%o PT = %o\n", segno, (sdw>>15)&1, (sdw>>12)&7, (sdw>>6)&7, ptaddr);
|
|
xxx = (sdw>>16)&0x3F;
|
|
if (xxx != 0) fprintf(stderr,"WARNING: X=%o\n", xxx);
|
|
if (ptaddr != 0)
|
|
for (page=0; page<64; page++) {
|
|
pmaddr = (ptaddr<<6) + page;
|
|
pte = mem[pmaddr];
|
|
fprintf(stderr," Seg %o page %d: pmaddr=%o, V=%d R=%d U=%d S=%d PPA=%o\n", segno, page, pmaddr, pte>>15, (pte>>14)&1, (pte>>13)&1, (pte>>12)&1, pte&0xFFF);
|
|
}
|
|
staddr += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
unsigned short dumppcb(unsigned short pcb) {
|
|
short i;
|
|
unsigned short nextpcb;
|
|
ea_t ea;
|
|
|
|
ea = MAKEVA(crs[OWNERH],pcb);
|
|
fprintf(stderr,"PCB %06o:\n", pcb);
|
|
fprintf(stderr," Level: %o\n", get16(ea+0));
|
|
nextpcb = get16(ea+1);
|
|
fprintf(stderr," Link: %o\n", nextpcb);
|
|
fprintf(stderr," Wait list: %o/%o\n", get16(ea+2), get16(ea+3));
|
|
fprintf(stderr," Abort flags: %o\n", get16(ea+4));
|
|
fprintf(stderr," CPU flags: %o\n", get16(ea+5));
|
|
fprintf(stderr," 6,7 (reserved): %o %o\n", get16(ea+6), get16(ea+7));
|
|
fprintf(stderr," Elapsed timers: %d %d\n", get16(ea+8), get16(ea+9));
|
|
fprintf(stderr," DTAR 2 & 3: %o|%o %o|%o\n", get16(ea+10), get16(ea+11), get16(ea+12), get16(ea+13));
|
|
fprintf(stderr," Process interval timer: %o\n", get16(ea+14));
|
|
fprintf(stderr," 15 (reserved): %o\n", get16(ea+15));
|
|
fprintf(stderr," Save mask: %o\n", get16(ea+16));
|
|
fprintf(stderr," Keys: %o\n", get16(ea+17));
|
|
for (i=0; i<16; i++) {
|
|
fprintf(stderr," %06o %06o", get16(ea+18+2*i), get16(ea+19+2*i));
|
|
if (i==7 || i==15)
|
|
fprintf(stderr,"\n");
|
|
}
|
|
fprintf(stderr," R0 Fault vec: %o/%o\n", get16(ea+50), get16(ea+51));
|
|
fprintf(stderr," R1 Fault vec: %o/%o\n", get16(ea+52), get16(ea+53));
|
|
fprintf(stderr," R2 Fault vec: %o/%o\n", get16(ea+54), get16(ea+55));
|
|
fprintf(stderr," R3 Fault vec: %o/%o\n", get16(ea+56), get16(ea+57));
|
|
fprintf(stderr," PG Fault vec: %o/%o\n", get16(ea+58), get16(ea+59));
|
|
fprintf(stderr," Conc. Stack Hdr: %o %o %o\n", get16(ea+60), get16(ea+61), get16(ea+62));
|
|
fprintf(stderr,"\n");
|
|
return nextpcb;
|
|
}
|
|
|
|
/* NOTE: the brsave array contains copies of the PB, SB, and LB base
|
|
registers at the time of the PCL, to compute argument effective
|
|
addresses. If the PCL faults during argument transfer, the ARGT
|
|
instruction will reload this array from the new stack frame
|
|
header. */
|
|
|
|
ea_t pclea(unsigned short brsave[6], ea_t rp, unsigned short *bitarg, short *store, short *lastarg) {
|
|
unsigned short ibr, br, ea_s, ea_w, bit, a;
|
|
unsigned int utempl;
|
|
ea_t ea, iwea;
|
|
|
|
iwea = 0;
|
|
*store = 0;
|
|
utempl = get32(rp);
|
|
ibr = utempl >> 16;
|
|
a = utempl & 0xFFFF;
|
|
bit = (ibr >> 12) & 0xF;
|
|
*store = ibr & 0100;
|
|
*lastarg = ibr & 0200;
|
|
br = (ibr >> 8) & 3;
|
|
if (T_PCL) fprintf(stderr," PCLAP ibr=%o, br=%d, i=%d, bit=%d, store=%d, lastarg=%d, a=%o\n", ibr, br, (ibr & 004000) != 0, bit, (*store != 0), (*lastarg != 0), a);
|
|
if (br != 3) {
|
|
ea_s = brsave[2*br] | (RPH & RINGMASK16);
|
|
ea_w = brsave[2*br + 1];
|
|
ea_w += a;
|
|
} else {
|
|
ea_s = crs[XBH] | (RPH & RINGMASK16);
|
|
ea_w = crs[XBL];
|
|
ea_w += a;
|
|
if (crs[XB] & EXTMASK16) {
|
|
bit += crs[X];
|
|
if (bit > 15) {
|
|
bit -= 16;
|
|
ea_w++;
|
|
}
|
|
if (bit == 0)
|
|
ea_s &= ~EXTMASK16;
|
|
}
|
|
}
|
|
ea = MAKEVA(ea_s, ea_w);
|
|
if (bit)
|
|
ea |= EXTMASK32;
|
|
if (T_PCL) fprintf(stderr," PCLAP ea = %o/%o, bit=%d\n", ea_s, ea_w, bit);
|
|
if (ibr & 004000) {
|
|
if (ea & 0x80000000)
|
|
fault(POINTERFAULT, ea>>16, 0);
|
|
iwea = ea;
|
|
ea = get32(iwea) | (RP & RINGMASK32);
|
|
if (T_PCL) fprintf(stderr," Indirect pointer is %o/%o\n", ea>>16, ea & 0xFFFF);
|
|
|
|
/* Case 35 wants a fault when the IP is 120000/0:
|
|
|
|
#28307386 24000/27740: PCL 24000/30045
|
|
ecb @ 24000/30045, access=7
|
|
ecb.pb: 4000/30041
|
|
ecb.framesize: 16
|
|
ecb.stackroot 4000
|
|
ecb.argdisp: 12
|
|
ecb.nargs: 1
|
|
ecb.lb: 4000/60000
|
|
ecb.keys: 14000
|
|
stack free pointer: 4000/70000, current ring=20000
|
|
before update, stackfp=24000/70000, SB=0/0
|
|
new SB=24000/70000
|
|
new RP=24000/30041
|
|
Entered ARGT
|
|
Transferring arg, 1 left, Y=12
|
|
PCLAP ibr=4300, br=0, i=1, bit=0, store=1, lastarg=1, a=27117
|
|
PCLAP ea = 24000/27117, bit=0
|
|
Indirect pointer is 120000/0
|
|
After indirect, PCLAP ea = 120000/0, bit=0
|
|
Storing arg, 1 left, Y=12
|
|
Stored
|
|
#29019968: fault '62, fcode=0, faddr=0/0, faultrp=24000/1356
|
|
|
|
[ Failure Report ]
|
|
|
|
address instruction scope loop
|
|
024000/027740 021410/030045 024000/027547
|
|
|
|
Actual: NO POINTER FAULT
|
|
Expected: POINTER FAULT
|
|
|
|
But, Case 37 doesn't want a fault:
|
|
|
|
#28891410 24000/30760: PCL 24000/31065
|
|
ecb @ 24000/31065, access=7
|
|
ecb.pb: 4000/31054
|
|
ecb.framesize: 16
|
|
ecb.stackroot 4000
|
|
ecb.argdisp: 12
|
|
ecb.nargs: 1
|
|
ecb.lb: 4000/60000
|
|
ecb.keys: 14000
|
|
stack free pointer: 4000/70000, current ring=20000
|
|
before update, stackfp=24000/70000, SB=0/0
|
|
new SB=24000/70000
|
|
new RP=24000/31054
|
|
Entered ARGT
|
|
Transferring arg, 1 left, Y=12
|
|
PCLAP ibr=4300, br=0, i=1, bit=0, store=1, lastarg=1, a=27117
|
|
PCLAP ea = 24000/27117, bit=0
|
|
Indirect pointer is 120000/0
|
|
#28891410: fault '77, fcode=120000, faddr=24000/27117, faultrp=24000/30760
|
|
|
|
0003 Unexpected POINTER fault. Returning to 030760
|
|
|
|
Changing <= to < in the ring comparison makes Case 37 work and Case 35 fail.
|
|
*/
|
|
|
|
#if 1
|
|
if (ea & 0x80000000)
|
|
if ((ea & 0xFFFF0000) != 0x80000000)
|
|
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) <= (ea & RINGMASK32)))
|
|
fault(POINTERFAULT, ea>>16, iwea);
|
|
#endif
|
|
bit = 0;
|
|
#if 0
|
|
/* CPU.PCL Case 33 shows that the bit field is not stored in the stack frame
|
|
for a 3-word indirect pointer, even though the E bit remains set */
|
|
if (ea & EXTMASK32)
|
|
bit = get16(ea+2) >> 12;
|
|
#endif
|
|
if (T_PCL) fprintf(stderr," After indirect, PCLAP ea = %o/%o, bit=%d\n", ea>>16, ea & 0xFFFF, bit);
|
|
}
|
|
|
|
if (!*store) {
|
|
#if 0
|
|
/* Case 36 wants a pointer fault here... See Case 31, 34, 37 also */
|
|
if (ea & 0x80000000)
|
|
if ((ea & 0xFFFF0000) != 0x80000000)
|
|
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) <= (ea & RINGMASK32)))
|
|
fault(POINTERFAULT, ea>>16, iwea);
|
|
#else
|
|
if (ea & 0x80000000)
|
|
fault(POINTERFAULT, ea>>16, iwea);
|
|
#endif
|
|
*(unsigned int *)(crs+XB) = ea;
|
|
crs[X] = bit;
|
|
}
|
|
if (bit) {
|
|
ea |= EXTMASK32;
|
|
*bitarg = bit;
|
|
} else {
|
|
*bitarg = 0;
|
|
}
|
|
return ea;
|
|
}
|
|
|
|
|
|
pcl (ea_t ecbea) {
|
|
short i;
|
|
short access;
|
|
unsigned short ecb[9];
|
|
short bit; /* bit offset for args */
|
|
ea_t newrp; /* start of new proc */
|
|
ea_t ea;
|
|
ea_t rp; /* return pointer */
|
|
short stackrootseg;
|
|
short stacksize;
|
|
short store; /* true if store bit set on AP */
|
|
short storedargs; /* # of arguments that have been stored */
|
|
short lastarg; /* true if "last" bit seen in PCL arglist */
|
|
ea_t argp; /* where to store next arg in new frame */
|
|
ea_t stackfp; /* new stack frame pointer */
|
|
pa_t pa; /* physical address of ecb */
|
|
unsigned short brsave[6]; /* old PB,SB,LB */
|
|
|
|
/* get segment access; mapva ensures either read or gate */
|
|
|
|
pa = mapva(ecbea, PACC, &access);
|
|
if (T_PCL) fprintf(stderr," ecb @ %o/%o, access=%d\n", ecbea>>16, ecbea&0xFFFF, access);
|
|
|
|
/* get a copy of the ecb. gates must be aligned on a 16-word
|
|
boundary, therefore can't cross a page boundary, and mapva has
|
|
already ensured that the ecb page is resident. For a non-gate
|
|
ecb, check to see if it crosses a page boundary. If not, a
|
|
memcpy is okay; if it does, do fetches */
|
|
|
|
if (access == 1) {
|
|
if ((ecbea & 0xF) != 0)
|
|
fault(ACCESSFAULT, 0, ecbea);
|
|
memcpy(ecb,mem+pa,sizeof(ecb));
|
|
} else if ((pa & 01777) <= 01750) {
|
|
memcpy(ecb,mem+pa,sizeof(ecb));
|
|
} else {
|
|
*(double *)(ecb+0) = get64(ecbea+0);
|
|
*(double *)(ecb+4) = get64(ecbea+4);
|
|
ecb[8] = get16(ecbea+8);
|
|
}
|
|
|
|
/* XXX: P400 docs say "no ring change takes place if not a
|
|
gate"; does that mean that if R0 calls a R3 ecb, it's
|
|
still in R0, or should it be weakened to the ecb ring?
|
|
(Case 24 of CPU.PCL indicates it should be weakened) */
|
|
|
|
if (T_PCL) fprintf(stderr," ecb.pb: %o/%o\n ecb.framesize: %d\n ecb.stackroot %o\n ecb.argdisp: %o\n ecb.nargs: %d\n ecb.lb: %o/%o\n ecb.keys: %o\n", ecb[0], ecb[1], ecb[2], ecb[3], ecb[4], ecb[5], ecb[6], ecb[7], ecb[8]);
|
|
|
|
newrp = *(unsigned int *)(ecb+0);
|
|
if (access != 1)
|
|
#if 0
|
|
newrp = (newrp & ~RINGMASK32) | (RP & RINGMASK32); /* no ring change */
|
|
#else
|
|
newrp = newrp | (RP & RINGMASK32); /* Case 24 indicates to weaken ring */
|
|
#endif
|
|
|
|
/* setup stack frame */
|
|
|
|
stackrootseg = ecb[3];
|
|
if (stackrootseg == 0) {
|
|
stackrootseg = get16((*(unsigned int *)(crs+SB)) + 1);
|
|
if (T_PCL) fprintf(stderr," stack root in ecb was zero, stack root from caller is %o\n", stackrootseg);
|
|
}
|
|
if (stackrootseg == 0)
|
|
fatal("Stack base register root segment is zero");
|
|
stackfp = get32(MAKEVA(stackrootseg,0));
|
|
if (stackfp == 0)
|
|
fatal("Stack free pointer is zero");
|
|
if (T_PCL) fprintf(stderr," stack free pointer: %o/%o, current ring=%o\n", stackfp>>16, stackfp&0xFFFF, RPH&RINGMASK16);
|
|
stacksize = ecb[2];
|
|
|
|
/* if there isn't room for this frame, check the stack extension
|
|
pointer */
|
|
|
|
if ((stackfp & 0xFFFF) + stacksize > 0xFFFF) {
|
|
stackfp = get32(MAKEVA(stackrootseg,2));
|
|
if (T_PCL) fprintf(stderr," no room for frame, extension pointer is %o/%o\n", stackfp>>16, stackfp&0xFFFF);
|
|
|
|
/* XXX: faddr may need to be the last segment tried when this is changed to loop.
|
|
CPU.PCL Case 26 wants fault address word number to be 3; set EHDB */
|
|
|
|
if (stackfp == 0 || (stackfp & 0xFFFF) + stacksize > 0xFFFF)
|
|
fault(STACKFAULT, 0, MAKEVA(stackrootseg,0) | (newrp & RINGMASK32));
|
|
}
|
|
|
|
/* setup the new stack frame at stackfp
|
|
|
|
NOTE: Ring must be added to stackfp so that any page faults that
|
|
occur while setting up the stack will have the correct ring for
|
|
CPU.PCL tests */
|
|
|
|
stackfp |= (newrp & RINGMASK32);
|
|
put16(0, stackfp);
|
|
put16(stackrootseg, stackfp+1);
|
|
put32(RP, stackfp+2);
|
|
put32(*(unsigned int *)(crs+SB), stackfp+4);
|
|
put32(*(unsigned int *)(crs+LB), stackfp+6);
|
|
put16(crs[KEYS], stackfp+8);
|
|
put16(RPL, stackfp+9);
|
|
|
|
#if 0
|
|
/* LATER: save caller's base registers for address calculations, and
|
|
pass to argt */
|
|
|
|
if (ecb[5] > 0) {
|
|
brsave[0] = RPH; brsave[1] = 0;
|
|
brsave[2] = crs[SBH]; brsave[3] = crs[SBL];
|
|
brsave[4] = crs[LBH]; brsave[5] = crs[LBL];
|
|
}
|
|
#endif
|
|
|
|
/* load new execution state from ecb */
|
|
|
|
if (T_PCL) fprintf(stderr," before update, stackfp=%o/%o, SB=%o/%o\n", stackfp>>16, stackfp&0xFFFF, crs[SBH], crs[SBL]);
|
|
if (access == 1)
|
|
*(unsigned int *)(crs+SB) = stackfp;
|
|
else
|
|
*(unsigned int *)(crs+SB) = (stackfp & ~RINGMASK32) | (RP & RINGMASK32);
|
|
if (T_PCL) fprintf(stderr," new SB=%o/%o\n", crs[SBH], crs[SBL]);
|
|
*(unsigned int *)(crs+LB) = *(unsigned int *)(ecb+6);
|
|
newkeys(ecb[8] & 0177760);
|
|
RP = newrp;
|
|
if (T_PCL) fprintf(stderr," new RP=%o/%o\n", RPH, RPL);
|
|
|
|
/* update the stack free pointer; this has to wait until after all
|
|
memory accesses, in case of stack page faults (PCL restarts).
|
|
Some ucode versions incorrectly store the ring in the free
|
|
pointer if the extension pointer was followed. Set EHDB to
|
|
suppress this spurious DIAG error. */
|
|
|
|
ea = MAKEVA(stackrootseg,0) | (newrp & RINGMASK32);
|
|
put32((stackfp+stacksize) & ~RINGMASK32, ea);
|
|
|
|
/* transfer arguments if arguments are expected. There is no
|
|
documentation explaining how the Y register is used during
|
|
argument transfer, so:
|
|
Y(high) = stack frame offset to store next argument
|
|
Y(low) = number of arguments left to transfer (JW hack!) */
|
|
|
|
if (ecb[5] > 0) {
|
|
crs[Y] = ecb[4];
|
|
crs[YL] = ecb[5];
|
|
argt();
|
|
}
|
|
}
|
|
|
|
/* for ARGT:
|
|
Registers:
|
|
- RP points to the ARGT instruction
|
|
- SB points to the new stack frame
|
|
- LB is for the called procedure
|
|
- Y is new frame offset of the next argument
|
|
- YL is the number of arguments left to transfer (HACK!)
|
|
Stack frame:
|
|
- PB points to the next argument template to be evaluated
|
|
- SB is the caller's saved SB
|
|
- LB is the caller's saved LB
|
|
*/
|
|
|
|
argt() {
|
|
unsigned short brsave[6];
|
|
unsigned short argsleft, argdisp, lastarg, store,bit;
|
|
unsigned int utempl;
|
|
unsigned short ecby; /* last offset where ecb temp ea was stored */
|
|
ea_t ea, stackfp, rp, ecbea;
|
|
unsigned short advancepb, advancey;
|
|
|
|
if (T_PCL) fprintf(stderr,"Entered ARGT\n");
|
|
|
|
/* stackfp is the new stack frame, rp is in the middle of
|
|
argument templates and is advanced after each transfer */
|
|
|
|
stackfp = *(unsigned int *)(crs+SB);
|
|
rp = get32(stackfp+2);
|
|
|
|
/* reload the caller's base registers for EA calculations */
|
|
|
|
brsave[0] = rp >> 16; brsave[1] = 0;
|
|
*(double *)(brsave+2) = get64(stackfp+4);
|
|
|
|
argdisp = crs[Y];
|
|
argsleft = crs[YL];
|
|
lastarg = 0; /* true when AP template with L bit is seen */
|
|
while (argsleft > 0 || !lastarg) {
|
|
|
|
if (T_PCL) fprintf(stderr," Transferring arg, %d left, Y=%o\n", argsleft, crs[Y]);
|
|
|
|
advancey = 0;
|
|
if (lastarg) {
|
|
ea = 0x80000000;
|
|
store = 1;
|
|
advancepb = 0;
|
|
} else {
|
|
ea = pclea(brsave, rp, &bit, &store, &lastarg) | (RP & RINGMASK32);
|
|
advancepb = 1;
|
|
}
|
|
if (argsleft > 0 && store) {
|
|
if (T_PCL) fprintf(stderr," Storing arg, %d left, Y=%o\n", argsleft, crs[Y]);
|
|
|
|
/* NOTE: some version of ucode only store 16 bits for omitted args.
|
|
Set EHDB to prevent this error.
|
|
|
|
Case 29 wants ring/E-bits preserved for omitted arguments */
|
|
|
|
#if 0
|
|
#define OMITTEDARG_MASK 0x8FFFFFFF
|
|
#else
|
|
#define OMITTEDARG_MASK 0xEFFFFFFF
|
|
#endif
|
|
|
|
if ((ea & 0x8FFF0000) == 0x80000000) {
|
|
ea = ea & OMITTEDARG_MASK; /* strip ring &/or E bits */
|
|
put32(ea, stackfp+crs[Y]);
|
|
} else {
|
|
put32(ea, stackfp+crs[Y]);
|
|
if (ea & EXTMASK32)
|
|
put16(bit<<12, stackfp+crs[Y]+2);
|
|
}
|
|
if (T_PCL) fprintf(stderr," Stored\n");
|
|
argsleft--;
|
|
advancey = 1;
|
|
}
|
|
|
|
/* advance rp/pb in new stack frame past this template, and
|
|
advance Y to the next arg displacement in the stack. Y
|
|
has to be advanced last because the PB store may fault.
|
|
If it does, the ARGT starts over, and this argument will
|
|
have to be transferred again. */
|
|
|
|
if (advancepb) {
|
|
rp += 2;
|
|
put32(rp, stackfp+2);
|
|
}
|
|
if (advancey) {
|
|
crs[Y] += 3;
|
|
crs[YL]--;
|
|
}
|
|
}
|
|
|
|
/* after argument transfer, advance real RP past ARGT */
|
|
|
|
RPL++;
|
|
}
|
|
|
|
|
|
void prtn() {
|
|
unsigned short stackrootseg;
|
|
ea_t newrp,newsb,newlb;
|
|
unsigned short newkeys;
|
|
|
|
stackrootseg = get16(*(unsigned int *)(crs+SB)+1);
|
|
put32(*(unsigned int *)(crs+SB), MAKEVA(stackrootseg,0));
|
|
newrp = get32(*(unsigned int *)(crs+SB)+2);
|
|
newsb = get32(*(unsigned int *)(crs+SB)+4);
|
|
newlb = get32(*(unsigned int *)(crs+SB)+6);
|
|
newkeys = get16(*(unsigned int *)(crs+SB)+8);
|
|
RP = newrp | (RP & RINGMASK32);
|
|
*(unsigned int *)(crs+SB) = newsb;
|
|
*(unsigned int *)(crs+LB) = newlb;
|
|
crs[KEYS] = newkeys & 0177760;
|
|
if (T_INST) printf(" Finished PRTN, RP=%o/%o\n", RPH, RPL);
|
|
}
|
|
|
|
|
|
/* process exchange register save: saves the current register
|
|
set to the process pcb.
|
|
NOTES:
|
|
- adding "wait" arg and only saving base registers fixed Case 63
|
|
*/
|
|
|
|
pxregsave(unsigned short wait) {
|
|
ea_t pcbp, regp;
|
|
unsigned short i, mask;
|
|
|
|
/* if registers aren't owned or are already saved, return */
|
|
|
|
if (crs[OWNERL] == 0 || (crs[KEYS] & 1))
|
|
return;
|
|
|
|
pcbp = *(unsigned int *)(crs+OWNER);
|
|
regp = pcbp+PCBREGS;
|
|
mask = 0;
|
|
for (i=(wait?12:0); i<16; i++) {
|
|
if (crsl[i] != 0) {
|
|
mask |= bitmask16[i+1];
|
|
put32(crsl[i], regp);
|
|
regp += 2;
|
|
}
|
|
}
|
|
put16(mask, pcbp+PCBMASK);
|
|
crs[KEYS] |= 1;
|
|
put16(crs[KEYS], pcbp+PCBKEYS);
|
|
}
|
|
|
|
/* pxregload: load pcbp's registers from their pcb to the current
|
|
register set, set OWNERL
|
|
|
|
NOTE: RP must be set by the caller since this happens whenever
|
|
a process is dispatched - not just when registers are loaded */
|
|
|
|
pxregload (ea_t pcbp) {
|
|
ea_t regp;
|
|
unsigned short i, mask;
|
|
|
|
if (T_PX) fprintf(stderr,"pxregload loading registers for process %o/%o\n", pcbp>>16, pcbp&0xFFFF);
|
|
regp = pcbp+PCBREGS;
|
|
mask = get16(pcbp+PCBMASK);
|
|
for (i=0; i<16; i++) {
|
|
if (mask & bitmask16[i+1]) {
|
|
crsl[i] = get32(regp);
|
|
regp += 2;
|
|
} else {
|
|
crsl[i] = 0;
|
|
}
|
|
}
|
|
crs[KEYS] = get16(pcbp+PCBKEYS);
|
|
*(unsigned int *)(crs+DTAR2) = get32(pcbp+PCBDTAR2);
|
|
*(unsigned int *)(crs+DTAR3) = get32(pcbp+PCBDTAR3);
|
|
crs[OWNERL] = pcbp & 0xFFFF;
|
|
|
|
if (T_PX) fprintf(stderr,"pxregload: registers loaded, ownerl=%o\n", crs[OWNERL]);
|
|
}
|
|
|
|
|
|
/* switch to the other register set (2 vs 3) */
|
|
|
|
ors() {
|
|
unsigned short rsnum;
|
|
unsigned short modals;
|
|
|
|
/* only bit 11 of crs in modals is important for register set */
|
|
|
|
printf("ors: current modals = %o, register set = %d\n", crs[MODALS], (crs[MODALS] & 0340)>>5);
|
|
modals = (crs[MODALS] ^ 040) | 0100;
|
|
rsnum = 2+((modals & 040) >> 5);
|
|
printf("ors: new modals = %o, register set = %d\n", modals, rsnum);
|
|
crs = regs.rs16[rsnum];
|
|
crsl = (void *)crs;
|
|
crs[MODALS] = modals;
|
|
printf("ors: new register set = %d\n", (crs[MODALS] & 0340)>>5);
|
|
}
|
|
|
|
|
|
/* the process exchange dispatcher's job is to:
|
|
- determine the highest priority process ready to run
|
|
- find a register set to use
|
|
- save the registers if they are currently owned and not already saved
|
|
- load this process' registers into the register set
|
|
- clear the save done bit in keys
|
|
- cause a process fault if any of this process' pcb abort flags are set
|
|
|
|
If no process can be found to run, the dispatcher idles and waits
|
|
for an external interrupt.
|
|
*/
|
|
|
|
dispatcher() {
|
|
ea_t pcbp, rlp;
|
|
unsigned short pcbw; /* pcb word address */
|
|
unsigned short rsnum;
|
|
unsigned short rlbol;
|
|
unsigned short utempa;
|
|
|
|
|
|
if (regs.sym.pcba != 0) {
|
|
pcbp = MAKEVA(crs[OWNERH], regs.sym.pcba);
|
|
regs.sym.pla = get16(pcbp+PCBLEV);
|
|
if (T_PX) printf("disp: dispatching PPA, pcba=%o, pla=%o\n", regs.sym.pcba, regs.sym.pla);
|
|
|
|
} else if (regs.sym.pcbb != 0) {
|
|
pcbp = MAKEVA(crs[OWNERH], regs.sym.pcbb);
|
|
regs.sym.pcba = regs.sym.pcbb;
|
|
regs.sym.pla = get16(pcbp+PCBLEV);
|
|
regs.sym.pcbb = 0;
|
|
if (T_PX) printf("disp: dispatching PPB, pcba=%o, pla=%o\n", regs.sym.pcba, regs.sym.pla);
|
|
|
|
} else {
|
|
if (T_PX) printf("disp: scanning RL\n");
|
|
if (regs.sym.pla != 0)
|
|
rlp = MAKEVA(crs[OWNERH], regs.sym.pla);
|
|
else if (regs.sym.plb != 0)
|
|
rlp = MAKEVA(crs[OWNERH], regs.sym.plb);
|
|
else
|
|
fatal("dispatch: both pla and plb are zero; can't locate ready list");
|
|
#if 0
|
|
if (regs.sym.pla < 0100 || regs.sym.pla > 0154)
|
|
fatal("regs.sym.pla is out of range!");
|
|
#endif
|
|
while(1) {
|
|
rlbol = get16(rlp);
|
|
if (rlbol != 0)
|
|
break;
|
|
rlp += 2;
|
|
}
|
|
if (rlbol == 1)
|
|
goto idle;
|
|
pcbp = MAKEVA(crs[OWNERH], rlbol);
|
|
regs.sym.pcba = rlbol;
|
|
regs.sym.pla = rlp & 0xFFFF;
|
|
}
|
|
pcbw = pcbp & 0xFFFF;
|
|
if (T_PX) printf("disp: process %o/%o selected\n", pcbp>>16, pcbw);
|
|
|
|
/* pcbp now points to the process we're going to run. BY
|
|
definition, this process should not be on any wait lists,
|
|
so pcb.waitlist(seg) should be zero. Check it */
|
|
|
|
utempa = get16(pcbp+PCBWAIT);
|
|
if (utempa != 0) {
|
|
printf("dispatch: pcb %o/%o selected, but wait segno = %o\n", pcbp>>16, pcbp&0xFFFF, utempa);
|
|
fatal(NULL);
|
|
}
|
|
|
|
/* save RP in current register set before possibly switching */
|
|
|
|
*(unsigned int *)(crs+PB) = RP;
|
|
|
|
/* find a register set for this process */
|
|
|
|
#if 0
|
|
rsnum = (crs[MODALS] & 0340)>>5;
|
|
if (crs[OWNERL] != pcbw && crs[OWNERL] != 0)
|
|
if (regs.rs16[rsnum ^ 1][OWNERL] == 0 || (regs.rs16[rsnum ^ 1][OWNERL] == pcbw && (regs.rs16[rsnum ^ 1][KEYS] & 1)) || ((regs.rs16[rsnum ^ 1][KEYS] & 1) && !(crs[KEYS] & 1)))
|
|
ors();
|
|
#endif
|
|
|
|
/* Cases that fail w/o any register switch:
|
|
- 3 err dispatch
|
|
- 5 reg data not saved correctly
|
|
- 7 crs.modals
|
|
- 11 crs.modals
|
|
- 13 crs.modals
|
|
- 17 err dispatch
|
|
- 19 crs.modals
|
|
- 25 crs.modals
|
|
- 27 err dispatch
|
|
- 31 crs.modals
|
|
- 45 err dispatch
|
|
- 47 crs.modals
|
|
- 49 err dispatch
|
|
- 51 crs.modals
|
|
- 61 crs.modals
|
|
- 63 ors.X wrong
|
|
- 81 save mask wrong
|
|
- 83 crs.modals
|
|
|
|
Cases that fail with simple register switch below:
|
|
- 9 crs.modals
|
|
- 23 crs.modals
|
|
- 29 crs.modals
|
|
* - 31 saved X wrong
|
|
* - 83 crs.modals
|
|
- 85 bad
|
|
- 89 crs.modals - switches register sets
|
|
- 90 crs.modals
|
|
|
|
Adding "&& crs[OWNERL] != 0" and setting this to zero in IRTN if PPA is
|
|
invalid fixes case 81 w/o breaking any other tests.
|
|
|
|
*/
|
|
|
|
#if 1
|
|
if (crs[OWNERL] != pcbw && crs[OWNERL] != 0)
|
|
ors();
|
|
#endif
|
|
|
|
/* If the selected register set is owned and hasn't been saved, save
|
|
it before taking it */
|
|
|
|
if (crs[OWNERL] == pcbw) {
|
|
if (T_PX) printf("disp: register set already owned by %o - no save\n", crs[OWNERL]);
|
|
} else {
|
|
if (T_PX) printf("disp: saving registers owned by %o\n", crs[OWNERL]);
|
|
pxregsave(0);
|
|
pxregload(pcbp);
|
|
}
|
|
|
|
/* if this process' abort flags are set, process fault */
|
|
|
|
utempa = get16(pcbp+PCBABT);
|
|
if (utempa != 0) {
|
|
if (T_PX) fprintf(stderr,"dispatch: abort flags for %o are %o\n", crs[OWNERL], utempa);
|
|
fault(PROCESSFAULT, utempa, 0);
|
|
fatal("fault returned after process fault");
|
|
}
|
|
|
|
crs[TIMER] = get16(pcbp+PCBIT);
|
|
RP = *(unsigned int *)(crs+PB);
|
|
crs[PBL] = 0;
|
|
crs[KEYS] &= ~3; /* erase "in dispatcher" and "save done" */
|
|
if (T_PX) printf("disp: returning from dispatcher, running process %o/%o at %o/%o\n", crs[OWNERH], crs[OWNERL], RPH, RPL);
|
|
return;
|
|
|
|
idle:
|
|
fatal("dispatch idle...");
|
|
}
|
|
|
|
/* take me off the ready list, setting my pcb link pointer to the arg
|
|
passed in. The dispatcher should always be entered after this
|
|
routine. */
|
|
|
|
unready (ea_t waitlist, unsigned short newlink) {
|
|
unsigned short level, bol, eol;
|
|
unsigned int rl;
|
|
ea_t rlp, pcbp;
|
|
|
|
if (regs.sym.pcba != crs[OWNERL])
|
|
fatal("unready: pcba mismatch");
|
|
|
|
pcbp = *(ea_t *)(crs+OWNER);
|
|
rlp = MAKEVA(crs[OWNERH], regs.sym.pla);
|
|
rl = get32(rlp);
|
|
bol = rl >> 16;
|
|
eol = rl & 0xFFFF;
|
|
if (bol != (pcbp & 0xFFFF)) {
|
|
printf("rlp=%o/%o, bol=%o, pcbp=%o/%o, pla=%o, pcba=%o\n", rlp>>16, rlp&0xFFFF, bol, pcbp>>16, pcbp&0xFFFF, regs.sym.pla, regs.sym.pcba);
|
|
fatal("unready: I'm not first on the ready list");
|
|
}
|
|
if (bol == eol) {
|
|
bol = 0;
|
|
eol = 0;
|
|
} else {
|
|
bol = get16(pcbp+1);
|
|
}
|
|
rl = (bol<<16) | eol;
|
|
put32(rl, rlp); /* update ready list */
|
|
if (T_PX) fprintf(stderr,"unready: new rl bol/eol = %o/%o\n", rl>>16, rl&0xFFFF);
|
|
put16(newlink, pcbp+1); /* update my pcb link */
|
|
put32(waitlist, pcbp+2); /* update my pcb wait address */
|
|
*(unsigned int *)(crs+PB) = RP;
|
|
pxregsave(1);
|
|
regs.sym.pcba = 0;
|
|
}
|
|
|
|
|
|
/* pcbp points to the pcb to put on the ready list
|
|
begend is 1 for beginning, 0 for end
|
|
returns true if this process is higher priority than me
|
|
*/
|
|
|
|
unsigned short ready (ea_t pcbp, unsigned short begend) {
|
|
ea_t rlp;
|
|
ea_t xpcbp;
|
|
unsigned short bol,eol,pcbw,level,resched;
|
|
unsigned int rl;
|
|
|
|
if ((pcbp & 0xFFFF) == crs[OWNERL])
|
|
fatal("Tried to put myself on the ready list!");
|
|
if (regs.sym.pcba != crs[OWNERL])
|
|
fatal("I'm running, but not regs.sym.pcba!");
|
|
|
|
level = get16(pcbp+PCBLEV);
|
|
rlp = MAKEVA(crs[OWNERH],level);
|
|
rl = get32(rlp);
|
|
if (T_PX) printf("ready: pcbp=%o/%o\n", pcbp>>16, pcbp&0xFFFF);
|
|
if (T_PX) printf("ready: old bol/eol for level %o = %o/%o\n", level, rl>>16, rl&0xFFFF);
|
|
pcbw = pcbp; /* pcb word number */
|
|
if ((rl>>16) == 0) { /* bol=0: this RL level was empty */
|
|
put32(0, pcbp+1); /* set link and wait SN in pcb */
|
|
rl = (pcbw<<16) | pcbw; /* set beg=end */
|
|
} else if (begend) { /* notify to beginning */
|
|
put32(rl & 0xFFFF0000, pcbp+1); /* set link and wait SN in pcb */
|
|
rl = (pcbw<<16) | rl&0xFFFF; /* new is bol, eol is unchanged */
|
|
} else { /* notify to end */
|
|
put32(0, pcbp+1); /* set link and wait SN in pcb */
|
|
xpcbp = MAKEVA(crs[OWNERH],rl&0xFFFF); /* get ptr to last pcb at this level */
|
|
put16(pcbw,xpcbp+1); /* set last pcb's forward link */
|
|
rl = (rl & 0xFFFF0000) | pcbw; /* rl bol is unchanged, eol is new */
|
|
}
|
|
put32(rl, rlp);
|
|
if (T_PX) printf("ready: new bol/eol for level %o = %o/%o, pcb's link is %o\n", level, rl>>16, rl&0xFFFF, get16(pcbp+1));
|
|
|
|
/* is this new process higher priority than me? If so, return 1
|
|
so that the dispatcher is entered. If not, check for new plb/pcbb */
|
|
|
|
resched = 0;
|
|
if (level < regs.sym.pla || (level == regs.sym.pla && begend)) {
|
|
regs.sym.plb = regs.sym.pla;
|
|
regs.sym.pcbb = regs.sym.pcba;
|
|
regs.sym.pla = level;
|
|
regs.sym.pcba = pcbw;
|
|
resched = 1;
|
|
} else if (level < regs.sym.plb || (level == regs.sym.plb && begend)) {
|
|
regs.sym.plb = level;
|
|
regs.sym.pcbb = pcbw;
|
|
}
|
|
return resched;
|
|
}
|
|
|
|
|
|
wait() {
|
|
ea_t ea;
|
|
ea_t pcbp, prevpcbp;
|
|
unsigned int utempl;
|
|
unsigned int pcblevnext; /* pcb level and link */
|
|
unsigned short bol;
|
|
unsigned short pcblev;
|
|
unsigned short pcbnext;
|
|
short count;
|
|
|
|
RESTRICT();
|
|
ea = apea(NULL);
|
|
if (T_PX) printf("%o/%o: WAIT on %o/%o, I am %o, keys=%o, modals=%o\n", RPH, RPL, ea>>16, ea&0xFFFF, crs[OWNERL], crs[KEYS], crs[MODALS]);
|
|
utempl = get32(ea); /* get count and BOL */
|
|
count = utempl>>16; /* count (signed) */
|
|
bol = utempl & 0xFFFF; /* beginning of wait list */
|
|
if (T_PX) fprintf(stderr," wait list count was %d, bol was %o\n", count, bol);
|
|
count++;
|
|
if (count >= 1) { /* I have to wait */
|
|
if (count == 1 && bol != 0)
|
|
fatal("WAIT: count == 1 but bol != 0");
|
|
if (count > 1 && bol == 0)
|
|
fatal("WAIT: count > 1 but bol == 0");
|
|
if (regs.sym.pcba == 0)
|
|
fatal("WAIT: pcba is zero");
|
|
if (bol != 0) {
|
|
pcbp = MAKEVA(crs[OWNERH],bol);
|
|
pcblevnext = get32(pcbp);
|
|
pcblev = pcblevnext >> 16;
|
|
}
|
|
if (count == 1 || regs.sym.pla < pcblev) { /* add me to the beginning */
|
|
utempl = (count<<16) | crs[OWNERL];
|
|
put32(utempl, ea); /* update semaphore count/bol */
|
|
} else {
|
|
/* do a priority scan... */
|
|
while (pcblev <= regs.sym.pla && bol != 0) {
|
|
prevpcbp = pcbp;
|
|
bol = pcblevnext & 0xFFFF;
|
|
if (bol != 0) {
|
|
pcbp = MAKEVA(crs[OWNERH],bol);
|
|
pcblevnext = get32(pcbp);
|
|
pcblev = pcblevnext >> 16;
|
|
}
|
|
}
|
|
put16(crs[OWNERL], prevpcbp+PCBLINK);
|
|
put16(*(unsigned short *)&count, ea); /* update count */
|
|
}
|
|
unready(ea, bol);
|
|
dispatcher();
|
|
} else
|
|
put16(*(unsigned short *)&count, ea); /* just update count and continue */
|
|
}
|
|
|
|
/* this handles several forms of notify:
|
|
- 001210 = NFYE
|
|
- 001211 = NFYB
|
|
- 001214 = INEN, notify to end, no CAI
|
|
- 001215 = INBN, notify to beg, no CAI
|
|
- 001216 = INEC, notify to end, CAI
|
|
- 001217 = INBC, notify to beg, CAI
|
|
*/
|
|
|
|
nfy(unsigned short inst) {
|
|
unsigned short resched, begend, bol, rsnum;
|
|
ea_t ea, pcbp;
|
|
unsigned int utempl;
|
|
short scount;
|
|
|
|
resched = 0;
|
|
begend = inst & 1;
|
|
#if 0
|
|
if (regs.sym.pcba != crs[OWNERL]) {
|
|
printf("NFY: regs.pcba = %o, but crs[OWNERL] = %o\n", regs.sym.pcba, crs[OWNERL]);
|
|
fatal(NULL);
|
|
}
|
|
#endif
|
|
RESTRICT();
|
|
ea = apea(NULL);
|
|
utempl = get32(ea); /* get count and BOL */
|
|
scount = utempl>>16; /* count (signed) */
|
|
bol = utempl & 0xFFFF; /* beginning of wait list */
|
|
if (T_PX) fprintf(stderr,"%o/%o: NFYB/E opcode %o, ea=%o/%o, count=%d, bol=%o, I am %o\n", RPH, RPL, inst, ea>>16, ea&0xFFFF, scount, bol, crs[OWNERL]);
|
|
if (scount > 0) {
|
|
if (bol == 0) {
|
|
printf("NFYB: bol is zero, count is %d for semaphore at %o/%o\n", scount, ea>>16, ea&0xFFFF);
|
|
fatal(NULL);
|
|
}
|
|
pcbp = MAKEVA(crs[OWNERH], bol);
|
|
utempl = get32(pcbp+PCBWAIT);
|
|
if (utempl != ea) {
|
|
printf("NFYB: bol=%o, pcb waiting on %o/%o != ea %o/%o\n", utempl>>16, utempl&0xFFFF, ea>>16, ea&0xFFFF);
|
|
fatal(NULL);
|
|
}
|
|
bol = get16(pcbp+PCBLINK); /* get new beginning of wait list */
|
|
resched = ready(pcbp, begend); /* put this pcb on the ready list */
|
|
}
|
|
scount = scount-1;
|
|
utempl = (scount<<16) | bol;
|
|
put32(utempl, ea); /* update the semaphore */
|
|
if (inst & 4) { /* interrupt notify */
|
|
if (inst & 2) /* clear active interrupt */
|
|
intvec = 0;
|
|
/* not sure about all this... Case 85/87 */
|
|
if (regs.sym.pcba == crs[OWNERL]) {
|
|
RP = regs.sym.pswpb;
|
|
crs[KEYS] = regs.sym.pswkeys;
|
|
}
|
|
}
|
|
if (resched || (inst & 4))
|
|
dispatcher();
|
|
}
|
|
|
|
|
|
lpsw() {
|
|
ea_t ea;
|
|
unsigned short m;
|
|
|
|
if (T_PX) printf("\n%o/%o: LPSW issued\n", RPH, RPL);
|
|
RESTRICT();
|
|
if (T_PX) printf("LPSW: before load, RPH=%o, RPL=%o, keys=%o, modals=%o\n", RPH, RPL, crs[KEYS], crs[MODALS]);
|
|
if (T_PX) printf("LPSW: crs=%d, ownerl[2]=%o, keys[2]=%o, modals[2]=%o, ownerl[3]=%o, keys[3]=%o, modals[3]=%o\n", crs==regs.rs16[2]? 2:3, regs.rs16[2][OWNERL], regs.rs16[2][KEYS], regs.rs16[2][MODALS], regs.rs16[3][OWNERL], regs.rs16[3][KEYS], regs.rs16[3][MODALS]);
|
|
ea = apea(NULL);
|
|
RPH = get16(ea);
|
|
RPL = get16(INCVA(ea,1));
|
|
newkeys(get16(INCVA(ea,2)));
|
|
m = get16(INCVA(ea,3));
|
|
if ((m & 0340) != (crs[MODALS] & 0340))
|
|
if (T_PX) printf("LPSW: WARNING: changed current register set: current modals=%o, new modals=%o\n", crs[MODALS], m);
|
|
crs[MODALS] = m;
|
|
if (T_PX) printf("LPSW: NEW RPH=%o, RPL=%o, keys=%o, modals=%o\n", RPH, RPL, crs[KEYS], crs[MODALS]);
|
|
if (T_PX) printf("LPSW: crs=%d, ownerl[2]=%o, keys[2]=%o, modals[2]=%o, ownerl[3]=%o, keys[3]=%o, modals[3]=%o\n", crs==regs.rs16[2]? 2:3, regs.rs16[2][OWNERL], regs.rs16[2][KEYS], regs.rs16[2][MODALS], regs.rs16[3][OWNERL], regs.rs16[3][KEYS], regs.rs16[3][MODALS]);
|
|
if (crs[MODALS] & 020)
|
|
if (T_PX) fprintf(stderr,"Mapped I/O enabled\n");
|
|
if (crs[MODALS] & 4) {
|
|
if (T_PX) fprintf(stderr,"Segmentation enabled\n");
|
|
if (domemdump) dumpsegs();
|
|
//traceflags = ~TB_MAP;
|
|
}
|
|
if (crs[MODALS] & 010) {
|
|
if (T_PX) fprintf(stderr,"Process exchange enabled:\n");
|
|
if (T_PX) printf("LPSW: PLA=%o, PCBA=%o, PLB=%o, PCBB=%o\n", regs.sym.pla, regs.sym.pcba, regs.sym.plb, regs.sym.pcbb);
|
|
#if 0
|
|
for (i=regs.sym.pla;; i += 2) {
|
|
ea = MAKEVA(crs[OWNERH], i);
|
|
utempa = get16(ea);
|
|
if (T_PX) fprintf(stderr," Level %o: BOL=%o, EOL=%o\n", i, utempa, get16(ea+1));
|
|
if (utempa == 1)
|
|
break;
|
|
while (utempa > 0)
|
|
utempa = dumppcb(utempa);
|
|
}
|
|
#endif
|
|
//traceflags = ~TB_MAP;
|
|
if (crs[KEYS] & 2) {
|
|
if (T_PX) printf("LPSW: before disp, RPH=%o, RPL=%o, keys=%o, modals=%o\n", RPH, RPL, crs[KEYS], crs[MODALS]);
|
|
dispatcher();
|
|
if (T_PX) printf("LPSW: after disp, RPH=%o, RPL=%o, keys=%o, modals=%o\n", RPH, RPL, crs[KEYS], crs[MODALS]);
|
|
if (T_PX) printf("LPSW: crs=%d, ownerl[2]=%o, keys[2]=%o, modals[2]=%o, ownerl[3]=%o, keys[3]=%o, modals[3]=%o\n", crs==regs.rs16[2]? 2:3, regs.rs16[2][OWNERL], regs.rs16[2][KEYS], regs.rs16[2][MODALS], regs.rs16[3][OWNERL], regs.rs16[3][KEYS], regs.rs16[3][MODALS]);
|
|
}
|
|
}
|
|
#if 0
|
|
/* XXX: hack to disable serial number checking if E32I is enabled.
|
|
Look for ERA/ANA sequence after illegal shift instruction, set
|
|
the ANA operand to zero. */
|
|
|
|
ea = MAKEVA(014,040747);
|
|
put16(0,ea);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Character instructions */
|
|
|
|
ldc(n) {
|
|
unsigned int utempl;
|
|
unsigned short m;
|
|
unsigned short far, flr;
|
|
|
|
far = FAR0;
|
|
flr = FLR0;
|
|
if (n) {
|
|
far = FAR1;
|
|
flr = FLR1;
|
|
}
|
|
|
|
utempl = GETFLR(n);
|
|
if (utempl > 0) {
|
|
m = get16(crsl[far]);
|
|
if (crsl[flr] & 0x8000) {
|
|
crs[A] = m & 0xFF;
|
|
crsl[flr] &= 0xFFFF0FFF;
|
|
crsl[far] = (crsl[far]+1) & 0x6FFFFFFF;
|
|
} else {
|
|
crs[A] = m >> 8;
|
|
crsl[flr] |= 0x8000;
|
|
}
|
|
utempl--;
|
|
PUTFLR(n,utempl);
|
|
crs[KEYS] &= ~0100; /* reset EQ */
|
|
} else { /* utempl == 0 */
|
|
crs[A] = 0;
|
|
crs[KEYS] |= 0100; /* set EQ */
|
|
}
|
|
}
|
|
|
|
|
|
stc(n) {
|
|
unsigned int utempl;
|
|
unsigned short m;
|
|
unsigned short far, flr;
|
|
|
|
far = FAR0;
|
|
flr = FLR0;
|
|
if (n) {
|
|
far = FAR1;
|
|
flr = FLR1;
|
|
}
|
|
|
|
utempl = GETFLR(n);
|
|
if (utempl > 0) {
|
|
m = get16(crsl[far]);
|
|
if (crsl[flr] & 0x8000) {
|
|
m = (m & 0xFF00) | (crs[A] & 0xFF);
|
|
put16(m,crsl[far]);
|
|
crsl[flr] &= 0xFFFF0FFF;
|
|
crsl[far] = (crsl[far]+1) & 0x6FFFFFFF;
|
|
} else {
|
|
m = (m & 0xFF) | (crs[A] << 8);
|
|
put16(m,crsl[far]);
|
|
crsl[flr] |= 0x8000;
|
|
}
|
|
utempl--;
|
|
PUTFLR(n,utempl);
|
|
crs[KEYS] &= ~0100; /* reset EQ */
|
|
} else { /* utempl == 0 */
|
|
crs[A] = 0;
|
|
crs[KEYS] |= 0100; /* set EQ */
|
|
}
|
|
}
|
|
|
|
|
|
main (int argc, char **argv) {
|
|
|
|
short tempa,tempa1,tempa2;
|
|
unsigned short utempa;
|
|
int templ,templ1,templ2;
|
|
long long templl;
|
|
unsigned int utempl,utempl1,utempl2;
|
|
float tempf,tempf1,tempf2;
|
|
double tempd,tempd1,tempd2;
|
|
unsigned short tempda[4],tempda1[4];
|
|
unsigned int ea32; /* full V/I mode eff address */
|
|
ea_t ea; /* final MR effective address */
|
|
ea_t earp; /* RP to use for eff address calcs */
|
|
unsigned short eabit;
|
|
unsigned short opcode;
|
|
short i,j,x;
|
|
unsigned short savemask;
|
|
unsigned short class;
|
|
int nw;
|
|
unsigned short rvec[9]; /* SA, EA, P, A, B, X, keys, dummy, dummy */
|
|
unsigned short inst;
|
|
unsigned short m,m1,m2;
|
|
unsigned short qtop,qbot,qseg,qmask,qtemp;
|
|
ea_t qea;
|
|
short scount; /* shift count */
|
|
unsigned short trapvalue;
|
|
ea_t trapaddr;
|
|
unsigned short stpm[8];
|
|
|
|
unsigned int instpermsecmask = 03777; /* initially assume 2048 inst/msec */
|
|
unsigned long long bootmsec; /* time we booted */
|
|
unsigned long long curmsec; /* current time in milliseconds */
|
|
|
|
struct timeval boot_tv;
|
|
struct timeval tv;
|
|
struct timezone tz;
|
|
float mips;
|
|
|
|
/* master clear:
|
|
- clear all registers
|
|
- register set is 2
|
|
- set P to '1000
|
|
- 16S mode, single precision
|
|
- interrupts and machine checks inhibited
|
|
- standard interrupt mode
|
|
*/
|
|
|
|
for (i=0; i < 32*REGSETS; i++)
|
|
regs.u32[i] = 0;
|
|
crs = (void *)regs.rs[2]; /* boot w/register set 2 */
|
|
crsl = (void *)crs;
|
|
crs[MODALS] = 0100;
|
|
newkeys(0);
|
|
RPL = 01000;
|
|
|
|
verbose = 0;
|
|
domemdump = 0;
|
|
boot = 0;
|
|
|
|
/* check args */
|
|
|
|
for (i=1; i<argc; i++) {
|
|
if (strcmp(argv[i],"--vv") == 0)
|
|
verbose = 2;
|
|
else if (strcmp(argv[i],"--v") == 0)
|
|
verbose = 1;
|
|
else if (strcmp(argv[i],"--memdump") == 0)
|
|
domemdump = 1;
|
|
else if (strcmp(argv[i],"--ss") == 0) {
|
|
if (i+1 < argc && argv[i+1][0] != '-') {
|
|
sscanf(argv[i+1],"%o", &templ);
|
|
sswitch = templ;
|
|
} else
|
|
sswitch = 0;
|
|
} else if (strcmp(argv[i],"--cpuid") == 0) {
|
|
if (i+1 < argc && argv[i+1][0] != '-') {
|
|
sscanf(argv[i+1],"%d", &templ);
|
|
cpuid = templ;
|
|
} else
|
|
cpuid = 0;
|
|
} else if (strcmp(argv[i],"--trace") == 0)
|
|
while (i+1 < argc && argv[i+1][0] != '-') {
|
|
if (strcmp(argv[i+1],"ear") == 0)
|
|
traceflags |= TB_EAR;
|
|
else if (strcmp(argv[i+1],"eav") == 0)
|
|
traceflags |= TB_EAV;
|
|
else if (strcmp(argv[i+1],"eai") == 0)
|
|
traceflags |= TB_EAI;
|
|
else if (strcmp(argv[i+1],"inst") == 0)
|
|
traceflags |= TB_INST;
|
|
else if (strcmp(argv[i+1],"flow") == 0)
|
|
traceflags |= TB_FLOW;
|
|
else if (strcmp(argv[i+1],"mode") == 0)
|
|
traceflags |= TB_MODE;
|
|
else if (strcmp(argv[i+1],"eaap") == 0)
|
|
traceflags |= TB_EAAP;
|
|
else if (strcmp(argv[i+1],"dio") == 0)
|
|
traceflags |= TB_DIO;
|
|
else if (strcmp(argv[i+1],"map") == 0)
|
|
traceflags |= TB_MAP;
|
|
else if (strcmp(argv[i+1],"pcl") == 0)
|
|
traceflags |= TB_PCL;
|
|
else if (strcmp(argv[i+1],"fault") == 0)
|
|
traceflags |= TB_FAULT;
|
|
else if (strcmp(argv[i+1],"px") == 0)
|
|
traceflags |= TB_PX;
|
|
else if (strcmp(argv[i+1],"all") == 0)
|
|
traceflags = -1;
|
|
else
|
|
fprintf(stderr,"Unrecognized trace flag: %s\n", argv[i+1]);
|
|
i++;
|
|
}
|
|
else if (strcmp(argv[i],"--boot") == 0)
|
|
boot = 1;
|
|
else if (argv[i][0] == '-' && argv[i][1] == '-')
|
|
fprintf(stderr,"Unrecognized argument: %s\n", argv[i]);
|
|
}
|
|
|
|
fprintf(stderr,"Sense switches set to %o\n", sswitch);
|
|
|
|
os_init();
|
|
|
|
if (boot) {
|
|
rvec[0] = 0760;
|
|
rvec[1] = 0760+1040-1;
|
|
rvec[2] = 01000;
|
|
rvec[3] = rvec[4] = rvec[5] = 0;
|
|
rvec[6] = 0;
|
|
/* setup DMA register '21 for the next boot record */
|
|
regs.sym.regdmx[041] = 03000;
|
|
|
|
} else {
|
|
|
|
/* read 9-word rvec header */
|
|
|
|
for (i=0; i<9; i++)
|
|
rvec[i] = readshort();
|
|
if (T_FLOW) fprintf(stderr,"SA=%o, EA=%o, P=%o, A=%o, B=%o, X=%o, K=%o\n\n", rvec[0], rvec[1],
|
|
rvec[2], rvec[3], rvec[4], rvec[5], rvec[6]);
|
|
if (rvec[2] > rvec[1])
|
|
fatal("Program start > EA: runfile is trashed");
|
|
}
|
|
|
|
/* read memory image from SA to EA inclusive */
|
|
|
|
nw = rvec[1]-rvec[0]+1;
|
|
if (fread(mem+rvec[0], sizeof(short), nw, stdin) != nw) {
|
|
perror("Error reading memory image");
|
|
fatal(NULL);
|
|
}
|
|
|
|
/* setup execution (registers, keys, address mask, etc.) from rvec */
|
|
|
|
crs[A] = rvec[3];
|
|
crs[B] = rvec[4];
|
|
crs[X] = rvec[5];
|
|
newkeys(rvec[6]);
|
|
RPL = rvec[2];
|
|
|
|
if (RPL == 0161000) /* hack for *DOS64; P is off by 3?? */
|
|
RPL = 0161003;
|
|
|
|
if (domemdump)
|
|
memdump(rvec[0], rvec[1]);
|
|
|
|
/* initialize the timer stuff */
|
|
|
|
if (gettimeofday(&boot_tv, &tz) != 0) {
|
|
perror("gettimeofday failed");
|
|
fatal(NULL);
|
|
}
|
|
|
|
/* main instruction decode loop */
|
|
|
|
trapaddr = 0144003;
|
|
trapvalue = -12345;
|
|
trapaddr = 0;
|
|
|
|
/* faults longjmp here: the top of the instruction fetch loop */
|
|
|
|
if (setjmp(jmpbuf))
|
|
;
|
|
|
|
while (1) {
|
|
|
|
if (trapaddr != 0 && mem[trapaddr] != trapvalue) {
|
|
printf("TRAP: at #%d, old value of '%o was %o; new value is %o\n", instcount, trapaddr, trapvalue, mem[trapaddr]);
|
|
trapvalue = mem[trapaddr];
|
|
}
|
|
#if 0
|
|
if (*(int *)(crs+XB) != 0) {
|
|
fprintf(stderr, "TRAP: at #%d, XB% changed to %o/%o\n", instcount, crs[XBH], crs[XBL]);
|
|
}
|
|
#endif
|
|
|
|
/* is an interrupt pending? */
|
|
|
|
if (intvec != 0) {
|
|
printf("fetch: taking interrupt vector '%o\n", intvec);
|
|
regs.sym.pswpb = RP;
|
|
regs.sym.pswkeys = crs[KEYS];
|
|
RPH = 4;
|
|
RPL = intvec;
|
|
crs[KEYS] = 014000;
|
|
intvec = 0;
|
|
}
|
|
|
|
/* as a speedup later, fetch 32/64 bits (or the rest of the page)
|
|
and maintain a prefetch queue */
|
|
|
|
prevpc = RP;
|
|
inst = get16(RP);
|
|
RPL++;
|
|
instcount++;
|
|
|
|
/* while a process is running, RP is the real program counter, PBH
|
|
is the active procedure segment, and PBL is zero. When a
|
|
process stops running, RP is copied to PB. When a process
|
|
starts running again, PB is copied to RP. See seg14.pma,
|
|
WRMSAV. */
|
|
|
|
crs[PBH] = RPH;
|
|
crs[PBL] = 0;
|
|
earp = RP;
|
|
if (crs[MODALS] & 010) { /* px enabled, bump 1ms process timer */
|
|
if ((instcount & instpermsecmask) == 0) {
|
|
|
|
#if 0
|
|
/* bump all timers, applying corrections based on actual time
|
|
if necessary */
|
|
|
|
if (!gettimeofday(&tv, &tz))
|
|
fatal("em: gettimeofday failed");
|
|
#endif
|
|
|
|
/* if 1ms resolution process timer overflows, set pcb abort flag */
|
|
|
|
if (++crs[TIMER] == 0) {
|
|
if (T_PX) printf("pcb %o timer overflow\n", crs[OWNERL]);
|
|
ea = *(ea_t *)(crs+OWNER);
|
|
m = get16(ea+4) | 1;
|
|
put16(m, ea+4);
|
|
fault(PROCESSFAULT, utempa, 0);
|
|
fatal("fault returned after process fault");
|
|
}
|
|
//printf("incremented timer to %d\n", *(short *)(crs+TIMER));
|
|
}
|
|
}
|
|
|
|
|
|
xec:
|
|
if (T_FLOW) fprintf(stderr,"\n%o/%o: %o A='%o/%:0d B='%o/%d X=%o/%d Y=%o/%d C=%d L=%d LT=%d EQ=%d #%d [%o]\n", RPH, RPL-1, inst, crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B), crs[X], *(short *)(crs+X), crs[Y], *(short *)(crs+Y), (crs[KEYS]&0100000) != 0, (crs[KEYS]&040000) != 0, (crs[KEYS]&0200) != 0, (crs[KEYS]&0100) != 0, instcount, crs[OWNERL]);
|
|
|
|
/* begin instruction decode: generic? */
|
|
|
|
if ((inst & 036000) == 0) {
|
|
if (T_INST) fprintf(stderr," generic\n");
|
|
class = inst>>14;
|
|
if (class == 0) {
|
|
if (T_INST) fprintf(stderr," generic class 0\n");
|
|
|
|
if (inst == 000005) { /* SGL */
|
|
if (T_FLOW) fprintf(stderr," SGL\n");
|
|
newkeys(crs[KEYS] & ~040000);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000011) { /* E16S */
|
|
if (T_FLOW) fprintf(stderr," E16S\n");
|
|
newkeys(crs[KEYS] & 0161777);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000013) { /* E32S */
|
|
if (T_FLOW) fprintf(stderr," E32S\n");
|
|
newkeys((crs[KEYS] & 0161777) | 1<<10);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001013) { /* E32R */
|
|
if (T_FLOW) fprintf(stderr," E32R\n");
|
|
newkeys((crs[KEYS] & 0161777) | 3<<10);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001011) { /* E64R */
|
|
if (T_FLOW) fprintf(stderr," E64R\n");
|
|
newkeys((crs[KEYS] & 0161777) | 2<<10);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000010) { /* E64V */
|
|
if (T_FLOW) fprintf(stderr," E64V\n");
|
|
newkeys((crs[KEYS] & 0161777) | 6<<10);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001010) { /* E32I */
|
|
if (T_FLOW) fprintf(stderr," E32I\n");
|
|
fault(RESTRICTFAULT, 0, 0);
|
|
newkeys((crs[KEYS] & 0161777) | 4<<10);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000505) { /* SVC */
|
|
if (T_FLOW) fprintf(stderr," SVC\n");
|
|
svc();
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000111) { /* CEA */
|
|
if (T_FLOW) fprintf(stderr," CEA\n");
|
|
switch ((crs[KEYS] & 016000) >> 10) {
|
|
case 0: /* 16S */
|
|
ea = crs[A];
|
|
i = ea & 0100000;
|
|
x = ea & 040000;
|
|
ea &= 037777;
|
|
while (1) {
|
|
if (x) /* indexed */
|
|
ea += crs[X];
|
|
if (!i) /* not indirect */
|
|
break;
|
|
if (ea < 040)
|
|
m = get16(0x80000000|ea);
|
|
else
|
|
m = get16(ea);
|
|
i = m & 0100000;
|
|
x = m & 040000;
|
|
ea = m & 037777; /* go indirect */
|
|
}
|
|
crs[A] = ea;
|
|
break;
|
|
case 1: /* 32S */
|
|
case 3: /* 32R */
|
|
while (crs[A] & 0100000) {
|
|
ea = crs[A] & 077777;
|
|
if (ea < 040)
|
|
crs[A] = get16(0x80000000|ea);
|
|
else
|
|
crs[A] = get16(ea);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000000) {
|
|
if (T_FLOW) fprintf(stderr," HLT\n");
|
|
RESTRICT();
|
|
fatal("Program halt");
|
|
}
|
|
|
|
if (inst == 000201) {
|
|
if (T_FLOW) fprintf(stderr," IAB\n");
|
|
tempa = crs[B];
|
|
crs[B] = crs[A];
|
|
crs[A] = tempa;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000205) { /* PIM (R-mode) */
|
|
if (T_FLOW) fprintf(stderr," PIM\n");
|
|
crs[A] = crs[B] | (crs[A] & 0x8000);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000211) { /* PID (R-mode) */
|
|
if (T_FLOW) fprintf(stderr," PID\n");
|
|
*(int *)(crs+L) = *(short *)(crs+A);
|
|
crs[B] &= 0x7fff;
|
|
continue;
|
|
}
|
|
|
|
/* DBL activates 31-bit mode (R-mode only):
|
|
|
|
LDA -> DLD (double load)
|
|
STA -> DST (double store)
|
|
ADD -> DAD (double add)
|
|
SUB -> DSB (double subtract)
|
|
|
|
Other R-mode, 31-bit instructions include:
|
|
|
|
PID, DIV, MPY, PIM, INT, FLOT
|
|
*/
|
|
|
|
if (inst == 000007) { /* DBL */
|
|
if (T_FLOW) fprintf(stderr," DBL\n");
|
|
newkeys(crs[KEYS] | 040000);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001314) {
|
|
if (T_FLOW) fprintf(stderr," CGT\n");
|
|
tempa = get16(RP); /* get number of words */
|
|
if (1 <= crs[A] && crs[A] < tempa)
|
|
RPL = get16(INCVA(RP,crs[A]));
|
|
else
|
|
RPL += tempa;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000115) {
|
|
if (T_FLOW) fprintf(stderr," PIDA\n");
|
|
*(int *)(crs+L) = *(short *)(crs+A);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000305) {
|
|
if (T_FLOW) fprintf(stderr," PIDL\n");
|
|
#if 0
|
|
*(int *)(crs+E) = *(int *)(crs+L);
|
|
*(int *)(crs+L) = (int)(*(int *)(crs+L) & 0x80000000) >> 31;
|
|
#else
|
|
*(long long *)(crs+L) = *(int *)(crs+L);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
/* XXX: how does PIMA affect registers when overflow occurs?
|
|
NOTE: PMA manual says copy B reg to A reg, but DIAG seems
|
|
to indicate a swap */
|
|
|
|
if (inst == 000015) {
|
|
if (T_FLOW) fprintf(stderr," PIMA\n");
|
|
tempa = crs[B];
|
|
crs[B] = crs[A];
|
|
crs[A] = tempa;
|
|
SETL(0);
|
|
SETCC_A;
|
|
if (((crs[A] ^ crs[B]) & 0x8000) || (crs[B] != 0 && crs[B] != 0xFFFF))
|
|
mathexception('i', FC_INT_OFLOW, 0);
|
|
else
|
|
CLEARC;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000301) {
|
|
if (T_FLOW) fprintf(stderr," PIML\n");
|
|
templ = *(int *)(crs+L);
|
|
*(int *)(crs+L) = *(int *)(crs+E);
|
|
SETL(0);
|
|
SETCC_L;
|
|
/* this is broken: see CPU.INTEGER.V Case 6 */
|
|
if (((templ ^ crs[E]) & 0x8000) || (templ != 0 && templ != -1))
|
|
mathexception('i', FC_INT_OFLOW, 0);
|
|
else
|
|
CLEARC;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001300) {
|
|
if (T_FLOW) fprintf(stderr," EAFA 0\n");
|
|
ea = apea(&eabit);
|
|
crsl[FAR0] = ea;
|
|
crsl[FLR0] = (crs[FLR0] & 0xFFFF0FFF) | (eabit << 12);
|
|
if (T_INST) fprintf(stderr," FAR=%o, eabit=%d, FLR=%x\n", crsl[FAR0], eabit, crsl[FLR0]);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001310) {
|
|
if (T_FLOW) fprintf(stderr," EAFA 1\n");
|
|
ea = apea(&eabit);
|
|
crsl[FAR1] = ea;
|
|
crsl[FLR1] = (crs[FLR1] & 0xFFFF0FFF) | (eabit << 12);
|
|
if (T_INST) fprintf(stderr," FAR=%o, eabit=%d, FLR=%x\n", crsl[FAR1], eabit, crsl[FLR1]);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001301) {
|
|
if (T_FLOW) fprintf(stderr," ALFA 0\n");
|
|
utempl = ((crsl[FAR0] & 0xFFFF) << 4) | ((crsl[FLR0] >> 12) & 0xF);
|
|
utempl += *(int *)(crs+L);
|
|
crsl[FAR0] = (crsl[FAR0] & 0xFFFF0000) | ((utempl >> 4) & 0xFFFF);
|
|
crsl[FLR0] = (crsl[FLR0] & 0xFFFF0FFF) | ((utempl & 0xF) << 12);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001311) {
|
|
if (T_FLOW) fprintf(stderr," ALFA 1\n");
|
|
utempl = ((crsl[FAR1] & 0xFFFF) << 4) | ((crsl[FLR1] >> 12) & 0xF);
|
|
utempl += *(int *)(crs+L);
|
|
crsl[FAR1] = (crsl[FAR1] & 0xFFFF0000) | ((utempl >> 4) & 0xFFFF);
|
|
crsl[FLR1] = (crsl[FLR1] & 0xFFFF0FFF) | ((utempl & 0xF) << 12);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001303) {
|
|
if (T_FLOW) fprintf(stderr," LFLI 0\n");
|
|
#if 0
|
|
for (utempa=0; utempa<256; utempa++) {
|
|
PUTFLR(0,utempa);
|
|
crsl[FLR0] |= 0x4000;
|
|
utempl = GETFLR(0);
|
|
if (utempa != utempl) {
|
|
fprintf(stderr," loaded %d, fetched %d\n", utempa, utempl);
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
utempa = get16(RP);
|
|
RPL++;
|
|
PUTFLR(0,utempa);
|
|
utempl = GETFLR(0);
|
|
if (T_INST) fprintf(stderr," Load Field length with %d, FLR=%x, actual = %d\n", utempa, crsl[FLR0], utempl);
|
|
if (utempa != utempl)
|
|
fatal("LFLI 0 error");
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001313) {
|
|
if (T_FLOW) fprintf(stderr," LFLI 1\n");
|
|
#if 0
|
|
for (utempa=0; utempa<256; utempa++) {
|
|
PUTFLR(1,utempa);
|
|
utempl = GETFLR(1);
|
|
if (utempa != utempl) {
|
|
fprintf(stderr," loaded %d, fetched %d\n", utempa, utempl);
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
utempa = get16(RP);
|
|
RPL++;
|
|
PUTFLR(1,utempa);
|
|
utempl = GETFLR(1);
|
|
if (T_INST) fprintf(stderr," Load Field length with %d, FLR=%x, actual = %d\n", utempa, crsl[FLR1], utempl);
|
|
if (utempa != utempl)
|
|
fatal("LFLI 0 error");
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001320) {
|
|
if (T_FLOW) fprintf(stderr," STFA 0\n");
|
|
ea = apea(NULL);
|
|
utempl = crsl[FAR0] & 0x6FFFFFFF;
|
|
utempa = crsl[FLR0] & 0xF000;
|
|
stfa:
|
|
if (utempa != 0) {
|
|
utempl = utempl | EXTMASK32;
|
|
put16(utempa,INCVA(ea,2));
|
|
}
|
|
put32(utempl,ea);
|
|
continue;
|
|
}
|
|
|
|
|
|
if (inst == 001330) {
|
|
if (T_FLOW) fprintf(stderr," STFA 1\n");
|
|
ea = apea(NULL);
|
|
utempl = crsl[FAR1] & 0x6FFFFFFF;
|
|
utempa = crsl[FLR1] & 0xF000;
|
|
goto stfa;
|
|
}
|
|
|
|
if (inst == 001321) {
|
|
if (T_FLOW) fprintf(stderr," TLFL 0\n");
|
|
PUTFLR(0,*(unsigned int *)(crs+L));
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001331) {
|
|
if (T_FLOW) fprintf(stderr," TLFL 1\n");
|
|
PUTFLR(1,*(unsigned int *)(crs+L));
|
|
continue;
|
|
}
|
|
|
|
|
|
if (inst == 001323) {
|
|
if (T_FLOW) fprintf(stderr," TFLL 0\n");
|
|
*(unsigned int *)(crs+L) = GETFLR(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001333) {
|
|
if (T_FLOW) fprintf(stderr," TFLL 1\n");
|
|
*(unsigned int *)(crs+L) = GETFLR(1);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001302) {
|
|
if (T_FLOW) fprintf(stderr," LDC 0\n");
|
|
ldc(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001312) {
|
|
if (T_FLOW) fprintf(stderr," LDC 1\n");
|
|
ldc(1);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001322) {
|
|
if (T_FLOW) fprintf(stderr," STC 0\n");
|
|
stc(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001332) {
|
|
if (T_FLOW) fprintf(stderr," STC 1\n");
|
|
utempl = GETFLR(1);
|
|
if (T_INST) fprintf(stderr," Before store, FLR=%d\n", utempl);
|
|
if (utempl > 0) {
|
|
m = get16(crsl[FAR1]);
|
|
if (crsl[FLR1] & 0x8000) {
|
|
if (T_INST) fprintf(stderr," Storing right byte\n");
|
|
m = (m & 0xFF00) | (crs[A] & 0xFF);
|
|
put16(m,crsl[FAR1]);
|
|
crsl[FLR1] &= 0xFFFF0FFF;
|
|
crsl[FAR1] = (crsl[FAR1]+1) & 0x6FFFFFFF;
|
|
} else {
|
|
if (T_INST) fprintf(stderr," Storing left byte\n");
|
|
m = (m & 0xFF) | (crs[A] << 8);
|
|
put16(m,crsl[FAR1]);
|
|
crsl[FLR1] |= 0x8000;
|
|
}
|
|
utempl--;
|
|
PUTFLR(1,utempl);
|
|
if (T_INST) fprintf(stderr," After store, FLR=%d\n", GETFLR(1));
|
|
crs[KEYS] &= ~0100; /* reset EQ */
|
|
} else if (utempl == 0) {
|
|
crs[A] = 0;
|
|
crs[KEYS] |= 0100; /* set EQ */
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000611) {
|
|
//traceflags = ~TB_MAP;
|
|
if (T_FLOW) fprintf(stderr," PRTN\n");
|
|
prtn();
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000041) {
|
|
if (T_FLOW) fprintf(stderr," SCA\n");
|
|
crs[A] = crs[VSC] & 0xFF;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000043) {
|
|
if (T_FLOW) fprintf(stderr," INK\n");
|
|
crs[A] = (crs[KEYS] & 0xFF00) | (crs[VSC] & 0xFF);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001005) {
|
|
if (T_FLOW) fprintf(stderr," TKA\n");
|
|
//printf("TKA: %o -> A\n", crs[KEYS]);
|
|
crs[A] = crs[KEYS];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000405) {
|
|
if (T_FLOW) fprintf(stderr," OTK\n");
|
|
newkeys((crs[A] & 0xFF00) | (crs[KEYS] & 0xFF));
|
|
crs[VSC] = crs[A] & 0xFF;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001015) {
|
|
if (T_FLOW) fprintf(stderr," TAK\n");
|
|
//printf("TAK: %o -> KEYS\n", crs[A]);
|
|
newkeys(crs[A] & 0177760);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000001) {
|
|
if (T_FLOW) fprintf(stderr," NOP\n");
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000715) {
|
|
if (T_FLOW) fprintf(stderr," RSAV\n");
|
|
ea = apea(NULL);
|
|
j = 1;
|
|
savemask = 0;
|
|
for (i = 11; i >= 0; i--) {
|
|
if (crsl[i] != 0) {
|
|
if (T_INST) fprintf(stderr," crsl[%d] saved, value=%o\n", i, crsl[i]);
|
|
put32(crsl[i], INCVA(ea,j));
|
|
savemask |= bitmask16[16-i];
|
|
}
|
|
j += 2;
|
|
}
|
|
put32(*(int *)(crs+XB), INCVA(ea,25));
|
|
put16(savemask, ea);
|
|
if (T_INST) fprintf(stderr," Saved, mask=%o\n", savemask);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000717) {
|
|
if (T_FLOW) fprintf(stderr," RRST\n");
|
|
ea = apea(NULL);
|
|
savemask = get16(ea);
|
|
//if (T_INST) fprintf(stderr," %o/%o: RRST %o/%o, mask=%o, modals=%o\n", RPH,RPL,ea>>16,ea&0xffff,savemask,crs[MODALS]);
|
|
if (T_INST) fprintf(stderr," Save mask=%o\n", savemask);
|
|
j = 1;
|
|
for (i = 11; i >= 0; i--) {
|
|
if (savemask & bitmask16[16-i]) {
|
|
crsl[i] = get32(INCVA(ea,j));
|
|
if (T_INST) fprintf(stderr," crsl[%d] restored, value=%o\n", i, crsl[i]);
|
|
} else {
|
|
crsl[i] = 0;
|
|
}
|
|
j += 2;
|
|
}
|
|
*(unsigned int *)(crs+XB) = get32(INCVA(ea,25));
|
|
if (T_INST) fprintf(stderr," XB restored, value=%o/%o\n", crs[XBH], crs[XBL]);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000101) {
|
|
if (T_FLOW) fprintf(stderr," NRM\n");
|
|
crs[VSC] = 0;
|
|
if (crs[A] == 0 && crs[B] == 0)
|
|
continue;
|
|
while (!((crs[A] ^ (crs[A] << 1)) & 0x8000)) {
|
|
if (T_INST) fprintf(stderr, " step %d: crs[A]=%o, crs[B]=%o\n", crs[VSC], crs[A], crs[B]);
|
|
crs[B] = crs[B] << 1;
|
|
crs[A] = (crs[A] & 0x8000) | ((crs[A] << 1) & 0x7FFE) | (crs[B] >> 15);
|
|
crs[VSC]++;
|
|
}
|
|
crs[B] &= 0x7FFF;
|
|
if (T_INST) fprintf(stderr, " finished with %d shifts: crs[A]=%o, crs[B]=%o\n", crs[VSC], crs[A], crs[B]);
|
|
continue;
|
|
}
|
|
|
|
if (000400 <= inst && inst <= 000402) {
|
|
if (T_FLOW) fprintf(stderr," ENB\n");
|
|
RESTRICT();
|
|
crs[MODALS] &= ~0100000;
|
|
continue;
|
|
}
|
|
|
|
if (001000 <= inst && inst <= 001002) {
|
|
if (T_FLOW) fprintf(stderr," INH\n");
|
|
RESTRICT();
|
|
crs[MODALS] |= 0100000;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 01200) {
|
|
if (T_FLOW) fprintf(stderr," STAC\n");
|
|
ea = apea(NULL);
|
|
if (get16(ea) == crs[B]) {
|
|
put16(crs[A], ea);
|
|
crs[KEYS] |= 0100; /* set EQ */
|
|
} else
|
|
crs[KEYS] &= ~0100; /* reset EQ */
|
|
continue;
|
|
}
|
|
|
|
if (inst == 01204) {
|
|
if (T_FLOW) fprintf(stderr," STLC\n");
|
|
ea = apea(NULL);
|
|
if (get32(ea) == *(int *)(crs+E)){
|
|
put32(*(int *)(crs+L), ea);
|
|
crs[KEYS] |= 0100; /* set EQ */
|
|
} else
|
|
crs[KEYS] &= ~0100; /* reset EQ */
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000415) {
|
|
if (T_FLOW) fprintf(stderr," ESIM\n");
|
|
RESTRICT();
|
|
crs[MODALS] &= ~040000;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000417) {
|
|
if (T_FLOW) fprintf(stderr," EVIM\n");
|
|
RESTRICT();
|
|
crs[MODALS] |= 040000;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000605) {
|
|
if (T_FLOW || T_PCL) fprintf(stderr," ARGT\n");
|
|
argt();
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000705) {
|
|
if (T_FLOW || T_PCL) fprintf(stderr," CALF\n");
|
|
ea = apea(NULL);
|
|
calf(ea);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000711) {
|
|
if (T_FLOW) fprintf(stderr," LPSW\n");
|
|
lpsw();
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000105) {
|
|
if (T_FLOW) fprintf(stderr," RTN\n");
|
|
m = get16(crs[S]+1);
|
|
if (m == 0)
|
|
fatal("RTN stack underflow");
|
|
crs[S] = get16(crs[S]);
|
|
continue;
|
|
}
|
|
|
|
/* Decimal and character instructions */
|
|
/* NOTE: ZFIL is used early after PX enabled, and can be used to cause
|
|
a UII fault and debug CALF etc. */
|
|
|
|
#if 0
|
|
if (inst == 001114) {
|
|
if (T_FLOW) fprintf(stderr," ZMV\n", inst);
|
|
utempa = crs[A];
|
|
do {
|
|
ldc(0);
|
|
if (crs[KEYS] & 0100)
|
|
crs[A] = 0240;
|
|
stc(1);
|
|
} while (!(crs[KEYS] & 0100));
|
|
crs[A] = utempa;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001114) {
|
|
if (T_FLOW) fprintf(stderr," ZMVD\n", inst);
|
|
utempa = crs[A];
|
|
utempl = GETFLR(0);
|
|
PUTFLR(0, 65535);
|
|
do {
|
|
ldc(0);
|
|
stc(1);
|
|
} while (!(crs[KEYS] & 0100));
|
|
crs[A] = utempa;
|
|
PUTFLR(0, utempl);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001116) {
|
|
if (T_FLOW) fprintf(stderr," ZFIL\n", inst);
|
|
do {
|
|
stc(1);
|
|
} while (!(crs[KEYS] & 0100));
|
|
continue;
|
|
}
|
|
#else
|
|
if (001100 <= inst && inst <= 001146) {
|
|
//traceflags = -1;
|
|
if (T_FLOW) fprintf(stderr," X/Z UII %o\n", inst);
|
|
fault(UIIFAULT, RPL, RP);
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
if (inst == 000315) {
|
|
if (T_FLOW) fprintf(stderr," WAIT\n", inst);
|
|
wait();
|
|
continue;
|
|
}
|
|
|
|
if (001210 <= inst && inst <= 001217) {
|
|
if (001212 <= inst && inst <= 001213)
|
|
fatal("Unrecognized NFY instruction");
|
|
if (T_FLOW) fprintf(stderr," NFY(%o)\n", inst);
|
|
nfy(inst);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000024) {
|
|
if (T_FLOW) fprintf(stderr," STPM\n", inst);
|
|
for (i=0; i<8; i++)
|
|
stpm[i] = 0;
|
|
stpm[1] = cpuid;
|
|
ea = *(unsigned int *)(crs+XB);
|
|
put64(*(double *)(stpm+0), ea);
|
|
put64(*(double *)(stpm+4), INCVA(ea,4));
|
|
continue;
|
|
}
|
|
|
|
if (inst == 001702) {
|
|
if (T_FLOW) fprintf(stderr," IDLE?\n", inst);
|
|
RESTRICT();
|
|
dispatcher();
|
|
continue;
|
|
}
|
|
|
|
if (inst == 000601) {
|
|
if (T_FLOW) fprintf(stderr," IRTN\n", inst);
|
|
RESTRICT();
|
|
//fatal("IRTN causes a loop in CPU.CACHE Case 4");
|
|
if (regs.sym.pcba != 0) {
|
|
RP = regs.sym.pswpb;
|
|
crs[KEYS] = regs.sym.pswkeys;
|
|
} else
|
|
crs[OWNERL] = 0;
|
|
dispatcher();
|
|
continue;
|
|
}
|
|
|
|
/* unusual restricted instructions */
|
|
|
|
if (inst == 3) {
|
|
if (T_FLOW) fprintf(stderr,"gen 3?\n");
|
|
printf("#%d: %o/%o: Generic instruction 3?\n", instcount, RPH, RPL);
|
|
continue;
|
|
}
|
|
|
|
for (i=0; i<GEN0TABSIZE; i++) {
|
|
if (inst == gen0tab[i]) {
|
|
if (T_FLOW) fprintf(stderr," %s\n", gen0nam[i]);
|
|
break;
|
|
}
|
|
}
|
|
if (i < GEN0TABSIZE)
|
|
continue;
|
|
|
|
if (T_INST) fprintf(stderr," unrecognized generic class 0 instruction!\n");
|
|
printf(" unrecognized generic class 0 instruction %o!\n", inst);
|
|
|
|
fault(UIIFAULT, RPL, 0);
|
|
fatal(NULL);
|
|
}
|
|
|
|
if (class == 3) {
|
|
if (T_INST) fprintf(stderr," generic class 3\n");
|
|
|
|
if (inst == 0141604) {
|
|
if (T_FLOW) fprintf(stderr," BCLT\n");
|
|
bclt:
|
|
if (crs[KEYS] & 0200)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141600) {
|
|
if (T_FLOW) fprintf(stderr," BCLE\n");
|
|
bcle:
|
|
if (crs[KEYS] & 0300)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141602) {
|
|
if (T_FLOW) fprintf(stderr," BCEQ\n");
|
|
bceq:
|
|
if (crs[KEYS] & 0100)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141603) {
|
|
if (T_FLOW) fprintf(stderr," BCNE\n");
|
|
bcne:
|
|
if (!(crs[KEYS] & 0100))
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141605) {
|
|
if (T_FLOW) fprintf(stderr," BCGE\n");
|
|
bcge:
|
|
if (!(crs[KEYS] & 0200))
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141601) {
|
|
if (T_FLOW) fprintf(stderr," BCGT\n");
|
|
bcgt:
|
|
if (!(crs[KEYS] & 0300))
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141705) {
|
|
if (T_FLOW) fprintf(stderr," BCR\n");
|
|
if (!(crs[KEYS] & 0100000))
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141704) {
|
|
if (T_FLOW) fprintf(stderr," BCS\n");
|
|
if (crs[KEYS] & 0100000)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141707) {
|
|
printf("BLR at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BLR\n");
|
|
if (!(crs[KEYS] & 020000))
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141706) {
|
|
printf("BLS at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BLS\n");
|
|
if (crs[KEYS] & 020000)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140614) {
|
|
if (T_FLOW) fprintf(stderr," BLT\n");
|
|
SETCC_A;
|
|
goto bclt;
|
|
}
|
|
|
|
if (inst == 0140610) {
|
|
if (T_FLOW) fprintf(stderr," BLE\n");
|
|
SETCC_A;
|
|
goto bcle;
|
|
}
|
|
|
|
if (inst == 0140612) {
|
|
if (T_FLOW) fprintf(stderr," BEQ\n");
|
|
SETCC_A;
|
|
goto bceq;
|
|
}
|
|
|
|
if (inst == 0140613) {
|
|
if (T_FLOW) fprintf(stderr," BNE\n");
|
|
SETCC_A;
|
|
goto bcne;
|
|
}
|
|
|
|
if (inst == 0140615) {
|
|
if (T_FLOW) fprintf(stderr," BGE\n");
|
|
SETCC_A;
|
|
goto bcge;
|
|
}
|
|
|
|
if (inst == 0140611) {
|
|
if (T_FLOW) fprintf(stderr," BGT\n");
|
|
SETCC_A;
|
|
goto bcgt;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140700) {
|
|
if (T_FLOW) fprintf(stderr," BLLE\n");
|
|
SETCC_L;
|
|
goto bcle;
|
|
}
|
|
|
|
if (inst == 0140702) {
|
|
if (T_FLOW) fprintf(stderr," BLEQ\n");
|
|
SETCC_L;
|
|
goto bceq;
|
|
}
|
|
|
|
if (inst == 0140703) {
|
|
if (T_FLOW) fprintf(stderr," BLNE\n");
|
|
SETCC_L;
|
|
goto bcne;
|
|
}
|
|
|
|
if (inst == 0140701) {
|
|
if (T_FLOW) fprintf(stderr," BLGT\n");
|
|
SETCC_L;
|
|
goto bcgt;
|
|
}
|
|
|
|
if (inst == 0141614) {
|
|
if (T_FLOW) fprintf(stderr," BFLT\n");
|
|
SETCC_F;
|
|
goto bclt;
|
|
}
|
|
|
|
if (inst == 0141610) {
|
|
if (T_FLOW) fprintf(stderr," BFLE\n");
|
|
SETCC_F;
|
|
goto bcle;
|
|
}
|
|
|
|
if (inst == 0141612) {
|
|
if (T_FLOW) fprintf(stderr," BFEQ\n");
|
|
SETCC_F;
|
|
goto bceq;
|
|
}
|
|
|
|
if (inst == 0141613) {
|
|
if (T_FLOW) fprintf(stderr," BFNE\n");
|
|
SETCC_F;
|
|
goto bcne;
|
|
}
|
|
|
|
if (inst == 0141615) {
|
|
if (T_FLOW) fprintf(stderr," BFGE\n");
|
|
SETCC_F;
|
|
goto bcge;
|
|
}
|
|
|
|
if (inst == 0141611) {
|
|
if (T_FLOW) fprintf(stderr," BFGT\n");
|
|
SETCC_F;
|
|
goto bcgt;
|
|
}
|
|
|
|
if (inst == 0141334) {
|
|
if (T_FLOW) fprintf(stderr," BIX\n");
|
|
crs[X]++;
|
|
bidx:
|
|
if (crs[X] != 0)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141324) {
|
|
if (T_FLOW) fprintf(stderr," BIY\n");
|
|
crs[Y]++;
|
|
bidy:
|
|
if (crs[Y] != 0)
|
|
RPL = get16(RP);
|
|
else
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140724) {
|
|
if (T_FLOW) fprintf(stderr," BDY\n");
|
|
crs[Y]--;
|
|
goto bidy;
|
|
}
|
|
|
|
if (inst == 0140734) {
|
|
if (T_FLOW) fprintf(stderr," BDX\n");
|
|
crs[X]--;
|
|
goto bidx;
|
|
}
|
|
|
|
if (inst == 0141206) { /* A1A */
|
|
if (T_FLOW) fprintf(stderr," A1A\n");
|
|
crs[A]++;
|
|
EXPC(crs[A] == 32768);
|
|
SETCC_A;
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140304) { /* A2A */
|
|
if (T_FLOW) fprintf(stderr," A2A\n");
|
|
crs[A] += 2;
|
|
EXPC(*(short *)(crs+A) <= -32767);
|
|
SETCC_A;
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
/* NOTE: confusion here about what changes on overflow */
|
|
|
|
if (inst == 0141216) { /* ACA */
|
|
if (T_FLOW) fprintf(stderr," ACA\n");
|
|
if (crs[KEYS] & 0100000) {
|
|
crs[A]++;
|
|
if (crs[A] == 0100000)
|
|
mathexception('i', FC_INT_OFLOW, 0);
|
|
else
|
|
CLEARC;
|
|
} else
|
|
CLEARC;
|
|
SETCC_A;
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140110) { /* S1A */
|
|
if (T_FLOW) fprintf(stderr," S1A\n");
|
|
crs[A]--;
|
|
EXPC(crs[A] == 32767);
|
|
SETCC_A;
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140310) { /* S2A */
|
|
if (T_FLOW) fprintf(stderr," S2A\n");
|
|
crs[A] -= 2;
|
|
EXPC(*(short *)(crs+A) >= -32766);
|
|
SETCC_A;
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141050) { /* CAL */
|
|
if (T_FLOW) fprintf(stderr," CAL\n");
|
|
crs[A] &= 0xFF;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141044) { /* CAR */
|
|
if (T_FLOW) fprintf(stderr," CAR\n");
|
|
crs[A] &= 0xFF00;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140040) { /* CRA */
|
|
if (T_FLOW) fprintf(stderr," CRA\n");
|
|
crs[A] = 0;
|
|
continue;
|
|
}
|
|
|
|
/* On the P300, the B register is the low-order word of the
|
|
DP floating pt fraction, so CRB was used to convert SPFP
|
|
numbers to DPFP. On the P400 and up, the B register and
|
|
DPFP accumulator do not overlap. For compatibility, there
|
|
are 3 related instructions:
|
|
|
|
'14 clears B and the low-order DPFP register
|
|
'15 clears only B
|
|
'16 clears only the low-order DPFP register
|
|
*/
|
|
|
|
if (inst == 0140014) { /* P300 CRB */
|
|
if (T_FLOW) fprintf(stderr," P300CRB\n");
|
|
crs[B] = 0;
|
|
crs[FLTD] = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140015) { /* CRB */
|
|
if (T_FLOW) fprintf(stderr," CRB\n");
|
|
crs[B] = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140016) { /* FDBL */
|
|
if (T_FLOW) fprintf(stderr," FDBL\n");
|
|
crs[FLTD] = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140010) { /* CRL */
|
|
if (T_FLOW) fprintf(stderr," CRL\n");
|
|
*(int *)(crs+L) = 0;
|
|
continue;
|
|
}
|
|
|
|
/* is this supposed to set C, L, and CC? */
|
|
|
|
if (inst == 0140214) { /* CAZ */
|
|
if (T_FLOW) fprintf(stderr," CAZ\n");
|
|
SETCC_A;
|
|
XSETL(0);
|
|
compskip:
|
|
if (crs[KEYS] & 0200)
|
|
RPL += 2;
|
|
else if (crs[KEYS] & 0100)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
/* NOTE: using "if crs[X]++ == 0" doesn't work because of unsigned
|
|
short type promotion! */
|
|
|
|
if (inst == 0140114) { /* IRX */
|
|
if (T_FLOW) fprintf(stderr," IRX\n");
|
|
crs[X]++;
|
|
if (crs[X] == 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140210) { /* DRX */
|
|
if (T_FLOW) fprintf(stderr," DRX\n");
|
|
crs[X]--;
|
|
if (crs[X] == 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141240) { /* ICR */
|
|
if (T_FLOW) fprintf(stderr," ICR\n");
|
|
crs[A] = crs[A] << 8;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141140) { /* ICL */
|
|
if (T_FLOW) fprintf(stderr," ICL\n");
|
|
crs[A] = crs[A] >> 8;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141340) { /* ICA */
|
|
if (T_FLOW) fprintf(stderr," ICA\n");
|
|
crs[A] = (crs[A] >> 8) | (crs[A] << 8);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140417) { /* LT */
|
|
if (T_FLOW) fprintf(stderr," LT\n");
|
|
crs[A] = 1;
|
|
crs[KEYS] = (crs[KEYS] & ~0300);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140416) { /* LF */
|
|
if (T_FLOW) fprintf(stderr," LF\n");
|
|
crs[A] = 0;
|
|
crs[KEYS] = (crs[KEYS] & ~0300) | 0100;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140314) {
|
|
if (T_FLOW) fprintf(stderr," TAB\n");
|
|
crs[B] = crs[A];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140504) {
|
|
if (T_FLOW) fprintf(stderr," TAX\n");
|
|
crs[X] = crs[A];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140505) {
|
|
if (T_FLOW) fprintf(stderr," TAY\n");
|
|
crs[Y] = crs[A];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140604) {
|
|
if (T_FLOW) fprintf(stderr," TBA\n");
|
|
crs[A] = crs[B];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141034) {
|
|
if (T_FLOW) fprintf(stderr," TXA\n");
|
|
crs[A] = crs[X];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141124) {
|
|
if (T_FLOW) fprintf(stderr," TYA\n");
|
|
crs[A] = crs[Y];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140104) {
|
|
if (T_FLOW) fprintf(stderr," XCA\n");
|
|
crs[B] = crs[A];
|
|
crs[A] = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140204) {
|
|
if (T_FLOW) fprintf(stderr," XCB\n");
|
|
crs[A] = crs[B];
|
|
crs[B] = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140407) {
|
|
if (T_FLOW) fprintf(stderr," TCA\n");
|
|
*(short *)(crs+A) = - (*(short *)(crs+A));
|
|
SETCC_A;
|
|
XSETL(0);
|
|
if (crs[A] != 0x8000) {
|
|
CLEARC;
|
|
} else {
|
|
mathexception('i', FC_INT_OFLOW, 0);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141210) {
|
|
if (T_FLOW) fprintf(stderr," TCL\n");
|
|
*(int *)(crs+L) = - (*(int *)(crs+L));
|
|
SETCC_L;
|
|
SETL(*(int *)(crs+L) == 0);
|
|
if (*(unsigned int *)(crs+L) != 0x80000000) {
|
|
CLEARC;
|
|
} else {
|
|
crs[KEYS] &= ~0200;
|
|
mathexception('i', FC_INT_OFLOW, 0);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140600) {
|
|
if (T_FLOW) fprintf(stderr," SCB\n");
|
|
newkeys(crs[KEYS] | 0100000);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140200) {
|
|
if (T_FLOW) fprintf(stderr," RCB\n");
|
|
newkeys(crs[KEYS] & 077777);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140024) {
|
|
if (T_FLOW) fprintf(stderr," CHS\n");
|
|
crs[A] ^= 0x8000;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140500) {
|
|
if (T_FLOW) fprintf(stderr," SSM\n");
|
|
crs[A] |= 0100000;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140100) {
|
|
if (T_FLOW) fprintf(stderr," SSP\n");
|
|
crs[A] &= 077777;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140401) {
|
|
if (T_FLOW) fprintf(stderr," CMA\n");
|
|
crs[A] = ~crs[A];
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140320) {
|
|
if (T_FLOW) fprintf(stderr," CSA\n");
|
|
newkeys((crs[KEYS] & 077777) | (crs[A] & 0x8000));
|
|
crs[A] = crs[A] & 077777;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141500) {
|
|
if (T_FLOW) fprintf(stderr," LCLT\n");
|
|
lclt:
|
|
crs[A] = ((crs[KEYS] & 0300) == 0200);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141501) {
|
|
if (T_FLOW) fprintf(stderr," LCLE\n");
|
|
lcle:
|
|
crs[A] = ((crs[KEYS] & 0300) != 0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141503) {
|
|
if (T_FLOW) fprintf(stderr," LCEQ\n");
|
|
lceq:
|
|
crs[A] = ((crs[KEYS] & 0100) != 0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141502) {
|
|
if (T_FLOW) fprintf(stderr," LCNE\n");
|
|
lcne:
|
|
crs[A] = ((crs[KEYS] & 0100) == 0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141504) {
|
|
if (T_FLOW) fprintf(stderr," LCGE\n");
|
|
lcge:
|
|
crs[A] = !(crs[KEYS] & 0200) || (crs[KEYS] & 0100);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141505) {
|
|
if (T_FLOW) fprintf(stderr," LCGT\n");
|
|
lcgt:
|
|
crs[A] = ((crs[KEYS] & 0300) == 0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140410) {
|
|
if (T_FLOW) fprintf(stderr," LLT\n");
|
|
SETCC_A;
|
|
goto lclt;
|
|
}
|
|
|
|
if (inst == 0140411) {
|
|
if (T_FLOW) fprintf(stderr," LLE\n");
|
|
SETCC_A;
|
|
goto lcle;
|
|
}
|
|
|
|
if (inst == 0140412) {
|
|
if (T_FLOW) fprintf(stderr," LNE\n");
|
|
SETCC_A;
|
|
goto lcne;
|
|
}
|
|
|
|
if (inst == 0140413) {
|
|
if (T_FLOW) fprintf(stderr," LEQ\n");
|
|
SETCC_A;
|
|
goto lceq;
|
|
}
|
|
|
|
if (inst == 0140414) {
|
|
if (T_FLOW) fprintf(stderr," LGE\n");
|
|
SETCC_A;
|
|
goto lcge;
|
|
}
|
|
|
|
if (inst == 0140415) {
|
|
if (T_FLOW) fprintf(stderr," LGT\n");
|
|
SETCC_A;
|
|
goto lcgt;
|
|
}
|
|
|
|
if (inst == 0141511) {
|
|
if (T_FLOW) fprintf(stderr," LLLE\n");
|
|
SETCC_L;
|
|
goto lcle;
|
|
}
|
|
|
|
if (inst == 0141513) {
|
|
if (T_FLOW) fprintf(stderr," LLEQ\n");
|
|
SETCC_L;
|
|
goto lceq;
|
|
}
|
|
|
|
if (inst == 0141512) {
|
|
if (T_FLOW) fprintf(stderr," LLNE\n");
|
|
SETCC_L;
|
|
goto lcne;
|
|
}
|
|
|
|
if (inst == 0141515) {
|
|
if (T_FLOW) fprintf(stderr," LLGT\n");
|
|
SETCC_L;
|
|
goto lcgt;
|
|
}
|
|
|
|
if (inst == 0141110) {
|
|
if (T_FLOW) fprintf(stderr," LFLT\n");
|
|
SETCC_F;
|
|
goto lclt;
|
|
}
|
|
|
|
if (inst == 0141111) {
|
|
if (T_FLOW) fprintf(stderr," LFLE\n");
|
|
SETCC_F;
|
|
goto lcle;
|
|
}
|
|
|
|
if (inst == 0141113) {
|
|
if (T_FLOW) fprintf(stderr," LFEQ\n");
|
|
SETCC_F;
|
|
goto lceq;
|
|
}
|
|
|
|
if (inst == 0141112) {
|
|
if (T_FLOW) fprintf(stderr," LFNE\n");
|
|
SETCC_F;
|
|
goto lcne;
|
|
}
|
|
|
|
if (inst == 0141114) {
|
|
if (T_FLOW) fprintf(stderr," LFGE\n");
|
|
SETCC_F;
|
|
goto lcge;
|
|
}
|
|
|
|
if (inst == 0141115) {
|
|
if (T_FLOW) fprintf(stderr," LFGT\n");
|
|
SETCC_F;
|
|
goto lcgt;
|
|
}
|
|
|
|
if (inst == 0140550) {
|
|
if (T_FLOW) fprintf(stderr," FLOT\n");
|
|
templ = crs[A];
|
|
templ = crs[B] | (templ<<15);
|
|
tempf = templ;
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
SETCC_L;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140534) {
|
|
if (T_FLOW) fprintf(stderr," FRN\n");
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140574) {
|
|
if (T_FLOW) fprintf(stderr," DFCM\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
prieee8(tempda);
|
|
*(double *)tempda = -(*(double *)tempda);
|
|
ieeepr8(tempda);
|
|
crs[FLTH] = tempda[0];
|
|
crs[FLTL] = tempda[1];
|
|
crs[FLTD] = tempda[2];
|
|
crs[FEXP] = tempda[3];
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141000) {
|
|
if (T_FLOW) fprintf(stderr," ADLL\n");
|
|
if (crs[KEYS] & 020000) {
|
|
crs[KEYS] &= ~0120300; /* clear C, L, and CC */
|
|
utempl = *(unsigned int *)(crs+L);
|
|
(*(int *)(crs+L))++;
|
|
if (utempl == 0x7FFFFFFF) {
|
|
SETC;
|
|
} else if (utempl == 0xFFFFFFFF)
|
|
crs[KEYS] |= 020100; /* set L and EQ */
|
|
else if (utempl & 0x80000000)
|
|
crs[KEYS] |= 0200; /* set LT */
|
|
} else {
|
|
CLEARC;
|
|
SETCC_L;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140530) {
|
|
if (T_FLOW) fprintf(stderr," FCM\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
tempf = -tempf;
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140510) {
|
|
if (T_FLOW) fprintf(stderr," FSZE\n");
|
|
if (*(int *)(crs+FLTH) == 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140511) {
|
|
if (T_FLOW) fprintf(stderr," FSNZ\n");
|
|
if (*(int *)(crs+FLTH) != 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140512) {
|
|
if (T_FLOW) fprintf(stderr," FSMI\n");
|
|
if (*(int *)(crs+FLTH) < 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140513) {
|
|
if (T_FLOW) fprintf(stderr," FSPL\n");
|
|
if (*(int *)(crs+FLTH) >= 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140514) {
|
|
if (T_FLOW) fprintf(stderr," FSLE\n");
|
|
if (*(int *)(crs+FLTH) < 0 || *(int *)(crs+FLTH) == 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140515) {
|
|
if (T_FLOW) fprintf(stderr," FSGT\n");
|
|
if (*(int *)(crs+FLTH) > 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140554) {
|
|
if (T_FLOW) fprintf(stderr," INT\n");
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
templ = tempf;
|
|
EXPC(tempf > 1073741823 || tempf < -1073741824);
|
|
crs[B] = templ & 0x7FFF;
|
|
crs[A] = templ >> 15;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140531) {
|
|
if (T_FLOW) fprintf(stderr," INTA\n");
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
tempa = tempf;
|
|
EXPC(tempf > 32767 || tempf < -32768);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140532) {
|
|
if (T_FLOW) fprintf(stderr," FLTA\n");
|
|
tempf = *(short *)(crs+A);
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
CLEARC;
|
|
}
|
|
|
|
if (inst == 0140533) {
|
|
if (T_FLOW) fprintf(stderr," INTL\n");
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
templ = tempf;
|
|
EXPC(tempf > 2147483647 || tempf < -2147483648);
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0140535) {
|
|
if (T_FLOW) fprintf(stderr," FLTL\n");
|
|
tempf = *(int *)(crs+L);
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
CLEARC;
|
|
}
|
|
|
|
if (inst == 0141414) {
|
|
if (T_FLOW) fprintf(stderr," ILE\n");
|
|
templ = *(int *)(crs+L);
|
|
*(int *)(crs+L) = *(int *)(crs+E);
|
|
*(int *)(crs+E) = templ;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141707) {
|
|
printf("BMxx at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BMLT\n");
|
|
if (crs[KEYS] & 020000)
|
|
goto bclt;
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141711) {
|
|
printf("BMxx at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BMLE\n");
|
|
if (crs[KEYS] & 020000)
|
|
goto bcle;
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141602) {
|
|
printf("BMxx at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BMEQ\n");
|
|
if (crs[KEYS] & 020000)
|
|
goto bceq;
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141603) {
|
|
printf("BMxx at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BMNE\n");
|
|
if (crs[KEYS] & 020000)
|
|
goto bcne;
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141606) {
|
|
printf("BMxx at #%d\n", instcount);
|
|
if (T_FLOW) fprintf(stderr," BMGE\n");
|
|
if (crs[KEYS] & 020000)
|
|
goto bcge;
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141710) {
|
|
printf("BMxx at #%d\n", instcount);
|
|
#if 0
|
|
/* this is good for tracing the failure if cpuid is set to 15 in
|
|
Primos boot. Weird memory maps for 9950 16MB? */
|
|
traceflags = -1;
|
|
#endif
|
|
|
|
if (T_FLOW) fprintf(stderr," BMGT\n");
|
|
if (crs[KEYS] & 020000)
|
|
goto bcgt;
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141404) {
|
|
if (T_FLOW) fprintf(stderr," CRE\n");
|
|
*(int *)(crs+E) = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141410) {
|
|
if (T_FLOW) fprintf(stderr," CRLE\n");
|
|
*(int *)(crs+L) = *(int *)(crs+E) = 0;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141414) {
|
|
if (T_FLOW) fprintf(stderr," ILE\n");
|
|
templ = *(int *)(crs+L);
|
|
*(int *)(crs+L) = *(int *)(crs+E);
|
|
*(int *)(crs+E) = templ;
|
|
continue;
|
|
}
|
|
|
|
/* queue instructions */
|
|
|
|
if (inst == 0141714) {
|
|
if (T_FLOW) fprintf(stderr," RTQ\n");
|
|
ea = apea(NULL);
|
|
qtop = get16(ea);
|
|
qbot = get16(ea+1);
|
|
if (qtop == qbot) {
|
|
crs[A] = 0;
|
|
crs[KEYS] |= 0100;
|
|
} else {
|
|
qseg = get16(ea+2) & 0x7FFF;
|
|
qmask = get16(ea+3);
|
|
qea = MAKEVA(qseg,qtop);
|
|
crs[A] = get16(qea);
|
|
qtop = (qtop & ~qmask) | ((qtop+1) & qmask);
|
|
put16(qtop, ea);
|
|
crs[KEYS] &= ~0100;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141715) {
|
|
if (T_FLOW) fprintf(stderr," RBQ\n");
|
|
ea = apea(NULL);
|
|
qtop = get16(ea);
|
|
qbot = get16(ea+1);
|
|
if (qtop == qbot) { /* queue empty */
|
|
crs[A] = 0;
|
|
crs[KEYS] |= 0100;
|
|
} else {
|
|
qseg = get16(ea+2) & 0x7FFF;
|
|
qmask = get16(ea+3);
|
|
qbot = (qbot & ~qmask) | ((qbot-1) & qmask);
|
|
qea = MAKEVA(qseg,qbot);
|
|
crs[A] = get16(qea);
|
|
put16(qbot, ea+1);
|
|
crs[KEYS] &= ~0100;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141716) {
|
|
if (T_FLOW) fprintf(stderr," ABQ\n");
|
|
ea = apea(NULL);
|
|
qtop = get16(ea);
|
|
qbot = get16(ea+1);
|
|
qseg = get16(ea+2) & 0x7FFF;
|
|
qmask = get16(ea+3);
|
|
qtemp = (qbot & ~qmask) | ((qbot+1) & qmask);
|
|
if (qtemp == qtop) { /* queue full */
|
|
crs[KEYS] |= 0100;
|
|
} else {
|
|
qea = MAKEVA(qseg,qbot);
|
|
put16(crs[A],qea);
|
|
put16(qtemp, ea+1);
|
|
crs[KEYS] &= ~0100;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141717) {
|
|
if (T_FLOW) fprintf(stderr," ATQ\n");
|
|
ea = apea(NULL);
|
|
qtop = get16(ea);
|
|
qbot = get16(ea+1);
|
|
qseg = get16(ea+2) & 0x7FFF;
|
|
qmask = get16(ea+3);
|
|
qtemp = (qtop & ~qmask) | ((qtop-1) & qmask);
|
|
if (qtemp == qbot) { /* queue full */
|
|
crs[KEYS] |= 0100;
|
|
} else {
|
|
qea = MAKEVA(qseg,qtemp);
|
|
put16(crs[A],qea);
|
|
put16(qtemp, ea);
|
|
crs[KEYS] &= ~0100;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0141757) {
|
|
if (T_FLOW) fprintf(stderr," TSTQ\n");
|
|
ea = apea(NULL);
|
|
qtop = get16(ea);
|
|
qbot = get16(ea+1);
|
|
qmask = get16(ea+3);
|
|
crs[A] = (qbot-qtop) & qmask;
|
|
SETCC_A;
|
|
continue;
|
|
}
|
|
|
|
if (T_INST) fprintf(stderr," unrecognized generic class 3 instruction!\n");
|
|
printf(" unrecognized generic class 3 instruction %o!\n", inst);
|
|
|
|
/* XXX: these are hacks for CPU.FAULT; not sure how to determine whether
|
|
an instruction is illegal or unimplemented... */
|
|
if (inst == 0141700)
|
|
fault(ILLINSTFAULT, RPL, 0);
|
|
else
|
|
fault(UIIFAULT, RPL, 0);
|
|
fatal(NULL);
|
|
|
|
}
|
|
|
|
|
|
if (class == 1) {
|
|
if (T_INST) fprintf(stderr," shift group\n");
|
|
scount = -inst & 077;
|
|
if (scount == 0)
|
|
scount = 0100;
|
|
switch (inst & 01700) {
|
|
|
|
case 00000: /* LRL */
|
|
if (T_FLOW) fprintf(stderr," LRL %d\n", scount);
|
|
if (scount <= 32) {
|
|
utempl = *(unsigned int *)(crs+A);
|
|
EXPC(utempl & bitmask32[33-scount]);
|
|
utempl = utempl >> scount;
|
|
*(unsigned int *)(crs+A) = utempl;
|
|
} else {
|
|
*(unsigned int *)(crs+A) = 0;
|
|
CLEARC;
|
|
}
|
|
break;
|
|
|
|
case 00100: /* LRS (different in R & V modes) */
|
|
if (T_FLOW) fprintf(stderr," LRS %d\n", scount);
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (scount <= 32) {
|
|
templ = *(int *)(crs+A);
|
|
EXPC(templ & bitmask32[33-scount]);
|
|
templ = templ >> scount;
|
|
*(int *)(crs+A) = templ;
|
|
} else if (crs[A] & 0x8000) {
|
|
*(int *)(crs+A) = 0xFFFFFFFF;
|
|
SETC;
|
|
} else {
|
|
*(int *)(crs+A) = 0;
|
|
CLEARC;
|
|
}
|
|
} else {
|
|
utempa = crs[B] & 0x8000; /* save B bit 1 */
|
|
if (scount <= 31) {
|
|
templ = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1);
|
|
EXPC(templ & bitmask32[32-scount]);
|
|
templ = templ >> (scount+1);
|
|
crs[A] = templ >> 15;
|
|
crs[B] = (templ & 0x7FFF) | utempa;
|
|
} else if (crs[A] & 0x8000) {
|
|
*(int *)(crs+A) = 0xFFFF7FFF | utempa;
|
|
SETC;
|
|
} else {
|
|
*(int *)(crs+A) = utempa;
|
|
CLEARC;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 00200: /* LRR */
|
|
if (T_FLOW) fprintf(stderr," LRR %d\n", scount);
|
|
if (scount > 32)
|
|
scount = scount - 32;
|
|
utempl = *(unsigned int *)(crs+A);
|
|
EXPC(utempl & bitmask32[33-scount]);
|
|
utempl = (utempl >> scount) | (utempl << (32-scount));
|
|
*(unsigned int *)(crs+A) = utempl;
|
|
break;
|
|
|
|
case 00400: /* ARL */
|
|
if (T_FLOW) fprintf(stderr," ARL %d\n", scount);
|
|
if (scount <= 16) {
|
|
utempa = crs[A];
|
|
EXPC(utempa & bitmask16[17-scount]);
|
|
utempa = utempa >> scount;
|
|
crs[A] = utempa;
|
|
} else {
|
|
crs[A] = 0;
|
|
CLEARC;
|
|
}
|
|
break;
|
|
|
|
case 00500: /* ARS */
|
|
if (T_FLOW) fprintf(stderr," ARS %d\n", scount);
|
|
if (scount <= 16) {
|
|
tempa = *(short *)(crs+A);
|
|
EXPC(tempa & bitmask16[17-scount]);
|
|
tempa = tempa >> scount;
|
|
*(short *)(crs+A) = tempa;
|
|
} else if (crs[A] & 0x8000) {
|
|
*(short *)(crs+A) = 0xFFFF;
|
|
SETC;
|
|
} else {
|
|
*(short *)(crs+A) = 0;
|
|
CLEARC;
|
|
}
|
|
break;
|
|
|
|
case 00600: /* ARR */
|
|
if (T_FLOW) fprintf(stderr," ARR %d\n", scount);
|
|
scount = ((scount-1)%16)+1; /* make scount 1-16 */
|
|
EXPC(crs[A] & bitmask16[17-scount]);
|
|
crs[A] = (crs[A] >> scount) | (crs[A] << (16-scount));
|
|
break;
|
|
|
|
case 01000: /* LLL */
|
|
if (T_FLOW) fprintf(stderr," LLL %d\n", scount);
|
|
if (scount <= 32) {
|
|
utempl = *(unsigned int *)(crs+A);
|
|
EXPC(utempl & bitmask32[scount]);
|
|
utempl = utempl << scount;
|
|
*(unsigned int *)(crs+A) = utempl;
|
|
} else {
|
|
*(unsigned int *)(crs+A) = 0;
|
|
CLEARC;
|
|
}
|
|
break;
|
|
|
|
case 01100: /* LLS (different in R/V modes) */
|
|
if (T_FLOW) fprintf(stderr," LLS %d\n", scount);
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (scount < 32) {
|
|
templ = 0x80000000;
|
|
templ = templ >> scount; /* create mask */
|
|
templ = templ & *(int *)(crs+A); /* grab bits */
|
|
templ = templ >> (31-scount); /* extend them */
|
|
EXPC(!(templ == -1 || templ == 0));
|
|
*(int *)(crs+A) = *(int *)(crs+A) << scount;
|
|
} else {
|
|
EXPC(*(int *)(crs+A) != 0);
|
|
*(int *)(crs+A) = 0;
|
|
}
|
|
} else {
|
|
utempa = crs[B] & 0x8000; /* save B bit 1 */
|
|
if (scount < 31) {
|
|
utempl = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1);
|
|
templ2 = 0x80000000;
|
|
templ2 = templ2 >> scount; /* create mask */
|
|
templ2 = templ2 & utempl; /* grab bits */
|
|
templ2 = templ2 >> (31-scount); /* sign extend them */
|
|
EXPC(!(templ2 == -1 || templ2 == 0));
|
|
//printf(" before: A=%x, B=%x, utempl=%x, ", crs[A], crs[B], utempl);
|
|
utempl = utempl << scount;
|
|
crs[A] = utempl >> 16;
|
|
crs[B] = ((utempl >> 1) & 0x7FFF) | utempa;
|
|
//printf(" after: A=%x, B=%x, utempl=%x\n", crs[A], crs[B], utempl);
|
|
} else {
|
|
EXPC(*(unsigned int *)(crs+A) != 0);
|
|
*(unsigned int *)(crs+A) = utempa;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 01200: /* LLR */
|
|
if (T_FLOW) fprintf(stderr," LLR %d\n", scount);
|
|
if (scount > 32)
|
|
scount = scount - 32;
|
|
utempl = *(unsigned int *)(crs+A);
|
|
EXPC(utempl & bitmask32[scount]);
|
|
utempl = (utempl << scount) | (utempl >> (32-scount));
|
|
*(unsigned int *)(crs+A) = utempl;
|
|
break;
|
|
|
|
case 01400: /* ALL */
|
|
if (T_FLOW) fprintf(stderr," ALL %d\n", scount);
|
|
if (scount <= 16) {
|
|
EXPC(crs[A] & bitmask16[scount]);
|
|
crs[A] = crs[A] << scount;
|
|
} else {
|
|
crs[A] = 0;
|
|
CLEARC;
|
|
}
|
|
break;
|
|
|
|
case 01500: /* ALS */
|
|
if (T_FLOW) fprintf(stderr," ALS %d\n", scount);
|
|
if (scount <= 15) {
|
|
tempa = 0100000;
|
|
tempa = tempa >> scount; /* create mask */
|
|
tempa = tempa & crs[A]; /* grab bits */
|
|
tempa = tempa >> (15-scount); /* extend them */
|
|
EXPC(!(tempa == -1 || tempa == 0));
|
|
crs[A] = crs[A] << scount;
|
|
} else if (crs[A] == 0) {
|
|
CLEARC;
|
|
} else {
|
|
crs[A] = 0;
|
|
SETC;
|
|
}
|
|
break;
|
|
|
|
case 01600: /* ALR */
|
|
if (T_FLOW) fprintf(stderr," ALR %d\n", scount);
|
|
scount = ((scount-1)%16)+1; /* make scount 1-16 */
|
|
EXPC(crs[A] & bitmask16[scount]);
|
|
crs[A] = (crs[A] << scount) | (crs[A] >> (16-scount));
|
|
break;
|
|
|
|
default:
|
|
printf("WARNING: unrecognized shift instruction %o at %o/%o\n", inst, RPH, RPL);
|
|
if (T_INST) fprintf(stderr," unrecognized shift instruction!: %o\n", inst);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (class == 2) {
|
|
if (T_INST) fprintf(stderr," skip group\n");
|
|
|
|
if (inst == 0101000) {
|
|
if (T_FLOW) fprintf(stderr," NOP\n");
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100000) {
|
|
if (T_FLOW) fprintf(stderr," SKP\n");
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0101400) {
|
|
if (T_FLOW) fprintf(stderr," SMI/SLT\n");
|
|
if (*(short *)(crs+A) < 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100400) {
|
|
if (T_FLOW) fprintf(stderr," SPL/SGE\n");
|
|
if (*(short *)(crs+A) >= 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0101100) {
|
|
if (T_FLOW) fprintf(stderr," SLN\n");
|
|
if (crs[A] & 1)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100100) {
|
|
if (T_FLOW) fprintf(stderr," SLZ\n");
|
|
if (!(crs[A] & 1))
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0101040) {
|
|
if (T_FLOW) fprintf(stderr," SNZ/SNE\n");
|
|
if (crs[A] != 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100040) {
|
|
if (T_FLOW) fprintf(stderr," SZE/SEQ\n");
|
|
if (crs[A] == 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0101220) {
|
|
if (T_FLOW) fprintf(stderr," SLE\n");
|
|
if (*(short *)(crs+A) <= 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100220) {
|
|
if (T_FLOW) fprintf(stderr," SGT\n");
|
|
if (*(short *)(crs+A) > 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0101001) {
|
|
if (T_FLOW) fprintf(stderr," SSC\n");
|
|
if (crs[KEYS] & 0100000)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100001) {
|
|
if (T_FLOW) fprintf(stderr," SRC\n");
|
|
if (!(crs[KEYS] & 0100000))
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if ((inst & 0177760) == 0100260) {
|
|
if (T_FLOW) fprintf(stderr," SAR %d\n", (inst & 017)+1);
|
|
if (!(crs[A] & bitmask16[(inst & 017)+1]))
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if ((inst & 0177760) == 0101260) {
|
|
if (T_FLOW) fprintf(stderr," SAS %d\n", (inst & 017)+1);
|
|
if (crs[A] & bitmask16[(inst & 017)+1])
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if ((inst & 0177760) == 0100240) {
|
|
if (T_FLOW) fprintf(stderr," SNR %d\n", (inst & 017)+1);
|
|
RESTRICT();
|
|
if (!(sswitch & bitmask16[(inst & 017)+1]))
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if ((inst & 0177760) == 0101240) {
|
|
if (T_FLOW) fprintf(stderr," SNS %d\n", (inst & 017)+1);
|
|
RESTRICT();
|
|
if (sswitch & bitmask16[(inst & 017)+1])
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0100200) { /* skip if machine check flop is reset */
|
|
if (T_FLOW) fprintf(stderr," SMCR\n");
|
|
RESTRICT();
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (inst == 0101200) { /* skip if machine check flop is set */
|
|
if (T_FLOW) fprintf(stderr," SMCS\n");
|
|
RESTRICT();
|
|
continue;
|
|
}
|
|
|
|
printf(" unrecognized skip instruction %o at %o/%o\n", inst, RPH, RPL);
|
|
fatal(NULL);
|
|
|
|
}
|
|
}
|
|
|
|
/* here for non-generic instructions: memory references or pio */
|
|
/* pio can only occur in S/R modes */
|
|
|
|
if (!(crs[KEYS] & 010000) && (inst & 036000) == 030000) {
|
|
pio(inst);
|
|
continue;
|
|
}
|
|
|
|
/* get ix bits and adjust opcode so that PMA manual opcode
|
|
references can be used directly, ie, if the PMA manual says the
|
|
opcode is '15 02, then 01502 can be used here. If the PMA
|
|
manual says the opcode is '11, then use 01100 (the XX extended
|
|
opcode bits are zero) */
|
|
|
|
i = inst & 0100000; /* indirect is bit 1 (left/MS bit) */
|
|
x = inst & 040000; /* indexed is bit 2 */
|
|
opcode = (inst & 036000) >> 4; /* isolate opcode bits */
|
|
|
|
/* fix ldx/stx (opcode '15): these instructions cannot be indexed
|
|
by X, so if an instruction specifies indexing by X, it acts
|
|
like an opcode extension. Opcodes listed as '35 02 for example
|
|
(sty in V-mode, jdx in R-mode) have X=1 with the 4 opcode bits
|
|
1101 ('15)
|
|
|
|
x=0, opcode='15 -> stx (SRV)
|
|
x=1, opcode='15 -> ldx (SRV) (aka '35)
|
|
|
|
x=0, opcode='15 01 -> flx (RV)
|
|
x=1, opcode='15 01 -> ldy (V) (aka '35 01)
|
|
|
|
x=0, opcode='15 02 -> dflx (V)
|
|
x=0, opcode='15 02 -> jdx (R)
|
|
x=1, opcode='15 02 -> sty (V) (aka '35 02)
|
|
|
|
x=0, opcode='15 03 -> jix (R)
|
|
x=1, opcode='15 03 -> jsx (RV) (aka '35 03)
|
|
*/
|
|
|
|
if (opcode == 01500) {
|
|
opcode = opcode | ((inst & 040000)>>4); /* if X set, expand opcode */
|
|
x = 0; /* clear X bit (these can't be indexed) */
|
|
if (T_INST) fprintf(stderr," ldx/stx opcode adjusted\n");
|
|
}
|
|
|
|
if (T_INST) fprintf(stderr," opcode=%5#0o, i=%o, x=%o\n", opcode, i, x);
|
|
|
|
switch ((crs[KEYS] & 016000) >> 10) {
|
|
case 0: /* 16S */
|
|
ea = ea16s(inst, i, x);
|
|
break;
|
|
case 1: /* 32S */
|
|
ea = ea32s(inst, i, x);
|
|
break;
|
|
case 2: /* 64R */
|
|
case 3: /* 32R */
|
|
ea = ea32r64r(earp, inst, i, x, &opcode);
|
|
break;
|
|
case 4: /* 32I */
|
|
ea = ea32i(earp, inst, i, x);
|
|
fatal("32I not supported");
|
|
break;
|
|
case 6: /* 64V */
|
|
ea = ea64v(earp, inst, i, x, &opcode, &eabit);
|
|
break;
|
|
default:
|
|
printf("Bad CPU mode in EA calculation, keys = %o\n", crs[KEYS]);
|
|
fatal(NULL);
|
|
}
|
|
|
|
if (T_INST) fprintf(stderr," EA: %o/%o\n",ea>>16, ea & 0xFFFF);
|
|
|
|
|
|
/* NOTE: basic and dbasic execute instructions from the register file
|
|
with TRACE ON */
|
|
|
|
if (opcode == 00100) {
|
|
if (T_FLOW) fprintf(stderr," JMP\n");
|
|
if (prevpc+1 == RP) /* 1-word JMP# instruction */
|
|
RPL = ea;
|
|
else
|
|
RP = ea; /* 2-word JMP% instruction */
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00200) {
|
|
crs[A] = get16(ea);
|
|
if ((crs[KEYS] & 050000) == 040000) { /* R-mode and DP */
|
|
if (T_FLOW) fprintf(stderr," DLD\n");
|
|
crs[B] = get16(INCVA(ea,1));
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," LDA\n");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00400) {
|
|
put16(crs[A],ea);
|
|
if ((crs[KEYS] & 050000) == 040000) {
|
|
if (T_FLOW) fprintf(stderr," DST\n");
|
|
put16(crs[B],INCVA(ea,1));
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," STA\n");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00600) {
|
|
utempa = crs[A];
|
|
m = get16(ea);
|
|
if ((crs[KEYS] & 050000) == 040000) {
|
|
if (T_FLOW) fprintf(stderr," DAD\n");
|
|
crs[B] += get16(INCVA(ea,1));
|
|
if (crs[B] & 0x8000) {
|
|
crs[A]++;
|
|
crs[B] &= 0x7fff;
|
|
}
|
|
crs[A] += m;
|
|
SETCC_L;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," ADD\n");
|
|
crs[A] += m;
|
|
SETCC_A;
|
|
}
|
|
EXPC(((~utempa ^ m) & (utempa ^ crs[A])) & 0x8000);
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00700) {
|
|
utempa = crs[A];
|
|
m = get16(ea);
|
|
if ((crs[KEYS] & 050000) == 040000) {
|
|
if (T_FLOW) fprintf(stderr," DSB\n");
|
|
crs[B] -= get16(INCVA(ea,1));
|
|
if (crs[B] & 0x8000) {
|
|
crs[A]--;
|
|
crs[B] &= 0x7fff;
|
|
}
|
|
crs[A] -= m;
|
|
SETCC_L;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," SUB\n");
|
|
crs[A] -= m;
|
|
SETCC_A;
|
|
}
|
|
crs[KEYS] &= ~0300;
|
|
if (utempa == m) {
|
|
crs[KEYS] |= 0100;
|
|
SETL(1);
|
|
CLEARC;
|
|
} else {
|
|
EXPC(((utempa ^ m) & (utempa ^ *(int *)(crs+L))) & 0x80000000);
|
|
SETCC_L;
|
|
if (crs[KEYS] & 0100000)
|
|
if (*(int *)(crs+L) > 0)
|
|
crs[KEYS] |= 0200;
|
|
else
|
|
crs[KEYS] &= ~0200;
|
|
if (utempa > m) {
|
|
SETL(1);
|
|
} else {
|
|
SETL(0);
|
|
}
|
|
}
|
|
//EXPC(((utempa ^ m) & (utempa ^ crs[A])) & 0x8000);
|
|
/* NOTE: setting L to zero causes Primos boot to fail with bad rvec */
|
|
//SETL(utempa > m);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00300) {
|
|
m = get16(ea);
|
|
if (T_FLOW) fprintf(stderr," ANA ='%o\n",m);
|
|
crs[A] &= m;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00500) {
|
|
m = get16(ea);
|
|
if (T_FLOW) fprintf(stderr," ERA ='%o\n", m);
|
|
crs[A] ^= m;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00302) {
|
|
if (T_FLOW) fprintf(stderr," ORA\n");
|
|
crs[A] |= get16(ea);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01000) {
|
|
if (T_FLOW) fprintf(stderr," JST\n");
|
|
put16(RPL,ea);
|
|
RPL = ea+1;
|
|
continue;
|
|
}
|
|
|
|
/* this should set the CC and L bits, and is implemented in u-code
|
|
with a subtract. However, that operation can overflow and give
|
|
the wrong result */
|
|
|
|
if (opcode == 01100) {
|
|
m = get16(ea);
|
|
if (T_FLOW) fprintf(stderr," CAS ='%o\n", m);
|
|
crs[KEYS] &= ~0300;
|
|
if (crs[A] == m) {
|
|
RPL++;
|
|
crs[KEYS] |= 0100;
|
|
} else if (*(short *)(crs+A) < *(short *)&m) {
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01200) {
|
|
if (T_FLOW) fprintf(stderr," IRS\n");
|
|
m = get16(ea) + 1;
|
|
put16(m,ea);
|
|
if (m == 0)
|
|
RPL++;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01300) {
|
|
if (T_FLOW) fprintf(stderr," IMA\n");
|
|
m = get16(ea);
|
|
put16(crs[A],ea);
|
|
crs[A] = m;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01400) {
|
|
if (T_FLOW) fprintf(stderr," JSY\n");
|
|
crs[Y] = RPL;
|
|
RPL = ea;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01402) {
|
|
if (T_FLOW) fprintf(stderr," JSXB\n");
|
|
*(unsigned int *)(crs+XB) = RP;
|
|
RP = ea;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01500) {
|
|
if (T_FLOW) fprintf(stderr," STX\n");
|
|
put16(crs[X],ea);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01600) {
|
|
if (T_FLOW) fprintf(stderr," MPY\n");
|
|
m = get16(ea);
|
|
templ = *(short *)(crs+A) * *(short *)&m;
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
*(int *)(crs+L) = templ;
|
|
CLEARC;
|
|
} else { /* R/S mode */
|
|
EXPC(templ > 1073741823 || templ < -1073741824);
|
|
crs[A] = (templ >> 15);
|
|
crs[B] = templ & 077777;
|
|
}
|
|
SETCC_L;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01603) {
|
|
if (T_FLOW) fprintf(stderr," MPL\n");
|
|
templ = get32(ea);
|
|
templl = (long long)(*(int *)(crs+L)) * (long long)templ;
|
|
*(long long *)(crs+L) = templl;
|
|
SETCC_LE;
|
|
CLEARC;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01700) {
|
|
if (T_FLOW) fprintf(stderr," DIV\n");
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
templ = *(int *)(crs+A);
|
|
} else { /* R/S mode */
|
|
templ = *(short *)(crs+A); /* convert to 32-bit signed */
|
|
templ = (templ<<15) | (crs[B] & 0x7FFF);
|
|
//printf("\nR-mode DIV: A='%o/%d, B='%o/%d, templ='%o/%d\n", crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B), templ, templ);
|
|
}
|
|
m = get16(ea);
|
|
if (m != 0 && abs(*(short *)(crs+A)) < abs(*(short *)&m)) {
|
|
crs[A] = templ / *(short *)&m;
|
|
crs[B] = templ % *(short *)&m;
|
|
CLEARC;
|
|
//printf("DIV results: m='%o/%d, A='%o/%d, B='%o/%d\n", m, *(short *)&m, crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B));
|
|
} else {
|
|
SETC;
|
|
//printf("DIV overflow\n");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01703) {
|
|
if (T_FLOW) fprintf(stderr," DVL\n");
|
|
templl = *(long long *)(crs+L);
|
|
templ = get32(ea);
|
|
if (templ != 0) {
|
|
*(int *)(crs+L) = templl / templ;
|
|
*(int *)(crs+E) = templl % templ;
|
|
CLEARC;
|
|
} else
|
|
SETC;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 03500) {
|
|
if (T_FLOW) fprintf(stderr," LDX\n");
|
|
crs[X] = get16(ea);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00101) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," EAL\n");
|
|
*(unsigned int *)(crs+L) = ea;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," EAA\n");
|
|
crs[A] = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* NOTE: P300 u-code listings show CC set on Jxx instructions */
|
|
|
|
if (opcode == 00203) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," LDL\n");
|
|
*(unsigned int *)(crs+L) = get32(ea);
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JEQ\n");
|
|
if (*(short *)(crs+A) == 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00703) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," SBL\n");
|
|
utempl = *(unsigned int *)(crs+L);
|
|
utempl2 = get32(ea);
|
|
*(int *)(crs+L) -= *(int *)&utempl2;
|
|
crs[KEYS] &= ~0300;
|
|
if (utempl == utempl2) {
|
|
crs[KEYS] |= 0100;
|
|
SETL(1);
|
|
CLEARC;
|
|
} else {
|
|
EXPC(((utempl ^ utempl2) & (utempl ^ *(int *)(crs+L))) & 0x80000000);
|
|
SETCC_L;
|
|
if (crs[KEYS] & 0100000)
|
|
if (*(int *)(crs+L) > 0)
|
|
crs[KEYS] |= 0200;
|
|
else
|
|
crs[KEYS] &= ~0200;
|
|
if (utempl > utempl2) {
|
|
SETL(1);
|
|
} else {
|
|
SETL(0);
|
|
}
|
|
}
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JGE\n");
|
|
if (*(short *)(crs+A) >= 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01002) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
//traceflags = ~TB_MAP;
|
|
if (T_FLOW || T_PCL) fprintf(stderr,"#%d %o/%o: PCL %o/%o\n", instcount, RPH, RPL-2, ea>>16, ea&0xFFFF);
|
|
pcl(ea);
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," CREP\n");
|
|
put16(RPL,crs[S]++);
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00503) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," ERL\n");
|
|
templ = get32(ea);
|
|
*(int *)(crs+A) ^= templ;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JGT\n");
|
|
if (*(short *)(crs+A) > 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00403) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," STL\n");
|
|
put32(*(unsigned int *)(crs+L),ea);
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JLE\n");
|
|
if (*(short *)(crs+A) <= 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00603) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," ADL\n");
|
|
utempl = *(unsigned int *)(crs+L);
|
|
templ = get32(ea);
|
|
*(int *)(crs+L) += templ;
|
|
EXPC(((~utempl ^ templ) & (utempl ^ *(int *)(crs+L))) & 0x80000000);
|
|
SETCC_L;
|
|
XSETL(0);
|
|
/* NOTE: correct LT if overflow occurred */
|
|
if (crs[KEYS] && 0x8000)
|
|
if (utempl & templ & 0x80000000) /* signs were both neg */
|
|
crs[KEYS] |= 020200; /* set LT and L */
|
|
else
|
|
crs[KEYS] &= ~0200;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JLT\n");
|
|
if (*(short *)(crs+A) < 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00303) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," ANL\n");
|
|
*(unsigned int *)(crs+L) &= get32(ea);
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JNE\n");
|
|
if (*(short *)(crs+A) != 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* NOTE: P300 u-code shows CC set for JIX/JDX */
|
|
|
|
if (opcode == 01502) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," DFLX\n");
|
|
crs[X] = get16(ea) * 4;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JDX\n");
|
|
crs[X]--;
|
|
if (crs[X] != 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 03502) {
|
|
if (T_FLOW) fprintf(stderr," STY\n");
|
|
put16(crs[Y],ea);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01503) {
|
|
if (crs[KEYS] & 010000) { /* V/I mode */
|
|
if (T_FLOW) fprintf(stderr," QFLX\n");
|
|
crs[X] = get16(ea) * 8;
|
|
} else {
|
|
if (T_FLOW) fprintf(stderr," JIX\n");
|
|
crs[X]++;
|
|
if (crs[X] != 0)
|
|
RPL = ea;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01501) {
|
|
if (T_FLOW) fprintf(stderr," FLX\n");
|
|
crs[X] = get16(ea) * 2;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 03501) {
|
|
if (T_FLOW) fprintf(stderr," LDY\n");
|
|
crs[Y] = get16(ea);
|
|
continue;
|
|
}
|
|
|
|
/* XXX: can JSX%, JSY%, and JST% cross segments like JMP% ? */
|
|
|
|
if (opcode == 03503) {
|
|
if (T_FLOW) fprintf(stderr," JSX\n");
|
|
crs[X] = RPL;
|
|
RPL = ea;
|
|
continue;
|
|
}
|
|
|
|
/* this should set the C and L bits, and is implemented in u-code
|
|
with a subtract. However, that operation can overflow and give
|
|
the wrong result */
|
|
|
|
if (opcode == 01103) {
|
|
if (T_FLOW) fprintf(stderr," CLS\n");
|
|
templ = get32(ea);
|
|
if (*(int *)(crs+L) == templ)
|
|
RPL++;
|
|
else if (*(int *)(crs+L) < templ)
|
|
RPL += 2;
|
|
XEXPC(0);
|
|
XSETL(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00601) {
|
|
if (T_FLOW) fprintf(stderr," FAD\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
*(int *)&tempf1 = get32(ea);
|
|
prieee4(&tempf1);
|
|
tempf += tempf1;
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01101) {
|
|
if (T_FLOW) fprintf(stderr," FCS\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
*(int *)&tempf1 = get32(ea);
|
|
prieee4(&tempf1);
|
|
crs[KEYS] &= ~0300;
|
|
if (tempf == tempf1) {
|
|
RPL++;
|
|
crs[KEYS] |= 0100;
|
|
} else if (tempf < tempf1) {
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01701) {
|
|
if (T_FLOW) fprintf(stderr," FDV\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
*(int *)&tempf1 = get32(ea);
|
|
prieee4(&tempf1);
|
|
tempf /= tempf1;
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0201) {
|
|
if (T_FLOW) fprintf(stderr," FLD\n");
|
|
crs[FLTH] = get16(ea);
|
|
m = get16(ea+1);
|
|
crs[FLTL] = m & 0xFF00;
|
|
crs[FEXP] = m & 0xFF;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01601) {
|
|
if (T_FLOW) fprintf(stderr," FMP\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
*(int *)&tempf1 = get32(ea);
|
|
prieee4(&tempf1);
|
|
tempf *= tempf1;
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00701) {
|
|
if (T_FLOW) fprintf(stderr," FSB\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
*(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF);
|
|
prieee4(&tempf);
|
|
*(int *)&tempf1 = get32(ea);
|
|
prieee4(&tempf1);
|
|
tempf -= tempf1;
|
|
ieeepr4(&tempf);
|
|
crs[FLTH] = (*(unsigned int *)&tempf) >> 16;
|
|
crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00;
|
|
crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF;
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0401) {
|
|
if (T_FLOW) fprintf(stderr," FST\n");
|
|
if (crs[FEXP] & 0xFF00)
|
|
mathexception('f', FC_SFP_STORE, ea);
|
|
put16(crs[FLTH],ea);
|
|
put16((crs[FLTL] & 0xFF00) | crs[FEXP],ea+1);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0602) {
|
|
if (T_FLOW) fprintf(stderr," DFAD\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
prieee8(tempda);
|
|
tempd = get64(ea);
|
|
prieee8(&tempd);
|
|
*(double *)tempda += tempd;
|
|
ieeepr8(tempda);
|
|
crs[FLTH] = tempda[0];
|
|
crs[FLTL] = tempda[1];
|
|
crs[FLTD] = tempda[2];
|
|
crs[FEXP] = tempda[3];
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01102) {
|
|
if (T_FLOW) fprintf(stderr, " DFCS\n");
|
|
m = get16(ea);
|
|
if ((crs[FLTH] & 0x8000) == (m & 0x8000)) {
|
|
m1 = get16(INCVA(ea,3));
|
|
if (m1 == crs[FEXP]) {
|
|
if (m == crs[FLTH]) {
|
|
utempl = get32(INCVA(ea,1));
|
|
if ((unsigned int)((crs[FLTL]<<16) | crs[FLTD]) == utempl) {
|
|
RPL += 1;
|
|
crs[KEYS] |= 0100;
|
|
} else if ((unsigned int)((crs[FLTL]<<16) | crs[FLTD]) < utempl) {
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
} else if (crs[FLTH] < m) {
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
} else if (crs[FEXP] < m1) { /* this line breaks CPU.FLOAT.V */
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
} else if (crs[FLTH] & 0x8000) { /* DAC < mem */
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
|
|
#if 0
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
prieee8(tempda);
|
|
printf(" FLTH=%x FLTL=%x FLTD=%x FEXP=%x, value=%e\n", crs[FLTH], crs[FLTL], crs[FLTD], crs[FEXP], *(double *)tempda);
|
|
tempd = get64(ea);
|
|
prieee8(&tempd);
|
|
printf(" ea H=%x ea L=%x ea D=%x ea X=%x, value=%e\n", get16(ea), get16(ea+1), get16(ea+2), get16(ea+3), tempd);
|
|
crs[KEYS] &= ~0300;
|
|
if (*(double *)tempda == tempd) {
|
|
RPL++;
|
|
crs[KEYS] |= 0100;
|
|
} else if (*(double *)tempda < tempd) {
|
|
RPL += 2;
|
|
crs[KEYS] |= 0200;
|
|
}
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01702) {
|
|
if (T_FLOW) fprintf(stderr," DFDV\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
prieee8(tempda);
|
|
tempd = get64(ea);
|
|
prieee8(&tempd);
|
|
*(double *)tempda /= tempd;
|
|
ieeepr8(tempda);
|
|
crs[FLTH] = tempda[0];
|
|
crs[FLTL] = tempda[1];
|
|
crs[FLTD] = tempda[2];
|
|
crs[FEXP] = tempda[3];
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0202) {
|
|
if (T_FLOW) fprintf(stderr," DFLD\n");
|
|
*(double *)tempda = get64(ea);
|
|
crs[FLTH] = tempda[0];
|
|
crs[FLTL] = tempda[1];
|
|
crs[FLTD] = tempda[2];
|
|
crs[FEXP] = tempda[3];
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01602) {
|
|
if (T_FLOW) fprintf(stderr," DFMP\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
prieee8(tempda);
|
|
tempd = get64(ea);
|
|
prieee8(&tempd);
|
|
*(double *)tempda *= tempd;
|
|
ieeepr8(tempda);
|
|
crs[FLTH] = tempda[0];
|
|
crs[FLTL] = tempda[1];
|
|
crs[FLTD] = tempda[2];
|
|
crs[FEXP] = tempda[3];
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0702) {
|
|
if (T_FLOW) fprintf(stderr," DFSB\n");
|
|
if (T_INST) fprintf(stderr," FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]);
|
|
if (T_INST) fprintf(stderr," ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00));
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
prieee8(tempda);
|
|
tempd = get64(ea);
|
|
prieee8(&tempd);
|
|
*(double *)tempda -= tempd;
|
|
ieeepr8(tempda);
|
|
crs[FLTH] = tempda[0];
|
|
crs[FLTL] = tempda[1];
|
|
crs[FLTD] = tempda[2];
|
|
crs[FEXP] = tempda[3];
|
|
XEXPC(0);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0402) {
|
|
if (T_FLOW) fprintf(stderr," DFST\n");
|
|
tempda[0] = crs[FLTH];
|
|
tempda[1] = crs[FLTL];
|
|
tempda[2] = crs[FLTD];
|
|
tempda[3] = crs[FEXP];
|
|
put64(*(double *)tempda, ea);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01202) {
|
|
if (T_FLOW) fprintf(stderr," EAXB\n");
|
|
*(ea_t *)(crs+XB) = ea;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01302) {
|
|
if (T_FLOW) fprintf(stderr," EALB\n");
|
|
*(ea_t *)(crs+LB) = ea;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0101) {
|
|
if (T_FLOW) fprintf(stderr," EAL\n");
|
|
*(ea_t *)(crs+L) = ea;
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0301) {
|
|
if (T_FLOW) fprintf(stderr," STLR\n");
|
|
utempa = ea; /* word number portion only */
|
|
if (utempa & 040000) { /* absolute RF addressing */
|
|
RESTRICT();
|
|
regs.s32[utempa & 0377] = *(int *)(crs+L);
|
|
} else {
|
|
utempa &= 037;
|
|
if (utempa > 017) RESTRICT();
|
|
*(((int *)crs)+utempa) = *(int *)(crs+L);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 0501) {
|
|
if (T_FLOW) fprintf(stderr," LDLR\n");
|
|
utempa = ea; /* word number portion only */
|
|
if (utempa & 040000) { /* absolute RF addressing */
|
|
RESTRICT();
|
|
*(int *)(crs+L) = regs.s32[utempa & 0377];
|
|
} else {
|
|
utempa &= 037;
|
|
if (utempa > 017) RESTRICT();
|
|
*(int *)(crs+L) = *(((int *)crs)+utempa);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 01401) {
|
|
if (T_FLOW) fprintf(stderr," EIO\n");
|
|
crs[KEYS] &= ~0100; /* reset EQ */
|
|
pio(ea & 0xFFFF);
|
|
continue;
|
|
}
|
|
|
|
if (opcode == 00102) {
|
|
if (T_FLOW) fprintf(stderr," XEC\n");
|
|
utempa = get16(ea);
|
|
//utempl = RP-2;
|
|
//printf("RPL %o/%o: XEC instruction %o|%o, ea is %o/%o, new inst = %o \n", utempl>>16, utempl&0xFFFF, inst, get16(utempl+1), ea>>16, ea&0xFFFF, utempa);
|
|
inst = utempa;
|
|
earp = INCVA(ea,1);
|
|
goto xec;
|
|
}
|
|
|
|
if (opcode == 00103) {
|
|
if (T_FLOW) fprintf(stderr," ENTR\n");
|
|
utempa = crs[S];
|
|
crs[S] -= ea;
|
|
put16(utempa,crs[S]);
|
|
continue;
|
|
}
|
|
|
|
#if 0
|
|
if (mem[066] != 0) {
|
|
if (T_FLOW) fprintf(stderr," JST* '66 [%o]\n", mem[066]);
|
|
mem[mem[066]] = RPL;
|
|
RPL = mem[066]+1;
|
|
continue;
|
|
}
|
|
#endif
|
|
printf("Unknown memory reference opcode: %o\n", opcode);
|
|
fatal(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/* Handle SVC instruction. For real hardware emulation on an R-mode
|
|
such as the P300, SVC would interrupt (JST*) through location '75
|
|
(in vectored mode) or would fault on the P400.
|
|
|
|
Since we're running programs without an OS underneath us, handle
|
|
the SVC's here.
|
|
|
|
Typical usage:
|
|
|
|
CALL TNOUA ('MESSAGE', 7)
|
|
JST TNOUA
|
|
DAC =C'MESSAGE'
|
|
DAC =7
|
|
OCT 0
|
|
...
|
|
|
|
The library would resolve the TNOUA reference like this:
|
|
|
|
TNOUA DAC ** RETURN ADDRESS
|
|
SVC ENTER THE OS
|
|
OCT 140703
|
|
JMP# BADCALL HERE FOR BAD SVC
|
|
...
|
|
|
|
The SVC code word follows the SVC instruction:
|
|
|
|
'100000 = this is an interlude; the actual arguments are found
|
|
at the address preceeding the SVC instruction (ie, the caller)
|
|
|
|
'040000 = there is an instruction following the SVC code, before
|
|
the argument list. If there is an SVC error, like a bad function
|
|
code, the SVC handler will return to the location following the
|
|
code word.
|
|
|
|
Bits 3-4 are ignored
|
|
|
|
Bits 5-10 are the SVC group, 1-15.
|
|
Bits 11-16 are the SVC function within the group.
|
|
|
|
Interludes are used because at the time a program is compiled, the
|
|
compiler doesn't know whether a call is going to the OS or not. So the
|
|
call is compiled like any other. It's dumb for the library TNOUA to
|
|
muck around with all the arguments, so bit 1 is set as a shortcut and
|
|
the address of the argument list is just before the SVC itself.
|
|
|
|
If a program knows it's going to call the OS, a direct SVC can be used,
|
|
with bit 1 clear:
|
|
|
|
SVC
|
|
OCT '040703
|
|
JMP# BADSVC
|
|
DAC =C'MESSAGE'
|
|
DAC =7
|
|
OCT 0
|
|
GOOD ...
|
|
|
|
BADSVC EQU *
|
|
|
|
*/
|
|
|
|
|
|
svc() {
|
|
|
|
#define MAXCLASS 015
|
|
#define MAXFUNC 027
|
|
#define MAXSVCARGS 10
|
|
|
|
unsigned short code; /* code word following SVC instruction */
|
|
unsigned short argl; /* address of argument list */
|
|
void *arg[MAXSVCARGS]; /* arg address array */
|
|
short actargs; /* number of actual arguments */
|
|
short class; /* SVC class, from bits 5-10 */
|
|
short func; /* SVC func within class, bits 11-16 */
|
|
short temp16;
|
|
|
|
static struct {
|
|
char name[8]; /* svc routine name */
|
|
char numargs; /* number of arguments for this svc */
|
|
short locargs; /* bit mask for LOC(X) arguments */
|
|
} svcinfo[MAXCLASS+1][MAXFUNC+1] = {
|
|
|
|
/* class 0 is a dummy: it's mapped to class 1 below */
|
|
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 1 */
|
|
|
|
"ATTACH", -5, 0, /* func 0 */
|
|
"SEARCH", -4, 0, /* func 1 */
|
|
"SAVE ", 2, 0, /* func 2 */
|
|
"RESTOR", -3, 0, /* func 3 */
|
|
"RESUME", 1, 0, /* func 4 */
|
|
"EXIT ", 0, 0, /* func 5 */
|
|
"ERRRTN", 4, 0, /* func 6 */
|
|
"UPDATE", 99, 0, /* func 7 */
|
|
"GETERR", 2, 0, /* func 010 */
|
|
"PRERR ", 0, 0, /* func 011 */
|
|
"GINFO ", 2, 0, /* func 012 */
|
|
"CNAME$", -3, 0, /* func 013 */
|
|
"ERRSET", 5, 0, /* func 014 */
|
|
"FORCEW", 2, 0, /* func 015 */
|
|
"",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 2 */
|
|
|
|
"READ ", 99, 0, /* func 0 */
|
|
"WRITE ", 99, 0, /* func 1 */
|
|
"RDLIN ", -4, 0, /* func 2 */
|
|
"WTLIN ", -4, 0, /* func 3 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 3 */
|
|
|
|
"PRWFIL", -6, 020000, /* func 0 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 4 */
|
|
|
|
"FAMSVC", 99, 0, /* func 0 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 5 */
|
|
|
|
"RREC ", -6, 0, /* func 0 */
|
|
"WREC ", -6, 0, /* func 1 */
|
|
"TIMDAT", 2, 0, /* func 2 */
|
|
"DIGIN ", -4, 0, /* func 3 */
|
|
"DIGINW", -4, 0, /* func 4 */
|
|
"RCYCL ", 0, 0, /* func 5 */
|
|
"D$INIT", 1, 0, /* func 6 */
|
|
"BREAK$", 1, 0, /* func 7 */
|
|
"T$MT ", 6, 040000, /* func 010 */
|
|
"T$LMPC", 5, 040000, /* func 011 */
|
|
"T$CMPC", 5, 040000, /* func 012 */
|
|
"T$AMLC", 5, 040000, /* func 013 */
|
|
"T$VG ", 5, 040000, /* func 014 */
|
|
"T$PMPC", 5, 040000, /* func 015 */
|
|
"RRECL ", -6, 0, /* func 016 */
|
|
"WRECL ", -6, 0, /* func 017 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 6 */
|
|
|
|
"COMANL", 0, 0, /* func 0 */
|
|
"C1IN ", 1, 0, /* func 1 */
|
|
"CMREAD", 1, 0, /* func 2 */
|
|
"COMINP", -3, 0, /* func 3 */
|
|
"CNIN$ ", 3, 0, /* func 4 */
|
|
"PHANT$", 5, 0, /* func 5 */
|
|
"",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 7 */
|
|
|
|
"T1IN ", 1, 0, /* func 0 */
|
|
"T1OU ", 1, 0, /* func 1 */
|
|
"TNOU ", 2, 0, /* func 2 */
|
|
"TNOUA ", 2, 0, /* func 3 */
|
|
"TOOCT ", 1, 0, /* func 4 */
|
|
"DUPLX$", 1, 0, /* func 5 */
|
|
"",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 010 */
|
|
|
|
"T$MT ", 6, 040000, /* func 0 */
|
|
"T$SMLC", 4, 020000, /* func 1 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 011 */
|
|
|
|
"T$LMPC", 6, 040000, /* func 0 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 012 */
|
|
|
|
"T$CMPC", 6, 040000, /* func 0 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 013 (user defined) */
|
|
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 014 */
|
|
|
|
"ATTAC$", 6, 002000, /* func 0 */
|
|
"CREAT$", 5, 004000, /* func 1 */
|
|
"ERRPR$", 6, 0, /* func 2 */
|
|
"ERRST$", 99, 0, /* func 3 */
|
|
"GPASS$", 5, 004000, /* func 4 */
|
|
"GQUOT$", 99, 0, /* func 5 */
|
|
"PRWFL$", 7, 021000, /* func 6 */
|
|
"RDENT$", 8, 000400, /* func 7 */
|
|
"SATTR$", 5, 004000, /* func 010 */
|
|
"SEARC$", 6, 002000, /* func 011 */
|
|
"SEGDR$", 5, 004000, /* func 012 */
|
|
"SPASS$", 3, 020000, /* func 013 */
|
|
"SQUOT$", 99, 0, /* func 014 */
|
|
"CNGNM$", 5, 004000, /* func 015 */
|
|
"COMIN$", 4, 010000, /* func 016 */
|
|
"RDTKN$", 5, 004000, /* func 017 */
|
|
"RESTO$", 4, 010000, /* func 020 */
|
|
"RESUM$", 2, 0, /* func 021 */
|
|
"SAVE$ ", 4, 010000, /* func 022 */
|
|
"",99,0, "",99,0, "",99,0, "",99,0, "",99,0,
|
|
|
|
/* class 015 */
|
|
|
|
"ATCH$$", 6, 0, /* func 0 */
|
|
"CREA$$", 5, 0, /* func 1 */
|
|
"",99,0, /* func 2 */
|
|
"",99,0, /* func 3 */
|
|
"GPAS$$", 5, 0, /* func 4 */
|
|
"",99,0, /* func 5 */
|
|
"PRWF$$", 7, 020000, /* func 6 */
|
|
"RDEN$$", 8, 0, /* func 7 */
|
|
"SATR$$", 5, 0, /* func 010 */
|
|
"SRCH$$", 6, 0, /* func 011 */
|
|
"SGDR$$", 5, 0, /* func 012 */
|
|
"SPAS$$", 3, 0, /* func 013 */
|
|
"",99,0, /* func 014 */
|
|
"CNAM$$", 5, 0, /* func 015 */
|
|
"COMI$$", 4, 0, /* func 016 */
|
|
"RDTK$$", 5, 0, /* func 017 */
|
|
"REST$$", 4, 0, /* func 020 */
|
|
"RESU$$", 2, 0, /* func 021 */
|
|
"SAVE$$", 4, 0, /* func 022 */
|
|
"COMO$$", 5, 0, /* func 023 */
|
|
"ERKL$$", 4, 0, /* func 024 */
|
|
"RDLIN$", 4, 0, /* func 025 */
|
|
"WTLIN$", 4, 0, /* func 026 */
|
|
"",99,0
|
|
};
|
|
|
|
#if 0
|
|
for (class=0; class<=MAXCLASS; class++)
|
|
for (func=0; func<=MAXFUNC; func++)
|
|
printf("Class %o, func %o: %s %d args %o\n", class,func, svcinfo[class][func].name, svcinfo[class][func].numargs, svcinfo[class][func].locargs);
|
|
#endif
|
|
|
|
/* later, change this to look for special fault vector of -1 and
|
|
interpret the svc here, to allow emulator to run r-mode programs
|
|
directly */
|
|
|
|
#if 1
|
|
fault(SVCFAULT, 0, 0);
|
|
#endif
|
|
|
|
/* get svc code word, break into class and function */
|
|
|
|
code = mem[RPL];
|
|
class = (code >> 6) & 077;
|
|
if (class == 0)
|
|
class = 1;
|
|
func = code & 077;
|
|
|
|
/* determine argument list location and create arg list vector */
|
|
|
|
if (code & 0100000)
|
|
argl = mem[RPL-2];
|
|
else if (code & 040000)
|
|
argl = RPL+2;
|
|
else
|
|
argl = RPL+1;
|
|
|
|
if (T_INST) fprintf(stderr," code=%o, class=%o, func=%o, argl=%o\n", code, class, func, argl);
|
|
if (class > MAXCLASS || func > MAXFUNC)
|
|
goto badsvc;
|
|
|
|
if (T_FLOW) fprintf(stderr," name=%s, #args=%d, LOC args=%o\n", svcinfo[class][func].name, svcinfo[class][func].numargs, svcinfo[class][func].locargs);
|
|
|
|
/* if location '65 is set, do indirect JST to handle svc */
|
|
|
|
if (mem[065] != 0) {
|
|
if (T_INST) fprintf(stderr," JST* '65 [%o]\n", mem[065]);
|
|
mem[mem[065]] = RPL;
|
|
RPL = mem[065]+1;
|
|
return;
|
|
}
|
|
|
|
if (svcinfo[class][func].numargs == 99)
|
|
goto badsvc;
|
|
|
|
if (svcinfo[class][func].locargs != 0)
|
|
fatal("Can't handle LOC() args");
|
|
|
|
actargs = 0;
|
|
if (svcinfo[class][func].numargs == 1) {
|
|
actargs = 1;
|
|
arg[0] = mem+mem[argl++];
|
|
if (mem[argl] == 0) /* single arg: terminating zero is optional */
|
|
argl++;
|
|
} else if (svcinfo[class][func].numargs > 0) {
|
|
while (mem[argl] != 0) {
|
|
if (actargs < MAXSVCARGS)
|
|
arg[actargs++] = mem+mem[argl];
|
|
argl++;
|
|
}
|
|
argl++; /* skip terminating zero */
|
|
while (actargs < svcinfo[class][func].numargs)
|
|
arg[actargs++] == NULL;
|
|
}
|
|
|
|
if (T_INST) fprintf(stderr," return=%o, actargs=%d\n", argl, actargs);
|
|
|
|
switch (class) {
|
|
case 0: /* same as class 1 */
|
|
case 1: /* funcs 0-'15 */
|
|
switch (func) {
|
|
case 0: /* ATTACH (NAME,DEV,PASSWD,HOMESET,ALTRTN) */
|
|
goto unimp;
|
|
case 1: /* SEARCH (KEY,NAME,UNIT,ALTRTN) */
|
|
goto unimp;
|
|
case 2: /* SAVE (RVEC,NAME) */
|
|
goto unimp;
|
|
case 3: /* RESTOR (RVEC,NAME,ALTRTN) */
|
|
goto unimp;
|
|
case 4: /* RESUME (NAME) */
|
|
goto unimp;
|
|
case 5: /* EXIT () */
|
|
os_exit();
|
|
case 6: /* ERRRTN (ALTRTN,'XXXXXX',MSG,MSGLEN) */
|
|
goto unimp;
|
|
case 7: /* UPDATE */
|
|
goto unimp;
|
|
case 010: /* GETERR (BUFF,N) */
|
|
goto unimp;
|
|
case 011: /* PRERR () */
|
|
goto unimp;
|
|
case 012: /* GINFO (BUFF,N) */
|
|
os_ginfo(arg[0], arg[1]);
|
|
break;
|
|
case 013: /* CNAME$ (OLDNAM,NEWNAM,ALTRTN) */
|
|
goto unimp;
|
|
case 014: /* ERRSET (ALTVAL,ALTRTN,'XXXXXX','MSG',MSGLEN) */
|
|
goto unimp;
|
|
case 015: /* FORCEW (KEY,UNIT) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 2: /* funcs 0-3 */
|
|
goto unimp;
|
|
break;
|
|
|
|
case 3: /* func 0 = PRWFIL */
|
|
switch (func) {
|
|
case 0: /* PRWFIL (KEY,UNIT,LOC(BUF),N,POS,ALTRTN) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 4: /* func 0 = FAMSVC (obsolete) */
|
|
goto unimp;
|
|
break;
|
|
|
|
case 5: /* funcs 0-'17 */
|
|
switch (func) {
|
|
case 0: /* RREC (PBAV,NWV,N,RA16,PDEV,ALTRTN) */
|
|
goto unimp;
|
|
case 1: /* WREC (PBAV,NWV,N,RA16,PDEV,ALTRTN) */
|
|
goto unimp;
|
|
case 2: /* TIMDAT (BUFF,N) */
|
|
os_timdat(arg[0], arg[1]);
|
|
break;
|
|
case 3: /* DIGIN (N,ADRVEC,DATVEC,ALTRTN) */
|
|
goto unimp;
|
|
case 4: /* DIGINW (same, but initial arg of 1 instead of 0 to DIGIN) */
|
|
goto unimp;
|
|
case 5: /* RECYCL */
|
|
goto unimp;
|
|
case 6: /* D$INIT (PDEV) */
|
|
goto unimp;
|
|
case 7: /* BREAK$ (ONOFF) */
|
|
os_break$(arg[0]);
|
|
break;
|
|
case 010: /* T$MT (UNIT,LOC(BUF),NW,INST,STATV,CODE) */
|
|
goto unimp;
|
|
case 011: /* T$LMPC (UNIT,LOC(BUF),NW,INST,STATV) */
|
|
goto unimp;
|
|
case 012: /* T$CMPC (UNIT,LOC(BUF),NW,INST,STATV) */
|
|
goto unimp;
|
|
case 013: /* T$AMLC (LINE,LOC(BUF),NW,INST,STATV) */
|
|
goto unimp;
|
|
case 014: /* T$VG (UNIT,LOC(BUF),NW,INST,STATV) */
|
|
goto unimp;
|
|
case 015: /* T$PMPC (UNIT,LOC(BUF),NW,INST,STATV) */
|
|
goto unimp;
|
|
case 016: /* RRECL (PBAV,NWV,N,RA32,PDEV,ALTRTN) */
|
|
goto unimp;
|
|
case 017: /* WRECL (PBAV,NWV,N,RA32,PDEV,ALTRTN) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 6: /* funcs 0-5 */
|
|
switch (func) {
|
|
case 0: /* COMANL () */
|
|
os_comanl();
|
|
break;
|
|
case 1: /* C1IN (CHAR) */
|
|
os_c1in(arg[0]);
|
|
break;
|
|
case 2: /* CMREAD (BUFF) */
|
|
strncpy(arg[0], " ", 6);
|
|
break;
|
|
case 3: /* COMINP (FILNAM,UNIT,ALTRTN) */
|
|
goto unimp;
|
|
case 4: /* CNIN$ (BUF,MAXCHARS,ACTCHARS) */
|
|
os_cnin$(arg[0], arg[1], arg[2]);
|
|
break;
|
|
case 5: /* PHANT$ (FILNAM,NAMLEN,UNIT,USER,CODE) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
switch (func) {
|
|
case 0: /* T1IN (CHAR) */
|
|
os_c1in(arg[0]);
|
|
break;
|
|
case 1: /* T1OU (CHAR) */
|
|
os_t1ou(arg[0]);
|
|
break;
|
|
case 2: /* TNOU */
|
|
case 3: /* TNOUA */
|
|
os_tnoua(arg[0],arg[1]);
|
|
if (func == 2) {
|
|
temp16 = 1;
|
|
os_tnoua("\n", &temp16);
|
|
}
|
|
break;
|
|
case 4: /* TOOCT (NUMBER) */
|
|
goto unimp;
|
|
case 5: /* DUPLX$ (KEY) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 010:
|
|
switch (func) {
|
|
case 0: /* T$MT (UNIT,LOC(BUF),NW,INST,STATV,CODE) */
|
|
goto unimp;
|
|
case 1: /* T$SLC1 (KEY,LINE,LOC(BUF),NWORDS) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 011:
|
|
switch (func) {
|
|
case 0: /* T$LMPC (UNIT,LOC(BUF),NW,INST,STATV,CODE) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 012:
|
|
switch (func) {
|
|
case 0: /* T$CMPC (UNIT,LOC(BUF),NW,INST,STATV,CODE) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 013:
|
|
switch (func) { /* func is 0-2 */
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 014:
|
|
switch (func) {
|
|
case 0: /* ATTAC$ (NAME,NAMLEN,LDEV,PASSWD,KEY,LOC(CODE)) */
|
|
goto unimp;
|
|
case 1: /* CREAT$ (NAME,NAMLEN,OWNER,NONOWNER,LOC(CODE)) */
|
|
goto unimp;
|
|
case 2: /* ERRPR$ (KEY,CODE,TEXT,TEXTLEN,PROGNAME,NAMLEN) */
|
|
os_errpr$ (arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
|
|
break;
|
|
case 4: /* GPASS$ (NAME,NAMLEN,OWNER,NONOWNER,LOC(CODE) */
|
|
goto unimp;
|
|
case 6: /* PRWFL$ (KEY,UNIT,LOC(BUF),NW,POS,RNW,LOC(CODE)) */
|
|
goto unimp;
|
|
case 7: /* RDENT$ (KEY,UNIT,BUF,BUFSIZ,RNW,NAME,NAMLEN,LOC(CODE)) */
|
|
goto unimp;
|
|
case 010: /* SATTR$ (KEY,NAME,NAMLEN,ARRAY,LOC(CODE)) */
|
|
goto unimp;
|
|
case 011: /* SEARC$ (KEY,NAME,NAMLEN,UNIT,TYPE,LOC(CODE) */
|
|
goto unimp;
|
|
case 012: /* SEGDR$ (KEY,UNIT,ENTRYA,ENTRYB,LOC(CODE)) */
|
|
goto unimp;
|
|
case 013: /* SPASS$ (OWNER,NONOWNER,LOC(CODE)) */
|
|
goto unimp;
|
|
case 015: /* CNGNM$ (OLDNAM,OLDLEN,NEWNAM,NEWLEN,LOC(CODE)) */
|
|
goto unimp;
|
|
case 016: /* COMIN$ (FILNAM,NAMLEN,UNIT,LOC(CODE)) */
|
|
goto unimp;
|
|
case 017: /* RDTKN$ (KEY,INFO(5),BUF,BUFLEN,LOC(CODE)) */
|
|
goto unimp;
|
|
case 020: /* RESTO$ (RVEC(9),FILNAM,NAMLEN,LOC(CODE)) */
|
|
goto unimp;
|
|
case 021: /* RESUM$ (NAME,NAMLEN) */
|
|
goto unimp;
|
|
case 022: /* SAVE$ (RVEC,FILNAM,NAMLEN,LOC(CODE)) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
case 015:
|
|
switch (func) {
|
|
case 0: /* ATCH$$ (UFDNAM,NAMLEN,LDEV,PASSWD,KEY,CODE) */
|
|
goto unimp;
|
|
case 1: /* CREA$$ (NAME,NAMLEN,OPASS,NPASS,CODE) */
|
|
goto unimp;
|
|
case 4: /* GPAS$$ (UFDNAM,NAMLEN,OPASS,NPASS,CODE) */
|
|
goto unimp;
|
|
case 6: /* PRWF$$ (KEY,FUNIT,LOC(BUF),BUFLEN,POS32,RNW,CODE) */
|
|
goto unimp;
|
|
case 7: /* RDEN$$ (KEY,FUNIT,BUF,BUFLEN,RNW,NAME32,NAMLEN,CODE) */
|
|
goto unimp;
|
|
case 010: /* SATR$$ (KEY,NAME,NAMLEN,ARRAY,CODE) */
|
|
goto unimp;
|
|
case 011: /* SRCH$$ (KEY,NAME,NAMLEN,FUNIT,TYPE,CODE) */
|
|
goto unimp;
|
|
case 012: /* SGDR$$ (KEY,FUNIT,ENTRYA,ENTRYB,CODE) */
|
|
goto unimp;
|
|
case 013: /* SPAS$$ (OWNER,NON-OWNER,CODE) */
|
|
goto unimp;
|
|
case 015: /* CNAM$$ (OLDNAM,OLDLEN,NEWNAM,NEWLEN,CODE) */
|
|
goto unimp;
|
|
case 016: /* COMI$$ (FILNAM,NAMLEN,UNIT,CODE) */
|
|
goto unimp;
|
|
case 017: /* RDTK$$ (KEY,INFO(5),BUF,BUFLEN,CODE) */
|
|
os_rdtk$$ (arg[0], arg[1], arg[2], arg[3], arg[4]);
|
|
break;
|
|
case 020: /* REST$$ (RVEC,NAME,NAMLEN,CODE) */
|
|
goto unimp;
|
|
case 021: /* RESU$$ (NAME,NAMLEN) */
|
|
goto unimp;
|
|
case 022: /* SAVE$$ (RVEC,NAME,NAMLEN,CODE) */
|
|
goto unimp;
|
|
case 023: /* COMO$$ (KEY,NAME,NAMLEN,XXXXXX,CODE) */
|
|
goto unimp;
|
|
case 024: /* ERKL$$ (KEY,ERASECH,KILLCH,CODE) */
|
|
os_erkl$$(arg[0], arg[1], arg[2], arg[3]);
|
|
break;
|
|
case 025: /* RDLIN$ (UNIT,LINE,NWDS,CODE) */
|
|
goto unimp;
|
|
case 026: /* WTLIN$ (UNIT,LINE,NWDS,CODE) */
|
|
goto unimp;
|
|
default:
|
|
goto unimp;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
goto unimp; /* bad class */
|
|
}
|
|
|
|
/* after the SVC, argl is the return address */
|
|
|
|
if (T_INST) fprintf(stderr," returning from SVC to %o\n", argl);
|
|
RPL = argl;
|
|
return;
|
|
|
|
|
|
unimp:
|
|
|
|
printf(" svc not implemented, class=%o, func=%o\n", class, func);
|
|
fatal(NULL);
|
|
|
|
/* here on a bad svc; if the bounce bit (bit 2) is set in the code word,
|
|
jump to the location following the code word (which is typically a
|
|
JMP instruction). If the bounce bit isn't set, we have to halt */
|
|
|
|
badsvc:
|
|
|
|
if (code & 040000) {
|
|
RPL++;
|
|
if (T_INST) fprintf(stderr," bouncing svc error to address %o\n", RPL);
|
|
return;
|
|
}
|
|
|
|
printf(" halting on bad svc, class=%o, func=%o\n", class, func);
|
|
fatal(NULL);
|
|
}
|
|
|
|
|
|
|
|
/* here for PIO instructions: OCP, SKS, INA, OTA. The instruction
|
|
word is passed in as an argument to handle EIO (Execute I/O) in
|
|
V-mode.
|
|
*/
|
|
|
|
pio(unsigned int inst) {
|
|
short class;
|
|
short func;
|
|
short device;
|
|
|
|
RESTRICT();
|
|
class = inst >> 14;
|
|
func = (inst >> 6) & 017;
|
|
device = inst & 077;
|
|
if (T_INST) fprintf(stderr," pio, class=%d, func='%o, device='%o\n", class, func, device);
|
|
if (devmap[device])
|
|
devmap[device](class, func, device);
|
|
else {
|
|
fprintf(stderr,"pio: no handler for device '%o\n", device);
|
|
return;
|
|
fatal(NULL);
|
|
}
|
|
}
|