100% found this document useful (3 votes)
86 views

Lecture 5 - Combinatorial and Sequential Logic

Here are some suggestions to improve the clarity of the control structure: 1. Use consistent indentation to clearly show block structure. 2. Put one statement per line to avoid nested statements becoming unclear. 3. Use clearer conditional expressions without double negatives or complex boolean logic. 4. Add comments to explain the intent or purpose rather than relying on complex expressions. 5. Maintain consistency in style across conditional expressions for readability. Making these changes would help simplify and clarify the control flow for easier understanding and maintenance. Clear structure and style are important for readability of sequential logic descriptions.

Uploaded by

antonioclj
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (3 votes)
86 views

Lecture 5 - Combinatorial and Sequential Logic

Here are some suggestions to improve the clarity of the control structure: 1. Use consistent indentation to clearly show block structure. 2. Put one statement per line to avoid nested statements becoming unclear. 3. Use clearer conditional expressions without double negatives or complex boolean logic. 4. Add comments to explain the intent or purpose rather than relying on complex expressions. 5. Maintain consistency in style across conditional expressions for readability. Making these changes would help simplify and clarify the control flow for easier understanding and maintenance. Clear structure and style are important for readability of sequential logic descriptions.

Uploaded by

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

Lecture 5: Sequential and

Combinatorial Logic,
Statements, Generics
TIE-50206 Logic Synthesis
Arto Perttula
Tampere University of Technology
Fall 2017
Seq.
n
logic foo_r
a_in
b_in
Comb. D Q n
n logic
c_in
1
Acknowledgements
• Prof. Pong P. Chu provided ”official” slides for
the book which is gratefully acknowledged
– See also: http://academic.csuohio.edu/chu_p/
• Most slides were originally made by Ari Kulmala
– and other previous lecturers (Teemu Pitkänen, Konsta
Punkka, Mikko Alho, Erno Salminen…)

Arto Perttula 7.11.2017 2


Contents
• Concurrent and sequential statements of VHDL
• Sequential logic from VHDL
– Reset
• Common pitfalls

Arto Perttula 7.11.2017 3


Concurrent vs. Sequential
Statement in HDL
• Most programming languages are sequential but digital logic
operates as parallel
• HW designers need a bit different frame of mind to take parallelism
into account
• VHDL is a parallel language but some things are better captured
with sequential description
• Hence, there are 2 types of statements
1. Concurrent
2. Sequential

Arto Perttula 7.11.2017 4


Category 1: Concurrent Statements
• Define interconnected blocks and processes that jointly define the behaviour or
structure of a design – inside the architecture
• Are executed in parallel and asynchronously with respect each others
– PROCESS
– COMPONENT INSTANTIATION
– GENERATE
– CONCURRENT SIGNAL ASSIGNMENT
– CONDITIONAL SIGNAL ASSIGNMENT
– SELECTED SIGNAL ASSIGNMENT
– CONCURRENT ASSERTION
– CONCURRENT PROCEDURE CALL
– BLOCK
• All concurrent statements can be labeled

Arto Perttula 7.11.2017 5


Category 2: Sequential
Statements
• Executed in order in which they appears
• Can be used inside processes, procedures and functions
– SIGNAL ASSIGNMENT
– VARIABLE ASSIGNMENT
– IF
– CASE
– ASSERTION
– LOOP
– NEXT
– EXIT
– PROCEDURE CALL
– RETURN
– NULL
– WAIT

Arto Perttula 7.11.2017 6


Detecting Concurrent And Sequential Code
begin -- rtl
sync_proc: process (clk, rst_n) • Concurrent:
variable k_v : integer;
begin -- process sync_proc
if rst_n = '0’
x_r <= 0;
1. sync_proc
y_r <= 0;
sequential 2. comb_proc
Architecture body

elsif clk'event and clk = '1' then


k_v := to_integer(unsigned(a_in));
x_r <= to_integer(unsigned(a_in));
y_r <= k_v + x_r;
3. z <= …;
end if;
end process sync_proc;
comb_proc: process (a_in, c_in)
4. m_out <= ...;
variable inter_v : std_logic;
begin -- process comb_proc
inter_v := a_in(0) and c_in(0);
• Sequential
if inter_v = '1' then
sequential
res <= a_in xor c_in;
else 1. Sync_proc
res <= a_in;
end if;
end process comb_proc; internals
z <= y_r;
m_out <= res when b_in(0) = '1' else
2. Comb_proc
std_logic_vector(to_unsigned(z,
end rtl;
data_width_g)); internals

Quiz: which signals


implement a register? A: x_r, y_r

Arto Perttula 7.11.2017 7


Sequential Statements: IF
• Probably the most important sequential statement Inside processes,
procedures and
• Like in conventional programming languages functions only
– Priority encoded (if tested first, then elsif, then else)
IF condition THEN
sequence of statements
[ ELSIF condition2
sequence of statements ]
[ ELSE
sequence of statements ]
END IF;
• Example of incrementing and clipping values within allowed range:
IF a > upper_limit_c THEN
a <= upper_limit_c;
ELSIF a < lower_limit_c
a <= lower_limit_c;
ELSE
a <= a+1;
END IF;

Arto Perttula 7.11.2017 8


Example: Combinatorial Mux Using IF
--
-- Synthesis example: Multiplexer using IF statement
--
ENTITY ifmultiplexer IS
port (
a, b, sel : IN STD_LOGIC;
z : OUT STD_LOGIC);
END ifmultiplexer;

ARCHITECTURE syn OF ifmultiplexer IS


BEGIN – Syn

PROCESS (a, b, sel)


BEGIN -- PROCESS
IF (sel = ’1’) THEN
z <= b;
ELSE
z <= a;
END IF;
END PROCESS;
END syn;

Arto Perttula 7.11.2017 9


Clear Control Structure Is Essential
if foo=’0’ then if foo=’0’ then
… …
end if; else
… …
stuff(); -- Branches are
… -- mutually exclusive.
if foo=’1’ then… -- Easier to analyze.
end if;
stuff(); -- Better separated

if… then if… then


a <=’0’; a <=’0’;
b <=’1’; b <=’1’;
else else
b <=’0’; a <=’1’;
a <=’1’; b <=’0’;
end if; -- Assignments in fixed
-- order
end if;

