Synthesis friendly code?

P

priceless

Guest
If I write a code like this
....
output reg [65:0] packet_wdata ,
....
reg [63:0] hdr ;
reg sob ;

always @(posedge clk200, negedge reset_n)
if (!reset_n)
packet_wdata[63:0] <= 64'd0;
else if (hdr_rden_r[1]) begin
packet_wdata[63:0] <= hdr; // line 1
packet_wdata[63] <= sob; // line 2
...
...
end
else if (pkt_wen_pre2)
packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

it behaves as expected, with the 63rd bit assigned with the header
value in line #2, overriding the 63 rd bit assignment in line marked
1.

When I ran the synthesis tool, it did not complain, and the
synthesized hardware works ok.

What I would like to know, is this a valid style, I noticed this style
a while ago in Cliff Cummings' paper, now a colleague says it's not a
good practice and other synthesis tools may issue error.

The synthesis tool I used is XST from xilinx (for fpga). Please
discuss your experiences.

Thanks in advance for your answer,
Ash
 
On Wed, 25 Jun 2008 02:38:49 -0700 (PDT), priceless wrote:

If I write a code like this
...
output reg [65:0] packet_wdata ,
...
reg [63:0] hdr ;
reg sob ;

always @(posedge clk200, negedge reset_n)
if (!reset_n)
packet_wdata[63:0] <= 64'd0;
else if (hdr_rden_r[1]) begin
packet_wdata[63:0] <= hdr; // line 1
packet_wdata[63] <= sob; // line 2
...
...
end
else if (pkt_wen_pre2)
packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

it behaves as expected, with the 63rd bit assigned with the header
value in line #2, overriding the 63 rd bit assignment in line marked
1.
Indeed so.

When I ran the synthesis tool, it did not complain, and the
synthesized hardware works ok.
I should very much hope so. Any synthesis tool that gets this
wrong is buggy. It works with every tool I'm aware of.

What I would like to know, is this a valid style, I noticed this style
a while ago in Cliff Cummings' paper, now a colleague says it's not a
good practice and other synthesis tools may issue error.
What evidence does your colleague have for this? I believe
your colleague is wrong.

Some folk don't like doing this because, they say,
you may get glitches in simulation.
This is true, but the glitch is zero-width and is
irrelevant on synchronous signals. The only situation
in which I'd be worried about this is if I were trying
to use that output as a derived clock or other
edge-sensitive signal, in which case I might get
strange behaviour in simulation. The synthesised
logic will definitely be OK.

Of course, in the example you give it would be very easy
to work around this:

packet_wdata[62:0] <= hdr[62:0]; // line 1
packet_wdata[63] <= sob; // line 2

or perhaps (better, in my opinion):

packet_wdata <= {sob, hdr[62:0]};
--
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.
 
rOn Wed, 25 Jun 2008 02:38:49 -0700 (PDT), priceless
<fasahat.hussain@gmail.com> wrote:

If I write a code like this
...
output reg [65:0] packet_wdata ,
...
reg [63:0] hdr ;
reg sob ;

always @(posedge clk200, negedge reset_n)
if (!reset_n)
packet_wdata[63:0] <= 64'd0;
else if (hdr_rden_r[1]) begin
packet_wdata[63:0] <= hdr; // line 1
packet_wdata[63] <= sob; // line 2
...
...
end
else if (pkt_wen_pre2)
packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

it behaves as expected, with the 63rd bit assigned with the header
value in line #2, overriding the 63 rd bit assignment in line marked
1.
When I ran the synthesis tool, it did not complain, and the
synthesized hardware works ok.
This is well-defined legal Verilog for both simulation and synthesis
so it should work as you expected and experienced.

What I would like to know, is this a valid style, I noticed this style
a while ago in Cliff Cummings' paper, now a colleague says it's not a
good practice and other synthesis tools may issue error.
Any synthesis tool which complains about this specific issue has a
problem itself. As for a concrete example from your colleague (which
synthesis tool) and a justification why it's not a good practice.
 
On Wed, 25 Jun 2008 23:56:10 -0700 (PDT), umairsiddiqui84@gmail.com
wrote:

