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 > FPGA-Based Prototyping Methodology > Getting the design ready for the prototype > Selecting a subset of the design for prototyping

TABLE OF CONTENTS

Xilinx FPGA FPGA Forum

Selecting a subset of the design for prototyping

FONT SIZE : AAA

Most SoC designs include SoC technology elements that are not available in FPGA  technology such as PLL, analog circuitry, BIST, SoC primitives and third-party IP.  The following paragraphs describe some options to deal with SoC design elements  that do not map into FPGA.

SoC block removal and its effect

In the cases where SoC design elements are not available in FPGA technology, or  where there is no desire to prototype certain blocks, these blocks need to be  removed from the design. The removal may be as simple as removing a complete  RTL design file from the project, leaving an unpaired module definition which  might be inferred automatically as a black box. Alternatively, the RTL design file  may need to be replaced with a dummy file which explicitly includes the necessary  directive to set the module as a black box for synthesis.

In less tidy arrangements, the element to be removed may be buried in an RTL file  alongside other logic that we wish to keep. In that case it may be necessary to alter  the RTL, but a better approach, as we shall see in chapter 9, would be to predict at  the time that the RTL was written that the element might need to be removed.

Figure 76: removing a block from the design using `ifdef

/* defining the compiler macro for prototyping only*/

`define FPGA; 

 <other rtl code> 

/* soc_block is not instantiated when FPGA macro is defined

(leaving the commented instantiation line helps others to 

understand what has been done. Proper documentation would also be 

helpful ) */ 

`ifdef FPGA

/ soc_block block1 (signals.);

/* instantiating soc_block only when FPGA macro is not defined*/ 

`else

soc_block block1 (signals.);

`endif

 <other rtl code>

Taking this approach, a conditional branch may have been placed into the original  RTL code, based on a single macro. The example in Figure 76 shows the condition removal of a module using `define and `ifdef. 

The rest of the design that would normally connect with the removed logic may be  handled in different ways by different synthesis tools. Some tools will simply flag  the condition as an error error-out because there are dangling connections, but other  tools will also remove downstream logic which is not driven as a result of the  change; either up to a block boundary or other synthesis-invariant point, up to and  including the entire cone of downstream logic. Upstream, that logic which  previously drove the removed block will also be pruned as far as any upstream  sources which also drive other, non-pruned, cones of logic.  

To illustrate this effect, let us consider the small excerpt from a design shown in  Figure 77.  

Typical excerpt of logic before block removal.png

Let us suppose that Block A is not required in the prototype so we intend to simply  remove it and allow the synthesis to prune out the unnecessary logic. The ripple-out  effect of Block A’s removal upstream and downstream will depend upon the  synthesis tool’s defaults and configuration. In Figure 78 we see that for a specific  synthesis tool set-up, the upstream and downstream logic is mostly pruned as we  might expect. Block A is removed along with all mutually exclusive upstream logic.

The AND gate is the point at which pruning stops because it is also driving other  logic.  

Downstream, two effects are instructive. Firstly, the downstream blocks receiving  inputs from the removed block will be removed in turn unless they also receive data  inputs from other parts of the design (clock or reset inputs are not sufficient). So in  our example, Block B is completely removed, probably causing further pruning of  ITS downstream logic. Block C will undergo pruning because some internal logic  will not be driven when Block A is removed, while some other logic will remain  because it is driven from other sources.

Effect of removing Block A from Figure 77 and resultant pruning.png

The second item of note is that the black box may not be removed by default and  neither will its downstream logic, with the consequence that back-end tools will  need to handle the lack of inputs, which may or may not be possible. This can  manifest itself in some very subtle ways, for example, an instantiated BlockRAM  may survive until place and route and then prevent completion because of nondriven inputs. Even worse may be the setting of non-driven inputs to unexpected  values and the BlockRAM remains in circuit. 

Thus, we should take care with simple removal of blocks as a method for reducing  the size of our prototype. Trimming of upstream logic which is unique to the removed block is not usually a problem; however, pruning of downstream logic  may have widespread and unpredictable effects.

Synthesis tool settings for cross-boundary optimizations will have an effect to  promote or prevent the ripple-out of logic removal. There may also be tool-specific  directives and attributes within the design or project files or the tool itself which  control logic pruning. Readers are encouraged to explore their own FPGA synthesis  tools in order to understand their behavior in these circumstances. For the  Synopsys® example, Synplify Pro® synthesis tools have a directive called  syn_noprune which, as the name suggests, prevents pruning of non-terminated or  non-driven signals.  

However, even if such a directive is used in synthesis, it may be that the place &  route tools will have their own default operation which overrides the setting when  dangling signals are found in the input netlist. It is good practice to ensure that  every system or toolset used for the project is explicitly given a predictable setup  rather than rely on defaults. If the members of our SoC and/or prototyping project  teams are running different tools installations and seeing different results in their  respective labs, then tool defaults and settings are a good place to start looking for  the reasons.  

So, block removal is a quick and powerful way to remove unwanted logic but may  have unforeseen results. A better approach may be to replace the block with a  simple set of constant values called stubs, which leave no room for ambiguity of  tool dependence. There is more detail on the use of stubs in the next section.

SoC element tie-off with stubs 

To remove possible ambiguity between tool-flows as a result of element removal, as  discussed above, a simple step is to add a dummy design file which explicitly ties off unused ports to desired values. Amending the example in section 7.5.1  aboveabove, we arrive at the following code:  

We see that the code is altered to call a different version of the SoC block that included the stubs which tie off outputs to specific values, controlling downstream  pruning. Inputs to the stub block can be ignored with the upstream pruning taking  place as normal, alternatively, dummy registers or other logic might be used to sink  the input signals or bring to an external test point using global signal (see next  section). Another advantage of using stubs is that it more fully defines the design  for simulation purposes. Simulators have a much more particular requirement for  complete RTL code and will often error-out on signals etc. by default.

Figure 79: Substituting stub block using `ifdef

