Managing Complexity with SystemC
SystemC came into being due to the engineering demands to model System-on-Chips (SoCs). SoCs require that we model both hardware and software concurrently thereby increasing the level of complexity that could not be managed by any other way. Today SystemC is being used in a number of ways ranging from SoC design, FPGA design and test and verification of chips. However, if we were to look a little deeper, it becomes clear that SystemC has a lot more to offer in varieties of different technology domains and applications. Its extensible framework, integral concept of time at multiple scales, ability to encapsulate algorithms and behavior in modules with well defined interfaces, ability to model concurrent behavior, hardware agnosticism and the ability to provide a variety of visualization mechanisms makes it an ideal platform to model almost any real life system or organism.
SystemC is essentially a C++ library that extends the C++ language by adding a timed model and hardware semantics to accurately model the hardware. The interesting thing is that it separates the modeling of the behavior from that of the communication mechanisms between them. That coupled with the ability to encapsulate and develop a hierarchical implementation, enables starting the model with a very simple element and communication model. Encapsulation also hides the complexity from one scale to the next. The well defined interface exposed by the encapsulated entity can be made as sophisticated as needed to expose the inherent behavior without exposing the implementation complexity.
This building block approach mimics how nature achieves its ultimate complexity. When one scrutinizes an organism, it starts to reveal its details and the interaction of its different parts. Its the parts and the interactions are labeled at that scale. On further magnification the part reveals a whole different set of entities and their interactions. This top down approach has not been widely explored in SystemC. Most of the current applications of SystemC are focused at chip synthesis and testing. They tend to be more bottom up use of SystemC.
This paper is an attempt to look at a more holistic approach to using SystemC for modeling. It is also attempts to expose the latent strengths of the SystemC framework that could be exploited in modeling systems.
Modeling Abstraction Hierarchy
SystemC allows a natural way of conceptualizing a system. Initially the concepts can be captured in high level blocks or “modules” with simple communication signals or “channels” connecting them. Modeling time is not an issue at this stage. The clock that provides timing to the modules is simply ensures synchronization and concurrency between modules. Modeling at this level can be especially useful in capturing the specification of dynamic behavior, called “executable specification”. This model is also known as System Architecture Model (SAM). It is unimportant to know how the system is going to be partitioned into hardware and software. SAM exposes the texture of computation needed in the modules. It shows the complexity and nature of computations involved. It shows the memory access patterns, floating point intensive operations, external event interactions and distributable data patterns. On the communications side it establishes the interfaces between the modules. This enables an architect to play around with redistributing the functionality between modules; or create new modules to make the interfaces more efficient. The interfaces establish the complexity of communications. As they get refined, the modules form the natural boundaries for the selection of implementation architecture. Figure 1 highlights SystemC’s ability to support the different phases of the design cycle.
Click to enlarge
Figure 1 Design Cycle
Modeling Time
SystemC’s simulator provides the flexibility of creating any number of clocks of widely varying timing. One can exploit this flexibility to have events happening at long intervals interspersed with events that happen very rapidly. The fastest events generated are in the order of picoseconds.
Initial designs can start with just a clock for creating synchronization among modules and concurrency. With timing refinement this clock can become the hardware generated clock. This model is called timing accurate model. In addition there can be a model with pseudo accurate timing. Such a model is useful in measuring gross timing of modules and their interactions to provide performance estimates of the modeled system. The model can provide first cut performance estimates and still run at reasonably fast speeds. Moreover one can estimate the execution time of the modules on different platforms. This provides and opportunity to explore suitability amongst different hardware architectures for the modules in the system. Even though this approach is not cycle accurate, it can still offer a degree of sophistication that far surpasses current manual models of estimating performance due to the communication and interaction model sophistication.
SystemC offers managers and system architects with a tool to accurately define the specifications of a complex dynamic system in ways that could not be done with diagrams and words. Using the timed model, the architect can code up what is called an executable specification. The executable spec captures the dynamic and interactive behavior.. Once compiled, this executable runs to produce the simulated dynamic behavior of the final system.
Figure 2 Modeling Behavior over time
Modularizing Algorithms
In most cases, an algorithm can be segmented into modules with data streaming in and out. The motivation on how to segment depends on a number of variables. They can be computation boundary, data merge or fork, intellectual property driven motivations and transition in the nature of data. Defining the modules also determines the nature of the data that flows between them. A typical algorithm also has setup and control issues. Some setup parameters deal with the overall computation while others are specific to computational blocks. The module specific constraints can be handled through control signals or properties. In streaming applications, the data itself can provide a level of flow control. Each module typically has a data valid signal coming in that ensures that the input data is valid. Furthermore there is also usually a data valid signal going out that indicates to the downstream modules that the output data of the module is ready to be consumed. All of these modules are stitched together by a top level or main entity which provides the overall setup for things like clock and tracing of signals into a file. Figure 3 shows a typical decomposition of an algorithm into a streaming pipeline of modules. There are a number of standard signals in SystemC that assist in connecting the modules together. In case the standard signals cannot provide the connectivity between modules, SystemC provides extensibility by allowing custom signals to be defined easily. This ability to define signals of varying complexity is key to its ability to model complex systems elegantly. Custom signals in Figure 3 are shown in red. At times there are cases where the size of the signal array maybe quite large; in which case it is preferable to define a custom signal that consists of a pointer to data rather than data itself. This is not something that would be done if the design was to be hardware synthesizable. However, for many applications where there is a need to develop the big picture model first and then optimize part or whole, this is something worth considering.
Figure 3 Modular Decomposition of an Algorithm
The signals in SystemC are called channels. SystemC comes with a number of “primitive channels, which can handle fixed point types, arbitrary precision integers, 4 level logic vectors and 4 level logic types amongst others. In order to model a more complicated signal behavior, “hierarchical channels” are created that can have any number of processes, modules, channels and ports within them. Signals are connected to the modules through ports. The interface for the module consists of the port definition on the input and output of a module.
The modules in SystemC are typically self-contained. They have well defined interfaces that enable upgrading the module with improved internal behavior while maintaining external connectivity. One can exchange the internal code in a compiled form so as to protect the intellectual property.
Example of a Simple Pipeline
The figure below shows a pipeline that implements a two dimensional filter in the Fourier domain. The aim is to highlight the potential of using SystemC to handle large data type using custom data type and to be able to visualize the data as it is transformed in the pipeline. It highlights the ability to embed visualization within a SystemC module. This visualization can be customized for each module, so as to be able to optimally view the data.
Figure 4 Simple SystemC Pipeline
The reader reads in the JPEG image and populates the RGB planes in a structure. The pointer to that structure is contained in a custom data type called rgb_pkt_ptr. A small visualization pipeline, based on Visualization Tool Kit (VTK), generates a visualization window. The visualization pipeline is run every time the module is run. In data and compute intensive applications, the ability to visualize data can be invaluable. The 2D filtering is performed on an image. This image is referenced using the pointer to data that actually resides in the reader. Another visualization window is used to display both image and its Fourier transform in the filter module. After the filtering the image is moved to the file writer using the same rgb_pkt_ptr custom data type. Then the writer records the data in a jpeg file.
Custom Data Types
The ability to define custom data types makes it easy to adapt the SystemC to any time of application. In the example, the data that needs to be passed between the modules consists of three large arrays. The code for implementing this data is shown below.
struct rgb_plane {
int red_plane[4096][4096];
int green_plane[4096][4096];
int blue_plane[4096][4096];
int width;
int height;
};
struct rgb_ptr_pkt {
rgb_plane *rgb_plane_ptr;
rgb_ptr_pkt& operator = (const rgb_ptr_pkt& rhs) {
rgb_plane_ptr = rhs.rgb_plane_ptr;
return *this;
}
inline bool operator == (const rgb_ptr_pkt& rhs) const {
return (rhs.rgb_plane_ptr == rgb_plane_ptr);
}
};
inline
ostream&
operator << ( ostream& os, const rgb_ptr_pkt& a )
{
os << "streaming of struct rgb_ptr_pkt not implemented";
return os;
}
void
sc_trace( sc_trace_file* tf, const rgb_ptr_pkt& a, const sc_string& name );
void sc_trace( sc_trace_file* tf, const rgb_ptr_pkt& a,
const sc_string& name )
{
sc_trace( tf, a.rgb_plane_ptr, name);
}
Four operations need to be defined for each custom data types. SystemC simulator uses these to perform the data movement between the modules. However there is another one defined in the source project that defines a type which contains the three planes and avoids the use of pointer. This data type will be the one to use in case hardware synthesis is desired.
Visualizing Data
For complex algorithms or those dealing with a variety of data streams of differing complexity, the challenge is at times visualizing the data to see the accuracy of computation. Its especially true for 2D and 3D applications. SystemC also provides the facility to log signals into vcd (Value Change Dump) or wif (Waveform Intermediate Format) files, creating is an efficient way to view all the signals of interest over short or long intervals of time in parallel. There are freeware vcd viewers available to view these types of file. These files can also be read by most of the EDA tools. These tools tend to have more sophisticated ways of viewing signals.
The sample program introduces a novel concept of using small visualization pipelets that are embedded in each module. It uses the vtk (Visualization Tool Kit) for implementing these pipelets. They are run every time the module is run. The pipelet is initialized when the module is initialized and before it enters the main loop. It is possible to customize the pipelet based on the nature of data being operated upon in that module. The visualization pipelet in the filter module depicts the data at three different points during the transformations.
Figure 5 shows that the same pipelet is being used to render the RGB planes in a window. The interactor controls the mouse interaction. The image in the window can be rotated, zoomed and moved around the window for better viewing. VTK provides a rich set of tools to make the rendered visualization more insightful. “VTK User’s Guide” in combination with many examples that can be found off the web can provide a better understanding in exploiting the inherent strengths of vtk.
Click to enlarge
Figure 5 Visualization in the 2D Filter Module
Managing Complexity
SystemC helps technical managers by enforcing an interface driven style that is also hierarchical in nature. Once the modules have been identified and interfaces defined, they can be distributed over multiple resources and managed. Furthermore, they can be unit tested with test benches. If the module is sufficiently complex, it can be divided further. SystemC based development handles the boundaries of hardware and software in a seamless manner. The same code can be implemented in either domain or any shade of combination of the two.
For algorithm developers and system architects, SystemC provides a consistent vernacular from the paper concept to implementation in any platform. This ability to provide a consistent interface is another way of managing the development of complex systems. Most current tools and languages are either too high level for being efficient in translating to the implementation platform, or these languages are too low a level for algorithm developers or system architects to use.
The visualization support shown here by example is especially effective in applications dealing with 2D and 3D data. Developers in genomic signal processing and biotechnology can also exploit these modeling techniques, since they need to model the behavior of complex organisms over time.
There are a number of good books written about SystemC that ease the learning curve. “SystemC: From Ground Up” by David C. Black and Jack Donovan provides detailed insights into using SystemC for implementing complex hardware/software systems.
Both SystemC and vtk described in this article are complex software packages and both of them have C++ as their building foundation. While they are both powerful in the capabilities they deliver, when combined they provide the tool much needed in current product and technology development. And like most good things in life, they are free.
Author:
Imran H. Khan
President, SoftServ International Corporation
i.khan@softserv-intl.com
Download source of simple pipeline project from
http://www.softserv-intl.com/index_files/Page461.htm
Web Sites of Interest:
- http://www.systemc.org/
- http://public.kitware.com/VTK/
Related Articles
- Managing the complexity of embedded software development through design automation tools
- Optimizing Automated Test Equipment for Quality and Complexity
- Why Low Complexity Video Coding is Answer to UHD TV Success
- Managing energy consumption in wireless IoT devices
- Hybrid Hardware Architecture for Low Complexity Motion Estimation Algorithm
New Articles
Most Popular
E-mail This Article | Printer-Friendly Page |