mikrocontroller.net

Forum: FPGA, VHDL & Co. Brainstorming Syntheselaufabhängiges Verhalten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bräuchte mal ein paar Ideen, vielleicht wisst ihr ja was.

Das Design um das es sich handelt ist ein Softcore.
Darauf läuft ein Programm.
Das Programm läuft auch auf einer PC Simulation mit dem gleichen 
Befehlssatz, fehlerfrei.

Der FPGA Softcore jedoch macht regelmäßig Probleme und zwar "verrechnet" 
er sich dann. Die genaue Ursache rauszufinden ist recht schwierig, 
jedoch war es mehrmals so, das einem Register ein Wert zugewiesen wurde 
und dieses Register im nächsten Takt als Zieladdresse für eine Lese- 
oder Schreiboperation genutzt wird. Nur das es die genutzte Adresse 
nicht gibt. Danach klemmt der Bus.

Jetzt aber das merkwürdige: es ist komplett Buildabhängig.
Etwa 2/3tel aller FPGA Builds zeigen diesen Verhalten nicht. Diese 
funktionieren dauerhaft, egal ob warm, kalt, auch über Tage hinweg.

Bei 1/3tel aller Builds ist das Verhalten da.
Und zwar absolut reproduzierbar für den jeweiligen Build!
Der Prozessor hängt immer an der gleichen Stelle, er verrechnet sich 
immer auf die gleiche Art und Weise in der gleichen Codezeile.
Beim nächsten "kaputten Build" verrechnet er sich woanders.
Beim gleichen Programm im Debugmodus(leicht anderer Assembler Code) 
verrechnet er sich woanders.

Bei Builds, in denen er sich schon früh im Programm verrechnet habe ich 
die Simulation bis dahin laufen lassen, welche wie erwartet tadellos 
funktioniert.

Das Design ist vollständig constraint, es gibt im gesamten Core keinen 
Taktübergang und es ist "weit weg" von jedem Pin. Das Timing ist 
erfüllt, wenn auch immer äußerst knapp.

Der Füllstand des FPGAs macht keinen Unterschied, der Fehler tritt bei 
30% Füllstand und bei 90% Füllstand gleichermaßen auf.
Retiming an oder aus bewirkt keinen Unterschied.

Der Fehler tritt sowohl mit Quartus 11 als auch 18.1 auf.


Hat noch jemand eine Idee was ich versuchen kann?
Ich bin mittlerweile ratlos.


Danke und Gruß

: Bearbeitet durch User
Autor: Vancouver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Äußerst knapp" könnte schön das Problem sein. Ein wenig Clockjitter, 
und schon gehts schief. Versuch mal, beim Clock 10% Overconstraining und 
schau, was herauskommt. bzw kannst du die Frequenz verringern? Ist das 
ein kommerzieller Core, oder opensource? Normalerweise sind solche 
Probleme immer auf ein Timingproblem zurückzuführen.

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:
> Und zwar absolut reproduzierbar für den jeweiligen Build!
Auch auf unterschiedlichen FPGAs? Unabhängig davon, ob du ein Reload 
initierst oder einen (partiellen) Reset machst?

> Hat noch jemand eine Idee was ich versuchen kann?
Sieh dir mal den Reset-Pfad an.

> jedoch war es mehrmals so, das einem Register ein Wert zugewiesen wurde
> und dieses Register im nächsten Takt als Zieladdresse für eine Lese-
> oder Schreiboperation genutzt wird.
Kann dazwischen jemand auf den Bus gehen (Interrupt, DMA, Injected 
Code...)?

> Hat noch jemand eine Idee was ich versuchen kann?
Ich würde auch mal so ein reproduzierbar "defektes" Design einfach mit 
der halben Taktfrequenz laufen lassen.

