VHDL’de RAM Bloğu Oluşturmak

RAM’ler (Random Access Memory – Rastgele Erişimli Hafıza), ROM’lardan farklı olarak verilerin hem okunmasına hem de yazılmasına izin veren bir hafıza birimidir. Rastgele erişim kontrol devresi ile saklanmış verilere rastgele sırada direk erişim sağlanır. Şekil 1’de NxM bitlik RAM gösterimi bulunmaktadır. Şekil 9‑24’den de görüleceği üzere in_ram_aktif giriş portunun aktif olması ile birlikte ile RAM’dan in_data_addr adresindeki data out_data çıkış portuna aktarılmaktadır. in_yaz_en giriş portunun aktif olması ile birlikte in_data giriş portundaki data in_data_addr adrsindeki yerine yazılmaktadır.

Şekil 1 NxM bitlik RAM

Hafıza elemanları tasarlanırken genel olarak kullanılan bazı terimlere aşina olmak gerekmektedir. Bu bölümde verilen örneklerde geçen VERI_UZUNLUGU tanımlaması tasarladığımız hafıza biriminin veri yolu genişliğini bildirmektedir. Örneğin bu değer 8 ise tasarlanan hafıza elemanı her bir adreste 8 bit uzunluğunda veri saklayabiliyor demektir.

Hafıza elemanları ile ilgili bir diğer tanımlama ise ROM_DERINLIGIdir. Bu tanımlama ile tasarladığımız hafıza elemanının kaç adet veri saklayacabileği belirtilmektedir. Bu değer aynı zaman doğrudan adresleme hattının uzunluğunun da belirlenmesini sağlamaktadır. Örneklemek gerekirse; 32 adet veri saklamak istersek ROM_DERINLIGI tanımlamasının değerinin 32 olması gerekmektedir. 32 adet veriyi adreslemek için gereken adres yolu genişliği ise  hesaplamında gösterildiği şekilde 5 bit olacaktır.

Örnek 1: Şekil 9‑24’de gösterilen blok ram tasarımın yapıldığı blok_ram.vhd VHDL kodu aşağıda verilmiştir. blok_ram varlığımıza ilişkin generic bildirimleri 7-10. satırlarda, port bildirimleri 11-16. satırları arasında yapılmaktıdır.

RAM tasarımında 1 bitlik saat darbesi giriş portu, 1 bitlik RAM aktif giriş portu, generic ROM_DERINLIGI parametresine bağlı olarak hesaplanan adres giriş portu, 1 bitlik yazma aktif giriş portu,  RAM’a dataların yazılması için VERI_UZUNLUGU uzunluğunda data giriş portu ve okununan adresindeki datanın RAM dışına aktarılması için VERI_UZUNLUGU uzunluğunda çıkış portu mevcuttur.

RAM adres uzunluğunun belirlenmesi için kullanılacak olan log2_int fonskiyonu 4. satırda tanımlanan ornekler_paket (Blok RAM oluşturma yazısında verilmiştir.) paketi içerisinde tanımlanmıştır. 24. satırda VERI_UZUNLUGU genişliğine sahip RAM_DERINLIGI derinliğinde tip tanımlama işlemi yapılmıştır.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.ornekler_paket.all;
 
entity blok_ram is
  generic(
    VERI_UZUNLUGU : integer := 8;
    RAM_DERINLIGI : integer := 110
  );
  port(
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_ram_aktif : in std_logic;
    in_yaz_en : in std_logic;
    in_data_addr : in std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0);
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data : out std_logic_vector(VERI_UZUNLUGU - 1 downto 0)
  );
end blok_ram;
 
architecture Behavioral of blok_ram is
 
  type t_BRAM_DATA is array (0 to RAM_DERINLIGI - 1) of std_logic_vector(VERI_UZUNLUGU - 1 downto 0) ;
  signal r_BRAM_DATA : t_BRAM_DATA := (others =>(others => '0'));
 
begin
 
  process(in_clk, in_rst)
  begin
    if in_rst = '1' then
      r_BRAM_DATA <= (others =>(others => '0'));
    elsif rising_edge(in_clk) then
      if in_ram_aktif = '1' then
        out_data <= r_BRAM_DATA(conv_integer(in_data_addr));
        if in_yaz_en = '1' then
          r_BRAM_DATA(conv_integer(in_data_addr)) <= in_data;
        end if;
      end if;
    end if;
  end process;

 end Behavioral;

Aşağıda verilen tb_blok_ram.vhd VHDL kodu ile  blok_ram varlığının benzetim işlemleri yapılmaktadır. Benzetim işlemlerinde, sinüs örneklerinin kaydedildiği sin.txt dosyasından okuma işlemleri yapılmakta ve okunan datalar RAM’a yazılmaktadır. Verilerin yazılma işlemi dosyanın sonuna gelinmesi veya RAM’in dolması durumlarında sonlanmaktadır. Yazma işlenmesinin sonlanması ile birlikte toplmda RAM’a yazılan data sayısı hafızaya alınmaktadır. Daha sonra ise okuma işlemi başlamaktadır. Okuma işlemleri aslında başlangıç anından itibaren yapılmaktadır. RAM’in başlangıç değerlerinin tamamının sıfır olması nedeniyle verilerin yazılma işlemi anında okunan dataların değeri sıfır olmaktadır. Okuma işleminde sinüs datalarının RAM’a yazılmış olması ile birlikte out_data çıkış portunda sinüs örnekleri görülmektedir (Şekil 2).

Şekil 2 block_ram varlığı benzetim çıktısı

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use std.textio.ALL;
use work.ornekler_paket.all;
 
entity tb_blok_ram is
end tb_blok_ram;
 
architecture Behavioral of tb_blok_ram is
 
  component blok_ram
  generic(
    VERI_UZUNLUGU : integer := 8;
    RAM_DERINLIGI : integer := 110
  );
  port(
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_ram_aktif : in std_logic;
    in_yaz_en : in std_logic;
    in_data_addr : in std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0);
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data : out std_logic_vector(VERI_UZUNLUGU - 1 downto 0)
  );
  end component;

  type t_RAM_Kontrol is (DATA_YAZ, DATA_OKU, TAMAM);
  signal r_RAM_Kontrol : t_RAM_Kontrol := DATA_YAZ;
  
  constant CLK_PERIOD : time := 150 ns;
  constant VERI_UZUNLUGU : integer := 24;
  constant RAM_DERINLIGI : integer := 500;
  constant VERI_YOLU : string := "C:\sin.txt";

  signal in_clk : std_logic := '0';
  signal in_rst : std_logic := '0';
  signal in_ram_aktif : std_logic := '0';
  signal in_yaz_en : std_logic := '0';
  signal in_data_addr : std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0) := (others => '0');
  signal in_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal out_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');   
  signal sayac : std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0) := (others => '0');
  signal ORNEK_SAYISI : std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0) := (others => '0');

begin
 
  process
  begin
    in_clk <= '1';
    wait for CLK_PERIOD / 2;
    in_clk <= '0';
    wait for CLK_PERIOD / 2;      
  end process;
 
  process(in_clk)
    file dosya : text open read_mode is VERI_YOLU;
    variable satir : line;
    variable data : integer;
  begin
    if rising_edge(in_clk) then
      case r_RAM_Kontrol is
        when DATA_YAZ =>
          if (not endfile(dosya)) then
            readline(dosya, satir);
            read(satir, data);
            in_data <= conv_std_logic_vector(data, VERI_UZUNLUGU);
            in_data_addr <= sayac;
            in_yaz_en <= '1';
            in_ram_aktif <= '1';
            if sayac = RAM_DERINLIGI - 1 then
              sayac <= (others => '0'); 
              ORNEK_SAYISI <= sayac;
              r_RAM_Kontrol <= DATA_OKU;
            else
              sayac <= sayac + 1; 
            end if;
          end if;
 
        when DATA_OKU =>
          in_yaz_en <= '0';
          in_data_addr <= sayac;
          sayac <= sayac + 1;
          if sayac = ORNEK_SAYISI then
            r_RAM_Kontrol <= TAMAM;
          end if;
 
        when TAMAM =>
          in_ram_aktif <= '0';    
          
        when others => NULL;
      end case;
    end if;
  end process;   
 
  blok_ram_map : blok_ram
  generic map(
    VERI_UZUNLUGU => VERI_UZUNLUGU,
    RAM_DERINLIGI => RAM_DERINLIGI
  )
  port map(
    in_clk => in_clk,
    in_rst => in_rst,
    in_ram_aktif => in_ram_aktif,
    in_yaz_en => in_yaz_en,
    in_data_addr => in_data_addr ,
    in_data => in_data,
    out_data => out_data
  );
end Behavioral;

Yukarıda verilen blok_ram.vhd VHDL kodu benzetimlerde kullanmak amacı ile reset girişi ile birlikte oluşturulmuştur. Vivado programı ile bu kodu sentezlenmesi esnasında FPGA içerisinde bulunan blok ram’lar kullanılmamaktadır. Örneğin VERI_UZUNLUGU parametresi 8 ve RAM_DERINLIGI 128 olarak seçilerek kod sentezlendiğinde elde edilen sonuçlar aşağıda verilmiştir. Sonuçlardan da görüleceği üzre block_ram varlığmız FPGA içerisinde bulunan mandallar (FF) ve bakma tabloları (LUTs) kullanılarak gerçekleştirilmiştir. RAM derinliği ve genişliği arttıkça ise alan tüketimi aratacaktır. Bu nedenle gerçekleme esnasında bu kodun kullanımı önerilmemektedir.

FPGA içerisinde bulunan ramların kullanılabilmesi için reset girişi ve hafıza bloğunun koddan çıkarılması gerekmektedir. Aşağıda verilen blok_ram.vhd VHDL kodu ile FPGA içerisinde verilen ram blokları kullanılmış olacaktır. Verilen sentez sonuçlarından da görüleceği üzere FPGA içerinde bulunan mandallar ve bakma tabloları kullanılmadan FPGA içerisinde bulunan blok ramlar kullanılarak blok_ram varlığımız gerçeklenmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.ornekler_paket.all;
 
entity blok_ram is
  generic(
    VERI_UZUNLUGU : integer := 8;
    RAM_DERINLIGI : integer := 110
  );
  port(
    in_clk : in std_logic;
    in_ram_aktif : in std_logic;
    in_yaz_en : in std_logic;
    in_data_addr : in std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0);
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data : out std_logic_vector(VERI_UZUNLUGU - 1 downto 0)
  );
end blok_ram;
 
architecture Behavioral of blok_ram is
 
  type t_BRAM_DATA is array (0 to RAM_DERINLIGI - 1) of std_logic_vector(VERI_UZUNLUGU - 1 downto 0) ;
  signal r_BRAM_DATA : t_BRAM_DATA := (others =>(others => '0'));
 
begin
 
  process(in_clk, in_rst)
  begin
    if rising_edge(in_clk) then
      if in_ram_aktif = '1' then
        out_data <= r_BRAM_DATA(conv_integer(in_data_addr));
        if in_yaz_en = '1' then
          r_BRAM_DATA(conv_integer(in_data_addr)) <= in_data;
        end if;
      end if;
    end if;
  end process;
 
end Behavioral;

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir