Ich möchte eine komplizierte Übertragungsfunktion zur Wiederverwertung
in unterschiedlichen Schaltungen vorbereiten. Die Funktion kommt aus
einem MATLAB oder EXCEL, das die Werte Y(X)) erzeugt und hat z.B. 16 Bit
auf 16 Bit. Ureigentlich wird eine Kennlinie verbogen, z.B. leicht
logarithmisch gemacht.
Eine Möglichkeit ist, sie per COE bei power up in ein RAM zu schieben,
was bereits gelungen ist und auch funktioniert. Da es sich aber um eine
teils als Interpolationsfunktion genutzte Ü-Kennline handelt, hat sie
Lücken. Diese sind dynamisch und von der Funktion abhängig.
D.h. es gibt X-Werte die nicht definiert sind. Das macht etwa 30% des
Speichers aus. Bei den neuen 18 Bit-Versionen sind es aber schon 40%.
Ich würde gerne das RAM sparen und es als Kombinatorik bauen lassen.
Nach meiner Vorstellung braucht er dazu für jedes Bit eine Schaltung mit
maximal 16 Eingängen, also eine klassische UND-ODER-Struktur.
Angelegt habe ich das hier:
1
case to_integer (unsigned(inp_dat)) is
2
3
when 0 => out_sqr <= 0 ;
4
when 1 => out_sqr <= 512 ;
5
when 2 => out_sqr <= 724 ;
6
when 3 => out_sqr <= 887 ;
7
when 4 => out_sqr <= 1024 ;
8
when 5 => out_sqr <= 1145 ;
9
when 6 => out_sqr <= 1254 ;
10
when 7 => out_sqr <= 1355 ;
11
when 8 => out_sqr <= 1448 ;
12
when 9 => out_sqr <= 1536 ;
13
when 10 => out_sqr <= 1619 ;
14
when 11 => out_sqr <= 1698 ;
15
when 12 => out_sqr <= 1774 ;
Das file wird mit einem Script direkt erzeugt und wäre sehr elegant
nutzbar, um verschiedene Versionen zu machen, die austauschbar sind.
Leider baut die Synthese eine geschlagene Ewigkeit, bis sie damit fertig
ist und schob es anfänglich trotzdem in ein RAM. Das habe ich ihm mit
USE BRAM 0 abgewöhnt und versucht, das zu bauen, aber selbst nach 2h
kommt kein Ergebnis.
Woran könnte das liegen?
Gibt es einen besseren Weg?
Messtechniker schrieb:> 16 Bit auf 16 Bit.
Dir ist klar wie viele Bits das sind? 2^16 Werte willst du abbilden auf
2^16 andere Werte.
Messtechniker schrieb:> aber selbst nach 2h kommt kein Ergebnis.
Was sagt denn deine Toolchain zu den Ressourcen? Werden schon >100% der
LUTs gebraucht? Das P+R kann sehr lange dauern wenn das FPGA voller
wird.
BRAM dafür ideal geeignet. Aber eine Tabelle aus 2^16 Einträgen mit je
16 Bits sind eben 1 MBit Speicher den du brauchst.
Der andere übliche Weg ist den Algorithmus zur Berechnung in Hardware zu
bauen, dann brauchst du da keine Tabelle ablegen.
Und wenn das nicht geht, dann kann man auch nur Teile der Tabelle
ablegen. Also z. B. jeden 8ten oder 2^nten Wert. Wenn man dazwischen was
braucht muss man interpolieren.
Messtechniker schrieb:> Ich würde gerne das RAM sparen und es als Kombinatorik bauen lassen.
Kombinatorik wird im FPGA nicht mit und-oder Struktur implementiert
sondern ebenfalls über RAM ( nur eben über das distributed RAM der LUTs
statt über das BlockRAM deines ersten Ansatzes). wenn du gleich viele
Stützwerte speichern willst, wirst du gleich viel RAM brauchen.
die Verschwendung des RAMs kommt daher, das du nicht für alle 2**n
Stützwerte verwendest. wenn du es schaffst, die tatsächlich benutzen
Adressen auf einen kleineren (dicht belegten) Adressraum abzubilden,
kannst du darüber die Verschwendung von Ram vermeiden.
Messtechniker schrieb:> Gibt es einen besseren Weg?
wird dein Signal wirklich noch besser, wenn du die Ausgleichskurve mit
2**18 stützstellen speicherst (statt 2**16 stützstellen zu nehmen und zu
interpolieren)
Achim S. schrieb:> ie Verschwendung des RAMs kommt daher, das du nicht für alle 2**n> Stützwerte verwendest. wenn du es schaffst, die tatsächlich benutzen> Adressen auf einen kleineren (dicht belegten) Adressraum abzubilden,
Nein, das geht leider nicht.
Gustl B. schrieb:> Der andere übliche Weg ist den Algorithmus zur Berechnung in Hardware zu> bauen, dann brauchst du da keine Tabelle ablegen.
Es gibt keine analytische Lösung dafür. Die Tabelle ist Ergebnis von
Berechnung und Messung. Diese wiederum ist die Folge von physikalischen
Dreckeffekten und sieht bei jedem System anders aus.
Gustl B. schrieb:> Dir ist klar wie viele Bits das sind? 2^16 Werte willst du abbilden auf> 2^16 andere Werte.
Ganz richtig.
Wie schon dargestellt, müsste jedes der 16 Ergebnis-Bits eine eigene
Schaltung bekommen, die von 16 Eingängen abhängig ist. Also sowas wie:
E(0) = A(15) and (not A(14)) and A(13) and A(11) ... A(0);
E(1) = (not A(15)) and (not A(14)) and A(12) ... A(1);
u.s.w.
Jede der 16 Gleichungen hat also maximal 16 Eingänge. Dabei kann es noch
ein Not geben. In den PLDs haben wir das immer als Matrix programmiert.
Das kann eigentlich so groß nicht werden, meine ich. Wenn eine LUT 6
Eingänge hat, braucht man 16x2 / 6 = 6 Stück und dann noch 1-2 dahinter
um diese 6 ersten zu ver-und-en. Oder ist da ein Denkfehler?
Hatte die Synthese abgebrochen und simuliere das jetzt nochmals durch.
Eventuell baue ich es auch erst einmal kleiner zum Testen.
Du willst nunmal insgesamt 2^16 mal 16 Bit speichern. Wenn ein Großteil
dieser Information redundant wäre (weil z.B. viele benachbarte
Stützstellen ähnliche Werte haben, dann lässt sich das reduzieren (indem
es "komprimiert" gespeichert wird). Aber die Größenordnung der
abgespeicherten Informationsmenge zur Ausgleichstabelle wird bei 128
kByte bleiben - egal ob in BlockRAM oder in LUTs gespeichert.
Messtechniker schrieb:> Das kann eigentlich so groß nicht werden, meine ich. Wenn eine LUT 6> Eingänge hat, braucht man 16x2 / 6 = 6 Stück und dann noch 1-2 dahinter> um diese 6 ersten zu ver-und-en. Oder ist da ein Denkfehler?
Das mit dem Denkfehler trifft zu. Eine LUT hat 6 Eingänge. Wenn du 7
Eingänge abdecken willst, brauchst du 2 LUTs. Für 8 Eingänge sind es 4
LUTs, für 9 Eingänge 8 LUTs (alles nur rein rechnerisch, real
funktioniert das mit der Potenzierung nur auf kleiner Skala).
Wenn du 16 Eingangsbits abdecken willst brauchst du als 2^(16-6) = 1024
LUTs, um ein Ausgangsbit zu erzeugen. Und die müssten ja noch
entsprechend zusammengeführt und verdrahtet werden. Das Ergebnis siehst
du an deinen aktuellen Implementierungsversuchen.
Ich wiederhole nochmal, was ich oben schrieben habe:
Achim S. schrieb:> wird dein Signal wirklich noch besser, wenn du die Ausgleichskurve mit> 2^18 stützstellen speicherst (statt 2^16 stützstellen zu nehmen und zu> interpolieren)
Steckt in deiner Tabelle tatsächlich so viel Information über einen
"echten" Kurvenverlauf? Unterscheiden sich bei 2^16 (oder sogar 2^18)
Stützstellen die Wert benachbarter Stützstellen wirklich deutlich und
kannst du den Unterschied tatsächlich bis auf 16 (oder gar 18) Bit
Auflösung bestimmen? Oder reicherst du die Übertragungsfunktion in
Wirklichkeit nur noch mit Rausch-Information an, die dein Messergebnis
real gar nicht mehr verbessert?
Falls du wirklich glaubst, die volle Tabelleninformation nutzen zu
können und zu wollen: spendiere das notwendige RAM dafür. Du wirst
nichts besseres finden, um Messwerttabellen zu speichern, als RAM. Wenn
das interne RAM nicht ausreichen sollte, nutze ein größeres FPGA oder
spendiere ein externes RAM.
Achim S. schrieb:> Wenn> das interne RAM nicht ausreichen sollte, nutze ein größeres FPGA oder> spendiere ein externes RAM.
Und als Nachtrag: wenn du tatsächlich auf externen Speicher setzen
solltest, muss das natürlich kein RAM sein. Als externen Speicher kannst
du die Speichertechnologie deiner Wahl einsetzen (z.B. auch einen Flash,
in dem deine Kalibrierwerte gespeichert sind).
Messtechniker schrieb:> Wie schon dargestellt, müsste jedes der 16 Ergebnis-Bits eine eigene> Schaltung bekommen, die von 16 Eingängen abhängig ist.
Nein. Denn du bildest ja nicht 16 Bits auf 16 Bits ab, sondern 2^16
Werte zu je 16 Bits auf 2^16 Werte zu 16 Bits. Und außerdem sind deine
Ausgangsbits doch keine Funktion der Eingangsbits. Du brauchst also
Speicher.
Und zwar 1 Mbit. Das haben nur größere FPGAs als LUTRAM. Bei BRAM auch
in der unteren Mittelklasse schon möglich.
Messtechniker schrieb:> Hatte die Synthese abgebrochen und simuliere das jetzt nochmals durch.
Interessant wäre jetzt der genaue FPGA in den das rein soll.
Simulationen bringt da nicht so viel, aber du kannst ja mal gucken was
im RTL Viewer draus gebaut wird. Und dann kannst du spaßeshalber mal ein
dickes FPGA einstellen und gucken was die Synthese macht. P+R kannst du
weglassen.
Messtechniker schrieb:> Das habe ich ihm mit> USE BRAM 0 abgewöhnt und versucht, das zu bauen, aber selbst nach 2h> kommt kein Ergebnis.
Ich bin mal den umgekehrten Weg gegangen: Die Tools haben immer versucht
den ROM-Inhalt (=Lookup-Table) als Logikgleichung zu optimieren. Jedes
Ausgangsbit ist eine Logikfunktion mit 2^n Eingängen. Als der
Synthesizer gezwungen wurde, das in den Block-RAM zu packen lief die
Synthese gleich viel schneller.
Duke
So, habe nochmal ein Bier gehabt und das Hirn durchgespült und ja,
natürlich gibt es wesentlich mehr, als nur jeweils 16(x16) Kombinationen
gültiger und-Verknüpfungen, die man verodern muss.
Die Netzliste hat für den Fall 16 inzwischen auch synthetisiert und ist
erwartungsgemäß gewaltig.
Gleichwohl gibt es Gründe das so zu machen, zumindest für die kleineren
Korrekturfunktionen.
Daher mal zur anderen Frage:
Davon ausgehend, ich habe ein synthetisiertes Ergebnis (Vivado kann ein
SCH aufmachen, oder die Implementierung) ... wie kann ich diese
Netzliste schnappen und als LIB-file hinterlegen, um es später in ein
VHDL hineinzudroppen?
Die 16 Eingänge stimmen schon aber die Gleichungen können ja beliebig
kompliziert sein. Es gibt nicht nur eine Kombination der 16 Eingänge
sondern theoretisch JEDE, Also für a(15) alle darunter und not a(15)
auch. Das sind 2hochN Gleichungen. Entsprechend viele LUTs werden
benötigt.
Hallo vielleicht wäre diese LUT-IP etwas:
https://www.xilinx.com/content/dam/xilinx/support/documents/ip_documentation/v_gamma_lut/v1_1/pg285-v-gamma-lut.pdf
Generell macht das Optimieren solcher Tabellen nur Sinn, wenn man
weniger als 30%, besser nur 20% Füllung hat, weil das ja letztlich ins
distributed RAM kommt und damit wichtige Resourcen wegfrisst. Der
Synthesizer steckt das obendrein auf Wunsch am Ende doch noch in ein
BRAM und dann ist man genau so weit. Etwaige Optimierungen an den
Adressen kann er dann ja auch berücksichtigen - das muss also nicht
vorab oder per Hand gemacht werden.
Wo ich mit einer solche Strategie Erfolg hatte, ist mein
Frequenz-Zähler-Core:
Der kann pro Kaskade jeweils durch 1,2,3 ... 9,10 teilen und einen Sinus
generieren. Die dazu nötigen Stützstellen purzeln auf die benötigten
ganzzahligen Vielfachen der Adressen zusammen. Mit einer Dichte von
Faktor 7x4 (empirisch ermittelt) komme ich auf eine Zahl, die in der
Nähe einer Binärzahl liegt und ein RAM weitgehend nutzt, wenn man einen
Viertelbogen einschreibt. Das reicht (bei nur einem BRAM) für einen sehr
guten DDS-Sinus.
Für die Abbildung solcher Spezialkorrekturfunktionen wo sich mehrere
Effekte addieren, ist es ansonsten eher lohnend auf Approximation zu
setzen und mit stückweisen, diskreten Annäherungen zu arbeiten.