Hallo Zusammen,
ich habe eine Sinustabelle mit 12-Werten à 12Bit in einem Blockram
liegen welche dann auf einen DAC geht. Nun benötige ich aber
unterschiedliche Amplituden, dieses Sinus-Signals, und bei 200MHZ ist
mir die Rechnerei zu komplex, zumal ich genügend BRAM übrig habe.
Die Idee ist also mehrere Sinustabellen hintereinander ins BRAM zu
legen. Beispielsweise:
Adresse 0-11 -> Amplitude 100%,
Adresse 12-23 -> Amplitude 95%,
Adresse 24-35 -> Amplitude 90%
Leider scheitere ich an der passenden Formulierung in VHDL.
Die ursprüngliche Sinustabelle erzeuge ich so:
Quartus gefällt das If-Statement wohl nicht...
Klar könnte ich jetzt zwei getrennte BRAMs machen, aber eig. wäre mir
zur einfacheren Adressierung ein einzelnes lieber.
Kann mir jemand auf die Sprünge helfen?
Besten Dank und viele Grüße,
Fabian
Alternativ könntest Du versuchen zwischen ROM-Tabelle und DAC noch einen
Multiplizierer unterzubringen. Bei 200 MHz braucht der vermutlich eine
Register-Pipeline.
Duke
VHDL-Starter schrieb im Beitrag #6663175:
> Quartus gefällt das If-Statement wohl nicht...
Der Vorschlag von Duke wäre auch mein erster Gedanke gewesen. Falls das
nicht funktioniert: mit "geschachtelten" generate statements könnte es
vielleicht gehen. Siehe S. 6 von
http://web.engr.oregonstate.edu/~traylor/ece474/vhdl_lectures/essential_vhdl_pdfs/essential_vhdl61-76.pdfVHDL-Starter schrieb im Beitrag #6663175:
> Nun benötige ich aber> unterschiedliche Amplituden, dieses Sinus-Signals, und bei 200MHZ ist> mir die Rechnerei zu komplex
Hat dein FPGA dsp-Cores? Bei meinen Anwendungen würde ich typischerweise
nur ein Sinus-RAM verwenden und einen dsp-Core mit Multiplikation zur
Amplitudenanpassung dahinter setzen. Gibt vielleicht ein paar Takte
Latenz, aber ich musste mir dabei noch in keinem Fall Sorgen machen, ob
der dsp-core die 200MHz schafft.
@Achim
ja das mit den DSP-Blöcken hatte ich auch schon überlegt. Ich versuche
aber noch, die Designs möglichst einfach zu halten, da mir die Erfahrung
einfach noch fehlt. Latenz wäre kein Problem... ich werde das mal
probieren, wenn die andere Version soweit funktioniert -> schöne
Lernaufgabe
VHDL-Starter schrieb im Beitrag #6663175:
> Und hier der fehlerhafte Versuch zwei Tabellen hintereinander generieren> zu lassen:
Das sollte so auch funktionieren. Nur hast du vergessen, deinen ROM Type
zu erweitern (immer noch als 0 to 11 definiert).
VHDL-Starter schrieb im Beitrag #6663175:
> und bei 200MHZ ist> mir die Rechnerei zu komplex, zumal ich genügend BRAM übrig habe.
Das ist nicht wirklich dein Ersnt?
Statt eine Multiplikation eine Masse an Speicher zu verwenden.
Das ist aber typisch Jungingenieur. Darf ich raten: Duale Hochschule /
Bachelor?
Wenn ein FPGA schnell genug ist, Daten aus einem RAM zu ziehen, was
meistenst Register kostet, um bis zum Ausgang zu kommen, dann packt er
auch einen Multiplikator, zumal die heute fest in den FPGA verbaut sind.
Kommentator schrieb:> Das ist aber typisch Jungingenieur. Darf ich raten: Duale Hochschule /> Bachelor?
Du glaubst nicht, was ich schon alles für Lösungen bei Altingenieuren
gesehen habe.
Es gibt einige die sich nicht (mehr) mit neuen Technologien
auseinandersetzen wollen oder können. Da wird dann ein TTL-Gattergrab
zusammengewürfelt, welches sich auch gut in einem CPLD abbilden lässt.
Vermutlich hat die Generation vorher ähnlich verächtlich auf die
IC-Nutzer geschaut und lieber diskrete Transistoren eingesetzt. Und
davor kamen die Röhren und vordem wurde Logik mechanisch realisiert.
Ist ja auch robuster, aber heute will keiner mehr die Feile in die Hand
nehmen...
Duke
Kommentator schrieb:> Wenn ein FPGA schnell genug ist, Daten aus einem RAM zu ziehen, was> meistenst Register kostet, um bis zum Ausgang zu kommen
Der TO nutzt nach eigenem Bekunden bereits ein Block-RAM für die
einfache Sinus-Tabelle. Für die einfache Sinustabelle belegt er darin
nur 12 Werte, für mehrere Sinustabellen mit unterschiedlichen Amplituden
wird einfach nur der ohnehin belegte RAM-Block besser ausgenutzt. Sein
Ansatz "kostet" ggf. weniger als die nachträgliche Multiplikation.
Wenn ein dsp-Multiplikator im FPGA vorhanden ist, hätte ich persönlich
auch den zur Amplitudenanpassung verwendet. Aber nur, weil ich das
offensichtlicher, intuitiver und feiner abstufbar finde als mehrere
Sinus-Tabellen ins BRAM zu stecken. Dass er als selbsterklärter
VHDL-Starter beide Lösungen ausprobieren will finde ich eher lobenswert
als dass man sich darüber mokieren müsste.
VHDL-Starter schrieb im Beitrag #6663175:
> Adresse 0-11 -> Amplitude 100%,> Adresse 12-23 -> Amplitude 95%,> Adresse 24-35 -> Amplitude 90%
Wenn es keine Platzprobleme im BRAM gibt, bietet es sich eventuell an,
die Adressen der Sinustabellen an Sechzehnergrenzen auszurichten. Dann
müssen nämlich die Adressbits nicht miteinander verrechnet werden,
sondern bleiben separat. Das spart dann eventuell eine LUT-Laufzeit.
Achim S. schrieb:> Der TO nutzt nach eigenem Bekunden bereits ein Block-RAM für die> einfache Sinus-Tabelle.
Was auch schon ein Fehler ist und auch kaum persistent, denn der
Synthesizer wird erkennen, dass er für eine 12-PUNKTE-Funktion besser
ein LUTRAM nehmen sollte, statt eines Block-RAMs und soforn das nicht
kommandiert ist, wird er dies auch tun :-)
Es sei denn, der TO hat die HW ausdrücklich instanziiert, statt es zu
inferieren und damit eben jenes altertümlich HW-Basteln appliziert, das
hier krtisiert wird:
Duke Scarring schrieb:> Da wird dann ein TTL-Gattergrab> zusammengewürfelt, welches sich auch gut in einem CPLD abbilden lässt.
Es ist allemal zweckmäßiger, die Funktion der Schaltung zu beschreiben,
statt die Struktur, abgesehen von sehr eindeutigen, alternativlosen
Realisationen, die der Synthesizer erst einbauen muss und damit mehr
Zeit benötigt.
Hier wird versucht, HW zu basteln, die sich komplett als Funktion
schreiben lässt, d.h. es bräuchte keine Verwendung eines BRAMs, sondern
nur die Beschreibung der Zuordnung ADR<->DAT an sich. Der Vorteil der
Verwendung der Beschreibung in Form einer Zuweisung ist zudem, dass der
sich ergebende Multiplexer und seine Kombinatorik mit den Ergebnissen
der LUTs und der davor liegenden Schaltung zusammengefasst werden kann
und damit es bessere Nieschenlösungen für AREA und SPEED gibt, d.h die
so zu bauende Schaltung ist sowohl schneller, als auch potenziell
kleiner.
Ferner ergibt sich bei größeren Schaltungen, die letztlich in der Tat im
RAM landen werden, die Möglichkeit, dass der Synthesizer die
RAM-Funktion mit anderen Speicheranforderungen mischt und in das dann
richtige RAM packt, nachdem die ADR-Zuordnung optimiert worden ist.
Wenn man seine Schaltung mit SUB-Modulen zusammenbaut, die selber alle
schon ihr Block-RAM mitbringen, weil es ausdrücklich eingebaut wurde,
besteht diese Chance kaum noch, es sei denn man stellt selber sicher,
dass ADR-Aufrufe, die vereinfacht werden können, so aufgezogen wurden,
dass sie zeitlich passen.
Gerade bei vielen kleinen und änhlichen Funktionen (und den Fall haben
wir ja hier) wird es darüber hinaus dennoch so sein, dass er zuerst die
zu erzeugenden BITs aus den Adressen heraus optimiert und dann ein
Netzwerk bekommt, dass deutlich kleiner ist, als die rechnerische Summe
der n Einzelnetzwerke, weil etliche LUTs / Kombinationen mehrfach
genutzt werden können. Auch die Sinus-typische Doppelfaltung um 2 Achsen
findet der Synthesizer und reduziert den RAM-Bedarf mal gleich deutlich.
Achim S. schrieb:> Dass er als selbsterklärter> VHDL-Starter beide Lösungen ausprobieren will finde ich eher lobenswert
Sicher ... hoffen wir, dass der VHDL-Starter alle denkbaren Optionen
ausprobiert, sie katalogisert, analysiert und dokumentiert - so wie es
richtige INGs tun und damit dann die wirklich optimiale Lösung auch
gefunden wird. :-)
Eventuell wäre eine kleine Publikation der Ergebnisse möglich. Dann
haben wir es schwarz auf weiss.
Was hier synthetisiert werden soll, braucht eigentlich weder Block-RAM
noch LUT-Ram. Als Beispiel der einfache LFO-WAVEFORM-GENERATOR aus
meinem ersten Synth:
Bei der üblichen Technik mit Viertel-Bogen und Anwendung einer voll
symmetrischen Vorschrift wie hier Digitale Sinusfunktion braucht es
in einem ARTIX gerade einmal 18 LUTs und 28 FFs bei 8 Bit Input und 11
Bit signed output. Die Tabelle hat 64 Einträge und 10-Bit Auflösung. Man
braucht das Signum, die Spiegelung der lokalen Adresse und bekommt somit
schon alle 4 Signalformen Sinus, Dreieck, Rechteck und Sägezahn heraus.
Effizienter geht es eigentlich nicht.
Bei der Aufgabenstellung des TE reichen sicher ein noch weniger LUTs.
Will man einen solch groben Sinus aber ernsthaft verwenden, sollte man
interpolieren.
Das hier wäre eine Simulation dazu. Man kann das auch noch verbessern ,
indem man den Sinus mit Parabeln interpoliert, bzw. ihn gleich aus
solchigen baut. Dann geht es auch mit hohen Auflösungen sehr genau.
Konkret einer bis zur 27. Oberwelle mit 28 Multiplieren, 14+1
pipeline-Stufen und etwas LUT-RAM (aber ohne BRAM) mit 20 Bit Ausgang -
effektiv 20 Bit Präzision bei 1kHz.
Ich habe mal vor geraumer Zeit eine Sin/cos-Tabelle nach opencores
hochgeladen. Sie ist unter Arithmetic... und liefert sin & cos
gleichzeitig ohne viel Mehraufwand weil zu jedem Zeitpunkt sin und cos
nie das gleiche Blockram ansprechen. Das Ding ist ziemlich
parametrisierbar, incl. pipeline delay und Auflösung.
Gruß, Gerhard
(der sich zur Zeit eher mit analogen 10 GHz-Sinusen beschäftigt.)
Gerhard H. schrieb:> weil zu jedem Zeitpunkt sin und cos> nie das gleiche Blockram ansprechen
Sicher? Wenn nur eine Viertelwelle hinterlegt wird, laufen beide
Auslese-Pointer auch gegeneinander und überkreuzen sich. Innerhalb der
ersten 90 Grad gilt COS (x) = SIN (90-x).
Dr. Wang schrieb:> Sicher?
Selbst wenn nicht, die meisten FPGAs, die ich kenne, können
Dual-port-RAM. Da kann jeder Generator den RAM lesen, wo er möchte. Man
könnte auch zwei unterschiedliche Frequenzen ausgeben.
Oder man taktet den RAM doppelt so schnell und multiplext die Zugriffe.
Duke
Für eine bekannte Wellenform würde ich kein BRAM nehmen, wenn es die
Größe nicht zwingend erfordert. Die Synthese kann das wirklich richtig
klein zusammenbacken und mehrere Zugriffe sind dann auch kein Problem
mehr. Wo es ein BRAM braucht, ist bei unbekannten Wellenformen, die der
Anwender laden möchte. Den zweiten Anschluss der BRAMs nutzt man dann
z.B. zur Auslese des nächsten Steps, um an Daten zu gelangen, die zur
Interpolation des Restvektors benötigt werden, der über bleibt, wenn man
aus der hochaufgelösten Phase die Adresse gewinnt. Die Steilheit (und
das wäre ja der COS des SIN) hat man dann auch gleich.
Wenn man einen DDS z.B. in einer PLL benutzt, dann hat man keine Zeit,
sich von einer neuen Phase zu einem genauen Sinus hin zu iterieren.
Totzeit verdient ihren Namen. Das ist der Tod jedes vernünftigen
Reglers.
Die BRAMs sind nun mal da. Wenn man sie ignoriert, dann sind sie
trotzdem noch da. Der Chip wird dadurch nicht billiger. Einen
optimierten
und gehärteten Block durch eine Poesie mit n Pipelinestufen zu ersetzen
ist nicht gerade der Weg zur Abstraktion.
Gerhard
Wobei die BRAMs meist an einer bestimmten Stelle im FPGA sitzen und man
von da schnell in Richtung Ausgang möchte, wird oft einen weiteren
Registertakt benötigt, bis der Wert dort ist, wo man ihn braucht. Der
Zugriff auf einen Sinus als Tabelle über LUTs, erfolgt hingegen in einem
Takt, zumindest wenn die Größe in den o.a. Bereichen bleibt. Auch der
Zugriff auf weitere 3-4 Adressen ist so möglich. Da ist man im Vergleich
sogar eventuell schneller, vor allem dann, wenn mit dem Wert etwas
veranstaltet werden soll, er also in weitere Kombinatorik einfließt, die
teilweise mit der Decodierung des Wertes zusammengefasst werden kann.
Aber auch größere Tabellen laufen noch einigermaßen schnell. Mal konkret
nachgeschaut:
Mein 24-Bit signed INT Sinus aus 12-Bit Adressen synthetisiert mit
64x768kHz = ~200 MHz und hat noch 1.3ns budget. Er hat die Adresse im 3.
Takt parat. Bedarf:
-- LUT 407 63400 0.64195585
-- FF 71 126800 0.05599369
-- IO 37 210 17.619047
-- BUFG 1 32 3.125
Mit Interpolation der 6 Restadressbits sind es 4 Takte. Mehrbedarf: 1
MUL.
Und gerade ausprobiert: 250 MHz constraint -> immer noch 0.6ns budget -
quer durchs FPGA geroutet. Register und LUTs lassen sich herrlich gut
verteilen.