dual port RAM write data - vhdl

I little bit confused with dual port RAM,my target is write and read data.I want to write data.like on the certain address will be 128 and on the rest adresses will be just 0.Is it works correctly,because Im not sure that those case statements are useful? How to write correctly data in this RAM?
I reading this article
and I think I need true dual port Ram.I have next code.
library ieee;
use ieee.std_logic_1164.all;
entity true_dual_port_ram_single_clock is
generic (
DATA_WIDTH : natural := 8;
ADDR_WIDTH : natural := 6
);
port (
clk : in std_logic;
addr_a : in natural range 0 to 2**ADDR_WIDTH - 1;
addr_b : in natural range 0 to 2**ADDR_WIDTH - 1;
data_a : in std_logic_vector((DATA_WIDTH-1) downto 0);
data_b : in std_logic_vector((DATA_WIDTH-1) downto 0);
we_a : in std_logic := '1';
we_b : in std_logic := '1';
q_a : out std_logic_vector((DATA_WIDTH -1) downto 0);
q_b : out std_logic_vector((DATA_WIDTH -1) downto 0)
);
end true_dual_port_ram_single_clock;
architecture rtl of true_dual_port_ram_single_clock is
-- Build a 2-D array type for the RAM
subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0);
type memory_t is array((2**ADDR_WIDTH - 1) downto 0) of word_t;
-- Declare the RAM signal.
shared variable ram : memory_t;
begin
process(clk)
begin
if(rising_edge(clk)) then -- Port A
if(we_a = '1') then
ram(addr_a) := data_a;
-- Read-during-write on the same port returns NEW data
case addr_a is
when 0 =>
q_a <= "10000000";
when 16 =>
q_a <= "10000000";
when others =>
q_a <="00000000";
end case;
q_a <= data_a;
else
-- Read-during-write on the mixed port returns OLD data
case addr_a is
when 0 =>
q_a <= "10000000";
when 16 =>
q_a <= "10000000";
when others =>
q_a <="00000000";
end case;
q_a <= ram(addr_a);
end if;
end if;
end process;
process(clk)
begin
if(rising_edge(clk)) then -- Port B
if(we_b = '1') then
case addr_a is
when 0 =>
q_b <= "10000000";
when 16 =>
q_b <= "10000000";
when others =>
q_b <="00000000";
end case;
ram(addr_b) := data_b;
-- Read-during-write on the same port returns NEW data
q_b <= data_b;
else
-- Read-during-write on the mixed port returns OLD data
if(we_b = '1') then
case addr_b is
when 0 =>
q_b <= "10000000";
when 16 =>
q_b <= "10000000";
when others =>
q_b <="00000000";
end case;
q_b <= ram(addr_b);
end if;
end if;
end if;
end process;
end rtl;

Related

Error (10818): Can't infer register because it does not hold its value outside the clock edge, how to fix it?

I have this code for a ram in VHDL and I get the following error while synthesis:
Error (10818): Can't infer register for "data_table[19][13]" at RAM.vhd(50) because it does not hold its value outside the clock edge
any help would be appreciated!
here is the code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity RAM is
port (
clk, wr_en : in std_logic;
address: in std_logic_vector (9 downto 0);
data_in : in std_logic_vector (15 downto 0);
data_out: out std_logic_vector (15 downto 0)
);
end entity RAM;
architecture RAM_Arch of RAM is
type Memory is array (0 to 1023) of std_logic_vector (15 downto 0);
signal data_table : Memory := (others => (others => '0'));
begin
process (clk)
variable init : boolean := true;
begin
if init = true then
-- some initiation
data_table(0) <= "0001010000011010";
data_table(1) <= "0011110000001000";
data_table(2) <= "0011110000010000";
data_table(3) <= "0011110000100000";
data_table(4) <= "0011110000000001";
data_table(10) <= "0001010000011100";
data_table(11) <= "0100000000000001";
data_table(12) <= "0011110000000001";
data_table(13) <= "0011110000000010";
data_table(14) <= "0011110000000100";
data_table(15) <= "0011110000001000";
data_table(16) <= "0011110000010000";
data_table(17) <= "0011110000100000";
-- data_table(18) <= "0011110001000000";
data_table(19) <= "1011110000010000";
-- data_table(19) <= "1011110000000001";
-- data_table(20) <= "1011110000000010";
-- data_table(21) <= "1011110000000100";
-- data_table(22) <= "1011110000001000";
-- data_table(24) <= "1011110000100000";
-- data_table(25) <= "1011110001000000";
-- data_table(26) <= "1011110010000000";
init := false;
end if;
if clk'event and clk = '1' then
if wr_en = '1' then -- Writing :)
data_table(to_integer(unsigned(address))) <= data_in;
end if;
end if;
end process;
data_out <= data_table(to_integer(unsigned(address)));
end architecture RAM_Arch;
If your code must be synthesized never put non-synchronous assignments in a synchronous process. Try:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ram is
port (
clk, wr_en: in std_logic;
address: in std_logic_vector(9 downto 0);
data_in : in std_logic_vector(15 downto 0);
data_out: out std_logic_vector(15 downto 0)
);
end entity ram;
architecture ram_arch of ram is
type memory is array (0 to 1023) of std_logic_vector (15 downto 0);
signal data_table: memory := (
0 => "0001010000011010",
1 => "0011110000001000",
2 => "0011110000010000",
3 => "0011110000100000",
4 => "0011110000000001",
10 => "0001010000011100",
11 => "0100000000000001",
12 => "0011110000000001",
13 => "0011110000000010",
14 => "0011110000000100",
15 => "0011110000001000",
16 => "0011110000010000",
17 => "0011110000100000",
-- 18 => "0011110001000000",
19 => "1011110000010000",
-- 19 => "1011110000000001",
-- 20 => "1011110000000010",
-- 21 => "1011110000000100",
-- 22 => "1011110000001000",
-- 24 => "1011110000100000",
-- 25 => "1011110001000000",
-- 26 => "1011110010000000",
others => (others => '0'));
begin
process (clk)
begin
if rising_edge(clk) then
if wr_en = '1' then -- writing :)
data_table(to_integer(unsigned(address))) <= data_in;
end if;
end if;
end process;
data_out <= data_table(to_integer(unsigned(address)));
end architecture ram_arch;
Note: you should probably not use std_logic. If you do not know the difference with std_ulogic prefer the latter. Same with std_logic_vector: prefer std_ulogic_vector.

How can i reduce number of ALMs in my VHDL design?

