Menerapkan Logika Sekuensial Menggunakan Blok 'always' Verilog
Sebuah artikel sebelumnya menunjukkan berbagai contoh penggunaan blok always untuk mengimplementasikan logika kombinasi. Blok always juga terutama digunakan untuk mengimplementasikan logika sekuensial yang memiliki elemen memori seperti flip flop yang dapat menahan nilai.
JK Flip Flop
Flip flop JK adalah salah satu banyak jenis flop yang digunakan untuk menyimpan nilai dan memiliki dua input data j dan k beserta satu untuk reset rstn dan satu lagi untuk clock clk. Tabel kebenaran untuk flip flop JK ditunjukkan di bawah ini dan biasanya diimplementasikan menggunakan gerbang NAND.
rstn
j
k
q
Komentar
0
0
0
0
Saat reset diaktifkan, output selalu nol
1
0
0
Tetapkan nilai
Saat baik j dan k adalah 0, output tetap sama seperti sebelumnya
1
0
1
1
Saat k=1, output menjadi 1
1
1
0
0
Saat k=0, output menjadi 0
1
1
1
Balikan nilai
Saat j=1,k=1 output membalik nilai saat ini
Kode Verilog behavior untuk flip-flop JK dapat ditulis seperti yang ditunjukkan di bawah ini
module jk_ff ( input j, // Input J input k, // Input K input rstn, // Active-low async reset input clk, // Input clk output reg q); // Output Q always @ (posedge clk or negedge rstn) begin if (!rstn) begin q <= 0; end else begin q <= (j & ~q) | (~k & q); end end endmodule
Testbench
Pertama deklarasikan semua variabel yang digunakan dalam testbench dan mulai jam menggunakan blok always sederhana yang dapat didorong ke desain. Kemudian inisialisasikan desain dan hubungkan portnya dengan variabel testbench yang sesuai. Perhatikan bahwa q bertipe wire karena terhubung ke output desain yang akan menggerakkannya secara aktif. Semua input lainnya ke desain bertipe reg sehingga dapat dijalankan dalam blok prosedural seperti initial.
Stimulus pertama menginisialisasi semua input desain ke nol dan kemudian menonaktifkan reset setelah beberapa waktu. Loop for digunakan untuk menggerakkan berbagai nilai ke j dan k yang dijalankan pada waktu acak. Setelah loop selesai, tunggu beberapa waktu lagi dan akhiri simulasi.
module tb; // Deklarasi variabel testbench reg j, k, rstn, clk; wire q; integer i; reg [2:0] dly; // Mulai jam always #10 clk = ~clk; // Instanisasi desain jk_ff u0 ( .j(j), .k(k), .clk(clk), .rstn(rstn), .q(q)); // Tulis stimulus initial begin {j, k, rstn, clk} <= 0; #10 rstn <= 1; for (i = 0; i < 10; i = i+1) begin dly = $random; #(dly) j <= $random; #(dly) k <= $random; end #20 $finish; end endmodule
Perhatikan dari gelombang simulasi bahwa pada posedge jam, output q berubah nilai berdasarkan status input j dan k seperti yang diberikan dalam tabel kebenaran.
Counter Modulo-10
Counter Modulus(MOD) hanya menghitung hingga suatu angka sebelum kembali ke nol. Counter MOD-N akan menghitung dari 0 hingga N-1 dan kemudian kembali ke nol dan mulai menghitung lagi. Counter semacam ini biasanya membutuhkan flop log2N untuk menahan nilai hitungan. Ditunjukkan di bawah ini adalah kode Verilog untuk counter MOD-10 yang terus menghitung naik pada setiap clock clk selama reset rstn dinonaktifkan.
Parameter Verilog dapat digunakan untuk membuat counter MOD-N yang lebih skalabel.
module mod10_counter ( input clk, input rstn, output reg[3:0] out); always @ (posedge clk) begin if (!rstn) begin out <= 0; end else begin if (out == 10) out <= 0; else out <= out + 1; end end endmodule
Testbench
Testbench pertama mendeklarasikan beberapa variabel yang dapat ditugaskan nilai dan didorong ke input desain. Modul counter kemudian diinstanisasi dan dihubungkan dengan sinyal testbench yang nantinya dijalankan dengan beberapa nilai dalam stimulus. Karena counter juga membutuhkan jam, jam testbench dimodelkan dengan blok always. Stimulus hanya mengatur nilai default pada waktu 0ns, kemudian menonaktifkan reset setelah 10ns dan desain diizinkan berjalan selama beberapa waktu.
Lihat bahwa modul counter menghitung dari nol hingga 9, kembali ke nol dan mulai menghitung lagi.
Register Geser Kiri 4bit
Ditunjukkan di bawah ini adalah register geser kiri 4-bit yang menerima input d ke LSB dan semua bit lainnya akan digeser ke kiri sebesar 1. Misalnya, jika d sama dengan nol dan nilai awal register adalah 0011, maka akan menjadi 0110 pada tepi berikutnya dari jam clk.
module lshift_4b_reg ( input d, input clk, input rstn, output reg [3:0] out ); always @ (posedge clk) begin if (!rstn) begin out <= 0; end else begin out <= {out[2:0], d}; end end endmodule
Testbench
Testbench mengikuti templat yang sama seperti yang ditunjukkan sebelumnya di mana beberapa variabel dideklarasikan, modul desain diinstanisasi dan dihubungkan dengan sinyal testbench. Kemudian jam dimulai dan stimulus dijalankan ke desain menggunakan blok initial. Dalam contoh testbench ini, berbagai nilai d harus dijalankan dan oleh karena itu loop for digunakan untuk mengulang 20 kali dan menerapkan nilai acak ke desain.
module tb; reg clk, rstn, d; wire [3:0] out; integer i; lshift_4b_reg u0 ( .d(d), .clk(clk), .rstn(rstn), .out(out)); always #10 clk = ~clk; initial begin {clk, rstn, d} <= 0; #10 rstn <= 1; for (i = 0; i < 20; i=i+1) begin @(posedge clk) d <= $random; end #10 $finish; end endmodule
Perhatikan bahwa setiap bit digeser ke kiri sebesar 1 dan nilai baru d diterapkan ke LSB.