: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]<Henning>ENXSpec1.bravo, ENXSpec2.bravo, and Ether-sil.dm.
Other information was obtained from [Indigo]<D0Source>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:
*
00Nop
*
01Receive EOP
*
10Output EOP
*
11Xmt data wake request
* Output Attention status encode & priority:
*
00Nop
*
01Output EOP
*
10Receive EOP
*
11Receive 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];
:ENDIF; *************************************