lingua-franca
lingua-franca copied to clipboard
Interleaved connections with hierarchy
In the C target, @cmnrd has pointed out that the way interleaved connections work with hierarchical programs is arguably incorrect. Consider a test program that looks like this (complete code below):
The connection is interleaved:
a.out-> interleaved(b.in)
We add hierarchy as follows (complete code below):
where the interleaved connection is as follows:
a.out -> interleaved(c.in)
Currently, the the behavior is that the first bank member of C will receive the first two outputs from a[0] followed by the first output from a[1]. This is not the same as above and arguably incorrect because the outside connection should not change how the inside connection is interpreted.
The reason for this behavior is that the C target has a single PortInstance that represents all the connections, inside and out, and the interleaving changes the order in which mixed radix digits are placed in the number that is used to index into the array of channels. I believe that the behavior could be made the same as the version without hierarchy by just implicitly treating an inside connection as interleaved if the outside connection is interleaved (note that the inside connection cannot be explicitly interleaved... that is prohibited by the validator).
Source code for the version without hierarchy:
target C {
timeout: 100ms
}
reactor A {
output[2] out:int
state count:int = 0
timer t(0, 10ms)
reaction(t) -> out {=
for(int i = 0; i < 2; i++) {
lf_set(out[i], self->count++);
}
=}
}
reactor B(bank_index:int = 0) {
input[3] in:int
reaction(in) {=
for(int i = 0; i < 3; i++) {
lf_print("%d Received %d", self->bank_index, in[i]->value);
}
=}
}
main reactor {
a = new[3] A()
b = new[2] B()
a.out -> interleaved(b.in)
}
Source code for the version with hierarchy:
target C {
timeout: 100ms
}
reactor A {
output[2] out:int
state count:int = 0
timer t(0, 10ms)
reaction(t) -> out {=
for(int i = 0; i < 2; i++) {
lf_set(out[i], self->count++);
}
=}
}
reactor B(bank_index:int = 0) {
input[3] in:int
reaction(in) {=
for(int i = 0; i < 3; i++) {
lf_print("%d Received %d", self->bank_index, in[i]->value);
}
=}
}
reactor C {
input[3] in:int
b = new B()
in -> b.in
}
main reactor {
a = new[3] A()
c = new[2] C()
a.out -> interleaved(c.in)
}
The reason for this behavior is that the C target has a single PortInstance that represents all the connections, inside and out, and the interleaving changes the order in which mixed radix digits are placed in the number that is used to index into the array of channels. I believe that the behavior could be made the same as the version without hierarchy by just implicitly treating an inside connection as interleaved if the outside connection is interleaved (note that the inside connection cannot be explicitly interleaved... that is prohibited by the validator).
I am not sure if this will work reliably in all cases. What if the connection forks off somewhere in the hierarchy? What if there is another connection on the path that uses the interleaved keyword?