// PupSubrs.bcpl. The Interlisp-D Pup package
// Last change October 11, 1983 3:58 PM by Bill van Melle
// 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
InitPupLevel0
// pup level 0 functions
SendEtherPacket
// pup package statics
socketQ; lenPBI; lenPup; maxPupDataBytes
pbiFreeQ; ndbQ; pbiTQ; pbiIQ
]
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
InitPupLevel0(PupZone, ContextQ, numPBIs, maxbytes)
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 [ RelPBI(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 RelPBI(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 [ RelPBI(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
]
and RelPBI(pbi) be
[
Enqueue(pbiFreeQ, pbi)
]