// £123 | \ # various characters to persuade gedit to accept the file // Translator for Leo III Intercode // The output file is both a listing file and is acceptable as binary program input to leo3.c // Author: David Holdsworth -- David.Holdsworth@bcs.org // the Intercode is in columns and the first line names the columns in lower case (all Intercode is in upper case) // only the initial letter of the heading is recognised, as follows: // s -> serialno, a -> action, r -> reference, i -> item, // d -> discriminant, m -> modifier, l -> literal, c -> comment, q -> query // any line in which the first cell starts with a lower case letter can redefine the columns, as must the first line // The line of stars is the point at which the code generated by gen2.c is inserted // This code is generated from the language definition in intercode.txt // This translator also fulfills much of the function of the loader, in that it operates with absolute addresses // and creates chapter 0 and gives each of the other chapters a procedure 0. // Its only function is in an initial translation of the copy-typed listing of the Intercode Translator 08000. // Subsequent translations can then use the result of this program, and then the real Translator run under leo3.c // Routes have channel no = route no, i.e. filenum * 9. // Each route has a pseudo route one bigger. // All rights reserved #include #include #include // arbitrary non-zero values for equality tests #define CONSTSHORT 900 #define CONSTLONG 901 #define PROCMODE 800 #define TABLEMODE 700 #define MAXCHAPS 15 #define CHAP0START 160 // chapter zero generated by translator #define MEMSTART 5600 // start of regular chapters #define PROC0VAR 6 // variable space in proc0, used for register dump when enter master, eg. action 40 #define MAXFILES 20 // just a guess // The modification group is fixed, and must be the same as initially set in the emulator #define MODGRP 1 int modinfo = 0; // I think that this is always the same unless we have multiple overlay points int traninfo = 0; // location of transit area list in procedure 0 int verbosity = 0; int hyperlinks = 0; // insert hyperlinks for refs (and for instructions if > 1) int nobuffswap = 0; // exploit the fact that emulator will not swap I/O areas char *fmt = "%6s|%3s|%4s|%5s|%1s|%1s|%7s|%s\n"; char separator = ','; char *ccstr[], *icstr[]; char buff[1000]; char **src[25000]; // source code line by line, starting with PROCR 100 char *sectcmt[100]; // comments on section lines int sectlen[100]; // lengths of sections int srcp = 0; int addr[25000]; // address at which generated code for this source line starts int procstart[1000]; // source line at which this procedure starts ... // ... or short word address of start of each section int procchap[1000]; // number of chapter for this procedure or section int chapaddr[MAXCHAPS]; // in pass 2 it is the base address of the chapter in real memory int chapsize[MAXCHAPS]; // total size of chapter int proc0size[MAXCHAPS]; // size of procedure 0 int secsize[MAXCHAPS]; // total size of sections int equivchap[MAXCHAPS]; // equivalent chapters in overlay scheme // int codebase[MAXCHAPS]; // relative base of code of each chapter ... int ovrindex[MAXCHAPS]; // gives start proc of each overlay (cannot be more overlays than chapters) int padding[MAXCHAPS]; // space to align sections with action 168 int curchap; // current chapter int curovr; // current overlay in pass 1 -- incomplete implementation int olcount; // count of overlays for loader int trcount = 0; // count of transit areas - calculated in the heading int icAct = -1; // Intercode action currently being processed char addrInd; // indicator for address resolution method when serial does not match offset char *filename[MAXFILES]; int fileannex[MAXFILES]; // location of annex in chapter 0 int filechap[MAXFILES]; // chapter associated with this file int filetype[MAXFILES]; // type of file int transect[MAXFILES]; // transit area associated(?) with this file (assume in same order as files?) int transize[MAXFILES]; // size of the above in short words int sercol = 0; int actcol = 0; int refcol = 4; int itemcol = 8; int disccol = 13; int modcol = 15; int litcol = 17; int cmtcol = 29; char *actinfo = "???"; char **head = NULL; // column headings to be repeated each PROCR int loc; // location to put the next stuff int entrypoint = 0; int absent = -10000; // really constants, but avoiding C pre-processor int alpha = -10001; int pass = 0; char *wline[30]; // working buffer for line assembly char *lastline[] = { "99999", "99999", "99999", "99999", "99999", "99999", "99999" }; FILE *fout; int swref(int s); // find the memory location for switch s or simulated modifier void notImplemented(char *s); // flag non-implemented instructions int memref(int r, int i, char *l); // calculates an N for a memory reference // generating extra instructions if needed int crash(int a, int b) // forcibly die diagnostically { char *zz, nogo; zz = NULL; fclose(fout); // write away end of output nogo = *zz; // deliberate crash } int kcheck = -9876; void check() // called for each instruction { int p = 353; if ( srcp < 3 ) return; return; // can do diagnostic checks here if ( procstart[p] != kcheck ) fprintf(fout, " Check: procstart[%d] is now %d\n", p, kcheck = procstart[p]); return; fprintf(fout, "Check:\n %s %s\n %s %s\n %s %s\n", src[0][sercol], src[0][actcol], src[1][sercol], src[1][actcol], src[2][sercol], src[2][actcol]); } defineCols(char **h) // define the columns based on the lower case names in line // result is a new heading line for printing purposes { int i = -1; char *s; while ( (s = h[++i]) != NULL ) if ( *s == 's' ) sercol = i; else if ( *s == 'a' ) actcol = i; else if ( *s == 'r' ) refcol = i; else if ( *s == 'i' ) itemcol = i; else if ( *s == 'd' ) disccol = i; else if ( *s == 'm' ) modcol = i; else if ( *s == 'l' ) litcol = i; else if ( *s == 'c' ) cmtcol = i; else if ( *s != 0 ) fprintf(stderr, "Heading col %s unrecognised\n", s); head = h; } char **readline(FILE *fin) // read a line of source and split into fields { int i = 0; unsigned char *b; unsigned char *p; int smark = 0; char **res; if ( fgets(buff, 999, fin) == NULL ) return NULL; if ( strlen(buff) < 3 ) // ignore short lines -- probably blank return readline(fin); // return the next line b = strdup(buff); wline[0] = b; p = b - 1; while ( *++p != 0 ) if ( smark != 0 ) // inside quotes { if ( *p == '\"' ) // if end of quotes { smark = 0; wline[i] ++; // skip the quote at the start *p = 0; // mark the end of the string here } } else if ( *p == separator || *p == '\n' ) { *p = 0; // comma not in quotes or end of line wline[++i] = p + 1; } else if ( *p < ' ' ) *p = 0; // falling off the end of a string or carriage return else if ( *p == '\"' ) // start of string smark = 1; while ( i < 9 ) wline[++i] = NULL; // pad fields for short record wline[++i] = NULL; // mark end of fields wline[++i] = NULL; // mark end of fields res = (char **)malloc(sizeof(char*) * ++i); while ( --i >= 0 ) res[i] = wline[i]; if ( res[actcol] == NULL ) res[actcol] = "163"; if ( **res < 'a' ) // if lower case letter, defines columns return res; // otherwise return line of input defineCols(res); return readline(fin); // return the next line } void doline(char **l) // do the business on line l { fprintf(fout, "%3d ", srcp); fprintf(fout, fmt, l[sercol], l[actcol], l[refcol], l[itemcol], l[disccol], l[modcol], l[litcol], l[cmtcol]); } char *reflink(char *refchs, int a, int n) // delivers the string to print in the reference position // if hyperlinks is set and n >= 0 this is a hot link { char *ws = "HREF=#"; int ref; if ( a == -2 ) // start of proc, const or tab ws = "NAME="; // create name anchor if ( hyperlinks != 0 && (ref = atoi(refchs)) > 0 && ref < 999 && n >= 0 ) { refchs = buff+strlen(buff)+1; if ( ref >= 100 ) // PROCR, TABLE or CONST sprintf(refchs, " %d", ws, ref, ref); else if ( ref >= 10 ) // section sprintf(refchs, " %d", ref, ref); else // section number of just one digit sprintf(refchs, " %d", ref, ref); } return refchs; } void codeOut(int a, int d, int m, int n, char **srcline) // output one instruction { if ( pass == 2 ) { int lloc = loc + chapaddr[curchap]; if ( a == 999 ) // unimplemented instruction strcpy(buff, "0/0/0 0 act unimp "); // put a halt order when the action is not yet implemented else if ( m >= 4 ) // simulated modifiers not implemented by this routine strcpy(buff, "0/0/0 0 mod unimp "); // put a halt order when the address was not resolved else if ( n < 0 ) // addressing error strcpy(buff, "0/0/0 0 bad addr "); // put a halt order when the address was not resolved // else if ( (a&0xFFFE0) != 0 ) // diag !!!!! // sprintf(buff, " %s duff ", srcline[sercol]); else { if ( a < 0 ) // a < 0 used for source lines that do not generate code buff[0] = 0; else if ( d < 2 ) // not alpha mode memory access sprintf(buff, "%d/%d/%d %d", a, d, m, n); else sprintf(buff, "%d/1/%d %d", a, m, n+1); // alpha mode access memset(buff+strlen(buff), ' ', 20); } if ( lloc >= 10000 ) buff[17] = 0; if ( lloc >= 1000 ) buff[18] = 0; else buff[19] = 0; if ( srcline == NULL ) fprintf(fout, "%s [%d] %c\n", buff, lloc, addrInd); // source is only printed once when multiple instructions are generated else if ( *actinfo == '!' ) // must be a table entry fprintf(fout, "%s [%d] %6s %4s %2s %4s %2s %1s %1s %2s %2s %2s %2s %1s %1s %1s %s\n", buff, lloc, srcline[sercol], reflink(srcline[1], 0, 0), srcline[2], srcline[3], srcline[4], srcline[5], srcline[6], srcline[7], srcline[8], srcline[9], srcline[10], srcline[11], srcline[12], srcline[13], srcline[14], actinfo); else if ( *actinfo == ' ' ) // must be a constant fprintf(fout, "%s [%d] %6s %-21s %-32s %s\n", buff, lloc, srcline[sercol], srcline[refcol], srcline[cmtcol], actinfo); else // must be a PROCR { char *refchs = srcline[refcol]; char *ws = "HREF=#"; int ref; if ( a == -2 ) // start of proc, const or tab ws = "NAME="; // create name anchor if ( hyperlinks != 0 && (ref = atoi(refchs)) > 0 && ref < 999 && n >= 0 ) { refchs = buff+strlen(buff)+1; if ( ref >= 100 ) // PROCR, TABLE or CONST sprintf(refchs, " %d", ws, ref, ref); else if ( ref >= 10 ) // section sprintf(refchs, " %d", ref, ref); else // section number of just one digit sprintf(refchs, " %d", ref, ref); } fprintf(fout, "%s [%d] %c %5s %3s %4s %5s %1s %-2s %7s %-33s %s\n", buff, lloc, addrInd, srcline[sercol], srcline[actcol], refchs, srcline[itemcol], srcline[disccol], srcline[modcol], srcline[litcol], srcline[cmtcol], actinfo); } } if ( a >= 0 ) loc++; if ( pass == 2 && n >= 8192 ) // something has gone very wrong { fprintf(fout, "Address too big: %d (%X) at %s\n", n, n, srcline[sercol]); printf("Bad address generated at %s\n", srcline[sercol]); crash(atoi(srcline[sercol]), n); } } void codeOutSM(int a, int d, int mod, int ref, int item, char *lit, char **line) // output one instruction usually, but deals with simulated modifiers // and also absolute addresses indicated by ref = 0 // for actions 0 to 5, 36, 37 (and maybe more later) { if ( ref == absent ) ref = 0; if ( mod < 4 ) // not simulated modifier { if ( ref == 0 ) // absolute addressing { loc ++; if ( pass == 2 ) fprintf(fout, "24/0/3 0 Extra code needed to address absolute\n"); // uses zero word in procedure 0 } codeOut(a, d, mod, memref(ref, item, lit), line); // N.B. for ref = 0, memref returns item as the address } else if ( ref == 18 ) // rather a kludge to address section 18 in division 0 { int w = addrcalc(ref, item, lit); codeOut(24, 0, 3, swref(1000+mod), line); // modify next codeOut(a, d, 0, w, NULL); // programmed instruction } else // simulated modifier { int lloc = loc; int w = memref(ref, item, lit); if ( lloc != loc ) // code has been generated to access other division notImplemented("simulated modifier in other division"); else { item = 1; // mod field of 24 order if ( ref == 0 ) // absolute addressing item = 3; // suppress division on 24 instruction codeOut(24, 0, item, swref(1000+mod), line); // modify next codeOut(a, d, 0, w, NULL); // programmed instruction } } } void codeOut2402(int mod, int ref, int item, char **line) // output instruction(s) to load address into A, deals with simulated modifiers // for use internally in things such as BULK COPY { if ( ref == absent ) ref = 0; if ( mod == 0 ) // no modifier { if ( ref == 0 ) // absolute addressing { loc ++; if ( pass == 2 ) fprintf(fout, "24/0/3 0 Extra code needed to address absolute\n"); } // uses zero word in procedure 0 codeOut(24, 0, 2, memref(ref, item, "0"), line); // N.B. for ref = 0, memref returns item as the address } else if ( mod < 4 ) // not simulated modifier { int lloc = loc; int w = memref(ref, item, "0"); if ( lloc == loc ) // no code has been generated to access other division or transit area { codeOut(24, 0, 0, modinfo + mod, line); codeOut(24, 0, 2, w, NULL); // so we can premodifier with the real modifier } else // need to add on the value of the modifier explicitly { int wl = proc0size[curchap]; // W/L to hold computed destination address codeOut(24, 0, 2, w, line); // desired address of transit area or other chap codeOut(0, 1, 0, wl, NULL); // Copy ABC so as to preserve C codeOut(0, 0, 3, 0, NULL); // Set binary to ensure that ADD works OK codeOut(24, 0, 3, modinfo, NULL); // accessed via pointer proc 0 codeOut(4, 0, 0, mod + mod, NULL); // add the value of the modifier codeOut(0, 0, 3, wl+4, NULL); // Restore C } } else // simulated modifier { int lloc = loc; int w = memref(ref, item, "0"); if ( lloc != loc ) // code has been generated to access other division notImplemented("simulated modifier in other division"); else { if ( w == 0 ) // ref = 0, item = 0 codeOut(6, 0, 0, swref(1000+mod), line);// load address from store else { item = 1; // mod field of 24 order if ( ref == 0 ) // absolute addressing { actinfo = "address absolute"; item = 3; // suppress division on 24 instruction } codeOut(24, 0, item, swref(1000+mod), line); // modify next codeOut(24, 0, 2, w, NULL); } } } } // ---------------------------------------------------------- // Setting up chapter 0 and procedure 0 int xbuff[500]; // buffer for assembling chapter 0 and procedure 0 char charval[256]; // Leo III cahracter values indexed by ASCII void valsOut(int *buff, int n, int addr) // output a list of constant values { int i, v; for ( i = 0; i>16, (v>>15)&1, (v>>13)&3, v&017777, i + addr, v); } } void chapter0() // set up chapter zero and output data for loading { int zzz = 0; // temporary pad int i; memset(xbuff, 0, 500 * sizeof(int)); xbuff[0] = 0; // C = Floating point indicator (= 0 unless floating point is required). xbuff[1] = MODGRP; // C + 1 = Modification group indicator (= 0 if mod. group is not // required, otherwise allotted mod. group). xbuff[2] = 3; // C + 2 = Priority class (as specified on programme heading sheet). xbuff[3] = 10; // C + 3 = Total number of chapters xbuff[4] = 3; // C + 4 = Number of chapters loaded initially (including the special chapter). xbuff[5] = 4; // C + 5 = Number of files. xbuff[6] = trcount; // C + 6 = Number of transit areas (i.e. sections). xbuff[7] = 0; // C + 7 = Number of alternate routes. xbuff[8] = entrypoint; // C + 8 = Entry point in absolute form. xbuff[9] = 2; // C + 9 = Chapter in which first instruction is located. xbuff[10] = 7; // C + 10 = Allocated tag number. xbuff[11] = 0; // C + 11 = Trials indicator (= 15 for trial under P.T.S.). xbuff[12] = 0x080; // C + 12 = Programme identity number (decimal). xbuff[13] = 0x8813; // C + 13 = Programme serial number (decimal). xbuff[14] = 1; // C + 14 = Number of last parameter + 1. xbuff[15] = 1; // C + 15 = Run and rerun number. xbuff[16] = 6; // C + 16' = 'Store modification register constant' (2 * number of // chapters initially /0). xbuff[18] = 62; // C + 18' = 'Routes modification register constant' (2 * number of // routes + number of sections) /0). xbuff[20] = zzz; // C + 20' = Allocated storage table. Entries are only held for initial // to chapters (including the special chapter). Each entry // C + 32' occupies one long word of storage as below: // Q10 Q6 Q5 Q1 // |End of chapter + 2 | Start of chapter | // C + 34' = Allocated routes and sections table. Each entry occupies i = trcount; // to one long word of storage as below: while ( --i >= 0 ) // C + 64' { xbuff[34+i+i+1] = // Q10 Q9 Q6 Q5 Q3 and Q4 Q1 and Q2 charval[filename[i][0]&255] *256 + charval[filename[i][1]&255]; // | |File identity | Route|128 or |Alloc. | xbuff[34+i+i] = // | | | Type |alloc. alt.|route no.| (filetype[i] << 16) // | | | |route no. | | + 0x8009 + i*9; } // The route numbers are held in channel and route form. All // entries except the alternate route (which is 128) and route // number are zero in the case of transit areas. xbuff[66] = zzz; // C + 66' = Annexe and section. An entry is held for each annexe or // to section and an entry occupies one long word divided as // C + 96' below: // Q10 Q6 Q5 Q1 // |End of annexe | Start of annexe | xbuff[98] = zzz; // C + 98' = Parameter table. This table specifies the parameters to // to be added as the Master Programme loads the programme. // C + 138' xbuff[140] = zzz; // C + 140' = These are used by the Master Programme for working locations // to associated with the programme. // C + 198' fprintf(fout, "X%d chapter 0 is here\n", CHAP0START); fprintf(fout, "L%d loading chapter 0\n", CHAP0START); valsOut(xbuff, 200, CHAP0START); } void precedure0(int ch) // set up a precedure zero at the start of a chapter and output data for loading in pass 2 { int zzz = 0; // temporary pad int i; int j = 0; // counter in xbuff int v; memset(xbuff, 0, 500 * sizeof(int)); // S = start address of chapters: // S = 0 always available to give access to division 0 xbuff[j++] = 0; // S+1 = 15-bit start address of first chapter // S+2 = 13-bit start address of first chapter // S+2C-1 = 15-bit start address of Cth chapter (programme has C chapters) // S+2C = 13-bit start address of Cth chapter // ---------------------------------- i = 1; // seems that chapter 0 is special and goes at the end while ( i < 3 && (v = chapaddr[i++]) >= 0 ) // should we do all chapters ... { xbuff[j++] = v & 0x7FFF; // .. or just the current overlay xbuff[j++] = v & 0x1FFFF; } xbuff[j++] = CHAP0START; // chap 0 address at the end ??? xbuff[j++] = CHAP0START; // chap 0 address at the end ??? // ---------------------------------- // S+2C+1 = Route number of first file // S+2C+R = Route number of Rth file (programme has R files) i = 0; while ( filename[i++] != NULL ) xbuff[j++] = i * 9; // bogus I/O routes, channel = route = i // ---------------------------------- // next pseudo route info -- pseudo route is R+1 // S+2C+R+1 = Area modifier of first I/P, O/P section (P1) // S+2C+R+2 = - (64+P1) // S+2C+R+2T-1 = Area modifier of Tth I/P, O/P section (programme has // T I/P, O/P sections) // S+2C+R+2T = - (64+PT) i = -1; traninfo = j; // address in this chapter where transit info is stored while ( filename[++i] != NULL ) { v = transect[i]; // section number of transit area xbuff[j++] = 9*i + 10; // seems to make sense along with code at 15406 etc xbuff[j++] = 9*i + 0x10004A; // indirection via pseudo route pointer } // S+2C+R+2T+1 = 8m' (m' is the allocated modifier group) if ( modinfo == 0 ) modinfo = j; else if ( modinfo != j ) { printf("Wrong location for modification indirectors %d != %d\n", modinfo, j); fprintf(fout, " Wrong location for modification indirectors %d != %d\n", modinfo, j); exit(1); } i = 8 * MODGRP; xbuff[j++] = i; // S+2C+R+2T+2 = - (8m'+2) xbuff[j++] = i + 0x100002; // indirector to mod reg 1 // S+2C+R+2T+3 = - (8m'+4) xbuff[j++] = i + 0x100004; // indirector to mod reg 2 // S+2C+R+2T+4 = - (8m'+6) xbuff[j++] = i + 0x100006; // indirector to mod reg 3 if ( pass == 2 ) { v = chapaddr[ch]; fprintf(fout, "L%d loading procedure 0 for chapter %d\n", v, ch); valsOut(xbuff, proc0size[ch], v); } } // ---------------------------------------------------------- // Dealing with constants int cbase21 = 0; // short constant pointer int cbase41 = 0; // long constant pointer int cbase = 0; // location of first constant int kcbase21[MAXCHAPS]; // keep short constant pointer int kcbase41[MAXCHAPS]; // keep long constant pointer int *cvals[MAXCHAPS]; // set up between passes to hold values of constants // no attempt to optimise multiple uses // do this later if the generated code is too big int cloc21(int val) // make a short store location containing val { int res = cbase21++; // last constant addr + 1 if ( pass == 2 ) // N.B. cvals is only set up after pass 1 { cvals[curchap][res-cbase] = val; // { char *p = NULL; // fprintf(fout, "What is going on?\n"); // if ( *p == 0 ) // fprintf(fout, "Don't believe this\n"); // } } return (res + chapaddr[curchap]) & 0x1FFF; // address within this division } int cloc41(int msval, int lsval) // make a long store location containing msval lsval { int res = cbase41; // next location cbase41 += 2; if ( pass == 2 ) { cvals[curchap][res-cbase] = lsval; cvals[curchap][res-cbase+1] = msval; } return (res + chapaddr[curchap]) & 0x1FFF; // address within this division } void checkLitOK(int ref, int item, int desc, int mod, char **srcline) // checks that all paramaters are zero { if ( ref > 0 ) fprintf(stderr, "Mysterious ref in a literal instruction %s\n", srcline[sercol]); if ( item > 0 ) fprintf(stderr, "Mysterious item in a literal instruction %s\n", srcline[sercol]); if ( desc > 0 ) fprintf(stderr, "Mysterious desc in a literal instruction %s\n", srcline[sercol]); if ( mod > 0 ) fprintf(stderr, "Mysterious mod in a literal instruction %s\n", srcline[sercol]); } // Next 3 routines for processing literals, depending on the radix required. // In Leo terms the processing of a literal is treated as 10 decimal digits plus a sign. // However, this is really hexadecimal, as digits 10 to 15 are also allowed at this point. // Several Intercode actions talk of converting the literal to binary, by which they mean // evaluting the digits as if they were a decimal number (digits 10 to 15 not allowed). // There are also literals that are true binary patterns of 0s and 1s with a possible minus sign. // There are 3 routines for literals, corresponding to the three cases above: // hexlit() -- radix 16, digits assembled into quartets // declit() -- radix 10, digits read as a conventional decimal number // binlit() -- radix 2, only digits 0 and 1 are relevant int top20; int hexlit(char *l) // evaluate a literal operand, if there is one, else 0 // assembles up to 10 hex digits into quartets. // If the literal starts with x (lowercase), the uppercase letters A-F are taken as digits 10 to 15 // In any case the lowercase letters t, e and p are 10, 11 and 15 (ten, eleven and pound) // If there are more than 5 digits, the top half is in top20. // If there is a minus sign, the result is negated // see routine litInstr() for more details { int ls20 = 0; int wc; int neg = 0; top20 = 0; l --; // skip back one ready to skip forward while ( *++l == ' ' ) ; // remove initial spaces l --; // skip back one ready to skip forward while ( (wc = *++l) != 0 ) if ( wc == '-' ) // minus might be at the end neg = -1; else { if ( wc == 't' ) // Leo versions of hex chars can mix in hex constants wc = 10; else if ( wc == 'e' ) wc = 11; else if ( wc == '+' ) wc = 12; else if ( wc == ':' ) wc = 13; else if ( wc == '.' ) wc = 14; else if ( wc == '£' ) // this may be problematic because of Unicode wc = 15; else if ( wc == 'p' ) // can use lower case p for pound wc = 15; else if ( wc >= 'A' ) // conventional Hex dgits are accepted for historical reasons wc += 10 - 'A'; else wc -= '0'; top20 = ((top20<<4) + (ls20>>16)) & 0xFFFFF; ls20 = ((ls20<<4) + wc) & 0xFFFFF; } if ( neg < 0 ) return -ls20; return ls20; } int declit(char *l) // evaluate a literal operand witha radix of 10 // Flags if the result is bigger that a short compartment { int ls20 = 0; char *l0 = l; int wc; top20 = 0; while ( *l == ' ' ) // remove initial spaces l ++; if ( *l == '-' ) // negative with - in front return -declit(l+1); else { while ( (wc = *(l++)) != 0 ) { if ( isdigit(wc) ) { ls20 = ls20*10 + wc - '0'; top20 *= 10; if ( (wc = ls20>>20) != 0 ) { top20 += wc; ls20 &= 0xFFFFF; } } else if ( wc == '-' && *l == 0 ) // minus sign often at the end return -ls20; else // non-digit in literal (hex??) { fprintf(fout, " Suspicous literal %s\n", l0); printf("Suspicous literal on line %s\n", src[srcp-1][sercol]); return hexlit(buff); } } } if ( top20 != 0 ) // something is afoot { fprintf(fout, " Suspiciously large literal value %s\n", l0); printf(" Suspiciously large literal value on line %s\n", src[srcp-1][sercol]); } return ls20; } int binlit() // evaluate the current literal as binary for actions such as 35 { char *s = src[srcp-1][litcol]; int res = 0; int c; while ( ((c = *(s++)) & 0x7E) == '0' ) // only true for digits 0 and 1 res += res + (c&1); if ( c == '-' ) // trailing minus sets bit 11 res += 0x400; else if ( c != 0 ) fprintf(fout, " Literal not binary\n"); return res; } // -------------------------------------- void litInstr(int i1, int i2, char *lit, char **srcline) // process instruction for addr, using 1/1/i1 if lit < 8192, else i2 // if i1 < 0 always put a literal in store { int addr = hexlit(lit); addrInd = ' '; // addressing indicator irrelevant here if ( top20 != 0 && addr >= 0 ) // large positive constant codeOut(i2, 1, 0, cloc41(top20, addr), srcline); else if ( (addr&8191) == addr && top20 == 0 // small non-negative and ... && i1 >= 0 ) //... literal instruction is available codeOut(1, 1, i1, addr, srcline); else if ( addr >= 0 && top20 == 0 ) // largish positive or ... codeOut(i2, 0, 0, cloc21(addr), srcline); // .. compulsory literal in store else if ( addr >= 0 ) // large positive codeOut(i2, 1, 0, cloc41(top20, addr), srcline); else if ( top20 == 0 ) // negative but not enormous codeOut(i2, 0, 0, cloc21(0x100000 - addr), srcline); else // negative enormous codeOut(i2, 1, 0, cloc41(0x100000 + top20, -addr), srcline); } // memdiff; // difference between the Intercode line number and the calculated address // set by next routine and used to help understand the addressing within PROCRs int addrcalc(int r, int i, char *l) // calculate the address for ref r and item i and literal l // There is a lot of guesswork in this at the moment, what if both i and l are present? { int res = -1; int p; int raw; char **line; if ( (p = hexlit(l)) != 0 ) // must be literal operand { if (r != 0 || i != 0 ) fprintf(fout, " Literal operand combined with others\n"); addrInd = ' '; // no address queries return p; } if ( r == absent ) // just a literal operand { addrInd = ' '; // no address queries return i; } if ( pass < 2 ) // tables not yet set up return 0x1234; // just rubbish to fill up the hole p = procstart[r]; // source address for procs, word address for sections if ( p < 0 ) fprintf(fout, " Procedure %d (or section) unknown\n", r); else if ( r < 100 ) // section address res = p + i; else if ( r == 999 ) // address relative to start of this chapter -- ??? res = i; else { sprintf(buff, "%d", r*100 + i); raw = addr[p] + i - 2; // raw address taken as item = address offset + 2 p -= 2; while ( (line = src[++p]) != NULL && (res = strcmp(line[sercol], buff)) < 0 ) ; if ( res == 0 ) // success res = addr[p]; // need to check for short address between two long words else if ( atoi(line[sercol]) - (res = r*100 + i) == 1 // stopped on line just one bigger ... && atoi(src[p-1][sercol]) - res == -1 ) // ... after line just one smaller res = addr[p] - 1; else { // diagnostic can be reinstated to investigate addressing errors // p -= 2; // diagnostic suppressed - can fail near the end of the code // fprintf(fout, " nums = %d: %s %s [ %s ] %s %s %s %s\n", p+2, src[p][sercol], src[p+1][sercol], src[p+2][sercol], // src[p+3][sercol], src[p+4][sercol], src[p+5][sercol], src[p+6][sercol]); // fprintf(fout, " Failed to identify item %s [%d, %d]\n", buff, r, i); do this later res = -2; // if ( r == 126 && i == 15 ) // kludge to deal with line 10230 // return addrcalc(126, 2, "0") + 13; } if ( raw == res ) // both address calculations give the same result addrInd = ' '; // no address queries else if ( icAct/10 == 7 ) // if some form of sequence change addrInd = ' '; // indicate serial number address is uncontentious else if ( icAct/10 == 8 ) // if subroutine addressing not at start of PROCR addrInd = 's'; // indicate serial number address else // must be absolute address { res = raw; // return offset address addrInd = 'a'; // indicate absolute address offset } } if ( res < 0 ) return res; return res + chapaddr[procchap[r]]; // diagnostics not currently obeyed if ( r == 126 && i == 15 ) fprintf(fout, " ??? %d %d\n", res, p); if ( r == 148 ) fprintf(fout, "Why did we calculate %d? We stopped at line %s\n", res + chapaddr[procchap[r]], src[p][sercol]); } // addresses of constants for 24 order to address across divisions int zero; // Address of a constant zero int div1; // Address of a constant 0x2000, i.e. div1 int div2; // Address of a constant 0x4000, i.e. div1 int div3; // Address of a constant 0x6000, i.e. div1 int last81; // location of the last 81 order (i.e. pointer to parameter space) int ixtransit(int r) // delivers index of transit area for this section, or -ve if not transit area { int i = trcount; while ( --i >= 0 && r != transect[i] ) ; // is this a transit area if ( nobuffswap != 0 && i >= 0 ) // buffer swapping will be suppressed in emulation return i - 64; // pretend this is not a transit area, but get num with & return i; } int memref(int r, int i, char *l) // calculates an N for a memory reference // generating extra instructions if needed { int memloc; int lloc = loc + chapaddr[curchap]; int refchap; // chapter being referenced int divbase; if ( r <= 0 ) // ref is blank or zero { addrInd = ' '; // no address queries if ( equivchap[curchap] != 1 ) // not in chapter 1 (i.e. div 0) // if ( pass == 2 ) // fprintf(fout, " %s Extra code needed to address absolute %d from %d (different chapter)\n", // src[srcp-1][sercol], i, lloc); return i; // r == 0 means absolute address, but this seems right } if ( r >= 1000 ) // ref is subroutine parameter { loc += 2; // need to generate 2 extra instructions on pass 2 if ( pass >= 2 ) { fprintf(fout, "24/0/3 %d Extra code needed to address caller\n", last81); fprintf(fout, "24/0/3 %d Extra code needed to address parameter\n", r-1000); if ( i != 0 ) fprintf(fout, " !!! Non-zero item in parameter\n"); } addrInd = ' '; // no address queries return 0; // Should this be return i? no } if ( (memloc = ixtransit(r)) >= 0 ) // yes, it is a transit area, and memloc is the transit area number { loc ++; // extra instruction will be generated if ( pass >= 2 ) fprintf(fout, "24/1/2 %d Extra code needed to address transit area no %d, section %d\n", memloc + memloc + 1 + traninfo, memloc, r); addrInd = ' '; // no address queries return i; // item is address within section } memloc = addrcalc(r, i, l); // this will have set addrInd refchap = procchap[r]; // chapter being referenced if ( refchap < 0 ) // ref is blank { fprintf(fout, "Chapter not allocated to %d\n", r); return -1; } if ( memloc < 0 ) // bad address return memloc; // if ( refchap != curchap ) // temporary to list cross chap references // printf("section %d which is in chap %d accessed in chap %d\n", r, refchap, curchap); if ( equivchap[refchap] == equivchap[curchap] )// not in a different chapter return memloc & 017777; // so bottom 13 bits of addrcalc is OK divbase = memloc & 0xFFE000; // needs to generate a "SMO" if ( divbase == 0 ) divbase = zero; else if ( divbase == 0x2000 ) divbase = div1; else if ( divbase == 0x4000 ) divbase = div2; else if ( divbase == 0x6000 ) divbase = div3; else divbase = cloc21(divbase); if ( pass == 2 ) fprintf(fout, "24/0/3 %d Extra code needed to address %d from %d (different chapter)\n", divbase, memloc, lloc); else if ( verbosity >= 2 ) // diagnostic to spot address mismatches due to chapter confusion fprintf(fout, "Extra code needed\n"); loc++; return memloc & 0x1FFF; // mask off division bit // next bit not executed actinfo = "other division"; // generating supplimentary modification codeOut(24, 0, 3, cloc21(memloc & 0xFFE000), NULL); // temporarily generates a new constant every time return memloc & 0x1FFF; // mask off division bit } int swlist[] = { 1000, 1012, 1000, 1019, 1000, 1020, 1000, 1004, 1000, 1005, 1000, 1006, 1000, 1008, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2}; // The only modifiers used are 12 19 20 4 5 6 8 // located at 16382, 16380, etc int swref(int s) // find the memory location for switch s // switches are currently put at the top of division 1, i.e. 16383 downwards // also simulated modifiers are here, by adding 1000 to the modifier number // only 7 simulated modifiers are actually in use // There is a dummy 1000 entry with each one to give a 2 word modifier location { int i = -1; while ( swlist[++i] != s && swlist[i] >= 0 ) ; if ( swlist[i] == -2 ) { printf("Run out of switches at line %s\n", src[srcp-1][sercol]); exit(1); // disaster !!! } else if ( swlist[i] < 0 ) // vacant slot { if ( s >= 1000 ) notImplemented("Extra simulated modifier"); swlist[i] = s; } return 8191 - i; } void constaddr(int newchap) // sort out constant space { int ch = curchap; int i, v; if ( pass < 2 ) { if ( curchap != 0 ) // not entry at start of first chapter { fprintf(fout, "\n Chapter %d\n Number of short constants = %5d\n Number of long constants = %5d\n", ch, cbase21, cbase41/2); cbase = loc; // location of first constant relative to chapter base, i.e. chapaddr[ch] if ( ((loc + cbase21) & 1) != 0 ) // if need to round up for long constants cbase21 ++; chapsize[ch] = loc + cbase21 + cbase41; cvals[ch] = (int *)malloc((cbase21 + cbase41) * sizeof(int)); fprintf(fout, " Chap %d has %d constants\n", ch, cbase21 + cbase41); kcbase21[ch] = cbase; // short constants start on top of computer code kcbase41[ch] = cbase + cbase21; // long constants start on top of short constants fprintf(fout, " Code starts at %d\n constants at %5d\n long constants at %5d\n", proc0size[ch] + PROC0VAR, kcbase21[ch], kcbase41[ch]); } cbase = 0; cbase41 = 0; cbase21 = 0; // ready for next chapter } else // pass 2 { if ( curchap != 0 ) // not entry at start of first chapter { fprintf(fout, "\n Constants for chapter %d\n short constants at %5d\n long constants at %5d\n", ch, kcbase21[ch] + chapaddr[ch], kcbase41[ch] + chapaddr[ch]); cbase = kcbase21[ch]; if ( loc != cbase ) fprintf(fout, "Out of sync at the end of chapter %d: %d != %d\n", ch, loc, cbase); loc = cbase41 + chapaddr[ch]; // end of possible overlay cbase41 -= cbase; // number of constants to generate for ( i = 0; i>16, (v>>15)&1, (v>>13)&3, v&017777, i + cbase + chapaddr[ch], v); // if ( i + cbase + chapaddr[ch] == 3515 ) // { char *p = NULL; // fprintf(fout, "What is going on?\n"); // if ( *p == 0 ) // fprintf(fout, "Don't believe this\n"); // } } } ch = newchap; cbase = cbase21 = kcbase21[ch]; cbase41 = kcbase41[ch]; } } void startproc(int p) // start of procedure p { int ch = procchap[p]; int size; if ( ch < 0 ) // should never happen { fprintf(fout, "Chapters up the creek! proc = %d\n", p); printf("Chapters up the creek! proc = %d\n", p); exit(1); } else if ( ch != curchap ) // changing chapters { constaddr(ch); // put the constants at the end or current chapter, and set up for pointers for new one size = loc; // remember size in case of overlay precedure0(curchap); // manufacture proc 0 for chapter just ending loc = proc0size[ch] + PROC0VAR; if ( pass == 2 ) { if ( equivchap[ch] != ch ) // this chapter is an overlay fprintf(fout, "O%02d %5d %5d Overlaying chapter %d by %d, equivalent to chapter %d\n", olcount++, chapaddr[ch], size, curchap, ch, equivchap[ch]); fprintf(fout, "L%d loading chapter %d\n", loc+chapaddr[ch], ch); } curchap = ch; zero = chapaddr[ch] & 0x1FFF; // address within this division -- used for addressing division 0 div1 = cloc21(0x2000); // used for addressing across divisions div2 = cloc21(0x4000); // used for addressing across divisions div3 = cloc21(0x6000); // used for addressing across divisions procchap[999] = curchap; // ref 999 is always current chapter } if ( pass+verbosity >= 2 ) fprintf(fout, "\n Start of procedure %d at location %d in chapter %d [%d]\n", p, loc, curchap, loc + chapaddr[curchap]); // used to generate zero word for the link address ... // ... but it seems that we always start with 81 code to make a blank codeOut(-2, 0, 0, 0, src[srcp-1]); // generates no code, just listing and maybe name anchor if ( pass < 2 ) procstart[p] = srcp; else if ( procstart[p] != srcp ) { fprintf(fout, "Out of sync at start of procedure %d [%d,%d]\n", p, procstart[p], srcp); printf("Out of sync at start of procedure %d [%d,%d]\n", p, procstart[p], srcp); check(); exit(1); } } // char charval[256]; // declared before chapter0() char hexval[256]; // TEMP !!! or maybe not // Basic Quartet // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // ___________________________________________________ // 0 | Sp | // 1 | - | // 2 | & | // Control 3 | 0 | // Quartet 4 | 1 2 3 4 5 6 7 8 9 10 11 + : . £ | // 5 | A B C D E F G H I = * ' ? ? ? | // 6 | J K L M N O P Q R ? % > < ½ \ | // 7 | / S T U V W X Y Z ( ) , ; ? ? | // |_________________________________________________| mkchars() // create the above conversion tables charval and hexval { int i; memset(charval, 0, 256); memset(hexval, 0, 256); for ( i = 0; i<16; i++ ) { hexval[i] = i; hexval[i+'0'] = i; } for ( i = 0; i<6; i++ ) hexval[i+'A'] = i + 10; hexval['t'] = 10; // ten char charval['t'] = 0x4A; // ten char hexval['e'] = 11; // eleven char charval['e'] = 0x4B; // eleven char hexval['p'] = 15; // pound char charval['p'] = 0x4F; // pound char charval[' '] = 0; charval['-'] = 16; charval['&'] = 32; charval['0'] = 48; for ( i = 1; i<10; i++ ) { charval[i+'0'] = i + 0x40; charval[i+'A'-1] = i + 0x50; charval[i+'Q'] = i + 0x70; // must precede next line charval[i+'I'] = i + 0x60; } charval['/'] = 0x71; hexval['+'] = 12; charval['+'] = 0x4C; hexval[':'] = 13; charval[':'] = 0x4D; hexval['.'] = 14; charval['.'] = 0x4E; hexval['£'&255] = 15; charval['£'&255] = 0x4F; // pound char charval['='] = 0x5A; charval['*'] = 0x5B; charval['\''] = 0x5C; charval['?'] = 0x5D; charval['%'] = 0x6B; charval['>'] = 0x6C; charval['<'] = 0x6D; charval['\\'] = 0x6F; charval['h'] = 0x6E; // h = half charval['('] = 0x7A; charval[')'] = 0x7B; charval[','] = 0x7C; charval[';'] = 0x7D; } char zbuff[1000]; char *zline[100]; void parsetable(int typ, char **line) // deal with tables as we meet different types // not sure if different types have different layouts { int i, v; int val[13]; int msval = 0; int lsval = 0; if ( strcmp(line[actcol], "NOTES") == 0 ) return; // ignore NOTES line actinfo = "!to be sorted out very soon"; // not currently printed for ( i = 0; i<13; i++ ) val[i] = atoi(line[i+1]); lsval = addrcalc(val[0], val[1], ""); // first item in all types of table if ( lsval < 0 ) lsval = 0; // missing ref msval = val[6]; // number of characters in Q6 msval += val[8]<<4; // number of spaces in Q7 msval += val[7]<<8; // number of spaces in Q8 msval += val[9]<<12; // number of zeros in Q9 if ( val[4] >= 2 ) msval |= 1<<16; // b37 = val[4] >= 2; if ( val[4] >= 1 ) msval |= 1<<17; // b38 = val[4] >= 1; if ( val[10] >= 1 ) msval |= 3<<18; // b39 = val[10] >= 1; numeric item to be signed if ( val[10] >= 2 ) msval &= 0x7FFFF; // b40 = val[10] >= 2; take out B40 from previous if ( val[12] != 0 ) msval |= 0x100000; // S2 = last entry marker if ( val[5] != 0 ) msval |= 0x80000; // b40 = repeatedly use this item v = lsval; codeOut(v>>16, (v>>15)&1, (v>>13)&3, v&017777, line); v = msval; codeOut(v>>16, (v>>15)&1, (v>>13)&3, v&017777, NULL); } char cmode = '?'; // constant mode letter, ? = undefined, M = mixed, not implemented int mxsh1[] = { 4, 5, 3, 7, 1 }; char mxch1[] = { 'B', 'B', 'B', 'B', 'B' }; int mxsh2[] = { 20, 4, 16 }; char mxch2[] = { 'D', 'R', 'B' }; int mxsh3[] = { 5, 3, 3, 3, 6 }; char mxch3[] = { 'B', 'B', 'B', 'B', 'B' }; int mxsh4[] = { 8, 6, 6 }; char mxch4[] = { 'B', 'B', 'B' }; int *mxsh; char *mxch; void parseconst(int mode, char **line) // parse constant and generate appropriate code // mixed constants are not done properly // with luck we will only have to acept a very few formats // and can do a quick kludge { unsigned char p[100]; int i = 0; unsigned char c; int msval = 0; int lsval = 0; int sign = 0; char *duff = NULL; int xmsval = 0; // accumulation of mixed constant int xlsval = 0; int xi = 0; // index for mixed constant shift values strncpy(p, line[refcol], 100); // the actual string // fprintf(fout, "Parsing constant: %s mode = %c\n", p, cmode); while ( (c = p[i++]) != 0 && duff == NULL ) if ( c == ';' ) // number end { p[i] = 0; // force end next time round if ( xi != 0 ) // end of mixed constant p[--i] = ','; // process last element of a mixed constant next iteration } else if ( c == '(' ) // type indicator { if ( i > 1 ) // not first char duff = "Cannot do proper mixed constants yet"; cmode = p[i++]; if ( strcmp(p, "(A)RUN(D)7t7e;") == 0 ) // line 87118 !!!! { msval = 0x69746; lsval = 0x57A7B; // leaves cmode set as 'A' p[i] = 0; // stop the loop } else if ( strcmp(p, "(A)ONS(D)5.5.;") == 0 ) { msval = 0x66657; lsval = 0x25E5E; p[i] = 0; // stop the loop } else if ( strcmp(p, "(A)TYPE(D)7.;") == 0 ) { msval = 0x73786; lsval = 0x7557E; p[i] = 0; // stop the loop } else if ( strcmp(p, "(D)2000(A)*;") == 0 ) // don't know what to do with this { msval = 0x2; // there is some doubt about the correctness of this lsval = 0x5B; p[i] = 0; // stop the loop } else if ( p[i++] != ')' ) // mixed const kludge if ( strcmp(p, "(B4)1(B5)1(B3)7(B7)11(B1)0;") == 0 ) { mxsh = mxsh1; mxch = mxch1; lsval = 0x10F16; p[i] = 0; // stop the loop } else if ( strcmp(p, "(B20)16(D)0(C)1:28;") == 0 ) { mxsh = mxsh2; mxch = mxch2; strcpy(p, "16,0,1:28;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)7(B3)1(B3)1(B3)1(B6)9;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "7,1,1,1,9;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)7(B3)1(B3)0(B3)6(B6)1;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "7,1,0,6,1;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)2(B3)0(B3)0(B3)1(B6)1;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "2,0,0,1,1;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)0(B3)2(B3)0(B3)1(B6)9;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "0,2,0,1,9;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)0(B3)6(B3)6(B3)6(B6)50;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "0,6,6,6,50;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)1(B3)7(B3)3(B6)0;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,1,7,3,0;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)0(B3)1(B3)0(B6)9;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,0,1,0,9;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)1(B3)1(B3)1(B6)9;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,1,1,1,9;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)1(B3)1(B3)1(B6)8;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,1,1,1,8;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)1(B3)0(B3)1(B6)15;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,1,0,1,15;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)0(B3)0(B3)1(B3)1(B6)0;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "0,0,1,1,0;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)0(B3)1(B3)1(B6)9;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,0,1,1,9;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)1(B3)1(B3)0(B3)1(B6)1;") == 0 ) { mxsh = mxsh3; mxch = mxch3; strcpy(p, "1,1,0,1,1;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B8)29(B6)31(B6)14;") == 0 ) { mxsh = mxsh4; mxch = mxch4; strcpy(p, "29,31,14;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B8)24(B6)50(B6)51;") == 0 ) { mxsh = mxsh4; mxch = mxch4; strcpy(p, "24,50,51;"); // input line without field width info i = 0; // start the loop again } else if ( strcmp(p, "(B5)0(B3)0(B3)0(B3)0(B6)0;") == 0 ) { mxsh = mxsh3; mxch = mxch3; lsval = 0; p[i] = 0; // stop the loop } else if ( strcmp(p, "(B8)40(B6)45(B6)49;") == 0 ) { lsval = (40<<12) + (45<<6) + 49; // there is only one of these p[i] = 0; // stop the loop } else duff = "No mixed constants yet"; } else if ( c == ',' ) // must be a mixed constant { cmode = mxch[xi]; // will crash if mxch = NULL c = mxsh[xi++]; // will crash if mxsh = NULL if ( msval != 0 ) duff = "mixed constant too difficult"; xmsval = ((xmsval<>(20-c))) & 0xFFFFF; xlsval = ((xlsval<>12)) & 0xFFFFF; lsval = ((lsval<<8) & 0xFFF00) | charval[c&255]; } else if ( c == '-' ) // accepted anywhere sign = 0x100000; else if ( c == 'x' ) // our convention for hex digits p[i] = hexval[p[i]&255]; // deal with next char else if ( cmode == 'D' ) // 'decimal' constant puts hex digits in quartets { msval = ((msval<<4) | (lsval>>16)) & 0xFFFFF; lsval = ((lsval<<4) & 0xFFFF0) | hexval[c&255]; } else if ( cmode == 'B' ) // 'binary' constant puts binary value expressed in decimal { if ( isdigit(c) ) { lsval = lsval*10 + c - '0'; msval *= 10; if ( (c = lsval>>20) != 0 ) { msval += c; lsval &= 0xFFFFF; } } else duff = "bad char in binary constant"; } else if ( cmode == 'R' ) // 'relative' constant puts relative address { if ( isdigit(c) ) msval = msval*10 + c - '0'; // procedure number else if ( c == ':' ) // separator between ref and item { int ps = procstart[msval]; // see addrcalc for detail if ( msval >= 100 ) // so ps points at the src ps = addr[ps]; // so get the absolute address lsval = atoi(p+i); // item number after the colon p[i] = ';'; // force end next time round lsval += ps + chapaddr[procchap[msval]]; msval = 0; // lsval = addrcalc(msval, lsval, "0"); // lsval -= addrcalc(msval, 0, "0"); // seems to be needed according to documentation ??? // fprintf(fout, " Just did R mode eval to %d %06X %05X\n", lsval, xmsval, xlsval); } else duff = "bad char in relative constant"; } else duff = "Mystery constant"; if ( duff != NULL ) { fprintf(stderr, "Duff constant at %s: %s %s\n", line[sercol], duff, line[refcol]); fprintf(fout, " Duff constant %s\n", duff); } if ( xmsval != 0 || xlsval != 0 ) // mixed constant (only a kludge) { msval = xmsval; lsval = xlsval; } if ( sign != 0 ) // negative i = '-'; else i = '+'; if ( mode == CONSTLONG ) { sprintf(p, " %05X %c%05X", lsval, i, msval); msval |= sign; } else { sprintf(p, " %c%05X", i, lsval); lsval |= sign; } actinfo = p; codeOut((lsval>>16), (lsval>>15)&1, (lsval>>13)&3, lsval&017777, line); if ( mode == CONSTLONG ) codeOut(msval>>16, (msval>>15)&1, (msval>>13)&3, msval&017777, NULL); // double word } void computerCode(int act, int ref, int item, char *lit, int disc, int mod) // process a group 10-13 instruction // see User Manual Vol III http://sw.ccs.bcs.org/leo/LeoIC.htm#a100 { int addr; actinfo = ccstr[(act-100)*8 + disc*4 + mod]; if ( strlen(lit) > 1 || atoi(lit) != 0 ) { addr = -1; actinfo = "Comp Code with lit"; } else if ( ref == absent ) // item is the address part (absolute address) addr = item; else if ( 1 == 1 ) // item is absolute offset in PROCR, not serial number (RTFM) { addr = memref(ref, item, "0"); } else // never do this // item is absolute offset in PROCR, not serial number (RTFM) { int addr2 = addrcalc(ref, item, "0"); // don't use memref, it might generate a 24 addr = memref(ref, 2, "0"); // base of routine if ( addr >= 0 ) // routine exists addr += item - 2; // actinfo = "CC Address fancy bit"; if ( addr2 >= 0 && ((addr^addr2) & 8191) != 0 ) // look for a mismatch addrInd = 'a'; // absolute address offset used else addrInd = ' '; // both methods give the same address } codeOut(act-100, disc, mod, addr, src[srcp-1]); if ( act == 123 && disc == 0 && mod == 0 ) // 123/0/0 STEP ON AND TEST indirect modifier by N. { char **line = src[srcp]; if ( line[actcol][0] == 'C' // only 123/0/0 has a C-line || atoi(line[actcol]) == 100 ) // but usually action 100 is the next line { ref = atoi(line[refcol]); item = atoi(line[itemcol]); actinfo = "Address of modifier"; addr = addrcalc(ref, item, "0"); srcp ++; // absorb the C-line codeOut(0, 0, addr>>13, addr&0x1FFF, line); // and point at the "modifier" } } } void notImplemented(char *s) // flag non-implemented instructions { char **l = src[srcp-1]; actinfo = s; codeOut(999, 0, 0, 0, l); // generates halt instruction and comment if ( pass == 2 || verbosity < 2 ) return; fprintf(fout, "Not implemented: %s ::: ", s); fprintf(fout, fmt, l[sercol], l[actcol], l[refcol], l[itemcol], l[disccol], l[modcol], l[litcol], l[cmtcol]); } void imagelink(char **line) // outputs link to original source test { if ( pass < 2 && verbosity == 0 ) return; if ( line[sercol][1] == 'q' ) // if there is a warning or query fprintf(fout, " Query: %s\n", line[cmtcol]); else if ( strlen(line[refcol]) >= 5 ) // if there is a URL for the file fprintf(fout, "\n Source: %s\n", line[refcol], line[cmtcol]); // ignore everything else else fprintf(fout, "\n Source: %s\n", line[cmtcol]); } int fieldval(char *s) // skip initial spaces then // get integer value, -10000 if absent, -10001 if alpha { int res; while ( *s == ' ' ) s ++; res = atoi(s); if ( res == 0 ) if ( *s == 0 ) // null string res = absent; else if ( *s != '0' ) // not an actual zero res = alpha; return res; } int itemval(char *s) // skip initial spaces then // get integer value, -10000 if absent, -10001 if alpha // but an item may be ove with - at the end { int res = fieldval(s); if ( res != 0 && s[strlen(s)-1] == '-' ) // -ve item value return -res; return res; } int concount() // count number of continuation lines { int i = -1; while ( strcmp(src[srcp + ++i][actcol], "C") == 0 ) ; return i; } void conpars() // deal with continuation lines which are addresses of locations { char **line; int v, ref, item; actinfo = ""; icAct = 89; // forces preference of serial no addressing -- may need to be a parameter while ( strcmp((line = src[srcp])[actcol], "C") == 0 ) { addr[srcp++] = loc; ref = fieldval(line[refcol]); item = fieldval(line[itemcol]); v = addrcalc(ref, item, "0"); if ( v < 0 ) fprintf(fout, "0/0/0 0 !!!!! Failed to find ref %d item %d [%d]\n", ref, item, v, loc++); else codeOut(v>>16, (v>>15)&1, (v>>13)&3, v&017777, line); } } int getRoute(char *fn) // get the route number for given file { int w = -1; while ( filename[++w] != NULL && strcmp(filename[w], fn) != 0 ) ; if ( filename[w] == NULL ) { printf("Filename %s unknown\n", fn); fprintf(fout, " Filename %s unknown\n", fn); } return (w+1)*9; } void generate() // generate the binary program for loading into the interpreter { char **line, **wline; int act, ref, item, disc, mod; // fields from the source code char *lit; // literal from the source code char *cmt; // comment from the source code int w; // working variable int mode = 0; // indicates wheter in PROCR or CONST -- and later TABLE int tabtype; // indicates which type of table we are processing srcp = 0; curchap = 0; // first proc will change this loc = 99999; // an arbitrary label to pass the self-consistency check on the the very first line curovr = 0; // start in overlay 0 while ( (line = src[srcp]) != lastline ) { if ( pass < 2 ) addr[srcp++] = loc; // remember addresses on first pass else if ( (w = addr[srcp++]) != loc && w >= 0) { fprintf(fout, "Up the creek :: %d != %d at %s\n", w, loc, line[sercol]); printf("Up the creek :: %d != %d at %s\n", w, loc, line[sercol]); exit(1); } // fprintf(fout, "%3d ---> %4s %5s %5s %s %s %7s\n", srcp-1, // line[actcol], line[refcol], line[itemcol], line[disccol], line[modcol], line[litcol]); check(); if ( line[sercol] == NULL ) // blank line or comment act = 163; // comment else { act = fieldval(line[actcol]); ref = fieldval(line[refcol]); // if ( ref == absent ) // ref = 0; // should be OK in all cases item = itemval(line[itemcol]); // N.B. may occasionally be -ve, e.g. line 28813 disc = fieldval(line[disccol]); mod = fieldval(line[modcol]); lit = line[litcol]; // literal is not generally an integer // fprintf(fout, "act = %d %s lit = %d\n", act, line[actcol], lit); // if ( pass == 1 && mod >= 4 && mode == PROCMODE ) // search for simulated modifiers // printf("act %3d mod %2d at %s\n", atoi(line[actcol]), mod, line[sercol]); if ( act < 0 || act >= 160 ) actinfo = ""; else actinfo = icstr[act]; cmt = line[cmtcol]; if ( memcmp(line[actcol], "PROCR", 5) == 0 ) act = 161; else if ( memcmp(line[actcol], "CONST", 5) == 0 ) act = 162; else if ( memcmp(line[actcol], "TABLE", 5) == 0 ) act = 167; else if ( mode == TABLEMODE && *(line[sercol]) != '0' ) // not a warning or file marker act = 166; else if ( act == absent ) // Ken Kemp says that this is to be interpreted as zero ... { actinfo = icstr[0]; // ignored if not in PROCMODE if ( mode == PROCMODE ) act = 0; // .. in a procedure, ... else act = 160; // .. but we need to catch other cases in act 160, viz constants } else if ( act == alpha ) // Continuation lines should only be seen for unimplemented actions act = 165; } icAct = act; // allow memref and addrcalc to know what action we are processing addrInd = ' '; // indicator for address resolution method when serial does not match offset switch(act) { /* --------------- */ case 0: // 000 - SELECT if ( strcmp(src[srcp-1][sercol], "32606") == 0 ) // !!! kludge to force in a 24 order even when no buff swap { w = ixtransit(ref); // find transit area number if ( w == -1 ) // check really is transit area fprintf(fout, " I/O not on transit area\n"); w &= 63; // pick out area number even if not swapping buffers codeOut( 24, 1, 2, traninfo+w+w+1, line); // pseudo route used as modifier codeOut(6, disc, mod, item, NULL); // this instruction never actually gets obeyed } else codeOutSM(6, disc, mod, ref, item, lit, line); break; /* --------------- */ case 1: // 001 - ADD codeOutSM(4, disc, mod, ref, item, lit, line); break; /* --------------- */ case 2: // 002 - SUBTRACT codeOutSM(5, disc, mod, ref, item, lit, line); break; /* --------------- */ case 3: // 003 - COPY codeOutSM(3, disc, mod, ref, item, lit, line); break; /* --------------- */ case 4: // 004 - AUGMENT codeOutSM(7, disc, mod, ref, item, lit, line); break; /* --------------- */ case 5: // 005 - TRANSFER codeOutSM(2, disc, mod, ref, item, lit, line); break; /* --------------- */ case 6: // 006 - MULTIPLY codeOut(9, disc, mod, memref(ref, item, lit), line); break; /* --------------- */ case 7: // 007 - MULTIPLY and ADD notImplemented("MULTIPLY and ADD"); break; /* --------------- */ case 8: // 008 - MULTIPLY and SUBTRACT notImplemented("MULTIPLY and SUBTRACT"); break; /* --------------- */ case 9: // 009 - DIVIDE notImplemented("DIVIDE"); break; /* --------------- */ case 10: // 010 - SELECT LITERAL checkLitOK(ref, item, disc, mod, line); litInstr(3, 6, lit, line); break; /* --------------- */ case 11: // 011 - ADD LITERAL checkLitOK(ref, item, disc, mod, line); litInstr(1, 4, lit, line); break; /* --------------- */ case 12: // 012 - SUBTRACT LITERAL checkLitOK(ref, item, disc, mod, line); litInstr(2, 5, lit, line); break; /* --------------- */ case 16: // 016 - MULTIPLY LITERAL w = proc0size[curchap]; // address of W/L codeOut(2, 0, 0, w, line); // transfer also clears A act = hexlit(lit); // this is what Leo III means by 'decimal' if ( act < 0 ) notImplemented("Negative multiplication"); else if ( act < 0x100000 ) codeOut(0, 0, 2, cloc21(act), NULL); else codeOut(0, 1, 2, cloc41(act>>20, act&0xFFFFF), NULL); if ( ref <= 0 && item == 0 ) // i.e. N = zero N.B. ref might be absent codeOut(10, disc, 0, w, NULL); else codeOut(10, disc, mod, memref(ref, item, "0"), NULL); break; /* --------------- */ case 17: // 017 - MULTIPLY LITERAL and ADD w = hexlit(lit); // this is what Leo III means by 'decimal' if ( w < 0 ) notImplemented("Negative multiplication"); else if ( w < 0x100000 ) codeOut(0, 0, 2, cloc21(w), line); else codeOut(0, 1, 2, cloc41(w>>20, w&0xFFFFF), line); codeOut(10, disc, mod, memref(ref, item, "0"), NULL); break; /* --------------- */ case 19: // 019 - DIVIDE LITERAL codeOut(1, 0, 1, 0, line); // Clear B if ( ref > 0 ) // (if N is non-zero) Is this check too simple codeOut(6, 0, 1, memref(ref, item, "0"), NULL); codeOut(18, 1, 1, 4119, NULL); // Align to Q2 of B litInstr(-1, 13, lit, NULL); // Literal break; /* --------------- */ case 20: // 020 - SELECT F/Point notImplemented("SELECT F/Point"); break; /* --------------- */ case 21: // 021 - ADD F/Point notImplemented("ADD F/Point"); break; /* --------------- */ case 22: // 022 - SUBTRACT F/Point notImplemented("SUBTRACT F/Point"); break; /* --------------- */ case 23: // 023 - COPY F/Point notImplemented("COPY F/Point"); break; /* --------------- */ case 24: // 024 - AUGMENT F/Point notImplemented("AUGMENT F/Point"); break; /* --------------- */ case 25: // 025 - TRANSFER F/Point notImplemented("TRANSFER F/Point"); break; /* --------------- */ case 26: // 026 - MULTIPLY F/Point notImplemented("MULTIPLY F/Point"); break; /* --------------- */ case 29: // 029 - DIVIDE F/Point notImplemented("DIVIDE F/Point"); break; /* --------------- */ case 30: // 030 - SHIFT (A) BY QUARTETS w = declit(lit); if ( w < 0 ) codeOut(18, 0, 1, 4128 + w, line); else codeOut(18, 0, 1, w, line); break; /* --------------- */ case 32: // 032 - SHIFT (AB) BY QUARTETS w = declit(lit); if ( w < 0 ) codeOut(18, 1, 1, 4128 + w, line); else codeOut(18, 1, 1, w, line); break; /* --------------- */ case 31: // 031 - SHIFT (A) BY BITS // drop through - only discriminant is different between 31 and 33 /* --------------- */ case 33: // 033 - SHIFT (AB) BY BITS disc = (act-31)>>1; // 1 to shift AB, 0 to shift A w = declit(lit); if ( w < 0 ) { int y = (-w)/4; // avoid negative numbers in case of ... int x = (-w)%4; // ... change of programming language if ( x != 0 ) // x from the manual is 4 - x ... { y ++; // ... if y is increased by 1 codeOut(18, disc, 3, 4-x, line); line = NULL; // listing is attached to first instruction } codeOut(18, disc, 1, 4128 - y, line); // notImplemented("right shift of AB"); } else codeOut(18, disc, 3, w, line); break; /* --------------- */ case 34: // 034 - SET (N) IN B if ( ref == absent ) ref = 0; if ( ref == 0 ) // absolute address { if ( mod == 0 ) w = 0; else if ( mod < 4 ) // real modifier { w = modinfo + mod; // using pointer in procedure 0 ref ++; } else w = swref(1000+mod); codeOut(24, ref, ref+1, w, line); // either 24/1/2 or 24/0/1 codeOut(0, disc, 2, item, NULL); // address is in item } else if ( mod >= 4 ) // simulate a modifier notImplemented("Simulted modifier"); // cannot do this yet, but will be easy for ref = 0 else if ( mod == 0 ) // no modifier, OK for memref to generate extra code codeOut(0, disc, 2, memref(ref, item, lit), line); else if ( ixtransit(ref) >= 0 // transit area || equivchap[ref] != equivchap[curchap] )// or in a different chapter { w = proc0size[curchap]; // address of W/Ls codeOut(0, 1, 0, w, line); // Copy ABC codeOut(0, 0, 3, zero, NULL); // binary radix -- needed to avoid possible corruption of -ve value codeOut(6, disc, mod, memref(ref, item, lit), NULL); // load new value of B into A codeOut(2, 1, 0, w+2, NULL); // .... and copy to working location codeOut(0, 1, 1, w, NULL); // Restore ABC with new value of B } else // simulate a modifier reg when in current chapter { codeOut(24, 0, 0, modinfo + mod, line); // using pointer in procedure 0 codeOut(0, disc, 2, memref(ref, item, lit), NULL);// memref will not generate extra code } break; /* --------------- */ case 35: // 035 - PREPARE FOR DIGIT COLLATION codeOut(1, 0, 1, binlit(), line); break; /* --------------- */ case 36: // 036 - COLLATE AND ADD codeOutSM(15, disc, mod, ref, item, lit, line); break; /* --------------- */ case 37: // 037 - REPLACE SELECTED BITS codeOutSM(14, disc, mod, ref, item, lit, line); break; /* --------------- */ case 38: // 038 - ROUND OFF w = hexlit(lit); // this is what Leo III means by 'decimal' codeOut(1, 0, 2, w, line); break; /* --------------- */ case 39: // 039 - ROUND UP w = proc0size[curchap]; // address of W/L codeOut(2, 1, 0, w, line); // transfer to W/L codeOut(27, 1, 0, loc + 2, NULL); // change sequence if (AB) = 0 codeOut(1, 1, 3, 1, NULL); codeOut(4, 1, 0, w, NULL); break; /* --------------- */ case 40: // 040 - OPEN FILE // temporary implementation !!!!!!!! ????????? codeOut( 0, 1, 0, proc0size[curchap], line); // copy ABC, set binary codeOut( 0, 0, 3, zero, NULL); // binary radix act= atoi(lit); // = 0 for output lit = line[refcol]; // file name in ASCII w = charval[lit[0]] * 256 + charval[lit[1]]; // file identity w = cloc41(w, 0x08099); // official pattern from User Man Vol III (where?) codeOut( 0, 1, 2, w, NULL); // control information to B if ( act = 0 ) // write w = zero; else w = cloc41(act, 0); // official pattern unknown, w = 0 is output codeOut( 6, 1, 0, w, NULL); // type of operation in Q6 w = getRoute(lit); codeOut( 1, 1, 1, w, NULL); // add in route number codeOut(25, 1, 1, 4096, NULL); codeOut(24, 0, 3, zero, NULL); // enter Master codeOut(23, 0, 2, 40, NULL); codeOut( 0, 0, 3, proc0size[curchap]+4, NULL); // restore C break; /* --------------- */ case 45: // 045 - REWIND // drop through - only Master routine no is different between 31 and 33 /* --------------- */ case 41: // 041 - CLOSE FILE // temporary implementation !!!!!!!! ????????? w = getRoute(line[refcol]); codeOut( 0, 1, 0, proc0size[curchap], line); // copy ABC, set binary codeOut( 0, 0, 3, zero, NULL); codeOut( 6, 1, 0, zero, NULL); // type of operation in Q6 don't know what it should be codeOut( 1, 1, 1, w, NULL); // add in route number codeOut(25, 1, 1, 4096, NULL); codeOut(24, 0, 3, zero, NULL); if ( strcmp(line[sercol], "12609") == 0 ) codeOut(23, 0, 2, 1, NULL); // used by mysterious fancy work at line 10230 else codeOut(23, 0, 2, act, NULL); // enter "Master" indicating which action codeOut( 0, 1, 1, proc0size[curchap], NULL); // restore ABC break; /* --------------- */ case 42: // 042 - INPUT // drop through - only Master routine no is different between 42 and 43 /* --------------- */ case 43: // 043 - OUTPUT // temporary implementation !!!!!!!! ????????? if ( item != 0 ) fprintf(fout, " Do not understand NZ item\n"); item = getRoute(line[refcol]); codeOut( 0, 1, 0, proc0size[curchap], line); // copy ABC, set binary codeOut( 0, 0, 3, zero, NULL); if ( *((line = src[srcp++])[actcol]) != 'C' ) // continuation line fprintf(fout, " Do not understand no continuation line\n"); ref = atoi(line[refcol]); if ( atoi(line[itemcol]) != 0 ) fprintf(fout, " Do not understand NZ item\n"); w = ixtransit(ref); // find transit area number if ( w == -1 ) // check really is transit area fprintf(fout, " I/O not on transit area\n"); w &= 63; // pick out area number if not swapping buffers codeOut( 0, 0, 2, traninfo+w+w, line); // pseudo route no to B codeOut( 6, 1, 0, zero, NULL); // type of operation in Q6 0 = write ?? codeOut( 1, 1, 1, item, NULL); // add in route number codeOut(25, 1, 1, 4096, NULL); codeOut(24, 0, 3, zero, NULL); // enter Master codeOut(23, 0, 2, act, NULL); codeOut( 0, 1, 1, proc0size[curchap], NULL); // restore C break; /* --------------- */ case 44: // 044 - SET/SELECT REEL COUNTER notImplemented("SET/SELECT REEL COUNTER"); break; /* --------------- */ case 48: // 048 - STEP BACK // drop through - in our interim versions, the action number on the 23/0/2 order is the difference /* --------------- */ case 49: // 049 - STEP FORWARD item = 0; // ... except that the step operations put 0 in msb // drop through /* --------------- */ case 46: // 046 - RUN BACK // drop through /* --------------- */ case 47: // 047 - RUN ON mod = getRoute(line[refcol]); // note action is not modifiable codeOut( 0, 1, 0, proc0size[curchap], line); // copy ABC codeOut( 0, 0, 3, zero, NULL); // set binary if ( *((line = src[srcp++])[actcol]) != 'C' )// continuation line fprintf(fout, " Do not understand no continuation line\n"); ref = atoi(line[refcol]); if ( ref == 0 ) // if NC = 0 { w = cloc41(item, hexlit(line[litcol])); // some amazement here about radix codeOut( 0, 1, 2, w, line); // control information to B } else { w = memref(ref, atoi(line[itemcol]), "0"); codeOut( 6, 0, 0, w, line); // select (NC) codeOut( 4, 1, 0, cloc41(item, 0), NULL); // first line item (decimal) in Q6-10 codeOut( 18, 1, 1, 4118, NULL); // manual says 4128, but think this is a misprint } codeOut( 6, 1, 0, 0, NULL); // type of operation in Q6 - no idea what codeOut( 1, 1, 1, mod, NULL); // add in route number codeOut( 25, 1, 1, 4096, NULL); codeOut(24, 0, 3, zero, NULL); // enter Master codeOut(23, 0, 2, act, NULL); codeOut( 0, 1, 1, proc0size[curchap], NULL); // restore C break; /* --------------- */ case 51: // 051 - UNPACK VARIABLE FIELD DATA notImplemented("UNPACK VARIABLE FIELD DATA"); break; /* --------------- */ case 50: // 050 - UNPACK FIXED FIELD DATA // drop through - only discriminant is different between 50 and 52 /* --------------- */ case 52: // 052 - EDIT if ( atoi(src[srcp][modcol]) != 0 ) notImplemented("EDIT or UNPACK with modification"); else if ( strcmp(src[srcp][actcol], "C") != 0 ) notImplemented("Continuation line missing with EDIT or UNPACK"); else { int desttran = ixtransit(ref); // transit area for destination or -1 char **cline = src[srcp++]; if ( ( equivchap[ref] != equivchap[curchap] // in different chapter || desttran >= 0 ) // or in a transit area && mod != 0 ) // and modified { int wl = proc0size[curchap]; // W/L to hold computed destination address codeOut(0, 1, 0, wl, line); // Copy ABC line = NULL; codeOut(0, 0, 3, 0, NULL); // Set binary to ensure that ADD works OK codeOut(24, 0, 2, memref(ref, item, "0"), NULL); // load destination into A, will generate 24/1/1 if ( mod >= 4 ) codeOut(4, 0, 0, swref(1000+mod), NULL); // add the value of the modifier else { codeOut(24, 0, 3, modinfo, NULL); // accessed via pointer proc 0 codeOut(4, 0, 0, mod + mod, NULL); // add the value of the modifier } mod = wl - modinfo; // cannot possibly be zero and will generate 24/1/2 to wl codeOut(2, 0, 0, wl, NULL); // store address in W/L codeOut(0, 1, 1, wl, NULL); // Restore ABC desttran = -2; // fprintf(fout, " suspect indirect modified bulk copy\n"); } else if ( mod >= 4) // simulated modifier in this chapter mod = swref(1000+mod) - modinfo; // will generate 23/1/2, but mod value will not be negative codeOut(24, 0, 2, memref(atoi(cline[refcol]), atoi(cline[itemcol]), "0"), line); // load table address into A actinfo = ""; if ( mod != 0 ) // destination is modified codeOut(24, 1, 2, mod + modinfo, NULL); if ( desttran == -2 ) // destination is modified and non-local codeOut(28, (act>>2)&1, 2, 0, cline); // address has been placed in W/L and used with 24/1/2 else codeOut(28, (act>>2)&1, 2, memref(ref, item, "0"), cline); // disc = 1 for EDIT, 0 for UNPACK FIXED } break; /* --------------- */ case 53: // 053 - CONDENSE notImplemented("CONDENSE"); break; /* --------------- */ case 54: // 054 - BULK CLEAR w = declit(lit); if ( w == 0 ) notImplemented("Bulk clear with continuation line"); if ( disc != 0 ) disc = 1; // beware disc = 2 on codeOut codeOut( 6, 1, 0, cloc41(0x20000 + w, 0), line); // load 'table entry' into A codeOut( 28, disc, disc, memref(ref, item, "0"), NULL);// note modifier 1 for long - error in manual?? break; /* --------------- */ case 55: // 055 - BULK COPY wline = line; line = src[srcp++]; // step srcp to C line w = atoi(line[disccol]); // discriminant of C-line if ( disc != 0 ) { disc = 1; // beware disc = 2 on codeOut if ( w == 0 ) // copy alpha to short numeric item++; // add 1 for alpha to short copy } codeOut2402(mod, ref, item, wline); // load source into A actinfo = ""; codeOut(18, 1, 0, 4123, line); // and shift it down into B item = atoi(line[itemcol]); if ( disc == 0 && w != 0 ) // copy short numeric to alpha item++; // add 1 to destination address w = declit(lit); if ( strcmp(line[actcol], "C") != 0 ) notImplemented("Continuation line missing from BULK COPY"); else if ( w >= 8192 ) notImplemented("Bulk copy big count"); // cannot see why the manual hints at this in Appendix A else { int destmod = atoi(line[modcol]); // modifier of destination int desttran = ixtransit(ref = atoi(line[refcol])); // transit area for destination if ( destmod >= 4 ) notImplemented("Bulk copy simulated modifier"); // cannot do sim mod destination if ( atoi(line[disccol]) != 0 ) mod = 1; // copy to alpha if ( ( equivchap[ref] != equivchap[curchap] // in different chapter || desttran >= 0 ) // or in a transit area && destmod != 0 ) // and modified { int wl = proc0size[curchap]; // W/L to hold computed destination address codeOut(0, 1, 0, wl, NULL); // Copy ABC codeOut(0, 0, 3, 0, NULL); // Set binary to ensure that ADD works OK codeOut(24, 0, 2, memref(ref, item, "0"), NULL); // load destination into A, will generate 24/1/1 codeOut(24, 0, 3, modinfo, NULL); // accessed via pointer proc 0 codeOut(4, 0, 0, destmod + destmod, NULL); // add the value of the modifier codeOut(2, 0, 0, wl, NULL); // store address in W/L codeOut(0, 1, 1, wl, NULL); // Restore ABC - only needed to restore C destmod = wl; // cannot possibly be zero and will generate 24/1/2 to wl desttran = -2; // fprintf(fout, " suspect indirect modified bulk copy\n"); } if ( w == 0 ) { line = src[srcp++]; if ( strcmp(line[actcol], "C") != 0 ) notImplemented("Second continuation line missing from BULK COPY"); codeOutSM(6, atoi(line[disccol]), atoi(line[modcol]), atoi(line[refcol]), atoi(line[itemcol]), "0", line); } else codeOut(1, 1, 3, w, NULL); // literal transfer size codeOut(18, 1, 1, 5, NULL); if ( destmod >= 4 ) // destination is modified indirectly codeOut(24, 1, 2, destmod, NULL); else if ( destmod != 0 ) // destination is modified by mod reg codeOut(24, 0, 0, destmod + modinfo, NULL); if ( desttran == -2 ) // destination is modified and non-local codeOut(28, disc, mod, 0, NULL); // address has been placed in W/L else codeOut(28, disc, mod, memref(ref, item, "0"), NULL); } break; /* --------------- */ case 56: // 056 - TABLE LOOKUP notImplemented("TABLE LOOKUP"); break; /* --------------- */ case 57: // 057 - MERGE CONSTANT LENGTH ITEMS notImplemented("MERGE CONSTANT LENGTH ITEMS"); break; /* --------------- */ case 58: // 058 - MERGE VARIABLE LENGTH ITEMS notImplemented("MERGE VARIABLE LENGTH ITEMS"); break; /* --------------- */ case 59: // 059 - SET MODIFICATION REGISTER FOR MERGE if ( mod < 4 ) notImplemented("Real modifier"); // cannot do this yet else { int mloc = swref(mod+1000); // location of simulated modifier w = proc0size[curchap]; // address of W/L codeOut(0, 1, 0, w, line); // Copy ABC codeOut(0, 0, 3, 0, NULL); // Set binary codeOut(24, 0, 2, memref(ref, item, "0"), NULL); // Start location codeOut(3, 0, 0, mloc , NULL); // Less significant half of modification register line = src[srcp++]; if ( strcmp(line[actcol], "C") != 0 ) notImplemented("Continuation line missing from SET MOD..."); else { codeOut(4, atoi(line[disccol]), atoi(line[modcol]), // Length memref(atoi(line[refcol]), atoi(line[itemcol]), "0"), line); codeOut(2, 0, 0, mloc+1 , NULL); // More significant half of modification resister } codeOut(0, 1, 1, w, NULL); // Restore ABC } break; /* --------------- */ case 60: // 060 - SET DECIMAL RADIX codeOut(0, 0, 3, cloc21(0x66666), line); break; /* --------------- */ case 61: // 061 - SET STERLING RADIX notImplemented("SET STERLING RADIX"); break; /* --------------- */ case 62: // 062 - SET EXCESS CONSTANTS codeOut(0, 0, 3, hexlit(lit), line); break; /* --------------- */ case 63: // 063 - CONVERT DECIMAL TO STERLING notImplemented("CONVERT DECIMAL TO STERLING"); break; /* --------------- */ case 64: // 064 - CONVERT STERLING TO DECIMAL notImplemented("CONVERT STERLING TO DECIMAL"); break; /* --------------- */ case 65: // 065 - CONVERT notImplemented("CONVERT"); break; /* --------------- */ case 66: // 066 - SET UP FOR SIGNIFICANT DIGIT FLOATING POINT ARITHMETIC notImplemented("SET UP FOR SIGNIFICANT DIGIT FLOATING POINT ARITHMETIC"); break; /* --------------- */ case 67: // 067 - SET UP FOR NORMALISED FLOATING POINT ARITHMETIC notImplemented("SET UP FOR NORMALISED FLOATING POINT ARITHMETIC"); break; /* --------------- */ case 70: // 070 - JUMP IF A == 0 codeOut(27, 0, 0, memref(ref, item, lit), line); break; /* --------------- */ case 71: // 071 - JUMP IF A != 0 codeOut(27, 0, 1, memref(ref, item, lit), line); break; /* --------------- */ case 72: // 072 - JUMP IF A >= 0 codeOut(27, 0, 2, memref(ref, item, lit), line); break; /* --------------- */ case 73: // 073 - JUMP IF A < 0 codeOut(27, 0, 3, memref(ref, item, lit), line); break; /* --------------- */ case 74: // 074 - JUMP IF AB == 0 // 27, 1, 0 codeOut(27, 1, 0, memref(ref, item, lit), line); break; /* --------------- */ case 75: // 075 - JUMP IF AB != 0 codeOut(27, 1, 1, memref(ref, item, lit), line); break; /* --------------- */ case 76: // 076 - JUMP unconditional codeOut(24, 1, 0, memref(ref, item, lit), line); break; /* --------------- */ case 77: // 077 - JUMP IF A* == 0 notImplemented("JUMP IF A* == 0"); break; /* --------------- */ case 78: // 078 - JUMP IF A* != 0 notImplemented("JUMP IF A* != 0"); break; /* --------------- */ case 79: // 079 - JUMP IF A* >= 0 notImplemented("JUMP IF A* >= 0"); break; /* --------------- */ case 80: // 080 - ENTER SUBROUTINE codeOut(26, 0, 0, memref(ref, 2, lit), line); // we need to ignore the item and go to the start w = 0; // for counting continuation lines while ( strcmp(src[srcp + (w++)][actcol], "C") == 0 ) ; if ( --w != 0 ) { codeOut(24, 1, 0, loc + w + 1, NULL); conpars(); // deal with continuation lines which are addresses of locations } // notImplemented("Subroutine parameters"); break; /* --------------- */ case 81: // 081 - START OF SUBROUTINE last81 = loc; // used for accessing parameters codeOut(0, 0, 0, 0, line); // generates zero word for the link address break; /* --------------- */ case 82: // 082 - END OF SUBROUTINE / LEAVE SUBROUTINE codeOut(26, 0, 1, memref(ref, 2, lit), line); // seems we need to ignore the item and get returj from the start break; /* --------------- */ case 83: // 083 - SET SWITCH(ES) AT LITERAL VALUE w = hexlit(lit); // assume usual meaning if ( w >= 10 ) // but warn of large values fprintf(fout, " Large switch value at line %s\n", line[sercol]); codeOut(1, 1, 3, w, line); codeOut(2, 0, 0, swref(ref), NULL); // transfer to private location break; /* --------------- */ case 84: // 084 - SET SWITCH(ES) AT VARIABLE VALUE if ( *(src[srcp][actcol]) == 'C' ) // continuation line { char **conline; // notImplemented("SET SWITCH(ES) AT VARIABLE"); // to flag until we meet one in execution conline = src[srcp++]; w = atoi(conline[refcol]); item = atoi(conline[itemcol]); mod = atoi(conline[modcol]); disc = atoi(conline[disccol]); codeOut(6, disc, mod, memref(w, item, "0"), line); line = conline; // generates correct listing on next line } codeOut(2, 0, 0, swref(ref), line); // transfer to private location break; /* --------------- */ case 85: // 085 - SWITCH R codeOut(24, 0, 1, swref(ref), line); codeOut(26, 0, 1, (loc + chapaddr[curchap]) & 017777, NULL); // exit via next word - assume switch starts at 1 conpars(); // deal with continuation lines which are addresses of locations break; /* --------------- */ case 86: // 086 - SELECT SWITCH R codeOut(6, 0, 0, swref(ref), line); break; /* --------------- */ case 87: // 087 - SWITCH ACCORDING TO N codeOut(24, 0, 1, memref(ref, item, lit), line); // modify addr used for exit codeOut(26, 0, 1, (loc + chapaddr[curchap]) & 017777, NULL); // exit via next word - assume switch starts at 1 conpars(); // deal with continuation lines which are addresses of locations break; /* --------------- */ case 90: // 090 - SET MODIFICATION REGISTER AT LITERAL w = declit(lit); // pointer value ref = declit(src[srcp][litcol]); // end value if ( strcmp(src[srcp][actcol], "C") != 0 ) notImplemented("Continuation line missing from SET MOD..."); else if ( mod >= 4 ) { codeOut(6, 1, 0, cloc41(ref&32767, w&32767), line); actinfo = "Simulated modifier"; codeOut(2, 1, 0, swref(1000+mod), src[srcp++]); } else { codeOut(26, 1, mod, cloc41(ref&32767, w&32767), line); actinfo = "Limit"; codeOut(-1, 0, 0, 0, src[srcp++]); // generates no code, just lists the continuation line and steps srcp } break; /* --------------- */ case 91: // 091 - SET MODIFICATION REGISTER AT VARIABLE if ( ref > 0 || item != 0 ) // does this equate to N != 0 ? w = memref(ref, item, "0"); // addressing location else if ( mod >= 4 ) // simulated modifier with value in A w = 0; // indicates value now in A from where we can copy to modifier else { w = proc0size[curchap]; // address of W/L codeOut(3, 1, 0, w, line); // put A into W/L line = NULL; // suppress listing on 2nd instruction } if ( mod < 4 ) // proper modifier codeOut(26, 1, mod, w, line); else if ( w == 0 ) codeOut(2, 1, 0, swref(mod+1000), line); // copy to simulated location else { codeOut(6, 1, 0, w, line); // value from variable location codeOut(2, 1, 0, swref(mod+1000), NULL); // copy to simulated location } break; /* --------------- */ case 92: // 092 - SET MODIFIER AT VARIABLE if ( ref != absent || item != 0 ) // does this equate to N != 0 ? { codeOut(6, 0, 0, memref(ref, item, "0"), line); // load variable line = NULL; // suppress listing on 2nd instruction } if ( mod >= 4 ) codeOut(2, 0, 0, swref(mod+1000), line); // transfer to location of simulated modifier else { codeOut(24, 0, 3, modinfo, line); // points at modifier group codeOut(2, 0, 0, mod + mod, NULL); // do the deed and leave A clear } break; /* --------------- */ case 93: // 093 - SET (N) AS MODIFIER notImplemented("SET (N) AS MODIFIER"); break; /* --------------- */ case 97: // 097 - STEP ON AND TEST MODIFICATION REGISTER (VARIABLE) codeOut(24, 0, 1, memref(ref, item, "0"), line); line = src[srcp++]; if ( *(line[actcol]) != 'C' ) // if no continuation line { line = NULL; // avoid reprint of source srcp --; // remove increment ref = 0; // execute next instruction } else if ( atoi(line[modcol]) != 0 ) notImplemented("Modified destination"); else { ref = atoi(line[refcol]); item = atoi(line[itemcol]); } lit = "0"; // ensures zero address part in next bit // drop through - now that we have tweaked the parameters /* --------------- */ case 94: // 094 - STEP ON AND TEST MODIFICATION REGISTER (LITERAL) w = declit(lit); if ( w < 0 ) w = 0x1000 - w; // 13-bit sign and modulus if ( mod >= 4 ) // simulated modifier { codeOut(23, 0, 0, w, line); codeOut(0, 0, 1, swref(1000+mod), NULL); } else codeOut(25, 0, mod, w, line); icAct = 89; // cause addresses to be calculated from serial no if ( ref > 0 ) // reference is present codeOut(24, 1, 0, memref(ref, item, "0"), NULL); else codeOut(24, 1, 0, (loc+1)&0x1FFF, NULL); // jump to next instruction break; /* --------------- */ case 95: // 095 - SELECT MODIFICATION REGISTER // drop through - only discriminant is different between 95 and 96 /* --------------- */ case 96: // 096 - SELECT MODIFIER if ( mod >= 4 ) codeOut(6, act&1, 0, swref(1000+mod), NULL); // Simulated modifier else { codeOut(24, 0, 3, modinfo, line); codeOut(6, act&1, 0, mod + mod, NULL); // accessed via pointer proc 0 } break; /* --------------- */ case 98: // 098 - ADD MODIFICATION REGISTER TO A // drop through - only action is different between 95 and 96 /* --------------- */ case 99: // 099 - SUBTRACT MODIFICATION REGISTER FROM A if ( mod >= 4 ) codeOut(act-94, disc, 0, swref(1000+mod), line); else { codeOut(24, 0, 3, modinfo, line); codeOut(act-94, disc, 0, mod + mod, NULL); // accessed via pointer proc 0 } break; /* --------------- */ case 100: // 100/0/0 HALT // 100: 100/0/3 SET RADIX // 100: 100/1/0 COPY REGISTERS // 100: 100/1/1 REPLACE REGISTERS // 100: 100/d/2 REPLACE (B) BY (N) case 101: // 101/0/1 PREPARE FOR DIGIT COLLATION // 101: 101/0/2 ROUND OFF // 101: 101/0/3 INTERCHANGE AREA ADDRESSES // 101: 101/1/1 ADD LITERAL ADDRESS // 101: 101/1/2 SUBTRACT LITERAL ADDRESS // 101: 101/1/3 SELECT LITERAL ADDRESS // 101: 101/d/0 TABLE LOOK UP case 102: // 102/d/m TRANSFER (A) TO N case 103: // 103/d/m COPY (A) TO N case 104: // 104/d/m ADD (N) TO (A) case 105: // 105/d/m SUBTRACT (N) FROM (A) case 106: // 106/d/m SELECT (N) case 107: // 107/d/m AUGMENT (N) BY (A) case 108: // 108/0/m MERGE CONSTANT LENGTH // 108: 108/1/m MERGE VARIABLE LENGTH case 109: // 109/d/m MULTIPLY UNIFORM RADIX case 110: // 110/d/m MULTIPLY AND ADD case 111: // 111/d/m MULTIPLY AND SUBTRACT case 112: // 112/d/m CONVERT case 113: // 113/d/m DIVIDE UNIFORM RADIX case 114: // 114/d/m REPLACE SELECTED BITS case 115: // 115/d/m COLLATE AND ADD case 116: // 116/1/0 COMPARE case 117: // 117/0/0 SPECIAL SELECT // 117: 117/1/0 SPECIAL COPY case 118: // 118/0/0 SHIFT LOGICAL // 118: 118/0/1 SHIFT ARITHMETIC // 118: 118/0/2 SCALE NUMERATOR // 118: 118/0/3 SHIFT BINARY // 118: 118/1/0 SHIFT LOGICAL // 118: 118/1/1 SHIFT ARITHMETIC // 118: 118/1/2 SCALE DENOMINATOR // 118: 118/1/3 SHIFT BINARY case 119: // 119/0/0 OUTPUT // 119: 119/0/1 INPUT ONE BLOCK/RESET TIMER // 119: 119/0/2 RUN BACK // 119: 119/0/3 RUN FORWARD // 119: 119/1/0 STEP BACK // 119: 119/1/1 REWIND // 119: 119/1/2 UNLOAD // 119: 119/1/3 STEP ON/SET MANUAL case 120: // 120/0/m ADD FLOATING POINT // 120: 120/1/m SUBTRACT FLOATING POINT case 121: // 121/0/m TRANSFER FLOATING POINT // 121: 121/1/m COPY FLOATING POINT case 122: // 122/0/m MULTIPLY FLOATING POINT // 122: 122/1/m DIVIDE FLOATING POINT case 123: // 123/0/0 STEP ON AND TEST // 123: 123/0/2 ENTER MASTER ROUTINE // 123: 123/0/3 SELECT TAG // 123: 123/1/m COPY INTO TAG case 124: // 124/0/0 MODIFY ADDRESS OF NEXT // 124: 124/0/1 MODIFY ADDRESS OF NEXT // 124: 124/0/2 SELECT LITERAL AND DIVISION // 124: 124/0/3 MODIFY ADDRESS OF NEXT // 124: 124/1/0 UNCONDITIONAL JUMP // 124: 124/1/1 SET MODIFICATION GROUP // 124: 124/1/2 MODIFY ADDRESS OF NEXT case 125: // 125/0/m STEP ON AND TEST // 125: 125/1/0 SET INDICATORS // 125: 125/1/1 CLEAR INDICATORS // 125: 125/1/2 INTERROGATE INDICATORS // 125: 125/1/3 CONDITIONAL HALT case 126: // 126/0/0 ENTER SUBROUTINE // 126: 126/0/1 LEAVE SUBROUTINE // 126: 126/0/2 ENTER PRIORITY CONTROL // 126: 126/0/3 LEAVE MASTER ROUTINE // 126: 126/1/0 TEST ROUTE // 126: 126/1/m SET MODIFICATION REGISTER case 127: // 127/0/0 JUMP A = Z // 127: 127/0/1 JUMP A != // 127: 127/0/2 JUMP A >= Z // 127: 127/0/3 JUMP A < Z // 127: 127/1/0 JUMP AB = Z // 127: 127/1/1 JUMP AB != Z // 127: 127/1/2 JUMP AB >= Z // 127: 127/1/3 JUMP AB < Z case 128: // 128/0/0 BULK CLEAR SHORT // 128: 128/0/0 BULK COPY SHORT NUMERIC // 128: 128/0/1 BULK COPY SHORT NUMERIC // 128: 128/0/2 UNPACK FIXED FIELD DATA // 128: 128/0/3 UNPACK VARIABLE FIELD DATA // 128: 128/1/0 BULK COPY ALPHA TO SHORT // 128: 128/1/1 BULK CLEAR LONG // 128: 128/1/1 BULK COPY LONG NUMERIC // 128: 128/1/2 EDIT FIXED FIELD FORMATS // 128: 128/1/3 CONDENSE case 129: // 129/0/0 EDIT FOR HOLLERITH OUTPUT // 129: 129/0/1 EDIT FOR ANELEX OUTPUT case 130: // 130/0/m TRANSFER DOUBLE LENGTH // 130: 130/1/m COPY DOUBLE LENGTH case 131: // 131/0/m ADD DOUBLE LENGTH // 131: 131/1/m SUBTRACT DOUBLE LENGTH computerCode(act, ref, item, lit, disc, mod); break; /* --------------- */ /* --------------- */ case 140: // 140 - CLEAR AB notImplemented("CLEAR AB"); break; /* --------------- */ case 141: // 141 - DOUBLE LENGTH ADD notImplemented("DOUBLE LENGTH ADD"); break; /* --------------- */ case 142: // 142 - DOUBLE LENGTH SUBTRACT notImplemented("DOUBLE LENGTH SUBTRACT"); break; /* --------------- */ case 143: // 143 - DOUBLE LENGTH COPY notImplemented("DOUBLE LENGTH COPY"); break; /* --------------- */ case 145: // 145 - DOUBLE LENGTH TRANSFER notImplemented("DOUBLE LENGTH TRANSFER"); break; /* --------------- */ case 146: // 146 - DOUBLE LENGTH MULTIPLY notImplemented("DOUBLE LENGTH MULTIPLY"); break; /* --------------- */ case 147: // 147 - DOUBLE LENGTH MULTIPLY and ADD notImplemented("DOUBLE LENGTH MULTIPLY and ADD"); break; /* --------------- */ case 148: // 148 - DOUBLE LENGTH MULTIPLY and SUBTRACT notImplemented("DOUBLE LENGTH MULTIPLY and SUBTRACT"); break; /* --------------- */ case 150: // 150 - OFFER OPTIONS w = hexlit(lit); if ( w == 0 ) // zero literal ... codeOut(6, 0, 0, memref(ref, item, lit), line); else codeOut(1, 1, 3, w, line); codeOut(0, 0, 2, cloc21(concount()), NULL); codeOut(25, 1, 1, 4096, NULL); codeOut(24, 0, 3, zero, NULL); codeOut(26, 0, 2, 1, NULL); // see comment on routiner svc in leo3.c conpars(); // deal with continuation lines which are addresses of locations break; /* --------------- */ case 151: // 151 - UNLOAD PROGRAMME codeOut(25, 1, 1, 4096, line); codeOut(24, 0, 3, zero, NULL); codeOut(26, 0, 2, 2, NULL); // see comment on routine svc in leo3.c break; /* --------------- */ case 152: // 152 - OVERLAY w = atoi(src[srcp][refcol]); // start chapter of new overlay if ( pass == 1 ) { fprintf(fout, "\n -------------------------\n"); fprintf(fout, " Equivalent PROCRs %d %s\n", ref, src[srcp][refcol]); fprintf(fout, " Equivalent CHAPs %d %d\n", procchap[ref], procchap[w]); curovr ++; // move to next overlay ovrindex[curovr] = w; fprintf(fout, " Overlay %d starts at proc %d\n", curovr, w); } else { int i = -1; while ( ovrindex[++i] >= 0 && ovrindex[i] != w ) ; // find which overlay we are calling if ( i < 0 ) fprintf(fout, " PROCR %d in CHAP %d is not recorded as starting an overlay\n", w, procchap[w]); else fprintf(fout, " PROCR %d in CHAP %d overlay = %d\n", w, procchap[w], i); w = i; } codeOut(24, 0, 3, zero, line); // enter Master codeOut(23, 0, 2, 100+w, src[srcp++]); // overlay indicated by n - 100 break; /* --------------- */ case 153: // 153 - SELECT DATE TO A, TIME TO B codeOut(24, 0, 3, zero, NULL); // division 0 codeOut(6, 1, 0, 138, line); // pick up date -- temp because no storage protection codeOut(24, 0, 3, zero, NULL); // division 0 codeOut(0, 0, 2, 156, NULL); // pick up time -- not yet implemented in emulator break; /* --------------- */ case 154: // 154 - COMMENT IN LOG w = proc0size[curchap]; // address of W/Ls codeOut( 0, 1, 0, w, line); // Copy ABC codeOut( 0, 0, 3, 0, NULL); // Set binary codeOut(24, 0, 2, memref(ref, item, lit), NULL); // Select annexe start codeOut(24, 0, 3, zero, NULL); // Enter Master codeOut(23, 0, 2, 154, NULL); // codeOut( 0, 1, 1, w, NULL); // Restore ABC break; /* --------------- */ case 155: // 155 - SELECT PROGRAM SERIAL TO A codeOut(6, 1, 0, cloc41(0x30483, 0x04141), line); break; /* --------------- */ case 156: // 156 - RELEASE ROUTE(S) ALLOCATED TO FILE B notImplemented("RELEASE ROUTE(S) ALLOCATED TO FILE B"); break; /* --------------- */ case 157: // 157 - EXPAND notImplemented("EXPAND"); break; /* --------------- */ case 158: // 158 - COMPARE notImplemented("COMPARE"); break; /* --------------- */ case 13: case 14: case 15: case 18: case 27: case 28: case 68: case 69: case 88: case 89: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 144: case 149: case 159: notImplemented("Unknown instruction"); /* --------------- */ break; case 160: // 160 action field blank - now thought to be zero if ( mode == PROCMODE ) // ... so this first bit is never used { fprintf(fout, " Action field blank - constant assumed -- deal with it later\n"); addr[srcp-1] = -1; // TEMP !!! overwrite loc value codeOut(-1, 0, 0, 0, src[srcp-1]); // generates no code, just listing } else if ( mode == CONSTSHORT ) // either short or long parseconst(CONSTSHORT, line); else if ( mode == CONSTLONG ) // either short or long parseconst(CONSTLONG, line); else fprintf(fout, " This connot happen: mode = %d\n", mode); break; case 161: // 161 start of procedure mode = PROCMODE; startproc(ref); break; case 162: // 162 start of constant section if ( disc == 1 || item == 1 ) { mode = CONSTLONG; // long constants indicated in either column if ( (loc&1) != 0 ) // odd address codeOut(31, 1, 3, 8191, NULL); // round up to long word with anything } else mode = CONSTSHORT; // short constants cmode = '?'; // forces definitions of type in first line startproc(ref); break; case 163: // 163 blank line or comment break; // ignore everything else case 164: // 164 Filename identification or warning imagelink(line); break; case 165: // act = alpha -- unimplemented continuation line if ( strcmp(line[actcol], "NOTES") == 0 ) codeOut(-1, 0, 0, 0, line); // generates no code, just listing else codeOut(999, 0, 0, 0, line); break; case 166: // a row of a table parsetable(tabtype, line); break; case 167: // start of a table if ( (loc&1) != 0 ) // odd address codeOut(31, 1, 3, 8191, NULL); // round up to long word with anything mode = TABLEMODE; if ( disc == 0 ) disc = item; // correct for change of convention mid way through if ( disc == 0 ) printf("Failed to find type for table %d\n", ref); tabtype = disc; startproc(ref); break; case 168: // set padding for a chapter padding[ref] = item; codeOut(-1, 0, 0, 0, line); // generates no code, just listing } } constaddr(1); // sort out constants for the last chapter precedure0(curchap); // manufacture proc 0 for chapter just ending if ( olcount != 0 ) // overlaid program needs last overlay specification fprintf(fout, "O%02d %5d %5d Overlaying final chapter %d, equivalent to chapter %d\n", olcount++, chapaddr[curchap], loc, curchap, equivchap[curchap]); } // Initialise diagnostic arrays char *icstr[] = { "SELECT", "ADD", "SUBTRACT", "COPY", "AUGMENT", "TRANSFER", "MULTIPLY", "MULTIPLY and ADD", "MULTIPLY and SUBTRACT", "DIVIDE", "SELECT LITERAL", "ADD LITERAL", "SUBTRACT LITERAL", "Invalid", "Invalid", "Invalid", "MULTIPLY LITERAL", "MULTIPLY LITERAL and ADD", "Invalid", "DIVIDE LITERAL", "SELECT F/Point", "ADD F/Point", "SUBTRACT F/Point", "COPY F/Point", "AUGMENT F/Point", "TRANSFER F/Point", "MULTIPLY F/Point", "Invalid", "Invalid", "DIVIDE F/Point", "SHIFT (A) BY QUARTETS", "SHIFT (A) BY BITS", "SHIFT (AB) BY QUARTETS", "SHIFT (AB) BY BITS", "SET (N) IN B", "PREPARE FOR DIGIT COLLATION", "COLLATE AND ADD", "REPLACE SELECTED BITS", "ROUND OFF", "ROUND UP", "OPEN FILE", "CLOSE FILE", "INPUT", "OUTPUT", "SET/SELECT REEL COUNTER", "REWIND", "RUN BACK", "RUN ON", "STEP BACK", "STEP FORWARD", "UNPACK FIXED FIELD DATA", "UNPACK VARIABLE FIELD DATA", "EDIT", "CONDENSE", "BULK CLEAR", "BULK COPY", "TABLE LOOKUP", "MERGE CONSTANT LENGTH ITEMS", "MERGE VARIABLE LENGTH ITEMS", "SET MODIFICATION REGISTER FOR MERGE", "SET DECIMAL RADIX", "SET STERLING RADIX", "SET EXCESS CONSTANTS", "CONVERT DECIMAL TO STERLING", "CONVERT STERLING TO DECIMAL", "CONVERT", "SET UP FOR SIGNIFICANT DIGIT FLOATING POINT ARITHMETIC", "SET UP FOR NORMALISED FLOATING POINT ARITHMETIC", "Invalid", "Invalid", "JUMP IF A == 0", "JUMP IF A != 0", "JUMP IF A >= 0", "JUMP IF A < 0", "JUMP IF AB == 0 // 27, 1, 0", "JUMP IF AB != 0", "JUMP unconditional", "JUMP IF A* == 0", "JUMP IF A* != 0", "JUMP IF A* >= 0", "ENTER SUBROUTINE", "START OF SUBROUTINE", "END OF SUBROUTINE / LEAVE SUBROUTINE", "SET SWITCH(ES) AT LITERAL VALUE", "SET SWITCH(ES) AT VARIABLE VALUE", "SWITCH R", "SELECT SWITCH R", "SWITCH ACCORDING TO N", "Invalid", "Invalid", "SET MODIFICATION REGISTER AT LITERAL", "SET MODIFICATION REGISTER AT VARIABLE", "SET MODIFIER AT VARIABLE", "SET (N) AS MODIFIER", "STEP ON AND TEST MODIFICATION REGISTER (LITERAL)", "SELECT MODIFICATION REGISTER", "SELECT MODIFIER", "STEP ON AND TEST MODIFICATION REGISTER (VARIABLE)", "ADD MODIFICATION REGISTER TO A", "SUBTRACT MODIFICATION REGISTER FROM A", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Leo CODE", "Invalid", "Invalid", "Invalid", "Invalid", "Invalid", "Invalid", "Invalid", "Invalid", "CLEAR AB", "DOUBLE LENGTH ADD", "DOUBLE LENGTH SUBTRACT", "DOUBLE LENGTH COPY", "Invalid", "DOUBLE LENGTH TRANSFER", "DOUBLE LENGTH MULTIPLY", "DOUBLE LENGTH MULTIPLY and ADD", "DOUBLE LENGTH MULTIPLY and SUBTRACT", "Invalid", "OFFER OPTIONS", "UNLOAD PROGRAMME", "OVERLAY", "SELECT DATE TO A, TIME TO B", "COMMENT IN LOG", "SELECT PROGRAM SERIAL TO A", "RELEASE ROUTE(S) ALLOCATED TO FILE B", "EXPAND", "COMPARE", "Invalid", "blank"}; char *ccstr[] = { "HALT", "Invalid", "REPLACE (B) BY (N)", "SET RADIX", "COPY REGISTERS", "REPLACE REGISTERS", "REPLACE (B) BY (N)", "Invalid", "TABLE LOOK UP", "PREPARE FOR DIGIT COLLATION", "ROUND OFF", "INTERCHANGE AREA ADDRESSES", "TABLE LOOK UP", "ADD LITERAL ADDRESS", "SUBTRACT LITERAL ADDRESS", "SELECT LITERAL ADDRESS", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "TRANSFER (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "COPY (A) TO N", "ADD (N) TO (A)", "ADD (N) TO (A)", "ADD (N) TO (A)", "ADD (N) TO (A)", "ADD (N) TO (A)", "ADD (N) TO (A)", "ADD (N) TO (A)", "ADD (N) TO (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SUBTRACT (N) FROM (A)", "SELECT (N)", "SELECT (N)", "SELECT (N)", "SELECT (N)", "SELECT (N)", "SELECT (N)", "SELECT (N)", "SELECT (N)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "AUGMENT (N) BY (A)", "MERGE CONSTANT LENGTH", "MERGE CONSTANT LENGTH", "MERGE CONSTANT LENGTH", "MERGE CONSTANT LENGTH", "MERGE VARIABLE LENGTH", "MERGE VARIABLE LENGTH", "MERGE VARIABLE LENGTH", "MERGE VARIABLE LENGTH", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY UNIFORM RADIX", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND ADD", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "MULTIPLY AND SUBTRACT", "CONVERT", "CONVERT", "CONVERT", "CONVERT", "CONVERT", "CONVERT", "CONVERT", "CONVERT", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "DIVIDE UNIFORM RADIX", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "REPLACE SELECTED BITS", "COLLATE AND ADD", "COLLATE AND ADD", "COLLATE AND ADD", "COLLATE AND ADD", "COLLATE AND ADD", "COLLATE AND ADD", "COLLATE AND ADD", "COLLATE AND ADD", "Invalid", "Invalid", "Invalid", "Invalid", "COMPARE", "Invalid", "Invalid", "Invalid", "SPECIAL SELECT", "Invalid", "Invalid", "Invalid", "SPECIAL COPY", "Invalid", "Invalid", "Invalid", "SHIFT LOGICAL", "SHIFT ARITHMETIC", "SCALE NUMERATOR", "SHIFT BINARY", "SHIFT LOGICAL", "SHIFT ARITHMETIC", "SCALE DENOMINATOR", "SHIFT BINARY", "OUTPUT", "INPUT ONE BLOCK/RESET TIMER", "RUN BACK", "RUN FORWARD", "STEP BACK", "REWIND", "UNLOAD", "STEP ON/SET MANUAL", "ADD FLOATING POINT", "ADD FLOATING POINT", "ADD FLOATING POINT", "ADD FLOATING POINT", "SUBTRACT FLOATING POINT", "SUBTRACT FLOATING POINT", "SUBTRACT FLOATING POINT", "SUBTRACT FLOATING POINT", "TRANSFER FLOATING POINT", "TRANSFER FLOATING POINT", "TRANSFER FLOATING POINT", "TRANSFER FLOATING POINT", "COPY FLOATING POINT", "COPY FLOATING POINT", "COPY FLOATING POINT", "COPY FLOATING POINT", "MULTIPLY FLOATING POINT", "MULTIPLY FLOATING POINT", "MULTIPLY FLOATING POINT", "MULTIPLY FLOATING POINT", "DIVIDE FLOATING POINT", "DIVIDE FLOATING POINT", "DIVIDE FLOATING POINT", "DIVIDE FLOATING POINT", "STEP ON AND TEST", "Invalid", "ENTER MASTER ROUTINE", "SELECT TAG", "COPY INTO TAG", "COPY INTO TAG", "COPY INTO TAG", "COPY INTO TAG", "MODIFY ADDRESS OF NEXT", "MODIFY ADDRESS OF NEXT", "SELECT LITERAL AND DIVISION", "MODIFY ADDRESS OF NEXT", "UNCONDITIONAL JUMP", "SET MODIFICATION GROUP", "MODIFY ADDRESS OF NEXT", "Invalid", "STEP ON AND TEST", "STEP ON AND TEST", "STEP ON AND TEST", "STEP ON AND TEST", "SET INDICATORS", "CLEAR INDICATORS", "INTERROGATE INDICATORS", "CONDITIONAL HALT", "ENTER SUBROUTINE", "LEAVE SUBROUTINE", "ENTER PRIORITY CONTROL", "LEAVE MASTER ROUTINE", "SET MODIFICATION REGISTER", "SET MODIFICATION REGISTER", "SET MODIFICATION REGISTER", "SET MODIFICATION REGISTER", "JUMP A = Z", "JUMP A !=", "JUMP A >= Z", "JUMP A < Z", "JUMP AB = Z", "JUMP AB != Z", "JUMP AB >= Z", "JUMP AB < Z", "BULK COPY SHORT NUMERIC", "BULK COPY SHORT NUMERIC", "UNPACK FIXED FIELD DATA", "UNPACK VARIABLE FIELD DATA", "BULK COPY ALPHA TO SHORT", "BULK COPY LONG NUMERIC", "EDIT FIXED FIELD FORMATS", "CONDENSE", "EDIT FOR HOLLERITH OUTPUT", "EDIT FOR ANELEX OUTPUT", "Invalid", "Invalid", "Invalid", "Invalid", "Invalid", "Invalid", "TRANSFER DOUBLE LENGTH", "TRANSFER DOUBLE LENGTH", "TRANSFER DOUBLE LENGTH", "TRANSFER DOUBLE LENGTH", "COPY DOUBLE LENGTH", "COPY DOUBLE LENGTH", "COPY DOUBLE LENGTH", "COPY DOUBLE LENGTH", "ADD DOUBLE LENGTH", "ADD DOUBLE LENGTH", "ADD DOUBLE LENGTH", "ADD DOUBLE LENGTH", "SUBTRACT DOUBLE LENGTH", "SUBTRACT DOUBLE LENGTH", "SUBTRACT DOUBLE LENGTH", "SUBTRACT DOUBLE LENGTH"}; main(int argc, char **argv) { FILE *fin; char **line; int v, j; int i = 0; int numchaps, numroutes; char *magic[] = { "%05d %2d/0 %s%s\n", "%05d %2d/1 %s%s\n", "%05d %2d/2 %s%s\n", "%05d %2d/3 %s%s\n", "%05d %2d/4 %s%s\n", "%05d %2d/5 %s%s\n", "%05d %2d/6 %s%s\n", "%05d %2d/7 %s%s\n", "%05d %2d/8 %s%s\n", "%05d %2d/9 %s%s\n", "%05d %2d/t %s%s\n" }; while ( *(argv[++i]) == '-' ) if ( (j = argv[i][1]) == 'v' ) if ( argv[i][2] == 0 ) verbosity ++; else verbosity = atoi(argv[i]+2); else if ( j == 'h' ) // insert hyperlinks hyperlinks ++; else if ( j == 'b' ) // operate without transit area buffer swaps nobuffswap = 1; // must run with -b switch on emulator fin = fopen(argv[i], "r"); if ( argc < i + 2 ) fout = stdout; else fout = fopen(argv[i+1], "w"); mkchars(); // sort out Leo characters if ( hyperlinks > 1 ) // put hot links into action info { for ( i = 0; i<70; i++ ) // creating actinfos with hot links { sprintf(buff, "%s", i, icstr[i]); icstr[i] = strdup(buff); } for ( i = 70; i<80; i++ ) // jumps are all lumped together { sprintf(buff, "%s", icstr[i]); icstr[i] = strdup(buff); } for ( i = 80; i<100; i++ ) // stop before computer code actions { sprintf(buff, "%s", i, icstr[i]); icstr[i] = strdup(buff); } for ( i = 140; i<159; i++ ) // all sorts of fancy stuff :-) { sprintf(buff, "%s", i, icstr[i]); icstr[i] = strdup(buff); } } // ser,act,ref,item,d,m,literal,comment -- order of columns is now defined to be this -- probably for ( i = 0; i<999; i++ ) // clear out this array before processing section declarations { procstart[i] = -1; procchap[i] = -1; } procstart[999] = 0; procchap[0] = 0; // ensures that absolute addresses are rocignised as in chapter 0 (equiv to 1) line = readline(fin); // first line must define columns if ( head == NULL ) { fprintf(fout, "First line must define columns\n"); printf("First line must define columns\n"); fprintf(fout, "Col1 = %s\n", line[0]); exit(1); } if ( nobuffswap == 0 ) fprintf(fout, "\n
\n");
   else
      fprintf(fout, "\n

This binary program must be emulated with -b switch

\n");

   for  ( i = 0; i 0 )
         fprintf(fout, "Skipped: %s %s\n", line[actcol], line[refcol]);
   // doline(line);
      line = readline(fin);
   }
   numroutes = i;             // count of number of I/O routes (i.e. files -- alternates ignored

   v = atoi(line[2]);             // max chapter number
   numchaps = v;
   i = atoi(line[3]);             // start at PROCR
   fprintf(fout, "%s  %d chapters + 0  start at proc %d\n", line[1], v, i);
   for  ( curchap = 1; curchap<=v; curchap++ )
   {  i = atoi(line[curchap+2]);  // chapter number
      secsize[curchap] = 0;       // total size of sections
      chapaddr[curchap] = 0;      // in pass 1 this is unimportant, in pass2 it is the base address of the chapter
      procchap[i] = curchap;      // number of chapter for this procedure
      fprintf(fout, "Procedure %d starts chapter %d\n", i, curchap);
      padding[curchap] = 0;       // space to align sections with action 168

      ovrindex[curchap] = -1;     // just make sure we have max poss overlays indexed
      equivchap[curchap] = curchap;
   }
   chapaddr[0] = 0;      // in pass 1 this is unimportant, in pass2 it is the base address of the chapter
   proc0size[0] = 0;     // do we need procedure 0 in chapter 0?
   chapaddr[v+1] = -1;   // marks end of list of chapters
   ovrindex[0] = 100;    // start of initial chapters
   equivchap[0] = 1;     // chapter 0 means absolute address, and chapter 1 is in division 1

   while  ( strcmp((line = readline(fin))[actcol], "PROCR") != 0 )  // process sections upto code sheets
      if  ( atoi(line[actcol]) == 164 )       // Link to source file
         imagelink(line);

      else if  ( strcmp(line[actcol], "INDEX") == 0 )  // INDEX of overlay equivalents
      {  for  ( curchap = 1; chapaddr[curchap] >= 0; curchap++ )      
         {  i = atoi(line[curchap+2]);  // chapter number or equivalent
            equivchap[curchap] = i;
         }
      }

      else if  ( strlen(line[actcol]) != 0 )       // ... or something else that we do not understand
         fprintf(fout, "Skipped: %s %s\n", line[actcol], line[refcol]);

      else if  ( strlen(line[refcol]) != 0 )  // must be a section definition
      {  i = atoi(line[refcol]);              // section number
         v = atoi(line[itemcol]);             // size in long words
         curchap = atoi(line[modcol]);
         procchap[i] = curchap;               // number of chapter for this section
         procstart[i] = secsize[curchap];     // put it in the right chapter
         sectcmt[i] = line[cmtcol];           // keep comments for later listing
         sectlen[i] = v;                      // keep lengths for later listing
         j = 'N';
         if  ( strcmp(line[disccol], "1") == 0 )
         {  j = 'T';
            transize[trcount] = v + v;        // size needed to set up procedure 0
            transect[trcount++] = i;          // counting transit areas for chapter 0
         }
         if  ( verbosity > -1 )               // always do this at present
            fprintf(fout, "Section: %2d in chap %2d at loc %4d %c %4d short words  %s\n",
                                 i, curchap, secsize[curchap], j, v+v, line[cmtcol]);
         secsize[curchap] += v + v;           // move up HWM
      }

   // Allocate procedures to chapters
   if  ( procchap[100] < 0 )                  // this may be an error
   {  fprintf(fout, "Allocating procedure 100 to chapter 1\n");
      procchap[100] = 1;
   }
   curchap = procchap[100];
   for  ( i = 101; i<1000; i++ )
      if  ( procchap[i] < 0 )
         procchap[i] = curchap;
      else
         curchap = procchap[i];

   i = 0;     // now to sort out space for base of procedure 0
   v = 2*numchaps + numroutes + 2*trcount + 5;                        // 2C+R+2T+5
   v += v&1;                                        // round up to even address
   if  ( verbosity > 0 )
      fprintf(fout, "   Intiial procedure 0 size = %d\n", v);
   while  ( chapaddr[++i] >= 0 )
      proc0size[i] = v;     // size of preset data before start of switch areas etc

   if  ( verbosity > 0 )
      doline(line);                         // first PROCR line
   src[srcp++] = line;                      // start with first procedure

   while  ( (line = readline(fin)) != NULL )
   {  if  ( verbosity > 0 )                 // only list source text on input if verbose
      {  if  ( strcmp(line[sercol]+3, "02") == 0 )
            doline(head);
         else if  ( strcmp(line[sercol]+3, "00") == 0 )
            fprintf(fout, "\n");

         if  ( strlen(line[sercol]) == 0 )  // ignore blank lines
         {  fprintf(fout, "------------\n");
            line[sercol] = "";
         }
         else
            doline(line);
      }

      if  ( strlen(line[sercol]) != 0 )             // if not blank line
      {  if  ( strcmp(line[actcol], "C") == 0       // if this is a continuation line ...
                &&  *(src[srcp-1][sercol]) == '0' ) // ... at the start of a page
         {  src[srcp] = src[srcp-1];                // put the marker line one later
            src[srcp-1] = line;                     // and put the real line at the foot of the previous page
            srcp ++;
         }
         else
            src[srcp++] = line;
      }
   }

   src[srcp++] = lastline;         // terminates address searches
   src[srcp] = NULL;

   check();

   fprintf(fout, "\n=============== First pass =================\n");
   check();

   loc = 8;                       // gets tagged onto the very first source line

   pass = 1;
   olcount = 0;
   generate();

   fprintf(fout, "\n=============== Memory allocation =================\n");

   if  ( verbosity != 0 )
   {  i = 0;
      fprintf(fout, "\n   Top of chapter  0 is at %d\n", secsize[0]);
      while  ( chapaddr[++i] >= 0 )
         fprintf(fout, "   Chapter %2d code starts at %d,  short constants at %d, long at %d,  code size %d,  total size %d\n",
                    i, proc0size[i] + PROC0VAR, kcbase21[i], kcbase41[i], chapsize[i], secsize[i]);
      i = 0;
      fprintf(fout, "\n   Address map\n");
      fprintf(fout, "     chapaddr  chapsize   proc0size   secsize   equivchap   ovrindex\n");
      while  ( chapaddr[++i] >= 0 )
         fprintf(fout, "%2d %9d %9d %9d %9d %9d %9d\n", i, chapaddr[i], chapsize[i], proc0size[i], secsize[i], equivchap[i], ovrindex[i]);
   }

// Now to sort out where to start code for each chapter

   fprintf(fout, "\n");
   chapaddr[0] = CHAP0START; // chapter zero generated by translator
   v = MEMSTART;             // start of next regular chapter
   i = 0;                    // chapter number
   while  ( chapaddr[++i] >= 0 )
   {//if  ( i >= 9 )
    //   chapsize[i] = 15200 - 8192; // - (i-9)*1000;      // ////////// !!!!!!!!!!!!! TEMP
      if  ( equivchap[i] != i )                        // if overlayed
         v = chapaddr[equivchap[i]];                   // start at same address as other one
      if  ( (((v + chapsize[i]) ^ v) & 8192) != 0 )    // chapter overflows division
         v = (v & 0xFFE000) + 8192;                    // move up to next division
      fprintf(fout, "Chapter %d equivalent to %d located at %d\n", i, equivchap[i], v);
      chapsize[i] += padding[i];                       // see action 168
      for  ( j = 0; j<100; j++ )
         if  ( procchap[j] == i )                      // section in this chapter
            fprintf(fout, "   Section %2d length %3d starts at %5d %s\n",
                        j, sectlen[j], (procstart[j] += chapsize[i]) + v, sectcmt[j]);
      chapaddr[i] = v;
      v += chapsize[i] + secsize[i];
   }

   if  ( verbosity != 0 )
      for  ( i = 0; i<100; i++ )
         if  ( procstart[i] >= 0 )
            fprintf(fout, "Section %d in chapter %d starts at %d %s\n",
                         i, procchap[i], procstart[i] + chapaddr[procchap[i]], sectcmt[i]);

   for  ( i = 0; ovrindex[i] >= 0; i++ )
      fprintf(fout, "PROCR %d in CHAP %d overlay = %d\n", ovrindex[i], procchap[ovrindex[i]], i);


   fprintf(fout, "\n=============== Second pass =================\n");
   check();

// loc = 160;      // location to put the next instruction - but 1st line is a PROCR
   pass = 2;
   olcount = 0;

   cbase21 = kcbase21[1];        // ready for chapter 1
   cbase41 = kcbase41[1];
   generate();

   // create A.S.L.s  i.e. 64 + R
   i = -1;
   while  ( filename[++i] != NULL )
   {  v = (i+1) * 9 + 64;
      curchap = procchap[transect[i]];
      fprintf(fout, "L%d   loading ASL for %s section %d in chapter %d\n",
                      v, filename[i], transect[i], curchap);
      xbuff[1] = procstart[transect[i]] + chapaddr[curchap]; // pointer for pseudo route
      xbuff[0] = fileannex[i] + chapaddr[0];
      valsOut(xbuff, 2, v);
   }

   chapter0();

   if  ( entrypoint != 0 )
      fprintf(fout, "E%d      entry point\n", addrcalc(entrypoint/100, entrypoint%100, "0"));

   i = -1;
   fprintf(fout, "\n   Address map\n");
   fprintf(fout, "       chapaddr  chapsize   proc0size   secsize   equivchap   ovrindex\n");
   while  ( chapaddr[++i] >= 0 )
      fprintf(fout, "  %2d %9d %9d %9d %9d %9d %9d\n", i, chapaddr[i], chapsize[i], proc0size[i], secsize[i], equivchap[i], ovrindex[i]);

