使用同一实体处理不同类型的数据 - 新的 VHDL 2008 功能是否可用于此?

问题描述 投票:0回答:1

我多次创建了可以处理不同类型数据的 VHDL 块。 一个例子是堆流数据排序器 - https://opencores.org/projects/heap_sorter,另一个例子是用于高速数据采集的数据集中器 - https://arxiv.org/abs/2309.13690

为了能够在同一设计中重用这些块来处理不同类型的数据,我通常将数据类型定义放在单独的包中,然后为特定数据类型创建单独的库,每个库都有自己的该包版本。

我的集中器的该方法的演示可作为 GHDL 模拟在 https://gitlab.com/WZabISE/xconcentrator/-/tree/8d094449b79a9318708dd34e59b7455bf097dcb5/sim_complex_type 中获得。

当然,这种方法在工作时远不方便。将类型传递给实体会更好,理论上这在 VHDL 2008 中应该是可能的。作为 MWE,我们可以使用多路复用器块。

文件 mux.vhd

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

library work;

entity mux is
  generic (
    type DATA_T;
    NOF_INPUTS : integer);
  port(
    data_i : in  array(NOF_INPUTS-1 downto 0) of DATA_T;
    sel : in integer range 0 to NOF_INPUTS-1;
    data_o : out DATA_T;
    clk : in std_logic
    );

end entity mux;

architecture rtl of mux is

begin  -- architecture rtl

  psel: process (clk) is
  begin  -- process psel
    if clk'event and clk = '1' then 
      data_o <= data_i(sel);
    end if;
  end process psel;
  
end architecture rtl;

测试平台 mux_tb.vhd:

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

entity mux_tb is

end entity mux_tb;

architecture sim of mux_tb is

  -- First mux
  constant NOF_INPUTS1 : integer := 4;
  subtype DATA1_T is integer;
  type DATA1_INS_T is array (NOF_INPUTS1-1 downto 0) of DATA1_T;
  signal din1 : DATA1_INS_T := (10,-132,45,76);  
  signal dout1 : DATA1_T;
  signal sel1    : integer range 0 to NOF_INPUTS1-1;

  -- Second mux
  constant NOF_INPUTS2 : integer := 3;
  subtype DATA2_T is unsigned(4 downto 0);
  type DATA2_INS_T is array (NOF_INPUTS2-1 downto 0) of DATA2_T;
  signal din2 : DATA2_INS_T := (x"1",x"7",x"9");  
  signal dout2 : DATA2_T;
  signal sel2    : integer range 0 to NOF_INPUTS2-1;
  -- clock
  signal clk : std_logic := '1';

begin  -- architecture sim

  -- component instantiation
  DUT1: entity work.mux
    generic map (
      DATA_T => DATA1_T,
      NOF_INPUTS => NOF_INPUTS1)
    port map (
      data_i => din1,
      sel    => sel1,
      data_o => dout1,
      clk    => clk);

  -- component instantiation
  DUT2: entity work.mux
    generic map (
      DATA_T => DATA2_T,
      NOF_INPUTS => NOF_INPUTS2)
    port map (
      data_i => din2,
      sel    => sel2,
      data_o => dout2,
      clk    => clk);

  -- clock generation
  clk <= not clk after 10 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
    -- insert signal assignments here
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 1;
    sel2 <= 1;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 2;
    sel2 <= 2;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 3;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 1;
    wait;
  end process WaveGen_Proc;

end architecture sim;

GHDL 的 makefile:

STD=synopsys
VSTD=08
ENTITY=mux_tb
RUN_OPTIONS= --stop-time=200ns --wave=${ENTITY}.ghw 
SOURCES = \
  mux.vhd \
  mux_tb.vhd \

OBJECTS=$(SOURCES:.vhd=.o)

all: $(OBJECTS)

%.o : %.vhd
    ghdl -a -g -C  --std=${VSTD} --ieee=${STD} $<

all: ${ENTITY}.ghw test
show:   ${ENTITY} ${ENTITY}.ghw
    gtkwave ${ENTITY}.ghw ${ENTITY}.sav
${ENTITY}: $(SOURCES:.vhd=.o)
    ghdl -e -g --mb-comments  --std=${VSTD} -fexplicit --ieee=${STD} ${ENTITY}
${ENTITY}.ghw: ${ENTITY}
    ./${ENTITY} ${RUN_OPTIONS} 
clean:
    rm -f *.o *.vcd *.ghw *.cf ${ENTITY} 

不幸的是,这种方法不起作用,因为我无法使用数组作为端口。 产生以下错误:

mux.vhd:12:18:error: type mark expected in a subtype indication
    data_i : in  array(NOF_INPUTS-1 downto 0) of DATA_T;
                 ^
mux.vhd:12:18:error: ';' or ')' expected after interface
    data_i : in  array(NOF_INPUTS-1 downto 0) of DATA_T;

首先必须声明输入数据的类型。 所以也许一个解决方案是将该类型作为另一个泛型传递:

文件 mux.vhd:

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

library work;

entity mux is
  generic (
    type DATA_T;
    type DATA_INS_T;    
    NOF_INPUTS : integer);
  port(
    data_i : DATA_INS_T;
    sel : in integer range 0 to NOF_INPUTS-1;
    data_o : out DATA_T;
    clk : in std_logic
    );

end entity mux;

architecture rtl of mux is

begin  -- architecture rtl

  psel: process (clk) is
  begin  -- process psel
    if clk'event and clk = '1' then 
      data_o <= data_i(sel);
    end if;
  end process psel;
  
end architecture rtl;

测试平台 mux_tb.vhd

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

entity mux_tb is

end entity mux_tb;

architecture sim of mux_tb is

  -- First mux
  constant NOF_INPUTS1 : integer := 4;
  subtype DATA1_T is integer;
  type DATA1_INS_T is array (NOF_INPUTS1-1 downto 0) of DATA1_T;
  signal din1 : DATA1_INS_T := (10,-132,45,76);  
  signal dout1 : DATA1_T;
  signal sel1    : integer range 0 to NOF_INPUTS1-1;

  -- Second mux
  constant NOF_INPUTS2 : integer := 3;
  subtype DATA2_T is unsigned(4 downto 0);
  type DATA2_INS_T is array (NOF_INPUTS2-1 downto 0) of DATA2_T;
  signal din2 : DATA2_INS_T := (x"1",x"7",x"9");  
  signal dout2 : DATA2_T;
  signal sel2    : integer range 0 to NOF_INPUTS2-1;
  -- clock
  signal clk : std_logic := '1';

begin  -- architecture sim

  -- component instantiation
  DUT1: entity work.mux
    generic map (
      DATA_T => DATA1_T,
      DATA_INS_T => DATA1_INS_T,
      NOF_INPUTS => NOF_INPUTS1)
    port map (
      data_i => din1,
      sel    => sel1,
      data_o => dout1,
      clk    => clk);

  -- component instantiation
  DUT2: entity work.mux
    generic map (
      DATA_T => DATA2_T,
      DATA_INS_T => DATA2_INS_T,
      NOF_INPUTS => NOF_INPUTS2)
    port map (
      data_i => din2,
      sel    => sel2,
      data_o => dout2,
      clk    => clk);

  -- clock generation
  clk <= not clk after 10 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
    -- insert signal assignments here
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 1;
    sel2 <= 1;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 2;
    sel2 <= 2;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 3;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 1;
    wait;
  end process WaveGen_Proc;

end architecture sim;

不幸的是,这并不奏效。 DATA_INS_T 类型被视为非数组。

mux.vhd:28:23:error: type of prefix is not an array
      data_o <= data_i(sel);

VHDL 2008 中提供的另一个可能的解决方案是使用通用包。 所以我定义了通用包 mux_pkg.vhd:

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

package mux_pkg is
  generic (
    type DATA_T;
    constant NOF_INPUTS : in integer
    );
  type DATA_INS_T is array (NOF_INPUTS-1 downto 0) of DATA_T;
  
end package;

我相应地修改了 mux.vhd:

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

library work;
--use work.mux_pkg.all;

entity mux is
  generic (
    type DATA_T;
    NOF_INPUTS : integer;
    package my_pkg is new work.mux_pkg generic map (DATA_T => DATA_T, NOF_INPUTS => NOF_INPUTS)
    );
  port(
    data_i : in my_pkg.DATA_INS_T;
    sel : in integer range 0 to NOF_INPUTS-1;
    data_o : out DATA_T;
    clk : in std_logic
    );

end entity mux;

architecture rtl of mux is

begin  -- architecture rtl

  psel: process (clk) is
  begin  -- process psel
    if clk'event and clk = '1' then 
      data_o <= data_i(sel);
    end if;
  end process psel;
  
end architecture rtl;

测试平台 mux_tb.vhd 也进行了修改:

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

entity mux_tb is

end entity mux_tb;

architecture sim of mux_tb is

  -- First mux
  constant NOF_INPUTS1 : integer := 4;
  subtype DATA1_T is integer;
  type DATA1_INS_T is array (NOF_INPUTS1-1 downto 0) of DATA1_T;
  signal din1 : DATA1_INS_T := (10,-132,45,76);  
  signal dout1 : DATA1_T;
  signal sel1    : integer range 0 to NOF_INPUTS1-1;

  -- Second mux
  constant NOF_INPUTS2 : integer := 3;
  subtype DATA2_T is unsigned(3 downto 0);
  type DATA2_INS_T is array (NOF_INPUTS2-1 downto 0) of DATA2_T;
  signal din2 : DATA2_INS_T := (x"1",x"7",x"9");  
  signal dout2 : DATA2_T;
  signal sel2    : integer range 0 to NOF_INPUTS2-1;
  -- clock
  signal clk : std_logic := '1';

begin  -- architecture sim

  -- component instantiation
  DUT1: entity work.mux
    generic map (
      DATA_T => DATA1_T,
      NOF_INPUTS => NOF_INPUTS1)
    port map (
      data_i => din1,
      sel    => sel1,
      data_o => dout1,
      clk    => clk);

  -- component instantiation
  DUT2: entity work.mux
    generic map (
      DATA_T => DATA2_T,
      NOF_INPUTS => NOF_INPUTS2)
    port map (
      data_i => din2,
      sel    => sel2,
      data_o => dout2,
      clk    => clk);

  -- clock generation
  clk <= not clk after 10 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
    -- insert signal assignments here
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 1;
    sel2 <= 1;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 2;
    sel2 <= 2;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 3;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 1;
    wait;
  end process WaveGen_Proc;

end architecture sim;

makefile 还需要一些小改动:

STD=synopsys
VSTD=08
ENTITY=mux_tb
RUN_OPTIONS= --stop-time=200ns --wave=${ENTITY}.ghw 
SOURCES = \
  mux_pkg.vhd \
  mux.vhd \
  mux_tb.vhd \

OBJECTS=$(SOURCES:.vhd=.o)

all: $(OBJECTS)

%.o : %.vhd
    ghdl -a -g -C  --std=${VSTD} --ieee=${STD} $<

all: ${ENTITY}.ghw test
show:   ${ENTITY} ${ENTITY}.ghw
    gtkwave ${ENTITY}.ghw ${ENTITY}.sav
${ENTITY}: $(SOURCES:.vhd=.o)
    ghdl -e -g --mb-comments  --std=${VSTD} -fexplicit --ieee=${STD} ${ENTITY}
${ENTITY}.ghw: ${ENTITY}
    ./${ENTITY} ${RUN_OPTIONS} 
clean:
    rm -f *.o *.vcd *.ghw *.cf ${ENTITY} 

不幸的是,这种尝试也导致了错误:

mux_tb.vhd:37:17:error: can't associate 'din1' with port "data_i"
      data_i => din1,
                ^
mux_tb.vhd:37:17:error: (type of 'din1' is data1_ins_t)
mux.vhd:15:5:error: (type of port "data_i" is data_ins_t)
mux_tb.vhd:48:17:error: can't associate 'din2' with port "data_i"
      data_i => din2,
                ^
mux_tb.vhd:48:17:error: (type of 'din2' is data2_ins_t)
mux.vhd:15:5:error: (type of port "data_i" is data_ins_t)
ghdl:error: compilation error

所以,我的问题是。 VHDL 2008 中提供的新功能是否有助于解决重复使用同一块来处理不同类型数据的问题?

types vhdl fpga reusability
1个回答
0
投票

正如我在帖子中提到的,我有一个基于使用单独的库(每种类型的处理数据一个)的解决方案。但是,它不需要 VHDL 2008。在该解决方案中,我将类型的定义放入单独的包中。

文件 data1_pkg.vhd:

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

package data1_pkg is
  constant NOF_INPUTS1 : integer := 4;
  subtype DATA1_T is integer;
  type DATA1_INS_T is array (NOF_INPUTS1-1 downto 0) of DATA1_T;
end package;

文件 data2_pkg.vhd:

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

