Mengapa pola VHDL sederhana ini untuk register geser tidak berfungsi seperti yang diharapkan

8

Pada pandangan pertama Anda akan mengharapkan kode sumber VHDL di bawah ini berperilaku sebagai register geser. Dalam q itu, seiring waktu akan menjadi

"UUUU0", "UUU00", "UU000", "U0000", "00000", ....

tetapi sebaliknya selalu Usetelah lima (atau lebih) siklus jam berturut-turut.

Kenapa ini?

Kode ini sebenarnya adalah versi yang jauh dari simulasi yang jauh lebih rumit. Tapi itu menunjukkan gejala yang saya lihat.

Ini menunjukkan hasil yang menarik dan tidak terduga ini selama simulasi di bawah ModelSim dan ActiveHDL, saya belum mencoba simulator lain dan akan (kedua untuk penjelasan penyebabnya) ingin tahu apakah orang lain bertindak dengan cara yang sama.

Untuk menjawab pertanyaan ini dengan benar, Anda harus memahami bahwa:

  • Saya tahu ini bukan cara terbaik untuk mengimplementasikan register geser
  • Saya tahu untuk sintesis RTL ini harus memiliki reset.
  • Saya tahu array std_logic adalah std_logic_vector.
  • Saya tahu operator agregasi &,.

Apa yang saya juga temukan:

  • Jika tugas temp(0)<='0';dipindahkan dalam proses, itu berfungsi.
  • Jika loop tidak dibuka (lihat kode komentar), itu berhasil.

Saya akan menegaskan kembali bahwa ini adalah versi yang sangat disederhanakan dari desain yang jauh lebih rumit (untuk CPU pipelined), dikonfigurasi untuk murni menunjukkan hasil simulasi yang tidak terduga. Jenis sinyal yang sebenarnya hanyalah penyederhanaan. Untuk alasan ini, Anda harus mempertimbangkan jawaban Anda dengan kode dalam bentuk apa adanya.

Dugaan saya adalah bahwa pengoptimal mesin simulasi VHDL keliru (atau mungkin sesuai spesifikasi) tidak repot untuk menjalankan ekspresi di dalam loop karena tidak ada sinyal di luar perubahan, meskipun saya dapat membuktikan hal ini dengan menempatkan loop terbuka dalam satu lingkaran.

Jadi saya berharap bahwa jawaban untuk pertanyaan ini lebih berkaitan dengan standar untuk simulasi VHDL dari sintaks VHDL tidak eksplisit dan bagaimana mesin simulasi VHDL melakukan optimisasi mereka, daripada jika diberikan kode contoh adalah cara terbaik untuk melakukan sesuatu atau tidak.

Dan sekarang ke kode saya mensimulasikan:

 library ieee;
 use ieee.std_logic_1164.all;   

 entity test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
 end entity;

 architecture example of test_simple is
    type   t_temp is array(4 downto 0) of std_logic;
    signal temp : t_temp;
 begin

    temp(0) <= '0';

    p : process (clk)
    begin               
        if rising_edge(clk) then
            for i in 1 to 4 loop
                    temp(i) <= temp(i - 1);
            end loop;

            --temp(1) <= temp(0);   
            --temp(2) <= temp(1);
            --temp(3) <= temp(2);
            --temp(4) <= temp(3);
        end if;
    end process p;
    q <= temp(4);
 end architecture;

Dan bangku tes:

library ieee;
use ieee.std_logic_1164.all;

entity Bench is
end entity;

architecture tb of bench is

component test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
end component;

signal clk:std_logic:='0';
signal q:std_logic;     
signal rst:std_logic;

constant freq:real:=100.0e3;

begin                       
    clk<=not clk after 0.5 sec / freq;

    TB:process
    begin
        rst<='1';
        wait for 10 us;
        rst<='0';
        wait for 100 us;
        wait;
    end process;

     --Note: rst is not connected
    UUT:test_simple  port map (clk=>clk,q=>q) ;
end architecture;
Jason Morgan
sumber
pertama coba inisialisasi temp dalam deklarasi sinyal, saya telah menemukan simulator VHDL unik tentang di mana Anda menginisialisasi hal
Matt
Tampak bahwa simulator mengabaikan tugas bersamaan temp(0)karena tidak ada "peristiwa" yang terkait dengan konstanta literal. Menempatkan tugas di dalam processmenciptakan hubungan dengan peristiwa jam yang membuatnya bekerja. Saya ingin tahu apakah menambahkan afterklausa ke tugas akan menjadi solusi potensial.
Dave Tweed

