Menggunakan Prosedur dalam VHDL: Sederhanakan Desain dengan Kode yang Dapat Digunakan Kembali
Dalam VHDL, prosedur adalah subprogram yang memungkinkan desainer menghindari blok kode berulang. Jika operasi yang sama dibutuhkan di beberapa tempat, membuat modul lengkap bisa berlebihan. Sebuah prosedur menawarkan solusi yang ringan dan dapat digunakan kembali.
Prosedur dapat dideklarasikan di setiap wilayah deklaratif—arsitektur, paket, atau proses—dan cakupannya terbatas pada wilayah tersebut. Ketika dipanggil, tubuh prosedur dieksekusi seolah-olah kodenya ditulis di tempat, memberikan Anda manfaat modularitas tanpa overhead dari komponen terpisah.
Berbeda dengan fungsi, prosedur tidak mengembalikan nilai secara langsung. Namun, Anda dapat mengirimkan nilai kembali dengan mendeklarasikan sinyal out atau inout dalam daftar parameter, sehingga secara efektif memungkinkan prosedur bertindak seperti modul kecil dengan input dan output.
Pos ini adalah bagian dari seri Tutorial VHDL Dasar.
Sintaks kanonis untuk mendefinisikan prosedur diilustrasikan di bawah ini:
procedure <procedure_name> (signal|variable|constant <name1> : in|out|inout <type>; signal|variable|constant <name2> : in|out|inout <type>; ... ) is <declarations_for_use_within_the_procedure> begin <code_performed_by_the_procedure_here> end procedure;
Daftar parameter mendefinisikan input dan output prosedur—seperti mini-modul. Parameter dapat berupa sinyal, variabel, atau konstanta. Di dalam prosedur Anda dapat mendeklarasikan objek tambahan (konstanta, variabel, tipe, subtype, alias) yang hanya valid dalam blok tersebut; sinyal tidak dapat dideklarasikan secara lokal.
Karena prosedur dapat berisi pernyataan wait, mereka sangat berguna dalam testbench—misalnya, sebagai driver BFM sederhana atau untuk memeriksa output DUT.
Latihan
Dalam tutorial sebelumnya, modul timer dibangun menggunakan pernyataan if-then-else yang sangat bersarang. Setiap tingkat bersamaan menambah kompleksitas dan mengurangi keterbacaan, meskipun operasi yang sama dilakukan pada himpunan sinyal yang berbeda. Pendekatan yang lebih baik adalah mengenkapsulasi logika berulang dalam prosedur.
Tutorial video berikutnya memandu Anda dalam membuat prosedur VHDL:
Contoh: Timer Berbasis Prosedur
Kode testbench tetap tidak berubah, kecuali penambahan pemanggilan prosedur untuk mendorong DUT:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T19_ProcedureTb is end entity; architecture sim of T19_ProcedureTb is constant ClockFrequencyHz : integer := 10; -- 10 Hz constant ClockPeriod : time := 1000 ms / ClockFrequencyHz; signal Clk : std_logic := '1'; signal nRst : std_logic := '0'; signal Seconds : integer; signal Minutes : integer; signal Hours : integer; begin i_Timer : entity work.T19_Timer(rtl) generic map(ClockFrequencyHz => ClockFrequencyHz) port map ( Clk => Clk, nRst => nRst, Seconds => Seconds, Minutes => Minutes, Hours => Hours); Clk <= not Clk after ClockPeriod / 2; process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); nRst <= '1'; wait; end process; end architecture;
Modul timer itu sendiri sekarang memanfaatkan prosedur untuk penambahan penghitung:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T19_Timer is generic(ClockFrequencyHz : integer); port( Clk : in std_logic; nRst : in std_logic; -- Reset negatif Seconds : inout integer; Minutes : inout integer; Hours : inout integer); end entity; architecture rtl of T19_Timer is signal Ticks : integer; procedure IncrementWrap( signal Counter : inout integer; constant WrapValue : in integer; constant Enable : in boolean; variable Wrapped : out boolean) is begin Wrapped := false; if Enable then if Counter = WrapValue - 1 then Wrapped := true; Counter <= 0; else Counter <= Counter + 1; end if; end if; end procedure; begin process(Clk) is variable Wrap : boolean; begin if rising_edge(Clk) then if nRst = '0' then Ticks <= 0; Seconds <= 0; Minutes <= 0; Hours <= 0; else IncrementWrap(Ticks, ClockFrequencyHz, true, Wrap); IncrementWrap(Seconds, 60, Wrap, Wrap); IncrementWrap(Minutes, 60, Wrap, Wrap); IncrementWrap(Hours, 24, Wrap, Wrap); end if; end if; end process; end architecture;
Gelombang di bawah ini memastikan bahwa penghitung menit berputar dengan benar ketika timer mencapai 60 menit:
Analisis
Dari gelombang kita melihat bahwa fungsionalitas pengulangan berperilaku sama dengan implementasi nested-if asli. Perubahan hanya struktural—tidak ada perubahan pada logika dasar.
Parameter pertama, Counter, adalah sinyal inout, yang memungkinkan prosedur untuk membaca dan memperbarui nilainya. Parameter kedua dan ketiga, WrapValue dan Enable, adalah konstanta; mereka diperlakukan sebagai konstanta waktu kompilasi di dalam prosedur.
Parameter terakhir, Wrapped, adalah variable yang dideklarasikan sebagai out. Ini berfungsi sebagai nilai pengembalian pseudo, menunjukkan apakah penghitung berputar selama panggilan tersebut.
Dalam proses utama, empat panggilan berturut-turut ke IncrementWrap merangkai penghitung. Variabel Wrap dari panggilan sebelumnya menjadi input Enable panggilan berikutnya. Penggunaan variabel sangat penting di sini karena pembaruan sinyal hanya terlihat setelah proses ditangguhkan; variabel memberikan aliran data prosedural segera.
Kesimpulan
Prosedur bertindak sebagai subprogram yang dapat digunakan kembali, menghindari kode duplikat.
Parameter dapat berupa sinyal, variabel, atau konstanta, menawarkan fleksibilitas.
Berbeda dengan fungsi, prosedur dapat berisi pernyataan wait, membuatnya ideal untuk driver testbench.