Bagaimana saya bisa menentukan sinyal "tidak peduli" dalam VHDL?

11

Dalam kursus Desain Logika kita semua belajar bahwa adalah mungkin untuk meminimalkan fungsi logika, misalnya dengan menggunakan peta Karnaugh atau algoritma Quine-McCluskey . Kami juga belajar bahwa nilai "Tidak Peduli" meningkatkan potensi minimalisasi.

Misalnya mengambil file register. The write_addressdan write_datasinyal tidak terlalu penting ketika write_enablesinyal '0'. Dengan demikian, mereka harus diberi nilai "Jangan Peduli" untuk memungkinkan lebih banyak optimasi dalam logika yang menggerakkan sinyal-sinyal ini (yaitu tidak dalam file register itu sendiri).

Apa cara yang benar untuk menentukan nilai "Tidak Peduli" dalam VHDL untuk memungkinkan alat sintesis lebih banyak ruang untuk kemungkinan optimasi?


Sejauh ini saya telah menemukan hal-hal berikut yang mungkin cocok. Tapi saya tidak begitu yakin apa pro dan kontra dari setiap pendekatan:

  • Sama sekali tidak menetapkan sinyal. Sepertinya ini bisa berhasil. Namun saya menemukan bahwa itu tidak berfungsi ketika Anda ingin mendefinisikan "melakukan apa-apa yang konstan" dari beberapa recordjenis, karena catatan konstanta harus sepenuhnya ditentukan (setidaknya Modelsim mengatakan demikian).
  • The std_logic_1164paket mendefinisikan nilai '-' -- Don't careuntuk std_ulogic. Sepertinya ini adalah pilihan semantik yang benar untuk "tidak peduli" yang eksplisit, tetapi saya belum pernah melihatnya digunakan di mana pun (kecuali dalam case?konstruksi VHDL-2008 yang tidak terkait ).
  • Modelsim menggunakan nilai 'X'untuk menampilkan sinyal yang tidak ditentukan. Namun saya tidak yakin apakah alat sintesis memahami 'X'penugasan eksplisit sebagai "tidak peduli".

Berikut cuplikan kode yang disederhanakan untuk klarifikasi, tempat saya menginisialisasi sinyal tidak peduli '-'.

Seperti yang Anda lihat, sinyal control.reg_write_addressdapat memiliki 3 nilai yang berbeda: "----", instruction(11 downto 8);dan instruction(3 downto 0);. Sekarang saya berharap ini akan disintesis menjadi multiplexer 2-input jika '-'ditafsirkan sebagai "tidak peduli". Seandainya saya menginisialisasi sinyal dengan (others => '0')bukannya '-', alat harus menghasilkan multiplexer 3-input sebagai gantinya.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package mytypes is
    type control_signals_t is record
        write_enable  : std_logic;
        write_address : std_ulogic_vector(3 downto 0);
        read_address  : std_ulogic_vector(3 downto 0);
    end record;

    -- All members of this constant must be fully specified.
    -- So it's not possible to simply not assign a value.
    constant CONTROL_NOP : control_signals_t := (
        write_enable  => '0',
        write_address => (others => '-'),
        read_address  => (others => '-')
    );
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library cfx;
use cfx.mytypes.all;

entity control_unit is
    port(
        instruction : in  std_ulogic_vector(15 downto 0);
        write_data  : out std_ulogic_vector(15 downto 0);
        ctrl        : out control_signals_t
    );
end entity;

