Electronic Design

Learn To Manage All Kinds of Complexity With SystemC

If you start thinking “outside the box,” you’ll realize that SystemC is actually an ideal platform to model almost any real-life system or organism.

SystemC came about because of the need to model systems-on-a-chip (SoCs). SoCs require concurrent modeling of hardware and software, increasing complexity to a level that could not be managed any other way. Today’s use of SystemC ranges from SoC design to FPGA design to test and verification of chips.

However, if we look a little deeper, it becomes clear that SystemC has much more to offer in a variety of different technology domains and applications. The platform is actually well-suited to model almost any real-life system or organism. It offers an extensible framework, an integral concept of time at multiple scales, the ability to encapsulate algorithms and behavior in modules with well-defined interfaces, the ability to model concurrent behavior, hardware agnosticism, and the ability to provide a variety of visualization mechanisms.

SystemC is essentially a C++ library that extends the C++ language by adding a timed model and hardware semantics to accurately model the hardware. Interestingly, it separates modules encapsulating behavior from that of the communication mechanisms between them. That characteristic coupled with the ability to encapsulate and develop a hierarchical implementation makes it possible to start 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. The parts and the interactions are labeled at that scale. Upon further magnification, the part reveals a whole different set of entities and their interactions. This top-down approach hasn’t been widely explored in SystemC. Most current SystemC applications aim at chip synthesis and testing, usually more bottom-up uses of SystemC.

This article looks at a more holistic approach to using SystemC for modeling. It 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 method 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 isn’t an issue at this stage. The clock that supplies timing to the modules 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 a system architecture model (SAM). It’s unimportant to know how the system is going to be partitioned into hardware and software. A SAM exposes the texture of computation needed in the modules. It shows the complexity and nature of computations involved, as well as 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. As a result, an architect can 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 selecting the implementation architecture. Figure 1 highlights SystemC’s ability to support the different phases of the design cycle.

Modeling Time

SystemC’s simulator has the flexibility to create any number of clocks with 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. Figure 2 visually describes the modules running at different time scales and starting at varying times.

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, and can be referred to as a 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 yield 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 an opportunity to explore suitability among different hardware architectures for the modules in the system. Even though this approach isn’t 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 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 the executable specification, which captures the dynamic and interactive behavior. Once compiled, this executable runs to produce the simulated dynamic behavior of the final system.

Modularizing Algorithms

In most cases, an algorithm can be segmented into modules with data streaming in and out. The decision on how to segment the algorithm depends on a number of variables. They can include computation boundary, data merge or fork, intellectual-property-driven motivations, and a transition in the nature of the data. Defining the modules also determines the nature of the data that flows between them.

A typical algorithm will also run into 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 will ensure the input data is valid. Furthermore, there’s also usually a data-valid signal going out that indicates to the downstream modules that the module’s output data 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 functions like clocking and tracing signals into a file. Figure 3 shows a typical decomposition of an algorithm into a streaming pipeline of modules. A number of standard signals in SystemC assist in connecting the modules together.

In case the standard signals can’t supply the connectivity between modules, SystemC offers extensibility by allowing custom signals to be easily defined. Defining signals of varying complexity is key to SystemC’s ability to model complex systems elegantly. The custom signals in Figure 3 are shown in red. In some cases, the signal array may be quite large. If so, it’s preferable to define a custom signal that consists of a pointer to data rather than data itself. This isn’t something that would be done if the design were to be hardware-synthesizable. However, for many applications in which there’s a need to develop the big picture model first, and then optimize part or whole, it’s something worth considering.

The signals in SystemC are called channels. SystemC comes with a number of “primitive channels, which can handle fixed-point types, arbitrary precision integers, four-level logic vectors, and four-level logic types, among others. To model a more complicated signal behavior, “hierarchical channels” are created. Such channels can have any number of processes, modules, channels, and ports within them. Signals connect to the modules through ports. The interface for the module consists of the port definition on the input and output of a module.

SystemC modules 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 to protect the intellectual property.

Simple Pipeline Example

Figure 4 shows a pipeline that implements a two-dimensional filter in the Fourier domain. The aim is to show the potential of using SystemC to handle large data types using custom data types, and visualize the data as it’s transformed in the pipeline. It highlights the ability to embed visualization within a SystemC module. This visualization can be customized for each module to optimally view the data.

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 displays both the image and its Fourier transform in the filter module. After 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 SystemC to any type of application. In the example discussed previously, the data that needs to be passed between modules consists of three large arrays. The following code implements this data:

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 const rgb_ptr_pkt& a )
\{
   os    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 must be defined for each custom data type. The SystemC simulator uses these to perform the data movement between the modules. However, another one defined in the source project defines a type that contains the three planes and avoids the use of a pointer. This data type should be used if hardware synthesis is desired.

Visualizing Data

For complex algorithms, or those dealing with a variety of data streams of differing complexity, the challenge occasionally involves visualizing the data to see the accuracy of computation. That is especially true for 2D and 3D applications. SystemC also offers the ability to log signals into VCD (Value Change Dump) or WIF (Waveform Intermediate Format) files, creating an efficient way to view all signals of interest in parallel over short or long time intervals. Freeware VCD viewers exist to view these types of files. Most of the EDA tools can also read such files. These tools tend to offer more sophisticated ways of viewing signals.

The sample program introduces a novel concept of using small visualization pipelets embedded in each module. It uses the VTK to implement these pipelets. They’re run every time the module is run. The pipelet is initialized when the module is initialized and before it enters the main loop. It’s possible to customize the pipelet based on the nature of the data being operated on in that module. The visualization pipelet in the filter module depicts the data at three different points during the transformations.

Figure 5 shows the same pipelet 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 for better viewing. VTK provides a rich set of tools to make the rendered visualization more insightful. The “VTK User’s Guide” in combination with many examples that can be found on the Web provide a more rounded understanding of VTK’s inherent strengths.

Managing Complexity

SystemC helps technical managers by enforcing an interface-driven style that’s also hierarchical in nature. After identifying the modules and defining the interfaces, 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 or combination of the two.

For algorithm developers and system architects, SystemC offers a consistent vernacular from the paper concept to implementation on 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 to be efficient in translating to the implementation platform, or these languages are too low a level for algorithm developers or system architects.

The example visualization support shown here is especially effective in applications dealing with 2D and 3D data. Developers in genomic signal processing and biotechnology can also exploit these modeling techniques, because they need to model the behavior of complex organisms over time.

A number of good books written about SystemC help 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. They’re both powerful in the capabilities they deliver, but when combined they provide a much-needed tool for current product and technology development. And like most good things in life, they cost nothing.

Additional Resources:

Download source code of a simple pipeline project from
www.softserv-intl.com/complexity.zip
www.sy stemc.org/
http://public.kitware.c om/VTK/

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish