State & Initialization
Semantically, every DFiant dataflow variable references a token stream (TS).
-
Unless stated otherwise, all dataflow variables are always consuming and always producing.
-
Previous token initialization:
-
The token history stream can be initialized.
-
Initialization does not mutate the dataflow variable.
-
Initialization has no effect on the TS. Only when using
prev
the initialization is placed on the TS reference. -
init
returns a reference to a new (initialized) dataflow variable, but maintains the mutability trait dataflow variable. -
Bubble tokens (?) :
-
Produced when a
prev
is called on a non-initialized dataflow variable. E.g.,Code Init Token Stream in : DFUInt[32]
?
2, 3, 1, 5, 9
in.prev
?
?, 2, 3, 1, 5, 9
in.prev(2)
?
?, ?, 2, 3, 1, 5, 9
in.prev.prev
?
?, ?, 2, 3, 1, 5, 9
val in1 = in.init(1); in1
1
2, 3, 1, 5, 9
in1.prev
1
1, 2, 3, 1, 5, 9
in1.prev(2)
1
1, 1, 2, 3, 1, 5, 9
in1.prev.init(8)
8
1, 2, 3, 1, 5, 9
val innew = DFUInt(32) := in1; innew
?
2, 3, 1, 5, 9
val ins7 = in.init(7, ?); ins7
(7, ?)
2, 3, 1, 5, 9
ins7.prev
?
7, 2, 3, 1, 5, 9
val ins78 = in.init(7, 8, ?); ins78
(7, 8, ?)
2, 3, 1, 5, 9
ins78.prev
(8, ?)
7, 2, 3, 1, 5, 9
ins78.prev(2)
?
8, 7, 2, 3, 1, 5, 9
in.init(7).prev.init(8, ?).prev
?
8, 7, 2, 3, 1, 5, 9
-
Bubbles are like any regular-value tokens in terms of consumption and production rules.
-
Bubbles are used to set phases between synchronized token streams by acting as a token place-holder within the stream queue.
-
Unless stated otherwise, any operation with a bubble token produces a bubble token (consuming the non-bubble token.). E.g.,
1 2 3
def foo(a : DFUInt(8)) = a + a.prev //'in' is token stream of: 2, 3, 1, 5, 9 //'foo(in)' returns: ?, 5, 4, 6, 14
-
prev
maintains Distributivity through basic operations e.g.:(a + b).prev
≗a.prev + b.prev
(timeless TS equality).Code Init Token Stream inL : DFUInt(32)
?
2, 3, 1, 5, 9
inR : DFUInt(32)
?
4, 0, 2
inL + inR
?
+
?
=
?
2, 3, 1, 5, 9
+
4, 0, 2
=
6, 3, 3
inL + inR.prev
?
+
?
=
?
2, 3, 1, 5, 9
+
?, 4, 0, 2
=
?, 7, 1, 7
inL.init(1) + inR.init(3).prev
1
+
3
=
4
2, 3, 1, 5, 9
+
3, 4, 0, 2
=
5, 7, 1, 7
inL.init(1, ?) + inR.init(3).prev
(1, ?)
+
3
=
(4, ?)
2, 3, 1, 5, 9
+
3, 4, 0, 2
=
5, 7, 1, 7
inL.init(1) + inR.init(3, ?).prev
1
+
?
=
?
2, 3, 1, 5, 9
+
3, 4, 0, 2
=
5, 7, 1, 7
inL.init(1).prev + inR.init(3).prev
1
+
3
=
4
1, 2, 3, 1, 5, 9
+
3, 4, 0, 2
=
4, 6, 3, 3
(inL.init(1) + inR.init(3)).prev
1
+
3
=
4
(2, 3, 1, 5, 9
+
4, 0, 2)
.prev =
4, 6, 3, 3
-
Bubbles are typically treated differently at the edges of the dataflow paths, when bridging to the real-time world. E.g.: not committing bubbles to memory cells, or not raising ready flags.
-
Casting:
-
Parts of a bits vector can be bubbles while others normal values.
-
However, when casting to a number (e.g., DFUInt), the casting must check validity of all bits.