RAM: warum nicht synthetisierbar?

OP Moderator Persönliche Seite #6280008
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.
Angehängte Dateien:
Gast #6280034
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.
OP Moderator Persönliche Seite #6280115
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.
Angehängte Dateien:
Gast #6280195
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.
OP Moderator Persönliche Seite #6280226
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.
#6280229
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.
#6280247
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
(Firma: www.elpra.de) Persönliche Seite #6280347
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.
Angehängte Dateien:
OP Moderator Persönliche Seite #6280441
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 …
(Firma: www.elpra.de) Persönliche Seite #6280498
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. ;-)
OP Moderator Persönliche Seite #6280506
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.
(Firma: www.elpra.de) Persönliche Seite #6280846
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. :-)
(Firma: www.elpra.de) Persönliche Seite #6281006
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. :-)
OP Moderator Persönliche Seite #6281245
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!
#6281508
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.
OP Moderator Persönliche Seite #6282282
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.
OP Moderator Persönliche Seite #6282335
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.
OP Moderator Persönliche Seite #6282372
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. :-)
Angehängte Dateien:
(Firma: www.elpra.de) Persönliche Seite #6282407
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. ;-)
#6282591
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).
OP Moderator Persönliche Seite #6282607
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.
#6283050
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.
OP Moderator Persönliche Seite #6283635
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;
Gast #6284860
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') );
OP Moderator Persönliche Seite #6284911
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.
(Firma: www.elpra.de) Persönliche Seite #6285001
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. :-)
Gast #6285028
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.
Gast #6285033
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.
OP Moderator Persönliche Seite #6285172
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. :)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren