-- 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..