Fungsi adalah subprogram dalam VHDL yang dapat digunakan untuk mengimplementasikan algoritma yang sering digunakan. Sebuah fungsi mengambil nol atau lebih nilai input, dan selalu mengembalikan nilai. Selain nilai kembalian, yang membedakan fungsi dari prosedur adalah tidak dapat berisi pernyataan Tunggu. Ini berarti bahwa fungsi selalu menggunakan waktu simulasi nol.
Jika Anda terbiasa dengan fungsi atau metode dari bahasa pemrograman lain, fungsi VHDL seharusnya mudah dipahami. Dalam VHDL kita tidak bisa menghilangkan nilai kembalian atau mengembalikan batal, suatu fungsi selalu harus mengembalikan sesuatu dan nilai kembalian harus diberikan ke sesuatu.
Pos blog ini adalah bagian dari seri Tutorial VHDL Dasar.
Dalam VHDL, ada dua jenis fungsi, murni dan tidak murni fungsi. Bahwa suatu fungsi adalah murni berarti fungsi tersebut tidak akan diizinkan untuk mengubah atau membaca sinyal eksternal apa pun. Kita dapat yakin bahwa ketika kita memanggil fungsi murni dengan argumen tertentu, itu akan selalu mengembalikan nilai yang sama. Kami mengatakan bahwa fungsi tersebut tidak memiliki efek samping .
Sintaks untuk mendeklarasikan fungsi dalam VHDL adalah:
[pure|impure] function <function_name> (<parameter1_name> : <parameter1_type> := <default_value>;
<parameter2_name> : <parameter2_type> := <default_value>;
... ) return <return_type> is
<constant_or_variable_declaration>
begin
<code_performed_by_the_function>
return <value>
end function;
Kata kunci murni/tidak murni adalah opsional, meskipun default akan murni jika kata kunci dihilangkan. Semua parameter diperlakukan sebagai konstanta di dalam fungsi. Dengan demikian, mereka tidak dapat diubah. Nilai default adalah opsional, dan fungsi harus selalu berakhir pada return pernyataan.
Fungsi memiliki wilayah deklaratifnya sendiri di antara in dan begin kata kunci. Konstanta, sinyal, atau variabel yang dideklarasikan di sini hanya valid di dalam fungsi itu sendiri, dan tidak akan mempertahankan nilainya melalui panggilan berikutnya ke fungsi tersebut.
Olahraga
Dalam tutorial ini, kita akan fokus pada fungsi murni, fungsi tidak murni akan dibahas dalam tutorial selanjutnya dalam seri ini.
Pada tutorial sebelumnya, kami membuat modul pengontrol lampu lalu lintas menggunakan finite-state machine (FSM). Kami menyalin-menempelkan banyak baris yang berisi penghitungan penghitung waktu dari satu keadaan ke keadaan lain, hanya mengubah satu konstanta sedikit.
Cari tahu bagaimana Anda dapat menyederhanakan kode mesin status dengan menggunakan fungsi:
Kode terakhir untuk fungsi testbench :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T21_FunctionTb is
end entity;
architecture sim of T21_FunctionTb is
-- We are using a low clock frequency to speed up the simulation
constant ClockFrequencyHz : integer := 100; -- 100 Hz
constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
signal Clk : std_logic := '1';
signal nRst : std_logic := '0';
signal NorthRed : std_logic;
signal NorthYellow : std_logic;
signal NorthGreen : std_logic;
signal WestRed : std_logic;
signal WestYellow : std_logic;
signal WestGreen : std_logic;
begin
-- The Device Under Test (DUT)
i_TrafficLights : entity work.T21_TrafficLights(rtl)
generic map(ClockFrequencyHz => ClockFrequencyHz)
port map (
Clk => Clk,
nRst => nRst,
NorthRed => NorthRed,
NorthYellow => NorthYellow,
NorthGreen => NorthGreen,
WestRed => WestRed,
WestYellow => WestYellow,
WestGreen => WestGreen);
-- Process for generating clock
Clk <= not Clk after ClockPeriod / 2;
-- Testbench sequence
process is
begin
wait until rising_edge(Clk);
wait until rising_edge(Clk);
-- Take the DUT out of reset
nRst <= '1';
wait;
end process;
end architecture;
Kode terakhir untuk modul lampu lalu lintas :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T21_TrafficLights is
generic(ClockFrequencyHz : natural);
port(
Clk : in std_logic;
nRst : in std_logic; -- Negative reset
NorthRed : out std_logic;
NorthYellow : out std_logic;
NorthGreen : out std_logic;
WestRed : out std_logic;
WestYellow : out std_logic;
WestGreen : out std_logic);
end entity;
architecture rtl of T21_TrafficLights is
-- Enumerated type declaration and state signal declaration
type t_State is (NorthNext, StartNorth, North, StopNorth,
WestNext, StartWest, West, StopWest);
signal State : t_State;
-- Calculate the number of clock cycles in minutes/seconds
function CounterVal(Minutes : integer := 0;
Seconds : integer := 0) return integer is
variable TotalSeconds : integer;
begin
TotalSeconds := Seconds + Minutes * 60;
return TotalSeconds * ClockFrequencyHz -1;
end function;
-- Counter for counting clock periods, 1 minute max
signal Counter : integer range 0 to CounterVal(Minutes => 1) +1;
begin
process(Clk) is
begin
if rising_edge(Clk) then
if nRst = '0' then
-- Reset values
NorthRed <= '1';
NorthYellow <= '0';
NorthGreen <= '0';
WestRed <= '1';
WestYellow <= '0';
WestGreen <= '0';
State <= NorthNext;
Counter <= 0;
else
-- Default values
NorthRed <= '0';
NorthYellow <= '0';
NorthGreen <= '0';
WestRed <= '0';
WestYellow <= '0';
WestGreen <= '0';
Counter <= Counter + 1;
case State is
-- Red light in all directions
when NorthNext =>
NorthRed <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if Counter = CounterVal(Seconds => 5) then
Counter <= 0;
State <= StartNorth;
end if;
-- Yellow light in north/south directions
when StartNorth =>
NorthRed <= '1';
NorthYellow <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if Counter = CounterVal(Seconds => 5) then
Counter <= 0;
State <= North;
end if;
-- Green light in north/south directions
when North =>
NorthGreen <= '1';
WestRed <= '1';
-- If 1 minute has passed
if Counter = CounterVal(Minutes => 1) then
Counter <= 0;
State <= StopNorth;
end if;
-- Red and yellow light in north/south direction
when StopNorth =>
NorthYellow <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if Counter = CounterVal(Seconds => 5) then
Counter <= 0;
State <= WestNext;
end if;
-- Red light in all directions
when WestNext =>
NorthRed <= '1';
WestRed <= '1';
-- If 5 seconds have passedf
if Counter = CounterVal(Seconds => 5) then
Counter <= 0;
State <= StartWest;
end if;
-- Yellow light in west/east direction
when StartWest =>
NorthRed <= '1';
WestRed <= '1';
WestYellow <= '1';
-- If 5 seconds have passed
if Counter = CounterVal(Seconds => 5) then
Counter <= 0;
State <= West;
end if;
-- Green light in west/east direction
when West =>
NorthRed <= '1';
WestGreen <= '1';
-- If 1 minute has passed
if Counter = CounterVal(Minutes => 1) then
Counter <= 0;
State <= StopWest;
end if;
-- Red and yellow light in west/east direction
when StopWest =>
NorthRed <= '1';
WestYellow <= '1';
-- If 5 seconds have passed
if Counter = CounterVal(Seconds => 5) then
Counter <= 0;
State <= NorthNext;
end if;
end case;
end if;
end if;
end process;
end architecture;
Bentuk gelombang setelah kita memasukkan run 5 min perintah di konsol ModelSim:
Bentuk gelombang dengan kursor ditambahkan pada transisi ke dan dari StartNorth negara:
Analisis
Kami mengganti perhitungan timer dari tutorial sebelumnya if Counter = ClockFrequencyHz * 5 -1 then dengan panggilan ke CounterVal baru fungsi yang kami buat:if Counter = CounterVal(Seconds => 5) then .
Kita dapat melihat dari tangkapan layar bentuk gelombang pertama bahwa fungsi modul tidak berubah. Menggunakan fungsi untuk tugas yang berulang adalah praktik desain yang baik. Terutama jika Anda dapat mengganti perhitungan dengan baris yang lebih mudah dibaca yang berisi istilah seperti Minutes dan Seconds .
Keuntungan lain menggunakan fungsi adalah kita dapat mengubah implementasi semua timer sekaligus, daripada melakukannya baris demi baris. Misalnya, jika kita telah menulis return TotalSeconds * ClockFrequencyHz; di CounterVal fungsi, semua timer akan bertahan satu siklus clock terlalu lama. Kami kemudian dapat mengubah ini menjadi return TotalSeconds * ClockFrequencyHz -1; di CounterVal fungsi, dan semua timer akan diperbaiki sekaligus.
Jika kita memeriksa tangkapan layar bentuk gelombang terakhir, kita dapat melihat mengapa kita perlu mengurangi 1 dari nilai timer yang dikembalikan dari CounterVal fungsi. Bentuk gelombang ini memeriksa durasi StartNorth negara, itu harus berlangsung selama tepat lima detik. Ketika State sinyal berubah menjadi StartNorth , Counter nilainya adalah 0, dan hanya berubah setelah siklus clock berikutnya. Jadi, jika kita menghitung hingga 500 siklus clock, StartNorth negara akan benar-benar berlangsung selama 501 siklus. Dengan testbench kami yang berjalan pada 100 Hz, 500 siklus clock adalah tepat lima detik.
Bawa Pulang
Fungsi dapat mengambil nol atau lebih parameter, tetapi selalu mengembalikan nilai
Fungsi tidak boleh berisi wait pernyataan
Fungsi murni tidak memiliki efek samping, sedangkan fungsi tidak murni dapat.