N-Stufiges Flip Flop erzeugen

OP #7911433
Lesenswert?

Hallo zusammen,

ich würde gerne in VHDL ein n-Stufiges Flip Flop erzeugen, wobei ich den Parameter n über ein generic weitergeben wollte.

Ich habe mir zwei Codebeispiele überlegt, wobei beim ersten Codebespiel in der Simulation mit Vivado beim Ergebnis "X" auftauchen, also anscheinend mehrere Quellen für das Signal.

Kann bitte jemand die Codebeispiele bewerten oder hat evtl. noch einen besseren Vorschlag.

Vielen Dank im Voraus Daniel

Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #7911461
Lesenswert?

Daniel P. schrieb:

ich würde gerne in VHDL ein n-Stufiges Flip Flop erzeugen,

Du willst aus mehreren Flipflops ein n-stufiges Schieberegister erzeugen, oder? Und über dieses Schieberegister willst du ein Signal um n Takte verzögern.

wobei ich den Parameter n über ein generic weitergeben wollte.

Das geht für 1 Bit einfach so:

1
:
2
generic n : integer range 2 to 16 := 2;
3
:
4
:
5
signal sr: std_logic_vector (n-1 downto 0)
6
:
7
sr <= sr(n-2 downto 2) & inbit  when rising_edge(clk); -- schiebt nach links
8
:
9
outbit <= sr(n-1);
10
:

Und für Vektoren geht es in etwa so:

1
:
2
generic n : integer := 2;
3
:
4
type slv16_array  is array (n-1 downto 0) of std_logic_vector(15 downto 0);
5
signal vsr : slv16_array := (others => (others => '0'));
6
:
7
vsr <= vsr(n-2 downto 2) & invect when rising_edge(clk); -- liest ein und schiebt nach links
8
outvect <= vsr(n-1);
9
:

Wenn die Länge des Schieberegisters zur Laufzeit umgeschaltet werden soll, dann sieht es für 1 Bit so aus:

1
:
2
signal n : integer range 2 to 16 := 2; -- min. 2 Bit, max. 16 Bit lang
3
signal sr: std_logic_vector (15 downto 0); -- muss für maximale Länge ausgelegt sein
4
:
5
sr <= sr(n-2 downto 2) & inbit  when rising_edge(clk); -- schiebt nach links
6
:
7
outbit <= sr(n-1);
8
:

Die Schieberegister-Zeile mit dem "when rising_edge()" kann man natürlich auch auf die lange Art mit einem Prozess schreiben:

1
process begin
2
   wait until rising_edge(clk);
3
   sr <= sr(n-2 downto 2) & inbit; -- schiebt nach links
4
end process;

Oder die traditionelle, ganz ausführliche Art aus dem letzten Jahrtausend:

1
process (clk)
2
begin
3
   if rising_edge(clk) then
4
      sr <= sr(n-2 downto 2) & inbit; -- schiebt nach links
5
   end if;
6
end process;

also anscheinend mehrere Quellen für das Signal.

Für welches Signal?

OP #7911543
Lesenswert?

Sorry für die Verwirrung: Zum Hintergrund. Ich bekomme als Eingangssignal einen 16Bit Zeitstempel. In Abhängigkeit von einem Generic (in meinem Beispiel die Konstante c_clk_del) möchte ich den Zeitstempel um die Anzahl "c_clk_del" Takte verzögern. Das ganze muss nicht zur Laufzeit umgeschaltet werden.

Lothar M. schrieb:

also anscheinend mehrere Quellen für das Signal.

Für welches Signal?

time_stamp(0)

OP #7911597
Lesenswert?

Danke für die Hilfe, habe mich für folgende Lösung entschieden:

1
type slv16_array  is array (n-1 downto 0) of std_logic_vector(15 downto 0);
2
signal vsr : slv16_array := (others => (others => '0'));
3
signal vsr_out : std_logic_vector(15 downto 0);
4
generic n : natural := 2;
5
vsr <= vsr(n-2 downto 0) & invec when rising_edge(clk);  
6
vsr_out <= vsr(n-1) when n > 0 else
7
           invec;
#7912473
Lesenswert?

Bradward B. schrieb:

Auf den default-wert in Zeile 2 ist nach der Synthese kein Verlass.

Prinzipiell ja, aber sowas prüft man einmal, ob das vom jeweiligen Synthesetool richtig umsetzt wird. Und das Synthesetool wechselt man nicht so oft wie die Socken...

Ich hatte den Fall bei Lattice Diamond neulich, wo ich meinen Code etwas umformulieren musste:

Ein

1
    type config_type is array( 0 to 15) of  std_ulogic_vector( 7 downto 0);
2
    constant default_config : config_type :=
3
    (
4
        0      => "11110000",
5
        others => ( others => '0')
6
    );
7

8
    constant default_config_array : config_array_t := ( others => ( default_config));

wird später partiell überschrieben, aber die default_config wurde nur komplett mit '0' initialisiert.

Nach ausformulieren:

1
    signal config_array : config_array_t := default_config_array;
2

3
begin
4

5
    -- needed for Lattice LSE
6
    -- otherwise byte 0 is not correct inialized
7
    --config_array( 0)    <= default_config; -- is used
8
    config_array( 1)    <= default_config;
