Import of wkt's apout src tree into svn.
authorwarren.toomey <warren.toomey@44b2186c-a14b-0410-8c95-595313601b93>
Tue, 6 May 2008 23:25:22 +0000 (23:25 +0000)
committerwarren.toomey <warren.toomey@44b2186c-a14b-0410-8c95-595313601b93>
Tue, 6 May 2008 23:25:22 +0000 (23:25 +0000)
30 files changed:
CHANGES [new file with mode: 0644]
COPYRIGHT [new file with mode: 0644]
LCLINT [new file with mode: 0644]
LIMITATIONS [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
aout.c [new file with mode: 0644]
aout.h [new file with mode: 0644]
apout.1 [new file with mode: 0644]
branch.c [new file with mode: 0644]
bsd_ioctl.c [new file with mode: 0644]
bsd_signal.c [new file with mode: 0644]
bsdtrap.c [new file with mode: 0644]
bsdtrap.h [new file with mode: 0644]
cpu.c [new file with mode: 0644]
debug.c [new file with mode: 0644]
defines.h [new file with mode: 0644]
double.c [new file with mode: 0644]
ea.c [new file with mode: 0644]
fp.c [new file with mode: 0644]
itab.c [new file with mode: 0644]
ke11a.c [new file with mode: 0644]
magic.c [new file with mode: 0644]
main.c [new file with mode: 0644]
single.c [new file with mode: 0644]
v1trap.c [new file with mode: 0644]
v1trap.h [new file with mode: 0644]
v7trap.c [new file with mode: 0644]
v7trap.h [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..792efc5
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,173 @@
+2.3 Beta1: to 10th June 2002
+----------------------------
+
+Changed debug statements in cpu.c to be TrapDebug statements as I was
+seeing output from these in the output file of 2.11BSD /lib/cpp.
+
+The problem with scripts has also been fixed, finally. I was passing
+the wrong path into the shell arguments.
+
+On a 1.6GHz Pentium 4 running FreeBSD 4.5, a make depend; make of the
+2.11BSD GENERIC kernel takes 72 seconds.
+
+2.3 Alpha3: to 1st June 2001
+----------------------------
+
+Added patches from Wilhelm B. Kloke wb@vestein.arb-phys.uni-dortmund.de
+to get Apout to run the Algol 68 binaries found which were added into
+the Unix Archive.
+
+A few changes for better Linux compilation. However, stream buffering
+doesn't seem to work on Linux, at least RedHat 6.2.
+
+2.3 Alpha2: to 10th Jan 2000
+----------------------------
+
+Added partial support for 0407-magic binaries from 2nd Edition. At
+present, this is enough for the C compiler on Dennis Ritchie's s2.tar
+archive to work. It's also good enough for the C compiler to recompile
+the last1120c compiler, and for the last1120c compiler to recompile itself.
+
+Added code to support 512-byte block seeks on /dev files for 1st Edition
+binaries. This was required to get tap(1) to work. This should really
+only force 512-byte seeks on specific /dev/files, not all of them.
+
+A significant rearrangement of the code in aout.c was done to make it
+more logical. I wouldn't say it was much tidier than before, though.
+
+A redefinition of sigset_t in NetBSD stopped Apout from being compiled
+there. Thanks to Soren, bsdsignal.c was modified to fix this problem.
+
+Some small changes to the output from -inst to make it look better.
+Added a WRITEBASE #define to help improve performance just a bit more.
+
+2.3 Alpha1: to 2nd Jan 2000
+---------------------------
+
+Added nearly complete support for 0405-magic binaries from 1st Edition,
+including emulating the KE11A extended arithmetic element. Still some
+work needed here on both the trap handling and KE11A support. Thanks to
+Tim Shoppa (shoppa@trailing-edge.com) for his eae code. The 0407-magic
+binaries from Dennis Ritchie's s2.tar archive are not yet supported. I
+need the V2/V3 manuals from Norman Wilson for this.
+
+Some tidying up of the code has been done, using LCLINT and by hand.
+I've made a Debug() macro which make the code look a bit cleaner.
+
+Some memory leaks removed. Natives exec()s now inherit the original
+environment, not the emulated one. Some mov() functions split into
+separate functions to help improve performance. Added a workaround
+for date handling in V5/V6 ctime(): see tail of v7trap.c.
+
+Stream buffering variables consolidated into main.c and some bugs
+removed (e.g "rw" -> "w+"). 2.11BSD emulation now has stream buffering,
+but it is turned off by default as it doesn't seem to provide any
+improvement in performance.
+
+2.2 Alpha9: to 2nd Mar 1999
+---------------------------
+
+I've added magic numbers for some 2.9BSD binaries: all 2.9 binaries
+run in the V7 environment, which seems to work but I'm sure that
+2.9 != V7.
+
+With help from Jonathan Naylor (g4klx@g4klx.demon.co.uk), and some work
+myself, I've managed to compile Apout under RedHat Linux 2.2. There are
+some 2.11BSD syscalls not implemented as a result, but I can recompile
+the V7 and the 2.11BSD kernels, which is a good indicator.
+
+
+2.2 Alpha8: to 15th Jan 1999
+----------------------------
+
+These changes came about due to my attempt to compile the UNIX `nsys'
+kernel source code, dated 1973, with the 5th Edition development tools.
+
+Added better detection of some special UNIX a.out binaries: the
+environment for these binaries was being incorrectly set by aout.c.
+There is now a magic.c which fixes the problem. See also LIMITATIONS
+for a note of bugs in some a.out binaries.
+
+Modified v7trap.c to be much cleaner, and to look a bit more like
+bsdtrap.c. Introduced several small bugs in V5/V6/V7 syscall emulation,
+notably pipe() and dup(), by the cleanup. These are fixed.
+
+
+2.2 Alpha7: to 11th Jan 1999
+----------------------------
+
+Modified the code to handle the syscall differences between
+V6 and V7: note that V5 and V6 are syscall identical. V6 has
+a different seek() and stat() to V7.
+
+Added a new file for 2.11BSD ioctls, did many of the terminal
+ioctls, and a few more syscalls. Now 2.11 vi runs. However,
+longjmp() doesn't work yet, because it requires working signals.
+
+Changed some types and #ifdefs for NetBSD and OpenBSD: thanks Soren!
+
+
+2.2 Alpha6: to 6th Jan 1999
+---------------------------
+
+Bugfixes: none that I can think of.
+
+Enhancements: tidied the code up somewhat. Changed uint -> u_int
+throughout. Added support for execution of native binaries: now I can
+run vi from inside 2.11 bin/sh, yay! Finally wrote the long-overdue
+manual page. Added RCS tags to all sources. Ensured that it compiled on
+FreeBSD 3.x and 2.1.x: I need to take it home for FreeBSD 2.2.x.
+
+
+2.2 Alpha5: to 5th Jan 1999
+---------------------------
+
+Bugfixes: fixed malloc bug, which was a too-large blksize from stat/fstat.
+Fixed the gtty/stty emulation, which was causing make to break.
+
+Enhancements: Apout can now run shell scripts. 2.11BSD overlay binaries
+are now supported, which is good news. I can now compile the 2.11 GENERIC
+kernel with no manual intervention. On a Pentium II 350MHz, this takes
+4:16secs with an optimised Apout.
+
+
+2.2 Alpha4: to 2nd Jan 1999
+---------------------------
+
+Fixed more deficiencies in the 2.11BSD emulation, in particular
+fork(), vfork() and sbrk(). The argv/envp environment is better
+but still not totally correct, I think. Finally got the correct
+code for 2.11 readdir().
+
+We now have a semi-working FP emulation. It's enough to keep 2.11
+happy, but it isn't very good. It will do for now.
+
+Many of the 2.11BSD syscalls are now implemented. Most are not
+verified, but a lot of 2.11BSD commands run, including sh, make,
+cc, date, cal. ls(1) goes into an infinite loop when doing ls -l,
+the inf. loop is in malloc(3). By substituting malloc(3) from
+Minix 1.3, this problem goes away. I don't know if it's a bug
+in the emulator, or in the 2.11 malloc() code.
+
+
+2.2 Alpha3 to 5th Dec 1998
+--------------------------
+
+Reorganised bsdtrap.[ch], and started work on the
+2.11BSD emulated syscalls; this is surprisingly
+easy for many of them.
+
+
+Changes from 2.1 to 2.2
+-----------------------
+
+ + General code tidying up and niggling bug removal.
+ + Code optimisation to speed things up, although
+   I haven't quantified the improvement yet.
+ + Separation of the binary loader and trap handlers
+   from the main program. This doesn't do anything now,
+   but it will make the emulation of several PDP-11
+   environments (e.g 2.11BSD, RT-11) much easier to do.
+ + Finished getting the stream buffering of I/O to work.
+   I still don't know why fdopen doesn't work on "rw".
+ + Some extra trap functionality, e.g basic signal handling.
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..087357d
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,46 @@
+The Apout simulator is copyright Warren Toomey, and is protected by the
+following notice.
+
+/* Apout is a PDP-11 a.out simulator.
+ * 
+ * For information contact:
+ * 
+ * Email:  wkt@tuhs.org
+ * FTP:    ftp://minnie.tuhs.org/pup/PDP-11/Sims/Apout
+ * 
+ * Copyright 1995-2002, Warren Toomey
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies. Warren Toomey
+ * makes no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without expressed or implied warranty.
+ */
+
+------
+
+The parts of Apout that deal with PDP-11 instruction emulation are derived
+from the PDP-11 simulator written by Eric A. Edwards, and are protected by
+the following notice.
+
+/* Parts of Apout are derived from 'pdp', a PDP-11 simulator.
+ * 
+ * For information contact:
+ * 
+ * Computer Science House
+ * Attn: Eric Edwards
+ * Box 861
+ * 25 Andrews Memorial Drive
+ * Rochester, NY 14623
+ * 
+ * Email:  mag@potter.csh.rit.edu
+ * FTP:    ftp.csh.rit.edu:/pub/csh/mag/pdp.tar.Z
+ * 
+ * Copyright 1994, Eric A. Edwards
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies.  Eric A. Edwards
+ * makes no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without expressed or implied warranty.
+ */
diff --git a/LCLINT b/LCLINT
new file mode 100644 (file)
index 0000000..3bb43a2
--- /dev/null
+++ b/LCLINT
@@ -0,0 +1,16 @@
+aout.c                 Fri Sep 17 13:00:33 EST 1999
+branch.c       Fri Sep 17 13:00:33 EST 1999
+bsd_ioctl.c    Fri Sep 17 13:03:34 EST 1999
+bsd_signal.c
+bsdtrap.c
+cpu.c          Fri Sep 17 15:04:05 EST 1999 bits to do
+debug.c                Fri Sep 17 15:04:01 EST 1999
+double.c       Fri Sep 17 15:08:46 EST 1999
+ea.c           Fri Sep 17 15:10:51 EST 1999
+fp.c
+itab.c                 Fri Sep 17 13:00:33 EST 1999
+ke11a.c
+magic.c                Fri Sep 17 13:00:33 EST 1999
+main.c
+single.c
+v7trap.c
diff --git a/LIMITATIONS b/LIMITATIONS
new file mode 100644 (file)
index 0000000..aad676c
--- /dev/null
@@ -0,0 +1,155 @@
+Bugs in Binaries
+----------------
+
+One of the V5 C compiler passes requires -DZERO_MEMORY: it must not
+initialise a variable properly. V5 and V6 ar(1) do not close a file
+descriptor after writing has finished. If Apout is compiled with
+stream buffering, when this file is copied it is truncated. Either
+turn off Apout stream buffering (a performance penalty), or patch
+ar.s to behave itself. The patch is:
+
+*** ar.s.orig   Thu Jan 14 09:40:46 1999
+--- ar.s        Thu Jan 14 09:41:12 1999
+***************
+*** 444,449 ****
+--- 444,451 ----
+        bes     crterr
+        mov     r0,afo
+        sys     write; magic; 2
++       mov     tfo,r0          / need to close before reading
++       sys     close
+  1:
+        mov     tfi,r0
+        sys     read; buf; 512.
+
+
+Floating-point Limitations
+--------------------------
+
+PDP-11 doubles are treated as floats. FEA/FEC don't exist.
+FP errors are not dealt with. Mistrust FP results for now.
+
+Limitations for 7th Edition Emulation in Apout 2.3
+--------------------------------------------------
+
+Note that V5 and V6 binaries are considered V7 binaries. Overlay
+binaries (type 0405) are not recognised.
+
+The errno values on the native system are not translated back to
+the V7 errno values. There is normally a 1-to-1 mapping, but V7
+only had 32 errno values; native errno values above this are going
+to confuse the emulated application.
+
+The following system calls are not implemented, and return an 
+EPERM error to the application: phys(2), prof(2), ptrace(2),
+acct(2), mount(2), umount(2), times(2). The following system
+calls are ignored: lock(2), stime(2).
+
+The following systems calls are only partially implemented:
+
+    signal(2):         Only SIG_DFL and SIG_IGN are implemented.
+    stty(2), gtty(2):  These should work, but V7 stty(1) doesn't work.
+    ioctl(2):          Only enough to emulate stty(2) amd gtty(2).
+
+The emulated applications use the native filesystem. Native filenames bigger
+than 14 characters are truncated to 14 characters before being passed to
+the application. In a similar way, inode numbers bigger than 65,536 are
+truncated modulo 65,536 before being passed to the application.
+
+Limitations for 5th & 6th Edition Emulation in Apout 2.3
+--------------------------------------------------------
+
+There seems to be a bug in V5/V6 ctime() which stops dates after
+November 1999 being displayed correctly. Apout works around this
+problem by modifying dates returned from system calls to be in
+the year 1998 if they are 1999 or later.
+
+Limitations for 2.9BSD Emulation in Apout 2.3
+---------------------------------------------
+
+At present, 2.9BSD binaries are treated as V7 binaries, so the limitations
+above apply. This also means that overlays are not understood, and also the
+2.9-specific system calls have not yet been implemented.
+
+Limitations for 2.11BSD Emulation in Apout 2.3
+----------------------------------------------
+
+Flags passed as arguments to the 2.11 syscalls are promoted to 32-bit
+ints and passed to the native syscall. The errno values on the native
+system are not translated back to the 2.11 errno values. To find out
+what syscalls have been implemented, grep for the word DONE in bsdtrap.c.
+
+The following 2.11 syscalls are not handled:
+
+       S_GETSOCKOPT, S_SETSOCKOPT, S_SELECT,
+       S_RECVMSG, S_SENDMSG, S_SENDTO, 
+       S_SIGBLOCK, S_SIGPAUSE, S_SIGRETURN,
+       S_SIGSETMASK, S_SIGSTACK, S_SIGVEC
+
+Limitations for 1st Edition Emulation in Apout 2.3
+--------------------------------------------------
+
+This is still in the experimental stages, with some problems with time
+values. The KE11A emulation is also incomplete. However, the following
+0405-magic binaries from Dennis Ritchie's s2.tar archive are known to work:
+
+       cat, cp, date, echo, ls, mkdir, sh, wc
+
+Most of the others seem to work as well, but I haven't tested them completely.
+The list of 0405-magic files on the s2 archive is:
+
+       bin/:           bin/mv
+       bin/ar          bin/od
+       bin/bas         bin/pr
+       bin/cat         bin/rew
+       bin/chball      bin/rmdir
+       bin/check       bin/roff
+       bin/chown       bin/sh
+       bin/cmp         bin/skip
+       bin/cp          bin/sort
+       bin/date        bin/stat
+       bin/db          bin/stty
+       bin/dc          bin/su
+       bin/df          bin/sum
+       bin/du          bin/tap
+       bin/echo        bin/tm
+       bin/ed          bin/tty
+       bin/exit        bin/wc
+       bin/form        bin/who
+       bin/goto        bin/write
+       bin/if          etc/getty
+       bin/login       etc/glob
+       bin/ls          etc/init
+       bin/mail        etc/msh
+       bin/mesg        /tc/suftab
+       bin/mkdir
+
+The following 1st Edition system calls are not yet emulated: GTTY, STTY, TELL.
+
+Limitations for 2nd Edition Emulation in Apout 2.3
+--------------------------------------------------
+
+The few 2nd Edition binaries with 0407-magic on the s2 archive can now
+be run with Apout. Essentially, they receive the same environment as
+the 1st Edition binaries, with a few small syscall differences. Note
+that, at present, I don't have a copy of the V2 manuals, so I can
+guarantee that 2nd Edition emulation still needs work.
+
+However, the emulation is good enough to allow the C compiler on the s2
+archive to compile the last1120c C compiler on Dennis Ritchie's homepage.
+
+The list of 0407-magic files in the s2 archive is below. I have starred
+those binaries that I know work with Apout.
+
+ *  bin/as                 usr/fort/fc1
+ *  bin/cc                 usr/fort/fc2
+    bin/ds                 usr/fort/fc3
+    bin/fc                 usr/fort/fc4
+    bin/find               usr/jack/a.out
+ *  bin/ld                 usr/jack/x.o
+    bin/maki            *  usr/lib/c0
+    bin/nm              *  usr/lib/c1
+ *  bin/size               usr/lib/crt0.o
+    bin/strip              usr/lib/fr0.o
+    bin/un                 usr/sys/a.out
+ *  etc/as2
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..fc1d7a6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,78 @@
+# Makefile for Apout PDP-11 application emulator
+#
+# $Revision: 1.29 $
+# $Date: 2002/06/10 11:49:48 $
+#
+# You will need gcc if you choose the optimised compile below
+CC=gcc
+
+# Set the CFLAGS, LDFLAGS for speed or debugging. If you don't want 2.11BSD
+# emulation, then remove the -DEMU211 flag.
+# Set up the LIBS if required for your system
+#
+# These flags for doing debugging
+CFLAGS= -Wall -g -DEMU211 -DEMUV1 -DNATIVES -DDEBUG -DZERO_MEMORY -DWRITEBASE
+LDFLAGS= -static -g
+
+# These flags for speed
+#CFLAGS= -DEMU211 -DNATIVES -DINLINE=inline -O2 -Winline -Wall \
+#      -finline-functions -fomit-frame-pointer
+#LDFLAGS=
+
+# Any extra libraries required
+LIBS= -lm
+
+# Install destinations
+MANDIR=/usr/local/man/man1
+BINDIR=/usr/local/bin
+
+VERSION= apout2.3beta1
+SRCS=  cpu.c aout.c aout.h branch.c double.c ea.c itab.c main.c ke11a.c \
+       single.c fp.c v7trap.c bsdtrap.c defines.h v7trap.h debug.c \
+       bsdtrap.h bsd_ioctl.c bsd_signal.c magic.c v1trap.c v1trap.h \
+       apout.1 apout.0 README COPYRIGHT CHANGES LIMITATIONS TODO Makefile
+OBJS=  aout.o branch.o bsd_ioctl.o bsd_signal.o bsdtrap.o cpu.o debug.o \
+       double.o ea.o fp.o itab.o ke11a.o magic.o main.o single.o v1trap.o \
+       v7trap.o
+
+apout: $(OBJS)
+       cc $(LDFLAGS) $(OBJS) -o apout $(LIBS)
+
+install: apout
+       cp apout $(BINDIR)
+       chmod 755 $(BINDIR)/apout
+       cp apout.1 $(MANDIR)
+       chmod 644 $(MANDIR)/apout.1
+
+clean:
+       rm -rf apout *core $(OBJS) *.dbg $(VERSION) $(VERSION).tar.gz apout.0
+
+apout.0: apout.1
+       nroff -man apout.1 > apout.0
+
+disttar: clean apout.0
+       - mkdir $(VERSION)
+       cp $(SRCS) $(VERSION)
+       chmod -R go+rX $(VERSION)
+       chmod -R u+w $(VERSION)
+       chown -R wkt $(VERSION)
+       tar vzcf $(VERSION).tar.gz $(VERSION)
+
+# Dependencies for object files
+aout.o: aout.c defines.h aout.h Makefile
+branch.o: branch.c defines.h Makefile
+bsd_ioctl.o: bsd_ioctl.c defines.h Makefile
+bsd_signal.o: bsd_signal.c defines.h bsdtrap.h Makefile
+bsdtrap.o: bsdtrap.c bsdtrap.h defines.h Makefile
+cpu.o: cpu.c defines.h Makefile
+debug.o: debug.c defines.h Makefile
+double.o: double.c defines.h Makefile
+ea.o: ea.c defines.h Makefile
+fp.o: fp.c defines.h Makefile
+itab.o: itab.c defines.h Makefile
+ke11a.o: ke11a.c defines.h Makefile
+magic.o: magic.c defines.h Makefile
+main.o: main.c defines.h Makefile
+single.o: single.c defines.h Makefile
+v1trap.o: v1trap.c v1trap.h defines.h Makefile
+v7trap.o: v7trap.c v7trap.h defines.h Makefile
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7880b15
--- /dev/null
+++ b/README
@@ -0,0 +1,140 @@
+              Apout -- Simulate PDP-11 Unix a.out binaries
+                           Version 2.3 Beta 1
+
+                    Warren Toomey  wkt@tuhs.org
+                               June 2002
+
+Introduction
+------------
+This program is a user-level simulator for UNIX a.out binaries. Binaries
+for V1, V2, V5, V6, V7, 2.9BSD and 2.11BSD can be run with this simulator.
+The user-mode PDP-11 instructions are simulated, and TRAP instructions
+are emulated by calling equivalent native-mode system calls.
+
+The advantages of an a.out simulator over a full-blown PDP-11 simulator are:
+
+   + system calls can be done natively, thus speeding up execution
+   + the simulator is less of a CPU-hog than a full-blown PDP-11 simulator
+   + you don't need a simulated operating system or a simulated file system
+
+Apout can be obtained via anonymous ftp at minnie.tuhs.org in the
+directory pub/PDP-11/Sims/Apout. The directory pub/PDP-11/Sims/Apout/UnixBins
+contains tar archives of a.out binaries from several versions of UNIX.
+
+Status
+------
+The program is now at release 2.3 Alpha2. Most of the binaries from V5, V6
+and V7 run fine. All of the V5/V6/V7 system calls are caught, but some are
+ignored and some generate EPERM errors. The V1, V2, 2.9BSD and 2.11BSD
+environments are still under construction: see the file LIMITATIONS for
+details. Finally, the simulator won't run on a big-endian machine.
+
+INSTALLATION
+------------
+I have only tested this program on FreeBSD 2.x and 3.x, and on RedHat
+Linux 2.2. It should compile on a 32-bit little-endian machine with
+some form of Unix; you may need to change some header file includes etc.
+See `defines.h' for the details. In particular, if your system doesn't have
+types for:
+
+       int8_t, int16_t, int32_t, u_int8_t, u_int16_t, u_int32_t
+
+or if your compiler doesn't have char=1 byte, short= 2 bytes, int=4 bytes,
+then alter the relevant typedefs in `defines.h'.
+
+The Makefile has two sets of CFLAGS/LDFLAGS: one set is for debugging, and
+the other set is for speed. If you define the C pre-processor macro `DEBUG',
+then this includes debugging code into the program. I use it quite heavily
+when trying to fix niggling problems.
+
+If you remove the -DEMU211 macro definition from the Makefile, the emulation
+of 2.11BSD will not be compiled in to the simulator. Similarly, if you remove
+the -DEMUV1 macro definition from the Makefile, the emulation of 1st and 2nd
+Edition UNIX will not be compiled in to the simulator. By default, EMUV1
+is disabled.
+
+
+Once you have configured apout, now type `make'. Hopefully, things will
+compile ok. You will eventually get the `apout' program.
+
+Now go find an old PDP-11 UNIX binary, e.g 7th Edition cal, and say:
+
+       % setenv APOUT_ROOT /           # for now
+       % apout cal 1970
+
+If the simulator is working, the calendar for 1970 will be printed out.
+The V7 shell works, and from there, you can run other programs.
+
+       % apout sh
+       # ls -l
+           output of ls
+       #
+
+Finally, install apout in /usr/local/bin, and the manual page apout.1 in
+the appropriate place. If you can't use the man page because of incompatible
+macros, then apout.0 is a text file which has the pre-formatted man page.
+
+DEBUG OPTIONS
+-------------
+When debugging is compiled in, the program has several options:
+
+       -inst   turns on instruction tracing, which is _very_ verbose
+       -trap   turns on TRAP tracing; not all syscalls have debugging code
+       -jsr    prints out the details of each jsr and rts
+       -fp     prints out some details of floating-point instructions
+
+All debugging output goes out to the file `apout.dbg'. These debugging options
+are mainly used for testing apout, and so the output in apout.dbg may not be
+very useful to you.
+
+ENVIRONMENT VARIABLES
+---------------------
+Apout has the concept of a simulated root filesystem for the simulated PDP-11
+binaries. When working with filenames, if the filenames are relative, they
+stay relative. If the filenames are absolute (i.e /usr/...), then apout
+prepends the value of the environment variable APOUT_ROOT to the filename.
+This allows you to say:
+
+       # setenv APOUT_ROOT /usr/misc/v7root
+
+before running apout to set the `root' of the filesystem wherever you want.
+You MUST set APOUT_ROOT before running apout.
+
+TODO
+----
+There's lots to do. Here's what I'd like to do, in a somewhat ordered list.
+
+       + Verify that the instruction simulation and    high priority
+            the syscalls all work correctly
+       + Complete some of the syscalls that are        med priority
+            not fully simulated
+       + Speed the simulator up                        med priority
+
+SOURCE ORGANISATION
+-------------------
+
+main.c         parses any arguments, loads the binary and calls run()
+cpu.c          holds the main instruction decode/execute loop
+itab.c         holds function lookup tables for all instructions
+ea.c           holds functions to decode the PDP-11 addressing modes
+debug.c                holds strings for all emulated opcodes
+
+single.c       single.c, double.c and branch.c hold most of the functions
+double.c        which perform the PDP-11 user-mode instructions. The code
+branch.c        in these files comes from a PDP-11 simulator by Eric Edwards
+fp.c           partially emulates FP instructions
+
+aout.c         determines what type of a.out the binary is, and what UNIX
+magic.c                 environment to set up. If V5/V6/V7, trap instructions fall
+v7trap.c        into v7trap.c which runs them using native system calls
+v7trap.h
+
+v1trap.c       if the binary is a 1st or 2nd Edition binary, traps fall
+v1trap.h        into v1trap.c, which likewise does the syscalls natively
+ke11a.c                emulates the KE11A extended arithmetic unit, used by V1/V2
+
+bsdtrap.c      if the binary is a 2.11BSD binary, trap instructions fall
+bsdtrap.h       into bsdtrap.c, which likewise does the syscalls natively
+bsd_ioctl.c    2.11BSD ioctl calls are handled with this file
+
+defines.h      holds function & typedef prototypes and useful cpp macros
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..6f0b650
--- /dev/null
+++ b/TODO
@@ -0,0 +1,72 @@
+                   Things to do in the Apout Emulator
+                   ----------------------------------
+
+Ensure stream buffering works!
+
+       Do some decent testing and code reading to make me happier.
+
+Speed Apout up
+
+       The biggest bottlenecks are the effective address calculations
+       in ea.c. After compiling 2.11BSD /sys/GENERIC kernel with a
+       gprof'd apout, we get:
+
+         %   cumulative   self              self     total           
+       time   seconds   seconds    calls  ms/call  ms/call  name    
+       64.9       3.64     3.64                             .mcount (123)
+       6.1       3.99     0.34  1609635     0.00     0.00  load_src [5]
+       5.6       4.30     0.31  1665976     0.00     0.00  mov [4]
+       5.3       4.60     0.30        2   148.44   959.47  run <cycle 1> [3]
+       3.4       4.79     0.19  1238127     0.00     0.00  load_dst [7]
+       2.2       4.91     0.12   602275     0.00     0.00  store_dst [10]
+       1.3       4.98     0.08   374121     0.00     0.00  loadb_src [12]
+       1.3       5.05     0.07   672481     0.00     0.00  store_dst_2 [13]
+       1.2       5.12     0.07   365911     0.00     0.00  cmp [6]
+       1.1       5.18     0.06   323386     0.00     0.00  movb [8]
+       1.1       5.24     0.06   515335     0.00     0.00  bne [15]
+
+       Everything else is below 1%. It doesn't look like there is
+       much room for improvement, maybe 10% worth?
+
+       We could go to having 65,536 separate functions, one for
+       each possible instruction. That would mean a large reorganisation
+       of the source, and would result in a significantly larger
+       binary for apout.
+
+       I've broken open some of the mov() functions which has improved
+       things a few percent. I did expand itab[] to 64K entries, but
+       the improvement was negligible. However, I should come back &
+       revisit this sometime.
+
+       Would it be worth adding STREAM_BUFFERING into bsdtrap.c? Possibly.
+       After a GENERIC kernel compile, I found that reads averaged 580
+       chars/read, writes averaged 115 chars/write. However, after getting
+       buffering to work in bsdtrap.c, I found that it actually slowed down
+       the GENERIC kernel compile, so I've left the code in but disabled it.
+
+Finish off 2.11BSD emulation
+
+       Finish off all the missing syscalls. This means I will have to
+       learn how the new signal stuff actually works. Emulating signals
+       is going to be really interesting, I can see!
+       
+       Enumerate and write all of the ioctls: yucko. That means all of
+       the terminal stuff, blah!
+
+Fix up the floating-point
+
+       If the UNIX binaries never use the FP error handling, then don't
+       bother to implement it. We should, however, implement doubles.
+       We should spend some time to ensure that the FP operations are
+       accurate, both in terms of FP accuracy, and in giving results
+       as if they were on a real PDP-11.
+
+Make it work on big-endian machines
+
+       This would cause a lot of heartache in the code. It's not that
+       pretty now, but can you imagine the #ifdefs once big-endian
+       support is added? I guess some well-written macros could help.
+
+Tidy up the code
+
+       In particular, aout.c is a mess. Should be more modular.
diff --git a/aout.c b/aout.c
new file mode 100644 (file)
index 0000000..d2d3dd0
--- /dev/null
+++ b/aout.c
@@ -0,0 +1,609 @@
+/* aout.c - parse and load the contents of a UNIX a.out file, for
+ * several flavours of PDP-11 UNIX
+ *
+ * $Revision: 1.50 $
+ * $Date: 2002/06/10 11:43:24 $
+ */
+#include "defines.h"
+#include "aout.h"
+
+/* Array of 64K for data and instruction space */
+static u_int8_t darray[PDP_MEM_SIZE], iarray[PDP_MEM_SIZE];
+
+#ifdef EMU211
+/* 2.11BSD allows up to 16 8K overlays in the 0430 and 0431 a.out types.
+ * Each overlay is loaded at the first 8K `click' above the end of the
+ * main text. The following structures hold the overlays from the current
+ * a.out, if there are any. Missing overlays have size 0 and pointer NULL.
+ */
+static struct {
+  u_int16_t size;
+  u_int8_t *ovlay;
+} ovlist[NOVL] = {
+    {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL},
+    {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL},
+    {0, NULL}, {0, NULL}, {0, NULL}
+};
+
+static u_int8_t *ovbase;       /* Base address of 2.11BSD overlays */
+u_int32_t ov_changes = 0;      /* Number of overlay changes */
+u_int8_t current_ov = 0;       /* Current overlay number */
+#endif
+
+/* Global array of pointers to arguments and environment. This
+ * allows load_a_out() to modify it when dealing with shell
+ * scripts, before calling set_arg_env()
+ */
+char *Argv[MAX_ARGS], *Envp[MAX_ARGS];
+int Argc, Envc;
+int Binary;                    /* Type of binary this a.out is */
+
+/* For programs without an environment, we set the environment statically.
+ * Eventually there will be code to get some environment variables
+ */
+static char *default_envp[4] = {
+  "PATH=/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/games:/usr/local/bin:.",
+  "HOME=/",
+  "TERM=vt100",
+  "USER=root"
+};
+static int default_envc = 4;
+
+/* Prototypes */
+static void set_arg_env(int want_env);
+
+
+/* Load the a.out header from the given file pointer, and return it.
+ * Also return an integer describing which version of UNIX the a.out
+ * belongs to. If errors on reading, return -1.
+ */
+int load_aout_header(FILE * zin, struct exec * E)
+{
+  char *cptr;
+
+                               /* Read the a_magic value first */
+                               /* This makes it easier to deal with */
+                               /* parsing any script interpreter below */
+  if (fread(E, sizeof(u_int16_t), 1, zin) != 1) return (-1);
+
+  switch (E->a_magic) {
+    case ANY_SCRIPT:           /* Shell script, return now */
+      return (IS_UNKNOWN);
+    case V1_NORMAL:
+    case ANY_NORMAL:           /* These are recognised below */
+    case ANY_ROTEXT:
+    case ANY_SPLITID:
+    case BSD_OVERLAY:
+    case BSD_ROVERLAY:
+    case A68_MAGIC:
+      break;
+
+    default:                   /* Unrecognised binary, mark as such */
+      E->a_magic = UNKNOWN_AOUT; return (IS_UNKNOWN);
+  }
+
+                               /* We can deal with this a.out, so */
+                               /* read in the rest of the header */
+  cptr = (char *) &(E->a_text);
+  if (fread(cptr, sizeof(struct exec) - sizeof(u_int16_t), 1, zin) != 1)
+                                                               return (-1);
+
+  switch (E->a_magic) {
+    case A68_MAGIC: if (E->a_data==A68_DATA) return(IS_A68);
+                   else { E->a_magic = UNKNOWN_AOUT; return (IS_UNKNOWN); }
+    case V1_NORMAL: return (IS_V1);
+    case BSD_OVERLAY:
+    case BSD_ROVERLAY: return (IS_211BSD);
+    case ANY_NORMAL:
+    case ANY_ROTEXT:
+    case ANY_SPLITID:  /* Check crt0.o 2nd magic for V2/V6/V7/2.11BSD */
+      if (E->a_magic2 == V2_M2) return (IS_V2);
+      if (E->a_magic2 == V6_M2) return (IS_V6);
+      if (E->a_magic2 == V7_M2) return (IS_V7);
+      if (E->a_magic2 == BSD_M2) return (IS_211BSD);
+
+                               /* Still no idea, use checksum to determine */
+      return(special_magic((u_int16_t *) E));
+
+    default:                   /* Should never get here */
+      E->a_magic = UNKNOWN_AOUT; return (IS_UNKNOWN);
+  }
+}
+
+
+/* Read in the executable name and its arguments from the shell script,
+ * and the re-call load_a_out to load in that binary. Returns 0 on
+ * success, -1 on error. Input file is always closed by this routine.
+ */
+int load_script(const char *file, const char *origpath,FILE * zin, int want_env)
+{
+#define SCRIPT_LINESIZE 512    /* Max size of 1st line in script */
+  char *script_line;
+  char *script_arg[MAX_ARGS];
+  int i, script_cnt = 0;
+  char **ap;
+
+  for (i=0;i<Argc;i++)
+    TrapDebug((dbg_file, "In load_script Argv[%d] is %s\n", i, Argv[i]));
+                               /* Get the first line of the file */
+  if (((script_line = (char *) malloc(SCRIPT_LINESIZE)) == NULL) ||
+      (fgets(script_line, SCRIPT_LINESIZE, zin) == NULL)) {
+    (void) fprintf(stderr, "Apout - could not read 1st line of script\n");
+    (void) fclose(zin);
+    return (-1);
+  }
+                               /* Now break into separate words */
+  for (ap = script_arg; (*ap = strsep(&script_line, " \t\n")) != NULL;)
+    if (**ap != '\0') {
+      ap++; script_cnt++;
+      if (script_cnt >= MAX_ARGS) break;
+    }
+  if (fclose(zin) != 0) { free(script_line); return (-1); }
+
+#ifdef DEBUG
+  TrapDebug((dbg_file, "Script: extra args are is %d\n", script_cnt));
+  if (trap_debug) {
+    for (i = 0; i < script_cnt; i++)
+      fprintf(dbg_file, " script_arg[%d] is %s\n", i, script_arg[i]);
+  }
+#endif
+
+                               /* Ensure we have room to shift the args */
+  if ((Argc + script_cnt) > MAX_ARGS) {
+    (void) fprintf(stderr, "Apout - out of argv space in script\n");
+    free(script_line); return (-1);
+  }
+                               /* Now shift the args up and insert new ones */
+  for (i = Argc - 1; i != 0; i--) Argv[i + script_cnt] = Argv[i];
+  for (i=0;i<Argc;i++)
+    TrapDebug((dbg_file, "Part A load_script Argv[%d] is %s\n", i, Argv[i]));
+  for (i = 0; i < script_cnt; i++) Argv[i] = script_arg[i];
+  if (origpath!=NULL) Argv[i] = strdup(origpath);
+  else Argv[i] = strdup(file);
+  Argc += script_cnt;
+  for (i=0;i<Argc;i++)
+    TrapDebug((dbg_file, "Part B load_script Argv[%d] is %s\n", i, Argv[i]));
+
+  file = xlate_filename(script_arg[0]);
+  free(script_line);
+  for (i=0;i<Argc;i++)
+    TrapDebug((dbg_file, "Leaving load_script Argv[%d] is %s\n", i, Argv[i]));
+  return (load_a_out(file, origpath, want_env));
+}
+
+
+/* Load the named PDP-11 executable file into the emulator's memory.
+ * Returns 0 if ok, -1 if error. Also initialise the simulator and set
+ * up the stack for the process with Argc, Argv, Envc, Envp.
+ * origpath is the path to the executable as seen by the simulated
+ * parent, or NULL if this is not known.
+ */
+int load_a_out(const char *file, const char *origpath, int want_env)
+{                              /* @globals errno,stdout,stderr; @ */
+#define V12_MEMBASE 16384      /* Offset for V1/V2 binaries load */
+  FILE *zin;
+  struct exec e;
+  u_int8_t *ibase, *dbase, *bbase;     /* Instruction, data, bss bases */
+  u_int16_t size;
+  int i;
+#ifdef EMU211
+  int j;
+#endif
+
+  for (i=0;i<Argc;i++)
+    TrapDebug((dbg_file, "In load_a_out Argv[%d] is %s\n", i, Argv[i]));
+
+  (void) signal(SIGBUS, bus_error);    /* Catch all bus errors here */
+
+  if ((zin = fopen(file, "r"))==NULL)  /* Open the file */
+    return (-1);
+
+  Binary = load_aout_header(zin, &e);  /* Determine a.out & Unix type */
+
+  if (e.a_magic == ANY_SCRIPT) {       /* Shell script, run that */
+    return (load_script(file, origpath, zin, want_env));
+  }
+#ifndef EMU211
+  if (Binary == IS_211BSD) {
+    (void) fprintf(stderr, "Apout not compiled to support 2.11BSD binaries\n");
+    (void) fclose(zin); return (-1);
+  }
+#endif
+#ifndef EMUV1
+  if (Binary == IS_V1) {
+    (void) fprintf(stderr,
+                  "Apout not compiled to support 1st Edition binaries\n");
+    (void) fclose(zin); return (-1);
+  }
+  if (Binary == IS_V2) {
+    (void) fprintf(stderr,
+                  "Apout not compiled to support 2nd Edition binaries\n");
+    (void) fclose(zin); return (-1);
+  }
+#endif
+
+#ifdef NATIVES
+                                       /* Executable was not recognised.
+                                        * Try to exec it as a native binary.
+                                        * If it fails, doesn't matter. If it
+                                        * succeeds, then great. This allows
+                                        * us to have mixed native and PDP-11
+                                        * binaries in the same filespace.
+                                        */
+  if (e.a_magic == UNKNOWN_AOUT) {
+#ifdef DEBUG
+    TrapDebug((dbg_file, "About to try native exec on %s\n", file));
+    fflush(dbg_file);
+#endif
+    (void) fclose(zin);
+    execv(file, Argv);         /* envp[] is the one Apout's main() got */
+    TrapDebug((dbg_file, "Nope, didn't work\n"));
+    (void) fprintf(stderr, "Apout - unknown a.out file %s\n", file);
+    return (-1);
+  }
+#endif
+                                       /* Now we know what environment to
+                                        * create, set up the memory areas
+                                        * according to the magic numbers
+                                        */
+#ifdef DEBUG
+  switch(Binary) {
+    case IS_A68: TrapDebug((dbg_file, "A68 binary\n")); break;
+    case IS_V1:  TrapDebug((dbg_file, "V1 binary\n")); break;
+    case IS_V2:  TrapDebug((dbg_file, "V2 binary\n")); break;
+    case IS_V5:  TrapDebug((dbg_file, "V5 binary\n")); break;
+    case IS_V6:  TrapDebug((dbg_file, "V6 binary\n")); break;
+    case IS_V7:  TrapDebug((dbg_file, "V7 binary\n")); break;
+    case IS_211BSD: TrapDebug((dbg_file, "2.11BSD binary\n")); break;
+  }
+#endif
+
+  switch (e.a_magic) {
+#ifdef EMUV1
+    case V1_NORMAL:                    /* V1 a.out binary looks like */
+      e.a_bss = e.a_syms;              /* 0405                       */
+      e.a_syms = e.a_data;             /* size of text               */
+      e.a_data = 0;                    /* size of symbol table       */
+                                       /* reloc bits                 */
+                                       /* size of data (i.e bss)     */
+                                       /* unused and zeroed          */
+                                       /* We must rearrange fields   */
+                                       /* Move back to start of V1 header */
+      if (fseek(zin, 0, SEEK_SET) != 0) {
+       (void) fclose(zin); return (-1);
+      }
+      ispace = dspace = darray;
+      ibase = &(ispace[V12_MEMBASE]);  /* Load & run the binary starting */
+      dbase = &(ispace[e.a_text]);     /* at address 16384 (040000) */
+      bbase = &(ispace[e.a_text + e.a_data]);
+      dwrite_base = 0;
+      e.a_entry = V12_MEMBASE;
+      break;
+#endif
+    case A68_MAGIC:                    /* Algol 68 image */
+       if (fseek(zin, 0, SEEK_SET) != 0) {
+         (void) fclose(zin); return (-1);
+       }
+       e.a_text= e.ov_siz[0]+1;
+       e.a_data= 0;
+       e.a_bss= 0160000-e.a_text;
+       e.a_entry= e.a_flag;
+       ibase = ispace = dspace = darray;
+       dbase= ibase;
+       dwrite_base = 0;
+       bbase= &(ispace[e.a_text+e.a_data]);
+       break;
+    case ANY_NORMAL:
+                                       /* Move back to end of V5/6/7 header */
+      if (fseek(zin, 16, SEEK_SET) != 0) {
+       (void) fclose(zin); return (-1);
+      }
+      ibase = ispace = dspace = darray;
+#ifdef EMUV1
+      if (Binary == IS_V2) {
+       ibase = &(ispace[V12_MEMBASE]);
+        e.a_entry = V12_MEMBASE;
+        dbase = &(ispace[e.a_text + V12_MEMBASE]);
+        bbase = &(ispace[e.a_text + e.a_data + V12_MEMBASE]);
+      } else
+#endif
+      {
+        dbase = &(ispace[e.a_text]);
+        bbase = &(ispace[e.a_text + e.a_data]);
+      }
+      if ((Binary < IS_V7))
+          dwrite_base = 0;
+      else dwrite_base = e.a_text;
+      break;
+    case ANY_ROTEXT:
+                                       /* Move back to end of V5/6/7 header */
+      if (fseek(zin, 16, SEEK_SET) != 0) {
+       (void) fclose(zin); return (-1);
+      }
+      /* @fallthrough@ */
+    case BSD_OVERLAY:
+                               /* Round up text area to next 8K boundary */
+      if (e.a_text % EIGHT_K) {
+       size = EIGHT_K * (1 + e.a_text / EIGHT_K);
+      } else size = e.a_text;
+                               /* And the next 8K boundary if overlays! */
+      if (e.a_magic == BSD_OVERLAY) {
+       if (e.max_ovl % EIGHT_K) {
+         size += EIGHT_K * (1 + e.max_ovl / EIGHT_K);
+       } else size += e.max_ovl;
+      }
+      ibase = ispace = dspace = darray;
+      dbase = &(ispace[size]);
+      bbase = &(ispace[size + e.a_data]);
+      dwrite_base = size;
+      break;
+    case ANY_SPLITID:
+                                       /* Move back to end of V5/6/7 header */
+      if (fseek(zin, 16, SEEK_SET) != 0) {
+       (void) fclose(zin); return (-1);
+      }
+      /* @fallthrough@ */
+    case BSD_ROVERLAY:
+      ibase = ispace = iarray;
+      dbase = dspace = darray;
+      bbase = &(dspace[e.a_data]);
+      
+                                       /* Try to stop null refs */
+      if (Binary == IS_211BSD) dwrite_base = 0;
+      else dwrite_base = 2;
+      break;
+    default:
+      (void) fprintf(stderr, "Apout - unknown a.out format 0%o\n", e.a_magic);
+      (void) fclose(zin); return (-1);
+  }
+
+
+               /* Initialise the instruction table for our environment */
+  switch (Binary) {
+#ifdef EMU211
+    case IS_211BSD:
+      for (i = 548; i < 552; i++) itab[i] = bsdtrap;
+      break;
+#endif
+#ifdef EMUV1
+    case IS_V1:
+    case IS_V2:
+      for (i = 544; i < 548; i++) itab[i] = rts;
+      for (i = 548; i < 552; i++) itab[i] = v1trap;
+      break;
+#endif
+    case IS_A68:
+      for (i = 544; i < 552; i++) itab[i] = v7trap;
+      break;
+    case IS_V5:
+    case IS_V6:
+    case IS_V7:
+      for (i = 548; i < 552; i++) itab[i] = v7trap;
+      break;
+    default:
+      fprintf(stderr, "Apout - unknown Unix version for %s\n", file);
+      exit(EXIT_FAILURE);
+  }
+
+#ifdef ZERO_MEMORY
+  memset(darray, 0, PDP_MEM_SIZE);     /* Clear all memory */
+  if (ispace != dspace) memset(iarray, 0, PDP_MEM_SIZE);
+#endif
+
+                                       /* Now load the text into ibase */
+  for (size = e.a_text; size;) {
+    i = (int) fread(ibase, 1, (size_t) size, zin);
+    if (i == -1) { (void) fclose(zin); return (i); }
+    size -= i;
+    ibase += i;
+  }
+
+#ifdef EMU211
+  /* Now deal with any overlays */
+  if (Binary == IS_211BSD)
+    switch (e.a_magic) {
+      case BSD_OVERLAY:
+      case BSD_ROVERLAY:
+                               /* Round up text area to next 8K boundary */
+       if (e.a_text % EIGHT_K) {
+         size = EIGHT_K * (1 + e.a_text / EIGHT_K);
+       } else size = e.a_text;
+       ovbase = &ispace[size];
+
+       for (i = 0; i < NOVL; i++) {
+         if (e.ov_siz[i] == 0) {
+           ovlist[i].size = 0;
+           ovlist[i].ovlay = NULL;
+           continue;
+         }
+                                       /* Create memory for the overlay */
+         ovlist[i].size = e.ov_siz[i];
+         if (ovlist[i].ovlay)
+           free(ovlist[i].ovlay);
+         ovlist[i].ovlay = (u_int8_t *) malloc(e.ov_siz[i]);
+         if (ovlist[i].ovlay == NULL) {
+           fprintf(stderr, "Apout - can't malloc overlay!\n");
+           exit(EXIT_FAILURE);
+         }
+                                       /* Load the overlay into memory */
+         for (size = ovlist[i].size, ibase = ovlist[i].ovlay; size;) {
+           j = fread(ibase, 1, size, zin);
+           if (j == -1) {
+             fclose(zin); return (j);
+           }
+           size -= j;
+           ibase += j;
+         }
+       }
+
+                               /* And deal with the emt instructions */
+       for (i = 544; i < 548; i++)
+         itab[i] = do_bsd_overlay;
+    }
+#endif
+
+                               /* Now load the data into dbase */
+  if (dbase)
+    for (size = e.a_data; size;) {
+      i = (int) fread(dbase, 1, (size_t) size, zin);
+      if (i == -1) { (void) fclose(zin); return (i); }
+      size -= i;
+      dbase += i;
+    }
+
+                               /* Now clear the bss */
+  if ((bbase != 0) && (e.a_bss != 0))
+    memset(bbase, 0, (size_t) e.a_bss);
+
+
+  /* Set up the registers and flags, and the stack */
+  (void) fclose(zin);
+  sim_init();
+  regs[PC] = e.a_entry;
+  if( Binary == IS_A68 ) {
+      regs[5]= e.max_ovl;
+      regs[4]= 0160000;
+  }
+  set_arg_env(want_env);
+  return (0);
+}
+
+/*
+ * C runtime startoff. When an a.out is loaded by the kernel, the kernel
+ * sets up the stack as follows:
+ *
+ *     _________________________________
+ *     | (NULL)                        | 0177776: top of memory
+ *     |-------------------------------|
+ *     |                               |
+ *     | environment strings           |
+ *     |                               |
+ *     |-------------------------------|
+ *     |                               |
+ *     | argument strings              |
+ *     |                               |
+ *     |-------------------------------|
+ *     | envv[envc] (NULL)             | end of environment vector tag, a 0
+ *     |-------------------------------|
+ *     | envv[envc-1]                  | pointer to last environment string
+ *     |-------------------------------|
+ *     | ...                           |
+ *     |-------------------------------|
+ *     | envv[0]                       | pointer to first environment string
+ *     |-------------------------------|
+ *     | argv[argc] (NULL)             | end of argument vector tag, a 0
+ *     |-------------------------------|
+ *     | argv[argc-1]                  | pointer to last argument string
+ *     |-------------------------------|
+ *     | ...                           |
+ *     |-------------------------------|
+ *     | argv[0]                       | pointer to first argument string
+ *     |-------------------------------|
+ * sp-> | argc                         | number of arguments
+ *     ---------------------------------
+ *
+ * Crt0 simply moves the argc down two places in the stack, calculates the
+ * the addresses of argv[0] and envv[0], putting those values into the two
+ * spaces opened up to set the stack up as main expects to see it.
+ *
+ * If want_env is set, create a stack by including environment variables:
+ * used by V7, 2.9BSD, 2.11BSD. Otherwise, don't create environment
+ * variables: used by V1 up to V6.
+ */
+static void set_arg_env(int want_env)
+{
+  int i, posn, len;
+  int eposn[MAX_ARGS];
+  int aposn[MAX_ARGS];
+
+                               /* Set default environment if there is none */
+  if (Envp[0] == NULL) {
+    Envc = default_envc;
+    for (i = 0; i < Envc; i++)
+      Envp[i] = default_envp[i];
+  }
+#ifdef DEBUG
+                       /* Set up the program's name -- used for debugging */
+  if (progname) free(progname);
+  progname = strdup(Argv[0]);
+
+  if (trap_debug) {
+    fprintf(dbg_file, "In set_arg_env, Argc is %d\n", Argc);
+    for (i = 0; i < Argc; i++)
+      fprintf(dbg_file, "  Argv[%d] is %s\n", i, Argv[i]);
+    for (i = 0; i < Envc; i++)
+      fprintf(dbg_file, "  Envp[%d] is %s\n", i, Envp[i]);
+  }
+#endif
+
+                       /* Now build the arguments and pointers on the stack */
+
+#ifdef EMUV1
+  if ((Binary == IS_V1) || (Binary == IS_V2))
+    posn = KE11LO - 2;                         /* Start below the KE11A */
+  else
+#endif
+    posn = PDP_MEM_SIZE - 2;
+  sl_word(posn, 0);                            /* Put a NULL on top of stack */
+
+  if (want_env == 1)
+    for (i = Envc - 1; i != -1; i--) {         /* For each env string */
+      len = strlen(Envp[i]) + 1;               /* get its length */
+      posn -= len;
+      memcpy(&dspace[posn], Envp[i], (size_t) len);
+      eposn[i] = posn;
+    }
+
+  for (i = Argc - 1; i != -1; i--) {           /* For each arg string */
+    len = strlen(Argv[i]) + 1;                 /* get its length */
+    posn -= len;
+    memcpy(&dspace[posn], Argv[i], (size_t) len);
+    aposn[i] = posn;
+  }
+  posn -= 2;
+  sl_word(posn, 0);                    /* Put a NULL at end of env array */
+
+  if (want_env == 1) {                 /* For each env string */
+    for (i = Envc - 1; i != -1; i--) {
+      posn -= 2;                       /* put a pointer to the string */
+      sl_word(posn, (u_int16_t) eposn[i]);
+    }
+    posn -= 2;
+  }
+                                       /* Put a NULL or -1 before arg ptrs */
+  if (want_env == 0) sl_word(posn, -1)
+  else sl_word(posn, 0);
+
+  for (i = Argc - 1; i != -1; i--) {           /* For each arg string */
+    posn -= 2;
+    sl_word(posn, (u_int16_t) aposn[i]);       /* put a ptr to the string */
+  }
+  posn -= 2;
+  sl_word(posn, (u_int16_t) Argc);             /* Save the count of args */
+  regs[SP] = (u_int16_t) posn;                 /* and initialise the SP */
+}
+
+
+#ifdef EMU211
+/* This function probably belongs in bsdtrap.c, but all the vars are
+ * here, so why not!
+ *
+ * Deal with overlay changes which come in via an emt instruction.
+ */
+
+void do_bsd_overlay()
+{
+  int ov = regs[0] - 1;
+
+  if (ovlist[ov].size == 0) {
+    fprintf(stderr, "Apout - can't switch to empty overlay %d\n", ov);
+    exit(EXIT_FAILURE);
+  }
+  JsrDebug((dbg_file, "switching to overlay %d\n", ov));
+
+  /* Memcpy overlay into main ispace */
+  memcpy(ovbase, ovlist[ov].ovlay, ovlist[ov].size);
+  ov_changes++;
+  current_ov = ov;
+}
+#endif
diff --git a/aout.h b/aout.h
new file mode 100644 (file)
index 0000000..e211353
--- /dev/null
+++ b/aout.h
@@ -0,0 +1,54 @@
+/* aout.h - parse and load the contents of a UNIX a.out file, for
+ * several flavours of PDP-11 UNIX
+ *
+ * $Revision: 1.4 $
+ * $Date: 2000/08/11 07:07:35 $
+ */
+#include <unistd.h>
+#define EIGHT_K                 8192
+
+/* UNIX magic numbers for the a.out header */
+#define V1_NORMAL      0405    /* normal: 1st Edition, six words long */
+#define ANY_NORMAL     0407    /* normal: V5,V6,V7,2.11BSD */
+#define ANY_ROTEXT     0410    /* read-only text: V5,V6,V7,2.11BSD */
+#define ANY_SPLITID    0411    /* seperated I&D: V5,V6,V7,2.11BSD */
+#define BSD_OVERLAY    0430    /* 2.11BSD overlay, non-separate */
+#define BSD_ROVERLAY   0431    /* 2.11BSD overlay, separate */
+#define ANY_SCRIPT     020443  /* Shell script, i.e #! */
+#define A68_MAGIC      0       /* Algol68 binaries have these magic nums */
+#define A68_DATA       0107116 /* Algol68 binaries have these magic nums */
+
+#define UNKNOWN_AOUT   034567  /* An unknown a.out header */
+
+/* a.out header for nearly all UNIX flavours */
+struct exec {
+    u_int16_t a_magic;         /* magic number */
+    u_int16_t a_text;          /* size of text segment */
+    u_int16_t a_data;          /* size of initialised data */
+    u_int16_t a_bss;           /* size of initialised bss */
+    u_int16_t a_syms;          /* size of symbol table */
+    u_int16_t a_entry;         /* entry point */
+    u_int16_t a_unused;                /* unused */
+    u_int16_t a_flag;          /* relocation info stripped */
+                               /* 16 bytes up to here */
+
+                               /* 2.11BSD overlay files have the following */
+#define NOVL   15
+     int16_t max_ovl;          /* maximum overlay size */
+    u_int16_t ov_siz[NOVL];    /* size of the i'th overlay */
+                               /* Note that if the file isn't a 2.11BSD */
+                               /* overlay, we have to rewind to undo */
+                               /* the read of this section */
+};
+
+/* Because V5, V6, V7 and 2.11BSD share several magic numbers
+ * in their a.out headers, we must distinguish them so as to
+ * set up the correct emulated environment. This is done by
+ * observing the differences in their crt0.s code: they all
+ * differ at position 021
+ */
+#define a_magic2       ov_siz[0]
+#define V2_M2          0177304         /* Doesn't apply to all, tho */
+#define V6_M2          0010600
+#define V7_M2          0016600
+#define BSD_M2         0162706
diff --git a/apout.1 b/apout.1
new file mode 100644 (file)
index 0000000..902365b
--- /dev/null
+++ b/apout.1
@@ -0,0 +1,234 @@
+.\" Copyright Warren Toomey
+.\"
+.\" $Revision: 1.9 $
+.\" $Date: 2002/06/10 12:08:27 $
+.\"
+.Dd December, 2000
+.Dt APOUT 1
+.Os
+.Sh NAME
+.Nm apout
+.Nd run PDP-11 UNIX a.out binaries
+.Sh SYNOPSIS
+.Nm apout
+.Op Fl inst
+.Op Fl trap
+.Op Fl jsr
+.Op Fl fp
+.Ar file
+.Op Ar arguments ...
+.Sh DESCRIPTION
+.Nm apout
+runs the
+.Ar file
+which contains a PDP-11 UNIX a.out binary from one of the following
+versions of UNIX: 1st Edition, 2nd Edition, 5th Edition, 6th Edition,
+7th Edition, 2.9BSD or 2.11BSD. Any arguments after the named
+.Ar file
+are passed as arguments to the a.out binary.
+.Pp
+User-mode PDP-11 instructions are interpreted and executed by
+.Nm apout,
+and system calls made by the interpreted a.out binary are performed
+by making real systems calls to the underlying native operating system.
+In this way, the interpreted a.out binary can interact with the real
+files and processes on the system.
+.Pp
+If
+.Nm apout
+has been compiled with debugging enabled, the following options are available:
+.Bl -tag -width trap
+.It Fl inst
+Output a line for each instruction emulated which gives:
+the PC in octal, the instruction in octal, the instruction's name,
+r0 to r6 in octal, and the values of the N, Z, V and C flags.
+.It Fl trap
+Output a line for each system call, which gives the name of the system
+call, possibly a list of arguments, and the value returned by the system
+call.
+.It Fl jsr
+Output a line for each
+.Ar jsr
+or
+.Ar rts
+giving the value of the new PC. For 2.11BSD overlay binaries, also output
+a line describing each overlay change.
+.It Fl fp
+For many of the emulated floating-point instructions, output a line
+describing the operation.
+.El
+.Pp
+If
+.Nm apout
+was not compiled with debugging enabled, none of these options exist.
+Any debugging output is directed to the file
+.Ar apout.dbg
+in the directory where
+.Nm apout
+was started. The debugging output is primarily designed to aid the
+developers of
+.Nm apout,
+and so it isn't exhaustive for all instructions, traps or floating-point
+operations.
+.Sh ENVIRONMENT VARIABLES
+.Nm apout
+requires one environment variable to be set:
+.Ev APOUT_ROOT.
+This variable names the `root' of the emulated filesystem.
+.Pp
+When
+.Nm apout
+works with filenames, if the filenames are relative, then they
+stay relative i.e all files on the system can be named, as long as they are
+given relative names. However, if the filenames are absolute, i.e they
+start with a slash, then
+.Nm apout
+prepends the value of the environment variable
+.Ev APOUT_ROOT
+to the filename. Therefore, if you have the 7th Edition files located in
+.Ar /usr/misc/v7root
+and you do:
+.Bd -literal
+    %  setenv APOUT_ROOT /usr/misc/v7root
+    %  apout $APOUT_ROOT/bin/sh
+    $
+.Ed
+.Pp
+then you will be greeted with the 7th Edition Bourne shell prompt as shown:
+you will still be in the directory where you started
+.Nm apout,
+but if you cd to /, then you will be taken to
+.Ar /usr/misc/v7root
+.Pp
+Note that you must set
+.Ev APOUT_ROOT
+before you can run 
+.Nm apout.
+.Sh EMULATED ENVIRONMENT VARIABLES
+Initially, PDP-11 binaries run via
+.Nm apout
+receive the following set of emulated environment variables:
+.Bd -literal
+    PATH  /bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/games:/usr/local/bin:.
+    HOME  /
+    TERM  vt100
+.Ed
+.Pp
+Emulated programs can, of course, change this emulated environment;
+they can also fork and exec other PDP-11 binaries, which will inherit the
+modified emulated environment.
+.Sh INTERACTION WITH NATIVE PROGRAMS
+Binaries that are interpreted by
+.Nm apout
+can interact with native programs in several ways: through files in the
+filesystem, and through pipes. For example, you can do the following:
+.Bd -literal
+    %  ls -lR | apout $APOUT_ROOT/bin/wc | lpr
+    %  apout $APOUT_ROOT/bin/sort < file | uniq > newfile
+.Ed
+.Pp
+where
+.Ar ls,
+.Ar lpr
+and
+.Ar uniq
+are native programs.
+.Pp
+If
+.Nm apout
+is compiled with the NATIVES preprocessor directive enabled, then native system
+binaries can be executed as well as PDP-11 binaries. For example:
+.Bd -literal
+    % cd $APOUT_ROOT
+    % ln -s `which vi` bin/vi       Add vi into the filespace
+    % apout bin/sh
+    $ ls -l                         Run the PDP-11 ls
+      ....
+    $ vi kim.c                      Run the native vi
+    $ cc -o kim kim.c               Compile with the PDP-11 compiler
+.Ed
+.Pp
+Note that native executable receive the same environment variables inherited
+by the
+.Nm apout
+process, and not the emulated environment that
+.Nm apout
+passes to emulated executables.
+.Sh ERROR MESSAGES
+So as to distinguish from error messages generated by the interpreted PDP-11
+binaries,
+.Nm apout
+prepends the word `Apout' to the beginning of its error messages. Below is
+the list of error messages that
+.Nm apout
+can generate:
+.Bd -ragged
+   Apout - V1 sectosixty too big
+   Apout - can't malloc overlay!
+   Apout - can't switch to empty overlay %d
+   Apout - could not read 1st line of script
+   Apout - couldn't load %s
+   Apout - open_dir couldn't open %s
+   Apout - out of argv space in script
+   Apout - pid %d bad FP register used at PC 0%o
+   Apout - pid %d bpt instruction at PC 0%o
+   Apout - pid %d bus error at PC 0%06o
+   Apout - pid %d emt instruction at PC 0%o
+   Apout - pid %d halt instruction at PC 0%o
+   Apout - pid %d illegal instruction %o at PC 0%o
+   Apout - pid %d iot instruction at PC 0%o
+   Apout - pid %d mark instruction at PC 0%o
+   Apout - pid %d mfpd instruction at PC 0%o
+   Apout - pid %d mtpd instruction at PC 0%o
+   Apout - pid %d segmentation fault at PC 0%06o
+   Apout - pid %d trap instruction at PC 0%o
+   Apout - pid %d unimplemented instruction at PC 0%o
+   Apout - pid %d unknown KE11 register 0%o
+   Apout - pid %d waiti instruction at PC 0%o
+   Apout - the %s syscall is not yet implemented
+   Apout - the 2.11BSD %s syscall is not yet implemented
+   Apout - unknown a.out format 0%o
+   Apout - unknown magic in header: 0x%x
+   Apout - unknown syscall %d at PC 0%o
+   Apout cannot set the environment for the a.out %s
+   Apout not compiled to support 1st Edition binaries
+   Apout not compiled to support 2nd Edition binaries
+   Apout not compiled to support 2.11BSD binaries
+.Ed
+.Sh CAVEATS
+As far as is known, the emulation of user-mode integer instructions is correct.
+The emulation of floating-point instructions is seriously deficient:
+only 32-bit floats are emulated: the extra 32-bits of precision in PDP-11
+doubles goes unused. None of the FP errors are emulated.
+.Pp
+The emulation of each of the emulated UNIX environments is mostly,
+but not fully, complete. Any UNIX system call environment is very
+sophisticated, and
+.Ar apout
+must translate from the emulated UNIX environment to the native one, and
+back. For an authorative description of what is missing from, or deficient
+in, each of the emulated UNIX environments, see the source files
+.Ar v1trap.c,
+.Ar v7trap.c
+and
+.Ar bsdtrap.c
+in the source directory for
+.Nm apout.
+You should also consult the file
+.Ar LIMITATIONS
+in the source directory for
+.Nm apout.
+.Sh SEE ALSO
+The latest source for
+.Nm apout
+can be obtained via anonymous ftp at minnie.tuhs.org in the directory
+pub/PDP-11/Sims/Apout. The directory pub/PDP-11/Sims/Apout/UnixBins
+contains tar archives of a.out binaries from several versions of UNIX.
+Information on PDP-11 UNIX can be found on the PUPS web page at
+http://minnie.tuhs.org/PUPS/
+.Sh HISTORY
+The first version of
+.Nm apout
+appeared in 1995, and provided support for 6th and 7th Edition
+UNIX binaries. In 1998/1999, support was added for 2.11BSD binaries.
+In 1999/2000, support was added for 1st and 2nd Edition UNIX binaries.
diff --git a/branch.c b/branch.c
new file mode 100644 (file)
index 0000000..94ab008
--- /dev/null
+++ b/branch.c
@@ -0,0 +1,387 @@
+/* branch.c - Branch instructions, and instructions which are complex to do
+ *
+ * $Revision: 2.22 $
+ * $Date: 1999/12/27 04:38:29 $
+ */
+#include "defines.h"
+
+/* We use the following macro for the branch instructions below */
+
+#define do_branch() \
+    {  offset = LOW8(ir); \
+       if (offset & SIGN_B) \
+           offset += 0177400; \
+       regs[PC] += (offset * 2); \
+    } \
+
+static u_int16_t offset;
+
+void bne() {
+    if (CC_Z==0) do_branch();
+}
+void beq() {
+    if (CC_Z==1) do_branch();
+}
+void bpl() {
+    if (CC_N==0) do_branch();
+}
+void bmi() {
+    if (CC_N==1) do_branch();
+}
+void bhi() {
+    if ((CC_Z==0) && (CC_C==0)) do_branch();
+}
+void bvc() {
+    if (CC_V==0) do_branch();
+}
+void bvs() {
+    if (CC_V==1) do_branch();
+}
+void bcc() {
+    if (CC_C==0) do_branch();
+}
+void bcs() {
+    if (CC_C==1) do_branch();
+}
+
+/* br() - Branch Always. */
+void br() {
+    do_branch();
+}
+
+
+/* blos() - Branch Lower or Same Instruction. */
+void blos() {
+    if ((CC_C!=0) || (CC_Z!=0)) do_branch();
+}
+
+/* bge() - Branch Greater Than or Equal Instruction. */
+void bge() {
+    if ((CC_N ^ CC_V) == 0) do_branch();
+}
+
+/* blt() - Branch Less Than Instruction. */
+void blt() {
+    if ((CC_N ^ CC_V) == 1) do_branch();
+}
+
+/* ble() - Branch Less Than Or Equal Instruction. */
+void ble() {
+    if (((CC_N ^ CC_V) == 1) || ((CC_Z)!=0)) do_branch();
+}
+
+/* bgt() - Branch Greater Than Instruction. */
+void bgt() {
+    if (((CC_N ^ CC_V) == 0) && ((CC_Z) == 0)) do_branch();
+}
+
+/* jmp() - Jump Instruction. */
+void jmp() {
+    load_ea(); regs[PC]=dstword;
+}
+
+/* jsr() - Jump To Subroutine Instruction. */
+void jsr() {
+    load_ea();
+    srcword=regs[SRC_REG]; push();
+    regs[SRC_REG] = regs[PC];
+    regs[PC] = dstword;
+    JsrDebug((dbg_file, "jsr to 0%o\n", dstword));
+}
+
+/* rts() - Return From Subroutine Instruction. */
+void rts() {
+    regs[PC] = regs[DST_REG];
+    pop(); regs[DST_REG] = dstword;
+    JsrDebug((dbg_file, "rts to 0%o\n", regs[PC]));
+}
+
+void scc() {
+    if (ir & CC_NBIT) CC_N=1;
+    if (ir & CC_ZBIT) CC_Z=1;
+    if (ir & CC_VBIT) CC_V=1;
+    if (ir & CC_CBIT) CC_C=1;
+}
+void ccc() {
+    if (ir & CC_NBIT) CC_N=0;
+    if (ir & CC_ZBIT) CC_Z=0;
+    if (ir & CC_VBIT) CC_V=0;
+    if (ir & CC_CBIT) CC_C=0;
+}
+
+/* sob() - Subtract One and Branch Instruction. */
+void sob() {
+    regs[SRC_REG] -= 1;
+    if (regs[SRC_REG]) {
+       regs[PC] -= (ir & 077) * 2;
+    }
+}
+
+/* mfps() - Move from Processor Status Instruction. */
+void mfps() {
+    srcbyte=(u_int8_t)0;
+    if (CC_N) srcbyte|= CC_NBIT;
+    if (CC_Z) srcbyte|= CC_ZBIT;
+    if (CC_V) srcbyte|= CC_VBIT;
+    if (CC_C) srcbyte|= CC_CBIT;
+
+    CHGB_CC_N(srcbyte);
+    CHGB_CC_Z(srcbyte);
+    CLR_CC_V();
+
+    if (DST_MODE) {
+       storeb_dst();
+    } else {
+       if (srcbyte & SIGN_B) {
+           dstword = 0177400;
+       } else {
+           dstword = 0;
+       }
+       dstword += (u_int16_t)srcbyte;
+       store_dst();
+    }
+}
+
+/* mtps() - Move to Processor Status Instruction. */
+void mtps() {
+    loadb_dst();
+    if (dstbyte & CC_NBIT) CC_N=1;
+    if (dstbyte & CC_ZBIT) CC_Z=1;
+    if (dstbyte & CC_VBIT) CC_V=1;
+    if (dstbyte & CC_CBIT) CC_C=1;
+}
+
+/* mfpi() - Move From Previous Instruction Space Instruction. */
+void mfpi() {
+    loadp_dst(); push();
+}
+
+
+/* mtpi() - To From Previous Instruction Space Instruction. */
+void mtpi() {
+     pop(); storep_dst();
+}
+
+/* ash() - Arithmetic Shift Instruction. */
+void ash() {
+    u_int16_t temp;
+    u_int16_t old;
+    u_int16_t sign;
+    u_int16_t count;
+
+    temp = regs[SRC_REG];
+    load_dst();
+    old = temp;
+
+    if ((dstword & 077) == 0) {                /* no shift */
+       CHG_CC_N(temp);
+       CHG_CC_Z(temp);
+       CLR_CC_V();
+       return;
+    }
+    if (dstword & 040) {               /* right shift */
+       count = 0100 - (dstword & 077);
+       sign = temp & SIGN;
+       while (count--) {
+           if (temp & LSBIT) {
+               SET_CC_C();
+           } else {
+               CLR_CC_C();
+           }
+           temp >>= 1;
+           temp += sign;
+       }
+    } else {                           /* left shift */
+       count = dstword & 037;
+       while (count--) {
+           if (temp & SIGN) {
+               SET_CC_C();
+           } else {
+               CLR_CC_C();
+           }
+           temp <<= 1;
+       }
+    }
+
+    CHG_CC_N(temp);
+    CHG_CC_Z(temp);
+
+    if ((old & SIGN) == (temp & SIGN)) {
+       CLR_CC_V();
+    } else {
+       SET_CC_V();
+    }
+    regs[SRC_REG] = temp;
+}
+
+
+/* mul() and divide() - Multiply and Divide Instructions.  These work on
+ * signed values, and we'll do the same.  This may not be portable. */
+
+union s_u_word {
+    u_int16_t u_word;
+    short s_word;
+};
+
+union s_u_long {
+    u_int32_t u_long;
+    long s_long;
+};
+
+void mul() {
+    union s_u_word data1;
+    union s_u_word data2;
+    union s_u_long tmp;
+
+    data1.u_word = regs[SRC_REG];
+    load_dst();
+    data2.u_word=dstword;
+
+    tmp.s_long = ((long) data1.s_word) * ((long) data2.s_word);
+
+    regs[SRC_REG] = (u_int16_t)(tmp.u_long >> 16);
+    regs[(SRC_REG) | 1] = (u_int16_t)(tmp.u_long & 0177777);
+
+    CLR_CC_ALL();
+
+    if (tmp.u_long == 0)
+       SET_CC_Z();
+    else
+       CLR_CC_Z();
+
+    if (tmp.u_long & 0x80000000)
+       SET_CC_N();
+    else
+       CLR_CC_N();
+}
+
+void divide() {
+    union s_u_long tmp;
+    union s_u_long eql;
+    union s_u_word data2;
+
+    tmp.u_long = regs[SRC_REG];
+    tmp.u_long = tmp.u_long << 16;
+    tmp.u_long += regs[(SRC_REG) | 1];
+
+    load_dst();
+    data2.u_word=dstword;
+
+    if (data2.u_word == 0) {
+       SET_CC_C();
+       SET_CC_V();
+       return;
+    } else {
+       CLR_CC_C();
+    }
+
+    eql.s_long = tmp.s_long / data2.s_word;
+    regs[SRC_REG] = (u_int16_t)eql.u_long & 0177777;
+
+    if (eql.u_long == 0)
+       SET_CC_Z();
+    else
+       CLR_CC_Z();
+
+    if ((eql.s_long > 077777) || (eql.s_long < -0100000))
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    if (eql.s_long < 0)
+       SET_CC_N();
+    else
+       CLR_CC_N();
+
+    eql.s_long = tmp.s_long % data2.s_word;
+    regs[(SRC_REG) | 1] = (u_int16_t)eql.u_long & 0177777;
+}
+
+/* ashc() - Arithmetic Shift Combined Instruction. */
+void ashc() {
+    u_int32_t temp;
+    u_int32_t old;
+    u_int32_t sign;
+    u_int16_t count;
+
+    temp = regs[SRC_REG];
+    temp <<= 16;
+    temp += regs[(SRC_REG) | 1];
+    old = temp;
+    load_dst();
+
+    if ((dstword & 077) == 0) { /* no shift */
+
+       CLR_CC_V();
+
+       if (temp & 0x80000000) {
+           SET_CC_N();
+       } else {
+           CLR_CC_N();
+       }
+
+       if (temp) {
+           CLR_CC_Z();
+       } else {
+           SET_CC_Z();
+       }
+       return;
+    }
+    if (dstword & 040) {               /* right shift */
+       count = 0100 - (dstword & 077);
+       sign = temp & 0x80000000;
+       while (count--) {
+           if (temp & LSBIT) {
+               SET_CC_C();
+           } else {
+               CLR_CC_C();
+           }
+           temp >>= 1;
+           temp += sign;
+       }
+    } else {                   /* left shift */
+       count = dstword & 037;
+       while (count--) {
+           if (temp & 0x80000000) {
+               SET_CC_C();
+           } else {
+               CLR_CC_C();
+           }
+           temp <<= 1;
+       }
+    }
+
+    if (temp & 0x80000000)
+       SET_CC_N();
+    else
+       CLR_CC_N();
+
+    if (temp)
+       CLR_CC_Z();
+    else
+       SET_CC_Z();
+
+    if ((old & 0x80000000) == (temp & 0x80000000)) {
+       CLR_CC_V();
+    } else {
+       SET_CC_V();
+    }
+
+    regs[SRC_REG] = (u_int16_t)(temp >> 16);
+    regs[(SRC_REG) | 1] = LOW16(temp);
+}
+
+/* xor() - Exclusive Or Instruction */
+void xor() {
+    tmpword = regs[SRC_REG];
+
+    load_dst();
+
+    tmpword = tmpword ^ dstword;
+
+    CHG_CC_N(tmpword);
+    CHG_CC_Z(tmpword);
+    CLR_CC_V();
+
+    dstword=tmpword; store_dst_2();
+}
diff --git a/bsd_ioctl.c b/bsd_ioctl.c
new file mode 100644 (file)
index 0000000..3fd1e0f
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * bsd_ioctl.c - Deal with 2.11BSD ioctl system calls.
+ *
+ * $Revision: 1.13 $ $Date: 1999/12/27 04:38:29 $
+ */
+#ifdef EMU211
+#include "defines.h"
+#include <sys/ioctl.h>
+#include <termios.h>
+#include "bsdtrap.h"
+#ifdef __linux__
+#include <linux/sockios.h>     /* FIOSETOWN */
+#endif
+
+/* Structures and defines required by this file */
+
+/* First the list of ioctls handled so far */
+#define TR_FIOCLEX     0x20006601      /* 0x2 is void */
+#define TR_TIOCGETP    0x40067408      /* 0x4 is a read */
+#define TR_TIOCSETP    0x40067409      /* 0x8 is a write */
+#define        TR_TIOCSETN     0x8006740a
+#define        TR_TIOCSETC     0x80067411
+#define TR_TIOCGETD    0x40027400
+#define TR_TIOCSETD    0x80027401
+#define TR_TIOCGETC    0x40067412
+#define TR_TIOCGLTC    0x40067474
+#define TR_TIOCSLTC    0x80067475
+#define TR_TIOCGWINSZ  0x40087468
+#define TR_TIOCSWINSZ  0x40027467
+#define TR_FIOSETOWN   0x8002667b
+#define TR_TIOCMGET    0x4002746a
+#define TR_TIOCGPGRP   0x40027477
+#define TR_TIOCSPGRP   0x80027476
+
+/* sgtty structure */
+struct tr_sgttyb {
+  int8_t sg_ispeed;            /* input speed */
+  int8_t sg_ospeed;            /* output speed */
+  int8_t sg_erase;             /* erase character */
+  int8_t sg_kill;              /* kill character */
+  int16_t sg_flags;            /* mode flags */
+};
+
+struct tr_tchars {
+        int8_t    t_intrc;        /* interrupt */
+        int8_t    t_quitc;        /* quit */
+        int8_t    t_startc;       /* start output */
+        int8_t    t_stopc;        /* stop output */
+        int8_t    t_eofc;         /* end-of-file */
+        int8_t    t_brkc;         /* input delimiter (like nl) */
+};
+
+struct tr_ltchars {
+        int8_t    t_suspc;        /* stop process signal */
+        int8_t    t_dsuspc;       /* delayed stop process signal */
+        int8_t    t_rprntc;       /* reprint line */
+        int8_t    t_flushc;       /* flush output (toggles) */
+        int8_t    t_werasc;       /* word erase */
+        int8_t    t_lnextc;       /* literal next character */
+};
+
+/*
+ * Values for sg_flags
+ */
+#define      TR_TANDEM          0x00000001     /* send stopc on out q full */
+#define      TR_CBREAK          0x00000002     /* half-cooked mode */
+                                               /* 0x4 (old LCASE) */
+#define      TR_ECHO            0x00000008     /* echo input */
+#define      TR_CRMOD           0x00000010     /* map \r to \r\n on output */
+#define      TR_RAW             0x00000020     /* no i/o processing */
+#define      TR_ODDP            0x00000040     /* get/send odd parity */
+#define      TR_EVENP           0x00000080     /* get/send even parity */
+#define      TR_ANYP            0x000000c0     /* get any parity/send none */
+                                               /* 0x100 (old NLDELAY) */
+                                               /* 0x200 */
+#define      TR_XTABS           0x00000400     /* expand tabs on output */
+
+/* Values for sg_ispeed and sg_ospeed */
+#define TR_B0      0
+#define TR_B50     1
+#define TR_B75     2
+#define TR_B110    3
+#define TR_B134    4
+#define TR_B150    5
+#define TR_B200    6
+#define TR_B300    7
+#define TR_B600    8
+#define TR_B1200   9
+#define TR_B1800   10
+#define TR_B2400   11
+#define TR_B4800   12
+#define TR_B9600   13
+#define TR_EXTA    14
+#define TR_EXTB    15
+
+
+
+/* Variables, functions and the actual code of this file */
+
+extern arglist *A;             /* Pointer to various arguments on stack */
+
+/* Forward prototypes */
+#ifdef __STDC__
+#define P(s) s
+#else
+#define P(s) ()
+#endif
+
+static int trap_gettermios(u_int16_t fd, u_int32_t type, u_int16_t ucnt);
+static int trap_settermios(u_int16_t fd, u_int32_t type, u_int16_t ucnt);
+
+#undef P
+
+int trap_ioctl()
+{
+  int i, val;
+  long larg1;
+#ifdef DEBUG
+  u_int8_t size, letter, value;
+#endif
+  int16_t *shortptr;
+  struct winsize *winptr;
+
+  larg1 = (sarg2 << 16) | uarg3;
+
+#ifdef DEBUG
+  if (trap_debug) {
+    fprintf(dbg_file, "val %d ",uarg1);
+    switch (larg1) {
+      case TR_FIOCLEX:   fprintf(dbg_file, "FIOCLEX "); break;
+      case TR_TIOCGETP:          fprintf(dbg_file, "TIOCGETP "); break;
+      case TR_TIOCSETP:          fprintf(dbg_file, "TIOCSETP "); break;
+      case TR_TIOCSETN:          fprintf(dbg_file, "TIOCSETN "); break;
+      case TR_TIOCSETC:          fprintf(dbg_file, "TIOCSETC "); break;
+      case TR_TIOCGETD:          fprintf(dbg_file, "TIOCGETD "); break;
+      case TR_TIOCSETD:          fprintf(dbg_file, "TIOCSETD "); break;
+      case TR_TIOCGETC:          fprintf(dbg_file, "TIOCGETC "); break;
+      case TR_TIOCGLTC:          fprintf(dbg_file, "TIOCGLTC "); break;
+      case TR_TIOCSLTC:          fprintf(dbg_file, "TIOCSLTC "); break;
+      case TR_TIOCGWINSZ: fprintf(dbg_file, "TIOCGWINSZ "); break;
+      case TR_TIOCSWINSZ: fprintf(dbg_file, "TIOCSWINSZ "); break;
+      case TR_FIOSETOWN:  fprintf(dbg_file, "FIOSETOWN "); break;
+      case TR_TIOCMGET:   fprintf(dbg_file, "TIOCMGET "); break;
+      case TR_TIOCGPGRP:  fprintf(dbg_file, "TIOCGPGRP "); break;
+      case TR_TIOCSPGRP:  fprintf(dbg_file, "TIOCSPGRP "); break;
+      default: fprintf(dbg_file, "0x%lx ", larg1);
+
+       value =  larg1 & 0xff;
+       letter = (larg1 >> 8) & 0xff;
+       size =   (larg1 >> 16) & 0xff;
+
+       fprintf(dbg_file, "('%c' ", letter);
+       fprintf(dbg_file, "size %d ", size);
+       fprintf(dbg_file, "val %d) ", value);
+    }
+    if (size) fprintf(dbg_file, "ptr %d ", uarg4);
+  }
+#endif
+
+  switch (larg1) {
+
+    case TR_TIOCGETP:
+    case TR_TIOCGETC:
+    case TR_TIOCGLTC:
+      i = trap_gettermios(uarg1, larg1, uarg4); break;
+
+    case TR_TIOCSETP:
+    case TR_TIOCSETN:
+    case TR_TIOCSETC:
+    case TR_TIOCSLTC:
+      i = trap_settermios(uarg1, larg1, uarg4); break;
+
+    case TR_FIOCLEX:
+      i = ioctl(uarg1, FIOCLEX, NULL); break;
+    case TR_TIOCGETD:
+      shortptr = (int16_t *) &dspace[uarg4];
+      i = ioctl(uarg1, TIOCGETD, &val);
+      if (i==0) *shortptr= val;
+      break;
+    case TR_TIOCGPGRP:
+      shortptr = (int16_t *) &dspace[uarg4];
+      i = ioctl(uarg1, TIOCGPGRP, &val);
+      if (i==0) *shortptr= val;
+      break;
+    case TR_TIOCSPGRP:
+      shortptr = (int16_t *) &dspace[uarg4];
+      val= *shortptr; i = ioctl(uarg1, TIOCSPGRP, &val); break;
+    case TR_TIOCSETD:
+      shortptr = (int16_t *) &dspace[uarg4];
+      val= *shortptr; i = ioctl(uarg1, TIOCSETD, &val); break;
+    case TR_FIOSETOWN:
+      shortptr = (int16_t *) &dspace[uarg4];
+      val= *shortptr;
+                               /* Something wrong here, wonder why! */
+      TrapDebug((dbg_file, "fd %d val %d ",uarg1,val));
+      i = ioctl(uarg1, FIOSETOWN, &val); break;
+    case TR_TIOCMGET:
+      shortptr = (int16_t *) &dspace[uarg4];
+      i = ioctl(uarg1, TIOCMGET, &val);
+      if (i==0) *shortptr= val;
+      break;
+
+    case TR_TIOCGWINSZ:
+                               /* 2.11BSD and POSIX winsize the same! */
+      winptr = (struct winsize *) &dspace[uarg4];
+      i= ioctl(uarg1, TIOCGWINSZ, winptr); break;
+    case TR_TIOCSWINSZ:
+      winptr = (struct winsize *) &dspace[uarg4];
+      i= ioctl(uarg1, TIOCSWINSZ, winptr); break;
+
+    default:
+      i = 0;
+  }
+  return (i);
+}
+
+
+/* Convert from termios to old sgttyb structure */
+static void to_sgttyb(struct tr_sgttyb * sgtb, struct termios * tios)
+{
+  switch (tios->c_ispeed) {
+     case B0: sgtb->sg_ispeed= TR_B0; break;
+     case B50: sgtb->sg_ispeed= TR_B50; break;
+     case B75: sgtb->sg_ispeed= TR_B75; break;
+     case B110: sgtb->sg_ispeed= TR_B110; break;
+     case B134: sgtb->sg_ispeed= TR_B134; break;
+     case B150: sgtb->sg_ispeed= TR_B150; break;
+     case B200: sgtb->sg_ispeed= TR_B200; break;
+     case B300: sgtb->sg_ispeed= TR_B300; break;
+     case B600: sgtb->sg_ispeed= TR_B600; break;
+     case B1200: sgtb->sg_ispeed= TR_B1200; break;
+     case B1800: sgtb->sg_ispeed= TR_B1800; break;
+     case B2400: sgtb->sg_ispeed= TR_B2400; break;
+     case B4800: sgtb->sg_ispeed= TR_B4800; break;
+     case B9600: sgtb->sg_ispeed= TR_B9600; break;
+     case B19200: sgtb->sg_ispeed= TR_EXTA; break;
+     case B38400: sgtb->sg_ispeed= TR_EXTB; break;
+     default: sgtb->sg_ispeed= TR_B0; break;
+  }
+  switch (tios->c_ospeed) {
+     case B0: sgtb->sg_ospeed= TR_B0; break;
+     case B50: sgtb->sg_ospeed= TR_B50; break;
+     case B75: sgtb->sg_ospeed= TR_B75; break;
+     case B110: sgtb->sg_ospeed= TR_B110; break;
+     case B134: sgtb->sg_ospeed= TR_B134; break;
+     case B150: sgtb->sg_ospeed= TR_B150; break;
+     case B200: sgtb->sg_ospeed= TR_B200; break;
+     case B300: sgtb->sg_ospeed= TR_B300; break;
+     case B600: sgtb->sg_ospeed= TR_B600; break;
+     case B1200: sgtb->sg_ospeed= TR_B1200; break;
+     case B1800: sgtb->sg_ospeed= TR_B1800; break;
+     case B2400: sgtb->sg_ospeed= TR_B2400; break;
+     case B4800: sgtb->sg_ospeed= TR_B4800; break;
+     case B9600: sgtb->sg_ospeed= TR_B9600; break;
+     case B19200: sgtb->sg_ospeed= TR_EXTA; break;
+     case B38400: sgtb->sg_ospeed= TR_EXTB; break;
+     default: sgtb->sg_ospeed= TR_B0; break;
+  }
+  sgtb->sg_erase = tios->c_cc[VERASE];
+  sgtb->sg_kill = tios->c_cc[VKILL];
+  sgtb->sg_flags = 0;
+  if (tios->c_oflag & OXTABS)
+    sgtb->sg_flags |= TR_XTABS;
+  if (tios->c_cflag & PARENB) {
+    if (tios->c_cflag & PARODD)
+      sgtb->sg_flags |= TR_ODDP;
+    else
+      sgtb->sg_flags |= TR_EVENP;
+  } else
+    sgtb->sg_flags |= TR_ANYP;
+  if (tios->c_oflag & ONLCR)
+    sgtb->sg_flags |= TR_CRMOD;
+  if (tios->c_lflag & ECHO)
+    sgtb->sg_flags |= TR_ECHO;
+  if (!(tios->c_lflag & ICANON)) {
+    if (!(tios->c_lflag & ECHO))
+      sgtb->sg_flags |= TR_CBREAK;
+    else
+      sgtb->sg_flags |= TR_RAW;
+  }
+}
+
+/* Convert from old sgttyb to termios structure */
+static void to_termios(struct tr_sgttyb * sgtb, struct termios * tios)
+{
+  TrapDebug((dbg_file, "\n\tto_termios: sgtty flags are 0x%x ",
+                                                       sgtb->sg_flags));
+
+  switch (sgtb->sg_ispeed) {
+     case TR_B0: tios->c_ispeed= B0; break;
+     case TR_B50: tios->c_ispeed= B50; break;
+     case TR_B75: tios->c_ispeed= B75; break;
+     case TR_B110: tios->c_ispeed= B110; break;
+     case TR_B134: tios->c_ispeed= B134; break;
+     case TR_B150: tios->c_ispeed= B150; break;
+     case TR_B200: tios->c_ispeed= B200; break;
+     case TR_B300: tios->c_ispeed= B300; break;
+     case TR_B600: tios->c_ispeed= B600; break;
+     case TR_B1200: tios->c_ispeed= B1200; break;
+     case TR_B1800: tios->c_ispeed= B1800; break;
+     case TR_B2400: tios->c_ispeed= B2400; break;
+     case TR_B4800: tios->c_ispeed= B4800; break;
+     case TR_B9600: tios->c_ispeed= B9600; break;
+     case TR_EXTA: tios->c_ispeed= B19200; break;
+     case TR_EXTB: tios->c_ispeed= B38400; break;
+     default: tios->c_ispeed= B0; break;
+  }
+  switch (sgtb->sg_ospeed) {
+     case TR_B0: tios->c_ospeed= B0; break;
+     case TR_B50: tios->c_ospeed= B50; break;
+     case TR_B75: tios->c_ospeed= B75; break;
+     case TR_B110: tios->c_ospeed= B110; break;
+     case TR_B134: tios->c_ospeed= B134; break;
+     case TR_B150: tios->c_ospeed= B150; break;
+     case TR_B200: tios->c_ospeed= B200; break;
+     case TR_B300: tios->c_ospeed= B300; break;
+     case TR_B600: tios->c_ospeed= B600; break;
+     case TR_B1200: tios->c_ospeed= B1200; break;
+     case TR_B1800: tios->c_ospeed= B1800; break;
+     case TR_B2400: tios->c_ospeed= B2400; break;
+     case TR_B4800: tios->c_ospeed= B4800; break;
+     case TR_B9600: tios->c_ospeed= B9600; break;
+     case TR_EXTA: tios->c_ospeed= B19200; break;
+     case TR_EXTB: tios->c_ospeed= B38400; break;
+     default: tios->c_ospeed= B0; break;
+  }
+  tios->c_cc[VERASE] = sgtb->sg_erase;
+  tios->c_cc[VKILL] = sgtb->sg_kill;
+
+                               /* Initially turn off any flags we might set */
+  tios->c_oflag &= ~(OXTABS|ONLCR);
+  tios->c_cflag &= ~(PARENB|PARODD);
+  tios->c_lflag &= ~(ECHO);
+
+  if (sgtb->sg_flags & TR_XTABS)
+    tios->c_oflag |= OXTABS;
+  if (sgtb->sg_flags & TR_ODDP) {
+    tios->c_cflag |= PARENB;
+    tios->c_cflag &= ~PARODD;
+  }
+  if (sgtb->sg_flags & TR_EVENP)
+    tios->c_cflag |= PARENB | PARODD;
+  if (sgtb->sg_flags & TR_ANYP)
+    tios->c_cflag &= ~PARENB;
+  if (sgtb->sg_flags & TR_CRMOD)
+    tios->c_oflag |= ONLCR;
+  if (sgtb->sg_flags & TR_ECHO)
+    tios->c_lflag |= ECHO;
+
+  if (sgtb->sg_flags & TR_RAW) {
+    tios->c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG|BRKINT|ICRNL|INPCK|ISTRIP|IXON);
+    tios->c_cflag &= ~(CSIZE|PARENB);
+    tios->c_cflag |= CS8;
+    tios->c_oflag &= ~(OPOST);
+    tios->c_cc[VMIN] = 1;
+    tios->c_cc[VTIME] = 0;
+  }
+
+  if (sgtb->sg_flags & TR_CBREAK) {
+  TrapDebug((dbg_file, "\n\tto_termios: setting cbreak I hope "));
+    tios->c_lflag &= ~(ECHO|ICANON);
+    tios->c_cc[VMIN] = 1;
+    tios->c_cc[VTIME] = 0;
+  }
+  TrapDebug((dbg_file, "\n\tto_termios: iflag is 0x%x", (int)tios->c_iflag));
+  TrapDebug((dbg_file, "\n\tto_termios: oflag is 0x%x", (int)tios->c_oflag));
+  TrapDebug((dbg_file, "\n\tto_termios: lflag is 0x%x ", (int)tios->c_lflag));
+}
+
+/* Convert from termios to old [l]tchars structures */
+static void to_tchars(struct tr_tchars *tc, struct tr_ltchars *ltc,
+                                               struct termios * tios)
+{
+  if (tc) {
+        tc->t_intrc=tios->c_cc[VINTR];
+        tc->t_quitc=tios->c_cc[VQUIT];
+        tc->t_startc=tios->c_cc[VSTART];
+        tc->t_stopc=tios->c_cc[VSTOP];
+        tc->t_eofc=tios->c_cc[VEOF];
+        tc->t_brkc=tios->c_cc[VEOL];
+  }
+  if (ltc) {
+        ltc->t_suspc=tios->c_cc[VSUSP];
+        ltc->t_dsuspc=tios->c_cc[VDSUSP];
+        ltc->t_rprntc=tios->c_cc[VREPRINT];
+        ltc->t_flushc=tios->c_cc[VDISCARD];
+        ltc->t_werasc=tios->c_cc[VERASE];
+        ltc->t_lnextc=tios->c_cc[VLNEXT];
+  }
+}
+
+/* Convert from old [l]tchars to termios structures */
+static void tc_to_tchars(struct tr_tchars *tc, struct tr_ltchars *ltc,
+                                               struct termios * tios)
+{
+  if (tc) {
+       tios->c_cc[VINTR]= tc->t_intrc;
+       tios->c_cc[VQUIT]= tc->t_quitc;
+       tios->c_cc[VSTART]= tc->t_startc;
+       tios->c_cc[VSTOP]= tc->t_stopc;
+       tios->c_cc[VEOF]= tc->t_eofc;
+       tios->c_cc[VEOL]= tc->t_brkc;
+  }
+  if (ltc) {
+       tios->c_cc[VSUSP]= ltc->t_suspc;
+       tios->c_cc[VDSUSP]= ltc->t_dsuspc;
+       tios->c_cc[VREPRINT]= ltc->t_rprntc;
+       tios->c_cc[VDISCARD]= ltc->t_flushc;
+       tios->c_cc[VERASE]= ltc->t_werasc;
+       tios->c_cc[VLNEXT]= ltc->t_lnextc;
+  }
+}
+/* Handle most get ioctls that deal with termios stuff */
+static int trap_gettermios(u_int16_t fd, u_int32_t type, u_int16_t ucnt)
+{
+  struct termios tios;
+  struct tr_sgttyb *sgtb;
+  struct tr_tchars *tc;
+  struct tr_ltchars *ltc;
+  int i;
+
+  if (ucnt == 0) return -1;
+  i = tcgetattr(fd, &tios);
+  if (i == -1) return i;
+  CLR_CC_C();
+
+  switch (type) {
+    case TR_TIOCGETP:
+      sgtb = (struct tr_sgttyb *) &dspace[ucnt];
+      to_sgttyb(sgtb, &tios); return 0;
+    case TR_TIOCGETC:
+      tc = (struct tr_tchars *) &dspace[ucnt];
+      to_tchars(tc, NULL, &tios); return 0;
+    case TR_TIOCGLTC:
+      ltc = (struct tr_ltchars *) &dspace[ucnt];
+      to_tchars(NULL, ltc, &tios); return 0;
+  }
+  /* Unknown type, should never get here */
+  return -1;
+}
+
+/* Handle most set ioctls that deal with termios stuff */
+static int trap_settermios(u_int16_t fd, u_int32_t type, u_int16_t ucnt)
+{
+  struct termios tios;
+  struct tr_sgttyb *sgtb;
+  struct tr_tchars *tc;
+  struct tr_ltchars *ltc;
+  int i;
+
+  if (ucnt == 0) return -1;
+  i = tcgetattr(fd, &tios);
+  if (i == -1) return i;
+  switch (type) {
+    case TR_TIOCSETP:
+      sgtb = (struct tr_sgttyb *) & dspace[ucnt];
+      to_termios(sgtb, &tios);
+      i = tcsetattr(fd, TCSANOW, &tios);
+      return (i);
+    case TR_TIOCSETN:
+      sgtb = (struct tr_sgttyb *) & dspace[ucnt];
+      to_termios(sgtb, &tios);
+      i = tcsetattr(fd, TCSADRAIN, &tios);
+      return (i);
+    case TR_TIOCSETC:
+      tc = (struct tr_tchars *) & dspace[ucnt];
+      tc_to_tchars(tc, NULL, &tios);
+      i = tcsetattr(fd, TCSANOW, &tios);
+      return (i);
+    case TR_TIOCSLTC:
+      ltc = (struct tr_ltchars *) & dspace[ucnt];
+      tc_to_tchars(NULL, ltc, &tios);
+      i = tcsetattr(fd, TCSANOW, &tios);
+      return (i);
+  }
+  /* Unknown type, should never get here */
+  return -1;
+}
+#endif                         /* EMU211 */
diff --git a/bsd_signal.c b/bsd_signal.c
new file mode 100644 (file)
index 0000000..9e1875f
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Much of this file comes from 2.11BSD's /usr/include/signal.h and is
+ * Copyright (c) 1986 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ *     Code to deal with 2.11BSD signals
+ */
+#include "defines.h"
+#include <signal.h>
+#include "bsdtrap.h"
+
+
+#define NBSDSIG        32
+
+#define        BSDSIGHUP       1       /* hangup */
+#define        BSDSIGINT       2       /* interrupt */
+#define        BSDSIGQUIT      3       /* quit */
+#define        BSDSIGILL       4       /* illegal instruct (not reset when caught) */
+#define        BSDSIGTRAP      5       /* trace trap (not reset when caught) */
+#define        BSDSIGIOT       6       /* IOT instruction */
+#define        BSDSIGEMT       7       /* EMT instruction */
+#define        BSDSIGFPE       8       /* floating point exception */
+#define        BSDSIGKILL      9       /* kill (cannot be caught or ignored) */
+#define        BSDSIGBUS       10      /* bus error */
+#define        BSDSIGSEGV      11      /* segmentation violation */
+#define        BSDSIGSYS       12      /* bad argument to system call */
+#define        BSDSIGPIPE      13      /* write on a pipe with no one to read it */
+#define        BSDSIGALRM      14      /* alarm clock */
+#define        BSDSIGTERM      15      /* software termination signal from kill */
+#define        BSDSIGURG       16      /* urgent condition on IO channel */
+#define        BSDSIGSTOP      17      /* sendable stop signal not from tty */
+#define        BSDSIGTSTP      18      /* stop signal from tty */
+#define        BSDSIGCONT      19      /* continue a stopped process */
+#define        BSDSIGCHLD      20      /* to parent on child stop or exit */
+#define        BSDSIGTTIN      21      /* to readers pgrp upon background tty read */
+#define        BSDSIGTTOU      22   /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define        BSDSIGIO        23      /* input/output possible signal */
+#define        BSDSIGXCPU      24      /* exceeded CPU time limit */
+#define        BSDSIGXFSZ      25      /* exceeded file size limit */
+#define        BSDSIGVTALRM    26      /* virtual time alarm */
+#define        BSDSIGPROF      27      /* profiling time alarm */
+#define BSDSIGWINCH    28      /* window size changes */
+#define BSDSIGUSR1     30      /* user defined signal 1 */
+#define BSDSIGUSR2     31      /* user defined signal 2 */
+#define bsdsigismember(set, signo) ((*(set) & (1L << ((signo) - 1))) != 0)
+
+#define        BSDSIG_ERR      -1
+#define        BSDSIG_DFL       0
+#define        BSDSIG_IGN       1
+
+/*
+ * Signal vector "template" used in sigaction call.
+ */
+struct bsd_sigaction {
+       int16_t sig_handler;            /* signal handler */
+       u_int32_t sa_mask;              /* signal mask to apply */
+       int16_t sa_flags;               /* see signal options below */
+};
+
+#define BSD_ONSTACK    0x0001  /* take signal on signal stack */
+#define BSD_RESTART    0x0002  /* restart system on signal return */
+#define        BSD_DISABLE     0x0004  /* disable taking signals on alternate stack */
+#define BSD_NOCLDSTOP  0x0008  /* do not generate SIGCHLD on child stop */
+
+
+/* Translate 2.11BSD signal value to our value */
+
+static int bsdsig[] = {
+       0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGIOT, SIGEMT,
+       SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS, SIGPIPE, SIGALRM,
+       SIGTERM, SIGURG, SIGSTOP, SIGTSTP, SIGCONT, SIGCHLD, SIGTTIN,
+       SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
+       SIGUSR1, SIGUSR2
+};
+
+/* We keep a set of struct sigactions
+ * for each 2.11BSD signal
+ */
+struct bsd_sigaction Sigact[NBSDSIG];
+
+
+/* Set all signals to their default value */
+void set_bsdsig_dfl(void)
+{
+  int i;
+
+  for (i=0;i<NBSDSIG;i++) {
+       if (bsdsig[i]) signal(bsdsig[i], SIG_DFL);
+       Sigact[i].sig_handler= BSDSIG_DFL;
+       Sigact[i].sa_mask= Sigact[i].sa_flags= 0;
+  }
+}
+
+int do_sigaction(int sig, int a, int oa)
+{
+  int i;
+  struct bsd_sigaction *act, *oact;
+  struct sigaction ouraction;
+
+  if ((sig<0) || (sig >= NBSDSIG)) return(EINVAL);
+
+  if (oa) {
+    oact= (struct bsd_sigaction *)&dspace[oa];
+    memcpy(oact, &Sigact[sig], sizeof(struct bsd_sigaction));
+  }
+
+  if (a) {
+    act= (struct bsd_sigaction *)&dspace[a];
+
+               /* If required, map mask here */
+               /* Currently, the assumption is a 1-1 match */
+    sigemptyset(&(ouraction.sa_mask));
+    for (i=1; i<NBSDSIG;i++) {
+       if bsdsigismember(&(act->sa_mask), i)
+               sigaddset(&(ouraction.sa_mask), i);
+    }
+               /* If required, map flags here */
+    ouraction.sa_flags= act->sa_flags;
+    ouraction.sa_handler= sigcatcher;
+  }
+
+  i= sigaction(bsdsig[sig], &ouraction, NULL);
+  if (i==-1) return(i);
+
+               /* Else save the new sigaction */
+  act= (struct bsd_sigaction *)&dspace[a];
+  memcpy(&Sigact[sig], act, sizeof(struct bsd_sigaction));
+  return(i);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* For now, the rest commented out. One day I might
+ * get around to implementing 2.11BSD signals properly
+ */
+
+#if 0
+int    (*signal())();
+
+typedef unsigned long sigset_t;
+
+
+/*
+ * Flags for sigprocmask:
+ */
+#define        BSDSIG_BLOCK    1       /* block specified signal set */
+#define        BSDSIG_UNBLOCK  2       /* unblock specified signal set */
+#define        BSDSIG_SETMASK  3       /* set specified signal set */
+
+typedef        int (*sig_t)();         /* type of signal function */
+
+/*
+ * Structure used in sigaltstack call.
+ */
+struct sigaltstack {
+       char    *ss_base;               /* signal stack base */
+       int     ss_size;                /* signal stack length */
+       int     ss_flags;               /* SA_DISABLE and/or SA_ONSTACK */
+};
+#define        MINBSDSIGSTKSZ  128                     /* minimum allowable stack */
+#define        BSDSIGSTKSZ     (MINBSDSIGSTKSZ + 384)  /* recommended stack size */
+
+/*
+ * 4.3 compatibility:
+ * Signal vector "template" used in sigvec call.
+ */
+struct sigvec {
+       int     (*sv_handler)();        /* signal handler */
+       long    sv_mask;                /* signal mask to apply */
+       int     sv_flags;               /* see signal options below */
+};
+#define SV_ONSTACK     SA_ONSTACK      /* take signal on signal stack */
+#define SV_INTERRUPT   SA_RESTART      /* same bit, opposite sense */
+#define sv_onstack sv_flags            /* isn't compatibility wonderful! */
+
+/*
+ * 4.3 compatibility:
+ * Structure used in sigstack call.
+ */
+struct sigstack {
+       char    *ss_sp;                 /* signal stack pointer */
+       int     ss_onstack;             /* current status */
+};
+
+/*
+ * Information pushed on stack when a signal is delivered.
+ * This is used by the kernel to restore state following
+ * execution of the signal handler.  It is also made available
+ * to the handler to allow it to properly restore state if
+ * a non-standard exit is performed.
+ */
+struct sigcontext {
+       int     sc_onstack;             /* sigstack state to restore */
+       long    sc_mask;                /* signal mask to restore */
+       int     sc_sp;                  /* sp to restore */
+       int     sc_fp;                  /* fp to restore */
+       int     sc_r1;                  /* r1 to restore */
+       int     sc_r0;                  /* r0 to restore */
+       int     sc_pc;                  /* pc to restore */
+       int     sc_ps;                  /* psl to restore */
+       int     sc_ovno                 /* overlay to restore */
+};
+
+/*
+ * Macro for converting signal number to a mask suitable for
+ * sigblock().
+ */
+#define sigmask(m)             (1L << ((m)-1))
+#define sigaddset(set, signo)  (*(set) |= 1L << ((signo) - 1), 0)
+#define sigdelset(set, signo)  (*(set) &= ~(1L << ((signo) - 1)), 0)
+#define sigemptyset(set)       (*(set) = (sigset_t)0, (int)0)
+#define sigfillset(set)         (*(set) = ~(sigset_t)0, (int)0)
+#define sigismember(set, signo) ((*(set) & (1L << ((signo) - 1))) != 0)
+
+#endif /* 0 */
diff --git a/bsdtrap.c b/bsdtrap.c
new file mode 100644 (file)
index 0000000..0a57b24
--- /dev/null
+++ b/bsdtrap.c
@@ -0,0 +1,877 @@
+/* bsdtrap.c - Deal with 2.11BSD trap instructions.
+ *
+ * $Revision: 1.65 $
+ * $Date: 2002/06/10 11:43:24 $
+ */
+#ifdef EMU211
+
+/* NOTE NOTE NOTE NOTE
+ * Grep for the word DONE in this file to see the implemented syscalls.
+ */
+
+#define BSDTRAP_NAME
+#include "defines.h"
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <utime.h>
+#include <sys/file.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include "bsdtrap.h"
+#ifdef __linux__
+#include <grp.h>               /* setgroups() */
+#endif
+
+#define MAX_BLKSIZE    1024    /* Maximum block size from stat/fstat */
+
+#undef STREAM_BUFFERING                /* This works, but doesn't seem to give */
+                               /* any speed improvement */
+
+arglist *A;                    /* Pointer to various arguments on stack */
+
+
+/* Forward prototypes */
+#ifdef __STDC__
+#define P(s) s
+#else
+#define P(s) ()
+#endif
+static int trap_execve P((int));
+static int bsdopen_dir P((char *name));
+#ifdef NEED_MAP_FCNTL
+static int16_t map_fcntl P((int16_t f));
+#endif
+#undef P
+
+void
+bsdtrap()
+{
+    int i, j, len, pid, pfd[2];
+    char *buf, *buf2;
+    int16_t *shortptr;
+    long larg1;
+    char *fmode;                               /* used with fdopen only */
+    struct stat stbuf;                         /* used in STAT */
+    struct tr_stat *tr_stbuf;                  /* used in STAT */
+    struct tr_timeval *tr_del, *tr_oldel;      /* used in ADJTIME */
+    struct timeval del, oldel;                 /* used in ADJTIME */
+    struct timeval utv[2];                     /* used in UTIMES */
+    struct tr_timezone *tr_zone;               /* used in GETTIMEOFDAY */
+    struct timezone zone;                      /* used in GETTIMEOFDAY */
+    struct tr_itimerval *tr_tval, *tr_oltval;  /* used in itimer calls */
+    struct itimerval tval, oltval;             /* used in itimer calls */
+    struct tr_sockaddr *tr_sock;               /* used in socket calls */
+    struct sockaddr sock;                      /* used in socket calls */
+    gid_t *gidset;                             /* used in GETGROUPS */
+    struct tr_rlimit *tr_rlp;                  /* used in rlimit calls */
+    struct rlimit rlp;                         /* used in rlimit calls */
+    struct tr_rusage *tr_use;                  /* used in getrusage */
+    struct rusage use;                         /* used in getrusage */
+    struct iovec *ivec;                                /* used in writev, readv */
+    struct tr_iovec *trivec;                   /* used in writev, readv */
+
+    TrapDebug((dbg_file, "pid %d %s: ", (int)getpid(),bsdtrap_name[ir & 0xff]));
+
+    A= (arglist *)&dspace[(regs[SP]+2)];
+
+    i=errno=0;
+    switch (ir & 0xff) {
+    case S_INDIR:
+       (void)printf("Does 2.11BSD use INDIR? I don't think so\n");
+       exit(EXIT_FAILURE);
+
+    case S_QUOTA:                              /* DONE - for now */
+    case S_SETQUOTA:                           /* DONE - for now */
+       i=-1; errno=EINVAL; break;
+
+                       /* These syscalls are not implemented, and */
+                       /* always return EPERM to the caller */
+    case S_PTRACE:                             /* DONE - bad syscall */
+    case S_MOUNT:                              /* DONE - bad syscall */
+    case S_UMOUNT:                             /* DONE - bad syscall */
+    case S_PROFIL:                             /* DONE - bad syscall */
+    case S_NOSYS147:                           /* DONE - bad syscall */
+    case S_SYSCTL:
+       i=-1; errno=EPERM; break;
+                       /* These syscalls are ignored, and */
+                       /* always return C=0 to the caller */
+    case S_OLDLOCK:                            /* DONE - ok syscall */
+    case S_OLDPHYS:                            /* DONE - ok syscall */
+    case S_FSTATFS:                            /* DONE - ok syscall */
+    case S_SIGPROCMASK:                                /* DONE - ok syscall */
+    case S_SIGRETURN:                          /* DONE - ok syscall */
+    case S_SIGALTSTACK:                                /* DONE - ok syscall */
+    case S_VHANGUP:                            /* DONE - ok syscall */
+       i=0; break;
+    case S_SIGACTION:                          /* DONE */
+#define NO_SIGNALS_YET
+#ifdef NO_SIGNALS_YET
+       i=0;
+#else
+       i= do_sigaction(uarg1, uarg2, uarg3);
+#endif
+       break;
+    case S_IOCTL:                              /* DONE a bit */
+       i=trap_ioctl(); break;
+    case S_SBRK:                               /* DONE */
+       if (uarg1<regs[SP]) {
+           i=0;
+           TrapDebug((dbg_file, "set break to %d ", uarg1));
+       } else {
+           i=-1; errno=ENOMEM;
+           TrapDebug((dbg_file, "break %d > SP %d", uarg1, regs[SP]));
+       }
+       break;
+    case S_SYNC:                               /* DONE */
+       sync(); i=0; break;
+    case S_FSYNC:                              /* DONE */
+       i= fsync(sarg1); break;
+    case S_GETDTABLESIZE:                      /* DONE */
+       i= getdtablesize(); break;
+    case S_EXIT:                               /* DONE */
+#ifdef DEBUG
+        TrapDebug((dbg_file, "val %d\n",sarg1)); fflush(dbg_file);
+#endif
+       exit(sarg1);
+    case S_DUP:                                        /* DONE */
+        TrapDebug((dbg_file, "on %d ",sarg1));
+       i = dup(sarg1);
+#ifdef STREAM_BUFFERING
+            if ((i!=-1) && ValidFD(sarg1) && stream[sarg1]) {
+                fmode= streammode[sarg1];
+                stream[i] = fdopen(i, fmode);
+                streammode[i]=fmode;
+            }
+#endif
+       break;
+    case S_DUP2:                               /* DONE */
+        TrapDebug((dbg_file, "on %d %d ",sarg1,sarg2));
+       i = dup2(sarg1,sarg2);
+#ifdef STREAM_BUFFERING
+            if ((i!=-1) && ValidFD(sarg2) && ValidFD(sarg1) && stream[sarg1]) {
+                fmode= streammode[sarg1];
+                stream[sarg2] = fdopen(sarg2, fmode);
+                streammode[sarg2]=fmode;
+            }
+#endif
+       break;
+    case S_REBOOT:                             /* DONE */
+       (void)Reboot(sarg1); break;
+    case S_UMASK:                              /* DONE */
+       i = umask((mode_t)sarg1); break;
+    case S_GETPAGESIZE:                                /* DONE */
+       i = getpagesize(); break;
+    case S_GETHOSTNAME:                                /* DONE */
+       buf = (char *)&dspace[uarg1];
+       i= gethostname(buf,sarg2); break;
+    case S_SETHOSTNAME:                                /* DONE */
+       buf = (char *)&dspace[uarg1];
+       sethostname(buf,sarg2); break;
+    case S_LSEEK:                              /* DONE */
+       larg1 = (sarg2 << 16) | uarg3;
+#ifdef STREAM_BUFFERING
+        if (ValidFD(sarg1) && stream[sarg1]) {
+            i = fseek(stream[sarg1], larg1, sarg4);
+            if (i == 0) i = ftell(stream[sarg1]);
+        } else
+#endif
+       i = lseek(sarg1, larg1, sarg4);
+       if (i == -1) break;
+       else {
+           regs[1] = i & 0xffff;
+           i= (i >> 16) & 0xffff;
+           break;
+       }
+    case S_READ:                               /* DONE */
+        TrapDebug((dbg_file, "%d bytes on %d ",uarg3,sarg1));
+       buf = &dspace[uarg2];
+#ifdef STREAM_BUFFERING
+        if (ValidFD(sarg1) && stream[sarg1])
+            i = fread(buf, 1, uarg3, stream[sarg1]);
+        else
+#endif
+       i = read(sarg1, buf, uarg3); break;
+    case S_LINK:                               /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       buf2 = xlate_filename(&dspace[uarg2]);
+       i = link(buf, buf2); break;
+    case S_SYMLINK:                            /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       buf2 = xlate_filename(&dspace[uarg2]);
+       i = symlink(buf, buf2); break;
+    case S_RENAME:                             /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       buf2 = xlate_filename(&dspace[uarg2]);
+       i = rename(buf, buf2); break;
+    case S_READLINK:                           /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = readlink(buf, &dspace[uarg2], sarg3); break;
+    case S_ACCESS:                             /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = access(buf, sarg2); break;
+    case S_MKDIR:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = mkdir(buf, sarg2); break;
+    case S_RMDIR:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = rmdir(buf); break;
+    case S_ACCT:                               /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = acct(buf); break;
+    case S_WRITEV:                             /* DONE */
+    case S_READV:                              /* DONE */
+       ivec= (struct iovec *)malloc(uarg3 * sizeof(struct iovec));
+       if (ivec==NULL) { i=-1; errno=EINVAL; break; }
+       trivec= (struct tr_iovec *)&dspace[uarg2];
+
+       for (j=0; j<uarg3; j++) {
+           ivec[j].iov_len= trivec[j].iov_len;
+           ivec[j].iov_base= (char *)&dspace[trivec[j].iov_base];
+       }
+       if ((ir & 0xff)==S_READV) i= readv(sarg1, ivec, uarg3);
+       else i= writev(sarg1, ivec, uarg3);
+       free(ivec);
+       break;
+    case S_WRITE:                              /* DONE */
+       buf = &dspace[uarg2];
+        TrapDebug((dbg_file, "%d bytes on %d ",uarg3,sarg1));
+#ifdef STREAM_BUFFERING
+        if (ValidFD(sarg1) && stream[sarg1])
+            i = fwrite(buf, 1, uarg3, stream[sarg1]);
+        else
+#endif
+       i = write(sarg1, buf, uarg3); break;
+    case S_CLOSE:                              /* DONE */
+#ifdef DEBUG
+    TrapDebug((dbg_file, "on %d ",sarg1));
+    if ((dbg_file!=NULL) && (sarg1==fileno(dbg_file))) {
+       i=0; break;                     /* Don't close our debug file! */
+    }
+#endif
+#ifdef STREAM_BUFFERING
+        if (ValidFD(sarg1) && stream[sarg1]) {
+            i = fclose(stream[sarg1]);
+            stream[sarg1] = NULL;
+        } else
+#endif
+       i = close(sarg1); break;
+    case S_FCNTL:
+        TrapDebug((dbg_file, "on %d %d %d ",sarg1,sarg2, sarg3));
+       i = fcntl(sarg1,sarg2,sarg3); break;
+    case S_FLOCK:
+       i = flock(sarg1,sarg2); break;
+    case S_LSTAT:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       tr_stbuf = (struct tr_stat *) &dspace[uarg2];
+       i = lstat(buf, &stbuf);
+        TrapDebug((dbg_file, "on %s ",buf));
+       goto dostat;
+    case S_STAT:                               /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       tr_stbuf = (struct tr_stat *) &dspace[uarg2];
+       i = stat(buf, &stbuf);
+        TrapDebug((dbg_file, "on %s ",buf));
+       goto dostat;
+    case S_FSTAT:                              /* DONE */
+       tr_stbuf = (struct tr_stat *) &dspace[uarg2];
+       i = fstat(uarg1, &stbuf);
+        TrapDebug((dbg_file, "on fd %d ",uarg1));
+
+dostat:
+       if (i == -1) break;
+       else {
+                       /* The following stops blksize equalling 64K,
+                        * which becomes 0 in a 16-bit int. This then
+                        * causes 2.11BSD flsbuf() to malloc(0), which
+                        * then causes malloc to go crazy - wkt.
+                        */
+           if (stbuf.st_blksize>MAX_BLKSIZE) stbuf.st_blksize=MAX_BLKSIZE;
+
+           tr_stbuf->st_dev = stbuf.st_dev;
+           tr_stbuf->st_ino = stbuf.st_ino;
+           tr_stbuf->st_mode = stbuf.st_mode;
+           tr_stbuf->st_nlink = stbuf.st_nlink;
+           tr_stbuf->st_uid = stbuf.st_uid;
+           tr_stbuf->st_gid = stbuf.st_gid;
+           tr_stbuf->st_rdev = stbuf.st_rdev;
+#ifndef NO_STFLAGS
+           tr_stbuf->st_flags = stbuf.st_flags;
+#endif
+           copylong(tr_stbuf->st_size, stbuf.st_size);
+           copylong(tr_stbuf->st_atim, stbuf.st_atime);
+           copylong(tr_stbuf->st_mtim, stbuf.st_mtime);
+           copylong(tr_stbuf->st_ctim, stbuf.st_ctime);
+           copylong(tr_stbuf->st_blksize, stbuf.st_blksize);
+           larg1= stbuf.st_blocks; copylong(tr_stbuf->st_blocks, larg1);
+       }
+       break;
+    case S_UTIMES:                             /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       tr_del = (struct tr_timeval *) &dspace[uarg2];
+       tr_oldel = (struct tr_timeval *) &dspace[uarg4];
+       i= utimes(buf, utv);
+       if (i==-1) break;
+       copylong(tr_del->tv_sec,    utv[0].tv_sec);
+       copylong(tr_del->tv_usec,   utv[0].tv_usec);
+       copylong(tr_oldel->tv_sec,  utv[1].tv_sec);
+       copylong(tr_oldel->tv_usec, utv[1].tv_usec);
+       break;
+    case S_ADJTIME:                            /* DONE */
+       tr_del = (struct tr_timeval *) &dspace[uarg1];
+                                               /* Convert tr_del to del */
+       copylong(del.tv_sec,  tr_del->tv_sec);
+       copylong(del.tv_usec, tr_del->tv_usec);
+       i= adjtime(&del, &oldel);
+
+       if (uarg2) {
+           tr_oldel = (struct tr_timeval *) &dspace[uarg2];
+           copylong(tr_oldel->tv_sec,  oldel.tv_sec);
+           copylong(tr_oldel->tv_usec, oldel.tv_usec);
+       }
+       break;
+    case S_GETTIMEOFDAY:                       /* DONE */
+       tr_del = (struct tr_timeval *)   &dspace[uarg1];
+       tr_zone = (struct tr_timezone *) &dspace[uarg2];
+       i= gettimeofday(&del, &zone);
+       copylong(tr_del->tv_sec,  del.tv_sec);
+       copylong(tr_del->tv_usec, del.tv_usec);
+       tr_zone->tz_minuteswest= zone.tz_minuteswest;
+       tr_zone->tz_dsttime= zone.tz_dsttime;
+       break;
+    case S_SETTIMEOFDAY:                       /* DONE */
+       tr_del = (struct tr_timeval *)   &dspace[uarg1];
+       tr_zone = (struct tr_timezone *) &dspace[uarg2];
+       copylong(del.tv_sec,  tr_del->tv_sec);
+       copylong(del.tv_usec, tr_del->tv_usec);
+       zone.tz_minuteswest= tr_zone->tz_minuteswest;
+       zone.tz_dsttime= tr_zone->tz_dsttime;
+       i= settimeofday(&del, &zone);
+       break;
+    case S_GETITIMER:                          /* DONE */
+       tr_tval = (struct tr_itimerval *) &dspace[uarg2];
+       i= getitimer(sarg1, &tval);
+       copylong(tr_tval->it_interval.tv_sec,  tval.it_interval.tv_sec);
+       copylong(tr_tval->it_interval.tv_usec, tval.it_interval.tv_usec);
+       copylong(tr_tval->it_value.tv_sec,  tval.it_value.tv_sec);
+       copylong(tr_tval->it_value.tv_usec, tval.it_value.tv_usec);
+       break;
+    case S_SETITIMER:                          /* DONE */
+       tr_tval = (struct tr_itimerval *) &dspace[uarg2];
+       tr_oltval = (struct tr_itimerval *) &dspace[uarg2];
+       copylong(tval.it_interval.tv_sec,  tr_tval->it_interval.tv_sec);
+       copylong(tval.it_interval.tv_usec, tr_tval->it_interval.tv_usec);
+       copylong(tval.it_value.tv_sec,     tr_tval->it_value.tv_sec);
+       copylong(tval.it_value.tv_usec,    tr_tval->it_value.tv_usec);
+       i= setitimer(sarg1, &tval, &oltval);
+       if (i == -1) break;
+       copylong(tr_oltval->it_interval.tv_sec,  oltval.it_interval.tv_sec);
+       copylong(tr_oltval->it_interval.tv_usec, oltval.it_interval.tv_usec);
+       copylong(tr_oltval->it_value.tv_sec,     oltval.it_value.tv_sec);
+       copylong(tr_oltval->it_value.tv_usec,    oltval.it_value.tv_usec);
+       break;
+    case S_UNLINK:                             /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = unlink(buf); break;
+    case S_OPEN:                               /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+
+       i = stat(buf, &stbuf);  /* If file is a directory */
+       if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
+           i = bsdopen_dir(buf);
+           fmode = "w+";
+            TrapDebug((dbg_file, "(dir) on %s ",buf));
+       } else {
+#ifdef NEED_MAP_FCNTL
+           sarg2= map_fcntl(sarg2);
+#endif
+           switch (sarg2 & O_ACCMODE) {
+              case O_RDONLY: fmode = "r"; break;
+              case O_WRONLY: fmode = "w"; break;
+              default: fmode = "w+"; break;
+            }
+           i = open(buf, sarg2, sarg3);
+            TrapDebug((dbg_file, "on %s ",buf));
+            TrapDebug((dbg_file, "sarg2 is %d, sarg3 is 0x%x ",sarg2,sarg3));
+       }
+#ifdef STREAM_BUFFERING
+       if (i==-1) break;
+        /* Now get its stream pointer if possible */
+        /* Can someone explain why fdopen doesn't work for O_RDWR? */
+# if 0
+        if (ValidFD(i) && !isatty(i) && (sarg2!=O_RDWR)) {
+            stream[i] = fdopen(i, fmode); streammode[i]=fmode;
+        }
+# endif
+       stream[i] = fdopen(i, fmode); streammode[i]=fmode;
+#endif
+       break;
+    case S_MKNOD:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = mknod(buf, sarg2, sarg3); break;
+    case S_CHMOD:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chmod(buf, sarg2); break;
+    case S_FCHMOD:                             /* DONE */
+       i = fchmod(sarg1, sarg2); break;
+    case S_TRUNCATE:                           /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       larg1 = (sarg2 << 16) | uarg3;
+       i = truncate(buf, larg1); break;
+    case S_FTRUNCATE:                          /* DONE */
+       larg1 = (sarg2 << 16) | uarg3;
+       i = ftruncate(sarg1, larg1); break;
+    case S_KILL:                               /* DONE */
+       i = kill(sarg1, sarg2); break;
+    case S_KILLPG:                             /* DONE */
+       i = killpg(sarg1, sarg2); break;
+    case S_CHOWN:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chown(buf, sarg2, sarg3); break;
+    case S_PIPE:                               /* DONE */
+       i = pipe(pfd);
+#ifdef STREAM_BUFFERING
+        if (ValidFD(pfd[0])) {
+                stream[pfd[0]] = fdopen(pfd[0], "r");
+                streammode[pfd[0]]= "r";
+        }
+        if (ValidFD(pfd[1])) {
+                stream[pfd[1]] = fdopen(pfd[1], "w");
+                streammode[pfd[1]]= "w";
+        }
+#endif
+       if (i == -1) break;
+       i = pfd[0]; regs[1] = pfd[1]; break;
+    case S_CHROOT:                             /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       if (buf == NULL) {
+           errno=ENOENT; i=-1; break;
+       }
+       set_apout_root(buf);
+       i=0; break;
+    case S_CHDIR:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chdir(buf); break;
+    case S_FCHDIR:                             /* DONE */
+       i = fchdir(sarg1); break;
+
+#ifndef NO_CHFLAGS
+    case S_CHFLAGS:                            /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chflags(buf,uarg2); break;
+    case S_FCHFLAGS:                           /* DONE */
+       i = fchflags(sarg1,uarg2); break;
+#endif
+
+    case S_CREAT:                              /* DONE */
+       buf = xlate_filename(&dspace[uarg1]);
+       i = creat(buf, sarg2);
+#ifdef STREAM_BUFFERING
+        if (ValidFD(i)) {
+                stream[i] = fdopen(i, "w");
+                streammode[i]= "w";
+        }
+#endif
+       break;
+    case S_EXECVE:                             /* DONE, I think */
+       i= trap_execve(1); break;
+    case S_EXECV:                              /* Not sure here */
+       i= trap_execve(0); break;
+    case S_WAIT:                               /* Not sure here */
+       i = wait(&pid);
+       if (i == -1) break;
+       regs[1] = pid;
+       break;
+    case S_WAIT4:                              /* Definitely incomplete */
+       TrapDebug((dbg_file, "on pid %d options %d ",sarg1,uarg3));
+       if (uarg4) TrapDebug((dbg_file, " rusage on!!! "));
+       shortptr = (int16_t *)&dspace[uarg2];
+       i= wait4(sarg1, &j, uarg3, 0);
+       *shortptr= j;
+       break;
+    case S_FORK:                               /* DONE */
+    case S_VFORK:                              /* DONE */
+       i = fork();
+       if (i!=0) { regs[PC]+=2; }              /* Took ages to find this! */
+       else ov_changes=0;
+       break;
+    case S_GETHOSTID:                          /* DONE */
+       i = gethostid();
+       regs[1] = i & 0xffff;
+       i= (i >> 16) & 0xffff;
+       break;
+    case S_SETHOSTID:                          /* DONE */
+       larg1 = (sarg2 << 16) | uarg3;
+       sethostid(larg1); i=0; break;
+    case S_GETUID:                             /* DONE */
+       i = getuid(); break;
+    case S_SETUID:                             /* DONE */
+       i = setuid(uarg1); break;
+    case S_GETEUID:                            /* DONE */
+       i = geteuid(); break;
+    case S_GETPID:                             /* DONE */
+       i = getpid(); break;
+    case S_GETPPID:                            /* DONE */
+       i = getppid(); break;
+    case S_GETGID:                             /* DONE */
+       i = getgid(); break;
+    case S_GETEGID:                            /* DONE */
+       i = getegid(); break;
+#ifndef NO_GETPGID
+    case S_GETPGRP:                            /* DONE */
+       i = getpgid(sarg1); break;
+#endif
+    case S_SETPGRP:                            /* DONE */
+       i = setpgid(sarg1,sarg2); break;
+    case S_SETREGID:                           /* DONE */
+       i = setregid(sarg1,sarg2); break;
+    case S_SETREUID:                           /* DONE */
+       i = setreuid(sarg1,sarg2); break;
+    case S_GETPRIORITY:                                /* DONE */
+       i = getpriority(sarg1,sarg2); break;
+    case S_SETPRIORITY:                                /* DONE */
+       i = setpriority(sarg1,sarg2,sarg3); break;
+    case S_LISTEN:                             /* DONE */
+       i = listen(sarg1,sarg2); break;
+    case S_SHUTDOWN:                           /* DONE */
+       i = shutdown(sarg1,sarg2); break;
+    case S_SOCKET:                             /* DONE */
+       i = socket(sarg1,sarg2,sarg3); break;
+    case S_SOCKETPAIR:                         /* DONE */
+       i = socketpair(sarg1,sarg2,sarg3, pfd); break;
+       shortptr= (int16_t *)&dspace[uarg4];
+       *shortptr= pfd[0]; shortptr+=2;
+       *shortptr= pfd[1];
+       break;
+    case S_RECV:                               /* DONE */
+       buf = &dspace[uarg2];
+       i = recv(sarg1, buf, sarg3, sarg4); break;
+    case S_SEND:                               /* DONE */
+       buf = &dspace[uarg2];
+       i = send(sarg1, buf, sarg3, sarg4); break;
+    case S_ACCEPT:                             /* DONE */
+       tr_sock= (struct tr_sockaddr *)&dspace[uarg2];
+       sock.sa_family= tr_sock->sa_family;
+       ll_word(uarg3, len);
+#ifndef __linux__
+       sock.sa_len=len;
+#endif
+       memcpy(sock.sa_data, tr_sock->sa_data, len);
+       i= accept(sarg1, &sock, &len);
+       if (i != -1) {
+           sl_word(uarg3,len);
+           memcpy(tr_sock->sa_data, sock.sa_data, len);
+       }
+       break;
+    case S_GETPEERNAME:                                /* DONE */
+       tr_sock= (struct tr_sockaddr *)&dspace[uarg2];
+       sock.sa_family= tr_sock->sa_family;
+       ll_word(uarg3, len);
+#ifndef __linux__
+       sock.sa_len=len;
+#endif
+       memcpy(sock.sa_data, tr_sock->sa_data, len);
+       i= getpeername(sarg1, &sock, &len);
+       if (i != -1) {
+           sl_word(uarg3,len);
+           memcpy(tr_sock->sa_data, sock.sa_data, len);
+       }
+       break;
+    case S_GETSOCKNAME:                                /* DONE */
+       tr_sock= (struct tr_sockaddr *)&dspace[uarg2];
+       sock.sa_family= tr_sock->sa_family;
+       ll_word(uarg3, len);
+#ifndef __linux__
+       sock.sa_len=len;
+#endif
+       memcpy(sock.sa_data, tr_sock->sa_data, len);
+       i= getsockname(sarg1, &sock, &len);
+       if (i != -1) {
+           sl_word(uarg3,len);
+           memcpy(tr_sock->sa_data, sock.sa_data, len);
+       }
+       break;
+    case S_BIND:                               /* DONE */
+       tr_sock= (struct tr_sockaddr *)&dspace[uarg2];
+       sock.sa_family= tr_sock->sa_family;
+       len= sarg3;
+#ifndef __linux__
+       sock.sa_len= sarg3;
+#endif
+       memcpy(sock.sa_data, tr_sock->sa_data, len);
+       i= bind(sarg1, &sock, len);
+       break;
+    case S_CONNECT:                            /* DONE */
+       tr_sock= (struct tr_sockaddr *)&dspace[uarg2];
+       sock.sa_family= tr_sock->sa_family;
+       len= sarg3;
+#ifndef __linux__
+       sock.sa_len= sarg3;
+#endif
+       memcpy(sock.sa_data, tr_sock->sa_data, len);
+       i= connect(sarg1, &sock, len);
+       break;
+    case S_RECVFROM:                           /* DONE I think */
+       tr_sock= (struct tr_sockaddr *)&dspace[uarg5];
+       sock.sa_family= tr_sock->sa_family;
+       ll_word(uarg6, len);
+#ifndef __linux__
+       sock.sa_len=len;
+#endif
+       memcpy(sock.sa_data, tr_sock->sa_data, len);
+       buf = &dspace[uarg2];
+       i= recvfrom(sarg1, buf, sarg3, sarg4, &sock, &len);
+       if (i != -1) {
+           sl_word(uarg6,len);
+           memcpy(tr_sock->sa_data, sock.sa_data, len);
+       }
+       break;
+    case S_GETGROUPS:
+       len= sarg1;
+       gidset= (gid_t *)malloc(len * sizeof(gid_t));
+       if (gidset==NULL) { i=-1; errno=EINVAL; break; }
+       i= getgroups(len, gidset);
+       shortptr= (int16_t *)&dspace[uarg2];
+       for (j=0; j<i; j++) shortptr[j]= gidset[j];
+       free(gidset);
+       break;
+    case S_SETGROUPS:
+       len= sarg1;
+       if (len>16) { i=-1; errno=EFAULT; break; }
+       gidset= (gid_t *)malloc(len * sizeof(gid_t));
+       if (gidset==NULL) { i=-1; errno=EINVAL; break; }
+       shortptr= (int16_t *)&dspace[uarg2];
+       for (j=0; j<len; j++) gidset[j]= shortptr[j];
+       i= setgroups(len, gidset);
+       free(gidset);
+       break;
+    case S_GETRLIMIT:                          /* DONE */
+       tr_rlp= (struct tr_rlimit *)&dspace[uarg2];
+       i= getrlimit(sarg1, &rlp);
+       if (i== -1) break;
+       copylong(tr_rlp->rlim_cur, rlp.rlim_cur);
+       copylong(tr_rlp->rlim_max, rlp.rlim_max);
+       break;
+    case S_SETRLIMIT:                          /* DONE */
+       tr_rlp= (struct tr_rlimit *)&dspace[uarg2];
+       copylong(rlp.rlim_cur, tr_rlp->rlim_cur);
+       copylong(rlp.rlim_max, tr_rlp->rlim_max);
+       i= setrlimit(sarg1, &rlp);
+       break;
+    case S_GETRUSAGE:
+       TrapDebug((dbg_file, "arg1 %d pointer 0%o ",sarg1,uarg2));
+       tr_use = (struct tr_rusage *) &dspace[uarg2];
+       i= getrusage(sarg1, &use);
+       if (i==-1) break;
+
+        /* Should do tr_use->ru_utime;        user time used */
+        /* Should do tr_use->ru_stime;        system time used */
+        copylong(tr_use->ru_maxrss, use.ru_maxrss);
+        copylong(tr_use->ru_ixrss, use.ru_ixrss);
+        copylong(tr_use->ru_idrss, use.ru_idrss);
+        copylong(tr_use->ru_isrss, use.ru_isrss);
+        copylong(tr_use->ru_minflt, use.ru_minflt);
+        copylong(tr_use->ru_majflt, use.ru_majflt);
+        copylong(tr_use->ru_ovly, ov_changes);
+        copylong(tr_use->ru_nswap, use.ru_nswap);
+        copylong(tr_use->ru_inblock, use.ru_inblock);
+        copylong(tr_use->ru_oublock, use.ru_oublock);
+        copylong(tr_use->ru_msgsnd, use.ru_msgsnd);
+        copylong(tr_use->ru_msgrcv, use.ru_msgrcv);
+        copylong(tr_use->ru_nsignals, use.ru_nsignals);
+        copylong(tr_use->ru_nvcsw, use.ru_nvcsw);
+        copylong(tr_use->ru_nivcsw, use.ru_nivcsw);
+       break;
+    default:
+       if ((ir & 0xff)>S_GETSOCKNAME) {
+         TrapDebug((stderr,"Apout - unknown syscall %d at PC 0%o\n",
+                                                       ir & 0xff,regs[PC]));
+       } else {
+          (void)fprintf(stderr,
+               "Apout - the 2.11BSD %s syscall is not yet implemented\n",
+                                               bsdtrap_name[ir & 0xff]);
+       }
+       exit(EXIT_FAILURE);
+    }
+
+       /* Set r0 to either errno or i, */
+       /* and clear/set C bit */
+
+    if (i == -1) {
+       SET_CC_C(); regs[0] = errno;
+       TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
+    } else {
+       CLR_CC_C(); regs[0]=i;
+       TrapDebug((dbg_file, "return %d\n", i));
+    }
+    return;
+}
+
+
+
+static int
+trap_execve(int want_env)
+{
+    u_int16_t cptr, cptr2;
+    char *buf, *name, *origpath;
+
+    origpath = strdup(&dspace[uarg1]);
+    name = xlate_filename(origpath);
+    TrapDebug((dbg_file, "%s Execing %s (%s) ", progname, name, origpath));
+
+    set_bsdsig_dfl();  /* Set signals to default values */
+
+    cptr=uarg2;
+    Argc=0; Envc=0;
+    while (Argc < MAX_ARGS) {
+       ll_word(cptr, cptr2);
+       if (cptr2 == 0)
+           break;
+       buf = &dspace[cptr2];
+       Argv[Argc++] = strdup(buf);
+       cptr += 2;
+       TrapDebug((dbg_file, "%s ", buf));
+    }
+    Argv[Argc] = NULL;
+    TrapDebug((dbg_file, "\n"));
+
+    if (want_env)
+      { cptr=uarg3;
+        while (Envc < MAX_ARGS) {
+         ll_word(cptr, cptr2);
+         if (cptr2 == 0)
+           break;
+         buf = &dspace[cptr2];
+         Envp[Envc++] = strdup(buf);
+         cptr += 2;
+        }
+       Envp[Envc] = NULL;
+      }
+
+    if (load_a_out(name,origpath,want_env) == -1) {
+       for (Argc--; Argc >= 0; Argc--)
+           free(Argv[Argc]);
+       if (want_env) for (Envc--; Envc >= 0; Envc--)
+           free(Envp[Envc]);
+       errno= ENOENT; return(-1);
+    }
+    run();                     /* Ok, so it's recursive, I dislike setjmp */
+    return(0);                 /* Just to shut the compiler up */
+}
+
+/* 2.11BSD reads directories as if they were ordinary files.
+ * The solution is to read the directory entries, and build a
+ * real file, which is passed back to the open call.
+ *
+ * A directory consists of some number of blocks of DIRBLKSIZ
+ * bytes, where DIRBLKSIZ is chosen such that it can be transferred
+ * to disk in a single atomic operation (e.g. 512 bytes on most machines).
+ *
+ * Each DIRBLKSIZ byte block contains some number of directory entry
+ * structures, which are of variable length.  Each directory entry has
+ * a struct direct at the front of it, containing its inode number,
+ * the length of the entry, and the length of the name contained in
+ * the entry.  These are followed by the name padded to a 4 byte boundary
+ * with null bytes.  All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ *
+ * The macro DIRSIZ(dp) gives the amount of space required to represent
+ * a directory entry.  Free space in a directory is represented by
+ * entries which have dp->d_reclen > DIRSIZ(dp).  All DIRBLKSIZ bytes
+ * in a directory block are claimed by the directory entries.  This
+ * usually results in the last entry in a directory having a large
+ * dp->d_reclen.  When entries are deleted from a directory, the
+ * space is returned to the previous entry in the same directory
+ * block by increasing its dp->d_reclen.  If the first entry of
+ * a directory block is free, then its dp->d_ino is set to 0.
+ * Entries other than the first in a directory do not normally have
+ * dp->d_ino set to 0.
+ */
+
+static int
+bsdopen_dir(char *name)
+{
+    DIR *d;
+    char *tmpname;
+    int i, nlen, total_left;
+    struct dirent *dent;
+    struct tr_direct odent, empty;
+
+    d = opendir(name);
+    if (d == NULL) return (-1);
+    tmpname= strdup(TMP_PLATE);
+    i= mkstemp(tmpname);
+    if (i == -1) {
+       (void)fprintf(stderr,"Apout - open_dir couldn't open %s\n", tmpname);
+       exit(EXIT_FAILURE);
+    }
+    unlink(tmpname); free(tmpname);
+
+    total_left=TR_DIRBLKSIZ;
+    empty.d_ino=0; empty.d_namlen=0; empty.d_name[0]='\0';
+    empty.d_name[1]='\0'; empty.d_name[2]='\0'; empty.d_name[3]='\0';
+
+    while ((dent = readdir(d)) != NULL) {
+       memset(odent.d_name, 0, TR_MAXNAMLEN+1);        /* Null name */
+       nlen= strlen(dent->d_name) +1;                  /* Name length */
+       if (nlen>TR_MAXNAMLEN+1) nlen=TR_MAXNAMLEN+1;
+       strncpy(odent.d_name, dent->d_name, nlen);
+       odent.d_ino = dent->d_fileno;
+                                               /* Nasty hack: ensure inode */
+                                               /* is never 0 */
+       if (odent.d_ino==0) odent.d_ino=1;
+       odent.d_namlen= nlen;
+       nlen+= (nlen & 3);                      /* Round up to mult of 4 */
+       odent.d_reclen=  nlen+6;                /* Name + 3 u_int16_ts */
+
+                                               /* Not enough room, write */
+                                               /* a blank entry */
+       if ( (total_left - odent.d_reclen) < 10) {
+           empty.d_reclen=total_left;
+           write(i, &empty, empty.d_reclen);
+           total_left=TR_DIRBLKSIZ;
+       }
+       write(i, &odent, odent.d_reclen);
+       total_left-= odent.d_reclen;
+    }
+    closedir(d);
+
+    if (total_left) {
+           empty.d_reclen=total_left; write(i, &empty, empty.d_reclen);
+    }
+    lseek(i, 0, SEEK_SET);
+    return (i);
+}
+
+#ifdef NEED_MAP_FCNTL
+/* Map the 2.11BSD fcntl mode bits to the underlying
+ * system's bits. We have to do this for Linux
+ */
+static int16_t map_fcntl(int16_t f)
+{
+  int16_t out=0;
+
+  if (f & BSD_RDONLY)   out |= O_RDONLY;
+  if (f & BSD_WRONLY)   out |= O_WRONLY;
+  if (f & BSD_RDWR)     out |= O_RDWR;
+  if (f & BSD_NONBLOCK) out |= O_NONBLOCK;
+  if (f & BSD_APPEND)   out |= O_APPEND;
+  if (f & BSD_SHLOCK)   out |= O_SHLOCK;
+  if (f & BSD_EXLOCK)   out |= O_EXLOCK;
+  if (f & BSD_ASYNC)    out |= O_ASYNC;
+  if (f & BSD_FSYNC)    out |= O_FSYNC;
+  if (f & BSD_CREAT)    out |= O_CREAT;
+  if (f & BSD_TRUNC)    out |= O_TRUNC;
+  if (f & BSD_EXCL)     out |= O_EXCL;
+
+  TrapDebug((dbg_file, "map_fcntl: 0x%x -> 0x%x, ",f,out));
+  return(out);
+}
+#endif
+#endif /* EMU211 */
diff --git a/bsdtrap.h b/bsdtrap.h
new file mode 100644 (file)
index 0000000..3773df5
--- /dev/null
+++ b/bsdtrap.h
@@ -0,0 +1,429 @@
+/* bsdtrap.h. Definitions for values and structures used in bsdtrap.c
+ *
+ * $Revision: 1.30 $
+ * $Date: 1999/03/01 19:14:16 $
+ */
+
+/* In this file, we list the trap number for each system call,
+ * and the structures associated with several of the systems
+ * calls in 2.11BSD UNIX
+ */
+
+#define S_INDIR                0
+#define S_EXIT         1
+#define S_FORK         2
+#define S_READ         3
+#define S_WRITE                4
+#define S_OPEN         5
+#define S_CLOSE                6
+#define S_WAIT4                7
+#define S_CREAT                8
+#define S_LINK         9
+#define S_UNLINK       10
+#define S_EXECV                11
+#define S_CHDIR                12
+#define S_FCHDIR       13
+#define S_MKNOD                14
+#define S_CHMOD                15
+#define S_CHOWN                16
+#define S_CHFLAGS      17
+#define S_FCHFLAGS     18
+#define S_LSEEK                19
+#define S_GETPID       20
+#define S_MOUNT                21
+#define S_UMOUNT       22
+#define S_SYSCTL       23
+#define S_GETUID       24
+#define S_GETEUID      25
+#define S_PTRACE       26
+#define S_GETPPID      27
+#define S_STATFS       28
+#define S_FSTATFS      29
+#define S_GETFSSTAT    30
+#define S_SIGACTION    31
+#define S_SIGPROCMASK  32
+#define S_ACCESS       33
+#define S_SIGPENDING   34
+#define S_SIGALTSTACK  35
+#define S_SYNC         36
+#define S_KILL         37
+#define S_STAT         38
+#define S_GETLOGIN     39
+#define S_LSTAT                40
+#define S_DUP          41
+#define S_PIPE         42
+#define S_SETLOGIN     43
+#define S_PROFIL       44
+#define S_SETUID       45
+#define S_SETEUID      46
+#define S_GETGID       47
+#define S_GETEGID      48
+#define S_SETGID       49
+#define S_SETEGID      50
+#define S_ACCT         51
+#define S_OLDPHYS      52
+#define S_OLDLOCK      53
+#define S_IOCTL                54
+#define S_REBOOT       55
+#define S_SYMLINK      57
+#define S_READLINK     58
+#define S_EXECVE       59
+#define S_UMASK                60
+#define S_CHROOT       61
+#define S_FSTAT                62
+#define S_GETPAGESIZE  64
+#define S_VFORK                66
+#define S_SBRK         69
+#define S_VHANGUP      76
+#define S_GETGROUPS    79
+#define S_SETGROUPS    80
+#define S_GETPGRP      81
+#define S_SETPGRP      82
+#define S_SETITIMER    83
+#define S_WAIT         84
+#define S_GETITIMER    86
+#define S_GETHOSTNAME  87
+#define S_SETHOSTNAME  88
+#define S_GETDTABLESIZE 89
+#define S_DUP2         90
+#define S_UNUSED1      91
+#define S_FCNTL                92
+#define S_SELECT       93
+#define S_UNUSED2      94
+#define S_FSYNC                95
+#define S_SETPRIORITY  96
+#define S_SOCKET       97
+#define S_CONNECT      98
+#define S_ACCEPT       99
+#define S_GETPRIORITY  100
+#define S_SEND         101
+#define S_RECV         102
+#define S_SIGRETURN    103
+#define S_BIND         104
+#define S_SETSOCKOPT   105
+#define S_LISTEN       106
+#define S_SIGSUSPEND   107
+#define S_SIGVEC       108
+#define S_SIGBLOCK     109
+#define S_SIGSETMASK   110
+#define S_SIGPAUSE     111
+#define S_SIGSTACK     112
+#define S_RECVMSG      113
+#define S_SENDMSG      114
+#define S_GETTIMEOFDAY 116
+#define S_GETRUSAGE    117
+#define S_GETSOCKOPT   118
+#define S_READV                120
+#define S_WRITEV       121
+#define S_SETTIMEOFDAY 122
+#define S_FCHOWN       123
+#define S_FCHMOD       124
+#define S_RECVFROM     125
+#define S_SETREUID     126
+#define S_SETREGID     127
+#define S_RENAME       128
+#define S_TRUNCATE     129
+#define S_FTRUNCATE    130
+#define S_FLOCK                131
+#define S_SENDTO       133
+#define S_SHUTDOWN     134
+#define S_SOCKETPAIR   135
+#define S_MKDIR                136
+#define S_RMDIR                137
+#define S_UTIMES       138
+#define S_ADJTIME      140
+#define S_GETPEERNAME  141
+#define S_GETHOSTID    142
+#define S_SETHOSTID    143
+#define S_GETRLIMIT    144
+#define S_SETRLIMIT    145
+#define S_KILLPG       146
+#define S_NOSYS147     147
+#define S_SETQUOTA     148
+#define S_QUOTA                149
+#define S_GETSOCKNAME  150
+
+
+/*
+ * System call names.
+ */
+#ifdef BSDTRAP_NAME
+char *bsdtrap_name[] = {
+       "indir",                /*   0 = indir */
+       "exit",                 /*   1 = exit */
+       "fork",                 /*   2 = fork */
+       "read",                 /*   3 = read */
+       "write",                /*   4 = write */
+       "open",                 /*   5 = open */
+       "close",                /*   6 = close */
+       "wait4",                /*   7 = wait4 */
+       "creat",                /*   8 = creat */
+       "link",                 /*   9 = link */
+       "unlink",               /*  10 = unlink */
+       "execv",                /*  11 = execv */
+       "chdir",                /*  12 = chdir */
+       "fchdir",               /*  13 = fchdir */
+       "mknod",                /*  14 = mknod */
+       "chmod",                /*  15 = chmod */
+       "chown",                /*  16 = chown; now 3 args */
+       "chflags",              /*  17 = chflags */
+       "fchflags",             /*  18 = fchflags */
+       "lseek",                /*  19 = lseek */
+       "getpid",               /*  20 = getpid */
+       "mount",                /*  21 = mount */
+       "umount",               /*  22 = umount */
+       "__sysctl",             /*  23 = __sysctl */
+       "getuid",               /*  24 = getuid */
+       "geteuid",              /*  25 = geteuid */
+       "ptrace",               /*  26 = ptrace */
+       "getppid",              /*  27 = getppid */
+       "statfs",               /*  28 = statfs */
+       "fstatfs",              /*  29 = fstatfs */
+       "getfsstat",            /*  30 = getfsstat */
+       "sigaction",            /*  31 = sigaction */
+       "sigprocmask",          /*  32 = sigprocmask */
+       "access",               /*  33 = access */
+       "sigpending",           /*  34 = sigpending */
+       "sigaltstack",          /*  35 = sigaltstack */
+       "sync",                 /*  36 = sync */
+       "kill",                 /*  37 = kill */
+       "stat",                 /*  38 = stat */
+       "getlogin",             /*  39 = getlogin */
+       "lstat",                /*  40 = lstat */
+       "dup",                  /*  41 = dup */
+       "pipe",                 /*  42 = pipe */
+       "setlogin",             /*  43 = setlogin */
+       "profil",               /*  44 = profil */
+       "setuid",               /*  45 = setuid */
+       "seteuid",              /*  46 = seteuid */
+       "getgid",               /*  47 = getgid */
+       "getegid",              /*  48 = getegid */
+       "setgid",               /*  49 = setgid */
+       "setegid",              /*  50 = setegid */
+       "acct",                 /*  51 = turn acct off/on */
+       "old phys",             /*  52 = old set phys addr */
+       "old lock",             /*  53 = old lock in core */
+       "ioctl",                /*  54 = ioctl */
+       "reboot",               /*  55 = reboot */
+       "old mpx - nosys",      /*  56 = old mpxchan */
+       "symlink",              /*  57 = symlink */
+       "readlink",             /*  58 = readlink */
+       "execve",               /*  59 = execve */
+       "umask",                /*  60 = umask */
+       "chroot",               /*  61 = chroot */
+       "fstat",                /*  62 = fstat */
+       "#63",                  /*  63 = used internally */
+       "getpagesize",          /*  64 = getpagesize */
+       "4.3 mremap - nosys",   /*  65 = mremap */
+       "vfork",                /*  66 = vfork */
+       "old vread - nosys",    /*  67 = old vread */
+       "old vwrite - nosys",   /*  68 = old vwrite */
+       "sbrk",                 /*  69 = sbrk */
+       "4.3 sstk - nosys",     /*  70 = sstk */
+       "4.3 mmap - nosys",     /*  71 = mmap */
+       "old vadvise - nosys",  /*  72 = old vadvise */
+       "4.3 munmap - nosys",   /*  73 = munmap */
+       "4.3 mprotect - nosys", /*  74 = mprotect */
+       "4.3 madvise - nosys",  /*  75 = madvise */
+       "vhangup",              /*  76 = vhangup */
+       "old vlimit - nosys",   /*  77 = old vlimit */
+       "4.3 mincore - nosys",  /*  78 = mincore */
+       "getgroups",            /*  79 = getgroups */
+       "setgroups",            /*  80 = setgroups */
+       "getpgrp",              /*  81 = getpgrp */
+       "setpgrp",              /*  82 = setpgrp */
+       "setitimer",            /*  83 = setitimer */
+       "wait",                 /*  84 = wait */
+       "4.3 swapon - nosys",   /*  85 = swapon */
+       "getitimer",            /*  86 = getitimer */
+       "gethostname",          /*  87 = gethostname */
+       "sethostname",          /*  88 = sethostname */
+       "getdtablesize",        /*  89 = getdtablesize */
+       "dup2",                 /*  90 = dup2 */
+       "nosys",                /*  91 = unused */
+       "fcntl",                /*  92 = fcntl */
+       "select",               /*  93 = select */
+       "nosys",                /*  94 = unused */
+       "fsync",                /*  95 = fsync */
+       "setpriority",          /*  96 = setpriority */
+       "socket",               /*  97 = socket */
+       "connect",              /*  98 = connect */
+       "accept",               /*  99 = accept */
+       "getpriority",          /* 100 = getpriority */
+       "send",                 /* 101 = send */
+       "recv",                 /* 102 = recv */
+       "sigreturn",            /* 103 = sigreturn */
+       "bind",                 /* 104 = bind */
+       "setsockopt",           /* 105 = setsockopt */
+       "listen",               /* 106 = listen */
+       "sigsuspend",           /* 107 = sigsuspend */
+       "sigvec",               /* 108 = sigvec */
+       "sigblock",             /* 109 = sigblock */
+       "sigsetmask",           /* 110 = sigsetmask */
+       "sigpause",             /* 111 = sigpause */
+       "sigstack",             /* 112 = sigstack */
+       "recvmsg",              /* 113 = recvmsg */
+       "sendmsg",              /* 114 = sendmsg */
+       "old vtrace - nosys",   /* 115 = old vtrace */
+       "gettimeofday",         /* 116 = gettimeofday */
+       "getrusage",            /* 117 = getrusage */
+       "getsockopt",           /* 118 = getsockopt */
+       "4.3 resuba - nosys",   /* 119 = resuba */
+       "readv",                /* 120 = readv */
+       "writev",               /* 121 = writev */
+       "settimeofday",         /* 122 = settimeofday */
+       "fchown",               /* 123 = fchown */
+       "fchmod",               /* 124 = fchmod */
+       "recvfrom",             /* 125 = recvfrom */
+       "setreuid",             /* 126 = setreuid */
+       "setregid",             /* 127 = setregid */
+       "rename",               /* 128 = rename */
+       "truncate",             /* 129 = truncate */
+       "ftruncate",            /* 130 = ftruncate */
+       "flock",                /* 131 = flock */
+       "old portal - nosys",   /* 132 = old portal */
+       "sendto",               /* 133 = sendto */
+       "shutdown",             /* 134 = shutdown */
+       "socketpair",           /* 135 = socketpair */
+       "mkdir",                /* 136 = mkdir */
+       "rmdir",                /* 137 = rmdir */
+       "utimes",               /* 138 = utimes */
+       "4.2 sigreturn - nosys",        /* 139 = old 4.2 sigreturn */
+       "adjtime",              /* 140 = adjtime */
+       "getpeername",          /* 141 = getpeername */
+       "gethostid",            /* 142 = gethostid */
+       "sethostid",            /* 143 = sethostid */
+       "getrlimit",            /* 144 = getrlimit */
+       "setrlimit",            /* 145 = setrlimit */
+       "killpg",               /* 146 = killpg */
+       "#147",                 /* 147 = nosys */
+       "setquota",             /* 148 = setquota */
+       "quota",                /* 149 = quota */
+       "getsockname",          /* 150 = getsockname */
+};
+#endif
+
+/* fcntl defines used by open */
+#define BSD_RDONLY        0x0000          /* open for reading only */
+#define BSD_WRONLY        0x0001          /* open for writing only */
+#define BSD_RDWR          0x0002          /* open for reading and writing */
+#define BSD_NONBLOCK      0x0004          /* no delay */
+#define BSD_APPEND        0x0008          /* set append mode */
+#define BSD_SHLOCK        0x0010          /* open with shared file lock */
+#define BSD_EXLOCK        0x0020          /* open with exclusive file lock */
+#define BSD_ASYNC         0x0040          /* signal pgrp when data ready */
+#define BSD_FSYNC         0x0080          /* synchronous writes */
+#define BSD_CREAT         0x0200          /* create if nonexistant */
+#define BSD_TRUNC         0x0400          /* truncate to zero length */
+#define BSD_EXCL          0x0800          /* error if already exists */
+
+
+/* stat struct, used by S_STAT, S_FSTAT, S_LSTAT */
+struct tr_stat
+{
+       int16_t    st_dev;
+       u_int16_t   st_ino;
+       u_int16_t   st_mode;
+       int16_t    st_nlink;
+       u_int16_t   st_uid;
+       u_int16_t   st_gid;
+       int16_t    st_rdev;
+       int8_t     st_size[4];          /* Alignment problems */
+       int8_t     st_atim[4];          /* Alignment problems */
+       int16_t    st_spare1;
+       int8_t     st_mtim[4];          /* Alignment problems */
+       int16_t    st_spare2;
+       int8_t     st_ctim[4];          /* Alignment problems */
+       int16_t    st_spare3;
+       int8_t     st_blksize[4];       /* Alignment problems */
+       int8_t     st_blocks[4];        /* Alignment problems */
+       u_int16_t   st_flags;
+       u_int16_t   st_spare4[3];
+};
+
+/* Directory entry */
+#define TR_DIRBLKSIZ   512
+#define TR_MAXNAMLEN   63
+struct tr_direct {
+    u_int16_t d_ino;                   /* inode number of entry */
+    u_int16_t d_reclen;                        /* length of this record */
+    u_int16_t d_namlen;                        /* length of string in d_name */
+    char d_name[TR_MAXNAMLEN+1];       /* name must be no longer than this */
+};
+
+/* used by S_ADJTIME */
+struct tr_timeval {
+    u_int32_t    tv_sec;           /* seconds */
+    u_int32_t    tv_usec;          /* and microseconds */
+};
+/* Used by S_GETTIMEOFDAY */
+struct tr_timezone {
+    int16_t        tz_minuteswest; /* minutes west of Greenwich */
+    int16_t        tz_dsttime;     /* type of dst correction */
+};
+
+/* used in itimer calls */
+struct tr_itimerval {
+    struct     tr_timeval it_interval;    /* timer interval */
+    struct     tr_timeval it_value;       /* current value */
+};
+
+/* Used by socket calls */
+struct tr_sockaddr {
+    u_int16_t sa_family;               /* address family */
+    char        sa_data[14];           /* up to 14 bytes of direct address */
+};
+
+/* used in rlimit calls */
+struct tr_rlimit {
+    int32_t rlim_cur;          /* current (soft) limit */
+    int32_t rlim_max;          /* maximum value for rlim_cur */
+};
+
+struct  tr_rusage {
+        struct tr_timeval ru_utime;        /* user time used */
+        struct tr_timeval ru_stime;        /* system time used */
+        u_int32_t  ru_maxrss;
+        u_int32_t  ru_ixrss;               /* integral shared memory size */
+        u_int32_t  ru_idrss;               /* integral unshared data size */
+        u_int32_t  ru_isrss;               /* integral unshared stack size */
+        u_int32_t  ru_minflt;              /* page reclaims */
+        u_int32_t  ru_majflt;              /* page faults */
+        u_int32_t  ru_ovly;                /* overlay changes */
+        u_int32_t  ru_nswap;               /* swaps */
+        u_int32_t  ru_inblock;             /* block input operations */
+        u_int32_t  ru_oublock;             /* block output operations */
+        u_int32_t  ru_msgsnd;              /* messages sent */
+        u_int32_t  ru_msgrcv;              /* messages received */
+        u_int32_t  ru_nsignals;            /* signals received */
+        u_int32_t  ru_nvcsw;               /* voluntary context switches */
+        u_int32_t  ru_nivcsw;              /* involuntary context switches */
+};
+
+/* for writev, readv */
+struct tr_iovec {
+    u_int16_t   iov_base;
+    u_int16_t   iov_len;
+};
+
+
+/* A union which will point at the trap args, so that
+ * we can get at the various args of different types
+ */
+typedef union {
+    int16_t   sarg[6]; /* Signed 16-bit args */
+    u_int16_t uarg[6]; /* Unsigned 16-bit args */
+} arglist;
+
+#define sarg1  A->sarg[0]
+#define sarg2  A->sarg[1]
+#define sarg3  A->sarg[2]
+#define sarg4  A->sarg[3]
+#define sarg5  A->sarg[4]
+#define sarg6  A->sarg[5]
+#define uarg1  A->uarg[0]
+#define uarg2  A->uarg[1]
+#define uarg3  A->uarg[2]
+#define uarg4  A->uarg[3]
+#define uarg5  A->uarg[4]
+#define uarg6  A->uarg[5]
diff --git a/cpu.c b/cpu.c
new file mode 100644 (file)
index 0000000..17753f4
--- /dev/null
+++ b/cpu.c
@@ -0,0 +1,209 @@
+/* cpu.c - this holds the main loop for the emulator, plus generic
+ * functions to deal with exceptional instructions and events
+ *
+ * $Revision: 1.25 $
+ * $Date: 2002/06/10 11:41:40 $
+ */
+#include "defines.h"
+#include <unistd.h>
+
+u_int8_t *ispace, *dspace;     /* Instruction and Data spaces */
+u_int16_t dwrite_base=2;       /* Lowest addr where dspace writes can occur */
+
+u_int16_t regs[8];             /* general registers */
+u_int16_t ir;                  /* current instruction register */
+u_int16_t *adptr;              /* used in memory access macros */
+u_int16_t ea_addr;             /* stored address for dest modifying insts */
+
+int CC_N=0;                    /* The processor status word is represented */
+int CC_Z=0;                    /* by these four values. On some */
+int CC_V=0;                    /* architectures, you may get a performance */
+int CC_C=0;                    /* increase by using shorts or bytes */
+
+u_int16_t dstword;             /* These globals are used in the effective */
+u_int16_t srcword;             /* address calculations, mainly to save */
+u_int16_t tmpword;             /* parameter passing overheads in */
+u_int8_t dstbyte;              /* function calls */
+u_int8_t srcbyte;
+u_int8_t tmpbyte;
+struct our_siglist *Sighead=NULL;      /* List of pending signals */
+struct our_siglist *Sigtail=NULL;      /* List of pending signals */
+void (*sigrunner)(void)= NULL;                 /* F'n that will run the signal */
+
+#ifdef DEBUG
+extern char *iname[1024];
+extern char *iname0[64];       /* Name of each instruction */
+extern char *iname1[64];
+char *name;
+#endif
+
+
+/* Run until told to stop. */
+void run() {
+#ifdef DEBUG
+    int i;
+
+    if (trap_debug) {
+       TrapDebug((dbg_file, "Just starting to run pid %d\n",(int)getpid()));
+       TrapDebug((dbg_file, "Regs are           "));
+       for (i=0;i<=PC;i++) TrapDebug((dbg_file, "%06o ",regs[i]));
+       TrapDebug((dbg_file, "\n"));
+    }
+#endif
+
+    while (1) {
+
+       /* Fetch and execute the instruction. */
+
+#ifdef DEBUG
+       lli_word(regs[PC], ir);
+       if (inst_debug) {
+          i= ir >> 6;
+          switch (i) {
+               case 0: name= iname0[ir & 077]; break;
+               case 2: name= iname1[ir & 077]; break;
+               default: name= iname[i];
+          }
+          TrapDebug((dbg_file, "%06o %06o %4s ", regs[7], ir, name));
+          TrapDebug((dbg_file, "%06o %06o %06o %06o %06o %06o %06o   ",
+               regs[0], regs[1], regs[2], regs[3],
+               regs[4], regs[5], regs[6]));
+          TrapDebug((dbg_file, "NZVC1 %d%d%d%d\n",CC_N,CC_Z,CC_V,CC_C));
+       }
+       regs[PC] += 2; itab[ir >> 6] ();
+       if ((Sighead!=NULL) && (sigrunner!=NULL)) (void) (*sigrunner)();
+#else
+       /* When not debugging, we can manually unroll this inner loop */
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       lli_word(regs[PC], ir); regs[PC] += 2; itab[ir >> 6] ();
+       if ((Sighead!=NULL) && (sigrunner!=NULL)) (void) (*sigrunner)();
+#endif
+    }
+}
+
+/* sim_init() - Initialize the cpu registers. */
+void sim_init() {
+    int x;
+
+    for (x = 0; x < 8; ++x) { regs[x] = 0; }
+    ir = 0; CLR_CC_ALL();
+}
+
+void bus_error(int signo)
+{
+    TrapDebug((dbg_file, "Apout - pid %d bus error at PC 0%06o\n",
+                                       (int)getpid(), regs[PC]));
+    TrapDebug((dbg_file, "%06o  ", ir));
+    TrapDebug((dbg_file, "%o %o %o %o %o %o %o %o  ",
+        regs[0], regs[1], regs[2], regs[3],
+        regs[4], regs[5], regs[6], regs[7]));
+    TrapDebug((dbg_file, "NZVC2 are %d%d%d%d\n",CC_N,CC_Z,CC_V,CC_C));
+    exit(EXIT_FAILURE);
+}
+
+void seg_fault() {
+    TrapDebug((dbg_file, "Apout - pid %d segmentation fault at PC 0%06o\n",
+                                       (int)getpid(), regs[PC]));
+    TrapDebug((dbg_file, "%06o  ", ir));
+    TrapDebug((dbg_file, "%o %o %o %o %o %o %o %o  ",
+        regs[0], regs[1], regs[2], regs[3],
+        regs[4], regs[5], regs[6], regs[7]));
+    TrapDebug((dbg_file, "NZVC3 are %d%d%d%d\n",CC_N,CC_Z,CC_V,CC_C));
+    exit(EXIT_FAILURE);
+}
+
+void waiti() {
+    TrapDebug((stderr, "Apout - pid %d waiti instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void halt() {
+    TrapDebug((stderr, "Apout - pid %d halt instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void iot() {
+    TrapDebug((stderr, "Apout - pid %d iot instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void emt() {
+    TrapDebug((stderr, "Apout - pid %d emt instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void bpt() {
+    TrapDebug((stderr, "Apout - pid %d bpt instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void illegal() {
+    TrapDebug((stderr, "Apout - pid %d illegal instruction %o at PC 0%o\n",
+                                       (int)getpid(),ir, regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void not_impl() {
+    TrapDebug((stderr, "Apout - pid %d unimplemented instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void mark() {
+    TrapDebug((stderr, "Apout - pid %d mark instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void mfpd() {
+    TrapDebug((stderr, "Apout - pid %d mfpd instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void mtpd() {
+    TrapDebug((stderr, "Apout - pid %d mtpd instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void trap() {
+    TrapDebug((stderr, "Apout - pid %d trap instruction at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+void bad_FP_reg() {
+    TrapDebug((stderr, "Apout - pid %d bad FP register used at PC 0%o\n",
+                                       (int)getpid(), regs[PC]));
+    exit(EXIT_FAILURE);
+}
+
+/* This is the generic function which catches
+ * a signal, and appends it to the queue.
+ */
+void sigcatcher(int sig)
+{
+ struct our_siglist *this;
+
+ this= (struct our_siglist *)malloc(sizeof(struct our_siglist));
+ if (this==NULL) return;
+
+ TrapDebug((dbg_file, "Caught signal %d\n",sig));
+
+ this->sig=sig; this->next=NULL;
+ if (Sighead==NULL) { Sighead=Sigtail=this; }
+ else { Sigtail->next= this; Sigtail=this; }
+}
diff --git a/debug.c b/debug.c
new file mode 100644 (file)
index 0000000..feb081d
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,159 @@
+/* List of names for each instruction
+ *
+ * $Revision: 1.5 $
+ * $Date: 1999/01/05 22:50:48 $
+ */
+#ifdef DEBUG
+char *iname0[64] = {
+    "halt","waiti","illegal","bpt","iot","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal"
+};
+
+char *iname1[64] = {
+    "rts","rts","rts","rts","rts","rts","rts","rts",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+    "ccc","ccc","ccc","ccc","ccc","ccc","ccc","ccc",
+    "ccc","ccc","ccc","ccc","ccc","ccc","ccc","ccc",
+    "scc","scc","scc","scc","scc","scc","scc","scc",
+    "scc","scc","scc","scc","scc","scc","scc","scc"
+};
+
+char *iname[1024] = {
+    "dositab0","jmp","dositab1","swabi","br","br","br","br",
+    "bne","bne","bne","bne","beq","beq","beq","beq",
+    "bge","bge","bge","bge","blt","blt","blt","blt",
+    "bgt","bgt","bgt","bgt","ble","ble","ble","ble",
+    "jsr","jsr","jsr","jsr","jsr","jsr","jsr","jsr",
+    "clr","com","inc","dec","neg","adc","sbc","tst",
+    "ror","rol","asr","asl","mark","mfpi","mtpi","sxt",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "mov","mov","mov","mov","mov","mov","mov","mov",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "cmp","cmp","cmp","cmp","cmp","cmp","cmp","cmp",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bit","bit","bit","bit","bit","bit","bit","bit",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bic","bic","bic","bic","bic","bic","bic","bic",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "bis","bis","bis","bis","bis","bis","bis","bis",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "add","add","add","add","add","add","add","add",
+    "mul","mul","mul","mul","mul","mul","mul","mul",
+    "divide","divide","divide","divide","divide","divide","divide","divide",
+    "ash","ash","ash","ash","ash","ash","ash","ash",
+    "ashc","ashc","ashc","ashc","ashc","ashc","ashc","ashc",
+    "xor","xor","xor","xor","xor","xor","xor","xor",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+    "sob","sob","sob","sob","sob","sob","sob","sob",
+    "bpl","bpl","bpl","bpl","bmi","bmi","bmi","bmi",
+    "bhi","bhi","bhi","bhi","blos","blos","blos","blos",
+    "bvc","bvc","bvc","bvc","bvs","bvs","bvs","bvs",
+    "bcc","bcc","bcc","bcc","bcs","bcs","bcs","bcs",
+    "emt","emt","emt","emt","trap","trap","trap","trap",
+    "clrb","comb","incb","decb","negb","adcb","sbcb","tstb",
+    "rorb","rolb","asrb","aslb","mtps","mfpd","mtpd","mfps",
+"illegal","illegal","illegal","illegal","illegal","illegal","illegal","illegal",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "movb","movb","movb","movb","movb","movb","movb","movb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb","cmpb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bitb","bitb","bitb","bitb","bitb","bitb","bitb","bitb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bicb","bicb","bicb","bicb","bicb","bicb","bicb","bicb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "bisb","bisb","bisb","bisb","bisb","bisb","bisb","bisb",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "sub","sub","sub","sub","sub","sub","sub","sub",
+    "fpset","ldfps","stfps","stst","clrf","tstf","absf","negf",
+    "mulf","mulf","mulf","mulf","moddf","moddf","moddf","moddf",
+    "addf","addf","addf","addf","ldf","ldf","ldf","ldf",
+    "subf","subf","subf","subf","cmpf","cmpf","cmpf","cmpf",
+    "stf","stf","stf","stf","divf","divf","divf","divf",
+    "stexp","stexp","stexp","stexp","stcfi","stcfi","stcfi","stcfi",
+    "stcdf","stcdf","stcdf","stcdf","ldexpp","ldexpp","ldexpp","ldexpp",
+    "lcdif","lcdif","lcdif","lcdif","ldcdf","ldcdf","ldcdf","ldcdf"
+};
+#endif
diff --git a/defines.h b/defines.h
new file mode 100644 (file)
index 0000000..b0d8119
--- /dev/null
+++ b/defines.h
@@ -0,0 +1,636 @@
+/* defines.h   - Definitions of things needed in all C files
+ *
+ * $Revision: 2.73 $
+ * $Date: 2002/06/10 12:08:27 $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+
+/* Defines for ifdef'd code -- define them in the Makefile */
+
+/* #define DEBUG                       adds in debugging code */
+/* #define ZERO_MEMORY                 zeros all of process memory before
+                                       it starts to run */
+/* #define NATIVES                     allows native binaries and PDP-11
+                                       binaries in the filespace */
+/* #define EMU211                      add 2.11BSD emulation */
+/* #define EMUV1                       add 1st Edition emulation */
+/* #define INLINE inline               inlines some functions (needs gcc) */
+                                       
+
+/* Optimisation defines */
+#ifndef INLINE
+# define INLINE
+#endif
+
+/* Special defines to enable/disable certain
+ * functionality. These are added as required
+ * to port to new platforms. Please send in new
+ * defines, please!
+ */
+
+#if defined(__FreeBSD__) && __FreeBSD__ < 3
+# define NO_GETPGID
+#endif
+
+#ifdef __FreeBSD__
+# define Reboot(x) reboot(x)
+#endif
+
+#ifdef __linux__
+# define NO_CHFLAGS
+# define NO_STFLAGS
+# define NO_GETPGID
+# define NEED_MAP_FCNTL
+# define SIGEMT 0
+# ifndef SIGSYS
+#  define SIGSYS 0
+# endif
+# define OXTABS XTABS
+# define VDSUSP VSUSP          /* I don't think these are equivalent */
+# define O_SHLOCK 0
+# define O_EXLOCK 0
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# define Reboot(x) reboot(x,NULL)
+#endif
+
+#ifndef Reboot
+# define Reboot(x) exit(0)
+#endif
+
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && \
+    !defined(__OpenBSD__) && !defined(__linux__)
+# define NEED_INT_N
+#endif
+
+/* Type definitions for PDP data types. You may need to
+ * define NEED_INT_N if your system  doesn't provide the
+ * types defined below. If you do this, the best way is
+ * to add some #if .. #define .. #endif lines above,
+ * rather then modifying the ones below. If you make
+ * changes to the #if's above, then I would  be very
+ * happy to include them.
+ *
+ * Warren Toomey: wkt@tuhs.org
+ */
+
+#ifdef NEED_INT_N
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef unsigned char u_int8_t;
+typedef unsigned short u_int16_t;
+typedef unsigned long u_int32_t;
+#endif
+
+/* Macro defines for debug output, makes
+ * the code look somewhat cleaner
+ */
+
+#ifdef DEBUG
+# define TrapDebug(x) if (trap_debug) (void)fprintf x
+# define InstDebug(x) if (inst_debug) (void)fprintf x
+# define JsrDebug(x)  if (jsr_debug)  (void)fprintf x
+# define FpDebug(x)   if (fp_debug)   (void)fprintf x
+#else
+# define TrapDebug(x)
+# define InstDebug(x)
+# define JsrDebug(x)
+# define FpDebug(x)
+#endif
+
+                               /* Defines for -DSTREAM_BUFFERING */
+#define NFILE   40             /* Number of file pointers we can buffer */
+#define ValidFD(x) ((x>=0) && (x<NFILE))
+                               /* Used for opening on directories */
+#define TMP_PLATE       "/usr/tmp/apout_dir.XXXXXX"
+
+
+/* Set up prototype macro for 
+ * both K&R and ANSI C platforms
+ */
+#ifdef __STDC__
+#define P(s) s
+#else
+#define P(s) ()
+#endif
+
+typedef void (*_itab) P((void));
+extern _itab itab[];           /* Instruction Table for Fast Decode. */
+
+typedef float  FLOAT;          /* For now, we use floats to do FP */
+
+/* PDP processor defines. */
+
+#define SP     6               /* stack pointer */
+#define PC     7               /* program counter */
+#define CC_NBIT 010            /* Positions of the flags in the */
+#define CC_ZBIT 04             /* processor status word */
+#define CC_VBIT 02
+#define CC_CBIT 01
+
+#define PDP_MEM_SIZE   65536   /* Size of inst-space and data-space */
+#define MAX_ARGS       200     /* Max cmd-line args per process */
+
+
+/* Global variables. */
+
+extern u_int16_t regs[8];      /* general registers */
+extern u_int16_t ir;           /* current instruction register */
+extern int CC_N;               /* The processor status word is represented */
+extern int CC_Z;               /* by these four values. On some */
+extern int CC_V;               /* architectures, you may get a performance */
+extern int CC_C;               /* increase by changing the size of the vars */
+
+extern FLOAT  fregs[8];                /* FP registers */
+extern int FPC;                        /* FP Status flags */
+extern int FPZ;
+extern int FPN;
+extern int FPV;
+extern int FPMODE;             /* 0 = float, 1 = doubles */
+extern int INTMODE;            /* 0 = integers, 1 = longs */
+
+extern u_int16_t ea_addr;      /* stored address for dest modifying insts */
+extern u_int8_t *ispace, *dspace;
+extern u_int16_t dwrite_base;  /* Lowest addr where dspace writes can occur */
+
+extern u_int16_t dstword;      /* These globals are used in the effective */
+extern u_int16_t srcword;      /* address calculations, mainly to save */
+extern u_int16_t tmpword;      /* parameter passing overheads in */
+extern u_int8_t dstbyte;       /* function calls */
+extern u_int8_t srcbyte;
+extern u_int8_t tmpbyte;
+
+                               /* The following array holds the FILE pointers
+                                * that correspond to open file descriptors.
+                                * Only fds which are not ttys have
+                                * FILE * pointers
+                                */
+extern FILE *stream[NFILE];
+extern char *streammode[NFILE];
+
+extern int sig_arrived;                /* Indicates if a signal has arrived */
+extern int Argc, Envc;         /* Arguments passed to new process */
+extern char *Argv[MAX_ARGS], *Envp[MAX_ARGS];
+extern int Binary;             /* Type of binary this a.out is. One of: */
+#define IS_UNKNOWN     0
+#define IS_V1          1
+#define IS_V2          2
+#define IS_V3          3
+#define IS_V4          4
+#define IS_V5          5
+#define IS_V6          6
+#define IS_V7          7
+#define IS_A68         68
+#define IS_29BSD       29
+#define IS_211BSD      211
+
+                               /* 2.11BSD overlay stuff */
+extern u_int32_t ov_changes;   /* Number of overlay changes */
+extern u_int8_t current_ov;    /* Current overlay number */
+
+#ifdef DEBUG
+                               /* Debugging flags */
+extern int inst_debug,         /* Print a line before each instruction */
+    trap_debug,                        /* Print details of each trap */
+    jsr_debug,                 /* Print out each jsr */
+    fp_debug;                  /* Print out each floating-point instruction */
+extern FILE *dbg_file;         /* Debugging output file */
+extern char *progname;         /* The program's name - used in debugging */
+#endif
+
+                               /* We keep a list of signals that are pending */
+struct our_siglist {
+        int sig;               /* Number of the signal */
+        struct our_siglist *next;
+};
+extern struct our_siglist *Sighead;    /* Head of the list */
+extern struct our_siglist *Sigtail;    /* Tail of the list */
+
+/* Inline defines. */
+
+#define CLR_CC_V()     CC_V=0
+#define CLR_CC_C()     CC_C=0
+#define CLR_CC_Z()     CC_Z=0
+#define CLR_CC_N()     CC_N=0
+#define CLR_CC_ALL()   CC_V=CC_C=CC_Z=CC_N=0
+
+#define SET_CC_V()     CC_V=1
+#define SET_CC_C()     CC_C=1
+#define SET_CC_Z()     CC_Z=1
+#define SET_CC_N()     CC_N=1
+
+#define SRC_MODE       (( ir & 07000 ) >> 9 )
+#define SRC_REG                (( ir & 0700 ) >> 6 )
+#define DST_MODE       (( ir & 070 ) >> 3 )
+#define DST_REG                ( ir & 07 )
+
+#define LSBIT  1               /* least significant bit */
+
+#define MPI    0077777         /* most positive integer */
+#define MNI    0100000         /* most negative integer */
+#define NEG_1  0177777         /* negative one */
+#define SIGN   0100000         /* sign bit */
+#define CARRY  0200000         /* set if carry out */
+
+#define MPI_B  0177            /* most positive integer (byte) */
+#define MNI_B  0200            /* most negative integer (byte) */
+#define NEG_1_B 0377           /* negative one (byte) */
+#define SIGN_B 0200            /* sign bit (byte) */
+#define CARRY_B 0400           /* set if carry out (byte) */
+
+#define LOW16( data )  (u_int16_t)(( data ) & 0177777 )        /* mask the lower 16 bits */
+#define LOW8( data )   (u_int8_t)(( data ) & 0377 )    /* mask the lower 8 bits */
+
+#define CHG_CC_N( d )  if ((d) & SIGN ) \
+                                       SET_CC_N(); \
+                               else \
+                                       CLR_CC_N()
+
+#define CHGB_CC_N( d ) if ((d) & SIGN_B ) \
+                               SET_CC_N(); \
+                       else \
+                               CLR_CC_N()
+
+#define CHG_CC_Z( d )  if ( d ) \
+                                       CLR_CC_Z(); \
+                               else \
+                                       SET_CC_Z()
+
+#define CHGB_CC_Z( d ) if ( LOW8( d )) \
+                               CLR_CC_Z(); \
+                       else \
+                               SET_CC_Z()
+
+#define CHG_CC_C( d )  if ((d) & CARRY ) \
+                                       SET_CC_C(); \
+                               else \
+                                       CLR_CC_C()
+
+#define CHG_CC_IC( d ) if ((d) & CARRY ) \
+                                       CLR_CC_C(); \
+                               else \
+                                       SET_CC_C()
+
+#define CHGB_CC_IC( d ) if ((d) & CARRY_B ) \
+                               CLR_CC_C(); \
+                       else \
+                               SET_CC_C()
+
+#define CHG_CC_V( d1, d2, d3 ) \
+                               if ((( d1 & SIGN ) == ( d2 & SIGN )) \
+                               && (( d1 & SIGN ) != ( d3 & SIGN ))) \
+                                       SET_CC_V(); \
+                               else \
+                                       CLR_CC_V()
+
+#define CHG_CC_VC( d1, d2, d3 ) \
+                               if ((( d1 & SIGN ) != ( d2 & SIGN )) \
+                               && (( d2 & SIGN ) == ( d3 & SIGN ))) \
+                                       SET_CC_V(); \
+                               else \
+                                       CLR_CC_V()
+
+#define CHG_CC_VS( d1, d2, d3 ) \
+                               if ((( d1 & SIGN ) != ( d2 & SIGN )) \
+                               && (( d1 & SIGN ) == ( d3 & SIGN ))) \
+                                       SET_CC_V(); \
+                               else \
+                                       CLR_CC_V()
+
+#define CHGB_CC_V( d1, d2, d3 ) \
+                               if ((( d1 & SIGN_B ) == ( d2 & SIGN_B )) \
+                               && (( d1 & SIGN_B ) != ( d3 & SIGN_B ))) \
+                                       SET_CC_V(); \
+                               else \
+                                       CLR_CC_V()
+
+#define CHGB_CC_VC(d1,d2,d3)   \
+                               if ((( d1 & SIGN_B ) != ( d2 & SIGN_B )) \
+                               && (( d2 & SIGN_B ) == ( d3 & SIGN_B ))) \
+                                       SET_CC_V(); \
+                               else \
+                                       CLR_CC_V()
+
+#define CHG_CC_V_XOR_C_N()     \
+                               if ((( CC_C ) && \
+                                  ( CC_N )) \
+                               || ((!( CC_C )) && \
+                                  ( ! ( CC_N )))) \
+                                       CLR_CC_V(); \
+                               else \
+                                       SET_CC_V()
+
+
+/* Macros to read and write loctions in
+ * main memory.
+ */
+
+extern u_int16_t *adptr;
+
+#define copylong(to,from) \
+       buf = (char *) &(to); buf2 = (char *) &(from); \
+       buf[0]=buf2[2]; buf[1]=buf2[3]; buf[2]=buf2[0]; buf[3]=buf2[1]
+
+#ifndef EMUV1
+/* lli_word() - Load a word from the given ispace logical address. */
+#define lli_word(addr, word) \
+       { adptr= (u_int16_t *)&(ispace[addr]); word= *adptr; }
+
+/* ll_word() - Load a word from the given logical address. */
+#define ll_word(addr, word) \
+       { adptr= (u_int16_t *)&(dspace[addr]); word= *adptr; }
+
+/* sl_word() - Store a word at the given logical address. */
+#ifdef WRITEBASE
+#define sl_word(addr, word) \
+       { if ((u_int16_t)addr < dwrite_base) seg_fault(); \
+         adptr= (u_int16_t *)&(dspace[addr]); *adptr= word; }
+#else
+#define sl_word(addr, word) \
+       { adptr= (u_int16_t *)&(dspace[addr]); *adptr= word; }
+#endif
+
+/* lli_byte() - Load a byte from the given logical ispace address. */
+#define lli_byte(addr, byte) \
+    byte = ispace[addr];
+
+/* ll_byte() - Load a byte from the given logical address. */
+#define ll_byte(addr, byte) \
+    byte = dspace[addr];
+
+/* sl_byte() - Store a byte at the given logical address. */
+#ifdef WRITEBASE
+#define sl_byte(addr, byte) \
+       { if (addr < dwrite_base) seg_fault(); \
+         dspace[addr]= byte; }
+#else
+#define sl_byte(addr, byte) \
+       { dspace[addr]= byte; }
+#endif
+#else
+                               /* These versions of the macros are required */
+                               /* because the KE11-A module is mapped into */
+                               /* a process' memory space in 1st Edition */
+#define KE11LO 0177300
+#define KE11HI 0177317
+
+/* lli_word() - Load a word from the given ispace logical address. */
+#define lli_word(addr, word) \
+       { if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               word= kell_word(addr);                                  \
+         } else { adptr= (u_int16_t *)&(ispace[addr]); word= *adptr; } \
+       }
+
+/* ll_word() - Load a word from the given logical address. */
+#define ll_word(addr, word) \
+       { if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               word= kell_word(addr);                                  \
+         } else { adptr= (u_int16_t *)&(dspace[addr]); word= *adptr; } \
+       }
+
+/* sl_word() - Store a word at the given logical address. */
+#ifdef WRITEBASE
+#define sl_word(addr, word) \
+       { if ((u_int16_t)addr < dwrite_base) seg_fault(); \
+         if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               kesl_word(addr, word);                                  \
+         } else { adptr= (u_int16_t *)&(dspace[addr]); *adptr= word; } \
+       }
+#else
+#define sl_word(addr, word) \
+       { if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               kesl_word(addr, word);                                  \
+         } else { adptr= (u_int16_t *)&(dspace[addr]); *adptr= word; } \
+       }
+#endif
+
+/* lli_byte() - Load a byte from the given logical ispace address. */
+#define lli_byte(addr, byte) \
+    byte = ispace[addr];
+
+/* ll_byte() - Load a byte from the given logical address. */
+#define ll_byte(addr, byte) \
+       { if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               byte= kell_byte(addr);                                  \
+         } else byte = dspace[addr];                                   \
+       }
+
+/* sl_byte() - Store a byte at the given logical address. */
+#ifdef WRITEBASE
+#define sl_byte(addr, byte) \
+       { if (addr < dwrite_base) seg_fault(); \
+         if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               kesl_byte(addr, byte);                                  \
+         } else dspace[addr]= byte;                                    \
+       }
+#else
+#define sl_byte(addr, byte) \
+       { if ((Binary<IS_V3) && (addr>=KE11LO) && (addr<=KE11HI)) {     \
+               kesl_byte(addr, byte);                                  \
+         } else dspace[addr]= byte;                                    \
+       }
+#endif
+#endif
+                               
+
+
+
+/* Function prototypes */
+
+/* aout.c */
+int load_a_out P((const char *file, const char *origpath, int want_env))
+                                       /*@globals errno,stdout,stderr; @*/ ;
+#ifdef EMU211
+void do_bsd_overlay P((void));
+#endif
+
+/* branch.c */
+void br P((void));
+void blos P((void));
+void bge P((void));
+void blt P((void));
+void ble P((void));
+void bgt P((void));
+void jmp P((void));
+void jsr P((void));
+void rts P((void));
+void bne P((void));
+void beq P((void));
+void bpl P((void));
+void bmi P((void));
+void bhi P((void));
+void bvc P((void));
+void bvs P((void));
+void bcc P((void));
+void bcs P((void));
+void scc P((void));
+void ccc P((void));
+void sob P((void));
+void mfps P((void));
+void mtps P((void));
+void mfpi P((void));
+void mtpi P((void));
+void ash P((void));
+void mul P((void));
+void divide P((void));
+void ashc P((void));
+void xor P((void));
+
+/* double.c */
+void mov P((void));
+void movsreg P((void));
+void movsreg1 P((void));
+void movsreg1pc P((void));
+void cmp P((void));
+void add P((void));
+void sub P((void));
+void bit P((void));
+void bic P((void));
+void bis P((void));
+void movb P((void));
+void cmpb P((void));
+void bitb P((void));
+void bicb P((void));
+void bisb P((void));
+
+/* cpu.c */
+void run P((void));
+void sim_init P((void));
+void bus_error P((int));
+void seg_fault P((void));
+void waiti P((void));
+void halt P((void));
+void iot P((void));
+void emt P((void));
+void bpt P((void));
+void fis P((void));
+void illegal P((void));
+void not_impl P((void));
+void mark P((void));
+void mfpd P((void));
+void mtpd P((void));
+void trap P((void));
+void bad_FP_reg P((void));
+void sigcatcher P((int sig));
+
+/* ea.c */
+void load_ea P((void));
+void pop P((void));
+void push P((void));
+void loadb_dst P((void));
+void loadb_src P((void));
+void storeb_dst P((void));
+void storeb_dst_2 P((void));
+void loadp_dst P((void));
+void storep_dst P((void));
+void load_src P((void));
+void store_dst P((void));
+void load_dst P((void));
+void store_dst_2 P((void));
+
+/* fp.c */
+void fpset P((void));
+void ldf P((void));
+void stf P((void));
+void clrf P((void));
+void addf P((void));
+void subf P((void));
+void negf P((void));
+void absf P((void));
+void mulf P((void));
+void moddf P((void));
+void divf P((void));
+void cmpf P((void));
+void tstf P((void));
+void ldfps P((void));
+void stfps P((void));
+void lcdif P((void));
+void stcfi P((void));
+void stexp P((void));
+void stcdf P((void));
+void ldcdf P((void));
+void stst P((void));
+void ldexpp P((void));
+
+/* itab.c */
+void dositab0 P((void));
+void dositab1 P((void));
+
+/* main.c */
+int main P((int argc, char **argv));
+void usage P((void));
+char * xlate_filename P((char *name));
+void set_apout_root P((char *dirname));
+
+/* magic.c */
+int special_magic P((u_int16_t *cptr));
+
+/* single.c */
+void adc P((void));
+void asl P((void));
+void asr P((void));
+void clr P((void));
+void com P((void));
+void dec P((void));
+void inc P((void));
+void neg P((void));
+void rol P((void));
+void ror P((void));
+void sbc P((void));
+void swabi P((void));
+void sxt P((void));
+void tst P((void));
+void tstb P((void));
+void aslb P((void));
+void asrb P((void));
+void clrb P((void));
+void comb P((void));
+void decb P((void));
+void incb P((void));
+void negb P((void));
+void rolb P((void));
+void rorb P((void));
+void adcb P((void));
+void sbcb P((void));
+
+/* v6trap.c */
+void v6trap P((void));
+
+/* v7trap.c */
+void v7trap P((void));
+
+/* v1trap.c */
+void v1trap P((void));
+
+/* bsdtrap.c */
+#ifdef EMU211
+void bsdtrap P((void))                 /*@globals errno,stdout,stderr; @*/ ;
+
+/* bsd_ioctl.h */
+int trap_ioctl P((void));
+
+/* bsd_signal.c */
+void set_bsdsig_dfl P((void));
+int do_sigaction P((int sig, int a, int oa));
+#endif
+
+/* ke11a.c */
+#ifdef EMUV1
+int16_t kell_word P((u_int16_t addr));
+void kesl_word P((u_int16_t addr, u_int16_t word));
+int8_t kell_byte P((u_int16_t addr));
+void kesl_byte P((u_int16_t addr, u_int8_t byte));
+void set_SR P((void));
+#endif
+
+#undef P
diff --git a/double.c b/double.c
new file mode 100644 (file)
index 0000000..4650406
--- /dev/null
+++ b/double.c
@@ -0,0 +1,280 @@
+/* double.c - Double operand instructions.
+ *
+ * $Revision: 2.11 $
+ * $Date: 1999/12/27 10:19:40 $
+ */
+#include "defines.h"
+
+static u_int32_t templong;
+
+
+/* mov() - Move Instruction.  Move operations with registers as the source
+ * and/or destination have been inlined. */
+void
+mov()
+{
+
+    if (SRC_MODE) {
+       load_src(); dstword=srcword;
+    } else {
+       dstword = regs[SRC_REG];
+    }
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+
+    if (DST_MODE) {
+       store_dst();
+    } else {
+       regs[DST_REG] = dstword;
+    }
+}
+
+/* movsreg(), movsreg1() and movsreg1pc() can all be replaced with
+ * mov() above. I've broken them out in an attempt to improve
+ * performance.
+ */
+void
+movsreg()
+{
+    dstword = regs[SRC_REG];
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+
+    if (DST_MODE) {
+       store_dst();
+    } else {
+       regs[DST_REG] = dstword;
+    }
+}
+
+void
+movsreg1()
+{
+    ll_word(regs[SRC_REG], dstword);
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+
+    if (DST_MODE) {
+       store_dst();
+    } else {
+       regs[DST_REG] = dstword;
+    }
+}
+
+void
+movsreg1pc()
+{
+    lli_word(regs[PC], dstword)
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+
+    if (DST_MODE) {
+       store_dst();
+    } else {
+       regs[DST_REG] = dstword;
+    }
+}
+
+
+
+/* cmp() - Compare Instruction. */
+void
+cmp()
+{
+    load_src();
+    load_dst();
+
+    tmpword = ~dstword;
+    templong = ((u_int32_t) srcword) + ((u_int32_t) (tmpword)) + 1;
+    tmpword = LOW16(templong);
+
+    CHG_CC_N(tmpword);
+    CHG_CC_Z(tmpword);
+    CHG_CC_VC(srcword, dstword, tmpword);      /* was CHG_CC_V */
+    CHG_CC_IC(templong);
+}
+
+
+/* add() - Add Instruction. */
+void
+add()
+{
+    load_src();
+    load_dst();
+
+    templong = ((u_int32_t) srcword) + ((u_int32_t) dstword);
+    tmpword = LOW16(templong);
+
+    CHG_CC_N(tmpword);
+    CHG_CC_Z(tmpword);
+    CHG_CC_V(srcword, dstword, tmpword);
+    CHG_CC_C(templong);
+
+    dstword=tmpword; store_dst_2();
+}
+
+/* Subtract Instruction. */
+void
+sub()
+{
+    load_src();
+    load_dst();
+
+    tmpword = ~srcword;
+    templong = ((u_int32_t) dstword) + ((u_int32_t) tmpword) + 1;
+    tmpword = LOW16(templong);
+
+    CHG_CC_N(tmpword);
+    CHG_CC_Z(tmpword);
+    CHG_CC_VS(srcword, dstword, tmpword);      /* was CHG_CC_V */
+    CHG_CC_IC(templong);
+
+    dstword=tmpword; store_dst_2();
+}
+
+
+/* bit() - Bit Test Instruction. */
+void
+bit()
+{
+    load_src();
+    load_dst();
+
+    dstword = srcword & dstword;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+}
+
+/* bic() - Bit Clear Instruction. */
+void
+bic()
+{
+    load_src();
+    load_dst();
+
+    dstword = (~srcword) & dstword;
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+
+    store_dst_2();
+}
+
+
+/* bis() - Bit Set Instruction. */
+void
+bis()
+{
+    load_src();
+    load_dst();
+
+    dstword = srcword | dstword;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+
+    store_dst_2();
+}
+
+/* movb() - Move Byte Instruction.  Move operations with registers as the
+ * source and/or destination have been inlined. */
+void
+movb()
+{
+    if (SRC_MODE) {
+       loadb_src();
+    } else {
+       srcbyte = LOW8(regs[SRC_REG]);
+    }
+
+    CHGB_CC_N(srcbyte);
+    CHGB_CC_Z(srcbyte);
+    CLR_CC_V();
+
+    /* move byte to a register causes sign extension */
+
+    if (DST_MODE) {
+       storeb_dst();
+    } else {
+       if (srcbyte & SIGN_B)
+           regs[DST_REG] = (u_int16_t)0177400 + (u_int16_t)srcbyte;
+       else
+           regs[DST_REG] = (u_int16_t)srcbyte;
+    }
+}
+
+/* cmpb() - Compare Byte Instruction. */
+void
+cmpb()
+{
+    u_int8_t data3;
+
+    loadb_src();
+    loadb_dst();
+
+    data3 = (u_int8_t)~dstbyte;
+    tmpword = ((u_int16_t) srcbyte) + ((u_int16_t) (data3)) + 1;
+    data3 = LOW8(tmpword);
+
+    CHGB_CC_N(data3);
+    CHGB_CC_Z(data3);
+    CHGB_CC_VC(srcbyte, dstbyte, data3);
+    CHGB_CC_IC(tmpword);
+}
+
+
+/* bitb() - Bit Test Byte Instruction. */
+void
+bitb()
+{
+    loadb_src();
+    loadb_dst();
+
+    dstbyte = srcbyte & dstbyte;
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CLR_CC_V();
+}
+
+/* bicb() - Bit Clear Byte Instruction. */
+void
+bicb()
+{
+    loadb_src();
+    loadb_dst();
+
+    dstbyte = (u_int8_t)((~srcbyte) & dstbyte);
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CLR_CC_V();
+
+    storeb_dst_2();
+}
+
+
+/* bisb() - Bit Set Byte Instruction. */
+
+void
+bisb()
+{
+    loadb_src();
+    loadb_dst();
+
+    dstbyte = srcbyte | dstbyte;
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CLR_CC_V();
+
+    storeb_dst_2();
+}
diff --git a/ea.c b/ea.c
new file mode 100644 (file)
index 0000000..31c9587
--- /dev/null
+++ b/ea.c
@@ -0,0 +1,588 @@
+/* ea.c - Calculate, load, and store using the proper effective address as
+ * specified by the current instruction.  Also push and pop stack operations.
+ *
+ * $Revision: 2.17 $
+ * $Date: 1999/09/17 05:11:10 $
+ */
+#include "defines.h"
+
+void 
+load_ea(void)
+{
+    u_int16_t indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       illegal();
+       return;
+    case 1:
+       dstword = regs[DST_REG];
+       return;
+    case 2:
+       dstword = regs[DST_REG];        /* this is wrong for 11/34 */
+       regs[DST_REG] += 2;
+       return;
+    case 3:
+       indirect = regs[DST_REG];       /* this is wrong for 11/34 */
+       regs[DST_REG] += 2;
+       lli_word(indirect, dstword);
+       return;
+    case 4:
+       regs[DST_REG] -= 2;
+       dstword = regs[DST_REG];
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       lli_word(indirect, dstword);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       dstword = regs[DST_REG] + indirect;
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+           ll_word(indirect, dstword);
+       return;
+    }
+    illegal();
+}
+
+
+INLINE void 
+pop(void)
+{
+    ll_word(regs[SP], dstword);
+    regs[SP] += 2;
+}
+
+
+INLINE void 
+push(void)
+{
+    regs[SP] -= 2;
+    sl_word(regs[SP], srcword);
+}
+
+
+void 
+loadb_dst(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       dstbyte = (u_int8_t)(regs[DST_REG] & 0377);
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       ea_addr = addr;
+       if (DST_REG == PC) {
+           lli_byte(addr, dstbyte)
+       } else {
+           ll_byte(addr, dstbyte);
+       }
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       ea_addr = addr;
+       if (DST_REG == PC) {
+           lli_byte(addr, dstbyte)
+       } else {
+           ll_byte(addr, dstbyte);
+       }
+       if (DST_REG >= 6)
+           regs[DST_REG] += 2;
+       else
+           regs[DST_REG] += 1;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       if (DST_REG == PC) {
+           lli_word(indirect, addr)
+       } else {
+           ll_word(indirect, addr);
+       }
+       ea_addr = addr;
+       ll_byte(addr, dstbyte);
+       regs[DST_REG] += 2;
+       return;
+    case 4:
+       if (DST_REG >= 6)
+           regs[DST_REG] -= 2;
+       else
+           regs[DST_REG] -= 1;
+       addr = regs[DST_REG];
+       ea_addr = addr;
+       ll_byte(addr, dstbyte);
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       ea_addr = addr;
+       ll_byte(addr, dstbyte);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       ea_addr = addr;
+       ll_byte(addr, dstbyte);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+           ll_word(indirect, addr);
+       ea_addr = addr;
+       ll_byte(addr, dstbyte);
+       return;
+    }
+    illegal();
+}
+
+
+void 
+loadb_src(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (SRC_MODE) {
+    case 0:
+       srcbyte = (u_int8_t)(regs[SRC_REG] & 0377);
+       return;
+    case 1:
+       addr = regs[SRC_REG];
+       if (SRC_REG == PC) {
+           lli_byte(addr, srcbyte);
+       } else {
+           ll_byte(addr, srcbyte);
+       }
+       return;
+    case 2:
+       addr = regs[SRC_REG];
+       if (SRC_REG == PC) {
+           lli_byte(addr, srcbyte);
+       } else {
+           ll_byte(addr, srcbyte);
+       }
+       if (SRC_REG >= 6)
+           regs[SRC_REG] += 2;
+       else
+           regs[SRC_REG] += 1;
+       return;
+    case 3:
+       indirect = regs[SRC_REG];
+       if (SRC_REG == PC) {
+           lli_word(indirect, addr)
+       } else {
+           ll_word(indirect, addr);
+       }
+       ll_byte(addr, srcbyte);
+       regs[SRC_REG] += 2;
+       return;
+    case 4:
+       if (SRC_REG >= 6)
+           regs[SRC_REG] -= 2;
+       else
+           regs[SRC_REG] -= 1;
+       addr = regs[SRC_REG];
+       ll_byte(addr, srcbyte);
+       return;
+    case 5:
+       regs[SRC_REG] -= 2;
+       indirect = regs[SRC_REG];
+       ll_word(indirect, addr);
+       ll_byte(addr, srcbyte);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[SRC_REG] + indirect;
+       ll_byte(addr, srcbyte);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[SRC_REG] + indirect;
+           ll_word(indirect, addr);
+       ll_byte(addr, srcbyte);
+       return;
+    }
+    illegal();
+}
+
+void 
+storeb_dst(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       regs[DST_REG]&= 0xff00;
+       regs[DST_REG]|= srcbyte;
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       sl_byte(addr, srcbyte);
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       sl_byte(addr, srcbyte);
+       if (DST_REG >= 6)
+           regs[DST_REG] += 2;
+       else
+           regs[DST_REG] += 1;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       sl_byte(addr, srcbyte);
+       regs[DST_REG] += 2;
+       return;
+    case 4:
+       if (DST_REG >= 6)               /* xyz */
+           regs[DST_REG] -= 2;
+       else
+           regs[DST_REG] -= 1;
+       addr = regs[DST_REG];
+       sl_byte(addr, srcbyte);
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       sl_byte(addr, srcbyte);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       sl_byte(addr, srcbyte);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+           ll_word(indirect, addr);
+       sl_byte(addr, srcbyte);
+       return;
+    }
+    illegal();
+}
+
+
+INLINE void 
+storeb_dst_2(void)
+{
+    if (DST_MODE == 0) {
+       regs[DST_REG]&= 0xff00;
+       regs[DST_REG]|= dstbyte;
+       return;
+    }
+    sl_byte(ea_addr, dstbyte);
+}
+
+
+void 
+loadp_dst(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       srcword = regs[DST_REG];
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       ll_word(addr, srcword);
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       ll_word(addr, srcword);
+       regs[DST_REG] += 2;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       ll_word(addr, srcword);
+       regs[DST_REG] += 2;
+       return;
+    case 4:
+       regs[DST_REG] -= 2;
+       addr = regs[DST_REG];
+       ll_word(addr, srcword);
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       ll_word(addr, srcword);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       if (DST_REG == PC)
+           lli_word(addr, srcword)
+       else
+           ll_word(addr, srcword);
+       return;
+    case 7:
+       not_impl();
+    }
+    illegal();
+}
+
+
+void 
+storep_dst(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       regs[DST_REG] = dstword;
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       sl_word(addr, dstword);
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       sl_word(addr, dstword);
+       regs[DST_REG] += 2;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       sl_word(addr, dstword);
+       regs[DST_REG] += 2;
+       return;
+    case 4:
+       regs[DST_REG] -= 2;
+       addr = regs[DST_REG];
+       sl_word(addr, dstword);
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       sl_word(addr, dstword);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       sl_word(addr, dstword);
+       return;
+    case 7:
+       not_impl();
+    }
+    illegal();
+}
+
+
+void 
+load_src(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (SRC_MODE) {
+    case 0:
+       srcword = regs[SRC_REG];
+       return;
+    case 1:
+       addr = regs[SRC_REG];
+       if (SRC_REG == PC) {
+           lli_word(addr, srcword)
+       } else {
+           ll_word(addr, srcword);
+       }
+       return;
+    case 2:
+       addr = regs[SRC_REG];
+       if (SRC_REG == PC) {
+           lli_word(addr, srcword)
+       } else {
+           ll_word(addr, srcword);
+       }
+       regs[SRC_REG] += 2;
+       return;
+    case 3:
+       indirect = regs[SRC_REG];
+       if (SRC_REG == PC) {
+           lli_word(indirect, addr)
+       } else {
+           ll_word(indirect, addr);
+       }
+       regs[SRC_REG] += 2;     /* is this right ? */
+       ll_word(addr, srcword);
+       return;
+    case 4:
+       regs[SRC_REG] -= 2;
+       addr = regs[SRC_REG];
+       ll_word(addr, srcword);
+       return;
+    case 5:
+       regs[SRC_REG] -= 2;
+       indirect = regs[SRC_REG];
+       ll_word(indirect, addr);
+       ll_word(addr, srcword);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[SRC_REG] + indirect;
+       ll_word(addr, srcword);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[SRC_REG] + indirect;
+           ll_word(indirect, addr);
+       ll_word(addr, srcword);
+       return;
+    }
+    illegal();
+}
+
+
+void 
+store_dst(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       regs[DST_REG] = dstword;
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       sl_word(addr, dstword);
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       sl_word(addr, dstword);
+       regs[DST_REG] += 2;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       regs[DST_REG] += 2;     /* is this right ? */
+       sl_word(addr, dstword);
+       return;
+    case 4:
+       regs[DST_REG] -= 2;
+       addr = regs[DST_REG];
+       sl_word(addr, dstword);
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       sl_word(addr, dstword);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       sl_word(addr, dstword);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+           ll_word(indirect, addr);
+       sl_word(addr, dstword);
+       return;
+    }
+    illegal();
+}
+
+
+void 
+load_dst(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       dstword = regs[DST_REG];
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       ea_addr = addr;
+       if (DST_REG == PC) {
+           lli_word(addr, dstword)
+       } else {
+           ll_word(addr, dstword);
+       }
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       ea_addr = addr;
+       if (DST_REG == PC) {
+           lli_word(addr, dstword)
+       } else {
+           ll_word(addr, dstword);
+       }
+       regs[DST_REG] += 2;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       if (DST_REG == PC) {
+           lli_word(indirect, addr)
+       } else {
+           ll_word(indirect, addr);
+       }
+       ea_addr = addr;
+       ll_word(addr, dstword);
+       regs[DST_REG] += 2;
+       return;
+    case 4:
+       regs[DST_REG] -= 2;
+       addr = regs[DST_REG];
+       ea_addr = addr;
+       ll_word(addr, dstword);
+       return;
+    case 5:
+       regs[DST_REG] -= 2;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       ea_addr = addr;
+       ll_word(addr, dstword);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       ea_addr = addr;
+       ll_word(addr, dstword);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+           ll_word(indirect, addr);
+       ea_addr = addr;
+       ll_word(addr, dstword);
+       return;
+    }
+    illegal();
+}
+
+
+INLINE void 
+store_dst_2(void)
+{
+    if (DST_MODE == 0) {
+       regs[DST_REG] = dstword;
+       return;
+    }
+    sl_word(ea_addr, dstword);
+}
diff --git a/fp.c b/fp.c
new file mode 100644 (file)
index 0000000..b3bc85d
--- /dev/null
+++ b/fp.c
@@ -0,0 +1,616 @@
+/* fp.c - PDP-11 floating point operations
+ *
+ * $Revision: 2.23 $
+ * $Date: 1999/12/30 02:11:16 $
+ */
+
+/* The floating-point emulation code here is just enough to allow
+ * 2.11BSD binaries to run. There is only emulation of PDP-11
+ * 32-bit floats: the extra 32-bits of precision in PDP-11 doubles
+ * goes unused. As well, I don't try to emulate any of the FP errors.
+ *
+ * If this is a problem, then feel free to correct it.
+ */
+#include "defines.h"
+#include <math.h>
+float powf(float x, float y);  /* FreeBSD 3.X no longer defines this */
+
+#define XUL    170141163178059628080016879768632819712.0 /* Biggest float */
+
+typedef struct {
+   unsigned frac1:7;   /* Fractional part of number */
+   unsigned exp:  8;   /* Excess 128 notation: exponenents -128 to +127 */
+                       /* become 0 to 255 */
+   unsigned sign: 1;   /* If 1, float is negative */
+   unsigned frac2: 16; /* Fractional part of number */
+} pdpfloat;
+
+
+/* Internal variables */
+FLOAT  fregs[8];       /* Yes, I know there are only 6, it makes it easier */
+int FPC=0;             /* Status flags */
+int FPZ=0;
+int FPN=0;
+int FPV=0;
+int FPMODE=0;          /* 0 = float, 1 = doubles */
+int INTMODE=0;         /* 0 = integers, 1 = longs */
+
+/* Temporary variables */
+FLOAT Srcflt;          /* Float specified by FSRC field */
+pdpfloat *fladdr;      /* Address of float  in dspace */
+int   AC;              /* Accumulator field in ir */
+int32_t srclong;       /* Longword from source address */
+int32_t dstlong;       /* Longword for destination address */
+static char *buf, *buf2; /* for copylong */
+
+
+
+
+/* Convert from PDP-11 float representation to native representation */
+static void from11float(FLOAT *out, pdpfloat *in)
+{
+ int32_t  exponent;
+ u_int32_t fraction;
+ FLOAT z;
+
+ exponent= in->exp - 128 - 24; /* 24 so as to shift the radix point left */
+                                   /* Add in the missing significant bit */
+ fraction= (in->frac1 << 16) + in->frac2 + 8388608;
+
+ z= powf(2.0, (float)exponent);
+ *out= (float)fraction * z;
+ if (in->sign) *out= -(*out);
+ FpDebug((dbg_file, "\t0%o from11float out is %f\n",regs[7], *out));
+}
+
+/* Convert from native representation to PDP-11 float representation */
+static void to11float(FLOAT *in, pdpfloat *out)
+{
+  int32_t  exponent=129;
+  u_int32_t fraction;
+  FLOAT infloat= *in;
+
+  FpDebug((dbg_file, "\t0%o to11float in is %f\n",regs[7], infloat));
+  if (infloat < 0.0) { out->sign=1; infloat= -infloat; } 
+  else out->sign=0;
+
+  if (infloat==0.0) { out->frac1=0; out->frac2=0; out->exp=0; return; }
+
+  /* We want the float's fraction to start with 1.0 (in binary) */
+  /* Therefore it must be < 2.0 and >= 1.0 */
+  while (infloat >= 2.0) { infloat *= 0.5; exponent++; }
+  while (infloat < 1.0)         { infloat *= 2.0; exponent--; }
+
+  infloat= infloat - 1.0;              /* Remove significant bit */
+  fraction= (int)(infloat * 8388608.0); /* Multiply fraction by 2^24 */
+  out->frac2= fraction & 0xffff;
+  out->frac1= (fraction>>16);
+  out->exp= exponent;
+}
+
+static struct { u_int16_t lo; u_int16_t hi; } intpair;
+/* Load (and convert if necessary) the float described by the source */
+/* address into Srcflt. */
+static void 
+load_flt(void)
+{
+    u_int16_t indirect,addr;
+    u_int16_t *intptr;
+
+    FpDebug((dbg_file, "\tload_flt mode %d\n", DST_MODE));
+    switch (DST_MODE) {
+    case 0:
+       Srcflt = fregs[DST_REG];
+       fladdr=NULL; return;
+    case 1:
+       if (DST_REG == PC) {
+           intptr = (u_int16_t *)&ispace[regs[DST_REG]];
+           intpair.lo= *intptr;
+           intpair.hi=0;
+           fladdr= (pdpfloat *)&intpair;
+       } else fladdr = (pdpfloat *)&dspace[regs[DST_REG]];
+       from11float(&Srcflt, fladdr);
+       return;
+    case 2:
+       if (DST_REG == PC) {
+           intptr = (u_int16_t *)&ispace[regs[DST_REG]];
+           intpair.lo= *intptr;
+           intpair.hi=0;
+           fladdr= (pdpfloat *)&intpair;
+           from11float(&Srcflt, fladdr);
+           regs[DST_REG] += 2;
+       } else {
+           fladdr = (pdpfloat *)&dspace[regs[DST_REG]];
+           from11float(&Srcflt, fladdr);
+           if (FPMODE) regs[DST_REG] += 8;
+           else regs[DST_REG] += 4;
+       }
+       return;
+    case 3:
+       ll_word(regs[DST_REG], indirect);
+       if (DST_REG == PC) {
+           intptr = (u_int16_t *)&ispace[indirect];
+           intpair.lo= *intptr;
+           intpair.hi=0;
+           fladdr= (pdpfloat *)&intpair;
+           from11float(&Srcflt, fladdr);
+           regs[DST_REG] += 2;
+       } else {
+           fladdr = (pdpfloat *)&dspace[indirect];
+           from11float(&Srcflt, fladdr);
+           if (FPMODE) regs[DST_REG] += 8;
+           else regs[DST_REG] += 4;
+       }
+       return;
+    case 4:
+       if (FPMODE) regs[DST_REG] -= 8;
+       else regs[DST_REG] -= 4;
+       fladdr = (pdpfloat *)&dspace[regs[DST_REG]];
+       from11float(&Srcflt, fladdr);
+       return;
+    case 5:
+       if (FPMODE) regs[DST_REG] -= 8;
+       else regs[DST_REG] -= 4;
+       ll_word(regs[DST_REG], indirect);
+       fladdr = (pdpfloat *)&dspace[indirect];
+       from11float(&Srcflt, fladdr);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect= regs[DST_REG] + indirect;
+       fladdr = (pdpfloat *)&dspace[indirect];
+       from11float(&Srcflt, fladdr);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+       ll_word(indirect, addr);
+       fladdr = (pdpfloat *)&dspace[addr];
+       from11float(&Srcflt, fladdr);
+       return;
+    }
+    illegal();
+}
+
+/* Save (and convert if necessary) Srcflt into the float described by the
+ * destination address */
+static void 
+save_flt(void)
+{
+    u_int16_t indirect;
+    u_int16_t addr;
+    pdpfloat *fladdr;
+
+    FpDebug((dbg_file, "\tsave_flt mode %d\n", DST_MODE));
+    switch (DST_MODE) {
+    case 0:
+       fregs[DST_REG] = Srcflt;
+       return;
+    case 1:
+       fladdr = (pdpfloat *)&dspace[regs[DST_REG]];
+       to11float(&Srcflt, fladdr);
+       return;
+    case 2:
+       fladdr = (pdpfloat *)&dspace[regs[DST_REG]];
+       to11float(&Srcflt, fladdr);
+       if (DST_REG == PC) regs[DST_REG] += 2;
+       else if (FPMODE) regs[DST_REG] += 8;
+       else regs[DST_REG] += 4;
+       return;
+    case 3:
+       ll_word(regs[DST_REG], indirect);
+       fladdr = (pdpfloat *)&dspace[indirect];
+       to11float(&Srcflt, fladdr);
+       if (DST_REG == PC) regs[DST_REG] += 2;
+       else if (FPMODE) regs[DST_REG] += 8;
+       else regs[DST_REG] += 4;
+       return;
+    case 4:
+       if (FPMODE) regs[DST_REG] -= 8;
+       else regs[DST_REG] -= 4;
+       fladdr = (pdpfloat *)&dspace[regs[DST_REG]];
+       to11float(&Srcflt, fladdr);
+       return;
+    case 5:
+       if (FPMODE) regs[DST_REG] -= 8;
+       else regs[DST_REG] -= 4;
+       ll_word(regs[DST_REG], indirect);
+       fladdr = (pdpfloat *)&dspace[indirect];
+       to11float(&Srcflt, fladdr);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+       fladdr = (pdpfloat *)&dspace[indirect];
+       to11float(&Srcflt, fladdr);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+       ll_word(indirect, addr);
+       fladdr = (pdpfloat *)&dspace[addr];
+       to11float(&Srcflt, fladdr);
+       return;
+    }
+    illegal();
+}
+
+/* lli_long() - Load a long from the given ispace logical address. */
+#define lli_long(addr, word) \
+       { adptr= (u_int16_t *)&(ispace[addr]); copylong(word, *adptr); } \
+
+/* ll_long() - Load a long from the given logical address. */
+#define ll_long(addr, word) \
+       { adptr= (u_int16_t *)&(dspace[addr]); copylong(word, *adptr); } \
+
+/* sl_long() - Store a long from the given logical address. */
+#define sl_long(addr, word) \
+       { adptr= (u_int16_t *)&(dspace[addr]); copylong(*adptr, word); } \
+
+static void 
+load_long(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       srclong = regs[DST_REG];
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       if (DST_REG == PC) {
+           lli_long(addr, srclong)
+       } else {
+           ll_long(addr, srclong);
+       }
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       if (DST_REG == PC) {
+           lli_long(addr, srclong)
+       } else {
+           ll_long(addr, srclong);
+       }
+       regs[DST_REG] += 4;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       if (DST_REG == PC) {
+           lli_word(indirect, addr)
+       } else {
+           ll_word(indirect, addr);
+       }
+       regs[DST_REG] += 4;
+       ll_long(addr, srclong);
+       return;
+    case 4:
+       regs[DST_REG] -= 4;
+       addr = regs[DST_REG];
+       ll_long(addr, srclong);
+       return;
+    case 5:
+       regs[DST_REG] -= 4;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       ll_long(addr, srclong);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       ll_long(addr, srclong);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+           ll_word(indirect, addr);
+       ll_long(addr, srclong);
+       return;
+    }
+    illegal();
+}
+
+
+static void 
+store_long(void)
+{
+    u_int16_t addr, indirect;
+
+    switch (DST_MODE) {
+    case 0:
+       regs[DST_REG]= dstlong;
+       return;
+    case 1:
+       addr = regs[DST_REG];
+       sl_long(addr, dstlong)
+       return;
+    case 2:
+       addr = regs[DST_REG];
+       sl_long(addr, dstlong)
+       regs[DST_REG] += 4;
+       return;
+    case 3:
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       regs[DST_REG] += 4;
+       sl_long(addr, dstlong);
+       return;
+    case 4:
+       regs[DST_REG] -= 4;
+       addr = regs[DST_REG];
+       sl_long(addr, dstlong);
+       return;
+    case 5:
+       regs[DST_REG] -= 4;
+       indirect = regs[DST_REG];
+       ll_word(indirect, addr);
+       sl_long(addr, dstlong);
+       return;
+    case 6:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       addr = regs[DST_REG] + indirect;
+       sl_long(addr, dstlong);
+       return;
+    case 7:
+       lli_word(regs[PC], indirect);
+       regs[PC] += 2;
+       indirect = regs[DST_REG] + indirect;
+       ll_word(indirect, addr);
+       sl_long(addr, dstlong);
+       return;
+    }
+    illegal();
+}
+
+
+/* Instruction handlers */
+void
+fpset()
+{
+    switch (ir) {
+       case 0170000:           /* CFCC */
+       CC_C= FPC; CC_V= FPV;
+       CC_Z= FPZ; CC_N= FPN;
+       return;
+    case 0170001:              /* SETF */
+       FPMODE=0; return;
+    case 0170002:              /* SETI */
+       INTMODE=0; return;
+    case 0170011:              /* SETD */
+       FPMODE=1; return;
+    case 0170012:              /* SETL */
+       INTMODE=1; return;
+    default:
+       not_impl();
+    }
+}
+
+void
+ldf()  /* Load float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  fregs[AC]= Srcflt;
+  FPC=0; FPV=0; 
+  if (fregs[AC]==0.0) FPZ=1; else FPZ=0;
+  if (fregs[AC]<0.0)  FPN=1; else FPN=0;
+}
+
+void
+stf()  /* Store float */
+{
+  AC= (ir >> 6) & 3;
+  Srcflt= fregs[AC];
+  save_flt();
+}
+
+
+void
+clrf() /* Store float */
+{
+  AC= (ir >> 6) & 3;
+  Srcflt= 0.0;
+  save_flt();
+  FPC= FPZ= FPV= 0; FPZ=1;
+}
+void
+addf() /* Add float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  fregs[AC]+= Srcflt;
+  FPC=0;
+  if (fregs[AC]>XUL)  FPV=1; else FPV=0;
+  if (fregs[AC]==0.0) FPZ=1; else FPZ=0;
+  if (fregs[AC]<0.0)  FPN=1; else FPN=0;
+}
+
+void
+subf() /* Subtract float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  fregs[AC]-= Srcflt;
+  FPC=0;
+  if (fregs[AC]>XUL)  FPV=1; else FPV=0;
+  if (fregs[AC]==0.0) FPZ=1; else FPZ=0;
+  if (fregs[AC]<0.0)  FPN=1; else FPN=0;
+}
+
+void
+negf() /* Negate float */
+{
+  load_flt();
+  fladdr->sign= -(fladdr->sign);
+  FPC=0; FPV=0; 
+  if (Srcflt==0.0) FPZ=1; else FPZ=0;
+  if (Srcflt<0.0)  FPN=1; else FPN=0;
+}
+
+
+void
+absf() /* Absolute float */
+{
+  load_flt();
+  fladdr->sign= 0;
+  FPC=0; FPV=0; FPN=0;
+  if (Srcflt==0.0) FPZ=1; else FPZ=0;
+}
+
+void
+mulf() /* Multiply float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  fregs[AC]*= Srcflt;
+  FPC=0;
+  if (fregs[AC]>XUL)  FPV=1; else FPV=0;
+  if (fregs[AC]==0.0) FPZ=1; else FPZ=0;
+  if (fregs[AC]<0.0)  FPN=1; else FPN=0;
+}
+
+
+void
+moddf() /* Multiply and integerise float */
+{
+  FLOAT x,y;
+
+  AC= (ir >> 6) & 3;
+  load_flt();
+  fregs[AC]*= Srcflt; y= fregs[AC];
+  if (y>0.0) x= (FLOAT) floor((double)y);
+  else x= (FLOAT) ceil((double)y);
+  fregs[AC|1]= x;
+
+  y=y-x;  fregs[AC]=y;
+
+  FPC=0;
+  if (fregs[AC]>XUL)  FPV=1; else FPV=0;
+  if (fregs[AC]==0.0) FPZ=1; else FPZ=0;
+  if (fregs[AC]<0.0)  FPN=1; else FPN=0;
+}
+
+void
+divf() /* Divide float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  fregs[AC]/= Srcflt;
+  FPC=0;
+  if (fregs[AC]>XUL)  FPV=1; else FPV=0;
+  if (fregs[AC]==0.0) FPZ=1; else FPZ=0;
+  if (fregs[AC]<0.0)  FPN=1; else FPN=0;
+}
+
+void
+cmpf() /* Compare float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  FPC=0; FPV=0;
+  if (fregs[AC]>Srcflt)         FPN=1; else FPN=0;
+  if (fregs[AC]==Srcflt) FPZ=1; else FPZ=0;
+}
+
+void
+tstf() /* Test float */
+{
+  AC= (ir >> 6) & 3;
+  load_flt();
+  FPC=0; FPV=0;
+  if (Srcflt<0.0)  FPN=1; else FPN=0;
+  if (Srcflt==0.0) FPZ=1; else FPZ=0;
+}
+
+void
+ldfps() /* Load FPP status */
+{
+    load_dst();
+    if (dstword & CC_NBIT) CC_N=1;
+    if (dstword & CC_ZBIT) CC_Z=1;
+    if (dstword & CC_VBIT) CC_V=1;
+    if (dstword & CC_CBIT) CC_C=1;
+}
+
+void
+stfps() /* Store FPP status */
+{
+    srcword=0;
+    if (CC_N) srcword|= CC_NBIT;
+    if (CC_Z) srcword|= CC_ZBIT;
+    if (CC_V) srcword|= CC_VBIT;
+    if (CC_C) srcword|= CC_CBIT;
+    store_dst();
+}
+
+void
+lcdif() /* Convert int to float */
+{
+  AC= (ir >> 6) & 3;
+  if (INTMODE==0) {    /* ints */
+       load_src();
+       fregs[AC]= (float) srcword;
+  } else {
+       load_long();
+       fregs[AC]= (float) srclong;
+  }
+}
+
+void
+stcfi() /* Convert int to float */
+{
+  AC= (ir >> 6) & 3;
+  if (INTMODE==0) {    /* ints */
+       dstword= (int16_t) fregs[AC];
+       store_dst();
+  } else {
+       dstlong= (int32_t) fregs[AC];
+       store_long();
+  }
+}
+
+void
+stexp() /* Store exponent */
+{
+ pdpfloat pdptmp;
+
+ AC= (ir >> 6) & 3;
+ to11float(&fregs[AC], &pdptmp);
+ dstword= pdptmp.exp - 128;
+ store_dst();
+}
+
+void stcdf()
+{
+       /* Switch FPMODE just while we're saving */
+ FPMODE=1 - FPMODE; stf(); FPMODE=1 - FPMODE;
+}
+
+void ldcdf()
+{
+ ldf();
+}
+
+void stst()
+{
+       /* For now */
+}
+
+void ldexpp()
+{
+ pdpfloat pdptmp;
+
+ AC= (ir >> 6) & 3;
+ to11float(&fregs[AC], &pdptmp);
+ load_src();                   /* srcword now holds new exponent */
+ srcword +=128;                        /* Convert to required exponent */
+ srcword &= 0xff;
+ pdptmp.exp= srcword;
+ from11float(&fregs[AC], &pdptmp);
+}
diff --git a/itab.c b/itab.c
new file mode 100644 (file)
index 0000000..1961f5e
--- /dev/null
+++ b/itab.c
@@ -0,0 +1,176 @@
+/* itab.c - Instruction decode table.
+ *
+ * $Revision: 2.12 $
+ * $Date: 1999/12/27 10:19:40 $
+ */
+
+#include "defines.h"
+
+static _itab sitab0[64] = {
+    halt, waiti, illegal, bpt, iot, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal
+};
+
+static _itab sitab1[64] = {
+    rts, rts, rts, rts, rts, rts, rts, rts,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    ccc, ccc, ccc, ccc, ccc, ccc, ccc, ccc,
+    ccc, ccc, ccc, ccc, ccc, ccc, ccc, ccc,
+    scc, scc, scc, scc, scc, scc, scc, scc,
+    scc, scc, scc, scc, scc, scc, scc, scc
+};
+
+void 
+dositab0(void)
+{
+    sitab0[ir & 077] ();
+}
+
+void 
+dositab1(void)
+{
+    sitab1[ir & 077] ();
+}
+
+_itab itab[1024] = {
+    dositab0, jmp, dositab1, swabi, br, br, br, br,
+    bne, bne, bne, bne, beq, beq, beq, beq,
+    bge, bge, bge, bge, blt, blt, blt, blt,
+    bgt, bgt, bgt, bgt, ble, ble, ble, ble,
+    jsr, jsr, jsr, jsr, jsr, jsr, jsr, jsr,
+    clr, com, inc, dec, neg, adc, sbc, tst,
+    ror, rol, asr, asl, mark, mfpi, mtpi, sxt,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    movsreg,movsreg,movsreg,movsreg,movsreg,movsreg,movsreg,movsreg,
+    movsreg1,movsreg1,movsreg1,movsreg1,movsreg1,movsreg1,movsreg1,movsreg1pc,
+    mov, mov, mov, mov, mov, mov, mov, mov,
+    mov, mov, mov, mov, mov, mov, mov, mov,
+    mov, mov, mov, mov, mov, mov, mov, mov,
+    mov, mov, mov, mov, mov, mov, mov, mov,
+    mov, mov, mov, mov, mov, mov, mov, mov,
+    mov, mov, mov, mov, mov, mov, mov, mov,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    cmp, cmp, cmp, cmp, cmp, cmp, cmp, cmp,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bit, bit, bit, bit, bit, bit, bit, bit,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bic, bic, bic, bic, bic, bic, bic, bic,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    bis, bis, bis, bis, bis, bis, bis, bis,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    add, add, add, add, add, add, add, add,
+    mul, mul, mul, mul, mul, mul, mul, mul,
+    divide, divide, divide, divide, divide, divide, divide, divide,
+    ash, ash, ash, ash, ash, ash, ash, ash,
+    ashc, ashc, ashc, ashc, ashc, ashc, ashc, ashc,
+    xor, xor, xor, xor, xor, xor, xor, xor,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    sob, sob, sob, sob, sob, sob, sob, sob,
+    bpl, bpl, bpl, bpl, bmi, bmi, bmi, bmi,
+    bhi, bhi, bhi, bhi, blos, blos, blos, blos,
+    bvc, bvc, bvc, bvc, bvs, bvs, bvs, bvs,
+    bcc, bcc, bcc, bcc, bcs, bcs, bcs, bcs,
+
+                       /* emt  at itab[544] to itab[547] */
+                       /* trap at itab[548] to itab[551] */
+
+    emt, emt, emt, emt, trap, trap, trap, trap,
+    clrb, comb, incb, decb, negb, adcb, sbcb, tstb,
+    rorb, rolb, asrb, aslb, mtps, mfpd, mtpd, mfps,
+    illegal, illegal, illegal, illegal, illegal, illegal, illegal, illegal,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    movb, movb, movb, movb, movb, movb, movb, movb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb, cmpb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bitb, bitb, bitb, bitb, bitb, bitb, bitb, bitb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bicb, bicb, bicb, bicb, bicb, bicb, bicb, bicb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    bisb, bisb, bisb, bisb, bisb, bisb, bisb, bisb,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    sub, sub, sub, sub, sub, sub, sub, sub,
+    fpset, ldfps, stfps, stst, clrf, tstf, absf, negf,
+    mulf, mulf, mulf, mulf, moddf, moddf, moddf, moddf,
+    addf, addf, addf, addf, ldf, ldf, ldf, ldf,
+    subf, subf, subf, subf, cmpf, cmpf, cmpf, cmpf,
+    stf, stf, stf, stf, divf, divf, divf, divf,
+    stexp, stexp, stexp, stexp, stcfi, stcfi, stcfi, stcfi,
+    stcdf, stcdf, stcdf, stcdf, ldexpp, ldexpp, ldexpp, ldexpp,
+    lcdif, lcdif, lcdif, lcdif, ldcdf, ldcdf, ldcdf, ldcdf
+};
diff --git a/ke11a.c b/ke11a.c
new file mode 100644 (file)
index 0000000..d1db07e
--- /dev/null
+++ b/ke11a.c
@@ -0,0 +1,230 @@
+/* ke11a.c - this holds the emulation of the PDP 11/20 extended
+ * arithmetic element. We only need this for 1st Edition a.out support.
+ * Code kindly borrowed from the eae support written by Tim Shoppa
+ * (shoppa@trailing-edge.com) for Bob Supnik's PDP-11 emulator.
+ *
+ * $Revision: 1.7 $
+ * $Date: 1999/12/28 03:57:31 $
+ */
+#ifdef EMUV1
+#include "defines.h"
+#include <unistd.h>
+
+void eae_wr(u_int16_t data, u_int16_t PA, int32_t access);
+void set_SR(void);
+
+/* I/O dispatch routine, I/O addresses 177300 - 177316 */
+
+#define eae_DIV 0177300                /* Divide */
+#define eae_AC  0177302                /* Accumulator */
+#define eae_MQ 0177304         /* MQ */
+#define eae_MUL        0177306         /* Multiply */
+#define eae_SC  0177310                /* Step counter */
+#define eae_SR  0177311                /* Status register */
+#define eae_NOR 0177312                /* Normalize */
+#define eae_LSH 0177314                /* Logical shift */
+#define eae_ASH 0177316                /* Arithmetic shift */
+#define WRITEB 1               /* Write of a byte */
+#define WRITEW 2               /* Write of a word */
+
+/* The MQ, AC, SC, and SR registers specify the state of the EAE */
+/* Here we define them as int32's, though in real life the MQ and AC */
+/* are 16 bits and the SC and SR are 8 bits */
+
+int32_t MQ;                            /* Multiply quotient */
+int32_t AC;                            /* Accumulator */
+int32_t SC = 0;                                /* Shift counter */
+int32_t SR;                            /* Status register */
+
+
+/* Load a word from one of the KE11 registers */
+int16_t kell_word(u_int16_t addr)
+{
+  int16_t data;
+  int pid;
+
+  switch (addr) {
+    case eae_DIV:
+      data = 0; break;
+    case eae_MQ:
+      data = MQ; break;
+    case eae_AC:                       /* high 16 bits of MQ */
+      data = AC; break;
+    case eae_SC:
+      set_SR();
+      data = (SR << 8) | SC; break;
+    case eae_SR:
+      set_SR();
+      data = (SR << 8); break;
+    case eae_NOR:
+      data = SC; break;
+    case eae_LSH:
+    case eae_ASH:
+    case eae_MUL:
+      data = 0; break;
+    default:
+      pid = getpid();
+      (void) fprintf(stderr, "Apout - pid %d unknown KE11 register 0%o\n",
+                    pid, addr);
+      exit(EXIT_FAILURE);
+  }
+  return data;
+}
+
+/* Load a byte from one of the KE11 registers */
+int8_t kell_byte(u_int16_t addr)
+{
+  if (addr&1) printf("Hmm, KE11 access on 0%o\n",addr);
+  return ((int8_t) kell_word(addr));
+}
+
+/* Save a word to one of the KE11 registers */
+void kesl_word(u_int16_t addr, u_int16_t word)
+{
+  eae_wr(word, addr, WRITEW);
+}
+
+/* Save a byte to one of the KE11 registers */
+void kesl_byte(u_int16_t addr, u_int8_t byte)
+{
+  eae_wr(byte, addr, WRITEB);
+}
+
+void eae_wr(u_int16_t data, u_int16_t PA, int32_t access)
+{
+  int32_t divisor, quotient, remainder;
+  int32_t dividend, product;
+  int32_t oldMQ;
+  int pid;
+
+  switch (PA) {
+    case eae_DIV:
+      SC = 0;
+      dividend = (AC << 16) | MQ;
+      divisor = data;
+      if (divisor >> 15) divisor = divisor | ~077777;
+      quotient = dividend / divisor;
+      MQ = quotient & 0177777;
+      remainder = dividend % divisor;
+      AC = remainder & 0177777;
+      SR = SR & 076;
+      if ((quotient > 32767) || (quotient < -32768)) { /* did we overflow? */
+       if (dividend < 0) SR = SR | 0100;
+       else SR = SR | 0200;
+      } else {
+       if (quotient < 0) SR = SR | 0300;
+      }
+      return;
+    case eae_AC:
+      AC = data;
+      if ((access == WRITEB) & (data >> 7))
+       AC = AC | 0177400;
+      return;
+    case eae_AC + 1:
+      printf("write to AC+1; data=%o", data);
+      AC = (AC & 0377) | (data << 8);
+      return;
+    case eae_MQ:
+      MQ = data;
+      if ((access == WRITEB) & (data >> 7)) MQ = MQ | 0177400;
+      if (MQ >> 15) AC = 0177777;
+      else AC = 0;
+      return;
+    case eae_MQ + 1:
+      printf("write to MQ+1; data=%o", data);
+      MQ = (MQ & 0377) | (data << 8);
+      if (MQ >> 15) AC = 0177777;
+      else AC = 0;
+      return;
+    case eae_MUL:
+      SC = 0;
+      if (data >> 15) data = data | ~077777;
+      if (MQ >> 15) MQ = MQ | ~077777;
+      product = MQ * data;
+      MQ = product & 0177777;
+      AC = (product >> 16) & 0177777;
+      SR = SR & 076;
+      if (AC >> 15) SR = SR | 0300;    /* set sign bit if necessary */
+      return;
+    case eae_SC:
+      if (access == WRITEB) return;    /* byte writes are no-ops */
+      SR = (data >> 8) & 0177777;
+      SC = data & 0000077;
+      return;
+    case eae_SR:
+      return;                          /* this is a No-op */
+    case eae_NOR:                      /* Normalize */
+      MQ = (AC << 16) | MQ;            /* 32-bit number to normalize in MQ */
+      for (SC = 0; SC < 31; SC++) {
+       if (MQ == (0140000 << 16))
+         break;
+       if ((((MQ >> 30) & 3) == 1) || (((MQ >> 30) & 3) == 2))
+         break;
+       MQ = MQ << 1;
+      }
+      printf("SC = %o\r\n", SC);
+      AC = (MQ >> 16) & 0177777;
+      MQ = MQ & 0177777;
+      return;
+    case eae_LSH:                      /* Logical shift */
+       MQ=(AC<<16)|MQ;                         /* Form a temporary 32-bit entity */
+       oldMQ=MQ & 0x80000000;          /* Save the sign bit for later */
+       SR=SR&0176;                     /* Clear overflow & carry bits */
+       data=data & 077;                        /* Convert data from 6-bit */
+       if (data>31) {          
+        data=64-data;                  /* Shift in a -ve direction */
+         SR=SR|((MQ>>(data-1))&1);     /* Get the bit that went off the end */
+         MQ=MQ>>data;                  /* and do the right shift */
+       } else {                                /* Else left shift */
+        if ((MQ<<(data-1))&0x80000000) SR|=1; /* Get the bit off the end */
+        MQ=MQ<<data;                   /* and do the left shift */
+       }
+       oldMQ= oldMQ ^ MQ;              /* Any difference in sign bit? */
+       if (oldMQ & 0x80000000) SR|=0200;/* Yes, set the overflow bit */
+       AC=(MQ>>16)&0177777;            /* Save result in AC and MQ */
+       MQ=MQ&0177777;
+       set_SR();
+       return;
+
+    case eae_ASH:                      /* Arithmetic shift */
+       MQ=(AC<<16)|MQ;                         /* Form a temporary 32-bit entity */
+       oldMQ=MQ & 0x80000000;          /* Save the sign bit for later */
+       SR=SR&0176;                     /* Clear overflow & carry bits */
+       data=data & 077;                        /* Convert data from 6-bit */
+       if (data>31) {          
+        data=64-data;                  /* Shift in a -ve direction */
+        divisor=1 << data;             /* Work out the dividing factor */
+         SR=SR|((MQ>>(data-1))&1);     /* Get the bit that went off the end */
+         MQ=MQ/divisor;                /* and do the right shift */
+       } else {                                /* Else left shift */
+        product=1 << data;             /* Work out the multiplying factor */
+        if ((MQ<<(data-1))&0x80000000) SR|=1; /* Get the bit off the end */
+        MQ=MQ*product;                 /* and do the left shift */
+       }
+       oldMQ= oldMQ ^ MQ;              /* Any difference in sign bit? */
+       if (oldMQ & 0x80000000) SR|=0200;/* Yes, set the overflow bit */
+       AC=(MQ>>16)&0177777;            /* Save result in AC and MQ */
+       MQ=MQ&0177777;
+       set_SR();
+       return;
+
+    default:
+      pid = getpid();
+      (void) fprintf(stderr, "Apout - pid %d unknown KE11 register 0%o\n",
+                    pid, PA);
+      exit(EXIT_FAILURE);
+  }
+}
+
+void set_SR(void)
+{
+  SR = SR & 0301;              /* clear the result bits we can set here */
+  if (((MQ & 0100000) == 0) && (AC == 0)) SR = SR | 002;
+  if (((MQ & 0100000) == 0100000) && (AC == 0177777)) SR = SR | 002;
+
+  if ((AC == 0) && (MQ == 0)) SR = SR | 0004;
+  if (MQ == 0) SR = SR | 0010;
+  if (AC == 0) SR = SR | 0020;
+  if (AC == 0177777) SR = SR | 0040;
+}
+#endif /* EMUV1 */
diff --git a/magic.c b/magic.c
new file mode 100644 (file)
index 0000000..4a9e59b
--- /dev/null
+++ b/magic.c
@@ -0,0 +1,134 @@
+/* magic.c - determine the environment for certain PDP-11 a.out binaries
+ *
+ * Some binaries in V1, V2, V5, V6, V7 and 2.11BSD are not caught with the
+ * magic numbers in aout.c. If this is the case, we fall into the
+ * special_magic() function, which calculates a checksum on the
+ * a.out header. If it matches any of the checksums below, it returns
+ * the appropriate environment value. Otherwise, it returns IS_UNKNOWN.
+ *
+ * $Revision: 1.13 $
+ * $Date: 2000/01/10 01:31:48 $
+ */
+#include "defines.h"
+
+struct spec_aout {
+       u_int32_t cksum;
+       int environment;
+};
+
+static struct spec_aout S[]= {
+       { 0x1042c2, IS_V6 },    /* V6 bin/dc */
+       { 0x10f02, IS_V5 },     /* V5 etc/update */
+       { 0x11002, IS_V5 },     /* V5 bin/clri */
+       { 0x1117c2, IS_V7 },    /* V7 bin/roff */
+       { 0x11702, IS_V6 },     /* V6 etc/update */
+       { 0x11a82, IS_V5 },     /* V5 bin/sum */
+       { 0x1319c2, IS_V5 },    /* V5 usr/fort/fc1 */
+       { 0x1332c2, IS_V2 },    /* /lib/c0 dated Jun 30 1973 from s2 tape */
+       { 0x13642, IS_V5 },     /* V5 bin/rew */
+       { 0x139e02, IS_V5 },    /* V5 bin/dc */
+       { 0x13c0, IS_V6 },      /* V6 usr/lib/tmgc */
+       { 0x14042, IS_V6 },     /* V6 bin/tty */
+       { 0x143c2, IS_V5 },     /* V5 bin/tty */
+       { 0x152ac2, IS_V6 },    /* V6 usr/lib/tmg */
+       { 0x15f42, IS_V5 },     /* V5 bin/kill */
+       { 0x16802, IS_V5 },     /* V5 bin/dsw */
+       { 0x16902, IS_V5 },     /* V5 bin/mkdir */
+       { 0x1720c2, IS_V6 },    /* V6 bin/cdb */
+       { 0x17742, IS_V5 },     /* V5 usr/bin/pfe */
+       { 0x17cc2, IS_V5 },     /* V5 usr/bin/mesg */
+       { 0x18702, IS_V5 },     /* V5 bin/rmdir */
+       { 0x194c2, IS_V6 },     /* V6 bin/chgrp */
+       { 0x197c2, IS_V6 },     /* V6 bin/chown */
+       { 0x19a42, IS_V5 },     /* V5 bin/chown */
+       { 0x19b342, IS_V6 },    /* V6 usr/bin/nroff */
+       { 0x19f682, IS_V6 },    /* V6 usr/fort/fc1 */
+       { 0x1b102, IS_V5 },     /* V5 bin/strip */
+       { 0x1ba02, IS_V6 },     /* V6 bin/strip */
+       { 0x1c342, IS_V5 },     /* V5 bin/cat */
+       { 0x1c8442, IS_V7 },    /* V7 usr/games/maze */
+       { 0x1cc782, IS_V6 },    /* V6 lib/fc0 */
+       { 0x1dfc2, IS_V5 },     /* V5 etc/getty */
+       { 0x1f9c2, IS_V2 },     /* /bin/nm dated Jun 30 1973 from s2 tape */
+       { 0x20202, IS_V5 },     /* V5 usr/games/bj */
+       { 0x21e42, IS_V6 },     /* V6 usr/bin/units */
+       { 0x23f82, IS_V5 },     /* V5 usr/bin/passwd */
+       { 0x260642, IS_V6 },    /* V6 lib/fc1 */
+       { 0x262a82, IS_211BSD }, /* 2.11 usr/new/m11 */
+       { 0x27e82, IS_V5 },     /* V5 usr/bin/grep */
+       { 0x290c2, IS_V7 },     /* V7 usr/games/cubic */
+       { 0x299c2, IS_V5 },     /* V5 usr/games/cubic */
+       { 0x2f482, IS_V5 },     /* V5 usr/bin/form */
+       { 0x3382, IS_V6 },      /* V6 bin/write */
+       { 0x326642, IS_V7 },    /* 2.9 awk */
+       { 0x33c42, IS_211BSD }, /* 2.11 usr/games/moo */
+       { 0x351382, IS_211BSD }, /* 2.11 usr/games/lib/zork */
+       { 0x3702, IS_V5 },      /* V5 usr/games/moo */
+       { 0x3b402, IS_V5 },     /* V5 bin/ar */
+       { 0x3cc02, IS_V2 },     /* /bin/size from from s2 tape */
+       { 0x4382, IS_V5 },      /* V5 bin/write */
+       { 0x451f42, IS_V7 },    /* 2.9 /lib/c1 */
+       { 0x47042, IS_211BSD }, /* 2.11 usr/games/ttt */
+       { 0x4fa02, IS_V5 },     /* V5 bin/ld */
+       { 0x51342, IS_211BSD }, /* 2.11 usr/games/bj */
+       { 0x53302, IS_V6 },     /* V6 usr/lib/suftab */
+       { 0x55882, IS_V7 },     /* 2.9 /bin/as */
+       { 0x54702, IS_V5 },     /* V5 usr/games/ttt */
+       { 0x55702, IS_V7 },     /* V7 bin/as */
+       { 0x5c342, IS_V2 },    /* /bin/cc dated Jun 30 1973 from s2 tape */
+       { 0x6f742, IS_V6 },     /* V6 usr/bin/sa */
+       { 0x7042, IS_V7 },      /* V7 bin/factor */
+       { 0x71702, IS_V7 },     /* V7 lib/as2 */
+       { 0x7342, IS_V5 },      /* V5 bin/du */
+       { 0x73782, IS_V7},      /* 2.9 /lib/as2 */
+       { 0x73e00, IS_V2 },     /* /bin/ld from s2 tape */
+       { 0x7a242, IS_V6 },     /* V6 lib/as2 */
+       { 0x7b102, IS_V6 },     /* V6 bin/as */
+       { 0x7d082, IS_V5 },     /* V5 bin/as */
+       { 0x7d6844, IS_V1 },    /* bin/cal from s2 tape */
+       { 0x7d942, IS_V5 },     /* V5 lib/as2 */
+       { 0x8002, IS_V5 },      /* V5 etc/lpd */
+       { 0x85842, IS_V5 },     /* V5 bin/ed */
+       { 0x8f00, IS_V6 },      /* V6 usr/lib/tmga */
+       { 0x915c2, IS_V6 },     /* V6 bin/bas */
+       { 0x94542, IS_V5 },     /* V5 bin/db */
+       { 0x98442, IS_V6 },     /* V6 usr/bin/ac */
+       { 0x9adc2, IS_V6 },     /* V6 bin/db */
+       { 0xa242, IS_V7 },      /* V7 bin/primes */
+       { 0xa4602, IS_V2 },     /* /bin/as from s2 tape */
+       { 0xa702, IS_V5 },      /* V5 bin/time */
+       { 0xad882, IS_V7 },     /* V7 bin/bas */
+       { 0xadc42, IS_V2 },     /* /usr/lib/c1 from s2 tape */
+       { 0xb5a82, IS_V6 },     /* V6 usr/bin/prof */
+       { 0xc1e42, IS_V5 },     /* V5 usr/bin/fed */
+       { 0xc3102, IS_V6 },     /* V6 bin/tp */
+       { 0xc8bc2, IS_V5 },     /* V5 bin/tp */
+       { 0xe1642, IS_V6 },     /* V6 usr/bin/roff */
+       { 0xe1f42, IS_V5 },     /* V5 usr/bin/roff */
+       { 0xec582, IS_V5 },     /* V5 bin/bas */
+       { 0xfc2, IS_V6 },       /* V6 usr/bin/typo */
+       { 0xfc002, IS_V2 },     /* /bin/as dated Jun 30 1973 from s2 tape */
+       { 0x38ec0, IS_V5 },     /* V5 bin/ar, Warrens */
+       { 0, 0 }
+};
+
+/* cptr points at the start of the a.out header */
+int special_magic(u_int16_t *cptr)
+{
+    u_int32_t cksum=0;
+    int i;
+
+    if (cptr==NULL) return(IS_UNKNOWN);
+                               /* Calculate the checksum */
+    for (i=0;i<8; i++) { cksum ^= cptr[i]; cksum = cksum<<1; }
+
+                               /* Try and find a match */
+    for (i=0; S[i].cksum!=0; i++) if (S[i].cksum==cksum) {
+      TrapDebug((dbg_file, "This a.out has special magic %d\n",i));
+      return(S[i].environment);
+    }
+
+                               /* None, return 0 */
+    (void)printf("Apout - unknown magic in header: 0x%x\n",cksum);
+    return(IS_UNKNOWN);
+}
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..cd52f6e
--- /dev/null
+++ b/main.c
@@ -0,0 +1,132 @@
+/* Startup for apout. Parse arguments, load the binary, and run it.
+ *
+ * $Revision: 1.22 $
+ * $Date: 2002/06/10 11:44:21 $
+ */
+#include <assert.h>
+#include "defines.h"
+
+/* The following array holds the FILE pointers that correspond to open file
+ * descriptors. Only fds which are not ttys have FILE * pointers
+ */
+FILE *stream[NFILE];
+char *streammode[NFILE]; /* Mode for each file - used for dup */
+
+                               /* The following two buffers are used as */
+                               /* part of the translation from virtal */
+                               /* absolute filenames to native ones. We */
+                               /* only have 2 buffers, so if you call */
+                               /* xlate_filename() 3 times, the 1st return */
+                               /* value will be destroyed. */
+static char realfilename[2][2 * MAXPATHLEN];
+static char *rfn[2];
+static int whichrfn=0;
+char *apout_root=NULL;         /* Root dir for simulated a.out */
+
+#ifdef DEBUG
+                               /* Debugging flags */
+int inst_debug= 0,             /* Print a line before each instruction */
+    trap_debug= 0,             /* Print details of each trap */
+    jsr_debug= 0,              /* Print out each jsr */
+    fp_debug=  0;              /* Print out each floating-point instruction */
+FILE *dbg_file = NULL;         /* Debugging output file */
+char *progname = NULL;         /* The program's name - used in debugging */
+#endif
+
+void usage()
+{
+  fprintf(stderr, "Usage: apout");
+#ifdef DEBUG
+  fprintf(stderr, " [-inst] [-trap] [-jsr] [-fp]");
+#endif
+  fprintf(stderr, " pdp11_binary\n");
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+    int i;
+
+    /* Ensure, before we start, that certain types are right */
+    assert(sizeof(int8_t)==1);  assert(sizeof(u_int8_t)==1);
+    assert(sizeof(int16_t)==2); assert(sizeof(u_int16_t)==2);
+    assert(sizeof(int32_t)==4); assert(sizeof(u_int32_t)==4);
+
+    if (argc < 2) usage();
+    if (!strcmp(argv[1], "-help")) usage();
+    if (!strcmp(argv[1], "--help")) usage();
+
+#ifdef DEBUG
+    while (1) {
+      if (!strcmp(argv[1], "-inst"))
+               { inst_debug = 1; argc--; argv++; continue; }
+      if (!strcmp(argv[1], "-trap"))
+               { trap_debug = 1; argc--; argv++; continue; }
+      if (!strcmp(argv[1], "-jsr"))
+               { jsr_debug = 1; argc--; argv++; continue; }
+      if (!strcmp(argv[1], "-fp"))
+               { fp_debug = 1; argc--; argv++; continue; }
+      break;
+    }
+    if (inst_debug|trap_debug|jsr_debug|fp_debug)
+                               dbg_file = fopen("apout.dbg", "w");
+#endif
+
+                               /* Prepare arg list for emulated environment */
+    argc--; argv++;
+    Argc= argc; Envp[0]=NULL;
+    for (i=0; i<argc; i++) Argv[i]= argv[i];
+
+                               /* Initialise the stream pointers */
+    for (i=3; i<NFILE; i++) { stream[i]=NULL; streammode[i]=NULL; }
+    stream[0]=stdin;  streammode[0]="r";
+    stream[1]=stdout; streammode[1]="w";
+    stream[2]=stderr; streammode[2]="w";
+
+                                /* Set the translation to a fictitious */
+                                /* root filesystem */
+    if ((apout_root = getenv("APOUT_ROOT"))) {  
+       set_apout_root(apout_root);
+    } else {
+        fprintf(stderr,                 
+                "APOUT_ROOT env variable not set before running apout\n");
+        exit(1);
+    }   
+
+                               /* Try to load the binary as an a.out */
+    if (load_a_out(argv[0],NULL,1) == -1) {
+       fprintf(stderr, "Apout - couldn't load %s\n", argv[0]);
+       exit(1);
+    }
+
+                               /* Other emulated systems (RT-11) can go here */
+
+    run();                     /* Now run the binary */
+    exit(0);
+}
+
+/* Translate from a filename to one which is possibly rooted in $APOUT_ROOT.
+ * Note we return a pointer to one of two buffers. The caller does not
+ * have to free the returned pointer, but successive calls will destroy
+ * calls from >2 calls earlier.
+ */
+char * xlate_filename(char *name)
+{
+    int i=whichrfn;
+
+    if (name == NULL) return (NULL);
+    if (name[0] == '\0') return(".");  /* Undocumented, but used in V7 */
+    if (name[0] != '/') return (name); /* Relative, keep it relative */
+    strcpy(rfn[i], name);              /* Copy name into buffer */
+    whichrfn= 1 - whichrfn;            /* Switch to other buffer next time */
+    return (realfilename[i]);
+}
+
+void set_apout_root(char *dirname)
+{
+        strcpy(realfilename[0], dirname);      
+        strcpy(realfilename[1], dirname);      
+        rfn[0] = realfilename[0]; rfn[0] += strlen(realfilename[0]);
+        rfn[1] = realfilename[1]; rfn[1] += strlen(realfilename[1]);
+}
diff --git a/single.c b/single.c
new file mode 100644 (file)
index 0000000..de7e334
--- /dev/null
+++ b/single.c
@@ -0,0 +1,528 @@
+/* single.c - Single operand instructions.
+ *
+ * $Revision: 2.10 $
+ * $Date: 1999/01/05 23:46:04 $
+ */
+#include "defines.h"
+
+/* adc() - Add Carry Instruction. */
+void 
+adc()
+{
+    load_dst();
+
+    if (CC_C) {                /* do if carry is set */
+       if (dstword == MPI)
+           SET_CC_V();
+       else
+           CLR_CC_V();
+       if (dstword == NEG_1)
+           SET_CC_C();
+       else
+           CLR_CC_C();
+       dstword++;                      /* add the carry */
+    } else {
+       CLR_CC_V();
+       CLR_CC_C();
+    }
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+
+    store_dst_2();
+}
+
+
+/* asl() - Arithmetic Shift Left Instruction. */
+void 
+asl()
+{
+    load_dst();
+
+    if (dstword & SIGN)
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    dstword <<= 1;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CHG_CC_V_XOR_C_N();
+
+    store_dst_2();
+}
+
+/* asr() - Arithmetic Shift Right Instruction. */
+void 
+asr()
+{
+    load_dst();
+
+    if (dstword & LSBIT)
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    dstword = (dstword >> 1) + (dstword & SIGN);     /* shift and replicate */
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+
+    CHG_CC_V_XOR_C_N();
+
+    store_dst_2();
+}
+
+/* clr() - Clear Instruction. */
+void 
+clr()
+{
+    CLR_CC_ALL(); SET_CC_Z();
+    dstword=0; store_dst();
+}
+
+/* com() - Complement Instruction. */
+void 
+com()
+{
+    load_dst();
+
+    dstword = ~dstword;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CLR_CC_V();
+    SET_CC_C();
+
+    store_dst_2();
+}
+
+/* dec() - Decrement Instruction. */
+void 
+dec()
+{
+    load_dst();
+
+    if (dstword == MNI)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    --dstword;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+
+    store_dst_2();
+}
+
+/* inc() - Increment Instruction. */
+void 
+inc()
+{
+    load_dst();
+
+    if (dstword == MPI)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    ++dstword;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+
+    store_dst_2();
+}
+
+/* neg() - Negate Instruction. */
+
+void 
+neg()
+{
+    load_dst();
+
+    dstword = (NEG_1 - dstword) + 1;
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+
+    if (dstword == MNI)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    if (dstword == 0)
+       CLR_CC_C();
+    else
+       SET_CC_C();
+
+    store_dst_2();
+}
+
+/* rol() - Rotate Left Instruction. */
+void 
+rol()
+{
+    load_dst();
+
+    tmpword = dstword & SIGN;          /* get sign bit */
+    dstword <<= 1;                     /* shift */
+
+    if (CC_C)          /* roll in carry */
+       dstword += LSBIT;
+
+    if (tmpword)                       /* roll out to carry */
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CHG_CC_V_XOR_C_N();
+
+    store_dst_2();
+}
+
+
+/* ror() - Rotate Right Instruction. */
+void 
+ror()
+{
+    load_dst();
+
+    tmpword = dstword & LSBIT; /* get low bit */
+    dstword >>= 1;                     /* shift */
+
+    if (CC_C)          /* roll in carry */
+       dstword += SIGN;
+
+    if (tmpword)                       /* roll out to carry */
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+    CHG_CC_V_XOR_C_N();
+
+    store_dst_2();
+}
+
+/* sbc() - Subtract Carry Instruction. */
+void 
+sbc()
+{
+    load_dst();
+
+    if (dstword == MNI)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    if (CC_C) {                /* do if carry is set */
+       if (dstword)
+           CLR_CC_C();
+       else
+           SET_CC_C();
+       --dstword;                      /* subtract carry */
+    } else {
+       CLR_CC_C();
+    }
+
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+
+    store_dst_2();
+}
+
+/* swabi() - Swap Bytes Instruction. */
+void 
+swabi()
+{
+    u_int16_t data2;
+    u_int16_t data3;
+
+    load_dst();
+
+    data2 = (dstword << 8) & 0xff00;
+    data3 = (dstword >> 8) & 0x00ff;
+    dstword = data2 + data3;
+
+    CLR_CC_ALL();
+    CHGB_CC_N(data3);          /* cool, negative and zero */
+    CHGB_CC_Z(data3);          /* checks done on low byte only */
+
+    store_dst_2();
+}
+
+/* sxt() - Sign Extend Instruction. */
+void 
+sxt()
+{
+    if (CC_N) {
+       dstword = NEG_1;
+       CLR_CC_Z();
+    } else {
+       dstword = 0;
+       SET_CC_Z();
+    }
+    CLR_CC_V();
+
+    store_dst();
+}
+
+/* tst() - Test Instruction. */
+void 
+tst()
+{
+    load_dst();
+
+    CLR_CC_ALL();
+    CHG_CC_N(dstword);
+    CHG_CC_Z(dstword);
+}
+
+/* tstb() - Test Byte Instruction. */
+void 
+tstb()
+{
+    loadb_dst();
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CLR_CC_V();
+    CLR_CC_C();
+
+}
+
+/* aslb() - Arithmetic Shift Left Byte Instruction. */
+void 
+aslb()
+{
+    loadb_dst();
+
+    if (dstbyte & SIGN_B)
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    dstbyte <<= 1;
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CHG_CC_V_XOR_C_N();
+
+    storeb_dst_2();
+}
+
+/* asrb() - Arithmetic Shift Right Byte Instruction. */
+void 
+asrb()
+{
+    loadb_dst();
+
+    if (dstbyte & LSBIT)
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    dstbyte = (dstbyte >> 1) + (dstbyte & SIGN_B);    /* shift and replicate */
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CHG_CC_V_XOR_C_N();
+
+    storeb_dst_2();
+}
+
+/* clrb() - Clear Byte Instruction. */
+void 
+clrb()
+{
+    CLR_CC_ALL(); SET_CC_Z();
+    srcbyte=0; storeb_dst();
+}
+
+
+/* comb() - Complement Byte Instruction. */
+void 
+comb()
+{
+    loadb_dst();
+
+    dstbyte = ~dstbyte;
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CLR_CC_V();
+    SET_CC_C();
+
+    storeb_dst_2();
+}
+
+/* decb() - Decrement Byte Instruction. */
+void 
+decb()
+{
+    loadb_dst();
+
+    if (dstbyte == MNI_B)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    --dstbyte;
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+
+    storeb_dst_2();
+}
+
+/* incb() - Increment Byte Instruction. */
+void 
+incb()
+{
+    loadb_dst();
+
+    if (dstbyte == MPI_B)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    ++dstbyte;
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+
+    storeb_dst_2();
+}
+
+/* negb() - Negate Byte Instruction. */
+void 
+negb()
+{
+    loadb_dst();
+
+    dstbyte = (NEG_1_B - dstbyte) + 1;/* hope this is right */
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+
+    if (dstbyte == MNI_B)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    if (dstbyte)
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    storeb_dst_2();
+}
+
+/* rolb() - Rotate Left Byte Instruction. */
+void 
+rolb()
+{
+    loadb_dst();
+
+    tmpbyte = dstbyte & SIGN_B; /* get top bit */
+    dstbyte <<= 1;                     /* shift */
+
+    if (CC_C)          /* roll in carry */
+       dstbyte = dstbyte + LSBIT;
+
+    if (tmpbyte)                       /* roll out to carry */
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CHG_CC_V_XOR_C_N();
+
+    storeb_dst_2();
+}
+
+/* rorb() - Rotate Right Byte Instruction. */
+void 
+rorb()
+{
+    loadb_dst();
+
+    tmpbyte = dstbyte & LSBIT; /* get low bit */
+    dstbyte >>= 1;                     /* shift */
+
+    if (CC_C)          /* roll in carry */
+       dstbyte += SIGN_B;
+
+    if (tmpbyte)                       /* roll out to carry */
+       SET_CC_C();
+    else
+       CLR_CC_C();
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+    CHG_CC_V_XOR_C_N();
+
+    storeb_dst_2();
+}
+
+/* adcb() - Add Carry Byte Instruction. */
+void 
+adcb()
+{
+    loadb_dst();
+
+    if (CC_C) {                /* do if carry is set */
+       if (dstbyte == MPI_B)
+           SET_CC_V();
+       else
+           CLR_CC_V();
+       if (dstbyte == NEG_1_B)
+           SET_CC_C();
+       else
+           CLR_CC_C();
+       ++dstbyte;                      /* add the carry */
+    } else {
+       CLR_CC_V();
+       CLR_CC_C();
+    }
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+
+    storeb_dst_2();
+}
+
+/* sbcb() - Subtract Carry Byte Instruction. */
+void 
+sbcb()
+{
+    loadb_dst();
+
+    if (CC_C) {                /* do if carry is set */
+       if (dstbyte)
+           CLR_CC_C();
+       else
+           SET_CC_C();
+
+       --dstbyte;                      /* subtract carry */
+    } else {
+       CLR_CC_C();
+    }
+
+    if (dstbyte == MNI_B)
+       SET_CC_V();
+    else
+       CLR_CC_V();
+
+    CHGB_CC_N(dstbyte);
+    CHGB_CC_Z(dstbyte);
+
+    storeb_dst_2();
+}
diff --git a/v1trap.c b/v1trap.c
new file mode 100644 (file)
index 0000000..a726f66
--- /dev/null
+++ b/v1trap.c
@@ -0,0 +1,522 @@
+/* v1trap.c - Deal with 1st Edition trap instructions.
+ *
+ * $Revision: 1.15 $
+ * $Date: 2002/06/10 11:43:24 $
+ */
+#ifdef EMUV1
+#include "defines.h"
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <termios.h>
+#include <utime.h>
+#include "v1trap.h"
+
+#ifdef __linux__
+# undef STREAM_BUFFERING                       /* It seems to work */
+#else
+# define STREAM_BUFFERING                      /* but not for Linux */
+#endif
+
+
+/* Forward prototypes */
+#ifdef __STDC__
+#define P(s) s
+#else
+#define P(s) ()
+#endif
+static int v1trap_exec P((void));
+static int v1open_dir P((char *name));
+static u_int32_t sectosixty P((time_t tim));
+
+#undef P
+
+
+/* V1 keeps some of the arguments to syscalls in registers, and some
+ * after the `sys' instruction itself. The list below gives the number
+ * of words, and the number in registers.
+ */
+struct v1sysent {
+  int nwords;
+  int nregs;
+};
+static struct v1sysent v1arg[] = {
+  {0, 0}, {0, 0}, {0, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 1}, {1, 1},
+  {2, 0}, {2, 0}, {1, 0}, {2, 0}, {1, 0}, {0, 0}, {2, 0}, {2, 0},
+  {2, 0}, {1, 0}, {2, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 0}, {1, 1},
+  {1, 1}, {0, 0}, {1, 0}, {1, 0}, {2, 1}, {1, 0}, {1, 0}, {2, 1},
+  {2, 1}, {1, 0}
+};
+
+/* Seeks on files in /dev are done in 512-byte blocks, not bytes.
+ * If a fd's entry in the following table is 1, then it's a device
+ * and not a file.
+ */
+int8_t isdev[NFILE]= {
+       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+static arglist V1A;
+
+void v1trap()
+{
+  extern int32_t AC, MQ;       /* in ke11a.c */
+  int i, mode, pid;
+  int status, exitval, errval; /* used in V2 wait */
+  int whence;
+  u_int16_t argbase;
+  int trapnum;
+  long larg;
+  char *buf, *buf2;
+  char *fmode;                 /* used with fdopen only */
+
+  struct stat stbuf;           /* used in STAT */
+  struct tr_v1stat *t1;                /* used in STAT */
+  struct timeval tval[2];      /* used in SMTIME */
+
+
+
+  /* Work out the actual trap number, and */
+  /* shift the PC up past any arguments */
+  /* to the syscall. Calculate base of args */
+  trapnum = ir & 077;
+  argbase = regs[PC];
+  regs[PC] += 2 * (v1arg[trapnum].nwords - v1arg[trapnum].nregs);
+
+  /* Move arguments into V1A so we can use them */
+  for (i = 0; i < v1arg[trapnum].nregs; i++) V1A.uarg[i] = regs[i];
+  for (; i < v1arg[trapnum].nwords; i++, argbase += 2)
+    ll_word(argbase, V1A.uarg[i]);
+
+  TrapDebug((dbg_file, "pid %d %s: ", (int) getpid(), v1trap_name[trapnum]));
+
+  switch (trapnum) {
+
+      /* XXX STILL TO DO: V1_GTTY, V1_STTY, V1_TELL */
+
+                       /* These syscalls are ignored, and return */
+                       /* with no effect on the caller */
+    case V1_BREAK:
+    case V1_CEMT:
+    case V1_ILGINS:
+    case V1_INTR:
+    case V1_QUIT:
+    case V1_RELE: return;
+
+                       /* These syscalls are not implemented, and */
+                       /* always return no error to the caller */
+    case V1_GTTY:
+    case V1_STTY: i=0; break;
+                       /* These syscalls are not implemented, and */
+                       /* always return an error to the caller */
+    case V1_MOUNT:
+    case V1_UMOUNT: i = -1; break;
+
+    case V1_EXIT:
+      if (Binary==IS_V1) exit(0);
+      if (Binary==IS_V2) {
+       exitval=regs[0] & 0xff;
+       if (regs[PC]==16790) exitval=0; /* s2-tape /bin/as doesn't set r0 */
+       TrapDebug((dbg_file, " with exitval %d\n", exitval));
+       exit(exitval);
+      }
+      i = -1;
+      break;
+
+#define EPOCH71        31536000                /* # seconds from 1970 to 1971 */
+#define EPOCH72        63072000                /* # seconds from 1970 to 1972 */
+    case V1_SMDATE:
+      buf = xlate_filename(&dspace[uarg1]);
+      if (buf[0] == '\0') buf = ".";   /* Not documented anywhere */
+      if (uarg1 == 0) buf = ".";       /* Who knows? for V1 */
+      i = stat(buf, &stbuf);
+      TrapDebug((dbg_file, " on %s (stat %d) ", buf, i));
+      if (i == -1) break;
+
+                                       /* Copy access time to preserve it */
+      tval[0].tv_sec= stbuf.st_atime; tval[0].tv_usec=0;
+      larg= (AC << 16) | (MQ & 0xffff); /* Get mod time in 60ths of a second */
+      TrapDebug((dbg_file, " %ld -> ", larg));
+      larg= larg/60 + EPOCH72;         /* Convert to seconds since 1970 */
+      TrapDebug((dbg_file, " 0x%lx ", larg));
+      tval[1].tv_sec= larg; tval[1].tv_usec=0;
+      i=utimes(buf, tval);
+      TrapDebug((dbg_file, " and %d for utimes ", i));
+      break;
+
+    case V1_TIME:
+                       /* Kludge: treat start of this year as the epoch. */
+                       /* Find #seconds from yearstart to now, multiply */
+                       /* by 60 so as to be in V1 units */
+      larg = sectosixty(time(NULL));
+      MQ = (int) larg & 0xffff;
+      AC = ((int) larg >> 16) & 0xffff;
+      i = 0; break;
+    case V1_SEEK:
+      /* Work out the args before we do the lseek */
+      whence = uarg3;
+      switch (uarg3) {
+       case 0:
+         larg = uarg2; break;
+       case 1:
+       case 2:
+         larg = sarg2; break;
+      }
+
+      if (ValidFD(sarg1) && isdev[sarg1]) larg*= 512;
+
+#ifdef STREAM_BUFFERING
+      if (ValidFD(sarg1) && stream[sarg1]) {
+       i = fseek(stream[sarg1], larg, whence);
+       if (i == 0)
+         i = ftell(stream[sarg1]);
+      } else
+#endif
+       i = lseek(sarg1, larg, whence);
+
+      TrapDebug((dbg_file, " on fd %d amt %ld whence %d return %d ",
+                                               sarg1, larg, whence, i));
+      if (i != -1) i = 0;
+      regs[0] = i;
+      break;
+    case V1_READ:
+      buf = &dspace[uarg2];
+#ifdef STREAM_BUFFERING
+      if (ValidFD(sarg1) && stream[sarg1])
+       i = fread(buf, 1, sarg3, stream[sarg1]);
+      else
+#endif
+       i = read(sarg1, buf, sarg3);
+      TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
+      regs[0] = i; break;
+    case V1_LINK:
+      buf = xlate_filename(&dspace[uarg1]);
+      buf2 = xlate_filename(&dspace[uarg2]);
+      i = link(buf, buf2);
+      regs[0] = i; break;
+    case V1_WRITE:
+      buf = &dspace[uarg2];
+#ifdef STREAM_BUFFERING
+      if (ValidFD(sarg1) && stream[sarg1])
+       i = fwrite(buf, 1, sarg3, stream[sarg1]);
+      else
+#endif
+       i = write(sarg1, buf, sarg3);
+      TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
+      regs[0] = i; break;
+    case V1_CLOSE:
+#ifdef STREAM_BUFFERING
+      if (ValidFD(sarg1) && stream[sarg1]) {
+       i = fclose(stream[sarg1]);
+       stream[sarg1] = NULL;
+      } else
+#endif
+       i = close(sarg1);
+      if ((i==0) && ValidFD(sarg1)) isdev[sarg1]=0;
+      TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
+      break;
+    case V1_STAT:
+      buf = xlate_filename(&dspace[uarg1]);
+      if (buf[0] == '\0') buf = ".";   /* Not documented anywhere */
+      if (uarg1 == 0) buf = ".";       /* Who knows? for V1 */
+      buf2 = &dspace[uarg2];
+      i = stat(buf, &stbuf);
+      TrapDebug((dbg_file, " on %s return %d ", buf, i));
+      goto dostat;
+    case V1_FSTAT:
+      buf2 = &dspace[uarg2];
+      i = fstat(sarg1, &stbuf);
+      TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
+
+  dostat:
+      if (i == -1) break;
+      t1 = (struct tr_v1stat *) buf2;
+                               /* Inode numbers <41 are reserved for */
+                               /* device files. Ensure we don't use them */
+      t1->inum = stbuf.st_ino & 0x7fff; if (t1->inum<41) t1->inum+=100;
+      t1->inl = stbuf.st_nlink;
+      t1->iuid = stbuf.st_uid;
+      t1->isize = (u_int16_t) (stbuf.st_size & 0xffff);
+      t1->iflags = (u_int16_t) (V1_ST_USED | V1_ST_MODIFIED);
+      if (stbuf.st_size > 4095)    t1->iflags |= V1_ST_LARGE;
+      if (stbuf.st_mode & S_IFDIR) t1->iflags |= V1_ST_ISDIR;
+      if (stbuf.st_mode & S_ISUID) t1->iflags |= V1_ST_SETUID;
+      if (stbuf.st_mode & S_IXUSR) t1->iflags |= V1_ST_EXEC;
+      if (stbuf.st_mode & S_IRUSR) t1->iflags |= V1_ST_OWNREAD;
+      if (stbuf.st_mode & S_IWUSR) t1->iflags |= V1_ST_OWNWRITE;
+      if (stbuf.st_mode & S_IROTH) t1->iflags |= V1_ST_WRLDREAD;
+      if (stbuf.st_mode & S_IWOTH) t1->iflags |= V1_ST_WRLDWRITE;
+
+      larg = sectosixty(stbuf.st_ctime); copylong(t1->ctime, larg);
+      larg = sectosixty(stbuf.st_mtime); copylong(t1->mtime, larg);
+      break;
+    case V1_UNLINK:
+      buf = xlate_filename(&dspace[uarg1]);
+      i = unlink(buf);
+      break;
+    case V1_OPEN:
+      buf = xlate_filename(&dspace[uarg1]);
+
+      i = stat(buf, &stbuf);   /* If file is a directory */
+      if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
+       i = v1open_dir(buf);
+       fmode = "w+";
+       TrapDebug((dbg_file, "(dir) on %s return %d ", buf, i));
+      } else {
+       switch (sarg2) {
+         case 0:
+           sarg2 = O_RDONLY; fmode = "r"; break;
+         case 1:
+           sarg2 = O_WRONLY; fmode = "w"; break;
+         default:
+           sarg2 = O_RDWR; fmode = "w+"; break;
+       }
+       i = open(buf, sarg2);
+       TrapDebug((dbg_file, " on %s return %d ", buf, i));
+      }
+      regs[0] = i;
+
+      if (ValidFD(i) && !strncmp(&dspace[uarg1],"/dev/",5)) {
+       TrapDebug((dbg_file, " (device file) "));
+       isdev[i]=1;
+      }
+
+#ifdef STREAM_BUFFERING
+      if (i==-1) break;
+#if 0
+      /* Now get its stream pointer if possible */
+      /* Can someone explain why fdopen doesn't work for O_RDWR? */
+      if (ValidFD(i) && !isatty(i) && (sarg2 != O_RDWR)) {
+       stream[i] = fdopen(i, fmode); streammode[i] = fmode;
+      }
+#endif
+       stream[i] = fdopen(i, fmode); streammode[i] = fmode;
+#endif
+      break;
+    case V1_CHMOD:
+      buf = xlate_filename(&dspace[uarg1]);
+      mode = 0;
+      if (uarg2 & V1_ST_SETUID)    mode |= S_ISUID;
+      if (uarg2 & V1_ST_EXEC)      mode |= S_IXUSR | S_IXGRP | S_IXOTH;
+      if (uarg2 & V1_ST_OWNREAD)   mode |= S_IRUSR;
+      if (uarg2 & V1_ST_OWNWRITE)  mode |= S_IWUSR;
+      if (uarg2 & V1_ST_WRLDREAD)  mode |= S_IRGRP | S_IROTH;
+      if (uarg2 & V1_ST_WRLDWRITE) mode |= S_IWGRP | S_IWOTH;
+      i = chmod(buf, mode);
+      break;
+    case V1_MKDIR:
+      buf = xlate_filename(&dspace[uarg1]);
+      mode = 0;
+      if (uarg2 & V1_ST_SETUID)    mode |= S_ISUID;
+      if (uarg2 & V1_ST_EXEC)      mode |= S_IXUSR | S_IXGRP | S_IXOTH;
+      if (uarg2 & V1_ST_OWNREAD)   mode |= S_IRUSR;
+      if (uarg2 & V1_ST_OWNWRITE)  mode |= S_IWUSR;
+      if (uarg2 & V1_ST_WRLDREAD)  mode |= S_IRGRP | S_IROTH;
+      if (uarg2 & V1_ST_WRLDWRITE) mode |= S_IWGRP | S_IWOTH;
+      i = mkdir(buf, mode);
+      break;
+    case V1_CHOWN:
+      buf = xlate_filename(&dspace[uarg1]);
+      uarg2&= 0x3fff;                  /* Why are uids > 16384? */
+      i = chown(buf, uarg2, 0);
+      TrapDebug((dbg_file, " %d on %s return %d",uarg2,buf,i));
+      break;
+    case V1_CHDIR:
+      buf = xlate_filename(&dspace[uarg1]);
+      i = chdir(buf);
+      break;
+    case V1_CREAT:
+      buf = xlate_filename(&dspace[uarg1]);
+      mode = 0;
+      if (uarg2 & V1_ST_SETUID)    mode |= S_ISUID;
+      if (uarg2 & V1_ST_EXEC)      mode |= S_IXUSR | S_IXGRP | S_IXOTH;
+      if (uarg2 & V1_ST_OWNREAD)   mode |= S_IRUSR;
+      if (uarg2 & V1_ST_OWNWRITE)  mode |= S_IWUSR;
+      if (uarg2 & V1_ST_WRLDREAD)  mode |= S_IRGRP | S_IROTH;
+      if (uarg2 & V1_ST_WRLDWRITE) mode |= S_IWGRP | S_IWOTH;
+      i = creat(buf, mode);
+      TrapDebug((dbg_file, " on %s return %d ", buf, i));
+#ifdef STREAM_BUFFERING
+      if (ValidFD(i)) {
+       stream[i] = fdopen(i, "w");
+       streammode[i] = "w";
+      }
+#endif
+      regs[0] = i; break;
+    case V1_EXEC:
+      i = v1trap_exec();
+      break;
+    case V1_WAIT:
+      i = wait(&status);
+      if (Binary==IS_V1) break;
+                                       /* 2nd Edition wait is different */
+      regs[0] = i;                     /* Save pid found in r0 */
+      if (i==-1) { MQ=0; break; }
+      exitval=WEXITSTATUS(status);
+      TrapDebug((dbg_file, "exitval %d ",exitval));
+      errval=0;
+      if (WIFSIGNALED(status)) {
+       switch(WTERMSIG(status)) {
+         case SIGBUS: errval=1; break;
+         case SIGTRAP: errval=2; break;
+         case SIGILL: errval=3; break;
+         case SIGIOT: errval=4; break;
+         case SIGEMT: errval=6; break;
+         case SIGQUIT: errval=8; break;
+         case SIGINT: errval=9; break;
+         case SIGKILL: errval=10; break;
+       }
+       if (WCOREDUMP(status)) errval+=16;
+      }
+        TrapDebug((dbg_file, "errval %d ",errval));
+      MQ= (exitval & 0xff) | (errval<<16);
+      TrapDebug((dbg_file, "v2 return pid is %d, MQ is 0x%x ",i,MQ));
+      break;
+    case V1_FORK:
+      pid = getpid();
+      i = fork();
+      switch (i) {
+                                       /* Error, inform the parent */
+       case -1: break;
+                                       /* Child gets ppid in r0 */
+       case 0:
+         i = pid; break;
+                               /* Parent: Skip child `bf', pid into r0 */
+       default:
+         regs[PC] += 2;
+         if (Binary==IS_V2) regs[0]=i;
+      }
+      break;
+    case V1_GETUID:
+      i = getuid();
+      break;
+      regs[0] = i;
+    case V1_SETUID:
+      i = setuid(sarg1);
+      break;
+    default:
+      if (trapnum > V1_ILGINS) {
+       fprintf(stderr, "Apout - unknown syscall %d at PC 0%o\n",
+                                                       trapnum, regs[PC]);
+      } else {
+       fprintf(stderr, "Apout - the %s syscall is not yet implemented\n",
+                                                       v1trap_name[trapnum]);
+      }
+      exit(1);
+  }
+
+  /* Clear C bit if no error, or */
+  /* set C bit as there was an error */
+
+  if (i == -1) {
+    SET_CC_C(); TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
+  } else {
+    CLR_CC_C(); TrapDebug((dbg_file, "return %d\n", i));
+  }
+#ifdef DEBUG
+  fflush(dbg_file);
+#endif
+  return;
+}
+
+
+static int v1trap_exec(void)
+{
+  u_int16_t cptr, cptr2;
+  char *buf, *name, *origpath;
+
+  origpath = strdup(&dspace[uarg1]);
+  name = xlate_filename(origpath);
+  TrapDebug((dbg_file, "%s Execing %s ", progname, name));
+
+  cptr = uarg2;
+
+  Argc = 0;
+  while (Argc < MAX_ARGS) {
+    ll_word(cptr, cptr2);
+    if (cptr2 == 0)
+      break;
+    buf = &dspace[cptr2];
+    Argv[Argc++] = strdup(buf);
+    cptr += 2;
+    TrapDebug((dbg_file, "%s ", buf));
+  }
+  Argv[Argc] = NULL;
+  TrapDebug((dbg_file, "\n"));
+
+  if (load_a_out(name, origpath, 0) == -1) {
+    for (Argc--; Argc >= 0; Argc--)
+      free(Argv[Argc]);
+    return (-1);
+  }
+  run();                       /* Ok, so it's recursive, I dislike setjmp */
+  return (0);
+}
+
+/* 1st Edition reads directories as if they were ordinary files.
+ * The solution is to read the directory entries, and build a
+ * real file, which is passed back to the open call.
+ * Limitation: 32-bit inode numbers are truncated to 16-bit ones.
+ */
+static int v1open_dir(char *name)
+{
+  DIR *d;
+  char *tmpname;
+  int i;
+  struct dirent *dent;
+
+  struct v1_direct {
+    int16_t d_ino;
+    int8_t d_name[8];
+  } v1dent;
+
+  d = opendir(name);
+  if (d == NULL) return (-1);
+  tmpname = strdup(TMP_PLATE);
+  i = mkstemp(tmpname);
+  if (i == -1) {
+    fprintf(stderr, "Apout - open_dir couldn't open %s\n", tmpname);
+    exit(1);
+  }
+  unlink(tmpname);
+  free(tmpname);
+
+  while ((dent = readdir(d)) != NULL) {
+    v1dent.d_ino = dent->d_fileno & 0x7fff;
+    if (v1dent.d_ino<41) v1dent.d_ino+=100;
+    strncpy(v1dent.d_name, dent->d_name, 8);
+    write(i, &v1dent, 10);
+  }
+  closedir(d);
+  lseek(i, 0, SEEK_SET);
+  return (i);
+}
+
+/* Given a time, work out the number of 1/60ths of seconds since
+ * the start of that time's year
+ */
+u_int32_t sectosixty(time_t tim)
+{
+  time_t epoch;
+  u_int32_t diff;
+  struct tm *T;
+
+  T = gmtime(&tim);
+  T->tm_sec = T->tm_min = T->tm_hour = T->tm_mon = 0;
+  T->tm_mday = 1;
+
+  epoch = timegm(T);           /* Find time at start of year */
+  diff = 60 * (tim - epoch);
+  if (diff > 0x71172C00) {
+    fprintf(stderr, "Apout - V1 sectosixty too big by %d\n",diff-0x71172C00);
+  }
+  return (diff);
+}
+#endif                         /* EMUV1 */
diff --git a/v1trap.h b/v1trap.h
new file mode 100644 (file)
index 0000000..717efad
--- /dev/null
+++ b/v1trap.h
@@ -0,0 +1,125 @@
+/* v1trap.h - Deal with 1st Edition trap instructions.
+ *
+ * $Revision: 1.1 $
+ * $Date: 1999/12/26 08:16:33 $
+ */
+
+/* In this file, we list the trap number for each system call,
+ * and the structures associated with several of the systems
+ * calls in 1st Edition UNIX
+ */
+
+#define V1_RELE    0
+#define V1_EXIT    1
+#define V1_FORK    2
+#define V1_READ    3
+#define V1_WRITE   4
+#define V1_OPEN    5
+#define V1_CLOSE   6
+#define V1_WAIT    7
+#define V1_CREAT   8
+#define V1_LINK    9
+#define V1_UNLINK  10
+#define V1_EXEC    11
+#define V1_CHDIR   12
+#define V1_TIME    13
+#define V1_MKDIR   14
+#define V1_CHMOD   15
+#define V1_CHOWN   16
+#define V1_BREAK   17
+#define V1_STAT    18
+#define V1_SEEK    19
+#define V1_TELL    20
+#define V1_MOUNT   21
+#define V1_UMOUNT  22
+#define V1_SETUID  23
+#define V1_GETUID  24
+#define V1_STIME   25
+#define V1_QUIT    26
+#define V1_INTR    27
+#define V1_FSTAT   28
+#define V1_CEMT    29
+#define V1_SMDATE  30
+#define V1_STTY    31
+#define V1_GTTY    32
+#define V1_ILGINS  33
+
+
+char *v1trap_name[]= {
+       "rele",
+       "exit",
+       "fork",
+       "read",
+       "write",
+       "open",
+       "close",
+       "wait",
+       "creat",
+       "link",
+       "unlink",
+       "exec",
+       "chdir",
+       "time",
+       "mkdir",
+       "chmod",
+       "chown",
+       "break",
+       "stat",
+       "seek",
+       "tell",
+       "mount",
+       "umount",
+       "setuid",
+       "getuid",
+       "stime",
+       "quit",
+       "intr",
+       "fstat",
+       "cemt",
+       "smdate",
+       "stty",
+       "gtty",
+       "ilgins"
+};
+
+
+struct tr_v1stat {
+       u_int16_t       inum;
+       u_int16_t       iflags;         /* Mode */
+       u_int8_t        inl;            /* Links */
+       u_int8_t        iuid;
+       u_int16_t       isize;
+       int16_t         iaddr[8];       /* Not used, I hope! */
+       u_int32_t       ctime;
+       u_int32_t       mtime;
+       u_int16_t       unused;
+};
+
+/* Values for v1stat iflags */
+#define V1_ST_USED     0100000
+#define V1_ST_ISDIR    0040000
+#define V1_ST_MODIFIED 0020000
+#define V1_ST_LARGE    0010000
+#define V1_ST_SETUID   0000040
+#define V1_ST_EXEC     0000020
+#define V1_ST_OWNREAD  0000010
+#define V1_ST_OWNWRITE 0000004
+#define V1_ST_WRLDREAD 0000002
+#define V1_ST_WRLDWRITE        0000001
+
+/* A union which will point at the trap args, so that
+ * we can get at the various args of different types
+ */
+typedef union {
+    int16_t   sarg[4];         /* Signed 16-bit args */
+    u_int16_t uarg[4];         /* Unsigned 16-bit args */
+} arglist;
+
+#define sarg1  V1A.sarg[0]
+#define sarg2  V1A.sarg[1]
+#define sarg3  V1A.sarg[2]
+#define sarg4  V1A.sarg[3]
+#define uarg1  V1A.uarg[0]
+#define uarg2  V1A.uarg[1]
+#define uarg3  V1A.uarg[2]
+#define uarg4  V1A.uarg[3]
diff --git a/v7trap.c b/v7trap.c
new file mode 100644 (file)
index 0000000..0ea142f
--- /dev/null
+++ b/v7trap.c
@@ -0,0 +1,709 @@
+/* v7trap.c - Deal with V7 trap instructions. V5 and V6 syscalls are also
+ * done here, because the syscall interface is nearly the same as V7.
+ *
+ * $Revision: 1.47 $
+ * $Date: 2002/06/10 11:43:24 $
+ */
+#include "defines.h"
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <termios.h>
+#include <utime.h>
+#include "v7trap.h"
+
+#ifdef __linux__
+# undef STREAM_BUFFERING               /* It seems to work */
+#else
+# define STREAM_BUFFERING              /* but not for Linux */
+#endif
+
+/* Forward prototypes */
+#ifdef __STDC__
+#define P(s) s
+#else
+#define P(s) ()
+#endif
+static int trap_exec P((int want_env));
+static int open_dir P((char *name));
+static int trap_gtty P((u_int16_t fd, u_int16_t ucnt));
+static int trap_stty P((u_int16_t fd, u_int16_t ucnt));
+static int v7signal P((int sig, int val));
+static void fixv6time P((time_t *t));
+#undef P
+
+
+/* V7 keeps some of the arguments to syscalls in registers, and some
+ * after the `sys' instruction itself. The list below gives the number
+ * of words, and the number in registers.
+ */
+struct v7sysent {
+       int nwords;
+       int nregs;
+};
+static struct v7sysent v7arg[] = {
+       {0, 0}, {1, 1}, {0, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 1}, {0, 0},
+       {2, 0}, {2, 0}, {1, 0}, {2, 0}, {1, 0}, {0, 0}, {3, 0}, {2, 0},
+       {3, 0}, {1, 0}, {2, 0}, {4, 1}, {0, 0}, {3, 0}, {1, 0}, {1, 1},
+       {0, 0}, {2, 2}, {4, 1}, {1, 1}, {2, 1}, {0, 0}, {2, 0}, {2, 1},
+       {2, 1}, {2, 0}, {1, 1}, {1, 0}, {0, 0}, {2, 1}, {0, 0}, {0, 0},
+       {1, 1}, {2, 2}, {0, 0}, {1, 0}, {4, 0}, {0, 0}, {1, 1}, {0, 0},
+       {2, 0}, {0, 0}, {0, 0}, {1, 0}, {3, 0}, {1, 0}, {3, 0}, {0, 0},
+       {4, 0}, {0, 0}, {0, 0}, {3, 0}, {1, 0}, {1, 0}, {0, 0}, {0, 0}
+};
+
+static arglist V7A;
+
+
+void
+v7trap()
+{
+    int i, pid, pfd[2];
+    int whence;
+    u_int16_t argbase;
+    int trapnum;
+    long larg;
+    char *buf, *buf2;
+    char *fmode;               /* used with fdopen only */
+
+    struct stat stbuf;         /* used in STAT */
+    struct tr_v7stat *t;       /* used in STAT */
+    struct tr_v6stat *t6;      /* used in STAT */
+    struct tr_timeb *tb;       /* used in FTIME */
+    struct timezone tz;                /* used in FTIME */
+    struct timeval tv;         /* used in FTIME */
+    struct timeval utv[2];     /* used in UTIME */
+
+
+
+                               /* Work out the actual trap number, and */
+                               /* shift the PC up past any arguments */
+                               /* to the syscall. Calculate base of args */
+    trapnum= ir & 077;
+    if (trapnum==S_INDIR) {
+       lli_word(regs[PC], argbase);
+       ll_word(argbase, ir);
+        trapnum= ir & 077; argbase+=2; regs[PC]+=2;
+    } else {
+       argbase=regs[PC];
+       regs[PC]+= 2* (v7arg[trapnum].nwords - v7arg[trapnum].nregs);
+
+                               /* However, V6 seek() has 1 less arg */
+       if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
+           if (trapnum==S_LSEEK) regs[PC]-=2;
+       }
+    }
+
+                       /* Move arguments into V7A so we can use them */
+    for (i=0; i<v7arg[trapnum].nregs; i++) V7A.uarg[i]= regs[i];
+    for (;i<v7arg[trapnum].nwords; i++,argbase+=2)
+                                       ll_word(argbase, V7A.uarg[i]);
+    TrapDebug((dbg_file, "pid %d %s: ", (int)getpid(),v7trap_name[trapnum]));
+
+    switch (trapnum) {
+                       /* These syscalls are not implemented, and */
+                       /* always return EPERM to the caller */
+    case S_PHYS:
+    case S_PROF:
+    case S_PTRACE:
+    case S_ACCT:
+    case S_MOUNT:
+    case S_UMOUNT:
+    case S_TIMES:
+       i=-1; errno=EPERM; break;
+
+                       /* These syscalls are ignored, and */
+                       /* always return C=0 to the caller */
+    case S_LOCK:
+    case S_STIME:
+    case S_BREAK:
+       i=0; break;
+    case S_SYNC:
+       sync(); i=0; break;
+
+    case S_SIGNAL:
+       i= v7signal(uarg1, uarg2);
+       break;
+    case S_EXIT:
+       exit(regs[0]);
+       i=-1; errno=EPERM; break;
+    case S_NICE:
+       i= nice(regs[0]); break;
+    case S_PAUSE:
+       i = pause(); break;
+    case S_DUP:
+       if (sarg1 > 0100) {
+           sarg1 -= 0100;
+           i = dup2(sarg1, sarg2);     /* Check that sarg2, not r1, holds */
+#ifdef STREAM_BUFFERING
+           if ((i!=-1) && ValidFD(sarg2) && ValidFD(sarg1) && stream[sarg1]) {
+               fmode= streammode[sarg1];
+               stream[sarg2] = fdopen(sarg2, fmode);
+               streammode[sarg2]=fmode;
+           }
+#endif
+       } else
+           i = dup(sarg1);
+#ifdef STREAM_BUFFERING
+           if ((i!=-1) && ValidFD(i)&& ValidFD(sarg1) && stream[sarg1]) {
+               fmode= streammode[sarg1];
+               stream[i] = fdopen(i, fmode);
+               streammode[i]=fmode;
+           }
+#endif
+       break;
+    case S_TIME:
+       i = time(&larg);
+       
+       if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
+         fixv6time(&larg);     /* Fix annoying bug in V5/V6 ctime() */
+       }
+       regs[1] = larg & 0xffff;
+       i = larg >> 16;
+       break;
+    case S_ALARM:
+       i = alarm(uarg1); break;
+    case S_UMASK:
+       i = umask(uarg1); break;
+    case S_LSEEK:
+                               /* Work out the args before we do the lseek */
+       if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
+           whence=uarg3;
+           switch (uarg3) {
+               case 0: larg= uarg2; break;
+               case 1: 
+               case 2: larg= sarg2; break;
+               case 3: whence=0; larg= 512 * uarg2; break;
+               case 4: whence=1; larg= 512 * sarg2; break;
+               case 5: whence=2; larg= 512 * sarg2; break;
+           }
+       } else {
+           larg = (uarg2 << 16) | uarg3;
+           whence= uarg4;
+       }
+#ifdef STREAM_BUFFERING
+       if (ValidFD(sarg1) && stream[sarg1]) {
+           i = fseek(stream[sarg1], larg, whence);
+           if (i == 0) i = ftell(stream[sarg1]);
+       } else
+#endif
+           i = lseek(sarg1, larg, whence);
+
+        TrapDebug((dbg_file, " on fd %d amt %ld whence %d return %d ",
+                                       sarg1, larg, whence, i));
+       if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
+          if (i!=-1) i=0;
+          break;
+       }
+       regs[1] = i & 0xffff;
+       i = i >> 16;
+       break;
+    case S_READ:
+       buf = &dspace[uarg2];
+#ifdef STREAM_BUFFERING
+       if (ValidFD(sarg1) && stream[sarg1])
+           i = fread(buf, 1, uarg3, stream[sarg1]);
+       else
+#endif
+           i = read(sarg1, buf, uarg3);
+        TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i)); 
+       break;
+    case S_LINK:
+       buf = xlate_filename(&dspace[uarg1]);
+       buf2 = xlate_filename(&dspace[uarg2]);
+       if (!strcmp(buf, buf2)) i=0;    /* Happens on mkdir(1) */
+       else i = link(buf, buf2);
+       break;
+    case S_ACCESS:
+       buf = xlate_filename(&dspace[uarg1]);
+       i = access(buf, sarg2);
+       break;
+    case S_WRITE:
+       buf = &dspace[uarg2];
+#ifdef STREAM_BUFFERING
+       if (ValidFD(sarg1) && stream[sarg1])
+           i = fwrite(buf, 1, uarg3, stream[sarg1]);
+       else
+#endif
+           i = write(sarg1, buf, uarg3);
+        TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
+       break;
+    case S_CLOSE:
+#ifdef STREAM_BUFFERING
+       if (ValidFD(sarg1) && stream[sarg1]) {
+           i = fclose(stream[sarg1]);
+           stream[sarg1] = NULL;
+       } else
+#endif
+           i = close(sarg1);
+        TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
+       break;
+    case S_GTTY:
+       i = trap_gtty(uarg1, uarg2); break;
+    case S_STTY:
+       i = trap_stty(uarg1, uarg2); break;
+    case S_IOCTL:
+       switch (uarg2) {
+       case (('t' << 8) + 8):  /* GTTY */
+           i = trap_gtty(uarg1, uarg3); break;
+       case (('t' << 8) + 9):  /* STTY */
+           i = trap_stty(uarg1, uarg3); break;
+       default:
+           i=0;
+       }
+       break;
+    case S_FTIME:
+       buf = &dspace[uarg1];
+       tb = (struct tr_timeb *) buf;
+       i = gettimeofday(&tv, &tz);
+       if (i == -1) break;
+       copylong(tb->time, tv.tv_sec);
+#if 0
+       buf = (char *) &(tb->time);
+       buf2 = (char *) &(tv.tv_sec);
+       buf[0] = buf2[2]; buf[1] = buf2[3]; buf[2] = buf2[0]; buf[3] = buf2[1];
+#endif
+       tb->millitm = tv.tv_usec / 1000;
+       tb->timezone = tz.tz_minuteswest;
+       tb->dstflag = tz.tz_dsttime;
+       break;
+    case S_STAT:
+       buf = xlate_filename(&dspace[uarg1]);
+       if (buf[0]=='\0') buf=".";              /* Not documented anywhere */
+       if (uarg1==0) buf=".";
+       buf2 = &dspace[uarg2];
+       i = stat(buf, &stbuf);
+        TrapDebug((dbg_file, " on %s return %d ",buf,i));
+       goto dostat;
+    case S_FSTAT:
+       buf2 = &dspace[uarg2];
+       i = fstat(sarg1, &stbuf);
+        TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
+
+dostat:
+       if (i == -1) break;
+                                       /* V6 and V7 have different stats */
+       if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
+           t6 = (struct tr_v6stat *) buf2;
+           t6->idev = stbuf.st_dev;
+           t6->inum = stbuf.st_ino;
+           t6->iflags = stbuf.st_mode;
+           t6->inl = stbuf.st_nlink;
+           t6->iuid = stbuf.st_uid;
+           t6->igid = stbuf.st_gid;
+           t6->isize = (u_int16_t) (stbuf.st_size & 0xffff);
+           t6->isize0 = (u_int8_t) ((stbuf.st_size>>16) & 0xff);
+                                       /* Fix annoying bug in V5/V6 ctime() */
+           fixv6time(&(stbuf.st_atime));
+           fixv6time(&(stbuf.st_mtime));
+           copylong(t6->atime, stbuf.st_atime);
+           copylong(t6->mtime, stbuf.st_mtime);
+#if 0
+           buf = (char *) &(t6->atime);
+           buf2 = (char *) &(stbuf.st_atime);
+           buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
+           buf = (char *) &(t6->mtime);
+           buf2 = (char *) &(stbuf.st_mtime);
+           buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
+#endif
+       } else {
+           t = (struct tr_v7stat *) buf2;
+           t->st_dev = stbuf.st_dev;
+           t->st_ino = stbuf.st_ino;
+           t->st_mode = stbuf.st_mode;
+           t->st_nlink = stbuf.st_nlink;
+           t->st_uid = stbuf.st_uid;
+           t->st_gid = stbuf.st_gid;
+           t->st_rdev = stbuf.st_rdev;
+           copylong(t->st_size, stbuf.st_size);
+           copylong(t->st_atim, stbuf.st_atime);
+           copylong(t->st_mtim, stbuf.st_mtime);
+           copylong(t->st_ctim, stbuf.st_ctime);
+#if 0
+           buf = (char *) &(t->st_size);
+           buf2 = (char *) &(stbuf.st_size);
+           buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
+           buf = (char *) &(t->st_atim);
+           buf2 = (char *) &(stbuf.st_atime);
+           buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
+           buf = (char *) &(t->st_mtim);
+           buf2 = (char *) &(stbuf.st_mtime);
+           buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
+           buf = (char *) &(t->st_ctim);
+           buf2 = (char *) &(stbuf.st_ctime);
+           buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
+#endif
+       }
+       break;
+    case S_UTIME:
+       utv[0].tv_usec = utv[1].tv_usec = 0;
+       copylong(dspace[uarg2], utv[0].tv_sec);
+       copylong(dspace[uarg2+4], utv[1].tv_sec);
+       buf = xlate_filename(&dspace[uarg1]);
+#if 0
+       buf2 = &dspace[uarg2];
+       buf3 = (char *) &(utv[0].tv_sec);
+       buf3[0]= buf2[2]; buf3[1]= buf2[3]; buf3[2]= buf2[0]; buf3[3]= buf2[1];
+
+       buf2 += 4;
+       buf3 = (char *) &(utv[1].tv_sec);
+       buf3[0]= buf2[2]; buf3[1]= buf2[3]; buf3[2]= buf2[0]; buf3[3]= buf2[1];
+#endif
+
+       i = utimes(buf, utv); break;
+    case S_UNLINK:
+       buf = xlate_filename(&dspace[uarg1]);
+       i = unlink(buf); break;
+    case S_OPEN:
+       buf = xlate_filename(&dspace[uarg1]);
+
+       i = stat(buf, &stbuf);  /* If file is a directory */
+       if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
+           i = open_dir(buf);
+           fmode = "w+";
+            TrapDebug((dbg_file, "(dir) on %s return %d ",buf,i));
+       } else {
+           switch (sarg2) {
+             case 0: sarg2 = O_RDONLY; fmode = "r"; break;
+             case 1: sarg2 = O_WRONLY; fmode = "w"; break;
+             default: sarg2 = O_RDWR; fmode = "w+"; break;
+           }
+           i = open(buf, sarg2);
+            TrapDebug((dbg_file, " on %s return %d ",buf,i));
+       }
+
+#ifdef STREAM_BUFFERING
+       if (i==-1) break;
+#if 0
+       /* Now get its stream pointer if possible */
+       /* Can someone explain why fdopen doesn't work for O_RDWR? */
+       if (ValidFD(i) && !isatty(i) && (sarg2!=O_RDWR)) {
+           stream[i] = fdopen(i, fmode); streammode[i]=fmode;
+       }
+#endif
+       stream[i] = fdopen(i, fmode); streammode[i]=fmode;
+#endif
+       break;
+    case S_MKNOD:
+       buf = xlate_filename(&dspace[uarg1]);
+
+       if ((uarg2 & 077000) == 040000) {
+               /* It's a directory creation */
+               i= mkdir(buf, uarg2 & 0777);
+       } else
+               i = mknod(buf, uarg2, sarg3);
+       break;
+    case S_CHMOD:
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chmod(buf, uarg2); break;
+    case S_KILL:
+       i = kill(sarg1, sarg2); break;
+    case S_CHOWN:
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chown(buf, sarg2, sarg3); break;
+    case S_PIPE:
+       i = pipe(pfd);
+       if (i == -1) break;
+#ifdef STREAM_BUFFERING
+       if (ValidFD(pfd[0])) {
+               stream[pfd[0]] = fdopen(pfd[0], "r");
+               streammode[pfd[0]]= "r";
+       }
+       if (ValidFD(pfd[1])) {
+               stream[pfd[1]] = fdopen(pfd[1], "w");
+               streammode[pfd[1]]= "w";
+       }
+#endif
+       i = pfd[0]; regs[1] = pfd[1]; break;
+    case S_CHROOT:
+       buf = xlate_filename(&dspace[uarg1]);
+       if (buf == NULL) { i=-1; errno=ENOENT; break; }
+       set_apout_root(buf);
+       i=0; break;
+    case S_CHDIR:
+       buf = xlate_filename(&dspace[uarg1]);
+       i = chdir(buf); break;
+    case S_CREAT:
+       buf = xlate_filename(&dspace[uarg1]);
+       i = creat(buf, sarg2);
+#ifdef STREAM_BUFFERING
+       if (i==-1) break;
+       if (ValidFD(i)) {
+               stream[i] = fdopen(i, "w");
+               streammode[i]= "w";
+       }
+#endif
+       break;
+    case S_EXECE:
+       i= trap_exec(1); break;
+       
+    case S_EXEC:
+       i= trap_exec(0); break;
+    case S_WAIT:
+       i = wait(&pid);
+       if (i == -1) break;
+       regs[1] = pid; break;
+    case S_FORK:
+       pid = getpid();
+       i = fork();
+       switch (i) {
+           /* Error, inform the parent */
+       case -1: break;
+           /* Child gets ppid in r0 */
+       case 0: i = pid; break;
+           /* Parent: Skip child `bf', pid into r0 */
+       default: regs[PC] += 2; 
+       }
+       break;
+    case S_GETUID:
+       i = geteuid(); regs[1] = i;
+       i = getuid(); break;
+    case S_GETPID:
+       i = getpid(); break;
+    case S_GETGID:
+       i = getegid(); regs[1] = i;
+       i = getgid(); break;
+    case S_SETUID:
+       i = setuid(sarg1); break;
+    case S_SETGID:
+       i = setgid(sarg1); break;
+    default:
+       if (trapnum>S_CHROOT) {
+         fprintf(stderr,"Apout - unknown syscall %d at PC 0%o\n",
+                                                       trapnum,regs[PC]);
+       } else {
+         fprintf(stderr,"Apout - the %s syscall is not yet implemented\n",
+                                               v7trap_name[trapnum]);
+       }
+       exit(1);
+    }
+
+       /* Set r0 to either errno or i, */
+       /* and clear/set C bit */
+
+    if (i == -1) {
+       SET_CC_C();
+       TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
+    } else {
+       CLR_CC_C(); regs[0]=i;
+#ifdef DEBUG
+       if (trap_debug) {
+         fprintf(dbg_file, "return %d\n", i);
+         fflush(dbg_file);
+       }
+#endif
+    }
+    return;
+}
+
+
+/* Translate V7 signal value to our value. */
+static int v7sig[] = {
+      0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGIOT, SIGEMT,
+      SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS, SIGPIPE, SIGALRM, SIGTERM
+};
+
+static int
+trap_exec(int want_env)
+{
+    int i;
+    u_int16_t cptr, cptr2;
+    char *buf, *name, *origpath;
+
+    origpath = strdup(&dspace[uarg1]);
+    name = xlate_filename(origpath);
+    TrapDebug((dbg_file, "%s Execing %s ", progname, name));
+
+    for (i=0;i<V7_NSIG;i++) signal(v7sig[i], SIG_DFL);
+
+    cptr=uarg2;
+
+    Argc=0; Envc=0;
+    while (Argc < MAX_ARGS) {
+       ll_word(cptr, cptr2);
+       if (cptr2 == 0)
+           break;
+       buf = &dspace[cptr2];
+       Argv[Argc++] = strdup(buf);
+       cptr += 2;
+       TrapDebug((dbg_file, "%s ", buf));
+    }
+    Argv[Argc] = NULL;
+    TrapDebug((dbg_file, "\n"));
+
+    if (want_env) {
+       cptr=uarg3;
+       while (Envc < MAX_ARGS) {
+           ll_word(cptr, cptr2);
+           if (cptr2 == 0)
+               break;
+           buf = &dspace[cptr2];
+           Envp[Envc++] = strdup(buf);
+           cptr += 2;
+       }
+    }
+    Envp[Envc] = NULL;
+
+    if (load_a_out(name, origpath, want_env) == -1) {
+       for (Argc--; Argc >= 0; Argc--) free(Argv[Argc]);
+       for (Envc--; Envc >= 0; Envc--) free(Envp[Envc]);
+       errno= ENOENT; return(-1);
+    }
+    run();                     /* Ok, so it's recursive, I dislike setjmp */
+    return(0);
+}
+
+/* 7th Edition reads directories as if they were ordinary files.
+ * The solution is to read the directory entries, and build a
+ * real file, which is passed back to the open call.
+ * Limitation: 32-bit inode numbers are truncated to 16-bit ones.
+ */
+static int
+open_dir(char *name)
+{
+    DIR *d;
+    char *tmpname;
+    int i;
+    struct dirent *dent;
+
+    struct old_direct {
+       int16_t d_ino;
+       int8_t d_name[14];
+    } odent;
+
+    d = opendir(name);
+    if (d == NULL) return (-1);
+    tmpname= strdup(TMP_PLATE);
+    i= mkstemp(tmpname);
+    if (i == -1) {
+       fprintf(stderr,"Apout - open_dir couldn't open %s\n", tmpname); exit(1);
+    }
+    unlink(tmpname); free(tmpname);
+
+    while ((dent = readdir(d)) != NULL) {
+       odent.d_ino = dent->d_fileno;
+       strncpy(odent.d_name, dent->d_name, 14);
+       write(i, &odent, 16);
+    }
+    closedir(d);
+    lseek(i, 0, SEEK_SET);
+    return (i);
+}
+
+static int
+trap_gtty(u_int16_t fd, u_int16_t ucnt)
+{
+    struct tr_sgttyb *sgtb;    /* used in GTTY/STTY */
+    struct termios tios;       /* used in GTTY/STTY */
+    int i;
+
+    i = tcgetattr(fd, &tios);
+    if (i == -1)
+       return i;
+    CLR_CC_C();
+    sgtb = (struct tr_sgttyb *) & dspace[ucnt];
+    sgtb->sg_ispeed = tios.c_ispeed;
+    sgtb->sg_ospeed = tios.c_ospeed;
+    sgtb->sg_erase = tios.c_cc[VERASE];
+    sgtb->sg_kill = tios.c_cc[VKILL];
+    sgtb->sg_flags = 0;
+    if (tios.c_oflag & OXTABS)
+       sgtb->sg_flags |= TR_XTABS;
+    if (tios.c_cflag & PARENB) {
+       if (tios.c_cflag & PARODD)
+           sgtb->sg_flags |= TR_ODDP;
+       else
+           sgtb->sg_flags |= TR_EVENP;
+    } else
+       sgtb->sg_flags |= TR_ANYP;
+    if (tios.c_oflag & ONLCR)
+       sgtb->sg_flags |= TR_CRMOD;
+    if (tios.c_lflag & ECHO)
+       sgtb->sg_flags |= TR_ECHO;
+    if (!(tios.c_lflag & ICANON)) {
+       if (!(tios.c_lflag & ECHO))
+           sgtb->sg_flags |= TR_CBREAK;
+       else
+           sgtb->sg_flags |= TR_RAW;
+    }
+    return 0;
+}
+static int
+trap_stty(u_int16_t fd, u_int16_t ucnt)
+{
+    struct tr_sgttyb *sgtb;    /* used in GTTY/STTY */
+    struct termios tios;       /* used in GTTY/STTY */
+    int i;
+
+    if (ucnt != 0) {
+       sgtb = (struct tr_sgttyb *) & dspace[ucnt];
+       tios.c_ispeed = sgtb->sg_ispeed;
+       tios.c_ospeed = sgtb->sg_ospeed;
+       tios.c_cc[VERASE] = sgtb->sg_erase;
+       tios.c_cc[VKILL] = sgtb->sg_kill;
+       if (sgtb->sg_flags & TR_XTABS)
+           tios.c_oflag |= OXTABS;
+       if (sgtb->sg_flags & TR_ODDP) {
+           tios.c_cflag |= PARENB;
+           tios.c_cflag &= ~PARODD;
+       }
+       if (sgtb->sg_flags & TR_EVENP)
+           tios.c_cflag |= PARENB | PARODD;
+       if (sgtb->sg_flags & TR_ANYP)
+           tios.c_cflag &= ~PARENB;
+       if (sgtb->sg_flags & TR_CRMOD)
+           tios.c_oflag |= ONLCR;
+       if (sgtb->sg_flags & TR_ECHO)
+           tios.c_lflag |= ECHO;
+       if (sgtb->sg_flags & TR_RAW) {
+           tios.c_lflag &= (~ICANON) & (~ECHO);
+           for (i = 0; i < NCCS; i++)
+               tios.c_cc[i] = 0;
+           tios.c_cc[VMIN] = 1;
+       }
+       if (sgtb->sg_flags & TR_CBREAK) {
+           tios.c_lflag &= (~ICANON);
+           tios.c_lflag |= ECHO;
+           for (i = 0; i < NCCS; i++)
+               tios.c_cc[i] = 0;
+           tios.c_cc[VMIN] = 1;
+       }
+       i = tcsetattr(fd, TCSANOW, &tios);
+       return (i);
+    } else
+       return (-1);
+}
+
+
+/* Where possible, deal with signals */
+static int v7signal(int sig, int val)
+{
+  if (sig>V7_NSIG) { errno=EINVAL; return(-1); }
+  if (v7sig[sig]==0) return(0);
+
+  switch(val) {
+    case V7_SIG_IGN:
+      return((int)signal(v7sig[sig], SIG_IGN));
+    case V7_SIG_DFL:
+      return((int)signal(v7sig[sig], SIG_DFL));
+    default:
+      return(0);      /* No handling of this as yet */
+  }
+}
+
+/* Workaround for bug in V5/V6 ctime() */
+static void fixv6time(time_t *t)
+{
+ struct tm *T;
+
+ T=gmtime(t);
+ if (T->tm_year>98) T->tm_year=98;
+ *t=timegm(T);
+}
diff --git a/v7trap.h b/v7trap.h
new file mode 100644 (file)
index 0000000..f8314b9
--- /dev/null
+++ b/v7trap.h
@@ -0,0 +1,229 @@
+/* v7trap.h - Deal with V7 trap instructions. Also do V5 and V6 syscalls.
+ *
+ * $Revision: 2.17 $
+ * $Date: 1999/12/26 08:16:33 $
+ */
+
+/* In this file, we list the trap number for each system call,
+ * and the structures associated with several of the systems
+ * calls in 7th Edition UNIX
+ */
+
+#define S_INDIR                0
+#define S_EXIT         1
+#define S_FORK         2
+#define S_READ         3
+#define S_WRITE                4
+#define S_OPEN         5
+#define S_CLOSE                6
+#define S_WAIT         7
+#define S_CREAT                8
+#define S_LINK         9
+#define S_UNLINK       10
+#define S_EXEC         11
+#define S_CHDIR                12
+#define S_TIME         13
+#define S_MKNOD                14
+#define S_CHMOD                15
+#define S_CHOWN                16
+#define S_BREAK                17
+#define S_STAT         18
+#define S_LSEEK                19
+#define S_GETPID       20
+#define S_MOUNT                21
+#define S_UMOUNT       22
+#define S_SETUID       23
+#define S_GETUID       24
+#define S_STIME                25
+#define S_PTRACE       26
+#define S_ALARM                27
+#define S_FSTAT                28
+#define S_PAUSE                29
+#define S_UTIME                30
+#define S_STTY         31
+#define S_GTTY         32
+#define S_ACCESS       33
+#define S_NICE         34
+#define S_FTIME                35
+#define S_SYNC         36
+#define S_KILL         37
+#define S_DUP          41
+#define S_PIPE         42
+#define S_TIMES                43
+#define S_PROF         44
+#define S_SETGID       46
+#define S_GETGID       47
+#define S_SIGNAL       48
+#define S_ACCT         51
+#define S_PHYS         52
+#define S_LOCK         53
+#define S_IOCTL                54
+#define S_EXECE                59
+#define S_UMASK                60
+#define S_CHROOT       61
+
+
+char *v7trap_name[]= {
+       "indir",
+       "exit",
+       "fork",
+       "read",
+       "write",
+       "open",
+       "close",
+       "wait",
+       "creat",
+       "link",
+       "unlink",
+       "exec",
+       "chdir",
+       "time",
+       "mknod",
+       "chmod",
+       "chown",
+       "break",
+       "stat",
+       "lseek",
+       "getpid",
+       "mount",
+       "umount",
+       "setuid",
+       "getuid",
+       "stime",
+       "ptrace",
+       "alarm",
+       "fstat",
+       "pause",
+       "utime",
+       "stty",
+       "gtty",
+       "access",
+       "nice",
+       "ftime",
+       "sync",
+       "kill",
+       "unknown",
+       "unknown",
+       "unknown",
+       "dup",
+       "pipe",
+       "times",
+       "prof",
+       "unknown",
+       "setgid",
+       "getgid",
+       "signal",
+       "unknown",
+       "unknown",
+       "acct",
+       "phys",
+       "lock",
+       "ioctl",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown",
+       "exece",
+       "umask",
+       "chroot"
+};
+
+
+struct tr_v7stat {
+    int16_t st_dev;
+    u_int16_t st_ino;
+    u_int16_t st_mode;
+    int16_t st_nlink;
+    int16_t st_uid;
+    int16_t st_gid;
+    int16_t st_rdev;
+    int8_t st_size[4];         /* Alignment problems */
+    int8_t st_atim[4];         /* Alignment problems */
+    int8_t st_mtim[4];         /* Alignment problems */
+    int8_t st_ctim[4];         /* Alignment problems */
+};
+
+struct tr_v6stat {
+       int16_t idev;           /* Device */
+       int16_t inum;
+       int16_t iflags;         /* Mode */
+       int8_t  inl;            /* Links */
+       int8_t  iuid;
+       int8_t  igid;
+       u_int8_t isize0;        /* Most significant 8 bits */
+       u_int16_t isize;
+       int16_t iaddr[8];       /* Not used, I hope! */
+       u_int32_t atime;        /* Alignment problems */
+       u_int32_t mtime;        /* Alignment problems */
+};
+
+struct tr_timeb {
+       u_int32_t time;
+       u_int16_t millitm;
+       int16_t  timezone;
+       int16_t  dstflag;
+};
+
+struct tr_sgttyb {
+       int8_t    sg_ispeed;              /* input speed */
+       int8_t    sg_ospeed;              /* output speed */
+       int8_t    sg_erase;               /* erase character */
+       int8_t    sg_kill;                /* kill character */
+       int16_t   sg_flags;               /* mode flags */
+};
+
+/*
+ * Values for sg_flags
+ */
+#define TR_TANDEM  01
+#define TR_CBREAK  02
+#define TR_LCASE   04
+#define TR_ECHO           010
+#define TR_CRMOD   020
+#define TR_RAW    040
+#define TR_ODDP           0100
+#define TR_EVENP   0200
+#define TR_ANYP           0300
+#define TR_XTABS   06000
+
+/*
+ * Values for signal
+ */
+#define V7_SIG_DFL 0
+#define V7_SIG_IGN 1
+
+#define V7_NSIG 15
+
+#define V7_SIGHUP  1   /* hangup */
+#define V7_SIGINT  2   /* interrupt */
+#define V7_SIGQUIT 3   /* quit */
+#define V7_SIGILL  4   /* illegal instruction (not reset when caught) */
+#define V7_SIGTRAP 5   /* trace trap (not reset when caught) */
+#define V7_SIGIOT  6   /* IOT instruction */
+#define V7_SIGEMT  7   /* EMT instruction */
+#define V7_SIGFPE  8   /* floating point exception */
+#define V7_SIGKILL 9   /* kill (cannot be caught or ignored) */
+#define V7_SIGBUS  10  /* bus error */
+#define V7_SIGSEGV 11  /* segmentation violation */
+#define V7_SIGSYS  12  /* bad argument to system call */
+#define V7_SIGPIPE 13  /* write on a pipe with no one to read it */
+#define V7_SIGALRM 14  /* alarm clock */
+#define V7_SIGTERM 15  /* software termination signal from kill */
+
+
+/* A union which will point at the trap args, so that
+ * we can get at the various args of different types
+ */
+typedef union {
+    int16_t   sarg[4];         /* Signed 16-bit args */
+    u_int16_t uarg[4];         /* Unsigned 16-bit args */
+} arglist;
+
+#define sarg1  V7A.sarg[0]
+#define sarg2  V7A.sarg[1]
+#define sarg3  V7A.sarg[2]
+#define sarg4  V7A.sarg[3]
+#define uarg1  V7A.uarg[0]
+#define uarg2  V7A.uarg[1]
+#define uarg3  V7A.uarg[2]
+#define uarg4  V7A.uarg[3]