|
@@ -1 +1,300 @@
|
|
|
+#include "TPL_PatternCollector.h"
|
|
|
+#include <cstring>
|
|
|
|
|
|
+/** \note Fundamental problem: there seems to be no information linking the names
|
|
|
+ in the system unit ("V" category) with their routines, except trial and
|
|
|
+ error. I have entered a few. There is no guarantee that the same pmap
|
|
|
+ offset will map to the same routine in all versions of turbo.tpl. They
|
|
|
+ seem to match so far in version 4 and 5.0 */
|
|
|
+
|
|
|
+
|
|
|
+#define roundUp(w) ((w + 0x0F) & 0xFFF0)
|
|
|
+extern void fixWildCards(uint8_t pat[]);
|
|
|
+void TPL_PatternCollector::enterSym(FILE *f, const char *name, uint16_t pmapOffset)
|
|
|
+{
|
|
|
+ uint16_t pm, cm, codeOffset, pcode;
|
|
|
+ uint16_t j;
|
|
|
+
|
|
|
+ /* Enter a symbol with given name */
|
|
|
+ allocSym(count);
|
|
|
+ strcpy(keys[count].name, name);
|
|
|
+ pm = pmap + pmapOffset; /* Pointer to the 4 byte pmap structure */
|
|
|
+ fseek(f, unitBase+pm, SEEK_SET);/* Go there */
|
|
|
+ cm = readShort(f); /* CSeg map offset */
|
|
|
+ codeOffset = readShort(f); /* How far into the code segment is our rtn */
|
|
|
+ j = cm / 8; /* Index into the cmap array */
|
|
|
+ pcode = csegBase+csegoffs[j]+codeOffset;
|
|
|
+ fseek(f, unitBase+pcode, SEEK_SET); /* Go there */
|
|
|
+ grab(f,PATLEN); /* Grab the pattern to buf[] */
|
|
|
+ fixWildCards(buf); /* Fix the wild cards */
|
|
|
+ memcpy(keys[count].pat, buf, PATLEN); /* Copy to the key array */
|
|
|
+ count++; /* Done one more */
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::allocSym(int count)
|
|
|
+{
|
|
|
+ keys.resize(count);
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::readCmapOffsets(FILE *f)
|
|
|
+{
|
|
|
+ uint16_t cumsize, csize;
|
|
|
+ uint16_t i;
|
|
|
+
|
|
|
+ /* Read the cmap table to find the start address of each segment */
|
|
|
+ fseek(f, unitBase+cmap, SEEK_SET);
|
|
|
+ cumsize = 0;
|
|
|
+ csegIdx = 0;
|
|
|
+ for (i=cmap; i < pmap; i+=8)
|
|
|
+ {
|
|
|
+ readShort(f); /* Always 0 */
|
|
|
+ csize = readShort(f);
|
|
|
+ if (csize == 0xFFFF) continue; /* Ignore the first one... unit init */
|
|
|
+ csegoffs[csegIdx++] = cumsize;
|
|
|
+ cumsize += csize;
|
|
|
+ grab(f,4);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::enterSystemUnit(FILE *f)
|
|
|
+{
|
|
|
+ /* The system unit is special. The association between keywords and
|
|
|
+ pmap entries is not stored in the .tpl file (as far as I can tell).
|
|
|
+ So we hope that they are constant pmap entries.
|
|
|
+ */
|
|
|
+
|
|
|
+ fseek(f, 0x0C, SEEK_SET);
|
|
|
+ cmap = readShort(f);
|
|
|
+ pmap = readShort(f);
|
|
|
+ fseek(f, offStCseg, SEEK_SET);
|
|
|
+ csegBase = roundUp(readShort(f)); /* Round up to next 16 bdry */
|
|
|
+ printf("CMAP table at %04X\n", cmap);
|
|
|
+ printf("PMAP table at %04X\n", pmap);
|
|
|
+ printf("Code seg base %04X\n", csegBase);
|
|
|
+
|
|
|
+ readCmapOffsets(f);
|
|
|
+
|
|
|
+ enterSym(f,"INITIALISE", 0x04);
|
|
|
+ enterSym(f,"UNKNOWN008", 0x08);
|
|
|
+ enterSym(f,"EXIT", 0x0C);
|
|
|
+ enterSym(f,"BlockMove", 0x10);
|
|
|
+ unknown(f,0x14, 0xC8);
|
|
|
+ enterSym(f,"PostIO", 0xC8);
|
|
|
+ enterSym(f,"UNKNOWN0CC", 0xCC);
|
|
|
+ enterSym(f,"STACKCHK", 0xD0);
|
|
|
+ enterSym(f,"UNKNOWN0D4", 0xD4);
|
|
|
+ enterSym(f,"WriteString", 0xD8);
|
|
|
+ enterSym(f,"WriteInt", 0xDC);
|
|
|
+ enterSym(f,"UNKNOWN0E0", 0xE0);
|
|
|
+ enterSym(f,"UNKNOWN0E4", 0xE4);
|
|
|
+ enterSym(f,"CRLF", 0xE8);
|
|
|
+ enterSym(f,"UNKNOWN0EC", 0xEC);
|
|
|
+ enterSym(f,"UNKNOWN0F0", 0xF0);
|
|
|
+ enterSym(f,"UNKNOWN0F4", 0xF4);
|
|
|
+ enterSym(f,"ReadEOL", 0xF8);
|
|
|
+ enterSym(f,"Read", 0xFC);
|
|
|
+ enterSym(f,"UNKNOWN100", 0x100);
|
|
|
+ enterSym(f,"UNKNOWN104", 0x104);
|
|
|
+ enterSym(f,"PostWrite", 0x108);
|
|
|
+ enterSym(f,"UNKNOWN10C", 0x10C);
|
|
|
+ enterSym(f,"Randomize", 0x110);
|
|
|
+ unknown(f,0x114, 0x174);
|
|
|
+ enterSym(f,"Random", 0x174);
|
|
|
+ unknown(f,0x178, 0x1B8);
|
|
|
+ enterSym(f,"FloatAdd", 0x1B8); /* A guess! */
|
|
|
+ enterSym(f,"FloatSub", 0x1BC); /* disicx - dxbxax -> dxbxax*/
|
|
|
+ enterSym(f,"FloatMult", 0x1C0); /* disicx * dxbxax -> dxbxax*/
|
|
|
+ enterSym(f,"FloatDivide", 0x1C4); /* disicx / dxbxax -> dxbxax*/
|
|
|
+ enterSym(f,"UNKNOWN1C8", 0x1C8);
|
|
|
+ enterSym(f,"DoubleToFloat",0x1CC); /* dxax to dxbxax */
|
|
|
+ enterSym(f,"UNKNOWN1D0", 0x1D0);
|
|
|
+ enterSym(f,"WriteFloat", 0x1DC);
|
|
|
+ unknown(f,0x1E0, 0x200);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::readString(FILE *f)
|
|
|
+{
|
|
|
+ uint8_t len;
|
|
|
+
|
|
|
+ len = readByte(f);
|
|
|
+ grab(f,len);
|
|
|
+ buf[len] = '\0';
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::unknown(FILE *f, unsigned j, unsigned k)
|
|
|
+{
|
|
|
+ /* Mark calls j to k (not inclusive) as unknown */
|
|
|
+ unsigned i;
|
|
|
+
|
|
|
+ for (i=j; i < k; i+= 4)
|
|
|
+ {
|
|
|
+ sprintf((char *)buf, "UNKNOWN%03X", i);
|
|
|
+ enterSym(f,(char *)buf, i);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::nextUnit(FILE *f)
|
|
|
+{
|
|
|
+ /* Find the start of the next unit */
|
|
|
+
|
|
|
+ uint16_t dsegBase, sizeSyms, sizeOther1, sizeOther2;
|
|
|
+
|
|
|
+ fseek(f, unitBase+offStCseg, SEEK_SET);
|
|
|
+ dsegBase = roundUp(readShort(f));
|
|
|
+ sizeSyms = roundUp(readShort(f));
|
|
|
+ sizeOther1 = roundUp(readShort(f));
|
|
|
+ sizeOther2 = roundUp(readShort(f));
|
|
|
+
|
|
|
+ unitBase += dsegBase + sizeSyms + sizeOther1 + sizeOther2;
|
|
|
+
|
|
|
+ fseek(f, unitBase, SEEK_SET);
|
|
|
+ if (fread(buf, 1, 4, f) == 4)
|
|
|
+ {
|
|
|
+ buf[4]='\0';
|
|
|
+ printf("Start of unit: found %s\n", buf);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::setVersionSpecifics()
|
|
|
+{
|
|
|
+
|
|
|
+ version = buf[3]; /* The x of TPUx */
|
|
|
+
|
|
|
+ switch (version)
|
|
|
+ {
|
|
|
+ case '0': /* Version 4.0 */
|
|
|
+ offStCseg = 0x14; /* Offset to the LL giving the Cseg start */
|
|
|
+ charProc = 'T'; /* Indicates a proc in the dictionary */
|
|
|
+ charFunc = 'U'; /* Indicates a function in the dictionary */
|
|
|
+ skipPmap = 6; /* Bytes to skip after Func to get pmap offset */
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ case '5': /* Version 5.0 */
|
|
|
+ offStCseg = 0x18; /* Offset to the LL giving the Cseg start */
|
|
|
+ charProc = 'T'; /* Indicates a proc in the dictionary */
|
|
|
+ charFunc = 'U'; /* Indicates a function in the dictionary */
|
|
|
+ skipPmap = 1; /* Bytes to skip after Func to get pmap offset */
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ printf("Unknown version %c!\n", version);
|
|
|
+ exit(1);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::savePos(FILE *f)
|
|
|
+{
|
|
|
+
|
|
|
+ if (positionStack.size() >= 20)
|
|
|
+ {
|
|
|
+ printf("Overflowed filePosn array\n");
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ positionStack.push_back(ftell(f));
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::restorePos(FILE *f)
|
|
|
+{
|
|
|
+ if (positionStack.empty() == 0)
|
|
|
+ {
|
|
|
+ printf("Underflowed filePosn array\n");
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ fseek(f, positionStack.back(), SEEK_SET);
|
|
|
+ positionStack.pop_back();
|
|
|
+}
|
|
|
+
|
|
|
+void TPL_PatternCollector::enterUnitProcs(FILE *f)
|
|
|
+{
|
|
|
+
|
|
|
+ uint16_t i, LL;
|
|
|
+ uint16_t hash, hsize, dhdr, pmapOff;
|
|
|
+ char cat;
|
|
|
+ char name[40];
|
|
|
+
|
|
|
+ fseek(f, unitBase+0x0C, SEEK_SET);
|
|
|
+ cmap = readShort(f);
|
|
|
+ pmap = readShort(f);
|
|
|
+ fseek(f, unitBase+offStCseg, SEEK_SET);
|
|
|
+ csegBase = roundUp(readShort(f)); /* Round up to next 16 bdry */
|
|
|
+ printf("CMAP table at %04X\n", cmap);
|
|
|
+ printf("PMAP table at %04X\n", pmap);
|
|
|
+ printf("Code seg base %04X\n", csegBase);
|
|
|
+
|
|
|
+ readCmapOffsets(f);
|
|
|
+
|
|
|
+ fseek(f, unitBase+pmap, SEEK_SET); /* Go to first pmap entry */
|
|
|
+ if (readShort(f) != 0xFFFF) /* FFFF means none */
|
|
|
+ {
|
|
|
+ sprintf(name, "UNIT_INIT_%d", ++unitNum);
|
|
|
+ enterSym(f,name, 0); /* This is the unit init code */
|
|
|
+ }
|
|
|
+
|
|
|
+ fseek(f, unitBase+0x0A, SEEK_SET);
|
|
|
+ hash = readShort(f);
|
|
|
+ //printf("Hash table at %04X\n", hash);
|
|
|
+ fseek(f, unitBase+hash, SEEK_SET);
|
|
|
+ hsize = readShort(f);
|
|
|
+ //printf("Hash table size %04X\n", hsize);
|
|
|
+ for (i=0; i <= hsize; i+= 2)
|
|
|
+ {
|
|
|
+ dhdr = readShort(f);
|
|
|
+ if (dhdr)
|
|
|
+ {
|
|
|
+ savePos(f);
|
|
|
+ fseek(f, unitBase+dhdr, SEEK_SET);
|
|
|
+ do
|
|
|
+ {
|
|
|
+ LL = readShort(f);
|
|
|
+ readString(f);
|
|
|
+ strcpy(name, (char *)buf);
|
|
|
+ cat = readByte(f);
|
|
|
+ if ((cat == charProc) || (cat == charFunc))
|
|
|
+ {
|
|
|
+ grab(f,skipPmap); /* Skip to the pmap */
|
|
|
+ pmapOff = readShort(f); /* pmap offset */
|
|
|
+ printf("pmap offset for %13s: %04X\n", name, pmapOff);
|
|
|
+ enterSym(f,name, pmapOff);
|
|
|
+ }
|
|
|
+ //printf("%13s %c ", name, cat);
|
|
|
+ if (LL)
|
|
|
+ {
|
|
|
+ //printf("LL seek to %04X\n", LL);
|
|
|
+ fseek(f, unitBase+LL, SEEK_SET);
|
|
|
+ }
|
|
|
+ } while (LL);
|
|
|
+ restorePos(f);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int TPL_PatternCollector::readSyms(FILE *f)
|
|
|
+{
|
|
|
+ grab(f,4);
|
|
|
+ if ((strncmp((char *)buf, "TPU0", 4) != 0) && ((strncmp((char *)buf, "TPU5", 4) != 0)))
|
|
|
+ {
|
|
|
+ printf("Not a Turbo Pascal version 4 or 5 library file\n");
|
|
|
+ fclose(f);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ setVersionSpecifics();
|
|
|
+
|
|
|
+ enterSystemUnit(f);
|
|
|
+ unitBase = 0;
|
|
|
+ do
|
|
|
+ {
|
|
|
+ nextUnit(f);
|
|
|
+ if (feof(f)) break;
|
|
|
+ enterUnitProcs(f);
|
|
|
+ } while (1);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|