Asynchrony in vhdl: SPI Slave - Low VIOLATION issue on post-route simulation - vhdl

I have implemented very simple SPI slave interface: 8 bit, MSB first, pol=1 pha=1. CS pin and 'Z' state of SO is not required. Max SPI SCK is 8 MHz. System clock 50 MHz
Code:
entity spi_slave_if is Port (
si : in STD_LOGIC;
sck : in STD_LOGIC;
so : out STD_LOGIC;
clk : in std_logic;
reset : in std_logic;
data_out : in std_logic_vector(7 downto 0); -- data for send
data_in : out std_logic_vector(7 downto 0); -- received data
transaction_done : out std_logic);
end spi_slave_if;
architecture Behavioral of spi_slave_if is
signal cur_bit, prev_bit: unsigned(2 downto 0);
begin
process(sck) begin
if falling_edge(sck) then
so <= data_out(to_integer(cur_bit));
end if;
end process;
process(sck, reset) begin
if (reset = '1') then
data_in <= (others => '0');
cur_bit <= to_unsigned(7, 3);
elsif rising_edge(sck) then
data_in(to_integer(cur_bit)) <= si;
cur_bit <= cur_bit - 1;
end if;
end process;
process(clk, reset)
variable td_raised: boolean;
begin
if reset = '1' then
prev_bit <= to_unsigned(7, 3);
td_raised := false;
transaction_done <= '0';
elsif falling_edge(clk) then
prev_bit <= cur_bit;
if td_raised then
transaction_done <= '0';
td_raised := false;
elsif (to_integer(prev_bit) = 0 and to_integer(cur_bit) = 7 ) then
transaction_done <= '1';
td_raised := true;
end if;
end if;
end process;
end Behavioral;
In testbench I try to model async master interface(with random data bytes) and random delays:
loop
UNIFORM(seed1, seed2, rand);
int_rand := INTEGER(TRUNC(rand*255.0)); -- rescale to 0..255
test_1_transact(125 ns, std_logic_vector(to_unsigned(int_rand, 8)));
wait for 1us; -- model async delay
wait for ((rand*0.00000001)*1 sec);
wait for ((rand*0.000000001)*1 sec);
wait for ((rand*0.0000000001)*1 sec);
end loop;
Where test_1_transact is:
procedure test_1_transact(constant prd : time; constant si_data &colon; std_logic_vector (7 downto 0)) is begin
data_out <= not si_data; --for back test invert dorward data
wait for 20ns; -- wait for data apply
FOR i IN 7 downto 0 LOOP
si <= si_data(i);
sck <= '0'; wait for prd / 2;
sck <= '1'; wait for prd / 2;
END LOOP;
end procedure;
When I do behevioral simulation code works fine all time.
But when I try to perform post route simulation, code also works first 47us, but then it failed, ISIM say me:
at 49422978 ps(3), Instance /test_spi_slv_if/uut/prev_bit_0/ : Warning: /X_FF HOLD Low VIOLATION ON I WITH RESPECT TO CLK;
Expected := 0.048 ns; Observed := 0.036 ns; At : 49422.978 ns
at 49922978 ps(3), Instance /test_spi_slv_if/uut/prev_bit_0/ : Warning: /X_FF HOLD Low VIOLATION ON I WITH RESPECT TO CLK;
Expected := 0.048 ns; Observed := 0.036 ns; At : 49922.978 ns
And on this moment transaction_done don't work.
Is there in vhdl some way to solve this?

Related

Different Clock Domain VHDL

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.

Unexpected value when reading ROM in the first clock pulse

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;

What is Simulator 45-1 Error in Xilinx Vivado?

I have been trying to make a generic sequence detector. When i try to simulate my design, I get a simulator 45-1 Fatal run time error. Can somebody please help me with this. Here is my Test bench and design.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Sequence_tb is
end Sequence_tb;
architecture Behavioral of Sequence_tb is
component sequence is
Generic(width: integer;
sequence: std_logic_vector);
Port(din,CLK,RST:in std_logic;
dout: out std_logic;
temp: buffer std_logic_vector(0 to width-1));
end component;
constant CLK_period: time := 10ns;
constant width: integer := 4;
constant sequence0: std_logic_vector(width-1 downto 0) := "1010";
signal din,CLK,RST,dout: std_logic := '0';
signal temp : std_logic_vector(0 to width-1) := (others=>'0');
begin
uut: sequence generic map(width=>width,sequence=>sequence0)
port map(din=>din,CLK=>CLK,RST=>RST,dout=>dout,temp=>temp);
CLK_proc: process
begin
CLK <= not CLK;
wait for CLK_period;
end process;
RST_proc: process
begin
RST <= '1';
wait for 20 ns;
RST <= '0';
wait;
end process;
din_proc: process
begin
din <= '1';
wait for 30 ns;
din <= '0';
wait for 10 ns;
din <= '1';
wait for 10 ns;
din <= '0';
wait for 10 ns;
din <= '1';
wait for 10 ns;
wait;
end process;
end Behavioral;
Design File:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Sequence is
Generic(width: integer;
sequence: std_logic_vector);
Port (din, CLK, rst: in std_logic;
dout: out std_logic;
temp: buffer std_logic_vector(0 to width-1));
end Sequence;
architecture Beh of Sequence is
subtype statetype is integer range 0 to width-1;
signal prstate,nxstate: statetype := 0;
begin
process(RST,CLK)
begin
if RST='1' then
temp <= (others => '0');
nxstate <= 0;
elsif CLK'event and CLK='1' then
temp(prstate) <= din;
for k in prstate downto 0 loop
if temp(k downto 0) = sequence(k downto 0) then
nxstate <= k;
exit;
else temp <= temp(1 to width-1) & '0';
end if;
end loop;
end if;
prstate <= nxstate;
end process;
dout <= '1' when prstate = width-1 and din = sequence(sequence'left) else '0';
end Beh;

Synthesizable wait statement in VHDL

I am writing a VHDL code to control AD7193 via SPI communication. ADC is controlled and configured via number of con-chip registers, DOUT/RDY (SPI_miso) goes low to indicate the completion of conversion. These are the code and timing characteristics (Please see Here) of AD7193.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity MainADC is port (
clk : in std_logic; -- OSC 50MHz
rst : in std_logic; -- Reset clock
sclk : out std_logic; -- out clock
cs : out std_logic; -- Chip select
spi_mosi: out std_logic; -- Write register
start : in std_logic; -- Start Conversion
spi_miso: in std_logic); -- Read register/Single channel, 24 bits
end MainADC;
architecture Behavior of MainADC is
signal outclk : std_logic;
signal clk_sel : std_logic; -- Clock Control
signal CommMode: std_logic_vector(7 downto 0) :="00001000"; -- Communications register==> next stage: Mode Register
signal Mode : std_logic_vector(23 downto 0) := "001010000000000001100000"; -- Single conversion mode
signal CommRead: std_logic_vector(7 downto 0) := "01011000"; -- Communications register==> next stage: Read Data
begin
cs <= '0'; -- Hardwired low
process(clk, rst) -- Clock_gen 500KHz
variable cnt : integer range 0 to 500 :=1;
begin
if (rst='1') then
cnt := 0;
outclk <= '0';
elsif (clk = '1' and clk'event) then
cnt := cnt + 1;
if (cnt = 50) then
cnt := 0;
outclk <= not outclk;
end if;
end if;
end process;
process(clk_sel)
begin
if (clk_sel='0') then
sclk <= '1'; --Clock Idle High
else
sclk <= outclk; --Provide Clock Cycles
end if;
end process;
process (outclk) -- SPI Comm
variable i : integer :=0;
variable data_temp: std_logic_vector(23 downto 0) :=(others=>'0');
begin
if (start = '0') then
clk_sel <= '0';
i:=0;
else
if falling_edge(outclk) then
i:=i+1;
if (i>=0 and i<=7) then -- Communications register==> next stage: Mode Register (8 bits)
clk_sel <= '1';
CommMode(7 downto 1) <= CommMode(6 downto 0);
CommMode(0) <= CommMode(7);
spi_mosi <= CommMode(7);
elsif (i=8) then
clk_sel <= '0'; --Clock Idle High
elsif (i>=9 and i<=32) then -- Single conversion mode (24 bits)
clk_sel <= '1';
Mode(23 downto 1) <= Mode(22 downto 0);
Mode(0) <= Mode(23);
spi_mosi <= Mode(23);
elsif (i=33) then
clk_sel <= '0'; --Clock Idle High
wait until (spi_miso'event and spi_miso='0'); --Wait for Ready Read Signal (DOUT/DRY)
elsif (i>=34 and i<= 41) then -- Communications register==> next stage: Read Data
clk_sel <= '1';
CommRead(7 downto 1) <= CommRead(6 downto 0);
CommRead(0) <= CommRead(7);
spi_mosi <= CommRead(7);
elsif (i=42) then
clk_sel <= '0'; --Clock Idle High
elsif (i>=43 and i<= 66) then
clk_sel <= '1';
data_temp(23 downto 0) := data_temp(22 downto 0) & spi_miso; --Read Data
elsif (i>=66 and i<=566) then -- Waiting for ADC Power Up after Conversion (~1ms)
clk_sel <= '0'; --Clock Idle High
elsif (i=567) then
i:=0;
end if;
end if;
end if;
end process;
end Behavior;
As far as I know Wait Until statement supports for vhdl synthesis, but I received this error: "Error (10441): VHDL Process Statement error at Main ADC.vhd(53): Process Statement cannot contain both a sensitivity list and a Wait Statement". How can I solve this error? Is there any other way to hold counter and waiting for DOUT/RDY event to know when conversion is complete for read data? Any opinions are appreciated! Thank you.
The error message is due to a VHDL language semantic restriction.
The wait until implies you're using spi_miso as a clock, and it looks like you're requiring a flip flop to toggle as a result of i counter reaching 33, before progressing to 34.
The error about the sensititvity list item (outclock) and the wait statement is telling you you can't use two different clocks in this process.
If there is no metastability issue with outclk, instead of waiting don't increment i unless spio_miso = 0 when i = 33. You could also evaluate i before incrementing it (the equivalent of making i a signal).
This may deserve simulation before synthesis. There may be other issues lurking in there.
Your VHDL analyzes with a couple of changes:
if falling_edge(outclk) then
if ( i /= 33 or spi_miso = '0' ) then
i:= i + 1;
end if;
if (i>=0 and i<=7) then -- Communications register==> next stage: Mode Register (8 bits)
clk_sel <= '1';
CommMode(7 downto 1) <= CommMode(6 downto 0);
CommMode(0) <= CommMode(7);
spi_mosi <= CommMode(7);
elsif (i=8) then
clk_sel <= '0'; --Clock Idle High
elsif (i>=9 and i<=32) then -- Single conversion mode (24 bits)
clk_sel <= '1';
Mode(23 downto 1) <= Mode(22 downto 0);
Mode(0) <= Mode(23);
spi_mosi <= Mode(23);
-- elsif (i=33) then
-- clk_sel <= '0'; --Clock Idle High
-- wait until (spi_miso'event and spi_miso='0'); --Wait for Ready Read Signal (DOUT/DRY)
elsif (i>=34 and i<= 41) then -- Communications register==>
(And I normally wouldn't put parentheses around an if statement expression.)

VHDL Counter result giving X

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

Resources