outputs are in conflict most of the time

  • Thread starter Martijn van Pottelberghe
  • Start date
M

Martijn van Pottelberghe

Hello everybody,

I'm trying to make a vhdl implementation of an 74162 (bcd counter with load)
Defined an entity and architecture, and entered a behavioural description
that I think should be ok overall.

After this definition, I made a testbench vhdl-file in order to simulate the
thing using modelsim.

Because i'm not even sure if the conflict appears within the testbench, or
in the component description, I'll insert both heir vhdl files below.
In order not to bother you too much I commented extensively so at least my
reasonings should be easy to follow.

Also I have a nice small png file of simulated signals, but the news server
won't let me post those 13kb..

Thanks for your attention so far..
Help would be greatly appreciated.

Regards,
Martijn

Here comes the 74162:
=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity sn_74162 is
port (
clr : in std_logic;
load : in std_logic;
ent : in std_logic;
enp : in std_logic;
clk : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
d : in std_logic;
oa : out std_logic;
ob : out std_logic;
oc : out std_logic;
od : out std_logic;
rco : out std_logic;

reset : in std_logic -- not an 74162's pin, though useful for testing
purposes
);
end sn_74162;

architecture gedrag of sn_74162 is
signal num_out: std_logic_vector(3 downto 0);
signal rco_on: std_logic; -- when i want to change rco, in fact i write to
rco_on
-- i do this in order to have a readable version of rco

begin
oa <= num_out(0);
ob <= num_out(1); -- map num_out vector to right outputs
oc <= num_out(2);
od <= num_out(3);

rco <= rco_on when rco_on'event;

process(reset) begin
if reset = '1' then
num_out <= "0000";
rco_on <= '0';
end if;
end process;

process(clk)
begin
if clk'event and clk='1' then -- clear, load all synchronous in the 162

-- if ripple carry has been set, now is the time to set it back to 0
-- (ripple carry is held high for 1 full clock cycle in this manner)
if rco_on = '1' then
rco_on <= '0';
end if;

if clr = '0' then -- logical diagram points out that clear has
presedence over load
num_out <= "0000";
elsif load = '0' then -- load has presedence over counting (loaded values
don'tget incremented)
num_out <= (a,b,c,d);
elsif enp = '0' and ent = '0' then -- increment
if num_out = "1001" then --is it 9, then back to 0 (because it's a bcd
counter)
num_out <= "0000";
rco_on <= '1'; -- clock to next counter in cascade
else num_out <= std_logic_vector(unsigned(num_out)+1);
end if;
end if;

end if; -- clk'event

end process;

end gedrag;

Here the testbench:
=======================================================================
library ieee;
use ieee.std_logic_1164.all;


entity testbench is
end testbench;

architecture tb_sn_74162 of testbench is
component sn_74162 port (
clr : in std_logic;
load : in std_logic;
ent : in std_logic;
enp : in std_logic;
clk : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
d : in std_logic;
oa : out std_logic;
ob : out std_logic;
oc : out std_logic;
od : out std_logic;
rco : out std_logic;
reset : in std_logic
); end component;

for uut : sn_74162 use entity work.sn_74162(gedrag);

signal clr : std_logic;
signal load : std_logic;
signal ent : std_logic;
signal enp : std_logic;
signal clk : std_logic := '0';
signal a : std_logic;
signal b : std_logic;
signal c : std_logic;
signal d : std_logic;
signal oa : std_logic;
signal ob : std_logic;
signal oc : std_logic;
signal od : std_logic;
signal rco : std_logic;
signal reset : std_logic;

constant HALF_CLOCK_PERIOD : time := 10 ns;
constant RESET_PERIOD : time := 2 ns;

--
-- place your own declarations here
--

begin --testbench

uut : sn_74162 port map (
clr => clr,
load => load,
ent => ent,
enp => enp,
clk => clk,
a => a,
b => b,
c => c,
d => d,
oa => oa,
ob => ob,
oc => oc,
od => od,
rco => rco,
reset => reset
);


clk <= not clk after HALF_CLOCK_PERIOD;
reset <= '1', '0' after RESET_PERIOD;


process
begin
-- test loading:
clr <= '1';
load <= '0';
ent <='0'; --load should have presedence; clock enable should'nt matter
enp <='0';
-- zeroes only
a <= '0';
b <= '0';
c <= '0';
d <= '0';
wait for 6*HALF_CLOCK_PERIOD;
-- ones only
a <= '1';
b <= '1';
c <= '1';
d <= '1';
wait for 6*HALF_CLOCK_PERIOD;
-- mixed
a <= '1';
b <= '0';
c <= '1';
d <= '0';
wait for 6*HALF_CLOCK_PERIOD;


-- value now 5
-- now test counting. enable is still active

load <='1'; -- load off; counting starts
wait for 24*HALF_CLOCK_PERIOD;

-- expected value now 5 + 16/2 (mod 10) = 4
-- (check if a pulse has been given to rco)

-- test inhibit:
ent <= '1'; -- one inhibit actief
wait for 6*HALF_CLOCK_PERIOD;

enp <= '1'; -- two inhibit actief
wait for 6*HALF_CLOCK_PERIOD;


-- test if load en clr still work (as they should)
a <= '1';
b <= '0';
c <= '1';
d <= '0';
wait for 6*HALF_CLOCK_PERIOD;


clr <= '0';
wait for 6*HALF_CLOCK_PERIOD;

wait;
end process;

end tb_sn_74162;
 
P

Paul Uiterlinden

Martijn said:
Hello everybody,

I'm trying to make a vhdl implementation of an 74162 (bcd counter
with load) Defined an entity and architecture, and entered a
behavioural description that I think should be ok overall.

After this definition, I made a testbench vhdl-file in order to
simulate the thing using modelsim.

Because i'm not even sure if the conflict appears within the
testbench, or in the component description, I'll insert both heir
vhdl files below. In order not to bother you too much I commented
extensively so at least my reasonings should be easy to follow.

You have two processes (in sn_74162) that both are driving signals
num_out and rco_on. That is your conflict: multiple drivers.

To solve that, put the reset part in the second process and scrap the
first process. Or better yet: just remove input reset. You already
have the clr input.

Also replace:

rco <= rco_on when rco_on'event;

by:

rco <= rco_on;

A concurrent signal assignment is triggered automatically when an
event occurs on a signal in the right hand side.
Also I have a nice small png file of simulated signals, but the news
server won't let me post those 13kb..

Even if it would, this is not a binary newsgroup, so don't do that.
Include a URL if you want to refer to a png file.

Paul.
 
K

KJ

Martijn van Pottelberghe said:
Hello everybody,

I'm trying to make a vhdl implementation of an 74162 (bcd counter with
load)
Defined an entity and architecture, and entered a behavioural description
that I think should be ok overall.

After this definition, I made a testbench vhdl-file in order to simulate
the
thing using modelsim.

Because i'm not even sure if the conflict appears within the testbench, or
in the component description, I'll insert both heir vhdl files below.
In order not to bother you too much I commented extensively so at least my
reasonings should be easy to follow.

In addition to Paul's post I would suggest changing all std_logic to
std_ulogic. Then the compiler will flag for you where you have two outputs
driving the same signal...without ever starting up the simulation. It's
much quicker. The only time std_logic is really needed is when you really
do need to have two outputs driving a common signal at the same time. This
occurs typically on data busses and will always involve tri-state control of
every driver (i.e. setting each process that drives a signal to 'Z').

I'm guessing that you're relatively new to VHDL and that whoever/whatever
you learned VHDL from always used std_logic as the basic type for
everything. Most people do learn this way, most people even continue to do
it this way....and it's a mistake (in my opinion). Most signals in any
design are never going to be intentionally driven by multiple sources so
std_logic is just the wrong choice.

Now most people (I would estimate it at 100%), as they write code ARE going
to UNintentionally drive a signal from two places at some point in their
career. And for each time they do this, if they use std_logic, they will
have to debug to find the problem or ask for outside help as you have. Each
person that used std_ulogic on the other hand will get the problem pointed
out to them clearly either when they compile the file or as soon as they
invoke the simulator (this occurs when the multiple drivers are physically
in separate files or entities and compiling alone is not enough to 'know'
that there are multiple drivers). The choice is yours to make.

One caveat to using std_ulogic is you may find yourself interfacing to
existing code that uses std_logic and you will have to either cave in and
change your signal or add some type conversions. But again, the compiler
flags those cases for you. In general, it is usually worth it I
think...others may think otherwise....when they're not busy using the
simulator to find multiple drivers.

KJ
 
P

Paul Uiterlinden

KJ said:
In addition to Paul's post I would suggest changing all std_logic to
std_ulogic. Then the compiler will flag for you where you have two
outputs
driving the same signal...without ever starting up the simulation.
It's
much quicker. The only time std_logic is really needed is when you
really
do need to have two outputs driving a common signal at the same
time. This occurs typically on data busses and will always involve
tri-state control of every driver (i.e. setting each process that
drives a signal to 'Z').

You're absolutely right. That is exactly what I do.

In addition, I always try to use types and constructs that gives an
error message at the earliest possibility. Use types with the
smallest possible range: delay_length in stead of time, natural
instead of integer. Also I avoid using the WHEN OTHERS choice in case
statements, especially in combination with enumerated types. If I
later extend the enumeration type, it gets automatically flagged
during analysis if I forget to add the choice to the case statement.
This however holds only for behavioral code (testbenches and models).
For synthesis the WHEN OTHERS is needed for other reasons than
strictly VHDL.
I'm guessing that you're relatively new to VHDL and that
whoever/whatever you learned VHDL from always used std_logic as the
basic type for
everything. Most people do learn this way, most people even
continue to do
it this way....and it's a mistake (in my opinion). Most signals in
any design are never going to be intentionally driven by multiple
sources so std_logic is just the wrong choice.

Now most people (I would estimate it at 100%), as they write code
ARE going to UNintentionally drive a signal from two places at some
point in their
career. And for each time they do this, if they use std_logic, they
will
have to debug to find the problem or ask for outside help as you
have. Each person that used std_ulogic on the other hand will get
the problem pointed out to them clearly either when they compile the
file or as soon as they invoke the simulator (this occurs when the
multiple drivers are physically in separate files or entities and
compiling alone is not enough to 'know'
that there are multiple drivers). The choice is yours to make.

One caveat to using std_ulogic is you may find yourself interfacing
to existing code that uses std_logic and you will have to either
cave in and
change your signal or add some type conversions.

If you're talking about std_logic/std_ulogic this is not true.
std_logic is a subtype of std_ulogic, so they "talk" to each other
without the need of any conversion.

If you're talking about std_logic_vector/std_ulogic_vector, then
you're right. That's why I only use std_logic_vector, not
std_ulogic_vector. I know I miss occasions to check for multiple
drivers that way. But then again, I always use mode buffer instead of
out. That also gives a check on multiple drivers, regardless of the
type involved. And you also do not need those pesky intermediate
signals if you want to read the output port signal internally.
 
K

KJ

Martijn van Pottelberghe said:
Hello everybody,

I'm trying to make a vhdl implementation of an 74162 (bcd counter with
load)
Defined an entity and architecture, and entered a behavioural description
that I think should be ok overall.

After this definition, I made a testbench vhdl-file in order to simulate
the
thing using modelsim.

Because i'm not even sure if the conflict appears within the testbench, or
in the component description, I'll insert both heir vhdl files below.
In order not to bother you too much I commented extensively so at least my
reasonings should be easy to follow.

In addition to Paul's post I would suggest changing all std_logic to
std_ulogic. Then the compiler will flag for you where you have two outputs
driving the same signal...without ever starting up the simulation. It's
much quicker. The only time std_logic is really needed is when you really
do need to have two outputs driving a common signal at the same time. This
occurs typically on data busses and will always involve tri-state control of
every driver (i.e. setting each process that drives a signal to 'Z').

I'm guessing that you're relatively new to VHDL and that whoever/whatever
you learned VHDL from always used std_logic as the basic type for
everything. Most people do learn this way, most people even continue to do
it this way....and it's a mistake (in my opinion). Most signals in any
design are never going to be intentionally driven by multiple sources so
std_logic is just the wrong choice.

Now most people (I would estimate it at 100%), as they write code ARE going
to UNintentionally drive a signal from two places at some point in their
career. And for each time they do this, if they use std_logic, they will
have to debug to find the problem or ask for outside help as you have. Each
person that used std_ulogic on the other hand will get the problem pointed
out to them clearly either when they compile the file or as soon as they
invoke the simulator (this occurs when the multiple drivers are physically
in separate files or entities and compiling alone is not enough to 'know'
that there are multiple drivers). The choice is yours to make.

One caveat to using std_ulogic is you may find yourself interfacing to
existing code that uses std_logic and you will have to either cave in and
change your signal or add some type conversions. But again, the compiler
flags those cases for you. In general, it is usually worth it I
think...others may think otherwise....when they're not busy using the
simulator to find multiple drivers.

KJ
 
M

Mike Treseler

Paul said:
If you're talking about std_logic/std_ulogic this is not true.
std_logic is a subtype of std_ulogic, so they "talk" to each other
without the need of any conversion.

Yes, and std_ulogic is an excellent choice for a default bit type.

The vector type std_ulogic_vector clashes with
numeric_std functions so I can't suggest
an obvious "best" default vector type.

I avoid multiple drivers by using
single process design entities.


-- Mike Treseler
 
K

KJ

Mike said:
Yes, and std_ulogic is an excellent choice for a default bit type.

The vector type std_ulogic_vector clashes with
numeric_std functions so I can't suggest
an obvious "best" default vector type.

The type clashes though can be easily resolved with the appropriate
type conversions

A_std_ulogic_vector_signal <=
std_ulogic_vector(std_logic_vector(An_Unsigned_Signal));

where 'A_std_ulogic_vector_signal is a std_ulogic_vector and
An_Unsigned_Signal is an unsigned.

For the 'write it only once' guys this could be put into a function

function Unsigned_To_Std_ULogic_Vector(L: unsigned) return
std_ulogic_vector is
begin
return (std_ulogic_vector(std_logic_vector(L)));
end function Unsigned_To_Std_ULogic_Vector;

and then packaged with other handy 'always need these types of things
whenever I do a VHDL design' package of VHDL things and used like...

A_std_ulogic_vector_signal <=
Unsigned_To_Std_ULogic_Vector(An_Unsigned_Signal);
I avoid multiple drivers by using
single process design entities.
But that doesn't help resolve unintended multiple drivers between
entities whereas std_ulogic would immediately flag it as soon as you
start sim without having to debug down to that error....either that or
run it through synthesis and let it find the multiple driver error.

Like I mentioned earlier in the thread, there can be other places where
type conversions are needed when interfacing with std_logic_vector and
where making use of std_ulogic_vector a bit annoying at times....but
I've found that it's generally not too bad. The amount of annoyance is
probably directly related to how much existing code there is that you
can't touch at all for whatever reason.

KJ
 
M

Mike Treseler

KJ said:
But that doesn't help resolve unintended multiple drivers between
entities

Port directions cover me there for all internal entities.
whereas std_ulogic would immediately flag it as soon as you
start sim

as soon as I compile, actually
without having to debug down to that error....either that or
run it through synthesis and let it find the multiple driver error.

Just to clarify, I agree with you on std_ulogic type for bits.
Like I mentioned earlier in the thread, there can be other places where
type conversions are needed when interfacing with std_logic_vector and
where making use of std_ulogic_vector a bit annoying at times....but
I've found that it's generally not too bad. The amount of annoyance is
probably directly related to how much existing code there is that you
can't touch at all for whatever reason.

default vector type annoyance
------------------- ---------
1. std_logic_vector mild: cast (un)signed for numerics
2. std_ulogic_vector mild: some users complain
3. unsigned moderate: implies numerics

So, it depends.
I see no clear default.

-- Mike Treseler
 
K

KJ

Mike said:
Port directions cover me there for all internal entities.


as soon as I compile, actually

Yes...almost always. I know I've run across cases where every file
compiled without error and still when vsim was invoked it choked about
two std_ulogics (or vectors) being driven from multiple sources. I
don't quite recall the circumstances though and just fixed the
unintended multiple drivers. In any event whether the compiler catches
it (as it generally does) or at worst it gets caught when invoking
'vsim' at least I didn't have to debug down to the error to find
it....as I did in my younger days....back when my memory was better.

KJ
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top