0% found this document useful (0 votes)
34 views

Design Synthesis

The document discusses designing systems using Verilog including modules, hierarchy, operators, continuous vs procedural assignments, multiplexers, priority encoders, sequential logic like flip-flops and registers, and arbitrary counting sequences.

Uploaded by

karanp859384
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views

Design Synthesis

The document discusses designing systems using Verilog including modules, hierarchy, operators, continuous vs procedural assignments, multiplexers, priority encoders, sequential logic like flip-flops and registers, and arbitrary counting sequences.

Uploaded by

karanp859384
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Design Synthesis using

(System)Verilog

LE

LE

LE

LE

LE

LE

LE

LE

M
E
M

LE

M
E
M

LE

LE

LE

Modules
Module design entity
ports and description
module and_or_1_bit (input logic x, y,
output logic f, g);

x
y

assign f = x & y;
assign g = x | y;

endmodule

Hierarchy module instantiation


module and_or_8_bits (input logic[7:0] x, y,
output logic[7:0] f, g);
and_or_1_bit
and_or_1_bit
and_or_1_bit
and_or_1_bit

bit0(.x(x[0]),
bit1(.x(x[1]),
bit2(.x(x[2]),
bit3(.x(x[3]),

.y(y[0]),
.y(y[1]),
.y(y[2]),
.y(y[3]),

.f(f[0]),
.f(f[1]),
.f(f[2]),
.f(f[3]),

.g(g[0]));
.g(g[1]));
.g(g[2]));
.g(g[3]));

and_or_1_bit
and_or_1_bit
and_or_1_bit
and_or_1_bit

bit4(.x(x[4]),
bit5(.x(x[5]),
bit6(.x(x[6]),
bit7(.x(x[7]),

.y(y[4]),
.y(y[5]),
.y(y[6]),
.y(y[7]),

.f(f[4]),
.f(f[5]),
.f(f[6]),
.f(f[7]),

.g(g[4]));
.g(g[5]));
.g(g[6]));
.g(g[7]));

endmodule

Actually it can be done simpler


module and_or_8_bits (input logic[7:0] x, y,
output logic[7:0] f, g);

assign f = x & y;
assign g = x | y;
endmodule

Operators
The most relevant Verilog operators
(for this stage of our course)

Operator Usage
Description
Logical Operators (1-bit result true/false)
!
&&
||

!A
A && B
A || B

Is A NOT true?
Are both A AND B true?
Are either A OR B true?

Bitwise Operators (multiple-bits result)


~
&
|
^
~^
^~

~A
A&B
A|B
A^B
A ~^ B
A^~ B

Complement (invert/negate) each bit of A


AND each bit of A with each bit of B
OR each bit of A with each bit of B
Exclusive OR (XOR) each bit of A with each bit of B
XNOR each bit of A with each bit of B

Unary Operators (1-bit result)


&
~&
|
~|
^
~^

&A
~&A
|A
~|A
^A
~^A

AND all bits in signal A


NAND all bits in signal A
OR all bits in signal A
NOR all bits in signal A
XOR all bits in signal A
XNOR all bits in signal A

Arithmetic Operators (multiple-bits result)


+
-

A+B
A-B
-A

Add A to B
Subtract B from A
Take 2s complement of A

Relational Operators (1-bit result)


==
!=
<
>
<=
>=

A==B
A!=B
A<B
A>B
A<=B
A>=B

Is A equal to B?
Is A not equal to B?
Is A less than B?
Is A greater than B?
Is A less than or equal to B?
Is A greater than or equal to B?

Continuous Signal Assignments vs.


Procedural Signal Assignments
module and_or_1_bit (input logic x, y,
output logic f, g);
assign f = x & y; /* continuous signal assignment */
always_comb
begin
g = x | y; // procedural signal assignment
// = is called blocking assignment
end
endmodule

The order of continuous signal


assignments (assign statements),
always blocks or module
instantiations DOES NOT matter!
The order of procedural signal
assignments in any always block
DOES matter!
module and_xor_1_bit (input logic x, y,
output logic f, g);
assign f = x & y;
always_comb
begin
g = x | y; // this statement will be dismissed!
g = x ^ y;
end
endmodule

Multiplexers
Using continuous signal assignment
module mux_2_to_1 (input logic sel,
input logic[7:0] x, y,
output logic[7:0] f);
assign f = sel ? x : y;
endmodule

Using procedural signal assignment


module mux_2_to_1 (input logic sel,
input logic[7:0] x, y,
output logic[7:0] f);
always_comb
begin
if (sel) f = x;
else f = y;
end
endmodule

or
module mux_2_to_1 (input logic sel,
input logic[7:0] x, y,
output logic[7:0] f);
always_comb
begin
f = y;
if (sel) f = x;
end
endmodule

Multiple Drivers Problem


module multiple_drivers (input logic sel1, sel2,
input logic[7:0] x, y,
output logic[7:0] f);
always_comb
begin
if (sel1) f = x;
else f = y;
end
always_comb
begin
if (sel2) f = y; // bad assignment
else f = x;
// it will NOT compile
end
endmodule

Short circuit between two signal paths:


impossible to implement unless the
targeted fabric provides some form of
resolution for it (not in our case)!
sel2
x
y

0
1

f
sel1
0
1

problem

Multiple Drivers Problem


The designer MUST decide which
signal path takes priority!

module multiple_drivers_fixed (input logic sel1, sel2,


input logic[7:0] x, y,
output logic[7:0] f);
logic[7:0] g; // internal signal within the module
always_comb
begin
if (sel1) f = x;
else f = g;
end
always_comb
begin
if (sel2) g = y;
else g = x;
end
endmodule

or
module multiple_drivers_fixed (input logic sel1, sel2,
input logic[7:0] x, y,
output logic[7:0] f);
assign f = sel1 ? x : (sel2 ? y : x);
endmodule

Priority Encoders
module priority_encoder (input logic c1, c2, c3,
input logic[7:0] w, x, y, z,
output logic[7:0] f);
always_comb
begin
if (c1) f = w;
else if (c2) f = x;
else if (c3) f = y;
else f = z;
end
endmodule

Equivalent code
module priority_encoder (input logic c1, c2, c3,
input logic[7:0] w, x, y, z,
output logic[7:0] f);
always_comb
begin
f = z;
if (c3) f = y;
if (c2) f = x;
if (c1) f = w;
end
endmodule

Sequential Logic
Fundamental sequential element edge-triggered Data (or D) flip-flop with
asynchronous reset (active low)
module d_flip_flop (input logic clock, resetn,
input logic d,
output logic q);
always_ff @(posedge clock or negedge resetn) // sensitivity list
begin
if (!resetn)
q <= 1'b0;
else
q <= d;
// this is a non-blocking assignment
end
endmodule

Combinational logic can be described


either using continuous assignments
or procedural assignments in
always or always_comb blocks
Sequential logic can be described
using always or always_ff blocks
Latches can be described using
always or always_latch blocks
(to be discussed later)

Registers
8-bit register with synchronous enable
module enabled_register (input logic clock, resetn,
input logic en,
input logic[7:0] d,
output logic[7:0] q);
always_ff @(posedge clock or negedge resetn)
begin
if (resetn == 1'b0) // different way to test for active low
q <= 8'b0000_0000;
else
begin
if (en == 1'b1)
q <= d;
end
end
endmodule

All the signals on the left hand side of


non-blocking procedural assignments
in always_ff blocks will end up as state
elements (flip-flops)!
IMPORTANT coding conventions:
in always_comb blocks use only
blocking assignments
in always_ff blocks use only
non-blocking assignments

Counters
8-bit modulo 201 up counter
module modulo_counter (input logic clock, resetn,
input logic en,
output logic[7:0] count);
logic load;
always_ff @(posedge clock or negedge resetn)
begin
if (!resetn)
count <= 8'h00;
else
begin
if (en)
begin
if (load)
count <= 8'h00;
else
count <= count + 8'd1;
end
end
end
assign load = (count == 8'd200);
endmodule

Note: Resetn will not be drawn

Counters
Equivalent code explaining
present_count and next_count
module modulo_counter (input logic clock, resetn,
input logic en,
output logic[7:0] count);
logic[7:0] present_count, next_count;
assign count = present_count;
always_ff @(posedge clock or negedge resetn)
begin
if (!resetn)
present_count <= 8'h00;
else
if (en)
present_count <= next_count; // non-blocking assignment
end
always_comb
begin: next_state_logic // this is a label for naming a block
logic load;
// declare a signal only for this block
load = (present_count == 8'd200); // blocking assignment
if (load)
next_count = 8'h00;
else
next_count = present_count + 8'd1;
end
endmodule

Important note: if a signal is driven in a sequential


block (if it appears on the left-hand side of the
assignments in an always_ff or always block
with the sensitivity list as shown in these
examples), then its occurrences on the right-hand
side of assignments stand for the present (or
current) state that was computed in the previous
clock cycle!

Arbitrary Counting Sequences


Reflected gray code sequence

module gray_code_counter (input logic clock, resetn,


output logic[3:0] gray_code_count);
logic[3:0] binary_count;
always_ff @ (posedge clock or negedge resetn)
if (resetn == 1'b0) binary_count <= 4'd0;
else binary_count <= binary_count + 4'd1;
always_comb
// next state logic
case (binary_count)
4'd1: gray_code_count = 4'd1; // blocking assignment
4'd2: gray_code_count = 4'd3;
4'd3: gray_code_count = 4'd2;
4'd4: gray_code_count = 4'd6;
4'd5: gray_code_count = 4'd7;
4'd6: gray_code_count = 4'd5;
4'd7: gray_code_count = 4'd4;
4'd8: gray_code_count = 4'd12;
4'd9: gray_code_count = 4'd13;
4'd10: gray_code_count = 4'd15;
4'd11: gray_code_count = 4'd14;
4'd12: gray_code_count = 4'd10;
4'd13: gray_code_count = 4'd11;
4'd14: gray_code_count = 4'd9;
4'd15: gray_code_count = 4'd8;
default: gray_code_count = 4'd0;
endcase
endmodule

Arbitrary Counting Sequences


Use a state machine approach
clock

11 10 14 15 13 12

gray_code_count

revised
mapping
logic

gray_code_count

module gray_code_counter (input logic clock, resetn,


output logic[3:0] gray_code_count);
always_ff @ (posedge clock or negedge resetn)
if (resetn == 1'b0) gray_code_count <= 4'd0;
else
case (gray_code_count)
// next state logic
4'd0: gray_code_count <= 4'd1; // non-blocking assignment
4'd1: gray_code_count <= 4'd3;
4'd3: gray_code_count <= 4'd2;
4'd2: gray_code_count <= 4'd6;
4'd6: gray_code_count <= 4'd7;
4'd7: gray_code_count <= 4'd5;
4'd5: gray_code_count <= 4'd4;
4'd4: gray_code_count <= 4'd12;
4'd12: gray_code_count <= 4'd13;
4'd13: gray_code_count <= 4'd15;
4'd15: gray_code_count <= 4'd14;
4'd14: gray_code_count <= 4'd10;
4'd10: gray_code_count <= 4'd11;
4'd11: gray_code_count <= 4'd9;
4'd9: gray_code_count <= 4'd8;
default: gray_code_count <= 4'd0;
endcase
endmodule

This implementation uses only four LEs (in each LE


we have one flip-flop used to store the state and one
4-LUT that implements the next state logic).

Arbitrary Counting Sequences


What happens if we re-specify the
next state logic as a priority encoder?
module gray_code_counter (input logic clock, resetn,
output logic[3:0] gray_code_count);
always_ff @ (posedge clock or negedge resetn)
if (resetn == 1'b0) gray_code_count <= 4'd0;
else begin
gray_code_count <= 4'd0; // non-blocking assignments
if (gray_code_count == 4'd0) gray_code_count <= 4'd1;
if (gray_code_count == 4'd1) gray_code_count <= 4'd3;
if (gray_code_count == 4'd3) gray_code_count <= 4'd2;
if (gray_code_count == 4'd2) gray_code_count <= 4'd6;
if (gray_code_count == 4'd6) gray_code_count <= 4'd7;
if (gray_code_count == 4'd7) gray_code_count <= 4'd5;
if (gray_code_count == 4'd5) gray_code_count <= 4'd4;
if (gray_code_count == 4'd4) gray_code_count <= 4'd12;
if (gray_code_count == 4'd12) gray_code_count <= 4'd13;
if (gray_code_count == 4'd13) gray_code_count <= 4'd15;
if (gray_code_count == 4'd15) gray_code_count <= 4'd14;
if (gray_code_count == 4'd14) gray_code_count <= 4'd10;
if (gray_code_count == 4'd10) gray_code_count <= 4'd11;
if (gray_code_count == 4'd11) gray_code_count <= 4'd9;
if (gray_code_count == 4'd9) gray_code_count <= 4'd8;
end
endmodule

Control/data path
Control path
finite state machine (FSM)
Data path
registers, arithmetic units (adders,
multipliers), logic units, shift
registers, counters, comparators,
embedded memories,

Status signals
comparator results, zero detect,
Control signals
synchronous enable, load, shift,

FSM
Up/down 2-bit counter with 0 detect
S0/
z=1
S3/
z=0

S1/
z=0
S2/
z=0

module fsm

(input logic clock, resetn, w,


output logic z);

logic[1:0] state;
parameter S0 = 2'b00;
parameter S1 = 2'b01;
parameter S2 = 2'b10;
parameter S3 = 2'b11;
always_ff @ (posedge clock or negedge resetn)
begin
if (!resetn)
state <= S0;
else
case (state)
S0: if (w) state <= S1; else state
S1: if (w) state <= S2; else state
S2: if (w) state <= S3; else state
S3: if (w) state <= S0; else state
endcase
end
assign z = (state == S0);
endmodule

<=
<=
<=
<=

S3;
S0;
S1;
S2;

FSM

module fsm

(input logic clock, resetn, w,


output logic z);

logic[1:0] present_state, next_state;


parameter S0 = 2'b00;
parameter S1 = 2'b01;
parameter S2 = 2'b10;
parameter S3 = 2'b11;
// present state logic
always_ff @ (posedge clock or negedge resetn)
begin
if (!resetn) present_state <= S0;
else present_state <= next_state;
end
// next state logic
always_comb
begin
case (present_state)
S0: if (w) next_state
S1: if (w) next_state
S2: if (w) next_state
S3: if (w) next_state
endcase
end
// output logic
always_comb
begin
z = (present_state == S0);
end
endmodule

=
=
=
=

S1;
S2;
S3;
S0;

else
else
else
else

next_state
next_state
next_state
next_state

=
=
=
=

S3;
S0;
S1;
S2;

Case Study: Pacemaker


Artificial pacemaker
medical device that regulates heart beats
listens to hearts electrical rhythm and if
abnormal activity is sensed then it sends
precisely-timed electrical signals

average heartbeat approx 70 pulses per minute


if ventricle contraction is not sensed in due time,
a ventricle stimulation is applied by the digital
circuitry treats bradycardia (slow heart rate)
can be extended to monitoring and stimulating
also the right atrium - called atrioventricular or
dual-chamber pacemakers
can be further extended to adapt to motion and
breathing rhythms called rate-responsive
more complex (yet similar) digital circuitry can be
used for implantable cardioverterdefibrillators

Pacemaker: Control/Data Path


S_REINITIALIZE COUNTER/
reload = 1, ventricle stimulation = 0
ventricle contraction
S_WAIT VENTRICLE CONTRACTION/
reload = 0, ventricle stimulation = 0
zero detect

any other case

S_APPLY VENTRICLE STIMULATION/


reload = 0, ventricle stimulation = 1

module pacemaker (input logic clock, resetn


// clock period is assumed 10 ms
input logic ventricle_contraction,
output logic ventricle_stimulation);
logic[7:0] counter; // keeps track of how much time has passed since last contraction
logic reload;
// used to re-initialize the counter (control signal)
logic zero_detect; // used to point that no contraction was sensed (status signal)
logic[1:0] present_state, next_state; // pacemaker states
parameter S_REINITIALIZE_COUNTER = 2'b00;
parameter S_WAIT_VENTRICLE_CONTRACTION = 2'b01;
parameter S_APPLY_VENTRICLE_STIMULATION = 2'b10;
always_ff @ (posedge clock or negedge resetn)
if (!resetn) counter <= 8'd0;
else if (reload) counter <= 8'd84; // approx 70 pulses per minute
else counter <= counter - 8'd1;
always_ff @ (posedge clock or negedge resetn)
if (!resetn) present_state <= S_REINITIALIZE_COUNTER;
else present_state <= next_state;
always_comb
case (present_state)
S_REINITIALIZE_COUNTER: next_state = S_WAIT_VENTRICLE_CONTRACTION;
S_WAIT_VENTRICLE_CONTRACTION: begin
if (ventricle_contraction) next_state = S_REINITIALIZE_COUNTER;
else if (zero_detect) next_state = S_APPLY_VENTRICLE_STIMULATION;
else next_state = S_WAIT_VENTRICLE_CONTRACTION;
end
S_APPLY_VENTRICLE_STIMULATION: next_state = S_REINITIALIZE_COUNTER;
default: next_state = S_REINITIALIZE_COUNTER;
endcase
assign zero_detect = (counter == 8'd0);
assign reload = (present_state == S_REINITIALIZE_COUNTER);
assign ventricle_stimulation = (present_state == S_APPLY_VENTRICLE_STIMULATION);
endmodule

Pacemaker: Control/Data Path


There is no need to declare explicitly
all the interface signals between the
control path and the data path
Shorter equivalent code (implicit)
module pacemaker (input logic clock, resetn,
input logic ventricle_contraction,
output logic ventricle_stimulation);
logic[7:0] counter;
enum logic[1:0] {S_REINITIALIZE_COUNTER,
S_WAIT_VENTRICLE_CONTRACTION,
S_APPLY_VENTRICLE_STIMULATION} state; // pacemaker states
always_ff @ (posedge clock or negedge resetn)
if (!resetn) begin
state <= S_REINITIALIZE_COUNTER;
counter <= 8'd0;
end else begin
counter <= counter - 8'd1;
case (state)
S_REINITIALIZE_COUNTER: begin
state <= S_WAIT_VENTRICLE_CONTRACTION;
counter <= 8'd84;
end
S_WAIT_VENTRICLE_CONTRACTION: begin
if (ventricle_contraction)
state <= S_REINITIALIZE_COUNTER;
else if (counter == 8'd0)
state <= S_APPLY_VENTRICLE_STIMULATION;
end
S_APPLY_VENTRICLE_STIMULATION: state <= S_REINITIALIZE_COUNTER;
default: state <= S_REINITIALIZE_COUNTER;
endcase
end
assign ventricle_stimulation = (state == S_APPLY_VENTRICLE_STIMULATION);
endmodule

Pacemaker: Control/Data Path


How does the design change for
dual-chamber pacemakers?

What about rate-responsive


pacemakers?
The data path will have more counters/registers
There will be additional states in the control path
More interface signals between them

Most importantly, the design approach


and the coding style stay the same!

Shift registers
Can be described using a for loop;
or signal concatenation {,,,};
or using the shift operators (e.g., >>)
`define DATA_WIDTH 16

// used outside the module to


// parameterize the design ports
module shift_register (input logic resetn, clock, serial_in, load,
input logic[`DATA_WIDTH-1:0] data_in,
output logic serial_out,
output logic[`DATA_WIDTH-1:0] data_out);
// right shift register
always_ff @(posedge clock or negedge resetn)
begin
if (!resetn)
data_out <= {`DATA_WIDTH{1'b0}}; // signal concatenation
// equivalent to: data_out <= `DATA_WIDTH'd0;
else
if (load)
data_out <= data_in;
else
begin : right_shift
// label for a block of statements
integer i;
// integer variable used as an iterator
for (i=`DATA_WIDTH-1; i>0; i=i-1)
data_out[i-1] <= data_out[i];
data_out[`DATA_WIDTH-1] <= serial_in;
end
// alternative code based on signal concatenation
/* data_out[`DATA_WIDTH-1:0] <= {serial_in, data_out[`DATA_WIDTH-1:1]}; */
// alternative code based on the >> operator
/* data_out <= (data_out >> 1);
data_out[`DATA_WIDTH-1] <= serial_in; */
end
assign serial_out = data_out[0];
endmodule

Bit counting
Combinational implementation for loop
`define INPUT_WIDTH 16
`define OUTPUT_WIDTH 5
module bit_count

(input logic[`INPUT_WIDTH-1:0] data_in,


output logic[`OUTPUT_WIDTH-1:0] data_out);

always_comb
begin : combinational_solution
integer i;
data_out = `OUTPUT_WIDTH'd0;
for (i=0; i <`INPUT_WIDTH; i+=1)
if (data_in[i])
data_out = data_out + `OUTPUT_WIDTH'd1;
end
endmodule

+1
data_in[0]

data_in[1]

data_in[14]

data_in[15]

0
1'b0
1'b1

+1

data_in
0

16

Load
0
0

+1

data_out
5

data_out

Load
SO

Clock

<<

SI

shift register
5

Combinational implementation

Sequential implementation

// sequential implementation that uses one shift register and one counter
module bit_count

(input logic resetn, clock, load,


input logic[`INPUT_WIDTH-1:0] data_in,
output logic[`OUTPUT_WIDTH-1:0] data_out);

logic[`INPUT_WIDTH-1:0] shift_register;
always_ff @(posedge clock, negedge resetn)
begin
if (!resetn) begin
shift_register <= `INPUT_WIDTH'd0;
data_out <= `OUTPUT_WIDTH'd0;
end else begin
if (load) begin
shift_register <= data_in;
data_out <= `OUTPUT_WIDTH'd0;
end else begin
shift_register <= (shift_register << 1); // left shift
if (shift_register[`INPUT_WIDTH-1])
data_out <= data_out + `OUTPUT_WIDTH'd1;
end
end
end
endmodule

Maximum Element in an Array


Combinational solution
`define DATA_WIDTH 16
`define ARRAY_SIZE 16
`define ARRAY_LOG_SIZE 4
module maximum_element (input logic clock, resetn, start,
input logic[`DATA_WIDTH-1:0] data_in,
output logic[`DATA_WIDTH-1:0] data_out);
logic[`DATA_WIDTH-1:0] register_file[`ARRAY_SIZE-1:0];
logic[`ARRAY_LOG_SIZE-1:0] load_counter;
logic load;
always_ff @(posedge clock, negedge resetn) begin
if (!resetn) begin : reset_register_file
integer i;
for (i=0; i<`ARRAY_SIZE; i+=1)
register_file[i] <= `DATA_WIDTH'd0;
load_counter <= `ARRAY_LOG_SIZE'd0; load <= 1'b0;
end else begin
if (start) load <= 1'b1;
else if (load_counter == {`ARRAY_LOG_SIZE{1'b1}}) load <= 1'b0;
if (load) begin
register_file[load_counter] <= data_in;
load_counter <= load_counter + `ARRAY_LOG_SIZE'd1;
end
end
end
always_comb begin : combinational_implementation_for_max_element
integer i;
data_out = `DATA_WIDTH'd0;
for (i=0; i <`ARRAY_SIZE; i+=1)
if (register_file[i] > data_out)
data_out = register_file[i];
end
endmodule

Maximum Element in an Array


Sequential solution
module maximum_element (input logic clock, resetn, start,
input logic[`DATA_WIDTH-1:0] data_in,
output logic[`DATA_WIDTH-1:0] data_out);
logic[`DATA_WIDTH-1:0] register;
logic[`ARRAY_LOG_SIZE-1:0] load_counter;
logic load;
always_ff @(posedge clock, negedge resetn)
begin
if (!resetn)
begin
load <= 1'b0;
register <= `DATA_WIDTH'd0;
load_counter <= `ARRAY_LOG_SIZE'd0;
data_out <= register;
end else begin
if (start) load <= 1'b1;
else if (load_counter == {`ARRAY_LOG_SIZE{1'b1}}) load <= 1'b0;
if (load) begin
register <= data_in;
load_counter <= load_counter + `ARRAY_LOG_SIZE'd1;
end
if (register > data_out) data_out <= register;
/* if a signed (2s complement) comparator is to be used */
/* if ($signed(register) > $signed(data_out)) data_out <= register; */
if (start && !load) begin
register <= `ARRAY_LOG_SIZE'd0;
data_out <= `ARRAY_LOG_SIZE'd0;
end
end
end
endmodule

Latches
Level sensitive storage elements
module latch_example1 (input logic enable, data_in,
output logic data_out);
always_latch
begin
if (enable)
data_out = data_in;
end
endmodule

module latch_example2 (input logic c1, c2, a, b,


output logic f, g);
always_latch
begin
if (c1) begin
f = a;
end else if (c2) begin
g = b;
end
end
endmodule

module latch_example3 (input logic c1, c2,


input logic a, b,
output logic f, g);
always_latch
begin
if (c1) begin
f = a;
g = b;
end else if (c2) begin
f = b;
g = a;
end
end
endmodule

Latches
Both case & if statements infer latches
module latch_example4 (input logic c1, c2,
input logic a, b,
output logic f, g);
always_latch
begin
case ({c1,c2})
2'b00: f
2'b01: g
2'b10: f
2'b11: g
endcase
end

=
=
=
=

a;
b;
a | b;
a & b;

endmodule

module latch_example5 (input logic c1, c2,


input logic a, b,
output logic f);
always_latch
begin
case ({c1,c2})
2'b00: f = a;
2'b01: f = b;
2'b10: f = a | b;
endcase
end
endmodule

Latches
What happens if we use incompletely
specified case or if statements with
always_comb?
module latch_incorrect (input logic c1, c2,
input logic a, b,
output logic f);
always_comb
begin
case ({c1,c2})
2'b00: f = a;
2'b01: f = b;
2'b10: f = a | b;
endcase
end

INCORRECT!
(the compiler
should give
an error)

endmodule

module combinational_correct (input logic c1, c2,


input logic a, b,
output logic f);
always_comb
begin
case ({c1,c2})
2'b00: f
2'b01: f
2'b10: f
default:
endcase
end
endmodule

=
=
=
f

a;
b;
a | b;
= 1'bx;

CORRECT!
(combinational
logic is further
optimized by
exploiting dont
care conditions)

Blocking vs. Non-blocking


Simple circuit for illustrative purposes
(in reality some additional
inputs/outputs will be required)
module example (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_ff @(posedge clock)
begin
a <= b + c;
b <= c + a;
c <= a + b;
end
assign f = c;
endmodule

clock

Blocking vs. Non-blocking


What happens if assignment to a
becomes blocking?
module example (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_ff @(posedge clock)
begin
a = b + c;
b <= c + a;
c <= a + b;
end
assign f = c;
endmodule

clock

Blocking vs. Non-blocking


What happens if assignment to b
becomes blocking?
module example (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_ff @(posedge clock)
begin
a <= b + c;
b = c + a;
c <= a + b;
end
assign f = c;
endmodule

Blocking vs. Non-blocking


What happens if assignment to c
becomes blocking?
module example (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_ff @(posedge clock)
begin
a <= b + c;
b <= c + a;
c = a + b;
end
assign f = c;
endmodule

clock

Blocking vs. Non-blocking


What happens if the assignment to a
is blocking and the output f is driven
by the a signal?
module example (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_ff @(posedge clock)
begin
a = b + c;
b <= c + a;
c <= a + b;
end
assign f = a;
endmodule

clock

Blocking vs. Non-blocking


Can we take the combinational a
signal to the output of the circuit?
module example (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_comb
begin
a = b + c;
end
always_ff @(posedge clock)
begin
b <= c + a;
c <= a + b;
end
assign f = a;
endmodule

You might also like