Synthesizing a black-box binary IP core with XST

This post was written by eli on June 16, 2011
Posted Under: FPGA

Surprisingly enough, I haven’t found a plain and simple cookbook on how to generate a presynthesized IP core for delivery. So I tried it out, and wrote my findings here. Since it’s a result of trial and error, I may have missed some crucial points. Please comment below if you know about such.

Synthesis

In GUI, uncheck “Add I/O Buffers”, set number of clock buffers to zero and set “Pack I/O Registers into IOBS” to No (see below what happens if we don’t). Using these settings, synthesize a very simple module such as this one:

module thecore
 (
 input clk,
 output reg data
 );

 always @(posedge clk)
 data <= !data;

endmodule

and then, on command prompt do

$ ngc2edif thecore.ngc

which will generate an EDIF file as thecore.ndf. Verify by reading this file than nothing else than simple logic elements are implemented. No BUFG or OBUF, for example. These indicate that the synthesizer generated elements which are beyond a core’s scope.

The relevant command-line flags (usually set up in e.g. trycore.xst) are

-iobuf NO -bufg 0 -iob false

Delivery: making an empty HDL file

This is somewhat obvious, and still: The delivery of a binary core consists of an NGC file (or EDIF) and an empty HDL file (headers only). In our simple case this is just

module thecore
 (
 input clk,
 output reg data
 );

endmodule

and that’s it. The receiver of the core should be notified to put the NGC file in a special directory. Putting it in the synthesis directory (the one to which the bitfile and other binaries are written) will in general work, but “Cleanup Project Files” does delete it every now and then on ISE 9.2 and possibly other versions as well (not consistently, which makes it even more annoying). The core directory should then be added to “Macro search path” in Translate’s properties, or an -sd “/path/to/mycores” flag in command line use.

If ISE is used (as opposed to command-line build), the NGC file should not be added to the project (ISE will reject it anyhow). The emtpy HDL file should be included in the project, of course.

Is NGC portable?

Can an NGC file by one version of XST be used with an earlier or later design toolset? Can an NGC file targeted for a certain Xilinx device be used for another?

I haven’t found any decisive answer for these questions, which are pretty crucial for whoever wants to release a core in binary format. If anyone has a pointer to a credible statement, please comment below.

What I do know for sure, is that the target device is noted in the NGC file, since that part number appears in the EDIF file generated from it.

I’ve tried to implement very simple designs targeting different devices with the core included (core generated for Spartan 3E, used implementing for Spartan-2 and Virtex-4), and it looks like ngdbuild (which is the one cooking the NGC soup) ignores conflicts in device names. It just runs through.

My educated guess is therefore that the NGC really is only a netlist + constraints, so as long as the logic primitives mentioned there make sense on the target device, nobody’s complaining. Personally, I will push my luck only to the extent of using the NGC within the same device family.

If we do it wrong…

I wanted to see what happens if the synthesis is done without the flags I mentioned above for adjustment. The result is I/O buffers and clock buffers inserted, and ngdbuild will complain with something like

ERROR:NgdBuild:770 - IBUF 'clk_IBUF' and IBUFG 'IBUFG' on net 'clk_IBUF' are
 lined up in series. Buffers of the same direction cannot be placed in series.
WARNING:NgdBuild:463 - input pad net 'clk_IBUF' has an illegal input buffer
ERROR:NgdBuild:925 - input net 'clk_IBUF' is connected to the incorrect side of
 buffer(s):
 pin O on block clk_IBUF with type IBUF
ERROR:NgdBuild:462 - output pad net 'data_OBUF' drives multiple buffers:
 pin I on block data_OBUF with type OBUF,
 pin I on block ndata1_INV_0 with type INV
ERROR:NgdBuild:467 - output pad net 'data_OBUF' has an illegal buffer

Can I use EDIF?

… or: Can I use ngc2edif’s output as a precompiled core? The truth is that there is no apparent reason to do so, except that some of us prefer knowing what we’re submitting, and a textual file is more helpful in this respect.

The .ndf file generated by ngc2edif was completely ignored by ngdbuild. Renaming its extension to .edf yielded the following “naughty boy” error:

Reading NGO file "L:/delme/tryblackbox/use/usetop.ngc" ...
Executing edif2ngd -noa "mycores\thecore.edf" "_ngo\thecore.ngo"
Release 9.2.03i - edif2ngd J.39
Copyright (c) 1995-2007 Xilinx, Inc.  All rights reserved.
INFO:NgdBuild - Release 9.2.03i edif2ngd J.39
INFO:NgdBuild - Copyright (c) 1995-2007 Xilinx, Inc.  All rights reserved.
ERROR:NgdBuild:766 - The EDIF netlist 'mycores/thecore.edf' was created by the
 Xilinx NGC2EDIF program and is not a valid input netlist.  Note that this
 EDIF netlist is intended for communicating timing information to third-party
 synthesis tools. Specifically, no user modifications to the contents of this
 file will effect the final implementation of the design.
ERROR:NgdBuild:276 - edif2ngd exited with errors (return code 1).

Which, simply put says: That EDIF was generated for simulation and not for implementation.

And here’s the nice thing about textual files: They are easy to edit. I mean, how did edif2ngd know who generated the file? Because it starts with

(edif thecore
 (edifVersion 2 0 0)
 (edifLevel 0)
 (keywordMap (keywordLevel 0))
 (status
 (written
 (timestamp 2011 6 16 21 43 12)
 (program "Xilinx ngc2edif" (version "J.39"))
 (author "Xilinx. Inc ")
 (comment "This EDIF netlist is to be used within supported synthesis tools")
 (comment "for determining resource/timing estimates of the design component")
 (comment "represented by this netlist.")
 (comment "Command line: thecore.ngc ")))

So I deleted those two lines having the word “Xilinx”. Now who’s smart?

And indeed, after these lines were deleted, the implementation ran all the way through. Bitfile loaded, FPGA did what I expected it to do. I tested this on a serious project, not this miniature example.

I should mention that I did get some scary warnings by ngc2edit saying “Signal bus X on block Y is not reconstructed, because there are some missing bus signals”. But in the end all is well.

Let’s give Xilinx the credit that they had a good reason to put this little stick in the wheels of using ngc2edif’s output for implementation. That even though it worked for me, it may not work in other situations. Either way, this is not in their standard flow, so I would use EDIFs with caution.

Reader Comments

Hi…
currently im trying to use ngc file in project navigater, i have done removing of I/O buffer in stynthesis option, copied ngc file into project directory and add as a black_box, but still im not getting behavioral simulation output. plz can u help me…?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

—- Uncomment the following library declaration if instantiating
—- any Xilinx primitives in this code.
–library UNISIM;
–use UNISIM.VComponents.all;

entity AND_Gate_BB is
port(
T_clk : in std_logic;
T_a,T_b,T_c : in std_logic;
T_x,T_y,T_z : out std_logic
);
end AND_Gate_BB;

architecture Behavioral of AND_Gate_BB is

component AND_Gate
port(
clk : in std_logic;
a,b,c : in std_logic;
x,y,z : out std_logic
);
end component;

attribute syn_black_box : boolean;
attribute syn_black_box of AND_Gate: component is true;

begin

BB: AND_Gate
port map(
clk => T_clk,
a => T_a,
b => T_b,
c => T_c,
x => T_x,
y => T_y,
z => T_z
);
end Behavioral;

#1 
Written By Mohanavel on July 27th, 2011 @ 07:39

That is brilliant. Thank you for posting this info. May I ask which version of ISE did you use?

#2 
Written By Alex on March 22nd, 2013 @ 03:56

It was ISE 9.2, as mentioned in the post.

#3 
Written By eli on March 22nd, 2013 @ 03:59

What version of ISE did you use? I remember unchecking the “Add I/O Buffers” before for trial routes with fresh RTL but I can’t seem to find it on 13.1.

#4 
Written By tom jones on June 17th, 2013 @ 22:19

Sorry – I should RTFM.

Also, the option is still available as of 13.1 but not called out in the GUI – just add “-iobuf no” to add’l command-line options.

#5 
Written By tom jones on June 17th, 2013 @ 22:24

Again — it was ISE 9.2.

Anyhow, the option is available in ISE under the XST’s process’ properties > Xilinx Specific Options.

Don’t know exactly where it’s to be found on 13.1.

#6 
Written By eli on June 17th, 2013 @ 22:28

Add a Comment

required, use real name
required, will not be published
optional, your blog address