VHDL: 'X' in output instead of '1' - vhdl

I wrote a simple Real Time Clock code. However in simulation it shows X instead of output bits, also a glitch after value "000001" in Seconds output.
Waveform Picture.
Could you please advise what is wrong with the code?
VHDL Code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL; -- Enables Adding
entity rtc_timer is
generic( CLK_FREQ : integer := 10);
port
(
nRST : in std_logic;
clk : in std_logic;
Seconds : inout std_logic_vector(5 downto 0);
Minutes : inout std_logic_vector(5 downto 0);
Hours : inout std_logic_vector(4 downto 0)
);
end rtc_timer;
architecture Behavioral of rtc_timer is
signal counter : integer;
begin
process(nRST, clk)
begin
if rising_edge(clk) then
-- Negative Reset Signal
if nRST = '0' then
counter <= 0;
Seconds <= (others => '0');
Minutes <= (others => '0');
Hours <= (others => '0');
elsif counter = CLK_FREQ - 1 then
counter <= 0;
if Seconds = 59 then
Seconds <= (others => '0');
if Minutes = 59 then
Minutes <= (others => '0');
if Hours = 23 then
Hours <= (others => '0');
else Hours <= Hours + 1;
end if;
else Minutes <= Minutes + 1;
end if;
else Seconds <= Seconds + 1;
end if;
else counter <= counter + 1;
end if;
end if;
end process;
end Behavioral;

Related

VHDL Vivado Combinatorial Loop Alert

