VHDL yazarken, SIGNALS için tamsayı (int) yerine std_logic_vector (slv) kullanmanızı tavsiye ederim . (Öte yandan, jenerikler için int, bazı sabitler ve bazı değişkenler son derece yararlı olabilir.) Basitçe söylemek gerekirse, int türünde bir sinyal bildirirseniz veya bir tamsayı için bir aralık belirtmeniz gerekiyorsa, muhtemelen Ters giden birşey mi var.
İnt ile ilgili sorun, VHDL programcısının int'in dahili mantık gösteriminin ne olduğu hakkında hiçbir fikri olmadığı ve bundan yararlanamayacağımızdır. Örneğin, 1 ila 10 aralığında bir int tanımlarsam, derleyicinin bu değerleri nasıl kodladığı hakkında hiçbir fikrim yoktur. Umarım 4 bit olarak kodlanır, ancak bunun ötesinde fazla bir şey bilmiyoruz. FPGA içindeki sinyalleri inceleyebiliyorsanız, "0001" ila "1010" olarak kodlanabilir veya "0000" ila "1001" olarak kodlanabilir. Ayrıca, insanlar için kesinlikle hiçbir anlam ifade etmeyecek şekilde kodlanması da mümkündür.
Bunun yerine int yerine slv kullanmalıyız, çünkü kodlama üzerinde kontrole sahibiz ve ayrıca ayrı bitlere doğrudan erişebiliyoruz. Daha sonra göreceğiniz gibi doğrudan erişime sahip olmak önemlidir.
Her bir bite erişmemiz gerektiğinde slv'ye int a atabiliriz, ancak bu gerçekten dağınık, çok hızlı olur. Bu, her iki dünyanın en iyisi yerine her iki dünyanın en kötüsünü almak gibidir. Kodun derleyicinin optimize etmesi zor olacak ve okumanız neredeyse imkansız. Bunu tavsiye etmiyorum.
Dediğim gibi, slv ile bit kodlamaları ve bitlere doğrudan erişim üzerinde kontrolünüz var. Peki bununla ne yapabilirsiniz? Size birkaç örnek göstereceğim. Diyelim ki her 4,294,000,000 saatte bir nabız atmanız gerekiyor. Bunu int ile nasıl yapacağınız aşağıda açıklanmıştır:
signal count :integer range 0 to 4293999999; -- a 32 bit integer
process (clk)
begin
if rising_edge(clk) then
if count = 4293999999 then -- The important line!
count <= 0;
pulse <= '1';
else
count <= count + 1;
pulse <= '0';
end if;
end if;
end process;
Ve slv kullanarak aynı kod:
use ieee.numeric_std.all;
signal count :std_logic_vector (32 downto 0); -- a 33 bit integer, one extra bit!
process (clk)
begin
if rising_edge(clk) then
if count(count'high)='1' then -- The important line!
count <= std_logic_vector(4293999999-1,count'length);
pulse <= '1';
else
count <= count - 1;
pulse <= '0';
end if;
end if;
end process;
Bu kodun çoğu int ve slv arasında, en azından ortaya çıkan mantığın boyutu ve hızı anlamında aynıdır. Elbette biri sayıyor, diğeri geri sayıyor, ancak bu örnek için önemli değil.
Aradaki fark "önemli çizgide".
İnt örneğiyle, bu 32 girişli bir karşılaştırıcı ile sonuçlanacaktır. Xilinx Spartan-3'ün kullandığı 4-Giriş LUT'lar ile, bu 11 LUT ve 3 seviye mantık gerektirecektir. Bazı derleyiciler bunu taşıma zincirini kullanacak ve 32 LUT'a eşdeğer olacak bir çıkarma işlemine dönüştürebilir, ancak 3 mantık seviyesinden daha hızlı çalışabilir.
Slv örneğinde, 32 bit karşılaştırması yoktur, bu nedenle "sıfır LUT'lar, sıfır mantık seviyeleri" dir. Tek ceza, sayacımızın ekstra bir bit olmasıdır. Bu fazladan sayacın ek zamanlaması taşıma zincirinde olduğundan, "neredeyse sıfır" ek zamanlama gecikmesi vardır.
Tabii bu aşırı bir örnektir, çünkü çoğu insan bu şekilde 32 bitlik bir sayaç kullanmaz. Daha küçük sayaçlar için geçerlidir, ancak fark hala önemli olmasına rağmen daha az dramatik olacaktır.
Bu, daha hızlı zamanlama elde etmek için int üzerinde slv'nin nasıl kullanılacağına sadece bir örnektir. Slv kullanmanın başka birçok yolu vardır - sadece biraz hayal gücü gerektirir.
Güncelleme: Martin Thompson'un "if (count-1) <0" ile int hakkında yaptığı yorumları ele alan şeyler eklendi
(Not: "sayı <0 ise" demek istediğinizi varsayarım, çünkü bu benim slv sürümümle daha eşdeğer olur ve bu ekstra çıkarma ihtiyacını ortadan kaldırır.)
Bazı durumlarda bu, amaçlanan mantık uygulamasını oluşturabilir, ancak her zaman çalışması garanti edilmez. Kodunuza ve derleyicinizin int değerini nasıl kodladığına bağlı olacaktır.
Derleyicinize ve int aralığınızı nasıl belirlediğinize bağlı olarak, sıfır int değerinin FPGA mantığına girdiğinde "0000 ... 0000" bit vektörüne kodlamaması tamamen mümkündür. Varyasyonunuzun çalışması için "0000 ... 0000" olarak kodlaması gerekir.
Örneğin, bir int değerini -5 ila +5 aralığında olacak şekilde tanımladığınızı varsayalım. 0 değerinin "0000" gibi 4 bit ve "0101" olarak +5 ve "1011" olarak -5 olarak kodlanmasını bekliyorsunuz. Bu, tipik iki bileşenli kodlama şemasıdır.
Ancak derleyicinin iki tamamlayıcı kullanacağını varsaymayın. Olağandışı olmasına rağmen, bir-tamamlayıcı "daha iyi" mantığına neden olabilir. Veya, derleyici -5 "0000", 0 "0101" ve +5 "1010" olarak kodlandığı bir tür "taraflı" kodlama kullanabilir.
İnt kodlaması "doğru" ise, derleyici taşıma biti ile ne yapılacağını tahmin edecektir. Ancak yanlışsa, ortaya çıkan mantık korkunç olacaktır.
Bu şekilde int kullanmanın makul mantık boyutu ve hızıyla sonuçlanması mümkündür, ancak bu bir garanti değildir. Farklı bir derleyiciye geçmek (örneğin XST'den Synopsis'e) veya farklı bir FPGA mimarisine gitmek, tam olarak yanlış olan şeyin olmasına neden olabilir.
İmzasız / İmzalı slv ile ilgili başka bir tartışma var. ABD Hükümeti komitesine VHDL'de bize bu kadar çok seçenek verdiği için teşekkür edebilirsiniz. :) Ben slv kullanın çünkü bu modüller ve çekirdekler arasındaki arayüz için standarttır. Bunun dışında ve simülasyonlardaki diğer bazı durumlarda, slv'yi imzalı / imzasız olarak kullanmanın büyük bir yararı olduğunu düşünmüyorum. İmzalı / imzasız üç belirtili sinyalleri destekleyip desteklemediğinden de emin değilim.