VHDL simulation failed with unexpected result - vhdl

I learned VHDL 5 years back, and never used after that as I was working on different domain. Now I'm working in a project that required some work in VHDL. I have to implement SPI to program a ADF4158 device. I opened a book for syntax and tried to program. I need to develop the below module, I coded as per my understanding and also a test bench but it doesnot work in the simulation like I need. Below is the module I want to develop and the over all block diagram.
Block diagram of process and vhdl module (clickable):
The following is the SPI timing diagram as follows (clickable):
The below is the VHDL code I wrote to acheive the above SPI communication:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.all;
entity sender is
Generic( DATA_WIDTH : INTEGER := 32); --32 bit registers to pogram (total 8 registers to program)
Port ( sys_clk : in STD_LOGIC; --clock from microblaze (32 MHz)
enable : in STD_LOGIC; --from microblaze to trigger start
reset : in STD_LOGIC; --reset spi clk generation
start_data_read : out STD_LOGIC; --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to buffer
start_data_write : out STD_LOGIC; --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to mosi port
data_in : in STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --program data (32bit data in 8 phases depending on register_select)
process_done : out STD_LOGIC; --flag bit to microblaze when complete process is complete
register_select : in STD_LOGIC_VECTOR(2 downto 0); --select code to identify which register to grogram, theorder can be manupulated from microblaze
sclk : buffer STD_LOGIC; --spi clock for ADC (3.2 MHz)
ss : out STD_LOGIC := '1'; --select line for ADF (slave)
mosi : out STD_LOGIC); --program data for ADF
end sender;
architecture Behavioral of sender is
type machine is(store, sending); --states of state-machine
signal state : machine := store;
signal clk_divide: STD_LOGIC_VECTOR(5 downto 0); --clock cycle ratio between system clock from microblaze and spi clock for ADF
signal tx_buffer_0 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 0)
signal tx_buffer_1 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 1)
signal tx_buffer_2 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 2)
signal tx_buffer_3 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 3)
signal tx_buffer_4 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 4)
signal tx_buffer_5 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 5)
signal tx_buffer_6 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 6)
signal tx_buffer_7 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 7)
begin
ClK_GEN: process(sys_clk)
begin --spi sclk 20:1 cycles of sys_clk(system runs at 32 MHz and SPI CLK required is 1.6 MHz)
if rising_edge(sys_clk) then
if reset = '1' then
clk_divide <= (others => '0');
mosi <= 'Z'; --send high impedence
else
if clk_divide < "001010" then --10
sclk <= '0';
clk_divide <= clk_divide + 1;
else
if clk_divide < "010100" then --20
sclk <= '1';
else
clk_divide <= (others => '0');
end if;
end if;
end if;
end if;
end process ClK_GEN;
SEND: process(sclk,enable,register_select)
begin
if rising_edge(sclk) then
if enable = '1' then
case state is
when store =>
start_data_read <= '1'; --ask microblaze to send register_selectcodes and data
case register_select is
when "000" =>
tx_buffer_7 <= data_in; --copy data to buffer
when "001" =>
tx_buffer_6 <= data_in;
when "010" =>
tx_buffer_5 <= data_in;
when "011" =>
tx_buffer_4 <= data_in;
when "100" =>
tx_buffer_3 <= data_in;
when "101" =>
tx_buffer_2 <= data_in;
when "110" =>
tx_buffer_1 <= data_in;
when "111" =>
tx_buffer_0 <= data_in;
when others =>
tx_buffer_1 <= (OTHERS => '0');
end case;
state <= sending; --change state to next
when sending =>
start_data_write <= '1'; --ask microblaze to send register_select codes to pgrogram a register
case register_select is
when "000" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_7 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "001" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_6 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "010" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
ss <= '1';
when "011" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_4 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "100" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_3 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "101" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_2 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "110" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_1 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "111" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_0 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when others =>
mosi <= '0';
end case;
end case;
end if;
end if;
end process SEND;
end Behavioral;
I also wrote a test bench code to send the above module, belowis the code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test_sender IS
END test_sender;
ARCHITECTURE behavior OF test_sender IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT sender
PORT(
sys_clk : IN std_logic;
enable : IN std_logic;
reset : IN std_logic;
start_data_read : OUT std_logic;
start_data_write : OUT std_logic;
data_in : IN std_logic_vector(31 downto 0);
process_done : OUT std_logic;
register_select : IN std_logic_vector(2 downto 0);
sclk : buffer std_logic;
ss : OUT std_logic;
mosi : OUT std_logic
);
END COMPONENT;
--Inputs
signal sys_clk : std_logic := '0';
signal enable : std_logic := '0';
signal reset : std_logic := '0';
signal data_in : std_logic_vector(31 downto 0) := (others => '0');
signal register_select : std_logic_vector(2 downto 0) := (others => '0');
--Outputs
signal start_data_read : std_logic;
signal start_data_write : std_logic;
signal process_done : std_logic;
signal sclk : std_logic;
signal ss : std_logic;
signal mosi : std_logic;
-- Clock period definitions
constant clk_sys_period : time := 31.25 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: sender PORT MAP (
sys_clk => sys_clk,
enable => enable,
reset => reset,
start_data_read => start_data_read,
start_data_write => start_data_write,
data_in => data_in,
process_done => process_done,
register_select => register_select,
sclk => sclk,
ss => ss,
mosi => mosi
);
-- Clock process definitions
clk_sys_process :process
begin
sys_clk <= '0';
wait for clk_sys_period/2;
sys_clk <= '1';
wait for clk_sys_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 1ns;
enable <= '1';
if start_data_read = '1' then
wait for 1ns;
register_select <= "000";
wait for 1 ns;
data_in <= "01001111001101010101010111100001";
wait for 5 ns;
register_select <= "001";
wait for 1 ns;
data_in <= "11001111001101010111011111100101";
wait for 5 ns;
register_select <= "010";
wait for 1 ns;
data_in <= "00000011001101010101011101100101";
wait for 5 ns;
register_select <= "011";
wait for 1 ns;
data_in <= "00011111001101010101010011100101";
wait for 5 ns;
register_select <= "100";
wait for 1 ns;
data_in <= "10001111001101010101011111100001";
wait for 5 ns;
register_select <= "101";
wait for 1 ns;
data_in <= "11001111001101010101011110000101";
wait for 5 ns;
register_select <= "110";
wait for 1 ns;
data_in <= "00101000001101010101011111100101";
wait for 5 ns;
register_select <= "111";
wait for 1 ns;
data_in <= "11111111001101010101011110100101";
wait for 5 ns;
end if;
if start_data_write = '1' then
wait for 1ns;
register_select <= "000";
wait for 5 ns;
register_select <= "001";
wait for 5 ns;
register_select <= "010";
wait for 5 ns;
register_select <= "011";
wait for 5 ns;
register_select <= "100";
wait for 5 ns;
register_select <= "101";
wait for 5 ns;
register_select <= "110";
wait for 5 ns;
register_select <= "111";
wait for 5 ns;
end if;
-- insert stimulus here
wait;
end process;
END;
The simulation is not working properly, and so the code is wrong, but I can't find out where is the mistake, it would be great if some one can help me and make me understand my mistake.

Do you mean to do a data_read and data_write in this simulation? In RTL we can do a check like the following because we look many times (probably on an edge of clock):
if start_data_read = '1' then
However your testbench process does not loop. So instead of doing an "IF" the way we do in RTL code, you need to do something to cause your test to stop until that condition exists. So your test would be the following:
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 1ns;
enable <= '1';
if start_data_read /= '1' then
wait until start_data_read = '1' ;
end if ;
-- Do a read sequence
. . .
if start_data_write /= '1' then
wait until start_data_write = '1' ;
end if ;
-- Do a write sequence
Within your read and write sequence, you have "wait for 5 ns". Can your device really accept operations this quickly? This is faster than a clock cycle. Are the operations in any way aligned with clock? You can wait for clock cycles by doing either of the following:
wait until rising_edge(Clk) ;
wait until Clk = '1' ; -- assumes Clk is only '0' or '1' (safe for clocks)
Once you get the basics working, you might further consider encapsulating a single write or read operation into a subprogram.

Related

I2Cmaster with MPU6050 in VHDL not working

For my hobby project I try to make a quadcopter which balances itself with the MPU-6050. The flight controller shall be the FPGA Altera cyclone IV, because its fun. I'm coding it in VHDL.
Anyway I'm stuck on the I2C communication with the MPU-6050. As bases I used the I2C master VHDL code from: https://www.digikey.com/eewiki/pages/viewpage.action?pageId=10125324.
I try to read the gyro registers and print them out on 8 leds just to see if I have some communication coming in.
I have tried to run with a 1Hz prescaler all the I2C phases in the state machine and light up some leds just to see if all phases are run through. This is the case. I have assigned the pins 2.5V default, I use 10k pull up resistors. The MPU6050 works perferct on an arduino.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mpu6050_2 is
port( clk_50 : in std_logic;
areset : in std_logic;
i2c_SDA : INOUT STD_LOGIC;
i2c_SCL : INOUT STD_LOGIC;
leds : out std_LOGIC_VECTOR(7 downto 0)
);
end entity mpu6050_2;
architecture struc of mpu6050_2 is
component i2c_master is
GENERIC(
input_clk : INTEGER := 50_000_000;
bus_clk : INTEGER := 400_000);
PORT(
clk : IN STD_LOGIC;
reset_n : IN STD_LOGIC;
ena : IN STD_LOGIC;
addr : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
rw : IN STD_LOGIC;
data_wr : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
busy : OUT STD_LOGIC;
data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
ack_error : BUFFER STD_LOGIC;
sda : INOUT STD_LOGIC;
scl : INOUT STD_LOGIC);
end component ;
type machine is (config1, config2, gyroH, gyroL);
signal state : machine:= config1; --current state
signal SDA_int : std_LOGIC;
signal SCL_int : std_LOGIC;
signal i2c_ena : std_LOGIC;
signal i2c_busy : std_LOGIC;
signal busy_prev : std_LOGIC;
signal i2c_rw : std_LOGIC;
signal i2c_data_wr : STD_LOGIC_VECTOR(7 DOWNTO 0);
signal gyro_data : std_LOGIC_VECTOR(15 downto 0);
signal i2c_data_rd : std_LOGIC_VECTOR (7 downto 0);
signal i2c_addr : STD_LOGIC_VECTOR(6 DOWNTO 0);
begin
process(areset, clk_50)
VARIABLE busy_cnt : INTEGER := 0; --keeps track of i2c busy signals during transaction
begin
if areset = '0' then
busy_cnt := 0;
i2c_ena <= '0';
state <= config1;
elsif rising_edge(clk_50) then
case state is
when config1 =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"6B"; -- hex6B powermanagement
when 1 =>
i2c_rw <= '0'; --write
i2c_data_wr <= "00000000"; -- ON with internal clock
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
busy_cnt := 0;
state <= config2;
end if;
when others => NULL;
end case;
when config2 =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"1B"; -- Gyro config
when 1 =>
i2c_rw <= '0'; --write
i2c_data_wr <= "00000000"; -- 250 degree/sec, no self test
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
busy_cnt := 0;
state <= gyroH;
end if;
when others => NULL;
end case;
when gyroH =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"43"; -- hex43 GYRO_OUT[15:8]
when 1 =>
i2c_rw <= '1'; --read
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
gyro_data(15 downto 8) <= i2c_data_rd;
busy_cnt := 0;
state <= gyroL;
end if;
when others => NULL;
end case;
when gyroL =>
busy_prev <= i2c_busy;
if (busy_prev = '0' and i2c_busy = '1') then
busy_cnt := busy_cnt + 1;
end if;
case busy_cnt is
when 0 =>
i2c_ena <= '1';
i2c_addr <= "1101000"; --MPU6050 adress
i2c_rw <= '0'; --write
i2c_data_wr <= x"44"; -- hex44 GYRO_OUT[7:0]
when 1 =>
i2c_rw <= '1'; --read
when 2 =>
i2c_ena <= '0';
if(i2c_busy = '0') then
gyro_data(7 downto 0) <= i2c_data_rd;
busy_cnt := 0;
state <= gyroH;
end if;
when others => NULL;
end case;
end case;
end if;
end process;
u0: i2c_master
port map(clk => clk_50, reset_n => areset, ena => i2c_ena, addr => i2c_addr, rw => i2c_rw, data_wr => i2c_data_wr, busy => i2c_busy, data_rd => i2c_data_rd
, sda => SDA_int, scl => SCL_int);
leds(7) <= gyro_data(0); --D4
leds(6) <= gyro_data(1); -- D5
leds(5) <= gyro_data(4); -- D6
leds(4) <= gyro_data(7); -- D7
leds(3) <= gyro_data(8); -- D8
leds(2) <= gyro_data(11); -- D9
leds(1) <= gyro_data(13); -- D10
leds(0) <= gyro_data(15); -- D11
i2c_SDA <= SDA_int;
i2c_SCL <= SCL_int;
end struc;
Result:
all the leds dont change status despite if i rotate the MPU6050. So no communication. Can anyone help me what i'm doing wrong?
First: I'm using the same component in one of my designs and do confirm it works.
I think you are just using the wrong i2c address to begin with.
In datasheets, i2c addresses are usually given including the read/write bit (for the MPU-6050, this is 0x68/01101000 and 0x69/01101001). The i2c master component used, however, expects to build the final i2c address by itself by appending (&) the i2c rw bit to the given address (see line 124 in the original sources), thus you must pass the address from the datasheet shifted by one bit.
Try using 0x34/0110100 as i2c address for read and write instead.
I only looked very briefly into the rest of your code (so there might be other culprits as well), but this should be enough to get you going.

Sequence Detector Output on FPGA using 3 Input Switches

I have created a bit sequence detector (for sequence 1110) using VHDL. I have used Moore’s State Machine to accomplish the task.
I am able to compile my code and get the desired output.
But on the FPGA board I am supposed to use SW0 as clock, SW1 as data input, SW2 as RESET, any of the LED as data output.
The problems I am facing:
I am unable to assign the clock signal to a switch, I always get an error. So I assigned the clock signal to the default clock signal on the board i.e. LOC = "E3" it work fine. But according to my question I need to assign it to a switch. How do do that?
I am unable to show the output on the fpga board i.e. the led lights up too fast for the naked eye once the data in pin is applied. Any suggestion on how to display the output using 3 input switch and an LED as output as per the above question?
The following code is my design implementation:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Design is
Port ( clock : in STD_LOGIC;
din : in STD_LOGIC;
rst : in STD_LOGIC;
dout : out STD_LOGIC);
end Design;
architecture Behavioral of Design is
type state is (st0, st1, st2, st3, st4);
signal present_state, next_state : state;
begin
synchronous_process: process (clock)
begin
if rising_edge(clock) then
if (rst = '1') then
present_state <= st0;
else
present_state <= next_state;
end if;
end if;
end process;
output_decoder : process(present_state, din)
begin
next_state <= st0;
case (present_state) is
when st0 =>
if (din = '1') then
next_state <= st1;
else
next_state <= st0;
end if;
when st1 =>
if (din = '1') then
next_state <= st2;
else
next_state <= st0;
end if;
when st2 =>
if (din = '1') then
next_state <= st3;
else
next_state <= st0;
end if;
when st3 =>
if (din = '1') then
next_state <= st3;
else
next_state <= st4;
end if;
when st4 =>
if (din = '1') then
next_state <= st1;
else
next_state <= st0;
end if;
when others =>
next_state <= st0;
end case;
end process;
next_state_decoder : process(present_state)
begin
case (present_state) is
when st0 =>
dout <= '0';
when st1 =>
dout <= '0';
when st2 =>
dout <= '0';
when st3 =>
dout <= '0';
when st4 =>
dout <= '1';
when others =>
dout <= '0';
end case;
end process;
end Behavioral;
The following is my testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity tb_moore is
end tb_moore;
architecture Behavioral of tb_moore is
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Design
PORT(
clock : IN std_logic;
din : IN std_logic;
rst : IN std_logic;
dout : OUT std_logic
);
END COMPONENT;
--Inputs
signal clock : std_logic := '0';
signal din : std_logic := '0';
signal rst : std_logic := '0';
--Outputs
signal dout : std_logic;
-- Clock period definitions
constant clk_period : time := 20 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Design PORT MAP (
clock => clock,
din => din,
rst => rst,
dout => dout
);
-- Clock process definitions
clk_process :process
begin
clock <= '0';
wait for clk_period/2;
clock <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
rst <= '1';
wait for 20 ns;
rst <= '0';
din <= '1';
wait for 20 ns;
din <= '1';
wait for 20 ns;
din <= '1';
wait for 20 ns;
din <= '1';
wait for 20 ns;
din <= '1';
wait for 20 ns;
din <= '0';
wait for 20 ns;
din <= '1';
wait for 20 ns;
din <= '1';
end process;
END;
and the following is the constrains file i used for the Nexys DDR4 FPGA Board.
## Clock signal
NET "clock" LOC = "E3" | IOSTANDARD = "LVCMOS33";
## Switches
NET "din" LOC=L16 | IOSTANDARD=LVCMOS33;
NET "rst" LOC=M13 | IOSTANDARD=LVCMOS33;
## LEDs
NET "dout" LOC=H17 | IOSTANDARD=LVCMOS33;

