using UART in VHDL - vhdl

I'm trying to use UART communication with a Lattice machox3 and a ft232R. I am trying to use the VHDL file I found on eewiki(Here). For some reason I am not being able to get tx to work when I simulate it. what am I doing wrong? Is there a simple uart implementation I could use? I tried making it myself, scine I just want to transmit, but I wasnt unsuccessful.
here is the waveform Active hdl gives me
this is the top file I am using to get this component to work.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--library machXO3;
--use machXO3.all;
entity UART_TOP is generic (
divisor : integer := 2604 -- Set the Baud Rate Divisor here.
-- Some common values: 300 Baud = 83333, 9600 Baud = 2604, 115200 Baud = 217, 921600 Baud = 27
);
PORT(
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission load on H
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC;
CLOCK_UART : in STD_LOGIC;
DIN : IN STD_LOGIC_VECTOR(15 downto 0)
);
end UART_TOP;
architecture Behavior of UART_TOP is
SIGNAL INTERNAL_CLOCK : STD_LOGIC;
SIGNAL MUX_0 : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL MUX_1 : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL MUX_S : STD_LOGIC_VECTOR(1 downto 0);
SIGNAL txEN: STD_LOGIC_VECTOR(0 downto 0);
SIGNAL counter : STD_LOGIC;
SIGNAL DATAsnd : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL LOAD : STD_LOGIC;
---------------------------------------------------
-- Buffer Input --
---------------------------------------------------
COMPONENT NOTM is
PORT(
Input : in STD_LOGIC;
Output : out STD_LOGIC
);
END COMPONENT;
---------------------------------------------------
-- Buffer Input --
---------------------------------------------------
COMPONENT InputBuffer is
generic(n: natural);
PORT(
clk : in STD_LOGIC;
En : in STD_LOGIC; -- 0 is enabled
Input : in STD_LOGIC_VECTOR (n-1 downto 0);
Output : out STD_LOGIC_VECTOR (n-1 downto 0)
);
END COMPONENT;
---------------------------------------------------
-- MUX04_2_1 --
---------------------------------------------------
COMPONENT MUX421 is
generic (
DATAWIDTH : natural := 8
);
port(
A : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
B : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
C : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
D : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
S : in STD_LOGIC_VECTOR(1 downto 0);
O : OUT STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0)
);
END COMPONENT;
---------------------------------------------------
-- Binary Counter --
---------------------------------------------------
COMPONENT binary_counter is
generic(
MIN_COUNT : natural := 0;
MAX_COUNT : natural := 17
);
port(
clk : in std_logic;
reset : in std_logic;
enable : in std_logic; -- 0 is enabled
q : out STD_LOGIC_VECTOR(MAX_COUNT-1 downto 0)
);
END COMPONENT;
---------------------------------------------------
-- UART. Mach0X3 --
---------------------------------------------------
COMPONENT uart_c IS
GENERIC(
clk_freq : INTEGER := 50_000_000; --frequency of system clock in Hertz
baud_rate : INTEGER := 19_200; --data link baud rate in bits/second
os_rate : INTEGER := 16; --oversampling rate to find center of receive bits (in samples per baud period)
d_width : INTEGER := 8; --data bus width
parity : INTEGER := 1; --0 for no parity, 1 for parity
parity_eo : STD_LOGIC := '0'); --'0' for even, '1' for odd parity
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission load on H
tx_data : IN STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data to transmit
rx : IN STD_LOGIC; --receive pin
rx_busy : OUT STD_LOGIC; --data reception in progress
rx_error : OUT STD_LOGIC; --start, parity, or stop bit error detected
rx_data : OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data received
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC); --transmit pin
END COMPONENT;
begin
-- UART
DATAOUT: UART_c
PORT MAP ( CLK => CLOCK_UART, --system clock
reset_n =>reset_n, --ascynchronous reset
tx_ena => tx_ena,--txEN(0), --initiate transmission
tx_data => DIN(7 downto 0), --data to transmit
rx =>'0' , --receive pin
tx => tx, --transmit pin
tx_busy => tx_busy
);
--UART LOAD
--LOADER: NOTM
--PORT MAP (INPUT => LOAD, OUTPUT => counter);
-- DATA to MUX
--MUX: MUX421
--PORT MAP (s => MUX_S, A => MUX_0, B => MUX_1, C => X"0D", D => X"0A", O => DO-- DATAsnd
--); -- C => X"0D", D => X"0A" cartidge return and line feed
-- Counter to mux
--cntr: binary_counter
--generic map (MAX_COUNT => 2)
--PORT MAP (
--clk => counter,
--reset => RESET,
--enable => ENABLE,
--q => MUX_S
--);
-- Counter to load
--Load_UART: binary_counter
--generic map (MAX_COUNT => 1)
--PORT MAP (
--clk => CLOCK_UART,
--reset => RESET,
--enable => LOAD,
--q => txEN
--);
--DATA to UART
--UARTBUFFER_0: InputBuffer
--generic map (N => 8)
--PORT MAP ( clk => CLOCK_UART, En =>ENABLE, Input => DIN(15 downto 8), OUTPUT => MUX_0);
--DATA to UART
--UARTBUFFER_1: InputBuffer
--generic map (N => 8)
--PORT MAP ( clk => CLOCK_UART, En =>ENABLE, Input => DIN(7 downto 0), OUTPUT => MUX_1);
end Behavior;
this is the UART itself
--------------------------------------------------------------------------------
--
-- FileName: uart_c.vhd
-- Dependencies: none
-- Design Software: Quartus II 64-bit Version 13.1.0 Build 162 SJ Web Edition
--
-- HDL CODE IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
--
-- Version History
-- Version 1.0 5/26/2017 Scott Larson
-- Initial Public Release
--
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY uart_c IS
GENERIC(
clk_freq : INTEGER := 50_000_000; --frequency of system clock in Hertz
baud_rate : INTEGER := 19_200; --data link baud rate in bits/second
os_rate : INTEGER := 16; --oversampling rate to find center of receive bits (in samples per baud period)
d_width : INTEGER := 8; --data bus width
parity : INTEGER := 1; --0 for no parity, 1 for parity
parity_eo : STD_LOGIC := '0'); --'0' for even, '1' for odd parity
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission
tx_data : IN STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data to transmit
rx : IN STD_LOGIC; --receive pin
rx_busy : OUT STD_LOGIC; --data reception in progress
rx_error : OUT STD_LOGIC; --start, parity, or stop bit error detected
rx_data : OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data received
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC); --transmit pin
END uart_c;
ARCHITECTURE logic OF uart_c IS
TYPE tx_machine IS(idle, transmit); --tranmit state machine data type
TYPE rx_machine IS(idle, receive); --receive state machine data type
SIGNAL tx_state : tx_machine; --transmit state machine
SIGNAL rx_state : rx_machine; --receive state machine
SIGNAL baud_pulse : STD_LOGIC := '0'; --periodic pulse that occurs at the baud rate
SIGNAL os_pulse : STD_LOGIC := '0'; --periodic pulse that occurs at the oversampling rate
SIGNAL parity_error : STD_LOGIC; --receive parity error flag
SIGNAL rx_parity : STD_LOGIC_VECTOR(d_width DOWNTO 0); --calculation of receive parity
SIGNAL tx_parity : STD_LOGIC_VECTOR(d_width DOWNTO 0); --calculation of transmit parity
SIGNAL rx_buffer : STD_LOGIC_VECTOR(parity+d_width DOWNTO 0) := (OTHERS => '0'); --values received
SIGNAL tx_buffer : STD_LOGIC_VECTOR(parity+d_width+1 DOWNTO 0) := (OTHERS => '1'); --values to be transmitted
BEGIN
--generate clock enable pulses at the baud rate and the oversampling rate
PROCESS(reset_n, clk)
VARIABLE count_baud : INTEGER RANGE 0 TO clk_freq/baud_rate-1 := 0; --counter to determine baud rate period
VARIABLE count_os : INTEGER RANGE 0 TO clk_freq/baud_rate/os_rate-1 := 0; --counter to determine oversampling period
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
baud_pulse <= '0'; --reset baud rate pulse
os_pulse <= '0'; --reset oversampling rate pulse
count_baud := 0; --reset baud period counter
count_os := 0; --reset oversampling period counter
ELSIF(clk'EVENT AND clk = '1') THEN
--create baud enable pulse
IF(count_baud < clk_freq/baud_rate-1) THEN --baud period not reached
count_baud := count_baud + 1; --increment baud period counter
baud_pulse <= '0'; --deassert baud rate pulse
ELSE --baud period reached
count_baud := 0; --reset baud period counter
baud_pulse <= '1'; --assert baud rate pulse
count_os := 0; --reset oversampling period counter to avoid cumulative error
END IF;
--create oversampling enable pulse
IF(count_os < clk_freq/baud_rate/os_rate-1) THEN --oversampling period not reached
count_os := count_os + 1; --increment oversampling period counter
os_pulse <= '0'; --deassert oversampling rate pulse
ELSE --oversampling period reached
count_os := 0; --reset oversampling period counter
os_pulse <= '1'; --assert oversampling pulse
END IF;
END IF;
END PROCESS;
--receive state machine
PROCESS(reset_n, clk)
VARIABLE rx_count : INTEGER RANGE 0 TO parity+d_width+2 := 0; --count the bits received
VARIABLE os_count : INTEGER RANGE 0 TO os_rate-1 := 0; --count the oversampling rate pulses
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
os_count := 0; --clear oversampling pulse counter
rx_count := 0; --clear receive bit counter
rx_busy <= '0'; --clear receive busy signal
rx_error <= '0'; --clear receive errors
rx_data <= (OTHERS => '0'); --clear received data output
rx_state <= idle; --put in idle state
ELSIF(clk'EVENT AND clk = '1' AND os_pulse = '1') THEN --enable clock at oversampling rate
CASE rx_state IS
WHEN idle => --idle state
rx_busy <= '0'; --clear receive busy flag
IF(rx = '0') THEN --start bit might be present
IF(os_count < os_rate/2) THEN --oversampling pulse counter is not at start bit center
os_count := os_count + 1; --increment oversampling pulse counter
rx_state <= idle; --remain in idle state
ELSE --oversampling pulse counter is at bit center
os_count := 0; --clear oversampling pulse counter
rx_count := 0; --clear the bits received counter
rx_busy <= '1'; --assert busy flag
rx_state <= receive; --advance to receive state
END IF;
ELSE --start bit not present
os_count := 0; --clear oversampling pulse counter
rx_state <= idle; --remain in idle state
END IF;
WHEN receive => --receive state
IF(os_count < os_rate-1) THEN --not center of bit
os_count := os_count + 1; --increment oversampling pulse counter
rx_state <= receive; --remain in receive state
ELSIF(rx_count < parity+d_width) THEN --center of bit and not all bits received
os_count := 0; --reset oversampling pulse counter
rx_count := rx_count + 1; --increment number of bits received counter
rx_buffer <= rx & rx_buffer(parity+d_width DOWNTO 1); --shift new received bit into receive buffer
rx_state <= receive; --remain in receive state
ELSE --center of stop bit
rx_data <= rx_buffer(d_width DOWNTO 1); --output data received to user logic
rx_error <= rx_buffer(0) OR parity_error OR NOT rx; --output start, parity, and stop bit error flag
rx_busy <= '0'; --deassert received busy flag
rx_state <= idle; --return to idle state
END IF;
END CASE;
END IF;
END PROCESS;
--receive parity calculation logic
rx_parity(0) <= parity_eo;
rx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
rx_parity(i+1) <= rx_parity(i) XOR rx_buffer(i+1);
END GENERATE;
WITH parity SELECT --compare calculated parity bit with received parity bit to determine error
parity_error <= rx_parity(d_width) XOR rx_buffer(parity+d_width) WHEN 1, --using parity
'0' WHEN OTHERS; --not using parity
--transmit state machine
PROCESS(reset_n, clk)
VARIABLE tx_count : INTEGER RANGE 0 TO parity+d_width+3 := 0; --count bits transmitted
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
tx_count := 0; --clear transmit bit counter
tx <= '1'; --set tx pin to idle value of high
tx_busy <= '1'; --set transmit busy signal to indicate unavailable
tx_state <= idle; --set tx state machine to ready state
ELSIF(clk'EVENT AND clk = '1') THEN
CASE tx_state IS
WHEN idle => --idle state
IF(tx_ena = '1') THEN --new transaction latched in
tx_buffer(d_width+1 DOWNTO 0) <= tx_data & '0' & '1'; --latch in data for transmission and start/stop bits
IF(parity = 1) THEN --if parity is used
tx_buffer(parity+d_width+1) <= tx_parity(d_width); --latch in parity bit from parity logic
END IF;
tx_busy <= '1'; --assert transmit busy flag
tx_count := 0; --clear transmit bit count
tx_state <= transmit; --proceed to transmit state
ELSE --no new transaction initiated
tx_busy <= '0'; --clear transmit busy flag
tx_state <= idle; --remain in idle state
END IF;
WHEN transmit => --transmit state
IF(baud_pulse = '1') THEN --beginning of bit
tx_count := tx_count + 1; --increment transmit bit counter
tx_buffer <= '1' & tx_buffer(parity+d_width+1 DOWNTO 1); --shift transmit buffer to output next bit
END IF;
IF(tx_count < parity+d_width+3) THEN --not all bits transmitted
tx_state <= transmit; --remain in transmit state
ELSE --all bits transmitted
tx_state <= idle; --return to idle state
END IF;
END CASE;
tx <= tx_buffer(0); --output last bit in transmit transaction buffer
END IF;
END PROCESS;
--transmit parity calculation logic
tx_parity(0) <= parity_eo;
tx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
tx_parity(i+1) <= tx_parity(i) XOR tx_data(i);
END GENERATE;
END logic;
and this is the test bench
-- VHDL Test Bench Created from source file UART_TOP.vhd -- Sun Aug 19 12:41:55 2018
--
-- Notes:
-- 1) This testbench template has been automatically generated using types
-- std_logic and std_logic_vector for the ports of the unit under test.
-- Lattice recommends that these types always be used for the top-level
-- I/O of a design in order to guarantee that the testbench will bind
-- correctly to the timing (post-route) simulation model.
-- 2) To use this template as your testbench, change the filename to any
-- name of your choice with the extension .vhd, and use the "source->import"
-- menu in the ispLEVER Project Navigator to import the testbench.
-- Then edit the user defined section below, adding code to generate the
-- stimulus for your design.
-- 3) VHDL simulations will produce errors if there are Lattice FPGA library
-- elements in your design that require the instantiation of GSR, PUR, and
-- TSALL and they are not present in the testbench. For more information see
-- the How To section of online help.
--
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY testbench IS
END testbench;
ARCHITECTURE behavior OF testbench IS
COMPONENT UART_TOP
PORT(
reset_n : IN std_logic;
tx_ena : IN std_logic;
CLOCK_UART : IN std_logic;
DIN : IN std_logic_vector(15 downto 0);
tx_busy : OUT std_logic;
tx : OUT std_logic
);
END COMPONENT;
SIGNAL reset_n : std_logic;
SIGNAL tx_ena : std_logic;
SIGNAL tx_busy : std_logic;
SIGNAL tx : std_logic;
SIGNAL CLOCK_UART : std_logic;
SIGNAL DIN : std_logic_vector(15 downto 0);
constant half_period : time := 10 ns;
BEGIN
-- Please check and add your generic clause manually
uut: UART_TOP PORT MAP(
reset_n => reset_n,
tx_ena => tx_ena,
tx_busy => tx_busy,
tx => tx,
CLOCK_UART => CLOCK_UART,
DIN => DIN
);
-- *** Test Bench - User Defined Section ***
tb : PROCESS
BEGIN
reset_n <= '1';
tx_ena <= '0';
DIN <= B"0101010101010101";
CLOCK_UART <= '1';
wait for half_period ;
CLOCK_UART <= '0';
wait for half_period ;
CLOCK_UART <= '1';
wait for half_period ;
CLOCK_UART <= '0';
wait for half_period ;
tx_ena <= '1';
loop
CLOCK_UART <= '1';
wait for half_period ;
tx_ena <= '0';
CLOCK_UART <= '0';
wait for half_period ;
end loop;
END PROCESS;
-- *** End Test Bench - User Defined Section ***
END;

