Documentation of the ACD UCSD III file format --------------------------------------------- author: holger.veit@iais.fraunhofer.de released under Creative Commons CC-BY-SA Advanced Computer Design uses a special format for UCSD CODE files and libraries for their PDQ-3 system. It is a mix of traditional III.0 and UCSD IV files. Overall structure: - The format is record structured, record size is 512 bytes Records are numbered 0...N in the file. - A CODE file is composed of up to three subfiles which may occur multiple times in a file: - directory subfile - interface subfile - code subfile (units) There are executables, like SYSTEM.FILER and Libraries, like SYSTEM.DRIVERS. Both of them are linked at runtime into the in-memory system image. The operating system keeps track of units in system. An executable typically consists of one or more directory subfiles and one or more code subfiles. A library, in addition, contains interface subfiles in addition to directory and code subfiles. In principle, all CODE files are treated the same: the runtime linker of the OS will load units into free memory until all external references are resolved. This already holds for the operating system itself; the secondary boot loader, loaded after the boot sector code, is the runtime linker itself. All subfiles are padded with NUL bytes if they are not exactly a multiple of 512 bytes in size. In case of interface subfiles, each record may contain any number of NUL bytes in between that are ignored. Code subfiles are word aligned, i.e. if a procedure ends at an even boundary, a NUL byte is inserted to have the following procedure start at the next even address. However, the code itself is byte oriented; the IPC addresses bytes rather than words. Directory subfile: ------------------ - The first record 0 in a CODE file is the directory subfile. - Each directory subfile is one record and may contain up to 23 entries. - Directory subfiles are a linkerd list. If more than 23 entries are needed, a following directory subfile is in the CODE file. Structure: Byte 0-1: always 0xffff Byte 2-3: record# of the next directory subfile Bytes 0x1a2-0x1ff: in record 0 may contain an ASCII copyright message Byte 4-0x1a1: variant record of 16 bytes size (18 including the tag) record case: integer of { unit declaration } 1: record ( name: string8; msipc: integer; linkflags: (segnum: byte; ?:byte); globalptr: integer; { point to global table of linked segment } ?: integer); { unit parameters } 2: record ( globalsz: integer; numpubext: integer; { number of public and externals } interfoff: integer; { blockoffset to interface in file } interfblks: integer; { number of blocks of interface } ?: record (bit0, {clear for PASCALSY } bit1, bit2, bit3, bit4...bit7: boolean; padding: byte end; ?: integer; ?: integer); { public segment definition } 3: record ( name: string8; segno: integer; { segment number in file } recoff: integer; { blockoffset of code in file } length: integer; { length of codefile in bytes } ?: integer); { external segment definition } 4: record ( name: string8; segno: integer; { external segment } ?: integer; ?: integer; ?: integer); end; In Memory structure loaded by LoadRecFile record relocblock: array[0...255] of integer; start: integer; { block nummer in file } nextlink: pointer; { to next inmemoryreloc record; global4 points to root} end; Unit structure: record codebase: integer; {0 address of loaded code (segbase) } publength: integer; {1 length of segment (segleng) } isloaded: boolean; {2 flag: loaded segment (segrefs) } diskoff: integer; {3 offset of seg block on disk (segaddr) } ?: record (bit0, {4 1st pubdef or seg=2 (segunit) } bit1, {from reloc2.word5.bit0 } bit2, {from reloc2.word5.bit1 } bit3, {false} bit4,bit5,bit6,bit7, bit8, bit9, { driver flag, will initialize? } bit10, bit11-15: boolean; ?:byte); ?: integer; {5 (prevsp) } name: string8; {6} chainlink: pointer; {10 point to next segment in chain } globallink: pointer; {11 link to system head} ?: byte; {12l} ?: byte; {12h segno} ?: integer; {13} NIL self: pointer; {14 pointer to itself} end; Interface subfile: ------------------ This is basically a text file, containing PASCAL source code. It is ASCII, with the following special characters: - NUL is ignored - CR is the line delimiter - DLE nn is used for indentation of lines NN-0x20 is the number of blanks (0x20) to be inserted at the beginning of a line. Typical sequence: CR DLE 0x24 "Procedure FooBar(Var xyzzy: Integer);" CR DLE .... (quotes not written) Code subfile: ------------- Byte 0-1: length of file in words, i.e. this number*2 points to the start of the procedure table+1 (where segment number is) Byte 2-3: byte address of start of relocation chain (see below), if 0, no relocation required Byte 4-11: name of Unit in ASCII, padded with blanks, 8 chars Byte 12-17: usually zero (padding) Byte 18-NNN: code starts here. Note that there may be constants and other structures used by a routine prepended, so first byte might not be a procedure entry (structure of procedure below) At the end: 2 bytes for each procedure entry, in reversed order 1 byte: segment number, 0x80...XX 1 Byte: number of procedures in procedure entry table Typical structure of procedure table (word aligned) 0xAAAA start address of fourth procedure 0xBBBB start address of third procedure 0xCCCC start address of second procedure 0xDDDD start address of first procedure (Byte0-1)*2 point here: 0x80 segment number 0x04 number of procedures Relocation chain: ----------------- - starts at byte address in (Byte2-3) record extunit: byte; { unit number where external procedure is } procno: byte; { procedure# to call in that unit } link: word {byte address to next relocation entry in this file, 0 if end } end; The unit number is typically 0x80...XXX where the unit number refers to a tag4 declaration in the directory entry corresponding to this code subfile. I.e. if the record looks like: 0x81 0x03 0x0183 and there is a corresponding tag4 entry for this code file like "FOOBAR" 0x0081 0x0000 0x0000 0x0000 then the runtime linker will locate (and if necessary, load) unit FOOBAR, and replace extunit/procno with the absolute extunit number of procedure 3. FOOBAR might occur in the segment dictionary as 0xB4; the linker will replace 0x81 with 0xB4. The pcode does extra segment calls with the following code fragment: LDC address_of_structure,2 CPF Note: operating system procedures use segment numbers of 0x01..0x7f in the segment table. Structure of procedure: ----------------------- .CPTR exitic { byte address of last RPU instruction } proc: start_of_instructions .... exitic: RPU nn { if necessary padding with 0 so that following proc starts at even byte } "proc" is the byte address in the procedure table.