Skip to content

Delayed and immediate transitions

When a transition is checked, how several transitions can fire in one tick, and how a chart finishes.

Every transition you have written so far has waited. A chart enters a state in one tick and can leave it in the next tick at the earliest, which is why nothing seemed to happen in tick 1. That rhythm keeps charts easy to follow, but some decisions belong to the moment of arrival. A lock that has just been given a code should say yes or no straight away; a controller that starts up should look at its inputs in tick 1, not in tick 2.

SCCharts lets you choose, one transition at a time. A delayed transition waits; an immediate transition may fire in the same tick its state was entered. This chapter shows both, what happens when immediate transitions follow one another within a tick, why KIELER refuses some charts that look harmless, and how a chart comes to an end in a final state.

Stairs climbs from Ground to Second, one floor at a time, while the input up is true. Its transitions are written the way you have written transitions so far. In the tour, up is true from tick 1, yet the chart only reaches the top in tick 3.

StairsSimulation

Diagram

Diagram of StairsStates: Ground (initial), First, Second. Transitions: Ground to First: up / floor = 1; First to Second: up / floor = 2.Stairsinput boolupoutput intfloor = 0GroundFirstSecondup/ floor = 1up/ floor = 2

Code

scchart Stairs {
input bool up
output int floor = 0
initial state Ground
if up do floor = 1 go to First
state First
if up do floor = 2 go to Second
state Second
}
Tick 0 of 4
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Stairs
Tickinput bool upoutput int floorActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 4 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 4 ticks:

  1. up = trueTick 1 enters Ground. up is already true, but Ground’s transition is delayed, and a delayed transition is never checked in the tick its state was entered (the state’s entry tick).
  2. Ground was entered in an earlier tick, so now its transition is checked. up is still true (an input keeps its value), so the chart moves to First and floor becomes 1. This is First’s entry tick, so First’s delayed transition waits.
  3. First’s transition may fire now: up is true, so the chart climbs to Second and floor is 2. A chain of delayed transitions moves at most one step per tick.
  4. Second has no outgoing transitions, so the chart stays there.
up is true in every tick, but floor changes at most once per tick.
Tick up State after floor after
1 true Ground 0
2 true (held) First 1
3 true (held) Second 2
4 true (held) Second 2

Two things hold the climb up. In tick 1, Ground has only just been entered; in tick 2, First has only just been entered. The tick in which a state is entered is that state’s entry tick, and the rule for an ordinary transition is short: it is never checked in its source state’s entry tick. In every later tick in which the state is still active, it is checked as usual.

Tick 1 is nothing more than the entry tick of the initial state, which is why a transition out of the initial state can fire in tick 2 at the earliest. But the rule is about every state, whenever it is entered: First is entered in tick 2, so its transition has to wait until tick 3. A chain of delayed transitions moves at most one step per tick. Every transition without a keyword is delayed.

Write immediate in front of a transition and it is checked in its source state’s entry tick too:

initial state Ground
immediate if up do floor = 1 go to First

Lift is Stairs with both transitions immediate. Here are the two side by side, with the same input:

Stairs and LiftComparison

Diagrams

Stairs

Diagram of StairsStates: Ground (initial), First, Second. Transitions: Ground to First: up / floor = 1; First to Second: up / floor = 2.Stairsinput boolupoutput intfloor = 0GroundFirstSecondup/ floor = 1up/ floor = 2

Lift

Diagram of LiftStates: Ground (initial), First, Second. Transitions: Ground to First: up / floor = 1; First to Second: up / floor = 2.Liftinput boolupoutput intfloor = 0GroundFirstSecondup/ floor = 1up/ floor = 2

Code

Stairs

scchart Stairs {
input bool up
output int floor = 0
initial state Ground
if up do floor = 1 go to First
state First
if up do floor = 2 go to Second
state Second
}

Lift

scchart Lift {
input bool up
output int floor = 0
initial state Ground
immediate if up do floor = 1 go to First
state First
immediate if up do floor = 2 go to Second
state Second
}
Tick 0 of 4
Inputs for tick 1, for both charts Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Stairs and Lift, no ticks yet
Tickinput bool upStairs: output int floorStairs: Active state of the chartLift: output int floorLift: Active state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 4 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 4 ticks, the same inputs for both charts:

  1. up = trueup is true from tick 1. Stairs enters Ground and stops there: its transition is delayed, so it is not checked in Ground’s entry tick. Lift enters Ground too, but its transition is immediate: it fires at once, and so does First’s, so Lift ends tick 1 in Second with floor 2.
  2. Stairs checks Ground’s transition now: it climbs to First, and floor is 1. First was entered in this tick, so its delayed transition waits. Lift is already at the top.
  3. Stairs reaches Second, two ticks after Lift: a chain of delayed transitions moves at most one step per tick.
  4. Both charts are in Second, which has no outgoing transitions.
The same input and the same states: Lift reaches Second in tick 1, Stairs in tick 3.

In tick 1, Lift enters Ground and checks its immediate transition at once: up is true, so the chart moves to First and sets floor to 1. Entering First makes tick 1 First’s entry tick as well, and First’s transition is immediate too, so it is checked straight away: the chart moves on to Second and floor becomes 2. All of this happens within tick 1. Only the values at the end of a tick are reported, so the 1 is never seen.

Tick up Stairs after Lift after
1 true Ground, floor 0 Second, floor 2
2 true (held) First, floor 1 Second, floor 2
3 true (held) Second, floor 2 Second, floor 2

A tick keeps following transitions for as long as it can: after every transition it checks the immediate transitions of the state it has just entered, and it stops at the first state where none of them is enabled. So one tick can pass through any number of states. Each transition’s effects run before the next transition is checked, so a trigger further along the chain sees the values written earlier in the same tick. When you step a simulation, every transition taken in the tick is highlighted, so a chain shows up as a path through the diagram.

The first link of a chain may be a delayed transition. When a delayed transition fires in tick 5, its target is entered in tick 5, and the target’s immediate transitions are checked in tick 5 too. Lock relies on this: it waits in Idle until enter is true, then passes through Check, which decides at once whether the code was right.

LockSimulation

Diagram

Diagram of LockStates: Idle (initial), Check. Transitions: Idle to Check: enter / tries += 1; Check to Idle: 1: code == 42 / open = true; Check to Idle: 2: / open = false.Lockinput intcodeinput boolenteroutput boolopen = falseoutput inttries = 0IdleCheckenter/ tries += 11: code == 42/ open = true2: / open = false

Code

scchart Lock {
input int code
input bool enter
output bool open = false
output int tries = 0
initial state Idle
if enter do tries += 1 go to Check
state Check
immediate if code == 42 do open = true go to Idle
immediate do open = false go to Idle
}
Tick 0 of 5
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Lock
Tickinput int codeinput bool enteroutput bool openoutput int triesActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 5 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 5 ticks:

  1. code = 42, enter = trueTick 1 enters Idle. Its transition is delayed, so enter has no effect yet.
  2. code = 7enter is still true, so Idle → Check fires and tries is 1. Check’s transitions are immediate and Check has just been entered, so they are checked in this tick: code is 7, so priority 1 fails, and priority 2, which has no trigger, takes the chart back to Idle with open false. Check was entered and left within the tick.
  3. enter = falseenter is false, so the chart stays in Idle.
  4. code = 42, enter = trueIdle → Check → Idle again, but this time code is 42, so priority 1 fires and open becomes true. tries is 2.
  5. enter = falseNothing fires. open keeps its value: it is a variable, and nothing assigned it in this tick.
Watch tick 2: the chart goes from Idle to Check and back to Idle within one tick.

In the diagram, an immediate transition is drawn as a dashed arrow: Check’s two transitions are dashed, and the delayed one out of Idle is solid.

Check is a state you never see at the end of a tick: it is entered and left in the same tick, every time. Its second transition has no trigger, so it is the default when the code is wrong, and because it is immediate as well, the chart is back in Idle in the same tick whichever way the check went. That default has to come last, as in chapter 3: written first, it would fire in every entry tick of Check, and KIELER would warn The transition is not reachable. on the code check after it. Notice also that enter keeps its value: while it stays true, Lock checks the code again in every tick.

You already know that a state’s outgoing transitions are checked in priority order and that the first enabled one wins (Triggers, effects and priority). Once delayed and immediate transitions are mixed, the question is which of them take part in that contest. Race has one of each: priority 1 is delayed, priority 2 is immediate.

RaceSimulation

Diagram

Diagram of RaceStates: Choose (initial), Done. Transitions: Choose to Done: 1: A / path = 1; Choose to Done: 2: B / path = 2; Done to Choose.Raceinput boolA, Boutput intpath = 0ChooseDone1: A/ path = 12: B/ path = 2

Code

scchart Race {
input bool A, B
output int path = 0
initial state Choose
if A do path = 1 go to Done
immediate if B do path = 2 go to Done
state Done
go to Choose
}
Tick 0 of 6
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Race
Tickinput bool Ainput bool Boutput int pathActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 6 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 6 ticks:

  1. A = true, B = trueTick 1 enters Choose. In a state’s entry tick only its immediate transitions are candidates, so priority 1 (if A, delayed) is skipped although A is true. Priority 2 (immediate if B) fires: path is 2.
  2. B = falseDone’s transition has no trigger, so it fires in the tick after Done’s entry tick: back to Choose. This is Choose’s entry tick again, so only the immediate transition counts, and B is false. A is true, but the delayed transition must wait.
  3. B = trueChoose was entered in an earlier tick, so now both transitions are candidates, checked in priority order. A is true, so priority 1, the delayed one, wins: path is 1. The immediate transition was enabled too, but priority decides.
  4. Two transitions in one tick. Done → Choose fires (Done was entered in tick 3). Choose has just been entered, so its immediate transition is checked at once: B is true, it fires, and path is 2.
  5. A = false, B = falseDone → Choose again. Both inputs are false, so the chart stays in Choose.
  6. B = trueChoose is no longer in its entry tick. A is false, so priority 1 fails, and priority 2 fires: an immediate transition is checked in later ticks too, not only on entry.
path records which transition fired last: 1 for the delayed one, 2 for the immediate one.

Done has one untriggered delayed transition back to Choose, so the chart keeps returning to Choose: in some ticks Choose has just been entered, in others it was already active.

The column Entry tick says whether Choose was entered in that tick:

Tick A B Entry tick State after path after
1 true true yes Done 2
2 true (held) false yes Choose 2
3 true (held) true no Done 1
4 true (held) true (held) yes Done 2
5 false false yes Choose 2
6 false (held) true no Done 2

Those six ticks show the whole rule:

  • In a state’s entry tick, only its immediate transitions are candidates, in priority order. In tick 1 the delayed priority 1 is skipped although A is true, and the immediate priority 2 fires. In tick 2 B is false, so nothing fires, and the chart stays in Choose.
  • In every later tick, all of the state’s transitions are candidates, in priority order. In tick 3 both are enabled, and the delayed priority 1 wins. Being immediate does not make a transition go first.
  • An immediate transition is not limited to the entry tick. In tick 6 it fires in a tick in which Choose was already active, because A is false.

Tick 4 is a chain that starts with a delayed transition: Done → Choose fires, Choose has just been entered, so its immediate transition is checked and fires in the same tick. In short, immediate changes when a transition may be checked; it never changes its priority.

What if a chain comes back to where it started? Spin tries to count to three with an immediate self-loop.

SpinChart

Diagram

Diagram of SpinStates: Counting (initial). Transitions: Counting to Counting: n < 3 / n += 1.Spinoutput intn = 0Countingn < 3/ n += 1

Code

scchart Spin {
output int n = 0
initial state Counting
immediate if n < 3 do n += 1 go to Counting
}

KIELER rejects this chart

  • Line 5, column 5The immediate transitions Counting → Counting form a loop that could run for ever within one tickKIELER says: The SCG is NOT asc-schedulable!Make one transition on the loop delayed (remove immediate): a tick must always end. KIELER rejects such a loop even if the triggers would stop it.About this message
Also a warning: These immediate transitions form a loop (Counting)
  • Warning, line 5, column 5KIELER says: There is an immediate loop. The model is not SASC. Involved states: [Counting]If all of them fire, the chart would run around the loop forever in one tick. Make at least one transition of the loop delayed (remove immediate).About this message
