Forum: FPGA, VHDL & Co. RAM: warum nicht synthetisierbar?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ich wollte mal einen "generischen RAM" zusammenschreiben um zu sehen, ob 
die Synthese dafür dann auch RAM-Blöcke des FPGA benutzt.

Leider bekomme ich dafür die berühmt-berüchtigte Fehlermeldung:
1
statement is not synthesizable since it does not hold its value under NOT(clock-edge) condition. VHDL-1242

So ganz verstehe ich aber nicht, was das Problem dabei ist … vielleicht 
kann mir ja mal jemand auf die Sprünge helfen?

Port-Signale sollten selbst erklärend sein, wie beim üblichen RAM, nur 
halt getaktet.

von Blechbieger (Gast)


Lesenswert?

Versuchst du ein RAM zu bauen das wie ein separates IC einen 
bidirektionalen Datenbus hat? So etwas gibt es innerhalb eines FPGAs 
nicht und mich würde es überraschen wenn ein Synthesizer aus Dual-Port 
RAM deine Beschreibung nachbauen kann. Aber zieh mal data <= Z in das if 
rein denn das dürfte die Fehlermeldung bewirken.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Blechbieger schrieb:
> Versuchst du ein RAM zu bauen das wie ein separates IC einen
> bidirektionalen Datenbus hat?

Das war erstmal die Idee … spätestens, wenn man mal externen RAM 
anschließen will, braucht man sowas ja – dachte ich mir. ;-)

> So etwas gibt es innerhalb eines FPGAs
> nicht und mich würde es überraschen wenn ein Synthesizer aus Dual-Port
> RAM deine Beschreibung nachbauen kann.

Interessanterweise scheint das zu klappen: LSE bescheinigt mir einen 
Ressourcenverbrauch von einem Register und einem EBR-Block (sowie zwei 
LUTs).

Synplify Pro braucht zwar 8 Register, implementiert aber den RAM auch 
mit einem EBR-Block. Anbei der "Technology View" von Synplify.

> Aber zieh mal data <= Z in das if
> rein denn das dürfte die Fehlermeldung bewirken.

Gut, ja, das hat's gebracht, danke!

Nun würde ich gern noch den Grund verstehen … warum darf ich die Zs nur 
innerhalb des getakteten Blocks zuweisen?

Aber OK, den Datenbus aufzuteilen, ist natürlich gar kein Problem. 
Interessant auf jeden Fall, dass die Synthese auch wirklich einen RAM 
dafür benutzt und nicht etwa ein Grab voller Flipflops.

von Blechbieger (Gast)


Lesenswert?

Jörg W. schrieb:
> Blechbieger schrieb:
>> Versuchst du ein RAM zu bauen das wie ein separates IC einen
>> bidirektionalen Datenbus hat?
>
> Das war erstmal die Idee … spätestens, wenn man mal externen RAM
> anschließen will, braucht man sowas ja – dachte ich mir. ;-)

Ein Modell eines externen RAM muss aber nicht synthetisierbar sein.

Jörg W. schrieb:
> Nun würde ich gern noch den Grund verstehen … warum darf ich die Zs nur
> innerhalb des getakteten Blocks zuweisen?

Der ganze Prozess ist getaktet (clk in der Sensitivity Liste) und wird 
bei jeder TaktFLANKE ausgeführt. Für die steigende Flanke ist alles OK 
aber bei fallender Flanke wird data immer auf Z gesetzt.

Hier vielleicht nicht zwingend notwendig aber in einer Simulation hätte 
man den Fehler sehen können. Daher sind Testbenches immer zu empfehlen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Blechbieger schrieb:
> Der ganze Prozess ist getaktet (clk in der Sensitivity Liste) und wird
> bei jeder TaktFLANKE ausgeführt. Für die steigende Flanke ist alles OK
> aber bei fallender Flanke wird data immer auf Z gesetzt.

Danke für die Erklärung, leuchtet ein.

> Hier vielleicht nicht zwingend notwendig aber in einer Simulation hätte
> man den Fehler sehen können. Daher sind Testbenches immer zu empfehlen.

Ja, wobei noch die Frage ist, ob ich das dort auch als "Fehler" 
überhaupt erkannt hätte. Möglicherweise wäre es mir beim Drübergucken 
als Feature durchgegangen.

von Markus F. (mfro)


Lesenswert?

Jörg W. schrieb:
> Nun würde ich gern noch den Grund verstehen … warum darf ich die Zs nur
> innerhalb des getakteten Blocks zuweisen?

Nehmen wir mal auseinander, was Du da bei der Synthese bestellt hast:

rising_edge(clk) ist definiert als
1
function rising_edge  (signal s : std_ulogic) return boolean is
2
begin
3
   return (s'event and (To_X01(s) = '1') and
4
                       (To_X01(s'last_value) = '0'));
5
end;

Wird also genau dann (und nur dann) für den Augenblick true, wenn eine 
positive Taktflanke auftritt. Zu allen anderen Zeiten false.
1
    data <= "ZZZZZZZZ";
2
    if rising_edge(clk) then
3
        if ce = '0' then
4
            if wr = '0' then
5
                cells(ad) <= data;
6
            elsif rd = '0' then
7
                data <= cells(ad);
8
            end if;
9
        end if;
10
    end if;
11
...

Wenn wir das data <= "ZZZZZZZZ" mal kurz weglassen, bedeutet das, das in 
eben jenem Augenblick das Register (oder eben in diesem Fall das RAM) 
aktiv wird und kann entweder beschrieben oder ausgelesen werden. In 
allen anderen "Augenblicken" behält es seinen Wert (speichert).

Jetzt hast Du noch eine asynchrone Signal-Zuweisung "dazugebastelt". 
Wenn die Bedingung "rising_edge()" nicht erfüllt ist, soll High-Z 
getrieben werden. Das widerspricht aber der "speicher"-Anweisung von 
oben, die Synthese stellt fest, dass dein RAM gar keins mehr ist bzw. 
maximal an der Taktflanke einen Spike (mit einem Wert, den es 
"vergessen" hat und mit Hardware, die so was gar nicht kann) produzieren 
könnte und meckert zurecht.

von Marius W. (mw1987)


Lesenswert?

Außerdem aufgepasst bei der Typendefinition des RAMs:
1
type
2
  ram_t is array(9 downto 0) of std_logic_vector(7 downto 0);

Das erzeugt dir einen RAM mit genau 10 Bytes. Du wolltest aber 
sicherlich einen RAM mit 2^10-Zellen. Also besser folgendes machen:
1
type
2
  ram_t is array(0 to ((2**addr'length)-1)) of std_logic_vector(7 downto 0);

Gruß
Marius

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marius W. schrieb:
> Das erzeugt dir einen RAM mit genau 10 Bytes.

Ah ja, danke für den Hinweis. Hatte mich schon gewundert, warum die 
Synthese nur 4 Adressleitungen produziert hat … ;-)

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ich habe es nicht getestet, es meusste aber in die Richtung vom meinem 
Anhang gehen.

Die Z Zuweisungen im Prozesses fuer den Tristate und das Adress 
Multiplexing ist nicht was du wolltest. Variablen werden erstmalig in 
einem Prozess synthetisiert, behalten aber dann ueber die Laufzeit ihren 
Wert.

Die Tristate Geschichte musst du ausserhalb des Prozesses machen.

Ebenso wuerde ich mir noch ueberlegen ob die wirklich seperate Rd und Wr 
enable haben willst. Macht das Design robuster und falls doch unbedingt 
separate Enables gewuenscht sind, wuerde ich das ein Layer darueber 
packen.

Und vll. noch ein finaler Tipp: Nimm besser .vhd als Dateiendung. Das 
ist deutlich verbreiteter.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Ich habe es nicht getestet, es meusste aber in die Richtung vom meinem
> Anhang gehen.

Danke, werde das heute Abend mal durch den Simulator jagen (und meine 
nun synthetisierte Fassung auch).

> Die Z Zuweisungen im Prozesses fuer den Tristate und das Adress
> Multiplexing ist nicht was du wolltest. Variablen werden erstmalig in
> einem Prozess synthetisiert, behalten aber dann ueber die Laufzeit ihren
> Wert.

War mir im Prinzip klar, aber jetzt wo du's sagst: ich darf die Variable 
nicht einfach nur initialisieren, sondern muss ihr stets neu den Wert 
zuweisen, oder? Ansonsten habe ich da wohl ein Latch gezimmert …

> Die Tristate Geschichte musst du ausserhalb des Prozesses machen.

OK.

> Ebenso wuerde ich mir noch ueberlegen ob die wirklich seperate Rd und Wr
> enable haben willst.

Hmm. Ich überlege gerade … Rd braucht man natürlich eigentlich nicht, 
hatten ja "richtige" RAMs auch nicht. Allerdings hatten die ein /OE, 
damit man die Ausgangstreiber aktivieren kann (also von Z nach 
data_out). Das wäre wohl insgesamt sinnvoller – wenn man jetzt beim 
bidirektionalen Datenbus bleibt.

> Und vll. noch ein finaler Tipp: Nimm besser .vhd als Dateiendung. Das
> ist deutlich verbreiteter.

Da ich nie groß Windows benutzt habe, waren mir die Dateiendungen und 
deren Länge immer so ziemlich egal. Bei mir gibt es auch JPEGs, die auf 
.jpeg enden, TIFFs auf .tiff und so. Ja, ist natürlich 'ne Frage, wem 
man das weiter gibt. Selbst Radiant ist da in sich nicht völlig 
konsistent: sie bieten einem beim Neuanlegen einer VHDL-Datei an, ob man 
sie auf .vhd oder .vhdl enden lassen will, aber wenn man eine 
existierende Datei zum Design hinzufügen will, dann haben sie erstmal 
nur *.v und *.vhd in der Auswahlmaske …

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> War mir im Prinzip klar, aber jetzt wo du's sagst: ich darf die Variable
> nicht einfach nur initialisieren, sondern muss ihr stets neu den Wert
> zuweisen, oder? Ansonsten habe ich da wohl ein Latch gezimmert …

Zum ersten Teil: Genau, nur initialisieren reicht nicht. Zum zweiten 
Teil: Das ist in diesem Fall extremst tricky, weil du ja eine Variable 
initialisierst, mit einem Signal das dynamisch ist. Eigentlich wuerde 
ich erwarten, dass das Synthese Tool meckert, wenn du etwas 
initialiseren willst und der Inhalt keine Konstante ist.

Jörg W. schrieb:
> Hmm. Ich überlege gerade … Rd braucht man natürlich eigentlich nicht,
> hatten ja "richtige" RAMs auch nicht. Allerdings hatten die ein /OE,
> damit man die Ausgangstreiber aktivieren kann (also von Z nach
> data_out). Das wäre wohl insgesamt sinnvoller – wenn man jetzt beim
> bidirektionalen Datenbus bleibt.

Theoretisch ist es auch kein Problem, in der Praxis jedoch schon. In 
deinem aktuellen Fall hast du mehr Freiheitsgrade als noetig und musst 
aufpassen was im Fall beim gleichzeitig aktivierten Rd & Wr passiert. 
Aktuell haettest du eine Bevorzugung von Wr im Prozess, also muss das 
auch angepasst werden beim Tristate Buffer.

Das Ergebnis ist: Mehr Functional & Code Coverage bei der Verifizierung 
ohne ein Gewinn an Funktionalitaet. Der fehlerfreiste Code ist immer 
der, den man nicht schreiben muss. ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Mehr Functional & Code Coverage bei der Verifizierung ohne ein Gewinn an
> Funktionalitaet.

:}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Eigentlich wuerde ich erwarten, dass das Synthese Tool meckert, wenn du
> etwas initialiseren willst und der Inhalt keine Konstante ist.

Wenn ich mir das Syntheseergebnis von SynplifyPro oben ansehe, dann 
haben sie offenbar meine (nicht korrekt ausgedrückte) Intention 
synthetisiert und diese Variable letztlich komplett weggelassen. 
Eigentlich hatte ich sie auch nur eingeführt, weil ich es sinnvoll fand, 
die Typumwandlung vom Vektor "addr" in den Array-Index (der "integer" 
ist) nur an einer Stelle zu machen.

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Das waere noch die letzte Falltuer die ich bei einem synthesetool 
akzeptieren wuerde. Den Init-Wert von von dem Signal als Init-Wert fuer 
die Variable nehmen. Da keine Zuweiseung mehr an die Variable erfolgt, 
ist die Adresse praktisch eine Konstante mit Wert 0 und der RAM ist 
genau Wort tief.

Jörg W. schrieb:
> Eigentlich hatte ich sie auch nur eingeführt, weil ich es sinnvoll fand,
> die Typumwandlung vom Vektor "addr" in den Array-Index (der "integer"
> ist) nur an einer Stelle zu machen.

Der Sinn der Variablen ist voellig in Ordnung. Ist praktisch eine 
Optimierung der Schreibweise, weil man die lange Cast-Verschachtelung 
nur einmal niederschreiben muss.

Wuerde natuerlich auch mit einem Signal gehen, aber solange die Adresse 
nur in dem Prozess gebraucht wird, ist das voellig in Ordnung, getreu 
dem Motto: Keep local things local. :-)

von Michael W. (Gast)


Lesenswert?

Blechbieger schrieb:
> Ein Modell eines externen RAM muss aber nicht synthetisierbar sein.

Aber er will ja synthetisieren.

Meine Frage: Warum soll man mit solchen Inferierten RAMs bauen und nimmt 
nicht die echten, die angeboten werden?

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

M. W. schrieb:
> Meine Frage: Warum soll man mit solchen Inferierten RAMs bauen und nimmt
> nicht die echten, die angeboten werden?

Zwei Moeglichkeiten:

1.) Portierbarkeit. Gerade im Zusammenspiel mit Symplify macht das Sinn, 
da ich davon ausgehe, dass Symplify mit dem gleichen Code auch fuer 
unterschiedliche FPGAs entsprechenden RAM baut.

2.) Das vermute ich in diesem Fall: Lernen. :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Zwei Moeglichkeiten:

Ja, beide :-)

