:TITLE[E3Load]; *Formerly called EtherLoad %Ed Fiala 5 January 1984: Reformat file to current conventions; allow ethernet input code to be called twice for Pilot booting (once for the germ, once for microcode). Renamed Base/BaseHi base register to be IniBaseLo/Hi (now setup by Initial); use a new register WordOffset so that IniBaseLo/Hi doesn't change, permitting restart; use a new register IReturn to hold the return PC. Change the socket number from the constant value OurVersionNumber to the BootFileNumber to avoid mistaking mistaking a retransmission of the microcode for the germ. Temporarily remove the checksum check at the end of transmission because the 10.0 germ does not have a checksum; this krock is fixed in Klamath. Moved register definitions and some other stuff to InitialDefs.mc. Removed the initialization assigning all devices to task 0 (now done by Initial). Call the SrShift procedure in Initial rather than duplicating it here. Add code to turn off ethernet controller interrupts before exit. HGM September 4, 1980 12:14 PM Avoid H4PE, more switches fixes, interlock outputs, use Junk rather than (R)CSLoc Ev Neely Aug 15, 1980 10:57 AM Fix swithches/bootaddress bug Jim Frandeen July 15, 1980 12:15 PM RCSLoc conflicts with def in GlobalDefs. Change to RRCSLoc Jim Frandeen March 2, 1980 11:29 AM Delete Includes for Integration Procedure HGM on February 4, 1980 11:59 PM % *I/O Address Registers for use by the IO Task Set[E3ReadDeviceID,0]; Set[E3ReadHostNumber,1]; Set[E3ReadStatus,2]; Set[E3ReadData,3]; Set[E3WriteState,0]; Set[E3WriteData,1]; *for access from Emulator Task MC[ReadInputDeviceID,OR[LShift[E3InTask,4],E3ReadDeviceID]]; MC[ReadOutputDeviceID,OR[LShift[E3OutTask,4],E3ReadDeviceID]]; MC[ReadInputHostNumber,OR[LShift[E3InTask,4],E3ReadHostNumber]]; MC[WriteInputState,OR[LShift[E3InTask,4],E3WriteState]]; MC[WriteOutputState,OR[LShift[E3OutTask,4],E3WriteState]]; *Status masks MC[CollisionMask,10000]; MC[OutputStatusMask,53000]; MC[InputStatusMask,124400]; *Ethernet device IDs 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]; MC[DisableInput,200]; *Disable input *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) % SetTask[0]; %Call here in Task 0 with error code already in MP. All devices are quiescent and assigned to task 0. The MP will be bumped once after about 2.5 minutes, if loading fails. The BFI (Boot File Index) is in T at call. IniBaseLo/Hi point at the block of storage where the boot file should be put. % OnPage[E3Page]; E3Load: BootFileNumber _ T, UseCTask; T _ APCTask&APC; IReturn _ T, Task; *Load CAddr Register of the first 2 devices T _ RTemp1 _ Xor[LShift[E3OutTask,4],E3InTask,377]C; LoadPage[InitialPage]; RTemp _ 10C, CallP[SrShift]; *Find the 3 mb EtherNet board Count _ 20C; E3NextBoard: T _ ReadInputDeviceID; Input[RTemp]; LU _ (RTemp) xor (EtherInputDeviceID); T _ RTemp1 _ (Zero) - 1, GoTo[E3StartInput,ALU=0]; LoadPage[InitialPage]; RTemp _ 4C, CallP[SrShift]; Count _ (Count) - 1, GoTo[E3NextBoard,R>=0]; GoTo[E3Trouble]; *No 3 mb Ethernet E3StartInput: Count _ 15C; *This works out to 15 decimal retries *before giving up. T _ ReadInputHostNumber; Input[Host]; E3SendAgain: RTemp _ LoA[E3InStartLoc]; RTemp _ (RTemp) or (HiA[E3InStartLoc,E3InTask]); APCTask&APC _ RTemp, Call[E3Ret]; *Poke sending process to send the request again RTemp _ LoA[E3OutStartLoc]; RTemp _ (RTemp) or (HiA[E3OutStartLoc,E3OutTask]); *The double loop below should take about 10 seconds initially; after *connecting to a boot server, each good packet resets the high-order *count to 300b for a 1.91 sec timeout. *(2000b+2)*[60000b*4 + 15d] * 100d ns = 102.6us*(16384*6 + 15) = 10.09 sec RTemp1 _ 2000C; APCTask&APC _ RTemp, Call[E3Ret]; E3More: Nop; RTemp _ 60000C, Call[.+1]; RTemp _ (RTemp) - 1, Skip[R<0]; Return; *Interlock RTemp1 _ (RTemp1) - 1, GoTo[E3More,R>=0]; *Timeout. Try again. Count _ (Count) - 1, GoTo[E3SendAgain,R>=0]; E3Trouble: IncMPanel; GoTo[.]; SetTask[E3OutTask]; *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 E3OutStart: OutMask _ 0C, At[E3OutStartLoc]; E3OutAgain: OutTemp _ DisableOutput; Output[OutTemp,E3WriteState]; OutTemp _ EnableOutput, Call[E3OutState]; T _ RHMask[Host]; OutTemp _ T, Call[E3OutData]; OutTemp _ EtherPup, Call[E3OutData]; OutTemp _ PupOverhead, Call[E3OutData]; *? The D0MicrocodeRequest communication convention puts 3xN words + *Pup overhead in each packet; this results in total packet lengths *alternating between 776b and 1004b when PupWatch is used. The *BootFileNumber used here is really a BFI, and the BFN used by the *boot servers is BFI+3000b. OutTemp _ D0MicrocodeRequest, Call[E3OutData]; OutTemp _ OurVersionNumber, Call[E3OutData]; *PupID Output[BootFileNumber,E3WriteData]; *PupID2 OutTemp _ 0C, Call[E3OutTwice]; *dest PupAddress OutTemp _ MiscServSocket, Call[E3OutData]; T _ RHMask[Host]; OutTemp _ T, Call[E3OutData]; *our PupAddress T _ BootFileNumber; OutTemp _ T, Call[E3OutTwice]; OutTemp _ (Zero) - 1, Call[E3OutData]; *checksum OutTemp _ SendThisPacket, Call[E3OutState]; Input[OutTemp,E3ReadStatus]; LU _ (OutTemp) and (CollisionMask); GoTo[E3OutColl,ALU#0]; E3OutDone: OutTemp _ DisableOutput, GoTo[E3OutState]; *Rats, got a collision E3OutColl: T _ OutMask _ (LSh[OutMask,1]) + 1, Skip[R>=0]; GoTo[E3OutDone]; *Too many collisions, give up Nop; Nop; OutTemp _ T, Call[E3Ret]; T _ (OutTemp) - 1, GoTo[.-2,R<0]; GoTo[E3OutAgain]; E3OutTwice: Output[OutTemp,E3WriteData]; E3OutData: Output[OutTemp,E3WriteData], GoTo[E3Ret]; E3OutState: Output[OutTemp,E3WriteState], GoTo[E3Ret]; *Because of the way the hardware OR's the task number into the high-order *bits of the RM address, this OutTemp_OutTemp will also interlock *InTemp for the input task. E3Ret: OutTemp _ OutTemp, Return; *Interlock SetTask[E3InTask]; E3InStart: Source _ 0C, At[E3InStartLoc]; Packet _ 0C; Checksum _ 0C; *Caller has setup IniBaseLo/Hi to point at storage address to receive *the microcode or germ. WordOffset _ 0C; *Skip first packet E3InPurge: InTemp _ PurgeThisPacket, Call[E3InState]; *wait here for next packet to arrive E3InFilter: Input[InTemp,E3ReadStatus]; *Beware of H4PE *Jam or BadAlignment? LU _ (InTemp) and (100400C), Call[E3InEqChk]; T _ EtherPup, Call[E3InSkip1Check]; Input[BytesLeft,E3ReadData]; *PupLength T _ D0MicrocodeAnswer, Call[E3InCheck]; T _ OurVersionNumber, Call[E3InCheck]; *PupID T _ Packet, Call[E3InCheck]; *PupID2 Input[InTemp,E3ReadData]; *our PupAddress T _ RHMask[InTemp]; LU _ (RHMask[Host]) xor T, Call[E3InEqChk]; *For us? T _ BootFileNumber, Call[E3InCheck]; T _ BootFileNumber, Call[E3InCheck]; Input[SourceTemp,E3ReadData]; T _ MiscServSocket, Call[E3InSkip1Check]; *his PupAddress *Check that this packet is coming from the right machine. This can be *skipped if all boot servers really send the same version of the file. LU _ Source; T _ SourceTemp, Skip[ALU#0]; Source _ T, Skip; LU _ (Source) xor T, Call[E3InEqChk]; *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 Packet _ (Packet) + 1, GoTo[E3InGo]; *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 E3InSkip1Check: Input[Junk,E3ReadData]; *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 E3InCheck: Input[InTemp,E3ReadData]; Nop; *Beware of bypass kludge LU _ (InTemp) xor T; E3InEqChk: GoTo[E3Ret,ALU=0]; GoTo[E3InPurge]; E3InState: Output[InTemp,E3WriteState], GoTo[E3Ret]; E3InGo: BytesLeft _ (BytesLeft) - (PupOverhead); LU _ Checksum, GoTo[E3EndMarker,ALU=0]; BytesLeft _ (BytesLeft) - 1, Call[E3Ret]; E3InLoop: BytesLeft _ (BytesLeft) - (2C), GoTo[E3InDone,R<0]; Skip[IOAtten']; GoTo[E3InStart]; *Packet ended early Input[Word,E3ReadData]; T _ Word; Checksum _ (Checksum) + T; T _ WordOffset; PStore1[IniBaseLo,Word]; WordOffset _ (WordOffset) + 1, Return; E3InDone: Input[Junk,E3ReadData]; *Pup Checksum Input[Junk,E3ReadData]; *CRC Input[InTemp,E3ReadStatus]; LU _ (InTemp) and (InputStatusMask); Skip[ALU=0]; GoTo[E3InStart]; *Packet had bad status (got smashed) *Reset timer to 2 sec whenever we get a good packet RTemp1 _ 300C, GoTo[E3InPurge]; E3EndMarker: InTemp _ DisableInput, Skip[ALU=0]; ***Temporarily patch out error check because germ doesn't have checksum ***Fixed in Klamath. * GoTo[E3InStart]; *Checksum didn't match Nop; Output[InTemp,E3WriteState]; APCTask&APC _ IReturn, GoTo[E3Ret]; :END;(2469)\f2 6439b6B2290b1B