Hallo alle zusammen!
Ich stehe gerade etwas auf dem Schlauch...
Folgendes Szenario:
Ich habe in meinem hypothetischen FPGA noch 10 RAM-Blöcke mit einer
breite von je 8-bit und jeweils 1024 Einträgen (=1kB pro Block) übrig
und möchte die jetzt zusammenfassen und als 'einen' Speicherblock
nutzen.
Als Address-Signal habe ich ein 14-bit breites Signal - also genug
Zustände (=16384) um alle 10*1024=10240 Einträge anzusprechen.
Wie konvertiere bzw. addressiere ich jetzt mein RAM-Array ohne dass mir
die Simulation um die Ohren fliegt??
Definition des RAMs:
Ich habe schon versucht mit "range" für das Signal addr_int zu arbeiten
um den Wertebereich virtuell zu begrenzen, aber ich bekomme in der
Simulation immer wieder den Fehler "14336 out of bound 0 to 10239" -
wahrscheinlich weil addr_int durch die Konvertierung des 14-bit Signals
eben auch größere Werte als 10240 annehmen kann.
Es ist klar, dass das Signal addr_i nicht den Wertebereich von 0 bis
10239 verlassen darf (was macht das RAM sonst?!), aber was, wenn dieses
Signal am Anfang nicht initialisiert ist und erst später durch z.B.
einen Reset auf einen initialen Wert gesetzt wird? Muss ich extra noch
einen Komparator einbauen um den Wertebereich direkt am Adresseingang
des RAMs zu begrenzen??
Irgendwie habe ich hier gerade ein Brett vor dem Kopf...
Vielleicht könnt ihr mir ja helfen ;)
Gruss,
Stephan
du kannst abfragen ob der bereich auserhalb ist und dann don't care
ausgeben
ram_read : process(clk_i)
begin
if rising_edge(clk_i) then
if addr_int < 10239 then
read_data <= ram(addr_int);
else
read_data <= (others => '-');
end if;
end if;
end process ram_read;
In der Simulation wird entweder Null gelesen oder Unsinn, oder es geht
wegen der Einschränkung nicht. In der Realität greift der Zugriff ins
Leere, weil es die ADR nicht gibt. Gelesen wird damit Nichts, gfs der
alte Wert aus dem vorherigen Zugriff oder ein Defaultwert.
Dies gilt, sofern die Erzeugerroutinen Deine Definition kapieren und das
RAm überhaupt noch reinquetschen können.
P.S. Kein normaler Mensch baut RAMs /= Potenz(2,x), weil das nur mehr
Aufwand macht.
Ich verstehe das Problem nicht.
Nahezu jedes Gerät mit einem Adress- und Datenbus hat wesentlich mehr
(mögliche) Adressen als tatsächlich ansprechbare Daten dahinter (ist
jedenfalls besser als andersrum). Ich wüsste beispielsweise keinen PC
mit 16 Exbibyte (ha, das Wort wollte ich schon immer mal schreiben).
Da ist es doch völlig unerheblich, ob ansprechbare Adressbereiche
irgendwie "gerade" oder "ungerade" anfangen/aufhören?
Wenn es für die Anwendung notwendig ist, muss die Steuerlogik eben beim
Adressieren illegaler Adressbereiche irgendeine Art von Fehler
(Bus-Error) auslösen. Wenn nicht, dann nicht (Garbage in -> Garbage
out).
Xilinx-Benutzer schrieb:> P.S. Kein normaler Mensch baut RAMs /= Potenz(2,x), weil das nur mehr> Aufwand macht.
Unsinn. Die Summe zweier Zweierpotenzen ist z.B. erstaunlich üblich,
obwohl es selbst keine Zweierpotenz ist. Sowas wie 48 oder 96 KB findet
man häufiger.
Stephan N. schrieb:> Vielleicht könnt ihr mir ja helfen ;)
Ich würde für die Simulation vollkommen unabhängig von der eigentlichen
RAM-Beschreibung einen Fehler ausgeben:
Denk in Hardware, Check "memory banking" und address decoding.
die addressbits die einen von den 10 Ram-primitiven auswählen, gehen
über einen 1 aus n decoder (wie 74??42) und treiben die einzelnen
chipselects oder output e-enable der RAM- primitive. Bei nicht tristate
datenbussen, müßen die Ausgänge noch gemuxt werden.
du brauchst also 2 arrays -> eins für die 2**n Zellen der Ramcomponenten
und eins für die 0 .. 9 RAM-primitive.
http://research.cs.tamu.edu/prism/lectures/mbsd/mbsd_l16.pdf
C. A. Rotwang schrieb:> du brauchst also 2 arrays -> eins für die 2**n Zellen der Ramcomponenten> und eins für die 0 .. 9 RAM-primitive.
Die Toolchain kann die 14 Adressbits normalerweise locker selbst so
aufdröseln, dass die unteren 10 Bits der Adresse für die RAM-Adressen
und die oberen 4 Bit über einen Adressdecoder zur RAM-Selektion
verwendet werden.
Lothar M. schrieb:> C. A. Rotwang schrieb:>> du brauchst also 2 arrays -> eins für die 2**n Zellen der Ramcomponenten>> und eins für die 0 .. 9 RAM-primitive.> Die Toolchain kann die 14 Adressbits normalerweise locker selbst so> aufdröseln, dass die unteren 10 Bits der Adresse für die RAM-Adressen> und die oberen 4 Bit über einen Adressdecoder zur RAM-Selektion> verwendet werden.
Auch bei dem "Hypothetischen FPGA" des TO?
Im Zweifelsfall würde ich das nicht der VHDL-Synthese überlassen sodern
dem Coregenerator o.ä. bspw https://www.youtube.com/watch?v=fbEuQk0-fE4
Auch Core-generatoren gehören der Toolchain und ersparen einem propitäre
VHDL-Konstrukte wo Simu und Synthese nicht zusammenpassen. Und in der
Regel gibt es auch gescheite Doku zu den Modellen, die einem verrät was
in der Simu in "Grenzbereichen" passiert.
C. A. Rotwang schrieb:> Auch bei dem "Hypothetischen FPGA" des TO?
Anscheinend traut er es dessen Toolchain zu.
> Und in der Regel gibt es auch gescheite Doku zu den Modellen
Naja, es sind die selben Bauteile, für die es idR. auch Datenblätter
gibt. Und auf diese Datenblätter bauen die Simulationsmodelle auch auf.
> Im Zweifelsfall würde ich das nicht der VHDL-Synthese überlassen sodern> dem Coregenerator
Im Zweifelsfall würde ich die RAM von Hand instantiieren. Dann bleibt
das Design (trotz des geringeren Abstraktionslevels verglichen mit der
reinen Verhaltensbeschreibung) immer noch recht leicht portier- und
parametrierbar.
Lothar M. schrieb:> C. A. Rotwang schrieb:>> Auch bei dem "Hypothetischen FPGA" des TO?> Anscheinend traut er es dessen Toolchain zu.>>> Und in der Regel gibt es auch gescheite Doku zu den Modellen> Naja, es sind die selben Bauteile, für die es idR. auch Datenblätter> gibt. Und auf diese Datenblätter bauen die Simulationsmodelle auch auf.>>> Im Zweifelsfall würde ich das nicht der VHDL-Synthese überlassen sodern>> dem Coregenerator> Im Zweifelsfall würde ich die RAM von Hand instantiieren. Dann bleibt> das Design (trotz des geringeren Abstraktionslevels verglichen mit der> reinen Verhaltensbeschreibung) immer noch recht leicht portier- und> parametrierbar.
Der Coregenerator macht auch nix anderes als die RAM zu instanzieren.
Und mit ner GUI tut man sich m.E. deutlich einfacher beim
paramtrisieren/verdrahten als jedes mal die GENERIC/Port MAP im
Libraryguide nachzuschlagen.
https://www.xilinx.com/support/documentation/sw_manuals/xilinx2012_2/ug953-vivado-7series-libraries.pdf
Ein CoreGenerator ist halt besser als ich komplexere Speicherstrukturen
, (insbesonders FIFO mit Flags an unterschiedlichen taktdomainen)
"zusammenzustricken". Steckt eben mehr KnowHow in dem generator als ein
Entwickler auf die Schnelle im Schädel hat. Nicht so "elegant" wie 3
Zeilen VHDL, dafür nicht so fehleranfällig wie elbstgeschriebene
Modelle.
C. A. Rotwang schrieb:> Ein CoreGenerator ist halt besser als ich komplexere Speicherstrukturen
Sofern er funktioniert :-) Gerade der Xilinx-Coregen, hat mir u.a. bei
SERDES, DDR3-CTRL (MIG) und sogar bei PLLs oft schon Mist hingeschrieben
und der Rat des jeweiligen FAEs war, den CoreGen zur Seite zu lassen und
alles per Hand zu machen.
Trotzdem ist die Nutzung der individuellen Primitive - gerade für
komplexe DualPort-RAMs - schon der richtige Weg, wenngleich man sich
dann auf den Hersteller festlegt und das VHDL nicht mehr universell ist.
Solange es aber nur der Austausch des Xilinx- gegen einen Altera-Wrapper
ist, macht es nichts. Letztlich muss man das VHDL oft ohnehin auf den
Hersteller anpassen, weil die RAM-Funktionen nicht 100% austauschbar
sind.
Zu dem Problem:
Man schränkt eigentlich nur die Adresse ein und überlässt es der
Synthese, sich was auszudenken. Erst, wenn die nicht greift und es
vergeigt, wird gestückelt. In Deinem Fall würde Ich die ADR beschränken
und die Simulation vollständig aufziehen, damit die Einschränkung
verifiziert und evident ist.
Danke dür die Hinweise soweit!
Ich habe auch schon überlegt mir meinen Speicherblock aus mehreren
Arrays, die dann wiederum eine 2er-Potenz als Größe haben, zu bauen.
Also quasi eine "manuelle" Dekodierung der oberen Adressbits zu machen
und dann den richtigen Block auszuwählen.
Das ganze soll aber generisch sein und nach Möglichkeit eben auch
Plattform-umabhängig. Und gerade bei der alten Xilinx ISE hatte ich
immer wieder Probleme mit mehrdimensionalen Arrays als Speicher...
Wie auch immer - ich prüfe jetzt ob der Speicher eine 2er-Potenz als
Größe hat und falls nicht schalte ich einen Komparator vor, der nur
gültige Adressen an den Speicher weiter gitb. Ist vielleicht nicht die
elganteste Möglichkeit, aber funktioniert soweit ganz gut ;)