VHDL Parametric Division Circuit - Book: FPGA Prototyping by VHDL Examples, Pong Chu - vhdl

I'm trying to follow an example on my VHDL book. Its name is FPGA Prototyping by VHDL Examples, Pong Chu. It has a Divider Circuit example in Chapter 6, Listing 5. I understood the general idea of a division operation. To verify the module I wrote a testbench and I saw that it doesn't work properly. If anyone could explain to me where the problem is, I would be very appreciated.
Here are the codes of module and testbench.
Module:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Divider is
generic(W: integer := 8;
CBIT: integer := 4 );
Port ( clk, reset : in STD_LOGIC;
start : in STD_LOGIC;
dvsr, dvnd : in STD_LOGIC_VECTOR (W-1 downto 0);
ready, done_tick : out STD_LOGIC;
quo, rmd : out STD_LOGIC_VECTOR (W-1 downto 0));
end Divider;
architecture Behavioral of Divider is
type state_type is (idle, op, last, done);
signal state_reg, state_next: state_type;
signal rh_reg, rh_next: UNSIGNED(W-1 downto 0) := (others => '0');
signal rl_reg, rl_next: STD_LOGIC_VECTOR(W-1 downto 0) := (others => '0');
signal rh_temp: UNSIGNED(W-1 downto 0) := (others => '0');
signal d_reg, d_next: UNSIGNED(W-1 downto 0) := (others => '0');
signal n_reg, n_next: UNSIGNED(CBIT-1 downto 0) := (others => '0');
signal q_bit: STD_LOGIC;
begin
-- FSMD State and Data Registers
process(clk, reset)
begin
if reset = '1' then
state_reg <= idle;
rh_reg <= (others => '0');
rl_reg <= (others => '0');
d_reg <= (others => '0');
n_reg <= (others => '0');
elsif rising_edge(clk) then
state_reg <= state_next;
rh_reg <= rh_next;
rl_reg <= rl_next;
d_reg <= d_next;
n_reg <= n_next;
end if;
end process;
-- FSMD Next-State Logic and Data Path Logic
process(state_reg, n_reg, rh_reg, rl_reg, d_reg, start, dvsr, dvnd, q_bit, rh_temp, n_next)
begin
ready <= '0';
done_tick <= '0';
state_next <= state_reg;
rh_next <= rh_reg;
rl_next <= rl_reg;
d_next <= d_reg;
n_next <= n_reg;
case state_reg is
when idle =>
ready <= '1';
if start = '1' then
rh_next <= (others => '0');
rl_next <= dvnd; -- Dividend
d_next <= UNSIGNED(dvsr); -- Divisor
n_next <= TO_UNSIGNED(W+1, CBIT); -- Index
state_next <= op;
end if;
when op =>
--Shift rh and rl left
rl_next <= rl_reg(W-2 downto 0) & q_bit;
rh_next <= rh_temp(W-2 downto 0) & rl_reg(W-1);
--Decrease index
n_next <= n_reg - 1;
if(n_next = 1) then
state_next <= last;
end if;
when last =>
rl_next <= rl_reg(W-2 downto 0) & q_bit;
rh_next <= rh_temp;
state_next <= done;
when done =>
state_next <= idle;
done_tick <= '1';
end case;
end process;
-- Compare and Subtract
process(rh_reg, d_reg)
begin
if rh_reg <= d_reg then
rh_temp <= rh_Reg - d_reg;
q_bit <= '1';
else
rh_temp <= rh_reg;
q_bit <= '0';
end if;
end process;
-- Output
quo <= rl_reg;
rmd <= STD_LOGIC_VECTOR(rh_reg);
end Behavioral;
Testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity tb_Divider is
-- Port ( );
end tb_Divider;
architecture Behavioral of tb_Divider is
signal clk, reset, start, ready, done: STD_LOGIC;
signal dvsr, dvnd: STD_LOGIC_VECTOR(7 downto 0);
signal quo, rmd: STD_LOGIC_VECTOR(7 downto 0);
component Divider is
port( clk, reset : in STD_LOGIC;
start : in STD_LOGIC;
dvsr, dvnd : in STD_LOGIC_VECTOR (7 downto 0);
ready, done_tick : out STD_LOGIC;
quo, rmd : out STD_LOGIC_VECTOR (7 downto 0));
end component Divider;
begin
UUT: Divider port map( clk => clk, reset => reset, start => start, dvsr => dvsr, dvnd => dvnd,
ready => ready, done_tick => done, quo => quo, rmd => rmd);
process
begin
clk <= '0';
wait for 10 ns;
clk <= '1';
wait for 10 ns;
end process;
process
begin
start <= '0';
dvnd <= x"00";
dvsr <= x"00";
wait for 100 ns;
start <= '1';
dvnd <= x"C8";
dvsr <= x"0A";
wait for 10 us;
end process;
end Behavioral;
Result of Testbench:

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

