Oberon/V2/SCC
< Oberon
MODULE SCC; (*NW 13.11.87 / 22.8.90 Ceres-2*)
IMPORT SYSTEM, Kernel;
CONST BufLen = 2048;
com = 0FFFFD008H; (*commands and status, SCC channel A*)
dat = 0FFFFD00CH;
DIPS = 0FFFFFC00H;
ICU = 0FFFF9004H;
RxCA = 0; (*R0: Rx Char Available*)
TxBE = 2; (*R0: Tx Buffer Empty*)
Hunt = 4; (*R0: Sync/Hunt*)
TxUR = 6; (*R0: Tx UnderRun*)
RxOR = 5; (*R1: Rx OverRun*)
CRC = 6; (*R1: CRC error*)
EOF = 7; (*R1: End Of Frame*)
TYPE Header* =
RECORD valid*: BOOLEAN;
dadr*, sadr*, typ*: SHORTINT;
len*: INTEGER; (*of data following header*)
destLink*, srcLink*: INTEGER (*link numbers*)
END ;
VAR in, out: INTEGER;
Adr: SHORTINT;
SCCR3: CHAR;
buf: ARRAY BufLen OF CHAR;
PROCEDURE PUT(r: SHORTINT; x: SYSTEM.BYTE);
BEGIN SYSTEM.PUT(com, r); SYSTEM.PUT(com, x)
END PUT;
PROCEDURE+ Int1;
VAR del, oldin: INTEGER; stat: SET; dmy: CHAR;
BEGIN SYSTEM.GET(dat, buf[in]);
PUT(1, 0X); (*disable interrupts*)
oldin := in; in := (in+1) MOD BufLen; del := 16;
LOOP
IF SYSTEM.BIT(com, RxCA) THEN del := 16;
IF in # out THEN SYSTEM.GET(dat, buf[in]); in := (in+1) MOD BufLen
ELSE SYSTEM.GET(dat, dmy)
END
ELSE SYSTEM.PUT(com, 1X); DEC(del);
IF SYSTEM.BIT(com, EOF) & (del <= 0) OR (del <= -16) THEN EXIT END
END
END ;
SYSTEM.PUT(com, 1X); SYSTEM.GET(com, stat);
IF (RxOR IN stat) OR (CRC IN stat) OR (in = out) THEN
in := oldin (*reset buffer*)
ELSE in := (in-2) MOD BufLen (*remove CRC*)
END ;
SYSTEM.PUT(com, 30X); (*error reset*)
SYSTEM.PUT(com, 10X); (*reset ext/stat interrupts*)
PUT( 1, 8X); (*enable Rx-Int on 1st char*)
SYSTEM.PUT(com, 20X); (*enable Rx-Int on next char*)
PUT( 3, SCCR3); (*enter hunt mode*)
END Int1;
PROCEDURE Start*(filter: BOOLEAN);
BEGIN in := 0; out := 0;
IF filter THEN SCCR3 := 0DDX ELSE SCCR3 := 0D9X END ;
SYSTEM.GET(DIPS, Adr); Adr := Adr MOD 40H;
Kernel.InstallIP(Int1, 1);
PUT( 9, 80X); (*reset A, disable all interrupts*)
PUT( 4, 20X); (*SDLC mode*)
PUT( 1, 0X); (*disable all interrupts*)
PUT( 2, 0X); (*interrupt vector*)
PUT( 3, SCCR3); (*8bit, hunt mode, Rx-CRC on, adr search, Rx off*)
PUT( 5, 0E1X); (*8bit, SDLC, Tx-CRC on, Tx off*)
PUT( 6, Adr); (*SDLC-address*)
PUT( 7, 7EX); (*SDLC flag*)
PUT( 9, 6X); (*master int on, no vector*)
PUT(10, 0E0X); (*FM0*)
PUT(11, 0F7X); (*Xtal, RxC = DPLL TxC = rate genL*)
PUT(12, 6X); (*lo byte of rate gen: Xtal DIV 16*)
PUT(13, 0X); (*hi byte of rate gen*)
PUT(14, 0A0X); (*DPLL = Xtal*)
PUT(14, 0C0X); (*FM mode*)
PUT( 3, SCCR3); (*Rx enable, enter hunt mode*)
SYSTEM.PUT(com, 80X); (*TxCRC reset*)
PUT(15, 0X); (*mask ext interrupts*)
SYSTEM.PUT(com, 10X);
SYSTEM.PUT(com, 10X); (*reset ext/status*)
PUT( 1, 0X); (*Rx-Int on 1st char off*)
PUT( 9, 0EX); (*no A reset, enable int, disable daisy chain*)
PUT( 1, 8X); (*enable Rx Int*)
PUT(14, 21X); (*enter search mode*)
SYSTEM.PUT(ICU, 19X); (*clear IRR and IMR bits, channel 1*)
END Start;
PROCEDURE SendPacket*(VAR head, buf: ARRAY OF SYSTEM.BYTE);
VAR i, len: INTEGER;
BEGIN head[2] := Adr;
len := ORD(head[5])*100H + ORD(head[4]);
LOOP (*sample line*) i := 60;
REPEAT DEC(i) UNTIL SYSTEM.BIT(com, Hunt) OR (i = 0);
IF i > 0 THEN (*line idle*) EXIT END ;
i := LONG(Adr)*128 + 800; (*delay*)
REPEAT DEC(i) UNTIL i = 0
END ;
Kernel.SetICU(0A2X); (*disable interrupts!*)
PUT( 5, 63X); (*RTS, send 1s*)
PUT( 5, 6BX); (*RTS, Tx enable*)
SYSTEM.PUT(com, 80X); (*reset Tx-CRC*)
SYSTEM.PUT(dat, ORD(head[1])); (*send dest*)
SYSTEM.PUT(com, 0C0X); (*reset underrun/EOM flag*)
REPEAT UNTIL SYSTEM.BIT(com, TxBE);
i := 2;
REPEAT SYSTEM.PUT(dat, head[i]); INC(i);
REPEAT UNTIL SYSTEM.BIT(com, TxBE)
UNTIL i = 10;
i := 0;
WHILE i < len DO
SYSTEM.PUT(dat, buf[i]); INC(i); (*send data*)
REPEAT UNTIL SYSTEM.BIT(com, TxBE)
END ;
REPEAT UNTIL SYSTEM.BIT(com, TxUR) & SYSTEM.BIT(com, TxBE);
PUT( 5, 63X); (*RTS, Tx disable, send 1s*)
i := 300;
REPEAT DEC(i) UNTIL i = 0;
PUT( 5, 0E1X); (*~RTS*)
PUT( 1, 8X); (*enable Rx-Int on 1st char*)
PUT(14, 21X); (*enter search mode*)
SYSTEM.PUT(com, 20X); (*enable Rx-Int on next char*)
PUT( 3, SCCR3); (*enter hunt mode*)
SYSTEM.PUT(ICU, 0A1X) (*enable interrupts*)
END SendPacket;
PROCEDURE Available*(): INTEGER;
BEGIN RETURN (in - out) MOD BufLen
END Available;
PROCEDURE Receive*(VAR x: SYSTEM.BYTE);
BEGIN
REPEAT UNTIL in # out;
x := buf[out]; out := (out+1) MOD BufLen
END Receive;
PROCEDURE ReceiveHead*(VAR head: ARRAY OF SYSTEM.BYTE);
VAR i: INTEGER;
BEGIN
IF (in - out) MOD BufLen >= 9 THEN head[0] := 1; i := 1;
REPEAT Receive(head[i]); INC(i) UNTIL i = 10
ELSE head[0] := 0
END
END ReceiveHead;
PROCEDURE Skip*(m: INTEGER);
BEGIN
IF m <= (in - out) MOD BufLen THEN out := (out+m) MOD BufLen ELSE out := in END
END Skip;
PROCEDURE Stop*;
BEGIN PUT(9, 80X); (*reset SCCA*)
SYSTEM.PUT(ICU, 39X); SYSTEM.PUT(ICU, 59X); (*reset IMR and IRR*)
END Stop;
BEGIN Start(TRUE)
END SCC.