SparcSoftcardLoader.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Created by J-C Cuenod, September 29, 1988 1:36:45 pm PDT
Christian Le Cocq October 25, 1988 5:23:32 pm PDT
Christophe Cuenod October 7, 1988 2:49:01 pm PDT
Loads a single a.out file into the SparcSoftcard
DIRECTORY
Basics USING [Card32FromF, HighHalf, LowHalf, UnsafeBlock],
Commander USING [CommandProc, Register],
DoveInputOutput USING [ Peek, Poke ],
FS USING [ Error, FileInfo, StreamOpen ],
IO USING [ CharClass, EndOfStream, GetFWord, GetTokenRope, PutF, RIS, rope, GetIndex, SetIndex, STREAM, UnsafeGetBlock, Reset],
RefTab USING [Ref, Create, Pairs, EachPairAction, Store, Delete],
Rope USING [Cat, ROPE],
SparcSoftcardLoaderOps,
SparcSoftcardMap,
SparcSoftcardOps,
SparcSoftcard;
SparcSoftcardLoader: CEDAR PROGRAM
IMPORTS Basics, Commander, DoveInputOutput, FS, IO, RefTab, Rope, SparcSoftcardMap, SparcSoftcardOps
EXPORTS SparcSoftcardLoaderOps
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
LoadInfoRep: TYPE ~ RECORD [
startAddress: CARD32,
memTrapStart: CARD32,
memCommStart: CARD32,
commLength: CARD32,
fileTextStart: CARD32,
memTextStart: CARD32,
textLength: CARD32,
fileDataStart: CARD32,
memDataStart: CARD32,
dataLength: CARD32,
memBssStart: CARD32,
bssLength: CARD32,
fileSymbolStart: CARD32,
memSymbolStart: CARD32,
symbolLength: CARD32
];
LoadInfo: TYPE ~ REF LoadInfoRep;
bufSize: NAT = 1000H;
Maximum size allowed by the compiler
aDotOutIdentificationByte: CARD16 ~ 0;
aDotOutTextSizeByte: CARD16 ~ 04H;
aDotOutDataSizeByte: CARD16 ~ 08H;
aDotOutBssSizeByte: CARD16 ~ 0CH;
aDotOutSymbolSizeByte: CARD16 ~ 10H;
aDotOutEntryPointByte: CARD16 ~ 14H;
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];
};
MyPokeLong: PROC [byteAddress: CARD32, word: CARD32] ~ {
IF (byteAddress MOD 4) # 0 THEN ERROR;
DoveInputOutput.Poke[(SparcSoftcard.cedarBackDoorBaseByte + byteAddress)/2, Basics.HighHalf[word]];
DoveInputOutput.Poke[(SparcSoftcard.cedarBackDoorBaseByte + byteAddress)/2 + 1, Basics.LowHalf[word]];
};
InsertResetPointer: PUBLIC PROC [resetVector: CARD32] ~ {
Insert by hand the instruction ba resetVector followed by nop
instruction: CARD32 ← 10800000H; -- ba 0
IF resetVector >= 800000H THEN ERROR; -- verify max offest
instruction ← instruction + resetVector/4; -- add offsett
MyPokeLong[0, instruction];
instruction ← 01000000H;  -- nop
MyPokeLong[4, instruction];
};
InsertInfo: PUBLIC PROC [loadInfo: LoadInfo] ~ {
MapPageZero[0];
InsertResetPointer[loadInfo.startAddress];
MyPokeLong[08h, loadInfo.startAddress];
MyPokeLong[0ch, loadInfo.memTrapStart];
MyPokeLong[10h, loadInfo.memCommStart];
MyPokeLong[14h, loadInfo.commLength];
MyPokeLong[18h, loadInfo.memTextStart];
MyPokeLong[1ch, loadInfo.textLength];
MyPokeLong[20h, loadInfo.memDataStart];
MyPokeLong[24h, loadInfo.dataLength];
MyPokeLong[28h, loadInfo.memBssStart];
MyPokeLong[2ch, loadInfo.bssLength];
MyPokeLong[30h, loadInfo.memSymbolStart];
MyPokeLong[34h, loadInfo.symbolLength];
};
SetCommunicationMap: PROC [start, length: CARD32] ~ {
The communication package uses a part of backdoor.
address: CARD32;
iteration: NAT;
IF (start MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
IF (length MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
Alignement error
address ← start;
iteration ← length / SparcSoftcard.softcardPageSizeByte;
FOR i: NAT IN [0..iteration) DO
MapOnePage[address, TRUE];
The communication area is non cachable
address ← address + SparcSoftcard.softcardPageSizeByte;
ENDLOOP;
};
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;
};
GetLoadInfo: PROC [stream: IO.STREAM] RETURNS [loadInfo: LoadInfo] = {
startAddress, bssLength, roundedBssLength: CARD32;
symbolLength, roundedSymbolLength: CARD32;
loadInfo ← NEW[LoadInfoRep];
IF GetLong[stream, aDotOutIdentificationByte] # aDotOutIdentificationValue THEN ERROR;
Bad magic number or tool version
startAddress ← GetLong[stream, aDotOutEntryPointByte];
IF (startAddress MOD SparcSoftcard.softcardPageSizeByte) # aDotOutHeaderSizeByte THEN ERROR;
Probably bad linking. The entry point has to be the first effective instruction.
loadInfo.startAddress ← GetLong[stream, aDotOutEntryPointByte];
loadInfo.memTrapStart ← SparcSoftcard.softcardPageSizeByte; -- TBR in page one
loadInfo.memCommStart ← loadInfo.memTrapStart + SparcSoftcard.softcardPageSizeByte;
loadInfo.fileTextStart ← 0;
loadInfo.memTextStart ← startAddress - aDotOutHeaderSizeByte;
loadInfo.commLength ← loadInfo.memTextStart - loadInfo.memCommStart;
loadInfo.textLength ← GetLong[stream, aDotOutTextSizeByte];
loadInfo.fileDataStart ← loadInfo.textLength;
loadInfo.memDataStart ← loadInfo.memTextStart + loadInfo.textLength;
loadInfo.dataLength ← GetLong[stream, aDotOutDataSizeByte];
loadInfo.memBssStart ← loadInfo.memDataStart + loadInfo.dataLength;
bssLength ← GetLong[stream, aDotOutBssSizeByte];
roundedBssLength ← ((bssLength + SparcSoftcard.softcardPageSizeByte - 1) / SparcSoftcard.softcardPageSizeByte) * SparcSoftcard.softcardPageSizeByte;
Extend size to the nearest page bondary.
loadInfo.bssLength ← roundedBssLength;
loadInfo.fileSymbolStart ← loadInfo.fileDataStart + loadInfo.dataLength;
loadInfo.memSymbolStart ← loadInfo.memBssStart + loadInfo.bssLength;
symbolLength ← GetLong[stream, aDotOutSymbolSizeByte];
roundedSymbolLength ← ((symbolLength + SparcSoftcard.softcardPageSizeByte - 1) / SparcSoftcard.softcardPageSizeByte) * SparcSoftcard.softcardPageSizeByte;
Extend size to the nearest page bondary.
loadInfo.symbolLength ← roundedSymbolLength;
};
LoadSegment: PROC [stream: IO.STREAM, fileStart, memStart, length: CARD32] = {
loadAddress, backdoorPointerWord16: CARD32;
buffer: ARRAY [0..bufSize/2) OF CARD16;
block: Basics.UnsafeBlock;
readSize: CARD16;
iteration: NAT;
IF (fileStart MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
IF (memStart MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
IF (length MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
Alignement error
iteration ← length / bufSize;
IO.SetIndex[stream, fileStart];
loadAddress ← memStart;
TRUSTED {
block ← [base: @buffer, count: bufSize];
};
FOR i: NAT IN [0..iteration) DO
IF (loadAddress MOD SparcSoftcard.softcardPageSizeByte) = 0 THEN {
MapPageZero[loadAddress];
backdoorPointerWord16 ← SparcSoftcard.cedarBackDoorBaseByte/2;
};
TRUSTED { readSize ← IO.UnsafeGetBlock[stream, block]; };
IF readSize # bufSize THEN ERROR;
File too small
FOR j: NAT IN [0..bufSize/2) DO
DoveInputOutput.Poke[backdoorPointerWord16, buffer[j]];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ENDLOOP;
TRUSTED {
ptr: LONG POINTER TO CARD16 ← @buffer[0];
limit: LONG POINTER TO CARD16 ← ptr + bufSize/2;
DO
IF ptr = limit THEN EXIT;
DoveInputOutput.Poke[backdoorPointerWord16, ptr^];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ptr ← ptr + SIZE[CARD16];
DoveInputOutput.Poke[backdoorPointerWord16, ptr^];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ptr ← ptr + SIZE[CARD16];
DoveInputOutput.Poke[backdoorPointerWord16, ptr^];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ptr ← ptr + SIZE[CARD16];
DoveInputOutput.Poke[backdoorPointerWord16, ptr^];
backdoorPointerWord16 ← backdoorPointerWord16 + 1;
ptr ← ptr + SIZE[CARD16];
ENDLOOP;
};
loadAddress ← loadAddress + bufSize;
ENDLOOP;
MapPageZero[0];
};
SetBssMap: PROC [memStart, length: CARD32] = {
iteration: NAT;
IF (memStart MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
IF (length MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
Alignement error
iteration ← length / SparcSoftcard.softcardPageSizeByte;
FOR i: NAT IN [0..iteration) DO
MapPageZero[memStart];
memStart ← memStart + SparcSoftcard.softcardPageSizeByte;
ENDLOOP;
MapPageZero[0];
};
MapPageZero: PROC [sparcVMAddress: CARD32]= {
backdoorEntry, superTextEntry, superDataEntry, dMAEntry: SparcSoftcardMap.MapEntry;
IF (sparcVMAddress MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
Alignement error
backdoorEntry.vMSpace.name ← cP;
superTextEntry.vMSpace.name ← sparcSuperProgram;
superDataEntry.vMSpace.name ← sparcSuperData;
dMAEntry.vMSpace.name ← dMA;
backdoorEntry.virtualAddressByte ← SparcSoftcard.cedarBackDoorBaseByte;
superTextEntry.virtualAddressByte ← sparcVMAddress;
superDataEntry.virtualAddressByte ← sparcVMAddress;
dMAEntry.virtualAddressByte ← sparcVMAddress;
backdoorEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
superTextEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
superDataEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
dMAEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
TRUSTED {
SparcSoftcardMap.WriteMapEntry[backdoorEntry];
SparcSoftcardMap.WriteMapEntry[superTextEntry];
SparcSoftcardMap.WriteMapEntry[superDataEntry];
SparcSoftcardMap.WriteMapEntry[dMAEntry];
};
};
MapOnePage: PROC [sparcVMAddress: CARD32, nonCachable: BOOLEANFALSE]= {
backdoorEntry, superTextEntry, superDataEntry, dMAEntry: SparcSoftcardMap.MapEntry;
IF (sparcVMAddress MOD SparcSoftcard.softcardPageSizeByte) # 0 THEN ERROR;
Alignement error
superTextEntry.flags.nonCachable ← nonCachable;
superDataEntry.flags.nonCachable ← nonCachable;
backdoorEntry.vMSpace.name ← cP;
superTextEntry.vMSpace.name ← sparcSuperProgram;
superDataEntry.vMSpace.name ← sparcSuperData;
dMAEntry.vMSpace.name ← dMA;
backdoorEntry.virtualAddressByte ← SparcSoftcard.cedarBackDoorBaseByte + sparcVMAddress;
superTextEntry.virtualAddressByte ← sparcVMAddress;
superDataEntry.virtualAddressByte ← sparcVMAddress;
dMAEntry.virtualAddressByte ← sparcVMAddress;
backdoorEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
superTextEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
superDataEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
dMAEntry.realAddressByte ← sparcVMAddress + SparcSoftcard.cedarMemoryExtensionSizeByte;
TRUSTED {
SparcSoftcardMap.WriteMapEntry[backdoorEntry];
SparcSoftcardMap.WriteMapEntry[superTextEntry];
SparcSoftcardMap.WriteMapEntry[superDataEntry];
SparcSoftcardMap.WriteMapEntry[dMAEntry];
};
};
GetLong: PROC [in: IO.STREAM, byteAddress: CARD16] RETURNS [result: CARD32] = {
IF (byteAddress MOD 4) # 0 THEN ERROR;
IO.SetIndex[in, byteAddress];
result ← Basics.Card32FromF[IO.GetFWord[in]];
};
startTable: RefTab.Ref ← RefTab.Create[];
StartAll: PROC [inputFile: IO.STREAM] ~ {
StartOne: RefTab.EachPairAction ~ {
sProc: PROC[inputFile: IO.STREAM] ← NARROW[val, REF PROC [inputFile: IO.STREAM]]^;
IO.Reset[inputFile];
sProc[inputFile];
};
index: INTIO.GetIndex[inputFile]; -- save the stream status
[] ← RefTab.Pairs[startTable, StartOne];
IO.SetIndex[inputFile, index]; -- restore the stream
};
RegisterStartProc: PUBLIC PROC [ref: REF, sProc: PROC [inputFile: IO.STREAM]] ~ {
IF sProc=NIL THEN [] ← RefTab.Delete[startTable, ref]
ELSE [] ← RefTab.Store[startTable, ref, NEW[PROC[inputFile: IO.STREAM] ← sProc]];
};
SparcSoftcardLoaderProc: Commander.CommandProc ~ {
FileExistence: PROC [fileName: ROPE] RETURNS [found: BOOLEANTRUE] ~ {
[] ← FS.FileInfo[fileName ! FS.Error => {
IF error.group = user THEN {
found ← FALSE;
CONTINUE;
};
}];
};
in: IO.STREAMIO.RIS[cmd.commandLine];
fileName, longFileName: ROPE;
inputFile: IO.STREAM;
loadInfo: LoadInfo;
fileNameGetCmdToken[in];
longFileNamefileName;
IF NOT FileExistence[fileName] THEN {
longFileName ← Rope.Cat[fileName, ".out"];
};
IF NOT FileExistence[longFileName] THEN {
IO.PutF[cmd.out, "Cannot find file %g\n", IO.rope[fileName]];
}
ELSE {
inputFile ← FS.StreamOpen[fileName: longFileName, accessOptions: $read];
Reset the Sparc, the cache and the DMA.
TRUSTED {
SparcSoftcardOps.SparcReset[];
SparcSoftcardOps.SparcCacheDisable[];
SparcSoftcardOps.SetDMAMode[display];
SparcSoftcardOps.SetDMAState[active];
SparcSoftcardOps.SetDMAState[inactive];
};
Get Load info about the field length
loadInfo ← GetLoadInfo[inputFile];
Set the communication map and restart communication package
SetCommunicationMap[loadInfo.memCommStart, loadInfo.commLength];
StartAll[inputFile];
Load different segments;
LoadSegment[inputFile, loadInfo.fileTextStart, loadInfo.memTextStart, loadInfo.textLength];
LoadSegment[inputFile, loadInfo.fileDataStart, loadInfo.memDataStart, loadInfo.dataLength];
SetBssMap[loadInfo.memBssStart, loadInfo.bssLength];
LoadSegment[inputFile, loadInfo.fileSymbolStart, loadInfo.memSymbolStart, loadInfo.symbolLength];
Sets the map for the trap page (page 1)
MapOnePage[SparcSoftcard.softcardPageSizeByte];
Insert the reset pointer and layout info
InsertInfo[loadInfo];
Start the sparc
TRUSTED {SparcSoftcardOps.SparcResetAndStart[];};
};
};
Registration
Commander.Register[
key: "SparcSoftcardLoader", proc: SparcSoftcardLoaderProc, doc: "Loads a a.out file into the SparcSoftcard memory"];
END.