This website uses cookies. By using this site, you consent to the use of cookies. For more information, please take a look at our Privacy Policy.
Home > FPGA Technical Tutorials > FPGAs: World Class Designs > Other Design Flows > C/C ++ -BASED DESIGN FLOWS

TABLE OF CONTENTS

Xilinx FPGA FPGA Forum

C/C ++ -BASED DESIGN FLOWS

FONT SIZE : AAA

With regard to the traditional HDL-based flows introduced in Chapter 5, a  design commences with an original concept, whose high-level definition is  determined by system architects and system designers. It is at this stage that  macro-architecture decisions are made, such as partitioning the design into  hardware and software components.   

The resulting specification is then handed over to the hardware design  engineers, who commence their portion of the development process by performing microarchitecture definition tasks such as detailing control structures,  bus structures, and primary data path elements. These microarchitecture definitions, which are often performed in brainstorming sessions on a whiteboard,  may include performing certain operations in parallel versus sequential, pipelining portions of the design versus nonpipelining, sharing common resources  (for example, two operations sharing a single multiplier, versus using dedicated resources) and so forth.   

Eventually, the design intent is captured by writing RTL VHDL/Verilog.  Following verification via simulation, this RTL is then synthesized down to  a structural netlist suitable for use by the target technology’s place-and-route  applications ( Figure 6-1 ).   

Traditional (simplified) HDL-based flowspng

At the time of this writing, these VHDL or Verilog-based flows account for  around 95 percent of all ASIC and FPGA designs; however, there are a number of problems associated with these flows:  

● Capturing the RTL is time-consuming : Even though Verilog and VHDL are  intended to represent hardware, it is still time-consuming to use these languages to capture the functionality of a design.  

● Verifying RTL is time-consuming : Using simulation to verify large designs  represented in RTL is computationally expensive and time-consuming.

● Evaluating alternative implementations is difficult : Modifying and reverifying RTL to perform a series of what-if evaluations of alternative microarchitecture implementations is difficult and time-consuming. This means  that the number of evaluations the design team can perform may be limited,  which can result in a less-than-optimal implementation.  

● Accommodating specification changes is difficult : If any changes to the  specification are made during the course of the project, folding these  changes into the RTL and performing any necessary reverification can be  painful and time-consuming. This is a significant consideration in certain  application areas, such as wireless projects, because broadcast standards  and protocols are constantly evolving and changing.  

● The RTL is implementation specific : Realizing a design in an FPGA typically requires a different RTL coding style from that used for an ASIC  implementation. This means that it can be extremely difficult to retarget  a complex design represented in RTL from one implementation technology to another. This is of concern when one is migrating an existing ASIC  design into an FPGA equivalent or creating an FPGA design to be used as  a prototype for a future ASIC implementation.

One way to view this is that all of the implementation intelligence associated  with the design is hardcoded into the RTL, which therefore becomes implementation specific. It’s important to understand that this implementation specificity goes beyond the coarse ASIC-versus-FPGA boundary, which dictates  that RTL intended for an FPGA implementation is not suitable for an optimal ASIC realization, and vice versa. Even assuming a single target device  architecture, the way in which a set of algorithms is used to process data may  require a number of different microarchitecture implementations, depending  on the target application areas.   

Actually, to be scrupulously fair, we should probably note that the same  RTL may be used to drive both ASIC and FPGA implementations. The reason  for doing this is to avoid the risk of introducing a functional bug into the RTL  when retargeting the code, but there is typically a penalty to be paid. That is, if code originally targeted toward an FPGA implementation is subsequently  used to drive an ASIC implementation, the resulting ASIC will typically  require more silicon real estate and have higher power consumption as compared to using RTL created with an ASIC architecture in mind. Similarly, if  code originally targeted toward an ASIC implementation is subsequently used  to drive an FPGA implementation, the ensuing FPGA will typically take a  significant performance hit as compared to using RTL created with an FPGA  architecture in mind.   

RTL is less than ideal for hardware-software codesign: System-on-chip  (SoC) devices are generally understood to be those that include microprocessor cores. Irrespective of whether these designs are to be realized using ASICs  or FPGAs, today’s SoCs are exhibiting an ever-increasing amount of software  content. When coupled with increased design reuse on the hardware side, in  many cases it is necessary to verify the software and hardware concurrently  so as to completely validate such things as the system diagnostics, RTOS,  device drivers, and embedded application software. Generally speaking, it  can be painful verifying (simulating) the hardware represented in VHDL or  Verilog in conjunction with the software represented in C/C ++ or assembly  language.   

One approach that addresses the issues enumerated above is to perform the  initial design capture at a higher level of abstraction than can be achieved with  RTL VHDL/Verilog. The first such level is to use some form of C/C ++ , but  as usual nothing is simple because there are a variety of alternatives, including  SystemC, augmented C/C ++ , and pure C/C ++ .

C versus C ++ and Concurrent versus Sequential

Before we leap into the fray, we should tie down a couple of points to ensure  that we’re all marching in step to the same beat. First, there is a wide variety of programming languages available, but—excepting specialist application  areas—the most commonly used by far are traditional C and its object-oriented  offspring C ++ . For our purposes here, we will refer to these collectively as  C/C ++ .   

The next point of import is that, by default, statements in languages like  C/C ++ are executed sequentially. For example, assuming that we have already  declared three integer variables called a, b, and c, then the following statements:

a = 6; /* Statement in C/C + + program */  
b = 2; /* Statement in C/C + + program */  
c = 9; /* Statement in C/C + + program */

would, perhaps not surprisingly, occur one after the other. However, this has  certain implications; for example, if we now assume that the following statements occur sometime later in the program:

a = b; /* Statement in C/C + + program */  

b = a; /* Statement in C/C + + program */

then a (which initially contained 6) will be loaded with the value currently  stored in b (which is 2). Next, b (which initially contained 2) will be loaded  with the value currently stored in a (which is now 2), so both a and b will end  up containing the same value.   The sequential nature of programming languages is the way in which software engineers think. However, hardware design engineers have quite a different view of the world. Let’s assume that a piece of hardware contains two  registers called a and b that are driven by a common clock signal. Let’s further  assume that these registers have previously been loaded with values of 6 and 2,  respectively. Finally, let’s assume that at some point in the HDL code, we see  the following statements:

a = b; /* Statement in VHDL/Verilog Code */  

b = a; /* Statement in VHDL/Verilog Code */

As usual, this syntax doesn’t actually represent VHDL or Verilog; it’s just a  generic syntax used only for the purposes of this example. Generally speaking,  hardware engineers would expect both of these statements to be executed concurrently (at the same time). This means that a (which initially contained 6)  will be loaded with the value stored in b (which was 2) while—at the same  time— b (which initially contained 2) will be loaded with the value stored  in a (which was 6). The result is that the initial contents of a and b will be  exchanged.   As usual, of course, the above is something of a simplification. However,  it’s fair to say that HDL statements will execute concurrently by default,  unless sequential behavior is forced by means of techniques like blocking assignments. Thus, by default, RTL-based logic simulators will execute  the statements shown above in this concurrent manner; similarly RTL-based  logic synthesis tools will generate hardware that handles these two activities  simultaneously. By comparison, unless explicitly directed to do otherwise (by  means of the techniques introduced later in this chapter), C/C ++ statements  will e xecute sequentially.

SystemC-based Flows  

FAQs  

What exactly is SystemC (and where did it come from)?  

Before we consider SystemC-based flows, it is probably a good idea to elaborate  a bit more on just what SystemC is, because there is typically some confusion on  this point . SystemC 1.0 – One of the underlying concepts behind SystemC is that it is an  open-source environment to which everyone contributes. As an example, consider  Linux, which was rough around the edges at first. Based on contributions from  different folks, however, Linux eventually became a real operating system (OS)  with the potential to challenge Microsoft. In this spirit, a relatively undocumented  SystemC 1.0 was let loose to roam wild and free circa 2000. SystemC 1.0 was a  C ++ class library that facilitated the representation of notions such as concurrency (things happening at the same time), timing, and I/O pins. By means of this  class library, engineers could capture designs at the RTL level of abstraction.  

One advantage of this early incarnation was that it facilitated hardware/software codesign environments. Another was that SystemC representations at the  RTL level of abstraction might simulate 5 to 10 times faster than their VHDL and  Verilog counterparts. On the downside, it was harder and more time-c onsuming  to capture an RTL-level design in SystemC 1.0 than with VHDL or Verilog.  Furthermore, there was a scarcity of design tools that could synthesize SystemC  1.0 representations into netlist-level equivalents with any degree of sophistication.  

SystemC 2.0 – Later, in 2002, SystemC 2.0 arrived on the scene. This augmented the 1.0 release with some high-level modeling constructs such as FIFOs  (a form of memory that can accept and subsequently make available a series of  words of data and that operates on a first-in first-out principle). The 2.0 release  also included a variety of behavioral, algorithmic, and system-level modeling  capabilities, such as the concepts of transactions and channels (which are used to  describe the communication of data between blocks at an abstract level).

To gain a little more perspective on SystemC, let’s first consider a typical scenario of how things would have worked using the original SystemC 1.0. As a  simple example, let’s assume that we have two functions called f ( x ) and g ( x )  that have to communicate with each other ( Figure 6-2 ).   

Interfacing in SystemC 1.0png

In this case, the interface between the blocks would have to be defined  at the pin level. The real problem with this approach occurs when you are in  the early stages of a design, because you are already defining implementation  details such as bus widths. This makes things difficult to change if you wish to  experiment with different what-if architectural scenarios. This aspect of things  became much easier with SystemC 2.0, which allowed abstract interfaces to be  declared between the blocks ( Figure 6-3 ).   

Interfacing in SystemC 2.0png

Now, the interfacing between the blocks can be performed at the level of  abstract records on the basis that, in the early stages of the design cycle, we don’t really care how data gets from point a to point b, just that it does get  there somehow.   

These abstract interfaces facilitate performing architectural evaluation early  in the design cycle. Once the architecture starts to firm up, you can start refining the interface by using high-level constructs such as a FIFO to which one  would assign attributes like width and depth and characteristics like blocking  write, nonblocking read, and how to behave when empty or full. Still later, this  logical interface can be replaced by a completely specified (pin-level) interface  that binds the functional blocks together at a more physical level.

Levels of Abstraction  

Truth to tell, this is where things start to become a little fuzzy around the  edges, not the least because one runs into different definitions depending on to whom one is talking. As a first pass, however, we might take a stab at capturing the different levels of SystemC abstraction, as shown in Figure 6-4 .   

This is why things become confusing, because SystemC can mean all  things to all people. To some it’s a replacement for RTL VHDL/Verilog, while  to others it’s a single language that can be used for system-level specification,  algorithmic and architectural analysis, behavioral design, and testbenches for  use in verification.   

One area of confusion comes when you start to talk about behavioral synthesis. This encompasses certain aspects of both the algorithmic and transactional levels (in the latter case, however, you have to be careful as to how to  define your transactions). 

SystemC-based Design-flfl ow Alternatives

This is a tricky one because one might go various ways here.  

● Many of today’s designs begin life as complex algorithms. In this case, it  is very common to start by creating a C or C ++ representation. This representation can be used to validate the algorithms by compiling it into a  form that can be run (simulated) 1,000 or more times faster than an RTL  equivalent. In the case of the HDL-based flows discussed in Chapter 5, this  C/C ++ representation of the algorithms would then be hand-translated into  RTL VHDL/Verilog. The C/C ++ representation will typically continue to  be used as a golden model, which means it can be linked into the RTL simulator and run in parallel with the RTL simulation. The results from the C/ C ++ and RTL models can be compared so as to ensure that they are functionally equivalent.

● Alternatively, in one flavor of a SystemC-based flow, the original C/C ++model could be incrementally modified by adding timing, concurrency, pin  definitions, and so forth to transform it to a level at which it would be amenable to SystemC-based RTL or behavioral synthesis.  

● In another flavor of a SystemC-based flow, the design might be initially  captured in SystemC using system, algorithmic, or transaction-level constructs that could be used for verification at a high level of abstraction. This  representation could then be incrementally modified to bring it down to a  level at which it would be amenable to SystemC-based RTL or behavioral  synthesis.

Irrespective of the actual route by which one might get there, let’s assume that  we are in possession of a SystemC representation of a design that is suitable  for SystemC-based behavioral or RTL synthesis. In this case, there are two  main design-flow alternatives, which are:  

  1. to translate the System C into RTL VHDL/Verilog automatically and  then to use conventional RTL synthesis technology, or  

  2. 2. to use SystemC-based synthesis to generate an implementation-level  netlist directly.

—Technology Trade-offs—  

● There are two schools of thought here. One says that synthesizing the  SystemC directly into the implementation-level netlist offers the cleanest,  fastest, and most efficient route.  

● Another view is that it’s better to translate the SystemC into RTL VHDL/ Verilog first because RTL is the way design engineers really visualize their  world; that this level is a natural staging point for integrating design blocks  (including third-party IP) originating from multiple sources; and that  Verilog/VHDL synthesis technology is extremely mature and powerful (as  compared to SystemC-based synthesis technology).   

Both of these flows can be applied to ASIC or FPGA targets ( Figure 6-5 ).   

The first SystemC synthesis applications were predominantly geared  toward ASIC flows, so they didn’t do a very good job at inferring FPGAs pecific entities such as embedded RAMs, embedded multipliers, and so forth.  More recent incarnations do a much better job of this, but the level of sophistication exhibited by different tools is a moving target, so the prospective user is  strongly advised to perform some indepth evaluations before slapping a bundle  of cash onto the bargaining table.   

Note that Figure 6-5 shows the use of implementation specific SystemC  to drive the ASIC versus FPGA flows. As soon as you start coding at the RTL  level and adding timing concepts, be it in VHDL, Verilog, or SystemC, then  achieving an optimal implementation requires that the code be written with a  specific target architecture in mind.

Alternative SystemC flowspng

—Technology Trade-offs—  

● Once again, having said this, the same SystemC can be used to drive  both ASIC and FPGA flows, but there is typically a penalty to be paid.  If SystemC code originally targeted toward an FPGA implementation is  subsequently used to drive an ASIC flow, the resulting ASIC will typically  require more silicon real estate and have higher power consumption as  compared to using code created with an ASIC architecture in mind.  

● Similarly, if code originally targeted toward an ASIC implementation is  subsequently used to drive an FPGA flow, the ensuing FPGA will typically  take a significant performance hit as compared to using code created with  an FPGA architecture in mind. This is primarily a result of hard-coding the  microarchitecture definition in the source.

Insider Info  

Depending on who you are talking to, folks either love SystemC or they loath it.  Most would agree that SystemC 2.0 is very promising and that there’s no other  language that provides the same capabilities (some of these capabilities are being  added into SystemVerilog, but not all of them).  

On the downside, many design engineers are reasonably proficient at writing  C, but most of them are significantly less familiar with the object-oriented aspects  of C ++. So requiring them to use SystemC means giving them more power on the  one hand, while thrusting them into a world they don’t like or understand on the  other. It’s also true that while SystemC can be very useful for verification and highlevel system modeling, in some respects it’s still relatively immature toolwise with  regard to actual implementation flows.

One school of thought says that, although SystemC is difficult to write by hand  and also difficult to synthesize, which makes it a somewhat clumsy specification  language, it does provide a powerful framework for simulation across languages  and levels of abstraction. At the time of this writing, a number of companies that  were strong supporters of SystemC in the United States have grown somewhat less  vocal over the last few years. On the other hand, SystemC is gaining some ground  in Europe and Asia. What does the future hold? Wait a few years, and I’ll be happy  to tell you!

Augmented C/C ++-based Flows

FAQs  

What do we mean by augmented C/C ++?  

There are two ways in which standard C/C ++ can be augmented to extend its  capabilities and the things it can be used to represent. The first is to include special comments, known as commented directives or pragmas, into the pure C/C ++ code. These comments can subsequently be recognized and interpreted by parsers,  precompilers, compilers, and other tools and used to add constructs to the code or  modify the way in which it is processed. One significant drawback to this approach  is that simulation requires the use of proprietary C/C ++ compilers as opposed to  using standard off-the-shelf compilers. This limits the options customers have and is  only viable if standards are developed for multiple EDA vendors to leverage.  

The other way in which C/C++ can be augmented is to add special keywords  and statements into the language. This is a very popular technique, and there is  a veritable plethora of such language variants roaming wild and free around the  world, each tailored toward a different application area. One downside of this  approach is that, once again, it requires proprietary C/C ++ compilers; otherwise,  tools such as simulators that have not been enhanced to understand these new  keywords and statements will crash and burn. A common solution to this problem is to wrap standard #ifdef directives around the new keywords and statements  such that a precompiler can be used to discard them as required (this is somewhat  inelegant, but it works).

In the case of capturing the functionality of hardware for ASIC and FPGA  designs, it is necessary to augment standard C/C ++ with special statements  to support such concepts as clocks, pins, concurrency, synchronization, and  resource sharing.   

Assuming that you have an initial model represented in pure C/C ++ , the  first step would be to augment it with clock statements, along with interface  statements used to define the input and output pins. You could then use an  appropriate synthesis tool to generate an implementation (as discussed below).

However, because C/C ++ is by nature sequential, the resulting hardware can  be horribly slow and inefficient if the synthesis tool is not capable of locating  potential parallelisms and exploiting them.   For example, assume that we have the following statements in a C/C ++representation of the design:

a = 6; /* Standard C/C + + statement */  

b = 2; /* Standard C/C + + statement */  

c = 9; /* Standard C/C + + statement */  

d = a + b; /* Standard C/C + + statement */  

:  

etc

By default, each sign is assumed by the synthesis application to represent one  clock cycle. Thus, if the above code were left as is, the augmented C/C ++ synthesis tool would generate hardware that loaded variable (register) a with 6 on  the first clock, then b with 2 on the next clock, then c with 9 on the next clock,  and so forth. Thus, by hardware standards, this would run horribly slowly.   

Of course, most synthesis tools would be capable of locating and exploiting  the potential parallelisms in the above example, but they might well miss more  complex cases that require human consideration and intervention. For the purposes of these discussions, however, we shall continue to work with this simple  test case. The point is that an augmented C/C ++ language will have keywords  like “ parallel ” (or “ par ” ) and “ sequential ” (or “ seq ” ) that will instruct the  downstream synthesis application as to which statements should be executed in  parallel, and so forth. For example:

parallel; /* Augmented C/C + + statement */  

a = 6; /* Standard C/C + + statement */  

b = 2; /* Standard C/C + + statement */  

c = 9; /* Standard C/C + + statement */  sequential; /* Augmented C/C + + statement */  

d = a  b; /* Standard C/C + + statement */ 

 :  

etc  

In this case, the parallel statement instructs the synthesis tool that the following statements can be implemented concurrently, while the sequential statement implies that the preceding operations must occur prior to any subsequent  actions taking place. Of course, these parallel and sequential statements can be  nested as required.

Things become more complex in the case of loops, depending on whether the  designer wishes to unravel them partially or fully. Just to give a point of reference, we might visualize a loop as being something like “ for i = 1 to 10 in increments of 1 do xxxx, yyyy, and zzzz ” . In some cases, it may be possible to simply  associate a parallel or sequential statement with the loop, but if more subtlety is  required, the designer may be obliged to completely rewrite these constructs.   It may also be necessary to add “ share ” statements if resource sharing is  required, and “ channel ” statements to share signals between expressions, and  the list goes on.

Augmented C/C++ Design-flfl ow Alternatives

As usual, one might go various ways here. As we previously discussed, in the  case of a design that begins life as a suite of algorithms, it is very common  to start by creating a C or C ++ representation. Following verification, this  C/C ++ model can be incrementally modified by adding statements for clocks,  pins, concurrency, synchronization, and resource sharing so as to make the  model suitable for the appropriate synthesis utility. Alternatively, the design  might be captured using the augmented C/C ++ language from the get-go.   Irrespective of the actual route we might take to get there, let’s assume that  we are in possession of an augmented C/C ++ representation of a design that is  suitable for synthesis. Once again, there are two main design-flow alternatives,  which are (1) to translate the augmented C/C ++ into Verilog or VHDL at the  RTL level of abstraction automatically and to then use conventional RTL synthesis technology, or (2) to use an appropriate augmented C/C ++ synthesis engine.   

And, once again, one school of thought says that synthesizing the augmented C/C ++ directly into the implementation level netlist offers the cleanest, fastest, and most efficient route. Others say that the RTL Verilog/VHDL  level is the natural staging post for design integration and that today’s RTL  synthesis technology is extremely mature and powerful.   Both of these flows can be applied to ASIC or FPGA targets ( Figure 6-6 ).  The first augmented C/C++ synthesis applications were predominantly geared  toward ASIC flows. This meant that these early incarnations didn’t do a tremendous job when it came to inferring FPGA-specific entities such as embedded  RAMs, embedded multipliers, and so forth. More recent versions of these tools  do a much better job at this, but, as usual, the prospective user is strongly advised  to perform some in-depth evaluations before handing over any hard-earned cash.   Note that Figure 6-6 shows the use of implementation-specific code to drive  the ASIC versus FPGA flows because achieving an optimal implementation  requires that the code be written with a specific target architecture in mind. In  reality, the same code can be used to drive both ASIC and FPGA flows, but there  is usually a penalty to be paid (see the discussions on SystemC for more details).

Pure C/C ++-based Flows

Last, but not least, we come to pure C/C ++ -based flows. In reality, the term pure  C/C++ actually refers to industry-standard C/C ++ that is minimally augmented  with SystemC data types to allow specific bit widths to be associated with variables and constants.   

Although relatively new, pure C/C ++ -based flows offer a number of advantages as compared to other C-based flows and traditional Verilog-/VHDL-based  flows:  

● Creating pure C/C++ is fast and efficient : Pure untimed C/C ++ representations are more compact and easier to create and understand than equivalent  SystemC and augmented C/C ++ representations (and they are much more  compact than their RTL equivalents, requiring perhaps 1/10th to 1/100th of  the code).  

● Verifying C/C++ is fast and efficient : A pure untimed C/C ++ representation will simulate significantly faster than a timed SystemC or augmented  C/C ++ model and 100 to 10,000 times faster than an equivalent RTL representation. In fact, pure C/C ++ models are already widely created and  used by system designers for algorithm and system validation.

● Evaluating alternative implementations is fast and efficient : Modifying  and reverifying pure untimed C/C ++ to perform a series of what-if evaluations of alternative microarchitecture implementations is fast and efficient.  This facilitates the design team’s ability to arrive at fundamentally superior  microarchitecture solutions. In turn, this can result in significantly smaller  and faster designs as compared to flows based on traditional hand-coded  RTL methods.  

● Accommodating specification changes is relatively easy : If any changes to  the specification are made during the course of the project, it’s relatively  easy to implement and evaluate these changes in a pure untimed C/C ++representation, thereby allowing the changes to be folded into the resulting  implementation.

Furthermore, as noted earlier in this chapter, one of the most significant problems associated with existing SystemC and augmented C/C ++ -based design  flows is that the implementation intelligence associated with the design has to be  hard-coded into the model, which therefore becomes implementation specific.   

A key aspect associated with a pure untimed C/C ++ -based design flow is  that the code presented to the synthesis engine is just what someone would  write if he or she didn’t have any preconceived hardware implementation or  target device architecture in mind. This means that the C/C ++ code that system designers write today is an ideal input to this form of synthesis. The only  modification typically required to use a pure C/C ++ model with the synthesis  engine is to add a single special comment to the source code to indicate the top  of the functional portion of the design (anything conceptually above this point  is considered to form part of the testbench).   

As opposed to adding intelligence to the source code (thereby locking it  into a target implementation), all of the intelligence is provided by the user  controlling and guiding the synthesis engine itself ( Figure 6-7 ).  

Once the synthesis engine has parsed the source code, the user can use it to  perform microarchitecture trade-offs and evaluate their effects in terms of size  and speed. The synthesis engine analyzes the code, identifies its various constructs and operators, along with their associated data and memory dependencies, and automatically provides for parallelism wherever possible. The engine  also provides a graphical interface that allows the user to specify how different  elements should be handled. For example, the interface 

● allows the user to associate ports with registers or RAM blocks;  

● identifies constructs like loops and allows the user to specify on an individual  basis whether they should be fully unraveled, partially unraveled, or left alone;  

● allows the user to specify whether loops and other constructs should be  pipelined;  

● allows the user to perform resource sharing on specific entities;  

● and so forth.  

These evaluations are performed on the fly, and the synthesis engine reports  total size/area and latency in terms of clock cycles and I/O delays (or through put time/cycles in the case of pipelined designs). The user-defined configuration associated with each what-if scenario can be named, saved, and reused as  required (it would be almost impossible to perform these trade-offs in a timely  manner using a conventional hand-coded RTL-based flow).

Once the user’s evaluations are completed, clicking the “ Go ” button causes the  synthesis engine to generate corresponding RTL VHDL. This code can subsequently be used by conventional logic synthesis or physically aware synthesis  applications to generate the netlist used to drive the downstream implementation (place-and-route, etc.) tools.

FAQs  

Why not synthesize directly into a gate-level netlist?  

As usual, it would be possible to synthesize the pure untimed C/C ++ directly into  a gate-level netlist (this alternative is not shown in Figure 6-7 ). However, generating  the intermediate RTL provides a comfort zone for the engineers by allowing them  to check that they are satisfied with the implementation decisions that have been made during the course of the C/C ++ to RTL translation. Furthermore, generating  intermediate RTL is useful because this is the level of abstraction where hardware  design engineers generally stitch together the various functional blocks forming  their designs. Large portions of today’s designs are typically presented in the form  of IP blocks represented in RTL. This means that the intermediate RTL step shown  in Figure 6-7 is a useful point in the design flow for integrating and verifying the  entire hardware system. The design engineers can then take full advantage of their  existing RTL synthesis technology, which is mature, robust, and well understood.

Different Levels of Synthesis Abstraction

The fundamental difference between the various C/C ++ -based flows presented in this chapter is the level of synthesis abstraction each can support.  For example, although SystemC offers significant system-level, algorithmic,  and transaction-level modeling capabilities, its synthesizable subset is at a relatively low level of abstraction. Similarly, although augmented C/C ++ representations are closer to pure C/C ++ than are their SystemC counterparts,  which means that they simulate much more quickly, their synthesizable subset  remains significantly lower than would be ideal.   

This lack of synthesis abstraction causes the timed SystemC and augmented C/C ++ representations to be implementation specific. In turn, this  makes them difficult to create and modify and significantly reduces their flexibility with regard to performing what-if evaluations and retargeting them  toward alternative implementation technologies ( Figure 6-8 ).

Different levels of CC  synthesis abstraction.png

By comparison, the latest generation of pure untimed C/C ++ synthesis  technology supports a high level of synthesis abstraction. Non-i mplementationspecific C/C ++ models are very compact and can be quickly and easily  created and modified. By means of the synthesis engine itself, the user can  quickly and easily perform what-if evaluations and retarget the design toward  alternative implementation technologies. The result is that a pure C/C ++ - based design flow can dramatically speed implementation and increase design  flexibility as compared to other C/C ++ -based flows.

Insider Info  

Before anyone starts to pen irate letters claiming the author is anti-SystemC, it  should be reiterated that the discussions presented here are focused on the use of  the various flavors of C/C ++ in the context of FPGA implementation flows. In this  case, the tool-chain used to progress SystemC representations through to actual  implementations is relatively immature and unsophisticated. When it comes to system-level modeling and verification applications, however,  SystemC can be extremely efficacious (many users see SystemC and SystemVerilog  being used in conjunction with each other, with SystemC being employed for the  initial system-level design representation, and then SystemVerilog being used to  “ flesh out ” the implementation-level details.

Mixed-language Design and Verififi cation Environments

Last, but not least, we should note that a number of EDA companies can provide mixed-level design and verification environments that can support the  cosimulation of models specified at multiple levels of abstraction.   

In some cases, this may simply involve linking a C/C ++ model to a Verilog  simulator via its programming language interface (PLI) or to a VHDL simulator via its foreign language interface (FLI). Alternatively, one might find a  SystemC environment with the capability to accept blocks represented in  Verilog or VHDL.   

And then there are very sophisticated environments that start with a graphical block-based editor showing the design’s major functional units, where the  contents of each block can be represented using the following:

● VHDL  

● Verilog  

● SystemVerilog  

● SystemC  

● Handel-C  

● Pure C/C ++  

The top-level design might be in a traditional HDL that calls submodules  in the various HDLs and in one or more flavors of C/C ++ . Alternatively, the t op-level design might be in one of the flavors of C/C ++ that calls submodules in the various languages.   

In this type of environment, the VHDL, Verilog, and SystemVerilog representations are usually handled by a single-kernel simulation engine. This  engine is then cosimulated with appropriate engines for the various flavors of  C/C ++ . Furthermore, this type of environment will incorporate source-code  debuggers that support the various flavors of C/C ++ ; it will allow testbenches  to be created using any of the languages; and supporting tools like graphical  waveform displays will be capable of displaying signals and variables associated with any of the language blocks.   

In reality, the various mixed-language design and verification environment solution combinations and permutations change on an almost weekly  basis, so you need to take a good look at what’s out there before you leap into  the fray.









  • XC3S4000-5FGG900C

    Manufacturer:Xilinx

  • FPGA Spartan-3 Family 4M Gates 62208 Cells 725MHz 90nm Technology 1.2V 900-Pin FBGA Tray
  • Product Categories: FPGAs (Field Programmable Gate Array)

    Lifecycle:Active Active

    RoHS:

  • XC2C128-7TQ144C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 3K Gates 128 Macro Cells 152MHz 0.18um Technology 1.8V 144-Pin TQFP
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS: No RoHS

  • XC2C128-7VQ100I

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 3K Gates 128 Macro Cells 152MHz 0.18um Technology 1.8V 100-Pin VTQFP
  • Product Categories: Embedded - CPLDs (Complex Programmable Logic Devices)

    Lifecycle:Active Active

    RoHS: No RoHS

  • XC3S400-4FGG456I

    Manufacturer:Xilinx

  • FPGA Spartan-3 Family 400K Gates 8064 Cells 630MHz 90nm Technology 1.2V Automotive 456-Pin FBGA
  • Product Categories: FPGAs

    Lifecycle:Active Active

    RoHS:

  • XC5204-6PQ160I

    Manufacturer:Xilinx

  • FPGA XC5200 Family 6K Gates 480 Cells 83MHz 0.5um Technology 5V 160-Pin PQFP
  • Product Categories:

    Lifecycle:Obsolete -

    RoHS: No RoHS

Need Help?

Support

If you have any questions about the product and related issues, Please contact us.