Forum: FPGA, VHDL & Co. Datentypprobelm beim Compilieren


von ni (Gast)


Lesenswert?

Hallo,

ich habe ein kleines Problem mit meinem VHDL-Code. Bin noch blutiger 
Anfänger und ihr werdet wahrscheinlich die Hände über dem Kopf 
zusammenschlagen, aber ich komm nicht drauf, woran es liegt.. Ich mache 
einige Berechnungen mit Integer-Signalen. Anschließend werden diese in 
einen std_logic_vector umgewandelt, um sie weiter verarbeiten zu können. 
Der Code sieht so aus:
1
...
2
type DIOARRAY is array (0 to 752) of integer;
3
4
signal diffarray: DIOARRAY := (others =>0);
5
signal IW1: integer range 0 to 2147483647 := 0;
6
signal filter_zaehler: integer range 0 to 752 := 2;
7
signal IW1_std: std_logic_vector(27 downto 0);
8
...
9
10
when filter1 =>  clk_sel <= '1';
11
                    if filter_zaehler < dcount-nPer then
12
                      
13
                      filter_zaehler2 <= filter_zaehler + 2;
14
                      
15
                      IW1 <= IW1 + diffarray(filter_zaehler)-diffarray(filter_zaehler+2);  
16
                      
17
                      filter_zaehler <= filter_zaehler + nPer;    
18
                  
19
                      state <= filter1;
20
                      
21
                    else
22
                    
23
24
                      IW1 <= 2*IW1 + diffarray(1) + diffarray(dcount+2);  
25
                      filter_zaehler <= 3;  
26
                      
27
                      IW1_std <= std_logic_vector(to_unsigned(IW1,IW1_std'LENGTH));  
28
                      
29
                      state <= filter2;
30
                  
31
                    end if;
Das ist natürlich nicht der gesamte Code und ich hab ein paar 
Deklarationen weggelassen, aber die machen auch keine Probleme.
Kommentiert man hinter IW1 in der Zeile
1
 IW1 <= IW1 + diffarray(filter_zaehler)-diffarray(filter_zaehler+2);
 die beiden Arrays aus, läuft der Compiler durch. Lässt man sie drinnen, 
so läuft der Compiler im Schritt "Analysis & Synthesis" bis 46% und 
macht dann gar nichts mehr. Gleiches gilt für die Zeile
1
IW1 <= 2*IW1 + diffarray(1) + diffarray(dcount+2);
Das Programm hängt sich allerdings nicht auf, man kann die Compilation 
einfach beenden. Ich nutze Quartus II.

Vielen Dank schonmal für die Hilfe!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Datentypprobelm
Du hast hier kein Problem mit einem Datentypen, sondern eher ein 
Implementierungsproblem.

> IW1 <= IW1 + diffarray(filter_zaehler)-diffarray(filter_zaehler+2);
Das ist ein Riesenmegamultiplexer, da kann man sich als Synthesizer 
schon mal die Zähne ausbeißen...
Korrektur: zwei Riesenmegamultiplexer.

> Gleiches gilt für die Zeile IW1 <= 2*IW1 + diffarray(1) +
> diffarray(dcount+2);
Korrektur: drei Riesenmegamultiplexer...
Du solltest dir unbedingt das Thema RAM-Blöcke mal genauer anschauen.

> Das ist natürlich nicht der gesamte Code
Ist dieser Prozessausschnitt getaktet?

: Bearbeitet durch Moderator
von ni (Gast)


Lesenswert?

Das war auch meine Vermutung, dass diese Berechnung einfach abartig groß 
ist.
Wie kann man solche Berechnungen trotzdem durchführen? Ein Bekannter 
meinte ich sollte die entsprechende megafunction benutzen. Würde das was 
helfen? Dann wäre die Berechnung ja nicht mehr komplett in 
kombinatorischer Logik aufgebaut?

Lothar M. schrieb:
>> Das ist natürlich nicht der gesamte Code
> Ist dieser Prozessausschnitt getaktet?

Ja. Er läuft mit 50 MHz.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Ein Bekannter meinte ich sollte die entsprechende megafunction benutzen.
Welche?

Letztlich muss das Array in ein RAM. Und ein RAM hat nur 1 oder 2 Ports 
wo mit jeweils 1 Adresse auf 1 Wort pro Takt zugegriffen werden kann 
(zudem kommt noch Latency ins Spiel, weil die Daten erst im nächsten 
Takt verfügbar sind...).

Du musst also eigentlich die Schaltung mit Funktionsblöcken 
(Adresszähler, Rechenwerk, zumindest aber dem RAM) auf ein Blatt Papier 
aufzeichnen und das dann mit der HardwareBESCHREIBUNGssprache VHDL 
beschreiben. Den Schritt mit der Malerei kannst du dir sparen, wenn du 
dir die Schaltung vorstellen kannst, denn auch dann kannst du sie 
beschreiben.

ni schrieb:
> Ja. Er läuft mit 50 MHz.
Und wie schnell muss diese Berechnung abgearbeitet sein? Reicht es aus, 
wenn du erst ein Wort liest, dann das nächste und dann rechnest? Oder 
muss alles "gleichzeitig" gehen?

von ni (Gast)


Lesenswert?

Welche megafunction ist eine gute Frage. Mit der Thematik habe ich mich 
noch nicht weiter mit beschäftigt.

Lothar M. schrieb:
> ni schrieb:
>> Ja. Er läuft mit 50 MHz.
> Und wie schnell muss diese Berechnung abgearbeitet sein? Reicht es aus,
> wenn du erst ein Wort liest, dann das nächste und dann rechnest? Oder
> muss alles "gleichzeitig" gehen?
Also das Array "diffarray" wird in einem vorherigen state durch einen 
externen Datenstream gefüllt bzw. es wird mit der Differenz von je zwei 
aufeinanderfolgenden Werten des Datenstreams gefüllt, um noch größere 
Zahlen zu vermeiden. Das anschließende Aufsummieren
1
IW1 <= IW1 + diffarray(filter_zaehler)-diffarray(filter_zaehler+2);
 sollte möglichst schnell sein. Zielt deine Frage darauf ab, die Werte 
des Arrays zuerst alle umzuspeichern und dann in einem Weiteren Schritt 
aufzusummieren?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Das anschließende Aufsummieren
Mir erschließt sich da der Sinn der Subtraktion nicht ganz. Zwei Takte 
später wird die doch durch die Addition neutralisiert...

> sollte möglichst schnell sein. Zielt deine Frage darauf ab...
Einfach eine Zeit zu erfahren, in der die 750 Operationen durchlaufen 
sein müssen. Dann kann man sich eine Strategie ausdenken.


BTW: warum eine so "unbinäre" Zahl. Das ist ja fast, wie wenn dich wer 
zwingt, im Siebenersystem zu rechnen...

BTW2: warum nur die Differenz abspeichern?  Wie breit sind die Werte, 
die da hereinkommen?

von ni (Gast)


Lesenswert?

Lothar M. schrieb:
> ni schrieb:
>> Das anschließende Aufsummieren
> Mir erschließt sich da der Sinn der Subtraktion nicht ganz. Zwei Takte
> später wird die doch durch die Addition neutralisiert...

Jaein. Da stimmt natürlich, was du geschrieben hast. Das hängt 
allerdings mit dem Algorithmus an sich zusammen. Einige der Werte müssen 
herausfallen. Zusammen mit der Zählweise der if-Schleife (die ja nicht 
einfach um 1 inkrementiert) und der vorhin erwähnten Differenzen ergibt 
sich mein Filter. Da gibts sicherlich noch einiges an 
Optimierungspotential, das ist mir klar.

Lothar M. schrieb:
>> sollte möglichst schnell sein. Zielt deine Frage darauf ab...
> Einfach eine Zeit zu erfahren, in der die 750 Operationen durchlaufen
> sein müssen. Dann kann man sich eine Strategie ausdenken.

Ok. Das wäre als nächstes empirisch zu bestimmen (ja ich weiß, ist wie 
mit der Henne und dem Ei). Die Größenordnung liegt bei etwa 15µs.

Lothar M. schrieb:
> BTW: warum eine so "unbinäre" Zahl. Das ist ja fast, wie wenn dich wer
> zwingt, im Siebenersystem zu rechnen...

Welche meinst du? Die sind ja alle etwas unschön;) Aber leider lässt 
sich da auch nichts dran drehen. Die müssen für das Filter genau so 
sein. Vllt. kann man später noch die Schleifen dahingehend ändern, dass 
sie mit "schöneren" Werten läuft und anschließend eine entsprechende 
Korrektur am Ergebnis vornehmen - fällt auch unter den Punkt 
Optimierungsbedarf;)

Lothar M. schrieb:
> BTW2: warum nur die Differenz abspeichern?  Wie breit sind die Werte,
> die da hereinkommen?

Das hat was mit dem Filter zu tun, wie oben geschrieben. Die kleineren 
Werte sind nur ein willkommener Nebeneffekt. Im schlechtesten Fall kann 
ein Element ohne Bildung der Differenz den Wert 92044800 erreichen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Die Größenordnung liegt bei etwa 15µs.
50 * 15 gibt dann wieder die 750. Du kannst also dieses Array synchron 
genau 1x durchlaufen.

> Das hängt allerdings mit dem Algorithmus an sich zusammen. Einige der
> Werte müssen herausfallen.
Letztlich musst du aber nicht pro Takt 2x auf das RAM zugreifen, sondern 
kannst diese "voreilenden"  Subtraktionswerte ja einfach 
zwischenspeichern für die Addition zwei Takte später.

> Im schlechtesten Fall kann ein Element ohne Bildung der Differenz den
> Wert 92044800 erreichen.
Das passt doch problemlos in einen Integer...

: Bearbeitet durch Moderator
von ni (Gast)


Lesenswert?

Lothar M. schrieb:
>> Das hängt allerdings mit dem Algorithmus an sich zusammen. Einige der
>> Werte müssen herausfallen.
> Letztlich musst du aber nicht pro Takt 2x auf das RAM zugreifen, sondern
> kannst diese "voreilenden"  Subtraktionswerte ja einfach
> zwischenspeichern für die Addition zwei Takte später.

Ja das stimmt. Das werde ich auf jeden Fall noch einbauen. Allerdings 
ist die Berechnung immer noch zu groß. Lässt man das voreilende Array 
weg, klappt es auch nicht.

Lothar M. schrieb:
>> Im schlechtesten Fall kann ein Element ohne Bildung der Differenz den
>> Wert 92044800 erreichen.
> Das passt doch problemlos in einen Integer...

Ja klar passt das in ein Integer. Ist auch nicht der primäre Zweck der 
Differenzbildung.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Allerdings ist die Berechnung immer noch zu groß
Es ist nicht die Berechnung, sondern die Tatsache, dass das Array nach 
der derzeitigen Beschreibung nicht als RAM implementiert werden kann. 
Sieh dir mal im Handbuch zum Synthesizer an, wie der ein RAM beschrieben 
haben möchte...

von ni (Gast)


Lesenswert?

Lothar M. schrieb:
> ni schrieb:
> Allerdings ist die Berechnung immer noch zu groß
>
> Es ist nicht die Berechnung, sondern die Tatsache, dass das Array nach
> der derzeitigen Beschreibung nicht als RAM implementiert werden kann.
> Sieh dir mal im Handbuch zum Synthesizer an, wie der ein RAM beschrieben
> haben möchte...

Achso daran liegt es. Dann werde ich mir mal das Handbuch zu dem Thema 
anschauen. Könnte man das Array in kleinere Arrays aufteilen, die 
einzeln als RAM implementiert werden können?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Könnte man das Array in kleinere Arrays aufteilen, die einzeln als RAM
> implementiert werden können?
Sag ichs mal so: die Größe ist nicht das Problem...

von ni (Gast)


Lesenswert?

Lothar M. schrieb:
> ni schrieb:
> Könnte man das Array in kleinere Arrays aufteilen, die einzeln als RAM
> implementiert werden können?
>
> Sag ichs mal so: die Größe ist nicht das Problem...

Hm, dann hab ich es immer noch nicht durchschaut;)
Wenn nicht die Größe, was dann?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Wenn nicht die Größe, was dann?
Sieh dir das Datenblatt deines RAMs an. Und sieh dir an, wie viele Ports 
das RAM hat. Und wie der Synthesizer so ein RAM beschrieben haben 
möchte. So wie du es derzeit beschreiben hast, dürfte kein RAM 
herauskommen, denn du möchtest auf 2 Ports gleichzeitig lesen und sicher 
noch an einem dritten Port schreiben. Solche RAMs sind vorstellbar, aber 
es gibt sie nicht so ohne Weiteres. Sie müssen aus mehreren RAM-Blöcken 
zusammengebaut werden.

Mein Vorschlag: schreib einfach mal einen Dreizeiler, der ein RAM 
implementiert. Hier habe ich sowas mal für Xilinx gemacht:
http://www.lothar-miller.de/s9y/archives/20-RAM.html#extended

von ni (Gast)


Lesenswert?

Gut, weiter rumraten bringt ja nichts. Ich werde mal genau das tun, was 
du geschrieben hast und mir das mit den RAMs mal genau durchlesen. Mal 
schauen, ob ich es dann hinbekomme; )

von ni (Gast)


Lesenswert?

So, ich habe mal Lothars RAM Beispiel nachprogrammiert. Wie das 
funktioniert, ist mir jetzt relativ klar.
Bin mir jetzt nicht so ganz sicher über die Vorgehensweise zu meinem 
Problem. Speichere ich jetzt erst das gesamte diffarray in ein 
separates, von mir noch zu programmierendes, RAM und kann dann die 
Berechnung genau so durchführen, wie in meinem Code zu sehen, nur halt 
nicht mehr mit +diffarray(filter_zeahler), sondern mit +RAM(Adresse xy) 
pseudocodemäßig?

@Lothar: deine Seite ist echt hilfreich!:)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> So, ich habe mal Lothars RAM Beispiel nachprogrammiert.
Und im Ressourcenreport ein RAM gefunden?

> Speichere ich jetzt erst das gesamte diffarray in ein separates, von
> mir noch zu programmierendes, RAM und kann dann die Berechnung genau so
> durchführen, wie in meinem Code zu sehen, nur halt nicht mehr mit
> +diffarray(filter_zeahler), sondern mit +RAM(Adresse xy) pseudocodemäßig?
Laut Radio Eriwna: Im Prinzip ja!
Das Ziel muss zuerst mal sein, dass aus diesem Array ein RAM wird. Und 
danach musst du die Daten zum richtigen Zeitpunkt aus dem RAM 
herausbringen. Und dort spuckt dir der Umstand in die Suppe, dass du an 
so ein RAM die Adresse anlegen musst und dann am Takt zupfen, um die 
Daten zu bekommen. Du bekommst also bei einem pro Takt hochzählenden 
Adresszähler die Daten einen Takt später. Dieses Verhalten nennt sich 
Latency.

> deine Seite ist echt hilfreich!:)
Viel Spass damit.

von ni (Gast)


Lesenswert?

Lothar M. schrieb:
> Laut Radio Eriwna: Im Prinzip ja!

Na das klingt doch schonmal ermutigend;D

Ich habe mir gestern Abend mal meine Vorgehensweise überlegt:
Das RAM muss 752 Zeilen haben mit einer Wortbreite von 28 Bit damit von 
-920448800 bis 92044800 jeder Wert herein passt.
In dem state, in welchem ich das diffarray gefüllt habe, beschreibe ich 
nun mein RAM mit den selben Daten und inkrementiere jedes Mal die 
Schreibadresse - das ursprüngliche Array fällt weg. Meine statemaschine 
ändert ihren Zustand mit dem 50MHz Taktsignal. Das heißt, dass ich für 
das Speichern im RAM 752 Takte brauche, also etwa 15µs.
In dem state, in dem ich dann aufsummiere, hole ich mir wieder jeden 
Takt ein Wort aus dem RAM und inkrementier die Leseadresse. Diesen Wert 
addiere ich einfach auf meine ursprüngliche Variable IW1. Dauert also 
auch nochmal 15µs.
Die Daten stehen ja immer erst einen Takt später zur Verfügung, was ja 
nichts macht, dann werden sie halt erst im nächsten Takt zu IW1 addiert. 
Ich muss dann nur die Schleifen jeweils ein Inkrement länger laufen 
lassen, damit beim letzten Wert nicht nur die Adresse erhöht wird, 
sondern auch Daten in oder aus dem RAM geholt werden.

Wahrscheinlich lässt sich das Zwischenspeichern im diffarray bzw jetzt 
ja dann diffram sogar wegrationalisieren. Ich werde es aber erstmal so 
machen. Die 30µs Verarbeitungszeit sind dann halt so. Gehen müsste es 
trotzdem.

Klingt das halberwegs vernünftig?;)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Die 30µs Verarbeitungszeit sind dann halt so.
Wenn reicht... ;-)
Wenn du ein DPRAM hast, könntest du das Schreiben und Auswerten 
parallelisieren. Allerdings musst du dann aufpassen, dass du beim Lesen 
das Schreiben nicht überholst...

