So i made a 4 bit adder, and I wanted it port mapped to an ALU I am building, yet for some reason the port map is coming up as an error. I have tried everything, changing variable types, changing the logic, and even changing variable names, but nothing works. The error pops up when I try to use the port map (the lines where it says bit0, bit1...), and the error complains about the work 'port' and ';'.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
use ieee.numeric_std.all;
-- Define the input and output signals
ENTITY bit_FA IS
PORT (
A, B : in unsigned(7 downto 0);
CI : in std_logic;
SUM : out unsigned(7 downto 0);
CO : out std_logic);
END bit_FA;
-- Describe the full adder 's behavior
ARCHITECTURE bit_FA1 OF bit_FA IS
signal tmp: unsigned(8 downto 0);
begin
tmp <= A + B + ("0" & ci); --trick to promote ci to unsigned
SUM <= tmp(7 downto 0);
CO <= tmp(8);
END bit_FA1;
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.ALL;
-- Define the input and output signals
ENTITY FinalLab IS
PORT (
CLK : in BIT;
code : in BIT_VECTOR;
A: in STD_LOGIC_VECTOR (3 downto 0);
B : inout STD_LOGIC_VECTOR (3 downto 0);
C, D : out STD_LOGIC_VECTOR (3 downto 0);
CO : out STD_LOGIC);
END FinalLab;
ARCHITECTURE behave_1 OF FinalLab IS
signal cin : std_logic_vector(3 downto 0);
component bit_FA is
port (
a, b, c : in std_logic;
sum, carry : out std_logic);
end component;
BEGIN
process(code)
begin
if code = "000" then
--error
bit0 : bit_FA port map( A(0), B(0), '0', C(0), cin(0));
bit1 : bit_FA port map ( A(1), B(1), carry(0), C(1), cin(1) );
bit2 : bit_FA port map ( A(2), B(2), carry(1), C(2), cin(2) );
bit3 : bit_FA port map ( A(3), B(3), carry(2), C(3), cin(3) );
CO <= cin(3);
elsif code = "001" then
C(0) <= A(3);
C(1) <= A(2);
C(2) <= A(1);
C(3) <= A(0);
elsif code = "010" then
--multiplication
B <= std_logic_vector( unsigned(B) - 1 );
elsif code = "011" then
C <= std_logic_vector( unsigned(A) + 1 );
elsif code = "100" then
C(0) <= not(A(0) XOR B(0));
C(1) <= not(A(1) XOR B(1));
C(2) <= not(A(2) XOR B(2));
C(3) <= not(A(3) XOR B(3));
elsif code = "101" then
C(0) <= not A(0);
C(1) <= not A(1);
C(2) <= not A(2);
C(3) <= not A(3);
elsif code = "110" then
C(0) <= A(3);
C(1) <= A(0);
C(2) <= A(1);
C(3) <= A(2);
elsif code = "111" then
C(0) <= A(1);
C(1) <= A(2);
C(2) <= A(3);
C(3) <= A(0);
end if;
end process;
END behave_1;
VHDL stands for VHSIC Hardware Description Language. As it is hardware, you cannot use if-statements and such to make components magically appear and disappear. All components need to be connected all the time.
What you can do is implement switched/multiplexers to select the output of components. However, you need intermediate signals.
I.e., the full adders need to be connected in the architecture scope and the output selected in the if statement
ARCHITECTURE behave_1 OF FinalLab IS
signal FA_out : std_logic_vector(3 downto 0);
[...]
begin
bit0 : bit_FA port map( A(0), B(0), '0', FA_out(0), cin(0));
bit1 : bit_FA port map ( A(1), B(1), cin(0), FA_out(1), cin(1) );
bit2 : bit_FA port map ( A(2), B(2), cin(1), FA_out(2), cin(2) );
bit3 : bit_FA port map ( A(3), B(3), cin(2), FA_out(3), cin(3) );
[...]
if code = "000" then
C <= FA_out;
CO <= cin(3);
[...]
Note: the CLK input port is there for a reason... use it.
Related
i am a bit new to VHDL and i try to learn by examples. So long story short i began with some basic examples like creating this Full Adder.
entity FA is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
Cin : in STD_LOGIC;
S : out STD_LOGIC;
Cout : out STD_LOGIC);
end FA;
architecture gate_level of FA is
begin
S <= A XOR B XOR Cin ;
Cout <= (A AND B) OR (Cin AND A) OR (Cin AND B) ;
end gate_level;
After that i tried to implement this 4-bit adder
And this is the code that i wrote.
entity Ripple_Adder is
Port ( A : in STD_LOGIC_VECTOR (3 downto 0);
B : in STD_LOGIC_VECTOR (3 downto 0);
Cin : in STD_LOGIC;
S : out STD_LOGIC_VECTOR (3 downto 0);
Cout : out STD_LOGIC);
end Ripple_Adder;
architecture Behavioral of Ripple_Adder is
-- Full Adder VHDL Code Component Decalaration
component FA
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
Cin : in STD_LOGIC;
S : out STD_LOGIC;
Cout : out STD_LOGIC);
end component;
-- Intermediate Carry declaration
signal c1,c2,c3: STD_LOGIC;
begin
-- Port Mapping Full Adder 4 times
FA1: FA port map( A(0), B(0), Cin, S(0), c1);
FA2: FA port map( A(1), B(1), c1, S(1), c2);
FA3: FA port map( A(2), B(2), c2, S(2), c3);
FA4: FA port map( A(3), B(3), c3, S(3), Cout);
end Behavioral;
Also i used a 4_bit_adder test bench file and i found out that the output is right. Now i am trying to implement a 4 bit multiplier with the usage of the 4 bit adder but i am a bit stuck. Actually this is the multiplier that i am trying to implement.
the code i wrote is this, but i am stuck at the port map
--library
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_textio.all;
use IEEE.std_logic_unsigned.all;
--entity
entity multy is
port (x: in std_logic_vector(3 downto 0);
y: in std_logic_vector(3 downto 0);
p : out std_logic_vector(7 downto 0)
);
end multy ;
-- architecture
architecture rtl of multy is
component Ripple_Adder
Port ( A : in std_logic_vector (3 downto 0);
B : in std_logic_vector (3 downto 0);
Cin : in std_logic;
S : out std_logic_vector (3 downto 0);
Cout : out std_logic);
end component ;
signal andgate: std_logic_vector(15 downto 0);
signal sumout: std_logic_vector( 11 downto 0);
signal carry: std_logic_vector(11 downto 0);
begin
andgate(0) <= x(0) and y(0);
andgate(1) <= x(1) and y(0); --b0
andgate(2) <= x(2) and y(0); --b1
andgate(3) <= x(3) and y(0); --b2
B
andgate(4) <= x(0) and y(1);
andgate(5) <= x(1) and y(1);
andgate(6) <= x(2) and y(1);
andgate(7) <= x(3) and y(1);
andgate(8) <= x(0) and y(2);
andgate(9) <= x(1) and y(2);
andgate(10) <= x(2) and y(2);
andgate(11) <= x(3) and y(2);
andgate(12) <= x(0) and y(3);
andgate(13) <= x(1) and y(3);
andgate(14) <= x(2) and y(3);
andgate(15) <= x(3) and y(3);
--gates
cell_1: Ripple_Adder port map();
cell_2: Ripple_Adder port map();
cell_3: Ripple_Adder port map();
--Assigning p values
p(0) <= andgate(0);
p(1) <= sumout(0);
p(2) <= sumout(4);
p(3) <= sumout(8);
p(4) <= sumout(9);
p(5) <= sumout(10);
p(6) <= sumout(11);
p(7) <= carry(11);
end rtl ;
"I am stuck on the port map" isn't a specific problem statement.
With named association members of formal ports in maps could be associated individually as well as in whole as long as all members of the formal are associated - IEEE Std 1076-2008 6.5.7 Association lists:
A formal interface object shall be either an explicitly declared interface object or member (see 5.1) of such an interface object. In the former case, such a formal is said to be associated in whole. In the latter cases, named association shall be used to associate the formal and actual; the subelements of such a formal are said to be associated individually. Furthermore, every scalar subelement of the explicitly declared interface object shall be associated exactly once with an actual (or subelement thereof) in the same association list, and all such associations shall appear in a contiguous sequence within that association list. Each association element that associates a slice or subelement (or slice thereof) of an interface object shall identify the formal with a locally static name.
Note you have too many carry elements (only need two), don't need andgate(0), don't need sumout(0), sumout(4) or sumout(11 downo 8), there's an extraneous character in the multy architecture, you're missing context clauses and have unused use clauses.
Your code using array intermediary signals:
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_textio.all; -- NOT USED
-- use ieee.std_logic_unsigned.all; -- NOT USED
entity multy is
port (
x: in std_logic_vector (3 downto 0);
y: in std_logic_vector (3 downto 0);
p: out std_logic_vector (7 downto 0)
);
end entity multy;
architecture rtl of multy is
component Ripple_Adder
port (
A: in std_logic_vector (3 downto 0);
B: in std_logic_vector (3 downto 0);
Cin: in std_logic;
S: out std_logic_vector (3 downto 0);
Cout: out std_logic
);
end component;
-- AND Product terms:
signal G0, G1, G2: std_logic_vector (3 downto 0);
-- B Inputs (B0 has three bits of AND product)
signal B0, B1, B2: std_logic_vector (3 downto 0);
begin
-- y(1) thru y (3) AND products, assigned aggregates:
G0 <= (x(3) and y(1), x(2) and y(1), x(1) and y(1), x(0) and y(1));
G1 <= (x(3) and y(2), x(2) and y(2), x(1) and y(2), x(0) and y(2));
G2 <= (x(3) and y(3), x(2) and y(3), x(1) and y(3), x(0) and y(3));
-- y(0) AND products (and y0(3) '0'):
B0 <= ('0', x(3) and y(0), x(2) and y(0), x(1) and y(0));
-- named association:
cell_1:
Ripple_Adder
port map (
a => G0,
b => B0,
cin => '0',
cout => B1(3), -- named association can be in any order
S(3) => B1(2), -- individual elements of S, all are associated
S(2) => B1(1), -- all formal members must be provide contiguously
S(1) => B1(0),
S(0) => p(1)
);
cell_2:
Ripple_Adder
port map (
a => G1,
b => B1,
cin => '0',
cout => B2(3),
S(3) => B2(2),
S(2) => B2(1),
S(1) => B2(0),
S(0) => p(2)
);
cell_3:
Ripple_Adder
port map (
a => G2,
b => B2,
cin => '0',
cout => p(7),
S => p(6 downto 3) -- matching elements for formal
);
p(0) <= x(0) and y(0);
end architecture rtl;
And a borrowed testbench to demonstrate:
library ieee;
use ieee.std_logic_1164.all;
entity multy_tb is -- testbench
end entity;
architecture foo of multy_tb is
signal x, y: std_logic_vector (3 downto 0);
signal yp, rp: std_logic_vector (7 downto 0);
use ieee.numeric_std.all;
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;
begin
DUT:
entity work.multy
port map (
x => x,
y => y,
p => yp
);
STIMULI:
process
begin
for i in 0 to 15 loop
x <= std_logic_vector(to_unsigned(i, x'length));
for j in 0 to 15 loop
y <= std_logic_vector(to_unsigned(j, y'length));
wait for 0 ns; -- assignments take effect
rp <= std_logic_vector(unsigned (x) * unsigned(y));
wait for 10 ns;
if yp /= rp then
report "multy error";
report HT & "expected " & to_string (rp);
report HT & "got " & to_string (yp);
end if;
end loop;
end loop;
wait;
end process;
end architecture;
The to_string function is included for pre -2008 simulators. Context clauses were added to FA and Ripple_Adder.
I am trying to create schematics for a NxM -bit parallel block multiplier using generic parameters to define the size of the multiplier, and generate statements to describe the internal structure. I am having some trouble with my sums and carries and I am not able to implement what I want to do in VHDL code.
Here is what I got so far:
1-bit multiplier:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity mult is
port (
a : in std_logic;
b : in std_logic;
Sin : in std_logic; --sum-in
Cin : in std_logic; --carry-in
Sout : out std_logic; --sum-out
Cout : out std_logic --carry-out
);
end mult;
architecture mult of mult is
begin
Sout <= '1' when a = '0' and b = '0' and Sin = '0' and Cin = '1' else
'1' when a = '0' and b = '0' and Sin = '1' and Cin = '0' else
'1' when a = '0' and b = '1' and Sin = '1' and Cin = '0' else
'1' when a = '0' and b = '1' and Sin = '0' and Cin = '1' else
'1' when a = '1' and b = '0' and Sin = '0' and Cin = '1' else
'1' when a = '1' and b = '0' and Sin = '1' and Cin = '0' else
'1' when a = '1' and b = '1' and Sin = '0' and Cin = '0' else
'1' when a = '1' and b = '1' and Sin = '1' and Cin = '1' else
'0';
Cout <= '1' when a = '0' and b = '0' and Sin = '1' and Cin = '1' else
'1' when a = '0' and b = '1' and Sin = '1' and Cin = '1' else
'1' when a = '1' and b = '0' and Sin = '1' and Cin = '1' else
'1' when a = '1' and b = '1' and Sin = '0' and Cin = '1' else
'1' when a = '1' and b = '1' and Sin = '1' and Cin = '0' else
'1' when a = '1' and b = '1' and Sin = '1' and Cin = '1' else
'0';
end mult;
Used it as a component in an NxM multiplier:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity generic_mult is
generic (bits: integer);
port (
a : in std_logic_vector(bits-1 downto 0);
b : in std_logic_vector(bits-1 downto 0);
answer: out std_logic_vector(bits*2-1 downto 0) --sum-out
);
end entity generic_mult;
architecture behavioral of generic_mult is
component mult is
port (
a : in std_logic;
b : in std_logic;
Sin : in std_logic; --sum-in
Cin : in std_logic; --carry-in
Sout : out std_logic; --sum-out
Cout : out std_logic --carry-out
);
end component;
type mem_word is array (0 to bits) of std_logic_vector(bits downto 0);
signal carry_internal : mem_word;
signal sum_internal : mem_word;
begin
this_is_label: for N in 1 to bits generate --Im sorry, my labels are horrible :(
this_is_label3: for M in 0 to bits-1 generate
this_is_label2: mult
port map (
a => a(N-1),
b => b(M),
Cin => carry_internal(M)(N),
Cout => carry_internal(M+1)(N),
Sin => sum_internal(M)(N),
Sout => sum_internal(M+1)(N-1)
);
end generate;
end generate;
labellll: for N in 0 to bits-1 generate
sum_internal(N+1)(N) <= carry_internal(N)(N);
carry_internal(0) <= (others => '0');
sum_internal(0) <= (others => '0');
answer(bits*2-1) <= carry_internal(bits)(bits);
answer(bits downto 0) <= sum_internal(bits);
end generate;
end behavioral;
And a testbench for it:
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity NM_mult_tb is
end NM_mult_tb;
architecture behavioral of NM_mult_tb is
component generic_mult
generic (bits: integer := 4);
port (
a : in std_logic_vector(bits-1 downto 0);
b : in std_logic_vector(bits-1 downto 0);
answer: out std_logic_vector(bits*2-1 downto 0) --sum-out
);
end component;
--declaring inputs and initializing them
signal a : std_logic_vector(3 downto 0) :="0101";
signal b : std_logic_vector(3 downto 0) :="1010";
signal Sin: std_logic_vector(3 downto 0) :="0000";
signal Cin: std_logic := '0';
--declaring outputs and initializing them
signal answer : std_logic_vector(7 downto 0); --sum-out
signal correct: std_logic; --carry-out
BEGIN
-- Instantiating the Design Under Test (DUT)
dut: generic_mult
GENERIC MAP (4)
PORT MAP (
a => a,
b => b,
answer => answer
);
-- Stimulus process
correct <= '1' when to_integer(unsigned(a))*to_integer(unsigned(b)) =
to_integer(unsigned(answer)) else '0';
stim_proc: process
begin
wait for 1 ns;
a <= a + 1;
if a = "0" then b <= b + 1; end if;
end process;
END;
When I simulate it I see that there is something wrong with carry-ins and sum-ins and outs and my answer has undefined bits in it:
If you have read my post this far, thank you very much for your attention. If someone could find the time to help me out with my problem I would be very grateful!
Sincerely,
A confused VHDL beginner
Libraries
So, for doing arithmetic you only need one arithmetic library: numeric_std. Don't use std_logic_arith because it is not standardized, so behavior can differ between implementations.
Then std_logic_unsigned could be risky. Jim Lewis explains here that its could be a good idea to use it, but I think that you should not. Better to use integer, unsigned and signed data types for all comparisons.
Entity mult
What you are implementing is lookup-tables. Combinatorial logic statements. This is not arithmetic, so no arithmetic libraries are needed.
However, you could simplify the code.
Let's take this description ar reference.
The 1x1 multiplier can be defined using logic operators (based on a full adder described here):
architecture rtl of mult is
signal FA_a, FA_b : std_logic;
begin
FA_a <= Sin;
FA_b <= a AND b;
Sout <= FA_a XOR FA_b XOR Cin;
Cout <= (FA_a AND FA_b) OR (Cin AND (FA_a XOR FA_b));
end architecture;
Or just skip this all and use the addition operator, which does the logic for you.
architecture rtl of mult is
use ieee.numeric_std.all;
signal FA_a, FA_b, FA_Cin : unsigned(1 downto 0) := (others => '0');
signal FA_out : unsigned(1 downto 0);
begin
FA_a(0) <= Sin;
FA_b(0) <= a AND b;
FA_Cin(0) <= Cin;
FA_out <= FA_a + FA_b + FA_Cin;
Sout <= FA_out(0);
Cout <= FA_out(1);
end architecture;
Entity generic_mult
First off, your multiplier is MxM, not MxN.
Next you complain about your labels in the comments... would take just as much effort to change them ;).
Regarding your implementation, you are assigning signals multiple times in the labellll generate block. It should be:
labellll: for N in 0 to bits-1 generate
sum_internal(N+1)(N) <= carry_internal(N)(N);
end generate;
carry_internal(0) <= (others => '0');
sum_internal(0) <= (others => '0');
answer(bits*2-1) <= carry_internal(bits)(bits);
answer(bits downto 0) <= sum_internal(bits);
but this is not the biggest problem, as it can be resolved.
The problem you do have, has to do with multiple drivers. In this_is_label2 you have the line:
Sout => sum_internal(M+1)(N-1)
And in labellll you have the line:
sum_internal(N+1)(N) <= carry_internal(N)(N);
Two statements, which are both assigning a value to sum_internal. If both 1 and 0 are assigned, this will resolve to X.
But this is not necesary, because it is the result of an error in your design. Please see my link again to see how you should implement the multiplier. I'm not going to do it for you (it's not that difficult and probably your homework. You don't learn anything if other people do your homework for you. ;) )
Testbench
You're combining unsigned arithmetic (to_integer(unsigned(a))*to_integer(unsigned(b))) with std_logic_vector arithmetic (a <= a + 1;). Don't do that. Preferably only use unsigned.
using the multiplication operator
As stated by pev.hall, you could just simplify everything and use the multiplication operator from the numeric_std package.
entity generic_mult is
generic (
M: positive;
N: positive
);
port (
a : in std_logic_vector(M-1 downto 0);
b : in std_logic_vector(N-1 downto 0);
answer : out std_logic_vector(M+N-1 downto 0)
);
end entity;
architecture rtl of generic_mult is
use ieee.numeric_std.all;
begin
answer <= std_logic_vector(unsigned(a)*unsigned(b));
end architecture;
I'm supposed to write up a 16-bit ALU. My professor wants us to try and code the adder and sub of the ALU with a
signal tmp : std_logic_vector(16 downto 0); and then in the case for the select input s we put:
tmp <= conv_std_logic_vector(conv_integer(a) + conv_integer(b), 17);
After experimenting with it for a while, my waveform only showed the inputs' values as UUUUUUUUUUUUUUUU. Even after I had commented out the conv_std_logic_vector(...) stuff.
Is there a simple explanation as to why my inputs aren't showing up in the waveform?
Here is my code:
-- 16-Bit ALU
-- By: Logan Jordon
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use IEEE.NUMERIC_STD.ALL;
--use ieee.std_logic_arith.all;
entity alu16 is
port (
a : in std_logic_vector(15 downto 0);
b : in std_logic_vector(15 downto 0);
s : in std_logic_vector(1 downto 0);
r : out std_logic_vector(15 downto 0);
cout : out std_logic;
lt, eq, gt : out std_logic;
overflow : out std_logic
);
end entity alu16;
architecture beh of alu16 is
signal tmp : std_logic_vector(16 downto 0);
signal add_overflow : std_logic;
signal sub_overflow : std_logic;
begin
-- PROCESS
process(a, b, add_overflow, sub_overflow)
begin
case s is
--ADD
when "00" =>
--tmp <= conv_std_logic_vector(conv_integer(a) + conv_integer(b), 17);
tmp <= a + b;
overflow <= add_overflow;
--SUB
when "01" =>
--tmp <= conv_std_logic_vector(conv_integer(a) - conv_integer(b), 17);
tmp <= a - b;
overflow <= sub_overflow;
--AND
when "10" =>
tmp <= '0' & a AND b;
overflow <= '0';
--OR
when "11" =>
tmp <= '0' & a OR b;
overflow <= '0';
when others =>
tmp <= "00000000000000000";
end case;
--One-Bitters
if a > b then
gt <= '1';
lt <= '0';
eq <= '0';
elsif a < b then
lt <= '1';
gt <= '0';
eq <= '0';
elsif a = b then
eq <= '1';
lt <= '0';
gt <= '0';
end if;
end process;
--OUTPUTS
cout <= tmp(16);
r <= tmp(15 downto 0);
add_overflow <= '1' when (a(15) = b(15)) and (a(15) /= tmp(15))
else '0';
sub_overflow <= '1' when (a(15) = NOT b(15)) and (a(15) /= tmp(15))
else '0';
end beh;
EDIT: In the case that it might be my test bench, here's the code for my testbench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use IEEE.NUMERIC_STD.ALL;
entity alu16_tb is
end alu16_tb;
architecture behavior of alu16_tb is
component ALU16
port(
a : in std_logic_vector(15 downto 0);
b : in std_logic_vector(15 downto 0);
s : in std_logic_vector(1 downto 0);
r : out std_logic_vector(15 downto 0);
cout : out std_logic;
lt, eq, gt : out std_logic;
overflow : out std_logic
);
end component;
-- Signals to interface with the UUT
-- Set each of the input vectors to unique values to avoid
-- needing a process to drive them below
signal a : std_logic_vector(15 downto 0) := "0000000000000000";
signal b : std_logic_vector(15 downto 0) := "0000000000000000";
signal s : std_logic_vector(1 downto 0) := "00";
signal r : std_logic_vector(15 downto 0):= "0000000000000000";
signal cout : std_logic := '0';
signal lt : std_logic := '0';
signal gt : std_logic := '0';
signal eq : std_logic := '0';
signal overflow : std_logic := '0';
constant tick : time := 10 ns;
begin
-- Instantiate the Unit Under Test (UUT)
uut : ALU16 port map (
a => a,
b => b,
s => s,
r => r,
cout => cout,
lt => lt,
gt => gt,
eq => eq,
overflow => overflow
);
-- Drive selector bits
drive_s : process
begin
a <= "0000000000000001";
b <= "0000000000000010";
wait for (tick*2);
s <= "00";
wait for (tick*2);
s <= "01";
wait for (tick*2);
s <= "10";
wait for (tick*2);
s <= "11";
end process drive_s;
end;
I have created a 4-Bit Adder , now I want to add and sub 2 registers as sign-magnitude values
so , there is two register named A and B , two bits named As and Bs have sign bits of values in A and B , one XOR Gate for making 2-complement of B in subtraction and at the end result should store in A and As ( value and Sign ) and overflow bit in a register named AVF
this is a simple diagram :
Mode = 1 => Sub; Mod = 0 => Add
I have written this codes :
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;
FSum : 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;
ALU :
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;
C : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
D : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
Cs : IN STD_LOGIC;
Ds : IN STD_LOGIC;
Mode_ALU : IN STD_LOGIC;
Sum_ALU : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
AVF : 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 E, Temp_Cs, Temp_Ds : STD_LOGIC;
SIGNAL Temp_S : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
Add : Adder_4_Bit PORT MAP(C, D, Mode_ALU, Temp_S, E);
-- Sum_ALU <= Temp_S;
-- Temp_Cs <= Cs;
-- Temp_Ds <= Ds;
PROCESS
BEGIN
WAIT FOR 30 ns;
Sum_ALU <= Temp_S;
Temp_Cs <= Cs;
Temp_Ds <= Ds;
END PROCESS;
PROCESS(C, D, Cs, Ds, Mode_ALU)
BEGIN
CASE Mode_ALU IS
WHEN '0' =>
IF ((Cs XOR Ds) = '1') THEN
AVF <= '0';
IF (E = '1') THEN
IF (Temp_S = "0000") THEN
Temp_Cs <= '0';
END IF;
ELSE
Sum_ALU <= (NOT Temp_S) + "0001";
Temp_Cs <= NOT Cs;
END IF;
ELSE
AVF <= E;
END IF;
WHEN '1' =>
IF ((Cs XOR Ds) = '1') THEN
AVF <= E;
ELSE
AVF <= '0';
IF (E = '1') THEN
IF (Temp_S = "0000") THEN
Temp_Cs <= '0';
END IF;
ELSE
Sum_ALU <= (NOT Temp_S) + "0001";
Temp_Cs <= NOT Cs;
END IF;
END IF;
WHEN Others =>
--
END CASE;
END PROCESS;
END Declare;
Test Bench :
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;
C : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
D : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
Cs : IN STD_LOGIC;
Ds : IN STD_LOGIC;
Mode_ALU : IN STD_LOGIC;
Sum_ALU : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
AVF : OUT STD_LOGIC
);
END COMPONENT;
SIGNAL Xs, Ys, M, Av : STD_LOGIC;
SIGNAL X, Y, O : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
ALU_PM : ALU PORT MAP(X, Y, Xs, Ys, M, O, Av);
Mode_Process : PROCESS
BEGIN
M <= '1';
WAIT FOR 10 ns;
M <= '0';
WAIT FOR 10 ns;
END PROCESS;
Calc_Process : PROCESS
BEGIN
X <= "0010";
Y <= "1011";
Xs <= '0';
Ys <= '1';
WAIT FOR 20 ns;
X <= "0110";
Y <= "0011";
Xs <= '1';
Ys <= '1';
WAIT FOR 20 ns;
X <= "0010";
Y <= "1011";
Xs <= '0';
Ys <= '1';
WAIT FOR 20 ns;
END PROCESS;
END Declare;
when I run test bench , the result value filled with 'X' :
I know the problem is in ALU , but I can`t find the problem.
There is no problem in 4-Bit Adder , I have tested.
Another problem is calc sign bit of the result , Is the PROCESSes I have written correct ?
At all what I should do to Code the diagram above ?
thanks ...
You have multiple drivers on signals Sum_ALU, Temp_Cs and Temp_Ds in file alu.vhd.
PROCESS
BEGIN
WAIT FOR 30 ns;
Sum_ALU <= Temp_S;
Temp_Cs <= Cs;
Temp_Ds <= Ds;
END PROCESS;
PROCESS(C, D, Cs, Ds, Mode_ALU)
BEGIN
CASE Mode_ALU IS
WHEN '0' =>
IF ((Cs XOR Ds) = '1') THEN
AVF <= '0';
IF (E = '1') THEN
IF (Temp_S = "0000") THEN
Temp_Cs <= '0';
END IF;
ELSE
Sum_ALU <= (NOT Temp_S) + "0001";
Temp_Cs <= NOT Cs;
END IF;
ELSE
AVF <= E;
END IF;
WHEN '1' =>
IF ((Cs XOR Ds) = '1') THEN
AVF <= E;
ELSE
AVF <= '0';
IF (E = '1') THEN
IF (Temp_S = "0000") THEN
Temp_Cs <= '0';
END IF;
ELSE
Sum_ALU <= (NOT Temp_S) + "0001";
Temp_Cs <= NOT Cs;
END IF;
END IF;
WHEN Others =>
--
END CASE;
END PROCESS;
Whenever you assign a signal in multiple process, as you did here, it yields multiple drivers. If the drivers don't agree on the value (one drives '1' and the other '0' for example), the result is undefined ('X'). You will have to solve the issue yourself, as I'm not sure what is the correct behaviour. However, if you remove the first process, no undefined signal appears in the simulation.
Furthermore, you should be aware that the statement wait for 30 ns; is not synthesizable. The synthesizer may either fail or simply ignore the wait statement. If your goal was to simulate routing delay, then your usage is fine, otherwise you should change the logic if your goal is synthesis.
Finally, your second process would generate latches if synthesized. Latches are memory element which are known to break circuits when used improperly. They are the main reason why circuit behaviour do not match simulations, and should be removed. Latches appears whenever a signal you assign in a combinational process is not assign in every path of the process. That means Temp_Cs and Sum_ALU needs an assignment every time the process is evaluated (AVF is fine as is); every if must have an else, and all signals must be assigned. One simple way to deal with this is to give default values at the beginning of the process, so that every signal has an assignments. If a signal is assigned multiple times in the evaluation of the process, then only the last assignation will be effective. For example:
PROCESS(C, D, Cs, Ds, Mode_ALU)
BEGIN
Temp_Cs <= Cs;
Sum_ALU <= Temp_S;
CASE Mode_ALU IS
While making assignations in the others branch of the case is not necessary, I would recommend it nevertheless. You can assign all signals to 'X' for example.
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 ...