Counter Question

B

bob

I have a counter (16 bit). I want to use the MSB bit 15 to signal that
the counter is full and STOP further counting. The max count would be
1000 0000 0000 0000 = full flag set
The code below works as when the MSB = hi the full flag goes high,
but for some reason an extra count is allowed.
I get 1000 0000 0000 0001.

Any ideas?

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

entity counter16bit is
port (

CLK: in STD_LOGIC;
RESET: in STD_LOGIC;
RESET2: in STD_LOGIC;
FULL: inout STD_LOGIC;
COUNT: inout STD_LOGIC_VECTOR(15 downto 0)
);
end counter16bit;

architecture Behavioral of counter16bit is

begin
process (CLK, RESET, RESET2)

begin

if RESET='1' or RESET2='0' then
COUNT <= "0000000000000000";
FULL <= '0';
elsif CLK='1' and CLK'event and full='0' then -- rising
edge of clk!
COUNT <= COUNT + 1;
FULL <= COUNT(15);
end if;
end process;
 
S

skatoulas

looking at it programmatically signals only get updated at the end of
the process execution. This means that u schedule count to become count
+ 1 when the process suspends, and u also scedule full to take the
value count(15) when the process suspends. So when count is 0111 1111
1111 1111 it's supposed to become 1111 1111 1111 1111 but full will
still be 0 as count hasnt yet changed! So there is one more count,
where full takes the value count(15) which is now 1 and count becomes
count + 1 which is 1000 0000 0000 0001. I know its a bit tricky to
understand but its the way it is...
To avoid this sort of confusion, use variables for temporary
assignments, then assign their values to the signals at the end of the
process. so in your case, create a 16-bit variable named temp_count and
an std_logic named temp_full, do all operations on the variables and
just before the end process statement type full<= temp_full and
count<=temp_count. Variable assignments (use the := operator) occur
instantly.
 
A

Andy Peters

bob said:
I have a counter (16 bit). I want to use the MSB bit 15 to signal that
the counter is full and STOP further counting. The max count would be
1000 0000 0000 0000 = full flag set
The code below works as when the MSB = hi the full flag goes high,
but for some reason an extra count is allowed.
I get 1000 0000 0000 0001.

Any ideas?

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

Don't use std_logic_arith and std_logic_unsigned. Use numeric_std
instead.
entity counter16bit is
port (

CLK: in STD_LOGIC;
RESET: in STD_LOGIC;
RESET2: in STD_LOGIC;
FULL: inout STD_LOGIC;
COUNT: inout STD_LOGIC_VECTOR(15 downto 0)

Why are FULL and COUNT declared as inouts?
);
end counter16bit;

architecture Behavioral of counter16bit is

begin
process (CLK, RESET, RESET2)
begin
if RESET='1' or RESET2='0' then
COUNT <= "0000000000000000";
FULL <= '0';

Better here would be:

COUNT said:
elsif CLK='1' and CLK'event and full='0' then
COUNT <= COUNT + 1;
FULL <= COUNT(15);
end if;
end process;

Well, you need to learn about when assignments take place. The
assignment

FULL <= COUNT(15);

looks at the state of COUNT on every rising edge of CLK. If COUNT(15)
is true, then FULL is true. However, watch the delta delays, since on
clock tick N, COUNT is updated, and the statement FULL <= COUNT(15)
won't see that update until the NEXT clock tick. (This is all basic
logic design, BTW).

There are some other problems with your code, too, but you should
digest the above stuff first.

-a
 
H

Hubble

Using a variable for count will do (Full now becomes 1 when cnt(15) is
becoming 1 by the increment, not one clock(-delta) afterwards. COUNT
can now be declared as out. Use a similar trick to convert the full
inout port to out (left as an exercise to the reader)


process (CLK, RESET, RESET2)
variable cnt: std_logic_vector(COUNT'range);
begin
if RESET='1' or RESET2='0' then
cnt := (others => '0');
COUNT <= (others => '0');
FULL <= '0';
elsif CLK='1' and CLK'event and Full='0' then -- rising
edge of clk!
cnt:=cnt+1;
COUNT<=cnt;
Full<=cnt(15);
end if;
end process;


Hubble.
 
B

bob

Thanks for all the help.
The code works much better now (attached).
I seem to needed to keep Full as inout so that I could use it in the
elsif line. Otherwise I get errors.

I only get the chance to writh VHDL once or twice a year so I tend to
forget how to code well and need to start from scratch (but dont realy
have the time). Bouncing from hardware, C and Visual Basic tends to
make you a jack of all trades but master of none.
So if you see any other sloppy or redundant code please point it out?
Also any books (clear and to the point) that you would recommend?


----------------------------------------------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter16bit is
port (
-- 16-bit synchronous counter,
CLK: in STD_LOGIC;
RESET: in STD_LOGIC;
RESET2: in STD_LOGIC;
FULL: inout STD_LOGIC;
COUNT: out STD_LOGIC_VECTOR(15 downto 0)
);
end counter16bit;

architecture Behavioral of counter16bit is

begin
process (CLK, RESET, RESET2)
variable cnt:std_logic_vector(15 downto 0);
variable temp_full:std_logic;

begin
if RESET='1' or RESET2='0' then
COUNT <= (others => '0');
cnt:= (others => '0'); -- occur instantly.
FULL <= '0';
temp_full:= '0'; -- occur instantly.

elsif CLK='1' and CLK'event and full='0' then -- rising
edge of clk!
cnt:=cnt+1; -- occur instantly.
COUNT<=cnt;
temp_full:=cnt(15); -- occur instantly.
FULL <= temp_full;
end if;
end process;

end Behavioral;
 
H

Hubble

I seem to needed to keep Full as inout so that I could use it in the
elsif line. Otherwise I get errors.


You should also be able also use temp_full (or even cnt(15)) in elsif.
Then FULL can be out instead if inout.

Sometimes you have to read an output port. Good practice is here to use
an internal signal (with suffix _int for internal) like this:

entity x ...
...
PORT outsig: out std_logic;
...
end entity;

architecture behav of x is
signal outsig_int: std_logic;
begin
outsig<=outsig_int; -- concurrent signal assignment

process1
... -- read/write outsig_int here



The problem is that you loose one delta (time tick). However I use
*never* INOUT instead of OUT.

Hubble.
 
B

bob

Thanks
Why the opposition to inout?

elsif line. Otherwise I get errors.


You should also be able also use temp_full (or even cnt(15)) in elsif.
Then FULL can be out instead if inout.

Sometimes you have to read an output port. Good practice is here to use
an internal signal (with suffix _int for internal) like this:

entity x ...
...
PORT outsig: out std_logic;
...
end entity;

architecture behav of x is
signal outsig_int: std_logic;
begin
outsig<=outsig_int; -- concurrent signal assignment

process1
... -- read/write outsig_int here



The problem is that you loose one delta (time tick). However I use
*never* INOUT instead of OUT.

Hubble.
 
A

Andy Peters

bob said:
Why the opposition to inout?

Because declaring a signal as inout implies that it will be used as
both an input and an output, and if you're using the entity in your
hierarchy's lower levels, the synthesizer may not like it because it
may expect tristate drivers.

Your problem is that you're trying to use a signal declared as an
output on the right-hand-side of an assignment. In VHDL, that's a
no-no. You should declare an "internal" version of the signal, do all
of the counting, etc with that internal version, and finally assign the
internal version to the port.

This is all basic VHDL stuff ...

-a
 
B

bob

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;
Because declaring a signal as inout implies that it will be used as
both an input and an output, and if you're using the entity in your
hierarchy's lower levels, the synthesizer may not like it because it
may expect tristate drivers.

Your problem is that you're trying to use a signal declared as an
output on the right-hand-side of an assignment. In VHDL, that's a
no-no. You should declare an "internal" version of the signal, do all
of the counting, etc with that internal version, and finally assign the
internal version to the port.

This is all basic VHDL stuff ...

-a

Implemented your suggestion and it works well. Thanks
It's just when I read the code from the top down, I think wow it is
making a decision with temp_full before I tell it what temp_full is.
Old habits die hard.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter16bit is
port (
-- 16-bit synchronous counter,
CLK: in STD_LOGIC;
RESET: in STD_LOGIC;
RESET2: in STD_LOGIC;
FULL: out STD_LOGIC;
COUNT: out STD_LOGIC_VECTOR(15 downto 0)
);
end counter16bit;

architecture Behavioral of counter16bit is

begin
process (CLK, RESET, RESET2)
variable cnt:std_logic_vector(15 downto 0);
variable temp_full:std_logic;

begin
if RESET='1' or RESET2='0' then
COUNT <= (others => '0');
cnt:= (others => '0'); -- occur instantly.
FULL <= '0';
temp_full:= '0'; -- occur instantly.

elsif CLK='1' and CLK'event and temp_full='0' then -- rising edge
of clk!
cnt:=cnt+1; -- occur instantly.
COUNT<=cnt;
temp_full:=cnt(15); -- occur instantly.
FULL <= temp_full;
end if;
end process;

end Behavioral;
 
H

Hubble

I think wow it is
making a decision with temp_full before I tell it what temp_full is.
Old habits die hard.

Note that VHDL always initializes its variables and signals. Enums like
boolean (false,true) and std_logic ('U',...) are initialized to the
left most value, that is booleans are always "false" at the beginning
and std_logic are "undefined" ('U'), but not uninitialized. So
temp_full is always intialized to 'U'. See als the paragraph in the LRM

http://www.microlab.ch/courses/vlsi/vhdl-ieee/TUTORIAL/IEEE/HTML/1076_4.HTM#4.3.1.3

Your code is not bad, but I would code like this:



...
elsif CLK'event and CLK='1' and CLK'last_value='0' then -- rising
edge
of clk!
if temp_full='0' then
cnt:=cnt+1; -- occur instantly.
COUNT<=cnt;
temp_full:=cnt(15); -- occur instantly.
FULL <= temp_full;
end if;
end if;

The nested "if temp_full='0'" makes the code clearer. Synthesis tools
are more happy with patterns like this (me too).

Hubble.
 
K

Klaus Falser

Thanks for all the help.
The code works much better now (attached).
I seem to needed to keep Full as inout so that I could use it in the
elsif line. Otherwise I get errors.

I only get the chance to writh VHDL once or twice a year so I tend to
forget how to code well and need to start from scratch (but dont realy
have the time). Bouncing from hardware, C and Visual Basic tends to
make you a jack of all trades but master of none.
So if you see any other sloppy or redundant code please point it out?
Also any books (clear and to the point) that you would recommend?


----------------------------------------------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter16bit is
port (
-- 16-bit synchronous counter,
CLK: in STD_LOGIC;
RESET: in STD_LOGIC;
RESET2: in STD_LOGIC;
FULL: inout STD_LOGIC;
COUNT: out STD_LOGIC_VECTOR(15 downto 0)
);
end counter16bit;

architecture Behavioral of counter16bit is

begin
process (CLK, RESET, RESET2)
variable cnt:std_logic_vector(15 downto 0);
variable temp_full:std_logic;

begin
if RESET='1' or RESET2='0' then
COUNT <= (others => '0');
cnt:= (others => '0'); -- occur instantly.
FULL <= '0';
temp_full:= '0'; -- occur instantly.

elsif CLK='1' and CLK'event and full='0' then -- rising
edge of clk!
cnt:=cnt+1; -- occur instantly.
COUNT<=cnt;
temp_full:=cnt(15); -- occur instantly.
FULL <= temp_full;
end if;
end process;

end Behavioral;

Taking FULL out of the process will give you a shorter
and IMHO better code.

architecture Behavioral of counter16bit is
signal CNT : unsigned(15 downto 0)
begin

FULL <= CNT(15);
COUNT <= std_logic_vector(CNT);

process (CLK, RESET, RESET2)

begin
if RESET='1' or RESET2='0' then
CNT <= (others => '0');
elsif rising_edge(CLK) then
if full='0' then
CNT <= CNT+1;
end if;
end if;
end process;

end Behavioral;


If you are using RESET2 to clear the counter during the
the normal operation, you should think about to clear it
synchronously.
It is better to use asynchronous reset only for having
a defined state at startup.

Hope this helps
Klaus
 
A

Andy Peters

bob said:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;


Implemented your suggestion and it works well. Thanks
It's just when I read the code from the top down, I think wow it is
making a decision with temp_full before I tell it what temp_full is.
Old habits die hard.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter16bit is
port (
-- 16-bit synchronous counter,
CLK: in STD_LOGIC;
RESET: in STD_LOGIC;
RESET2: in STD_LOGIC;
FULL: out STD_LOGIC;
COUNT: out STD_LOGIC_VECTOR(15 downto 0)
);
end counter16bit;

architecture Behavioral of counter16bit is

begin
process (CLK, RESET, RESET2)
variable cnt:std_logic_vector(15 downto 0);
variable temp_full:std_logic;

begin
if RESET='1' or RESET2='0' then
COUNT <= (others => '0');
cnt:= (others => '0'); -- occur instantly.
FULL <= '0';
temp_full:= '0'; -- occur instantly.

elsif CLK='1' and CLK'event and temp_full='0' then -- rising edge
of clk!
cnt:=cnt+1; -- occur instantly.
COUNT<=cnt;
temp_full:=cnt(15); -- occur instantly.
FULL <= temp_full;
end if;
end process;

end Behavioral;

You're still waaaay too complicated. Why the variables? The clocked
process should contain the counter logic only. An assignment to FULL
can take place outside of the process. And don't confuse the
synthesizer by putting "AND temp_full" in the clock-edge condition. To
wit:

signal iCOUNT : unsigned(15 downto 0);

counter : process (CLK, RESET1, RESET2) is
begin
if (RESET1 = '1' or RESET2 = '0') then
iCOUNT <= (others => '0');
elsif rising_edge(CLK) then
if (iCOUNT(15) = '0') then -- if not full
iCOUNT <= iCOUNT + 1;
end if;
end if;
end process counter;

-- drive external signals:
COUNT <= iCOUNT;
FULL <= iCOUNT(15);

Does this make any sense?

-a
 
M

Mike Treseler

Andy said:
You're still waaaay too complicated. Why the variables? The clocked
process should contain the counter logic only.

In this simple example, the case for variables
may be weak, but I will take this opportunity
to demonstrate one way to do it for those
who are so inclined. I might point out, that
in a complex process, there are many more
local registers than there are ports, and
the advantages of a description using
variables becomes clearer.

-- Mike Treseler
---------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Wed Jul 27 12:07:42 2005 Mike Treseler
entity counter16bit is
port (
-- 16-bit synchronous counter,
clk : in std_ulogic;
reset1 : in std_ulogic;
reset2 : in std_ulogic;
full : out std_ulogic;
count : out std_logic_vector(15 downto 0)
);
end counter16bit;

architecture synth of counter16bit is
begin
process (clk, reset1, reset2) is
variable cnt_v : unsigned(15 downto 0);
variable full_v : std_logic;
begin
template: if (reset1 = '1' or reset2 = '0') then
-- init process registers
cnt_v := (count'range => '0');
full_v := '0';
elsif rising_edge(clk) then
-- lets make full mean full, not half full:
if cnt_v = (count'range => '1') then
full_v := '1';
else
full_v := '0';
cnt_v := cnt_v + 1;
end if;
end if template;

-- wire local regs to ports:
count <= std_logic_vector(cnt_v);
full <= full_v;
end process;
end architecture synth;
 

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,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top