pupillo
Guest
Wed Aug 25, 2010 12:19 pm
Hi,
Here below a stupid code to show a problem that I can't understand.
I have a 8 bit register (myReg) and a clk.
On each rising edge of clk a process should set myReg(0 to 1) to '0'
using a for loop and another process (always on each ris. edge) set
the other bits to '0' as well (remind, it's a STUPID code just for
understanding).
When I simulate (tried more simulators) I get zeroes on myReg(0 to 1)
(ok) but U on the others (2 to 7). WHY?
If I don't use the for loop (and I simply use assignments) it works.
If I move the assignments done by the second process, after the end
loop line of the first process it works.
Thnaks
Pupillo
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity user_logic is
end entity user_logic;
architecture myArch of user_logic is
signal myReg : std_logic_vector(0 to 7);
signal myClk :std_logic;
begin
REG_0_1_WRITE_PROC : process( myClk ) is
begin
if myClk'event and myClk = '1' then
for index in 0 to 1 loop
myReg(index)<='0';
end loop;
end if;
end process REG_0_1_WRITE_PROC;
REG_2_7_WRITE_PROC : process( myClk ) is
begin
if myClk'event and myClk = '1' then
myReg(2 to 7) <= (others => '0');
end if;
end process REG_2_7_WRITE_PROC;
gen_clkrocess begin
while (true) loop
myClk<='0';
wait for 5 ns;
myClk<='1';
wait for 5 ns;
end loop;
end process;
end myArch;
Brian Drummond
Guest
Wed Aug 25, 2010 12:19 pm
On Wed, 25 Aug 2010 02:19:18 -0700 (PDT), pupillo <t.dalpozzo_at_gmail.com> wrote:
Quote:
Hi,
If I don't use the for loop (and I simply use assignments) it works.
If I move the assignments done by the second process, after the end
loop line of the first process it works.
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_arith.all;
-- use ieee.std_logic_unsigned.all;
-- Don't use these! You don't need them for this example.
-- When you need signed or unsigned types,
use ieee.numeric_std;
-- instead
-- if myClk'event and myClk = '1' then
-- If you want a rising edge detector, use this...
if rising_edge(clk)
-- then pathological testbenches that alternate between "H" and "1"
-- won't clock your circuit when they shouldn't!
Both the above defects come from following design guidelines that have been
obsolete for well over 15 years.
But the basic problem is that both processes drive "myreg" and without a
complete analysis (especially of the loop, which could compute the loop bounds
in much more complex ways) it's impossible for the compiler to detect that you
have got it right (driving all the bits, exactly once each).
So the language simplifies by saying that each process potentially drives all of
"myreg".
Solutions:
(1) Drive "myreg" from exactly one process. As you confirmed, that works.
It's also less verbose, and probably clearer.
(2) Drive a separate signal from each process, and combine them externally
myreg <= myreg_2 & myreg_1; -- from process 2 and 1 respectively
(Naturally you have declared myreg_1 as 2 bits wide, etc)
This involves an extra signal assignment.
People will tell you that your sim runs slower, but I'll be damned if I can
measure the difference in the context of a whole project. It'll certainly be
faster than trying to find an obscure bug introduced by being too clever.
The only problem worth mentioning is that if you use any signals from "myreg" as
clocks to other logic, they will appear one delta cycle later (i.e. zero time
later but in a different order from the original design) and that can cause
different simulation results (race conditions) downstream. But using them as
clocks would be bad design practice anyway.
(3) Drive a separate signal from each process, and use an alias to rename them
to "myreg"
i.e. in the signal declaration section,
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
Avoids the extra delta cycle. I haven't tested this and there may be an obscure
rule why an alias won't work in this situation, but I believe it should.
- Brian
Jonathan Bromley
Guest
Wed Aug 25, 2010 2:42 pm
On Aug 25, 11:24 am, Brian Drummond wrote:
Quote:
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
Brian, I don't think you can do this. What then happens
if you attempt to assign to myreg??? Remember that "&"
is simply a function that returns a result.
OTOH there may be some way to do it using aggregates.
Where is Jim Lewis when you need him? :-)
alias myreg : std_logic_vector(7 downto 0) is
(7 => myreg_2(5)
,6 => myreg_2(4)
, .... ad nauseam ....
,2 => myreg_2(0)
,1 => myreg_1(1)
,0 => myreg_1(0) );
Even if it works (which I doubt) it's pretty nasty!
--
Jonathan Bromley
Mike Treseler
Guest
Wed Aug 25, 2010 5:05 pm
On 8/25/2010 8:52 AM, pupillo wrote:
Quote:
I think that the best thing is driving all the bus within the same
process,
True.
Quote:
however I wonder why a compiler should try to suppose that
only one process drives all the signals. It looks like going against
the semantic of vhdl.
But there is only one signal:
signal myReg : std_logic_vector(0 to 7);
Use use two vectors or std_ulogic for bits.
It is easier to combine than slice in vhdl.
-- Mike Treseler
pupillo
Guest
Wed Aug 25, 2010 6:52 pm
On 25 Ago, 13:42, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
Quote:
On Aug 25, 11:24 am, Brian Drummond wrote:
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
Brian, I don't think you can do this. What then happens
if you attempt to assign to myreg??? Remember that "&"
is simply a function that returns a result.
OTOH there may be some way to do it using aggregates.
Where is Jim Lewis when you need him? :-)
alias myreg : std_logic_vector(7 downto 0) is
(7 => myreg_2(5)
,6 => myreg_2(4)
, .... ad nauseam ....
,2 => myreg_2(0)
,1 => myreg_1(1)
,0 => myreg_1(0) );
Even if it works (which I doubt) it's pretty nasty!
--
Jonathan Bromley
I think that the best thing is driving all the bus within the same
process, however I wonder why a compiler should try to suppose that
only one process drives all the signals. It looks like going against
the semantic of vhdl.
Jonathan Bromley
Guest
Wed Aug 25, 2010 7:45 pm
On Wed, 25 Aug 2010 08:52:18 -0700 (PDT), pupillo wrote:
Quote:
I think that the best thing is driving all the bus within the same
process,
Yes. Very good for your sanity.
Quote:
however I wonder why a compiler should try to suppose that
only one process drives all the signals. It looks like going against
the semantic of vhdl.
Two issues here:
- all the 'U' values you saw were precisely because you
had two processes driving the same signa; the problem
was that one process was unexpectedly driving 'U's,
because.....
- a 'for' loop in VHDL is "dynamically elaborated", so the
for-loop range cannot be used to determine which of a set
of signals the process drives. Consequently, if you drive
even one bit of the vector from within that for-loop,
the whole vector is driven by the process. Search the
VHDL LRM for the phrase "longest static prefix" to find
more detail on why this is so.
The for-loop thing is often quite irritating, especially
to people who use for-loops for synthesis and expect the
loop to be statically unrolled. In VHDL that is not what
happens. For-generate loops, on the other hand, ARE
statically elaborated and you can use them to drive
selected bits of a vector while leaving other bits
undriven - bear in mind that the for-generate is
actually constructing separate processes for each
pass of the loop, and each process statically knows
which part of the vector it's driving. Not so with
a procedural for-loop; there's just one process, but
if you use the loop counter as an index into the vector
then the process doesn't know statically which bits
it will drive, and must conclude that it's driving
the whole vector.
No easy answers, I'm afraid (apart from the sensible
"just one process" advice). Most people (me included)
find the LRM description of longest-static-prefix
quite hard to follow, although it's very precise.
--
Jonathan Bromley
pupillo
Guest
Wed Aug 25, 2010 8:31 pm
I think that you're right.
For VHDL it'is ONE signal (even though it's a bus), thus driving one
signal in two process can lead to a undefined behaviour.
Pupillo
On 25 Ago, 18:05, Mike Treseler <mtrese...@gmail.com> wrote:
Quote:
On 8/25/2010 8:52 AM, pupillo wrote:
I think that the best thing is driving all the bus within the same
process,
True.
however I wonder why a compiler should try to suppose that
only one process drives all the signals. It looks like going against
the semantic of vhdl.
But there is only one signal:
signal myReg : std_logic_vector(0 to 7);
Use use two vectors or std_ulogic for bits.
It is easier to combine than slice in vhdl.
-- Mike Treseler
Brian Drummond
Guest
Wed Aug 25, 2010 9:50 pm
On Wed, 25 Aug 2010 04:42:38 -0700 (PDT), Jonathan Bromley
<spam_at_oxfordbromley.plus.com> wrote:
Quote:
On Aug 25, 11:24 am, Brian Drummond wrote:
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
Brian, I don't think you can do this. What then happens
if you attempt to assign to myreg??? Remember that "&"
is simply a function that returns a result.
I was assuming that there would only be assignments to its component parts.
But my posting machine doesn't do VHDL, and my work machine isn't on the
internet, so this approach remains untested (here)...
- Brian
Jonathan Bromley
Guest
Thu Aug 26, 2010 10:15 am
Quote:
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
But my posting machine doesn't do VHDL, and my work machine isn't on the
internet, so this approach remains untested (here)...
ModelSim won't compile it, but I haven't had time to
trawl the LRM to work out exactly what to do instead.
Given that "A&B" is not a reference-able thing, but rather
is just the value-result of a function's execution, I
don't think it will ever be possible to make that happen.
Aggregates don't seem to work either. Once again, I haven't
had a chance to work out precisely why, or what you could
do about it.
--
Jonathan Bromley
pupillo
Guest
Thu Aug 26, 2010 10:21 am
On 26 Ago, 09:15, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
Quote:
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
But my posting machine doesn't do VHDL, and my work machine isn't on the
internet, so this approach remains untested (here)...
ModelSim won't compile it, but I haven't had time to
trawl the LRM to work out exactly what to do instead.
Given that "A&B" is not a reference-able thing, but rather
is just the value-result of a function's execution, I
don't think it will ever be possible to make that happen.
Aggregates don't seem to work either. Once again, I haven't
had a chance to work out precisely why, or what you could
do about it.
--
Jonathan Bromley
OK,
thanks to all, I will keep in mind your advices
Pupillo
Jonathan Bromley
Guest
Fri Aug 27, 2010 5:41 pm
On Fri, 27 Aug 2010 08:49:13 -0700 (PDT), Andy wrote:
Quote:
you cannot just create an alias that is a vector of disassociated bits
because those bits are not located together where a vector reference
will work.
Agreed, that makes perfect sense, and I've no doubt
it's what actually happens.
_A_fortiori_ you can't alias to the value (result)
of an expression, such as A&B.
--
Jonathan Bromley
Andy
Guest
Fri Aug 27, 2010 6:49 pm
On Aug 26, 2:15 am, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
Quote:
alias myreg : std_logic_vector(7 downto 0) is myreg_2 & myreg_1;
But my posting machine doesn't do VHDL, and my work machine isn't on the
internet, so this approach remains untested (here)...
ModelSim won't compile it, but I haven't had time to
trawl the LRM to work out exactly what to do instead.
Given that "A&B" is not a reference-able thing, but rather
is just the value-result of a function's execution, I
don't think it will ever be possible to make that happen.
Aggregates don't seem to work either. Once again, I haven't
had a chance to work out precisely why, or what you could
do about it.
--
Jonathan Bromley
I tend to think of aliases as just a different handle to the same
object. It does not and cannot rely upon any movement of data. Thus
you cannot just create an alias that is a vector of disassociated bits
because those bits are not located together where a vector reference
will work.
Andy