On Jun 25, 4:32 pm, Jonathan Bromley wrote:
Some folk don't like doing this because, they say,
you may get glitches in simulation.
This is true, but the glitch is zero-width and is
irrelevant on synchronous signals.
[...]
I would like to quote from IEEE Standard Verilog STD 1364-2001,
Section 5.4.1, page#66
2-Non blocking assignments shall be performed in the order the
statements were executed. Consider the following example:
initial begin
a <= 0;
a <= 1;
end
When this block is executed, there will be two events added to the non
blocking assign update queue. The previous rule requires that they be
entered on the queue in source order; this rule requires that they be
taken from the queue and performed in source order as well. Hence, at
the end of time step 1, the variable a will be assigned 0 and then 1.
As far as simulation glitches are concerned, it seems like simulator
only consider the last assignment. I wrote the following test code:
[...]
I run the test code on Modelsim 6.2g SE and no glitches are generated.
In practice you are almost certainly correct, but it is not
that simple.

First, I don't see how you can produce evidence that "no glitches
are generated". Any glitch is sure to be zero-width, and might not
appear on a waveform viewer. You might not even see it in ModelSim's
"list" window, which shows value changes within a time slot at
different delta cycles, because there is no delta cycle (iteration
around the Verilog scheduler) between the two updates. However,
the LRM most certainly specifies that both updates should be
performed, and it does NOT specify the ordering of those two
updates relative to the triggering and execution of other
procedural code.

The scheduler algorithm clearly shows that signal updates caused
by nonblocking assignment are "activated" before being executed,
and therefore they compete with other active events in the
simulator's scheduler. Given the following code:

reg a;
initial begin
a <= 0;
#10
a <= 1;
a <= 0;
end
always @a $display("a changed to %b at time %0d", a, $time);

then I can reliably predict that the always block will trigger
at time 0 and print

a changed to 0 at time 0

In any practical, reasonably efficient simulator I would
expect there to be no triggering of "@a" at time 10 (no
glitch, as you claim) but I believe it would also be
LRM-compliant for the $display to execute once or twice
at time 10. Consequently, it is legitimate for simulators
to elide all nonblocking updates to a variable and execute
only the last, even though that's not what the LRM says.
--
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.
 
On Jun 25, 4:32 pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
Some folk don't like doing this because, they say,
you may get glitches in simulation.
This is true, but the glitch is zero-width and is
irrelevant on synchronous signals. The only situation
in which I'd be worried about this is if I were trying
to use that output as a derived clock or other
edge-sensitive signal, in which case I might get
strange behaviour in simulation. The synthesised
logic will definitely be OK.
I would like to quote from IEEE Standard Verilog STD 1364-2001,
Section 5.4.1, page#66

This standard guarantees a certain scheduling order.
1- Statements within a begin-end block shall be executed in the order
in which they appear in that begin-end block. Execution of statements
in a particular begin-end block can be suspended in favor of other
processes in the model; however, in no case shall the statements in a
begin-end
block be executed in any order other than that in which they appear in
the source.

2-Non blocking assignments shall be performed in the order the
statements were executed. Consider the following example:

initial begin
a <= 0;
a <= 1;
end

When this block is executed, there will be two events added to the non
blocking assign update queue. The previous rule requires that they be
entered on the queue in source order; this rule requires that they be
taken from the queue and performed in source order as well. Hence, at
the end of time step 1, the variable a will be assigned 0 and then 1.

As far as simulation glitches are concerned, it seems like simulator
only consider the last assignment. I wrote the following test code:

