Fungsi Verilog Dijelaskan: Sintaks, Contoh, dan Perbedaan dengan Task

目次

1. Apa itu Fungsi Verilog? (Konsep Dasar dan Peran)

Verilog HDL (Hardware Description Language) adalah bahasa deskripsi perangkat keras yang digunakan untuk merancang dan mensimulasikan sirkuit digital. Di antara fitur-fiturnya, fungsi adalah mekanisme yang memungkinkan Anda memodularisasi operasi spesifik dan membuatnya dapat digunakan kembali. Memahami fungsi Verilog tidak hanya meningkatkan keterbacaan dan pemeliharaan kode tetapi juga mengarah pada desain sirkuit yang lebih efisien. Dalam artikel ini, kami menjelaskan konsep dasar fungsi Verilog dan bagaimana mereka digunakan dalam desain dunia nyata.

Apa itu fungsi?

Sebuah fungsi Verilog adalah sebuah blok yang melakukan perhitungan atau operasi spesifik dan mengembalikan satu nilai. Dengan menggunakan fungsi, Anda dapat mengurangi kode redundan dan membuat deskripsi sirkuit Anda lebih sederhana.

Karakteristik Utama Fungsi

  • Dapat ditentukan satu atau lebih input (hanya input yang diizinkan)
  • Hanya satu output (nilai kembalian fungsi)
  • Keterlambatan waktu (misalnya, #10) tidak diizinkan
  • Fungsi harus selalu mendeskripsikan logika kombinasional
  • Fungsi didefinisikan di luar blok always dan dievaluasi segera (tidak seperti task)

Kapan Menggunakan Fungsi Verilog

Fungsi Verilog terutama digunakan dalam skenario berikut:

1. Mendeskripsikan Logika Kombinasional

Karena fungsi mengembalikan hasil segera berdasarkan input, mereka sering digunakan dalam logika kombinasional. Contoh: penjumlahan, pengurangan, enkoder, dekoder, dan operasi aritmatika lainnya.

2. Meningkatkan Kegunaan Ulang Kode

Anda dapat menghilangkan kode redundan dengan merangkum logika yang sering digunakan menjadi fungsi. Contoh: mengubah ekspresi kondisional kompleks menjadi fungsi untuk meningkatkan keterbacaan dalam modul.

3. Mengurangi Kesalahan Desain

Dengan memusatkan perhitungan atau operasi logika dalam satu fungsi, Anda dapat mengurangi kesalahan saat memodifikasi kode. Contoh: perhitungan CRC (Cyclic Redundancy Check) atau pemeriksaan paritas.

Perbedaan Antara Fungsi dan Task

Dalam Verilog, ada konstruksi lain yang disebut task. Meskipun fungsi dan task serupa, mereka berbeda dalam cara yang penting:
ItemFungsiTugas
OutputHanya satuBeberapa diizinkan
MasukanYaYa
Local VariablesDiizinkanDiizinkan
Penundaan (#10)Tidak diizinkanDiizinkan
Penggunaan di dalam alwaysDiizinkanTidak diizinkan
Invocationfunction_name(arguments)task_name(arguments);

Kapan Menggunakan Fungsi

  • Saat Anda membutuhkan hasil perhitungan segera
  • Untuk logika yang tidak termasuk keterlambatan
  • Saat satu nilai kembalian sudah cukup

Kapan Menggunakan Task

  • Saat proses termasuk keterlambatan (misalnya, #10)
  • Saat diperlukan beberapa output
  • Untuk tujuan simulasi/debug (misalnya, output log)

Ringkasan

  • Sebuah fungsi Verilog adalah sebuah fungsi yang menerima input dan mengembalikan satu nilai .
  • Ia paling cocok untuk mendeskripsikan logika kombinasional dan tidak dapat menyertakan keterlambatan.
  • Berguna untuk mengurangi kode redundan dan meningkatkan keterbacaan .
  • Fungsi dan task berbeda; memilih yang tepat tergantung pada kasus penggunaan Anda .

2. Cara Menulis Fungsi Verilog [Beginner-Friendly Example]

Dalam bagian sebelumnya, kami membahas konsep dasar fungsi Verilog. Di sini, kami akan membahas sintaks sebenarnya dan cara menulis fungsi Verilog dalam praktik.

Sintaks Dasar Fungsi

Sebuah fungsi Verilog ditulis menggunakan sintaks umum berikut:
function [output_bit_width] function_name;
    input [input_bit_width] input1, input2, ...;
    begin
        function_name = expression;
    end
endfunction

Poin Kunci

  • Deklarasikan dengan kata kunci function
  • Nilai kembalian ditugaskan ke variabel dengan nama yang sama dengan fungsi
  • Deklarasikan input menggunakan input (Anda tidak dapat menggunakan output atau inout )
  • Lakukan perhitungan di dalam begin ... end
  • Definisikan fungsi di luar blok always

Contoh Sederhana Fungsi Verilog

Contoh berikut menunjukkan fungsi yang melakukan penjumlahan 8-bit:
module example;
    function [7:0] add_function;
        input [7:0] a, b;
        begin
            add_function = a + b;
        end
    endfunction

    reg [7:0] x, y, sum;

    initial begin
        x = 8'b00001100; // 12
        y = 8'b00000101; // 5
        sum = add_function(x, y);
        $display("Sum: %d", sum); // Sum: 17
    end
endmodule

Penjelasan

  • add_function mengambil dua masukan 8-bit ( a dan b ) dan mengembalikan jumlahnya
  • Fungsi dipanggil dengan sum = add_function(x, y); dan menugaskan hasilnya ke sum
  • Blok initial menggunakan $display untuk menampilkan hasil

Mendeklarasikan Input dan Output dalam Fungsi

Mendeklarasikan Input

Fungsi Verilog hanya dapat menerima argumen input.
function [7:0] my_function;
    input [7:0] in1, in2;
    begin
        my_function = in1 & in2; // AND operation
    end
endfunction
Catatan: Anda tidak dapat mendeklarasikan output dalam sebuah fungsi. Nilai kembali selalu variabel dengan nama yang sama dengan fungsi.

Fungsi dengan Pernyataan Kondisional

Anda juga dapat menggunakan pernyataan if atau case di dalam fungsi.
function [3:0] max_function;
    input [3:0] a, b;
    begin
        if (a > b)
            max_function = a;
        else
            max_function = b;
    end
endfunction
Fungsi ini mengembalikan nilai yang lebih besar antara a dan b.

Ringkasan

  • Fungsi Verilog didefinisikan dengan kata kunci function dan mengembalikan satu nilai
  • Hanya argumen input yang diizinkan (tidak ada output )
  • Nilai kembali ditugaskan ke variabel dengan nama yang sama dengan fungsi
  • Pernyataan if dan case dapat digunakan untuk logika kondisional

3. Cara Menggunakan Fungsi Verilog [With Practical Code Examples]

Pada bagian sebelumnya, kami mempelajari sintaks dasar dan cara menulis fungsi Verilog. Di sini, kami akan menjelaskan cara menerapkan fungsi dalam desain nyata dengan contoh praktis.

Cara Memanggil Fungsi

Fungsi Verilog dipanggil seperti penugasan variabel biasa, menggunakan format function_name(arg1, arg2, ...). Contoh berikut mendefinisikan fungsi XOR 8-bit dan menggunakannya di dalam sebuah modul:
module function_example;
    function [7:0] xor_function;
        input [7:0] a, b;
        begin
            xor_function = a ^ b;
        end
    endfunction

    reg [7:0] x, y, result;

    initial begin
        x = 8'b11001100;
        y = 8'b10101010;
        result = xor_function(x, y); // calling the function
        $display("XOR Result: %b", result); // XOR Result: 01100110
    end
endmodule

Poin Penting

  • Fungsi dipanggil dalam bentuk variable = function(arguments);
  • Dapat digunakan di dalam blok always atau initial
  • Fungsi berfungsi sebagai logika kombinatorial

Menggunakan Fungsi dalam Logika Kombinatorial

Karena fungsi Verilog selalu dievaluasi secara langsung, mereka berguna dalam membangun logika kombinatorial. Contoh berikut menunjukkan decoder 2-ke-4 yang diimplementasikan dengan sebuah fungsi:
module decoder_example;
    function [3:0] decoder;
        input [1:0] sel;
        begin
            case (sel)
                2'b00: decoder = 4'b0001;
                2'b01: decoder = 4'b0010;
                2'b10: decoder = 4'b0100;
                2'b11: decoder = 4'b1000;
                default: decoder = 4'b0000;
            endcase
        end
    endfunction

    reg [1:0] select;
    wire [3:0] decoded_output;

    assign decoded_output = decoder(select); // using the function

    initial begin
        select = 2'b01;
        #10; // add delay to observe simulation changes
        $display("Decoded Output: %b", decoded_output); // Decoded Output: 0010
    end
endmodule

Penjelasan

  • Fungsi decoder mengubah input 2-bit menjadi output decoder 4-bit
  • Menggunakan pernyataan case untuk menentukan output berdasarkan input
  • assign digunakan untuk memetakan output fungsi ke decoded_output → Fungsi ini beroperasi sebagai bagian dari logika kombinatorial

Fungsi vs. Blok Always [Comparison Table]

Baik fungsi Verilog maupun blok always digunakan untuk mendeskripsikan logika, tetapi tujuan dan pembatasannya berbeda.
ItemFungsiBlok Selalu
Lokasi DefinisiDi luar always blokDi dalam blok always
Masukaninputregwire
KeluaranHanya satu nilaiDapat memperbarui beberapa nilai
Penundaan (#10)Tidak diizinkanDiizinkan
Retensi NegaraTidak diizinkanDiizinkan
Main UsageLogika kombinasiLogika berurutan atau pemrosesan berbasis peristiwa

Panduan Utama

  • Gunakan fungsi untuk menyederhanakan operasi logika sederhana (logika kombinatorial)
  • Gunakan blok always untuk rangkaian yang menyimpan status (mis., flip-flop)
  • Jika Anda memerlukan penundaan (seperti #10), gunakan blok always alih-alih fungsi

Ringkasan: Cara Menggunakan Fungsi Verilog

✅ Panggil fungsi dengan function_name(arguments)Fungsi paling cocok untuk logika kombinatorial dan berbeda dari blok always ✅ Gunakan pernyataan case atau if untuk mendeskripsikan logika fleksibel ✅ Berguna untuk decoder, operasi aritmetika, dan lainnya

4. Aplikasi Praktis Fungsi Verilog (Desain Decoder dan ALU)

Sejauh ini, kita telah mempelajari sintaks dasar dan penggunaan fungsi Verilog. Pada bagian ini, kita akan melihat cara menerapkan fungsi dalam desain rangkaian digital nyata, menggunakan decoder dan ALU (Arithmetic Logic Units) sebagai contoh.

Implementasi Fungsi Decoder (Decoder 2-ke-4)

Decoder adalah rangkaian yang mengubah sejumlah kecil bit input menjadi jumlah bit output yang lebih besar. Sebagai contoh, decoder 2-ke-4 mengubah input 2-bit menjadi output 4-bit. Mari kita implementasikan ini menggunakan fungsi:
module decoder_example;
    function [3:0] decoder;
        input [1:0] sel;
        begin
            case (sel)
                2'b00: decoder = 4'b0001;
                2'b01: decoder = 4'b0010;
                2'b10: decoder = 4'b0100;
                2'b11: decoder = 4'b1000;
                default: decoder = 4'b0000;
            endcase
        end
    endfunction

    reg [1:0] select;
    wire [3:0] decoded_output;

    assign decoded_output = decoder(select); // using the function

    initial begin
        select = 2'b00; #10;
        $display("Decoded Output: %b", decoded_output);
        select = 2'b01; #10;
        $display("Decoded Output: %b", decoded_output);
        select = 2'b10; #10;
        $display("Decoded Output: %b", decoded_output);
        select = 2'b11; #10;
        $display("Decoded Output: %b", decoded_output);
    end
endmodule

Implementasi Fungsi ALU (Penjumlahan, Pengurangan, AND, OR)

ALU (Arithmetic Logic Unit) adalah rangkaian inti dari CPU, yang bertanggung jawab melakukan operasi aritmetika dan logika seperti penjumlahan, pengurangan, AND, dan OR. Di sini, kita merancang ALU 8-bit sederhana menggunakan fungsi Verilog:
module alu_example;
    function [7:0] alu;
        input [7:0] a, b;
        input [1:0] op; // 2-bit control signal
        begin
            case (op)
                2'b00: alu = a + b; // Addition
                2'b01: alu = a - b; // Subtraction
                2'b10: alu = a & b; // AND
                2'b11: alu = a | b; // OR
                default: alu = 8'b00000000;
            endcase
        end
    endfunction

    reg [7:0] x, y;
    reg [1:0] opcode;
    wire [7:0] result;

    assign result = alu(x, y, opcode); // using the function

    initial begin
        x = 8'b00001100; // 12
        y = 8'b00000101; // 5

        opcode = 2'b00; #10;
        $display("Addition Result: %d", result); // 12 + 5 = 17

        opcode = 2'b01; #10;
        $display("Subtraction Result: %d", result); // 12 - 5 = 7

        opcode = 2'b10; #10;
        $display("AND Result: %b", result); // AND operation

        opcode = 2'b11; #10;
        $display("OR Result: %b", result); // OR operation
    end
endmodule

Ringkasan

Fungsi dapat digunakan secara efektif dalam rangkaian kombinasi seperti decoder dan ALUMenggunakan pernyataan case memungkinkan deskripsi operasi yang fleksibelFungsi meningkatkan keterbacaan dan membuat desain lebih dapat digunakan kembaliFungsi paling cocok untuk logika kombinasi, tetapi tidak untuk rangkaian sequential (karena tidak dapat menyertakan penundaan)

5. Pertimbangan Penting Saat Menggunakan Fungsi Verilog

Fungsi Verilog adalah alat yang kuat yang meningkatkan keterbacaan kode dan dapat digunakan kembali, tetapi mereka juga memiliki beberapa batasan. Pada bagian ini, kami akan menjelaskan poin-poin kunci yang perlu Anda ketahui saat menggunakan fungsi.

Panggilan Rekursif Tidak Diizinkan

Pada fungsi Verilog, panggilan rekursif dilarang. Ini berarti sebuah fungsi tidak dapat memanggil dirinya sendiri di dalam tubuhnya.

❌ Contoh NG: Fungsi Rekursif

function [3:0] factorial;
    input [3:0] n;
    begin
        if (n == 0)
            factorial = 1;
        else
            factorial = n * factorial(n - 1); // ❌ Recursive call not allowed
    end
endfunction
Kode ini akan menghasilkan kesalahan simulasi.

✅ Solusi: Gunakan Loop Sebagai Ganti

Jika rekursi diperlukan, gunakan loop di dalam blok always atau task sebagai gantinya.
task factorial_task;
    input [3:0] n;
    output [15:0] result;
    integer i;
    begin
        result = 1;
        for (i = 1; i <= n; i = i + 1)
            result = result * i;
    end
endtask
Dengan menggunakan loop, rekursi dapat dihindari.

Penundaan Waktu (#10) Tidak Dapat Digunakan di Dalam Fungsi

Karena fungsi Verilog dievaluasi secara langsung (berfungsi sebagai logika kombinasi), mereka tidak dapat menyertakan penundaan waktu seperti #10.

❌ Contoh NG: Penundaan di Dalam Fungsi

function [7:0] delay_function;
    input [7:0] in;
    begin
        #10; // ❌ Delay not allowed inside functions
        delay_function = in + 1;
    end
endfunction
Kode ini akan menyebabkan kesalahan kompilasi.

✅ Solusi: Gunakan Blok Always Sebagai Ganti

Jika penundaan diperlukan, gunakan blok always atau task sebagai gantinya daripada fungsi.
task delay_task;
    input [7:0] in;
    output [7:0] out;
    begin
        #10;
        out = in + 1;
    end
endtask
Singkatnya, gunakan task untuk operasi yang melibatkan penundaan.

Memilih Antara Fungsi dan Task

Pada Verilog, baik fungsi maupun task ada. Meskipun terlihat mirip, mereka memiliki kasus penggunaan yang berbeda dan harus dipilih secara tepat.
ItemFungsiTugas
KeluaranHanya satuBeberapa diizinkan
Masukkaninputinputoutput
Local VariablesDiizinkanDiizinkan
Penundaan (#10)Tidak diizinkanDiizinkan
Penggunaan di dalam alwaysDiizinkanTidak diizinkan
Invocationfunction_name(arguments)task_name(arguments);

Kapan Menggunakan Fungsi

✅ Ketika Anda membutuhkan hasil perhitungan segera (misalnya penjumlahan, pengurangan, operasi logika) ✅ Untuk mendeskripsikan logika kombinasi tanpa penundaan ✅ Ketika hanya satu nilai kembali yang diperlukan

Kapan Menggunakan Task

✅ Ketika penundaan (#10, dll.) diperlukan ✅ Ketika beberapa output dibutuhkan ✅ Untuk operasi simulasi/debug (monitoring, display, dll.)

Fungsi Tidak Dapat Didefinisikan di Dalam Blok Always

Fungsi Verilog tidak dapat didefinisikan di dalam blok always. Fungsi harus didefinisikan di luar dan kemudian dipanggil di dalam always.

❌ Contoh NG: Mendefinisikan Fungsi di Dalam Always

always @(a or b) begin
    function [7:0] my_function; // ❌ Not allowed inside always
        input [7:0] x, y;
        begin
            my_function = x + y;
        end
    endfunction
end
Kode ini akan menghasilkan kesalahan kompilasi.

✅ Contoh yang Benar

Definisikan fungsi di luar always dan panggil di dalamnya:
function [7:0] add_function;
    input [7:0] x, y;
    begin
        add_function = x + y;
    end
endfunction

always @(a or b) begin
    result = add_function(a, b); // ✅ call the function
end

Ringkasan

Fungsi Verilog memiliki beberapa batasanTidak ada pemanggilan rekursif (gunakan loop atau task sebagai gantinya) ✅ Tidak ada penundaan (#10) (gunakan always atau task sebagai gantinya) ✅ Tidak dapat didefinisikan di dalam blok always (harus didefinisikan di luar) ✅ Hanya satu nilai kembali (gunakan task jika diperlukan beberapa output) ✅ Gunakan fungsi dan task secara tepat sesuai situasi

6. [FAQ] Pertanyaan yang Sering Diajukan tentang Fungsi Verilog

Sejauh ini, kami telah membahas dasar-dasar, penggunaan lanjutan, dan pertimbangan penting dari fungsi Verilog. Pada bagian ini, kami merangkum pertanyaan yang sering diajukan dan jawabannya tentang fungsi Verilog.

Apa perbedaan antara fungsi dan task?

Q. Apa perbedaan antara fungsi Verilog dan task? Mana yang harus saya gunakan?

A. Fungsi digunakan ketika Anda perlu “mengembalikan satu nilai secara langsung,” sementara task digunakan ketika Anda memerlukan “beberapa output atau operasi yang melibatkan penundaan.”
ItemFungsiTugas
OutputHanya satuBeberapa diizinkan
Masukaninputinputoutput
Local VariablesDiizinkanDiizinkan
Tunda (#10)Tidak diizinkanDiizinkan
Penggunaan di dalam alwaysDiizinkanTidak diizinkan
Invocationfunction_name(arguments)task_name(arguments);

Kapan Menggunakan Fungsi

✅ Ketika Anda membutuhkan hasil perhitungan segera (misalnya penjumlahan, pengurangan, operasi logika) ✅ Untuk mendeskripsikan logika kombinasi tanpa penundaan ✅ Ketika hanya satu nilai kembali yang diperlukan

Kapan Menggunakan Task

✅ Ketika Anda membutuhkan penundaan (misalnya #10) ✅ Ketika beberapa output diperlukan ✅ Ketika menulis kode debug/monitoring untuk simulasi

Apakah saya dapat menggunakan reg di dalam fungsi?

Q. Bisakah saya mendeklarasikan variabel reg di dalam fungsi?

A. Tidak, Anda tidak dapat menggunakan reg di dalam fungsi, tetapi Anda dapat menggunakan integer sebagai gantinya. Dalam fungsi Verilog, Anda tidak dapat mendeklarasikan variabel bertipe reg, tetapi Anda dapat menggunakan integer untuk perhitungan.

✅ Contoh yang Benar (Menggunakan integer)

function [7:0] multiply;
    input [3:0] a, b;
    integer temp;
    begin
        temp = a * b;
        multiply = temp;
    end
endfunction

Kapan saya harus menggunakan fungsi?

Q. Dalam situasi apa penggunaan fungsi tepat?

A. Fungsi paling cocok untuk “operasi aritmetika sederhana” dan “logika kombinasi.” Contoh di mana fungsi berguna meliputi:
  • Operasi aritmetika (penjumlahan, pengurangan, logika)
  • Decoder dan encoder
  • Perbandingan (menemukan nilai maksimum/minimum)
  • Pemeriksaan kesalahan (misalnya pemeriksaan parity)
Namun, fungsi tidak cocok untuk rangkaian sekuensial yang mencakup flip‑flop.

Apakah satu fungsi dapat memanggil fungsi lain?

Q. Bisakah fungsi Verilog memanggil fungsi lain di dalamnya?

A. Ya, sebuah fungsi dapat memanggil fungsi lain, tetapi berhati‑hati dengan ketergantungan.
function [7:0] add;
    input [7:0] a, b;
    begin
        add = a + b;
    end
endfunction

function [7:0] double_add;
    input [7:0] x, y;
    begin
        double_add = add(x, y) * 2; // calling another function
    end
endfunction

Bagaimana saya harus memilih antara fungsi dan blok always?

Q. Bagaimana saya memutuskan apakah harus menggunakan fungsi atau blok always?

A. Fungsi digunakan untuk “logika kombinasi,” sementara blok always digunakan untuk “logika sekuensial.”
ItemFungsiBlok Selalu
Penundaan (#10)Tidak diizinkanDiizinkan
Retensi StatusTidak diizinkanDiizinkan
Penggunaan UtamaLogika kombinasi (perhitungan instan)Logika berurutan (flip-flops, penghitung)
Sebagai contoh, ketika melakukan penjumlahan:

✅ Fungsi (Logika Kombinasi)

function [7:0] add;
    input [7:0] a, b;
    begin
        add = a + b;
    end
endfunction

✅ Blok Always (Logika Sekuensial)

always @(posedge clk) begin
    sum <= a + b; // works as a flip-flop
end

Ringkasan

Fungsi paling cocok untuk operasi sederhana dan logika kombinasiPahami perbedaan antara fungsi dan task serta gunakan secara tepatBlok always untuk logika sekuensial, fungsi untuk logika kombinasiFungsi tidak dapat menyertakan penundaan (#10) atau array — gunakan task atau modul sebagai gantinya