Schematics are not the only way to specify digital logic. In modern design tools, it is also possible to specify the logic textually and have it automatically converted into logic gates or programmable logic. The Synario tool suite supports three different hardware description languages (HDLs): ABEL, Verilog, and VHDL. We will be using ABEL which is the oldest of the three and the only one designed specifically for programmable logic devices.
Lets go back to the Synario Project Navigator and start up a new
project. Then lets add a new source file but this time we'll select
"ABEL-HDL Module" rather than "Schematic"
or "Verilog Test Fixture".
We'll be prompted for the module name, the file name, and the
title of our file. Frequently, the module and file name are the
same. However, the file name will be appended with the .abl extension.
The title should be descriptive and help us remember the function
of the module.
After we click "OK", two things happen. An ABEL file
is included as a new source to our project (notice the "A"
in the icon for the source file in the snapshot below) and a text
editor window is opened containing a template file for our module.
The Text Editor allows us to enter a textual specification of
the logic we want in our module. In this case, we'll specify the
calendar subsystem we used as an example in lecture. Recall that
the input is the month and a flag specifying whether the year
is leap or not. The output is an indication of how many days are
in the month.
First, we must enter a specification for the inputs and outputs.
MODULE a5
interface (m8, m4, m2, m1, leap -> d28, d29, d30, d31);
TITLE 'calendar subsystem';
"Inputs
m8, m4, m2, m1, leap pin;
"Outputs
d28, d29, d30, d31 pin istype 'com';
"Aliases
month = [m8, m4, m2, m1];
days = [d28, d29, d30, d31];
The portion of the file shown above specifies the interface of
the module (inputs -> outputs)
and the pins. We specify the type of the outputs (you'll see why
this matters later on) by using the istype
keyword. In this case, we have combinational logic so our outputs
are of type 'com'. Note that
in ABEL, any line that starts with a double-quote (") is
a comment line (that is, the rest of the line after the quote
is ignored - you do not need to close the quote). Therefore, the
words "Inputs" and "Outputs" are not of any
significance to ABEL. We also include some aliases that group
a collection of signals under one name so that we can refer to
the entire group as a unit.
ABEL allows us to enter a specification for the logic in many
different ways. We'll go through a few in this tutorial. First,
lets start with the truth-table method.
The truth table is specified by listing all the input combinations we care about and their corresponding inputs. Notice how the number of bits must match precisely with the specification given at the beginning of the truth table (5 inputs, month (4) and leap (1) -> 4 outputs, days (4) ) The month inputs alias allowed us to use decimal numbers for the month rather than binary values (this is why the order of the month inputs in the alias statement was important - high order bit to low order bit). Note also the use of .X. to specify a don't care input. This tells the ABEL compilers that for any value of that particular input the output values should be the same. Finally, note that we did not list all the possible input combinations. The presence of the .X.s gave ABEL a hint that it should use the input combinations not listed as don't care conditions. However, in general, ABEL does not do this. To ensure that ABEL takes advantage of this sort of don't care information you can declare an output to be istype 'dc, com'.
We are now ready to compile our specification and see what the
result is. Synario keeps track of all the steps required in compilation.
Select the ABEL source in the "Sources" sub-window and
then double-click on "Reduced Equations" in the "Process"
sub-window of the navigator.
The resulting file is a5.eq1 and it contains, among other things,
the following equations for our four outputs:
Equations:
d28 = ( !m8 & !m4 & m2 & !m1 & !leap);
d29 = ( !m8 & !m4 & m2 & !m1 & leap);
d30 = ( !m8 & m4 & !m1
# m8 & !m4 & m1);
d31 = ( m8 & !m2 & !m1
# m8 & !m4 & !m1
# !m8 & m1);
We can now use this module as we would have used any module specified
with the schematics editor. This includes simulating the circuit
and using it as a sub-circuit of a larger design. We'll see how
to turn an ABEL module into a schematic editor symbol in just
a bit. Right now, lets turn to some other ways of specifying combinational
logic in ABEL. Instead of using a truth-table we could have written
equations of each of the outputs directly. ABEL will still minimize
them for us. We could replace the truth table block with:
EQUATIONS
d28 = ( !m8 & !m4 & m2 & !m1 & !leap);
d29 = ( !m8 & !m4 & m2 & !m1 & leap);
d30 = ( !m8 & m4 & !m2 & !m1 # !m8 & m4 & m2 & !m1
# m8 & !m4 & !m2 & m1 # m8 & !m4 & m2 & m1);
d31 = ( !m8 & !m4 & !m2 & m1 # !m8 & !m4 & m2 & m1
# !m8 & m4 & !m2 & m1 # !m8 & m4 & m2 & m1
# m8 & !m4 & !m2 & !m1 # m8 & !m4 & m2 & !m1
# m8 & m4 & !m2 & !m1)
The resulting minimized equations are the same as before. ABEL
performs two-level minimization for us. Yet another way of specifying
our logic function is to use programming language constructs such
as:
EQUATIONS
WHEN (month == 2) THEN { "if its February
WHEN (leap == 1) THEN "and its a leap year
days = [0,1,0,0]; "then its 29 days
ELSE
days = [1,0,0,0]; "otherwise its 28 days
}
ELSE {
WHEN ( (month == 4) # (month == 6)
# (month == 9) # (month == 11) ) THEN
days = [0,0,1,0]; "cases where its 30 days
ELSE
days = [0,0,0,1]; "31 days for others regardless of month
}
The resulting minimized equations are not exactly the same as
before. The reason for this is that we are now asking for the
output to be [0,0,0,1] for all cases besides 2, 4, 6, 9, and 11.
This yields the following:
Equations:
d28 = ( !leap & !m1 & m2 & !m4 & !m8);
d29 = ( leap & !m1 & m2 & !m4 & !m8);
d30 = ( !m1 & m4 & !m8
# m1 & !m4 & m8);
d31 = ( !m2 & !m4 & !m8
# m4 & m8
# m1 & !m8
# !m1 & m8);
Note that although the equations for d28, d29, and d30 are the
same, the equation for d31 is quite different (in fact, it includes
0, 13, 14, and 15). In order to get the same equations as before
we need to specify that we don't care what the values are for
0, 13, 14, and 15. We can do this as follows:
EQUATIONS
WHEN (month == 2) THEN { "if its February
WHEN (leap == 1) THEN "and its a leap year
days = [0,1,0,0]; "then its 29 days
ELSE
days = [1,0,0,0]; "otherwise its 28 days
}
ELSE {
WHEN ( (month == 4) # (month == 6)
# (month == 9) # (month == 11) ) THEN
days = [0,0,1,0]; "cases where its 30 days
ELSE WHEN ( (month == 1) # (month == 3) # (month == 5)
# (month == 7) # (month == 8) # (month == 10)
# (month == 12) ) THEN
days = [0,0,0,1]; "cases where its 31 days
ELSE
days = [.X.,.X.,.X.,.X.]; "don't care about others
}
You should now verify that the equations are in fact the same
(as they should be since the same information was provided).
These are the three basic mechanisms for specifying combinational logic in ABEL: truth table, equations, when-then-else. You can see more detailed explanations of these in the ABEL-HDL on-line manual available by selecting "ABEL HDL Language" in the "Help" menu of the Synario text editor you used to enter your ABEL files. You should give this manual a quick scan.
Now, we will turn to the task of using ABEL module as sub-module
in a larger design. To do this, lets go back to our four-bit adder
from the past homework assignment. We are going to redo the assignment
using equations in ABEL rather than a schematic. Open a new project
and create a new ABEL source and enter the following:
MODULE fa
interface (a, b, cin -> sum, cout);
TITLE 'full adder';
a, b, cin pin;
sum, cout pin istype 'com';
EQUATIONS
sum = a $ b $ cin; " & is for AND
cout = a & b " # is for OR
# b & cin " $ is for XOR
# a & cin; " ! is for NOT
" see manual for others and precedence
END
The equations derived from this specification from this are:
Equations:
sum = ( a & !b & !cin
# !a & b & !cin
# !a & !b & cin
# a & b & cin);
cout = (a & b
# b & cin
# a & cin);
This exactly what we would expect. Now lets make a symbol that
includes this ABEL file for the specification of its functionality.
To do this lets begin by starting yet another new project with
a schematic source. The schematic editor will start up with an
empty sheet. We will now enter the top-level design of the four-bit
adder and then link it to the full-adder ABEL code as a sub-module.
Begin by selecting "New Block Symbol ..." from the "Add"
menu. Enter the following to specify the full-adder sub-module:
After clicking on the "Run" button, you'll be able to place the shell of the full-adder module (note that we have not yet attached any functionality to this module). If the cursor does not change to let you place the module, you can always select it again by picking it out of the symbol library when you select "Symbol..." from the "Add" menu.
Construct a schematic diagram that looks like the following:
There are two new elements in this schematic. The down pointing arrow (to signify a connection to 0 or ground) and the flat top labeled VCC (to signify a connection to 1 or a high-voltage). The way you obtain these symbols is a bit strange. You add a net name to a wire that is precisely GND (or VCC), however, for the symbol to appear rather than just the name, the wire must be vertical and unconnected at the bottom (top) for GND (VCC). GND and VCC are really "Global Nets" in the Synario vocabulary, that is, they are predefined. By adding the net name GND or VCC to one of your wires, you are connecting it (by name) to logic 0 or 1, respectively. The reason to do this is that sometimes you may want a value permanently tied to 0 or 1. In this case, because you may just want to simulate all combinations of a0, a1, a2, a3 against a fixed value of [0, 0, 0, 1] for [b3, b2, b1, b0].
After you save your schematic, you'll notice that the project
navigator window now shows that a sub-module of unknown type is
being used in this project. It is now time to attach a source
file to this sub-module definition. You can do that by selecting
the sub-module in question (indicated by a question mark) in the
"Sources" sub-window of the project navigator and then
selecting "Import..." from the "Source" menu.
You can now select the ABEL file we previously defined for the
full adder module. The question mark should disappear and the
project navigator will look like this:
The next step is to select the top-level schematic and compile
it to see what equations are derived from the fact that we've
tied the b inputs to 0 and 1. The result is as follows:
Equations:
GND = (0);
VCC = (1);
These signify that we have only defined the value of two nets
in this schematic (actually, they were defined globally, but we
are using them in the schematic), GND and VCC.
We could now create a new "Verilog Test Fixture" source and simulate this design. Recall that we only have the a inputs, the b inputs have been tied to 0 or 1 and thus should not appear in our simulation test fixture. This is the same process as in the previous tutorial and will not repeat it here.
If we ever change our ABEL file for the full adder module, we need to make sure that the change is reflected in the schematics that may use it. This is especially the case when we change the inputs or outputs of the module and may need to add/remove connections to it in the schematic.
We have one more step to complete. We need to choose a target
device with which to implement our four-bit adder. To do so, we
select the virtual device and double-click on it. This causes
the following window to pop-up:
We'll select the "Standard PLD" "E0320" whose logic diagram is attached at the end of this tutorial. The E0320 is a common PAL that allows us up to 10 inputs and 8 outputs. Each output function can have up to 8 product terms (any 8 product terms of up to 10 input variables) and there is no sharing of terms between outputs. The logic between the OR gate collecting the 8 product terms and the output will be explained later in the quarter. The project navigator window now reflects this choice and shows a whole new suite of options in the "Processes" sub-window. These include steps required to make the design fit onto the available resources (making sure each equation is no more than 8 product terms) which is called "fitting" and the process required to create the "fuse map" for the part. The "fuse map" is the set of instructions required by a PLD programmer so that it can break the connections that are not require in the part by this particular design. We won't concern ourselves with the details of the programming process but we do need to make sure our design fits into the part we selected.
If we now double-click on the pre-fit and post-fit equations we'll
see the following results (note that the post-fit and pre-fit
equations are the same because we did not have pre-fit equations
with more than 8 product terms):
Equations:
cout = ( a3 & a2 & a1 & a0
# a3 & a2 & a1 & cin);
s3 = ( a3 & !a2
# a3 & !a1
# a3 & !a0 & !cin
# !a3 & a2 & a1 & a0
# !a3 & a2 & a1 & cin);
s2 = ( a2 & !a1
# !a2 & a1 & a0
# !a2 & a1 & cin
# a2 & !a0 & !cin);
s1 = ( !a1 & a0
# !a1 & cin
# a1 & !a0 & !cin);
s0 = ( a0 & cin
# !a0 & !cin);
Note that the b inputs to not appear anywhere. The equations for
cout shows that they have been taken into account, however. The
cout output will be true when the a input is 15 or it is 14 and
there is a carry-in. This is because the b inputs were tied to
the value 1. Therefore, there is a carry out for 15+1+0, 15+1+1,
and 14+1+1 just as we would have expected.
By double-clicking on "Chip Report" in the "Processes"
sub-window, we can see how the pins of the chip will be assigned
to our inputs and outputs and compare this against the logic diagram
of the E0320. The chip report shows the following:
E0320
+---------\ /---------+
| \ / |
| ----- |
a3 | 1 20 | Vcc
| |
a2 | 2 19 |
| |
a1 | 3 18 |
| |
a0 | 4 17 |
| |
cin | 5 16 | s0
| |
| 6 15 | s1
| |
| 7 14 | s2
| |
| 8 13 | s3
| |
| 9 12 | cout
| |
GND | 10 11 |
| |
| |
'---------------------------'
E0320 Resource Allocations:
----------------------------------------------------------------------
Device | Resource | Design |
Resources | Available | Requirement | Unused
======================|===========|=============|==============
| | |
Input Pins: | | |
Input: | 10 | 5 | 5 ( 50 %)
Output Pins: | | |
In/Out: | 8 | 5 | 3 ( 37 %)
Output: | - | - | -
Buried Nodes: | | |
Input Reg: | - | - | -
Pin Reg: | 8 | 0 | 8 (100 %)
Buried Reg: | - | - | -
E0320 Product Terms Distribution:
-----------------------------------------------------------------------
Signal | Pin | Terms | Terms | Terms
Name | Assigned | Used | Max | Unused
=================================|==========|=======|=======|=======
cout | 12 | 2 | 8 | 6
s3 | 13 | 5 | 8 | 3
s2 | 14 | 4 | 8 | 4
s1 | 15 | 3 | 8 | 5
s0 | 16 | 2 | 8 | 6
==== List of Inputs/Feedbacks ====
Signal Name | Pin | Pin Type
=========================================|==========|=========
a3 | 1 | CLK/IN
a2 | 2 | INPUT
a1 | 3 | INPUT
a0 | 4 | INPUT
cin | 5 | INPUT
E0320 Unused Resources:
---------------------------------------------------------------------
Pin | Pin | Product | Flip-flop
Number | Type | Terms | Type
=======|========|=============|==========
6 | INPUT | - | -
7 | INPUT | - | -
8 | INPUT | - | -
9 | INPUT | - | -
11 | INPUT | - | -
17 | BIDIR | NORMAL 8 | D
18 | BIDIR | NORMAL 8 | D
19 | BIDIR | NORMAL 8 | D
Not all of this will make sense yet, but you should scan through
this feedback and see what does make sense to you at this point.
Had the design not fit because an equation required more than
8 product terms, we would now have to split some of our equations
so that it could be made to fit. To do this, of course, we require
more inputs and outputs and product terms. This process may also
need to be iterated as we change schematics and try new decompositions.
You have now completed the Synario/ABEL tutorial.