[code:1:cec5138cb2]
`timescale 1ns/1ps

module test;

reg a;

initial begin
a <= 0;
#100;
a <= 0;
a <= 1; //should create glitch
a <= 0;
#100;
a <= 1;
#100;
a <= 1;
a <= 0; //should create glitch
a <= 1;
#100;
a <= 0;
#100;
$finish;
end

endmodule

[/code:1:cec5138cb2]

I run the test code on Modelsim 6.2g SE and no glitches are generated.
 
On Thu, 26 Jun 2008 09:06:00 +0100, Jonathan Bromley
<jonathan.bromley@MYCOMPANY.com> wrote:

In any practical, reasonably efficient simulator I would
expect there to be no triggering of "@a" at time 10 (no
glitch, as you claim) but I believe it would also be
LRM-compliant for the $display to execute once or twice
at time 10. Consequently, it is legitimate for simulators
to elide all nonblocking updates to a variable and execute
only the last, even though that's not what the LRM says.
My own reading of section 11 is that a compliant sim is required to
carry out the update, so the $display should execute twice. cver does
actually do that, but the other sims I tried it on didn't (one
nameless FPGA vendor's sim couldn't run the code at all).

Here's an interesting one. I have some test code which increments a
variable using a function call:

x = add(x, 1);

Is this guaranteed to be atomic? I have at least one test sim where
it's *not* atomic. If two different processes attempt to update x
simultaneously then, under the right circumstances, it only gets
incremented once: both processes read the same value, and both add one
to the old value.

Technically, this is LRM-compliant, because of the bit in 11.4.1(a)
about suspending statements in a begin-end block "in favor of other
processes". Practically, it's crazy - the scheduler is effectively
allowed to be pre-emptive rather than event-driven.

-Evan
 
On Fri, 27 Jun 2008 14:33:11 +0100, Evan Lavelle wrote:

My own reading of section 11 is that a compliant sim is required to
carry out the update,
agreed

so the $display should execute twice.
I don't follow that. @(sig) detects an event on sig only
if execution has reached the @ *before* sig is updated.
Given that the NBA-induced signal updates and the execution
of code that includes the @() are both on the Active
scheduler region, and are both competing for the simulator's
attention, I see no guaranteed ordering of the interleaving
of the two updates on the target signal and the execution
of the @() event control.

Consequently the observed behaviour if simultaneous
NBAs are elided and only the last one executed is one of
the possible LRM-compliant behaviours that might occur if
you require that all NBA updates be performed in order;
and therefore there is effectively no LRM obligation on
a simulator to perform any updates save the last one.

I'd be interested to see any solid refutation of this
argument - I'm fairly sure it's robust, but it's easy to
overlook things when trying to reason about Verilog :)

cver does actually do that
[triggering an @() on _every_ NBA update to a signal]
but the other sims I tried it on didn't
There are at least two reasonable ways to implement @().
One method is to trace all writes to any signal that
participates in the event control. It looks as though
that's what cver is doing. Another method is to evaluate
the event expression each time you've otherwise exhausted
the Active region, and promote the @()-delayed code to
Active if the event has been triggered. Clearly the two
methods can give divergent results in the presence of
zero-width, zero-delta glitches. (yes, I know there's
no such thing as a delta in Verilog, but you know what
I mean...)

Here's an interesting one. I have some test code which
increments a variable using a function call:

x = add(x, 1);

Is this guaranteed to be atomic?
I believe not; there seems to be no guarantee of atomicity
of anything at all in the scheduling semantics.

I have at least one test sim where it's *not* atomic.
[...]
Technically, this is LRM-compliant, because of the bit in 11.4.1(a)
about suspending statements in a begin-end block "in favor of other
processes". Practically, it's crazy - the scheduler is effectively
allowed to be pre-emptive rather than event-driven.
Yup. It would have been soooooo much easier if Verilog had specified
atomic execution of code between scheduling points (event waits,
time delays etc). But it doesn't (I wonder if that was a conscious
decision, to leave the door open to multi-CPU implementations, or
low cunning to preserve back-compatibility with some bizarre
existing implementation, or just traditional Verilog vagueness?
Steven Sharp will pretty certainly know the answer).

SystemVerilog introduces a few concessions to atomicity. For
example, the processes spawned by fork...join_none are guaranteed
to be created immediately, but not to start execution until
their parent blocks. And at least we have a couple of
synchronisation primitives (semaphore, mailbox) that make it
possible to get mutual exclusion in a sane manner now.

I have seen plenty of Verilog code in the wild that makes
unjustified, but practically reasonable, assumptions about
atomic execution. I would *love* to see the LRM changed
to guarantee atomic execution of a function, for example.

(one nameless FPGA vendor's sim couldn't
run the code at all).
Oh dear....
--
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.
 
On Fri, 27 Jun 2008 15:11:37 +0100, Jonathan Bromley
<jonathan.bromley@MYCOMPANY.com> wrote:

On Fri, 27 Jun 2008 14:33:11 +0100, Evan Lavelle wrote:

My own reading of section 11 is that a compliant sim is required to
carry out the update,

agreed

so the $display should execute twice.

I don't follow that. @(sig) detects an event on sig only
if execution has reached the @ *before* sig is updated.
Given that the NBA-induced signal updates and the execution
of code that includes the @() are both on the Active
scheduler region, and are both competing for the simulator's
attention, I see no guaranteed ordering of the interleaving
of the two updates on the target signal and the execution
of the @() event control.
This is currently my understanding of how this code would be
processed, although I may well change my mind in 5 minutes:

1 - NBA 1 is encountered; the RHS is read "immediately"; the update
event is placed on the NBA update event queue

2 - repeat for NBA 2

3 - execution carries on till a suspend point is reached, at which
point we start cycling around the pseudo-code in 11.4

4 - there are no active events (by definition, since we'ce suspended),
and assume that there are no inactive events; we therefore "activate
all NBA update events"

5 - NBA #1 becomes the first active event to be processed (contrary to
the pseudo-code); it's an update event, so we add an evaluation event
for the "$display process"

6 - loop around again. The pseudo-code is a bit hazy here, but the
evaluation event is now presumably an active event, and the scheduler
has a choice of 2 active events. However, NBA #2 is an update event,
so it has priority; we have to add a second evaluation event for the
display process

7 - loop around again. We now have two evaluation events for the
"$display process", and no update events

There's nothing that says that you can drop one of the two evaluation
events, and it seems to me that a simulator is on pretty thin ice if
it decides to do that. If the sim does drop one then presumably -

1 - it thinks it's doing you a favour by optimising your code, or

2 - it's misunderstood the meaning of the "last NBA wins" rule (which
didn't exist anyway until... what? '94? '95?). The last NBA does win,
but there doesn't appear to be anything which allows the first one to
be ignored.

But, as I said, I could well have changed my mind by the time I hit
the 'send' button. Besides, it hardly matters - we all know that what
the LRM says is only half the story, if you can manage to read it.

Yup. It would have been soooooo much easier if Verilog had specified
atomic execution of code between scheduling points (event waits,
time delays etc). But it doesn't (I wonder if that was a conscious
decision, to leave the door open to multi-CPU implementations, or
low cunning to preserve back-compatibility with some bizarre
existing implementation, or just traditional Verilog vagueness?
Steven Sharp will pretty certainly know the answer).
He actually gave an answer a couple of years ago, somewhere in
http://groups.google.co.uk/group/comp.lang.verilog/browse_frm/thread/d97f5ff5db3d5e71/66dfad98e0b9daff?hl=en&tvc=1#66dfad98e0b9daff

Pertinent bits attached below.

I have seen plenty of Verilog code in the wild that makes
unjustified, but practically reasonable, assumptions about
atomic execution. I would *love* to see the LRM changed
to guarantee atomic execution of a function, for example.
But...

1 - there's nothing special about functions. They return a value using
a blocking assignment, and can't advance time, so they can, in
principle, be invisible to an event-driven scheduler

2 - Exactly the same is true for an increment which doesn't use a
function call (a = a + 1)

3 - Verilog has no private data. With a pre-emptive scheduler, nothing
is guaranteed to work, unless you build your own mutexes everywhere.
Ergo, the LRM is wrong, or Verilog doesn't work :)

(one nameless FPGA vendor's sim couldn't
run the code at all).

Oh dear....
That's nothing. It worked fine before their recent update, along with
various other bits, which now don't work either. My contact in
Bangalore was unimpressed when I pointed this out.

-Evan

============================================================
(SS, not me)

"There is the rigamarole about allowing a begin-end to suspend in
favor
of executing another process, and then resume later. If taken to
extremes, this would make the language very hard to use, since many
common practices would become nondeterministic. This seems to have
been stated partly to allow for simulator optimizations involving
inlining of one process into another. For example, when an always
block updates a variable, a simulator might immediately update a net
that is assigned from that variable. This can be viewed as suspending
the always block, executing the continuous assignment, and then
resuming the always block. But no simulator is going to arbitrarily
suspend one process to execute another, unless there is at least some
kind of event-driven connection between them.

This statement may also have been intended to allow for some kind of
parallel simulation, with processes running in parallel on different
processors. But while such things have always sounded good in theory,
they have never turned out to be practical in reality.

The scheduling semantics aren't really that complicated. With few
exceptions, in real simulators, processes run until they deliberately
suspend at an event control or delay control. There may be some
apparent exceptions for optimizations like inlining of fanout."
 
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jonathan Bromley wrote:
| On Fri, 27 Jun 2008 14:33:11 +0100, Evan Lavelle wrote:
|
|> My own reading of section 11 is that a compliant sim is required to
|> carry out the update,
|
| agreed
|
|> so the $display should execute twice.
|
| I don't follow that. @(sig) detects an event on sig only
| if execution has reached the @ *before* sig is updated.
| Given that the NBA-induced signal updates and the execution
| of code that includes the @() are both on the Active
| scheduler region, and are both competing for the simulator's
| attention, I see no guaranteed ordering of the interleaving
| of the two updates on the target signal and the execution
| of the @() event control.

What happens is all the Active stuff is done, which in the example
includes creating some non-blocking assignments. These go in the
NB assign queue, which is not touched until the Active queue
completes.

Then, all the events in the NB queue are transferred into the Active
queue, and the cycle repeats. So now these NB Assigns are Active
update events, the first of which triggers the @() event control.
What *typically* happens next is that the @() event is put on the
end of the Active queue, which will be after the second NB Assign,
which is already in the active queue. It gets gray here--The second
NB Assign will "trigger" the @() again, but one can argue that it
is already triggered so it not waiting anymore. Thus, the @() will
be triggered exactly once.

| Consequently the observed behaviour if simultaneous
| NBAs are elided and only the last one executed is one of
| the possible LRM-compliant behaviours that might occur if
| you require that all NBA updates be performed in order;
| and therefore there is effectively no LRM obligation on
| a simulator to perform any updates save the last one.

Yes, and in practice that is what Icarus Verilog does.


|> Here's an interesting one. I have some test code which
|> increments a variable using a function call:
|>
|> x = add(x, 1);
|>
|> Is this guaranteed to be atomic?
|
| I believe not; there seems to be no guarantee of atomicity
| of anything at all in the scheduling semantics.

I believe it is not guaranteed by the LRM to be atomic, but is
widely expected to be atomic. In fact, it is widely expected
that any sequence of behavioral code without delays, waits or
blocking event controls is atomic. Icarus Verilog follows this
rule (modulus the occasional bug). Otherwise, things just get
far too nutty.

I actually think this "rule" and the lack of software-style
synchronization primitives (semaphores, mutexes, etc.) makes
good sense. Because Verilog is so "micro"-threaded, anything
other would make any strictly correct code hopelessly dense
with mutexes.

- --
Steve Williams "The woods are lovely, dark and deep.
steve at icarus.com But I have promises to keep,
http://www.icarus.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFIZUW/rPt1Sc2b3ikRAkfOAKDDlHDRlxnvGZcUY9tb21jklCNJggCfbNZi
giBzrDhrNHCg1N7uyuRcsvM=
=CsKV
-----END PGP SIGNATURE-----
 
On Fri, 27 Jun 2008 12:55:43 -0700, Stephen Williams
<spamtrap@icarus.com> wrote:

Then, all the events in the NB queue are transferred into the Active
queue, and the cycle repeats. So now these NB Assigns are Active
update events, the first of which triggers the @() event control.
What *typically* happens next is that the @() event is put on the
end of the Active queue, which will be after the second NB Assign,
which is already in the active queue. It gets gray here--The second
NB Assign will "trigger" the @() again, but one can argue that it
is already triggered so it not waiting anymore. Thus, the @() will
be triggered exactly once.
You can't put the argument quite this way, because you need to respond
to the second evaluation event, not the first.

I suppose you could argue that the scheduler can run only the last
evaluation event on the queue for a given process, because all inputs
that the process is sensitive to will have their new values when the
last event is reached.

But, I don't buy this. The LRM doesn't say this, and the delta-cycle
model only works if all evaluation events are stored up and acted on,
in order. If the simulator wants to drop an evaluation event, it must
confirm that the lost event will not affect *any* part of the
simulation network, and not produce any other change of state (running
or not running $display, for example) when the slot finishes.

In the general case, this analysis might be next to impossible.
Consider the case where there's a cross-coupled latch downstream from
'a', for example. The sim would either have to do a formal analysis of
the circuit, or actually run the simulation both with and without the
glitch, which is clearly pointless. The circuit ends up in 2 very
diferent states with and without the glitch. If the sim drops the
glitch, then a delta-delay RTL simulation will produce a different
result from a timing simulation and the real hardware.

It seems to me that this fits in the class of Verilog optimisations
that makes your code run faster, and doesn't affect 99.9% of good
code.

I believe it is not guaranteed by the LRM to be atomic, but is
widely expected to be atomic. In fact, it is widely expected
that any sequence of behavioral code without delays, waits or
blocking event controls is atomic. Icarus Verilog follows this
rule (modulus the occasional bug). Otherwise, things just get
far too nutty.

I actually think this "rule" and the lack of software-style
synchronization primitives (semaphores, mutexes, etc.) makes
good sense.
Me too. It would be better if it was written down, though.

-Evan
 
On Jun 25, 4:38 am, priceless <fasahat.huss...@gmail.com> wrote:
If I write a code like this
...
output reg [65:0]  packet_wdata        ,
...
  reg      [63:0]       hdr       ;
  reg                   sob ;

  always @(posedge clk200, negedge reset_n)
    if (!reset_n)
      packet_wdata[63:0] <= 64'd0;
    else if (hdr_rden_r[1]) begin
      packet_wdata[63:0]  <= hdr;     // line 1
      packet_wdata[63]    <= sob;     // line 2
      ...
      ...
    end
    else if (pkt_wen_pre2)
      packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

it behaves as expected, with the 63rd bit assigned with the header
value in line #2, overriding the 63 rd bit assignment in line marked
1.

When I ran the synthesis tool, it did not complain, and the
synthesized hardware works ok.

What I would like to know, is this a valid style, I noticed this style
a while ago in Cliff Cummings' paper, now a colleague says it's not a
good practice and other synthesis tools may issue error.

The synthesis tool I used is XST from xilinx (for fpga).  Please
discuss your experiences.

Thanks in advance for your answer,
Ash
Just a sidenote.. aren't we inferring a latch by not ending your code
with an ELSE statement?
 
On Thu, 10 Jul 2008 11:40:24 -0700 (PDT), Roosta <opehund@gmail.com>
wrote:

Given that this is a clocked process, the synthesis may infer
a clock enable.  Generally you need to worry about else or
default clauses for combinatorial logic, not flip-flops.- Hide quoted text -

- Show quoted text -

So what is inferred here? This below?

packet_wdata[63:0] <= packet_wdata[63:0]

And where is it documented that omitted a default clause in non-
blocking infers that? Just curious because I didn't know. I'm
reading a synthesis book now and maybe have not come across that yet.
We're talking about procedural assignments here which are basically
triggered assignments ie if the events in the dependency trigger the
block is executed. But also there is a conditional assignment in the
block which is triggered by the always block. This conditional
assignment also plays a role in whether the assignment is executed or
not. So if the condition evaluates to false the assignment is not
executed at all in which case the value stored in the register doesn't
change. You can interpret this as if there is an else statement which
assigns the register to itself, which is one of the possible ways the
logic is synthesized ie there is a mux at the input of the flop which
is controlled by the output of the "if" statement. If it's true the
new value is forwarded to the data input of the flop and if it's false
the current output of the flop is forwarded to the input of the flop.
But in RTL simulation the simulator probably doesn't even schedule an
assignment event so the value stays the same but in actual hardware in
every clock cycle there has to be something at the data input of the
flop so the mux is inferred (or a clock enable is inferred etc.)
 
On Jul 10, 11:40 am, Roosta <opeh...@gmail.com> wrote:
On Jun 25, 4:38 am, priceless <fasahat.huss...@gmail.com> wrote:



If I write a code like this
...
output reg [65:0] packet_wdata ,
...
reg [63:0] hdr ;
reg sob ;

always @(posedge clk200, negedge reset_n)
if (!reset_n)
packet_wdata[63:0] <= 64'd0;
else if (hdr_rden_r[1]) begin
packet_wdata[63:0] <= hdr; // line 1
packet_wdata[63] <= sob; // line 2
...
...
end
else if (pkt_wen_pre2)
packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

it behaves as expected, with the 63rd bit assigned with the header
value in line #2, overriding the 63 rd bit assignment in line marked
1.

When I ran the synthesis tool, it did not complain, and the
synthesized hardware works ok.

What I would like to know, is this a valid style, I noticed this style
a while ago in Cliff Cummings' paper, now a colleague says it's not a
good practice and other synthesis tools may issue error.

The synthesis tool I used is XST from xilinx (for fpga). Please
discuss your experiences.

Thanks in advance for your answer,
Ash

Just a sidenote.. aren't we inferring a latch by not ending your code
with an ELSE statement?
Given that this is a clocked process, the synthesis may infer
a clock enable. Generally you need to worry about else or
default clauses for combinatorial logic, not flip-flops.
 
On Jul 10, 12:50 pm, gabor <ga...@alacron.com> wrote:
On Jul 10, 11:40 am, Roosta <opeh...@gmail.com> wrote:





On Jun 25, 4:38 am, priceless <fasahat.huss...@gmail.com> wrote:

If I write a code like this
...
output reg [65:0]  packet_wdata        ,
...
  reg      [63:0]       hdr       ;
  reg                   sob ;

  always @(posedge clk200, negedge reset_n)
    if (!reset_n)
      packet_wdata[63:0] <= 64'd0;
    else if (hdr_rden_r[1]) begin
      packet_wdata[63:0]  <= hdr;     // line 1
      packet_wdata[63]    <= sob;     // line 2
      ...
      ...
    end
    else if (pkt_wen_pre2)
      packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

it behaves as expected, with the 63rd bit assigned with the header
value in line #2, overriding the 63 rd bit assignment in line marked
1.

When I ran the synthesis tool, it did not complain, and the
synthesized hardware works ok.

What I would like to know, is this a valid style, I noticed this style
a while ago in Cliff Cummings' paper, now a colleague says it's not a
good practice and other synthesis tools may issue error.

The synthesis tool I used is XST from xilinx (for fpga).  Please
discuss your experiences.

Thanks in advance for your answer,
Ash

Just a sidenote.. aren't we inferring a latch by not ending your code
with an ELSE statement?

Given that this is a clocked process, the synthesis may infer
a clock enable.  Generally you need to worry about else or
default clauses for combinatorial logic, not flip-flops.- Hide quoted text -

- Show quoted text -
So what is inferred here? This below?

packet_wdata[63:0] <= packet_wdata[63:0]

And where is it documented that omitted a default clause in non-
blocking infers that? Just curious because I didn't know. I'm
reading a synthesis book now and maybe have not come across that yet.
 
On Jul 10, 3:03 pm, Muzaffer Kal <k...@dspia.com> wrote:
On Thu, 10 Jul 2008 11:40:24 -0700 (PDT), Roosta <opeh...@gmail.com
wrote:

Given that this is a clocked process, the synthesis may infer
a clock enable. Generally you need to worry about else or
default clauses for combinatorial logic, not flip-flops.- Hide quoted text -

- Show quoted text -

So what is inferred here? This below?

packet_wdata[63:0] <= packet_wdata[63:0]

And where is it documented that omitted a default clause in non-
blocking infers that? Just curious because I didn't know. I'm
reading a synthesis book now and maybe have not come across that yet.

We're talking about procedural assignments here which are basically
triggered assignments ie if the events in the dependency trigger the
block is executed. But also there is a conditional assignment in the
block which is triggered by the always block. This conditional
assignment also plays a role in whether the assignment is executed or
not. So if the condition evaluates to false the assignment is not
executed at all in which case the value stored in the register doesn't
change. You can interpret this as if there is an else statement which
assigns the register to itself, which is one of the possible ways the
logic is synthesized ie there is a mux at the input of the flop which
is controlled by the output of the "if" statement. If it's true the
new value is forwarded to the data input of the flop and if it's false
the current output of the flop is forwarded to the input of the flop.
But in RTL simulation the simulator probably doesn't even schedule an
assignment event so the value stays the same but in actual hardware in
every clock cycle there has to be something at the data input of the
flop so the mux is inferred (or a clock enable is inferred etc.)
The code here was clearly made for synthesis. The term "infer a
latch"
generally means a gated transparent latch, not a flip-flop that
doesn't change state on every clock cycle. The classic D latch would
look like:

always @*
if (G) Q = D;

Note that @* is the same in this case as @ (G or D). This sort
of code will invariably trigger a warning during synthesis like

WARNING: Found 1 bit latch for signal Q

While I have used a blocking assignment in this case, the
difference between this latch and the flip-flop in the
original example is not blocking vs. non-blocking assignments.

The difference is in the sensitivity list as noted by Muzaffer.
Whether synthesis results in a D flip-flop with a feedback
mux, or a D flip-flop with a clock enable probably depends
on the target hardware. In no case would synthesis result
in a transparent latch with the original code.

Regards,
Gabor
 
On Jul 11, 1:29 am, gabor <ga...@alacron.com> wrote:
On Jul 10, 3:03 pm, Muzaffer Kal <k...@dspia.com> wrote:



On Thu, 10 Jul 2008 11:40:24 -0700 (PDT), Roosta <opeh...@gmail.com
wrote:

Given that this is a clocked process, the synthesis may infer
a clock enable. Generally you need to worry about else or
default clauses for combinatorial logic, not flip-flops.- Hide quoted text -

- Show quoted text -

So what is inferred here? This below?

packet_wdata[63:0] <= packet_wdata[63:0]

And where is it documented that omitted a default clause in non-
blocking infers that? Just curious because I didn't know. I'm
reading a synthesis book now and maybe have not come across that yet.

We're talking about procedural assignments here which are basically
triggered assignments ie if the events in the dependency trigger the
block is executed. But also there is a conditional assignment in the
block which is triggered by the always block. This conditional
assignment also plays a role in whether the assignment is executed or
not. So if the condition evaluates to false the assignment is not
executed at all in which case the value stored in the register doesn't
change. You can interpret this as if there is an else statement which
assigns the register to itself, which is one of the possible ways the
logic is synthesized ie there is a mux at the input of the flop which
is controlled by the output of the "if" statement. If it's true the
new value is forwarded to the data input of the flop and if it's false
the current output of the flop is forwarded to the input of the flop.
But in RTL simulation the simulator probably doesn't even schedule an
assignment event so the value stays the same but in actual hardware in
every clock cycle there has to be something at the data input of the
flop so the mux is inferred (or a clock enable is inferred etc.)

The code here was clearly made for synthesis. The term "infer a
latch"
generally means a gated transparent latch, not a flip-flop that
doesn't change state on every clock cycle. The classic D latch would
look like:

always @*
if (G) Q = D;

Note that @* is the same in this case as @ (G or D). This sort
of code will invariably trigger a warning during synthesis like

WARNING: Found 1 bit latch for signal Q

While I have used a blocking assignment in this case, the
difference between this latch and the flip-flop in the
original example is not blocking vs. non-blocking assignments.

The difference is in the sensitivity list as noted by Muzaffer.
Whether synthesis results in a D flip-flop with a feedback
mux, or a D flip-flop with a clock enable probably depends
on the target hardware. In no case would synthesis result
in a transparent latch with the original code.

Regards,
Gabor
The code is effectively

reg [63:0] hdr ;
reg sob ;

always @(posedge clk200, negedge reset_n)
if (!reset_n)
packet_wdata[63:0] <= 64'd0;
else if (hdr_rden_r[1]) begin
/*
packet_wdata[63:0] <= hdr; // line 1
packet_wdata[63] <= sob; // line 2
*/
packet_wdata[63:0] <= {sob, hdr[62:0]};
...
...
end
else if (pkt_wen_pre2)
packet_wdata[63:0] <= {data_h, mix_doutfifo_rdata[31:0]};

and it produces no latch...

regards
 

Welcome to EDABoard.com

Sponsor

Back
Top