Jawaban:

7

Ini ada hubungannya dengan apa yang dapat dengan mudah dievaluasi pada waktu elaborasi, secara formal, apa yang disebut "ekspresi statis lokal". Ini adalah aturan yang terlihat tidak jelas, tetapi perlu beberapa pemikiran - pada akhirnya itu masuk akal, dan simulator Anda cukup benar dalam mengingatkan Anda dengan menghasilkan hasil yang tidak jelas.

Sekarang, temp(1)dapat dievaluasi pada waktu kompilasi (bahkan lebih awal dari waktu elaborasi) dan dapat menghasilkan driver pada bit 1 dari "temp".

Namun, temp(i)melibatkan sedikit lebih banyak pekerjaan untuk alat. Mengingat sifat sepele dari loop terikat di sini (1 hingga 4) jelas bagi kita manusia bahwa suhu (0) tidak dapat didorong dan apa yang Anda lakukan aman. Tapi bayangkan batas-batasnya adalah fungsi-fungsi lower(foo) to upper(bar)dalam sebuah paket yang dideklarasikan di tempat lain ... sekarang yang paling bisa Anda katakan dengan pasti adalah yang tempdidorong - sehingga ekspresi "lokal statis"temp .

Dan itu berarti bahwa proses dibatasi oleh aturan-aturan ini untuk mendorong semua temp, di mana Anda memiliki beberapa driver temp(0)- proses mengemudi (tidak ada nilai awal, yaitu 'u') dan eksternal temp(0) <= '0';. Jadi secara alami kedua pembalap memutuskan untuk 'U'.

Alternatifnya adalah "aturan kecil yang macet" (pendapat) bahwa jika loop bounds adalah konstanta, lakukan satu hal, tetapi jika mereka dinyatakan sebagai sesuatu yang lain, lakukan sesuatu yang lain, dan seterusnya ... aturan kecil yang lebih aneh seperti itu ada, semakin kompleks bahasa menjadi ... menurut saya, bukan solusi yang lebih baik.

Brian Drummond
sumber
Jawaban yang bagus (+1), tapi saya tidak setuju dengan karakterisasi Anda tentang "aturan kecil yang aneh". Seluruh titik simulasi adalah untuk mewakili perilaku perangkat keras nyata. Saya memahami kendala yang dibuat oleh kompilasi independen dari masing-masing modul, tetapi saya pikir aturannya adalah bahwa apa pun yang dapat dievaluasi pada waktu kompilasi seharusnya . Ini akan menjadi aturan yang jauh lebih umum, dan akan membantu sistem mematuhi prinsip "kejutan paling tidak". Mengizinkan alat untuk tidak melakukan evaluasi itu terasa lebih "berantakan" bagi saya.
Dave Tweed
Komentar wajar - Ada misalnya memiliki (dan secara formal menyatakan) lebih banyak kerumitan tentang aturan seperti ini, dan mengelola untuk menyajikan pandangan yang jauh lebih sederhana kepada pengguna kami (tanpa faktor WTF dari C!). VHDL awalnya disederhanakan (IMO agak terlalu jauh) dari Ada. Tapi mungkin itu bisa mengadopsi aturan "ketik pembekuan" Ada yang akan memungkinkan optimasi semacam ini ketika jelas aman (seperti di sini) dan melarangnya sebaliknya ...
Brian Drummond
Terima kasih Brian, apa yang Anda katakan tentu masuk akal. Gagasan tentang satu aturan sederhana daripada banyak aturan yang tidak jelas tampaknya masuk akal juga. Apakah Anda mengatakan perilaku ini benar (dan memang ditentukan) untuk semua simulator atau hanya dua yang saya coba?
Jason Morgan
2
Jika saya menemukan satu yang melakukan sesuatu yang berbeda, saya akan mengajukan bug terhadapnya! Satu hal yang akan dikatakan oleh para pencela terbesar VHDL adalah bahwa hal itu menjamin hasil simulasi yang konsisten dalam kasus-kasus di mana bahasa lain (bukan hanya Verilog) tidak. (meskipun ya, kadang-kadang kekurangannya juga mengganggu saya!)
Brian Drummond
1
Eksperimen perbaikan cepat: jika jawaban saya benar, Anda dapat mengarahkan "temp (0) <= 'Z';" dalam prosesnya, oleh karena itu "memutus" driver phantom, dan driver eksternal akan bekerja ...
Brian Drummond