Forum: FPGA, VHDL & Co. Generics und Frage zu Integer-Typen


von Marius S. (lupin) Benutzerseite


Lesenswert?

Ich habe mal eine einfache Frage zu Generics und muss mal ein wenig über 
den Integer-Typ rum heulen ;-)

Als Beispiel mal ein einfaches Schieberegister, welches mitzählt wie 
viel Bits geladen wurden. Das Schieben wird über das Signal shift_enable 
aktiviert und das Register wird gleichzeitig darüber zurück gesetzt (ist 
in Ordnung das so zu machen, oder?) :-)
1
entity DataShifter is
2
  generic (
3
    RegWidth      : integer := 14
4
  );
5
  port(
6
    clk           : in  std_logic;
7
    din           : in  std_logic;
8
    shift_enable  : in  std_logic;
9
    bit_ctr       : in  unsigned(3 downto 0);
10
    dout          : out std_logic_vector (RegWidth-1 downto 0)
11
  );
12
end DataShifter;
13
14
architecture Behavioral of DataShifter is
15
  -- Haelt die geladenen Bits
16
  signal ShiftReg : std_logic_vector(RegWidth-1 downto 0);
17
begin
18
  -- Zuweisung des Schieberegisters an Ausgang
19
  dout <= ShiftReg;
20
21
  -- Dieser Prozess laedt die neuen Eingangswerte
22
  ShiftInData : process
23
  begin
24
    wait until rising_edge(clk);
25
    -- Schieben aktiv?
26
    if shift_enable='1' then
27
      -- Neues Bit einschieben
28
      ShiftReg <= ShiftReg(ShiftReg'high-1 downto 0) & din;
29
      -- Zaehler erhoehen
30
      bit_ctr <= bit_ctr + 1;
31
    else
32
      -- Keine Daten einschieben
33
      -- Reset des Dateninhaltes fuer naechstes Schieben
34
      ShiftReg <= (others => '0');
35
      -- Zaehler ruecksetzen
36
      bit_ctr <= to_unsigned(0, bit_ctr'length);
37
    end if;
38
  end process ShiftInData;
39
end Behavioral;

Alles ganz toll, oder?
Nur was ist, wenn ich jetzt z.B. RegWidth auf 32 setze? Mein bit_ctr ist 
dann leider zu klein.

Wie macht man da normalerweise? Integer benutzen?

Jetzt kommt das Geheule über Integer-Typen :-)

Ich habe mittlerweile versucht so wenig Integer wie möglich zu nutzen, 
da die hin- und her-Konvertiererei etwas nervig wurde. Außerdem werden 
die Grenzen von Integer-Werten in ISim z.B. nicht geprüft, in ModelSim 
aber schon. Außerdem will man ja oftmals einen Überlauf haben (der sich 
mit Unsigned-Werten viel schöner beschreiben lässt).

Ein anderes Problem mit Integern habe ich, wenn ich z.B. einen 4-Bit 
Unsigned habe, den ich in einen Integer konvertieren will, der nur einen 
Range von 0 bis 12 hat. Jetzt kann es unter Umständen mal vorkommen, 
dass ein 4-Bit Wert >12 verarbeitet wird (was aber für die Funktion egal 
ist). Da gibt die Simulation in ModelSim natürlich auch einen Fehler 
aus.
Natürlich könnte ich den Integer-Bereich jetzt auch erweitern. Aber 
genau so gut kann ich eigentlich auch gleich komplett Unsigned-Typen 
verwenden.

Außerdem passiert es schnell mal, dass man einen Integer z.B. mit Range 
"0 to 32" beschreibt, obwohl man eigentlich Range "0 to 31" meinte (weil 
evtl. nicht immer sofort 100% klar ist wie viel Bits für den Integer 
drauf gehen).

Also irgendwie mag ich Integer nicht so gerne - berechtigt oder bin ich 
zu doof? :-)

Und wie sieht die Lösung für das Generics-Problem aus?

von greg (Gast)


Lesenswert?

Marius S. schrieb:
> Nur was ist, wenn ich jetzt z.B. RegWidth auf 32 setze? Mein bit_ctr ist
> dann leider zu klein.

Parametrisiere einfach die Größe von bit_ctr anhand der RegWidth. Du 
brauchst ceil(log2(RegWidth)) Bits. Und sollte bit_ctr nicht eher ein 
internes Signal sein?
1
use ieee.math_real.all;
2
...
3
signal bit_ctr : std_logic_vector(integer(ceil(log2(real(RegWidth))))-1 downto 0);

Am besten wäre es vielleicht, das in eine kleine Function in einem 
Package stecken.

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


Lesenswert?

Marius S. schrieb:
> Mein bit_ctr ist dann leider zu klein.
Am einfachsten machst ma einen Zähler sowieso als eingeschränkten 
Integer (solange der Zähler nicht weiter als bis 2.147.483.647 zählen 
muss). Dann spart man sich auch dieses Rumgewürge beim Zurücksetzen des 
Zählers.

Und das "Ausrechnen" des Zähler-Wertebereichs ist, naja, sagen wir mal: 
unnötig
1
  signal bit_ctr : integer range 0 to RegWidth-1;
Einfacher und klarer geht es kaum...

Marius S. schrieb:
> Ein anderes Problem mit Integern habe ich, wenn ich z.B. einen 4-Bit
> Unsigned habe, den ich in einen Integer konvertieren will, der nur einen
> Range von 0 bis 12 hat. Jetzt kann es unter Umständen mal vorkommen,
> dass ein 4-Bit Wert >12 verarbeitet wird (was aber für die Funktion egal
> ist). Da gibt die Simulation in ModelSim natürlich auch einen Fehler
> aus.
Ist ja auch richtig: du selber hast den Wertebereich so definiert und 
für richtig befunden. Der Simulator zeigt dir nur, dass da etwas anders 
läuft als du dir gedacht hast. Er arbeitet nicht gegen, sondern für 
dich... ;-)

> Jetzt kann es unter Umständen mal vorkommen, dass ein 4-Bit Wert >12
> verarbeitet wird (was aber für die Funktion egal ist).
Dann ist der Wertebereich des Integers falsch definiert. Wenn es 
passieren kann aber egal ist und keine Fehlfunktion auftreten 
kann, dann musst du den Wertebereich schon so definieren, dass auch kein 
Fehler angemeckert wird.
Aber es gibt eben Fälle, wo es nicht egal ist, wenn ein eingeschränkter 
Wertebereich verlassen wird, weil z.B. abhängig von diesem Wert eine FSM 
eine Weiterschltung vornimmt...

> Außerdem passiert es schnell mal, dass man einen Integer z.B. mit Range
> "0 to 32" beschreibt, obwohl man eigentlich Range "0 to 31" meinte (weil
> evtl. nicht immer sofort 100% klar ist wie viel Bits für den Integer
> drauf gehen).
Halb so schlimm: der Synthesizer schmeißt dir das unnötige Bit raus und 
weist dich darauf hin.

> Also irgendwie mag ich Integer nicht so gerne
Ich nehme für Zähler&Co nur wegen des eingeschränkten Wertebereichs bei 
mehr als 31 Bit den Datentyp unsigned. Und das ist selten der Fall...

: Bearbeitet durch Moderator
von greg (Gast)


Lesenswert?

Lothar Miller schrieb:
> Am einfachsten machst ma einen Zähler sowieso als eingeschränkten
> Integer (solange der Zähler nicht weiter als bis 2.147.483.647 zählen
> muss). Dann spart man sich auch dieses Rumgewürge beim Zurücksetzen des
> Zählers.

Synthetisiert das denn zu effizienter Hardware? Ich meine in 
"VHDL-Synthese" von Reichardt/Schwarz mal gelesen zu haben, dass Integer 
generell nur eingeschränkt synthesefähig wäre und man damit äußerst 
vorsichtig sein sollte. Ist das überholt und mit heutigen Tools kein 
Problem mehr?

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


Lesenswert?

greg schrieb:
> Synthetisiert das denn zu effizienter Hardware?
Es synthetisiert zur selben Hardware. Ob die effizient ist, steht auf 
einem andern Blatt...

> Ich meine in "VHDL-Synthese" von Reichardt/Schwarz mal gelesen zu haben,
> dass Integer generell nur eingeschränkt synthesefähig wäre
Findest du die Stelle nochmal? Das hast du sicher falsch aufgefasst.

> Ist das überholt
Es gab nie Probleme damit. Es kann nur dann holprig werden, wenn 
ausschließlich uneingeschränkte Integer verwendet werden, denn dann 
muss hinterher der Optimizer aufräumen. Und dann hagelt es Warnungen... 
:-/

von Christoph Z. (christophz)


Lesenswert?

greg schrieb:
> Synthetisiert das denn zu effizienter Hardware?

Ob du einen Zähler mit einem eingeschränkten Integer oder mit Unsigned 
beschreibst hat keinen einfluss auf die generierte Hardware. Sowas haben 
die Tools im Griff (und wäre auch schlecht wenn nicht).

Trotzdem, nicht alles ist Synthesefähig, das gilt ja für unsigned auch 
:-)

von Christoph Z. (christophz)


Lesenswert?

Marius S. schrieb:
1
generic (
2
    RegWidth      : integer := 14

Ich habe mir angewöhnt für diese Zwecke nicht integer sondern positive 
zu nehmen (im Standard definierter eingeschränkter Integertyp von 1 bis 
max. Integerwert). Wenn die 0 auch erlaubt sein soll, natural.

Damit niemand auf die Idee kommt, mir eine negative Zahl in den Generic 
zu schreiben (an vielen Stellen würde nichts passieren, Fehler währen 
warscheinlich mühsam zu suchen).

von Marius S. (lupin) Benutzerseite


Lesenswert?

greg schrieb:
> integer(ceil(log2(real(RegWidth))))-1

Na, wenn das mal nicht einfach und eindeutig ist :-)

Ein Package habe ich mir schon angelegt, hab auch eine einfache log2 
Funktion für integers. Aber will eigtl. nicht für jede Kleinigkeit das 
Package einbinden.

Lothar Miller schrieb:
> Ich nehme für Zähler&Co nur wegen des eingeschränkten Wertebereichs bei
> mehr als 31 Bit den Datentyp unsigned. Und das ist selten der Fall...

Und den Überlauf für die Zähler beschreibst du dann auch entsprechend 
von Hand?

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


Lesenswert?

Marius S. schrieb:
> Und den Überlauf für die Zähler beschreibst du dann auch entsprechend
> von Hand?
Ja. Und der Syntesizer ist so schlau und macht da das Richtige draus. 
Und ausserdem: nur ganz selten reicht ein Zähler mit implizitem Überlauf 
aus. Meist muss der Zähler doch sowieso bei 13 oder 97 oder 135 oder 
ähnlich unbinären Werten zurückgesetzt werden. Warum dann nicht einfach 
alle Zähler gleich beschreiben?

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


Lesenswert?

Christoph Z. schrieb:
> generic (
>     RegWidth      : integer := 14
>
> Ich habe mir angewöhnt für diese Zwecke nicht integer sondern positive
> zu nehmen (im Standard definierter eingeschränkter Integertyp von 1 bis
> max. Integerwert). Wenn die 0 auch erlaubt sein soll, natural.
>
> Damit niemand auf die Idee kommt, mir eine negative Zahl in den Generic
> zu schreiben
Man könnte das natürlich auch einfach so schreiben:
1
 generic (
2
     RegWidth      : integer range 4 to 16 := 14
3
 );
Denn Natural und Positive sind ja auch nur eingeschränkte Integer:
1
subtype Natural is Integer range 0 to Integer'high;
2
subtype Positive is Integer range 1 to Integer'high;

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.