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?

  • \$\begingroup\$ Looking at "standard.vhdl" (2008 version) I see type integer_vector is array (natural range <>) of integer;. So I would suggest declaring your own subtype of integer and declare my_int_vector along the same lines, and see how far you get. All uses of integer_vector I've seen so far have been in verification, not synthesis, so you may hit corner cases, but there's no fundamental reason AFAIK why it shouldn't work. \$\endgroup\$ Oct 25 '20 at 13:17
  • \$\begingroup\$ Point is I don't want the integer range to be defined in the array type definition. Otherwise I will need a memory entity for every data width. If the output of the memory is assigned to a vector of fixed size, the unused RAM bits are optimized away, right? just realized that's what the code does! Simulation runs correctly although the values of the memory array are expressed as full 32 bit values, the module synthesizes to one BRAM as it should. LOL I had declared the memory type in the entity. Looking at moving it to a common file I didn't realize it was already being truncated. \$\endgroup\$
    – gnuarm
    Oct 25 '20 at 22:32
  • \$\begingroup\$ Got a bit ahead of myself. I had it working well when using the local type definition. type BRAM_t is array (integer range <>) of natural range 0 to 2**DataWidth-1; Using integer_vector makes the initial value neg-max and the to_unsigned barfs. Then more issues with Active-HDL and simple aggregates. lather, rinse, repeat. Anyway, it works with integer_vector and no type definition at all (big plus... I think). The Gowin synthesis tool is giving me a single block RAM as hoped. Schematic tool shows all 2048 internal FF 32 wide banks, so won't be much use on real designs. \$\endgroup\$
    – gnuarm
    Oct 25 '20 at 23:26

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:
-- Blk_mem - Memory block, variable data width and depth
-- 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
    AddrWidth : positive := 11;
    DataWidth : positive := 9
    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";

  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;
    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
    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);
  Clk_gen: Clk <= not Clk after Clock_Half_Period;

  stimulus: process (Clk)
    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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.