Forum: FPGA, VHDL & Co. Timing constraints: OFFSET?


von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Hallo allerseits!

Wie schon im Thread "Takt ausgeben" (gibt's ne Moeglichkeit nen 
huebschen Link zu setzen wie zu Artikeln?) geht es um einen 
TFT-Controller mit 64Mhz Pixelclock im Spartan-3A. Ich habe nun mit 
einigen Zaehlern meine Synchronisationssignale erzeugt und in der 
Simulation sieht auch alles gut aus soweit. Nur eine Kleinigkeit ist mir 
aufgefallen: Skew zwischen den verschiedenen Datenleitungen und 
Verzoegerung aller Datenleitungen gegenueber dem Taktausgang (DDR-FF).

Zwar liegen alle diese Werte weeeeeit im gruenen Bereich fuer meine 
Anwendung (laut post-route simulation 0.5ns Skew zw. Daten und 1.5ns 
Verzoegerung zum Takt, bis zu ca. 4 ns waere OK wenn ich das Datasheet 
von meinem TFT richtig lese), aber ich frage mich wie ich dieses Timing 
in User Constraints giessen kann. Ich habe ein bisschen im Xilinx 
Constaints Guide 
<http://toolbox.xilinx.com/docsan/xilinx9/books/docs/cgd/cgd.pdf>; 
gelesen, aber wirklich verstanden habe ich das nicht alles.

Mit "OFFSET" kann ich die Verzoegerung zwischen einem Clock-Eingang und 
meinen Datenein-/ausgaengen festlegen. Das ist fuer synchone Design 
sicher wichtig, aber was mich interessiert ist das Verhaeltnis von 
Clock-*Aus*gang zu Datenausgaengen. Kann ich das auch festlegen? Oder 
haengt das nur von meinem Design ab?

Gruesse,
Sebastian

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


Lesenswert?

>gibt's ne Moeglichkeit nen huebschen Link zu setzen wie zu Artikeln?
Ja, einfach indem du die URL zu dem
Beitrag "Timing constraints: OFFSET?"
in den Text reinkopierst.

>Verhaeltnis von Clock-*Aus*gang zu Datenausgaengen.
Richtig, der constraint heißt OFFSET OUT (clock to pad)
Mit OFFSET OUT kannst du angeben, wieviel später das mit dem FPGA-Takt 
getaktete Signal am Ausgangspin stabil sein muss. Das macht Sinn, wenn 
du den FPGA-Takt extern zum Einlesen des Signals in ein Register (z.B. 
auch Schieberegister) verwendest.

Allerdings ist dein Takt-Ausgang offenbar nicht der FPGA-Takt, sondern 
ein daraus abgeleitetes Signal (nennen wir es Clock). Deshalb musst du 
den Clock-Ausgang auf den FPGA-Takt constrainen und genauso den 
Datenausgang. Mir fällt jetzt auf Anhieb keine Möglichkeit ein, ein 
Signal auf ein beliebiges anderes Signal (Daten auf Clock) zu 
beziehen...

Am einfachsten wird es sein, die Daten und den Clock vor der Ausgabe 
noch einmal mit dem FPGA-Takt zu synchronisieren. Dann wird dafür das FF 
im IO-PAD verwendet, und du hast den minimal möglichen Zeitversatz in 
den Signalen. Allerdings noch keinen Bezug von den Daten zum Clock...
                                                |
                                           FPGA | Platine
                                                |
           Daten ----------[IOB-Reg]------------O----
             ^                ^      OFFSET OUT |
  FPGA-Takt--+----------------|                 |
             v                v      OFFSET OUT |
           Clock ----------[IOB-Reg]------------O----
                                                |


Du könntest allerdings den nach aussen gehenden Clock noch zum 
Synchronisieren der Daten am FPGA-Ausgang (im FPGA) verwenden. Dann 
könntest du diese Daten wieder auf den Clock constrainen.
                                           |
                                      FPGA | Platine
                      (IOB-Reg)            |
           Daten -----[Register]-----------O----
             ^            ^     OFFSET OUT |
  FPGA-Takt--+            |                |
             v            |                |
           Clock ---------+----------------O----
                                           |