Arto Perttula 7.11.2017 10


Clear Control Structure (2)
if val >10 then if val < buf_limit_c then
… -- Simple things first
… -- lots of code -- Constants vs. magic num
… -- Be careful with ±1
… else
… …
else … -- lots of code
-- only few code lines …
end if; …

end if;

if foo = ’0’ then


if foo=’1’ then -- Normal case
… else
-- WOW! Something strange -- Error handling
-- happened… -- Better commenting
else …
-- Normal case end if;
end if;

Arto Perttula 7.11.2017 11


Clear Control Structure (3)
b <=’1’; -- moved here

if foo=’1’ then if foo=’1’ then


a <=’1’; b<=’1’; else a <=’1’; -- indent
if bar=… then a<=’0’;… end if; -- 1 statement/line
b <=’1’; -- Blank lines
end if; else
if bar=… then
a<=’0’;

end if; -- bar=
end if; -- foo=1

if … then if … then
if full=’1’ then… if full = ’1’ then…
else … else …
else else
if full=’0’ then… if full = ’1’ then…
else … -- Consistency
else …

Arto Perttula 7.11.2017 12


Clear Control Structure (4)
if not(cnt_r /=10) then if cnt_r = 10 then
… -- Double negative removed

else else
if (to_integer(d and ”001”)=1 then if d(1) = ’1’ then
… -- Slicing vs. C-like masking
-- Simpler comparison
elsif (not e)and f) and h then …
… elsif (e=’0’ and f=’1’ and h=’1’)
then
-- Added whitespaces, line break
-- and explicit number literals.
elsif i nor j then …
… elsif i=’0’ and j=’0’ then
-- NOR is difficult for humans,
-- just like NAND
else …
… else

Arto Perttula 7.11.2017 13


Inside processes,

Statements: CASE
procedures and
functions only

• Alternative to if-clause
• All possible choices must be considered or the last choice must contain others clause
CASE expression IS
WHEN choice1 =>
statements
WHEN choice2 =>
statements
WHEN others =>
statements
END CASE;
• Example problem with DesignCompiler synthesis tool (from Synopsys):
– ”Error: All possible string values of selector type not covered by choices.”
signal sel : std_logic;
...
CASE sel IS
WHEN ‘0’ => result <= a;
WHEN ‘1’ => result <= b;
END CASE;

Arto Perttula 7.11.2017 14


Statements: CASE (2)
Inside processes,
procedures and
functions only

• Example:
CASE state IS
WHEN “000” =>
output <= 0;
WHEN “001”=>
output <= 1;
WHEN “010”=>
output <= 2;
WHEN “011”=>
output <= 3;
WHEN OTHERS =>
output <= 4;
END CASE;
• Use when others => with case
– Otherwise, some tools want you to specify also what happens with other std_logic values,
e.g., ”X11”, ”1Z1”, ”WHH”, ”UUU”

Arto Perttula 7.11.2017 15


Statements: NULL
• Performs no action
• Is used to explicitly show that no action is to be performed when certain conditions
are true
• Example
CASE state IS
WHEN “000” =>
output <= 1;
WHEN “001”=>
output <= 2;
WHEN “010”=>
output <= 3;
WHEN OTHERS =>
NULL;
END CASE;
NOTE: be careful with NULL statement. In asynchronous/combinatorial processes it may
generate latches (prob. unintentional)

Arto Perttula 7.11.2017 16


Statements: Assertion
• Checks a specific condition and gives message
• Great help in simulation (not synthesizable)
• Also as checkers inside the module
– E.g., if we assume that always input a < 10, we put an assertion
– Use assertions to verify the initial assumptions (e.g., generic value range, input value range, known
properties and relations)!
• General form:
ASSERT condition [REPORT s_expr] [SEVERITY sl_expr]
• Examples:
ASSERT word_count_g < 10
REPORT “Parameter word count too big (should be <10)”
SEVERITY warning;
• Checks by TB done only during verification but assertions are always there in every simulation
• Assertions can be inside or outside a process

Arto Perttula 7.11.2017 17


Inside processes,

Statements: WAIT
procedures and
functions only

• Stops execution of a process or procedure


• General form:
WAIT [on sensitivity_list] [UNTIL b_expr] [FOR t_expr]
• Examples:
WAIT ON a;
WAIT UNTIL a = ‘1’;
WAIT FOR 10 ns;
WAIT ON a UNTIL b = ‘1’ FOR 100 ns;
WAIT UNTIL Clk’EVENT AND Clk = ‘1’;
• Another way to do clock-triggered process (not recommended)
• Reserve usage for test benches only
Arto Perttula 7.11.2017 18
Statements: LOOP
• A way to represent iteration
– Good for generic and portable code
• 3 different forms possible
– Prefer for loop
• General form:
[label:] [iteration_scheme] LOOP
{sequential_statement}
END LOOP [label];
• Examples:
FOR i IN 10 DOWNTO 0 LOOP
a(i) := b(i);
Inside processes, END LOOP;
procedures and functions
Preferred loops
WHILE i < 10 LOOP •The bounds are easily seen
a(i) := a(i) + 1;
i := i+1;
END loop;

LOOP
clock <= not clock;
wait for ClockPeriod/2;
Also in concurrent part IF error = ‘1’ THEN
EXIT; example of clock generation in simulation test benches
END IF;
END LOOP;

Arto Perttula 7.11.2017 19


Statements: EXIT
• exit statement is used to jump out from loops during execution and complete
current loop
– Problem: the exit points in arbitrary locations make the code very hard to comprehend later
– Note! Hardware implemented for worst case anyway
– You cannot have any speed advantage with early exits or such
• Example:
outer_loop:FOR j IN 0 TO data_width_g-1 LOOP
inner_loop:FOR i IN 0 TO n_cpu_c-1 LOOP
IF exit_cond = true THEN
EXIT inner_loop;
ELSE
counter :=counter +1;
END IF;
END LOOP inner_loop;
END LOOP outer_loop;

Arto Perttula 7.11.2017 20


Statements: NEXT
• next statement is used to stop execution of statements in the loop for this
iteration and go to the next iteration
– Same obfuscation problem as with exit
• Example:
outer_loop:FOR j IN 0 TO data_width_g-1 LOOP
inner_loop:FOR i IN 0 TO n_cpu_c-1 LOOP
IF next_cond = true THEN
NEXT inner_loop;
ELSE
counter := counter +1;
END IF;
END LOOP inner_loop;
END LOOP outer_loop;

Arto Perttula 7.11.2017 21


Subprograms
• Variables inside subprograms are local
• Variables are valid only during subprogram execution
• Contain sequential statements
• Produce combinatorial logic
• Functions:
– Can return one argument (can be compound type)
– All parameters are input parameters
FUNCTION n_one_bits(vec : BIT_VECTOR) RETURN INTEGER IS
VARIABLE tmp : INTEGER;
BEGIN
tmp := 0;
FOR i IN vec’RANGE LOOP
IF vec(i) = ‘1’ THEN
tmp := tmp+1;
ELSE
tmp := tmp;
END IF;
END LOOP;
RETURN tmp;
END n_one_bits;

Arto Perttula 7.11.2017 22


Subprograms (2)
• Procedures:
– Can contain several input, output and inout parameters

PROCEDURE n_one_bits (SIGNAL vec : IN BIT_VECTOR;


VARIABLE int : OUT INTEGER) IS
BEGIN
int := 0;
FOR i IN vec’range LOOP
IF vec(i) = ‘1’ THEN
int := int+1;
ELSE
int := int;
END IF;
END LOOP;
END n_one_bits;
Arto Perttula 7.11.2017 23
Procedures And Functions: Call And Return

• Procedure and function call statements:


procedure_name([actual parameters]);
• Parameters can be positional or named association
myproc1(formal1 => ‘1’,
formal2 => ”111”,
formal3 => 1
);
myprocedure3; --No parameters

-- Similar to component instantiation and also positional assignment:


myproc1(my_signal,my_variable,1);
return statement completes execution of innermost procedure or function
• return statement can be used only in body of procedure or function
• Examples:
RETURN(“1111”);

RETURN;

Arto Perttula 7.11.2017 24


SEQUENTIAL LOGIC

Arto Perttula 7.11.2017 25


Recap: Combinatorial vs. Sequential
Circuit
• Combinatorial circuit: • Sequential circuit:
– No internal state – With internal state
– Output is a function of inputs – Output is a function of inputs and
only internal state
– No latches/FFs – Synchronous design style with
– Described with processes or DFFs
concurrent statements • Includes also combinatorial logic
– Described with processes

n n
Comb. Comb.
logic logic

Arto Perttula 7.11.2017 26


Sequential Statements vs. Logic
• Sequential VHDL statements do not necessarily represent
sequential (synchronous) digital logic circuits
• They can describe both combinatorial and synchronous logic circuits
• Modeling combinatorial logic with sequential statements:
– Sensitivity list of process statements must contain all inputs used in
VHDL statements
– Conditional and selected signal assignments (also if and case
statements) must cover all possible branches (to avoid inferring
unintentional latches)

Arto Perttula 7.11.2017 27


Sequential Statements vs.
Sequential Logic D Q
• The two basic types of synchronous elements are
1. D-type latch (level sensitive memory cell) ena
2. D-type flip-flop (edge-triggered memory cell)
D Q
• The main disadvantage of latches (instead of flip-
flops) is that static timing analysis (STA) of clk
synthesized circuits can be very complex
– Do not use latches! => Inferred latches indicate very
likely a bug
– They also complicate manufacturing tests
Arto Perttula 7.11.2017 28
Sequential Statements vs.
Sequential Logic (2)
• Flip-flops are inferred by signal assignment in a process that detects some
signal’s edge
– Note! Assigning in reset branch creates DFF as well, even if the clk’event branch
does not touch that signal
• Example of rising edge detection:

IF (clk’EVENT AND clk=’1’) THEN


statements...
END IF;
input ports,
statements D Q assigned signals
signals, and output ports
generics, constants
clk 7.11.2017 29
Designing Synchronous Circuits
• All signals and ports that are assigned a value in process containing
[ELS]IF (clk’EVENT AND clk=’1’) THEN
are implemented as registers!
– Note that a register consists of several flip-flops
• This is because these assignments take place only at clock edge
– This is exactly how the flip-flops work: they load the input value on clock edge
• Explicit usage of flip-flop component is not recommended
• Many signal types can infer registers. Integers become registers (32b) as
well as std_logic_vectors and own defined types.
– A flip-flop is instantiated for each bit
– Integer ranges should be defined
Arto Perttula 7.11.2017 30
Designing Synchronous Circuits (2)
• Remember the concept of RTL design
• With VHDL synchronous design style, this is actually just what you do
– Define what happens before a register and where that data goes
...
ELSIF clk'event AND clk = '1' THEN -- rising clock edge
result_r <= (a_in XOR b_in) + c_in;
END IF;
... Do this operation and move the
Inputs may come result to result register
from registers or
other comb logic, The code shows
result_r
but example code that result_r is a
does not show a_in
where
b_in
c_in
Comb.
logic
D Q register, postfix
_r is meant for
human reader

clk
7.11.2017 31
Trivial Example: DFF
• Example: model a single rising-edge triggered D flip-flop

Process activated when there is


a change in value of reset or clk

If reset is active

Reminder: No code
before if
or after end if
If reset was not active
AND we have a rising
Arto Perttula edge in signal ‘clk’ 32
Example 2: Multiply-Accumulate
Step 1: Define the Entity
• Entity is the same for all architecture variants
– However, clk and rst_n are ignored in combinatorial
Data width is parameterized, we’ll
entity mac is return to this…
generic (
data_width_g : integer := 4);
Default range is 4-1 downto 0 = 4 bits
port (
clk : in std_logic;
rst_n : in std_logic;
a_in : in std_logic_vector(data_width_g-1 downto 0);
b_in : in std_logic_vector(data_width_g-1 downto 0);
c_in : in std_logic_vector(data_width_g-1 downto 0);
mac_out : out std_logic_vector(data_width_g*2-1 downto 0)
);
end mac;
Double width due to multiplication Default: 4*2-1 = 7, 7 downto 0 = 8 bits
(in numeric_std, two 4-bit number addition
results in 4-bit result, not 5-bit.) 7.11.2017 33
MAC: 3 Possible Architectures
1) Combinatorial circuit:
A_in
B_in * Mac_out
C_in +
2) Synchronous circuit:
A_in
B_in * Mac_out
C_in + D Q