architecture rtl of control_unit is
begin
    decode_instruction : process(instruction) is
    begin
        -- Set sensible default values that do nothing.
        -- Especially all "write_enable" signals should be '0'.
        -- Everything else is mostly irrelevant (don't care).
        ctrl       <= CONTROL_NOP;
        write_data <= (others => '-');

        if instruction(15 downto 12) = "1100" then
            -- Load 8 bit of data into the register file
            ctrl.write_enable  <= '1';
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
            ctrl.write_address <= instruction(11 downto 8);
        elsif instruction(15 downto 8) = "11111001" then
            -- Load 4 bit of data into the register file
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
            ctrl.write_address <= instruction(3 downto 0);
        elsif instruction(15 downto 8) = "10110101" then
            -- Read from the register file. Don't use the write signals at all.
            ctrl.read_address <= instruction(3 downto 0);
        end if;
    end process;
end architecture;
Fritz
sumber
Bisakah Anda menguraikan apa yang Anda coba lakukan write_addressdan write_data? Optimalisasi apa yang Anda harapkan terjadi?
fru1tbat
Saya harap contoh ini memperjelas apa yang ingin saya capai.
Fritz

Jawaban:

9

Saya akan menyerahkannya kepada ahli LRM untuk memberikan jawaban yang lebih rinci, tetapi singkatnya, pendekatan Anda harus valid - saya menjalankan tes cepat dengan versi terbaru Quartus, dan menangani '-'seperti yang seharusnya - logika yang dihasilkan dikurangi seperti yang diharapkan ketika output default '-'( 'X'berfungsi juga, by the way). Lebih lanjut tentang pendekatan yang Anda cantumkan:

  • Tidak menetapkan sinyal bukan pilihan untuk contoh Anda, tentu saja, jika Anda tidak ingin kait. Jika ini adalah proses yang sudah berjalan, Anda sedikit lebih baik, tetapi Anda masih bisa mengaktifkannya di tempat yang mungkin tidak Anda perlukan. Mungkin aku kehilangan niatmu di sini.

  • '-', seperti yang disebutkan sebelumnya, mungkin merupakan pilihan terbaik, karena alasan semantik dan praktis.

  • Tergantung pada apa yang Anda maksud dengan "undefined". 'X'secara teknis "tidak dikenal". 'U'untuk sinyal yang tidak diinisialisasi, yang ditampilkan ModelSim "X"untuk representasi hex. 'X'tampaknya bekerja, seperti yang saya sebutkan di atas.

Alternatif lain adalah melakukan optimasi sendiri dan menghapus satu kasus agar tidak diuji secara eksplisit:

if instruction(15 downto 8) = "11111001" then
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
else
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
end if;

Ini memiliki kelemahan yang signifikan (sebagian besar terkait dengan kejelasan kode), dan saya mungkin akan memilih solusi yang lebih ideal.

Secara kebetulan, '-'ini juga biasa digunakan dengan std_match(), yang saya akan pertimbangkan untuk menggunakan decoding Anda, misalnya:

if std_match(instruction(15 downto 8), "1100----") then

Meskipun pada titik itu, Anda mungkin lebih baik hanya menggunakan case?.

fru1tbat
sumber
6

Singkatnya: Ini VHDL legal dan biasanya didukung oleh alat sintesis.

Namun agak jarang melihatnya digunakan. Saya tidak tahu kenapa. Menurut saya, kode Anda adalah contoh yang baik untuk menggunakannya.

Namun ada satu kelemahan yang harus diperhatikan: pada sintesis, fungsi-fungsi yang mendorong output di mana tidak peduli yang terlibat bisa berbeda antara proses sintesis. Ini membuat sintesis kurang deterministik. Jika output yang telah didefinisikan sebagai tidak peduli digunakan (karena kesalahan), ini dapat membuat kesalahan lebih sulit ditemukan.

Dukungan alat

Setidaknya alat berikut akan menerima tidak peduli dan memanfaatkan kemungkinan optimasi:

  • Xilinx (ref .: "Panduan Pengguna XST")
  • Altera (ref .: "Gaya Coding HDL yang Disarankan")
  • Synplify (ref .: "Synplify manual manual")

Xilinx dan Altera akan memperlakukan '-'dan 'X'sebagai tidak peduli, Synplify akan memperlakukan mereka dan lebih jauh 'U'dan 'W'(lemah) tidak peduli.

Carl
sumber
1
Saya punya aplikasi lain dari kelemahan itu. Kode bekerja dalam simulasi, tetapi tidak pada FPGA, karena kode saya tampak seperti: if signal = '1' then a; else b; end if;. Sayangnya signaltidak 1atau 0tapi -. Jadi dalam simulasi, elsecabang dieksekusi, tetapi dalam perangkat keras -ternyata menjadi 1, jadi cabang yang sebenarnya dieksekusi ...
Fritz
Ya, saya punya simulasi bug pass yang sama, tetapi paling sering dalam kasus saya ada 'U's, umum di awal simulasi, yang telah digunakan mengarah ke beberapa elseblok kode yang dieksekusi. Akan luar biasa jika kondisional entah bagaimana bisa dibuat untuk diperbanyak 'U', mirip dengan perilaku ekspresi boolean bersamaan.
Carl
Setelah saya menemukan bug itu saya memastikan untuk selalu menulis sesuatu seperti if signal = '1' then output <= '1'; elsif signal='0' then output <= '0'; else output <= '-'; end if;. Dan saya menambahkan yang berikut ini ke semua register dan memori: assert not is_X(write_enable) report "we=" & str(A_write_enable) severity ERROR;dan if write_enable = '1' then assert not is_X(write_addr) report "write_addr=str(write_addr) severity ERROR; end if;. Ditambah sama untuk write_data. Bersama-sama, itu seharusnya menangkap hampir semua kesalahan ini.
Fritz
Itu cara, tapi itu terlalu bertele-tele bagi saya. Saya berharap untuk kemungkinan ini dalam bahasa VHDL.
Carl
1
Ya, VHDL sedikit bertele-tele, tapi itu hanya cara VHDL. : D Di sisi lain itu juga sangat eksplisit, dan tidak melakukan "sihir hitam" di belakang saya, yang menurut saya cukup bagus (lih. Zen Python "Eksplisit lebih baik daripada implisit").
Fritz