counter not incrementing for RAM with built-in counter

I am new to vhdl and trying create a RAM in which I first write data then I read that data. The task is supposed to be created using a FSM. I have created the behavioral code as follows along with its test bench but the counters are not incrementing and I dont get it.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sorting is
port (
clk : in std_logic;
en : in std_logic;
data_in : in std_logic_vector(23 downto 0);
data_out : out std_logic_vector(23 downto 0));
end entity;
architecture bhv of sorting is
type internal_ram is array(1 downto 0) of std_logic_vector(23 downto 0);
signal int_ram_in : internal_ram;
signal int_ram_out : internal_ram;
type state_type is (s0, s1, s2); --stages is fsm
signal state, nxt_state : state_type;
signal cntr_in : integer range 0 to 3;--unsigned(1 downto 0); --read counter
signal cntr_out : integer range 0 to 3;-- unsigned(1 downto 0); --write counter
begin
-- fsm_loop : process(clk)
-- begin
-- if rising_edge(clk) then
-- if (en = '1') then
-- state <= s0;
-- else
-- state <= nxt_state;
-- end if;
-- end if;
-- end process;
comp_loop : process(clk, state, en, data_in)
begin
if rising_edge(clk) then
case(state) is
when s0 =>
if (en = '1') then
cntr_in <= 0;
cntr_out<= 0;
else
nxt_state <= s1;
end if;
when s1 => --writing in internal_ram
if (cntr_in = 3) then
cntr_in <= 0;--(others => '0');
nxt_state <= s2;
else
cntr_in <= cntr_in + 1;
int_ram_in(cntr_in) <= data_in;
end if;
when s2 => --using data_in
if (cntr_out = 3) then
cntr_out <= 0;--(others => '0');
nxt_state<= s0;
else
cntr_out <= cntr_out + 1;
data_out <= int_ram_in(cntr_out);
end if;
end case;
end if;
end process;
end bhv;
The test bench used is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity sorting_tb is
end entity sorting_tb;
architecture tb of sorting_tb is
component sorting
port (
clk : in std_logic;
en : in std_logic;
data_in : in std_logic_vector(23 downto 0);
data_out : out std_logic_vector(23 downto 0)
);
end component;
signal clk : std_logic := '0';
signal en : std_logic := '1';
signal data_in : std_logic_vector(23 downto 0);
signal data_out : std_logic_vector(23 downto 0);
begin
mapping: sorting port map(
clk => clk,
en => en,
data_in => data_in,
data_out => data_out);
clock: process
begin
clk <= '1'; wait for 10 ns;--50MHz clk
clk <= '0'; wait for 10 ns;
end process;
stimuli: process
begin
--1st run
wait for 10ns;
en <= '0';
data_in <= "111100001111000011110000";
wait for 20ns;
data_in <= "111100001111000011110001";
wait for 20ns;
data_in <= "111100001111000011110010";
wait for 20ns;
data_in <= "111100001111000011110011";
-- en <= '1';
wait for 200ns;
en <= '1';
--2nd run
wait for 20ns;
en <= '0';
data_in <= "001100001111000011110000";
wait for 20ns;
data_in <= "011100001111000011110001";
wait for 20ns;
data_in <= "101100001111000011110010";
wait for 20ns;
data_in <= "111100001111000011110011";
-- en <= '1';
wait for 200ns;
en <= '1';
end process;
end tb;
And the simulation that I get is this:

When an output should go to 1, it goes to unknown

So for a school assignment we have to make a clock using different modules and I have an up-down counter and a finite state machine. I should be able to press a button so the counter goes up by one or down by one and this for the hours, minutes and seconds.
The problem is in the testbench of my fsm. When you add a number the up_down signal should go to 1 so the counter knows it has to count up, but when this happens the signal goes to unknown and when I want decrease it the signal goes back to 0 as it should.
I have looked for why it could do this but have no clue whatsoever, does anybody know why? I'll ad my code and a screenshot of the testbench.
a) The finite state machine
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity tijd_FSM is
Port ( clk_1ms : in std_logic;
BTU : in std_logic;
BTD : in STD_LOGIC;
BTR : in std_logic;
mo_tijd : in std_logic;
EupH : out std_logic;
EdownH : out std_logic;
EupM : out std_logic;
EdownM : out std_logic;
EupS : out std_logic;
EdownS : out std_logic;
up_down : out std_logic;
blink_tijd: out std_logic_vector (1 downto 0)
);
end tijd_FSM;
architecture Behavioral of tijd_FSM is
type state is (s0, s1, s2, s3);
signal present_state, next_state : state;
begin
state_reg: process (clk_1ms)
begin
if rising_edge(clk_1ms) then
if(BTR = '1' and mo_tijd = '1') then
present_state <= next_state;
else
present_state <= present_state;
end if;
end if;
end process;
--state machine process.
outputs: process (present_state, BTU, BTD)
begin
case present_state is
when s0 => --Gewone weergave
blink_tijd <= "00";
up_down <= '0';
when s1 => --Instellen UU
if(BTU ='1') then
up_down <= '1';
EupH <= '1';
elsif(BTD='1') then
up_down <= '0';
EdownH <= '1';
else
EupH <= '0';
EdownH <= '0';
end if;
blink_tijd <= "10";
when s2 => --Instellen MM
if(BTU ='1') then
up_down <= '1';
EupM <= '1';
elsif(BTD='1') then
up_down <= '0';
EdownM <= '1';
else
EupM <= '0';
EdownM <= '0';
end if;
blink_tijd <= "10";
when s3 => --Instellen SS
if(BTU ='1') then
up_down <= '1';
EupS <= '1';
elsif(BTD='1') then
up_down <= '0';
EdownS <= '1';
else
EupS <= '0';
EdownS <= '0';
end if;
blink_tijd <= "01";
when others => null;
end case;
end process;
nxt_state: process (BTR, present_state)
begin
case present_state is
when s0 =>
if BTR = '1' then next_state <= s1;
else next_state <= s0;
end if;
when s1 =>
if BTR = '1' then next_state <= s2;
else next_state <= s1;
end if;
when s2 =>
if BTR = '1' then next_state <= s3;
else next_state <= s2;
end if;
when s3 =>
if BTR = '1' then next_state <= s0;
else next_state <= s3;
end if;
when others => next_state <= s0;
end case;
end process;
end Behavioral;
b) The testbench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY tb_tijd_FSM IS
END tb_tijd_FSM;
ARCHITECTURE behavior OF tb_tijd_FSM IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT tijd_FSM
PORT(
clk_1ms : IN std_logic;
BTU : IN std_logic;
BTD : IN std_logic;
BTR : IN std_logic;
mo_tijd : IN std_logic;
EupH : OUT std_logic;
EdownH : OUT std_logic;
EupM : OUT std_logic;
EdownM : OUT std_logic;
EupS : OUT std_logic;
EdownS : OUT std_logic;
up_down : OUT std_logic;
blink_tijd : OUT std_logic_vector(1 downto 0)
);
END COMPONENT;
--Inputs
signal clk_1ms : std_logic := '0';
signal BTU : std_logic := '0';
signal BTD : std_logic := '0';
signal BTR : std_logic := '0';
signal mo_tijd : std_logic := '0';
--Outputs
signal EupH : std_logic;
signal EdownH : std_logic;
signal EupM : std_logic;
signal EdownM : std_logic;
signal EupS : std_logic;
signal EdownS : std_logic;
signal up_down : std_logic;
signal blink_tijd : std_logic_vector(1 downto 0);
-- Clock period definitions
constant clk_1ms_period : time := 1 ms;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: tijd_FSM PORT MAP (
clk_1ms => clk_1ms,
BTU => BTU,
BTD => BTD,
BTR => BTR,
mo_tijd => mo_tijd,
EupH => EupH,
EdownH => EdownH,
EupM => EupM,
EdownM => EdownM,
EupS => EupS,
EdownS => EdownS,
up_down => up_down,
blink_tijd => blink_tijd
);
-- Clock process definitions
clk_1ms_process :process
begin
clk_1ms <= '0';
wait for clk_1ms_period/2;
clk_1ms <= '1';
wait for clk_1ms_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
up_down <= '0';
mo_tijd <= '1';
--Hij begint in state s0
wait for 1 ms;
BTR <= '1'; --s1
wait for 1 ms;
BTR <= '0';
wait for 1 ms;
BTU <= '1';
wait for 1 ms;
BTU <= '0';
wait for 1 ms;
BTD <= '1';
wait for 1 ms;
BTD <= '0';
wait for 1 ms;
BTR <= '1'; --s2
wait for 1 ms;
BTR <= '0';
wait for 1 ms;
BTU <= '1';
wait for 1 ms;
BTU <= '0';
wait for 1 ms;
BTD <= '1';
wait for 1 ms;
BTD <= '0';
wait for 1 ms;
BTR <= '1'; -- s3
wait for 1 ms;
BTR <= '0';
wait for 1 ms;
BTU <= '1';
wait for 1 ms;
BTU <= '0';
wait for 1 ms;
BTD <= '1';
wait for 1 ms;
BTD <= '0';
wait;
end process;
END;
c) The waveform image
In stim_proc you have up_down <= '0', which drives 0 on the same signal that the output of your state machine is connected.
As long as the state machine also drives 0 everything is fine as the combination resolves to 0. When the state machine drives 1 however, the resolution is X, undefined.
As far as I can see, there is no reason for stim_proc to drive this signal, so removing that line should give you what you want.

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