-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved. -- PhoneHeadDicentra.mesa, HGM, 29-Nov-84 18:06:13 DIRECTORY Environment USING [Byte], Inline USING [BITAND, BITOR, LowHalf], ResidentMemory USING [Allocate], DicentraInputOutput USING [ InterruptLevel, IOAddress, Output, SetPhonelineCSB, SetWakeupMask], MultibusAddresses USING [ dialer0, dialer1, dialer2, modem0, scc0, scc1, scc2, scc3], PhoneFace USING [Line, Status]; PhoneHeadDicentra: PROGRAM IMPORTS Inline, DicentraInputOutput, ResidentMemory EXPORTS PhoneFace = BEGIN Line: TYPE = PhoneFace.Line; Status: TYPE = PhoneFace.Status; sendTail, recvTail: ARRAY Line OF IOCB; csb: LONG POINTER TO CSB = AllocateCSB[]; CSB: TYPE = ARRAY Line OF ControlBlock; ControlBlock: TYPE = RECORD [ tranState: WORD, tranIOCB: ShortIOCB, tranIOCBMapped: LONG POINTER, recvState: WORD, recvIOCB: ShortIOCB, recvIOCBMapped: LONG POINTER, tranUnderruns: CARDINAL, tranUnused: ARRAY [9..12) OF WORD, recvMissed: CARDINAL, recvAborted: CARDINAL, recvAbortIdle: CARDINAL, recvAbortEx: CARDINAL]; IOCB: TYPE = LONG POINTER TO ControlBlockRecord; ShortIOCB: TYPE = POINTER TO ControlBlockRecord; controlBlockSize: PUBLIC CARDINAL ← SIZE[ControlBlockRecord]; ControlBlockRecord: PUBLIC TYPE = RECORD [ next: ShortIOCB, status: WORD, buffer: LONG POINTER, bytes: CARDINAL, bytesLeft: CARDINAL, unused: ARRAY [6..8) OF WORD, finger: LONG POINTER, mapped: LONG POINTER, spare: ARRAY [12..16) OF WORD ]; lines: CARDINAL = 8; NoSuchLine: ERROR = CODE; channels: ARRAY [0..lines) OF LONG POINTER TO Words = [ LOOPHOLE[MultibusAddresses.scc0 + 10H], -- Chan A LOOPHOLE[MultibusAddresses.scc0 + 00H], -- Chan B LOOPHOLE[MultibusAddresses.scc1 + 10H], LOOPHOLE[MultibusAddresses.scc1 + 00H], LOOPHOLE[MultibusAddresses.scc2 + 10H], -- Chan A LOOPHOLE[MultibusAddresses.scc2 + 00H], -- Chan B LOOPHOLE[MultibusAddresses.scc3 + 10H], LOOPHOLE[MultibusAddresses.scc3 + 00H]]; interruptVect: ARRAY [0..lines) OF WORD = [0, 0, 10H, 10H, 20H, 20H, 30H, 30H]; baudRateNumber: ARRAY [0..lines) OF WORD = [014H, 014H, 077H, 077H, 077H, 077H, 077H, 077H]; Words: TYPE = RECORD [ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15: WORD]; TurnOn: PUBLIC PROCEDURE [interruptBits: WORD] = BEGIN SetupTestClocks[]; csb↑ ← ALL[ [ tranState: 0, tranIOCB: NIL, tranIOCBMapped: NIL, recvState: 0, recvIOCB: NIL, recvIOCBMapped: NIL, tranUnderruns: 0, tranUnused: ALL[0], recvMissed: 0, recvAborted: 0, recvAbortIdle: 0, recvAbortEx: 0 ] ]; FOR line: Line IN [0..lines) DO InitChip[line]; ENDLOOP; FOR line: Line IN [0..lines) DO ResetLine[line]; ENDLOOP; DicentraInputOutput.SetWakeupMask[interruptBits, phoneLine]; DicentraInputOutput.SetPhonelineCSB[csb]; END; SetupTestClocks: PROCEDURE = BEGIN SetupTestClock[MultibusAddresses.modem0, 00BH]; -- LCa for first 2 lines at 56KB SetupTestClock[MultibusAddresses.dialer0, 041H]; -- LCb for next 2 lines at 9600 SetupTestClock[MultibusAddresses.dialer1, 041H]; -- LCc for next 2 lines at 9600 SetupTestClock[MultibusAddresses.dialer2, 041H]; -- LCd for next 2 lines at 9600 END; SetupTestClock: PROCEDURE [chip: DicentraInputOutput.IOAddress, ticks: CARDINAL] = BEGIN DicentraInputOutput.Output[001H, chip + 000H]; -- Master Interrupt Control ← Reset DicentraInputOutput.Output[000H, chip + 000H]; -- Master Interrupt Control ← No Reset DicentraInputOutput.Output[010H, chip + 001H]; -- Master Config Control ← Enable Port C and Cnt3 DicentraInputOutput.Output[000H, chip + 01AH]; -- Cnt3 MSB DicentraInputOutput.Output[ticks, chip + 01BH]; -- Cnt3 LSB DicentraInputOutput.Output[0C2H, chip + 01EH]; -- Cnt3 Mode ← Sq Out DicentraInputOutput.Output[006H, chip + 00CH]; -- Cnt3 Command ← Go END; InitChip: PROCEDURE [line: Line] = BEGIN chan: LONG POINTER TO Words = channels[line]; chanB: LONG POINTER TO Words = channels[Inline.BITOR[line, 1]]; IF line > lines THEN ERROR NoSuchLine; DicentraInputOutput.Output[002H, @chanB.r0]; -- Shift Left (ADR0 is ignored) DicentraInputOutput.Output[0C9H, @chan.r9]; -- Hardware Reset, MIE, V, VIS DicentraInputOutput.Output[interruptVect[line], @chan.r2]; -- Int Vector Base END; TurnOff: PUBLIC PROCEDURE = BEGIN DicentraInputOutput.SetPhonelineCSB[NIL]; END; ResetLine: PUBLIC PROCEDURE [line: Line] = BEGIN chan: LONG POINTER TO Words = channels[line]; IF line > lines THEN ERROR NoSuchLine; DicentraInputOutput.Output[000H, @chan.r1]; -- Disable all ints DicentraInputOutput.SetPhonelineCSB[csb]; -- Just in case csb[line].tranIOCB ← NIL; csb[line].tranState ← 0; csb[line].recvIOCB ← NIL; csb[line].recvState ← 0; DicentraInputOutput.Output[interruptVect[line], @chan.r2]; -- Int Vector Base DicentraInputOutput.Output[020H, @chan.r4]; -- SDLC DicentraInputOutput.Output[013H, @chan.r1]; -- Rx All Int, Tx Int En, Ext Int En DicentraInputOutput.Output[0D9H, @chan.r3]; -- 8bits/char, Hunt, CRC, RxE DicentraInputOutput.Output[0EBH, @chan.r5]; -- DTR, 8bits/char, TxE, RTS, CRC DicentraInputOutput.Output[07EH, @chan.r7]; -- Flag Char DicentraInputOutput.Output[084H, @chan.r10]; -- CRC←1, Abort on Underrun DicentraInputOutput.Output[080H, @chan.r15]; -- Enable Ext Int on Abort DicentraInputOutput.Output[070H, @chan.r0]; -- Reset Rx CRC, Error Reset DicentraInputOutput.Output[090H, @chan.r0]; -- Reset Tx CRC, Reset Ext/Sts Int DicentraInputOutput.Output[008H, @chan.r11]; -- External Clocks IF FALSE THEN BEGIN DicentraInputOutput.Output[baudRateNumber[line], @chan.r12]; -- Low byte of time constant DicentraInputOutput.Output[000H, @chan.r13]; -- High byte of time constant DicentraInputOutput.Output[003H, @chan.r14]; -- Baud Rate Gen from PClk DicentraInputOutput.Output[050H, @chan.r11]; -- Clocks from BR Gen END; END; GetPacketsMissed: PUBLIC PROCEDURE [line: Line] RETURNS [CARDINAL] = BEGIN IF line > lines THEN ERROR NoSuchLine; RETURN[csb[line].recvMissed] END; QueueOutput: PUBLIC PROCEDURE [line: Line, iocb: IOCB, buffer: LONG POINTER, bytes: CARDINAL] = BEGIN chan: LONG POINTER TO Words = channels[line]; firstByte: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte = buffer; IF line > lines THEN ERROR NoSuchLine; iocb.status ← 0; iocb.next ← NIL; iocb.buffer ← buffer; iocb.bytes ← bytes; IF csb[line].tranIOCB = NIL THEN BEGIN csb[line].tranIOCB ← Inline.LowHalf[iocb]; DicentraInputOutput.Output[080H, @chan.r0]; -- Reset Tx CRC DicentraInputOutput.Output[firstByte[0], @chan.r8]; -- Send first data byte END ELSE BEGIN sendTail[line].next ← Inline.LowHalf[iocb]; IF csb[line].tranIOCB = NIL AND iocb.status = 0 THEN -- Rats, lost race BEGIN csb[line].tranIOCB ← Inline.LowHalf[iocb]; DicentraInputOutput.Output[080H, @chan.r0]; -- Reset Tx CRC DicentraInputOutput.Output[firstByte[0], @chan.r8]; -- Send first data byte END; END; sendTail[line] ← iocb; END; GetSendStatus: PUBLIC PROCEDURE [iocb: IOCB] RETURNS [status: Status] = BEGIN IF iocb.status = 0 THEN RETURN[pending]; SELECT iocb.status FROM 0FFFFH => RETURN[ok]; ENDCASE => RETURN[underrun]; END; QueueInput: PUBLIC PROCEDURE [line: Line, iocb: IOCB, buffer: LONG POINTER, bytes: CARDINAL] = BEGIN iocb.status ← 0; iocb.next ← NIL; iocb.buffer ← buffer; iocb.bytes ← bytes; IF line > lines THEN ERROR NoSuchLine; IF csb[line].recvIOCB = NIL THEN BEGIN csb[line].recvIOCB ← Inline.LowHalf[iocb] END ELSE BEGIN recvTail[line].next ← Inline.LowHalf[iocb]; IF csb[line].recvIOCB = NIL AND iocb.status = 0 THEN -- lost race csb[line].recvIOCB ← Inline.LowHalf[iocb]; END; recvTail[line] ← iocb; END; GetRecvStatus: PUBLIC PROCEDURE [iocb: IOCB] RETURNS [status: Status] = BEGIN IF iocb.status = 0 THEN RETURN[pending]; IF iocb.status = 1 THEN RETURN[packetTooLong]; IF Inline.BITAND[iocb.status, 020H] # 0 THEN RETURN[overrun]; IF Inline.BITAND[iocb.status, 040H] # 0 THEN RETURN[crc]; SELECT Inline.BITAND[iocb.status, 0FFH] FROM 087H => RETURN[ok]; ENDCASE => RETURN[otherError]; END; GetPacketLength: PUBLIC PROCEDURE [iocb: IOCB] RETURNS [bytes: CARDINAL] = BEGIN RETURN[iocb.bytes - iocb.bytesLeft - 1]; END; AllocateCSB: PROCEDURE RETURNS [base: LONG POINTER] = BEGIN pages: CARDINAL = 1; base ← ResidentMemory.Allocate[hyperspace, pages]; END; SetupTestClocks[]; END.