Newbee in VHDL ... why is this not working?
From
Christoph Linden@21:1/5 to
All on Thu May 14 04:49:11 2020
Hi all,
I am getting into VHDL right now and doing the first implementation of some architecutres. For me to learn I follow nand2tetris, that uses its own HDL and translating that for my learning into VHDL.
I am at the point of createing a 4bit adder with carry look ahead.
I have defined two entities CLA4 and Add4LAC.
CLA4 is supposed to calculate the look ahead carry
Add4LAC is a 4bit adder with carry that uses CLA4 to calculate the carries of every bit.
I also have written a testbench to check it with ModelSim. The result is weird and I do not understand it at all.
I have defined in my simulator the following signals:
a,b (3 downto 0) --operands
cin --carry in
sum (3 downto 0) -- output of the sum
carry -- carry output.
for testing purposes i also added the expected results as
csum and ccarry (compare sum and compare carry).
If I now run it, with the following input:
a <= "0000";
b <= "0000";
cin <= '0';
csum <= "0000";
ccarry <= '0';
The result is not as in csum and ccarry, but instead:
# a b cin sum coutcsum ccout
# 0000 0000 0 UUUU 0 0000 0
# ** Note: Result Mismatch!
# Time: 10 ns Iteration: 0 Instance: /add4lactb
# 1111 1111 0 UU00 0 1110 1
# ** Note: Result Mismatch!
# Time: 20 ns Iteration: 0 Instance: /add4lactb
Can someone please help me to understand what is wrong? I am getting undefined output ... ???
I must have made a generic mistake and have no idea what it is. Even stepping through the code with ModelSim does not give any hint.
Here is the code:
-- Full 16 bit adder for Hack Computer with look ahead carry
-- From the book nand2tetris, translated to vhdl
-- by Christoph Linden
-- Look ahead carry calculation for 4 bits.
-- length to be defined as constant c_WordWidth
library ieee;
use ieee.std_logic_1164.all;
entity CLA4 is
port(
-- inputs
i_g : in std_logic_vector (3 downto 0);
i_p : in std_logic_vector (3 downto 0);
i_cin : in std_logic;
-- outputs
o_cout : out std_logic_vector (3 downto 0) );
end entity;
architecture cal4 of CLA4 is
signal cp0 : std_logic;
signal cp0p1 : std_logic;
signal cp0p1p2 : std_logic;
signal cp0p1p2p3 : std_logic;
signal g0p1 : std_logic;
signal g0p1p2 : std_logic;
signal g0p1p2p3 : std_logic;
signal g1p2 : std_logic;
signal g1p2p3 : std_logic;
signal g2p3 : std_logic;
begin
process (i_p, i_g, i_cin) is
begin
-- caculate bit 1 preproduct and carry out 0
-- And(a=p[0],b=cin,out=p0c);
-- Or(a=p0c,b=g[0],out=cout[0]);
cp0 <= i_p(0) and i_cin;
o_cout(0) <= cp0 or i_g(0);
-- calculate bit 2 preproduct and carry out 1
-- And3Way(a=cin, b=p[0], c=p[1], out=cp0p1);
-- And(a=g[0],b=p[1],out=g0p1);
-- Or3Way(a=cp0p1,b=g0p1,c=g[1],out=cout[1]);
cp0p1 <= i_cin and i_p(0) and i_p(1);
g0p1 <= i_g(0) and i_p(1);
o_cout(1) <= cp0p1 or g0p1 or i_g(1);
--calculate bit 3 preproducts and carry out 2
-- And4Way(a=cin, b=p[0], c=p[1], d=p[2], out=cp0p1p2);
-- And3Way(a=g[0],b=p[1],c=p[2],out=g0p1p2);
-- And(a=g[1],b=p[2],out=g1p2);
-- Or4Way(a=cp0p1p2,b=g0p1p2,c=g1p2,d=g[2],out=cout[2]);
cp0p1p2 <= i_cin and i_p(0) and i_p(1) and i_p(2);
g0p1p2 <= i_g(0) and i_p(1) and i_p(2);
g1p2 <= i_g(1) and i_p(2);
o_cout(2) <= cp0p1p2 or g0p1p2 or g1p2 or i_g(2);
--calculate bit 4 preproducts and carry out 4
-- And5Way(a=cin, b=p[0], c=p[1], d=p[2], e=p[3], out=cp0p1p2p3);
-- And4Way(a=g[0], b=p[1], c=p[2], d=p[3], out=g0p1p2p3);
-- And3Way(a=g[1],b=p[2],c=p[3],out=g1p2p3);
-- And(a=g[2],b=p[3],out=g2p3);
-- Or5Way(a=cp0p1p2p3,b=g0p1p2p3,c=g1p2p3,d=g2p3, e=g[3],out=cout[3]);
cp0p1p2p3 <= i_cin and i_p(0) and i_p(1) and i_p(2) and i_p(3);
g0p1p2p3 <= i_g(0) and i_p(1) and i_p(2) and i_p(3);
g1p2p3 <= i_g(1) and i_p(2) and i_p(3);
g2p3 <= i_g(2) and i_p(3);
o_cout(3) <= cp0p1p2p3 and g0p1p2p3 and g1p2p3 and g2p3;
end process;
end architecture;
-- a 4 bit carry look ahead adder.
library ieee;
use ieee.std_logic_1164.all;
entity Add4LAC is
port(
-- inputs
i_a : in std_logic_vector (3 downto 0);
i_b : in std_logic_vector (3 downto 0);
i_cin : in std_logic;
-- outputs
o_sum : out std_logic_vector (3 downto 0);
o_carry : out std_logic );
end entity;
architecture add4lac of Add4LAC is
component CLA4
port(
-- inputs
i_g : in std_logic_vector (3 downto 0);
i_p : in std_logic_vector (3 downto 0);
i_cin : in std_logic := 'L';
-- outputs
o_cout : out std_logic_vector (3 downto 0) );
end component;
signal g0,g1,g2,g3 : std_logic;
signal p0,p1,p2,p3 : std_logic;
signal c0,c1,c2 : std_logic;
begin
u1: CLA4
port map(
i_g(0) => g0,
i_g(1) => g1,
i_g(2) => g2,
i_g(3) => g3,
i_p(0) => p0,
i_p(1) => p1,
i_p(2) => p2,
i_p(3) => p3,
o_cout(0) => c0,
o_cout(1) => c1,
o_cout(2) => c2,
o_cout(3) => o_carry );
process (i_a,i_b,i_cin) is
begin
-- Bit 0
g0 <= i_a(0) and i_b(0);
p0 <= i_a(0) xor i_b(0);
o_sum(0) <= p0 xor i_cin;
-- Bit 1
g1 <= i_a(1) and i_b(1);
p1 <= i_a(1) xor i_b(1);
o_sum(1) <= p1 xor c0;
-- Bit 2
g2 <= i_a(2) and i_b(2);
p2 <= i_a(2) xor i_b(2);
o_sum(2) <= p2 xor c1;
-- Bit 3
g3 <= i_a(3) and i_b(3);
p3 <= i_a(3) xor i_b(3);
o_sum(3) <= p3 xor c2;
end process;
end architecture;
Here is the tb code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use ieee.std_logic_textio.all;
entity Add4LACTB is
end entity;
architecture sim of Add4LACTB is
signal a,b,sum,csum : std_logic_vector (3 downto 0);
signal cin,carry,ccarry : std_logic;
component Add4LAC
port(
-- inputs
i_a : in std_logic_vector (3 downto 0);
i_b : in std_logic_vector (3 downto 0);
i_cin : in std_logic;
-- outputs
o_sum : out std_logic_vector (3 downto 0);
o_carry : out std_logic );
end component;
begin
Adder1: Add4LAC
port map(
i_a => a,
i_b => b,
i_cin => cin,
o_sum => sum,
o_carry => carry );
process is
variable v_myline : line;
begin
write(v_myline, string'(" a"), left, 5);
write(v_myline, string'(" b"), left, 5);
write(v_myline, string'(" cin"), left, 5);
write(v_myline, string'(" sum"), left, 5);
write(v_myline, string'(" cout"), left, 5);
write(v_myline, string'("csum"), left, 5);
write(v_myline, string'("ccout"), left, 5);
writeline(output, v_myline);
-- testscenarios
--set a %B0000000000000000,
--set b %B0000000000000000,
--set a %B0000000000000000,
--set b %B1111111111111111,
--set a %B1111111111111111,
--set b %B1111111111111111,
--set a %B1010101010101010,
--set b %B0101010101010101,
--set a %B0011110011000011,
--set b %B0000111111110000,
--set a %B0001001000110100,
--set b %B1001100001110110,
a <= "0000";
b <= "0000";
cin <= '0';
csum <= "0000";
ccarry <= '0';
wait for 10 ns;
write(v_myline, a, left, 5);
write(v_myline, b, left, 5);
write(v_myline, cin, left, 5);
write(v_myline, sum, left, 5);
write(v_myline, carry, left, 5);
write(v_myline, csum, left, 5);
write(v_myline, ccarry, left, 5);
writeline(output, v_myline);
if sum /= csum or carry /= ccarry then
report "Result Mismatch!";
-- wait ;
end if;
a <= "1111";
b <= "1111";
cin <= '0';
csum <= "1110";
ccarry <= '1';
wait for 10 ns;
write(v_myline, a, left, 5);
write(v_myline, b, left, 5);
write(v_myline, cin, left, 5);
write(v_myline, sum, left, 5);
write(v_myline, carry, left, 5);
write(v_myline, csum, left, 5);
write(v_myline, ccarry, left, 5);
writeline(output, v_myline);
if sum /= csum or carry /= ccarry then
report "Result Mismatch!";
wait ;
end if;
wait;
end process;
end architecture;
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)
From
Christoph Linden@21:1/5 to
All on Thu May 14 07:59:38 2020
Okay reworked it and (besides a bug in there) it now does what it supposed to do.
However I am not sure if that is how you would do such things normally.
Should I use a fully
-- Look ahead carry calculation for 4 bits.
-- length to be defined as constant c_WordWidth
library ieee;
use ieee.std_logic_1164.all;
entity CLA4 is
port(
-- inputs
i_g : in std_logic_vector (3 downto 0);
i_p : in std_logic_vector (3 downto 0);
i_cin : in std_logic;
-- outputs
o_cout : out std_logic_vector (3 downto 0) );
end entity;
architecture cla4 of CLA4 is
signal cp0 : std_logic;
signal cp0p1 : std_logic;
signal cp0p1p2 : std_logic;
signal cp0p1p2p3 : std_logic;
signal g0p1 : std_logic;
signal g0p1p2 : std_logic;
signal g0p1p2p3 : std_logic;
signal g1p2 : std_logic;
signal g1p2p3 : std_logic;
signal g2p3 : std_logic;
begin
process (i_p, i_g, i_cin) is
begin
-- caculate bit 1 preproduct and carry out 0
-- And(a=p[0],b=cin,out=p0c);
-- Or(a=p0c,b=g[0],out=cout[0]);
cp0 <= i_p(0) and i_cin;
-- calculate bit 2 preproduct and carry out 1
-- And3Way(a=cin, b=p[0], c=p[1], out=cp0p1);
-- And(a=g[0],b=p[1],out=g0p1);
-- Or3Way(a=cp0p1,b=g0p1,c=g[1],out=cout[1]);
cp0p1 <= i_cin and i_p(0) and i_p(1);
g0p1 <= i_g(0) and i_p(1);
--calculate bit 3 preproducts and carry out 2
-- And4Way(a=cin, b=p[0], c=p[1], d=p[2], out=cp0p1p2);
-- And3Way(a=g[0],b=p[1],c=p[2],out=g0p1p2);
-- And(a=g[1],b=p[2],out=g1p2);
-- Or4Way(a=cp0p1p2,b=g0p1p2,c=g1p2,d=g[2],out=cout[2]);
cp0p1p2 <= i_cin and i_p(0) and i_p(1) and i_p(2);
g0p1p2 <= i_g(0) and i_p(1) and i_p(2);
g1p2 <= i_g(1) and i_p(2);
--calculate bit 4 preproducts and carry out 4
-- And5Way(a=cin, b=p[0], c=p[1], d=p[2], e=p[3], out=cp0p1p2p3);
-- And4Way(a=g[0], b=p[1], c=p[2], d=p[3], out=g0p1p2p3);
-- And3Way(a=g[1],b=p[2],c=p[3],out=g1p2p3);
-- And(a=g[2],b=p[3],out=g2p3);
-- Or5Way(a=cp0p1p2p3,b=g0p1p2p3,c=g1p2p3,d=g2p3, e=g[3],out=cout[3]);
cp0p1p2p3 <= i_cin and i_p(0) and i_p(1) and i_p(2) and i_p(3);
g0p1p2p3 <= i_g(0) and i_p(1) and i_p(2) and i_p(3);
g1p2p3 <= i_g(1) and i_p(2) and i_p(3);
g2p3 <= i_g(2) and i_p(3);
end process;
process (cp0,cp0p1,g0p1,cp0p1p2,g0p1p2,
g1p2,cp0p1p2p3,g0p1p2p3,g1p2p3,g2p3,i_g) is
begin
o_cout(0) <= cp0 or i_g(0);
o_cout(1) <= cp0p1 or g0p1 or i_g(1);
o_cout(2) <= cp0p1p2 or g0p1p2 or g1p2 or i_g(2);
o_cout(3) <= cp0p1p2p3 or g0p1p2p3 or g1p2p3 or g2p3 or i_g(3);
end process;
end architecture;
-- a 4 bit carry look ahead adder.
library ieee;
use ieee.std_logic_1164.all;
entity Add4LAC is
port(
-- inputs
i_a : in std_logic_vector (3 downto 0);
i_b : in std_logic_vector (3 downto 0);
i_cin : in std_logic;
-- outputs
o_sum : out std_logic_vector (3 downto 0);
o_carry : out std_logic );
end entity;
architecture add4lac of Add4LAC is
component CLA4
port(
-- inputs
i_g : in std_logic_vector (3 downto 0);
i_p : in std_logic_vector (3 downto 0);
i_cin : in std_logic := 'L';
-- outputs
o_cout : out std_logic_vector (3 downto 0) );
end component;
signal g0,g1,g2,g3 : std_logic;
signal p0,p1,p2,p3 : std_logic;
signal c0,c1,c2 : std_logic;
begin
u1: CLA4
port map(
i_g(0) => g0,
i_g(1) => g1,
i_g(2) => g2,
i_g(3) => g3,
i_p(0) => p0,
i_p(1) => p1,
i_p(2) => p2,
i_p(3) => p3,
o_cout(0) => c0,
o_cout(1) => c1,
o_cout(2) => c2,
o_cout(3) => o_carry );
process (i_a,i_b,i_cin) is
begin
-- Bit 0
g0 <= i_a(0) and i_b(0);
p0 <= i_a(0) xor i_b(0);
-- Bit 1
g1 <= i_a(1) and i_b(1);
p1 <= i_a(1) xor i_b(1);
-- Bit 2
g2 <= i_a(2) and i_b(2);
p2 <= i_a(2) xor i_b(2);
-- Bit 3
g3 <= i_a(3) and i_b(3);
p3 <= i_a(3) xor i_b(3);
end process;
process(c0,c1,c2,p0,p1,p2,p3) is
begin
o_sum(0) <= p0 xor i_cin;
o_sum(1) <= p1 xor c0;
o_sum(2) <= p2 xor c1;
o_sum(3) <= p3 xor c2;
end process;
end architecture;
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)
From
Rick C@21:1/5 to
Christoph Linden on Thu May 14 15:45:59 2020
On Thursday, May 14, 2020 at 10:59:41 AM UTC-4, Christoph Linden wrote:
Okay reworked it and (besides a bug in there) it now does what it supposed to do.
However I am not sure if that is how you would do such things normally.
Should I use a fully
I don't know, you didn't finish the question.
You might look at the regularity in the calculations and use looping constructs to evaluate them. Then you would need either processes or generate statements.
For example, just as you use a vector for o_sum (which you never declare either internally or as an output) you can define your intermediate terms as vectors letting the index point to the right one at the right time.
You will need to give this a bit of thought and a nice diagram of the arrangement of the logical entities would help to see the regularity of the problem being solved.
Here is your code without the processes.
-- Look ahead carry calculation for 4 bits.
-- length to be defined as constant c_WordWidth
library ieee;
use ieee.std_logic_1164.all;
entity CLA4 is
port(
-- inputs
i_g : in std_logic_vector (3 downto 0);
i_p : in std_logic_vector (3 downto 0);
i_cin : in std_logic;
-- outputs
o_cout : out std_logic_vector (3 downto 0) );
end entity;
architecture cla4 of CLA4 is
signal cp0 : std_logic;
signal cp0p1 : std_logic;
signal cp0p1p2 : std_logic;
signal cp0p1p2p3 : std_logic;
signal g0p1 : std_logic;
signal g0p1p2 : std_logic;
signal g0p1p2p3 : std_logic;
signal g1p2 : std_logic;
signal g1p2p3 : std_logic;
signal g2p3 : std_logic;
begin
cp0 <= i_p(0) and i_cin;
cp0p1 <= i_cin and i_p(0) and i_p(1);
g0p1 <= i_g(0) and i_p(1);
cp0p1p2 <= i_cin and i_p(0) and i_p(1) and i_p(2);
g0p1p2 <= i_g(0) and i_p(1) and i_p(2);
g1p2 <= i_g(1) and i_p(2);
cp0p1p2p3 <= i_cin and i_p(0) and i_p(1) and i_p(2) and i_p(3);
g0p1p2p3 <= i_g(0) and i_p(1) and i_p(2) and i_p(3);
g1p2p3 <= i_g(1) and i_p(2) and i_p(3);
g2p3 <= i_g(2) and i_p(3);
o_cout(0) <= cp0 or i_g(0);
o_cout(1) <= cp0p1 or g0p1 or i_g(1);
o_cout(2) <= cp0p1p2 or g0p1p2 or g1p2 or i_g(2);
o_cout(3) <= cp0p1p2p3 or g0p1p2p3 or g1p2p3 or g2p3 or i_g(3);
-- Bit 1
g1 <= i_a(1) and i_b(1);
p1 <= i_a(1) xor i_b(1);
-- Bit 2
g2 <= i_a(2) and i_b(2);
p2 <= i_a(2) xor i_b(2);
-- Bit 3
g3 <= i_a(3) and i_b(3);
p3 <= i_a(3) xor i_b(3);
o_sum(0) <= p0 xor i_cin;
o_sum(1) <= p1 xor c0;
o_sum(2) <= p2 xor c1;
o_sum(3) <= p3 xor c2;
end architecture;
--
Rick C.
+ Get 1,000 miles of free Supercharging
+ Tesla referral code -
https://ts.la/richard11209
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)