9
    config_array( 2)    <= default_config;
10
    ...
11

12
    module_i0: entity work.module
13
    port map
14
    (
15
        clk          => clk,                    -- : in    std_ulogic;
16
        ...
17
        config       => config_array( 0),       -- : out   config_type;
18
        ...
19
    );

klappte es wie gewünscht...

(Firma: Starfleet) #7912475
Lesenswert?

Auf den default-wert in Zeile 2 ist nach der Synthese kein Verlass.

Prinzipiell ja, aber sowas prüft man einmal, ob das vom jeweiligen Synthesetool richtig umsetzt wird. Und das Synthesetool wechselt man nicht so oft wie die Socken...

Hm, erzähl das mal einem Barfüßler ;-)

Ich seh hier eher das Problem der Architektur, gibt man einen Reset-Value an, nimmt das Synthesetool oft keine Schieberegister.Makros wie SRL16 (bspw. Xilinx Spartan) auch wenn es in der konkreten FPGA-Architektur möglich wäre. Aber der TO wollte ja lt. Headline ohnehin ("riesige") FF statt schlanke Schiebeketten.

#8090720
Lesenswert?

Hallo Daniel,auch wenn du schon eine funktionierende Lösung gepostet hast, solltest du den Einwand von Bradward bezüglich der Synthese und der Default-Werte sehr ernst nehmen. Dein Ansatz mit dem zweidimensionalen Array (slv16_array) hat in der Praxis zwei gravierende Haken:Gatter-Verschwendung (Keine SRL-Inferenz): Vivado wird durch die Struktur deines verschachtelten Arrays fast immer daran gehindert, das Schieberegister in die hocheffizienten SRL16E/SRL32E (Look-Up-Tables als Schieberegister) zu mappen. Das System synthetisiert dir hier echte, teure Flip-Flops (FFs). Bei einem 16-Bit-Zeitstempel mal n Stufen explodiert dir völlig grundlos der Ressourcenverbrauch.Der 'X'-Fehler in der Simulation: Deine Zeile vsr <= vsr(n-2 downto 0) & invec nutzt den Verkettungsoperator & auf ein Array von Vektoren. Das führt je nach Vivado-Simulator-Version zu fehlerhaften Index-Auflösungen, wodurch das Signal auf den uninitialisierten Zustand 'X' oder 'U' springt.Die saubere, industriekonforme Lösung (1D-Bitvektor-Faltung):Umgehe das zweidimensionale Array komplett. Du kannst das Schieberegister als einen einzigen, flachen std_logic_vector dimensionieren. Das garantiert dir eine perfekte SRL-Inferenz (Vivado packt bis zu 32 Stufen in eine einzige LUT) und läuft in der Simulation absolut 'X'-frei.Hier ist die saubere Umsetzung für deinen 16-Bit-Zeitstempel:

1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3

4
library IEEE;
5
use IEEE.STD_LOGIC_1164.ALL;
6

7
entity timestamp_delay is
8
    generic (
9
        g_clk_del : natural := 4  -- Anzahl der Verzögerungstakte (>= 0)
10
    );
11
    port (
12
        clk      : in  std_logic;
13
        invec    : in  std_logic_vector(15 downto 0);
14
        vsr_out  : out std_logic_vector(15 downto 0)
15
    );
16
end timestamp_delay;
17

18
architecture RTL of timestamp_delay is
19
    -- Konstante zur Vermeidung von null-breiten Vektoren bei g_clk_del = 0 im Deklarationsteil
20
    constant c_sr_width : natural := integer'max(1, g_clk_del * 16);
21
    signal sr_flat      : std_logic_vector(c_sr_width - 1 downto 0) := (others => '0');
22
begin
23

24
    -- Generische Weiche für den Sonderfall g_clk_del = 0 (Direktleitung)
25
    gen_bypass: if g_clk_del = 0 generate
26
        vsr_out <= invec;
27
    end generate;
28

29
    -- Standardfall: Verzögerung aktiv (Sicher für alle Werte ab 1)
30
    gen_delay: if g_clk_del > 0 generate
31
    
32
        -- Spezialfall: Genau 1 Takt Verzögerung (Verhindert fehlerhafte Slices)
33
        gen_one_delay: if g_clk_del = 1 generate
34
            process(clk)
35
            begin
36
                if rising_edge(clk) then
37
                    sr_flat <= invec;
38
                end if;
39
            end process;
40
            vsr_out <= sr_flat;
41
        end generate;
42

43
        -- Allgemeiner Fall: Mehr als 1 Takt Verzögerung
44
        gen_multi_delay: if g_clk_del > 1 generate
45
            process(clk)
46
            begin
47
                if rising_edge(clk) then
48
                    -- Schiebt den alten Inhalt sauber nach links und hängt das neue Signal an
49
                    sr_flat <= sr_flat((g_clk_del * 16) - 17 downto 0) & invec;
50
                end if;
51
            end process;
52
            
53
            -- Greift die ältesten 16 Bit ganz links im Vektor ab
54
            vsr_out <= sr_flat((g_clk_del * 16) - 1 downto (g_clk_del * 16) - 16);
55
        end generate;
56
        
57
    end generate;
58

59
end RTL;
: Bearbeitet durch Moderator

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren