acd_format

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.