-------------------------------------------------------------------------
-- Rether protocol
-- Realtime First (RTF) version
-- translated to Murphi by Yifei Dong
-- October 1998
-------------------------------------------------------------------------
CONST
NUM_NODES : 5; -- number of nodes in the network
NUM_SLOTS : 3; -- number of RT+NRT time slots per cycle
NUM_MAXRT : NUM_SLOTS-1; -- maximal number of RT time slots
MAX_NODE_ID : NUM_NODES-1;
TYPE
NodeID : 0..MAX_NODE_ID;
SlotsNum : 0..NUM_SLOTS;
Token : RECORD
servingRealtime : BOOLEAN;
realtimeMode : ARRAY [NodeID] OF BOOLEAN;
rtSlots : SlotsNum;
nrtSlotsAvail : SlotsNum;
nextNRTNode : NodeID;
END;
NodeState : ENUM {
NODE_START,
NODE_RT,
NODE_NRT
};
CycleState : ENUM {
CYCLE_START,
CYCLE_MIDDLE,
CYCLE_END
};
Action : ENUM {
null,
rt,
nrt,
reserve,
startcycle,
endcycle
};
VAR
token : Token;
gottoken : ARRAY [NodeID] OF BOOLEAN;
state : ARRAY [NodeID] OF NodeState;
cyclestate : CycleState;
-- auxilary monitoring variables
action : Action;
num_starts : -1..2;
reservednow : ARRAY [NodeID] OF BOOLEAN; -- reserved RT in this cycle
reservedlast: ARRAY [NodeID] OF BOOLEAN; -- reserved RT in last cycle
RTserved : ARRAY [NodeID] OF BOOLEAN; -- served RT in this cycle
NRTserved : ARRAY [NodeID] OF BOOLEAN; -- served RT in this cycle
-------------------------------------------------------------------------
PROCEDURE incID(VAR n:NodeID);
BEGIN
n := (n+1) % NUM_NODES;
END;
PROCEDURE observe(node:NodeID; a:Action);
VAR
n: NodeID;
BEGIN
action := a;
SWITCH a
CASE reserve:
reservednow[node] := true;
RTserved[node] := false;
CASE rt:
-- property rt-1
ASSERT(! reservednow[node]); -- node is not researved in this cycle
-- property rtf
ASSERT(FORALL i:NodeID DO !NRTserved[i] END);
RTserved[node] := true;
CASE nrt:
NRTserved[node] := true;
CASE startcycle:
num_starts := num_starts+1;
ASSERT(num_starts <= 1); -- property cc-2
FOR n:=0 TO MAX_NODE_ID DO
reservedlast[n] := reservednow[n];
END;
CLEAR reservednow;
CLEAR RTserved;
CLEAR NRTserved;
CASE endcycle:
num_starts := num_starts-1;
-- property rt-2
ASSERT(FORALL i:NodeID DO reservedlast[i] -> RTserved[i] END);
-- property rtt
ASSERT(EXISTS i:NodeID DO RTserved[i] END);
-- property nrt
ASSERT(EXISTS i:NodeID DO NRTserved[i] END);
END;
END;
PROCEDURE PassTokenTo(node:NodeID);
BEGIN
ASSERT(! gottoken[node]);
gottoken[node] := true;
END;
PROCEDURE releaseRT(node:NodeID);
BEGIN
ASSERT(token.realtimeMode[node]);
IF token.rtSlots > 1 THEN
token.rtSlots := token.rtSlots - 1;
token.realtimeMode[node] := FALSE;
END;
END;
PROCEDURE reserveRT(node:NodeID);
BEGIN
ASSERT(! token.realtimeMode[node]);
IF token.rtSlots < NUM_MAXRT THEN
observe(node, reserve);
token.rtSlots := token.rtSlots + 1;
token.realtimeMode[node] := TRUE;
END;
END;
PROCEDURE rtPassToken(node:NodeID);
VAR
n : NodeID;
BEGIN
state[node] := NODE_START;
-- If there is the next RT node, pass the token to it
IF node < MAX_NODE_ID THEN
FOR n := node+1 TO MAX_NODE_ID DO
IF token.realtimeMode[n] THEN
PassTokenTo(n);
RETURN;
END;
END;
END;
-- else pass the token to the next NRT node
token.servingRealtime := FALSE;
PassTokenTo(token.nextNRTNode);
END;
PROCEDURE nrtPassToken(node:NodeID);
BEGIN
state[node] := NODE_START;
incID(token.nextNRTNode);
ASSERT(token.nrtSlotsAvail > 0);
token.nrtSlotsAvail := token.nrtSlotsAvail - 1;
IF token.nrtSlotsAvail > 0 THEN
PassTokenTo(token.nextNRTNode);
ELSE
cyclestate := CYCLE_END;
END;
END;
-------------------------------------------------------------------------
RULESET node:NodeID DO
RULE "get token"
state[node] = NODE_START &
gottoken[node]
==>
BEGIN
gottoken[node] := FALSE;
IF token.servingRealtime THEN
ASSERT(token.realtimeMode[node]);
observe(node, rt);
state[node] := NODE_RT;
ELSE
observe(node, nrt);
state[node] := NODE_NRT;
ENDIF;
END;
RULE "realtime mode -- release"
state[node] = NODE_RT
==>
BEGIN
releaseRT(node);
rtPassToken(node);
END;
RULE "realtime mode -- no release"
state[node] = NODE_RT
==>
BEGIN
rtPassToken(node);
END;
RULE "non-realtime mode -- reserve"
state[node] = NODE_NRT
& ! token.realtimeMode[node]
==>
BEGIN
reserveRT(node);
nrtPassToken(node);
END;
RULE "non-realtime mode -- no reserve"
state[node] = NODE_NRT
==>
BEGIN
nrtPassToken(node);
END;
ENDRULESET;
-------------------------------------------------------------------------
RULE "start of cycle"
cyclestate = CYCLE_START
==>
VAR
n: NodeID;
BEGIN
observe(0, startcycle);
token.servingRealtime := TRUE;
-- pass the token to the first RT node
FOR n := 0 TO MAX_NODE_ID DO
IF token.realtimeMode[n] THEN
cyclestate := CYCLE_MIDDLE;
PassTokenTo(n);
RETURN;
END;
END;
ERROR "no realtime node";
END;
RULE "end of cycle"
cyclestate = CYCLE_END
==>
VAR
n : NodeID;
BEGIN
observe(0, endcycle);
token.nrtSlotsAvail := NUM_SLOTS - token.rtSlots;
cyclestate := CYCLE_START;
END;
-------------------------------------------------------------------------
LIVENESS "ns"
ALWAYS EVENTUALLY NRTserved[0];
-------------------------------------------------------------------------
STARTSTATE
CLEAR token;
token.realtimeMode[0] := TRUE;
token.rtSlots := 1;
token.nextNRTNode := 0;
token.nrtSlotsAvail := NUM_SLOTS - token.rtSlots;
CLEAR gottoken;
CLEAR state;
cyclestate := CYCLE_START;
CLEAR action;
num_starts := 0;
CLEAR reservednow;
CLEAR reservedlast;
CLEAR RTserved;
CLEAR NRTserved;
END;