www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Bereichsabfrage in Case


Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

habe folgende Frage an Euch: Ich möchte in einer Case-Abfrage einzelne
Adress-Werte abfragen, möchte aber gleichzeitig einen Adress-Bereich 
abfragen. Ist eine der drei folgenden Varianten zu bevorzugen ? Bin mir 
nicht sicher, ob die dritte Variante so überhaupt funktioniert ...
Oder gibt es gar eine elegantere Methode ? Vorab vielen Dank für Eure 
Meinungen und Vorschläge.

Grüsse,
Stefan123



-- Variante 1
process(clk)
begin
    wait until rising_edge(clk);
    
    case addr is
        when x"01" => ...
        when x"02" => ...
        when x"03" => ...
        when others => null;
    end case;
    
    if addr > x"07" and addr < x"0F" then
        ...
    end if;

end process;


-- Variante 2
process(clk)
begin
    wait until rising_edge(clk);
    
    case addr is
        when x"01" => ...
        when x"02" => ...
        when x"03" => ...
        when others => 
                if addr > x"07" and addr < x"0F" then
                    ...
                end if;
    end case; 

end process;


-- Variante 3
process(clk)
begin
    wait until rising_edge(clk);
    
    case addr is
        when x"01" => ...
        when x"02" => ...
        when x"03" => ...
        when (addr > x"07" & addr < x"0F") => ...
        when others => null;
               
    end case; 

end process;






