-- 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