-- File: PhoneHeadDicentra.mesa - last edit:
-- AOF 15-Feb-88 9:12:42
-- HGM 29-Nov-84 18:06:13
-- Copyright (C) 1983, 1984, 1988 by Xerox Corporation. All rights reserved.
DIRECTORY
DicentraInputOutput USING [
InterruptLevel, IOAddress, Output, SetPhonelineCSB, SetWakeupMask],
Environment USING [Byte],
Inline USING [BITAND, BITOR, LowHalf],
MultibusAddresses USING [
dialer0, dialer1, dialer2, IOAddress, modem0, scc0, scc1, scc2, scc3],
NewRS232CFace USING [
Command, CommandStatus, ControlRecord, DeviceStatus, LineNumber,
Operation, OperationPtr, ParameterHandle, ParameterStatus, ResetRecord,
RS232CClientType, TransferStatus],
PhoneFace USING [Line, Status],
ResidentHeap USING [Alignment, HeapLocation],
ResidentMemory USING [Allocate];
PhoneHeadDicentra: PROGRAM
IMPORTS Inline, DicentraInputOutput, ResidentMemory
EXPORTS NewRS232CFace, 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;
offset: CARDINAL = SIZE[NewRS232CFace.Operation];
controlBlockSize: PUBLIC <<PhoneFace>> CARDINAL ← SIZE[ControlBlockRecord];
operationSize: PUBLIC <<NewRS232CFace>> CARDINAL ←
SIZE[NewRS232CFace.Operation] + controlBlockSize;
operationAlignment: PUBLIC <<NewRS232CFace>> ResidentHeap.Alignment ← a1;
operationLocation: PUBLIC <<NewRS232CFace>> ResidentHeap.HeapLocation ← first64K;
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;
numberOfLines: PUBLIC NewRS232CFace.LineNumber ← lines;
NoSuchLine: ERROR = CODE;
Handle: PUBLIC <<NewRS232CFace>> TYPE = RECORD[line: Line, flag: CARDINAL];
nilHandle: PUBLIC <<NewRS232CFace>> Handle ← [lines, LAST[CARDINAL]];
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, Initialize: PUBLIC <<PhoneFace, NewRS232CFace>> PROC[
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;
InitializeCleanup: PUBLIC <<NewRS232CFace>> PROC[] = {}; --InitializeCleanup
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: PROC[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: PROC[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;
InitiateCommand: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, command: NewRS232CFace.Command]
RETURNS[commandStatus: NewRS232CFace.CommandStatus] =
{RETURN[inProgress]}; --InitiateCommand
InitiateReceive: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, operation: NewRS232CFace.OperationPtr]
RETURNS [transferStatus: NewRS232CFace.TransferStatus] =
BEGIN
QueueInput[
handle.line, LOOPHOLE[operation + offset],
operation.dataBuffer, operation.bufferByteLength];
RETURN[inProgress];
END; --InitiateReceive
InitiateResetStatusBits: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, resetRecord: NewRS232CFace.ResetRecord]
RETURNS [commandStatus: NewRS232CFace.CommandStatus] =
{RETURN[inProgress]}; --InitiateResetStatusBits
InitiateSetControlBits: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, controlRecord: NewRS232CFace.ControlRecord]
RETURNS [commandStatus: NewRS232CFace.CommandStatus] =
{RETURN[inProgress]}; --InitiateSetControlBits
InitiateSetParameters: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, parameters: NewRS232CFace.ParameterHandle]
RETURNS[parameterStatus: NewRS232CFace.ParameterStatus] =
{RETURN[inProgress]}; --InitiateSetParameters
InitiateTransmit: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, operation: NewRS232CFace.OperationPtr]
RETURNS [transferStatus: NewRS232CFace.TransferStatus] =
BEGIN
QueueOutput[
handle.line, LOOPHOLE[operation + offset],
operation.dataBuffer, operation.bufferByteLength];
RETURN[inProgress];
END; --InitiateTransmit
PollCommand: PUBLIC <<NewRS232CFace>> PROC[handle: Handle]
RETURNS [commandStatus: NewRS232CFace.CommandStatus] =
{RETURN[completed]}; --PollCommand
PollReceiveOrTransmit: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, operation: NewRS232CFace.OperationPtr]
RETURNS[
bytesTransferred: CARDINAL, transferStatus: NewRS232CFace.TransferStatus] =
BEGIN
OPEN iocb: LOOPHOLE[operation + offset, IOCB];
SELECT TRUE FROM
(iocb.status = 00000H) =>
RETURN[0, inProgress]; --either send or receive
(iocb.status = 0FFFFH) =>
RETURN[iocb.bytes - iocb.bytesLeft - 1, success]; --send success
(Inline.BITAND[iocb.status, 0FFH] = 087H) =>
RETURN[iocb.bytes - iocb.bytesLeft - 1, success]; --receive okay
(iocb.status = 00001H) =>
RETURN[0, invalidFrame]; --receive packetToLong
(Inline.BITAND[iocb.status, 020H] # 0) =>
RETURN[0, dataLost]; --receive overrun
(Inline.BITAND[iocb.status, 040H] # 0) =>
RETURN[0, checksumError]; --crc
ENDCASE =>
RETURN[0, deviceError]; --receive or transmit otherError
END; --PollReceiveOrTransmit
PollSetControlBits: PUBLIC <<NewRS232CFace>> PROC[handle: Handle]
RETURNS [commandStatus: NewRS232CFace.CommandStatus] =
{RETURN[completed]}; --PollSetControlBits
PollSetParameters: PUBLIC <<NewRS232CFace>> PROC[handle: Handle]
RETURNS[parameterStatus: NewRS232CFace.ParameterStatus] =
{RETURN[completed]}; --PollSetParameters
ReleaseHandle: PUBLIC <<NewRS232CFace>> PROC[handle: Handle]
RETURNS [nilHandle: Handle] = {RETURN[nilHandle]}; --ReleaseHandle
ResetStatusBits: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, resetRecord: NewRS232CFace.ResetRecord] = {};
SetControlBits: PUBLIC <<NewRS232CFace>> PROC[
handle: Handle, controlRecord: NewRS232CFace.ControlRecord] = {};
TurnOff: PUBLIC <<PhoneFace>> PROC =
BEGIN
DicentraInputOutput.SetPhonelineCSB[NIL];
END;
ResetLine: PUBLIC <<PhoneFace>> PROC[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 <<PhoneFace>> PROC[line: Line] RETURNS [CARDINAL] =
BEGIN
IF line > lines THEN ERROR NoSuchLine;
RETURN[csb[line].recvMissed]
END;
QueueOutput: PUBLIC <<PhoneFace>> PROC[
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;
GetDeviceStatus: PUBLIC <<NewRS232CFace>> PROC[handle: Handle]
RETURNS[deviceStatus: NewRS232CFace.DeviceStatus] =
BEGIN
END; --GetDeviceStatus
GetHandle: PUBLIC <<NewRS232CFace>> PROC[
lineNumber: NewRS232CFace.LineNumber,
rs232cClient: NewRS232CFace.RS232CClientType ← normalClient]
RETURNS [handle: Handle] = {RETURN[[lineNumber, LAST[CARDINAL]]]};
GetNextLine: PUBLIC <<NewRS232CFace>> PROC[
lineNumber: NewRS232CFace.LineNumber]
RETURNS [nextLineNumber: NewRS232CFace.LineNumber] =
{RETURN[IF (lineNumber ← lineNumber.SUCC) < lines THEN lineNumber
ELSE NewRS232CFace.LineNumber.FIRST]}; --GetNextLine
GetSendStatus: PUBLIC <<PhoneFace>> PROC[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 <<PhoneFace>> PROC[
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 <<PhoneFace>> PROC[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 <<PhoneFace>> PROC[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.