State machine and unsigned signal

I have a few problems with a fairly simple state machine I made. No matter what I do, the signal startS1, startS2, enS and mS always stays unsigned in simulation even when I hit the reset button and I can't figure out why. There's a component in the mix, but I did test the component and it works perfectly. I hope you can help me!
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity machine_etat is
generic (N_bit : integer := 8);
Port ( LOAD : in STD_LOGIC_VECTOR (N_bit-1 downto 0);
RESET : in STD_LOGIC;
START : in STD_LOGIC;
CLK : in STD_LOGIC;
OUTPUT : out STD_LOGIC_VECTOR (N_bit-1 downto 0));
end machine_etat;
architecture Behavioral of machine_etat is
TYPE machine is (IddleT, DepartT, LoadT, ShiftT, EndT);
SIGNAL Etat1, Etat2 : machine:= IddleT;
SIGNAL mS: STD_LOGIC_VECTOR (1 downto 0);
SIGNAL enS : STD_LOGIC;
SIGNAL outputS : STD_LOGIC_VECTOR (N_bit-1 downto 0);
component Reg_decal is
generic (N_bit : integer := N_bit);
Port ( CLK : in STD_LOGIC;
RESET : in STD_LOGIC;
EN : in STD_LOGIC;
M : in STD_LOGIC_VECTOR (1 downto 0);
LOAD : in STD_LOGIC_VECTOR (N_bit-1 downto 0);
OUTPUT : out STD_LOGIC_VECTOR (N_bit-1 downto 0));
end component;
SIGNAL startS1, startS2 : STD_LOGIC;
begin
OUTPUT <= outputS;
Reg_dec: Reg_decal
generic map (N_bit => N_bit)
port map (CLK => CLK,
RESET => RESET,
EN => enS,
M => mS,
LOAD => LOAD,
OUTPUT => outputS);
Machine1: process (CLK)
begin
if RESET = '1' then
enS <= '0';
mS <= "00";
startS1 <= '0';
startS2 <= '0';
Etat1 <= IddleT;
elsif rising_edge(CLK) then
CASE Etat1 is
WHEN IddleT =>
if startS1 = '1' OR START = '1' then
Etat1 <= DepartT;
else
Etat1 <= IddleT;
end if;
WHEN DepartT =>
Etat1 <= LoadT;
startS1 <= '0';
WHEN LoadT =>
mS <= "11";
enS <= '1';
Etat1 <= ShiftT;
WHEN ShiftT =>
mS <= "00";
Etat1 <= EndT;
WHEN EndT =>
enS <= '0';
startS2 <= '1';
Etat1 <= IddleT;
WHEN Others =>
Etat1 <= IddleT;
end CASE;
end if;
end process;
Machine2: process (CLK)
begin
if RESET = '1' then
Etat2 <= IddleT;
elsif rising_edge(CLK) then
CASE Etat2 is
WHEN IddleT =>
if startS2 = '1' then
Etat2 <= DepartT;
else
Etat2 <= IddleT;
end if;
WHEN DepartT =>
startS2 <= '0';
Etat2 <= LoadT;
WHEN LoadT =>
enS <= '1';
Etat2 <= ShiftT;
WHEN ShiftT =>
mS <= "01";
Etat2 <= EndT;
WHEN EndT =>
Etat2 <= IddleT;
startS1 <= '1';
WHEN Others =>
end CASE;
end if;
end process;
end Behavioral;
Add RESET to your process sensitivity list.