Vancouver schrieb:
> "Äußerst knapp" könnte schön das Problem sein. Ein wenig Clockjitter,
> und schon gehts schief.
Oder wenn ein Schlauer steigende und fallende Flanken verwendet und der 
Takt z.B. mit 60/40 ein wenig asymmetrisch ist.

: Bearbeitet durch Moderator
Autor: blub (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du den sourcecode parat? Lade ihn bitte hoch, dann lässt sich die 
Quelle des Timingproblems möglicherweise identifizieren (zB Asynchrones 
Verhalten in der Alu oder sowas)

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank schonmal für die Denkanstöße.

Also tippt ihr auch am ehesten auf Timing.

Den Takt zu verringern wird nicht so einfach, weil sehr viele 
Komponenten dran hängen die dann nicht mehr funktionieren. 
Overcontraining kann ich versuchen, mal sehen was die Synthese schafft.

Ansonsten kann ich mal einen zusätzlichen, halbierten Takt aus der PLL 
holen, nur den Core damit betreiben und schauen ob der Fehler dann 
überhaupt jemals auftritt.
Würde mich nicht so sehr stören das einfach eine Weile so zu nutzen.


Lothar M. schrieb:
> Auch auf unterschiedlichen FPGAs? Unabhängig davon, ob du ein Reload
> initierst oder einen (partiellen) Reset machst?

Habe leider nur das eine Board zum testen.
Ein vollständiger Reset ist nicht möglich, kann nur den Core 
zurücksetzen.
Register welche dieser schon geschrieben hat sind nicht rücksetzbar. 
Entsprechend ist das Verhalten je nach Fall nicht immer identisch 
zwischen neu runterladen und nur Core resetten.

Lothar M. schrieb:
> Kann dazwischen jemand auf den Bus gehen (Interrupt, DMA, Injected
> Code...)?

An sich nicht. Das ASM-Binary wird über den Bus ins RAM transportiert, 
aber nach dem einschalten des Cores kommt da nichts mehr.
Was aber sein kann, ist das sich das Zeitverhalten unterscheidet, weil 
z.b. Zugriffe aufs SDRam vom Core aus unterschiedlich lange dauern 
können wegen Refresh. Hängt dann davon ab wann ich den Core einschalte, 
nicht vom Build.

Lothar M. schrieb:
> fallende Flanken

Sind alles steigende.

blub schrieb:
> Hast du den sourcecode parat? Lade ihn bitte hoch, dann lässt sich die
> Quelle des Timingproblems möglicherweise identifizieren (zB Asynchrones
> Verhalten in der Alu oder sowas)

Hab es mal angehangen, ich bezweifle allerdings das man da so einfach 
etwas findet.
Die Logik, welche versagt, befindet sich zudem konsequent in einem 
getakteten Prozess. (execute stage)

Autor: Stormy Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:

> Hat noch jemand eine Idee was ich versuchen kann?
Die allokierten M9K-Blöcke manuell zuweisen, manchmal ist einer davon 
madig.
Signaltap rausschmeissen.

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Signaltap nutze ich nicht. Der Fehler tritt auch nicht in Zusammenhang 
mit Blockram auf.

Trotzdem Danke!

Autor: blub (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach ein Testprogramm (benchmark sozusagen) und wenn Fehler auftauchen 
gib sie aus

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Können wir mal dein Constraints-File sehen?

'vollständig constrained' muß ja nicht heißen, dass das alles richtig 
ist.

Hast Du Taktübergänge im Design?

Autor: Stormy Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:

> blub schrieb:
>> Hast du den sourcecode parat? Lade ihn bitte hoch, dann lässt sich die
>> Quelle des Timingproblems möglicherweise identifizieren (zB Asynchrones
>> Verhalten in der Alu oder sowas)
>
> Hab es mal angehangen, ich bezweifle allerdings das man da so einfach
> etwas findet.

Das ist ja auch nur ein Teil des Sources, zum nachvollziehen braucht es 
noch das constraintfile (*.sdc) und das settingfile (*.qpf) sowie alle 
anderen built-scripte aus denen ersichtlich ist welche settings aktiv 
sind.
Und natürlich sollte man alle logfiles durchgelesen haben, da findet 
sich oft die entscheidende Warning. (*.rpt in /outputs o.ä.)


>Der Prozessor hängt immer an der gleichen Stelle, er verrechnet sich
>immer auf die gleiche Art und Weise in der gleichen Codezeile.
>Beim nächsten "kaputten Build" verrechnet er sich woanders.
Klingt nach einem Programmspeicher-ROM problem. Verschieb mal mit nem 
Linkerscripte das codesegment und schau ob das Problem mitwandert.
Anderes Board verwenden wäre auch ne Idee. VHDL-rumgestochere würde ich 
da erst mal lassen, frag mal einen Embedded Softwareheini wie man 
Probleme mit bestimmten Codezeilen eingrenzt. 
https://www.mikrocontroller.net/forum/gcc

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich verwende keinen gcc, sondern meinen eigenen Compiler und kenne daher 
den ausgeführten Code bis auf die Instruktion runter.

Mit Codezeile ist hier CPU Instruktion gemeint. Welche fehlschlägt sehe 
ich recht einfach daran, das der Bus hängt, damit die CPU hängt, ich den 
ProgramCounter auslesen kann und per Debugger auch weiß wie die Register 
stehen.

Der Programmspeicher(SRAM + Blockram Cache) ist ok.
Zum einen weil ich den zurückgelesen habe, zum anderen wenn ich die 
Instruktion die zum Aufhängen führt (read/write register from/to bus) 
gegen eine unverfängliche ersetze (move register), dann läuft es weiter 
und ich sehe das er an eine Murx Adresse schreiben wollte.

Markus F. schrieb:
> Können wir mal dein Constraints-File sehen?
> Hast Du Taktübergänge im Design?

Ist angehangen. Allerdings schon auf 18ns Period statt 20, auch wenn es 
leider nichts gebracht hat.

Das Timing ignore habe ich deshalb drinne, weil ein Pfad von 100 nach 
108 Mhz natürlich nichts wird und ich deshalb jeden Übergang selbst 3 
mal eintakte oder über Dualclock Blockrams führe.

Taktübergänge habe ich auch nur Richtung VGA und Audio, beides schließe 
ich hierfür aus, weil kein Zugriff auf Register aus dem Bereich passiert 
wenn es crasht.

Autor: VHDL-Polizei (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Sowas:
               if (cache_write_done = '1') then
                  cache_write_enable <= '0';
                  stall_pipe         <= '0';
                  request_cmd_exe    <= '1';
               end if;
         
               if (cache_read_done = '1') then
                  result            <= signed(cache_read_data);
                  cache_read_enable <= '0';
                  stall_pipe        <= '0';
                  request_cmd_exe   <= '1';
               end if;

ist immer schlecht, weil keine Priorisierung vorliegt. Wenn beide 
Signale gleichzeitig kommen kriegt man da schnell einen deadlock. Kann 
aber nicht sagen, ob hier sowas vorkommen kann.

Immer ELSIF nehmen!

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Werden CLOCK2_50 und CLOCK3_50 nur für die PLL genutzt?
Was hängt an clk12 dran?

Duke

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle Input Clocks sind 50Mhz und gehen direkt in eine PLL.

Aus der ersten werden 100 Mhz für nahezu das ganze FPGA gemacht sowie 
120° versetzte 100 Mhz für die SDRam Clock.

Aus Clock2_50 werden 108 Mhz für VGA
Aus Clock3_50 werden 12 MHz für Audio


@  VHDL-Polizei:

Danke. Das elsif schreibe ich absichtlich nicht, weil der Cache nur eine 
Operation gleichzeitig ausführen kann.

Bei einem elsif würde der Pfad für "result" länger werden,
natürlich nur falls die Synthese nicht merkt das nicht beides 
gleichzeitig auftreten kann und es selbst optimiert.
Der "result" Pfad ist kritischste im ganzen Core.

Mir ist klar, das der Code vielleicht schwieriger zu verstehen ist, weil 
ich vom Überschreiben der Signale an späterer Stelle im Code regen 
Gebrauch mache.

Autor: VHDL-Polizei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:
> weil
> ich vom Überschreiben der Signale an späterer Stelle im Code regen
> Gebrauch mache.

eine super Strategie, um gut lesbaren Code zu erzeugen ...

und sich dann selber darin zu verfangen

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Ich persönlich finde das
a <= '0'
if (b = '1') then
   a <= '1';
end if;

besser lesbar als das.
if (b = '1') then
   a <= '1';
else
   a <= '0'
end if;

Gerade für Signale die nur einen Takt aktiv sein sollen finde ich es 
sehr übersichtlich die am Anfang eines Prozesses definiert auf inaktiv 
zu setzen und später zu überschreiben wenn nötig.

Mir ist aber schon klar dass das kein allgemeiner Konsens ist, deswegen 
mache ich sowas auch nur in einem Hobbyprojekt was ich voraussichtlich 
eh nur alleine ankucke. Auf Arbeit schreibe ich solchen Code nicht.

Genau das war aber meine Befürchtung wenn ich meinen Code hier 
einstelle: das der Stil kritisiert wird, auch er mit dem Problem absolut 
nichts zu tun hat.

In einem synchronen Prozess kann ich schreiben was ich will, das 
Syntheseergebnis sollte nicht vom Seed des Fitters abhängig sein.

Habe den Code eigentlich nur eingestellt, damit man sieht ob der 
betroffene Code weder asynchrone Berechnungen drin hat, noch 
Taktübergänge oder sonstiges was sonst Probleme machen könnte.
Vielleicht wäre ja jemandem noch ein Konstrukt aufgefallen das 
(syntheselaufabhängige) Probleme machen könnte, mir aber noch unbekannt 
ist.

Autor: Gustl B. (-gb-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verwende auch die erste Variante.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein .sdc-File, das keine set_[input|output]_delay Statements enthält, 
würde ich nicht als vollständig constrained erachten (und Quartus meines 
Wissens nach auch nicht).
Immerhin hängt ja anscheinend (zumindest) RAM dran (natürlich weiss ich 
nicht, ob das beim beschriebenen Problem überhaupt eine Rolle 
spielt/spielen kann).

Das '\gcores' erweckt den leisen Verdacht, das wir hier potentiell von 
einer per generate erzeugten Mehrkern-Implementierung reden?

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, sind 12 von den Schätzchen drin. Aktiv ist aber nur der erste bei 
diesem Problem hier.
Hatte auch schon überlegt den Code auf den Anderen laufen zu lassen, 
wäre aber ein großer Umbau im FPGA, weil es bestimmte Register gibt, an 
die nur der Erste darf, festverdrahtet.
Meine Testskripte prüfen alle Cores, da ist bisher leider(?) noch kein 
Fehler aufgetreten, nur bei den tatsächlichen Programmen. Wie das halt 
so ist...

Bin da aber auch dran. Habe extra eine Sammlung von "kaputten" Binaries 
auf die ich einen neuen Satz von Tests loslassen will.

Markus F. schrieb:
> Ein .sdc-File, das keine set_[input|output]_delay Statements enthält,
> würde ich nicht als vollständig constrained

So gesehen stimmt das natürlich, ich nutze "nur" IO-FFs für die externen 
Komponenten. Hier ist sicher potenziell ein Risiko das etwas schief 
geht. In Frage kommt aber nur das SRAM, alles andere ist nicht 
Ausführungsrelevant.
Auf der anderen Seite sollten IO-FFs keine Schwankungen erlauben.

Habe im qsf zusätzlich fürs SRAM stehen:

- set_global_assignment -name FMAX_REQUIREMENT "100 MHz" -section_id 
sram
- set_instance_assignment -name CLOCK_SETTINGS sram -to sram_*
- set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to sram_*
- set_instance_assignment -name FAST_INPUT_REGISTER ON -to sram_*
- set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to 
sram_*


DENNOCH: beim durchsehen gerade ist mir aufgefallen, das mein sram_wren, 
trotz alledem nicht in einem Output-FF gelandet ist. Dem werde ich mal 
nachgehen. Denn auch wenn das wohl eher nicht für das akute Problem 
verantwortlich ist, sollte das nicht sein.

Autor: Markus F. (mfro)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Robert P. schrieb:
> - set_global_assignment -name FMAX_REQUIREMENT "100 MHz" -section_id
> sram

Achtung, ab jetzt Mutmassung:

Das sind Anweisungen an den alten "Classic"-Timing-Analyzer (und 
entsprechend dem Fitter). Würde mich wundern, wenn das in 18.1 noch 
funktioniert.

Ich glaube, das ist irgendwann nach der 9er-Version verschwunden. 
Zumindest die älteren Quartus-Versionen haben die Project-Files noch 
automatisch migriert, ob die neueren das noch tun, weiss ich nicht.

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, das SRAM-Design stammt ursprünglich aus 2010 von einem alten Cyclone 
2 mit Quartus 9, hab das nie mehr wesentlich angepasst.

Ehrlich gesagt weiß ich gar nicht warum das überhaupt noch drin ist.
Eigentlich sollte das 100 Mhz Contraint auf dem sdc, was ja auch für die 
SRAM Pins/IOFF gilt, ausreichen.

Andersherum gefragt: wie würden deine Contraints da aussehen?

Ich gebe zu, mit Constraints habe ich es nicht so. Versuche eigentlich 
immer die Logik so zu schreiben das ein allgemeines Clock Constraint 
reicht und die Tools sich den Rest daraus selbst errechnen, schon wegen 
der Portierbarkeit.

Hier kann es aber sein das es nicht reicht...

Autor: Markus F. (mfro)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Ich würde erst mal die PLL-Clocks nicht "von Hand" definieren. Sonst 
vergisst Du (ich jedenfalls) garantiert bei der nächsten Änderung in der 
PLL die constraints nachzuziehen.
derive_pll_clocks
derive_clock_uncertainty

reicht (und Du kannst die set_clock_uncertainty- und 
create_generated_clock- Zeilen rausschmeissen).

Dann sollte für die SRAM-clock m.E. eine virtuelle clock her und die 
SRAM I/Os set_input_delay und set_output_delay-Statements bekommen (das 
ist doch synchones SRAM, oder?).

bei mir sieht das (hier für ein DDR-RAM Interface) so aus:
set period [expr roundto(1000.0 / 33.0, 3)]

create_clock -period $period -name CLK_MAIN [get_ports {CLK_MAIN}]
create_clock -period $period -name virt_clk_main_in
create_clock -period $period -name virt_clk_main_out

set_clock_groups -asynchronous \
                 -group { I_PLL1|altpll_component|auto_generated|pll1|clk[1] } \
                 -group { I_PLL1|altpll_component|auto_generated|pll1|clk[2] } \
                 -group { I_PLL1|altpll_component|auto_generated|pll1|clk[3] } \
                 -group { I_PLL1|altpll_component|auto_generated|pll1|clk[4] } \
                 -group { i_ddr_pll|altpll_component|auto_generated|pll1|clk[0] \
                          i_ddr_pll|altpll_component|auto_generated|pll1|clk[1] \
                          i_ddr_pll|altpll_component|auto_generated|pll1|clk[2] \
                          i_ddr_pll|altpll_component|auto_generated|pll1|clk[3] \
                          i_ddr_pll|altpll_component|auto_generated|pll1|clk[4] \
                          virt_clk_main_in \
                          virt_clk_main_out \
                          CLK_MAIN } \
...

# constrain DDR writes
set_output_delay -clock virt_clk_ddr_out -max 0.5 [get_ports VD[*]]
set_output_delay -clock virt_clk_ddr_out -min -0.25 [get_ports VD[*]] -add_delay 
set_output_delay -clock virt_clk_ddr_out -max 0.5 -clock_fall [get_ports VD[*]] -add_delay
set_output_delay -clock virt_clk_ddr_out -min -0.25 -clock_fall [get_ports VD[*]] -add_delay

# set false paths for opposite edge data transfers (rising -> falling and falling -> rising) that Quartus
# Timing Analyzer would (falsely) check (and badly miss timing) by default otherwise
set_false_path -setup -rise_from i_ddr_pll|altpll_component|auto_generated|pll1|clk[3] -fall_to virt_clk_ddr_out
set_false_path -setup -fall_from i_ddr_pll|altpll_component|auto_generated|pll1|clk[3] -rise_to virt_clk_ddr_out
set_false_path -hold -rise_from i_ddr_pll|altpll_component|auto_generated|pll1|clk[3] -rise_to virt_clk_ddr_out
set_false_path -hold -fall_from i_ddr_pll|altpll_component|auto_generated|pll1|clk[3] -fall_to virt_clk_ddr_out


Die clock groups sind eine "Abkürzung" für set_false_path. Clocks in 
einer Gruppe müssen zusammen betrachtet werden, Clocks in 
unterschiedlichen Gruppen betrachtet der Timing Analyzer nicht.
Passt natürlich für SRAM nicht, aber vielleicht kannst Du ja was damit 
anfangen.

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Danke!

>> derive_pll_clocks

Das klingt gut, werde ich so machen inklusive den clock groups.

>> derive_clock_uncertainty

Das habe ich auch gefunden, aber als tcl command im timing analyzer 
eingegeben. Der hat mir dann die Zeilen im sdc erzeugt. Wusste nicht das 
man es auch direkt ins sdc schreiben kann.
Jetzt wirds mir aber auch klar: im sdc stehen einfach die tcl commands 
drin...

>> das ist doch synchones SRAM

leider nein, Asynchrones mit 10ns Zugriffszeit. Im Moment halte ich dort 
eh die Timings ein, indem ich einen Takt länger warte, was effektiv 
~20ns Lesezeit statt 10ns sind. Zusammen mit IOFF sollte das dann völlig 
unproblematisch sein.

Genau 10ns einzuhalten sind ja kaum machbar, ein bischen Schwankung 
zwischen den Addressleitungen ist immer und alles zwischen 50 und 100Mhz 
wird noch aufwändiger hinterher, wenn die Daten wieder auf 100 Mhz 
müssen.


Ein synchrones SDRam habe ich auch noch, aber das dient nur als 
Framebuffer und läuft fehlerfrei mit IOFF + 120° verschobenen 200Mhz auf 
toggle FF -> 100 Mhz.
Damit hatte ich erst Probleme als ich noch die 100 Mhz ohne IOFF mit 
Delays rausgegeben habe, deshalb würde ich da ungerne hin zurück.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:
>>> das ist doch synchones SRAM
>
> leider nein, Asynchrones mit 10ns Zugriffszeit. Im Moment halte ich dort
> eh die Timings ein, indem ich einen Takt länger warte, was effektiv
> ~20ns Lesezeit statt 10ns sind. Zusammen mit IOFF sollte das dann völlig
> unproblematisch sein.

Ich würde zumindest die Adress- und Datenleitungen mit set_output_delay 
constrainen und das 'Ausgabefenster' so 'zusammenziehen', um 
sicherzustellen, dass die Bus-Bits einigermassen gleichzeitig und nicht 
'irgendwann' am RAM ankommen.

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, habe jetzt mal die write_enable Leitung mit Output Delay constraint. 
So:
set_output_delay -clock { iPLL|altpll_component|auto_generated|pll1|clk[0] } -min 1 [get_ports {sram_wren}]
set_output_delay -clock { iPLL|altpll_component|auto_generated|pll1|clk[0] } -max 2 [get_ports {sram_wren}]

davon verspreche ich mir, das write_enable im Schreibfall immer NACH 
Adresse und Daten aktiv wird, so wie das Datenblatt das will.
Wobei mir noch nicht klar ist worauf ich Addr und Data jetzt setzen 
soll. -0.5 bis 0.5?

Ich will eigentlich gar kein Delay auf Addr/data beaufschlagen, die 
sollen einfach nur gleichzeitig raus kommen. Genau das habe ich mir von 
IO-FF ohne Delay versprochen: alle kommen immer zur gleichen Zeit raus, 
nämlich wenn die rising_edge vom Takt durch ist. Vorallem über alle 
Builds hinweg.
Wenn ich jetzt da explizit ein Output Constraint hinschreibe, riskiere 
ich nicht das er mir dann in jedem Build wieder etwas anderes hinbaut, 
nur um das constraint zu erfüllen?



Außerdem noch folgendes Problem: das constraint oben wird angenommen und 
taucht nicht in der Liste "ignored Comnstraints" auf.

Unter "Check timing" finde ich den Eintrag:
generated_io_delay  1

Soweit alles ok.

Wenn ich dann auf "Report all I/O Timings" gehe, dann steht da aber 
"nothing to report". In der Console dann jedoch:
Report Timing: Found 1 setup paths (0 violated).  Worst case slack is 
0.683
Report Timing: Found 1 hold paths (0 violated).  Worst case slack is 
8.006

Was im Moment schön und gut ist, aber spätestens wenn 2 constraints drin 
sind natürlich schwammig wird.

WO finde ich denn nun welches Output delay tatsächlich vorliegt für 
diesen Build und Pin?
Klar kann man der Analyse einfach glauben, aber ich würds gerne schon 
mal sehen was er gemacht hat.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast Du die "Timing-Driven Synthesis" (unter "Analysis/Synthesis 
settings) eingeschaltet?

Wenn nicht, haben die Timing-Constraints nur Kontrollfunktion und der 
Fitter interessiert sich nicht dafür.

Im Logfile sollte irgendwo "Timing-Driven Synthesis is running" 
erscheinen.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:
> Ich will eigentlich gar kein Delay auf Addr/data beaufschlagen, die
> sollen einfach nur gleichzeitig raus kommen.

Das machst Du ja mit set_output_delay auch nicht. set_output_delay sagt, 
dass die Signale vom Pin bis zum Port der externen Logik in Bezug auf 
die Clock eben minimal und maximal die Zeit brauchen, die Du angibst.
Gibst Du nichts an, geht der Fitter davon aus, dass die Signale "in 
Nullzeit" (also 0 Setup und eine Periode Hold) dort ankommen und hat 
alle Freiheiten.

set_output_delay "beschneidet" die Freiheitsgrade des Fitters, Du 
beschreibst damit die FPGA-Umgebung. Mit '-max' gibst Du die Setup-Zeit 
+ das Board delay zum Zielregister an (der Fitter weiss also, dass er 
die Signale entsprechend früher "losschicken" muss), -min ist dessen 
Hold-Zeit (Kommando an den Fitter: "nicht zu früh loslassen"). Wenn Du 
dieses Fenster 'enger' machst, hast Du eine feine Kontrolle darüber, wie 
die Signale dort ankommen. Wenn die Timing-Driving Synthese 
eingeschaltet ist, versucht der Fitter diese Vorgaben einzuhalten.

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja ist an.


Mir ist noch nicht klar von welchem Freiheitsgrad wir hier sprechen.

Annahme: IO-FF, mit steigender Taktflanke landet ein Vektor (sagen wir 
20 Bits/Pins) in diesen FFs, welche direkt am Pin liegen.

WIE soll der Fitter denn hier noch 2 ns Verzögerung zwischen den 
Einzelsignalen des Vektors einbauen?
Gibt es dafür extra Logik?

Er wird ja wohl nicht das Signal zurück ins FPGA schicken, dort ein 
bischen mäandern und danach erst raus.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:
> Annahme: IO-FF, mit steigender Taktflanke landet ein Vektor (sagen wir
> 20 Bits/Pins) in diesen FFs, welche direkt am Pin liegen.
>
> WIE soll der Fitter denn hier noch 2 ns Verzögerung zwischen den
> Einzelsignalen des Vektors einbauen?
> Gibt es dafür extra Logik?

Zunächst mal hilft dir das Constraining, erst mal rauszufinden ob und wo 
genau Du überhaupt ein Problem hast oder nicht (der Timing Analyzer muss 
dann nicht mehr raten, sondern **weiss** wirklich was).

Dann hast Du eine Clock, die (wahrscheinlich) über den Clock-Tree (also 
über spezielle, besonders schnelle Verbindungen geroutet wird - oder 
auch nicht). Auch hier kann der Fitter einen Umweg nehmen oder nicht. 
Auch kann er (aber auch Du selbst) mit deinen PLL's was tun(so denn dein 
Takt von einer PLL  erzeugt wird) - 'Clock compensation'.

Dann gibt's (nicht bei jedem FPGA, aber den Meisten) noch so hübsche 
Sachen wie den 'Output Enable Delay' oder 'Delay from Output Register to 
Output Pin' (schau' mal im Assignment Editor, was es da so alles gibt 
bzw. ins Device Handbuch, was dein Typ kann).
Die Frage ist hier m.E. eher "an welcher der vielen Schrauben dreh' ich 
für welches Problem"

Autor: Robert P. (fpgazumspass) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann arbeiten wir mal damit.
Wie würdest du das jetzt setzen für das SRAM?

Ich möchte eigentlich gerne folgendes:

Adresse, Daten und WE gleichzeitig setzen.
Laut Datenblatt ist das ok, man muss nur garantieren das WE definitiv 
nicht VOR Addr/data ankommt.

Vorher hat mein Design scheinbar nur funktioniert, weil WE nicht im IOFF 
war und deshalb leicht verzögert rauskam. Mit der Umstellung auf alles 
IOFF lief es nicht mehr. Warscheinlich war das damals Absicht es nicht 
ins IOFF zu tun, weiß ich nach 9 Jahren nicht mehr.

Nun will ich es fixen.
Ich habe jetzt WE auf +1/+2 (min/max) gesetzt. Damit läuft es erstmal 
wieder.

Meine Vorstellung ist jedoch, das ich auch Addr und Data constrainen 
sollte.
Mit -0.5 bis +0.5?
Kann man das machen?

Oder sollte ich auf 0-1 für Addr und Data und 2-3 für WE?
Möchte eigentlich das er Addr und Data garnicht "anfässt" und nur WE 
verzögert rausgibt.

Auch hier wüsste ich gerne warum es ohne Constraint nicht geht und mit 
schon. Leider erfahre ich nicht wie er das Delay jetzt tatsächlich 
erreicht hat.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert P. schrieb:
> Meine Vorstellung ist jedoch, das ich auch Addr und Data constrainen
> sollte.
> Mit -0.5 bis +0.5?
> Kann man das machen?

Da darf ich dir das hier: 
http://web02.gonzaga.edu/faculty/talarico/CP430/LEC/TimeQuest_User_Guide.pdf 
(das ist nicht der "echte" Link, es gab mal ein offizielles Wiki von 
Altera, aber das hat Intel sauber verbaselt, als sie die übernommen 
haben) wärmstens ans Herz legen.

Hat zumindest mir enorm geholfen, das Thema timing constraints 
wesentlich besser zu verstehen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.