Aber wehe, wenn ich auf das Ende sehe...
Das Problem ist dann nämlich die Übernahme der Daten mit Clock ins 
Register.

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Ok, das kann ich nachvollziehen. Die getakteten IOB-FFs wuerden genau 
das machen was ich will. Die Sache mit den getakteten IOB-FFs hat auch 
Joko/Jochen in Beitrag "Re: Takt ausgeben" schon 
angesprochen.
Ich gebe den selben Takt aus den ich auch fuer meine Logik verwende, 
ueber ein DDR-FF (OFDDRCPE). Die Datenausgaenge setze ich in einem 
Process abhaengig von der selben Clock. Ich bin einfach mal davon 
ausgegangen das ISE das schon so einrichten wird, scheint aber ja nicht 
der Fall zu sein. Wie kann ich das in umsetzen, muss ich da irgendwelche 
Xilinx-Blackboxen instanziieren oder klappts einfach mit der richtigen 
Beschreibung in VHDL?

Ich werde mal ausprobieren ob ich das "OFFSET OUT" Constraint hinbekomme 
und wie es sich auswirkt...

Sebastian

von Joko (Gast)


Lesenswert?

Hi Sebatian,

  da DDR-FlipFlop muß (leider) instanziiert werden - eine 'behavioral' 
Beschreibung verstehen dir Synthese-Tolls nicht...

Offset-Out ist das richtige constraint, um die Schaltung auf dem PCB 
"sicher" zum Laufen zu bringen - allerdings wird es Dir eine etwas zu 
pessimistische Angabe liefern:
der OFFSET bezieht sich nämlich immer auf den verwendeten Clock-Eingang 
(also den Pin, der Deinen FPGA mit dem Takt versorgt).

Hieraus folgt (wenn die FFs mit der steigenden Flanke betrieben werden:
 a) Datenausgänge ändern sich IRGENDWANN zwischen "0ns" und "Offset Out 
der Daten" nach der steigen Flanke am Clock-Eingangs-Pin

 b) Dein Clock-Eingang ändert sich IRGENDWANN zwischen "0ns" und "Offset 
Out des Clocks" nach der steigen Flanke am Clock-Eingangs-Pin

aus a) und b) folgt, daß - wenn dein externer Baustein mit der 
steigenden Flanke arbeiten - Du beim Ändern der Datenbits eine fallende 
Flanke am Clockpin erzeugen solltest (-> Einstellung der 
D0,D1-Eingänge), da Du ANDERNFALLS nicht sicherstellen könntest, daß die 
Daten stabil sind, wenn die Clock eine steigende Flanke hat.

Also:
  - Daten und fallende Clockflanke gleichzeitig
  - Offset-Out so setzen, daß steigende Flanke
        (mit theoretisch 0 ns Versögerung)
    SICHER NACH dem 'Einschwingen (Offset-Out max. der Daten) passiert

  => dies ist eine "worst case" Annhame und eigentlich zu pessimistisch:
    die minimal möglichen 'offset out' liegen Erfahrungsgemäß bei 1/3 
der
    maximalen - aber das garantiert Dir niemand

   die ISE 11.1 soll angeblich ein neues constraint einführen, mit dem 
man
   diese sog. 'Source-Synchronen' Interfaces genauer beschreiben kann!
    (warten wir's mal ab)

Gruß
Jochen

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


Lesenswert?

>der OFFSET bezieht sich nämlich immer auf den verwendeten Clock-Eingang
>(also den Pin, der Deinen FPGA mit dem Takt versorgt).
War ja auch die ursprüngliche Denkweise. Da gab es einen Board-Takt, mit 
dem das ganze Design versorgt wird (so die Idee). Und auf diesen Takt 
beziehen sich alle Komponenten vor und nach dem FPGA, deshalb muss sich 
auch das Constraint auf diesen Takt beziehen.

Wenn aber intern Takte erzeugt werden (Haarsträubender Taktgenerator 
oder DCM & Co) kann ich durchaus auf diese internen Takte auch 
constrainen.

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Danke fuer die Antworten!

Ich glaube ich habe das soweit alles verstanden, korriegert mich wenn 
ich falsch liege :-)

Das OFFSET Constraint richtet sich nach einem Clock-Input-Pin am FPGA. 
Mein Takt sieht so aus: 16 Mhz von extern (moechte ich nicht aendern 
weil auf Evaluationboard aufgeloetet) werden in DCM vervierfacht (der 
externe Takt wird fuer nichts ausser dem DCM verwendet). Der 
vervierfachte Takt wird fuer die interne Logik benutzt und ausgegeben 
fuer das TFT.

Ich kann nun ja ueber die DCM dafuer sorgen das mein interner Takt in 
Phase mit dem externen ist. Aber er ist immer noch viermal zo schnell. 
Funktioniert das OFFSET Constraint fuer diesen Fall?

Jochen:
Du schreibst von DDR-FFs. Solch eines habe ich fuer die Taktausgabe 
verwendet. Aber wie ist es mit den Daten? Wenn ich den Takt wie im 
anderen Thread besprochen invertiere kann ich fuer die Daten doch die 
normalen IOB-FFs benutzen und brauche kein double data rate. Da die 
Daten eine halbe Periodendauer haben um "aussen anzukommen", was ich ja 
offenbar ueber das OFFSET OUT Constraint sicherstellen kann. Meine Frage 
war nun wie ich diese normalen IOB-FFs in VHDL einbaue. Habt ihr da 
vielleicht ein Beispiel parat? Das ist wahrscheinlich eine relativ doofe 
Frage... hab ich aber noch nie gemacht und bin etwas ratlos wie ich das 
anstellen muss...

Vielen Dank!
Sebastian

von Joko (Gast)


Lesenswert?

@Sebastian

> Das OFFSET Constraint richtet sich nach einem Clock-Input-Pin am FPGA.
ja

>Funktioniert das OFFSET Constraint fuer diesen Fall?
ja

>Du schreibst von DDR-FFs. Solch eines habe ich fuer die Taktausgabe
>verwendet.
gut

>Aber wie ist es mit den Daten? Wenn ich den Takt wie im
>anderen Thread besprochen invertiere kann ich fuer die Daten doch die
>normalen IOB-FFs benutzen und brauche kein double data rate.
genau

> Meine Frage war nun wie ich diese normalen IOB-FFs in VHDL einbaue.
hatte ich falsch verstanden

> Habt ihr da vielleicht ein Beispiel parat?
- ganz 'normales' - process mit rising_edge(..)
- der Ausgang dieser FFs dann direkt auf den Port geben
- ISE (map) sagen, daß es die IOB-FFs verwenden soll
   (default ist 'nein')
- im FPGA-Editor (irgenwo gibt's auch nen report, aber ich verwende
   immer den FPGA-Editor) nachsehen, daß die IOB-FFs auch wirklich
   verwendet wurden

Gruß
Jochen

von Joko (Gast)


Lesenswert?

@Lothar Miller

> Wenn aber intern Takte erzeugt werden (Haarsträubender Taktgenerator
> oder DCM & Co) kann ich durchaus auf diese internen Takte auch
> constrainen.

ich teste es nicht mit JEDER ISE-Version - vielleicht geht's ja mit
irgendeiner...
(Glaub' ich aber nicht, da mir dieses Feature erst für die 11.1 in
Aussicht gestellt wurde)

In den Versionen, die ich auf dieses Feature getestet habe, hieß es
immer, daß das Clock-Netz, auf das ich mich beziehen wollte, kein
PAD sei  => ERROR

Gruß
Jochen

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Hi,

allmaehlich wird die Sache etwas klarer.

Joko wrote:
[Benutzung von IOB-FFs]
>> Habt ihr da vielleicht ein Beispiel parat?
> - ganz 'normales' - process mit rising_edge(..)
Benutze ich.

