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: BOOLEAN _ TRUE; -- 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)}; 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 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. Ô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 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. ʘJšœ3™3J˜Jšœ ™ J™/J™+J™šÏk ˜ Jšœœ˜Jšœœ˜Jšœœœ˜+Jšœœ˜šœœœ˜J˜——šœ œ˜š˜Jšœ œœ˜—Jš˜J˜Jšœœœ˜Jšœœœœ˜J˜Jšœœ˜ Jšœœ˜J˜Jšœœœ˜JšœœœÏc$˜˜>—šœœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜—šœœ˜Jšœ˜Jšœ ˜ Jšœ ˜ J˜ J˜—J˜šœœœ ˜J˜Jšœ˜Jšœ˜Jšœ œ˜ J˜Jšœ˜J˜J˜J˜Jšœ ˜ Jšœ œ˜šœ˜šœ;˜;Jšœ˜šœœ˜Jšœœ˜Jš œœ œ œœ ˜G—Jšœ œœ œ˜7—šœC˜CJšœœ˜šœœ˜Jšœœ˜Jšœœ,˜B—Jšœ œ˜#Jšœ œœ œ˜9—šœ/˜/Jšœ˜Jšœœ œ˜&šœœ˜Jš œ œœœœ˜0Jšœœœ˜