SparcSoftcardLoader.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
First created by Christophe Cuenod, September 9, 1988 11:01:04 am PDT
Loads a single a.out file into the SparcSoftcard
DIRECTORY
Basics USING [BITAND, BITNOT, HighHalf, LowHalf, UnsafeBlock],
Basics USING [HighHalf, LowHalf, UnsafeBlock],
Commander USING [CommandProc, Register],
DoveInputOutput USING [ Peek, Poke ],
FS USING [ StreamOpen ],
IO USING [ CharClass, EndOfStream, GetTokenRope, RIS, STREAM, UnsafeGetBlock],
Rope USING [ROPE],
SparcSoftcardOps,
SparcSoftcard;
SparcSoftcardLoader: CEDAR PROGRAM
IMPORTS Basics, Commander, DoveInputOutput, FS, IO, SparcSoftcardOps
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
aDotOutIdentificationByte: CARD16 ~ 0;
aDotOutEntryPointByte: CARD16 ~ 14H;
aDotOutBssSizeByte: CARD16 ~ 0CH;
aDotOutHeaderSizeByte: CARD16 ~ 20H;
aDotOutIdentificationValue: CARD32 ~ 0103010BH;
MyPeek: PROC [address: CARD32] RETURNS [word: UNSPECIFIED] ~ {
word ← DoveInputOutput.Peek[address];
};
MyPoke: PROC [address: CARD32, word: UNSPECIFIED] ~ {
DoveInputOutput.Poke[address, word];
};
InsertResetPointer: PUBLIC PROC [resetVector: CARD32] ~ {
Insert by hand the instruction ba resetVector followed by nop
instruction: CARD32 ← 10800000H; -- ba 0
IF resetVector >= 1000000H THEN ERROR; -- verify max offest
instruction ← instruction + resetVector/4; -- add offsett
DoveInputOutput.Poke[SparcSoftcard.cedarBackDoorBaseByte/2, Basics.HighHalf[instruction]];
DoveInputOutput.Poke[SparcSoftcard.cedarBackDoorBaseByte/2 + 1, Basics.LowHalf[instruction]];
instruction ← 01000000H;  -- nop
DoveInputOutput.Poke[SparcSoftcard.cedarBackDoorBaseByte/2 + 2, Basics.HighHalf[instruction]];
DoveInputOutput.Poke[SparcSoftcard.cedarBackDoorBaseByte/2 + 3, Basics.LowHalf[instruction]];
};
IndicateVMSize: PUBLIC PROC [sparcVMSize: CARD32] ~ {
Insert by hand the size of the VM at address 8 (byte address)
DoveInputOutput.Poke[SparcSoftcard.cedarBackDoorBaseByte/2 + 4, Basics.HighHalf[sparcVMSize]];
DoveInputOutput.Poke[SparcSoftcard.cedarBackDoorBaseByte/2 + 5, Basics.LowHalf[sparcVMSize]];
};
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
SparcSoftcardLoaderProc: Commander.CommandProc ~ {
GetLong: PROC [byteAddress: CARD16] RETURNS [result: CARD32] = {
IF (byteAddress MOD 4) # 0 THEN ERROR;
result ← buffer[byteAddress/2] * 65536 + buffer[byteAddress/2 + 1];
};
SetOneMoreMapPage: PROC ~ {
backdoorEntry.virtualAddressByte ← SparcSoftcard.cedarBackDoorBaseByte;
Always on the same backdoor page
superTextEntry.virtualAddressByte ← loadAddress;
superDataEntry.virtualAddressByte ← loadAddress;
backdoorEntry.realAddressByte ← loadAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
superTextEntry.realAddressByte ← loadAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
superDataEntry.realAddressByte ← loadAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
SparcSoftcardOps.WriteMapEntry[backdoorEntry];
SparcSoftcardOps.WriteMapEntry[superTextEntry];
SparcSoftcardOps.WriteMapEntry[superDataEntry];
};
in: IO.STREAMIO.RIS[cmd.commandLine];
fileName: ROPE ← GetCmdToken[in];
inputFile: IO.STREAMFS.StreamOpen[fileName: fileName, accessOptions: $read];
startAddress, loadAddress, bssSize: CARD32;
backdoorEntry, superTextEntry, superDataEntry: SparcSoftcardOps.MapEntry;
backdoorPointerWord16: CARD32;
bufSize: NAT = 1000H;
Maximum size allowed by the compiler
buffer: ARRAY [0..bufSize/2) OF CARD16;
block: Basics.UnsafeBlock;
readSize: CARD16;
Reads first the beginning of the file to check the header and find out the loading address
TRUSTED {
block ← [base: @buffer, count: bufSize];
readSize ← IO.UnsafeGetBlock[inputFile, block];
};
IF readSize # bufSize THEN ERROR;
File way too small
IF GetLong[aDotOutIdentificationByte] # aDotOutIdentificationValue THEN ERROR;
Bad magic number or tool version
startAddress ← GetLong[aDotOutEntryPointByte];
IF (startAddress MOD SparcSoftcard.softcardPageSizeByte) # aDotOutHeaderSizeByte THEN ERROR;
Probably bad linking. The entry point has to be the first effective instruction.
loadAddress ← startAddress - aDotOutHeaderSizeByte;
bssSize ← GetLong[aDotOutBssSizeByte];
Reset the Sparc and the cache
SparcSoftcardOps.SparcReset[];
SparcSoftcardOps.SparcCacheDisable[];
Set the first map pages
backdoorEntry.vMSpace.name ← cP;
superTextEntry.vMSpace.name ← sparcSuperProgram;
superDataEntry.vMSpace.name ← sparcSuperData;
backdoorEntry.virtualAddressByte ← SparcSoftcard.cedarBackDoorBaseByte;
backdoorEntry.realAddressByte ← SparcSoftcard.cedarMemoryExtensionSizeByte;
SparcSoftcardOps.WriteMapEntry[backdoorEntry];
The first page of backdoor points to the begining of free memory
superTextEntry.virtualAddressByte ← 0;
superTextEntry.realAddressByte ← SparcSoftcard.cedarMemoryExtensionSizeByte;
SparcSoftcardOps.WriteMapEntry[superTextEntry];
The first page of sparcSuperProgram points to the begining of free memory
superDataEntry.virtualAddressByte ← 0;
superDataEntry.realAddressByte ← SparcSoftcard.cedarMemoryExtensionSizeByte;
SparcSoftcardOps.WriteMapEntry[superDataEntry];
The first page of sparcSuperData points to the begining of free memory
Insert the reset pointer
InsertResetPointer[startAddress];
Transfert the data and set additional map pages if needed
WHILE readSize = bufSize DO
IF (loadAddress MOD SparcSoftcard.softcardPageSizeByte) = 0 THEN {
Set one more map page.
SetOneMoreMapPage[];
backdoorPointerWord16 ← SparcSoftcard.cedarBackDoorBaseByte/2;
};
FOR i: NAT IN [0..bufSize/2) DO
DoveInputOutput.Poke[backdoorPointerWord16, buffer[i]];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ENDLOOP;
TRUSTED {
readSize ← IO.UnsafeGetBlock[inputFile, block];
};
loadAddressloadAddress + bufSize;
ENDLOOP;
IF readSize # 0 THEN ERROR;
the file has an odd length (ie non multiple of softcardPageSizeByte)
Zero bss
WHILE bssSize > 0 DO
IF (loadAddress MOD SparcSoftcard.softcardPageSizeByte) = 0 THEN {
Set one more map page.
SetOneMoreMapPage[];
backdoorPointerWord16 ← SparcSoftcard.cedarBackDoorBaseByte/2;
};
FOR i: NAT IN [0..bufSize/2) DO
DoveInputOutput.Poke[backdoorPointerWord16, 0];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ENDLOOP;
loadAddressloadAddress + bufSize;
bssSizebssSize - bufSize;
ENDLOOP;
IF bssSize # 0 THEN ERROR;
the bss has an odd length (ie non multiple of softcardPageSizeByte)
For debug replace the first page of backdoor to the begining of free memory
backdoorEntry.virtualAddressByte ← SparcSoftcard.cedarBackDoorBaseByte;
backdoorEntry.realAddressByte ← SparcSoftcard.cedarMemoryExtensionSizeByte;
SparcSoftcardOps.WriteMapEntry[backdoorEntry];
Start the sparc
SparcSoftcardOps.SparcResetAndStart[];
};
Registration
Commander.Register[
key: "SparcSoftcardLoader", proc: SparcSoftcardLoaderProc, doc: "Loads a a.out file into the SparcSoftcard memory"];
END.