Es sollte insbesondere auch ein Test sein, ob die Synthese derartige 
Konstrukte erkennt und dann auch tatsächlich durch "on-board RAM" 
realisiert, und das haben sowohl Synplify als auch LSE demonstriert, 
dass sie das können.

: Bearbeitet durch Moderator
von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Wenn der Code mal final ist und du ihn hier reinstellst, kann ich ihn 
auch mal noch in ISE, Vivado und Quartus synthetisieren. Dann haettest 
du auch noch einen Vendor abhaengigen Vergleich. :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

OK. Habe jetzt nochmal weitgehend deinen Vorschlag umgesetzt. Siehe da, 
jetzt werden auch keine Register mehr gebraucht :)

Möchte das aber morgen erstmal simulieren und mir ansehen, ob's 
eigentlich das ist, was ich mir vorgestellt habe. Dafür isses mir jetzt 
schon etwas zu spät.

Danke jedenfalls schon mal an alle Mitdiskutanten!

von Duke Scarring (Gast)


Lesenswert?

Theoretisch gibt es den IEEE Std. 1076.6 'IEEE Standard for VHDL 
RegisterTransfer Level (RTL) Synthesis', der auch einen Abschnitt zu RAM 
und ROM enthält:
https://ieeexplore.ieee.org/servlet/opac?punumber=9308