Related

Why won't a VHDL "inout" signal be assigned a value when used as an output

I have a VHDL description for a bridge, and the bidirectional signal "mem_data_port0" is not getting assigned any value regardless of what I write to it. The pins on the FPGA are assigned accordingly, but no output.
I have the code below (its for an FPGA going into a larger system, so comments will reflect other system components that are not the FPGA)
FYI: The FPGA is a Lattice LCMXO2-7000HC
Any tips on assigning "mem_data_port0"?
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;
use ieee.numeric_std.all;
library machxo2;
use machxo2.all;
entity SinglePhasePowerAnalyzerBridge is
port(
output0 : out std_logic; -- dummy, unassigned outputs
output1 : out std_logic;
output2 : out std_logic;
output3 : out std_logic;
output4 : out std_logic;
output5 : out std_logic;
output6 : out std_logic;
output7 : out std_logic;
accq_data_in : in std_logic_vector (15 downto 0); -- accquisition data in
accq_clk : in std_logic; -- accquisition clock in
accq_data_ready : in std_logic; -- data ready in 0: sending voltage/current data, 1: sending frequency data
accq_reset : in std_logic; -- accquisition reset (active low)
accq_voltage_current : in std_logic; -- accquisition select for voltage and current 0: voltage, 1: current
buffer_data_port0 : out std_logic_vector (15 downto 0); -- buffer data
buffer_address_port0 : in std_logic_vector(12 downto 0); -- buffer address low bits
buffer_address_high_port0 : in std_logic_vector(2 downto 0); -- buffer address high bits
buffer_high_byte_en_port0 : in std_logic; -- high byte enable
buffer_low_byte_en_port0 : in std_logic; -- low byte enable
buffer_write_en_port0 : in std_logic; -- write enable
buffer_output_en_port0 : in std_logic; -- output enable
buffer_memory_en_port0 : in std_logic; -- memory enable
buffer_interrupt_out : out std_logic;
-- pins going to external SRAM memory
mem_data_port0 : inout std_logic_vector (15 downto 0);
mem_address_port0 : out std_logic_vector(12 downto 0);
mem_address_high_port0 : out std_logic_vector (3 downto 0);
mem_memory_en_port0 : out std_logic := '1';
mem_output_en_port0 : out std_logic := '1';
mem_write_en_port0 : out std_logic := '1';
mem_high_byte_en_port0 : out std_logic := '0';
mem_low_byte_en_port0 : out std_logic := '0';
debug_out : out std_logic -- debug output
);
end SinglePhasePowerAnalyzerBridge;
architecture rtl of SinglePhasePowerAnalyzerBridge is
signal frequency_storage_buffer : std_logic_vector (15 downto 0); -- frequency buffer
signal voltage_storage_pointer : integer range 0 to 8191;
signal current_storage_pointer : integer range 0 to 8191;
signal signal_accq_data_in : std_logic_vector (15 downto 0);
signal signal_accq_clk : std_logic;
signal signal_inverse_accq_clk : std_logic;
signal signal_accq_data_ready : std_logic;
signal signal_accq_reset : std_logic;
signal signal_accq_voltage_current : std_logic;
signal signal_delayed_inverse_accq_clk : std_logic;
signal signal_buffer_data_port0 : std_logic_vector (15 downto 0);
signal signal_buffer_address_port0 : std_logic_vector(12 downto 0);
signal signal_buffer_address_high_port0 : std_logic_vector(2 downto 0);
signal signal_buffer_high_byte_en_port0 : std_logic;
signal signal_buffer_low_byte_en_port0 : std_logic;
signal signal_buffer_write_en_port0 : std_logic;
signal signal_buffer_output_en_port0 : std_logic;
signal signal_buffer_memory_en_port0 : std_logic;
begin
signal_accq_data_in <= accq_data_in; -- connect all the pins to internal signals
signal_accq_clk <= accq_clk;
signal_accq_data_ready <= accq_data_ready;
signal_accq_reset <= accq_reset;
signal_accq_voltage_current <= accq_voltage_current;
signal_inverse_accq_clk <= not signal_accq_clk;
--debug_out <= signal_delayed_inverse_accq_clk;
signal_buffer_address_port0 <= buffer_address_port0;
signal_buffer_address_high_port0 <= buffer_address_high_port0;
signal_buffer_high_byte_en_port0 <= buffer_high_byte_en_port0;
signal_buffer_low_byte_en_port0 <= buffer_low_byte_en_port0;
signal_buffer_write_en_port0 <= buffer_write_en_port0;
signal_buffer_output_en_port0 <= buffer_output_en_port0;
signal_buffer_memory_en_port0 <= buffer_memory_en_port0;
buffer_interrupt_out <= not signal_accq_data_ready;
output2 <= signal_accq_data_ready; -- dummy outputs, so the input pins are not left uncommected
output3 <= signal_accq_clk;
output4 <= signal_accq_reset;
output5 <= signal_accq_voltage_current;
general_event : process(signal_accq_clk, signal_accq_data_ready, signal_accq_data_in, signal_accq_voltage_current, signal_accq_reset,
signal_buffer_memory_en_port0, signal_buffer_output_en_port0, signal_buffer_write_en_port0, signal_buffer_address_high_port0, signal_buffer_address_port0,
signal_buffer_data_port0, frequency_storage_buffer, signal_accq_reset, signal_accq_data_ready, voltage_storage_pointer, current_storage_pointer)
begin
if(signal_accq_data_ready = '0') then -- when data from the acquisition controller comes in
mem_output_en_port0 <= '1'; -- disable memory output
mem_memory_en_port0 <= '0'; -- enable memory
mem_write_en_port0 <= signal_inverse_accq_clk; -- send the acquisition clock to the memory write enable pin
if(signal_accq_reset = '1') then -- if reset is not activated...
accq_clk_edge : if(rising_edge(signal_accq_clk)) then -- process on clock rising edge
if(signal_accq_voltage_current = '1') then -- if sending current data
mem_data_port0 <= signal_accq_data_in; -- store the data in the current buffer
mem_address_port0 <= std_logic_vector(to_unsigned(current_storage_pointer, 13));
mem_address_high_port0 <= "0001"; -- sending current data to memory
current_storage_pointer <= (current_storage_pointer + 1); -- increment the counter
elsif (signal_accq_voltage_current = '0') then -- do the same if sending voltage data
--mem_data_port0 <= signal_accq_data_in; -- store the data in the voltage buffer
mem_data_port0 <= "1111111111111111";
mem_address_port0 <= std_logic_vector(to_unsigned(voltage_storage_pointer, 13));
mem_address_high_port0 <= "0000"; -- sending voltage data to memory
voltage_storage_pointer <= (voltage_storage_pointer + 1); -- increment the counter
end if;
end if accq_clk_edge;
else -- if reset is activated...
voltage_storage_pointer <= 0; -- reset everything to 0
current_storage_pointer <= 0; -- reset everything to 0
end if;
--end process accq_event;
elsif (signal_accq_data_ready = '1') then -- if data ready is high, the buffer is in read mode
mem_data_port0 <= "ZZZZZZZZZZZZZZZZ"; -- set memory data lines to input, or read mode
mem_write_en_port0 <= '1'; -- disable writing to the memory
mem_output_en_port0 <= '0'; -- enable memory output
mem_address_port0 <= signal_buffer_address_port0; -- select the appropriate addreess
mem_address_high_port0 (2 downto 0) <= signal_buffer_address_high_port0; -- do the same with the high bits
if(rising_edge(signal_accq_clk) and signal_accq_reset = '1') then -- if the accquisition MCU is writing with the data ready pin high
frequency_storage_buffer <= signal_accq_data_in; -- store the frequency value that it's sending
end if;
if(signal_accq_reset = '0') then -- reset as before if reset is enabled
voltage_storage_pointer <= 0; -- reset everything to 0
current_storage_pointer <= 0; -- reset everything to 0
end if;
if(signal_buffer_memory_en_port0 = '0' and signal_buffer_write_en_port0 = '1' and signal_accq_data_ready = '1' and signal_accq_reset = '1') then -- memory enabled and write enable high...
case signal_buffer_address_high_port0 is
when "000" => signal_buffer_data_port0 <= mem_data_port0; -- output data to downstream MCUs as needed
when "001" => signal_buffer_data_port0 <= mem_data_port0;
when "010" => signal_buffer_data_port0 <= frequency_storage_buffer;
when "011" => signal_buffer_data_port0 <= std_logic_vector(to_unsigned(voltage_storage_pointer, 16));
when "100" => signal_buffer_data_port0 <= std_logic_vector(to_unsigned(current_storage_pointer, 16));
when "111" => signal_buffer_data_port0 <= "1010000001010110"; -- 0xA056
when others=>
end case;
end if;
if(signal_buffer_output_en_port0 = '0') then
--buffer_data_port0(7 downto 0) <= signal_buffer_data_port0 (15 downto 8);
--buffer_data_port0(15 downto 8) <= signal_buffer_data_port0 (7 downto 0);
buffer_data_port0 <= signal_buffer_data_port0;
else
buffer_data_port0 <= "ZZZZZZZZZZZZZZZZ";
end if;
end if;
end process general_event;
output6 <= signal_buffer_high_byte_en_port0;
output7 <= signal_buffer_low_byte_en_port0;
end rtl;
I've tried your code on Modelsim. Although I can't comment on the correctness of mem_data_port0's behavior, it does get assigned values depending on the other relevant signals, so for the out direction it works.
If you're talking about the fact that you cannot assign values to it from outside, all I could think of is that you forgot to assign it the high impedance in input mode, but you do, so that's out.
An explanation could be that your entity is not the top level entity, which would render inout ports unusable (inout has no meaning inside the FPGA, only at the design's top level).

VHDL Altera Qartus random data in unsigned register after (others => 0) + 1

I'm having trouble figuring out why I'm getting problems with my clock enable timer in a UART controller. The counter is cntR. It should start counting from zero after a condition is met, yet it starts at zero and then switches to a random number instead of incrementing 0 to 1. Here's the process code where something bad happens:
process(reset, clock)
begin
if reset = '1' then
cntR <= (others => '0');
elsif rising_edge(clock) then
if rcv_reg = r_idle and rxd = '1' then
cntR <= (others => '0');
else
if cntR = DIVVALUE then
cntR <= (others => '0');
else
cntR <= cntR + 1;
end if;
end if;
end if;
end process;
here are the declarations (probably not that important):
entity SART is
generic(
INCLK : natural := 50000000;
BAUDRATE : natural := 9600;
CNT_WIDTH : natural := 14
);
port(
clock : in std_logic;
reset : in std_logic;
send : in std_logic;
rxd : in std_logic;
data_in : in std_logic_vector(7 downto 0);
data_ready : out std_logic;
clear_to_send : out std_logic;
txd : out std_logic;
data_out : out std_logic_vector(7 downto 0)
);
end SART;
-- Receiver FSM states
type RCV_STATE_TYPE is (
r_idle,
r_start,
r_data1,r_data2,r_data3,r_data4,r_data5,r_data6,r_data7,r_data8,
r_stop1
);
signal rcv_reg, rcv_next : RCV_STATE_TYPE;
signal cntR : unsigned(CNT_WIDTH-1 downto 0);
This is what I get from Signal Tap:
For the record, I'm using Altera Quartus 13.0.0 and a DE0-Nano with a Cyclone IV FPGA.
Thank you in advance for your input.
I managed to fix this problem. It turns out, that I didn't have an SDC file in the project and hence the TimeQuest Timing Analyzer report stated that my maximum clock frequency is 10 times higher that when I had the SDC file attached. After writing an SDC file containing only clock declarations I got a maximum clock frequency of about 7 MHz from TimeQuest. I generated a PLL to get a 5 MHz frequency clock and now everything works flawlessly.

VHDL Multiple Processes error

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.

Logic for an FPGA to output an analog clock on a VGA screen

I am implementing an analog clock which will display an hour and minute hand on a vga screen 640x480 with clock centered at 480x480. The clock will update once a minute. The timing diagram below shows the timing for HSYNC and VSYNC and their position relative to a 26.25MHz clock.
This is my first course in VHDL, I want to know what I am missing in clock.vhd and how to write the test bench effectively so I can get the output
I have a separate component called counter.vhd which gets instantiated twice in clock.vhd, one as the horizontal counter and one as the vertical counter.
Here is my code for counter.vhd, clock.vhd and my testbench which is not complete.
counter.vhd
entity counter is
Port ( clk : STD_LOGIC;
reset : STD_LOGIC;
ena : STD_LOGIC;
rollover_out : STD_LOGIC;
address : STD_LOGIC_VECTOR(7 downto 0);
sync : STD_LOGIC
);
-- Generics
generic (count_value :=800;
sync_start :=10;
sync_end :=20
);
end counter;
architecture Behavioral of counter is
signal temp : STD_LOGIC_VECTOR(9 downto 0); -- counts to 800
process (clk, reset)
if (reset = 0) then
temp <="000000";
sync <='1';
rollover_out <='0';
else (clk'event & clk = 1);
rollover_out <='0';
temp <= temp+"000000";
if (temp = count_value - 1) then
temp <="000000"
rollover_out <= '1';
end if;
if (sync_start = temp) then
sync <= '0';
end if;
if (sync_end = temp) then
sync <= '1';
end if;
end if;
end process;
address <= temp (8 downto 1);
begin
-- 800 horizontal sync counter
process(h_count_reg,h_end,pixel_tick)
begin
if (pixel_tick = '1') then -- 25MHz tick
if (h_end='1') then
h_count_next <= (others => '0');
else
h_count_next <= h_count_reg+1;
end if;
else
h_count_next <= h_count_reg;
end if;
end process;
-- 525 vertical sync counter
process(v_count_reg,h_end,v_end,pixel_tick)
begin
if (pixel_tick = '1') and (h_end = '1') then
if (v_end = '1') then
v_count_next <= (others => '0');
else
v_count_next <= v_count_reg+1;
end if;
else
v_count_next <= v_count_reg;
end if;
end process;
end Behavioral;
clock.vhd
entity clock is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
hsync : out STD_LOGIC;
vsync : out STD_LOGIC;
video_on : out STD_LOGIC;
p_tick : out STD_LOGIC;
pixel_x : out STD_LOGIC_VECTOR(9 downto 0);
pixel_y : out STD_LOGIC_VECTOR(9 downto 0)
);
end clock;
architecture Behavioral of clock is
-- VGA 640x480 sync parameters
constant HD: integer:=640; -- horizontal display area
constant HF: integer:=16; -- horizontal front porch
constant HB: integer:=48; -- horizontal back porch
constant HR: integer:=96; -- horizontal retrace "sync pulse"
constant VD: integer:=480; -- vertical display area
constant VF: integer:=10; -- vertical front porch
constant VB: integer:=33; -- vertical back porch
constant VR: integer:=2; -- vertical retrace "sync pulse"
-- mod2 counter to generate a 25MHz enable tick
signal mod2_reg : std_logic;
signal mod2_next : std_logic;
-- sync counters for the horizontal and vertical scans
signal v_count_reg : unsigned(9 downto 0);
signal v_count_next : unsigned(9 downto 0);
signal h_count_reg : unsigned(9 downto 0);
signal h_count_next : unsigned(9 downto 0);
-- output buffer
signal v_sync_reg : unsigned(9 downto 0);
signal h_sync_reg : unsigned(9 downto 0);
signal v_sync_next : unsigned(9 downto 0);
signal h_sync_next : unsigned(9 downto 0);
-- status signal
signal h_end : std_logic;
signal v_end : std_logic;
signal pixel_tick : std_logic;
component counter
generic (count_value :=800;
sync_start :=10;
sync_end :=20
);
Port (clk : STD_LOGIC;
reset : STD_LOGIC;
ena : STD_LOGIC;
rollover_out : std_logic;
sync : STD_LOGIC;
address : std_logic_vector(9 downto 0)
);
signal carry : std_logic;
end component;
horizontal: counter
generic map (count_value :=800;
sync_start :=10;
sync_end :=20
);
PORT MAP (clk <= clk;
reset <= reset;
ena <= '1';
rollover_out <= carry;
sync <= hsync
address <= open
);
vertical: counter
generic map (count_value :=525;
sync_start := 2;
sync_end := 4
);
Port map (clk <= clk;
reset <= reset;
ena <= carry;
rollover_out <= open;
sync <= vsync;
address <= open
);
begin
-- register
process(clk,reset)
begin
if (reset='1') then
mod2_reg <= '0';
v_count_reg <=(others=>'0');
h_count_reg <=(others=>'0');
v_sync_reg <=(others=>'0');
h_sync_reg <=(others=>'0');
elsif(clk' event and clk='1') then
mod2_reg <= mod2_next;
v_count_reg <= v_count_next;
h_count_reg <= h_count_next;
v_sync_reg <= v_sync_next;
h_sync_reg <= h_sync_next;
end if;
end process;
-- mod2 circuit to generate 25MHz enable tick
mod2_next <= not mod2_reg;
-- 25MHz pixel tick
pixel_tick <= '1' when mod2_reg = '1' else '0';
-- status
h_end <= -- end of horizontal counter
'1' when h_count_reg = (HD+HF+HB+HR-1) else --799
'0';
v_end <= -- end of vertical counter
'1' when v_count_reg = (VD+VF+VB+VR-1) else --524
'0';
-- video on/off
video_on <= '1' when (h_count_reg < HD) and (v_count_reg < VD) else '0';
-- output signals
hsync <= h_sync_reg;
vsync <= v_sync_reg;
pixel_x <= std_logic_vector(h_count_reg);
pixel_y <= std_logic_vector(v_count_reg);
p_tick <= pixel_tick;
end Behavioral;
testbench
ENTITY clock_tb IS
END clock_tb;
ARCHITECTURE behavior OF clock_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT clock
PORT(
clk : IN std_logic;
reset : IN std_logic;
hsync : OUT std_logic;
vsync : OUT std_logic;
video_on : OUT std_logic;
p_tick : OUT std_logic;
pixel_x : OUT std_logic_vector(9 downto 0);
pixel_y : OUT std_logic_vector(9 downto 0)
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal reset : std_logic := '0';
--Outputs
signal hsync : std_logic;
signal vsync : std_logic;
signal video_on : std_logic;
signal p_tick : std_logic;
signal pixel_x : std_logic_vector(9 downto 0);
signal pixel_y : std_logic_vector(9 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: clock PORT MAP (
clk => tb_clk,
reset => tb_reset,
hsync => tb_hsync,
vsync => tb_vsync,
video_on => tb_video_on,
p_tick => tb_p_tick,
pixel_x => tb_pixel_x,
pixel_y => tb_pixel_y
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
If I understand the question correctly, you need to segment your task up into two sections.
First you need a design that when given the 26.25MHz clock will generate the HSYNC, VSYNC and video data signals to be put out on the pins of the FPGA.
Second you need to fill in that video data with an RGB / YCbCr bitmap of pixel data that represent a graphic for the clock hands. This block would take in the video timing signals and the clock and then fill the video data in.
How you generate the clock hands is the tricky part and I suspect where the person running the course is looking for some ingenuity to solve that particular problem.
Start small and build up. Try and get the design together to generate the timing signals and put a flat block of colour or black and white on the screen. It is possible to create a testbench that will then save that pixel data to a file which can be processed into a bitmap, so that you can see what the result would be in simulation before you get to hardware.

Synthesised Synthesis/Implementation

I'm attempting to create an I2C Bus, however I've stumbled into a very awkward problem - during the mapping part of implementation I get the warning that MapLib:701 - Signal SDA connected to top level port SDA has been removed.
After digging back through, I found this was caused by a previous warning in the I2C Master itself: Xst:1293 - FF/Latch <sda_internal> has a constant value of 1 in block <IIC_MASTER>. This FF/Latch will be trimmed during the optimization process. On looking through, it seems that the entire state machine has been optimized away - why is this and how can I stop it? In the logic simulation below, it works as expected and I have no idea exactly what I've done that makes it think that the entire state machine is redundant!.
I've put the image of what I expect to see below, and then the two code blocks describing the I2C Master block and the top level block. Any help at all is massively appreciated!
Top Level
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY I2CBus IS
PORT(
SYSCLK_N : IN STD_LOGIC; --system 200MHz differential clock
SYSCLK_P : IN STD_LOGIC;
BTN : IN STD_LOGIC; -- to manually change reset
LED : OUT STD_LOGIC; --to observe reset value
SCL : OUT STD_LOGIC;
SDA : INOUT STD_LOGIC
);
END I2CBus;
ARCHITECTURE behavior OF I2CBus IS
-------------------DECLARE MASTER & SLAVE COMPONENTS------------------------
COMPONENT IIC_MASTER
PORT(SCL : IN STD_LOGIC;
SCL2X : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
ENA : IN STD_LOGIC;
ADR : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
REG : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
RW : IN STD_LOGIC;
DAT_WR : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
BUSY : OUT STD_LOGIC;
SDA : INOUT STD_LOGIC;
ACK_ERR : BUFFER STD_LOGIC);
END COMPONENT IIC_MASTER;
COMPONENT DCM
PORT(
SYSCLK_P : IN STD_LOGIC; -- CLOCK IN PORTS 200MHZ DIFFERENTIAL
SYSCLK_N : IN STD_LOGIC;
-- CLOCK OUT PORTS
SYSCLK : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT CLK_DIVIDER
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END COMPONENT CLK_DIVIDER;
-------------------I2C MASTER ONLY SIGNALS-----------------
--Inputs
signal reset_n : std_logic; --active high
--Outputs
signal busy : std_logic;
signal ack_err : std_logic;
-----------------------------------------------------------
signal SCL_internal : std_logic;
signal SCL2X_internal : std_logic;
signal sysclk : std_logic;
BEGIN
--------------------I2C_master Instantiation-------------------
master : IIC_Master
port map(
SCL => SCL_internal, --map constant data to send over I2C for now
SCL2X => SCL2X_internal,
RESET_N => RESET_N,
ENA => '1', --hold enable on
ADR => "1011001", --keep address constant
REG => x"AA", --keep target register constant
RW => '0', --always read
DAT_WR => x"77", --keep data to send constant
BUSY => BUSY,
SDA => SDA,
ACK_ERR => ACK_ERR
);
DCM_CLK : DCM
port map(
SYSCLK_P => SYSCLK_P,
SYSCLK_N => SYSCLK_N,
SYSCLK => sysclk --generate 200 MHz clock from system clocks
);
Clk_Div : Clk_Divider --Divide 200MHz clock down to frequencies that can be
generic map( --seen on an oscilloscope
INPUT_FREQ => 200000000, --200 MHz input
OUT1_FREQ => 10, --10 Hz output
OUT2_FREQ => 20 --20 Hz output
)
port map(
SYSCLK => sysclk, --system clock
RESET_N => reset_n, --reset
OUT1 => scl_internal,
OUT2 => scl2x_internal
);
----------------Mappings---------------------------
reset_n <= not BTN; --reset low when button pressed
LED <= not reset_n; --light LED when reset
SCL <= 'Z' when scl_internal = '1' else scl_internal;
end behavior;
I2C Master Block
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity IIC_MASTER IS
PORT(SCL : IN STD_LOGIC; --SCL clock
SCL2X : IN STD_LOGIC; --SCL x2 rate clock
RESET_N : IN STD_LOGIC; --ACTIVE LOW
ENA : IN STD_LOGIC; --ENABLE ACTIVE HIGH
ADR : IN STD_LOGIC_VECTOR(6 DOWNTO 0); --TARGET ADDRESS
REG : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --TARGET REGISTER
RW : IN STD_LOGIC; --READ LOW, WRITE HIGH
DAT_WR : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --DATA TO WRITE TO SLAVE
BUSY : OUT STD_LOGIC; --HIGH WHEN BUSY
SDA : INOUT STD_LOGIC; --SERIAL DATA ON BUS
ACK_ERR : BUFFER STD_LOGIC); --FLAG IF WRONG ACK FROM SLAVE
END IIC_MASTER;
architecture BEHAVIORAL of IIC_MASTER is
type state is (begn, ready, start, command, cmd_ack, reg_cmd, reg_ack, wr, rd, data_ack, stop);
signal i2cstate : state;
signal sda_internal : std_logic := '1'; --internal SDA
signal scl_internal : std_logic;
signal scl2x_internal : std_logic;
signal addr_rw : std_logic_vector(7 downto 0); --latched address (6-0) + rw (7)
signal reg_tx : std_logic_vector(7 downto 0); --latched slave register
signal data_tx : std_logic_vector(7 downto 0); -- data to write to slave
signal bit_cnt : integer range 0 to 7 := 7; --number of bits sent in transaction
begin
------state machine logic & writing to SDA on data clk rising edge-----
state_machine : process(scl2x_internal)
begin
if falling_edge(scl2x_internal) then
if reset_n = '0' then --when reset is low, set to ready i2cstate <= ready; --NOT IN TEMPLATE
busy <= '1'; --set to busy
sda_internal <= '1'; --disable sda to Z
ACK_ERR <= '0'; --clear error/ack flag
bit_cnt <= 7; --reset bit count
i2cstate <= ready;
else
if scl_internal = '0' then --in middle of clock low
case i2cstate is
when begn => i2cstate <= ready; --unconditional transition
when ready => if ENA = '1' then
BUSY <= '1'; --set busy
addr_rw <= ADR & RW; --get address & rw (concatenate)
reg_tx <= REG; --get target register
data_tx <= DAT_WR; --Collect data to write from port
i2cstate <= start; --update state
else
BUSY <= '0'; --set not busy
i2cstate <= ready; --remain ready
end if;
when start =>
BUSY <= '1'; --ensure busy remains on
bit_cnt <= 7; --reset bit counter for bytes
ACK_ERR <= '0';
sda_internal <= addr_rw(bit_cnt); --put first command bit on bus
i2cstate <= command; -- also an unconditional transition
when command =>
if bit_cnt = 0 then
sda_internal <= '1'; --set high for acknowledge
bit_cnt <= 7; --reset bit counter for bytes
i2cstate <= cmd_ack;
else
bit_cnt <= bit_cnt - 1; --decrement bit count
sda_internal <= addr_rw(bit_cnt - 1); --send next address bit on bus
i2cstate <= command; --stay in this state until command is sent
end if;
when cmd_ack =>
sda_internal <= reg_tx(bit_cnt); --write first register bit
i2cstate <= reg_cmd; --go to register sending state
when reg_cmd =>
if bit_cnt = 0 then --register transmitted
sda_internal <= '1'; --release internal sda for acknowledgement
bit_cnt <= 7; --reset bit count
i2cstate <= reg_ack; --go to reg ack
else
bit_cnt <= bit_cnt - 1; --decrement
sda_internal <= reg_tx(bit_cnt - 1); --write next reg bit to bus
i2cstate <= reg_cmd; --keep writing
end if;
when reg_ack =>
if addr_rw(0) = '0' then -- if read/write is high, read
sda_internal <= data_tx(bit_cnt); --write first data bit
i2cstate <= wr; -- go to write state
else --else if low, write
sda_internal <= '1'; --release internal sda for reading
i2cstate <= rd; --go to read state
end if;
when wr =>
BUSY <= '1'; --ensure busy flag still high
if bit_cnt = 0 then --byte transmitted
sda_internal <= '1'; --release internal sda for acknowledgement
bit_cnt <= 7; --reset bit count
BUSY <= '0'; -- data all written, so lower busy to notify others
i2cstate <= data_ack; --go to slav ack
else
bit_cnt <= bit_cnt - 1; --decrement
sda_internal <= data_tx(bit_cnt - 1); --write next bit to bus
i2cstate <= wr; --keep writing
end if;
when rd => null;
when data_ack => --acknowledge write
if ENA = '1' then --continue transaction
BUSY <= '0'; -- accept continue by keeping busy low
addr_rw <= ADR & RW; --fetch next address & command
data_tx <= DAT_WR; --fetch next data to write
reg_tx <= REG; --fetch next register
if addr_rw = ADR & RW and reg_tx = REG then --if the same location
sda_internal <= DAT_WR(bit_cnt); --write first bit of data
i2cstate <= wr; --go to write state
else --continue next transaction with a new read/write or slave
i2cstate <= start; --continue from start
end if;
else
i2cstate <= stop; --transaction done, go to end
sda_internal <= '0';
end if;
when stop =>
BUSY <= '0'; --set not busy
i2cstate <= ready;
end case;
elsif scl_internal = '1' then --in middle of clock high
case i2cstate is
when start => sda_internal <= '0';
when stop => sda_internal <= '1';
when cmd_ack | reg_ack | data_ack =>
if (SDA /= '0' or ACK_ERR = '1') then
ACK_ERR <= '1'; --no acknowledge or prev. error
end if;
when others => null;
end case;
end if;
end if;
end if;
end process;
scl_internal <= '1' when SCL = 'Z' else SCL;
scl2x_internal <= '1' when SCL2X = 'Z' else SCL2X;
SDA <= 'Z' when sda_internal = '1' else '0';
end BEHAVIORAL;
scl_internal <= '1' when SCL = 'Z' else SCL;
scl2x_internal <= '1' when SCL2X = 'Z' else SCL2X;
You cannot test for equality to 'Z' and synth should warn about these. Simulation can, but there is no hardware block that works that way for synthesis to use.
I2C signals use a WIRED-OR convention, you drive 'Z' but you must test for '0' or '1' Specifically, logic high can be represented by either 'H' or '1', the former being a weak form of '1'. This means that testing for '1' may synthesise to the right thing, but simulation will no longer work...
So what's happening is that synthesis is seeing invalid logic for SCL, which allows it to delete the lot.
Solutions:
First, in your testbench, drive 'H' on SCL and SDA permanently. Because it's weak, (like a pullup), '0' can override it.
Secondly, either explicitly test for '0' :
scl_internal <= 0 when SCL = '0' else '1';
scl2x_internal <= '0' when SCL2X = '0' else '1';
or explicitly test for 'H' as well as '1'
scl_internal <= '1' when SCL = 'H' or SCL = '1' else SCL;
scl2x_internal <= '1' when SCL2X = 'H' or SCL2X = '1' else SCL2X;
or use the "to_01xz" function to collapse 'H' and '1' into the same value
scl_internal <= '1' when to_01xz(SCL) = '1' else SCL;
scl2x_internal <= '1' when to_01xz(SCL2X) = '1' else SCL2X;

Resources