Yükselen kenar dedektörü
Bir girişin tek bir yükselen kenarı, tam olarak bir clock periyodu boyunca çıkış üretir. Son çevrimi hatırlayan flip-flop ve karşılaştıran kapı.
- Seviye
- rtl
- Kod
- rising-edge-detector
- Kontrol edildi
- Verilator 5.052, Icarus Verilog 13.0, Yosys 0.66
- Yayımlandı
- Yazarlık
- Taslağı yapay zekâ desteğiyle hazırlandı
- Durum
- Yapım aşamasında — gözden geçirilsin diye yayında, bitmiş değil.
Yükselen kenar dedektörü bir seviyeyi olaya çevirir: sig_in yüksek kaldığı sürece çıkış
pulse yalnızca bir clock periyodu boyunca yüksek olur, yükselişten sonraki çevrimde. Senkron
bir tasarımda "şu olduğunda şunu bir kez yap" diyen her şeyin arkasındaki devre budur — bir
buton basışı, bir FIFO yazması, bir start sinyali.
Devrenin tamamı bir flip-flop ile bir kapıdan ibarettir. Flip-flop sig_in'in bir çevrim önce
ne olduğunu hatırlar; kapı ise şimdi yüksek olup olmadığını ve o zaman olmadığını sorar.
“Çalıştır” bu senaryoyu baştan oynatır; bir girişe basmak buradan devam eder.
Çalışan bir devre: şeması ve dalga biçimi aynı zaman ekseninde. Girişler: sig_in, rst_n. Çıkışlar: pulse. clk periyodu 8 tick. Şunlardan kurulu: 1 D flip-flop, 1 çevirici, 1 AND kapısı. Dalga biçimi şunları gösteriyor: clk, rst_n, sig_in, sig_d, pulse.
Şekil 1. “Çalıştır”a basın. sig_in ikinci kenarda yükselir; pulse ardından gelen tek periyot boyunca yüksek kalır.
Nasıl çalışır, kenar kenar
Çizimin altındaki dalga biçimini izleyin. İlk yükselen kenardan önce sig_d X'tir: flip-flop'u
hiçbir şey sıfırlamamıştır ve henüz bir kenar gelmemiştir, dolayısıyla hiçbir değer tutmaz —
reset'in devrenin bir parçası olmasının, sonradan eklenen bir şey olmamasının sebebi de budur.
İlk kenarda sig_d, sig_in'in tuttuğu 0'ı alır ve pulse 0 kalır, çünkü sig_in henüz
0'dır.
sig_in ikinci kenarda yükselir, ama o kenar sig_in'in hemen önceki değerini, 0'ı örnekler.
Artık sig_in 1 iken sig_d hâlâ flip-flop'un yakaladığı 0'dır; ~sig_d 1 olur ve pulse
yükselir. Üçüncü kenarda flip-flop yetişir, sig_d 1 olur ve pulse düşer — yükselmesinden tam
bir clock periyodu sonra.
Kod
// One rising edge of sig_in produces one clock period of pulse.
//
// Reset style for this module: asynchronous, active low. One style per page,
// stated up front, so nothing on the page has to be read twice.
module rising_edge_detector (
input logic clk,
input logic rst_n,
input logic sig_in,
output logic pulse
);
// The value sig_in had one clock period ago.
logic sig_d;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
sig_d <= 1'b0;
end else begin
sig_d <= sig_in;
end
end
// High for exactly one clock period, on the cycle after sig_in rises.
assign pulse = sig_in & ~sig_d;
endmoduleReset biçimi dosyanın başında belirtilir ve bir kez kullanılır: asenkron, aktif düşük. Çizimdeki
flip-flop always_ff bloğudur, assign ise tersleyen girişiyle birlikte AND kapısıdır.
Sentez sonucu
rising_edge_detector.sv, Yosys'un genel sentezinde 2 hücre olur; 1 tanesi flip-flop. Hücreler Yosys'un kendi kapı kütüphanesinden; bir FPGA'nın ya da standart hücre kütüphanesinin değil. Sayı herhangi bir çipin alanını değil, mantığı ölçer.
| Hücre | Ne olduğu | Adet |
|---|---|---|
$_DFF_PN0_ | yükselen kenarda D flip-flop, 0 değerine aktif düşük asenkron reset | 1 |
$_ANDNOT_ | ikinci girişi terslenmiş AND, A & ~B | 1 |
| Toplam | 2 | |
Lint Verilator 5.052 ile, testbench Icarus Verilog 13.0 ile, sentez Yosys 0.66 ile yapıldı.
Icarus bu sayfanın iki senaryosunu da bu kod üzerinde yeniden oynattı ve dalga biçiminin çizdiği 340 değerin hepsi tutuyor.
Sentezden önceki netlist
Yosys prep'in rising_edge_detector.sv dosyasında okuduğu yapı, henüz hiçbir kapı seçilmeden; netlistsvg 1.0.2 ile çizildi.
Tuzaklar
Asenkron bir giriş. sig_in başka bir clock domain'inden geliyorsa, onu koymanın yeri bu
devre değildir. Flip-flop sig_in'i tam değiştiği anda örnekleyip metastable (yarı kararlı)
olabilir ve AND kapısı bir clock periyodundan çok daha kısa bir pulse üretebilir — bir sonraki
aşamanın kaçıracağı ya da bir kenarda yakalayıp diğerinde kaçıracağı kadar kısa. Önce
senkronlayın, sonra kenarı yakalayın.
Devrenin yalnızca yarısına ulaşan reset. sig_d reset'lenir; pulse reset'lenmez, çünkü
kombinasyoneldir. sig_in zaten yüksekken reset'ten çıkmak hemen bir pulse üretir. Çoğu zaman
istenen de budur, ama bu hiçbir zaman kazara olmamalıdır.
Kendinizi sınayın
- pulse neden sig_in yüksek kaldığı sürece değil de tam olarak bir clock periyodu boyunca yüksek kalır?
- Çünkü flip-flop yetişir. sig_in yükseldikten bir kenar sonra sig_d de 1 olur, bu yüzden sig_in & ~sig_d yeniden 0'a döner — sig_in ne kadar uzun süre yüksek kalırsa kalsın.
- Bu devre clk'ye senkron olmayan bir girişle ne yapar?
- Bir clock periyodu uzunluğunda olmayan bir pulse üretir, hatta hiç üretmeyebilir. Flip-flop bir değişikliği tam olurken örnekleyebilir ve AND kapısı bir glitch görür. Asenkron bir girişin bu devreden sonra değil, önce bir senkronlayıcıya (synchronizer) ihtiyacı vardır.
Görev: Üç pulse
1, 3 ve 6 numaralı kenarlarda pulse 1 olsun. Yalnızca sig_in girişini siz sürersiniz.
- Sizin girişiniz
-
- sig_in, başlangıçta 0
- Betik
-
- rst_n başlangıçta 0.
- rst_n, 0 numaralı kenardan önce 1 olur.
- Hedef
-
- 1 numaralı kenarda pulse değeri 1.
- 3 numaralı kenarda pulse değeri 1.
- 6 numaralı kenarda pulse değeri 1.
JavaScript açıkken “Başla” bu görevi şekilde oynatır.