Perché questo semplice schema VHDL per un registro a scorrimento non funziona come previsto


8

A prima vista ti aspetteresti che il codice sorgente VHDL di seguito si comporti come un registro a scorrimento. In quel q, col tempo sarebbe

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

ma invece è sempre Udopo cinque (o più) cicli di clock consecutivi.

Perchè è questo?

Questo codice è in realtà una versione molto semplificata di una simulazione molto più complicata. Ma dimostra i sintomi che vedo.

Presenta questo risultato interessante e inaspettato durante la simulazione sia con ModelSim che con ActiveHDL, non ho provato altri simulatori e (in secondo luogo per una spiegazione della causa) mi piacerebbe sapere se altri agiscono allo stesso modo.

Per rispondere correttamente a questa domanda devi capire che:

  • So che questo non è il modo migliore per implementare un registro a turni
  • So che per la sintesi RTL questo dovrebbe avere un reset.
  • So che un array di std_logic è uno std_logic_vector.
  • So che l'operatore di aggregazione, &.

Quello che ho trovato anche:

  • Se l'assegnazione temp(0)<='0';viene spostata all'interno del processo, funziona.
  • Se il ciclo non è scartato (vedi codice commentato), funziona.

Ribadirò che questa è una versione molto semplificata di un design molto più complicato (per una CPU pipeline), configurata per mostrare puramente i risultati di simulazione imprevisti. I tipi di segnale effettivi sono solo una semplificazione. Per questo motivo devi considerare le tue risposte con il codice nel modulo così com'è.

La mia ipotesi è che l'ottimizzatore del motore di simulazione VHDL stia erroneamente (o forse secondo le specifiche) a non preoccuparsi di eseguire le espressioni all'interno del loop poiché nessun segnale esterno cambia, anche se posso confutare ciò inserendo il loop non imballato in un loop.

Quindi mi aspetto che la risposta a questa domanda abbia più a che fare con gli standard per la simulazione VHDL della sintassi VHDL esplicita e con il modo in cui i motori di simulazione VHDL eseguono le loro ottimizzazioni, piuttosto che se un esempio di codice sia il modo migliore per fare qualcosa o meno.

E ora al codice che sto simulando:

 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;

E il banco prova:

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;

prima prova a inizializzare temp nella dichiarazione del segnale, ho scoperto che i simulatori vhdl sono eccentrici su dove inizializzi le cose
Matt,

Sembrerebbe che il simulatore stia ignorando l'assegnazione concorrente temp(0)perché non ci sono "eventi" associati alla costante letterale. Inserendo il compito all'interno di processcrea un'associazione con gli eventi di clock che lo fa funzionare. Mi chiedo se l'aggiunta di una afterclausola al compito sarebbe una potenziale soluzione alternativa.
Dave Tweed,

Risposte:


7

Ha a che fare con ciò che può essere facilmente valutato in fase di elaborazione, formalmente, ciò che viene chiamato "espressione statica locale". Questa è una regola dall'aspetto oscuro, ma merita un po 'di pensiero - alla fine ha un senso, e il tuo simulatore è abbastanza corretto nell'avvertirti generando risultati non ovvi.

Ora temp(1)può essere valutato in fase di compilazione (anche prima del tempo di elaborazione) e può generare un driver sul bit 1 di "temp".

Tuttavia, temp(i)comporta un po 'più di lavoro per gli strumenti. Data la natura insignificante dei limiti del loop qui (da 1 a 4), è ovvio per noi umani che temp (0) non può essere guidato e ciò che stai facendo è sicuro. Ma immagina che i limiti fossero funzioni lower(foo) to upper(bar)in un pacchetto dichiarato da qualche altra parte ... ora il massimo che puoi dire con certezza è che tempè guidato - quindi l'espressione "localmente statica" ètemp .

Ciò significa che il processo è vincolato da queste regole per guidare tutto temp, a quel punto hai più driver attivi temp(0): il processo guida (nessun valore iniziale, cioè 'u') e l'esterno temp(0) <= '0';. Quindi, naturalmente, i due driver si risolvono in "U".

L'alternativa sarebbe una "piccola regola confusa" (opinione) secondo cui se i limiti del ciclo fossero costanti, fare una cosa, ma se fossero dichiarati come qualcos'altro, fare qualcos'altro, e così via ... più piccole regole così strane ci sono, più complessa diventa la lingua ... secondo me, non una soluzione migliore.


Buona risposta (+1), ma non sono d'accordo con la tua caratterizzazione di "piccola regola". L'intero punto della simulazione è rappresentare il comportamento dell'hardware reale. Comprendo i vincoli creati dalla compilazione indipendente di singoli moduli, ma penso che la regola dovrebbe essere che tutto ciò che può essere valutato in fase di compilazione dovrebbe essere. Questa sarebbe una regola molto più generale e aiuterebbe il sistema ad aderire al principio della "minima sorpresa". Consentire agli strumenti di non eseguire tali valutazioni mi sembra più "confuso".
Dave Tweed,

Commento onesto - Ada ad esempio ha (ed esprime formalmente) molta più complessità riguardo a regole come questa, e riesce a presentare una visione molto più semplice a noi utenti (senza il fattore WTF di C!). VHDL era originariamente semplificato (IMO un po 'troppo lontano) da Ada. Ma forse potrebbe adottare le regole di "congelamento del tipo" di Ada che consentirebbero questo tipo di ottimizzazione quando chiaramente al sicuro (come qui) e lo proibirebbero altrimenti ...
Brian Drummond,

Grazie Brian, quello che dici sicuramente ha senso. L'idea di una regola semplice piuttosto che di molte regole oscure sembra avere senso anche. Diresti che questo comportamento è vero (e anzi specificato) per tutti i simulatori o sono solo i due che ho provato?
Jason Morgan,

2
Se ne trovassi uno che ha fatto qualcosa di diverso, inoltrerei un bug! Una cosa che i maggiori detrattori di VHDL dirà a suo favore è che garantisce risultati di simulazione coerenti nei casi in cui altre lingue (non solo Verilog) non lo fanno. (anche se sì, a volte anche i suoi difetti mi infastidiscono!)
Brian Drummond,

1
Esperimento di correzione rapida: se la mia risposta è corretta, puoi guidare "temp (0) <= 'Z';" all'interno del processo, quindi "disconnettendo" il driver fantasma, e il driver esterno funzionerà ...
Brian Drummond,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.