Come posso specificare i segnali "non importa" in VHDL?


11

Nei corsi di Logic Design abbiamo appreso che è possibile minimizzare una funzione logica, ad esempio usando una mappa di Karnaugh o l' algoritmo Quine – McCluskey . Abbiamo anche appreso che i valori "Non preoccuparti" aumentano il potenziale di minimizzazione.

Ad esempio prendere un file di registro. I segnali write_addresse write_datanon contano davvero quando è il write_enablesegnale '0'. Pertanto, dovrebbe essere assegnato loro un valore "Non preoccuparti" per consentire ulteriori ottimizzazioni nella logica che guida questi segnali (cioè non nel file di registro stesso).

Qual è il modo corretto di specificare tali valori di "Non preoccuparti" in VHDL per consentire allo strumento di sintesi più spazio per possibili ottimizzazioni?


Finora ho trovato le seguenti cose che potrebbero essere adatte. Ma non sono davvero sicuro di quali siano i pro e i contro di ogni approccio:

  • Semplicemente non assegnare il segnale. Sembra che potrebbe funzionare. Tuttavia, ho scoperto che non funziona quando si desidera definire una "costante di non fare nulla" di un certo recordtipo, poiché le costanti dei record devono essere completamente specificate (almeno mi dice Modelsim).
  • Il std_logic_1164pacchetto definisce il valore '-' -- Don't careper std_ulogic. Sembra che sia la scelta semanticamente corretta per un esplicito "non importa", ma non l'ho mai visto usato da nessuna parte (tranne nei case?costrutti VHDL-2008 non correlati ).
  • Modelsim utilizza il valore 'X'per visualizzare segnali non definiti. Tuttavia, non sono sicuro che gli strumenti di sintesi comprendano 'X'un'assegnazione esplicita come "non importa".

Ecco uno snippet di codice semplificato per chiarimenti, in cui ho inizializzato i segnali non importa '-'.

Come si può vedere, il segnale control.reg_write_addresspuò avere 3 diversi valori: "----", instruction(11 downto 8);e instruction(3 downto 0);. Ora mi aspetto che questo sia sintetizzato in un multiplexer a 2 ingressi se '-'interpretato come "non importa". Se avessi inizializzato il segnale con (others => '0')invece di '-', lo strumento avrebbe dovuto invece generare un multiplexer a 3 ingressi.

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;

Potresti approfondire cosa stai cercando di fare con write_addresse write_data? Quale ottimizzazione ti aspetti di avere?
fru1tbat

Spero che l'esempio renda più chiaro ciò che voglio ottenere.
Fritz,

Risposte:


9

Lascerò a un esperto LRM di fornire una risposta più dettagliata, ma in breve, il tuo approccio dovrebbe essere valido - ho eseguito un test rapido con una versione recente di Quartus e gestisce '-'come dovrebbe - la logica generata è ridotta come previsto quando l'output è predefinito '-'( 'X'funziona anche, tra l'altro). Maggiori informazioni sugli approcci che hai elencato:

  • Non assegnare il segnale non è in realtà un'opzione per il tuo esempio, ovviamente, se non vuoi i latch. Se è un processo con clock, stai leggermente meglio, ma otterrai comunque abilitazioni dove potresti non averne bisogno. Forse mi manca il tuo intento qui.

  • '-', come notato in precedenza, è probabilmente l'opzione migliore, sia per ragioni semantiche che pratiche.

  • Dipende da cosa intendi per "indefinito". 'X'è tecnicamente "sconosciuto". 'U'è per segnali non inizializzati, che ModelSim visualizza come "X"per le rappresentazioni esadecimali. 'X'sembra funzionare, però, come ho notato sopra.

Un'altra alternativa sarebbe quella di fare da soli l'ottimizzazione e rimuovere un caso dalla prova esplicita:

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;

Ciò presenta svantaggi significativi (principalmente legati alla chiarezza del codice), e probabilmente sceglierei una soluzione più ideale.

Per inciso, '-'è anche comunemente usato con std_match(), che vorrei prendere in considerazione per la tua decodifica, ad esempio:

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

Anche se a quel punto, probabilmente stai meglio usando case?.


6

In breve: è VHDL legale ed è generalmente supportato da strumenti di sintesi.

È comunque piuttosto raro vederlo usato. Non so davvero perché. Il tuo codice mi sembra essere un buon esempio di quando sarebbe significativo usarlo.

Vi è tuttavia uno svantaggio di cui bisogna essere consapevoli: in sintesi, le funzioni che guidano gli output in cui non sono coinvolti problemi potrebbero essere diverse tra i cicli di sintesi. Questo rende la sintesi meno deterministica. Se vengono utilizzati (per errore) gli output che sono stati definiti come non importanti, ciò può rendere più difficile trovare l'errore.

Strumento di supporto

Almeno i seguenti strumenti accetteranno non importa e si avvarranno delle possibilità di ottimizzazione:

  • Xilinx (rif .: "Manuale dell'utente XST")
  • Altera (rif .: "Stili di codifica HDL consigliati")
  • Synplify (rif .: "Manuale di riferimento di Synplify")

Xilinx e Altera tratteranno '-'e 'X'come non importa, Synplify tratterà quelli e inoltre 'U'e 'W'(debole) come non importa.


1
Ho avuto un'altra applicazione di questo inconveniente. Il codice ha lavorato nella simulazione, ma non sul FPGA, perché il mio codice sembrava: if signal = '1' then a; else b; end if;. Purtroppo non lo signalera 1o 0ma -. Quindi, nella simulazione, il elseramo è stato eseguito, ma in hardware -si è rivelato essere un 1, quindi il ramo vero è stato eseguito ...
Fritz

Sì, ho avuto simulazioni simili per il passaggio di bug, ma il più delle volte nel mio caso ci sono le 'U's, comuni all'inizio delle simulazioni, che sono state usate portando ad eseguire alcuni elseblocchi di codice. Sarebbe meraviglioso se i condizionali potessero in qualche modo essere propagati 'U', in modo simile al comportamento delle espressioni booleane concorrenti.
Carl,

Dopo aver trovato quel bug mi sono assicurato di scrivere sempre qualcosa del genere if signal = '1' then output <= '1'; elsif signal='0' then output <= '0'; else output <= '-'; end if;. E ho aggiunto quanto segue a tutti i registri e memorie: assert not is_X(write_enable) report "we=" & str(A_write_enable) severity ERROR;e if write_enable = '1' then assert not is_X(write_addr) report "write_addr=str(write_addr) severity ERROR; end if;. Più lo stesso per write_data. Insieme, ciò dovrebbe rilevare quasi tutti questi errori.
Fritz,

È un modo, ma è troppo prolisso per me. Vorrei questa possibilità nel linguaggio VHDL.
Carl,

1
Bene sì, VHDL è un po 'prolisso, ma è solo il modo VHDL. : D D'altra parte è anche molto esplicito, e non fa "magia nera" dietro la mia schiena, che trovo piuttosto carina (cfr. Lo Zen di Python "Explicit è meglio che implicito").
Fritz,
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.