Hallo,
ich bekomme alle x ns zwei STD_LOGIC_VECTOREN als Eingangssignal mit
jeweils einer Größe von y Bit und möchte diese zeitgleich (parallel) in
einen Speicher oder Register schreiben? Nach z Taktzyklen ist der
Speichervorgang vorbei und beginnt nach einigen us erneut.
Welche Form von Speicher ist für eine solche Prozedur am geeignetesten?
Register / Blockram? Der Speicher müsste auch wieder parallel ausgelesen
werden, um Beispielsweise das erste 8 Bit Speicherelement mit dem
Zweiten 8 Bit Speicherelement im ersten Takt und das dritte Element mit
dem 4 Element im 2 Takt etc. pp zu vergleichen?
Gruß,
Da Du für x, y und z keine konkreten Zahlen nennst, kann man Dir auch
nicht wirklich helfen.
Tom schrieb:> Der Speicher müsste auch wieder parallel ausgelesen> werden, um Beispielsweise das erste 8 Bit Speicherelement mit dem> Zweiten 8 Bit Speicherelement im ersten Takt und das dritte Element mit> dem 4 Element im 2 Takt etc. pp zu vergleichen?
Vielleicht helfen Dir dabei zwei Speicher, die abwechselnd beschrieben
werden?
Duke
Hi Duke,
in einem Takt bekomme ich zwei mal 8 Bit Signale des Typs
STD_LOGIC_VECTOR. Nach 1000 Takten also 2000 Signalwerte. Diese 2000
Werte bilden meine Gesamtinformation.
Ich möchte also mit jedem Takt die zwei 8 Bit Signale in einem Speicher
/ Register speichern, sodass mir nach 1000 Takten die kompletten
Informationen in meinem Speicher vorliegen.
Also irgendwie in der Art:
"schreibe die 8 Bit des signal's A im Takt 1 an adresse "00000000" in
und
schreibe die 8 Bit des signal's B im Takt 1 an adresse "00000001"
schreibe die 8 Bit des signal's A im Takt 2 an adresse "00000010" in
und
schreibe die 8 Bit des signal's B im Takt 2 an adresse "00000011"
.
.
.
Tom schrieb:> Welche Form von Speicher ist für eine solche Prozedur am geeignetesten?Tom schrieb:> Diese 2000> Werte bilden meine Gesamtinformation.
Also 16 kBit.
Dafür reicht der interne Speicher im FPGA, bei Xilinx BRAM genannt.
Duke
Wenn ich mit Hilfe des Core Generators von Xilinx die Block RAM Funktion
erstelle, kommt für diese Aufgabe doch nur der True Dual Port Ram in
Frage, oder?
Beide Eingänge benötigen einen gemeinsamen Takt (Common Clock).
Was ich noch nicht so richtig verstanden habe, ist, wie das mit dem
Write Enable funktionert. (Use Byte Write Enable mit ByteSize 8 und 9
Bits).
Als Algorithmus würde ich "Minumum Area" nehmen.
Sollte als erstes geschrieben oder gelesen werden? Da vorher noch nichts
im Ram drin steht, würde ich schreiben sagen.
Und ein enable Pin macht in diesem Fall ja auch Sinn.
Fragen über Fragen ;-)
Vielen Dank und schönes Wochenende,
Tom
> Sollte als erstes geschrieben oder gelesen werden?
Was denkst du denn was drinne steht wenn du noch nichts reingeschrieben
hast ? Macht das Sinn für dich ? Erst ein Blatt Papier lesen und dann
erst was draufschreiben ?
Uwe schrieb:> Was denkst du denn was drinne steht wenn du noch nichts reingeschrieben> hast ? Macht das Sinn für dich ? Erst ein Blatt Papier lesen und dann> erst was draufschreiben ?
klar, da gebe ich Dir recht, wie ich es auch schon geschrieben hatte.
Jedoch wusste ich nicht, ob evtl. noch mehr dahinter steckt.
Lattice User schrieb:> Mach den Speicher 16 bit breit, da brauchst du keinen Dualport RAM,> ausser du möchtest schreiben und lesen entkoppeln.
Und ich kann trotzdem zwei Adressen gleichzeitig beschreiben und beim
Lesen zwei Adressen gleichenzeitig auslesen? Denn wenn ich im CoreGen
nur SinglePort Ram auswähle, habe ich auch nur einen Eingang und einen
Ausgang.
Meinst Du damit, dass ich dann die 2 * 8 Bit Werte mit dem '&' Operator
verknüpfe und diese dann als 1 Signal in den Ram schreibe?
Später sollte es evtl. auf eine Größe von 4096 * 12 Bit Werten
vergrößtert werden.
Lässt sich das alles mit einem Takt realisieren, denn in der nächsten
aktiven Taktflanke liegen zwei neue Signale an A und B an?
Welchen Nachteil hat DualPort Ram für diese Anwendung gegenüber dem
SinglePort? Deutlich mehr Ressourcenverbrauch?
Empfiehlt es sich, den Ram mit Hilfe des CoreGen zu realisieren oder
beispielsweise mit so einer einfachen Implementrierung?
http://www.doulos.com/knowhow/vhdl_designers_guide/models/simple_ram_model/
Was den Coregenerator betrifft, bin ich dann an die jeweils vorher
definierte Hardware gebunden?
Was würde ich nur ohne das super Forum machen ;-)
Vielen Dank,
Tom
Tom schrieb:> Lattice User schrieb:>> Mach den Speicher 16 bit breit, da brauchst du keinen Dualport RAM,>> ausser du möchtest schreiben und lesen entkoppeln.>> Und ich kann trotzdem zwei Adressen gleichzeitig beschreiben und beim> Lesen zwei Adressen gleichenzeitig auslesen?
Klar, wenn Deine Daten auf der gleichen Adresse liegen.
> Denn wenn ich im CoreGen> nur SinglePort Ram auswähle, habe ich auch nur einen Eingang und einen> Ausgang.
Logisch.
> Meinst Du damit, dass ich dann die 2 * 8 Bit Werte mit dem '&' Operator> verknüpfe und diese dann als 1 Signal in den Ram schreibe?
Ganz genau.
> Später sollte es evtl. auf eine Größe von 4096 * 12 Bit Werten> vergrößtert werden.
Schau ins Datenblatt, welche Speicheranordnungen unterstützt werden.
> Lässt sich das alles mit einem Takt realisieren, denn in der nächsten> aktiven Taktflanke liegen zwei neue Signale an A und B an?
Ja.
> Welchen Nachteil hat DualPort Ram für diese Anwendung gegenüber dem> SinglePort? Deutlich mehr Ressourcenverbrauch?
Nein. Kein Nachteil. Die zwei Ports sind sowieso vorhanden. Aber wenn
man nur Singleport braucht, sieht der Code mit Singleport einfacher aus,
als mit Dualport-BRAM.
> Empfiehlt es sich, den Ram mit Hilfe des CoreGen zu realisieren oder> beispielsweise mit so einer einfachen Implementrierung?
CoreGen hab ich für BRAMs noch nie verwendet. Der macht die Sache m.E.
nur unnötig kompliziert und unportabel.
> http://www.doulos.com/knowhow/vhdl_designers_guide...
Ja, das ist gut. Das steht (leider mit veralteten Synopsis-Libs) auch im
XST USer Guide.
> Was den Coregenerator betrifft, bin ich dann an die jeweils vorher> definierte Hardware gebunden?
Jain.
Duke
Nur so als Beispiel.
Du kannst mit dieser Beischreibungsform beliebig viele Leseports an ein
solches Ram hängen, die Synthese findet selbst raus wie sie das sinnvoll
in HW abbilden kann.(z.b. Daten mehrfach speichern)
Klar sollte man vor Augen haben was dabei passiert, aber das muss man so
oder so.
Coregen für solche Sachen ist absoluter Overkill.
Eine (vielleicht dumme) Frage habe ich bezüglich des BRAMS noch. BRAM
steht doch für Block RAM. Bezieht sich das BRAM auf einen im FPGA
bezogenen Speicher (gibt es auch FPGA's ohne BRAM?) oder wird nur der
Aufbau des Speichers in Form von Blöcken so bezeichnet und BRAM würde
sich immer implementieren lassen?
In dem Beispiel bezieht hab ich einfach irgenteinen Namen gegeben.
Typischerweise versteht man unter BRAM schon einen konkreten Speichertyp
im FPGA(Blockram).
Wer der Synthese vertraut, wird aber feststellen das bei halbwegs
geeineter Schreibweise die Tools anhand von gewählter Speichertiefe und
Breite schon von alleine feststellen welcher Speicher sinnvoll zu
verwenden ist.
Andere Typen selbst auswählen kann man aber auch ganz einfach im Code
über attribute (unterscheiden sich ggf je nach Hersteller).
Macht aber fast nur dann Sinn wenn die Ressourcen(BRAMs oder LUTs oder
FFs) knapp werden.
Vergessen:
Bei dem Beispiel oben ist es ein 24 Bit mal 4096 Ram. Das würde in
Blockram bei den meisten neuen FPGAs genau ein BRAM ergeben bzw eins pro
frei adressierbarem Leseport.
In FFs wären das 98304FF, das baut die Synthese nur wenns ganz übel
hingeschrieben ist.
Als distributed Ram (in LUTs, falls unterstützt) sind das je nach
Lutgröße 1500 bis 6000 Luts, was auch schon sehr viel ist.
Deshalb lege ich jetzt mal meine Hand dafür ins Feuer das die aktuellen
Tools von Synopsys, Xilinx und Altera dort allesamt selbst die
Entscheidung treffen werden daraus Blockram zu bauen solange welcher
Verfügbar ist.
Nimmst du die Speichertiefe z.b. auf 16 runter, dann wird in den
allermeisten Fällen hingegen Distributed Ram rauskommen.
Probiers einfach mal, du siehst im Report ja was er draus macht.
Wenn write_enable jetzt nun 1 ist, wird mit jeden Takt der Wert von
data_a und data_b hintereinander gehangen in den Speicher an
n-ter(write_address) Zeile gespeichert.
Sobald write_enable wieder null wird, sind somit alle Werte im Ram
gespeichert, wenn ich das richtig verstanden habe.
Was ich noch nicht ganz verstanden habe ist, was genau mit
1
data_out1<=bram(read_adress1/2)(11downto0);
2
data_out2<=bram(read_adress2/2)(23downto12);
Muss read_adress nicht bei data_out1 und data_out2 nicht dieselbe sein?
Ich habe mir nun mal eine TB geschrieben, um den Eingängen mal ein paar
Werte zuzuweisen.
1
LIBRARYieee;
2
USEieee.std_logic_1164.ALL;
3
Useieee.numeric_std.all;
4
5
6
7
ENTITYtb_BRAM_24x4096IS
8
ENDtb_BRAM_24x4096;
9
10
ARCHITECTUREbehaviorOFtb_BRAM_24x4096IS
11
12
-- Component Declaration for the Unit Under Test (UUT)
Leider waren die Werte für data_out_a und data_out b null.
Liegt das daran, dass ich hier versuche gleichzeitig zu schreiben und zu
lesen?
Wie kann ich nun sehen, was in den Speicher geschrieben wurde? Muss ich
dann nachdem der Speicher beschrieben wurde und der write_enable wieder
null auslesen?
Wenn ich von aussen, also von einer übergeordneten Ebene den Speicher
auslesen möchte, benötige ich dafür nicht auch ein read_enable?
Sorry für die vielen Fragen und Danke nochmal für die tolle Hilfe!
Ich habe es nun mit einem zusätzlichen enable Eingang gelöst. Wenn
enable und write enable = '1' sind, dann wird geschrieben, wenn enable 1
und write enable 0 ist, wird gelesen.
Eine eigene Frage?
Dieser Thread ist über 14 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.