Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Industrial programming >> VHDL

Cara menggunakan Fungsi Tidak Murni di VHDL

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

Pergi ke tutorial berikutnya »


VHDL

  1. Bagaimana Kami Menggunakan Molibdenum?
  2. Cara membuat daftar string di VHDL
  3. Bagaimana menghentikan simulasi di testbench VHDL
  4. Cara membuat pengontrol PWM di VHDL
  5. Cara menghasilkan angka acak di VHDL
  6. Cara menggunakan Prosedur dalam Proses di VHDL
  7. Cara menggunakan Fungsi di VHDL
  8. realloc() Fungsi di C Library:Bagaimana cara menggunakannya? Sintaks &Contoh
  9. free() Fungsi di pustaka C:Bagaimana cara menggunakannya? Belajar dengan Contoh
  10. Cara Menggunakan Penggiling Pemotong