Search code examples
vhdlaggregates

Aggregate Ordering with Named Association


I'm struggling to understand the bit order of an aggregate, especially since I've used name association.

The buses are defined as (0 to 3) and (3 downto 0), but since I've used named association, why are the outputs z3..0 and ob3..0 the reverse of each other? Why is outputs_b the reverse of z_bus? Why did assigning outputs_b from the constant array make a difference to the bit ordering as compared to assigning z_bus from a literal?

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Test_TB is
end entity;

architecture V1 of Test_TB is
    type TLogicLevel is (L, H, X);
    type TOutputs is array(natural range<>) of TLogicLevel;
    type TOutputsTable is array(natural range<>) of TOutputs;

    constant OUTPUTS_TABLE: TOutputsTable :=
    (
        (3 => H,  2 => H,  1 => H,  0 => L),
        (3 => X,  2 => X,  1 => X,  0 => X)  -- Added this because it can't compile an array with a single element.
    );

    signal outputs_a: TOutputs(0 to 3);
    signal outputs_b: TOutputs(3 downto 0);
    signal oa0, oa1, oa2, oa3: TLogicLevel;
    signal ob0, ob1, ob2, ob3: TLogicLevel;

    signal y_bus: TOutputs(0 to 3);
    signal z_bus: TOutputs(3 downto 0);
    signal y0, y1, y2, y3: TLogicLevel;
    signal z0, z1, z2, z3: TLogicLevel;

begin

    process
    begin
        wait for 10 ns;
        y_bus <= (3 => H, 2 => H, 1 => H, 0 => L);              -- Performs bit-for-bit copy.
        z_bus <= (3 => H, 2 => H, 1 => H, 0 => L);              -- Performs bit-for-bit copy. NOT REVERSED.
        outputs_a <= OUTPUTS_TABLE(0);                          -- Performs bit-for-bit copy.
        outputs_b <= OUTPUTS_TABLE(0);                          -- Performs bit-reverse copy. IS REVERSED.
        wait for 10 ns;
        (3 => oa3, 2 => oa2, 1 => oa1, 0 => oa0) <= outputs_a;  -- Performs bit-for-bit copy.
        (3 => ob3, 2 => ob2, 1 => ob1, 0 => ob0) <= outputs_b;  -- Performs bit-reverse copy of a reverse copy, i.e. reverse reverse.
        wait for 10 ns;
        (3 => y3, 2 => y2, 1 => y1, 0 => y0) <= y_bus;          -- Performs bit-for-bit copy.
        (3 => z3, 2 => z2, 1 => z1, 0 => z0) <= z_bus;          -- Performs bit-reverse copy of non-reverse copy. So z3..0 is the reverse of ob3..0.
        wait;
    end process;

end architecture;

enter image description here


Solution

  • Your code is behaving as I would expect.

    signal y_bus: TOutputs(0 to 3);
    signal z_bus: TOutputs(3 downto 0);
    ...
    y_bus <= (3 => H, 2 => H, 1 => H, 0 => L);  
    z_bus <= (3 => H, 2 => H, 1 => H, 0 => L); 
    

    For y_bus the left hand bit is 0, which you have set to L. For z_bus the left hand bit is 3, which you have set to H. CHECK.

    constant OUTPUTS_TABLE: TOutputsTable :=
    (
        (3 => H,  2 => H,  1 => H,  0 => L),
    ...
    signal outputs_a: TOutputs(0 to 3);
    signal outputs_b: TOutputs(3 downto 0);
    ....
    outputs_a <= OUTPUTS_TABLE(0);
    outputs_b <= OUTPUTS_TABLE(0); 
    

    For OUTPUTS_TABLE(0) the left hand bit is 0, which you have set to L. For outputs_a the left hand bit is 0, so you would expect that to be L. For outputs_b the left hand bit is 3, so you would expect that to be L. CHECK.

    signal outputs_a: TOutputs(0 to 3);
    signal outputs_b: TOutputs(3 downto 0);
    ...
    (3 => oa3, 2 => oa2, 1 => oa1, 0 => oa0) <= outputs_a;
    (3 => ob3, 2 => ob2, 1 => ob1, 0 => ob0) <= outputs_b;
    

    For outputs_a the left hand bit is 0, so you would expect oa0 to be L, because it is that that is one the left hand side. For outputs_b the left hand bit is 3, so you would expect ob0 to be L, because it is that that is one the left hand side. CHECK. But hang on, why are oa0 and ob0 the left hand side? Because that is how the bits in the aggregates (3 => oa3, 2 => oa2, 1 => oa1, 0 => oa0) and (3 => ob3, 2 => ob2, 1 => ob1, 0 => ob0) will be numbered, because the index type will be an integer and integer types count up.

    signal y_bus: TOutputs(0 to 3);
    signal z_bus: TOutputs(3 downto 0);
    ....
    y_bus <= (3 => H, 2 => H, 1 => H, 0 => L); 
    z_bus <= (3 => H, 2 => H, 1 => H, 0 => L); 
    ....
    (3 => y3, 2 => y2, 1 => y1, 0 => y0) <= y_bus;
    (3 => z3, 2 => z2, 1 => z1, 0 => z0) <= z_bus;
    

    So, as we already know, for y_bus the left hand bit is 0, which you have set to L and for z_bus the left hand bit is 3, which you have set to H. So, you would expect y0 (the left hand bit) to be L and z0 (the left hand bit) to be H. CHECK.

    My head hurts.