/* defining the compiler macro */

`define FPGA; 

/ define stub block (preferably in separate file used only for 

prototype) 

module SoC_block1_stub (signals… )

input …;

output …;

/ elsewhere in the SoC design

<other rtl code> 

/* replacing the SoC_block instance with stub equivalent */ 

`ifdef FPGA

SoC_block SoC_block1_stub (signals.);

/* instantiating SoC module SoC_block when FPGA macro is not 

defined*/ 

`else

SoC_block SoC_block1 (signals.);

`endif

<other rtl code>


Therefore, stubs are a useful way to ensure repeatable pruning results, regardless of  which tool we use or its setup.

Minimizing and localizing RTL changes

In previous examples,`define and `ifdef are used to control the synthesis branching  between the FPGA and SoC code at compile time. In some cases, original RTL  designers prefer to keep their code free of implementation-specific alterations. This  fits within their team’s style guidance of separation and modularity. It is seen to be  “cleaner” to keep as much target-specific code out of as much of the RTL as  possible. In general, this also leads to a more adaptable design. There are a couple  additional options that avoid unwanted ifdef’s but still improve the design’s  adaptability.  

As suggested in a few of the examples, one option is to create “libraries” for each  target, for example, by isolating a sub-list of the source files that is target-specific  and only including the relevant sub-list for a given target. The good points of this approach are that it allows us to quickly compare the two lists and discern where  there are differences between the two databases. The strong disadvantage is that  there are still two databases, and notwithstanding the naturally higher level of  separation as compared to some of the other common approaches, maintaining  multiple databases means more work and frequently leads to negligence of the  secondary database.  

This disadvantage is minimized if the target-specific code is kept as isolated as  possible from the remaining code. For example, if several SoC library primitives are  instantiated directly in a large module, two copies of the large module would have  to be maintained. On the other hand, if the instantiation is of the library component  (containing in one case the SoC primitive and in another case the synthesizable,  behavioral equivalent), there is more chance that the code can change locally,  without having to implement the change in multiple files.

Figure 80: Use of VHDL Global Signal to extract signal to a test point

# Globals Package

package globals_pkg is

signal observe_1 : std_logic;

end globals_pkg;

# Low Level Arch

use WORK.globals_pkg.all;

architecture bhv of deep_down is

signal what_to_watch : std_logic;

. . .

Begin

observe_1 <= what_to_watch;

End Bhv;

# Top Level Arch

use WORK.globals_pkg.all;

architecture Bhv of top_design is

. . .

Begin

trace_pin <= observe_1; 

End;


Some users find that the use of XMRs (cross-module references) in Verilog or  Global signals, the VHDL equivalent, helps to decrease the scope of RTL changes. In Figure 80 we see an example of bringing an internal node out to a test pin using a  VHDL Global signal. In this way we need change only three files and the only  boundary change is at the top-level block in order to add the test pin itself.  Another good use of XMRs is to inject signals into a lower level. For example, one  of the common needs in making a design FPGA-ready is to simplify clocking. To make this easier, SoC RTL writers are asked to keep clock generators, gates etc. in a  common block at the top level. Their reason for not doing so is often that it would  complicate the hierarchy boundaries to push the clocks down to the low-level  modules where the clocks are used. XMRs can overcome that objection. XMRs may  also be used retrospectively by the prototyping team to achieve much the same goal.

Note: netlist editing instead of RTL changes

Another approach is to use a netlist editing utility which may accompany some  synthesis or partitioning tools. We explicitly specify the differences between the  original database and any modifications required for the prototype directly in the  synthesis netlist. The netlist editor would be run after each synthesis run, usually  from a common script. This approach can be thought of as a series of overlays on  the original RTL with the target-specific library compiled in parallel with the design and then stitched into the design using the netlist editor. This has all the advantages  of the multiple filelist approach, maintains and utilizes the original golden SoC RTL  without changes, and eliminates most issues associated with keeping RTL databases  in sync.  

Other approaches include using code generators and project generators. These are  frequently written in Perl, C, etc., or using makefiles, or combinations thereof. In  practice, most projects use combinations of approaches. For example, a project  could use ifdef’s for the library selection, or include them in the library itself.  

However it is done, the target-specific code should be architected so that it is tightly  bound to local sections of the design. Keeping the effect close to the cause avoids  confusion. The best approach is the one that minimizes the impact on the design and  maximizes the ease and simplicity of switching between targets.

SoC element replacement with equivalent RTL

In the cases where a non-synthesizable SoC design element is needed in the FPGAbased prototyping effort, it may be replaced with synthesizable RTL code. In Figure  81 we see an example of an SoC primitive SoC_mux being replaced with RTL code: 

It is obviously important to verify that the RTL is functionally equivalent to the SoC module it’s replacing. Therefore some simulation of the replacement alongside the  original, perhaps with assertions checking for differences, would be very useful. We  discuss such an approach with respect to memories in section 7.7.3 below.

Figure 81: Replacing instantiation with behavioral code

/* defining the compiler macro */

`define FPGA true; 

module SoC_top (…inputs, outputs…); 

input ……; 

output ……;

/some internal signals definitions

wire sel;

wire in1;

wire in2;

wire mux_out;

/* replacing the SoC_mux instance with RTL */ 

`ifdef FPGA

assign mux_out = sel ? in1 : in2;


/* instantiating SoC module SoC_mux when FPGA macro is not 

defined*/ 

`else

SoC_mux SoC_mux1 (

.input1(in1),

.input1(in1),

.select(sel),

.output(mux_out)

);

‘endif

endmodule

Recommendation: It’s important to note that if the remaining design is not  properly terminated after removal of some blocks then the synthesis tool may  optimize out (i.e., remove) any logic that is not driven by, or is not driving, other  logic as a result. Therefore additional design modifications or synthesis directives  may be necessary, such as creating stub designs.

In many cases the SoC element which requires replacement is an instantiated leaf  cell from the technology library. A good source of equivalent functionality for such  an instantiated SoC element can be found in the actual technology library used for  the SoC.

The liberty (.lib) format for technology libraries includes an equation for the  functionality for each leaf cell. We can see such a function for a basic cell in the  small excerpt from a .lib file shown in  Figure 82 and we can see the function of the output pin Y in logical terms of the  inputs. It is a simple matter to convert this “function” equation into equivalent RTL,  although there are EDA utilities which can perform the same task quickly and  without error.

As an example, FPGA synthesis tools from Synopsys have the ability to read the .libfile directly and refer to the cell description in order to resolve instantiations of leaf  cells in the RTL.

Figure 82: Excerpt from an AND-OR cell description in .lib file

cell (AOI22XL) {

cell_footprint : aoi22;

area : 10.1844;

pin(A0) {

 direction : input;

 } 

pin(A1) { 

 direction : input;

 } 

pin(B0) {

 direction : input;

 } 

pin(B1) {

 direction : input;

 } 

pin(Y) {

 direction : output;

 function : "(!((A0 A1) | (B0 B1)))";

Figure 83 shows part of an RTL view of a gate-level netlist after being compiled  into FPGA synthesis. Note that the blocks are leaf-cell elements from the  technology library used for the SoC synthesis.  

As noted previously, each of these cells would normally be interpreted by FPGA  synthesis as a black box. Luckily, the source .lib file for the technology is available  to the prototyping team and we can add this to our synthesis project as any other  design file. The tools then automatically extract the functionality as mentioned,  mapping it to FPGA resources during synthesis as normal.

Figure 83.png

If the .lib file is not available, or we are not using a synthesis tool that supports this  flow, then a colleague supporting the SoC tool flow might be able to create a  Verilog file from the .lib to add into the FPGA project. That Verilog file would only  be a set of module definitions, which could be created using a utility such as  Synopsys lib2syn, or even by a script which extracts the function from the .lib file  and transcribes it into a Verilog module declaration.

SoC element replacement by inference

In some cases SoC elements can be substituted by equivalent FPGA design  elements or “cores.” These FPGA cores are special-purpose FPGA entities used to  optimize FPGA implementation for area and or performance. Common examples of  FPGA primitives are memory blocks or shift register functions.  

Usually, we do not need to simply replace an SoC element with an FPGA  equivalent but instead we replace it with an RTL description and allow the synthesis  tools to map it into FPGA elements by inference. The example in  

Figure 84 shows an 8x4 synchronous RAM module soc_ram being replaced by RTL code. In this case, the FPGA memory block will be inferred by the synthesis tool  during synthesis.

The RTL enabled by the FPGA macro will be interpreted by the FPGA synthesis as  RAM and mapped into the relevant resource in the FPGA(s).

Figure 84: Instantiated RAM replaced by inferred equivalent

/* defining the compiler macro */

`define FPGA true; 