KIELER refuses to compile Spin: its self-loop is immediate.

KIELER does not run this chart. What it reports:

  • errors from the scheduler: one or more lines like Can't schedule from _g1 to _cg1, then The SCG is NOT asc-schedulable!;
  • the warning Instantaneous loop detected!;
  • on the transition itself, the warning There is an immediate loop. The model is not SASC., followed by the states involved.

SCCharts Lab shows the same errors plus a plainer one, Circular dependency prevents scheduling this tick., and words the warning Potential instantaneous loop.

The reason is that a tick must end. KIELER compiles each tick into a fixed sequence of steps, and a cycle of immediate transitions would need to go back to an earlier step, possibly for ever. You can see that n < 3 stops Spin after three rounds, but the compiler does not look at triggers: the check is about the shape of the chart. Every cycle made only of immediate transitions is rejected, whatever its triggers say. This one is refused too, although its two guards can never both be true:

initial state Ping
immediate if flip go to Pong
state Pong
immediate if !flip go to Ping

The fix is always the same: make at least one transition on the cycle delayed. A delayed transition cannot fire again in the tick its state was re-entered, so a cycle through it goes round at most once per tick. CountSteps is Spin without the keyword immediate:

CountStepsSimulation

Diagram

Diagram of CountStepsStates: Counting (initial). Transitions: Counting to Counting: n < 3 / n += 1.CountStepsoutput intn = 0Countingn < 3/ n += 1

Code

scchart CountSteps {
output int n = 0
initial state Counting
if n < 3 do n += 1 go to Counting
}
Tick 0 of 5
Timing diagram of CountSteps
Tickoutput int nActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 5 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 5 ticks:

  1. Tick 1 enters Counting. The self-loop is delayed, so it does not fire in Counting’s entry tick.
  2. n < 3 holds, so the self-loop fires and n is 1. Taking the loop leaves Counting and enters it again, which makes this tick Counting’s entry tick: the delayed loop cannot fire a second time in it.
  3. The loop fires once more: n is 2.
  4. n is 3.
  5. n < 3 is false now, so the loop does not fire. The chart rests in Counting for good.
One step per tick: n becomes 1, 2 and 3 in ticks 2, 3 and 4.

Lock has a cycle as well, Idle → Check → Idle, and KIELER accepts it because the transition out of Idle is delayed. If you really want three steps of work in one tick, don’t loop: write the result directly (n = 3), or spread the work over several ticks as CountSteps does. The chapter Why the compiler says no explains the scheduling behind these messages.

A state written with final is a final state; the diagram gives it a double outline. When the chart’s top level is in a final state at the end of a tick, the chart terminates in that tick, and from then on it does nothing at all. (With several concurrent regions at the top level, every one of them must be in a final state; that comes in Concurrent regions.) In this guide’s timing diagrams, a small triangle next to a tick’s number marks the tick in which the chart terminated.

Finish counts one lap and stops. Its final state even has a transition back to Lap. Predict what happens, run it, then open the explanation:

FinishPrediction

Diagram

Diagram of FinishStates: Lap (initial), Done (final). Transitions: Lap to Done: next / laps += 1; Done to Lap: next.Finishinput boolnextoutput intlaps = 0LapDonenext/ laps += 1next

Code

scchart Finish {
input bool next
output int laps = 0
initial state Lap
if next do laps += 1 go to Done
final state Done
if next go to Lap
}

next is true in ticks 1 to 3 and false in tick 4.

Inputs per tick. A value in grey was not set in that tick: it holds from an earlier one.

Ticknext
1true
2true
3true
4false
Plays the scenario on the diagram, then marks each answer.
Explanation

In tick 2, Lap → Done fires and laps becomes 1. The chart ends the tick in a final state, so it terminates in tick 2. In tick 3, next is still true, and an ordinary state would now take Done’s transition back to Lap; but a terminated chart checks nothing, so laps stays 1 for good.

A few details, all visible in KIELER’s simulator:

  • The transition into the final state runs its effects as usual; termination happens at the end of that tick.
  • A chart can terminate in tick 1, if a chain of immediate transitions from the initial state reaches a final state.
  • “Final” means “may count as finished”, not “stop here”. If a final state has an immediate transition that is enabled when the state is entered, the chain continues, the chart does not end the tick in a final state, and nothing terminates.

Most controllers never terminate: they run as long as the device is switched on. Final states earn their keep inside superstates, where reaching one lets the superstate finish and move on with join to (Superstates). One KIELER quirk to know about already: a chart that declares a signal never terminates in KIELER’s simulator (Signals and termination).

You may meet two more keywords in front of transitions. delayed says explicitly what no keyword means. auto is a leftover that KIELER still accepts, and it also means delayed; the first example on the KIELER wiki’s syntax page uses it.

initial state A
auto do step = 1 go to B
state B
delayed do step = 2 go to C
final state C

Both transitions behave exactly like transitions without a keyword: this chart is in A after tick 1, in B after tick 2 (step 1), and reaches C in tick 3, where it terminates with step 2. Write transitions without a keyword, and use immediate where you mean it.

Decide in tick 1

Startup should look at ok in tick 1: if ok is true it sets running and goes to Ready, otherwise it goes to the final state Fault. As written, it decides one tick late. Change it so that the decision is made in tick 1. Then try ok false in tick 1: in which tick does the chart terminate?

Show the starter chart
scchart Startup {
input bool ok
output bool running = false
initial state Check
if ok do running = true go to Ready
go to Fault
state Ready
final state Fault
}
Show a solution
scchart Startup {
input bool ok
output bool running = false
initial state Check
immediate if ok do running = true go to Ready
immediate go to Fault
state Ready
final state Fault
}

Break the loop

KIELER rejects Door. Make it compile with the smallest change you can find, keeping this behaviour: if open is true in tick 1, the door is already open at the end of tick 1.

Show the starter chart
scchart Door {
input bool open
output bool isOpen = false
initial state Closed
immediate if open do isOpen = true go to Opened
state Opened
immediate if !open do isOpen = false go to Closed
}
Show a solution
scchart Door {
input bool open
output bool isOpen = false
initial state Closed
immediate if open do isOpen = true go to Opened
state Opened
if !open do isOpen = false go to Closed
}
A delayed transition from Idle to Check fires in tick 5. Check has one outgoing transition, immediate if x > 0 go to Done, and x is 3. Which state is the chart in at the end of tick 5?
Show the answer

Answer C: Done: Check is entered in tick 5, so its immediate transition is checked in tick 5 too

Entering a state, by any transition and in any tick, makes that tick the state’s entry tick, and its immediate transitions are checked at once. The delayed transition starts the chain; the immediate one continues it in the same tick.

Choose has two outgoing transitions: priority 1 is if A go to X, priority 2 is immediate if B go to Y. Choose was entered two ticks ago. In this tick A and B are both true. What happens?
Show the answer

Answer A: Priority 1 fires and the chart goes to X

Outside its entry tick, all of a state’s transitions are candidates, in priority order, and the first enabled one wins. immediate only matters in the entry tick, when the delayed transition would not have been a candidate.

Which of these charts does KIELER accept?
Show the answer

Answer C: A goes to B with immediate if I, and B goes back to A with if !I

The first two contain a cycle made only of immediate transitions, which KIELER rejects whatever the triggers say (The SCG is NOT asc-schedulable!). The third cycle contains a delayed transition, so it can go round at most once per tick.

Key ideas

  • A state’s entry tick is the tick in which it is entered. Delayed transitions (no keyword, delayed or auto) are not checked in it; immediate transitions are.
  • After the entry tick, all of a state’s transitions compete in priority order. immediate never raises a transition’s priority.
  • A tick follows immediate transitions until it reaches a state where none is enabled. A delayed transition can start such a chain.
  • KIELER rejects every cycle made only of immediate transitions, whatever the guards. Make one transition on the cycle delayed.
  • When the top level is in a final state at the end of a tick, the chart terminates and does nothing from then on.

Next, Variables, types and expressions: the data a chart works with, from booleans to arrays.

Report a mistake on this page