procedure in VHDL returns unknown - vhdl

I have to compare functional and rtl codes. The following code is written as a structural code for twoscomponent of a 16 bit input. I have tried to code the following circuit:
Here I have enclosed the code and the test-bench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity two_s_complement_16bit_rtl is
Port ( A : in STD_LOGIC_VECTOR (15 downto 0);
Cout : out STD_LOGIC_VECTOR (15 downto 0):= (others => '0'));
end two_s_complement_16bit_rtl;
architecture Behavioral of two_s_complement_16bit_rtl is
procedure two_s_complement (
A : in std_logic;
B : in std_logic;
C : out std_logic;
cout : out std_logic;
cin : in std_logic) is
begin
cout := ((not A) and B) xor (((not A) xor B) and cin);
end procedure;
begin
process (A)
variable temp_C, temp_Cout: STD_LOGIC_VECTOR(15 downto 0);
constant B_0 : STD_LOGIC := '1';
constant B_1 : STD_LOGIC := '0';
begin
for i in 0 to 15 loop
if (i = 0) then
two_s_complement ( A(i), B_0 ,temp_C(i) ,temp_Cout(i) , B_1);
else
two_s_complement ( A(i), B_1 ,temp_C(i) ,temp_Cout(i) , temp_C(i-1));
end if;
end loop;
Cout <= temp_Cout;
end process;
end Behavioral;
The test-bench:
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
entity two_s_complement_16bit_rtl_tb is
end;
architecture bench of two_s_complement_16bit_rtl_tb is
component two_s_complement_16bit_rtl
Port ( A : in STD_LOGIC_VECTOR (15 downto 0);
Cout : out STD_LOGIC_VECTOR (15 downto 0):= (others => '0'));
end component;
signal A: STD_LOGIC_VECTOR (15 downto 0);
signal Cout: STD_LOGIC_VECTOR (15 downto 0):= (others => '0');
begin
uut: two_s_complement_16bit_rtl port map ( A => A,
Cout => Cout );
stimulus: process
begin
-- Put initialisation code here
A <= "0100010010110000";
wait for 10 ns;
A <= "0011000011110111";
wait for 10 ns;
A <= "0000000000000001";
wait for 10 ns;
A <= "0011110010110011";
wait for 10 ns;
A <= "0010000100100001";
wait for 10 ns;
A <= "0001011100100011";
wait for 10 ns;
A <= "1011000110111001";
wait for 10 ns;
A <= "0000001011001010";
wait for 10 ns;
A <= "0011110110100000";
wait for 10 ns;
A <= "0100000111111000";
wait for 10 ns;
A <= "1011111001111100";
wait for 10 ns;
A <= "1111000110000001";
wait for 10 ns;
A <= "0111000111001011";
wait for 10 ns;
A <= "1011011101101010";
wait for 10 ns;
A <= "1111001001010111";
wait for 10 ns;
-- Put test bench stimulus code here
wait;
end process;
end;
I have considered three inputs for the first unit, but two of them Cin and B have their constant values as mentioned in the code, but the output is unknown.

There are three apparent errors.
First the two_s_complement procedure does not assign C which is easy to fix:
procedure
two_s_complement (
a: in std_logic;
b: in std_logic;
c: out std_logic;
cout: out std_logic;
cin: in std_logic
) is
variable inta: std_logic := not a;
begin
c := inta xor b xor cin; -- ADDED
cout := ((not a) and b) xor (((not a) xor b) and cin);
-- cout := (inta and b) or (inta and cin);
end procedure;
This is shown as a full adder with the a input inverted.
Second, you've got an incorrect association for cin in the procedure calls:
for i in 0 to 15 loop
if i = 0 then
two_s_complement (
a => a(i),
b => b_0,
c => temp_c(i),
cout => temp_cout(i),
cin => b_1
);
else
two_s_complement (
a => a(i),
b => b_1,
c => temp_c(i),
cout => temp_cout(i),
cin => temp_cout(i - 1) -- WAS temp_c(i-1)
);
end if;
The error stands out when you use named association.
Third the cout output of two_s_complement_16bit_rtl should be assigned from temp_c:
cout <= temp_c; -- WAS temp_cout;
Fixing these three things gives:
something that looks right.
The two's complement can be simplified by delivering not A to an increment circuit where all the unneeded gates are streamlined along with eliminating the B input. You'd find for instance that the LSB is never affected.

Related

16-bit adder outputs wrong results for some numbers

Here is the code I have written for a 16 bit adder - The results of this files should be compared with a adder written in functional format: A+B, so they should make sense. The files are uploaded here:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Full_Adder_16 is
Port ( a : in STD_LOGIC_VECTOR (15 downto 0);
b : in STD_LOGIC_VECTOR (15 downto 0);
s : out STD_LOGIC_VECTOR (15 downto 0));
end Full_Adder_16;
architecture Behavioral of Full_Adder_16 is
component Full_Adder
port(x, y, cin: in std_logic;
sum, cout: out std_logic);
end component;
type cinout is array (0 to 15) of std_logic;
signal c : cinout;
signal cout : STD_LOGIC;
begin
c(0) <= '0';
adding: for i in 15 downto 0 generate
leftmost: if i=15 generate
Full_Adder_15: Full_Adder port map (x => a(i), y => b(i), cin => c(i), sum => s(i), cout => cout);
end generate;
otherwise: if i/=15 generate
Full_Adder_x: Full_Adder port map (x => a(i), y => b(i), cin => c(i), sum => s(i), cout => c(i+1));
end generate;
end generate;
end Behavioral;
And here is the testbench:
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
entity Full_Adder_16_tb is
end;
architecture bench of Full_Adder_16_tb is
component Full_Adder_16
Port ( a : in STD_LOGIC_VECTOR (15 downto 0);
b : in STD_LOGIC_VECTOR (15 downto 0);
s : out STD_LOGIC_VECTOR (15 downto 0));
end component;
signal a: STD_LOGIC_VECTOR (15 downto 0);
signal b: STD_LOGIC_VECTOR (15 downto 0);
signal s: STD_LOGIC_VECTOR (15 downto 0);
begin
uut: Full_Adder_16 port map ( a => a,
b => b,
s => s );
stimulus: process
begin
-- Put initialisation code here
A <= "0100010010110000";
B <= "0001010111011110";
wait for 10 ns;
A <= "0011000011110111";
B <= "0100000101000001";
wait for 10 ns;
A <= "0000000000000001";
B <= "0010011000000111";
wait for 10 ns;
A <= "0011110010110011";
B <= "1000111101011110";
wait for 10 ns;
A <= "0010000100100001";
B <= "1111101000100111";
wait for 10 ns;
A <= "0001011100100011";
B <= "0101101101101101";
wait for 10 ns;
A <= "1011000110111001";
B <= "1001011001011111";
wait for 10 ns;
A <= "0000001011001010";
B <= "1000011011101011";
wait for 10 ns;
A <= "0011110110100000";
B <= "1100111000000010";
wait for 10 ns;
A <= "0100000111111000";
B <= "0001001111100101";
wait for 10 ns;
A <= "1011111001111100";
B <= "0100001101010111";
wait for 10 ns;
A <= "1111000110000001";
B <= "1010000100001110";
wait for 10 ns;
A <= "0111000111001011";
B <= "1011000111010100";
wait for 10 ns;
A <= "1011011101101010";
B <= "1100111100101110";
wait for 10 ns;
A <= "1111001001010111";
B <= "0110010000100001";
wait for 10 ns;
A <= "0111111101101100";
B <= "0111000100001111";
wait for 10 ns;
A <= "0000111101111000";
B <= "1100011111101100";
wait for 10 ns;
A <= "0011100001100111";
B <= "1010101100100000";
wait for 10 ns;
A <= "1111111101000111";
B <= "0110111101011100";
wait for 10 ns;
A <= "0011111101000001";
B <= "1100100001100100";
wait for 10 ns;
A <= "1011011111000111";
B <= "1000111101011011";
wait for 10 ns;
A <= "1001011010010100";
B <= "0110001100101111";
wait for 10 ns;
A <= "1111111000100101";
B <= "1111111110001010";
wait for 10 ns;
A <= "1011100101000001";
B <= "0000100000000011";
-- Put test bench stimulus code here
wait;
end process;
end;
I just need the sum value since the result will be an alu output. But the result is wrong for some numbers, here is the wave form:
I have used the same adder to write a code for a multiplier but it works fine. Any comments to solve this problem will be appreciated.
The Full_adder is as follows:
library IEEE;
use IEEE.std_logic_1164.all;
entity Full_Adder is
port(x, y, cin: in std_logic;
sum, cout: out std_logic);
end Full_Adder;
architecture my_dataflow of Full_Adder is
begin
sum <= (x xor y) xor cin;
cout <= (x and y) or (x and cin) or (y and cin);
end my_dataflow;

