Electronic – Using VHDL integer_vector for a block ram type, how to restrict the integer range

genericramvhdl

Trying to simply infer block rams in a design with varying depths and widths. I'd like to have one ram definition since it is going to use a vendor specific attribute and it seems like a good idea to keep it confined to one module.

Using integer_vector for the array type it is simple enough to set the range of the array index. Setting the range of the integers in the array is not so clear. Is it possible to set the integer range in the signal declaration rather than a type declaration?

I need both the depth and width of the memory to be set by generics where it is instantiated. Will I need to use a vector type instead of the integer type to be able to do this?

Best Answer

Here is the final code, well final as of this moment.

-- VHDL created by Arius, Inc  copyright 2020
--------------------------------------------------------------------------------
-- Company: Arius, Inc
-- Engineer: Rick Collins
--
-- Create Date:   2020/10/25 03:23z
-- Design Name:   Alarm
-- Module Name:   Blk_mem
-- Project Name:  OVB_Alarm
--
-- Revision:
-- Revision 0.01 - File Created
--
-- Additional Comments:
--
-- Notes:  -  SYNTHESIZABLE CODE ONLY
-- Blk_mem - Memory block, variable data width and depth
--
-- Notes:  -  NOT ASSURED TO BE SYNTHESIZABLE CODE
-- VHDL_test_mem - Write and read memory to verify functionality
--
--------------------------------------------------------------------------------
-- Test synthesis of memory, semi-dual port
library ieee;
use ieee.NUMERIC_STD.all;
use ieee.std_logic_1164.all;
-- use work.Common.all;
use work.all;

entity Blk_mem is
  generic(
    AddrWidth : positive := 11;
    DataWidth : positive := 9
    );
  port(
    Clk     : in    std_logic := '1';
    Wr_Data : in    unsigned(DataWidth-1 downto 0);
    Wr_Addr : in    unsigned(AddrWidth-1 downto 0);
    Wr_CE   : in    std_logic;
    Rd_Data : out   unsigned(DataWidth-1 downto 0);
    Rd_Addr : in    unsigned(AddrWidth-1 downto 0);
    Rd_CE   : in    std_logic
  );
end Blk_mem;

architecture behav of Blk_mem is
  -- type BRAM_t is array (integer range <>) of
  --                                    natural range 0 to 2**DataWidth-1;
  signal BRAM_mem : integer_vector (0 to 2**AddrWidth-1);
  -- attribute syn_ramstyle:string;
  -- attribute syn_ramstyle of BRAM_mem : signal is "block_ram";
begin

  BRAM_proc: process (Clk) is
    variable Addr_M_Wr, Addr_M_Rd : natural range 0 to 2**AddrWidth-1;
    variable Rd_Mem : natural range 0 to 2**DataWidth-1;
  begin
    if (rising_edge(Clk)) then
      if (Wr_CE) then
        Addr_M_Wr := to_integer(Wr_Addr); -- capture write address
        BRAM_mem (Addr_M_Wr) <= to_integer(Wr_Data);
      end if;
      if (Rd_CE) then
        Rd_Mem := BRAM_mem(to_integer(Rd_Addr)) mod 2**DataWidth;
        Rd_Data <= to_unsigned(Rd_Mem, Rd_Data'length);
      end if;
    end if;
  end process BRAM_proc;

END behav;  -- Blk_mem


-- synthesis translate_off
library ieee;
use ieee.NUMERIC_STD.all;
use ieee.std_logic_1164.all;
--use work.Common.all;
use work.all;

entity VHDL_test_mem is
  generic(
    CLK_HZ : REAL := 33.554432E6;
    AddrWidth : positive := 11;
    DataWidth : positive := 9
    );
--   port(
--   );
end VHDL_test_mem;

architecture TB_ARCH of VHDL_test_mem is
  constant Clock_Half_Period : time := 500 ms / CLK_HZ;  -- 14901 ps; --
  signal Clk        : std_logic := '1';
  signal Wr_Data    : unsigned(DataWidth-1 downto 0) := (others => '1');
  signal Wr_Addr    : unsigned(AddrWidth-1 downto 0) := (others => '0');
  signal Wr_CE      : std_logic := '1';
  signal Rd_Data    : unsigned(DataWidth-1 downto 0) := (others => '0');
  signal Rd_Addr    : unsigned(AddrWidth-1 downto 0) := (others => '1');
  signal Rd_CE      : std_logic := '1';
  signal Wr_Data_d  : unsigned(DataWidth-1 downto 0) := (others => '1');
  signal Wr_Data_dd : unsigned(DataWidth-1 downto 0);
begin
  Clk_gen: Clk <= not Clk after Clock_Half_Period;

  stimulus: process (Clk)
  begin
    if (rising_edge(Clk)) then
      Wr_Addr <= Wr_Addr + 1;
      Rd_Addr <= Wr_Addr;
      Wr_Data <= RESIZE(not (Wr_Addr + 1), Wr_Data'length);
      Wr_Data_d <= Wr_Data;
      Wr_Data_dd <= Wr_Data_d;
      assert Rd_Data = Wr_Data_dd
        report "Error in memory verification, Wr_Data = " &
                to_hstring(Wr_Data_dd) & ", Rd_Data = " & to_hstring(Rd_Data)
        severity warning;
    end if;
  end process;

  -- ^[ \t]+([_a-zA-Z0-9\-]+[ \t]+:) [a-zA-Z]+[ \t]+(.+;?$)
  --   signal \1 \2
  -- ^([ \t]+)([_a-zA-Z0-9]+)([ \t]+=>[ \t])[^;]*(;?)$

  Mem_Test: entity Blk_mem
    generic map (
      AddrWidth => AddrWidth,
      DataWidth => DataWidth
      )
    port map (
      Clk       => Clk,
      Wr_Data   => Wr_Data,
      Wr_Addr   => Wr_Addr,
      Wr_CE     => Wr_CE,
      Rd_Data   => Rd_Data,
      Rd_Addr   => Rd_Addr,
      Rd_CE     => Rd_CE
      ); -- Blk_mem
END TB_ARCH;  -- VHDL_test_mem
-- synthesis translate_on
```