Forum: FPGA, VHDL & Co. Bereichsabfrage in Case


von Stefan123 (Gast)


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

1
-- Variante 1
2
process(clk)
3
begin
4
    wait until rising_edge(clk);
5
    
6
    case addr is
7
        when x"01" => ...
8
        when x"02" => ...
9
        when x"03" => ...
10
        when others => null;
11
    end case;
12
    
13
    if addr > x"07" and addr < x"0F" then
14
        ...
15
    end if;
16
17
end process;
18
19
20
-- Variante 2
21
process(clk)
22
begin
23
    wait until rising_edge(clk);
24
    
25
    case addr is
26
        when x"01" => ...
27
        when x"02" => ...
28
        when x"03" => ...
29
        when others => 
30
                if addr > x"07" and addr < x"0F" then
31
                    ...
32
                end if;
33
    end case; 
34
35
end process;
36
37
38
-- Variante 3
39
process(clk)
40
begin
41
    wait until rising_edge(clk);
42
    
43
    case addr is
44
        when x"01" => ...
45
        when x"02" => ...
46
        when x"03" => ...
47
        when (addr > x"07" & addr < x"0F") => ...
48
        when others => null;
49
               
50
    end case; 
51
52
end process;

von user (Gast)


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;

von Stefan123 (Gast)


Lesenswert?

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

wird nicht ein Adressbereich abgefragt, sondern lediglich zwei Werte!

Grüsse,
Stefan123

von Stefan123 (Gast)


Lesenswert?

Das wäre noch evtl. eine Variante ?
1
-- Variante 4
2
process(clk)
3
begin
4
    wait until rising_edge(clk);
5
    
6
    case addr is
7
        when x"01" => ...
8
        when x"02" => ...
9
        when x"03" => ...
10
        when x"08" to x"0E" => ...
11
        when others => null;
12
               
13
    end case; 
14
15
end process;

Grüsse,
Stefan123

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

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

von Stefan123 (Gast)


Lesenswert?

Hi Lothar,

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


Grüsse,
Stefan123

von mki (Gast)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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:
1
-- Variante 5
2
process(clk)
3
begin
4
    wait until rising_edge(clk);  -- wozu hier der Takt? Das gibt einen Takt Latency!
5
    
6
    case to_integer(unsigned(addr)) is
7
        when to_integer(unsigned(x"01")) => ...
8
        when to_integer(unsigned(x"02")) => ...
9
        when to_integer(unsigned(x"03")) => ...
10
        when to_integer(unsigned(x"08")) to 
11
             to_integer(unsigned(x"0E")) => ...
12
        when others => null;
13
               
14
    end case; 
15
16
end process;

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

BTW:
Wozu eigentlich der Takt im Prozess?

von Stefan123 (Gast)


Lesenswert?

Variante 5 liefert folgende Fehlermeldung (Modelsim)
1
case to_integer(unsigned(addr)) is
2
        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

von Mathi (Gast)


Lesenswert?

Verwende to_unsigned(Wert, Breite)
1
case to_integer(unsigned(addr)) is
2
        when to_integer(to_unsigned(x"01", addr'length)) => ...

von Stefan123 (Gast)


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

von Mathi (Gast)


Lesenswert?

Dann benutze einen hexint 16#Wert...

von Stefan123 (Gast)


Lesenswert?

>Dann benutze einen hexint 16#Wert...

Was genau meinst du denn damit ?


Grüsse,
Stefan123

von Mathi (Gast)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Mathi schrieb:
> Dann benutze einen hexint 16#Wert...
Ja, klar, warum nicht das naheliegendste zuerst... :-/
1
  process begin
2
    wait until rising_edge(clk);  
3
    case to_integer(unsigned(addr)) is
4
        when 16#01# => ...
5
        when 16#02# => ...
6
        when 16#03# => ...
7
        when 16#08# to 
8
             16#0E# => ...
9
        when others => null;
10
    end case; 
11
  end process;

von Mathi (Gast)


Lesenswert?

Stimmt, habe die letzte Raute vergessen: 16#ff#

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

von Stefan123 (Gast)


Lesenswert?

1
when 16#01# =>

Das funktioniert jetzt.

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

nicht klar kommt. Ist doch eindeutig beschrieben.


Grüsse,
Stefan123

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Stefan123 schrieb:
> Frage mich nur, wieso der Compiler mit
>
1
> when to_integer(unsigned(x"01")) => ...
2
>
> 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.

von Stefan123 (Gast)


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.:

1
signal addr : unsigned(7 downto 0);
2
3
constant cAdd_x : unsigned(7 downto 0) := x"01";
4
constant cAdd_y : unsigned(7 downto 0) := x"02";
5
constant cAdd_z : unsigned(7 downto 0) := x"03";
6
7
process(clk)
8
begin
9
    if rising_edge(clk) then
10
11
        case to_integer(addr) is
12
            when 16#cAdd_x# to 16#cAdd_z# => ...            
13
            ...
14
        end case;
15
16
    end if;
17
18
end process;

Grüsse,
Stefan123

von Stefan123 (Gast)


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:
1
case to_integer(unsigned(addr)) is
2
        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
1
case to_integer(unsigned(addr)) is
2
        when to_integer(unsigned'(x"01")) => ...
3
        when to_integer(unsigned'(x"01")) to to_integer(unsigned'(x"02") =>


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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>> Was kann man da machen ?
1
signal addr : unsigned(7 downto 0);
2
3
constant cAdd_x : unsigned(7 downto 0) := x"01";
4
constant cAdd_y : unsigned(7 downto 0) := x"02";
5
constant cAdd_z : unsigned(7 downto 0) := x"03";
6
7
process(clk)
8
begin
9
    if rising_edge(clk) then
10
        case to_integer(addr) is
11
            when to_integer(cAdd_x) to to_integer(cAdd_z) => ...            
12
            ...
13
        end case;
14
    end if;
15
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

von Stefan123 (Gast)


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

von Stefan123 (Gast)


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:
1
process(clk)
2
begin
3
    if rising_edge(clk) then
4
        case to_integer(addr) is
5
            when to_integer(cAdd_x) to to_integer(cAdd_z) => ...            
6
            ...
7
        end case;
8
    end if;
9
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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.