module soc_top (…inputs, outputs…); 

input ……; 

output ……;

/some internal signals definitions

wire [3:0] mem_out;

wire [3:0] mem_in;

wire [2:0] addr;

wire we;

wire clk;

/* replace soc_ram instance with RTL when compiling for FPGA */ 

`ifdef FPGA

reg [3:0] mem [7:0];

assign mem_out = mem[addr];

always @(posedge clk) 

if(we) mem[addr]= mem_in;

/* instantiating SoC module soc_ram when compiling for SoC */ 

`else

soc_ram soc_ram1 (

.mem_do(mem_out),

.mem_di(mem_in),

.mem_addr(addr),

.mem_clk(clk),

.mem_we(we)

);

`endif

endmodule

SoC element replacement by instantiation

In addition to memory blocks, FPGAs have some special-purpose blocks that may  be needed for the prototyping effort. Examples of such blocks are high-speed serial interface blocks (also known as SERDES), DDR memory interfaces and FIFOs.  Since these special-purpose blocks are highly programmable, they are not always  inferred by the synthesis tools and instead they must be instantiated directly into the  design.

The process of including such elements is as follows:  

• Create an FPGA element using the FPGA vendor’s supplied tools (such as  the Xilinx® CORE Generator™ tool, Memory Interface Generator etc.)  Typically the user selects the core type, the target technology and defines  the various parameters’ initial state values etc.  

• The FPGA tool generates the desired core’s FPGA netlist and initialization  file –where applicable – that are used in the place & route stage, and a  template file used to instantiate the generated core into the main design.  

• In addition, the tool generates a wrapper file containing functional  simulation customization data that, combined with the primitive model  used in the core, can be used for functional simulation. 

• We then instantiate the template file in the design and connects the module  to the design.

Figure 85: Instantiation template created by Xilinx® CORE Generator tool

/----------- Begin Cut here for INSTANTIATION Template ---/ 

/ INST_TAG

fifo_generator_v5_1 YourInstanceName (

.clk(clk),

.din(din), / Bus [17 : 0] 

.rd_en(rd_en),

.rst(rst),

.wr_en(wr_en),

.dout(dout), / Bus [17 : 0] 

.empty(empty),

.full(full));

/ INST_TAG_END ------ End INSTANTIATION Template ---------

Copyright © 2011 Xilinx, Inc.

Figure 85 shows an instantiation of a FIFO template generated by the Xilinx® CORE Generator tool: 

Figure 86: use of FIFO module in defined using the template in Figure 85

/* instantiating the above FIFO module in the design “top”;

module top (input… outputs…); 

/* defining the compiler macro */

`define FPGA true; 

module top (input… outputs…); 

<other RTL code>

`ifdef FPGA

/* instantiation of FPGA FIFO */

fifo_generator_v5_1 MyFIFO(

.clk(Myclk),

.din(Mydin), 

.rd_en(Myrd_en),

.rst(Myrst),

.wr_en(Mywr_en),

.dout(Mydout), 

.empty(Myempty),

.full(Myfull));

`else

/original SoC primitive instance

soc_FIFO MyFIFO (

.clk(Myclk),

.soc_din(Mydin),

. soc_rd_en(Myrd_en),

. soc_rst(Myrst),

. soc_wr_en(Mywr_en),

. soc_dout(Mydout), 

. soc_empty(Myempty),

. soc_full(Myfull));

‘endif

endmodule

The FIFO template would be instantiated in place of SoC FIFO module as shown in  Figure 86, once again using the FPGA macro to branch between implementations. 

In the example, the synthesis tool will generate a netlist with an FPGA equivalent  black box in place of the SoC black box. The contents are added in when the design reaches the back-end and the association is made by the model name in the  template. 

When instantiating a core for which an FPGA netlist exists, the synthesis tool  usually applies timing constraints to the core. Furthermore, depending on the  synthesis tool, it may also be possible to include the FPGA netlist during synthesis  so that further optimization may occur. In this case, we refer to the module as a gray  box.

Controlling inference using directives

There may be situations where within the same design the use of special-purpose  FPGA resources is desired for some instances, but not desired for other instances.  Such situations can happen due to the finite number of available resources or the  locations of these resources and the way they are connected into the design. For  example, in some Xilinx® FPGA families, dedicated 48-bit multiplier blocks are  available in fixed columns on the die. By default, the FPGA synthesis should map to  dedicated resources but we also need to be able to override the default decisions in  some situations. For example, when routing delays to a multiplier from the rest of  the design placement would outweigh the performance gain in using it.  In that case it would be better instead to implement the multiply function in  general-purpose distributed logic. So there is a need to selectively direct the  synthesis tool to infer the dedicated multipliers for some multiply functions and to  

Figure 87: RTL excerpt showing control of DSP48 mapping using synthesis  directive

<other RTL statements>

. . .

Reg [7:0] x1_in1, x1_in2; /inputs to multiplier 1

Reg [7:0] x2_in1, x2_in2; /inputs to multiplier 2

wire [15:0] mult_out1 /* synthesis syn_dspstyle = “dsp48” */;

wire [15:0] mult_out2 /* synthesis syn_dspstyle = “logic” */;

/* a DSP48 will be inferred for the multiplier driving mult_out1 

*/

/* a DSP48 will not be inferred for the multiplier driving 

mult_out2 */

Assign mult_out1 <=x1_in1 * x1_in2;

Assign mult_out2 <=x2_in1 * x2_in2;

In that case it would be better instead to implement the multiply function in  general-purpose distributed logic. So there is a need to selectively direct the  synthesis tool to infer the dedicated multipliers for some multiply functions and to  map to logic in other cases. A synthesis attribute should be available to control these  kinds of decisions and override the default.  

In the RTL in Figure 87 we see the use in Synopsys FPGA synthesis of an attribute  called syn_dspstyle. This attribute can take one of two values: “logic” or “dsp48”  and it is used to direct the synthesis to infer or not to infer the 48-bit fixed  multiplier. 

Note that this attribute also applies to other entities that can be mapped into the  DSP48 block such as adders and registers.  

In some cases, this process can be done automatically when synthesis infers the use  of DSP and RAM blocks. The inference is timing-driven and often paths are retimed  to get better DSP and RAM packing, but also a running count of DSP and RAM  usage is maintained so that if the resource limit for the target FPGA is overflowed.  Then some of the design that might otherwise infer DSP and RAM blocks will be  automatically mapped into other logic resources instead.




  • XC2C384-10PQG208C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 9K Gates 384 Macro Cells 125MHz 0.18um Technology 1.8V 208-Pin PQFP
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS:

  • XC2C384-10TQG144I

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 9K Gates 384 Macro Cells 125MHz 0.18um Technology 1.8V 144-Pin TQFP
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS:

  • XC2C384-7PQ208C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 9K Gates 384 Macro Cells 217MHz 0.18um Technology 1.8V 208-Pin PQFP
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS: No RoHS

  • XC2C512-10FG324C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 12K Gates 512 Macro Cells 128MHz 0.18um Technology 1.8V 324-Pin FBGA
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS:

  • XC2C512-10FT256C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 12K Gates 512 Macro Cells 128MHz 0.18um Technology 1.8V 256-Pin FTBGA
  • Product Categories: Embedded - CPLDs (Complex Programmable Logic Devices)

    Lifecycle:Active Active

    RoHS: No RoHS

Need Help?

Support

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