* EtherLoad.mc
* Edit by HGM September 4, 1980 12:14 PM Avoid H4PE, more switches fixes, interlock outputs, use Junk rather than (R)CSLoc
* Edit by Ev Neely Aug 15, 1980 10:57 AM Fix swithches/bootaddress bug
*Edit by Jim Frandeen July 15, 1980 12:15 PM RCSLoc conflicts with def in GlobalDefs. Change to RRCSLoc
* Edit by Jim Frandeen March 2, 1980 11:29 AM Delete Includes for Integration Procedure
* Edit by HGM on February 4, 1980 11:59 PM
TITLE[EtherBoot];
* Tasks
Set[OutTask, 2];
Set[InTask, 3];
Set[OutNotifyTask, LSHIFT[OutTask,14]];
Set[InNotifyTask, LSHIFT[InTask,14]];
* Locations
Set[EtherPage, 4];
Set[EmStartLoc, OR[LSHIFT[EtherPage,10], 102]];
Set[OutStartLoc, OR[LSHIFT[EtherPage,10], 130]];
Set[InStartLoc, OR[LSHIFT[EtherPage,10], 110]];
* I/O Address Registers for use by the IO Task
Set[ReadDeviceID, 0];
Set[ReadHostNumber, 1];
Set[ReadStatus, 2];
Set[ReadData, 3];
Set[WriteState, 0];
Set[WriteData, 1];
* for access from Emulator Task
MC[ReadInputDeviceID, OR[LSHIFT[InTask,4],ReadDeviceID]];
MC[ReadOutputDeviceID, OR[LSHIFT[OutTask,4],ReadDeviceID]];
MC[ReadInputHostNumber, OR[LSHIFT[InTask,4],ReadHostNumber]];
MC[WriteInputState, OR[LSHIFT[InTask,4],WriteState]];
MC[WriteOutputState, OR[LSHIFT[OutTask,4],WriteState]];
* Status masks
MC[CollisionMask, 10000];
MC[OutputStatusMask, 53000];
MC[InputStatusMask, 124400];
* New Ethernet device IDs (This won’t work with old boards - fix them)
MC[EtherInputDeviceID, 3400];
MC[EtherOutputDeviceID, 3000];
* State Register command words
MC[PurgeThisPacket, 260]; * Enable Input, PurgeMode
MC[SendThisPacket, 107]; * Enable Output, OutputEOP, JamEnable
MC[EnableOutput, 103]; * Enable Output, JamEnable
MC[DisableOutput, 100];
* Constants for things in a packet
MC[EtherPup, 1000]; * in second word of packet on an Ethernet
MC[OurVersionNumber, 1]; * Used in PupID and socket#
MC[MiscServSocket, 4]; * Misc Services socket
MC[D0MicrocodeRequest, 264]; * pupType
MC[D0MicrocodeAnswer, 265];
MC[PupOverhead, 26]; * pupLength of empty Pup
%
Encapsulation is:
0 dest,,source (dest is 0 for broadcast)
1 packet type (1000 for pup)
Pup body is:
2 length (bytes) (26B is min)
3 ctl,,pupType (ctl is normally 0)
4 first word of pupID
5 second word of pupID
6 dest net,,dest host (0 for broadcast)
7 first word of dest socket
8 second word of dest socket
9 source net,,source host
10 first word of source socket
11 second word of source socket
... body goes here
12 pup checksum (-1 to ignore)
%
% Macros for generating Notify values
Sample usage is:
R ← RHNV[task#,loc];
R ← (R) OR (LHNV[task#,loc]);
APC&APCTask ← R;
RETURN;
%
MACRO[RHNV,AND[0377,#2]C];
MACRO[LHNV,OR[LSHIFT[#1,14],AND[007400,#2]]C];
* Registers:
SETTASK[0];
RV[R0, 0];
RV[Temp, 2];
RV[Count, 3];
RV[DeviceAddress, 4];
RV[ShiftCount, 5];
SETTASK[OutTask];
RV[OutTemp, 41];
RV[OutMask, 42];
RV[BootFileNumber, 43];
SETTASK[InTask];
RV[InTemp, 61];
RV[BytesLeft, 62];
RV[Junk, 63];
RV[Source, 64];
RV[SourceTemp, 65];
RV[Packet, 66];
RV[Checksum, 67];
RV[Word, 70];
RV[Base, 72];
RV[BaseHi, 73];
* Task 3 registers referenced by other tasks
RV[TimerReg, 76];
RV[Host, 77];
ONPAGE[EtherPage];
SETTASK[0];
* Jump here in Task 0 with error code already in MP.
* MP will be bumped once if we can’t load things.
* BootFile number is in T
EtherLoad:BootFileNumber ← T, AT [EmStartLoc];
* I’m not sure if this is really needed
* set all device address to zero so stray wakeups won’t kill us
T ← DeviceAddress ← (ZERO)-1;
ShiftCount ← 400C, CALL[Shift];
MC[EtherAddresses, AND[NOT[OR[LSHIFT[OutTask,4],InTask]],377]];
* Load CAddr Register of the first 2 devices
T ← DeviceAddress ← EtherAddresses;
ShiftCount ← 10C, CALL[Shift];
* Find the EtherNet board
Count ← 20C;
NextBoard:T ← ReadInputDeviceID;
Input[Temp];
LU ← (Temp) XOR (EtherInputDeviceID);
GOTO[StartInput,ALU=0], T ← DeviceAddress ← (ZERO)-1;
ShiftCount ← 4C, CALL[Shift];
GOTO[NextBoard,R>=0], Count ← (Count) - 1;
NoEthernet:GOTO[EmTrouble];
StartInput:Count ← 15C; * This works out to 15 decimal
T ← ReadInputHostNumber;
Input[Host];
SendAgain:R0 ← AND[0377, InStartLoc]C;
R0 ← (R0) OR (OR[InNotifyTask,AND[007400, InStartLoc]]C);
APC&APCTask ← R0, CALL[Ret];
* Poke sending process to send the request again
R0 ← AND[0377, OutStartLoc]C;
R0 ← (R0) OR (OR[OutNotifyTask,AND[007400, OutStartLoc]]C);
APC&APCTask ← R0, CALL[Ret];
* This double loop should take about 10 seconds
* I used trial and error to get it right
TimerReg ← 1000C;
More:R0 ← 60000C;
* I can’t quite get rid of the extra instructions in this tangle
NOP;
CALL[Ret];
R0 ← (R0)-1, GOTO[.-2,R>=0];
TimerReg ← (TimerReg)-1, GOTO[More,R>=0];
Count ← (Count)-1, GOTO[SendAgain,R>=0];
* Timeout
EmTrouble:IncMPanel;
GOTO[.];
* Shift the device address registers another step
* Args in T, DeviceAddress, and Count
Shift:ShiftCount ← (ShiftCount) - 1, GENSRCLOCK;
GOTO [.-1,ALU#0], T ← DeviceAddress ← RCY[DeviceAddress, 1];
RETURN;
SETTASK[OutTask];
* The Ethernet encapsulation is 2 words and a short Pup is 11 words
* That fits into the buffer so there is no need to TASK
OutStart:OutMask ← 0C, AT [OutStartLoc];
OutAgain:OutTemp ← DisableOutput;
OUTPUT[OutTemp, WriteState];
OutTemp ← EnableOutput, CALL[OutState];
T ← RHMASK[Host];
OutTemp ← T, CALL[OutData];
OutTemp ← EtherPup, CALL[OutData];
OutTemp ← PupOverhead, CALL[OutData];
OutTemp ← D0MicrocodeRequest, CALL[OutData];
OutTemp ← OurVersionNumber, CALL[OutData]; * PupID
OUTPUT[BootFileNumber, WriteData]; * PupID2
OutTemp ← 0C, CALL[OutTwice]; * dest PupAddress
OutTemp ← MiscServSocket, CALL[OutData];
T ← RHMASK[Host];
OutTemp ← T, CALL[OutData]; * our PupAddress
OutTemp ← OurVersionNumber, CALL[OutTwice];
OutTemp ← (ZERO)-1, CALL[OutData]; * checksum
OutTemp ← SendThisPacket, CALL[OutState];
INPUT[OutTemp, ReadStatus];
LU ← (OutTemp) AND (CollisionMask);
GOTO[OutColl,ALU#0];
OutDone:OutTemp ← DisableOutput, GOTO[OutState];
* Rats, got a collision
OutColl:T ← OutMask ← (LSH[OutMask,1])+1, SKIP[R>=0];
GOTO[OutDone]; * Too many collisions, give up
NOP; * ARG
NOP;
OutTemp ← T, CALL[Ret];
T ← (OutTemp)-1, GOTO[.-2,R<0];
GOTO[OutAgain];
OutTwice:OUTPUT [OutTemp, WriteData];
OutData:OUTPUT [OutTemp, WriteData], GOTO[Ret];
OutState:OUTPUT [OutTemp, WriteState];
Ret:OutTemp ← OutTemp, RETURN; * Interlock
SETTASK[InTask];
InStart:Source ← 0C, AT [InStartLoc];
Packet ← 0C;
Checksum ← 0C;
Base ← MicrocodeAddress;
Base ← (Base) + 1;* eb files don’t have version word
BaseHi ← 0C;
* skip over first packet
InPurge:InTemp ← PurgeThisPacket, CALL[InState];
* wait here for next packet to arrive
InFilter:INPUT[InTemp,ReadStatus]; * Beware of H4PE
LU ← (InTemp) AND (100400C); * Jam or BadAlignment
Skip[ALU=0];
GOTO[InPurge]; * Looks bad - don’t touch this packet
NOP; * Alignment
T ← EtherPup, Call[InSkip1Check];
INPUT[BytesLeft, ReadData]; * PupLength
T ← D0MicrocodeAnswer, CALL[InCheck];
T ← OurVersionNumber, CALL[InCheck]; * PupID
T ← Packet, CALL[InCheck]; * PupID2
INPUT[InTemp, ReadData]; * our PupAddress
T ← RHMASK[InTemp];
LU ← (RHMASK[Host]) XOR (T);
SKIP[ALU=0];
GOTO[InPurge]; * Not for us
NOP; * Alignment
T ← OurVersionNumber, CALL[InCheck];
T ← OurVersionNumber, CALL[InCheck];
INPUT[SourceTemp,ReadData];
T ← MiscServSocket, CALL[InSkip1Check]; * his PupAddress
* We have not checked to see if the packet has ended already
* (Probably with bad status because of a collision)
* The hope is that some data will mismatch by now
* Check that this packet is comming from the right machine.
* We can skip this if all the boot servers really send the same version of the microcode.
HostCheck:T ← (Source);
T ← SourceTemp, SKIP[ALU#0];
Source ← T;
LU ← (Source) XOR (T);
SKIP[ALU=0];
GOTO[InPurge];
Packet ← (Packet)+1, GOTO[InGo];
* We only get a wakeup if there are at least 4 words in the buffer
* so it is safe to skip up to 3 words before checking one
InSkip1Check:
INPUT[Junk, ReadData];
* T has data word to be compared with next input data word
* There is no check for short packet
* since it will get tested at InLoop before we do anything stupid
InCheck:INPUT[InTemp, ReadData];
NOP; * Beware of bypass kludge
LU ← (InTemp) XOR (T);
GOTO[Ret,ALU=0];
GOTO[InPurge];
InState:OUTPUT [InTemp, WriteState], GOTO[Ret];
InGo:BytesLeft ← (BytesLeft)-(PupOverhead);
GOTO[EndMarker,ALU=0];
BytesLeft ← (BytesLeft)-1, CALL[Ret];
InLoop:BytesLeft ← (BytesLeft)-(2C), GOTO[InDone,R<0];
SKIP[NOAtten];
InShort:GOTO[InStart]; * Packet ended early
TakeOne:INPUT[Word,ReadData];
T ← Word;
Checksum ← (Checksum)+T;
PSTORE1[Base,Word,0];
Base ← (Base)+1, RETURN;
InDone:INPUT[Junk,ReadData]; * Pup Checksum
INPUT[Junk,ReadData]; * CRC
INPUT[InTemp,ReadStatus];
LU ← (InTemp) AND (InputStatusMask);
SKIP[ALU=0];
BadStatus:GOTO[InStart]; * Packet got smashed
* Reset timer to 2 sec whenever we get a good packet
TimerReg ← 140C, GOTO [InPurge];
EndMarker:LU ← Checksum;
InTemp ← and[MicrocodeLoadedLoc, 7400]c, SKIP[ALU=0];
GOTO[InStart]; * Checksum didn’t match
InTemp ← (InTemp) or (and[MicrocodeLoadedLoc, 377]c);
APC&APCTask ← InTemp;
return;
END;