-- MouseSimImpl.mesa -- created by Haeberli: 30-Sep-81 15:46:15 DIRECTORY InlineDefs, Mouse; MouseSimImpl: PROGRAM IMPORTS InlineDefs EXPORTS Mouse = { OPEN InlineDefs, Mouse; PinState: TYPE = ARRAY Mouse.Pin OF Mouse.Value; drivenPinState: PinState ← ALL[x]; lastDrivenPinState: PinState ← drivenPinState; currentPinState: PinState ← ALL[x]; lastPinState: PinState ← lastPinState; version: Mouse.ChipVersion ← Rev3; EndRecordPat: PUBLIC PROCEDURE = {}; GetPin: PUBLIC PROCEDURE [pin: Mouse.Pin] RETURNS [value: Mouse.Value] = { RETURN[currentPinState[pin]]}; PlayPat: PUBLIC PROCEDURE [pat: Pattern] = {}; RecordPat: PUBLIC PROCEDURE [pat: Pattern] = {}; SetVersion: PUBLIC PROCEDURE [v: Mouse.ChipVersion] = {version ← v; Reset[]}; Reset: PUBLIC PROCEDURE = { drivenPinState ← ALL[x]; lastDrivenPinState ← drivenPinState; currentPinState ← ALL[x]; lastPinState ← currentPinState; testEnabled ← FALSE; testDataBit ← FALSE; lastTestDataBit ← FALSE; secondToLastTestDataBit ← FALSE; testWord ← 0; lastTestWord ← 0; newTestWord ← 0; xA ← zero; xB ← zero; xL ← zero; yA ← zero; yB ← zero; yL ← zero; phiLong ← one; phiShort ← zero; anyGood ← zero; jump ← zero}; SetPin: PUBLIC PROCEDURE [pin: Mouse.Pin, value: Mouse.Value] = { IF value # drivenPinState[pin] THEN { lastDrivenPinState ← drivenPinState; drivenPinState[pin] ← value; PinChanged[pin, lastDrivenPinState[pin], value]}}; SetPinMap: PUBLIC PROCEDURE [pinMap: Mouse.PinMap] = {}; PinChanged: PROCEDURE [pin: Mouse.Pin, oldValue, newValue: Mouse.Value] = { SELECT pin FROM RedA => Debounce[RedA, oldValue, newValue, RedB]; RedB => Debounce[RedB, oldValue, newValue, RedA]; YellowA => Debounce[YellowA, oldValue, newValue, YellowB]; YellowB => Debounce[YellowB, oldValue, newValue, YellowA]; BlueA => Debounce[BlueA, oldValue, newValue, BlueB]; BlueB => Debounce[BlueB, oldValue, newValue, BlueA]; TestEnable => TestEnableC[oldValue, newValue]; Gnd => GndC[oldValue, newValue]; YA => Driver[YA]; YB => Driver[YB]; XA => Driver[XA]; XB => Driver[XB]; TestData => IF testEnabled THEN TestDataC[oldValue, newValue] ELSE Driver[PhiLong]; TestClock => IF testEnabled THEN TestClockC[oldValue, newValue] ELSE Driver[PhiShort]; GateTest => GateTestC[oldValue, newValue]; Vdd => VddC[oldValue, newValue]; AnyGood => Driver[AnyGood]; Jump => Driver[Jump]; ENDCASE}; testEnabled: BOOLEAN ← FALSE; testDataBit: BOOLEAN ← FALSE; lastTestDataBit: BOOLEAN ← FALSE; secondToLastTestDataBit: BOOLEAN ← FALSE; testWord: WORD ← 0; lastTestWord: WORD ← 0; newTestWord: WORD ← 0; xA: Mouse.Value ← zero; xB: Mouse.Value ← zero; xL: Mouse.Value ← zero; yA: Mouse.Value ← zero; yB: Mouse.Value ← zero; yL: Mouse.Value ← zero; phiLong: Mouse.Value ← one; phiShort: Mouse.Value ← zero; anyGood: Mouse.Value ← zero; jump: Mouse.Value ← zero; Counter: TYPE = RECORD [A, B, L: POINTER TO Mouse.Value]; xCounter: Counter = [@xA, @xB, @xL]; yCounter: Counter = [@yA, @yB, @yL]; Direction: TYPE = {Down, Stay, Up}; Distance: TYPE = {Stay, Half, Full}; pinSource: ARRAY Mouse.Pin OF POINTER TO Mouse.Value = [ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, yCounter.A, yCounter.B, xCounter.A, xCounter.B, @phiLong, @phiShort, NIL, NIL, @anyGood, @jump]; VNOT: PROCEDURE [value: Value] RETURNS [valueInverse: Value] = { IF value # x THEN {value ← IF value = zero THEN one ELSE zero}; RETURN[value]}; State: TYPE = [0..7] ← 0; CountRecord: TYPE = RECORD [A, B, L: Mouse.Value]; StateFromCounter: ARRAY Value OF ARRAY Value OF ARRAY Value OF State = [ zero: [zero: [zero: 0, one: 7], one: [zero: 2, one: 1]], one: [zero: [zero: 6, one: 5], one: [zero: 4, one: 3]]]; CounterFromState: ARRAY State OF CountRecord = [ [zero, zero, zero], [zero, one, one], [zero, one, zero], [one, one, one], [ one, one, zero], [one, zero, one], [one, zero, zero], [zero, zero, one]]; Count: PROCEDURE [counter: Counter, dir: Direction, dist: Distance] = { OPEN InlineDefs; state: INTEGER; delta: INTEGER; cr: CountRecord; SELECT dist FROM Stay => RETURN; Half => delta ← 1; Full => delta ← 2; ENDCASE; SELECT dir FROM Down => delta ← (-delta); Stay => RETURN; Up => NULL ENDCASE; state ← StateFromCounter[counter.A↑][counter.B↑][counter.L↑]; state ← (state + delta + 8) MOD 8; cr ← CounterFromState[state]; counter.A↑ ← cr.A; counter.B↑ ← cr.B; counter.L↑ ← cr.L}; Debounce: PROCEDURE [ pin: Mouse.Pin, oldValue, newValue: Mouse.Value, otherPin: Mouse.Pin] = { IF newValue = x THEN { IF drivenPinState[otherPin] = x THEN { currentPinState[otherPin] ← VNOT[oldValue]}; currentPinState[pin] ← VNOT[currentPinState[otherPin]]} ELSE { currentPinState[pin] ← newValue; IF drivenPinState[otherPin] = x THEN { currentPinState[otherPin] ← VNOT[currentPinState[pin]]}}}; Driver: PROCEDURE [pin: Mouse.Pin] = { currentPinState[pin] ← IF drivenPinState[pin] = x THEN pinSource[pin]↑ ELSE drivenPinState[pin]}; TestEnableC: PROCEDURE [oldValue, newValue: Mouse.Value] = { currentPinState[TestEnable] ← newValue; testEnabled ← newValue = one; IF NOT testEnabled THEN { currentPinState[TestData] ← pinSource[TestData]↑; currentPinState[TestClock] ← pinSource[TestClock]↑}}; TestDataC: PROCEDURE [oldValue, newValue: Mouse.Value] = {}; TestClockC: PROCEDURE [oldValue, newValue: Mouse.Value] = { IF (oldValue = zero AND newValue = one) THEN { lastTestDataBit ← NOT (drivenPinState[TestData] = one)}; IF (oldValue = one AND newValue = zero) THEN { SELECT version FROM Rev3 => {testWord ← BITOR[BITSHIFT[testWord, 1], IF lastTestDataBit THEN 1 ELSE 0]}; Rev4, Rev5 => {testWord ← BITOR[ BITSHIFT[testWord, -1], IF testDataBit THEN 0 ELSE 100000B]; testDataBit ← lastTestDataBit}; Rev6, Rev7 => {testWord ← BITOR[ BITSHIFT[testWord, -1], IF testDataBit THEN 0 ELSE 100000B]; testDataBit ← secondToLastTestDataBit; secondToLastTestDataBit ← lastTestDataBit}; ENDCASE; }}; MoveDirection: TYPE = { UpLeft, Left, DownLeft, Up, Stayed, Down, UpRight, Right, DownRight}; ShiftCount: TYPE = [-15..15]; Mask: ARRAY MoveDirection OF WORD = [ 3567B, 7777B, 7356B, 73567B, 177777B, 167356B, 73560B, 177760B, 167340B]; Shift: ARRAY MoveDirection OF ShiftCount = [-5, -4, -3, -1, 0, 1, 3, 4, 5]; Move: ARRAY MoveDirection OF BOOLEAN ← ALL[FALSE]; MakeMove: PROCEDURE [md: MoveDirection, dist: Distance] = { SELECT md FROM UpLeft => {Count[yCounter, Down, dist]; Count[xCounter, Down, dist]}; Left => {Count[xCounter, Down, dist]}; DownLeft => {Count[yCounter, Up, dist]; Count[xCounter, Down, dist]}; Up => {Count[yCounter, Down, dist]}; Stayed => NULL; Down => {Count[yCounter, Up, dist]}; UpRight => {Count[yCounter, Down, dist]; Count[xCounter, Up, dist]}; Right => {Count[xCounter, Up, dist]}; DownRight => {Count[yCounter, Up, dist]; Count[xCounter, Up, dist]} ENDCASE; currentPinState[Jump] ← zero; currentPinState[AnyGood] ← one; }; ResolveMove: PROCEDURE [md1, md2: MoveDirection] = { IF md2 = Left THEN {md2 ← md1; md1 ← Left}; IF md2 = Stayed THEN {md2 ← md1; md1 ← Stayed}; SELECT md1 FROM Stayed => MakeMove[md2, Half]; Left => { SELECT md2 FROM Up => MakeMove[UpLeft, Half]; Down => MakeMove[DownLeft, Half] ENDCASE}; Right => { SELECT md2 FROM Up => MakeMove[UpRight, Half]; Down => MakeMove[DownRight, Half] ENDCASE} ENDCASE}; Moved: PROCEDURE [last, new: WORD] = { OPEN InlineDefs; cMoves: CARDINAL ← 0; mdA, mdB: MoveDirection ← Stayed; FOR d: MoveDirection IN MoveDirection DO Move[d] ← BITAND[BITAND[last, BITSHIFT[new, Shift[d]]], Mask[d]] # 0; ENDLOOP; FOR d: MoveDirection IN MoveDirection DO IF Move[d] THEN {cMoves ← cMoves + 1; mdB ← mdA; mdA ← d}; ENDLOOP; currentPinState[Jump] ← one; currentPinState[AnyGood] ← zero; SELECT cMoves FROM 0 => NULL; 1 => MakeMove[mdA, Full]; 2 => ResolveMove[mdA, mdB] ENDCASE; Driver[XA]; Driver[XB]; Driver[YA]; Driver[YB]; Driver[Jump]; Driver[AnyGood]}; GateTestC: PROCEDURE [oldValue, newValue: Mouse.Value] = { IF (oldValue = zero AND newValue = one) THEN {newTestWord ← testWord; }; IF (oldValue = one AND newValue = zero) THEN { Moved[lastTestWord, newTestWord]; lastTestWord ← newTestWord}}; GndC: PROCEDURE [oldValue, newValue: Mouse.Value] = { currentPinState[Gnd] ← zero}; VddC: PROCEDURE [oldValue, newValue: Mouse.Value] = { currentPinState[Gnd] ← one}; Reset; }. MPH 30-Sep-81 15:46:15 created initially