====== Alternate Buffer ====== We start with the previous definition of a templated buffer: template defproc buffer (chan?(int) L; chan!(int) R) { one_place_buffer b[N]; (i : N-1 : b[i].R = b[i+1].L;) b[0].L = L; b[N-1].R = R; } In this version, we used the ''='' operation to connect channels to each other. There are other ways this can be done, and here we describe the syntax for a number of different options that achieve the same result in terms of creating a FIFO. ===== Using auxillary variables ===== We can create an array of size ''N-1'' to correspond to the internal channels between the ''N'' buffers. template defproc buffer (chan?(int) L; chan!(int) R) { one_place_buffer b[N]; chan(int) ch[N-1]; (i : N-1 : b[i].R = ch[i];) (i : N-1 : b[i+1].L = ch[i];) b[0].L = L; b[N-1].R = R; } This can be re-written as follows: template defproc buffer (chan?(int) L; chan!(int) R) { one_place_buffer b[N]; chan(int) ch[N-1]; (i : 1 .. N-1 : b[i].L = ch[i-1]; b[i].R = ch[i]; ) b[0].L = L; b[0].R = ch[0]; b[N-1].L = ch[N-2]; b[N-1].R = R; } Another version of this is the following: template defproc buffer (chan?(int) L; chan!(int) R) { one_place_buffer b[N]; chan(int) ch[N-1]; (i : N : [ i = 0 -> b[i].L = L; b[i].R = ch[i]; [] i = N-1 -> b[i].L = ch[i-1]; b[i].R = R; [] else -> b[i].L = ch[i-1]; b[i].R = ch[i]; ] ) } ===== Using port connections directly ===== Instead of using the dot notation to explicitly connect ports, we observe that each set of connections operates on the same instance ''b[i]''. This can be written as follows: template defproc buffer (chan?(int) L; chan!(int) R) { one_place_buffer b[N]; chan(int) ch[N-1]; (i : N : [ i = 0 -> b[i](L,ch[i]); [] i = N-1 -> b[i](ch[i-1],R); [] else -> b[i](ch[i-1], ch[i]); ] ) } This approach relies on the order of ports being known; if instead it is preferable to connect ports by name, the following syntax is also valid. template defproc buffer (chan?(int) L; chan!(int) R) { one_place_buffer b[N]; chan(int) ch[N-1]; (i : N : [ i = 0 -> b[i](.L=L, .R=ch[i]); [] i = N-1 -> b[i](.L=ch[i-1], .R=R); [] else -> b[i](.L=ch[i-1], .R=ch[i]); ] ) } ===== Dynamic creation of buffer instances ===== ACT also permits instances to be created one at a time. So rather than declaring a single buffer array of size ''N'', we can create it one segment of the array at a time. template defproc buffer (chan?(int) L; chan!(int) R) { chan(int) ch[N-1]; (i : N : one_place_buffer b[i..i]; [ i = 0 -> b[i](.L=L, .R=ch[i]); [] i = N-1 -> b[i](.L=ch[i-1], .R=R); [] else -> b[i](.L=ch[i-1], .R=ch[i]); ] ) } Each ''b[i..i]'' slice augments the array ''b''. Note that when connecting to ports, you can leave connections dangling and then refer to them later. For example, the following avoids using the extra channel array. template defproc buffer (chan?(int) L; chan!(int) R) { chan(int) ch[N-1]; (i : N : one_place_buffer b[i..i]; [ i = 0 -> b[i](.L=L); [] i = N-1 -> b[i](.L=b[i-1].R, .R=R); [] else -> b[i](.L=b[i-1].R); ] ) } ... which may be easier to read as follows: template defproc buffer (chan?(int) L; chan!(int) R) { chan(int) ch[N-1]; (i : N : one_place_buffer b[i..i]; [ i = 0 -> b[i].L=L; [] i = N-1 -> b[i](.L=b[i-1].R, .R=R); [] else -> b[i].L=b[i-1].R; ] ) } This version is similar to the original version we started with.