Menu

Penugasan Blocking vs Non-Blocking di Verilog: Kapan Memakai = vs <=

Topik yang paling sering membingungkan pemula Verilog. Arti sebenarnya dari = dan <= di dalam blok always, dan aturan yang mencegah sebagian besar race condition.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Dua Operator

Di dalam blok always dan initial, Verilog punya dua operator penugasan:

  • = adalah penugasan blocking. Perbarui LHS sekarang, sebelum lanjut ke pernyataan berikutnya.
  • <= adalah penugasan non-blocking. Evaluasi RHS sekarang, lalu jadwalkan LHS untuk diperbarui di akhir langkah waktu saat ini.

Di luar blok prosedural (di assign) hanya ada =: assign a <= b adalah syntax error. Di dalam blok prosedural, keduanya sah, dan memilih yang tepat adalah keputusan terpenting bagi pemula Verilog.

Apa yang Dilakukan Blocking

Blocking berperilaku seperti yang kamu harapkan dari bahasa software: baris demi baris, dari atas ke bawah. Pernyataan N selesai sebelum pernyataan N+1 dimulai:

Ini murni berurutan. Setiap pernyataan melihat efek dari pernyataan di atasnya. Itu sesuai dengan intuisi software.

Apa yang Dilakukan Non-Blocking

Non-blocking dibentuk mengikuti hardware. Semua sisi kanan dievaluasi memakai nilai di awal langkah waktu. Semua sisi kiri diperbarui di akhir langkah waktu. Urutan pernyataan di kode sumber tidak mengubah ketergantungan antarsinyal:

Potongan kode itu menjalankan rotasi tiga arah a → b → c → a dalam satu langkah. Dengan blocking, kamu butuh variabel sementara agar salah satunya tidak tertimpa. Dengan non-blocking, pertukarannya terjadi sekaligus karena setiap RHS membaca nilai sebelum langkah itu.

Persis seperti itulah tiga flip-flop berperilaku di tepi clock: semuanya menangkap input-nya pada saat yang sama, apa pun ketergantungan di antara mereka.

Aturan yang Menyelamatkanmu

Pakai <= di blok yang dikendalikan clock. Pakai = di blok kombinasional.

Itu saja. Hafalkan. Tulis tanpa perlu berpikir. Sebagian besar race condition, ketidakcocokan simulasi dan sintesis, serta bug "di tempatku jalan, tapi tidak setelah sintesis" berasal dari pelanggaran aturan ini.

Aturan ini punya alasan di hardware: blok yang dikendalikan clock memodelkan flip-flop yang semuanya mengambil sampel input-nya bersamaan. Blok kombinasional memodelkan logika yang merambat secepat mungkin. Semantik operator penugasannya sesuai dengan kedua perilaku itu.

Setiap <= membaca nilai register sumber saat ini dan menjadwalkan register tujuan untuk menerima nilai itu di akhir langkah waktu. Hasil akhirnya persis seperti yang dilakukan shift register di hardware: setiap flip-flop menangkap nilai tetangganya, semuanya di tepi clock yang sama, tanpa race.

Sekarang bayangkan apa yang terjadi kalau memakai penugasan blocking:

// WRONG - this is not a shift register!
always @(posedge clk) begin
    out[3] = out[2];   // out[3] becomes out[2]
    out[2] = out[1];   // out[2] becomes out[1], which we just set above
    out[1] = out[0];
    out[0] = in;
end

Setiap pernyataan menimpa sumbernya sebelum pernyataan berikutnya membacanya. Dalam satu siklus clock, in akan merambat sampai ke out[3], karena setiap baris melihat nilai yang baru saja ditulis oleh baris di atasnya. Perilaku di hardware sungguhan (yang memakai semantik non-blocking) akan sangat berbeda dari yang ditunjukkan simulator.

Blok Kombinasional: Blocking Itu Benar

Untuk always @(*), penugasan blocking adalah yang benar. Tidak ada flip-flop, tidak ada aturan penangkapan serentak yang perlu ditegakkan, dan variabel perantara berguna:

sum dihitung lebih dulu, lalu result memakai nilai yang baru saja dihitung. Logika kombinasionalnya menjadi satu potong hardware: result = ~(a + b). Tidak ada flip-flop yang muncul karena tidak ada clock.

Kalau kamu memakai <= di sini, simulator tetap akan memperbarui sum sebelum result dievaluasi terhadapnya (karena kedua pembaruan terjadi di akhir langkah), tapi urutannya akan sedikit berbeda dan banyak tool sintesis akan mengeluh. Jangan dicampur; pilih operator yang sesuai dengan jenis bloknya.

Kesalahan yang Paling Menyakitkan

Ini dia: blok yang dikendalikan clock dengan penugasan blocking.

// BUG: race condition waiting to happen
always @(posedge clk) begin
    a = b;
    b = c;
    c = a;
end

Di simulasi, simulator mungkin memproses a dulu, lalu b, lalu c, dan menghasilkan satu set nilai. Hardware akan menghasilkan set nilai yang lain, karena flip-flop sungguhan menangkap secara bersamaan. Keduanya diam-diam berbeda, dan kamu akan membuang satu hari untuk mencari bug-nya. Pakai <= di blok yang dikendalikan clock.

Kenapa Ada Dua Operator

Para perancang Verilog bisa saja memilih satu semantik penugasan dan memakainya terus. Mereka tidak melakukannya, karena bahasa ini harus memodelkan dua perilaku hardware yang berbeda:

  • Logika kombinasional: sinyal merambat terus-menerus, ketergantungan itu penting, pertanyaan "apa yang dihitung gerbang ini" masuk akal.
  • Logika sekuensial: tepi clock terjadi, setiap flip-flop menangkap secara bersamaan, ketergantungan antara input dan output flip-flop terlepas satu sama lain.

Blocking untuk yang pertama. Non-blocking untuk yang kedua. Operatornya memilih semantik; simulator mengerjakan sisanya.

Selanjutnya

Sekarang kamu punya aturan untuk menulis blok prosedural apa pun dengan benar. Bab berikutnya naik dari blok-blok tunggal ke konstruksi alur kontrol yang ada di dalamnya: if/else, case, dan loop for. Aturan blocking vs non-blocking tetap berlaku di dalam semuanya.

Pertanyaan yang sering diajukan

Apa perbedaan penugasan blocking dan non-blocking di Verilog?

Blocking (=) langsung memperbarui target sebelum pernyataan berikutnya dijalankan. Ini memodelkan eksekusi berurutan. Non-blocking (<=) menjadwalkan pembaruan di akhir langkah waktu saat ini: setiap RHS non-blocking dievaluasi memakai nilai lama dari semua sinyal, lalu setiap LHS diperbarui dalam satu langkah yang terkoordinasi. Non-blocking adalah cara flip-flop sebenarnya berperilaku.

Kapan sebaiknya memakai = dan kapan <= di Verilog?

Aturannya: pakai <= di blok always @(posedge clk) yang dikendalikan clock, dan pakai = di blok kombinasional always @(*). Satu aturan itu mencegah seluruh kelompok race condition yang muncul dari penugasan campuran. Di dalam blok initial testbench, = adalah pilihan yang biasa; <= jarang muncul di sana.

Kenapa penugasan non-blocking dibutuhkan di Verilog?

Karena flip-flop di hardware semuanya menangkap input-nya bersamaan di tepi clock. Kalau kamu memakai = (blocking) di kode yang dikendalikan clock, urutan pernyataan di file-mu akan menentukan sinyal mana yang melihat nilai baru dari sinyal lain: race condition antara simulasi dan hardware sungguhan. <= mencocokkan perilaku hardware dengan mengevaluasi semua RHS dulu, baru melakukan semua pembaruan.

Apa yang terjadi kalau = dan <= dicampur di blok always yang sama di Verilog?

Kamu mendapat race condition. Campuran itu menghasilkan hardware yang perilakunya bergantung pada cara kerja internal simulator (urutan penjadwalan event), dan lebih buruk lagi, hasil simulasinya mungkin tidak cocok dengan hasil sintesis. Kebanyakan tool lint menandainya sebagai error. Solusinya, pilih salah satu sesuai peran bloknya: non-blocking untuk yang dikendalikan clock, blocking untuk yang kombinasional.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai