--- /dev/null
+# $Header$
+
+This directory contains two programs:
+
+mkswitch:
+ C program, necessary for regenerating the giant switches
+ which are part of the INT project.
+
+mkfuncs:
+ shell script that can be used to generate new function
+ files, if a new implementation is needed.
+
+The first program reads an input file which holds the interpreter
+opcode table (as shown in the [IR-81] report appendix B),
+and creates an output file which contains an enormous switch
+file. This switch has entries for each possible opcode. It's
+possible to supply a third filename, which is the name of file
+where all functions will be stored. This is necessary if a new
+function implementation is needed.
+
+The first argument to mkswitch is the prefix to be used in the
+generated function names. For the interpreter proper this prefix
+is Do.
+
+The input file contains lines in the following format:
+
+ Mnemonic Flags Count First-number
+
+The created switch file will contain a switch, with each case
+having one of the following formats (? is the opcode):
+
+ 1) case ?: DoAz();
+ 2) case ?: DoBm(val);
+ 3) case ?: DoCs(hob, wsize);
+ 4) case ?: DoDXY(wsize);
+
+Ad 1) This format shows that the corresponding opcode does not
+ have an argument. Often the operand is popped from the
+ stack.
+
+ e.g. DoNOPz(), this performs the NOP instruction.
+
+Ad 2) This is the format for a mini. There is one implicit
+ argument (I) .
+
+ e.g. DoLOCm(1), this is the LOC 1 instruction.
+
+Ad 3) This format corresponds with a shortie. There is an implicit
+ argument (high order byte), and a one byte text argument
+ (low order byte). W equals 'wsize' (if a word multiple),
+ otherwise it equals '1'. H is the value of the high
+ order byte.
+
+ e.g. DoLOEs(2, wsize), these are all LOE instructions,
+ with all addresses in the range:
+ (512 * wordsize) . . (767 * wordsize).
+
+Ad 4) This format is used for opcodes with 2 or more text arguments,
+ and no implicit arguments. There are 6 types:
+
+ XY = l2: two byte negative or positive text argument.
+ XY = n2: two byte negative text argument.
+ XY = p2: two byte positive text argument.
+ XY = l4: four byte negative or positive text argument.
+ XY = n4: four byte negative text argument.
+ XY = p4: four byte positive text argument.
+
+ W equals 'wsize' (if a word multiple), otherwise it equals 1.
+
+ e.g. DoLDLp2(wsize), these are all LDL instructions, with
+ negative local offsets, which are word multiples.
+
+
+When two file arguments are given to mkswitch (input file and output file),
+only the switch is generated. If an additional third file name is
+given (another output file), this file is filled with all function
+calls in such a manner that mkfuncs will generate new function files.
+
+Mkfuncs expects two arguments, an input file generated by
+mkswitch and the name of a directory where the new function
+files are stored. These files (15) each represent one group (as
+proposed in [IR-81] sec 11.3) of instructions. Each file will
+contain all functions needed to implement that specific group
+of instructions. The functions will only contain a logging
+message, and a call to newPC() which is necessary to skip the
+arguments. The names of the generated files are: do_XXX.c, where
+XXX is the name of the corresponding instruction group.
+
--- /dev/null
+/*
+ Generates contents of opcode switch from ip_spec.t
+ Call is:
+ mkswitch prefix ip_spec.t cases [ functions ]
+
+ Note:
+ The u flag has been implemented by just copying and adjusting the
+ code for 2, which is almost identical to that for 4. When this has
+ stabilized, combine.
+*/
+
+/* $Header$ */
+
+#include <stdio.h>
+
+extern char *sprintf();
+extern FILE *popen();
+
+char *progname;
+
+FILE *ifp; /* Input File Pointer */
+FILE *ofp; /* Output File Pointer */
+FILE *ffp = 0; /* Function File Pointer */
+char *Prefix; /* Prefix for function name */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char mnem[8]; /* Mnemonic */
+ char flgs[8]; /* Flags */
+ char command[32];
+
+ progname = argv[0];
+
+ if (argc < 4 || argc >5) {
+ fatal("usage is: %s prefix ip_spec.t cases [ functions ]\n",
+ argv[0]);
+ }
+
+ Prefix = argv[1];
+
+ if ((ifp = fopen(argv[2], "r")) == 0) {
+ fatal("cannot open '%s' for reading\n", argv[2]);
+ }
+
+ if ((ofp = fopen(argv[3], "w")) == 0) {
+ fatal("cannot open '%s' for writing\n", argv[3]);
+ }
+
+ if (argc == 5) { /* Need to store functions */
+ sprintf(command, "sort | uniq > %s", argv[4]);
+ if ((ffp = popen(command, "w")) == 0) {
+ fatal("cannot popen '%s'\n", command);
+ }
+ }
+
+ /* Start reading the input file */
+ while (fscanf(ifp, "%s %s", mnem, flgs) >= 0) {
+ int i;
+ char *p;
+ char *base;
+ int cnt, first;
+
+ /* check flags */
+ for (p = flgs; *p; p++) {
+ if (!in("-ms2u4eNPwo", *p)) {
+ fatal("bad flags ip_spec: %s\n", flgs);
+ }
+ }
+
+ if ( in(flgs, '-')
+ + in(flgs, 'm')
+ + in(flgs, 's')
+ + in(flgs, '2')
+ + in(flgs, 'u')
+ + in(flgs, '4')
+ != 1
+ ) {
+ fatal("duplicate or missing opcode flag ip_spec: %s\n",
+ flgs);
+ }
+
+ if ( in(flgs, 'N')
+ + in(flgs, 'P')
+ > 1
+ ) {
+ fatal("duplicate restriction flags ip_spec: %s\n", flgs);
+ }
+
+ /* capitalize mnemonic */
+ for (p = mnem; *p; p++) {
+ *p += ('A' - 'a');
+ }
+
+ /* scan rest of line */
+ if ( in(flgs, '-')
+ || in(flgs, '2')
+ || in(flgs, 'u')
+ || in(flgs, '4')
+ ) {
+ fscanf(ifp, " %d \n", &first);
+ }
+ else {
+ fscanf(ifp, " %d %d \n", &cnt, &first);
+ }
+
+ /* determine base */
+ if (in(flgs, 'e')) /* Escaped (secondary) opcode */
+ base = "SEC_BASE";
+ else
+ if (in(flgs, '4')) /* Escaped (tertiary) opcode */
+ base = "TERT_BASE";
+ else
+ base = "PRIM_BASE";
+
+ /* analyse the opcode */
+ if (in(flgs, '-')) { /* No arguments */
+ NoArgs(base, first, mnem);
+ } else if (in(flgs, 'm')) { /* Mini */
+ for (i = 0; i<cnt; i++) {
+ Mini(i, flgs, base, first, mnem);
+ }
+ } else if (in(flgs, 's')) { /* Shortie */
+ for (i = 0; i<cnt; i++) {
+ Shortie(i, flgs, base, first, mnem);
+ }
+ } else if (in(flgs, '2')) { /* Two byte signed */
+ TwoSgn(flgs, base, first, mnem);
+ } else if (in(flgs, 'u')) { /* Two byte unsigned */
+ TwoUns(flgs, base, first, mnem);
+ } else if (in(flgs, '4')) { /* Four byte signed */
+ FourSgn(flgs, base, first, mnem);
+ } else {
+ fatal("no opcode flag in ip_spec %s\n", flgs);
+ }
+ }
+ exit(0);
+}
+
+NoArgs(base, first, mnem)
+ char *base;
+ int first;
+ char *mnem;
+{
+ fprintf(ofp, "\t\tcase %s+%d:\t%s%sz(); break;\n",
+ base, first, Prefix, mnem);
+ if (ffp) {
+ fprintf(ffp, "%s%sz() {", Prefix, mnem);
+ fprintf(ffp, "LOG((\"@ %s%sz()\"));}\n", Prefix, mnem);
+ }
+}
+
+Mini(i, flgs, base, first, mnem)
+ int i;
+ char *flgs;
+ char *base;
+ int first;
+ char *mnem;
+{
+ char arg[16];
+ int newi = in(flgs, 'N') ? (-i-1) : in(flgs, 'o') ? (i+1) : i;
+
+ switch (newi) {
+ case -1:
+ sprintf(arg, "%s",
+ in(flgs, 'w') ? "-wsize" : "-1L");
+ break;
+ case 0:
+ sprintf(arg, "0L");
+ break;
+ case 1:
+ sprintf(arg, "%s",
+ in(flgs, 'w') ? "wsize" : "1L");
+ break;
+ default:
+ sprintf(arg, "%dL%s",
+ newi, in(flgs, 'w') ? "*wsize" : "");
+ break;
+ }
+ fprintf(ofp, "\t\tcase %s+%d:\t%s%sm(%s); break;\n",
+ base, first+i, Prefix, mnem, arg);
+ if (ffp) {
+ fprintf(ffp, "%s%sm(arg) long arg; {",
+ Prefix, mnem);
+ fprintf(ffp, "LOG((\"@ %s%sm(%%d)\", arg));}\n",
+ Prefix, mnem);
+ }
+}
+
+Shortie(i, flgs, base, first, mnem)
+ int i;
+ char *flgs;
+ char *base;
+ int first;
+ char *mnem;
+{
+ char arg[16];
+ int newi = in(flgs, 'N') ? (-i-1) : in(flgs, 'o') ? (i+1) : i;
+
+ sprintf(arg, "%dL, %s", newi, (in(flgs, 'w') ? "wsize" : "1L"));
+ fprintf(ofp, "\t\tcase %s+%d:\t%s%ss(%s); break;\n",
+ base, first+i, Prefix, mnem, arg);
+ if (ffp) {
+ fprintf(ffp, "%s%ss(hob, wfac) long hob; size wfac; {",
+ Prefix, mnem);
+ fprintf(ffp, "LOG((\"@ %s%ss(%%d)\", hob, wfac));",
+ Prefix, mnem);
+ fprintf(ffp, " newPC(PC+1);}\n");
+ }
+}
+
+TwoSgn(flgs, base, first, mnem)
+ char *flgs;
+ char *base;
+ int first;
+ char *mnem;
+{
+ char *xy = in(flgs, 'P') ? "p2" : in(flgs, 'N') ? "n2" : "l2";
+
+ fprintf(ofp, "\t\tcase %s+%d:\t%s%s%s(%s); break;\n",
+ base, first, Prefix, mnem, xy,
+ in(flgs, 'w') ? "wsize" : "1L");
+ if (ffp) {
+ fprintf(ffp, "%s%s%s(arg) long arg; {", Prefix, mnem, xy);
+ fprintf(ffp, "LOG((\"@ %s%s%s(%%d)\", arg));",
+ Prefix, mnem, xy);
+ fprintf(ffp, " newPC(PC+2);}\n");
+ }
+}
+
+TwoUns(flgs, base, first, mnem)
+ char *flgs;
+ char *base;
+ int first;
+ char *mnem;
+{
+ char *xy = "u";
+
+ fprintf(ofp, "\t\tcase %s+%d:\t%s%s%s(%s); break;\n",
+ base, first, Prefix, mnem, xy,
+ in(flgs, 'w') ? "wsize" : "1L");
+ if (ffp) {
+ fprintf(ffp, "%s%s%s(arg) long arg; {", Prefix, mnem, xy);
+ fprintf(ffp, "LOG((\"@ %s%s%s(%%d)\", arg));",
+ Prefix, mnem, xy);
+ fprintf(ffp, " newPC(PC+2);}\n");
+ }
+}
+
+FourSgn(flgs, base, first, mnem)
+ char *flgs;
+ char *base;
+ int first;
+ char *mnem;
+{
+ char *xy = in(flgs, 'P') ? "p4" : in(flgs, 'N') ? "n4" : "l4";
+
+ fprintf(ofp, "\t\tcase %s+%d:\t%s%s%s(%s); break;\n",
+ base, first, Prefix, mnem, xy,
+ in(flgs, 'w') ? "wsize" : "1L");
+ if (ffp) {
+ fprintf(ffp, "%s%s%s(arg) long arg; {", Prefix, mnem, xy);
+ fprintf(ffp, "LOG((\"@ %s%s%s(%%d)\", arg));",
+ Prefix, mnem, xy);
+ fprintf(ffp, " newPC(PC+4);}\n");
+ }
+}
+
+int
+in(flgs, c)
+ char *flgs;
+ char c;
+{
+ while (*flgs)
+ if (c == *flgs++)
+ return 1;
+ return 0;
+}
+
+fatal(fmt, str)
+ char *fmt;
+ char *str;
+{
+ fprintf(stderr, "%s, (fatal error): ", progname);
+ fprintf(stderr, fmt, str);
+ fprintf(stderr, "\n");
+ exit(1);
+}