Forum: FPGA, VHDL & Co. FPGA/VHDL Timing


von Florian R. (flo0815)


Lesenswert?

Hallo beisammen,

zunächst vorneweg: bin ein FPGA und VHDL Newcomer, es könnten also 
einige blöde Fragen folgen :-).

Ich habe gerade folgendes Verständnisproblem. In einer entity habe ich 
eine component eingebunden. Diese (selbstgebastelte) component besteht 
aus einem process, der zwei Binärzahlen dividiert. Da das leider eine 
recht sequenzielle Angelegenheit ist, gehe ich mal davon aus, dass das 
mit einem Takt nicht getan ist.
Wenn ich jetzt in der entity dem divider auf die Eingänge Werte gebe, 
wie kann ich dann sichergehen, dass der Ausgang, den ich auslese auch zu 
den Eingabewerten gehört und nicht zu denen davor? Muss ich warten, bis 
sich der Ausgang ändert bzw. ein trigger signal mit einbauen?
Wenn ja, wo ist dann der Unterschied zur Verwendung einer function oder 
procedure? Dann müsste die hardware quasi so synthetisiert werden, dass 
automatisch gewartet wird?
Ach ja: Wie ist das dann, wenn ich "vorgefertigte" Komponenten, wie z.B. 
einen hardware multiplier (Spartan3E) einbinde. Muss/kann ich da warten?

Hinter diese Timing-Sache steig ich noch nicht so ganz. Die sequenzielle 
Art zu Denken ist nur schwer zu verdrängen...

Vielen Dank für jede Hilfe und jeden Hinweis.

Gruß
flo0815

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

> Da das leider eine
> recht sequenzielle Angelegenheit ist, gehe ich mal davon aus, dass das
> mit einem Takt nicht getan ist.
Ich hoffe, du meinst damit: Du hast eine komplizierte ("tiefe") 
kombinatorische Logik beschrieben - also einen Haufen LUT's - deren 
Ausgänge direkt das Ergebnis in Abhängigkeit von den Eingängen ausgeben?
Weil sequentiell kann ein FPGA nicht - diese LUT's, auch wenn davon 
viele hintereinander geschaltet sind, arbeiten ja im Prinzip alle 
parallel.
>Wenn ich jetzt in der entity dem divider auf die Eingänge Werte gebe,
>wie kann ich dann sichergehen, dass der Ausgang, den ich auslese auch zu
>den Eingabewerten gehört und nicht zu denen davor?
Vermutlich gibst du mit einer Taktflanke die Eingabedaten auf die 
Eingänge, und liest bei der nächsten Taktflanke das Ergebnis aus 
(jeweils mittels FlipFlops)? Dann macht die Toolchain das automatisch, 
vorausgesetzt, sie weiß, wie schnell der Takt ist, was in der UCF-Datei 
angegeben werden kann. Wenn deine kombinatorische Logik länger braucht 
um die Eingabe zu verarbeiten als ein Takt dauert, gibts Timing Errors 
am Ende des Place&Route bzw. in der Ausgabe der maximal möglichen 
Frequenz wird eine niedrigere angegeben.
>Ach ja: Wie ist das dann, wenn ich "vorgefertigte" Komponenten, wie z.B.
>einen hardware multiplier (Spartan3E) einbinde. Muss/kann ich da warten?
Die Dinger sind sehr schnell, wie schnell steht im Datenblatt. Wenn du 
die inferierst - also einfach "c <= a * b;" schreibst, wird der 
Hardware-Block ja automagisch verwendet, und die Toolchain errechnet 
genau wie bei normaler Logik ob er schnell genug ist.

Zur Division guggst du da:
http://www.lothar-miller.de/s9y/categories/24-Division

von Florian R. (flo0815)


Lesenswert?

Danke für die schnelle Antwort!


>Ich hoffe, du meinst damit: Du hast eine komplizierte ("tiefe")
>kombinatorische Logik beschrieben - also einen Haufen LUT's - deren
>Ausgänge direkt das Ergebnis in Abhängigkeit von den Eingängen ausgeben?

Das hoffe ich auch:
1
entity DIVIDER is
2
--------------------------------------------------------------------
3
    Port ( Divisor_DIV  : in  STD_LOGIC_VECTOR(17 downto 0);
4
           Dividend_DIV : in STD_LOGIC_VECTOR(17 downto 0);
5
        Quotient_DIV : out STD_LOGIC_VECTOR(17 downto 0);
6
           Start_DIV   : in  STD_LOGIC;
7
        Finished_DIV : out STD_LOGIC);
8
end DIVIDER;
9
--------------------------------------------------------------------
10
--------------------------------------------------------------------
11
architecture Behavioral of DIVIDER is
12
13
begin
14
15
  Pdiv: process(Start_DIV)
16
  
17
  variable topbit   : INTEGER RANGE -1 TO 17;
18
  variable temp    : STD_LOGIC_VECTOR (18 downto 0);
19
  variable quot     : STD_LOGIC_VECTOR (17 downto 0):=(others => '0');
20
  
21
  begin
22
  
23
    Finished_Div <= '0';
24
  
25
    if Start_DIV='1' and Start_DIV'event then
26
    
27
      if Divisor_DIV > Dividend_DIV then
28
      
29
        Quotient_DIV <= (others => '0');
30
      
31
      else
32
        
33
        if divisor_DIV = "000000000000000000" then
34
        
35
          quotient_DIV <= "111111111111111111";
36
          
37
        else
38
        
39
          -- Find leftmost non-zero digit of divisor and save in variable topbit
