Skip to content

VHDL-2019 Elaboration: Can't lower type T_GENERIC #1017

@bpadalino

Description

@bpadalino

I saw this repository and thought it was silly to utilize rust to generate some VHDL. I also didn't like the data type or sizes being determined in such a hard-coded fashion, so I tried to write some VHDL-2019 compatible code to just create the general sorting matrix and ran into an issue with a lowering of a generic type.

I am sure a smaller test is possible, but I didn't try to reduce it.

package sorting_pkg is
    -- elements indices for comparison
    type elements is (l, r) ;

    -- the indices that need to be compared
    type tuple_t is array(elements) of integer ;
    constant IGNORE : tuple_t := tuple_t'(-1, -1) ;

    -- the array of comparisons that need to happen based on the number of stages and the number of elements
    -- an array entry with both indices the same natural index, pass-through
    -- an array entry with both indices -1, ignore
    type comparisons_t is array(natural range <>, natural range <>) of tuple_t ;

    -- get the comparisons
    function get_comparisons(constant num_elements : in positive) return comparisons_t ;

    -- invalid entries
    constant NULL_COMPARISONS : comparisons_t(0 to -1, 0 to -1) := (others => (others => IGNORE)) ;

end package ;

package body sorting_pkg is

    function init_comparisons(constant num_elements, num_stages : in positive) return comparisons_t is
        variable rv : comparisons_t(0 to num_stages-1, 0 to num_elements-1) := (others => (others => IGNORE));
    begin
        return rv ;
    end function ;

    -- TODO: Create a function to make these entries for all possible networks
    function comparisons_8 return comparisons_t is
        variable rv : comparisons_t := init_comparisons(num_elements => 8, num_stages => 6) ;
    begin
        rv(0,0) := (0,2); rv(0,1) := (1,3); rv(0,2) := (4,6); rv(0,3) := (5,7);                                     -- stage 0: 4 comparisons
        rv(1,0) := (0,4); rv(1,1) := (1,5); rv(1,2) := (2,6); rv(1,3) := (3,7);                                     -- stage 1: 4 comparisons
        rv(2,0) := (0,1); rv(2,1) := (2,3); rv(2,2) := (4,5); rv(2,3) := (6,7);                                     -- stage 2: 4 comparisons
        rv(3,0) := (2,4); rv(3,1) := (3,5); rv(3,2) := (0,0); rv(3,3) := (1,1); rv(3,4) := (6,6); rv(3,5) := (7,7); -- stage 3: 2 comparisons, 4 pass-through
        rv(4,0) := (1,4); rv(4,1) := (3,6); rv(4,2) := (0,0); rv(4,3) := (2,2); rv(4,4) := (5,5); rv(4,5) := (7,7); -- stage 4: 2 comparisons, 4 pass-through
        rv(5,0) := (1,2); rv(5,1) := (3,4); rv(5,2) := (5,6); rv(5,3) := (0,0); rv(5,4) := (7,7);                   -- stage 5: 3 comparisons, 2 pass-through
        return rv ;
    end function ;

    function get_comparisons(constant num_elements : in positive) return comparisons_t is
    begin
        case num_elements is
            when 8      => return comparisons_8 ;
            when others => return NULL_COMPARISONS ;
        end case ;
    end function ;

end package body ;

library ieee;
use ieee.std_logic_1164.all;

use work.sorting_pkg.all ;

