如何在VHDL的端口声明中使用从泛型参数计算的常量?

Mil*_*šić 5 vhdl

一个例子是一个通用的寄存器文件,我试图像这样实现:

entity register_file is
generic(reg_width: integer := 32; reg_num: integer := 16);
constant sel_num: integer := integer(CEIL(LOG(Real(reg_num))));
port (
    data_in: in std_logic_vector(reg_width - 1 downto 0);
    data_out: out std_logic_vector(reg_width - 1 downto 0);
    rd_sel: in std_logic_vector(sel_num - 1 downto 0);
    wr_sel: in std_logic_vector(sel_num - 1 downto 0);
    rd_enable: in std_logic;
    wr_enable: in std_logic;
    clock: in std_logic;
);
end register_file;
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为它似乎是通用的,端口必须是前两个声明,其次是其他声明.如果我在端口声明后移动type和constant,则在处理端口声明时它们不可见.

我是VHDL的新手,我认为这应该是一个常见的问题,但我找不到解决方案.显然,我想避免使用复制粘贴解决方案.

Bri*_*ond 5

如果没有其他用途reg_num,只需制作sel_num通用.

否则,写一个函数调用sel转换reg_num为另一个自然.问题是,在哪里放置功能?

在我的设计中,我倾向于在一个名为的包中放入许多常见的数据类型,声明,函数和时钟周期(*)common.

package common is
   function sel(n : natural) return natural;
   constant clock_period : time := 1 sec / 32000000;

   constant num_regs : natural := 16;
   subtype sel_word is std_logic_vector(sel(num_regs) downto 0);
end common;  -- package body contains the function body
Run Code Online (Sandbox Code Playgroud)

然后我的实体看起来像

use Work.common.all;

entity register_file is
generic(reg_width: integer := 32; reg_num: integer := 16);
port (
    rd_sel: in std_logic_vector(sel(reg_num) downto 0);  -- OK
    wr_sel: in sel_word;                                 -- better?
...
Run Code Online (Sandbox Code Playgroud)

如果设计的不同部分需要不同的"regnum"值,那么通用方法将是首选.

否则,将这些详细信息放在"common"中可以让您使用单个文件对整个设计进行参数化,并且不存在某些泛型的硬编码(可能是错误)值的风险.

(*)时钟频率为何?从一个参数扩展所有时序延迟,波特率参数,存储器等待状态等是非常有用的,知道当我改变时钟时它们都将保持正确...