I am writing a VHDL homework, which produces a strange behavior, which I do not understand.
The concept is the following. There should be an LFSR which is used to generate random numbers. The LFSR could be driven by I_CLK or by I_NEXT input. If the LFSR is driven by the I_CLK, it should automatically generate random numbers on its output, but if its driven by the I_NEXT input, it should generate number by changing the I_NEXT value manually from 0 to 1. I have a problem with the following code. If I comment out one of the processes, the LFSR works fine but if all the processes are enabled, it just do not work at all. Could you help me figure out the problem? I think it should be a design error, but I do not know what is wrong with my design.
entity LFSR_v2 is
Generic (
width : positive := 31;
tap_1 : positive := 30;
tap_2 : positive := 27
);
Port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
i_load : in std_logic;
i_direction : in std_logic;
o_number : out std_logic_vector (width -1 downto 0);
i_seed : in std_logic_vector (width -1 downto 0)
);
end LFSR_v2;
architecture Behavioral of LFSR_v2 is
signal internal_number : std_logic_vector(width -1 downto 0);
begin
-------------------------------------------------------------------------------------------
-- FREE RUNNING PROCESS
--
-- In Free Running mode the LFSR switches its state on every rising edge of the i_clk input.
-------------------------------------------------------------------------------------------
next_number_free_run : process(i_clk, i_reset)
--variable fileline : line;
--variable gen_num : integer;
begin
if rising_edge(i_clk) then
--------------------------------------
-- NORMAL MODE
-- enable = 1
-- reset = 0
--------------------------------------
if (i_enable = '1' and i_free_run = '1') then
-- Internal number to the output
o_number <= internal_number;
-----------------------------
-- RESET
-----------------------------
if(i_reset = '1') then
if(i_direction = '1') then
internal_number <= (OTHERS => '1');
else
internal_number <= (OTHERS => '0');
end if;
else
------------------------------
-- LOAD SEED
-- load = 1
------------------------------
if(i_load = '1') then
internal_number <= i_seed;
else
--------------------------------------
-- GENERATE NEXT NUMBER - FREE RUNNING
-- load = 0
-- free_run = 1
-------------------------------------
if(i_direction = '1') then
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
else
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
end if;
----------------------------------------
-- FILE LOGGING
----------------------------------------
--gen_num := to_integer(internal_number);
--write(fileline, gen_num);
--writeline(MyFile, fileline);
end if;
end if;
end if;
end if;
end process next_number_free_run;
---------------------------------------------------------------------------------
-- MANUAL RUNNING PROCESS
--
-- In this mode the LFSR does not use the input clock to generate the next number.
-- Number can be generated by creating a 0 -> 1 signal change on the i_next input.
---------------------------------------------------------------------------------
next_number_man_run : process(i_next, i_reset)
--variable fileline : line;
--variable gen_num : integer;
begin
if rising_edge(i_next) then
--------------------------------------
-- NORMAL MODE
-- enable = 1
-- reset = 0
--------------------------------------
if (i_enable = '1' and i_free_run = '0') then
-- Internal number to the output
o_number <= internal_number;
-----------------------------
-- RESET
-----------------------------
if(i_reset = '1') then
if(i_direction = '1') then
internal_number <= (OTHERS => '1');
else
internal_number <= (OTHERS => '0');
end if;
else
------------------------------
-- LOAD SEED
-- load = 1
------------------------------
if(i_load = '1') then
internal_number <= i_seed;
else
--------------------------------------
-- GENERATE NEXT NUMBER - FREE RUNNING
-- load = 0
-- free_run = 1
-------------------------------------
if(i_direction = '1') then
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
else
internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
end if;
----------------------------------------
-- FILE LOGGING
----------------------------------------
--gen_num := to_integer(internal_number);
--write(fileline, gen_num);
--writeline(MyFile, fileline);
end if;
end if;
end if;
end if;
end process next_number_man_run;
end Behavioral;
Test bench for the code:
----------------------------
-- TEST SEED INIT
----------------------------
-- ENABLE OFF -> SEED SHOULD NOT BE INITIALIZED
s_enable <= '0';
s_reset <= '0';
s_free_run <= '0';
s_load <= '1';
s_next <= '0';
s_direction <= '0';
s_seed <= (OTHERS => '1');
wait for 20 ns;
-- ENABLE ON -> SEED SHOULD BE INITIALIZED
s_enable <= '1';
s_reset <= '0';
s_next <= '0';
s_free_run <= '0';
s_load <= '1';
s_direction <= '0';
s_seed <= (OTHERS => '1');
wait for 20 ns;
-- DRIVE MANUAL
s_next <= '1';
wait for clk_period /2;
s_next <= '0';
wait for clk_period /2;
s_next <= '1';
wait for clk_period /2;
s_next <= '0';
wait for clk_period /2;
Instead of using a clock source multiplexer, you should use a synchronous clock-enable as also suggested by Brian.
When the clock enable is high, the LFSR counts up/down one step at the rising edge of the free-running clock i_clk. The definition is:
If i_free_run is high, then the clock enable is also high, i.e. counting always.
If i_free_run is low, then the clock enable is only high for one clock cycle of i_clk every time i_next has changed from low to high, i.e., single step with i_next.
As i_next is driven by a button, you must:
sample the button value with i_clk, i.e., make it synchronous to clock,
debounce the sampled button value. i_next is then the output of the debouncer.
I have applied this method to your code. To limit the code size, I have shortened the implementation to just one direction and no initialization with a seed. You have to put in your full implementation as indicated. Please note, that you have to initialize the LFSR with all zero when counting up with XNOR.
library ieee;
use ieee.std_logic_1164.all;
entity LFSR_v2 is
Generic (
width : positive := 31;
tap_1 : positive := 30;
tap_2 : positive := 27
);
Port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
-- i_load : in std_logic;
-- i_direction : in std_logic;
-- i_seed : in std_logic_vector (width -1 downto 0)
o_number : out std_logic_vector (width -1 downto 0)
);
end LFSR_v2;
architecture Behavioral of LFSR_v2 is
signal internal_number : std_logic_vector(width -1 downto 0);
signal clock_enable : std_logic;
signal next_old : std_logic := '0'; -- old value of "i_next"
begin
-- calculate clock enable
clock_enable <= '1' when i_free_run = '1' else
i_next and not next_old;
process(i_clk) -- no i_reset here!
begin
if rising_edge(i_clk) then
next_old <= i_next; -- save old value for edge detection
-- This should be outside of the clock-enable block or even a concurrent statement
o_number <= internal_number;
if (clock_enable = '1' and i_enable = '1') then -- "i_enable" as in original code
---------------------------------------------------------------
-- Replace the following short implementation with your full
-- implementation
---------------------------------------------------------------
if(i_reset = '1') then
internal_number <= (OTHERS => '0'); -- must be all zero for XNOR below!
else
internal_number <= internal_number(width - 2 downto 0) &
(internal_number(tap_1) xnor internal_number(tap_2));
end if;
end if;
end if;
end process;
end Behavioral;
This is my testbench:
library ieee;
use ieee.std_logic_1164.all;
entity LFSR_v2_tb is
end LFSR_v2_tb;
architecture sim of LFSR_v2_tb is
component LFSR_v2
generic (
width : positive;
tap_1 : positive;
tap_2 : positive);
port (
i_enable : in std_logic;
i_reset : in std_logic;
i_clk : in std_logic;
i_next : in std_logic;
i_free_run : in std_logic;
o_number : out std_logic_vector (width -1 downto 0));
end component;
-- component generics
constant width : positive := 31;
constant tap_1 : positive := 30;
constant tap_2 : positive := 27;
-- component ports
signal i_enable : std_logic;
signal i_reset : std_logic;
signal i_clk : std_logic := '1';
signal i_next : std_logic;
signal i_free_run : std_logic;
signal o_number : std_logic_vector (width -1 downto 0);
begin -- sim
DUT: LFSR_v2
generic map (
width => width,
tap_1 => tap_1,
tap_2 => tap_2)
port map (
i_enable => i_enable,
i_reset => i_reset,
i_clk => i_clk,
i_next => i_next,
i_free_run => i_free_run,
o_number => o_number);
-- clock generation
i_clk <= not i_clk after 10 ns;
-- waveform generation
WaveGen_Proc : process
begin
i_free_run <= '1'; -- start with a free-running clock
i_reset <= '1';
i_enable <= '1'; -- must be high even for reset
i_next <= '0';
wait until rising_edge(i_clk);
i_reset <= '0'; -- now let the LFSR toogle on i_clk
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
i_free_run <= '0'; -- change to single step mode
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
for i in 1 to 3 loop -- 3 single steps
i_next <= '1'; -- do single step
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
i_next <= '0';
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
wait until rising_edge(i_clk);
end loop; -- i
i_free_run <= '1'; -- change back to free-running clock
wait until rising_edge(i_clk);
wait;
end process WaveGen_Proc;
end sim;
And this is the simulation result. Please note, that the output signal changes rapidly at the "..." boxes.
You can not implement two different designs in one entity.
Use either:
two entities or
two different architectures of the same entity or
two if..generate statements and a generic parameter to switch the implementations.
Solutions 2 and 3 are not so good in your case, because one uses a clock and the other a next signal. One signal is always unused -> the port list of the entity is filled with dummy signals.
Related
i am new in the fpga filed ,
im trying to sample 2 inputs that rises with clock at the same time.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith;
use ieee.numeric_std.all;
ENTITY hold_threat IS
PORT (
pwr_gt_thresh : IN std_logic;
clk : IN std_logic;
reset : IN std_logic;
hw_seperation_bin_number : in std_logic_vector(12 downto 0);
fft_raw_index : in std_logic_vector (12 downto 0);
fft_data_valid : in std_logic;
threat_exists_buffered_pulse : out std_logic;
pwr_gt_thresh_out : out std_logic;
threat_end_index :out std_logic_vector (12 downto 0);
threat_start_index :out std_logic_vector (12 downto 0)
);
END hold_threat;
ARCHITECTURE behavoral OF hold_threat IS
signal s_threat_exists_buffered_pulse : std_logic;
signal s_pwr_gt_thresh_out : std_logic;
signal hw_seperation_bin_number_counter : integer range 0 to 8191;
signal s_fft_start_index : std_logic_vector (13 downto 0);
signal s_fft_end_index : std_logic_vector (12 downto 0);
signal s_new_count : std_logic;
begin
threat_start_index <= s_fft_start_index(12 downto 0);
threat_end_index <= s_fft_end_index;
threat_exists_buffered_pulse <= s_threat_exists_buffered_pulse;
pwr_gt_thresh_out <= s_pwr_gt_thresh_out;
process(reset, clk)
begin
if reset = '1' then
hw_seperation_bin_number_counter <= to_integer(unsigned(hw_seperation_bin_number)) -1 ;
s_threat_exists_buffered_pulse <= '0';
s_fft_start_index <="11" & X"FFF";
s_fft_end_index <= '1' & X"FFF";
s_new_count <= '0' ;
elsif rising_edge(clk) then
if(fft_data_valid = '1') then
if (pwr_gt_thresh = '1' ) then
hw_seperation_bin_number_counter <= to_integer(unsigned(hw_seperation_bin_number)) -1;
s_new_count <='1';
s_threat_exists_buffered_pulse <= '1';
if(s_fft_start_index(13) = '1' ) then
s_fft_start_index<= '0'& fft_raw_index;
else
s_fft_start_index<= s_fft_start_index;
end if;
else
if( hw_seperation_bin_number_counter = 0 ) and s_new_count ='1'then
s_threat_exists_buffered_pulse <= '0';
s_fft_end_index<= fft_raw_index;
s_new_count <= '0';
elsif (s_new_count ='1') then
hw_seperation_bin_number_counter <= hw_seperation_bin_number_counter - 1;
s_threat_exists_buffered_pulse <= '1';
end if;
end if;
else -- clock , no data valid
s_threat_exists_buffered_pulse <= s_threat_exists_buffered_pulse;
if (s_new_count = '0') then
hw_seperation_bin_number_counter <= to_integer(unsigned(hw_seperation_bin_number)) -1 ;
s_fft_start_index <="11" & X"FFF";
s_fft_end_index <= '1' & X"FFF";
else
hw_seperation_bin_number_counter <= hw_seperation_bin_number_counter;
s_fft_start_index <=s_fft_start_index;
s_fft_end_index <= s_fft_end_index;
end if;
end if;
end if;
end process;
END ARCHITECTURE behavoral;
in the simulation the clock ,pwr_gt_thresh , fft_data_valid rise together at the same time but the condition
elsif rising_edge(clk) then
if(fft_data_valid = '1') then
if (pwr_gt_thresh = '1' ) then
is never true .
if i change the simulation so that the data rise before the clock everything works good
why the data and the clock cannot rise together ?
Disclaimer: For more complete details you might want to do some research on "setup time" for clocked logic. And while you're at it, keep reading on "hold time".
In just three sentences:
The signal on a sampled data line needs to fulfill some timing requirements to be "caught" correctly. The time before the clock edge is the setup time. The time the signal has to be stable is the hold time.
Something to think about for fun:
You will come across values of real hardware that specify negative setup times. Was does this mean?
I'm making a custom hardware ARINC 429 Core.
For now I have described the module in transmission (TX-FSM), according to the ARINC 429 standard and a FIFO in transmission from which it takes the data and sends them to the outside.
The FIFO works at a frequency of 2MHz (clk2M), while TX-FSM can generate a frequency of 100kb / s or 12.5kb / s (clk429) from 2MHz as per standard.
Since the FIFO works at a higher frequency (2 MHz), and the TX-FSM works at a lower frequency (100 kb/s), when the TX-FSM requests a data from the FIFO by raising the "TX_FIFO_rd" signal ("rd_en" on FIFO ), the FIFO supplies all the data contained within it, since in the FIFO clock domain the "rd_en" signal remains high for several cycles.
The FIFO should only provide one data at a time. Once the data has been transmitted, the TX-FSM will request the next data.
How can I make the FIFO and TX-FSM work in sync using a single clock?
FIFO VHDL code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FIFO is
generic (
FIFO_WIDTH : natural := 32;
FIFO_DEPTH : integer := 10;
ALMOST_FULL_LEVEL : integer := 8;
ALMOST_EMPTY_LEVEL : integer := 2
);
port (
reset : in std_logic;
clk : in std_logic;
-- FIFO Write Interface
wr_en : in std_logic;
wr_data : in std_logic_vector(FIFO_WIDTH-1 downto 0);
ALMOST_FULL : out std_logic;
FULL : out std_logic;
-- FIFO Read Interface
rd_en : in std_logic;
rd_data : out std_logic_vector(FIFO_WIDTH-1 downto 0);
ALMOST_EMPTY : out std_logic;
EMPTY : out std_logic
);
end FIFO;
architecture rtl of FIFO is
type t_FIFO_DATA is array (0 to FIFO_DEPTH) of std_logic_vector(FIFO_WIDTH-1 downto 0);
signal r_FIFO_DATA : t_FIFO_DATA := (others => (others => '0'));
signal r_WR_INDEX : integer range 0 to FIFO_DEPTH -1 := 0;
signal r_RD_INDEX : integer range 0 to FIFO_DEPTH -1 := 0;
-- # Words in FIFO, has extra range to allow for assert conditions
signal r_FIFO_COUNT : integer range -1 to FIFO_DEPTH+1 := 0;
signal w_FULL : std_logic;
signal w_EMPTY : std_logic;
begin
-- FIFO process
-------------------------------------------------------------------
-------------------------------------------------------------------
WRITE_INDEX : process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
r_WR_INDEX <= 1;
else
if (wr_en = '1' and w_FULL = '0') then
if r_WR_INDEX = FIFO_DEPTH-1 then
r_WR_INDEX <= 1;
else
r_WR_INDEX <= r_WR_INDEX + 1;
end if;
end if;
end if;
end if;
end process;
READ_INDEX : process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
r_RD_INDEX <= 0;
else
if (rd_en = '1' and w_EMPTY = '0') then
if r_RD_INDEX = FIFO_DEPTH-1 then
r_RD_INDEX <= 0;
else
r_RD_INDEX <= r_RD_INDEX + 1;
end if;
end if;
end if;
end if;
end process;
COUNT_INDEX : process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
r_FIFO_COUNT <= 0;
else
if (wr_en = '1' and rd_en = '0') then
r_FIFO_COUNT <= r_FIFO_COUNT + 1;
elsif (wr_en = '0' and rd_en = '1') then
if r_FIFO_COUNT > 0 then
r_FIFO_COUNT <= r_FIFO_COUNT - 1;
end if;
end if;
end if;
end if;
end process;
Write_Data : process (clk) is
begin
if rising_edge(clk) then
if wr_en = '1' then
r_FIFO_DATA(r_WR_INDEX) <= wr_data;
end if;
end if;
end process;
rd_data <= r_FIFO_DATA(r_RD_INDEX);
w_FULL <= '1' when r_FIFO_COUNT = FIFO_DEPTH else '0';
w_EMPTY <= '1' when r_FIFO_COUNT = 0 else '0';
ALMOST_FULL <= '1' when r_FIFO_COUNT > ALMOST_FULL_LEVEL else '0';
ALMOST_EMPTY <= '1' when r_FIFO_COUNT < ALMOST_EMPTY_LEVEL else '0';
FULL <= w_FULL;
EMPTY <= w_EMPTY;
end rtl;
TX-FSM code
-- Arinc 429 trasmitter interface
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Tx is
port
(
--INPUT
clk2M : in std_logic; -- clock signal
reset : in std_logic; -- reset signal
enable : in std_logic; -- enable signal
en_parity : in std_logic; -- enable parity bit
parity : in std_logic; -- odd/even parity
speed : in std_logic; -- speed 100kbps or 12.5kbps
gap : in std_logic; -- gap between two messages: 4 or 64 bit of gap
TX_FIFO_ep : in std_logic; -- TX FIFO EMPTY
a429TX_in : in std_logic_vector (31 downto 0); -- data in
--OUTPUT
a429TX_outA : out std_logic; -- positive out
a429TX_outB : out std_logic; -- negative out
TX_FIFO_rd : out std_logic -- TX FIFO READ
);
end entity;
architecture RTL_A429TX of Tx is
-- FSM state name
type state_type is (IDLE,START, PAR,TRANSMITTING,WAITING);
signal state : state_type;
-- FSM register
signal shift_reg : std_logic_vector (31 downto 0);
signal shift_counter : std_logic_vector (4 downto 0);
signal gap_counter : std_logic_vector (6 downto 0);
-- speed clock register
signal clk429 : std_logic;
signal clk429_counter : integer;
signal clk429_max_count : integer;
signal clk429_half_count : integer;
begin
-- speed clock process
-------------------------------------------------------------------
-------------------------------------------------------------------
-- select speed process
process (speed)
begin
if (speed = '1') then
clk429_max_count <= 19; -- 100kbs/s
clk429_half_count <= 10;
else
clk429_max_count <= 159; -- 12.5kbs/s
clk429_half_count <= 80;
end if;
end process;
-- clock429 generate speed process
process (clk2M, reset)
begin
if (reset = '1') then
clk429 <= '0';
elsif rising_edge(clk2M) then
if (clk429_counter <= clk429_half_count ) then
clk429 <= '1';
else
clk429 <= '0';
end if;
end if;
end process;
-- counter activity process
process (clk2M, reset)
begin
if (reset = '1') then
clk429_counter <= 0;
elsif rising_edge(clk2M) then
if (clk429_counter >= clk429_max_count) then
clk429_counter <= 0;
else
clk429_counter <= clk429_counter + 1;
end if;
end if;
end process;
-------------------------------------------------------------------
-------------------------------------------------------------------
-- a429TX interface process
process (clk429, reset)
variable p : std_logic;
begin
if reset = '1' then
state <= IDLE;
shift_reg <= (others => '0');
shift_counter <= (others => '0');
gap_counter <= (others => '0');
a429TX_outA <= '0';
a429TX_outB <= '0';
TX_FIFO_rd <= '0';
elsif rising_edge(clk429) then
case state is
when IDLE => -- idle state
if (enable = '1') then
if (gap = '1') then
gap_counter <= "0000100"; -- 4
else
gap_counter <= "1000000"; -- 64
end if;
if TX_FIFO_ep = '0' then
TX_FIFO_rd <= '1';
state <= START;
else
state <= IDLE;
end if;
else
state <= IDLE;
end if;
when START =>
-- data formatting
TX_FIFO_rd <= '0';
shift_reg <= a429TX_in(31 downto 8)& a429TX_in(0) & a429TX_in(1) & a429TX_in(2) & a429TX_in(3) & a429TX_in(4) & a429TX_in(5) & a429TX_in(6) & a429TX_in(7);
shift_counter <= "11111";
if ( en_parity = '1') then
state <= PAR;
else
state <= TRANSMITTING;
end if;
when PAR => -- parity state
--TX_FIFO_rd <= '0';
p := '0';
for I in 31 downto 0 loop
p := p xor shift_reg(I);
end loop;
if (parity = '1') then
shift_reg(31) <= p; -- odd
else
shift_reg(31) <= not p; -- even
end if;
state <= TRANSMITTING;
when TRANSMITTING => -- transmission state
--TX_FIFO_rd <= '0';
a429TX_outA <= shift_reg(0);
a429TX_outB <= not shift_reg(0);
shift_reg <= shift_reg(0) & shift_reg(31 downto 1);
if (shift_counter = "00000") then
state <= WAITING;
else
shift_counter <= shift_counter -1;
state <= TRANSMITTING;
end if;
when WAITING => -- wait state. generate gap
a429TX_outA <= '0';
a429TX_outB <= '0';
if (gap_counter > 0) then
gap_counter <= gap_counter - 1;
state <= WAITING;
else
state <= IDLE;
end if;
when others => -- default
state <= IDLE;
end case;
elsif falling_edge (clk429) then
a429TX_outA <= '0';
a429TX_outB <= '0';
end if;
end process;
clk429 <= clk429;
end architecture;
Thanks for your help.
Run both FIFOs at the 2 MHz clk2M, and then generate a single cycle enable indication on TX_FIFO_rd when FIFO read data transfer is required.
Thereby you can get the benefit from synchronous design, without the hazzle of handling multiple clock domains.
Also, it is not good (but actually very bad :-) synchronous design practice to generate internal clock like the clk429, since it results in error prune design and more complex timing closure with Static Timing Analysis (STA). Instead make an enable signal that is asserted a single cycle, run the design on the clk2M, and the only update the relevant state when the enable signal is high.
I'm trying to create a ROM where a number of values is stored and, after receiving a clock pulse, one of its values is read and then sent to the output while the counter that keeps track of the current position in the ROM is increased by 1. The problem that i found is that the ROM value is not retrieved as it should be in the first clock event.
Entity code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity memoria is
Port ( clock, reset :in STD_LOGIC;
valor : out STD_LOGIC_VECTOR(7 downto 0);
vazia : out STD_LOGIC);
end memoria;
architecture Behavioral of memoria is
type ROM is array (0 to 4) of STD_LOGIC_VECTOR(7 downto 0); --Read only memory
constant mem : ROM := (b"00000000", b"00000001", b"00000010", b"00000011", b"11111111"); --"11111111" is the stop value
signal mem_value : STD_LOGIC_VECTOR(7 downto 0);
begin
process(clock, reset)
variable counter : integer := 0;
begin
if reset = '1' then
valor <= "11111111";
vazia <= '1';
elsif clock'event and clock = '1' then
mem_value <= mem(counter); --gets the current memory value
if mem_value = "11111111" then --checks if the value read is the stop one
vazia <= '1';
else
vazia <= '0';
end if;
valor <= mem_value; --sends the memory value read to the output
if counter < 4 then
counter := counter + 1; --increases counter by one
end if;
else
valor <= "11111111";
vazia <= '0';
end if;
end process;
end Behavioral;
Test Bench
ENTITY memoria_tb IS
END memoria_tb;
ARCHITECTURE behavior OF memoria_tb IS
--Inputs
signal clock : std_logic;-- := '0';
signal reset : std_logic := '0';
--Outputs
signal valor : std_logic_vector(7 downto 0);
signal vazia : std_logic;
-- Clock period definitions
constant clock_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: entity work.memoria PORT MAP (
clock => clock,
reset => reset,
valor => valor,
vazia => vazia
);
-- Clock process definitions
clock_process :process
begin
clock <= '0';
wait for clock_period/2;
clock <= '1';
wait for clock_period/2;
end process;
END;
Image of the error
I would like to know how to get the first ROM value in the first clock pulse instead of UUUUUUUU. Thanks for the help.
The problem was that the outputs should always be assigned after the process as noted in this post https://forums.xilinx.com/t5/General-Technical-Discussion/Counter-implementation-in-vhdl/td-p/570433.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity memoria is
Port ( clock, reset :in STD_LOGIC;
valor : out STD_LOGIC_VECTOR(7 downto 0);
vazia : out STD_LOGIC);
end memoria;
architecture Behavioral of memoria is
type ROM is array (0 to 4) of STD_LOGIC_VECTOR(7 downto 0); --Read only memory
constant mem : ROM := (b"00000000", b"00000001", b"00000010", b"00000011", b"11111111"); --"11111111" is the stop value
signal mem_value : STD_LOGIC_VECTOR(7 downto 0);
signal empty : STD_LOGIC;
begin
process(clock, reset)
variable counter : integer := 0;
begin
if reset = '1' then
mem_value <= "11111111";
empty <= '1';
elsif clock'event and clock = '1' then
mem_value <= mem(counter); --gets the current memory value
if mem_value = "11111111" then --checks if the value read is the stop one
empty <= '1';
else
empty <= '0';
end if;
if counter < 4 then
counter := counter + 1; --increases counter by one
end if;
else
mem_value <= "11111111";
empty <= '0';
end if;
end process;
valor <= mem_value; --sends the memory value read to the output
vazia <= empty;
end Behavioral;
I have a simple VHDL design and test bench that does not produce the expected output. ISim shows 'U' for all the outputs until the 'running' state is achieved (myState='1'). Then they show 0 and X values. The first PROCESS block should set all outputs to '0' when ENABLE is '0'. The test bench toggles ENABLE 0-1-0 to insure an event triggers the process, but the outputs stay at 'U'. Is the problem in the design, the test, or both?
VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity TestHarness1 is
port (
ADAT_WDCLK : in std_logic;
ADAT_BCLK: in std_logic;
ADAT_OUT12: in std_logic;
ENABLE: in std_logic;
PCM_FS : out std_logic;
PCM_CLK : out std_logic;
PCM_DIN : out std_logic
);
end TestHarness1;
architecture Behavioral of TestHarness1 is
--type state is (STOPPED, RUNNING);
signal tmp : std_logic;
signal myState : std_logic;
begin
PCM_DIN <= tmp;
-- State management process
process (ENABLE, ADAT_WDCLK) begin -- Eval on input changes
if (ENABLE = '0') then
myState <= '0'; --STOPPED;
PCM_FS <= '0'; -- All outputs muted
PCM_CLK <= '0';
tmp <= '0';
else
if (myState = '0' and rising_edge(ADAT_WDCLK)) then
-- Move to running state only at start of a frame
myState <= '1'; --RUNNING;
end if;
end if;
end process;
-- Output process
process (ADAT_WDCLK, ADAT_BCLK, myState) variable counter: integer := 0; begin
-- Only do something if we are in running state, process above
-- sets outputs when stopped.
if (myState = '1') then
-- Pass the clocks through, inverting the bit clock
PCM_FS <= ADAT_WDCLK;
PCM_CLK <= not ADAT_BCLK;
-- Generate fixed bit pattern data '11000101'
if rising_edge(ADAT_WDCLK) then
-- This would happen naturally since there are 4 bytes per word clock
counter := 0;
end if;
if falling_edge(ADAT_WDCLK) then
-- This would happen naturally since there are 4 bytes per word clock
counter := 0;
end if;
if rising_edge(ADAT_BCLK) then -- Change data state only on falling edge of output PCM_CLK
if counter = 0 or counter = 1 or counter = 5 or counter = 7 then
tmp <= '1';
else
tmp <= '0';
end if;
if (counter = 7) then
counter := 0; -- Reset counter
else
counter := counter + 1; -- Just inc counter
end if;
end if;
end if;
end process;
end Behavioral;
Test Bench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY TH1TestBench3 IS
END TH1TestBench3;
ARCHITECTURE behavior OF TH1TestBench3 IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT TestHarness1
PORT(
ADAT_WDCLK : IN std_logic;
ADAT_BCLK : IN std_logic;
ADAT_OUT12 : IN std_logic;
ENABLE : IN std_logic;
PCM_FS : OUT std_logic;
PCM_CLK : OUT std_logic;
PCM_DIN : OUT std_logic
);
END COMPONENT;
--Inputs
signal ADAT_WDCLK : std_logic := '0';
signal ADAT_BCLK : std_logic := '0';
signal ADAT_OUT12 : std_logic := '0';
signal ENABLE : std_logic := '0';
--Outputs
signal PCM_FS : std_logic;
signal PCM_CLK : std_logic;
signal PCM_DIN : std_logic;
-- Clock period definitions. Note WDCLK is defined in terms of the bit clock
-- to insure they are exactly in sync.
constant ADAT_BCLK_period : time := 326 ns; -- About 3.072MHz (https://www.sensorsone.com/frequency-to-period-calculator/)
constant ADAT_WDCLK_period : time := ADAT_BCLK_period * 64; -- 48KHz
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: TestHarness1 PORT MAP (
ADAT_WDCLK => ADAT_WDCLK,
ADAT_BCLK => ADAT_BCLK,
ADAT_OUT12 => ADAT_OUT12,
ENABLE => ENABLE,
PCM_FS => PCM_FS,
PCM_CLK => PCM_CLK,
PCM_DIN => PCM_DIN
);
-- Clock process definitions
ADAT_WDCLK_process :process
begin
ADAT_WDCLK <= '0';
wait for ADAT_WDCLK_period/2;
ADAT_WDCLK <= '1';
wait for ADAT_WDCLK_period/2;
end process;
ADAT_BCLK_process :process
begin
ADAT_BCLK <= '1';
wait for ADAT_BCLK_period/2;
ADAT_BCLK <= '0';
wait for ADAT_BCLK_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
ENABLE <= '1';
wait for 100 ns;
ENABLE <= '0';
wait for 7500 ns;
ENABLE <= '1';
wait for ADAT_WDCLK_period*10;
-- insert stimulus here
wait;
end process;
END;
ISim shows the ENABLE pulse early in the simulation, but the outputs remain 'U' until the rising edge of the WCLK with ENABLE=1. Then they start to change (as designed) but they show some X values.
Modified VHDL
For reference, here is the modified VHDL that resolves the problem of U's and X's in the simulation output. However, there is a functional problem with the PCM_DIN output... seems like it is delayed one (BCLK) cycle. I expected it to be '1' as soon as ADAT_WDCLK goes high the first time after ENABLE. But it does not go to '1' until a BLCK cycle later.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity TestHarness1 is
port (
ADAT_WDCLK : in std_logic;
ADAT_BCLK: in std_logic;
ADAT_OUT12: in std_logic;
ENABLE: in std_logic;
PCM_FS : out std_logic;
PCM_CLK : out std_logic;
PCM_DIN : out std_logic
);
end TestHarness1;
architecture Behavioral of TestHarness1 is
--type state is (STOPPED, RUNNING);
signal tmp : std_logic;
signal myState : std_logic;
begin
PCM_DIN <= tmp;
-- State management process
process (ENABLE, ADAT_WDCLK) begin -- Eval on input changes
if (ENABLE = '0') then
myState <= '0'; --STOPPED;
else
if (myState = '0' and rising_edge(ADAT_WDCLK)) then
-- Move to running state only at start of a frame
myState <= '1'; --RUNNING;
end if;
end if;
end process;
-- Output process
process (ADAT_WDCLK, ADAT_BCLK, myState) variable counter: integer := 0; begin
-- Only do something if we are in running state
if (myState = '0') then
PCM_FS <= '0'; -- All outputs muted
PCM_CLK <= '0';
tmp <= '0';
elsif (myState = '1') then
-- Pass the clocks through, inverting the bit clock
PCM_FS <= ADAT_WDCLK;
PCM_CLK <= not ADAT_BCLK;
if rising_edge(ADAT_BCLK) then -- Generate fixed serial bit pattern
if counter = 0 or counter = 1 or counter = 5 or counter = 7 then
tmp <= '1';
else
tmp <= '0';
end if;
if (counter = 7) then
counter := 0; -- Reset counter
else
counter := counter + 1; -- Just inc counter
end if;
end if;
end if;
end process;
end Behavioral;
ISim of the above (including the internal myState signal)... why is PCM_DIN delayed one BCLK cycle?
Regarding the 'X' (Forcing Unknown) values you are seeing:
You are driving the signals PCM_FS, PCM_CLK and tmp from multiple processes, which results in the simulator being unable to resolve the value being driven. You need to fix this such that they are only being driven from one process, or drive 'Z' when they are not in use.
Regarding the 'U' values, they exist because you have no initial values for the signals. Once you write the signals for the first time (after the enable), they will be assigned for the first time.
I am attempting to build a counter in VHDL. Eventual goal is to hook the "do_count" to a button. The total will be converted to BCD and displayed on a 7-segment display. Push the button, watch the numbers increment.
I'm using ModelSim and I can see the internal "counter_value" correctly increment by 1. But the output signal "total" becomes "000X" then "00X0" during my two test "do_count"s. Why am I getting an X'd signal?
I've moved the "output <= current_value" around inside the process, outside the process, inside the 'if's, etc. Still the "000X".
I've tried using a variable 'tmp' inside the process.
count_up : process(clk) is
variable tmp : unsigned (15 downto 0 );
begin
tmp := current_value;
-- snip
if do_count='1' then
current_value <= tmp + to_unsigned(1,16);
end if;
Still I get the "000X".
Full code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity d_counter is
port ( rst : in std_logic;
clk : in std_logic;
do_count : in std_logic;
total : out unsigned (15 downto 0)
);
end entity d_counter;
architecture counter_arch of d_counter is
signal current_value : unsigned (15 downto 0) := (others=>'0');
begin
count_up : process(clk) is
begin
if rst='1' then
current_value <= (others=>'0');
total <= (others=>'0');
elsif rising_edge(clk) then
if do_count='1' then
current_value <= current_value + to_unsigned(1,16);
end if;
end if;
end process count_up;
total <= current_value;
end architecture counter_arch;
Testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity test_counter is
begin
end entity test_counter;
architecture run_test_counter of test_counter is
signal t_rst : std_logic := '1';
signal t_clk : std_logic := '0';
signal t_do_count : std_logic;
signal t_total : unsigned( 15 downto 0 );
component d_counter is
port ( rst : in std_logic;
clk : in std_logic;
do_count : in std_logic;
total : out unsigned( 15 downto 0 )
);
end component d_counter;
begin
uut : d_counter
port map( rst => t_rst,
clk => t_clk,
do_count => t_do_count,
total => t_total );
clock : process is
begin
t_clk <= '0'; wait for 10 ns;
t_clk <= '1'; wait for 10 ns;
end process clock;
stimulus : process is
begin
t_rst <= '1';
t_do_count <= '0';
t_total <= (others =>'0');
wait for 15 ns;
t_rst <= '0';
wait for 10 ns;
t_do_count <= '1';
wait for 10 ns;
t_do_count <= '0';
wait for 10 ns;
t_do_count <= '1';
wait for 10 ns;
t_do_count <= '0';
wait for 10 ns;
wait;
end process stimulus;
end architecture run_test_counter;
Update 03-Oct-2012.
BOTH the answers helped. Moving "total <= current_value" inside the process (From #simon) and removing the extra "t_total <= (others =>'0');" (From #peter-bennett) in my testbench was required. I had to do both to get rid of the X's.
It looks like your mistake is in your testbench. The signal t_total is mapped to the total output of your counter component, yet you are writing to it with the t_total <= (others => '0') assignment. If you remove this I think your problem will go away.
uut : d_counter
port map( rst => t_rst,
clk => t_clk,
do_count => t_do_count,
total => t_total );
clock : process is
begin
t_clk <= '0'; wait for 10 ns;
t_clk <= '1'; wait for 10 ns;
end process clock;
stimulus : process is
begin
t_rst <= '1';
t_do_count <= '0';
t_total <= (others =>'0'); <-- Do not assign to t_total (its an output)
Your code write multi-driven with "total". You should delete assigment in process count_up.
count_up : process(clk) is
begin
if rst='1' then
current_value <= (others=>'0');
total <= (others=>'0'); --> Remove it
elsif rising_edge(clk) then
if do_count='1' then
current_value <= current_value + to_unsigned(1,16);
end if;
end if;
end process count_up;
total <= current_value; -- Keep it