-- MouseSimImpl.mesa
-- created by Haeberli: 30-Sep-81 15:46:15
-- added new versions, R. Garner April 13, 1982 4:03 PM
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 ← Rev5;
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, Rev5A => {testWord ← BITOR[
BITSHIFT[testWord, -1], IF testDataBit THEN 0 ELSE 100000B];
testDataBit ← lastTestDataBit};
Rev6A, Rev6B, Rev7A, Rev7B, Rev8, Rev9 => {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