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ß
"Ä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.
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.
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)
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)
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.
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?
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
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.
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!
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.
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
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.
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?
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.
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.
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...
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.
1
derive_pll_clocks
2
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:
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.
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.
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.
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.
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.
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.
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.
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"
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.
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.