Modelsim Altera VHDL MEMORY ROM

I am confused on to why my VHDL design is not working. I am to create a top.vhd file that will program an FPGA board to display addresses 0 through 15 and the corresponding values to each address. When I simulate my design, all the clocks and resets work. The problem I am having is my FSM processes and Address process. I know there is a lot going on here, so if you need clarification I can answer your questions.
library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.all;
entity top is
port(Clock : in std_logic;
Reset : in std_logic;
SW : in std_logic_vector (1 downto 0);
HEX2, HEX4: out std_logic_vector ( 6 downto 0);
KEY0: in std_logic);
end entity;
architecture top_arch of top is
component char_decoder is
port(BIN_IN : in std_logic_vector (3 downto 0);
HEX_OUT : out std_logic_vector (6 downto 0));
end component;
component rom_16x4_sync is
port (clock: in std_logic;
address: in std_logic_vector (3 downto 0);
rom_en: in std_logic;
data_out: out std_logic_vector(3 downto 0));
end component;
type state_type is (start, read_rom, clear_addr, done);
signal current_state, next_state : state_type;
signal Rom_en, addr_count_clr, addr_count_en : std_logic;
signal address_counter : integer range 0 to 15;
signal address_uns : unsigned (3 downto 0);
signal clock_slow : std_logic;
signal rom_out : std_logic_vector (3 downto 0);
begin
char : char_decoder port map (BIN_IN => rom_out, HEX_OUT => HEX2);
char1 : char_decoder port map (BIN_IN => std_logic_vector(address_uns), HEX_OUT => HEX4);
clock_slow <= Clock;
rom : rom_16x4_sync port map (clock => clock_slow, address => std_logic_vector(address_uns), rom_en => Rom_en, data_out => rom_out);
State_Memory : process (clock_slow, Reset)
begin
if (Reset = '0') then
current_state <= start;
elsif (clock_slow'event and clock_slow = '1') then
current_state <= next_state;
end if;
end process;
NEXT_STATE_LOGIC : process (current_state)
begin
case (current_state) is
when start => if (KEY0 = '0') then
next_state <= read_rom;
else next_state <= start;
end if;
when read_rom => if (address_counter = 15) then
next_state <= clear_addr;
else
address_counter <= address_counter + 1;
end if;
when clear_addr => next_state <= done;
address_counter <= 0;
when done => next_state <= done;
end case;
end process;
OUTPUT_LOGIC : process (current_state)
begin
case (current_state) is
when start => Rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
when read_rom => Rom_en <= '1';
addr_count_en <= '1';
addr_count_clr <= '0';
when clear_addr => Rom_en <= '0';
addr_count_en <= '1';
addr_count_clr <= '1';
when done => Rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
end case;
end process;
Address_Count : process (addr_count_en, addr_count_clr, clock_slow)
begin
if (clock_slow'event and clock_slow = '1') then
if (addr_count_en = '1') then
if (addr_count_clr = '1') then
address_uns <= "0000";
else
address_uns <= address_uns + 1;
end if;
end if;
end if;
end process;
address_uns <= to_unsigned(address_counter,4);
end architecture;
I commented on what I could see wrong with your code:
address_counter isn't clocked and is redundant. Remove the assignments and change the comparison to address_uns (which should also go into the sensitivity list) in process NEXT_STATE_LOGIC. Remove the concurrent signal assignment to address_uns following process Address_Counter. If processes Address_Count and OUTPUT_LOGIC are correct as well as rom_16x4_sync you should have something that works.
Well I had most the bits and pieces sitting around from other questions to gen a complete MCVE together with little effort mostly by copying and pasting and that gave:
As you can see that didn't work, and the reason why is that address_uns needs to be reset (it's default value is all 'U's).
Adding a reset gives:
So the gist of this is that your state machine was almost correct, it was missing the address counter in it's sensitivity list and had two address counters. Limiting that to one and resetting it so you weren't adding 1 to all 'U's shows your state machine is working.
And the code with all the fixes:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity char_decoder is
port (
bin_in: in std_logic_vector (3 downto 0);
hex_out: out std_logic_vector (6 downto 0)
);
end entity;
architecture dummy of char_decoder is
-- seven segment display
--
-- a
-- f b
-- g
-- e c
-- d
--
-- SEGMENT is defined (g downto a)
--
type segment7 is array (integer range 0 to 15) of
std_logic_vector (6 downto 0);
constant hex_to_segment: segment7 := (
"1000000", -- 0
"1111001", -- 1
"0100100", -- 2
"0110000", -- 3
"0011001", -- 4
"0010010", -- 5
"0000010", -- 6
"1111000", -- 7
"0000000", -- 8
"0011000", -- 9
"0001000", -- A
"0000011", -- b
"0111001", -- C
"0100001", -- d
"0000110", -- E
"0001110" -- F
);
begin
process (bin_in)
variable seg7_val: integer range 0 to 15;
begin
seg7_val := to_integer(unsigned(bin_in));
hex_out <= hex_to_segment(seg7_val);
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rom_16x4_sync is
port (
clock: in std_logic;
address: in std_logic_vector (3 downto 0);
rom_en: in std_logic;
data_out: out std_logic_vector(3 downto 0)
);
end entity;
architecture dummy of rom_16x4_sync is
type rom_array is array (0 to 15) of std_logic_vector(3 downto 0);
function fill_rom return rom_array is
variable ret_val: rom_array;
begin
for i in rom_array'reverse_range loop -- backward to i
ret_val(i) := std_logic_vector(to_unsigned(i,4));
end loop;
return ret_val;
end function;
constant rom: rom_array := fill_rom;
begin
process (clock)
begin
if rising_edge(clock) and rom_en = '1' then -- NO RESET
data_out <= rom(to_integer(unsigned(address)));
end if;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity top is
port (
clock: in std_logic;
reset: in std_logic;
sw: in std_logic_vector (1 downto 0); -- not used?
hex2, hex4: out std_logic_vector ( 6 downto 0);
key0: in std_logic
);
end entity;
architecture top_arch of top is
component char_decoder is
port (
bin_in: in std_logic_vector (3 downto 0);
hex_out: out std_logic_vector (6 downto 0)
);
end component;
component rom_16x4_sync is
port (
clock: in std_logic;
address: in std_logic_vector (3 downto 0);
rom_en: in std_logic;
data_out: out std_logic_vector(3 downto 0)
);
end component;
type state_type is (start, read_rom, clear_addr, done);
signal current_state,
next_state: state_type;
signal rom_en,
addr_count_clr,
addr_count_en: std_logic;
-- signal address_counter: integer range 0 to 15;
signal address_uns: unsigned (3 downto 0);
signal clock_slow: std_logic;
signal rom_out: std_logic_vector (3 downto 0);
begin
char:
char_decoder
port map (
bin_in => rom_out,
hex_out => hex2
);
char1:
char_decoder
port map (
bin_in => std_logic_vector(address_uns),
hex_out => hex4
);
clock_slow <= clock;
rom:
rom_16x4_sync
port map (
clock => clock_slow,
address => std_logic_vector(address_uns),
rom_en => rom_en, data_out => rom_out
);
state_memory:
process (clock_slow, reset)
begin
if reset = '0' then
current_state <= start;
elsif clock_slow'event and clock_slow = '1' then
current_state <= next_state;
end if;
end process;
next_state_logic:
-- process (current_state)
process (current_state, address_uns)
begin
case (current_state) is
when start =>
if key0 = '0' then
next_state <= read_rom;
else
next_state <= start;
end if;
when read_rom =>
if address_uns = 15 then
next_state <= clear_addr;
-- else
-- address_counter <= address_counter + 1;
end if;
when clear_addr => -- not a defined sequential logic inference
next_state <= done;
-- address_counter <= 0;
when done =>
next_state <= done;
end case;
end process;
output_logic:
process (current_state)
begin
case (current_state) is
when start =>
rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
when read_rom =>
rom_en <= '1';
addr_count_en <= '1';
addr_count_clr <= '0';
when clear_addr =>
rom_en <= '0';
addr_count_en <= '1';
addr_count_clr <= '1';
when done =>
rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
end case;
end process;
address_count:
process (addr_count_en, addr_count_clr, clock_slow)
begin
if reset = '0' then -- added reset
address_uns <= (others =>'0');
elsif clock_slow'event and clock_slow = '1' then
if addr_count_en = '1' then
if addr_count_clr = '1' then
address_uns <= "0000";
else
address_uns <= address_uns + 1;
end if;
end if;
end if;
end process;
-- address_uns <= to_unsigned(address_counter, 4);
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity top_tb is
end entity;
architecture foo of top_tb is
signal clock: std_logic := '0';
signal reset: std_logic := '1';
signal sw: std_logic_vector (1 downto 0) := "00";
signal hex2, hex4: std_logic_vector ( 6 downto 0);
signal key0: std_logic := '0';
begin
DUT:
entity work.top
port map (
clock => clock,
reset => reset,
sw => sw,
hex2 => hex2,
hex4 => hex4,
key0 => key0
);
CLK:
process
begin
wait for 5 ns;
clock <= not clock;
if now > 200 ns then
wait;
end if;
end process;
STIMULIS:
process
begin
wait for 1 ns;
reset <= '0';
wait for 10 ns;
reset <= '1';
wait for 10 ns;
wait;
end process;
end architecture;
The char_decoder I used should be fully functional. The ROM contents are simply dummied up.

Change VHDL testbench and 32bit-ALU with clock to one without

I wrote this VHDL-program vor an ALU and its testbench that is working:
ALU-code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU_CLK is
port( Clk : in std_logic; --clock signal
InRegA,InRegB : in signed(31 downto 0); --input operands
InOp : in unsigned(2 downto 0); --Operation to be performed
OutReg : out signed(31 downto 0); --output of ALU
OutZero : out std_logic
);
end ALU_CLK;
architecture Behavioral of ALU_CLK is
signal Reg1,Reg2,Reg3 : signed(31 downto 0) := (others => '0');
begin
Reg1 <= INregA;
Reg2 <= InRegB;
OutReg <= Reg3;
process(Clk)
variable temp: signed(31 downto 0);
begin
if(rising_edge(Clk)) then
case InOp is
when "010" =>
temp := Reg1 + Reg2; --addition
when "000" =>
temp := Reg1 and Reg2; --AND gate
when "001" =>
temp := Reg1 or Reg2; --OR gate
when others =>
NULL;
end case;
if temp = (31 downto 0=>'0') then
OutZero <= '1';
else
OutZero <= '0';
end if;
Reg3 <= temp;
end if;
end process;
end Behavioral;
The testbench code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY tb IS
END tb;
ARCHITECTURE ALU_CLK OF tb IS
signal Clk : std_logic := '0';
signal A,B,R : signed(31 downto 0) := (others => '0');
signal Op : unsigned(2 downto 0) := (others => '0');
signal zero : std_logic :='0';
constant Clk_period : time := 10 ns;
BEGIN
uut: entity work.ALU_CLK PORT MAP (
Clk => Clk,
InRegA => A,
InRegB => B,
InOp => Op,
OutReg => R,
OutZero => zero
);
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
wait for Clk_period*1;
--test normal operations
A <= "00000000000000000000000000010011"; --19 in decimal
B <= "00000000000000000000000000001100"; --12 in decimal
Op <= "000"; wait for Clk_period; --Bitwise and A and B
Op <= "001"; wait for Clk_period; --Bitwise or B from A.
Op <= "010"; wait for Clk_period; --addition A nad B
wait;
end process;
END;
To shorten the code listings a bit I did not post all the operations the ALU does.
I can manage it to change the ALU to one without the clk but how can I test it with a testbench?
Even in a test bench for a module without a clock, it may be a good idea to have
a clock that can time the test events, and make it easier to see the test
progress in waveforms.
So after removal of the clock from the ALU, the test bench process can control
stimuli and do the checks like:
-- Combined stimuli and check process
process is
begin
...
-- === 2 + 2 test ===
-- Stimuli control
wait until rising_edge(clk);
InRegA <= to_signed(2, InRegA'length);
InRegB <= to_signed(2, InRegA'length);
InOp <= "010"; -- Add
-- Output check
wait until falling_edge(clk);
assert OutReg = InRegA + InRegB;
assert (OutZero = '1') = (OutReg = 0);
...
end process;
To simplify the check part, it can be moved to a separate process and the check
can be made depending on the operation like:
-- Check process
process (clk) is
begin
if falling_edge(clk) then
if check then
-- OutReg check
case InOp is
when "010" => assert OutReg = InRegA + InRegB; -- Add
when "000" => assert OutReg = (InRegA and InRegB); -- And
when "001" => assert OutReg = (InRegA or InRegB); -- Or
when others => report "Unsupported operation" severity ERROR;
end case;
-- OutZero check
assert (OutZero = '1') = (OutReg = 0);
end if;
end if;
end process;
The check signal is controlled by the stimuli process, to guard when the
check is to be made, in order to avoid false errors in startup or for other
special conditions.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity alu32bit is
port(en:in STD_LOGIC;
opc:in STD_LOGIC_VECTOR(3 downto 0);
a_in,b_in:in STD_LOGIC_VECTOR(31 downto 0);
y_op:out STD_LOGIC_VECTOR(31 downto 0));
end alu32 bit;
architecture Behavioral of alu32 bit is
begin
Process(en,a_in,b_in,opc)
begin
if(en='1')then
when "0001"=>y_op<=a_in+b_in;
when "0010"=>y_op<=a_in-b_in;
when "0011"=>y_op<=not a_in;
when "0100"=>y_op<=a_in and b_in;
when "0101"=>y_op<=a_in or b_in;
when "0110"=>y_op<=a_in nand b_in;
when "0111"=>y_op<=a_in xor b_in;
when others=>null;
end case;
else
y_op<="ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
end if;
end process;
end Behavioral;
In the end I got this:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU_32 is
port(
InRegA,InRegB : in signed(31 downto 0); --input operands
InOp : in unsigned(2 downto 0); --Operation to be performed
OutReg : out signed(31 downto 0); --output of ALU
OutZero : out std_logic
);
end ALU_32;
architecture Behavioral of ALU_32 is
--temporary signal declaration.
signal Reg1,Reg2,Reg3 : signed(31 downto 0) := (others => '0');
begin
Reg1 <= InRegA;
Reg2 <= InRegB;
OutReg <= Reg3;
process(InOp, InRegA, inRegB)
variable temp: signed(31 downto 0);
begin
case InOp is
when "010" =>
temp := Reg1 + Reg2; --addition
when "110" =>
temp := Reg1 - Reg2; --subtraction
when "000" =>
temp := Reg1 and Reg2; --AND gate
when "001" =>
temp := Reg1 or Reg2; --OR gate
when "100" =>
temp := Reg1 nor Reg2; --NOR gate
when "011" =>
temp := Reg1 xor Reg2; --XOR gate
when "101" =>
temp := not Reg1; --NOT gate
when "111" =>
if Reg1 < Reg2 then --SLT (set on less than) gate
temp := (others => '1');
else
temp := (others => '0');
end if;
when others =>
NULL;
end case;
if temp = (31 downto 0=>'0') then
OutZero <= '1';
else
OutZero <= '0';
end if;
Reg3 <= temp;
end process;
end Behavioral;
And the working testbench is:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
ENTITY tb2 IS
END tb2;
ARCHITECTURE ALU_32 OF tb2 IS
COMPONENT ALU_32
PORT(
InRegA : IN signed(31 downto 0);
InRegB : IN signed(31 downto 0);
InOp : IN unsigned(2 downto 0);
OutReg : OUT signed(31 downto 0);
OutZero : OUT std_logic
);
END COMPONENT;
--Inputs
signal InRegA : signed(31 downto 0) := (others => '0');
signal InRegB : signed(31 downto 0) := (others => '0');
signal InOp : unsigned(2 downto 0) := (others => '0');
--Outputs
signal OutReg : signed(31 downto 0);
signal OutZero : std_logic;
-- No clocks detected in port list. Replace <clock> below with
-- appropriate port name
--constant <InOp>_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: ALU_32 PORT MAP (
InRegA => InRegA,
InRegB => InRegB,
InOp => InOp,
OutReg => OutReg,
OutZero => OutZero
);
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
-- insert stimulus here
--test normal operations
InRegA <= "00000000000000000000000000010011"; --19 in decimal
InRegB <= "00000000000000000000000000001100"; --12 in decimal
InOp <= "000"; wait for 100 ns; --Bitwise and A and B
InOp <= "001"; wait for 100 ns; --Bitwise or B from A.
InOp <= "010"; wait for 100 ns; --addition A nad B
InOp <= "100"; wait for 100 ns; --Bitwise NOR of A and B
InOp <= "011"; wait for 100 ns; --Bitwise XOR of A and B
InOp <= "110"; wait for 100 ns; --substract A and B
InOp <= "101"; wait for 100 ns; --Bitwise NOT of A
InOp <= "111"; wait for 100 ns; --Bitwise SLT of A and B
-- test SLT the other way around
InRegB <= "00000000000000000000000000010011"; --19 in decimal
InRegA <= "00000000000000000000000000001100"; --12 in decimal
InOp <= "111"; wait for 100 ns; --Bitwise SLT of A and B
-- test Branch equal that substraction is 0 and zero is 1
InRegA <= "00000000000000000000000000001011"; --11 in decimal
InRegB <= "00000000000000000000000000001011"; --11 in decimal
InOp <= "110"; wait for 100 ns; --substract A and B
wait;
end process;
END;
Here is the result of the simulation:

FSM model of FIR filter

I want to make a FSM model of FIR, for that I need to write FIR calculation code line in FSM implementation.
Here is the actual and correct code for FIR
entity fir_4tap is
port( Clk : in std_logic; --clock signal
Clk_fast : in std_logic;
-- Xin : in signed(7 downto 0); --input signal
bit_in : in std_logic;
bit_out : out std_logic;
Yout : out signed(15 downto 0) --filter output
);
end fir_4tap;
architecture Behavioral of fir_4tap is
signal add_out3 : signed(15 downto 0) := (others => '0');
signal index : unsigned(2 downto 0) := (others =>'0');
signal counter : unsigned(3 downto 0) := (others => '0');
signal p : unsigned(1 downto 0) := (others => '0');
signal k : unsigned(1 downto 0) := (others => '0');
signal j : unsigned(1 downto 0) := (others => '0');
type array_signed is array(8 downto 0) of signed(7 downto 0);
signal z : array_signed := (others => "00000000");
type array_signed1 is array(3 downto 0) of signed(7 downto 0);
signal H : array_signed1 := (others => "00000000");
signal Xin : array_signed1 := (others => "00000000");
begin
z(0) <= to_signed(-3,8);
z(1) <= to_signed(1,8);
z(2) <= to_signed(0,8);
z(3) <= to_signed(-2,8);
z(4) <= to_signed(-1,8);
z(5) <= to_signed(4,8);
z(6) <= to_signed(-5,8);
z(7) <= to_signed(6,8);
z(8) <= to_signed(0,8);
H(0) <= to_signed(-2,8);
H(1) <= to_signed(-1,8);
H(2) <= to_signed(3,8);
H(3) <= to_signed(4,8);
process (clk)
begin
if (rising_edge(Clk)) then
index <= index +1;
if (index = "111") then
Xin(to_integer(p)) <= z(to_integer(counter)); k <= p;
p <= p + 1;
***-- This part of the code has problem, I want to write the line which is summing --up for add_out3 in a for loop.***
add_out3 <= (others => '0');
add_out3 <= Xin(to_integer(k))*H(to_integer(j)) + Xin(to_integer(k-1))*H(to_integer(j+1)) + Xin(to_integer(k-2))*H(to_integer(j+2)) + Xin(to_integer(k-3))*H(to_integer(j+3));
Yout <= add_out3;
end if;
end if;
end process;
end Behavioral;
Now Below is the FSM implementation try by me but not getting the same out sample as input can somebody tell me what could be the problem in the code?
----------------FSM implementation of the FIR filter ----------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity test is
port( Clk : in std_logic; --clock signal
Clk_fast : in std_logic;
bit_in : in std_logic;
bit_out : out std_logic;
Yout : out signed(15 downto 0) --filter output
);
end test;
architecture Behavioral of test is
signal data_buffer : signed(7 downto 0) := (others => '0');
signal index : unsigned(2 downto 0) := (others =>'0');
signal counter : unsigned(3 downto 0) := (others => '0');
type array_signed is array(8 downto 0) of signed(7 downto 0);
signal z : array_signed := (others => "00000000");
type array_signed1 is array(3 downto 0) of signed(7 downto 0);
signal H : array_signed1 := (others => "00000000");
signal input : signed(7 downto 0) := (others => '0');
type MULT_TYPE is array(3 downto 0) of signed(15 downto 0);
signal MULT_array : MULT_TYPE := (others => "0000000000000000");
type ADD_TYPE is array(3 downto 0) of signed(15 downto 0);
signal ADD_array : ADD_TYPE := (others => "0000000000000000");
constant ZERO : signed(15 downto 0) := (others => '0');
type state_type is (s0,s1,s2,s3); --type of state machine.
signal current_s : state_type := s0; --current and next state declaration.
signal next_s : state_type := s0;
signal reset : std_logic := '0';
signal go : std_logic := '0';
signal change_state : std_logic := '0' ;
signal counter_FSM_monitor : unsigned( 6 downto 0) := "0000000";
begin
z(0) <= to_signed(-3,8);
z(1) <= to_signed(1,8);
z(2) <= to_signed(0,8);
z(3) <= to_signed(-2,8);
z(4) <= to_signed(-1,8);
z(5) <= to_signed(4,8);
z(6) <= to_signed(-5,8);
z(7) <= to_signed(6,8);
z(8) <= to_signed(0,8);
H(0) <= to_signed(-2,8);
H(1) <= to_signed(-1,8);
H(2) <= to_signed(3,8);
H(3) <= to_signed(4,8);
process (Clk) is
begin
if falling_edge(Clk) then
data_buffer(to_integer(index)) <= bit_in;
index <= index +1;
if (index = "111") then
input <= z(to_integer(counter));
counter <= counter + 1;
if(counter = "1000") then
counter <= "0000";
end if;
end if;
end if;
end process;
process (clk_fast)
begin
if (falling_edge(clk_fast)) then
counter_FSM_monitor <= counter_FSM_monitor + 1;
if( to_integer(counter_FSM_monitor) = 76) then
counter_FSM_monitor <= "0000000";
end if;
case change_state is
when '1' =>
current_s <= next_s; --state change.
when '0' => --current_s <= s0;
when others =>
end case;
end if;
end process;
Process(current_s,input)
begin
if ( to_integer(counter_FSM_monitor) < 64 ) then
-- waiting for the Input
elsif (to_integer(counter_FSM_monitor) >= 64 and to_integer(counter_FSM_monitor) < 76) then
---------------------------------------------- FSM ----------------------------------------
case current_s is
when s0 =>
mult_array(0) <= input*H(3);
ADD_array(0) <= ZERO + mult_array(0);
next_s <= s1;
change_state <= '1';
when s1 =>
mult_array(1) <= input*H(2);
ADD_array(1) <= mult_array(1) + ADD_array(0);
next_s <= s2;
change_state <= '1';
when s2 =>
mult_array(2) <= input*H(1);
ADD_array(2) <= mult_array(2) + ADD_array(1);
next_s <= s3;
change_state <= '1';
when s3 =>
mult_array(3) <= input*H(0);
ADD_array(3) <= mult_array(3) + ADD_array(2);
Yout <= ADD_array(3);
next_s <= s0;
change_state <= '1';
when others =>
next_s <= s0;-- never comes here
change_state <= '1';
end case;
---------------------------------------------- FSM ----------------------------------------
end if;
end process;
end Behavioral;
How ever I am not able to receive the same output which I received by the first code.
FSM code gives the correct output for the first out but from the second out sample it gives wrong result.Can somebody tell me what I am doing wrong ?
This answer is for the initial version of the question but Now question has been changed.
Made add_out3 a variable instead of a signal.
for i in 0 to 3 loop
add_out3 := add_out3 + Xin(k-i)*H(i);
end loop;
Did the above changes in the for loop It works fine.
So the code in my question is a correct code for FIR also, works smoothly.
Learnt that one needs to be very careful while using signal or variables. All the signals get a new value at the same time i.e at the end of clock period, while in variables values gets updated as assigned within a process. Tried to run the simulation step by step and figured out the problem.

Resources