I'm trying to implement an alarm module for the digital clock in VHDL. I have written architecture for it, but when I run Compilation I get too many Adaptive Logic Modules (around 2000), which I think is too much. I will post my code below.
I think division and modulus operation could be causing it, in this line of code.
alarm_hour1 <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length));
alarm_hour0 <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));
Still, I'm not sure how can I work around this.
Also, I would be very grateful if You give more comments on my design, and point out some mistakes, and ways how I can improve my design. I'm fairly new to VHDL so any advice is appreciated.
Thanks a lot.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity alarm is
port(
--INPUTS
reset : in std_logic;
clock : in std_logic;
alarm_enable : in std_logic;
alarm_set : in std_logic;
alarm_increment : in std_logic;
alarm_decrement : in std_logic;
currentTime_hour1 : in std_logic_vector(3 downto 0);
currentTime_hour0 : in std_logic_vector(3 downto 0);
currentTime_minute1 : in std_logic_vector(3 downto 0);
currentTime_minute0 : in std_logic_vector(3 downto 0);
--OUTPUTS
alarm_buzzer : out std_logic;
alarm_hour1 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_hour0 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_minute1 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_minute0 : buffer std_logic_vector(3 downto 0) := "0000"
);
end alarm;
architecture alarmBehaviour of alarm is
--ALARM TIME
signal savedHours : integer := 0;
signal savedMinutes : integer := 0;
signal incrementDecrementbuttonDetect : std_logic;
signal set_lastButtonState : std_logic := '0';
signal setButtonDetect : std_logic := '0';
--STATE MACHINE
type state_type is (idle, setHour, setMinute);
signal state_reg, state_next : state_type;
begin
incrementDecrementbuttonDetect <= alarm_increment or alarm_decrement;
--STATE REGISTER
process(clock, reset)
begin
if (reset = '1') then
state_reg <= idle;
elsif rising_edge(clock) then
state_reg <= state_next;
end if;
end process;
--SET BUTTON PRESSED
process(clock)
begin
if(rising_edge(clock)) then
if(alarm_set = '1' and set_lastButtonState = '0') then
setButtonDetect <= '1';
else
setButtonDetect <= '0';
end if;
set_lastButtonState <= alarm_set;
end if;
end process;
--NEXT STATE
process(state_reg, setButtonDetect)
begin
case state_reg is
when idle =>
if setButtonDetect = '1' then
state_next <= setHour;
else
state_next <= idle;
end if;
when setHour =>
if setButtonDetect = '1' then
state_next <= setMinute;
else
state_next <= setHour;
end if;
when setMinute =>
if setButtonDetect = '1' then
state_next <= idle;
else
state_next <= setMinute;
end if;
end case;
end process;
process (incrementDecrementbuttonDetect, state_reg)
begin
if rising_edge(incrementDecrementbuttonDetect) then
case state_reg is
when idle =>
when setHour =>
if alarm_increment = '1' then
if savedHours = 23 then
savedHours <= 0;
else
savedHours <= savedHours + 1;
end if;
else null;
end if;
if alarm_decrement = '1' then
if savedHours = 0 then
savedHours <= 23;
else
savedHours <= savedHours - 1;
end if;
else null;
end if;
when setMinute =>
if alarm_increment = '1' then
if savedMinutes = 59 then
savedMinutes <= 0;
else
savedMinutes <= savedMinutes + 1;
end if;
else null;
end if;
if alarm_decrement = '1' then
if savedMinutes = 0 then
savedMinutes <= 59;
else
savedMinutes <= savedMinutes - 1;
end if;
else null;
end if;
end case;
end if;
end process;
alarm_hour1 <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length));
alarm_hour0 <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));
--ALARM BUZZER CONDITION
process (currentTime_hour1, currentTime_hour0, currentTime_minute1, currentTime_minute0,
alarm_enable, alarm_hour1, alarm_hour0, alarm_minute1, alarm_minute0)
begin
if((alarm_hour1 = currentTime_hour1) and (alarm_hour0 = currentTime_hour0)
and (alarm_minute1 = currentTime_minute1) and (alarm_minute0 = currentTime_minute0) and alarm_enable = '1') then
alarm_buzzer <= '1';
else
alarm_buzzer <= '0';
end if;
end process;
end alarmBehaviour;
Consider keeping the alarm time in Binary-Coded Decimal (BCD) format instead of binary format, whereby you can compare it directly with the current time, that is provided in BCD format.
This is a good example of how using the appropriate internal data format can reduce the computational problem significantly, since you can simply eliminate the costly division and modulo operations by keeping just one data format (BCD) instead of mixing BCD and binary data formats.
The range of signals savedHours and savedMinutes is not specified, so Quartus assumes they are 32 bits wide. Inference of a divider with one 32-bit operand results into a large tree of conditional subtractions.
Updating your code to something like
--ALARM TIME
signal savedHours : natural range 0 to 23 := 0;
signal savedMinutes : natural range 0 to 59 := 0;
will very likely result into less ALM usage.
Also, please note that rising_edge should be used for clock signals only (at VHDL starter level). Instead of connecting logic to the clock input of a register, what you probably want is some button debounce logic.

Trying to display on 640x480 vga display with fpga

