Ich arbeite mit verschiedenen Chips von Lattice mit Lattice Diamond und
hätte gerne etwas Orientierung, welche Constraints für asynchrone Inputs
notwendig sind. Mir geht es weniger um einen spezifischen Fall als eher
um ein "how to it right".
Leider ist die Dokumentation von Lattice spärlich bis nicht vorhanden
bzw. das was ich gefunden habe enthält nicht wirklich praktische
Beispiele.
Eine gute Quelle diesbezüglich, die auch auf Lattice spezifische Details
eingeht, wäre wirklich hilfreich.
Für asynchrone Eingänge verwende ich typischerweise einen zweistufigen
Synchronizer (asynchrones Eingangssignal: input, synchronisiertes
Ausgangssignal: output(1)):
1 | process(clk, rst)
|
2 | begin
|
3 | if rst='0' then
|
4 | output <= (others => '0');
|
5 | elsif rising_edge(clk) then
|
6 | output <= output(0) & input;
|
7 | end if;
|
8 | end process;
|
Die Eingangssignale sind sehr unterschiedlich und reichen von
mechanischen Inputs (weniger als 1 Flanke pro Sekunde) zu read/write
Handshake Signalen eines parallelen Memory Bus, die nur einige Sample
Clock Cycles lang sind.
Die Fragen die ich mir Stelle sind:
- Muss ich hier keep Attribute im Code verwenden damit die Toolchain die
Flipflops nicht wegoptimiert? Falls ja, wie würden diese aussehen?
- Wie verhindere ich, dass bei hohem Fanout die Flipflops dupliziert
werden, insbesondere das erste Flipflop output(0)? Gibt es dafür
überhaupt eine Möglichkeit?
- Welche Timing Constraints benötige ich bzw. benötige ich überhaupt
welche? Muss ich den Einfang als false path definieren?
Was passiert mit Eingängen, die im Constraint File weder als false path
definiert sind, noch setup/hold constraints haben? Werden die einfach
als asynchron angenommen und in der STA ignoriert?
- Habe ich irgendwelche Constraints übersehen die notwendig wären?