Skip to content

Short on time?

For the evening before a lab: set up in three steps, build one small chart in five, meet the eight surprises that catch everyone, and revise every chapter’s key ideas.

Every part links to the chapter with the full story. If you only want to revise, skip to the key ideas at the end. When you have more time, Learn teaches all of it properly, with exercises.

  1. Install VS Code, then the SCCharts Lab extension from the Extensions view (Ctrl+Shift+X, or Cmd+Shift+X on a Mac). If KIELER’s own extension, KIELER VS Code, is installed, disable or uninstall it and reload the window: the two cannot run side by side.

  2. Make sure there is a C compiler, because simulation compiles your chart to C. On Windows the first simulation offers to download one. On Linux install gcc with your package manager. On macOS run this in a terminal:

    Terminal window
    xcode-select --install

    Java comes with the extension on Windows (x64), Apple Silicon Macs and Linux (x64).

  3. Save a chart as a file ending in .sctx, open the diagram preview (Ctrl+Alt+V), press Simulate… and choose Netlist-based Simulation (C). Then Step runs one tick.

Getting SCCharts has the details, a chart to check your setup with, and the other tools. Everything below also runs in this page, and in the playground, with nothing installed.

The chart is a microwave oven: a start button, a door, a heater and a lamp. Each step adds one idea to the version before. Press Step to run a tick yourself, or Next to follow the guided tour, which explains every tick.

MicrowaveSimulation

Diagram

Diagram of MicrowaveStates: Idle (initial), Cooking. Transitions: Idle to Cooking: start / heating = true; Cooking to Idle: door / heating = false.Microwaveinput boolstart, dooroutput boolheating = falseIdleCookingstart/ heating = truedoor/ heating = false

Code

scchart Microwave {
input bool start, door
output bool heating = false
initial state Idle
if start do heating = true go to Cooking
state Cooking
if door do heating = 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. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Microwave
Tickinput bool startinput bool dooroutput bool heatingActive 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. start = true, door = falseTick 1 enters Idle. start is already true, but a transition is not checked in the tick its state is entered, so nothing else happens.
  2. start is still true: an input keeps its value until it is changed. Now Idle’s transition is checked. It fires, sets heating to true and moves to Cooking, all in this tick.
  3. start = falsestart is released. Cooking only reacts to door, so nothing fires, and heating keeps the value it was given in tick 2.
  4. door = trueThe door opens. The transition back to Idle fires and switches heating off in the same tick.
  5. door = falseThe door shuts. Idle waits for the next start.
start is already true in tick 1, but the oven only starts heating in tick 2.

A chart is scchart Name { … }. Declarations come first, without semicolons: an input is set by the environment (you, in the simulator), an output by the chart. Then the states, one of them initial. Under each state come its transitions, written if trigger do effect go to Target.

Each tick the chart reads its inputs, checks the transitions of the state it is in, takes the first whose trigger holds, and writes its outputs. Tick 1 only enters the initial state: a transition is checked from the tick after its state was entered. Thinking in ticks and Your first SCChart explain both.

The first version has a flaw. Press start with the door open and it heats anyway: with both inputs left on, it switches the heater on and off in alternate ticks. The fix is a second transition out of Idle, written first:

MicrowaveSimulation

Diagram

Diagram of MicrowaveStates: Idle (initial), DoorOpen, Cooking. Transitions: Idle to DoorOpen: 1: door; Idle to Cooking: 2: start / heating = true; DoorOpen to Idle: !door; Cooking to DoorOpen: door / heating = false.Microwaveinput boolstart, dooroutput boolheating = falseIdleDoorOpenCooking1: door2: start/ heating = true!doordoor/ heating = false

Code

scchart Microwave {
input bool start, door
output bool heating = false
initial state Idle
if door go to DoorOpen
if start do heating = true go to Cooking
state DoorOpen
if !door go to Idle
state Cooking
if door do heating = false go to DoorOpen
}
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 Microwave
Tickinput bool startinput bool dooroutput bool heatingActive 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. start = false, door = falseTick 1 enters Idle.
  2. start = true, door = trueThe door is open and start is pressed, in the same tick. Both of Idle’s transitions are enabled. The one written first, numbered 1 in the diagram, wins: the chart goes to DoorOpen, and heating stays false.
  3. start = false, door = falseThe door shuts, and DoorOpen goes back to Idle.
  4. start = truestart with the door shut. Only transition 2 is enabled now, and the oven heats.
  5. start = false, door = trueThe door opens while the oven is cooking. heating goes off, and the chart waits in DoorOpen.
  6. door = falseThe door shuts, and the chart is back in Idle. It does not carry on cooking: that takes another start.
Tick 2: the door is open and start is pressed. Transition 1 wins, so the oven does not heat.

When several transitions of a state could fire in the same tick, the one written first wins; the diagram numbers them 1:, 2:. Write the one that must win, here the door, first. Triggers, effects and priority has the rules.

The oven should beep when it starts. A beep is an event, not a setting, so it is a signal:

MicrowaveSimulation

Diagram

Diagram of MicrowaveStates: Idle (initial), DoorOpen, Cooking. Transitions: Idle to DoorOpen: 1: door; Idle to Cooking: 2: start / heating = true; beep; DoorOpen to Idle: !door; Cooking to DoorOpen: door / heating = false.Microwaveinput boolstart, dooroutput boolheating = falseoutput signalbeepIdleDoorOpenCooking1: door2: start/ heating = true;beep!doordoor/ heating = false

Code

scchart Microwave {
input bool start, door
output bool heating = false
output signal beep
initial state Idle
if door go to DoorOpen
if start do heating = true; beep go to Cooking
state DoorOpen
if !door go to Idle
state Cooking
if door do heating = false go to DoorOpen
}
Tick 0 of 5
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 Microwave
Tickinput bool startinput bool dooroutput bool heatingoutput signal beepActive 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. start = false, door = falseTick 1 enters Idle. beep is absent: a signal is present only in a tick in which something emits it.
  2. start = truestart: the transition sets heating and emits beep. Both are true after this tick.
  3. start = falseNothing fires. heating keeps its value, but beep is absent again: nothing emitted it in this tick.
  4. start = truestart again, while the oven is cooking. Cooking does not react to start, so nothing is emitted.
  5. start = false, door = trueThe door opens: heating goes off. This transition emits nothing, so there is no beep.
beep is present only in tick 2, the tick that emits it; heating stays true.

output signal beep declares it, and naming it as an effect, do heating = true; beep, emits it. Several effects are separated by ;. A signal is present only in a tick in which something emits it. A variable such as heating keeps its last value until something writes it again. That difference is the subject of Signals.

The lamp inside the oven is on while the door is open or the oven is heating. It gets a state machine of its own, a second region, next to the oven’s:

MicrowaveSimulation

Diagram

Diagram of MicrowaveStates: Idle (initial), DoorOpen, Cooking, Dark (initial), Lit. Transitions: Idle to DoorOpen: 1: door; Idle to Cooking: 2: start / heating = true; beep; DoorOpen to Idle: !door; Cooking to DoorOpen: door / heating = false; Dark to Lit: door || heating / lamp = true; Lit to Dark: !door && !heating / lamp = false.Microwaveinput boolstart, dooroutput boolheating = falseoutput boollamp = falseoutput signalbeepOvenIdleDoorOpenCooking1: door2: start/ heating = true;beep!doordoor/ heating = falseLampDarkLitdoor || heating/ lamp = true!door && !heating/ lamp = false

Code

scchart Microwave {
input bool start, door
output bool heating = false
output bool lamp = false
output signal beep
region Oven {
initial state Idle
if door go to DoorOpen
if start do heating = true; beep go to Cooking
state DoorOpen
if !door go to Idle
state Cooking
if door do heating = false go to DoorOpen
}
region Lamp {
initial state Dark
if door || heating do lamp = true go to Lit
state Lit
if !door && !heating do lamp = false go to Dark
}
}
Tick 0 of 5
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 Microwave
Tickinput bool startinput bool dooroutput bool heatingoutput bool lampoutput signal beepActive state of region OvenActive state of region Lamp
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. start = false, door = falseTick 1 enters the initial state of each region: Idle in Oven, Dark in Lamp.
  2. start = trueOven starts cooking and sets heating. Lamp reads heating in the same tick, sees true and switches lamp on. Regions react together, and a region sees what another has written in the same tick.
  3. start = falseBoth regions wait.
  4. door = trueThe door opens. Oven switches heating off and goes to DoorOpen. Lamp stays in Lit, because the door is open.
  5. door = falseThe door shuts. Oven returns to Idle, and Lamp, seeing neither the door nor heating, goes dark.
Tick 2: Oven sets heating, and Lamp sees it in the same tick.

Each region Name { … } is in one of its own states, and every region reacts in every tick. Regions talk through variables within the tick: Lamp reads heating after Oven has written it, whichever region comes first in the file. Give each variable one writer: if two regions could set the same variable to different values, KIELER rejects the chart. Concurrent regions and Why the compiler says no explain why.

The finished oven cooks for three seconds, stops when the door opens, and starts only on a fresh press of start:

MicrowaveSimulation

Diagram

Diagram of MicrowaveStates: Idle (initial), DoorOpen, Cooking (superstate), Heat (initial), Done (final), Dark (initial), Lit. Transitions: Heat to Done: 3 second; Idle to DoorOpen: 1: door; Idle to Cooking: 2: start && !pre(start) / heating = true; beep; DoorOpen to Idle: !door; Cooking to DoorOpen: 1: door / heating = false; Cooking to Idle: 2: / heating = false; beep; Dark to Lit: door || heating / lamp = true; Lit to Dark: !door && !heating / lamp = false.Microwaveinput boolstart, door, secondoutput boolheating = falseoutput boollamp = falseoutput signalbeepOvenIdleDoorOpenCookingHeatDone3 second1: door2: start && !pre(start)/ heating = true;beep!door1: door/ heating = false2: / heating = false;beepLampDarkLitdoor || heating/ lamp = true!door && !heating/ lamp = false

Code

scchart Microwave {
input bool start, door, second
output bool heating = false
output bool lamp = false
output signal beep
region Oven {
initial state Idle
if door go to DoorOpen
if start && !pre(start) do heating = true; beep go to Cooking
state DoorOpen
if !door go to Idle
state Cooking {
initial state Heat
if 3 second go to Done
final state Done
}
if door do heating = false abort to DoorOpen
do heating = false; beep join to Idle
}
region Lamp {
initial state Dark
if door || heating do lamp = true go to Lit
state Lit
if !door && !heating do lamp = false go to Dark
}
}
Tick 0 of 12
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. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of Microwave
Tickinput bool startinput bool doorinput bool secondoutput bool heatingoutput bool lampoutput signal beepActive state of region OvenActive state of the region of CookingActive state of region Lamp
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 12 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 12 ticks:

  1. start = false, door = false, second = falseTick 1 enters Idle and Dark.
  2. start = truestart becomes true. start && !pre(start) holds, because start was false in the previous tick. The oven beeps, heats and enters Cooking, and with it Heat. The lamp comes on.
  3. second = trueThe timer reports a second. if 3 second counts it: one.
  4. second = falseNo second has passed in this tick, so the count stays at one.
  5. second = trueTwo.
  6. second = falseStill two.
  7. second = trueThree: Heat goes to Done, a final state, so Cooking has finished. Its join to fires in the same tick: heating goes off and the oven beeps. The lamp goes dark.
  8. second = falsestart is still true: nobody has released it. Without !pre(start) the oven would start again now. With it, nothing happens, because start did not become true in this tick.
  9. start = falsestart is released.
  10. start = trueA new press: the oven beeps and cooks again, and if 3 second starts counting from zero.
  11. door = trueThe door opens in the middle of cooking. The strong abort abort to DoorOpen leaves Cooking at once, before Heat reacts, and switches heating off. The lamp stays on: the door is open.
  12. door = falseThe door shuts: DoorOpen returns to Idle, and the lamp goes dark. start is still true, but that is not a new press.
Ticks 3 to 7 count three seconds; tick 11 opens the door in the middle of cooking.
  • A count delay. if 3 second go to Done fires in the third tick in which second is true, counted from the tick after Heat was entered. Ticks are not seconds, so the oven needs an input that says when a second has passed, which a hardware timer would provide; in the simulator you set it yourself. The previous tick covers count delays and Counters and timeouts other ways to time things.
  • A superstate and an abort. Cooking has states inside it. Its own transitions, written after its closing brace, leave it whatever the inside is doing: if door … abort to DoorOpen stops the cooking at once, before the inside reacts (a strong abort; with go to the inside would react first). See Superstates and Aborts.
  • Termination. When the inside reaches its final state Done, the transition do heating = false; beep join to Idle fires, in the same tick.
  • An edge. start && !pre(start) is true only in the tick in which start becomes true: pre(start) is its value in the previous tick. Without it, a start left on would start the oven again the moment it finished. The previous tick explains pre.

Each frame’s Open in the playground link opens its chart in an editor, where you can change it and run your version.

Nearly everyone meets these in their first week.

  1. Tick 1 only enters. In tick 1 the chart enters its initial states; their transitions are checked from tick 2 on. What happens in tick 1
  2. Transitions wait a tick unless they are immediate. A transition is not checked in the tick its state is entered, so a chain of states moves one step per tick; an immediate transition can fire in the entry tick. Delayed and immediate transitions
  3. Inputs keep their value. In the simulators an input stays as you set it until you change it, so a button you switched on is pressed in every tick that follows. Inputs keep their value
  4. Signals vanish, variables stay. A signal is present only in a tick that emits it; a variable keeps the last value written to it. Signals or variables?
  5. Two regions cannot set one variable to different values. KIELER rejects the chart, with The SCG is NOT asc-schedulable!, even if the two writes could never happen in the same tick. Write–write conflicts
  6. Effects need do, and comparisons need ==. if A x = 1 go to B and if x = 3 go to B are both syntax errors; write if A do x = 1 go to B and if x == 3 go to B. Grammar traps
  7. No ; after a declaration. input bool A; is a syntax error, reported as no viable alternative at input ';' together with a puzzling message about bool: mismatched input 'bool' expecting 'primitive' in SCCharts Lab, no viable alternative at input 'bool' in KIELER VS Code. A semicolon after a declaration
  8. The first chart in the file is the one that runs. With several sccharts in one file, KIELER simulates the first, not the one you are looking at. Several charts in one file
  • A message. Search Compiler messages for its words. The box at the top of that page, The messages you will meet first, covers the five that come up most. When there are several messages, start with the earliest line KIELER complains about, fix it, and look again.
  • No message, wrong behaviour. My chart does not do what I expect goes through the usual symptoms, from “nothing happens in tick 1” to “my output stays true”.
  • Syntax you half remember. The cheat sheet has all of it on one page, and its grammar traps list the mistakes the parser punishes.

The summaries that end the twelve Learn chapters, in one place. If a line surprises you, its chapter is one click away.

1 Thinking in ticks

  • A reactive program runs for ever, responding to its environment. SCCharts describes such programs as a sequence of ticks.
  • In each tick the chart reads a snapshot of its inputs, reacts, and writes its outputs. It sees values, not changes: a held input looks the same in every tick.
  • Under the synchrony hypothesis a reaction takes no time, so outputs belong to the same tick as the inputs that caused them.
  • Ticks are logical time. How long a tick lasts in physical time is up to the program that runs the chart.
  • The same inputs always give the same outputs.
  • Tick 1 starts the chart in its initial state. Ordinary transitions out of a state are checked only from the tick after the state was entered.

2 Your first SCChart

  • A chart is scchart Name { ... } in a .sctx file. If a file has several, the first one is run.
  • Inside the braces: declarations first (input bool button, output int level = 0, no semicolons), then actions, then states.
  • Exactly one state is initial; the chart starts there in tick 1.
  • A transition is written under its source state: if trigger do effect go to Target. Trigger and effect are optional.
  • In the diagram, the initial state has a heavy outline and each transition is labelled trigger / effect.
  • Start with the earliest line KIELER complains about; the other messages often follow from it.

3 Triggers, effects and priority

  • A trigger is a boolean expression over the chart’s variables. Only the active state’s triggers count, with the current tick’s values.
  • An effect is an assignment. Several effects are separated by ; and run left to right, each seeing the writes before it.
  • A state’s transitions are tried in written order; the first whose trigger holds fires, and only its effects run. The diagram numbers them when there are several.
  • A transition without a trigger fires in the first tick after its state was entered. Put it last.
  • A self-loop leaves its state and enters it again. To stay in a state, you need no transition.
  • The transition is not reachable. means an untriggered transition is hiding the ones after it.

4 Delayed and immediate transitions

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

5 Variables, types and expressions

  • Inputs are written by the environment, outputs and locals by the chart. In the simulator an input keeps its value until you change it.
  • Variables start at their type’s default (0, false, 0.0) or their initial value, assigned once in tick 1, in declaration order, with tick 1’s inputs available.
  • Arithmetic is C’s: integer division truncates towards zero, ints wrap at 32 bits, and storing a float in an int truncates. Float literals are rounded to single precision, so never compare floats with ==.
  • The conditional c ? a : b binds tighter than everything else. Parenthesise its parts.
  • Prefer x += e and x++ to x = x + e. A vector assignment runs element by element, in order.
  • Some C details show through: strings compare as pointers, and nothing checks for division by zero or for indices out of range.

6 Signals

  • A signal is present in a tick if and only if something emits it in that tick; output and local signals start every tick absent.
  • Emit with the signal’s name as an effect (do S), test with its name as a condition (if S, !S). Emitting a variable or assigning a signal is an error.
  • In the simulator, an input signal stays present until you set it absent.
  • A valued signal adds a value: emit with V(e), read with val(V). The value persists while the signal is absent.
  • Several emissions in one tick: without a combine function the last one wins; with combine op they are combined from the operator’s start value.
  • To build on a signal’s value, use last tick’s: pre(val(V)).
  • In KIELER’s simulator, a chart that declares a signal never terminates.

7 Superstates

  • A superstate is a state with states inside. Entering it enters its initial state in the same tick, all the way down.
  • A superstate’s own transitions, written after its closing brace, leave it whichever inner state is active. The next entry starts again at the initial state.
  • Declarations inside a superstate are local to it. The nearest declaration wins, and locals are initialised again on every entry.
  • When the inside reaches a final state the superstate terminates, and join to can fire in that same tick. A join without a trigger is immediate; if c join to waits at least one tick.

8 Concurrent regions

  • A region is a state machine of its own. A chart or a superstate can have several, side by side; each is in one state at a time, and all of them react in every tick.
  • Regions communicate within a tick. For each variable, absolute writes come first, then updates, then reads. The order of the regions in the file does not matter, as long as you write updates with += and ++.
  • A superstate with regions terminates when all of them are in final states at the same time, and its join to fires in that tick.
  • The same inputs always give the same outputs. A chart without a valid order, such as two regions setting one output to different values, is rejected.

9 Aborts

  • A transition written on a superstate is an abort: it can cut the inside short. A weak abort (go to) lets the inside finish its tick first; a strong abort (abort to) leaves before the inside moves.
  • Aborts are delayed unless written immediate. A strong abort reads its trigger before the inside reacts, a weak abort after.
  • Transitions are tried in the order written, and strong aborts must come first. A join behaves like a weak abort; when a join and a weak abort both apply, the first written wins.
  • On a simple state there is no inside to skip: go to and abort to behave alike unless the state has a during action.

10 Entry, during and exit actions

  • An entry action runs every time its state is entered and an exit action every time it is left, whichever transition did it. Put an effect in a state when it belongs to being in that state.
  • A during action runs in every tick in which its state is already active: not in the entry tick, but in the tick the state is left by go to. immediate during adds the entry tick.
  • When a transition is taken: the source’s during actions (not for abort to), exit actions innermost first, the transition’s effects, entry actions outermost first, then the target’s immediate behaviour.
  • Exit actions run on strong aborts too. Only during actions depend on the kind of abort.
  • A self-loop leaves and re-enters its state, so its exit and entry actions run.
  • A trigger on an action is checked at that moment; a label changes only the diagram.

11 The previous tick

  • pre(x) is the value x had at the end of the previous tick. Writes in the current tick don’t change it.
  • In tick 1, and when a superstate is entered again for its own locals, pre(x) is the default of the type (0, false), not the initial value.
  • b && !pre(b) is a rising edge and !b && pre(b) a falling edge: each is true for exactly one tick. Trigger on the edge when one press should do one thing.
  • pre(S) asks whether a signal was present in the previous tick; pre(val(V)) is a valued signal’s previous value.
  • if n T fires in the n-th tick in which T holds since the state was entered. Only immediate counts the entry tick, and every entry restarts the count. Inside a state with a reset self-loop KIELER rejects count delays: count by hand there.

12 Why the compiler says no

  • KIELER accepts a chart only if it can order every tick so that the result cannot depend on the order of the regions. The one hole: old-style updates such as x = x + 1 in two regions; write +=.
  • For each variable, every tick runs all absolute writes first, then all updates, then all reads, while each region keeps its own order. Concurrent writes must agree; updates must commute.
  • The check is static: it ignores triggers and values, so conflicts that only exist on paper are rejected too.
  • An emission is an update and a test is a read, so emissions come before tests; a region may test a signal before emitting it.
  • A cycle of immediate transitions is rejected whatever its guards; something must take time.
  • Fixes: one owner, updates with +=, a one-way dependency, pre, a delayed transition, or one region instead of two.

When the lab is over, start properly with Thinking in ticks. At the end of Learn, Put it together asks you to write a whole chart from its interface alone.

Report a mistake on this page