I am literally writing this in desperation. i've tried some many times to make it work and it just doesn't.
im using Altera DE2 board - Cyclone II EP2C35F672C6 & been trying to display simple image on 640x480 vga screen.
im using a vga controller design i made for a different board- Altera DE1 which worked really good.
the difference on this DE2 board is a different DAC component which has 10bit rgb data instead of 4bit like in the DE1 board, and it has extra needed ouputs - VGA_SYNC, VGA_BLANK, VGA_CLK.
So i made the needed changes & found an example where it says to set VGA_BLANK to '1' constant and VGA_SYNC to '0'. VGA_CLK is connected to the 25.175 Mhz pixel clk which is the pll clk output.
i've tried so many variations & tried to use another example where they set vga_blank to '1' when in visable aread & '0' when not and it still didnt work. i just get a black screen saying no video input when i run the design.
below is the implementation of my timing generator, data_generator & vga_top_level
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.vga_consts.all;
entity vga_toplevel is
port
(
-- in --
clk, rst : in std_logic;
-- out --
vga_clk, vga_blank, vga_sync : out std_logic;
r_data, g_data, b_data : out std_logic_vector(9 downto 0);
h_sync, v_sync : out std_logic
);
end entity;
architecture structural of vga_toplevel is
component pll
port
(
areset : IN STD_LOGIC := '0';
inclk0 : IN STD_LOGIC := '0';
c0 : OUT STD_LOGIC ;
locked : OUT STD_LOGIC
);
end component;
component timing_generator
port
(
clk, rst : in std_logic;
h_cnt : out integer range 0 to h_frame-1;
v_cnt : out integer range 0 to v_frame-1;
vga_blank, vga_sync : out std_logic;
h_sync, v_sync : out std_logic
);
end component;
component data_generator
generic
(
vis_x : integer := visable_x;
vis_y : integer := visable_y
);
port
(
clk, rst : in std_logic;
h_cnt : in integer range 0 to h_frame-1;
v_cnt : in integer range 0 to v_frame-1;
-- RGB values
r_data, g_data, b_data : out std_logic_vector(9 downto 0)
);
end component;
signal h_cnt, v_cnt : integer range 0 to h_frame-1;
signal pll_clk, rst_out, locked : std_logic;
-------------------------------------------------------------------
begin
rst_out <= not locked; -- uncomment for PLL use
vga_clk <= pll_clk;
-- rst_out <= rst; -- comment for PLL use
-- pll_clk <= clk; -- comment for PLL use
PLL1: pll
port map
(
inclk0 => clk,
areset => rst,
c0 => pll_clk,
locked => locked
);
T_GEN: timing_generator
port map
(
-- in --
clk => pll_clk,
rst => rst_out,
-- out --
vga_blank => vga_blank,
vga_sync => vga_sync,
v_cnt => v_cnt,
h_cnt => h_cnt,
v_sync => v_sync,
h_sync => h_sync
);
D_GEN: data_generator
port map
(
-- in --
clk => pll_clk,
rst => rst_out,
v_cnt => v_cnt,
h_cnt => h_cnt,
r_data => r_data,
g_data => g_data,
b_data => b_data
);
end architecture;
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.vga_consts.all;
entity timing_generator is
port
(
clk, rst : in std_logic;
h_cnt : out integer range 0 to h_frame-1;
v_cnt : out integer range 0 to v_frame-1;
vga_blank : out std_logic;
vga_sync : out std_logic;
h_sync, v_sync : out std_logic
);
end entity;
architecture behave of timing_generator is
signal h_cnt_inner : integer range 0 to h_frame-1;
signal v_cnt_inner : integer range 0 to v_frame-1;
begin
vga_blank <= '1';
vga_sync <= '0';
h_cnt <= h_cnt_inner;
v_cnt <= v_cnt_inner;
-- counter for pixels --
process (clk, rst)
begin
if rst = '1' then
h_cnt_inner <= 0;
elsif rising_edge(clk) then
if h_cnt_inner = h_frame-1 then
h_cnt_inner <= 0;
else
h_cnt_inner <= h_cnt_inner + 1;
end if;
end if;
end process;
-- counter for lines --
process (clk, rst)
begin
if rst = '1' then
v_cnt_inner <= 0;
elsif rising_edge(clk) then
if v_cnt_inner = v_frame-1 then
v_cnt_inner <= 0;
elsif h_cnt_inner = 654 then
v_cnt_inner <= v_cnt_inner + 1;
end if;
end if;
end process;
-- h_sync generator --
process (clk, rst)
begin
if rst = '1' then
h_sync <= '1';
elsif rising_edge(clk) then
if h_cnt_inner = h_sync_d(0)-1 then
h_sync <= '0';
elsif h_cnt_inner = h_sync_d(1) then
h_sync <= '1';
end if;
end if;
end process;
-- v_sync generator --
process(clk, rst)
begin
if rst = '1' then
v_sync <= '1';
elsif rising_edge(clk) then
if v_cnt_inner = v_sync_d(0) then
v_sync <= '0';
elsif v_cnt_inner = v_sync_d(1) + 1 then
v_sync <= '1';
end if;
end if;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.vga_consts.all;
entity data_generator is
generic (
vis_x : integer := visable_x;
vis_y : integer := visable_y
);
port
(
clk, rst : in std_logic;
h_cnt : in integer range 0 to h_frame-1;
v_cnt : in integer range 0 to v_frame-1;
-- RGB values for each pixel
r_data, g_data, b_data : out std_logic_vector(9 downto 0)
);
end entity;
architecture behave of data_generator is
begin
-- process to handle only 1 color - blue screen
process(clk, rst)
begin
if rst = '1' then
r_data <= (others => '0');
g_data <= (others => '0');
b_data <= (others => '0');
elsif rising_edge(clk) then
if (h_cnt >= h_vis_d(0)) and (h_cnt < h_vis_d(1)) and (v_cnt >= v_vis_d(0)) and (v_cnt < v_vis_d(1)) then
-- if in visiable area
r_data <= (others => '1');
g_data <= (others => '1');
b_data <= (others => '1');
else
r_data <= (others => '0');
g_data <= (others => '0');
b_data <= (others => '0');
end if;
end if;
end process;
end architecture;

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 ).

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.

Resources