DTProms.mesa, HGM, November 14, 1984 1:08:09 am PST
Run DTProms
Copy /Ivy/Murray/DT/DTProms.mesa ← DTProms.mesa
Copy /Ivy/Murray/DT/DTProms.mb ← DTProms.mb
DIRECTORY
Convert USING [RopeFromTime],
FS USING [StreamOpen],
IO USING [Close, PutChar, PutRope, STREAM],
Loader USING [BCDBuildTime],
Rope USING [Cat, Length, ROPE];
DTProms: CEDAR PROGRAM
IMPORTS
Convert, FS, IO, Loader, Rope =
BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
mb: STREAM;
memory: CARDINAL ← 0;
Bit: TYPE = BOOLEAN;
virgin: BOOLEANTRUE; -- Virgin bits in TBP28L22s are high
TransmitControl: PROC =
BEGIN
State: TYPE = MACHINE DEPENDENT {idle(0), data(1), crc(2), (3)};
addr: RECORD [
blank: [0..256),
state: State,
timeout: Bit,
inhibit: Bit,
ready: Bit,
word: Bit,
notCollision: Bit,
notDefer: Bit ];
output: RECORD [
nextState: State,
notIdle: Bit,
idle: Bit,
carrier: Bit,
load: Bit,
notLoad: Bit,
spare: Bit ← virgin,
blank: [0..256) ← 0 ];
StartNewMemory["TC", 8];
FOR i: CARDINAL IN [0..256) DO
state, nextState: State;
timeout, inhibit, ready, word, collision, defer: Bit;
idle, carrier, load: Bit ← FALSE;
TRUSTED { addr ← LOOPHOLE[i]; };
state ← addr.state;
timeout ← addr.timeout;
inhibit ← addr.inhibit;
ready ← addr.ready;
word ← addr.word;
collision ← ~addr.notCollision;
defer ← ~addr.notDefer;
idle ← TRUE;
nextState ← state;
SELECT state FROM
idle => {
IF ~collision AND ~defer AND ~inhibit AND ready THEN {
idle ← FALSE; -- Kick Word
load ← TRUE;
nextState ← data; }; };
data => {
idle ← FALSE;
carrier ← TRUE;
IF word THEN
SELECT TRUE FROM
inhibit => nextState ← crc; -- End of Data
ready => load ← ~collision;
~ready => nextState ← idle; -- Data Late
ENDCASE => ERROR;
IF collision OR timeout THEN nextState ← idle; }; -- Catastrophe
crc => {
idle ← FALSE;
carrier ← TRUE;
IF word THEN { -- End of CRC
idle ← TRUE;
carrier ← FALSE;
nextState ← idle; };
IF collision OR timeout THEN nextState ← idle; }; -- Catastrophe
ENDCASE => nextState ← idle;
output.nextState ← nextState;
output.notIdle ← ~idle;
output.idle ← idle;
output.carrier ← carrier;
output.load ← load;
output.notLoad ← ~load;
PutWord[1]; -- Memory contents
PutWord[0]; -- Source line number
TRUSTED { PutWord[LOOPHOLE[output, CARDINAL]]; };
ENDLOOP;
END;
BitStuffing: PROC =
BEGIN
State: TYPE = MACHINE DEPENDENT {
idle0, idle1, idle2, idle3, idle4, idle5, idle6, idle7,
start0, start1, start2, start3, start4, start5, start6, start7,
no0s, one0, two0s, three0s, four0s, five0s,
stop0, stop1, stop2, stop3, stop4, stop5, stop6, stop7, (31)};
addr: RECORD [
blank: [0..256),
state: State,
notTick: Bit,
carrier: Bit,
dataIn: Bit ];
output: RECORD [
nextState: State,
shift: Bit,
active: Bit,
dataOut: Bit,
blank: [0..256) ← 0 ];
StartNewMemory["BS", 8];
FOR i: CARDINAL IN [0..256) DO
state, nextState: State;
tick, carrier, dataIn: Bit;
shift, active, dataOut: Bit;
TRUSTED { addr ← LOOPHOLE[i]; };
state ← addr.state;
tick ← ~addr.notTick;
carrier ← addr.carrier;
dataIn ← addr.dataIn;
nextState ← state;
shift ← tick;
dataOut ← TRUE;
SELECT state FROM
idle0, idle1, idle2, idle3, idle4, idle5, idle6, idle7 => {
shift ← ~carrier;
IF tick THEN {
nextState ← state.SUCC;
IF state = idle7 THEN nextState ← IF carrier THEN start0 ELSE idle0; };
IF nextState IN (idle0..idle7) THEN dataOut ← FALSE; };
start0, start1, start2, start3, start4, start5, start6, start7 => {
shift ← FALSE;
IF tick THEN {
nextState ← state.SUCC;
IF state = start7 THEN { nextState ← no0s; dataOut ← dataIn; }; };
IF ~carrier THEN nextState ← idle0;
IF nextState IN (start0..start7) THEN dataOut ← FALSE; };
no0s, one0, two0s, three0s, four0s, five0s => {
dataOut ← dataIn;
IF state = five0s THEN dataOut ← TRUE;
IF tick THEN {
nextState ← IF dataIn THEN no0s ELSE state.SUCC;
IF state = five0s THEN { nextState ← no0s; shift ← FALSE; };
IF ~carrier THEN { nextState ← stop0; shift ← FALSE; dataOut ← TRUE; }; }; };
stop0, stop1, stop2, stop3, stop4, stop5, stop6, stop7 => {
IF tick THEN {
shift ← FALSE;
nextState ← state.SUCC;
IF state = stop7 THEN nextState ← idle0; };
IF nextState IN (stop0..stop7) THEN dataOut ← FALSE; };
ENDCASE => nextState ← idle0;
active ← nextState IN [start0..stop7];
output.nextState ← nextState;
output.active ← active;
output.shift ← shift;
output.dataOut ← dataOut;
PutWord[1]; -- Memory contents
PutWord[0]; -- Source line number
TRUSTED { PutWord[LOOPHOLE[output, CARDINAL]]; };
ENDLOOP;
END;
ClockRecovery: PROC =
BEGIN
State: TYPE = MACHINE DEPENDENT {
one0(0), one1, one2, one3, one4, one5, one6, one7(7),
zero0(8), zero1, zero2, zero3, zero4, zero5, zero6, zero7, (31)};
one0 => line went up in the previous 1/8th of a bit cell, this bit is a 1
zero0 => line would have gone up in the previous 1/8th of a bit cell, but this bit is a 0
Our clock is running 8 times the nominal bit rate on the line. A bit will normally be 4 slots wide, but asymetries may distort a bit to 3, or 5 slots. tick is raised during the 2nd slot so it becomes available during the 3rd slot. The next stage must grab the bit right away, or it may change if a bit is narrow.
We could raise tick 1 slot earlier, but this code will get slightly more verbose.
addr: RECORD [
blank: [0..256),
state: State,
gnd: Bit,
mask: Bit,
line: Bit ];
output: RECORD [
nextState: State,
spare1: Bit ← virgin,
spare2: Bit ← virgin,
tick: Bit,
blank: [0..256) ← 0 ];
StartNewMemory["CR", 8];
FOR i: CARDINAL IN [0..256) DO
state, nextState: State;
line, mask: Bit;
tick: Bit ← FALSE;
addr ← LOOPHOLE[i];
state ← addr.state;
line ← addr.line;
mask ← addr.mask;
IF state # State.LAST THEN nextState ← state.SUCC;
SELECT state FROM
one0 => tick ← mask; -- This bit is a one
IN [one1..one5] => NULL;
one6 =>
IF line THEN nextState ← one0; -- Advance one tick
one7 =>
IF line THEN nextState ← one0; -- Right on
zero0 =>
IF line THEN nextState ← one0 -- Drop back one tick
ELSE tick ← mask; -- This bit is a zero
IN [zero1..zero5] =>
IF line THEN nextState ← one0; -- Lost sync??
zero6 =>
IF line THEN nextState ← one0; -- Advance one tick
zero7 =>
IF line THEN nextState ← one0 -- Right on
ELSE nextState ← zero0;
ENDCASE => nextState ← one0;
output.nextState ← nextState;
output.tick ← tick;
PutWord[1]; -- Memory contents
PutWord[0]; -- Source line number
TRUSTED { PutWord[LOOPHOLE[output, CARDINAL]]; };
ENDLOOP;
END;
BitUnstuffing: PROC =
BEGIN
State: TYPE = MACHINE DEPENDENT {
abort(0),
flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, -- Expecting bit n of a flag
start00, -- start<n><m> => n bits since flag, m 0s since last 1
start10, start11,
start20, start21, start22,
start30, start31, start32, start33,
start40, start41, start42, start43, start44,
start50, start51, start52, start53, start54, start55,
start60, start61, start62, start63, start64, start65,
start70, start71, start72, start73, start74, start75,
data0, data1, data2, data3, data4, data5, data6, (63)}; -- n 0s since last 1
addr: RECORD [
blank: [0..256),
state: State,
tick: Bit,
data: Bit ];
output: RECORD [
nextState: State,
shift: Bit,
carrier: Bit,
blank: [0..256) ← 0 ];
StartNewMemory["BU", 8];
FOR i: CARDINAL IN [0..256) DO
state, nextState: State;
tick, data, shift, carrier: Bit;
addr ← LOOPHOLE[i];
state ← addr.state;
tick ← addr.tick;
data ← addr.data;
nextState ← state;
shift ← TRUE;
SELECT state FROM
abort => nextState ← IF data THEN flag0 ELSE abort;
flag0 => nextState ← IF data THEN flag0 ELSE flag1;
IN [flag1..flag6] => nextState ← IF data THEN flag0 ELSE state.SUCC;
flag7 => nextState ← IF data THEN start00 ELSE abort;
start00 => nextState ← IF data THEN start10 ELSE start11;
start10 => nextState ← IF data THEN start20 ELSE start21;
start11 => nextState ← IF data THEN start20 ELSE start22;
start20 => nextState ← IF data THEN start30 ELSE start31;
start21 => nextState ← IF data THEN start30 ELSE start32;
start22 => nextState ← IF data THEN start30 ELSE start33;
start30 => nextState ← IF data THEN start40 ELSE start41;
start31 => nextState ← IF data THEN start40 ELSE start42;
start32 => nextState ← IF data THEN start40 ELSE start43;
start33 => nextState ← IF data THEN start40 ELSE start44;
start40 => nextState ← IF data THEN start50 ELSE start51;
start41 => nextState ← IF data THEN start50 ELSE start52;
start42 => nextState ← IF data THEN start50 ELSE start53;
start43 => nextState ← IF data THEN start50 ELSE start54;
start44 => nextState ← IF data THEN start50 ELSE start55;
start50 => nextState ← IF data THEN start60 ELSE start61;
start51 => nextState ← IF data THEN start60 ELSE start62;
start52 => nextState ← IF data THEN start60 ELSE start63;
start53 => nextState ← IF data THEN start60 ELSE start64;
start54 => nextState ← IF data THEN start60 ELSE start65;
start55 => nextState ← IF data THEN start50 ELSE flag6; -- Normal idle case
start60 => nextState ← IF data THEN start70 ELSE start71;
start61 => nextState ← IF data THEN start70 ELSE start72;
start62 => nextState ← IF data THEN start70 ELSE start73;
start63 => nextState ← IF data THEN start70 ELSE start74;
start64 => nextState ← IF data THEN start70 ELSE start75;
start65 => nextState ← IF data THEN start60 ELSE abort;
start70 => nextState ← IF data THEN data0 ELSE data1;
start71 => nextState ← IF data THEN data0 ELSE data2;
start72 => nextState ← IF data THEN data0 ELSE data3;
start73 => nextState ← IF data THEN data0 ELSE data4;
start74 => nextState ← IF data THEN data0 ELSE data5;
start75 => nextState ← IF data THEN start70 ELSE abort;
IN [data0..data4] => nextState ← IF data THEN data0 ELSE state.SUCC;
data5 => nextState ← IF data THEN data0 ELSE data6;
data6 => nextState ← IF data THEN flag0 ELSE abort;
ENDCASE => nextState ← abort;
SELECT state FROM
start55, start65, start75, data5, data6 => shift ← FALSE;
ENDCASE => NULL;
IF ~tick THEN {
shift ← FALSE;
nextState ← state; };
carrier ← nextState IN [data0..data6];
output.nextState ← nextState;
output.shift ← shift;
output.carrier ← carrier;
PutWord[1]; -- Memory contents
PutWord[0]; -- Source line number
TRUSTED { PutWord[LOOPHOLE[output, CARDINAL]]; };
ENDLOOP;
END;
ReceiveControl: PROC =
BEGIN
State: TYPE = MACHINE DEPENDENT {
idle(0), start, data, end(3)};
addr: RECORD [
blank: [0..256),
state: State,
enable: Bit,
match: Bit,
word: Bit,
shift: Bit,
data: Bit,
carrier: Bit ];
output: RECORD [
nextState: State,
notFce: Bit,
crcClr: Bit,
notClear: Bit,
notAbort: Bit,
end: Bit,
write: Bit,
blank: [0..256) ← 0 ];
StartNewMemory["RC", 8];
FOR i: CARDINAL IN [0..256) DO
state, nextState: State;
enable, match, word, shift, data, carrier: Bit;
fce, crcClr, clear, abort, end, write: Bit ← FALSE;
addr ← LOOPHOLE[i];
state ← addr.state;
enable ← addr.enable;
match ← addr.match;
word ← addr.word;
shift ← addr.shift;
data ← addr.data;
carrier ← addr.carrier;
nextState ← state;
SELECT state FROM
idle => {
clear ← ~carrier;
IF ~word THEN nextState ← IF carrier THEN start ELSE end; };
start => {
fce ← shift;
IF ~carrier THEN nextState ← end; -- Noise burst?
IF word THEN {
nextState ← IF match THEN data ELSE end; }; };
data => {
write ← word;
IF ~carrier THEN {
nextState ← end;
abort ← ~word; }; };
end => {
IF ~carrier THEN {
nextState ← idle;
crcClr ← TRUE; }; };
ENDCASE => ERROR;
IF ~enable THEN { nextState ← idle; fce ← TRUE; };
output.nextState ← nextState;
output.notFce ← ~fce;
output.crcClr ← crcClr;
output.notClear ← ~clear;
output.notAbort ← ~abort;
output.end ← end;
output.write ← write;
PutWord[1]; -- Memory contents
PutWord[0]; -- Source line number
TRUSTED { PutWord[LOOPHOLE[output, CARDINAL]]; };
ENDLOOP;
END;
PutTimeStamp: PROC [name: ROPE] =
BEGIN
PutWord[4]; -- Define (fake) Memory
memory ← memory + 1;
PutWord[memory];
PutWord[8];
name ← Rope.Cat[name, " of ", Convert.RopeFromTime[Loader.BCDBuildTime[DoIt]]];
PutRope[name];
END;
StartNewMemory: PROC [name: ROPE, bitsPerWord: CARDINAL] =
BEGIN
PutWord[4]; -- Define Memory
memory ← memory + 1;
PutWord[memory];
PutWord[bitsPerWord];
PutRope[name];
PutWord[2]; -- Set Current Memory
PutWord[memory];
PutWord[0]; -- Current PC
END;
PutRope: PROC [rope: ROPE] =
BEGIN
IO.PutRope[mb, rope];
PutByte[0]; -- End of string
IF (rope.Length[] MOD 2) = 0 THEN PutByte[0]; -- Round up to word
END;
PutWord: PROC [data: CARDINAL] = TRUSTED
BEGIN
IO.PutChar[mb, LOOPHOLE[data/256, CHAR]];
IO.PutChar[mb, LOOPHOLE[data, CHAR]];
END;
PutByte: PROC [data: CARDINAL] = TRUSTED
BEGIN
IO.PutChar[mb, LOOPHOLE[data, CHAR]];
END;
DoIt: PROCEDURE =
BEGIN
mb ← FS.StreamOpen["DTProms.mb", $create];
PutTimeStamp["DTProms.mb"];
ClockRecovery[];
BitUnstuffing[];
ReceiveControl[];
TransmitControl[];
BitStuffing[];
PutWord[0]; -- End of data marker
IO.Close[mb];
mb ← NIL;
END;
DoIt[];
END.