> Klingt das halberwegs vernünftig?;)
Das passt soweit. Die kleinen Problemchen, die sich dabei ergeben, musst 
du eben aus dem Weg räumen.

Ein Denkanstoß:
Nachdem du es jetzt so machst, dass du offenbar erst 15µs lang "von vorn 
nach hinten" ins RAM schreibst, und dann 15µs "von vorn nach hinten" 
verarbeitest, warum verarbeitest du das Eingangssignal dann nicht direkt 
"von vorn nach hinten" oder sogar dauernd durchlaufend "on the fly"?

: Bearbeitet durch Moderator
von ni (Gast)


Lesenswert?

Lothar M. schrieb:
>> Klingt das halberwegs vernünftig?;)
> Das passt soweit. Die kleinen Problemchen, die sich dabei ergeben, musst
> du eben aus dem Weg räumen.

Ja auf "Compilieren" drücken und funktioniert, erwarte ich auch nicht;D

Lothar M. schrieb:
> Nachdem du es jetzt so machst, dass du erst 15µs lang "von vorn nach
> hinten" ins RAM schreibst, und dann 15µs "von vorn nach hinten"
> verarbeitest, warum verarbeitest du das Eingangssignal dann nicht direkt
> "von vorn nach hinten" oder sogar dauernd durchlaufend "on the fly"?

Das ist das, was ich mit wegrationalisieren meinte. Je länger ich meinen 
Code angeschaut habe, desto klarer wird mir, dass es eigentlich ziemlich 
umständlich ist, wie ich es mache. Aber dafür weiß ich jetzt, wie man 
ein RAM benutzt, das ist doch auch was!;) Danke für deine Hilfe!

von ni (Gast)


Lesenswert?

Hallo,

ich habe meinen VHDL-Code nun umgebaut. Ich bin mir allerdings nicht 
ganz sicher, ob ich es richtig gemacht habe;)
Der Compiler bleibt nicht mehr während der Synthese stehen, dafür 
braucht er aber gefühlt ewig, um einmal durchzulaufen, wobei den größten 
Teil der Zeit der Fitter verbraucht. Wir reden hier von insgesamt etwa 
11 Minuten Compilingzeit... Ohne die RAMs sinds 20 Sekunden.
Im Compilation-Report ist mir aufgefallen, dass beim Punkt "Total logic 
elements" nun nicht mehr <1% sondern 68% stehen.
Der Compiler spuckt außerdem unter anderem die Info "Found 1 instances 
of uninferred RAM logic" aus.

von Klakx (Gast)


Lesenswert?

ni schrieb:
> 11 Minuten Compilingzeit

je nach Größe des Systems kann das auch länger dauern. Bei mir laufen 
auch Designs 2h durch Synthese+Implementierung, und das ist nicht mal 
der Extremfall.

von Markus F. (mfro)


Lesenswert?

ni schrieb:
> Der Compiler spuckt außerdem unter anderem die Info "Found 1 instances
> of uninferred RAM logic" aus.

Tja - es ist eben doch nicht alles RAM, was glänzt ;).

Lies' Dir das Kapitel mit der RAM-Inferierung noch einmal durch.

von ni (Gast)


Lesenswert?

Klakx schrieb:
> ni schrieb:
>> 11 Minuten Compilingzeit
>
> je nach Größe des Systems kann das auch länger dauern. Bei mir laufen
> auch Designs 2h durch Synthese+Implementierung, und das ist nicht mal
> der Extremfall.

Na dann bin ich ja noch gut bedient mit 11 Minuten;)

Wenn im Compilation Report die Anzahl der logischen Elemente gestiegen 
ist, dann spricht das doch sehr dafür, dass ich distributed RAM und kein 
Block-RAM gebastelt hab? Ich habe nicht explizit ein wait until o.ä. wie 
in Lothars Beispiel zum RAM verwendet, da meine statemaschine sowieso 
auf die steigende Flanke des Taktsignals reagiert.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

ni schrieb:
> Ich habe nicht explizit ein wait until o.ä. wie in Lothars Beispiel zum
> RAM verwendet
Aber du hast den Abschnitt "Inferring RAM"  o.ä. im Synthesizer Handbuch 
gelesen und dich an die Beschreibung und die Beispiele dort gehalten?

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.