Der kann zumindest als Anhaltspunkt dienen, was ein Synthesetool können 
sollte.

Duke

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Duke Scarring schrieb:
> Theoretisch gibt es den IEEE Std. 1076.6

Hilft mir leider nicht viel, darauf habe ich keinen Zugriff (wie mir 
scheint).

von Markus F. (mfro)


Lesenswert?

Jörg W. schrieb:
> Duke Scarring schrieb:
>> Theoretisch gibt es den IEEE Std. 1076.6
>
> Hilft mir leider nicht viel, darauf habe ich keinen Zugriff (wie mir
> scheint).

Das wäre (auch wenn Du drankämest - das Internet bietet da durchaus 
alternative Möglichkeiten) nur begrenzt hilfreich: der Standard wurde 
zurückgezogen, da muss sich keiner (mehr) dran halten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Die Tristate Geschichte musst du ausserhalb des Prozesses machen.
1
data_q <= data when ce = '1' and rd = '0' and wr = '1' else (others => 'Z');

Da meckert mir das Radiant:
1
(VHDL-1576) this construct is only supported in VHDL 1076-2008

Habe ich nicht ganz verstanden, alle VHDL-Tutorials benennen das 
when-Schlüsselwort für nebenläufige Anweisungen als schon immer 
vorhanden …

