ALU implementation w/ ADDER - logic

Hello I'm trying to create a 32-bit adder with a few opcodes and I've got it working quite well except for two cases and I can't seem to find what's causing them.. Maybe you can help me?
The subtraction case always fails for some reason and the ADDC case fails to compute the correct output when it should be using the carry bit in c_reg that has been created by the ADDS operation.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY ALU IS
GENERIC(WIDTH : NATURAL := 32);
PORT(Clk : IN STD_LOGIC := '0';
Reset : IN STD_LOGIC := '0';
A : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
B : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
Op : IN STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '0');
Outs : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END ALU;
ARCHITECTURE arch_ALU OF ALU IS
COMPONENT adder
PORT(OpA : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
OpB : IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
Cin : IN STD_LOGIC;
Cout : OUT STD_LOGIC;
Result : OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0));
END COMPONENT;
SIGNAL adder_output : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL B_neg : STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL c_flag : STD_LOGIC := '0';
SIGNAL c_reg : STD_LOGIC := '0';
SIGNAL cin : STD_LOGIC := '0';
BEGIN
adder_comp : adder
PORT MAP(OpA => A,
OpB => B_neg,
Cin => cin,
Result => adder_output,
Cout => c_flag);
WITH Op SELECT
B_neg <= NOT(B) WHEN "1000",
B WHEN OTHERS;
WITH Op SELECT
cin <= '1' WHEN "1000", -- SUB
c_reg WHEN "0111", -- ADDC
'0' WHEN OTHERS; -- ADD/ADDS
ALU_Process:
PROCESS(Clk)
BEGIN
IF Reset = '0' THEN
Outs <= (OTHERS => '0');
ELSIF rising_edge(Clk) THEN
CASE Op IS
WHEN "0001" => Outs <= A AND B;
WHEN "0010" => Outs <= A OR B;
WHEN "0011" => Outs <= A NOR B;
WHEN "0100" => Outs <= A XOR B;
WHEN "0101" => Outs <= adder_output; -- ADD
WHEN "0110" => Outs <= adder_output; -- ADDS
c_reg <= c_flag;
WHEN "0111" => Outs <= adder_output; -- ADDC
WHEN "1000" => Outs <= adder_output; -- SUB
WHEN "1001" => Outs <= STD_LOGIC_VECTOR(UNSIGNED(A) SLL to_integer(UNSIGNED(B(4 DOWNTO 0))));
WHEN "1010" => Outs <= STD_LOGIC_VECTOR(unsigned(A) SRL to_integer(UNSIGNED(B(4 DOWNTO 0))));
WHEN "1011" => Outs <= STD_LOGIC_VECTOR(shift_right(SIGNED(A),to_integer(UNSIGNED(B(4 DOWNTO 0)))));
WHEN OTHERS => Outs <= (OTHERS => '0');
END CASE;
END IF;
END PROCESS;
END arch_ALU;
Only the ADDS operation should write it's carry-out to the c_reg and ADDC operation should take the c_reg into account when calculating it's output
The adder is tested and working correctly so the problem is not in the adder design.
First of all I'd like to get to know the problem of the subtraction because it is doing subtraction but the result is a little bit off.. For example:
A : h'E6A4960F
B : h'7B494E34
Op : d'1000
Outs: h'6B5B47DA while it should be h'6B5B47DB
A : h'EFDE31A3
B : h'0BCAB8FA
Op : d'1000
Out : h'E41378BB while should be h'E41378A9
Can you spot my misstake? Cause I certainly can't..

While you didn't provide a Minimal, Complete, and Verifiable example the reader can at least test the subtract portions of your design that are present:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity alu is
generic (width: natural := 32);
port (
clk: in std_logic := '0';
reset: in std_logic := '0';
a: in std_logic_vector(width - 1 downto 0) := (others => '0');
b: in std_logic_vector(width - 1 downto 0) := (others => '0');
op: in std_logic_vector(3 downto 0) := (others => '0');
outs: out std_logic_vector(width - 1 downto 0)
);
end alu;
architecture arch_alu of alu is
-- component adder
-- port (
-- opa: in std_logic_vector(width - 1 downto 0);
-- opb: in std_logic_vector(width - 1 downto 0);
-- cin: in std_logic;
-- cout: out std_logic;
-- result: out std_logic_vector(width - 1 downto 0)
-- );
-- end component;
procedure adder (
signal opa: in std_logic_vector(width - 1 downto 0);
signal opb: in std_logic_vector(width - 1 downto 0);
signal cin: in std_logic;
signal cout: out std_logic;
signal result: out std_logic_vector(width - 1 downto 0)
) is
variable sum: unsigned (width downto 0);
begin
sum := unsigned('0' & opa) + unsigned(opb) + unsigned'(""& cin);
result <= std_logic_vector(sum (width - 1 downto 0));
cout <= sum(width);
end procedure;
signal adder_output: std_logic_vector(width - 1 downto 0) := (others => '0');
signal b_neg: std_logic_vector(width - 1 downto 0) := (others => '0');
signal c_flag: std_logic := '0';
signal c_reg: std_logic := '0';
signal cin: std_logic := '0';
begin
adder_comp:
adder
-- port map (
(
opa => a,
opb => b_neg,
cin => cin,
result => adder_output,
cout => c_flag
);
with op select
b_neg <= not b when "1000",
b when others;
with op select
cin <= '1' when "1000", -- sub
c_reg when "0111", -- addc
'0' when others; -- add/adds
alu_process:
process(clk)
begin
if reset = '0' then
outs <= (others => '0');
elsif rising_edge(clk) then
case op is
when "0001" => outs <= a and b;
when "0010" => outs <= a or b;
when "0011" => outs <= a nor b;
when "0100" => outs <= a xor b;
when "0101" => outs <= adder_output; -- add
when "0110" => outs <= adder_output; -- adds
c_reg <= c_flag;
when "0111" => outs <= adder_output; -- addc
when "1000" => outs <= adder_output; -- sub
when "1001" => outs <= std_logic_vector (
unsigned(a) sll to_integer(unsigned(b(4 downto 0)))
);
when "1010" => outs <= std_logic_vector (
unsigned(a) srl to_integer(unsigned(b(4 downto 0)))
);
when "1011" => outs <= std_logic_vector (
shift_right(signed(a),to_integer(unsigned(b(4 downto 0))))
);
when others => outs <= (others => '0');
end case;
end if;
end process;
end arch_alu;
library ieee;
use ieee.std_logic_1164.all;
entity alu_tb is
end entity;
architecture foo of alu_tb is
constant width: integer := 32;
signal clk: std_logic := '0';
signal reset: std_logic := '0';
signal a: std_logic_vector(width - 1 downto 0) := (others => '0');
signal b: std_logic_vector(width - 1 downto 0) := (others => '0');
signal op: std_logic_vector(3 downto 0) := (others => '0');
signal outs: std_logic_vector(width - 1 downto 0);
begin
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 90 ns then
wait;
end if;
end process;
DUT:
entity work.alu
port map (
clk => clk,
reset => reset,
a => a,
b => b,
op => op,
outs => outs
);
STIMULUS:
process
begin
wait for 20 ns;
reset <= '1';
a <= x"E6A4960F";
b <= x"7B494E34";
op <= "1000";
wait for 20 ns;
a <= x"EFDE31A3";
b <= x"0BCAB8FA";
wait for 20 ns;
wait;
end process;
end architecture;
I wrote a quick and dirty procedure adder. This eliminates your adder entity/architecture and the component declaration.
I added a simple testbench for the two subtractions, this eliminates your test bench or testing procedure.
And this gives:
And as you can see the results are what you claim as correct.
So what that leaves is either your adder or your testbench (it's a stretch to blame your component declaration).
So what we get from this is that you haven't presented enough information to determine where the error is.
I did this little demonstration because the two errors don't have all the wrong bits in common. If you've tested your adder and are sure of it, it's probably the stimulus input when subtracting.

Related

vhdl: object subtype is not locally static

using GHDL to compile some VHDL getting a weird error. simulation compiler for VHDL fails on line: "case i_cli_adr is" with error message: "vhdl: object subtype is not locally static". How to fix it?
library ieee;
use ieee.std_logic_1164.all;
entity sim_regs is
generic(
LW : integer := 16
);
port(
i_sys_clk : in std_logic;
i_sys_rst_n : in std_logic;
i_cli_vld : in std_logic;
i_cli_wnr : in std_logic;
i_cli_adr : in std_logic_vector(LW-1 downto 0);
i_cli_dat : in std_logic_vector(LW-1 downto 0);
);
end entity;
architecture sim of sim_regs is
signal testreg0 : std_logic_vector(LW-1 downto 0);
signal testreg1 : std_logic_vector(LW-1 downto 0);
signal awrite : std_logic;
begin
awrite <= i_cli_vld and i_cli_wnr;
process(i_sys_clk)
begin
if (i_sys_clk = '1' and i_sys_clk'event) then
if (i_sys_rst_n = '0') then
testreg0 <= (others => '0');
testreg1 <= (others => '0');
end if;
else
o_cli_rvld <= '0';
if (awrite = '1') then
case i_cli_adr is
when 0 => testreg0 <= i_cli_dat;
when 1 => testreg1 <= i_cli_dat;
end case;
end if;
end if;
end process;
end architecture;
The fix was to hard code the size of address internally
architecture sim of sim_regs is
signal aaddr : std_logic_vector(15 downto 0);
begin
aaddr <= i_cli_adr and X"FFFF";
--- now can use aaddr in place of i_cli_adr in "case"
Complete Example:
library ieee;
use ieee.std_logic_1164.all;
use IEEE.numeric_std.all;
entity sim_regs is
generic(
LW : integer := 16
);
port(
i_sys_clk : in std_logic;
i_sys_rst_n : in std_logic;
i_cli_vld : in std_logic;
i_cli_wnr : in std_logic;
i_cli_adr : in std_logic_vector(LW-1 downto 0);
i_cli_dat : in std_logic_vector(LW-1 downto 0);
o_cli_rdat : out std_logic_vector(LW-1 downto 0);
o_cli_rvld : out std_logic;
i_cli_rbsy : in std_logic
);
end entity;
architecture sim of sim_regs is
signal testreg0 : std_logic_vector(LW-1 downto 0);
signal testreg1 : std_logic_vector(LW-1 downto 0);
signal testreg2 : std_logic_vector(LW-1 downto 0);
signal testreg3 : std_logic_vector(LW-1 downto 0);
signal aaddr : std_logic_vector(15 downto 0);
signal awrite : std_logic;
signal aread : std_logic;
begin
awrite <= i_cli_vld and i_cli_wnr;
aread <= i_cli_vld and not i_cli_wnr and not i_cli_rbsy;
aaddr <= i_cli_adr and X"FFFF";
process(i_sys_clk)
begin
if (i_sys_clk = '1' and i_sys_clk'event) then
if (i_sys_rst_n = '0') then
o_cli_rvld <= '0';
o_cli_rdat <= (others => '0');
testreg0 <= (others => '0');
testreg1 <= (others => '0');
testreg2 <= (others => '0');
testreg3 <= (others => '0');
end if;
else
o_cli_rvld <= '0';
if (awrite = '1') then
case aaddr is
when X"0000" => testreg0 <= i_cli_dat;
when X"0001" => testreg1 <= i_cli_dat;
when X"0002" => testreg2 <= i_cli_dat;
when X"0003" => testreg3 <= i_cli_dat;
when others => null;
end case;
elsif (aread = '1') then
o_cli_rvld <= '1';
case aaddr is
when X"0000" => o_cli_rdat <= testreg0;
when X"0001" => o_cli_rdat <= testreg1;
when X"0002" => o_cli_rdat <= testreg2;
when X"0003" => o_cli_rdat <= testreg3;
when others => o_cli_rdat <= (others => '0');
end case;
end if;
end if;
end process;
end architecture;

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

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:

4-Bit ALU to BCD display

I have a mega-assignment and the last part(for extra marks) is to display the output of a designed ALU using two 7-seg displays. These should display the result of the operations performed in the ALU. I am performing logical and arithmetic operations and I can only use the lower display for logical operations. For the arithmetic operations I need to use BCD code to display the answers. My ALU is working fine, I am finding it hard to do the decoder part. I don't even know if I am on the right track. Help!
CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
entity codeALU is
Port ( A : in STD_LOGIC_VECTOR (3 downto 0);
B : in STD_LOGIC_VECTOR (3 downto 0);
Cin : in STD_LOGIC;
S0 : in STD_LOGIC;
S1 : in STD_LOGIC;
M : in STD_LOGIC;
Cout : out STD_LOGIC;
Z : out STD_LOGIC;
F : out STD_LOGIC_VECTOR (3 downto 0);
bcd1 : out STD_LOGIC_VECTOR (6 downto 0);
bcd2 : out STD_LOGIC_VECTOR (6 downto 0));
end codeALU;
architecture Behavioral of codeALU is
begin
process(A, B, M, Cin, S1, S0)
variable temp : STD_LOGIC_VECTOR (4 downto 0);
variable Fx : STD_LOGIC_VECTOR (3 downto 0);
variable Cx, Zx : STD_LOGIC;
variable Sel : STD_LOGIC_VECTOR (2 downto 0);
begin
Sel := S1 & S0 & Cin;
Cx := '0';
Zx := '0';
if M = '0' then
Z <= '0';
case Sel(2 downto 1) is
when "00" =>
Fx := A AND B;
Zx := '0';
when "01" =>
Fx := A XOR B;
when "10" =>
Fx := A OR B;
when "11" =>
Fx := A XNOR B;
when others =>
null;
end case;
case Fx is
when "0000"=> bcd1 <="0000001"; -- '0'
when "0001"=> bcd1 <="1001111"; -- '1'
when "0010"=> bcd1 <="0010010"; -- '2'
when "0011"=> bcd1 <="0000110"; -- '3'
when "0100"=> bcd1 <="1001100"; -- '4'
when "0101"=> bcd1 <="0100100"; -- '5'
when "0110"=> bcd1 <="0100000"; -- '6'
when "0111"=> bcd1 <="0001111"; -- '7'
when "1000"=> bcd1 <="0000000"; -- '8'
when "1001"=> bcd1 <="0000100"; -- '9'
when others=> bcd1 <="1111111";
end case;
else
case Sel is
when "000" =>
temp := (B(3)&B(3 downto 1) + ('0'&A));
Fx := temp(3 downto 0);
Cx := temp(4);
when "001" =>
temp := (A(3)&A(3 downto 1) + ('0'&B));
Fx := temp(3 downto 0);
Cx := temp(4);
when "010" =>
temp := ('0'&A) + ('0'&B);
Fx := temp(3 downto 0);
Cx := temp(4);
when "011" =>
temp := ('0'&A) + ('0'&B) + ('0'&Cin);
Fx := temp(3 downto 0);
Cx := temp(4);
when "100" =>
temp := ('0'&A) + (not B);
Fx := temp(3 downto 0);
Cx := temp(4);
when "101" =>
temp := (not B) + ('0'&A) + 1;
Fx := temp(3 downto 0);
Cx := temp(4);
when "110" =>
temp := ('0'&A) + ('0'&B(3 downto 1));
Fx := temp(3 downto 0);
Cx := temp(4);
when "111" =>
temp := ('0'&B) + ('0'&A(3 downto 1));
Fx := temp(3 downto 0);
Cx := temp(4);
when others =>
null;
end case;
case Fx is
when "0000"=> bcd2 <="0000001"; -- '0'
when "0001"=> bcd2 <="1001111"; -- '1'
when "0010"=> bcd2 <="0010010"; -- '2'
when "0011"=> bcd2 <="0000110"; -- '3'
when "0100"=> bcd2 <="1001100"; -- '4'
when "0101"=> bcd2 <="0100100"; -- '5'
when "0110"=> bcd2 <="0100000"; -- '6'
when "0111"=> bcd2 <="0001111"; -- '7'
when "1000"=> bcd2 <="0000000"; -- '8'
when "1001"=> bcd2 <="0000100"; -- '9'
when others=> bcd2 <="1111111";
end case;
for i in 0 to 3 loop
Zx := Zx or Fx(i);
end loop;
Z <= not Zx;
end if;
F <= Fx;
Cout <= Cx;
end process;
end Behavioral;
Test Bench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_arith.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY test4ALU IS
END test4ALU;
ARCHITECTURE behavior OF test4ALU IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT codeALU
PORT(
A : IN std_logic_vector(3 downto 0);
B : IN std_logic_vector(3 downto 0);
Cin : IN std_logic;
S0 : IN std_logic;
S1 : IN std_logic;
M : IN std_logic;
Cout : OUT std_logic;
Z : OUT std_logic;
F : OUT std_logic_vector(3 downto 0);
bcd1 : OUT std_logic_vector(6 downto 0);
bcd2 : OUT std_logic_vector(6 downto 0)
);
END COMPONENT;
--Inputs
signal A : std_logic_vector(3 downto 0) := (others => '0');
signal B : std_logic_vector(3 downto 0) := (others => '0');
signal Cin : std_logic := '0';
signal S0 : std_logic := '0';
signal S1 : std_logic := '0';
signal M : std_logic := '0';
--Outputs
signal Cout : std_logic;
signal Z : std_logic;
signal F : std_logic_vector(3 downto 0) := (others => '0');
signal bcd1 : std_logic_vector(6 downto 0);
signal bcd2 : std_logic_vector(6 downto 0);
-- No clocks detected in port list. Replace <clock> below with
-- appropriate port name
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: codeALU PORT MAP (
A => A,
B => B,
Cin => Cin,
S0 => S0,
S1 => S1,
M => M,
Cout => Cout,
Z => Z,
F => F,
bcd1 => bcd1,
bcd2 => bcd2
);
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
A <= "1001";
B <= "1111";
M <= '0';
wait for 50 ns;
S1 <= '0';
S0 <= '0';
wait for 50 ns;
S1 <= '0';
S0 <= '1';
wait for 50 ns;
S1 <= '1';
S0 <= '0';
wait for 50 ns;
S1 <= '1';
S0 <= '1';
wait for 50 ns;
M <= '1';
S1 <= '0';
S0 <= '0';
Cin <= '0';
wait for 50 ns;
S1 <= '0';
S0 <= '0';
Cin <= '1';
wait for 50 ns;
S1 <= '0';
S0 <= '1';
Cin <= '0';
wait for 50 ns;
S1 <= '0';
S0 <= '1';
Cin <= '1';
wait for 50 ns;
S1 <= '1';
S0 <= '0';
Cin <= '0';
wait for 50 ns;
S1 <= '1';
S0 <= '0';
Cin <= '1';
wait for 50 ns;
S1 <= '1';
S0 <= '1';
Cin <= '0';
wait for 50 ns;
S1 <= '1';
S0 <= '1';
Cin <= '1';
wait;
end process;
process
begin
for i in 0 to 9 loop
F <= conv_std_logic_vector(i,4);
wait for 50 ns;
end loop;
end process;
END;
You've issue in your test bench:
Within codeALU entity is F defined as out signal. Within you test bench signal F is used to map F out from component codeALU. In the name less process below in test bench the signal F gets value: F <= conv_std_logic_vector(i,4);
It's unusable behavior. You see it in modelsim as red X's (not defined).

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