Forum: FPGA, VHDL & Co. Datenbreite eines Signals aus einer Generic setzen (VHDL)


von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Fangen wir mit dem Codesegment an.
1
entity ....
2
  generic(clk_freq : integer);
3
...
4
architecture ..........
5
  signal   tickcounter : unsigned (8 downto 0) := (others => '0');
6
  constant tick        : integer               := (clk_freq/10E6);    
7
  signal   tick_event  : std_logic             := '0';
8
9
10
11
begin
12
13
  process(clk)
14
  begin
15
    if rising_edge(clk) then
16
      if (tickcounter = tick) then
17
        tickcounter <= (others => '0');
18
        tick_event  <= '1';
19
      else
20
        tickcounter <= tickcounter+1;
21
        tick_event  <= '0';
22
      end if;
23
    end if;
24
  end process;

Ich ermittle für ein paar Frequenzen, die Takteiler automatisch. Dafür 
gebe ich über generic die Frequenz mit und der Fitter ermittelt die 
Werte für den Taktteiler. Das funktioniert soweit gut.
So muss ich mich nicht bei verschiedenen Boards die Teiler von Hand 
ausknobeln und hart in den Code eintragen.
Bringt etwas Flexibilität ins System.
Jetzt hatte ich einen Fall, da reichte die Breite des tickcounter nicht 
aus, weil die Frequenzen zu weit auseinander lagen.

Große Frage:
Gibt es eine Möglichkeit die Zählerbreite automatisch zu setzen?

Ich schreibe es mal so und hoffe auf Vorschläge.
1
  signal   tickcounter : unsigned (needed range for clk_freq/10E6)

von berndl (Gast)


Lesenswert?

René D. schrieb:
> Fangen wir mit dem Codesegment an.
> entity ....
>   generic(clk_freq : integer);
> ...
> architecture ..........
>   signal   tickcounter : unsigned (8 downto 0) := (others => '0');
>   constant tick        : integer               := (clk_freq/10E6);
>   signal   tick_event  : std_logic             := '0';
>
> begin
>
>   process(clk)
>   begin
>     if rising_edge(clk) then
>       if (tickcounter = tick) then
>         tickcounter <= (others => '0');
>         tick_event  <= '1';
>       else
>         tickcounter <= tickcounter+1;
>         tick_event  <= '0';
>       end if;
>     end if;
>   end process;
>
> Ich ermittle für ein paar Frequenzen, die Takteiler automatisch. Dafür
> gebe ich über generic die Frequenz mit und der Fitter ermittelt die
> Werte für den Taktteiler. Das funktioniert soweit gut.
> So muss ich mich nicht bei verschiedenen Boards die Teiler von Hand
> ausknobeln und hart in den Code eintragen.
> Bringt etwas Flexibilität ins System.
> Jetzt hatte ich einen Fall, da reichte die Breite des tickcounter nicht
> aus, weil die Frequenzen zu weit auseinander lagen.
>
> Große Frage:
> Gibt es eine Möglichkeit die Zählerbreite automatisch zu setzen?
>
> Ich schreibe es mal so und hoffe auf Vorschläge.  signal   tickcounter :
> unsigned (needed range for clk_freq/10E6)

Hallo Rene,
also ob du den Logarithmus Dualis in VHDL so einfach berechnen kannst, 
weiss ich nicht und wage es mal zu bezweifeln...
Ich helfe mir immer damit, dass ich die Breite des unsigned auch als 
Generic mitgebe. Damit ist meine Component generisch, beim instanzieren 
wird dann alles festgelegt. Ist mein workaround fuer sowas...

Gruss,
- berndl

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

>
> Hallo Rene,
> also ob du den Logarithmus Dualis in VHDL so einfach berechnen kannst,
> weiss ich nicht und wage es mal zu bezweifeln...

es gibt tatsächlich die Logfunktion in VHDL.
package math_real
1
function log2 (x: in rea) return real;

Doch wie weiter?


> Ich helfe mir immer damit, dass ich die Breite des unsigned auch als
> Generic mitgebe. Damit ist meine Component generisch, beim instanzieren
> wird dann alles festgelegt. Ist mein workaround fuer sowas...

Das wollte ich gerade vermeiden. Für ein Problem zwei Werte durch die 
Hierarchie durchcoden und dann sind die  Werte wieder von Hand zu 
setzen.
Mal sehen ob sich doch eine Lösung ergibt.

von Christian R. (supachris)


Lesenswert?

HIlft das dir? Mache ich immer, wenn ich die Bit-Breite ausrechnen 
lassen will:
1
constant REG_ADDR_WIDTH : integer := integer(ceil(log2(real(NUMBER_OF_REGS))));

von berndl (Gast)


Lesenswert?

Genau das muesste es sein! Wieder was dazu gelernt...

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Christian R. schrieb:
> HIlft das dir? Mache ich immer, wenn ich die Bit-Breite ausrechnen
> lassen will:
>
>
1
constant REG_ADDR_WIDTH : integer := 
2
> integer(ceil(log2(real(NUMBER_OF_REGS))));
3
>

Das werde es heute Abend ausprobieren. Würde mir so gefallen, wenn ich 
es so einsetzen kann.

von Sigi (Gast)


Lesenswert?

Warum benutzt du für "tickcounter" nicht integer bzw.
"integer range 0 to tick-1", dann wird die Weite
autom bestimmt.
Und: du vergleichst "tickcount" mit "tick" statt mit "tick-1".

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Fragezeichen nicht auf deiner Tastatur?

Sigi schrieb:
> Warum benutzt du für "tickcounter" nicht integer bzw.
> "integer range 0 to tick-1", dann wird die Weite
> autom bestimmt.