I am trying to implement a simple ALU:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity simple_alu is
Port (
clk : in std_logic;
rst : in std_logic;
op : in std_logic_vector (1 downto 0);
in0 : in std_logic_vector (31 downto 0);
in1 : in std_logic_vector (31 downto 0);
res : out std_logic_vector (31 downto 0);
done_flag : out std_logic
);
end simple_alu;
architecture Behavioral of simple_alu is
type state_type is (start, add, sub, mul, pow, done);
signal state, next_state : state_type := start;
signal status : std_logic := '0';
signal inter, shift_reg, zero : std_logic_vector (31 downto 0) := (others => '0');
begin
SYNC_PROC: process (clk, rst)
begin
if (rst = '0') then
if rising_edge(clk) then
state <= next_state;
res <= inter;
done_flag <= status;
end if;
else
state <= start;
res <= (others => '0');
done_flag <= '0';
end if;
end process;
--MEALY State-Machine - Outputs based on state and inputs
OUTPUT_DECODE: process (state, in0, in1, shift_reg)
variable result, temp : std_logic_vector (31 downto 0);
variable flag : std_logic := '0';
begin
shift_reg <= in1;
temp := temp;
flag := flag;
result := result;
case state is
when start =>
result := std_logic_vector(to_signed(1, 32));
temp := in0;
flag := '0';
when add => result := std_logic_vector(signed(in0) + signed(in1));
when sub => result := std_logic_vector(signed(in0) - signed(in1));
when mul => result := std_logic_vector(resize(signed(in0) * signed(in1), 32));
when pow =>
if (shift_reg(shift_reg'low) = '1') then
result := std_logic_vector(resize(signed(result) * signed(temp), 32));
else
result := result;
end if;
temp := std_logic_vector(resize(signed(temp) * signed(temp), 32));
shift_reg <= std_logic_vector(shift_right(signed(shift_reg), 1));
when done =>
result := result;
flag := '1';
when others =>
end case;
inter <= result;
status <= flag;
end process;
NEXT_STATE_DECODE: process (state, op, shift_reg, zero, rst) -- rst indicates that one input (op, in0 or in1) changed
begin
--declare default state for next_state to avoid latches
next_state <= state; --default is to stay in current state
case (state) is
when start =>
case (op) is
when "00" => next_state <= add;
when "01" => next_state <= sub;
when "10" => next_state <= mul;
when "11" => next_state <= pow;
when others => next_state <= done;
end case;
when add => next_state <= done;
when sub => next_state <= done;
when mul => next_state <= done;
when pow =>
if (shift_reg = zero) then
next_state <= done;
else
next_state <= pow;
end if;
when done =>
if (rst = '1') then
next_state <= start;
end if;
when others =>
end case;
end process;
end Behavioral;
This seems to be working, at least in this testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity simple_alu_tb is
end simple_alu_tb;
architecture Behavioral of simple_alu_tb is
component simple_alu is
Port (
clk : in std_logic;
rst : in std_logic;
op : in std_logic_vector (1 downto 0);
in0 : in std_logic_vector (31 downto 0);
in1 : in std_logic_vector (31 downto 0);
res : out std_logic_vector (31 downto 0);
done_flag : out std_logic
);
end component;
signal clk : std_logic := '0';
signal rst : std_logic := '0';
signal op : std_logic_vector (1 downto 0) := (others => '0');
signal in0 : std_logic_vector (31 downto 0) := (others => '0');
signal in1 : std_logic_vector (31 downto 0) := (others => '0');
signal res : std_logic_vector (31 downto 0) := (others => '0');
signal done_flag : std_logic := '0';
constant clk_period : time := 1 ns;
begin
--Instantiate the Unit Under Test (UUT)
uut: simple_alu Port Map (
clk => clk,
rst => rst,
op => op,
in0 => in0,
in1 => in1,
res => res,
done_flag => done_flag
);
-- Clock process definitions
clk_process :process
begin
clk <= '1';
wait for clk_period/2;
clk <= '0';
wait for clk_period/2;
end process;
stim_proc: process
begin
wait for 2*clk_period;
rst <= '1';
wait for clk_period;
rst <= '0';
wait for 4*clk_period;
op <= "00"; -- add
in0 <= std_logic_vector(to_signed(12, 32));
in1 <= std_logic_vector(to_signed(3, 32));
rst <= '1';
wait for clk_period;
rst <= '0';
wait for 2*clk_period;
assert (res = std_logic_vector(to_signed(15, 32))) report "addition failed" severity failure;
wait for 4*clk_period;
op <= "01"; -- sub
in0 <= std_logic_vector(to_signed(12, 32));
in1 <= std_logic_vector(to_signed(3, 32));
rst <= '1';
wait for clk_period;
rst <= '0';
wait for 2*clk_period;
assert (res = std_logic_vector(to_signed(9, 32))) report "subtraction failed" severity failure;
wait for 4*clk_period;
op <= "10"; -- mul
in0 <= std_logic_vector(to_signed(12, 32));
in1 <= std_logic_vector(to_signed(3, 32));
rst <= '1';
wait for clk_period;
rst <= '0';
wait for 2*clk_period;
assert (res = std_logic_vector(to_signed(36, 32))) report "multiplication failed" severity failure;
wait for 4*clk_period;
op <= "11"; -- pow
in0 <= std_logic_vector(to_signed(12, 32));
in1 <= std_logic_vector(to_signed(7, 32));
rst <= '1';
wait for clk_period;
rst <= '0';
wait for 4*clk_period;
assert (res = std_logic_vector(to_signed(35831808, 32))) report "power failed" severity failure;
wait for 4*clk_period;
op <= "11"; -- pow
in0 <= std_logic_vector(to_signed(12, 32));
in1 <= std_logic_vector(to_signed(6, 32));
rst <= '1';
wait for clk_period;
rst <= '0';
wait for 4*clk_period;
assert (res = std_logic_vector(to_signed(2985984, 32))) report "power failed" severity failure;
wait;
end process;
end Behavioral;
I would like to implement that as AXI4-lite component. So I generate the wrapper, adapt the write process and instantiate my module as follows:
...
process (S_AXI_ACLK)
variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
-- command_reg <= (others => '0');
-- done_flag <= '0';
slv_reg1 <= (others => '0');
slv_reg2 <= (others => '0');
-- slv_reg3 <= (others => '0');
else
loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
if (slv_reg_wren = '1') then
case loc_addr is
when b"00" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-4) loop -- write to command register only
if ( S_AXI_WSTRB(byte_index) = '1' ) then
-- Respective byte enables are asserted as per write strobes
-- slave registor 0
command_reg(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
when b"01" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
-- Respective byte enables are asserted as per write strobes
-- slave registor 1
slv_reg1(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
when b"10" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
-- Respective byte enables are asserted as per write strobes
-- slave registor 2
slv_reg2(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
-- when b"11" => -- do not write to reg3
-- for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
-- if ( S_AXI_WSTRB(byte_index) = '1' ) then
-- -- Respective byte enables are asserted as per write strobes
-- -- slave registor 3
-- slv_reg3(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
-- end if;
-- end loop;
when others =>
command_reg <= command_reg;
done_flag <= done_flag;
slv_reg1 <= slv_reg1;
slv_reg2 <= slv_reg2;
-- slv_reg3 <= slv_reg3;
end case;
end if;
end if;
end if;
end process;
...
-- Add user logic here
-- byte0 byte1 byte2 byte3
slv_reg0 <= done_flag & "0000000" & "00000000" & "00000000" & command_reg;
alu : simple_alu
port map (
clk => S_AXI_ACLK,
rst => slv_reg_wren, -- reset on every write to a register, high active
op => command_reg(1 downto 0),
in0 => slv_reg1,
in1 => slv_reg2,
res => slv_reg3,
done_flag => done_flag
);
-- User logic ends
But when I try to generate the bitstream for my wrapper design which includes the Zync UltraScale+ MPSoC, AXI Interconnect, Processor System Reset and my AXI Peripheral I get the following error:
ERROR: [DRC LUTLP-1] Combinatorial Loop Alert: 1 LUT cells form a combinatorial loop. This can create a race condition. Timing analysis may not be accurate. The preferred resolution is to modify the design to remove combinatorial logic loops. If the loop is known and understood, this DRC can be bypassed by acknowledging the condition and setting the following XDC constraint on any one of the nets in the loop: 'set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets <myHier/myNet>]'. One net in the loop is design_1_i/simple_alu_0/U0/simple_alu_v1_0_S00_AXI_inst/alu/state[0]_i_2_n_0. Please evaluate your design. The cells in the loop are: design_1_i/simple_alu_0/U0/simple_alu_v1_0_S00_AXI_inst/alu/state[0]_i_2.
ERROR: [DRC LUTLP-1] Combinatorial Loop Alert: 1 LUT cells form a combinatorial loop. This can create a race condition. Timing analysis may not be accurate. The preferred resolution is to modify the design to remove combinatorial logic loops. If the loop is known and understood, this DRC can be bypassed by acknowledging the condition and setting the following XDC constraint on any one of the nets in the loop: 'set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets <myHier/myNet>]'. One net in the loop is design_1_i/simple_alu_0/U0/simple_alu_v1_0_S00_AXI_inst/alu/state[1]_i_3_n_0. Please evaluate your design. The cells in the loop are: design_1_i/simple_alu_0/U0/simple_alu_v1_0_S00_AXI_inst/alu/state[1]_i_3.
Please excuse the huge amount of code, I couldn't find a way to show the error with a smaller example.
I tried the solution proposed here:
set_property SEVERITY {Warning} [get_drc_checks LUTLP-1]
But that did nothing. I also tried setting set_property ALLOW_COMBINATORIAL_LOOPS TRUE for the two nets but that leaves me unsure about the functionality of my circuit. I am using Vivado v2018.3, my target is the Ultra96 from Avnet. Any clues?
EDIT: I have updated the code to reflect the current implementation, I get warnings about latches for result_reg, flag_reg and temp_reg. How do I resolve those?
After a long struggle I finally came up with this solution:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity simple_alu is
Port (
clk : in std_logic;
rst : in std_logic;
op : in std_logic_vector (1 downto 0);
in0 : in std_logic_vector (31 downto 0);
in1 : in std_logic_vector (31 downto 0);
res : out std_logic_vector (31 downto 0);
done_flag : out std_logic
);
end simple_alu;
architecture Behavioral of simple_alu is
type state_type is (start, add, sub, mul, pow, done);
signal state, next_state : state_type := start;
signal result, next_result, temp, next_temp, shift_reg, next_shift_reg, zero : std_logic_vector (31 downto 0) := (others => '0');
signal next_done_flag : std_logic := '0';
begin
SYNC_PROC: process (clk, rst)
begin
if rising_edge(clk) then
if (rst = '1') then
state <= start;
else
state <= next_state;
res <= next_result;
result <= next_result;
temp <= next_temp;
shift_reg <= next_shift_reg;
done_flag <= next_done_flag;
end if;
end if;
end process;
--MEALY State-Machine - Outputs based on state and inputs
OUTPUT_DECODE: process (state, result, in0, in1, temp, shift_reg)
begin
next_done_flag <= '0';
next_result <= result;
next_shift_reg <= shift_reg;
next_temp <= temp;
case state is
when start =>
next_result <= std_logic_vector(to_signed(1, 32));
next_temp <= in0;
next_shift_reg <= in1;
when add => next_result <= std_logic_vector(signed(in0) + signed(in1));
when sub => next_result <= std_logic_vector(signed(in0) - signed(in1));
when mul => next_result <= std_logic_vector(resize(signed(in0) * signed(in1), 32));
when pow =>
if (shift_reg(shift_reg'low) = '1') then
next_result <= std_logic_vector(resize(signed(result) * signed(temp), 32));
else
next_result <= result;
end if;
next_temp <= std_logic_vector(resize(signed(temp) * signed(temp), 32));
next_shift_reg <= std_logic_vector(shift_right(signed(shift_reg), 1));
when done => next_done_flag <= '1';
when others =>
end case;
end process;
NEXT_STATE_DECODE: process (state, op, shift_reg, zero)
begin
--declare default state for next_state to avoid latches
next_state <= state; --default is to stay in current state
case (state) is
when start =>
case (op) is
when "00" => next_state <= add;
when "01" => next_state <= sub;
when "10" => next_state <= mul;
when "11" => next_state <= pow;
when others => next_state <= done;
end case;
when add => next_state <= done;
when sub => next_state <= done;
when mul => next_state <= done;
when pow =>
if (shift_reg = zero) then
next_state <= done;
else
next_state <= pow;
end if;
when done =>
when others =>
end case;
end process;
end Behavioral;
The problem was that I did not understand how hardware description works, now I know a little (at least I hope so..). Especially how clocked and unclocked processes are connected (save intermediate results in registers). I will leave this question up just in case another beginner stumbles upon the same issue. If you think I should remove it, please state that in a comment and I will do so.
Here are some resources that helped me:
this question and in particular the accepted answer
some rules I picked up somewhere:
Don't read from the signals to which you write.
Have a correct sensitivity list (all signals that you read should be in the sensitivity list)
Make sure that all signals to which your write are assigned in every path. (for example: in each branch of an if-else-statement)
For processes which use variable, make sure every variable is initialized a default value before reading it (in another variable or signal ).

implementing a 50ns delay in VHDL

I'm sending data to and A/D converter and I need the command data to be delayed at least 50ns from clk_19khz. Here is what I have so far.
How do I insert a delay of 50ns which is a requirement for the A/D between the clk_19khz and my first Dout bit to the A/D?
I'm using a Xilinx FPGA. Thanks for the help!
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;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity PSOL is
Port ( clk : in STD_LOGIC;
clk_19khz : OUT std_logic;
Dout :out std_logic);
end PSOL;
architecture Behavioral of PSOL is
signal temp : std_logic;
signal count : integer range 0 to 1301 := 0; --1301
signal temp2 : std_logic;
signal dcount : integer range 0 to 11 := 0; --
signal start : std_logic := '1'; -- indicates the start of
signal parity : std_logic := '1'; --used to varify data sent
signal stop : std_logic := '0'; --indicate when word/command has
--signal chip_select : bit :='1'; -- active low
begin
process (clk)
begin
if (clk' EVENT AND clk='1') then
if (count = 1301) then --1301
temp <= not(temp);
count <=0;
else
count <= count + 1;
end if;
end if;
end process;
clk_19khz <= temp;
temp2 <= temp;
process (temp2)
begin
If (temp2' EVENT and temp2 ='0') then
dcount <= dcount + 1;
parity <= '1';
stop <= '0';
start <='1';
if (dcount < 12 and start = '1' and stop = '0') then
CASE dcount is
when 1 => Dout <= start; -- need delay 50ns before this
when 2 => Dout <= '0';
when 3 => Dout <= '1';
when 4 => Dout <= '0';
when 5 => Dout <= '1';
when 6 => Dout <= '0';
when 7 => Dout <= '0';
when 8 => Dout <= '1';
when 9 => Dout <= '1';
when 10 => Dout <= parity;
when 11 => Dout <= '0';
when others => null;
end case;
end if;
end if;
--dcount <= 0;
--start <='1';
end process;
end Behavioral;
Your clock (50 MHz) has a period of 20 ns. So you'll need a modulo-3 counter to count a delay of at least 3 clock pulses which gives a delay of 60 ns.
Declarations:
signal delay_en : std_logic;
signal delay_us : unsigned(1 downto 0) := (others => '0');
signal delay_ov : std_logic;
Usage:
process(clk)
begin
if rising_edge(clk) then
if (delay_en = '1') then
delay_us <= delay_us + 1;
else
delay_us <= (others => '0');
end if;
end if;
end process;
delay_ov <= '1' when (delay_us = 2) else '0';
Your current implementation needs to drive delay_en while it's waiting for the timespan. If the delay is over, it emits the signal delay_ov (ov = overflow). This can be used by your solution to go on the in algorithm. Your code should also deassert delay_en, what clears the counter to 0.

How to set a value at moduleEN - VHDL

I've this code:
library IEEE;
use IEEE.std_logic_1164.all;
entity Controller is
port (
CLK : in std_logic;
OutENABLE : out std_logic_vector (2 downto 0);
ModuleRESET : in std_logic;
ModuleENABLE : in std_logic
);
end Controller;
architecture Controller_archi of Controller is
signal Counter : integer range 0 to 4200 := 0;
begin
process (CLK, ModuleRESET)
begin
if ModuleRESET = '0' then
OutENABLE <= (others => '0');
Counter <= 0;
elsif rising_edge(CLK) then
if ModuleENABLE = '1' then
Counter <= Counter + 1;
case Counter is
when 0 =>
OutENABLE <= "001";
when 450 =>
OutENABLE <= "010";
when 900 =>
OutENABLE <= "100";
when 1350 =>
OutENABLE <= "001";
Counter <= 0;
when others =>
end case;
else
OutENABLE <= "000";
end if;
end if;
end process;
end Controller_archi;
But it's not working like I need.
What I need:
When ModuleENABLE goes '1' instantly OutENABLE goes "001" and not at first rising_edge(CLK) (Now, in this code, if ModuleENABLE goes '1' OutENABLE doesn't change from "000" to "001", it change to "001" after first rising_edge(CLK))
Counter go up when rising_edge(CLK) and OutENABLE it's updated every CLK event. (Now, in this code, counter go up when rising_edge(CLK) but OutENABLE it's updated when rising_edge(CLK) and not when CLK goes up and goes down)
So I've modified code to do that:
library IEEE;
use IEEE.std_logic_1164.all;
entity Controller is
port (
CLK : in std_logic;
OutENABLE : out std_logic_vector (2 downto 0);
ModuleRESET : in std_logic;
ModuleENABLE : in std_logic
);
end Controller;
architecture Controller_archi of Controller is
signal Counter : integer range 0 to 4200 := 0;
begin
process (CLK, ModuleENABLE, ModuleRESET)
begin
if ModuleRESET = '0' then
OutENABLE <= (others => '0');
Counter <= 0;
elsif ModuleENABLE = '1' then
if rising_edge(CLK) then
Counter <= Counter + 1;
end if;
case Counter is
when 0 =>
OutENABLE <= "001";
when 450 =>
OutENABLE <= "010";
when 900 =>
OutENABLE <= "100";
when 1350 =>
OutENABLE <= "001";
Counter <= 0;
when others =>
end case;
else
Counter <= 0;
OutENABLE <= "000";
end if;
end process;
end Controller_archi;
Now code work like I need in ModelSim, but when I synthesize it or compile it and simulate again it doesn't work.
My question is:
What it's wrong with second code and how I can fix it?
If I can't fix second code how I can modify first code to work like I need?
What it's wrong with second code and how I can fix it?
Your synthesis tool is fussy about how the clock and reset lines are connected. You have to use a structure like:
if ModuleRESET = '0' then
...
elsif rising_edge(CLK) then
or the synthesis tool cannot recognise the clock and reset lines.
If I can't fix second code how I can modify first code to work like I need?
You need to move "OutENABLE" outside of the first process, and into a process of its own. From what you've said, OutENABLE should not be a register - it should be a combinatorial function of Counter, ModuleRESET and ModuleENABLE. Try this.
process (CLK, ModuleRESET)
begin
if ModuleRESET = '0' then
Counter <= 0;
elsif rising_edge(CLK) then
if ModuleENABLE = '1' then
Counter <= Counter + 1;
case Counter is
when 1350 =>
Counter <= 0;
when others =>
null;
end case;
end if;
end if;
end process;
process (Counter, ModuleRESET, ModuleEnable)
begin
OutENABLE <= "000";
if ModuleRESET = '1' and ModuleENABLE = '1' then
case Counter is
when 0 .. 449 =>
OutENABLE <= "001";
when 450 .. 899 =>
OutENABLE <= "010";
when 900 .. 1349 =>
OutENABLE <= "100";
when others =>
OutENABLE <= "001";
end case;
end if;
end process;

How to send some data 10 times with a delay of 10 ms between chunks of databits to the TX port of uart

I have an sensor it has an unlocked byte sequence which needs to be sent to it to unlock it and then it can receive the other command data.
The sensor receive data at a baudrate of 115200 bps, 8 data bits, even parity, 2 stop bits.
and before receiving any command data( used to set parameters) It needs to recieve d4 (hexadecimal number, byte) 10 times at an interval of 1ms.
I send the d4 converted into bits 11010100 added with parity and stop bits becomes 11010100011 to the TX port of uart at the baud rate of 115200 but how to create a delay between two d4 data byte sent ? I am writing the code if not clear please let me know I would put more details.
entity Uart_tx is
port (
TX : out std_logic;
clk_in : in std_logic;
but_div_clk : out std_logic;
clk_in_2 : in std_logic
);
end Uart_tx;
architecture Behavioral of Uart_tx is
signal tx_clk : std_logic := '0';
signal clk_1Khz : std_logic := '0';
signal q : unsigned(8 downto 0) := (others => '0');
signal p : unsigned(8 downto 0) := (others => '0');
type state_type is (idle, start);
signal state : state_type;
signal tick_in : std_logic := '0';
subtype byte is std_logic_Vector(7 downto 0);
type byte_array is array(natural range <>) of byte;
signal data_byte_array : byte_array(1 to 8);
-- signal curr_byte : std_logic_vector(7 downto 0);
signal byte_index : unsigned(2 downto 0) := "000";
subtype reg is std_logic_Vector(10 downto 0);
type reg_array is array(natural range <>) of reg;
signal TxDataReg_array : reg_array(1 to 8);
signal cur_Tx_reg : std_logic_vector(10 downto 0);
signal current_reg : unsigned(3 downto 0) := "0001";
signal count : unsigned (4 downto 0) := (others => '0');
signal count_d : unsigned (4 downto 0) := (others => '0');
signal sent_d4 : unsigned (3 downto 0) := (others => '0');
signal send_d4 : std_logic := '1';
signal D_4 : std_logic_vector(10 downto 0) :="11000101011";
begin
-- below are random entry ..actual data will come from slv_reg registers.
data_byte_array(1) <= "10101010"; -- slv_reg0(7 downto 0);
data_byte_array(2) <= "10101011"; -- slv_reg0(15 downto 8);
data_byte_array(3) <= "10101010"; -- slv_reg0(23 downto 16);
data_byte_array(4) <= "10101011"; -- slv_reg0(31 downto 24);
data_byte_array(5) <= "10101010"; -- slv_reg1(39 downto 32);
data_byte_array(6) <= "10101011"; -- slv_reg1(47 downto 40);
data_byte_array(7) <= "10101010"; -- slv_reg1(55 downto 48);
data_byte_array(8) <= "10101011"; -- slv_reg1(63 downto 56);
tick_in <= '1';
---------------------------------------Clk_div-----------------------------------------
process ( clk_in ) is
begin
if clk_in'event and clk_in = '1' then
q <= q + 1;
tx_clk <= q(8); --- 58.gdfg/2^8 =~ 230Khz baud rate = 115200
but_div_clk <= tx_clk;
end if;
end process;
---------------------------------------Clk_div------------------------------------------
---------------------------------------Clk_div------------------------------------------
process( clk_in_2 ) is
begin
if clk_in_2'event and clk_in_2 = '1' then
p <= p + 1;
clk_1Khz <= p(7);
end if;
end process;
---------------------------------------------------------------------------------------
--------------------------------------TX_Process----------------------------------------
process( state, tx_clk , tick_in) is
variable parity : std_logic := '0';
variable curr_byte : std_logic_vector(7 downto 0) := (others => '0');
begin
case state is
when idle => TX <= '1';
if tick_in = '1' then
state <= start;
else
TX <= '1';
end if;
when start =>
if send_d4 = '1' then
if (rising_edge(clk_1Khz)) then
case count_d is
when "00000" => TX <= D_4(0);
when "00001" => TX <= D_4(1);
when "00010" => TX <= D_4(2);
when "00011" => TX <= D_4(3);
when "00100" => TX <= D_4(4);
when "00101" => TX <= D_4(5);
when "00110" => TX <= D_4(6);
when "00111" => TX <= D_4(7);
when "01000" => TX <= D_4(8);
when "01001" => TX <= D_4(9);
when "01010" => TX <= D_4(10);
when others => TX <= '1';
end case;
count_d <= count_d +1;
sent_d4 <= sent_d4 + 1;
if to_integer(count_d) = 11 then
count_d <= "00000";
end if;
if to_integer(sent_d4) = 10 then
send_d4 <= '0' ;
end if;
end if;
else
for i in 1 to 8 loop
curr_byte := data_byte_array(i);
parity := '0';
for j in curr_byte'range loop
parity := parity xor curr_byte(j);
end loop;
if parity = '0' then
TxDataReg_array(i) <= "110" & curr_byte ;
else
TxDataReg_array(i) <= "111" & curr_byte ;
end if;
end loop;
cur_Tx_reg <= TxDataReg_array(to_integer(byte_index)+1);
byte_index <= byte_index + 1;
if rising_edge(tx_clk) then
case count is
when "00000" => TX <= cur_Tx_reg(0);
when "00001" => TX <= cur_Tx_reg(1);
when "00010" => TX <= cur_Tx_reg(2);
when "00011" => TX <= cur_Tx_reg(3);
when "00100" => TX <= cur_Tx_reg(4);
when "00101" => TX <= cur_Tx_reg(5);
when "00110" => TX <= cur_Tx_reg(6);
when "00111" => TX <= cur_Tx_reg(7);
when "01000" => TX <= cur_Tx_reg(8);
when "01001" => TX <= cur_Tx_reg(9);
when "01010" => TX <= cur_Tx_reg(10);
when others => TX <= '1';
end case;
count <= count+1;
if to_integer(count) = 11 then
count <= "00000";
state <= idle;
-- TX <= '1';
end if;
end if;
end if;
when others => TX <= '1';
end case;
end process;
end Behavioral;
To get a timed delay you have to implement a counter that ticks off a computed number of clock cycles equal to 1 ms. You then need to insert states into your FSM that activate the counter and wait for it to complete when needed. It is possible to manually calculate the counter value but you can make the tools do the work for you and avoid having magic numbers in your code.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...
constant CLOCK_FREQ : real := 50.0e6; -- 50 MHz system clock
constant SENSOR_DELAY : real := 1.0e-3; -- 1 ms delay
constant DELAY_COUNT : natural := integer(CLOCK_FREQ * SENSOR_DELAY);
-- This could be auto calculated with a ceil_log2() function
constant TIMER_SIZE : natural := 16;
signal timer : unsigned(TIMER_SIZE-1 downto 0);
constant DELAY_INIT : unsigned(timer'range)
:= to_unsigned(DELAY_COUNT, timer'length);
...
-- Initialize the timer sometime before you want the delay
timer <= DELAY_INIT;
...
-- Somewhere in your FSM
when WAIT_1MS =>
timer <= timer - 1;
if timer = 0 then
state <= WHATEVER_YOU_WANT_NEXT;
end if;
This method of using real constants to compute integer values is subject to rounding errors and general floating-point inaccuracies. For these sort of long delays, the small error (typically off-by-one) that could happen isn't usually of concern.
Note that you need to rework your state machine to follow more conventional patterns. You have created a process that mixes pure combinational logic with synchronous. You should not mix the two. You should not have the rising_edge() tests inside your FSM case statement but rather there should be a single if-block evaluating rising_edge() that contains your FSM.
If you need a clock sensitive process then it should only have the clock and an (optional) asynchronous reset in its sensitivity list. Any other pure combinational code should be put in a separate process. In a design such as this that shouldn't be necessary though.
VHDL allows what you have now but synthesis tools expect the use of a more limited style when describing the hardware. You risk having unexpected results if they can handle your code at all.

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