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
>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 derFPGA-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.
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
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
>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.
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
@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
@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
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
Sooo... mit mehr FFs kommen auch mehr IOB-FFs heraus.
Mein Code sah bisher (grob zusammengestueckelt) in etwa so aus:
1
entitylcd_ctrlis
2
Port(
3
clk:instd_logic;
4
red:outstd_logic_vector(5downto0);
5
green:outstd_logic_vector(5downto0);
6
blue:outstd_logic_vector(5downto0);
7
h_sync:outstd_logic;
8
v_sync:outstd_logic;
9
enable:outstd_logic
10
);
11
endlcd_ctrl;
12
13
architectureBehavioraloflcd_ctrlis
14
15
signalred_i:unsigned(5downto0):="000001";
16
signalgreen_i:unsigned(5downto0):="000100";
17
signalblue_i:unsigned(5downto0):="010000";
18
signalh_sync_i:std_logic:='0';
19
signalv_sync_i:std_logic:='0';
20
signalenable_i:std_logic:='0';
21
...
22
signalline:integerrange0to806-1:=0;
23
...
24
begin
25
26
process(clk)
27
begin
28
ifrising_edge(clk)then
29
30
ifline<TFT_V_SYNCthen
31
v_sync_i<='0';
32
line_data<='0';
33
elsifline<TFT_V_SYNC+TFT_V_PORCH_BACKthen
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
ifrising_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
endif;
11
endprocess;
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?
>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
ifrising_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
ifline<TFT_V_SYNCthen
13
v_sync_i<='0';
14
line_data<='0';
15
elsifline<TFT_V_SYNC+TFT_V_PORCH_BACKthen
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.
@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
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
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
>ifrising_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
>ifline<TFT_V_SYNCthen
13
>v_sync_i<='0';
14
>line_data<='0';
15
>elsifline<TFT_V_SYNC+TFT_V_PORCH_BACKthen
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
> 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
ifrising_edge(clk)then
5
ifline<TFT_V_SYNCthen
6
v_sync_i<='0';
7
line_data<='0';
8
elsifline<TFT_V_SYNC+TFT_V_PORCH_BACKthen
9
v_sync_i<='1';
10
line_data<='0';
11
:
12
elsif...
13
:
14
:
15
endprocess;
16
17
process(clk)
18
begin
19
ifrising_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
endprocess;
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