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;
~
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:
BOOLEAN ←
FALSE]= {
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: INT ← IO.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:
BOOLEAN ←
TRUE] ~ {
[] ←
FS.FileInfo[fileName !
FS.Error => {
IF error.group = user
THEN {
found ← FALSE;
CONTINUE;
};
}];
};
in: IO.STREAM ← IO.RIS[cmd.commandLine];
fileName, longFileName: ROPE;
inputFile: IO.STREAM;
loadInfo: LoadInfo;
fileName ← GetCmdToken[in];
longFileName ← fileName;
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[];};
};