VHDL is:
- Strongly typed.
- Case insensitive (unlike verilog).
- Full form: VHSIC Hardware Description Language
- where VHSIC is Very High Speed Integrated Circuits
- Named after the US DoD project that created it: VHSIC program
Comments
Part of a line that comes after a --
.
Reserved words
Reference: https://www.seas.upenn.edu/~ese171/vhdl/keywordlist.html (95 words here)
abs |
access |
after |
alias |
all |
and |
architecture |
array |
assert |
attribute |
begin |
block |
body |
buffer |
bus |
case |
component |
configuration |
constant |
disconnect |
downto |
else |
elsif |
end |
entity |
exit |
file |
for |
function |
generate |
generic |
group |
guarded |
if |
impure |
in |
inertial |
inout |
is |
label |
library |
linkage |
literal |
loop |
map |
mod |
nand |
new |
next |
nor |
not |
null |
of |
on |
open |
or |
others |
out |
package |
port |
postponed |
procedure |
process |
pure |
range |
record |
register |
reject |
return |
rol |
ror |
select |
severity |
signal |
shared |
sla |
sli |
sra |
srl |
subtype |
then |
to |
transport |
type |
unaffected |
units |
until |
use |
variable |
wait |
when |
while |
with |
xnor |
xor |
Operators
Concatenation (&
)
- Both operands must be of same type.
- Like pasting together two operands.
-- If
a : std_logic_vector (2 downto 0)
b : std_logic_vector (1 downto 0)
-- then
a & b
-- is of type std_logic_vector (5 downto 0)
Ref: https://www.nandland.com/vhdl/examples/example-concatenation-operator.html
Assignment
<=
assign value to a signal
- Takes effect in the next cycle.
:=
assign value to a variable
- Takes effect immediately.
Variables
-- variable var_name : type
: std_logic_vector (7 downto 0); variable outvector
Records
- Similar to C
struct
. - Often used to define new VHDL types.
Syntax:
type <type-name> is record
<attr1> : <type>;
<attr2> : <type>;
...
<attrn> : <type>;
end record <type-name>;
Example:
type rec_typ is record: std_logic;
in_en : std_logic_vector (7 downto 0);
data : std_logic;
out_en
end record rec_typ;
-- use the record
: rec_typ := (in_en => '0',
constant inst_rec_type => '00001001',
data => '1); out_en
Another example:
<= (oldver => "00",
nstate => '0'); curst
enum type
, START, FINISH); type state_t is (IDLE
Components
Code that can be reused.
Helps to organize the code.
Reference: link (pdf)
Signals vs variables
Signal | Variable |
---|---|
Assign with <= |
Assign with := |
Usable inside/outside processes | Usable only inside processes |
Visible in many processes | Visible only in one process |
(but assigned only in one) | |
May get value only on next | Immediately gets value on |
clock on assignment (in seq circuits) | assignment |
Easier to sythesize | Can be harder to synthesize |
Process
- A VHDL construct containing a set of actions (sequential statements) to be executed sequentially.
- The process itself is a concurrent statement.
Example:
process is
begin<= sign + 1;
sign
wait for 10 ns; end process;
Sensitivity list
- List of signals for which a state change would cause the body of process to be executed.
- ie, the signals that the process is 'sensitive' to.
others
We can set/reset values of a few bits of a bit-vector and then set/reset the remaining bits to some value at once using others
.
: std_logic_vector (7 downto 0);
bv <= (2 => '1',
bv => '1',
0 => '0');
others -- bit 2 and 0 are set to 1 and all others to 0.
-- ie, bv now has 00000101 as its value.
Gaisler style
Ref: link
- Consists of 2-process entities.
- Each consists of two processes:
- Combinatory logic process (ie, asynchronous)
- Sequential logic process (deals register states)
Combinational
+-----------------+
d--→-->| q = fq(d, r) |-------> q
+-->| r_in = fr(d, r) |--→--+
| +-----------------+ |
r ↑ ↓ r_in
| +-----------------+ |
+-←-| r = r_in |--←--+
clk--->-| |
+-----------------+
Sequential
The sequential component merely copies the value of rin generated by the combinational process to the register at the start of the next clock cycle.
Consider an example of an 8 bit counter, where:
- load signal enabled to load data value to counter from where counting should start.
- count signal enabled to continue counting.
library ieee;
use ieee.std_logic_1164.all;
entity count8 is
port(
: in std_logic;
clk: in std_logic_vector (7 downto 0);
d: out std_logic_vector (7 downto 0);
q
);end count8;
is
architecture count8_arch signal r, r_in : std_logic_vector (7 downto 0);
begin
comb: process(load, count, d, r) is
variable tmp : std_logic_vector (7 downto 0);
begin
if load = '1' then
:= d;
tmp elsif count = '1' then
:= r + 1;
tmp else
:= r;
tmp end if;
<= tmp;
r_in <= r;
q end process;
seq: process(clk)
begin
if rising_edge(clk) then
<= r_in;
r end if;
end process;
end count8_arch;
We can do the same using record types:
Packages
An example:
-- https://www.ics.uci.edu/~jmoorkan/vhdlref/function.html
package refpack is
function parity (x : std_logic_vector)
return std_logic;
end refpack;
package body refpack is
function parity (x : std_logic_vector)
return std_logic is
begin
-- function body
end parity;
end refpack;
case ('switch') statement
Syntax:
<expression> is
case <const> =>
when ...
<const> =>
when ...
end case;
Example:
case a_const is"00" =>
when := 0;
a_var "01" =>
when := 1;
a_var "10" =>
when := 2;
a_var end case;
Procedure
- Like functions but doesn't have to return any value or can return multiple values??.
Functions
- May contain any sequential statement except signal assignment and wait.
- Functions can have only input parameters, so the mode of args (ie,
out~/~in
) needn't be mentioned. - Got to return some value (otherwise use a procedure). ref
- Equivalent to combinatory logic. Cannot replace code containing events or delays.
- TODO VHDL-93 functions may be declared as pure or impure.
Syntax:
function function_name (args: arg_types) ret_type is
declarations
begin
sequential statements
end function_name;
Example:
-- Boolean NOT
: std_logic)
function cust_not (val
return std_logic is
begin= '1' then
if val '0';
return
else'1';
return
end if; end function cust_not;
VHDL vs C
VHDL | C |
---|---|
elsif |
else if |
= |
== |
:= & <= |
= |
if
statement
Example:
= '1' then
if load := r + 1;
tmp = '1' then
elsif count := r - 1;
tmp
else:= 1;
tmp end if;
Loops
-- find first set bit
: std_logic_vector(7 downto 0);
variable vec : natural;
variable first
'range loop
for i in vec= '1' then
if vec(i) := i;
first -- break statement
exit;
end if; end loop;
std_logic_1164
- VHDL 1993 onwards.
- Expanded in VHDL 2008
- only logical operations are defined on these types.
Operations
Operators available in this package include:
and | or | xor |
nand | nor | nxor |
std_logic_vector
Like an array of std_logic
elements.
-- Vector of 8 bits in each case
-- MSB is in the beginning.
-- Better use this form to avoid confusion
: std_logic_vector (7 downto 0);
signal a
-- MSB is at the end.
: std_logic_vector (0 to 7);
signal b
-- Indexing a bitvector
-- Get 4th element of a vector
b(4)
Extract specific bit positions
vec(0)
: bit 0vec(9 downto 7)
: bits 9,8,7vec(1 to 3)
: bits 1,2,3
Ref: link
Types
U
: uninitializedX
: forcing unknown0
: forcing 01
: forcing 1Z
: high impedance (tri-state)W
: weak unknownL
: weak 0H
: weak 1-
: don't care
U | X | 0 | 1 | Z | W | L | H | - | |
---|---|---|---|---|---|---|---|---|---|
U | U | U | U | U | U | U | U | U | U |
X | U | X | X | X | X | X | X | X | X |
0 | U | X | 0 | X | 0 | 0 | 0 | 0 | X |
1 | U | X | X | 1 | 1 | 1 | 1 | 1 | X |
Z | U | X | 0 | 1 | Z | W | L | H | X |
W | U | X | 0 | 1 | W | W | W | W | X |
L | U | X | 0 | 1 | L | W | L | W | X |
H | U | X | 0 | 1 | H | W | W | H | X |
- | U | X | X | X | X | X | X | X | X |
Source: http://people.sabanciuniv.edu/erkays/el310/ch09.pdf
Explained
- 'Forcing' means that the the signal is driven by a circuit with a regular driving current. [1][1]
- Only 0, 1 and
Z
find practical use in synthesis these days.
Moore machine
Bit vector representation
numeric_std
- ieee.numericstd
- Provides efficient implementation of operations like
+
,-
, comparison, etc.
Syntax examples
Assignment after a delay
Although practically, it is quite impossible to construct a circuit with an exact delay since many factors are at play:
- device technology
- routing
- fabrication process
- operation environment
<= a + b + 1 after 10 ns;
y -- means that whenever a or b changes, the expression a+b+1 is evaluated
-- and its value is assigned to y after a delay of 10ns.
Closed feedback loop (bad!)
- A variable is being used to calculate its own next value.
- Considered bad practice. Better avoided.
- Because, it becomes sensitive to internal propagation delays and might lead to race condition.
- Confuses synthesis software.
- Complicates verification and testing.
- Presence of a closed feedback loop => circuit is no longer combinational.
<= (q and (not en)) or (d and en);
q -- keep value of q unchanged if en is 0.
-- Otherwise use d to set q
Conditional assignment
signal_name <= value_expr_1 when boolean_expr_1 else
value_expr_2 when boolean_expr_2 else
...
value_expr_n;
Examples
4:1 MUX
library ieee;
use ieee.std_logic_1164.all;
entity mux41 is
port(
, b, c, d: in std_logic_vector(7 downto 0); -- input lines
a: in std_logic_vector(1 downto 0); -- select lines (2)
s: out std_logic_vector(7 downto 0) -- output line
o
);end mux41;
is
architecture mux41_arch begin
<= a when (s="00") else
o when (s="01") else
b when (s="10") else
c
d;end mux41_arch;
2:4 decoder
s0 | s1 | out |
---|---|---|
0 | 0 | 0001 |
0 | 1 | 0010 |
0 | 1 | 0100 |
1 | 1 | 1000 |
library ieee;
use ieee.std_logic_1164.all;
entity decoder is
port(
: in std_logic_vector(1 downto 0);
s: out std_logic_vector(3 downto 0)
o
);end decoder;
is
architecture decoder_arch begin
<= "0001" when (s="00") else
o "0010" when (s="01") else
"0100" when (s="10") else
"1000";
end decoder_arch;
4:2 priority encoder
r (in) | code (out) | active (out) |
---|---|---|
1xxx | 11 | 1 |
01xx | 10 | 1 |
001x | 01 | 1 |
0001 | 00 | 1 |
0000 | 00 | 0 |
library ieee;
use ieee.std_logic_1164.all;
entity prio42 is
port(
: in std_logic_vector(3 downto 0);
r: out std_logic_vector(1 downto 0);
code: out std_logic
active
);end piro42;
is
architecture prio42_arch begin
<= "11" when (r(3)='1') else
code "10" when (r(2)='1') else
"01" when (r(1)='1')
"00";
-- Not sure if the following line would've been okay.
-- active <= '0' when (r="0000") else '1';
<= r(3) or r(2) or r(1) or r(0);
active end prio42_arch;
Simple ALU
ctrl | result |
---|---|
0xx | src0 + 1 |
100 | src0 + src1 |
101 | src0 - src1 |
110 | src0 and src1 |
111 | src0 or src1 |
library ieee;
use ieee.std_logic_1164.all;
entity alu is
port(
: in std_logic_vector(2 downto 0);
ctrl, src0: in std_logic_vector(7 downto 0);
src1: out std_logic_vector(7 downto 0);
result
);end alu;
is
architecture alu_arch signal sum, diff, inc: std_logic_vector(7 downto 0);
begin
<= src0 + 1
inc <= src0 + 1 when
ctrl end alu_arch;
Terms
- Delta cycle
- Applicable only during simulation.
- Doesn't affect synthesized circuit.
- Delta delay
- An infinitesimaly small delay after which assignments to signals happen in VHDL by default. ie, unless a delay amount is explicitly specified.
- Wikipedia
package
Compilation and simulation
Three phases in simulation of VHDL code:
- Analysis (compilation)
- Elaboration
- Simulation
Analysis
- VHDL compiler is also known as an analyzer.
- Check if code conforms to syntax and semantics. If okay, generates intermediate code.
- This intermediate code can be used by simulators and synthesizers, after some processing if needed.
Elaboration
- Converts the intermediate code generated as a result of analysis to a form that can be used by simulators.
- A driver is created for each signal.
- Each driver holds the current value and a queue of future values of the signal associated with it.
Simulation
- Consists of an initialization phase and the actual simulation.
- Simulation commands accepted by the simulator control the simulation.
Tips
wait
statement cannot appear outsideprocess
-es.if
statements cannot appear outsideprocess
-es.- Writing test benches always takes more time than writing the design.
Leave a component port disconnected
Ports can be left disconnected while doing port map
on components. Use open
.
: HALFADD port map
ADDER2=>Y,A=>X,SUM=>S,CARRY=>open); (B
Reference: https://www.ics.uci.edu/~jmoorkan/vhdlref/compinst.html
Non-standard packages to avoid
Don't use | Instead use |
---|---|
ieee.std_logic_unsigned |
ieee.numeric_std.all |
ieee.std_logic_arith |
use ieee.numeric_std.all;
-- use ieee.std_logic_arith.all;
Type conversion for std_logic_vector
to_integer() +--------+ std_logic_vector()
+---------------| signed |-------------------+
| +--------+ |
| ^ ^ |
| | | |
| to_signed()| |signed() |
| | | |
V | | V
+---------+ | | +------------------+
| |-----------+ +-----------| |
| integer | | std_logic_vector |
| |-----------+ +-----------| |
+---------+ | | +------------------+
^ | | ^
| | | |
| to_unsigned()| |unsigned() |
| | | |
| V V |
| +----------+ |
+--------------| unsigned |------------------+
to_integer() +----------+ std_logic_vector()
<------------------------> <-------------------------------->
Conversion functions Type cast
Acronyms
- LRM: Language Reference Manual.
- ie, the VHDL standard (IEEE Std 1076-2008 seems to be the latest)
More
- generic
- attribute
- scalar types
- comparison operators
- Linting tool:
- Style checks:
ghdl -s --std=08 file.vhdl
- Logical error checks: https://github.com/m-kru/go-hdl
- Style checks:
Glossary
General
- ASIC
- Application Specific Integrated Circuit
Synthesis
- A process by which an abstract specification of desired circuit behaviour (typically at RTL level) is turned into a design implementation using logic gates.
- VHDL => source is compiled and mapped into an implementation technology like FPGA or ASIC.
- Not all VHDL constructs are suitable for synthesis though.
- Eg: Stuff that explicitly mention timing (like
wait for 10 ns
) are not synthesisable though they can be used during simulation.
Register Transfer Notation (RTL)
References
- RTL hardware design using VHDL by Pong P. Chu
- Digital systems design using VHDL by Charles H. Roth jr and Lizy Kurian John
- IEEE standard VHDL Language reference manual (IEEE Std 1076, 2000 edition)
Doubts
- if a signal appears in the sensitivity list of multiple processes, in which order will the process blocks be run?
- In the case of simulation, it's implementation defined.