Synthesizable for-loop

S

Shaun

Guest
I'm trying to implement a synthesizable array of D flip-flops using a
for-loop. I'm using the Altera Quartus compiler. It doesn't seem to
like having the sensitivity list inside the for-loop. Is the following
code correct, and if it is, how can I reword it to make it more
palatable to Quartus?

Thanks,
Shaun

wire [7:0] rx;
reg [7:0] active;
always begin
integer i;
for (i = 0; i < 8; i = i + 1) begin
@(negedge rx)
active <= 1'b1;
end
end

Error (10856): Verilog HDL error at repeater.v(83): multiple event
control statements not supported for synthesis
 
On Jan 29, 11:11 am, "Shaun" <sjack...@gmail.com> wrote:
I'm trying to implement a synthesizable array of D flip-flops using a
for-loop. I'm using the Altera Quartus compiler. It doesn't seem to
like having the sensitivity list inside the for-loop. Is the following
code correct, and if it is, how can I reword it to make it more
palatable to Quartus?

Thanks,
Shaun

wire [7:0] rx;
reg [7:0] active;
always begin
integer i;
for (i = 0; i < 8; i = i + 1) begin
@(negedge rx)
active <= 1'b1;
end
end

Error (10856): Verilog HDL error at repeater.v(83): multiple event
control statements not supported for synthesis

Use a generate statement instead.

-a
 
On 29 Jan 2007 10:11:19 -0800, "Shaun" <sjackman@gmail.com> wrote:

I'm trying to implement a synthesizable array of D flip-flops using a
for-loop. I'm using the Altera Quartus compiler. It doesn't seem to
like having the sensitivity list inside the for-loop. Is the following
code correct
No :)

rx;
reg [7:0] active;
always begin
integer i;
for (i = 0; i < 8; i = i + 1) begin
@(negedge rx)
active <= 1'b1;
end
end

Oh dear. Do you really want to do that?

I'm guessing that you want to create 8 FFs, each of which
is set by the rising edge of an individual signal rx. But your
code doesn't do anything at all like that. @(negedge...)
freezes execution until the event occurs. Suppose you fall
into this for-loop and rx[0] happens to be stubbornly idle.
The very first pass round the loop freezes at
@(negedge rx[0])
and meanwhile all your other rx[...] inputs can be flailing
around like a bunch of eels in a bucket and your code would
be none the wiser.

We'll talk about how you could implement the array of FFs
in a moment. However, I strongly suspect you DON'T want
to do it at all, because it creates one clock domain per input
signal. If this is, as I guess, some sort of interrupt register,
then I would be MUCH more comfortable with a piece of
code that:
(1) resynchronises all the inputs to your common system clock;
(2) synchronously edge-detects them by passing them through
another register and detecting (for each one) the condition
"was 1 on the previous clock, is 0 on this clock".

Anyway, that's me trying to do your design for you, so let's
not go there; instead here's how to build a bunch of
eight flops (oh, and I presume you have some other way
to set them back to zero, which you haven't mentioned for
the sake of brevity):

module(...);
wire [7:0] rx;
reg [7:0] active;
generate
genvar i;
for (i=0; i<8; i=i+1) begin: CaptureFlops
always @(negedge rx) begin
active <= 1'b1;
end
end
endgenerate
endmodule

In other words, build 8 separate always blocks for the
8 clock domains. A single clocked always block can
handle only one single clock signal.

A word of warning: some synthesis tools like the genvar
declaration to be outside the generate/endgenerate,
some like it to be inside. Try it and see. Both are legal
Verilog.
--
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 Jan 29, 11:25 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
I'm guessing that you want to create 8 FFs, each of which
is set by the rising edge of an individual signal rx. But your
code doesn't do anything at all like that. @(negedge...)
freezes execution until the event occurs. Suppose you fall
....


Interesting. I hadn't expected that behaviour. So what I built was a
state machine, with each interrupt line moving to the next state in
succession.

We'll talk about how you could implement the array of FFs
in a moment. However, I strongly suspect you DON'T want
to do it at all, because it creates one clock domain per input
signal. If this is, as I guess, some sort of interrupt register,
then I would be MUCH more comfortable with a piece of
code that:
(1) resynchronises all the inputs to your common system clock;
(2) synchronously edge-detects them by passing them through
another register and detecting (for each one) the condition
"was 1 on the previous clock, is 0 on this clock".
You are correct. It is an interrupt register on the bus of a
microcontroller. The microcontroller can read the interrupt register
and reset it with a write. The PLD also implements a PIO expander
where the WRITE line is the clock to an array of D flip-flops and the
READ line qualified by address lines is the output-enable back to the
bus. The PLD does not have a global clock other than these bus lines.
Does it make sense to use either READ or WRITE to synchronise the
interrupt lines? Or should I perhaps generate a global clock internal
to the PLD?

Anyway, that's me trying to do your design for you, so let's
not go there; instead here's how to build a bunch of
eight flops (oh, and I presume you have some other way
to set them back to zero, which you haven't mentioned for
the sake of brevity):
I did omit the reset line. I thought I'd figure that out once I got
set working. <grin>

module(...);
wire [7:0] rx;
reg [7:0] active;
generate
genvar i;
for (i=0; i<8; i=i+1) begin: CaptureFlops
always @(negedge rx) begin
active <= 1'b1;
end
end
endgenerate
endmodule

In other words, build 8 separate always blocks for the
8 clock domains. A single clocked always block can
handle only one single clock signal.

I didn't know of the generate statement. I've been using this [1]
Verilog cheat sheet to answer simple questions about syntax. It seems
relatively complete, but is missing the generate statement. Is there a
more complete guide?

[1] http://www.sutherland-hdl.com/on-line_ref_guide/vlog_ref_body.html

A word of warning: some synthesis tools like the genvar
declaration to be outside the generate/endgenerate,
some like it to be inside. Try it and see. Both are legal
Verilog.
I'm using Altera Quartus, and it was happy with both.

My original solution follows. Any comments or critiques are most
welcome.

module srflipflop(q, set, reset);
output q;
input set, reset;
reg q;
always @(posedge set or posedge reset)
if (reset)
q <= 1'b0;
else if (set)
q <= 1'b1;
endmodule

assign active_oe = ~RD & active_cs;
assign active_r = ~WR & active_cs;
wire [7:0] active;
srflipflop active_ff[7:0](active, ~rx, {8{active_r}});
assign D = active_oe ? active : 8'bZ;

Thank you for your detailed response. Cheers,
Shaun
 
On 29 Jan 2007 14:55:33 -0800, "Shaun" <sjackman@gmail.com> wrote:

[...]
Interesting. I hadn't expected that behaviour. So what I built was a
state machine, with each interrupt line moving to the next state in
succession.
Yes, but not one that any synthesis tool I know could handle.

You are correct. It is an interrupt register on the bus of a
microcontroller. The microcontroller can read the interrupt register
and reset it with a write.
OK.

The PLD also implements a PIO expander
where the WRITE line is the clock to an array of D flip-flops and the
READ line qualified by address lines is the output-enable back to the
bus.
OK, that's good CPLD glue-logic fodder.

The PLD does not have a global clock other than these bus lines.
Oh dear. That makes things a lot harder.

Does it make sense to use either READ or WRITE to synchronise the
interrupt lines?
It might be the only hope, if you have no global clock.

Or should I perhaps generate a global clock internal
to the PLD?
Not generally possible, in most PLDs.

[...]
eight flops (oh, and I presume you have some other way
to set them back to zero, which you haven't mentioned for
the sake of brevity):

I did omit the reset line. I thought I'd figure that out once I got
set working. <grin
I wasn't thinking of reset; I was thinking of your "clear on write"
functionality. Reset is good too, but probably not essential;
your software presumably can clear down the register before
it's enabled the CPU's master interrupt.

Verilog cheat sheet to answer simple questions about syntax. It seems
relatively complete, but is missing the generate statement.
I think that's because it describes ye olde Verilog-1995 standard.
Almost all tools now fully support Verilog-2001, which introduced
"generate" and a few other useful goodies.

Is there a more complete guide?
Yes, but we want some money for them :)
www.doulos.com/content/products/golden_reference_guides.php

My original solution follows. Any comments or critiques are most
welcome.

module srflipflop(q, set, reset);
output q;
input set, reset;
reg q;
always @(posedge set or posedge reset)
if (reset)
q <= 1'b0;
else if (set)
q <= 1'b1;
endmodule

assign active_oe = ~RD & active_cs;
assign active_r = ~WR & active_cs;
wire [7:0] active;
srflipflop active_ff[7:0](active, ~rx, {8{active_r}});
assign D = active_oe ? active : 8'bZ;
There's not much wrong with that, except the set/reset flop.
It is not a standard coding style, and you really need to
check exactly what Quartus is creating from it. Because of
the non-standard coding, it's not at all obvious whether you
get level-sensitive or edge-sensitive setting and resetting.
Flops with both asynchronous set AND reset is a long-standing
issue in Verilog coding styles for synthesis; if you can stay
out of that territory, you'll be a happier and saner person.

Otherwise, the obvious flaw is the possibility that one of the
"set" (interrupt) inputs might be changing during the CPU's
read cycle, yielding indeterminate data. However, since
you are only concerned with the individual interrupt flags
and not the numeric value of the interrupt word, this is
unlikely to be a problem in practice.

For the record, if you could do The Decent Thing (tm) and
bring in the microprocessor's clock on to the PLD as a
global clock, I'd do this instead (using Verilog-2001
so I get a sensible port list with the declarations in it):

module int_req_register (
input clock, reset, // System clock, power-up reset
input [7:0] n_irq, // External active-low interrupt requests
input active_cs, nWR nRD, // CPU databus controls
input [7:0] CPU_data, // CPU write data
output reg [7:0] irq_active // Registered requests
);

reg [7:0] irq_resync, irq_edge_sense;
integer i; // loop counter only
always @(posedge clock or posedge reset)
if (reset) begin
irq_active <= 0;
irq_resync <= 0;
irq_edge_sense <= 0;
end else begin // Clocked logic
// resynchronise and edge detect the interrupts
irq_resync <= ~n_irq; // put it the right way up
irq_edge_sense <= irq_resync;
// Manage the interrupt register. Default behaviour
// is to set any bit for which there is a fall on irq input
// (i.e. irq_resync high, irq_edge_sense low).
irq_active <= irq_active | (irq_resync & ~irq_edge_sense);
// Reset every bit of the irq_active for which your
// written data is 1, if you're writing.
if (active_cs && ~nWR)
for (i=0; i<8; i=i+1)
if (CPU_data)
irq_active <= 1'b0;
// if executed, the preceding statement overrides any
// earlier assignment to that bit of irq_active
end // clocked logic
endmodule

You still need your read-enable to put data on to the CPU's
data bus, of course:
assign D = active_oe ? active : 8'bZ;
where "active" is the connection from the int_req_register's
8-bit "irq_active" output.

Note that I've also, very cheaply, added the ability to reset
the interrupt flags selectively - if you want to reset the
whole lot, write 0xFF to the appropriate register.

This is a much cleaner and more portable design.

Depending on the CPU's bus cycle timing, it might be appropriate
to qualify the write strobe signals somewhat so that they last for
only one clock cycle.
--
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.
 
Shaun wrote:
Interesting. I hadn't expected that behaviour. So what I built was a
state machine, with each interrupt line moving to the next state in
succession.
Yes. Once you get into procedural code, such as inside
an always block, execution of that procedural code is
sequential. An always block creates a single thread of
execution that executes its body sequentially and then
loops back to the top and continues there.

The generate loop is a structured way of creating multiple
always block instances, which then execute independently
in parallel.

These are the language or simulation semantics, for
which synthesis tools try to produce corresponding
hardware.


Does it make sense to use either READ or WRITE to synchronise the
interrupt lines?
If you don't at least do this, then your design has
the potential for a serious timing race. If the
interrupt gets set during a read cycle, there may
or may not be time for that value to propagate
through the logic in your CPU before you latch
the result. And if there are multiple latches in the
CPU that are affected by the interrupt value that
is read, it might make it to some in time, but not to
others. Your CPU might end up in a state that is
not consistent with the interrupt being either true
or false. This unexpected state might be disastrous
for the CPU.

Even with synchronization using READ, if the
interrupt request is asynchronous, it may not meet
the setup/hold requirements with respect to READ.
This could put your interrupt latch into a metastable
state. Instead of picking true or false immediately,
it could take an indeterminate period of time to
decide. A late transition could get you into the same
race problem described above. The probability of
this problem is dependent on the technology of the
latch, and decreases exponentially with the time
allowed for the value to settle. So if you have plenty
of setup time in your read cycle, this may occur
rarely enough not to be a problem in practice.

If you don't, then the usual solution is to provide
multiple cycles of settling time by clocking the
value through multiple levels of synchronization
flops before sampling it. That requires some kind
of clock to be available. Alternately, you could
have some kind of read or write cycle that captures
a sample, and then come back and read the result
after enough delay (the next CPU cycle is probably
late enough).


A word of warning: some synthesis tools like the genvar
declaration to be outside the generate/endgenerate,
some like it to be inside. Try it and see. Both are legal
Verilog.
As of Verilog-2005, the generate/endgenerate can
be omitted entirely.


My original solution follows. Any comments or critiques are most
welcome.

module srflipflop(q, set, reset);
output q;
input set, reset;
reg q;
always @(posedge set or posedge reset)
if (reset)
q <= 1'b0;
else if (set)
q <= 1'b1;
endmodule
If this was intended to model a level-sensitive
SR flop (with priority for reset), then it has some
flaws.

Consider the following input sequence:
1. set and reset are false
2. set goes true, and q becomes 1
3. reset goes true, and q becomes 0
(because reset has priority)
4. reset goes false, while set is still true

Since the event control is not sensitive to
the negedge of reset, it will not wake up,
and q will remain 0. But for a level-sensitive
SR flop, q should go to 1 since set is still
true while reset is false.

To model a level-sensitive flop, you would
need to remove the posedge from reset.
This would then cause it to wake up on that
negedge of reset and determine the correct
output for the current input state. You could
remove the posedge from set also, but it is
not necessary in this case, and would cause
unnecessary evaluations.
 
On Jan 30, 2:13 pm, s...@cadence.com wrote:
....
My original solution follows. Any comments or critiques are most
welcome.

module srflipflop(q, set, reset);
output q;
input set, reset;
reg q;
always @(posedge set or posedge reset)
if (reset)
q <= 1'b0;
else if (set)
q <= 1'b1;
endmodule

If this was intended to model a level-sensitive
SR flop (with priority for reset), then it has some
flaws.
....
To model a level-sensitive flop, you would
need to remove the posedge from reset.
This would then cause it to wake up on that
negedge of reset and determine the correct
output for the current input state. You could
remove the posedge from set also, but it is
not necessary in this case, and would cause
unnecessary evaluations.
My synthesis software (Altera Quartus) complains on @(posedge set or
reset).
Error: mixed single- and double-edge expressions are not supported

Seems odd, but fair enough.

For the level-sensitive version, @(set or reset), it emits a warning.
Warning: inferring latch(es) for variable "q", which holds its
previous value in one or more paths through the always construct

The latch output is declared as `output reg q', which I thought would
be enough to suppress the warning. On my hardware, an Altera PLD with
128 macrocells, the latch takes 2 more macrocells than the flip-flop.
Is there such a thing as an edge-sensitive SR flip-flop, where both
the S & R posedge do the sensible thing and negedge are ignored?
That's what I had attempted to write above, except that a posedge on S
would reset the flip-flop if R is high at the time of the edge. In
fact, what I wrote above appears to be level-sensitive to the reset
line, and edge-sensitive to the set line. Is that correct? As in the
following pseudocode
q = reset ? 0 : posedge set ? 1 : q;
whereas a SR latch is
q = reset ? 0 : set ? 1 : q;
and the (possibly mythical) SR flip-flop I described would be
q = posedge reset 0 : posedge set ? 1 : q;

If I'm correct, then what I wrote is a D flip-flop with a level-
sensitive reset where
q = reset ? 0 : posedge clk ? d : q;
and d is always 1.

Is it possible to design a flip-flop sensitive to only the edges of S
& R? I suppose that's essentially a flip-flop with two clocks, which
would be rather unusual.

Thanks for your explanation of timing races, synchronization, and
metastability. I'll have to mull it over and do some reading, but I
believe I understand the brunt of it. Cheers,
Shaun
 
On Jan 30, 2:57 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
....
Is there a more complete guide?

Yes, but we want some money for them :)
www.doulos.com/content/products/golden_reference_guides.php
Thanks for the pointer. I ordered one yesterday.

For the record, if you could do The Decent Thing (tm) and
bring in the microprocessor's clock on to the PLD as a
global clock, I'd do this instead (using Verilog-2001
so I get a sensible port list with the declarations in it):
The Verilog-2001 port-declaration syntax is much better. Thanks for
the tip.

module int_req_register (
....
endmodule

You still need your read-enable to put data on to the CPU's
data bus, of course:
assign D = active_oe ? active : 8'bZ;
where "active" is the connection from the int_req_register's
8-bit "irq_active" output.

Note that I've also, very cheaply, added the ability to reset
the interrupt flags selectively - if you want to reset the
whole lot, write 0xFF to the appropriate register.

This is a much cleaner and more portable design.
Your design is very good reading. Thank you. To detect the rising edge
of the interrupt signal, you fed the signal into two cascaded latches,
looking for a zero in one latch and a one in the next. I take it this
is fundamentally how synchronization is implemented. Is it generally a
mistake to build logic that uses the edge of any external signal that
is not synchronous to the clock?

Cheers,
Shaun
 
end else begin // Clocked logic
// resynchronise and edge detect the interrupts
irq_resync <= ~n_irq; // put it the right way up
irq_edge_sense <= irq_resync;
// Manage the interrupt register. Default behaviour
// is to set any bit for which there is a fall on irq input
// (i.e. irq_resync high, irq_edge_sense low).
irq_active <= irq_active | (irq_resync & ~irq_edge_sense);
// Reset every bit of the irq_active for which your
// written data is 1, if you're writing.
if (active_cs && ~nWR)
for (i=0; i<8; i=i+1)
if (CPU_data)
irq_active <= 1'b0;
// if executed, the preceding statement overrides any
// earlier assignment to that bit of irq_active
end // clocked logic
endmodule


Just wanted to note for Shaun that as stated in the comment above the
CPU write overrides the earlier assignments to the interrupt vector.
In my experience this is usually not what you want to do in this type
of case, because if the input interrupt pulse happens to occur on the
same cycle that the CPU write is trying to clear the interrupt then
you "lose" the new interrupt. Usually you want to do the CPU clear
first, and then set the interrupts if any of the inputs are active.

RPD
 
"Shaun" <sjackman@gmail.com> wrote in message
news:1170264921.270625.314390@a34g2000cwb.googlegroups.com...
On Jan 30, 2:13 pm, s...@cadence.com wrote:
...
snip
My synthesis software (Altera Quartus) complains on @(posedge set or
reset).
Error: mixed single- and double-edge expressions are not supported

Seems odd, but fair enough.
snip

You get this warning because you don't either 1) specify @(posedge set or
posedge reset) which isn't valid in hardware anyway, or 2) have an if(
reset ) clause directly below your @(posedge set or reset) to asynchronously
clear your register.

If you want a clock-based set and a clock-based reset rather than using an
S-R latch (2 combinatorial elements) you need two registers clocked by the
individual sources and use of an XOR to get a combinatorial result.

Most designers get a real clock into the system in order to avoid problems
like this.

As long as you can make sure the set and reset don't occur at the same time,
your edge-controlled system could use a syntax such as:

reg Qs, Qr;
always @(posedge set) Qs <= ~Qr;
always @(posedge reset) Qr <= Qs;
wire Q = Qr ^ Qs;

You can use a generate block to have 8 different sets and 8 different resets
for 8 Qs/Qr pairs.

- John_H
 
On 31 Jan 2007 09:55:25 -0800, "Shaun" <sjackman@gmail.com> wrote:

To detect the rising edge
of the interrupt signal, you fed the signal into two cascaded latches,
looking for a zero in one latch and a one in the next. I take it this
is fundamentally how synchronization is implemented.
Yes, if you can be sure that the external input is changing slowly
with respect to your clock. It's a form of oversampling.

If the input signal is not clean - such as a mechanical switch
that bounces - then the synchronisation may require further tricks.

Is it generally a
mistake to build logic that uses the edge of any external signal that
is not synchronous to the clock?
Yes, except in a few very special situations. Obviously there are
times when it's unavoidable.
--
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 31 Jan 2007 10:18:39 -0800, "rpd_design"
<rdonohue@yahoo.com> wrote:

Just wanted to note for Shaun that as stated in the comment above the
CPU write overrides the earlier assignments to the interrupt vector.
In my experience this is usually not what you want to do in this type
of case, because if the input interrupt pulse happens to occur on the
same cycle that the CPU write is trying to clear the interrupt then
you "lose" the new interrupt. Usually you want to do the CPU clear
first, and then set the interrupts if any of the inputs are active.
Interesting.... Your analysis of my code is spot-on, but I'm not sure
I agree about the desired behaviour.
In any of these request-acknowledge efforts there's always the
problem of acknowledge racing with request. That's why I added
the "selective clear" feature, in which requests are cleared only if
the corresponding bit is written as '1'. The normal usage model
would be:

- Detect that one or more bits are set in the request register,
and use that to trigger a CPU interrupt
- On interrupt service, read the request register to find which
requests are active; log that information somewhere
- Write back EXACTLY the same value you read from the request
register. This will clear only those bits that were set when
you read it, i.e. requests that you are going to service anyway.
If one of those was asserted again at the moment you tried
to clear it, it doesn't matter because you're going to service
that request anyway.
- Meanwhile, if any other requests have been activated between
you reading the request and acknowledging it, you won't set
those bits in your acknowledge and therefore they'll still be there
after you did the acknowledge - so you get another interrupt.

But I definitely agree that it's an issue that needs careful thought.
--
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 30 Jan 2007 13:13:32 -0800, sharp@cadence.com wrote:


A word of warning: some synthesis tools like the genvar
declaration to be outside the generate/endgenerate,
some like it to be inside. Try it and see. Both are legal
Verilog.

As of Verilog-2005, the generate/endgenerate can
be omitted entirely.
Is it particularly sinful or un-stylish to leave them in?
I find the presence of "for", "if" and "case" at the top level
of a module to be somewhat disturbing unless they're
enclosed in generate...endgenerate as a visual clue.

--
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 31 Jan 2007 09:35:21 -0800, "Shaun"
<sjackman@gmail.com> wrote:

For the level-sensitive version, @(set or reset), it emits a warning.
Warning: inferring latch(es) for variable "q"
Yes. The problem is that FPGA/CPLD devices do not usually have
asynchronous latches as built-in primitives. Consequently, you
need to manufacture them from cross-coupled logic gates.
This gives rise to cyclic paths in the "combinational" logic. Such
cyclic paths give both optimisation and timing analysis software
a very hard time, and - unless you take special care - can easily
lead to hardware that doesn't work the way you intended.

The latch output is declared as `output reg q', which I thought would
be enough to suppress the warning.
Nah. "reg" in Verilog just declares the object as a variable -
something that gets its value by procedural assignment rather
than by connection. It says nothing about hardware structures.
Here's a reg that doesn't look even remotely like a flop or latch:

reg NAND;
always @(a or b) NAND = ~(a & b);

Is there such a thing as an edge-sensitive SR flip-flop, where both
the S & R posedge do the sensible thing and negedge are ignored?
Yes. You can build it from two regular flip-flops and a little low
cunning - the only time I've ever seen this actually written down
was by Bob Weinstein who christened it the Flancter, thereby
rendering Google searches for it somewhat easier :)

Here it is... it should synthesise without difficulty.

// Immediately after a Set_clock, Qs and Qr are DIFFERENT.
always @(posedge Set_clock)
if (Qr) Qs <= 0; else Qs <= 1; // Qs <= ~Qr;
// Immediately after a Reset_clock, Qs and Qr are THE SAME.
always @(posedge Reset_clock)
if (Qs) Qr <= 1; else Qr <= 0; // Qr <= Qs;
// Report "They are different" to the outside world.
assign Set_not_reset = Qs ^ Qr;

The curious "if" formulation is designed to get rid of X values in
simulation without requiring an explicit power-up reset. I wouldn't
normally cheat quite so blatantly, but I'm able to reason that the
Flancter circuit in reality catches up with itself after the very
first clock event on either of the two inputs. My simulation
model is a little more pessimistic than that, requiring a clock
event on each of the two inputs before giving a deterministic
output instead of X.

The output signal "Set_not_reset" goes to 1 after each rising edge
on Set_clock, and to 0 after each rising edge on Reset_clock.

In an otherwise synchronous design, this approach leads to some
interesting difficulties because Set_not_reset is not synchronous
with ANYTHING - its rising edges are synchronous with Set_clock,
and its falling edges with Reset_clock.
--
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 Feb 1, 6:18 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On 30 Jan 2007 13:13:32 -0800, s...@cadence.com wrote:

As of Verilog-2005, the generate/endgenerate can
be omitted entirely.

Is it particularly sinful or un-stylish to leave them in?
I find the presence of "for", "if" and "case" at the top level
of a module to be somewhat disturbing unless they're
enclosed in generate...endgenerate as a visual clue.
I wouldn't think so.

From a parser perspective, they were never needed.

From a user perspective, they could have provided better
error checking. A user might forget the "initial" keyword and
start their procedural for/if/case at the top level. This looks
to the parser like a generate construct, and will probably
produce confusing error messages about the rules for
generates, instead of about the lack of initial/always.

Requiring generate/endgenerate around these generate
constructs would allow the parser to distinguish whether
they were intended to be generate constructs or not.
Unfortunately, this capability was weakened because the
2001 standard did not restrict the contents of generate-
endgenerate to only be generate constructs. It allowed
arbitrary module items to appear there, including initial
blocks. So the bare for/if/case inside the generate region
might have been intended to be a procedural one inside a
missing initial after all. The parser still cannot tell. The
2005 LRM does say that parsers may use them to give
better error messages.

They do provide value for human readers if you use them
around generate constructs and don't use them around
other constructs. The reader is less likely to misread them
as procedural constructs that way. Unlike parsers, humans
may not notice the missing "initial".
 
On Jan 31, 12:35 pm, "Shaun" <sjack...@gmail.com> wrote:
Thanks for your explanation of timing races, synchronization, and
metastability. I'll have to mull it over and do some reading, but I
believe I understand the brunt of it
Note that there probably won't be a serious problem with
the read of the register. That probably only sets a single
register in your CPU to the unstable value. It will probably
have stabilized in this second register before you do
anything with it.

The real problem would be with the interrupt signal going
into the CPU that causes the interrupt. If you get a race
such that some of the PC bits jump to the interrupt vector
value, and the others go to PC+1, the CPU goes into the
weeds. This probably isn't a problem if you are using an
existing CPU design that has an interrupt input that was
designed to be asynchronous. The designer presumably
put in the necessary synchronization stages to prevent
this.
 

Welcome to EDABoard.com

Sponsor

Back
Top