1-Giriş

Bu yazıda verilog ile SRAM denetimi konusuna değineceğiz. Aslında yapılması gereken çok fazla birşey yok, SRAMlerin arayüzleri ve kullanımları gayet basit.

2-SRAM Nedir, Nasıl Çalışır?

Bu konuda Vikipedi’de çok güzel bir yazı var. Tavsiye ederim:

http://tr.wikipedia.org/wiki/SRAM

Bu uygulamada yapmak istediğimiz belleğin 0 – 5000 adresleri arasına 8 bitlik artan veri yazmak ve ardından da saniyede bir kere ilk adresten başlayarak yazdığımız veriyi bellekten okumak.

SRAM fiziki olarak deneme kartınızda bulunmasa bile SRAM’i FPGA içinde oluşturup kullanabilirsiniz. Xilinx’de bu Block RAM olarak geçiyor. Altera’da ise direk olarak RAM adı verilmiş. Ben de bu yazıda Spartan 3E500 Starter Kit kartımı kullandığımdan fiziki SRAM yerine Block RAM kullanacağım. Block RAM’in nasıl oluşturulduğuna Xilinx Core Generator ile Block RAM oluşturmak adlı yazımdan bakabilirsiniz.

3-Uygulama Kodları

sram_uygulamasi.v:

  1. `timescale 1ns / 1ps
  2. module sram_uygulamasi(
  3. SAAT,
  4. LEDLER,
  5. ILKLENDIR
  6. );
  7. // girdi-ç?kt? kap?lar?
  8. input               SAAT;
  9. output  [7:0]       LEDLER;
  10. input                   ILKLENDIR;
  11. // yazmaç ve teller
  12. reg                     yaz_oku;
  13. wire        [7:0]   sram_veri_cikis;
  14. reg         [7:0]   sram_veri_giris;
  15. reg     [12:0]  sram_adres;
  16. reg                     sram_veri_yaz;
  17. reg     [31:0]  sayac;
  18. reg     [7:0]       ledler;
  19. always @ (posedge SAAT) begin
  20. if(ILKLENDIR) begin
  21. // sistemi ilklendir
  22. yaz_oku                 <= 1’b0;
  23. sayac                   <= 0;
  24. sram_veri_yaz       <= 1’b0;
  25. sram_veri_giris <= 0;
  26. sram_adres          <= 0;
  27. ledler              <= 0;
  28. end
  29. else begin
  30. // 1000 veri yaz, 1000 veri oku
  31. if(yaz_oku == 1’b0) begin
  32. // yaz
  33. sayac           <= 0;
  34. sram_veri_yaz   <= 1’b1;
  35. ledler          <= sram_veri_giris;
  36. if(sram_adres == 5000) begin
  37. // okumaya geç
  38. yaz_oku                 <= 1’b1;
  39. sram_adres          <= 0;
  40. sram_veri_giris <= 0;
  41. end
  42. else begin
  43. // yazmaya devam et
  44. yaz_oku                 <= 1’b0;
  45. sram_adres          <= sram_adres + 1’b1;
  46. sram_veri_giris <= sram_veri_giris + 1’b1;
  47. end
  48. end
  49. else begin
  50. // oku
  51. sram_veri_yaz       <= 1’b0;
  52. sram_veri_giris <= sram_veri_giris;
  53. ledler              <= sram_veri_cikis;
  54. if(sayac == 50000000) begin
  55. // yeni veri okunabilir
  56. sayac               <= 0;
  57. if(sram_adres == 5000) begin
  58. // yeni veri okuma, yazmaya geri dön
  59. sram_adres          <= 0;
  60. yaz_oku                 <= 1’b0;
  61. end
  62. else begin
  63. // yeni veri oku
  64. yaz_oku                 <= 1’b1;
  65. sram_adres          <= sram_adres + 1’b1;
  66. end
  67. end
  68. else begin
  69. // yeni veri okuma, bekle
  70. yaz_oku                 <= yaz_oku;
  71. sayac                   <= sayac + 1’b1;
  72. sram_adres          <= sram_adres;
  73. end
  74. end
  75. end
  76. end
  77. // Block RAM
  78. block_ram_1 bellegim_benim(
  79. .clka(SAAT),                        // saat darbesi
  80. .dina(sram_veri_giris),         // yaz?lacak veri
  81. .addra(sram_adres),             // adres
  82. .wea(sram_veri_yaz),                // yaz/oku ayar i?nesi
  83. .douta(sram_veri_cikis)         // okunan veri
  84. );
  85. assign LEDLER = ledler;
  86. endmodule

sram_uygulamasi.ucf:

  1. NET “SAAT” LOC = “C9” | IOSTANDARD = LVCMOS33 ;
  2. NET “SAAT” PERIOD = 20.0ns HIGH 40%;
  3. NET “LEDLER<7>” LOC = “F9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  4. NET “LEDLER<6>” LOC = “E9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  5. NET “LEDLER<5>” LOC = “D11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  6. NET “LEDLER<4>” LOC = “C11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  7. NET “LEDLER<3>” LOC = “F11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  8. NET “LEDLER<2>” LOC = “E11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  9. NET “LEDLER<1>” LOC = “E12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  10. NET “LEDLER<0>” LOC = “F12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
  11. NET “ILKLENDIR” LOC = “K17” | IOSTANDARD = LVTTL | PULLDOWN ;

4- Vidyo

(… ve gelecek projemin ne olduğu hakkında bir ipucu …)

5-Teşekkür, Tebrik ve 1. Geleneksel Kapanış Konuşması

Bu yazıda SRAM kullanımını bir adet örnek ile görmüş olduk. Kendi oyun konsolu projemde bu SRAM denetleyiciyi kullanmayı planlıyorum.

Umarım işinize yarar. Kolay gelsin. İyi çalışmalar.

6- Super Mario Bros. 3 – King of Koopas (Bowser) Melodisi

Çok güzel evet BRAM denetlediğinizi sandınız ama… acaba cidden denetlediniz mi? Hayır! Block RAM’i ISE kaçırdı 😀

Xilinx ISE otomatik olarak yaptıklarınızı sildi ve sayaçlar yerleştirdi -çünkü mantıklı olan bu, ama bazen mantıksız olarak da silebiliyor, dikkat edin-. Yani Block RAM kullanılmadı. Hmm… peki bunu nasıl mı anlarız? Bir süredir ISE kullanıyorsanız zaten yeterince şüphecisinizdir ama değilseniz RTL şemasına bakmanız yeterli:

brk_sematik.JPG

Kodda biraz değişiklik yaparak ISE’nin optimizasyon yapmamasını sağlayalım 😀 (ledler <= sram_veri_giris; satırını ledler <= ledler ile değiştiriyorum). Buyrun düzgün kodumuz:

  1. `timescale 1ns / 1ps
  2. module sram_uygulamasi(
  3. SAAT,
  4. LEDLER,
  5. ILKLENDIR
  6. );
  7. // girdi-ç?kt? kap?lar?
  8. input               SAAT;
  9. output  [7:0]       LEDLER;
  10. input                   ILKLENDIR;
  11. // yazmaç ve teller
  12. reg                     yaz_oku;
  13. wire        [7:0]   sram_veri_cikis;
  14. reg         [7:0]   sram_veri_giris;
  15. reg     [12:0]  sram_adres;
  16. reg                     sram_veri_yaz;
  17. reg     [31:0]  sayac;
  18. reg     [7:0]       ledler;
  19. always @ (posedge SAAT) begin
  20. if(ILKLENDIR) begin
  21. // sistemi ilklendir
  22. yaz_oku                 <= 1’b0;
  23. sayac                   <= 0;
  24. sram_veri_yaz       <= 1’b0;
  25. sram_veri_giris <= 0;
  26. sram_adres          <= 0;
  27. ledler              <= 0;
  28. end
  29. else begin
  30. // 1000 veri yaz, 1000 veri oku
  31. if(yaz_oku == 1’b0) begin
  32. // yaz
  33. sayac           <= 0;
  34. sram_veri_yaz   <= 1’b1;
  35. ledler          <= ledler;
  36. if(sram_adres == 5000) begin
  37. // okumaya geç
  38. yaz_oku                 <= 1’b1;
  39. sram_adres          <= 0;
  40. sram_veri_giris <= 0;
  41. end
  42. else begin
  43. // yazmaya devam et
  44. yaz_oku                 <= 1’b0;
  45. sram_adres          <= sram_adres + 1’b1;
  46. sram_veri_giris <= sram_veri_giris + 1’b1;
  47. end
  48. end
  49. else begin
  50. // oku
  51. sram_veri_yaz       <= 1’b0;
  52. sram_veri_giris <= sram_veri_giris;
  53. ledler              <= sram_veri_cikis;
  54. if(sayac == 50000000) begin
  55. // yeni veri okunabilir
  56. sayac               <= 0;
  57. if(sram_adres == 5000) begin
  58. // yeni veri okuma, yazmaya geri dön
  59. sram_adres          <= 0;
  60. yaz_oku                 <= 1’b0;
  61. end
  62. else begin
  63. // yeni veri oku
  64. yaz_oku                 <= 1’b1;
  65. sram_adres          <= sram_adres + 1’b1;
  66. end
  67. end
  68. else begin
  69. // yeni veri okuma, bekle
  70. yaz_oku                 <= yaz_oku;
  71. sayac                   <= sayac + 1’b1;
  72. sram_adres          <= sram_adres;
  73. end
  74. end
  75. end
  76. end
  77. // Block RAM
  78. block_ram_1 bellegim_benim(
  79. .clka(SAAT),                        // saat darbesi
  80. .dina(sram_veri_giris),         // yaz?lacak veri
  81. .addra(sram_adres),             // adres
  82. .wea(sram_veri_yaz),                // yaz/oku ayar i?nesi
  83. .douta(sram_veri_cikis)         // okunan veri
  84. );
  85. assign LEDLER = ledler;
  86. endmodule

7- Son

Umarım işinize yarar. Kolay gelsin.