Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

beginner synthesize question - my debounce process won't synthesize.

23 views
Skip to first unread message

jleslie48

unread,
Jan 5, 2009, 11:20:04 AM1/5/09
to
hello all,

I'm sure their are different ways to do this, and I would like to
explore them at a later date, but as I'm still novice at VHDL coding
I'd like to know what is wrong with this particular code. Its a
simple debounce process and the synthesize reports an error on line
44:

----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 08:06:38 12/31/2008
-- Design Name:
-- Module Name: VhdlModule1 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library
IEEE;
--line 20
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity VhdlModule1
is
--line 30
port( CLK : in std_logic;
SIGNAL_IN : in std_logic;
SIGNAL_OUT : out std_logic);
end VhdlModule1;


architecture Behavioral of VhdlModule1 is

constant DEBOUNCE_COUNT : integer := 5;
signal SIGNAL_OUT_TEMP : std_logic := '0';

begin

P1: process (CLK, SIGNAL_IN,
SIGNAL_OUT_TEMP) -- line 44
variable mycount : integer := 0;
begin
if (CLK = '1' and CLK'event and SIGNAL_OUT_TEMP /= SIGNAL_IN) then
mycount := mycount +
1;
-- line 48
if (mycount >= DEBOUNCE_COUNT) then
SIGNAL_OUT_TEMP <= SIGNAL_IN;
mycount := 0;
end if;
else
mycount :=
0;
-- line 54
end if;
SIGNAL_OUT <= SIGNAL_OUT_TEMP;
end process P1;

end Behavioral;

-----------------------------------------------------------------------------------------------------------------------------

the error message is this:
*******************************************
Analyzing Entity <VhdlModule1> in library <work> (Architecture
<Behavioral>).

ERROR:Xst:827 - "//dhpc-1/shared/jon/MyVhdl/VhdlModule1.vhd" line 44:
Signal mycount cannot be synthesized, bad synchronous description. The
description style you are using to describe a synchronous element
(register, memory, etc.) is not supported in the current software
release.

******************************************
I've tried this code with both 9.2 and the 10.1 ISE with no change.
I've also tried declaring mycount as a SIGNAL and that didn't change
anything either (another question is why I would want mycount to be a
SIGNAL or a VARIABLE, pros and cons but lets stick to the main issue
first)

In my trial and terror attempt to fix this synth, I can report that if
I comment out either line 48 or 54 the synth works, but I don't
understand why I can't have both lines in and the code be valid.

I'm guessing my problem is me trying to program with my single cpu,
sequential processing C background in the very non-linear non-
sequential environment that is VHDL, so any insight into this would be
helpful.

Sincerely,

Jon

Nathan Bialke

unread,
Jan 5, 2009, 11:44:09 AM1/5/09
to
> P1: process (CLK, SIGNAL_IN,
> SIGNAL_OUT_TEMP)                                            -- line 44
> variable mycount : integer := 0;
> begin
>         if (CLK = '1' and CLK'event and SIGNAL_OUT_TEMP /= SIGNAL_IN) then
>                 mycount := mycount +
> 1;
> -- line 48
>                 if (mycount >= DEBOUNCE_COUNT) then
>                         SIGNAL_OUT_TEMP <= SIGNAL_IN;
>                         mycount := 0;
>                 end if;
>         else
>                 mycount :=
> 0;
> -- line 54
>         end if;
>         SIGNAL_OUT <= SIGNAL_OUT_TEMP;
> end process P1;
>
> end Behavioral;

First, consider what it is you're trying to synthesize in terms of
discrete logic parts (think 74xx series logic components).

Then, you will probably find that your problem is that there are no
logic elements that can support how you're describing mycount. mycount
as described can change on both the rising and falling edges of CLK.
Most likely, the FPGA you are designing for does not have dual-edge
triggered internal flipflops (although interestingly, CoolRunner CPLDs
do). I also think that's not what you want. In addition, I suspect
you'll have a problem with SIGNAL_OUT for similar reasons, but I'll
leave that as an exercise to you.

rickman

unread,
Jan 5, 2009, 1:26:07 PM1/5/09
to
What Nathan said is correct. Specifically what you are doing wrong is
including the comparison "SIGNAL_OUT_TEMP /= SIGNAL_IN" in the IF that
detects the rising edge of the clock. You also have an else condition
that covers the case when the comparison fails, as well as any time
the clock is ***NOT*** at a rising edge. You need to separate the if
for the clock edge from the if for the enabling condition.

You will do much better as a beginner if you don't treat an HDL as a
programming language, but rather use it to describe hardware. When
you try to "program" in an HDL you often end up with code that is not
even synthesizable as you have done. Don't "program" hardware,
"describe" hardware!

So first think of the hardware you want to implement and then look up
the HDL constructs that will produce this hardware. Logic is pretty
much logic, but registers take a little practice to get right. You
have to specify the clock correctly and consistently as well as
understanding when a clock enable will be used and when all of the
logic will be rolled into the D input of the D-FF.

A couple of points about how you are generating SIGNAL_OUT. The
debounce circuit must prevent SIGNAL_OUT from glitching, but it does
not *have* to introduce a delay. Also, your design is retriggerable
so that each time the input changes earlier than the timeout the
counter resets and starts over. Another way to do this is to use a
longer timeout that is assured of being longer than the debounce time
and updating SIGNAL_OUT as soon as the input changes the *first*
time. So the input change is detected and the output follows while
the counter starts. Until the counter reaches the timeout, SIGNAL_OUT
is inhibited from changing again. This prevents the output from
bouncing, but does not introduce the delay that the circuit below will
have.

Rick

jleslie48

unread,
Jan 5, 2009, 5:53:38 PM1/5/09
to

Nathan and Rick,

Wonderful insight, thank you both.

You both hit the nail on the head, by stating:

"First, consider what it is you're trying to synthesize in terms of
discrete logic parts "

"You will do much better as a beginner if you don't treat an HDL as a


programming language, but rather use it to describe hardware."

I have never dealt with hardware in my entire 25 year career. I have
strictly done software programming,
and I realize that my interpretations of this very hardware one-to-one
mapped environment is wrong. Quite frankly,
I don't even know what a D-FF (a "D" flip-flop??) is. My boss just
stuck me in the front of the plane because all of the
real pilots were sucked out of the cockpit during the explosion. I'm
flying blind here.

But I want to learn how to do this right, so I'm trying to re-train my
brain.

Anyway, so here of course is the simple fix to my synth problem (at
least I'm not calling it a compile anymore!):

P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)

variable mycount : integer := 0;
begin

if (CLK = '1' and CLK'event ) then --{1
if (SIGNAL_OUT_TEMP /= SIGNAL_IN) then --{2


mycount := mycount + 1;

if (mycount >= DEBOUNCE_COUNT) then --{3


SIGNAL_OUT_TEMP <= SIGNAL_IN;
mycount := 0;

end if; --3}
else
mycount := 0;
end if; --2}

end if; --1}


SIGNAL_OUT <= SIGNAL_OUT_TEMP;
end process P1;

Now my process only does something on a RISING edge of the clock
pulse, as a clocked process should do.
However I cannot "see" my hardware situation in my head. I think that
my issue with the bad program is that
line 54 would be wrongly firing on every FALLING edge of CLK as well
and thus not have me achieve the desired
results, but I don't see how the compiler, err, synthesize function,
was able to discern my intention. From what you
two have said is I must of made a situation where the wiring of the
"hardware" was impossible, but I don't see that.

I also see that my debounce, will also put a delay of 5 clock pulses
after SIGNAL_IN stops bouncing before effecting
a change in SIGNAL_OUT_TEMP and then one more clock pulse for the
change to effect SIGNAL_OUT.

I'm not sure what you are getting out Nathan, other than my original
[wrong] code as shown would of never allowed MYCOUNT
to get above 1, so SIGNAL_OUT would be forever stuck at
SIGNAL_OUT_TEMP's initial state.

Rick though, you intrigue me on improving the debounce design. I
believe you have pointed out that my debounce functionality will not
raise the state of SIGNAL_OUT_TEMP until after 5 CLK rising edges
after all bounces. What I think you are getting at is that I should
raise the state of SIGNAL_OUT_TEMP immediately on SIGNAL_IN, but then
not do anything to SIGNAL_OUT_TEMP until an appropriate amount
of Clock pulses after the input stops bouncing, aka assume the state
change, but don't bother looking again until the dust settles.


jleslie48

unread,
Jan 5, 2009, 6:06:10 PM1/5/09
to

ok a D flip flop means that whatever its input is its output is
delayed to the next rising edge :)))

Gabor

unread,
Jan 5, 2009, 7:03:39 PM1/5/09
to
On Jan 5, 1:26 pm, rickman <gnu...@gmail.com> wrote:
[SNIP]

> A couple of points about how you are generating SIGNAL_OUT.  The
> debounce circuit must prevent SIGNAL_OUT from glitching, but it does
> not *have* to introduce a delay.  Also, your design is retriggerable
> so that each time the input changes earlier than the timeout the
> counter resets and starts over.  Another way to do this is to use a
> longer timeout that is assured of being longer than the debounce time
> and updating SIGNAL_OUT as soon as the input changes the *first*
> time.  So the input change is detected and the output follows while
> the counter starts.  Until the counter reaches the timeout, SIGNAL_OUT
> is inhibited from changing again.  This prevents the output from
> bouncing, but does not introduce the delay that the circuit below will
> have.
>
> Rick

Strictly speaking to de-glitch the input you do need to
add a delay. If you only want to de-bounce the signal
you don't. The circuit as described will filter out glitches
shorter than DEBOUNCE_COUNT.

rickman

unread,
Jan 5, 2009, 7:14:58 PM1/5/09
to
On Jan 5, 5:53 pm, jleslie48 <j...@jonathanleslie.com> wrote:
> On Jan 5, 1:26 pm, rickman <gnu...@gmail.com> wrote:
>
> Anyway, so here of course is the simple fix to my synth problem (at
> least I'm not calling it a compile anymore!):

Heck, I call it compiling. I get tired of saying those big words like
synthesize and instantiate, etc. I AM compiling my description of a
design into something that the machine understands. At that level, it
*is* just like software... some software anyway. I use Forth where I
can and that is a whole different thing...


> P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)
> variable mycount : integer := 0;
> begin
>         if (CLK = '1' and CLK'event ) then --{1
>              if (SIGNAL_OUT_TEMP /= SIGNAL_IN) then --{2
>                     mycount := mycount + 1;
>                     if (mycount >= DEBOUNCE_COUNT) then  --{3
>                              SIGNAL_OUT_TEMP <= SIGNAL_IN;
>                              mycount := 0;
>                         end if; --3}
>                 else
>                    mycount := 0;
>                 end if; --2}
>
>         end if; --1}
>         SIGNAL_OUT <= SIGNAL_OUT_TEMP;
> end process P1;

You are using a variable for mycount. I may be showing my ignorance
of variables, but it is not clear to me exactly what the comparison
will do since it follows the increment.


> mycount := mycount + 1;
> if (mycount >= DEBOUNCE_COUNT) then --{3

The difference between a variable and a signal has to do with *when*
you look at the value in other statements. In this case mycount will
synthesize to a register. It will use an incrementer to do the +1 and
will use a comparitor to test for >= DEBOUNCE_COUNT. It will also
have a reset signal to clear it depending on the count. The signal
comparison will be also be part of the logic for the clear. But how
exactly will the value of mycount be used in the test with
DEBOUNCE_TEMP? You are doing the test after you have incremented it,
but by the rules of synthesis, this is not the value that will be
latched into the register on the clock edge. That value will depend
on the result of the comparison.

I am not saying this is a bad design because I am not sure. As much
as anything I am showing that I seldom work with variables and I just
plain don't know what this will synthesize. If you make mycount a
signal, then the input to everything within the process will be the
direct output of the register and the resulting circuit will be very
clear. The rules of signal synthesis is that the value latched in the
register is the last value assigned during the process. All other
values are in essence "over written" before the clock edge is done.
For a variable, each value assigned is in use until the next value
assigned.


> Now my process only does something on a RISING edge of the clock
> pulse, as a clocked process should do.
> However I cannot "see" my hardware situation in my head.  I think that
> my issue with the bad program is that
> line 54 would be wrongly firing on every FALLING edge of CLK as well
> and thus not have me achieve the desired
> results, but I don't see how the compiler, err, synthesize function,
> was able to discern my intention.  From what you
> two have said is I must of made a situation where the wiring of the
> "hardware" was impossible, but I don't see that.

The synthesis could not "see" your intent and so it threw up its hands
and cried "foul"! BTW, not only was the use of the else clause wrong,
but as long as I am criticizing... opps, "giving advice", I'll point
out that your sensitivity list is overly populated.

P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)

You are using a clock, but no reset so the only thing in the
sensitivity list should be the clock. Otherwise in the original post,
not only are you telling it to reset the counter on the falling edge
of the clock, but on *any* transition of the other signals, one of
which is assigned in the process. The sensitivity list of a process
is *not* like the parameter list of a subroutine. It tells the tools
when the process should be run, not what data is going in and out of
it. Think of this as a trigger list for a concurrent process (because
that is what it is). Remember that all statements outside of a
process (or function) are parallel processes (including the processes
themselves). If you are familiar with programming multiple processes
this may make a bit more sense.


> I also see that my debounce, will also put a delay of 5 clock pulses
> after SIGNAL_IN stops bouncing before effecting
> a change in SIGNAL_OUT_TEMP and then one more clock pulse for the
> change to effect SIGNAL_OUT.
>
> I'm not sure what you are getting out Nathan, other than my original
> [wrong] code as shown would of never allowed MYCOUNT
> to get above 1, so SIGNAL_OUT would be forever stuck at
> SIGNAL_OUT_TEMP's initial state.
>
> Rick though, you intrigue me on improving the debounce design. I
> believe you have pointed out that my debounce functionality will not
> raise the state of SIGNAL_OUT_TEMP until after 5 CLK rising edges
> after all bounces.  What I think you are getting at is that I should
> raise the state of SIGNAL_OUT_TEMP immediately on SIGNAL_IN, but then
> not do anything to SIGNAL_OUT_TEMP until an appropriate amount
> of Clock pulses after the input stops bouncing, aka assume the state
> change, but don't bother looking again until the dust settles.

Actually, you stated it better than I did. Yes, that is exactly what
I meant. If this were being built out of hardware (in the old style
where the hardware is scarce) a double throw switch would be used with
a single FF. This circuit would make the FF change state as soon as
the leading edge of the signal arrived without delay. There is no
reason that your circuit can't do the same thing.

As to the D FF, I think the D refers to a DATA input which the output
follows when clocked. This is compared to a T FF which toggles each
time it is clocked and the T input is high. If the T input is low it
does not change state. Others are the RS (typically not clocked) with
one set input and one reset input, and the JK which has two inputs
along with a clock and can either remember the last state, go low, go
high or toggle. You will likely never see any of these monsters.

Rick

jleslie48

unread,
Jan 5, 2009, 9:12:51 PM1/5/09
to

by all means criticize away. I came here for constructive criticism
and all I've heard
so far has been great. I'm just stabbing in the dark on my code, so I
hardly expect I'm picking
the right/best way of doing things.

The reason I used 'variable' was simply because that was what I found
first in the glossary when
I was looking for a place to store an integer value and in C we call
them variables. That's the section
of the book I read. I didn't know that the more commonly used
contruct was a SIGNAL.

Now I realize that I've introduced a timing issue where my variable
'mycount' will increment at the same
time that I do the DEBOUNCE_COUNT check, and as a result I may
(depending on when things within the
clock pulse occur) not recognize that I've debounced until an
additional clock pulse, viz, mycount might actually
reach 6 before it changes SIGNAL_OUT_TEMP (but then it instantly gets
reset to 0.)

>"The synthesis could not "see" your intent and so it threw up its hands
>and cried "foul"!"

- here's my issue. I don't see what my foul was. I agree that
functionally what I wrote would never work; every
falling edge of the clock pulse would reset 'mycount' to 0. but I
don't understand why just because it was stupid
it wouldn't synthesize. I'm guessing I ended up with two plugs instead
of a plug and a socket( like when I wired up my
christmas tree), somewhere, but its
not obvious to me that my SYNTAX yields to a non-resolvable state. I
think this has to do with me not being able
to visualize the discrete logic parts.

for example in c:
x = 0;
While (x < 10) {
x++;
// do something 10 times
}//while loop 1

x = 0;
While ((x < 10) && (x>20)) {
x++;
// this will never happen; x can never be <10 and > 20 at the same
time
}//while loop 2

x = 0;
While (x < 10) {
x++;
// this will happen forever because the line below forces x to
always be 5 for the while test.
x = 5;
}//while loop 3


all thee WHILE loops are syntacticaly correct, the second one just
doesn't make any sense, and the
third will do a real nice job of sending my program into an infinite
loop, I can
compile and link the while loops and generate prefectly executable
code, it will be an executable time debugging
issue for me to recognize my errors in loops 2 and 3.

In the case that started this thread, ISE recognized that I did
something stupid, well, it recognized I did
something that was impossible to resolve even though my syntax was
fine. I don't know how it did that.

>"I'll point
> out that your sensitivity list is overly populated.
>
> P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)"

ahh, so the sensitivity list should only include elements that define
when my "rising edges" of
activity should occur, in my case CLK, and in many other cases a RESET
event.
SIGNAL_IN is an untimed event that needs to be checked WHEN the CLK
pulse rises but since by
itself it cannot be synched up, it is not necessary in the sensitivity
list. Is that it?

And continuing, by forcing values to change based on SIGNAL_IN at a
rising edge time of CLK, I have made those
logic element into a D-FF, eg, the event of mycount incrementing
occurs on the rising edge of the clock and not
just whenever Signal_in goes high.


jtw

unread,
Jan 5, 2009, 10:52:24 PM1/5/09
to
<.... snip>
>
There are library elements for some devices that support clocking on both
edges; for example, DDR I/O. Some tools may not be able to infer such
elements, while others may. Typiclly, they would be instantiated.

In general, however, most devices won't support the structure; a standard
template [if (rising_edge) then ..., or if (signal'event and signal=value)]
clues the synthesizer in so it can choose an appropriate library element.

Simulation, of course, has no such restrictions.

In principal, the synthesizer should be able to build up such a complex
structure out of basic gates, but would it be worth the trouble?


JTW


rickman

unread,
Jan 5, 2009, 10:56:51 PM1/5/09
to
On Jan 5, 9:12 pm, jleslie48 <j...@jonathanleslie.com> wrote:
> On Jan 5, 7:14 pm, rickman <gnu...@gmail.com> wrote:
>
> "as I am criticizing... opps, "giving advice",
>
> by all means criticize away. I came here for constructive criticism
> and all I've heard
> so far has been great. I'm just stabbing in the dark on my code, so I
> hardly expect I'm picking
> the right/best way of doing things.

I was just kidding. It is easy to give advice, harder to give good
advice.


> The reason I used 'variable' was simply because that was what I found
> first in the glossary when
> I was looking for a place to store an integer value and in C we call
> them variables. That's the section
> of the book I read. I didn't know that the more commonly used
> contruct was a SIGNAL.

That is understandable and there is nothing wrong with variables. You
just have to understand how they work and how they will synthesize.
The best way to learn to code in an HDL is to look at the template
code that the synthesis vendors provide. If you stick with that type
of code, you will have a synthesizable design at least.


> Now I realize that I've introduced a timing issue where my variable
> 'mycount' will increment at the same
> time that I do the DEBOUNCE_COUNT check, and as a result I may
> (depending on when things within the
> clock pulse occur) not recognize that I've debounced until an
> additional clock pulse, viz, mycount might actually
> reach 6 before it changes SIGNAL_OUT_TEMP (but then it instantly gets
> reset to 0.)

It's not so much a timing issue as what logic will be generated. The
logic will likely work, it will just be a bit more complex than
needed.


> >"The synthesis could not "see" your intent and so it threw up its hands
> >and cried "foul"!"
>
> - here's my issue. I don't see what my foul was. I agree that
> functionally what I wrote would never work; every
> falling edge of the clock pulse would reset 'mycount' to 0. but I
> don't understand why just because it was stupid
> it wouldn't synthesize.

It wouldn't synthesize because there is no hardware that will update
both on the rising edge and the falling edge. At least there is none
that I know of. If there is some circuit that will work that way, it
would be so "unique" that the synthesis vendors would not design their
programs to support it.


> In the case that started this thread, ISE recognized that I did
> something stupid, well, it recognized I did
> something that was impossible to resolve even though my syntax was
> fine. I don't know how it did that.

The synthesis recognized that it did not know how to construct logic
to implement your design. The simulator would likely have worked just
fine. But the code would have done some weird things compared to
hardware. In fact, you could say that when running the simulator, and
HDL *is* software and when running synthesis, it is *hardware*, or had
better be hardware.

Your code would run in the simulator (I think) but will update the
mycount variable on the rising edge, as well as the falling edge and
also any time either of the other two signals change.


> >"I'll point
> > out that your sensitivity list is overly populated.
>
> > P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)"
>
> ahh, so the sensitivity list should only include elements that define
> when my "rising edges" of
> activity should occur, in my case CLK, and in many other cases a RESET
> event.
> SIGNAL_IN is an untimed event that needs to be checked WHEN the CLK
> pulse rises but since by
> itself it cannot be synched up, it is not necessary in the sensitivity
> list. Is that it?

Yes, exactly. If you look at a template for a register you will see
exactly this. If it is a combinatorial process, all signals on the
right side of any assignments or in condtional part of an if or case
needs to be in the list.


> And continuing, by forcing values to change based on SIGNAL_IN at a
> rising edge time of CLK, I have made those
> logic element into a D-FF, eg, the event of mycount incrementing
> occurs on the rising edge of the clock and not
> just whenever Signal_in goes high.

That sounds right. In hardware there is combinatorial logic which is
just made up of gates. There is no clock and any time any input
changes, the output can change. Sequential logic is the term for
registers and latches (slightly different use of the clock) and
constitute memory. A register only changes the output when the clock
has the appropriate edge (some are rising edge and others falling edge
triggered). A latch uses an enable. The input passes through to the
output any time the enable is high. When the enable goes low, the
current output is remembered. Mostly latches should be avoided. They
happen by accident when combinatorial logic is does not specify the
output for all possible input combinations. In that case the
assumption is that the last output should be held which is exactly
what a latch does. This is all well described in pretty much any HDL
design book.

Rick

jleslie48

unread,
Jan 6, 2009, 7:43:45 AM1/6/09
to

Thanks again Rick and everyone for a very enlightening discussion.

I'm going to continue to see what I can make, (and break) and see if I
can
apply these ideas.

>It wouldn't synthesize because there is no hardware that will update
>both on the rising edge and the falling edge.

- I'm back to my hardware realization deficiencies. This is
definitely my Achilles Heal.
I've got a technician who knows 10x more than my EE guys on putting
together circuits;
throws together cell phone jammers out of spare parts and altoids tin
boxes, and never
went to college. He just gets it. I'm gonna have to spend more time
with him.

john.o...@gmail.com

unread,
Jan 6, 2009, 8:19:37 AM1/6/09
to
<snip>

> "as I am criticizing... opps, "giving advice",
>
> by all means criticize away.  I came here for constructive criticism
> and all I've heard
> so far has been great.  I'm just stabbing in the dark on my code, so I
> hardly expect I'm picking
> the right/best way of doing things.
>
> The reason I used 'variable' was simply because that was what I found
> first in the glossary when
> I was looking for a place to store an integer value and in C we call
> them variables.  That's the section
> of the book I read.  I didn't know that the more commonly used
> contruct was a SIGNAL.
<snip>
In a somewhat tangential note, one of my new-years resolutions is to
finally get over the hump and get to learning Verilog (after several
failed attempts at VHDL). I'm also coming from a software
background. When I had started playing with VHDL in the past, I
picked up several books and read through them, but none of them seemed
to hit the "practical" side of developing FPGA code (i.e., their focus
was the complete language, and not necessarily related to actually
building FPGA-based systems, which I'm assuming the OP is trying to
do).

Then I stumbled upon the following book:
http://www.amazon.com/FPGA-Prototyping-ByVerilog-Examples-Spartan-3/dp/0470185325/ref=sr_1_11?ie=UTF8&s=books&qid=1231247475&sr=8-11

and its brethren:

http://www.amazon.com/FPGA-Prototyping-VHDL-Examples-Spartan-3/dp/0470185317/ref=pd_bxgy_b_text_b

I have found the Verilog book truly outstanding, doing an excellent
job of starting at the beginning (assuming VERY little knowledge other
than basic digital logic), and working through the construction of
different elements of interest (UARTs, FIFOs, all the way up to the
Picoblaze soft-core processor). Very focused on practical
development, and building real-world FPGA designs. Yes, this book is
specifically targeted at the Spartan 3 FPGA (having a real chip to
tackle real examples is always reasonable, IMHO), but there is
annotation next to each section that is Xilinx/Spartan specific, so
you know what is and isn't generic.

Anyway, just figured I'd pass this along. I know everyone learns
differently, but this did the trick for me. I have no connection with
the author, but am a very pleased customer to have finally gotten over
the HDL hump.

John O.
www.jrobot.net

Brian Drummond

unread,
Jan 6, 2009, 9:54:52 AM1/6/09
to
On Mon, 5 Jan 2009 16:14:58 -0800 (PST), rickman <gnu...@gmail.com>
wrote:

...


>I am not saying this is a bad design because I am not sure.

Very good points.
Barring synthesis bugs (and XST handles variables pretty well) I would
expect it to do exactly what you want, but be pretty slow.

In one cycle, you will get the increment, the comparison, and the clear
to 0 (possibly a 2:1 mux but more likely the RESET input on a FDRE).
That's a lot of logic in series; it could be as slow as 100MHz.

>If you make mycount a
>signal, then the input to everything within the process will be the
>direct output of the register and the resulting circuit will be very
>clear.

Especially note the comparison is on a registered value, not the
incrementer output, so you get a faster (better pipelined) circuit.
If you don't need 200MHz, either approach works.

(Make sure you understand why the variable version will reset mycount
one cycle earlier; you can modify DEBOUNCE_COUNT to compensate for
that!)

>The rules of signal synthesis is that the value latched in the
>register is the last value assigned during the process. All other
>values are in essence "over written" before the clock edge is done.
>For a variable, each value assigned is in use until the next value
>assigned.

This is the most important point.
To bring out another aspect of it, which emphasises the reason
(and IMO the brilliance) behind the signal assignment rules:

variables are EXACTLY like variables in your familiar "C" environment;
they are local to the process, and between "process" and "end process"
you can pretty much write C (albeit translated into VHDL, with
procedures, functions etc, but with operator overloading, much better
type checking, real booleans, etc). Granted, if you use pointers (access
types) it'll simulate fine but won't be synthesizable, but I suspect the
same is true in these "C to hardware" languages too...

signals are the inter-process communication mechanism. As such, they
require a simple clean update-scheduling mechanism to avoid race
conditions to let you design large parallel processing systems with
minimum pain.

Or hardware.

So a process calculates the new value for a signal, then suspends
itself.
Then, once all processes are suspended, all the signal assignments take
place. This creates "events" on any signals being assigned.
Then, any processes listening for those events are activated.

>P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)
>
>You are using a clock, but no reset so the only thing in the
>sensitivity list should be the clock.

...


> The sensitivity list of a process
>is *not* like the parameter list of a subroutine. It tells the tools
>when the process should be run, not what data is going in and out of
>it. Think of this as a trigger list for a concurrent process (because
>that is what it is).

YES!

Limiting sensitivity to "Clk" (and possibly Reset) is not essential;
it's just very good practice.

- Brian

Andreas Ehliar

unread,
Jan 6, 2009, 6:06:29 AM1/6/09
to
On 2009-01-05, jleslie48 <j...@jonathanleslie.com> wrote:
> I'm sure their are different ways to do this, and I would like to
> explore them at a later date, but as I'm still novice at VHDL coding
> I'd like to know what is wrong with this particular code. Its a
> simple debounce process and the synthesize reports an error on line
> 44:

Another thing which I haven't yet seen anyone mention is synchronization
of signals that are not synchronuous with your system clock. Like for
example signals from a button.

This is a very important area which a VLSI designer really needs to
know about. To illustrate, say that you create the following design
in VHDL. x is a signal which is generated externally and which can
change at any time (lets say that it is connected to a button).

-- a, b, and x are all 1 bit wide signals
process(clk) begin
if rising_edge(clk) then
a <= x;
b <= not x;
end if;
end process;

Now, if you simulate this, you will see that a and b mirror each other.
When a is set to 1, b is set to 0 and vice versa (at least if we disregard
all the other values possible in std_logic). And everything always
happens on the rising edge of the clk signal. This should be true
regardless of when x is modified, even if it is modified one delta delay
before or after the rising clock (or even simultaneously with the clock).
The relationship between a and b will still be the same. [1]

However, if you implement this circuit things are not quite as easy.
You will implement two flip-flops and a not-gate [2]. And the delay
x to a will not be the same as x to b. Lets assume that the delay
x to b is longer than the x to a delay. In that case if x is modified
at precisely the wrong time interval (right before the rising clock edge),
it might be that the changing value can be propagated to a before
the clock edge and to b after the clock edge. So in this case it is
no longer guaranteed that a is equal to not b. We basically have a
race condition here.

The way to avoid this is by making sure that the inputs to this
state machine is always synchronuous to the clock edge. One way
to do this is to put a single flip-flop first. Like this:

-- a, b, and x are all 1 bit wide signals
process(clk) begin
if rising_edge(clk) then
x_sync <= x; -- This is the only place where x is used
-- The rest of the design _must_ use x_sync
a <= x_sync;
b <= not x_sync;
end if;
end process;

In this case, even if x is modified close to a clock edge, a and
b will not get out of phase since they both depend on x_sync which
has been synchronized with the clock signal. [3]

Unfortunately the real world is not quite so simple. There is also
something called metastability which it is impossible to avoid in
theory, but in practice it can be avoided by using more than one
synchronization flip-flop. Most usually two flip-flops, but sometimes
three. (See for example http://www.asic-world.com/tidbits/metastablity.html
for more information about this.)


These kind of problems are part of the reason why everyone recommends
that only one system clock should be used in a design if you can get
away with it. Sometimes it is not possible. If you do have a valid reason
for crossing clock domains you really need to understand what is going on.
An introduction can be found at http://www.fpga4fun.com/CrossClockDomain.html


Hope this is of some use to you.

/Andreas

[1] I am quite certain that this will be guaranteed in VHDL even if you
change the signal exactly on the same exact time delay as the clock. I am
unsure whether this is true for Verilog (but I wouldn't bet on it being
true).
[2] Well, it is not certain that you will get that if the synthesis
tool is being clever. But lets ignore that for now.
[3] Assuming the clock frequency is not so high that the routing
and logic delay between x and a,b is too high. But the timing
analysis tool should warn us if there is danger of that.

Brian Drummond

unread,
Jan 6, 2009, 10:43:47 AM1/6/09
to
On Mon, 5 Jan 2009 18:12:51 -0800 (PST), jleslie48
<j...@jonathanleslie.com> wrote:

>On Jan 5, 7:14 pm, rickman <gnu...@gmail.com> wrote:
>> On Jan 5, 5:53 pm, jleslie48 <j...@jonathanleslie.com> wrote:

>>"The synthesis could not "see" your intent and so it threw up its hands
>>and cried "foul"!"
>
>- here's my issue. I don't see what my foul was. I agree that
>functionally what I wrote would never work; every
>falling edge of the clock pulse would reset 'mycount' to 0. but I
>don't understand why just because it was stupid
>it wouldn't synthesize. I'm guessing I ended up with two plugs instead
>of a plug and a socket

That's a pretty good analogy actually.

Rickman makes the point that this code will simulate (and do something
odd) but not synthesise. You really have to treat VHDL as, not exactly
as two separate languages, but as having two separate modes of
operation. In C, you would program somewhat differently for Visual
Studio NET edition, and the Microchip PIC C compiler...

In VHDL you (a) have to generate hardware, and (b) have to test it in
simulation. In the latter case, you can use the full language to express
your tests as simply and as comprehensively as you can.

But synthesis is different. The synthesis tool has to translate what you
write into the building blocks available. It actually doesn't try
compiling arbitrary VHDL into raw silicon; it's more like a process of
recognising specific design patterns and translating them into blocks it
already has in hardware.

For example, "Single Process State Machine", "Pure Combinatorial
Process", "Single Clocked Process With Asynch Reset" and so on
(don't look these up in the Gang of Four book; try the Xilinx
"Synthesis and Simulation Design Guide:"
http://toolbox.xilinx.com/docsan/xilinx6/books/docs/sim/sim.pdf
instead!)

As synth tools advance, the number of patterns correctly translated is
increasing, so you'll see discrepancies between older books and recent
practice. Multiplication is now translated well; division is not (the
special case of division by 2^n may be recognised; but there are simpler
alternatives instead!) Floating point is not recognised ... yet, but
it's coming. And so on.

>for example in c:
>x = 0;
>While (x < 10) {
> x++;
> // do something 10 times
> }//while loop 1

This one in a VHDL process could translate successfully; however it
will generate ten identical instances of "do something"; possibly with a
very long combinatorial path through 10 strings of gates...


>>"I'll point
>> out that your sensitivity list is overly populated.
>>
>> P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)"
>
>ahh, so the sensitivity list should only include elements that define
>when my "rising edges" of
>activity should occur, in my case CLK, and in many other cases a RESET
>event.

Yes; though not every process needs to be clocked.

GATE: process (a,b)
begin
d <= a and b and c;
end process GATE;

is a perfectly legal description of a 3-input AND gate.
It won't simulate quite as desired of course, and it might synthesise,
but I would hope for a warning about the incomplete sensitivity list...

Combinatorial processes are legitimate, and synthesisable, but
error-prone (as above!) - mixing clocked and combinatorial in the same
process is definitely not recommended.

One pattern you will often see in older books, that is definitely NOT
recommended now, is "Two (or three) process state machine". It has one
clocked process which simply registers the current state, and a separate
(purely combinatorial) process which computes the next state from
current state and input signals. (And a third process for outputs)

In the real world, with deadlines looming, someone inevitably updates
the combinatorial process and forgets to update the sensitivity list.
Oops...

- Brian

Jonathan Bromley

unread,
Jan 6, 2009, 10:53:03 AM1/6/09
to
On Tue, 06 Jan 2009 15:43:47 +0000, Brian Drummond wrote:

>In VHDL you (a) have to generate hardware, and (b) have to test it in
>simulation. In the latter case, you can use the full language to express
>your tests as simply and as comprehensively as you can.
>
>But synthesis is different.

[etc, etc]

A very nice description. Thanks.
--
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...@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.

Andreas Ehliar

unread,
Jan 6, 2009, 10:45:23 AM1/6/09
to
On 2009-01-06, Andreas Ehliar <ehliar...@isy.liu.se> wrote:
> These kind of problems are part of the reason why everyone recommends
> that only one system clock should be used in a design if you can get
> away with it. Sometimes it is not possible. If you do have a valid reason
> for crossing clock domains you really need to understand what is going on.
> An introduction can be found at http://www.fpga4fun.com/CrossClockDomain.html

Before someone else corrects me, I should also point out that the
synchronization technique I mentioned in my previous posting will only work
correctly for 1-bit wide signals. If you have vectors as input or want to
send multiple bits over a clock domain you really need to read an article like
the one I mentioned above to understand what is going on.

/Andreas

jleslie48

unread,
Jan 6, 2009, 4:57:16 PM1/6/09
to

thanks again for the insight everybody. a few thoughts to continue,

1) changing line 44 getting rid of the unnecessary sensitivities:

P1: process (CLK)


resulted in a warning:
WARNING:Xst:819 - "//dhpc-1/shared/jon/MyVhdl/VhdlModule1.vhd" line
44: One or more signals are missing in the process sensitivity list.
To enable synthesis of FPGA/CPLD hardware, XST will assume that all
necessary signals are present in the sensitivity list. Please note
that the result of the synthe
sis may differ from the initial design specification. The missing
signals are:


Note that I didn't cut off the message, suspiciously there were no
signals listing after the "The missing signals are:" line.

2) the building block issues:
(a) "In VHDL you (a) have to generate hardware, and (b) have to test


it in
simulation. In the latter case, you can use the full language to
express
your tests as simply and as comprehensively as you can.

But synthesis is different. The synthesis tool has to translate what


you
write into the building blocks available. It actually doesn't try
compiling arbitrary VHDL into raw silicon; it's more like a process of
recognising specific design patterns and translating them into blocks
it
already has in hardware. "

(b)"Rickman makes the point that this code will simulate (and do


something
odd) but not synthesise. You really have to treat VHDL as, not exactly
as two separate languages, but as having two separate modes of
operation."

(c)"Now, if you simulate this, you will see that a and b mirror each


other.
When a is set to 1, b is set to 0 and vice versa (at least if we
disregard
all the other values possible in std_logic). And everything always
happens on the rising edge of the clk signal. This should be true
regardless of when x is modified, even if it is modified one delta
delay
before or after the rising clock (or even simultaneously with the
clock).
The relationship between a and b will still be the same. [1]

However, if you implement this circuit things are not quite as easy.
You will implement two flip-flops and a not-gate [2]. And the delay
x to a will not be the same as x to b. Lets assume that the delay
x to b is longer than the x to a delay. In that case if x is modified
at precisely the wrong time interval (right before the rising clock
edge),
it might be that the changing value can be propagated to a before
the clock edge and to b after the clock edge. So in this case it is
no longer guaranteed that a is equal to not b. We basically have a
race condition here. "


From what was quoted in (a,b,c) above, it seems to me that simulation
doesn't
really do a very good job of simulating what is actually going to
happen then.
(c) actually this one sort of makes sense, as there is no control on
when x can change,

Jonathan Bromley

unread,
Jan 6, 2009, 5:18:57 PM1/6/09
to
On Tue, 6 Jan 2009 13:57:16 -0800 (PST), jleslie48 wrote:

[...]


>From what was quoted in (a,b,c) above, it seems to me
> that simulation doesn't really do a very good job of
> simulating what is actually going to happen then.

I think this misses the point. VHDL and Verilog are
designed and defined as simulation languages, and
simulation does an excellent job of showing you what
the code says should happen. The culprit here is
synthesis. Synthesis is honour-bound to do one of
two things: either build logic that matches (at the
clock cycle level) the simulation behaviour, or
throw an error. Unfortunately, for various historical
(hysterical?) reasons, synthesis sometimes chooses to
ignore certain language constructs that it can't
faithfully reproduce in logic, giving only a warning
message at best. This is the all-too-familiar problem
of synthesis/simulation mismatch. The usual culprits
are:

- wrong sensitivity list (synthesis assumes a complete
sensitivity list on non-clocked processes)
- time delays in your simulation code (synthesis
simply ignores all time delays)
- pragmas or directives in the code that are
meaningful to synthesis but, being embedded in
comments or user-defined attributes, are ignored
by simulation - state machine encoding attributes,
and the dreaded Verilog full_case/parallel_case

and a few other, less common things.

In fairness, engineers who take the trouble to read and
correctly interpret synthesis warnings will rarely get
bitten by such mismatches. But it's a little tiresome
that you can flog your way through extensive simulation
and only at synthesis time finally discover that you
have written some code that doesn't map sensibly to
hardware. That's why many engineers (me included) will
typically do trial synthesis runs very early in the life
of a project, long before functional behaviour is fully
debugged.

jleslie48

unread,
Jan 6, 2009, 6:24:31 PM1/6/09
to
">for example in c:
>x = 0;
>While (x < 10) {
> x++;
> // do something 10 times
> }//while loop 1

>This one in a VHDL process could translate successfully; however it
>will generate ten identical instances of "do something"; possibly with a
>very long combinatorial path through 10 strings of gates... "


this doesn't make sense to me. ~will generate ten identical instances
of "do something"~
it can't be that raw. what if that loop was (x< 10000000)? it can't
simply make yyy copies
of the same line by brute force. YOu'd fill your memory in 2 seconds.
and what if the initial
value of x was not a "synthesize" fixed value? what if :

-- read x from a UART

-- for x number of times
-- do something.

then there would be no way to make the right number of instances at
synth time.

Brian Drummond

unread,
Jan 6, 2009, 7:48:13 PM1/6/09
to
On Tue, 6 Jan 2009 13:57:16 -0800 (PST), jleslie48
<j...@jonathanleslie.com> wrote:

>
>thanks again for the insight everybody. a few thoughts to continue,
>
>1) changing line 44 getting rid of the unnecessary sensitivities:
>
> P1: process (CLK)
>
>
>resulted in a warning:
>WARNING:Xst:819 - "//dhpc-1/shared/jon/MyVhdl/VhdlModule1.vhd" line
>44: One or more signals are missing in the process sensitivity list.

Assuming the modified process still looks like...

> > P1: process (CLK, SIGNAL_IN, SIGNAL_OUT_TEMP)

> > variable mycount : integer := 0;
> > begin

> > if (CLK = '1' and CLK'event ) then --{1
...
> > end if; --1}


> > SIGNAL_OUT <= SIGNAL_OUT_TEMP;
> > end process P1;

... notice the assignment outside the "if CLK..." statement?

You have 2 options:
(a) restore SIGNAL_OUT_TEMP to the sensitivity list;
(b) move the assignment where it belongs, outside the process.
Then it is a separate parallel process sensitive only to SIGNAL_OUT_TEMP
(but a trivial one).

- Brian

Brian Drummond

unread,
Jan 6, 2009, 8:21:48 PM1/6/09
to
On Tue, 6 Jan 2009 15:24:31 -0800 (PST), jleslie48
<j...@jonathanleslie.com> wrote:

>">for example in c:
>>x = 0;
>>While (x < 10) {
>> x++;
>> // do something 10 times
>> }//while loop 1
>
>>This one in a VHDL process could translate successfully; however it
>>will generate ten identical instances of "do something"; possibly with a
>>very long combinatorial path through 10 strings of gates... "

>this doesn't make sense to me. ~will generate ten identical instances
>of "do something"~
>it can't be that raw. what if that loop was (x< 10000000)? it can't
>simply make yyy copies
>of the same line by brute force. YOu'd fill your memory in 2 seconds.

Ohhhh yes it can! you'd fill your FPGA, sure.
But I said it would work; not that it was always a good idea!

Now if you wanted to generate a single instance of "do_something" which
took 10 clock cycles, you would use a different pattern; possibly with a
"wait for rising_edge(clk)" inside the while loop. Or in the process
style you have seen so far, maintain a separate counter to know when
you're done.

One thing we don't have, yet, is any semi-automatic way to combine both;
unroll your loop to 1000 parallel instances, and count 10000 cycles.
That level of detail you have to handle yourself. Not just the
compromise; how fast do you need it, and how big is your FPGA? but the
execution details.

>and what if the initial
>value of x was not a "synthesize" fixed value? what if :
>
>-- read x from a UART
>
>-- for x number of times
> -- do something.
>
>then there would be no way to make the right number of instances at
>synth time.

This is a good question. The short answer is that x has to be locally
static, since you can't (yet!) grow more hardware at runtime.

So transform the problem into something achievable.

The usual pattern is to agree an upper bound on x, and implement that
upper bound in hardware, executing do_something conditional on the
actual value.

constant x_max:integer := 15;

for i in 1 to x_max loop
if i < x then
... No, it's better, safer and tidier to use the type system properly:

subtype x_type is integer range 0 to 15;
signal x : x_type;

-- this is inside a process of course!
for i in x_type loop
if i < x then
do_something;
end if;
end loop;

If do_something is synthesisable, so is this.

- Brian

jleslie48

unread,
Jan 7, 2009, 12:02:47 PM1/7/09
to
On Jan 6, 7:48 pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:

> ... notice the assignment outside the "if CLK..." statement?
>
> You have 2 options:
> (a) restore SIGNAL_OUT_TEMP to the sensitivity list;
> (b) move the assignment where it belongs, outside the process.
> Then it is a separate parallel process sensitive only to SIGNAL_OUT_TEMP
> (but a trivial one).
>
> - Brian

Brian,

Confirmed and thank you. That makes perfect sense. This is the
fix I tried:

----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 08:06:38 12/31/2008
-- Design Name:
-- Module Name: VhdlModule1 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;

use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity VhdlModule1 is


port( CLK : in std_logic;
SIGNAL_IN : in std_logic;
SIGNAL_OUT : out std_logic);
end VhdlModule1;


architecture Behavioral of VhdlModule1 is

constant DEBOUNCE_COUNT : integer := 5;
signal SIGNAL_OUT_TEMP : std_logic := '0';

begin

P1: process (CLK) --, SIGNAL_IN, SIGNAL_OUT_TEMP)


variable mycount : integer := 0;
begin
if (CLK = '1' and CLK'event ) then --{1

if (SIGNAL_OUT_TEMP /= SIGNAL_IN) then --{2

mycount := mycount + 1;

if (mycount >= DEBOUNCE_COUNT) then --{3


SIGNAL_OUT_TEMP <= SIGNAL_IN;
mycount := 0;

end if; --3}
else
mycount := 0;
end if; --2}

end if; --1}

end process P1;

SIGNAL_OUT <= SIGNAL_OUT_TEMP; --line 62

end Behavioral;
----------------------------------------------------------------------------------

Note line 62 is the old line 56 but now has moved outside the domain
of the process p1. So now that line is a bit of concurrent logic, and
while
concurrent logic is generally to be avoided, in this case as it is a
simple
output assignment its clocking is not required to be exact.

The error message makes sense now; SIGNAL_OUT was "sensitive" to the
value SIGNAL_OUT_TEMP, but I never declared it formally in the
sensitivity
list.


jleslie48

unread,
Jan 7, 2009, 12:36:05 PM1/7/09
to
On Jan 6, 8:21 pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:
end if; --1}


>
> - Brian

You still have me scratching my head on this. Lets look at my example:


if (mycount >= DEBOUNCE_COUNT) then --{3


SIGNAL_OUT_TEMP <= SIGNAL_IN;
mycount := 0;

end if; --3}

in this code, DEBOUNCE_COUNT is a constant 5, so are you saying
that the lines:


SIGNAL_OUT_TEMP <= SIGNAL_IN;
mycount := 0;

are repeated 5 times?

or this is fundamentally different than a while loop by the nature of
using IF instead of WHILE?

In other words, if I re-write my repeat 10 loop as such:

looper10_proc: process (CLK,RESET)
variable icount : integer := 0;
begin
if (reset = SWITCH_ON) then
icount := 0;
elsif (CLK = '1' and CLK'event ) then --{1
if (icount <= 10 ) then --{2
icount := icount +1;
-- do that same something
end if; --2}

end if; --1}

end process looper_10_proc;

I think I'm back to keeping the hardware in mind at all times....

Andy

unread,
Jan 7, 2009, 2:11:59 PM1/7/09
to
On Jan 5, 6:14 pm, rickman <gnu...@gmail.com> wrote:
> If you make mycount a
> signal, then the input to everything within the process will be the
> direct output of the register and the resulting circuit will be very
> clear.  

While the structure of the circuit may be more clear, the behavior is
not. Take for example:

This snippet, using a signal for mycount:


mycount <= mycount + 1;
if (mycount >= DEBOUNCE_COUNT) then

...
end if;

is equivalent to this one (also using a signal for mycount):


if (mycount >= DEBOUNCE_COUNT) then

...
end if;


mycount <= mycount + 1;

With variables, these two descriptions, which "read" differently,
would implement different behavior, and correspondingly different
circuitry. The latter example would result in the registered (clock-
cycle-delayed) version of mycount being compared to debounce_count.
Using variables in clocked processes allows you to choose where to put
registers and where to chain combinatorial paths together, without
having to use separate processes, or re-state complex expressions.

With signals, since updates are always postponed, all references are
the same relative to last update. We unkowingly simplify that to say
that a signal assigned in a clocked process is always a register*.
With variables, it is not the variable that implies a register or not,
it is each reference to it that determines whether a register is used,
and only for that reference. In other words, you can easily have
multiple references to the same variable, some of which imply a
register, others do not. Of course multiple registers implied from
multiple references to the same variable are combined into one
register.

The basic rule is that if the variable referenced was last updated in
a prior clock cycle, then a register must be used to "remember" the
value for that specific reference. Otherwise, the combinatorial value
is implied for that reference.

* The OP's final signal assignment outside the clocked if-statement is
not synthesizeable (at least not correctly) because it it is from
another signal (signal_out_temp). If however, signal_out_temp were a
variable, then it would be synthesizeable, at least by some tools.
Signals assigned from expressions of variable(s), after and outside
the clocked if-statement, result in registered references to the
variable(s) being combinatorially assigned to the output signal. If
there were operators or function calls in the expression, those would
be implemented combinatorially after the registered variable values.

For example:
if rising_edge(clk) then
a := ina;
b := inb;
c <= a + b;
end if;

'c' is a register output with the sum of ina and inb on its input.

but in this example:
if rising_edge(clk) then
a := ina;
b := inb;
end if;
c <= a + b;

C is the output of the adder driven by registers with ina and inb on
their inputs.


I also noticed the OP's comments delineating the nested levels of if
statements. It should also be noted that if-statements can be labeled,
and if they are, the corresponding end if must include the label:

clock: if rising_edge(clk) then
...
end if clock;

The advantage of this over comments is that labels are checked and
enforced by the compiler; comments are not.

Andy

rickman

unread,
Jan 7, 2009, 4:39:34 PM1/7/09
to
On Jan 7, 2:11 pm, Andy <jonesa...@comcast.net> wrote:
> On Jan 5, 6:14 pm, rickman <gnu...@gmail.com> wrote:
>
> > If you make mycount a
> > signal, then the input to everything within the process will be the
> > direct output of the register and the resulting circuit will be very
> > clear.  
>
> While the structure of the circuit may be more clear, the behavior is
> not. Take for example:
>
> This snippet, using a signal for mycount:
>   mycount <= mycount + 1;
>   if (mycount >= DEBOUNCE_COUNT) then
>   ...
>   end if;
>
> is equivalent to this one (also using a signal for mycount):
>   if (mycount >= DEBOUNCE_COUNT) then
>   ...
>   end if;
>   mycount <= mycount + 1;

I don't follow your assertion. You get the same behavior from two
descriptions using signals and get two different behaviors using
variables. Isn't one behavior more clear than two behaviors? There
are lots of ways that different code can result in the same behavior.
That does not make any of these code examples more complex to
understand. You stated some rules for determining what value is used
for variables and when registers are synthesized. These rules are
much more complex than the rules for signals. That was my point.

The OP is a beginner and I recommend that any beginner stick with
signals until they have mastered those rules. Then they can add in
the confusion factor of variables. I especially recommend this for
software people learning an HDL. Signals are new to them and they
will do better to learn up front the parts of HDL that are different
from software. Signals are required, variables are not. Start with
the minimum that you need to learn, then branch out.

Rick

rickman

unread,
Jan 7, 2009, 4:52:48 PM1/7/09
to

This violates Rick's first rule of writing HDL code; "Write a
description of the hardware, not a program."

When you say you want to do something 10 times, what do you mean? Are
you saying you want to use the same piece of hardware 10 times in
succession to do the same thing? For example, pulse an output 10
times. That can't be done in a simple loop. You have to construct a
counter to count the iterations, you likely also have to have a
counter divide down the clock to measure the length of a pulse. So
you "describe" the counters rather than expecting the tool to know
that a loop is supposed to count the usage of a piece of hardware.

Seriously, when you want to design hardware, always start with a block
diagram showing the various registered signals. The logic can be
shown as other blocks like muxes or adders or just clouds. They can
be easily synthesized. But you need to specify where the registers
will be and that controls the structure of your design and code.

Loops are good for describing things that get done the same way, but
on different signals. An example is a bit shifter. You can say

A(n downto 1) <= A(n-1 downto 0);

This is simple and clear. But I have seen people write,

for i in n-1 downto 0 loop
A(i+1) <= A(i);
end loop;

This is not unclear and I am sure there are times when it is
preferred, especially when the range of i varies. I may be reaching
beyond my experience as I don't know that a non-constant range for i
can be synthesized.

I tend to stick with simple constructs because they are most portable
and simple to understand. If I have a need for a more complex
construct, I am not afraid of it, but I have found little need.

Rick

rickman

unread,
Jan 7, 2009, 5:06:20 PM1/7/09
to
On Jan 7, 12:36 pm, jleslie48 <j...@jonathanleslie.com> wrote:
>
> You still have me scratching my head on this. Lets look at my example:
>
>  if (mycount >= DEBOUNCE_COUNT) then  --{3
>      SIGNAL_OUT_TEMP <= SIGNAL_IN;
>      mycount := 0;
>      end if; --3}
>
> in this code, DEBOUNCE_COUNT is a constant 5, so are you saying
> that the lines:
>      SIGNAL_OUT_TEMP <= SIGNAL_IN;
>      mycount := 0;
>
> are repeated 5 times?
>
> or this is fundamentally different than a while loop by the nature of
> using IF instead of WHILE?

The IF is not a while. The loop of a process is repeated on the same
hardware (process) on each clock tick. Each time the process is run
an explicit loop repeats N times. Very different.


> In other words, if I re-write my repeat 10 loop as such:
>
> looper10_proc: process (CLK,RESET)
> variable icount : integer := 0;
> begin
>    if (reset = SWITCH_ON) then
>          icount := 0;
>     elsif (CLK = '1' and CLK'event ) then --{1
>         if (icount <= 10 ) then --{2
>                     icount := icount +1;
>                     -- do that same something
>        end if; --2}
>
>     end if; --1}
>
> end process looper_10_proc;
>
> I think I'm back to keeping the hardware in mind at all times....

Good boy!!!

Remember that each process (that includes each line of concurrent
code) is a description of a piece of hardware that runs when an input
changes (implied in concurrent code or explicit in a process). Every
line of code that is executed within a process is defining what the
hardware will do on that one trigger event. If you want a process to
do 10 things on 10 different clock cycles, you need to give it a way
to know which clock cycle it is on (a counter perhaps) and then
describe those different behaviors. That is what you have done in the
above code. You use icount to tell what clock cycle you are on and
you use the IF statement to tell the process what to do on the
different clock cycles. If you want to do something multiple times on
separate hardware (parallel operations) you can use an explicit loop
to define that. Variables can be used in this case but will often
result in multiple copies of hardware.

HDL is complex and simple at the same time. I recommend that you
think in terms of the hardware and then describe the hardware in the
HDL because that tends to take away the complex parts of the HDL and
you can use cookie cutters to create your code. I've been doing this
for over 15 years and I am still using the cookie cutter method.
Others have been doing this for less time, but spend a higher
percentage of their time on HDL and so have learned more complex
methods that reduce their effort. But they didn't learn those methods
the first day on the job.

Rick

jleslie48

unread,
Jan 8, 2009, 10:32:11 AM1/8/09
to
On Jan 7, 2:11 pm, Andy <jonesa...@comcast.net> wrote:

>
> I also noticed the OP's comments delineating the nested levels of if
> statements. It should also be noted that if-statements can be labeled,
> and if they are, the corresponding end if must include the label:
>
> clock: if rising_edge(clk) then
> ...
> end if clock;
>
> The advantage of this over comments is that labels are checked and
> enforced by the compiler; comments are not.
>
> Andy

Wow! about time a language allowed labels on ifs. I've been doing
it
for years with comments I don't even realize I'm doing it.

>
> * The OP's final signal assignment outside the clocked if-statement is
> not synthesizeable (at least not correctly) because it it is from
> another signal (signal_out_temp). If however, signal_out_temp were a
> variable, then it would be synthesizeable, at least by some tools.
> Signals assigned from expressions of variable(s), after and outside
> the clocked if-statement, result in registered references to the
> variable(s) being combinatorially assigned to the output signal. If
> there were operators or function calls in the expression, those would
> be implemented combinatorially after the registered variable values.

Well the synth only complained when I took SIGNAL_OUT_TEMP, SIGNAL_IN
out of the sensitivity list, can you elaborate a little more on what
you feel is
not synthesizeable with the original code?


jleslie48

unread,
Jan 8, 2009, 11:20:15 AM1/8/09
to

Yay!!! I got something right.

Your very polite in calling it "cut and paste." I've always called in
"Plagiarize
it you can" and have been doing so for 25 years :)))

I see what your saying, and its gonna be a learning curve to get used
to watching
the hardware all the time as I program. Having done a bit of work on
compiler design
that while thing still bugs me though. To a compiler an IF and a
WHILE are just
variations of the same thing. The if becomes in assembly language:

<conditional jump> to else_part
-- then code goes here
<unconditional jump> to endif_xyz
label else_part:
--else code goes here
label endif_xyz:

and the while would be:

label topofwhile_xyz:
<conditional jump> to end_of_while_xyz
---stuff to do
<unconditional jump> to topofwhile_xyz
label end_of_while_xyz:

I was expecting the synth do work similarly.

bish

unread,
Jan 8, 2009, 11:47:58 AM1/8/09
to
On Jan 6, 8:43 pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:
AND gate must respond to change to 'c' in the above description for it
to be a truly 3-input AND gate.
But 'c' not being in the sensitivity list, d is supposed to have the
same value until 'a' or 'b' changes regardless of any change in 'c'.
So if we follow the rules of sensitivity list, how can we say the
above code to be a legal description of a 3-input AND gate?

Now let's assume synthesis tool tries to exactly describe user's
intent in above code (intentional exclusion of c from sensitivity
list). I don't see this being possible without having some sort of
memory (flip-flop or latch) for c. But the process will not be
combinatorial then. So to keep this as a combinatorial logic,
synthesis tool must make an AND gate (this is what I think, I may me
wrong, I don't know!!!). And I believe AND here is just an example,
any combinatorial however complex might be synthesized in a similar
way, i.e. synthesized hardware not having any difference in its
working in either cases of including or excluding 'c' (or alike
inputs of other combinatorial block). So why should synthesis tool
generate warning messages for not including all the inputs of
combinatorial block in sensitivity list? ('c' in this case; It has to
get 3-input AND here).
Only one point I see for having this warning message useful is when,
say designer by mistake typed 'c' in the expression
d <= a and b and c; and he actually did not want to have 'c' as an
input the combinatorial process containing this assignment!!

Andy

unread,
Jan 8, 2009, 1:10:05 PM1/8/09
to
On Jan 8, 9:32 am, jleslie48 <j...@jonathanleslie.com> wrote:
> Well the synth only complained when I took SIGNAL_OUT_TEMP, SIGNAL_IN
> out of the sensitivity list, can you elaborate a little more on what
> you feel is
> not synthesizeable with the original code?

Well, it's kind of tricky to explain, but here goes.

Take this example:
process (clk) is
begin
if rising_edge(clk) then
count_temp <= count_temp + 1;
end if;
count_out <= count_temp;
end process;

On the rising edge of the clock, clock_out will have the un-
incremented value (because there is no process suspension between the
increment assignment and the subsequent reference of count_temp).

However, on the falling edge of the clock, the whole clocked if clause
does not execute, but the assignment to clock_out still does. Since
the process has suspended since count_temp was incremented, count_out
will be assigned with the incremented value. That requires the output
to change on the falling edge. I suppose it could be synthesized that
way, but I seriously doubt any tool is smart enough to realize it and
do it correctly.

Some synthesis tools are able to synthesize processes that operate on
both edges of a clock, but they cannot do it for the same signal on
both edges (that would be a Double Data Rate flop, which most target
platforms do not support, except some in the IO.

Now, if count_temp were a variable, then some synthesis tools figure
out that count_out updates on the rising edge of the clock, and
synthesize it accordingly.

This brings us to a somewhat popular means of implementing double data
rate (DDR) behavior using single data rate (normal) registers:

process (clk) is
variable qr, qf : std_logic;
begin
if rising_edge(clk) then
qr := d xor qf; -- registered qf ref
elsif falling_edge(clk) then
qf := d xor qr; -- registered qr ref
end if;
q <= qf xor qr; -- combinatorial xor of reg'd qr/qf
end process;

The above behaves (WRT q and d) exactly like this one:

process (clk) is
begin
if rising_edge(clk) or falling_edge(clk) then
q <= d;
end if;
end process;

The former is synthesizable (by some tools), but the latter is not
(perhaps it should be, and implemented in the form of the former).

The former description takes advantage of the nature of both variables
and signals in one clocked process to do what normally would require
three separate processes (one RE, one FE, and one combinatorial).

Hope this helps,

Andy

Brian Drummond

unread,
Jan 8, 2009, 2:22:20 PM1/8/09
to
On Thu, 8 Jan 2009 08:47:58 -0800 (PST), bish <bish...@gmail.com>
wrote:

>> Yes; though not every process needs to be clocked.
>>
>> GATE: process (a,b)
>> begin
>>   d <= a and b and c;
>> end process GATE;
>>
>> is a perfectly legal description of a 3-input AND gate.
>> It won't simulate quite as desired of course, and it might synthesise,
>> but I would hope for a warning about the incomplete sensitivity list...
>>
>AND gate must respond to change to 'c' in the above description for it
>to be a truly 3-input AND gate.
>But 'c' not being in the sensitivity list, d is supposed to have the
>same value until 'a' or 'b' changes regardless of any change in 'c'.
>So if we follow the rules of sensitivity list, how can we say the
>above code to be a legal description of a 3-input AND gate?

Legal is not necessarily the same as correct!
(Anyone who has used C will be aware of this...)

>Now let's assume synthesis tool tries to exactly describe user's
>intent in above code (intentional exclusion of c from sensitivity
>list). I don't see this being possible without having some sort of
>memory (flip-flop or latch) for c.

THAT's the point: the synthesis tool won't even try the exact
description. It'll recognise the combinatorial pattern, implement it,
and warn about the sensitivity list, as jleslie noticed.

>So to keep this as a combinatorial logic,
>synthesis tool must make an AND gate (this is what I think, I may me
>wrong, I don't know!!!).

True for all the synth tools I have used.

>And I believe AND here is just an example,
>any combinatorial however complex might be synthesized in a similar
>way,

Absolutely.

> So why should synthesis tool
>generate warning messages for not including all the inputs of
>combinatorial block in sensitivity list?

>Only one point I see for having this warning message useful is when,
>say designer by mistake typed 'c' in the expression
>d <= a and b and c; and he actually did not want to have 'c' as an
>input the combinatorial process containing this assignment!!

That's one reason; a more likely scenario is that he added 'c' later,
and omitted to correct the sensitivity list...

Either way, the warning is *essential* to alert the designer to the fact
that the implementation cannot meet the specification (description) and
is therefore not what he tested in simulation.

That is a serious problem, if ignored.

- Brian

Brian Drummond

unread,
Jan 8, 2009, 2:40:50 PM1/8/09
to
On Thu, 8 Jan 2009 07:32:11 -0800 (PST), jleslie48
<j...@jonathanleslie.com> wrote:

>On Jan 7, 2:11 pm, Andy <jonesa...@comcast.net> wrote:

>> clock: if rising_edge(clk) then
>> ...
>> end if clock;
>>
>> The advantage of this over comments is that labels are checked and
>> enforced by the compiler; comments are not.
>>
>> Andy
>
>Wow! about time a language allowed labels on ifs. I've been doing
>it
>for years with comments I don't even realize I'm doing it.

Then I think you'll find a lot more "about time"s in VHDL, where it
allows the compiler to statically check lots of things (or better, allow
algorithms to be expressed in intrinsically safe manner) for clearer and
more reliable code.

And thanks to Andy for pointing this example out; it's one I don't use
enough myself.

>> * The OP's final signal assignment outside the clocked if-statement is
>> not synthesizeable (at least not correctly) because it it is from
>> another signal (signal_out_temp). If however, signal_out_temp were a
>> variable, then it would be synthesizeable, at least by some tools.

>Well the synth only complained when I took SIGNAL_OUT_TEMP, SIGNAL_IN


>out of the sensitivity list, can you elaborate a little more on what
>you feel is not synthesizeable with the original code?

Again it's synthesisable; just not correctly, i.e. not in a way that
matches simulation.

SIGNAL_OUT_TEMP is assigned after the clocked process.
It is not copied to SIGNAL_OUT until the clocked process wakes up again
... with only CLK in the sensitivity list, that is half a cycle later.
The synthesis tool will implement something, but probably not that...

Restoring SIGNAL_OUT_TEMP to the sensitivity list wakes the process up
immediately (i.e. in the next delta cycle). Now, a really good synthesis
tool should correctly implement the final signal assignment. But it's
enough of a deviation from the normal pattern that it may not be
recognised by all synth tools. So why take the risk?

- Brian


Brian Drummond

unread,
Jan 8, 2009, 2:52:42 PM1/8/09
to
On Wed, 7 Jan 2009 09:36:05 -0800 (PST), jleslie48
<j...@jonathanleslie.com> wrote:

>On Jan 6, 8:21 pm, Brian Drummond <brian_drumm...@btconnect.com>
>wrote:

>> -- this is inside a process of course!


>> for i in x_type loop
>> if i < x then
>> do_something;
>> end if;
>> end loop;
>>

end if; --1}

>You still have me scratching my head on this. Lets look at my example:
>
>
> if (mycount >= DEBOUNCE_COUNT) then --{3
> SIGNAL_OUT_TEMP <= SIGNAL_IN;
> mycount := 0;
> end if; --3}
>
>in this code, DEBOUNCE_COUNT is a constant 5, so are you saying
>that the lines:
> SIGNAL_OUT_TEMP <= SIGNAL_IN;
> mycount := 0;
>
>are repeated 5 times?

Absolutely not...

>or this is fundamentally different than a while loop by the nature of
>using IF instead of WHILE?

Yes. Because semantically, IF and WHILE are very different.
(even if, in some languages, they may look similar). In VHDL you cannot
even write a while loop without using the word "loop" somewhere, which
may help to make the distinction clear.

>In other words, if I re-write my repeat 10 loop as such:
>
>looper10_proc: process (CLK,RESET)
>variable icount : integer := 0;
>begin
> if (reset = SWITCH_ON) then
> icount := 0;
> elsif (CLK = '1' and CLK'event ) then --{1
> if (icount <= 10 ) then --{2
> icount := icount +1;
> -- do that same something
> end if; --2}
>
> end if; --1}
>
>end process looper_10_proc;

As Rick says, good!
That is a good example of a pattern to iterate ten times with one
"do_something".

- Brian

jleslie48

unread,
Jan 8, 2009, 3:31:26 PM1/8/09
to
On Jan 8, 2:52 pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:

>


> >In other words, if I re-write my repeat 10 loop as such:
>
> >looper10_proc: process (CLK,RESET)
> >variable icount : integer := 0;
> >begin
> > if (reset = SWITCH_ON) then
> > icount := 0;
> > elsif (CLK = '1' and CLK'event ) then --{1
> > if (icount <= 10 ) then --{2
> > icount := icount +1;
> > -- do that same something
> > end if; --2}
>
> > end if; --1}
>
> >end process looper_10_proc;
>
> As Rick says, good!
> That is a good example of a pattern to iterate ten times with one
> "do_something".
>
> - Brian

My turing machine, language processing, LL(1) grammar, and compiler
design Professors are turning over in their graves,
but it seems to be a consensus that this is the way it works.

Brian Drummond

unread,
Jan 10, 2009, 10:44:45 AM1/10/09
to

Why are they unhappy?

This is not so very different from the implementation of a round robin
scheduler (e.g. providing a "do_something" service to 10 processes) in a
software system, when you don't impose the straitjacket of a single
process on the design.

Sure, there are cleaner ways of hiding the details under an abstraction;
wrap the process in a component and you can do the same here. But
someone still has to implement those details.

You could ask if there is a better pattern to implement this.
There nearly is...

I previously suggested the possible use of "wait for rising_edge(clk)"
inside the while loop. Just for fun I got around to trying this last
night.

-- (A,B are 10-element 1D arrays of unsigned)
Scale_Vec: process
begin
wait for rising_edge(clk);
for i in A'range loop
-- wait for rising_edge(clk);
B(i) <= A(i) * Scale;
end loop;
end process;

in Xilinx XST 10.1.3 synthesises, as expected, to use 10 multipliers.

But with the Wait moved inside the loop (as commented out) it should use
one, and service each vector entry in turn.

I don't see anything fundamentally impossible to synthesise; however XST
doesn't support this construct.


Next time I turn a Windows machine on I'll try it in Altera's free
edition.

I think the problem with synthesis is that HW engineers don't complain
enough about poor syntesis support for useful

Brian Drummond

unread,
Jan 10, 2009, 10:48:52 AM1/10/09
to

Why are they unhappy?

This is not so very different from the implementation of a round robin
scheduler (e.g. providing a "do_something" service to 10 processes) in a
software system, when you don't impose the straitjacket of a single
process on the design.

Sure, there are cleaner ways of hiding the details under an abstraction;
wrap the process in a component and you can do the same here. But
someone still has to implement those details.

You could ask if there is a better pattern to implement this.
There nearly is...

I previously suggested the possible use of "wait for rising_edge(clk)"
inside the while loop. Just for fun I got around to trying this last
night.

-- (A,B are 10-element 1D arrays of unsigned)
Scale_Vec: process
begin
wait for rising_edge(clk);
for i in A'range loop
-- wait for rising_edge(clk);
B(i) <= A(i) * Scale;
end loop;
end process;

in Xilinx XST 10.1.3 synthesises, as expected, to use 10 multipliers.

But with the Wait moved inside the loop (as commented out) it should use

one, and service each vector entry in turn. (Note: the above is
incomplete; you would need some externally visible synchronisation
mechanism to know when the n-cycle loop had finished!)

I don't see anything fundamentally impossible to synthesise; however XST
doesn't support this construct.


Next time I turn a Windows machine on I'll try it in Altera's free
edition.

I think the problem with synthesis is not so much the low level of the
language; but the low level at which it is normally used. Result: HW
engineers don't complain enough about poor synthesis support for useful
higher level constructs. So synthesis is only getting better slowly.

- Brian

rickman

unread,
Jan 10, 2009, 8:54:29 PM1/10/09
to

If what we describe is not what you expected, what hardware *do* you
expect from the above code?

I may have understood what you are confused about some 10 or 15 years
ago. But I have been using this stuff for so long that the ways it
works is second nature to me. Help me understand what you are
confused about.

Rick

Alex Colvin

unread,
Jan 10, 2009, 9:10:49 PM1/10/09
to
Something that surprised me as a beginner is that much HDL compilation is
done by template matching, rather than from e.g., denotational semantics.
This results in syntactically correct programs which are semantically
equivalent with different synthesis behavior.

A good reference is IEEE 1076.6, which describes standard templates.
Rising-edge clocks, for example, allows
a) RISING_EDGE(clk_signal_name)
b) clk_signal_name = '1' and clk_signal_name'EVENT
c) clk_signal_name'EVENT and clk_signal_name = '1'
d) clk_signal_name = '1' and not clk_signal_name'STABLE
e) not clk_signal_name'STABLE and clk_signal_name = '1'

which can appear in various IF or WAIT templates.

Note also that these are intended to be commonly supported templates. Your
synthesizer may differ.


--
mac the naïf

rickman

unread,
Jan 12, 2009, 8:55:41 PM1/12/09
to


I had a very bad experience when I started working with an HDL. The
synthesizer I used was a branded product that came with a schematic
program we wanted to use. Their tool was total crap and the result
was that I had to switch to another tool in mid project. Between the
two I found that the easiest way to get a decent result was to program
to please the tools rather than expecting the tools to be what you
want. So that is what I do to this day. I am sure that at this point
a lot of the concessions I make are not useful anymore as the tools
have improved over the last 10 or more years. But my methods still
work just fine and *always* give good results tending toward very
good. The problem with template matching for some users is that they
don't have hardware experience to know what hardware to use and so
don't know what templates to use. I am sure that some day this won't
be a problem at all and HDLs will be written just like any other
program. But that day is still a long way off I think.

Rick

jleslie48

unread,
Jan 13, 2009, 5:18:16 PM1/13/09
to
On Jan 10, 8:54 pm, rickman <gnu...@gmail.com> wrote:

>
> > My turing machine, language processing, LL(1) grammar, and compiler
> > design Professors are turning over in their graves,
> > but it seems to be a consensus that this is the way it works.
>
> If what we describe is not what you expected, what hardware *do* you
> expect from the above code?
>
> I may have understood what you are confused about some 10 or 15 years
> ago. But I have been using this stuff for so long that the ways it
> works is second nature to me. Help me understand what you are
> confused about.
>
> Rick

Rick and Brian,

sorry gentlemen, I had an unscheduled funeral to attend that
interrupted this engaging conversation.

what my turing machine and language processing professors, and my work
with compilers dictates to me is this:

I don't see why the IF statement translates any different than the
while/for loop. both should
translate to static sizes independent of the number of interations
that are completed:

an IF translates to:

<conditional jump> to else_part
-- then code goes here
<unconditional jump> to endif_xyz
label else_part:
--else code goes here
label endif_xyz:

and the WHILE would be:

label topofwhile_xyz:
<conditional jump> to end_of_while_xyz
---stuff to do
<unconditional jump> to topofwhile_xyz
label end_of_while_xyz:

I was expecting the synth do work similarly.

The data value of the number of iterations is swallowed up by the
<conditional jump> and thus the sizing of the "circuit" is
independent of the number of interations. Bascially the synth forced
me to manually build a for 1 to 10 loop, whereas there is no reason
the synth couldn't of done it all by itself (see above WHILE loop
pseudo-assembly code.)

Gabor

unread,
Jan 13, 2009, 5:56:44 PM1/13/09
to

I think you're missing the fact that the hardware synthesis
MUST unroll the loop. i.e. the entire loop runs concurrently
thereby creating hardware for each iteration. It can't do that
for a loop whose iterations are not known at the time of
synthesis.

There may be some cases where a loop can be coded without
using for 1 to 10, but where the number of iterations is
known at synthesis time. This does not necessarily mean
they are synthesizable. The synthesis process uses templates
to fit your code into structures available in the underlying
hardware. Synthesizable code must fit into the available
templates.

Regards,
Gabor

Brian Drummond

unread,
Jan 13, 2009, 8:20:08 PM1/13/09
to
On Tue, 13 Jan 2009 14:18:16 -0800 (PST), jleslie48
<j...@jonathanleslie.com> wrote:

>On Jan 10, 8:54 pm, rickman <gnu...@gmail.com> wrote:

>
>I don't see why the IF statement translates any different than the
>while/for loop. both should
>translate to static sizes independent of the number of interations
>that are completed:
>
>an IF translates to:
>
><conditional jump> to else_part
>-- then code goes here
><unconditional jump> to endif_xyz
>label else_part:
>--else code goes here
>label endif_xyz:
>
>and the WHILE would be:
>
>label topofwhile_xyz:
><conditional jump> to end_of_while_xyz
>---stuff to do
><unconditional jump> to topofwhile_xyz
>label end_of_while_xyz:
>
>I was expecting the synth do work similarly.

The big difference between the two is this:
in the While loop, the jump is _backwards_.

A more CS-oriented view would be that the difference between IF and
WHILE is exactly that between a directed acyclic and a cyclic graph.
Unrolling the loop is then transforming the cyclic graph into acyclic
form.

If you are decomposing the operation into machine instructions, and
executing them sequentially, that is no problem; it merely takes a very
long time.

But you aren't decomposing into anything sequential, unless you can
_force_ a serialisation, e.g. with a "wait until rising_edge(clk)"
in the loop. (Which is unrecognised by XST. Incidentally I tried it in
the Altera synthesis tool. It fails too, interestingly the error is
"More than one Wait in Process" - therefore Altera is explicitly
unrolling the loop even before examining its contents!)

Therefore the ONLY ways are: (a) to force that serialisation (either as
above but in a better synthesis tool, if one exists), or explicitly in
the pattern you suggested (and criticise)
or (b) unroll the loop (e.g. use ten multipliers in prev example)

>The data value of the number of iterations is swallowed up by the
><conditional jump> and thus the sizing of the "circuit" is
>independent of the number of interations.

I hope the above shows why it doesn't work that way.

- Brian

jleslie48

unread,
Jan 14, 2009, 8:16:56 AM1/14/09
to
On Jan 13, 8:20 pm, Brian Drummond <brian_drumm...@btconnect.com>
wrote:

AHHHH!!!!! so what you and Gabor are saying is that the synth is
trying to make my while loop work all within one clock tick, rather
than have the n (in the example, 10) iterations occur once per clock
tick as my re-written version version does (see post Jan 7, 12:36 pm,
the looper10_proc.) So in my bad code, the 'do something' to all
occur in the one clock cycle, has to be repeated n times IN HARDWARE ,
thus allowing all to occur at the same time. Correct?

Gabor

unread,
Jan 14, 2009, 9:05:13 AM1/14/09
to

By Jove I think you've got it! :-)

jleslie48

unread,
Jan 14, 2009, 9:26:27 AM1/14/09
to
On Jan 14, 9:05 am, Gabor <ga...@alacron.com> wrote:

> > AHHHH!!!!! so what you and Gabor are saying is that the synth is
> > trying to make my while loop work all within one clock tick, rather
> > than have the n (in the example, 10) iterations occur once per clock
> > tick as my re-written version version does (see post Jan 7, 12:36 pm,
> > the looper10_proc.) So in my bad code, the 'do something' to all
> > occur in the one clock cycle, has to be repeated n times IN HARDWARE ,
> > thus allowing all to occur at the same time. Correct?
>
> By Jove I think you've got it! :-)


That is a very important mis-understanding to have cleared up. I
would of been
programming the ~do something~ to calcuate an average or a summation,
and
the looping nature of the while loop would of been completely wrong.
This aint' no C compiler.


Rob Gaddi

unread,
Jan 14, 2009, 11:59:09 AM1/14/09
to
On Wed, 14 Jan 2009 06:26:27 -0800 (PST)
jleslie48 <j...@jonathanleslie.com> wrote:

> On Jan 14, 9:05 am, Gabor <ga...@alacron.com> wrote:

> [snip]


>
> This aint' no C compiler.
>

And there's the moral of the story.


--
Rob Gaddi, Highland Technology
Email address is currently out of order

0 new messages