Andalan Utama Verilog Behavioral
assign menggambarkan logika kombinasional dengan satu persamaan. Begitu kamu butuh if/else, case, atau memori, kamu beralih ke always. Blok always adalah potongan kode prosedural yang berjalan ulang setiap kali sinyal tertentu berubah. Sinyal-sinyal yang memicu jalannya ulang itu adalah sensitivity list.
Ada dua bentuk always yang paling sering kamu lihat:
always @(*): berjalan ulang setiap kali sinyal apa pun yang dibaca di dalam blok berubah. Membangun logika kombinasional.always @(posedge clk): hanya berjalan ulang di tepi naikclk. Membangun logika sekuensial yang dikendalikan clock (flip-flop).
Bentuk lain juga ada (@(a or b), @(negedge clk), @(posedge clk or negedge reset_n)), tapi dua bentuk di atas mencakup hampir setiap blok yang bisa disintesis yang akan kamu tulis.
always @(*) yang Kombinasional
Tiga hal yang perlu diperhatikan:
outbertipereg. Apa pun yang diberi nilai di dalamalwaysharus bertipereg. Kata kunci itu tidak berarti "ini flip-flop"; di sini artinya hanya "aku ditulis dari blok prosedural".always @(*). Tanda*berarti "bangun setiap kali ada yang kubaca berubah". Simulator otomatis menentukan sensitivity list-nya. Kamu bisa menulis daftarnya secara manual, misalnyaalways @(sel), tapi@(*)lebih aman karena sinyal yang terlewat adalah sumber bug klasik.- Tanpa clock. Blok ini menggambarkan logika kombinasional. Synthesizer menghasilkan sepotong logika yang langsung menghitung
outdarisel: tanpa flip-flop, tanpa butuh pin clock.
Case default secara sintaks memang opsional, tapi secara semangat tidak. Kalau dihilangkan, nilai input apa pun yang tidak ditentukan membuat out menahan nilai sebelumnya, yang disintesis menjadi latch yang tidak diinginkan. Selalu sertakan default.
always @(posedge clk) yang Sekuensial
Perbedaan utamanya dari versi kombinasional:
always @(posedge clk). Blok ini hanya berjalan ulang di tepi naikclk. Tidak ada yang terjadi di antara tepi-tepi itu.- Penugasan non-blocking
<=. Di dalam blok yang dikendalikan clock, inilah operator yang tepat. Artinya "jadwalkancountuntuk menerima nilai barunya di akhir langkah waktu", persis seperti perilaku flip-flop. Alasannya dan alternatifnya ada di Blocking vs Non-blocking. - Tidak perlu
default.if-nya sudah mencakup kedua cabang (reset dan bukan reset). Tidak ada risiko latch.
Synthesizer melihat bentuk ini (sensitivity dengan clock, penugasan non-blocking) dan menghasilkan register 4-bit (empat flip-flop), ditambah logika kombinasional yang menghitung count + 1 dan mux yang memilih antara reset dan penambahan.
Perbedaan di Sintesis
Sumber module yang sama bisa menggambarkan dua hardware yang sama sekali berbeda, tergantung bentuk blok always-nya:
| Blok | Hardware |
|---|---|
always @(*) y = expr; | Logika kombinasional murni. Tanpa memori. |
always @(posedge clk) y <= expr; | Flip-flop. Menangkap expr sekali per siklus clock. |
always @(*) if (en) y = expr; | Latch: biasanya bug. Kasus "else" menahan nilai lama. |
always @(posedge clk) if (en) y <= expr; | Flip-flop dengan enable. Hanya menangkap saat en bernilai high. |
Kasus ketiga adalah jebakan latch. Latch adalah sel memori transparan yang menahan output-nya saat input-nya tidak aktif: berguna di desain tertentu, tapi hampir selalu bug kalau muncul tanpa sengaja. Kebanyakan tool sintesis memberi peringatan keras saat menyimpulkan latch yang tidak kamu minta. Perlakukan peringatan itu sebagai error.
Variasi Sensitivity List
Kamu akan melihat beberapa sensitivity list yang kurang umum:
always @(a or b or c): daftar eksplisit. Verilog-2001 menambahkan pemisah,:always @(a, b, c). Keduanya bisa dipakai.always @(posedge clk or negedge reset_n): reset asinkron. Blok berjalan di tepi naik clock atau di tepi turun reset. Dipakai saat reset harus langsung berlaku, tanpa menunggu clock berikutnya.always @(negedge clk): clock di tepi turun. Jarang; beberapa desain memakainya untuk flip-flop "negative-edge-triggered" yang menangkap di tepi turun, bukan tepi naik.
Untuk desain baru, utamakan always @(*) untuk kombinasional dan always @(posedge clk) untuk sekuensial. Pakai reset asinkron hanya kalau desainnya memang benar-benar membutuhkannya.
Dua Blok Adalah Dua Potong Hardware
Beberapa blok always di module yang sama saling independen: masing-masing menjadi potongan hardware tersendiri:
Blok yang dikendalikan clock menghasilkan register flip-flop. Blok kombinasional menghasilkan gerbang XOR. Keduanya berdampingan; tidak ada yang tahu tentang yang lain. Kedua output berubah dengan jadwal yang sama sekali berbeda.
Yang Tidak Bisa Dilakukan Blok always
Beberapa hal yang terlihat menggoda tapi tidak diperbolehkan:
- Memberi nilai ke
wire: targetnya harusreg. Compiler menegakkan aturan ini. - Memberi nilai ke
regyang sama dari dua blokalwaysyang berbeda: menghasilkan perilaku tak terdefinisi di simulasi dan tidak bisa disintesis. Satu penggerak untuk setiap sinyal. - Membaca dan menulis sinyal yang sama di blok kombinasional yang sama dengan cara yang menciptakan loop umpan balik:
always @(*) x = x + 1;adalah loop tanpa delay yang tidak bisa diselesaikan simulator.
Dua yang pertama ditangkap compiler. Yang ketiga kadang baru terlihat saat simulasi, dalam bentuk simulasi yang macet.
Selanjutnya
Dokumen berikutnya, Blok Initial, membahas saudara dari always: blok yang berjalan tepat satu kali di awal simulasi. Ini andalan utama testbench. Setelah itu, aturan penugasan blocking vs non-blocking yang menentukan apakah blok yang dikendalikan clock-mu bekerja seperti yang kamu maksud.
Pertanyaan yang sering diajukan
Apa itu blok always di Verilog?
always membuka blok prosedural yang berjalan ulang setiap kali sinyal di sensitivity list-nya berubah. Ada dua jenis: always @(*) membangun logika kombinasional (berjalan ulang setiap kali ada input yang berubah), dan always @(posedge clk) membangun logika sekuensial (berjalan ulang di setiap tepi naik clk). Isi blok always bisa berisi if, case, for, dan penugasan prosedural.
Apa perbedaan always @(*) dan always @(posedge clk)?
always @(*) peka terhadap sinyal apa pun yang dibaca di dalam blok; hasilnya logika kombinasional tanpa memori. always @(posedge clk) hanya peka terhadap tepi naik clk; hasilnya flip-flop yang menangkap state sekali per siklus clock. Yang pertama tidak punya clock dan register; yang kedua punya keduanya.
Apa itu sensitivity list di Verilog?
Daftar sinyal setelah @ yang menentukan kapan blok always berjalan ulang. @(*) adalah singkatan untuk 'setiap sinyal yang dibaca di dalam blok'. @(posedge clk) hanya berjalan di tepi naik clk. @(posedge clk or negedge reset_n) berjalan di salah satu dari kedua event itu, dan dipakai untuk reset asinkron. Salah menulis sensitivity list adalah salah satu penyebab paling umum hasil simulasi dan sintesis yang tidak cocok.
Bisakah memberi nilai ke wire di dalam blok always?
Tidak. Blok always hanya bisa memberi nilai ke reg (atau logic di SystemVerilog). Compiler menegakkan aturan ini. Kalau kamu ingin sebuah wire menjadi output dari logika prosedural, deklarasikan reg perantara, gerakkan di dalam always, lalu assign wire tersebut dari reg itu di luar blok. Atau cukup ubah wire itu menjadi reg.