Hallo,
ich stehe vor einem Problem und möchte mich hier mal erkundigen, wie man
soetwas am besten umsetzt.
Ich habe zwei parallele Datenkanäle mit je 12bit Breite.
Beide Datenkanäle sollen mit Hilfe von LUTs auf 8bit herunter gerechnet
werden. Ich möchte also nur 8bit weiter verarbeiten, aber die Dynamik
von 12bit annähernd erhalten.
Nun scheitere ich daran, eine solche LUT zu erstellen.
Ich habe in einem anderen Thread mit auf den Weg bekommen, dass man dzau
wohl (Block)RAM/ROM nehmen könnte/müsste.
Mein 12bit Eingangswert ist die Adresse, von der ich dann den 8bit Wert
lese...
Nur wie genau erstelle ich einen solchen BlockRAM/ROM?
In den Templates finde ich nur einen mit 6bit Adresse, der auch nur 1bit
als Ausgang hat.
Wie fülle ich einen solchen ROM am besten mit Daten, die dann nicht mehr
verändert werden können?
Muss es ein DualPort sein, wenn ich die LUT ohne Neubeschreiben des
FPGAs ändern möchte?
Wäre denn auch folgende Lösung denkbar?
Ich unterteile meinen 12bit Wertebereich in 5 Bereiche. Je nachdem in
welchen Bereich der Eingangswert fällt, rechne ich ihn zum Ausgangswert
um. Dazu bräuchte ich pro Wert z.B. folgenden Ausdruck:
Ausgangswert = (Eingangswert - 3074)/128 + 192
Dauert eine solche Rechnung mit STD_LOGIC_VECTOR extrem lange, oder ist
sie sehr aufwendig, oder könnte ich damit den BlockRAM erschlagen?
Dann habe ich einfach 5 cases nach denen der Eingangswert seinem Wert
entsprechend umgerechnet wird.
Dank der fünf Formeln, brauche ich dann zum Ändern der LUT nur diese zu
ändern.
Ich wäre für Hinweise zu meinem Problem sehr dankbar!
Vielen Dank!
Andi
du brauchst ein blockram mit 4096 einträgen.
das kannst du als array in vhdl hinschreiben, und die synthese die
arbeit machen lassen das ganze auf die kleineren blockrams verteilen
lassen
Andreas B. schrieb:> Nur wie genau erstelle ich einen solchen BlockRAM/ROM?
1. Du instatiierst es manuell
2. Du beschreibst es in einer Hochsprache
3. Du nimmst den Core-Generator
Zu 2. sieh dir z.B. das an:
http://www.lothar-miller.de/s9y/categories/31-DDFS
Und lies den XST User Guide...
> Wie fülle ich einen solchen ROM am besten mit Daten, die dann nicht mehr> verändert werden können?
Das kommt darauf an, welchen Weg du oben ausgewählt hast...
> Muss es ein DualPort sein, wenn ich die LUT ohne Neubeschreiben des> FPGAs ändern möchte?
Nein, du kannst auch ein "normales" RAM beschreiben, solange du nicht
gleichzeitig von einer anderen Adresse lesen willst.
> Ausgangswert = (Eingangswert - 3074)/128 + 192> Dauert eine solche Rechnung mit STD_LOGIC_VECTOR extrem lange,
Genau 1 Takt, denn zum Glück willst du nur durch eine 2er Potenz teilen.
> oder ist sie sehr aufwendig,
Nein. Ich würde dir da so ca. 100MHz Taktfrequenz prognostizieren.
> Dauert eine solche Rechnung mit STD_LOGIC_VECTOR extrem lange
Rechne besser mit geeigneten Datentypen unsigned und signed (aus der
ieee.numeric_std.all).
Lothar Miller schrieb:> 3. Du nimmst den Core-Generator
Das habe ich getan, an die IP-Cores habe ich mal wieder nicht gedacht,
sondern nur die Templates durchgeschaut. Irgendwann merke ich es mir und
schaue nach, bevor ich frage, wie ich etwas erstelle.
Das habe ich nun getan mit 8bit mal 4096 Zeilen.
Nun habe ich deinem Bsp. folgenden Code entnommen:
1
constantSinus_Rom:Rom64x8:=(
2
x"00",x"03",x"06",x"09",x"0c",x"0f",x"12",x"15",
3
x"18",x"1b",x"1e",x"21",x"24",x"27",x"2a",x"2d",
4
x"30",x"33",x"36",x"39",x"3b",x"3e",x"41",x"43",
5
x"46",x"49",x"4b",x"4e",x"50",x"52",x"55",x"57",
6
x"59",x"5b",x"5e",x"60",x"62",x"64",x"66",x"67",
7
x"69",x"6b",x"6c",x"6e",x"70",x"71",x"72",x"74",
8
x"75",x"76",x"77",x"78",x"79",x"7a",x"7b",x"7b",
9
x"7c",x"7d",x"7d",x"7e",x"7e",x"7e",x"7f",x"7f");
Dem entnehme ich, dass ich eine Konstante händisch mit kommagetrennten
Werten initialisieren kann, die ich dann sicher dem RAM übergeben kann.
Ich arbeite das erste mal mit BlockRAM und habe daher noch ein paar
Fragen dazu:
1. Wie übergebe ich den Inhalt der Constanten dem RAM? Denn ich habe nur
folgendes INSTANTIATION Template, mit dem ich auf den RAM zugreifen
kann.
1
your_instance_name:RAM
2
portmap(
3
clka=>clka,
4
ena=>ena,
5
wea=>wea,
6
addra=>addra,
7
dina=>dina,
8
douta=>douta);
2. wenn ich den Weg über die händische Definition der Konstanten
vermeiden will, kann ich dann mit Hilfe einer for-Schleife, die die
Adresse hochzählt, den RAM auch beim Start beschreiben lassen?
Vielen Dank!
Andi
Andreas B. schrieb:> kann ich dann mit Hilfe einer for-Schleife, die die> Adresse hochzählt, den RAM auch beim Start beschreiben lassen?
Nur, wenn die Daten zu diesem Zeitpunkt statisch sind. Dann wird daraus
einfach wieder der Inhalt für ein BRAM erzeugt...
Andreas B. schrieb:> Ich arbeite das erste mal mit BlockRAM und habe daher noch ein paar> Fragen dazu:> 1. Wie übergebe ich den Inhalt der Constanten dem RAM?
Genau so:
> Dem entnehme ich, dass ich eine Konstante händisch mit kommagetrennten> Werten initialisieren kann, die ich dann sicher dem RAM übergeben kann.
Diese Werte werden automatisch beim Laden des FPGAs in das BRAM
geschrieben, und sind dort dann sofort verfügbar.
> Denn ich habe nur folgendes INSTANTIATION Template, mit dem ich> auf den RAM zugreifen kann.
Das ist der Ansatz 1 vom
Beitrag "Re: Von 12bit auf 8bit mittels LUT"
Und dort kannst du natürlich auch beim Anlegen der Instanz die Daten
initialiseren. Weiteres verrät dir der XST User Guide (kommt dir der
Begriff bekannt vor?).
Du solltest unbedingt darauf achten, nicht die 3 Implementierungsarten
miteinander zu verknoten. Das endet im Chaos...
Also an deiner Stelle würde ich einfach von den 12-Bit, die 4
niederwertigsten nicht beachten und gut ists. Wenn du dann noch eine
Korrektur per LUT machen willst, würde ich diese danach durchführen.
Eine 8-Bit-LUT hat nur 256 Einträge gegenüber deinen 4096.
Da kann ich tom nur zustimmen. Ein einfache Schift-Operation sollte hier
genügen. Und anschließend die Anpassung per LUT oder nach deiner o.g.
Gleichung:
Hallo und vielen Dank,
die Vorgehensweise mit 8 aus 12 Bits habe ich schon versucht und die
Dynamik ist leider nicht ausreichend. Wenn ich von 12 Bits 4 verwerfe,
fehlt mir genau dieser Dynamikumfang, der mir noch fehlt. Daher möchte
ich mittels LUT von 12 auf 8bit kommen.
Ich habe jetzt im Core Generator ein .coe File angelegt damit testweise
den BRAM initialisiert. Nun muss ich das Ganze nur noch passend
einbinden und testen.
Dennoch ist mir schleierhaft, wie ich den IPCore BRAM ohne .coe File
initialisieren kann. In Lothar seinem Bsp. wird ja ein array vom Typ
Rom64x8 erstellt und dann mittels Konstanten gefüllt. Da fehlt mir aber
das Verständnis oder der Blick, wie die Zuordnung der Adressen gelöst
wird. Oder kann man bei einem array automatisch mit array (11 downto 0)
auf die STD_LOGIC_VECTOR Adressen zugreifen, ohne das man das extra
festlegen muss?
Könnte ich dann mein Problem (feste, unveränderbare LUT vorausgesetzt)
auch so lösen?
--und das ganze insgesamt 4096 mal, halt nur mit sinnvollen Werten
7
x"00",
8
x"00");
Hätte ich so auch ohne IPCore und RAM Generator einen ROM erstellt und
könnte auf diesen mittels 12bit Adresse zugreifen?
1
data_out<=LUT_Rom(conv_integer(Adress_vector));
Der XST User Guide sagt mir freilich etwas und hält auch viele Beispiele
bereit, aber dennoch habe ich immer meine Problem, den dort gezeigten
VHDL Code komplett zu durchschauen. Oft sind es Kleinigkeiten oder
irgendwelche mir unbekannten Kniffe, über die ich stolpere.
Vielen Dank!
Andi
Die Inferrierung klappt so, allerdings muss das Auslesen getaktet
erfolgen, damit XST da einen BRAM Block draus macht. Die BRAM Speicher
sind synchron. Du hast dann einen Takt Latenz, aber dafür einen BRAM.
Die entscheidende Stelle auf Lothars Seite:
Andreas B. schrieb:> In Lothar seinem Bsp. ...
Der Dativ ist dem Genitiv sein Tod! :-/
Du hättest schreiben dürfen:
In Lothars Beispiel...
> Oder kann man bei einem array automatisch mit array (11 downto 0)> auf die STD_LOGIC_VECTOR Adressen zugreifen, ohne das man das extra> festlegen muss?
Nein.
Man muß den vorher nach integer konvertieren, denn nur mit einem
Integer darf in VHDL ein Array indiziert werden.
Wie schon von Christian gesagt muß die Adresse des so beschriebenen RAMs
getaktet werden, damit tatsächlich ein BlockRAM ins Spiel kommt.
Wenn du das nicht tust, dann wird stattdessen Distributed RAM (in den
LUTs) angelegt... :-o
BTW:
>>> conv_integer()
Nimm besser die numeric_std und ihre Casts & Konvertierungen
http://www.lothar-miller.de/s9y/archives/14-Numeric_Std.html