How to create a pseudo-random sequence with a 16 bit LFSR

I am trying to generate a random sequence of 16 bit.
The problem is that the output is getting undefined state. I feel that this is due to parallel processing in those xor statements. So I have put in delays but it still doesn't work.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity random_data_generator is
port (
por : in STD_LOGIC;
sys_clk : in STD_LOGIC;
random_flag : in STD_LOGIC;
random_data : out STD_LOGIC_vector (15 downto 0)
);
end random_data_generator;
architecture Behavioral of random_data_generator is
signal q : std_logic_vector(15 downto 0);
signal n1,n2,n3 : std_logic;
begin
process(sys_clk)
begin
if(por='0') then
q<= "1001101001101010";
elsif(falling_edge(sys_clk)) then
if(random_flag='1') then
n1<= q(15) xor q(13);
n2<= n1 xor q(11) after 10 ns;
n3<= n2 xor q(10) after 10 ns;
q<= q(14 downto 0) & n3 after 10 ns;
end if;
end if;
end process;
random_data <= q;
end Behavioral;
Making some small structural changes to your LFSR:
library ieee;
use ieee.std_logic_1164.all;
entity random_data_generator is
port (
por: in std_logic;
sys_clk: in std_logic;
random_flag: in std_logic;
random_data: out std_logic_vector (15 downto 0)
);
end entity random_data_generator;
architecture behavioral of random_data_generator is
signal q: std_logic_vector(15 downto 0);
signal n1, n2, n3: std_logic;
begin
process (por, sys_clk) -- ADDED por to sensitivity list
begin
if por = '0' then
q <= "1001101001101010";
elsif falling_edge(sys_clk) then
if random_flag = '1' then
-- REMOVED intermediary products as flip flops
q <= q(14 downto 0) & n3; -- REMOVED after 10 ns;
end if;
end if;
end process;
-- MOVED intermediary products to concurrent signal assignments:
n1 <= q(15) xor q(13);
n2 <= n1 xor q(11); -- REMOVED after 10 ns;
n3 <= n2 xor q(10); -- REMOVED after 10 ns;
random_data <= q;
end architecture behavioral;
These changes remove the n1, n2, and n3 flip flops by promoting those assignments to concurrent signal assignment statements. The fundamental issue generating 'U's is that these flip flops were not initialized. They were flip flops because their assignment was inside the if statement with an elsif condition on the falling edge of sys_clk.
Adding a testbench:
library ieee;
use ieee.std_logic_1164.all;
entity rng_tb is
end entity;
architecture foo of rng_tb is
signal por: std_logic;
signal sys_clk: std_logic := '0';
signal random_flag: std_logic;
signal random_data: std_logic_vector (15 downto 0);
begin
DUT:
entity work.random_data_generator
port map (
por => por,
sys_clk => sys_clk,
random_flag => random_flag,
random_data => random_data
);
CLOCK:
process
begin
wait for 5 ns;
sys_clk <= not sys_clk;
if now > 2800 ns then
wait;
end if;
end process;
STIMULI:
process
begin
por <= '1';
random_flag <= '0';
wait until falling_edge(sys_clk);
por <= '0';
wait until falling_edge(sys_clk);
wait for 1 ns;
por <= '1';
wait until falling_edge(sys_clk);
random_flag <= '1';
wait;
end process;
end architecture;
Analyzing both, elaborating and simulating the testbench gives:
Showing a pseudo-random sequence with a length longer than 16 using a 16 bit Linear Feedback Shift Register (LFSR).

Why won't VHDL left shifter work?

