From f5ed23867fc4a4f90440883f156862f408f56cb0 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 27 Apr 2015 23:20:16 +0200 Subject: [PATCH 01/18] Fix bad code generation multiple modifications of the same variable between sequence points leads to undefined behaviour. --- src/kn10def.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kn10def.h b/src/kn10def.h index 99b5d18..66e7770 100644 --- a/src/kn10def.h +++ b/src/kn10def.h @@ -235,7 +235,8 @@ typedef int pcinc_t; /* Type of all instruction routines */ #if KLH10_EXTADR # define PC_ADDXCT(x) { register pcinc_t i__ = (x); if (i__) PC_ADD(i__); } #else -# define PC_ADDXCT(x) (cpu.mr_PC += (x)) /* For now; fix up later? */ +# define PC_ADDXCT(x) { volatile pcinc_t i__ = (x); cpu.mr_PC += i__; } +/*# define PC_ADDXCT(x) (cpu.mr_PC += (x)) / * For now; fix up later? */ #endif /* Macros for putting PC into a word. From 0a03946833d3bff4258eb439bdc5bbfad69a3c5b Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 27 Apr 2015 23:33:58 +0200 Subject: [PATCH 02/18] Add tap/bridge support, and some other small build support things for my environment. --- bld/nbaxp/00build | 3 + bld/nbx86/00build | 2 + doc/install.txt | 40 +++++++ run/klt20/klt20.ini | 7 +- src/Mk-nbx86.mk | 2 +- src/dpimp.c | 4 + src/dpni20.c | 47 ++++++-- src/klh10.c | 3 + src/kn10ops.c | 4 +- src/osdnet.c | 283 +++++++++++++++++++++++++++++++++++++++++--- src/osdnet.h | 15 ++- 11 files changed, 374 insertions(+), 36 deletions(-) diff --git a/bld/nbaxp/00build b/bld/nbaxp/00build index 2c71ab1..c33ba7a 100755 --- a/bld/nbaxp/00build +++ b/bld/nbaxp/00build @@ -1,2 +1,5 @@ #!/bin/sh make base-kl CONFFLAGS_AUX=-DKLH10_I_CIRC=1 +# or +# make base-ks CONFFLAGS_AUX=-DKLH10_I_CIRC=1 +# make base-ks-its CONFFLAGS_AUX=-DKLH10_I_CIRC=1 diff --git a/bld/nbx86/00build b/bld/nbx86/00build index 2c71ab1..4e1debd 100755 --- a/bld/nbx86/00build +++ b/bld/nbx86/00build @@ -1,2 +1,4 @@ #!/bin/sh +export KL10HOME=/scratch/tops20/emulators/panda-dist/i386 make base-kl CONFFLAGS_AUX=-DKLH10_I_CIRC=1 +#make base-ks-its CONFFLAGS_AUX=-DKLH10_I_CIRC=1 diff --git a/doc/install.txt b/doc/install.txt index 38c0ec1..69f640c 100644 --- a/doc/install.txt +++ b/doc/install.txt @@ -175,6 +175,16 @@ config file if they don't already exist (correct as of FreeBSD 4.2): pseudo-device bpf 1 # Need at least one for NI20 or IMP pseudo-device tun 1 # Need at least one for IMP +NetBSD +------ + See The NetBSD Guide, chapter 17.9 "Kernel Tuning" for information on +how to recompile a kernel. You need at least these options (as of 3.0): + + options SYSVSHM # System V-like memory sharing + options SHMMAXPGS=10240 # 2048 pages is the default, >8192 for KLH10 + + pseudo-device tap # cloning device for NI20 + pseudo-device bridge # cloning device for NI20 Linux ----- @@ -1116,6 +1126,36 @@ mistakenly "fixed" to disallow it (FreeBSD). other host before telnetting back into the KN10. A better solution would be to fix those OSes that are open-source, and push to have these fixes incorporated in the standard releases. + For NetBSD (it may work on FreeBSD too) there exists a better +solution. A special configuration is created with a virtual ethernet +segment that has its host-side in the form of the interface tap0 (as in +the example below). The tap0 interface is bridged to the real network +interface. The NI20 is at the "other end" of the virtual ethernet. +(This differs from the other connectivity methods where the named +interface is the one that is basically used as the NI20). The NI20 is +therefore a dedicated interface: + + devdef ni0 564 ni20 ipaddr=10.0.0.51 ifc=tap0 dedic=true + +If the named tap interface already exists, no further changes to its +configuration are made. You can use this for alternative connectivity, +such as routed on the 10.0.1.0/24 subnet (instead of bridged): + + # To the shell, suppose your real network is 10.0.0.0/24, + # create a 10.0.1.0/24 network for KLH: + ifconfig tap0 create inet 10.0.1.1 netmask 255.255.255.0 up + ; in .ini file: + devdef ni0 564 ni20 ipaddr=10.0.1.51 ifc=tap0 dedic=true + ! in SYSTEM:INTERNET.ADDRESS on TOPS-20 v7.0 + IPNI#0,10 0 1 51,PACKET-SIZE:1500,DEFAULT,PREFERRED + ! in SYSTEM:INTERNET.ADDRESS on TOPS-20 v7.1 + IPNI#0,10.0.1.51,PACKET-SIZE:1500,LOGICAL-HOST-MASK:255.255.255.0,DEFAULT,PREFERRED + ! in SYSTEM:INTERNET.GATEWAYS on TOPS-20 v7.x + PRIME 10.0.1.1 + +(If TOPS-20 v7.0 can't do subnetting it might be better to use a +192.168.2.0/24 network) + LHDH (IMP): (KS-ITS only) diff --git a/run/klt20/klt20.ini b/run/klt20/klt20.ini index ad66100..2a7a489 100644 --- a/run/klt20/klt20.ini +++ b/run/klt20/klt20.ini @@ -12,7 +12,12 @@ devdef mta0 rh1.0 tm03 type=tu45 ; Need KLNI to avoid LAPRBF BUGCHKs - use valid address if known ; -devdef ni0 564 ni20 ipaddr=10.0.0.51 +; devdef ni0 564 ni20 ipaddr=10.0.0.51 +; The (NetBSD/FreeBSD) version with tap(4) and bridge(4) creates the named +; tap device dynamically and bridges it to the default interface. +; If you want it differently (for instance routed instead of bridged), +; you can create the tap yourself and it will be used as it is. +devdef ni0 564 ni20 ipaddr=10.0.0.51 ifc=tap0 dedic=true ; Load disk bootstrap directly load boot.sav diff --git a/src/Mk-nbx86.mk b/src/Mk-nbx86.mk index 05931e0..64816d5 100644 --- a/src/Mk-nbx86.mk +++ b/src/Mk-nbx86.mk @@ -21,7 +21,7 @@ # Build definitions SRC = ../../src -CFLAGS = -c -g3 -O3 +CFLAGS = -c -g3 -O3 -ggdb CFLAGS_LINT = -ansi -pedantic -Wall -Wshadow \ -Wstrict-prototypes -Wmissing-prototypes \ -Wmissing-declarations -Wredundant-decls diff --git a/src/dpimp.c b/src/dpimp.c index 6428dd3..afe4e9b 100644 --- a/src/dpimp.c +++ b/src/dpimp.c @@ -228,6 +228,10 @@ default for every OS that implements /dev/tun. #include /* For setpriority() */ #include /* For mlockall() */ +#if CENV_SYS_NETBSD +#include +#endif + #include "dpimp.h" /* DPIMP specific defs, grabs DPSUP if needed */ #ifdef RCSID diff --git a/src/dpni20.c b/src/dpni20.c index 0690b1b..3085e0f 100644 --- a/src/dpni20.c +++ b/src/dpni20.c @@ -169,6 +169,7 @@ The following general situations are possible: RCSID(dpni20_c,"$Id: dpni20.c,v 2.7 2003/02/23 18:07:50 klh Exp $") #endif + /* Globals */ int chpid; /* PID of child, handles input (net-to-10). */ @@ -432,6 +433,8 @@ main(int argc, char **argv) progname = progname_w; /* Reset progname to indicate identity */ tentoeth(dpni); /* Parent process handles output to net */ + osn_pfdeinit(); + return 1; /* Never returns, but placate compiler */ } @@ -498,6 +501,7 @@ void net_init(register struct dpni20_s *dpni) ea_set(&ihost_ea, &npf.osnpf_ea); /* Copy actual ea */ } + /* Now set any return info values in shared struct. */ memcpy(dpni->dpni_eth, (char *)&ihost_ea, 6); /* Copy ether addr */ @@ -996,7 +1000,7 @@ pfshow(struct OSN_PFSTRUCT *pf) /* LNX packetfilter initialization */ -#if KLH10_NET_LNX +#if KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE /* The Linux PF_PACKET interface is described to some extent @@ -1092,6 +1096,10 @@ int lnx_filter(register struct dpni20_s *dpni, */ void eth_adrset(register struct dpni20_s *dpni) { +#if OSN_USE_IPONLY + dbprintln("\"%s\" multicast table ignored - IP-only interface", + dpni->dpni_ifnam); +#else unsigned char rdea[ETHER_ADRSIZ]; char old[OSN_EASTRSIZ]; char new[OSN_EASTRSIZ]; @@ -1157,6 +1165,7 @@ void eth_adrset(register struct dpni20_s *dpni) } } +#endif /* Assume succeeded since call succeeded, and clobber our address! */ memcpy(dpni->dpni_eth, dpni->dpni_rqeth, ETHER_ADRSIZ); } @@ -1175,6 +1184,10 @@ void eth_adrset(register struct dpni20_s *dpni) void eth_mcatset(register struct dpni20_s *dpni) { +#if OSN_USE_IPONLY + dbprintln("\"%s\" multicast table ignored - IP-only interface", + dpni->dpni_ifnam); +#else ossock_t s; int i, n, j; char ethstr[OSN_EASTRSIZ]; @@ -1249,6 +1262,7 @@ void eth_mcatset(register struct dpni20_s *dpni) nmcats = n; memcpy(ethmcat[0], dpni->dpni_mcat[0], (n * 6)); +#endif } /* ARP Hackery */ @@ -1361,7 +1375,9 @@ int arp_myreply(register unsigned char *buf, register int cnt) /* Now send it! Ignore any errors. */ if (swstatus) { char ipstr[OSN_IPSTRSIZ]; - dbprintln("ARP MyReply %s", ip_adrsprint(ipstr, ife->ife_ipchr)); + char ethstr[OSN_EASTRSIZ]; + dbprintln("ARP MyReply %s %s", ip_adrsprint(ipstr, ife->ife_ipchr), + eth_adrsprint(ethstr, ife->ife_ea)); } #if KLH10_NET_DLPI @@ -1372,6 +1388,9 @@ int arp_myreply(register unsigned char *buf, register int cnt) (void) putmsg(pffd, NULL, &data, 0); } #else + /* XXX + * Why is this sent to the packet filter (= host) and not to the -10????? + */ (void)write(pffd, pktbuf, sizeof(pktbuf)); #endif return TRUE; @@ -1441,7 +1460,7 @@ void ethtoten(register struct dpni20_s *dpni) cnt = data.len; /* Else cnt must be -1 as call failed */ } -#elif KLH10_NET_NIT || KLH10_NET_PFLT || KLH10_NET_LNX +#elif KLH10_NET_NIT || KLH10_NET_PFLT || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE cnt = read(pffd, buff, max); #elif KLH10_NET_BPF cnt = read(pffd, tbuff, tmax); @@ -1499,17 +1518,20 @@ void ethtoten(register struct dpni20_s *dpni) else dbprint("Read=%d", cnt); } -#if KLH10_NET_LNX +#if KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE /* Linux has no packet filtering, thus must apply manual check to each and every packet read, unless dedicated. Ugh! */ - if (!dpni->dpni_dedic) { + if (KLH10_NET_TAP_BRIDGE || !dpni->dpni_dedic) { /* Sharing interface. Check for IP, DECNET, 802.3 */ - if (!lnx_filter(dpni, buff, cnt)) + if (!lnx_filter(dpni, buff, cnt)) { + if (DBGFLG) + dbprint("Dropped"); continue; /* Drop packet, continue reading */ + } } #endif /* KLH10_NET_LNX */ -#if KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX +#if KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE #if 0 if (DBGFLG) if (((struct ether_header *)buff)->ether_type == htons(ETHERTYPE_ARP)) @@ -1521,7 +1543,7 @@ void ethtoten(register struct dpni20_s *dpni) if (DBGFLG) dbprint("sent RPKT"); -#endif /* KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX */ +#endif /* KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX || NET_TAP_BRIDGE */ #if KLH10_NET_BPF /* Screwy BPF algorithm requires more overhead because there's @@ -1594,7 +1616,11 @@ void tentoeth(register struct dpni20_s *dpni) /* Must check for outbound ARP requests if asked to and have ** at least one entry in our table of host's IP interfaces. */ +#if KLH10_NET_TAP_BRIDGE + doarpchk = 0; +#else doarpchk = (dpni->dpni_doarp & DPNI_ARPF_OCHK) && (osn_nifents() > 0); +#endif dpx = dp_dpxto(&dp); /* Get ptr to "To-DP" xfer stuff */ buff = dp_xrbuff(dpx, &max); @@ -1640,7 +1666,7 @@ void tentoeth(register struct dpni20_s *dpni) } #else cnt = write(pffd, buff, rcnt); -#endif +#endif /* else KLH10_NET_DLPI */ if (cnt != rcnt) { if ((cnt < 0) && (errno == EINTR)) { continue; /* Start over, may have new cmd */ @@ -1701,6 +1727,9 @@ void dumppkt(unsigned char *ucp, int cnt) fprintf(stderr, "\r\n"); } } + + + /* Add OSDNET shared code here */ diff --git a/src/klh10.c b/src/klh10.c index d01a4b6..4b68f3f 100644 --- a/src/klh10.c +++ b/src/klh10.c @@ -337,6 +337,7 @@ CMDDEF(cd_lights, fc_lights, CMRF_TLIN, "", KEYSBEGIN(fectbkeys) KEYDEF("?", cd_ques) KEYDEF("help", cd_help) + KEYDEF("exit", cd_quit) KEYDEF("quit", cd_quit) KEYDEF("load", cd_load) KEYDEF("dump", cd_dump) @@ -2765,6 +2766,7 @@ fc_dump(struct cmd_s *cm) static void fc_lights(struct cmd_s *cm) { +#if KLH10_DEV_LITES /* Moby conditional for entire file */ unsigned long port = 0; int c; char *sloc = cm->cmd_arglin; @@ -2783,6 +2785,7 @@ fc_lights(struct cmd_s *cm) } } printf("?Bad address\n"); +#endif /* KLH10_DEV_LITES */ } /* Instruction printing routines */ diff --git a/src/kn10ops.c b/src/kn10ops.c index 3c9eee3..9ac90b9 100644 --- a/src/kn10ops.c +++ b/src/kn10ops.c @@ -759,7 +759,7 @@ dw10_t op10ashc(register dw10_t d, ** must be done to the argument prior to the call! */ static dw10_t -x_ashc(register dw10_t d, +x_ashc(/*register*/ dw10_t d, register int i) { #endif /* IFFLAGS */ @@ -3238,7 +3238,7 @@ static int qdivstep(qw10_t *aq, register dw10_t d, register int nmagbits) { - register qw10_t qw; + /*register*/ qw10_t qw; dw10_t quot; register int qbit; diff --git a/src/osdnet.c b/src/osdnet.c index ba664a1..96e0093 100644 --- a/src/osdnet.c +++ b/src/osdnet.c @@ -68,7 +68,7 @@ int osn_ifsock(char *ifnam, ossock_t *as) { #if (KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \ - KLH10_NET_TUN || KLH10_NET_LNX) + KLH10_NET_TUN || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE) return ((*as = socket(AF_INET, SOCK_DGRAM, 0)) >= 0); #else # error OSD implementation needed for osn_ifsock @@ -79,7 +79,7 @@ int osn_ifclose(ossock_t s) { #if (KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \ - KLH10_NET_TUN || KLH10_NET_LNX) + KLH10_NET_TUN || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE) return (close(s) >= 0); #else # error OSD implementation needed for osn_ifclose @@ -161,6 +161,12 @@ or alternatively: ? (sizeof(struct ifreq) - sizeof(struct sockaddr) + (ifr).ifr_addr.sa_len) \ : sizeof(struct ifreq)) + This has been made trickier by NetBSD 5.0, which doesn't put a sockaddr + but a (union with as largest member a) sockaddr_storage in the ifreq. + Now the size is always the same again, but not sizeof(struct sockaddr). + This can (probably) be recognised by the existence of + #define ifr_space ifr_ifru.ifru_space / * sockaddr_storage * / + */ /* Note that searching for AF_INET or IP addresses only finds interfaces that @@ -288,7 +294,7 @@ osn_iftab_pass(int opts, int npass, int s, struct ifconf *ifc) uses a variable-size "ifreq" entry! Choke... */ ifnext = ifp + 1; /* Assume normal entry at first */ -#if NETIF_HAS_SALEN +#if NETIF_HAS_SALEN && !defined(ifr_space) if (ifp->ifr_addr.sa_len > sizeof(struct sockaddr)) { offset = ifp->ifr_addr.sa_len - sizeof(struct sockaddr); ifnext = (struct ifreq *)((char *)ifnext + offset); @@ -382,6 +388,8 @@ osn_iftab_pass(int opts, int npass, int s, struct ifconf *ifc) } } +#include + void osn_ifctab_show(FILE *f, struct ifconf *ifc) { @@ -393,7 +401,14 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) int nents = 0; int nvary = 0; - fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\n", + fprintf(f, "sizeof struct ifreq = %d\r\n", (int) sizeof(struct ifreq)); + fprintf(f, "IFNAMSIZ = %d\r\n", (int) IFNAMSIZ); + fprintf(f, "offset of struct sockaddr_storage = %d\r\n", (int) offsetof(struct ifreq, ifr_space)); + fprintf(f, "sizeof struct sockaddr = %d\r\n", (int) sizeof(struct sockaddr)); + fprintf(f, "sizeof struct sockaddr_storage = %d\r\n", (int) sizeof(struct sockaddr_storage)); + fprintf(f, "sizeof union ifr_ifru = %d\r\n", (int) sizeof(ifr->ifr_ifru)); + + fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\r\n", (long)ifc->ifc_len, ifc->ifc_len/sizeof(struct ifreq), (int)sizeof(struct sockaddr)); @@ -408,18 +423,19 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) len = sizeof(struct sockaddr); #endif + fprintf(f, "offset: %d\r\n", (int)((char *)ifr - (char *)ifc->ifc_req)); /* Output entry data */ - fprintf(f, "%2d: \"%.*s\" fam %d, len %d", + fprintf(f, "%2d: \"%.*s\" sockaddr.sa_family %d, .sa_len %d", i, (int)sizeof(ifr->ifr_name), ifr->ifr_name, ifr->ifr_addr.sa_family, len); if (len) { cp = (unsigned char *) ifr->ifr_addr.sa_data; - fprintf(f, " = %x", *cp); + fprintf(f, " = (sockaddr.sa_data) %x", *cp); for (--len; len > 0; --len) { fprintf(f, ":%x", *++cp); } } - fprintf(f, "\n"); + fprintf(f, "\r\n"); cp = (unsigned char *) ifr->ifr_addr.sa_data; switch (ifr->ifr_addr.sa_family) { @@ -429,7 +445,7 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) struct in_addr *in = &skin->sin_addr; unsigned char *ucp = (unsigned char *) &in->s_addr; - fprintf(f, " AF_INET = port %d, IP %d.%d.%d.%d\n", + fprintf(f, " AF_INET = port %d, IP %d.%d.%d.%d\r\n", (int)skin->sin_port, ucp[0], ucp[1], ucp[2], ucp[3]); } @@ -439,7 +455,7 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) case AF_LINK: { struct sockaddr_dl *dla = (struct sockaddr_dl *) &ifr->ifr_addr; - fprintf(f, " AF_LINK = type %d, alen %d", + fprintf(f, " AF_LINK = type %d, sdl_alen %d", dla->sdl_type, dla->sdl_alen); if (len = dla->sdl_alen) { cp = (unsigned char *) LLADDR(dla); @@ -448,18 +464,23 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) fprintf(f, ":%x", *++cp); } } - fprintf(f, "\n"); + fprintf(f, "\r\n"); } break; #endif +#if defined(AF_INET6) + case AF_INET6: + fprintf(f, " AF_INET6 (No handler for this)\r\n"); + break; +#endif default: - fprintf(f, " No handler for this family\n"); + fprintf(f, " No handler for this family\r\n"); } /* Move onto next entry */ -#if NETIF_HAS_SALEN +#if NETIF_HAS_SALEN && !defined(ifr_space) if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) { ++nvary; ifr = (struct ifreq *)((char *)(ifr + 1) + @@ -469,10 +490,10 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) ifr++; } if (nvary) - fprintf(f, "Interface summary: %d entries of varying length\n", + fprintf(f, "Interface summary: %d entries of varying length\r\n", nents); else - fprintf(f, "Interface summary: %d entries of std length %d\n", + fprintf(f, "Interface summary: %d entries of std length %d\r\n", nents, (int)sizeof(struct ifreq)); } @@ -483,7 +504,7 @@ osn_iftab_show(FILE *f, struct ifent *ifents, int nents) register struct ifent *ife; int i; - fprintf(f, "Filtered IFE table: %d entries\n", nents); + fprintf(f, "Filtered IFE table: %d entries\r\n", nents); for (i = 0, ife = ifents; i < nents; ++i, ++ife) { fprintf(f, "%2d: \"%s\"", i, ife->ife_name); @@ -502,7 +523,7 @@ osn_iftab_show(FILE *f, struct ifent *ifents, int nents) fprintf(f, " (Other: fam %d)", ife->ife_pother->ifr_addr.sa_family); } - fprintf(f, "\n"); + fprintf(f, "\r\n"); } } @@ -897,6 +918,9 @@ osn_ifeaget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ return TRUE; } +static struct eth_addr emhost_ea = /* Emulated host ether addr for tap */ + { 0xf2, 0x0b, 0xa4, 0xff, 0xff, 0xff }; + /* OSN_PFEAGET - get physical ethernet address for an open packetfilter FD. * * Also not well documented, but generally easier to perform. @@ -945,8 +969,20 @@ osn_pfeaget(int pfs, /* Packetfilter socket or FD */ } ea_set(eap, endp.end_addr); -#elif KLH10_NET_BPF && !CENV_SYS_NETBSD && !CENV_SYS_FREEBSD - /* NetBSD no longer seems to support this */ +#elif KLH10_NET_TAP_BRIDGE + /* If we do tap(4) + bridge(4), the ether address of the tap is wholly + * irrelevant, it is on the other side of the "wire". + * Our own address is something we can make up completely. + */ + if (emhost_ea.ea_octets[5] == 0xFF) { + time_t t = time(NULL); + emhost_ea.ea_octets[5] = t & 0xFE; + emhost_ea.ea_octets[4] = (t >> 8) & 0xFF; + emhost_ea.ea_octets[3] = (t >> 16) & 0xFF; + } + ea_set(eap, &emhost_ea); /* Return the ether address */ +#elif (KLH10_NET_BPF && !CENV_SYS_NETBSD && !CENV_SYS_FREEBSD) + /* NetBSD no longer seems to support this (on bpf) */ struct ifreq ifr; strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); @@ -1131,7 +1167,7 @@ osn_ifeaset(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ char *ifnam, /* Interface name */ unsigned char *newpa) /* New ether address */ { -#if CENV_SYS_DECOSF || KLH10_NET_LNX \ +#if CENV_SYS_DECOSF || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE \ || (CENV_SYS_FREEBSD && defined(SIOCSIFLLADDR)) /* Common preamble code */ @@ -1190,6 +1226,8 @@ osn_ifeaset(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ if (ownsock) close(s); return FALSE; } +# elif KLH10_NET_TAP_BRIDGE + ea_set(&emhost_ea, newpa); # else # error "Unimplemented OS routine osn_ifeaset()" # endif @@ -1338,6 +1376,7 @@ pfopen(void) } #endif /* KLH10_NET_PFLT || KLH10_NET_BPF */ + #if KLH10_NET_PFLT @@ -1916,6 +1955,212 @@ osn_pfinit(struct osnpf *osnpf, void *arg) } #endif /* KLH10_NET_NIT */ +/* + * Too bad that this is never called... + */ +osn_pfdeinit() +{ +#if KLH10_NET_TAP_BRIDGE + void tap_bridge_close(); + tap_bridge_close(); +#endif +} + +#if KLH10_NET_TAP_BRIDGE + +osn_pfinit(register struct osnpf *osnpf, void *arg) +{ + int fd; + char *ifnam = osnpf->osnpf_ifnam; + + /* No "default interface" concept here */ + if (!ifnam || !ifnam[0]) + esfatal(1, "Packetfilter interface must be specified"); + + fd = tap_bridge_open(ifnam); + + /* Now get our fresh new virtual interface's ethernet address. + */ + (void) osn_pfeaget(fd, ifnam, (unsigned char *)&(osnpf->osnpf_ea)); + + return fd; +} + +#include +#include +#include + +static struct ifreq br_ifr; +static struct ifreq tap_ifr; +static int my_tap; + +/* + * A TAP is a virtual ethernet interface, much like TUN is a virtual IP + * interface. We can use it to inject packets into the Unix input stream, + * provided it is UP and the host side has a matching IP address and + * netmask (also much like TUN), or that it is bridged to another interface. + * + * Here we try to create the user-given interface and then bridge it to + * the "default" interface. This is probably the most common configuration. + * If something else is desired, the user can set up the tap herself, + * and we'll just use it as it is. This is useful for a routed approach, + * for instance. + */ +int +tap_bridge_open(char *ifnam) +{ + int tapfd; + int res; + union ipaddr netmask; + char cmdbuff[128]; + struct ifent *ife; + int s; + int i; + struct ifbreq br_req; + struct ifdrv br_ifd; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + esfatal(1, "tap_bridge_open: socket() failed"); + } + + /* try to create tapN as specified by the user */ + memset(&tap_ifr, 0, sizeof(tap_ifr)); + strcpy(tap_ifr.ifr_name, ifnam); + res = ioctl(s, SIOCIFCREATE, &tap_ifr); + if (res == 0) { + my_tap = 1; + dbprintln("Created host-side tap \"%s\"", ifnam); + } else { + if (errno != EEXIST) + esfatal(1, "tap_bridge_open: can't create tap \"%s\"?", ifnam); + my_tap = 0; + dbprintln("Host-side tap \"%s\" alread exists; use it as-is", ifnam); + } + + sprintf(cmdbuff, "/dev/%s", ifnam); + tapfd = open(cmdbuff, O_RDWR, 0); + + if (tapfd < 0) { + /* Note possible error meanings: + ENOENT - no such filename + ENXIO - not configured in kernel + */ + esfatal(1, "Couldn't find or open 10-side tap \"%s\"", cmdbuff); + } + + dbprintln("Opened 10-side tap \"%s\"", cmdbuff); + + /* Finally, turn on IFF_UP just in case the above didn't do it. + Note interface name is still there from the SIOCIFCREATE. + */ + if (ioctl(s, SIOCGIFFLAGS, &tap_ifr) < 0) { + esfatal(1, "tap_bridge_open tap SIOCGIFFLAGS failed"); + } + if (!(tap_ifr.ifr_flags & IFF_UP)) { + tap_ifr.ifr_flags |= IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, &tap_ifr) < 0) { + esfatal(1, "tap_bridge_open tap SIOCSIFFLAGS failed"); + } + if (DP_DBGFLG) + dbprint("tap_bridge_open tap did SIOCSIFFLAGS"); + } + + if (my_tap) { + for (i = 0; i < 1000; i++) { + /* try to create bridge%d */ + memset(&br_ifr, 0, sizeof(br_ifr)); + sprintf(br_ifr.ifr_name, "bridge%d", i); + res = ioctl(s, SIOCIFCREATE, &br_ifr); + if (res == 0) + break; + if (errno != EEXIST) + esfatal(1, "tap_bridge_open: can't create bridge \"%s\"?", br_ifr.ifr_name); + } + dbprintln("Created bridge \"%s\"", br_ifr.ifr_name); + + /* + * Find default IP interface to bridge with. + * It might find the wrong one if there is more than one. + */ + + ife = osn_ipdefault(); + if (!ife) + esfatal(0, "Couldn't find default interface"); + + if (swstatus) + dbprintln("Bridging with default interface \"%s\"", ife->ife_name); + + if (1) { + sprintf(cmdbuff, "/sbin/brconfig %s add %s add %s up", + br_ifr.ifr_name, ife->ife_name, ifnam); + res = system(cmdbuff); + dbprintln("%s => %d", cmdbuff, res); + } else { + /* do whatever brconfig bridge0 add intf0 does... */ + memset(&br_ifd, 0, sizeof(br_ifd)); + memset(&br_req, 0, sizeof(br_req)); + + /* set name of the bridge */ + strcpy(br_ifd.ifd_name, br_ifr.ifr_name); + br_ifd.ifd_cmd = BRDGADD; + br_ifd.ifd_len = sizeof(br_req); + br_ifd.ifd_data = &br_req; + + /* brconfig bridge0 add tap0 (the virtual interface) */ + strcpy(br_req.ifbr_ifsname, ifnam); + res = ioctl(s, SIOCSDRVSPEC, &br_ifd); + if (res == -1) + esfatal(1, "tap_bridge_open: can't add virtual intf to bridge?"); + + /* brconfig bridge0 add vr0 (the hardware interface) */ + strcpy(br_req.ifbr_ifsname, ife->ife_name); + res = ioctl(s, SIOCSDRVSPEC, &br_ifd); + if (res == -1) + esfatal(1, "tap_bridge_open: can't add real intf to bridge?"); + + /* Finally, turn on IFF_UP just in case the above didn't do it. + * Note interface name is still there. + */ + if (ioctl(s, SIOCGIFFLAGS, &br_ifr) < 0) { + esfatal(1, "tap_bridge_open bridge SIOCGIFFLAGS failed"); + } + if (!(br_ifr.ifr_flags & IFF_UP)) { + br_ifr.ifr_flags |= IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, &br_ifr) < 0) { + esfatal(1, "tap_bridge_open bridge SIOCSIFFLAGS failed"); + } + if (DP_DBGFLG) + dbprint("tap_bridge_open bridge did SIOCSIFFLAGS"); + } + + } + } + close(s); + + return tapfd; /* Success! */ +} + +void +tap_bridge_close() +{ + if (my_tap) { + int s, res; + struct ifreq tap_ifr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + esfatal(1, "tap_bridge_close: socket() failed"); + } + + /* Destroy bridge */ + res = ioctl(s, SIOCIFDESTROY, &br_ifr); + res = ioctl(s, SIOCIFDESTROY, &tap_ifr); + + close(s); + } +} + +#endif /* KLH10_NET_TAP_BRIDGE */ + #if KLH10_NET_DLPI /* DLPI packetfilter initialization */ diff --git a/src/osdnet.h b/src/osdnet.h index 4f0ab26..028af38 100644 --- a/src/osdnet.h +++ b/src/osdnet.h @@ -59,6 +59,9 @@ #ifndef KLH10_NET_DLPI /* Solaris Data Link Provider Interface */ # define KLH10_NET_DLPI 0 #endif +#ifndef KLH10_NET_TAP_BRIDGE /* BSD Ethernet Tunnel device + a bridge */ +# define KLH10_NET_TAP_BRIDGE 0 +#endif #ifndef KLH10_NET_TUN /* BSD IP Tunnel device */ # define KLH10_NET_TUN 0 #endif @@ -67,14 +70,18 @@ #endif #if !(KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \ - KLH10_NET_TUN || KLH10_NET_LNX) + KLH10_NET_TUN || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE) /* None explicitly specified, pick a reasonable default */ -# if (CENV_SYS_FREEBSD && OSN_USE_IPONLY) +# if ((CENV_SYS_NETBSD || CENV_SYS_FREEBSD) && OSN_USE_IPONLY) # undef KLH10_NET_TUN # define KLH10_NET_TUN 1 # elif (CENV_SYS_NETBSD || CENV_SYS_FREEBSD) -# undef KLH10_NET_BPF -# define KLH10_NET_BPF 1 +/* + * # undef KLH10_NET_BPF + * # define KLH10_NET_BPF 1 + */ +# undef KLH10_NET_TAP_BRIDGE +# define KLH10_NET_TAP_BRIDGE 1 # elif CENV_SYS_DECOSF # undef KLH10_NET_PFLT # define KLH10_NET_PFLT 1 From 79e1a9e89855a410b9bed65a0947d919c267abb6 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 27 Apr 2015 23:34:34 +0200 Subject: [PATCH 03/18] Add a build note for strange error "[DTE: Bad to-10 BP 442200,,733000][dte_10xfrbeg: 10cnt left: 4086][dte_10xfrbeg: out of data, no I bit]" --- src/Makefile.mk | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Makefile.mk b/src/Makefile.mk index 05c6ed0..89d6ab8 100644 --- a/src/Makefile.mk +++ b/src/Makefile.mk @@ -360,6 +360,30 @@ base-kl: -DKLH10_CLIENT=\\\"MyKL\\\" \ $(CONFFLAGS_AUX) " +### +# On Sat, 26 Dec 2009, Jean-Marc Bourguet posted: +# +# > [DTE: Bad to-10 BP 442200,,733000][dte_10xfrbeg: 10cnt left: 4086][dte_10xfrbeg: out of data, no I bit] +# +# This is a known problem on some Linux systems with high performance +# hardware. As far as I know, Ken has not found a fix for it. +# +# The workaround is to rebuild klh10 with a special configuration that +# avoids the esoteric real-time-interrupt mechanisms. +# +# In klh20-2.0h/src/Makefile, lines 357 and 358, you will find: +# -DKLH10_ITIME_INTRP=1 \ +# -DKLH10_CTYIO_INT=1 \ +# +# Change both of these lines so they now read: +# -DKLH10_ITIME_SYNC=1 \ +# -DKLH10_CTYIO_INT=0 \ +# +# You should only do this on a system which has this problem. It will run +# on other systems, but will eat up CPU unnecessarily. +# +# -- Mark -- + #################################################################### ## Lintish versions to see how many compiler warnings we can generate ## From 425337375cde9b5a5aa72ae30313261b23bd994c Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 27 Apr 2015 23:37:11 +0200 Subject: [PATCH 04/18] Remove src/*.old files. --- src/Makefile.mk.old | 726 --------- src/Mk-lnx86.mk.old | 45 - src/dvhost.c.old | 334 ----- src/dvhost.h.old | 46 - src/inexts.c.old | 2585 -------------------------------- src/injrst.c.old | 760 ---------- src/inmove.c.old | 718 --------- src/klh10.c.old | 2881 ------------------------------------ src/klh10.h.old | 410 ------ src/kn10cpu.c.old | 3411 ------------------------------------------- src/kn10def.h.old | 971 ------------ src/kn10pag.c.old | 1965 ------------------------- src/kn10pag.h.old | 973 ------------ src/opcods.h.old | 797 ---------- src/osdnet.c.old | 2609 --------------------------------- src/osdsup.c.old | 1724 ---------------------- 16 files changed, 20955 deletions(-) delete mode 100644 src/Makefile.mk.old delete mode 100644 src/Mk-lnx86.mk.old delete mode 100644 src/dvhost.c.old delete mode 100644 src/dvhost.h.old delete mode 100644 src/inexts.c.old delete mode 100644 src/injrst.c.old delete mode 100644 src/inmove.c.old delete mode 100644 src/klh10.c.old delete mode 100644 src/klh10.h.old delete mode 100644 src/kn10cpu.c.old delete mode 100644 src/kn10def.h.old delete mode 100644 src/kn10pag.c.old delete mode 100644 src/kn10pag.h.old delete mode 100644 src/opcods.h.old delete mode 100644 src/osdnet.c.old delete mode 100644 src/osdsup.c.old diff --git a/src/Makefile.mk.old b/src/Makefile.mk.old deleted file mode 100644 index d8112fe..0000000 --- a/src/Makefile.mk.old +++ /dev/null @@ -1,726 +0,0 @@ -# KLH10 Makefile. -# $Id: Makefile.mk,v 2.6 2002/03/21 09:44:05 klh Exp $ -# -# Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -# All Rights Reserved -# -# This file is part of the KLH10 Distribution. Use, modification, and -# re-distribution is permitted subject to the terms in the file -# named "LICENSE", which contains the full text of the legal notices -# and should always accompany this Distribution. -# -# This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -# -# This notice (including the copyright and warranty disclaimer) -# must be included in all copies or derivations of this software. -# -##################################################################### - -# KLH10 Makefile scheme -# -# /src/ -# Makefile - Top-level makefile for in-src build (not recommended) -# Makefile.mk - All generic rules and definitions -# Mk-.mk - Platform-specific definitions -# -# /bld/ -# Makefile -> ../../src/Mk-.mk -# (or local version thereof) -# [any locally munged .h files] -# -# Each top-level makefile should define at least the following: -# SRC = -# -##################################################################### - - -# Basic default definitions. -# Normally these will be overridden by build-specific make -# invocations, by both or either of: -# (1) concatenation of a platform-specific makefile of the -# form "Mk-.mk" -# (the most recent defs override these defaults) -# (2) command line definitions, which override those from any files. - -# Generic compile/link flags -# Suitable for plain vanilla Unix but normally overridden. -CC = cc -CFLAGS = -c -I. -I$(SRC) -CFLAGS_AUX = -CFLAGS_LINT = -LINKER = $(CC) -LDFLAGS = -LDOUTF = -o -LIBS = - -# Variables specific to this makefile setup -# SRC and MAKE_CENV are normally overridden. -SRC = ../../src -MAKE_CENV = -CENVFLAGS = -CONFFLAGS = -CONFFLAGS_AUX = - -MAKER = make -f $(SRC)/Makefile.mk $(MAKE_CENV) -BUILDMOD = $(CC) $(CFLAGS) $(CFLAGS_AUX) \ - $(CENVFLAGS) $(CONFFLAGS) $(CONFFLAGS_AUX) - - -## Default if no target given to make. -## -default: - @echo 'Intended to be invoked from a bld// directory, look' - @echo 'at bld/*/Makefile for examples.' - -## Default if no target given to bld/ invocation -## -usage: - @echo 'Use "make ", eg "make base-kl"' - @echo 'Normally the target is one of these 3 base configs:' - @echo ' base-kl KL10 version for TOPS (kn10-kl and utils)' - @echo ' base-ks KS10 version for TOPS (kn10-ks and utils)' - @echo ' base-ks-its KS10 version for ITS (kn10-ks and utils)' - @echo 'Or these utilities:' - @echo ' tapedd Tape copy & conversion' - @echo ' vdkfmt Virtual disk copy & conversion' - @echo ' wxtest Test w10_t internals' - @echo ' enaddr Show and manage ether interfaces' - @echo 'Or these actions:' - @echo ' clean Clean binaries from build directory' - @echo ' install Install binaries in $$KLH10_HOME' - -## Help for makefile debugging -## -showdefs: - @echo "Showing target defs:" - @echo "SRC = $(SRC)" - @echo "MAKER = $(MAKER)" - @echo "CFLAGS = $(CFLAGS)" - @echo "CFLAGS_AUX = $(CFLAGS_AUX)" - @echo "CENVFLAGS = $(CENVFLAGS)" - @echo "CONFFLAGS = $(CONFFLAGS)" - @echo "CONFFLAGS_AUX = $(CONFFLAGS_AUX)" - @echo "BUILDMOD = $(BUILDMOD)" - - -# Generally applicable rules - -# It would be nice to use the .c.o inference rule for all the .o files, -# but the DECOSF "make" chokes when sources are in a different directory, -# never even invoking .c.o at all. Their /usr/bin/posix/make loses too -# because its MAKEARGS macro prevents recursive makes from accepting -# args with spaces in them. -# -# Thus, for max portability every module target must have explicit -# build commands, and due to the same DECOSF lossage cannot use $< -# in those commands. Sigh! - -.SUFFIXES: $(SUFFIXES) .i - -.c.o: - $(BUILDMOD) $< - -.c.s: - $(BUILDMOD) -S $< - -.c.i: - $(BUILDMOD) -E $< > $*.i - -# Don't flush these files if interrupted. -# Currently no intermediate source files are generated, so -# this can be empty, but hang on to last binary anyway. -.PRECIOUS: kn10-ks kn10-kl - - -####################################################################### -## -## Define sources constituting the KLH10. I have not bothered -## to derive a full set of dependencies for each module since -## there are too many possible combinations; safest to always -## recompile everything. -## -## Also, note the KS and KL have two independent module lists in order -## to allow controlling the order in which modules are loaded; this -## can help improve locality. - -# Generic header files - -CONFS = cenv.h klh10.h word10.h wfio.h fecmd.h feload.h \ - kn10mac.h kn10def.h kn10pag.h kn10clk.h kn10dev.h kn10ops.h \ - opcods.h opdefs.h osdsup.h \ - dvcty.h dvuba.h dvrh11.h dvlhdh.h dvdz11.h dvch11.h \ - dvrh20.h dvrpxx.h dvtm03.h dvni20.h dvhost.h \ - vmtape.h vdisk.h - -# Modules needed for KL10 version. - -OFILES_KL = klh10.o prmstr.o fecmd.o feload.o wfio.o osdsup.o \ - kn10cpu.o kn10pag.o kn10clk.o opdata.o kn10ops.o \ - inmove.o inhalf.o inblsh.o intest.o \ - infix.o inflt.o inbyte.o injrst.o \ - inexts.o inio.o kn10dev.o \ - dvcty.o dvdte.o \ - vdisk.o dvrpxx.o dvrh20.o \ - vmtape.o dvtm03.o \ - dvni20.o dpsup.o \ - dvhost.o - -# Modules needed for KS10 version. - -OFILES_KS = klh10.o prmstr.o fecmd.o feload.o wfio.o osdsup.o \ - kn10cpu.o kn10pag.o kn10clk.o opdata.o kn10ops.o \ - inmove.o inhalf.o inblsh.o intest.o \ - infix.o inflt.o inbyte.o injrst.o \ - inexts.o inio.o kn10dev.o dvuba.o \ - dvcty.o \ - vdisk.o dvrpxx.o dvrh11.o \ - vmtape.o dvtm03.o \ - dvlhdh.o dvdz11.o dvch11.o \ - dpsup.o \ - dvhost.o - -# Device Processes (DPs) built concurrently with KN10 - -DPROCS_KL = dprpxx dptm03 dpni20 -DPROCS_KS = dprpxx dptm03 -DPROCS_KSITS = dprpxx dptm03 dpimp - - -# Base utility programs, independent of KN10 -# (there are others not included in the base configs) - -BASE_UTILS = wfconv tapedd vdkfmt wxtest -ALL_UTILS = $(BASE_UTILS) udlconv uexbconv enaddr - - -############################################################ -## KLH10 config - helper definitions -## - -# Subflags for fully synchronous time emulation -# These are good for debugging, or on a slow machine. -TSYNCFLAGS = \ - -DKLH10_RTIME_SYNCH=1 \ - -DKLH10_ITIME_SYNCH=1 \ - -DKLH10_QTIME_SYNCH=1 - -# Subflags for fully OS-interrupt-driven time emulation -# These are best for high performance on a fast machine. -TINTFLAGS = \ - -DKLH10_RTIME_OSGET=1 \ - -DKLH10_ITIME_INTRP=1 \ - -DKLH10_QTIME_OSVIRT=1 - -# Subflags for synchronous polling versions of certain device drivers. -# These are good for debugging. -DSYNCFLAGS = \ - -DKLH10_IMPIO_INT=0 \ - -DKLH10_CTYIO_INT=0 - -# Subflags for interrupt-driven versions of certain device drivers. -# These are best for high performance. -DINTFLAGS = \ - -DKLH10_IMPIO_INT=1 \ - -DKLH10_CTYIO_INT=1 - - -#################################################################### -## -## Basic KN10 configurations -## - -kn10-ks: $(OFILES_KS) - $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-ks $(OFILES_KS) $(LIBS) - -kn10-kl: $(OFILES_KL) - $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-kl $(OFILES_KL) $(LIBS) - - -#################################################################### -## Auxiliary action targets - -clean: - @rm -f kn10-ks kn10-kl *.o \ - $(DPROCS_KL) $(DPROCS_KS) $(DPROCS_KSITS) \ - $(ALL_UTILS) - - -# Install. This should really use a shell script instead. -# -install-unix: - @echo "Copying binaries into ${KLH10_HOME}" - @-rm -rf ${KLH10_HOME}/flushed - @-mkdir ${KLH10_HOME}/flushed - @if [ -x ${KLH10_HOME}/kn10-ks ]; then \ - mv ${KLH10_HOME}/kn10-ks ${KLH10_HOME}/flushed; fi - @if [ -x ${KLH10_HOME}/kn10-kl ]; then \ - mv ${KLH10_HOME}/kn10-kl ${KLH10_HOME}/flushed; fi - @if [ -x ${KLH10_HOME}/dprpxx ]; then \ - mv ${KLH10_HOME}/dprpxx ${KLH10_HOME}/flushed; fi - @if [ -x ${KLH10_HOME}/dptm03 ]; then \ - mv ${KLH10_HOME}/dptm03 ${KLH10_HOME}/flushed; fi - @if [ -x ${KLH10_HOME}/dpni20 ]; then \ - mv ${KLH10_HOME}/dpni20 ${KLH10_HOME}/flushed; fi - @if [ -x ${KLH10_HOME}/dpimp ]; then \ - mv ${KLH10_HOME}/dpimp ${KLH10_HOME}/flushed; fi - @if [ -x kn10-ks ]; then cp -p kn10-ks ${KLH10_HOME}/; fi - @if [ -x kn10-kl ]; then cp -p kn10-kl ${KLH10_HOME}/; fi - @if [ -x dprpxx ]; then cp -p dprpxx ${KLH10_HOME}/; fi - @if [ -x dptm03 ]; then cp -p dptm03 ${KLH10_HOME}/; fi - @if [ -x dpni20 ]; then cp -p dpni20 ${KLH10_HOME}/; fi - @if [ -x dpimp ]; then cp -p dpimp ${KLH10_HOME}/; fi - @if [ -x enaddr ]; then cp -p enaddr ${KLH10_HOME}/; fi - @if [ -x tapedd ]; then cp -p tapedd ${KLH10_HOME}/; fi - @if [ -x udlconv ]; then cp -p udlconv ${KLH10_HOME}/; fi - @if [ -x uexbconv ]; then cp -p uexbconv ${KLH10_HOME}/; fi - @if [ -x vdkfmt ]; then cp -p vdkfmt ${KLH10_HOME}/; fi - @if [ -x wfconv ]; then cp -p wfconv ${KLH10_HOME}/; fi - @if [ -x wxtest ]; then cp -p wxtest ${KLH10_HOME}/; fi - @echo "Done!" - -#################################################################### -## Specific KLH10 configurations -## -## Provided as a convenience, not intended to satisfy all -## possible platforms or configurations. - -# Standard setup for KS ITS -# -base-ks-its: - $(MAKER) kn10-ks $(DPROCS_KSITS) $(BASE_UTILS) udlconv \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = \ - -DKLH10_CPU_KS=1 \ - -DKLH10_SYS_ITS=1 \ - -DKLH10_EVHS_INT=1 \ - -DKLH10_DEV_DPTM03=1 \ - -DKLH10_DEV_DPRPXX=1 \ - -DKLH10_DEV_DPIMP=1 \ - -DKLH10_SIMP=0 \ - -DKLH10_NET_TUN=SYS_FREEBSD \ - -DKLH10_MEM_SHARED=1 \ - $(TINTFLAGS) \ - $(DINTFLAGS) \ - -DKLH10_APRID_SERIALNO=759 -DKLH10_DEVMAX=12 \ - -DKLH10_CLIENT=\\\"MyITS\\\" \ - $(CONFFLAGS_AUX) \ - -DVMTAPE_ITSDUMP=1 " - - -# Standard setup for KS (TOPS-20, maybe TOPS-10) -# -base-ks: - $(MAKER) kn10-ks $(DPROCS_KS) $(BASE_UTILS) \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = \ - -DKLH10_CPU_KS=1 \ - -DKLH10_SYS_T20=1 \ - -DKLH10_EVHS_INT=1 \ - -DKLH10_DEV_DPTM03=1 \ - -DKLH10_DEV_DPRPXX=1 \ - -DKLH10_MEM_SHARED=1 \ - $(TINTFLAGS) \ - $(DINTFLAGS) \ - -DKLH10_APRID_SERIALNO=759 -DKLH10_DEVMAX=12 \ - -DKLH10_CLIENT=\\\"MyKS\\\" \ - $(CONFFLAGS_AUX) " - -# Standard setup for KL (TOPS-10 and TOPS-20) -# -base-kl: - $(MAKER) kn10-kl $(DPROCS_KL) $(BASE_UTILS) uexbconv \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = \ - -DKLH10_CPU_KLX=1 \ - -DKLH10_SYS_T20=1 \ - -DKLH10_EVHS_INT=1 \ - -DKLH10_DEV_DPNI20=1 \ - -DKLH10_DEV_DPTM03=1 \ - -DKLH10_DEV_DPRPXX=1 \ - -DKLH10_MEM_SHARED=1 \ - -DKLH10_RTIME_OSGET=1 \ - -DKLH10_ITIME_INTRP=1 \ - -DKLH10_CTYIO_INT=1 \ - -DKLH10_APRID_SERIALNO=1 \ - -DKLH10_CLIENT=\\\"MyKL\\\" \ - $(CONFFLAGS_AUX) " - -#################################################################### -## Lintish versions to see how many compiler warnings we can generate -## -lint-ks-its: - $(MAKER) kn10-ks $(DPROCS_KSITS) $(BASE_UTILS) udlconv \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX) $(CFLAGS_LINT)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = $(CONFFLAGS) $(CONFFLAGS_AUX)" - -lint-ks: - $(MAKER) kn10-ks $(DPROCS_KS) $(BASE_UTILS) \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX) $(CFLAGS_LINT)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = $(CONFFLAGS) $(CONFFLAGS_AUX)" - -lint-kl: - $(MAKER) kn10-kl $(DPROCS_KL) $(BASE_UTILS) uexbconv \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX) $(CFLAGS_LINT)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = $(CONFFLAGS) $(CONFFLAGS_AUX)" - - -#################################################################### -## KLH10 versions for diagnostics and debugging. -## - -# "Port"-friendly KS, for helping port to a new platform. -# Simplest possible configuration: -# No shared memory -# No device subprocs -# No realtime interrupts or clock - synchronous emulation -port-ks: - $(MAKER) kn10-ks $(BASE_UTILS) \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = \ - -DKLH10_CPU_KS=1 \ - -DKLH10_SYS_T20=1 \ - -DKLH10_RTIME_SYNCH=1 \ - -DKLH10_APRID_SERIALNO=759 -DKLH10_DEVMAX=12 \ - -DKLH10_CLIENT=\\\"MyKS\\\" \ - $(CONFFLAGS_AUX) " - - -# Build KL0 with KI paging, for running diagnostics. -# Two versions, one synch and one realtime. -# Note: The diags tend to fail miserably when faced with a KLX using KI -# paging, so don't try that. - -# KL0 with KI paging - synchronous, good for debugging with diagnostics. -# NOTE: CFLAGS for this one should be set up for NO optimization!!! -kl0i-sync: - $(MAKER) kn10-kl $(DPROCS_KL) \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = \ - -DKLH10_CPU_KL0=1 \ - -DKLH10_SYS_T10=1 \ - -DKLH10_PAG_KI=1 \ - -DKLH10_EVHS_INT=1 \ - -DKLH10_DEV_DPNI20=1 \ - -DKLH10_DEV_DPTM03=1 \ - -DKLH10_DEV_DPRPXX=1 \ - -DKLH10_RTIME_SYNCH=1 \ - -DKLH10_ITIME_SYNCH=1 \ - -DKLH10_CTYIO_INT=0 \ - $(CONFFLAGS_AUX) " - -# KL0 with KI paging - Realtime & optimized, good for timing diagnostics. -# -kl0i-rtmopt: - $(MAKER) kn10-kl $(DPROCS_KL) \ - "SRC = $(SRC)" \ - "CC = $(CC)" \ - "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ - "LDFLAGS = $(LDFLAGS)" \ - "LIBS = $(LIBS)" \ - "CENVFLAGS = $(CENVFLAGS)" \ - "CONFFLAGS = \ - -DKLH10_CPU_KL0=1 \ - -DKLH10_SYS_T10=1 \ - -DKLH10_PAG_KI=1 \ - -DKLH10_EVHS_INT=1 \ - -DKLH10_DEV_DPNI20=1 \ - -DKLH10_DEV_DPTM03=1 \ - -DKLH10_DEV_DPRPXX=1 \ - -DKLH10_RTIME_OSGET=1 \ - -DKLH10_ITIME_INTRP=1 \ - -DKLH10_CTYIO_INT=0 \ - $(CONFFLAGS_AUX) " - - -#################################################################### -## Device Process (DP) programs -## -## These cannot be made individually - they are expected to be -## built as byproducts of building the KLH10, in order to share -## a common set of config parameters. -## - -# --------- RPXX disk drive subprocess -# -dprpxx.o: $(SRC)/dprpxx.c $(SRC)/dprpxx.h $(SRC)/dpsup.h $(SRC)/vdisk.c - $(BUILDMOD) $(SRC)/dprpxx.c - -dprpxx: dprpxx.o dpsup.o - $(LINKER) $(LDFLAGS) $(LDOUTF) dprpxx dprpxx.o dpsup.o $(LIBS) - - -# --------- TM03 tape drive subprocess -# -dptm03.o: $(SRC)/dptm03.c $(SRC)/dptm03.h $(SRC)/dpsup.h $(SRC)/vmtape.c - $(BUILDMOD) $(SRC)/dptm03.c - -OFILES_DPTM03=dptm03.o dpsup.o wfio.o prmstr.o - -dptm03: $(OFILES_DPTM03) - $(LINKER) $(LDFLAGS) $(LDOUTF) dptm03 $(OFILES_DPTM03) $(LIBS) - - -# --------- NI20 Network Interface subprocess (KL only) -# -dpni20.o: $(SRC)/dpni20.c $(SRC)/dpni20.h $(SRC)/dpsup.h - $(BUILDMOD) $(SRC)/dpni20.c - -dpni20: dpni20.o dpsup.o - $(LINKER) $(LDFLAGS) $(LDOUTF) dpni20 dpni20.o dpsup.o $(LIBS) - - -# --------- IMP subprocess (ITS KS only; counterpart for dvlhdh) -# -dpimp.o: $(SRC)/dpimp.c $(SRC)/dpimp.h $(SRC)/dpsup.h - $(BUILDMOD) $(SRC)/dpimp.c - -dpimp: dpimp.o dpsup.o - $(LINKER) $(LDFLAGS) $(LDOUTF) dpimp dpimp.o dpsup.o $(LIBS) - - -#################################################################### -## UTILITIES -## -## These can be built independently, and normally do not require -## any CONFFLAGS. -## - -## TAPEDD - Tape device-to-device copy -## Needs CONFFLAGS just for optional VMTAPE_ITSDUMP. -## -tapedd.o: $(SRC)/tapedd.c $(SRC)/vmtape.c $(SRC)/vmtape.h - $(CC) $(CFLAGS) $(CENVFLAGS) $(CONFFLAGS) $(SRC)/tapedd.c - -tapedd: tapedd.o wfio.o prmstr.o - $(LINKER) $(LDFLAGS) $(LDOUTF) tapedd tapedd.o wfio.o prmstr.o $(LIBS) - - -## VDKFMT - Virtual Disk Format & copy -## -vdkfmt.o: $(SRC)/vdkfmt.c $(SRC)/vdisk.c $(SRC)/vdisk.h - $(CC) $(CFLAGS) $(CENVFLAGS) $(SRC)/vdkfmt.c - -vdkfmt: vdkfmt.o - $(LINKER) $(LDFLAGS) $(LDOUTF) vdkfmt vdkfmt.o $(LIBS) - - -## WXTEST - word10.h tester -## -wxtest.o: $(SRC)/wxtest.c $(SRC)/word10.h - $(CC) $(CFLAGS) $(CENVFLAGS) $(SRC)/wxtest.c - -wxtest: wxtest.o - $(LINKER) $(LDFLAGS) $(LDOUTF) wxtest wxtest.o $(LIBS) - - -## WFCONV - Word-File Conversion -## -wfconv.o: $(SRC)/wfconv.c $(SRC)/wfio.c $(SRC)/wfio.h $(SRC)/word10.h - $(CC) $(CFLAGS) $(CENVFLAGS) $(SRC)/wfconv.c - -wfconv: wfconv.o - $(LINKER) $(LDFLAGS) $(LDOUTF) wfconv wfconv.o $(LIBS) - - -## UDLCONV - DIR.LIST Conversion (of ITS interest only) -## -udlconv.o: $(SRC)/udlconv.c - $(CC) $(CFLAGS) $(CENVFLAGS) $(SRC)/udlconv.c - -udlconv: udlconv.o - $(LINKER) $(LDFLAGS) $(LDOUTF) udlconv udlconv.o $(LIBS) - - -## UEXBCONV - Convert .EXB file into .SAV (of KL interest only) -## -uexbconv.o: $(SRC)/uexbconv.c $(SRC)/wfio.c $(SRC)/wfio.h $(SRC)/word10.h - $(CC) $(CFLAGS) $(CENVFLAGS) $(SRC)/uexbconv.c - -uexbconv: uexbconv.o - $(LINKER) $(LDFLAGS) $(LDOUTF) uexbconv uexbconv.o $(LIBS) - - -## ENADDR - Ethernet interface test & manipulation -## May require CONFFLAGS to force a particular osdnet config. -enaddr.o: $(SRC)/enaddr.c $(SRC)/osdnet.h $(SRC)/osdnet.c - $(CC) $(CFLAGS) $(CENVFLAGS) $(CONFFLAGS) $(SRC)/enaddr.c - -enaddr: enaddr.o - $(LINKER) $(LDFLAGS) $(LDOUTF) enaddr enaddr.o $(LIBS) - - -#################################################################### -## KN10 modules. In order to build into a directory other than the -## one the sources are located, must specify the location of -## each and every source file. Ugh. Some but not all dependencies -## are included here. -## -## Sorted alphabetically. -## - -dpsup.o: $(SRC)/dpsup.c $(SRC)/dpsup.h - $(BUILDMOD) $(SRC)/dpsup.c - -dvch11.o: $(SRC)/dvch11.c $(SRC)/dvch11.h - $(BUILDMOD) $(SRC)/dvch11.c - -dvcty.o: $(SRC)/dvcty.c $(SRC)/dvcty.h - $(BUILDMOD) $(SRC)/dvcty.c - -dvdte.o: $(SRC)/dvdte.c $(SRC)/dvdte.h - $(BUILDMOD) $(SRC)/dvdte.c - -dvdz11.o: $(SRC)/dvdz11.c $(SRC)/dvdz11.h - $(BUILDMOD) $(SRC)/dvdz11.c - -dvhost.o: $(SRC)/dvhost.c $(SRC)/dvhost.h - $(BUILDMOD) $(SRC)/dvhost.c - -dvlhdh.o: $(SRC)/dvlhdh.c $(SRC)/dvlhdh.h - $(BUILDMOD) $(SRC)/dvlhdh.c - -dvni20.o: $(SRC)/dvni20.c $(SRC)/dvni20.h - $(BUILDMOD) $(SRC)/dvni20.c - -dvrh11.o: $(SRC)/dvrh11.c $(SRC)/dvrh11.h - $(BUILDMOD) $(SRC)/dvrh11.c - -dvrh20.o: $(SRC)/dvrh20.c $(SRC)/dvrh20.h - $(BUILDMOD) $(SRC)/dvrh20.c - -dvrpxx.o: $(SRC)/dvrpxx.c $(SRC)/dvrpxx.h - $(BUILDMOD) $(SRC)/dvrpxx.c - -dvtm03.o: $(SRC)/dvtm03.c $(SRC)/dvtm03.h - $(BUILDMOD) $(SRC)/dvtm03.c - -dvuba.o: $(SRC)/dvuba.c $(SRC)/dvuba.h - $(BUILDMOD) $(SRC)/dvuba.c - -fecmd.o: $(SRC)/fecmd.c $(SRC)/fecmd.h - $(BUILDMOD) $(SRC)/fecmd.c - -feload.o: $(SRC)/feload.c $(SRC)/feload.h - $(BUILDMOD) $(SRC)/feload.c - -inblsh.o: $(SRC)/inblsh.c - $(BUILDMOD) $(SRC)/inblsh.c - -inbyte.o: $(SRC)/inbyte.c - $(BUILDMOD) $(SRC)/inbyte.c - -inexts.o: $(SRC)/inexts.c - $(BUILDMOD) $(SRC)/inexts.c - -infix.o: $(SRC)/infix.c - $(BUILDMOD) $(SRC)/infix.c - -inflt.o: $(SRC)/inflt.c - $(BUILDMOD) $(SRC)/inflt.c - -inhalf.o: $(SRC)/inhalf.c - $(BUILDMOD) $(SRC)/inhalf.c - -inio.o: $(SRC)/inio.c - $(BUILDMOD) $(SRC)/inio.c - -injrst.o: $(SRC)/injrst.c - $(BUILDMOD) $(SRC)/injrst.c - -inmove.o: $(SRC)/inmove.c - $(BUILDMOD) $(SRC)/inmove.c - -intest.o: $(SRC)/intest.c - $(BUILDMOD) $(SRC)/intest.c - -kn10clk.o: $(SRC)/kn10clk.c $(SRC)/kn10clk.h - $(BUILDMOD) $(SRC)/kn10clk.c - -kn10cpu.o: $(SRC)/kn10cpu.c $(SRC)/klh10.h $(SRC)/klh10s.h $(SRC)/klh10.c - $(BUILDMOD) $(SRC)/kn10cpu.c - -kn10dev.o: $(SRC)/kn10dev.c $(SRC)/kn10dev.h - $(BUILDMOD) $(SRC)/kn10dev.c - -kn10ops.o: $(SRC)/kn10ops.c $(SRC)/kn10ops.h - $(BUILDMOD) $(SRC)/kn10ops.c - -kn10pag.o: $(SRC)/kn10pag.c $(SRC)/kn10pag.h - $(BUILDMOD) $(SRC)/kn10pag.c - -klh10.o: $(SRC)/klh10.c $(SRC)/klh10.h $(SRC)/klh10s.h - $(BUILDMOD) $(SRC)/klh10.c - -opdata.o: $(SRC)/opdata.c $(SRC)/kn10def.h $(SRC)/opcods.h - $(BUILDMOD) $(SRC)/opdata.c - -osdsup.o: $(SRC)/osdsup.c $(SRC)/osdsup.h - $(BUILDMOD) $(SRC)/osdsup.c - -prmstr.o: $(SRC)/prmstr.c $(SRC)/prmstr.h - $(BUILDMOD) $(SRC)/prmstr.c - -vdisk.o: $(SRC)/vdisk.c $(SRC)/vdisk.h - $(BUILDMOD) $(SRC)/vdisk.c - -vmtape.o: $(SRC)/vmtape.c $(SRC)/vmtape.h - $(BUILDMOD) $(SRC)/vmtape.c - -wfio.o: $(SRC)/wfio.c $(SRC)/wfio.h - $(BUILDMOD) $(SRC)/wfio.c - - -#################################################################### -## OLD STUFF -## Misc crocks kept around just in case. -## - -optest: optest.o - $(LINKER) $(LDFLAGS) -o optest optest.o $(LIBS) - - -# This is only for munching Alan's ITS DUMP tape info format -dlmunch: dlmunch.o lread.o - $(LINKER) -o dlmunch dlmunch.o lread.o - -#################################################################### diff --git a/src/Mk-lnx86.mk.old b/src/Mk-lnx86.mk.old deleted file mode 100644 index c3d5596..0000000 --- a/src/Mk-lnx86.mk.old +++ /dev/null @@ -1,45 +0,0 @@ -# KLH10 Makefile for Linux on i386 -# $Id: Mk-lnx86.mk,v 2.5 2002/04/24 18:03:04 klh Exp $ -# -# Copyright © 2001 Kenneth L. Harrenstien -# All Rights Reserved -# -# This file is part of the KLH10 Distribution. Use, modification, and -# re-distribution is permitted subject to the terms in the file -# named "LICENSE", which contains the full text of the legal notices -# and should always accompany this Distribution. -# -# This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -# -# This notice (including the copyright and warranty disclaimer) -# must be included in all copies or derivations of this software. -# -##################################################################### - -# Local config setup, for GNU "make"! -# Recursively invokes make with right params for local platform. - -# Build definitions -SRC = ../../src -CFLAGS = -c -g3 -O3 -I. -I$(SRC) -CFLAGS_LINT = -ansi -pedantic -Wall -Wshadow \ - -Wstrict-prototypes -Wmissing-prototypes \ - -Wmissing-declarations -Wredundant-decls - -# Source definitions -CENVFLAGS = -DCENV_CPU_I386=1 -DCENV_SYS_LINUX=1 \ - -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE - -# Any target with no customized rule here is simply passed on to the -# standard Makefile. If no target is specified, "usage" is passed on -# to generate a helpful printout. - -usage .DEFAULT: - @make -f $(SRC)/Makefile.mk $@ \ - "SRC=$(SRC)" \ - "CFLAGS=$(CFLAGS)" \ - "CFLAGS_LINT=$(CFLAGS_LINT)" \ - "CENVFLAGS=$(CENVFLAGS)" - -install: - make -f $(SRC)/Makefile.mk install-unix diff --git a/src/dvhost.c.old b/src/dvhost.c.old deleted file mode 100644 index 41c79a2..0000000 --- a/src/dvhost.c.old +++ /dev/null @@ -1,334 +0,0 @@ -/* DVHOST.C - Fake "Host" device to provide access to native host platform -*/ -/* $Id: dvhost.c,v 2.3 2001/11/10 21:28:59 klh Exp $ -*/ -/* Copyright © 1994, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: dvhost.c,v $ - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -/* -*/ -#include "klh10.h" - -#if !KLH10_DEV_HOST && CENV_SYS_DECOSF - /* Stupid gubbish needed to prevent OSF/1 AXP compiler from - ** halting merely because compiled file is empty! - */ -static int decosfcclossage; -#endif - -#if KLH10_DEV_HOST /* Moby conditional for entire file */ - -#include /* For size_t etc */ -#include -#include -#include - -#include "kn10def.h" /* This includes OSD defs */ -#include "kn10dev.h" -#include "kn10ops.h" -#include "dvhost.h" -#include "kn10clk.h" /* Need access to clock stuff */ -#include "prmstr.h" /* For parameter parsing */ - -#ifdef RCSID - RCSID(dvhost_c,"$Id: dvhost.c,v 2.3 2001/11/10 21:28:59 klh Exp $") -#endif - -struct host { - struct device hst_dv; /* Generic 10 device structure */ -}; -static int nhosts = 0; - -#define DVHOST_NSUP 1 /* Should never be anything else! */ - -struct host dvhost[DVHOST_NSUP]; - - -/* Function predecls */ - -static int hst_conf(FILE *f, char *s, struct host *hst); - -#if KLH10_CPU_KS -static void hst_write(struct device *, /* Unibus register write */ - uint18, dvureg_t); -#else -static void hst_cono(struct device *, h10_t); /* CONO 18-bit conds out */ -# if 0 -static w10_t hst_coni(); /* CONI 36-bit conds in */ -static void hst_datao(); /* DATAO word out */ -static w10_t hst_datai(); /* DATAI word in */ -# endif -#endif /* !KLH10_CPU_KS */ - - -/* Configuration Parameters */ - -#if KLH10_CPU_KS -# define DVHOST_PARAMS \ - prmdef(HSTP_DBG, "debug"), /* Initial debug value */\ - prmdef(HSTP_BR, "br"), /* BR priority */\ - prmdef(HSTP_VEC, "vec"), /* Interrupt vector */\ - prmdef(HSTP_ADDR,"addr") /* Unibus address */ -#else -# define DVHOST_PARAMS \ - prmdef(HSTP_DBG, "debug") /* Initial debug value */ -#endif /* KLH10_CPU_KS */ - -enum { -# define prmdef(i,s) i - DVHOST_PARAMS -# undef prmdef -}; - -static char *hstprmtab[] = { -# define prmdef(i,s) s - DVHOST_PARAMS -# undef prmdef - , NULL -}; - -/* HST_CONF - Parse configuration string and set defaults. -** At this point, device has just been created, but not yet bound -** or initialized. -** NOTE that some strings are dynamically allocated! Someday may want -** to clean them up nicely if config fails or device is uncreated. -*/ -static int hst_conf(FILE *f, char *s, struct host *hst) -{ - int i, ret = TRUE; - struct prmstate_s prm; - char buff[200]; -#if KLH10_CPU_KS - long lval; -#endif - - /* First set defaults for all configurable parameters - Unfortunately there's currently no way to access the UBA # that - we're gonna be bound to, otherwise could set up defaults. Later - fix this by giving dvhost_create() a ptr to an arg structure, etc. - */ - DVDEBUG(hst) = FALSE; - - prm_init(&prm, buff, sizeof(buff), - s, strlen(s), - hstprmtab, sizeof(hstprmtab[0])); - while ((i = prm_next(&prm)) != PRMK_DONE) { - switch (i) { - case PRMK_NONE: - fprintf(f, "Unknown HOST parameter \"%s\"\n", prm.prm_name); - ret = FALSE; - continue; - case PRMK_AMBI: - fprintf(f, "Ambiguous HOST parameter \"%s\"\n", prm.prm_name); - ret = FALSE; - continue; - default: /* Handle matches not supported */ - fprintf(f, "Unsupported HOST parameter \"%s\"\n", prm.prm_name); - ret = FALSE; - continue; - - case HSTP_DBG: /* Parse as true/false boolean or number */ - if (!prm.prm_val) /* No arg => default to 1 */ - DVDEBUG(hst) = 1; - else if (!s_tobool(prm.prm_val, &DVDEBUG(hst))) - break; - continue; - -#if KLH10_CPU_KS - case HSTP_BR: /* Parse as octal number */ - if (!prm.prm_val || !s_tonum(prm.prm_val, &lval)) - break; - if (lval < 4 || lval > 7) { - fprintf(f, "HOST BR must be one of 4,5,6,7\n"); - ret = FALSE; - } else - hst->hst_dv.dv_brlev = lval; - continue; - - case HSTP_VEC: /* Parse as octal number */ - if (!prm.prm_val || !s_tonum(prm.prm_val, &lval)) - break; - if (lval < 4 || lval > 0400 || (lval&03)) { - fprintf(f, "HOST VEC must be valid multiple of 4\n"); - ret = FALSE; - } else - hst->hst_dv.dv_brvec = lval; - continue; - - case HSTP_ADDR: /* Parse as octal number */ - if (!prm.prm_val || !s_tonum(prm.prm_val, &lval)) - break; -#if 0 - if (lval < (DVHOST_REG_N<<1) || (lval&037)) { - fprintf(f, "HOST ADDR must be valid Unibus address\n"); - ret = FALSE; - } else -#endif - hst->hst_dv.dv_addr = lval; - continue; -#endif /* KLH10_CPU_KS */ - } - ret = FALSE; - fprintf(f, "HOST param \"%s\": ", prm.prm_name); - if (prm.prm_val) - fprintf(f, "bad value syntax: \"%s\"\n", prm.prm_val); - else - fprintf(f, "missing value\n"); - } - - /* Param string all done, do followup checks or cleanup */ -#if KLH10_CPU_KS -# if 0 - if (!hst->hst_dv.dv_brlev || !hst->hst_dv.dv_brvec || !hst->hst_dv.dv_addr) { - fprintf(f, "HOST missing one of BR, VEC, ADDR params\n"); -# else - if (!hst->hst_dv.dv_addr) { - fprintf(f, "HOST missing ADDR param\n"); -# endif - ret = FALSE; - } - /* Set 1st invalid addr */ - hst->hst_dv.dv_aend = hst->hst_dv.dv_addr + (DVHOST_REG_N * 2); -#endif /* KLH10_CPU_KS */ - - return ret; -} - -/* HOST interface routines to KLH10 */ - -struct device * dvhost_create(FILE *f, char *s) -{ - register struct host *hst; - - /* Parse string to determine which device to use, config, etc etc - ** But for now, just allocate sequentially. Hack. - */ - if (nhosts >= DVHOST_NSUP) { - fprintf(f, "Too many HOSTs, max: %d\n", DVHOST_NSUP); - return NULL; - } - hst = &dvhost[nhosts++]; /* Pick unused dev */ - memset((char *)hst, 0, sizeof(*hst)); /* Clear it out */ - - /* Initialize generic device part of HOST struct */ - iodv_setnull(&hst->hst_dv); /* Initialize as null device */ - -#if KLH10_CPU_KS - /* Operate as new-style Unibus device */ - hst->hst_dv.dv_write = hst_write; /* Write unibus register */ -#else - /* Operate as old-style IO-bus device */ - hst->hst_dv.dv_cono = hst_cono; /* Do CONO only */ -#endif - - /* Configure from parsed string and remember for init - */ - if (!hst_conf(f, s, hst)) - return NULL; - - return &hst->hst_dv; -} - - -#if !KLH10_CPU_KS - -/* CONO 18-bit conds out -** Args D, ERH -** Returns nothing -*/ -static insdef_cono(hst_cono) -{ - register struct host *hst = (struct host *)d; - register uint18 cond = erh; - - if (DVDEBUG(hst)) - fprintf(DVDBF(hst), "[hst_cono: %lo]\r\n", (long)erh); - - if (cond == DVHOST_CO_IDLE) - clk_idle(); /* Invoke CLK_IDLE! */ -} - -#if 0 /* Nothing else needed for now */ - -/* CONI 36-bit conds in -** Args D -** Returns condition word -*/ -static insdef_coni(hst_coni) -{ - register w10_t w; - register struct host *hst = (struct host *)d; - - if (DVDEBUG(hst)) - fprintf(DVDBF(hst), "[hst_coni: %lo,,%lo]\r\n", - (long)hst->hst_lhcond, (long)hst->hst_cond); - return w; -} - -/* DATAO word out -** Args D, W -** Returns nothing -*/ -static insdef_datao(hst_datao) -{ - register struct host *hst = (struct host *)d; - - if (DVDEBUG(hst)) - fprintf(DVDBF(hst), "[hst_datao: %lo,,%lo]\r\n", - (long)LHGET(w), (long)RHGET(w)); - -} - -/* DATAI word in -** Args D -** Returns data word -*/ -static insdef_datai(hst_datai) -{ - register struct host *hst = (struct host *)d; - register w10_t w; - - - if (DVDEBUG(hst)) - fprintf(DVDBF(hst), "[hst_datai: %lo,,%lo]\r\n", - (long)LHGET(w), (long)RHGET(w)); - return w; -} - -#endif /* 0 */ /* Nothing else needed for now */ -#endif /* !KLH10_CPU_KS */ - -#if KLH10_CPU_KS - -/* Unibus interface routines */ - -static void hst_write(struct device *d, uint18 addr, register dvureg_t val) -{ - register struct host *hst = (struct host *)d; - - if (DVDEBUG(hst)) - fprintf(DVDBF(hst), "[hst_write: %lo]\r\n", (long)val); - - if (val == DVHOST_CO_IDLE) - clk_idle(); /* Invoke CLK_IDLE! */ -} -#endif /* KLH10_CPU_KS */ - -#endif /* KLH10_DEV_HOST */ diff --git a/src/dvhost.h.old b/src/dvhost.h.old deleted file mode 100644 index 19274f9..0000000 --- a/src/dvhost.h.old +++ /dev/null @@ -1,46 +0,0 @@ -/* DVHOST.H - HOST native platform access defniitions -*/ -/* $Id: dvhost.h,v 2.3 2001/11/10 21:28:59 klh Exp $ -*/ -/* Copyright © 1994, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: dvhost.h,v $ - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#ifndef DVHOST_INCLUDED -#define DVHOST_INCLUDED 1 - -#ifdef RCSID - RCSID(dvhost_h,"$Id: dvhost.h,v 2.3 2001/11/10 21:28:59 klh Exp $") -#endif - -/* Only externally visible entry point for HOST driver - */ -#include "kn10dev.h" -extern struct device * dvhost_create(FILE *f, char *s); - -#define DVHOST_NSUP 1 /* Should be only 1! */ - -/* CONO bits -** Preliminary hackery... -*/ -#define DVHOST_CO_IDLE 01 /* "Op-code" to do idle hackery */ - -#define DVHOST_REG_N 1 /* If on a Unibus, only one register */ - -#endif /* ifndef DVHOST_INCLUDED */ diff --git a/src/inexts.c.old b/src/inexts.c.old deleted file mode 100644 index 3740244..0000000 --- a/src/inexts.c.old +++ /dev/null @@ -1,2585 +0,0 @@ -/* INEXTS.C - Extended (String) Instruction routines -*/ -/* $Id: inexts.c,v 2.4 2002/05/21 10:06:55 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: inexts.c,v $ - * Revision 2.4 2002/05/21 10:06:55 klh - * Fixed XBLT to behave like real KL with respect to high 6 bits - * of src/dst addresses. New algorithm also fixes a pagefail bug. - * - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -/* See CODING.TXT for guidelines to coding instruction routines. */ - -#include -#include "klh10.h" -#include "kn10def.h" /* Machine defs */ -#include "kn10ops.h" /* PDP-10 ops */ - -#ifdef RCSID - RCSID(inexts_c,"$Id: inexts.c,v 2.4 2002/05/21 10:06:55 klh Exp $") -#endif - -/* Exported functions (other than instrs) */ - -void inexts_init(void); /* Initialize any necessary EXTEND stuff */ - -/* Local predeclarations */ - -#if KLH10_EXTADR -static int xea_fiwcalc(w10_t iw, unsigned int sect, - acptr_t acp, pment_t *map, vaddr_t *va, int f); -#endif - -/* Notes: -** -** + The EXTEND string instructions are documented to be undefined when -** used with PXCT (except for MOVSLJ), but appropriate mapping is -** done anyway since it costs nothing and lets MOVSLJ work. This may -** change with extended addressing. -** + The G-Format extended instructions are handled in inflt.c. -*/ - -/* NOTES: - The EXTEND instructions, as described by the PRM, contain a lot -of ambiguities as to exactly how they behave in response to unusual -conditions, especially with respect to the resulting AC contents. Here -is a list of unclear points, with the assumptions made by KLH10 code. - -* Are the AC bits at c(E0) checked? PRM only says (p.1-25) "must be zero". - [ANSWER: KS: AC bits MUST == 0 or it traps as a MUUO. - KL: AC bits ignored. - ] -* Is E1 always computed whether or not it is used? - [Assume YES, based on PRM 1-25 top paragraph: - "As with all instructons, before executing the second word the - processor calculates an effective address for it; this is referred - to as E1, ..." - ANSWER: YES, if: - KS: opcode is 0-17 incl and AC=0 (else MUUO taken before E1 calc) - KL: opcode is 0-31 incl (else MUUO taken) - and not 20 (else E1 skipped) - ] -* Are fill bytes from c(E0+1), c(E0+2) always pre-fetched (liable to page - fault before anything done), or only referenced when and if needed? - [ANSWER: - KS/KL: pre-fetched for all MOVSx instructions. - KS/KL: pre-fetched for all CMPSx, but KS/KL differ if lengths equal - (see comments at ix_cmps). - KS/KL: CVTBDx only fetches fill if needed. - KS: pre-fetched for EDIT (but float char only fetched as needed). - KL: both fill and float only fetched as needed. - ] -* What happens if the zero-specified high bits in string counts are - non-zero? - [ANSWER: traps as MUUO] - -* Are the high 9 bits of string lengths used as flags for intermediate states, - such as if a page fault interrupts between IBP and LDB? - [ANSWER: No -- kept clear.] - -* Are OWG byte pointers left alone if a page fault happens on the first ref, - or have they already been converted (so that initial P is lost)? - [ANSWER: already converted] - -* Are byte pointers converted so that I and X are zero? If not, are the - X and I references made with every use of the BP? What happens if - I is set? - [ANSWER: NO! Apparently EA is recomputed on each BP ref. - I and X are retained just as for normal ILDB/IDPB. - Implementation here simulates this without actually doing the - recomputation unless indirection makes it necessary. - Of course, all that work is probably pointless because - any user program that sets I won't work in general, - because a new word is indirected through as soon as Y - is incremented!] - -* What happens if a 2-word BP has its 2nd word in IFIW format instead - of EFIW -- is it converted to EFIW or left as IFIW? If IFIW, are resulting - pointer EAs re-computed with every reference to check for insection overflow? - Argh! - [ANSWER: no conversion is done; EFIW/IFIW distinction is maintained - and addresses are incremented appropriately for the format, i.e. - IFIW insection overflow just wraps. - Furthermore, having both bit 0,1 set in 2nd word causes an illegal - indirection page fault.] - -* NOTE! From empirical testing, an II page fault prior to any string use of BP - results in BP having been incremented, but P is backed up so that - a re-invocation will still refer to the same byte. - e.g. initial BP: 004440,,0 ? 600001,,70 - result BP: 444440,,0 ? 600001,,71 - -* Since OWGBPs are allowed in section 0 by the byte instructions, do the - EXTEND string instructions convert them? But if instr is restarted, TWGBPs - will fail because they can't be used in section 0! What's the plan?? - [ANSWER: OWGBPs not allowed in sect 0 by EXTEND instrs; they're - interpreted as OWLBPs.] - -* When a OWGBP is converted to a TWGBP, is the 2nd word an EFIW or IFIW? - [ANSWER: EFIW with I+X= 0] - -* What happens if BPs are not aligned? (see also MOVSRJ question) - [ANSWER: behave just as if using ILDB/IDPBs -- they stay unaligned - until a word boundary is crossed, whereupon they are aligned. - This applies to a MOVSRJ skip as well.] - -* Do translation tables cross section boundaries? - [Assume E1+offset follows same rules as normal E+offset, i.e. - depends on whether E1 is local or global. - WRONG! On real KL, always crosses section boundaries, EVEN IF - RUNNING IN ZERO SECTION, regardless of locality of E1.] - -* Is there any limit on the size of a translation table? - [ANSWER: No -- simply adds byte/2 to E1. Can jump entire - sections!] - -* Does extended address computation for E1 depend on location of word at E0, - or on PC? What about computation of addresses for translation table entries? - [Assume depends on location of word addressed by E0. - Also assume E1+offset follows same rules as normal E+offset.] - --------------------- -* MOVSO: does the offset apply to the fill byte? Is the fill byte tested? - [ANSWER: No to both.] -* MOVSO: is the oversize byte test applied with source or dest byte size? - [ANSWER: Dest byte size] -* MOVSO: what is state of ACs if instr stops due to oversize byte? Is source - BP & count pointing to guilty byte or backed up? - [Assume backed up, so a re-try will fail identically] - --------------------- -* MOVST: If a translation function terminates, is the rest of the dest string - filled or not? - [ANSWER: No - not filled.] - --------------------- -* MOVSRJ: Does this really always skip, even if some source bytes are left? - [ANSWER: Yes - by definition no source bytes are ever left!] -* MOVSRJ: If source bytes are skipped, are any memory refs made (ie possible - to page-fail) or is the source pointer merely bumped? - [ANSWER: No mem refs - src pointer is simply bumped. !!! BUT !!! - On the KL, the src skip is always made as if the 1st wd was a - OWLBP, regardless of actual format, thus this skip loses if BP - is really a OWG, TWG, or TWL!!! Ucode bug!] -* MOVSRJ: If source bytes skipped, is the BP bumped as if ILDB were done, or - as if ADJBP (which preserves possible non-alignment)? - [ANSWER: Bumped as if IBP, thus non-alignment is only preserved until - the first word increment.] - --------------------- -* CMPSx: Are the bytes signed for comparison purposes? - [Assuming unsigned] -* CMPSx: What about full-word 36-bit bytes? (CAM uses signed compare) - [Assuming unsigned for consistency] -* CMPSx: What happens to the length and pointer of a string that counts out - and has its fill byte used? - [Assuming length remains 0 and pointer is left pointing to last byte] -* CMPSx: Are the high bits of the fill-byte words used, or are they masked - out before the comparison? - [NO! Formerly assumed masked out, but empirical testing shows this - is not the case. Fill word is used as a whole.] - --------------------- -* CVTBDx: Must the N & M bits be clear initially? Is their value ignored? - [Assuming value ignored, since may be restarting] -* CVTBDx: Are the N and M bits always set to either 0 or 1, or are new - settings just IOR'd in? - [Assuming IOR'd, since may be restarting instruction] -* CVTBDx: Is the low-order sign bit ignored in the setting of N? - [Assuming yes] -* CVTBDx: What happens for max negative integer (which cannot be readily - negated into positive form)? - [Assuming code does right thing & generates correct value] -* CVTBDx: Does a page-fault or interrupt really update all ACs by - storing back new binary # and new pointer/length, or does it - always either run to completion or restore original ACs? - [Assuming former, updates all ACs with partial results] -* CVTBDx: Does CVTBDO check result byte for being oversize, like MOVSO? - [Assuming not] - --------------------- -* CVTBDT: What happens if translated digit has a 4-bit value greater - than 9? Is check made after translation or are the bits just masked? - [Assume bits just masked, don't test for 9 < x <= 017] -* CVTBDT: What are source len and BP values if string is terminated, or - aborted because of a bad digit? - [Assume points to terminating or bad byte, with len indicating - remainder of string] - --------------------- -* CVTDBT: What happens if last source byte forces termination? Does it - skip because instruction ate all bytes, or not skip because a - termination happened? - [Assume no skip] - --------------------- -* EDIT: What happens if an illegal command byte is seen? - [Assume updates ACs, so a re-xct will immediately fail - on that byte as well, and then MUUO-fails] - [WRONG! Diagnostic simulation simply treats unrecognized - pattern bytes as NOPs. Ucode agrees. Sigh.] -*/ - - -/* See opdefs.h for the definition of xinsdef(), -** which is used to define all extended instruction routines. -*/ - -insdef(i_extend) -{ - register w10_t xw; - register unsigned int xop; - - xw = vm_read(e); /* Get contents of E0 using normal XRW map */ - xop = iw_op(xw); /* Find extended opcode */ - - /* Check extended opcode (and perhaps AC) before doing indexed dispatch. - Note that KL doesn't check AC field, whereas KS requires that - it be zero! - */ -#if KLH10_CPU_KLX - if (xop >= IX_N) - return i_muuo(op, ac, e); /* Bad op */ - -#elif KLH10_CPU_KS -# if (IX_N == 040 || IX_N == 020) /* Faster check if power of 2 */ - if (LHGET(xw) & (((~(IX_N-1))<<9) | (AC_MASK<<5))) /* Check op and AC fields */ -# else - if (xop >= IX_N || (LHGET(xw) & (AC_MASK<<5))) /* Check op, AC field */ -# endif - return i_muuo(op, ac, e); /* Bad op or AC */ -#endif - - /* Calculate E1 using normal XEA map, which may page-fail! - ** Following the normal instruction model, - ** E1 would be calculated before looking at anything else (OP or AC). - ** However... - ** For both KS and KL this is always done after the initial OP+AC check, - ** regardless of whether the instruction needs E1 or not, with - ** one exception: on the KL, XBLT skips the E1 calc entirely! - ** (this exception doesn't seem worth emulating) - */ -#if KLH10_EXTADR - /* Default section for 2nd instr word EA calc is the section - ** that word was fetched from. - */ - return (*opcxrtn[xop])(xop, ac, e, xea_calc(xw, va_sect(e))); -#else - return (*opcxrtn[xop])(xop, ac, e, ea_calc(xw)); -#endif -} - -xinsdef(ix_undef) -{ - return i_muuo(I_EXTEND, ac, e0); -} - - -#if KLH10_SYS_T10 || KLH10_SYS_T20 /* DEC systems only */ - -/* All of the remaining code in this module is ignored for an ITS system, -** since the extended instructions were all tossed from the ITS ucode. -*/ - -/* AC flags for Binary<->Decimal conversions */ - -#define CVTF_L H10SIGN /* User sets to control justification */ -#define CVTF_S H10SIGN /* Another name for same bit */ -#define CVTF_N (H10SIGN>>1) /* Instr sets 1 if non-zero */ -#define CVTF_M (H10SIGN>>2) /* Instr sets 1 if negative */ -#define CVTF_ALL (CVTF_L|CVTF_N|CVTF_M) - -/* Internal result codes for the various instructions */ -/* NOTE: See EA_RES_PF, EA_RES_PI defs; must match RES_PF, RES_PI! */ -enum xires { - RES_OK=0, /* 0 is general non-error status */ - RES_TRUNC=1, /* Set 1 for efficient code (usu. returns PCINC_1) */ - RES_WON=2, /* Ditto (usu. returns PCINC_2) */ - RES_PF, /* Page Fail */ - RES_PI, /* PI Interrupt */ - RES_MUUO }; /* MUUO trap */ - - -/* Auxiliary power-of-10 table for CVT instructions */ -#define DPOW_MAX 23 -static dw10_t dpow10[DPOW_MAX]; /* Later maybe define at compile time */ - -void -inexts_init(void) /* Initialize any necessary EXTEND stuff */ -{ - register int i; - register dw10_t d; - h10_t savflgs; - - op10m_setz(d.w[0]); /* Set double fix to 1 */ - XWDSET(d.w[1], 0, 1); - dpow10[0] = d; /* Store 1 as first table entry */ - XWDSET(d.w[1], 0, 10); /* Then set it to 10 */ - - /* Compute rest of power-of-10 table, ignoring any overflow traps */ - savflgs = cpu.mr_pcflags; - for (i = 1; i < DPOW_MAX; ++i) { - qw10_t q; - q = op10dmul(dpow10[i-1], d); - dpow10[i] = q.d[1]; - } - cpu.mr_pcflags = savflgs; -} - - -/* Other auxiliaries */ - -/* Macro to fetch string length into a native 32-bit type for efficiency. -** Does a mask test to see whether length word has any illegal bits set -** and traps as a MUUO if so. -*/ -#define AC_32GET(r, a, off, lmask) \ - { register w10_t w; \ - w = ac_get(ac_off(a, off)); \ - if (op10m_tlnn(w, lmask)) \ - return i_muuo(I_EXTEND, (a), e0); \ - r = ((uint32)LHGET(w) << H10BITS) | RHGET(w); /* Convert to 32-bit value */ \ - } - -#if KLH10_EXTADR -# define ILLEG_LHVABITS 0770000 /* Bits illegal in LH of 30-bit virt addr */ -#else -# define ILLEG_LHVABITS 0777777 -#endif - -#if 0 -static uint32 -ac_32get(ac) -{ - register w10_t w; - w = ac_get(ac); /* Get c(AC) */ - return ((uint32)LHGET(w) << 18) | RHGET(w); /* Convert to 32-bit value */ -} -#endif /* 0 */ - -static void -ac_32set(int ac, uint32 val) -{ - register w10_t w; - LRHSET(w, (val>>18)&H10MASK, val & H10MASK); /* Put val into word */ - ac_set(ac, w); /* Store in AC */ -} - -#if KLH10_CPU_KLX - -/* XBLT -** NOTE: Per [Uhler83], XBLT is allowed from section 0 on a KLX! -** On the KS10 there is only section 0, so this always traps as a -** MUUO on that machine. Assume single-section KL similar. -** -** This is a straightforward implementation and there are several -** ways to optimize it: -** - Separate loops for forward and reverse BLTs -** - Test for 32-bit count and optimize in register -** - Test for src -> src+1 and avoid re-reading value if mappings same. -** - Test for within-mem-page BLTs and break into memcpy segments. -** -** Note: for PXCT, source uses XBEA mapping, dest uses XBRW. -** These correspond to PXCT AC bits 11 and 12 respectively. -** -** Note: The PRM implies the high 6 bits must be zero, and the original -** code here would cause a MUUO trap if they were set. However, a -** real KL appears to ignore these bits (and the ucode agrees); TOPS-20 -** CLISP turns out to depend on this! -** Thus, this code now preserves the high 6 bits, although there is -** no attempt to prevent overflow into them; this seems to be how -** the KL ucode worked. -*/ - -xinsdef(ix_xblt) -{ - register vaddr_t src, dst; - register vmptr_t svp, dvp; - w10_t wcnt, wsrc, wdst, wdone; - enum xires res = RES_WON; - - wsrc = ac_get(ac_off(ac,1)); /* Get source addr */ - va_gfrword(src, wsrc); /* Make global addr from wd */ - wdst = ac_get(ac_off(ac,2)); /* Now get destination */ - va_gfrword(dst, wdst); /* Likewise get global addr */ - - wcnt = ac_get(ac); /* Get possibly 36-bit cnt */ - if (op10m_skipge(wcnt)) { - register uint32 cnt; - uint32 origcnt; - - if (op10m_tlnn(wcnt, 0740000)) { - /* If any of high 4 bits are set, cannot represent in a 32-bit - count -- just use max possible count. This works because - only 30 bits of address are possible, so a 32-bit count - would wrap all of virtual memory 4 times! Will normally - get a page fail attempting this. - */ - cnt = MASK32; - } else { - cnt = W10_U32(wcnt); /* Get 32 bits of count */ - if (!cnt) /* If count zero, */ - return PCINC_1; /* return without any refs */ - } - origcnt = cnt; - - /* Do normal forward transfer */ - for (;;) { - if ( !(svp = vm_xbeamap(src, VMF_READ|VMF_NOTRAP)) - || !(dvp = vm_xbrwmap(dst, VMF_WRITE|VMF_NOTRAP))) { - res = RES_PF; - break; - } - vm_pset(dvp, vm_pget(svp)); /* Transfer the word */ - - va_ginc(src); /* Bump addrs up */ - va_ginc(dst); - if (--cnt == 0) /* Bump count down, see if done */ - break; /* stop loop! */ - - /* Done with one iteration, now check before doing next */ - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - cnt = origcnt - cnt; /* Find # of words transferred */ - W10_U32SET(wdone, cnt); - - } else { - /* Negative count means reverse xfer */ - register int32 cnt; /* Signed! */ - int32 origcnt; - - if ((~W10_LH(wcnt)) & 0760000) { - /* If any of high 5 bits are clear, cannot represent in a 32-bit - count -- just use max possible count. Same rationale as for - forward transfer. - */ - cnt = -MASK31; - } else { - cnt = W10_S32(wcnt); /* Get 32 bits of signed count */ - } - origcnt = cnt; - - /* Do reverse transfer */ - for (;;) { - va_gdec(src); /* Bump addrs down */ - va_gdec(dst); - - if ( !(svp = vm_xbeamap(src, VMF_READ|VMF_NOTRAP)) - || !(dvp = vm_xbrwmap(dst, VMF_WRITE|VMF_NOTRAP))) { - res = RES_PF; - break; - } - vm_pset(dvp, vm_pget(svp)); /* Transfer the word */ - - if (++cnt >= 0) /* Bump count up; if gone, */ - break; /* stop loop! */ - - /* Done with one iteration, now check before doing next */ - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - cnt = origcnt - cnt; /* Find -<#> of words transferred */ - W10_S32SET(wdone, cnt); - } - - /* Now update ACs. wdone contains the # words transfered (positive if - * forward, negative if reverse). - */ - op10m_sub(wcnt, wdone); /* Update word values */ - op10m_add(wsrc, wdone); - op10m_add(wdst, wdone); - - ac_set(ac, wcnt); /* Store back in ACs */ - ac_set(ac_off(ac, 1), wsrc); - ac_set(ac_off(ac, 2), wdst); - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - default: break; - } - return PCINC_1; -} -#endif /* KLH10_CPU_KLX */ - -/* New EA calculation function needed to support string instructions - Later move this to kn10pag.h, kn10cpu.c? -*/ - -enum eaarg { EA_ARG_IFIW=0, EA_ARG_EFIW=1, EA_ARG_UFIW=-1 }; - -/* NOTE!!! - Code assumes EA_RES_PF == RES_PF (ditto RES_PI) for simplicity!!! - */ -enum eares { EA_RES_OK=0, EA_RES_PF=RES_PF, EA_RES_PI=RES_PI }; - -#if KLH10_EXTADR - -/* XEA_FIWCALC - Extended Addressing IFIW/EFIW EA calc -** Returns result code after depositing EA in location provided. -** -** This is exactly the same algorithm as the standard (but faster) -** XEA_XCALC function except that instead of aborting on any error -** (page fail or PI), it returns with an error code. -** Although slower, this functionality is needed to give the extended -** string instructions a chance to clean up. -*/ -static int -xea_fiwcalc(register w10_t iw, /* IFIW/EFIW to evaluate */ - register unsigned int sect, /* Current section, if IFIW */ - register acptr_t acp, /* AC block mapping */ - register pment_t *map, /* Page table mapping */ - register vaddr_t *va, /* Result EA as virtual address */ - int f) /* arg flags */ -{ - register vaddr_t e; /* Address to return */ - - if (f) { - if (f > 0) goto xea_efiw; - else goto xea_ufiw; - } - - /* Handle IFIW - Instruction Format Indirect Word */ - for (;;) { - if (op10m_tlnn(iw, IW_X)) { /* Indexing? */ - register w10_t xw; - xw = ac_xget(iw_x(iw), acp); /* Get c(X) */ - /* Check for type of indexing. - ** Do global only if NZS E, X>0, and X<6:17> NZ - */ - if (op10m_skipge(xw) && sect && op10m_tlnn(xw, VAF_SMSK)) { - /* Note special hackery for global indexing: Y becomes - ** a signed displacement. - */ - va_gmake30(e, VAF_30MSK & (va_30frword(xw) - + (op10m_trnn(iw, H10SIGN) - ? (RHGET(iw) | (VAF_SMSK<src = src; /* Save args */ - bp->ac = ac; - w = ac_get(ac); /* Get the byte pointer */ - bp->p = LHGET(w) >> 12; /* P in high 6 bits */ - -#if KLH10_EXTADR - /* For extended addressing there are 3 cases: - ** OWLBP - One-Word Local BP - ** TWGBP - Two-Word Global BP (only valid in NZ PC sect) - ** OWGBP - One-Word Global BP (only valid in NZ PC sect, immediately - ** converted into a TWGBP) - ** NOTE: this is contrary to the way byte instructions - ** like DPB behave! (They accept OWGBPs in section 0) - */ - if (PC_ISEXT) { - if (bp->p > 36) { /* OWGBP? */ - register struct owgbpe *tp; - if (bp->p >= 63) - return RES_MUUO; /* return i_muuo(op, ac, e); */ - tp = &owgbptab[bp->p - 37]; - bp->p = tp->p; - bp->s = tp->s; - va_gfrword(bp->y, w); /* Get full 30-bit address */ - bp->fmt = BPF_OWG; /* Say originally an OWGBP */ - bp->isindir = FALSE; - - } else if (op10m_tlnn(w, BPF_2WD)) { /* TWGBP? */ - /* It's a TWGBP! - ** Note the NZ-section test above is always made using PC section, - ** unlike byte instrs which always use the section the byte ptr - ** was fetched from. - ** This is actually consistent if you remember that the ACs are - ** considered to belong to PC section. - */ - bp->s = (LHGET(w) >> 6) & 077; /* S in next 6 */ - w = ac_get(ac_off(ac,1)); /* Fetch 2nd word from AC+1 */ - - /* Interpret word as either an IFIW or EFIW. - ** Note this EA-calc is subject to hairy PXCT stuff! - ** Default section is PC section, unless affected by - ** PXCT in which case it's PCS. - ** No postprocessing is needed because both E and D bits are - ** implied if previous context applies to this pointer. - */ - if (op10m_skipl(w)) { /* IFIW? */ - if (op10m_tlnn(w, IW_EI)) { /* Bits 0,1 == 11? */ - /* Generate page fail trap for bits 0,1 == 11 */ - /* This is failure code 24 (PRM 3-41) */ - /* BP came from ACs which are always current context */ - vaddr_t e; /* Set up args for pagefail */ - va_lmake(e, 0, ac_off(ac,1)); - pag_iiset(e, cpu.vmap.cur); - return RES_PF; - } - bp->fmt = BPF_TWL; /* Say originally a TWLBP */ - bp->isindir = (op10m_tlnn(w, IW_I) != 0); - if (cpu.mr_inpxct && (cpu.mr_inpxct & (src ? 02 : 01))) { - /* Use XBEA if source, XBRW if dest, plus PCS */ - err = xea_fiwcalc(w, pag_pcsget(), - (src ? cpu.acblk.xbea : cpu.acblk.xbrw), - (src ? cpu.vmap.xbea : cpu.vmap.xbrw), - &(bp->y), EA_ARG_IFIW); - } else - err = xea_fiwcalc(w, PC_SECT, - cpu.acblk.xbea, cpu.vmap.xbea, - &(bp->y), EA_ARG_IFIW); - - } else { /* EFIW, no default section needed */ - bp->fmt = BPF_TWG; /* Say originally a TWGBP */ - bp->isindir = (op10m_tlnn(w, IW_EI) != 0); - if (cpu.mr_inpxct && (cpu.mr_inpxct & (src ? 02 : 01))) { - err = xea_fiwcalc(w, 0, - (src ? cpu.acblk.xbea : cpu.acblk.xbrw), - (src ? cpu.vmap.xbea : cpu.vmap.xbrw), - &(bp->y), EA_ARG_EFIW); - } else - err = xea_fiwcalc(w, 0, - cpu.acblk.xbea, cpu.vmap.xbea, - &(bp->y), EA_ARG_EFIW); - } - if (err) - return (enum xires)err; - } - else - goto localbp; /* Not a OWGBP or TWGBP, drop thru */ - - } else { - /* Plain vanilla one-word local BP. - ** As for TWGBPs, default section is PC section. - */ - localbp: - bp->s = (LHGET(w) >> 6) & 077; /* S in next 6 */ - bp->fmt = BPF_OWL; /* Say originally an OWLBP */ - bp->isindir = (op10m_tlnn(w, IW_I) != 0); - - if (cpu.mr_inpxct && (cpu.mr_inpxct & (src ? 02 : 01))) { - /* Use XBEA if source, XBRW if dest, plus PCS */ - err = xea_fiwcalc(w, pag_pcsget(), - (src ? cpu.acblk.xbea : cpu.acblk.xbrw), - (src ? cpu.vmap.xbea : cpu.vmap.xbrw), - &(bp->y), EA_ARG_IFIW); - } else { - /* Use XBEA mapping plus PC section */ - err = xea_fiwcalc(w, PC_SECT, - cpu.acblk.xbea, cpu.vmap.xbea, - &(bp->y), EA_ARG_IFIW); - } - if (err) - return (enum xires)err; - } - -#else /* end EXTADR */ - - bp->s = (LHGET(w) >> 6) & 077; /* S in next 6 */ - bp->isindir = (op10m_tlnn(w, IW_I) != 0); - - err = ((cpu.vmap.cur == cpu.vmap.xea) - ? ea_fiwcalc(w, cpu.acblk.xea, cpu.vmap.xea, &(bp->y)) - : (src ? ea_fiwcalc(w, cpu.acblk.xbea, cpu.vmap.xbea, &(bp->y)) - : ea_fiwcalc(w, cpu.acblk.xbrw, cpu.vmap.xbrw, &(bp->y)))); - if (err) - return (enum xires)err; -#endif /* !EXTADR */ - - /* Have P, S, and Y. Now finish setting up handy variables. */ - bp->newp = (W10BITS - bp->s) & 077; /* New P when moving to next word */ - bp->bmsk = /* Byte mask to use */ - wbytemask[bp->s <= W10BITS ? bp->s : W10BITS]; - bp->vp = NULL; - bp->ycnt = 0; - - return RES_OK; -} - - -/* XBPUPDATE - Store BP back in AC. -** Format to store is pre-determined by initial conversion. See -** XBPGET for the rules. -** NOTE: Care must be taken to preserve existing S, I, and X fields; -** only P and Y can be updated. For Y in particular this means -** updating it with the # of word increments since the last update. -*/ -static void -xbpupdate(register struct cleanbp *bp) -{ - register w10_t w; - register int ac = bp->ac; - -#if KLH10_EXTADR - switch (bp->fmt) { - case BPF_OWL: -#endif - w = ac_get(ac); - op10m_tlz(w, 0770000); /* Clear for new P */ - op10m_tlo(w, ((h10_t)(bp->p) << 12)); /* Set new P */ - RHSET(w, (RHGET(w) + bp->ycnt)&H10MASK); /* Set new Y */ - ac_set(ac, w); -#if KLH10_EXTADR - break; - - case BPF_TWL: - w = ac_get(ac); - op10m_tlz(w, 0770000); /* Clear for new P */ - op10m_tlo(w, ((h10_t)(bp->p) << 12) | BPF_2WD); - ac_set(ac, w); - ac = ac_off(ac, 1); - w = ac_get(ac); - RHSET(w, (RHGET(w) + bp->ycnt)&H10MASK); /* Set new Y */ - ac_set(ac, w); /* Store 2nd wd */ - break; - - case BPF_OWG: /* Store as simple TWG */ - XWDSET(w, (((h10_t)(bp->p) << 12) | (bp->s << 6) | BPF_2WD), 0); - ac_set(ac, w); - XWDSET(w, (h10_t)va_sect(bp->y), va_insect(bp->y)); - ac_set(ac_off(ac,1), w); /* Store 2nd wd */ - break; - - case BPF_TWG: - w = ac_get(ac); - op10m_tlz(w, 0770000); /* Clear for new P */ - op10m_tlo(w, ((h10_t)(bp->p) << 12) | BPF_2WD); - ac_set(ac, w); - ac = ac_off(ac, 1); - w = ac_get(ac); - { - uint32 y30; - y30 = (va_30frword(w) + bp->ycnt) & MASK30; /* Get new 30-bit Y */ - XWDSET(w, ((LHGET(w)&0770000) /* Preserve high 6 bits */ - | (y30 >> 18)), y30 & H10MASK); - } - ac_set(ac, w); /* Store 2nd wd */ - break; - } -#endif /* KLH10_EXTADR */ - bp->ycnt = 0; /* Must clear so further updates will work! */ -} - - -/* XIBP - Increment clean pointer, return TRUE if word address bumped */ -/* static int xibp(bp); */ -#define xibp(bp) ( \ - (((bp)->p -= (bp)->s) < 0) \ - ? ((bp)->p = (bp)->newp, (bp)->ycnt++, va_inc((bp)->y), 1) \ - : 0 ) - -/* XDECBP - Back up one, after already incremented. -** This is a function rather than an in-line macro because it's -** only called when backing out of an error, i.e. rarely. -** This should never be called unless the BP has been incremented, -** meaning that backing up should always be possible simply by -** backing up P. -** Unfortunately, nothing keeps the user from providing a bogus S. -** Unclear what the real machine does, but here I'll try to recover. -*/ -static void -xdecbp(register struct cleanbp *bp) -{ - if ((bp->p += bp->s) > W10BITS) { -#if 0 - panic("xdecbp: bad P! P=%lo S=%lo", (long)bp->p, (long)bp->s); -#endif - bp->p = bp->newp; /* Attempt feeble recovery */ - } -} - -/* XILDB - Fetch source byte. -** Note: for support of PXCT'd MOVSLJ, the map used is XBEA which -** is interpreted by EXTEND as the "source" map. -** ALSO NOTE: In order to conform to expectations of DFKCC diagnostic, -** the byte pointer is always incremented, whether or not a page failure -** happens. If a page failure does happen, the backup simply adjusts -** P, and leaves Y alone; if Y was incremented, it is left incremented. -** This is guaranteed to still work since P will then point to start of -** word and the next increment will get us back to the page fail point. -** ALSO NOTE: in order to accurately emulate the screw case where -** the BP is using an indirect address, we need to remember this fact -** and recompute the byte EA entirely when Y is incremented. Ugh! -** Worst problem is that all normal EA computations -** do a pagfail longjmp, with no provision for a failure return! -** Thus we use a duplicate XEA calc that *does* do fail-return. -** NOTE: also needs to provide for INSBRK exit! Yuck! -*/ - -static enum xires -xildb(register struct cleanbp *bp, register w10_t *wp) -{ - register w10_t w; - - if ((bp->p -= bp->s) < 0) { /* Find new P and Y */ - bp->p = bp->newp; /* Next word, so fix up P */ - bp->vp = NULL; - bp->ycnt++; - if (bp->isindir) { /* Using indirect EA? */ - /* Ugh. Write out BP, then re-compute byte EA. */ - register enum xires res; - xbpupdate(bp); - if (res = xbpinit(bp, bp->ac, bp->src)) { - xdecbp(bp); /* Failed?? Back up P */ - return bp->err = res; - } - } - else - va_inc(bp->y); /* Can just bump Y */ - } - if (!bp->vp) { /* Map new word addr if needed */ - if (!(bp->vp = vm_xbeamap(bp->y, VMF_READ|VMF_NOTRAP))) { - /* Map failure only backs up P, never Y! */ - if ((bp->p += bp->s) > W10BITS) /* Back up P */ - bp->p = bp->newp; /* Catch any screwy P+S case */ - return bp->err = RES_PF; /* Report failure */ - } - bp->wd = vm_pget(bp->vp); /* Fetch new word */ - } - - w = bp->wd; - op10m_rshift(w, bp->p); /* Shift word to right-align byte */ - op10m_and(w, bp->bmsk); /* Mask out byte */ - *wp = w; - return RES_OK; -} - - -/* XIDPB - Deposit dest byte. -** Note: for support of PXCT'd MOVSLJ, the map used is XBRW which -** is interpreted by EXTEND as the "destination" map. -** Same behavior on page failure as XILDB above. -*/ -static enum xires -xidpb(register struct cleanbp *bp, register w10_t *wp) -{ - register w10_t w, bmask; - - if ((bp->p -= bp->s) < 0) { /* Find new P and Y */ - bp->p = bp->newp; /* Next word, so fix up P */ - bp->vp = NULL; - bp->ycnt++; - if (bp->isindir) { /* Using indirect EA? */ - /* Ugh. Write out BP, then re-compute byte EA. */ - register enum xires res; - xbpupdate(bp); - if (res = xbpinit(bp, bp->ac, bp->src)) { - xdecbp(bp); /* Failed?? Back up P */ - return bp->err = res; - } - } - else - va_inc(bp->y); /* Can just bump Y */ - } - if (!bp->vp) { /* Map new word addr if needed */ - if (!(bp->vp = vm_xbrwmap(bp->y, VMF_WRITE|VMF_NOTRAP))) { - /* Map failure only backs up P, never Y! */ - if ((bp->p += bp->s) > W10BITS) /* Back up P */ - bp->p = bp->newp; /* Catch any screwy P+S case */ - return bp->err = RES_PF; /* Report failure */ - } - bp->wd = vm_pget(bp->vp); /* Fetch new word */ - } - - bmask = bp->bmsk; /* Get mask for byte */ - w = *wp; /* Fetch new byte */ - op10m_lshift(bmask, bp->p); /* Shift out to align mask with byte pos */ - op10m_lshift(w, bp->p); /* Shift new byte into position */ - op10m_andcm(bp->wd, bmask); /* Clear bits from byte pos in word */ - op10m_and(w, bmask); /* And remove excess bits from byte */ - op10m_ior(bp->wd, w); /* Stuff byte into word! */ - - /* Later try to defer storage until all done with word */ - vm_pset(bp->vp, bp->wd); /* Store new word */ - return RES_OK; -} - - -/* This is used only for MOVSRJ. -** The KL+KS ucode simply IBPs to effect the MOVSRJ skipping. -** This does it more cleverly, but the real reason is so the EA can -** be correctly recomputed if the BP was indirected through. -** Any resulting page fault happens before the first actual ILDB ref -** but that's okay. -** Note that no CLOCKPOLL/INSBRKTEST is needed because the loop here is -** limited to 35 iterations or less. -*/ -static enum xires -xadjbp(register struct cleanbp *bp, - register int32 n) /* Positive # of bytes to adjust up by */ -{ - register int32 yn; - - /* Make sure can't screw up due to bogus S (zero or >36) */ - if (bp->s <= 0) - return RES_OK; - - while (--n >= 0) { - if ((bp->p -= bp->s) < 0) { /* Find new P until hit end */ - - /* Must increment Y by 1. Take advantage of the forced word - alignment to add all remaining words in one swoop. - */ - if (bp->s >= W10BITS) { /* Guard against bogus S */ - yn = n+1; /* Full-word bytes. Note extra 1 */ - n = 0; - } else { - yn = (n / (W10BITS/bp->s)) + 1; /* Note extra 1 */ - n = (n % (W10BITS/bp->s)); - } - bp->ycnt += yn; - bp->p = bp->newp - (n * bp->s); - - /* Now update Y. If BP is indirect, must recompute the EA and - possibly fail (which involves no backup). - */ - if (bp->isindir) { - xbpupdate(bp); - return xbpinit(bp, bp->ac, bp->src); - } else - va_add(bp->y, yn); - break; - } - } - return RES_OK; -} - -/* MOVSLJ - Move String Left Justified (EXTEND [016 ]) -** -** This is the only EXTEND string instruction legal for PXCTing (and only -** on an extended KL). The -** necessary mappings are done by the byte-pointer auxiliary routines. -** See DEC PRM p.3-51. -*/ -xinsdef(ix_movslj) -{ - register int32 len1, len2; /* Note signed */ - register vaddr_t va; - struct cleanbp s1, s2; - w10_t wbyte; - w10_t wfill; - enum xires res = RES_TRUNC; - - AC_32GET(len1, ac, 0, 0777000); /* Get source len */ - AC_32GET(len2, ac, 3, 0777000); /* Get dest len */ - - /* Now to satisfy diag expectations, always fetch fill byte, thus - ** triggering a page fail at this point if necessary. - */ - va = e0; - va_inc(va); /* Get E0+1 */ - wfill = vm_read(va); /* Get c(E0+1) */ - - if (!len2) /* Quick check for null case */ - return len1 ? PCINC_1 : PCINC_2; /* Skip if no source bytes left */ - - XBPGET(&s1, ac, 1, BPSRC); /* Set up for read, may pagefault */ - XBPGET(&s2, ac, 4, BPDST); - - /* Default result depends on whether strings will count out together */ - res = (len1 == len2) ? RES_WON : RES_TRUNC; - - while (--len2 >= 0) { - if (--len1 < 0) { /* If source string is gone */ - /* Get fill byte, start inner loop */ - res = RES_WON; /* Source string exhausted */ - do { - if (xidpb(&s2, &wfill)) { - /* Clean up and fail (normally page fail) */ - res = s2.err; - ++len2; - break; - } - } while (--len2 >= 0); - break; /* Return, either won or page-failed */ - } - - /* Fetch & store byte */ - if (xildb(&s1, &wbyte)) { - /* Clean up and fail (normally page fail) */ - res = s1.err; - ++len1, ++len2; /* Back up */ - break; - } - if (xidpb(&s2, &wbyte)) { /* Store byte */ - /* Clean up and page-fail */ - res = s2.err; - xdecbp(&s1); /* Back up source BP */ - ++len1, ++len2; - break; - } - - /* Done with one iteration, now check before doing next */ - if (len2 <= 0) - break; /* Nope, all done */ - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - - /* Done, update ACs and return appropriate PC increment - ** (Skips if source was exhausted) - */ - ac_32set(ac, (len1 > 0 ? len1 : 0)); - xbpupdate(&s1); /* Update BP in AC+1,2 */ - ac_32set(ac_off(ac,3), (len2 > 0 ? len2 : 0)); - xbpupdate(&s2); /* Update BP in AC+4,5 */ - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - case RES_WON: return PCINC_2; /* Skips if source exhausted */ - default: - case RES_TRUNC: return PCINC_1; - } -} - -/* MOVSO - Move String Offset (EXTEND [014 ]) -*/ -xinsdef(ix_movso) -{ - register int32 len1, len2; /* Note signed */ - register vaddr_t va; - struct cleanbp s1, s2; - w10_t wbyte; - w10_t wfill; - register w10_t woff, wmask; - enum xires res = RES_TRUNC; - - if (va_insect(e1) & H10SIGN) /* See if high halfwd bit set */ - LRHSET(woff, H10MASK, va_insect(e1)); /* Yep, sign-extend it */ - else LRHSET(woff, 0, va_insect(e1)); /* Nope */ - - AC_32GET(len1, ac, 0, 0777000); /* Get source len */ - AC_32GET(len2, ac, 3, 0777000); /* Get dest len */ - - /* Now to satisfy diag expectations, always fetch fill byte, thus - ** triggering a page fail at this point if necessary. - */ - va = e0; - va_inc(va); /* Get E0+1 */ - wfill = vm_read(va); /* Get c(E0+1) */ - - if (!len2) /* Quick check for null case */ - return len1 ? PCINC_1 : PCINC_2; /* Skip if no source bytes left */ - XBPGET(&s1, ac, 1, BPSRC); /* Set up for read, may pagefault */ - XBPGET(&s2, ac, 4, BPDST); - - /* Final setup for offset - remember mask to use */ - wmask = s2.bmsk; /* Get mask for byte */ - op10m_setcm(wmask); /* Complement it to get test mask */ - - /* Default result depends on whether strings count out together */ - res = (len1 == len2) ? RES_WON : RES_TRUNC; - - while (--len2 >= 0) { - if (--len1 < 0) { /* If source string is gone */ - - /* Note offset not applied to fill byte! */ - res = RES_WON; /* Source string exhausted */ - do { - if (xidpb(&s2, &wfill)) { - /* Clean up and page fail */ - res = s2.err; - ++len2; - break; - } - } while (--len2 >= 0); - break; /* Return, either won or page-failed */ - } - - /* Fetch & store byte */ - if (xildb(&s1, &wbyte)) { - /* Clean up and page-fail */ - res = s1.err; - ++len1, ++len2; /* Back up */ - break; - } - /* Now do special MOVSO stuff. */ - op10m_add(wbyte, woff); /* Add offset */ - if (op10m_tdnn(wbyte, wmask)) { /* Check for non-byte bits set */ - /* Clean up and lose. Source BP and len are left pointing - ** to the guilty byte (last one referenced). - */ - ++len2; /* Back up pre-decremented count */ - res = RES_TRUNC; - break; - } - if (xidpb(&s2, &wbyte)) { /* Store byte */ - /* Clean up and page-fail */ - res = s2.err; - xdecbp(&s1); /* Back up source BP */ - ++len1, ++len2; - break; - } - - /* Done with one iteration, now check before doing next */ - if (len2 <= 0) /* More to do? */ - break; - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - - /* Done, update ACs and return appropriate PC increment - ** (Skips if source was exhausted) - */ - ac_32set(ac, (len1 > 0 ? len1 : 0)); - xbpupdate(&s1); /* Update BP in AC+1,2 */ - ac_32set(ac_off(ac,3), (len2 > 0 ? len2 : 0)); - xbpupdate(&s2); /* Update BP in AC+4,5 */ - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - case RES_WON: return PCINC_2; /* Skips if source exhausted */ - default: - case RES_TRUNC: return PCINC_1; - } -} - -/* MOVST - Move String Translated (EXTEND [015 ]) -** -** It appears that real machine always fetches the fill byte regardless -** of whether it is needed or not. So I'm doing the same thing in order -** to accurately emulate the page fail testing done by the diagnostics. -** Sigh. Similar problem for CMPSxx. -*/ - -xinsdef(ix_movst) -{ - register int32 len1, len2; /* Note signed */ - register vmptr_t vp; - register vaddr_t va; - h10_t flags; - struct cleanbp s1, s2; - w10_t wbyte; - w10_t wfill; - enum xires res = RES_WON; - - /* First get lengths and check for illegal bits */ - AC_32GET(len1, ac, 0, 0077000); /* Get source len */ - flags = ac_getlh(ac) & CVTF_ALL; /* Find flags */ - - AC_32GET(len2, ac, 3, 0777000); /* Get dest len */ - - /* Now to satisfy diag expectations, always fetch fill byte, thus - ** triggering a page fail at this point if necessary. - */ - va = e0; - va_inc(va); /* Get E0+1 */ - wfill = vm_read(va); /* Get c(E0+1) */ - - if (!len2) /* Quick check for no-destination case */ - return len1 ? PCINC_1 : PCINC_2; /* Skip if no source bytes either */ - XBPGET(&s1, ac, 1, BPSRC); /* Set up for read, may pagefault */ - XBPGET(&s2, ac, 4, BPDST); - - /* Start loop. Note result defaults to RES_WON. */ - while (--len1 >= 0) { /* Loop reading from source */ - register h10_t ent; - if (xildb(&s1, &wbyte)) { /* Fetch byte */ - res = s1.err; /* Clean up and page-fail */ - ++len1; /* Back up */ - break; - } - /* Now do special MOVST stuff. */ - ent = RHGET(wbyte); - va = e1; - va_add(va, (ent>>1)); /* Get E1+(ent>>1) */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) { - xdecbp(&s1); /* Back up source bp */ - ++len1; /* Back up */ - res = RES_PF; /* Clean up and page-fail */ - break; - } - /* Do translation (same table as CVTDBT) */ - ent = (ent & 01) ? vm_pgetrh(vp) : vm_pgetlh(vp); - switch ((ent >> 15) & 07) { - case 0: break; - case 1: res = RES_TRUNC; break; - case 2: flags &= ~CVTF_M; break; - case 3: flags |= CVTF_M; break; - case 4: flags |= CVTF_S|CVTF_N; break; - case 5: flags |= CVTF_N; res = RES_TRUNC; break; - case 6: flags = CVTF_S|CVTF_N; break; - case 7: flags = CVTF_S|CVTF_N|CVTF_M; break; - } - if (res != RES_WON) /* If wants to stop now, */ - break; /* leave the loop! */ - - if (flags & CVTF_S) { - LRHSET(wbyte, 0, ent & 007777); /* Get translated byte */ - if (xidpb(&s2, &wbyte)) { /* Deposit it! */ - res = s2.err; /* Clean up and page-fail */ - xdecbp(&s1); - ++len1; -/* KLH: Possible bug here, if pagefail at this point - the flags have already been clobbered! But flag state shouldn't - affect the repeated translation, so this should be OK. -*/ - break; - } - if (--len2 <= 0) { /* Byte stored, bump count! */ - if (len1 > 0) /* Dest full, must stop. */ - res = RES_TRUNC; /* Say truncated, if any source left */ - break; - } - } - - /* Done with one iteration, now check before doing next */ - if (len1 <= 0) /* Stop now if none left */ - break; - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - - /* Now see if have to fill out rest of dest string. - ** This only happens if result is still RES_WON. - */ - if (res == RES_WON && len2 > 0) { - for (;;) { - /* OK, set up for fill loop, using saved fill byte */ - /* Note translation not applied to fill byte! */ - if (xidpb(&s2, &wfill)) { - res = s2.err; /* Clean up and page fail */ - break; - } - if (--len2 <= 0) - break; - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - } - - /* Done, update ACs and return appropriate PC increment - ** (Skips if source was exhausted) - */ - if (len1 < 0) - len1 = 0; /* Clear so don't return -1! */ - ac_setlrh(ac, flags | (len1>>H10BITS), len1 & H10MASK); - xbpupdate(&s1); /* Update BP in AC+1,2 */ - ac_32set(ac_off(ac,3), (len2 > 0 ? len2 : 0)); - xbpupdate(&s2); /* Update BP in AC+4,5 */ - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - case RES_WON: return PCINC_2; /* Skips if source exhausted */ - default: - case RES_TRUNC: return PCINC_1; - } -} - -/* MOVSRJ - Move String Right Justified (EXTEND [017 ]) -** -** Although PRM doesn't say so explicitly, AC is always 0 unless the -** instr is interrupted, because the source string is always completely -** consumed one way or another. -*/ -xinsdef(ix_movsrj) -{ - register int32 len1, len2; /* Note signed */ - register vaddr_t va; - struct cleanbp s1, s2; - w10_t wbyte; - w10_t wfill; - enum xires res = RES_OK; - - AC_32GET(len1, ac, 0, 0777000); /* Get source len */ - AC_32GET(len2, ac, 3, 0777000); /* Get dest len */ - - /* Now to satisfy diag expectations, always fetch fill byte, thus - ** triggering a page fail at this point if necessary. - */ - va = e0; - va_inc(va); /* Get E0+1 */ - wfill = vm_read(va); /* Get c(E0+1), may pagefault */ - - if (!len2) /* Quick check for null dest case */ - return PCINC_2; /* MOVSRJ always skips?? */ - XBPGET(&s1, ac, 1, BPSRC); /* Set up for read, may pagefault */ - XBPGET(&s2, ac, 4, BPDST); - - /* Decide what to do */ - if (len1 < len2) { - /* Use initial padding with fill. Fill dest until same len as src. */ - for (;;) { - if (xidpb(&s2, &wfill)) { - res = s2.err; - break; - } - if (--len2 <= len1) /* Update dest len, keep going */ - break; /* unless dest now small enough */ - - CLOCKPOLL(); /* More to do, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - } else if (len1 > len2) { - /* Source too big, skip over source bytes before starting copy */ - res = xadjbp(&s1, len1-len2); /* IBP it cleverly, RES_OK if won */ - len1 = len2; /* Source len now same as dest */ - } - - if ((res == RES_OK) /* Make sure still OK (not PF or PI) */ - && len2) { /* and dest string still needs more stuff */ - /* At this point, len1 == len2 and at least one byte to copy */ - for (;;) { - if (xildb(&s1, &wbyte)) { /* Fetch byte! */ - res = s1.err; /* Page-fail. No backup needed */ - break; - } - if (xidpb(&s2, &wbyte)) { /* Store byte! */ - res = s2.err; - xdecbp(&s1); /* Page-fail, must back up source BP */ - break; - } - - /* Done with one iteration, now check before doing next */ - if (--len2 <= 0) - break; /* Nope, all done */ - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - len1 = len2; /* Update len1 to match len2 */ - } - - /* Done, update ACs and return appropriate PC increment - ** (MOVSRJ always skips unless interrupted) - */ - ac_32set(ac, len1); - xbpupdate(&s1); /* Update BP in AC+1,2 */ - ac_32set(ac_off(ac,3), len2); - xbpupdate(&s2); /* Update BP in AC+4,5 */ - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - default: - case RES_OK: - case RES_WON: return PCINC_2; - } -} - -/* CMPSxx - Compare Strings (EXTEND [001-007 ]) -** Note 000 and 004, which otherwise would be CMPS and CMPSA, -** are respectively illegal and EDIT. -** -** In order to make the DFKCC diag happy it appears that we need to -** reference the appropriate fill word at E0+1 or E0+2 first, before -** comparing any bytes! -*/ - -/* Success bits for op */ -#define CMPF_LT 01 /* Skip if S1 < S2 */ -#define CMPF_EQ 02 /* Skip if S1 = S2 */ -#define CMPF_GT 04 /* Skip if S1 > S2 */ - -static int cmpftab[] = { - 0, /* [000 ] Illegal - wd be "CMPS", never skip */ - CMPF_LT, /* [001 ] CMPSL */ - CMPF_EQ, /* [002 ] CMPSE */ - CMPF_LT|CMPF_EQ, /* [003 ] CMPSLE */ - -1, /* [004 ] EDIT - wd be "CMPSA", always skip */ - CMPF_EQ|CMPF_GT, /* [005 ] CMPSGE */ - CMPF_LT|CMPF_GT, /* [006 ] CMPSN */ - CMPF_GT /* [007 ] CMPSG */ -}; - -/* Common code for CMPSx extended instructions. -** Skips if string comparison result matches any of the requested CMPF bits. -*/ -xinsdef(ix_cmps) /* Do all CMPSx instructions */ -{ - register int32 len1, len2; /* Note signed */ - register vaddr_t va; - struct cleanbp s1, s2; - w10_t w1, w2; - register w10_t fill; - enum xires res = RES_OK; - register int cmpf; - - /* Set up string lengths. */ - AC_32GET(len1, ac, 0, 0777000); /* Get source len */ - AC_32GET(len2, ac, 3, 0777000); /* Get dest len */ - - /* To accurately emulate the KS/KL with respect to page fails, we - ** we need to fetch the appropriate fill byte first, and do it even - ** if none is needed (string lengths equal). - */ -#if 0 /* More efficient, but won't trigger failures that diag expects */ - if (!len1 && !len2) /* Quick check for null case */ - return (xop == (IX_CMPSE & 0777)) ? PCINC_2 : PCINC_1; -#endif - - /* It appears that when the lengths are equal, the fill byte fetched - ** comes from E0+2 on the KS, E0+1 on the KL. Whoopee. - ** Again, this is only to keep diags happy. - */ - va = e0; /* Set up E0 */ -#if KLH10_CPU_KL - if (len1 <= len2) -#elif KLH10_CPU_KS - if (len1 < len2) -#endif - va_inc(va); /* Get E0+1 (source fill) */ - else - va_add(va, 2); /* Get E0+2 (dest fill) */ - fill = vm_read(va); /* Fetch fill byte, may pagefault */ - - XBPGET(&s1, ac, 1, BPSRC); /* Set up for read, may pagefault */ - XBPGET(&s2, ac, 4, BPDST); - - /* Loop until pagefail, interrupt, bytes not equal, or count out */ - cmpf = CMPF_EQ; /* Default if count out is equal */ - for (;;) { - if (--len1 >= 0) { /* Get byte from string 1 */ - if (xildb(&s1, &w1)) { - res = s1.err; - ++len1; /* Back up, assume BP backed up */ - break; - } - } else { - if (len2 <= 0) break; - if (len1 == -1) { /* If first time here, get fill byte */ - w1 = fill; - } - } - - if (--len2 >= 0) { /* Get byte from string 2 */ - if (xildb(&s2, &w2)) { - res = s2.err; - ++len2; /* Back up */ - if (len1 >= 0) { - ++len1; - xdecbp(&s1); /* Back up first BP */ - } - break; - } - } else { - /* No test for len1 cuz if we got here it's known to be OK */ - if (len2 == -1) { /* If first time here, get fill byte */ - w2 = fill; - } - } - - /* Both bytes fetched, now test */ - if (op10m_camn(w1, w2)) { /* Test for equality */ - cmpf = (op10m_ucmpl(w1, w2) /* Not equal! Use unsigned compare */ - ? CMPF_LT : CMPF_GT); - break; - } - - /* Equal so far. Set up to repeat loop... */ - CLOCKPOLL(); /* Keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - - /* Return result after updating ACs */ - ac_32set(ac, (len1 > 0 ? len1 : 0)); - xbpupdate(&s1); /* Update BP in AC+1 */ - ac_32set(ac_off(ac,3), (len2 > 0 ? len2 : 0)); - xbpupdate(&s2); /* Update BP in AC+4 */ - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - default: - /* Skip if result bit found in op's success bits */ - return (cmpf & cmpftab[xop & 07]) ? PCINC_2 : PCINC_1; - } -} - -/* CVTBDO - Convert Binary to Decimal Offset (EXTEND [012 ]) - CVTBDT - Convert Binary to Decimal Translated (EXTEND [013 ]) - -NOTE: - It has been discovered the hard way that CVTBDx does the -string length check before it attempts to load or reference the byte -pointers (in particular, during monitor startup to determine CPU type). -Hence the initialization of S2 must be delayed until after that point. - - Also, the fill byte fetch, unlike the MOVS and CMPS instructions, -is only done if needed -- not beforehand! - - Also, the real hardware uses the First-Part-Done flag to tell -itself that an interrupted CVTBDx has gubbish in the ACs that are not -meaningful to anything but the KL microcode. The emulation here avoids -using FPD by always restoring the ACs to a sensible state. For this reason, -diagnostics (ie DFKCC) that test interrupted results will always fail. - - Note that a successful CVTBDx is defined to clear the length AC, -even if no filling was done; thus the returned length cannot be used to -tell how many characters were deposited, and in fact its value during -an interrupt (on a real KL) is the # of digits left to do, not the # of -bytes left in destination buffer. The code here emulates this for -simplicity. - -*/ -static int cvtb_digcnt(dw10_t *ad); - -xinsdef(ix_cvtbd) /* Do both CVTBDO and CVTBDT */ -{ - register int32 len2; /* Note signed */ - register vaddr_t va; - h10_t flags; - register int ndigs; - struct cleanbp s2; - w10_t wfill, woff; - dw10_t d; - int transf; - enum xires res = RES_TRUNC; - - AC_32GET(len2, ac, 3, 0077000); /* Get dest len (may fail) */ - flags = ac_getlh(ac_off(ac,3)) & CVTF_ALL; /* Find flags */ - - /* Check opcode to see if doing translate. Must mask IX_ since enum - ** has special high bit(s). - */ - transf = (xop == (IX_CVTBDT & 0777)); /* See if doing translate */ - if (!transf) { /* If not, set up offset */ - if (va_insect(e1) & H10SIGN) /* See if high halfwd bit set */ - LRHSET(woff, H10MASK, va_insect(e1)); /* Yep, sign-extend it */ - else LRHSET(woff, 0, va_insect(e1)); /* Nope */ - } - - ac_dget(ac, d); /* Get binary double */ - - /* Set N,M flags appropriately */ - if (op10m_signtst(d.w[0])) { - flags |= CVTF_N | CVTF_M; /* Non-zero and Minus */ - op10m_dmovn(d); /* Make positive */ - } else { - op10m_signclr(d.w[1]); /* Positive, ensure low sign clear */ - if (op10m_skipn(d.w[0]) || op10m_skipn(d.w[1])) - flags |= CVTF_N; /* Non-zero */ - } - /* Put flags in now if KL -- easier than checking for aborts at - ** XBPGET and fill-byte fetch below. - */ -#if KLH10_CPU_KL - ac_setlrh(ac_off(ac,3), flags | (len2>>H10BITS), len2 & H10MASK); -#endif - - /* The low sign bit is guaranteed to be clear at this point, - ** and the high sign bit will only be set if the entire number - ** is the maximum negative value of -2^70. - */ - - /* At this point, determine how large number will be. - ** Can either do a binary search on power-of-10 table, or - ** actually build string and find out. - ** Max is 22 digits; search would take max of 5 comparisons (2^5 == 32) - ** whereas building string does divides by 10... ugh! - ** Idea: faster to do own add/sub loop, using power-of-10 table. A - ** single regular DDIV does 70 dadd/dsubs! - */ - if (op10m_signtst(d.w[0])) { /* If still negative, */ - ndigs = 22; /* is max # of 2^70!! */ - } else { - ndigs = cvtb_digcnt(&d); - } - - if (ndigs > len2) { - /* Number requires more digits than dest string has, so fail */ - return PCINC_1; - } - - /* OK to proceed, now set up destination BP. - ** This cannot be done earlier since CVTBDx is used by certain - ** processor-ID algorithms that leave garbage in the ACs and will be - ** very surprised to get a page fail or MUUO instead! - */ - XBPGET(&s2, ac, 4, BPDST); /* Set up dest BP from ACs */ - - /* If dest string is longer, and CVTF_L is set, pad out. */ - if ((len2 > ndigs) && (flags & CVTF_L)) { - - /* Get fill byte word from E0+1 - can page-fail! - ** No special cleanup needed as flags have already been set if KL. - */ - va = e0; - va_inc(va); - wfill = vm_read(va); - - res = RES_TRUNC; - while (len2 > ndigs) { - if (xidpb(&s2, &wfill)) { /* Store fill byte */ - res = s2.err; - break; - } - --len2; - CLOCKPOLL(); /* Keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - if (res != RES_TRUNC) { - ac_setlrh(ac_off(ac,3), flags | (len2>>H10BITS), len2 & H10MASK); - xbpupdate(&s2); /* Update BP in AC+4 */ - switch (res) { - case RES_PF: pag_fail(); - case RES_PI: apr_int(); - default: break; - } - } - } - - /* At this point, only "ndigs" more bytes to deposit. - ** OK to stop keeping track of len2, because returned count is - ** always 0 if success, and if interrupted the real KL sets this - ** to updated ndigs, not updated len2, so we do the same. - ** ndigs is guaranteed to be nonzero (see cvtb_digcnt). - */ - - /* Build decimal string. Starting with power-of-10 specified by - ** ndigs, count how many times one has to subtract that before - ** number is within range of lesser power, and that's the digit - ** for that position. - */ - for (;;) { - register int dig; - w10_t wbyte; - dw10_t rbdw; /* For rollback if pagefail */ - - rbdw = d; /* Save current number */ - if (ndigs == 1) - dig = RHGET(d.w[1]); /* d contains last digit */ - else - for (dig = 0; !op10m_udcmpl(d, dpow10[ndigs-1]); ++dig) { - /* Carry out a DSUB. Assumes low sign bit clear! */ - op10m_sub(d.w[0], dpow10[ndigs-1].w[0]); /* Sub high words */ - op10m_sub(d.w[1], dpow10[ndigs-1].w[1]); /* Sub low words */ - if (op10m_signtst(d.w[1])) { /* If low sign now set, */ - op10m_dec(d.w[0]); /* carry to high word */ - op10m_signclr(d.w[1]); /* and clear low sign */ - } - } - - /* dig now contains digit 0-9 for this position */ - - /* Offset or translate digit into a byte, then deposit that */ - if (!transf) { - wbyte = woff; - op10m_addi(wbyte, dig); - } else { - /* Translate stuff */ - register vmptr_t vp; - va = e1; - va_add(va, dig); /* Get E1+dig */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) { - res = RES_PF; /* Page fail, can't fetch transl */ - d = rbdw; /* Roll back to original # */ - break; - } - wbyte = vm_pget(vp); - if (ndigs == 1 && (flags & CVTF_M)) /* Special hack for last dig */ - RHSET(wbyte, LHGET(wbyte)); /* Use LH instead if M set */ - LHSET(wbyte, 0); /* Clear LH */ - } - if (xidpb(&s2, &wbyte)) { - res = s2.err; /* Page fail, can't deposit byte */ - d = rbdw; /* Roll back to original # */ - break; - } - - /* Success for this digit! */ - if (--ndigs <= 0) { /* Was it last digit? */ - op10m_setz(d.w[1]); /* Clear low AC (high already clear) */ - break; /* And leave loop! */ - } - - CLOCKPOLL(); /* More digits, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - - - ac_dset(ac, d); /* Store back binary number */ - ac_setlrh(ac_off(ac,3), flags | (ndigs>>H10BITS), ndigs & H10MASK); - xbpupdate(&s2); /* Store BP back in AC+4,5 */ - switch (res) { - case RES_PF: pag_fail(); - case RES_PI: apr_int(); - default: break; - } - - return PCINC_2; -} - - - -/* Count # decimal digits in double-word binary number, which is guaranteed -** to be positive with sign bits clear in both words. -*/ - -static int -cvtb_digcnt(dw10_t *ad) -{ - register int i; - register dw10_t d; - - d = *ad; - for (i = 1; i < DPOW_MAX; ++i) - if (op10m_udcmpl(d, dpow10[i])) - break; - - /* i has the power of 10 that this number fits under, thus the # of digits - ** needed to represent it is likewise i. i will never be 0, even when - ** the number is zero, because count starts at 1. - */ - return i; -} - -/* CVTDBO - Convert Decimal to Binary Offset (EXTEND [010 ]) - CVTDBT - Convert Decimal to Binary Translated (EXTEND [011 ]) -*/ - -#define CVTF_S H10SIGN /* User sets to indicate pre-existing # */ - -xinsdef(ix_cvtdb) /* Do both CVTDBO and CVTDBT */ -{ - register int32 len1; /* Note signed */ - register int transf; /* TRUE if CVTDBT, else CVTDBO */ - register vaddr_t va; - h10_t flags; - struct cleanbp s1; - w10_t wbyte, woff; - dw10_t d; - unsigned int dig; - enum xires res; - - AC_32GET(len1, ac, 0, 0077000); /* Get src len (may MUUO-fail) */ - flags = ac_getlh(ac) & CVTF_ALL; /* Find flags */ - XBPGET(&s1, ac, 1, BPSRC); /* Set up source BP */ - - /* Check opcode to see if doing translate. Must mask IX_ since enum - ** has special high bit(s). - */ - transf = (xop == (IX_CVTDBT & 0777)); - if (!transf) { /* If not, set up offset */ - if (va_insect(e1) & H10SIGN) /* See if high halfwd bit set */ - LRHSET(woff, H10MASK, va_insect(e1)); /* Yep, sign-extend it */ - else LRHSET(woff, 0, va_insect(e1)); /* Nope */ - } - - if (flags & CVTF_S) /* Number already there? */ - ac_dget(ac_off(ac,3), d); /* Get binary double */ - else { - op10m_dsetz(d); /* Nope, clear it */ - if (!transf) /* If doing offset (CVTDBO), ensure */ - flags |= CVTF_S; /* that S is now set. */ - } - - /* Now loop over source string. Note default result is RES_WON. */ - res = RES_WON; - if (len1 > 0) - for (;;) { /* Loop check is near end */ - - if (xildb(&s1, &wbyte)) { - res = s1.err; - break; - } - --len1; /* Byte gobbled, so bump count */ - if (!transf) { /* Do offset? */ - op10m_add(wbyte, woff); /* Add in offset */ - if (LHGET(wbyte)) { - res = RES_TRUNC; - break; /* Abort, digit is outside range */ - } - dig = RHGET(wbyte); - - } else { /* Do translation */ - register vmptr_t vp; - register h10_t ent; - ent = RHGET(wbyte); - va = e1; - va_add(va, (ent>>1)); /* Get E1+(ent>>1) */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) { - /* Page-fail trying to fetch translation table entry */ - xdecbp(&s1); /* Back up source bp */ - ++len1; - res = RES_PF; - break; - } - ent = (ent & 01) ? vm_pgetrh(vp) : vm_pgetlh(vp); - switch ((ent >> 15) & 07) { - case 0: break; - case 1: res = RES_TRUNC; break; - case 2: flags &= ~CVTF_M; break; - case 3: flags |= CVTF_M; break; - case 4: flags |= CVTF_S|CVTF_N; break; - case 5: flags |= CVTF_N; res = RES_TRUNC; break; - case 6: flags = CVTF_S|CVTF_N; break; - case 7: flags = CVTF_S|CVTF_N|CVTF_M; break; - } - if (res != RES_WON) /* If wants to stop now, */ - break; /* leave the loop! */ - dig = ent & 017; /* Isolate digit in case S is set */ - } - - /* dig now contains the value 0-9. Add into number so far. */ - if (!transf || (flags & CVTF_S)) { /* Put digit in? */ - dw10_t dtmp; - - /* Verify that it's a 0-9 value! */ - if (dig > 9) { - res = RES_TRUNC; - break; /* Abort, digit is outside range */ - } - - /* Multiply existing number by 10 and then add digit. - ** We do the multiply "by hand" here to avoid extremely slow - ** full-blown DMUL, by using fact multiplier is always 10. - ** This amounts to (x * 8) + (x * 2) which can be done with - ** two shifts and two adds. - */ - dtmp = d; - op10m_ashcleft(dtmp, 1); /* Multiply by 2 */ - op10m_ashcleft(d, 3); /* Multiply by 8 */ - - /* Add together to produce multiply by 10. Code depends on - ** fact that above macros always clear sign bit of low word. - */ - op10m_add(d.w[0], dtmp.w[0]); /* Add high words */ - op10m_add(d.w[1], dtmp.w[1]); /* Add low words */ - if (op10m_signtst(d.w[1])) { /* If low sign now set, */ - op10m_inc(d.w[0]); /* carry to high word */ - op10m_signclr(d.w[1]); /* and clear low sign */ - } - /* Now finally add in the digit! */ - op10m_addi(d.w[1], dig); /* Add into low word */ - if (op10m_signtst(d.w[1])) { /* If low sign now set, */ - op10m_inc(d.w[0]); /* carry to high word */ - op10m_signclr(d.w[1]); /* and clear low sign */ - } - } - - /* This byte done; if any more, do usual clock/PI check */ - if (len1 <= 0) { - res = RES_WON; /* Source all gone, win! */ - break; - } - CLOCKPOLL(); /* More left, keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - break; - } - } - - /* Left loop, see if it succeeded or if we aborted */ - if (res == RES_WON && (flags & CVTF_M)) /* If won, must negate? */ - op10m_dmovn(d); /* Yup, do so */ - - /* Now propagate high sign to low word. This has to be done in a - ** general way since if we started with a pre-loaded value - ** the sign bits are unpredictable. - */ - if (op10m_signtst(d.w[0])) - op10m_signset(d.w[1]); /* Set low sign */ - else - op10m_signclr(d.w[1]); /* Clear low sign */ - - ac_setlrh(ac, flags | (len1>>H10BITS), len1 & H10MASK); - xbpupdate(&s1); /* Store byte ptr in AC+1,2 */ - ac_dset(ac_off(ac,3), d); /* Store back binary number */ - - switch (res) { - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - case RES_WON: return PCINC_2; /* Skips if ate source w/o probs */ - default: - case RES_TRUNC: return PCINC_1; - } -} - -/* EDIT - Edit String (EXTEND [004 ]) -** -** Extended KL note: -** The pattern string and mark addresses must be handled differently -** depending on whether running extended or not. Test for this is PC -** section; if 0, both mark & pattern are treated as 18-bit addrs, else -** as 30-bit addrs. -** If using 18-bit addrs, having any high bits set <6:17> is -** undefined, but for the KLH10 I'll have them do a MUUO trap. -** OOPS. Judging from the diagnostics, it appears that this is not -** what the machine does. Instead, simply ignore any high bits not -** needed for the address (either 18-bit or 30-bit). This includes -** the high 6 bits of the mark pointer, even though the PRM says they -** are MBZ. -*/ -#define EC_MESSAG 0100 -#define EC_SKPM 0500 -#define EC_SKPN 0600 -#define EC_SKPA 0700 -#define EC0_STOP 000 -#define EC0_SELECT 001 -#define EC0_SIGST 002 -#define EC0_FLDSEP 003 -#define EC0_EXCHMD 004 -#define EC0_NOP 005 - -xinsdef(ix_edit) -{ - register uint32 pp; /* Pattern pointer */ - register vaddr_t ppva; /* Pattern pointer virtual addr */ - register unsigned int ppbn; /* Byte # within pattern word */ - register vaddr_t mark; /* Mark pointer */ - register vmptr_t vp; - register vaddr_t va; /* Random temporary vaddr_t */ - register int inc; - h10_t flags, ent; - struct cleanbp s1, s2; - w10_t pword, wbyte; -#if KLH10_EXTADR - vaddr_t mark2; /* Mark pointer plus 1, for TWGBPs */ -#endif - enum xires res; - - AC_32GET(pp, ac, 0, 0040000); /* Get pattern addr (B3=0) */ - pp &= MASK30; /* 30-bit mask */ -#if KLH10_EXTADR - if (PC_ISEXT) - va_gmake30(ppva, pp); /* Get vaddr_t from 30-bit value */ - else -#endif - { -#if 0 /* This turns out not to be checked on the real machine */ - if (pp & (H10MASK<> 12) & 03; /* Find byte # in pattern word */ - - { - register acptr_t acp; - - acp = ac_map(ac_off(ac,3)); /* Get mark pointer and check it */ -#if 0 /* Not checked on real machine */ - if (op10m_tlnn(*acp, ILLEG_LHVABITS)) - return i_muuo(I_EXTEND, ac, e0); -#endif -#if KLH10_EXTADR - if (PC_ISEXT) { - va_gfrword(mark, *acp); - mark2 = mark; - va_ginc(mark2); - } else -#endif - { -#if 0 /* Not checked on real machine */ - if (LHGET(*acp)) /* Not extended, high bits not OK */ - return i_muuo(I_EXTEND, ac, e0); -#endif - va_lmake(mark, 0, RHGET(*acp)); -#if KLH10_EXTADR - mark2 = mark; - va_linc(mark2); -#endif - } - } - - XBPGET(&s1, ac, 1, BPSRC); /* Set up byte ptrs, may page-fail */ - XBPGET(&s2, ac, 4, BPDST); - - /* Start loop; leaves it only via goto! - ** Note we check for PI only when fetching a new command word - ** rather than after each command byte. This will delay any PI - ** by up to 3 edit commands but that should be okay. - */ - pword = vm_read(ppva); /* Set up pattern word, may page-fail */ - inc = 0; - for (;;) { - /* First increment pattern pointer and fetch command */ - ppbn += inc; - if (ppbn > 3) { - pp += (ppbn >> 2); /* Increment word ptr */ - va_add(ppva, (ppbn>>2)); - ppbn &= 03; /* Reset byte # */ - - /* Now check for events before doing next */ - CLOCKPOLL(); /* Keep clock going */ - if (INSBRKTEST()) { /* Watch for PI interrupt */ - res = RES_PI; - goto cleanup; - } - /* Fetch next word of 4 commands */ - if (!(vp = vm_xrwmap(ppva, VMF_READ|VMF_NOTRAP))) { - goto pf_presrc; /* Take pagefail exit */ - } - pword = vm_pget(vp); /* Get new pattern word */ - } - inc = 1; /* Reset to normal increment */ - switch (ppbn & 03) { - case 0: ent = LHGET(pword) >> 9; break; - case 1: ent = LHGET(pword) & 0777; break; - case 2: ent = RHGET(pword) >> 9; break; - case 3: ent = RHGET(pword) & 0777; break; - } - - /* Now decode pattern command */ - switch (ent & 0700) { - case EC_MESSAG: /* Insert fill-type char */ - va = e0; - if (flags & CVTF_S) - va_add(va, (ent&077)+1); /* Get E0+(ent&077)+1 */ - else - va_add(va, 1); /* Get E0+1 */ - vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP); - if (!vp) - goto pf_presrc; /* Take pagefail exit */ - wbyte = vm_pget(vp); - if ((flags & CVTF_S) || op10m_skipn(wbyte)) { - if (xidpb(&s2, &wbyte)) - goto pf2_presrc; /* No backup, take pagefail error */ - } - continue; - case EC_SKPM: /* Skip if M set */ - if (flags & CVTF_M) - inc = (ent & 077) + 2; /* Include PP+1 too */ - continue; - case EC_SKPN: /* Skip if N set */ - if (!(flags & CVTF_N)) - continue; /* Nope */ - /* N set, drop through to unconditional skip */ - case EC_SKPA: /* Skip next n+1 commands */ - inc = (ent & 077) + 2; /* Include PP+1 too */ - continue; - - /* Not a recognized class, check entire byte as command */ - default: switch (ent) { - case EC0_SELECT: /* Select Next source byte */ - break; /* Drop out - complex subcommand */ - case EC0_SIGST: - if (flags & CVTF_S) /* If S already set, */ - continue; /* treat as no-op */ - /* Do things in this sequence so if we page-fail nothing - ** has to be backed out of. - */ - va = e0; - va_add(va, 2); /* Get E0+2 */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) - goto pf_presrc; - wbyte = vm_pget(vp); /* Get "float char" */ - if (!(vp = vm_xrwmap(mark, VMF_WRITE|VMF_NOTRAP))) - goto pf_presrc; - - xbpupdate(&s2); /* Store dest BP back in AC+4 */ - vm_pset(vp, ac_get(ac_off(ac,4))); /* Also store at mark */ -#if KLH10_EXTADR - /* May need to set 2nd word of mark, if dest BP is 2-word */ - if (PC_ISEXT) { - if (vm_issafedouble(mark)) - vp++; - else if (!(vp = vm_xrwmap(mark2, VMF_WRITE|VMF_NOTRAP))) - goto pf_presrc; - vm_pset(vp, ac_get(ac_off(ac,5))); /* Store 2nd wd */ - } -#endif - if (op10m_skipn(wbyte)) { /* If float char non-zero, */ - if (xidpb(&s2, &wbyte)) /* try storing it */ - goto pf2_presrc; /* Fail, no backup */ - } - flags |= CVTF_S; /* OK to set flag now! */ - continue; - case EC0_FLDSEP: /* Separate fields */ - flags &= ~(CVTF_S|CVTF_M|CVTF_N); - continue; - case EC0_EXCHMD: /* Exchange Mark and Dest BP */ - /* Find length of dest BP, and assume mark is same - ** For now (non-extended), always assume 1 word. - ** This code can be improved! - */ - xbpupdate(&s2); /* Store dest BP back in AC+4 */ -#if KLH10_EXTADR - /* Gross hair to handle 2-word BPs */ - if (PC_ISEXT) { - vmptr_t vp2; - if (!(vp = vm_xrwmap(mark, VMF_WRITE|VMF_NOTRAP))) - goto pf_presrc; - if (vm_issafedouble(mark)) - vp2 = vp+1; - else if (!(vp2 = vm_xrwmap(mark2, VMF_WRITE|VMF_NOTRAP))) - goto pf_presrc; - wbyte = ac_get(ac_off(ac,5)); /* Save 2nd dst wd */ - ac_set(ac_off(ac,5), vm_pget(vp2)); /* Set 2nd dst wd */ - vm_pset(vp2, wbyte); /* Set 2nd mark wd */ - } else /* Do normal 1-word case */ -#endif - { - if (!(vp = vm_xrwmap(mark, VMF_WRITE|VMF_NOTRAP))) - goto pf_presrc; - } - - wbyte = ac_get(ac_off(ac,4)); /* Save 1st dst wd */ - ac_set(ac_off(ac,4), vm_pget(vp)); /* Set 1st dst wd */ - vm_pset(vp, wbyte); /* Set 1st mark wd */ - - /* Set up bp for internal use, fail if error result - ** (most likely MUUO for bogus OWGBP, if extended) - */ - if (res = xbpinit(&s2, ac_off(ac,4), BPDST)) { - /* Note: Not sure if this is correct behavior, since at - ** this point the AC has already been clobbered, and the - ** rest of the world is probably not in a very good - ** state either. Perhaps try to restore from saved BP? - */ - goto cleanup; - } - continue; - - default: - /* NOTE! Unrecognized pattern bytes are simply treated - ** as NOPs. - ** Fall through to handle like NOP. - */ - case EC0_NOP: - continue; - case EC0_STOP: /* Stop Edit */ - res = RES_WON; - if (++ppbn > 3) /* Increment PP one last time */ - ppbn = 0, ++pp, va_inc(ppva); - goto cleanup; - } - } - - /* Drop through to handle SELECT command - ** Because the source string BP is incremented here, any pagefail - ** after a successful xildb must jump to pf_postsrc instead - ** of pf_presrc. - */ - if (xildb(&s1, &wbyte)) { /* Get source byte */ - res = s1.err; /* oops */ - goto cleanup; /* no backup, not incremented yet */ - } - - /* Carry out translation-type subcommand */ - ent = RHGET(wbyte); - va = e1; - va_add(va, (ent>>1)); /* Get E1 + (ent>>1) */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) { - goto pf_postsrc; /* Page fail, back up source BP */ - } - - /* Do translation (similar to CVTDBT) */ - ent = (ent & 01) ? vm_pgetrh(vp) : vm_pgetlh(vp); - switch ((ent >> 15) & 07) { - case 2: - flags &= ~CVTF_M; - if (1) ; /* Hack to skip over next stmt */ - else { - case 3: - flags |= CVTF_M; - } - case 0: - if (flags & CVTF_S) - LRHSET(wbyte, 0, ent & 07777); /* Set up translated byte */ - else { /* Get fill byte, check it */ - va = e0; - va_inc(va); /* Get E0+1 */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) - goto pf_postsrc; - wbyte = vm_pget(vp); - if (!op10m_skipn(wbyte)) /* If fill byte zero, */ - continue; /* do nothing */ - } - if (xidpb(&s2, &wbyte)) /* Try storing it */ - goto pf2_postsrc; /* Ugh, back out and fail */ - continue; - - case 5: - flags |= CVTF_N; - /* Drop thru to terminate edit */ - case 1: - res = RES_TRUNC; - if (++ppbn > 3) /* Increment PP one last time */ - ppbn = 0, ++pp, va_inc(ppva); - goto cleanup; - - case 6: - flags &= ~CVTF_M; - if (1) ; /* Hack to skip over next stmt */ - else { - case 7: - flags |= CVTF_M; - } - case 4: - flags |= CVTF_N; - if (!(flags & CVTF_S)) { - /* These are exactly the same actions as SIGST!! */ - /* Do things in this sequence so if we page-fail nothing - ** (other than source BP) has to be backed out of. - */ - va = e0; - va_add(va, 2); /* Get E0+2 */ - if (!(vp = vm_xrwmap(va, VMF_READ|VMF_NOTRAP))) - goto pf_postsrc; - wbyte = vm_pget(vp); /* Get "float char" */ - if (!(vp = vm_xrwmap(mark, VMF_WRITE|VMF_NOTRAP))) - goto pf_postsrc; - - xbpupdate(&s2); /* Store dest BP back in AC+4 */ - vm_pset(vp, ac_get(ac_off(ac,4))); /* Also store at mark */ -#if KLH10_EXTADR - /* May need to set 2nd word of mark, if dest BP is 2-word */ - if (PC_ISEXT) { - if (vm_issafedouble(mark)) - vp++; - else if (!(vp = vm_xrwmap(mark2, VMF_WRITE|VMF_NOTRAP))) - goto pf_postsrc; - vm_pset(vp, ac_get(ac_off(ac,5))); /* Store 2nd wd */ - } -#endif - if (op10m_skipn(wbyte)) { /* If float char non-zero, */ - if (xidpb(&s2, &wbyte)) /* try storing it */ - goto pf2_postsrc; /* No backup needed. */ - } - flags |= CVTF_S; /* OK to set flag now! */ - } - LRHSET(wbyte, 0, ent & 07777); /* Set up translated byte */ - if (xidpb(&s2, &wbyte)) /* Try storing it */ - goto pf2_postsrc; - continue; - } - /* Should never come here */ - } - - /* Common return points for pagefails. Control never drops or breaks - ** out of main loop except with gotos. - */ -pf2_postsrc: - xdecbp(&s1); /* Back up source bp */ -pf2_presrc: - res = s2.err; /* Get specific error result from S2 ref */ - goto cleanup; - -pf_postsrc: - xdecbp(&s1); /* Back up source bp */ -pf_presrc: /* No backup needed */ - res = RES_PF; - -cleanup: - /* Done, update ACs and return appropriate PC increment - */ - ac_setlrh(ac, flags | ((uint18)ppbn << 12) | (pp>>H10BITS), pp & H10MASK); - xbpupdate(&s1); /* Set AC+1, AC+2 */ - /* AC+3: Mark address is never changed, so needn't store it back */ - xbpupdate(&s2); /* Set AC+4, AC+5 */ - - switch (res) { - case RES_MUUO: return i_muuo(I_EXTEND, ac, e0); - case RES_PF: pag_fail(); /* Never returns */ - case RES_PI: apr_int(); /* Never returns */ - case RES_WON: return PCINC_2; /* Skips if source exhausted */ - default: - case RES_TRUNC: return PCINC_1; - } -} - -#endif /* T10 || T20 */ diff --git a/src/injrst.c.old b/src/injrst.c.old deleted file mode 100644 index cab675e..0000000 --- a/src/injrst.c.old +++ /dev/null @@ -1,760 +0,0 @@ -/* INJRST.C - Jump (and Stack) instruction routines -*/ -/* $Id: injrst.c,v 2.4 2002/03/21 09:50:55 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: injrst.c,v $ - * Revision 2.4 2002/03/21 09:50:55 klh - * Fixed refs of fe_debug to use mr_debug - * - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - - -/* See CODING.TXT for guidelines to coding instruction routines. */ - -#include "klh10.h" -#include "kn10def.h" -#include "kn10ops.h" -#include /* For debug output */ - -#ifdef RCSID - RCSID(injrst_c,"$Id: injrst.c,v 2.4 2002/03/21 09:50:55 klh Exp $") -#endif - -/* Imported functions */ - -extern void pishow(FILE *); -extern void pcfshow(FILE *, h10_t flags); - - - -insdef(i_jffo) /* JFFO */ -{ - register int i = op10ffo(ac_get(ac)); - if (i < 36) { /* Found a bit? */ - ac_setlrh(ac_off(ac,1), 0, i); /* Yep, set AC+1 */ - PC_JUMP(e); /* and take the jump! */ - return PCINC_0; - } - ac_setlrh(ac_off(ac,1), 0, 0); /* Empty, don't jump */ - return PCINC_1; -} - -insdef(i_jfcl) -{ - if (ac) { /* See which flags we're asking for */ - register h10_t flags; - - flags = (h10_t)ac << (18-4); /* Shift to match PC flags */ - if (PCFTEST(flags)) { /* Any of them match? */ - PCFCLEAR(flags); /* Yes, clear them */ - PC_JUMP(e); /* and take the jump! */ - return PCINC_0; - } - } - return PCINC_1; -} - - -insdef(i_jsr) /* JSR */ -{ - register w10_t w; - - PC_1WORD(w); /* Make PC-word in w (PC+1, plus flags if sect 0) */ - vm_write(e, w); /* Store it at E */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */ - va_inc(e); /* Jump to E+1 (local or global) */ - PC_JUMP(e); - return PCINC_0; -} - -insdef(i_jsp) /* JSP */ -{ - register w10_t w; - - PC_1WORD(w); /* Cons up PC+1 word in w */ - ac_set(ac, w); /* Store it in AC */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */ - PC_JUMP(e); /* Jump to E */ - return PCINC_0; -} - -/* Note for JSA and JRA that there is no difference in their behavior -** when executed in non-zero sections. -*/ -insdef(i_jsa) /* JSA */ -{ - register w10_t w; - - vm_write(e, ac_get(ac)); /* Store c(AC) into E */ - PC_XWDPC1(w, va_insect(e)); /* Cons up word: ,, */ - ac_set(ac, w); /* Store that JSA-word in AC */ - va_inc(e); /* Jump to E+1 */ - PC_JUMP(e); - return PCINC_0; -} - -insdef(i_jra) /* JRA */ -{ - register vaddr_t va; - - va_lmake(va, PC_SECT,ac_getlh(ac)); /* Make AC.lh a local address */ - ac_set(ac, vm_read(va)); /* Get c(AC.lh) into AC */ - PC_JUMP(e); /* Jump to E */ - return PCINC_0; -} - -/* JRST hackery */ - -/* Declare subvariants of JRST */ -pcinc_t ij_jrstf (int, int, vaddr_t); -pcinc_t ij_halt (int, int, vaddr_t); -pcinc_t ij_jen (int, int, vaddr_t); -pcinc_t ij_jrst10(int, int, vaddr_t); -#if !KLH10_SYS_ITS -pcinc_t ij_portal(int, int, vaddr_t); -pcinc_t ij_xjrstf(int, int, vaddr_t); -pcinc_t ij_xjen (int, int, vaddr_t); -pcinc_t ij_xpcw (int, int, vaddr_t); -pcinc_t ij_sfm (int, int, vaddr_t); -#endif -#if KLH10_CPU_KLX -pcinc_t ij_xjrst (int, int, vaddr_t); -#endif - - -insdef(i_jrst) -{ - switch (ac) { - case 0: /* JRST */ - PC_JUMP(e); - return PCINC_0; - -#if !KLH10_SYS_ITS - case 1: return ij_portal(op, ac, e); /* PORTAL - not used by ITS */ -#endif /* DEC */ - case 2: return ij_jrstf(op, ac, e); /* JRSTF - Used */ - case 4: return ij_halt(op, ac, e); /* HALT - Used */ -#if !KLH10_SYS_ITS && (KLH10_CPU_KS||KLH10_CPU_KLX) - case 5: return ij_xjrstf(op, ac, e); /* XJRSTF - not used by ITS */ - case 6: return ij_xjen(op, ac, e); /* XJEN - not used by ITS */ - case 7: return ij_xpcw(op, ac, e); /* XPCW - not used by ITS */ -#endif /* DEC KS || KLX */ - case 010: return ij_jrst10(op, ac, e); /* JRST 10, - used once (?) */ - case 012: return ij_jen(op, ac, e); /* JEN - used frequently */ -#if !KLH10_SYS_ITS && (KLH10_CPU_KS||KLH10_CPU_KLX) - case 014: return ij_sfm(op, ac, e); /* SFM - not used by ITS */ -# if KLH10_CPU_KLX - case 015: return ij_xjrst(op, ac, e); /* XJRST - not used by ITS */ -# endif /* KLX */ -#endif /* DEC */ -#if KLH10_SYS_ITS - case 017: break; /* - used once by KL10 ITS */ -#endif - } - /* Illegal - MUUO (3,11,13,16,17) */ - return i_muuo(op, ac, e); -} - - -/* DORSTF - Actually carry out flag restoration for JRSTF/XJRSTF/XJEN/XPCW. -** Restore flags from the top 12 bits of the word in w. -** -** All flags are restored verbatim with these exceptions: -** USER cannot be cleared by a new setting of 0 (no effect), although -** a 1 will always set it. -** UIO can always be cleared, but new setting of 1 will only have -** an effect if the old mode is EXEC. (Note that if old -** mode is user, 1 merely has no effect; the bit may already -** be set and will remain so.) -** PUBLIC can always be set by a 1, but a 0 only has effect if -** old mode is EXEC and new mode is USER. -** -** No special actions are taken for PrevCtxtPublic or PrevCtxtUser. -** -** The wording of the DEC PRM (6/82 p.2-71) is a little misleading, as it -** implies that bit 6 (User-IO) cannot be set to 1 while in user mode; however, -** it appears in reality that it *can* be, if it was *already* 1. -** This is a rather subtle point. -*/ - /* LH(w) contains flags to restore */ -#if KLH10_EXTADR -static pcinc_t dorstf(register w10_t w, vaddr_t e, int pcsf) -# define IJ_DO_RSTF(w, e, pcsf) dorstf(w, e, pcsf) -#else -static pcinc_t dorstf(register w10_t w, vaddr_t e) -# define IJ_DO_RSTF(w, e, pcsf) dorstf(w, e) -#endif -{ - register uint18 newf; /* New flags to restore */ - -#if KLH10_DEBUG - if (cpu.mr_debug) { - putc('[', stderr); - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); -#if KLH10_EXTADR - if (pcsf) fprintf(stderr, "(PCS:%o)", pag_pcsget()); -#endif - fprintf(stderr,"%lo: -> ", (long) PC_30); - } -#endif - newf = LHGET(w); /* Get flags into easy-access reg */ - - if (PCFTEST(PCF_USR)) { /* Currently in user mode? */ - newf |= PCF_USR; /* Never permit USR clearing */ - if (!PCFTEST(PCF_UIO)) /* If not already in UIO, */ - newf &= ~PCF_UIO; /* don't permit UIO setting */ - } -#if KLH10_CPU_KL || KLH10_CPU_KI - if (PCFTEST(PCF_PUB) /* If trying to clear Public, */ - && (newf & PCF_PUB)==0) { /* Must be EXEC, setting USER too. */ - if (PCFTEST(PCF_USR) || !(newf&PCF_USR)) - newf |= PCF_PUB; /* Nope, don't clear it */ - } -#endif /* KL || KI */ - - /* For XJRSTF/XJEN, a new PCS is loaded from the flag word only if - ** the new flags specify EXEC mode. - ** (PRM 2-66, 2nd sentence from bottom). - */ -#if KLH10_EXTADR /* If going into EXEC mode, restore PCS */ - if (pcsf && !(newf & PCF_USR)) { - pag_pcsset(RHGET(w) & UBR_PCS); /* For now, ignore too-big PCS */ - } -#endif - - cpu.mr_pcflags = newf & PCF_MASK; /* Set new flags!! */ - PC_JUMP(e); /* Take the jump... */ - apr_pcfcheck(); /* Check flags for any changes. */ - /* NOTE! It is important to check AFTER the PC has changed, so that - ** if there is a user/exec context change, the saved JPC will be the - ** appropriate one for the previous context. - */ -#if KLH10_DEBUG - if (cpu.mr_debug) { - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); -#if KLH10_EXTADR - if (pcsf) fprintf(stderr, "(PCS:%o)", pag_pcsget()); -#endif - fprintf(stderr,"%lo:]\r\n", (long) PC_30); - } -#endif - return PCINC_0; -} - -#if !KLH10_SYS_ITS -/* PORTAL (JRST 1,) - Clear Public and jump to E -** On KS10, equivalent to JRST. -*/ -insdef(ij_portal) -{ -#if KLH10_CPU_KI || KLH10_CPU_KL - PCFCLEAR(PCF_PUB); /* Always clear public, nothing else needed */ -#endif - PC_JUMP(e); - return PCINC_0; -} -#endif /* !KLH10_SYS_ITS */ - -/* JRSTF (JRST 2,)- Jump and Restore Flags from final word used in calc of E. -** -** Because this word isn't saved by the normal instruction loop, -** it needs to be recomputed. This is painful, but I judged that -** it was better to make JRSTF slower so that every other instruction could -** be slightly faster. -** -** The "mr_injrstf" flag is set solely so any page faults which occur can -** avoid being faked out. No faults should in fact happen at this point; -** if any do there is a horrible error somewhere. -*/ - -insdef(ij_jrstf) -{ - register w10_t w; - register vaddr_t ea; -#if KLH10_EXTADR - if (PC_ISEXT) /* A JRSTF in non-zero section is a MUUO */ - return i_muuo(op, ac, e); -#endif - cpu.mr_injrstf = TRUE; - - /* Assume that our execution started at mr_PC. This will be untrue - ** only if we're being executed as a trap or interrupt instruction. - ** XCT is allowed, but PXCT is fortunately illegal. - */ - ea = PC_VADDR; /* Get PC as a virtual address */ - for (;;) { - w = vm_fetch(ea); /* Get instr */ - if (iw_op(w) != I_XCT) - break; - ea = ea_calc(w); /* Is XCT, track chain */ - } - if (iw_op(w) != op /* Must match original instr */ - || iw_ac(w) != ac) /* both in OP and AC */ - panic("ij_jrstf: cannot duplicate op"); - - /* Now get to the point of this stupid exercise! */ - w = ea_wcalc(w, cpu.acblk.xea, cpu.vmap.xea); /* Do full EA calc */ - if (RHGET(w) != va_insect(e)) /* One more check... */ - panic("ij_jrstf: cannot duplicate E"); - cpu.mr_injrstf = FALSE; /* No more pagefault risk */ - return IJ_DO_RSTF(w, e, FALSE); -} - -/* JEN (JRST 12,) - Combination of JRST10 and JRSTF. -** Lets those routines do the work. JRSTF's hack to find the PC flags -** will work, because the opcode & AC are all passed along to it. -** If user mode, only legal if User-IOT is set. -*/ -insdef(ij_jen) -{ -#if KLH10_EXTADR - if (PC_ISEXT) - return i_muuo(op, ac, e); -#endif -#if KLH10_CPU_KS || KLH10_CPU_KA - if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) -#elif KLH10_CPU_KL - if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */ - || (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB))) -#elif KLH10_CPU_KI - if (PCFTEST(PCF_USR | PCF_PUB)) /* Kernel mode only */ -#endif - return i_muuo(op, ac, e); - pi_dismiss(); /* Tell PI to dismiss current int */ - return ij_jrstf(op, ac, e); -} - -/* JRST 10, - Dismisses current interrupt ("restores the level on which the -** highest priority interrupt is currently being held"). -** If user mode, only legal if User-IOT is set. -*/ -insdef(ij_jrst10) -{ -#if KLH10_CPU_KS || KLH10_CPU_KA - if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Exec */ -#elif KLH10_CPU_KL - if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */ - || (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB))) -#elif KLH10_CPU_KI - if (PCFTEST(PCF_USR | PCF_PUB)) /* Kernel mode only */ -#endif - return i_muuo(op, ac, e); - - pi_dismiss(); /* Tell PI to dismiss current int */ - PC_JUMP(e); /* Take the jump... */ - -#if KLH10_DEBUG - if (cpu.mr_debug) { - fprintf(stderr,"[ -> "); - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); - fprintf(stderr,"%lo:]\r\n", (long) PC_30); - } -#endif - return PCINC_0; -} - -/* HALT (JRST 4,) - Halt the processor. -*/ -insdef(ij_halt) -{ -#if KLH10_CPU_KS || KLH10_CPU_KA - if (!PCFTEST(PCF_USR)) /* Exec mode can halt */ -#elif KLH10_CPU_KL || KLH10_CPU_KI - if (!PCFTEST(PCF_USR|PCF_PUB)) /* Only Kernel mode can halt */ -#endif - { - cpu.mr_haltpc = cpu.mr_PC; /* Remember loc of the HALT instr */ - PC_JUMP(e); /* Update PC as if jumped */ - apr_halt(HALT_PROG); /* Halt processor! */ - /* Never returns */ - } - return i_muuo(op, ac, e); -} - -/* DEC extended variants of JRST, never used on ITS or a single-section KL */ - -#if !KLH10_SYS_ITS && (KLH10_CPU_KS||KLH10_CPU_KLX) - -/* XJRSTF (JRST 5,) -** Pretty much the same as JRSTF except the flags and PC come from -** a pair of memory locations. On the KS10 no section addressing -** is possible (wonder what happens if tried on a real KS10?) -** -** XJRSTF and XJEN don't save anything. -** A new PCS is loaded from the flag word only if a KLX and the new -** flags specify exec mode (PRM 2-66, 2nd sentence from bottom). -** The new flags are used verbatim, except for the same restrictions -** as JRSTF (that is, USER, UIO, PUBLIC flags are special-cased). -** (PRM 2-71) -** See dorstf() for more comments. -*/ -insdef(ij_xjrstf) -{ - register dw10_t dpcw; - - vm_dread(e, dpcw); /* Fetch double-wd from E, E+1 (may pageflt) */ - va_lfrword(e, LOGET(dpcw)); /* New PC from c(E+1) */ - return IJ_DO_RSTF(HIGET(dpcw), e, TRUE); /* Use flags from c(E) */ -} - -/* XJEN (JRST 6,) -** See comments for XJRSTF -- essentially the same. -** To XJRSTF as JEN is to JRSTF, but only allowed in Exec mode. -** However, one special precaution is taken; the PCW at E, E+1 is fetched -** prior to restoring an interrupt level, to ensure any page fault -** happens before clobbering the PI status! -** This is why the XJRSTF code is duplicated, rather than calling -** it after dismissing the interrupt. -*/ -insdef(ij_xjen) -{ - register dw10_t dpcw; - -#if KLH10_CPU_KS - if (PCFTEST(PCF_USR)) /* Ensure we're in exec mode */ -#elif KLH10_CPU_KLX - if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */ - || (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB))) -#endif - return i_muuo(op, ac, e); - - vm_dread(e, dpcw); /* Fetch double-wd from E, E+1 (may pageflt) */ - pi_dismiss(); /* Tell PI to dismiss current int */ - va_lfrword(e, LOGET(dpcw)); /* New PC from E+1 */ - return IJ_DO_RSTF(HIGET(dpcw), e, TRUE); /* Use flags from E */ -} - -/* XPCW (JRST 7,) -** Note special precaution as for XJEN to ensure any page faults happen -** prior to changing flags or PC. -** -** PCS is saved in the flag word ONLY if old mode was exec (the flag -** test is on old flags, not new ones). -** No new PCS is set. -** The new flags are taken from the new flag word, subject to -** same restrictions as JRSTF. It doesn't appear that -** either PCP or PCU is specially set. -** PRM says XPCW should only be used as interrupt instr, but T20 -** monitor does use it as regular instr (in SCHED). -** This code only implements its "regular" behavior; the KLH10 -** PI interrupt code special-cases XPCW itself and never calls -** this routine. -*/ -insdef(ij_xpcw) -{ - register w10_t w; - register vaddr_t e2; - dw10_t dpcw; - -#if KLH10_CPU_KS - if (PCFTEST(PCF_USR)) /* Ensure we're in exec mode */ -#elif KLH10_CPU_KLX - if ((PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* User-IOT or Kernel */ - || (!PCFTEST(PCF_USR) && PCFTEST(PCF_PUB))) -#endif - return i_muuo(op, ac, e); - - e2 = e; - va_add(e2, 2); /* Get E+2 */ - vm_dread(e2, dpcw); /* Fetch double from E+2, E+3 (may pageflt) */ - - LRHSET(w, cpu.mr_pcflags, 0); /* Set up 1st word of PCW */ -#if KLH10_EXTADR - if (!PCFTEST(PCF_USR)) /* If in exec mode */ - RHSET(w, pag_pcsget()); /* then OK to add pager's PrevContextSection */ -#endif - vm_write(e, w); /* Store in E */ - PC_1TOWORD(w); /* Set up PC+1 word */ - va_inc(e); - vm_write(e, w); /* Store in E+1 */ - - va_lfrword(e2, LOGET(dpcw)); /* New PC from E+3 */ - return IJ_DO_RSTF(HIGET(dpcw), e2, FALSE); /* Use flags from E+2 */ -} - -/* SFM (JRST 14,) -** This is now legal in user mode, but the PCS info is only stored if in -** exec mode. (PRM 2-72) -** Additionally, PRM 2-73 says on an extended KL, SFM is only legal in -** NZ section. However, this was changed as of KL ucode 331 to -** allow 0-section as well, and there is no IO-legal test; -** PCS is still only saved if in exec mode, though. -*/ -insdef(ij_sfm) -{ - register w10_t w; - -#if KLH10_CPU_KS /* KS10 requires exec mode (kernel) */ - if (PCFTEST(PCF_USR)) /* Ensure we're in exec mode */ - return i_muuo(op, ac, e); -#endif - - /* Don't need to mung flags since not changing modes */ - LRHSET(w, cpu.mr_pcflags, 0); /* Set up 1st word of PCW */ -#if KLH10_EXTADR - if (!PCFTEST(PCF_USR)) /* If in exec mode, */ - RHSET(w, pag_pcsget()); /* add PCS to the flag word */ -#endif - vm_write(e, w); /* Store in E */ - return PCINC_1; /* That's all, no jump! */ -} - -#if KLH10_CPU_KLX - -/* XJRST (JRST 15,) -** This is yet another late addition to the KL that was never -** documented in the PRM. It seems to have been added as of ucode -** 301 and is used extensively in the T20 monitor. -** Basically appears to jump to c(E) rather than E, treating -** the contents of E as a full 30-bit global virtual address. It's -** not clear whether the high 6 bits matter, but I'll assume they are -** ignored. -** This also appears to be legal in any section, in any mode. -** Not a bad idea, actually. -*/ - -insdef(ij_xjrst) -{ - register w10_t w; - register vaddr_t va; - - w = vm_read(e); /* Fetch c(E) */ - va_gfrword(va, w); /* Turn into a virtual address */ - PC_JUMP(va); /* Jump there! */ - return PCINC_0; -} -#endif /* KLX */ - -#endif /* !ITS && (KS || KLX) */ - -/* Stack instructions */ - -/* Note: on the KA10 the push and pop operations are done by -** adding or subtracting 1,,1 as a word entity (ie not independent halves). -** Also, there are no trap flags, so Pushdown Overflow is set instead. -** These actions are not yet coded for, to avoid clutter. -*/ - -/* Note special page map context references for stack instructions. -** These are so PXCT can work by twiddling the context pointers. -** For: -** Computing E - normal ea_calc() using XEA map -** R/W of c(E) for PUSH, POP - normal XRW map -** R/W of stack data - special XBRW map -*/ -#define vm_stkread(a) (vm_pget(vm_xbrwmap((a), VMF_READ))) -#define vm_stkwrite(a, w) (vm_pset(vm_xbrwmap((a), VMF_WRITE), (w))) -#define vm_stkmap(a, f) vm_xbrwmap((a), (f)) - -/* No other special actions are needed for PXCT; the test for running -** extended is always made using PC section (regardless of context). -** However, on an extended KL Uhler claims stack references should -** always be made in the current context. What isn't clear is whether -** a KLX is expected to ignore the stack-context AC bit (12), or if it -** does undefined things as a result. -** For generality this code does implement stack reference mapping even -** on a KLX, which corresponds to the latter option. As long as the -** monitor only uses valid AC bit combinations we'll be fine. -** -** HOWEVER - it appears from the DFKED diagnostic that bit 12 DOES -** operate in a real KL and it affects both the test for PC section AND the -** mapping used for the stack pointer. Ugh!!!! -** Don't know yet whether it is used by a real monitor. -*/ - -insdef(i_push) -{ - register w10_t w; - register vaddr_t sloc; - - w = ac_get(ac); - -#if KLH10_EXTADR - /* Determine if stack pointer is local or global */ - if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) { - /* Global format */ - op10m_inc(w); /* Increment entire word */ - va_gfrword(sloc, w); /* Get global addr from wd */ - vm_stkwrite(sloc, vm_read(e)); /* Push c(E) on stack */ - } else -#endif - { - /* Local format */ - RHSET(w, (RHGET(w)+1)&H10MASK); /* Increment RH only */ - va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */ - vm_stkwrite(sloc, vm_read(e)); /* Push c(E) on stack */ - - /* All mem refs won, safe to store AC and test for setting Trap 2 */ - LHSET(w, (LHGET(w)+1)&H10MASK); /* Increment LH */ - if (LHGET(w) == 0) /* If became 0, */ - PCFTRAPSET(PCF_TR2); /* set Trap 2! */ - } - ac_set(ac, w); - return PCINC_1; -} - -insdef(i_pushj) -{ - register w10_t pcw, w; - register vaddr_t sloc; - - - w = ac_get(ac); - PC_1WORD(pcw); /* Make PC+1 word */ - -#if KLH10_EXTADR - - /* Determine if stack pointer is local or global */ - if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) { - /* Global format */ - op10m_inc(w); /* Increment entire word */ - va_gfrword(sloc, w); /* Get global addr from wd */ - vm_stkwrite(sloc, pcw); /* Push PC word on stack */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */ - } else -#endif - { - /* Local format */ - RHSET(w, (RHGET(w)+1)&H10MASK); /* Increment RH only */ - va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */ - vm_stkwrite(sloc, pcw); /* Push PC word on stack */ - - /* All mem refs won, safe to store AC and test for setting Trap 2 */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear these flags */ - LHSET(w, (LHGET(w)+1)&H10MASK); /* Increment LH */ - if (LHGET(w) == 0) /* If became 0, */ - PCFTRAPSET(PCF_TR2); /* set Trap 2! */ - } - ac_set(ac, w); - PC_JUMP(e); /* Jump to new PC */ - return PCINC_0; -} - - -insdef(i_pop) -{ - register w10_t w; - register vaddr_t sloc; - - w = ac_get(ac); - -#if KLH10_EXTADR - /* Determine if stack pointer is local or global */ - if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) { - /* Global format */ - va_gfrword(sloc, w); /* Get global addr from wd */ - vm_write(e, vm_stkread(sloc)); /* Pop stack to c(E) */ - op10m_dec(w); /* Decrement entire word */ - - } else -#endif - { - /* Local format */ - va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */ - vm_write(e, vm_stkread(sloc)); /* Pop stack to c(E) */ - - /* All mem refs won, safe to store AC and test for setting Trap 2 */ - RHSET(w, (RHGET(w)-1)&H10MASK); /* Decrement RH only */ - if (LHGET(w) == 0) { /* If decrement will wrap, */ - PCFTRAPSET(PCF_TR2); /* set Trap 2! */ - LHSET(w, H10MASK); - } else - LHSET(w, LHGET(w)-1); /* Decr LH, no mask needed */ - } - ac_set(ac, w); - return PCINC_1; -} - -insdef(i_popj) -{ - register w10_t pcw, w; - register vaddr_t sloc; - - w = ac_get(ac); - -#if KLH10_EXTADR - /* Determine if stack pointer is local or global */ - if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) { - /* Global format */ - va_gfrword(sloc, w); /* Get global addr from wd */ - pcw = vm_stkread(sloc); /* Pop PC word off stack */ - op10m_dec(w); /* Decrement entire word */ - } else -#endif - { - /* Local format */ - va_lmake(sloc, PC_SECT, RHGET(w)); /* Get local address */ - pcw = vm_stkread(sloc); /* Pop PC word off stack */ - - /* All mem refs won, safe to store AC and test for setting Trap 2 */ - RHSET(w, (RHGET(w)-1)&H10MASK); /* Decrement RH only */ - if (LHGET(w) == 0) { /* If decrement will wrap, */ - PCFTRAPSET(PCF_TR2); /* set Trap 2! */ - LHSET(w, H10MASK); - } else - LHSET(w, LHGET(w)-1); /* Decr LH, no mask needed */ - } - - /* Build correct new PC from PC word popped off */ - if (PC_ISEXT) - va_lfrword(e, pcw); - else va_lmake(e, PC_SECT, RHGET(pcw)); - - ac_set(ac, w); - PC_JUMP(e); /* Now jump to restored PC */ - return PCINC_0; -} - - -insdef(i_adjsp) -{ - register w10_t w; - register h10_t h; - - w = ac_get(ac); /* Get stack pointer */ -#if KLH10_EXTADR - /* Determine if stack pointer is local or global */ - if (PC_ISEXT && op10m_skipge(w) && op10m_tlnn(w, VAF_SMSK)) { - /* Global format */ - if (H10SIGN & va_insect(e)) { /* Negative adjustment? */ - register w10_t wadj; - LRHSET(wadj, H10MASK, va_insect(e)); /* Set up word */ - op10m_add(w, wadj); /* Add negative adj */ - } else - op10m_addi(w, va_insect(e)); /* Can just add immediately */ - } else -#endif - { - /* Local format */ - register h10_t adj = va_insect(e); - RHSET(w, (RHGET(w)+adj)&H10MASK); /* Add offset to RH */ - if ((h = LHGET(w)+adj) & H10SIGN) { /* New count negative? */ - if ((adj & H10SIGN) && (LHGET(w) & H10SIGN)==0) - PCFTRAPSET(PCF_TR2); /* Neg E made cnt pos -> neg */ - } else { /* New count positive */ - if ((adj & H10SIGN)==0 && (LHGET(w) & H10SIGN)) - PCFTRAPSET(PCF_TR2); /* Pos E made cnt neg -> pos */ - } - LHSET(w, (h & H10MASK)); /* Store new count */ - } - ac_set(ac, w); - return PCINC_1; -} - diff --git a/src/inmove.c.old b/src/inmove.c.old deleted file mode 100644 index af22fda..0000000 --- a/src/inmove.c.old +++ /dev/null @@ -1,718 +0,0 @@ -/* INMOVE.C - Word move instruction routines -*/ -/* $Id: inmove.c,v 2.3 2001/11/10 21:28:59 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: inmove.c,v $ - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#include "klh10.h" -#include "kn10def.h" /* Machine defs */ -#include "kn10ops.h" /* PDP-10 ops */ - -#ifdef RCSID - RCSID(inmove_c,"$Id: inmove.c,v 2.3 2001/11/10 21:28:59 klh Exp $") -#endif - -/* See CODING.TXT for guidelines to coding instruction routines. */ - - -/* Full-word data stuff */ - -insdef(i_exch) /* EXCH AC,E */ -{ - register vmptr_t p = vm_modmap(e); /* Check access, get pointer */ - register w10_t w; - w = vm_pget(p); /* Save mem in temporary loc */ - vm_pset(p, ac_get(ac)); /* Move c(AC) to E */ - ac_set(ac, w); /* Move c(E) to AC */ - return PCINC_1; -} - - -/* MOVEx group - MOVE, MOVEI, MOVEM, MOVES */ - -insdef(i_move) /* MOVE AC,E */ -{ - ac_set(ac, vm_read(e)); - return PCINC_1; -} - -insdef(i_movei) /* MOVEI AC,E */ -{ - ac_setlrh(ac, 0, va_insect(e)); - return PCINC_1; -} - -insdef(i_movem) /* MOVEM AC,E */ -{ - vm_write(e, ac_get(ac)); - return PCINC_1; -} - -insdef(i_moves) /* MOVES AC,E */ -{ - register vmptr_t p = vm_modmap(e); /* Make write access ref */ - if (ac) ac_set(ac, vm_pget(p)); - return PCINC_1; -} - - -/* MOVSx group - MOVS, MOVSI, MOVSM, MOVSS */ - -insdef(i_movs) /* MOVS AC,E */ -{ - register w10_t w; - w = vm_read(e); - ac_setlrh(ac, RHGET(w), LHGET(w)); - return PCINC_1; -} - -insdef(i_movsi) /* MOVSI AC,E */ -{ - ac_setlrh(ac, va_insect(e), 0); - return PCINC_1; -} - -insdef(i_movsm) /* MOVSM AC,E */ -{ - register w10_t w; - LRHSET(w, ac_getrh(ac), ac_getlh(ac)); - vm_write(e, w); - return PCINC_1; -} - -insdef(i_movss) /* MOVSS AC,E */ -{ - register vmptr_t p = vm_modmap(e); /* Make R/W access ref */ - register w10_t w; - LRHSET(w, vm_pgetrh(p), vm_pgetlh(p)); - vm_pset(p, w); /* Store back in mem */ - if (ac) ac_set(ac, w); - return PCINC_1; -} - - -/* MOVNx group - MOVN, MOVNI, MOVNM, MOVNS */ - -insdef(i_movn) /* MOVN AC,E */ -{ - register w10_t w; - w = vm_read(e); - op10mf_movn(w); /* Negate, setting flags if necessary */ - ac_set(ac, w); - return PCINC_1; -} - -insdef(i_movni) /* MOVNI AC,E */ -{ - register w10_t w; - LRHSET(w, 0, va_insect(e)); - op10mf_movn(w); /* Negate, setting flags if 0 */ - ac_set(ac, w); - return PCINC_1; -} - -insdef(i_movnm) /* MOVNM AC,E */ -{ - register vmptr_t p = vm_wrtmap(e); /* Check mem ref first */ - register w10_t w; - w = ac_get(ac); - op10mf_movn(w); /* Negate, setting flags if necessary */ - vm_pset(p, w); - return PCINC_1; -} - -insdef(i_movns) /* MOVNS AC,E */ -{ - register vmptr_t p = vm_modmap(e); /* Check mem ref first */ - register w10_t w; - w = vm_pget(p); - op10mf_movn(w); /* Negate, setting flags if necessary */ - vm_pset(p, w); - if (ac) ac_set(ac, w); - return PCINC_1; -} - - -/* MOVMx group - MOVM, MOVMI, MOVMM, MOVMS */ - -insdef(i_movm) /* MOVM AC,E */ -{ - register w10_t w; - w = vm_read(e); - op10mf_movm(w); /* Make pos, setting flags if necessary */ - ac_set(ac, w); - return PCINC_1; -} - -#if 0 -insdef(i_movmi) /* MOVMI AC,E is identical to MOVEI AC,E */ -#endif - -insdef(i_movmm) /* MOVMM AC,E */ -{ - register vmptr_t p = vm_wrtmap(e); /* Check mem ref first */ - register w10_t w; - w = ac_get(ac); - op10mf_movm(w); /* Make pos, setting flags if necessary */ - vm_pset(p, w); - return PCINC_1; -} - -insdef(i_movms) /* MOVMS AC,E */ -{ - register vmptr_t p = vm_modmap(e); /* Check mem ref first */ - register w10_t w; - w = vm_pget(p); - op10mf_movm(w); /* Make pos, setting flags if necessary */ - vm_pset(p, w); - if (ac) ac_set(ac, w); - return PCINC_1; -} - -/* Double-word data move instructions. -** DMOVE and DMOVEM are handled differently from the other instructions -** that manipulate double words, for greater efficiency. -** -** There is a large fuzzy gray area surrounding the question of page fails -** for double-word operands. In general the KLH10 tries not to do anything -** at all if a page fail would happen on either the first or second word, -** thus avoiding the issue of intermediate results. -** -** BUT! Examination of the ucode indicates otherwise: -** KL DMOVE/DMOVN: Atomic; both words are fetched before any ACs are set. -** A pagefail on read of 2nd word leaves no ACs changed. -** KL DMOVEM/DMOVNM: First gets both ACs, then stores. -** 1st (high) word is stored, then 2nd (low); -** A pagefail on write of 2nd word leaves 1st already stored. -** -** KS DMOVE/DMOVN: same as KL. -** KS DMOVEM/DMOVNM: 2nd word is stored, then 1st!? -** -** The KL diag (DFKEA) agrees with the KL for DMOVE and DMOVEM (DMOVN/M is -** not tested). -** -** Given this discrepancy, the KLH10's approach isn't so bad. But just to -** be ultra safe, I'll attempt to emulate the KS/KL lossage. -*/ - -/* DMOVE checks to see if the double can be copied directly into the -** ACs. If not, intermediate storage must be used to allow for the -** possibility of a page fault between words, or AC/address wraparound, or -** AC overlap if mem ref is to ACs. -*/ - -insdef(i_dmove) /* DMOVE AC,E */ -{ - /* See if fast move OK, normally true. Hope the testing doesn't end up - ** using more time than the conservative case! - ** NOTE this assumes C structure copies are done sequentially. If this - ** is not true, must test for e == ac+1 instead. - */ - if (ac_issafedouble(ac) /* ACs contiguous? */ - && vm_issafedouble(e) /* Mem locs safe too? */ - && (va_insect(e) != ac_off(ac,-1))) /* no AC overlap with Mem? */ - *ac_mapd(ac) = vm_pgetd(vm_xrwmap(e,VMF_READ)); /* Yep! */ - else { - register dw10_t d; /* Conservative case, use intermed stg */ - vm_dread(e, d); /* Fetch the double */ - ac_dset(ac, d); /* Set in ACs */ - } - return PCINC_1; -} - -insdef(i_dmovem) /* DMOVEM AC,E */ -{ - /* See if fast move OK, normally true. Hope the testing doesn't end up - ** using more time than the conservative case! - ** NOTE this assumes C structure copies are done sequentially. If this - ** is not true, must test for e == ac-1 instead. - */ - if (ac_issafedouble(ac) /* ACs contiguous? */ - && vm_issafedouble(e) /* Mem locs safe too? */ - && (va_insect(e) != ac_off(ac,1))) /* no AC overlap with Mem? */ - vm_psetd(vm_xrwmap(e,VMF_WRITE), *ac_mapd(ac)); /* Yep! */ - else { - register dw10_t d; /* Conservative case, use intermed stg */ -#if KLH10_CPU_KL - ac_dget(ac, d); /* Get from ACs */ - vm_write(e, d.w[0]); /* Do first word */ - va_inc(e); - vm_write(e, d.w[1]); /* Do second word */ - -#elif KLH10_CPU_KS - register vaddr_t va; - ac_dget(ac, d); /* Get from ACs */ - va = e; - va_inc(va); - vm_write(va, d.w[1]); /* Do second word first! */ - vm_write(e, d.w[0]); /* Do first word last! */ - -#else /* What I'd really prefer to use - atomic double write */ - register vmptr_t p0, p1; - p0 = vm_xrwmap(e, VMF_WRITE); /* Check access for 1st word */ - va_inc(e); /* Bump E by 1, may wrap funnily */ - p1 = vm_xrwmap(e, VMF_WRITE); /* Check access for 2nd word */ - ac_dget(ac, d); /* Get from ACs */ - vm_pset(p0, d.w[0]); /* Set 1st from AC */ - vm_pset(p1, d.w[1]); /* Set 2nd from AC+1 */ -#endif - } - return PCINC_1; -} - -/* DMOVN is a vanilla double-precision arithmetic instruction. -** May set flags. -*/ -insdef(i_dmovn) /* D_MOVN AC,E */ -{ - register dw10_t d; - vm_dread(e, d); /* Fetch into D */ - op10mf_dmovn(d); /* Negate in place, with flags */ - ac_dset(ac, d); /* Store in ACs */ - return PCINC_1; -} - -/* DMOVNM requires special-casing due to differing order of operation -** for the double-word memory store. -** May set flags. Note flags are set prior to possible page fail, -** thus potentially losing just like the ucode. -*/ -insdef(i_dmovnm) /* DMOVNM AC,E */ -{ - register dw10_t d; - - ac_dget(ac, d); /* Fetch AC, AC+1 into D */ - op10mf_dmovn(d); /* Negate in place, with flags! */ - if (vm_issafedouble(e)) /* Fast move OK? */ - vm_psetd(vm_xrwmap(e,VMF_WRITE), d); /* Yep! */ - else { -#if KLH10_CPU_KL - vm_write(e, HIGET(d)); /* Do first word */ - va_inc(e); - vm_write(e, LOGET(d)); /* Do second word */ - -#elif KLH10_CPU_KS - register vaddr_t va; - va = e; - va_inc(va); - vm_write(va, LOGET(d)); /* Do second word first! */ - vm_write(e, HIGET(d)); /* Do first word last! */ - -#else /* What I'd really prefer to use - atomic double write */ - register vmptr_t p0, p1; - p0 = vm_xrwmap(e, VMF_WRITE); /* Check access for 1st word */ - va_inc(e); /* Bump E by 1, may wrap funnily */ - p1 = vm_xrwmap(e, VMF_WRITE); /* Check access for 2nd word */ - vm_pset(p0, HIGET(d)); /* Set 1st (high) */ - vm_pset(p1, LOGET(d)); /* Set 2nd (low) */ -#endif - } - return PCINC_1; -} - -/* BLT. (XBLT is handled by the EXTEND instr code) */ - -/* BLT - with optimization for case where dest is source+1. -** Note test for using same mapping, since BLT can be used for -** transfers between user and exec maps! -*/ - -/* Note special page map context references for BLT. -** These are so PXCT can work by twiddling the context pointers. -** For: -** Computing E - normal ea_calc() using XEA map -** Store word to destination - normal XRW map -** Read word from source - special XBRW map -*/ -#define vm_srcread(a) (vm_pget(vm_xbrwmap((a), VMF_READ))) - -/* Additional PXCT note for KLX: -** Uhler claims both source and dest must use the same (previous) -** context (thus the only valid AC values are 5 and 15 -- bits 10 and 12 -** must always be set!) -** It isn't clear whether a KLX is expected to ignore those bits -** and always use previous context, or if it simply does undefined things -** if those bits are off (requesting current context). -** For simplicity this code does implement current context mapping -** even on a KLX, which corresponds to the latter option. As long as -** the monitor only uses valid AC bit combinations this is okay. -*/ - -/* There are some ambiguities in the DEC PRM p.2-8 description of BLT. - -* Do the KI/KA test for RH[AC] >= RH(E) just as the KS/KL do, or can - the destination block wrap around? - [Assume yes, no dest wraparound] -* What happens if AC *is* in the destination block? - [Assume value indeterminate unless last word of xfer, then is - that value.] -* What happens if AC is in the source block? - [Assume value indeterminate, but if no pager/int, is original value] - [WRONG!!!! Turns out that for KS/KL, the AC is updated immediately - with the final src,,cnt value! So any copy involving that AC as - source will contain the "final" value. Aborts due to pagefail - or PI will re-clobber it with the correct intermediate value. - Exhibited by this test: MOVE 1,[1,,1] ? BLT 1,1 - which leaves 2,,2 in AC1.] - -* Exactly what is left in the AC for the KL case of RH[AC] > RH(E)? - The PRM says as if the "reverse xfer" happened, but does this - mean the last locs that wd have been referenced, or the next ones? - [Assume latter - the "next" ones.] -* The footnote on PRM p.2-8 claims an extended KL will count from section - 0 up into 1. Exactly what does this mean? That a source block - could consist of stuff from sect 0 mem, then the ACs (cuz 1,,0-17 is - used to ref the ACs), then sect 1 mem? What about the optimized - case where dest == src+1, would this still use the original - word value or would the BLT start reading from the sect 1 source? - [Assume we don't need to emulate this lossage. Yeech.] - -* !! Note from Uhler document that source and dest are incremented in-section - only, even if addresses are global, without altering local/global flag - that pager uses. -*/ - -insdef(i_blt) -{ - register int32 cnt; /* Note signed */ - register vaddr_t src, dst; - register vmptr_t vp; - -#if KLH10_EXTADR - src = dst = e; /* E sets default section & l/g flag */ - va_setinsect(src, ac_getlh(ac)); /* Set up source addr */ - va_setinsect(dst, ac_getrh(ac)); /* Set up dest addr */ -#else - va_lmake(src, 0, ac_getlh(ac)); - va_lmake(dst, 0, ac_getrh(ac)); -#endif - cnt = (va_insect(e) - va_insect(dst)); /* # words to move, less 1 */ - - if (cnt <= 0) { - /* Special case, either just 1 word or dest block would wrap - ** (So-called "reverse transfer" attempt). Main reason for - ** handling this specially is to emulate KL rev-xfer weirdness. - */ - register vmptr_t rp; - - /* First ensure we can carry out the single xfer expected */ - if (!(rp = vm_xbrwmap(src, VMF_READ|VMF_NOTRAP)) - || !(vp = vm_xrwmap(dst, VMF_WRITE|VMF_NOTRAP))) { - pag_fail(); /* Ugh, take page-fail trap */ - } - - /* OK, now if KL or KS, pre-clobber AC appropriately *before* - ** the copy, so that if AC is involved, behavior will emulate - ** the machines. Sigh. - */ -#if KLH10_CPU_KL - /* KL always updates as if the full reverse xfer happened */ - ac_setlrh(ac, (va_insect(src)+cnt+1) & H10MASK, - (va_insect(dst)+cnt+1) & H10MASK); -#elif KLH10_CPU_KS - /* KS only reflects what actually got xfered (according to PRM; - ** it may in fact behave like the KL for all I know!) - */ - ac_setlrh(ac, (va_insect(src)+1) & H10MASK, - (va_insect(dst)+1) & H10MASK); -#endif - vm_pset(vp, vm_pget(rp)); /* Copy directly from source */ - - return PCINC_1; - } - -#if KLH10_CPU_KS || KLH10_CPU_KL - /* Before starting xfer, clobber AC to final value. This emulates - ** the peculiar way the KS/KL do things. Note that due to this - ** pre-clobberage, there is no need to store a final value at the - ** end of a successful BLT. Any aborts MUST TAKE CARE to store the proper - ** intermediate value!! - */ - ac_setlrh(ac, (va_insect(src)+cnt+1) & H10MASK, - (va_insect(dst)+cnt+1) & H10MASK); -#endif /* KS || KL */ - - if ((va_insect(src)+1) == va_insect(dst) /* Special case? */ - && (cpu.vmap.xrw == cpu.vmap.xbrw)) { /* Must have same mapping! */ - - /* Simple set-memory-to-value BLT */ - register w10_t w; - - /* Get first word and remember that. Just in case it helps the - ** compiler optimize, use xrw map instead of xbrw since we only - ** come here if they're the same. - */ - if (!(vp = vm_xrwmap(src, VMF_READ|VMF_NOTRAP))) { - ac_setlrh(ac, va_insect(src), /* Oops, save AC */ - va_insect(dst)); - pag_fail(); /* Take page-fail trap */ - } - w = vm_pget(vp); /* Get word, remember it */ - - do { - CLOCKPOLL(); /* Keep clock going */ - if (INSBRKTEST()) { /* Watch for interrupt */ - ac_setlrh(ac, va_insect(src), /* Oops, save AC */ - va_insect(dst)); - apr_int(); /* Take interrupt */ - } - if (!(vp = vm_xrwmap(dst, VMF_WRITE|VMF_NOTRAP))) { - ac_setlrh(ac, va_insect(src), /* Oops, save AC */ - va_insect(dst)); - pag_fail(); /* Take page-fail trap */ - } - vm_pset(vp, w); /* Store word value */ - va_linc(src); /* Do LOCAL increment of addrs! */ - va_linc(dst); - } while (--cnt >= 0); - } - else do { - - /* Normal BLT transfer */ - register vmptr_t rp; - CLOCKPOLL(); /* Keep clock going */ - if (INSBRKTEST()) { /* Watch for interrupt */ - ac_setlrh(ac, va_insect(src), /* Oops, save AC */ - va_insect(dst)); - apr_int(); /* Take interrupt */ - } - - if (!(rp = vm_xbrwmap(src, VMF_READ|VMF_NOTRAP)) - || !(vp = vm_xrwmap(dst, VMF_WRITE|VMF_NOTRAP))) { - ac_setlrh(ac, va_insect(src), /* Oops, save AC */ - va_insect(dst)); - pag_fail(); /* Take page-fail trap */ - } - vm_pset(vp, vm_pget(rp)); /* Copy directly from source */ - va_linc(src); /* Add 1 to both addrs */ - va_linc(dst); /* Again, LOCAL increment only */ - - } while (--cnt >= 0); - -#if 0 /* No longer needed, code done inline to avoid this check */ - /* Broke out of loop, see if page-failed or not */ - if (cnt >= 0) { /* Use this as indicator */ - ac_setlrh(ac, va_insect(src), /* Oops, save AC */ - va_insect(dst)); - pag_fail(); /* Ugh, take page-fail trap */ - } -#endif - -#if 0 /* KLH10_CPU_KS || KLH10_CPU_KL */ - /* This is no longer used. Instead, to more accurately emulate the - ** KS/KL, the final AC value is stored immediately at the start of - ** the BLT code, so if nothing goes wrong, nothing needs to be done. - */ - - /* End of BLT, but KS/KL must leave AC pointing - ** to what would be the next transfer... unless AC happens - ** to be the last destination! - ** - ** vp still points to last destination, so we can use that for testing, - ** avoiding hassle of determining whether dst is an ac reference! - */ - if (ac_map(ac) != vp) - ac_setlrh(ac, va_insect(src), va_insect(dst)); -#endif /* KS || KL */ - - return PCINC_1; -} - -#if 0 /* Old version, saved in memory of simpler times */ - -insdef(i_blt) -{ - register w10_t w, val; - register int optim; - - e &= H10MASK; - w = ac_get(ac); /* Get src,,dst */ - - if ((LHGET(w)+1)&H10MASK == RHGET(w)) /* Special case? */ - && (cpu.vmap.xrw == cpu.vmap.xbrw)) { /* Must be same mapping! */ - val = vm_srcread(LHGET(w)); - optim = TRUE; - } else optim = FALSE; - for (;;) { - vm_write(RHGET(w), (optim ? val : vm_srcread(LHGET(w)))); - if (RHGET(w) >= e) { /* Last word? Note also stop if AC.rh > E */ - break; /* Win! */ - } - LHSET(w, (LHGET(w)+1)&H10MASK); /* Add 1 to both halves */ - RHSET(w, (RHGET(w)+1)&H10MASK); - ac_set(ac, w); /* Store back in AC in case of pagefail */ - - CLOCKPOLL(); /* Keep clock going */ - if (INSBRKTEST()) apr_int(); /* Watch for interrupt */ - } - - /* End of BLT, but to emulate KS10 exactly must leave AC pointing - ** to what would be the next transfer... unless AC is last destination. - */ - if (ac != RHGET(w)) { - LHSET(w, (LHGET(w)+1)&H10MASK); /* Add 1 to both halves */ - RHSET(w, (RHGET(w)+1)&H10MASK); - ac_set(ac, w); /* Store back in AC */ - } - return PCINC_1; -} -#endif /* 0 - old version */ - -/* BLTBU and BLTUB -** -** New KS10 instructions, not documented in PRM; behavior here is based -** on description from Alan. These are like BLT but transfer blocks of 8-bit -** bytes, packing or unpacking between "Byte format" and "Unibus format". -** -** "Byte format" is the normal PDP-10 format: -** <4 unused bits> -** -** "Unibus format" is sort of like the screwy PDP-11 byte order: -** <2-bits><2-bits> -** -** It isn't clear whether the <2-bits> fields are meaningful or whether they -** are mapped to and from the 4-bit field in Byte format. -** [Assume not mapped; extra bits are cleared in both directions] -** -** [Alan sez: -** Of course in the case of a device that can put 18 bits of data on the -** Unibus, the extra bits show up where the diagram says "2 BITS". (There is -** a bit in the UBA map that says whether the UBA should expect 18-bit data to -** be written to that page. I have no idea what happens if you set it wrong, -** perhaps it just controls whether the extra bits are passed through or -** written as 0.)] -*/ - - -#if KLH10_CPU_KS - -/* BLTBU - Like BLT but transforms each word from Byte to Unibus format. -** BLTUB - Ditto, Unibus to Byte format. -** For more explanation of the code, see BLT. -*/ -#define defblt(name) \ - insdef(name) { register w10_t w, val; \ - register vaddr_t src, dst; \ - register uint18 stop = va_insect(e); \ - w = ac_get(ac); \ - va_lmake(src, 0, LHGET(w)); \ - va_lmake(dst, 0, RHGET(w)); \ - for (;;) { \ - val = vm_srcread(src); \ - blttransform(val); \ - vm_write(dst, val); \ - if (RHGET(w) >= stop) \ - break; \ - LHSET(w, (LHGET(w)+1)&H10MASK); \ - RHSET(w, (RHGET(w)+1)&H10MASK); \ - ac_set(ac, w); \ - CLOCKPOLL(); \ - if (INSBRKTEST()) apr_int(); \ - va_inc(src); \ - va_inc(dst); \ - } \ - if (ac != RHGET(w)) { \ - LHSET(w, (LHGET(w)+1)&H10MASK); \ - RHSET(w, (RHGET(w)+1)&H10MASK); \ - ac_set(ac, w); \ - } \ - return PCINC_1; \ - } - -/* Byte fmt to Unibus fmt, clears extra bits */ -#define blttransform(v) \ - RHSET(v, ((RHGET(v)<<4)&(0377<<8)) \ - | ((LHGET(v)&03)<<6) | ((RHGET(v)>>12)&077) ); \ - LHSET(v, ((LHGET(v)>>10)&0377) | ((LHGET(v)<<6)&(0377<<8)) ) -defblt(i_bltbu) -#undef blttransform - - -/* Unibus fmt to Byte fmt, clears extra bits */ -#define blttransform(v) \ - LHSET(v, ((LHGET(v)&0377)<<10) \ - | ((LHGET(v)&(0377<<8))>>6) \ - | ((RHGET(v)>>6)&03) ); \ - RHSET(v, ((RHGET(v)>>4)&(0377<<4)) \ - | ((RHGET(v)&&077)<<12) ) -defblt(i_bltub) -#undef blttransform - -#endif /* KS */ - -#if KLH10_EXTADR - -/* XMOVEI and XHLLI. -** These two instructions are not as straightforward as they -** might seem. One might expect them to simply: -** (1) use whatever the section number of the EA is, or -** (2) always set LH = 1 if reference is to an AC. -** -** In fact, they do neither. -** The use of LH=1 to represent a global AC address happens ONLY if: -** (a) EA is local, (b) section # is non-zero, and (c) in-section -** address is 0-17 inclusive. -** -** In particular, a local reference to 0,,AC (even if made while PC_ISEXT) -** will be stored as 0,,AC and not 1,,AC. -** Likewise, a global reference to 0,,AC is stored as 0,,AC even though -** it *DOES* reference the ACs, just like 1,,AC! -** -** The following table sums it up: -** -** LOCAL 0,,AC => 0,,AC -** LOCAL NZ,,AC => 1,,AC -** LOCAL *,,NAC => *,,NAC -** GLOBAL *,,* => *,,* -** -** This behavior is coded into the va_iscvtacref() macro. -** -** Finally, this same conversion is also done for the EA stored as a result -** of a LUUO, MUUO, or pagefail trap. -** (what about PC?) -*/ - -/* XMOVEI - Actually an extended SETMI. -** Special boolean variant when using extended addressing -*/ -insdef(i_xmovei) -{ - if (va_iscvtacref(e)) - ac_setlrh(ac, 1, va_insect(e)); /* Global AC reference */ - else - ac_setlrh(ac, va_sect(e), va_insect(e)); - return 1; -} - - -/* XHLLI - Actually an extended HLLI. -** Special halfword variant when using extended addressing -*/ -insdef(i_xhlli) -{ - if (va_iscvtacref(e)) - ac_setlh(ac, 1); /* Global AC reference */ - else - ac_setlh(ac, va_sect(e)); - return 1; -} - -#endif /* KLH10_EXTADR */ diff --git a/src/klh10.c.old b/src/klh10.c.old deleted file mode 100644 index 0faa3e5..0000000 --- a/src/klh10.c.old +++ /dev/null @@ -1,2881 +0,0 @@ -/* KLH10.C - Main for KLH10 (also Front End Console for now) -*/ -/* $Id: klh10.c,v 2.9 2002/05/21 16:54:32 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: klh10.c,v $ - * Revision 2.9 2002/05/21 16:54:32 klh - * Add KLH10_I_CIRC to allow any sys to have CIRC - * - * Revision 2.8 2002/05/21 10:01:22 klh - * Add ub_debug param. - * Allow access to HZ vars even if using synch clock. - * - * Revision 2.7 2002/04/24 07:56:08 klh - * Add os_msleep, using nanosleep - * - * Revision 2.6 2002/03/28 16:51:04 klh - * Tweak to fc_quit - * - * Revision 2.5 2002/03/21 09:50:08 klh - * Mods for CMDRUN (concurrent mode) - * - * Revision 2.4 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#include -#include /* Malloc and friends */ -#include -#include -#include -#include -#include -#include /* For error-reporting functions */ - -#include "klh10.h" -#include "kn10mac.h" /* FLD macros */ -#include "kn10def.h" -#include "kn10dev.h" -#include "kn10ops.h" -#include "wfio.h" -#include "fecmd.h" -#include "feload.h" -#include "prmstr.h" -#include "dvcty.h" /* For cty_ functions */ - -#if KLH10_CPU_KS -# include "dvuba.h" /* So can get at device info */ -#endif - -#ifdef RCSID - RCSID(klh10_c,"$Id: klh10.c,v 2.9 2002/05/21 16:54:32 klh Exp $") -#endif - -/* Exported functions */ -void klh10_main(int argc, char **argv); -void fe_aprcont(int, int, vaddr_t, int); -void fe_shutdown(void); -void fe_traceprint(w10_t, vaddr_t); -void fe_begpcfdbg(FILE *f); -void fe_endpcfdbg(FILE *f); -void pishow(FILE *); -void pcfshow(FILE *, h10_t); -void insprint(FILE *, int); -/* void panic(char *, ...); */ /* Declared in kn10def.h */ - -/* Imported functions */ -extern void apr_init(void); -extern int apr_run(void); - -/* Local function kept external for easier debug access */ -void errpt(void); - - -/* Local variables */ - -int proc_bkgd = FALSE; /* TRUE if want to run in background */ -int fedevchkf = FALSE; /* TRUE to do periodic device attention checks */ -ospri_t proc_pri = 0; /* CPU process priority on host OS */ -int cmdpromptnew = TRUE; /* Set whenever cmdprompt changed */ -char *cmdprompt = /* Set initial command prompt */ -#ifdef KLH10_CMDPROMPT - KLH10_CMDPROMPT; -#else - ":KLH10# :KLH10> :KLH10>> "; -#endif - -char *ld_fmt = NULL; /* Current load file format */ -char *ld_dfmt = /* Default format if none specified */ -#if KLH10_SYS_ITS - "u36"; /* Alan's Unixified format */ -#else - "c36"; /* Core-Dump format */ -#endif -struct loadinfo ld_inf; /* Args to and results from loader */ - -enum fevmmode { /* FEVM_XMAP memory mapping mode defs */ - FEVM_DFLT, /* Use FE default mode */ - FEVM_CUR, /* Current machine mode mapping */ - FEVM_PHYS, /* Force physical map */ - FEVM_EXEC, /* Force exec map */ - FEVM_USER, /* Force user map */ - FEVM_ACB /* Select AC block */ -}; - -/* DDT mode variables */ -vaddr_t ddt_loadsa; /* Last loaded start address */ -vaddr_t ddt_cloc; /* Current location (.) */ -enum fevmmode ddt_clmode; /* Current location FEVM mode */ -w10_t ddt_val; /* Last value */ - -/* Flags to pinstr() */ -#define PINSTR_OPS 01 /* Show operands of instr */ -#define PINSTR_EA 02 /* Use E furnished */ -void pinstr(FILE *, w10_t, int, vaddr_t); - -/* Local Function predeclarations */ - -static void klh10_init(void); -static void mem_init(void), mem_term(void); -static int mem_setlock(FILE *, FILE *, int); -static void swinit(int, char **); -static int aprhalted(void); -static void wd1print(FILE *, w10_t); -static void wd2print(FILE *, w10_t); -static void addrprint(FILE *, vaddr_t, enum fevmmode); -static void nextinsprint(FILE *, int); -static void easymprint(FILE *, vaddr_t); -static int addrparse(char *, vaddr_t *, enum fevmmode *); -static char *strf6(char **, w10_t); -static struct tm *timefrits(struct tm *, w10_t); - -vmptr_t fevm_xmap(vaddr_t, enum fevmmode); /* FE memory mapping */ - -/****************** Command Tables and dispatch ******************/ - -/* New version of command parser -- succumb to GDB, DBX, UNIX influence. -** -** Old version used an even simpler one-character instant-action parser. -*/ - -static FILE *cminfile = NULL; /* Set if reading commands from file */ -static char *cminfname; /* Filename */ -static int cminchar(void); /* Funct to read from file or TTY */ - -#define CMDQCHAR '\\' /* Quote char for token parsing */ - -#ifndef CMDBUFLEN -# define CMDBUFLEN 512 -#endif -#ifndef CMDMAXARG -# define CMDMAXARG 10 -#endif - -struct cmd_s { - int cmd_flags; /* State flags */ - char *cmd_prm; /* Pointer to command prompt */ - char *cmd_buf; /* Pointer to start of buffer */ - size_t cmd_blen; /* Size of buffer */ - int cmd_left; /* # chars left for current cmd being input */ - char *cmd_inp; /* Input deposit pointer */ - char *cmd_rdp; /* Readout pointer */ - size_t cmd_rleft; /* # chars left to read */ - - /* Provide all command routines with their desired arguments */ - char *cmd_arglin; /* Original pointer to start of args on line */ - int cmd_argc; /* # of tokens */ - char *cmd_argv[CMDMAXARG+1]; /* Array of token pointers */ - char *cmd_tdp; /* Next free loc in token buffer */ - size_t cmd_tleft; /* # chars free in token buffer */ - char cmd_tokbuf[CMDBUFLEN+CMDMAXARG]; - -#if 0 - char *cmd_wbf; /* Pointer to work buffer */ - size_t cmd_wblen; /* Size in chars */ - char *cmd_wbp; /* Current deposit ptr */ - size_t cmd_wbleft; /* # chars left */ -#endif -} command; - -#define CMDF_ACTIVE 01 /* Activation char seen, execute accumulated cmd */ -#define CMDF_INACCUM 02 /* In accumulation phase */ -#define CMDF_NOPRM 040 /* Disable prompt */ - -static char cmdbuf[CMDBUFLEN]; /* Original command string buffer */ -#if 0 -static char cmdwbf[CMDBUFLEN]; /* Working buffer */ -#endif - -struct cmkey_s { - char *cmk_key; - union cmnode *cmk_p; -}; -struct cmrtn_s { - void (*cmr_vect)(struct cmd_s *); /* Function to call */ - int cmr_flgs; /* Misc flags */ - char *cmr_synt; /* Arg syntax */ - char *cmr_help; /* Short one-line help */ - char *cmr_desc; /* Long description */ -}; - -#define CMRF_NOARG 01 /* Command takes no args */ -#define CMRF_TOKS 010 /* Command wants whole line tokenized, via cm */ -#define CMRF_TLIN 020 /* Command wants overall line arg, via cm */ -#define CMRF_CMPTR 040 /* Command wants just cmd state ptr */ - -union cmnode { /* All possible nodes for a keyword */ - struct cmrtn_s cmn_rtn; -}; - - -/* Predeclarations */ -void cmdinit(struct cmd_s *, char *, char *, size_t); -int cmdexec(struct cmd_s *); -int cmdaccum(struct cmd_s *); - -struct cmkey_s *cmdkeylookup(char *, struct cmkey_s *, struct cmkey_s **); -char *cmdlsetup(struct cmd_s *); -static void slinlim(char *); - - -/* CMDDEF is used to define top-level commands. It does not accumulate -** them into a table (C is far too puny for that) but gathers together -** various information that a higher-level table can then point to. -*/ -#define CMDDEF(deflab, func, flgs, argsyn, minihelp, longdesc) \ - static void func(struct cmd_s *); \ - static struct cmrtn_s deflab = { func, flgs, argsyn, minihelp, longdesc }; - -CMDDEF(cd_ques, fc_ques, CMRF_NOARG, NULL, - "How to get help", "") -CMDDEF(cd_help, fc_help, CMRF_TOKS, NULL, - "Basic help", "") -CMDDEF(cd_quit, fc_quit, CMRF_NOARG, NULL, - "Quit emulator", "") -CMDDEF(cd_load, fc_load, CMRF_TOKS, "", - "Load binary into KN10", "") -CMDDEF(cd_dump, fc_dump, CMRF_TOKS, "", - "Dump binary from KN10", "") -CMDDEF(cd_go, fc_go, CMRF_TLIN, "[]", - "Start KN10 at address", "") -CMDDEF(cd_shutdown,fc_shutdown,CMRF_NOARG,NULL, - "Halt OS gracefully", "") -CMDDEF(cd_reset, fc_reset, CMRF_NOARG, NULL, - "Halt & Reset KN10", "") -CMDDEF(cd_exa, fc_exa, CMRF_TLIN, "[]", - "Show word at address", "") -CMDDEF(cd_exnext,fc_exnext, CMRF_NOARG, NULL, - "Show Next word", "") -CMDDEF(cd_exprev,fc_exprev, CMRF_NOARG, NULL, - "Show Previous word", "") -CMDDEF(cd_dep, fc_dep, CMRF_TOKS, " ", - "Deposit value at address", "") -CMDDEF(cd_bkpt, fc_bkpt, CMRF_TLIN, "", - "Set breakpoint at PC loc", "") -#if 1 /* New setup */ -CMDDEF(cd_step, fc_step, CMRF_TLIN, "<#>", - "Single-Step # KN10 instrs", "") -CMDDEF(cd_proc, fc_proc, CMRF_NOARG, NULL, - "Proceed KN10 without CTY", "") -#else -CMDDEF(cd_step, fc_step, CMRF_NOARG, NULL, - "Single-Step KN10", "") -CMDDEF(cd_proc, fc_proc, CMRF_TLIN, "<#>", - "Proceed # instrs", "") -#endif -CMDDEF(cd_cont, fc_cont, CMRF_NOARG, NULL, - "Continue KN10", "") -CMDDEF(cd_view, fc_view, CMRF_NOARG, NULL, - "View KN10 status", "") -CMDDEF(cd_set, fc_set, CMRF_TLIN, "[ []]", - "Set/show KLH10 variables", "") -CMDDEF(cd_trace, fc_trace, CMRF_NOARG, NULL, - "Toggle execution trace", "") -CMDDEF(cd_halt, fc_halt, CMRF_NOARG, NULL, - "Halt KN10 immediately", "") -CMDDEF(cd_zero, fc_zero, CMRF_NOARG, NULL, - "Zero first 256K memory", "") -CMDDEF(cd_devload,fc_devload, CMRF_TLIN, - " ", - "Load dynamic-library device driver", "") -CMDDEF(cd_devdef,fc_devdef, CMRF_TLIN, - " {ub<#>,} ", - "Define, bind, and initialize device", "") -CMDDEF(cd_devshow,fc_devshow, CMRF_TLIN, - "[]", - "Show device driver & definition binding info", "") -#if KLH10_EVHS_INT -CMDDEF(cd_devevshow,fc_devevshow, CMRF_TLIN, - "[]", - "Show device event registration info", "") -#endif -CMDDEF(cd_dev_cmd,fc_dev_cmd, CMRF_TLIN, - " ", - "Execute device-dependent command", "") - -CMDDEF(cd_devboot,fc_devboot, CMRF_TLIN, - " [halt]", - "Boot from device", "") -CMDDEF(cd_devmnt,fc_devmnt, CMRF_TLIN, - " []", - "Mount device media", "") -CMDDEF(cd_devunmnt,fc_devunmnt, CMRF_TLIN, - "", - "Unmount device media", "") -CMDDEF(cd_devdbg,fc_devdbg, CMRF_TLIN, - " []", - "Set device debug value (0=none)", "") -CMDDEF(cd_devwait,fc_devwait, CMRF_TLIN, - "[] []", - "Wait for device (or all devs)", "") - - -#define KEYSBEGIN(name) struct cmkey_s name[] = { -#define KEYDEF(key,nod) { key, (union cmnode *)(&nod) }, -#define KEYSEND { 0, 0 } }; - -KEYSBEGIN(fectbkeys) - KEYDEF("?", cd_ques) - KEYDEF("help", cd_help) - KEYDEF("quit", cd_quit) - KEYDEF("load", cd_load) - KEYDEF("dump", cd_dump) - KEYDEF("go", cd_go) - KEYDEF("shutdown", cd_shutdown) - KEYDEF("reset", cd_reset) - KEYDEF("examine", cd_exa) - KEYDEF("next-examine", cd_exnext) - KEYDEF("^-examine", cd_exprev) - KEYDEF("deposit", cd_dep) - KEYDEF("breakpt", cd_bkpt) - KEYDEF("1-step", cd_step) - KEYDEF("proceed", cd_proc) - KEYDEF("continue", cd_cont) - KEYDEF("view", cd_view) - KEYDEF("set", cd_set) - KEYDEF("trace-toggle", cd_trace) - KEYDEF("halt", cd_halt) - KEYDEF("zero", cd_zero) - KEYDEF("devdefine", cd_devdef) - KEYDEF("devdebug", cd_devdbg) - KEYDEF("devboot", cd_devboot) - KEYDEF("devmount", cd_devmnt) - KEYDEF("devunmount",cd_devunmnt) - KEYDEF("devwait", cd_devwait) - KEYDEF("devshow", cd_devshow) -#if KLH10_EVHS_INT - KEYDEF("devevshow", cd_devevshow) -#endif - KEYDEF("dev", cd_dev_cmd) - KEYDEF("devload", cd_devload) -KEYSEND - -static void error(char *, ...), syserr(int, char *, ...); - -jmp_buf errenv; - -int initdone = 0; - -void -errpt(void) /* Call this to restart loop */ -{ - if (!initdone) { - fprintf(stderr, "Died during startup... goodbye!\n"); - os_exit(1); - } - - /* Return to main KLH10 command processor loop. - ** All implementations of longjmp() had better know how to jump out of - ** a signal handler context! - */ - longjmp(errenv, 1); -} - -/* Print out KLH10 compile-time configuration info - */ -#include "klh10s.h" /* Define string equivs to config params! */ - -static void -pconfig(FILE *f) -{ - fprintf(f, "Compiled for %s on %s with word model %s\n", - KLH10S_CENV_SYS_, KLH10S_CENV_CPU_, WORD10_MODEL); - fputs("Emulated config:\n", f); - fprintf(f, "\t CPU: %s SYS: %s Pager: %s APRID: %ld\n", - KLH10S_CPU_, KLH10S_SYS_, KLH10S_PAG_, - (long)KLH10_APRID_SERIALNO); - fprintf(f, "\t Memory: %ld pages of %d words (%s)\n", - (long)PAG_MAXPHYSPGS, (int)PAG_SIZE, - (KLH10_MEM_SHARED ? "SHARED" : "private")); - fprintf(f, "\t Time interval: %s Base: %s", - KLH10S_ITIME_, KLH10S_RTIME_); -#if KLH10_SYS_ITS - fprintf(f, " Quantums: %s", KLH10S_QTIME_); -#endif -#if KLH10_CLK_ITHZFIX - fprintf(f, "\n\t Interval default: %dHz\n", KLH10_CLK_ITHZFIX); -#else - fprintf(f, "\n\t Interval default: set by 10\n"); -#endif - fprintf(f, "\t Internal clock: %s\n", KLH10S_CLKTRG_); - - /* Show hardware emulation stuff first, then software features */ - fprintf(f, "\t Other:%s\n", - KLH10S_MCA25 - KLH10S_I_CIRC - KLH10S_JPC - KLH10S_DEBUG - KLH10S_PCCACHE - KLH10S_CTYIO_INT - KLH10S_IMPIO_INT - KLH10S_EVHS_INT - ); - - /* Show peripheral device drivers known at compile time */ - fprintf(f, "\t Devices:%s\n", - KLH10S_DEV_DTE - KLH10S_DEV_RH - KLH10S_DEV_RPXX - KLH10S_DEV_TM03 - KLH10S_DEV_NI20 - KLH10S_DEV_DZ11 - KLH10S_DEV_CH11 - KLH10S_DEV_LHDH - ); -} - -static void -pversion(FILE *f) -{ - fputs("KLH10", f); -#ifdef KLH10_VERSION - fprintf(f, " %s", KLH10_VERSION); -#endif -#ifdef KLH10_CLIENT - fprintf(f, " (%s)", KLH10_CLIENT); -#endif -#if defined(__DATE__) && defined(__TIME__) - fprintf(f, " built %s %s", __DATE__, __TIME__); -#endif - fputc('\n', f); -} - -static void -pgreeting(FILE *f) -{ - pversion(f); -#ifdef KLH10_COPYRIGHT - fprintf(f, "%s\n", KLH10_COPYRIGHT); -#endif -#ifdef KLH10_WARRANTY - fprintf(f, "%s\n", KLH10_WARRANTY); -#endif - fputc('\n', f); - pconfig(f); -} - - -void -klh10_main(int argc, - char **argv) -{ - /* Handle command line args/switches, if any */ - swinit(argc, argv); - - os_init(); /* Initialize any OS-dependent stuff */ - - /* Ensure stdout is unbuffered, like stderr, to avoid the otherwise - ** confusing skews between the two streams. This must be done prior to - ** any output on stdout. - */ - setbuf(stdout, (char *)NULL); - if (proc_bkgd) - fprintf(stderr, "[Running in background]\n"); - pgreeting(stdout); /* Print greeting message if one */ - - klh10_init(); /* Do machine init and configuring */ - fe_ctyinit(); /* Initialize console, KLH10 UI */ - - if (!setjmp(errenv)) { - /* Once-only first-time stuff */ - initdone = TRUE; /* errenv jmpbuf now set */ - - } else { - /* Recover from error catch - something called errpt(). */ - printf(""); - /* If reading from command file, abort it */ - if (cminfile) { - fclose(cminfile); - cminfile = NULL; - printf("[Aborted input from \"%s\"]\n", cminfname); - } - } - fe_cmdloop(); -} - -void -fe_cmdloop(void) -{ - enum femode omode = -1; - int prompted = FALSE; - - fe_ctyreset(); /* Reset our terminal mode stuff */ - printf("\n"); /* Make sure we prompt on a new line */ - - /* Enter command parser loop */ - for (;;) { - - /* Determine new prompt if necessary */ - if (cmdpromptnew || (omode != cpu.fe.fe_mode)) { - cmdinit(&command, fe_cmprompt(cpu.fe.fe_mode), - cmdbuf, sizeof(cmdbuf)); - omode = cpu.fe.fe_mode; - prompted = FALSE; - cmdpromptnew = FALSE; - } - if (cpu.fe.fe_debug) - fprintf(stderr, "[femode %d prompt %d]", omode, prompted); - - switch (omode) { - case FEMODE_CMDCONF: - case FEMODE_CMDHALT: - if (prompted) - command.cmd_flags |= CMDF_NOPRM; - else - command.cmd_flags &= ~CMDF_NOPRM; - if (!cmdlsetup(&command)) { /* Read typein command line */ - printf("\n"); /* If failed, try again */ - break; - } - if (fedevchkf) /* If checking for dev attn, */ - fedevchkf = dev_dpchk_ctl(TRUE); /* do so here */ - (void) cmdexec(&command); /* Parse and execute */ - break; - - case FEMODE_CMDRUN: - /* See if input available. If so, parse and execute, else - run the CPU. - */ - if (cminfile || fe_ctyintest()) { - if (prompted) - command.cmd_flags |= CMDF_NOPRM; - else - command.cmd_flags &= ~CMDF_NOPRM; - if (!cmdlsetup(&command)) { /* Read input cmd line */ - printf("\n"); /* If failed, try again */ - break; - } - (void) cmdexec(&command); /* Parse and execute */ - break; - } - - /* Nothing to do, start running! */ - if (!prompted) { - fputs(fe_cmprompt(cpu.fe.fe_mode), stdout); - prompted = TRUE; - } - fe_aprcont(FEMODE_CMDRUN, 0, 0, 0); /* Resume KN10 */ - continue; /* No cmd done, so don't reset "prompted" */ - - case FEMODE_CTYRUN: /* Should not happen */ - default: - cpu.fe.fe_mode = FEMODE_CMDHALT; - error("[FE invalid mode %d]", omode); - } - prompted = FALSE; - } -} - - -void -fc_quit(struct cmd_s *cm) -{ - if (!aprhalted()) - printf("KN10 still running!\n"); - printf("Are you sure you want to quit? [Confirm]"); - fe_ctycmforce(); - switch (cminchar()) { - case '\r': - case '\n': - case 'y': - case 'Y': - case -1: /* EOF */ - break; - default: /* Anything else prevents quit */ - return; - } - printf("Shutting down..."); - - dev_term(); /* Power off all devices that might need it */ - - mem_term(); /* Flush memory in case shared */ - - printf("Bye!\n"); - os_exit(0); -} - -/* FE_SHUTDOWN - Attempt to bring down PDP-10 OS and quit emulator as -** gracefully as possible *without* any user interaction. -** -** This is intended to be used when operating as a background process, -** when errors that would normally halt and await input should -** instead attempt to give both the PDP-10 OS and the emulator a -** chance to clean up before the process is killed. This currently -** means: -** (1) Any request for TTY input - in bkgd mode that implies something -** went wrong. -** (2) Receipt of a SIGTERM software termination signal. -** -** Probably better would be a way to suspend operations and then allow -** re-attaching a TTY to the emulator -- but UNIX sucks in that regard -** and still hasn't implemented technology that existed 25 years ago! -*/ - -static int -fe_shuttmo(void *arg) /* arg is ignored */ -{ - printf("[Auto-shutdown timed out]\n"); - fe_shutdown(); /* Re-invoke next phase of shutdown */ - return CLKEVH_RET_KILL; /* Won't actually return */ -} - -void -fe_shutdown(void) -{ - static int shutstate = 0; /* Initial shutdown state */ - - switch (shutstate) { - case 0: - ++shutstate; - /* First determine whether a PDP-10 OS ever actually seemed to get - ** going; a good heuristic is to see if paging mode is on. - ** If so, attempt to trigger a shutdown. - */ - if (cpu.mr_paging) { - /** Attempt OS shutdown! - ** Set a clock timeout of N seconds, after which to force shutdown - ** anyway. For now, set N = 3. - */ - printf("[Attempting auto-shutdown]\n"); - (void) clk_tmrget(fe_shuttmo, (void *)NULL, - (int32) CLK_USECS_PER_SEC * 3); - fc_shutdown((struct cmd_s *)NULL); /* No input required for this */ - /* Will not return */ - } - - case 1: - ++shutstate; - - case 2: - ++shutstate; - printf("[Starting auto-quit]\n"); - dev_term(); /* Power off all devices that might need it */ - /* This should kill all DP subprocs */ - case 3: - ++shutstate; - mem_term(); /* Flush memory in case using shared segs */ - - case 4: - ++shutstate; - printf("[Exiting]\n"); - } - os_exit(1); /* Die with an error */ -} - -/* ERROR - Called only by FE code to report some error in interacting -** with the user. -*/ -static void -error(char *fmt, ...) -{ - fprintf(stderr, "\n"); - { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - fprintf(stderr, "\n"); - - errpt(); -} - - -/* SYSERR - Called only by FE code to report some OS error in interacting -** with the user. -*/ -static void -syserr(int num, char *fmt, ...) -{ - { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - fprintf(stderr, " - %s\n", os_strerror(num)); - - errpt(); -} - - -/* PANIC - called while the KLH10 is actually running, whenever something -** detects a situation that should be impossible or cannot be handled. -*/ -void -panic(char *fmt, ...) -{ - fprintf(stderr, "\r\nKLH10 PANIC: "); - { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - } - fprintf(stderr, "\r\n Current PC= %#lo\r\n", (long) PC_30); - - errpt(); /* For now, break directly to main loop */ -} - -/* Startup arg parsing and default setting. -** For now, all we do with args is interpret the first as a command file. -** If no arg, look for KLH10_INITFILE as default init command file. -*/ - -#define KLH10_SWITCHES \ - swidef(SWI_BKGD, "background"), /* Run in bkgnd mode */\ - swidef(SWI_HELP, "help"), /* Not yet */\ - swidef(SWI_VERSION, "version") /* Not yet */ -enum { -# define swidef(i,s) i - KLH10_SWITCHES -# undef swidef -}; - -static char *switab[] = { -# define swidef(i,s) s - KLH10_SWITCHES -# undef swidef - , NULL -}; - -static char usage[] = "Usage: klh10 [-background] [initfile]\n"; - -void -swinit(int ac, char **av) -{ - FILE *f; - char *initfile = NULL; - char *cp; - int res, kx1, kx2; - - while (--ac > 0) { - cp = *(++av); - if (*cp != '-') { - /* Arg that isn't a switch is assumed to be init filename */ - if (initfile) { /* If already have it, error */ - fprintf(stderr, "%s", usage); - os_exit(1); - } - initfile = cp; - continue; - } - res = s_xkeylookup(cp+1, (void *)switab, sizeof(switab[0]), - (voidp_t *)NULL, (voidp_t *)NULL, &kx1, &kx2); - if (res == 1) switch (kx1) { - case SWI_BKGD: - proc_bkgd = TRUE; - continue; - } - - /* Fall through to here if bad switch or something else wrong */ - fprintf(stderr, "Unknown switch \"%s\"\n", cp); - fprintf(stderr, "%s", usage); - os_exit(1); - } - - if (!initfile) { /* If no init file explicitly given */ - initfile = KLH10_INITFILE; /* Use default, but */ - f = fopen(initfile, "r"); /* if not there, don't complain */ - } else if (!(f = fopen(initfile, "r"))) { - syserr(-1, "Cannot open \"%s\"", initfile); - /* Doesn't return since init not yet finished */ - } - - if (f) { - cminfile = f; /* Set - read cmds from file until gone */ - cminfname = initfile; /* Remember its name */ - } - - /* Set any other defaults necessary */ - ld_fmt = ld_dfmt; /* Set current load/dump format to default */ -} - -/* Command parsing routines. -** New full-line version, still simple-minded. -** Eventually can go to CCMD-like or GDB-like package, but for now keep -** the overall size small. -** -** Some of the parsing functions are in PRMSTR so they can readily be -** called by other modules (specifically device emulation code). -*/ - -void cmdreset(struct cmd_s *); -void cmdspfls(struct cmd_s *); -static void stolower(char *); -static int smatch(char *, char *); - -static int cmdargs_none(struct cmd_s *cm); -static int cmdargs_one(struct cmd_s *cm, char **); -static int cmdargs_two(struct cmd_s *cm, char **, char **); -static int cmdargs_all(struct cmd_s *cm); -static int cmdargs_n(struct cmd_s *cm, int n); - -void cmdinit(struct cmd_s *cm, - char *prompt, - char *ibuf, - size_t ilen) -{ - cm->cmd_flags = 0; - cm->cmd_prm = prompt; - cm->cmd_buf = ibuf; - cm->cmd_blen = ilen; - cmdreset(cm); -} - -void -cmdreset(struct cmd_s *cm) -{ - cm->cmd_flags &= ~(CMDF_ACTIVE|CMDF_INACCUM); - cm->cmd_left = cm->cmd_blen; - cm->cmd_inp = cm->cmd_rdp = cm->cmd_buf; - cm->cmd_inp[0] = '\0'; - cm->cmd_rleft = 0; - cm->cmd_arglin = NULL; - cm->cmd_argc = 0; - cm->cmd_argv[0] = NULL; - cm->cmd_tdp = cm->cmd_tokbuf; - cm->cmd_tleft = sizeof(cm->cmd_tokbuf)-1; -} - -static int -cminchar(void) -{ - register int ch; - - if (!cminfile) - return fe_ctyin(); - - if ((ch = getc(cminfile)) == EOF) { - fclose(cminfile); - cminfile = NULL; - fprintf(stdout, "[EOF on \"%s\"]\n", cminfname); - ch = '\n'; /* Try to end gracefully */ - } else { - putc(ch, stdout); /* Echo file input char */ - fe_ctycmforce(); /* Ensure it's out */ - } - return ch; -} - -int -cmdaccum(struct cmd_s *cm) -{ - register int ch; - - /* Output prompt if not already there */ - if ((cm->cmd_flags & CMDF_INACCUM) == 0) { - printf("%s", cm->cmd_prm ? cm->cmd_prm : ">"); - cm->cmd_flags |= CMDF_INACCUM; - fe_ctycmforce(); /* Force out any pending tty output */ - } - - for (;;) { - if ((ch = cminchar()) < 0) /* Get char from file or TTY */ - break; /* Break out if EOF */ - - if (cm->cmd_left <= 1) { - error("Command line overflow (%d chars!); \"%.10s...\" flushed.\n", - (int)cm->cmd_blen, cm->cmd_buf); -#if 0 - fe_ctyinflush(); /* Flush any pending input */ -#endif - cmdreset(cm); - return cmdaccum(cm); - } - - *(cm->cmd_inp)++ = ch; - --(cm->cmd_left); - - /* Again, simple built-in handling; no dynamic specification of - ** activation chars. - */ - switch (ch) { - /* See if last char was activation char */ - case '\r': - case '\n': - cm->cmd_flags |= CMDF_ACTIVE; /* Got one! */ - *(cm->cmd_inp) = '\0'; - return TRUE; - } - } - return FALSE; /* No more input */ -} - -/* CMDEXEC - Called when we're known to have an activated command in buffer. -** Parse first keyword to see if it's anything recognizable, and -** invoke appropriate function if so. -*/ -int -cmdexec(struct cmd_s *cm) -{ - register char *cp; - char tokbuf[100]; - char *tcp = tokbuf; - size_t tcnt = sizeof(tokbuf); - size_t fcnt = cm->cmd_inp - cm->cmd_rdp; /* # chars left to read */ - struct cmkey_s *key, *key2; - register struct cmrtn_s *cd; - int argc; - - if (cpu.fe.fe_debug) { - *(cm->cmd_inp) = '\0'; - fprintf(stderr, "[cmdexec \"%s\"]", cm->cmd_rdp); - } - - /* Get first token on line */ - cp = s_1token(&tcp, &tcnt, &cm->cmd_rdp, &fcnt); - if (!cp) { /* If no token (empty line) */ - return 0; /* just return having done nothing */ - } - if (*cp == '\n' || *cp == '\r') /* If EOL, just return */ - return 0; /* without adding our own echo */ - if (*cp == ';') /* If start of comment, */ - return 0; /* ditto */ - - /* Have token, see if it's a command */ - stolower(cp); /* Force lowercase for lookup */ - argc = s_keylookup(cp, fectbkeys, sizeof(struct cmkey_s), - (void *)&key, (void *)&key2); - if (argc <= 0) { - printf("Unknown command: \"%s\"\n", cp); - return 0; - } - if (argc > 1) { - printf("Ambiguous command: \"%s\" => %s, %s%s\n", - cp, key->cmk_key, key2->cmk_key, - argc > 2 ? ", ..." : ""); - return 0; - } - - /* Found a single match! Execute it... */ - /* First set up its args as indicated by flags */ - cd = &(key->cmk_p->cmn_rtn); /* Get ptr to routine definition */ - cmdspfls(cm); /* Flush initial spaces from line */ - cm->cmd_arglin = cm->cmd_rdp; - cm->cmd_rleft = strlen(cm->cmd_rdp); - if (cd->cmr_flgs & CMRF_CMPTR) { - (*cd->cmr_vect)(cm); /* Special handling, no arg hackery */ - return 1; - } - slinlim(cm->cmd_rdp); /* Ensure no EOL in line */ - cm->cmd_rleft = strlen(cm->cmd_rdp); - if (cd->cmr_flgs & CMRF_NOARG) { - if (cm->cmd_rleft) { - printf("Bad syntax - no args allowed\n"); - return 0; - } - (*cd->cmr_vect)(cm); - return 1; - } else if (cd->cmr_flgs & CMRF_TLIN) { - /* That's all it wants - cmd_rleft will be set but cmd_argc is 0 */ - (*cd->cmr_vect)(cm); - return 1; - } - argc = cmdargs_all(cm); - if (cd->cmr_flgs & CMRF_TOKS) { - (*cd->cmr_vect)(cm); /* Invoke with all tokens set up */ - return 1; - } else return 0; - - return 1; -} - - -char * -cmdlsetup(struct cmd_s *cm) -{ - char *cp; - size_t len; - - if (cpu.fe.fe_debug) - fprintf(stderr, "[cmdlsetup]"); - - if (!(cm->cmd_flags & CMDF_NOPRM) && cm->cmd_prm) { - fputs(cm->cmd_prm, stdout); - } - - fe_ctycmforce(); /* Force out any pending tty output */ - cmdreset(cm); - if (cminfile) { - cp = fgets(cm->cmd_inp, (int)cm->cmd_left-1, cminfile); - if (!cp) { - fprintf(stdout, "[EOF on %s]\n", cminfname); - fclose(cminfile); - cminfile = NULL; - return cmdlsetup(cm); /* Try again using TTY */ - } - fputs(cp, stdout); /* Echo the input line */ - } else { - cp = fe_ctycmline(cm->cmd_inp, (int)cm->cmd_left-1); - if (cp == NULL) - return NULL; - } - - len = strlen(cp); - cm->cmd_left -= len; - cm->cmd_inp += len; - - return cp; -} - - -/* CMDFLS - Flush whitespace from current command pos -*/ -void -cmdspfls(register struct cmd_s *cm) -{ - register char *cp = cm->cmd_rdp; - - if (cp) - while (isspace(*cp)) ++cp; - cm->cmd_rdp = cp; -} - -/* Helper functions for FC_ commands */ - -static int -cmdargs_none(register struct cmd_s *cm) -{ - if (cm->cmd_rleft || cm->cmd_argc > 0) { - printf("Bad syntax - no args allowed\n"); - return 0; - } - return 1; -} - -static int -cmdargs_one(register struct cmd_s *cm, char **as1) -{ - if (cm->cmd_argc == 1) { - *as1 = cm->cmd_argv[0]; - return 1; - } - if (cm->cmd_argc > 1) { - printf("Bad syntax - too many args\n"); - } else - printf("Bad syntax - no arg\n"); - return 0; -} - -static int -cmdargs_two(register struct cmd_s *cm, char **as1, char **as2) -{ - if (cm->cmd_argc == 2) { - *as1 = cm->cmd_argv[0]; - *as2 = cm->cmd_argv[1]; - return 1; - } - printf("Bad syntax - need two args\n"); - return 0; -} - -static int -cmdargs_all(register struct cmd_s *cm) -{ - /* See if haven't yet tokenized line and there's something on it */ - if (cm->cmd_argc == 0 && cm->cmd_rleft) { - cm->cmd_argc = s_tokenize(cm->cmd_argv, - CMDMAXARG, - &cm->cmd_tdp, &cm->cmd_tleft, - &cm->cmd_rdp, &cm->cmd_rleft); - cm->cmd_argv[cm->cmd_argc] = NULL; - } - return cm->cmd_argc; /* Return # of tokens */ -} - -static int -cmdargs_n(register struct cmd_s *cm, int n) -{ - /* See if haven't yet tokenized line and there's something on it */ - if (cm->cmd_argc == 0 && cm->cmd_rleft) { - if (n > CMDMAXARG) - n = CMDMAXARG; - cm->cmd_argc = s_tokenize(cm->cmd_argv, - n, - &cm->cmd_tdp, &cm->cmd_tleft, - &cm->cmd_rdp, &cm->cmd_rleft); - cm->cmd_argv[cm->cmd_argc] = NULL; - } - return cm->cmd_argc; /* Return # of tokens parsed */ -} - -#ifndef CMVPAR_INCLUDED /* Using external parser stuff? */ -# define CMVPAR_INCLUDED 0 /* Nope, use our own */ -#endif - -#if !CMVPAR_INCLUDED - /* Use own internal parsing code */ - -struct cmkey_s * -cmdkeylookup(char *cp, - register struct cmkey_s *keytab, - register struct cmkey_s **key2) -{ - struct cmkey_s *key; - - (void) s_keylookup(cp, (voidp_t)keytab, sizeof(struct cmkey_s), - (voidp_t*)&key, (voidp_t*)key2); - return key; -} - -#endif /* !CMVPAR_INCLUDED */ - -static void -fc_ques(struct cmd_s *cm) -{ - printf("Type \"help\" or \"help \" for help.\n"); -} - -static void -helpline(register struct cmkey_s *kp) -{ - int cols; - register char *cp; - - if ((cols = 20 - strlen(kp->cmk_key)) < 0) - cols = 0; - if (!(cp = kp->cmk_p->cmn_rtn.cmr_synt)) - cp = ""; - if (cols < strlen(cp)) /* Key and syntax too long? */ - printf("%s %s\n %s\n", - kp->cmk_key, cp, kp->cmk_p->cmn_rtn.cmr_help); - else - printf("%s %-*s %s\n", - kp->cmk_key, cols, cp, kp->cmk_p->cmn_rtn.cmr_help); -} - -static void -fc_help(struct cmd_s *cm) -{ - struct cmkey_s *kp, *key2; - int cols; - register char *cp; - - /* Get first token on line. OK if NULL. */ - cp = cm->cmd_argv[0]; - - if (!cp || !*cp) { /* If no specific arg, show everything */ - for (kp = fectbkeys; kp->cmk_key; ++kp) { - helpline(kp); - } - return; - } - - (void) s_keylookup(cp, (voidp_t)fectbkeys, sizeof(struct cmkey_s), - (voidp_t *)&kp, (voidp_t *)&key2); - if (!kp) { - printf("Unknown command: \"%s\"\n", cp); - return; - } - if (!key2) { /* Just one match, so show it in detail */ - helpline(kp); - if ((cp = kp->cmk_p->cmn_rtn.cmr_desc) && *cp) - printf("%s\n", cp); - return; - } - - /* More than one match, show each one */ - for (kp = fectbkeys; kp->cmk_key; ++kp) { - if (smatch(cp, kp->cmk_key) > 0) - helpline(kp); - } -} - -/* SLINLIM - Limit string to 1 line by chopping it at first EOL seen. -*/ -static void -slinlim(register char *s) -{ - for (; *s; ++s) - if (*s == '\r' || *s == '\n') { - *s = '\0'; - break; - } -} - -static void -stolower(register char *s) -{ - for (; *s; ++s) - if (isupper(*s)) - *s = tolower(*s); -} - -/* SMATCH - compare strings -** Returns 0 if mismatched -** 1 if S1 is initial substring of S2 -** 2 if S1 is exact match of S2 -*/ -static int -smatch(register char *s1, - register char *s2) -{ - while (*s1) { - if (*s1++ != *s2++) - return 0; - } - return *s2 ? 1 : 2; -} - -/* KLH10_INIT - Actually an internal routine to initialize and configure -** the emulator. Could be considered analogous to "loading the -** microcode"... -*/ -static void -klh10_init(void) -{ - -#if KLH10_SYS_T20 && KLH10_CPU_KS -# if KLH10_CTYIO_ADDINT - cpu.fe.cty_lastint = 20; /* 20ms delay to add extra output-done int */ -# else - cpu.fe.fe_iowait = 50; /* Alternative for avoiding T20 CTY lossage */ -# endif -#endif - cpu.fe.fe_intchr = '\034'; /* Default int char is FS (ctrl-\) */ - cpu.mr_exsafe = 2; /* Default to exec-mode safety check/halt */ - - /* Move this to pag_init? */ - /* Some checking that couldn't be done at compile time */ - if (VMF_ACC & PAG_PAMSK) { - error("Pager access bits (%lx) overlap phys page mask (%lx)!\n", - (long)VMF_ACC, (long)PAG_PAMSK); - } - - - op_init(); /* Initialize runtime opcode dispatch tables */ -#if (KLH10_CPU_KS || KLH10_CPU_KL) && (KLH10_SYS_T10 || KLH10_SYS_T20) - { - extern void inexts_init(void); - inexts_init(); /* Initialize EXTEND instruction stuff */ - } -#endif - - /* Now can add in any special runtime cases */ - - mem_init(); /* Initialize memory */ - apr_init(); /* Initialize APR stuff (includes internal devs) */ - dev_init(); /* And general IO device stuff */ - cty_init(); /* And console TTY stuff */ -} - -/* MEM_INIT - Allocate & initialize PDP10 memory. -** Perhaps move this to pag_init? -*/ -static void -mem_init(void) -{ - size_t memsiz; - char *ptr; - - /* Determine amount of phys mem to get */ - memsiz = (size_t)PAG_SIZE * PAG_MAXPHYSPGS * sizeof(w10_t); - - /* Always attempt to get shared memory first. If that fails - ** (either because OS can't do it, or KLH10 was compiled without - ** support), then go for private memory. - */ - fprintf(stdout, "[MEM: Allocating %ld pages ", (long)PAG_MAXPHYSPGS); - if (os_mmcreate(memsiz, &cpu.mm_physegid, &ptr)) { - cpu.mm_shared = TRUE; - fprintf(stdout, "shared memory, clearing..."); - } else { - /* Failed - routine already barfed about it, if OS failure. */ - cpu.mm_shared = FALSE; - - /* Allocate private 10 memory */ - cpu.mm_physegid = 0; - fprintf(stdout, "private memory, clearing..."); - if (!(ptr = malloc(memsiz))) { - syserr(errno, "MEM: cannot malloc KN10 physical memory!\n"); - } - } - - cpu.physmem = (vmptr_t)ptr; - - /* To avoid unpleasant surprises to code that expects unused bits - ** of w10_t words to be zero, we clear it all to begin with. - */ - memset(ptr, 0, memsiz); /* Clear it all out */ - fprintf(stdout, "done]\n"); -} - -/* MEM_TERM - Terminate (de-init) memory stuff. -** Mainly intended to clean up shared-seg stuff. May later be useful -** for re-configuring memory. -** Will of course bomb completely if anything refs phys mem after -** this call... -*/ -static void -mem_term(void) -{ - if (cpu.mm_shared) { - os_mmkill(cpu.mm_physegid, (char *)cpu.physmem); - cpu.mm_physegid = 0; - } else { - free((char *)cpu.physmem); - } - cpu.physmem = NULL; - cpu.mm_shared = FALSE; -} - -static int -mem_setlock(FILE *of, FILE *ef, int nlockf) -{ - if (nlockf == cpu.mm_locked) { - if (of) - fprintf(of, "Memory already %slocked\n", nlockf ? "" : "un"); - return TRUE; - } - if (os_memlock(nlockf)) { - if (of) - fprintf(of, "Memory %slocked\n", nlockf ? "" : "un"); - cpu.mm_locked = nlockf; - return TRUE; - } else { - if (ef) - fprintf(ef, "Memory could not be %slocked - %s\n", - (nlockf ? "" : "un"), os_strerror(-1)); - return FALSE; - } -} - -/* Support routines for FC_SET - parameter parsing -*/ - -static int cmvp_prompt(struct prmvcx_s *); -static int cmvp_sethz(struct prmvcx_s *); -static int cmvp_setpri(struct prmvcx_s *); -static int cmvp_memlock(struct prmvcx_s *); - -extern int ld_debug; /* From feload.c */ -#if KLH10_DEBUG && KLH10_CPU_KS -extern int tim_debug; /* From kn10cpu.c */ -#endif -#if KLH10_CPU_KS -extern int ub_debug; /* From dvuba.c */ -#endif - -struct prmvar_s fecmvars[] = { - PRMVAR("sw", "Data switch word", - PRMVT_WRD, &cpu.mr_dsw, NULL, NULL), - PRMVAR("mem_lock", "Set on to attempt locking memory", - PRMVT_BOO, &cpu.mm_locked, cmvp_memlock, NULL), - PRMVAR("proc_pri", "CPU process priority", - PRMVT_DEC, &proc_pri, cmvp_setpri, NULL), - PRMVAR("cpu_debug", "General CPU debug trace", - PRMVT_BOO, &cpu.mr_debug, NULL, NULL), - PRMVAR("cpu_exsafe", "Enable exec mode safety halts", - PRMVT_OCT, &cpu.mr_exsafe, NULL, NULL), - PRMVAR("fe_intchr", "KLH10 cmd escape char", - PRMVT_OCT, &cpu.fe.fe_intchr, NULL, NULL), - PRMVAR("fe_prompt", "KLH10 cmd prompt", - PRMVT_STR, &cmdprompt, cmvp_prompt, NULL), - PRMVAR("fe_runenable", "Enable running KN10 during KLH10 cmd processing", - PRMVT_BOO, &cpu.fe.fe_runenable, NULL, NULL), - PRMVAR("fe_debug", "FE debug trace", - PRMVT_BOO, &cpu.fe.fe_debug, NULL, NULL), - PRMVAR("cty_debug", "CTY debug trace", - PRMVT_BOO, &cpu.fe.fe_ctydebug, NULL, NULL), -#if KLH10_SYS_T20 && KLH10_CPU_KS - PRMVAR("cty_iowait", "CTY output delay, usec", - PRMVT_DEC, &cpu.fe.fe_iowait, NULL, NULL), -# if KLH10_CTYIO_ADDINT - PRMVAR("cty_lastint", "CTY last-char extra output int, msec", - PRMVT_DEC, &cpu.fe.cty_lastint, NULL, NULL), -# endif -#endif -#if KLH10_DEBUG && KLH10_CPU_KS - PRMVAR("tim_debug", "KS timebase debug trace", - PRMVT_BOO, &tim_debug, NULL, NULL), -#endif -#if KLH10_CPU_KS - PRMVAR("ub_debug", "KS unibus debug info (bad ctl/addr warnings)", - PRMVT_BOO, &ub_debug, NULL, NULL), -#endif - PRMVAR("ld_fmt", "LOAD/DUMP word format", - PRMVT_STR, &ld_fmt, NULL, NULL), - PRMVAR("ld_debug", "LOAD debug trace", - PRMVT_BOO, &ld_debug, NULL, NULL), - PRMVAR("insbreak", "APR loop interrupt", - PRMVT_DEC, &cpu.mr_insbreak, NULL, NULL), -#if KLH10_CLKTRG_COUNT - PRMVAR("clk_ipms", "Instrs per virt msec", - PRMVT_DEC, &cpu.clk.clk_ipmsrq, - cmvp_sethz,NULL), -#endif -#if 1 /* KLH10_CLKTRG_OSINT */ - PRMVAR("clk_ithz", "OS interval timer - current value in Hz", - PRMVT_DEC, &cpu.clk.clk_ithzcmreq, - cmvp_sethz, NULL), - PRMVAR("clk_ithzfix", "ITimer value fixed at this if non-zero", - PRMVT_DEC, &cpu.clk.clk_ithzfix, - cmvp_sethz, NULL), - PRMVAR("clk_ithzosreq", "ITimer value last requested by OS", - PRMVT_DEC, &cpu.clk.clk_ithzosreq, - NULL, NULL), -#endif - PRMVAR("pisys_on", "Set if PI sys on", - PRMVT_OCT, &cpu.pi.pisys_on, NULL, NULL), - PRMVAR("pilev_on", "Levs enabled", - PRMVT_OCT, &cpu.pi.pilev_on, NULL, NULL), - PRMVAR("pilev_pip", "Levs PI in Progress", - PRMVT_OCT, &cpu.pi.pilev_pip, NULL, NULL), - PRMVAR("pilev_preq", "Prog PI reqs", - PRMVT_OCT, &cpu.pi.pilev_preq, NULL, NULL), - PRMVAR("pilev_aprreq", "APR PI reqs", - PRMVT_OCT, &cpu.pi.pilev_aprreq, NULL, NULL), - PRMVAR("pilev_dreq", "Device PI reqs", - PRMVT_OCT, &cpu.pi.pilev_dreq, NULL, NULL), -#if KLH10_CPU_KS - PRMVAR("pilev_ub1req", "UBA #1 PI reqs", - PRMVT_OCT, &cpu.pi.pilev_ub1req, NULL, NULL), - PRMVAR("pilev_ub3req", "UBA #3 PI reqs", - PRMVT_OCT, &cpu.pi.pilev_ub3req, NULL, NULL), -#endif -#if KLH10_CPU_KL - PRMVAR("pilev_rhreq", "RH20 PI reqs", - PRMVT_OCT, &cpu.pi.pilev_rhreq, NULL, NULL), - PRMVAR("pilev_dtereq", "DTE20 PI reqs", - PRMVT_OCT, &cpu.pi.pilev_dtereq, NULL, NULL), -#endif - PRMVAR("feiosignulls", "# SIGIOs with no input", - PRMVT_DEC, &feiosignulls, NULL, NULL), - PRMVAR("feiosiginps", "# SIGIOs with CTY input", - PRMVT_DEC, &feiosiginps, NULL, NULL), - PRMVAR("feiosigtests", "# non-SIGIO tests in above", - PRMVT_DEC, &feiosigtests, NULL, NULL), - PRMVAR(NULL, "", PRMVT_NULL, NULL, NULL, NULL) -}; - -/* Various parameter get/set auxiliary functions */ - -static int -cmvp_prompt(register struct prmvcx_s *cx) -{ - /* First just set requested value normally */ - if (!prmvp_set(cx)) - return FALSE; /* Problem setting param? Already reported */ - - /* Then must do special re-init stuff */ - fe_cmpromptset(cmdprompt); - cmdpromptnew = TRUE; - return TRUE; -} - -static int -cmvp_memlock(register struct prmvcx_s *cx) -{ - return mem_setlock(cx->prmvcx_of, cx->prmvcx_ef, cx->prmvcx_val.vi); -} - -static int -cmvp_setpri(register struct prmvcx_s *cx) -{ - ospri_t npri = cx->prmvcx_val.vi; - ospri_t opri; - - if (os_setpriority(npri) == FALSE) { - if (cx->prmvcx_ef) - fprintf(cx->prmvcx_ef, "Could not change priority - %s\n", - os_strerror(-1)); - return FALSE; - } - if (os_getpriority(&opri) == FALSE) { - if (cx->prmvcx_ef) - fprintf(cx->prmvcx_ef, "Could not find priority - %s\n", - os_strerror(-1)); - return FALSE; - } - if (cx->prmvcx_of) { - if (opri == proc_pri) - fprintf(cx->prmvcx_of, "Process priority remains %ld\n", - (long)opri); - else - fprintf(cx->prmvcx_of, "Process priority changed from %ld to %ld\n", - (long)proc_pri, (long)opri); - } - proc_pri = opri; - return TRUE; -} - -static int -cmvp_sethz(register struct prmvcx_s *cx) -{ - /* First just set requested value normally */ - if (!prmvp_set(cx)) - return FALSE; /* Problem setting param? Already reported */ - - /* Then must do special re-init stuff */ -#if KLH10_CLKTRG_COUNT - clk_ipmsset(cpu.clk.clk_ipmsrq); -#elif KLH10_CLKTRG_OSINT - clk_ithzset(cpu.clk.clk_ithzcmreq); -#endif - return TRUE; -} - - -static int -addrparse(register char *str, - vaddr_t *vloc, - enum fevmmode *mloc) -{ - w10_t w; - enum fevmmode mode = FEVM_DFLT; - int local = FALSE, global = FALSE; - - if (!str) return FALSE; - while (isalpha(*str)) { - switch (islower(*str) ? toupper(*str++) : *str++) { - case 'L': local = TRUE; break; - case 'G': global = TRUE; break; - case 'C': mode = FEVM_CUR; break; - case 'P': mode = FEVM_PHYS; break; - case 'E': mode = FEVM_EXEC; break; - case 'U': mode = FEVM_USER; break; - case 'A': mode = FEVM_ACB; break; - default: - return 0; /* Bad syntax, unknown char */ - } - } - *mloc = mode; - - /* Note distinction between 123456 and 0,,123456 - ** (ie explicit specification of section #) - */ - switch (s_towd(str, &w)) { - default: /* Bad syntax of address */ - return FALSE; - case 1: /* One value: */ - if (!local && !global) /* If not otherwise specified, */ - local = TRUE; /* defaults to local */ - break; - case 2: /* Two values: ,, */ - if (!local && !global) /* If not otherwise specified, */ - global = TRUE; /* defaults to global */ - break; - } - - /* Problem if local - where does default section # come from? - ** Depends on mode, but even the mode gets hairy. - */ - if (mode == FEVM_ACB) { /* Special hack, ac block # in LH */ - if ((LHGET(w) & ~(h10_t)07) /* Only allow blocks 0-7 */ - || (RHGET(w) & ~(h10_t)AC_MASK)) /* and ACs 0-017 */ - return FALSE; - va_hmake(*vloc, LHGET(w), RHGET(w)); - return TRUE; - } - if (local) - va_lmake(*vloc, LHGET(w) & VAF_SMSK, RHGET(w)); - else - va_gmake(*vloc, LHGET(w) & VAF_SMSK, RHGET(w)); - return TRUE; -} - - -/* FC_SET - Set/Show KLH10 variables -*/ -static void -fc_set(struct cmd_s *cm) -{ - struct prmvar_s *p1, *p2; - int res; - char *cp = cm->cmd_arglin; - - if (!cp || !*cp /* If no arg, show all vars */ - || *cp == '?') { /* Ditto if starts with ? */ - for (p1 = fecmvars; p1->prmv_name; ++p1) - prm_varshow(p1, stdout); - return; - } - if (!strchr(cp, '=')) { /* If doesn't look like var=val */ - res = s_keylookup(cp, (voidp_t)fecmvars, sizeof(*p1), - (voidp_t*)&p1, (voidp_t*)&p2); - if (res == 1) { - prm_varshow(p1, stdout); - } else if (res > 1) { - fprintf(stdout, "Ambiguous variable: \"%s\", \"%s\"%s\n", - p1->prmv_name, p2->prmv_name, (res > 2 ? ", ..." : "")); - } else { - fprintf(stdout, "Unknown var or bad syntax, must be =\n"); - } - return; - } - - prm_varset(&cp, fecmvars, stdout, stdout); -} - - -/* Device control commands */ - -/* FC_DEVLOAD - Load a dynamic/shared library as a device driver, -** and defines its name for later use in configuration. -** -** Syntax is: -** devload [] -** -** where -** - Arbitrary device driver name. -** - Pathname for library in native OS. -** - "Entry point" symbol (init/config routine) -** - Optional description text -*/ -static void -fc_devload(struct cmd_s *cm) -{ - if (cmdargs_n(cm, 3) != 3) { - printf("?Bad syntax - usage: %s\n", cd_devload.cmr_synt); - return; - } - stolower(cm->cmd_argv[0]); /* Driver name forced to lowercase */ - (void) dev_drvload(stdout, - cm->cmd_argv[0], - cm->cmd_argv[1], - cm->cmd_argv[2], - cm->cmd_rdp); -} - - -/* FC_DEVDEF - Do initial device configuration -** Defines the device name and does its initial configuration setup. -** -** Syntax is: -** devdefine { <10dev> } [] -** { UB } -** where -** - Name to identify device -** <10dev> - A PDP-10 device number, or predefined keyword (CTY, etc) -** Implies device uses dev-IO instructions. -** UB - A Unibus controller (n = 1 or 3) -** Implies device uses KS IO instructions. -** - Name of a driver module, either builtin or dynamic. -** - Optional args to dev's init routine (rest of line) -** -** NOTE: this replaces old design of: -** devconf { <10dev> } {static } -** { UB } {extern } -** but the static/extern option has been replaced by DEVLOAD. -*/ -static void -fc_devdef(struct cmd_s *cm) -{ - if (cmdargs_n(cm, 3) != 3) { - printf("?Bad syntax - usage: %s\n", cd_devdef.cmr_synt); - return; - } - stolower(cm->cmd_argv[0]); /* Driver name forced to lowercase */ - stolower(cm->cmd_argv[1]); /* Device number ditto */ - stolower(cm->cmd_argv[2]); /* Driver name ditto */ - (void) dev_define(stdout, - cm->cmd_argv[0], - cm->cmd_argv[1], - cm->cmd_argv[2], - cm->cmd_rdp); -} - - -static void -fc_devshow(struct cmd_s *cm) -{ - /* Pass first token on line. OK if NULL. */ - (void) cmdargs_n(cm, 1); - (void) dev_show(stdout, cm->cmd_argv[0], cm->cmd_rdp); -} - -#if KLH10_EVHS_INT -static void -fc_devevshow(struct cmd_s *cm) -{ - /* Pass first token on line. OK if NULL. */ - (void) cmdargs_n(cm, 1); - (void) dev_evshow(stdout, cm->cmd_argv[0], cm->cmd_rdp); -} -#endif /* KLH10_EVHS_INT */ - -/* FC_DEVSET - Hack defined device from 10 side -** For use when need to set device-related things from the 10's side of -** the fence, for a specific device. -** Syntax: -** devset = [devvar2>= ...] -*/ -static void -fc_devset(char *argline) -{ -} - - -/* FC_DEV_CMD - Generic device command -** Syntax: dev -** -** Invokes device's command parsing and execution, which can be anything -** the device wants to do with the line. Most should follow certain -** conventions, however: -** dev help - Show what this device understands -** dev status - Show status in appropriate form -** dev show [param] [...] - Show specific device vars -** dev set [param=val] [...] - Set them -*/ -static void -fc_dev_cmd(struct cmd_s *cm) -{ - /* Consume first token on line - must exist */ - if (cmdargs_n(cm, 1) != 1) { /* If no token */ - printf("Bad dev cmd syntax, need device specifier\n"); - return; - } - (void) dev_command(stdout, cm->cmd_argv[0], cm->cmd_rdp); -} - - -static void -fc_dev_help(struct cmd_s *cm) -{ - /* Pass first token on line. OK if NULL. */ - (void) cmdargs_n(cm, 1); - (void) dev_help(stdout, cm->cmd_argv[0], cm->cmd_rdp); -} - -static void -fc_dev_status(struct cmd_s *cm) -{ - /* Pass first token on line. OK if NULL. */ - (void) cmdargs_n(cm, 1); - (void) dev_status(stdout, cm->cmd_argv[0], cm->cmd_rdp); -} - -static void -fc_devmnt(struct cmd_s *cm) -{ - char *spath; - - /* Consume first two tokens on line - must exist */ - switch (cmdargs_n(cm, 2)) { - case 0: - printf("Bad syntax - must be specified\n"); - return; - case 1: - spath = ""; /* Ensure 2nd arg non-null as NULL means dismount */ - break; - default: - spath = cm->cmd_argv[1]; - break; - } - (void) dev_mount(stdout, cm->cmd_argv[0], spath, cm->cmd_rdp); - fedevchkf = dev_dpchk_ctl(TRUE); /* Start periodic checks if nec */ -} - -static void -fc_devunmnt(struct cmd_s *cm) -{ - /* Consume first token on line - must exist */ - if (cmdargs_n(cm, 1) != 1) { /* If no token */ - printf("Bad syntax - must be specified\n"); - return; - } - (void) dev_mount(stdout, cm->cmd_argv[0], (char *)NULL, cm->cmd_rdp); - fedevchkf = dev_dpchk_ctl(TRUE); /* Start periodic checks if nec */ -} - -static void -fc_devdbg(struct cmd_s *cm) -{ - /* Pass first two tokens on line. OK if NULL. */ - if (cmdargs_n(cm, 2) < 1) - cm->cmd_argv[1] = NULL; - (void) dev_debug(stdout, cm->cmd_argv[0], cm->cmd_argv[1], cm->cmd_rdp); -} - -static void -fc_devwait(struct cmd_s *cm) -{ - char *dev; - long totsec = -1; - osstm_t stm; /* Sleep time spec */ - - /* Consume first two tokens on line. OK if NULL. */ - switch (cmdargs_n(cm, 2)) { - case 0: - dev = NULL; /* All devices */ - totsec = -1; /* Indefinitely */ - break; - case 1: /* One arg, either or */ - dev = cm->cmd_argv[0]; - if (s_todnum(dev, &totsec)) - dev = NULL; /* Numeric, is */ - else - totsec = -1; /* Not numeric, is */ - break; - default: - dev = cm->cmd_argv[0]; - if (!s_todnum(cm->cmd_argv[1], &totsec)) { - printf("Bad syntax - \"%s\" must be timeout in secs\n", - cm->cmd_argv[1]); - return; - } - break; - } - - /* OK, now start the wait. */ - OS_STM_SET(stm, totsec); - while (dev_waiting(stdout, dev)) { - if (os_msleep(&stm) <= 0) - break; /* Stop waiting if timed out */ - } -} - -/* FC_DEVBOOT - Boot using specified device. -** devboot [halt] -** Uses device's "read-in mode" to read in a small piece of -** bootstrap code and starts execution there. -** If option "halt" given, doesn't actually start PDP-10, -** just sets start addr so if continued will start bootstrap. -*/ -static void -fc_devboot(struct cmd_s *cm) -{ - int opthalt = FALSE; - vaddr_t bootsa; - - if (!aprhalted()) { - printf("KN10 still running! Halt or Reset it first.\n"); - return; - } - - /* Consume first two tokens on line */ - switch (cmdargs_n(cm, 2)) { - case 0: - printf("Bad syntax - must be specified\n"); - return; - case 1: - break; - default: - if (strcasecmp(cm->cmd_argv[1], "halt")==0) - opthalt = TRUE; - else { - printf("Unknown option \"%s\"\n", cm->cmd_argv[1]); - return; - } - break; - } - - if (!dev_boot(stdout, cm->cmd_argv[0], &bootsa)) { - printf("Bootstrap readin of %s failed\n", cm->cmd_argv[0]); - return; - } - - /* Success! Set up returned boot address as both new PC and new - start address, and maybe go. - */ - ddt_loadsa = bootsa; - PC_SET(bootsa); - if (opthalt) { - printf("Bootstrap read in, halted with PC = %lo\n", (long)bootsa); - return; - } - printf("Bootstrap read in\n"); - fe_aprcont(FEMODE_CTYRUN, FEAPRF_START, bootsa, 0); -} - -/* FC_RESET - Halts and Resets PDP-10 (clears all status) -*/ -static void -fc_reset(struct cmd_s *cm) -{ - fc_halt(cm); /* Ensure halted if not already */ - apr_init(); -} - -/* FC_GO - Starts PDP-10 at given location. Defaults to last -** loaded start address, if any. -*/ -static void -fc_go(struct cmd_s *cm) -{ - vaddr_t loc; - enum fevmmode mode; - char *sloc = cm->cmd_arglin; - - if (!aprhalted()) { - printf("KN10 still running! Halt or Reset it first.\n"); - return; - } - - if (sloc && *sloc) { - if (!addrparse(sloc, &loc, &mode)) { - printf("?Bad address\n"); - return; - } else if (mode != FEVM_DFLT && mode != FEVM_CUR) { - printf("?Bad address mode - only Current allowed\n"); - return; - } else if (va_isglobal(loc)) { - printf("?Bad address - only local allowed\n"); - return; - } - ddt_loadsa = loc; /* Mode will always be current */ - } - fe_aprcont(FEMODE_CTYRUN, FEAPRF_START, ddt_loadsa, 0); -} - -/* FC_CONT - Continues PDP-10 at current PC. -** Safe to call this even if KN10 is running. -** -*/ -static void -fc_cont(struct cmd_s *cm) -{ - fe_aprcont(FEMODE_CTYRUN, - (aprhalted() ? FEAPRF_VERBOSE : 0), - 0, 0); -} - -/* FE_APRCONT - Resume execution. -** (old startf: +1 start, 0 continue, -1 continue verbosely) -*/ -void -fe_aprcont(int femode, - int startf, - vaddr_t newpc, - int nsteps) -{ - int res; - - if (cpu.fe.fe_debug) - fprintf(stderr, "[aprcont %o 0x%x %d, intf_fecty %d]", - femode, startf, nsteps, cpu.intf_fecty); - - if (fedevchkf) - fedevchkf = dev_dpchk_ctl(FALSE); /* Turn off dev checking! */ - if (startf & FEAPRF_START) - PC_SET(newpc); - - if (startf & (FEAPRF_START | FEAPRF_VERBOSE)) - printf("%s KN10 at loc %#lo...\n", - ((startf&FEAPRF_START) ? "Starting" : "Continuing"), - (long)PC_30); - - /* Set up TTY handling appropriately for running */ - fe_ctyenable(femode); /* No echo, no CR/LF hacks, no delay */ - cpu.mr_running = TRUE; - cpu.mr_1step = nsteps; - res = apr_run(); /* Go! */ - cpu.mr_running = FALSE; - fe_ctydisable((res == HALT_FECMD) /* Restore TTY mode if necessary */ - ? FEMODE_CMDRUN - : FEMODE_CMDHALT); - switch (res) { - case HALT_PROG: /* Program halt (JRST 4,) */ - printf("[HALTED: Program Halt, PC = %lo]\n", (long)PC_30); - break; - - case HALT_FECTY: /* FE Console interrupt */ - printf("[HALTED: FE interrupt]\n"); - break; - - case HALT_FECMD: /* FE Console command ready to execute */ - break; - - case HALT_BKPT: /* Hit breakpoint */ - printf("[HALTED: Breakpoint]\n"); - break; - - case HALT_STEP: /* Single-Stepping */ - break; - - case HALT_EXSAFE: /* Something bad in exec mode */ - printf("[HALTED: Exec program error? (\"set cpu_exsafe=1\" to continue)]\n"); - break; - - case HALT_PANIC: /* Panic - internal error, bad state */ - printf("[HALTED: Panic - may be in inconsistent state]\n"); - break; - } -} - - -static int aprhalted(void) -{ - if (cpu.fe.fe_mode == FEMODE_CMDRUN) - return FALSE; - return TRUE; -} - -/* FC_SHUTDOWN - Halts PDP-10 OS gracefully if possible, by -** putting cruft in the shutdown location of the FECOM area. -** Assumes physical mapping, as does the CTY code. -** -** KA/KI versions would probably set the data switches here. -*/ -static void -fc_shutdown(struct cmd_s *cm) -{ - register vmptr_t vp; - - vp = vm_physmap(FECOM_SWIT0); /* Find loc for data-switch 0 sim */ - op10m_seto(*vp); /* Set word to ones */ - fc_cont(cm); /* Resume CPU, let OS do rest */ -} - -/* FC_HALT - Halts PDP-10 violently. -** Not needed until true threads/subprocess version exists, since -** currently any interaction with KLH10 commands means the 10 is -** already stopped! -*/ -static void -fc_halt(struct cmd_s *cm) -{ - if (aprhalted()) { - printf("KN10 already halted.\n"); - return; - } - cpu.fe.fe_mode = FEMODE_CMDHALT; - printf("[HALTED: FE command, PC = %lo]\n", (long)PC_30); -} - - -/* Various commands primarily for debugging */ - -/* FC_ZERO - Clears first 256K of physical memory -*/ -static void -fc_zero(struct cmd_s *cm) -{ - memset((char *)vm_physmap(0), 0, sizeof(w10_t)*(H10MASK+1)); /* Zap! */ - printf("OK\n"); -} - -/* FC_TRACE - Toggles execution tracing -*/ -static void -fc_trace(struct cmd_s *cm) -{ - if (cpu.mr_dotrace) { - cpu.mr_dotrace = 0; - printf("Tracing now off\n"); - } else { - cpu.mr_dotrace = TRUE; - printf("Tracing now ON\n"); - } -} - -#if 0 /* Not bound to a command now, use SET. */ - -/* FC_DEBUG - Toggles general debug flag -*/ -static void -fc_debug(void) -{ - if (cpu.mr_debug) { - cpu.mr_debug = 0; - printf("Debug now off\n"); - } else { - cpu.mr_debug = TRUE; - printf("Debug now ON\n"); - } -} -#endif - -/* FC_STEP - Single-steps by N instructions. -*/ -static void -fc_step(struct cmd_s *cm) -{ - char *snum = cm->cmd_arglin; - long n = 1; - - if (!aprhalted()) { - printf("KN10 still running! Halt it first.\n"); - return; - } - - if (snum && *snum) - if (!s_tonum(snum, &n)) { - printf("?Bad count syntax\n"); - return; - } - if (n <= 0) { - printf("?Bad step count\n"); - return; - } - fe_aprcont(FEMODE_CTYRUN, 0, 0, n); - putchar('\n'); - nextinsprint(stdout, PINSTR_OPS); -} - -/* FC_BKPT - Sets location to stop at. 0 clears. -*/ -static void -fc_bkpt(struct cmd_s *cm) -{ - vaddr_t loc; - enum fevmmode mode; - char *sloc = cm->cmd_arglin; - - if (sloc && *sloc) { - if (!addrparse(sloc, &loc, &mode)) { - printf("?Bad address\n"); - return; - } else if (mode != FEVM_DFLT && mode != FEVM_CUR) { - printf("?Bad address mode - only Current allowed\n"); - return; - } else if va_isglobal(loc) { - printf("?Bad address - only local allowed\n"); - return; - } - - cpu.mr_bkpt = loc; /* Mode will always be current */ - } -} - - -/* FC_PROC - Proceed KN10 without CTY -*/ -static void -fc_proc(struct cmd_s *cm) -{ - if (!aprhalted()) { - /* Should only happen if already in FEMODE_CMDRUN */ - printf("KN10 already running\n"); - return; - } - cpu.fe.fe_mode = FEMODE_CMDRUN; /* Change mode! */ -} - - - - -/* FC_EXNEXT - Examine next word -** FC_EXPREV - Previous word -*/ -static void -fc_exnext(struct cmd_s *cm) -{ - va_inc(ddt_cloc); - fc_exa((struct cmd_s *)NULL); -} - -static void -fc_exprev(struct cmd_s *cm) -{ - va_dec(ddt_cloc); - fc_exa((struct cmd_s *)NULL); -} - -/* FC_EXA - Examine PDP-10 word -*/ -static void -fc_exa(struct cmd_s *cm) -{ - vaddr_t loc; - enum fevmmode mode; - register vmptr_t vp; - char *sloc; - - sloc = (cm ? cm->cmd_arglin : NULL); - - if (sloc && *sloc) { - if (!addrparse(sloc, &loc, &mode)) { - printf("?Bad address\n"); - return; - } else if (mode != FEVM_DFLT) - ddt_clmode = mode; /* Set new mode if not default */ - ddt_cloc = loc; - } - - putchar(' '); - addrprint(stdout, ddt_cloc, ddt_clmode); - putchar('/'); - putchar(' '); - - if (vp = fevm_xmap(ddt_cloc, ddt_clmode)) { - ddt_val = vm_pget(vp); - wd1print(stdout, ddt_val); - if (LHGET(ddt_val) & 0777000) { /* Opcode exists? */ - putchar('\t'); - pinstr(stdout, ddt_val, 0, ddt_cloc/*unused*/); - } - } else - fprintf(stdout, "\?\?"); - - putchar('\n'); -} - -/* FC_DEP - Deposit PDP-10 word -*/ -static void -fc_dep(struct cmd_s *cm) -{ - w10_t wd; - vaddr_t loc; - register vmptr_t vp; - enum fevmmode mode; - char *sloc, *sval; - - if (!cmdargs_two(cm, &sloc, &sval)) - return; - - if (sloc && *sloc) { - if (!addrparse(sloc, &loc, &mode)) { - printf("?Bad address\n"); - return; - } else if (mode != FEVM_DFLT) - ddt_clmode = mode; /* Set new mode if not default */ - ddt_cloc = loc; - } - - if (!sval || !*sval || !s_towd(sval, &wd)) { - printf("?Bad word syntax\n"); - return; - } - ddt_val = wd; - - if (vp = fevm_xmap(ddt_cloc, ddt_clmode)) - vm_pset(vp, ddt_val); - else { - printf("?Cannot map address "); - addrprint(stdout, ddt_cloc, ddt_clmode); - printf(" - value not deposited\n"); - } -} - -static vmptr_t -fevm_map(paddr_t pa) -{ - if ((pa & ~AC_MASK)==0) - return &cpu.acblk.cur[pa]; /* Use currently active AC block */ - - /* For now, assume physical memory mapping. - ** Later, can use current page map and report error if any failures. - */ - return vm_physmap(pa & H10MASK); -} - -vmptr_t -fevm_xmap(vaddr_t e, enum fevmmode mode) -{ - register pment_t *map; - register acptr_t acp; - register int acb; - - switch (mode) { - default: - case FEVM_CUR: acp = cpu.acblk.cur; map = cpu.vmap.cur; break; - case FEVM_PHYS: acp = cpu.acblk.cur; map = pr_pmap; break; - case FEVM_USER: acp = cpu.acblk.cur; map = cpu.pr_umap; break; - case FEVM_EXEC: acp = cpu.acblk.cur; map = cpu.pr_emap; break; - case FEVM_ACB: - /* Ensure AC block # in LH is 0-7 and AC # in RH is 0-017 inclusive */ - acb = va_lh(e); - if ((acb & ~07) || (va_insect(e) & ~(h10_t)AC_MASK)) - return NULL; /* Ugh, one of them out of range */ - return &cpu.acblks[acb][va_ac(e)]; /* Use AC in right block */ - } - return vm_xtrymap(e, VMF_READ, acp, map); -} - -static int -fevm_tryeacalc(register w10_t *wp, - register acptr_t acp, - register pment_t *map, - int indcnt) /* Indirection level count */ -{ - register h10_t tmp; - register vmptr_t vp; - -#if KLH10_EXTADR -/* - * ERROR * Need to revise this for XA -*/ -#endif - for (;;) { - if ((tmp = LHGET(*wp)) & IW_X) { /* Indexing? */ - register w10_t wea; - wea = ac_xget(tmp & IW_X, acp); /* Get c(X) */ - LHSET(*wp, LHGET(wea)); - RHSET(*wp, (RHGET(*wp)+RHGET(wea))&H10MASK); /* Add previous Y */ - } - if (!(tmp & IW_I)) /* Indirection? */ - return TRUE; /* Nope, return now! */ - - /* Handle indirection */ - if (--indcnt < 0) - return FALSE; - if ((vp = vm_xtrymap(RHGET(*wp), VMF_READ, acp, map)) == NULL) - return FALSE; - *wp = vm_pget(vp); - } -} - -/* FC_VIEW - Show PDP-10 status summary -*/ -static void -fc_view(struct cmd_s *cm) -{ - printf("KN10 status: %s %s", - (cpu.fe.fe_mode == FEMODE_CMDRUN ? "RUNNING" : "STOPPED"), - (cpu.mr_usrmode ? "USER" : "EXEC")); - if (cpu.mr_inpxct) printf(" PXCT-%o", cpu.mr_inpxct); - if (cpu.mr_intrap) printf(" TRAP-%o", cpu.mr_intrap); - if (cpu.mr_injrstf) printf(" JRSTF"); /* Either on or off */ - putchar('\n'); - -#if KLH10_JPC - printf(" PC: %lo [JPC: %lo UJPC: %lo EJPC: %lo]\n", - (long)PC_30, - (long)cpu.mr_jpc, (long)cpu.mr_ujpc, (long)cpu.mr_ejpc); -#if KLH10_ITS_JPC - printf(" ITSPAGER UJPC: %lo EJPC: %lo\n", - (long)cpu.pag.pr_ujpc, (long)cpu.pag.pr_ejpc); -#endif -#endif /* KLH10_JPC */ - printf(" Flags: %lo\n", (long)cpu.mr_pcflags); - - nextinsprint(stdout, PINSTR_OPS); -} - -/* FE_TRACEPRINT called from APR loop if tracing and about to execute -** an instruction. -*/ - -void -fe_traceprint(register w10_t instr, - vaddr_t e) -{ - pishow(stdout); - pcfshow(stdout, cpu.mr_pcflags); - printf("%lo: ", (long)PC_30); - - pinstr(stdout, instr, PINSTR_OPS|PINSTR_EA, e); - putc('\r', stdout); - putc('\n', stdout); -} - -void -fe_begpcfdbg(FILE *f) -{ - putc('[', f); - pishow(f); - pcfshow(f, cpu.mr_pcflags); - fprintf(f,"%lo: => ", (long) PC_30); -} - -void -fe_endpcfdbg(FILE *f) -{ - pishow(f); - pcfshow(f, cpu.mr_pcflags); - fprintf(f,"%lo:]\r\n", (long) PC_30); -} - -void -pishow(FILE *f) /* Show PI status */ -{ - register int lev, num; - if (cpu.pi.pilev_pip) { - num = pilev_nums[cpu.pi.pilev_pip]; /* Find level # */ - fprintf(f, "PI%o", num); - lev = cpu.pi.pilev_pip & ~pilev_bits[num]; /* And remaining PIPs */ - if (lev) { - fputc('[', f); - while (lev) { - num = pilev_nums[lev]; /* Find level # */ - fprintf(f, "%o", num); - lev &= ~pilev_bits[num]; - } - putc(']', f); - } - putc(' ', f); - } -} - -struct { h10_t flag; char ch; } flgtab[] = { - { PCF_ARO, 'O'}, /* Arithmetic Overflow (or Prev Ctxt Public) */ - { PCF_CR0, 'C'}, /* Carry 0 - Carry out of bit 0 */ - { PCF_CR1, 'c'}, /* Carry 1 - Carry out of bit 1 */ - { PCF_FOV, 'F'}, /* Floating Overflow */ - { PCF_FPD, '1'}, /* First Part Done */ - { PCF_USR, 'U'}, /* User Mode */ - { PCF_UIO, 'I'}, /* User In-Out (or Prev Ctxt User) */ - { PCF_PUB, 'P'}, /* Public Mode */ - { PCF_AFI, 'A'}, /* Addr Failure Inhibit */ -#if 0 /* Special-cased */ - { PCF_TR2, 'x'}, /* Trap 2 (PDL overflow) */ - { PCF_TR1, 'x'}, /* Trap 1 (Arith overflow) */ -#endif - { PCF_FXU, 'f'}, /* Floating Exponent Underflow */ - { PCF_DIV, 'D'} /* No Divide */ -}; - -void /* Show PC Flag status */ -pcfshow(FILE *f, - register h10_t flags) -{ - register int i; - - if (flags & (PCF_TR1|PCF_TR2)) { - fprintf(f, "TRAP%o ", (int)FLDGET((uint32)flags, (PCF_TR1|PCF_TR2))); - flags &= ~(PCF_TR1|PCF_TR2); - } - for (i = 0; flags && i < (sizeof(flgtab)/sizeof(flgtab[0])); ++i) - if (flags & flgtab[i].flag) { /* Found it? */ - flags &= ~flgtab[i].flag; /* Turn off */ - putc(flgtab[i].ch, f); - } - if (flags) { /* If any flags still left, */ - fprintf(f, "[PCF: %#lo]", (long)flags); /* show those too */ - } - putc(' ', f); -} - -static void -nextinsprint(FILE *f, - int argf) -{ - w10_t w; - vmptr_t vp; - vaddr_t e; - - fprintf(f, "Next: "); - pishow(f); - pcfshow(f, cpu.mr_pcflags); - fprintf(f, " %lo/ ", (long)PC_30); - - e = PC_VADDR; - if (!(vp = fevm_xmap(e, FEVM_CUR))) { - fprintf(f, " \?\?\n"); - return; - } - w = vm_pget(vp); - if (LHGET(w) & 0777000) { - pinstr(f, w, argf, e/*unused*/); - } else - wd2print(f, w); - fprintf(f, "\n"); -} - - -/* Print address as symbolic if possible. -** This function isn't called by anything yet. -*/ -static void -easymprint(FILE *f, - register vaddr_t e) -{ - - /* Take care of any randomly set bits in LH */ - if (va_lh(e)) fprintf(f, "%lo,,", (long)va_lh(e)); - - /* Now attempt to look up RH value as symbol? */ - - - fprintf(f, "%lo", (long)va_insect(e)); /* Punt for now */ -} - -static void -wd1print(FILE *f, - w10_t w) -{ - if (LHGET(w)) fprintf(f, "%lo,,", (long)LHGET(w)); - fprintf(f, "%lo", (long)RHGET(w)); -} - -static void -wd2print(FILE *f, - w10_t w) -{ - fprintf(f, "%lo,,%lo", (long)LHGET(w), (long)RHGET(w)); -} - - -static void -addrprint(FILE *f, - vaddr_t vloc, - enum fevmmode mode) -{ - register pment_t *map = cpu.vmap.cur; - register int ch; - - switch (mode) { - default: - case FEVM_CUR: ch = 0; break; - case FEVM_PHYS: ch = (map == pr_pmap) ? 0 : 'P'; break; - case FEVM_USER: ch = (map == cpu.pr_umap) ? 0 : 'U'; break; - case FEVM_EXEC: ch = (map == cpu.pr_emap) ? 0 : 'E'; break; - case FEVM_ACB: ch = 'A'; break; - } - - if (ch) { - putc(ch, f); - putc(' ', f); - } - if (va_lh(vloc)) { - fprintf(f, "%lo,,", (long)va_lh(vloc)); - } - fprintf(f, "%#lo", (long)va_insect(vloc)); -} - -static char * -strf6(char **acp, - register w10_t w) -{ - register int i = 6; - char *rp = *acp; - register char *cp = rp; - - while (--i >= 0) { - if (!LHGET(w) && !RHGET(w)) break; - w = op10rot(w, 6); /* Rotate high 6 bits to low 6 */ - *cp++ = (RHGET(w) & 077) + 040; - RHSET(w, RHGET(w) & ~077); - } - *cp++ = 0; /* Note moves past the nul char! */ - *acp = cp; /* Update pointer */ - return rp; /* And return start of original */ -} - -/* ITS disk-format time: */ -#define DFTM_YEAR 0177000 /* LH: 4.7-4.1 Year, mod 100. */ -#define DFTM_MON 0740 /* LH: 3.9-3.6 Month, 1=Jan */ -#define DFTM_DAY 037 /* LH: 3.5-3.1 Day, 1-31 */ -#define DFTM_SECS 0777776 /* RH: 2.9-1.2 Secs in day */ -#define DFTM_HSEC 01 /* RH: 1.1 Half-second resolution */ - -static struct tm * -timefrits(register struct tm *t, - register w10_t w) -{ - t->tm_year = (LHGET(w) & DFTM_YEAR) >> 9; - t->tm_mon = ((LHGET(w) & DFTM_MON) >> 5) - 1; - t->tm_mday = (LHGET(w) & DFTM_DAY); - t->tm_hour = RHGET(w) / (60*60*2); - t->tm_min = (RHGET(w) % (60*60*2)) / 60; - t->tm_sec = (RHGET(w) % (60*60*2)) % 60; - return t; -} - -/* FC_LOAD - Load given filename into PDP10 physical memory. -** May use any executable type, stored on disk in any 36-bit format. -*/ -int ld_debug = 0; /* TRUE to show debug info; use SET to change */ - -static void -fc_load(struct cmd_s *cm) -{ - WFILE lwf; - register FILE *f; - int res = 0; - int wft = -1; - char *farg; - - if (!cmdargs_one(cm, &farg)) - return; - - if (!aprhalted()) { - printf("KN10 still running! Halt or Reset it first.\n"); - return; - } - - /* Open file for reading */ - if (!(f = fopen(farg, "rb"))) - syserr(errno, "Couldn't open load file \"%s\"", farg); - - /* Determine word format to use */ - if (ld_fmt) { - if ((wft = wf_type(ld_fmt)) < 0) - printf("Unknown ld_fmt setting \"%s\", using default.\n", ld_fmt); - } - if (wft < 0) { - if ((wft = wf_type(ld_dfmt)) < 0) - wft = WFT_U36; - } - wf_init(&lwf, wft, f); /* Init WFILE */ - printf("Using word format \"%s\"...\n", wf_typnam(&lwf)); - - ld_inf.ldi_type = LOADT_UNKNOWN; /* Init ld_inf (assume unknown) */ - ld_inf.ldi_debug = ld_debug; - - res = fe_load(&lwf, &ld_inf); - if (!res) { - printf("Load failed for \"%s\".\n", farg); - } else { - printf("Loaded \"%s\":\n", farg); - ddt_loadsa = RHGET(ld_inf.ldi_startwd); /* Set default GO address */ - } - printf("Format: %s\n", ld_inf.ldi_typname); - printf("Data: %d, Symwds: %d, Low: %#lo, High: %#lo, Startaddress: %#lo\n", - ld_inf.ldi_ndata, ld_inf.ldi_nsyms, - (long)ld_inf.ldi_loaddr, (long)ld_inf.ldi_hiaddr, - (long) RHGET(ld_inf.ldi_startwd)); - if (ld_inf.ldi_evlen != -1) { - if (ld_inf.ldi_evlen != ((h10_t)I_JRST<<9)) - printf("Entvec: %#lo wds at %#lo\n", - (long) ld_inf.ldi_evlen, (long) ld_inf.ldi_evloc); - else - printf("\ -Entvec: JRST (120 ST: %#lo, 124 RE: %#lo, 137 VR: %lo,,%lo)\n", - (long) vm_pgetrh(fevm_map(0120)), - (long) vm_pgetrh(fevm_map(0124)), - (long) vm_pgetlh(fevm_map(0137)), - (long) vm_pgetrh(fevm_map(0137))); - } - - if (ld_inf.ldi_aibgot) { - register w10_t *aib = &ld_inf.ldi_asminf[0]; - char line[100]; - char *s = line; - struct tm t; - - timefrits(&t, aib[AIB_TIME]); /* Decompose ITS time */ - printf("\ -Assembled by %s on %04d-%02d-%02d %02d:%02d:%02d from file \"%s:%s;%s %s\"\n", - strf6(&s, aib[AIB_UNAME]), - t.tm_year + 1900, t.tm_mon+1, t.tm_mday, - t.tm_hour, t.tm_min, t.tm_sec, - strf6(&s, aib[AIB_DEV]), - strf6(&s, aib[AIB_DIR]), - strf6(&s, aib[AIB_FN1]), - strf6(&s, aib[AIB_FN2]) ); - } - - fclose(f); -} - -/* FC_DUMP - Dump PDP10 physical memory into given filename. -** Assumes either ITS SBLK or DEC CSAV format, stored on disk using -** a selectable word mode. -*/ -static void -fc_dump(struct cmd_s *cm) -{ - WFILE lwf; - register FILE *f; - int res = 0; - int wft = -1; - char *farg; - - if (!cmdargs_one(cm, &farg)) - return; - if (!aprhalted()) { - printf("KN10 still running! Halt or Reset it first.\n"); - return; - } - /* Open file for writing */ - if (!(f = fopen(farg, "wb"))) - syserr(errno, "Couldn't open dump file \"%s\"", farg); - - /* Determine word format to use */ - if (ld_fmt) { - if ((wft = wf_type(ld_fmt)) < 0) - printf("Unknown ld_fmt setting \"%s\", using default.\n", ld_fmt); - } - if (wft < 0) { - if ((wft = wf_type(ld_dfmt)) < 0) - wft = WFT_U36; - } - wf_init(&lwf, wft, f); /* Init WFILE */ - printf("Using word format \"%s\"\n", wf_typnam(&lwf)); - -#if KLH10_SYS_ITS - printf("Using dump format ITS-SBLK\n"); - ld_inf.ldi_type = LOADT_SBLK; -#else - printf("Using dump format DEC-CSAV\n"); - ld_inf.ldi_type = LOADT_DECSAV; -#endif - ld_inf.ldi_debug = TRUE; - ld_inf.ldi_loaddr = 0; - ld_inf.ldi_hiaddr = H10MASK; - - res = fe_dump(&lwf, &ld_inf); - if (!res) { - printf("Dump failed for \"%s\".\n", farg); - } else { - printf("Dumped \"%s\":\n", farg); - } - printf("Format %s, wftype %s\n", ld_inf.ldi_typname, wf_typnam(&lwf)); - printf("%ld words dumped from range %lo to %lo inclusive.\n", - (long) ld_inf.ldi_ndata, (long) ld_inf.ldi_loaddr, - (long) ld_inf.ldi_hiaddr); - - fclose(f); -} - - -/* Instruction printing routines */ - -void -pinstr(FILE *f, - register w10_t w, /* Instruction word */ - int flags, /* PINSTR_ flags */ - vaddr_t e) /* E to use, if PINSTR_EA given */ -{ - register int op, ac, x; - register vmptr_t vp; - register int opflg; - struct opdef *opdf; - - op = iw_op(w) & 0777; /* Get op, with some paranoia */ - ac = iw_ac(w); - - opdf = opcptr[op]; /* Get ptr to opcode definition */ - opflg = opdf ? opdf->opflg : 0; /* Find flags */ - if (!opflg) /* Cover up for unflagged instrs */ - opflg = IF_1X1; /* Generic c(AC) & c(E) instr */ - - if (opflg & IF_IO) { /* Special IO-format instr? */ - x = ((op & 077)<<1) | ((ac >> 3)&01); /* Find device */ - op = ac & 07; /* Find IO operation */ - opflg = opcioflg[op]; /* Get new flags */ - fprintf(f, "%s", opcionam[op]); - if (opcdvnam[x]) - fprintf(f, " %s,", opcdvnam[x]); - else - fprintf(f, " %o,", x<<2); /* Special shift to emulate asmblr */ - } else { - if (!opdf || !opdf->opstr) - fprintf(f, "%3o", op); - else { - fprintf(f, "%s", opdf->opstr); - if (opflg & IF_OPN) - fprintf(f, "-%03o", op); - } - - /* If AC field is 0, only print it if AC is used. */ - if (ac || ((opflg & IF_AS) && (opflg&IF_AFMASK) != IF_A0)) - fprintf(f, " %o,", ac); - else putc(' ', f); - } - - /* Now show I,X,Y for instruction. If X is set, don't show a zero Y. */ - if (iw_i(w)) - putc('@', f); - x = iw_x(w); - if (iw_y(w) || !x) /* Do Y only if NZ or no X */ - fprintf(f, "%lo", (long)iw_y(w)); - if (x) - fprintf(f, "(%o)", x); - - /* Now see whether to show any args of instruction -- tricky part. */ - if ((flags & PINSTR_OPS)==0) - return; /* Nope */ - - /* Show AC as operand? */ - if (opflg & IF_AS) { - if (ac || (opflg & IF_AFMASK)) { - fprintf(f, "\t%o/ ", ac); - switch (opflg & IF_AFMASK) { - case IF_A0: - case IF_A1: - wd1print(f, ac_get(ac)); /* Use current AC block */ - break; - case IF_A2: - wd1print(f, ac_get(ac)); /* Use current AC block */ - fputs(" ? ", f); - wd1print(f, ac_get(ac_off(ac,1))); /* Show AC+1 */ - break; - case IF_A4: - wd1print(f, ac_get(ac)); /* Use current AC block */ - fputs(" ? ", f); - wd1print(f, ac_get(ac_off(ac,1))); /* Show AC+1 */ - fputs(" ? ", f); - wd1print(f, ac_get(ac_off(ac,2))); /* Show AC+2 */ - fputs(" ? ", f); - wd1print(f, ac_get(ac_off(ac,3))); /* Show AC+3 */ - break; - } - } - } - - - /* Show E as operand? */ - if (opflg & IF_MFMASK) { - putc('\t', f); /* Space out */ -#if KLH10_EXTADR -/* - * ERROR * Need to revise for XA eacalc? -*/ -#endif - if ((flags & PINSTR_EA)==0) { /* Try computing E if not given */ - flags |= PINSTR_EA; /* Assume will succeed */ - if (LHGET(w) & (IW_I|IW_X)) { - w10_t eawd; - eawd = w; - if (!fevm_tryeacalc(&eawd, cpu.acblk.cur, cpu.vmap.cur, 2)) - flags &= ~PINSTR_EA; /* Oops, didn't succeed */ - else va_lmake(e, 0, RHGET(eawd)); - } else va_lmake(e, 0, RHGET(w)); - } - if ((flags & PINSTR_EA)==0) - fprintf(f, "E = \?\?"); - else switch (opflg & IF_MFMASK) { - case IF_M1: /* Operand is 1 word */ - case IF_M2: /* " 2 words (double) */ - case IF_M4: /* " 4 words (quad) */ - case IF_MIN: /* " instruction at E */ - -#if KLH10_EXTADR -/* - * ERROR * Need to revise for XA eacalc? -*/ -#endif - fprintf(f, "%lo/ ", (long)va_insect(e)); - if (!(vp = fevm_xmap(e, FEVM_CUR))) { - fprintf(f, "\?\?"); - break; - } - w = vm_pget(vp); - switch (opflg & IF_MFMASK) { - case IF_M1: - wd1print(f, w); /* Show word at E */ - break; - case IF_M2: /* Show double at E */ - case IF_M4: - wd1print(f, w); /* Do first word */ - fprintf(f, " ? "); - va_inc(e); /* Point to next word */ - if (vp = fevm_xmap(e, FEVM_CUR)) - wd1print(f, vm_pget(vp)); - else fprintf(f, "-\?\?-"); - break; - case IF_MIN: /* Show instruction at E */ - pinstr(f, w, 0, e); /* "e" just a handy null vaddr_t */ - break; - } - break; - case IF_ME: /* " E (immediate) */ - case IF_MEIO: /* " IO register (Unibus) */ - fprintf(f, "E = %lo", (long)va_insect(e)); - break; - case IF_ME8: /* " signed 8-bit E */ - { paddr_t pa = va_insect(e); - fprintf(f, "E = %lo = %d.", (long)pa, - (int)((pa&0400) ? (pa | ~0377) : (pa & 0377))); - } - break; - case IF_MEF: /* " floating immediate */ - fprintf(f, "E = %lo = (?.?)", (long)va_insect(e)); - break; - } - } - - /* Show any special stuff for instruction? */ - if (opflg & IF_SPEC) { - } -} diff --git a/src/klh10.h.old b/src/klh10.h.old deleted file mode 100644 index 6d64ddc..0000000 --- a/src/klh10.h.old +++ /dev/null @@ -1,410 +0,0 @@ -/* KLH10.H - General Configuration Definitions -*/ -/* $Id: klh10.h,v 2.10 2003/02/23 18:23:38 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: klh10.h,v $ - * Revision 2.10 2003/02/23 18:23:38 klh - * Bump version: 2.0H - * - * Revision 2.9 2002/05/21 16:54:32 klh - * Add KLH10_I_CIRC to allow any sys to have CIRC - * - * Revision 2.8 2002/05/21 09:41:58 klh - * Bump version: 2.0G - * - * Revision 2.7 2002/04/24 07:40:10 klh - * Bump version to 2.0E - * - * Revision 2.6 2002/03/28 16:51:39 klh - * Version 2.0D update - * - * Revision 2.5 2002/03/21 09:50:38 klh - * New version - * - * Revision 2.4 2001/11/19 10:39:05 klh - * Bump version: 2.0A - * - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#ifndef KLH10_INCLUDED -#define KLH10_INCLUDED 1 - -#ifndef KLH10_USE_RCSID /* For now, default to always on */ -# define KLH10_USE_RCSID 1 -#endif -#if KLH10_USE_RCSID -# include "rcsid.h" -#endif -#ifdef RCSID - RCSID(klh10_h,"$Id: klh10.h,v 2.10 2003/02/23 18:23:38 klh Exp $") -#endif - -/* Preliminary legalisms (heavy sigh) */ - -#ifndef KLH10_COPYRIGHT -# define KLH10_COPYRIGHT "\ - Copyright © 2002 Kenneth L. Harrenstien -- All Rights Reserved." -#endif -#ifndef KLH10_WARRANTY -# define KLH10_WARRANTY "This program comes \"AS IS\" with ABSOLUTELY NO WARRANTY." -#endif -#ifndef KLH10_VERSION -# define KLH10_VERSION "V2.0H" -#endif -#ifndef KLH10_CLIENT -# define KLH10_CLIENT "Generic" -#endif - - -/* C environment setup definitions. -*/ - -#include "cenv.h" /* Get CENV_CPU_ and CENV_SYS_ */ - -/* Canonical C true/false values */ -#define TRUE 1 -#define FALSE 0 - -/* For convenience when passing/setting a function pointer to NULL, to - show its nature without specifying the entire prototype. NULL alone - is sufficient in ANSI C. -*/ -#define NULLPROC (NULL) - -/* Compilation switches defining desired emulation target */ - -/* Define CPU type to emulate. -** For now, ignore peculiarities such as Foonly and Systems Concepts -** since they were primarily emulations of some DEC type. -*/ -#ifndef KLH10_CPU_6 /* DEC PDP-6 (Model 166 processor) */ -# define KLH10_CPU_6 0 -#endif -#ifndef KLH10_CPU_KA /* DEC KA10 */ -# define KLH10_CPU_KA 0 -#endif -#ifndef KLH10_CPU_KI /* DEC KI10 */ -# define KLH10_CPU_KI 0 -#endif -#ifndef KLH10_CPU_KS /* DEC KS10 (2020) */ -# define KLH10_CPU_KS 0 -#endif -#ifndef KLH10_CPU_KL0 /* DEC KL10 (single section - KL10A?) */ -# define KLH10_CPU_KL0 0 -#endif -#ifndef KLH10_CPU_KLX /* DEC KL10 (extended KL10B, 0 or non-0 section) */ -# define KLH10_CPU_KLX 0 -#endif -#ifndef KLH10_CPU_KN /* KLH KN10 (placeholder for non-HW features) */ -# define KLH10_CPU_KN 0 -#endif -#ifndef KLH10_CPU_XKL /* XKL XKL-1 (TOAD-1 System), a super-extended KL */ -# define KLH10_CPU_XKL 0 -#endif - -#if !(KLH10_CPU_6|KLH10_CPU_KA|KLH10_CPU_KI \ - |KLH10_CPU_KS|KLH10_CPU_KL0|KLH10_CPU_KLX|KLH10_CPU_KN|KLH10_CPU_XKL) -# undef KLH10_CPU_KS -# define KLH10_CPU_KS 1 /* Use KS10 as default */ -#endif - -#define KLH10_CPU_KL (KLH10_CPU_KL0 || KLH10_CPU_KLX || KLH10_CPU_XKL) - - -/* Define SYSTEM type emulated machine supports. -** Primarily affects paging, but sometimes a few other things. -** These switches are comparable to KS/KL ucode conditionals, since -** each system tends to have its own peculiar variety of ucode (or -** even different hardware, for KA/KI). -*/ -#ifndef KLH10_SYS_ITS /* MIT ITS system */ -# define KLH10_SYS_ITS 0 -#endif -#ifndef KLH10_SYS_WTS /* Stanford WAITS system */ -# define KLH10_SYS_WTS 0 -#endif -#ifndef KLH10_SYS_10X /* BBN TENEX system */ -# define KLH10_SYS_10X 0 -#endif -#ifndef KLH10_SYS_T10 /* DEC TOPS-10 system */ -# define KLH10_SYS_T10 0 -#endif -#ifndef KLH10_SYS_T20 /* DEC TOPS-20 system */ -# define KLH10_SYS_T20 0 -#endif - -#if !(KLH10_SYS_ITS|KLH10_SYS_WTS|KLH10_SYS_10X|KLH10_SYS_T10|KLH10_SYS_T20) -# undef KLH10_SYS_ITS -# define KLH10_SYS_ITS 1 /* Default for now is ITS (yeah!) */ -#endif - -/* Now define additional flags peculiar to each system/CPU, which -** describe the hardware features emulated ("what" as opposed to "how"). -** These could go into kn10*.h config files, where -** * = 3-letter CPU or SYS identifier. -*/ - -/* Select pager to use. -** DEC has had 3 different varieties of memory mgt: -** KA relocation (not emulated) -** KI paging (emulated; also called "Tops-10 paging") -** KL paging (emulated; also called "Tops-20 paging") -** For ITS this depended on the machine. Only the KS is emulated here. -** For TENEX a special BBN pager was used. This is not emulated, -** but would be quite similar to KL paging. -*/ -#ifndef KLH10_PAG_KI -# define KLH10_PAG_KI 0 -#endif -#ifndef KLH10_PAG_KL -# define KLH10_PAG_KL 0 -#endif -#ifndef KLH10_PAG_ITS -# define KLH10_PAG_ITS 0 -#endif - -/* If no paging scheme explicitly selected, pick default */ -#if !(KLH10_PAG_KI | KLH10_PAG_KL | KLH10_PAG_ITS) -# undef KLH10_PAG_KI -# define KLH10_PAG_KI KLH10_SYS_T10 -# undef KLH10_PAG_KL -# define KLH10_PAG_KL KLH10_SYS_T20 -# undef KLH10_PAG_ITS -# define KLH10_PAG_ITS KLH10_SYS_ITS -#endif - -#if KLH10_SYS_ITS /* ITS normally includes all of these */ -# ifndef KLH10_ITS_JPC -# define KLH10_ITS_JPC 1 /* Include ITS JPC feature */ -# endif -# if KLH10_ITS_JPC -# undef KLH10_JPC -# define KLH10_JPC 1 /* Include general-purpose JPC, for debug */ -# endif -# ifndef KLH10_ITS_1PROC -# define KLH10_ITS_1PROC 1 /* Include ITS 1-proceed feature */ -# endif -#endif - -#ifndef KLH10_I_CIRC /* True to include ITS CIRC instruction */ -# define KLH10_I_CIRC (KLH10_SYS_ITS) -#endif - -#ifndef KLH10_MCA25 /* MCA25 KL Cache/Paging Upgrade */ -# define KLH10_MCA25 (KLH10_CPU_KL && KLH10_SYS_T20) -#endif - -#ifndef KLH10_EXTADR /* True to support extended addressing */ -# define KLH10_EXTADR (KLH10_CPU_KLX || KLH10_CPU_XKL) -#endif - -/* Peripheral Devices -** Determine here which ones will be available for use. -** Further configuration is done at runtime. -*/ - -/* KL10 devices (old-style IO bus devices) */ - -#ifndef KLH10_DEV_DTE -# define KLH10_DEV_DTE KLH10_CPU_KL -#endif -#ifndef KLH10_DEV_RH20 -# define KLH10_DEV_RH20 KLH10_CPU_KL -#endif -#ifndef KLH10_DEV_NI20 -# define KLH10_DEV_NI20 KLH10_CPU_KL -#endif - -/* KS10 devices (new-style Unibus devices) */ - -#ifndef KLH10_DEV_RH11 -# define KLH10_DEV_RH11 KLH10_CPU_KS -#endif -#ifndef KLH10_DEV_DZ11 /* KS10 DZ11 also part of basic system? */ -# define KLH10_DEV_DZ11 KLH10_SYS_ITS /* Try just ITS for now */ -#endif -#ifndef KLH10_DEV_LHDH /* KS10 LHDH IMP interface */ -# define KLH10_DEV_LHDH KLH10_SYS_ITS /* Only on ITS for now */ -#endif -#ifndef KLH10_DEV_CH11 /* KS10 CH11 Chaosnet interface? */ -# define KLH10_DEV_CH11 KLH10_SYS_ITS /* Only on ITS for now */ -#endif - -/* Generic controller drive devices - work for either bus */ - -#ifndef KLH10_DEV_RPXX -# define KLH10_DEV_RPXX (KLH10_DEV_RH20 | KLH10_DEV_RH11) -#endif -#ifndef KLH10_DEV_TM03 -# define KLH10_DEV_TM03 (KLH10_DEV_RH20 | KLH10_DEV_RH11) -#endif - -/* Universal devices - currently just one pseudo-dev */ - -#ifndef KLH10_DEV_HOST -# define KLH10_DEV_HOST 1 -#endif - -/* CPU and PI configuration (PI includes IO) -** The parameters defined earlier specify WHAT to emulate; by contrast, -** these specify HOW the emulation should be done. -*/ - -#ifndef KLH10_PCCACHE /* True to include experimental PC cache stuff */ -# define KLH10_PCCACHE 1 -#endif -#ifndef KLH10_JPC /* True to include JPC feature */ -# define KLH10_JPC 1 /* For now, always - helps debug! */ -#endif - -/* MEMORY - Select emulation method -** Sharable memory has pitfalls but is useful for subproc DMA and -** perhaps future SMP implementation. -*/ -#ifndef KLH10_MEM_SHARED /* TRUE to use sharable memory segment */ -# define KLH10_MEM_SHARED 0 -#endif - -/* REAL-TIME CLOCK - Select emulation method -*/ -#ifndef KLH10_RTIME_SYNCH /* Synchronized - use count */ -# define KLH10_RTIME_SYNCH 0 -#endif -#ifndef KLH10_RTIME_OSGET /* OS value used for all references */ -# define KLH10_RTIME_OSGET 0 -#endif -#ifndef KLH10_RTIME_INTRP /* Interrupt-driven (not implemented) */ -# define KLH10_RTIME_INTRP 0 -#endif -#if !(KLH10_RTIME_SYNCH|KLH10_RTIME_OSGET|KLH10_RTIME_INTRP) -# undef KLH10_RTIME_OSGET -# define KLH10_RTIME_OSGET 1 /* Default to asking system */ -#endif - -/* INTERVAL-TIME CLOCK - Select emulation method -*/ -#ifndef KLH10_ITIME_SYNCH /* Synchronized - use count */ -# define KLH10_ITIME_SYNCH 0 -#endif -#ifndef KLH10_ITIME_INTRP /* Interrupt-driven */ -# define KLH10_ITIME_INTRP 0 -#endif -#if !(KLH10_ITIME_SYNCH|KLH10_ITIME_INTRP) -# undef KLH10_ITIME_SYNCH -# define KLH10_ITIME_SYNCH 1 /* Default to synchronous counter */ -#endif - -/* INTERVAL-TIME CLOCK - set default interval in HZ -** This is the actual interval time in HZ that will be enforced -** unless the user explicitly does a "set clk_ithzfix". -** A value of 0 allows the 10 to set it to anything. -** 60 is a good default; 30 may be needed on slower/older hardware. -*/ -#ifndef KLH10_CLK_ITHZFIX -# define KLH10_CLK_ITHZFIX 60 -#endif - -/* QUANTUM COUNTER - Select emulation method (ITS only) -*/ -#ifndef KLH10_QTIME_SYNCH /* Synchronized - use count */ -# define KLH10_QTIME_SYNCH 0 -#endif -#ifndef KLH10_QTIME_OSREAL /* Use OS realtime */ -# define KLH10_QTIME_OSREAL 0 -#endif -#ifndef KLH10_QTIME_OSVIRT /* Use OS virtual (user CPU) time */ -# define KLH10_QTIME_OSVIRT 0 -#endif - -#if KLH10_SYS_ITS /* Only default if ITS */ -# if !(KLH10_QTIME_SYNCH|KLH10_QTIME_OSREAL|KLH10_QTIME_OSVIRT) -# undef KLH10_QTIME_SYNCH -# define KLH10_QTIME_SYNCH 1 /* Default to synchronous counter */ -# endif -#endif - - -/* DEVICE I/O WAKEUP - Select I/O checking method for various devices. -** These parameters select interrupt-driven methods if TRUE; -** otherwise polling is used. -** Future alternatives may use threads or subprocesses. -*/ -#ifndef KLH10_CTYIO_INT /* True to use CTY interrupts */ -# define KLH10_CTYIO_INT 0 -#endif -#ifndef KLH10_IMPIO_INT /* True to use IMP interrupts */ -# define KLH10_IMPIO_INT 0 -#endif -#ifndef KLH10_EVHS_INT /* True to use new event handling scheme */ -# define KLH10_EVHS_INT 0 -#endif - -/* DEVICE SUBPROCESS - Select basic implementation method for various devices -** These parameters select an asynchronous sub-process method if TRUE; -** otherwise a blocking method is used. -** Not all devices will work without subprocesses (e.g. NI20) -** Future alternatives may use threads. -*/ -#ifndef KLH10_DEV_DPNI20 /* True to use dev subproc for NI20 net */ -# define KLH10_DEV_DPNI20 KLH10_DEV_NI20 -#endif -#ifndef KLH10_DEV_DPRPXX /* True to use dev subproc for RPxx disk */ -# define KLH10_DEV_DPRPXX 0 -#endif -#ifndef KLH10_DEV_DPTM03 /* True to use dev subproc for TM03 tape */ -# define KLH10_DEV_DPTM03 0 -#endif - -/* Two different ways to implement IMP subproc */ -#ifndef KLH10_DEV_DPIMP /* True to use dev subproc for IMP (net) */ -# define KLH10_DEV_DPIMP KLH10_DEV_LHDH -#endif -#ifndef KLH10_DEV_SIMP /* True to use pipe subproc for IMP (net) */ -# define KLH10_DEV_SIMP (KLH10_DEV_LHDH && !KLH10_DEV_DPIMP) -#endif - - -#ifndef KLH10_DEV_DP /* True to include DP subproc support */ -# define KLH10_DEV_DP (KLH10_DEV_DPNI20 \ - |KLH10_DEV_DPRPXX|KLH10_DEV_DPTM03|KLH10_DEV_DPIMP) -#endif - -/* Miscellaneous config vars */ - -#ifndef KLH10_INITFILE /* Default initialization command file */ -# define KLH10_INITFILE "klh10.ini" -#endif - -#ifndef KLH10_DEBUG /* TRUE to include debug output code */ -# define KLH10_DEBUG 1 -#endif - -/* Hack for KS T20 CTY output. (see cty_addint() in dvcty.c) -*/ -#ifndef KLH10_CTYIO_ADDINT /* Set 1 to use hack */ -# define KLH10_CTYIO_ADDINT (KLH10_CPU_KS && KLH10_SYS_T20 && KLH10_CTYIO_INT) -#elif KLH10_CTYIO_ADDINT -# if !KLH10_CPU_KS || !KLH10_SYS_T20 /* Unless a KS T20, */ -# undef KLH10_CTYIO_ADDINT /* force this to 0 */ -# define KLH10_CTYIO_ADDINT 0 -# endif -#endif - -#endif /* ifndef KLH10_INCLUDED */ diff --git a/src/kn10cpu.c.old b/src/kn10cpu.c.old deleted file mode 100644 index eb5e7d6..0000000 --- a/src/kn10cpu.c.old +++ /dev/null @@ -1,3411 +0,0 @@ -/* KN10CPU.C - Main Processor Operations (APR, PI, PAG) -*/ -/* $Id: kn10cpu.c,v 2.9 2002/05/21 16:54:32 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: kn10cpu.c,v $ - * Revision 2.9 2002/05/21 16:54:32 klh - * Add KLH10_I_CIRC to allow any sys to have CIRC - * - * Revision 2.8 2002/05/21 16:25:26 klh - * Fix typo - * - * Revision 2.7 2002/05/21 10:03:02 klh - * Fix SYNCH implementation of KL timebase - * - * Revision 2.6 2002/03/21 09:50:08 klh - * Mods for CMDRUN (concurrent mode) - * - * Revision 2.5 2001/11/19 10:43:28 klh - * Add os_rtm_adjust_base for ITS on Mac - * - * Revision 2.4 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#include -#include /* For setjmp, longjmp */ - -#include "klh10.h" -#include "osdsup.h" -#include "kn10def.h" -#include "kn10ops.h" -#include "kn10dev.h" /* For device PI handling */ -#include "dvcty.h" /* For cty_ stuff */ - -#ifdef RCSID - RCSID(kn10cpu_c,"$Id: kn10cpu.c,v 2.9 2002/05/21 16:54:32 klh Exp $") -#endif - -/* Exported functions */ -void apr_init(void); -int apr_run(void); -void pi_devupd(void); -void apr_check(void); -void pxct_undo(void); /* Stuff needed by KN10PAG for page fail trap */ -void trap_undo(void); -#if KLH10_ITS_1PROC -void a1pr_undo(void); -#elif KLH10_CPU_KI || KLH10_CPU_KL -void afi_undo(void); -#endif - -/* Imported functions */ -extern void fe_begpcfdbg(FILE *); -extern void fe_endpcfdbg(FILE *); -extern void pishow(FILE *); -extern void pcfshow(FILE *, h10_t flags); -extern void pinstr(FILE *, w10_t w, int flags, vaddr_t e); -extern void fe_traceprint (register w10_t instr, vaddr_t e); - -/* Pre-declarations */ -static void trap_xct(void); -static int pi_check(void); -static void pi_xct(int lev); -static void pi_init(void); -static int tim_init(void); -#if KLH10_EXTADR - static int apr_creep(void); - static void apr_hop(void); -#else - static int apr_walk(void); - static void apr_fly(void); -#endif -#if KLH10_ITS_1PROC - static void apr_1proc(void); -#endif -#if KLH10_CPU_KI || KLH10_CPU_KL /* AFI Handling */ - static void apr_afi(void); -#endif -#if KLH10_CPU_KS - static void tim_rdtim(dw10_t *); - static void tim_wrtim(dw10_t *); -# if KLH10_RTIME_SYNCH - static void tim_basefreeze(void); - static void tim_baseunfreeze(void); -# endif -#endif /* KLH10_CPU_KS */ - -jmp_buf aprhaltbuf; /* Use this jump buffer to halt CPU, return to FE */ -jmp_buf aprloopbuf; /* Use this jump buffer to return to main APR loop */ - -/* APR_INIT - Called at startup to initialize APR "device" stuff -*/ -void -apr_init(void) -{ - INSBRK_INIT(); /* Ensure insbreak cleared */ - - cpu.aprf.aprf_set = cpu.aprf.aprf_ena = cpu.aprf.aprf_lev = 0; - cpu.mr_pcflags = 0; - PC_SET30(0); - PCCACHE_RESET(); -#if KLH10_CPU_KS -# if KLH10_SYS_ITS - LRHSET(cpu.mr_hsb, 0, 0500); /* Initial HSB base addr */ - LRHSET(cpu.mr_aprid, /* Set APR ID word */ - AIF_ITS | KLH10_APRID_UCVER, /* ITS ucode */ - KLH10_APRID_SERIALNO); -# else /* DEC */ - LRHSET(cpu.mr_hsb, 0, 0376000); /* Initial HSB base addr */ - LRHSET(cpu.mr_aprid, /* Set APR ID word */ - AIF_UBLT /* Have BLTUB, BLTBU */ - /* The INHCST and NOCST bits shouldn't be on for T20, but T20 - ** ignores them while T10 expects them with KL paging, so always - ** have them on. Sigh. - */ - | AIF_INHCST | AIF_NOCST /* For T10 */ - | (KLH10_PAG_KI ? AIF_KIPG : 0) - | (KLH10_PAG_KL ? AIF_KLPG : 0) - | KLH10_APRID_UCVER, - KLH10_APRID_SERIALNO); -# endif /* DEC */ - -#elif KLH10_CPU_KL - LRHSET(cpu.mr_aprid, - ( AIF_PMV - | (KLH10_PAG_KL ? AIF_T20 : 0) - | (KLH10_EXTADR ? AIF_EXA : 0) - | (KLH10_I_CIRC ? AIF_SEX : 0) - | (KLH10_CPU_KLX ? AIF_KLB : 0) - | KLH10_APRID_UCVER), - ( AIF_CCA - | AIF_CHN - | (KLH10_MCA25 ? AIF_MCA : 0) - | (KLH10_CPU_KLX ? AIF_KLX : 0) - | KLH10_APRID_SERIALNO)); /* SN # */ -#endif - - cpu.mr_usrmode = cpu.mr_inpxct = cpu.mr_intrap = - cpu.mr_injrstf = cpu.mr_inpi = 0; -#if KLH10_ITS_1PROC - cpu.mr_in1proc = 0; -#elif KLH10_CPU_KI || KLH10_CPU_KL - cpu.mr_inafi = 0; -#endif - cpu.mr_dotrace = cpu.mr_1step = 0; - - op10m_setz(cpu.mr_dsw); /* Clear data switches initially */ - - pi_init(); /* Init the PI system */ - pag_init(); /* Init the pager */ - tim_init(); /* Init the timers/clocks */ -} - -/* APR_RUN - Invoked by FE to start PDP-10 running! -** All this routine does is select the actual main loop to use, -** based on the debugging or operating parameters in effect. -** -** Note that there are two different setjmp points. One is to allow -** halting the CPU loop; the other implements traps (PI interrupts etc) by -** re-entering the start of the CPU loop. The latter used to be inside -** the loop functions but has been moved outside because some compilers -** refuse to optimize anything that contains a setjmp! -*/ -int -apr_run(void) -{ - register int haltval; - - /* Save return point for APR halt */ - if (haltval = _setjmp(aprhaltbuf)) { /* If longjmp back, */ - clk_suspend(); /* stop internal clock */ - return haltval; /* return from running APR */ - } - clk_resume(); /* Resume internal clock */ - - /* Determine which APR loop to start or re-enter! */ - if (cpu.mr_bkpt || cpu.mr_dotrace || cpu.mr_1step -#if KLH10_SYS_T20 && KLH10_CPU_KS - || cpu.fe.fe_iowait || cpu.io_ctydelay -#endif - ) { - /* Debug loop of some sort - invoke slow loop */ - - /* Save point to return to for trap/interrupt */ - if (_setjmp(aprloopbuf)) { - if (cpu.mr_bkpt && PC_INSECT == cpu.mr_bkpt) - return HALT_BKPT; - } -#if KLH10_EXTADR - return apr_creep(); /* Extended (KL) */ -#else - return apr_walk(); /* Non-extended (KS) */ -#endif - } else { - /* No debugging - invoke normal fast loop, max speed */ - - _setjmp(aprloopbuf); /* Save return point for trap/interrupt */ -#if KLH10_EXTADR - apr_hop(); /* Extended (KL) */ -#else - apr_fly(); /* Non-extended (KS) */ -#endif - /* Fast loop shouldn't ever return, but if it does then we must - be doing some kind of manual debugging. - */ - return HALT_STEP; - } -} - -#if !KLH10_EXTADR -/* APR_WALK - Routine to use when debugging or some other kind of -** slow checking within the main loop may be needed. -** NON-EXTENDED operation. -*/ -static int -apr_walk(void) -{ - register w10_t instr; - - for (;;) { - register vaddr_t ea; - - /* Check for possible interrupt, trap, or special handling */ - if (INSBRKTEST()) { /* Check and handle all possible "asynchs" */ - apr_check(); - if (cpu.mr_bkpt && PC_INSECT == cpu.mr_bkpt) - return HALT_BKPT; - } - - /* Fetch next instruction from new PC (may page fault) */ - instr = vm_fetch(PC_VADDR); - - /* Compute effective address (may page fault) */ - ea = ea_calc(instr); /* Find it with inline macro */ - - /* Now dispatch after setting up AC (may page fault or set trap). - ** During execution, cpu.mr_PC contains PC of this instruction. It - ** is not incremented (if at all) until execution finishes. - */ -#if 1 - if (cpu.mr_dotrace) /* Show instruction about to be XCT'd */ - fe_traceprint(instr, ea); -#endif - - /* EXECUTE! */ - PC_ADDXCT(op_xct(iw_op(instr), iw_ac(instr), ea)); - -#if KLH10_SYS_T20 && KLH10_CPU_KS - /* Gross hack to emulate I/O device delays for buggy 10 software */ - if (cpu.io_ctydelay && (--cpu.io_ctydelay <= 0)) { - cty_timeout(); - } -#endif - CLOCKPOLL(); /* Update clock if necessary */ - -#if 1 /* Hack to support FE single-stepping */ - if (cpu.mr_1step && (--cpu.mr_1step <= 0)) { - cpu.mr_1step = 0; - return HALT_STEP; - } - if (cpu.mr_bkpt && PC_INSECT == cpu.mr_bkpt) - return HALT_BKPT; -#endif - } -} - - -/* APR_FLY - Primary loop when no debugging or special checks -** are necessary. -** NON-EXTENDED operation. -*/ -static void -apr_fly(void) -{ - register w10_t instr; -#if KLH10_PCCACHE - register vmptr_t vp; - register paddr_t pc; - register paddr_t cachelo = 1; /* Lower & upper bounds of PC */ - register paddr_t cachehi = 0; -#endif - - PCCACHE_RESET(); /* Robustness: invalidate cached PC info */ - for (;;) { - if (INSBRKTEST()) /* Check and handle all possible "asynchs" */ - apr_check(); -#if KLH10_PCCACHE - /* See if PC is still within cached page pointer */ - if ((pc = PC_INSECT) <= cachehi && cachelo <= pc - && cpu.mr_cachevp) { - vp = cpu.mr_cachevp + (pc & PAG_MASK); /* Win, fast fetch */ - } else { - vp = vm_xeamap(PC_VADDR, VMF_FETCH); /* Do mapping, may fault */ - /* Remember start of page or ac block */ - cpu.mr_cachevp = vp - (pc & PAG_MASK); - if (cachelo = (pc & (H10MASK & ~PAG_MASK))) { - /* Normal page reference */ - cachehi = cachelo | PAG_MASK; - } else if (pc > AC_17) { /* Page 0, special handling */ - cachelo = AC_17+1; - cachehi = PAG_MASK; - } else - cachehi = AC_17; /* Running in ACs */ - } - instr = vm_pget(vp); -#else - instr = vm_fetch(PC_VADDR); /* Fetch next instr */ -#endif - PC_ADDXCT(op_xct(iw_op(instr), iw_ac(instr), ea_calc(instr))); - -#if 0 /* Turn on to help debug this loop */ - if (cpu.mr_1step && (--cpu.mr_1step <= 0)) { - cpu.mr_1step = 0; - return HALT_STEP; - } -#endif - - CLOCKPOLL(); /* Update clock if necessary */ - } -} -#endif /* !KLH10_EXTADR */ - - -/* APR_INT - Abort current instruction; interrupt processor by returning -** to main loop. -** Someday might pass optional arg to longjmp for special dispatching -** into main loop. -*/ -void -apr_int(void) -{ -#if KLH10_ITS_1PROC - if (cpu.mr_in1proc) a1pr_undo(); /* Undo if in one-proceed */ -#elif KLH10_CPU_KI || KLH10_CPU_KL - if (cpu.mr_inafi) afi_undo(); /* Undo if in AFI */ -#endif - if (cpu.mr_intrap) trap_undo(); /* Undo if in trap instruction */ - if (cpu.mr_inpxct) pxct_undo(); /* Undo if PXCT operand */ - _longjmp(aprloopbuf, 1); -} - -/* APR_HALT - Halt processor. -** Passes reason back up to apr_run(). -*/ -void apr_halt(enum haltcode haltval) /* A HALT_xxx value */ -{ - _longjmp(aprhaltbuf, haltval); -} - -#if KLH10_EXTADR - -/* APR_CREEP - EXTENDED version of APR_WALK. -** Slow debug checking, slower with XA operation. -*/ -static int -apr_creep(void) -{ - register w10_t instr; - - for (;;) { - register vaddr_t ea; - - /* Check for possible interrupt, trap, or special handling */ - if (INSBRKTEST()) { /* Check and handle all possible "asynchs" */ - apr_check(); - if (cpu.mr_bkpt && PC_INSECT == cpu.mr_bkpt) - return HALT_BKPT; - } - - /* Fetch next instruction from new PC (may page fault) */ - instr = vm_PCfetch(); - - /* Compute effective address (may page fault) */ - ea = xea_calc(instr, PC_SECT); /* Find it with inline macro */ - - /* Now dispatch after setting up AC (may page fault or set trap). - ** During execution, cpu.mr_PC contains PC of this instruction. It - ** is not incremented (if at all) until execution finishes. - */ -#if 1 - if (cpu.mr_dotrace) /* Show instruction about to be XCT'd */ - fe_traceprint(instr, ea); -#endif - - /* EXECUTE! */ - PC_ADDXCT(op_xct(iw_op(instr), iw_ac(instr), ea)); - CLOCKPOLL(); /* Update clock if necessary */ - -#if 1 /* Hack to support FE single-stepping */ - if (cpu.mr_1step && (--cpu.mr_1step <= 0)) { - cpu.mr_1step = 0; - return HALT_STEP; - } - if (cpu.mr_bkpt && PC_INSECT == cpu.mr_bkpt) - return HALT_BKPT; -#endif - } -} - -/* APR_HOP - EXTENDED version of APR_FLY. -** Fast loop, hobbled by XA operations. -** No PC Cache stuff to begin with -- keep simple for now. -*/ -static void -apr_hop(void) -{ - register w10_t instr; - - for (;;) { - if (INSBRKTEST()) /* Check and handle all possible "asynchs" */ - apr_check(); - instr = vm_PCfetch(); /* Fetch next instr */ - - PC_ADDXCT(op_xct(iw_op(instr), iw_ac(instr), - xea_calc(instr, PC_SECT))); - -#if 0 /* Turn on to help debug this loop */ - if (cpu.mr_1step && (--cpu.mr_1step <= 0)) { - cpu.mr_1step = 0; - return HALT_STEP; - } -#endif - CLOCKPOLL(); /* Update clock if necessary */ - } -} -#endif /* EXTADR */ - - -/* APR_CHECK - Check all possible "interrupt" conditions to see what -** needs to be done, and do it. -** Clears mr_insbreak if nothing needed doing. -*/ -int apr_intcount = 0; - -void -apr_check(void) -{ -#if 0 - apr_intcount++; -#endif - for (;;) { /* Start of outer synchronous-handling loop */ - - INSBRK_ACTBEG(); /* Start inner asynch-handling loop */ - - /* Check for various interrupt-driven stuff */ - if (INTF_TEST(cpu.intf_fecty)) { - INTF_ACTBEG(cpu.intf_fecty); - INTF_ACTEND(cpu.intf_fecty); /* Immediately reset flag */ - apr_halt(fe_haltcode()); /* And halt processor! */ - } - -#if KLH10_EVHS_INT - if (INTF_TEST(cpu.intf_evsig)) { - INTF_ACTBEG(cpu.intf_evsig); - dev_evcheck(); - INTF_ACTEND(cpu.intf_evsig); - } -#endif -#if KLH10_CTYIO_INT - if (INTF_TEST(cpu.intf_ctyio)) { - INTF_ACTBEG(cpu.intf_ctyio); - cty_incheck(); - INTF_ACTEND(cpu.intf_ctyio); - } -#endif - if (INTF_TEST(cpu.intf_clk)) { - INTF_ACTBEG(cpu.intf_clk); - clk_synctimeout(); /* Invoke clock timeouts */ - INTF_ACTEND(cpu.intf_clk); - } - - /* Check for PI requests */ - { - register int pilev; - if (pilev = pi_check()) /* If PI interrupt requested, */ - pi_xct(pilev); /* handle it! */ - } - - /* Make sure no further asynchs have come in. This macro will - ** either loop or clear the insbreak flag. - */ - INSBRK_ACTEND(); - - /* OK, the insbreak flag is clear! Now OK to handle synchronous - ** trap conditions, where instructions must be executed. This cannot - ** be done within the inner asynch loop because iterative instructions - ** that do an INSBRKTEST would abort prematurely. - ** - ** This problem also potentially afflicts PI execution if the - ** interrupt instruction uses an indirect address, but the EA calc - ** code allows up to 1 indirection for speed before checking INSBRK. - ** If any monitor does double indirections then PI will hang - ** forever and this code must be re-thought. Just clearing INSBRK - ** is not good enough because some asynch event could turn INSBRK - ** back on during PI execution. Sigh. - */ -#if KLH10_ITS_1PROC - /* Any pending PI has been handled, now look for one-proceed trap */ - if (PCFTEST(PCF_1PR)) { - apr_1proc(); /* One-proceed next instruction */ - if (INSBRKTEST()) /* If it tickled the insbreak flag, */ - continue; /* restart outer loop! */ - } else -#elif KLH10_CPU_KI || KLH10_CPU_KL - /* Any pending PI has been handled, now see if hacking AFI */ - if (PCFTEST(PCF_AFI)) { - apr_afi(); /* Exert AFI on next instruction */ - if (INSBRKTEST()) /* If it tickled the insbreak flag, */ - continue; /* restart outer loop! */ - } else -#endif - /* Check for trap flags set. One-proceed/AFI also checks, so if - ** we did either, this is skipped. - */ - if (PCFTEST(PCF_TR1|PCF_TR2) && cpu.mr_paging) { - trap_xct(); /* Execute trap instruction */ - if (INSBRKTEST()) /* It may have tickled insbreak */ - continue; - } - - /* If we're here, nothing else to do, so resume normal execution */ - break; - } -} - -/* Effective Address Calculation. -** The routines here are full-blown functions called when the -** inline macros give up. -*/ - -w10_t -ea_wcalc(register w10_t iw, - register acptr_t acp, - register pment_t *map) -{ - register h10_t tmp; - - for (;;) { - if ((tmp = LHGET(iw)) & IW_X) { /* Indexing? */ - register w10_t wea; - wea = ac_xget(tmp & IW_X, acp); /* Get c(X) */ - LHSET(iw, LHGET(wea)); - RHSET(iw, (RHGET(iw)+RHGET(wea))&H10MASK); /* Add previous Y */ - } - if (!(tmp & IW_I)) /* Indirection? */ - return iw; /* Nope, return now! */ - iw = vm_pget(vm_xmap(RHGET(iw), /* Yup, do it */ - VMF_READ, - acp, map)); - if (iw_i(iw)) { /* If new word is indirect too */ - CLOCKPOLL(); - if (INSBRKTEST()) apr_int(); /* Stop infinite @ loops */ - } - } -} - -#if 1 - -vaddr_t -ea_fncalc(register w10_t iw, - register acptr_t acp, - register pment_t *map) -{ - register vaddr_t ea; - register h10_t tmp; - - tmp = LHGET(iw); - for (;;) { - if (tmp & IW_X) { /* Indexing? */ - /* Could optimize here by adding both words before masking; - ** another job for word10.h or kn10ops.h. - */ - va_lmake(ea, 0, - (RHGET(iw) + ac_xgetrh(tmp & IW_X, acp)) & H10MASK); - } else /* Not indexing, just use Y */ - va_lmake(ea, 0, RHGET(iw)); - - if (!(tmp & IW_I)) /* Indirection? */ - return ea; /* Nope, return now! */ - - /* Indirection, do it */ - iw = vm_pget(vm_xmap(ea, VMF_READ, acp, map)); - if ((tmp = LHGET(iw)) & IW_I) { /* If new word also indirect */ - CLOCKPOLL(); - if (INSBRKTEST()) apr_int(); /* Stop infinite @ loops */ - } - } -} -#endif - -#if KLH10_EXTADR - -/* XEA_XCALC - Extended Addressing EA calc!! -** This is it -- the monster that combines with vm_xmap to -** suck all the CPU cycles out of a KL emulation! -*/ -vaddr_t -xea_xcalc(register w10_t iw, /* IFIW to evaluate */ - register unsigned sect, /* Current section */ - register acptr_t acp, /* AC block mapping */ - register pment_t *map) /* Page table mapping */ -{ - register vaddr_t e; /* Address to return */ - - for (;;) { - if (op10m_tlnn(iw, IW_X)) { /* Indexing? */ - register w10_t xw; - xw = ac_xget(iw_x(iw), acp); /* Get c(X) */ - /* Check for type of indexing. - ** Do global only if NZS E, X>0, and X<6:17> NZ - */ - if (op10m_skipge(xw) && sect && op10m_tlnn(xw, VAF_SMSK)) { - /* Note special hackery for global indexing: Y becomes - ** a signed displacement. - */ - va_gmake30(e, VAF_30MSK & (va_30frword(xw) - + (op10m_trnn(iw, H10SIGN) - ? (RHGET(iw) | (VAF_SMSK<,,Y -** XCT 4,[MOVE 1,(X)] -** According to the doc, the EA is computed in current context, which -** results in a GLOBAL address of ,,Y that is then used for a ref -** in previous context (and bombs if section doesn't exist!). -** -** However, on a real KL, the reference is made to 0,,Y. Why? -** Don't know. Until someone figures out from prints -** exactly what is going on, the following hack is used to modify -** the algorithm to match the KL more closely: -** For case (2), if PCS=0, locality of E is ignored; mem ref -** is always made using PCS. -*/ -vaddr_t -xea_pxctcalc(register w10_t iw, - register unsigned sect, /* Current section */ - register acptr_t acp, /* AC block mapping */ - register pment_t *map, /* Page table mapping */ - int ebit, int dbit) /* E-calc and Data-ref bits from PXCT */ -{ - register vaddr_t e; - register int pxbits = cpu.mr_inpxct; - - if (ebit & pxbits) { /* If mapping E calc */ - /* E-bit set, do pre-proc but never post-proc */ - sect = pag_pcsget(); /* Make default section PCS */ - return xea_xcalc(iw, sect, acp, map); /* Compute E normally */ - } - - /* E-bit not set, may do post-proc */ - e = xea_xcalc(iw, sect, acp, map); /* Compute E normally */ - if ((pxbits & dbit) /* D set? (prev ctxt mem ref) */ - && (!(sect = pag_pcsget()) /* PCS==0? (SEE NOTE ABOVE!!) */ - || va_islocal(e))) { /* or E is local? */ - va_lmake(e, sect, va_insect(e)); /* Yup, apply PCS post-proc */ - } - return e; -} -#endif /* KLH10_EXTADR */ - -#if KLH10_CPU_KS - -/* UMOVE, UMOVEM - Move from and to user memory. -** Even though these are nominally identical to PXCT 4,[MOVE/M] -** they are implemented with their own routines, partly because -** there *is* one difference (legal in User-IOT mode) and partly -** because they are used in lots of places. -** Note the use of vm_xmap() which directly specifies the mapping to -** use, thus avoiding any need to set cpu.mr_inpxct. -** Unfortunately, these instructions are only defined for the KS, -** although they would be very handy for the KL as well. -*/ -insdef(i_umove) -{ - if (cpu.mr_usrmode && !PCFTEST(PCF_UIO)) /* Must be EXEC or User-IOT */ - return i_muuo(op, ac, e); - ac_set(ac, vm_pget( /* Do it, may page fault */ - vm_xmap(e, VMF_READ, cpu.acblk.prev, cpu.vmap.prev))); - return PCINC_1; -} - -insdef(i_umovem) -{ - if (cpu.mr_usrmode && !PCFTEST(PCF_UIO)) /* Must be EXEC or User-IOT */ - return i_muuo(op, ac, e); - vm_pset(vm_xmap(e, VMF_WRITE, cpu.acblk.prev, cpu.vmap.prev), - ac_get(ac)); /* Do it, may page fault */ - return PCINC_1; -} -#endif /* KS */ - -/* TRAP_XCT - Called when about to execute next instruction and notice -** that trap flags are set. Paging must be ON. -** PC points to not-yet-executed new instruction. In order to fake out -** instruction execution routines, we back this up by 1, which makes -** normal return work properly. -** However, any abnormal return to main loop (page fault or PI interrupt) -** must back out by undoing this! -** -** KLX notes: -** There is a serious problem here with extended addressing. -** In order to properly determine E for the trap instruction in an -** extended program, we must know the section # of the instruction that -** caused the trap (this constitutes the default section for EA computation). -** However, in the current KLH10 architecture, by the time we get here -** we can't know for sure where the guilty instruction was! PC has already -** been changed and if it was a jump of some kind then we can't tell -** what it was before (note normal increments and skips are always local, -** so for those we always know what PC section was). -** It may be possible to use the JPC feature to help out here. -** The only jumps that set Trap 1 are SOJ and AOJ. -** The only jumps that set Trap 2 are POPJ and PUSHJ. -** Finally, it's not clear which section is the default section if -** the trap occured as a result of an XCT chain. Hopefully it is *NOT* -** that of the final instruction word, since while we might be able to -** determine the correct section, there's no way we can find out from PC -** where the original XCT was. -** For the time being, we'll use PC section, and hope nothing loses -** too badly. -*/ -static void -trap_xct(void) -{ - register w10_t instr; - register paddr_t loc; - - /* Find location of trap instruction and fetch it. - ** This is a physical memory address, so no page fault is possible. - */ - switch (cpu.mr_pcflags & (PCF_TR1|PCF_TR2)) { /* Find trap offset */ - case 0: return; /* Not trapping?? */ - case PCF_TR1: loc = UPT_TR1; break; - case PCF_TR2: loc = UPT_TR2; break; - case (PCF_TR1|PCF_TR2): loc = UPT_TR3; break; - } - loc += (cpu.mr_usrmode ? cpu.mr_ubraddr : cpu.mr_ebraddr); /* Find loc in PT */ - instr = vm_pget(vm_physmap(loc)); /* Fetch the trap instr */ - -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - fprintf(stderr,"TRAP:{"); - pinstr(stderr, instr, 0, 0L); /* 0L not right but ok for now */ - } -#endif - - cpu.mr_intrap = cpu.mr_pcflags & (PCF_TR1|PCF_TR2); /* Remember traps */ - cpu.mr_pcflags &= ~(PCF_TR1|PCF_TR2); /* Clear from flags */ - PC_ADD(-1); /* Fake 'em out */ - - /* Now execute it */ -#if KLH10_EXTADR - PC_ADDXCT(op_xct(iw_op(instr), iw_ac(instr), xea_calc(instr, PC_SECT))); -#else - PC_ADDXCT(op_xct(iw_op(instr), iw_ac(instr), ea_calc(instr))); -#endif - cpu.mr_intrap = 0; /* Normal return, no longer doing trap instr */ - -#if KLH10_DEBUG - if (cpu.mr_debug) { - putc('}', stderr); - fe_endpcfdbg(stderr); - } -#endif -} - -/* TRAP_UNDO - Called by abnormal instruction termination (abort or pagefault) -** while executing a trap instruction, to undo stuff properly. -*/ -void -trap_undo(void) -{ - if (cpu.mr_intrap) { - cpu.mr_pcflags &= ~(PCF_TR1|PCF_TR2); /* Clear from PC flags */ - cpu.mr_pcflags |= cpu.mr_intrap; /* Add old flags */ - cpu.mr_intrap = 0; - PC_ADD(1); /* Undo trap's backup of PC */ - INSBRKSET(); /* Want attention later */ - } -} - -#if KLH10_CPU_KS - -/* KS10 Clock and Interval Timing system -** -** See the PRM p.4-37 for a description of KS system timing. The original -** code here attempted to emulate the KS millisecond counter behavior by -** calling tim_ksupdate() at each millisecond countdown, but there is no -** real reason to do a timer update at anything less than the interval -** timer interrupt frequency, since all of the interaction between the -** monitor and the hardware is done via specific instructions that -** can take care to fake things out correctly. -** -** The KS10 basically has two ways of tracking time, a 71-bit -** time base and a 35-bit interval timer, both of which are -** run at exactly 4.1 MHz. The reason for this odd frequency appears to -** be an attempt to have the 12-bit internal counter count out at -** almost exactly one millisecond (1<<12 == 4096), but it really is -** exactly 4.1 MHz and not 4.096MHz!! Sigh, but close enough. -** -** This means each tick (low-order bit) represents 1/4.1 == 0.243902439... -** usec, and 4 ticks represent what ITS calls a "short usec" of -** 1/1.025 == .975 usec. Thus ignoring the low-order 2 bits gives -** a count of short usecs, and ignoring the low-order 12 bits gives a -** count of milliseconds (to be precise, 999.02439 usec). -** -** This code relies on the CLK facilities to provide either of two -** emulation methods: synchronous countdown, or OS run-time interrupts. -** See KN10CLK.C for more details. When using the synchronous method, -** each cycle tick should be considered equal to 1 virtual usec since -** that's roughly how fast a real KS10 executes instructions. -** -** The ITS pager's "quantum timer" is also driven off this counter so -** as to emulate a 1 MHz clock rate. On a KA the quantum timer returned by -** SPM is a 4.096/4 usec quantity. On a KL there is no quantum timer but -** it is approximated by performance counters to provide similar 4.096-usec -** units to ITS. On a KS (which implements SPM) the units are 3.9/16 usec -** (same as the time base) which ITS converts to 3.9-usec. -** Theoretically the quantum timer is continuously -** incremented whenever there is no PI in Progress. Since it is hacked -** in native mode, only 32 bits are supported, but that should be sufficient -** since the original KA-10 counter was only 18 bits. -** To emulate this with a low-resolution clock, the quantum counter is -** only updated whenever: -** PIP status changes: -** Enter PIP: freeze quant -** Leave PIP: unfreeze quant -** counter is read by ITS SPM instruction: freeze, read, unfreeze -** counter is set by ITS LMPR instruction: set, unfreeze -** millisecond clock ticks: add 1000 if unfrozen (not in PIP) -** The mechanics of un/freezing are: -** To unfreeze (start, so it can be ticked up by 1ms clock): -** quant = quant + -** To freeze value (stop, so it can be read): -** quant = quant - -** -** The basic idea is to normalize the quant counter whenever it is -** decoupled from the interval clock increment, by seeing how far it is in usec -** to the next interval tick. -** -** The same principle applies to maintaining the time base. -** -** Note that the code makes a simplifying assumption that each counter tick -** (ctick) is equivalent to 1/4 usec, rather than exactly 1/4.1 usec. -** This allows usec quantities to be added and subtracted from the counters -** simply by shifting them up by 2 bits. -*/ - -static void tim_ksupdate(void *); - -/* The main loop countdown is considered to be in units of short microseconds. -** Each such unit is equivalent to 4 timebase units. The countdown starts -** at a value calculated to reach zero after 1 millisecond, whereupon all -** other counters are updated. -*/ - -/* TIM_INIT - Initialize time stuff. KS version. -*/ -static int -tim_init(void) -{ - /* Init new internal clock */ - clk_init(); - -#if KLH10_ITIME_SYNCH - clk_itickset(CLK_USECS_PER_SEC/60); /* Default to 60HZ */ -#elif KLH10_ITIME_INTRP - clk_itickset(CLK_USECS_PER_SEC/30); /* Default to 30HZ */ -#endif /* (60 still too fast) */ - - clk_itmrget(tim_ksupdate, (char *)NULL); /* Put in 1st itick entry */ - -#if KLH10_RTIME_SYNCH - cpu.tim.tim_base[0] = 0; /* Initialize time base */ - cpu.tim.tim_base[1] = 0; - cpu.tim.tim_base[2] = 0; - tim_baseunfreeze(); /* Start it going */ - -#elif KLH10_RTIME_OSGET -# if KLH10_SYS_ITS /* ITS uses timebase as date/time clock if value OK */ - { - FILE *f; - - if ((f = fopen(TIMEBASEFILE, "r")) == NULL) { - LRHSET(cpu.tim.wrbase.w[0], 0, 0); - LRHSET(cpu.tim.wrbase.w[1], 0, 0); - os_rtmget(&cpu.tim.osbase); - return FALSE; - } - fread((char *)&cpu.tim.wrbase, sizeof(cpu.tim.wrbase), 1, f); - fread((char *)&cpu.tim.osbase, sizeof(cpu.tim.osbase), 1, f); - os_rtm_adjust_base(&cpu.tim.osbase, &cpu.tim.osbase, 0); - if (ferror(f)) { - fclose(f); - return FALSE; - } - fclose(f); - } -# else /* T20 (and T10?) use timebase as uptime clock, must clear */ - LRHSET(cpu.tim.wrbase.w[0], 0, 0); - LRHSET(cpu.tim.wrbase.w[1], 0, 0); - os_rtmget(&cpu.tim.osbase); -# endif /* !ITS */ -#endif - - return TRUE; -} - - -#if KLH10_QTIME_OSREAL || KLH10_QTIME_OSVIRT -static osrtm_t qcbase; - -/* Freeze - get realtime and compute # quantums used since last qcbase. */ -int32 -quant_freeze(int32 qc) -{ - osrtm_t rtm; - -#if KLH10_QTIME_OSREAL - os_rtmget(&rtm); /* Find current realtime */ -#else - os_vrtmget(&rtm); /* Find current virtual time used */ -#endif - os_rtmsub(&rtm, &qcbase); /* Get diff since last freeze */ - - /* Paranoia check - last line of defense against systems that - ** don't report runtime in a monotonically increasing way. - ** See os_vrtmget() for more detail. - */ -#if CENV_SYSF_BSDTIMEVAL - if (rtm.tv_sec < 0 || rtm.tv_usec < 0) { -# if 0 /* Disable output for now. Perhaps bump a meter later */ - fprintf(stderr, "[Neg quantum! %ld,%ld]\r\n", - (long)rtm.tv_sec, (long)rtm.tv_usec); -# endif - return qc; - } -#endif /* CENV_SYSF_BSDTIMEVAL */ - - return qc + (int32)os_rtm_toqct(&rtm); /* Convert to quantum ticks! */ -} - -/* Unfreeze - get realtime and remember as qcbase for current quantum count. */ -int32 -quant_unfreeze(int32 qc) -{ -#if KLH10_QTIME_OSREAL - os_rtmget(&qcbase); /* Find current realtime */ -#else - os_vrtmget(&qcbase); /* Find current virtual time used */ -#endif - return qc; -} -#endif /* OSREAL || OSVIRT */ - -#if KLH10_RTIME_SYNCH - -static void -tim_basefreeze(void) /* Freeze to read actual value */ -{ - register uint32 adjtim; - adjtim = CLK_USEC_UNTIL_ITICK() << 2; - cpu.tim.tim_base[0] = (cpu.tim.tim_base[0] - adjtim) & MASK32; - if (cpu.tim.tim_base[0] > -adjtim) { /* Check for underflow */ - if ((cpu.tim.tim_base[1] = (cpu.tim.tim_base[1]-1)&MASK32) == MASK32) - cpu.tim.tim_base[2]--; - } -} - -static void -tim_baseunfreeze(void) -{ - register uint32 adjtim; - adjtim = (CLK_USEC_UNTIL_ITICK() << 2); - cpu.tim.tim_base[0] = (cpu.tim.tim_base[0] + adjtim) & MASK32; - if (cpu.tim.tim_base[0] < adjtim) { /* Check for overflow */ - if ((cpu.tim.tim_base[1] = (cpu.tim.tim_base[1]+1)&MASK32)==0) - cpu.tim.tim_base[2]++; - } -} -#endif /* KLH10_RTIME_SYNCH */ - -/* TIM_KSUPDATE - Invoked when KS10 interval timer goes off; -** either OS timer fired, or internal synch counter counted out. -*/ -static void -tim_ksupdate(void *ignored) -{ -#if KLH10_RTIME_SYNCH - /* Update time base. */ - { - int32 intv4 = CLK_USECS_PER_ITICK << 2; /* Interval in 1/4 us units */ - - if (((cpu.tim.tim_base[0] += intv4) & MASK32) < intv4) - if ((cpu.tim.tim_base[1] = (cpu.tim.tim_base[1]+1)&MASK32) == 0) - ++cpu.tim.tim_base[2]; - } -#endif - -#if KLH10_SYS_ITS && KLH10_QTIME_SYNCH - /* Update quantum timer if not PIP. */ - if (!cpu.pi.pilev_pip) - cpu.pag.pr_quant += (CLK_USECS_PER_ITICK<<2); -#endif - - /* Attempt PI if interval done. - ** For now assume that call to tim_ksupdate() always implies interval done, - ** so always fire if permitted. - */ - if (op10m_skipn(cpu.tim.tim_intreg)) { /* If interval cntr is set */ - cpu.aprf.aprf_set |= APRF_TIM; /* "Timer Interval Done" */ - apr_picheck(); /* Check to trigger PI */ - } -} - -#if KLH10_DEBUG -int tim_debug = 0; /* Hack for KS timebase debugging */ -#endif - -/* TIM_RDTIM - Get time base using OS real time. -*/ -static void -tim_rdtim(register dw10_t *tbase) -{ -#if KLH10_RTIME_SYNCH - register w10_t hi, lo; - - /* Freeze/normalize the time-base quantity at this point */ - tim_basefreeze(); - -#define TB cpu.tim.tim_base - RHSET(lo, TB[0] & (H10MASK&~03)); /* Low 18 bits in RH */ - LHSET(lo, (TB[0] >> 18) & (((h10_t)1<<(32-18))-1)); /* 14 bits in LH */ - LHSET(lo, (LHGET(lo) | (TB[1] << 14)) & MASK17); /* 3 more */ - /* Note sign bit of low word must be clear, ditto bottom 2 bits */ - RHSET(hi, (TB[1] >> 3) & H10MASK); /* Shove 18 into RH */ - LHSET(hi, (TB[1] >> 21) & (((h10_t)1<<(32-21))-1)); /* 11 more bits */ - LHSET(hi, (LHGET(hi) | (TB[2] << 11)) & H10MASK); /* All rest */ -#undef TB - tim_baseunfreeze(); - tbase->w[0] = hi; - tbase->w[1] = lo; - -#elif KLH10_RTIME_OSGET - osrtm_t rtm; - - if (!os_rtmget(&rtm)) { - op10m_setz(tbase->w[0]); - op10m_setz(tbase->w[1]); - return; - } - - /* Now find difference between current time and old systime */ - os_rtmsub(&rtm, &cpu.tim.osbase); -#if KLH10_DEBUG - if (tim_debug) - printf("OS time diff: %ld sec, %ld usec\r\n", - (long)OS_RTM_SEC(rtm), (long)OS_RTM_USEC(rtm)); -#endif - /* Now convert this quantity to KS10 ticks, add that to old timebase, - ** and return the new timebase value. - ** A real pain on these crippled 32-bit machines. - */ - os_rtm_tokst(&rtm, tbase); - -#if KLH10_DEBUG - if (tim_debug) - printf("KS time diff: %#lo,,%#lo %#lo,,%#lo\r\n", - (long) LHGET(HIGET(*tbase)), (long) RHGET(HIGET(*tbase)), - (long) LHGET(LOGET(*tbase)), (long) RHGET(LOGET(*tbase)) ); - if (tim_debug) - printf("KS old time: %#lo,,%#lo %#lo,,%#lo\r\n", - (long) LHGET(HIGET(cpu.tim.wrbase)), (long) RHGET(HIGET(cpu.tim.wrbase)), - (long) LHGET(LOGET(cpu.tim.wrbase)), (long) RHGET(LOGET(cpu.tim.wrbase)) ); -#endif - - /* Slightly faster double addition. Assumes low signs always 0 */ - op10m_udaddw(*tbase, cpu.tim.wrbase.w[1]); /* First add low word */ - op10m_add(tbase->w[0], cpu.tim.wrbase.w[0]); /* Then add high word */ - -#if KLH10_DEBUG - if (tim_debug) - printf("KS new time: %#lo,,%#lo %#lo,,%#lo\r\n", - (long) LHGET(HIGET(*tbase)), (long) RHGET(HIGET(*tbase)), - (long) LHGET(LOGET(*tbase)), (long) RHGET(LOGET(*tbase)) ); -#endif - -#endif -} - -/* TIM_WRTIM - Set time base, relative to OS real time. -** Makes permanent record of offset so that the next KLH10 -** startup can pretend that the clock kept running. -*/ -static void -tim_wrtim(register dw10_t *tbase) -{ -#if KLH10_RTIME_SYNCH - dw10_t d; - - d = *tbase; - tim_basefreeze(); /* Stop, to get valid current time */ -#define TB cpu.tim.tim_base - TB[0] &= ~MASK12; /* Keep bottom 12 bits of current time! */ - TB[0] |= ((uint32)LHGET(LOGET(d)) << 18) | (RHGET(LOGET(d))&~MASK12); - TB[1] = (LHGET(LOGET(d)) >> (18-(35-32))) & 07; /* High 3 */ - TB[1] |= (((uint32)LHGET(HIGET(d)) << 18) | RHGET(HIGET(d))) << 3; - TB[2] = LHGET(HIGET(d)) >> (32-(18+3)); -#undef TB - tim_baseunfreeze(); - -#elif KLH10_RTIME_OSGET - FILE *f; - osrtm_t absolute_osbase; - - cpu.tim.wrbase = *tbase; - op10m_andcmi(cpu.tim.wrbase.w[1], MASK12); /* Zap low 12 bits */ - - if (!os_rtmget(&cpu.tim.osbase)) { - return; - } -# if KLH10_SYS_ITS /* ITS wants timebase to endure over reloads */ - if ((f = fopen(TIMEBASEFILE, "w")) == NULL) - return; - fwrite((char *)&cpu.tim.wrbase, sizeof(cpu.tim.wrbase), 1, f); -# if 1 - os_rtm_adjust_base(&cpu.tim.osbase, &absolute_osbase, 1); - fwrite((char *)&absolute_osbase, sizeof(absolute_osbase), 1, f); -# else - fwrite((char *)&cpu.tim.osbase, sizeof(cpu.tim.osbase), 1, f); -# endif - fclose(f); -# endif /* ITS */ -#endif -} - - -/* IO_RDTIM - (CONO TIM,) -*/ -ioinsdef(io_rdtim) -{ - register vmptr_t p0, p1; - dw10_t d; - - p0 = vm_xrwmap(e, VMF_WRITE); /* Check access for 1st word */ - va_inc(e); /* Bump E by 1, may wrap funnily */ - p1 = vm_xrwmap(e, VMF_WRITE); /* Check access for 2nd word */ - - tim_rdtim(&d); /* Read time double-word into here */ - vm_pset(p0, HIGET(d)); /* OK, set the double-word */ - vm_pset(p1, LOGET(d)); - return PCINC_1; -} - -/* IO_WRTIM - (CONO MTR,) Set Time Base -** Note that the bottom 12 bits cannot be set. They are left as whatever -** they already were in the time base registers. -*/ -ioinsdef(io_wrtim) -{ - dw10_t d; - vm_dread(e, d); /* Fetch the double */ - tim_wrtim(&d); /* Store it as time base! */ - return PCINC_1; -} - -/* IO_RDINT - (CONI TIM,) -*/ -ioinsdef(io_rdint) -{ - vm_write(e, cpu.tim.tim_intreg); /* Store interval register into E */ - return PCINC_1; -} - -/* IO_WRINT - (CONI MTR,) Set KS10 interval counter period from c(E) -** -** The interval counter counts down in the same units as the time -** base (at 4.1MHz, each tick represents 1/4.1 usec) -** This instruction is only invoked once during monitor startup -** so doesn't need to be fast, and only a few specific cases are provided -** for. -** ITS uses a 60 Hz period (0205355) -** T20 uses a 1000 Hz period ( 010004) -** T10 uses a 60 Hz period (0200000) but twiddles it incessantly -** for leap jiffy, leap msec, etc. -** -** It isn't clear what happens if the period is set to 0. This code -** assumes it turns the counter off. It's possible a real KS might -** interpret this as interrupting the next time the counter overflows, -** which could be anywhere from 1 usec to 140 minutes. -*/ -ioinsdef(io_wrint) -{ - register w10_t w; - - w = vm_read(e); /* Read new interval register from E */ - cpu.tim.tim_intreg = w; - -#if KLH10_ITIME_INTRP - INTF_INIT(cpu.intf_clk); - if (op10m_skipn(w)) { - register uint32 usec; - - if (!LHGET(w)) { - if (RHGET(w) == 0205355) /* ITS: 1/60 sec? */ - usec = CLK_USECS_PER_SEC/60; - else if (RHGET(w) == 01004) /* T20: 1ms? */ - usec = CLK_USECS_PER_MSEC; - else if ((0200000 <= RHGET(w)) /* T10: within "60Hz" range? */ - && (RHGET(w) <= 0220000)) - usec = CLK_USECS_PER_SEC/60; - else - goto gencase; - } - else if (LHGET(w) < 037777) { /* Ensure no ovfl */ - gencase: - /* General case: usec = (ticks * 1/4.1) - ** Compute this as ((ticks * 10) / 41) - */ - usec = (LHGET(w) << H10BITS) | RHGET(w); - usec = (usec * 10) / 41; - } else { - fprintf(stderr, "[io_wrint: Unsupported interval: %lo,,%lo]\r\n", - (long)LHGET(w), (long)RHGET(w)); - return PCINC_1; /* Do nothing */ - } - - /* Ask to change interval timer. Normally this request will - ** be ignored, unless KLH10 user has cleared clk_ithzfix. - ** See corresponding KL code in io_co_tim(). - */ - clk_itickset(usec); /* Set timer going! */ - - } else { -#if 0 - /* Don't allow KS to get any more interval timer ints, but - ** must keep internal CLK timer alive. - */ -#endif - } -#endif /* KLH10_ITIME_INTRP */ - - return PCINC_1; -} -#endif /* KLH10_CPU_KS */ - -#if KLH10_CPU_KL - -/* KL timer and meter code */ - -/* -The KL10 has two different time counters, a time base and an interval counter, -very similar to those for the KS. - -INTERVAL COUNTER: - The interval counter is a 12-bit 100kHz counter (each unit is -exactly 10 usec). The minimum interval is thus 10 usec to 40.950 -msec. TOPS-20 sets its interval to 0144 (100.) so that it interrupts -every 1ms. - Whenever the countup reaches a value equal to the interval -period, it sets its "Done" flag (which may trigger a PI), clears -itself, and starts over. If the count reaches its maximum value -without matching the set period (this can only happen if the period is -set at a time when the count is already greater than the period), then -both the "Done" and "Overflow" flags are set. - PI for the interval counter is specially handled -- it -executes the instruction at EPT+514. Hence it needs to be checked for -in a slightly different way. - - Synchronous mode emulation: each instruction is interpreted as 1 usec - and the interval period used for the clock poll countdown. - If the interval counter is off, a default period of 1ms - is used for clock polling. - Interrupt mode emulation: the interval period is translated into - suitable host platform units. Currently there may be a - check for T20's 1ms period to silently substitute a more - manageable 10ms period instead. - -TIME BASE: - The time base is one of the peculiar KL double-word counts. -The 16-bit hardware count portion is incremented at 1MHz (one tick = 1 -usec); note this is shifted up 12 bits from the low end of the doubleword. -(TOPS-20 basically ignores those low 12 bits.) - - Synchronous mode emulation: As for the interval counter, each - instruction is interpreted as 1 usec and the time base - maintained from the clock poll countdown (which has a - period corresponding to either the interval counter or - the default polling count). - OS mode emulation: every RDTIME request instigates a host platform - system call for the current time-of-day in units as small - as feasible. From this is subtracted the OS time base - as of the last KL timebase check, and the result - translated into 1MHz units. - -Beware: Only 32 bits of hardware counter are guaranteed, which at 1MHz is - approximately 4K sec == 1 hour. There will be a time loss for - KLH10_RTIME_OSGET if execution is suspended for that long! -*/ - -static void tim_klupdate(void *); - -/* TIM_INIT - Initialize time stuff. KL version. -*/ -static int -tim_init(void) -{ - /* Initialize interval counter */ - cpu.tim.tim_on = 0; - cpu.tim.tim_flgs = 0; - cpu.tim.tim_intper = 0; - cpu.tim.tim_intcnt = 0; - - /* Initialize time base */ -#if KLH10_RTIME_SYNCH - cpu.tim.tim_ibased = 0; - cpu.tim.tim_ibaser = 0; -#elif KLH10_RTIME_OSGET - if (!os_rtmget(&cpu.tim.tim_osbase)) { /* Get OS realtime */ - fprintf(stderr, "tim_init: Cannot get OS realtime!\n"); - return FALSE; - } -#endif - - /* Init internal clock */ - clk_init(); - clk_itickset(CLK_USECS_PER_SEC/30); /* Default to 30HZ */ - /* (60 still too fast) */ - clk_itmrget(tim_klupdate, (char *)NULL); /* Put in 1st itick entry */ - - return TRUE; -} - -/* TIM_KLUPDATE - Invoked once per ITICK (interval timer tick) -** KL version. -*/ -static void -tim_klupdate(void *ignored) /* Arg is unused */ -{ -#if KLH10_RTIME_SYNCH - /* Update time base by adding # of usec since last update, which - * may have been due to either this function or a RDTIME. - * Avoid bogus value in case interval period changed. - */ - cpu.tim.tim_ibased += - (CLK_USECS_PER_ITICK < cpu.tim.tim_ibaser) ? 0 - : (CLK_USECS_PER_ITICK - cpu.tim.tim_ibaser); - cpu.tim.tim_ibaser = 0; /* Reset usec since last itick */ -#endif - - /* Attempt PI if interval done. - ** For now assume that call to tim_klupdate() always implies interval done. - */ - if (cpu.tim.tim_on) { - cpu.tim.tim_intcnt = 0; /* Reset countup */ - - cpu.tim.tim_flgs |= TIM_RDONE; /* "Timer Interval Done" */ - if (cpu.pi.pilev_timreq |= cpu.tim.tim_lev) /* Add PI if any */ - pi_devupd(); /* Check to trigger intrupt */ - } -} - -/* General-purpose utility to update counter doublewords -** Note hair to ensure that "hardware" counter is shifted up by 12. -*/ -#define DWCNT_UPDATE(pa, cntvar) \ - { vp = vm_physmap(pa); \ - d = vm_pgetd(vp); /* Get double (EPT/UPT is known safe ref) */\ - if ((cntvar) & ~MASK23) /* Add high bits if any */\ - op10m_addi(d.w[0], ((cntvar)>>23) & H10MASK); \ - LRHSET(w, ((cntvar) >> (H10BITS-12))&H10MASK, ((cntvar)<<12) & H10MASK); \ - op10m_udaddw(d, w); /* Add W into D */\ - vm_psetd(vp, d); /* Store back into original loc as update */\ - (cntvar) = 0; /* Clear "hardware" counter */\ - } - -static pcinc_t -mtr_store(register unsigned int pa, - register uint32 *acnt, - register vaddr_t e) -{ - register w10_t w; /* Vars needed for MTR_DWUPDATE */ - register dw10_t d; - register vmptr_t vp; - - if (cpu.mr_paging) { - DWCNT_UPDATE(pa, *acnt) /* Do update, leave dword in d */ - } else { - /* If no paging, can't refer to EPT or UPT. Just pass on - ** value of hardware counter, and don't reset it. - */ - LRHSET(d.w[0], 0, (*acnt >> 23) & H10MASK); /* Hi bits into hi wd */ - LRHSET(d.w[1], (*acnt >> (H10BITS-12))&H10MASK, - (*acnt << 12) & H10MASK); - } - - /* Now store in desired location */ - vm_dwrite(e, d); /* Can pagefail after all this, sigh */ - return PCINC_1; -} - - -/* RDPERF (70200 = BLKI TIM,) Read Performance Analysis Count -** Read process execution time doubleword from EPT+512, -** add current hardware counter, store result in E, E+1. -** NOTE: PRM 3-61 is *INCORRECT*. Description there is a duplicate of -** that for RDEACT. EPT map on p.3-30 is right. -*/ -ioinsdef(io_rdperf) -{ - return mtr_store((cpu.mr_ebraddr + EPT_PRF), /* EPT+512 */ - &cpu.tim.tim_perf, - e); -} - -/* RDTIME (70204 = DATAI TIM,) Read Time Base -** Read time base doubleword from EPT+510, -** add current hardware time base counter, store result in E, E+1. -*/ -/* - The KL10 time base is a 59-bit doubleword integer (low sign is -0, low 12 bits are ignored) that increments at exactly 1MHz (1 each usec). -It's OK to set the last 12 bits if the extra precision is available from -the host platform. - -Note that 20 bits are needed to store a 1M value. Thus 32 bits is -exactly enough to hold the result of left-shifting a value up to 1M -by 12 bits (for adding into low part of word). -*/ -/* NOTE: - It appears that the only place the T20 monitor actually reads the -EPT timebase contents (rather than using RDTIME) is a place in APRSRV -called GETMID where the low word is used as a unique structure media ID. -(extremely bogusly, if you ask me). - It would be VERY nice if the EPT update could be totally flushed -and the timebase merely returned in response to a RDTIME. But if GETMID -is to be supported (and it looks suspiciously important), then EPT+510 -needs to be updated every so often just on the .000001% probability it -might be needed. - Perhaps a closer examination of the caller of GETMID (WRTHOM in -DSKALC.MAC) might reveal something else we could trigger the update on. -The best candidate seems to be a WRTIME (CONO MTR,) that resets the -time base; by setting the low 12 bits (otherwise unused) of the location -to some random fixed value, can ensure that the initial structure always gets -that value as its media ID. - -*/ -ioinsdef(io_rdtime) -{ - uint32 ibase; - -#if KLH10_RTIME_SYNCH - /* Find # usec since last RDTIME and add them into EPT timebase. - ** tim_ibased is always added directly - it accounts for usec - ** since last RDTIME, up to the most recent interval tick. - ** tim_ibaser however is only used to remember the last value of - ** CLK_USEC_SINCE_ITICK(), ie usec since the most recent interval tick. - ** The difference between the new value and the old one is the - ** # of usec elapsed since the last update of tim_ibased. - */ - uint32 cticks = CLK_USEC_SINCE_ITICK(); - - if (cticks >= cpu.tim.tim_ibaser) { - ibase = cpu.tim.tim_ibased + (cticks - cpu.tim.tim_ibaser); - } else { - /* Shouldn't happen, but be prepared if weird change to interval - ** period causes this. - */ - fprintf(stderr, "[io_rdtime: tim_ibaser skew, %ld < %ld]\r\n", - (long)cticks, (long)cpu.tim.tim_ibaser); - ibase = cpu.tim.tim_ibased; - } - cpu.tim.tim_ibaser = cticks; /* Remember last subinterval cnt */ - cpu.tim.tim_ibased = 0; - -#elif KLH10_RTIME_OSGET - osrtm_t rtm, rtmbase; - - if (!os_rtmget(&rtm)) /* Get OS realtime */ - panic("io_rdtime: Cannot get OS realtime!"); - rtmbase = rtm; /* Remember for new base */ - os_rtmsub(&rtm, &cpu.tim.tim_osbase); /* Find elapsed realtime */ - cpu.tim.tim_osbase = rtmbase; /* Set base for next time */ - ibase = os_rtm_toklt(&rtm); /* Convert diff to KL ticks */ -#else - ibase = 0; -#endif - - return mtr_store((cpu.mr_ebraddr + EPT_TBS), /* EPT+510 */ - &ibase, - e); -} - -/* WRPAE (70210 = BLKO TIM,) Write Performance Analysis Enables -** Select counting method and conditions for PERF counter, based -** on c(E). -** Makes a read reference but otherwise is a nop for now. -*/ -ioinsdef(io_wrpae) -{ - (void) vm_redmap(e); /* Do a read reference */ - return PCINC_1; -} - -/* CONO TIM, (70220) Conditions Out, Interval Counter -** Set up interval counter according to E. -** It's unclear what a zero interval might mean. For the time -** being I'm interpreting it as 1<<12 (4096.) -*/ -ioinsdef(io_co_tim) -{ - register h10_t ebits = va_insect(e); - register unsigned int newper = ebits & TIM_PERIOD; /* 12 bits */ - - if (!newper) /* Interpret a zero period as 4096 */ - newper = 1<<12; - - /* Check for clearing TIM_RDONE and TIM_ROVFL flags */ - if (ebits & TIM_WFCLR) { - cpu.tim.tim_flgs = 0; /* Clear Done & Overflow flags */ - if (cpu.pi.pilev_timreq) { /* If PI was set, */ - cpu.pi.pilev_timreq = 0; /* clear it, and */ - pi_devupd(); /* propagate the change */ - } - } - - /* Not clear (:-) how to clear counter in middle of a countdown. - ** Assume it only happens when turning things off (in which case - ** value is irrelevant) or on (in which case we simply restart). - */ - if (ebits & TIM_WCLR) - cpu.tim.tim_intcnt = 0; /* Clear countup */ - - /* See if changing either the period or the on/off state. - ** Generally they are changed only once at monitor startup and never - ** thereafter, although CONO TIM, must be done after every interrupt - ** in order to turn off the DONE bit. - */ - if (newper != cpu.tim.tim_intper - || (cpu.tim.tim_on != (ebits & TIM_ON))) { - if (ebits & TIM_ON) { /* Turn interval counter on? */ - /* Changing period can glitch all meters (and timebase) unless - ** they are partially incremented to compensate. But ignore that - ** for the time being since no known monitor ever changes in - ** midstream. - ** Note previous code that prevents newper from being 0. - */ -#if 0 /* KLH10_ITIME_SYNCH */ - /* For now, ignore "minor" change attempts. T10 tries to - ** twiddle this incessantly for a "leap jiffy" and it will - ** never do any good. So avoid wasting the overhead... - ** This check ignores attempts to reduce the period or increase it - ** by less than 3. - */ - if (((int)(newper - cpu.tim.tim_intper)) > 2) - clk_itickset(((uint32)newper)*10); - -#elif 1 /* KLH10_ITIME_INTRP */ - /* Go ahead and ask the clock code for a new timer period. - ** Normally this request will be ignored in favor of a fixed - ** runtime parameter (clk_ithzfix), unless the user has cleared it. - ** This both cures T10's twiddling (centered around 60Hz) - ** and avoids T20's too-fast 1ms tick. - */ - clk_itickset(((uint32)newper)*10); -#endif - } else { /* Turning counter off */ - /* No explicit turnoff of CLK internal timer, cuz other things - ** like peripheral device timeouts may depend on it. - ** Clearing TIM_ON bit will suffice to ensure that 10 doesn't - ** receive unexpected interval interrupts. - ** - ** Doesn't keep interval counter state from changing; oh well. - */ - } - cpu.tim.tim_on = (ebits & TIM_ON); /* Set flag to new state */ - cpu.tim.tim_intper = newper; - } - - return PCINC_1; -} - -/* CONI TIM, (70224) Conditions In, Interval Counter -** Read status of interval counter into c(E). -*/ -ioinsdef(io_ci_tim) -{ - register w10_t w; - - if (cpu.tim.tim_on) { -#if KLH10_ITIME_SYNCH /* Get 10usec units */ - cpu.tim.tim_intcnt = CLK_USEC_SINCE_ITICK() / 10; -#elif KLH10_ITIME_INTRP - cpu.tim.tim_intcnt++; /* Can't tell, so just bump each time */ -#endif - } - LRHSET(w, (cpu.tim.tim_intcnt & MASK12), - cpu.tim.tim_on | cpu.tim.tim_flgs | cpu.tim.tim_intper); - - vm_write(e, w); - return PCINC_1; -} - -/* CONSZ TIM, (70230) Skip if all TIM status bits in non-zero E are zero. -*/ -ioinsdef(io_sz_tim) -{ -#if 1 - return (va_insect(e) & - (cpu.tim.tim_on | cpu.tim.tim_flgs | cpu.tim.tim_intper)) - ? PCINC_1 : PCINC_2; -#else - return (va_insect(e) - && !(va_insect(e) & - (cpu.tim.tim_on | cpu.tim.tim_flgs | cpu.tim.tim_intper))) - ? PCINC_2 : PCINC_1; -#endif -} - -/* CONSO TIM, (70234) Skip if any TIM status bits in E are set. -*/ -ioinsdef(io_so_tim) -{ - return (va_insect(e) & - (cpu.tim.tim_on | cpu.tim.tim_flgs | cpu.tim.tim_intper)) - ? PCINC_2 : PCINC_1; -} -#endif /* KL */ - -#if KLH10_CPU_KL - -/* Device MTR */ - - -/* MTR_UPDATE - Carry out the "update accounts" operation -** described by PRM 3-57 for the Execution and Memory accounts. -** Called by pager code when UBR is set. -*/ -void -mtr_update(void) -{ - register w10_t w; /* Vars needed for DWCNT_UPDATE */ - register dw10_t d; - register vmptr_t vp; - - if (cpu.tim.mtr_on && cpu.mr_paging) { - DWCNT_UPDATE(cpu.mr_ubraddr + UPT_MRC, cpu.tim.mtr_mact) - DWCNT_UPDATE(cpu.mr_ubraddr + UPT_PXT, cpu.tim.mtr_eact) - } -} - - -/* RDMACT (70240 = BLKI MTR,) Read Memory Account -** Read memory reference doubleword from UPT+506, -** add current hardware counter, store result in E, E+1. -*/ -ioinsdef(io_rdmact) -{ - return mtr_store( - (cpu.mr_ubraddr + UPT_MRC), /* UPT+506 */ - &cpu.tim.mtr_mact, - e); -} - -/* RDEACT (70244 = DATAI MTR,) Read Execution Account -** Read process execution time doubleword from UPT+504, -** add current hardware counter, store result in E, E+1. -*/ -ioinsdef(io_rdeact) -{ - return mtr_store( - (cpu.mr_ubraddr + UPT_PXT), /* UPT+504 */ - &cpu.tim.mtr_eact, - e); -} - -/* WRTIME (70260 = CONO MTR,) Conditions Out, Meters -** Set up meters and timing. -** See comments for io_rdtime() regarding time base setup. -*/ -ioinsdef(io_wrtime) -{ - register uint18 erh = va_insect(e); - - if (erh & MTR_SUA) { - /* Set up Accounts */ - - /* Reflect new flag bits in test words */ - cpu.tim.mtr_on = (erh & MTR_AON); - cpu.tim.mtr_ifexe = (erh & MTR_AEPI); - cpu.tim.mtr_ifexepi = (erh & MTR_AENPI); - - /* Actually do something about it? */ - } - - /* Remember flags for CONI */ - cpu.tim.mtr_flgs = erh & (MTR_AEPI|MTR_AENPI|MTR_AON|MTR_TBON|MTR_ICPIA); - - /* Set PIA for interval counter */ - cpu.tim.tim_lev = pilev_bits[erh & MTR_ICPIA]; - if (cpu.pi.pilev_timreq) { /* If PI already being requested */ - cpu.pi.pilev_timreq = cpu.tim.tim_lev; /* may need to change lev */ - pi_devupd(); /* and re-check priority */ - } - - /* Take care of time base */ - if (erh & MTR_TBOFF) - cpu.tim.tim_tbon = 0; - if (erh & MTR_TBON) - cpu.tim.tim_tbon = MTR_TBON; - if (erh & MTR_TBCLR) { /* Reset time base hardware ctr */ -#if KLH10_RTIME_SYNCH - cpu.tim.tim_ibased = 0; - cpu.tim.tim_ibaser = CLK_USEC_SINCE_ITICK(); -#elif KLH10_RTIME_OSGET - (void) os_rtmget(&cpu.tim.tim_osbase); -#endif - /* Special hack. See comments at io_rdtime for explanation. */ - if (cpu.mr_paging) { - vmptr_t vp = vm_physmap(cpu.mr_ebraddr + EPT_TBS + 1); - vm_psetrh(vp, vm_pgetrh(vp) | 01367); /* 759. */ - } - } - - return PCINC_1; -} - -/* CONI MTR, (70264) Conditions In, Meters -** Read status of meters & timers into c(E). -*/ -ioinsdef(io_ci_mtr) -{ - register w10_t w; - - LRHSET(w, 0, cpu.tim.mtr_flgs); - vm_write(e, w); - return PCINC_1; -} - -/* CONSZ MTR, (70270) Skip if all MTR status bits in non-zero E are zero. -*/ -ioinsdef(io_sz_mtr) -{ -#if 1 - return (va_insect(e) & cpu.tim.mtr_flgs) - ? PCINC_1 : PCINC_2; -#else - return (va_insect(e) && !(va_insect(e) & cpu.tim.mtr_flgs)) - ? PCINC_2 : PCINC_1; -#endif -} - -/* CONSO MTR, (70274) Skip if any MTR status bits in E are set. -*/ -ioinsdef(io_so_mtr) -{ - return (va_insect(e) & cpu.tim.mtr_flgs) - ? PCINC_2 : PCINC_1; -} - -#endif /* KL */ - -/* PI "device" code. */ - -/* Later make these EXTDEFs in kn10def.h and initialize both at runtime */ -int pilev_bits[8] = { - 0, PILEV1, PILEV2, PILEV3, PILEV4, PILEV5, PILEV6, PILEV7 -}; -unsigned char pilev_nums[PILEVS+1] = { 0 }; /* 1st entry zero */ - -/* PI_INIT - Called at startup to initialize PI "device" stuff -*/ -static void -pi_init(void) -{ - register int i; - - /* Set up pilev_nums array, skipping 1st entry which is 0 */ - for (i = 1; i <= PILEVS; ++i) { - register unsigned num = 8, r = i; - while (r) --num, r >>= 1; - pilev_nums[i] = num; - } - - /* Clear PI system */ - cpu.pi.pisys_on = 0; - cpu.pi.pilev_on = 0; - cpu.pi.pilev_pip = 0; - cpu.pi.pilev_preq = 0; - cpu.pi.pilev_dreq = 0; - - /* Clear all device requests too */ - cpu.pi.pilev_aprreq = 0; -#if KLH10_CPU_KS - cpu.pi.pilev_ub1req = 0; - cpu.pi.pilev_ub3req = 0; -#elif KLH10_CPU_KL - cpu.pi.pilev_timreq = 0; - cpu.pi.pilev_rhreq = 0; - cpu.pi.pilev_dtereq = 0; - cpu.pi.pilev_diareq = 0; -#endif -} - -/* RDPI (CONI PI,) - Stores PI status word in E. -** The only PI data subject to asynch update is cpu.pi.pilev_dreq which -** isn't returned in the status, so we don't need to lock anything. -*/ -ioinsdef(io_rdpi) -{ - register w10_t w; - LRHSET(w, cpu.pi.pilev_preq, - ((cpu.pi.pilev_pip< cpu.pi.pilev_pip) ? levs : 0; -} - -#if KLH10_CPU_KS - -/* PI_XCT - Take PI interrupt - KS10 version. -** -** Instruction loop aborted due to PI interrupt on given level. -** Level mask is furnished, as returned by pi_check(). -** Save context, set up new, then return to main loop. -** -** No cleanup needs to be done here as whatever was needed has already -** been done -- this routine is only called from the main loop between -** instructions. The next instruction (what PC points to) might actually -** have just been aborted and backed out of. -** -** Taking an interrupt involves executing the "interrupt vector" -** dispatch instruction for that particular interrupt. This must be -** either a JSR or XPCW (ITS only uses JSR); anything else causes an -** "illegal interrupt" halt. A JSR automatically enters Exec mode; -** an XPCW uses the new flags. -** -** Normally the PI dispatch instruction for level N is found at location -** EPT+040+(2*N) -** However, for an interrupt caused by a Unibus device with vector -** V on adapter C, the PI dispatch is located at: -** c(EPT+0100+C) + (V/4) -** That is, C indexes into the EPT to get a table pointer; V is used -** as an offset from that pointer to get the dispatch instruction location. -** -** NOTE! The vector table address is mapped, not physical! PRM doesn't -** mention this, but this is what TOPS-20 expects. -** -** (NOTE: The DEC Proc Ref Man (6/82 p.4-4) claims adapter #s (1 and 3) -** are not equivalent to the controller #s used in IO addrs (0 and 1). However -** this appears to be wrong and conflicts with the description of IO instrs -** on p. 2-128 of the same manual. Assumption here is controller==adapter.) -** -** Lower-numbered levels have higher priority. -** Within a level, lowest adapter # has highest priority. -** Within an adapter, it appears to be a free-for-all, but presumably -** whichever device is physically closer on the Unibus wins. -** This is represented here by the order in which the devices are -** checked. -** -** Regarding the actual PI level that a Unibus device interrupts on: -** a device may interrupt the Unibus on one of BR4-BR7 (higher number -** has higher priority). BR4&BR5 become KS10 PI requests on the "low" level, -** BR6&BR7 become KS10 PI requests on the "high" level. The actual -** specification of the high and low levels is made by the setting of -** the Unibus Adapter Status register (at UB_UBASTA). -*/ -static void -pi_xct(register int lev) -{ - register w10_t w; - register vaddr_t e; - register paddr_t intvec, pa; /* Note phys addr */ - register int num; - - /* First do a JFFO equivalent to return the PI level number. - ** This hack uses a 128-byte array for speed (32 wds on most machines). - */ - if (!lev || (lev & ~PILEVS)) /* Error checking */ - panic("pi_xct: bad PI level"); - num = pilev_nums[lev]; /* Presto! */ - lev = pilev_bits[num]; /* Get clean single bit */ - - /* Find dispatch info, set up new context, PC, etc. */ - if (lev & cpu.pi.pilev_dreq) { /* Device request? */ - if (lev & cpu.pi.pilev_aprreq) { /* If APR device, do */ - intvec = cpu.mr_ebraddr + EPT_PI0 + (2 * num); /* normal stuff. */ - /* Assume APR interrupt does not automatically turn itself off - ** after being granted, so aprreq remains set. - */ - w = vm_pget(vm_physmap(intvec)); /* Fetch from phys mem */ - } else { - if ((lev & cpu.pi.pilev_ub1req) /* Unibus #1? */ - && (intvec = ub1_pivget(lev))) - pa = EPT_UIT+1; - else if ((lev & cpu.pi.pilev_ub3req) /* Unibus #3? */ - && (intvec = ub3_pivget(lev))) - pa = EPT_UIT+3; - else - panic("pi_xct: Spurious pilev_dreq: %o", cpu.pi.pilev_dreq); - /* If this panic is hit, there is a BUG someplace in the - ** KLH10 code. You can proceed by using the "Set pilev_dreq 0" - ** command, but the bug really should be tracked down. - */ - - pa = vm_pgetrh(vm_physmap(cpu.mr_ebraddr+pa)); /* Get table ptr */ - if (!pa) panic("pi_xct: no PI dev table"); - intvec = pa + (intvec/4); /* Finally derive addr */ - - /* Danger zone -- use exec mapping, can page fault! - ** Uses phys mapping if paging off, will fail if NXM. - */ - if (cpu.mr_paging) { - va_lmake(e, 0, intvec & H10MASK); /* Convert to vaddr_t */ - w = vm_pget(vm_execmap(e, VMF_FETCH)); /* Map and get */ - } else - w = vm_pget(vm_physmap(intvec)); /* Fetch from phys mem */ - } - } else { - /* Must be non-device program-requested PI, do normal stuff */ - /* Find addr of int vector instr */ - intvec = cpu.mr_ebraddr + EPT_PI0 + (2 * num); - w = vm_pget(vm_physmap(intvec)); /* Fetch from phys mem */ - } - - /* Have dispatch vector address and fetched interrupt instr */ - - /* Now do it! - ** Note potential screwiness with EA calculation and mem refs. EA - ** is computed using current context (which might not be EXEC!), and - ** the memory refs are made to exec space with whatever the current AC - ** block is. - ** Also, it is POSSIBLE for the JSR/XPCW to cause a page failure while - ** trying to store the PC word. If this happens, the processor - ** should halt (per DEC Proc Ref Man (12/82) p.4-14 footnote). - ** For the time being we use another silly kludge flag (cpu.mr_inpi). - */ -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - } -#endif - switch (iw_op(w)) { - case I_JSR: - /* Interrupt JSR differs from a normal JSR in three ways: - ** (1) Saved PC is as-is, not PC+1 - ** (2) E ref is always to EXEC memory (phys, if paging off) - ** (3) PC flags are munged (in addition to normal clearing) - */ - e = ea_calc(w); /* Figure eff addr (hope I,X not set!) */ - - LRHSET(w, cpu.mr_pcflags, PC_INSECT); /* Cons up PC word */ - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - vm_pset(vm_execmap(e,VMF_WRITE), w); /* Store PC word */ - cpu.mr_inpi = FALSE; /* Now out of PI */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1); /* Clear normally */ -#if KLH10_ITS_1PROC - /* Note that the above PCFCLEAR also clears the PFC_1PR - ** one-proceed flag, in guise of PCF_AFI. This is proper. - */ -#endif - /* Won, now safe to mung processor state and go all the way */ - PCFCLEAR(PCF_USR); /* Switch to exec mode */ - apr_pcfcheck(); /* Make right things happen */ - va_inc(e); /* Increment new PC to E+1 */ - PC_JUMP(e); /* Jump there! */ - break; - - case I_JRST: - if (iw_ac(w) != 07) { /* Verify XPCW (JRST 7,) */ - default: - panic("Illegal Interrupt Halt! Bad int instr: %o,,%o", - LHGET(w), RHGET(w)); - } - /* Handle XPCW. Can't use ij_xpcw() since it checks the flags, - ** and uses current mapping for mem refs. Here, we ignore flags - ** and always use exec mapping once E is obtained. - ** Note mapping is physical if paging off. - */ - { - e = ea_calc(w); /* Figure eff addr (hope I,X not set!) */ - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - LRHSET(w, cpu.mr_pcflags, 0); /* Cons up flag word */ - vm_pset(vm_execmap(e,VMF_WRITE), w); /* Store */ - LRHSET(w, 0, PC_INSECT); /* Cons up PC word */ - va_inc(e); /* E+1 */ - vm_pset(vm_execmap(e,VMF_WRITE), w); /* Store */ - va_inc(e); /* E+2 */ - w = vm_pget(vm_execmap(e,VMF_READ)); /* Get flags */ - va_inc(e); /* E+3 */ - pa = vm_pgetrh(vm_execmap(e,VMF_READ)); /* Get PC */ - cpu.mr_inpi = FALSE; /* Now out of PI */ - - /* Won, now safe to mung processor state and go all the way */ - cpu.mr_pcflags = LHGET(w) & PCF_MASK; /* Set new flags */ - apr_pcfcheck(); /* Make right things happen */ - va_lmake(e, 0, pa); /* Get vaddr_t */ - PC_JUMP(e); /* Jump to E */ - } - break; - } - - /* Fix up PI vars to account for taking interrupt */ -#if KLH10_SYS_ITS - if (!cpu.pi.pilev_pip) /* Entering PIP? */ - cpu.pag.pr_quant = /* Yes, no more quantums! */ - quant_freeze(cpu.pag.pr_quant); -#endif /* ITS */ - cpu.pi.pilev_pip |= lev; /* PI now in progress on this level */ -#if KLH10_DEBUG - if (cpu.mr_debug) - fe_endpcfdbg(stderr); -#endif -} -#endif /* KLH10_CPU_KS */ - - -/* PI_DISMISS - Dismiss current PI interrupt. -** No-op if no currently active interrupt. -** Must check for re-interrupting if something else is still -** making a request on the same level. -*/ -void -pi_dismiss(void) -{ - if (cpu.pi.pilev_pip) { -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - } -#endif - /* Clear leftmost bit */ - cpu.pi.pilev_pip &= ~pilev_bits[pilev_nums[cpu.pi.pilev_pip]]; - -#if KLH10_SYS_ITS - if (!cpu.pi.pilev_pip) /* No longer PIP? */ - cpu.pag.pr_quant = /* Let 'er rip */ - quant_unfreeze(cpu.pag.pr_quant); -#endif /* ITS */ - if (pi_check()) /* Check for new interrupt to take */ - INSBRKSET(); /* This seems to hang us up?? */ -#if KLH10_DEBUG - if (cpu.mr_debug) { - fprintf(stderr, "(dismiss) "); - pishow(stderr); - putc(']', stderr); - } -#endif - } -} - -#if KLH10_CPU_KL - -/* PI_XCT - Take PI interrupt - KL10 version. -** -** Instruction loop aborted due to PI interrupt on given level. -** Level mask is furnished, as returned by pi_check(). -** Save context, set up new, then return to main loop. -** -** No cleanup needs to be done here as whatever was needed has already -** been done -- this routine is only called from the main loop between -** instructions. The next instruction (what PC points to) might actually -** have just been aborted and backed out of. -** -** Taking an interrupt involves executing the interrupt instruction -** for that particular interrupt. This must be either a JSR or XPCW -** anything else causes an "illegal interrupt" halt. -** (The KL allows BLKI/BLKO but T20 at least doesn't use it.) -** A JSR automatically enters Exec mode; an XPCW uses the new flags. -** -** The KL PI handling is rather complex. See the PRM. -** -** NOTE! The vector table address is mapped, not physical! PRM doesn't -** mention this, but this is what TOPS-20 expects. -** -** Lower-numbered levels have higher priority. -** Within a level, lowest device # has highest priority. -** -*/ -static void -pi_xct(register int lev) -{ - register w10_t w; - register vaddr_t e; - register paddr_t intvec; /* Note phys addr */ - register int num; - register int sect = 0; /* Default section for int instr */ - - /* First do a JFFO equivalent to return the PI level number. - ** This hack uses a 128-byte array for speed (32 wds on most machines). - ** PI level 0 is not supported. - */ - if (!lev || (lev & ~PILEVS)) /* Error checking */ - panic("pi_xct: bad PI level"); - num = pilev_nums[lev]; /* Presto! */ - lev = pilev_bits[num]; /* Get clean single bit */ - - /* Determine source of interrupt. - ** Get its PI function word and derive the interrupt address. - ** The order checked here is that described by PRM p.3-4 - ** Note: - ** In order to handle the situation where programmed requests can - ** be recognized even while their PI level is disabled, without - ** accidentally handling a device request instead, the programmed flags - ** are checked ahead of everything but the interval timer (as per - ** PRM), and the timer check includes a special test to verify that - ** non-program-request PIs are allowed. - */ - if ((lev & cpu.pi.pilev_timreq) /* Check interval timer */ - && (lev & cpu.pi.pilev_on)) { /* Verify enabled */ - /* Interval Timer - internal device. - ** Not clear if PI request is turned off when int is taken, or - ** when TIM_RDONE bit is cleared by int handler. - ** I'll assume it's similar to APR interrupts and leave it on, so - ** the handler must explicitly turn it off by clearing TIM_RDONE. - */ - LRHSET(w, PIFN_FVEC, EPT_ICI); /* Invent bogus fn word */ - intvec = cpu.mr_ebraddr + EPT_ICI; - - } else if ((lev & cpu.pi.pilev_preq) /* Check programmed requests */ - || (lev & cpu.pi.pilev_aprreq)) { /* Check APR request */ - /* Programmed PI requests and APR requests are handled - ** in the same way. They are not automatically turned off when - ** the interrupt is taken, and both use the standard interrupt. - */ - LRHSET(w, 0, 0); /* Use normal dispatch */ - intvec = cpu.mr_ebraddr + EPT_PI0 + (2*num); - - } else if (lev & cpu.pi.pilev_dreq) { - /* External device of some kind. Scan to find which one. - */ - extern struct device *devrh20[8], *devdte20[4]; - register int i; - register struct device *dv = NULL; - - /* First check 8 RH20 channels (maybe rotate order?) */ - if (lev & cpu.pi.pilev_rhreq) { - for (i = 0; i < 8; ++i) { - if ((dv = devrh20[i]) && (dv->dv_pireq & lev)) - break; - } - if (i >= 8) - panic("pi_xct: spurious pilev_rhreq: %o", cpu.pi.pilev_rhreq); - - w = (*(dv->dv_pifnwd))(dv); /* Get its PI funct word */ - LHSET(w, (LHGET(w)&~PIFN_DEV) | (i << 7)); /* Force dev bits */ - intvec = cpu.mr_ebraddr + (RHGET(w) & 0777); - - } else if (lev & cpu.pi.pilev_dtereq) { - /* Then check 4 DTE20s (maybe rotate order?) */ - for (i = 0; i < 4; ++i) { - if ((dv = devdte20[i]) && (dv->dv_pireq & lev)) - break; - } - if (i >= 4) - panic("pi_xct: spurious pilev_dtereq: %o", cpu.pi.pilev_dtereq); - - w = (*(dv->dv_pifnwd))(dv); /* Get its PI funct word */ - LHSET(w, (LHGET(w) & ~PIFN_DEV) | ((i+8)<<7)); - switch (LHGET(w) & PIFN_FN) { - case PIFN_F0: /* Device not interval timer, so do std int */ - case PIFN_FSTD: - intvec = cpu.mr_ebraddr + EPT_PI0 + (2*num); - break; - - case PIFN_FVEC: - /* Special DTE20 code for vector interrupt */ - intvec = cpu.mr_ebraddr + EPT_DT0 + (i<<3) + 2; - break; - - /* Special cases that only DTE20 should be using */ - case PIFN_FINC: - { - register vmptr_t vp; - va_gfrword(e, w); /* Make global virt addr from 13-35 */ - cpu.mr_inpi = TRUE; - vp = vm_execmap(e,VMF_WRITE); - cpu.mr_inpi = FALSE; - if (LHGET(w) & PIFN_Q) - w = vm_pget(vp), op10m_dec(w); - else - w = vm_pget(vp), op10m_inc(w); - vm_pset(vp, w); - return; - } - - case PIFN_FEXA: - case PIFN_FDEP: - case PIFN_FBYT: - panic("pi_xct: DTE20 function not implemented: %lo,,%lo", - (long)LHGET(w), (long)RHGET(w)); - - default: - panic("pi_xct: Illegal function word %lo,,%lo", - (long)LHGET(w), (long)RHGET(w)); - } - - } else if (lev & cpu.pi.pilev_diareq) { - /* Finally check single DIA20 */ - - /* DIA20 is apparently the only device that can ask for - ** a "dispatch interrupt" using bits 13-35 as exec virtual addr. - */ - panic("pi_xct: DIA20 interrupts not supported yet"); - - } else { - - panic("pi_xct: Spurious pilev_dreq: %o", cpu.pi.pilev_dreq); - /* If this panic is hit, there is a BUG someplace in the - ** KLH10 code. You can proceed by using the "Set pilev_dreq 0" - ** command, but the bug really should be tracked down. - */ - } - -#if 0 - /* Determine whether function is special, and execute immediately - ** if so. Distinguish DTE20s from other devices. - */ - switch (LHGET(w) & PIFN_FN) { - case PIFN_F0: /* Device is not interval timer, so do std int */ - case PIFN_FSTD: - intvec = cpu.mr_ebraddr + EPT_PI0 + (2*num); - sect = 0; /* Default section is 0 */ - break; - case PIFN_FVEC: - break; - - /* Special cases that only DTE20 should be using */ - case PIFN_FINC: - case PIFN_FEXA: - case PIFN_FDEP: - case PIFN_FBYT: - default: - panic("pi_xct: Illegal function word %lo,,%lo", - (long)LHGET(w), (long)RHGET(w)); - } - - /* Default section is 0 unless function is "dispatch interrupt", - ** i.e. a vector interrupt from DIA20. - */ - sect = 0; -#endif - - - } else - panic("pi_xct: Spurious int: %o", lev); - - /* Here, have PI function word in w and phys addr of instr in intvec. - ** Standard and vector interrupts come here. - */ - cpu.acblks[7][3] = w; /* Save function word in AC3, BLK7 */ - /* This works as long as BLK7 is not the - ** current AC block - safe enough. - */ - w = vm_pget(vm_physmap(intvec)); /* Fetch int instr from phys mem */ - - - /* Have dispatch vector address and fetched interrupt instr */ - - /* Now do it! - ** Note potential screwiness with EA calculation and mem refs. - ** EA is computed using EXEC context with whatever the current AC block - ** is (which may not be exec ACs), and the default section is normally 0. - ** - ** Also, it is POSSIBLE for the JSR/XPCW to cause a page failure while - ** trying to store the PC word or calculating E. If this happens, - ** the pager should set the "In-out Page Failure" APR flag - ** (per DEC PRM p.3-7 top parag) - ** For the time being we use another silly kludge flag (cpu.mr_inpi). - */ -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - } -#endif - switch (iw_op(w)) { - case I_JSR: - /* Interrupt JSR differs from a normal JSR: - ** (1) Saved PC is as-is, not PC+1 - ** (2) E ref is always to EXEC memory - ** (3) PC flags are munged (in addition to normal clearing) - ** (4) PC section test is checked from "sect" instead of PC - ** section. If PC had NZ sect, you lose big. One - ** reason why XPCW is "preferred"! - */ - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - e = xea_calc(w, sect); /* Figure EA (hope I,X not set!) */ - - if (sect) - PC_TOWORD(w); /* Use extended PC word, no flags */ - else - LRHSET(w, cpu.mr_pcflags, PC_INSECT); /* Cons up PC word */ - vm_pset(vm_execmap(e,VMF_WRITE), w); /* Store */ - cpu.mr_inpi = FALSE; /* Now out of PI */ - - /* Won, now safe to mung processor state and go all the way */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1 /* Clear normal flgs*/ - | PCF_USR | PCF_PUB); /* plus User & Public! */ - apr_pcfcheck(); /* Make right things happen */ - va_inc(e); /* Increment new PC to E+1 */ - PC_JUMP(e); /* Jump there! */ - break; - - case I_JRST: - if (iw_ac(w) != 07) { /* Verify XPCW (JRST 7,) */ - default: - panic("Illegal Interrupt Halt! Bad int instr: %o,,%o", - LHGET(w), RHGET(w)); - } - /* Handle XPCW. Can't use ij_xpcw() since it checks the flags, - ** and uses current mapping for mem refs. Here, we ignore flags - ** and always use exec mapping once E is obtained. - ** Note special hacking of PCS for extended KL. - */ -/* Other comments - Note PRM 3-7,3-8 comments on execution in kernel mode, plus - default section of 0 unless function word is a dispatch. - Does XPCW always think it's in kernel mode? Assume yes. This - means it always saves PCS in old flag word, and can set - new flags to whatever it wants. - New flags are simply taken from new-flag word; PCP and PCU are - evidently not treated specially. - PCS doesn't appear to be touched. - KCIO claims that "ucode sets PCS" but I can't find anything - of that sort in the PI code. No mention in PRM. No reason - I can imagine for setting PCS, anyway. -*/ - { - register w10_t npc; - - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - e = xea_calc(w, sect); /* Figure EA (hope I,X not set!) */ - LRHSET(w, cpu.mr_pcflags, pag_pcsget()); /* Cons up flag word */ - vm_pset(vm_execmap(e,VMF_WRITE), w); /* Store */ - PC_TOWORD(w); /* Cons up PC word (not PC+1 !!)*/ - va_inc(e); /* E+1 */ - vm_pset(vm_execmap(e,VMF_WRITE), w); /* Store */ - va_inc(e); /* E+2 */ - w = vm_pget(vm_execmap(e,VMF_READ)); /* Get flags */ - va_inc(e); /* E+3 */ - npc = vm_pget(vm_execmap(e,VMF_READ)); /* Get PC */ - cpu.mr_inpi = FALSE; /* Now out of PI */ - - /* Won, now safe to mung processor state and go all the way */ - cpu.mr_pcflags = LHGET(w) & PCF_MASK; /* Set new flags */ - apr_pcfcheck(); /* Make right things happen */ - va_lfrword(e, npc); /* Get 30-bit address from word */ - PC_JUMP(e); /* Jump to E */ - } - break; - -#if 1 /* Diagnostics emulation support */ - /* These instrs are actually UNDEFINED for use as interrupt - ** instructions but the KL diagnostics (DFKAA) expect them to work, - ** so this otherwise unnecessary code is provided to keep diags happy. - ** - ** In the absence of any definition, the algorithms here represent - ** my best guess at their operation. - ** Note that the ACs are whatever the current AC block is. - */ - case I_AOSE: - /* AOSE is done by doing the increment and falling thru to SKIPE. - ** DFKAA doesn't use a NZ AC, so don't bother checking it. - ** No flags (especially no trap flags!) are set. - */ - { - register vmptr_t vp; - - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - e = xea_calc(w, sect); /* Figure EA (hope I,X not set!) */ - vp = vm_execmap(e,VMF_WRITE); - cpu.mr_inpi = FALSE; /* Now out of PI */ - w = vm_pget(vp); - op10m_inc(w); /* Increment (don't set flags!) */ - vm_pset(vp, w); /* Store back */ - goto pi_skipe; - } - case I_SKIPE: - /* Interrupt SKIPE differs from a normal SKIPE: - ** DFKAA doesn't use a NZ AC, so don't bother checking it. - ** Skip means interrupt is dismissed. - ** No-skip means 2nd PI location is executed. For DFKAA this is - ** always a JSP, so we fall through (sort of) to handle it. - */ - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - e = xea_calc(w, sect); /* Figure EA (hope I,X not set!) */ - w = vm_pget(vm_execmap(e,VMF_READ)); - cpu.mr_inpi = FALSE; /* Now out of PI */ - - pi_skipe: - if (op10m_skipe(w)) { - /* Skipped, so dismiss the interrupt! - ** PIP isn't set -- basically nothing happens! - */ -#if KLH10_DEBUG - if (cpu.mr_debug) - fe_endpcfdbg(stderr); -#endif - return; - } - /* Didn't skip, so handle 2nd PI instr */ - w = vm_pget(vm_physmap(intvec+1)); /* Fetch from phys mem */ - if (iw_op(w) != I_JSP) { - panic("Illegal Interrupt Halt! Bad int instr: %o,,%o", - LHGET(w), RHGET(w)); - } - /* Fall through to handle JSP as 2nd PI location instr */ - - case I_JSP: - /* Interrupt JSP differs from a normal JSP: - ** (1) Saved PC is as-is, not PC+1 - ** (2) E ref is always to EXEC memory - ** (3) PC flags are munged (in addition to normal clearing) - ** (4) PC section test is checked from "sect" instead of PC - ** section. If PC had NZ sect, you lose big. One - ** reason why XPCW is "preferred"! - */ - cpu.mr_inpi = TRUE; /* Tell pager we're in PI */ - e = xea_calc(w, sect); /* Figure EA (hope I,X not set!) */ - cpu.mr_inpi = FALSE; /* Now out of PI */ - num = iw_ac(w); /* Remember AC to use */ - if (sect) - PC_TOWORD(w); /* Use extended PC word, no flags */ - else - LRHSET(w, cpu.mr_pcflags, PC_INSECT); /* Cons up PC word */ - ac_set(num, w); /* Store in AC */ - - /* Won, now safe to mung processor state and go all the way */ - PCFCLEAR(PCF_FPD|PCF_AFI|PCF_TR2|PCF_TR1 /* Clear normal flgs*/ - | PCF_USR | PCF_PUB); /* plus User & Public! */ - apr_pcfcheck(); /* Make right things happen */ - PC_JUMP(e); /* Jump to E! */ - break; - -#endif /* 1 Diagnostics emulation support */ - } - - /* Fix up PI vars to account for taking interrupt */ - cpu.pi.pilev_pip |= lev; /* PI now in progress on this level */ -#if KLH10_DEBUG - if (cpu.mr_debug) - fe_endpcfdbg(stderr); -#endif -} -#endif /* KLH10_CPU_KL */ - -/* Local UUO (LUUO) handling. -** On KS10, just use loc 40 & 41 from whichever space we're in. -** I wonder what happens on a real machine if the instr at 41 screws up? -** This code will already have clobbered loc 40 by then. -** On extended machine, if zero-section just use 40 & 41 as usual. -** If non-Z section, use 4-wd block pointed to by UPT+420 (or EPT+420 -** if exec mode). -** PRM 2-124 appears to be wrong when it asserts that an exec-mode LUUO -** is treated as a MUUO; this is contradicted by Uhler and V7 T20. -** Rather, the behavior is just like user-mode LUUOs except the block -** is pointed to by the EPT instead of UPT. -** Note code in i_xct that duplicates the LUUO code, in order to avoid -** the risk of C stack overflow if the non-extended case encounters -** another LUUO in location 41! -*/ -insdef(i_luuo) -{ - register w10_t w; - register vaddr_t va; - -#if KLH10_EXTADR - if (PC_ISEXT) { - /* Get dispatch vector from physical address of UPT or EPT */ - w = vm_pget(vm_physmap(cpu.mr_usrmode - ? (cpu.mr_ubraddr + UPT_LUU) - : (cpu.mr_ebraddr + EPT_LUU))); - - va_gfrword(va, w); /* Convert word to global vaddr_t */ - - /* Don't need to mung flags since not changing any modes */ - LRHSET(w, cpu.mr_pcflags, ((h10_t)op << 9) | (ac << 5)); - vm_write(va, w); /* Store first loc (flags, opcode) */ - va_ginc(va); - PC_1TOWORD(w); /* Put full PC+1 into word */ - vm_write(va, w); /* Store 2nd loc (PC+1) */ - va_ginc(va); - va_toword_acref(e, w); /* Store E in word, canonicalizing */ - /* for AC ref just like XMOVEI, XHLLI */ - vm_write(va, w); /* Store 3rd loc (E) */ - va_ginc(va); - w = vm_read(va); /* Fetch new PC from 4th loc */ - va_lfrword(va, w); /* Make local vaddr_t from it */ - PC_JUMP(va); - return PCINC_0; - } -#endif /* KLH10_EXTADR */ - - /* Running non-extended, do normal stuff. - ** Note: later could optimize access to 041 knowing it's within page, - ** by using a vmptr_t and incrementing that. - ** If this code is changed, see also the LUUO code in i_xct(). - */ - LRHSET(w, ((h10_t)op<<9)|(ac<<5), /* Put instr together */ - va_insect(e)); - va_lmake(va, 0, 040); /* Get vaddr_t for loc 40 */ - vm_write(va, w); /* Store the word */ - va_linc(va); - return i_xct(I_XCT, 0, va); /* Execute instr at 41 */ -} - - -/* Monitor UUO (MUUO) handling. -** This is also called for any instruction that is illegal -** in user mode. -** -** KLX behavior: -** PCS is saved in the flag word ONLY if old mode was exec. -** PCS is always saved in the saved process context word (UBR). -** The new flags are all cleared except that PCP and PCU are set -** to reflect the old Public and User mode flags. -** Since User is cleared, new mode is always exec. -** New PCS is always set from section # of old PC. -** New PC is masked to either 30 bits (sez PRM) or 23 (sez ucode). -** -** KS behavior: -** It appears that the KS10 restores flags from the PC word vector -** even in T20 mode, just like T10 and single-section KL. -** USER is always cleared, and PCU set to previous value of USER. -*/ -insdef(i_muuo) -{ - register w10_t w; - -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - fprintf(stderr,"MUUO %o => ", op); - } -#endif - - /* First set up return PC from MUUO. - ** The PC needs to be bumped by one before being saved, so return - ** will be to the next instruction. - ** - ** If the MUUO is being executed as a trap instruction (as indicated - ** by cpu.mr_intrap) then the trap flags are already clear; upon - ** return, cpu.mr_intrap will be automatically cleared as well. - ** - ** It used to be the case that KLH10 trap instruction execution (trap_xct) - ** didn't touch the PC, thus the MUUO code here had to avoid incrementing - ** the PC for the trap-instruction case. However, the trap code now - ** does a PC decrement so as to fake out all instructions (including - ** MUUO), so no special casing is needed for MUUO's PC increment. - */ -#if 1 - PC_ADD(1); /* Bump PC, so saved PC is a return to after MUUO */ -#else /* Old regime */ - if (!cpu.mr_intrap) /* Unless trapping, bump PC */ - PC_ADD(1); /* so saved PC is return to after MUUO */ -#endif - -#if KLH10_EXTADR - - LRHSET(w, cpu.mr_pcflags, ((h10_t)op<<9)|(ac<<5)); /* Build op wd */ - if (!cpu.mr_usrmode) /* If in exec mode, */ - op10m_iori(w, pag_pcsget()); /* add PCS into op word */ - vm_pset(vm_physmap(cpu.mr_ubraddr + UPT_UUO), w); /* Store op */ - PC_TOWORD(w); - vm_pset(vm_physmap(cpu.mr_ubraddr + UPT_UPC), w); /* Store OPC */ - - /* Set up and store MUUO E. This algorithm is the same one - ** used by XMOVEI. - */ - if (va_iscvtacref(e)) - LRHSET(w, 1, va_insect(e)); /* Global AC reference */ - else - LRHSET(w, va_sect(e), va_insect(e)); - vm_pset(vm_physmap(cpu.mr_ubraddr + UPT_UEA), w); /* Store MUUO E */ - - /* Set up and store current UBR. This includes current PCS - ** before we clobber it. - */ - op10m_tlz(cpu.mr_ubr, UBR_PCS); - op10m_tlo(cpu.mr_ubr, pag_pcsget()&UBR_PCS); - vm_pset(vm_physmap(cpu.mr_ubraddr + UPT_UCX), cpu.mr_ubr); /* Store UBR */ - - /* Now find where new PC will come from, since it depends on - ** the current state -- whether in user mode, and if trapping. - ** For the KL and KI, public mode is also tested. - */ - w = vm_pget(vm_physmap(cpu.mr_ubraddr + - (cpu.mr_usrmode - ? (PCFTEST(PCF_PUB) - ? (cpu.mr_intrap ? UPT_UPT : UPT_UPN) - : (cpu.mr_intrap ? UPT_UUT : UPT_UUN)) - : (PCFTEST(PCF_PUB) - ? (cpu.mr_intrap ? UPT_UST : UPT_USN) - : (cpu.mr_intrap ? UPT_UET : UPT_UEN)) - ))); - - /* Extended MUUO always sets new pager PCS */ - pag_pcsset(PC_SECT); /* Set it from old PC */ - - va_lfrword(e, w); /* Build local vaddr_t from word */ - PC_SET(e); /* Set new PC */ - - /* Now need to build new PC flags. All are cleared, except for - ** PCP and PCU which are set based on the old flags. - ** This appears to be the only place where PCP and PCU are ever set! - */ - cpu.mr_pcflags = (PCFTEST(PCF_PUB) ? PCF_PCP : 0) - | (PCFTEST(PCF_USR) ? PCF_PCU : 0); - -#else /* not KLH10_EXTADR */ - - /* Although MUUO trapping is not logically related to paging, - ** in practice the MUUO algorithm is a function of the pager being - ** used, so the different versions here are selected likewise. - ** Note that a KI10 would need something different from any of this. - */ -#if KLH10_CPU_KLX || (KLH10_CPU_KS && KLH10_PAG_KL) /* KLX or T20 KS */ - LRHSET(w, cpu.mr_pcflags, ((h10_t)op<<9)|(ac<<5)); /* Build op word */ - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_UUO), w); /* Store op word */ - LRHSET(w, 0, PC_INSECT); - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_UPC), w); /* Store old PC */ - LRHSET(w, 0, va_insect(e)); - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_UEA), w); /* Store MUUO E */ - -#else /* KL0, KS/T10, KS/ITS, KI */ - LRHSET(w, ((h10_t)op<<9)|(ac<<5), va_insect(e)); /* Build instr */ - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_UUO), w); /* Store instr */ - LRHSET(w, cpu.mr_pcflags, PC_INSECT); - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_UPC), w); /* Store old PC */ -#endif - -#if KLH10_CPU_KL || KLH10_CPU_KS - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_UCX), cpu.mr_ubr); /* Store UBR */ -#endif - - /* Now find where new PC will come from, since it depends on - ** the current state -- whether in user mode, and if trapping. - ** For the KL and KI, public mode is also tested. - */ -#if KLH10_CPU_KS - w = vm_pget(vm_physmap(cpu.mr_ubraddr + (cpu.mr_usrmode - ? (cpu.mr_intrap ? UPT_UUT : UPT_UUN) - : (cpu.mr_intrap ? UPT_UET : UPT_UEN)) )); - -#elif KLH10_CPU_KI || KLH10_CPU_KL - w = vm_pget(vm_physmap(cpu.mr_ubraddr + - (cpu.mr_usrmode - ? (PCFTEST(PCF_PUB) - ? (cpu.mr_intrap ? UPT_UPT : UPT_UPN) - : (cpu.mr_intrap ? UPT_UUT : UPT_UUN)) - : (PCFTEST(PCF_PUB) - ? (cpu.mr_intrap ? UPT_UST : UPT_USN) - : (cpu.mr_intrap ? UPT_UET : UPT_UEN)) - ))); -#else -# error "KA10 not implemented" -#endif - - PC_SET30(RHGET(w)); /* Set new PC */ - - /* Now need to build new PC flags. Extended KL claims to - ** always clear the flags since the vector has no room for them. - ** Systems/machines which use old-format 18-bit PC & flags - ** do set the flags, however. - ** Not clear if latter case always sets the PCU flag appropriately. - ** For now, assume not. - */ -#if KLH10_CPU_KLX - cpu.mr_pcflags = (cpu.mr_usrmode) ? PCF_PCU : 0; - -#elif KLH10_CPU_KL0 || KLH10_CPU_KS || KLH10_CPU_KI - cpu.mr_pcflags = LHGET(w) & PCF_MASK; -# if KLH10_CPU_KS || KLH10_CPU_KI /* KS ucode always forces PCU */ - if (cpu.mr_usrmode) /* (not sure about KI) */ - cpu.mr_pcflags |= PCF_PCU; - else cpu.mr_pcflags &= ~PCF_PCU; -# endif -#else -# error "KA10 not implemented" -#endif - -#endif /* !KLH10_EXTADR */ - - apr_pcfcheck(); /* Check flags for any changes */ - -#if KLH10_DEBUG - if (cpu.mr_debug) - fe_endpcfdbg(stderr); - if (cpu.mr_exsafe && (PC_INSECT == 0)) { /* Hack to catch T10 bug */ - fprintf(stderr, "[KLH10: MUUO going to 0]"); - if (cpu.mr_exsafe >= 2) - apr_halt(HALT_EXSAFE); - } -#endif - return PCINC_0; -} - - -#if KLH10_ITS_1PROC -/* APR_1PROC - perform one-proceed. Routine is here because it's similar -** to the MUUO code. -*/ -static void -apr_1proc(void) -{ - register w10_t w; - -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - fprintf(stderr,"1PROC "); - } -#endif - - /* Execute next instruction. This may actually be a trap instruction, - ** so check for that (duplicating code in apr_check()). - ** The 1-proceed flag needs to be turned off during execution so any - ** saved PC flags don't have it set, but it also needs to be turned - ** back on if the instruction gets a page fault or something. Hence - ** yet another crockish internal flag, cpu.mr_in1proc. - */ - cpu.mr_in1proc = TRUE; /* Say hacking 1-proceed */ - PCFCLEAR(PCF_1PR); /* Then safe to turn off flag */ - if (PCFTEST(PCF_TR1|PCF_TR2) && cpu.mr_paging) - trap_xct(); - else - PC_ADDXCT(i_xct(I_XCT, 0, PC_VADDR)); /* XCT next instr */ - cpu.mr_in1proc = FALSE; /* No longer interruptible */ - - /* Now take the 1-proceed trap! Similar to MUUO handling. */ -/* NOTE: May need to mung PC flags for PCP, PCU! */ - LRHSET(w, cpu.mr_pcflags, PC_INSECT); - vm_pset(vm_physmap(cpu.mr_ubraddr+UPT_1PO), w); /* Store old PC */ - w = vm_pget(vm_physmap(cpu.mr_ubraddr + UPT_1PN)); /* Get new flgs+PC */ - PC_SET30(RHGET(w)); /* Set new PC */ -/* NOTE: May need to mung PC flags for PCP, PCU! */ - cpu.mr_pcflags = LHGET(w) & PCF_MASK; /* and new flags */ - apr_pcfcheck(); /* Check flags for changes */ -#if KLH10_DEBUG - if (cpu.mr_debug) - fe_endpcfdbg(stderr); -#endif -} - -/* A1PR_UNDO - Recover if page-fault or interrupt out of one-proceed. -*/ -void -a1pr_undo(void) -{ - PCFSET(PCF_1PR); /* Turn flag back on */ - cpu.mr_in1proc = FALSE; -} -#endif /* KLH10_ITS_1PROC */ - -#if KLH10_CPU_KI || KLH10_CPU_KL /* AFI Handling */ - -/* APR_AFI - Execute next instruction under Addr-Failure-Inhibit flag. -** Very similar to one-proceed stuff. -** This attempts to emulate the behavior described in PRM 3-52, -** although that is a bit unclear about odd cases like traps. -*/ -static void -apr_afi(void) -{ -#if KLH10_DEBUG - if (cpu.mr_debug) { - fe_begpcfdbg(stderr); - fprintf(stderr,"AFI "); - } -#endif - - /* Execute next instruction. This may actually be a trap instruction, - ** so check for that (duplicating code in apr_check()). - ** The AFI flag needs to be turned off during execution so any - ** saved PC flags don't have it set, but it also needs to be turned - ** back on if the instruction gets a page fault or something. Hence - ** yet another crockish internal flag, cpu.mr_inafi. - */ - /* HOWEVER, one exception to this, unlike the one-proceed case: - ** If taking a trap, leave the flag ON, so it will be saved & cleared - ** if the trap instruction saves it, and otherwise cleared afterwards. - ** This will lose if the trap instruction sets AFI itself, but that - ** seems too improbable to worry about. - */ - cpu.mr_inafi = TRUE; /* Say hacking AFI */ - if (PCFTEST(PCF_TR1|PCF_TR2) && cpu.mr_paging) { /* If trapping, */ - trap_xct(); /* Do trap instr, leave flag on! */ - PCFCLEAR(PCF_AFI); /* Then safe to turn off flag */ - } else { - PCFCLEAR(PCF_AFI); /* Then safe to turn off flag */ - PC_ADDXCT(i_xct(I_XCT, 0, PC_VADDR)); /* XCT next instr */ - } - cpu.mr_inafi = FALSE; /* No longer interruptible */ - - /* Nothing else to do */ -#if KLH10_DEBUG - if (cpu.mr_debug) - fe_endpcfdbg(stderr); -#endif -} - -/* AFI_UNDO - Recover if page-fault or interrupt out of AFI. -*/ -void -afi_undo(void) -{ - PCFSET(PCF_AFI); /* Turn flag back on */ - cpu.mr_inafi = FALSE; -} -#endif /* KLH10_CPU_KI || KLH10_CPU_KL */ - - -insdef(i_illegal) -{ - if (!cpu.mr_usrmode && cpu.mr_exsafe) { - /* Barf just in case, but fall thru to let 10 monitor handle it */ - fprintf(stderr,"[KLH10: Illegal exec mode op, PC = %lo: %o %o,%lo]", - (long)PC_30, op, ac, (long)e); - if (cpu.mr_exsafe >= 2) - apr_halt(HALT_EXSAFE); - } - return i_muuo(op, ac, e); -} diff --git a/src/kn10def.h.old b/src/kn10def.h.old deleted file mode 100644 index 1ae0f98..0000000 --- a/src/kn10def.h.old +++ /dev/null @@ -1,971 +0,0 @@ -/* KLH10 CPU state and register definitions -*/ -/* $Id: kn10def.h,v 2.5 2002/05/21 10:02:31 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: kn10def.h,v $ - * Revision 2.5 2002/05/21 10:02:31 klh - * Fix SYNCH implementation of KL timebase - * - * Revision 2.4 2002/03/21 09:50:08 klh - * Mods for CMDRUN (concurrent mode) - * - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#ifndef KN10DEF_INCLUDED -#define KN10DEF_INCLUDED 1 - -#ifdef RCSID - RCSID(kn10def_h,"$Id: kn10def.h,v 2.5 2002/05/21 10:02:31 klh Exp $") -#endif - -#include "osdsup.h" /* Ensure any OS-dependent stuff is available */ - -#include "word10.h" /* Basic PDP-10 word definitions & facilities */ - -#ifndef EXTDEF -# define EXTDEF extern /* Default is to declare (not define) vars */ -#endif - -/* INSBRK - Sum of all interrupt flags. This is invoked whenever something -** (PI interrupt, trap, device I/O, etc) wants to break out of the normal -** instruction execution loop once the current instruction is done. -** See the INTF macros in osdsup.h. -*/ -#define INSBRK_INIT() INTF_INIT(cpu.mr_insbreak) -#define INSBRKSET() INTF_SET(cpu.mr_insbreak) -#define INSBRKTEST() INTF_TEST(cpu.mr_insbreak) -#define INSBRK_ACTBEG() INTF_ACTBEG(cpu.mr_insbreak) -#define INSBRK_ACTEND() INTF_ACTEND(cpu.mr_insbreak) - -/* Accumulator reference definitions */ - -#define AC_BITS 4 -#define AC_N (1<w[0] = ac_get(AC_17), (dp)->w[1] = ac_get(AC_0), 0 )) - -#define ac_dpset(dp,a) ( ac_issafedouble(a) \ - ? ((*ac_mapd(a) = *(dp)), 0) \ - : (ac_set(AC_17, (dp)->w[0]), ac_set(AC_0, (dp)->w[1]), 0) ) -#define ac_dget(a,d) (ac_issafedouble(a) \ - ? (((d) = *ac_mapd(a)),0) \ - : ((d).w[0] = ac_get(AC_17), (d).w[1] = ac_get(AC_0), 0 )) -#define ac_dset(a,d) (ac_issafedouble(a) \ - ? ((*ac_mapd(a) = (d)), 0) \ - : (ac_set(AC_17, (d).w[0]), ac_set(AC_0, (d).w[1]), 0) ) - -/* Memory definitions */ - -/* Get virtual addressing and virtual memory definitions */ - -#include "kn10pag.h" /* Include pager definitions */ - -/* Well, they used to take up a few pages here... */ - -/* Program Counter (PC) macros -** -** All references to and manipulations of PC should use a PC_ macro. -** This permits relatively straightforward experimentation with -** different PC implementations. -*/ -/* Likewise, the type used to hold a PC may be different from that -** for a virtual address, although for the time being they are still -** the same. -** NOTE: Later when questing for speed, attention needs to be given to the -** cases of mr_bkpt and klh10.c's setting of pcva_t variables. -** -** NOTE also: possibility of a vm_PCfetch() macro to fetch c(PC) -** specially (knows PC is local, no vaddr_t conversion, etc). -*/ -typedef vaddr_t pcva_t; /* Type of PC virt addr */ -typedef int pcinc_t; /* Type of all instruction routines */ -# define PCINC_0 0 /* Instr jumped */ -# define PCINC_1 1 /* Instr normal */ -# define PCINC_2 2 /* Instr skipped */ - -/* Macros to obtain a PC attribute. -*/ -#define PC_VADDR cpu.mr_PC /* Get PC as a vaddr_t */ -#define PC_30 va_30(cpu.mr_PC) /* Full 30-bit PC value */ -#define PC_SECT va_sect(cpu.mr_PC) /* PC section # (right-justified) */ -#define PC_SECTF va_sectf(cpu.mr_PC) /* PC section as a field value */ -#define PC_INSECT va_insect(cpu.mr_PC) /* PC in-section part */ -#define PC_ISEXT PC_SECTF /* TRUE if PC in NZ section */ -#define PC_PAGE va_xapage(cpu.mr_PC) /* Full XA page # of PC */ -#define PC_PAGOFF va_pagoff(cpu.mr_PC) -#define PC_AC va_ac(cpu.mr_PC) -#if KLH10_EXTADR -# define PC_ISACREF ((cpu.mr_PC & (VAF_SBAD|VAF_NNOTA))==0) -#else -# define PC_ISACREF ((cpu.mr_PC & VAF_NNOTA)==0) -#endif - -/* Macros to set or change the PC. -** It would be possible to optimize the SETs if all PC refs -** (vm_fetch in particular) always knew it was local-format. -*/ -#define PC_ADD(n) va_ladd(cpu.mr_PC,n) /* Add n to PC (always local) */ -#define PC_SET30(a) va_lmake30(cpu.mr_PC,a) /* Set PC from int w/o JPC */ -#define PC_SET(va) va_lmake30(cpu.mr_PC,va_30(va)) /* " from vaddr_t */ - -#if KLH10_JPC /* Take a jump. Special so can set JPC if desired */ -# define PC_JUMP(e) (cpu.mr_jpc = cpu.mr_PC, PC_SET(e)) -#else -# define PC_JUMP(e) PC_SET(e) -#endif - -/* Special macro to increment PC based on instruction execution. -** This must NOT be replaced by an expression such as -** (PC = (PC+(x)) & H10MASK) -** because C can't guarantee whether PC or (x) is evaluated first! -*/ -#if KLH10_EXTADR -# define PC_ADDXCT(x) { register pcinc_t i__ = (x); if (i__) PC_ADD(i__); } -#else -# define PC_ADDXCT(x) (cpu.mr_PC += (x)) /* For now; fix up later? */ -#endif - -/* Macros for putting PC into a word. -*/ -#define PC_TOWORD(w) LRHSET(w, PC_SECT, PC_INSECT) /* Put PC in wd */ -#define PC_XWDPC1(w,l) LRHSET(w,l,(cpu.mr_PC+1)&H10MASK) /* ,, */ -#define PC_1TOWORD(w) PC_XWDPC1(w, PC_SECT) /* ,, */ -#define PC_F1WORD(w) PC_XWDPC1(w, cpu.mr_pcflags) /* ,, */ - -/* Macro to put "PC-word" in word: PC+1 plus flags if sect 0 -*/ -#if KLH10_EXTADR -# define PC_1WORD(w) (PC_ISEXT ? PC_1TOWORD(w) : PC_F1WORD(w)) -#else -# define PC_1WORD(w) PC_F1WORD(w) -#endif - - -/* Processor Map change macros -** This macro should be invoked whenever something happens to -** change the address space mapping, either the page map or -** AC block selection. -*/ -#if KLH10_PCCACHE -# define PCCACHE_RESET() (cpu.mr_cachevp = NULL) -#else -# define PCCACHE_RESET() -#endif - -/* Processor PC Flag (PCF) macros */ - -#define PCFSET(f) (cpu.mr_pcflags |= (f)) -#define PCFTRAPSET(f) (cpu.mr_pcflags |= (f), INSBRKSET()) -#define PCFCLEAR(f) (cpu.mr_pcflags &= ~(f)) -#define PCFTEST(f) (cpu.mr_pcflags & (f)) - -/* Macro for OP10 facilities (from kn10ops) to use for flag setting */ -#define OP10_PCFSET(f) (cpu.mr_pcflags |= (f), \ - (((f)&(PCF_TR1|PCF_TR2)) ? INSBRKSET() : 0)) - - -/* PDP-10 processor flags -** These defs are the left half bit values of PDP-10 PC flags. -** Unless otherwise specified, all exist on all models. -*/ -#define PCF_ARO 0400000 /* Arithmetic Overflow (or Prev Ctxt Public) */ -#define PCF_CR0 0200000 /* Carry 0 - Carry out of bit 0 */ -#define PCF_CR1 0100000 /* Carry 1 - Carry out of bit 1 */ -#define PCF_FOV 040000 /* Floating Overflow */ -#define PCF_FPD 020000 /* First Part Done */ -#define PCF_USR 010000 /* User Mode */ -#define PCF_UIO 04000 /* User In-Out (or Prev Ctxt User) */ -#define PCF_PUB 02000 /* [KL/KI] Public Mode */ -#define PCF_AFI 01000 /* [KL/KI] Addr Failure Inhibit */ -#define PCF_TR2 0400 /* [KL/KI/KS] Trap 2 (PDL overflow) */ -#define PCF_TR1 0200 /* [KL/KI/KS] Trap 1 (Arith overflow) */ -#define PCF_FXU 0100 /* Floating Exponent Underflow */ -#define PCF_DIV 040 /* No Divide */ -#define PCF_MASK (H10MASK&~037) /* Can't mung low 5 bits, save for I(X) */ - -/* Duplicate flag meanings in exec mode */ -#define PCF_PCP PCF_ARO /* [KL/KI] Previous Context Public */ -#define PCF_PCU PCF_UIO /* [KL/KI/KS] Previous Context User */ -#if KLH10_ITS_1PROC -# define PCF_1PR PCF_AFI /* KS10 One-proceed flag - re-use AFI */ -#else -# define PCF_1PR 0 -#endif - -/* Instruction opcode macros and defs */ - -/* These cannot come earlier because they depend on some typedefs such -** as vaddr_t and pcinc_t. -*/ - -#include "opdefs.h" /* PDP-10 instruction opcodes and declarations */ - /* Includes IW_ facilities */ - - -/* Processor/microcode configuration */ - -/* APRID bit definitions. -** It appears that some monitors actually pay attention to these bits. -** While the KS and KL have superficially similar APRID fields, the -** meanings of the bits are completely different, so each needs its -** own specific definitions. -*/ - -/* KS notes: -** The PRM originally had no option bits defined; all of the options -** defined below were later additions. -*/ -#if KLH10_CPU_KS -# define AIF_UCOPT 0777000 /* LH: Microcode options field */ -# if KLH10_SYS_ITS -# define AIF_ITS 020000 /* ITS ucode [ITS KS10 only!] */ -# else -# define AIF_INHCST 0400000 /* "Inhibit CST update" supported */ -# define AIF_NOCST 0200000 /* No CST */ -# define AIF_SEX 0100000 /* "Exotic uCode" (ie non-standard) */ -# define AIF_UBLT 040000 /* BLTUB, BLTBU supported */ -# define AIF_KIPG 020000 /* KI paging (old T10) */ -# define AIF_KLPG 010000 /* KL paging (T20) */ -# endif -# define AIF_UCVER 0777 /* LH: ucode version # field */ -# define AIF_HWOPT 0700000 /* RH: Hardware options field */ -# define AIF_SNO 077777 /* RH: Processor serial # (15 bits!) */ - -/* Default the ucode version and APR serial number */ - -# ifndef KLH10_APRID_UCVER -# if KLH10_SYS_ITS -# define KLH10_APRID_UCVER 0262 /* Last ITS KS ucode version */ -# else -# define KLH10_APRID_UCVER 0130 /* Last DEC KS ucode version? */ -# endif -# endif -# ifndef KLH10_APRID_SERIALNO -# define KLH10_APRID_SERIALNO 4097 /* This is popular for some reason */ -# endif /* (maybe cuz an impossible SN for a KL) */ - -#endif /* KS */ - - -/* KL notes: -** Most of the KL bits are documented in the PRM, but -** AIF_KLB, AIF_PMV, and AIF_MCA were later additions. -** When ITS ran on a KL10A, it used the same bit as the KS10 (AIF_ITS) -** to indicate it was non-standard ucode. But there's no need to -** resurrect MC, so don't worry about it. -*/ -#if KLH10_CPU_KL -# define AIF_UCOPT 0777000 /* LH: Microcode options field */ -# define AIF_T20 0400000 /* 0 UCode supports T20 paging */ -# define AIF_EXA 0200000 /* 1 uCode supports Extended Addressing */ -# define AIF_SEX 0100000 /* 2 "Exotic uCode" (ie non-standard) */ -# define AIF_KLB 040000 /* 3 KL10B CPU (?) */ -# define AIF_PMV 020000 /* 4 PMOVE/PMOVEM */ -# define AIF_VER 0777 /* LH: ucode version # field */ - -# define AIF_HWOPT 0770000 /* RH: Hardware options field */ -# define AIF_50H 0400000 /* 18 50Hz power */ -# define AIF_CCA 0200000 /* 19 Cache */ -# define AIF_CHN 0100000 /* 20 "Channel" - has RH20s? */ -# define AIF_KLX 040000 /* 21 Extended KL10, else Single-section KL */ -# define AIF_OSC 020000 /* 22 "Master Oscillator" (golly) */ -# define AIF_MCA 010000 /* 23 MCA25 Keep Bit (per MCA25 doc p.A-10) */ -# define AIF_SNO 07777 /* RH: Hardware Serial Number (only 12 bits) */ - -/* Default the ucode version and APR serial number */ - -# ifndef KLH10_APRID_UCVER -# if KLH10_SYS_ITS -# define KLH10_APRID_UCVER 02-- /* Last ITS KL ucode version? */ -# else -# define KLH10_APRID_UCVER 0442 /* Last DEC KL ucode version? */ -# endif -# endif -# ifndef KLH10_APRID_SERIALNO -# define KLH10_APRID_SERIALNO 759 /* Well, what else to use? */ -# endif - -#endif /* KL */ - -/* APR "device" definitions -*/ - -struct aprregs { - int aprf_set; /* APR flag settings & chan # */ - int aprf_ena; /* APR flags enabled for interrupt */ - int aprf_lev; /* APR level bit to interrupt on */ -}; - -/* APR device flags. Note these all fit within 16 bits on the KS. -** The KL is a bit messier but can still be managed. -*/ -#if KLH10_CPU_KL -# define APRW_IORST 0200000 /* 19 W: Clear all external I/O devices */ -# define APRR_SWPBSY 0200000 /* 19 R: Sweep busy */ -#endif -#define APRW_ENA 0100000 /* 20 Enable ints on selected flags */ -#define APRW_DIS 040000 /* 21 Disable ints on selected flags */ -#define APRW_CLR 020000 /* 22 Clear flags */ -#define APRW_SET 010000 /* 23 Set flags */ -#define APRF_MASK 07760 /* Flag mask */ -#if KLH10_CPU_KL -# define APRF_SBUS 04000 /* 24 S-Bus Error */ -# define APRF_NXM 02000 /* 25 No Memory (locks ERA) */ -# define APRF_IOPF 01000 /* 26 IO Page Failure */ -# define APRF_MBPAR 0400 /* 27 MB Parity (locks ERA) */ -# define APRF_CDPAR 0200 /* 28 Cache Dir Parity */ -# define APRF_ADPAR 0100 /* 29 Address Parity (locks ERA) */ -# define APRF_PWR 040 /* 30 Nuclear Parity (ok, Power Failure) */ -# define APRF_SWPDON 020 /* 31 Sweep Done */ -#elif KLH10_CPU_KS -# define APRF_24 04000 /* 24 Unused? */ -# define APRF_INT80 02000 /* 25 Interrupt 8080 FE when set */ -# define APRF_PWR 01000 /* 26 Power failure */ -# define APRF_NXM 0400 /* 27 Non-ex memory */ -# define APRF_BMD 0200 /* 28 Bad Memory data */ -# define APRF_ECC 0100 /* 29 Corrected memory data */ -# define APRF_TIM 040 /* 30 Timer Interval done */ -# define APRF_FEINT 020 /* 31 Interrupt from 8080 FE */ -#endif -#define APRR_INTREQ 010 /* Something's requesting an int */ -#define APRF_CHN 07 /* Mask for APR channel */ - - -/* PI System definitions -** -** Terminology note: ITS still uses the word "channel" to mean the same thing -** as what DEC now calls "level". -*/ - -/* PI device flags, written by CONO PI, (KS: WRPI) -** Note all fit within 16 bits, except for high-order KL bits that -** aren't really part of the PI system. -*/ -#if KLH10_CPU_KL -# define PIF_WEPADR 0400000 /* Write Even Parity - Address */ -# define PIF_WEPDAT 0200000 /* Write Even Parity - Data */ -# define PIF_WEPDIR 0100000 /* Write Even Parity - Directory */ -#endif -#define PIW_LDRQ 020000 /* Drop IRQs on selected levels */ -#define PIW_CLR 010000 /* Clear PI system */ -#define PIW_LIRQ 04000 /* Initiate interrupt on selected levels */ -#define PIW_LON 02000 /* Turn on selected levels (enable) */ -#define PIW_LOFF 01000 /* Turn off " " (disable) */ -#define PIW_OFF 0400 /* Turn off PI system */ -#define PIW_ON 0200 /* Turn on " " */ -#define PILEVS 0177 /* Mask for all PI level select bits */ -#define PILEV1 0100 /* Bits used to select particular PI levels */ -#define PILEV2 040 -#define PILEV3 020 -#define PILEV4 010 -#define PILEV5 04 -#define PILEV6 02 -#define PILEV7 01 - -/* Flags read by CONI PI, (KS: RDPI) -** LH 0177 bits contain levels with program requests active (preq) -** RH 0177 bits contain levels turned on (enabled) -** RH 0177<<8 contain levels being held (PI In Progress) -*/ -#define PIR_PIPSHIFT 8 /* Shift arg to find PIP bits in RH */ -#define PIR_ON PIW_ON /* PI system on */ - -#if KLH10_CPU_KL - /* PI Function Word fields */ -#define PIFN_ASP 0700000 /* LH: Address space to use for fns 4 & 5 */ -#define PIFN_ASPEPT 0 /* Exec Process Table */ -#define PIFN_ASPEVA 0100000 /* Exec virtual address */ -#define PIFN_ASPPHY 0400000 /* Physical address */ - -#define PIFN_FN 070000 /* LH: Function code */ -#define PIFN_F0 0 /* Internal device or zero word */ -#define PIFN_FSTD 010000 /* Standard interrupt EPT+(40+2N) */ -#define PIFN_FVEC 020000 /* Vector interrupt (dev/adr) */ -#define PIFN_FINC 030000 /* Increment */ -#define PIFN_FEXA 040000 /* DTE20 Examine */ -#define PIFN_FDEP 050000 /* DTE20 Deposit */ -#define PIFN_FBYT 060000 /* DTE20 Byte Transfer */ -#define PIFN_FAOS 070000 /* IPA20-L (NIA20, CI) inc & return val */ - -#define PIFN_Q 04000 /* LH: Q bit */ -#define PIFN_DEV 03600 /* LH: Physical Device # */ -#define PIFN_LHADR 037 /* LH: High 5 bits of address */ - /* RH: Low 18 bits of address */ - -#endif /* KL */ - -struct piregs { - int pisys_on; /* PIR_ON bit set if PI system on, else 0 */ - int pilev_on; /* Levels active (enabled) - can take ints */ - int pilev_pip; /* Levels holding ints (PI in Progress) */ - - int pilev_preq; /* Levels to initiate prog reqs on */ - /* (these take effect even if pilev_on is off!) */ - - int pilev_dreq; /* Device PI requests outstanding */ - int pilev_aprreq; /* "Devices" in APR */ -#if KLH10_CPU_KL - int pilev_timreq; /* Interval timer PI request */ - int pilev_rhreq; /* RH20 device requests */ - int pilev_dtereq; /* DTE20 device requests */ - int pilev_diareq; /* DIA20 device requests */ - -#elif KLH10_CPU_KS - int pilev_ub1req; /* Devices on UBA #1 */ - int pilev_ub3req; /* Devices on UBA #3 */ -#endif -}; - -/* Defined & initialized in kn10cpu.c PI code; later make EXTDEFs */ -extern int pilev_bits[]; /* Bit masks indexed by PI level number */ -extern unsigned char pilev_nums[]; /* PI level nums indexed by PI bit mask */ - -/* Timing system definitions */ - -#if KLH10_CPU_KL - -/* Bits for CONO MTR, (those marked [I] are also read on CONI) -*/ -# define MTR_SUA 0400000 /* Set Up Accounts */ -# define MTR_AEPI 040000 /* [I] Acct: Executive PI Account */ -# define MTR_AENPI 020000 /* [I] Acct: Executive Non-PI Account */ -# define MTR_AON 010000 /* [I] Acct: Turn on */ -# define MTR_TBON 04000 /* [I] Time Base: turn on */ -# define MTR_TBOFF 02000 /* Time Base: turn off */ -# define MTR_TBCLR 01000 /* Time Base: clear */ -# define MTR_ICPIA 07 /* [I] Interval Counter: PI Assignment */ - -/* Bits for CONO TIM, -*/ -# define TIM_WCLR 0400000 /* Clear Interval Counter */ -# define TIM_ON 040000 /* Turn on Interval Counter */ -# define TIM_WFCLR 020000 /* Clear Interval Flags */ -# define TIM_RDONE 020000 /* Interval Done */ -# define TIM_ROVFL 010000 /* Interval Overflow */ -# define TIM_PERIOD 07777 /* Interval Period */ -/* Note: LH of CONI has current interval counter in its TIM_PERIOD field */ - -/* According to the PRM, all hardware counters are 16 bits except -** the interval counter (12 bits). -** -** All "doubleword" counts are 59-bit unsigned quantities with the -** hardware counter at the low end. -** The representation in a PDP-10 doubleword has the high 36 bits -** in the high-order word, and the low 23 in bits 1-23 of the low word, -** with bit 0 zero. -** The low 12 bits of the doubleword are reserved for -** extensibility to future faster machines (!). -*/ - -#endif /* KL */ - - -struct timeregs { - -#if KLH10_CPU_KS - w10_t tim_intreg; /* Interval Time reg set by WRINT */ - - uint32 tim_base[3]; /* 71-bit time base, native form */ - dw10_t wrbase; /* Time Base of last WRTIM */ - osrtm_t osbase; /* OS Time Base of last WRTIM */ - -#elif KLH10_CPU_KL - unsigned mtr_flgs; /* MTR condition flags */ - int mtr_on; /* TRUE if accounting on */ - int mtr_ifexe; /* TRUE to include exec non-PI */ - int mtr_ifexepi; /* TRUE to include exec PI */ - uint32 mtr_eact; /* Execution acct hardware cntr */ - uint32 mtr_mact; /* Mem ref acct hardware cntr */ - - int tim_on; /* TRUE if interval counter on */ - int tim_lev; /* PI level bit to interrupt on, if any */ - unsigned int tim_flgs; /* TIM condition flags and PIA */ - unsigned int tim_intper; /* Interval counter period */ - unsigned int tim_intcnt; /* Interval countdown */ - - int tim_tbon; /* Time base on/off flag */ -# if KLH10_RTIME_SYNCH - /* Time base - virt usec since last RDTIME */ - uint32 tim_ibased; /* usec due to done interval interrupt */ - uint32 tim_ibaser; /* usec due to rem ticks since last interval */ -# elif KLH10_RTIME_OSGET - osrtm_t tim_osbase; /* OS Time Base of last WRTIME reset */ -# endif - - uint32 tim_perf; /* Performance analysis hardware cntr */ -#endif -}; - -#define TIMEBASEFILE "APR.TIMEBASE" /* Change this name later */ - -/* Determine whether any clock countdown is needed at all */ -#define IFCLOCKED (KLH10_RTIME_SYNCH || KLH10_ITIME_SYNCH || KLH10_QTIME_SYNCH) -#define IFPOLLED (!KLH10_CTYIO_INT || !KLH10_IMPIO_INT) - -#include "kn10clk.h" /* New clock stuff */ - - -/* Stuff needed for ITS pager quantum counter, used by both kn10cpu and kn10pag. - See time code comments in KN10CPU. -*/ -#if KLH10_SYS_ITS -# if KLH10_QTIME_SYNCH -# define quant_unfreeze(q) ((q) + (CLK_USEC_UNTIL_ITICK()<<2)) -# define quant_freeze(q) ((q) - (CLK_USEC_UNTIL_ITICK()<<2)) -# elif KLH10_QTIME_OSREAL || KLH10_QTIME_OSVIRT - extern int32 quant_freeze(int32), quant_unfreeze(int32); -# endif -#endif - -/* UPT/EPT definitions -*/ - -/* UPT Offsets -** ITS: In non-time sharing and at clock level, UPT=EPT. -*/ - -#if KLH10_PAG_KI -# define UPT_PMU 0 /* 000-377: T10 User page map table (pages 0-777) */ -# define UPT_PME340 0400 /* 400-417: T10 Exec page map table (pages 340-377) */ -#endif - -#if KLH10_CPU_KI -# define UPT_PFT 0420 /* User page failure trap instr */ -#elif KLH10_CPU_KLX -# define UPT_LUU 0420 /* 30-bit addr of LUUO dispatch block */ -#endif -#define UPT_TR1 0421 /* User mode arith ovfl trap. */ -#define UPT_TR2 0422 /* User mode pdl ov trap. */ -#define UPT_TR3 0423 /* User mode trap 3 in non-one-proceed microcode. */ - - /* Although MUUO trapping is not logically related to paging, - ** in practice the MUUO algorithm is a function of the pager being - ** used, as well as the CPU, so the different versions here are - ** selected likewise. These categories correspond to those in - ** PRM 2-126 (fig 2.3) - */ -#if KLH10_CPU_KLX || (KLH10_CPU_KS && KLH10_PAG_KL) /* KLX or T20 KS */ -# define UPT_UUO 0424 /* MUUO PC flags, opcode, A, and PCS stored here. */ -# define UPT_UPC 0425 /* MUUO old PC */ -# define UPT_UEA 0426 /* MUUO Effective Address */ -# define UPT_UCX 0427 /* MUUO process context (from RDUBR) */ -#elif KLH10_CPU_KL0 && KLH10_PAG_KL /* T20 KL0 */ -# define UPT_UUO 0425 /* MUUO opcode, A, PC and Eff Addr */ -# define UPT_UPC 0426 /* MUUO old PC and flags */ -# define UPT_UCX 0427 /* MUUO process context (from RDUBR) */ -#elif (KLH10_CPU_KL0 || KLH10_CPU_KS) && (KLH10_PAG_KI || KLH10_PAG_ITS) -# define UPT_UUO 0424 /* MUUO opcode, A, PC and Eff Addr */ -# define UPT_UPC 0425 /* MUUO old PC and flags */ -# define UPT_UCX 0426 /* MUUO process context (from RDUBR) */ -#elif KLH10_CPU_KI -# define UPT_UUO 0424 /* MUUO opcode, A, PC and Eff Addr */ -# define UPT_UPC 0425 /* MUUO old PC and flags */ -#endif - - -#define UPT_UEN 0430 /* MUUO new PC - Exec mode, no trap */ -#define UPT_UET 0431 /* MUUO new PC - Exec mode, trap instr */ -#if KLH10_SYS_ITS && KLH10_CPU_KS -# define UPT_1PO 0432 /* One-proceed old PC stored here (if 1proc ucode) */ -# define UPT_1PN 0433 /* One-proceed new PC obtained from here (if " ) */ -#elif KLH10_CPU_KI || KLH10_CPU_KL -# define UPT_USN 0432 /* MUUO new PC - Supv mode, no trap */ -# define UPT_UST 0433 /* MUUO new PC - Supv mode, trap instr */ -#endif -#define UPT_UUN 0434 /* MUUO new PC - User mode, no trap */ -#define UPT_UUT 0435 /* MUUO new PC - User mode, trap instr */ -#if KLH10_CPU_KI || KLH10_CPU_KL -# define UPT_UPN 0436 /* MUUO new PC - Public mode, no trap */ -# define UPT_UPT 0437 /* MUUO new PC - Public mode, trap instr */ -#endif - - -#if KLH10_CPU_KS || KLH10_CPU_KL -# if KLH10_PAG_KI /* T10 paging */ -# define UPT_PFW 0500 /* Page Fail Word */ -# define UPT_PFO 0501 /* Page Fail Old PC+flags word */ -# define UPT_PFN 0502 /* Page Fail New PC+flags word */ -# elif KLH10_PAG_KL /* T20 paging */ -# define UPT_SC0 0540 /* T20 User Section 0 pointer */ -# if KLH10_CPU_KS || KLH10_CPU_KLX -# define UPT_PFW 0500 /* Page Fail Word */ -# define UPT_PFF 0501 /* Page Fail Flags */ -# define UPT_PFO 0502 /* Page Fail Old PC */ -# define UPT_PFN 0503 /* Page Fail New PC */ -# elif KLH10_CPU_KL0 -# define UPT_PFW 0501 /* Page Fail Word */ -# define UPT_PFO 0502 /* Page Fail Old PC+flags word */ -# define UPT_PFN 0503 /* Page Fail New PC+flags word */ -# endif -# endif -#endif /* KS+KL */ - -#if KLH10_CPU_KL -# define UPT_PXT 0504 /* User Process Execution Time (doubleword) */ -# define UPT_MRC 0506 /* User Memory Reference Count (doubleword) */ -#endif - - -/* EPT Locations */ - -#if KLH10_CPU_KL -# define EPT_CL0 0 /* Channel Logout Area 0 (of 8) (quadword) */ -#endif -#if KLH10_CPU_KI -# define EPT_UUO 040 /* Exec LUUO stored here */ -# define EPT_UUH 041 /* Exec LUUO handler instruction */ -#endif -#define EPT_PI0 040 /* PI0LOC+2*PICHN = Addr of instr pair for PICHN. */ - /* Note KL has a PI0! Otherwise, locs */ - /* actually used are 42-57 inclusive. */ -#if KLH10_CPU_KL -# define EPT_CB0 060 /* Channel Block Fill Word 0 (of 4) */ -#endif - -#if KLH10_CPU_KS -# define EPT_UIT 0100 /* EPT_UIT+N contains addr of the interrupt */ - /* table for unibus adapter N. Only */ - /* adapters 1 and 3 ever exist. */ -#endif /* KS */ - -#if KLH10_CPU_KL -# define EPT_DT0 0140 /* DTE20 Control Block 0 (of 4) (8 wds each) */ -#endif -#if KLH10_PAG_KI -# define EPT_PME400 0200 /* 200-377: T10 Exec page map table (pages 400-777) */ -#endif -#if KLH10_CPU_KLX -# define EPT_LUU 0420 /* Exec mode 30-bit LUUO block location */ -#elif KLH10_CPU_KI -# define EPT_PFT 0420 /* Exec page failure trap instr */ -#endif -#define EPT_TR1 0421 /* Exec mode arith ovfl trap. */ -#define EPT_TR2 0422 /* Exec mode pdl ov trap. */ -#define EPT_TR3 0423 /* Exec mode trap 3 (1 proceed?). */ - -#if KLH10_SYS_ITS -/* - In the ITS microcode the three words used to deliver a page fail are - determined from the current interrupt level. At level I, the page fail - word is stored in EPTPFW+<3*I>, the old PC is stored in EPTPFO+<3*I>, - and the new PC is obtained from EPTPFN+<3*I>. If no interrupts are in - progress we just use EPTPFW, EPTPFO and EPTPFN. -*/ -#define EPT_PFW 0440 /* Page fail word stored here. */ -#define EPT_PFO 0441 /* Page fail old PC stored here. */ -#define EPT_PFN 0442 /* Page fail new PC obtained from here. */ -#endif /* ITS */ - -#if KLH10_CPU_KL -/* The PRM doesn't mention this, but it appears that TOPS-20 (at least) uses -** EPT locations 444-457 inclusive as a special communication area with -** the Master DTE. See dvdte.h for more details. -*/ -#endif - -#if KLH10_CPU_KL -# define EPT_TBS 0510 /* Time Base (doubleword) */ -# define EPT_PRF 0512 /* Performance Analysis Counter (doubleword) */ -# define EPT_ICI 0514 /* Interval Counter Interrupt Instruction */ -#endif - -#if KLH10_PAG_KL -# define EPT_SC0 0540 /* T20 Exec Section 0 pointer */ -#endif -#if KLH10_PAG_KI -# define EPT_PME0 0600 /* 600-757: T10 Exec page map table (pages 0-337) */ - /* (note pages 340-377 are in UPT!) */ -#endif - -/* FE (console) stuff needed for interaction */ - -/* Halt codes returned to FE when KLH10 CPU stops. -*/ -enum haltcode { /* Must not be zero */ - HALT_PROG=1, /* Program halt (JRST 4,) */ - HALT_FECTY, /* FE Console interrupt */ - HALT_FECMD, /* FE Console command ready to execute */ - HALT_BKPT, /* Hit breakpoint */ - HALT_STEP, /* Single-Stepping */ - HALT_EXSAFE, /* Badness in exec mode */ - HALT_PANIC /* Panic - internal error, bad state */ -}; - -/* FE command mode */ -enum femode { /* runnable running ctyon Description */ - FEMODE_CMDCONF, /* 0 0 0 not inited, cmd i/o */ - FEMODE_CMDHALT, /* 1 0 0 halted, cmd i/o */ - FEMODE_CMDRUN, /* 1 1 0 running, cmd i/o */ - FEMODE_CTYRUN /* 1 1 1 running, CTY I/O */ -}; - -struct feregs { - enum femode fe_mode; /* FE input handling mode */ - int fe_cmdready; /* TRUE if FE cmd input buff ready to exeute */ - int fe_runenable; /* TRUE to run KN10 during cmd input */ - int fe_intchr; /* If non-zero, FE interrupt/cmd escape char */ - int fe_intcnt; /* # times intchr seen before handled */ - int fe_ctyon; /* TRUE if passing input to PDP-10 CTY */ - int fe_ctyinp; /* # chars CTY input waiting, if any */ - int fe_debug; /* TRUE to print debug info */ - int fe_ctydebug; /* TRUE to print CTY debugging info */ - -#if KLH10_CPU_KS - int fe_iowait; /* # usec clock ticks to delay I/O response */ -# if KLH10_CTYIO_ADDINT - int cty_lastint; /* # 1ms ticks after last output to give int */ - int cty_prevlastint; /* Previous value of above */ - struct clkent *cty_lastclk; /* Clock timer for last-output int */ -# endif -#endif /* KLH10_CPU_KS */ -}; - -#if KLH10_CPU_KS - -/* FE <-> KS10 Communications Area locations */ -#define FECOM_SWIT0 030 /* Simulated switch 0. Set by 8080 SH cmd. */ -#define FECOM_KALIV 031 /* Keep Alive & Status. */ -#define FECOM_CTYIN 032 /* CTY input. */ -#define FECOM_CTYOT 033 /* CTY output. */ -#define FECOM_KLKIN 034 /* KLINIK user input word (from 8080). */ -#define FECOM_KLKOT 035 /* KLINIK user output word (to 8080). */ -#define FECOM_RHBAS 036 /* BOOT RH11 base address. */ -#define FECOM_QNUM 037 /* BOOT Unit Number. */ -#define FECOM_BOOTP 040 /* Magtape Boot Format and Slave Number. */ - -#endif /* KS */ - -#if KLH10_CPU_KL /* Low core locs checked by T20 scheduler */ -# define FECOM_SWIT0 030 /* SHLTW - Halt request if NZ, see SCHED.MAC */ - /* 020 */ /* SCTLW - Request word, various bits */ -#endif - -/* Global Machine state variables -** This is a structure so references to the contents can all be made -** as offsets from a base address (which may be in a register). On -** some architectures such as the SPARC this allows a 1-instruction -** reference as opposed to the usual 3-instruction sequence for a -** random global reference. -** On other architectures it doesn't matter but doesn't hurt either. -*/ - -struct machstate { - /* Current ACs; at start of struct to make indexing faster. - ** This block is swapped with cpu.acblks[n] - ** whenever the current AC block changes. - */ - acblk_t acs; - int mr_acbcur; /* AC block # of current acs above */ - - /* General internal machine registers */ - h10_t mr_pcflags; /* Current PC flags */ - pcva_t mr_PC; /* Current virtual PC */ -#if KLH10_PCCACHE - vmptr_t mr_cachevp; /* Current cached PC map pointer */ -#endif -#if KLH10_JPC - pcva_t mr_jpc; /* Virtual PC of last jump instruction */ - pcva_t mr_ujpc; /* Last JPC when user mode left */ - pcva_t mr_ejpc; /* Last JPC when exec mode left */ -#endif -#if KLH10_CPU_KS - w10_t mr_hsb; /* Halt Status Block base address */ -#elif KLH10_CPU_KI || KLH10_CPU_KL - w10_t mr_adrbrk; /* Address Break register */ -#endif - w10_t mr_aprid; /* Processor ID */ - w10_t mr_ebr; /* Executive Base Register */ - w10_t mr_ubr; /* User Base Register */ - paddr_t mr_ebraddr, mr_ubraddr; /* Word addresses for above */ - int mr_paging; /* TRUE if paging & traps enabled */ - int mr_usrmode; /* TRUE if in USER mode (else EXEC mode) */ - int mr_inpxct; /* TRUE if executing PXCT operand */ -#if KLH10_CPU_KLX - pcva_t mr_pxctpc; /* Saved PC if PXCT bit 12 set */ -#endif - h10_t mr_intrap; /* NZ (Trap flags set) if XCTing trap instr */ -#if KLH10_ITS_1PROC - int mr_in1proc; /* TRUE if executing one-proceed instr */ -#elif KLH10_CPU_KI || KLH10_CPU_KL - int mr_inafi; /* TRUE if executing AFI instruction */ -#endif - int mr_injrstf; /* TRUE if executing JRSTF/JEN */ - int mr_inpi; /* TRUE if executing PI instruction */ - - osintf_t mr_insbreak; /* See INSBRKSET, INSBRKTEST */ - osintf_t intf_fecty; /* For FE CTY interrupts */ -#if KLH10_EVHS_INT - osintf_t intf_evsig; /* For event-reg signals */ -#endif - osintf_t intf_ctyio; /* For CTY I/O */ - osintf_t intf_clk; /* Clock interval interrupt */ - - vmptr_t physmem; /* Ptr to physical memory area */ - struct acregs acblk; /* AC block mappings */ - struct vmregs vmap; /* Pager context mappings */ - struct pagregs pag; /* Paging registers */ - struct aprregs aprf; /* APR device stuff */ - struct piregs pi; /* PI system stuff */ - struct timeregs tim; /* Timer and clock stuff */ - struct clkregs clk; /* Internal Clock stuff */ - w10_t mr_dsw; /* Console Data Switches */ - - /* Debugging stuff */ - int mr_debug; /* TRUE to print general CPU debug info */ - int mr_dotrace; /* TRUE if doing execution trace */ - int mr_1step; /* TRUE to stop after next instr */ - int mr_exsafe; /* NZ does exec-mode safety checks; 2 = halt */ - pcva_t mr_bkpt; /* Non-zero to stop when mr_PC == mr_bkpt */ - pcva_t mr_haltpc; /* PC of a halt instruction */ - - /* Miscellaneous cruft */ - int mr_runnable; /* TRUE if CPU runnable (ie init complete) */ - int mr_running; /* TRUE if CPU running (not halted) */ - int mm_shared; /* TRUE if using shared phys memory */ - int mm_locked; /* TRUE if want memory locked */ - osmm_t mm_physegid; /* Phys memory shared segment ID (can be 0) */ - struct feregs fe; /* FE stuff */ -#if KLH10_CPU_KS - int io_ctydelay; /* Ugh. To emulate I/O device delays. */ -#endif - - /* Bulk storage, at end so it's less annoying when debugging. */ - - w10_t acblks[ACBLKS_N][16]; /* Actual AC blocks! 16 wds each */ - opfp_t opdisp[I_N]; /* I_xxx Routine dispatch table */ - pment_t pr_umap[PAG_MAXVIRTPGS]; /* Internal user mode map table */ - pment_t pr_emap[PAG_MAXVIRTPGS]; /* " exec " " " */ -}; - -EXTDEF struct machstate cpu; - - -/* Processor function declarations - from kn10cpu.c */ - -extern void apr_picheck(void); /* Check for pending PI */ -extern void apr_pcfcheck(void); /* Check PC flags for side effects */ -extern void apr_int(void); /* Invoke interrupt system */ -extern void apr_halt(enum haltcode); /* Halt processor */ -extern void pi_dismiss(void); /* Dismiss current interrupt */ -#if KLH10_CPU_KL -extern void mtr_update(void); /* Update accounts */ -#endif - -/* Finally, declare panic routine to call when all else fails. */ - -extern void panic(char *, ...); - -#endif /* ifndef KN10DEF_INCLUDED */ diff --git a/src/kn10pag.c.old b/src/kn10pag.c.old deleted file mode 100644 index c82c277..0000000 --- a/src/kn10pag.c.old +++ /dev/null @@ -1,1965 +0,0 @@ -/* KN10PAG.C - Main Processor: Pager -*/ -/* $Id: kn10pag.c,v 2.4 2002/04/26 05:22:21 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: kn10pag.c,v $ - * Revision 2.4 2002/04/26 05:22:21 klh - * Add missing include of - * - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#include -#include - -#include "klh10.h" -#include "osdsup.h" -#include "kn10def.h" -#include "kn10ops.h" - -#ifdef RCSID - RCSID(kn10pag_c,"$Id: kn10pag.c,v 2.4 2002/04/26 05:22:21 klh Exp $") -#endif - -/* Exported functions - see kn10pag.h */ - -/* Imported functions */ -extern void pishow(FILE *f); -extern void pcfshow(FILE *f, h10_t flags); -extern void insprint(FILE *, int); - -extern void pxct_undo(void); /* KN10CPU stuff needed for page fail trap */ -extern void trap_undo(void); -#if KLH10_ITS_1PROC -extern void a1pr_undo(void); -#elif KLH10_CPU_KI || KLH10_CPU_KL -extern void afi_undo(void); -#endif - -/* Local Pre-declarations */ -static void acblk_set(unsigned, unsigned); -static void pag_enable(int); -static void pag_clear(void); -static void pag_mapclr(pment_t *); -static void pag_segclr(pment_t *); -static void pag_nxmfail(paddr_t, pment_t, char *); - -/* Pager code */ -/* - As implemented here, the pager maintains its own internal map -tables which are used for all virtual memory references (non-virtual -ones go directly to physical memory). - - There are two map tables, one for EXEC mode mapping and the other -for USER mode. There is one map entry for each possible page in the virtual -address space. - - For the ITS pager this is 256 entries, further separated -into "low" and "high" halves of 128 entries each, so that each half can -be changed independently of the other. - - When a page map is first set up, just the location of the -entries in the PDP-10 memory is noted, and the internal map entries are -cleared. Any reference which finds an invalid (clear) entry will first -trap to the pager, which attempts to load the corresponding entry from -the PDP-10 memory. This is called a "page refill". If found and -valid, the entry is set internally and the reference allowed to -proceed. If still invalid, a page fault trap happens. - - Whenever the documentation talks about an instruction -"resetting the page table", for the emulator this means that the -relevant internal map entries are cleared. (There is no cache, thus -"clearing the cache" is a no-op.) - - Currently there is actually a third internal page map, which -merely mirrors physical memory and is used as the mapping table before -paging is turned on. This table never changes. - -*/ - -/* PAG_INIT - Initialize the paging system. -*/ -void -pag_init(void) -{ - register int i; - - /* Initialize externally visible registers */ -#if KLH10_CPU_KS - LRHSET(cpu.mr_ebr, 0, - (KLH10_PAG_KL ? EBR_T20 : 0)); /* Set flag if using T20 (KL) paging */ -#else - LRHSET(cpu.mr_ebr, 0, 0); /* KL diags expect 0?!? */ -#endif - -#if KLH10_CPU_KL - LRHSET(cpu.mr_ubr, UBR_SETACB | UBR_SETPCS | UBR_SET, 0); -#elif KLH10_CPU_KS - LRHSET(cpu.mr_ubr, UBR_SETACB | UBR_SET, 0); /* Bits 0&2 always set */ -#endif - -#if KLH10_JPC - cpu.mr_ujpc = cpu.mr_ejpc = cpu.mr_jpc = 0; -#endif -#if KLH10_PAG_ITS - cpu.pag.pr_dbr1 = cpu.pag.pr_dbr2 = /* DBR regs */ - cpu.pag.pr_dbr3 = cpu.pag.pr_dbr4 = 0; - cpu.pag.pr_quant = /* Misc stuff */ - cpu.pag.pr_ujpc = cpu.pag.pr_ejpc = 0; -#elif KLH10_PAG_KL -# if KLH10_CPU_KS - cpu.pag.pr_spb = cpu.pag.pr_csb = 0; /* Base addresses */ -# elif KLH10_CPU_KL - op10m_setz(PAG_PR_SPB); - op10m_setz(PAG_PR_CSB); -# endif - op10m_setz(PAG_PR_CSTMWD); /* Word values */ - op10m_setz(PAG_PR_PURWD); - - cpu.pag.pr_physnxm = (paddr_t)PAG_MAXPHYSPGS << PAG_BITS; -#endif /* KLH10_PAG_KL */ - -#if KLH10_CPU_KL - cpu.pag.pr_pcs = cpu.pag.pr_pcsf = 0; - cpu.pag.pr_era = 0; -#endif - - /* Do AC block initialization. */ - cpu.mr_acbcur = 0; /* Specify current AC block */ - acblk_set(0, 0); /* Set up cur & prev blocks */ - - /* Set up physical memory "map" */ - for (i = 0; i < PAG_MAXVIRTPGS; ++i) - pr_pmap[i] = (VMF_READ|VMF_WRITE) | i; - pag_clear(); /* Clear Exec and User maps */ - - pag_enable(0); /* Ensure paging is off internally */ -} - -/* ACBLK_SET - Subroutine to set current and previous AC blocks -** Always keeps the current block ACs in cpu.acs for faster reference. -*/ -static void -acblk_set(register unsigned int new, - register unsigned int old) -{ - if (new >= ACBLKS_N || old >= ACBLKS_N) - panic("acblk_set: ac blk # out of range: %d or %d", new, old); - if (cpu.mr_acbcur != new) { - /* Put current ACs back in shadow block, then load from new block */ - *(acblk_t *)cpu.acblks[cpu.mr_acbcur] = cpu.acs; - cpu.acs = *(acblk_t *)cpu.acblks[new]; /* Do structure copy! */ - cpu.mr_acbcur = new; /* Remember new AC block for next call */ - } - acmap_set(&cpu.acs.ac[0], /* Set up new mappings */ - ((old == new) ? &cpu.acs.ac[0] : cpu.acblks[old])); -} - -/* PAG_ENABLE - Enable or disable paging. -** Callers must also clear the cache, page map, and KLH10 PC cache if any, -** by invoking pag_clear() before or after this function. -*/ -static void -pag_enable(int onf) -{ - - /* Originally it wasn't clear whether the EPT, UPT, and AC block selection - ** were in effect even when paging is off. - ** However, this appears to be the case for the KL, - ** and reportedly the KS as well. - */ -#if 0 /* KLH10_CPU_KS */ - if (onf) { /* Turning paging/traps on or off? */ -#else - if (1) { /* ALWAYS set EPT/UPT and AC block selections */ -#endif - /* Set word addr of EPT and UPT so we start using them */ - cpu.mr_ebraddr = (paddr_t)(RHGET(cpu.mr_ebr) & EBR_BASEPAG) << 9; - cpu.mr_ubraddr = -#if KLH10_PAG_ITS - ((paddr_t)(LHGET(cpu.mr_ubr) & UBR_BASELH) << 18) - | RHGET(cpu.mr_ubr); -#else /* DEC */ - pag_pgtopa(RHGET(cpu.mr_ubr) & UBR_BASEPAG); -#endif - /* Set AC block selections */ - acblk_set((LHGET(cpu.mr_ubr) & UBR_ACBCUR) >> 9, /* Set cur */ - (LHGET(cpu.mr_ubr) & UBR_ACBPREV) >> 6); /* and prev */ - } - -#if 0 /* KLH10_CPU_KS */ - if (!onf) { /* Turning paging/traps off? */ - /* Turn off everything that we use internally, without munging - ** the current settings of the externally visible registers. - */ - cpu.mr_ubraddr = cpu.mr_ebraddr = 0; /* No EPT or UPT */ - acblk_set(0, 0); /* Point to AC block 0 */ - } -#endif /* KS */ - - if (onf) { /* Turning paging/traps on or off? */ - if (cpu.mr_paging) /* If already paging, can stop now */ - return; - -#if KLH10_PAG_ITS - /* The Exec DBRs had better already be set! */ - if (!cpu.pag.pr_dbr3 || !cpu.pag.pr_dbr4) - panic("pag_enable: Exec DBRs not set!"); -#endif - - /* Now set up mapping and context properly */ - - /* Turn on paging! */ - cpu.vmap.user = cpu.pr_umap; /* Make each mode use its own map */ - cpu.vmap.exec = cpu.pr_emap; - vmap_set(cpu.pr_emap, /* Set current & previous VM map */ - (PCFTEST(PCF_UIO) ? cpu.pr_umap : cpu.pr_emap)); - - cpu.mr_paging = TRUE; - - } else { - /* Turn off paging! Do this even if think we're off, for init. */ - cpu.vmap.user = pr_pmap; /* Make both modes use phys map */ - cpu.vmap.exec = pr_pmap; - vmap_set(pr_pmap, pr_pmap); /* Point to phys map */ - - cpu.mr_paging = FALSE; - } -} - -/* PAG_CLEAR - Invalidate all pager maps by clearing all internal entries. -** Perhaps optimize by keeping count of refills? If count zero, -** don't need to re-clear the table. -*/ -static void -pag_clear(void) -{ - PCCACHE_RESET(); /* Invalidate cached PC info */ - pag_mapclr(cpu.pr_umap); - pag_mapclr(cpu.pr_emap); -} - -static void /* Ditto but one map only */ -pag_mapclr(register pment_t *p) -{ - memset((char *)p, 0, PAG_MAXVIRTPGS*sizeof(*p)); -} - -/* Not actually used for anything */ -static void /* Ditto but only half a map */ -pag_segclr(register pment_t *p) -{ - memset((char *)p, 0, (PAG_MAXVIRTPGS/2)*sizeof(*p)); -} - -/* Common IO instructions that manipulate the paging system */ - -/* IO_RDEBR (70124 = CONI PAG,) - Read Executive Base Register -*/ -ioinsdef(io_rdebr) -{ - vm_write(e, cpu.mr_ebr); - return PCINC_1; -} - -#if KLH10_CPU_KL -/* CONSZ PAG, (70130) - KL: Skips if all EBR bits in nonzero E are zero. -** Not explicitly mentioned, but evidently works. -** UUO on KS10. -*/ -ioinsdef(io_sz_pag) -{ - return (va_insect(e) && !(va_insect(e) & RHGET(cpu.mr_ebr))) - ? PCINC_2 : PCINC_1; -} - -/* CONSO PAG, (70134) - KL: Skips if any EBR bits in E are set -** Not explicitly mentioned, but evidently works. -** UUO on KS10. -*/ -ioinsdef(io_so_pag) -{ - return (va_insect(e) & RHGET(cpu.mr_ebr)) - ? PCINC_2 : PCINC_1; -} -#endif /* KL */ - -/* IO_WREBR (70120 = CONO PAG,) - Write Executive Base Register -** Set pointer to EPT, enable paging. -** On ITS, bit EBR_T20 only affects the way MUUOs are trapped. -** Resets (invalidates) cache and page table. -** Note that pag_enable actually effects the EBR alterations. -*/ -ioinsdef(io_wrebr) -{ - register h10_t ebits = va_insect(e); - - if (ebits & EBR_ENABLE) { -#if KLH10_PAG_ITS || KLH10_PAG_KI - if (ebits & EBR_T20) - panic("io_wrebr: Cannot support TOPS-20 (KL) paging"); -#elif KLH10_PAG_KL - /* Only barf on this if KS. KL is now always KL-paging, but - ** apparently ignores state of this bit?! At least diags seem - ** to expect this behavior. - */ -# if KLH10_CPU_KS - if (!(ebits & EBR_T20)) - panic("io_wrebr: Cannot support TOPS-10 (KI) paging"); -# endif -#endif - } else { /* Preserve former state of bit */ - if (RHGET(cpu.mr_ebr) & EBR_T20) - ebits |= EBR_T20; - else ebits &= ~EBR_T20; - } - - /* Always set EBR, but only change paging type bit if enabled */ - RHSET(cpu.mr_ebr, - (ebits & (EBR_CCALK|EBR_CCALD|EBR_T20|EBR_ENABLE|EBR_BASEPAG))); - pag_enable((ebits & EBR_ENABLE) /* Turn paging/traps on/off */ - ? TRUE : FALSE); - pag_clear(); /* Clear page tables */ -#if KLH10_DEBUG - if (cpu.mr_debug) { - putc('[', stderr); - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); - fprintf(stderr,"%lo: EBR<=%lo]\r\n", - (long) PC_30, (long) cpu.mr_ebraddr); - } -#endif - - return PCINC_1; -} - -/* IO_RDUBR (70104 = DATAI PAG,) - Read User Base Register -*/ -ioinsdef(io_rdubr) -{ -#if KLH10_CPU_KL /* Stuff current PCS into UBR word. */ - op10m_tlz(cpu.mr_ubr, UBR_PCS); - op10m_tlo(cpu.mr_ubr, pag_pcsget()&UBR_PCS); -#endif - vm_write(e, cpu.mr_ubr); - return PCINC_1; -} - -/* IO_WRUBR (70114 = DATAO PAG,) - Write User Base Register -** Resets (invalidates) cache and page table if UPT changes. -** The two bits UBR_SETACB and UBR_SET have already been set in cpu.mr_ubr by -** the initialization code and are never changed thereafter. -*/ -ioinsdef(io_wrubr) -{ - register w10_t w; - w = vm_read(e); /* Get UBR word */ - -#if KLH10_DEBUG - if (cpu.mr_debug) { - putc('[', stderr); - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); - fprintf(stderr,"%lo: UBR<=", (long) PC_30); - } -#endif - - /* Select AC blocks? */ - if (LHGET(w) & UBR_SETACB) { - - /* It appears that WRUBR always immediately changes - ** the AC blocks even if not paging, for both KL and KS. - */ - acblk_set((LHGET(w) & UBR_ACBCUR) >> 9, /* Set cur */ - (LHGET(w) & UBR_ACBPREV) >> 6); /* and prev */ - PCCACHE_RESET(); /* Invalidate cached PC info */ - - /* Put new selections into UBR */ - LHSET(cpu.mr_ubr, (LHGET(cpu.mr_ubr) & ~(UBR_ACBCUR|UBR_ACBPREV)) - | (LHGET(w) & (UBR_ACBCUR|UBR_ACBPREV))); -#if KLH10_DEBUG - if (cpu.mr_debug) { - fprintf(stderr,"(%o,%o)", (int) (LHGET(w)&UBR_ACBCUR)>>9, - (int) (LHGET(w)&UBR_ACBPREV)>>6); - } -#endif - } - -#if KLH10_CPU_KL - if (LHGET(w) & UBR_SETPCS) { - /* Doesn't matter whether paging on or not, just set pager PCS */ - pag_pcsset(LHGET(w) & UBR_PCS); -#if KLH10_DEBUG - if (cpu.mr_debug) { - fprintf(stderr,"(PCS:%o)", (int)(LHGET(w) & UBR_PCS)); - } -#endif - } -#endif /* KL */ - - /* Select new UPT? */ - if (LHGET(w) & UBR_SET) { - -#if KLH10_CPU_KL - /* Unless explicitly suppressed, setting a new user base address - ** always updates the exec/mem accounts of the previous user. - ** This must be done before mr_ubraddr is clobbered! - */ - if (!(RHGET(w) & UBR_DNUA)) /* Unless bit suppresses it, */ - mtr_update(); /* update previous user accts */ -#endif - - RHSET(cpu.mr_ubr, RHGET(w) & UBR_RHMASK); /* Set UBR RH */ - -#if KLH10_PAG_ITS - LHSET(cpu.mr_ubr, /* ITS - also set UBR LH */ - (LHGET(cpu.mr_ubr) & ~UBR_BASELH) | (LHGET(w) & UBR_BASELH)); - cpu.mr_ubraddr = ((paddr_t)(LHGET(w) & UBR_BASELH) << 18) | RHGET(w); -#else /* DEC */ - cpu.mr_ubraddr = pag_pgtopa(RHGET(w) & UBR_BASEPAG); -#endif - - /* Also must reset cache and page table. - ** KLH10 also resets its PC cache if any. - */ - pag_clear(); /* Or? pag_mapclr(cpu.pr_umap); */ - } -#if KLH10_DEBUG - if (cpu.mr_debug) { - if (LHGET(w) & UBR_SET) - fprintf(stderr,"%lo]\r\n", (long) cpu.mr_ubraddr); - else fprintf(stderr, "--]\r\n"); - } -#endif - return PCINC_1; -} - -/* IO_CLRPT (70110 = BLKO PAG,) - Clear Page Table Entry (reffed by E) -** Per DEC documentation (KSREF.MEM 12/78 p.2-9) this clears the -** page entry in BOTH user and exec maps. -** ITS: Unlike the ITS ucode which only invalidates the first half-page -** (since DEC pages are half the size of ITS pages), this really does -** clear the mapping for the entire ITS page. -** -** NOTE!!!! CLRPT must mask E to make sure the page number is within -** the supported hardware page map! It is entirely possible for E to have -** an absurd value, and this DOES HAPPEN on TOPS-20 due to a monitor bug. -** Specifically, two places in DSKALC.MAC that call MONCLR thinking the arg is -** a page # instead of an address, giving it AC1/ 224000,,2 => page 4,,0 !!! -** This problem is fixed by va_page() which only returns a supported -** virtual page number. -*/ -ioinsdef(io_clrpt) -{ - PCCACHE_RESET(); /* Invalidate cached PC info */ - cpu.pr_umap[va_page(e)] = 0; /* Zapo! */ - cpu.pr_emap[va_page(e)] = 0; - return PCINC_1; -} - -#if KLH10_SYS_ITS - -/* IO_CLRCSH (70100 = BLKI PAG,) - Clear Cache -*/ -ioinsdef(io_clrcsh) -{ -#if 0 /* This isn't actually necessary as the non-existent memory cache - ** has nothing to do with the KLH10 PC cache. FYI only. - */ - PCCACHE_RESET(); /* Invalidate cached PC info */ -#endif - return PCINC_1; -} -#endif /* ITS */ - -/* Auxiliaries */ - -/* PFBEG, PFEND - Start and end debug info for page failure trap */ -static void -pfbeg(void) -{ - fprintf(stderr, "[PFAIL(%s,%lo,%s,\"%s\") ", - (cpu.pag.pr_fmap == cpu.pr_umap ? "U" - : (cpu.pag.pr_fmap == cpu.pr_emap ? "E" - : (cpu.pag.pr_fmap == pr_pmap ? "P" - : (cpu.pag.pr_fmap == NULL ? "IO" - : "\?\?\?")))), (long) cpu.pag.pr_fref, - ((cpu.pag.pr_facf&VMF_WRITE) ? "W" - : ((cpu.pag.pr_facf&VMF_READ) ? "R" - : "0")), - cpu.pag.pr_fstr ? cpu.pag.pr_fstr : "?" ); - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); - fprintf(stderr,"%lo: => ", (long) PC_30); -} - -static void -pfend(void) -{ - pishow(stderr); pcfshow(stderr, cpu.mr_pcflags); - fprintf(stderr,"%lo:]\r\n", (long) PC_30); -} - -static uint32 -fetch32(register vaddr_t e) -{ - register w10_t w; - w = vm_read(e); /* Get word from c(E) */ - return ((uint32)LHGET(w) << 18) | RHGET(w); /* Convert to 32-bit value */ -} - -static void -store32(register vaddr_t e, - register uint32 val) -{ - register w10_t w; - LRHSET(w, (val>>18)&H10MASK, val & H10MASK); /* Put val into word */ - vm_write(e, w); /* Store at c(E) */ -} - -#if KLH10_PAG_ITS || KLH10_PAG_KI - -/* PAG_REFILL - Called when a virtual mem ref failed due to invalid -** access bits in the page map. Attempts a refill of the entry. -** On success, returns a vmptr_t to the physical memory location. -** On failure, depending on whether VMF_NOTRAP is set in the access flags, -** Not set - calls pag_fail() to carry out a page fault trap. -** Set - returns NULL. -*/ -vmptr_t -pag_refill(register pment_t *p, /* Page map pointer */ - vaddr_t e, /* Virtual address to map */ - pment_t f) /* Access flags */ -{ - register pment_t ent; /* Pager table entry, used by "hardware" */ - register pagno_t pag; - register h10_t mapent; /* Map entry set up by software */ - register vaddr_t addr; /* Address of map entry word */ - - pag = va_page(e); /* Get virtual page number */ - - /* Find address of correct page map entry from software table */ - -#if KLH10_PAG_ITS - /* Find which DBR to refill from; depends on user/exec context and - ** whether in low or high memory. - */ - if (p == cpu.pr_umap) { /* Assume user map (most common) */ - addr = ((pag & 0200) ? cpu.pag.pr_dbr2 : cpu.pag.pr_dbr1) - + ((pag & 0177) >> 1); - } else if (p == cpu.pr_emap) { /* Else must be exec map */ - addr = ((pag & 0200) ? cpu.pag.pr_dbr3 : cpu.pag.pr_dbr4) - + ((pag & 0177) >> 1); - } -#elif KLH10_PAG_KI - if (p == cpu.pr_umap) /* Assume user map (most common) */ - addr = cpu.mr_ubraddr + UPT_PMU + (pag>>1); - else if (p == cpu.pr_emap) { /* Else must be exec map */ - if (pag & 0400) - addr = cpu.mr_ebraddr + EPT_PME400 + ((pag&0377)>>1); - else { - if (pag >= 0340) /* Get special seg from UPT? */ - addr = cpu.mr_ubraddr + UPT_PME340 + ((pag-0340)>>1); - else - addr = cpu.mr_ebraddr + EPT_PME0 + (pag>>1); - } - } -#endif - else if (p == pr_pmap) { - /* Physical map -- turn reference into a NXM. */ - pag_nxmfail((paddr_t) va_30(e), f, "paging-off refill"); - return vm_physmap(0); /* In case return, provide a ptr */ - - } else { - panic("pag_refill: unknown map! p=0x%lX, e=%#lo, f=%#lo", - (long)p, (long)e, (long)f); - } - - - /* Fetch map entry from PDP-10 memory. This is a halfword table - ** hence we test low bit of page # to see if entry is in LH or RH. - */ - mapent = (pag & 01) /* Get RH or LH depending on low bit */ - ? RHPGET(vm_physmap(addr)) : LHPGET(vm_physmap(addr)); - - /* Transform software pagemap flags into internal "hardware" flags. */ -#if KLH10_PAG_ITS - switch (mapent & PM_ACC) { /* Check out ITS access bits */ - case PM_ACCNON: /* 00 - No access */ - ent = 0; - break; - case PM_ACCRO: /* 01 - Read Only */ - case PM_ACCRWF: /* 10 - Convert R/W/F to RO */ - ent = (f & VMF_WRITE) /* Fail if writing, else win */ - ? 0 : VMF_READ; - break; - case PM_ACCRW: /* 11 - Read/Write */ - ent = VMF_READ | VMF_WRITE; /* Always win */ - break; - } -#elif KLH10_PAG_KI - switch (mapent & (PM_ACC|PM_WRT)) { - case 0: - case PM_WRT: /* No access */ - ent = 0; - break; - case PM_ACC: /* Read-Only */ - ent = (f & VMF_WRITE) /* Fail if writing, else win */ - ? 0 : VMF_READ; - break; - case PM_ACC|PM_WRT: /* Read/Write */ - ent = VMF_READ | VMF_WRITE; /* Always win */ - break; - } -#endif - - /* Now check access... */ - if (ent) { -#if KLH10_PAG_KI - /* Should check here for getting a physical page # greater than - ** our available physical memory. But as long as we always support - ** the max possible (512K for KS, etc) we're safe. - */ - if ((mapent & PM_PAG) > PAG_PAMSK) { - /* Ugh, fail with NXM */ - cpu.pag.pr_fref = pag_pgtopa(mapent & PM_PAG) | va_pagoff(e); - cpu.pag.pr_fstr = "NXM page"; - cpu.pag.pr_flh = - (p == cpu.pr_umap ? PF_USER : 0) /* U */ - | PMF_NXMERR /* fail type 37 */ - | PF_VIRT; /* V=1 */ - - cpu.aprf.aprf_set |= APRF_NXM; /* Report as APR flag too */ - apr_picheck(); /* Maybe set PI (will happen after pagefail) */ - - } else -#endif - { - p[pag] = ent | (mapent & PM_PAG); /* Won, set hardware table */ - return vm_physmap(pag_pgtopa(mapent & PM_PAG) | va_pagoff(e)); - } - } else { - - /* Failed, store info so that pag_fail can trap later if caller - ** decides to invoke it. - */ - cpu.pag.pr_fref = va_insect(e); /* Save virtual addr */ - cpu.pag.pr_fstr = (ent & VMF_READ) ? "W in RO page" : "NoAcc page"; -#if KLH10_PAG_ITS - cpu.pag.pr_flh = (p == cpu.pr_umap ? PF_USR : 0) - | ((f & VMF_WRITE) ? PF_WRT : 0) - | ((mapent & PM_29) ? PF_29 : 0) - | ((mapent & PM_28) ? PF_28 : 0); -#elif KLH10_PAG_KI -# if KLH10_CPU_KS - cpu.pag.pr_flh = PF_VIRT - | (p == cpu.pr_umap ? PF_USER : 0) - | ((f & VMF_WRITE) ? PF_WREF : 0) - | ((mapent & PM_ACC) ? (PF_ACC - | ((mapent & PM_SFT) ? PF_SFT : 0)) - : 0); -# elif KLH10_CPU_KL - cpu.pag.pr_flh = - (p == cpu.pr_umap ? PF_USER : 0) /* U */ - | ((mapent & PM_ACC) ? PF_ACC : 0) /* A */ - | ((mapent & PM_WRT) ? PF_WRT : 0) /* W */ - | ((mapent & PM_SFT) ? PF_SFT : 0) /* S */ - | ((f & VMF_WRITE) ? PF_WREF : 0) /* T */ - | ((mapent & PM_PUB) ? PF_PUB : 0) /* P */ - | ((mapent & PM_CSH) ? PF_CSH : 0) /* C */ - | PF_VIRT; /* V */ -# endif -#endif - } - - cpu.pag.pr_fmap = p; - cpu.pag.pr_facf = f; - - if (!(f & VMF_NOTRAP)) /* If caller isn't suppressing traps, */ - pag_fail(); /* take page failure trap now! */ - return NULL; /* Otherwise just return NULL */ -} -#endif /* KLH10_PAG_ITS || KLH10_PAG_KI */ - - -#if KLH10_CPU_KS - -/* PAG_IOFAIL - Called from IO code for bad unibus address -*/ -void -pag_iofail(paddr_t ioaddr, - int bflg) /* True if byte-mode reference */ -{ -#if KLH10_PAG_ITS - cpu.pag.pr_flh = (PF_NXI|PF_PHY|PF_IO - | (bflg ? PF_BYT : 0) - | (cpu.vmap.cur == cpu.pr_umap ? PF_USR : 0) - ); -#elif KLH10_PAG_KI || KLH10_PAG_KL - cpu.pag.pr_flh = (PF_HARD|PF_VIRT|PF_IOREF - | (bflg ? PF_IOBYTE : 0) - | (cpu.vmap.cur == cpu.pr_umap ? PF_USER : 0) - ); -#endif - cpu.pag.pr_fref = ioaddr; - cpu.pag.pr_fstr = "NX IO addr"; - cpu.pag.pr_fmap = NULL; - cpu.pag.pr_facf = 0; - pag_fail(); -} -#endif /* KLH10_CPU_KS */ - - -/* PAG_FAIL - Instruction aborted due to page failure (mem ref). -** Save context, set up new, then longjmp to main loop. -** NOTE: the virtual address given must be correct! This routine assumes -** the LH (section or controller) bits are meaningful when building -** the page fail word. -** -** Note that ITS KS10 pager microcode differs from DEC: -** - Words are in EPT, not UPT. -** - Page fail vector saves PC+flags in 1 word (like T10), not 2 like T20. -** - Instead of one vector, there are 8, one for each PI level plus -** the non-PI case! -** -;;; In the ITS microcode the three words used to deliver a page fail are -;;; determined from the current interrupt level. At level I, the page fail -;;; word is stored in EPTPFW+<3*I>, the old PC is stored in EPTPFO+<3*I>, -;;; and the new PC is obtained from EPTPFN+<3*I>. If no interrupts are in -;;; progress we just use EPTPFW, EPTPFO and EPTPFN. - -** DEC T10 and T20 differ mainly in that the old flags+PC are 1 word on T10, -** 2 words on T20. -** -** The Extended KL case is basically identical to KS T20. -** -** Extended KL behavior: -** PCS is saved in the flag word ONLY if old mode was exec. -** New flags are all cleared; PCP and PCU are not set. -** Evidently no new PCS is set. -** -** Also, on the KL, for AR and ARX parity errors the "word with correct -** parity" is saved in AC0, block 7. But we never get such errors -** except for physical NXMs. -** Also, on the KL, for IO Page Failures (ie PF during PI interrupt instr) -** the PI function word is stored in AC2, block 7. -** T20 monitor code says "as of KL ucode v257", 24-Feb-82. -*/ -void -pag_fail(void) -{ - register w10_t w; - register paddr_t paddr; - - /* Sanity checks */ - if (!cpu.mr_paging && cpu.mr_exsafe) { - pfbeg(); /* Do initial barf */ - fprintf(stderr, "Paging OFF, but trapping!]\r\n"); - if (cpu.mr_exsafe >= 2) - apr_halt(HALT_EXSAFE); - } - if (cpu.mr_injrstf) /* Internal error */ - panic("pag_fail: page fail in JRSTF!"); - - /* First undo whatever we were in the middle of. */ - -#if KLH10_ITS_1PROC - if (cpu.mr_in1proc) a1pr_undo(); /* Undo if in one-proceed */ -#elif KLH10_CPU_KI || KLH10_CPU_KL - if (cpu.mr_inafi) afi_undo(); /* Undo if in AFI */ -#endif - if (cpu.mr_intrap) trap_undo(); /* Undo if in trap instruction */ - if (cpu.mr_inpxct) pxct_undo(); /* Undo if PXCT operand */ - /* (This may restore correct PC!) */ - if (cpu.mr_inpi) { - /* Page failure during interrupt instruction! - ** KS always drops dead. - ** KL does something a little more elaborate. Since it really - ** ought not to happen, and can be hard to figure out after the fact, - ** some error output is given even though execution continues - ** to emulate the KL. - ** Note that the PI function word has already been stored in AC3 BLK7. - ** The page fail word needs to be put into AC2 BLK7. - */ -#if KLH10_CPU_KL - if (cpu.mr_exsafe || cpu.mr_debug) { - pfbeg(); /* Barf to show what's going on */ - fprintf(stderr, "PI IO Page Fail]\r\n"); - if (cpu.mr_exsafe >= 2) - apr_halt(HALT_EXSAFE); - } - cpu.aprf.aprf_set |= APRF_IOPF; /* Set IO Page Fail bit */ - apr_picheck(); /* Trigger new PI, we hope */ - LRHSET(w, cpu.pag.pr_flh | (cpu.pag.pr_fref >> H10BITS), - cpu.pag.pr_fref & H10MASK); - cpu.acblks[7][2] = w; /* Store page fail word here */ - cpu.mr_inpi = FALSE; /* Say no longer in PI */ - apr_int(); /* Back to main loop */ -#else /* KA+KI+KS */ - pfbeg(); - cpu.mr_inpi = FALSE; /* Say no longer in PI */ - panic("Illegal Instruction halt - page fail during int instr!"); -#endif /* !KL */ - } - -#if KLH10_DEBUG - if (cpu.mr_debug) - pfbeg(); /* Output page fail debugging info */ -#endif - - /* Now put together a page fail word. - ** Note that the address (pr_fref) is NOT masked here; that's left - ** up to the refill/map code, which knows how many bits to use. - */ - LRHSET(w, cpu.pag.pr_flh | (cpu.pag.pr_fref >> H10BITS), - cpu.pag.pr_fref & H10MASK); - - /* Now have page fail word. Deliver the fault... */ -#if KLH10_PAG_ITS -# define XPT_PFW EPT_PFW /* ITS uses words in EPT! */ -# define XPT_PFO EPT_PFO -# define XPT_PFN EPT_PFN - /* Find highest PIP and get number for that */ - paddr = cpu.mr_ebraddr + (3 * pilev_nums[cpu.pi.pilev_pip]); - -#elif KLH10_PAG_KI || KLH10_PAG_KL -# define XPT_PFW UPT_PFW /* T10/T20 use words in UPT! */ -# define XPT_PFO UPT_PFO -# define XPT_PFN UPT_PFN - paddr = cpu.mr_ubraddr; - -#endif - - vm_pset(vm_physmap(XPT_PFW+paddr), w); /* Store page fail word */ - - /* Now save old context (PC, flags, PCS). - ** This is *very* processor-specific and the code here - ** doesn't account for all processor/system variations yet. - */ -#if (KLH10_CPU_KLX || KLH10_CPU_KS) && KLH10_PAG_KL /* T20 on KS or KLX */ - /* Use 4-word page-fail block with room for big PCs */ -# if KLH10_EXTADR - if (!PCFTEST(PCF_USR)) /* Make saved flag word */ - LRHSET(w, cpu.mr_pcflags, pag_pcsget()); /* save PCS */ - else /* Unless in user mode */ -# endif - LRHSET(w, cpu.mr_pcflags, 0); - vm_pset(vm_physmap(UPT_PFF+paddr), w); /* Store flag word */ - -# if KLH10_EXTADR - /* NOTE: Empirical testing on a real 2065 indicates that only 23 - ** bits of PC appear to be saved, not the full 30 bits. - ** Hence the mask by VAF_VSMSK for now (later PC or PC_SECT may be - ** pre-cleaned, rendering explicit mask unnecessary). - */ - LRHSET(w, PC_SECT & VAF_VSMSK, PC_INSECT); /* Make old PC word */ -# else - LRHSET(w, 0, PC_INSECT); /* Make old PC word */ -# endif - vm_pset(vm_physmap(XPT_PFO+paddr), w); /* Store old PC */ - - w = vm_pget(vm_physmap(XPT_PFN+paddr)); /* Get new PC word */ -# if KLH10_EXTADR - PC_SET30((((paddr_t)LHGET(w)<<18) | RHGET(w)) & MASK30); -# else - PC_SET30(RHGET(w)); /* Set new PC */ -# endif - cpu.mr_pcflags = 0; /* and clear flags */ - -#else /* KL0/T20, KLX/T10, KS/T10, ITS */ - - /* Use 3-word page-fail block with old PC+flags */ - LRHSET(w, cpu.mr_pcflags, PC_INSECT); /* Make old PC word */ - vm_pset(vm_physmap(XPT_PFO+paddr), w); /* Store old PC */ - w = vm_pget(vm_physmap(XPT_PFN+paddr)); /* Get new PC word */ - PC_SET30(RHGET(w)); /* Set new PC */ - cpu.mr_pcflags = LHGET(w) & PCF_MASK; /* and new flags */ -#endif - - apr_pcfcheck(); /* Check flags for any changes */ - -#if KLH10_DEBUG - if (cpu.mr_debug) - pfend(); /* Finish up debug info */ -#endif - - apr_int(); /* Back to main loop */ -} - -#if KLH10_PAG_ITS - -/* ITS Page register instructions */ - -/* IO_LDBR1 - (BLKI .WR.,) -** IO_LDBR2 - (DATAI .WR.,) -** IO_LDBR3 - (BLKO .WR.,) -** IO_LDBR4 - (DATAO .WR.,) -*/ -#define setdbr(dbr) dbr = va_insect(e); pag_clear(); return PCINC_1 -ioinsdef(io_ldbr1) { setdbr(cpu.pag.pr_dbr1); } -ioinsdef(io_ldbr2) { setdbr(cpu.pag.pr_dbr2); } -ioinsdef(io_ldbr3) { setdbr(cpu.pag.pr_dbr3); } -ioinsdef(io_ldbr4) { setdbr(cpu.pag.pr_dbr4); } -#undef setdbr - -/* IO_LPMR - (CONSO .WR.,) -** Load DBR block from memory into pager registers -*/ -ioinsdef(io_lpmr) -{ - register w10_t w; - register int i; - vmptr_t p[5]; - - /* LPMR isn't that frequent, so resolve the 5 refs with a loop */ - for (i = 0; i < 5; ++i) { - if (i) va_inc(e); /* Bump addr, may wrap */ - p[i] = vm_xrwmap(e, VMF_READ); /* Ensure all locations are valid */ - } - - w = vm_pget(p[0]); /* Get DBR1 */ - cpu.pag.pr_dbr1 = ((uint32)LHGET(w) << 18) | RHGET(w); - w = vm_pget(p[1]); /* Get DBR2 */ - cpu.pag.pr_dbr2 = ((uint32)LHGET(w) << 18) | RHGET(w); - w = vm_pget(p[2]); /* New quantum timer */ -#if KLH10_CPU_KS - /* KS quantum field is 044000 (high 32 bits; low 4 ignored) */ - cpu.pag.pr_quant = ((uint32)LHGET(w) << (18-4)) | (RHGET(w)>>4); -#else -# error "io_lpmr() not implemented for non-KS10" -#endif - if (!cpu.pi.pilev_pip) /* Start it going if OK */ - cpu.pag.pr_quant = quant_unfreeze(cpu.pag.pr_quant); - w = vm_pget(p[3]); - cpu.pag.pr_ujpc = ((uint32)LHGET(w) << 18) | RHGET(w); - w = vm_pget(p[4]); - cpu.pag.pr_ejpc = ((uint32)LHGET(w) << 18) | RHGET(w); -#if KLH10_ITS_JPC /* Update JPC for mode */ - cpu.mr_jpc = (cpu.mr_usrmode ? cpu.pag.pr_ujpc : cpu.pag.pr_ejpc); -#endif - - /* Now must reset cache and page tables!! */ - pag_clear(); - - return PCINC_1; -} - -/* IO_SDBR1 - (BLKI .RD.,) -** IO_SDBR2 - (DATAI .RD.,) -** IO_SDBR3 - (BLKO .RD.,) -** IO_SDBR4 - (DATAO .RD.,) -*/ -static pcinc_t getdbr(vaddr_t, uint32); - -ioinsdef(io_sdbr1){ return getdbr(e, cpu.pag.pr_dbr1); } -ioinsdef(io_sdbr2){ return getdbr(e, cpu.pag.pr_dbr2); } -ioinsdef(io_sdbr3){ return getdbr(e, cpu.pag.pr_dbr3); } -ioinsdef(io_sdbr4){ return getdbr(e, cpu.pag.pr_dbr4); } - -static pcinc_t -getdbr(vaddr_t e, uint32 dbr) -{ - register w10_t w; - LRHSET(w, (dbr>>18)&H10MASK, dbr & H10MASK); - vm_write(e, w); - return PCINC_1; -} - -/* IO_SPM - (CONSO .RD.,) -** Store DBRs etc in memory -*/ -ioinsdef(io_spm) -{ - register w10_t w; - register int32 qcnt; - vmptr_t p[5]; - - /* SPM isn't that frequent, so resolve the 5 refs with a loop */ - for (qcnt = 0; qcnt < 5; ++qcnt) { - if (qcnt) va_inc(e); /* Bump addr, may wrap */ - p[qcnt] = vm_wrtmap(e); /* Ensure all locations are valid */ - } - - LRHSET(w, (cpu.pag.pr_dbr1>>18)&H10MASK, cpu.pag.pr_dbr1 & H10MASK); - vm_pset(p[0], w); /* Store DBR1 */ - LRHSET(w, (cpu.pag.pr_dbr2>>18)&H10MASK, cpu.pag.pr_dbr2 & H10MASK); - vm_pset(p[1], w); /* Store DBR2 */ - qcnt = (cpu.pi.pilev_pip ? cpu.pag.pr_quant - : quant_freeze(cpu.pag.pr_quant)); -#if KLH10_CPU_KS - /* KS quantum field is 044000 (high 32 bits; low 4 ignored) */ - LRHSET(w, (qcnt>>(18-4))&H10MASK, ((qcnt<<4) & H10MASK)); -#else -# error "io_spm() not implemented for non-KS10" -#endif - vm_pset(p[2], w); /* Store Quantum timer */ -#if KLH10_ITS_JPC - if (cpu.mr_usrmode) /* Update latest JPC for mode */ - cpu.pag.pr_ujpc = cpu.mr_jpc; - else cpu.pag.pr_ejpc = cpu.mr_jpc; -#endif - LRHSET(w, (cpu.pag.pr_ujpc>>18)&H10MASK, cpu.pag.pr_ujpc & H10MASK); - vm_pset(p[3], w); - LRHSET(w, (cpu.pag.pr_ejpc>>18)&H10MASK, cpu.pag.pr_ejpc & H10MASK); - vm_pset(p[4], w); - return PCINC_1; -} -#endif /* KLH10_PAG_ITS */ - -#if KLH10_PAG_KL /* DEC instruction for KL (T20) paging */ - -/* MAP - Map an Address. -** This is not an IO-class instruction and the PRM says nothing -** about its legality in user mode, but it can't hurt, so no -** user-mode checking is done. -** HOWEVER, PRM 3-42 says on KL same IO-class restrictions do apply. -** NOTE: this code always does a full refill in order to find all of -** the entry bits; it does not look in the "hardware" map entry -** because we only keep a couple of the desired bits there to save -** space and improve cacheability. -** Since MAP is not called frequently this is OK speedwise, -** but this may consitute a difference from the real hardware -** (suppose something changed the map pointers without invalidating -** the page table). -** Also note: -** MAP can be invoked by a PXCT, so needs to use XRW mapping when -** checking out the refill. -** Question: -** What happens if NXM interrupts are enabled for APR and a NXM -** happens as a result of MAP? Is it ignored, or is the interrupt -** still triggered although the page fail trap isn't? -** For the time being, I'll assume YES. This is probably a non-issue -** anyway as enabling those ints is discouraged. -*/ -insdef(i_map) -{ - register vmptr_t vmp; - register w10_t w; - register h10_t pfent; - register h10_t pflags; - register paddr_t pa; - -#if KLH10_CPU_KL - if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) - return i_muuo(op, ac, e); -#endif - - if (vmp = pag_refill(cpu.vmap.xrw, e, VMF_NOTRAP)) { - pa = vmp - cpu.physmem; /* Recover physical addr */ - pfent = cpu.pag.pr_flh; /* And fetch access bits for page */ - - /* Now transform access bits into MAP result bits. */ -#if KLH10_MCA25 /* PF_KEEP is a re-use of PF_VIRT */ - pflags = PF_ACC; - if (pfent & PT_KEEP) pflags |= PF_KEEP; -#else - pflags = PF_ACC | PF_VIRT; -#endif -#if KLH10_CPU_KL - if (pfent & PT_PACC) pflags |= PF_PUB; -#endif - if (pfent & PT_WACC) pflags |= PF_WRT; - if (pfent & PT_CACHE) pflags |= PF_CSH; - if (pfent & CST_MBIT) pflags |= PF_MOD; /* Special non-PT bit */ - if (cpu.vmap.xrw == cpu.pr_umap) pflags |= PF_USER; - - } else { - pflags = cpu.pag.pr_flh; /* Just get fail bits already set up */ - pa = cpu.pag.pr_fref & MASK22; /* And recover failing addr */ - } - LRHSET(w, (pflags | (pa >> H10BITS)), pa & H10MASK); - ac_set(ac, w); /* Store result in given AC */ - return PCINC_1; -} -#endif /* KLH10_PAG_KL */ - -#if KLH10_PAG_KI - -/* MAP instruction for KI (T10) paging. -** KI paging MAP is different enough from KL/T20 that it makes -** more sense to keep it a separate routine. In particular, there -** is no way for a map entry to "fail", even though a pag_refill call -** could cause a failure. -*/ - -insdef(i_map) -{ - register h10_t pflags; - register paddr_t pa; - register pment_t *p; - register pagno_t pag; - register h10_t mapent; /* Map entry set up by software */ - register vaddr_t addr; /* Address of map entry word */ - register w10_t w; - -#if KLH10_CPU_KL - if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) - return i_muuo(op, ac, e); -#endif - - /* Find map entry. This does a refill lookup instead of checking - ** the hardwage page table. - */ - pag = va_page(e); /* Get virtual page number */ - p = cpu.vmap.xrw; /* Use XRW map (may be PXCT'd) */ - if (p == cpu.pr_umap) /* Assume user map (most common) */ - addr = cpu.mr_ubraddr + UPT_PMU + (pag>>1); - else if (p == cpu.pr_emap) { /* Else must be exec map */ - if (pag & 0400) - addr = cpu.mr_ebraddr + EPT_PME400 + ((pag&0377)>>1); - else { - if (pag >= 0340) /* Get special seg from UPT? */ - addr = cpu.mr_ubraddr + UPT_PME340 + ((pag-0340)>>1); - else - addr = cpu.mr_ebraddr + EPT_PME0 + (pag>>1); - } - } else { - if (p != pr_pmap) /* Permit phys map to return 0 */ - panic("[i_map: unknown map %lo!]", (long)p); - op10m_setz(w); /* Return 0 (what else?) */ - ac_set(ac, w); - return PCINC_1; - } - - /* Fetch map entry from PDP-10 memory. This is a halfword table - ** hence we test low bit of page # to see if entry is in LH or RH. - */ - mapent = (pag & 01) /* Get RH or LH depending on low bit */ - ? RHPGET(vm_physmap(addr)) : LHPGET(vm_physmap(addr)); - - if (mapent & PM_ACC) { /* Valid mapping? */ - /* Now transform access bits into MAP result bits. */ - pflags = - (p == cpu.pr_umap ? PF_USER : 0) /* U */ - | ((mapent & PM_ACC) ? PF_ACC : 0) /* A */ - | ((mapent & PM_WRT) ? PF_WRT : 0) /* W */ - | ((mapent & PM_SFT) ? PF_SFT : 0) /* S */ - /* T=0 */ - | ((mapent & PM_PUB) ? PF_PUB : 0) /* P */ - | ((mapent & PM_CSH) ? PF_CSH : 0) /* C */ - | PF_VIRT; /* V=1 */ - - /* Always return phys addr, even if bogus and would NXM if tried */ - pa = pag_pgtopa(mapent & PM_PAG) | va_pagoff(e); - LRHSET(w, (pflags | (pa >> H10BITS)), pa & H10MASK); - } else - LRHSET(w, PF_VIRT, 0); /* Invalid mapping */ - - ac_set(ac, w); /* Store result in given AC */ - return PCINC_1; -} -#endif /* KLH10_PAG_KI */ - -/* DEC (mainly TOPS-20) Page register instructions */ - -#if KLH10_PAG_KL && KLH10_CPU_KS - -/* WRSPB (70240 = BLKI MTR,) - Write SPT Base Address -** Sets SPB from c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -** Note: one might expect this to invalidate the cache and page table, -** but the PRM makes no mention of this action. So we don't. -*/ -ioinsdef(io_wrspb) -{ - cpu.pag.pr_spb = fetch32(e); - return PCINC_1; -} - -/* RDSPB (70200 = BLKI TIM,) - Read SPT Base Address -** Reads SPB into c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -*/ -ioinsdef(io_rdspb) -{ - store32(e, cpu.pag.pr_spb); - return PCINC_1; -} - -/* WRCSB (70244 = DATAI MTR,) - Write CST Base Address -** Sets CSB from c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -** Note: one might expect this to invalidate the cache and page table, -** but the PRM makes no mention of this action. So we don't. -*/ -ioinsdef(io_wrcsb) -{ - cpu.pag.pr_csb = fetch32(e); - return PCINC_1; -} - -/* RDCSB (70204 = DATAI TIM,) - Read CST Base Address -** Reads CSB into c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -*/ -ioinsdef(io_rdcsb) -{ - store32(e, cpu.pag.pr_csb); - return PCINC_1; -} - -/* WRCSTM (70254 = DATAO MTR,) - Write CST Mask Register -** Sets CSTM from c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -*/ -ioinsdef(io_wrcstm) -{ - cpu.pag.pr_cstm = vm_read(e); - return PCINC_1; -} - -/* RDCSTM (70214 = DATAO TIM,) - Read CST Mask Register -** Reads CSTM into c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -*/ -ioinsdef(io_rdcstm) -{ - vm_write(e, cpu.pag.pr_cstm); - return PCINC_1; -} - -/* WRPUR (70250 = BLKO MTR,) - Write Process Use Register -** Sets PUR from c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -*/ -ioinsdef(io_wrpur) -{ - cpu.pag.pr_pur = vm_read(e); - return PCINC_1; -} - -/* RDPUR (70210 = BLKO TIM,) - Read Process Use Register -** Reads PUR into c(E). -** IO-class instruction, assumed legal only in Exec or if User-IOT set. -*/ -ioinsdef(io_rdpur) -{ - vm_write(e, cpu.pag.pr_pur); - return PCINC_1; -} - -#endif /* KL-paging && KS */ - -#if KLH10_CPU_KL - -/* DEC KL10 Cache Instructions -** -** These are here because they have more to do with paging -** than anything else. For the KLH10, they basically do -** nothing at all, since there is no cache to manage. -*/ - -/* -** - (70140 = BLKI CCA,) - Sweep Cache, uselessly -** SWPIA (70144 = DATAI CCA,) - Sweep Cache, Invalidate All Pages -** SWPVA (70150 = BLKO CCA,) - Sweep Cache, Validate All Pages -** SWPUA (70154 = DATAO CCA,) - Sweep Cache, Unload All Pages -** - (70160 = CONO CCA,) - Sweep Cache, uselessly -** SWPIO (70164 = CONI CCA,) - Sweep Cache, Invalidate One Page -** SWPVO (70170 = CONSZ CCA,) - Sweep Cache, Validate One Page -** SWPUO (70174 = CONSO CCA,) - Sweep Cache, Unload One Page -*/ -ioinsdef(io_swp) /* Invoked directly by BLKI and CONO */ -{ - /* Pretend sweep is done instantly, and hope nothing breaks. */ -#if 0 /* Always off, to avoid needing more than 16 bits */ - cpu.aprf.aprf_set &= ~APRR_SWPBSY; -#endif - cpu.aprf.aprf_set |= APRF_SWPDON; /* Say sweep done */ - apr_picheck(); /* Trigger int if desired */ - return PCINC_1; -} - -ioinsdef(io_swpia) { return io_swp(e); } -ioinsdef(io_swpva) { return io_swp(e); } -ioinsdef(io_swpua) { return io_swp(e); } -ioinsdef(io_swpio) { return io_swp(e); } -ioinsdef(io_swpvo) { return io_swp(e); } -ioinsdef(io_swpuo) { return io_swp(e); } - - -/* WRFIL (70010 = BLKO APR,) - Write Refill Table -** KL10 hack for programming the cache. Fortunately no need to -** do anything here! -*/ -ioinsdef(io_wrfil) -{ - return PCINC_1; -} - -#endif /* KL */ - -#if KLH10_CPU_KL - -/* KL10 Address Break and Memory Maintenance instructions */ - -/* (70014 = DATAO APR,) - KL: Set Address Break register -** Sets address break from c(E). -** Note: This is not actually implemented, for obvious efficiency -** reasons. It certainly *could* be if that proved desirable. -*/ -ioinsdef(io_do_apr) -{ - cpu.mr_adrbrk = vm_read(e); - return PCINC_1; -} - -/* (70004 = DATAI APR,) - KL: Read Address Break register -** Reads address break into c(E). -*/ -ioinsdef(io_di_apr) -{ - vm_write(e, cpu.mr_adrbrk); - return PCINC_1; -} - - -/* RDERA (70040 = BLKI PI,) - KL: Read Error Address Register -** Reads ERA into c(E). -** -** To fake out the APR locking flag hackery, simply zap the ERA anytime -** this is called and no locking flag is set. -*/ -ioinsdef(io_rdera) -{ - w10_t w; - - if (!(cpu.aprf.aprf_set & (APRF_NXM|APRF_MBPAR|APRF_ADPAR))) - cpu.pag.pr_era = 0; /* No locking flags, zap ERA */ - - LRHSET(w, (cpu.pag.pr_era >> 18) & 07777, cpu.pag.pr_era & H10MASK); - vm_write(e, w); - return PCINC_1; -} - - -/* SBDIAG (70050 = BLKO PI,) - KL: S Bus Diagnostic Function -** Send c(E) to S-bus memory controller, read return word into E+1. -** Controller # in bits 0-4, function code in 31-35. -** -** Apparently function 0 returns -1 for a "non-ex Fbus" controller, 0 for a -** non-existent controller? -** -** Documentation for the function and return words can be found in -** the PRM, Appendix G, "Handling Memory". -** -** The support here is the minimum necessary to fake out TOPS-20. -** For now it pretends to have MF20 memories with the maximum -** amount of physical memory (22 bits). Actually it takes advantage of -** the trivial way T20 does its memory init by simply pretending to have a -** single MF20 (controller 010) that responds "here!" to the entire -** physical memory range! -*/ - -/* SBDIAG function word fields */ -#define SBD_FCTLR 0760000 /* LH: Controller # (MF20s are 10-17) */ -#define SBD_FFUN 037 /* RH: Function # */ -# define SBD_FN_0 0 -# define SBD_FN_1 01 -/* Functions 2, 6, and 7 are only used to attempt error correction. */ -/* 7 is used by KL diags (SUBKL) to initialize memory. */ -# define SBD_FN_7 07 -# define SBD_FN_12 012 - -#define SBD_F0CLR 010000 /* LH: F0 Clear error flags */ -#define SBD_R0ERRS 0770000 /* LH: Error bits */ - -#define SBD_R1TYP 01700 /* LH: Controller Type Field */ -# define SBD_R1TMA20 00100 /* LH: MA20 */ -# define SBD_R1TDMA20 00200 /* LH: DMA20 */ -# define SBD_R1TMB20 00300 /* LH: MB20 */ -# define SBD_R1TMF20 00500 /* LH: MF20 */ -#define SBD_R1OFFL 02000 /* RH: Off Line */ - -#define SBD_F12BLKNO 0176000 /* RH: F12 Block # - high 6 bits of */ - /* 22-bit phys addr (block=64K) */ -#define SBD_R12BLKNH 010 /* LH: Block Disable ("Not here") */ - - -ioinsdef(io_sbdiag) -{ - register w10_t w; - register paddr_t pa; - - w = vm_read(e); /* Read the function word */ - if ((LHGET(w) >> 13) == 010) { /* Controller # we support? */ - - switch (RHGET(w) & SBD_FFUN) { /* Get function # */ - case SBD_FN_0: - LRHSET(w, 06000, 0); /* Say nothing wrong */ - break; - - case SBD_FN_1: - LRHSET(w, SBD_R1TMF20, 0); /* Say MF20 and online */ - break; - - case SBD_FN_7: - if (!op10m_tlnn(w, 04)) /* If 7-14 enabled, return them */ - LHSET(w, 0); /* else clear LH */ - RHSET(w, 0); /* always clear RH */ - break; - - case SBD_FN_12: - pa = (RHGET(w) & SBD_F12BLKNO) >> 10; /* Get block # */ - pa <<= (16 - PAG_BITS); /* Find phys page # it represents */ - if (pa < PAG_MAXPHYSPGS) - op10m_setz(w); /* Win, say phys mem is there */ - else - LRHSET(w, SBD_R12BLKNH, 0); /* Ugh, say no block */ - break; - - default: -#if KLH10_DEBUG - fprintf(stderr, "[io_sbdiag: Unimpl function: %#lo,,%#lo]\r\n", - (long)LHGET(w), (long)RHGET(w)); -#endif - op10m_setz(w); - break; - } - } else - op10m_setz(w); - - /* Store result */ - va_inc(e); /* Bump to E+1 */ - vm_write(e, w); /* Store result word in E+1 */ - return PCINC_1; -} - - -#endif /* KL */ - -#if KLH10_PAG_KL - -/* DEC TOPS-20 (KL) paging */ - -/* PAG_REFILL - Called when a virtual mem ref failed due to invalid -** access bits in the page map. Attempts a refill of the entry. -** On success, returns a vmptr_t to the physical memory location. -** On failure, depending on whether VMF_NOTRAP is set in the access flags, -** Not set - calls pag_fail() to carry out a page fault trap. -** Set - returns NULL. -** -** Note that if a MCA25 is defined to be present, what was formerly -** PF_VIRT becomes PF_KEEP. This change is not supported at the -** moment for failing refills; pag_t20map() does not report the -** access bits it found for failing references. -** However, there is nothing in the T20 monitor that tests for this. -*/ - -static vmptr_t pag_t20map(pment_t *, pagno_t, pment_t); - -vmptr_t -pag_refill(register pment_t *p, /* Page map pointer */ - vaddr_t e, /* Virtual address to map */ - pment_t f) /* Access flags */ -{ - register vmptr_t vmp; - register h10_t pflh; - - /* Note page number passed to pag_t20map is the FULL XA page, which on - ** a KL is 12+9=21 bits, not the supported 5+9=14 virtual. - */ - if (vmp = pag_t20map(p, va_xapage(e), (f & VMF_ACC))) /* Try mapping */ - return vmp + va_pagoff(e); /* Won, return mapped ptr! */ - - /* Ugh, analyze error far enough to build page fail word LH bits, - ** so that pag_fail can be invoked either now or later. - ** - ** Note that here is where we check for and set the APR condition bits - ** for (eg) NXM. If a PI is triggered (not a good idea, according to PRM - ** p.4-42), it will not take effect until - ** after the page fail trap has happened and control returns to the - ** main instruction loop. - */ - cpu.pag.pr_fmap = p; - cpu.pag.pr_facf = f; - switch (pflh = cpu.pag.pr_flh) { -#if KLH10_CPU_KS - case PMF_PARERR: /* Uncorrectable memory error */ - /* Phys addr set in pr_fref */ - cpu.aprf.aprf_set |= APRF_BMD; /* Report as APR flag too */ - apr_picheck(); /* Maybe set PI (will happen after pagefail) */ - pflh |= PF_VIRT; - break; - case PMF_NXMERR: /* Nonexistent memory */ - /* Phys addr set in pr_fref */ - cpu.aprf.aprf_set |= APRF_NXM; /* Report as APR flag too */ - apr_picheck(); /* Maybe set PI (will happen after pagefail) */ - pflh |= PF_VIRT; - break; - -#elif KLH10_CPU_KL - case PMF_ISCERR: /* Illegal section # */ - /* PRM 3-41 says don't set PF_VIRT for this error! */ - /* NOTE: Address part is undefined by PRM, but real KL seems to - ** report only 23 bits of virtual address. - */ - cpu.pag.pr_fref = va_30(e) & MASK23; /* Remember virt ref */ - break; - - /* Here we are using PMF_NXMERR to indicate not an ARX parity error - ** but a reference to non-existent physical memory, which sets - ** APR CONI bit 25 as well as bit 27. - ** The ERA (Error Address Register) also needs to be set. For now - ** just use the failing phys addr ref. - */ - case PMF_NXMERR: /* Nonexistent physical memory */ - /* Phys addr set in pr_fref, may have very high bits */ - cpu.pag.pr_era = cpu.pag.pr_fref; - cpu.aprf.aprf_set |= APRF_NXM | APRF_MBPAR; - apr_picheck(); /* Maybe set PI (will happen after pagefail) */ - pflh |= PF_VIRT; - break; -#endif - case PMF_OTHERR: /* Random inaccessibility (soft) */ - if (f & VMF_WRITE) - pflh |= PF_WREF; - /* Drop thru */ - case PMF_WRTERR: /* Write violation (soft) */ - default: -#if KLH10_CPU_KS - cpu.pag.pr_fref = va_insect(e); /* Remember virtual addr ref */ -#elif KLH10_CPU_KL - /* NOTE: real KL seems to report only 23 bits of virtual address. - */ - cpu.pag.pr_fref = va_30(e) & MASK23; /* Remember virtual ref */ -#endif - pflh |= PF_VIRT; - break; - } - if (p == cpu.pr_umap) - pflh |= PF_USER; - cpu.pag.pr_flh = pflh; /* Store complete flags back */ - - if (!(f & VMF_NOTRAP)) /* If caller isn't suppressing traps, */ - pag_fail(); /* take page failure trap now! */ - return NULL; /* Otherwise just return NULL */ -} - - -/* PAG_T20MAP - Perform address mapping. -** On success, returns vmptr_t to start of physical page. -** The summarized access bits in pr_flh will be used only by MAP. -** On failure, returns NULL. -** pr_flh in this case will contain a PMF_xxx value to be used by -** the refill code to build a page fail word. MAP ignores it. -** -** WARNING: No checks are made to see whether the CST base address has -** anything reasonable in it. This is a possible source of problems -** on the KL which can update the SPT or CST pointers anytime it likes, -** without special notification to the pager. -*/ -static vmptr_t -pag_t20map(register pment_t *p, /* Page map pointer */ - pagno_t vpag, /* Virtual Page # */ - pment_t f) /* Access flags */ -{ - register w10_t w; - register h10_t accbits = 0; - register paddr_t paddr; - register pagno_t pag, pgn; - - accbits = PT_WACC | PT_CACHE /* | PT_PACC */ ; /* Start with these */ - - /* Find which map to refill from. - ** Get appropriate section pointer (always 0 on KS) - */ - if (p == cpu.pr_umap) { /* Assume user map (most common) - UBR */ - paddr = cpu.mr_ubraddr + UPT_SC0; - } else if (p == cpu.pr_emap) { /* Else must be exec map - EBR */ - paddr = cpu.mr_ebraddr + UPT_SC0; - } else if (p == pr_pmap) { /* If phys map, trigger NXM */ - cpu.pag.pr_flh = PMF_NXMERR; /* NXM during phys ref */ - cpu.pag.pr_fref = pag_pgtopa(vpag); - cpu.pag.pr_fstr = "NXM with phys map"; - return NULL; /* Fail - non-ex memory in phys ref */ - } else - panic("pag_t20map: unknown page table! p=0x%lX, pg=%#lo", - (long)p, (long)vpag); - -#if KLH10_CPU_KL - if (vpag & ~PAG_NAMSK) { /* Non-zero section bits? */ - if (vpag >= PAG_MAXVIRTPGS) { - cpu.pag.pr_flh = PMF_ISCERR; /* Illegal Address */ - /* cpu.pag.pr_fref = 0; */ /* Set in pag_refill */ - cpu.pag.pr_fstr = "Illeg sect #"; - return NULL; /* Fail - Illegal virt address */ - } - paddr += (vpag >> (PAG_NABITS-PAG_BITS)); /* Get section # */ - pag = vpag & PAG_NAMSK; /* Find in-section page # */ - } - else -#endif - pag = vpag; /* Get page # for table lookup */ - - for (;;) { - if (paddr >= cpu.pag.pr_physnxm) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = paddr; - cpu.pag.pr_fstr = "NXM fetching sect ptr"; - return NULL; /* Fail - NXM fetching section pointer */ - } - w = vm_pget(vm_physmap(paddr)); /* Get section pointer */ - - switch (LHGET(w) >> 15) { /* Find pointer type */ - default: - case PTT_NOACC: - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "noacc sect ptr"; - return NULL; /* Fail - inaccessible pointer */ - - case PTT_IMMED: - accbits &= LHGET(w); /* Mask access bits (P,W,C) */ - break; /* Won, drop out with ptr to map */ - - case PTT_SHARED: - accbits &= LHGET(w); /* Mask access bits (P,W,C) */ - paddr = PAG_PR_SPBPA + RHGET(w); /* Find SPT ent addr */ - if (paddr >= cpu.pag.pr_physnxm) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = paddr; - cpu.pag.pr_fstr = "NXM for sect SPT ent"; - return NULL; /* Fail - NXM fetching SPT entry */ - } - w = vm_pget(vm_physmap(paddr)); /* Get SPT entry */ - break; /* Won, have page addr */ - - case PTT_INDIRECT: - /* DEC PRM p.3-35 and p.4-22 says "Memory status is kept only - ** for the page maps." i.e. not for section table pages. So any - ** indirect section pointers generate no CST checks/updates. - */ - accbits &= LHGET(w); /* Mask access bits (P,W,C) */ - pgn = LHGET(w) & PT_IIDX; /* Save idx into next table */ - paddr = PAG_PR_SPBPA + RHGET(w); /* Find SPT ent addr */ - if (paddr >= cpu.pag.pr_physnxm) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = paddr; - cpu.pag.pr_fstr = "NXM for @ sect SPT ent"; - return NULL; /* Fail - NXM fetching SPT entry */ - } - w = vm_pget(vm_physmap(paddr)); /* Get SPT entry */ - if (LHGET(w) & SPT_MDM) { - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "non-core sect map"; - return NULL; /* Fail - inaccessible page map */ - } - paddr = pag_pgtopa(RHGET(w) & SPT_PGN) + pgn; - continue; /* Loop to get next section pointer */ - } - break; /* Break from switch is break from loop */ - } - - /* Now have the page address of the page map to use! - ** w contains the final pointer word. - ** pag is the page # to look up in the page map. - ** accbits has the access bits so far. - */ - for (;;) { - if (LHGET(w) & SPT_MDM) { - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "non-core page map"; - return NULL; /* Fail - inaccessible page map */ - } - pgn = RHGET(w) & SPT_PGN; - - /* Check page # here before possibly clobbering CST */ - if (pgn > (PAG_MAXPHYSPGS-1)) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = pag_pgtopa(pgn) + pag; - cpu.pag.pr_fstr = "map in NX page"; - return NULL; /* Fail - map in non-ex page */ - } - /* Carry out CST update if CST exists. */ - if (PAG_PR_CSBPA) { - w = vm_pget(vm_physmap(PAG_PR_CSBPA + pgn)); /* Get CST */ - if ((LHGET(w) & CST_AGE) == 0) { - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "map age trap"; - return NULL; /* Fail - age trap */ - } - op10m_and(w, PAG_PR_CSTMWD); /* AND it with CSTM */ - op10m_ior(w, PAG_PR_PURWD); /* IOR with PUR */ - vm_pset(vm_physmap(PAG_PR_CSBPA+pgn), w); /* Store back in CST */ - } - - /* OK, now pluck out page map entry */ - paddr = pag_pgtopa(pgn) + pag; - w = vm_pget(vm_physmap(paddr)); /* Get page map entry */ - - /* Handle map pointer */ - switch (LHGET(w) >> 15) { /* Get map pointer type */ - default: - case PTT_NOACC: - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "noacc page ptr"; - return NULL; /* Fail - inaccessible pointer */ - - case PTT_IMMED: - accbits &= LHGET(w); /* Mask access bits (P,W,C) */ - break; /* Won, drop out with ptr to page */ - - case PTT_SHARED: - accbits &= LHGET(w); /* Mask access bits (P,W,C) */ - paddr = PAG_PR_SPBPA + RHGET(w); /* Find SPT ent addr */ - if (paddr >= cpu.pag.pr_physnxm) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = paddr; - cpu.pag.pr_fstr = "NXM for page SPT ent"; - return NULL; /* Fail - NXM fetching SPT entry */ - } - w = vm_pget(vm_physmap(paddr)); /* Get SPT entry */ - break; /* Won, drop out with page addr */ - - case PTT_INDIRECT: - /* Note these effect CST update for secondary page maps by looping. - */ - accbits &= LHGET(w); /* Mask access bits (P,W,C) */ - pag = LHGET(w) & PT_IIDX; /* Clobber page # with index! */ - paddr = PAG_PR_SPBPA + RHGET(w); /* Find SPT ent addr */ - if (paddr >= cpu.pag.pr_physnxm) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = paddr; - cpu.pag.pr_fstr = "NXM for @ page SPT ent"; - return NULL; /* Fail - NXM fetching SPT entry */ - } - w = vm_pget(vm_physmap(paddr)); /* Get SPT entry */ - continue; /* Loop to handle it */ - } - break; - } - - /* Now have final page address */ - if (LHGET(w) & SPT_MDM) { /* Check storage medium field */ - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "non-core page"; - return NULL; /* Fail - inaccessible pointer to page */ - } - pag = RHGET(w) & SPT_PGN; - - /* Check page # here before possibly clobbering CST */ - if (pag > (PAG_MAXPHYSPGS-1)) { - cpu.pag.pr_flh = PMF_NXMERR; - cpu.pag.pr_fref = pag_pgtopa(pag); /* Don't know offset here */ - cpu.pag.pr_fstr = "NX phy page"; - return NULL; /* Fail - non-ex page # */ - } - - /* Carry out CST update if CST exists */ - if (PAG_PR_CSBPA) { - w = vm_pget(vm_physmap(PAG_PR_CSBPA + pag)); /* Get CST */ - if ((LHGET(w) & CST_AGE) == 0) { - cpu.pag.pr_flh = PMF_OTHERR; - cpu.pag.pr_fstr = "page age trap"; - return NULL; /* Fail - age trap */ - } - op10m_and(w, PAG_PR_CSTMWD); /* AND it with CSTM */ - op10m_ior(w, PAG_PR_PURWD); /* IOR with PUR */ - - /* Last check - attempted write reference? If so, may need to - ** also set M bit in CST entry. - */ - if (accbits & PT_WACC) { /* If page is writable */ - if (f & VMF_WRITE) /* and this is write ref */ - op10m_iori(w, CST_MBIT); /* then force the M bit */ - accbits |= RHGET(w) & CST_MBIT; /* Turn on M if set in CST */ - /* (note symbol mix with PT_xxx) */ - } else if (f & VMF_WRITE) { - /* Page not writable, but trying to do a write ref. Fail. */ - vm_pset(vm_physmap(PAG_PR_CSBPA+pag), w); - cpu.pag.pr_flh = PMF_WRTERR; - cpu.pag.pr_fstr = "W in RO Page"; - return NULL; /* Fail, page not writable */ - } - vm_pset(vm_physmap(PAG_PR_CSBPA+pag), w); /* Store back in CST */ - - } else { - /* CST doesn't exist (this can happen for TOPS-10 using T20 paging). - ** Not clear what to do about reporting the M bit. - ** Currently the hardware page table emulation doesn't retain such - ** a bit, in order to keep the entry size at 16 bits. So we'll - ** fake it for now by pretending that M is always set if W is; - ** i.e. all writable pages are assumed to be modified. - ** And let's hope nobody pays attention to it. T20 at least - ** doesn't appear to. - ** Note: error msg is deliberately worded differently from CST - ** case, to maintain uniqueness of all messages. Helps debug. - */ - if (accbits & PT_WACC) { /* If page is writable */ - accbits |= CST_MBIT; /* then always turn on M */ - /* (note symbol mix with PT_xxx) */ - } else if (f & VMF_WRITE) { - /* Page not writable, but trying to do a write ref. Fail. */ - cpu.pag.pr_flh = PMF_WRTERR; - cpu.pag.pr_fstr = "W of RO page"; - return NULL; /* Fail, page not writable */ - } - } - cpu.pag.pr_flh = accbits; /* Remember bits in case MAP */ - - /* Won completely, update internal page map! - ** VMF_READ serves the function of a 'valid' bit, and - ** VMF_WRITE serves as the 'M' (modified) bit. M should be set only - ** if the page is writable *and* M is set in the CST. - ** There is no need or support for an internal 'C' (cacheable) bit. - ** Likewise for any other bits (P, K) at the moment. - */ - p[vpag] = pag | VMF_READ - | ((accbits & CST_MBIT) ? VMF_WRITE : 0); - - return vm_physmap(pag_pgtopa(pag)); -} - -#endif /* T20 (KL) paging */ - -#if KLH10_EXTADR - -/* PAG_IISET - Called to set up for taking an Illegal Indirection page fail. -** PAG_IIFAIL - Called from effective address calculation if an -** illegal indirect word is seen (bits 0,1 == 11). -** The PRM says nothing about what the page fail word contains for -** this case; what I'll do is provide E, where c(E) contains the -** bad indirect word. This appears to be correct, according to the -** DFKED diagnostics. -** The PRM also says nothing about the handling of this when not -** paging! -*/ -void -pag_iiset(vaddr_t e, - pment_t *map) -{ - cpu.pag.pr_flh = (PMF_IIERR | PF_VIRT - | (map == cpu.pr_umap ? PF_USER : 0) - ); - cpu.pag.pr_fref = va_30(e); - cpu.pag.pr_fstr = "Illeg Indir"; - cpu.pag.pr_fmap = map; - cpu.pag.pr_facf = 0; -} - -void -pag_iifail(vaddr_t e, - pment_t *map) -{ - pag_iiset(e, map); - pag_fail(); /* What to do if not paging? */ -} - -#endif /* KLH10_EXTADR */ - -/* PMOVE, PMOVEM. Sort of related to paging, so put here. -*/ - -#if KLH10_CPU_KLX - -/* PMOVE - [op 052] Move from physical memory address (late KL addition) -** c(E) contains physical address of word to fetch into AC. -*/ -insdef(i_pmove) -{ - register w10_t w; - register paddr_t pa; - - if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* Standard IO-legal test */ - return i_muuo(op, ac, e); - - w = vm_read(e); - pa = ((paddr_t)LHGET(w)<<18) | RHGET(w); - if (pa >= ((paddr_t)PAG_MAXPHYSPGS << PAG_BITS)) { - /* Non-ex phys mem ref, do page-fail */ - pag_nxmfail(pa, VMF_READ, "PMOVE NXM"); - op10m_setz(w); /* If no trap, read 0 */ - ac_set(ac, w); - } else - ac_set(ac, vm_pget(vm_physmap(pa))); /* Fetch c(PA) into AC */ - - return PCINC_1; -} - -/* PMOVEM - [op 053] Move to physical memory address (late KL addition) -** c(E) contains physical address of word to store AC into. -*/ -insdef(i_pmovem) -{ - register w10_t w; - register paddr_t pa; - - if (PCFTEST(PCF_USR) && !PCFTEST(PCF_UIO)) /* Standard IO-legal test */ - return i_muuo(op, ac, e); - - w = vm_read(e); - pa = ((paddr_t)LHGET(w)<<18) | RHGET(w); - if (pa >= ((paddr_t)PAG_MAXPHYSPGS << PAG_BITS)) { - /* Non-ex phys mem ref, do page-fail */ - pag_nxmfail(pa, VMF_WRITE, "PMOVEM NXM"); - /* If no trap, just do nothing */ - } else - vm_pset(vm_physmap(pa), ac_get(ac)); /* Store AC in c(PA) */ - - return PCINC_1; -} - -#endif /* KLH10_CPU_KLX */ - - -/* PAG_NXMFAIL - Handle physical memory map NXM error, eg if paging off. -** -** What to do if something like PMOVE/M references non-existent phys memory? -** There's no doc that says anything about this. -** What I'll do here is take a page failure trap of type PMF_NXMERR, which -** is the right thing on the KS and seems close enough on the KL. -** The APR bits set differ, however. -** Based on the MCA25 doc (p.A-8), bit 0 is also set if in user mode. -** See T20 pag_refill() for similar code. -** Note: for KL with KI paging, the DFKDA diagnostic expects code 36, -** "AR Parity", for a NXM error. -*/ -static void -pag_nxmfail(paddr_t pa, - pment_t f, /* Access flags */ - char *str) -{ - cpu.pag.pr_fmap = pr_pmap; /* Physical map */ - cpu.pag.pr_facf = f; - cpu.pag.pr_fref = pa; /* Phys failure addr */ - cpu.pag.pr_fstr = str; /* Failure string for debugging */ - -#if KLH10_PAG_ITS /* ITS/KS: just a guess */ - cpu.pag.pr_flh = PF_NXM | PF_PHY | (PCFTEST(PCF_USR) ? PF_USR : 0); -#else /* KS: Non-ex memory, KL: AR parity */ - cpu.pag.pr_flh = PMF_NXMERR | (PCFTEST(PCF_USR) ? PF_USER : 0); -#endif - - cpu.aprf.aprf_set |= -#if KLH10_CPU_KS - APRF_NXM; /* Report as APR flag too (B27) */ -#elif KLH10_CPU_KL - APRF_NXM | APRF_MBPAR; /* KL has different flags */ - cpu.pag.pr_era = pa; /* Also remember phys addr here */ -#endif - - apr_picheck(); /* Maybe set PI (will happen after pagefail) */ - if (cpu.mr_paging) /* If paging, */ - pag_fail(); /* Take page failure trap now! */ - - /* Ugh!! Return to caller, who should carry out some default */ - if (cpu.mr_exsafe) { - pfbeg(); /* Barf about it */ - fprintf(stderr, "Paging OFF, no trap!]\r\n"); - if (cpu.mr_exsafe >= 2) - apr_halt(HALT_EXSAFE); - } -} diff --git a/src/kn10pag.h.old b/src/kn10pag.h.old deleted file mode 100644 index 3e085ca..0000000 --- a/src/kn10pag.h.old +++ /dev/null @@ -1,973 +0,0 @@ -/* KN10PAG.H - Pager state and register definitions -*/ -/* $Id: kn10pag.h,v 2.3 2001/11/10 21:28:59 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: kn10pag.h,v $ - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#ifndef KN10PAG_INCLUDED -#define KN10PAG_INCLUDED 1 - -#ifdef RCSID - RCSID(kn10pag_h,"$Id: kn10pag.h,v 2.3 2001/11/10 21:28:59 klh Exp $") -#endif - -/* Address space definitions, in terms of bits */ - -/* Naming note: -** Use: For: -** PA Physical Address. -** NA "iN-section" or "Normal" 18-bit Address. -** XA full eXtended virt Address (30-bit). -** VA Virtual Address actually supported (18 or 23-bit). -** -** XS full eXtended Section # (12-bit) -** VS Virtual Section # actually supported (5-bit) -*/ - -#ifndef PAG_PABITS /* # bits of address physically available */ -# if KLH10_CPU_KLX -# define PAG_PABITS 22 /* 22 MAX! Can set less for debugging */ -# else -# define PAG_PABITS 19 /* True for KS10 anyway */ -# endif -#endif - -#define PAG_NABITS 18 /* Normal in-section virtual address bits */ -#define PAG_XSBITS 12 /* # bits virtual section possible */ -#define PAG_XABITS 30 /* # virtual bits possible in extended mode (18+12) */ - -#if KLH10_CPU_KLX -# define PAG_VSBITS 5 /* # bits virtual section actually supported */ -# define PAG_MAXBITS PAG_XABITS /* Max address of any kind */ -#else -# define PAG_VSBITS 0 /* # bits virtual section actually supported */ -# define PAG_MAXBITS PAG_PABITS /* Max address of any kind */ -#endif - - /* # virtual address bits actually supported! (18 or 23) */ -#define PAG_VABITS (PAG_VSBITS+PAG_NABITS) - - -#if KLH10_PAG_ITS -# define PAG_BITS 10 /* # bits of address encompassed by a page */ -#else -# define PAG_BITS 9 -#endif - -#define PAG_VMFBITS 2 /* # of access bits needed in page table */ - /* (See VMF_ flags) */ - -/* The remaining definitions are more or less all derived -** from the above parameters. -** Note some of the defs should be unsigned but aren't, as they are -** used in some #if tests and some preprocs don't like 1UL. -** Still guaranteed positive since long is >= 32 bits. -*/ - -/* Max # of pages the KLH10 emulates in physical memory. -*/ -#ifndef PAG_MAXPHYSPGS -# define PAG_MAXPHYSPGS (1L<<(PAG_PABITS-PAG_BITS)) -#endif - -/* Max # of virtual pages this pager will support. -*/ -#define PAG_MAXVIRTPGS (1L<<(PAG_VABITS-PAG_BITS)) - -/* # bits needed in a page table entry. -** Only have to support available phys mem. -*/ -#define PAG_PMEBITS (PAG_VMFBITS+PAG_PABITS-PAG_BITS) - - -/* Now declare three types: -** paddr_t - fast type big enough to hold the biggest phys/virt address. -** pagno_t - fast type big enough to hold a physical page #. -** pment_t - compact type for holding a hardware page table entry. -** -** For explanation of the #if tests, see similar code in word10.h that -** defines WORD10_INT18. -*/ -#ifndef INT_MAX -# include -#endif - -/* paddr_t - Physical address (always integral type) -** This is a macro instead of the typedef it should be, because -** on some Nazi U-boxes it is cleverly typedefed in , and -** C has no way to undefine (or even test) for such things. -*/ -#ifndef KLH10_PADDR_T /* Permit compile-time override */ -# if (INT_MAX > (1L<<(PAG_MAXBITS-2))) -# define KLH10_PADDR_T int /* Assume int is fastest if it's big enough */ -# else -# define KLH10_PADDR_T long -# endif -#endif -/* typedef unsigned KLH10_PADDR_T paddr_t; */ -#define paddr_t unsigned KLH10_PADDR_T - -#ifndef KLH10_PAGNO_T /* Permit compile-time override */ -# if (INT_MAX > (PAG_MAXPHYSPGS>>2)) -# define KLH10_PAGNO_T int -# else -# define KLH10_PAGNO_T long -# endif -#endif - typedef unsigned KLH10_PAGNO_T pagno_t; - -#ifndef KLH10_PMENT_T /* Permit compile-time override */ -# if (SHRT_MAX > (1L<<(PAG_PMEBITS-2))) -# define KLH10_PMENT_T short -# elif (INT_MAX > (1L<<(PAG_PMEBITS-2))) -# define KLH10_PMENT_T int -# else -# define KLH10_PMENT_T long -# endif -#endif - typedef unsigned KLH10_PMENT_T pment_t; - - -#define PAG_SIZE (1<>PAG_BITS)&PAG_PAMSK) /* Phy to page */ -#define pag_pgtopa(p) (((paddr_t)(p)) << PAG_BITS) /* Page to phy */ - -/* To extract page # from given virtual address, -** see va_page(va) and va_xapage(va). -*/ - -/* Virtual Address Facilities (includes EA calculation) -** -** vaddr_t is the object type used to store a full PDP-10 -** virtual address. This is NOT the same as a physical -** address and may not even be an integral type. -** -** Both extended and non-extended definitions are integrated here. -** There are complicated enough however that perhaps a separate file -** would be a good idea (vaddr.h?). -*/ - - typedef int32 vaddr_t; /* Later make unsigned */ - typedef int32 vaint_t; /* For future code */ - typedef uint32 vauint_t; - -#if !KLH10_EXTADR - -# define va_lh(va) ((va) >> H10BITS) -# define va_ac(va) ((va) & AC_MASK) -# define va_sect(va) (0) -# define va_sectf(va) (0) -# define va_insect(va) ((va) & H10MASK) -# define va_pagoff(va) ((va) & PAG_MASK) /* Get offset within page */ -# define va_page(va) ((pagno_t)((va)>>PAG_BITS)&PAG_VAMSK) /* Get page # */ -# define va_xapage(va) ((pagno_t)((va)>>PAG_BITS)&PAG_XAMSK) /* FULL page!! */ -# define va_30(va) (va) - -# define va_ladd(va,n) ((va) = ((va)+(n))&H10MASK) -# define va_linc(va) va_ladd(va,1) /* Local increment by 1 */ -# define va_add(va,n) va_ladd(va,n) /* General same as local */ -# define va_inc(va) va_linc(va) /* Ditto */ -# define va_dec(va) va_ladd(va,-1) - -# define va_lmake(va, s, n) ((va) = (n)) -# define va_gmake(va, s, n) ((va) = (n)) -# define va_lmake30(va, pa) ((va) = (pa)) -# define va_hmake(va, lh, rh) ((va) = ((lh)<>1)) -#define VAF_GLOBAL VAF_LGFLAG -#define VAF_LOCAL 0 - -#define VAF_NBITS PAG_NABITS /* 18 bits in-section */ -#define VAF_SBITS PAG_XSBITS /* 12 bits section # */ - /* (Even though pager may only support 5) */ -#define VAF_VSBITS PAG_VSBITS /* # bits virtual section possible */ -#define VAF_SPOS VAF_NBITS - -#define VAF_SMSK (((vauint_t)1<> H10BITS)&H10MASK) -# define va_ac(va) ((va) & AC_MASK) -# define va_sect(va) (((va)>>VAF_SPOS)&VAF_SMSK) -# define va_sectf(va) ((va) & VAF_SFLD) -# define va_insect(va) ((va) & H10MASK) -# define va_pagoff(va) ((va) & PAG_MASK) /* Get offset within page */ -# define va_page(va) ((pagno_t)((va)>>PAG_BITS)&PAG_VAMSK) /* Get page # */ -# define va_xapage(va) ((pagno_t)((va)>>PAG_BITS)&PAG_XAMSK) /* FULL page!! */ -# define va_30(va) ((va) & VAF_30MSK) - -# define va_ladd(va,n) ((va) = (((va)&~VAF_NFLD)|(((va)+(n))&VAF_NFLD))) -# define va_linc(va) va_ladd(va,1) /* Local increment by 1 */ -# define va_add(va,n) (va_islocal(va) ? va_ladd(va,n) : va_gadd(va,n)) -# define va_inc(va) (va_islocal(va) ? va_linc(va) : va_ginc(va)) -# define va_dec(va) (va_islocal(va) ? va_ladd(va,-1) : va_gadd(va,-1)) - -# define va_lmake(va, s, n) ((va) = ((s)< User low mem ( 0-377777) - DBR2 -> User high (400000-777777) - DBR3 -> EXEC high - DBR4 -> EXEC low (didn't exist on KA-10s) -*/ - -/* Page table entry format */ -#define PM_29 0400000 /* Bit 2.9 of ITS map entry halfword */ -#define PM_28 0200000 /* Bit 2.8 */ - -#define PM_ACC (PM_29|PM_28) /* Mask for ITS access bits: */ - /* Note: h/w treats RWF the same as RO. */ -#define PM_ACCNON ((h10_t)00<<16) /* 00 - invalid, inaccessible */ -#define PM_ACCRO ((h10_t)01<<16) /* 01 - Read Only */ -#define PM_ACCRWF ((h10_t)02<<16) /* 10 - Read/Write/First (== RO) */ -#define PM_ACCRW ((h10_t)03<<16) /* 11 - Read/Write */ - -#define PM_AGE 020000 /* Age bit */ -#define PM_CSH 010000 /* Cache enable bit */ -#define PM_PAG PAG_PAMSK /* Physical ITS page number (max 1777?) */ -#if (PM_PAG & PM_CSH) - * ERROR * "ITS page number field too large" -#endif - - -/* Format of ITS page fail word */ -#define PF_USR 0400000 /* 4.9 Indicates user address space. */ -#define PF_NXI 0200000 /* 4.8 Nonexistent IO register. */ -#define PF_NXM 0100000 /* 4.7 Nonexistent memory. */ -#define PF_PAR 0040000 /* 4.6 Uncorrectable memory error. */ - /* (AC0 in block 7 has the word unless 4.7 is */ - /* also set.) */ - /* 4.5 unused */ -#define PF_WRT 0010000 /* 4.4 Soft fault reference called for writing. */ -#define PF_29 004000 /* 4.3 - 4.2 Access bits for referenced page in soft */ -#define PF_28 002000 /* fault. (from 2.9 & 2.8 of page entry) */ -#define PF_PHY 0001000 /* 4.1 Address given was physical. */ - /* 3.9 unused */ -#define PF_IO 0000200 /* 3.8 Indicates an IO operation. */ - /* 3.7-3.6 unused */ -#define PF_BYT 0000020 /* 3.5 Indicates a byte IO operation. */ - /* 3.4 - 1.1 IO address */ - /* or */ - /* 3.1 - 1.1 Memory address */ -#define PF_PNO 0776000 /* 2.9 - 2.2 Virtual page number */ - - -/* Format of the area read and written by LPMR, SPM: */ -#define LPMR_DBR1 0 /* User low DBR */ -#define LPMR_DBR2 1 /* User high DBR */ -#define LPMR_QUANT 2 /* Quantum timer */ -#define LPMR_UJPC 3 /* User JPC (if supported) */ -#define LPMR_EJPC 4 /* Exec JPC (if supported) */ - -/* The quantum timer appears to be incremented approximately every -** millisecond (2^12 the KS10 internal clock rate) whenever -** not holding an interrupt (ie no PI in progress). -*/ - -/* Paging register variables */ -struct pagregs { - int32 pr_dbr1, pr_dbr2, pr_dbr3, pr_dbr4; /* DBR regs */ - int32 pr_quant; - vaddr_t pr_ujpc, pr_ejpc; - - /* Common to all systems */ - h10_t pr_flh; /* Fail word LH bits */ - paddr_t pr_fref; /* Failing virtual/physical address */ - char *pr_fstr; /* Failure reason (for debugging) */ - pment_t *pr_fmap; /* Failing map pointer */ - h10_t pr_facf; /* Failing ref access bits */ -}; -#endif /* ITS */ - -/* T10 (KI) Pager definitions */ - -#if KLH10_PAG_KI - -/* Page table entry format */ -#define PM_ACC 0400000 /* B0 - Access allowed (R or RW) */ -#define PM_PUB 0200000 /* B1 - Public (not used in KS10) */ -#define PM_WRT 0100000 /* B2 - Writable */ -#define PM_SFT 0040000 /* B3 - Software (not used by page refill) */ -#define PM_CSH 0020000 /* B4 - Cacheable */ -#define PM_PAG 0017777 /* Physical DEC page number - 13 bits */ -#if (PM_PAG < PAG_PAMSK) - /*#*/ * ERROR * "T10 page number field too small" -#endif - -/* Page fail bits as returned by MAP or page failure trap */ -#define PF_USER ((h10_t)1<<17) /* B0 - User space reference (else exec) */ -#define PF_HARD ((h10_t)1<<16) /* B1 - Hardware or IO failure (else soft) */ -#define PF_ACC ((h10_t)1<<15) /* B2 - 'Access' bit from page map entry */ -#define PF_WRT (1<<14) /* B3 - 'Writable' bit from page map entry */ -#define PF_SFT (1<<13) /* B4 - 'Soft' bit from page map entry */ -#define PF_WREF (1<<12) /* B5 - Reference was write */ -#define PF_PUB (1<<11) /* B6 - 'Public' bit from refill eval */ -#define PF_CSH (1<<10) /* B7 - 'Cacheable' bit from refill eval */ -#define PF_VIRT (1<<9) /* B8 - Physical or Virtual reference */ - /* (1<<8) */ /* B9 - */ -#define PF_IOREF (1<<7) /* B10 - IO Bus reference */ - /* (1<<6) (1<<5) */ /* B11,B12 - */ -#define PF_IOBYTE (1<<4) /* B13 - Byte mode in failing IO ref */ - -#if KLH10_CPU_KL /* Sufficient for now, later merge */ -# define PMF_IIERR ((h10_t)024<<12) /* Illegal Indirect (EFIW) */ -# define PMF_NXMERR ((h10_t)036<<12) /* AR parity error (pretend NXM) */ -#endif /* DFKDA diag expects this */ - - -struct pagregs { -#if KLH10_CPU_KL - int pr_pcs; /* Previous Context Section */ - paddr_t pr_pcsf; /* PCS, shifted into field position */ - paddr_t pr_era; /* Error Address Register */ -#endif /* KL */ - - paddr_t pr_physnxm; /* 1st physical NXM address */ - - /* Common to all systems */ - h10_t pr_flh; /* Page fail code, or refill access bits */ - paddr_t pr_fref; /* If phys failure, holds phys addr of ref */ - char *pr_fstr; /* Failure string for debugging */ - pment_t *pr_fmap; /* Failing hardware map pointer */ - h10_t pr_facf; /* Failing ref access bits */ -}; - -#endif /* KLH10_PAG_KI */ - -/* T20 (KL) Pager definitions */ - -#if KLH10_PAG_KL - -/* Bits for page map entry LH as returned by MAP or page failure. -** Source for this is DEC PRM p.4-26 to p.4-28. -** Same bits for KL, PRM p.3-40. -*/ -#define PF_USER ((h10_t)1<<17) /* B0 U - User space reference (else exec) */ -#define PF_HARD ((h10_t)1<<16) /* B1 H - Hardware or IO failure (else soft) */ -#define PF_ACC (1<<15) /* B2 A - Accessible, refill eval completed */ -#define PF_MOD (1<<14) /* B3 M - 'Modified' bit from h/w page table */ -#define PF_WRT (1<<13) /* B4 S - 'Writable' bit from refill eval */ -#define PF_WREF (1<<12) /* B5 T - Reference was write */ -#define PF_PUB (1<<11) /* B6 P - 'Public' bit from refill eval */ -#define PF_CSH (1<<10) /* B7 C - 'Cacheable' bit from refill eval */ -#define PF_VIRT (1<<9) /* B8 V - Physical or Virtual reference */ -#if KLH10_MCA25 -# define PF_KEEP (1<<9) /* B8 K - Keep page during WRUBR */ -#endif - -#if KLH10_CPU_KS - /* (1<<8) */ -# define PF_IOREF (1<<7) /* B10 - IO Bus reference */ - /* (1<<6) (1<<5) */ -# define PF_IOBYTE (1<<4) /* B13 - Byte mode in failing IO ref */ -#endif /* KS */ - -/* Special hardware failure codes in high 6 bits. */ -#if KLH10_CPU_KS -# define PMF_PARERR ((h10_t)036<<12) /* Uncorrectable memory error */ -# define PMF_NXMERR ((h10_t)037<<12) /* Nonexistent memory */ -# define PMF_IOERR ((h10_t)020<<12) /* Nonexistent IO register */ -#elif KLH10_CPU_KL -# define PMF_PUBERR ((h10_t)021<<12) /* Proprietary violation */ -# define PMF_ADRERR ((h10_t)023<<12) /* Address break */ -# define PMF_IIERR ((h10_t)024<<12) /* Illegal Indirect (EFIW) */ -# define PMF_PGTERR ((h10_t)025<<12) /* Page table parity error */ -# define PMF_ISCERR ((h10_t)027<<12) /* Illegal Address (sect > 037) */ -# define PMF_NXMERR ((h10_t)036<<12) /* AR parity error (pretend NXM) */ -# define PMF_ARXERR ((h10_t)037<<12) /* ARX parity error */ -#endif -#define PMF_WRTERR ((h10_t)011<<12) /* Write violation (soft) */ -#define PMF_OTHERR ((h10_t)000<<12) /* Random inaccessibility (soft) */ - -/* Section and Map pointer format */ -#define PT_PACC (1<<14) /* B3 - 'P' bit, public */ -#define PT_WACC (1<<13) /* B4 - 'W' bit, writeable */ -#define PT_KEEP (1<<12) /* B5 - 'K' bit, Keep (KL MCA25) */ -#define PT_CACHE (1<<11) /* B6 - 'C' bit, cacheable */ -#define PT_TYPE ((h10_t)07<<15) /* High 3 bits are pointer type */ -#define PTT_NOACC 0 /* Inaccessible pointer */ -#define PTT_IMMED 1 /* Immediate pointer (see SPT fields) */ -#define PTT_SHARED 2 /* Shared pointer */ - /* RH: Index into SPT */ -#define PTT_INDIRECT 3 /* Indirect pointer */ -#define PT_IIDX 0777 /* LH: B9-17 Next index */ - /* RH: Index into SPT (like shared) */ - -/* Format of SPT (Special Page Table) entries. -** The "Page Address" defined here is also used in -** immediate section/map pointers (type PTT_IMMED). -*/ -#define SPT_MDM 077 /* LH: B12-17 Storage medium (0=mem) */ -#define SPT_RSVD 0760000 /* RH: B18-22 Reserved */ -#define SPT_PGN 0017777 /* RH: B23-35 Page Number */ - -/* Format of CST (Core Status Table) entry. -** There is one entry for every physical page on the machine. -*/ -#define CST_AGE 0770000 /* LH: Page age - if zero, trap on ref. */ -#define CST_HWBITS 017 /* RH: Hardware bits, s/w shouldn't hack */ -#define CST_MBIT 01 /* RH: referenced page modified */ - -/* Paging registers -** Note that on the KL the "registers" are stored in AC block 6. -** Assumption is that this is NEVER the current ac block; known -** to be true for T20 monitor at least. -*/ -struct pagregs { -#if KLH10_CPU_KS - paddr_t pr_spb; /* SPT Base address (not aligned, unknown size) */ - paddr_t pr_csb; /* CST Base address (not aligned, # = phys pages) */ - w10_t pr_cstm; /* CST Mask word */ - w10_t pr_pur; /* CST Process Use Register */ -# define PAG_PR_SPBPA cpu.pag.pr_spb -# define PAG_PR_CSBPA cpu.pag.pr_csb -# define PAG_PR_CSTMWD cpu.pag.pr_cstm -# define PAG_PR_PURWD cpu.pag.pr_pur -#elif KLH10_CPU_KL -# define PAG_PR_SPB (cpu.acblks[6][3]) -# define PAG_PR_CSB (cpu.acblks[6][2]) -# define PAG_PR_SPBPA (((paddr_t)LHGET(PAG_PR_SPB)<<18) \ - | RHGET(PAG_PR_SPB)) -# define PAG_PR_CSBPA (((paddr_t)LHGET(PAG_PR_CSB)<<18) \ - | RHGET(PAG_PR_CSB)) -# define PAG_PR_CSTMWD (cpu.acblks[6][0]) -# define PAG_PR_PURWD (cpu.acblks[6][1]) - int pr_pcs; /* Previous Context Section */ - paddr_t pr_pcsf; /* PCS, shifted into field position */ - paddr_t pr_era; /* Error Address Register */ -#endif /* KL */ - - paddr_t pr_physnxm; /* 1st physical NXM address */ - - /* Common to all systems */ - h10_t pr_flh; /* Page fail code, or refill access bits */ - paddr_t pr_fref; /* If phys failure, holds phys addr of ref */ - char *pr_fstr; /* Failure string for debugging */ - pment_t *pr_fmap; /* Failing map pointer */ - h10_t pr_facf; /* Failing ref access bits */ -}; - -#endif /* KLH10_PAG_KL */ - -#if KLH10_CPU_KL -# define pag_pcsget() cpu.pag.pr_pcs -# define pag_pcsfget() cpu.pag.pr_pcsf -# define pag_pcsset(s) (cpu.pag.pr_pcsf = ((paddr_t)(s)<<18),\ - cpu.pag.pr_pcs = (s)) -#endif - -/* Pager function declarations - exported from kn10pag.c */ - -extern void pag_init(void); /* Initialize pager stuff */ - - /* Called if vm_xmap mapping macros fail. Refill, trap if page-fail */ -extern vmptr_t pag_refill(pment_t *, vaddr_t, pment_t); - -extern void pag_fail(void); /* Effect page-fail trap */ - -#if KLH10_CPU_KS -extern void pag_iofail(paddr_t, int); /* PF trap for IO unibus ref */ -#endif - -#if KLH10_EXTADR /* PF trap for Illegal-Indirect ref */ -extern void pag_iifail(vaddr_t, pment_t *); -extern void pag_iiset(vaddr_t, pment_t *); /* Set up vars for above */ -#endif - -#endif /* ifndef KN10PAG_INCLUDED */ diff --git a/src/opcods.h.old b/src/opcods.h.old deleted file mode 100644 index 0e8985a..0000000 --- a/src/opcods.h.old +++ /dev/null @@ -1,797 +0,0 @@ -/* OPCODS.H - Definitions of all PDP-10 instruction opcodes -*/ -/* $Id: opcods.h,v 2.4 2002/05/21 16:54:32 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: opcods.h,v $ - * Revision 2.4 2002/05/21 16:54:32 klh - * Add KLH10_I_CIRC to allow any sys to have CIRC - * - * Revision 2.3 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#ifndef OPCODS_RCSID -# define OPCODS_RCSID \ - RCSID(opcods_h,"$Id: opcods.h,v 2.4 2002/05/21 16:54:32 klh Exp $") -#endif - -/* This file is intended to be included multiple times, always within -** a specific context that defines the macros "idef", "ixdef", and "iodef" -** suitably so as to declare or define various parts of the bindings -** represented in this file. -** -** Normal instructions are defined with: -** idef(opval, name, enum, rtn, flags) -** -** and EXTEND opcodes are defined with: -** ixdef(xopval, name, enum, rtn, flags) -** -** IO instructions (with internal or external devices) are -** defined with: -** iodef(iocod, name, enum, rtn, flags) -** where "iocod" is built with IOINOP or IOEXOP. -** -** Operations not specified here are all initialized at startup to -** an appropriate default value, usually "i_muuo" so the monitor -** can handle them. -** Only one opcode is truly illegal: 0 in EXEC mode, which currently -** stops the KLH10 rather than trapping. To change this, -** remove the definition for "ILLEG". -*/ - -idef(000, "ILLEG", I_ILLEG, i_illegal, IF_SPEC) -idef(001, "LUUO", I_LUUO, i_luuo, IF_OPN|IF_1X1) /* 001-037 inclusive */ -idef(040, "MUUO", I_MUUO, i_muuo, IF_OPN|IF_1X1) /* all others */ - -/* Opcodes 040-0101 inclusive default to i_muuo */ - - /* Late KL additions, note opcodes formerly UUOs "reserved for DEC" */ -#if KLH10_CPU_KLX - idef(052, "PMOVE", I_PMOVE, i_pmove, IF_1S) /* KL PMOVE */ - idef(053, "PMOVEM",I_PMOVEM,i_pmovem,IF_1SM) /* KL PMOVEM */ -#endif - -#if KLH10_SYS_ITS /* ITS pager XCT */ - idef(0102, "XCTRI", I_XCTRI, i_pxct, IF_SPEC|IF_MR|IF_MIN) - idef(0103, "XCTR", I_XCTR, i_pxct, IF_SPEC|IF_MR|IF_MIN) -#elif KLH10_CPU_KL - idef(0102, "GFAD", I_GFAD, i_gfad, IF_2X) /* KL GFAD */ - idef(0103, "GFSB", I_GFSB, i_gfsb, IF_2X) /* KL GFSB */ -#endif - -#if KLH10_SYS_T10 || KLH10_SYS_T20 - idef(0104, "JSYS", I_JSYS, i_muuo, IF_ME) /* BBN PAGER INSTRUCTION */ -#endif -#if KLH10_CPU_KS || KLH10_CPU_KL - idef(0105, "ADJSP", I_ADJSP, i_adjsp, IF_1XI) /* KL/KS */ -#endif -#if KLH10_CPU_KL - idef(0106, "GFMP", I_GFMP, i_gfmp, IF_2X) /* KL GFMP */ - idef(0107, "GFDV", I_GFDV, i_gfdv, IF_2X) /* KL GFDV */ -#endif -#if !KLH10_CPU_KA - idef(0110, "DFAD", I_DFAD, i_dfad, IF_2X) /* KI+ */ - idef(0111, "DFSB", I_DFSB, i_dfsb, IF_2X) /* KI+ */ - idef(0112, "DFMP", I_DFMP, i_dfmp, IF_2X) /* KI+ */ - idef(0113, "DFDV", I_DFDV, i_dfdv, IF_2X) /* KI+ */ -# if KLH10_CPU_KS || KLH10_CPU_KL - idef(0114, "DADD", I_DADD, i_dadd, IF_2X) /* KL/KS */ - idef(0115, "DSUB", I_DSUB, i_dsub, IF_2X) /* KL/KS */ - idef(0116, "DMUL", I_DMUL, i_dmul, IF_AS|IF_A4|IF_MR|IF_M2) /* KL/KS */ - idef(0117, "DDIV", I_DDIV, i_ddiv, IF_AS|IF_A4|IF_MR|IF_M2) /* KL/KS */ -# endif /* KL/KS */ - idef(0120, "DMOVE", I_DMOVE, i_dmove, IF_2S) /* KI+ */ - idef(0121, "DMOVN", I_DMOVN, i_dmovn, IF_2S) /* KI+ */ - idef(0122, "FIX", I_FIX, i_fix, IF_1S) /* KI+ */ -# if KLH10_CPU_KS || KLH10_CPU_KL - idef(0123,"EXTEND",I_EXTEND,i_extend,IF_SPEC|IF_AS|IF_A4|IF_MR|IF_M1) /* KL/KS */ -# endif /* KL/KS */ - idef(0124, "DMOVEM",I_DMOVEM,i_dmovem, IF_2SM) /* KI+ */ - idef(0125, "DMOVNM",I_DMOVNM,i_dmovnm, IF_2SM) /* KI+ */ - idef(0126, "FIXR", I_FIXR, i_fixr, IF_1S) /* KI+ */ - idef(0127, "FLTR", I_FLTR, i_fltr, IF_1S) /* KI+ */ -#endif /* !KA */ -idef(0130, "UFA", I_UFA, i_ufa, IF_AS|IF_A2|IF_MR|IF_M1) /* KA/KI */ -idef(0131, "DFN", I_DFN, i_dfn, IF_1XB) /* KA/KI only */ -idef(0132, "FSC", I_FSC, i_fsc, IF_1XI) -idef(0133, "IBP", I_IBP, i_ibp, IF_AS|IF_A0|IF_MS|IF_M1) -idef(0134, "ILDB", I_ILDB, i_ildb, IF_AW|IF_A1|IF_MS|IF_M1) -idef(0135, "LDB", I_LDB, i_ldb, IF_AW|IF_A1|IF_MR|IF_M1) -idef(0136, "IDPB", I_IDPB, i_idpb, IF_AR|IF_A1|IF_MS|IF_M1) -idef(0137, "DPB", I_DPB, i_dpb, IF_AR|IF_A1|IF_MS|IF_M1) -idef(0140, "FAD", I_FAD, i_fad, IF_1X) -idef(0141, "FADL", I_FADL, i_fadl, IF_1XFL) /* PDP6/KA/KI (not KL/KS) */ -idef(0142, "FADM", I_FADM, i_fadm, IF_1XM) -idef(0143, "FADB", I_FADB, i_fadb, IF_1XB) -idef(0144, "FADR", I_FADR, i_fadr, IF_1X) -idef(0145, "FADRI", I_FADRI, i_fadri, IF_1XFI) /* KA+ INSTR (PDP6: FADRL) */ -idef(0146, "FADRM", I_FADRM, i_fadrm, IF_1XM) -idef(0147, "FADRB", I_FADRB, i_fadrb, IF_1XB) -idef(0150, "FSB", I_FSB, i_fsb, IF_1X) -idef(0151, "FSBL", I_FSBL, i_fsbl, IF_1XFL) /* PDP6/KA/KI (not KL/KS) */ -idef(0152, "FSBM", I_FSBM, i_fsbm, IF_1XM) -idef(0153, "FSBB", I_FSBB, i_fsbb, IF_1XB) -idef(0154, "FSBR", I_FSBR, i_fsbr, IF_1X) -idef(0155, "FSBRI", I_FSBRI, i_fsbri, IF_1XFI) /* KA+ INSTR (PDP6: FSBRL) */ -idef(0156, "FSBRM", I_FSBRM, i_fsbrm, IF_1XM) -idef(0157, "FSBRB", I_FSBRB, i_fsbrb, IF_1XB) -idef(0160, "FMP", I_FMP, i_fmp, IF_1X) -idef(0161, "FMPL", I_FMPL, i_fmpl, IF_1XFL) /* PDP6/KA/KI (not KL/KS) */ -idef(0162, "FMPM", I_FMPM, i_fmpm, IF_1XM) -idef(0163, "FMPB", I_FMPB, i_fmpb, IF_1XB) -idef(0164, "FMPR", I_FMPR, i_fmpr, IF_1X) -idef(0165, "FMPRI", I_FMPRI, i_fmpri, IF_1XFI) /* KA+ INSTR (PDP6: FMPRL) */ -idef(0166, "FMPRM", I_FMPRM, i_fmprm, IF_1XM) -idef(0167, "FMPRB", I_FMPRB, i_fmprb, IF_1XB) -idef(0170, "FDV", I_FDV, i_fdv, IF_1X) -idef(0171, "FDVL", I_FDVL, i_fdvl, IF_1XFL) /* PDP6/KA/KI (not KL/KS) */ -idef(0172, "FDVM", I_FDVM, i_fdvm, IF_1XM) -idef(0173, "FDVB", I_FDVB, i_fdvb, IF_1XB) -idef(0174, "FDVR", I_FDVR, i_fdvr, IF_1X) -idef(0175, "FDVRI", I_FDVRI, i_fdvri, IF_1XFI) /* KA+ INSTR (PDP6: FDVRL) */ -idef(0176, "FDVRM", I_FDVRM, i_fdvrm, IF_1XM) -idef(0177, "FDVRB", I_FDVRB, i_fdvrb, IF_1XB) - - /* ; 200-277 (MOVE - SUBB) */ -idef(0200, "MOVE", I_MOVE, i_move, IF_1S) -idef(0201, "MOVEI", I_MOVEI, i_movei, IF_1SI) -idef(0202, "MOVEM", I_MOVEM, i_movem, IF_1SM) -idef(0203, "MOVES", I_MOVES, i_moves, IF_1SS) -idef(0204, "MOVS", I_MOVS, i_movs, IF_1S) -idef(0205, "MOVSI", I_MOVSI, i_movsi, IF_1SI) -idef(0206, "MOVSM", I_MOVSM, i_movsm, IF_1SM) -idef(0207, "MOVSS", I_MOVSS, i_movss, IF_1SS) -idef(0210, "MOVN", I_MOVN, i_movn, IF_1S) -idef(0211, "MOVNI", I_MOVNI, i_movni, IF_1SI) -idef(0212, "MOVNM", I_MOVNM, i_movnm, IF_1SM) -idef(0213, "MOVNS", I_MOVNS, i_movns, IF_1SS) -idef(0214, "MOVM", I_MOVM, i_movm, IF_1S) -idef(0215, "MOVMI", I_MOVMI, i_movei, IF_1SI) /* Same as MOVEI */ -idef(0216, "MOVMM", I_MOVMM, i_movmm, IF_1SM) -idef(0217, "MOVMS", I_MOVMS, i_movms, IF_1SS) -idef(0220, "IMUL", I_IMUL, i_imul, IF_1X) -idef(0221, "IMULI", I_IMULI, i_imuli, IF_1XI) -idef(0222, "IMULM", I_IMULM, i_imulm, IF_1XM) -idef(0223, "IMULB", I_IMULB, i_imulb, IF_1XB) -idef(0224, "MUL", I_MUL, i_mul, IF_AS|IF_A2|IF_X1) -idef(0225, "MULI", I_MULI, i_muli, IF_AS|IF_A2|IF_XI) -idef(0226, "MULM", I_MULM, i_mulm, IF_1XM) -idef(0227, "MULB", I_MULB, i_mulb, IF_AS|IF_A2|IF_MS|IF_M1) -idef(0230, "IDIV", I_IDIV, i_idiv, IF_AS|IF_A2|IF_X1) -idef(0231, "IDIVI", I_IDIVI, i_idivi, IF_AS|IF_A2|IF_XI) -idef(0232, "IDIVM", I_IDIVM, i_idivm, IF_AR|IF_A1|IF_MS|IF_M1) -idef(0233, "IDIVB", I_IDIVB, i_idivb, IF_AS|IF_A2|IF_MS|IF_M1) -idef(0234, "DIV", I_DIV, i_div, IF_AS|IF_A2|IF_X1) -idef(0235, "DIVI", I_DIVI, i_divi, IF_AS|IF_A2|IF_XI) -idef(0236, "DIVM", I_DIVM, i_divm, IF_AR|IF_A1|IF_MS|IF_M1) -idef(0237, "DIVB", I_DIVB, i_divb, IF_AS|IF_A2|IF_MS|IF_M1) -idef(0240, "ASH", I_ASH, i_ash, IF_AS|IF_A1|IF_ME8) -idef(0241, "ROT", I_ROT, i_rot, IF_AS|IF_A1|IF_ME8) -idef(0242, "LSH", I_LSH, i_lsh, IF_AS|IF_A1|IF_ME8) -idef(0243, "JFFO", I_JFFO, i_jffo, IF_AR|IF_A1|IF_ME|IF_JMP) /* KA+ */ -idef(0244, "ASHC", I_ASHC, i_ashc, IF_AR|IF_A2|IF_ME8) -idef(0245, "ROTC", I_ROTC, i_rotc, IF_AR|IF_A2|IF_ME8) -idef(0246, "LSHC", I_LSHC, i_lshc, IF_AR|IF_A2|IF_ME8) - -#if KLH10_I_CIRC /* AI-KA and KL/KS: ROTC WITH AC+1 GOING THE WRONG WAY */ - idef(0247, "CIRC", I_CIRC, i_circ, IF_AR|IF_A2|IF_ME8) -#endif -idef(0250, "EXCH", I_EXCH, i_exch, IF_1XB) -idef(0251, "BLT", I_BLT, i_blt, IF_SPEC|IF_1XB) -idef(0252, "AOBJP", I_AOBJP, i_aobjp, IF_AS|IF_A1|IF_ME|IF_JMP) -idef(0253, "AOBJN", I_AOBJN, i_aobjn, IF_AS|IF_A1|IF_ME|IF_JMP) -idef(0254, "JRST", I_JRST, i_jrst, IF_SPEC|IF_ME|IF_JMP) -idef(0255, "JFCL", I_JFCL, i_jfcl, IF_SPEC|IF_ME|IF_JMP) -idef(0256, "XCT", I_XCT, i_xct, IF_SPEC|IF_MR|IF_MIN) -#if !KLH10_CPU_KA && (KLH10_PAG_KI || KLH10_PAG_KL) - idef(0257, "MAP", I_MAP, i_map, IF_1C|IF_X1) /* KI+ (DEC pager) */ -#endif -idef(0260, "PUSHJ", I_PUSHJ, i_pushj, IF_SPEC|IF_1C|IF_ME|IF_JMP) -idef(0261, "PUSH", I_PUSH, i_push, IF_SPEC|IF_1X) -idef(0262, "POP", I_POP, i_pop, IF_SPEC|IF_AS|IF_A1|IF_MW|IF_M1) -idef(0263, "POPJ", I_POPJ, i_popj, IF_SPEC|IF_AS|IF_A1|IF_ME|IF_JMP) -idef(0264, "JSR", I_JSR, i_jsr, IF_MW|IF_M1|IF_JMP) -idef(0265, "JSP", I_JSP, i_jsp, IF_1C|IF_ME|IF_JMP) -idef(0266, "JSA", I_JSA, i_jsa, IF_AS|IF_A1|IF_MW|IF_M1|IF_JMP) -idef(0267, "JRA", I_JRA, i_jra, IF_SPEC|IF_AS|IF_A1|IF_ME|IF_JMP) -idef(0270, "ADD", I_ADD, i_add, IF_1X) -idef(0271, "ADDI", I_ADDI, i_addi, IF_1XI) -idef(0272, "ADDM", I_ADDM, i_addm, IF_1XM) -idef(0273, "ADDB", I_ADDB, i_addb, IF_1XB) -idef(0274, "SUB", I_SUB, i_sub, IF_1X) -idef(0275, "SUBI", I_SUBI, i_subi, IF_1XI) -idef(0276, "SUBM", I_SUBM, i_subm, IF_1XM) -idef(0277, "SUBB", I_SUBB, i_subb, IF_1XB) - - /* ; 300-377 (CAI - SOSG) */ -idef(0300, "CAI", I_CAI, i_cai, IF_NOP) -idef(0301, "CAIL", I_CAIL, i_cail, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0302, "CAIE", I_CAIE, i_caie, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0303, "CAILE", I_CAILE, i_caile, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0304, "CAIA", I_CAIA, i_caia, IF_SKP) -idef(0305, "CAIGE", I_CAIGE, i_caige, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0306, "CAIN", I_CAIN, i_cain, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0307, "CAIG", I_CAIG, i_caig, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0310, "CAM", I_CAM, i_cam, IF_MR|IF_M1) -idef(0311, "CAML", I_CAML, i_caml, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0312, "CAME", I_CAME, i_came, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0313, "CAMLE", I_CAMLE, i_camle, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0314, "CAMA", I_CAMA, i_cama, IF_SKP|IF_MR|IF_M1) -idef(0315, "CAMGE", I_CAMGE, i_camge, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0316, "CAMN", I_CAMN, i_camn, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0317, "CAMG", I_CAMG, i_camg, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0320, "JUMP", I_JUMP, i_jump, IF_NOP) -idef(0321, "JUMPL", I_JUMPL, i_jumpl, IF_JMP|IF_AR|IF_A1|IF_ME) -idef(0322, "JUMPE", I_JUMPE, i_jumpe, IF_JMP|IF_AR|IF_A1|IF_ME) -idef(0323, "JUMPLE",I_JUMPLE,i_jumple, IF_JMP|IF_AR|IF_A1|IF_ME) -idef(0324, "JUMPA", I_JUMPA, i_jumpa, IF_JMP|IF_ME) -idef(0325, "JUMPGE",I_JUMPGE,i_jumpge, IF_JMP|IF_AR|IF_A1|IF_ME) -idef(0326, "JUMPN", I_JUMPN, i_jumpn, IF_JMP|IF_AR|IF_A1|IF_ME) -idef(0327, "JUMPG", I_JUMPG, i_jumpg, IF_JMP|IF_AR|IF_A1|IF_ME) -idef(0330, "SKIP", I_SKIP, i_skip, IF_AW|IF_A0|IF_MR|IF_M1) -idef(0331, "SKIPL", I_SKIPL, i_skipl, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0332, "SKIPE", I_SKIPE, i_skipe, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0333, "SKIPLE",I_SKIPLE,i_skiple, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0334, "SKIPA", I_SKIPA, i_skipa, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0335, "SKIPGE",I_SKIPGE,i_skipge, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0336, "SKIPN", I_SKIPN, i_skipn, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0337, "SKIPG", I_SKIPG, i_skipg, IF_SKP|IF_AW|IF_A0|IF_MR|IF_M1) -idef(0340, "AOJ", I_AOJ, i_aoj, IF_AS|IF_A1|IF_ME) -idef(0341, "AOJL", I_AOJL, i_aojl, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0342, "AOJE", I_AOJE, i_aoje, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0343, "AOJLE", I_AOJLE, i_aojle, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0344, "AOJA", I_AOJA, i_aoja, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0345, "AOJGE", I_AOJGE, i_aojge, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0346, "AOJN", I_AOJN, i_aojn, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0347, "AOJG", I_AOJG, i_aojg, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0350, "AOS", I_AOS, i_aos, IF_AW|IF_A0|IF_MS|IF_M1) -idef(0351, "AOSL", I_AOSL, i_aosl, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0352, "AOSE", I_AOSE, i_aose, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0353, "AOSLE", I_AOSLE, i_aosle, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0354, "AOSA", I_AOSA, i_aosa, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0355, "AOSGE", I_AOSGE, i_aosge, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0356, "AOSN", I_AOSN, i_aosn, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0357, "AOSG", I_AOSG, i_aosg, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0360, "SOJ", I_SOJ, i_soj, IF_AS|IF_A1|IF_ME) -idef(0361, "SOJL", I_SOJL, i_sojl, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0362, "SOJE", I_SOJE, i_soje, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0363, "SOJLE", I_SOJLE, i_sojle, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0364, "SOJA", I_SOJA, i_soja, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0365, "SOJGE", I_SOJGE, i_sojge, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0366, "SOJN", I_SOJN, i_sojn, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0367, "SOJG", I_SOJG, i_sojg, IF_JMP|IF_AS|IF_A1|IF_ME) -idef(0370, "SOS", I_SOS, i_sos, IF_AW|IF_A0|IF_MS|IF_M1) -idef(0371, "SOSL", I_SOSL, i_sosl, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0372, "SOSE", I_SOSE, i_sose, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0373, "SOSLE", I_SOSLE, i_sosle, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0374, "SOSA", I_SOSA, i_sosa, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0375, "SOSGE", I_SOSGE, i_sosge, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0376, "SOSN", I_SOSN, i_sosn, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) -idef(0377, "SOSG", I_SOSG, i_sosg, IF_SKP|IF_AW|IF_A0|IF_MS|IF_M1) - - /* ; 400-477 (SETZ - SETOB) */ -idef(0400, "SETZ", I_SETZ, i_setz, IF_1C) -idef(0401, "SETZI", I_SETZI, i_setzi, IF_1C) -idef(0402, "SETZM", I_SETZM, i_setzm, IF_1CM) -idef(0403, "SETZB", I_SETZB, i_setzb, IF_1CB) -idef(0404, "AND", I_AND, i_and, IF_1X) -idef(0405, "ANDI", I_ANDI, i_andi, IF_1XI) -idef(0406, "ANDM", I_ANDM, i_andm, IF_1XM) -idef(0407, "ANDB", I_ANDB, i_andb, IF_1XB) -idef(0410, "ANDCA", I_ANDCA, i_andca, IF_1X) -idef(0411, "ANDCAI",I_ANDCAI,i_andcai, IF_1XI) -idef(0412, "ANDCAM",I_ANDCAM,i_andcam, IF_1XM) -idef(0413, "ANDCAB",I_ANDCAB,i_andcab, IF_1XB) -idef(0414, "SETM", I_SETM, i_setm, IF_1S) -#if KLH10_EXTADR - idef(0415,"XMOVEI",I_XMOVEI,i_xmovei, IF_1SI) /* Extended version */ -#else - idef(0415,"SETMI", I_SETMI, i_setmi, IF_1SI) -#endif -idef(0416, "SETMM", I_SETMM, i_setmm, IF_MS|IF_M1) -idef(0417, "SETMB", I_SETMB, i_setmb, IF_1SB) -idef(0420, "ANDCM", I_ANDCM, i_andcm, IF_1X) -idef(0421, "ANDCMI",I_ANDCMI,i_andcmi, IF_1XI) -idef(0422, "ANDCMM",I_ANDCMM,i_andcmm, IF_1XM) -idef(0423, "ANDCMB",I_ANDCMB,i_andcmb, IF_1XB) -idef(0424, "SETA", I_SETA, i_seta, IF_NOP) -idef(0425, "SETAI", I_SETAI, i_setai, IF_NOP) -idef(0426, "SETAM", I_SETAM, i_setam, IF_1SM) -idef(0427, "SETAB", I_SETAB, i_setab, IF_1SM) -idef(0430, "XOR", I_XOR, i_xor, IF_1X) -idef(0431, "XORI", I_XORI, i_xori, IF_1XI) -idef(0432, "XORM", I_XORM, i_xorm, IF_1XM) -idef(0433, "XORB", I_XORB, i_xorb, IF_1XB) -idef(0434, "IOR", I_IOR, i_ior, IF_1X) -idef(0435, "IORI", I_IORI, i_iori, IF_1XI) -idef(0436, "IORM", I_IORM, i_iorm, IF_1XM) -idef(0437, "IORB", I_IORB, i_iorb, IF_1XB) -idef(0440, "ANDCB", I_ANDCB, i_andcb, IF_1X) -idef(0441, "ANDCBI",I_ANDCBI,i_andcbi, IF_1XI) -idef(0442, "ANDCBM",I_ANDCBM,i_andcbm, IF_1XM) -idef(0443, "ANDCBB",I_ANDCBB,i_andcbb, IF_1XB) -idef(0444, "EQV", I_EQV, i_eqv, IF_1X) -idef(0445, "EQVI", I_EQVI, i_eqvi, IF_1XI) -idef(0446, "EQVM", I_EQVM, i_eqvm, IF_1XM) -idef(0447, "EQVB", I_EQVB, i_eqvb, IF_1XB) -idef(0450, "SETCA", I_SETCA, i_setca, IF_AS|IF_A1) -idef(0451, "SETCAI",I_SETCAI,i_setcai, IF_AS|IF_A1) -idef(0452, "SETCAM",I_SETCAM,i_setcam, IF_1SM) -idef(0453, "SETCAB",I_SETCAB,i_setcab, IF_AS|IF_A1|IF_MW|IF_M1) -idef(0454, "ORCA", I_ORCA, i_orca, IF_1X) -idef(0455, "ORCAI", I_ORCAI, i_orcai, IF_1XI) -idef(0456, "ORCAM", I_ORCAM, i_orcam, IF_1XM) -idef(0457, "ORCAB", I_ORCAB, i_orcab, IF_1XB) -idef(0460, "SETCM", I_SETCM, i_setcm, IF_1X) -idef(0461, "SETCMI",I_SETCMI,i_setcmi, IF_1XI) -idef(0462, "SETCMM",I_SETCMM,i_setcmm, IF_1XM) -idef(0463, "SETCMB",I_SETCMB,i_setcmb, IF_1XB) -idef(0464, "ORCM", I_ORCM, i_orcm, IF_1X) -idef(0465, "ORCMI", I_ORCMI, i_orcmi, IF_1XI) -idef(0466, "ORCMM", I_ORCMM, i_orcmm, IF_1XM) -idef(0467, "ORCMB", I_ORCMB, i_orcmb, IF_1XB) -idef(0470, "ORCB", I_ORCB, i_orcb, IF_1X) -idef(0471, "ORCBI", I_ORCBI, i_orcbi, IF_1XI) -idef(0472, "ORCBM", I_ORCBM, i_orcbm, IF_1XM) -idef(0473, "ORCBB", I_ORCBB, i_orcbb, IF_1XB) -idef(0474, "SETO", I_SETO, i_seto, IF_1C) -idef(0475, "SETOI", I_SETOI, i_setoi, IF_1C) -idef(0476, "SETOM", I_SETOM, i_setom, IF_1CM) -idef(0477, "SETOB", I_SETOB, i_setob, IF_1CB) - - /* ; 500-577 (HLL - HLRES) */ -idef(0500, "HLL", I_HLL, i_hll, IF_1S) -#if KLH10_EXTADR - idef(0501,"XHLLI", I_XHLLI, i_xhlli, IF_1C) /* Extended version */ -#else - idef(0501,"HLLI", I_HLLI, i_hlli, IF_1C) -#endif -idef(0502, "HLLM", I_HLLM, i_hllm, IF_1SM) -idef(0503, "HLLS", I_HLLS, i_hlls, IF_1SS) -idef(0504, "HRL", I_HRL, i_hrl, IF_1S) -idef(0505, "HRLI", I_HRLI, i_hrli, IF_1SI) -idef(0506, "HRLM", I_HRLM, i_hrlm, IF_1SM) -idef(0507, "HRLS", I_HRLS, i_hrls, IF_1SS) -idef(0510, "HLLZ", I_HLLZ, i_hllz, IF_1S) -idef(0511, "HLLZI", I_HLLZI, i_hllzi, IF_1C) -idef(0512, "HLLZM", I_HLLZM, i_hllzm, IF_1SM) -idef(0513, "HLLZS", I_HLLZS, i_hllzs, IF_1SS) -idef(0514, "HRLZ", I_HRLZ, i_hrlz, IF_1S) -idef(0515, "HRLZI", I_HRLZI, i_hrlzi, IF_1C) -idef(0516, "HRLZM", I_HRLZM, i_hrlzm, IF_1SM) -idef(0517, "HRLZS", I_HRLZS, i_hrlzs, IF_1SS) -idef(0520, "HLLO", I_HLLO, i_hllo, IF_1S) -idef(0521, "HLLOI", I_HLLOI, i_hlloi, IF_1C) -idef(0522, "HLLOM", I_HLLOM, i_hllom, IF_1SM) -idef(0523, "HLLOS", I_HLLOS, i_hllos, IF_1SS) -idef(0524, "HRLO", I_HRLO, i_hrlo, IF_1S) -idef(0525, "HRLOI", I_HRLOI, i_hrloi, IF_1C) -idef(0526, "HRLOM", I_HRLOM, i_hrlom, IF_1SM) -idef(0527, "HRLOS", I_HRLOS, i_hrlos, IF_1SS) -idef(0530, "HLLE", I_HLLE, i_hlle, IF_1S) -idef(0531, "HLLEI", I_HLLEI, i_hllei, IF_1C) -idef(0532, "HLLEM", I_HLLEM, i_hllem, IF_1SM) -idef(0533, "HLLES", I_HLLES, i_hlles, IF_1SS) -idef(0534, "HRLE", I_HRLE, i_hrle, IF_1S) -idef(0535, "HRLEI", I_HRLEI, i_hrlei, IF_1SI) -idef(0536, "HRLEM", I_HRLEM, i_hrlem, IF_1SM) -idef(0537, "HRLES", I_HRLES, i_hrles, IF_1SS) -idef(0540, "HRR", I_HRR, i_hrr, IF_1S) -idef(0541, "HRRI", I_HRRI, i_hrri, IF_1SI) -idef(0542, "HRRM", I_HRRM, i_hrrm, IF_1SM) -idef(0543, "HRRS", I_HRRS, i_hrrs, IF_1SS) -idef(0544, "HLR", I_HLR, i_hlr, IF_1S) -idef(0545, "HLRI", I_HLRI, i_hlri, IF_1C) -idef(0546, "HLRM", I_HLRM, i_hlrm, IF_1SM) -idef(0547, "HLRS", I_HLRS, i_hlrs, IF_1SS) -idef(0550, "HRRZ", I_HRRZ, i_hrrz, IF_1S) -idef(0551, "HRRZI", I_HRRZI, i_hrrzi, IF_1SI) -idef(0552, "HRRZM", I_HRRZM, i_hrrzm, IF_1SM) -idef(0553, "HRRZS", I_HRRZS, i_hrrzs, IF_1SS) -idef(0554, "HLRZ", I_HLRZ, i_hlrz, IF_1S) -idef(0555, "HLRZI", I_HLRZI, i_hlrzi, IF_1C) -idef(0556, "HLRZM", I_HLRZM, i_hlrzm, IF_1SM) -idef(0557, "HLRZS", I_HLRZS, i_hlrzs, IF_1SS) -idef(0560, "HRRO", I_HRRO, i_hrro, IF_1S) -idef(0561, "HRROI", I_HRROI, i_hrroi, IF_1SI) -idef(0562, "HRROM", I_HRROM, i_hrrom, IF_1SM) -idef(0563, "HRROS", I_HRROS, i_hrros, IF_1SS) -idef(0564, "HLRO", I_HLRO, i_hlro, IF_1S) -idef(0565, "HLROI", I_HLROI, i_hlroi, IF_1C) -idef(0566, "HLROM", I_HLROM, i_hlrom, IF_1SM) -idef(0567, "HLROS", I_HLROS, i_hlros, IF_1SS) -idef(0570, "HRRE", I_HRRE, i_hrre, IF_1S) -idef(0571, "HRREI", I_HRREI, i_hrrei, IF_1SI) -idef(0572, "HRREM", I_HRREM, i_hrrem, IF_1SM) -idef(0573, "HRRES", I_HRRES, i_hrres, IF_1SS) -idef(0574, "HLRE", I_HLRE, i_hlre, IF_1S) -idef(0575, "HLREI", I_HLREI, i_hlrei, IF_1C) -idef(0576, "HLREM", I_HLREM, i_hlrem, IF_1SM) -idef(0577, "HLRES", I_HLRES, i_hlres, IF_1SS) - - /* ; 600-677 (TRN - TSON) */ -idef(0600, "TRN", I_TRN, i_trn, IF_NOP) -idef(0601, "TLN", I_TLN, i_tln, IF_NOP) -idef(0602, "TRNE", I_TRNE, i_trne, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0603, "TLNE", I_TLNE, i_tlne, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0604, "TRNA", I_TRNA, i_trna, IF_SKP) -idef(0605, "TLNA", I_TLNA, i_tlna, IF_SKP) -idef(0606, "TRNN", I_TRNN, i_trnn, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0607, "TLNN", I_TLNN, i_tlnn, IF_SKP|IF_AR|IF_A1|IF_ME) -idef(0610, "TDN", I_TDN, i_tdn, IF_MR|IF_M1) -idef(0611, "TSN", I_TSN, i_tsn, IF_MR|IF_M1) -idef(0612, "TDNE", I_TDNE, i_tdne, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0613, "TSNE", I_TSNE, i_tsne, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0614, "TDNA", I_TDNA, i_tdna, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0615, "TSNA", I_TSNA, i_tsna, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0616, "TDNN", I_TDNN, i_tdnn, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0617, "TSNN", I_TSNN, i_tsnn, IF_SKP|IF_AR|IF_A1|IF_MR|IF_M1) -idef(0620, "TRZ", I_TRZ, i_trz, IF_AS|IF_A1|IF_ME) -idef(0621, "TLZ", I_TLZ, i_tlz, IF_AS|IF_A1|IF_ME) -idef(0622, "TRZE", I_TRZE, i_trze, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0623, "TLZE", I_TLZE, i_tlze, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0624, "TRZA", I_TRZA, i_trza, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0625, "TLZA", I_TLZA, i_tlza, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0626, "TRZN", I_TRZN, i_trzn, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0627, "TLZN", I_TLZN, i_tlzn, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0630, "TDZ", I_TDZ, i_tdz, IF_AS|IF_A1|IF_MR|IF_M1) -idef(0631, "TSZ", I_TSZ, i_tsz, IF_AS|IF_A1|IF_MR|IF_M1) -idef(0632, "TDZE", I_TDZE, i_tdze, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0633, "TSZE", I_TSZE, i_tsze, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0634, "TDZA", I_TDZA, i_tdza, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0635, "TSZA", I_TSZA, i_tsza, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0636, "TDZN", I_TDZN, i_tdzn, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0637, "TSZN", I_TSZN, i_tszn, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0640, "TRC", I_TRC, i_trc, IF_AS|IF_A1|IF_ME) -idef(0641, "TLC", I_TLC, i_tlc, IF_AS|IF_A1|IF_ME) -idef(0642, "TRCE", I_TRCE, i_trce, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0643, "TLCE", I_TLCE, i_tlce, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0644, "TRCA", I_TRCA, i_trca, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0645, "TLCA", I_TLCA, i_tlca, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0646, "TRCN", I_TRCN, i_trcn, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0647, "TLCN", I_TLCN, i_tlcn, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0650, "TDC", I_TDC, i_tdc, IF_AS|IF_A1|IF_MR|IF_M1) -idef(0651, "TSC", I_TSC, i_tsc, IF_AS|IF_A1|IF_MR|IF_M1) -idef(0652, "TDCE", I_TDCE, i_tdce, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0653, "TSCE", I_TSCE, i_tsce, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0654, "TDCA", I_TDCA, i_tdca, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0655, "TSCA", I_TSCA, i_tsca, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0656, "TDCN", I_TDCN, i_tdcn, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0657, "TSCN", I_TSCN, i_tscn, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0660, "TRO", I_TRO, i_tro, IF_AS|IF_A1|IF_ME) -idef(0661, "TLO", I_TLO, i_tlo, IF_AS|IF_A1|IF_ME) -idef(0662, "TROE", I_TROE, i_troe, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0663, "TLOE", I_TLOE, i_tloe, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0664, "TROA", I_TROA, i_troa, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0665, "TLOA", I_TLOA, i_tloa, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0666, "TRON", I_TRON, i_tron, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0667, "TLON", I_TLON, i_tlon, IF_SKP|IF_AS|IF_A1|IF_ME) -idef(0670, "TDO", I_TDO, i_tdo, IF_AS|IF_A1|IF_MR|IF_M1) -idef(0671, "TSO", I_TSO, i_tso, IF_AS|IF_A1|IF_MR|IF_M1) -idef(0672, "TDOE", I_TDOE, i_tdoe, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0673, "TSOE", I_TSOE, i_tsoe, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0674, "TDOA", I_TDOA, i_tdoa, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0675, "TSOA", I_TSOA, i_tsoa, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0676, "TDON", I_TDON, i_tdon, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) -idef(0677, "TSON", I_TSON, i_tson, IF_SKP|IF_AS|IF_A1|IF_MR|IF_M1) - -/* I/O INSTRUCTION DISPATCH */ - -/* Opcodes 0700-0777 inclusive default to either i_muuo or i_diodisp */ - -#if KLH10_CPU_KS || KLH10_CPU_KL /* "Internal" devices; AC-dispatched */ - idef(0700, "IO700", I_IOV0, i_io700disp, IF_IO) - idef(0701, "IO701", I_IOV1, i_io701disp, IF_IO) - idef(0702, "IO702", I_IOV2, i_io702disp, IF_IO) -#endif /* KS || KL */ - -/* idef(0703, NULL, I_IO03, i_703, IF_IO) */ - -#if KLH10_CPU_KS /* Only KS, sigh... */ - idef(0704, "UMOVE", I_UMOVE, i_umove, IF_SPEC) /* KS = PXCT 4,[MOVE] */ - idef(0705, "UMOVEM", I_UMOVEM, i_umovem, IF_SPEC) /* KS = PXCT 4,[MOVEM] */ -#endif /* KS */ - -/* idef(0706, NULL, I_IO06, i_706, IF_IO) */ -/* idef(0707, NULL, I_IO07, i_707, IF_IO) */ - -#if KLH10_CPU_KS -# if KLH10_SYS_ITS - idef(0710, "IORDI", I_IORDI, i_iordi, IF_MEIO) - idef(0711, "IORDQ", I_IORDQ, i_iordq, IF_MEIO) - idef(0712, "IORD", I_IORD, i_iord, IF_MEIO) - idef(0713, "IOWR", I_IOWR, i_iowr, IF_MEIO) - idef(0714, "IOWRI", I_IOWRI, i_iowri, IF_MEIO) - idef(0715, "IOWRQ", I_IOWRQ, i_iowrq, IF_MEIO) -# else /* DEC */ - idef(0710, "TIOE", I_TIOE, i_tioe, IF_MEIO) - idef(0711, "TION", I_TION, i_tion, IF_MEIO) - idef(0712, "RDIO", I_RDIO, i_rdio, IF_MEIO) - idef(0713, "WRIO", I_WRIO, i_wrio, IF_MEIO) - idef(0714, "BSIO", I_BSIO, i_bsio, IF_MEIO) - idef(0715, "BCIO", I_BCIO, i_bcio, IF_MEIO) -# endif /* DEC */ - - idef(0716, "BLTBU", I_BLTBU, i_bltbu, IF_SPEC|IF_AS|IF_A1|IF_MW|IF_M1) - idef(0717, "BLTUB", I_BLTUB, i_bltub, IF_SPEC|IF_AS|IF_A1|IF_MW|IF_M1) - -# if KLH10_SYS_ITS - idef(0720, "IORDBI", I_IORDBI, i_iordbi, IF_MEIO) - idef(0721, "IORDBQ", I_IORDBQ, i_iordbq, IF_MEIO) - idef(0722, "IORDB", I_IORDB, i_iordb, IF_MEIO) - idef(0723, "IOWRB", I_IOWRB, i_iowrb, IF_MEIO) - idef(0724, "IOWRBI", I_IOWRBI, i_iowrbi, IF_MEIO) - idef(0725, "IOWRBQ", I_IOWRBQ, i_iowrbq, IF_MEIO) -# else /* DEC */ - idef(0720, "TIOEB", I_TIOEB, i_tioeb, IF_MEIO) - idef(0721, "TIONB", I_TIONB, i_tionb, IF_MEIO) - idef(0722, "RDIOB", I_RDIOB, i_rdiob, IF_MEIO) - idef(0723, "WRIOB", I_WRIOB, i_wriob, IF_MEIO) - idef(0724, "BSIOB", I_BSIOB, i_bsiob, IF_MEIO) - idef(0725, "BCIOB", I_BCIOB, i_bciob, IF_MEIO) -# endif /* DEC */ -#endif /* KLH10_CPU_KS */ - -/* -idef(0726, NULL, I_IO26, i_726, IF_IO) -idef(0727, NULL, I_IO27, i_727, IF_IO) -idef(0730, NULL, I_IO30, i_730, IF_IO) -idef(0731, NULL, I_IO31, i_731, IF_IO) -idef(0732, NULL, I_IO32, i_732, IF_IO) -idef(0733, NULL, I_IO33, i_733, IF_IO) -idef(0734, NULL, I_IO34, i_734, IF_IO) -idef(0735, NULL, I_IO35, i_735, IF_IO) -idef(0736, NULL, I_IO36, i_736, IF_IO) -idef(0737, NULL, I_IO37, i_737, IF_IO) -idef(0740, NULL, I_IO40, i_740, IF_IO) -idef(0741, NULL, I_IO41, i_741, IF_IO) -idef(0742, NULL, I_IO42, i_742, IF_IO) -idef(0743, NULL, I_IO43, i_743, IF_IO) -idef(0744, NULL, I_IO44, i_744, IF_IO) -idef(0745, NULL, I_IO45, i_745, IF_IO) -idef(0746, NULL, I_IO46, i_746, IF_IO) -idef(0747, NULL, I_IO47, i_747, IF_IO) -idef(0750, NULL, I_IO50, i_750, IF_IO) -idef(0751, NULL, I_IO51, i_751, IF_IO) -idef(0752, NULL, I_IO52, i_752, IF_IO) -idef(0753, NULL, I_IO53, i_753, IF_IO) -idef(0754, NULL, I_IO54, i_754, IF_IO) -idef(0755, NULL, I_IO55, i_755, IF_IO) -idef(0756, NULL, I_IO56, i_756, IF_IO) -idef(0757, NULL, I_IO57, i_757, IF_IO) -idef(0760, NULL, I_IO60, i_760, IF_IO) -idef(0761, NULL, I_IO61, i_761, IF_IO) -idef(0762, NULL, I_IO62, i_762, IF_IO) -idef(0763, NULL, I_IO63, i_763, IF_IO) -idef(0764, NULL, I_IO64, i_764, IF_IO) -idef(0765, NULL, I_IO65, i_765, IF_IO) -idef(0766, NULL, I_IO66, i_766, IF_IO) -idef(0767, NULL, I_IO67, i_767, IF_IO) -idef(0770, NULL, I_IO70, i_770, IF_IO) -idef(0771, NULL, I_IO71, i_771, IF_IO) -idef(0772, NULL, I_IO72, i_772, IF_IO) -idef(0773, NULL, I_IO73, i_773, IF_IO) -idef(0774, NULL, I_IO74, i_774, IF_IO) -idef(0775, NULL, I_IO75, i_775, IF_IO) -idef(0776, NULL, I_IO76, i_776, IF_IO) -idef(0777, NULL, I_IO77, i_777, IF_IO) -*/ - -/* "INTERNAL" DEVICE IO INSTRUCTIONS (0700-0702 inclusive) */ - - /* APR */ -iodef(IOINOP(0700, 0), "APRID", IO_APRID, io_aprid, IF_IO) /* BI APR, */ -#if KLH10_CPU_KL - /* DATAI APR, - (KA/KI: Read console switches) */ - iodef(IOINOP(0700, 01), NULL, IO_DI_APR, io_di_apr, IF_IO) /* DI APR, */ - iodef(IOINOP(0700, 02), "WRFIL", IO_WRFIL, io_wrfil, IF_IO) /* BO APR, */ - /* DATAO APR, - (KA: set relocs) (KI: set maint) */ - iodef(IOINOP(0700, 03), NULL, IO_DO_APR, io_do_apr, IF_IO) /* DO APR, */ -#endif -iodef(IOINOP(0700, 04), "WRAPR", IO_WRAPR, io_wrapr, IF_IO) /* CO APR, */ -iodef(IOINOP(0700, 05), "RDAPR", IO_RDAPR, io_rdapr, IF_IO) /* CI APR, */ -iodef(IOINOP(0700, 06), NULL, IO_SZ_APR, io_sz_apr, IF_IO) /* SZ APR, */ -iodef(IOINOP(0700, 07), NULL, IO_SO_APR, io_so_apr, IF_IO) /* SO APR, */ - - /* PI */ -#if KLH10_CPU_KL - iodef(IOINOP(0700, 010), "RDERA", IO_RDERA, io_rdera, IF_IO) /* BI PI, */ -#endif -#if 0 - iodef(IOINOP(0700, 011), NULL, IO_DI_PI, NULL, IF_IO) /* DI PI, */ -#endif -#if KLH10_CPU_KL - iodef(IOINOP(0700, 012),"SBDIAG",IO_SBDIAG,io_sbdiag,IF_IO) /* BO PI, */ -#endif -#if 0 /* DATAO PI, - (KA/KI: Disp data on console lites) */ - iodef(IOINOP(0700, 013), NULL, IO_DO_PI, NULL, IF_IO) /* DO PI, */ -#endif -iodef(IOINOP(0700, 014), "WRPI", IO_WRPI, io_wrpi, IF_IO) /* CO PI, */ -iodef(IOINOP(0700, 015), "RDPI", IO_RDPI, io_rdpi, IF_IO) /* CI PI, */ -iodef(IOINOP(0700, 016), NULL, IO_SZ_PI, io_sz_pi, IF_IO) /* SZ PI, */ -iodef(IOINOP(0700, 017), NULL, IO_SO_PI, io_so_pi, IF_IO) /* SO PI, */ - - /* PAG */ -#if KLH10_CPU_KS || KLH10_CPU_KL -# if KLH10_SYS_ITS - iodef(IOINOP(0701, 0),"CLRCSH",IO_CLRCSH,io_clrcsh,IF_IO) /* BI PAG, */ -# endif - iodef(IOINOP(0701, 01), "RDUBR", IO_RDUBR, io_rdubr, IF_IO) /* DI PAG, */ - iodef(IOINOP(0701, 02), "CLRPT", IO_CLRPT, io_clrpt, IF_IO) /* BO PAG, */ - iodef(IOINOP(0701, 03), "WRUBR", IO_WRUBR, io_wrubr, IF_IO) /* DO PAG, */ - iodef(IOINOP(0701, 04), "WREBR", IO_WREBR, io_wrebr, IF_IO) /* CO PAG, */ - iodef(IOINOP(0701, 05), "RDEBR", IO_RDEBR, io_rdebr, IF_IO) /* CI PAG, */ -# if KLH10_CPU_KL - iodef(IOINOP(0701, 06), NULL, IO_SZ_PAG, io_sz_pag, IF_IO) /* SZ PAG, */ - iodef(IOINOP(0701, 07), NULL, IO_SO_PAG, io_so_pag, IF_IO) /* SO PAG, */ -# endif -#endif /* KS || KL */ - - /* CCA */ -#if KLH10_CPU_KL - iodef(IOINOP(0701, 010), NULL, IO_BI_CCA,io_swp, IF_IO) /* BI CCA, */ - iodef(IOINOP(0701, 011), "SWPIA", IO_SWPIA, io_swpia, IF_IO) /* DI CCA, */ - iodef(IOINOP(0701, 012), "SWPVA", IO_SWPVA, io_swpva, IF_IO) /* BO CCA, */ - iodef(IOINOP(0701, 013), "SWPUA", IO_SWPUA, io_swpua, IF_IO) /* DO CCA, */ - iodef(IOINOP(0701, 014), NULL, IO_CO_CCA,io_swp, IF_IO) /* CO CCA, */ - iodef(IOINOP(0701, 015), "SWPIO", IO_SWPIO, io_swpio, IF_IO) /* CI CCA, */ - iodef(IOINOP(0701, 016), "SWPVO", IO_SWPVO, io_swpvo, IF_IO) /* SZ CCA, */ - iodef(IOINOP(0701, 017), "SWPUO", IO_SWPUO, io_swpuo, IF_IO) /* SO CCA, */ -#elif KLH10_SYS_ITS && KLH10_CPU_KS - iodef(IOINOP(0701, 011), "RDPCST",IO_RDPCST,io_rdpcst,IF_IO) /* DI CCA, */ - iodef(IOINOP(0701, 013), "WRPCST",IO_WRPCST,io_wrpcst,IF_IO) /* DO CCA, */ -#endif - - /* TIM */ -#if KLH10_CPU_KS -# if KLH10_PAG_ITS - iodef(IOINOP(0702, 0), "SDBR1", IO_SDBR1, io_sdbr1, IF_IO) /* BI TIM, */ - iodef(IOINOP(0702, 01), "SDBR2", IO_SDBR2, io_sdbr2, IF_IO) /* DI TIM, */ - iodef(IOINOP(0702, 02), "SDBR3", IO_SDBR3, io_sdbr3, IF_IO) /* BO TIM, */ - iodef(IOINOP(0702, 03), "SDBR4", IO_SDBR4, io_sdbr4, IF_IO) /* DO TIM, */ - iodef(IOINOP(0702, 07), "SPM", IO_SPM, io_spm, IF_IO) /* SO TIM, */ -# elif KLH10_PAG_KL /* DEC-specific hacks */ - iodef(IOINOP(0702, 0), "RDSPB", IO_RDSPB, io_rdspb, IF_IO) /* BI TIM, */ - iodef(IOINOP(0702, 01), "RDCSB", IO_RDCSB, io_rdcsb, IF_IO) /* DI TIM, */ - iodef(IOINOP(0702, 02), "RDPUR", IO_RDPUR, io_rdpur, IF_IO) /* BO TIM, */ - iodef(IOINOP(0702, 03), "RDCSTM",IO_RDCSTM,io_rdcstm,IF_IO) /* DO TIM, */ -# endif - iodef(IOINOP(0702, 04), "RDTIM", IO_RDTIM, io_rdtim, IF_IO) /* CO TIM, */ - iodef(IOINOP(0702, 05), "RDINT", IO_RDINT, io_rdint, IF_IO) /* CI TIM, */ - iodef(IOINOP(0702, 06), "RDHSB", IO_RDHSB, io_rdhsb, IF_IO) /* SZ TIM, */ -#endif /* KS */ -#if KLH10_CPU_KL - iodef(IOINOP(0702, 0), "RDPERF", IO_RDPERF, io_rdperf, IF_IO) /* BI TIM, */ - iodef(IOINOP(0702, 01), "RDTIME", IO_RDTIME, io_rdtime, IF_IO) /* DI TIM, */ - iodef(IOINOP(0702, 02), "WRPAE", IO_WRPAE, io_wrpae, IF_IO) /* BO TIM, */ -# if 0 - iodef(IOINOP(0702, 03), NULL, IO_DO_TIM, NULL, IF_IO) /* DO TIM, */ -# endif - iodef(IOINOP(0702, 04), NULL, IO_CO_TIM, io_co_tim, IF_IO) /* CO TIM, */ - iodef(IOINOP(0702, 05), NULL, IO_CI_TIM, io_ci_tim, IF_IO) /* CI TIM, */ - iodef(IOINOP(0702, 06), NULL, IO_SZ_TIM, io_sz_tim, IF_IO) /* SZ TIM, */ - iodef(IOINOP(0702, 07), NULL, IO_SO_TIM, io_so_tim, IF_IO) /* SO TIM, */ -#endif /* KL */ - - /* MTR */ -#if KLH10_CPU_KS -# if KLH10_PAG_ITS - iodef(IOINOP(0702, 010), "LDBR1", IO_LDBR1, io_ldbr1, IF_IO) /* BI MTR, */ - iodef(IOINOP(0702, 011), "LDBR2", IO_LDBR2, io_ldbr2, IF_IO) /* DI MTR, */ - iodef(IOINOP(0702, 012), "LDBR3", IO_LDBR3, io_ldbr3, IF_IO) /* BO MTR, */ - iodef(IOINOP(0702, 013), "LDBR4", IO_LDBR4, io_ldbr4, IF_IO) /* DO MTR, */ - iodef(IOINOP(0702, 017), "LPMR", IO_LPMR, io_lpmr, IF_IO) /* SO MTR, */ -# elif KLH10_PAG_KL /* DEC-specific hacks */ - iodef(IOINOP(0702, 010), "WRSPB", IO_WRSPB, io_wrspb, IF_IO) /* BI MTR, */ - iodef(IOINOP(0702, 011), "WRCSB", IO_WRCSB, io_wrcsb, IF_IO) /* DI MTR, */ - iodef(IOINOP(0702, 012), "WRPUR", IO_WRPUR, io_wrpur, IF_IO) /* BO MTR, */ - iodef(IOINOP(0702, 013), "WRCSTM",IO_WRCSTM,io_wrcstm,IF_IO) /* DO MTR, */ -# endif - iodef(IOINOP(0702, 014), "WRTIM", IO_WRTIM, io_wrtim, IF_IO) /* CO MTR, */ - iodef(IOINOP(0702, 015), "WRINT", IO_WRINT, io_wrint, IF_IO) /* CI MTR, */ - iodef(IOINOP(0702, 016), "WRHSB", IO_WRHSB, io_wrhsb, IF_IO) /* SZ MTR, */ -#endif /* KS */ -#if KLH10_CPU_KL - iodef(IOINOP(0702, 010), "RDMACT",IO_RDMACT, io_rdmact, IF_IO) /* BI MTR, */ - iodef(IOINOP(0702, 011), "RDEACT",IO_RDEACT, io_rdeact, IF_IO) /* DI MTR, */ -# if 0 - iodef(IOINOP(0702, 012), NULL, IO_BO_MTR, NULL, IF_IO) /* BO MTR, */ - iodef(IOINOP(0702, 013), NULL, IO_DO_MTR, NULL, IF_IO) /* DO MTR, */ -# endif - iodef(IOINOP(0702, 014), "WRTIME",IO_WRTIME, io_wrtime, IF_IO) /* CO MTR, */ - iodef(IOINOP(0702, 015), NULL, IO_CI_MTR, io_ci_mtr, IF_IO) /* CI MTR, */ - iodef(IOINOP(0702, 016), NULL, IO_SZ_MTR, io_sz_mtr, IF_IO) /* SZ MTR, */ - iodef(IOINOP(0702, 017), NULL, IO_SO_MTR, io_so_mtr, IF_IO) /* SO MTR, */ -#endif /* KL */ - -/* NOTE!! Check the IO_N def in opdefs.h if more IO-class ops are added! */ - -/* EXTENDED INSTRUCTIONS */ - -#if (KLH10_CPU_KS || KLH10_CPU_KL) \ - && (KLH10_SYS_T10 || KLH10_SYS_T20) /* DEC systems only */ -ixdef(IXOP(000), "ILLEG", IX_ILLEG, ix_undef, IF_SPEC) -ixdef(IXOP(001), "CMPSL", IX_CMPSL, ix_cmps, IF_SPEC) /* Common rtn */ -ixdef(IXOP(002), "CMPSE", IX_CMPSE, ix_cmps, IF_SPEC) /* " */ -ixdef(IXOP(003), "CMPSLE", IX_CMPSLE, ix_cmps, IF_SPEC) /* " */ -ixdef(IXOP(004), "EDIT", IX_EDIT, ix_edit, IF_SPEC) -ixdef(IXOP(005), "CMPSGE", IX_CMPSGE, ix_cmps, IF_SPEC) /* Common rtn */ -ixdef(IXOP(006), "CMPSN", IX_CMPSN, ix_cmps, IF_SPEC) /* " */ -ixdef(IXOP(007), "CMPSG", IX_CMPSG, ix_cmps, IF_SPEC) /* " */ -ixdef(IXOP(010), "CVTDBO", IX_CVTDBO, ix_cvtdb, IF_SPEC) /* Common rtn */ -ixdef(IXOP(011), "CVTDBT", IX_CVTDBT, ix_cvtdb, IF_SPEC) /* " */ -ixdef(IXOP(012), "CVTBDO", IX_CVTBDO, ix_cvtbd, IF_SPEC) /* Common rtn */ -ixdef(IXOP(013), "CVTBDT", IX_CVTBDT, ix_cvtbd, IF_SPEC) /* " */ -ixdef(IXOP(014), "MOVSO", IX_MOVSO, ix_movso, IF_SPEC) -ixdef(IXOP(015), "MOVST", IX_MOVST, ix_movst, IF_SPEC) -ixdef(IXOP(016), "MOVSLJ", IX_MOVSLJ, ix_movslj,IF_SPEC) -ixdef(IXOP(017), "MOVSRJ", IX_MOVSRJ, ix_movsrj,IF_SPEC) -#if KLH10_CPU_KLX /* Always MUUO if not on extended KL */ - ixdef(IXOP(020), "XBLT", IX_XBLT, ix_xblt, IF_SPEC) -#endif -#if KLH10_CPU_KL - ixdef(IXOP(021), "GSNGL", IX_GSNGL, ix_gsngl, IF_SPEC) - ixdef(IXOP(022), "GDBLE", IX_GDBLE, ix_gdble, IF_SPEC) -# if 0 /* Simulated in T10+T20 monitor */ - ixdef(IXOP(023), "GDFIX", IX_GDFIX, ix_gdfix, IF_SPEC) - ixdef(IXOP(024), "GFIX", IX_GFIX, ix_gfix, IF_SPEC) - ixdef(IXOP(025), "GDFIXR", IX_GDFIXR, ix_gdfixr,IF_SPEC) - ixdef(IXOP(026), "GFIXR", IX_GFIXR, ix_gfixr, IF_SPEC) -# endif /* 0 */ - ixdef(IXOP(027), "DGFLTR", IX_DGFLTR, ix_dgfltr,IF_SPEC) - ixdef(IXOP(030), "GFLTR", IX_GFLTR, ix_gfltr, IF_SPEC) - ixdef(IXOP(031), "GFSC", IX_GFSC, ix_gfsc, IF_SPEC) -#endif /* KL only */ -#endif /* (KL||KS) && (T10||T20) */ - -/* NOTE!! Check the IX_N def in opdefs.h if more EXTEND ops are added! */ - -/* Other cruft for dubious posterity */ - -/* -;OLD PROGRAMS USE THESE NAMES - -CLEAR==SETZ -CLEARI==SETZI -CLEARM==SETZM -CLEARB==SETZB - -;RANDOM ALIAS NAMES - -ERJMP==JUMP 16, ; TOPS-20 JSYS-error dispatch (becomes JRST) -ERCAL==JUMP 17, ; TOPS-20 JSYS-error call (becomes PUSHJ 17,) -ADJBP==IBP ;KL10 FORM OF IBP WITH VARIABLE NUMBER TO INCREMENT -JFOV==JFCL 1, ;PDP10 INSTRUCTION (PC CHANGE ON PDP6) -JCRY1==JFCL 2, -JCRY0==JFCL 4, -JCRY==JFCL 6, -JOV==JFCL 10, -PORTAL==JRST 1, ; KI/KL -JRSTF==JRST 2, -HALT==JRST 4, -XJRSTF==JRST 5, ; KL/KS -XJEN==JRST 6, ; KL/KS -XPCW==JRST 7, ; KL/KS -JEN==JRST 12, -SFM==JRST 14, ; KL/KS -XMOVEI==SETMI ; KL only -XHLLI==HLLI ; KL only - -;PDP6 HAS LONG FORM ROUNDED INSTEAD OF IMMEDIATES (FADRL, not FADRI, etc) - -*/ diff --git a/src/osdnet.c.old b/src/osdnet.c.old deleted file mode 100644 index fa6a1bb..0000000 --- a/src/osdnet.c.old +++ /dev/null @@ -1,2609 +0,0 @@ -/* OSDNET.C - OS Dependent Network facilities -*/ -/* $Id: osdnet.c,v 2.8 2003/02/23 18:22:08 klh Exp $ -*/ -/* Copyright © 1999, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: osdnet.c,v $ - * Revision 2.8 2003/02/23 18:22:08 klh - * Fix various problems for NetBSD/Alpha 1.6. - * - * Revision 2.7 2002/03/18 04:25:03 klh - * Add support for promiscuous mode, fix minor ARP error output - * - * Revision 2.6 2001/11/19 10:32:34 klh - * Solaris port fixups. - * - * Revision 2.5 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -/* This file, like DPSUP.C, is intended to be included directly - into source code rather than compiled separately and then linked - together. The reason for this is that the actual configuration - of code will vary depending on its intended use, so a single .o - file cannot satisfy all programs. - */ - -#include /* For basic Unix syscalls */ - -/* The possible configuration macro definitions, with defaults: - */ -#ifndef NETIFC_MAX -# define NETIFC_MAX 20 -#endif - -#ifndef OSDNET_INCLUDED -# include "osdnet.h" /* Insurance to make sure our defs are there */ -#endif - -#ifdef RCSID - RCSID(osdnet_c,"$Id: osdnet.c,v 2.8 2003/02/23 18:22:08 klh Exp $") -#endif - -/* Local predeclarations */ - -struct ifent *osn_iflookup(char *ifnam); -int osn_ifealookup(char *ifnam, unsigned char *eap); - -/* Get a socket descriptor suitable for general net interface - examination and manipulation; this is not necessarily suitable for - use as a packetfilter. - This may only make sense on Unix. - */ -int -osn_ifsock(char *ifnam, ossock_t *as) -{ -#if (KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \ - KLH10_NET_TUN || KLH10_NET_LNX) - return ((*as = socket(AF_INET, SOCK_DGRAM, 0)) >= 0); -#else -# error OSD implementation needed for osn_ifsock -#endif -} - -int -osn_ifclose(ossock_t s) -{ -#if (KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \ - KLH10_NET_TUN || KLH10_NET_LNX) - return (close(s) >= 0); -#else -# error OSD implementation needed for osn_ifclose -#endif -} - - -/* Minor utilities */ - -char * -eth_adrsprint(char *cp, unsigned char *ea) -{ - sprintf(cp, "%x:%x:%x:%x:%x:%x", ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); - return cp; -} - -char * -ip_adrsprint(char *cp, unsigned char *ia) -{ - sprintf(cp, "%d.%d.%d.%d", ia[0], ia[1], ia[2], ia[3]); - return cp; -} - - -/* Interface Table initialization -** Gets info about all net interfaces known to the native system. -** Used for several purposes, hence fairly general. -** -*/ -/* - SIOCGIFCONF documentation is virtually non-existent. The following - info comes from looking at source code. - struct ifconf ifconf; - s = socket(AF_INET, SOCK_DGRAM, 0); - ioctl(s, SIOCGIFCONF, &ifconf); - - ifconf has only two elements: - : struct ifconf - caddr_t ifcu_buf; Buffer to use - int ifc_len; Buffer size in bytes (or # bytes used) - - On return, the buffer holds a series of "struct ifreq" entries, each of - which holds an interface name and address. On older systems, each - such entry was a fixed size, but this was later changed in order to - accomodate longer addresses and consequently, - =====>> EACH ENTRY MAY BE OF VARYING SIZE!!!! <<====== - - This, by the way, is why SIOCGIFCONF appeared to be broken on OSF/1 when - used with a single ifreq's worth of buffer -- since it needed a larger - "ifreq" than the buffer had room for, it returned nothing. - - Although the second element of "struct ifreq" is a union, SIOCGIFCONF always - uses it to return a sockaddr: - : struct ifreq - char ifr_name[16] interface name, eg "de0" - struct sockaddr ifr_addr interface address - : struct sockaddr - unsigned char sa_len # bytes in this sockaddr - unsigned char sa_family address type, AF_xxx - char sa_data[14] actually up to 253 bytes! - - Note that the sa_len field is new; older versions of sockaddr had - just sa_family and sa_data. - - To repeat, the actual size of an ifreq depends on the size of the - sockaddr it contains. This is ALWAYS at least sizeof(struct sockaddr), - so trickiness is only needed when sa_len is greater than this default - size. - -#define _SIZEOF_ADDR_IFREQ(p) \ - ((p)->ifr_addr.sa_len <= sizeof(struct sockaddr) \ - ? sizeof(struct ifreq) \ - : (sizeof(struct ifreq)-sizeof(struct sockaddr)+(p)->ifr_addr.sa_len)) - -or alternatively: - -#define _SIZEOF_ADDR_IFREQ(ifr) \ - ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) \ - ? (sizeof(struct ifreq) - sizeof(struct sockaddr) + (ifr).ifr_addr.sa_len) \ - : sizeof(struct ifreq)) - -*/ -/* - Note that searching for AF_INET or IP addresses only finds interfaces that - are presently configured with IP addresses by "ifconfig", typically those - that are also up. An interface that is dedicated to the emulator will - normally be both "down" and have no IP address bound to it. - - Another way to look at this is that until an interface is configured - up, it has no IP address bound to it. This is the same reason that - SIOCGIFADDR cannot be used to find the IP address of a dedicated - interface; there is none. -*/ - -/* Complete table as returned from system by SIOCGIFCONF - * Currently static for debugging, could be dynamic. - */ -static struct ifconf ifctab; -static char ifcbuf[sizeof(struct ifreq) * NETIFC_MAX]; - -/* Our own internal table of interface entries, filtered - to keep only the ones we're interested in. - */ -static int iftab_initf = 0; -static int iftab_nifs = 0; -static struct ifent iftab[NETIFC_MAX]; - -static void osn_iftab_pass(int opts, int npass, int s, struct ifconf *ifc); - -/* Get table of all interfaces, using our own generic entry format. - * Routine works as follows: - * - * First, grabs a IFCONF table of all interfaces from the kernel. - * Each IFR entry contains a name and an address. - * - * Second, scan this IFCONF table (pass 1) to build our own table of IFE - * entries, made of all IFR entries that pass the following filter - * flags: - * IFTAB_IPS - if set, accepts AF_INET interfaces (with IP address) - * IFTAB_ETHS - if set, accepts LINK interfaces with Ether-like addrs. - * IFTAB_OTH - if set, accepts all others (with unknown addr) - * - * Third, make another scan of IFCONF (pass 2) that grabs *all* information - * about any interface present in our IFE table, regardless of what caused - * it to be inserted. - */ -int -osn_iftab_init(int opts) -{ - int s; - struct ifconf *ifc = &ifctab; - register struct ifent *ifet; - - /* Start out with empty table */ - iftab_nifs = 0; - ifet = &iftab[0]; - - /* Open socket with AF_INET family to get at IP stuff. - */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - esfatal(1, "osn_iftab_init socket()"); - } - - /* Gobble table of config info about all interfaces, including name - and IP address. - */ - ifc->ifc_len = sizeof(ifcbuf); - ifc->ifc_buf = (caddr_t)ifcbuf; - if (ioctl(s, SIOCGIFCONF, (char *)ifc) < 0) { - close(s); - esfatal(1, "osn_iftab_init SIOCGIFCONF"); - } - if (ifc->ifc_len < sizeof(struct ifreq)) { - if (DP_DBGFLG) - dbprintln("SIOCGIFCONF only got %d bytes (need %d)", - (int)ifc->ifc_len, (int)sizeof(struct ifreq)); - close(s); - return 0; /* Assume no interfaces */ - } - if (DP_DBGFLG) - dbprintln("SIOCGIFCONF returned %d bytes (%d ifcs?)", - (int)ifc->ifc_len, (int)(ifc->ifc_len/sizeof(struct ifreq))); - - if (DP_DBGFLG) - osn_ifctab_show(stdout, ifc); - - /* Grabbed everything from OS, now grovel through it */ - osn_iftab_pass(opts, 1, s, ifc); /* Do pass 1 scan */ - osn_iftab_pass(opts, 2, s, ifc); /* Do pass 2 scan */ - iftab_initf = opts; /* Inited! */ - - close(s); - if (DP_DBGFLG) - osn_iftab_show(stdout, &iftab[0], iftab_nifs); - return iftab_nifs; -} - -int -osn_nifents(void) -{ - return iftab_nifs; -} - -static void -osn_iftab_pass(int opts, int npass, int s, struct ifconf *ifc) -{ - register int i; - int offset; - struct ifreq ifr; - register struct ifreq *ifp, *ifend, *ifnext; - register struct ifent *ife, *ifet; - - /* Start out with empty table */ - if (npass == 1) - iftab_nifs = 0; - - ifet = &iftab[0]; - - ifp = ifc->ifc_req; - ifend = (struct ifreq *)((char *)ifp + ifc->ifc_len); - for (; ifp < ifend; ifp = ifnext) { - - /* Find next pointer now, to simplify structure of code. - This is complicated by the fact that the returned table format - has changed under different OS versions. The "new regime" - uses a variable-size "ifreq" entry! Choke... - */ - ifnext = ifp + 1; /* Assume normal entry at first */ -#if NETIF_HAS_SALEN - if (ifp->ifr_addr.sa_len > sizeof(struct sockaddr)) { - offset = ifp->ifr_addr.sa_len - sizeof(struct sockaddr); - ifnext = (struct ifreq *)((char *)ifnext + offset); - } -#endif - /* See whether this entry is already in table. - */ - for (i = 0; i < iftab_nifs; ++i) { - if (strncmp(ifp->ifr_name, ifet[i].ife_name, sizeof(ifp->ifr_name)) - == 0) { - /* Found existing entry! Use its pointer */ - ife = &ifet[i]; - break; - } - } - if (i >= iftab_nifs) { - if (npass == 2) - continue; - /* Pass1, decide now whether to create entry or not */ - /* See if it's something we're interested in. */ - if ((opts & IFTAB_IPS) && (ifp->ifr_addr.sa_family == AF_INET)) { - /* yes */ -#if NETIF_HAS_ETHLINK - } else if ((opts & IFTAB_ETHS) - && (ifp->ifr_addr.sa_family == AF_LINK) - && (((struct sockaddr_dl *)&ifp->ifr_addr)->sdl_alen - == ETHER_ADRSIZ)){ - /* yes */ -#endif - } else if (opts & IFTAB_OTH) { - /* yes */ - } else { - /* Nope, ignore this one */ - continue; - } - - /* Yes, create this entry */ - if (iftab_nifs >= NETIFC_MAX-1) { - error("ifc table overflow, max %d", NETIFC_MAX); - return; /* Stop now */ - } - ife = &ifet[iftab_nifs++]; /* New table entry to fill out */ - - /* Copy interface name and ensure null-terminated - even if sizes someday get out of synch. - */ - strncpy(ife->ife_name, ifp->ifr_name, - (sizeof(ife->ife_name) < sizeof(ifp->ifr_name)) - ? sizeof(ife->ife_name) : sizeof(ifp->ifr_name)); - ife->ife_name[sizeof(ife->ife_name)-1] = '\0'; - - /* These ioctls should work for all interfaces */ - strncpy(ifr.ifr_name, ifp->ifr_name, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0) { - syserr(errno, "SIOCGIFFLAGS for \"%s\"", ife->ife_name); - continue; /* Discard entry */ - } - ife->ife_flags = ifr.ifr_flags; - - /* SIOCGIFMTU: ifr_mtu */ - /* SIOCGIFMETRIC: ifr_metric */ - continue; - } - if (npass == 1) - continue; - - /* Pass 2 and dealing with an existing entry. Flesh it out! */ - switch (ifp->ifr_addr.sa_family) { - case AF_INET: - ife->ife_pinet = ifp; /* Remember pointer */ - ife->ife_ipint = ((struct sockaddr_in *) - &ifp->ifr_addr)->sin_addr.s_addr; - break; -#if NETIF_HAS_ETHLINK - case AF_LINK: - if (((struct sockaddr_dl *)&ifp->ifr_addr)->sdl_alen - == ETHER_ADRSIZ) { - /* Looks like Ethernet physical link, save addr */ - struct sockaddr_dl *dla = (struct sockaddr_dl *)&ifp->ifr_addr; - memcpy(ife->ife_ea, LLADDR(dla), dla->sdl_alen); - ife->ife_gotea = TRUE; - ife->ife_plink = ifp; - break; - } -#endif - /* Else drop through to "other" case */ - default: - ife->ife_pother = ifp; - break; - } - } -} - -void -osn_ifctab_show(FILE *f, struct ifconf *ifc) -{ - register struct ifreq *ifr; - struct ifreq *ifrend; - int len; - int i; - unsigned char *cp; - int nents = 0; - int nvary = 0; - - fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\n", - (long)ifc->ifc_len, ifc->ifc_len/sizeof(struct ifreq), - (int)sizeof(struct sockaddr)); - - ifr = ifc->ifc_req; - ifrend = (struct ifreq *)((char *)(ifc->ifc_req) + ifc->ifc_len); - for (i = 0; ifr < ifrend; ++i) { - ++nents; - -#if NETIF_HAS_SALEN - len = ifr->ifr_addr.sa_len; -#else - len = sizeof(struct sockaddr); -#endif - - /* Output entry data */ - fprintf(f, "%2d: \"%.*s\" fam %d, len %d", - i, (int)sizeof(ifr->ifr_name), ifr->ifr_name, - ifr->ifr_addr.sa_family, len); - if (len) { - cp = (unsigned char *) ifr->ifr_addr.sa_data; - fprintf(f, " = %x", *cp); - for (--len; len > 0; --len) { - fprintf(f, ":%x", *++cp); - } - } - fprintf(f, "\n"); - - cp = (unsigned char *) ifr->ifr_addr.sa_data; - switch (ifr->ifr_addr.sa_family) { - case AF_INET: - { - struct sockaddr_in *skin = (struct sockaddr_in *) &ifr->ifr_addr; - struct in_addr *in = &skin->sin_addr; - unsigned char *ucp = (unsigned char *) &in->s_addr; - - fprintf(f, " AF_INET = port %d, IP %d.%d.%d.%d\n", - (int)skin->sin_port, - ucp[0], ucp[1], ucp[2], ucp[3]); - } - break; - -#if NETIF_HAS_ETHLINK - case AF_LINK: - { - struct sockaddr_dl *dla = (struct sockaddr_dl *) &ifr->ifr_addr; - fprintf(f, " AF_LINK = type %d, alen %d", - dla->sdl_type, dla->sdl_alen); - if (len = dla->sdl_alen) { - cp = (unsigned char *) LLADDR(dla); - fprintf(f, " = %x", *cp); - for (--len; len > 0; --len) { - fprintf(f, ":%x", *++cp); - } - } - fprintf(f, "\n"); - } - break; -#endif - - default: - fprintf(f, " No handler for this family\n"); - } - - - /* Move onto next entry */ -#if NETIF_HAS_SALEN - if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) { - ++nvary; - ifr = (struct ifreq *)((char *)(ifr + 1) + - (ifr->ifr_addr.sa_len - sizeof(struct sockaddr))); - } else -#endif - ifr++; - } - if (nvary) - fprintf(f, "Interface summary: %d entries of varying length\n", - nents); - else - fprintf(f, "Interface summary: %d entries of std length %d\n", - nents, (int)sizeof(struct ifreq)); -} - - -void -osn_iftab_show(FILE *f, struct ifent *ifents, int nents) -{ - register struct ifent *ife; - int i; - - fprintf(f, "Filtered IFE table: %d entries\n", nents); - - for (i = 0, ife = ifents; i < nents; ++i, ++ife) { - fprintf(f, "%2d: \"%s\"", i, ife->ife_name); - if (ife->ife_pinet) { - unsigned char *ucp = ife->ife_ipchr; - fprintf(f, " (IP %d.%d.%d.%d)", - ucp[0], ucp[1], ucp[2], ucp[3]); - } - if (ife->ife_plink || ife->ife_gotea) { - unsigned char *ucp = ife->ife_ea; - fprintf(f, " (%sEther %x:%x:%x:%x:%x:%x)", - (ife->ife_plink ? "" : "Extracted "), - ucp[0], ucp[1], ucp[2], ucp[3], ucp[4], ucp[5]); - } - if (ife->ife_pother) { - fprintf(f, " (Other: fam %d)", - ife->ife_pother->ifr_addr.sa_family); - } - fprintf(f, "\n"); - } -} - -/* OSN_IFTAB_ARP - Look up an entry ARP-style (given IP address) - */ -struct ifent * -osn_iftab_arp(struct in_addr ia) -{ - register int i = 0; - register struct ifent *ife = iftab; - - for (; i < iftab_nifs; ++i, ++ife) - if (ife->ife_ipia.s_addr == ia.s_addr) - return ife; - return NULL; -} - -/* OSN_IFTAB_ARPGET - As above, but returns EA if found. - */ -int -osn_iftab_arpget(struct in_addr ia, unsigned char *eap) -{ - register struct ifent *ife; - - if ((ife = osn_iftab_arp(ia)) && ife->ife_gotea) { - ea_set(eap, ife->ife_ea); - return TRUE; - } - return FALSE; -} - - -/* OSN_IPDEFAULT - Find a default IP interface entry; take the first one - * that's up and isn't a loopback. - */ -struct ifent * -osn_ipdefault(void) -{ - register int i = 0; - register struct ifent *ife = iftab; - - for (; i < iftab_nifs; ++i, ++ife) - if ((ife->ife_flags & IFF_UP) && !(ife->ife_flags & IFF_LOOPBACK)) - return ife; - return NULL; -} - -/* OSN_IFLOOKUP - Find interface entry in our table; NULL if none. - */ -struct ifent * -osn_iflookup(char *ifnam) -{ - register int i = 0; - register struct ifent *ife = iftab; - - for (; i < iftab_nifs; ++i, ++ife) - if (strcmp(ifnam, ife->ife_name) == 0) - return ife; - return NULL; -} - -/* OSN_IFEALOOKUP - Find ethernet address, barf if neither in our table nor - * available via OS. - */ -int -osn_ifealookup(char *ifnam, /* Interface name */ - unsigned char *eap) /* Where to write ether address */ -{ -#if NETIF_HAS_ETHLINK - register struct ifent *ife; - - if ((ife = osn_iflookup(ifnam)) - && (ife->ife_plink || ife->ife_gotea)) { - ea_set(eap, ife->ife_ea); - return TRUE; - } - return FALSE; -#else - return osn_ifeaget(-1, ifnam, eap, (unsigned char *)NULL); -#endif -} - -/* OSN_ARP_STUFF - stuff emulated-host ARP entry into kernel. -** Note it isn't necessary to specify an interface! -** Also, the code assumes that if an ARP entry already exists in the -** kernel for the given IP address, it will be reset to this new -** setting rather than (eg) failing. -*/ -int -osn_arp_stuff(unsigned char *ipa, unsigned char *eap, int pubf) -{ - char ipbuf[OSN_IPSTRSIZ]; - char eabuf[OSN_EASTRSIZ]; - -#if NETIF_HAS_ARPIOCTL - struct arpreq arq; - int sock; - - memset((char *)&arq, 0, sizeof(arq)); /* Clear & set up ARP req */ - arq.arp_pa.sa_family = AF_INET; /* Protocol addr is IP type */ - memcpy( /* Copy IP addr */ - (char *) &((struct sockaddr_in *)&arq.arp_pa)->sin_addr, - ipa, sizeof(struct in_addr)); - arq.arp_ha.sa_family = AF_UNSPEC; /* Hardware addr is Ether */ - ea_set(arq.arp_ha.sa_data, eap); /* Copy Ether addr */ - - /* Set ARP flags. Always make permanent so needn't keep checking. */ - arq.arp_flags = ATF_PERM; /* Make permanent */ - if (pubf) - arq.arp_flags |= ATF_PUBL; /* Publish it for us too! */ - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* Get random socket */ - syserr(errno, "Cannot set ARP entry for %s %s - socket()", - ip_adrsprint(ipbuf, ipa), - eth_adrsprint(eabuf, eap)); - return FALSE; - } - (void) ioctl(sock, SIOCDARP, (char *)&arq); /* Clear old info */ - if (ioctl(sock, SIOCSARP, (char *)&arq) < 0) { /* Set new */ - syserr(errno, "Cannot set ARP entry for %s %s - SIOCSARP", - ip_adrsprint(ipbuf, ipa), - eth_adrsprint(eabuf, eap)); - close(sock); - return FALSE; - } - close(sock); - return TRUE; -#elif CENV_SYS_XBSD - /* The new BSD systems completely did away with the ARP ioctls - and instead substituted a far more complicated PF_ROUTE socket hack. - Rather than attempt to duplicate the arp(8) utility code here, - let's try simply invoking it! - arp -S pub - Note that NetBSD doesn't support -S yet, only -s. -S is like -s - but deletes any existing entry first, avoiding the need for -d - which is needed on NetBSD to avoid complaints from arp(8). - */ - FILE *f; - int err; - char arpbuff[200]; - char resbuff[200]; - - sprintf(arpbuff, -# if CENV_SYS_NETBSD - "/usr/sbin/arp -d %s; /usr/sbin/arp -s %s %s %s", - ip_adrsprint(ipbuf, ipa), -# else - "/usr/sbin/arp -S %s %s %s", -# endif - ip_adrsprint(ipbuf, ipa), - eth_adrsprint(eabuf, eap), - (pubf ? "pub" : "")); - if (DP_DBGFLG) - dbprintln("invoking \"%s\"", arpbuff); - if ((f = popen(arpbuff, "r")) == NULL) { - syserr(errno, "cannot popen: %s", arpbuff); - error("Cannot set ARP entry for %s %s", - ip_adrsprint(ipbuf, ipa), - eth_adrsprint(eabuf, eap)); - return FALSE; - } - /* Read resulting output to avoid possibility it might hang otherwise */ - resbuff[0] = '\0'; - (void) fgets(resbuff, sizeof(resbuff)-1, f); - err = pclose(f); /* Hope this doesn't wait4() too long */ - if (err) { - dbprintln("arp exit error: status %d", err); - dbprintln("arp command was: %s", arpbuff); - } - if (DP_DBGFLG) - dbprintln("arp result \"%s\"", resbuff); - return TRUE; -#else - error("Cannot set ARP entry for %s %s - no implementation", - ip_adrsprint(ipbuf, ipa), - eth_adrsprint(eabuf, eap)); - return FALSE; -#endif -} - -/* OSN_IFIPGET - get IP address for a given interface name. - * This is separate from osn_ifiplook() in case iftab_init - * screws up for some ports. -*/ -int -osn_ifipget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ - char *ifnam, /* Interface name */ - unsigned char *ipa) /* Where to write IP address */ -{ - int ownsock = FALSE; - char ipstr[OSN_IPSTRSIZ]; - struct ifreq ifr; - - if (s == -1) { - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syserr(errno, "Can't get IP addr for \"%s\": socket()", ifnam); - return FALSE; - } - ownsock = TRUE; - } - - /* Find IP address for this interface */ - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFADDR, (caddr_t *)&ifr) < 0) { - syserr(errno, "Can't get IP addr for \"%s\": SIOCGIFADDR", ifnam); - if (ownsock) - close(s); - return FALSE; - } - memcpy(ipa, - (char *)&(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), - IP_ADRSIZ); - - if (ownsock) - close(s); - if (DP_DBGFLG) - dbprintln("IP address for \"%s\" = %s", - ifnam, ip_adrsprint(ipstr, ipa)); - return TRUE; -} - -/* OSN_IFNMGET - get IP netmask for a given interface name. - * Only needed for IMP, not NI20. -*/ -int -osn_ifnmget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ - char *ifnam, /* Interface name */ - unsigned char *ipa) /* Where to write IP netmask */ -{ - int ownsock = FALSE; - char ipstr[OSN_IPSTRSIZ]; - struct ifreq ifr; - - if (s == -1) { - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syserr(errno, "Can't get IP netmask for \"%s\": socket()", ifnam); - return FALSE; - } - ownsock = TRUE; - } - - /* Find IP address for this interface */ - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFNETMASK, (caddr_t *)&ifr) < 0) { - syserr(errno, "Can't get IP netmask for \"%s\": SIOCGIFNETMASK",ifnam); - if (ownsock) - close(s); - return FALSE; - } - memcpy(ipa, - (char *)&(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), - IP_ADRSIZ); - - if (ownsock) - close(s); - if (DP_DBGFLG) - dbprintln("IP netmask for \"%s\" = %s", - ifnam, ip_adrsprint(ipstr, ipa)); - return TRUE; -} - - -/* OSN_IFEAGET - get physical ethernet address for a given interface name. - * - * This is fairly tricky as the OSD mechanism for this tends to - * be *very* poorly documented. - * - * Apparently only DEC OSF/1 and Linux can find this directly. - * However, other systems seem to be divided into either of two - * camps: - * 4.3BSD: Hack - get the IP address of the interface, then use - * use SIOCGARP to look up the hardware address from the - * kernel's ARP table. Clever and gross. - * 4.4BSD: New regime, no ARP. But can get it directly as an - * AF_LINK family address in the ifconf table. -*/ -int -osn_ifeaget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ - char *ifnam, /* Interface name */ - unsigned char *eap, /* Current ether address */ - unsigned char *def) /* Default (hardware) ether address */ -{ - char eastr[OSN_EASTRSIZ]; - -#if CENV_SYS_DECOSF /* Direct approach */ - { - int ownsock = FALSE; - struct ifdevea ifdev; - - if (s == -1) { - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syserr(errno, "Can't get EN addr for \"%s\": socket()", ifnam); - return FALSE; - } - ownsock = TRUE; - } - strncpy(ifdev.ifr_name, ifnam, sizeof(ifdev.ifr_name)); - if (ioctl(s, SIOCRPHYSADDR, &ifdev) < 0) { - syserr(errno, "Can't get EN addr for \"%s\": SIOCRPHYSADDR", ifnam); - if (ownsock) close(s); - return FALSE; - } - if (ownsock) - close(s); - ea_set(eap, ifdev.current_pa); - if (def) - ea_set(def, ifdev.default_pa); - } - -#elif KLH10_NET_LNX - { - int ownsock = FALSE; - struct ifreq ifr; - - if (s == -1) { - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syserr(errno, "Can't get EN addr for \"%s\": socket()", ifnam); - return FALSE; - } - ownsock = TRUE; - } - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0 ) { - syserr(errno, "SIOCGIFHWADDR of %s failed", ifnam); - if (ownsock) close(s); - return FALSE; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - error("%s is not an ethernet - ARPHRD type %d", - ifnam, ifr.ifr_hwaddr.sa_family); - if (ownsock) close(s); - return FALSE; - } - if (ownsock) - close(s); - ea_set(eap, &ifr.ifr_addr.sa_data[0]); /* Return the ether address */ - if (def) - memset(def, 0, ETHER_ADRSIZ); - } - -#elif NETIF_HAS_ARPIOCTL - { - /* Much more general hack */ - unsigned char ipchr[IP_ADRSIZ]; - char ipstr[OSN_IPSTRSIZ]; - - /* Get IP address for this interface, as an argument for ARP lookup */ - if (!osn_ifipget(s, ifnam, ipchr)) { - error("Can't get EN addr for \"%s\": osn_ifipget failed", ifnam); - return FALSE; - } - - /* Have IP address, now do ARP lookup hackery */ - if (!osn_arp_look((struct in_addr *)ipchr, eap)) { - syserr(errno,"Can't find EN addr for \"%s\" %s using ARP", - ifnam, ip_adrsprint(ipstr, ipchr)); - return FALSE; - } - if (def) - memset(def, 0, ETHER_ADRSIZ); - } - -#elif NETIF_HAS_ETHLINK - /* Should never happen unless osn_ifeaget() is called directly - without going through osn_ifealookup(). If so, attempt - to do right thing anyway. - */ - { - register struct ifent *ife; - - if (iftab_initf == 0) { - /* Try to initialize iftab, ignore errors */ - (void) osn_iftab_init(IFTAB_ETHS); - } - if (!(ife = osn_iflookup(ifnam)) - || !(ife->ife_gotea)) { - error("No EN addr in iftab for \"%s\"", ifnam); - return FALSE; - } - ea_set(eap, ife->ife_ea); - if (def) - memset(def, 0, ETHER_ADRSIZ); - } - -#else -# error "Unimplemented OS routine osn_ifeaget()" -#endif - dbprintln("EN addr for \"%s\" = %s", - ifnam, eth_adrsprint(eastr, eap)); - return TRUE; -} - -/* OSN_PFEAGET - get physical ethernet address for an open packetfilter FD. - * - * Also not well documented, but generally easier to perform. -*/ -int -osn_pfeaget(int pfs, /* Packetfilter socket or FD */ - char *ifnam, /* Interface name (sometimes needed) */ - unsigned char *eap) /* Where to write ether address */ -{ - -#if KLH10_NET_NIT - /* SunOS/Solaris: The EA apparently can't be found until after the PF FD - ** is open; an attempt to simply do a socket(AF_UNSPEC, SOCK_DGRAM, 0) - ** will just fail with a protocol-not-supported error. And using an - ** AF_INET socket just gets us the IP address, sigh. - ** Perhaps using AF_DECnet would work, as it does for OSF/1? - */ - struct ifreq ifr; - struct strioctl si; /* Must use kludgy indirect cuz stream */ - - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - si.ic_timout = INFTIM; - si.ic_cmd = SIOCGIFADDR; - si.ic_len = sizeof ifr; - si.ic_dp = (char *)𝔦 - if (ioctl(pfs, I_STR, (char *)&si) < 0) { - syserr(errno, "ether SIOCGIFADDR failed for \"%s\"", ifnam); - ea_clr(eap); - return FALSE; - } - ea_set(eap, &ifr.ifr_addr.sa_data[0]); /* Return the ether address */ - -#elif KLH10_NET_PFLT /* Really DECOSF */ - struct endevp endp; - - if (ioctl(pfs, EIOCDEVP, (caddr_t *)&endp) < 0) { - syserr(errno, "EIOCDEVP failed"); - ea_clr(eap); - return FALSE; - } - if (endp.end_dev_type != ENDT_10MB - || endp.end_addr_len != ETHER_ADRSIZ) { - syserr(errno, "EIOCDEVP returned non-Ethernet info!"); - ea_clr(eap); - return FALSE; - } - ea_set(eap, endp.end_addr); - -#elif KLH10_NET_BPF && !CENV_SYS_NETBSD - /* NetBSD no longer seems to support this */ - struct ifreq ifr; - - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(pfs, SIOCGIFADDR, (char *) &ifr) < 0) { - syserr(errno, "SIOCGIFADDR for EA failed (%d, \"%s\")", - pfs, ifnam); - ea_clr(eap); - return FALSE; - } - ea_set(eap, &ifr.ifr_addr.sa_data[0]); /* Return the ether address */ - -#elif KLH10_NET_DLPI - { - static int dleaget(int fd, unsigned char *eap); - - /* Use handy auxiliary to hide hideous DLPI details */ - if (!dleaget(pfs, eap)) - return FALSE; - } -#else - if (!osn_ifeaget(pfs, ifnam, eap, (unsigned char *)NULL)) - return FALSE; -#endif - - if (DP_DBGFLG) { - char eastr[OSN_EASTRSIZ]; - - dbprintln("EN addr for \"%s\" = %s", - ifnam, eth_adrsprint(eastr, eap)); - } - return TRUE; -} - -#if CENV_SYS_XBSD -static int osn_pareth(char *cp, unsigned char *adr); -#endif - -/* OSN_ARP_LOOK - Attempt looking up ARP information from OS - * This may be needed by DPIMP to find the ether addr for an IP address, - * or by DPNI20 when trying to determine its own ether address. - * In any case, it's a very OS-dependent technique worth encapsulating. - * - * NOTE: Failure to find an address should not cause an error printout, - * unless there is some actual system glitch. - */ -int -osn_arp_look(struct in_addr *ipa, /* Look up this IP address */ - unsigned char *eap) /* Return EA here */ -{ -#if NETIF_HAS_ARPIOCTL - char ipstr[OSN_IPSTRSIZ]; - struct arpreq arq; - int sock; - - /* Query kernel directly. */ - memset((char *)&arq, 0, sizeof(arq)); /* Clear & set up ARP req */ - arq.arp_pa.sa_family = AF_INET; /* Protocol addr is IP type */ - arq.arp_ha.sa_family = AF_UNSPEC; /* Hardware addr is Ether */ - ((struct sockaddr_in *)&arq.arp_pa)->sin_addr = *ipa; - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* Get random socket */ - syserr(errno, "osn_arp_look socket()"); - return FALSE; - } - if (ioctl(sock, SIOCGARP, (char *)&arq) != 0) { /* Get ARP info */ - close(sock); - /* If SIOCGARP fails, assume it just means the entry wasn't found, - rather than implying some error. - */ - if (DP_DBGFLG) - dbprintln("No ARP info for %s", - ip_adrsprint(ipstr, (unsigned char *)ipa)); - return FALSE; - } - close(sock); - - /* Won, check flags */ - if (!(arq.arp_flags & ATF_COM)) { - if (DP_DBGFLG) - dbprintln("ARP entry incomplete for %s", - ip_adrsprint(ipstr, (unsigned char *)ipa)); - return FALSE; - } - ea_set((char *)eap, arq.arp_ha.sa_data); /* Copy ether addr */ - return TRUE; - -#elif CENV_SYS_XBSD - /* The new BSD stuff did away with the ARP ioctls and substituted an - ** extremely complicated routing IPC mechanism. For the time being - ** I'll just use a horrible hack. - */ - unsigned char *cp = (unsigned char *)ipa; - char *arppath = "/usr/sbin/arp"; - char arpbuff[128]; - FILE *f; - char fhost[100]; - char fip[32]; - char fat[8]; - char fhex[32]; - struct eth_addr etha; - int res; - - /* Use -n to avoid symbolic lookup hangs */ - sprintf(arpbuff, "%s -n %u.%u.%u.%u", arppath, - cp[0], cp[1], cp[2], cp[3]); - if (DP_DBGFLG) - dbprintln("invoking \"%s\"", arpbuff); - if ((f = popen(arpbuff, "r")) == NULL) { - syserr(errno, "cannot popen: %s", arpbuff); - return FALSE; - } - arpbuff[0] = '\0'; - (void) fgets(arpbuff, sizeof(arpbuff)-1, f); - res = pclose(f); /* Hope this doesn't wait4() too long */ - if (res) - dbprintln("arp exit error: status %d", res); - if (DP_DBGFLG) - dbprintln("arp result \"%s\"", arpbuff); - - /* Parse the result. There are three possible formats: - ** () at 4+ words - ** () at (incomplete) 4 words only? - ** () -- no entry 5 words only - */ - res = sscanf(arpbuff, "%99s %31s %7s %31s", fhost, fip, fat, fhex); - if (res == 4 && (strcmp(fat, "at")==0) - && osn_pareth(fhex, (unsigned char *)ða)) { - ea_set(eap, ða); - return TRUE; - } - - /* Failed, see if failure is understood or not */ - if (res == 4 - && ( ((strcmp(fat, "at")==0) && strcmp(fhex, "(incomplete)")==0) - || ((strcmp(fat, "--")==0) && strcmp(fhex, "no")==0))) { - - /* Failed in a way we understand, so don't complain */ - return FALSE; - } - error("osn_arp_look result unparseable: \"%s\"", arpbuff); - return FALSE; - -#else - error("osn_arp_look not implemented"); - return FALSE; -#endif -} - -#if CENV_SYS_XBSD /* Auxiliary to support code in osn_arp_look() */ -static int -osn_pareth(char *cp, unsigned char *adr) -{ - unsigned int b1, b2, b3, b4, b5, b6; - int cnt; - - cnt = sscanf(cp, "%x:%x:%x:%x:%x:%x", &b1, &b2, &b3, &b4, &b5, &b6); - if (cnt != 6) { - /* Later try as single large address #? */ - return FALSE; - } - if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255 || b5 > 255 || b6 > 255) - return FALSE; - *adr++ = b1; - *adr++ = b2; - *adr++ = b3; - *adr++ = b4; - *adr++ = b5; - *adr = b6; - return TRUE; -} -#endif /* CENV_SYS_XBSD */ - -#if !OSN_USE_IPONLY /* This stuff not needed for DPIMP */ - -/* OSN_IFEASET - Set physical ethernet address for a given interface name. - * - * Like osn_ifeaget, also tricky with obscure non-standard mechanisms. - * -*/ -int -osn_ifeaset(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ - char *ifnam, /* Interface name */ - unsigned char *newpa) /* New ether address */ -{ -#if CENV_SYS_DECOSF || KLH10_NET_LNX \ - || (CENV_SYS_FREEBSD && defined(SIOCSIFLLADDR)) - - /* Common preamble code */ - int ownsock = FALSE; - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (s == -1) { - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syserr(errno, "Failed osn_ifeaset socket()"); - return FALSE; - } - ownsock = TRUE; - } - -# if CENV_SYS_DECOSF /* Direct approach */ - /* NOTE!!! DECOSF Doc bug! - ** Contrary to appearances in osnpf_ifnam && osnpf->osnpf_ifnam[0]) { /* Allow default ifc */ - /* Bind to specified HW interface */ - if (ioctl(fd, EIOCSETIF, osnpf->osnpf_ifnam) < 0) - esfatal(1, "Couldn't open packetfilter for \"%s\" - EIOCSETIF", - osnpf->osnpf_ifnam); - } - - /* Set up various mode & flag stuff */ - - /* Only the super-user can allow promiscuous or copy-all to be set. */ -#if 0 - /* Allow promiscuous mode if someone wants to use it. - ** For shared interface, never true. - */ - arg = 1; - if (ioctl(fd, EIOCALLOWPROMISC, &arg)) - esfatal(1, "EIOCALLOWPROMISC failed"); /* Maybe not SU? */ -#endif - /* Allow ENCOPYALL bit to be set. - ** Always use this for shared interface so the multicast-bit stuff - ** we grab can also be seen by kernel and other sniffers. - */ - arg = 1; - if (ioctl(fd, EIOCALLOWCOPYALL, &arg)) - esfatal(1, "EIOCALLOWCOPYALL failed"); /* Maybe not SU? */ - - - /* Ensure following bits clear: - ** no timestamps, no batching, no held signal - */ - bits = (ENTSTAMP | ENBATCH | ENHOLDSIG); - if (ioctl(fd, EIOCMBIC, &bits)) - esfatal(1, "EIOCMBIC failed"); - - /* Set: - ** ??? Put interface into promisc mode (if allowed by SU) - ** KLH: No longer -- shouldn't be necessary. - ** Pass packet along to other filters - ** Copy packets to/from native kernel ptcls - to allow talking with - ** native host platform! - */ - bits = (/* ENPROMISC | */ ENNONEXCL | ENCOPYALL); - if (ioctl(fd, EIOCMBIS, &bits)) - esfatal(1, "ioctl: EIOCMBIS"); - - /* Set up packet filter for it - only needed if sharing interface */ - if (!osnpf->osnpf_dedic) { - if (ioctl(fd, EIOCSETF, pfbuild(pfarg, &(osnpf->osnpf_ip.ia_addr))) < 0) - esfatal(1, "EIOCSETF failed"); - } - - /* Now can get our interface's ethernet address. - ** In general, this has to wait until after the packetfilter is opened, - ** since until then we don't have a handle on the specific interface - ** that will be used. - */ - { - struct endevp endp; - - if (ioctl(fd, EIOCDEVP, (caddr_t *)&endp) < 0) - esfatal(1, "EIOCDEVP failed"); - if (endp.end_dev_type != ENDT_10MB - || endp.end_addr_len != 6) - esfatal(1, "EIOCDEVP returned non-Ethernet info!"); - ea_set(&(osnpf->osnpf_ea), endp.end_addr); - } - - /* Miscellaneous stuff */ - - /* Hack: use timeout mechanism to see if it helps avoid wedging system - ** when using OSF/1 V3.0. - */ - if (osnpf->osnpf_rdtmo) - { - struct timeval tv; - - tv.tv_sec = osnpf->osnpf_rdtmo; - tv.tv_usec = 0; - - if (ioctl(fd, EIOCSRTIMEOUT, &tv) < 0) - esfatal(1, "EIOCSRTIMEOUT failed"); - } - - /* If backlog param was provided, try to set system's idea of how many - ** input packets can be kept on kernel queue while waiting for us to - ** read them into user space. - */ - if (osnpf->osnpf_backlog) { - if (ioctl(fd, EIOCSETW, &(osnpf->osnpf_backlog)) < 0) - esfatal(1, "EIOCSETW failed"); - } - - /* Ready to roll! */ - return fd; -} -#endif /* KLH10_NET_PFLT */ - -#if KLH10_NET_BPF - -int -osn_pfinit(register struct osnpf *osnpf, void *arg) -{ - int fd; - struct bpf_version bv; - struct ifreq ifr; - u_int u; - int i; - char *ifnam = osnpf->osnpf_ifnam; - - /* No "default interface" concept here */ - if (!ifnam || !ifnam[0]) - esfatal(1, "Packetfilter interface must be specified"); - - /* Open an unused BPF device for R/W */ - fd = pfopen(); /* Will abort if fail */ - - /* Check the filter language version number */ - if (ioctl(fd, BIOCVERSION, (char *) &bv) < 0) - esfatal(1, "kernel BPF interpreter out of date"); - else if (bv.bv_major != BPF_MAJOR_VERSION || - bv.bv_minor < BPF_MINOR_VERSION) - efatal(1, "requires BPF language %d.%d or higher; kernel is %d.%d", - BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bv.bv_major, bv.bv_minor); - - /* Set immediate mode so that packets are processed as they arrive, - rather than waiting until timeout or buffer full. - - WARNING: NetBSD does not implement this correctly! The code - in src/sys/net/bpf.c:bpfread() treats the immediate flag in a way - that causes it to return EWOULDBLOCK if no input is available. But - this flag must still be set in order for bpfpoll() to detect input - as soon as it arrives! - See dpni20 and dpimp read loops for workaround. - */ - i = 1; - if (ioctl(fd, BIOCIMMEDIATE, (char *) &i) < 0) - esfatal(1, "BIOCIMMEDIATE failed"); - - /* Set the read() buffer size. - Must be set before interface is attached! - */ - u = OSN_BPF_MTU; - if (ioctl(fd, BIOCSBLEN, (char *) &u) < 0) - esfatal(1, "BIOCSBLEN failed"); - - /* Set up packet filter for it - only needed if sharing interface? - Not sure whether it's needed for a dedicated interface; will need - to experiment. - */ - if (!osnpf->osnpf_dedic) { - struct OSN_PFSTRUCT *pf; - - /* Set the kernel packet filter */ - pf = pfbuild(arg, &(osnpf->osnpf_ip.ia_addr)); - if (ioctl(fd, BIOCSETF, (char *)pf) < 0) - esfatal(1, "BIOCSETF failed"); - } - - - /* Set read timeout. - Safety check in order to avoid infinite hangs if something - wedges up. The periodic re-check overhead is insignificant. - */ - /* Set read timeout. - Safety hack derived from need to use timeout to avoid wedging system - when using OSF/1 V3.0. Probably useful for other systems too. - */ - if (osnpf->osnpf_rdtmo) - { - struct timeval tv; - - tv.tv_sec = osnpf->osnpf_rdtmo; - tv.tv_usec = 0; - - if (ioctl(fd, BIOCSRTIMEOUT, (char *) &tv) < 0) - esfatal(1, "BIOCSRTIMEOUT failed"); - } - - /* Attach/bind to desired interface device - */ - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(fd, BIOCSETIF, (char *) &ifr) < 0) - esfatal(1, "BIOCSETIF failed for interface \"%s\"", ifnam); - - /* This code only works with Ethernet, so check for that. - Note cannot check until after interface is attached. - */ - if (ioctl(fd, BIOCGDLT, (char *) &u) < 0) - esfatal(1, "BIOCGDLT failed for interface \"%s\"", ifnam); - if (u != DLT_EN10MB) - efatal(1, "%s is not an ethernet", ifnam); - - - /* Now get our interface's ethernet address. - ** In general, this has to wait until after the packetfilter is opened, - ** since until then we don't have a handle on the specific interface - ** that will be used. - */ - (void) osn_pfeaget(fd, ifnam, (unsigned char *)&(osnpf->osnpf_ea)); - - /* Ready to roll! */ - return fd; -} - -#endif /* KLH10_NET_BPF */ - -#if KLH10_NET_TUN -/* - In order to use the TUN interface we have to do the equivalent of - (1) "ifconfig tun0 up" - as well as - (2) "arp perm pub" - and finally - (3) "sysctl -w net.inet.ip.forwarding=1" - if you want to connect in from other machines besides - the one the emulator is running on. This last step must - still be done externally as it affects overall system - security. - -For (1) the code must flush any existing address, add the new address, and -ensure the interface's IFF_UP flag is set. Assuming we'll always be running -on *BSD because that's the only system supporting TUN at the moment, the -necessary calls are - SIOCDIFADDR - Delete existing address - SIOCAIFADDR - Add existing address (and broadcast and mask) - SIOCSIFFLAGS - To set IFF_UP - - Some comments about how SIOCAIFADDR and SIOCDIFADDR work, based on - observation of the FreeBSD code: - - The miniscule doc is in netintro(4). Use an AF_INET, DGRAM socket. - Both take: - -DELETE takes a struct ifreq (can use an ifaliasreq like the doc claims, -but the SIOCDIFADDR ioctl only defines it as taking an ifreq's worth of -data!). If the first addr matches an existing one, that one is -deleted. Otherwise, the first AF_INET address is deleted; INADDR_ANY -from in.h (ie all zeros) is probably the right thing for this case. - - -ADD takes a new struct so as to set everything at once: - - struct ifaliasreq { - char ifra_name[IFNAMSIZ]; // if name, e.g. "en0" - struct sockaddr ifra_addr; - struct sockaddr ifra_broadaddr; - struct sockaddr ifra_mask; - }; - -For ADD, the ifra_addr field is the new address to add. -However, the ifra_broadaddr field is actually used in two different ways. - If the interface has IFF_BROADCAST set, then ifra_broadaddr is the - broadcast address, as advertised. - But if it has IFF_POINTOPOINT set, it is interpreted as "ifra_dstaddr"; - the destination (or remote) address. It is an error if this address - is INADDR_ANY. -The ifra_mask field is ignored (left as-is or zeroed if new) unless - ifra_mask.sin_len is non-zero. - - */ - -int -osn_pfinit(register struct osnpf *osnpf, void *arg) -{ - int allowextern = TRUE; /* For now, always try for external access */ - int fd; - char tunname[sizeof "/dev/tun000"]; - char *ifnam = tunname + sizeof("/dev/")-1; - int i = -1; - char ipb1[OSN_IPSTRSIZ]; - char ipb2[OSN_IPSTRSIZ]; - struct ifent *ife = NULL; /* Native host's default IP interface if one */ - struct in_addr iplocal; /* TUN ifc address at hardware OS end */ - struct in_addr ipremote; /* Address at remote (emulated host) end */ - static unsigned char ipremset[4] = { 192, 168, 0, 44}; - - /* Remote address is always that of emulated machine */ - ipremote = osnpf->osnpf_ip.ia_addr; - - /* Local address is that of hardware machine if we want to permit - external access. If not, it doesn't matter (and may not even - exist, if there is no hardware interface) - */ - if (allowextern) { - if (osn_iftab_init(IFTAB_IPS) && (ife = osn_ipdefault())) { - iplocal = ife->ife_ipia; - } else { - error("Cannot find default IP interface for host"); - allowextern = FALSE; - } - } - if (!allowextern) { - /* Make up bogus IP address for internal use */ - memcpy((char *)&iplocal, ipremset, 4); - } - - if (DP_DBGFLG) - dbprint("Opening TUN device"); - - do { - sprintf(tunname, "/dev/tun%d", ++i); - } while ((fd = open(tunname, O_RDWR)) < 0 && errno == EBUSY); - - if (fd < 0) - esfatal(1, "Couldn't open tunnel device %s", tunname); - - if (DP_DBGFLG) - dbprintln("Opened %s, configuring for local %s, remote %s", - ifnam, - ip_adrsprint(ipb1, (unsigned char *)&iplocal), - ip_adrsprint(ipb2, (unsigned char *)&ipremote)); - - - /* Activate TUN device. - First address is "local" -- doesn't matter if all we care about is - talking to the native/hardware host, and it can be set to any of the IP - address ranges reserved for LAN-only (non-Internet) use, such as - 10.0.0.44. - However, if planning to allow other machines to access the virtual - host, probably best to use an address suitable for the same LAN - subnet as the hardware host. - Unclear yet whether it works to use the host's own address; it at - least allows the configuration to happen. - - Second address is "remote" -- the one the emulated host is using. - It should probably match the same network as the local address, - especially if planning to connect from other machines. - */ -#if 0 /* Hacky method */ - { - char cmdbuff[128]; - int res; - sprintf(cmdbuff, "ifconfig %s %s %s up", - ifnam, - ip_adrsprint(ipb1, (unsigned char *)&iplocal), - ip_adrsprint(ipb2, (unsigned char *)&ipremote)); - - if ((res = system(cmdbuff)) != 0) { - esfatal(1, "osn_pfinit: ifconfig failed to initialize tunnel device?"); - } - } -#else - { - /* Internal method */ - int s; - struct ifaliasreq ifra; - struct ifreq ifr; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - esfatal(1, "pf_init: tun socket() failed"); - } - - /* Delete first (only) IP address for this device, if any. - Ignore errors. - */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCDIFADDR, &ifr) < 0) { - if (DP_DBGFLG) - syserr(errno, "osn_pfinit tun SIOCDIFADDR failed"); - } - - memset(&ifra, 0, sizeof(ifra)); - strncpy(ifra.ifra_name, ifnam, sizeof(ifra.ifra_name)); - ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_family = AF_INET; - ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_addr = iplocal; - ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_family = AF_INET; - ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_addr = ipremote; - if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { - esfatal(1, "osn_pfinit tun SIOCAIFADDR failed"); - } - - /* Finally, turn on IFF_UP just in case the above didn't do it. - Note interface name is still there from the SIOCDIFADDR. - */ - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { - esfatal(1, "osn_pfinit tun SIOCGIFFLAGS failed"); - } - if (!(ifr.ifr_flags & IFF_UP)) { - ifr.ifr_flags |= IFF_UP; - if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { - esfatal(1, "osn_pfinit tun SIOCSIFFLAGS failed"); - } - if (DP_DBGFLG) - dbprint("osn_pfinit tun did SIOCSIFFLAGS"); - } - } -#endif - - /* Now optionally determine ethernet address. - This amounts to what if anything we should put in the native - host's ARP tables. - - If we only intend to use the net between the virtual host and - its hardware host, then no ARP hackery is needed. - - However, if the intent is to allow traffic between the virtual - host and other machines on the LAN or Internet, then an ARP - entry is required. It must advertise the virtual host's IP - address, using one of the hardware host's ethernet addresses - so any packets on the LAN for the virtual host will at least - wind up arriving at the hardware host it's running on. - */ - - /* Simple method is to get the ifconf table and scan it to find the - first interface with both an IP and ethernet address given. - Non-4.4BSD systems may not provide the latter datum, but if - we're using TUN then we almost certainly also have the good stuff - in ifconf. - */ - if (allowextern && ife) { - /* Need to determine ether addr of our default interface, then - publish an ARP entry mapping the virtual host to the same - ether addr. - */ - (void) osn_arp_stuff((unsigned char *)&ipremote, ife->ife_ea, TRUE); - - /* Return that as our ether address */ - ea_set((char *)&osnpf->osnpf_ea, ife->ife_ea); - } else { - /* Assume no useful ether addr */ - ea_clr((char *)&osnpf->osnpf_ea); - } - - if (DP_DBGFLG) - dbprintln("osn_pfinit tun completed"); - - return fd; -} - -#endif /* KLH10_NET_TUN */ - -#if KLH10_NET_LNX - -/* - The Linux PF_PACKET interface is described to some extent - by the packet(7) man page. - - Linux provides no kernel packet filtering mechanism other than - possibly a check on the ethernet protocol type, but this is useless - for us since we'll always want to check for more than just one type; - e.g. IP and ARP, plus possibly 802.3 or DECNET packets. - - From the man page for packet(7): - By default all packets of the specified protocol type are - passed to a packet socket. To only get packets from a spe- - cific interface use bind(2) specifying an address in a - struct sockaddr_ll to bind the packet socket to an inter- - face. Only the sll_protocol and the sll_ifindex address - fields are used for purposes of binding. - */ -int -osn_pfinit(struct osnpf *osnpf, void *arg) -{ - int fd; - char *ifcname = osnpf->osnpf_ifnam; - struct ifreq ifr; - - /* Open a socket of the desired type. - */ - struct sockaddr_ll sll; - int ifx; - - /* Get raw packets with ethernet headers - */ - fd = socket(PF_PACKET, SOCK_RAW, -#if 0 /*OSN_USE_IPONLY*/ /* If DPIMP or otherwise IP only */ - htons(ETH_P_IP) /* for IP only */ -#else - htons(ETH_P_ALL) /* for everything */ -#endif - ); - if (fd < 0) - esfatal(1, "Couldn't open packet socket"); - - /* Need ifc index in order to do binding, so get it. */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifcname, sizeof(ifr.ifr_name)); - if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0 ) - esfatal(1, "SIOCGIFINDEX of %s failed", ifcname); - ifx = ifr.ifr_ifindex; - - /* Bind to proper device/interface using ifc index */ - memset(&sll, 0, sizeof(sll)); - sll.sll_family = AF_PACKET; - sll.sll_protocol = htons(ETH_P_ALL); - sll.sll_ifindex = ifx; - if (bind(fd, (struct sockaddr *)&sll, sizeof(sll))) - esfatal(1, "bind to %s failed", ifcname); - - /* This code only works with Ethernet, so check for that */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifcname, sizeof(ifr.ifr_name)); - if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0 ) - esfatal(1, "SIOCGIFHWADDR of %s failed", ifcname); - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) - efatal(1, "%s is not an ethernet - ARPHRD type %d", - ifcname, ifr.ifr_hwaddr.sa_family); - - /* Finally, attempt to determine current ethernet MAC address. - Assume above call returned it in sa_data. - */ - ea_set(&osnpf->osnpf_ea, &ifr.ifr_addr.sa_data[0]); - - return fd; -} - -#endif /* KLH10_NET_LNX */ - -#if KLH10_NET_NIT - -/* NIT packetfilter initialization */ - -int -osn_pfinit(struct osnpf *osnpf, void *arg) -{ - int fd; - struct strioctl si; - struct ifreq ifr; - - /* Open NIT stream. We'll be doing both R and W. */ - if ((fd = open("/dev/nit", O_RDWR)) < 0) - esfatal(1, "Couldn't open NIT"); - - /* Ensure that each read gives us one packet */ - if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) - esfatal(1, "I_SRDOPT failed"); - - /* Set up kernel filtering */ - if (ioctl(fd, I_PUSH, "pf") < 0) - esfatal("I_PUSH pf failed"); - - /* Set up packet filter for it */ - if (!osnpf->osnpf_dedic) { - struct OSN_PFSTRUCT *pf; - pf = pfbuild(arg, &osnpf->osnpf_ip.ia_addr); - si.ic_timout = INFTIM; /* Should this be osnpf_rdtmo? */ - si.ic_cmd = NIOCSETF; /* Set packet filter */ - si.ic_len = sizeof(*pf); /* XXX Unfortunate dependency */ - si.ic_dp = (char *)pf; - if (ioctl(fd, I_STR, (char *)&si) < 0) - esfatal(1, "NIOCSETF failed"); - } - - /* Finally, bind to proper device and flush anything accumulated */ - strncpy(ifr.ifr_name, osnpf->osnpf_ifnam, sizeof(ifr.ifr_name)); - si.ic_cmd = NIOCBIND; - si.ic_len = sizeof(ifr); - si.ic_dp = (char *)𝔦 - if (ioctl(fd, I_STR, (char *)&si) < 0) - esfatal(1, "NIOCBIND failed"); - - if (ioctl(fd, I_FLUSH, (char *)FLUSHR) < 0) - esfatal(1, "I_FLUSH failed"); - - /* Get our ethernet address. - ** This can't be done until after the NIT is open and bound. - */ - (void) osn_pfeaget(fd, osnpf->osnpf_ifnam, &(osnpf->osnpf_ea)); - - /* Ready to roll! */ - return fd; -} -#endif /* KLH10_NET_NIT */ - -#if KLH10_NET_DLPI - -/* DLPI packetfilter initialization */ - -#define MAXSIZE (32 * 1024) /* Whuffo? */ -#define MAXADDR 1024 -#define MAXCTLBUF (sizeof (dl_unitdata_req_t) + sizeof (long) + MAXADDR) -#define MAXDLBUF 8192 /* Maybe just MAXCTLBUF */ - -struct ledladdr { - struct ether_addr dl_phys; - unsigned short dl_sap; -}; - -struct dlpictx { - int dc_fd; - struct strbuf dc_ctl; - char dc_ebuf[200]; /* Error output */ - long dc_buf[MAXDLBUF]; -}; - -/* Fake SAP must be above 1500 to avoid 802.3 interpretation, but -** might be dangerous if it were 2048 which is IP (try that later, tho) -*/ -#define FAKESAP 2049 - -#if OSN_USE_IPONLY -static int dlfastpathon(struct dlpictx *dc, int sap); -#endif - -static int strioctl(int fd, int cmd, int len, char *dp); -static int dl_sendreq(struct dlpictx *dc, char *ptr, int len, char *what); -static int strgetmsg(struct dlpictx *dc, char *caller, struct strbuf *datap, - int *flagsp); -static int dlattachreq(struct dlpictx *dc, long ppa); -static int dlokack(struct dlpictx *dc); -static int dlbindreq(struct dlpictx *dc, u_long sap, u_long max_conind, - unsigned short service_mode, unsigned short conn_mgmt); -static int dlbindack(struct dlpictx *dc); -static int dlpromisconreq(struct dlpictx *dc, u_long level); -static int dladdrreq(struct dlpictx *dc, int type); -static int dladdrack(struct dlpictx *dc, unsigned char *addr); -static int dlsetaddrreq(struct dlpictx *dc, unsigned char *addr); -#if 0 -static int dlpromiscoff(struct dlpictx *dc); -static int dlinforeq(struct dlpictx *dc); -static int dlinfoack(struct dlpictx *dc); -static int dlenabmulti(struct dlpictx *dc, char *addrp, int len); -static int dldisabmulti(struct dlpictx *dc, char *addrp, int len); -static int dldetachreq(struct dlpictx *dc); -static int dlunbindreq(struct dlpictx *dc); -#endif - - -int osn_pfinit(struct osnpf *osnpf, void *arg) -{ - int fd; - int ppa; - char *cp; - unsigned char curea[ETHER_ADRSIZ]; - char devpath[IFNAMSIZ+40]; - char eastr[OSN_EASTRSIZ]; - unsigned char *ucp; - struct dlpictx dc; - - /* Figure out right name of device to use. - ** Munch device spec, eg "hmeNN" becomes /dev/hme, unit NN. - ** Code formerly allowed full pathname as device spec, but no longer. - */ - if (osnpf->osnpf_ifnam[0] == 0) - efatal(1, "Ethernet DLPI interface must be specified"); - strcpy(devpath, "/dev/"); - strcat(devpath, osnpf->osnpf_ifnam); /* Buffer always big enough */ - ppa = 0; /* Assume unit #0 */ - cp = &devpath[strlen(devpath)-1]; /* Point to end of string */ - if (isdigit(*cp)) { /* Go to start of unit digits */ - while (isdigit(*--cp)); /* (code safe cuz of /dev/ prefix) */ - ppa = atoi(++cp); - *cp = '\0'; /* Chop off unit digits */ - } - - /* Open device. We'll be doing both R and W. */ - if ((fd = open(devpath, O_RDWR)) < 0) { - esfatal(1, "Couldn't open DLPI packetfilter for ifc \"%s\" (%s)", - devpath, osnpf->osnpf_ifnam); - } - memset((void *)&dc, 0, sizeof(dc)); - dc.dc_fd = fd; - - /* Attach to specific unit */ - if (dlattachreq(&dc, (long)ppa) - || dlokack(&dc)) - efatal(1, dc.dc_ebuf); - - /* Bind */ -#if OSN_USE_IPONLY /* Note using IP SAP */ - if (dlbindreq(&dc, 0x800, 0, DL_CLDLS, 0) -#else /* Note using fake SAP to avoid Solaris lossage */ - if (dlbindreq(&dc, FAKESAP, 0, DL_CLDLS, 0) -#endif - || dlbindack(&dc)) - efatal(1, dc.dc_ebuf); - -#if OSN_USE_IPONLY /* Apparently only needed for this */ - /* Do stuff for "fastpath" which may be needed to allow header to - be included in data buffer rather than separate control struct. - */ - if (dlfastpathon(&dc, 0) < 0) - efatal(1, dc.dc_ebuf); -#elif 0 /* !OSN_USE_IPONLY */ /* Apparently not needed */ - if (dlfastpathon(&dc, FAKESAP) < 0) - efatal(1, dc.dc_ebuf); -#endif - - /* Set up various mode & flag stuff */ - - /* Do input side of DLPI stream */ - -#if CENV_SYS_SOLARIS - /* Turn on raw receive path, so that ethernet header is included in data. - ** This is a special Solaris frob. - */ - if (strioctl(fd, DLIOCRAW, 0, NULL) < 0) { - esfatal(1, "DLIOCRAW ioctl"); - } -#endif - -#if !OSN_USE_IPONLY - /* Don't need this hackery if only want IP packets */ - /* Enable receiving all packets, all SAPs (ethernet header type values) */ - -# if CENV_SYS_SOLARIS - /* Enable promiscuous mode. On Solaris, this is required in order - ** for ALLSAP to work!!! Gross bletcherous misfeatured bug!!! - */ - if ((dlpromisconreq(&dc, DL_PROMISC_PHYS) < 0) - || dlokack(&dc) < 0) - efatal(1, dc.dc_ebuf); -# endif - /* Evidently must explicitly ask for promiscuous SAPs */ - if (dlpromisconreq(&dc, DL_PROMISC_SAP) < 0 - || dlokack(&dc) < 0) - efatal(1, dc.dc_ebuf); - /* And multicast too!? To quote tcpdump, - ** "you would have thought promiscuous would be sufficient" - */ - if (dlpromisconreq(&dc, DL_PROMISC_MULTI) < 0 - || dlokack(&dc) < 0) - efatal(1, dc.dc_ebuf); -#endif /* !OSN_USE_IPONLY */ - - /* Find the physical ethernet address of the interface we got. - ** Do it now, because it may be needed in order to set up the - ** correct packet filter (sigh). - */ - if (dladdrreq(&dc, DL_CURR_PHYS_ADDR) < 0 - || dladdrack(&dc, (unsigned char *)curea) < 0) - efatal(1, dc.dc_ebuf); - - /* HACK HACK -- see if ethernet addr already given, and if so, - ** try to set it if different. - */ - if (!ea_isclr(&osnpf->osnpf_ea) - && (ea_cmp(&osnpf->osnpf_ea, curea) != 0)) { - char old[OSN_EASTRSIZ]; - char new[OSN_EASTRSIZ]; - - /* Attempt to set our EN addr */ - eth_adrsprint(old, (unsigned char *)curea); - eth_adrsprint(new, (unsigned char *)&osnpf->osnpf_ea); - - if (dlsetaddrreq(&dc, (unsigned char *)&osnpf->osnpf_ea) < 0 - || dlokack(&dc) < 0) - efatal(1, dc.dc_ebuf); - - /* Double-check by fetching new addr again and using it */ - if (dladdrreq(&dc, DL_CURR_PHYS_ADDR) < 0 - || dladdrack(&dc, (unsigned char *)curea) < 0) - efatal(1, dc.dc_ebuf); - - if (ea_cmp(&osnpf->osnpf_ea, curea) == 0) { - dbprintln("\"%s\" E/N addr changed: Old=%s New=%s", - osnpf->osnpf_ifnam, old, new); - } else { - dbprintln("\"%s\" E/N addr change failed, Old=%s New=%s", - osnpf->osnpf_ifnam, old, new); - } - } - ea_set(&osnpf->osnpf_ea, curea); - -#if 0 - /* Ensure that each read gives us one packet. - ** Shouldn't matter since we use getmsg(), but code left here in case. - */ - if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) - esfatal(1, "I_SRDOPT failed"); -#endif - - /* Set up packet filter for it - should only be needed if - ** sharing interface, but on Solaris we may be always in promiscuous - ** mode! - */ -#if !CENV_SYS_SOLARIS - if (!osnpf->osnpf_dedic) -#endif - { - struct OSN_PFSTRUCT *pf; - - if (ioctl(fd, I_PUSH, "pfmod") < 0) - esfatal(1, "PUSH of pfmod failed"); - -#if !OSN_USE_IPONLY - if (osnpf->osnpf_dedic) - /* Filter on our ether addr */ - pf = pfeabuild(arg, (unsigned char *)&osnpf->osnpf_ea); - else -#endif - /* Filter on our IP addr */ - pf = pfbuild(arg, &osnpf->osnpf_ip.ia_addr); - - if (strioctl(dc.dc_fd, PFIOCSETF, sizeof(*pf), (char *)pf) < 0) - esfatal(1, "PFIOCSETF failed"); - } - - /* Needed? Flush read side to ensure clear of anything accumulated */ - if (ioctl(fd, I_FLUSH, (char *)FLUSHR) < 0) - esfatal(1, "I_FLUSH failed"); - - /* Ready to roll! */ - return fd; -} - -/* Handy auxiliary to pick up EA address given the PF FD, in case - it's needed again after osn_pfinit is done. - */ -static int -dleaget(int fd, unsigned char *eap) -{ - struct dlpictx dc; - - dc.dc_fd = fd; - if ((dladdrreq(&dc, DL_CURR_PHYS_ADDR) < 0) - || (dladdrack(&dc, (unsigned char *)eap) < 0)) { - error(dc.dc_ebuf); - ea_clr(eap); - return FALSE; - } - return TRUE; -} - -#if OSN_USE_IPONLY /* Apparently only needed for this */ -static int -dlfastpathon(struct dlpictx *dc, int sap) -{ - dl_unitdata_req_t *req; - struct ledladdr { - struct ether_addr dl_phys; - unsigned short dl_sap; - } *dladdrp; - int n; - - /* Construct DL_UNITDATA_REQ primitive. */ - req = (dl_unitdata_req_t *) dc->dc_buf; - req->dl_primitive = DL_UNITDATA_REQ; - req->dl_dest_addr_length = sizeof (short) + ETHER_ADRSIZ; - req->dl_dest_addr_offset = sizeof (dl_unitdata_req_t); - req->dl_priority.dl_min = 0; - req->dl_priority.dl_max = 0; - - /* Set up addr - instead of a specific dest address, just clear it out */ - dladdrp = (struct ledladdr *) - (((char *)req) + req->dl_dest_addr_offset); - dladdrp->dl_sap = sap; - memset(&dladdrp->dl_phys, 0, ETHER_ADRSIZ); - - if ((n = strioctl(dc->dc_fd, DL_IOC_HDR_INFO, - sizeof(*req)+sizeof(*dladdrp), - (char *)req)) < 0) { - esfatal(1, "DL_IOC_HDR_INFO ioctl failed"); - } - return n; -} -#endif /* OSN_USE_IPONLY */ - - -/* Derived variously from TCPDUMP and Sun's ugly DLTX sample program - */ - -static int -strioctl(int fd, int cmd, int len, char *dp) -{ - struct strioctl str; - int rc; - - str.ic_cmd = cmd; - str.ic_timout = INFTIM; - str.ic_len = len; - str.ic_dp = dp; - rc = ioctl(fd, I_STR, &str); - - return (rc < 0) ? rc : str.ic_len; -} - -static int -dl_sendreq(struct dlpictx *dc, char *ptr, int len, char *what) -{ - struct strbuf ctl; - int flags = 0; - - ctl.maxlen = 0; - ctl.len = len; - ctl.buf = ptr; - - if (putmsg(dc->dc_fd, &ctl, (struct strbuf *) NULL, flags) < 0) { - sprintf(dc->dc_ebuf, "%s putmsg failed: %s", - what, dp_strerror(errno)); - return (-1); - } - return (0); -} - -#if OSN_USE_IPONLY -# define DL_MAXWAIT 0 -#else -# define DL_MAXWAIT 15 /* secs to wait for ACK msg */ -#endif - -#if DL_MAXWAIT - -#include - -static void -sigalrm(s) -{ -} -#endif - -static int -strgetmsg(struct dlpictx *dc, - char *caller, - struct strbuf *datap, - int *flagsp) -{ - int rc; - - dc->dc_ctl.maxlen = MAXDLBUF; - dc->dc_ctl.len = 0; - dc->dc_ctl.buf = (char *)dc->dc_buf; - if (flagsp) - *flagsp = 0; - -#if DL_MAXWAIT - signal(SIGALRM, sigalrm); - if (alarm(DL_MAXWAIT) < 0) { - esfatal(1, "%s: alarm set", caller); - } -#endif - - /* Get expected message */ - if ((rc = getmsg(dc->dc_fd, &dc->dc_ctl, datap, flagsp)) < 0) { - sprintf(dc->dc_ebuf, "%s: getmsg - %s", - caller, dp_strerror(errno)); - return -1; - } - -#if DL_MAXWAIT - if (alarm(0) < 0) { - esfatal(1, "%s: alarm clear", caller); - } -#endif - - /* Got it - now do paranoia check */ - if (rc & (MORECTL | MOREDATA)) { - sprintf(dc->dc_ebuf, "%s: getmsg returned%s%s", - caller, - ((rc & MORECTL) ? " MORECTL" : ""), - ((rc & MOREDATA) ? " MOREDATA" : "")); - return -1; - } - - /* Yet more paranoia - control info should exist */ - /* Take this out if all callers check length */ - if (dc->dc_ctl.len < sizeof (long)) { - sprintf(dc->dc_ebuf, "%s: getmsg ctl.len too short: %d", - dc->dc_ctl.len); - return -1; - } - return 0; -} -#undef DL_MAXWAIT - -static int -dlattachreq(struct dlpictx *dc, long ppa) -{ - dl_attach_req_t req; - - req.dl_primitive = DL_ATTACH_REQ; - req.dl_ppa = ppa; - return dl_sendreq(dc, (char *)&req, sizeof(req), "dlattach"); -} - -static int -dlokack(struct dlpictx *dc) -{ - union DL_primitives *dlp; - - if (strgetmsg(dc, "dladdrack", NULL, NULL) < 0) - return -1; - - dlp = (union DL_primitives *) dc->dc_ctl.buf; - - if (dlp->dl_primitive != DL_OK_ACK) { - sprintf(dc->dc_ebuf, "dlokack unexpected primitive %0lX", - (long)dlp->dl_primitive); - return -1; -#if 0 - /* Possibly insert general error handler (DLTX) */ - if (dlp->dl_primitive == DL_ERROR_ACK) - dlerror(dlp->error_ack.dl_errno); - else - printdlprim(dlp); -#endif - } - - if (dc->dc_ctl.len != sizeof(dl_ok_ack_t)) { - sprintf(dc->dc_ebuf, "dlokack incorrect size %ld", - (long)dc->dc_ctl.len); - return -1; - } - return 0; -} - -static int -dlbindreq(struct dlpictx *dc, - u_long sap, - u_long max_conind, - unsigned short service_mode, - unsigned short conn_mgmt) -{ - dl_bind_req_t req; - - req.dl_primitive = DL_BIND_REQ; - req.dl_sap = sap; - req.dl_max_conind = max_conind; - req.dl_service_mode = service_mode; - req.dl_conn_mgmt = conn_mgmt; - req.dl_xidtest_flg = 0; - - return dl_sendreq(dc, (char *)&req, sizeof(req), "dlbind"); -} - -static int -dlbindack(struct dlpictx *dc) -{ - union DL_primitives *dlp; - - if (strgetmsg(dc, "dlbindack", NULL, NULL) < 0) - return -1; - - dlp = (union DL_primitives *) dc->dc_ctl.buf; - - if (dlp->dl_primitive != DL_BIND_ACK) { - sprintf(dc->dc_ebuf, "dlbindack unexpected response %0lX", - (long)dlp->dl_primitive); - return -1; - } - - if (dc->dc_ctl.len < sizeof (dl_bind_ack_t)) { - sprintf(dc->dc_ebuf, "dlbindack: short response: %d", - dc->dc_ctl.len); - return -1; - } -#if 0 /* Don't understand this */ - if (flags != RS_HIPRI) { - sprintf(dc->dc_ebuf, "dlbindack: DL_OK_ACK was not M_PCPROTO"); - return -1; - } -#endif - return 0; -} - - -static int -dlpromisconreq(struct dlpictx *dc, u_long level) -{ - dl_promiscon_req_t req; - - req.dl_primitive = DL_PROMISCON_REQ; - req.dl_level = level; - return dl_sendreq(dc, (char *)&req, sizeof(req), "dlpromiscon"); -} - -/* - * type arg: DL_FACT_PHYS_ADDR for "factory" address, - * DL_CURR_PHYS_ADDR for actual current address. - */ -static int -dladdrreq(struct dlpictx *dc, int type) -{ - dl_phys_addr_req_t req; - - req.dl_primitive = DL_PHYS_ADDR_REQ; - req.dl_addr_type = type; /* DL_{FACT,CURR}_PHYS_ADDR */ - return dl_sendreq(dc, (char *)&req, sizeof(req), "dladdr"); -} - -static int -dladdrack(struct dlpictx *dc, unsigned char *addr) -{ - union DL_primitives *dlp; - unsigned char *ucp; - int len; - - if (strgetmsg(dc, "dladdrack", NULL, NULL) < 0) - return -1; - - dlp = (union DL_primitives *) dc->dc_ctl.buf; - - if (dlp->dl_primitive != DL_PHYS_ADDR_ACK) { - sprintf(dc->dc_ebuf, "dladdrack unexpected response %0lX", - (long)dlp->dl_primitive); - return -1; - } - if (dc->dc_ctl.len < sizeof (dl_phys_addr_ack_t)) { - sprintf(dc->dc_ebuf, "dladdrack: short response: %d", - dc->dc_ctl.len); - return -1; - } - - /* Hardwired paranoia check, assume ethernet for now */ - len = dlp->physaddr_ack.dl_addr_length; - if (len != ETHER_ADRSIZ) { - sprintf(dc->dc_ebuf, "dladdrack: non-Ether addr len %d", len); - return (-1); - } - ucp = ((unsigned char *)dlp) + dlp->physaddr_ack.dl_addr_offset; - memcpy(addr, ucp, (size_t)len); - - return 0; -} - -static int -dlsetaddrreq(struct dlpictx *dc, unsigned char *addr) -{ - /* Request is bigger than struct def; overlay it in buffer */ - dl_set_phys_addr_req_t *req = (dl_set_phys_addr_req_t *)dc->dc_buf; - - req->dl_primitive = DL_SET_PHYS_ADDR_REQ; - req->dl_addr_length = ETHER_ADRSIZ; - req->dl_addr_offset = sizeof(dl_set_phys_addr_req_t); - memcpy(&dc->dc_buf[req->dl_addr_offset], addr, ETHER_ADRSIZ); - - return dl_sendreq(dc, (char *)req, sizeof(*req) + ETHER_ADRSIZ, - "dlsetaddr"); -} - -#endif /* KLH10_NET_DLPI */ - -#if 0 /* KLH10_NET_DLPI */ - -/* DLPI functions not currently used, but kept around in case - */ - -/* Turn off promiscuous mode - */ -static int -dlpromiscoff(struct dlpictx *dc) -{ - dl_promiscoff_req_t req; - - req.dl_primitive = DL_PROMISCOFF_REQ; - return dl_sendreq(dc, (char *)&req, sizeof(req), "dlpromiscoff"); -} - - -static int -dlinforeq(struct dlpictx *dc) -{ - dl_info_req_t req; - - req.dl_primitive = DL_INFO_REQ; - return (dl_sendreq(dc, (char *)&req, sizeof(req), "info")); -} - -static int -dlinfoack(struct dlpictx *dc) -{ - union DL_primitives *dlp; - - if (strgetmsg(dc, "dlinfoack", NULL, NULL) < 0) - return -1; - - dlp = (union DL_primitives *) dc->dc_ctl.buf; - if (dlp->dl_primitive != DL_INFO_ACK) { - sprintf(dc->dc_ebuf, "dlinfoack unexpected primitive %ld", - (long)dlp->dl_primitive); - return -1; - } - - /* Extra stuff like the broadcast address can be returned */ - if (dc->dc_ctl.len < DL_INFO_ACK_SIZE) { - sprintf(dc->dc_ebuf, "dlinfoack: incorrect size %ld", - (long)dc->dc_ctl.len); - return -1; - } - return 0; -} - -static int -dlenabmulti(struct dlpictx *dc, - char *addrp, - int len) -{ - dl_enabmulti_req_t *req; - - req = (dl_enabmulti_req_t *) dc->dc_buf; - req->dl_primitive = DL_ENABMULTI_REQ; - req->dl_addr_length = len; - req->dl_addr_offset = sizeof (dl_enabmulti_req_t); - memcpy((dc->dc_buf + sizeof(dl_enabmulti_req_t)), addrp, len); - - return (dl_sendreq(dc, (char *)req, sizeof(*req)+len, "dlenabmulti")); -} - -static int -dldisabmulti(struct dlpictx *dc, - char *addrp, - int len) -{ - dl_disabmulti_req_t *req; - - req = (dl_disabmulti_req_t *) dc->dc_buf; - req->dl_primitive = DL_DISABMULTI_REQ; - req->dl_addr_length = len; - req->dl_addr_offset = sizeof (dl_disabmulti_req_t); - memcpy((dc->dc_buf + sizeof(dl_disabmulti_req_t)), addrp, len); - - return (dl_sendreq(dc, (char *)req, sizeof(*req)+len, "dldisabmulti")); -} - -static int -dldetachreq(struct dlpictx *dc) -{ - dl_detach_req_t req; - - req.dl_primitive = DL_DETACH_REQ; - return (dl_sendreq(dc, (char *)&req, sizeof(req), "dldetach")); -} - -static int -dlunbindreq(struct dlpictx *dc) -{ - dl_unbind_req_t req; - - req.dl_primitive = DL_UNBIND_REQ; - return (dl_sendreq(dc, (char *)&req, sizeof(req), "dlunbind")); -} - -#endif /* KLH10_NET_DLPI */ - -/* Auxiliary OSDNET.C stuff stops here */ - -#if 0 /* Limit of included code so far */ - -/* Both need to dump packets out - */ -void -dumppkt(unsigned char *ucp, int cnt) -{ - int i; - - while (cnt > 0) { - for (i = 8; --i >= 0 && cnt > 0;) { - if (--cnt >= 0) - fprintf(stderr, " %02x", *ucp++); - if (--cnt >= 0) - fprintf(stderr, "%02x", *ucp++); - } - fprintf(stderr, "\r\n"); - } -} - -/* Merge DPNI20's arp_myreply() with DPIMP's arp_req() ?? - But one sends out a reply, the other a request... - */ - -/* There was an ether_write() for NIT unused in dpni20.c - whereas dpimp.c still uses it for everything. -*/ - -#endif /* if 0 - still-excluded code */ diff --git a/src/osdsup.c.old b/src/osdsup.c.old deleted file mode 100644 index 133157a..0000000 --- a/src/osdsup.c.old +++ /dev/null @@ -1,1724 +0,0 @@ -/* OSDSUP.C - OS-Dependent Support for KLH10 -*/ -/* $Id: osdsup.c,v 2.11 2003/02/23 18:18:01 klh Exp $ -*/ -/* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien -** All Rights Reserved -** -** This file is part of the KLH10 Distribution. Use, modification, and -** re-distribution is permitted subject to the terms in the file -** named "LICENSE", which contains the full text of the legal notices -** and should always accompany this Distribution. -** -** This software is provided "AS IS" with NO WARRANTY OF ANY KIND. -** -** This notice (including the copyright and warranty disclaimer) -** must be included in all copies or derivations of this software. -*/ -/* - * $Log: osdsup.c,v $ - * Revision 2.11 2003/02/23 18:18:01 klh - * Tweak cast to avoid warning on NetBSD/Alpha. - * - * Revision 2.10 2002/05/21 16:27:36 klh - * (MRC) Another os_tmget tweak - T20 expects DTE timezone to ignore DST. - * - * Revision 2.9 2002/04/24 07:56:08 klh - * Add os_msleep, using nanosleep - * - * Revision 2.8 2002/03/26 06:18:24 klh - * Add correct timezone to DTE's time info - * - * Revision 2.7 2002/03/21 09:50:08 klh - * Mods for CMDRUN (concurrent mode) - * - * Revision 2.6 2001/11/19 12:09:58 klh - * Disable shared mem hacking if no DPs - * - * Revision 2.5 2001/11/19 10:43:28 klh - * Add os_rtm_adjust_base for ITS on Mac - * - * Revision 2.4 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ - -#include -#include /* For strrchr */ - -#include "klh10.h" -#include "kn10def.h" -#include "osdsup.h" -#include "kn10ops.h" - -#if CENV_SYS_UNIX -# include -# include -# include - -# include -# include -# include /* For struct tm, localtime() */ - -# if CENV_SYSF_BSDTIMEVAL -# include /* BSD: For setitimer() */ -# include /* BSD: For getrusage() */ -# endif - -# if CENV_SYS_SOLARIS -# include -# include -# endif -# if CENV_SYS_SOLARIS || CENV_SYS_XBSD || CENV_SYS_LINUX -# if CENV_SYS_LINUX -# include /* For FIONREAD */ -# else -# include /* For FIONREAD */ -# endif -# include /* BSD: For setitimer() */ -# include /* No getrusage(), use times() */ -# include /* For CLK_TCK */ -# endif - -# if CENV_SYSF_TERMIOS -# include /* SV4: For terminal stuff */ -# else -# include -# endif - - /* Declare syscalls used */ -# if CENV_SYS_UNIX && !CENV_SYS_V7 -# include /* read, write, lseek */ -# include /* ioctl, stty, gtty */ -# include /* getrusage */ - /* sys/stat.h: fstat */ - /* sys/time.h: gettimeofday, setitimer */ -# else - extern int gtty(), stty(), ioctl(), read(), write(), lseek(), fstat(); - extern int gettimeofday(), setitimer(), getrusage(); -# endif - -#elif CENV_SYS_MAC -# include -# include -# include -# include -# include -# include -# include - -# include "timer-glue.h" - -#if CENV_USE_COMM_TOOLBOX - extern void InitializeMac(); - extern void (*HaltRoutine)(); - extern void CheckEvents(Boolean idle); - extern Boolean tty_crlf_mode; - extern int keyboard_buffer_fill_pointer; -#endif /* CENV_USE_COMM_TOOLBOX */ -#endif /* CENV_SYS_MAC */ - -#if CENV_SYSF_STRERROR - extern char *strerror(int); /* Not always declared in string.h */ -#endif - -extern void fe_shutdown(void); - -#ifdef RCSID - RCSID(osdsup_c,"$Id: osdsup.c,v 2.11 2003/02/23 18:18:01 klh Exp $") -#endif - -/* OS-dependent program startup and exit. -** Surprisingly, "main" is really an OSD function! -** Note that klh10_main is a void function; exit is performed by calling -** os_exit() with a status value. -** If it becomes necessary for program exit to do so by returning -** a value from main(), this can be accomplished by having os_exit -** do a longjmp back to the main() here. -*/ - -extern void klh10_main(int, char **); /* In klh10.c */ - -int -main(int argc, char **argv) -{ -# if CENV_SYS_MAC /* Increase stack size on a Mac */ - size_t *base = (size_t *) 0x000908; - SetApplLimit ((Ptr) (*base - (size_t) 65535L)); -# endif - klh10_main(argc, argv); - return 0; -} - -void -os_init(void) -{ -#if CENV_SYS_UNIX /* Just return error if write to pipe fails */ - osux_signal(SIGPIPE, SIG_IGN); -#elif CENV_SYS_MAC - InitializeMac(); -#endif -} - -void -os_exit(int status) -{ -#if CENV_SYS_MAC && CENV_USE_COMM_TOOLBOX - os_timer(0, NULL, 0, NULL); /* Stop the timer. Important! */ - if (status) { - os_ttycmforce(); /* Badness. Give user a chance */ - for (;;) CheckEvents(TRUE); /* to read final message */ - } -#endif - exit(status); -} - - -char * -os_strerror(int err) -{ - if (err == -1 && errno != err) - return os_strerror(errno); -#if CENV_SYSF_STRERROR - return strerror(err); -#else -# if CENV_SYS_UNIX - { -# if !CENV_SYS_XBSD /* Already in signal.h */ - extern int sys_nerr; - extern char *sys_errlist[]; -# endif - if (0 < err && err <= sys_nerr) - return sys_errlist[err]; - } -# endif - if (err == 0) - return "No error"; - else { - static char ebuf[30]; - sprintf(ebuf, "Unknown-error-%d", err); - return ebuf; - } -#endif /* !CENV_SYSF_STRERROR */ -} - -/* Controlling terminal stuff -** -** Note hack to support background mode; see fecmd.c -*/ - -static int osttyback = FALSE; /* Initially false, not in background */ - -#if CENV_SYS_UNIX -static int ttystated = FALSE; - -static struct ttystate { -# if CENV_SYSF_TERMIOS - struct termios tios; -# else - struct sgttyb sg; -# if CENV_SYSF_BSDTTY - struct tchars t; - struct ltchars lt; -# endif -# endif -} - inistate, /* Initial state at startup, restored on exit */ - cmdstate, /* State while waiting for command line */ - cmrstate, /* State while collecting command line & KN10 running */ - runstate; /* State while KN10 running, CTY I/O */ - -static void -ttyget(register struct ttystate *ts) -{ -# if CENV_SYSF_TERMIOS - (void) tcgetattr(0, &(ts->tios)); /* Get all terminal attrs */ -# else - - gtty(0, &(ts->sg)); /* Get basic sgttyb state */ -# if CENV_SYSF_BSDTTY - ioctl(0, TIOCGETC, &(ts->t)); /* Get tchars */ - ioctl(0, TIOCGLTC, &(ts->lt)); /* Get ltchars */ -# endif /* CENV_SYSF_BSDTTY */ - -# endif /* !CENV_SYSF_TERMIOS */ -} - -static void -ttyset(register struct ttystate *ts) -{ -# if CENV_SYSF_TERMIOS - (void) tcsetattr(0, TCSANOW, &(ts->tios)); /* Set all terminal attrs */ - /* Note change is immediate */ -# else - - stty(0, &(ts->sg)); /* Set basic sgttyb state */ -# if CENV_SYSF_BSDTTY - ioctl(0, TIOCSETC, &(ts->t)); /* Set tchars */ - ioctl(0, TIOCSLTC, &(ts->lt)); /* Set ltchars */ -# endif /* CENV_SYSF_BSDTTY */ - -# endif /* !CENV_SYSF_TERMIOS */ -} -#endif /* CENV_SYS_UNIX */ - -/* This routine is needed on systems that inherited the original unix -** genetic defect wherein a caught signal de-installs -** the original handler. -*/ -#if CENV_SYS_MAC && !CENV_USE_COMM_TOOLBOX -static void (*intsighan)(); -static void -intresig(void) -{ - signal(SIGINT, intresig); /* Re-install self, sigh! */ - (*intsighan)(); /* Invoke intended handler */ -} -#endif - -/* TTY background mode stuff - */ -void -os_ttybkgd(ossighandler_t *rtn) -{ - if (rtn && !osttyback) { - /* Turn on background mode */ - osttyback = TRUE; /* Say running in bkgd */ -#if CENV_SYS_UNIX - /* Clear TTY state in case it's ever referenced by accident */ - memset((void *)&inistate, 0, sizeof(inistate)); - ttystated = TRUE; - (void) osux_signal(SIGTERM, rtn); -#endif /* CENV_SYS_UNIX */ - - } else if (!rtn && osttyback) { - /* Turn off background mode */ - osttyback = FALSE; -#if CENV_SYS_UNIX - ttystated = FALSE; /* Must get new tty state */ - (void) osux_signal(SIGTERM, SIG_DFL); -#endif /* CENV_SYS_UNIX */ - } -} - -/* Initialize controlling TTY. -** This routine now takes an attribute struct! -*/ -void -os_ttyinit(osttyinit_t *osti) -{ -#if CENV_SYS_UNIX - /* Turn off SIGQUIT since the last thing we want to do with - ** a 32MB data segment is dump core! - */ - osux_signal(SIGQUIT, SIG_IGN); - - /* Set up SIGINT to trap to FE (KLH10 command processor). - ** SIGINT is used instead of (eg) SIGQUIT because SIGINT is the - ** only appropriate value available from the ANSI C standard. - */ - osux_signal(SIGINT, osti->osti_inthdl); /* Use native SIGINT */ - - if ((osti->osti_attrs & OSTI_BKGDF) - && osti->osti_bkgdf) { - os_ttybkgd(osti->osti_trmhdl); /* This will set ttystated=TRUE */ - } - - if (!ttystated) { /* If first time, */ - ttyget(&inistate); /* remember initial TTY state */ - ttystated = TRUE; - } - - /* Now set up various states as appropriate */ - cmdstate = cmrstate = runstate = inistate; /* Start with known state */ - - if (!osttyback) { -# if CENV_SYSF_TERMIOS - runstate.tios.c_iflag = IMAXBEL; /* Minimal input processing */ - runstate.tios.c_oflag &= ~OPOST; /* No output processing */ - runstate.tios.c_cflag &= ~(CSIZE|PARENB|PARODD); - runstate.tios.c_cflag |= CS8; /* No parity, 8-bit chars */ - runstate.tios.c_lflag = ISIG; /* Allow sigs for VINTR */ - memset(runstate.tios.c_cc, -1, sizeof(runstate.tios.c_cc)); - runstate.tios.c_cc[VINTR] = osti->osti_intchr; - runstate.tios.c_cc[VMIN] = 1; - runstate.tios.c_cc[VTIME] = 0; - - /* Command-run mode settings */ - cmrstate.tios.c_lflag |= ISIG; /* Allow sigs for VINTR */ - cmrstate.tios.c_cc[VINTR] = osti->osti_intchr; - cmdstate = cmrstate; /* Duplicate for cmd mode */ - -# else - cmdstate.sg.sg_flags |= CBREAK; /* Want CBREAK for cmds */ - runstate.sg.sg_flags |= CBREAK; /* and running */ - runstate.sg.sg_flags &= ~(ECHO|CRMOD); /* no echo when running */ - -# if CENV_SYSF_BSDTTY - /* If a specific command escape/interrupt char is set, use that and - ** turn off everything else. If 0, not set, all chars available for - ** possible debugging. - */ - if (cpu.fe.fe_intchr) { - runstate.t.t_intrc = osti->osti_intchr; - runstate.t.t_quitc = - runstate.t.t_startc = - runstate.t.t_stopc = - runstate.t.t_eofc = -1; - - /* At this point, OK for cmd and cmdrun input */ - cmrstate.t = cmdstate.t = runstate.t; - cmrstate.lt = cmdstate.lt = runstate.lt; - - /* Now finish clearing decks for run state */ - runstate.t.t_brkc = -1; - runstate.lt.t_suspc = - runstate.lt.t_dsuspc = - runstate.lt.t_rprntc = - runstate.lt.t_flushc = - runstate.lt.t_werasc = - runstate.lt.t_lnextc = -1; - } -# endif /* CENV_SYSF_BSDTTY */ -# endif /* !CENV_SYSF_TERMIOS */ - - } /* end of if(!osttyback) */ - -#elif CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - HaltRoutine = osti->osti_inthdl; /* Command-. calls HaltRoutine, */ - tty_crlf_mode = FALSE; /* returning to FE cmd level */ -# else - intsighan = osti->osti_inthdl; /* Remember actual handler to use */ - signal(SIGINT, intresig); /* Command-. returns to FE cmd level */ -# endif - -#else -# error "Unimplemented OS routine os_ttyinit()" -#endif -} - -#if KLH10_CTYIO_INT -/* Set TTY I/O signal handler - */ -void -os_ttysig(ossighandler_t *rtn) -{ -# if CENV_SYS_DECOSF || CENV_SYS_SUN || CENV_SYS_XBSD || CENV_SYS_LINUX - osux_signal(SIGIO, rtn); -# elif CENV_SYS_SOLARIS - osux_signal(SIGPOLL, rtn); -# else -# error "Unimplemented OS routine os_ttysig()" -# endif -} - -/* Enable TTY I/O signalling - */ -static void -tty_iosigon(void) -{ -#if CENV_SYS_DECOSF || CENV_SYS_SUN || CENV_SYS_XBSD || CENV_SYS_LINUX - fcntl(0, F_SETFL, FASYNC); /* Set asynch-operation flag */ -# if CENV_SYS_FREEBSD || CENV_SYS_NETBSD || CENV_SYS_LINUX - /* FreeBSD for sure, NetBSD probably, Linux almost certainly */ - /* On these systems, it isn't sufficient to simply set FASYNC - (what they now call O_ASYNC). The F_SETOWN function must *ALSO* - be called in order to set the process (or process group) that will - receive the SIGIO or SIGURG signal; it doesn't default! Argh!! - On OSF/1 this applies only to SIGURG, which we aren't using. - */ - { - static int doneonce = 0; - if (!doneonce) { - fcntl(0, F_SETOWN, getpid()); - doneonce = TRUE; - } - } -# endif - -#elif CENV_SYS_SOLARIS - ioctl(0, I_SETSIG, S_INPUT); /* Set stream to signal on input */ - -#else -# error "Unimplemented OS routine tty_iosigon()" -#endif -} - -/* Disable TTY I/O signalling - */ -static void -tty_iosigoff(void) -{ -#if CENV_SYS_DECOSF || CENV_SYS_SUN || CENV_SYS_XBSD || CENV_SYS_LINUX - fcntl(0, F_SETFL, 0); /* Clear asynch-operation flag */ -#elif CENV_SYS_SOLARIS - ioctl(0, I_SETSIG, 0); /* Clear TTY stream signal behavior */ -#else -# error "Unimplemented OS routine tty_iosigoff()" -#endif -} - -#endif /* KLH10_CTYIO_INT */ - -void -os_ttyreset(void) -{ -#if CENV_SYS_UNIX -# if KLH10_CTYIO_INT - tty_iosigoff(); /* Turn off TTY I/O signalling */ -# endif - ttyset(&inistate); /* Restore original TTY state */ - -#elif CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - os_ttycmforce(); - tty_crlf_mode = FALSE; -# else - csetmode(C_ECHO, stdin); /* line buffering */ -# endif - -#else -# error "Unimplemented OS routine os_ttyreset()" -#endif -} - -void -os_ttycmdmode(void) -{ -#if CENV_SYS_UNIX -# if KLH10_CTYIO_INT - tty_iosigoff(); /* Turn off TTY I/O signalling */ -# endif - ttyset(&cmdstate); /* Restore command-mode TTY state */ - -#elif CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - os_ttycmforce(); - tty_crlf_mode = FALSE; -# else - csetmode(C_CBREAK, stdin); /* no line buffering */ -# endif - -# else -# error "Unimplemented OS routine os_ttycmdmode()" -#endif -} - -/* Hybrid mode: line command input, but signal if possible when ready. - */ -void -os_ttycmdrunmode(void) -{ -#if CENV_SYS_UNIX -# if KLH10_CTYIO_INT - tty_iosigon(); /* Turn on TTY I/O signalling */ -# endif - ttyset(&cmrstate); /* Change to command-run TTY state */ - -#elif CENV_SYS_MAC - os_ttycmdmode(); - -#else -# error "Unimplemented OS routine os_ttyrunmode()" -#endif -} - - -void -os_ttyrunmode(void) -{ -#if CENV_SYS_UNIX -# if KLH10_CTYIO_INT - tty_iosigon(); /* Turn on TTY I/O signalling */ -# endif - ttyset(&runstate); /* Change to "run" TTY state */ - -#elif CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - os_ttycmforce(); - tty_crlf_mode = TRUE; -# else - csetmode(C_RAW, stdin); /* no line buffering */ -# endif - -#else -# error "Unimplemented OS routine os_ttyrunmode()" -#endif -} - -#if CENV_SYS_MAC && !CENV_USE_COMM_TOOLBOX -static int macsavchar = -1; -#endif - -/* OS_TTYINTEST - See if any TTY input available, and returns count of chars. -** If count unknown, OK to return just 1; routine will be invoked -** frequently (either by clock timeout or by I/O signal). -*/ -int -os_ttyintest(void) -{ -#if CENV_SYS_UNIX - { - /* OSD WARNING: the FIONREAD ioctl is defined to want a "long" on SunOS - ** and presumably old BSD, but it uses an "int" on Solaris and DEC OSF/1! - ** Leave undefined for unknown systems to ensure this is checked on - ** each new port. - */ -#if CENV_SYS_SUN - long retval; -#elif CENV_SYS_SOLARIS || CENV_SYS_DECOSF || CENV_SYS_XBSD || CENV_SYS_LINUX - int retval; -#endif - if (ioctl(0, FIONREAD, &retval) != 0) /* If this call fails, */ - return 0; /* assume no input waiting */ - return (int) retval; - } -#elif CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - if (stdin->buffer_len) - return stdin->buffer_len; - - CheckEvents(FALSE); - return (keyboard_buffer_fill_pointer); -# else - { - unsigned char c; - if (macsavchar >= 0) /* If previously input char is there, */ - return 1; /* say so. */ - if (mactick) - (*mactick)(); /* Do a simulated clock tick (KLH: ?!!) */ - - if (read(0, (char *)&c, 1) != 1) /* If this call fails, */ - return 0; /* assume no input waiting */ - switch (c &= 0177) { /* what did we get? */ - case 034: /* CTRL-\ */ - raise(SIGINT); /* request the console */ - return 0; /* Allow for possible return */ - case 010: /* backspace becomes delete (sigh) */ - c = 0177; - default: - macsavchar = c; /* save character */ - } - return 1; /* have something to read */ - } -# endif - -#else -# error "Unimplemented OS routine os_ttyintest()" -#endif -} - -int -os_ttyin(void) -{ -#if CENV_SYS_UNIX - { - unsigned char buf; - if (read(0, (char *)&buf, 1) != 1) /* If this call fails, */ - return -1; /* assume no input waiting */ - return buf; - } -#elif CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - if (os_ttyintest()) - return getc(stdin); - else return -1; -# else - { - int c = macsavchar; - macsavchar = -1; /* read the character */ - return c; - } -# endif - -#else -# error "Unimplemented OS routine os_ttyin()" -#endif -} - -int -os_ttyout(int ch) -{ -#if CENV_SYS_UNIX || CENV_SYS_MAC - char chloc = ch & 0177; /* Sigh, must mask off T20 parity */ -# if CENV_USE_COMM_TOOLBOX - /* Event check to allow stopping runaway typeout on Mac */ - static int ttyout_event_check_counter = 1; - if (--ttyout_event_check_counter <= 0) { - CheckEvents(FALSE); - ttyout_event_check_counter = 100; - } -# endif - return write(1, &chloc, 1) == 1; - -#else -# error "Unimplemented OS routine os_ttyout()" -#endif -} - -/* TTY String output. -** Note assumption that 8th bit is already masked, if desired. -** Call may block, sigh. -*/ -int -os_ttysout(char *buf, int len) /* Note length is signed int */ -{ -#if CENV_SYS_UNIX || CENV_SYS_MAC -# if CENV_USE_COMM_TOOLBOX - /* Event check to allow stopping runaway typeout on Mac */ - CheckEvents(FALSE); -# endif - return write(1, buf, (size_t)len) == len; - -#else -# error "Unimplemented OS routine os_ttysout()" -#endif -} - -/* Top-level command character input -** May want to be different from os_ttyin(). -*/ -int -os_ttycmchar(void) -{ -#if CENV_SYS_MAC && CENV_USE_COMM_TOOLBOX - { - int ch; - - while(!os_ttyintest()) - CheckEvents(TRUE); - ch = getc(stdin); - os_ttyout(ch); - os_ttycmforce(); - return ch; - } -#else - return getc(stdin); -#endif -} - -char * -os_ttycmline(char *buffer, int size) -{ -#if CENV_SYS_MAC && CENV_USE_COMM_TOOLBOX - { - /*--- Add rubout processing later ---*/ - int i=0, ch; - - os_ttycmforce(); - --size; /* allow for null at end */ - while (i < size) { - ch = os_ttycmchar(); - if (ch == 015) - break; - else if (ch == 0177) { - printf("XXX\n"); - os_ttycmforce(); - i = 0; - } else - buffer[i++] = ch; - } - buffer[i] = 0; - return buffer; - } -#else - return fgets(buffer, size, stdin); -#endif -} - -void -os_ttycmforce(void) -{ - fflush(stdout); -} - -/* General-purpose System-level I/O. -** It is intended that this level of IO be in some sense the fastest -** or most efficient way to interact with the host OS, as opposed to -** the more portable stdio interface. -*/ - -int -os_fdopen(osfd_t *afd, char *file, char *modes) -{ -#if CENV_SYS_UNIX || CENV_SYS_MAC - int flags = 0; - if (!afd) return FALSE; - for (; modes && *modes; ++modes) switch (*modes) { - case 'r': flags |= O_RDONLY; break; /* Yes I know it's 0 */ - case 'w': flags |= O_WRONLY; break; - case '+': flags |= O_RDWR; break; - case 'a': flags |= O_APPEND; break; - case 'b': /* Binary */ -# if CENV_SYS_MAC - flags |= O_BINARY; -# endif - break; - case 'c': flags |= O_CREAT; break; - /* Ignore unknown chars for now */ - } -# if CENV_SYS_MAC - if ((*afd = open(file, flags)) < 0) -# else - if ((*afd = open(file, flags, 0666)) < 0) -# endif - return FALSE; - return TRUE; - -#else -# error "Unimplemented OS routine os_fdopen()" -#endif -} - -int -os_fdclose(osfd_t fd) -{ -#if CENV_SYS_UNIX || CENV_SYS_MAC - return close(fd) != -1; -#else -# error "Unimplemented OS routine os_fdclose()" -#endif -} - -int -os_fdseek(osfd_t fd, osdaddr_t addr) -{ -#if CENV_SYS_UNIX - return lseek(fd, addr, L_SET) != -1; -#elif CENV_SYS_MAC - return lseek(fd, addr, SEEK_SET) != -1; -#else -# error "Unimplemented OS routine os_fdseek()" -#endif -} - -int -os_fdread(osfd_t fd, - char *buf, - size_t len, size_t *ares) -{ -#if CENV_SYS_UNIX - register int res = read(fd, buf, len); - if (res < 0) { - if (ares) *ares = 0; - return FALSE; - } -#elif CENV_SYS_MAC - /* This is actually generic code for any system supporting unix-like - ** calls with a 16-bit integer count interface. - ** --- I don't think the Mac needs this but I'll leave it anyway --Moon - */ - register size_t res = 0; - register unsigned int scnt, sres = 0; - - while (len) { - scnt = len > (1<<14) ? (1<<14) : len; /* 16-bit count each whack */ - if ((sres = read(fd, buf, scnt)) != scnt) { - if (sres == -1) { /* If didn't complete, check for err */ - if (ares) *ares = res; /* Error, but may have read stuff */ - return FALSE; - } - res += sres; /* No error, just update count */ - break; /* and return successfully */ - } - res += sres; - len -= sres; - buf += sres; - } -#else -# error "Unimplemented OS routine os_fdread()" -#endif - if (ares) *ares = res; - return TRUE; -} - -int -os_fdwrite(osfd_t fd, - char *buf, - size_t len, size_t *ares) -{ -#if CENV_SYS_UNIX - register int res = write(fd, buf, len); - if (res < 0) { - if (ares) *ares = 0; - return FALSE; - } -#elif CENV_SYS_MAC - /* This is actually generic code for any system supporting unix-like - ** calls with a 16-bit integer count interface. - ** --- I don't think the Mac needs this but I'll leave it anyway --Moon - */ - register size_t res = 0; - register unsigned int scnt, sres = 0; - - while (len) { - scnt = len > (1<<14) ? (1<<14) : len; /* 16-bit count each whack */ - if ((sres = write(fd, buf, scnt)) != scnt) { - if (sres == -1) { /* If didn't complete, check for err */ - if (ares) *ares = res; /* Error, but may have written stuff */ - return FALSE; - } - res += sres; /* No error, just update count */ - break; /* and return successfully */ - } - res += sres; - len -= sres; - buf += sres; - } -#else -# error "Unimplemented OS routine os_fdwrite()" -#endif - if (ares) *ares = res; - return TRUE; -} - -/* Support for "atomic" intflag reference. -** Intended to work like EXCH, not always truly atomic but -** close enough. As function to prevent optimizing away -** the swap. -*/ -osintf_t -os_swap(osintf_t *addr, int val) -{ - register int tmp = (int)*addr; - *addr = val; - return tmp; -} - - -/* Support for OS real-time clock - -OS Realtime values: - - BSD Unix and SunOS use a timeval structure with two 32-bit -members, tv_sec and tv_usec. The latter is always modulo 1,000,000 -and fits within 20 bits. - - MacOS uses a 64-bit unsigned integer which counts microseconds. - -*/ - -/* OS_RTMGET - Get OS real time -*/ -int -os_rtmget(register osrtm_t *art) -{ -#if CENV_SYSF_BSDTIMEVAL - if (gettimeofday(art, (struct timezone *)NULL) == 0) - return TRUE; - return FALSE; -#elif CENV_SYS_MAC - Microseconds(art); - return TRUE; -#else -# error "Unimplemented OS routine os_rtmget()" -#endif -} - -/* OS_VRTMGET - Get OS virtual (user CPU) time, in same units as real time. -*/ -int -os_vrtmget(register osrtm_t *art) -{ -#if CENV_SYS_SOLARIS /* Precision sucks, but it's all we have */ - struct tms tms; - - if (times(&tms) == 0) { - art->tv_sec = tms.tms_utime / CLK_TCK; - art->tv_usec = (tms.tms_utime % CLK_TCK) - * (1000000/CLK_TCK); /* Turn into usec */ - return TRUE; - } - return FALSE; -#elif CENV_SYSF_BSDTIMEVAL - /* WARNING!!! Some systems turn out not to report getrusage runtime in a - ** monotonically increasing way! This can result in negative deltas - ** from one get to the next. - ** In particular, this was still true of FreeBSD as of 3.3. - ** See quant_freeze() which contains code to check and recover from this - ** regardless of native OS. - */ - struct rusage rus; - - if (getrusage(RUSAGE_SELF, &rus) == 0) { - *art = rus.ru_utime; /* Return user-time used */ - return TRUE; - } - return FALSE; -#elif CENV_SYS_MAC - Microseconds(art); - return TRUE; -#else -# error "Unimplemented OS routine os_vrtmget()" -#endif -} - -/* OS_RTMSUB - Find difference in OS realtime values -** Does A = A - B; -*/ -void -os_rtmsub(register osrtm_t *a, register osrtm_t *b) -{ -#if CENV_SYSF_BSDTIMEVAL - a->tv_sec -= b->tv_sec; - if ((a->tv_usec -= b->tv_usec) < 0) { - --a->tv_sec; - a->tv_usec += 1000000; - } -#elif CENV_SYS_MAC - unsigned long long avalue, bvalue; - avalue = RTM_PTR_TO_LONG_LONG(a); - bvalue = RTM_PTR_TO_LONG_LONG(b); - avalue -= bvalue; - RTM_PTR_TO_LONG_LONG(a) = avalue; -#else -# error "Unimplemented OS routine os_rtmsub()" -#endif -} - -/* OS_RTM_ADJUST_BASE - Convert an OS realtime value between - * relative and absolute time - */ -void -os_rtm_adjust_base(osrtm_t *in, osrtm_t *out, int b_absolute) -{ -#if CENV_SYS_MAC - /* OS realtimes are relative to system boot on MacOS */ - - unsigned long secs; - unsigned long long longusecs, boot_time; - osrtm_t curtime_relative; - - Microseconds(&curtime_relative); - GetDateTime(&secs); - longusecs = (unsigned long long)secs * (unsigned long long)1000000; - boot_time = longusecs - RTM_PTR_TO_LONG_LONG(&curtime_relative); - - if (b_absolute) - { - /* Make a relative time absolute */ - - RTM_PTR_TO_LONG_LONG(out) = RTM_PTR_TO_LONG_LONG(in) + boot_time; - } - else - { - /* Make an absolute time relative */ - - RTM_PTR_TO_LONG_LONG(out) = RTM_PTR_TO_LONG_LONG(in) - boot_time; - } -#else - /* OS realtimes are always absolute on other OS's */ - - *out = *in; -#endif -} - -/* OS_RTM_TO_SECS, OS_RTM_TO_USECS - Simulate Unix format of - * OS realtime value on Macintosh - */ -#if CENV_SYS_MAC -unsigned long os_rtm_to_secs(osrtm_t rtm) -{ - unsigned long long value = RTM_PTR_TO_LONG_LONG(&rtm); - return value / 1000000; -} - -unsigned long os_rtm_to_usecs(osrtm_t rtm) -{ - unsigned long long value = RTM_PTR_TO_LONG_LONG(&rtm); - return value % 1000000; -} -#endif /* CENV_SYS_MAC */ - - -/* OS_TIMER - Set interval timer interrupt, given interval time in usec. -** Note interval is passed as a uint32. This is big enough for -** 4.29 seconds; all known monitors interrupt at a much faster rate! -** If interval is 0, turn timer interrupt off; the caller has to -** make sure it doesn't pass this value unless that is what is intended! -*/ -void -os_timer(int type, - ossighandler_t *irtn, - register uint32 usecs, - ostimer_t *ostate) -{ -#if CENV_SYSF_BSDTIMEVAL - struct itimerval itm; - - if (type != ITIMER_VIRTUAL) - type = ITIMER_REAL; /* Default is real-time */ - if (ostate) - ostate->ostmr_type = type; - - if (usecs == 0) { - /* Turn timer off */ - timerclear(&itm.it_interval); - timerclear(&itm.it_value); - /* Ignore signals prior to clearing interval timer. - ** Used to be SIG_DFL but this created a danger window since default - ** behavior of both signals is to exit process. - */ - (void) osux_sigact(((type == ITIMER_VIRTUAL) ? SIGVTALRM : SIGALRM), - SIG_IGN, - ostate ? &ostate->ostmr_sigact : NULL); - } else { - itm.it_interval.tv_sec = itm.it_value.tv_sec = usecs / 1000000; - itm.it_interval.tv_usec = itm.it_value.tv_usec = usecs % 1000000; - (void) osux_sigact(((type == ITIMER_VIRTUAL) ? SIGVTALRM : SIGALRM), - irtn, - ostate ? &ostate->ostmr_sigact : NULL); - } - - if (setitimer(type, &itm, ostate ? &ostate->ostmr_itm : NULL) != 0) { - panic("os_timer: setitimer() failed - %s", os_strerror(errno)); - } - -#elif CENV_SYS_MAC - /* Use the MacOS Time Manager */ - static interval_timer* timer = NULL; - - if (usecs == 0) - { /* Turn timer off */ - if (timer) stop_interval_timer(timer); - } - else - { /* Turn timer on (create timer on first use) */ - if (timer == NULL) timer = make_interval_timer(irtn); - start_interval_timer(timer, usecs); - }; - -#else -# error "Unimplemented OS routine os_timer()" -#endif -} - -void -os_rtimer(ossighandler_t *irtn, uint32 usecs) -{ - os_timer(OS_ITIMER_REAL, irtn, usecs, (ostimer_t *)NULL); -} - -void -os_vtimer(ossighandler_t *irtn, uint32 usecs) -{ - os_timer(OS_ITIMER_VIRT, irtn, usecs, (ostimer_t *)NULL); -} - -void -os_timer_restore(ostimer_t *ostate) -{ -#if CENV_SYSF_BSDTIMEVAL && CENV_SYSF_SIGSET - sigset_t blkset, savset; - int ret; - - /* Prevent sigs from going off between handler and timer restoration */ - sigfillset(&blkset); - sigprocmask(SIG_BLOCK, &blkset, &savset); - (void) osux_sigrestore(&ostate->ostmr_sigact); - ret = setitimer(ostate->ostmr_type, &ostate->ostmr_itm, NULL); - (void) sigprocmask(SIG_SETMASK, &savset, (sigset_t *)NULL); - if (ret != 0) { - panic("os_timer_restore: setitimer() failed - %s", os_strerror(errno)); - } -#elif CENV_SYS_MAC - /* no Mac code needed --Moon */ -#else -# error "Unimplemented OS routine os_timer_restore()" -#endif -} - - -/* OS_V2RT_IDLE - special function for clk_idle(). -** Idles for an amount of real time equivalent to however much -** virtual time is left until the next clock interrupt. -** Requires various special hackery - seizes SIGALRM and then assumes -** nothing else changes it (or if it does, it gets restored). -** This is to reduce the overhead of setting up the handler every time. -** Note non-modular reference to INSBRKTEST() - may be able to -** flush it if stats show it's rarely a useful test. -** NOTE: perhaps use nanosleep() here if it exists? -*/ -void -os_v2rt_idle(ossighandler_t *hdlarg) -{ -#if CENV_SYSF_BSDTIMEVAL && CENV_SYSF_SIGSET - sigset_t allmsk, oldmsk, nomsk; - struct itimerval ntval, vtval; - static ossighandler_t *handler = NULL; - - if (handler != hdlarg) { /* First time with no handler */ - if (hdlarg) - osux_signal(SIGALRM, (handler = hdlarg)); - else { - /* Forced clearing of handler */ - osux_signal(SIGALRM, SIG_IGN); - handler = NULL; - } - } - - sigfillset(&allmsk); /* Specify all signals */ - sigemptyset(&nomsk); /* Specify no signals */ - sigprocmask(SIG_BLOCK, &allmsk, &oldmsk); /* Block them all */ - timerclear(&ntval.it_interval); - timerclear(&ntval.it_value); - setitimer(ITIMER_VIRTUAL, &ntval, &vtval); /* Find & stop virtual timer */ - if (timerisset(&vtval.it_value)) { - /* Some remaining time left to go in virtual timer. - ** Turn it into a real-time one-shot. - */ - ntval.it_value = vtval.it_value; /* No interv, just one-shot */ - setitimer(ITIMER_REAL, &ntval, (struct itimerval *)NULL); - while (!INSBRKTEST()) { - sigsuspend(&nomsk); /* Wait for interrupt */ - } - /* Done, now restore virtual timer appropriately */ - getitimer(ITIMER_REAL, &ntval); - if (timerisset(&ntval.it_value)) { /* If didn't time out */ - vtval.it_value = ntval.it_value; /* get remaining time */ - timerclear(&ntval.it_value); /* Turn off real-time timer */ - setitimer(ITIMER_REAL, &ntval, (struct itimerval *)NULL); - } else - vtval.it_value = vtval.it_interval; /* Full restart */ - } - setitimer(ITIMER_VIRTUAL, &vtval, (struct itimerval *)NULL); - - sigprocmask(SIG_SETMASK, &oldmsk, (sigset_t *)NULL); - -#elif CENV_SYS_MAC - /* Mac does nothing yet to be nice to other processes --Moon */ -#else -# error "Unimplemented OS routine os_v2rt_idle()" -#endif -} - -/* OS_SLEEP - Sleep for N seconds regardless of signals. -** This must not conflict with the behavior of os_timer(). Certain -** systems may require special hackery to achieve this. -** Currently this is only used by dvni20.c, where it is -** OK to suspend all clock interrupts for the duration of the sleep. -** -** On DEC OSF/1 the sleep() call uses a different mechanism independent -** of SIGALRM, which is good. -** -** Solaris sleep() uses ITIMER_REAL and SIGALRM. This is still true -** as of Solaris 5.8. -** -** On FreeBSD sleep(3) is implemented using nanosleep(2). -*/ -void -os_sleep(int secs) -{ -#if CENV_SYSF_NANOSLEEP - osstm_t stm; - - OS_STM_SET(stm, secs); - while (os_msleep(&stm) > 0) ; - -#elif CENV_SYSF_BSDTIMEVAL - /* Must save & restore ITIMER_REAL & SIGALRM, which conflict w/sleep() */ - ostimer_t savetmr; - - /* Turn off ITIMER_REAL and SIGALRM, saving old state, - do the sleep, then restore the world. - */ - os_timer(OS_ITIMER_REAL, SIG_IGN, 0, &savetmr); - sleep(secs); /* Do the gubbish */ - os_timer_restore(&savetmr); - -#elif CENV_SYS_MAC - /* I don't think the Mac needs this --Moon */ -#else -# error "Unimplemented OS routine os_sleep()" -#endif -} - -/* OS_MSLEEP - Sleep for N milliseconds or until interrupted. -** Returns > 0 if interrupted but time still remains (updates -** its osstm_t arg to indicate time left). -** Returns == 0 if time expired. -** Returns -1 for some other error. -** -** This is typically used where we want to wake up on signals to examine -** our state, but not proceed with KN10 CPU execution until either the -** state is satisfactory or time has expired. -** -** This must not conflict with the behavior of os_timer(). Certain -** systems may require special hackery to achieve this. -** Currently this is only used by dvni20.c and dvtm03.c, where it is -** OK to suspend all clock interrupts for the duration of the sleep. -** -** Where possible this should use POSIX nanosleep(), -** which claims not to interfere with other timers or signals. -** -** Tru64/FreeBSD/NetBSD/Linux support nanosleep(). -** Solaris claims to support nanosleep() but requires link hackery: -** in 5.5: -lposix4 -** in 5.8: -lrt -** -** NOTE: -** On some systems, select() can be used for subsecond timeouts. -** However, whether or not the time remaining is returned is OSD, -** so this cannot be relied on to maintain an overall timeout; -** for that, doing several sleeps may have to suffice. -*/ -int -os_msleep(osstm_t *stm) -{ -#if CENV_SYSF_NANOSLEEP - - if (nanosleep(stm, stm) == 0) { - stm->tv_sec = 0; /* Make sure returns zero */ - stm->tv_nsec = 0; - return 0; - } - return (errno == EINTR) ? 1 : -1; - -#elif CENV_SYS_MAC - /* I don't think the Mac needs this --Moon */ -#else -# error "Unimplemented OS routine os_msleep()" -#endif -} - -#if KLH10_CPU_KS -/* -KS10 Realtime values: - - The KS10 time base is a 71-bit doubleword integer (low sign is -0) that counts at 4.1MHz; i.e. its value increments by 4,100,000 each -second, 4.1 each usec. Each unit is thus 1/4.1 = 0.24390243902439027 usec. - -Comments from KSHACK;KSDEFS: - ; The time is a 71. bit unsigned number. The bottom - ; 12. bits cannot be set. The bottom 2 bits cannot - ; even be read. It increments at 4.1 MHz. The top - ; 59. bits (the ones you can set) thus measure - ; (almost) milliseconds. The top 69. bits (the - ; ones you can read) thus measure "short" - ; microseconds. The time wraps around every 18. - ; million years. To make the top 59. bits actually - ; measure milliseconds, the clock would have to run - ; at 4.096 MHz. However it -really- -does- run at - ; exactly 4.1 MHz! - -A "short microsecond" from the top 69 bits (ignoring the low 2) is: - (1/4.1) * 4 = 0.97560975609756106 usec - -An ITS quantum unit is as close to 4.096 usec as possible. By taking the -top 67 bits (ignoring the low 4) we now have a quantum tick: - (1/4.1) * 16 = 3.9024390243902443 usec - -And this is the derivation of the "3.9 usec tick" in the ITS sources. - -The equation for converting a Unix usec time into KS ticks would be to -compute: - ((tv_sec*1000000)+tv_usec) * 4.1 - - which could be done without floating-point, if one had large enough - integers, as: - (tv_sec * 4100000) + (tv_usec * 4) + (tv_usec / 10) - -For now we'll borrow PDP-10 words and ops to accomplish this. - -*/ - -/* OS_RTM_TOKST - Convert OS realtime ticks into KS ticks -*/ -void -os_rtm_tokst(register osrtm_t *art, - dw10_t *ad) -{ - register dw10_t d; - register w10_t w; - -#if CENV_SYSF_BSDTIMEVAL - LRHSET(w, 017, 0507640); /* 4,100,000. */ - d = op10xmul(w, op10utow(art->tv_sec)); - w = op10utow((int32)((art->tv_usec << 2) + (art->tv_usec / 10))); - op10m_udaddw(d, w); /* Add word into double */ - -#elif CENV_SYS_MAC - unsigned long long value = RTM_PTR_TO_LONG_LONG(art); - value = value * 4 + value / 10; /* microseconds times 4.1 */ - /* Convert 64-bit integer to pdp-10 double-integer format - discarding the sign bit */ - d.w[0].lh = (value >> (35 + 18)) & 0377777; - d.w[0].rh = (value >> 35) & 0777777; - d.w[1].lh = ((value >> 18) & 0377777); - d.w[1].rh = value & 0777777; - -#else -# error "Unimplemented OS routine os_rtm_tokst()" -#endif - *ad = d; -} - - -/* OS_RTM_TOQCT - Convert OS realtime ticks into KS quantum counter ticks (ITS) -** This code assumes it is always given a time interval, not an -** absolute time, and thus 32-bit values should be big enough. -** Note arithmetic is different since we're ignoring the low -** 4 bits of the result; each quantum tick is 16 KS ticks, or -** approx 3.9 usec. -*/ -unsigned long -os_rtm_toqct(register osrtm_t *art) -{ -#if CENV_SYSF_BSDTIMEVAL - return ((unsigned long)(art->tv_sec * 4100000) - + (art->tv_usec << 2) + (art->tv_usec/10)) >> 4; -#elif CENV_SYS_MAC - unsigned long long value = RTM_PTR_TO_LONG_LONG(art); - return (unsigned long)((value * 4 + value / 10) >> 4); -#else -# error "Unimplemented OS routine os_rtm_toqct()" -#endif -} - -#endif /* KLH10_CPU_KS */ - -#if KLH10_CPU_KL - -/* -KL10 Realtime values: - - The KL10 time base hardware counter counts at exactly 1MHz, thus -1 KL tick == 1 usec. - The counter is a 16-bit quantity, thus 32 bits should be quite -sufficient as a return value. The real hardware updates an EPT location -if it overflows, but for our purposes the monitor is always going to -read the time explicitly often enough that overflow should never happen. -See io_rdtime(). - -*/ - -/* OS_RTM_TOKLT - Convert OS realtime ticks into KL ticks (usecs) -*/ -unsigned long -os_rtm_toklt(register osrtm_t *art) -{ -#if CENV_SYSF_BSDTIMEVAL - return ((unsigned long)art->tv_sec * 1000000) + art->tv_usec; -#elif CENV_SYS_MAC - return art->lo; -#else -# error "Unimplemented OS routine os_rtm_toklt()" -#endif -} - -#endif /* KLH10_CPU_KL */ - - -/* Miscellaneous stuff */ - -/* OS_TMGET - Get current real-world time from OS in TM structure. -** This includes a painful timezone computation that is intended to be -** portable for every system implementing the standard {gm,local}time() -** facilities. Unfortunately after many years the standards people STILL -** can't agree on the need for tm_gmtoff, forcing everyone to do contortions -** like this! -** Note this is invoked only by the DTE code during system startup, -** so efficiency is not an issue; also, the timezone is in hours rather -** than minutes or seconds because that's all that the DTE can handle. -** If anything else needs localtime values on a more frequent or precise -** basis, some changes will be needed. -** The time zone that the DTE wants is the TOPS-20 timezone, which is -** represented as the number of hours west of UTC in standard time. For -** example, the west coast of North America is always 8 regardless of -** summer time. There is a separate flag to indicate that summer time is -** in effect. -** This differs from what most people think of as a timezone value, -** which is the number of hours/minutes east of UTC in local time. For -** example, the west coast of North America is -0800 in winter and -0700 -** in summer. -*/ -int -os_tmget(register struct tm *tm, int *zone) -{ - time_t tad; - int julian, zn; - - if (time(&tad) == (time_t)-1) - return 0; - - /* To derive timezone, break TAD down into both local time and GMT (UTC) - * and find the difference between them. This code came from MRC. - */ -#if 1 - if (gmtime_r(&tad, tm) == NULL) - return 0; - zn = tm->tm_hour * 60 + tm->tm_min; - julian = tm->tm_yday; - if (localtime_r(&tad, tm) == NULL) - return 0; /* Some problem */ -#else - /* Alternative code if system doesn't have the _r facilities */ - { - register struct tm *stm; - if (!(stm = gmtime(&tad))) - return 0; - zn = stm->tm_hour * 60 + stm->tm_min; - julian = stm->tm_yday; - if (!(stm = localtime(&tad))) - return 0; /* Some problem */ - *tm = *stm; /* Copy static to dynamic stg */ - } -#endif - /* minus UTC minutes since midnight */ - zn = tm->tm_hour * 60 + tm->tm_min - zn; - /* julian can be one of: - * 36x local time is December 31, UTC is January 1, offset -24 hours - * 1 local time is 1 day ahead of UTC, offset +24 hours - * 0 local time is same day as UTC, no offset - * -1 local time is 1 day behind UTC, offset -24 hours - * -36x local time is January 1, UTC is December 31, offset +24 hours - */ - if (julian = (tm->tm_yday - julian)) - zn += ((julian < 0) == (abs(julian) == 1)) ? -24*60 : 24*60; - - /* At this point zn contains the numer of minutes east of UTC in local - * time. We divide by 60 to get integral hours, negate to make it be - * hours west of UTC, and add one if summer time to get the standard - * time hour offset. - * Resulting zone must be an integral hour. - */ - *zone = -(zn / 60) + (tm->tm_isdst ? 1 : 0); - return 1; -} - -/* Signal handling support, if needed. -** The canonical model for signal handling is BSD, where handlers are -** NOT de-installed when a signal is caught, and system calls are -** restarted when the handler returns. -*/ - -#if CENV_SYS_UNIX - -int -osux_signal(int sig, ossighandler_t *func) -{ - return osux_sigact(sig, func, (ossigact_t *)NULL); -} - -int -osux_sigact(int sig, ossighandler_t *func, ossigact_t *ossa) -{ -#if CENV_SYSF_SIGSET - struct sigaction act; - - act.sa_handler = func; - act.sa_flags = SA_RESTART; - sigemptyset(&act.sa_mask); - sigaddset(&act.sa_mask, sig); /* Suspend this sig during handler */ - if (ossa) - ossa->ossa_sig = sig; - return sigaction(sig, &act, (ossa ? &ossa->ossa_sa : NULL)); -#elif CENV_SYS_BSD - void (*ret)(); - - ret = signal(sig, func); - if (ossa) { - ossa->ossa_sig = sig; - ossa->ossa_handler = func; - } - return (ret == SIG_ERR) ? -1 : 0; -#else -# error "Unimplemented OS routine osux_sigact()" -#endif -} - -int -osux_sigrestore(ossigact_t *ossa) -{ -#if CENV_SYSF_SIGSET - return sigaction(ossa->ossa_sig, - &ossa->ossa_sa, (struct sigaction *)NULL); -#elif CENV_SYS_BSD - return (signal(ossa->ossa_sig, ossa->ossa_handler) == SIG_ERR) - ? -1 : 0; -#else -# error "Unimplemented OS routine osux_sigrestore()" -#endif -} - - -#endif /* CENV_SYS_UNIX */ - -/* Process priority facilities -** -*/ - -int -os_setpriority(ospri_t npri) -{ -#if CENV_SYS_UNIX - if (setpriority(PRIO_PROCESS, 0, npri) == 0) - return TRUE; -#endif - return FALSE; -} - -int -os_getpriority(ospri_t *aopri) -{ -#if CENV_SYS_UNIX - register ospri_t opri; - - errno = 0; - if (((opri = getpriority(PRIO_PROCESS, 0)) != -1) || !errno) { - *aopri = opri; - return TRUE; - } -#endif - return FALSE; -} - -/* Memory Mapping facilities -** These use the SYSV IPC shared memory calls. -** It's becoming increasingly likely that most unices will have them. -** Ugh. Would prefer something like mmap() but it has its own set -** of problems, the most important of which is the fact there is no -** control over pages being (uselessly) written out to disk. -*/ - -int -os_mmcreate(register size_t memsiz, - osmm_t *amm, - char **aptr) -{ -#if CENV_SYS_UNIX && KLH10_DEV_DP - - int shmid; - char *ptr; - - *amm = 0; - *aptr = NULL; - - /* Create a shared mem seg. Set perms to owner-only RW. - ** Note shmget will lose grossly if on a system where its size arg - ** (defined as a u_int) is less than 32 bits! - */ - if ((shmid = shmget(IPC_PRIVATE, (u_int)memsiz, 0600)) == -1) { - fprintf(stderr, "[os_mmcreate: shmget failed for %ld bytes - %s]\n", - (long)memsiz, os_strerror(errno)); - return FALSE; - } - - /* Attempt to attach segment into our address space */ - ptr = (char *)shmat(shmid, (void *)0, SHM_RND); - if (ptr == (char *)-1) { - fprintf(stderr, "[os_mmcreate: shmat failed for %ld bytes - %s]\n", - (long)memsiz, os_strerror(errno)); - - /* Clean up by flushing seg */ - shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL); - return FALSE; - } - - /* Won, return results */ - *amm = shmid; /* Remember shared seg ID */ - *aptr = ptr; - return TRUE; -#else - errno = 0; /* No error, just not implemented */ - return FALSE; -#endif -} - -int -os_mmshare(osmm_t mm, char **aptr) -{ - return 0; /* Nothing for now */ -} - -int -os_mmkill(osmm_t mm, char *ptr) -{ -#if CENV_SYS_UNIX && KLH10_DEV_DP - shmdt((caddr_t)ptr); /* Detach attached segment */ - shmctl(mm, IPC_RMID, /* then try to flush it */ - (struct shmid_ds *)NULL); -#endif - return TRUE; -} - -/* Attempt to lock all of our process memory now and in the future. -*/ -#if CENV_SYS_DECOSF || CENV_SYS_SOLARIS -# include -#endif - -int -os_memlock(int dolock) -{ -#if CENV_SYS_DECOSF || CENV_SYS_SOLARIS - /* Both Solaris and OSF/1 have mlockall() which looks like what we want. - ** It requires being the super-user, but don't bother to check here, - ** just return error if it fails for any reason. - */ - if (dolock) - return (mlockall(MCL_CURRENT+MCL_FUTURE) == 0); - else - return (munlockall() == 0); -#else - return FALSE; -#endif -} - -/* Dynamic/Sharable Library Loading stuff -*/ - -#if CENV_SYS_DECOSF -# include /* Defs for dlopen, dlsym, dlclose, dlerror */ -#endif - -int -os_dlload(FILE *f, /* Report errors here */ - char *path, /* Pathname of loadable lib */ - osdll_t *ahdl, /* Returned handle if any */ - char *isym, /* Init Symbol to look up */ - void **avec) /* Returned symbol address */ -{ -#if CENV_SYS_DECOSF - void *hdl, *vec; - - if (!(hdl = dlopen(path, RTLD_NOW))) { - if (f) - fprintf(f, "Load of \"%s\" failed: %s\n", path, dlerror()); - return FALSE; - } - /* Load won, look up symbol! */ - if (!(vec = dlsym(hdl, isym))) { - if (f) - fprintf(f, "Load of \"%s\" failed, couldn't resolve \"%s\": %s\n", - path, isym, dlerror()); - dlclose(hdl); /* Clean up by flushing it, sigh */ - return FALSE; - } - - /* Everything won, return success! */ - *ahdl = hdl; - *avec = vec; - return TRUE; - -#else /* DLLs not supported */ - if (f) - fprintf(f, "Cannot load \"%s\": Dynamic Libraries not supported\n", - path); - return FALSE; -#endif -} - -int -os_dlunload(FILE *f, osdll_t hdl) -{ -#if CENV_SYS_DECOSF - dlclose(hdl); /* No error return? Foo! */ - return TRUE; /* Hope this worked */ - -#else /* DLLs not supported, never loaded! */ - return TRUE; -#endif -} From aad94caa2f55482aef9bc0e87dbaee4cb963eea7 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 4 May 2015 00:38:33 +0200 Subject: [PATCH 05/18] Fix undefined int swstatus when building enaddr. --- src/enaddr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/enaddr.c b/src/enaddr.c index 9340240..330682c 100644 --- a/src/enaddr.c +++ b/src/enaddr.c @@ -90,6 +90,8 @@ int promiscon = FALSE; /* Desired mode (True = on) */ unsigned char pa_cur[6]; unsigned char pa_def[6]; +int swstatus = 1; + static char *sprinteth(char *, unsigned char *); static void penetaddr(char *ifc, unsigned char *cur, unsigned char *def); static int pareth(char *, unsigned char *); From 9800c5b768388f0417110f1c993b44bea99c6862 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 4 May 2015 00:47:36 +0200 Subject: [PATCH 06/18] Fix some undeclared functions by adding the proper #includes. gcc warned with "warning: incompatible implicit declaration of built-in function 'foo'". --- src/dpsup.c | 1 + src/dvuba.c | 1 + src/enaddr.c | 1 + src/osdsup.c | 1 + 4 files changed, 4 insertions(+) diff --git a/src/dpsup.c b/src/dpsup.c index 417bfde..27272bd 100644 --- a/src/dpsup.c +++ b/src/dpsup.c @@ -40,6 +40,7 @@ static int decosfcclossage; #if KLH10_DEV_DP /* Moby conditional for entire file */ #include +#include #include /* For strerror() if present */ #include "dpsup.h" diff --git a/src/dvuba.c b/src/dvuba.c index 338184d..5f50b76 100644 --- a/src/dvuba.c +++ b/src/dvuba.c @@ -48,6 +48,7 @@ static int decosfcclossage; #if KLH10_CPU_KS /* Moby conditional for entire file */ #include /* For stderr if buggy */ +#include #include "kn10def.h" #include "kn10ops.h" diff --git a/src/enaddr.c b/src/enaddr.c index 330682c..9258a0f 100644 --- a/src/enaddr.c +++ b/src/enaddr.c @@ -52,6 +52,7 @@ #include #include +#include #include #include diff --git a/src/osdsup.c b/src/osdsup.c index 4189ca6..737ee2b 100644 --- a/src/osdsup.c +++ b/src/osdsup.c @@ -44,6 +44,7 @@ */ #include +#include #include /* For strrchr */ #include "klh10.h" From d59d61451cddfe205aad99a6b8451894c3a89ee8 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 4 May 2015 01:07:26 +0200 Subject: [PATCH 07/18] Rename FILE *logf and static void log(char *fmt, ...) because gcc complains about them: vdkfmt.c:133:7: warning: built-in function 'logf' declared as non-function tapedd.c:246:7: warning: built-in function 'logf' declared as non-function enaddr.c:174:13: warning: conflicting types for built-in function 'log' even though it probably should not. has not been included as far as I can see. --- src/enaddr.c | 4 +- src/tapedd.c | 116 +++++++++++++++++++++++++-------------------------- src/vdkfmt.c | 60 +++++++++++++------------- 3 files changed, 90 insertions(+), 90 deletions(-) diff --git a/src/enaddr.c b/src/enaddr.c index 9258a0f..1694f13 100644 --- a/src/enaddr.c +++ b/src/enaddr.c @@ -171,7 +171,7 @@ char *log_strerror(err) -static void log(char *fmt, ...) +static void logit(char *fmt, ...) { fprintf(stderr, "[%s: ", log_progname); { @@ -255,7 +255,7 @@ static void logfatal_ser(int num, char *fmt, ...) #define dp_strerror log_strerror -#define dbprint log +#define dbprint logit #define dbprintln logln #define error logerror #define syserr logerror_ser diff --git a/src/tapedd.c b/src/tapedd.c index a64ca4f..b57ac8c 100644 --- a/src/tapedd.c +++ b/src/tapedd.c @@ -243,7 +243,7 @@ long sw_recskip = 0; long sw_fileskip = 0; rsiz_t sw_bothsiz = 0; char *sw_logpath = NULL; -FILE *logf = NULL; +FILE *logfile = NULL; struct dev { char *d_pname; /* Print name, "In" or "Out" */ @@ -363,7 +363,7 @@ os_strerror(int err) void errhan(void *arg, struct vmtape *t, char *s) { - fprintf(logf, "; %s: %s\n", t->mt_devname, s); + fprintf(logfile, "; %s: %s\n", t->mt_devname, s); } @@ -371,7 +371,7 @@ void efatal(char *errmsg) /* print error message and exit */ /* error message string */ { fflush(stdout); - fprintf(logf, "\n?%s\n",errmsg); + fprintf(logfile, "\n?%s\n",errmsg); exit(1); } @@ -384,7 +384,7 @@ main(int argc, char **argv) register struct dev *d; int ret; - logf = stderr; + logfile = stderr; signal(SIGINT, exit); /* Allow int to terminate log files etc */ vmt_init(&dvi.d_vmt, "TapeIn"); @@ -399,11 +399,11 @@ main(int argc, char **argv) if (!sw_logpath) - logf = stderr; + logfile = stderr; else { - if ((logf = fopen(sw_logpath, "w")) == NULL) { - logf = stderr; - fprintf(logf, "; Cannot open log file \"%s\", using stderr.\n", + if ((logfile = fopen(sw_logpath, "w")) == NULL) { + logfile = stderr; + fprintf(logfile, "; Cannot open log file \"%s\", using stderr.\n", sw_logpath); } } @@ -420,26 +420,26 @@ main(int argc, char **argv) if (!dvo.d_recsiz) dvo.d_recsiz = sw_bothsiz; if (sw_verbose) { #define LOGTAPE(d,name) \ - fprintf(logf, "; %s tape spec \"%s\" (Type: %s", \ + fprintf(logfile, "; %s tape spec \"%s\" (Type: %s", \ name, (d).d_path, mtypstr[(d).d_istape]); \ if ((d).d_istape == MTYP_VIRT) \ - fprintf(logf, " format: %s", vmt_fmtname((d).d_vfmt)); \ - fprintf(logf, ")\n") + fprintf(logfile, " format: %s", vmt_fmtname((d).d_vfmt)); \ + fprintf(logfile, ")\n") LOGTAPE(dvi, " Input"); LOGTAPE(dvo, "Output"); #undef LOGTAPE if (dvi.d_recsiz) - fprintf(logf, "; Input record size %ld\n", (long)dvi.d_recsiz); + fprintf(logfile, "; Input record size %ld\n", (long)dvi.d_recsiz); if (dvo.d_recsiz) - fprintf(logf, "; Output record size %ld\n", (long)dvo.d_recsiz); + fprintf(logfile, "; Output record size %ld\n", (long)dvo.d_recsiz); if (sw_maxfile) - fprintf(logf, "; Max tapemarks (files) to process: %ld\n", sw_maxfile); + fprintf(logfile, "; Max tapemarks (files) to process: %ld\n", sw_maxfile); if (sw_maxrec) - fprintf(logf, "; Max records to process: %ld\n", sw_maxrec); + fprintf(logfile, "; Max records to process: %ld\n", sw_maxrec); if (sw_logpath) - fprintf(logf, "; Using logging path %s\n", sw_logpath); + fprintf(logfile, "; Using logging path %s\n", sw_logpath); } /* Open I/O files as appropriate */ @@ -472,25 +472,25 @@ main(int argc, char **argv) /* Do it! */ - fprintf(logf, "; Copying from \"%s\" to \"%s\"...\n", dvi.d_path, + fprintf(logfile, "; Copying from \"%s\" to \"%s\"...\n", dvi.d_path, dvo.d_path ? dvo.d_path : NULLDEV); if (!docopy()) { - fprintf(logf, "; Stopped unexpectedly.\n"); + fprintf(logfile, "; Stopped unexpectedly.\n"); ret = FALSE; } if (!devclose(&dvo)) { - fprintf(logf, "; Error closing output.\n"); + fprintf(logfile, "; Error closing output.\n"); ret = FALSE; } for (d = &dvi; d; d = (d == &dvi) ? &dvo : NULL) { if (d->d_istape) - fprintf(logf, "; %3s: %ld+%ld errs, %ld files, %ld recs, %" + fprintf(logfile, "; %3s: %ld+%ld errs, %ld files, %ld recs, %" VMTAPE_POS_FMT "d bytes\n", d->d_pname, d->mta_herr, d->mta_serr, d->d_files, d->d_recs, d->d_tloc); } - fclose(logf); + fclose(logfile); exit(ret ? 0 : 1); } @@ -537,7 +537,7 @@ int docopy(void) if (vmt_framecnt(&dvi.d_vmt)) { if (!devwrite(&dvo, dvi.d_buff, (rsiz_t)vmt_framecnt(&dvi.d_vmt))) { - fprintf(logf, "; Stopped due to output write error: %s\n", + fprintf(logfile, "; Stopped due to output write error: %s\n", os_strerror(-1)); ret = FALSE; break; @@ -576,7 +576,7 @@ int docopy(void) } if (err < 0) { - fprintf(logf, "; Stopped due to input read error: %s\n", + fprintf(logfile, "; Stopped due to input read error: %s\n", os_strerror(-1)); ret = FALSE; } @@ -603,11 +603,11 @@ do_tdtest(void) char *errstr = NULL; if (!dvi.d_cpath) { - fprintf(logf, "; No input tape directory specified\n"); + fprintf(logfile, "; No input tape directory specified\n"); return 1; } if (!dvo.d_cpath) { - fprintf(logf, "; No output tape directory specified\n"); + fprintf(logfile, "; No output tape directory specified\n"); return 1; } @@ -629,7 +629,7 @@ do_tdtest(void) } if (errstr) { - fprintf(logf,"; Problem with tape desc file \"%s\": %s\n", + fprintf(logfile,"; Problem with tape desc file \"%s\": %s\n", dvi.d_cpath, errstr); return 1; } @@ -638,7 +638,7 @@ do_tdtest(void) if (strcmp(dvo.d_cpath, "") == 0) { tdof = stdout; } else if ((tdof = fopen(dvo.d_cpath, "w")) == NULL) { - fprintf(logf,"Cannot open tape desc file \"%s\": %s\n", + fprintf(logfile,"Cannot open tape desc file \"%s\": %s\n", dvo.d_cpath, os_strerror(-1)); return FALSE; } @@ -880,7 +880,7 @@ int devopen(register struct dev *d, int wrtf) strncpy(v.vmta_datpath, d->d_rpath, sizeof(v.vmta_datpath)); } if (!vmt_attrmount(&d->d_vmt, &v)) { /* Try mounting it */ - fprintf(logf, "; Couldn't mount %sput virtual tape: %s\n", + fprintf(logfile, "; Couldn't mount %sput virtual tape: %s\n", d->d_pname, d->d_path); return FALSE; } @@ -898,7 +898,7 @@ int devopen(register struct dev *d, int wrtf) char *s; rpath = malloc(strlen(d->d_path)+4+1); if (!rpath) { - fprintf(logf, "; Cannot malloc data filename\n"); + fprintf(logfile, "; Cannot malloc data filename\n"); return FALSE; } strcpy(rpath, d->d_path); @@ -915,7 +915,7 @@ int devopen(register struct dev *d, int wrtf) ** the tapedesc or rawdata path was explicitly given. */ if (!vmt_xmount(&(d->d_vmt), d->d_cpath, d->d_rpath, wrtf)) { - fprintf(logf, "; Couldn't mount %sput virtual tape: %s\n", + fprintf(logfile, "; Couldn't mount %sput virtual tape: %s\n", d->d_pname, d->d_path); return FALSE; } @@ -937,7 +937,7 @@ int devopen(register struct dev *d, int wrtf) if (strcmp(d->d_rpath, "") == 0) { d->d_fd = wrtf ? FD_STDOUT : FD_STDIN; } else if (!os_mtopen(d, wrtf)) { - fprintf(logf, "; Cannot open %sput: %s\n", + fprintf(logfile, "; Cannot open %sput: %s\n", d->d_pname, os_strerror(-1)); return FALSE; } @@ -962,27 +962,27 @@ int devopen(register struct dev *d, int wrtf) if (d->d_cpath) { if (!(d->d_vmt.mt_filename = dupcstr(d->d_cpath))) { - fprintf(logf, "; malloc failed for cpath dupcstr\n"); + fprintf(logfile, "; malloc failed for cpath dupcstr\n"); return FALSE; } if (strcmp(d->d_cpath, "") == 0) { d->d_vmt.mt_ctlf = (wrtf ? stdout : stdin); } else if ((d->d_vmt.mt_ctlf = fopen(d->d_cpath, (wrtf ? "w" : "r"))) == NULL) { - fprintf(logf,"Cannot open tape desc file \"%s\": %s\n", + fprintf(logfile,"Cannot open tape desc file \"%s\": %s\n", d->d_cpath, os_strerror(-1)); return FALSE; } /* Tape-desc file open, now parse it if reading */ if (!wrtf && !tdr_scan(&(d->d_vmt), d->d_vmt.mt_ctlf, d->d_cpath)) { - fprintf(logf, "; Cannot parse tape desc\n"); + fprintf(logfile, "; Cannot parse tape desc\n"); return FALSE; } /* Do final setup if writing */ if (wrtf && d->d_rpath) { if (!(d->d_vmt.mt_datpath = dupcstr(d->d_rpath))) { - fprintf(logf, "; malloc failed for rpath dupcstr\n"); + fprintf(logfile, "; malloc failed for rpath dupcstr\n"); return FALSE; } } @@ -997,7 +997,7 @@ int devopen(register struct dev *d, int wrtf) if (d->d_blen <= d->d_recsiz) /* If it's bigger, */ d->d_blen = d->d_recsiz; /* adjust quietly */ else /* else warn user */ - fprintf(logf, "; Tapedir forcing larger %sput record size (%ld instead of %ld)\n", + fprintf(logfile, "; Tapedir forcing larger %sput record size (%ld instead of %ld)\n", d->d_pname, (long)d->d_blen, (long)d->d_recsiz); } @@ -1029,7 +1029,7 @@ int devbuffer(struct dev *d, char *buffp, rsiz_t blen) */ blen = (blen + 511) & ~511; /* Relies on fact 512 is power of 2 */ if ((buffp = malloc(blen)) == NULL) { - fprintf(logf, "; Cannot malloc %sput buffer (size %ld)\n", + fprintf(logfile, "; Cannot malloc %sput buffer (size %ld)\n", d->d_pname, blen); return FALSE; } @@ -1091,7 +1091,7 @@ int devread(struct dev *d) /* Still to do? Handle dir-only case, plus dir+dev case? */ ret = os_mtread(d); /* Attempt read from device */ if (ret < 0) { - fprintf(logf, "; %sput device read error: %s\n", + fprintf(logfile, "; %sput device read error: %s\n", d->d_pname, os_strerror(-1)); return ret; } @@ -1161,7 +1161,7 @@ int devwerr(struct dev *d, int err) if (d->d_cpath) { /* Have tapedir? */ if (!td_recapp(&d->d_vmt.mt_tdr, (long)0, 0, err)) { - fprintf(logf, "devwerr: td_recapp malloc failed"); + fprintf(logfile, "devwerr: td_recapp malloc failed"); return FALSE; } @@ -1178,7 +1178,7 @@ int devweof(struct dev *d) else { if (d->d_cpath) { /* Have tapedir? */ if (!td_recapp(&d->d_vmt.mt_tdr, (long)0, 1, 0)) { - fprintf(logf, "devweof: td_recapp malloc failed"); + fprintf(logfile, "devweof: td_recapp malloc failed"); ret = FALSE; } } @@ -1276,7 +1276,7 @@ int os_mtread(struct dev *dp) acs[1] = dp->d_fd; acs[2] = (int)&iov; if (jsys(DUMPI, acs) > 0) { - fprintf(logf, "; Warning: DUMPI won for max rec size %ld!\n", + fprintf(logfile, "; Warning: DUMPI won for max rec size %ld!\n", (long)dp->d_blen); dp->mta_frms = dp->d_blen; return 1; @@ -1287,14 +1287,14 @@ int os_mtread(struct dev *dp) case monsym("IOX5"): /* Device or data error (rec length) */ acs[1] = dp->d_fd; if (jsys(GDSTS, acs) <= 0) { - fprintf(logf, "; Tape GDSTS%% error: %s\n", os_strerror(-1)); + fprintf(logfile, "; Tape GDSTS%% error: %s\n", os_strerror(-1)); os_mtclrerr(dp->d_fd); dp->mta_herr++; return 0; } break; default: - fprintf(logf, "; Tape DUMPI%% error: %s\n", os_strerror(-1)); + fprintf(logfile, "; Tape DUMPI%% error: %s\n", os_strerror(-1)); os_mtclrerr(dp->d_fd); dp->mta_herr++; return 0; @@ -1302,7 +1302,7 @@ int os_mtread(struct dev *dp) /* Analyze "error". acs[2] has flags, [3] has count in LH */ flgs = acs[2]; - t20status(dp, logf, flgs, acs[3]); + t20status(dp, logfile, flgs, acs[3]); dp->mta_frms = ((unsigned)acs[3]) >> 18; /* Find cnt of data */ /* Opening in industry-compatible mode apparently works to force use of @@ -1310,7 +1310,7 @@ int os_mtread(struct dev *dp) /* dp->mta_frms *= sizeof(int); */ os_mtclrerr(dp->d_fd); if (flgs & (MT_DVE|MT_DAE)) { - fprintf(logf, "; Tape error: %s\n", + fprintf(logfile, "; Tape error: %s\n", (flgs & MT_DVE) ? "Device" : "Data"); dp->mta_serr++; continue; /* Try again */ @@ -1339,14 +1339,14 @@ int os_mtread(struct dev *dp) if (dp->mta_frms <= 0) { case -1: /* Error */ dp->mta_serr++; - fprintf(logf, "; Tape read error: %s\n", os_strerror(-1)); - os_mtstatus(dp, logf); /* Show full status */ + fprintf(logfile, "; Tape read error: %s\n", os_strerror(-1)); + os_mtstatus(dp, logfile); /* Show full status */ if (retry <= 0) { if (os_mtfsr(dp)) { /* Try spacing over 1 rec */ retry = dp->mta_retry; dp->mta_herr++; } else { - fprintf(logf, "; Cannot proceed past read error, aborting...\n"); + fprintf(logfile, "; Cannot proceed past read error, aborting...\n"); return -1; } } @@ -1365,7 +1365,7 @@ int os_mtread(struct dev *dp) } } else if (dp->mta_frms >= dp->d_blen) - fprintf(logf, "; Warning: read max rec size %ld!\n", + fprintf(logfile, "; Warning: read max rec size %ld!\n", dp->mta_frms); @@ -1397,7 +1397,7 @@ int os_mtwrite(struct dev *dp) } /* Error return */ dp->mta_serr++; - fprintf(logf, "; Tape DUMPO%% error: %s\n", os_strerror(-1)); + fprintf(logfile, "; Tape DUMPO%% error: %s\n", os_strerror(-1)); os_mtclrerr(dp->d_fd); dp->mta_herr++; return 0; @@ -1415,10 +1415,10 @@ int os_mtwrite(struct dev *dp) if (dp->d_istape == MTYP_QIC) { full = (used + 0777) & ~0777; /* Round up to 512-byte boundary */ if (used < dp->d_recsiz) - fprintf(logf, "; Warning: partial record padded out (%ld => %ld)\n", + fprintf(logfile, "; Warning: partial record padded out (%ld => %ld)\n", (long)used, (long)full); if (full > dp->d_blen) { - fprintf(logf, "; Internal bug: padout exceeds buffer (%ld > %ld)\n", + fprintf(logfile, "; Internal bug: padout exceeds buffer (%ld > %ld)\n", (long)full, (long)dp->d_blen); full = dp->d_blen; } @@ -1437,12 +1437,12 @@ int os_mtwrite(struct dev *dp) } /* Error of some kind */ dp->mta_serr++; - fprintf(logf, "; (Rec %ld, try %d) ", + fprintf(logfile, "; (Rec %ld, try %d) ", dp->d_recs, dp->mta_retry - retry); if (ret < 0) { - fprintf(logf, "Tape write error: %s\n", os_strerror(-1)); + fprintf(logfile, "Tape write error: %s\n", os_strerror(-1)); } else { - fprintf(logf, "Tape write truncated: %d, shd be %ld\n", + fprintf(logfile, "Tape write truncated: %d, shd be %ld\n", ret, (long)used); if (ret > 0) { used -= ret; /* Update to write out rest */ @@ -1452,7 +1452,7 @@ int os_mtwrite(struct dev *dp) dp->mta_frms += ret; } } - os_mtstatus(dp, logf); /* Show full status */ + os_mtstatus(dp, logfile); /* Show full status */ } while (--retry > 0); /* Continue N times */ dp->mta_herr++; #endif @@ -1471,7 +1471,7 @@ int os_mtweof(struct dev *dp) /* Write a tapemark */ mtcmd.mt_op = MTWEOF; mtcmd.mt_count = 1; if (ioctl(dp->d_fd, MTIOCTOP, &mtcmd) < 0) { - fprintf(logf, "; MTWEOF ioctl failed: %s\n", os_strerror(-1)); + fprintf(logfile, "; MTWEOF ioctl failed: %s\n", os_strerror(-1)); dp->mta_herr++; return FALSE; } @@ -1491,7 +1491,7 @@ int os_mtfsr(struct dev *dp) /* Forward Space Record (to inter-record gap)*/ mtcmd.mt_op = MTFSR; mtcmd.mt_count = 1; if (ioctl(dp->d_fd, MTIOCTOP, &mtcmd) < 0) { - fprintf(logf, "; MTFSR ioctl failed: %s\n", os_strerror(-1)); + fprintf(logfile, "; MTFSR ioctl failed: %s\n", os_strerror(-1)); dp->mta_herr++; return FALSE; } diff --git a/src/vdkfmt.c b/src/vdkfmt.c index b95f6de..7cb06d4 100644 --- a/src/vdkfmt.c +++ b/src/vdkfmt.c @@ -130,7 +130,7 @@ int sw_verbose; int sw_maxsec; int sw_maxfile; char *sw_logpath; -FILE *logf; +FILE *logfile; #define DBGFLG sw_verbose @@ -244,7 +244,7 @@ os_strerror(int err) void errhan(struct vdk_unit *t, char *s) { - fprintf(logf, "; %s: %s\n", t->dk_devname, s); + fprintf(logfile, "; %s: %s\n", t->dk_devname, s); } @@ -252,7 +252,7 @@ void efatal(char *errmsg) /* print error message and exit */ /* error message string */ { fflush(stdout); - fprintf(logf, "\n?%s\n",errmsg); + fprintf(logfile, "\n?%s\n",errmsg); exit(1); } @@ -262,7 +262,7 @@ main(int argc, char **argv) { int ret; - logf = stderr; + logfile = stderr; signal(SIGINT, exit); /* Allow int to terminate log files etc */ dvi.d_fmt = dvo.d_fmt = -1; @@ -272,11 +272,11 @@ main(int argc, char **argv) if (!sw_logpath) - logf = stderr; + logfile = stderr; else { - if ((logf = fopen(sw_logpath, "w")) == NULL) { - logf = stderr; - fprintf(logf, "; Cannot open log file \"%s\", using stderr.\n", + if ((logfile = fopen(sw_logpath, "w")) == NULL) { + logfile = stderr; + fprintf(logfile, "; Cannot open log file \"%s\", using stderr.\n", sw_logpath); } } @@ -287,23 +287,23 @@ main(int argc, char **argv) dvi.d_dcf.dcf_ntrk * dvi.d_dcf.dcf_ncyl; if (sw_verbose) { - fprintf(logf, "; Input disk spec \"%s\" (Type: %s) Format: %s\n", + fprintf(logfile, "; Input disk spec \"%s\" (Type: %s) Format: %s\n", dvi.d_path, mtypstr[dvi.d_isdisk], fmttab[dvi.d_fmt]); - fprintf(logf, "; Output disk spec \"%s\" (Type: %s) Format: %s\n", + fprintf(logfile, "; Output disk spec \"%s\" (Type: %s) Format: %s\n", dvo.d_path, mtypstr[dvo.d_isdisk], fmttab[dvo.d_fmt]); /* Show config info here */ - fprintf(logf, "; Drive type: %s\n", dvi.d_dcf.dcf_name); - fprintf(logf, "; %ld sectors, %d wds/sec\n", dvi.d_totsec, + fprintf(logfile, "; Drive type: %s\n", dvi.d_dcf.dcf_name); + fprintf(logfile, "; %ld sectors, %d wds/sec\n", dvi.d_totsec, dvi.d_dcf.dcf_nwds); - fprintf(logf, "; (%d secs, %d trks, %d cyls\n", + fprintf(logfile, "; (%d secs, %d trks, %d cyls\n", dvi.d_dcf.dcf_nsec, dvi.d_dcf.dcf_ntrk, dvi.d_dcf.dcf_ncyl); if (sw_logpath) - fprintf(logf, "; Using logging path %s\n", sw_logpath); + fprintf(logfile, "; Using logging path %s\n", sw_logpath); } /* Open I/O files as appropriate */ @@ -313,27 +313,27 @@ main(int argc, char **argv) exit(1); /* Do it! */ - fprintf(logf, "; Copying from \"%s\" to \"%s\"...\n", dvi.d_path, + fprintf(logfile, "; Copying from \"%s\" to \"%s\"...\n", dvi.d_path, dvo.d_path ? dvo.d_path : NULLDEV); if (ret = docopy()) ret = devclose(&dvo); else (void) devclose(&dvo); - if (!ret) fprintf(logf, "; Stopped unexpectedly.\n"); + if (!ret) fprintf(logfile, "; Stopped unexpectedly.\n"); #if 0 { register struct devdk *d; for (d = &dvi; d; d = (d == &dvi) ? &dvo : NULL) { if (d->d_isdisk) - fprintf(logf, "; %s: %d+%d errs, %d secs, %ld bytes\n", + fprintf(logfile, "; %s: %d+%d errs, %d secs, %ld bytes\n", d->d_pname, d->mta_herr, d->mta_serr, d->d_secs, d->d_tloc); } } #endif - fclose(logf); + fclose(logfile); exit(ret ? 0 : 1); } @@ -347,13 +347,13 @@ int docopy(void) int nwrt = 0; if (DBGFLG) - fprintf(logf, "; Pages:\n"); + fprintf(logfile, "; Pages:\n"); for (; nsect <= dvi.d_totsec;) { err = devread(&dvi, nsect, wbuff); /* Get a sector */ if (!err) { - fprintf(logf, "; Aborting loop, last err: %s\n", os_strerror(-1)); + fprintf(logfile, "; Aborting loop, last err: %s\n", os_strerror(-1)); return 0; } @@ -366,7 +366,7 @@ int docopy(void) nwrt++; err = devwrite(&dvo, nsect, wbuff); /* Write a sector */ if (!err) { - fprintf(logf, "; Aborting loop, last err: %s\n", + fprintf(logfile, "; Aborting loop, last err: %s\n", os_strerror(-1)); return 0; } @@ -377,14 +377,14 @@ int docopy(void) /* Hack to show nice pattern, one char per 4-sector page */ if (DBGFLG) { if ((nsect & 03) == 0) { - putc(pagsym[nwrt&03], logf); + putc(pagsym[nwrt&03], logfile); nwrt = 0; } } } if (DBGFLG) - fprintf(logf, "\n"); + fprintf(logfile, "\n"); return TRUE; } @@ -515,7 +515,7 @@ int devopen(register struct devdk *d, int wrtf) char *opath, *path; if (!(opath = d->d_path) || !*opath) { - fprintf(logf, "; Null mount path\n"); + fprintf(logfile, "; Null mount path\n"); return FALSE; } path = malloc(strlen(opath)+1); @@ -532,7 +532,7 @@ int devopen(register struct devdk *d, int wrtf) d->d_vdk.dk_nwds = d->d_dcf.dcf_nwds; if (!vdk_mount(&(d->d_vdk), path, wrtf)) { - fprintf(logf, "; Cannot mount device \"%s\": %s\n", + fprintf(logfile, "; Cannot mount device \"%s\": %s\n", path, os_strerror(d->d_vdk.dk_err)); free(path); return FALSE; @@ -547,7 +547,7 @@ int devclose(struct devdk *d) int res = TRUE; if (DBGFLG && d->d_path) - fprintf(logf, "; Closing \"%s\"\n", d->d_path); + fprintf(logfile, "; Closing \"%s\"\n", d->d_path); if (d->d_isdisk) { res = vdk_unmount(&(d->d_vdk)); /* Close real disk */ @@ -570,14 +570,14 @@ int devread(struct devdk *d, long int daddr, w10_t *buff) #if 0 if (DBGFLG) - fprintf(logf, "; read daddr=%ld\n", daddr); + fprintf(logfile, "; read daddr=%ld\n", daddr); #endif nsec = vdk_read(&d->d_vdk, buff, (uint32)daddr, 1); if (d->d_vdk.dk_err || (nsec != 1)) { - fprintf(logf, "; read error on %s: %s\n", + fprintf(logfile, "; read error on %s: %s\n", d->d_vdk.dk_filename, os_strerror(d->d_vdk.dk_err)); return FALSE; } @@ -592,14 +592,14 @@ int devwrite(struct devdk *d, long int daddr, w10_t *buff) #if 0 if (DBGFLG) - fprintf(logf, "; write daddr=%ld\n", daddr); + fprintf(logfile, "; write daddr=%ld\n", daddr); #endif nsec = vdk_write(&d->d_vdk, buff, (uint32)daddr, 1); if (d->d_vdk.dk_err || (nsec != 1)) { - fprintf(logf, "; write error on %s: %s\n", + fprintf(logfile, "; write error on %s: %s\n", d->d_vdk.dk_filename, os_strerror(d->d_vdk.dk_err)); return FALSE; } From 52e89809fc6d43e16d09281e945b38337c9ae51e Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 4 May 2015 01:08:45 +0200 Subject: [PATCH 08/18] Add handy building script. --- bld/MAKE-ALL | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 bld/MAKE-ALL diff --git a/bld/MAKE-ALL b/bld/MAKE-ALL new file mode 100755 index 0000000..8bbcc41 --- /dev/null +++ b/bld/MAKE-ALL @@ -0,0 +1,34 @@ +#!/bin/sh + +# TOP=/some/where/klh10 +# Removed "/bld" from current directory, if it's there +TOP="${PWD%/bld}" +BUILD=nbaxp + +cd $TOP || exit 1 + +echo "This script builds all PDP-10 variants." + +buildone() { +( + model="$1" + + export KLH10_HOME=$TOP/new/${BUILD}-${model} + mkdir -p ${KLH10_HOME} + cd bld/$BUILD + make clean + make base-${model} CONFFLAGS_AUX=-DKLH10_I_CIRC=1 + make tapedd vdkfmt wxtest enaddr + make install +) +} + +echo "Building KL" +buildone kl + +echo "Building KS" +buildone ks + +echo "Building KS-ITS" +buildone ks-its + From b9fcfeab377dedb40113a00c95103de776b327c6 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:16:26 +0200 Subject: [PATCH 09/18] Make build script more useful by making it guess the build type from the directory you're in. Alternatively you can override it on the command line. --- bld/MAKE-ALL | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/bld/MAKE-ALL b/bld/MAKE-ALL index 8bbcc41..5ea7016 100755 --- a/bld/MAKE-ALL +++ b/bld/MAKE-ALL @@ -1,13 +1,34 @@ #!/bin/sh +# +# Simple build script to build all 3 cpu models in one go. +# +# Usage: MAKE-ALL buildtarget +# +# where buildtarget is for example nbaxp (NetBSD for Alpha AXP, or +# any other little-endian 64-bit CPU). + +DEFBUILD=nbaxp # TOP=/some/where/klh10 # Removed "/bld" from current directory, if it's there -TOP="${PWD%/bld}" -BUILD=nbaxp +case "${PWD}" in + */bld) + TOP="${PWD%/bld}" + ;; + */bld/*) + DEFBUILD="${PWD##*/}" + TOP="${PWD%/bld/*}" + ;; + *) + TOP="$PWD" + ;; +esac + +BUILD=${1-$DEFBUILD} cd $TOP || exit 1 -echo "This script builds all PDP-10 variants." +echo "This script builds all PDP-10 variants for host $BUILD." buildone() { ( From c948e8efff93b028f06980e296f6d4af4e9cc100 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:18:05 +0200 Subject: [PATCH 10/18] moved to . --- src/dvlites.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dvlites.c b/src/dvlites.c index 807a6cb..243fca7 100644 --- a/src/dvlites.c +++ b/src/dvlites.c @@ -31,7 +31,7 @@ static int decosfcclossage; #if KLH10_DEV_LITES /* Moby conditional for entire file */ -#include +#include #include "dvlites.h" From 5365b5845a660b792924347efe36585a817e95f5 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:18:43 +0200 Subject: [PATCH 11/18] Conditionalize a debug message that doesn't compile on Linux. --- src/osdnet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/osdnet.c b/src/osdnet.c index 96e0093..8c9dd52 100644 --- a/src/osdnet.c +++ b/src/osdnet.c @@ -403,13 +403,15 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) fprintf(f, "sizeof struct ifreq = %d\r\n", (int) sizeof(struct ifreq)); fprintf(f, "IFNAMSIZ = %d\r\n", (int) IFNAMSIZ); +#if CENV_SYS_NETBSD fprintf(f, "offset of struct sockaddr_storage = %d\r\n", (int) offsetof(struct ifreq, ifr_space)); +#endif fprintf(f, "sizeof struct sockaddr = %d\r\n", (int) sizeof(struct sockaddr)); fprintf(f, "sizeof struct sockaddr_storage = %d\r\n", (int) sizeof(struct sockaddr_storage)); fprintf(f, "sizeof union ifr_ifru = %d\r\n", (int) sizeof(ifr->ifr_ifru)); fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\r\n", - (long)ifc->ifc_len, ifc->ifc_len/sizeof(struct ifreq), + (long)ifc->ifc_len, (int)(ifc->ifc_len/sizeof(struct ifreq)), (int)sizeof(struct sockaddr)); ifr = ifc->ifc_req; From 4a29858bbfedd616e0f5bf575796cc1f47df69b6 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:20:29 +0200 Subject: [PATCH 12/18] Remove extra arguments to printf(). These are presumably block numbers but they get printed earlier anyway. --- src/kn10dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kn10dev.c b/src/kn10dev.c index f4458d3..daae37d 100644 --- a/src/kn10dev.c +++ b/src/kn10dev.c @@ -1348,7 +1348,7 @@ dev_boot(FILE *of, return FALSE; if (op10m_camn(vm_pget(vp), w6hom)) { if (of) fprintf(of, "Bad HOM check, val = %lo,,%lo\n", - 1, (long)LHGET(w), (long)RHGET(w)); + (long)LHGET(w), (long)RHGET(w)); return FALSE; } if (of) fprintf(of, "OK\nReading HOM sector 010 ..."); @@ -1357,7 +1357,7 @@ dev_boot(FILE *of, return FALSE; if (op10m_camn(vm_pget(vp), w6hom)) { if (of) fprintf(of, "Bad HOM check, val = %lo,,%lo\n", - 010, (long)LHGET(w), (long)RHGET(w)); + (long)LHGET(w), (long)RHGET(w)); return FALSE; } w = vm_pget(vm_physmap(FE_BOOTLOC+0103)); /* Get ptrs pag addr */ From dafe65141acc67b80626efebcfe381702aa38924 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:21:14 +0200 Subject: [PATCH 13/18] Make sure printf() arguments are of the right size. Apparently they have a different size on Linux. --- src/tapedd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tapedd.c b/src/tapedd.c index b57ac8c..008cb4a 100644 --- a/src/tapedd.c +++ b/src/tapedd.c @@ -1546,7 +1546,7 @@ void os_mtstatus(struct dev *dp, FILE *f) return; } fprintf(f, "; Status for magtape %s:\n", dp->d_path); - fprintf(f, "; Type: %#x (vals in sys/mtio.h)\n", mtstatb.mt_type); + fprintf(f, "; Type: %#x (vals in sys/mtio.h)\n", (int)mtstatb.mt_type); # if CENV_SYS_SUN fprintf(f, "; Flags: %#o ->", mtstatb.mt_flags); if (mtstatb.mt_flags & MTF_SCSI) fprintf(f, " SCSI"); @@ -1556,8 +1556,8 @@ void os_mtstatus(struct dev *dp, FILE *f) fprintf(f, "; Optim blkfact: %d\n", mtstatb.mt_bf); # endif - fprintf(f, "; Drive status: %#o (dev dep)\n", mtstatb.mt_dsreg); - fprintf(f, "; Error status: %#o (dev dep)\n", mtstatb.mt_erreg); + fprintf(f, "; Drive status: %#o (dev dep)\n", (int)mtstatb.mt_dsreg); + fprintf(f, "; Error status: %#o (dev dep)\n", (int)mtstatb.mt_erreg); fprintf(f, "; Err - Cnt left: %ld\n", (long)mtstatb.mt_resid); # if CENV_SYS_SUN fprintf(f, "; Err - File num: %ld\n", (long)mtstatb.mt_fileno); From 800d799b340e536724e2ed0a5686975ad01fc2a0 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:21:37 +0200 Subject: [PATCH 14/18] Fix usage printing. --- src/uexbconv.c | 2 +- src/wfconv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uexbconv.c b/src/uexbconv.c index fe3d3fa..ea48adc 100644 --- a/src/uexbconv.c +++ b/src/uexbconv.c @@ -97,7 +97,7 @@ main(int argc, char **argv) switch (arg[1]) { case 'v': swverb = 1; break; default: - fprintf(stderr, usage); + fprintf(stderr, usage, argv[0]); exit(1); } } diff --git a/src/wfconv.c b/src/wfconv.c index 98d41ed..c0b0196 100644 --- a/src/wfconv.c +++ b/src/wfconv.c @@ -84,7 +84,7 @@ main(int argc, char **argv) w10_t w; if (argc != 2 || strlen(typestr = argv[1]) != 3) { - fprintf(stderr, usage); + fprintf(stderr, "%s", usage); exit(1); } if (typestr[0] != '-' From 6c0cbe0f91b419808c49a6d63f886190db098f42 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 02:40:46 +0200 Subject: [PATCH 15/18] Improve comment. --- bld/MAKE-ALL | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bld/MAKE-ALL b/bld/MAKE-ALL index 5ea7016..88ae4d3 100755 --- a/bld/MAKE-ALL +++ b/bld/MAKE-ALL @@ -10,7 +10,13 @@ DEFBUILD=nbaxp # TOP=/some/where/klh10 -# Removed "/bld" from current directory, if it's there + +# Remove "/bld" or "/bld/nbaxp" from current directory, if it's there. +# In the latter case, assume that as the build type by default. +# If none of these current directories apply, this script must be run +# from the $TOP directory, and the build will be for the host as +# indicated on the command line, or nbaxp by default. + case "${PWD}" in */bld) TOP="${PWD%/bld}" From b03241657d17066226da22eac3b7c74707726906 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sat, 18 Jul 2015 03:14:59 +0200 Subject: [PATCH 16/18] Add two helper scripts to put xterms in a nice mood for ITS. --- run/ksits/setvt100 | 12 ++++++++++++ run/ksits/setvt52 | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100755 run/ksits/setvt100 create mode 100755 run/ksits/setvt52 diff --git a/run/ksits/setvt100 b/run/ksits/setvt100 new file mode 100755 index 0000000..8ebcf35 --- /dev/null +++ b/run/ksits/setvt100 @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a shell script for running in an XTerm +# to set the opposite of the settings from the setvt52 script. + +# Reverse the settings from setvt52 (SET <-> RESET) +printf '\e< ' # Exit VT52 mode (Enter VT100 mode). + +printf '\e[?67h' # Ps = 6 7 -> Backarrow key sends delete (DECBKM) + +printf '\e[?1036h' # Ps = 1 0 3 6 -> Send ESC when Meta modifies a key (enables the metaSendsEscape resource). + +stty intr ^C diff --git a/run/ksits/setvt52 b/run/ksits/setvt52 new file mode 100755 index 0000000..50fc951 --- /dev/null +++ b/run/ksits/setvt52 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# This is a shell script for running in an XTerm +# to set it to better modes to run ITS in: +# +# - VT52 mode; +# - the backarrow key sends DEL (not backspace); +# - the meta key sends ESC before a key instead of setting its 8th bit; +# - correct terminal size. + +printf '\e< ' # Exit VT52 mode (Enter VT100 mode). + # CSI ? Pm l DEC Private Mode Reset (DECRST) +printf '\e[?67l' # Ps = 6 7 -> Backarrow key sends delete (DECBKM) + + # CSI ? Pm h DEC Private Mode Set (DECSET) +printf '\e[?1036l' # Ps = 1 0 3 6 -> Send ESC when Meta modifies a key + # (enables the metaSendsEscape resource). + + # CSI Ps ; Ps ; Ps t Window manipulation + # May be disabled using the allowWindowOps resource. +printf '\e[8;24;80t' # Ps = 8 ; height ; width -> Resize the text area to [height;width] in characters. +printf '\e[?2l' # Ps = 2 -> Designate VT52 mode (DECANM). + +# After this, run ITS, then setvt100. From 06caf9770da8eb81e3e2247df158a01772a16315 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sun, 19 Jul 2015 15:56:09 +0200 Subject: [PATCH 17/18] Add a Linux AXP target (also usable for amd64 aka x86_64 hosts) so that the USEINT memory model can be used, rather than the USEHWD model that gets used for 32-bit i386. --- bld/lnaxp/Makefile | 1 + src/Mk-lnaxp.mk | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 120000 bld/lnaxp/Makefile create mode 100644 src/Mk-lnaxp.mk diff --git a/bld/lnaxp/Makefile b/bld/lnaxp/Makefile new file mode 120000 index 0000000..0ce20c9 --- /dev/null +++ b/bld/lnaxp/Makefile @@ -0,0 +1 @@ +../../src/Mk-lnaxp.mk \ No newline at end of file diff --git a/src/Mk-lnaxp.mk b/src/Mk-lnaxp.mk new file mode 100644 index 0000000..891ec9a --- /dev/null +++ b/src/Mk-lnaxp.mk @@ -0,0 +1,45 @@ +# KLH10 Makefile for Linux on i386 +# $Id: Mk-lnx86.mk,v 2.5 2002/04/24 18:03:04 klh Exp $ +# +# Copyright © 2001 Kenneth L. Harrenstien +# All Rights Reserved +# +# This file is part of the KLH10 Distribution. Use, modification, and +# re-distribution is permitted subject to the terms in the file +# named "LICENSE", which contains the full text of the legal notices +# and should always accompany this Distribution. +# +# This software is provided "AS IS" with NO WARRANTY OF ANY KIND. +# +# This notice (including the copyright and warranty disclaimer) +# must be included in all copies or derivations of this software. +# +##################################################################### + +# Local config setup, for GNU "make"! +# Recursively invokes make with right params for local platform. + +# Build definitions +SRC = ../../src +CFLAGS = -c -g3 -O3 -I. -I$(SRC) +CFLAGS_LINT = -ansi -pedantic -Wall -Wshadow \ + -Wstrict-prototypes -Wmissing-prototypes \ + -Wmissing-declarations -Wredundant-decls + +# Source definitions +CENVFLAGS = -DCENV_CPU_ALPHA=1 -DCENV_SYS_LINUX=1 -DKLH10_DEV_LITES=1 \ + -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + +# Any target with no customized rule here is simply passed on to the +# standard Makefile. If no target is specified, "usage" is passed on +# to generate a helpful printout. + +usage .DEFAULT: + @make -f $(SRC)/Makefile.mk $@ \ + "SRC=$(SRC)" \ + "CFLAGS=$(CFLAGS)" \ + "CFLAGS_LINT=$(CFLAGS_LINT)" \ + "CENVFLAGS=$(CENVFLAGS)" + +install: + make -f $(SRC)/Makefile.mk install-unix From 23378e1e9b3d8282904fc58683f44a85797574d1 Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Sun, 19 Jul 2015 16:18:35 +0200 Subject: [PATCH 18/18] Slightly update build instructions. --- doc/install.txt | 9 ++++++++- src/Mk-lnaxp.mk | 4 ++-- src/Mk-nbaxp.mk | 4 ++-- src/Mk-osfaxp.mk | 3 ++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/install.txt b/doc/install.txt index 69f640c..558be0b 100644 --- a/doc/install.txt +++ b/doc/install.txt @@ -53,8 +53,10 @@ for other ports such as MacOS or Windows have not yet been written. $ cd /bld/ $ make base-kl ;;; or base-ks or base-ks-its + or to make all variants, installing to /new/-: + $ ../MAKE-ALL - Or see the "Building" section farther on. + Or see the "BUILDING FROM SOURCES" section farther on. Read "doc/dfkfb.txt" if you want to do a quick KL performance test now. @@ -233,6 +235,11 @@ BUILDING FROM SOURCES Notes: +The "*axp" directories are not only useful for Alpha AXP hosts, but also +for any other little-endian 64-bit CPU. That includes amd64 aka x86_64. +While the x86 configuration may work on amd64, it is likely to be +a bit less efficient. + Solaris has two possible Makefiles; the default uses GCC, but you can change the link to Mk-solsparc-cc.mk which uses Sun's C compiler. diff --git a/src/Mk-lnaxp.mk b/src/Mk-lnaxp.mk index 891ec9a..c094e0b 100644 --- a/src/Mk-lnaxp.mk +++ b/src/Mk-lnaxp.mk @@ -1,5 +1,5 @@ -# KLH10 Makefile for Linux on i386 -# $Id: Mk-lnx86.mk,v 2.5 2002/04/24 18:03:04 klh Exp $ +# KLH10 Makefile for Linux on amd64 / x86_64 / Alpha +# (or any other little-endian 64-bit cpu) # # Copyright © 2001 Kenneth L. Harrenstien # All Rights Reserved diff --git a/src/Mk-nbaxp.mk b/src/Mk-nbaxp.mk index 4cbb309..0ca1260 100644 --- a/src/Mk-nbaxp.mk +++ b/src/Mk-nbaxp.mk @@ -1,5 +1,5 @@ -# KLH10 Makefile for NetBSD on Alpha -# $Id: Mk-nbaxp.mk,v 2.5 2002/04/26 05:59:32 klh Exp $ +# KLH10 Makefile for NetBSD on amd64 / x86_64 / Alpha +# (or any other little-endian 64-bit cpu) # # Copyright © 2001 Kenneth L. Harrenstien # All Rights Reserved diff --git a/src/Mk-osfaxp.mk b/src/Mk-osfaxp.mk index 28ee2b7..9a6c8e4 100644 --- a/src/Mk-osfaxp.mk +++ b/src/Mk-osfaxp.mk @@ -1,4 +1,5 @@ -# KLH10 Makefile for OSF/1 (DU, Tru64) on Alpha +# KLH10 Makefile for OSF/1 (DU, Tru64) on amd64 / x86_64 / Alpha +# (or any other little-endian 64-bit cpu) # $Id: Mk-osfaxp.mk,v 2.3 2001/11/10 21:28:59 klh Exp $ # # Copyright © 2001 Kenneth L. Harrenstien