3) Pipelined synchronous circuit:


A_in
B_in * D Q
Mac_out

D Q
+ D Q
C_in

Arto Perttula 7.11.2017 34


MAC: Combinatorial Architecture
A_in
• Combinatorial circuit has no flip-flops B_in * Mac_out
architecture rtl of mac is
C_in +
begin -- rtl

mac_comb: process (a_in, b_in, c_in)


variable result_v : unsigned(data_width_g*2-1 downto 0);
begin -- process mac_comb
-- note that result_v does not depend on its previous value
-- => this is safe usage of variable to beautify the code

result_v := unsigned(a_in)*unsigned(b_in)+unsigned(c_in);
mac_out <= std_logic_vector(result_v);

end process mac_comb;


Multiplication precedes addition, but
parentheses would make that more obvious.
end rtl;
Here we don’t care about overflow in the sum.
Arto Perttula 7.11.2017 35
MAC: Synchronous Architecture
• Synchronous circuit with single output flip-flop
architecture rtl of mac is
A_in
begin -- rtl B_in * Mac_out
mac_sync : process (clk, rst_n)
variable result_v : unsigned(data_width_g*2-1 downto 0);
C_in
+ D Q

begin -- process mac_comb


if rst_n = '0' then -- asynchronous reset (active low)
mac_out <= (others => '0');

elsif clk'event and clk = '1' then -- rising clock edge


result_v := unsigned(a_in)*unsigned(b_in)+unsigned(c_in);
mac_out <= std_logic_vector(result_v);
end if;
end process mac_sync;

end rtl; A register is generated for mac_out


since: Result_v is just a wire and not
•It is a signal (port out) and implemented as register since
•It is assigned a value within the • it is a variable that does not
clock region
7.11.2017 36
depend on its previous value
MAC: Pipelined
A_in
B_in * D Q
Mac_out

D Q
+ D Q
C_in

• Pipelined version has two register stages


architecture rtl of mac is
signal mul_r : unsigned(data_width_g*2-1 downto 0); -- internal signal (reg)
signal c_r : unsigned(data_width_g-1 downto 0); -- internal signal (delay reg)

begin -- rtl

mac_pipe : process (clk, rst_n)


begin -- process mac_comb
if rst_n = '0' then -- asynchronous reset (active low)
mac_out <= (others => '0');

elsif clk'event and clk = '1' then -- rising clock edge


c_r <= unsigned(c_in);
mul_r <= unsigned(a_in)*unsigned(b_in);
mac_out <= std_logic_vector(mul_r + c_r); The mul_r is updated in previous
end if; statement. However, signal values do
end process mac_pipe; not change until the next clock edge
with the clock region (unlike variables).
end rtl;
Registers implemented for each Therefore, mac_out functions correctly
signal. as it uses mul_r(t) while the preceding
Order of assigments does not statement produced mul_r(t+1).
matter here
Arto Perttula 7.11.2017 37
MAC: Second Pipelined Version
4) Pipelined synchronous circuit without outregister:
architecture rtl of mac is
signal mul_r : unsigned(data_width_g*2-1 downto 0);
A_in
B_in * D Q
Mac_out
signal c_r : unsigned(data_width_g-1 downto 0);

begin -- rtl
C_in
D Q
+ mac_pipe : process (clk, rst_n)
begin -- process mac_comb
if rst_n = '0' then
-- Note that intermediate pipeline registers do
-- not have to be nullified under reset
c_r <= (others => '0');
Mac_out moved out of the mul_r <= (others => '0');
clock region causes that no
register generated for it but just elsif clk'event and clk = '1’
a wire coming from an adder. c_r <= unsigned(c_in);
It must NOT be reset. mul_r <= unsigned(a_in)*unsigned(b_in);
end if;
end process mac_pipe;
Quiz: why would this made more sense than v3?
A: Smaller area. Delay of ADD doesn’t probably increase the critical path mac_out <= std_logic_vector(mul_r + c_r);

end rtl; 38
System Reset
• Brings the system into known state
– At-start-up
– After crash
• Known state = deterministic values for flip-flops in the system
– Concerns sequential logic (sequential processes)
• Memory (SRAM, DRAM) contents usually remain in reset
– But you cannot count on that!
– Contents are lost when power is shutdown
– Will be initialized/reset explicitly location by location (often with SW)
• Flip-flop’s value may be set
1. Asynchronously via special input pin – Asynchronous reset
2. Synchronously via D input – Synchronous reset
3. Synchronously via D input – Normal operation

Arto Perttula 7.11.2017 39


DFF with Asynchronous Reset
• Common way set
1. Reset
– Drives the set or clear inputs of a flip-flop D Q
comb
– The other always inactive
– Output Q updated even if no clock signal present
– Avoid logic gates in reset signal if possible
clear
2. Normal operation
– Value of D appears on Q after each rising edge of clock D flip-flop
– D driven by some combinatorial logic (or input pins)
– Clock driven by input pin, PLL, or or other special clock generation logic. Not by your own
logic!
• Thou shalt not mess with reset or clock signals!

Arto Perttula 7.11.2017 40


DFF with Asynchronous Reset (2)
async_rst : process (clk, rst_n) set
-- use exactly this sensitivity list set
begin
-- No signal assignments here

if rst_n = '0' then comb D Q


-- Assign bootup values for DFFs in this branch.
-- Use constant values only! Do not read signals or
-- input ports! Avoid comb. logic in reset signal. clk

elsif clk'event and clk = '1' then clear


-- Assign the values of normal operation in this branch.
-- No other conditions to elsif. Otherwise you’ll get
-- comb. logic into the clock tree which is disastrous.
-- Use nested if-statements instead.
end if;
D flip-flop. Bad conventions crossed out.
-- No else of elsif branches here Clouds denote combinatorial logic (AND, OR,
-- No signal assignments here
NOT, XOR etc.) Prefer just connecting a wire
end process async_rst;

Arto Perttula 7.11.2017 41


DFF with Synchronous Reset
• Not so common way but OK
• Uses simpler DFFs that have no asynchronous inputs
• Now, also the reset needs valid clock signal
– PLL may take milliseconds before locking and providing clean clock
1. Reset
– Sets/clears the D input
– Minor increase to critical path
– Routing the reset signal throughout the chip is easier than in
asynchronous case
2. Normal operation as previously
Arto Perttula 7.11.2017 42
DFF with Synchronous Reset (2)
sync_rst_n
sync_rst : process (clk)
-- use exactly this sensitivity list
begin comb D Q
-- No signal assignments here
if clk'event and clk = '1' then
if sync_rst_n = ’0’ then
DFF set to ’0’ at sync. reset
-- Assign bootup values for DFFs in this branch.
-- No other conditions here.
-- Assign constant reset values only.
else
-- Assign the values of normal operation in this branch. sync_rst_n
end if;
-- No elsif branches here.
end if; comb D Q
-- No else of elsif branches here
-- No signal assignments here
end process sync_rst;
DFF set to ’1’ at sync. reset

Arto Perttula 7.11.2017 43


Timing Example: Asynchronous
Reset + Synchronous

Clear DFF output changes only on clock edge when reset is not
active
 Reset signal set output value to zero immediately
 Synchronous clear signal set output to zero on clock edge

Q changes
after clk
Undefined signal value on reset. edge again

Note! This timing in simulation.


In real HW, Q2 does not care
about reset and just stores D U
on every clk edge (also values 0 and 1).

Sync. clear Reset happens


D has no effect First active
when rst_n = 0 clk edge
affects on immediately, 44
clk edge not on clk edge!
The True Devil – Never Do!
ENTITY bad_counter IS
PORT (
reset, clk, inc : IN STD_LOGIC;
cnt : BUFFER INTEGER RANGE 0 TO 4);
END bad_counter;
ARCHITECTURE example OF bad_counter IS
BEGIN -- Example
PROCESS (clk, reset, inc, cnt)
BEGIN -- PROCESS
IF reset = ’0’ THEN -- asynchronous reset (active low)
cnt <= 0;
ELSIF inc = ’1’ THEN
cnt <= cnt+1;
ELSIF clk’EVENT AND clk = ’1’ THEN -- rising clock edge
cnt <= cnt-1;
END IF; What is wrong?
END PROCESS;
END example;
Generates a pseudo-random machine.
45
Few Further Notes about Reset
• Terms ”Asynchronous/Synchronous Reset” refers how the reset signal is
connected to the DFFs
• All flip-flops must leave the reset state simultaneously
• Hence in both cases, the reset signal must be synchronous to the
used clocks!
– Reset from external pin is specifically synchronized first!
– Otherwise, some DFFs may start little earlier (one cycle) than others  Medium-
scale catastrophe
– Synchronization logic covered later
• In large chip, the reset operation may be complex sequence
– Detect stable voltage and clock first, reset blocks in certain order…
Arto Perttula 7.11.2017 46
Few Further Notes about Reset (2)
• Reset signal has similar setup and hold time constraints as D input to avoid
metastability problems
• Syncronous reset via D input is good for synchronizers at chip’s inputs
– The incoming values propagate through the synchronizer during reset
– However, asynchronous reset needs constant values. Hence, synchronized
inputs are reset differently depending on their behavior. Hard to maintain such
logic.
• Both styles are used and there is no clear winner
– But you can, of course, have endless and heated discussion on their benefits 

Arto Perttula 7.11.2017 47


GENERICS AND GENERATE
STATEMENTS
Arto Perttula 7.11.2017 48
Generics
• Pass instance-specific information to an entity
• Ability to parameterize models using generics
• The values of generic parameters must be computable at design time
– Dynamic changes are not possible
• Use generics instead of hard-coded values in interface!
– Not all mac units are 32-bit wide, some are 16-bit and some 64-bit
entity mac is
generic (
data_width_g : integer := 4);
port (
clk : in std_logic;
rst_n : in std_logic;
a_in : in std_logic_vector(data_width_g-1 downto 0);
b_in : in std_logic_vector(data_width_g-1 downto 0);
c_in : in std_logic_vector(data_width_g-1 downto 0);
mac_out : out std_logic_vector(data_width_g*2-1 downto 0)
);
end mac;

Arto Perttula 7.11.2017 49


Generics (2) begin -- testbench

-- component instantiation
DUT: mac
Component declaration

architecture testbench of tb_mac is


generic map (
component mac data_width_g =>

Architecture body
generic ( data_width_c)
data_width_g : integer :=4); port map (
port ( clk => clk,
clk : in std_logic; rst_n => rst_n,
rst_n : in std_logic; a_in => a_to_mac,
a_in : in std_logic_vector(data_width_g-1 downto 0); b_in => b_to_mac,
b_in : in std_logic_vector(data_width_g-1 downto 0); c_in => c_to_mac,
c_in : in std_logic_vector(data_width_g-1 downto 0); mac_out => mac_result);
mac_out : out std_logic_vector(data_width_g*2-1 downto 0));
end component; ...

-- values to assign for component generics end testbench;


constant data_width_c : integer := 8;

-- Internal signals to/from DUT


Component instantiation.
signal clk : std_logic; Define the value of
signal rst_n : std_logic; generic(s) and attach the
signal a_to_mac : std_logic_vector(data_width_c-1 downto 0); interface signals
signal b_to_mac : std_logic_vector(data_width_c-1 downto 0);
signal c_to_mac : std_logic_vector(data_width_c-1 downto 0);
signal mac_result : std_logic_vector(data_width_c*2-1 downto 0);
Note:
 By using generic, this same code for mac can be used for
any data_width_g and it works without modifications
Local constant
We define the signals that  If generic value is not specified in the instantiation, the
are attached to the
default is used (in this case 4, as shown in previous slide’s
component in instantiation
entity declaration). Danger danger.

Arto Perttula 7.11.2017 50


Generic Use Case Examples (3)
1. Widths of port and internal signals
2. Sizes of register files and memories
3. Addresses
– E.g., own address, shared region in memory…
4. Enables for features
– Whether or not instantiate some sub-module
– Encrypt/decrypt/both, little/big-endian
5. File paths in test benches
• However, large number of generics makes verification harder
– How to test all (at least most) combinations?
– How to detect and prevent illegal combinations?
– New users might also get confused
• Default values simplify instantiation, BUT
– Responsible integrator always sets ALL generics explicitly
Arto Perttula 7.11.2017 51
Summary of Generics
• They are great! Use them!

Arto Perttula 7.11.2017 52