Wenn ich aber VHDL-2008 in den Einstellungen aktiviere, dann kackt die 
LSE mit einer segmentation violation ab. :/ SynplifyPro geht aber.

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Hast du diese Zeile in einem Prozess stehen? Dann waere das in der Tat 
2008 only.

Siehe z.B.:

https://www.doulos.com/knowhow/vhdl_designers_guide/vhdl_2008/vhdl_200x_ease/#sequential

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Hast du diese Zeile in einem Prozess stehen?

Upps, ja. Das war natürlich nicht beabsichtigt. :/

OK, außerhalb des Prozesses geht es natürlich auch ohne VHDL-2008 – aber 
LSE kackt trotzdem ab, sowie die Zeile drin ist.

Nun ja, es gibt ja noch SynplifyPro. :)

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Kannst du mal das File posten, bei dem LSE den Geist aufgibt? Dann kann 
ich hier auch mal probieren. LSE hat in der Tat ein paar Eigenheiten, 
aber bei dem Tri-State versagen, das waere ein Unding. :-O

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Tobias B. schrieb:
> Kannst du mal das File posten, bei dem LSE den Geist aufgibt?

Ja klar.

Ich habe mal einen Supportrequest dafür aufgemacht.

Egal, wie fehlerhaft der Code sein mag, ein segfault ist nie eine 
korrekte Antwort. ;-)

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Ok, gute Nachricht: Macht auch hier im Diamond (unter Linux) Aerger. 
Dann ma schauen was dem Tool nicht passt. :-/

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> Macht auch hier im Diamond (unter Linux) Aerger.

Wird ja vermutlich das gleiche Binary für die Synthese sein.

In irgendeiner Ecke hatte ich mal das Wort "DiamondNG" gelesen, das 
scheint das zu sein, als was das Programm mal ins Rennen gegangen ist. 
Danach haben sie ihm dann mit "Radiant" lieber einen neuen Namen 
gegeben.

: Bearbeitet durch Moderator
von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Jep, das wird wohl wirklich so sein.

Und ich bekomm in keiner Variante dazu, dass der Segfault verschwindet. 
Selbst wenn ich mich an das VHDL Template hlte klappt das nicht.

Bin mal gespannt was der Support dazu meint. In der Regel ist der 
wirklich hilfsbereit, zumindest waren meine bisherigen Erfahrungen sehr 
positiv.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

OK, jetzt auch mal die ersten 2 Bytes in einer Testbench geschrieben und 
gelesen. Sieht mir sinnvoll aus – OK, so sinnvoll, wie ein 
bidirektionaler Bus innerhalb eines FPGA halt sein kann.

Wenn man das jetzt noch nach außen pinnt, könnte man wohl das FPGA als 
teuren (und noch dazu getakteten) SRAM benutzen. :-)

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> OK, so sinnvoll, wie ein
> bidirektionaler Bus innerhalb eines FPGA halt sein kann.

Ja, der Bus muss ja nicht FPGA intern sein. Wenn du die Ports sauber 
nach aussen durchschleifst, dann bleibt der bi-direktionale Bus an den 
FPGA IOs.

Es gibt pro und contra Argumente das so zu tun, ich mischel da auch 
immer mal wieder durch, abhaengig davon welche Variante der einfacher zu 
lesende Code ist.

Bei einem einfachen Speicher faellt es allerdings auch mir schwer da ein 
gutes Argument zu finden. ;-)

von Christoph Z. (christophz)


Lesenswert?

Jörg W. schrieb:
> Wenn man das jetzt noch nach außen pinnt, könnte man wohl das FPGA als
> teuren (und noch dazu getakteten) SRAM benutzen. :-)

Vergleich mal die heutigen Preise von Dualport SRAM und einem FPGA.

In der letzten Firma hatten wir klassisch ein Dualport-RAM zwischen zwei 
Prozessoren vorgesehen. Habe dann mal überschlagen wie viel BlockRAMs 
ich dafür einsetzen könnte bzw. wie viel mehr ein grösserer FPGA 
kostest, wenn es nicht reichen würde im Vergleich zu separatem 
Dualport-RAM. (war ca. 2012):

1. Es gibt fasst nur noch Cypress das Dualport-RAMs baut
2. Damals gab es für den selben Preis einen FPGA der doppelt so viel 
Speicher hat oder umgekehrt, ein FPGA kostet die Hälfte zum 
vergleichbaren Dualport-RAM (ohne Entwicklungskosten) :-)

Geht natürlich nur, wenn man nicht aus ganz zwingenden Gründen wirklich 
ein asynchrones RAM braucht. Das FPGA Dualport-RAM wird immer synchron 
sein (wie die ganz schnellen Dualport-RAMs auch).

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Christoph Z. schrieb:
> Vergleich mal die heutigen Preise von Dualport SRAM und einem FPGA.

Na gut, ich hatte ja einen Singleport-RAM synthetisiert. Das war jetzt 
mehr als Übung, um mit dem ganzen Tristate-Geraffel mal irgendwas 
überhaupt anzustellen und ein Gefühl dafür zu bekommen. War ja auch gut 
so, gerade Tobias' Hinweise dazu waren durchaus wertvoll in der 
Lernkurve.

Aber interessant, dass ein FPGA, selbst wenn man große Teile davon brach 
liegen lässt, am Ende billiger ist als ein dedizierter Dualport-RAM. 
Dürfte an den Stückzahlen (und daraus folgend eher älterer 
Silizium-Techologie) liegen: externe Dualport-RAMs werden wohl nur eine 
Nische sein, FPGAs inzwischen ein Massenmarkt.

von Christoph Z. (christophz)


Lesenswert?

War ja mehr gedacht als interessante Anekdote zu deiner Aussage :-)

Jörg W. schrieb:
> Dürfte an den Stückzahlen (und daraus folgend eher älterer
> Silizium-Techologie) liegen: externe Dualport-RAMs werden wohl nur eine
> Nische sein, FPGAs inzwischen ein Massenmarkt.

Hatte mich damals auch überrascht und bin zum Selben Schluss gekommen.

Gratis bekommt man dann auch noch JTAG für den Fertigungstest, Debug 
Möglichkeiten, ja man kann sogar das RAM per Bitstream initialisieren. 
Und kann nebenbei auch gleich die letzten übrig gebliebenen 
Standard-Gatter ICs wegrationalisieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:
> 2.) Das vermute ich in diesem Fall: Lernen. :-)

Positiv: ich habe nun in der Testbench auch noch procedures verstanden 
und sogar mal eine for-Schleife verwendet. :) Damit wird sie angenehm 
übersichtlich:
1
  begin
2
    wait for 10 * T;
3
    wr_ram(X"48");
4
    a <= a + 1;
5
    wr_ram(X"65");
6
    a <= 42;
7
    wr_ram(X"21");
8
9
    data <= "ZZZZZZZZ";
10
    L1: for ad in 0 to 64 loop
11
      a <= ad;
12
      rd_ram(d);
13
    end loop L1;
14
    wait for T;
15
    data <= "ZZZZZZZZ";
16
    wait;
17
  end process;

von chris (Gast)


Lesenswert?

Das Thema Tri-State und RAM gab's hier schon mal:
Beitrag "Re: VHDL Grundlagen Ram"
Dort ging es auch darum, dass nicht alle Synthesetools die RAMs bei 
jedem Hersteller gleich syntethisieren.

von PCB (Gast)


Lesenswert?

Bei Xilinx gab es speziell ein Dokument dafür, wie man Code schreiben 
muß, damit das Synthesetool z.B. einen Block RAM erkennen kann.

Bei Lattice gibt es aber auch die Memory Guides, wo man sich die 
RAM-Module rauskopieren kann und im VHDL-Code eine Instanz daraus bilden 
kann.

Achja, deine Arrays kannst du auch mit der folgenden Zeile Code 
initialisieren:
signal cells: ram_t := (others => ( others => '0') );

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

PCB schrieb:

> Bei Lattice gibt es aber auch die Memory Guides, wo man sich die
> RAM-Module rauskopieren kann und im VHDL-Code eine Instanz daraus bilden
> kann.

Damit meinst du jetzt die speziellen Primitiven, die direkt EBR oder 
SPRAM instanziieren? Die sind mir bewusst, ich wollte ja hier vor allem 
sehen, ob/wie die Synthesetools auch von sich aus aus einem "generischen 
RAM" das erkennen. Das hat ja recht gut funktioniert.

> Achja, deine Arrays kannst du auch mit der folgenden Zeile Code
> initialisieren:
> signal cells: ram_t := (others => ( others => '0') );

Danke, gute Idee.

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Damit meinst du jetzt die speziellen Primitiven, die direkt EBR oder
> SPRAM instanziieren? Die sind mir bewusst, ich wollte ja hier vor allem
> sehen, ob/wie die Synthesetools auch von sich aus aus einem "generischen
> RAM" das erkennen. Das hat ja recht gut funktioniert.

Er meint schon reines VHDL, Architektur unspezifisch. Z.B. in 
https://www.xilinx.com/support/documentation/sw_manuals/xilinx10/books/docs/xst/xst.pdf 
auf Seite 199.

Wie man an deinem Beispiel gut sieht, sind die Synthese Tools nicht hart 
darauf angewiesen, dass ein RAM genau so beschrieben sein muss. Da hat 
man deutlich mehr Freihheitsgrade und ein Array aus Vektoren ist da 
schon fast alles was man braucht. :-)

von PCB (Gast)


Lesenswert?

Jörg W. schrieb:
> Damit meinst du jetzt die speziellen Primitiven, die direkt EBR oder
> SPRAM instanziieren? Die sind mir bewusst, ich wollte ja hier vor allem
> sehen, ob/wie die Synthesetools auch von sich aus aus einem "generischen
> RAM" das erkennen. Das hat ja recht gut funktioniert.

Hat das Synthesetool bei dir denn auch angezeigt, dass es eine RAM-Zelle 
erkannt hat?

Weil ich selber gerade das Problem hatte: bei den ice40 FPGAs gibt es 
keine verlässliche Angabe über die Timings der EBRs. Besonders beim 
Auslesen der EBRs hatte ich Probleme. Der Leseport wird bei mir direkt 
auf den IO gelegt und vom Timing her gabs bei einem Takt von ~25MHz 
Probleme beim Empfänger.

Warum machst du nicht eigentlich nur eine READ/WRITE Leitung, wo du doch 
noch ein Chip Enable hast?

@ Tobias:
Es stimmt zwar, dass ich zuerst die Coding Styles ansprach aber danach 
meinte ich schon die Primitiven.

von PCB (Gast)


Lesenswert?

Man sollte sich meiner Meinung nach schon über die Struktur der 
Primitiven Gedanken machen. Bei den ice40 FPGAs sind die EBRs z.B. nur 
Pseudo Dual-Port RAMse, haben also nur einen Lese- und einen 
Schreibport.
Und nur die 256x16Bit Primitive ist dort die Einzige, die eine 
Bitmaskierung anbietet, weil sie die Standardprimitive ist, aus der die 
anderen abgeleitet werden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias B. schrieb:

> Er meint schon reines VHDL, Architektur unspezifisch. Z.B. in
> 
https://www.xilinx.com/support/documentation/sw_manuals/xilinx10/books/docs/xst/xst.pdf
> auf Seite 199.

Gut, er schrieb auch was von Lattice, da hatte ich jetzt nichts so 
direktes gefunden.

> Da hat
> man deutlich mehr Freihheitsgrade und ein Array aus Vektoren ist da
> schon fast alles was man braucht. :-)

Das ist gut zu wissen. :)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

PCB schrieb:

> Hat das Synthesetool bei dir denn auch angezeigt, dass es eine RAM-Zelle
> erkannt hat?

Ja – sogar LSE, bevor es einen segfault geworfen hat. ;-)

> Warum machst du nicht eigentlich nur eine READ/WRITE Leitung, wo du doch
> noch ein Chip Enable hast?

Das hatte Tobias ja weiter oben schon angemerkt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.