Fungsi tidak murni dapat membaca atau menulis sinyal apa pun dalam cakupannya, juga sinyal yang tidak ada dalam daftar parameter. Kami mengatakan bahwa fungsi tersebut memiliki efek samping .
Yang kami maksud dengan efek samping adalah tidak ada jaminan bahwa fungsi akan mengembalikan nilai yang sama setiap kali dipanggil dengan parameter yang sama. Jika fungsi dapat membaca sinyal yang tidak ada dalam daftar parameter, nilai yang dikembalikan mungkin juga bergantung pada parameter bayangan ini. Selain itu, fungsi tersebut mungkin mengubah sinyal eksternal yang tidak ditetapkan dari nilai kembaliannya.
Pos blog ini adalah bagian dari seri Tutorial VHDL Dasar.
Meskipun kita dapat mendeklarasikan fungsi tidak murni di mana pun kita dapat mendeklarasikan fungsi yang normal dan murni, hanya masuk akal untuk menggunakannya dalam proses. Ketika dideklarasikan dalam arsitektur di mana kami biasanya mendeklarasikan sinyal kami, tidak ada sinyal yang akan berada dalam cakupannya pada waktu kompilasi. Dengan demikian, fungsi tidak murni tidak dapat melakukan lebih dari fungsi murni ketika dideklarasikan dalam arsitektur atau dalam sebuah paket.
Motivasi untuk menggunakan fungsi yang tidak murni adalah terutama untuk mendeklarasikan kode. Kita dapat memanipulasi sinyal apa pun dengan fungsi murni hanya dengan menambahkannya ke daftar parameter, tetapi jika daftar parameter menjadi terlalu panjang, itu akan mengaburkan daripada menyederhanakan.
Sintaks untuk mendeklarasikan fungsi tidak murni cukup dengan menulis impure function bukannya function saat mendeklarasikannya. Lihat tutorial fungsi untuk sintaks fungsi umum.
Olahraga
Dalam tutorial sebelumnya, kami menyederhanakan kode finite-state machine (FSM) kami dengan menggunakan fungsi untuk menghitung nilai waktu tunda. Kami menyediakan parameter Menit dan Detik untuk menentukan berapa lama kami ingin menunda setiap perubahan status.
Jika CounterVal fungsi mengembalikan true , waktunya telah habis dan sudah waktunya untuk pergi ke keadaan FSM berikutnya. Dalam proses yang sama, kami juga harus mengatur ulang Counter sinyal, jika tidak, fungsi tidak akan berfungsi di status berikutnya. Pengatur waktu sudah kedaluwarsa.
Counter sinyal akan selalu disetel ke 0 ketika fungsi kembali benar. Bukankah lebih baik jika ini terjadi di CounterVal berfungsi alih-alih beberapa tempat dalam kode mesin negara?
Di video tutorial kali ini kita akan memperbaiki kode FSM dari tutorial sebelumnya menggunakan fungsi yang tidak murni:
Kode terakhir untuk fungsi tidak murni testbench :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T22_ImpureFunctionTb is
end entity;
architecture sim of T22_ImpureFunctionTb 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.T22_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 T22_TrafficLights is
generic(ClockFrequencyHz : integer);
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 T22_TrafficLights is
-- 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;
-- Enumerated type declaration and state signal declaration
type t_State is (NorthNext, StartNorth, North, StopNorth,
WestNext, StartWest, West, StopWest);
signal State : t_State;
-- Counter for counting clock periods, 1 minute max
signal Counter : integer range 0 to ClockFrequencyHz * 60;
begin
process(Clk) is
-- This impure function reads and drives the Counter signal
-- which is not on the parameter list.
impure function CounterExpired(Minutes : integer := 0;
Seconds : integer := 0)
return boolean is
begin
if Counter = CounterVal(Minutes, Seconds) then
Counter <= 0;
return true;
else
return false;
end if;
end function;
begin
if rising_edge(Clk) then
if nRst = '0' then
-- Reset values
State <= NorthNext;
Counter <= 0;
NorthRed <= '1';
NorthYellow <= '0';
NorthGreen <= '0';
WestRed <= '1';
WestYellow <= '0';
WestGreen <= '0';
else
-- Default values
NorthRed <= '0';
NorthYellow <= '0';
NorthGreen <= '0';
WestRed <= '0';
WestYellow <= '0';
WestGreen <= '0';
Counter <= Counter + 1;
case State is
-- Red in all directions
when NorthNext =>
NorthRed <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= StartNorth;
end if;
-- Red and yellow in north/south direction
when StartNorth =>
NorthRed <= '1';
NorthYellow <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= North;
end if;
-- Green in north/south direction
when North =>
NorthGreen <= '1';
WestRed <= '1';
-- If 1 minute has passed
if CounterExpired(Minutes => 1) then
State <= StopNorth;
end if;
-- Yellow in north/south direction
when StopNorth =>
NorthYellow <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= WestNext;
end if;
-- Red in all directions
when WestNext =>
NorthRed <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= StartWest;
end if;
-- Red and yellow in west/east direction
when StartWest =>
NorthRed <= '1';
WestRed <= '1';
WestYellow <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= West;
end if;
-- Green in west/east direction
when West =>
NorthRed <= '1';
WestGreen <= '1';
-- If 1 minute has passed
if CounterExpired(Minutes => 1) then
State <= StopWest;
end if;
-- Yellow in west/east direction
when StopWest =>
NorthRed <= '1';
WestYellow <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
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:
Analisis
Seperti yang dapat kita lihat dari bentuk gelombang, keluaran modul tetap tidak berubah setelah kita menambahkan fungsi tidak murni. Kami tidak mengubah logika sama sekali, hanya kodenya saja.
Evaluasi Counter sinyal telah dipindahkan dari kode FSM ke fungsi baru yang tidak murni CounterExpired . Counter <= 0; baris untuk menghapus Counter sinyal juga telah dipindahkan ke fungsi tidak murni.
Hasilnya adalah kode FSM yang lebih mudah dibaca yang dapat lebih mudah dipelihara. Ini subjektif, tapi bagi saya CounterExpired(Seconds => 5) lebih enak dilihat daripada Counter = CounterVal(Seconds => 5) .
Seberapa jauh Anda harus menggunakan fungsi yang tidak murni sepenuhnya terserah Anda dan siapa pun yang membayar layanan Anda. Beberapa orang merasa bahwa mereka harus digunakan dengan hati-hati karena akan lebih sulit untuk melihat semua penyebab dan efek dari algoritma yang tersembunyi dalam subprogram. Orang lain, seperti saya, merasa bahwa selama Anda membuat niat Anda jelas, kode yang lebih mudah dibaca sebenarnya membuatnya kurang rawan kesalahan.
Untuk alasan ini, Anda lebih mungkin menemukan fungsi tidak murni dalam kode testbench daripada di modul produksi. Testbenches biasanya lebih kompleks daripada modul yang mereka uji, dan persyaratan untuk kebenaran kode kurang ketat daripada kode RTL.
Bawa Pulang
Fungsi tidak murni dapat membaca atau mengarahkan sinyal yang tidak ada dalam daftar parameternya
Masuk akal untuk mendeklarasikan fungsi tidak murni dalam suatu proses