Merancang Logika Kombinasi dalam Verilog Menggunakan Pernyataan Assign Berkelanjutan
Pernyataan assign Verilog biasanya digunakan untuk menggerakkan sinyal tipe wire secara berkelanjutan dan disintesis sebagai logika kombinasi. Berikut adalah beberapa contoh desain lainnya menggunakan pernyataan assign.
Contoh #1 : Logika kombinasi sederhana
Kode yang ditunjukkan di bawah ini mengimplementasikan logika kombinasi digital sederhana yang memiliki output wire z yang dijalankan secara berkelanjutan dengan pernyataan assign untuk merealisasikan persamaan digital.
module combo ( input a, b, c, d, e, output z); assign z = ((a & b) | (c ^ d) & ~e); endmodule
Modul combo diperelaborasi ke dalam skema hardware berikut menggunakan alat sintesis dan dapat terlihat bahwa logika kombinasi diimplementasikan dengan gerbang digital.
Testbench
Testbench adalah platform untuk mensimulasikan desain untuk memastikan desain berperilaku seperti yang diharapkan. Semua kombinasi input dijalankan ke modul desain menggunakan loop for dengan pernyataan keterlambatan 10 unit waktu sehingga nilai baru diterapkan ke input setelah beberapa waktu.
module tb; // Deklarasi variabel testbench reg a, b, c, d, e; wire z; integer i; // Instanisasi desain dan hubungkan input/output desain dengan // variabel testbench combo u0 ( .a(a), .b(b), .c(c), .d(d), .e(e), .z(z)); initial begin // Pada awal waktu, inisialisasi semua input desain // ke nilai yang diketahui, dalam hal ini kita memilih 0. a <= 0; b <= 0; c <= 0; d <= 0; e <= 0; // Gunakan tugas $monitor untuk mencetak setiap perubahan sinyal ke // konsol simulasi $monitor ("a=%0b b=%0b c=%0b d=%0b e=%0b z=%0b", a, b, c, d, e, z); // Karena ada 5 input, ada 32 kombinasi input yang berbeda // Gunakan iterator "i" untuk bertambah dari 0 hingga 32 dan tetapkan nilai // ke variabel testbench sehingga menggerakkan input desain for (i = 0; i < 32; i = i + 1) begin {a, b, c, d, e} = i; #10; end end endmodule
Modul half adder menerima dua input scalar a dan b dan menggunakan logika kombinasi untuk menugaskan output sum dan carry bit cout. Sum dijalankan oleh XOR antara a dan b sementara carry bit diperoleh oleh AND antara kedua input.
module ha ( input a, b, output sum, cout); assign sum = a ^ b; assign cout = a & b; endmodule
Testbench
module tb; // Deklarasi variabel testbench reg a, b; wire sum, cout; integer i; // Instanisasi desain dan hubungkan input/output desain dengan // variabel testbench ha u0 ( .a(a), .b(b), .sum(sum), .cout(cout)); initial begin // Pada awal waktu, inisialisasi semua input desain // ke nilai yang diketahui, dalam hal ini kita memilih 0. a <= 0; b <= 0; // Gunakan tugas $monitor untuk mencetak setiap perubahan sinyal ke // konsol simulasi $monitor("a=%0b b=%0b sum=%0b cout=%0b", a, b, sum, cout); // Karena hanya ada 2 input, ada 4 kombinasi input yang berbeda // Gunakan iterator "i" untuk bertambah dari 0 hingga 4 dan tetapkan nilai // ke variabel testbench sehingga menggerakkan input desain for (i = 0; i < 4; i = i + 1) begin {a, b} = i; #10; end end endmodule
Sebuah full adder dapat dibangun menggunakan modul half adder yang ditunjukkan di atas atau seluruh logika kombinasi dapat diterapkan seperti yang ada dengan pernyataan assign untuk menggerakkan output sum dan cout.
module fa ( input a, b, cin, output sum, cout); assign sum = (a ^ b) ^ cin; assign cout = (a & b) | ((a ^ b) & cin); endmodule
Testbench
module tb; reg a, b, cin; wire sum, cout; integer i; fa u0 ( .a(a), .b(b), .cin(cin), .sum(sum), .cout(cout)); initial begin a <= 0; b <= 0; $monitor("a=%0b b=%0b cin=%0b sum=%0b cout=%0b", a, b, cin, sum, cout); for (i = 0; i < 7; i = i + 1) begin {a, b, cin} = i; #10; end end endmodule
Multiplexer 2x1 sederhana menggunakan operator ternary untuk memutuskan input mana yang harus ditugaskan ke output c. Jika sel adalah 1, output dijalankan oleh a dan jika sel adalah 0 output dijalankan oleh b.
module mux_2x1 (input a, b, sel, output c); assign c = sel ? a : b; endmodule
Testbench
module tb; // Deklarasi variabel testbench reg a, b, sel; wire c; integer i; // Instanisasi desain dan hubungkan input/output desain dengan // variabel testbench mux_2x1 u0 ( .a(a), .b(b), .sel(sel), .c(c)); initial begin // Pada awal waktu, inisialisasi semua input desain // ke nilai yang diketahui, dalam hal ini kita memilih 0. a <= 0; b <= 0; sel <= 0; $monitor("a=%0b b=%0b sel=%0b c=%0b", a, b, sel, c); for (i = 0; i < 3; i = i + 1) begin {a, b, sel} = i; #10; end end endmodule
Demultiplexer menggunakan kombinasi input sel dan f untuk menggerakkan sinyal output yang berbeda. Setiap sinyal output dijalankan oleh pernyataan assign terpisah. Perhatikan bahwa sinyal yang sama biasanya tidak direkomendasikan untuk dijalankan oleh berbagai pernyataan assign.
module demux_1x4 ( input f, input [1:0] sel, output a, b, c, d); assign a = f & ~sel[1] & ~sel[0]; assign b = f & sel[1] & ~sel[0]; assign c = f & ~sel[1] & sel[0]; assign d = f & sel[1] & sel[0]; endmodule
Testbench
module tb; // Deklarasi variabel testbench reg f; reg [1:0] sel; wire a, b, c, d; integer i; // Instanisasi desain dan hubungkan input/output desain dengan // variabel testbench demux_1x4 u0 ( .f(f), .sel(sel), .a(a), .b(b), .c(c), .d(d)); // Pada awal waktu, inisialisasi semua input desain // ke nilai yang diketahui, dalam hal ini kita memilih 0. initial begin f <= 0; sel <= 0; $monitor("f=%0b sel=%0b a=%0b b=%0b c=%0b d=%0b", f, sel, a, b, c, d); // Karena ada 3 input, ada 8 kombinasi input yang berbeda // Gunakan iterator "i" untuk bertambah dari 0 hingga 8 dan tetapkan nilai // ke variabel testbench sehingga menggerakkan input desain for (i = 0; i < 8; i = i + 1) begin {f, sel} = i; #10; end end endmodule
module dec_3x8 ( input en, input [3:0] in, output [15:0] out); assign out = en ? 1 << in: 0; endmodule
Testbench
module tb; reg en; reg [3:0] in; wire [15:0] out; integer i; dec_3x8 u0 ( .en(en), .in(in), .out(out)); initial begin en <= 0; in <= 0; $monitor("en=%0b in=0x%0h out=0x%0h", en, in, out); for (i = 0; i < 32; i = i + 1) begin {en, in} = i; #10; end end endmodule