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:
- `timescale 1ns / 1ps
- module sram_uygulamasi(
- SAAT,
- LEDLER,
- ILKLENDIR
- );
- // girdi-ç?kt? kap?lar?
- input SAAT;
- output [7:0] LEDLER;
- input ILKLENDIR;
- // yazmaç ve teller
- reg yaz_oku;
- wire [7:0] sram_veri_cikis;
- reg [7:0] sram_veri_giris;
- reg [12:0] sram_adres;
- reg sram_veri_yaz;
- reg [31:0] sayac;
- reg [7:0] ledler;
- always @ (posedge SAAT) begin
- if(ILKLENDIR) begin
- // sistemi ilklendir
- yaz_oku <= 1’b0;
- sayac <= 0;
- sram_veri_yaz <= 1’b0;
- sram_veri_giris <= 0;
- sram_adres <= 0;
- ledler <= 0;
- end
- else begin
- // 1000 veri yaz, 1000 veri oku
- if(yaz_oku == 1’b0) begin
- // yaz
- sayac <= 0;
- sram_veri_yaz <= 1’b1;
- ledler <= sram_veri_giris;
- if(sram_adres == 5000) begin
- // okumaya geç
- yaz_oku <= 1’b1;
- sram_adres <= 0;
- sram_veri_giris <= 0;
- end
- else begin
- // yazmaya devam et
- yaz_oku <= 1’b0;
- sram_adres <= sram_adres + 1’b1;
- sram_veri_giris <= sram_veri_giris + 1’b1;
- end
- end
- else begin
- // oku
- sram_veri_yaz <= 1’b0;
- sram_veri_giris <= sram_veri_giris;
- ledler <= sram_veri_cikis;
- if(sayac == 50000000) begin
- // yeni veri okunabilir
- sayac <= 0;
- if(sram_adres == 5000) begin
- // yeni veri okuma, yazmaya geri dön
- sram_adres <= 0;
- yaz_oku <= 1’b0;
- end
- else begin
- // yeni veri oku
- yaz_oku <= 1’b1;
- sram_adres <= sram_adres + 1’b1;
- end
- end
- else begin
- // yeni veri okuma, bekle
- yaz_oku <= yaz_oku;
- sayac <= sayac + 1’b1;
- sram_adres <= sram_adres;
- end
- end
- end
- end
- // Block RAM
- block_ram_1 bellegim_benim(
- .clka(SAAT), // saat darbesi
- .dina(sram_veri_giris), // yaz?lacak veri
- .addra(sram_adres), // adres
- .wea(sram_veri_yaz), // yaz/oku ayar i?nesi
- .douta(sram_veri_cikis) // okunan veri
- );
- assign LEDLER = ledler;
- endmodule
sram_uygulamasi.ucf:
- NET “SAAT” LOC = “C9” | IOSTANDARD = LVCMOS33 ;
- NET “SAAT” PERIOD = 20.0ns HIGH 40%;
- NET “LEDLER<7>” LOC = “F9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<6>” LOC = “E9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<5>” LOC = “D11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<4>” LOC = “C11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<3>” LOC = “F11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<2>” LOC = “E11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<1>” LOC = “E12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- NET “LEDLER<0>” LOC = “F12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ;
- 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:
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:
- `timescale 1ns / 1ps
- module sram_uygulamasi(
- SAAT,
- LEDLER,
- ILKLENDIR
- );
- // girdi-ç?kt? kap?lar?
- input SAAT;
- output [7:0] LEDLER;
- input ILKLENDIR;
- // yazmaç ve teller
- reg yaz_oku;
- wire [7:0] sram_veri_cikis;
- reg [7:0] sram_veri_giris;
- reg [12:0] sram_adres;
- reg sram_veri_yaz;
- reg [31:0] sayac;
- reg [7:0] ledler;
- always @ (posedge SAAT) begin
- if(ILKLENDIR) begin
- // sistemi ilklendir
- yaz_oku <= 1’b0;
- sayac <= 0;
- sram_veri_yaz <= 1’b0;
- sram_veri_giris <= 0;
- sram_adres <= 0;
- ledler <= 0;
- end
- else begin
- // 1000 veri yaz, 1000 veri oku
- if(yaz_oku == 1’b0) begin
- // yaz
- sayac <= 0;
- sram_veri_yaz <= 1’b1;
- ledler <= ledler;
- if(sram_adres == 5000) begin
- // okumaya geç
- yaz_oku <= 1’b1;
- sram_adres <= 0;
- sram_veri_giris <= 0;
- end
- else begin
- // yazmaya devam et
- yaz_oku <= 1’b0;
- sram_adres <= sram_adres + 1’b1;
- sram_veri_giris <= sram_veri_giris + 1’b1;
- end
- end
- else begin
- // oku
- sram_veri_yaz <= 1’b0;
- sram_veri_giris <= sram_veri_giris;
- ledler <= sram_veri_cikis;
- if(sayac == 50000000) begin
- // yeni veri okunabilir
- sayac <= 0;
- if(sram_adres == 5000) begin
- // yeni veri okuma, yazmaya geri dön
- sram_adres <= 0;
- yaz_oku <= 1’b0;
- end
- else begin
- // yeni veri oku
- yaz_oku <= 1’b1;
- sram_adres <= sram_adres + 1’b1;
- end
- end
- else begin
- // yeni veri okuma, bekle
- yaz_oku <= yaz_oku;
- sayac <= sayac + 1’b1;
- sram_adres <= sram_adres;
- end
- end
- end
- end
- // Block RAM
- block_ram_1 bellegim_benim(
- .clka(SAAT), // saat darbesi
- .dina(sram_veri_giris), // yaz?lacak veri
- .addra(sram_adres), // adres
- .wea(sram_veri_yaz), // yaz/oku ayar i?nesi
- .douta(sram_veri_cikis) // okunan veri
- );
- assign LEDLER = ledler;
- endmodule
7- Son
Umarım işinize yarar. Kolay gelsin.