// New address map designed to show overlaps
   i = -1;
   fprintf(fout, "\n   Alternative address map\n");
   fprintf(fout, "  chap code base  sec base  sec top\n");
   while  ( chapaddr[++i] >= 0 )
   {  int codebase = chapaddr[i];
      int sectbase = chapsize[i] + codebase;
      int sectop = secsize[i] + sectbase;
      fprintf(fout, "  %2d %9d %9d %9d\n", i, codebase, sectbase, sectop);
   }
   fprintf(fout, "         End of free store = %d\n", 16384 - 45);

   fprintf(fout, "
\n\n
\n\n\n"); if ( nobuffswap != 0 ) printf("This binary program must be emulated with -b switch\n"); fclose(fout); // exit(0); // remove the comment marks to remove the section map fout = fopen("secmap.txt", "w"); for ( j = 0; j<100; j++ ) if ( procstart[j] >= 0 ) { int chap = procchap[j]; int chbase = chapaddr[chap]; fprintf(fout, magic[chap], procstart[j] + chbase, j, "start ", sectcmt[j]); fprintf(fout, magic[chap], procstart[j] + chbase + sectlen[j]*2 - 1, j, "end", ""); } i = 0; while ( chapaddr[++i] >= 0 ) { int codebase = chapaddr[i]; int sectbase = chapsize[i] + codebase; fprintf(fout, "%05d ----------- top of chapter %2d\n", sectbase-1, i); } fclose(fout); }