> - der Ausgang dieser FFs dann direkt auf den Port geben
Ist auch erfuellt.

> - ISE (map) sagen, daß es die IOB-FFs verwenden soll
>    (default ist 'nein')
Die unter "Map Properties" steht bei mir "Pack I/O Registers/Latches 
into IOBs" = "For Inputs and Outputs" (war auch per Defualt so, ISE 
9.2i). Ich vermute du meinst diese Einstellung.

> - im FPGA-Editor (irgenwo gibt's auch nen report, aber ich verwende
>    immer den FPGA-Editor) nachsehen, daß die IOB-FFs auch wirklich
>    verwendet wurden
Aus dem FPGA-Editor werd ich nicht schlau, aber im Map Report steht 
folgendes:
1
Total Number of 4 input LUTs:             60 out of   7,168    1%
2
  Number used as logic:                 41
3
  Number used as a route-thru:          19
4
  Number of bonded IOBs:               27 out of     195   13%
5
    IOB Flip Flops:                     3
6
  Number of ODDR2s used:                1
7
    Number of DDR_ALIGNMENT = NONE      1
8
  Number of GCLKs:                     2 out of      24    8%
9
  Number of DCMs:                      1 out of       4   25%

3 IOB-FFs sind etwas wenig bei 20 Ausgaengen um die es geht... mal sehen 
ob ich eine Moeglichkeit finde das zu verbessern. Vorschlaege?

Sebastian

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Sooo... mit mehr FFs kommen auch mehr IOB-FFs heraus.

Mein Code sah bisher (grob zusammengestueckelt) in etwa so aus:
1
entity lcd_ctrl is
2
  Port ( 
3
   clk :     in    std_logic;
4
  red :     out  std_logic_vector (5 downto 0);
5
   green :     out  std_logic_vector (5 downto 0);
6
   blue :     out    std_logic_vector (5 downto 0);
7
   h_sync :   out    std_logic;
8
   v_sync :   out    std_logic;
9
   enable :   out    std_logic
10
  );
11
end lcd_ctrl;
12
13
architecture Behavioral of lcd_ctrl is
14
15
   signal red_i:     unsigned (5 downto 0) := "000001";
16
   signal green_i:   unsigned (5 downto 0) := "000100";
17
   signal blue_i:   unsigned (5 downto 0) := "010000";
18
   signal h_sync_i:   std_logic := '0';
19
   signal v_sync_i:   std_logic := '0';
20
   signal enable_i:   std_logic := '0';
21
...
22
  signal line:        integer range 0 to 806-1 := 0;
23
...
24
begin
25
26
  process(clk)
27
  begin
28
    if rising_edge(clk) then
29
    
30
      if line < TFT_V_SYNC then
31
        v_sync_i <= '0';
32
        line_data <= '0';
33
      elsif line < TFT_V_SYNC+TFT_V_PORCH_BACK then
34
        v_sync_i <= '1';
35
        line_data <= '0';
36
...
37
38
red <= std_logic_vector(red_i);
39
green <= std_logic_vector(green_i);
40
blue <= std_logic_vector(blue_i);
41
h_sync <= h_sync_i;
42
v_sync <= v_sync_i;
43
enable <= enable_i;

Das ergibt 3 IOB-FFs.

Kleine Aenderung fuer mehr FFs:
1
process(clk)
2
begin  
3
  if rising_edge(clk) then
4
      red <= std_logic_vector(red_i);
5
      green <= std_logic_vector(green_i);
6
      blue <= std_logic_vector(blue_i);
7
      h_sync <= h_sync_i;
8
      v_sync <= v_sync_i;
9
      enable <= enable_i;
10
  end if;
11
end process;

Dies ergibt 21 IOB-FFs, passt genau zur Anzahl der AUsgaenge dieses 
Entities. Mit ist aber nicht klar wieso das einen Unterschied macht. Die 
erste Variante hat doch auch schon ein process(clk), wieso wird das 
nicht in IOB-FFs verwandelt?

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


Lesenswert?

>Meine Frage war nun wie ich diese normalen IOB-FFs in VHDL einbaue.
Das macht die Toolchain automatisch, wenn du keine Kombinatorik nach dem 
letzten FF einbaust. Deine Zuweisungen (vermutlich concurrent) hatten 
offenbar noch Kombinatorik drin.

Wenn du z.B.
>  red <= std_logic_vector(red_i);
in jedem Zweig der if-Abfrage einen Wert zuweist, bekommst du 
Kombinatorik (Mux), kein FF.

So wäre es auch gegangen, den Takt Latency hast du jetzt sowieso...
1
:
2
  process(clk)
3
  begin
4
    if rising_edge(clk) then
5
      red <= std_logic_vector(red_i);
6
      green <= std_logic_vector(green_i);
7
      blue <= std_logic_vector(blue_i);
8
      h_sync <= h_sync_i;
9
      v_sync <= v_sync_i;
10
      enable <= enable_i;
11
    
12
      if line < TFT_V_SYNC then
13
        v_sync_i <= '0';
14
        line_data <= '0';
15
      elsif line < TFT_V_SYNC+TFT_V_PORCH_BACK then
16
        v_sync_i <= '1';
17
        line_data <= '0';
18
:
19
:

@ Joko
Richtig...   :-(
>An OFFSET specification must use a pad signal to designate the clock.

von Joko (Gast)


Lesenswert?

@Sebastian

> Mit ist aber nicht klar wieso das einen Unterschied macht.

eben deshalb verwende ich immer den FPGA-Editor
(Einarbeitung lohnt sich wirklich !)
-> Reports (mit "map -detail -pr b" würde das .mrp file
      sagen, wo welches IOB-FF verwendet wurde)
   sagen einem zwar, was los ist, geben einem aber seltenst
   auch den Grund dafür an.

   Mit dem Fpga-Editor läßt sich sehr genau sehen, ob es
   einen konkreten Grund gibt, daß etwas nicht so gemacht
   werden konnte/wurde, wie gedacht.
   Irren ist halt menschlich - man übersieht manchmal auch einfache
   Zusammenhänge - als da wären (bei Dir trifft aber wohl nix zu)

   - die FFs wurden als Input-FFs verwendet:
       Input-Pad -> FF -> Output-Pad
         => beide möglich
   - das gewählte aoutput-Pad liegt in einem Tile, das bereits
       ein FF verwendet, das mit einer anderen Clock getaktet wird
   - die Synthese hast (für besserers timing) die FFs 'nach vorne'
     verschoben
   - Das ucf-file oder der VHDL-Code verwendet das attribute IOB-false
   etc.

Gruß
Jochen

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Lothar Miller wrote:
> Wenn du z.B.
>>  red <= std_logic_vector(red_i);
> in jedem Zweig der if-Abfrage einen Wert zuweist, bekommst du
> Kombinatorik (Mux), kein FF.
Das ergibt natuerlich Sinn... habe ich nicht bedacht.

Ohne Constraints aber mit IOB-FFs habe ich sowohl Skew als auch Delay 
von deutlich unter 100ps in der Post-Route Simulation (die 
komischerweise jetzt 10x so lange dauert). Scheint tatsaechlich einen 
gigantischen Unterschied zu machen. Damit bin ich dann auch fuer 
moegliche zukuenftige Anforderungen an genaueres Timing gewappnet.

In dieser Anwendung brauche ich diese Praezision zwar nicht zwingend, 
aber mein Verstaendnis von FPGAs hat's auf jeden Fall weiter gebracht. 
Vielen Dank euch beiden. Wird sicher nicht lange dauern bis mir die 
naechste Frage einfaellt ;-)

Den FPGA-Editor werde ich mir auch nochmal ansehen... vielleicht 
entdecke ich ja irgendwann die Bedeutung der vielen bunten Kaestchen ;-)

Viele Gruesse aus dem fernen Osten,
Sebastian

von Joko (Gast)


Lesenswert?

der FPGA-Editor ist nicht bunt - das is der Floorplanner (den
verwende ich auch nicht - zu schwierig)
der Editor ist (fast) selbsterklärend..