entity sorting_network is
  generic (
    type a is array(natural range <>) of type is private;
    function "<"(l, r : in a'element) return boolean is <>;
    comparisons : comparisons_t
  );
  port(
    clock       : in    std_logic;
    unsorted    : in    a ;
    sorted      : out   a
  );
end entity;

architecture arch of sorting_network is

    constant NUM_ELEMENTS   : natural := a'length ;
    constant NUM_STAGES     : natural := comparisons'length(1) ;

    -- Riviera PRO doesn't like this
    --subtype STAGES is comparisons'range(1) ;
    --subtype ELEMENTS is a'range ;

    subtype STAGES is natural range 0 to comparisons'length(1)-1 ;
    subtype ELEMENTS is natural range 0 to a'length(1)-1 ;

    type data_array is array (natural range <>, natural range <>) of a'element ;
    signal data : data_array(STAGES, ELEMENTS) ;

begin

    -- Input assignments
    stage0 : for element in 0 to NUM_ELEMENTS-1 generate
        data(0, element) <= unsorted(element) ;
    end generate ;

    -- Sorting network
    gen_stages : for stage in 0 to NUM_STAGES-1 generate
        process(clock) begin
            if( rising_edge(clock) ) then
                for element in 0 to NUM_ELEMENTS-1 loop
                    if comparisons(stage,element)(l) = -1 then
                        -- Ignore the entry
                        null ;
                    elsif comparisons(stage, element)(l) = comparisons(stage, element)(r) then
                        -- Pass through
                        -- Note: Evaluation of this constant should not turn into logic
                        data(stage+1, element) <= data(stage, element) ;
                    else
                        -- Only logic generated here for this comparison
                        if data(stage, comparisons(stage, element)(l)) < data(stage, comparisons(stage, element)(r)) then
                            -- Swap
                            data(stage+1, comparisons(stage, element)(l)) <= data(stage, comparisons(stage, element)(r)) ;
                            data(stage+1, comparisons(stage, element)(r)) <= data(stage, comparisons(stage, element)(l)) ;
                        else
                            -- No Swap, pass-through
                            data(stage+1, comparisons(stage, element)(l)) <= data(stage, comparisons(stage, element)(l)) ;
                            data(stage+1, comparisons(stage, element)(r)) <= data(stage, comparisons(stage, element)(r)) ;
                        end if ;
                    end if ;
                end loop ;
            end if ;
        end process ;
    end generate ;

    -- Output assignments
    gen_output : for element in 0 to NUM_ELEMENTS-1 generate
        sorted(element) <= data(NUM_STAGES, element) ;
    end generate ;

end architecture ;

library ieee ;
use ieee.std_logic_1164.all ;
use work.sorting_pkg.all ;

entity sorting_tb is
end entity ;

architecture arch of sorting_tb is

    constant NUM_ELEMENTS : positive := 8 ;

    -- Get the sorting network based on the number of elements
    constant comparisons : comparisons_t := get_comparisons(num_elements => NUM_ELEMENTS) ;

    -- A couple of input data types
    type data_t is array(comparisons'range(2)) of natural ;
    type data2_t is array(comparisons'range(2)) of real ;

    -- Common clock
    signal clock    : std_ulogic ;

    -- Natural data type
    signal data     : data_t ;
    signal sorted   : data_t ;

    -- Real data type
    signal data2    : data2_t ;
    signal sorted2  : data2_t ;

begin

    -- Make sure we have a valid network
    assert comparisons'length(1) > 0 report "NULL sorting network" severity failure ;

    U_natural_network : entity work.sorting_network
      generic map (
        a           => data'subtype,
        comparisons => comparisons
      ) port map (
        clock       => clock,
        unsorted    => data,
        sorted      => sorted
      ) ;

    U_real_network : entity work.sorting_network
      generic map (
        a           => data2'subtype,
        comparisons => comparisons
      ) port map (
        clock       => clock,
        unsorted    => data2,
        sorted      => sorted2
      ) ;

end architecture ;
$ nvc --std=2019 -a sort_generic.vhdl -e sorting_tb
** Fatal: cannot lower type kind T_GENERIC
[0x560efbb440a6] ../src/diag.c:1052 diag_femit
[0x560efbb440a6] ../src/diag.c:1077 diag_emit
[0x560efba5a4d0] ../src/util.c:585 fatal_trace
[0x560efba668cc] ../src/lower.c:711 lower_type.lto_priv.0.cold
[0x560efbafee67] ../src/lower.c:774 lower_signal_type.lto_priv.0
[0x560efbafef63] ../src/lower.c:749 lower_signal_type.lto_priv.0
[0x560efbb189cc] ../src/lower.c:7897 lower_decls.lto_priv.0
[0x560efbad8c09] ../src/lower.c:13073 lower_instance
[0x560efbad8c09] ../src/lower.c:1419 elab_lower.lto_priv.0
[0x560efbadac21] ../src/elab.c:1536 elab_architecture.lto_priv.0
[0x560efbae217f] ../src/elab.c:1711 elab_stmts.lto_priv.0
[0x560efbadac37] ../src/elab.c:1538 elab_architecture.lto_priv.0
[0x560efbbbe674] ../src/elab.c:2313 elab.constprop.0
[0x560efba79222] ../src/nvc.c:481 elaborate
[0x560efba768be] ../src/nvc.c:2128 process_command
[0x560efba77b61] ../src/nvc.c:1259 dump_cmd
[0x560efba77b61] ../src/nvc.c:2134 process_command
[0x560efba72845] ../src/nvc.c:2288 main

nvc 1.14.0 (1.14.0.r33.gbb35ff9a) (Using LLVM 14.0.0) [x86_64-pc-linux-gnu]

Please report this bug at https://github.com/nickg/nvc/issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions