Synthesizing a black-box binary IP core with XST
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;
That is brilliant. Thank you for posting this info. May I ask which version of ISE did you use?
It was ISE 9.2, as mentioned in the post.
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.
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.
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.