Autor: user (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, also das ist eigendlich die eleganteste Methode:

process(clk)
begin
    if rising_edge(clk) then

        case addr is
            when x"01" => ...
            when x"02" => ...
            when x"03" => ...
            when x"07" | x"0F" => ...
            when others => null;

        end case;

    end if;

end process;

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, nicht ganz. In deiner Abfrage
when x"07" | x"0F" => ...

wird nicht ein Adressbereich abgefragt, sondern lediglich zwei Werte!

Grüsse,
Stefan123

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wäre noch evtl. eine Variante ?
-- Variante 4
process(clk)
begin
    wait until rising_edge(clk);
    
    case addr is
        when x"01" => ...
        when x"02" => ...
        when x"03" => ...
        when x"08" to x"0E" => ...
        when others => null;
               
    end case; 

end process;

Grüsse,
Stefan123

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> when x"08" to x"0E" => ...
Das to geht nur, wenn addr ein Integer (oder ein Aufzählungstyp) 
ist.

Sowas ginge also:
signal seli : integer range 0 to 15;
:
  seli <= to_integer(unsigned(sel));
  process(seli, din) begin
    case seli is
      when 0 to 1  => dout1<=din(15 downto 12);
      when 2       => dout1<=din(11 downto  8);
      when 3 to 6  => dout1<=din( 7 downto  4);
      when 7 to 15 => dout1<=din( 3 downto  0);
      when others  => null;
    end case;
  end process;

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Lothar,

danke für deinen Hinweis. Welche der Varianten 1-3 würdest du verwenden 
?
Funktioniert Variante 3 ?


Grüsse,
Stefan123

Autor: mki (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke Vaiante 3 funktioniert so nicht. Und das schon vom Syntax her. 
Der Compiler wird nicht verstehen was du ihn damit sagen willst. Vom 
Gefühl her würde ich Variante 2 bevorzugen.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Funktioniert Variante 3 ?
Nein.
Siehe Beitrag "Re: Bereichsabfrage in Case"

>Welche der Varianten 1-3 würdest du verwenden?
Am lesbarsten dürfte Variante 2 sein.
Ich würde einfachh alle ausprobieren und dann die Laufzeiten und den 
Ressourcenbedarf ansehen...  ;-)

Sowas ginge evtl. auch:
-- Variante 5
process(clk)
begin
    wait until rising_edge(clk);  -- wozu hier der Takt? Das gibt einen Takt Latency!
    
    case to_integer(unsigned(addr)) is
        when to_integer(unsigned(x"01")) => ...
        when to_integer(unsigned(x"02")) => ...
        when to_integer(unsigned(x"03")) => ...
        when to_integer(unsigned(x"08")) to 
             to_integer(unsigned(x"0E")) => ...
        when others => null;
               
    end case; 

end process;

Variante 6 wäre, gleich alles mit if abzufragen...

BTW:
Wozu eigentlich der Takt im Prozess?

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Variante 5 liefert folgende Fehlermeldung (Modelsim)
case to_integer(unsigned(addr)) is
        when to_integer(unsigned(x"01")) => ...

Error: Type conversion (to unsigned) can not have string literal 
operand.


Der Takt wird verwendet um aus der Adress-Dekodierung registrierte 
Signale (...) zu erzeugen.


Grüsse,
Stefan123

Autor: Mathi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verwende to_unsigned(Wert, Breite)
case to_integer(unsigned(addr)) is
        when to_integer(to_unsigned(x"01", addr'length)) => ...

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Verwende to_unsigned(Wert, Breite)

Moment mal, x"01" ist doch kein Integer, sondern ein std_logic_vector. 
Also kommt man mit "to_unsigned" nicht weiter.


Grüsse,
Stefan123

Autor: Mathi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann benutze einen hexint 16#Wert...

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Dann benutze einen hexint 16#Wert...

Was genau meinst du denn damit ?


Grüsse,
Stefan123

Autor: Mathi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann bei einem Integer die Basis angeben. Das hat die Form 
Basis#Wert. D.h. wenn Du den dec-Wert 255 angeben willst, kannst Du 
16#ff schreiben.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mathi schrieb:
> Dann benutze einen hexint 16#Wert...
Ja, klar, warum nicht das naheliegendste zuerst... :-/
  process begin
    wait until rising_edge(clk);  
    case to_integer(unsigned(addr)) is
        when 16#01# => ...
        when 16#02# => ...
        when 16#03# => ...
        when 16#08# to 
             16#0E# => ...
        when others => null;
    end case; 
  end process;

Autor: Mathi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt, habe die letzte Raute vergessen: 16#ff#

@Lothar:
... Weil man zu gerne kompliziert denkt ;)

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
when 16#01# => 

Das funktioniert jetzt.

Frage mich nur, wieso der Compiler mit
when to_integer(unsigned(x"01")) => ...

nicht klar kommt. Ist doch eindeutig beschrieben.


Grüsse,
Stefan123

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan123 schrieb:
> Frage mich nur, wieso der Compiler mit
>
> when to_integer(unsigned(x"01")) => ...
> 
> nicht klar kommt. Ist doch eindeutig beschrieben.
Die Funktion unsigned() weiß nicht, welcher Typ x"01" denn genau ist. 
Es kann ja ein signed, ein unsigned, ein std_ulogic_vector oder was auch 
immer sein. 6 Typen stehen zur Auswahl.

Ein Qualifier hilft ein Stück weiter: to_integer( unsigned'(x"01") )
Hier wird der Funktion to_integer() explizit gesagt, dass x"01" ein 
unsigned-Vektor ist. Diese Umrechnung ginge also klar.
Aber case-when hat prinzipiell ein Problem mit der nicht statischen 
Funktion to_integer(), denn im case-when darf nur ein explizit 
statischer Wert stehen.

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, eine Sache ist ja nun doch noch etwas krückig:


Wenn man Adressen über Konstanten dekodieren möchte, dann wird das 
folgende Beispiel nicht funktionieren. Was kann man da machen ?

z.B.:


signal addr : unsigned(7 downto 0);

constant cAdd_x : unsigned(7 downto 0) := x"01";
constant cAdd_y : unsigned(7 downto 0) := x"02";
constant cAdd_z : unsigned(7 downto 0) := x"03";

process(clk)
begin
    if rising_edge(clk) then

        case to_integer(addr) is
            when 16#cAdd_x# to 16#cAdd_z# => ...            
            ...
        end case;

    end if;

end process;



Grüsse,
Stefan123

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, also Lothars Variante mit "unsigned' " lässt sich kompilieren, 
Modelsim beklagt sich "Case choice must be a locally static expression."
Aber das kann man ja in den Compile-Optionen ausschalten und stört auch 
nicht weiter für die Synthese.

Funktioniert:
case to_integer(unsigned(addr)) is
        when to_integer(unsigned'(x"01")) => ...


Ein weiterer Vorteil, die Adress-Bereichs-Abfrage nicht in den 
others-Zweig zu packen ist, dass Adress-Überlagerungen bemängelt werden.

Beispiel: wird von Modelsim bemängelt
case to_integer(unsigned(addr)) is
        when to_integer(unsigned'(x"01")) => ...
        when to_integer(unsigned'(x"01")) to to_integer(unsigned'(x"02") =>


Beispiel: wird nicht von Modelsim bemängelt
case to_integer(unsigned(addr)) is
        when to_integer(unsigned'(x"01")) => ...
        when others =>
             if addr >=x"01" and addr <= x"02" then

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Was kann man da machen ?
signal addr : unsigned(7 downto 0);

constant cAdd_x : unsigned(7 downto 0) := x"01";
constant cAdd_y : unsigned(7 downto 0) := x"02";
constant cAdd_z : unsigned(7 downto 0) := x"03";

process(clk)
begin
    if rising_edge(clk) then
        case to_integer(addr) is
            when to_integer(cAdd_x) to to_integer(cAdd_z) => ...            
            ...
        end case;
    end if;
end process;


> Beispiel: wird von Modelsim bemängelt
Klar, denn es gibt zwei Pfade für addr=x"01".

> Beispiel: wird nicht von Modelsim bemängelt
Nur wird für addr=x"01" der others-Fall nicht ausgeführt...  :-o

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nur wird für addr=x"01" der others-Fall nicht ausgeführt...  :-o

Genau das zeigt die Simulation. Ist also u.U. nicht eindeutig, wenn man 
Variante 2 verwendet.

Grüsse,
Stefan123

Autor: Stefan123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Lothar,

>Aber case-when hat prinzipiell ein Problem mit der nicht statischen
>Funktion to_integer(), denn im case-when darf nur ein explizit
>statischer Wert stehen.

eine Frage hätte ich da noch:
process(clk)
begin
    if rising_edge(clk) then
        case to_integer(addr) is
            when to_integer(cAdd_x) to to_integer(cAdd_z) => ...            
            ...
        end case;
    end if;
end process;



Mit Modelsim erhalte ich folgende Warnung:

"Case choice must be a locally static expression"

Wenn ich jedoch versuche, einen integerierten Logic-Analyzer einzubauen 
(Altera Signaltap), so erhalte ich folgende Fehlermeldung:

ERROR: case choice must be a locally static expression (VHDL-1438)


Wie passt das zusammen? Wieso gibt Modelsim (mit aktiviertem "Check for 
Synthesis") eine Warnung aus, während es beim Einbau des Signaltap-Cores 
zu einem Abbruch kommt ?
Gibt es einen Ausweg aus dem Schlamassel, um dennoch die Bereichsabfrage 
hinzubekommen ?

Grüsse,
Stefan123

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.