J
Jonathan Bromley
Guest
On Wed, 28 Jan 2009 16:43:45 -0800 (PST), Mark Brehob wrote:
Some people think this is unhelpful, too far from hardware,
too confusing, too error-prone... you name it. But for me,
and for several other designers I respect, it's an important
technique.
In a clocked process, there are at least three reasons
I can think of for having local variables with immediate-
update behaviour.
(1) Pre-calculating a subexpression
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
always @(posedge clock)
// Labelled begin-end so we can declare
// local variables in it
begin : HasSubexpression
reg Enable;
// Precalculate Enable based on other inputs.
// This has the effect of a piece of combinational
// logic computing Enable from a,b,c,d.
if (a)
Enable = 0;
else if (b ^ c)
Enable = 1;
else
Enable = d;
// Use Enable in various ways:
if (Enable)
Count <= Count + 1;
case (Enable? u[1:0] : u[3:2])
0: ...
1: ...
2: ...
default: ...
endcase
end
(2) Hiding local functionality that
you don't want to expose elsewhere
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In fairness, this one really applies only to VHDL
because in VHDL you can't have local signals in a
process, but only local variables. However, it's
easy to mimic in Verilog too.
always @(posedge clock) begin : RiseDetector
reg Delayed_D;
Rise <= D & ~Delayed_D;
Delayed_D = D;
end
Note here that I've used blocking assignment to Delayed_D,
and consequently the assignment must happen AFTER any use
of the local because in the previous expression I want
the value of Delayed_D that was saved on the previous clock.
In Verilog, but not in VHDL, I could have used nonblocking
assignment to the local and then it would not have
mattered in which order I did the assignments.
(3) Getting a sneak preview of the next-state
value of a state variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens to be my personal favoured style
for writing state machines, but of course not
everyone agrees. The reasoning goes like this:
- In a state machine, it is probably *only* the
state machine itself that actually cares about
the state variable. So let's hide the state
variable inside its process.
- To get outputs that are a pure function of
the state, but nevertheless are themselves
registered, I need to update those outputs
based on the next-state value of the state
variable so that they update at the same time
as the state changes.
Here's how it works:
always @(posedge clock) begin: FSM
reg [whatever:0] state;
// state-name constants
localparam IDLE = 0, RUN = 1, HOLD = 2;
// Step 1: Default values for the outputs
running <= 0;
holding <= 0;
// Step 2: State transition logic (NO outputs):
// compute next-state as a function of inputs
case (state)
IDLE : if (start)
state = RUN;
RUN : if (stop)
state = HOLD;
HOLD : if (release)
state = IDLE;
default : state = IDLE;
endcase
// Step 3: Now the local variable "state" contains the
// NEXT-state value; we can use that to determine
// values for registered outputs
case (state)
RUN: running <= 1;
HOLD: holding <= 1;
endcase
end
There are many variations on this theme, and - to repeat -
not everyone agrees that this is a good idea. But it
works for me.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OK, so where does that leave the "don't mix blocking and
nonblocking" rule? Here's the REAL rule:
In a clocked process:
1.ALWAYS use nonblocking assignment to any variable
whose value will be used outside the process;
2.NEVER mix blocking and nonblocking assignment
to a single variable;
3.any variable assigned by blocking assignment must
be declared locally in the process's begin-end, so
that it can't be referenced from outside (at least,
not for synthesis);
4.be aware of the immediate-update semantics of
blocking assignment. This means...
- if you read such a variable before assigning
to it, you get the value that it was given
on the PREVIOUS clock - held in a flip-flop;
- if you read such a variable after assigning
to it, you get the combinational value that
you just assigned to it.
In a VHDL clocked process, these rules 1,2,3 are
effectively enforced for you by the language;
variables are local to a process and update immediately
by := variable assignment; signals are declared outside
a process and have delayed update by <= signal assignment.
In Verilog you must enforce the rules for yourself.
Rule 1 is essential to avoid simulation races and
consequent mismatch with synthesis. Rule 2 is
essential to maintain your sanity, but is also a
requirement for all synthesis tools I know of.
Rule 3 helps to align Verilog and VHDL coding
styles, and makes it much easier to obey rule 1.
You will also find some people advocating the extensive
use of process-local variables to enable a very
software-like description of a design's behaviour,
with blocking assignment to local variables everywhere.
Internal result values can then be copied on to output
signals by nonblocking assignment when their value is
finally established. This approach gives your synth
tool LOTS of work to do, but hey, that's what it's for.
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
First, let me be 100% honest: Maybe you *don't* want it.Could you give an example or otherwise illustrate the issue here? I'm
not sure what "the behaviour of VHDL variables in a clocked process"
is, or why I'd want it.
Some people think this is unhelpful, too far from hardware,
too confusing, too error-prone... you name it. But for me,
and for several other designers I respect, it's an important
technique.
In a clocked process, there are at least three reasons
I can think of for having local variables with immediate-
update behaviour.
(1) Pre-calculating a subexpression
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
always @(posedge clock)
// Labelled begin-end so we can declare
// local variables in it
begin : HasSubexpression
reg Enable;
// Precalculate Enable based on other inputs.
// This has the effect of a piece of combinational
// logic computing Enable from a,b,c,d.
if (a)
Enable = 0;
else if (b ^ c)
Enable = 1;
else
Enable = d;
// Use Enable in various ways:
if (Enable)
Count <= Count + 1;
case (Enable? u[1:0] : u[3:2])
0: ...
1: ...
2: ...
default: ...
endcase
end
(2) Hiding local functionality that
you don't want to expose elsewhere
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In fairness, this one really applies only to VHDL
because in VHDL you can't have local signals in a
process, but only local variables. However, it's
easy to mimic in Verilog too.
always @(posedge clock) begin : RiseDetector
reg Delayed_D;
Rise <= D & ~Delayed_D;
Delayed_D = D;
end
Note here that I've used blocking assignment to Delayed_D,
and consequently the assignment must happen AFTER any use
of the local because in the previous expression I want
the value of Delayed_D that was saved on the previous clock.
In Verilog, but not in VHDL, I could have used nonblocking
assignment to the local and then it would not have
mattered in which order I did the assignments.
(3) Getting a sneak preview of the next-state
value of a state variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens to be my personal favoured style
for writing state machines, but of course not
everyone agrees. The reasoning goes like this:
- In a state machine, it is probably *only* the
state machine itself that actually cares about
the state variable. So let's hide the state
variable inside its process.
- To get outputs that are a pure function of
the state, but nevertheless are themselves
registered, I need to update those outputs
based on the next-state value of the state
variable so that they update at the same time
as the state changes.
Here's how it works:
always @(posedge clock) begin: FSM
reg [whatever:0] state;
// state-name constants
localparam IDLE = 0, RUN = 1, HOLD = 2;
// Step 1: Default values for the outputs
running <= 0;
holding <= 0;
// Step 2: State transition logic (NO outputs):
// compute next-state as a function of inputs
case (state)
IDLE : if (start)
state = RUN;
RUN : if (stop)
state = HOLD;
HOLD : if (release)
state = IDLE;
default : state = IDLE;
endcase
// Step 3: Now the local variable "state" contains the
// NEXT-state value; we can use that to determine
// values for registered outputs
case (state)
RUN: running <= 1;
HOLD: holding <= 1;
endcase
end
There are many variations on this theme, and - to repeat -
not everyone agrees that this is a good idea. But it
works for me.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OK, so where does that leave the "don't mix blocking and
nonblocking" rule? Here's the REAL rule:
In a clocked process:
1.ALWAYS use nonblocking assignment to any variable
whose value will be used outside the process;
2.NEVER mix blocking and nonblocking assignment
to a single variable;
3.any variable assigned by blocking assignment must
be declared locally in the process's begin-end, so
that it can't be referenced from outside (at least,
not for synthesis);
4.be aware of the immediate-update semantics of
blocking assignment. This means...
- if you read such a variable before assigning
to it, you get the value that it was given
on the PREVIOUS clock - held in a flip-flop;
- if you read such a variable after assigning
to it, you get the combinational value that
you just assigned to it.
In a VHDL clocked process, these rules 1,2,3 are
effectively enforced for you by the language;
variables are local to a process and update immediately
by := variable assignment; signals are declared outside
a process and have delayed update by <= signal assignment.
In Verilog you must enforce the rules for yourself.
Rule 1 is essential to avoid simulation races and
consequent mismatch with synthesis. Rule 2 is
essential to maintain your sanity, but is also a
requirement for all synthesis tools I know of.
Rule 3 helps to align Verilog and VHDL coding
styles, and makes it much easier to obey rule 1.
You will also find some people advocating the extensive
use of process-local variables to enable a very
software-like description of a design's behaviour,
with blocking assignment to local variables everywhere.
Internal result values can then be copied on to output
signals by nonblocking assignment when their value is
finally established. This approach gives your synth
tool LOTS of work to do, but hey, that's what it's for.
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.