VHDL
Initiated by US Government’s VHSIC Program in 1980.IBM, TI and Intermetrics started the development of VHDL in 1983
• VHDL Ver. 7.2 released in 1985
• IEEE standard 1076-1987 in 1987
• IEEE 1076-1993 - revision in 1993
• VHDL is a product of VHSIC program of US Department of Defense (DoD).
VHDL
• Very High Speed Integrated Circuit Hardware Description Language.
• VHDL is an industry standard HDL for the Description, Modeling and Synthesis of digital circuits and systems.
• Can model a digital system at many levels of abstraction in VHDL.
• The algorithmic or functional level
• Data flow
• Gate level
• Can verify design functionality early in the design process and simulate a design written as a VHDL description.
• Logic Synthesis and optimization converts a VHDL description to a gate level implementation in a given technology.
• Reduces circuit design time and errors.
• VHDL descriptions provide technology independent documentation for a design and its functionality.
• Power and Flexibility
• Powerful constructs to write complex logic
• It has multiples levels of design descriptions
• It supports design libraries and the creation of reusable components
• It provides for design hierarchies to create module design
• Device independent design
• VHDL permits to create a design without first choosing the device for implementation
• Portability
• VHDL is an IEEE standard.
• Libraries of VHDL models of components can be shared across platforms,tools organization and technical group
• ASIC Migration
• Quick time to market and low cost
• VHDL supports design hierarchies
– A digital system can be modeled as a set of interconnected components
• It supports flexible design methodologies
– Top-down , Bottom-up or mixed.
• VHDL is not technology specific. It can support various hardware technologies
• It supports both synchronous and asynchronous timing models
• Various modeling techniques such as FSM, algorithmic and Boolean equations can be modeled using VHDL.
• Any large design can be modeled using VHDL
– No limitation imposed by the size of a design
• Test benches can be written in VHDL to test other models.
• Propagation delays, set-up and hold time timing constraints can be described in VHDL
• Generics and attributes are useful in describing parameterized design
• Models written in VHDL can be verified by Simulation
• Behavioral models are capable of being synthesized to gate- level description
What is the difference between VHDL and Verilog?
Ans:Fundamentally speaking, not a lot. You can produce robust designs and comprehensive test environments with both languages, for both ASIC and FPGA. However, the two languages approach the task from different directions; VHDL, intended as a specification language, is very exact in its nature and hence very verbose. Verilog, intended as a simulation language, it much closer to C in style, in that it is terse and elegant to write but requires much more care to avoid nasty bugs. VHDL doesn't let you get away with much; Verilog assumes that whatever you wrote was exactly what you intended to write. If you get a VHDL architecture to compile, it's probably going to approximate to the function you wanted. For Verilog, successful compilation merely indicates that the syntax rules were met, nothing more. VHDL has some features that make it good for system-level modeling, whereas Verilog is much better than VHDL at gate-level simulation.
VHDL Design units
• Entity
• Package
• Configuration
• Architecture
• Package body
Packages in VHDL
• A package is collection of commonly used subprograms declarations and definitions of objects, function, procedures, components, attributes.
• Can be shared across designs
• Package declaration - interface to package
• Package body - to contain the full code for any functions or procedures which have been declared in the associated package.
• example of a package is std_logic_1164
• Package is a collection of
• types, constants, subprograms, functions etc.
• to group a set of
• related items
• global information
• can be shared by many designs
• A package is made visible with a ‘use ‘clause of the form
Use lib_name.package_name.item ;
package is split into declaration and optional body
– only the declaration interface is visible to user
Package declaration
- Type and subtype declarations
- Constant declarations
- Global signal declarations
- Function and procedure declarations
- File declarations
- Component declarations
- Alias declarations
- Use clauses
Package declaration
Syntax is
package package_name is
constant, procedure, function,
component declarations
end package_name ;
Package Body
• Associated with a package declaration of the same name
• Contains the subprogram bodies of functions and procedures declared in the package declaration.
• Each package can have only one package body. Contain behavior of the subprograms
• values of constants etc (deferred)
• contain the algorithm for any functions or procedures
• Items in the package body are not visible to other design units
Syntax is
package body package_name is
declarations
constant,procedure,
function,
component
definitions
end package_name ;
Package
Package my_info is
type prime is (3,5,7,11);
subtype address is bit_vector(15 downto 0)
type MVL is(‘U’, ‘0’, ‘1’, ‘z’);
end my_info
• package body describe the behavior
• clause use is used to access the package
• items in package is refereed by package name.item name
• Example
use my_info.all
Standard Package
• The STANDARD package
– Predefines a number of data types, subtypes and functions which are visible to all design units.
• It is a part of the language specification.
Package standard
Package STANDARD is
type BOOLEAN is ( FALSE, TRUE);
type BIT is ( ‘0’ , ‘1’);
type SEVERITY_LEVEL is ( NOTE,WARNING, ERROR , FAILURE );
type INTEGER is range -2147483648 to + 2147483648 ;
type BIT_VECTOR is array ( Natural range <> ) of BIT;
type STRING is array (POSITIVE range <> ) of CHARACTER;
subtype POSITIVE
subtype NATURAL
end STANDARD;
Std_logic_1164 package
• It is not a part of VHDL standard definition.
• It contains definitions of data types, subtypes, and functions which extended VHDL into a multi value logic.
• IEEE standard # 1164 logic types package.
• defines types and operations on types for 9 valued logic.
• Nine valued logic - H, L, Z, X, and other permutation of hard / soft high and low logic levels).
Std_logic_1164
type std_ulogic
– unresolved logic type of 9 values
type std_ulogic_vector
– vector of std_ulogic
function resolved
– resolving a std_ulogic to std_logic
Subtype std_logic
– a resolved version of std_ulogic
subtype std_logic_vector
– a resolved vector of std_logic.
• Conversion functions
– From std_ulogic and bit, std_logic_vector and bit_vector etc.
• Functions rising edge and falling edge
– For edge detection of signals
Synopyss Packages
• Std_logic_1164 Package
• std_logic_misc Package.
• std_logic_arith Package
• Represents numeric values as arrays of numeric values
Std_logic_arith Package
• Contains type conversion functions
• Allows us to perform arithmetic operations and numeric comparisons on array data types
• Defines two major data types UNSIGNED and SIGNED.
• Can use the package for both synthesis and simulation.
• Can make the std_logic_vector synonymous with either SIGNED or UNSIGNED.
use of this package in a VHDL source file
library IEEE;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_1164.all;
Type definitions for signed and unsigned.
Type unsigned is array ( natural range <> ) of std_logic;
Type signed is array(natural range <> ) of std_logic;
Unsigned
• Represents an unsigned numeric value.
• Decimal number 8 can be represented as UNSIGNED’(“1000”)
• A larger vector holds a larger number
• A four bit vector holds value up to 15
• A eight bit vector holds value up to 255.
• Negative numbers cannot be represented in an unsigned variable.
• Zero is the smallest value that can be represented.
• MSB is the farthest left array bound.
• Variable a : unsigned ( 1 to 10) ;
signal s1 : unsigned ( 5 downto 0);
Signed
• Represents a signed numeric value
• A 2 s complement binary number with the farthest left bit as the sign bit.
• SIGNED’ (“0101”) --represents +5
• SIGNED’ (“1101”) --represents - 5
• A variable or signal can be declared as signed.
• A large vector holds a large number
• A four bit variable holds from - 8 to 7
• A 8 bit variable holds value from -128 to 127
• variable v1 : signed( 1to 10 );
• signal s1 : signed ( 5 downto 0);
Std_logic_arith
• Functions
• Conversion functions
• Three sets of Conversion functions to convert values between UNSIGNED and SIGNED data type and integer.
• The conv_Integer functions
• The conv_unsigned and conv_signed
• Arithmetic Functions
• For use with combinations of unsigned and signed and the predefined types std_ulogic and integer.
Functions
• Comparison Functions
• Functions to compare unsigned and signed data types to each other and to predefined data type integer.
• Shift Functions
• For shifting the bits in signed and unsigned numbers
• SHL --shift left logical
• SHR - -shift right logical.
Numeric packages
• Numeric_bit
– Based on arrays with elements of type bit .
• Numeric_std
– Based on arrays with elements of type std_logic.
• Making the packages visible
library IEEE;
use IEEE.numeric_std.all;
use IEEE.std_logic_1164.all;
numeric-std
• Package defines two data types
Signed,unsigned
• Are arrays of element type std_logic.
• Type signed represents 2’S complement signed numbers
• Type unsigned represents unsigned magnitudes
• Range of a number is defined by the number of bits used in the array representation
Signed and Unsigned
• Signal a :signed ( 7 downto 0);
• signal b : unsigned ( 7 downto 0 );
• Both declarations create 8 bit buses
• First Declaration will be interpreted as a signed number with the range -128 to 127.
• Second declaration will be interpreted as an unsigned number with the range 0 to 255.
• Arrays are read from left to right , with the MSB on the left.
Package Declaration
• Package part_list is
component xor2
generic prop_delay : time := 2 ns;
port (a,b : in bit ; c : out bit) ;
end component;
component and2
port (a,b : in bit ; c : out bit) ;
end component;
end part_list
• compile this package to work library
Package Example
Package example is
procedure mux2to1(signal select : in bit;
signal din0 : in bit;
signal din1 : in bit;
signal d_out : out bit);
end example ;
Package body example is
procedure mux2to1( signal select : in bit;
signal din0 : in bit;
signal din1 : in bit;
signal d_out : out bit) is
Package body
begin
case select is
when ‘0’ =>
d_out <= din0;
when others =>
d_out <= din1;
end case;
end mux2to1;
end example;
VHDL Language elements
• Comments
• Comments are useful for documentation
• Give suitable comments wherever needed
“ - - ” comments starts with two hyphens
extends to the end of line or “CR”
-- This is a VHDL comment ended with a CR
-- VHDL do not support block comments
Example:comments
entity dff is --entity name
port(din ,clk : in bit; -- inputs
q : out bit); --output
end dff;
architecture behv of dff is
begin
process(clk) begin -- process is executed when CLK changes
if(clk’event and clk =‘1’) then --rising edge of clock
q<= din;
end if;
end process
end behv;
VHDL Language elements
• Identifier
– reserved words/ keywords
– user defined names - basic identifier &
extended identifier
Identifier
• should start with a letter
• can have underscore and digits- but last
character can not be “ _”
• Identifiers are case insensitive
• Examples
Data, data, daTa represent same identifier
1data , -data _data are data_ are wrong identifiers
mysignal and my_signal are different identifiers
Extended Identifier
• Identifier between two backslashes
• extended identifier is case sensitive
• Examples
\Myvhdl\ and \MyVHDL\ are different identifier
\-35\, \_cs17\ , \cs17_\ are valid identifiers
\$@!-- \\ __\ supported
Count and \Count\ are different identifiers
Keywords
• Keywords are special identifiers reserved to define the language constructs.
• A list of some keywords in VHDL is as follows
• entity case if else
• when loop process nor
• xnor nand or and
• exit alias block array
• begin after generic architecture
Non legal identifiers
_tx_clk identifier must start with a letter
8b10b identifier must start with a letter
Large#number letters, digits & under scores
Link_bar__ 2 under scores in succession are not allowed
Select VHDL reserved words
RXclk_ Last character cannot be an _
VHDL General syntax
• VHDL is case insensitive.
• The semicolon is used to indicate termination of a statement.
• Two dashes (--) are used to indicate the start of a comment.
• Identifiers must begin with a letter, subsequent characters must be alphanumeric or’_’ underscore.
• VHDL is a strongly typed language.
Number System
• Literal numbers in the base of
10 - decimal
2 - binary
16 - hexadecimal
• a point represents a real number
• Examples - decimal literal numbers
default base is 10
0, 1, 123_456_789, 98E5- integer
0.0, 233.5, 3.74, 98E-5 - real
1.23E-11,1.0E+4,3.024E+23 -real literal with exponent
Based literal
• Base is explicitly indicated
• base and exponent are decimal numbers
• alphabets are case insensitive
• Examples
2#1000_0001#, 16#81#
2#1.1111_1111_1111#E+11, 16#F.Ff#E2
16#fc#, 16#6#E1
Character and string literals
• Literal characters by single quote
• Examples
‘A’ ‘a’ ‘#’ ‘q’
String Literals
• Strings by double quotes
• Example
“This is a String”
“Is this string “” quoted””?”
• Examples for Bit strings
b”1000_0001” o”123” x”3E”
Architecture in VHDL
Syntax
• architecture architecture_name of entity_name is
[arch_item declarative_part]
begin
[arch_statement_part]
end [architecture_name];
• Declarative part - items for construction as
– signals
– components
– data types
– subprograms.
Concurrent statements define the relationship between the inputs and outputs.
• Concurrent signal assignment
• Process statement
• Component instantiation
• Concurrent procedure call
• Generate statement
Dataflow:
Example
architecture data_flow of ha_add is
begin
sum <= x xor y;
carry <= x and y ;
end data_flow;
architecture data_flow of full_add is
begin
sum <= x xor y xor z ;
carry <=(x and y)or(x and z)or (y and z );
end data_flow;
VHDL Structural description
supports hierarchical design
supports top down and bottom to top design flow
supports mixed mode
defines a system as collection of hierarchical modules
Structural designs consists of VHDL netlists.
Components are instantiated and connected together with signals
architecture structural of ha_add is
begin
x1:xorg port map(x,y, sum );
a2:andg port map(x,y,carry);
end structural;
Library:
• A library is a place to which design units may be complied.
• Entity declaration and architecture body pairs may be complied into a library.
Design units within a library may be used with other entities, provided that the library and design unit are visible.
Predefined libraries:
• STD
– Contains standard packages
• Components:
– STANDARD and TEXTIO.
– Automatically included in every design unit
• WORK
– User specified packages are stored in WORK library.
IEEE library;
• Is a storage place for IEEE standard design units such as the packages std_logic_1164, numeric_std and numeric_bit.
• The library must be made visible by way of a library clause. library IEEE ;
• The components, packages, declarations, functions and procedures within a library must be made visible via a use clause
Use IEEE. Std_logic_1164. all ;
Components
• A component represents an entity architecture pair.
• Components are design entities that can be instantiated in another architecture leading to hierarchical description.
• A component must be declared before it is instantiated
Component declaration:
Component component_name[is]
generic( generic_list);
port ( port_list);
end component_name;
• The component can be defined in a Package, design entity , architecture or block declarations.
• Components can be declared in the declaration portion of the architecture.
• Components can be declared in a package.
Component instantiation
• Introduces a subsystem declared elsewhere, either as a component or as an entity_architecture pair.
• The name of the instantiated component must match the name of the declared component.
• The instantiated component is called with actual parameters for generics & ports.
Configuration
• A configuration declaration is used to bind entity statements to particular architecture body to form components of a design.
• Configuration allows the late binding of components after multiple architecture bodies have been written and complied.
• A configuration declaration (identified with the configuration keyword) specifies which architectures are to be bound to the entity.
• It allows you to change how components are connected in your design description at the time of simulation
Default configuration
• Configuration declarations are always optional.
• The VHDL standard specifies a default configuration .
• In the case where there are more than one architecture for an entity, the last architecture complied will take precedence, and will be bound to the entity.
Configuration syntax
Configuration configuration_name of entity_name is
-- configuration declarations
for architecture_name
for instance_label : component_name
use entity library_name. entity_name (arch_name);
end for;
-- other for clauses
end for;
Syntax:
Configuration configuration_name of entity_name is
-- configuration declarations
for architecture_name
for instance_label : component_name
use configuration library_name. config_name;
end for;
end for;
Configuration rsffcon2 of rsff is
for behave
end for;
end rsffcon2;
Entity in VHDL
• Provides the port information
– Describes the interface of the design entity.
• The interface includes all inputs, outputs and bi-directional signals and generics.
• Declares the design name.
• A declarative part to declare Subprograms, types and constants .
– Declarations are visible to all the architectures assigned to the entity.
• An entity may contain its own passive statements.
Entity syntax:
Entity entity_name is
[generic;]
[port;]
[begin]
[entity statements;]
end [entity_name];
Ports:
• Each I/O signal in an entity declaration is a port.
• Must have a name , a direction (mode) and a data type.
• A port is a data object(signal).
• It can be assigned values and used in expressions.
Port Data Types
• Pre defined
– Boolean
– bit
– bit_vector
– integer.
• IEEE std_logic_1164
– std_ulogic , std_logic
– std_logic_vectors.
Modes:
• In - input port, read only
• out - output port , write only
• inout - bi-directional port, read/write,
multiple drivers
• buffer - read and update, single driver
Modelling the behavioura way;
• Architecture body
– describes an implementation of an entity
– may be several per entity
• Behavioral architecture
– describes the algorithm performed by the module
– contains
• process statements, each containing
– sequential statements, including
• signal assignment statements and
• wait statements
Modelling the structural way:
• Structural architecture
– implements the module as a composition of subsystems
– contains
• signal declarations, for internal interconnections
– the entity ports are also treated as signals
• component instances
– instances of previously declared entity/architecture pairs
• port maps in component instances
– connect signals to component ports
Mixed behavior and structure
• An architecture can contain both behavioral and structural parts
– process statements and component instances
• collectively called concurrent statements
– processes can read and assign to signals
• Example: register-transfer-level (RTL) Model
– data path described structurally
– control section described behaviorally
Testbench
• Testing a design by simulation
• Use a test bench model
– a Model that uses your Model
– apply test sequences to your inputs
– monitors values on output signals
• either using simulator
• or with a process that verifies correct operation
• or logic analyzer
entity declaration
entity add4 is
port
( a : in std_logic_vector(3 downto 0);
b : in std_logic_vector(3 downto 0);
ci : in std_logic;
sum : out std_logic_vector(3 downto 0);
co : out std_logic);
end add4;
entity and 2 is --and gate
port (a,b : in bit;
y : out bit);
end and2;
architecture dataflow of and2 is
Begin
y<=a and b;
end dataflow;
Generics:
• Part of entity header
• generic are constants
• passed to entity during simulation
• used to control the behavior of entity
• Generics are inputs. It is read only
• Generic values can be overridden
Use:
To specify the size of ports.
The number of sub components within a block.
The timing characteristics of a block.
Physical characteristics of a design
The width of the vectors
Syntax:
• Generic ( generic_interface_list);
Where do you declare Generics?
Generics can be declared in entities and component declarations.
The value of a generic constant can be specified using the generic map ( ) when the component is instantiated.
The value can also be specified when the component is declared.
Component xor2
generic ( gate_delay : time := 6 ns);
If both are specified , then the value provided by the generic map ( ) takes precedence
Entity gen_gates is
generic ( delay : time := 10 ns );
port ( in1 , in2 : in std_logic;
output : out std_logic);
end gen_gates;
Architecture gates of gen_gates is
begin
output <= in1 or in2 after delay;
end gates;
Examples
generic rise_time : time; -- not specified
generic count : natural := 10;
generic prop-delay : time := 5 nS;
• use keyword generic map to assign value while instantiation
Parameterized model
Architecture generic_delay of half_adder is
component xor2
generic( gate_delay : time);
port ( a ,b : in std_logic ; c : out std_logic);
end component;
component and2
generic ( gate_delay : time );
port ( a, b : in std_logic; c : out std_logic);
end component;
begin
x : xor2 generic map( gate_delay => 6 ns) port map ( a ,b, sum);
a1 : and2 generic map ( gate_delay => 6 ns) port map ( a ,b , carry);
end generic_delay;
Passing values of generics through multiple levels of hierarchy
entity half_adder is
generic ( gate_delay : time := 3 ns);
port ( a ,b : in std_logic;
sum , carry : out std_logic’ );
end half_adder;
Architecture gen_delay2 of half_adder is
component xor2
generic( gate_delay : time);
port ( a ,b : in std_logic ; c : out std_logic);
end component;
component and2
generic ( gate_delay : time );
port ( a, b : in std_logic; c : out std_logic);
end component
Concurrent statements
• Concurrent signal assignment
• Conditional signal assignment
• Selected signal assignment.
• Component Instantiation
• Process statements
• Generate statement
• Block statement
• Concurrent procedure and function calls.
• Data flow model the functionality
• Use concurrent signal assignment statements
• An architecture body can have any number of concurrent statements
• Ordering of statements are unimportant
• Are activated whenever any of the signals in the RHS of the <= changes their value.
• Multiple assignments to the same signal create multiple drivers.The type of the signal must be of resolved type
Data flow modeling
• Example 2 input AND gate
entity and2 is
port (a, b : in bit; c : out bit);
end and2;
architecture and2 of and2 is
begin
c <= a and b after 2 ns;
end and2;
• Example Full Adder
entity FA is
port( a_in, b_in , cy_in : in bit;
sum_out, cy_out : out bit);
end FA;
architecture FA of FA is
begin
sum_out <= a_in xor b-in xor cy_in;
cy_out <= (a_in and b_in) or (b_in and cy_in) or (a_in and cy_in);
end Fa;
• Select from different values based the expression
• Sensitive to expression and signals
• Expression are not evaluated in sequence
• All possible values of the expression must be covered
• Use others for uncovered values
• Similar to case in process
Selected signal assignment
With choice_expression select target <= expression when choices, expression when choices;
entity mux421 is
port( a,b,c,d : in std_logic_vector(3 downto 0);
s : in std_logic_vector(1 downto 0);
o : out std_logic_vector(3 downto 0));
end mux421;
Architecture mux_a of mux421 is
begin
with s select
o <= a when”00”,
b when”01”,
c when”10”,
d when others;
end mux_a;
selective signal aasignment
Architecture buf_a of tri_state_buf is
begin
with en select
buf_out <= buf_in when ‘1’ ,
‘Z’ when others;
end buf_a;
Conditional signal assignment
• Select from different values based on conditions
• Sensitive to signals or conditions
• Conditions are checked one by one
• Output is assigned based on the first true condition
• Equivalent if elsif else end if in process
When_else
• Conditional signal assignment
• A signal is assigned a value based on a condition being TRUE.
signal_name <=
value_ a when condition1 else
value_b when condition2 else
value_X;
Conditional signal assignment
architecture conditional of tri_state_buf is
begin
buf_out <= buf_in when( en = ‘1’) else ‘Z’;
end conditional;
A conditional signal assignment must end with an unconditional else expression.
architecture mux421_a of mux421 is
begin
o <= a when (s = “00”) else
b when (s = “01”) else
c when (s = “10”) else
d;
end mux421_a;
Data objects in VHDL
• Hold values of specific type.
• There are three classes of data objects.
Constants
Signals
Variables .
They must be declared before they are used
Constant
• Can hold a single value type
• Assigned during simulation start
• Can not be altered during simulation run
• Used to improve the readability of the code.
• Constants may be declared in package, entity, architecture or process declarative regions.
• Make it easier to modify the code.
• Deferred constant- missing initial value
• Constant constant_name : type := value;
Examples
constant pi : real := 3.1417;
constant delay : time := 5 nS;
constant max_width : integer := 64;
constant width:integer :=31;
constant period : time := 50 ns;
Variable
• A data object with a single current value.
• Variable variable_name : type;
• Variable variable_name : type := initial_value;
• Value of variable can be modified by assignment statement
• Must be declared only in the declarative regions of a process or sub program.
• Scope of the variable is limited to the process or subprogram they are defined in.
Examples
1. Variable count : natural := 0;
2. Variable status : bit_vector(0 to 7);
3. Variable no_error : boolean := true;
Note : -
in 2- the default value is 0
in 3 false if not specified
Signals
• An object with a past history of value.
• Holds a list of values
• Includes the current value
• A set of possible future values
• Future values assigned using signal assignment statement
• Signals are equivalent to wires and are used to inter connect components.
• Entity Ports are signals .
• Can represent the state of memory elements.
• Signals do not change instantaneously
Signal declaration
• signal signal_name : type;
• signal signal_name : type := initial_value;
• Signal temp : std_logic;
• signal count : bit_vector( 2 downto 0 ) := “000”;
• type state is ( idle ,s0, s1);
• signal present_state , next_state : state;
Signal declaration
• Can be explicitly declared in the declarative part of
• Package are visible in all design entities using the package
• Architecture- signals are visible inside the architecture only
• Block– signals are restricted to the block
• A port declaration in an entity is an implicit signal declaration.
– Signal is visible to all architectures assigned to that entity.
• Signal declared as ports have modes.
• But locally declared signals can be read and written.
Alias
• Declare an alternative name for
– full object or part of object
• The object can be constant, signal, variable , file.
• Example
signal path : bit_vector (15 downto 0);
alias command :bit_vector(2 downto 0) is path(15 downto 13);
alias reg_adr : bit_vector(4 downto 0) is path(12 downto 8);
alias reg_data : bit_vector(7 downto 0) is path(7 downto 0);
Variable assignment
• Replaces the current value of the variable by a new value determined by an expression.
Variable_name := expression;
• Variable assignment is instantaneous.
• := delimiter is used to define variable assignment.
Current_state := s4;
Example:Variable
entity dummy is
end dummy;
architecture var of dummy is
signal trigger, sum: integer:=0;
begin
process
variable var1: integer:=1;
variable var2: integer:=2;
variable var3: integer:=3;
begin
wait on trigger;
var1 := var2 + var3;
var2 := var1;
var3 := var2;
sum <= var1 + var2 + var3;
end process;
end var ;
Signal Assignment
• Schedules a new value for a signal to occur at some future time.
• The current value of a signal is never changed.
• Signal assignment statements can appear inside
– a process(Sequential signal assignment) or
– directly in an architecture(Concurrent signal assignment).
• Signal assignments are delayed.
X1 <= ‘1’ after 5 ns;
d2 <= ‘1’; -- Delta delay.
• <= indicates signal assignment.
Example:signal
entity dummy is
end dummy;
architecture sig of dummy is
signal trigger, sum: integer:=0;
signal sig1: integer:=1;
signal sig2: integer:=2;
signal sig3: integer:=3;
begin
process
begin
wait on trigger;
sig1 <= sig2 + sig3;
sig2 <= sig1;
sig3 <= sig2;
sum <= sig1 + sig2 + sig3;
end process;
end sig;
Signals vs Variables
• Variables are declared within process,subprograms.
• Signals are declared within architecture bodies,packages and block declaration. They are used as ports for VHDL entities.
• Signal assignment <=
• Variable assignment :=
• Variable assignment is immediate;
• Signal assignments are delayed.
Expressions and operators
• Expression are similar to C expressions
• Formula combining primaries and operators
• Primaries are
» objects,
» literal,
» functions
• Operators are
» logical
» relational
» shift
» arithmetic
VHDL Operators
• Logical and or nand nor xor xnor
• Relational = /= < <= > >=
• Shift sll srl sla sra rol ror
• Addition + - &
• Unary + -
• Multiplying * / mod rem
• Miscellaneous ** abs not
Logical operators
• AND, OR, NAND, NOR, XOR, XNOR
• Predefined for the types bit or Boolean and
for one dimensional arrays of bits and Boolean of equal length.
• Arrays
• Operation is applied between corresponding elements
• Result is an array of same length
• Operators AND .OR and XOR are associative
• Operator NAND and NOR are not associative
• Example
a NAND b NAND c ; -- is illegal
signal a,b,c : bit_vector( 2 downto 0);
signal d,e,f,g : bit_vector( 1 downto 0);
signal h,I,j,k : bit; signal l,m,n,o,p : Boolean
a <= b and c;
d <= e or f or g;
h <= (I nand j) nand k;
l <= (m xor n) and (o xor p);
• Identify the common errors
– 1) h <= I and j or k
– 2) L <= m nand n nand o nand p;
• Parenthesis is required.
– 3) a <= b and e;
• Operands must be of same size.
Relational operators
= Equality /= Inequality
< Less <= less than or equal to
> greater >= greater than or equal to
– Result of relational operator is Boolean - (true or false)
– Both operands should be same type
– = /= operates on any type except files
– Other operands work on Scalar or one dimensional arrays
– The comparison starts from left to right
– Smaller operands are patched with 0 to match the size
– Examples
bit_vector (‘1’, ‘0’,’1’) > bit_vector (‘1’,’0’,’0’);
string “We” < “Our”;
‘X’ > ‘Z’ ;
type atod is (‘A’, ‘B’, ‘C’, ‘D’);
then atod` ‘A’ < atod`‘D’;
atod`’C’ > atod`’B’;
Shift operators
• Sll Shift left logical
• srl Shift right logical
• sla Shift left arithmetic
• sra Shift right arithmetic
• rol rotate left logical
• ror rotate right logical
• Syntax is
• b <= a SLL 1;
– The left operand type is a one dimensional array whose element type is of BIT or Boolean.
– The right operand is of type integer representing the shift distance.
– The result type is same as that of the left operand type.
All left operands are bit_vectors.
“1001010”SLL 2
0101000 --shifted bits are filled with 0
“1001010”SRL 3
“0001001”.
“1001010” SLA 2
“0101000” --filled with right most bit
“1001010” SRA 3
“1111001” --filled with ‘1’ which is the left most bit.
“1001010” ROL 2
“0101010”
“1001010” ROR3
“0101001”
Arithmetic operators
• + Addition of same numeric type
• - Subtraction of same numeric type
• The left operand , the right operand and the result will be of the same numeric data type
• * Multiplication -- integer multiplication
• / Division
• Work on integers, physical and floating point
• Mod ( Modulus) works on integers
• The result will have the sign of second operand
• rem works on integers
The result will have the sign of first operand
Unary operators
• Has only one operand
• Operators + and - are predefined for all integer data types.
• The operator (-) negates its operand.
• Signal a,b : integer range -8 to 6;
• A <= -b;
Example:
entity example is
port( x,y : in bit_vector( 3 downto 0);
q1 : out bit_vector(4 downto 0)
q2,q3 : out bit_vector(3 downto 0);
q4 : out bit_vector(7 downto 0);
end example ;
architecture behv of example is
begin
process(x,y) begin
q1<= (‘0’ & x ) + ( ‘0’ & y); --addition
q2<= x-y; --subtraction
q3<=x/y; --division
q4<=x*y; --multiplication
end process;
end behv ;
Concentanation
• Predefined adding operator for any one dimensional array type.
• & Concatenation operator works on one-dimensional arrays.
– The right array is appended to the left array to form a new array
• Examples
‘0’ & ‘1’ will result “01”
“BA” & “LL” will result “BALL”
Examples:
Signal a,d : bit_vector( 3 downto 0);
signal b,c,g : bit_vector( 1 downto 0);
signal e : bit_vector(2 downto 0);
signal f,h,I :bit;
signal j,k,l : integer range 0 to 3;
a <= not b & not c;-- array & array
d <= not e ¬ f; -- array & element
g <= h & I; -- element & element
j <= k + l -- addition.
Miscellaneous operators
• abs absolute - works on any numeric type
• Not is a miscellaneous operator
– ‘0’ is treated as false
– ‘1’ is treated as true
• ** Exponential
• Integer or floating point as the left operand
• integer as the right operand
• Integer can not have negative right operand
Data types in VHDL
VHDL allows data to be represented in terms of high-level data types.These data types can represent individual wire in a circuit, or can represent collections of wires using a concept called an array.
A data type is a named set of values.
The data type of an object specifies what values the object may have and limits the kinds of operation that may be performed on objects of that type.
VHDL is a strongly typed language ie data objects of different base types cannot be assigned to one another without the use of a type conversion function.
Every data type in VHDL has a defined set of values, and a defined set of valid operations. Scalar data types have simple, single values.
Scalar data types include enumeration data types numeric data types ( integer and real) and physical data types.
Scalar types have an order, which allows relational operators to be used with them.Data objects of scalar types can only hold one value at the current simulation time.Floating point type and physical types are not supported by synthesis tools.
BIT
It can be used in any VHDL specification without any additional declarations.
Signal s1 , s2 : bit;
……..
s1 <= ‘1’;
s2 <= not s1;
……..
Any additional assignment to s1 or s2 is illegal.
STD_ULOGIC
A nine value unresolved logic is not a part of VHDL standard.It is defined in IEEE std_logic_1164 package.
It is not permitted to specify two value assignments to a signal of type std_ulogic.The values 0, 1 , L, H, Z & don’t care are supported for synthesis.The IEEE 1164 standard defines arrays of std_logic as std_logic_vector.VHDL also provides subtypes, which are defined as subsets of other types.
Anywhere a type definition can appear, a subtype definition can also appear.
The difference between a type and a subtype is that a subtype is a subset of a previously defined parent (or base) type or subtype.
All operators and functions defined for std_ulogic can be applied to std_logic.Std_logic is the industry standard type and in practice it is recommended to declare signals to be of type std_logic.A resolution function in the form of a look up table determines the values of multiple driven signals.
Data type;Integer
The integer type is a scalar type whose set of values includes integer numbers of the specified range.
Type type_name is range integer_left_bound to integer_right_bound;
type type_name is range integer_left_bound downto integer_right_bound;
All integer types have the same set of arithmetic operators defined in the package STANDARD.
Both the operands and the result are of integer type
Relational operations can also be checked on integer operands.
For logic synthesis, signals or variables of integer type should be constrained with a range.
Integer;sub type
VHDL also provides subtypes, which are defined as subsets of other types.Anywhere a type definition can appear, a subtype definition can also appear. The difference between a type and a subtype is that a subtype is a subset of a previously defined parent (or base) type or subtype.Sub type is a type with a constraint.
Positive is a integer data type whose values are a set of positive integers ( from 1 to maximum positive integer).
Natural is a integer data type whose values are a set of natural integers ( from 0 to maximum positive integer).Are defined in package standard.
Floating point
Floating point type values are used to approximate real numbers.Floating point types can be constrained. The only pre-defined floating type is real which included the range –1.0E 38 to + 1.0E 38.All floating point types have the same set of arithmetic operators namely addition , subtraction, multiplication, division, ABS and exponentiation.Floating point types are not often supported in synthesis tools.
Data types:Physical
A physical type is a numeric scalar that represents some quantity like length, time,pressure, resistance etc.The range defines the minimum and maximum values of a given quantity expressed in the base units.
The primary unit(um) serves as the base unit for representing values of the specified type.The secondary units are defined as multiplicity of primary units.Their declarations may contain only integer literals.Only relational and arithmetic operators can be used with objects of physical data type.
Physical types are not synthesizable. The VHDL standard predefines only one physical type TIME in the STANDARD package.The primary unit is femto seconds (fs).All the other secondary units are specified in terms of the base unit.
Data type: Arrays
Array is a composite object whose elements are of the same type.VHDL supports N-dimensional arrays. Array elements can be of any type. An array has an index whose value selects each element. The index range determines how many elements are in the array and their ordering (low to high, or high downto low). An index can be of any integer type.
can declare multidimensional arrays by building one-dimensional arrays where the element type is another one-dimensional array.Each of the element is indexed by one or more indices.An array may be either constrained or unconstrained.The difference between these two arrays comes from the index range in the array type definition. The array is constrained if the size of the array is constrained
A constrained array’s index range is explicitly defined; for example, an integer range (0 to 7).
Define an unconstrained array’s index range as a type, for example, INTEGER. This definition implies that the index range can consist of any contiguous subset of that type’s values.
When you declare an array variable or signal of this type, you also define its actual index range. Different declarations can have different index ranges.
There are two predefined array data types.Data type string is an array of character elements. It is used for creating text for printing.
Data type bit_vector is an array of bits. It is used to describe the data stored in a register or the data being transmitted over a parallel bus.
Type String is array ( positive range < > ) of character ;
Type bit_vector is array (natural range < > ) of bit ;
The index range is placed within parenthesis following the reserved word array. The notation < > means that the range is unconstrained.
Bit-vector
The bit_vector type is an unconstrained vector of elements of type bit.The size of a particular vector is specified during its declaration.The index can be either a ascending or descending range.
Bit_vector is an unresolved type and there can be only one assignment to an object of bit_vector type in an architecture.
Assignments to an object of bit_vector type can be performed using single element assignments, concatenation, aggregates , slices or any combination of them.Logical values for objects of the bit_vector type must be written in double quotes.
Data Type-Record
Record types are composite types in which the elements may have different types. The elements form an ordered list.An object of a record type has multiple elements of different types. Individual fields of a record can be referenced by element name.
Individual Assignments to elements
Each element id referenced by the record object name followed by a dot and elements name.Expression assigned to an element of a record must result in a value of the same type as the element.Constants in VHDL of type record are not supported for synthesis.(the initialization of records is not supported).
PROCEDURAL MODELLING
INITIAL
initial $display(“Hello Verilog");
ALWAYS
always $display("Hello Verilog");
Example:
module three_initial;
initial $display("Initial Statement 1");
initial $display("Initial Statement 2");
initial $display("Initial Statement 3");
endmodule
• creates a race condition at time 0. If it is important to
• have the statements run in a particular order, you can introduce delays to control the order in which the statements are executed.
module three_initial_with_delay;
initial #1 $display("Initial Statement 1");
initial $display("Initial Statement 2");
initial #2 $display("Initial Statement 3");
endmodule
BEGIN END BLOCKS
module initial_begin;
initial
begin
$display("Statement 1");
$display("Statement 2");
$display("Statement 3");
end
endmodule
BEGIN END BLOCKS WITH DELAY
module initial_begin_with_delay;
initial
begin
#1 $display("Statement 1");
$display("Statement 2");
#2 $display("Statement 3");
end
endmodule
MULTIPLE BEGIN-END
module initial_two_begin;
initial
begin
#1 $display("Statement 1");
$display("Statement 2");
#2 $display("Statement 3");
end
initial
begin
$display("Block 2 Statement 1");
#2 $display("Block 2 Statement 2");
#2 $display("Block 2 Statement 3");
end
endmodule
FORK-JOIN
• The fork-join block is similar to the begin-end block: It is also used to group statements.
• In begin-end blocks, the statements are sequential, and the delays are additive.
• In fork-join blocks, the statements are concurrent, and the delays are independent, or absolute from the time the fork-join block starts.
module f;
initial
fork
#1 $display("Statement 1");
$display("Statement 2");
#2 $display("Statement 3");
join
initial
fork
$display("Block 2 Statement 1");
#2 $display("Block 2 Statement 2");
#2 $display("Block 2 Statement 3");
join
endmodule
I am citing some of the books that I used during my learning, at my RTL design internship. I think any editions of the books will be good enough.
1. A VHDL Primer by Jairam Bhaskar
2. Beginner's guide to VHDL by Peter J. Ashenden (Keep in mind that there is also book called designer's guide to VHDL)
3. VHDL: Programming by Example, Douglas L. Perry
4. VHDL Handbook by Hardi Electronics
5. Digital Design: Principles and Practices by John F. Wakerly (Actually, this book gives good comparisons and examples on HDLs - VHDL, Verilog and ABEL)
6. VHDL Tutorial by Peter J. Ashenden
https://surf-vhdl.com/vhdl-syntax-web-course-surf-vhdl/
There are two types of HDL Languages are VHDL and Verilog HDL. One must be good at the concepts of Digital Logic Design before start learning the HDL.
Follow the lectures Electronics-Digital Circuits and Systems by Prof. Srinivasan, IIT Madras to become familiar with the Digital Logic Design.
Then go for the Hardware Description Language, For VHDL follow the book A VHDL Primer by J.Bhasker to learn all the basic concepts in VHDL. Additionally one can go through the Lectures Eectronics-Digital System Design by Prof. Kuruvilla Varghes, IISc, Bangalore. Refer Lecture (Lec-09 to Lec-22) for VHDL. He will cover most of the topics in VHDL with some examples.
IF you are a basic learners then try to implement the following design examples using Vhdl/verilog:
Combinational circuit examples:
-Implement basic logic gates, simulate and verify the behavior using vhdl/Verilog
-Implement half-adder circuit, simulate and verify the behavior using vhdl/Verilog
-Implement full-adder circuit, simulate and verify the behavior using vhdl/Verilog
-Implement subtractor circuit, simulate and verify the behavior using vhdl/Verilog
-Implement multiplexer, de-multiplexer, simulate and veriry the behavior using vhdl/Verilog
-Implement encoder and decoder circuit, simulate and veriry the behavior using vhdl/Verilog
-Implement binary to grey, and vice-versa, simulate and verify the behavior using vhdl/Verilog
-Implement comparator circuit, simulate and verify the behavior using vhdl/Verilog
-Implement ALU unit, simulate and verify the behavior using vhdl/Verilog
-Implement multiplier/divider, simulate and verify the behavior using vhdl/verilog
-Implement tri-state buffer, simulate and verify the behavior using vhdl/verilog
Sequential circuits examples:
-Implement D-FF circuit with synchronous reset, simulate and verify the behavior using vhdl/verilog,
* Implement D-FF circuit with asynchronous reset, simulate and verify the behavior using vhdl/verilog,
-Implement counter circuit with load, simulate and verify the behavior using vhdl/verilog,
-Implement shift register (SISO, SIPO, PISO, PIPO) using shift operator & concatenation operator, simulate and verify the behavior using vhdl/verilog,
-Implement application of shift-register, simulate and verify the behavior using vhdl/verilog,
Follow the below blogs/forums for more details:
VHDL Syntax Web-Course - Surf-VHDL State machine model
- Values stored in registers are the state of the circuit
- Combinational logic computes:
- next state
- outputs
- function of current state and inputs (Mealy machine)
- function of current state only (Moore machine)
State diagram into a logic
- counter
- flip-flops to hold state
- logic to compute next state
- clock signal controls when flip-flop memory can change
- wait just long enough for combinational logic to compute new value
- Describe FSM behavior, e.g. state diagram
- Inputs and Outputs
- States (symbolic)
- State transitions
- State diagram to state transition table, i.e. truth table
- Inputs: inputs and current state
- Outputs: outputs and next state
- State encoding
- decide on representation of states
- lots of choices
- Implementation
- flip-flop for each state bit
- synthesize combinational logic from encoded state table
- Implement simple count sequence: 000, 010, 011, 101, 110
- Derive the state transition table from the state transition diagram
- Start-up states
- at power-up, FSM may be in an used or invalid state
- design must guarantee that it (eventually) enters a valid state
- Self-starting solution
- design FSM so that all the invalid states eventually
- transition to a valid state may limit exploitation of don't cares
- Moore: outputs depend on current state only
- Mealy: outputs may depend on current state and current inputs
Design of sequential circuit can be composed of designing combinational circuit and state register. Sequential circuits are implemented in two different ways:
- Mealy Machine
- Moore Machine
Mealy Machine
In case of Mealy machine, output is a function of not only the present inputs but also past inputs. In other words we can say; in case of Mealy, both output and the next state depends on the present input and the present state.
Moore Machine
In case of Moore machine, present output is not a function of present inputs but is a function of past inputs. The next state is a function of both the present input and the present state.
In this case the output is not associated with the transition but are associated with the state unlike the Mealy machine. This is because the output “O” is a function of present state (PS) and independent of present input “I”.
Of-course present input I influences the next state (NS) and that’s how it is going to influence the output but there is a time lag between the input and output. The present inputs are going to influence the outputs that are going to come after the next clock.
FINITE STATE MACHINES
Moore machines are useful because their output signals are synchronized with the clock.
No matter when input signals reach the Moore Machine, its output signals will not change until the rising
edge of the next clock cycle. This is very important to avoid setup timing violations.
For example, if a Mealy machine’s input signal(s) changes sometime in the middle of a clock cycle, one or more of its outputs and next state signals may change some time later. “Some time later” might come after the setup time threshold for the next rising edge.
If this happens, the registers that will hold the FSMs next state may receive garbage, or just incorrect inputs. Obviously, this amounts to a bug(s) in FSM
The tradeoff in using the Moore machine is that sometimes the Moore machine will require more states to specify its function than the Mealy machine. This is because in a Moore machine, output signals are only dependent on the current state.
In a Mealy machine, outputs are dependent on both the current state and the inputs.
The Mealy machine allows you to specify different output behavior for a single state.
We will need a way to express the following in Verilog:
1. A state encoding for each state.
2. A mechanism for keeping track of the current state.
3. Transitions from state to state.
4. Output values based on the current state.
We will construct the FSM one step at a time.
1. Creating a State Encoding
We will create our state encoding with Verilog parameters. Parameters are symbolic constants with
either global (given by the Verilog keyword parameter) or module (localparam) scope.
Because we only want our state encoding to be visible to the module in which we will write the FSM, we will use the latter: localparam.
localparam STATE_Initial = 3’d0 ,
STATE_1 = 3’d1 ,
STATE_2 = 3’d2 ,
STATE_3 = 3’d3 ,
STATE_4 = 3’d4;
In Program 1, the 3’d notation indicates that the number specified is in the decimal radix. If we were
to use 3’b, the encoding would look like that shown in Program 2. Both implementations are equivelent.
Base 10, or 3’d, is typically easier to read.
Because this FSM has 5 total states, we must allocate 3 bits to specify the encoding (hence 3’d
as opposed to 2’d or 4’d. This is extremely important. If you specify too few bits for your state
encoding, Verilog will not warn you. In fact, when synthesized, each state will only get as many bits as you provide. For example, if STATE_4 was specified like this: STATE_4 = 2’d4, STATE_4 would be specified as 00, the bottem 2 bits of what was intended, namely 100.
PROGAM2
localparam STATE_Initial = 3’b000 ,
STATE_1 = 3’b001 ,
STATE_2 = 3’b010 ,
STATE_3 = 3’b011 ,
STATE_4 = 3’ b100 ;
As 3 bits can specify a total of 8 states (0-7), our encoding specifies 3 potential states not specified
as being actual states.
There are several ways of dealing with this problem:
1. Ignore it, and always press Reset as a way of initializing the FSM.
2. Specify these states, and make non-conditional transitions from them to the STATE_Initial.
To reduce ambiguity, we will choose the second option, which makes our final state encoding that
shown in Program 3.
localparam STATE_Initial = 3’d0 ,
STATE_1 = 3’d1 ,
STATE_2 = 3’d2 ,
STATE_3 = 3’d3 ,
STATE_4 = 3’d4 ,
STATE_5_PlaceHolder = 3’d5 ,
STATE_6_PlaceHolder = 3’d6 ,
STATE_7_PlaceHolder = 3’d7;
This is a simple encoding: STATE_Initial is assigned 0, STATE_1 is assigned 1, etc. This is not optimal if state minimization can be performed on the FSM .
We do not recommend applying state minimization techniques by hand, however. They have the tendancy to introduce bugs and create cryptic FSMs that cannot be easily understood by human readers. This defeats one of the large pros of Verilog: human readability. Furthermore, the Synthesis tools that ‘compile’ an FSM, written in Verilog, perform state minimization automatically. Only perform state minimization manually to the extent that the function of the FSM remains clear.
The first option is to instantiate a module that acts as a register and use its output value as our current state. Alternatively, we can create a reg element of the appropriate width and use its value as our current state. We will use the second method for the remainder of this tutorial, out of personal preference. As such, we will store the current state as depicted reg [2:0] CurrentState ;
Module instantiation
Register #( . Width ( ...) )
SentReg (. Clock ( ...) , // Input port
Reset ( ...) , // Input port
Set( ...) , // Input port
Enable (...) , // Input port
In( ...) , // Input port
Out( ...) ); // OUTPUT port
Module declaration
module MyModule (In , Out);
parameter Width = 32;
input [Width -1:0] In , Out;
endmodule
wire elements are simple wires (or busses/bit-vectors of arbitrary width) in Verilog designs.
The following are syntax rules when using wires:
1. wire elements are used to connect input and output ports of a module instantiation together with
some other element in your design.
2. wire elements are used as inputs and outputs within an actual module declaration.
3. wire elements must be driven by something, and cannot store a value without being driven. In
other words, wire elements are a stateless way of connecting two peices in a Verilog-based design.
4. wire elements cannot be used as the left-hand side of an = or <= sign in an always@ block.
5. wire elements are the only legal type on the left-hand side of an assign statement.
6. wire elements can only be used to model combinational logic.
Legal uses of the wire element
wire A, B, C, D, E; // simple 1-bit wide wires
wire [8:0] Wide ; // a 9-bit wide wire
reg I;
assign A = B & C; // using a wire with an assign statement
always @(B or C) begin
I = B | C; // using wires on the right - hand side of an always@
// assignment
end
mymodule MyModule (. In (D), // using a wire as the input of a module
Out(E)); // using a wire as the output of a module
reg Elements (Combinational and Sequential logic)
reg are similar to wires, but can be used to store information (‘state’) like registers. The following are
syntax rules when using reg elements.
1. reg elements can be connected to the input port of a module instantiation. Note that reg cannot
connect to the output port of a module instantiation.
2. reg elements can be used as outputs within an actual module declaration. Note that reg cannot
be used as inputss within an actual module declaration.
3. reg is the only legal type on the left-hand side of an always@ block = or <= sign.
4. reg is the only legal type on the left-hand side of an initial block = sign (used in Test Benches).
5. reg cannot be used on the left-hand side of an assign statement.
6. reg can be used to create registers when used in conjunction with always@(posedge Clock) blocks.
7. reg can, therefore, be used to create both combinational and sequential logic.
wire A, B;
reg I, J, K; // simple 1-bit wide reg elements
reg [8:0] Wide ; // a 9-bit wide reg element
always @(A or B) begin
I = A | B; // using a reg as the left - hand side of an always@
// assignment
end
initial begin // using a reg in an initial block
J = 1’b1;
#1
J = 1’b0;
end
always @( posedge Clock ) begin
K <= I; // using a reg to create a positive -edge - triggered register
end
wire and reg elements can be used interchangably in certain situations:
1. Both can appear on the right-hand side of assign statements and always@ block = or <= signs.
2. Both can be connected to the input ports of module instantiations.
Transitioning from State to State
After we have established our state encoding and a means of storing the current state value (which will henceforth be referred to as CurrentState), our next task is to create a way for the FSM to actually change state, and for it to choose how to change state. This material requires that you be comfortable with always@ blocks
always@ Blocks
always@ blocks are used to describe events that should happen under certain conditions. always@ blocks are always followed by a set of parentheses, a begin, some code, and an end. Program 9 shows a skeleton always@ block.
always @( ... sensitivity list ... ) begin
elements ...
end
Elements in an always@ block are set/updated in sequentially and in parallel, depending on the type
of assignment used. There are two types of assignments: <= (non-blocking) and = (blocking).
Non-blocking assignments happen in parallel. In other words, if an always@ block contains multiple <=
assignments, which are literally written in Verilog sequentially, you should think of all of the assignments being set at exactly the same time
always @( ... sensitivity list ... ) begin
B <= A;
C <= B;
D <= C;
end
specifies a circuit that reads “when the sensitivity list is satisfied, B gets A’s value, C gets B’s old value, and D gets C’s old value.” The key here is that C gets B’s old value, etc (read: think OLD value!. This ensures that C is not set to A, as A is B’s new value, at the instant of the always@ block’s
execution. Non-blocking assignments are used when specifying sequential2 logic
Blocking assignments happen sequentially. In other words, if an always@ block contains multiple =
assignments, you should think of the assignments being set one after another.
always @( ... sensitivity list ... ) begin
B = A;
C = B;
D = C;
end
“when the sensitivity list is satisfied, B gets A, C gets B, and D gets C.” But, by the time C gets B, B has been set to A. Likewise, by the time D gets C, C has been set to B, which, as we stated above, has been set to A. This always@ block turns B, C, and D into A. Blocking assignments are used when specifying combinational logic
always@(posedge Clock) (“always at the positive edge of the clock”) or always@(negedge Clock) (“always
at the negative edge of the clock”) blocks are used to describe Sequential Logic, or Registers.
Only <= (non-blocking) assignments should be used in an always@(posedge Clock) block. Never use =
(blocking) assignments in always@(posedge Clock) blocks.
Only use always@(posedge Clock) blocks when you want to infer an element(s) that changes its value at the positive or negative edge of the clock.
always @( posedge Clock ) begin
B <= A;
C <= B;
D <= C;
end
always@( * ) blocks are used to describe Combinational Logic, or Logic Gates. Only = (blocking)
assignments should be used in an always@( * ) block. Never use <= (non-blocking) assignments in
always@( * ) blocks. Only use always@( * ) block when you want to infer an element(s) that changes
its value as soon as one or more of its inputs change.
Always use ‘*’ (star) for your sensitivity list in always@( * ) blocks. The sensitivity list specifies
which signals should trigger the elements inside the always@ block to be updated.
“when A or B change values, update the value of every element inside the always@( * ) block. In this case, the only element inside the always@( * ) block is C, which in this case is assigned the and of A and B. A very common bug is to introduce an incomplete sensitivity list. In other words, ‘*’ sets the sensitivity list to any values that can have an impact on a value(s) determined by the always@( * ) block. ‘*’ provides a bug-free shorthand for creating complete sensitivity lists.
The following are some easy-to-make mistakes in Verilog that can have a dramatic [and undesired]
effect on a circuit
Consider the shift register from Figure .
If you place = assignments inside of an always@(posedge Clock) block to produce the shift register, you instead get the parallel registers shown in Figure and Program .
we might also get one register, whose output is tied to B, C and D. Both possible outcomes are equivelent. These circuit make sense, but don’t create shift registers! (As shift registers are common construct, we assume that you wanted to create a shift register)
always @( posedge Clock ) begin
B = A;
C = B;
D = C;
end
We place <= assignments inside of always@(* ) is less pronounced. In this case, just consider what type of circuit you want to create: do you want all statements to be executed in parallel or in ‘sequence.
In the always@( * ), the distinction between <= and = is sometimes very subtle, as the point of always@
( * ) is to trigger at indefinite times (unlike the very definite posedge Clock).
We recommend =in conjunction with always@( * ) to establish good convention (as = was originally meant to be associated with combinational logic).
always @( * ) begin
B <= A;
C <= B;
D <= C;
end
An always@( * ) block that will not generate latches
wire Trigger , Pass ;
reg A, C;
always @( * ) begin
A = 1’b0;
C = 1’b1;
if ( Trigger ) begin
A = Pass ;
C = Pass ;
end
FINITE STATE MACHINES
Moore machines are useful because their output signals are synchronized with the clock.
No matter when input signals reach the Moore Machine, its output signals will not change until the rising
edge of the next clock cycle. This is very important to avoid setup timing violations.
For example, if a Mealy machine’s input signal(s) changes sometime in the middle of a clock cycle, one or more of its outputs and next state signals may change some time later. “Some time later” might come after the setup time threshold for the next rising edge.
If this happens, the registers that will hold the FSMs next state may receive garbage, or just incorrect inputs. Obviously, this amounts to a bug(s) in FSM
The tradeoff in using the Moore machine is that sometimes the Moore machine will require more states to specify its function than the Mealy machine. This is because in a Moore machine, output signals are only dependent on the current state. In a Mealy machine, outputs are dependent on both the current state and the inputs.
The Mealy machine allows you to specify different output behavior for a single state.
We will need a way to express the following in Verilog:
1. A state encoding for each state.
2. A mechanism for keeping track of the current state.
3. Transitions from state to state.
4. Output values based on the current state.
We will construct the FSM one step at a time.
1. Creating a State Encoding
We will create our state encoding with Verilog parameters.
Parameters are symbolic constants with either global (given by the Verilog keyword parameter) or module (localparam) scope. Because we only want our state encoding to be visible to the module in which we will write the FSM, we will use the latter: localparam.
localparam STATE_Initial = 3’d0 ,
STATE_1 = 3’d1 ,
STATE_2 = 3’d2 ,
STATE_3 = 3’d3 ,
STATE_4 = 3’d4;
In Program 1, the 3’d notation indicates that the number specified is in the decimal radix. If we were
to use 3’b, the encoding would look like that shown in Program 2. Both implementations are equivelent.
Base 10, or 3’d, is typically easier to read.
Because this FSM has 5 total states, we must allocate 3 bits to specify the encoding (hence 3’d
as opposed to 2’d or 4’d. This is extremely important. If you specify too few bits for your state
encoding, Verilog will not warn you. In fact, when synthesized, each state will only get as many bits as
you provide. For example, if STATE_4 was specified like this: STATE_4 = 2’d4, STATE_4 would be specified
as 00, the bottem 2 bits of what was intended, namely 100.
PROGAM2
localparam STATE_Initial = 3’b000 ,
STATE_1 = 3’b001 ,
STATE_2 = 3’b010 ,
STATE_3 = 3’b011 ,
STATE_4 = 3’ b100 ;
As 3 bits can specify a total of 8 states (0-7), our encoding specifies 3 potential states not specified
as being actual states.
There are several ways of dealing with this problem:
1. Ignore it, and always press Reset as a way of initializing the FSM.
2. Specify these states, and make non-conditional transitions from them to the STATE_Initial.
To reduce ambiguity, we will choose the second option, which makes our final state encoding that
shown in Program 3.
localparam STATE_Initial = 3’d0 ,
STATE_1 = 3’d1 ,
STATE_2 = 3’d2 ,
STATE_3 = 3’d3 ,
STATE_4 = 3’d4 ,
STATE_5_PlaceHolder = 3’d5 ,
STATE_6_PlaceHolder = 3’d6 ,
STATE_7_PlaceHolder = 3’d7;
This is a simple encoding: STATE_Initial is assigned 0, STATE_1 is assigned 1, etc. This is not optimal if state minimization can be performed on the FSM .
We do not recommend applying state minimization techniques by hand, however. They have the tendancy to introduce bugs and create cryptic FSMs that cannot be easily understood by human readers. This defeats one of the large pros of Verilog: human readability. Furthermore, the Synthesis tools that ‘compile’ an FSM, written in Verilog, perform state minimization automatically. Only perform state minimization manually to the extent that the function of the FSM remains clear.
The first option is to instantiate a module that acts as a register and use its output value as our current state. Alternatively, we can create a reg element of the appropriate width and use its value as our current state. We will use the second method for the remainder of this tutorial, out of personal preference. As such, we will store the current state as depicted reg [2:0] CurrentState ;
Module instantiation
Register #( . Width ( ...) )
SentReg (. Clock ( ...) , // Input port
Reset ( ...) , // Input port
Set( ...) , // Input port
Enable (...) , // Input port
In( ...) , // Input port
Out( ...) ); // OUTPUT port
Module declaration
module MyModule (In , Out);
parameter Width = 32;
input [Width -1:0] In , Out;
endmodule
wire elements are simple wires (or busses/bit-vectors of arbitrary width) in Verilog designs.
The following are syntax rules when using wires:
1. wire elements are used to connect input and output ports of a module instantiation together with
some other element in your design.
2. wire elements are used as inputs and outputs within an actual module declaration.
3. wire elements must be driven by something, and cannot store a value without being driven. In
other words, wire elements are a stateless way of connecting two peices in a Verilog-based design.
4. wire elements cannot be used as the left-hand side of an = or <= sign in an always@ block.
5. wire elements are the only legal type on the left-hand side of an assign statement.
6. wire elements can only be used to model combinational logic.
Legal uses of the wire element
wire A, B, C, D, E; // simple 1-bit wide wires
wire [8:0] Wide ; // a 9-bit wide wire
reg I;
assign A = B & C; // using a wire with an assign statement
always @(B or C) begin
I = B | C; // using wires on the right - hand side of an always@
// assignment
end
mymodule MyModule (. In (D), // using a wire as the input of a module
Out(E)); // using a wire as the output of a module
reg Elements (Combinational and Sequential logic)
reg are similar to wires, but can be used to store information (‘state’) like registers. The following are
syntax rules when using reg elements.
1. reg elements can be connected to the input port of a module instantiation. Note that reg cannot
connect to the output port of a module instantiation.
2. reg elements can be used as outputs within an actual module declaration. Note that reg cannot
be used as inputss within an actual module declaration.
3. reg is the only legal type on the left-hand side of an always@ block = or <= sign.
4. reg is the only legal type on the left-hand side of an initial block = sign (used in Test Benches).
5. reg cannot be used on the left-hand side of an assign statement.
6. reg can be used to create registers when used in conjunction with always@(posedge Clock) blocks.
7. reg can, therefore, be used to create both combinational and sequential logic.
wire A, B;
reg I, J, K; // simple 1-bit wide reg elements
reg [8:0] Wide ; // a 9-bit wide reg element
always @(A or B) begin
I = A | B; // using a reg as the left - hand side of an always@
// assignment
end
initial begin // using a reg in an initial block
J = 1’b1;
#1
J = 1’b0;
end
always @( posedge Clock ) begin
K <= I; // using a reg to create a positive -edge - triggered register
end
wire and reg elements can be used interchangably in certain situations:
1. Both can appear on the right-hand side of assign statements and always@ block = or <= signs.
2. Both can be connected to the input ports of module instantiations.
Transitioning from State to State
After we have established our state encoding and a means of storing the current state value (which will
henceforth be referred to as CurrentState), our next task is to create a way for the FSM to actually
change state, and for it to choose how to change state. This material requires that you be comfortable
with always@ blocks
always@ Blocks
always@ blocks are used to describe events that should happen under certain conditions. always@ blocks
are always followed by a set of parentheses, a begin, some code, and an end. Program 9 shows a skeleton always@ block.
always @( ... sensitivity list ... ) begin
elements ...
end
Elements in an always@ block are set/updated in sequentially and in parallel, depending on the type
of assignment used. There are two types of assignments: <= (non-blocking) and = (blocking).
Non-blocking assignments happen in parallel. In other words, if an always@ block contains multiple <=
assignments, which are literally written in Verilog sequentially, you should think of all of the assignments
being set at exactly the same time
always @( ... sensitivity list ... ) begin
B <= A;
C <= B;
D <= C;
end
specifies a circuit that reads “when the sensitivity list is satisfied, B gets A’s value, C gets B’s old value, and D gets C’s old value.” The key here is that C gets B’s old value, etc (read: think OLD value!. This ensures that C is not set to A, as A is B’s new value, at the instant of the always@ block’s
execution. Non-blocking assignments are used when specifying sequential2 logic
Blocking assignments happen sequentially. In other words, if an always@ block contains multiple =
assignments, you should think of the assignments being set one after another.
always @( ... sensitivity list ... ) begin
B = A;
C = B;
D = C;
end
“when the sensitivity list is satisfied, B gets A, C gets B, and D gets C.” But, by the time C gets B, B has been set to A. Likewise, by the time D gets C, C has been set to B, which, as we stated above, has been set to A. This always@ block turns B, C, and D into A. Blocking assignments are used when specifying combinational logic
always@(posedge Clock) (“always at the positive edge of the clock”) or always@(negedge Clock) (“always
at the negative edge of the clock”) blocks are used to describe Sequential Logic, or Registers.
Only <= (non-blocking) assignments should be used in an always@(posedge Clock) block. Never use =
(blocking) assignments in always@(posedge Clock) blocks.
Only use always@(posedge Clock) blocks when you want to infer an element(s) that changes its value at the positive or negative edge of the clock.
always @( posedge Clock ) begin
B <= A;
C <= B;
D <= C;
end
always@( * ) blocks are used to describe Combinational Logic, or Logic Gates. Only = (blocking)
assignments should be used in an always@( * ) block. Never use <= (non-blocking) assignments in
always@( * ) blocks. Only use always@( * ) block when you want to infer an element(s) that changes
its value as soon as one or more of its inputs change.
Always use ‘*’ (star) for your sensitivity list in always@( * ) blocks. The sensitivity list specifies
which signals should trigger the elements inside the always@ block to be updated.
“when A or B change values, update the value of every element inside the always@( * ) block. In this case, the only element inside the always@( * ) block is C, which in this case is assigned the and of A and B. A very common bug is to introduce an incomplete sensitivity list. In other words, ‘*’ sets the sensitivity list to any values that can have an impact on a value(s) determined by the always@( * ) block. ‘*’ provides a bug-free shorthand for creating complete sensitivity lists.
The following are some easy-to-make mistakes in Verilog that can have a dramatic [and undesired]
effect on a circuit
Consider the shift register
If you place = assignments inside of an always@(posedge Clock) block to produce the shift register, you instead get the parallel registers shown in Figure and Program .
we might also get one register, whose output is tied to B, C and D. Both possible outcomes are equivelent. These circuit make sense, but don’t create shift registers! (As shift registers are common construct, we assume that you wanted to create a shift register)
always @( posedge Clock ) begin
B = A;
C = B;
D = C;
end
We place <= assignments inside of always@(* ) is less pronounced. In this case, just consider what type of circuit you want to create: do you want all statements to be executed in parallel or in ‘sequence.
In the always@( * ), the distinction between <= and = is sometimes very subtle, as the point of always@
( * ) is to trigger at indefinite times (unlike the very definite posedge Clock).
We recommend =in conjunction with always@( * ) to establish good convention (as = was originally meant to be associated with combinational logic).
always @( * ) begin
B <= A;
C <= B;
D <= C;
end
An always@( * ) block that will not generate latches
wire Trigger , Pass ;
reg A, C;
always @( * ) begin
A = 1’b0;
C = 1’b1;
if ( Trigger ) begin
A = Pass ;
C = Pass ;
end
72Hz
clock generation in verilog
------------------------------------
It depends on whether
you’re trying to create a simulated circuit or one for actual synthesis, say, in
an FPGA.
For a simulated circuit, it’s as easy as declaring a register, and then
toggling it (e.g. x = ~x), followed by a delay of 27778 microseconds, which is
half the period of a 72 hz rate ( i.e. “#27777” after having previously
declared ‘timescale 1us) in a loop. The key is that the simulator uses the
timescale as units for the specified delays, and does the hard work for you of
deciding exactly when the next statement should execute.
However, creating real delays in a circuit requires understanding of the
hardware. The typical way to create Verilog that would produce a 72hz signal in
this case would be to take a clock signal of a known (likely higher) frequency
coming from an external source or onboard clock generator, and then create a
counter to divide down that clock. When the count reaches the right number,
toggle the output and there’s your 72hz clock. For example, let’s assume clk is
1Mhz:
reg (14:0) count; //Need 15 bits to count this high
reg out;
always @(posedge clk)
begin
if (count == 27776) //since started at zero...
begin
count <= 0;
out <= ~out;
end
else
begin
count <= count + 1;
out <= out;
end
end
--------------------------------------------------------------------------------------------------------------------------
Verilog code for Clock domain
crossing
module clk_2_cross ( clock1, clock2,
rst_n, data_in, data_out);
input clock1;
input clock2;
input rst_n;
output data_out;
input data_in;
reg data_out_meta;
reg [1:0] data_out_reg;
// Assign statements
assign data_out = data_out_reg[1];
// Always block to declare
synchronous logic from source clock domain
always @ (posedge clock1)
begin
data_out_meta <= data_in;
end
// Always block to declare synchronous
logic in destination clock domain
always @ (posedge clock2 or negedge
rst_n)
begin
if (! rst_n)
data_out_reg
<= 'b0;
else
// Implement shift
register for two flops.
data_out_reg <=
{data_out_reg[0], data_out_meta};
end
endmodule
// Note: Above shift register can also
be implemented // like below:
// data_out_reg[0] <=
data_out_meta;
// data_out_reg[1] <=
data_out_reg[0];
====================================================================
Verilog code for
flip-flop with a positive-edge clock.
module flop (clk, d, q);
input clk, d;
output q;
reg q;
always @(posedge clk)
begin
q <= d;
end
endmodule
Verilog code for a
flip-flop with a negative-edge clock and asynchronous clear.
module flop (clk, d, clr, q);
input clk, d, clr;
output q;
reg q;
always @(negedge clk or posedge clr)
begin
if (clr)
q <= 1’b0;
else
q <= d;
end
endmodule
Verilog code for the
flip-flop with a positive-edge clock and synchronous set.
module flop (clk, d, s, q);
input clk, d, s;
output q;
reg q;
always @(posedge clk)
begin
if (s)
q <= 1’b1;
else
q <= d;
end
endmodule
Verilog code for the
flip-flop with a positive-edge clock and clock enable.
module flop (clk, d, ce, q);
input clk, d, ce;
output q;
reg q;
always @(posedge clk)
begin
if (ce)
q <= d;
end
endmodule
Verilog code for a
4-bit register with a positive-edge clock, asynchronous set and clock enable.
module flop (clk, d, ce, pre, q);
input clk, ce, pre;
input [3:0] d;
output [3:0] q;
reg [3:0] q;
always @(posedge clk or posedge pre)
begin
if (pre)
q <= 4’b1111;
else if (ce)
q <= d;
end
endmodule
Verilog code for a
latch with a positive gate.
module latch (g, d, q);
input g, d;
output q;
reg q;
always @(g or d)
begin
if (g)
q <= d;
end
endmodule
Verilog code for a
latch with a positive gate and an asynchronous clear.
module latch (g, d, clr, q);
input g, d, clr;
output q;
reg q;
always @(g or d or clr)
begin
if (clr)
q <= 1’b0;
else if (g)
q <= d;
end
endmodule
Verilog code for a
4-bit latch with an inverted gate and an asynchronous preset.
module latch (g, d, pre, q);
input g, pre;
input [3:0] d;
output [3:0] q;
reg [3:0] q;
always @(g or d or pre)
begin
if (pre)
q <= 4’b1111;
else if (~g)
q <= d;
end
endmodule
Following is Verilog code for a
tristate element using a combinatorial process and always block.
module three_st (t, i, o);
input t, i;
output o;
reg o;
always @(t or i)
begin
if (~t)
o = i;
else
o = 1’bZ;
end
endmodule
Following is the Verilog code for a
tristate element using a concurrent assignment.
module three_st (t, i, o);
input t, i;
output o;
assign o = (~t) ? i: 1’bZ;
endmodule
Following is the Verilog code for a
4-bit unsigned up counter with asynchronous clear.
module counter (clk, clr, q);
input clk, clr;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk or posedge clr)
begin
if (clr)
tmp <= 4’b0000;
else
tmp <= tmp + 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit unsigned down counter with synchronous set.
module counter (clk, s, q);
input clk, s;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk)
begin
if (s)
tmp <= 4’b1111;
else
tmp <= tmp - 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit unsigned up counter with an asynchronous load from the primary input.
module counter (clk, load, d, q);
input clk, load;
input [3:0] d;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk or posedge load)
begin
if (load)
tmp <= d;
else
tmp <= tmp + 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit unsigned up counter with a synchronous load with a constant.
module counter (clk, sload, q);
input clk, sload;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk)
begin
if (sload)
tmp <= 4’b1010;
else
tmp <= tmp + 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit unsigned up counter with an asynchronous clear and a clock enable.
module counter (clk, clr, ce, q);
input clk, clr, ce;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk or posedge clr)
begin
if (clr)
tmp <= 4’b0000;
else if (ce)
tmp <= tmp + 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit unsigned up/down counter with an asynchronous clear.
module counter (clk, clr, up_down, q);
input clk, clr, up_down;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk or posedge clr)
begin
if (clr)
tmp <= 4’b0000;
else if (up_down)
tmp <= tmp + 1’b1;
else
tmp <= tmp - 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit signed up counter with an asynchronous reset.
module counter (clk, clr, q);
input
clk, clr;
output signed [3:0] q;
reg signed [3:0] tmp;
always @ (posedge clk or posedge clr)
begin
if (clr)
tmp <= 4’b0000;
else
tmp <= tmp + 1’b1;
end
assign q = tmp;
endmodule
Following is the Verilog code for a
4-bit signed up counter with an asynchronous reset and a modulo maximum.
module counter (clk, clr, q);
parameter MAX_SQRT = 4, MAX = (MAX_SQRT*MAX_SQRT);
input
clk, clr;
output [MAX_SQRT-1:0] q;
reg [MAX_SQRT-1:0] cnt;
always @ (posedge clk or posedge clr)
begin
if (clr)
cnt <= 0;
else
cnt <= (cnt + 1) %MAX;
end
assign q = cnt;
endmodule
Following is the Verilog code for a
4-bit unsigned up accumulator with an asynchronous clear.
module accum (clk, clr, d, q);
input clk, clr;
input [3:0] d;
output [3:0] q;
reg [3:0] tmp;
always @(posedge clk or posedge clr)
begin
if (clr)
tmp <= 4’b0000;
else
tmp <= tmp + d;
end
assign q = tmp;
endmodule
Following is the Verilog code for an
8-bit shift-left register with a positive-edge clock, serial in and serial out.
module shift (clk, si, so);
input clk,si;
output so;
reg [7:0] tmp;
always @(posedge clk)
begin
tmp <= tmp << 1;
tmp[0] <= si;
end
assign so = tmp[7];
endmodule
Following is the Verilog code for an
8-bit shift-left register with a negative-edge clock, a clock enable, a serial
in and a serial out.
module shift (clk, ce, si, so);
input clk, si, ce;
output so;
reg [7:0] tmp;
always @(negedge clk)
begin
if (ce) begin
tmp <= tmp << 1;
tmp[0] <= si;
end
end
assign so = tmp[7];
endmodule
Following is the Verilog code for an
8-bit shift-left register with a positive-edge clock, asynchronous clear,
serial in and serial out.
module shift (clk, clr, si, so);
input clk, si, clr;
output so;
reg [7:0] tmp;
always @(posedge clk or posedge clr)
begin
if (clr)
tmp <= 8’b00000000;
else
tmp <= {tmp[6:0], si};
end
assign so = tmp[7];
endmodule
Following is the Verilog code for an
8-bit shift-left register with a positive-edge clock, a synchronous set, a
serial in and a serial out.
module shift (clk, s, si, so);
input clk, si, s;
output so;
reg [7:0] tmp;
always @(posedge clk)
begin
if (s)
tmp <= 8’b11111111;
else
tmp <= {tmp[6:0], si};
end
assign so = tmp[7];
endmodule
Following is the Verilog code for an
8-bit shift-left register with a positive-edge clock, a serial in and a
parallel out.
module shift (clk, si, po);
input clk, si;
output [7:0] po;
reg [7:0] tmp;
always @(posedge clk)
begin
tmp <= {tmp[6:0], si};
end
assign po = tmp;
endmodule
Following is the Verilog code for an
8-bit shift-left register with a positive-edge clock, an asynchronous parallel
load, a serial in and a serial out.
module shift (clk, load, si, d, so);
input clk, si, load;
input [7:0] d;
output so;
reg [7:0] tmp;
always @(posedge clk or posedge load)
begin
if (load)
tmp <= d;
else
tmp <= {tmp[6:0], si};
end
assign so = tmp[7];
endmodule
Following is the Verilog code for an
8-bit shift-left register with a positive-edge clock, a synchronous parallel
load, a serial in and a serial out.
module shift (clk, sload, si, d, so);
input clk, si, sload;
input [7:0] d;
output so;
reg [7:0] tmp;
always @(posedge clk)
begin
if (sload)
tmp <= d;
else
tmp <= {tmp[6:0], si};
end
assign so = tmp[7];
endmodule
Following is the Verilog code for an
8-bit shift-left/shift-right register with a positive-edge clock, a serial in
and a serial out.
module shift (clk, si, left_right, po);
input clk, si, left_right;
output po;
reg [7:0] tmp;
always @(posedge clk)
begin
if (left_right == 1’b0)
tmp <= {tmp[6:0], si};
else
tmp <= {si, tmp[7:1]};
end
assign po = tmp;
endmodule
Following is the Verilog code for a
4-to-1 1-bit MUX using an If statement.
module mux (a, b, c, d, s, o);
input a,b,c,d;
input [1:0] s;
output o;
reg o;
always @(a or b or c or d or s)
begin
if (s == 2’b00)
o = a;
else if (s == 2’b01)
o = b;
else if (s == 2’b10)
o = c;
else
o = d;
end
endmodule
Following is the Verilog Code for a
4-to-1 1-bit MUX using a Case statement.
module mux (a, b, c, d, s, o);
input a, b, c, d;
input [1:0] s;
output o;
reg o;
always @(a or b or c or d or s)
begin
case (s)
2’b00 : o = a;
2’b01 : o = b;
2’b10 : o = c;
default : o = d;
endcase
end
endmodule
Following is the Verilog code for a
3-to-1 1-bit MUX with a 1-bit latch.
module mux (a, b, c, d, s, o);
input a, b, c, d;
input [1:0] s;
output o;
reg o;
always @(a or b or c or d or s)
begin
if (s == 2’b00)
o = a;
else if (s == 2’b01)
o = b;
else if (s == 2’b10)
o = c;
end
endmodule
Following is the Verilog code for a
1-of-8 decoder.
module mux (sel, res);
input [2:0] sel;
output [7:0] res;
reg [7:0] res;
always @(sel or res)
begin
case (sel)
3’b000 : res = 8’b00000001;
3’b001 : res = 8’b00000010;
3’b010 : res = 8’b00000100;
3’b011 : res = 8’b00001000;
3’b100 : res = 8’b00010000;
3’b101 : res = 8’b00100000;
3’b110 : res = 8’b01000000;
default : res = 8’b10000000;
endcase
end
endmodule
Following Verilog code leads to the
inference of a 1-of-8 decoder.
module mux (sel, res);
input [2:0] sel;
output [7:0] res;
reg [7:0] res;
always @(sel or res) begin
case (sel)
3’b000 : res = 8’b00000001;
3’b001 : res = 8’b00000010;
3’b010 : res = 8’b00000100;
3’b011 : res = 8’b00001000;
3’b100 : res = 8’b00010000;
3’b101 : res = 8’b00100000;
// 110 and 111 selector values are unused
default : res = 8’bxxxxxxxx;
endcase
end
endmodule
Following is the Verilog code for a
3-bit 1-of-9 Priority Encoder.
module priority (sel, code);
input [7:0] sel;
output [2:0] code;
reg [2:0] code;
always @(sel)
begin
if (sel[0])
code = 3’b000;
else if (sel[1])
code = 3’b001;
else if (sel[2])
code = 3’b010;
else if (sel[3])
code = 3’b011;
else if (sel[4])
code = 3’b100;
else if (sel[5])
code = 3’b101;
else if (sel[6])
code = 3’b110;
else if (sel[7])
code = 3’b111;
else
code = 3’bxxx;
end
endmodule
Following is the Verilog code for a
logical shifter.
module lshift (di, sel, so);
input [7:0] di;
input [1:0] sel;
output [7:0] so;
reg [7:0] so;
always @(di or sel)
begin
case (sel)
2’b00 : so = di;
2’b01 : so = di << 1;
2’b10 : so = di << 2;
default : so = di << 3;
endcase
end
endmodule
Following is the Verilog code for an
unsigned 8-bit adder with carry in.
module adder(a, b, ci, sum);
input [7:0] a;
input [7:0] b;
input ci;
output [7:0] sum;
assign sum = a + b + ci;
endmodule
Following is the Verilog code for an
unsigned 8-bit adder with carry out.
module adder(a, b, sum, co);
input [7:0] a;
input [7:0] b;
output [7:0] sum;
output co;
wire [8:0] tmp;
assign tmp = a + b;
assign sum = tmp [7:0];
assign co = tmp [8];
endmodule
Following is the Verilog code for an
unsigned 8-bit adder with carry in and carry out.
module adder(a, b, ci, sum, co);
input ci;
input [7:0] a;
input [7:0] b;
output [7:0] sum;
output co;
wire [8:0] tmp;
assign tmp = a + b + ci;
assign sum = tmp [7:0];
assign co = tmp [8];
endmodule
Following is the Verilog code for an
unsigned 8-bit adder/subtractor.
module addsub(a, b, oper, res);
input oper;
input [7:0] a;
input [7:0] b;
output [7:0] res;
reg [7:0] res;
always @(a or b or oper)
begin
if (oper == 1’b0)
res = a + b;
else
res = a - b;
end
endmodule
Following is the Verilog code for an
unsigned 8-bit greater or equal comparator.
module compar(a, b, cmp);
input [7:0] a;
input [7:0] b;
output cmp;
assign cmp = (a >= b) ? 1’b1 : 1’b0;
endmodule
Following is the Verilog code for an
unsigned 8x4-bit multiplier.
module compar(a, b, res);
input [7:0] a;
input [3:0] b;
output [11:0] res;
assign res = a * b;
endmodule
Following Verilog template shows the
multiplication operation placed outside the always block and the pipeline
stages represented as single registers.
module mult(clk, a, b, mult);
input clk;
input [17:0] a;
input [17:0] b;
output [35:0] mult;
reg [35:0] mult;
reg [17:0] a_in, b_in;
wire [35:0] mult_res;
reg [35:0] pipe_1, pipe_2, pipe_3;
assign mult_res = a_in * b_in;
always @(posedge clk)
begin
a_in <= a;
b_in <= b;
pipe_1 <= mult_res;
pipe_2 <= pipe_1;
pipe_3 <= pipe_2;
mult <= pipe_3;
end
endmodule
Following Verilog template shows the
multiplication operation placed inside the always block and the pipeline stages
are represented as single registers.
module mult(clk, a, b, mult);
input clk;
input [17:0] a;
input [17:0] b;
output [35:0] mult;
reg [35:0] mult;
reg [17:0] a_in, b_in;
reg [35:0] mult_res;
reg [35:0] pipe_2, pipe_3;
always @(posedge clk)
begin
a_in <= a;
b_in <= b;
mult_res <= a_in * b_in;
pipe_2 <= mult_res;
pipe_3 <= pipe_2;
mult <= pipe_3;
end
endmodule
Following Verilog template shows the
multiplication operation placed outside the always block and the pipeline
stages represented as single registers.
module mult(clk, a, b, mult);
input clk;
input [17:0] a;
input [17:0] b;
output [35:0] mult;
reg [35:0] mult;
reg [17:0] a_in, b_in;
wire [35:0] mult_res;
reg [35:0] pipe_1, pipe_2, pipe_3;
assign mult_res = a_in * b_in;
always @(posedge clk)
begin
a_in <= a;
b_in <= b;
pipe_1 <= mult_res;
pipe_2 <= pipe_1;
pipe_3 <= pipe_2;
mult <= pipe_3;
end
endmodule
Following Verilog template shows the
multiplication operation placed inside the always block and the pipeline stages
are represented as single registers.
module mult(clk, a, b, mult);
input clk;
input [17:0] a;
input [17:0] b;
output [35:0] mult;
reg [35:0] mult;
reg [17:0] a_in, b_in;
reg [35:0] mult_res;
reg [35:0] pipe_2, pipe_3;
always @(posedge clk)
begin
a_in <= a;
b_in <= b;
mult_res <= a_in * b_in;
pipe_2 <= mult_res;
pipe_3 <= pipe_2;
mult <= pipe_3;
end
endmodule
Following Verilog template shows the
multiplication operation placed outside the always block and the pipeline
stages represented as shift registers.
module mult3(clk, a, b, mult);
input clk;
input [17:0] a;
input [17:0] b;
output [35:0] mult;
reg [35:0] mult;
reg [17:0] a_in, b_in;
wire [35:0] mult_res;
reg [35:0] pipe_regs [3:0];
assign mult_res = a_in * b_in;
always @(posedge clk)
begin
a_in <= a;
b_in <= b;
{pipe_regs[3],pipe_regs[2],pipe_regs[1],pipe_regs[0]} <=
{mult, pipe_regs[3],pipe_regs[2],pipe_regs[1]};
end
endmodule
Following templates to implement
Multiplier Adder with 2 Register Levels on Multiplier Inputs in Verilog.
module mvl_multaddsub1(clk, a, b, c, res);
input clk;
input [07:0] a;
input [07:0] b;
input [07:0] c;
output [15:0] res;
reg [07:0] a_reg1, a_reg2, b_reg1, b_reg2;
wire [15:0] multaddsub;
always @(posedge clk)
begin
a_reg1 <= a;
a_reg2 <= a_reg1;
b_reg1 <= b;
b_reg2 <= b_reg1;
end
assign multaddsub = a_reg2 * b_reg2 + c;
assign res = multaddsub;
endmodule
Following is the Verilog code for
resource sharing.
module addsub(a, b, c, oper, res);
input oper;
input [7:0] a;
input [7:0] b;
input [7:0] c;
output [7:0] res;
reg [7:0] res;
always @(a or b or c or oper)
begin
if (oper == 1’b0)
res = a + b;
else
res = a - c;
end
endmodule
Following templates show a
single-port RAM in read-first mode.
module raminfr (clk, en, we, addr, di, do);
input clk;
input we;
input en;
input [4:0] addr;
input [3:0] di;
output [3:0] do;
reg [3:0] RAM [31:0];
reg [3:0] do;
always @(posedge clk)
begin
if (en) begin
if (we)
RAM[addr] <= di;
do <= RAM[addr];
end
end
endmodule
Following templates show a
single-port RAM in write-first mode.
module raminfr (clk, we, en, addr, di, do);
input clk;
input we;
input en;
input [4:0] addr;
input [3:0] di;
output [3:0] do;
reg [3:0] RAM [31:0];
reg [4:0] read_addr;
always @(posedge clk)
begin
if (en) begin
if (we)
RAM[addr] <= di;
read_addr <= addr;
end
end
assign do = RAM[read_addr];
endmodule
Following templates show a
single-port RAM in no-change mode.
module raminfr (clk, we, en, addr, di, do);
input clk;
input we;
input en;
input [4:0] addr;
input [3:0] di;
output [3:0] do;
reg [3:0] RAM [31:0];
reg [3:0] do;
always @(posedge clk)
begin
if (en) begin
if (we)
RAM[addr] <= di;
else
do <= RAM[addr];
end
end
endmodule
Following is the Verilog code for a
single-port RAM with asynchronous read.
module raminfr (clk, we, a, di, do);
input clk;
input we;
input [4:0] a;
input [3:0] di;
output [3:0] do;
reg [3:0] ram [31:0];
always @(posedge clk)
begin
if (we)
ram[a] <= di;
end
assign do = ram[a];
endmodule
Following is the Verilog code for a
single-port RAM with "false" synchronous read.
module raminfr (clk, we, a, di, do);
input clk;
input we;
input [4:0] a;
input [3:0] di;
output [3:0] do;
reg [3:0] ram [31:0];
reg [3:0] do;
always @(posedge clk)
begin
if (we)
ram[a] <= di;
do <= ram[a];
end
endmodule
Following is the Verilog code for a
single-port RAM with synchronous read (read through).
module raminfr (clk, we, a, di, do);
input clk;
input we;
input [4:0] a;
input [3:0] di;
output [3:0] do;
reg [3:0] ram [31:0];
reg [4:0] read_a;
always @(posedge clk)
begin
if (we)
ram[a] <= di;
read_a <= a;
end
assign do = ram[read_a];
endmodule
Following is the Verilog code for a
single-port block RAM with enable.
module raminfr (clk, en, we, a, di, do);
input clk;
input en;
input we;
input [4:0] a;
input [3:0] di;
output [3:0] do;
reg [3:0] ram [31:0];
reg [4:0] read_a;
always @(posedge clk)
begin
if (en) begin
if (we)
ram[a] <= di;
read_a <= a;
end
end
assign do = ram[read_a];
endmodule
Following is the Verilog code for a
dual-port RAM with asynchronous read.
module raminfr (clk, we, a, dpra, di, spo, dpo);
input clk;
input we;
input [4:0] a;
input [4:0] dpra;
input [3:0] di;
output [3:0] spo;
output [3:0] dpo;
reg [3:0] ram [31:0];
always @(posedge clk)
begin
if (we)
ram[a] <= di;
end
assign spo = ram[a];
assign dpo = ram[dpra];
endmodule
Following is the Verilog code for a
dual-port RAM with false synchronous read.
module raminfr (clk, we, a, dpra, di, spo, dpo);
input clk;
input we;
input [4:0] a;
input [4:0] dpra;
input [3:0] di;
output [3:0] spo;
output [3:0] dpo;
reg [3:0] ram [31:0];
reg [3:0] spo;
reg [3:0] dpo;
always @(posedge clk)
begin
if (we)
ram[a] <= di;
spo = ram[a];
dpo = ram[dpra];
end
endmodule
Following is the Verilog code for a
dual-port RAM with synchronous read (read through).
module raminfr (clk, we, a, dpra, di, spo, dpo);
input clk;
input we;
input [4:0] a;
input [4:0] dpra;
input [3:0] di;
output [3:0] spo;
output [3:0] dpo;
reg [3:0] ram [31:0];
reg [4:0] read_a;
reg [4:0] read_dpra;
always @(posedge clk)
begin
if (we)
ram[a] <= di;
read_a <= a;
read_dpra <= dpra;
end
assign spo = ram[read_a];
assign dpo = ram[read_dpra];
endmodule
Following is the Verilog code for a
dual-port RAM with enable on each port.
module raminfr (clk, ena, enb, wea, addra, addrb, dia, doa, dob);
input clk, ena, enb, wea;
input [4:0] addra, addrb;
input [3:0] dia;
output [3:0] doa, dob;
reg [3:0] ram [31:0];
reg [4:0] read_addra, read_addrb;
always @(posedge clk)
begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end
end
end
always @(posedge clk)
begin
if (enb) begin
read_addrb <= addrb;
end
end
assign doa = ram[read_addra];
assign dob = ram[read_addrb];
endmodule
Following is Verilog code for a ROM
with registered output.
module rominfr (clk, en, addr, data);
input clk;
input en;
input [4:0] addr;
output reg [3:0] data;
always @(posedge clk)
begin
if (en)
case(addr)
4’b0000: data <= 4’b0010;
4’b0001: data <= 4’b0010;
4’b0010: data <= 4’b1110;
4’b0011: data <= 4’b0010;
4’b0100: data <= 4’b0100;
4’b0101: data <= 4’b1010;
4’b0110: data <= 4’b1100;
4’b0111: data <= 4’b0000;
4’b1000: data <= 4’b1010;
4’b1001: data <= 4’b0010;
4’b1010: data <= 4’b1110;
4’b1011: data <= 4’b0010;
4’b1100: data <= 4’b0100;
4’b1101: data <= 4’b1010;
4’b1110: data <= 4’b1100;
4’b1111: data <= 4’b0000;
default: data <= 4’bXXXX;
endcase
end
endmodule
Following is Verilog code for a ROM
with registered address.
module rominfr (clk, en, addr, data);
input clk;
input en;
input [4:0] addr;
output reg [3:0] data;
reg [4:0] raddr;
always @(posedge clk)
begin
if (en)
raddr <= addr;
end
always @(raddr)
begin
if (en)
case(raddr)
4’b0000: data = 4’b0010;
4’b0001: data = 4’b0010;
4’b0010: data = 4’b1110;
4’b0011: data = 4’b0010;
4’b0100: data = 4’b0100;
4’b0101: data = 4’b1010;
4’b0110: data = 4’b1100;
4’b0111: data = 4’b0000;
4’b1000: data = 4’b1010;
4’b1001: data = 4’b0010;
4’b1010: data = 4’b1110;
4’b1011: data = 4’b0010;
4’b1100: data = 4’b0100;
4’b1101: data = 4’b1010;
4’b1110: data = 4’b1100;
4’b1111: data = 4’b0000;
default: data = 4’bXXXX;
endcase
end
endmodule
Following is the Verilog code for an
FSM with a single process.
module fsm (clk, reset, x1, outp);
input clk, reset, x1;
output outp;
reg outp;
reg [1:0] state;
parameter s1 = 2’b00; parameter s2 = 2’b01;
parameter s3 = 2’b10; parameter s4 = 2’b11;
always @(posedge clk or posedge reset)
begin
if (reset) begin
state <= s1; outp <= 1’b1;
end
else begin
case (state)
s1: begin
if (x1 == 1’b1) begin
state <= s2;
outp <= 1’b1;
end
else begin
state <= s3;
outp <= 1’b1;
end
end
s2: begin
state <= s4;
outp <= 1’b0;
end
s3: begin
state <= s4;
outp <= 1’b0;
end
s4: begin
state <= s1;
outp <= 1’b1;
end
endcase
end
end
endmodule
Following is the Verilog code for an
FSM with two processes.
module fsm (clk, reset, x1, outp);
input clk, reset, x1;
output outp;
reg outp;
reg [1:0] state;
parameter s1 = 2’b00; parameter s2 = 2’b01;
parameter s3 = 2’b10; parameter s4 = 2’b11;
always @(posedge clk or posedge reset)
begin
if (reset)
state <= s1;
else begin
case (state)
s1: if (x1 == 1’b1)
state <= s2;
else
state <= s3;
s2: state <= s4;
s3: state <= s4;
s4: state <= s1;
endcase
end
end
always @(state) begin
case (state)
s1: outp = 1’b1;
s2: outp = 1’b1;
s3: outp = 1’b0;
s4: outp = 1’b0;
endcase
end
endmodule
Verilog code for an
FSM with three processes.
module fsm (clk, reset, x1, outp);
input clk, reset, x1;
output outp;
reg outp;
reg [1:0] state;
reg [1:0] next_state;
parameter s1 = 2’b00; parameter s2 = 2’b01;
parameter s3 = 2’b10; parameter s4 = 2’b11;
always @(posedge clk or posedge reset)
begin
if (reset)
state <= s1;
else
state <= next_state;
end
always @(state or x1)
begin
case (state)
s1: if (x1 == 1’b1)
next_state = s2;
else
next_state = s3;
s2: next_state = s4;
s3: next_state = s4;
s4: next_state = s1;
endcase
end
Synthesis vs. Compilation
Have the hardware design clear in your mind when you write the verilog . Write the Verilog CODE to describe that HW.It is a Hardware Description Language not a Hardware Imagination Language.If you are very clear, the synthesis tools are likely to figure it out
• Descriptions mapped to hardware
• Verilog design patterns for best synthesis
• Verilog and VHDL started out as simulation languages, but soon programs were written to automatically convert Verilog code into low-level circuit descriptions (netlists).
• Synthesis converts Verilog (or other HDL) descriptions to an implementation using technology-specific primitives:
• For FPGAs: LUTs, flip-flops, and RAM blocks
• For ASICs: standard cell gate and flip-flop libraries, and memory blocks
• Automatically manages many details of the design process:
• Fewer bugs
• Improves productivity
• Abstracts the design data (HDL description) from any particular implementation technology
• Designs can be re-synthesized targeting different chip technologies; E.g.: first implement in FPGA then later in ASIC
• In some cases, leads to a more optimal design than could be achieved by manual means (e.g.: logic optimization)
• Variety of general and ad-hoc (special case) methods:
• Instantiation: maintains a library of primitive modules (AND, OR, etc.) and user defined modules
• “Macro expansion”/substitution: a large set of language operators
(+, -, Boolean operators, etc.) and constructs (if-else, case) expand into special circuits
• Inference: special patterns are detected in the language description and treated specially (e.g.,: inferring memory blocks from variable declaration and read/write statements, FSM detection and generation from “always @ (posedge clk)” blocks)
• Logic optimization: Boolean operations are grouped and optimized with logic minimization techniques
• Structural reorganization: advanced techniques including sharing of operators, and retiming of circuits (moving FFs), and others
• Logical operators map into primitive logic gates
• Arithmetic operators map into adders, subtractors, …
• Unsigned 2s complement
• Model carry: target is one-bit wider that source
• Watch out for *, %, and /
• Relational operators generate comparators
• Shifts by constant amount are just wire connections
• No logic involved
• Variable shift amounts a whole different story --- shifter
Condition
• Compiler
– Recognizes all possible constructs in a formally defined program language
– Translates them to a machine language representation of execution process
• Synthesis
– Recognizes a target dependent subset of a hardware description language
– Maps to collection of concrete hardware resources
– Iterative tool in the design flow
• Verilog has two types of assignments within always blocks:
• Blocking procedural assignment “=“
– RHS is executed and assignment is completed before the next statement is executed; e.g.,
Assume A holds the value 1 … A=2; B=A; A is left with 2, B with 2.
• Non-blocking procedural assignment “<=“
– RHS is executed and assignment takes place at the end of the current time step (not clock cycle); e.g.,
Assume A holds the value 1 … A<=2; B<=A; A is left with 2, B with 1.
• Notion of “current time step” is tricky in synthesis, so to guarantee that your simulation matches the behavior of the synthesized circuit, follow these rules:
i. Use blocking assignments to model combinational logic within an always block
ii. Use non-blocking assignments to implement sequential logic
iii. Do not mix blocking and non-blocking assignments in the same always block
iv. Do not make assignments to the same variable from more than one always block
Supported verilog constructs
– Net types: wire, tri, supply1, supply0; register types: reg, integer, time (64 bit reg); arrays of reg
– Continuous assignments
– Gate primitive and module instantiations
– always blocks, user tasks, user functions
– inputs, outputs, and inouts to a module
– All operators (+, -, *, /, %, <, >, <=, >=, ==, !=, ===, !==, &&, ||, !, ~, &, ~&, |, ~|, ^~, ~^, ^, <<, >>, ?:, { }, {{ }}) [Note: / and % are supported for compile-time constants and constant powers of 2]
– Procedural statements: if-else-if, case, casex, casez, for, repeat, while, forever, begin, end, fork, join
– Procedural assignments: blocking assignments =, nonblocking assignments <= (Note: <= cannot be mixed with = for the same register).
– Compiler directives: `define, `ifdef, `else, `endif, `include, `undef
– Miscellaneous:
– Integer ranges and parameter ranges
– Local declarations to begin-end block
– Variable indexing of bit vectors on the left and right sides of assignments
Unsupported Verilog
Generate error and halt synthesis
• Net types: trireg, wor, trior, wand, triand, tri0, tri1, and charge strength;
• register type: real
• Built-in unidirectional and bidirectional switches, and pull-up, pull-down
• Procedural statements: assign (different from the “continuous assignment”), deassign, wait
• Named events and event triggers
• UDPs (user defined primitives) and specify blocks
• force, release, and hierarchical net names (for simulation only)
Simply ignored
• Delay, delay control, and drive strength
• Scalared, vectored
• Initial block
• Compiler directives (except for `define, `ifdef, `else, `endif, `include, and `undef, which are supported)
• Calls to system tasks and system functions (they are only for simulation)
Combinational logic can be generated using:
- Primitive gate instantiation:
AND, OR, etc.
- Continuous assignment (assign keyword), example:
Module adder_8 (cout, sum, a, b, cin);
output cout;
output [7:0] sum;
input cin;
input [7:0] a, b;
assign {cout, sum} = a + b + cin;
endmodule
- Always block:
always @ (event_expression)
begin
// procedural assignment statements, if statements,
// case statements, while, repeat, and for loops.
// Task and function calls
end
• Make sure all signals assigned in a combinational always block are explicitly assigned values every time that the always block executes--otherwise latches will be generated to hold the last value for the signals not assigned values!
module mux4to1 (out, a, b, c, d, sel);
output out;
input a, b, c, d;
input [1:0] sel;
reg out;
always @(sel or a or b or c or d)
begin
case (sel)
2'd0: out = a;
2'd1: out = b;
2'd3: out = d;
endcase
end
endmodule
• To avoid synthesizing a latch in this case, add the missing select line:
2'd2: out = c;
• Or, in general, use the “default” case:
default: out = foo;
• If you don’t care about the assignment in a case (for instance you know that it will never come up) then assign the value “x” to the variable; E.g.:
default: out = 1‘bx;
The x is treated as a “don’t care” for synthesis and will simplify the logic
(The synthesis directive “full_case” will accomplish the same, but can lead to differences between simulation and synthesis.)
Latch rule
• If a variable is not assigned in all possible executions of an always statement then a latch is inferred
– E.g., when not assigned in all branches of an if or case
– Even a variable declared locally within an always is inferred as a latch if incompletely assigned in a conditional statement
FSM
• Style guidelines (some of these are to get the right result, and some just for readability)
– Must have reset
– Use separate always blocks for sequential and combination logic parts
– Represent states with defined labels or enumerated types
• Use CASE statement in an always to implement next state and output logic
• Always use default case and assert the state variable and output to ‘bx:
– Avoids implied latches
– Allows use of don’t cares leading to simplified logic
• “FSM compiler” within synthesis tool can re-encode your states; Process is controlled by using a synthesis attribute (passed in a comment).
Introduction to Gate level Modelling
Verilog has built in primitives like gates, transmission gates, and switches. These are rarely used in design (RTL Coding), but are used in post synthesis world for modeling the ASIC/FPGA cells; these cells are then used for gate level simulation, or what is called as SDF simulation. Also the output netlist format from the synthesis tool, which is imported into the place and route tool, is also in Verilog gate level primitives.
• Note : RTL engineers still may use gate level primitivies or ASIC library cells in RTL when using IO CELLS, Cross domain synch cells.
• Gate primitives are predefined in Verilog, which are ready to use. They are instantiated like modules.
• There are two classes of gate primitives: Multiple input gate primitives and Single input gate primitives.
• Multiple input gate primitives include and, nand, or, nor, xor, and xnor. These can have multiple inputs and a single output. They are instantiated as follows:
• // Two input AND gate.
and and_1 (out, in0, in1);
// Three input NAND gate.
nand nand_1 (out, in0, in1, in2);
// Two input OR gate.
or or_1 (out, in0, in1);
// Four input NOR gate.
nor nor_1 (out, in0, in1, in2, in3);
// Five input XOR gate.
xor xor_1 (out, in0, in1, in2, in3, in4);
// Two input XNOR gate.
xnor and_1 (out, in0, in1);
• Single input gate primitives include not, buf, notif1, bufif1, notif0, and bufif0. These have a single input and one or more outputs. Gate primitives notif1, bufif1, notif0, and bufif0 have a control signal.
• The gates propagate if only control signal is asserted, else the output will be high impedance state (z). They are instantiated as follows:
• // Inverting gate.
not not_1 (out, in);
// Two output buffer gate.
buf buf_1 (out0, out1, in);
// Single output Inverting gate with active-high control signal.
notif1 notif1_1 (out, in, ctrl);
// Double output buffer gate with active-high control signal.
bufif1 bufif1_1 (out0, out1, in, ctrl);
// Single output Inverting gate with active-low control signal.
notif0 notif0_1 (out, in, ctrl);
// Single output buffer gate with active-low control signal.
bufif0 bufif1_0 (out, in, ctrl);
Array of instances
wire [3:0] out, in0, in1;
and and_array[3:0] (out, in0, in1);
The above statement is equivalent to following bunch of statements:
and and_array0 (out[0], in0[0], in1[0]);
and and_array1 (out[1], in0[1], in1[1]);
and and_array2 (out[2], in0[2], in1[2]);
and and_array3 (out[3], in0[3], in1[3]);
module full_adder (sum, c_out, ino, in1, c_in);
output sum, c_out;
input in0, in1, c_in;
wire s0, c0, c1;
// Half adder : port connecting by order.
half_adder ha_0 (s0, c0, in0, in1);
// Half adder : port connecting by name.
half_adder ha_1 (.sum(sum),
.in0(s0),
.in1(c_in),
.carry(c1));
// 2-input XOR gate, to get c_out.
xor xor_1 (c_out, c0, c1);
endmodule
In Verilog, a designer can specify the gate delays in a gate primitive instance. This helps the designer to get a real time behavior of the logic circuit.
Rise delay: It is equal to the time taken by a gate output transition to 1, from another value 0, x, or z.
Fall delay: It is equal to the time taken by a gate output transition to 0, from another value 1, x, or z.
Turn-off delay: It is equal to the time taken by a gate output transition to high impedance state, from another value 1, x, or z.
If the gate output changes to x, the minimum of the three delays is considered.
• If only one delay is specified, it is used for all delays.
• If two values are specified, they are considered as rise, and fall delays.
• If three values are specified, they are considered as rise, fall, and turn-off delays.
• The default value of all delays is zero.
and #(5) and_1 (out, in0, in1);
// All delay values are 5 time units.
nand #(3,4,5) nand_1 (out, in0, in1);
// rise delay = 3, fall delay = 4, and turn-off delay = 5.
or #(3,4) or_1 (out, in0, in1);
// rise delay = 3, fall delay = 4, and turn-off delay = min(3,4) = 3.
There is another way of specifying delay times in verilog, Min:Typ:Max values for each delay. This helps designer to have a much better real time experience of design simulation, as in real time logic circuits the delays are not constant. The user can choose one of the delay values using +maxdelays, +typdelays, and +mindelays at run time. The typical value is the default value.
and #(4:5:6) and_1 (out, in0, in1);
// For all delay values: Min=4, Typ=5, Max=6.
nand #(3:4:5,4:5:6,5:6:7) nand_1 (out, in0, in1);
// rise delay: Min=3, Typ=4, Max=5, fall delay: Min=4, Typ=5, Max=6, turn-off delay: Min=5, Typ=6, Max=7.
In the above example, if the designer chooses typical values, then rise delay = 4, fall delay = 5, turn-off delay = 6.
HDL EMERGENCE
• The need to a standardized language for hardware description
• Verilog® and VHDL
• Simulators emerged
• Usage: functional verification
• Path to implementation: manual translation into gates
• Logic synthesis technology
• Late 1980s
• Dramatic change in digital design
• Design at Register-Transfer Level (RTL) using an HDL
TYPICAL DESIGN FLOW
• Design specification
• Behavioral description
• RTL description
• Functional verification and testing
• Logic synthesis
• Gate-level netlist
• Logical verification and testing
• Floor planning, automatic place & route
• Physical layout
• Layout verification
• Implementation
IMPORTANCE OF HDL
• Retargeting to a new fabrication technology
• Functional verification earlier in the design cycle
• Textual concise representation of the design
• Similar to computer programs
• Easier to understand
Trends
Design at behavioral level
Formal verification techniques
Very high speed and time critical circuits
e.g. microprocessors
Mixed gate-level and RTL designs
Hardware-Software Co-design
System-level languages: SystemC, SpecC,
• IEEE 1364-2001 is the latest Verilog HDL standard
• Verilog is case sensitive (Keywords are in lowercase)
• The Verilog is both a behavioral and a structure language
Popularity of Verilog HDL
• Verilog HDL
• General-purpose
• Easy to learn, easy to use
• Similar in syntax to C
• Allows different levels of abstraction and mixing them
• Supported by most popular logic synthesis tools
• Post-logic-synthesis simulation libraries by all fabrication vendors
PLI to customize Verilog simulators to designers’ needs
DIFFERENCES:VERILOG AND VHDL
• Verilog is similar to C- language.
• Many feel that Verilog is easier to learn and use than VHDL.
Behavioral
• Procedural code, similar to C programming
• Little structural detail (except module interconnect)
Dataflow
• Specifies transfer of data between registers
• Some structural information is available (RTL)
• Sometimes similar to behavior
Structural (gate,switch)
• Interconnection of simple components
• Purely structural
Elements of Verilog-logic values
0: zero, logic low, false, ground
1: one, logic high, power
X: unknown
Z: high impedance, unconnected, tri-state
• Nets
– Nets are physical connections between devices
– Many types of nets, but all we care about is wire.
• Declaring a net
wire [<range>] <net_name> ;
Range is specified as [MSb:LSb]. Default is one bit wide
• Registers
– Implicit storage-holds its value until a new value is assigned to it.
– Register type is denoted by reg.
• Declaring a register
reg [<range>] <reg_name>;
Ø Parameters are not variables, they are constants.
Basic verilog primitives
• Basic logic gates only
– and
– or
– not
– buf
– xor
– nand
– nor
– xnor
– bufif1, bufif0
notif1, notif0
Logical operators
• && ® logical AND
• || ® logical OR
• ! ® logical NOT
• Operands evaluated to ONE bit value: 0, 1 or x
• Result is ONE bit value: 0, 1 or x
A = 1; A && B ® 1 && 0 ® 0
B = 0; A || !B ® 1 || 1 ® 1
C = x; C || B ® x || 0 ® x
Bitwise operators
• & ® bitwise AND
• | ® bitwise OR
• ~ ® bitwise NOT
• ^ ® bitwise XOR
• ~^ or ^~ ® bitwise XNOR
• Operation on bit by bit basis
Shift conditional operator
• ® shift right
• << ® shift left
• a = 4’b1010;
d = a >> 2;// d = 0010,c = a << 1;// c = 0100
• cond_expr ? true_expr : false_expr
keywords
• Note : All keywords are defined in lower case
• Examples :
• module, endmodule
• input, output, inout
• reg, integer, real, time
• not, and, nand, or, nor, xor
• parameter
• begin, end
• fork, join
• specify, endspecify
• module – fundamental building block for Verilog designs
• Used to construct design hierarchy
• Cannot be nested
• endmodule – ends a module – not a statement
• => no “;”
• Module Declaration
• module module_name (module_port, module_port, …);
• Example: module full_adder (A, B, c_in,
• c_out, S);
Modules
• Verilog supported levels of abstraction
• Behavioral (algorithmic) level
• Describe the algorithm used
• Very similar to C programming
• Dataflow level
Describe how data flows between registers and is processed
• Gate level
Interconnect logic gates
• Switch level
Interconnect transistors (MOS transistors)
• Register-Transfer Level (RTL)
Generally known as a combination of behavioral+dataflow that is synthesizable by EDA tools
VERILOG Lexical conventions
Verilog is very similar to C and is case-sensitive
All keywords are in lowercase
A Verilog program is a string of tokens
• Whitespace
• Comments
• Delimiters
• Numbers
• Strings
• Identifiers
• Keywords
Whitespace
Blank space (\b)
Tab (\t)
Newline (\n)
Whitespace is ignored in Verilog except
In strings
When separating tokens
• Comments
Used for readability and documentation
Just like C:
• // single line comment
• /* multi-line
comment
*/
/* Nested comments
/* like this */ may not be acceptable (depends on Verilog compiler) */
• Operators
Unary
a = ~b;
Binary
a = b && c;
Ternary
a = b ? c : d; // the only ternary operator
• Number Specification
Sized numbers
Unsized number
Unknown and high-impedance values
• Negative numbSized numbers
– General syntax: <size>’<base><number>
• <size> number of bits (in decimal)
• <number> is the number in radix <base>
• <base> :
– d or D for decimal (radix 10)
– b or B for binary (radix 2)
– o or O for octal (radix 8)
– h or H for hexadecimal (radix 16)
• Examples:4’b1111
– 12’habc
16’d255ers
• Unsized numbers
Default base is decimal
Default size is at least 32 (depends on Verilog compiler)
Examples
• 23232
• ’habc
• ’o234
• X or Z values
Unknown value: lowercase x
• 4 bits in hex, 3 bits in octal, 1 bit in binary
High-impedance value: lowercase z
• 4 bits in hex, 3 bits in octal, 1 bit in binary
– Examples
• 12’h13x
• 6’hx
• 32’bz
Extending the most-significant part
• Applied when <size> is bigger than the specified value
– Filled with x if the specified MSB is x
– Filled with z if the specified MSB is z
– Zero-extended otherwise
• Examples:
– 6’hx
• Negative numbers
Put the sign before the <size>
Examples:
• -6’d3
• 4’d-2 // illegal
Two’s complement is used to store the value
• Underscore character and question marks
Use ‘_’ to improve readability
• 12’b1111_0000_1010
• Not allowed as the first character
‘?’ is the same as ‘z’ (only regarding numbers)
• 4’b10?? // the same as 4’b10zz
• Strings
As in C, use double-quotes
Examples:
• “Hello world!”
• “a / b”
• “text\tcolumn1\bcolumn2\n”
• Identifiers and keywords
identifiers: alphanumeric characters, ‘_’, and ‘$’
• Should start with an alphabetic character or ‘_’
• Only system tasks can start with ‘$’
Keywords: identifiers reserved by Verilog
Examples:
• reg value;
• input clk;
• Escaped identifiers
Start with ‘\’
End with whitespace (space, tab, newline)
Can have any printable character between start and end
The ‘\’ and whitespace are not part of the identifier
– Examples:
• \a+b-c // a+b-c is the identifier
• \**my_name** // **my_name** is the identifier
Used as name of modules
DATA TYPES
• Value set and strengths
• Nets and Registers
• Vectors
• Integer, Real, and Time Register Data Types
• Arrays
• Memories
• Parameters
• Strings
VALUE SET
Verilog concepts to model hardware circuits
Value level
Value strength
Used to accurately model
Signal contention
MOS devices
Dynamic MOS
Other low-level details
Value level | HW Condition |
0 | Logic zero, false |
1 | Logic one, true |
x | Unknown |
z | High imp., floating |
Strength level | Type |
supply | Driving |
strong | Driving |
pull | Driving |
large | Storage |
weak | Driving |
medium | Storage |
small | Storage |
highz | High Impedance |
NETS
• Used to represent connections between HW elements
Values continuously driven on nets
• Keyword: wire
Default: One-bit values
• unless declared as vectors
Default value: z
• For trireg, default is x
Examples
• wire a;
• wire b, c;
• wire d=1’b0;
REGISTERS
• Registers represent data storage elements
Retain value until next assignment
NOTE: this is not a hardware register or flipflop
Keyword: reg
Default value: x
– Example:
reg reset;
initial
begin
reset = 1’b1;
#100 reset=1’b0;
end
VECTORS
• Net and register data types can be declared as vectors (multiple bit widths)
• Syntax:
wire/reg [msb_index : lsb_index] data_id;
• Example
wire a;
wire [7:0] bus;
wire [31:0] busA, busB, busC;
reg clock;
reg [0:40] virtual_addr;
Consider wire [7:0] bus;
wire [31:0] busA, busB, busC;
reg [0:40] virtual_addr;
• Access to bits or parts of a vector is possible:
busA[7]
bus[2:0] // three least-significant bits of bus
// bus[0:2] is illegal.
virtual_addr[0:1] /* two most-significant bits
* of virtual_addr
*/
INTEGER, REAL, AND TIME REGISTER DATA TYPES
• Integer
Keyword: integer
Very similar to a vector of reg
• integer variables are signed numbers
• reg vectors are unsigned numbers
Bit width: implementation-dependent (at least 32-bits)
• Designer can also specify a width:
integer [7:0] tmp;
– Examples:
integer counter;
initial
counter = -1;
• Real
– Keyword: real
– Values:
• Default value: 0
• Decimal notation: 12.24
• Scientific notation: 3e6 (=3x106)
– Cannot have range declaration
– Example:
real delta;
initial
begin
delta=4e10;
delta=2.13;
end
integer i;
initial
i = delta; // i gets the value 2 (rounded value of 2.13)
Time
Used to store values of simulation time
Keyword: time
Bit width: implementation-dependent (at least 64)
$time system function gives current simulation time
– Example:
time save_sim_time;
initial
save_sim_time = $time;
ARRAYS
• Only one-dimensional arrays supported
• Allowed for reg, integer, time
– Not allowed for real data type
• Syntax:
<data_type> <var_name>[start_idx : end_idx];
• Examples:
integer count[0:7];
reg bool[31:0];
time chk_point[1:100];
reg [4:0] port_id[0:7];
integer matrix[4:0][4:0]; // illegal
count[5]
chk_point[100]
port_id[3]
Note the difference between vectors and arrays
MEMORIES
• RAM, ROM, and register-files used many times in digital systems
• Memory = array of registers in Verilog
• Word = an element of the array
– Can be one or more bits
• Examples:
reg membit[0:1023];
reg [7:0] membyte[0:1023];
membyte[511]
• Note the difference (as in arrays):
reg membit[0:127];
reg [0:127] register;
PARAMETERS
• Similar to const in C
But can be overridden for each module at compile-time
• Syntax:
parameter <const_id>=<value>;
• Gives flexibility
Allows to customize the module
• Example:
parameter port_id=5;
parameter cache_line_width=256;
parameter bus_width=8;
wire [bus_width-1:0] bus;
STRINGS
• Strings are stored in reg variables.
• 8-bits required per character
• The string is stored from the least-significant part to the most-significant part of the reg variable
• Example:
reg [8*18:1] string_value;
initial
string_value = “Hello World!”;
• Escaped characters
– \n: newline \t: tab
– %%: % \\: \
– \”: “ \ooo: character number in octal
SYSTEM TASKS AND COMPILER DIRECTIVES
• System Tasks: standard routine operations provided by Verilog
Displaying on screen, monitoring values, stopping and finishing simulation, etc.
• All start with $
• $display: displays values of variables, strings, expressions.
• Syntax: $display(p1, p2, p3, …, pn);
• p1,…, pn can be quoted string, variable, or expression
• Adds a new-line after displaying pn by default
• Format specifiers:
• %d, %b, %h, %o: display variable respectively in decimal, binary, hex, octal
• %c, %s: display character, string
• %e, %f, %g: display real variable in scientific, decimal, or whichever smaller notation
• %v: display strength
• %t: display in current time format
• %m: display hierarchical name of this module
• $display examples:
• $display(“Hello Verilog World!”);
• Output: Hello Verilog World!
• $display($time);
• Output: 230
• reg [0:40] virtual_addr;
• $display(“At time %d virtual address is %h”, $time, virtual_addr);
• Output: At time 200 virtual address is 1fe000001c
• reg [4:0] port_id;
• $display(“ID of the port is %b”, port_id);
• Output: ID of the port is 00101
• reg [3:0] bus;
• $display(“Bus value is %b”, bus);
• Output: Bus value is 10xx
• $display(“Hierarchical name of this module is %m”);
• Output: Hierarchical name of this module is top.p1
• $display(“A \n multiline string with a %% sign.”);
• Output: A
multiline string with a % sign.
• $monitor: monitors a signal when its value changes
• Syntax: $monitor(p1, p2, p3, …, pn);
• p1,…, pn can be quoted string, variable, or signal names
• Format specifiers just as $display
• Continuously monitors the values of the specified variables or signals, and displays the entire list whenever any of them changes.
• $monitor needs to be invoked only once (unlike $display)
• Only one $monitor (the latest one) can be active at any time
• $monitoroff to temporarily turn off monitoring
• $monitoron to turn monitoring on again
• $monitor Examples:
• initial
• begin
• $monitor($time, “Value of signals clock=%b, reset=%b”, clock, reset);
• end
• Output:
0 value of signals clock=0, reset=1
5 value of signals clock=1, reset=1
10 value of signals clock=0, reset=0
• $stop: stops simulation
• Simulation enters interactive mode when reaching a $stop system task
• Most useful for debugging
• $finish: terminates simulation
• Examples:
initial
begin
clock=0;
reset=1;
#100 $stop;
#900 $finish;
end
General syntax:
`<keyword>
`define: similar to #define in C, used to define macros
`<macro_name> to use the macro defined by `define
Examples:
`define WORD_SIZE 32
`define S $stop
`define WORD_REG reg [31:0]
`WORD_REG a_32_bit_reg;
COMPILER DIRECTIVES
• General syntax:
`<keyword>
• `define: similar to #define in C, used to define macros
• `<macro_name> to use the macro defined by `define
• Examples:
`define WORD_SIZE 32
`define S $stop
`define WORD_REG reg [31:0]
`WORD_REG a_32_bit_reg;
• include: Similar to #include in C, includes entire contents of another file in your Verilog source file
• Example:
`include header.v
...
<Verilog code in file design.v>
...Dataflow modeling
• Dataflow modeling is a higher level of abstraction. The designer no need have any knowledge of logic circuit. He should be aware of data flow of the design.
• The gate level modeling becomes very complex for a VLSI circuit. Hence dataflow modeling became a very important way of implementing the design.
• In dataflow modeling most of the design is implemented using continuous assignments, which are used to drive a value onto a net. The continuous assignments are made using the keyword assign.
Features
• A powerful way to implement a design
• Logic synthesis tools can be used to create a gatelevel net list
• RTL (register transfer level) is a combination of dataflow and behavioral modeling
Assign
The assign statement is used to make continuous assignment in the dataflow modeling. The assign statement usage is given below:
assign out = in0 + in1; // in0 + in1 is evaluated and then assigned to out.
• The LHS of assign statement must always be a scalar or vector net or a concatenation. It cannot be a register.
• Continuous statements are always active statements.
• Registers or nets or function calls can come in the RHS of the assignment.
• The RHS expression is evaluated whenever one of its operands changes. Then the result is assigned to the LHS.
• Delays can be specified.
assign out[3:0] = in0[3:0] & in1[3:0];
assign {o3, o2, o1, o0} = in0[3:0] | {in1[2:0],in2}; // Use of concatenation.
Implicit Net Declaration:
wire in0, in1;
assign out = in0 ^ in1;
In the above example out is undeclared, but verilog makes an implicit net declaration for out.
Implicit Continuous Assignment:
wire out = in0 ^ in1;
The above line is the implicit continuous assignment. It is same as,
wire out;
assign out = in0 ^ in1;
Operands
• constants
• parameters
• nets
• variables (reg, integer, time, real, realtime)
• bit-select
• part-sel
• array element
• function calls
Delays
There are three types of delays associated with dataflow modeling. They are: Normal/regular assignment delay, implicit continuous assignment delay and net declaration delay.
Normal/regular assignment delay:
assign #10 out = in0 | in1;
If there is any change in the operands in the RHS, then RHS expression will be evaluated after 10 units of time.
Lets say that at time t, if there is change in one of the operands in the above example, then the expression is calculated at t+10 units of time.
The value of RHS operands present at time t+10 is used to evaluate the expression.
Implicit continuous assignment delay:
wire #10 out = in0 ^ in1;
is same as
wire out;
assign 10 out = in0 ^ in1;
Net declaration delay:
wire #10 out;
assign out = in;
is same as
wire out;
assign #10 out = in;
Variable data types
reg
integer
time
real
real-time
Reg variable
Hold a value between assignments
May be used to model hardware registers
• Examples
reg a, b;
reg [7:0] data_a;
reg [0:7] data_b;
reg signed [7:0] d;
Integer Variable
Contains integer values
• Has at least 32 bits
• Is treated as a signed reg variable with the LSB
• being bit 0
• integer i, j;
• integer data[7:0];
Time variable
• Used for storing and manipulating simulation time
• Used in conjunction with the $time system task
• Only unsigned value and at least 64 bits, with the
• LSB being bit 0
• time events;
• time current_time;
Real and real time variable
• Cannot use range declaration
• Defaulted to zero (0.0)
• real events;
• realtime current_time;
Assignments in Verilog
• Continuous assignments assign values to nets (vector and scalar)
They are triggered whenever simulation causes the value of the right-hand side to change
Keyword “assign”
e.g. assign out = in1 & in2;
• Procedural assignments drive values onto registers (vector and scalar)
They Occur within procedures such as always and initial
They are triggered when the flow of execution reaches them (like in C)
Blocking and Non-Blocking procedural assignments
• Procedural Assignments
Blocking assignment statement (= operator) acts much like in traditional programming languages. The whole statement is done before control passes on to the next statement
Nonblocking assignment statement (<= operator) evaluates all the right-hand sides for the current time unit and assigns the left-hand sides at the end of the time unit
• Delay Control (#)
Expression specifies the time duration between initially encountering the statement and when the statement actually executes.
Delay in Procedural Assignments
• Inter-Statement Delay
• Intra-Statement Delay
For example:
• Inter-Statement Delay
#10 A = A + 1;
• Intra-Statement Delay
A = #10 A + 1;
D Flip flop with synchronous reset
module d_flipflop_synrst(data_in,data_out,clock,reset);
input data_in;
input clock,reset;
output reg data_out;
always@(posedge clock)
begin
if(reset)
data_out<=1'd0;
else
data_out<=data_in;
end
endmodule
Procedural Assignments
• Executes a procedure allowing for more powerful constructs such as if-then-else and case statement.
• For example 2:1 mux:
– if-then-else
if (A) then D = B else D = C;
– case
case(A)
1'b1 : D = B;
1'b0 : D = C;
endcase
This is obviously much easier to implement and read then Boolean expressions!!
Always block
• An always block is an example of a procedure.
• The procedure executes a set of assignments when a defined set of inputs change.
Example:
module mux_2_1(a, b, out, sel);
input a, b, sel;
output out;
reg out;
always @ (a or b or sel)
begin
if (sel) out = a;
else out = b;
end
endmodule
The always block ‘executes’ whenever signals named in the sensitivity list change.
Literally: always execute at a or b or sel.
Sensitivity list should include conditional (sel) and right side (a, b) assignment variables.
As Easier Way to Implement the Sensitivity List
• Recent versions of Verilog provides a means to implement the sensitivity list without explicitly listing each potential variable.
• Instead of listing variables as in the previous example
always @ (a or b or sel)
Simply use
always @*
The * operator will automatically identify all sensitive variables.
Blocking and non-blocking assignments
• Blocking (=) and non-blocking (<=) assignments are provided to control the execution order within an always block.
• Blocking assignments literally block the execution of the next statement until the current statement is executed.
– Consequently, blocking assignments result in ordered statement execution.
– Combinational logic: Use blocking statements with always blocks with the * operator to mimic logic flow of combinational logic.
– Sequential logic: Use non-blocking statements with always blocks sensitive to rising clock edge to mimic parallel sequential logic.
–
For example:
assume a = b = 0 initially;
a = 1; //executed first
b = a; //executed second
then a = 1, b = 1 after ordered execution
• Non-blocking assignments literally do not block the execution of the next statements. The right side of all statements are determined first, then the left sides are assigned together.
– Consequently, non-blocking assignments result in simultaneous or parallel statement execution.
For example:
assume a = b = 0 initially;
a <= 1;
b <= a;
then a = 1, b = 0 after parallel execution
Result is different from ordered exec!!! Does not preserve logic flow
To block or not to block
Ordered execution mimics the inherent logic flow of combinational logic.
Hence blocking assignments generally work better for combinational logic.
For example:
module blocking(a,b,c,x,y);
input a,b,c;
output x,y;
reg x,y;
always @*
begin
x = a & b;
y = x | c;
end
endmodule
module nonblocking(a,b,c,x,y);
input a,b,c;
output x,y;
reg x,y;
always @*
begin
x <= a & b;
y <= x | c;
end
endmodule
Blocking behavior | a | b | c | x | y |
Initial values | 1 | 1 | 0 | 1 | 1 |
a changesàalways block execs | 0 | 1 | 0 | 1 | 1 |
x = a & b; //make assignment | 0 | 1 | 0 | 0 | 1 |
y = x | c; //make assignment | 0 | 1 | 0 | 0 | 0 |
Non-blocking behavior | a | b | c | x | y |
Initial values | 1 | 1 | 0 | 1 | 1 |
a changesàalways block execs | 0 | 1 | 0 | 1 | 1 |
x = a & b; | 0 | 1 | 0 | 1 | 1 |
y = x | c; //x not passed from here | 0 | 1 | 0 | 1 | 1 |
make x, y assignments | 0 | 1 | 0 | 0 | 1 |
non-blocking behavior does not preserve logic flow!!
Sequential logic
• Can be generalized as a series of combinational blocks with registers to hold results.
• Shift registers are used to implement multiplication/division and other functions.
clk | D0 | Q0 | Q1 |
initial | 1 | 0 | 0 |
rising edge | 1 | 1 | 0 |
rising edge | 0 | 0 | 1 |
Notice that the inputs of each stage are “evaluated” then latched into the registers at each rising clock edge.
• Because the shift logic evaluates inputs in parallel and latches result on a rising clk edge, a non-blocking always procedure sensitive to a rising clock can be used to implement.
Sensitive to rising clock edge. Note that in this case we must explicitly specify sensitivity to the rising edge of clock. Simply using the * will not work.
• What if we used blocking statements instead. Notice the following results:
The logic statements are simplified to Q0 = Q1 = D0. Logic is evaluated on rising edge of clk. Verilog is synthesized as one stage logic.
Test bench for D Flip flop with synchronous reset
module Tb_dflipflop_synrst();
reg data_in;
reg clock,reset;
wire data_out;
d_flipflop_synrst UUT(.data_in(data_in),
.data_out(data_out),
.clock(clock),
.reset(reset));
initial begin
// Initiliase Input Stimulus
data_in = 0;
clock = 0;
reset=0;
end
always #100 clock=~clock;
//Stimulus
initial
begin
#200 data_in = 1'b1;
reset = 1'b1;
#200 data_in = 1'b1;
reset = 1'b1;
#300 data_in = 1'b1;
reset=1'b0;
#600 data_in = 1'b0;
#500 data_in = 1'b1;
#200 data_in = 1'b0;
#400 $stop;
end
endmodule
No comments:
Post a Comment