![]() |
|
|
(interface (port (array (rename a "a[3:0]") 4) (direction INPUT)) (port (array (rename b "b[3:0]") 4) (direction INPUT)) (port (array (rename q "q[3:0]") 4) (direction OUTPUT)) )
That is, it contains a 4-bit input named "a", a 4-bit input named "b", and a 4-bit output named "q". Further, assume that the EDIF is for a Xilinx Virtex design.
Here is a JHDL design which will read in the EDIF and treat it like
any other JHDL module:
import byucc.jhdl.base.*; import byucc.jhdl.Logic.*; import byucc.jhdl.Xilinx.*; import byucc.jhdl.Xilinx.Virtex.*; import byucc.jhdl.parsers.edif.sablecc.*; public class add_wrapper extends Logic { public static CellInterface[] cell_interface = { in( "a", 4), in( "b", 4), out( "q", 4), }; Wire a; Wire b; Wire q; public add_wrapper(Node parent, Wire a, Wire b, Wire q ) { super(parent); this.a = connect( "a", a); this.b = connect( "b", b); this.q = connect( "q", q); EdifPortInterface[] portWires = { EdifPortInterface.addPort("a", a), EdifPortInterface.addPort("b", b), EdifPortInterface.addPort("q", q), }; Cell cel = EdifParser.parse(this, "add.edn", portWires, "Virtex"); } // end constructor } // end class
Things of interest include the following:
javac add_wrapper.java java jab add_wrapper
put a 3 put b 4
Then click the cycle button and the window looks like this:
OK, so maybe there is more...
java byucc.jhdl.parsers.EDIF.sablecc.BuildWrapper -t Virtex add.edn
and it will parse "add.edn" and create the file "add_wrapper.java" shown
below which you can use instead of writing your own wrapper by hand:
// Automatically generated EDIF wrapper... import byucc.jhdl.base.*; import byucc.jhdl.Logic.*; import byucc.jhdl.Xilinx.*; import byucc.jhdl.Xilinx.Virtex.*; import byucc.jhdl.parsers.edif.sablecc.*; public class add_wrapper extends Logic { public static CellInterface[] cell_interface = { in( "a", 4), in( "b", 4), out( "q", 4), }; Wire a; Wire b; Wire q; public add_wrapper(Node parent, Wire a, Wire b, Wire q ) { super(parent); this.a = connect( "a", a); this.b = connect( "b", b); this.q = connect( "q", q); // Changes to make below if there is a clock port called "clk" on the imported EDIF and you want // to wire it to the default global clock: // EdifPortInterface.addPort("clk", getDefaultClock()); // Alternatively, if your wrapper has a port called "clk" and you want // to hook it to a clock driver of your own making: // Put these two lines in: // Wire myclk = wire(1, "myclk"); // clockDriver("clk", "myclk", "01", "clockDriver"); // Now, change the EdifPortInterface.addPort() below to be: // EdifPortInterface.addPort("clk", myclk); EdifPortInterface[] portWires = { EdifPortInterface.addPort("a", a), EdifPortInterface.addPort("b", b), EdifPortInterface.addPort("q", q), }; Cell cel = EdifParser.parse(this, "add.edn", portWires, "Virtex"); } // end constructor } // end class
Notice also that when you executed the command
java byucc.jhdl.parsers.edif.sablecc.BuildWrapper -t Virtex add.edn
you got something like this:
(status (written (timeStamp 2000 6 29 15 2 7) (program "BYU-CC's JHDL-EDIF netlister by Peter Bellows and Eric Blake" (version "JHDL.RELEASE.BRENT.6.28"))))
When you parse this EDIF file, the parser gives you a WARNING saying that the element (status) of the EDIF file has been ignored by the parser. It also tells you that if you want to see the full description of this element as it appears in the EDIF file you only need to add the following line to your add_wrapper.java file:
byucc.jhdl.JHDLOutput.getJHDLOutput("EDIF_ignore_loud");
Try adding this line of code to your add_wrapper.java file right before
the call to the EDIF parser:
...... byucc.jhdl.JHDLOutput.getJHDLOutput("edif_ignore_loud"); Cell cel = EdifParser.parse(this, "add.edn", portWires, "Virtex"); ......
Now compile and execute the file:
javac add_wrapper.java java jab add_wrapper
By having added that line of code now you have enabled the JHDLOutput and the warning given by the parser will now look something like this:
In the following automatically generated wrapper, you will see that the tool saw that the EDIF had a clock port and so created a clock port on the wrapper's interface as well as created a PortInterface entry for it:
... public class ramtest_wrapper extends Logic { public static CellInterface[] cell_interface = { in( "a", 4), in( "clk", 1), in( "d", 1), out( "q", 1), in( "we", 1), }; ... // Changes to make below if there is a clock port called "clk" on the imported EDIF and you want // to wire it to the default global clock: // EdifPortInterface.addPort("clk", getDefaultClock()); // Alternatively, if your wrapper has a port called "clk" and you want // to hook it to a clock driver of your own making: // Put these two lines in: // Wire myclk = wire(1, "myclk"); // clockDriver("clk", "myclk", "01", "clockDriver"); // Now, change the EdifPortInterface.addPort() below to be: // EdifPortInterface.addPort("clk", myclk); EdifPortInterface[] portWires = { EdifPortInterface.addPort("a", a), EdifPortInterface.addPort("clk", clk), EdifPortInterface.addPort("d", d), EdifPortInterface.addPort("q", q), EdifPortInterface.addPort("we", we), }; Cell cel = EdifParser.parse(this, "ramtest.edn", portWires, "Virtex"); } // end constructor } // end class
However, you will see that it also suggested how you might hook a clock to that port, depending on what you wanted to do. The first suggestion simply hooks the clock up to the global default clock. The second lets you insert a ClockDriver and specify the clock's waveform.
As an alternative to doing this in the wrapper, you could write a testbench
to directly import the EDIF. Below is a complete testbench to load the
EDIF for a CLB RAM test circuit and read all 16 locations. When executed
in JAB, one can see the successive values of the memory coming out on the
"q" port.
import byucc.jhdl.Logic.*; import byucc.jhdl.Xilinx.*; import byucc.jhdl.base.*; import byucc.jhdl.Xilinx.Virtex.*; import byucc.jhdl.parsers.edif.sablecc.*; public class tbe_ramtest extends Logic implements TestBench { public static void main(String argv[]) { HWSystem hw = new HWSystem(); tbe_ramtest tb = new tbe_ramtest(hw); hw.cycle(iterations); } // Here are the addresses static final int[] a_data = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, }; Wire d; Wire we; Wire a; Wire q; public void reset() { count = 0; d.put(this, 0); we.put(this, 0); a.put(this, 0); } static final int iterations = 20; int count = 0; public void clock() { d.put(this, 0); we.put(this, 0); a.put(this, a_data[count%iterations]); count++; } public tbe_ramtest(Node parent) { super(parent); VirtexTechMapper tm = new VirtexTechMapper( true ); setDefaultTechMapper( tm ); d = wire(1, "d"); we = wire(1, "we"); a = wire(4, "a"); q = wire(1, "q"); EdifPortInterface[] ports = { EdifPortInterface.addPort("d", d), EdifPortInterface.addPort("we", we), EdifPortInterface.addPort("a", a), EdifPortInterface.addPort("q", q), EdifPortInterface.addPort("clk", getDefaultClock()), }; Cell my_ramtest = EdifParser.parse(this, "ramtest.edn", ports, "Virtex"); } }
Try the following
javac tbe_ramtest.java java jab tbe_ramtest
cycle 20
java byucc.jhdl.parsers.edif.sablecc.BuildWrapper ramtest_pads.edn
The file "ramtest_pads_wrapper.java" will be created. This design has a clock port on it. There will be a comment in "ramtest_pads_wrapper.java" showing how you might want to modify the design to add a clock driver to the circuit in case it was going to be your top-level design. You should read the comment to understand how to do that.
javac ramtest_pads_wrapper.java java jab ramtest_pads_wrapper
This will:
... modify the wrapper ... javac ramtest_pads_wrapper.java java jab ramtest_pads_wrapper
NOTE: if you used an automatically-generated wrapper you will see that it has many 1-bit ports as in: "a_0_", "a_1_", etc. (this is what happens when pads are thrown away). However, the EDIF parser on import will always merge these into a wide port by looking at the indices. Thus, when you modify the wrapper you will want to replace all these by a single port and wire named "a". Otherwise, you will get an error.
(interface (port in0 (direction INPUT)) (port in1 (direction INPUT)) (port in2 (direction INPUT)) (port in3 (direction INPUT)) (port out0 (direction OUTPUT)) (port out3 (direction OUTPUT)) )
the ports in0 - in3 will be reconstructed into a 4 bit port
called in. The other 2 ports will attempt to reconstruct a 2 bit
port out. However, since the number of ports is less than the greatest
port index, the ports will remain single bit ports with their given names.
The final reconstructed port interface for this EDIF section is shown in
the following JHDL code.
public static CellInterface[] cell_interface{ in( "in", 4 ); out( "out0", 1); out( "out3", 1); }
If the desired cell to be parsed is not actually the top-level cell of
the EDIF file, you may specify that particular cell. To specify a
subcell of the EDIF file, use the overloaded parse
method
of the EdifParser for that purpose. This method is just like the other
parse
method mentioned at the top of this page, except
that the name of the subcell comes after the name of the EDIF file.
For example:
Cell cel = EdifParser.parse(this, "add.edn", "subcellname", portWires, "Virtex");
This will parse the file add.edn and generate a JHDL cell representation of the file. Then it will search through the children of the top-level cell until it finds one with the name "subcellname"; the EdifParser will then return that subcell. If the EdifParser cannot find a cell by that name, a NullPointerException is thrown.
This feature can be used with the BuildWrapper class as well. Simply
use the -sub
switch followd by the name of the subcell to be targetted.
The JHDL Netlister is a tool that enables a user to netlist the components of a design into machine-generated JHDL code. The cell hierarchy is read, starting with the top-level cell, and the top cell and each child cell are written out into a separate .java file. The entire hierarchy is netlisted in this fashion, with one cell per .java file. The cell's name is used as the filename for each .java file by default. Any wires needed to connect the cells together are also netlisted in their respective parent cells.
For example, a common scenario is to use a schematic capture tool to design a cell. The CAD tool usually has an option to netlist the design to an EDIF file, targeted to a certain library such as Xilinx XC4000 or Virtex. The user may then use the JHDL Netlister to translate the EDIF file to JHDL files, compile the JHDL, and then use the cells by instantiating the cells in JHDL source code that the user has written. In this manner, the JHDL Netlister can be used to import designs from other CAD tools to JHDL.
A java wrapper program enables the user to netlist into JHDL from an EDIF file at the command line. To run the JHDL netlister, type
java byucc.jhdl.netlisters.jhdl.BuildJHDL < -t target > my_EDIF_file.edf
where 'target' is the architecture that the EDIF file was synthesized against. Current valid options for 'target' are:
XC4000 Virtex Virtex2
For example, to netlist an EDIF file called div3by3_100.edf, which was targeted to Virtex, the user should type:
java byucc.jhdl.netlisters.jhdl.BuildJHDL -t Virtex div3by3_100.edf
Note: if a target architecture is not specified, the current default is Virtex.
Note about large EDIF files: It is likely that for large EDIF files, java will run out of heap memory. To avoid this error, the user should specify on the command line for java that increases java's memory limit. For example:
For Java 1.1.x:
java -mx128M byucc.jhdl.netlisters.jhdl.BuildJHDL -t Virtex div3by3_100.edf
For Java 1.2.x or 1.3.x:
java -Xmx128M byucc.jhdl.netlisters.jhdl.BuildJHDL -t Virtex div3by3_100.edf
These examples show running the JHDL Netlister with a maximum heap memory size of 128 megabytes.
It is possible to use the JHDL netlister in the same way that other netlisters are used from a JHDL testbench. The syntax is very similar to other netlisting functions. Please read the documentation on Test Benches for more information on this topic. The syntax for netlisting to JHDL from a testbench looks like this:
------- tb_MyCell.java -------- Cell my_cell; // Cell to be netlisted ... public tb_MyCell( ... ){ // testbench constructor JHDLNetlistWriter my_writer = new JHDLNetlistWriter( my_cell, "my_cell.java" ); //Instantiate the netlister my_writer.writeTree(); // actually output JHDL ... ------- tb_MyCell.java -------
The JHDL netlister is still under development. It has been tested with small and medium-sized designs and has netlisted accurately. However, on large designs with many wires, a naming conflict sometimes appears that creates multiple instances of a wire, or references a wire in a JHDL cell constructor call that has not been instantiated. In this case, the user must fix the naming discrepancy by hand in the generated source code.
The JHDL code that is generated is decidedly ugly. Eventually, the code will hopefully be more human-readable.
| JHDL Home Page | Configurable Computing Lab | Prev (FSM Generators) | Next (Logic Revisited) | |
JHDL 0.3.45
Copyright (c) 1998-2003 Brigham Young University. All rights reserved.
Last updated on 11 May 2006