ansonsten

http://toolbox.xilinx.com/docsan/xilinx10/help/iseguide/mergedProjects/fpga_editor/whskin_homepage.htm

Gruß
Jochen

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Hallo nochmal...
habe natuerlich schon die naechste Frage :-)

Lothar Miller wrote:
> So wäre es auch gegangen, den Takt Latency hast du jetzt sowieso...
>
1
> :
2
>   process(clk)
3
>   begin
4
>     if rising_edge(clk) then
5
>       red <= std_logic_vector(red_i);
6
>       green <= std_logic_vector(green_i);
7
>       blue <= std_logic_vector(blue_i);
8
>       h_sync <= h_sync_i;
9
>       v_sync <= v_sync_i;
10
>       enable <= enable_i;
11
> 
12
>       if line < TFT_V_SYNC then
13
>         v_sync_i <= '0';
14
>         line_data <= '0';
15
>       elsif line < TFT_V_SYNC+TFT_V_PORCH_BACK then
16
>         v_sync_i <= '1';
17
>         line_data <= '0';
18
> :
19
> :
20
>

Habe den Code einem bekannten gezeigt. Der meinte (beispielsweise) 
enable und enable_i im selben Takt zu setzen waere unsauber.

Ich bin davon ausgegangen das das der voellig normale Weg ist FFs zu 
erzeugen, da sich Zuweisungen auf Signale immer(?) erst im naechsten 
Takt des process() auswirken. Oder kann es da Probleme geben wenn z.B. 
das Taktsignal wg. Routing zu unterschiedlichen Zeiten ankommt? Ist dies 
der richtige Weg FFs zu erzeugen oder gibt es einen besseren?

Se-dergernallesrichtigmachenwill-bastian

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


Lesenswert?

> Der meinte (beispielsweise)enable und enable_i
> im selben Takt zu setzen waere unsauber.
Falsch, die werden ja sowieso mit dem selben Takt gesetzt.

Evtl. hat der Mensch den selben Prozess gemeint?
Dann ist er wahrscheinlich einer von denen, die nach Quellcode-Zeilen 
abrechnen uund lieber etwas mehr hinschreiben, als nötig ist. So könnte 
man das bei exakt gleichem Ergebnis natürlich auch schreiben:
1
:
2
  process(clk)
3
  begin
4
    if rising_edge(clk) then
5
      if line < TFT_V_SYNC then
6
        v_sync_i <= '0';
7
        line_data <= '0';
8
      elsif line < TFT_V_SYNC+TFT_V_PORCH_BACK then
9
        v_sync_i <= '1';
10
        line_data <= '0';
11
        :
12
      elsif...
13
      :
14
      :
15
  end process;
16
17
  process(clk)
18
  begin
19
    if rising_edge(clk) then
20
      red <= std_logic_vector(red_i);
21
      green <= std_logic_vector(green_i);
22
      blue <= std_logic_vector(blue_i);
23
      h_sync <= h_sync_i;
24
      v_sync <= v_sync_i;
25
      enable <= enable_i;
26
  end process;
27
:
28
:

> Ich bin davon ausgegangen das das der voellig normale Weg ist FFs zu
> erzeugen, da sich Zuweisungen auf Signale immer(?) erst im naechsten
> Takt des process() auswirken.
Richtig, diese Denkweise stimmt.

> Oder kann es da Probleme geben wenn z.B.
> das Taktsignal wg. Routing zu unterschiedlichen Zeiten ankommt?
Nein, denn FPGAs sind so aufgebaut, dass der Takt an allen FFs 
gleichzeitig ankommt. Sonst würde es kein synchrones (das heißt 
zeitgleiches) Design geben. Die FPGA-Hersteller sorgen mit nicht wenig 
Aufwand dafür, dass jedes geschriebene rising_edge(clk) gleichzeitig 
ausgeführt wird. Siehe dazu auch den Beitrag 
http://www.mikrocontroller.net/articles/Taktung_FPGA/CPLD

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.