|
Practical FPGA Programming in C Authors: Pellerin D., Thibault S. Published year: 2005 Pages: 47-48/208 |
4.8. Using Output StreamsOutput streams may be written using the co_stream_write function as follows :
co_stream_open(output_stream, O_WRONLY, INT_TYPE(32));
for (i=0; i < ARRAYSIZE; i++) {
co_stream_write(output_stream, &data[i], sizeof(int32));
}
co_stream_close(output_stream);
The stream must be a writable stream (opened with the O_WRONLY direction indicator), and the data must match the size of the stream datatype. The co_stream_write function, when invoked, first checks to see if the specified output stream is full. If the stream is full, the function blocks until there is room in the stream buffer for a write operation to be performed. This is an important aspect of stream behavior: once a stream has been opened and is being used by a producer and consumer process, there is no need for you (as the application programmer) to manage the stream in terms of acknowledgments or other control signals. There is, of course, a downside to the standard behavior of streams. If your producer and consumer processes are not properly designed, there can be a risk of deadlock conditions, in which neither the producer nor the consumer can proceed with its operations. We'll discuss the issue of stream synchronization and deadlocks in more detail in later chapters. |
4.9. Using Input StreamsTwo operations may be performed on an input stream: an end-of-stream test and a stream read. The end-of-stream test checks to see whether a "close" operation was performed on the stream by the stream writer. It does this by checking the current element at the head of the stream. If this element is determined to be an end-of-stream token, a true value is returned; otherwise , a false value is returned indicating that the stream is open . The co_stream_eos function is nonblocking, and a return value of false does not imply that there is, or will be, more data available. The co_stream_read function attempts to read the next stream element and blocks if the stream is empty. A read operation on a closed stream returns the value TRue . Thus, the preferred sequence of operations is to describe a stream reading loop:
err = co_stream_open(input_stream, O_RDONLY, INT_TYPE(32));
while(co_stream_read(input_stream) == co_err_none) {
. . . // Process the data here
}
co_stream_close(input_stream);
When an input stream is closed using co_stream_close , all the unread data in the stream is flushed, and the EOS token is consumed. If there is no EOS in the stream (for example, the writer hasn't closed it yet), co_stream_close blocks until an EOS is detected . Note also that co_stream_close writes the EOS token only when called from the writer process, so it is important not to close a stream from the read side unless the EOS token has been detected. Checking for End of StreamThe co_stream_eos function returns TRue to indicate that the writer has closed the stream. Once co_stream_eos returns false, all subsequent calls to co_stream_eos return false until the reader closes the stream. Similarly, all subsequent calls to co_stream_read fail with co_err_eos until the stream is closed and reopened for reading. Efficient Use of Stream ReadsThe efficient processing of stream- related data is a key part of programming using Impulse C. There are three possible methods of reading data from streams: Method 1 (preferred method)
while(co_stream_read(input_stream) == co_err_none) {
... // Process the data here
}
Method 2 (acceptable method)
do {
if (co_stream_read(input_stream,&i,sizeof(i)) == co_err_none) {
... // Process the data here
}
} while(!co_stream_eos(input_stream));
or the following derivative:
while ( ! co_stream_eos(input_stream) ) {
if ( co_stream_read(input_Stream, &i, sizeof(i)) == co_err_none ) {
. . .
}
}
Method 3 (less acceptable)
while(!co_stream_eos(input_stream)) {
co_stream_read(input_stream,&i,sizeof(i));
... // Process the data here
}
or the following derivative (which is also less acceptable):
do {
co_stream_read(input_stream,&i,sizeof(i));
... // Process the data here
}while(!co_stream_eos(input_stream));
As indicated, the first two methods are acceptable, but the third may result in problems during simulation and/or in the generated VHDL and should not be used. (The reason? It's possible that between the call to co_stream_eos and co_stream_read , the stream may be closed by the upstream process. Since method 3 does not check the return value of co_stream_read , the read buffer could contain invalid data.) Which method you will use depends on the nature of your application, but there are significant trade-offs for processes that will be compiled to hardware. Because each control point in a hardware process will require a full cycle, method 1 is strongly preferred for efficient hardware synthesis. Also, when testing for a condition on the return value from co_stream_read , the condition must be ( co_stream_read (...) == co_err_none ) as shown. The best strategy is almost always the first of these three methods. Eliminating the explicit call to co_stream_eos will result in the loop waiting (possibly forever) for the the first data element to appear on the stream and will not result in an additional wasted cycle. If, however, you need to perform conditional read operations or are operating on multiple streams simultaneously , the second method is acceptable as an alternative. |
|
Practical FPGA Programming in C Authors: Pellerin D., Thibault S. Published year: 2005 Pages: 47-48/208 |
![]() FPGA Prototyping By Verilog Examples: Xilinx Spartan-3 Version | ![]() 100 Power Tips For FPGA Designers | ![]() C++ Concurrency in Action: Practical Multithreading |
![]() FPGA Prototyping By Verilog Examples: Xilinx Spartan-3 Version | ![]() 100 Power Tips For FPGA Designers |
![]() C++ Concurrency in Action: Practical Multithreading |