-- File: EtherBoot.mesa,  Edit: HGM November 4, 1980  1:50 AM
-- Snitched from Taft's EtherBoot.asm with a bit of help from Teco


DIRECTORY
  BcplOps USING [BcplJSR],
  ProcessDefs USING [DisableInterrupts],
  DiskLessDefs;

EtherBoot: PROGRAM IMPORTS BcplOps, ProcessDefs EXPORTS DiskLessDefs =
  BEGIN


  BootDMTViaNet: PUBLIC PROCEDURE = BEGIN BootViaNet[0, 0]; END;

  BootViaNet: PUBLIC PROCEDURE [bootFileNumber, host: WORD] =
    BEGIN
    ProcessDefs.DisableInterrupts[];
    bootLoaderProgram[74B] ← bootFileNumber;
    bootLoaderProgram[67B] ← host*400B;
    goLoadSomething[6B] ← @bootLoaderProgram[31B];
    [] ← BcplOps.BcplJSR[JSR, @goLoadSomething[0B], NIL]; -- bye bye

    END;

  GetPointerToBootLoader: PUBLIC PROCEDURE RETURNS [POINTER] =
    BEGIN RETURN[@bootLoaderProgram]; END;

  goLoadSomething: ARRAY [0..8] OF UNSPECIFIED ←
    [20406B, --  lda 0 lvBootLoaderPacket		; Get pointer to loader
      101400B, --  inc 0 0			; Compute page0image-1
      24405B, --  lda 1 k400			; Last destination address
      34405B, --  lda 3 lblt			; Negative of number of words
      61005B, --  blt				; Move loader into page 0
      6B, --  jmp boot0-page0image+page0origin	; Dive into loader
      0B, --  lvBootLoaderPacket: bootLoaderPacket
      400B, --  k400:	400
      177402B --  lblt:	-401+page0origin
      ];

  bootLoaderProgram: ARRAY [31B..426B] OF WORD ←
    [
      --                             1	
      --                             2	; EtherBoot.asm - Alto Ethernet boot loader
      --                             3	; Implemented (with much blood and sweat) by E. A. Taft / July 1976
      --                             4	
      --                             5	;	Last modified January 2, 1978  1:54 PM
      --                             6	
      --                             7	.ent bootLoaderPacket
      --                             8	.ent EtherBoot
      --                             9	
      --                            10	.srel
      --                            11	
      --     0        31B           12	bootLoaderPacket: .bootLoaderPacket
      --     1         0B           13	EtherBoot: .EtherBoot
      --                            14	
      --                            15	.nrel
      --                            16	
      --                            17	; Format of an Ethernet-encapsulated Pup
      --               0            18	etherAdr = 0		; Destination/source bytes
      --               1            19	etherType = 1		; Ethernet type word
      --               2            20	pupLength = 2		; Pup length
      --               3            21	pupType = 3		; Transport control and type
      --               4            22	pupID = 4		; Pup ID (2 words)
      --               6            23	pupDNetHost = 6		; Pup destination net/host
      --               7            24	pupDSocket = 7		; Pup destination socket (2 words)
      --              11            25	pupSNetHost = 11	; Pup source net/host
      --              12            26	pupSSocket = 12		; Pup source socket
      --              14            27	pupContents = 14	; Pup contents start here
      --                            28	
      --             602            29	typeBreathOfLife = 602	; Ethernet type for a boot loader packet
      --            1000            30	typePup = 1000		; Ethernet type for a Pup
      --             244            31	typeMayday = 244	; Pup type for boot file request
      --               4            32	socketMiscServices = 4	; Socket to which request should be sent
      --              20            33	socketEFTPReceiver = 20	; Our EFTP receiver socket
      --                            34	
      --               3            35	page0origin = 3		; Where page 0 portion of loader runs
      --             624            36	page1origin = 624	; Where page 1 portion of loader will run
      --                            37	
      --                            38	; Ethernet control word addresses
      --             600            39	ePLoc = 600
      --             601            40	eBLoc = 601
      --             602            41	eELoc = 602
      --             603            42	eLLoc = 603
      --             604            43	eICLoc = 604
      --             605            44	eIPLoc = 605
      --             606            45	eOCLoc = 606
      --             607            46	eOPLoc = 607
      --             610            47	eHLoc = 610
      --                            48	
      --                            49	; Convenient constant for accessing Ethernet control words by
      --                            50	; displacement addressing
      --             777            51	eBase = 777

      --                            52	
      --                            53	; EtherBoot(bfn, returnOnFail [false], host [0])
      --                            54	; BCPL-callable procedure that copies the boot loader into page 0
      --                            55	; and dives into it.  bfn is the desired boot file number and
      --                            56	; host, if specified, is host from which to request the boot file
      --                            57	; (the default is zero, meaning broadcast the request).
      --                            58	
      --                            59	; If no boot server responds to the request and returnOnFail is true,
      --                            60	; EtherBoot returns to its caller.  Pages 0 and 1 are clobbered and
      --                            61	; interrupts are disabled, so it is the caller's responsibility to
      --                            62	; save and restore these pages and reenable interrupts.
      --                            63	
      --                            64	.EtherBoot:
      --     0     61000            65		dir			; Interrupts off
      --     1     50543            66		sta 2 bcplStack		; Save stack pointer for possible return
      --     2     40472            67		sta 0 mayday+pupID+1	; Put bfn in mayday packet
      --     3     21400            68		lda 0 0 3		; Get number of args
      --     4    100400            69		neg 0 0
      --     5    101405            70		inc 0 0 snr		; Skip if more than one
      --     6       405            71		 jmp eb1
      --     7    175400            72		inc 3 3			; Where to return to
      --    10    125014            73		mov# 1 1 szr		; returnOnFail true?
      --    11     54534            74		 sta 3 GiveUp		; Yes, set up return pc
      --    12    101405            75		inc 0 0 snr		; Skip if more than two args
      --    13    102461            76	eb1:	 mkzero 0 0 skp		; No host supplied, use zero
      --    14     21003            77		 lda 0 3 2		; Host supplied, use it
      --    15     40460            78		sta 0 mayday+pupDNetHost  ; Set Pup destination host
      --    16    101300            79		movs 0 0		; Put dest in left half
      --    17     40450            80		sta 0 mayday+etherAdr	; Set Ether destination
      --    20     22406            81		lda 0 @lvBootLoaderPacket  ; Get pointer to loader
      --    21    101400            82		inc 0 0			; Compute page0image-1
      --    22     24405            83		lda 1 k400		; Last destination address
      --    23     34405            84		lda 3 lblt		; Negative of number of words
      --    24     61005            85		blt			; Move loader into page 0
      --    25         6            86		jmp boot0-page0image+page0origin  ; Dive into loader
      --                            87	
      --    26         0            88	lvBootLoaderPacket: bootLoaderPacket
      --    27       400            89	k400:	400
      --    30    177402            90	lblt:	-401+page0origin

      --                            91	
      --                            92	; The Ethernet Boot Loader.
      --                            93	; The first two words are reserved for the Ethernet header.
      --                            94	; The Alto jumps to the third word of the packet after receipt.
      --                            95	
      --                            96	.bootLoaderPacket:	; Absolute address = 1 at runtime
      --    31--0B, --        97		0		; Destination/source (filled in at runtime)
      --    32--602B, --        98		typeBreathOfLife
      --                            99	
      --                           100	; The following code runs only in page 0 and never migrates to page 1.
      --                           101	page0image:	; Absolute address = 3 at runtime
      --                           102	
      --                           103	; Set the parameter that determines the desired boot file
      --    33--22574B, --       104		lda 0 @c177035		; Get keyboard bits
      --    34--100000B, --       105		com 0 0			; Turn them right side up
      --    35--40437B,
      --       106		sta 0 mayday+pupID+1	; Use as low 16 bits of Pup ID
      --                           107	
      --                           108	; Correct all memory parity by reading and writing all words in memory
      --                           109	; (note that interrupts are off, so the parity errors won't cause trouble).
      --                           110	; EtherBoot procedure enters here.
      --    36--102000B,
      --       111	boot0:	mkminusone 0 0		; First source adr = 0 (-1)
      --    37--34431B, --       112		lda 3 k1000		; Count = -177000
      --    40--164000B, --       113		com 3 1			; Last dest adr = 176777
      --    41--61005B, --       114		blt
      --                           115	
      --                           116	; Zero selected regions in page 1
      --    42--102460B, --       117		mkzero 0 0
      --    43--24567B, --       118		lda 1 c427		; Zero 401-427
      --    44--34572B, --       119		lda 3 m27
      --    45--61006B, --       120		blks
      --    46--24565B, --       121		lda 1 c567		; Zero 431-567
      --    47--34570B, --       122		lda 3 m137
      --    50--61006B, --       123		blks
      --    51--24564B, --       124		lda 1 c777		; Zero 600-777
      --    52--34566B, --       125		lda 3 m200
      --    53--61006B, --       126		blks
      --                           127	
      --                           128	; Copy top part of boot loader up to page 1 (note ac1 still contains 777)
      --    54--20565B, --       129		lda 0 pPage1Code
      --    55--34565B, --       130		lda 3 mPage1Count
      --    56--61005B, --       131		blt
      --                           132	
      --                           133	; Set up a "Mayday" packet to broadcast
      --    57--125220B, --       134		movzr 1 1		; Make mask = 377
      --    60--46573B,
      --       135		sta 1 @.errcnt		; Max allowable output errors = 377
      --    61--20576B, --       136		lda 0 c3		; Reset Ethernet
      --    62--61004B, --       137		sio
      --    63--123400B, --       138		and 1 0			; Mask local ethernet address
      --    64--30551B, --       139		lda 2 .eBase
      --    65--41211B, --       140		sta 0 eHLoc-eBase 2	; Store for microcode
      --    66--4416B, --       141		jsr boot1		; Make pointer to output packet
      --                           142	
      --                           143	; The "Mayday" packet that we broadcast
      --    67--0B, --       144	mayday:	0		; Destination/source (filled in)
      --    70--1000B, --       145	k1000:	1000		; Ethernet packet type = typePup
      --    71--26B, --       146		22.		; Pup length
      --    72--244B, --       147		typeMayday	; Transport control/type
      --    73--0B, --       148	timeout: 0		; Pup ID
      --    74--0B, --       149		0		; 
      --    75--0B,
      --       150		0		; Destination net/host (broadcast or filled in)
      --    76--0B, --       151		0		; Destination socket
      --    77--4B, --       152		socketMiscServices
      --   100--0B, --       153		0		; Source net/host (filled in at runtime)
      --   101--0B, --       154		0		; Source socket (EFTP receiver)
      --   102--20B, --       155		socketEFTPReceiver
      --   103--177777B, --       156		-1		; Nil checksum
      --                           157	
      --   104--55210B,
      --       158	boot1:	sta 3 eOPLoc-eBase 2	; Set pointer to packet
      --   105--25400B, --       159		lda 1 etherAdr 3	; Get dest host from packet
      --   106--107000B, --       160		add 0 1			; Set source = me
      --   107--45400B, --       161		sta 1 etherAdr 3
      --   110--41411B,
      --       162		sta 0 pupSNetHost 3	; Set Pup source net = 0, host = me
      --   111--20547B, --       163		lda 0 d13		; Size of packet
      --   112--41207B, --       164		sta 0 eOCLoc-eBase 2

      --                           165	
      --                           166	; Page 0 portion of boot loader (cont'd)
      --                           167	
      --                           168	; Loop here for each retransmission of broadcast request
      --   113--20544B, --       169	boot2:	lda 0 c3		; Reset Ethernet
      --   114--61004B, --       170		sio
      --   115--6531B, --       171		jsr @.DoEtherOutput	; Send packet off
      --                           172	
      --                           173	; Set up to receive reply
      --   116--34517B,
      --       174	boot3:	lda 3 .eBase		; For accessing Ethernet control words
      --   117--30544B, --       175		lda 2 c1000		; Where to put reply (page 2)
      --   120--51606B, --       176		sta 2 eIPLoc-eBase 3
      --   121--20510B, --       177		lda 0 d269		; Max length
      --   122--41605B, --       178		sta 0 eICLoc-eBase 3
      --   123--42526B, --       179		sta 0 @.maxLength
      --   124--102460B, --       180		mkzero 0 0		; Zero post location
      --   125--41601B, --       181		sta 0 ePLoc-eBase 3
      --   126--20530B, --       182		lda 0 c2		; etherInputCommand
      --   127--61004B, --       183		sio			; Fire up receiver
      --                           184	
      --                           185	; Await reply
      --   130--21601B,
      --       186	boot4:	lda 0 ePLoc-eBase 3	; Anything happened?
      --   131--101014B, --       187		sz 0 0
      --   132--414B, --       188		 jmp boot6		; Yes
      --   133--61020B, --       189		mul			; No, waste time
      --   134--14737B, --       190		dsz timeout		; Timed out (about 1 second)?
      --   135--773B, --       191		 jmp boot4		; No, keep waiting
      --   136--14517B, --       192		dsz retries		; Yes, too many retries?
      --   137--754B, --       193		 jmp boot2		; No, send another request
      --   140--20517B, --       194		lda 0 c3		; Yes, reset interface and give up
      --   141--61004B, --       195		sio
      --   142--30402B, --       196		lda 2 bcplStack
      --   143--2402B, --       197		jmp @GiveUp		; Return to caller or loop
      --                           198	
      --   144--0B, --       199	bcplStack: 0
      --   145--732B,
      --       200	GiveUp:	Bomb-D			; Overwritten by EtherBoot if returnOnFail
      --                           201	
      --                           202	; Here when have possible reply
      --   146--34514B, --       203	boot6:	lda 3 c377		; Good input done status?
      --   147--162414B, --       204		se 3 0
      --   150--746B, --       205		 jmp boot3		; No, ignore
      --   151--21001B, --       206		lda 0 etherType 2	; Yes, is it a Pup?
      --   152--24511B, --       207		lda 1 c1000
      --   153--106414B, --       208		se 0 1
      --   154--742B, --       209		 jmp boot3		; No, ignore
      --   155--21003B, --       210		lda 0 pupType 2		; Yes, get Pup type
      --   156--163400B, --       211		and 3 0
      --   157--35005B, --       212		lda 3 pupID+1 2		; Get sequence number
      --   160--24501B, --       213		lda 1 c30		; EFTP data?
      --   161--106415B, --       214		sne 0 1
      --   162--175014B, --       215		sz 3 3			; Sequence number zero?
      --   163--733B, --       216		 jmp boot3		; No, ignore

      --                           217	
      --                           218	; Page 0 portion of boot loader (cont'd)
      --                           219	
      --                           220	; We got a good packet, set up for transfer.
      --   164--21000B, --       221		lda 0 etherAdr 2	; Get dest/source word
      --   165--42465B, --       222		sta 0 @.goodDestSource	; Save it
      --   166--34457B,
      --       223		lda 3 .ackPacket	; Where we will build the Ack
      --   167--56445B,
      --       224		sta 3 @.eOPLoc		; Set pointer (count already ok)
      --   170--55775B,
      --       225		sta 3 426-ackPacket+D 3	; Cursor coordinates = (531,531)
      --   171--55776B, --       226		sta 3 427-ackPacket+D 3
      --   172--101300B, --       227		movs 0 0		; Swap source and destination
      --   173--41400B, --       228		sta 0 etherAdr 3	; Store in Ack
      --   174--20467B, --       229		lda 0 c1000		; Type = Pup
      --   175--41401B, --       230		sta 0 etherType 3
      --   176--20432B, --       231		lda 0 d22		; Pup length = 22
      --   177--41402B, --       232		sta 0 pupLength 3
      --   200--121400B, --       233		inc 1 0			; Pup type = Ack = 31
      --   201--41403B, --       234		sta 0 pupType 3
      --   202--21006B,
      --       235		lda 0 pupDNetHost 2	; Copy and exchange source and
      --   203--41411B, --       236		sta 0 pupSNetHost 3	;  destination ports
      --   204--21007B, --       237		lda 0 pupDSocket 2
      --   205--41412B, --       238		sta 0 pupSSocket 3
      --   206--21010B, --       239		lda 0 pupDSocket+1 2
      --   207--41413B, --       240		sta 0 pupSSocket+1 3
      --   210--21011B, --       241		lda 0 pupSNetHost 2
      --   211--41406B, --       242		sta 0 pupDNetHost 3
      --   212--21012B, --       243		lda 0 pupSSocket 2
      --   213--41407B, --       244		sta 0 pupDSocket 3
      --   214--21013B, --       245		lda 0 pupSSocket+1 2
      --   215--41410B, --       246		sta 0 pupDSocket+1 3
      --   216--15414B, --       247		dsz pupContents 3	; Pup checksum = nil (-1)
      --                           248	
      --                           249	; Now read and discard packet 0 (which has the disk boot loader)
      --                           250	; and read packet 1, which contains the data destined for page 0.
      --   217--6427B,
      --       251		jsr @.DoEtherOutput	; Ack the packet we just got
      --   220--12434B, --       252		isz @.seqNum		; Advance to sequence number 1
      --   221--6426B, --       253		jsr @.ReceiveEFTPPacket	; Read packet 1
      --                           254	
      --                           255	; Set up to transfer packet data into page 0 and jump to remaining
      --                           256	; boot code in page 1
      --   222--20421B, --       257		lda 0 pPage2Data	; First source adr -1
      --   223--24437B, --       258		lda 1 c377		; Last dest adr
      --   224--134000B, --       259		com 1 3			; - number of words (400)
      --   225--30417B,
      --       260		lda 2 pPage2Packet	; Where to start reading packet 2
      --   226--2422B, --       261		jmp @.ContinueBoot	; Jump to code in page 1
      --                           262	
      --                           263	
      --   227--177035B, --       264	c177035: 177035
      --   230--26B, --       265	d22:	22.
      --   231--415B, --       266	d269:	269.
      --   232--427B, --       267	c427:	427
      --   233--567B, --       268	c567:	567
      --   234--607B, --       269	.eOPLoc: eOPLoc
      --                           270	.eBase:
      --   235--777B, --       271	c777:	777
      --   236--177751B, --       272	m27:	-27
      --   237--177641B, --       273	m137:	-137
      --   240--177600B, --       274	m200:	-200
      --   241--225B, --       275	pPage1Code: page1image-page0image+page0origin-1
      --   242--177624B, --       276	mPage1Count: page1origin-1000
      --   243--1013B,
      --       277	pPage2Data: 1000+12.-1	; Where page 0 data sits when in page 2
      --   244--764B,
      --       278	pPage2Packet: 1000-12.	; Where to start reading packet 2
      --   245--431B,
      --       279	.ackPacket: ackPacket-D	; Where Ack packet is built
      --   246--712B, --       280	.DoEtherOutput: DoEtherOutput-D
      --   247--634B, --       281	.ReceiveEFTPPacket: ReceiveEFTPPacket-D
      --   250--735B, --       282	.ContinueBoot: ContinueBoot-D
      --   251--611B, --       283	.maxLength: maxLength-D
      --   252--567B, --       284	.goodDestSource: goodDestSource-D
      --   253--564B, --       285	.errcnt: errcnt-D
      --   254--566B, --       286	.seqNum: seqNum-D
      --   255--36B, --       287	retries: 30.		; Max number of broadcast retries

      --                           288	
      --                           289	; Page 1 portion of boot program
      --                           290	
      --                           291	page1image:
      --                           292	
      --                           293	
      --                           294	; Assemble variables and constants here so they can be reached
      --                           295	; from the page 0 code also.
      --                           296	
      --                           297	
      --                           298	; Constants
      --   256--2B, --       299	c2:	2
      --   257--3B, --       300	c3:	3
      --   260--15B, --       301	d13:	13.
      --   261--30B, --       302	c30:	30		; typeEFTPData
      --   262--377B, --       303	c377:	377
      --   263--1000B, --       304	c1000:	1000
      --   264--177764B, --       305	md12:	-12.
      --                           306	
      --          177432           307	D = page1image-page1origin	; Load - runtime displacement
      --                           308	; Note -
      --                           309	; To generate a page 1 pc-relative address for absolute address "X"
      --                           310	;  write "X+D".
      --                           311	; To generate an absolute (runtime) page 1 address for label "X"
      --                           312	;  write "X-D".
      --                           313	
      --                           314	; Ethernet control words addresses, for referencing relative
      --                           315	; to the page 1 portion of the boot loader.
      --             232           316	rEPLoc = ePLoc+D
      --             233           317	rEBLoc = eBLoc+D
      --             234           318	rEELoc = eELoc+D
      --             235           319	rELLoc = eLLoc+D
      --             236           320	rEICLoc = eICLoc+D
      --             237           321	rEIPLoc = eIPLoc+D
      --             240           322	rEOCLoc = eOCLoc+D
      --             241           323	rEOPLoc = eOPLoc+D
      --             242           324	rEHLoc = eHLoc+D
      --                           325	
      --                           326	; Random page 1 words we use as temporaries.
      --                           327	; All are assumed to be initialized to zero.
      --                           328	
      --                           329	; 400-414 are used for scratch
      --                           330	
      --              63           331	ackPacket = 431+D	; 13. words in which Ack packet is built.
      --                           332				; This is the cursor bitmap!
      --             216           333	errcnt = 564+D		; Output error countdown
      --             217           334	recret = 565+D		; Return from ReceiveEFTPPacket
      --             220           335	seqNum = 566+D		; Current EFTP sequence number
      --             221           336	goodDestSource = 567+D	; Ethernet address of me/partner
      --             243           337	maxLength = 611+D	; Max input packet length (269 or 12)
      --             244           338	dallyTimeout = 612+D	; Timeout for end dally if nonzero
      --             245           339	endFlag = 613+D		; Zero if packet was Data, nonzero if End
      --                           340	
      --                           341	
      --   265--436B,
      --       342	.ackID1: ackPacket-D+pupID+1  ; Pointer to Ack's sequence number

      --                           343	
      --                           344	; Page 1 portion of boot loader (cont'd)
      --                           345	; Subroutines called from both page 0 and page 1
      --                           346	
      --                           347	; Receive EFTP packet
      --                           348	;	2/ where to put it in memory
      --                           349	; Ac2 is unchanged upon return.
      --                           350	; endFlag will be zero if a Data was received, nonzero if End.
      --                           351	; If dallyTimeout is nonzero, it will be counted down and the
      --                           352	; routine will return if it reaches zero.
      --                           353	
      --                           354	ReceiveEFTPPacket:
      --   266--54731B, --       355		sta 3 recret		; Save return
      --   267--50750B, --       356		sta 2 rEIPLoc		; Set input pointer
      --                           357	
      --                           358	; Await a new packet
      --   270--20753B, --       359	rec1:	lda 0 maxLength		; Set count
      --   271--40745B, --       360		sta 0 rEICLoc
      --   272--102460B, --       361		mkzero 0 0		; Zero post location
      --   273--40737B, --       362		sta 0 rEPLoc
      --   274--20762B, --       363		lda 0 c2		; etherInputCommand = 2
      --   275--61004B, --       364		sio			; Fire up receiver
      --   276--20734B,
      --       365	rec1a:	lda 0 rEPLoc		; Wait for something to happen
      --   277--105304B, --       366		movs 0 1 szr
      --   300--406B, --       367		 jmp rec1b		; Something happened, check it
      --   301--20743B,
      --       368		lda 0 dallyTimeout	; No activity yet, check timeout
      --   302--101014B, --       369		sz 0 0
      --   303--14741B,
      --       370		 dsz dallyTimeout	; One is set, count it down
      --   304--772B, --       371		  jmp rec1a		; Not set or not yet timed out
      --   305--2712B, --       372		jmp @recret		; Timed out, return now
      --                           373	
      --                           374	; A packet has arrived.  Accept if good input or buffer overrun.
      --                           375	; This code is a bit mysterious because the way it works is to
      --                           376	; set ac1 = 1000 iff the status is acceptable.  This then gets
      --                           377	; compared with the incoming Ethernet type which should be 1000.
      --   306--34754B, --       378	rec1b:	lda 3 c377
      --   307--167700B, --       379		ands 3 1		; Ac1 ← 1000 iff post code = 2
      --   310--116415B, --       380		sne 0 3			; Good normal input done status?
      --   311--24752B,
      --       381		 lda 1 c1000		; Yes, make it look like post 2
      --                           382	
      --                           383	; Ensure that it is an EFTP Data or End from the correct partner
      --   312--21001B, --       384		lda 0 etherType 2	; Get ethernet type word
      --   313--106414B, --       385		se 0 1			; Is it a Pup? (1000)
      --   314--754B, --       386		 jmp rec1		; No, ignore
      --   315--21000B,
      --       387		lda 0 etherAdr 2	; Get destination/source word
      --   316--24703B, --       388		lda 1 goodDestSource	; Correct partner?
      --   317--106414B, --       389		se 0 1
      --   320--750B, --       390		 jmp rec1		; No, ignore (should really abort)
      --   321--21003B, --       391		lda 0 pupType 2		; Get Pup type
      --   322--163400B, --       392		and 3 0
      --   323--24736B, --       393		lda 1 c30		; Switch on it
      --   324--106405B, --       394		sub 0 1 snr
      --   325--404B, --       395		 jmp rec3		; Got Data packet
      --   326--121400B, --       396		inc 1 0
      --   327--101404B, --       397		inc 0 0 szr		; Skip if End
      --   330--740B, --       398		 jmp rec1		; Neither Data nor End, ignore
      --   331--44714B,
      --       399	rec3:	sta 1 endFlag		; Set nonzero if this is an End
      --                           400	
      --                           401	; Got an EFTP Data or end packet.
      --                           402	; Now check sequence number and send Ack
      --   332--21005B,
      --       403		lda 0 pupID+1 2		; Get packet sequence number
      --   333--42732B, --       404		sta 0 @.ackID1		; Set it for possible Ack
      --   334--24664B, --       405		lda 1 seqNum		; Get expected sequence number
      --   335--122405B, --       406		sub 1 0 snr		; Is it the right one?
      --   336--404B, --       407		 jmp rec4		; Yes
      --   337--101405B,
      --       408		inc 0 0 snr		; No, retransmission of last one?
      --   340--4404B, --       409		 jsr DoEtherOutput	; Yes, ack it
      --   341--727B, --       410		jmp rec1		; Ignore it and look for next
      --                           411	
      --                           412	; Here when got a new packet
      --   342--10656B, --       413	rec4:	isz seqNum		; Advance sequence number
      --   343--34654B, --       414		lda 3 recret		; Restore return pc
      --                           415					; Fall into DoEtherOutput

      --                           416	
      --                           417	; Page 1 portion of boot loader (cont'd)
      --                           418	
      --                           419	; Do Ethernet output
      --                           420	; Assumes the packet and eOPLoc and eOCLoc are set up
      --                           421	; Does not clobber ac2
      --                           422	
      --                           423	DoEtherOutput:
      --   344--24403B, --       424		lda 1 k777
      --   345--120500B, --       425		negl 1 0		; Delay about 2 ms to ensure that
      --   346--101404B, --       426		inc 0 0 szr		;  our ack is heard
      --   347--777B, --       427	k777:	 777			; (Otherwise known as "jmp .-1")
      --   350--40662B, --       428		sta 0 rEPLoc		; Zero post location
      --   351--40664B, --       429		sta 0 rELLoc		; Zero load location
      --   352--40664B, --       430		sta 0 rEICLoc		; Zero input count location
      --   353--102520B, --       431		mkone 0 0		; etherOutputCommand = 1
      --   354--61004B, --       432		sio			; Start output
      --   355--20655B, --       433		lda 0 rEPLoc		; Wait for something to happen
      --   356--101015B, --       434		snz 0 0
      --   357--776B, --       435		 jmp .-2
      --   360--106415B, --       436		sne 0 1			; Good output done? ( = 777)
      --   361--1400B, --       437		 jmp 0 3		; Yes, done, return
      --   362--14634B, --       438		dsz errcnt		; No, check error counter
      --   363--761B, --       439		 jmp DoEtherOutput	; Retry
      --                           440	
      --                           441	; If we get too many errors, probably the Ethernet interface
      --                           442	; is broken, so we should reset and give up lest we pollute
      --                           443	; the Ethernet indefinitely
      --   364--20673B, --       444	Bomb:	lda 0 c3		; etherResetCommand
      --   365--61004B, --       445		sio
      --   366--400B, --       446	c400:	400			; (Otherwise known as "jmp .")

      --                           447	
      --                           448	; ** Main page 1 program **
      --                           449	; Control resumes here when the page 0 code is finished.
      --                           450	; When we get here, the second data packet of the transfer has
      --                           451	; been received (the one destined for page 0) and now resides
      --                           452	; in page 2, and the ac's are set up such that blt will move
      --                           453	; the data to page 0.  This code's responsibility is to receive
      --                           454	; the remaining pages of the transfer and store them starting at
      --                           455	; page 2.  The following variables are already set up:
      --                           456	;	goodDestSource	expected Ethernet dest/source word
      --                           457	;	seqNum		the next expected EFTP sequence number (2)
      --                           458	;	ac2		points to place to store next packet
      --                           459	;			(1000 minus the offset pupContents)
      --                           460	; Also, an Ack packet has already been built at ackPacket.
      --                           461	
      --                           462	ContinueBoot:
      --   367--61005B, --       463		blt			; Copy data to page 0
      --                           464	
      --                           465	; The main loop of the EFTP boot load sequence.
      --                           466	; First, save away the stuff at the end of the previous page
      --                           467	; that will get clobbered by the new Pup's header.
      --                           468	; Locations 400-413 are used for scratch.
      --   370--102000B,
      --       469	bootlp:	mkminusone 0 0		; Compute first source adr -1
      --   371--143000B, --       470		add 2 0
      --   372--34672B, --       471		lda 3 md12		; -12. (number of words)
      --   373--24667B,
      --       472		lda 1 c377		; Compute pointer to last word of
      --   374--166400B, --       473		sub 3 1			;  save area
      --   375--61005B, --       474		blt			; Save the data
      --                           475	
      --                           476	; Now receive the next Data (or End) packet
      --   376--4670B, --       477		jsr ReceiveEFTPPacket
      --                           478	
      --                           479	; Now restore the clobbered region
      --   377--20663B,
      --       480		lda 0 c377		; Pointer to start of save area -1
      --   400--34664B, --       481		lda 3 md12		; -12. (number of words)
      --   401--164000B, --       482		com 3 1			; Compute pointer to last word of
      --   402--147000B, --       483		add 2 1			;  clobbered region
      --   403--61005B, --       484		blt			; Move the data back
      --                           485	
      --                           486	; Unless memory is now full, advance the pointer and repeat.
      --                           487	; If we just read into the last page of memory, set the pointer to
      --                           488	; a scratch region at 400 and set the count so that only a minimum-
      --                           489	; length Pup (e.g., the End that we are expecting) will be
      --                           490	; accepted.
      --   404--24762B, --       491		lda 1 c400		; Amount to advance pointer by
      --   405--132414B,
      --       492		se 1 2			; Skip if already at scratch region
      --   406--133000B, --       493		 add 1 2		; Normally, advance pointer
      --   407--20636B, --       494		lda 0 endFlag
      --   410--34416B, --       495		lda 3 memOverflow
      --   411--101015B, --       496		snz 0 0			; Was an End received?
      --   412--156415B, --       497		sne 2 3			; Or beyond end of memory?
      --   413--131001B, --       498		 mov 1 2 skp		; Yes, set pointer to 400
      --   414--754B, --       499		 jmp bootlp		; No, continue normally
      --   415--24643B, --       500		lda 1 d13		; Limit packet length to minimum
      --   416--44625B, --       501		sta 1 maxLength
      --   417--101015B, --       502		snz 0 0			; Received End?
      --   420--750B, --       503		 jmp bootlp		; No, continue
      --   421--14623B,
      --       504		dsz dallyTimeout	; Yes, enable timeout (set to -1)
      --   422--4644B,
      --       505		jsr ReceiveEFTPPacket	; Await second End or timeout
      --   423--20634B, --       506		lda 0 c3		; Reset the Ethernet
      --   424--61004B, --       507		sio
      --   425--2000B, --       508		jmp @0			; Jump into the bootload!
      --                           509	
      --   426--176764B
      --       510	memOverflow: 177000-12.  ; Where ac2 will point when memory is full
      --                           511	
      --                           512	
      --                           513	; ** Warning **
      --                           514	; The last 12 words of page 1 get clobbered during the act of
      --                           515	; receiving page 2.  This is ok since those 12 words are saved
      --                           516	; and restored.  However, the stuff in those words must not be
      --                           517	; executed or referenced while in the clobbered state!
      --                           518	
      --                           519		.end
      ];


  END..