Ich arbeite ungern mit Integer in Signalen. Aus folgenden Grund.
Die Simulation mach was anderes als die Hardware bei fehlerhaften 
Überläufen.
In diesem Fall wäre es noch überschaubar und würde den Code lesbarer 
machen.


> Und: du vergleichst "tickcount" mit "tick" statt mit "tick-1".
Du hast recht, dass ich auf tick-1 vergleichen muss, da ich auf Null 
zurücksetze und das ein Zählerwert entspricht.

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Folgender Code ist fitbar und läuft im FPGA.


1
library ieee;
2
3
use ieee.std_logic_1164.all;
4
use ieee.numeric_std.all;
5
use ieee.math_real.all;
6
7
8
9
  constant tick        : integer               := (clk_freq/10E6);
10
  constant tick_WIDTH  : integer := integer(ceil(log2(real(tick))));
11
  signal   tickcounter : unsigned (tick_WIDTH downto 0) := (others => '0');
12
13
14
  process(clk)
15
  begin
16
    if rising_edge(clk) then
17
      if (tickcounter = tick-1) then
18
        tickcounter <= (others => '0');
19
        tick_event  <= '1';
20
      else
21
        tickcounter <= tickcounter+1;
22
        tick_event  <= '0';
23
      end if;
24
    end if;
25
  end process;

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


Lesenswert?

Ich hätte da ein (tick_WIDTH-1 downto 0) erwartet...

Wenn du beim Berechnen der Tick-Breite noch eins dazu gibst, dann klappt 
es auch an den Grenzen der Zweierpotenzen, und du hast nicht so oft ein 
Bit zuviel (das die Synthese wieder wegwerfen muss)
 http://www.lothar-miller.de/s9y/archives/72-Breite-eines-Vektors-berechnen-log2.html

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Lothar Miller schrieb:
> Ich hätte da ein (tick_WIDTH-1 downto 0) erwartet...

Hatte ich auch erwartet. Bei genauerer mathematischer Betrachtung 
errechnet der Log2 wieviele Zustände ich abbilden kann. Und die Zahl 0 
darf man als Zustand nicht vergessen.


Bsp:

log2(4)=2

Ergebnis für vier Zustände brauche ich zwei Leitungen.
Damit kann ich die Zahlen von 0...3 abbilden.
Die vier ist außerhalb des Wertebereiches.
Deshalb passt dein Vorschlag nicht.


>Wenn du beim Berechnen der Tick-Breite noch eins dazu gibst, dann klappt
>es auch an den Grenzen der Zweierpotenzen,

vermutlich meinst du  hier dasgleiche, da ich nicht wie du vorgeschlagen 
hast mit tick_width-1 arbeite.

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


Lesenswert?

René D. schrieb:
>> Wenn du beim Berechnen der Tick-Breite noch eins dazu gibst, dann klappt
>> es auch an den Grenzen der Zweierpotenzen,
> vermutlich meinst du  hier dasgleiche, da ich nicht wie du vorgeschlagen
> hast mit tick_width-1 arbeite.
Was ich meine, ist, dass du den halben Wertebereich des Vektors 
verschenkst. Denn wenn dein Zähler 7 Schritte (also von 0 bis 6) zählen 
soll, dann bekommst du einen Vektor ceil(log2(7)) = 3 downto 0. Und das 
sind 4 Bit statt der tatsächlich nötigen 3 Bit.

Oder wenn du 100MHz Taktfrequenz hast, dann bekommst du einen Vorteiler 
von 100, das ergibt mit deiner Formel dann einen Vektor
ceil(log2(100)) = 7 downto 0.
Wieder ein Bit zuviel: 6 downto 0 würden hier reichen.

BTW: ich würde in diesem Fall hier den Vorteiler tickcounter sowieso 
einfach als integer durchgehen lassen. Da spart man sich die ganze 
Rechnerei... ;-)

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Lothar du hast mich überzeugt.


  constant tick        : integer               := (clk_freq/10E6);
  signal   tickcounter : integer range 0 to tick-1;

Synthesizing Unit <i2c_master>.
    Related source file is 
"/home/red/softcore/mais2/rtl/device/i2c_master/I2C_master.vhd".
        clk_freq = 80000000
    Found 1-bit register for signal <start_A_d1>.
    Found 3-bit register for signal <tickcounter>.
    Found 1-bit register for signal <tick_event>.
    Found 1-bit register for signal <SCL_falling>.
    Found 8-bit register for signal <SCL_counter>.
    Found 4-bit register for signal <bit_counter>.

80E6/10E6=8

0...7 Zählerwerte braucht 3 Signalleitungen
Und die ISE kapiert es auch.

Der Code sieht auch schöner aus.

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


Lesenswert?

René D. schrieb:
> Der Code sieht auch schöner aus.
So ist es.
Nur, wenn du den impliziten Zählerüberlauf z.B. eines 4-Bit Zäahlers von 
15 nach 0 haben möchtest, ist die unsigned Variante schöner zu lesen. 
Aber auch ein integer Zähler, der explizit von 15 auf 0 gesetzt werden 
muss, ergibt den selben Ressourcenbedarf:
1
  signal cntu : unsigned (3 downto 0) := (others=>'0');
2
  signal cnti : integer range 0 to 15 := 0;
3
  
4
  :
5
  :
6
7
  process begin
8
    wait until rising_edge(clk);
9
    
10
    -- unsigned Zähler mit implizitem Überlauf
11
    cntu <= cntu + '1';
12
13
    -- integer Zähler mit explizitem Überlauf
14
    if cnti<15 then
15
       cnti <= cnti + 1;
16
    else 
17
       cnti <= 0;
18
    end if;
19
20
    --> beide Varianten bringen das selbe Synteseergebnis
21
22
  end process;

: Bearbeitet durch Moderator
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.