Generating second counter in VHDL - timer

I am new to VHDL and trying to generate 1 second counter. For simplicity, I am using the clock frequency of 10 Hz. For this purpose I am using a clk as an input and LED as an output. My VHDL code is given below:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
entity tick_counter is
generic(FrequencyHz : integer := 10);
Port ( clk : in STD_LOGIC;
led : out STD_LOGIC);
end tick_counter;
architecture Behavioral of tick_counter is
signal tick :integer;
signal counter :integer;
begin
process(clk, tick, counter)
begin
if rising_edge(clk) then
if tick = FrequencyHz - 1 then
tick <= 0;
counter <= counter + 1;
else
tick <= tick + 1;
end if;
end if;
end process;
led <= '1' when counter = 3 else '0';
end Behavioral;
I tried to write the code in such a way so that, when three seconds pass, the LED turns ON. My test bench code is given below:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY tick_counter_tb IS
END tick_counter_tb;
ARCHITECTURE behavior OF tick_counter_tb IS
-- Component Declaration for the Unit Under Test (UUT)
-- We're slowing down the clock to speed up simulation time
constant FrequencyHz : integer := 10; -- 10 Hz
constant clk_period : time := 1000 ms / FrequencyHz;
COMPONENT tick_counter
PORT( clk : IN std_logic;
led : OUT std_logic);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
--Outputs
signal led : std_logic;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut : entity work.tick_counter
generic map(FrequencyHz => FrequencyHz)
PORT MAP (clk => clk,
led => led);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait until rising_edge(clk);
-- insert stimulus here
wait;
end process;
END;
But in the simulation result, I am just seeing a blank diagram as shown below (link given):
I don't understand where I am making a mistake. Any help would be highly appreciated.

The default initial value of an integer is INTEGER'LOW (a very negative number).
That means counter won't become 3 for a very long time (as the busybee indicated).
You can constrain and/or provide an initial value for tick. counter appears to be meant as a modulo counter range 0 to 3. It's modulus could be passed identically to tick which uses FrequencyHZ. Also note that any integer counter needs explicit roll over, it's an error if the result of an addition doesn't fall with the range INTEGER'LOW to INTEGER'HIGH or the constrained range.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- USE ieee.std_logic_unsigned.ALL;
-- use ieee.numeric_std.all;
entity tick_counter is
generic(FrequencyHz : integer := 10);
Port ( clk : in STD_LOGIC;
led : out STD_LOGIC);
end tick_counter;
architecture Behavioral of tick_counter is
-- Initial value of integers is INTEGER'LOW (a large negative number)
signal tick: integer range 0 to FrequencyHz - 1 := 0;
signal counter: integer := 0; -- ADDED default initial value
begin
process(clk, tick, counter)
begin
if rising_edge(clk) then
if tick = FrequencyHz - 1 then
tick <= 0;
if counter = 3 then -- ADDED MODULUS 4 test for counter
counter <= 0;
else
counter <= counter + 1;
end if;
else
tick <= tick + 1;
end if;
end if;
end process;
led <= '1' when counter = 3 else '0';
end Behavioral;
With the changes the simulation will cause led to be a '1' for one second every four seconds.

Related

Use generate statement to create 'n' array of registers in VHDL

I am converting an old AHDL code to VHDL, and I need to create 5 arrays of resisters using a generate statement. I've never used generate before, and after trying for a couple of hours I still can't find an answer for my problem. My initial approach was to use a 18 bit input array, and a 18 bit output array, but I know that that's not the way to do it.
This is the code I have right now:
entity setup_comp_reg is
generic(
NUM_ID: integer := 18
);
port (
clk: in std_logic;
D: in std_logic_vector(17 downto 0);
clrn: in std_logic;
ena: in std_logic;
Q: out std_logic_vector(17 downto 0)
);
end setup_comp_reg;
architecture rtl of setup_comp_reg is
begin
DFFE: process (clk, clrn, ena) -- 18 times, using generate
begin
if (clrn = '0') then
Q<= (others => '0');
elsif (rising_edge(clk)) then
if (ena = '1') then
Q<= D;
end if;
end if;
end process;
end rtl;
So, I already have the DFFE, but how to use generate to create 5 arrays with 18 bits each?
The AHDL code is pretty self explanatory, it might help too:
for i in 17 to 0 generate
rg_bit_time[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adBT&iWR);
rg_sample_time[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adSP&iWR);
rg_low_sync[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adLS&iWR);
rg_hi_sync[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adHS&iWR);
end generate;
Thank you.
The AHDL generate statement represents four flip flops for each iteration of i.
AHDL generate statement:
for i in 17 to 0 generate
rg_bit_time[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adBT&iWR);
rg_sample_time[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adSP&iWR);
rg_low_sync[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adLS&iWR);
rg_hi_sync[i].(d, clk, clrn, ena) = (iDATA[i], clk, not reg_reset, adHS&iWR);
end generate;
AHDL uses a function prototype to represent primitives (here, DFFE). The return value would be the q output (and isn't mentioned in the AHDL generate statement). There are four assignments to names with function prototype associations. That represents four arrays of 18 flip flops.
The function prototype for the DFFE register is shown in the Altera Hardware Description Language (AHDL) Language Reference Manual, Section 3, Primitives, Flip Flop and latch Primitives, Table 3-9. MAX+PLUS II Flipflops & Latches:
Where the return value would be associated with the name (e.g. rg_bit_time[i]) in assignment statements in the AHDL generate statement.
In VHDL we'd do that by associating actuals with formals of a DFFE entity that would include the output.
A behavioral representation with ports for all the outputs and inputs would look something like:
library ieee; -- ADDED context clause
use ieee.std_logic_1164.all;
entity setup_comp_reg is
generic (
NUM_ID: integer := 18
);
port (
clk: in std_logic;
D: in std_logic_vector(NUM_ID - 1 downto 0);
clrn: in std_logic;
ena: in std_logic;
-- Q: out std_logic_vector(17 downto 0)
WR: in std_logic; -- ADDED
adBT: in std_logic; -- ADDED
adSP: in std_logic; -- ADDED
adLS: in std_logic; -- ADDED
adHS: in std_logic; -- ADDED
rg_bit_time: out std_logic_vector(NUM_ID - 1 downto 0); -- ADDED
rg_sample_time: out std_logic_vector(NUM_ID - 1 downto 0); -- ADDED
rg_low_sync: out std_logic_vector(NUM_ID - 1 downto 0); -- ADDED
rg_hi_sync: out std_logic_vector(NUM_ID - 1 downto 0) -- ADDED
);
end entity setup_comp_reg;
architecture rtl of setup_comp_reg is
-- For no -2008 dependency, ADD these:
signal adBTWR: std_logic;
signal adSPWR: std_logic;
signal adLSWR: std_logic;
signal adHSWR: std_logic;
begin
-- Write ENABLE conditions:
adBTWR <= adBT and WR;
adSPWR <= adSP and WR;
adLSWR <= adLS and WR;
adHSWR <= adHS and WR;
SETUP_REGS:
for i in NUM_ID - 1 downto 0 generate
BIT_TIME:
process (clk, clrn) -- enables not needed in sensitivity list
begin
if clrn = '0' then
rg_bit_time(i) <= '0';
elsif rising_edge (clk) then
if adBTWR = '1' then
rg_bit_time(i) <= D(i);
end if;
end if;
end process;
SAMPLE_TIME:
process (clk, clrn)
begin
if clrn = '0' then
rg_sample_time(i) <= '0';
elsif rising_edge (clk) then
if adSPWR = '1' then
rg_sample_time(i) <= D(i);
end if;
end if;
end process;
LOW_SYNC:
process (clk, clrn)
begin
if clrn = '0' then
rg_low_sync(i) <= '0';
elsif rising_edge (clk) then
if adLSWR = '1' then
rg_low_sync(i) <= D(i);
end if;
end if;
end process;
HI_SYNC:
process (clk, clrn)
begin
if clrn = '0' then
rg_hi_sync(i) <= '0';
elsif rising_edge (clk) then
if adHSWR = '1' then
rg_hi_sync(i) <= D(i);
end if;
end if;
end process;
end generate;
end architecture rtl;
You could associate individual flip flops from an entity (DFFE) but there's no need in a VHDL Register Transfer Logic (RTL) representation. In AHDL you'd have no choice, a named element would be a flip flop associated more than likely with a pin of a device.
You could also streamline the above description, it's written this way to show providence with the AHDL generate statement (without individual flip flops).
Using a generate statement with instantiated flip flops would elaborate to i number of nested block statements for the instantiation, the outer for the port map, the inner containing one or more processes implementing the flip flop for each of the four names. The above does that without instantiation (saving one block statement nesting level).
A description using loop statements instead of the generate statement would eliminate all the processes for individual flip flops and could be collapsed further by using assignment with a target that's an array object:
architecture rtl1 of setup_comp_reg is
-- For no -2008 dependency, ADD these:
signal adBTWR: std_logic;
signal adSPWR: std_logic;
signal adLSWR: std_logic;
signal adHSWR: std_logic;
begin
-- Write ENABLE conditions:
adBTWR <= adBT and WR;
adSPWR <= adSP and WR;
adLSWR <= adLS and WR;
adHSWR <= adHS and WR;
-- SETUP_REGS:
BIT_TIME:
process (clk, clrn) -- enables not needed in sensitivity list
begin
if clrn = '0' then
rg_bit_time <= (others => '0');
elsif rising_edge (clk) then
if adBTWR = '1' then
rg_bit_time <= D;
end if;
end if;
end process;
SAMPLE_TIME:
process (clk, clrn)
begin
if clrn = '0' then
rg_sample_time <= (others => '0');
elsif rising_edge (clk) then
if adSPWR = '1' then
rg_sample_time <= D;
end if;
end if;
end process;
LOW_SYNC:
process (clk, clrn)
begin
if clrn = '0' then
rg_low_sync <= (others => '0');
elsif rising_edge (clk) then
if adLSWR = '1' then
rg_low_sync <= D;
end if;
end if;
end process;
HI_SYNC:
process (clk, clrn)
begin
if clrn = '0' then
rg_hi_sync <= (others => '0');
elsif rising_edge (clk) then
if adHSWR = '1' then
rg_hi_sync <= D;
end if;
end if;
end process;
end architecture rtl1;
That's four process statements.
The canny ready will notice the code could be compacted further by using separate enables for the named register outputs:
architecture rtl2 of setup_comp_reg is
signal adBTWR: std_logic;
signal adSPWR: std_logic;
signal adLSWR: std_logic;
signal adHSWR: std_logic;
begin
-- Write ENABLE conditions:
adBTWR <= adBT and WR;
adSPWR <= adSP and WR;
adLSWR <= adLS and WR;
adHSWR <= adHS and WR;
BT_SP_LS_HS:
process (clk, clrn) -- enables not needed in sensitivity list
begin
if clrn = '0' then
rg_bit_time <= (others => '0');
rg_sample_time <= (others => '0');
rg_low_sync <= (others => '0');
rg_hi_sync <= (others => '0');
elsif rising_edge (clk) then
if adBTWR = '1' then
rg_bit_time <= D;
end if;
if adSPWR = '1' then
rg_sample_time <= D;
end if;
if adLSWR = '1' then
rg_low_sync <= D;
end if;
if adHSWR = '1' then
rg_hi_sync <= D;
end if;
end if;
end process;
end architecture rtl2;
Process statements are the unit of simulation in VHDL. The fewer there are the less execution overhead from suspension and resumption. The rtl2 example has one process statement. It works without having all the enables in the sensitivity list because they are 'sampled' on the clock rising edge. The authority for leaving the enables out comes from IEEE Std 1076.6-2004 (now withdrawn, RTL Synthesis) which describes syntax for and the required sensitivity list elements for edge sensitive sequential logic. Vendors typically provide examples of a subset of the sequential logic forms they will support and are guaranteed to comply with 1076.6.
The VHDL code above all analyzes.
(Looks like part of an IC tester.)

VHDL weird behavoir of an array of unsigneds

basically I have a array of unsigneds and a process that increments the first value of in the array by one. This worked fine untill I implemented an asynchronos reset, that sets the elements of the array to 0. The weird thing is, even when the code of the asynchronos reset is never reached, it makes the rest of my code not work anymore. Here is my code:
use work.datentyp.all;
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity vektoruhr is
port (
clk, reset : in std_logic ;
);
end vektoruhr;
architecture v1 of vektoruhr is
signal internal_stamp : vektor := (others => (others => '0'));
begin
process(clk)
begin
if(rising_edge(clk)) then
internal_stamp(0) <= internal_stamp(0) + 1;
end if;
end process;
process(reset)
begin
if(rising_edge(reset)) then
report "reset triggered";
-- internal_stamp <= (others => (others => '0'));
alarm <= '0';
end if;
end process;
end v1;
As you can see, the line
-- internal_stamp <= (others => (others => '0'));
is commented out. Like this, everything works fine. But if I delete the --, the value of the first element is 00 first, then gets changed to 0x after the first incrementation and to xx after the second one. After that it stay at xx. The reset input is set to '0' from the begining and is never changed.
VHDL is a hardware description language. Each process represents a piece of hardware. You are driving the signal internal_stamp from two processes.; you have a short circuit. When you comment out the line
internal_stamp <= (others => (others => '0'));
this results in internal_stamp being driven from only one process. Hence no short circuit and no 'X' values.
If you're coding sequential logic, you should stick to a template. Here is one such template for sequential logic with an asynchronous reset, which all synthesis tools should understand:
process(clock, async_reset) -- nothing else should go in the sensitivity list
begin
-- never put anything here
if async_reset ='1' then -- or '0' for an active low reset
-- set/reset the flip-flops here
-- ie drive the signals to their initial values
elsif rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
Here is a template for sequential logic without an asynchronous reset:
process(clock) -- nothing else should go in the sensitivity list
begin
if rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here (including the reset)
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
So, you should code your logic using one process, not two. Assuming you want an asynchronous reset:
process(clk, reset)
begin
if reset = '1' then
report "reset triggered";
internal_stamp <= (others => (others => '0'));
alarm <= '0';
elsif(rising_edge(clk)) then
internal_stamp(0) <= internal_stamp(0) + 1;
end if;
end process;
However, if you want a synchronous reset:
process(clk)
begin
if(rising_edge(clk)) then
if reset = '1' then
report "reset triggered";
internal_stamp <= (others => (others => '0'));
alarm <= '0';
else
internal_stamp(0) <= internal_stamp(0) + 1;
end if;
end process;

Determine Lengths of Columns in Matrix

I am to determine the length of each column in a 4x4 matrix. The lengths of each columns are counted from the bottom of each column upwards and are only counted from the initial '1' accessed onwards.
1110
0111
0110
0001
Column1=1, Column2=3, Column3=3, Column4=4 etc...
Does anyone have any ideas how I could do this? I have thus far attempted to produce a matrix alongside a function to extract each of the columns.
type col_mat is array (0 to 3) of std_logic;
type matrix is array (0 to 3, 0 to 3) of std_logic;
signal M: matrix;
signal temp_col : col_mat;
signal count : unsigned (1 downto 0):= "00";
function extract_col(x: matrix; column : integer) return col_mat is
variable ret: col_mat;
begin
for i in col_mat'range loop
ret(i) := x(i,column)
end loop;
return ret;
end function;
begin
if rising_edge(clk) then
temp_col<= extract_col(M, to_integer(count) );
count <= count+1;
end if;
end process;
You're describing a priority encoder and from the looks of it you're implying it operates in one clock, which can run into some clock rate limit based on the target device (assuming you'll synthesize).
A priority encode can be an if statement, a case statement, a loop statement with an exit (as Martin Zabel commented), describe one combinatorially with logic operators or with a conditional signal assignment.
For this particular use a loop statement is the most compact and one has been added to your process.
The following code is derived from your question, fleshed out into a Minimal, Complete, and Verifiable example.
The results are in terms of array type indexes (starting from 0).
I added a pipeline register for count named column as well as registers for a signal to specify a '1' was found (found_1) and the highest row value a '1' is found in (imaginatively named row):
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity column is
end entity;
architecture foo of column is
type col_mat is array (0 to 3) of std_logic;
type matrix is array (0 to 3, 0 to 3) of std_logic; -- (row,column)
-- signal M: matrix;
-- 1110
-- 0111
-- 0110
-- 0001
--
-- Column1=1, Column2=3, Column3=3, Column4=4 etc...
--
-- column0 = 0, column1 = 2 column2 = 2, column3 = 3
-- (matrix is defined so (0,0) is the upper left hand corner)
-- Looking for the highest column index occupied by a '1'
signal M: matrix := ( -- for demo provide matrix default value
('1','1','1','0'), -- row 0
('0','1','1','1'),
('0','1','1','0'),
('0','0','0','1') -- row 3
);
-- signal temp_col: col_mat;
signal count: unsigned (1 downto 0):= "00";
function extract_col(x: matrix; column: integer) return col_mat is
variable ret: col_mat;
begin
for i in col_mat'range loop
ret(i) := x(i,column); -- was missing semicolon
end loop;
return ret;
end function;
-- added signals:
signal clk: std_logic := '1'; -- rising_edge() requires 0 -> 1 trans
signal found_1: std_logic := '0';
signal column: unsigned (1 downto 0);
signal row: integer range 0 to 3;
signal mat_col: col_mat;
begin
UNLABELED:
process (clk)
variable temp_col: col_mat; -- made temp_col a variable, use immediately
begin
if rising_edge(clk) then
temp_col := extract_col(M, to_integer(count)); -- was signal
-- priority encoder: -- added loop
for i in temp_col'RIGHT downto temp_col'LEFT loop -- highest first
if temp_col(i) = '1' then
found_1 <= '1';
column <= count;
row <= i;
exit;
else
found_1 <= '0';
end if;
end loop;
mat_col <= temp_col; -- added
count <= count + 1;
end if;
end process;
CLOCK: -- Added clock process
process
begin
wait for 10 ns;
clk <= not clk;
if now > 90 ns then
wait;
end if;
end process;
end architecture;
And when simulated this gives:
I added mat_col because the tool I used doesn't do delta cycle waveforms and variables have no notion of time. temp_col was made a variable to allow it's value to be used in immediately after it's assigned (an updated signal value is not available in the current simulation cycle).
You can also see I provided a default value for M from your question.

For loops and rom in vhdl

I'm doing a musicbox with VHDL. I first played just A4 and I was successful.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
entity Basic is
Port( clk : in STD_LOGIC;
note : out STD_LOGIC;
);
end Basic;
architecture Behavioral of Basic is
signal count : unsigned (15 downto 0) := (others => '0');
begin
note <= std_logic(count(15));
process (clk)
begin
if rising_edge(clk) then
if (count=56817) then
count <= "0000000000000000";
else
count <= count + 1;
end if;
end if;
end process;
end Behavioral;
My unfinished code is like this
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
entity Basic is
Port( clk : in STD_LOGIC;
note : out STD_LOGIC;
address: in integer range 0 to 31
);
end Basic;
architecture Behavioral of Basic is
signal count : unsigned (15 downto 0) := (others => '0');
signal reg_address : integer range 0 to 31 ;
type rom_array is array (0 to 31) of integer (4 downto 0);
constant rom: rom_array := ( "11011", "11011",
"11011", "11011","11011", "11011",
"11011", "11011", "11011", "11011",
"11011", "11011","11011", "11011",
"11011", "11011","11011", "11011",
"11011", "11011","11011", "11011",
"11011", "11011","11011", "11011",
"11011", "11011","11011", "11011",
"11011", "11011");
begin
note <= std_logic(count(15));
process (clk)
begin
if rising_edge(clk) then
reg_address <= address;
if (reg_address < 32) then
if (count = rom(reg_address)) then
count <= "0000000000000000";
else
count <= count + 1;
end if;
else
reg_address <= "00000";
end if;
end if;
reg_address <= reg_address + 1;
end process;
end Behavioral;
the rom values are going to change.
I'm trying to generate a sound by dividing the clock. Like 25mhz/56818 = 440. To play a song I thought of creating a rom filled with numbers needed to divide the clock, then do a for loop and play the song. But I can't because for loop isn't similar to java/C so I think I need to bypass it.
My errors are:
ERROR:HDLParsers:526 - "C:/Users/user/DigitalProje/Basic.vhd" Line 18. Non array type integer can not have a index constraint.
ERROR:HDLParsers:3312 - "C:/Users/user/DigitalProje/Basic.vhd" Line 19. Undefined symbol 'rom_array'.
ERROR:HDLParsers:1209 - "C:/Users/user/DigitalProje/Basic.vhd" Line 19. rom_array: Undefined symbol (last report in this block)
ERROR:HDLParsers:3285 - "C:/Users/user/DigitalProje/Basic.vhd" Line 19. No array or record type can be found that has elements of types matching the aggregate.
ERROR:HDLParsers:532 - "C:/Users/user/DigitalProje/Basic.vhd" Line 19. Deferred constant are allowed only in packages.
ERROR:HDLParsers:808 - "C:/Users/user/DigitalProje/Basic.vhd" Line 35. = can not have such operands in this context.
ERROR:HDLParsers:800 - "C:/Users/user/DigitalProje/Basic.vhd" Line 41. Type of reg_address is incompatible with type of 00000.
VHDL is a strong-typed language, so you must be strict with the types.
Two issues, the rom_array is made with integer type elements, but it looks like the intention may have been to use unsigned (or another vector type) based on the constant assign to rom; so maybe do:
type rom_array is array (0 to 31) of unsigned (4 downto 0);
The reg_address is integer, thus it can't be assigned with string like in reg_address <= "00000";, so consider changing this to:
reg_address <= 0;

vhdl comparing vector output

I have a vector A that's 64bits long and I want the output B to equal 3 while A is 30-35 and zero elsewhere. I can't figure out the testbench to loop through the vector A as a bit. I've tried several different ways but only got 1/5 of the array to give any output at all. This is as far as I could get without syntax/compile errors.
Main code
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;
entity ent is
port(A:in std_logic_vector(5 downto 0);
B:out std_logic_vector(3 downto 0));
end ent;
architecture arch_ent of ent is
begin
with A select
B <= "0011" when "011110",
"0011" when "011111",
"0011" when "100000",
"0011" when "100001",
"0011" when "100010",
"0011" when "100011",
"0000" when others;
end arch_ent;
Testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb is
end tb;
architecture arch_tb of tb is
component ent
port(A:in std_logic_vector(5 downto 0);
B:out std_logic_vector(3 downto 0));
end component;
signal A_tb: std_logic_vector(5 downto 0);
signal B_tb: std_logic_vector(3 downto 0);
begin
uut: entity ent port map(A=>A_tb, B=>B_tb);
tb: process
constant period: time := 20ns;
begin
for i in A_tb'range loop
A_tb <= std_logic_vector(to_unsigned(i,6));
wait for period;
assert (B_tb = "0011")
report "test failed" severity error;
end loop;
wait;
end process;
end arch_tb;
In the end I'm trying to plot out the waveform like this:
http://i10.photobucket.com/albums/a142/blargonblop/wave.png
where A will go to 63 and each output is its correct value from 30-35 and 0 elsewhere
The loop parameter you use to specify the number of 'tests' is A_tb'range, which happens to be 5 downto 0, or six tests, i is assigned 5,4,3,2,1 and 0 successively.
You want to specify i in 0 to 2**A-tb'length-1 or i in 0 to 63 to get all 64 possible A_tb 'binary' values.
(A_tb'length = 6, 2**6-1 = 63, where ** is the exponentiation operator, 2 to the 6th power minus 1 equals 63)
I found two syntax errors in your test bench, 20ns where the standard requires a space between 20 and ns:
constant period: time := 20 ns;
And entity ent where that should either be just ent (you have a component declaration ent) or entity work.ent and no need for a component declaration:
uut: ent port map(A=>A_tb, B=>B_tb);
or
uut: entity work.ent port map(A=>A_tb, B=>B_tb);
And in keeping with Russell's answer there is no implied logic replication in a loop other than through synthesis which unravels loop iterations by paralleling logic (the replication). Not all loop statements are intended as synthesis targets.
Test benches are generally not synthesized and are used to write tests (as in your case) for a VHDL model that might be used as a synthesis target.
First, loops are just fine, and common, in testbenches. #Russell's comment applies to RTL code. You can adapt his approach for this problem and make it work. You would need to use 64 as a sentinel (ending) value and do your end of test checks then. Keep in mind though that the most important thing you do is code for readability. Test cases generally run from top to bottom of a process one time.
You loop has some issues in addition to the recommendations #DavidKoontz gave. Specifically,
Your assertion is should not be checked when you expect B to be 0.
Using numeric_std_unsigned (requires VHDL-2008 compile switch) will simplify your conversions.
Keep an error count so you can report pass or failed at the end.
Keep your constants in the architecture or a package
So the modified code is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
entity tb is
end tb;
architecture arch_tb of tb is
constant period: time := 20 ns;
...
begin
...
tb: process
variable ErrorCount :
begin
for i in i in 0 to 2**A-tb'length-1
A_tb <= to_slv(i,6);
wait for period;
if i >= 30 and i <= 35 then
if B_tb /= 3 then
ErrorCount := Error Count + 1 ;
report "B_tb = " & to_string(B_tb) & " Expecting: 0011" severity ERROR ;
end if;
else
if B_tb /= 0 then
ErrorCount := Error Count + 1 ;
report "B_tb = " & to_string(B_tb) & " Expecting: 0000" severity ERROR ;
end if;
end loop;
if ErrorCount = 0 then
report "Test Passed" severity NOTE ;
else
report "Test FAILED. There were " & to_string(ErrorCount) & " Errors " severity NOTE;
end if;
std.env.stop(0) ; -- testbench stops here
end process;
Note that the rules about using (or forbidding usage of) numeric_std_unsigned do not apply to testbenches.
You really should not be using a for loop for this. For loops in VHDL are used to REPLICATE LOGIC, not to do something some number of times. Try something like this in your test bench:
signal r_CLOCK : std_logic := '0';
signal r_INDEX : unsigned(5 downto 0) := (others => '0');
begin
r_CLOCK <= not r_CLOCK after period/2;
process (r_CLOCK)
begin
if rising_edge(r_CLOCK) then
r_INDEX <= r_INDEX + 1;
end if;
end process;
Now simply cast r_INDEX as std_logic_vector and pass it to your ent component.

Resources