<> <> <> <> DIRECTORY Basics USING [bytesPerWord, LongMult, LongDiv], BufferDefs USING [OisBuffer], Checksums USING [ComputeChecksum], CommunicationInternal USING [], CommUtilDefs USING [], DriverDefs USING [GetInputBuffer, ReturnFreeBuffer], DriverTypes USING [Encapsulation], EthernetFace USING [ControlBlock, DeviceHandle, GlobalStatePtr, globalStateSize, GetNextDevice, GetPacketLength, GetStatus, nullDeviceHandle, QueueInput, QueueOutput, TurnOff, TurnOn], EthernetOneFace USING [DeviceHandle, GetEthernet1Address, GetNextDevice, nullDeviceHandle], MPCodes USING [findPupAddress, emptyMP], NSAddress USING [broadcastHostNumber, HostNumber, nullNetworkNumber, NetworkAddress, ProcessorID, SocketNumber], OISCPTypes USING [bytesPerPktHeader, PacketType, BufferBody], PrincOpsUtils USING [Copy, LongCopy, LowHalf], Process USING [MsecToTicks, SecondsToTicks, Ticks], ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses, processorID, SetMP], PupDefs USING [], --EXPORTS Time Conversion stuff PupStream USING [Tocks], --EXPORTS Time Conversion stuff PupTypes USING [PupAddress, PupHostID], VM USING [AddressForPageNumber, Allocate, Free, Interval, lowCore, PageNumberForAddress, PagesForWords, Pin]; PilotCommUtil: MONITOR IMPORTS Checksums, DriverDefs, EthernetFace, EthernetOneFace, PrincOpsUtils, Process, ProcessorFace, VM EXPORTS CommunicationInternal, CommUtilDefs, DriverDefs, PupDefs, PupStream SHARES BufferDefs = { <> MixedIocbSize: ERROR = CODE; <> iocbSize: CARDINAL _ 0; IocbType: TYPE = RECORD[ next: LONG POINTER TO IocbType, rest: SEQUENCE COMPUTED CARDINAL OF WORD]; freeIocb: LONG POINTER TO IocbType _ NIL; AllocateIocb: PUBLIC ENTRY PROC [nwords: CARDINAL] RETURNS [i: LONG POINTER] = { IF iocbSize = 0 THEN iocbSize _ nwords; IF iocbSize # nwords THEN Glitch[MixedIocbSize]; IF freeIocb # NIL THEN { i _ freeIocb; freeIocb _ freeIocb.next } ELSE i _ VM.lowCore.NEW[IocbType[iocbSize-SIZE[IocbType[0]]]]; }; FreeIocb: PUBLIC ENTRY PROC [iocbPtr: LONG POINTER] = { i: LONG POINTER TO IocbType = LOOPHOLE[iocbPtr]; i.next _ freeIocb; freeIocb _ i; }; <> AllocateBuffers: PUBLIC PROC [nwords: CARDINAL] RETURNS [base: LONG POINTER] = { interval: VM.Interval = VM.Allocate[VM.PagesForWords[nwords]]; VM.Pin[interval]; base _ VM.AddressForPageNumber[interval.page]; }; FreeBuffers: PUBLIC PROC [base: LONG POINTER, nwords: CARDINAL] = { VM.Free[[page: VM.PageNumberForAddress[base], count: VM.PagesForWords[nwords]]]; }; <> Zero: PUBLIC PROC [p: POINTER, l: CARDINAL] = { IF l = 0 THEN RETURN; p^ _ 0; PrincOpsUtils.Copy[from: p, to: p + 1, nwords: l - 1]; }; <> <> <> <> <> TockConversionTroubles: PUBLIC ERROR = CODE; SecondsToTocks: PUBLIC SAFE PROC [t: CARDINAL] RETURNS [PupStream.Tocks] = CHECKED { tks: Process.Ticks = Process.SecondsToTicks[t]; IF tks = LAST[Process.Ticks] THEN ERROR TockConversionTroubles; RETURN[[tks]]; }; <> MsToTocks: PUBLIC SAFE PROC [t: CARDINAL] RETURNS [PupStream.Tocks] = CHECKED { IF t = 0 THEN ERROR TockConversionTroubles; RETURN[[Process.MsecToTicks[t]]]; }; <> errorHandler: PROC [ERROR] _ DefaultErrorHandler; CaptureErrors: PUBLIC PROC [proc: PROC [ERROR]] = {errorHandler _ proc}; DefaultErrorHandler: PROC [why: ERROR] = { SIGNAL LOOPHOLE[why, SIGNAL] }; Glitch: PUBLIC PROC [why: ERROR] = {DO errorHandler[why] ENDLOOP}; FriendOfCopyLong: PUBLIC PROC [from: LONG POINTER, nwords: CARDINAL, to: LONG POINTER] = { PrincOpsUtils.LongCopy[from, nwords, to]; }; myHostNumber: CARDINAL _ 0; SmashMyHostNumber: PUBLIC ENTRY PROC [new: CARDINAL] = { myHostNumber _ new; }; GetEthernetHostNumber: PUBLIC ENTRY PROC RETURNS [CARDINAL] = { ether: EthernetOneFace.DeviceHandle; IF myHostNumber#0 THEN RETURN[myHostNumber]; -- easy known case <> ether _ EthernetOneFace.GetNextDevice[EthernetOneFace.nullDeviceHandle]; IF ether#EthernetOneFace.nullDeviceHandle THEN { net, host: [0..256); [net, host] _ EthernetOneFace.GetEthernet1Address[ether]; RETURN[myHostNumber _ host]; }; <> ProcessorFace.SetMP[MPCodes.findPupAddress]; myHostNumber _ GetPupHostNumber[]; ProcessorFace.SetMP[MPCodes.emptyMP]; RETURN[myHostNumber]; }; <> global: EthernetFace.GlobalStatePtr _ LOOPHOLE[LONG[NIL]]; wordsPerPupHeader: CARDINAL = 11; -- includes checksum, not encapsulaton bytesPerPupHeader: CARDINAL = wordsPerPupHeader*2; translationRequest: CARDINAL = 1; translationResponse: CARDINAL = 2; GetPupHostNumber: PROC RETURNS [host: PupTypes.PupHostID] = { oisBuf: BufferDefs.OisBuffer _ LOOPHOLE[DriverDefs.GetInputBuffer[]]; Request: TYPE = MACHINE DEPENDENT RECORD [ id0, id1: CARDINAL, arg: WORD, who: NSAddress.ProcessorID]; request: LONG POINTER TO Request = LOOPHOLE[@oisBuf.ois.oisWords[0]]; Reply: TYPE = MACHINE DEPENDENT RECORD [ id0, id1: CARDINAL, arg: WORD, answer: PupTypes.PupAddress]; reply: LONG POINTER TO Reply = LOOPHOLE[@oisBuf.ois.oisWords[0]]; pulsesPerSec: LONG CARDINAL _ Basics.LongMult[1000, Basics.LongDiv[100000, ProcessorFace.microsecondsPerHundredPulses]+1]; <> timeoutPulses: LONG CARDINAL _ 0; i: CARDINAL _ 1; mySocket: NSAddress.SocketNumber _ LOOPHOLE[PrincOpsUtils.LowHalf[LOOPHOLE[ProcessorFace.GetClockPulses[]]]]; <> pupAddressTranslation: NSAddress.SocketNumber _ LOOPHOLE[9]; pupAddrTransPacket: OISCPTypes.PacketType _ LOOPHOLE[6]; minWordsPerEthernetPacket: CARDINAL = (64/2)-2; --*** Should move to DriverTypes myID: NSAddress.ProcessorID _ LOOPHOLE[ProcessorFace.processorID]; ether: EthernetFace.DeviceHandle _ EthernetFace.GetNextDevice[EthernetFace.nullDeviceHandle]; IF ether = EthernetFace.nullDeviceHandle THEN ERROR No10MBDriverAndNo3MBDriver; THROUGH [0..15] DO timeoutPulses _ timeoutPulses + pulsesPerSec; ENDLOOP; <> DO startPulses: LONG CARDINAL = ProcessorFace.GetClockPulses[]; EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, LOOPHOLE[myID], 0, 0, global]; i _ i + 1; request^ _ [i, i, translationRequest, myID]; oisBuf.encapsulation.ethernetDest _ NSAddress.broadcastHostNumber; oisBuf.encapsulation.ethernetType _ ois; oisBuf.ois.pktLength _ OISCPTypes.bytesPerPktHeader + SIZE[Request, Basics.bytesPerWord]; oisBuf.ois.transCntlAndPktTp _ [[FALSE, 0, 0], pupAddrTransPacket]; oisBuf.ois.source _ [ net: NSAddress.nullNetworkNumber, host: myID, socket: mySocket]; oisBuf.ois.destination _ [ net: NSAddress.nullNetworkNumber, host: NSAddress.broadcastHostNumber, socket: pupAddressTranslation]; SetOisChecksum[oisBuf]; oisBuf.encapsulation.ethernetSource _ myID; EthernetFace.QueueOutput[ ether, @oisBuf.encapsulation, MAX[SIZE[DriverTypes.Encapsulation]+WdsPerEthernetPacket[oisBuf.ois.pktLength], minWordsPerEthernetPacket], oisBuf.iocbChain]; WHILE (ProcessorFace.GetClockPulses[] - startPulses) <= timeoutPulses DO IF EthernetFace.GetStatus[oisBuf.iocbChain]#pending THEN EXIT; REPEAT FINISHED => { EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, LOOPHOLE[myID], 0, 0, global]; }; ENDLOOP; WHILE (ProcessorFace.GetClockPulses[] - startPulses) <= timeoutPulses DO oisBuf.encapsulation.ethernetType _ LOOPHOLE[0]; EthernetFace.QueueInput[ ether, @oisBuf.encapsulation, oisBuf.length, oisBuf.iocbChain]; WHILE (ProcessorFace.GetClockPulses[] - startPulses) <= timeoutPulses DO IF EthernetFace.GetStatus[oisBuf.iocbChain] = pending THEN LOOP; IF EthernetFace.GetStatus[oisBuf.iocbChain] # ok THEN EXIT; IF oisBuf.encapsulation.ethernetType # ois THEN EXIT; IF oisBuf.ois.destination.host # myID THEN EXIT; IF oisBuf.ois.source.socket # pupAddressTranslation THEN EXIT; IF oisBuf.ois.destination.socket # mySocket THEN EXIT; IF EthernetFace.GetPacketLength[oisBuf.iocbChain] < WdsPerEthernetPacket[oisBuf.ois.pktLength] THEN EXIT; IF oisBuf.ois.pktLength < OISCPTypes.bytesPerPktHeader THEN EXIT; IF (reply.arg # translationResponse) THEN EXIT; IF ~TestOisChecksum[oisBuf] THEN EXIT; EthernetFace.TurnOff[ether]; DriverDefs.ReturnFreeBuffer[oisBuf]; RETURN[reply.answer.host] ENDLOOP; ENDLOOP; ENDLOOP; }; SetOisChecksum: PROC [b: BufferDefs.OisBuffer] = { b.ois.checksum _ Checksums.ComputeChecksum[ 0, (b.ois.pktLength + 1 - 2)/2, @b.ois.pktLength]; }; TestOisChecksum: PROC [b: BufferDefs.OisBuffer] RETURNS [BOOL] = { RETURN[ b.ois.checksum = Checksums.ComputeChecksum[ 0, (b.ois.pktLength + 1 - 2)/2, @b.ois.pktLength] OR b.ois.checksum = 177777B]; }; WdsPerEthernetPacket: PROC [bodyBytes: CARDINAL] RETURNS[wds: CARDINAL] = { minWdsPerEthernetPacket: CARDINAL = ((64-4)/Basics.bytesPerWord); wds _ SIZE[DriverTypes.Encapsulation] + (bodyBytes + Basics.bytesPerWord-1)/Basics.bytesPerWord; wds _ MAX[wds, minWdsPerEthernetPacket]; }; No10MBDriverAndNo3MBDriver: PUBLIC ERROR = CODE; DriverNeedsSomeGlobalStorage: PUBLIC ERROR = CODE; IF EthernetFace.globalStateSize # 0 THEN ERROR DriverNeedsSomeGlobalStorage; }....