// PupSubrs.bcpl. The Interlisp-D Pup package // Last change July 20, 1983 2:53 PM by Bill van Melle // Last change June 7, 1983 12:15 PM by Bill van Melle // Last change March 14, 1983 5:27 PM by Bill van Melle // Last change February 11, 1983 11:39 AM by Bill van Melle // Last change August 9, 1982 9:29 PM by Bill van Melle // Raw packet addition May 19, 1982 2:34 PM by Bill van Melle // This file contains Pup subrs called from Lisp. It also has the entry // which starts up the pup package and enqueue its contexts onto ContextQ get "LispBcpl.decl" get "Pup0.decl" get "Pup1.decl" get "PupAlEth.decl" external [ // procedures defined GETPACKETBUFFER READRAWPBI WRITERAWPBI PUPLEVEL1STATE XMoveWords // dumb MoveWords DeImplementedSubr StartPup // called from init only // Lisp procedures used EqNIL; @XGetBase; IPutBase; Serial EmAddr; EmUnbox; RAIDCode @XSetReadBR; @XSetWriteBR; @RRead; @RWrite // Lisp statics used @ContextQ; @lvNIL; @lvKT // OS Procedures Enqueue; Dequeue; Block; Min; CallSwat; TruePredicate InitializeZone; Allocate; Free; Zero; InitializeContext DisableInterrupts; EnableInterrupts; CauseInterrupt TimerHasExpired; StartIO // pup level 1 functions OpenLevel1Socket; InitPupLevel1 CloseLevel1Socket; ReleasePBI // pup level 0 functions SendEtherPacket // pup package statics socketQ; lenPBI; lenPup; maxPupDataBytes pbiFreeQ; ndbQ; pbiTQ; pbiIQ ] manifest [ psRoutingInfo = 2 ] static [ HaveEther = false // true if Ethernet alive on machine PupZone // zone for pup allocations XtraQ // queue of "extra" output PBIs XUses = 0 // how many xtras have been used numPBIs // how many pbi's we allocated // stuff for raw packet pupRawState = true // true if not running pup level 1 rawPbiIQ // input queue of raw packets localNDB // ndb for local net ] structure Queue: [ head word tail word ] static [ lastPBI = 0 ] let DeImplementedSubr() = RAIDCode("Subr not implemented", lvNIL) and StartPup(zone, zoneLength) be [ test Serial() ls #377 ifso [ PupZone = InitializeZone(zone, zoneLength, PupOutOfSpace) numPBIs = 20 let maxbytes = 568 // longer for NS packets: 546 data bytes plus a header that is 6 words longer, // plus encapsulation that is 5 words longer InitPupLevel1(PupZone, ContextQ, numPBIs, maxbytes) let s = socketQ [ s = s>>PupSoc.link if s>>PupSoc.lclPort.socket↑1 eq 0 & s>>PupSoc.lclPort.socket↑2 eq psRoutingInfo then [ // knock router's allocation in half or so to // avoid getting clogged when Bcpl runs little let half = (s>>PupSoc.numIPBI rshift 1)+(s>>PupSoc.numIPBI rshift 2) s>>PupSoc.iAll = s>>PupSoc.iAll - (half lshift 8 + half) break ] ] repeatwhile s XtraQ = Allocate(PupZone, 2) Zero(XtraQ, 2) // extra output pbis for i = 1 to 3 do Enqueue(XtraQ, Allocate(PupZone, lenPBI)) HaveEther = true StartRawPup() ] ifnot [ // no ether, give this to Lisp HaveEther = false IPutBase(IFPMDSZone, zone) IPutBase(IFPMDSZoneLength, zoneLength) ] ] and PupOutOfSpace() be [ RAIDCode("Pup level 1 out of space. Probably too many sockets open", lvNIL) ] repeat and StartRawPup() = valof [ localNDB = ndbQ>>Queue.head // assume only one if ndbQ>>Queue.tail ne localNDB then CallSwat ("More than one NDB") rawPbiIQ = Allocate(PupZone, 2+lenPF) // queue to stash input on Zero(rawPbiIQ, 2) // initially empty let rawPF = rawPbiIQ+2 rawPF>>PF.predicate = TruePredicate rawPF>>PF.queue = rawPbiIQ Enqueue(lv localNDB>>NDB.pfQ, rawPF) // add a filter for non-pups (lv localNDB>>NDB.pupPF)>>PF.queue = rawPbiIQ pupRawState = true resultis lvNIL ] and XMoveWords(src, dst, n) be [ // Move n words between two virtual addresses XSetReadBR(src) XSetWriteBR(dst) for i = 0 to n-1 do RWrite(i, RRead(i)) ] and GETPACKETBUFFER() = valof [ unless HaveEther do resultis lvNIL if lastPBI then [ ReleasePBI(lastPBI); lastPBI = 0 ] let pb = Dequeue(pbiFreeQ) test pb ifso [ Zero(pb, lenPBIOverhead) pb>>PBI.queue = pbiFreeQ ] ifnot [ pb = Dequeue(XtraQ) test pb ifso [ Zero(pb, lenPBIOverhead) // clear header pb>>PBI.queue = XtraQ // so it comes back XUses = XUses + 1 // count it ] ifnot [ // (2) if the interface is transmitting and has timed out, reset it // and fake a load overflow indication to unhang the software. if localNDB>>EtherNDB.eOB ne 0 & TimerHasExpired(lv localNDB>>EtherNDB.tTimer) then UnWedgeEther() resultis lvNIL ] ] pb>>PBI.socket = 0 // charge to no socket lastPBI = pb resultis EmAddr(pb) ] and UnWedgeEther() be [ DisableInterrupts() StartIO(localNDB>>EtherNDB.resetCmd) // causes pending interrupt @(localNDB>>EtherNDB.ePLoc) = 3 lshift 8 // fake a load overflow EnableInterrupts() ] and WRITERAWPBI (pbi) = valof [ unless HaveEther do resultis lvNIL let pb = EmUnbox(pbi) if lastPBI then [ if pb ne lastPBI then ReleasePBI(lastPBI) lastPBI = 0 ] pb>>PBI.socket = 0 // no socket associated pb>>PBI.ndb = localNDB pb>>PBI.status = 0 SendEtherPacket (pb) resultis pbi ] and READRAWPBI () = valof [ unless HaveEther do resultis lvNIL if lastPBI then [ ReleasePBI(lastPBI); lastPBI = 0 ] let pbi = Dequeue (rawPbiIQ) // get pbi from input q if pbi eq 0 then [ // nothing has arrived. Make sure interface not dead if localNDB>>EtherNDB.eState eq 0 & pbiFreeQ!0 ne 0 then [ @(localNDB>>EtherNDB.ePLoc) = 0 CauseInterrupt(localNDB>>EtherNDB.mask) ] resultis lvNIL ] pbi>>PBI.queue = pbiFreeQ pbi>>PBI.socket = 0 lastPBI = pbi resultis EmAddr(pbi) ] and PUPLEVEL1STATE(flg) = valof [ unless EqNIL(flg) do DeImplementedSubr() (lv localNDB>>NDB.pupPF)>>PF.queue = rawPbiIQ pupRawState = true resultis lvNIL ]