Because TTA/TCE is an environment without operating system, there is also no file system available for implementing file-based I/O. Therefore, one popular way to get input and output to/from the TTA is using shared memory for communicating the data. For stream processing type of applications, one can also use an I/O function unit that implements the required operations for streaming.
TCE ships with example operations for implementing stream type input/output. These operations can be used to read and write samples from streams in the designed TTA processor. The basic interface of the operations allows reading and writing samples from the streams and querying the status of an input or output stream (buffer full/empty, etc.). The status operations are provided to allow the software running in the TTA to do something useful while the buffer is empty or full, for example switch to another thread. Otherwise, in case one tries to read/write a sample from/to a stream whose buffer is empty/full, the TTA is locked and the cycles until the situation resolves are wasted.
The example streaming operations in the base operation set are called STREAM_IN, STREAM_OUT, STREAM_IN_STATUS, and STREAM_OUT_STATUS. These operations have a simulation behavior definition which simulates the stream I/O by reading/writing from/to files stored in the file system of the simulator host. STREAM_IN and STREAM_OUT operations allow defining in/out files using TTASIM_STREAM_IN_FILE and TTASIM_STREAM_OUT_FILE environment variables respectively.
Here is an example C code that implements streaming I/O with the operations:
#include "tceops.h" int main() { char byte; int status; while (1) { _TCE_STREAM_IN_STATUS(0, status); if (status == 0) break; _TCE_STREAM_IN(0, byte); _TCE_STREAM_OUT(byte); } return 0; }
This code uses the TCE operation invocation macros from tceops.h to read bytes from the input stream and write the same bytes to the output stream until there is no more data left. This situation is indicated with the status code 0 queried with the STREAM_IN_STATUS operation. The value means the stream buffer is empty, which means the file simulating the input buffer has reached the end of file.
You can test the code by creating a file <FU_NAME>.in with some test data, compiling the code and simulating it. The code should create a copy of that file to the stream output file <FU_NAME>.out. These files should reside in the directory where the simulator is started. You can get the FU_NAME from the streaming function units in the adf file.
When these function units are instantiated in ProDe, they are realized with specific operation latencies. STREAM_IN and STREAM_OUT take 3 clock cycles, and STREAM_IN_STATUS and STREAM_OUT _STATUS execute in 1 clock cycle.
The Stream In -FU has three external ports. ext_data is 8 bits wide and is used to communicate the data byte from the external stream source to the TTA FU. When the TTA application program invokes the STREAM_IN -operation, the ext_data signal is sampled by the FU and the Stream In -FU automatically sends an acknowledge-signal back to the stream source through the ext_ack port of the FU. The external stream source is supposed to provide the next stream data value to ext_data upon noticing a rising edge in ext_ack. The three cycle latency of the operation allows some time for this to happen. Finally, the TTA application program can query the availability of stream data by invoking the STREAM_IN_STATUS -operation. This command reads the value of the ext_status port of the Stream In FU and the external stream device is expected to keep the signal high in this port when there is still data available, and low when the stream device has run out of data. The application program sees the status as a numerical value '1' or '0'.
The Stream Out -FU works in a similar fashion. The ext_data port is now an output and provides the data to the external stream sink. The external stream sink is expected to sample the value of ext_data when ext_dv (data valid) is high. ext_dv is automatically operated by the FU when the application program invokes the operation STREAM_OUT. STREAM_OUT has also a latency of 3 clock cycles to allow the external stream sink to take care of the data sample. Invoking the STREAM_OUT_STATUS operation samples the signal in the ext_status -port, which the external stream sink is expected to keep high if there is still space in the stream sink. When the stream sink is full, the signal in the ext_status -port must be pulled low by the stream sink.
Having several distinct stream sources or sinks must at the moment be realized by manually copying the FUs along with their HDB and VHDL parts. The operations must have distinct names so that the compiler is explicitly instructed to read from a specific source or write to a specific sink.
Pekka Jääskeläinen 2018-03-12