PutHeader:
PROC [file: File] ~ {
Write header. The file pointer is moved to the end of the header. The first call to WriteHeader is a dummy in order to ascertain the header size and fill the file up to the start point of the first vector block. The real header is written only at closing time (this simplifies a lot of things). File position on entry is ignored, and is set to start pont of 1st vector block on exit (always a multiple of 1K for efficiency on PC).
Header format is known by PC software and should not be changed.
PutByte:
PROC [b:
BYTE] ~ {
Write a byte into file and then update file checksum (not buffered).
IO.PutByte[file.stream, b];
file.ckSum ← Basics.BITAND[file.ckSum+b, 000FFH];
};
PutCard16:
PROC [c:
CARD16] ~ {
Write a 16-bit integer in little-endian order (LSB first)
PutByte[Basics.LowByte[c]];
PutByte[Basics.HighByte[c]];
};
PutInt32:
PROC [i:
INT32] ~ {
Write a 32-bit integer in little-endian order (LSB first)
n: Basics.LongNumber;
n.li ← i;
PutByte[n.ll];
PutByte[n.lh];
PutByte[n.hl];
PutByte[n.hh];
};
PutCard: PROC [c: CARD32] ~ {
Write a 32-bit integer in little-endian order (LSB first)
n: Basics.LongNumber;
n.lc ← c;
PutByte[n.ll];
PutByte[n.lh];
PutByte[n.hl];
PutByte[n.hh];
};
PutCRope:
PROC [r: Rope.
ROPE] ~ {
Write the rope C-style (NULL terminated).
EachChar: Rope.ActionType ~ { PutByte[ORD[c]] };
[] ← Rope.Map[base: r, action: EachChar];
PutByte[00H];
};
PutRope:
PROC [r: Rope.
ROPE, length:
INT] ~ {
Write the rope extended to length characters with NULLs (or truncated if too long)
EachChar: Rope.ActionType ~ { PutByte[ORD[c]] };
[] ← Rope.Map[base: r, action: EachChar, start: 0, len: MIN[length, Rope.Length[r]]];
THROUGH [Rope.Length[r] .. length) DO PutByte[00H] ENDLOOP;
};
PutWireDescription: SymTab.EachPairAction ~ {
wd: WireDescription = NARROW [val];
PutByte[ORD[wd.flavor]]; -- will be 0FFH for termination flag
PutCRope[wd.name];
FOR pins:
LIST
OF PinDescription ← wd.pins, pins.rest
UNTIL pins=
NIL
DO
pin: PinDescription = pins.first;
PutByte[pin.group]; -- will be 0xFF for terminator
PutByte[pin.byte];
PutByte[pin.mask];
PutByte[pin.bit];
PutCRope[pin.pkgName];
PutCRope[pin.conName];
ENDLOOP;
PutByte[0FFH]; -- end of pin descriptions list
};
ckSumOffset: INT; -- this is where the checksum will go once completed...
ckSumByte: BYTE;
IO.SetIndex[file.stream, 0]; -- backup to start of file
PutRope[headerSignature, 8];
PutInt32[file.hdrSize]; -- garbage on 1st pass...
PutCard16[file.nGroups];
PutCard16[vectorBlockLength];
PutInt32[file.nVects];
PutInt32[LOOPHOLE[file.timeStamp]];
ckSumOffset ← IO.GetIndex[file.stream]; -- note down where checksum should go finally
PutByte[00H]; -- this is the checksum position, patched at end
PutRope[file.id, 120]; -- comment for display on the PC
PutCRope[file.package.name]; -- start of package/fixture description
PutCRope[file.package.fixtureName];
[] ← SymTab.Pairs[file.package.signals, PutWireDescription];
PutByte[0FFH]; -- end of wire descriptions list
THROUGH [(IO.GetIndex[file.stream] MOD 1024) .. 1024) DO PutByte[00H] ENDLOOP; -- add adequate padding
file.hdrSize ← IO.GetIndex[file.stream];
IF ( file.hdrSize MOD 1024 ) # 0 THEN ERROR; -- internal bug
ckSumByte ← Basics.BITAND[0100H-file.ckSum, 000FFH]; -- recompute checksum for total 0
IO.SetIndex[file.stream, ckSumOffset]; -- get back to where the checksum should be
IO.PutByte[file.stream, ckSumByte]; -- and write it
IO.SetIndex[file.stream, file.hdrSize]; -- get back to end of header
};
WriteBByte:
PROC [file: File, b:
BYTE] ~ {
Write byte into file buffer and update file checksum (physically written only on flush).
block: REF TEXT ← file.block;
IF block.length>=block.maxLength THEN ERROR; -- buffer overflowed
block[block.length] ← VAL[b];
block.length ← block.length+1;
file.ckSum ← Basics.BITAND[file.ckSum+b, 000FFH];
};
FlushBlock:
PROC [file: File, nBytes:
NAT] ~ {
Flush current block padded to nBytes with zeroes.
block: REF TEXT ← file.block;
IF block.length>nBytes THEN ERROR; -- internal bug
UNTIL block.length=nBytes DO WriteBByte[file, 00H] ENDLOOP;
IO.PutBlock[file.stream, block, 0, nBytes];
block.length ← 0;
};