I'm new to VHDL and I'm trying to write a left shifter that takes in a 32 bit value and a 5 bit value. The left shifter then tries to perform a logical left shift of the 32 bit value by moving out the number of bits specified by the 5 bit number on the left and bringing that many zeros on the right. I can't understand why the array notation isn't working. The result of 1 << 1 produces 20000000 instead of 00000002. Can someone explain where I'm going wrong? Here's the code:
SIGNAL lshiftOutput : STD_LOGIC_VECTOR( 31 downto 0 );
COMPONENT Lshift32
Port( a : in STD_LOGIC_VECTOR( 31 downto 0 );
b : in STD_LOGIC_VECTOR( 4 downto 0 );
lshiftOutput : out STD_LOGIC_VECTOR( 31 downto 0 ) );
END COMPONENT;
PROCESS( a, b, opcode, adderOutput, subtractOutput, xorOutput, lshiftOutput, rshiftOutput )
BEGIN
IF opcode = "0000" THEN
result <= x"00000000";
ELSIF opcode = "0001" THEN
result <= adderOutput;
ELSIF opcode = "0010" THEN
result <= subtractOutput;
ELSIF opcode = "0011" THEN
result <= NOT a;
ELSIF opcode = "0100" THEN
result <= a AND b;
ELSIF opcode = "0101" THEN
result <= a OR b;
ELSIF opcode = "0110" THEN
result <= xorOutput;
ELSIF opcode = "0111" THEN
result <= lshiftOutput;
ELSIF opcode = "1000" THEN
result <= rshiftOutput;
END IF;
END PROCESS;
LIBRARY ieee;
USE ieee.std_logic_unsigned.ALL;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY Lshift32 IS
Port( a : in STD_LOGIC_VECTOR ( 31 downto 0 );
b : in STD_LOGIC_VECTOR ( 4 downto 0 );
lshiftOutput : out STD_LOGIC_VECTOR ( 31 downto 0 ) );
END Lshift32;
ARCHITECTURE Lshift32Architecture of Lshift32 IS
BEGIN
PROCESS( a, b )
VARIABLE shiftAmount : INTEGER := 0;
BEGIN
shiftAmount := to_integer( b(4 downto 0) );
-- Shift left
lshiftOutput <= a( 31-shiftAmount downto 0 ) & ( shiftAmount-1 downto 0 => '0' );
END PROCESS;
END Lshift32Architecture;
The test bench for this is:
-- Shift Left -------------------------------------------------------
WAIT FOR 9 ns;
op <= "0111";
-- 1 << 1
input_a <= x"00000001";
input_b <= x"00000001";
WAIT FOR 1 ns;
IF (output /= x"00000002") THEN
ASSERT false REPORT "1 << 1 has incorrect result" severity error;
END IF;
Brian asked that you supply a Minimal, Complete, and Verifiable example, your edited code doesn't do that. And the reason for asking is that it's possible to create an mcve around the portions of your code you originally supplied that does give the right answer:
library ieee; -- added
use ieee.std_logic_1164.all; -- added
use ieee.numeric_std_unsigned.all; -- added
entity lshift32 is
port( a : in std_logic_vector ( 31 downto 0 );
b : in std_logic_vector ( 4 downto 0 );
lshiftoutput : out std_logic_vector ( 31 downto 0 ) );
end entity lshift32;
architecture lshift32architecture of lshift32 is
begin
process( a, b )
variable shiftamount : integer := 0;
begin
shiftamount := to_integer( b(4 downto 0) );
-- shift left
lshiftoutput <= a( 31-shiftamount downto 0 ) & ( shiftamount-1 downto 0 => '0' );
end process;
end architecture lshift32architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;
entity lshift32_tb is
end entity;
architecture foo of lshift32_tb is
signal a: std_logic_vector (31 downto 0) := (others => '0');
signal b: std_logic_vector (4 downto 0) := (others => '0');
signal lshiftoutput: std_logic_vector (31 downto 0);
begin
DUT:
entity work.lshift32
port map (
a => a,
b => b,
lshiftoutput => lshiftoutput
);
SIMULIS:
process
begin
wait for 10 ns;
a(0) <= '1'; -- 1
b(0) <= '1'; -- 1
wait for 10 ns;
wait;
end process;
ANALYSIS:
process (lshiftoutput)
variable shiftamount: integer;
begin
if now > 0 ns then
shiftamount := to_integer(b);
report "ShiftAmount = " & integer'image(shiftamount);
report "lshiftOutput = " & to_string(lshiftoutput);
end if;
end process;
end architecture;
And running the above testbench gives:
ghdl -a --std=08 lshift.vhdl
ghdl -e --std=08 lshift32_tb
ghdl -r lshift32_tb
lshift.vhdl:60:13:#10ns:(report note): ShiftAmount = 1
lshift.vhdl:61:13:#10ns:(report note): lshiftOutput = 00000000000000000000000000000010
And that your execution fails says there's either something wrong with your context clause (use clauses) or something wrong with your testbench.
Note that you are using both none standard package std_logic_unsigned and IEEE standard package numeric_std. You really shouldn't mix and match there can be unexpected consequences.
The package numeric_std_unsigned is available with a VHDL implementation compliant with the IEEE Std 1076-2008 standard. If using a previous version of the VHDL standard you can use package numeric_std and type convert b to unsigned as the expression passed to to_integer.
For the testbench supplied with this answer you'd also find that to_stringfor std_logic_vector is not supplied. Without seeing your entire testbench it could well be functional.
If you want to prove the answer supplied testbench works in a non -2008 revision environment:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
The function can be supplied as an architecture declarative item.

VHDL : False Results in 4-Bit Adder and Subtractor

I want to make a 4-Bit Adder and Subtractor with VHDL
I have created 1-Bit Full-Adder , XOR Gate ( for Subtract ) and a 4-Bit Adder as shown below :
Full-Adder :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY FullAdder_1_Bit IS
PORT(
X, Y : IN STD_LOGIC;
CIn : IN STD_LOGIC;
Sum : OUT STD_LOGIC;
COut : OUT STD_LOGIC
);
END FullAdder_1_Bit;
ARCHITECTURE Behavier OF FullAdder_1_Bit IS
BEGIN
Sum <= X XOR Y XOR CIn;
COut <= (X AND Y) OR (X AND CIn) OR (Y AND CIn);
END Behavier;
XOR Gate :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY XORGate IS
PORT(
X1, X2 : IN STD_LOGIC;
Y : OUT STD_LOGIC
);
END XORGate;
ARCHITECTURE Declare OF XORGate IS
BEGIN
Y <= X1 XOR X2;
END Declare;
4-Bit Adder :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY Adder_4_Bit IS
PORT(
A, B : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
Mode : IN STD_LOGIC;
Sum : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
COut : OUT STD_LOGIC
);
END Adder_4_Bit;
ARCHITECTURE Structure OF Adder_4_Bit IS
COMPONENT FullAdder_1_Bit IS
PORT(
X, Y : IN STD_LOGIC;
CIn : IN STD_LOGIC;
Sum : OUT STD_LOGIC;
COut : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT XORGate IS
PORT(
X1, X2 : IN STD_LOGIC;
Y : OUT STD_LOGIC
);
END COMPONENT;
SIGNAL COut_Temp : STD_LOGIC_VECTOR(2 DOWNTO 0);
SIGNAL XB : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
B_0 : XORGate PORT MAP(Mode, B(0), XB(0));
B_1 : XORGate PORT MAP(Mode, B(1), XB(1));
B_2 : XORGate PORT MAP(Mode, B(2), XB(2));
B_3 : XORGate PORT MAP(Mode, B(3), XB(3));
SUM_0 : FullAdder_1_Bit
PORT MAP (A(0), XB(0), Mode, Sum(0), COut_Temp(0));
SUM_1 : FullAdder_1_Bit
PORT MAP (A(1), XB(1), COut_Temp(0), Sum(1), COut_Temp(1));
SUM_2 : FullAdder_1_Bit
PORT MAP (A(2), XB(2), COut_Temp(1), Sum(2), COut_Temp(2));
SUM_3 : FullAdder_1_Bit
PORT MAP (A(3), XB(3), COut_Temp(2), Sum(3), COut);
END;
and in my Main Codes , i have used those ( like Test-Bench ! ) :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.ALL;
ENTITY Add_AND_Sub IS
END Add_AND_Sub;
ARCHITECTURE Declare OF Add_AND_Sub IS
COMPONENT Adder_4_Bit IS
PORT(
A, B : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
Mode : IN STD_LOGIC;
Sum : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
COut : OUT STD_LOGIC
);
END COMPONENT;
SIGNAL A, B : STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL Mode : STD_LOGIC;
SIGNAL As, Bs, E, AVF : STD_LOGIC;
SIGNAL XA, XB, Sum : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
Add : Adder_4_Bit
PORT MAP(XA, XB, Mode, Sum, E);
PROCESS(A, B, Mode)
BEGIN
As <= A(4);
Bs <= B(4);
XA <= A(3 DOWNTO 0);
XB <= B(3 DOWNTO 0);
CASE Mode IS
WHEN '0' =>
IF ((As XOR Bs) = '1') THEN
Mode <= '1';
XA <= Sum;
AVF <= '0';
IF (E = '1') THEN
IF (XA = "0000") THEN
As <= '0';
END IF;
ELSE
XA <= (NOT XA) + "0001";
As <= NOT As;
END IF;
ELSE
XA <= Sum;
END IF;
WHEN '1' =>
IF ((As XOR Bs) = '1') THEN
Mode <= '0';
XA <= Sum;
AVF <= E;
ELSE
AVF <= '0';
XA <= Sum;
IF (E = '1') THEN
IF (XA = "0000") THEN
As <= '0';
END IF;
ELSE
XA <= (NOT XA) + "0001";
As <= NOT As;
END IF;
END IF;
WHEN Others =>
--
END CASE;
END PROCESS;
END Declare;
The main scenario is to Model this algorithm :
but now i want to have output in XA and As
I Should use registers shown in algorithm such as "E" and "AVF"
there is one question :
we know port maps are continuously connected , so when i change Mode Value , Result ( Sum ) must change , is it True ?!
I have tried this code but i cant get output in XA , and there is no True result for sum values , i know there is some problem in my main code ( Process ) , but i cant find problems
please check that codes and tell me what goes wrong !
Edit :
Im using ModelSim and its simulation for testing my code , first i force values of "A", "B" and "Mode" then run to get result and wave
thanks ...
Your testbench add_and_sub makes no assignments to it's a and b, they're default values are all 'U's.
What do you expect when your inputs to adder_4_bit are undefined?
Look at the not_table, or_table, and_table and xor_table in the body of the std_logic_1164 package.
Also to be a Minimal, Complete, and Verifiable example your readers need both expected and actual results.
If you're actually simulating the testbench I'd expect it consume no simulation time and after some number of delta cycles during initialization show sum and e chock full of 'U's.
I haven't personally modified your testbench to determine if your adder_4_bit works, but if you provide it with valid stimulus you can debug it. It can be helpful to consume simulation time and use different input values.
Adding a monitor process to add_and_sub:
MONITOR:
process (sum)
function to_string(inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
-- report "image_str = " & image_str;
return image_str;
end;
begin
report "sum = " & to_string(sum);
end process;
gives:
fourbitadder.vhdl:174:10:#0ms:(report note): sum = uuuu
one event on sum.
Add a process to cause events on a and 'b`:
STIMULUS:
process
begin
a <= "00000" after 10 ns;
b <= "00000" after 10 ns;
wait for 20 ns;
wait;
end process;
and we get:
(clickable)
We find we get an event on a and b but sum didn't change.
And the reason why is apparent in the case statement in the process. The default value of mode is 'U', and the case statement has choices for 0, 1 and:
when others =>
--
end case;
And the others choice results in no new value in mode.
Why nothing works can be discovered by reading the source of the body for package std_logic_1164, the xor_table, and_table, or_table. With mode = 'U' all your combinatorial outputs will be 'U'.
And to fix this you can assign a default value to mode where it is declared in the testbench:
signal mode : std_logic := '0';
With mode defined as a valid choice resulting in some action we note xa is now never defined causing the same issue:
(clickable)
And this is a problem in the process:
process(a, b, mode)
begin
as <= a(4);
bs <= b(4);
xa <= a(3 downto 0);
xb <= b(3 downto 0);
case mode is
when '0' =>
if ((as xor bs) = '1') then
mode <= '1';
xa <= sum;
avf <= '0';
if (e = '1') then
if (xa = "0000") then
as <= '0';
end if;
else
xa <= std_logic_vector(unsigned(not xa) + unsigned'("0001"));
as <= not as;
end if;
else
xa <= sum;
end if;
when '1' =>
if ((as xor bs) = '1') then
mode <= '0';
xa <= sum;
avf <= e;
else
avf <= '0';
xa <= sum;
if (e = '1') then
if (xa = "0000") then
as <= '0';
end if;
else
xa <= std_logic_vector(unsigned(not xa) + unsigned'("0001"));
as <= not as;
end if;
end if;
when others =>
--
end case;
Notice there are three places where xa is assigned, with no simulation time between them. There's only one projected output waveform value for any simulation time. A later assignment in the same process will result in the later value being assigned, in this case sum, which is all 'U's.
So how do you solve this conundrum? There are two possibilities. First you could not try and do algorithmic stimulus generation, assigning input to add explicitly with wait statements between successive assignments of different values. You can also insert delays between successive assignments to the same signal in the existing process, which requires a substantial re-write.
On a positive note the adder_4_bit and full_adder_1bit look like they should work. The problem appears to be all in the testbench.
I made some changes
I made a ALU unit as :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
USE ieee.std_logic_unsigned.ALL;
ENTITY ALU IS
PORT(
--Clk : IN STD_LOGIC;
A, B : IN STD_LOGIC_VECTOR(4 DOWNTO 0);
Sel : IN STD_LOGIC;
AOut : OUT STD_LOGIC_VECTOR(4 DOWNTO 0);
AsO : OUT STD_LOGIC
);
END ALU;
ARCHITECTURE Declare OF ALU IS
COMPONENT Adder_4_Bit IS
PORT(
A, B : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
Mode : IN STD_LOGIC;
Sum : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
COut : OUT STD_LOGIC
);
END COMPONENT;
SIGNAL As, Bs, E, AVF : STD_LOGIC;
SIGNAL XA, XB, Sum : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL Mode : STD_LOGIC;
BEGIN
Add : Adder_4_Bit
PORT MAP(XA, XB, Mode, Sum, E);
PROCESS
BEGIN
As <= A(4);
Bs <= B(4);
XA <= A(3 DOWNTO 0);
XB <= B(3 DOWNTO 0);
CASE Sel IS
WHEN '0' =>
IF ((As XOR Bs) = '1') THEN
Mode <= '1';
AVF <= '0';
WAIT ON Sum;
IF (E = '1') THEN
IF (Sum = "0000") THEN
As <= '0';
END IF;
ELSE
Sum <= (NOT Sum) + "0001";
As <= NOT As;
END IF;
ELSE
Mode <= '0';
WAIT ON Sum;
END IF;
AOut <= Sum;
AsO <= As;
WHEN '1' =>
IF ((As XOR Bs) = '1') THEN
Mode <= '0';
WAIT ON Sum;
AVF <= E;
ELSE
Mode <= '1';
WAIT ON Sum;
AVF <= '0';
IF (E = '1') THEN
IF (Sum = "0000") THEN
As <= '0';
END IF;
ELSE
Sum <= (NOT Sum) + "0001";
As <= NOT As;
END IF;
END IF;
AOut <= Sum;
AsO <= As;
WHEN Others =>
--
END CASE;
END PROCESS;
END Declare;
and A Test Bench like this :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
USE ieee.std_logic_unsigned.ALL;
ENTITY ALU_Test_Bench IS
END ALU_Test_Bench;
ARCHITECTURE Declare OF ALU_Test_Bench IS
COMPONENT ALU IS
PORT(
--Clk : IN STD_LOGIC;
A, B : IN STD_LOGIC_VECTOR(4 DOWNTO 0);
Sel : IN STD_LOGIC;
AOut : OUT STD_LOGIC_VECTOR(4 DOWNTO 0);
AsO : OUT STD_LOGIC
);
END COMPONENT;
SIGNAL Xs, S : STD_LOGIC;
SIGNAL X, Y, O : STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
ALU_PM : ALU PORT MAP(X, Y, S, O, Xs);
Main_Process : PROCESS
BEGIN
WAIT FOR 100 ns;
X <= "00010";
Y <= "11011";
S <= '0';
WAIT FOR 30 ns;
S <= '1';
WAIT FOR 30 ns;
WAIT FOR 100 ns;
X <= "01110";
Y <= "10011";
S <= '0';
WAIT FOR 30 ns;
S <= '1';
WAIT FOR 30 ns;
WAIT FOR 100 ns;
X <= "10011";
Y <= "11111";
S <= '0';
WAIT FOR 30 ns;
S <= '1';
WAIT FOR 30 ns;
END PROCESS;
END Declare;
As i say , i want to model the algorithm i posted in first post
there is some problem ...
for example when i simulate and run test bench , there is no output value in O and Xs !
I know the problem is in ALU and Test Bench
I changed ALU many times and tested many ways but all times some things goes wrong !
If you want to code that algorithm , which units you will create or at all what will you create ?! and how will you code that ?!
thanks for your help ...

How to concatenate 3 operation select bits in a 4-bit ALU design - VHDL

So I have been working on this assignment and it requires me to design a 4-bit ALU being controlled by a couple of bits(namely S1, S0, Cin/C0(carry in) and M) Depending on the value of M the ALU will perform either logical or Arithmetic operations. I have temporarily designed an ALU which works with an input named 'Sel' while I figure out how to take the values of the 3 diff inputs(S0, S1, Cin/C0). I cannot figure out how to concatenate the 3 bits. I have also used '-' for dont care bits while performing logical operations. Also since I haven't used the 3 control selects, Mode (m) feels redundant. So ignore some parts of the code since they aren't useful.
I have attached an image at the end which explains what is expected.
CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity 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;
Sel : in STD_LOGIC_VECTOR (2 downto 0);
M : in STD_LOGIC;
Cout : out STD_LOGIC;
Z : out STD_LOGIC;
F : out STD_LOGIC_VECTOR (3 downto 0));
end codeALU;
architecture Behavioral of codeALU is
begin
process(A, B, M, Cin, Sel)
--variable X : STD_LOGIC_VECTOR (1 downto 0);
--variable Y : STD_LOGIC_VECTOR (2 downto 0);
variable temp : STD_LOGIC_VECTOR (4 downto 0);
variable Fx : STD_LOGIC_VECTOR (3 downto 0);
variable Cx, Zx : STD_LOGIC;
begin
--X := S1 & S0;
--Y := S1 & S0 & Cin;
Cx := '0';
Zx := '0';
if M = '0' then
Z <= '0';
case Sel 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;
elsif M = '1' then
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;
for i in 0 to 3 loop
Zx := Zx or Fx(i);
end loop;
Z <= not Zx;
else null;
end if;
F <= Fx;
Cout <= Cx;
end process;
end Behavioral;
TEST BENCH
![LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY test2ALU IS
END test2ALU;
ARCHITECTURE behavior OF test2ALU 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;
Sel : IN std_logic_vector(2 downto 0);
M : IN std_logic;
Cout : OUT std_logic;
Z : OUT std_logic;
F : OUT std_logic_vector(3 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 Sel : std_logic_vector(2 downto 0) := (others => '0');
signal M : std_logic := '0';
--Outputs
signal Cout : std_logic;
signal Z : std_logic;
signal F : std_logic_vector(3 downto 0);
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: codeALU PORT MAP (
A => A,
B => B,
Cin => Cin,
Sel => Sel,
M => M,
Cout => Cout,
Z => Z,
F => F
);
-- 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;
Sel <= "00-";
wait for 50 ns;
Sel <= "01-";
wait for 50 ns;
Sel <= "10-";
wait for 50 ns;
Sel <= "11-";
wait for 50 ns;
M <= '1';
Sel <= "000";
wait for 50 ns;
Sel <= "001";
wait for 50 ns;
Sel <= "010";
wait for 50 ns;
Sel <= "011";
wait for 50 ns;
Sel <= "100";
wait for 50 ns;
Sel <= "101";
wait for 50 ns;
Sel <= "110";
wait for 50 ns;
Sel <= "111";
-- insert stimulus here
wait;
end process;
END;][1]
What you tried to do with X and Y (and which you commented out) is a perfectly reasonable way of concatenating your selects. The problem is the don't-cares. The ordinary case statement does not handle don't-cares the way you're expecting (i.e. it doesn't match against them as if they can be anything - it handles them as a unique std_logic value same as everything else). If you have tools that support VHDL-2008, you can use case?, which does match against don't-care values the way you want. You could even concatenate M into your select as well and shorten your code a bit. Like:
process (all)
variable sel : std_logic_vector(3 downto 0);
begin
sel := M & S1 & S0 & Cin;
case? sel is
when "000-" =>
Fx := A and B;
when "001-" =>
Fx := A or B;
...
when "1000" =>
...
(Note that I'm using sel here as an internal variable instead of a port.)
If you can't use VHDL-2008, you will have to nest your if/case statements appropriately. Hint: you can use a slice of sel in a case statement, so if Cin is always a don't-care for M = '0', you can do something like:
process (M, S0, S1, Cin, A, B)
variable sel : std_logic_vector(2 downto 0);
begin
sel := S1 & S0 & Cin;
if M = '0' then
case sel(2 downto 1) is -- Cin is don't-care
when "00" =>
Fx := A and B;
when "01" =>
Fx := A or B;
...
else
case sel is -- all control bits are significant
when "000" =>
...
As Paebbels pointed out, a better solution for you perhaps would be just to explicitly give multiple choices where there's a don't-care, though that may get tedious for designs with more control bits.

Resources