0% found this document useful (0 votes)
9 views40 pages

Lec5 - Counters Modified

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views40 pages

Lec5 - Counters Modified

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 40

Libraires, Types in Seq.

circuits

LECTURE 5
Libraries
 Libraries provide an alternative to explicit component declaration
 Standard Library (STD) – Implicit
 Working Library (work) – Implicit
 Resource Libraries
 IEEE developed libraries
library
library ieee;
ieee;
 Intel FPGA component libraries use
use ieee.std_logic_1164.all;
ieee.std_logic_1164.all;
 Any library of design units that are referenced in a design
 Libraries are structured in one or more packages that contain the
declaration of types, functions and components
 Components within a declared package do not need to be re-
declared within the architecture.
 User-defined packages are common (component reuse)
Referencing libraries and
packages
 Syntax:
library <name>;
use <name>.<package_name>.all;

 library clause:
 Defines the library name that can be reference
 Is a symbolic name to a path/directory
 use clause
 Specifies the package and object in the library that
you have specified in the library clause
 All packages used must be compiled
The WORK library
 The fact that the work library is implicit in all designs, provides an
library work; -- library is where we save our design
 alternative way--to(.vhd
instantiate
use work.all; file &components
compiler & within an entity
simulator etc files)
 This notation is called direct instantiation or entity instantiation, to
differentiate from the component instantiation described before
 It relies on the fact that components declared in a library do not
need to be re-declared in the architecture
Libraries - IEEE
 The ieee library contains several packages:
 std_logic_1164
 std_logic_textio Packages that contain
 std_logic_arith types and functions for
 std_logic_signed circuit design, synthesis,
 std_logic_unsigned and simulation

Packages designed to replace
numeric_bit

STD_LOGIC for synthesis of
numeric_std
arithmetic functions
 math_real
Non-synthesizable (mostly) functions
 math_complex
on real and complex numbers
Packages –
std_logic_1164
 This package contains the definition of types:
std_ulogic std_ulogic_vector
std_logic std_logic_vector
 For these types, it (re-)defines the logic functions:
and nand or xor xnor not

function “and” ( L : STD_ULOGIC; R : STD_ULOGIC) return STD_ULOGIC;


function “and” ( L : STD_LOGIC; R : STD_LOGIC) return STD_LOGIC;
function “and” ( L : STD_ULOGIC_VECTOR; R : STD_ULOGIC_VECTOR)
return STD_ULOGIC_VECTOR;
function “and” ( L : STD_LOGIC_VECTOR; R : STD_LOGIC _VECTOR)
return STD_LOGIC_VECTOR;

 Plus some conversion functions between similar types (mostly


obsolete) and a couple of test functions, notably:
rising_edge falling_edge
The importance of types
 Take for example a STD_LOGIC_VECTOR of size 8 bits
my_vector <= "10000001";
[...]
if my_vector < 0 then [...]
 Is the condition true?
 It depends...
 If the vector represents an unsigned number, then it is equal to +129
and the condition is false
 If the vector represents a signed number, then it is equal to -127 and
the condition is true
 The operator “<” cannot be defined (has no meaning) for type
STD_LOGIC_VECTOR


After a series of “hacks”, the IEEE developed a new package
Packages – numeric_std
 This package contains the definition of the following synthesizable
types and functions:
 The signed and unsigned types
 The logic functions: and, or, nand, nor, not, xor, xnor
 The arithmetic functions: +, -, *, /, rem, mod
 The comparison functions: <, <=, >, >=, =, /=
 The shift functions: shift_left, shift_right, rotate_left,
rotate_right
 Several type conversion functions
 Note that these functions are only defined for signed and
unsigned types (and not, for example, for std_logic_vector)
 Once the package has been declared on top of your VHDL file,
these functions can be used without additional declarations
Complex operators
 One of the key features of VHDL is the possibility of using complex
operators rather than relying only on logic gates
 The arithmetic functions: +, -, *, /, mod, rem, abs
 The comparison functions: <, <=, >, >=, =, /=
 The shift functions: shift, rotate
 Using these operators is fundamental for the design of complex
circuits (particularly in datapaths)
 However, arithmetic and comparison operators have different
meaning and different hardware implementations depending on
the type of signal they are applied to
Synthesizable VHDL –
 NUMERIC.STD
Using the IEEE.numeric_std package and the signed and
unsigned types allows you to use complex operations on data
 IEEE libraries being defined for synthesis, these operators are fully
synthesizable: they will be transformed into an (optimized)
hardware implementation by the synthesis tools. Their use is
highly recommended for synthesizable VHDL (much better control
of arithmetic operations)
 But be careful! The definition may not necessarily always meet
your needs as a designer – for example, the + operator does not
explicitly define a carry out value
function "+" (L, R: UNSIGNED) return UNSIGNED;
-- Result subtype: UNSIGNED(MAX(L'LENGTH, R'LENGTH)-1
downto 0).
-- Result: Adds two UNSIGNED vectors that may be of
different lengths
Synthesizable VHDL – NUMERIC_STD
 In hardware, SIGNED and UNSIGNED are exactly equivalent to
STD_LOGIC_VECTOR, but carry additional information for the
synthesis tools, so are not quite identical
 In order to use an operator (or a function) on a signal, the operator
must be defined for the specific type of the signal. For example,
from numeric_std:
function "+" (L: UNSIGNED,R: UNSIGNED) return UNSIGNED;
function "+" (L: SIGNED, R: SIGNED) return SIGNED;
function "+" (L: UNSIGNED;R: NATURAL) return UNSIGNED;
function "+" (L: NATURAL; R: UNSIGNED) return UNSIGNED;
function "+" (L: INTEGER; R: SIGNED) return SIGNED;
function "+" (L: SIGNED; R: INTEGER) return SIGNED;

 As a consequence, their use requires frequent type conversions


between std_logic_vector, signed/unsigned, and integer.
These conversion are realised either through conversion functions
or typecasting.
Type conversion
 to_unsigned / to_signed
 These functions convert integers to unsigned or signed vectors. Their
syntax is:
to_unsigned(value,num_bits);

to_signed(value,num_bits);
 For example:

signal my_vector : unsigned(7 downto 0);


[...]
my_vector <= to_unsigned(34, 8);
Type conversion
 to_integer
 This function converts other types to integer. In synthesizable VHDL, it is used most
commonly on signed or unsigned
 Its syntax is:
to_integer(vector);

 Note that the vector must not have multiple possible integer values. Hence:
signal my_vector : std_logic_vector(7 downto 0);
signal my_integer : integer;
[...]
my_integer <= to_integer(my_vector); -- ILLEGAL
is illegal, but
signal my_vector : unsigned(7 downto 0);
signal my_integer : integer;
[...]
my_integer <= to_integer(my_vector);
is correct.
Type casting
 When converting between similar vectors of the same size,
type casting is used:

signal my_vector : std_logic_vector(7 downto 0);


signal my_unsigned : unsigned(7 downto 0);
[...]
my_unsigned <= unsigned(my_vector);
my_vector <= std_logic_vector(my_unsigned);

 For example, to go back to the illegal example of the


to_integer function, an alternative solution can be:

signal my_vector : std_logic_vector(7 downto 0);


signal my_integer : integer;
[...]
my_integer <= to_integer(my_vector); -- ILLEGAL
my_integer <= to_integer(unsigned(my_vector)); -- OK
User-Defined Types
 Pre-defined types are just some of many possible data types in
VHDL. Others can be user-defined types
 Syntax:
type type_name is [type definition];
signal signal_name: type_name;
 For synthesis, all types should have an obvious mapping to a
binary representation
 User-defined types:
type day_of_the_month is range 0 to 31;
signal current_day: day_of_the_month;
 Synthesis will convert this to binary 0 to binary 31 (5 bit bus)
 User-defined enumeration types: Keep in
type my_door is (open, closed, locked); mind!
signal current_state: my_door;
 Synthesis will convert this to binary 0 to binary 2 (2 bit bus)
 Any operator applied to user-defined types must be defined
whenever it involves different types
1
Counters 6

 Counter:A Sequential Circuit that


counts pulses. Used for Event
Counting, Frequency Division,
Timing, and Control Operations.
1
Counters 7
 Timing Diagram
Counters
 After (D-type) flip-flops and registers, arguably the most important
sequential component for digital designs is the counter
 Note that counters are sometimes implemented using type
integer: this is actually not bad design practice in itself, but
requires moderately advanced VHDL skills
 Type integer is often interpreted as a 32-bit bus by synthesis tools,
creating a 32-bit counter (rarely needed) – there are strong restrictions
on the use of this type for synthesizable VHDL
 In this module, you should never use type integer for counters, but
always type unsigned

Why do we
need
unsigned?
Counters – 8-bit
unlimited
entity CNT_8BIT is
port (CLK, EN, RST : in STD_LOGIC;
Q : out UNSIGNED(7 downto 0));
end CNT_8BIT;

architecture arch of CNT_8BIT is


signal Qint : UNSIGNED(7 downto 0);
begin
CNT8: process (CLK)
begin
Note the
if (rising_edge(CLK)) then
arithmetic
if (RST = '1') then
operator '+' ! Type
Qint <= (others => '0');
UNSIGNED and
else
NUMERIC_STD
if (EN = '1') then
package required
Qint <= (Qint + 1);
end if;
end if; What happens
end if; when the
end process CNT8; counter
Q <= Qint; reaches 255?
end arch;
Counters
 Often, counters are limited (i.e., they do not use the full range of
values that can be represented by their bit size).There are several
“proper” implementations of limited counter, and several bad
ones.
Counters – 4-bit decimal counter 0 to 9
(1)
entity CNT_10 is
port (CLK, EN, RST : in STD_LOGIC;
Q : out UNSIGNED(3 downto 0));
end CNT_10;
architecture arch of CNT_10 is
signal Qint : UNSIGNED(3 downto 0);
begin
CNT_DEC: process (CLK)
begin
if (rising_edge(CLK)) then
if (RST = '1') then
Qint <= (others => '0');
else
if (EN = '1') then
if (Qint = 9) then -- or (Qint = "1001")
Qint <= (others => '0');
else
Qint <= (Qint + 1);
end if;
end if;
end if;
end if;
end process CNT_DEC;
Q <= Qint; BEST
end arch;
Counters
entity CNT_10 is
– 4-bit
decimal counter
port (CLK, EN, RST : in STD_LOGIC;
Q : out UNSIGNED(3 0 to 9
downto 0));

(1)
end CNT_10;

architecture arch of CNT_10 is


signal Qint : UNSIGNED(3 downto 0);
begin
CNT_DEC : process (CLK)
begin
if (rising_edge(CLK)) then
if (RST = '1' or ((Qint = 9) and (EN = '1')) then
Qint <= (others => '0');
else
if (EN = '1') then
Qint <= (Qint + 1);
end if;
end if;
end if;
end process CNT_DEC;
Q <= Qint; FINE
end arch;
Counters
entity CNT_10 is
– 4-bit
decimal counter
port (CLK, EN, RST : in STD_LOGIC;
Q : out UNSIGNED(3 0 to 9
downto 0));

(1)
end CNT_10;

architecture arch of CNT_10 is


signal Qint : UNSIGNED(3 downto 0);
begin
CNT_DEC : process (CLK)
begin
if (rising_edge(CLK)) then
if (RST = '1' or Qint = 10) then
Qint <= (others => '0');
else
if (EN = '1') then
Qint <= (Qint + 1);
end if;
end if;
end if;
end process CNT_DEC; WRON
G
Q <= Qint;
end arch;
Counters
entity CNT_10 is – 4-bit
port (CLK, EN, RST : in STD_LOGIC;
decimal counter
Q : out UNSIGNED(3
end CNT_10;
0 to 9
downto 0));

(1)
architecture arch of CNT_10 is
signal Qint : UNSIGNED(3 downto 0);
begin
CNT_DEC : process (CLK)
begin
if (Qint = 10) then
Qint <= "0000";
elsif (rising_edge(CLK)) then
if (RST = '1') then
Qint <= (others => '0');
else
if (EN = '1') then
Qint <= (Qint + 1);
end if;
end if;
end if;
end if;
end process CNT_DEC;
WRON
Q <= Qint;
end arch; G
Shift Registers
2
 Right Shift: A movement of data from left 5 to
right in the shift register (toward the LSB).
One bit shift per clock pulse.
 Left Shift: A movement of data from right to
left in the shift register (toward the MSB). One
bit shift per clock pulse.
 Rotation: Serial shifting (right or left) with
the output of the last FF connected to the
input of the first. Results in continuous
circulation of SR data.
Shift Registers

26
Shift Registers

27
Serial Shift Register (SR)
2
 A 4-Bit Left Shift Register. 8
 DIN is shifted into the LSB FF and shifted toward the
MSB.

Q3 D3 Q2 D2 Q1 D1 Q0 D0 DIN

MSB LSB

< < < <


CLK
SS Left Shift – 1 2
9

Q3 D3 Q2 D2 Q1 D1 Q0 D0 DIN

MSB LSB

< < < <


CLK
SS Left Shift – 2 3
0

Q3 D3 Q2 D2 Q1 D1 Q0 D0 DIN

MSB LSB

< < < <


CLK
SS Left Shift – 3 3
1

Q3 D3 Q2 D2 Q1 D1 Q0 D0 DIN

MSB LSB

< < < <


CLK
SS Left Shift – 4 3
2

Q3 D3 Q2 D2 Q1 D1 Q0 D0 DIN

MSB LSB

< < < <


CLK
Bi-Directional Shift Register
3
3
 When DIR = 0, the path of Left_Shift_In
is selected.

 When DIR = 1, it selects the Right Shift In Path.

Q3  Q2  Q1  Q0 

Q3  Q2  Q1  Q0 
Arrays
 An array in VHDL is a type that represents collection
of objects of the same type. Its declaration must
include the size and the type of object:
type myarray is array (31 downto 0) of integer;
signal array1: myarray;
 Arrays are extremely useful constructs. Some of the
standard and IEEE types are arrays (string,
bit_vector, std_logic_array, signed, unsigned).
These types are defined in the respective packages
and do not need to be re-declared. For example:
signal array1: STD_LOGIC_VECTOR (31 downto 0);
is equivalent to
type my_vector_type is array (31 downto 0) of STD_LOGIC;
signal my_vector : my_vector_type;
 Note that in hardware only one-dimensional arrays
make any sense! (with a couple of exceptions )
Arrays
 Arrays can be declared in either direction and with any
finite bound:
input array1: in STD_LOGIC_VECTOR (31 downto 0);
signal array2: STD_LOGIC_VECTOR (1 to 3);
as long as the bounds make sense:
input array1: in STD_LOGIC_VECTOR (0 downto 6); --ILLEGAL
signal array2: STD_LOGIC_VECTOR (3 to 0); --ILLEGAL
For synthesizable VHDL, the use of to is strongly
discouraged!
 Any “slice” of an array can be assigned, including a
single element, as long as the two sides have the same
size:
array2(1) <= '0';
array2 <= array1(2 downto 0);
array1(15 downto 8) <= "01010101";
 Once a direction has been declared, it cannot be
changed:
Arrays
signal array1: STD_LOGIC_VECTOR (4 downto 0);
signal array2: STD_LOGIC_VECTOR (2 downto 0);
signal a,b,c: STD_LOGIC;
signal array3: STD_LOGIC_VECTOR (1 downto 0);
 Arrays can be defined with the concatenation operator
&:
array2 <= a & b & c; -- order is important (downto)
array1 <= array3 & array2; -- order is important (downto)

 In comparison operators, array operands can be of


different lengths, but are left-aligned:
array1 <= "10011";
array2 <= "111";
if (array2 > array 1) then […]
Returns TRUE for unsigned numbers! So don’t do it!
Arrays
signal array1: STD_LOGIC_VECTOR (4 downto 0);
signal array2 : STD_LOGIC_VECTOR (1 downto 0);
signal a: STD_LOGIC;

 The others clause is particularly useful when dealing


with arrays:
array1 <= array2 & (others => '0'); -- concatenation
and in particular:
array1 <= (others => '0'); -- reset

REG: process (CLK)


begin
if (rising_edge(CLK)) then
if (RST = '1') then
array1 <= (others => '0'); -- instead of "00000";
elsif (WEN = '1') then
array1 <= Data;
end if; KEEP IN
end if;
end process REG;
MIND!
Arrays: memories
An exception to the one-dimension rule is in the definition
of memories (both ROMs and RAMs).
entity async_rom16x8 is Size of ROM (16x8)
Port ( Address : in UNSIGNED (3 downto 0);
DataOut : out STD_LOGIC_VECTOR (7 downto 0));
end async_rom16x8;

architecture arch of async_rom16x8 is

type ROM_Array is array (0 to 15) of std_logic_vector(7 downto 0);


constant Content: ROM_Array := (
0 => B"00100100", Contents of addresses 0, 1, 2, 5, 6
1 => B"00000001", (B"XXXX") = binary number
2 => B"00010010",
5 => B"11111111",
6 => B"00000011", 0s for all other addresses
others => B"00000000");
Asynchronous
read (no clock)
begin Library function
DataOut <= Content(to_integer(Address));
end arch;
Arrays: memories
entity sync_rom16x8 is
Port (CLK, REN : in STD_LOGIC; Size of ROM (16x8)
Address : in UNSIGNED (3 downto 0);
DataOut : out STD_LOGIC_VECTOR (7 downto 0));
end sync_rom16x8;

architecture arch of sync_rom16x8 is


type ROM_Array is array (0 to 15) of std_logic_vector(7 downto 0);
constant Content: ROM_Array := (
0 => B"00100100", Contents of addresses 0, 1, 2, 5, 6
1 => B"00000001", (B"XXXX") = binary number
2 => B"00010010",
5 => B"11111111",
6 => B"00000011", 0s for all other addresses
others => B"00000000");
begin Synchronous read
process (CLK) (rising edge)
begin No reset in a memory
if (rising_edge(CLK)) then
if (REN='1') then
DataOut <= Content(to_integer(Address));
end if;
end if;
end process;
end arch;
Arrays: memories
entity dual_port_ram16x8 is
Port ( CLK, WEN : in STD_LOGIC; Separate read and write ports
WAddress : in UNSIGNED (3 downto 0);
RAddress : in UNSIGNED (3 downto 0);
DataIn : in STD_LOGIC_VECTOR (7 downto 0);
DataOut : out STD_LOGIC_VECTOR (7 downto 0));
end dual_port_ram16x8;

architecture arch of dual_port_ram16x8 is

type ram_type is array (0 to 15) of std_logic_vector(7 downto 0);


signal my_ram: ram_type := (
0 => X"F3", Signal, not constant for values
1 => X"06", (optional, rare, initialization)
others => X"00");
begin
Asynchronous read
DataOut <= my_ram(to_integer(RAddress));

process (CLK) Synchronous write (rising edge)


begin
if (rising_edge(CLK)) then No reset in a memory
if (WEN='1') then
my_ram(to_integer(WAddress)) <= DataIn;
end if;
end if;
end process;
end arch;

You might also like