40
          topbit := -1;
41
          for i in 17 downto 0 loop
42
            if divisor_DIV(i) = '1' then 
43
              topbit := i;
44
              exit;
45
            end if;      
46
          end loop;
47
          
48
          -- Do division algorithm.
49
          temp := "0"&dividend_DIV;
50
          for i in 18-(topbit+1) downto 0 loop
51
            if temp(topbit+i+1 downto i) >= "0"&divisor_DIV(topbit downto 0) then
52
              temp(topbit+i+1 downto i) := (temp(topbit+i+1 downto i))-("0"&divisor_DIV(topbit downto 0));
53
              quot(i):='1';
54
            end if;
55
           end loop;
56
           
57
           quotient_DIV <= quot;
58
          
59
        end if;
60
          
61
      end if;
62
    
63
    end if;
64
    
65
    Finished_DIV <= '1';
66
    
67
  end process;
68
69
end Behavioral;

>Vermutlich gibst du mit einer Taktflanke die Eingabedaten auf die
>Eingänge, und liest bei der nächsten Taktflanke das Ergebnis aus
>(jeweils mittels FlipFlops)?

Keine Ahnung, mach ich das? Ich setze die Signale Divisor_DIV und 
Dividend_DIV, danach setze ich Start_DIV<='1' und warte auf eine 
steigende Flanke auf Finished_DIV. Meine Frage ist, ob ich dieses 
triggern und warten auf Bestätigung immer machen muss, wenn ich auch 
tatsächlich das aktuelle Ergebnis und nicht das des letzten Durchgangs 
haben will.

Danke übrigens für den Link. Werde mir das mal genauer anschauen.

Gruß
Flo

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


Lesenswert?

Ein Tipp an einen Anfänger: du brauchst keine for-Schleife.
Sie macht etwas ganz anderes, als du erwartest...  :-o

>> Vermutlich gibst du mit einer Taktflanke die Eingabedaten ...
> Keine Ahnung, mach ich das?
Nein, schlimmer: du hast gar keinen Takt, sondern einen Dividierer 
kombinatorisch beschreiben... :-/
Geh einfach mal davon aus, dass du mit deiner Beschreibung einen 
riesengroßen kombinatorischen Multiplexer gebaut hast:
1
          for i in 18-(topbit+1) downto 0 loop  
2
            if temp(topbit+i+1 downto i) >= "0"&divisor_DIV(topbit downto 0) then     
3
               -- das ist ein Mega-Multiplexer
4
              temp(topbit+i+1 downto i) := (temp(topbit+i+1 downto i))-("0"&divisor_DIV(topbit downto 0));    
5
              quot(i):='1';
6
            end if;
7
           end loop;

Das wird sich nicht in Hardware abbilden lassen:
1
          for i in 18-(topbit+1) downto 0 loop  ...
Denn du kannst für die Synthese nur einen statischen Bereich für die 
for-Schleife angeben...
Du wirst diesen Dividierer also bestenfalls simulieren können. Manchen 
reicht das  ;-)

> Muss ich warten,...
Ja, das Ding ist unglaublich kompilziert (wenn du es mal übersetzt 
bekommst), und die Synthese wird dir dafür dann eine recht lange 
Laufzeit bescheinigen. Die mußt du abwarten.
Und: auf dein
1
Finished_DIV <= '0';
2
:
3
Finished_DIV <= '1';
kannst du dich nicht verlassen. Die Synthese wird dieses Signal einfach 
fest auf '1' legen, weil die letzte Zuweisung im Prozess gewinnt (ein 
Prozess wird in der theoretischen Zeit 0 abgearbeitet).

von Florian R. (flo0815)


Lesenswert?

Also, danke für die umfangreiche Antwort. Hast mir gerade mehr 
brauchbare Hinweise und v.a. Verständnishilfen gegeben, als ich in 
diversen Tutorials gefunden habe. Das mit der For-Schleife hab ich schon 
befürchtet.

Ich war so frei, und habe nun den Divisions-Algorithmus von deiner 
Homepage benutzt. Das ist für eine Semesterarbeit. Wäre das für dich in 
Ordnung, wenn ich den Algorithmus benutze - selbstverständlich 
wissenschaftlich korrekt mit Quellen/Autorenangabe?

Ich denke das mit dem Takt habe ich jetzt zumindest grob verstanden. Ein 
anderes Modul habe ich jetzt als FSM geschrieben. Da kann ich sauber auf 
den Dividierer warten und kann halbwegs nachvollziehen was passiert 
(oder nicht passiert :-)).

Noch eine Frage: Gibt es empfehlenswerte Literatur, die eben auf die 
Synthetisierbarkeit eingeht? Über VHDL gibt es ja zeugs wie Sand am 
Meer, aber ich habe praktisch nichts mit praktischen Hinweisen für die 
Synthese gefunden.

Nochmal vielen Dank.

Gruß
Flo

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


Lesenswert?

> Ich war so frei, und habe nun den Divisions-Algorithmus von deiner
> Homepage benutzt. Das ist für eine Semesterarbeit. Wäre das für dich in
> Ordnung, wenn ich den Algorithmus benutze - selbstverständlich
> wissenschaftlich korrekt mit Quellen/Autorenangabe?
Wie üblich eben... ;-)

> Noch eine Frage: Gibt es empfehlenswerte Literatur, die eben auf die
> Synthetisierbarkeit eingeht?
VHDL-Synthese von Reichardt&Schwarz

von Florian R. (flo0815)


Lesenswert?

Sehr gut. Danke!

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.