11package org.lflang.generator.uc
22
33import java.util.*
4- import kotlin.collections.HashSet
5- import org.lflang.*
4+ import org.lflang.allConnections
65import org.lflang.generator.PrependOperator
76import org.lflang.generator.orNever
87import org.lflang.generator.uc.UcInstanceGenerator.Companion.isAFederate
98import org.lflang.generator.uc.UcPortGenerator.Companion.arrayLength
109import org.lflang.generator.uc.UcPortGenerator.Companion.isArray
1110import org.lflang.generator.uc.UcReactorGenerator.Companion.codeType
11+ import org.lflang.joinWithLn
1212import org.lflang.lf.*
13+ import org.lflang.toText
1314
1415/* *
1516 * This generator creates code for configuring the connections between reactors. This is perhaps the
@@ -357,9 +358,9 @@ class UcConnectionGenerator(
357358
358359 private fun generateReactorCtorCode (conn : UcGroupedConnection ) =
359360 if (conn.isLogical) {
360- " LF_INITIALIZE_LOGICAL_CONNECTION(${reactor.codeType} , ${conn.getUniqueName()} , ${conn.bankWidth} , ${conn.portWidth} )"
361+ " LF_INITIALIZE_LOGICAL_CONNECTION(${reactor.codeType} , ${conn.getUniqueName()} , ${conn.bankWidth} , ${conn.portWidth} ); "
361362 } else {
362- " LF_INITIALIZE_DELAYED_CONNECTION(${reactor.codeType} , ${conn.getUniqueName()} , ${conn.delay} , ${conn.bankWidth} , ${conn.portWidth} )"
363+ " LF_INITIALIZE_DELAYED_CONNECTION(${reactor.codeType} , ${conn.getUniqueName()} , ${conn.delay} , ${conn.bankWidth} , ${conn.portWidth} ); "
363364 }
364365
365366 private fun generateFederateCtorCode (conn : UcFederatedConnectionBundle ) =
@@ -373,8 +374,87 @@ class UcConnectionGenerator(
373374 """
374375 .trimMargin()
375376
376- private fun generateConnectionStatements (conn : UcGroupedConnection ) =
377- conn.channels.joinToString(separator = " \n " ) { generateConnectChannel(conn, it) }
377+ private fun generateGroupedConnectChannel (
378+ groupedConn : UcGroupedConnection ,
379+ src : UcChannel ,
380+ dest : UcChannel ,
381+ size : Int ,
382+ ) =
383+ """ |lf_grouped_connect((Connection *) &self->${groupedConn.getUniqueName()} [${src.getCodeBankIdx()} ][${src.getCodePortIdx()} ], (Port *) ${src.generateChannelPointer()} , (Port *) ${dest.generateChannelPort()} , ${size} );
384+ """
385+ .trimMargin()
386+
387+ private fun generateInterleavedConnectChannel (
388+ groupedConn : UcGroupedConnection ,
389+ src : UcChannel ,
390+ dest : UcChannel ,
391+ maxBankSrc : Int ,
392+ maxPortSrc : Int ,
393+ ) =
394+ """
395+ |for(int j = 0; j < ${maxBankSrc} ; j++) {
396+ | for(int i = 0; i < ${maxPortSrc} ; i++) {
397+ | lf_connect((Connection *) &self->${groupedConn.getUniqueName()} [j][i], (Port *) &self->${src.varRef.container.name} [j].${src.varRef.name} [i], (Port *) &self->${dest.varRef.container.name} [i].${dest.varRef.name} [j]);
398+ | }
399+ |}
400+ """
401+ .trimMargin()
402+
403+ // checks if the given list of Integers is continuously increasing.
404+ fun isContinuous (array : List <Int >): Boolean {
405+ return array.size != array[array.size - 1 ] + 1
406+ }
407+
408+ private fun generateOutboundConnection (
409+ conn : UcGroupedConnection ,
410+ outgoingConns : List <UcConnectionChannel >
411+ ): String {
412+ val groupedDownstreams = HashMap <Pair <VarRef , Int >, MutableList <UcConnectionChannel >>()
413+ outgoingConns.forEach { channel ->
414+ groupedDownstreams
415+ .getOrPut(Pair (channel.dest.varRef, channel.dest.bankIdx), { mutableListOf () })
416+ .add(channel)
417+ }
418+
419+ return groupedDownstreams
420+ .map { groupedDownstream ->
421+ groupedDownstream.value.sortBy { it.dest.portIdx }
422+ val sequential = groupedDownstream.value.map { it.dest.portIdx }
423+
424+ if (isContinuous(sequential) && sequential.size >= 4 ) {
425+ generateGroupedConnectChannel(
426+ conn,
427+ groupedDownstream.value[0 ].src,
428+ groupedDownstream.value[0 ].dest,
429+ groupedDownstream.value.size)
430+ } else {
431+ groupedDownstream.value.joinToString(separator = " \n " ) {
432+ generateConnectChannel(conn, it)
433+ }
434+ }
435+ }
436+ .joinToString(separator = " \n " ) { it }
437+ }
438+
439+ private fun generateConnectionStatements (conn : UcGroupedConnection ): String {
440+ // A common wiring pattern enabled by the interleaved keyword uses two banks of reactors,
441+ // each with a port bank. The connections are interleaved so that src[j][i] is connected to
442+ // dest[i][j]. This optimization is performed only if more than four connections need to be
443+ // drawn.
444+
445+ return if (conn.channels.all {
446+ it.src.bankIdx == it.dest.portIdx && it.src.portIdx == it.dest.bankIdx
447+ } && conn.channels.size >= 4 ) {
448+ // here we need to calculate the maximum bank and port index, which will
449+ // become the bounds of the two for-loops.
450+ val maxBankIdx = conn.channels.maxOf { it.src.bankIdx } + 1
451+ val maxPortIdx = conn.channels.maxOf { it.src.portIdx } + 1
452+ generateInterleavedConnectChannel(
453+ conn, conn.channels[0 ].src, conn.channels[0 ].dest, maxBankIdx, maxPortIdx)
454+ } else {
455+ generateOutboundConnection(conn, conn.channels)
456+ }
457+ }
378458
379459 private fun generateConnectFederateOutputChannel (
380460 bundle : UcFederatedConnectionBundle ,
0 commit comments