//AltIOPup.bcpl -- AltIO linkage to Pup package // Last modified March 14, 1981 3:39 PM get "altio.decl" get "pup0.decl" get "pupaleth.decl" external [ //outgoing procedures PupReset; NBReadWord; NBWriteWord; NBBlockTransfer; ConvertNBP //incoming procedures InitializeContext; Block Enqueue; Dequeue; Unqueue; Min MemReadRelative; MemWriteRelative; RMWBitAbsolute; SignalMaxc MemReadBlock32A; MemWriteBlock32A; DisplaceMaxcAdr MoveBlock; CallSwat //outgoing statics pupCtx; lenPupCtx; pupInputRequest; pupOutputRequest pbiIQ; pbiFreeQ; lenPup; lenPBI; ndbQ; etherNDB //incoming statics ctxQ; impNDB ] static [ pupInputRequest; pupOutputRequest pbiIQ; pbiFreeQ; lenPup; lenPBI; ndbQ; etherNDB pupCtx lenPupCtx = 150 ] // --------------------------------------------------------------------------- let PupReset() be // --------------------------------------------------------------------------- // Called to reinitialize the Pup context when an i/o reset is done [ Unqueue(ctxQ, pupCtx) //no-op if this is the first time Enqueue(ctxQ, InitializeContext(pupCtx, lenPupCtx, PupProcess)) pupInputRequest = false pupOutputRequest = false ] // --------------------------------------------------------------------------- and PupProcess() be // --------------------------------------------------------------------------- // Process that handles Pup input and output for Maxc [ until pupInputRequest do [ //after i/o reset and before Maxc first requests input, //just discard all packets that are received while pbiIQ!0 ne 0 do Enqueue(pbiFreeQ, Dequeue(pbiIQ)) Block() ] let maxcNBP = vec 2 let nbp = vec lenNBP let pbphys = vec 2 // PupProcess (cont'd) // The main loop of the process [ Block() if pupInputRequest & pbiIQ!0 ne 0 then [ // Ready to hand received Pup to Maxc pupInputRequest = false // Read the NBP from XPUPIB and see if Maxc is really ready MemReadRelative(xPUPIB, maxcNBP) unless ConvertNBP(maxcNBP, nbp) loop // Get the Pup and compute PBPHYS word. // This is conceptually different for Ethernet and Arpanet Pups, // but it just so happens that the length of the encapsulation and // the position of the source host address are the same for both! (yuk) let pbi = Dequeue(pbiIQ) pbphys>>PBPHYS.words = (pbi>>PBI.pup.length+3) rshift 2 pbphys>>PBPHYS.net = pbi>>PBI.ndb>>NDB.localNet pbphys>>PBPHYS.host = pbi>>EtherPBI.src // Copy the Pup and the PBPHYS word into the Maxc buffer NBWriteBlock32(nbp, xPBHEAD, lv pbi>>PBI.pup, pbphys>>PBPHYS.words) NBWriteWord(nbp, xPBPHYS, pbphys) Enqueue(pbiFreeQ, pbi) // Signal Maxc that we have given it a Pup MemWriteRelative(xPUPIB, maxcNBP) //set use flag RMWBitAbsolute(aNVMAX, nmPUPIDN) SignalMaxc() ] if pupOutputRequest & pbiFreeQ!0 ne 0 then [ // Ready to get Pup from Maxc and send it pupOutputRequest = false // Read the NBP from XPUPOB and see if Maxc is really ready MemReadRelative(xPUPOB, maxcNBP) unless ConvertNBP(maxcNBP, nbp) loop // Copy the PBPHYS word and the Pup from the Maxc buffer let pbi = Dequeue(pbiFreeQ) if pbi eq 0 then [ pupOutputRequest = true; loop ] NBReadWord(nbp, xPBPHYS, pbphys) if pbphys>>PBPHYS.words lshift 1 gr lenPup then CallSwat("Maxc Pup too large") NBReadBlock32(nbp, xPBHEAD, lv pbi>>PBI.pup, pbphys>>PBPHYS.words) // Queue packet for transmission on appropriate network. // Note that the Ether and Arpa net numbers are wired in. (yuk) let ndb = selecton pbphys>>PBPHYS.net into [ case netEther: etherNDB case netArpa: impNDB default: CallSwat("Maxc sent Pup to unknown net") ] pbi>>PBI.ndb = ndb (ndb>>NDB.encapsulatePup)(pbi, pbphys>>PBPHYS.host) pbi>>PBI.queue = pbiFreeQ (ndb>>NDB.level0Transmit)(pbi) // Signal Maxc that we have taken the Pup MemWriteRelative(xPUPOB, maxcNBP) //set use flag RMWBitAbsolute(aNVMAX, nmPUPODN) SignalMaxc() ] ] repeat ] // Flavors of Maxc memory operations that perform the necessary // remap when a page boundary is crossed. // --------------------------------------------------------------------------- and NBReadWord(nbp, disp, maxcData) = // --------------------------------------------------------------------------- // Performs a one-word read whose Maxc address is // disp relative to the address denoted by nbp, and whose // Alto address is maxcData. disp ls nbp>>NBP.count1? MemReadRelative(disp, maxcData, lv nbp>>NBP.adr1), MemReadRelative(disp-nbp>>NBP.count1, maxcData, lv nbp>>NBP.adr2) // --------------------------------------------------------------------------- and NBWriteWord(nbp, disp, maxcData) = // --------------------------------------------------------------------------- // Performs a one-word write whose Maxc address is // disp relative to the address denoted by nbp, and whose // Alto address is maxcData. disp ls nbp>>NBP.count1? MemWriteRelative(disp, maxcData, lv nbp>>NBP.adr1), MemWriteRelative(disp-nbp>>NBP.count1, maxcData, lv nbp>>NBP.adr2) // --------------------------------------------------------------------------- and NBReadBlock32(nbp, disp, maxcData, count) = // --------------------------------------------------------------------------- NBBlockTransfer(MemReadBlock32A, nbp, disp, maxcData, count, 2) // --------------------------------------------------------------------------- and NBWriteBlock32(nbp, disp, maxcData, count) = // --------------------------------------------------------------------------- NBBlockTransfer(MemWriteBlock32A, nbp, disp, maxcData, count, 2) // --------------------------------------------------------------------------- and NBBlockTransfer(Operation, nbp, disp, maxcData, count, inc) = valof // --------------------------------------------------------------------------- // Performs the specified Maxc block operation Op. The Maxc address // of the start of the block is disp relative to nbp, and the // Alto address of the block is maxcData. count is the number of // Maxc words to transfer and inc is the Alto address increment for // each Maxc word. [ let maxcAdr = vec 1 test disp ls nbp>>NBP.count1 ifso DisplaceMaxcAdr(disp, maxcAdr, lv nbp>>NBP.adr1) ifnot DisplaceMaxcAdr(disp-nbp>>NBP.count1, maxcAdr, lv nbp>>NBP.adr2) let code = nil while count ne 0 do [ let remWords1 = nbp>>NBP.count1-disp let c = Min(count, maxBlt) if remWords1 gr 0 then c = Min(c, remWords1) if remWords1 eq 0 then MoveBlock(maxcAdr, lv nbp>>NBP.adr2, 2) code = Operation(maxcAdr, maxcData, c) if code ne 0 then break maxcData = maxcData+c*inc disp = disp+c count = count-c // If we stopped because of the maxBlt limit, give other contexts // a chance to run. if c eq maxBlt then Block() ] resultis code ] // --------------------------------------------------------------------------- and ConvertNBP(maxcWord, nbp) = valof // --------------------------------------------------------------------------- // Converts a Net Buffer Pointer read from Maxc in maxcWord // into an NBP structure. The Net Buffer Pointer read from Maxc // is in the following form (see Maxc document 11): // B0 use flag // B1-2 zero // B3-14 second physical page number, if block crosses // page boundary; zero otherwise // B15-26 first physical page number // B27-35 location in page of start of block // The use flag (B0) of the Maxc word is set to one in preparation // for writing it back to Maxc as a completion signal. // Returns true if the buffer is ready for AltIO to act on it, // i.e., the use flag is zero and the whole word is nonzero. [ if maxcWord!1 eq 0 % (maxcWord!0 & #100000) ne 0 resultis false nbp>>NBP.adr1↑0 = maxcWord!1 nbp>>NBP.adr1↑1 = maxcWord!2 nbp>>NBP.count1 = #1000 - ((maxcWord!1 lshift 4 + maxcWord!2 rshift 12)& #777) nbp>>NBP.adr2↑0 = (maxcWord!0 & #17776) lshift 4 nbp>>NBP.adr2↑1 = 0 maxcWord!0 = maxcWord!0 % #100000 resultis true ]