Menu

Finite State Machine di Verilog: Pola FSM Standar

Cara menulis FSM Verilog seperti para profesional: register state yang dikendalikan clock, blok next-state yang kombinasional, dan pemisahan rapi yang mudah dibaca dan disintesis.

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

Apa Itu FSM

Finite state machine adalah kontroler yang:

  • Memegang salah satu dari sekumpulan state bernama yang tetap pada waktu kapan pun.
  • Berpindah antar-state berdasarkan input (dan mungkin state saat ini).
  • Menghasilkan output yang bergantung pada state saat ini (dan mungkin input saat ini).

Itu mencakup bagian desain digital yang luasnya mengejutkan: kontroler lampu lalu lintas, transmitter UART, kontroler memori, penangan protokol jaringan, decoder instruksi, apa pun yang punya mode operasi yang terpisah-pisah.

Yang membuat FSM terasa berbeda dari logika jalur data adalah isinya berupa state, bukan nilai. Counter berjalan melewati 1, 2, 3, 4. FSM berjalan melewati IDLE, FETCHING, BUSY, DONE: bentuknya sama, tapi state-nya punya nama dan transisinya punya makna.

Pola Dua Proses

FSM Verilog yang standar memakai dua blok always:

  1. Blok yang dikendalikan clock yang menangkap register state di setiap tepi clock. Memakai penugasan non-blocking. Ukurannya kecil, biasanya tiga baris.
  2. Blok kombinasional yang memakai case pada state saat ini untuk menghitung state berikutnya dan output. Memakai penugasan blocking. Kode yang "menarik" ada di sini.

Pemisahan ini punya tiga manfaat: memaksamu memikirkan state secara eksplisit, menghasilkan hardware yang dengan rapi menjadi "satu register ditambah satu blok kombinasional", dan menjadi standar, sehingga siapa pun yang membaca kode Verilog-mu langsung mengenalinya.

Contoh Lengkap: Detektor Urutan

FSM klasik untuk belajar: mendeteksi urutan bit 1011 di sebuah input serial. Keluarkan pulsa selama satu siklus saat urutannya lengkap.

Struktur dua bloknya sesuai dengan poin-poin di atas. Ada beberapa detail kerapian yang patut ditunjukkan:

  • Nilai default di awal blok kombinasional. next_state = state (tetap di tempat) dan detected = 1'b0 (tanpa pulsa) adalah penugasan "tidak melakukan apa-apa". Setiap cabang case lalu hanya mengatur hal yang berbeda. Ini membuat latch mustahil tersimpulkan.
  • localparam untuk nama state. Siapa pun yang membaca module ini berpikir dalam S0, S1, S2, S3, bukan dalam 3'd0, 3'd1. Synthesizer yang melakukan penggantiannya.
  • Tidak ada output dari blok yang dikendalikan clock. Semua logika "apa yang dilakukan state ini" berada di blok kombinasional. Blok yang dikendalikan clock tidak bertanggung jawab atas apa pun selain memegang state saat ini.

Moore vs Mealy

Moore: output hanya bergantung pada state saat ini. Mealy: output bergantung pada state saat ini dan input saat ini.

Di contoh di atas, detected diatur di dalam cabang S3 hanya saat in cocok dengan salah satu pola yang melengkapi urutan. Itu output Mealy: ia bergantung pada in selain pada state. Versi Moore akan punya state tersendiri untuk "baru saja terdeteksi" dan mengatur detected = 1 setiap kali state itu aktif; output-nya akan muncul satu siklus lebih lambat, tapi tidak pernah terpengaruh glitch di in.

Kedua gaya sama-sama sah. Moore menjadi default di buku teks karena output-nya dijamin tidak mengalami glitch saat input berubah di tengah siklus. Mealy lebih cepat (tanpa latensi register untuk output yang digerakkan input) dan dalam banyak kasus menghasilkan hardware yang lebih kecil. Pilih berdasarkan protokol yang sedang kamu implementasikan.

Encoding State: Biner, One-Hot, Gray

Pola bit yang kamu berikan ke setiap state berpengaruh pada luas area dan kecepatan:

  • Biner (S0 = 3'd0, S1 = 3'd1, ...): register state paling kecil, ⌈log⁡2N⌉\lceil \log_2 N \rceil bit untuk NN state. Logika dekodenya paling banyak.
  • One-hot (S0 = 4'b0001, S1 = 4'b0010, ...): N bit untuk N state. Logika dekodenya sangat sederhana (setiap state adalah satu kabel); transisinya cepat. FPGA sering memakai ini secara default.
  • Gray code: state yang berurutan hanya berbeda satu bit. Berguna saat bit-bit state melintasi clock domain.

Kebanyakan tool sintesis modern memilih encoding untukmu (Vivado, Quartus, dan Design Compiler semuanya punya mode otomatis yang mencoba setiap encoding lalu memilih yang terbaik). Kamu jarang perlu menentukannya. Kalau perlu, kebanyakan tool menerima anotasi attribute atau pragma (* fsm_encoding = "one_hot" *).

Varian Tiga Blok

Sesekali kamu akan melihat FSM yang dipecah menjadi tiga: satu blok yang dikendalikan clock untuk state, satu blok kombinasional untuk next-state, satu blok kombinasional untuk output. Itu hanyalah pola dua blok dengan perhitungan output yang dipindahkan ke bloknya sendiri:

// State register
always @(posedge clk) ...

// Next-state logic
always @(*) ...

// Output logic
always @(*) begin
    case (state)
        ...
    endcase
end

Gaya output terpisah ini berguna saat output-nya banyak dan logika next-state akan jadi berantakan kalau keduanya ada di blok yang sama. Untuk FSM kecil, ini berlebihan.

Fungsi default di FSM

Setiap pernyataan case di FSM sebaiknya punya cabang default. Dua alasannya:

  1. Keamanan: kalau register state entah bagaimana menerima nilai yang tidak valid (korupsi, bug, reset sebagian), default mengembalikannya ke state yang jelas.
  2. Petunjuk untuk sintesis: saat case eksplisitnya sudah lengkap (misalnya state 2-bit dengan keempat nilai ditangani), default: next_state = 'x; memberi tahu synthesizer "aku jamin default-nya tidak terjangkau, optimalkan sesukamu". Kalau jalur yang tidak terjangkau itu ternyata tercapai di simulasi, x yang dihasilkan akan menyebar dan langsung menampakkan bug-nya.
default: begin
    next_state = S0;   // safe recovery
    // or
    next_state = 'x;   // unreachable, optimize freely
end

Pilih berdasarkan apakah kamu sudah membuktikan default-nya benar-benar tidak terjangkau.

Hal yang Perlu Diwaspadai

Lupa nilai default di awal blok kombinasional. Tanpa next_state = state dan default untuk output, cabang yang tidak memberi nilai ke semua sinyal akan memunculkan latch.

Menaruh output di blok yang dikendalikan clock. Kalau detected <= 1 ada di blok always @(posedge clk), output-nya menjadi registered: ia muncul satu siklus terlambat. Itu bisa disengaja (output "Mealy registered"), tapi sering menjadi kesalahan desain yang tidak disengaja saat spesifikasinya meminta pulsa seketika.

Mencampur blocking dan non-blocking. Blok yang dikendalikan clock: <=. Blok kombinasional: =. Mencampur keduanya dalam satu blok adalah race condition.

Blok always kombinasional yang merujuk next_state dan memberi nilai ke state. Itu membangun loop umpan balik yang tidak bisa diselesaikan simulator. Blok yang dikendalikan clock memiliki state; blok kombinasional memiliki next_state; jangan biarkan salah satunya menyentuh variabel milik yang lain.

Selanjutnya

Sekarang kamu bisa membangun kontroler apa pun yang bisa kamu gambarkan. Bab berikutnya mundur selangkah dari desain yang bisa disintesis dan membahas testbench yang mengujinya: cara menggerakkan stimulus, mengamati output, menyimpan waveform, dan memastikan module-mu benar-benar melakukan apa yang kamu kira.

Pertanyaan yang sering diajukan

Apa itu finite state machine di Verilog?

FSM adalah kontroler yang memegang salah satu dari sekumpulan kecil state bernama dan berpindah di antaranya berdasarkan input. Di Verilog, implementasi standarnya punya dua blok: always yang dikendalikan clock untuk memperbarui register state di setiap tepi clock, dan always kombinasional yang menghitung state berikutnya dan output berdasarkan state saat ini dan input-nya.

Apa pola FSM standar di Verilog?

FSM dua proses: satu blok always @(posedge clk) yang dikendalikan clock memegang register state dan memakai penugasan non-blocking, dan satu blok kombinasional always @(*) memakai case pada state saat ini untuk menghitung state berikutnya dan output. Pemisahan ini membuat kodenya mudah dibaca, di-lint, dan disintesis dengan rapi.

Apa perbedaan FSM Mealy dan Moore?

Di FSM Moore, output hanya bergantung pada state saat ini. Di FSM Mealy, output bergantung pada state saat ini sekaligus input saat ini. Mesin Mealy bereaksi satu siklus lebih cepat (tanpa latensi register untuk output yang bergantung pada input), tapi bisa menghasilkan glitch kalau input berubah di tengah siklus. Mesin Moore lebih lambat satu siklus tapi lebih bisa diprediksi, dan menjadi pilihan default kecuali kamu butuh kecepatannya.

Bagaimana cara melakukan encoding state di Verilog?

Pakai konstanta localparam di dalam module: localparam IDLE = 3'd0; dan seterusnya. Ada tiga encoding yang umum: biner (state 0, 1, 2, ..., register state paling kecil), one-hot (satu bit per state, lebih sedikit tingkat logika per transisi), dan gray code (state yang berurutan hanya berbeda satu bit, meminimalkan glitch). Tool sintesis biasanya memilih encoding untukmu; menentukannya sendiri jarang diperlukan.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai