|   JHDL Home Page   |   Configurable Computing Lab   |   User's Manual (TOC)   | Search

Level 1 - Instantiating Primitive Library Elements in JHDL

If you will be using an FPGA from a particular manufacturer and model, you can use objects that describe primitives specific to that hardware. Xilinx Virtex for example, has a mult_add primitive used exclusively for building fast and small multipliers.

Pros: faster
Cons: not portable, APIs change from technology to technology

Disclaimer

Although this section is termed Level 1 design, don't let that term mislead you. It is called Level 1 because it is the lowest-level way to design circuits in JHDL. That is, it gives you direct access to the vendors' primitive libraries of components. It is recommended that you use this level of design for performance- and area-sensitive parts of your circuit only. It is much more verbose and cumbersome than using the Logic package as described in Level 2 - The Logic Package. However, a knowledge of this level of design will be important to anyone wanting to create optimized designs.

Details

A previous section of this manual outlined the declaration of circuit modules as Java classes as well as the declaration, creation, and accessing of wires. In this section, the creation of logic in a circuit constructor by instancing primitive library elements is described. An example of a 2:1 mux built from logic gates will be used for the example. It consists of an inverter, 2 AND gates, and an OR gate and is shown here in its entirety:
     import byucc.jhdl.base.*;
     import byucc.jhdl.Logic.*;
     import byucc.jhdl.Xilinx.Virtex.*;
  
     public class mux extends Logic {
       public static CellInterface[] cell_interface = {
         in("a", 1),
         in("b", 1),
         in("sel", 1),
         out("q", 1),
       };
      
       public mux(Node parent, Wire a, Wire b, Wire sel, Wire q) {
         super(parent);
         connect("a", a);
         connect("b", b);
         connect("sel", sel);
         connect("q", q);
  
         // Declare and construct local wires
         Wire a1 = new Xwire(this, 1, "a1");
         Wire a2 = new Xwire(this, 1, "a2");
         Wire selbar = new Xwire(this, 1, "selbar");
  
         // Invert signal "sel"
         new inv(this, sel, selbar);
  
         // Form AND gates
         new and2(this, a, selbar, a1);
         new and2(this, b, sel, a2);
  
         // Form OR gate
         new or2(this, a1, a2, q);
       }
     }

Importing The Proper Library

     import byucc.jhdl.base.*;
     import byucc.jhdl.Logic.*;
     import byucc.jhdl.Xilinx.Virtex.*;

To access a technology library you must first import it. The above lines import the Virtex-specific library of primitives in addition to the regular libraries which are always imported.

To find what libraries are available for importing, go to the JHDL API page, and search through the Packages section of the API documentation. For example, in there you will find a package called byucc.jhdl.Xilinx.Virtex. That contains the Virtex primitives. Clicking on that package reveals a collection of classes in that package. Each such class represents a primitive. The class clkdll is an example. Clicking on it gives a description of the primitive and shows how to call its constructor(s). Note that Xwire, the wire object used in the previous sections is also a class in this library.

To be technical about it, if you are going to do design using only library primitives there is no need to import the Logic package (the 2nd line in the code above). However, if you don't do that, your class will then need to extend something other than Logic (like Structural). However, there is really no advantage to doing this. Thus, in our example above, we import the Logic package and have our class extend the Logic class.

Building The Circuit

To use a primitive (including a wire) you simply call its constructor. Thus, the first thing done in the example is to construct the local wires:

     Wire a1 = new Xwire(this, 1, "a1");
     Wire a2 = new Xwire(this, 1, "a2");
     Wire selbar = new Xwire(this, 1, "selbar");

Every object in JHDL needs to be linked into the JHDL internal circuit data structure through its parent. Thus, the first parameter in the above calls is this. What this means is that the parent cell for the wires constructed is this, or the cell currently being constructed.

The next step is to instance each gate in the circuit, passing in as parameters the wires to connect to it.:

     new inv(this, sel, selbar);
     new and2(this, a, selbar, a1);
     new and2(this, b, sel, a2);
     new or2(this, a1, a2, q);

As before, this is the parent cell for these gates. That is, hierarchically, they are children of the cell currently being constructed.

Hierarchical JHDL Design

As was shown in the JHDL Getting Started guide, once a cell has been created, it can be saved away and then used in the creation of higher-level cells. In the JHDL Getting Started guide we first built a 1-bit adder and then used that in the construction of the NBitAdder. Thus, the mux created here could be used in a likewise manner.

There are a number of ramifications of JHDL circuits just being Java classes. First, as seen above, instancing a JHDL circuit is just creating an instance of a Java object. Thus, as long as the file mux.java is on your Java CLASSPATH, when you instance it with the new keyword Java will find it. Usually "." is in your CLASSPATH and so if the file is in the current directory Java will find it. More expert users often create other locations to hold their building blocks and place that directory on their CLASSPATH. See standard Java documentation for more information on the CLASSPATH, JAR files, packages, and the like.

Summary

That's it. There is not much more to know about directly instancing library primitives. Since library primitives are just regular JHDL Java classes (like the ones you create for your own designs), once you know how to instance library primitives you know how to do hierarchical JHDL design as well. The steps to using library primitives are:
  1. Import the Java package associated with the technology of interest.
  2. Go into the API documentation and find the primitive you want.
  3. Read up there to understand the format of the constructor call required for that primitive.
  4. Create an instance of the primitive with a new call.
By the way, steps 2 and 3 are usually the hardest part - the libraries are very large and it may take some time to find what you want.

Where To Go Next?

As mentioned at the top of this document in the disclaimer, the Logic package makes doing design for general logic much easier than what was shown here! It is highly recommended that you use the Logic package for most of your design and descend into the realm of library primitives only when you must do so to get circuits with better area or performance than those that the Logic package produces.

Read up on this next in Level 2 - The Logic Package.

|   JHDL Home Page   |   Configurable Computing Lab   |   Prev (Logic Descriptions)   |   Next (Logic Package)   |


JHDL 0.3.45