im pretty new to the vhdl language so please bear with me. I just did the vhdl code for a 1 bit adder, but I am having trouble writing for the 4bit adder. This is what I got so far, if anybody could point me in the right direction of what to look up that would be awesome!
VHDL code:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY Adder4 IS
GENERIC(CONSTANT N: INTEGER := 4);
PORT(
a, b: IN STD_LOGIC_VECTOR(N-1 DOWNTO 0); -- Input SW[7..4]: a[3..0] inputs,
-- SW[3..0]: b[3..0]
sum: OUT STD_LOGIC_VECTOR(N-1 DOWNTO 0); -- Output LEDR[3..0]
cOut: OUT STD_LOGIC -- Output LEDR[4]
);
END Adder4;
ARCHITECTURE imp OF Adder4 IS
COMPONENT Adder1
PORT(
a, b, cIn : in STD_LOGIC;
sum, cOut : out STD_LOGIC);
END COMPONENT;
SIGNAL carry_sig: std_logic_vector(N DOWNTO 0);
BEGIN
-- What to write here?
END imp;
In deference to sharth's fine answer on the chance you did intend to have an N number of Adder1s instantiated in Adder4:
ARCHITECTURE imp OF Adder4 IS
COMPONENT Adder1
PORT(
a, b, cIn : in STD_LOGIC;
sum, cOut : out STD_LOGIC);
END COMPONENT;
SIGNAL carry_sig: std_logic_vector(N-1 DOWNTO 0);
signal carry_in: std_logic_vector(N-1 DOWNTO 0);
BEGIN
-- What to write here?
carry_in <= ((carry_sig(N-2 downto 0)) &'0');
Adders:
for i in 0 to N-1 generate
begin
ADD1:
Adder1 port map (
a => a(i),
b => b(i),
cIn => carry_in(i),
sum => sum(i),
cOut => carry_sig(i)
);
end generate;
Carry_Out:
cOut <= carry_sig(N-1);
END imp;
ARCHITECTURE gen OF Adder4 IS
COMPONENT Adder1
PORT(
a, b, cIn : in STD_LOGIC;
sum, cOut : out STD_LOGIC);
END COMPONENT;
SIGNAL carry_sig: std_logic_vector(N-1 DOWNTO 0);
BEGIN
-- What to write here?
Adders:
for i in 0 to N-1 generate
ADD0:
if i = 0 generate
Add1:
Adder1 port map (
a => a(i),
b => b(i),
cIn => '0',
sum => sum(i),
cOut => carry_sig(i)
);
end generate;
ADDN:
if i /= 0 generate
Add1:
Adder1 port map (
a => a(i),
b => b(i),
cIn => carry_sig(i-1),
sum => sum(i),
cOut => carry_sig(i)
);
end generate;
end generate;
Carry_Out:
cOut <= carry_sig(N-1);
END architecture;
I prefer the first architecture (imp) myself, requiring a second std_logic_vector for carry_in, but greatly simplifying any generate construct. There's a difference in hierarchy between the two and first is easier to read.
The first architecture (imp) also shows how to instantiate Adder1 four times manually, eliminating the generate construct and substituting all (i) range expressions for their respective Adder1 instance range expressions ((0),(1),(2),(3), respectively).
The manually instantiated adder1s would look something like:
-- Note in this case you'd likely declare all the std_logic_vector with
-- ranges (3 downto 0)
SIGNAL carry_sig: std_logic_vector(3 DOWNTO 0);
signal carry_in: std_logic_vector(3 downto 0);
BEGIN
-- What to write here?
carry_in <= ((carry_sig(2 downto 0)) &'0');
ADD0:
Adder1 port map (
a => a(0),
b => b(0),
cIn => carry_in(0),
sum => sum(0),
cOut => carry_sig(0)
);
...
ADD3:
Adder1 port map (
a => a(3),
b => b(3),
cIn => carry_in(3),
sum => sum(3),
cOut => carry_sig(3)
);
cOut <= carry_sig(3); -- or connect directly to cOut in ADD3 above
The additional carry_in vector using carry_sig adjusted upward with a least significant carry_in of '0' makes it simple to write. It can also be easier to read implementing a carry look ahead method if the carry in and carry out signals are separately named.
A test bench can also accommodate a width N Adder4:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity adder4_tb is
constant N: natural := 4;
end entity;
architecture tb of adder4_tb is
signal a,b,sum: std_logic_vector (N-1 downto 0);
signal carryout: std_logic;
begin
DUT: entity work.Adder4
generic map (N => N) -- associates formal N with actual N (a constant)
port map (
a => a,
b => b,
sum => sum,
cOut => carryout
);
STIMULUS:
process
variable i,j: integer;
begin
for i in 0 to N*N-1 loop
for j in 0 to N*N-1 loop
a <= std_logic_vector(to_unsigned(i,N));
b <= std_logic_vector(to_unsigned(j,N));
wait for 10 ns; -- so we can view waveform display
end loop;
end loop;
wait; -- end the simulation
end process;
end architecture;
All this without regard to carry tree delay time which can be affected by implementation or the use of fast carry circuits (e.g. carry look ahead).
And this gives us a simulation that looks like:
Or for a closer view:
When using a generate statement based architecture if you changed the declaration of N you'd have an adder that would synthesis and simulate in variable widths specified by N up until the ripple carry would no longer work for the input data rate (10 ns in the test bench currently).
Note the generic map association of he generic N formal with the actual N declared in the test bench means in this case that the N declared in the test bench sets the width N in Adder4 as well.