Model of the Month


We can update you automatically when this page changes.
To receive regular notification of updates to our Model of the Month section, click here.


Generic Large-capacity RAM Model

The behavioural code presented in this month's Model of the Month will enable you to create a large-capacity RAM model limited only by the virtual memory of you computer.

When modeling large memories using VHDL, many users are disappointed by the limited sizes of RAM that they can create. This is because of the way that simulators “build” the RAM model during elaboration. When modeling RAMs, it is better to use an integer array or an array of bit vectors for the RAM storage rather than an array of std_logic_vectors. In this example, we use an integer array because it is intellectually more challenging!

On this page, we show the VHDL for the generic RAM core (entity and architecture) and a 64k word by 16-bit RAM model which instantiates the generic RAM core. You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Acknowledgements page for more details).


The VFP Library is required for simulating this month's Model of the Month
To download the VFP files, click here.


-- Generic Large-capacity RAM Model

-- +-----------------------------+
-- | Copyright 1995-1996 DOULOS  |
-- |       Library: memory       |
-- |    designer : Tim Pagden    |
-- |     opened: 26 Nov 1995     |
-- +-----------------------------+

-- Function: 64k x 16 SRAM with separate I/O. OE and CS are active HIGH
--   WE latches data on rising edge

library ieee;  
library vfp;
  use ieee.std_logic_1164.all;
  use vfp.generic_functions.all;

entity sram_64k_16 is
generic (
  -- more to do with attribute'ing
  architecture_DNH_filename : string := "????????.dnh" -- 
);              
port (
  address  : in  std_ulogic_vector(15 downto 0);
  CS       : in  std_ulogic;
  WE       : in  std_ulogic;
  OE       : in  std_ulogic;
  data_in  : in  std_logic_vector(15 downto 0);
  data_out : out std_logic_vector(15 downto 0)
);
begin
  -- data bus width must be integer power of 2 bits, < 64
  assert is_factor_of_32(data_in'length)
    report "Width of data bus must be 1, 2, 4, 8, 16 or 32 bits."
    severity warning;
end sram_64k_16;

-- Architectures:
--   12.02.96 original      PASSED SIMULATION

library memory;

architecture original of sram_64k_16 is
  use memory.sram_core_GENERIC_cmpt.all;

  constant address_width : integer := 16;
  constant data_width : integer := 16;
  
  attribute dnh_file_name : string(1 to 12);
  attribute dnh_file_name of sram_64k_16 : entity is architecture_DNH_filename; 

begin

  G1: sram_core_GENERIC 
    generic map (
      address_width => address_width,
      data_width => data_width
    )
    port map (
      address => address, 
      CS => CS, 
      WE => WE, 
      OE => OE, 
      data_in => data_in, 
      data_out => data_out
    );
  
end original;
 
-- +-----------------------------+
-- | Copyright 1995-1996 DOULOS  |
-- |       Library: memory       |
-- |    designer : Tim Pagden    |
-- |     opened: 26 Nov 1995     |
-- +-----------------------------+

-- Function: generic SRAM model with separate I/O. OE and CS are active HIGH
--   WE latches data on rising edge

library ieee;  
library vfp;
  use ieee.std_logic_1164.all;
  use vfp.generic_functions.all;

entity sram_core_GENERIC is
generic (
  -- entity parameterization (must have these in the generic map)
  address_width : integer := 0; --
  data_width    : integer := 0; -- 
  -- more to do with attribute'ing
  architecture_DNH_filename : string := "????????.dnh" -- 
);              
port (
  address  : in  std_ulogic_vector(address_width-1 downto 0);
  CS       : in  std_ulogic;
  WE       : in  std_ulogic;
  OE       : in  std_ulogic;
  data_in  : in  std_logic_vector(data_width-1 downto 0);
  data_out : out std_logic_vector(data_width-1 downto 0)
);
begin
  -- data bus width must be integer power of 2 bits, < 64
  assert is_factor_of_32(data_width)
    report "Width of data bus must be 1, 2, 4, 8, 16 or 32 bits."
    severity warning;
end sram_core_GENERIC;

-- Architectures:
--   12.02.96 original      PASSED SIMULATION

library vfp;
library ieee;

architecture original of sram_core_GENERIC is
  use vfp.host_environment_parameters.all;
  use vfp.standard_types.all;
  use vfp.generic_functions.all;
  use vfp.generic_conversions.all;
  use IEEE.std_logic_1164.all;

  constant memory_depth : integer := 2 ** address_width;
  constant num_bits_in_integer : integer := vfp.host_environment_parameters.num_bits_in_integer;
  
  attribute dnh_file_name : string(1 to 12);
  attribute dnh_file_name of sram_core_GENERIC : entity is architecture_DNH_filename; 

begin

  -- address, 0 to 31
  -- memory_depth, 0 to 7
  -- num_slices_in_integer, 4
  -- WE is inactive after the posedge until the -ve edge
  -- CS and OE are both active high

  -- the disadvantage of modeling with integer memory is that there's
  -- no representation of undefined or unknown in the integer memory
  -- itself. As the default value of integer is 100..000 in 32 bit
  -- parlance, you have to be aware that 000..000 could mean 
  -- uninitialized as well as real all-zero data
  ram_access: process (address, cs, we, oe)
    constant num_slices_in_integer : integer := num_bits_in_integer / data_in'length;
    constant memory_depth : integer := (2**(address'length)) / num_slices_in_integer;
    type integer_memory is array (0 to memory_depth-1) of integer;
    variable memory_array : integer_memory;
    variable memory_index : integer;
    variable memory_data : integer;
    variable memory_word : std_ulogic_vector(num_bits_in_integer-1 downto 0);
    variable intra_memory_index : integer;
    variable upper_bound : integer;
    variable invalid_control_signals : boolean;
    variable address_int : integer;
  begin
    data_out <= (others =>  'X'); -- initially set output buffers driving unknowns
    if not (cs = '1' or cs = '0') then
      invalid_control_signals := TRUE;
    elsif not (oe = '1' or oe = '0') then
      invalid_control_signals := TRUE;
    elsif not (we = '1' or we = '0') then
      invalid_control_signals := TRUE;
    else
      invalid_control_signals := FALSE;
      data_out <= (others => 'Z'); 
      -- set output buffers high-impedance if memory control signals are valid levels
    end if;
    if not invalid_control_signals then
      -- cs, oe and we must each be 1 or 0 for this branch to be taken
      address_int := to_integer(address);
      if cs = '1' then -- memory access possible
        if oe = '1' then  -- read or clash possible
          if we = '1' then
            -- read cycle
            memory_index := address_int / num_slices_in_integer; -- 4 := 17/4
            -- converts address into index into memory
            memory_data := memory_array(memory_index);
            -- extracts integer where addressed word is placed
            memory_word := to_std_ulogic_vector (memory_data, num_bits_in_integer);
            -- converts integer to 32-bit vector
            intra_memory_index := address_int mod num_slices_in_integer; -- 1 := 17/4
            -- address now used to get word-index of addressed word in 32-bit vector
            upper_bound := (intra_memory_index + 1) * data_out'length;
            -- defines upper index of addressed word in 32-bit vector
            data_out <= To_StdLogicVector (memory_word(upper_bound-1 downto upper_bound-data_out'length));
            -- To_StdLogicVector is IEEE std_logic_1164, drives data bus with addressed memory word
          elsif we = '0' then
            assert false
              report "oe and we are both active." 
              severity warning;
          end if;
        elsif oe = '0' then -- oe is inactive, only write possible
          if (we = '1') and we'event then
            -- write cycle
            memory_index := address_int / num_slices_in_integer; 
            -- converts address into index into memory
            memory_data := memory_array(memory_index);
            -- extracts integer where addressed word is placed
            memory_word := to_std_ulogic_vector (memory_data, num_bits_in_integer);
            -- converts integer to 32-bit vector
            intra_memory_index := address_int mod num_slices_in_integer;
            -- address now used to get word-index of addressed word in 32-bit vector
            upper_bound := (intra_memory_index + 1) * data_in'length;
            -- defines upper index of addressed word in 32-bit vector
            memory_word(upper_bound-1 downto upper_bound-data_in'length) := to_StdULogicVector (data_in);
            -- inserts data into extracted memory word
            -- ... now convert whole word to integer & place back in integer array
            memory_array(memory_index) := to_integer(to_twos_complement(memory_word));
          elsif we = '1' then
            -- both we and oe not active, nowt happens
          elsif we = '0' then
            -- we active, nowt happens until posedge of WE
          end if;
        end if;
      else
        -- memory not selected
      end if;
    else
      assert false
        report "Control signals are not active, memory is not selected."
        severity note;
    end if;
  end process;
  
end original;

To download the VHDL source code for this month's
Model of the Month, click here.

VHDL and Verilog source code for other Models of the Month
can be downloaded from here.


building blocksAdvanced VHDL Techniques
accumulator diagramASIC Design and Project Services
teaching pointerDoulos Training Courses


river sceneDoulos Home Page

Copyright 1995-1997 Doulos
This page was last updated 12th March 1996

mail iconWe welcome your e-mail comments. Please contact us at: webmaster@doulos.co.uk