• 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 Anssi Saari@21:1/5 to Christoph Linden on Thu May 14 15:53:37 2020
    Christoph Linden <christoph.linden@googlemail.com> writes:

    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.

    Doesn't seem like a great way to learn. Do you have a software
    background? Anyways, a quick comment on the CLA4.

    architecture cal4 of CLA4 is

    [...]

    begin

    process (i_p, i_g, i_cin) is

    begin

    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);

    The nature of hardware is such that these three assignments happen in
    parallel, hence your o_cout(1) ends up being U at time 0. Same for
    o_cout(2). I don't remember off hand how to code such primitives in VHDL
    but somehow you need to add delay between these assignments. Or do the assignment all at once.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Nicolas Matringe@21:1/5 to Christoph Linden on Thu May 14 14:29:54 2020
    Hello

    On 2020-05-14 13:49, Christoph Linden wrote:
    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.

    [...]

    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);
    [...]

    This won't work. You're treating signals as variables, which they are
    not. Remember VHDL is NOT software.
    A signal gets its value assigned at the end of the process. In the
    snippet above, cp0 equal 'U' because it's never been assigned anything
    yet. Then you compute a value (i_p(0) and i_cin) to be assigned to cp0.
    On the next line, though, cp0 is still equal to 'U' because the computed
    value will not be assigned until the end of the process.
    Depending on what you want to do, you can either write a second process
    that will compute o_cout(0) based on cp0, or make cp0 a variable (local
    to the process) instead of a signal (local to the architecture)

    Nicolas

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christoph Linden@21:1/5 to All on Thu May 14 07:36:08 2020
    Am Donnerstag, 14. Mai 2020 14:29:56 UTC+2 schrieb Nicolas Matringe:

    This won't work. You're treating signals as variables, which they are
    not. Remember VHDL is NOT software.
    A signal gets its value assigned at the end of the process. In the
    snippet above, cp0 equal 'U' because it's never been assigned anything
    yet. Then you compute a value (i_p(0) and i_cin) to be assigned to cp0.
    On the next line, though, cp0 is still equal to 'U' because the computed value will not be assigned until the end of the process.
    Depending on what you want to do, you can either write a second process
    that will compute o_cout(0) based on cp0, or make cp0 a variable (local
    to the process) instead of a signal (local to the architecture)

    Nicolas

    Hi Nicolas, thanks for the response.

    Also Thanks Anssi.

    Trying to add some additional information.

    I just transferred it from the HDL of nand2tetris, so that might be a bad way of doing so.

    What I want to create is a combinational logic (actually defining it at gate level), where those things propagate through.

    Obiously I could write an adder in a much simpler way in VHDL, but that is not my goal.

    I try to first implement it as close to the gate level as posible without writing gate (e.g. AND, NOT, XOR gates).

    What I am looking for is something like a propagation delay as it will happen naturally.

    If I would wire discrete AND/OR Chips and want to do a ( a AND b ) OR c I would simply wire the output of the AND chip to the one input of the or gate and then with propagation delay of both gates I will receive the output at OR.

    This is what I assume that all the statements would automatically do.

    Can you please explain quickly how I would achieve that without implementing real gates and "wire" them up in VHDL but using a similar construct? Or in other words, how would you create this and/or example from above.

    Now I try to split this into processes... I tried to avoid variables. Is variables a common thing to use in normal VHDL designs? I thougt it is more for use in loops, that in the end do not result in logic, but just in the behaviour description...

    --- 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 09:59:42 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

    -- 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;

    You seem to like processes for everything. There is no reason to put this particular code into processes. It can all be concurrent logic outside of processes. Then to test your code you would normally create a test fixture to instantiate your adder
    code, supply inputs and check outputs. Processes are useful for combinational logic to group signals when they share the same inputs. When assignments don't share the same inputs related assignments can be grouped using white space with a lot less
    typing.

    process (cp0,cp0p1,g0p1,cp0p1p2,g0p1p2,
    g1p2,cp0p1p2p3,g0p1p2p3,g1p2p3,g2p3,i_g) is
    begin
    ...
    end process;

    Way too much typing for me.

    Just my 2000 millicents worth.

    BTW, the question in your post seems to have been cut off.

    --

    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)
  • 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)
  • From Christoph Linden@21:1/5 to All on Thu May 14 23:00:25 2020
    Am Freitag, 15. Mai 2020 00:46:01 UTC+2 schrieb Rick C:
    Thank you Rick, very helpful.

    1. Unfortunately I do not know anymore what the questions should have been. I believe it was in the ballpark how I can do this similar to a structural design but without defining single and gates.

    2. The o_sum part. The problem is, that for whatever reason google.groups interpreted part of the code as "quote". So if you click on the quote you see, that it is actually two entities. One entity is calculating the carry look ahead and the other is
    doing the actual add of the four bits.

    That is why it looks so weird if you do not unfold the quote.

    But anyhow I understood what you was saying and yes, I just used the process, because I did not understood that I do not need to use process all the time.

    I will give it a try.

    Is the following understanding correct:

    Process for sequential (a must to react on the clock and the edge of the signal)

    no process for combinatory circuits (such as ALU designs)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rick C@21:1/5 to Christoph Linden on Fri May 15 00:02:56 2020
    On Friday, May 15, 2020 at 2:00:27 AM UTC-4, Christoph Linden wrote:
    Am Freitag, 15. Mai 2020 00:46:01 UTC+2 schrieb Rick C:
    Thank you Rick, very helpful.

    1. Unfortunately I do not know anymore what the questions should have been. I believe it was in the ballpark how I can do this similar to a structural design but without defining single and gates.

    2. The o_sum part. The problem is, that for whatever reason google.groups interpreted part of the code as "quote". So if you click on the quote you see, that it is actually two entities. One entity is calculating the carry look ahead and the other is
    doing the actual add of the four bits.

    That is why it looks so weird if you do not unfold the quote.

    But anyhow I understood what you was saying and yes, I just used the process, because I did not understood that I do not need to use process all the time.

    I will give it a try.

    Is the following understanding correct:

    Process for sequential (a must to react on the clock and the edge of the signal)

    no process for combinatory circuits (such as ALU designs)

    It is obvious you are just getting started, so I understand. I had no one to ask when I learned to use VHDL. I took a week course and the instructor sucked so badly he answered questions wrong. It's one thing not to know, but giving out bad info is
    terrible.

    I won't say you should not use a process for combinational circuits. A process is of no value for simple assignments to signals. Processes also have variables which are updated immediately, unlike signals which are not updated until the process ends
    and the simulation proceeds to the next time step which is a delta time step. That's a bit complicated and I'm happy to explain it if you want. Most people consider that signals are updated at the end of the process which is essentially correct.

    Concurrent code does not use variables. Every concurrent assignment is actually a process. It runs whenever any of the inputs change state, just like a process. Essentially all concurrent code produces logic that runs in parallel. Even the process
    statement is concurrent code creating a process that runs in parallel with other processes including the concurrent logic. Hence the name concurrent.

    Variables can used in sequential code such as processes, functions and procedures. They allow code to be written in a similar manner to code written for CPUs which are executed sequentially. For example you can write

    a := b + c;
    a := a + d;

    This would add b, c and d and assign it to a in the order shown. If a were a signal, the last assignment in the process would be the only one taking effect. Notice a different assignment operator is used for signals <= and variables :=

    Often beginners confuse processes with subroutines like sequential programming languages use. You don't seem to have that confusion.

    So there are many ways to do the job. It also makes a difference if you are working with VHDL 2008 or an older version. There are many improvements in 2008 that makes coding easier. Often you must enable VHDL 2008 in your tool even if it is capable.

    I hope this helps.

    --

    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)
  • From Christoph Linden@21:1/5 to All on Fri May 15 04:06:40 2020
    Am Freitag, 15. Mai 2020 09:02:59 UTC+2 schrieb Rick C:
    On Friday, May 15, 2020 at 2:00:27 AM UTC-4, Christoph Linden wrote:
    Am Freitag, 15. Mai 2020 00:46:01 UTC+2 schrieb Rick C:
    Thank you Rick, very helpful.

    1. Unfortunately I do not know anymore what the questions should have been. I believe it was in the ballpark how I can do this similar to a structural design but without defining single and gates.

    2. The o_sum part. The problem is, that for whatever reason google.groups interpreted part of the code as "quote". So if you click on the quote you see, that it is actually two entities. One entity is calculating the carry look ahead and the other
    is doing the actual add of the four bits.

    That is why it looks so weird if you do not unfold the quote.

    But anyhow I understood what you was saying and yes, I just used the process, because I did not understood that I do not need to use process all the time.

    I will give it a try.

    Is the following understanding correct:

    Process for sequential (a must to react on the clock and the edge of the signal)

    no process for combinatory circuits (such as ALU designs)

    It is obvious you are just getting started, so I understand. I had no one to ask when I learned to use VHDL. I took a week course and the instructor sucked so badly he answered questions wrong. It's one thing not to know, but giving out bad info is
    terrible.

    I won't say you should not use a process for combinational circuits. A process is of no value for simple assignments to signals. Processes also have variables which are updated immediately, unlike signals which are not updated until the process ends
    and the simulation proceeds to the next time step which is a delta time step. That's a bit complicated and I'm happy to explain it if you want. Most people consider that signals are updated at the end of the process which is essentially correct.

    Concurrent code does not use variables. Every concurrent assignment is actually a process. It runs whenever any of the inputs change state, just like a process. Essentially all concurrent code produces logic that runs in parallel. Even the process
    statement is concurrent code creating a process that runs in parallel with other processes including the concurrent logic. Hence the name concurrent.

    Variables can used in sequential code such as processes, functions and procedures. They allow code to be written in a similar manner to code written for CPUs which are executed sequentially. For example you can write

    a := b + c;
    a := a + d;

    This would add b, c and d and assign it to a in the order shown. If a were a signal, the last assignment in the process would be the only one taking effect. Notice a different assignment operator is used for signals <= and variables :=

    Often beginners confuse processes with subroutines like sequential programming languages use. You don't seem to have that confusion.

    So there are many ways to do the job. It also makes a difference if you are working with VHDL 2008 or an older version. There are many improvements in 2008 that makes coding easier. Often you must enable VHDL 2008 in your tool even if it is capable.


    I hope this helps.

    --

    Rick C.

    -- Get 1,000 miles of free Supercharging
    -- Tesla referral code - https://ts.la/richard11209

    Thank you so much Rick, that really helps and is highly appreciated.

    I was aware of the parallelity of execution, but actually the process is only update one time... So you are right, what I would need to do would be putting each line in a process, which is pretty much pointless.

    I came from nand2tetris, which has a much more simplified HDL to get the principles of chip design transported/tought. I now wanted to get into a real HDL to implement this chip (a very simple 16bit processor) into an FPGA.

    So i learned some of the tutorials from https://vhdlwhiz.com/, which helped alot - for instance all the basic gates and muxers and stuff I could implement easily. But at that point I struggled because of simply not really understanding what a process
    does and why something within a process is not the same as a simple concurrent logic without any process.

    You helped me on that alot and it is now much clearer. I am pretty sure I will stumble accross it again in the future, as things are getting more complicated, but for now.

    THANKS A MILLION, really appreciated.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rick C@21:1/5 to Christoph Linden on Fri May 15 04:40:01 2020
    On Friday, May 15, 2020 at 7:06:42 AM UTC-4, Christoph Linden wrote:
    Am Freitag, 15. Mai 2020 09:02:59 UTC+2 schrieb Rick C:
    On Friday, May 15, 2020 at 2:00:27 AM UTC-4, Christoph Linden wrote:
    Am Freitag, 15. Mai 2020 00:46:01 UTC+2 schrieb Rick C:
    Thank you Rick, very helpful.

    1. Unfortunately I do not know anymore what the questions should have been. I believe it was in the ballpark how I can do this similar to a structural design but without defining single and gates.

    2. The o_sum part. The problem is, that for whatever reason google.groups interpreted part of the code as "quote". So if you click on the quote you see, that it is actually two entities. One entity is calculating the carry look ahead and the other
    is doing the actual add of the four bits.

    That is why it looks so weird if you do not unfold the quote.

    But anyhow I understood what you was saying and yes, I just used the process, because I did not understood that I do not need to use process all the time.

    I will give it a try.

    Is the following understanding correct:

    Process for sequential (a must to react on the clock and the edge of the signal)

    no process for combinatory circuits (such as ALU designs)

    It is obvious you are just getting started, so I understand. I had no one to ask when I learned to use VHDL. I took a week course and the instructor sucked so badly he answered questions wrong. It's one thing not to know, but giving out bad info
    is terrible.

    I won't say you should not use a process for combinational circuits. A process is of no value for simple assignments to signals. Processes also have variables which are updated immediately, unlike signals which are not updated until the process
    ends and the simulation proceeds to the next time step which is a delta time step. That's a bit complicated and I'm happy to explain it if you want. Most people consider that signals are updated at the end of the process which is essentially correct.

    Concurrent code does not use variables. Every concurrent assignment is actually a process. It runs whenever any of the inputs change state, just like a process. Essentially all concurrent code produces logic that runs in parallel. Even the
    process statement is concurrent code creating a process that runs in parallel with other processes including the concurrent logic. Hence the name concurrent.

    Variables can used in sequential code such as processes, functions and procedures. They allow code to be written in a similar manner to code written for CPUs which are executed sequentially. For example you can write

    a := b + c;
    a := a + d;

    This would add b, c and d and assign it to a in the order shown. If a were a signal, the last assignment in the process would be the only one taking effect. Notice a different assignment operator is used for signals <= and variables :=

    Often beginners confuse processes with subroutines like sequential programming languages use. You don't seem to have that confusion.

    So there are many ways to do the job. It also makes a difference if you are working with VHDL 2008 or an older version. There are many improvements in 2008 that makes coding easier. Often you must enable VHDL 2008 in your tool even if it is
    capable.

    I hope this helps.

    --

    Rick C.

    -- Get 1,000 miles of free Supercharging
    -- Tesla referral code - https://ts.la/richard11209

    Thank you so much Rick, that really helps and is highly appreciated.

    I was aware of the parallelity of execution, but actually the process is only update one time... So you are right, what I would need to do would be putting each line in a process, which is pretty much pointless.

    I came from nand2tetris, which has a much more simplified HDL to get the principles of chip design transported/tought. I now wanted to get into a real HDL to implement this chip (a very simple 16bit processor) into an FPGA.

    So i learned some of the tutorials from https://vhdlwhiz.com/, which helped alot - for instance all the basic gates and muxers and stuff I could implement easily. But at that point I struggled because of simply not really understanding what a process
    does and why something within a process is not the same as a simple concurrent logic without any process.

    You helped me on that alot and it is now much clearer. I am pretty sure I will stumble accross it again in the future, as things are getting more complicated, but for now.

    THANKS A MILLION, really appreciated.

    No problem. I didn't realize you were working on an actual design. I thought this was a learning exercise.

    If you are targeting FPGAs, there is no point in trying to implement a carry lookahead, at least not for 16 bits. Every FPGA I know of uses a fast carry chain optimized in the silicon which runs much faster than any sort of speedup implemented in the
    LUTs in the FPGA fabric. They use a similar sort of carry speedup involving a transmission gate which is faster than a logic gate. So each stage has a logic delay which all bits execute in parallel and the ripple carry which is a small fraction of a ns
    per bit.

    So unless you are doing the carry lookahead as an exercise, just typing the addition of your signals is all you need to do. Oh, and using ieee.numeric_std. That will let you use signed or unsigned data types for your adder. Or you can use integer
    types with the range restricted to 16 bits. That could be lesson 2 if you are interested.

    --

    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)
  • From Nicolas Matringe@21:1/5 to Christoph Linden on Sun May 17 13:43:56 2020
    On 2020-05-15 13:06, Christoph Linden wrote:

    I was aware of the parallelity of execution, but actually the process is only update one time... So you are right, what I would need to do would be putting each line in a process, which is pretty much pointless.

    You don't have to put each line in a process, just write concurrent
    assignments (which are, actually, implicit processes without all the fuss)

    Writing

    a <= b and c;

    outside of a process is strictly equivalent to

    process (b, c)
    begin
    a <= b and c;
    end process;

    You can therefore write

    a <= b and c;
    d <= a or e;

    and it will give you exactly d <= (b and c) or e;
    as long as it's NOT in a process.

    Nicolas

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christoph Linden@21:1/5 to All on Mon May 18 09:48:20 2020
    Am Sonntag, 17. Mai 2020 13:43:58 UTC+2 schrieb Nicolas Matringe:
    On 2020-05-15 13:06, Christoph Linden wrote:

    I was aware of the parallelity of execution, but actually the process is only update one time... So you are right, what I would need to do would be putting each line in a process, which is pretty much pointless.

    You don't have to put each line in a process, just write concurrent assignments (which are, actually, implicit processes without all the fuss)

    Writing

    a <= b and c;

    outside of a process is strictly equivalent to

    process (b, c)
    begin
    a <= b and c;
    end process;

    You can therefore write

    a <= b and c;
    d <= a or e;

    and it will give you exactly d <= (b and c) or e;
    as long as it's NOT in a process.

    Nicolas

    Thanks for the explanation ... it comes together step by step. and that is why I am doing this as a learning experience based on an already existing design I did within the nand2tetris course with a very simplified HDL.

    Actually the HDL has only structural design and also comes with nothing like processes... My journey goes on now with mixed design and then getting into a full behavioural implementation. As Rick mentioned ... obviously I could simply use sum=a+b; and
    would be fine. But that was to easy :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rick C@21:1/5 to Christoph Linden on Mon May 18 15:22:52 2020
    On Monday, May 18, 2020 at 12:48:24 PM UTC-4, Christoph Linden wrote:
    Am Sonntag, 17. Mai 2020 13:43:58 UTC+2 schrieb Nicolas Matringe:
    On 2020-05-15 13:06, Christoph Linden wrote:

    I was aware of the parallelity of execution, but actually the process is only update one time... So you are right, what I would need to do would be putting each line in a process, which is pretty much pointless.

    You don't have to put each line in a process, just write concurrent assignments (which are, actually, implicit processes without all the fuss)

    Writing

    a <= b and c;

    outside of a process is strictly equivalent to

    process (b, c)
    begin
    a <= b and c;
    end process;

    You can therefore write

    a <= b and c;
    d <= a or e;

    and it will give you exactly d <= (b and c) or e;
    as long as it's NOT in a process.

    Nicolas

    Thanks for the explanation ... it comes together step by step. and that is why I am doing this as a learning experience based on an already existing design I did within the nand2tetris course with a very simplified HDL.

    Actually the HDL has only structural design and also comes with nothing like processes... My journey goes on now with mixed design and then getting into a full behavioural implementation. As Rick mentioned ... obviously I could simply use sum=a+b; and
    would be fine. But that was to easy :-)

    You might get more applicable experience trying to program something with a state machine. That can let you see the advantages and disadvantages of processes, procedures, functions and just plain old concurrent logic and forget about coding structurally.
    .. I mean as a low level technique stringing gates together.

    One that is often taught in school is an elevator. You can start with one that goes between two floors. There is one in a building I frequent and oddly enough it has two buttons, 1 and 2 rather than the one button required since you don't really have a
    choice where to go. You just need an "other floor" button.

    Maybe I'll go into the elevator business and specialize in simplified elevator controls. One button takes you to a random floor. You keep pushing it until you get where you want to go.

    --

    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)