:IF[Rubicon]; ******************************* TITLE[E10Load.not.assembled.for.Rubicon]; :ELSE; ************************************** TITLE[E10Load]; %Ed Fiala 19 June 1984: Update OldWordOffset at E10InStart and E10InDone as suggested by Blackman. Ed Fiala 12 March 1984: Supply missing Disp at E10OutputDone-5 reported by Blackman. Ed Fiala 6 February 1984: BFN initialization changes. Ed Fiala 16 January 1984: This file is a stub for implementing 10 mb ethernet booting. The BFNs in InitialDefs.mc and the Germ Request code in Initial.mc must also be edited. Documentation for the ENX 10 mb controller was obtained from "Ethernet Controller (ENX) Design Specification" by Tom Henning, Len Scheese, and Malcolm Thomson. This was supposed to have been obtained from [ISIS]ENXSpec1.bravo, ENXSpec2.bravo, and Ether-sil.dm. Other information was obtained from [Indigo]TrinityUCode.dm from the file ENXTask.mc (i.e., from the Pilot ENX microcode). This file is not debugged yet. The following need to be done: 1) Compute E10RequestCSum below and enable the commented-out code below E10Start. 2) Implement the exponential backoff collision retry algorithm (not absolutely required, but desirable--maybe omit it from the Boot.mb version of this program if space is very tight). 3) Find out what how to deal with abnormal output events other than collisions and fix code. 4) Find out whether PurgeMode can be entered at E10InStart when the receiver is presently idle--does purge mode automatically and immediately drop into enable-input mode in this case? If so, save 2 mi at E10InStart. 5) Worry about code at E10InDone. 6) Is the IOStrobe needed at E10EndMarker? 7) Is some kind of Input required before testing IOAttention? 8) Worry about the ordering of the IOStrobe and IOStore16 at E10InLoop. % SetTask[E10Task]; Set[Pream02,52525]; *OR 200b into Pream02 to get Pream3 *Set[E10RequestCSum,x]; *Request packet checksum not including *the three-word host number or boot file number. MC[NSOverhead,50]; *Packet length - NSOverhead = the number of data *bytes in the packet. The packet length in the *header is supposed to include all bytes in the *packet from the software checksum up to but not *including the hardware CRC at the end. The minimum *legal packet would be 46b bytes (2 smaller) because *it contains no sequence number. *Input register definitions Set[E10DevID,0]; MC[E10DeviceID,12400]; *ID for 10 mb Ethernet controller (ENX) *The three ways of reading the Status1 register read the same value but *have different effects on the mode latch. Set[E10Status1,1]; *Status1 register Set[E10XmtStatus,15]; *Status1 register, sets Mode Latch to Xmt Mode Set[E10RcvStatus,11]; *Status1 register, resets Mode Latch to Rcv Mode *Bits 0..3 duplicate bits 4..7 Set[E10SIBA,4000]; *Input bad alignment Set[E10SIORun,2000]; *Input overrun Set[E10SIBadPkt,1000]; *Input bad packet (Not in HW manual??) Set[E10SICRC,400]; *Input bad CRC MC[E10ISMask,Or[E10SIBA,E10SIBadPkt,E10SIORun,E10SICRC]]; Set[E10SOPar,200]; *Output bad parity Set[E10SOURun,100]; *Output underrun Set[E10SOColl,40]; *Transmitter-detected collision Set[E10SOFault,20]; *Output data fault MC[E10OSMask,Or[E10SOPar,E10SOURun,E10SOColl,E10SOFault]]; MC[E10OCollisionMask,E10SOColl]; *Bit 12d: XmtMicrocodeFlag (controller mode latch) *Bit 13..14d: io status encode * Input Attention status encode & priority: * 00 Nop * 01 Receive EOP * 10 Output EOP * 11 Xmt data wake request * Output Attention status encode & priority: * 00 Nop * 01 Output EOP * 10 Receive EOP * 11 Receive data wake request *Bit 15d: Xmt Fault (caused by bits 8..11d) Set[E10Status2,2]; *Status2 register *Bit 0: Reset Output' *Bit 1: Reset Output Buffer' *Bit 2: Output EOP *Bits 3..7: OutXSCount0..4 *Bit 8d: Reset Input' *Bit 9d: Purge mode *Bit 10d: LoopBack mode *Bits 11..15d: InXSCount0..4 *E10InData form for Input, E10IData form for IOStore4 or IOStore16. Set[E10InData,3]; *Data Set[E10IData,Add[LShift[E10Task,4],E10InData]]; *Data *Output register definitions Set[E10ResetState,0]; *General reset MC[E10ResetAll,0]; *Resets InState and OutState registers Set[E10IState,1]; *InState register MC[E10DisableInput,Or[LShift[1,14],0]]; *Resets: Enable Input MC[E10EnableInput,Or[LShift[11,14],0]]; *Sets: Enable Input MC[E10SetPurgeMode,Or[LShift[15,14],0]]; *Sets: Enable Input, PurgeMode Set[E10OState,2]; *OutState register Set[SetOutputEOP,340]; *Sets: Enable Output, OutputEOP Set[OutExcess,0]; *Minus number of excess bytes sent in output packet. MC[EnableOutput,300]; *Sets: Enable Output, Output Buffer MC[DisableOutput,0]; *Clears: Output State Reg, Reset Output Buf *MC[ResetBuffer,200]; *Clears: Reset Output Buffer Set[E10OutData,4]; *Output data for OUTPUT operation Set[E10OData,Add[LShift[E10Task,4],4]]; *Output data for IOFetch16 % *Completion codes MC[E10GoodPacket,040000]; *Good packet MC[E10ErrorZeroBuf,064000]; *Input or output buffer less than 16 words MC[E10PktBufOverrun,061000]; *Input buffer overrun MC[E10ErrorCountOV,062000]; *16 collisions occurred on output MC[E10LateCollision,063000]; *Output only % %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 BFN (Boot File Number) is in T at call. IniBaseLo/Hi point at the block of storage where the boot file should be put. At exit, the requested boot file has been loaded into the block of storage beginning at IniBaseLo/Hi and the WordOffset register points at the word after the last one loaded. The code here begins by assigning the 10 mb Ethernet controller to E10Task. Then the host number is determined from microlocation 7777b, where it was left by the boot program from the EPROMs. Then a MicrocodeRequest packet is broadcast to request the desired boot file. The encapsulation of this request is as follows: xxxxxx Preamble (a 4-word constant discarded by recipient) xxxxxx xxxxxx xxxxxx 177777 Destination host address (3 words) 177777 177777 000000 Source host address (3 words) ------ (from bits 0..15d of microlocation 7777b) ------ (from bits 16..31d of microlocation 7777b) 003000 Packet type ------ Software checksum over the following 16-bit words of the packet 000046 Packet length (in bytes beginning with the checksum, not including the 8 bytes of trailing zeroes) 000011 Control 000000 Destination network (2 words) 000000 177777 Destination host address (3 words) 177777 177777 000012 Destination socket number 000000 Source network number (2 words) 000000 ------ Source host address (3 words computed as above) ------ ------ 000101 Source socket number 000001 Boot packet type (request) 000000 Boot file number (3 words; first two words are a constant value 125002 for all Dolphins, a different constant for other machines; ------ third word is the boot file number desired) 000000 000000 000000 000000 Sending stops here; the hardware automatically supplies a 32-bit CRC. In response to this request, a boot server transmits the file as a sequence of packets to the requestor. The original timeout of 10 seconds is reset to 2 seconds after each packet is successfully received. The form of each of the packets is: ------ Destination host address (3 words) ------ ------ ------ Source host address (may be the gateway's--don't use this) ------ ------ 003000 Packet type ------ Software checksum ------ Packet length (in bytes beginning with the software checksum, not including the CRC at the end of the packet; this will equal 40d for the overhead bytes + 8xN for the data; the boot servers are known to transmit 512d data bytes in each packet up to the last packet) 000011 Control 000000 Destination network number (2 words) 000000 ------ Destination host address (3 words) ------ ------ 000101 Destination socket number ------ Source network number (2 words) ------ ------ Source host address (3 words real source--use this) ------ ------ 000012 Source socket number 000002 Boot packet type (reply) 000000 Boot file number (3 words; first two words are a constant value 125002 for all Dolphins, a different constant for other machines; ------ third word is the boot file number desired) ------ Sequence number beginning with 1 ------ boot file data .... Hardware CRC Much of the received packet is thrown away unchecked. The first packet of a sequence is accepted, if the destination host address is ours, the sequence number is 1, and the boot file number and packet type are correct. Subsequent packets are accepted if the destination host address is ours, the packet has the next consecutive sequence number, the packet type and boot file number are correct, and the source host matches packet 1's. Due to space limitiations, packet checksums are not verified. A packet having a length of 40d indicates no boot file data is present and ends the packet sequence. Since no packet can be less than 30d words long, there may be extra words at the end not included in the length--these are thrown out. The software checksum, initially 0, covers all packet words beginning with the word after the software checksum and ending with the last word before the hardware CRC. Each word is ones-complement added to the checksum, and then the checksum is left-cycled 1; equivalently, the old checksum and new data can each be left-cycled 1 and then ones-complement added. A final checksum of 177777b is converted to 0 by convention because 177777b in the software checksum by convention means that the sender did not compute the checksum. % SetTask[0]; OnPage[E10Page]; E10Load: BootFileNumber _ T, UseCTask; T _ APCTask&APC, Task; *Save return address of caller in Initial.mc IReturn _ T; Count _ 20C; *Load the task number register of the first io controller with the *task number desired for the 10 mb Ethernet. T _ RTemp1 _ Xor[E10Task,17]C; E10NextBoard: LoadPage[InitialPage]; RTemp _ 4C, CallP[SrShift]; *In Initial.mc T _ Or[LShift[E10Task,4],E10DevID]C; Input[RTemp]; *See if the controller is, in fact, the 10 mb Ethernet controller. T _ E10DeviceID; LU _ (LHMask[RTemp]) xor T; T _ RTemp1 _ (Zero) - 1, GoTo[E10GetHostID,ALU=0]; *If the controller is not the 10 mb Ethernet controller, then shift the *task number (complemented) to the next controller and try again. Count _ (Count) - 1, GoTo[E10NextBoard,R>=0]; *No 10 mb Ethernet controller found. GoTo[E10Trouble]; %The 10 mb Ethernet controller has been assigned to the proper task. Determine the 48-bit host number as 0 in the high-order 16 bits followed by the value in the microinstruction at 7777b (left there by the Boot code and preserved from then on by all microcode systems). % E10GetHostID: RTemp _ HiA[7777]; RTemp _ (RTemp) or (LoA[7777]); E10HostID1 _ T _ 0C, Call[E10GetCS]; E10HostID2 _ T; T _ 1C, Call[E10GetCS]; E10HostID3 _ T; %Now task 0 wakes up the 10 mb Ethernet task to output the boot file request. Then task 0 waits until a timeout has occurred. Upon timeout it will try again until failure has occurred 15d times, at which point it increments the MP and halts. Originally the timeout loop is set to ~10 seconds; when each good packet is received, the high-order count is reset to 300b for ~2 second timeout. It is important not to try too hard here because malfunctioning machines have been known to flood the ethernet with repeated "boot me" requests, causing problems for other users. % Count _ 15C; E10SendAgain: RTemp _ LoA[E10StartLoc]; RTemp _ (RTemp) or (HiA[E10StartLoc,E10Task]); *Start E10Task APCTask&APC _ RTemp, Call[E10Ret]; RTemp1 _ 2000C; E10More: Nop; RTemp _ 60000C, Call[.+1]; RTemp _ (RTemp) - 1, Skip[R<0]; Return; RTemp1 _ (RTemp1) - 1, GoTo[E10More,R>=0]; *Timeout. Resend request for boot file. Count _ (Count) - 1, GoTo[E10SendAgain,R>=0]; E10Trouble: IncMPanel; GoTo[.]; E10GetCS: APCTask&APC _ RTemp; ReadCS; *Force even placement T _ CSData, Return, DispTable[1,1,0]; SetTask[E10Task]; *Useful subroutines for building boot file request packet E10Out3: Output[E10Temp0,E10OutData]; Nop; E10Out2: Output[E10Temp0,E10OutData]; Nop; E10Out1: Output[E10Temp0,E10OutData], GoTo[E10Ret]; E10WriteInState: Output[E10Temp0,E10IState], GoTo[E10Ret]; %E10CSumT: E10Temp0 _ (E10Temp0) + T; E10Temp0 _ (E10Temp0) + 1, UseCOutAsCIn, Return; % %Now output the boot file request packet. This will be sent at least once, more times if the boot file is not received correctly the first time. Start to send words to the hardware. The hardware will start transmission to the Wire as soon as the buffer has more than 128 words, or when the OutputEOP bit is set (for a packet of less than 127 words). For this short packet, output won't start until OutputEOP is set, so the fact that the Output's do not prepare the message as fast as the 10 mb Ethernet requires is of no concern. The transmit hardware generates a wakeup request whenever the transmit buffer holds less than 128 words. Whenever an IOStrobe is received, while the microcode is in transmit mode, transmit wake requests are inhibited until the data transfer has taken place. This prevents double wakeups caused by the memory pipe. When the output end-of-packet is set, wakeups will not be requested until the wire has exhausted the buffer data or sensed a collision. From then on, wakeups will be generated until ResetOutput' is sent via the OutState register. Transmit wakeups can be inhibited by disabling the transmit hardware via the State Register by the signal ResetOutput'. The microcode may output 1, 4, or 16d words at-a-time and is allowed to output an excess number of words, if it wishes. The final Output, IOFetch4, or IOFetch16 must be preceded by outputting OutputEOP and an Excess Byte Count defined to be minus the number of excess bytes sent (0 to -31d). Here, exactly the right number of bytes are sent, so the excess is 0. % E10Start: *General reset of the hardware E10Temp0 _ E10ResetAll, At[E10StartLoc]; Output[E10Temp0,E10ResetState]; *Interlock the previous Output and then enable output. E10Temp0 _ EnableOutput; Output[E10Temp0,E10OState]; E10Temp0 _ E10Temp0; *Interlock the output *Enable transmitter interrupts Input[E10Temp1,E10XmtStatus]; *Four-word preamble = 52525b..52525b..52525b..52725b E10Temp0 _ HiA[Pream02]; E10Temp0 _ (E10Temp0) or (LoA[Pream02]), Call[E10Out3]; E10Temp0 _ (E10Temp0) or (200C), Call[E10Out1]; *Three-word destination host = 177777b..177777b..177777b. E10Temp0 _ (E10Temp0) or not (0C), Call[E10Out3]; *Three-word source host = HostID1..HostID2..HostID3 Output[E10HostID1,E10OutData]; Output[E10HostID2,E10OutData]; Output[E10HostID3,E10OutData]; *Packet type = 3000b E10Temp0 _ 3000C, Call[E10Out1]; *Software checksum (all precomputed except for source host address and *boot file number) % E10Temp0 _ HiA[E10RequestCSum]; E10Temp0 _ (E10Temp0) or (LoA[E10RequestCSum]); T _ LCy[HostID1,14], Call[E10CSumT]; T _ LCy[HostID2,13], Call[E10CSumT]; T _ LCy[HostID3,12], Call[E10CSumT]; T _ LCy[BootFileNumber,5], Call[E10CSumT]; Output[E10Temp0,E10OutData], Call[E10Ret]; % *Instead of the above code, indicate checksum not computed by putting *-1 in the software checksum word. E10Temp0 _ (E10Temp0) or not (0C), Call[E10Out1]; *Packet length = 46b E10Temp0 _ 46C, Call[E10Out1]; *Control = 11b E10Temp0 _ 11C, Call[E10Out1]; *Two-word destination network = 0..0 E10Temp0 _ 0C, Call[E10Out2]; *Three-word destination host = 177777b..177777b..177777b. E10Temp0 _ (E10Temp0) or not (0C), Call[E10Out3]; *Destination socket number = 12b E10Temp0 _ 12C, Call[E10Out1]; *Two-word source network number = 0..0 E10Temp0 _ 0C, Call[E10Out2]; *Three-word source host = HostID1..HostID2..HostID3 Output[E10HostID1,E10OutData]; Output[E10HostID2,E10OutData]; Output[E10HostID3,E10OutData]; *Source socket number E10Temp0 _ 101C, Call[E10Out1]; *Boot packet type = 1 (request) E10Temp0 _ 1C, Call[E10Out1]; *Three-word boot file number = E10BFNHi..E10BFNMid..BootFileNumber E10Temp0 _ HiA[E10BFNHi]; E10Temp0 _ (E10Temp0) or (LoA[E10BFNHi]), Call[E10Out1]; E10Temp0 _ HiA[E10BFNMid]; E10Temp0 _ (E10Temp0) or (LoA[E10BFNMid]), Call[E10Out1]; Output[BootFileNumber,E10OutData]; *Four words of zeroes completes the packet; three are sent, then the *OutputEOP and excess count, and finally the last zero. E10Temp0 _ 0C, Call[E10Out3]; *Start the transmitter and tell it minus the number of excess bytes that *will be sent in a five-bit field; since exactly the right byte count is *sent, the excess value is 0. E10Temp1 _ Or[SetOutputEOP,OutExcess]C; Output[E10Temp1,E10OState]; *Output the final 0 (Must have 1 non-memory-ref mi after the previous *Output to allow the E10Temp1 write to complete). Call[E10Out1]; %End output of boot file request packet. Next wakeup happens after the request has been fully transmitted or suffered a collision or when a packet is received. Process the wakeup reason by decoding Status1. Collisions should be retried with the exponential backoff algorithm. Input packets are ignored until Output EOP is received. Upon Output EOP, output is disabled, and the code falls through to E10InStart. At E10InStart, at least one packet (the one just transmitted) will be flushed before the boot server's response can possibly be received (Output packet done is higher priority than receiver wakeups, so its status will be reported before the receiver EOP for the same packet). % Input[E10Temp0,E10Status1]; LU _ Dispatch[E10Temp0,15,2]; *dispatch on io status Disp[.+1]; GoTo[E10Trouble], DispTable[4]; *Nop status is impossible *Output EOP; check for problems. LU _ (E10Temp0) and (E10OSMask), GoTo[E10OutputDone]; *Receive EOP; flush incoming packet and wait. E10Temp0 _ E10SetPurgeMode, GoTo[E10WriteInState]; *Receiver data wakeup; flush incoming packet and wait. E10Temp0 _ E10SetPurgeMode, GoTo[E10WriteInState]; E10OutputDone: LU _ (E10Temp0) and (Or[E10SOPar,E10SOURun,E10SOFault]C), GoTo[E10OutOff,ALU=0]; *Some problem on output; retry expected failures (collisions only); *crash on other problems. Skip[ALU=0]; GoTo[E10Trouble]; *Fatal problem ***Collision. Should retry with exponential backoff algorithm; for now, ***disable output and wait in the input loop until timeout occurs. Nop; E10OutOff: E10Temp0 _ DisableOutput; Output[E10Temp0,E10OState]; *Initialize registers for receiving the boot file. E10InStart: Packet _ 0C; *Select receive mode wakeups Input[E10Temp0,E10RcvStatus]; Checksum _ 0C; *Caller has setup IniBaseLo/Hi to point at storage address to receive the *microcode or germ. T _ OldWordOffset _ 0C; *Enable input. E10Temp0 _ E10EnableInput, GoTo[.+2]; E10InPurge: E10Temp0 _ E10SetPurgeMode; WordOffset _ T; *Purge the current packet, after which input is automatically reenabled *by the hardware. ***Is input automatically reenabled by hardware? ***Does this automatically and immediately drop into receive mode, if the ***receiver had nothing to purge? Output[E10Temp0,E10IState], Call[E10Ret]; %Idle state of input microcode. Wait for the next packet to arrive; this is the only reason for a wakeup here because the transmitter is off. The receiver throws away the preamble for a packet and generates a wakeup request whenever 16d or more words are in the receiver's buffer. Whenever an IOStrobe is received, while the controller is in receive mode, receive wake requests will be inhibited until the data transfer has taken place. This prevents double wakeups caused by the memory pipe. Once end-of-packet is sensed, wakeups are then continuously requested until purge mode is set. The microcode transfers 4 or 16d words at-a-time, so the final transfer in a packet may append some garbage to the last valid data. The number of excess bytes read is indicated by an Input Excess Byte Count defined to be 32 minus the number of good bytes in the last input transfer. ???IOAtten' will occur AFTER? or BEFORE? the final transfer has STARTED? or COMPLETED??? The boot servers send 512d data bytes plus encapsulation bytes in each packet, so there are no excess bytes with the last IOStore16 for a packet until the final packet of the file is transmitted, and we don't care about excess words after the EOF. Since the file is transmitted into a 16d-word aligned storage buffer, this means that IOStore16's can be used throughout without any complications. % *At least 16d words are in the buffer here. Each subroutine call below *will return (without letting the emulator run) unless fewer than 16d words *remain in the buffer. In that event, E10Task will block until either 16d *words are in the buffer or EOP occurs. T _ E10HostID1, Call[E10InCheck]; T _ E10HostID2, Call[E10InCheck]; T _ E10HostID3, Call[E10InCheck]; *Receive source host; this may be a gateway rather than a real source, so *we ignore it and check the original source specified later. Input[E10Temp0,E10InData]; *Skip last 2 words of source host; then receive & check packet type T _ 3000C, Call[E10InSkip2]; *Receive & ignore software checksum Input[E10Temp0,E10InData]; *Receive packet length (in bytes beginning with the software checksum, *not including the CRC at end-of-packet). Input[BytesLeft,E10InData]; *Skip 1 word control and 2 words destination network number; then check *three words of destination host. Input[E10Temp0,E10InData]; T _ E10HostID1, Call[E10InSkip2]; T _ E10HostID2, Call[E10InCheck]; T _ E10HostID3, Call[E10InCheck]; *Receive & check destination socket number T _ 101C, Call[E10InCheck]; *Branch on 1st packet while skipping 1st source network number word. LU _ Packet; Input[E10Temp0,E10InData], GoTo[E10InPacket1,ALU=0]; *Skip 2nd source network number word and check 3 source host words. T _ E10Source0, Call[E10InSkip1]; T _ E10Source1, Call[E10InCheck]; T _ E10Source2, Call[E10InCheck]; *Skip source socket number; then receive & check boot packet type E10InPacket2: T _ 2C, Call[E10InSkip1]; *Skip 2 constant words of boot file number; then receive & check the *interesting word. T _ BootFileNumber, Call[E10InSkip2]; *Receive & check sequence number T _ (Packet) + 1, Call[E10InCheck]; %Packet is acceptable. The boot servers are supposed to send complete pages until the last page of the file; this means that IOStore16's can be used throughout, since each packet will contain 32xN bytes of data. The receiver is not screwed up by Input/IOStore16'ing words beyond the end of the packet anyway. Following the last 512d-byte data packet, a partially-full packet will be sent followed by an empty packet (i.e., one containing the 50b bytes of overhead without any following data words); this terminates the file. % E10InGo: BytesLeft _ (BytesLeft) - (NSOverhead); T _ WordOffset, GoTo[E10EndMarker,ALU=0]; *Preserve WordOffset at the beginning in case something is found to *be wrong with the packet below. OldWordOffset _ T; BytesLeft _ (BytesLeft) - 1, Call[E10Ret]; E10InLoop: BytesLeft _ (BytesLeft) - (40C), GoTo[E10InDone,R<0]; ***Maybe this IOStrobe has to be done after the IOStore16 and at least ***1 mi before the Return below. T _ WordOffset, IOStrobe, Skip[IOAtten]; %IOAtten occurs when something unusual has happened; when receiver interrupts are enabled, the possibilities are EOP, output packet done (impossible here), and transmitter data wakeup (impossible here). Hence, IOAtten implies EOP here. But if that happens before exhausting BytesLeft, the packet was incomplete, so assume a late collision happened, and purge the packet. If there was a late collision, sender may detect it and retransmit, in which case we will get the packet again. Or if it is the first packet in the file, another boot server may answer our boot file request. Otherwise, the 10 second timeout (1st packet) or 2 second timeout (subsequent packets) will elapse, and we will try again. It is important here not to flood the ethernet with too frequent boot file requests because this can trash the net when a machine is not working well, so it would not be a good idea to go to E10InStart here. % T _ OldWordOffset, GoTo[E10InPurge]; IOStore16[IniBaseLo,E10IData]; WordOffset _ (WordOffset) + (20C), Return; E10InDone: Call[.+1]; Input[E10Temp0,E10Status1]; LU _ (E10Temp0) and (E10ISMask), GoTo[.+3,IOAtten']; *Harmlessly process legal garbage words after the last good data in the *packet until we get IOAtten' indicating EOP. T _ WordOffset, IOStrobe; IOStore16[IniBaseLo,E10IData], GoTo[E10Ret]; T _ WordOffset, Skip[ALU=0]; T _ OldWordOffset, GoTo[E10InPurge]; *Bad packet *Good packet; reset high-order timeout word for ~2 second timeout. Packet _ (Packet) + 1; OldWordOffset _ T; RTemp1 _ 300C, GoTo[E10InPurge]; E10EndMarker: ***GoTo E10InStart if checksum is bad here. E10Temp0 _ E10ResetAll; Output[E10Temp0,E10ResetState]; IOStrobe; APCTask&APC _ IReturn, GoTo[E10Ret]; *Receive 1st packet of the file. E10InPacket1: *Skip 2nd source network number word Input[E10Temp0,E10InData]; *Receive & save 3 source host number words Input[E10Source0,E10InData]; Input[E10Source1,E10InData]; Input[E10Source2,E10InData], GoTo[E10InPacket2]; E10InSkip2: Input[E10Temp0,E10InData]; E10InSkip1: Input[E10Temp0,E10InData]; E10InCheck: Input[E10Temp0,E10InData]; Nop; *Beware bypass kludge LU _ (E10Temp0) xor T; E10InEqChk: GoTo[E10Ret,ALU=0]; T _ OldWordOffset, GoTo[E10InPurge]; E10Ret: E10Temp0 _ E10Temp0, Return; END[E10Load];(2469)\f2 :ENDIF; ************************************* (635)\f2