The baseline TDM mixer design uses a single kernel implementing the vectorization described earlier. It processes NSAMP samples of one channel, switches to a different carrier frequency, processes NSAMP samples of that channel, and repeats until it processes all channels.
You can read the input and output buffers in linear addressing order because the DMA configuration already places samples in their correct destinations. The following figure shows the baseline design. The design supports NSAMP=64 samples and CC=32 channels, uses a single compute tile, and distributes buffers across three tiles. There is no attempt to optimize the design floor plan. The design uses double-buffered I/O, and it contains one phase_inc lookup table specifying phase increments for each channel. Unity values drive the design so each channel produces its own tone.
The compiler schedules the inner for-loop (Line 57) within an initiation interval (II) of 15 cycles. The theoretical minimum II from hardware operations is two cycles, indicating inefficiency from poor software scheduling. This performance runs about 7X to 8X slower than theory. Refactor the code in the following section to improve throughput. With II=15, the design achieves a throughput of ~2600 MB/s or ~550 MSPS (assuming each cint16 sample is four bytes).
Consider two points about the II reporting of Line 57:
The tool shows II information only when you enable the verbose option.
Although the code contains three for-loops, reporting appears only for the innermost loop. This result means the compiler applied software pipelining optimization solely to the innermost loop for this design. In other designs, the tool can report IIs for multiple loops when it optimizes them with pipelining.
The following figure shows kernel code for the baseline design. The top-left portion shows the header file code. The constructor receives the static mixer frequency configuration from the phase_inc_i array. An additional phase array holds the state of the mixer between kernel invocations. The bottom-left shows the constructor code. It initializes the phase of all mixer channels to zero in this code.
The right portion shows the actual kernel code. The output loop (Line 42) runs over all channels supported by the mixer. Lines 45 to 51 compute the fixed vector ramp required by the current channel. Line 54 restores the previous phase value for the current channel from memory. The inner loop on Line 57 processes all NSAMP samples for the current channel eight at a time using two pipelined operations. The first multiplies the vector ramp by the next value generated by the sincos() generator. The second multiplies the 8-lane vector of the mixer phasor with the 8-lane vector of input samples. The curr variable accumulates the phase for the sincos() generator. Line 67 stores the final phase value to memory for the next kernel call.
Lines 61 and 62 perform two 8‑lane vector multiplications. These instructions are pipelined and require many cycles to complete. The compiler must finish these instructions before scheduling the next loop body iteration, reducing throughput and stalling execution. As a result, this loop achieves an II=15, even though these instructions have a theoretical II=2. Improvement depends on filling the loop with more compute workloads, as described in the following section.