// £123 | \ # various characters to persuade gedit to accept the file // This is a version of intercode.c, but under development // for dealing with overlays // 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 ech of the other chapters a procedure 0. // Routes have channel no = route no, i.e. filenum * 9. // Each route has a pseudo route one bigger. #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) { ******************************************** 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]); } 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); }