How to use a constant computed from a common parameter in a port declaration in VHDL?

An example would be a generic register file, which I am trying to implement as follows:

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;

This does not work because it seems that the generic and the port should be the first two announcements, followed by the others. If I move the type and constant after the port declaration, they are not visible when processing the port declaration.

I am new to VHDL and I think this should be a common problem, but I cannot find a solution. Obviously, I would like to avoid the copy-paste solution.

+4
source share
4 answers

If reg_numthere is no other use , just make it sel_numgeneric.

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

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?
...

"regnum", .

"" (, , ) .

(*) ? , , .. , , ...

+4

, , . , , . :

entity register_file is
    generic(
        reg_width: integer := 32;
        reg_num: integer := 16;
        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
    );

begin
    assert sel_num = integer(CEIL(LOG(Real(reg_num))));
end;

, , , , .

+2

, , , , addr_len . 2 ** addr_len, .

, , , , , ceil(log2(entries)), :

package common is
  function ceil_log2(i : natural) return natural;
end package;

library ieee;
use ieee.math_real.all;
package body common is
  function ceil_log2(i : natural) return natural is
  begin
    return integer(ceil(log2(real(i))));  -- Example using real calculation
  end function;
end package body;

reg_num = 2 ** len, , ceil_log2, :

library ieee;
use ieee.std_logic_1164.all;

library work;
use work.common.all;

entity register_file is
  generic(
    reg_width : integer := 32;
    reg_num   : integer := 16);
  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(ceil_log2(reg_num) - 1 downto 0);
    wr_sel    : in  std_logic_vector(ceil_log2(reg_num) - 1 downto 0);
    rd_enable : in  std_logic;
    wr_enable : in  std_logic;
    clock     : in  std_logic);
end register_file;

register_file rd_sel/wr_sel, , , , , ceil_log2, , . , , reg_num sel_num:

entity register_file is
  generic(
    ...
    reg_num   : integer := 16;
    sel_num   : integer :=  4);
  port (
    ...
    rd_sel    : in  std_logic_vector(sel_num - 1 downto 0);
    wr_sel    : in  std_logic_vector(sel_num - 1 downto 0);
    ...
...
architecture syn of register_file is
  ...
begin
  ...
  assert 2 ** sel_num >= reg_num report "sel_num to small to address all registers given by reg_num";
end architecture;

.

+1

( , , )

... :

entity register_file is
port (
    data_in: in std_logic_vector;
    data_out: out std_logic_vector;
    rd_sel: in unsigned;
    wr_sel: in unsigned;
    rd_enable: in std_logic;
    wr_enable: in std_logic;
    clock: in std_logic;
);
end register_file;

, , , , .

data_in'range , . , 2 ** rd_sel'length.

, , , data_in'length = data_out'length wr_sel'length = rd_sel'length


(Note: I made selports unsigned, since you can no doubt use them as an index (i.e. a number), and this will save some conversions. You can also make them integer, and then the width of the register file will be determined by the range of the integer, transferred to)

+1
source

All Articles