Statements: GENERATE
• Very important for hierarchical design
• generate statement makes possible to replicate (FOR GENERATE)
– Component instantiations
– Concurrent statements
• Also conditional replication/instantiation is possible (IF GENERATE)
– Whether a component is instantiated or not
– Whether concurrent statement/process is implemented or not
– Note that there is no ELSE GENERATE
• Example: DMA – direct memory access
– Parametrized amount of DMA channels
– Real code example from a research project
Arto Perttula 7.11.2017 53
Example:
Idea of DMA Component
• DMA copies data to/from dual-port memory from/to network
– Much faster than CPU-controlled communication
• CPU sets: src addr, dst addr, data amount, and command
• Example TX: Send 100 bytes starting from 0x200 in DPRAM to network addr 0x5000
• Example RX: If there’s data coming from network with addr 0xF000, put it to addr
0x164 in DPRAM, Interrupt CPU when 50 bytes have been received.
• There can be multiple RX transfers (=channels) pending – use FOR GENERATE

CPU dual-port RAM

instr.memory DMA Network IF Network


rxc rxc … rxc
54
Example of For-Generate Component
-- Component
channels : for i in 0 to n_chans_g-1 generate Parameters: HW: Ports:

Data_width_
i_rx_chan : n2h2_rx_chan Mem_addr_r(0)

_cmp_hi_
hibi_addr
generic map ( Channel 0 …

Id = 0
data_width_g => data_width_g, Irq_chan_r(0)
id_g => i,

g
...

Data_width_
addr_cmp_hi_g => hibi_addr_cmp_hi_g) … Mem_addr_r(1)

_cmp_hi_

hibi_addr
port map ( Channel 1
clk => clk, Irq_chan_r(1)

Id = 1
rst_n => rst_n,

g
avalon_addr_in => mem_addr_r(i),
...


irq_out => irq_chan_r(i)
);

Data_width_
Mem_addr_r

_cmp_hi_
n_chans_g-1
hibi_addr
end generate channels; …
Channel (n_chans_g-1)

 Hardware parameterized with generics, same ”base” for all
n_chans_g-1 Irq_chan_r

Id =
 In example, each channel has

g
(n_chans_g-1)
 Different identifier id_g
 Same signal widths data_width_g and addr_cmp_hi_g
 I/Os can be mapped to different signals
 Outputs must be mapped to different signals!
 In example, each channel has
 Different mem_addr_r and irq_chan_r (std_logic_vector position in 2D-array)
 Same clk and rst_n
Arto Perttula 7.11.2017 55
For-generate
• Note that the generic parameters can be result of a function, from a table etc.
– Very powerful
-- purpose: To determine proper relative frequencies
– Statically computed values, no dynamic parameters -- depending on the syncmode

i_hibi_nios : hibi_wrapper_r4 function determine_clk_freq (


generic map ( constant device_is_bus : boolean;
id_g => get_prior(i), constant syncmode : integer range 0 to 3;
-- … constant frequency : integer)
base_id_g => 2**id_width_c-1, return integer is
id_width_g => id_width_c, begin -- determine_clk_freq
addr_g => get_addr(i), case syncmode is
rel_bus_freq_g => determine_clk_freq(true, when 1 =>
fifo_sel_g, bus_freq_c), --asyn fast
rel_agent_freq_g => determine_clk_freq(false, if device_is_bus then
fifo_sel_g, cpu_freq_c), return bus_freq_c;
prior_g => get_prior(i), else
arb_type_g => arb_type_c(i), return hibi_sync_freq_c;
fifo_sel_g => fifo_sel_g, end if;
inv_addr_en_g => 0, when others =>
-- … --sync
) return frequency;
a) Generic value determined with function end case;
• Get_prior(i) return 0;
• Determine_clk_freq(..) end determine_clk_freq;
b) Generic value read from a constant table
• Arb_type_c(i) 56
Summary
• Combinatorial logic described with concurrent
statements and processes. Sequential logic only with
processes.
• Generics, if-generate, for-generate and assertions are
great
• Loop bounds, signal widths, signals slicing indices, and
generic values must be known at compile time
(=synthesis-time)
Arto Perttula 7.11.2017 57
TIPS AND PITFALLS

Arto Perttula 7.11.2017 58


Get Rid of Red Signals
• Red signals in wave form indicate serious problems!
• Your first task is to remove all red signals!
• There are 2 reasons
1. Signal does not have any value – undefined ’U’
– Any logic reading that signal will malfunction
– Likely caused by
a) Missing initialization during reset
b) Failed component instantiation during simulation bootup
• ”Component DUV is not bound”
• This is only warning in ModelSim
• This may be unnoticed if there are many messages and designer is not careful
– Note that some red signals are derived from those failing due to above reasons

Arto Perttula 7.11.2017 59


Get Rid of Red Signals (2)
2. Signal has conflicting values – result is ’X’
– It is driven in 2+ places in code that will be executed in parallel
a) Two processes (including reset part of synchronous process)
b) In process and concurrent assignment (=outside all processes)
c) Multiple concurrent assignments
d) Port of subcomponent and signal in higher level component
– Again, some red signals are derived from those failing due to above
reasons
• Reminder: Your first task is to remove all red signals!

Arto Perttula 7.11.2017 60



tb_conflict.vhd
library ieee; • sync: process (clk, rst_n)
• use ieee.std_logic_1164.all; • begin -- process conflicting_reset • gen_stimulus: process
• use ieee.numeric_std.all; • if rst_n = '0' then • begin -- process

• entity tb_conflict is • test1_duv_tb <= '0'; -- aargh2! Conlict with DUV's ouput • wait for period_c/2; -- align to rising edge
• • wait for period_c/3; -- wait "a little"
• end tb_conflict; • -- Other reset values here •
• counter_r <= (others => '0'); • wait for 10 * period_c; -- aargh5! a_tb_duv not given any value
• architecture behavioral of tb_conflict is • •
• • a_tb_duv <= '0';
• constant period_c : time := 10 ns; • elsif clk'event and clk = '1' then
• wait for 10 * period_c;
• • -- Regular sync. logic here • a_tb_duv <= '1';
• signal clk : std_logic := '0'; • counter_r <= counter_r+1; • wait for 1 * period_c;
• signal rst_n : std_logic; • a_tb_duv <= '0';
• signal a_tb_duv : std_logic; • if to_integer(counter_r) = 20 then • wait for 10 * period_c;
• test1_duv_tb <= '1'; -- aargh3!
• signal test0_duv_tb : std_logic; • • a_tb_duv <= '1';
• signal test1_duv_tb : std_logic; • elsif to_integer(counter_r) = 30 then • wait for 1 * period_c;
• test1_duv_tb <= 'Z'; -- suspicious but works • a_tb_duv <= '0';
• signal counter_r : unsigned ( 10-1 downto 0); • wait for 10 * period_c;
• elsif to_integer(counter_r) = 35 then
• • test1_duv_tb <= 'H'; -- suspicious but works
• begin -- behavioral • •
• elsif to_integer(counter_r) = 40 then • a_tb_duv <= '1';
• DUV : entity work.var1 • test1_duv_tb <= 'L'; -- suspicious but works • wait for 1 * period_c;
• port map ( • • a_tb_duv <= '0';
• clk => clk, • end if; • wait for 10 * period_c;
• rst_n => rst_n, • end if;
• a_in => a_tb_duv, • end process sync;
• test0_out => test0_duv_tb, • a_tb_duv <= '1';
• test1_out => test1_duv_tb • counter_r <= (others => 'Z'), • wait for 10 * period_c;
• ); • (others => '0') after 50 * period_c; --aargh4! • a_tb_duv <= '0';
• wait for 10 * period_c;
• clk <= not clk after period_c/2;
• rst_n <= '0', '1' after 5* period_c; • wait for 10 * period_c;
• •
• test0_duv_tb <= '0'; -- aargh1! Conlict with DUV's ouput • assert false report "Simulation ended succesfully" severity failure;
• wait;

• end process gen_stimulus;

• end behavioral;
61
Get Rid of Red Signals (3)
Conflict between ’1’ driven
Undefined value ’U’ at by DUV and ’0’ driven by
input ruins both outputs TB- Short-circuit between
tb_conflict.vhd
GND and VDD. zap!

Conflict between
Conflict between Conflict between Values ’Z’, ’H’ or values given in
’0’ driven by DUV ’1’ driven by DUV ’L’ driven by TB process and in
and ’1’ driven by and ’0’ driven by do not cause concurrent
TB TB. conflicts. assignment 62
Timing Example: Signal vs. Variable
architecture rtl of ac is
signal x_r : integer; Process is triggered at clock edge.
signal y_r : integer; Variable is updated instantly at the clock edge.
signal z : integer; Signal is updated just after the clock edge Simulator view:
begin -- rtl

value: process (clk, rst_n)


variable k_v : integer;
begin -- process value
if rst_n = '0' then
x_r <= 0;
y_r <= 0;

elsif clk'event and clk = '1' then


k_v := to_integer(unsigned(a_in));
x_r <= to_integer(unsigned(a_in));

y_r <= k_v + x_r;


Note: difference in variable and signal timing has been
end if; exaggerated in fig. In simulator, they look the same
end process value; y_r(t) = k_v (t) + x_r(t),
Note: variables are not necessarily visible at all in older i.e. a_in(t)+a_in(t-1)
z <= y_r;
simulator’s wave window! Debugging gets
z <= y_r is a continuous
end rtl; complicated… assignment, happens
instantly (not within the clock
Arto Perttula region)
Signal vs. Variable Value Update (2)
architecture rtl of ac is
signal x_r : integer; • Note that variable is used within
signal y_r : integer;
signal z : integer;
clock sensitive process
begin -- rtl
– It’s value is updated only when
value: process (clk, rst_n) there’s event on clock (in
variable k_v : integer;
begin -- process value simulator!)
if rst_n = '0' then
x_r <= 0; • However, when implemented,
y_r <= 0;
k_v is part of the comb. logic
elsif clk'event and clk = '1' then
k_v := to_integer(unsigned(a_in));
”cloud” that constantly executes
x_r <= to_integer(unsigned(a_in));
– Short-hand notation for part of
y_r <= k_v + x_r; the comb. logic
end if; a_in – Immediate value assignment
end process value; k_v
z <= y_r;

end rtl;
D Q x_r + D Q

7.11.2017 64
Signal vs. Variable Value Update (3)
architecture rtl of ac is architecture rtl of ac is
signal x_r : integer; signal x_r : integer;
signal y_r : integer; signal y_r : integer;
signal z : integer; signal z : integer;
begin -- rtl begin -- rtl

value: process (clk, rst_n) value: process (clk, rst_n)


variable k_v : integer;
begin -- process value begin -- process value
if rst_n = '0' then equivalent if rst_n = '0' then
x_r <= 0;
y_r <= 0;

elsif clk'event and clk = '1' then


= x_r <= 0;
y_r <= 0;

elsif clk'event and clk = '1' then


k_v := to_integer(unsigned(a_in)); -- var removed
x_r <= to_integer(unsigned(a_in)); x_r <= to_integer(unsigned(a_in));

y_r <= k_v + x_r; y_r <= unsigned(a_in) + x_r;

end if; end if;


end process value; end process value;

z <= y_r; In this case, the variable is not z <= y_r;


very useful, but used for
end rtl; demonstration purposes only. end rtl; 7.11.2017 65
Example (4): Simulation vs. Real HW
architecture rtl of ac is
signal x_r : integer; Input changes and internal
signal y_r : integer;
signal z : integer; wire k_v has the exactly the In HW:
begin -- rtl same value.
value: process (clk, rst_n)
variable k_v : integer;
begin -- process value
if rst_n = '0' then
x_r <= 0;
y_r <= 0;

elsif clk'event and clk = '1' then


k_v := to_integer(unsigned(a_in));
x_r <= to_integer(unsigned(a_in));

y_r <= k_v + x_r;

end if;
end process value; Note: simulator’s view does not fully match real
world, although the register x_r and outputs y_r
z <= y_r;
and z are the same!
end rtl; 7.11.2017 66
VHDL Pitfalls
1. Identifiers
– VHDL isn’t case sensitive (e.g., Input and input are the same)
– (But some tool’s are…)
2. Misspelled If statement
– ELSIF written as ELSE IF
3. Wrong string delimiters
– ’0001’ instead of ”0001”, or ”0” instead of ’0’
– 0 instead of ’0’ or vice versa
4. Misused reserverd words
– Reserved words used as object names: IN , OUT, BUFFER, AND, NAND, OR
5. Incomplete case statement
– VHDL requires all conditions to be presented
– Conditions must be locally static (determined at compile-time)

Arto Perttula 7.11.2017 67


VHDL Pitfalls (2)
6. Expression evaluation
– Following operations have equal precedence: AND, OR, NAND, NOR, XOR
– Example of illegal expression a OR b AND c
– Corrected expression a OR (b AND c)
7. Signal assignment from multiple sources
– E.g., signal is reset in sequential process, but it is assigned outside the process
– You must define only one driver for a signal!
– A process, a concurrent statement…
– Three-state/Weak logic are allowed at chip I/O

Arto Perttula 7.11.2017 68


Notes on Syntax
• Signal declarations are before architecture’s begin clause
• Signal assignment is <=, variable assignment is :=
– Depends on the object in the left hand side
– Source type can be different sig <= var; var := sig
• Equality comparison is =, inequality /=
• Entity ports and generic declarations
– Lines end with semicolon (;) except the last one
• Component instantiation
– Assignments end with comma (,) except the last one
– Mapping symbol points to right =>
• Emacs is a dear friend and helps a lot in these!
i_rx_chan_1 : n2h2_rx_chan
generic map (
data_width_g => data_width_g,
...
No semi-colon
addr_cmp_hi_g => hibi_addr_cmp_hi_g)
port map ( Points to the right
clk => clk,
rst_n => rst_n,
avalon_addr_in => mem_addr_r(i),
...
irq_out => irq_chan_r(i)
No comma allowed
69
);
Mistakes in Simulation vs. Synthesis

• The process sensitivity list is incomplete!


– May hide bugs in the design
– Synthesis ignores sensitivity list but simulation relies on it’s completeness
– Always use compile option –check_synthesis with ModelSim
• Using non-synthesizable structures or datatypes
• E.g., using don’t care operator
– E.g., when ”1--” => …
– May simulate well (ModelSim supports) but does not synthesize!
• Behavior of reset and three-state logic ’Z’
• Timing of variables
• Delays and indefinite loops are not synthesizable

Arto Perttula 7.11.2017 70


VHDL Pitfall: NULL-Statement in CASE
--
-- Null statement in case statement
-- at combinatorial process
-- produces latch in synthesis to hold the last value.
--
ENTITY null_statement IS
PORT (
sel : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
output : OUT STD_LOGIC);
END null_statement;
ARCHITECTURE example OF null_statement IS
BEGIN -- Example
PROCESS (sel)
BEGIN -- PROCESS
CASE sel IS
WHEN "00" => output <= ’0’;
WHEN "10" => output <= ’1’;
WHEN OTHERS => NULL;
END CASE;
END PROCESS;
END example;

Arto Perttula 7.11.2017 71


Top 20 Errors in VHDL
• This is a list of the most common VHDL errors. The Top 10 account for
about 40% of all errors. The Top 20 account for about 60% of all errors.
• Source: Doulos VHDL Golden reference guide

!
!

Arto Perttula 7.11.2017 72


EDA Tool Pitfalls
• These apply to many languages, though
1. Some tools behave stRangely if there are white spaces in paths
– E.g., My Documents\rocket.vhd, source codes\cool_stuff.vhd
– E.g., EDA tool just freezes or doesn’t find a file (without telling what it’s looking for…)
– Scandinavian alphabets å,ä,ö,Å,Ä,Ö are sometimes confusing also
2. Tool project files store file paths as absolute instead of relative ones
– E.g., rom_init =/home/jeppe/sw/prom.hex instead of ../sw/prom.hex
– Hard/impossible to move project files
• To other designers or your customer!
• To directory without white spaces in its name
– More common than you think!
– The same path definition may be stored into multiple files
• Correction is tedious at best, impossible in case of binary files
– Re-creating a project file from scratch and imitating the settings is error-prone, annoying and waste of time

Arto Perttula 7.11.2017 73


EDA Tool Pitfalls (2)
4. Version incompatibilities
– Opening files in different version of the tool fails
• Worst part:some parts seem to work, so you’ll start working until some things silently fail and you’ll go crazy
• Worst part #2: file does not tell which version it is. Go figure!
– ToolA v1.2 works well only with ToolB 2.71 but not with older or newer ones
• Worst part: vendor does not offer older versions anymore
– You must document clearly which versions you have used
5. Strange problems when developing in both Linux and Windows (and Cygwin)
– Both / and \ are used in path definitions
– Different line breaks (use dos2unix or unix2dos)
– Latin-1 vs. UTF-8 vs. some other character encoding
– Certain tools/licenses are available only for Linux and some Windows, and you’ll need both
6. Windows both allows and does not allow file name to be over 255 characters
– Tool might be able to create a temporary file with such a name…
– But the same tool cannot read or remove it!
Arto Perttula 7.11.2017 74
EDA Tool Pitfalls (3)
7. Too few user privileges
– Some tools store user’s information into installation directory…
– But user doesn’t necessarily have write access to that folder, only the admin folks who installed the SW
8. Vendor lock-in: moving to other tools is too difficult
– Customer is tied to certain tool or chip vendor because it is too laborious and costly to move all legacy
code to new environment
a) Proprietary file format that cannot be converted to others
b) Standard format is broken on purpose by incorporating ”helpful additions”
• Might prevent opening and editing the files in other programs
c) Some tools pose stricter rules which code constructs are acceptable
d) Organization shares some data only in a stupid format, say .pdf instead of .xlsx
9. Node-locked licenses are tied to certain computer, e.g., it’s MAC address
– Let’s hope that one computer doesn’t break…
– You’ll may need a wired LAN, not just any internet connection

Arto Perttula 7.11.2017 75


EDA Tool Pitfalls (4)
10. Internal database gets corrupted
– Some things work, some things do not, go figure
– Remove the generated files and try again
– > rm syn/db; rm sim/work
– Therefore, you must keep your sources strictly separated from the
project setting files and generated ones
11. User does not read error and warning messages carefully
– Not actually a tool problem… ;)
– However, vague messages are tools fault
• ”A file not found” Which file? Where did you look for it?
Arto Perttula 7.11.2017 76

You might also like