package data2_pkg is
  constant NOF_INPUTS2 : integer := 3;
  subtype DATA2_T is unsigned(3 downto 0);
  type DATA2_INS_T is array (NOF_INPUTS2-1 downto 0) of DATA2_T;
end package;

此外,我还为使用上述定义的多路复用器实体准备了包:

文件 my_pkg1.vhd

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

package my_pkg is 
    subtype DATA_T is DATA1_T;
    subtype DATA_INS_T is DATA1_INS_T;
    constant NOF_INPUTS : integer := NOF_INPUTS1;
end package;

并文件 my_pkg2.vhd:

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

package my_pkg is 
    subtype DATA_T is DATA2_T;
    subtype DATA_INS_T is DATA2_INS_T;
    constant NOF_INPUTS : integer := NOF_INPUTS2;
end package;

它们都提供包 my_pkg,但它们将被编译成不同的库。

mux.vhd 文件现在很简单:

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

library work;
use work.my_pkg.all;

entity mux is
  port(
    data_i : in DATA_INS_T;
    sel : in integer range 0 to NOF_INPUTS-1;
    data_o : out DATA_T;
    clk : in std_logic
    );

end entity mux;

architecture rtl of mux is

begin  -- architecture rtl

  psel: process (clk) is
  begin  -- process psel
    if clk'event and clk = '1' then 
      data_o <= data_i(sel);
    end if;
  end process psel;
  
end architecture rtl;

测试平台 mux_tb.vhd 根据处理数据的类型使用在单独库中定义的多路复用器:

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

library lib1;
use lib1.data1_pkg.all;

library lib2;
use lib2.data2_pkg.all;

entity mux_tb is

end entity mux_tb;

architecture sim of mux_tb is

  -- First mux
  signal din1 : DATA1_INS_T := (10,-132,45,76);  
  signal dout1 : DATA1_T;
  signal sel1    : integer range 0 to NOF_INPUTS1-1;

  -- Second mux
  signal din2 : DATA2_INS_T := (x"1",x"7",x"9");  
  signal dout2 : DATA2_T;
  signal sel2    : integer range 0 to NOF_INPUTS2-1;
  -- clock
  signal clk : std_logic := '1';

begin  -- architecture sim

  -- component instantiation
  DUT1: entity lib1.mux
    port map (
      data_i => din1,
      sel    => sel1,
      data_o => dout1,
      clk    => clk);

  -- component instantiation
  DUT2: entity lib2.mux
    port map (
      data_i => din2,
      sel    => sel2,
      data_o => dout2,
      clk    => clk);

  -- clock generation
  clk <= not clk after 10 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
    -- insert signal assignments here
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 1;
    sel2 <= 1;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 2;
    sel2 <= 2;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 3;
    sel2 <= 0;
    wait until clk = '0';
    wait until clk = '1';
    sel1 <= 0;
    sel2 <= 1;
    wait;
  end process WaveGen_Proc;

end architecture sim;

编译和模拟现在通过 shell 脚本 build.sh 运行:

#!/bin/bash

# Do cleanup
rm -rf *.o *.cf lib1 lib2
mkdir lib1
mkdir lib2

STD=synopsys
VSTD=02
ENTITY=mux_tb
RUN_OPTIONS="--stop-time=200ns --wave=${ENTITY}.ghw"

LIB1_SRC="\
  data1_pkg.vhd \
  my_pkg1.vhd \
  mux.vhd \
  "

LIB2_SRC="\
  data2_pkg.vhd \
  my_pkg2.vhd \
  mux.vhd \
"

SOURCES=" \
  mux_tb.vhd \
"

for f in ${LIB1_SRC}; do 
   ghdl -a -g -C  --work=lib1 --workdir=lib1 --std=${VSTD} --ieee=${STD} $f
done
echo Done lib1

for f in ${LIB2_SRC}; do
   ghdl -a -g -C  --work=lib2 --workdir=lib2 --std=${VSTD} --ieee=${STD} $f
done
echo done lib2

for f in ${SOURCES}; do
   ghdl -a -P./lib1/ -P./lib2/ --std=${VSTD} -g -C --ieee=${STD} $f
done
echo Analyzed

ghdl -e  -g -P./lib1/ -P./lib2/ --mb-comments  --std=${VSTD} -fexplicit --ieee=${STD} ${ENTITY} 

./${ENTITY} ${RUN_OPTIONS} 

这个方法非常有效。但是它不使用新的 VHDL 2008 功能...

© www.soinside.com 2019 - 2024. All rights reserved.