mikrocontroller.net

Forum: FPGA, VHDL & Co. FPGA überfüllt -> Brauche Hilfe bei der Optimierung.


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen

Ich versuch, eine eigentlich einfache Aufgabe mittels eines FPGAs zu 
lösen.
Leider aber wird mein VHDL-Code in eine riesige Struktur synthetisiert. 
Ich habe bereits eine Verdacht warum, aber ich wärse sehr froh um eure 
Hilfe bei der Optimierung.

Ausgangslage:

Chip: Lattice MachXO3-4300C Speedgrade 5

Beim FPGA kommen externe RGB Daten an (insgesamt drei std_logic_vector 
(7 downto 0))

Diese Vektoren verden verrechnet und es steht ein Ergebnis in einem 
signal namens RESULT.

Nun gut. Dieses Resultat wird nun in einem zweidimensionalen Array 
bestehend aus Integer gespeichert. Nennen wird deses Array 
RGB_RES_ARRAY()().
Das Array ist wie folgt definiert:
  type t_RESMemory_row is array (0 to 17) of integer range 0 to 65535;
  type t_RES_Array is array (0 to 15) of t_LEDMemory_row;

....

signal RGB_RES_ARRAY: t_RES_Array;

In dieses Array wird nun synchron zu einem übergeordneten Clock das 
Resultat gespeichert:
entity rgbanalyzer is
  port( 
...
DATA_OUT : out t_RES_Array;
...     

);
end rgbanalyzer;
....

process (CLK)
if(rising_edge(CLK)) then     
..
 if(RESULT > RGB_RES_ARRAY(row)(col)) then

        RGB_RES_ARRAY(row)(col) <= RESULT;
     end if;
   ...
   end if;

Ebenfalls clock synchron wird dieses Array an den Ausgangsport der 
Entity gelegt.

..
if(col > foo) then 
  DATA_OUT <= RGB_RES_ARRAY;
  DATA_SEND_REQ <= '1';
end if;


Nun werden in einer übergeordneten Entity die Daten umgemappt.

type t_Memory_row is array (0 to 48) of integer range 0 to 65535;
type t_TX_Engine is array (0 to 5) of t_Memory_row;

signal TX_ENGINE_DATA_IN : t_TX_Engine;
....

TX_ENGINE_DATA_IN(0)(0)  <= RGB_DATA_OUT (0)(0);
TX_ENGINE_DATA_IN(0)(16) <= RGB_DATA_OUT (0)(1);
TX_ENGINE_DATA_IN(0)(32) <= RGB_DATA_OUT (0)(2);
TX_ENGINE_DATA_IN(1)(0)  <= RGB_DATA_OUT (0)(3);
TX_ENGINE_DATA_IN(1)(16) <= RGB_DATA_OUT (0)(4);
TX_ENGINE_DATA_IN(1)(32) <= RGB_DATA_OUT (0)(5);
TX_ENGINE_DATA_IN(2)(0)  <= RGB_DATA_OUT (0)(6);
TX_ENGINE_DATA_IN(2)(16) <= RGB_DATA_OUT (0)(7);
TX_ENGINE_DATA_IN(2)(32) <= RGB_DATA_OUT (0)(8);
(weitere mappings)
....

In der TX-Engine selbst, werden die Daten nochmals von integer in 
std_logic_vectoren umgewandelt und dabei in ein langes Schieberegister 
gemappt.
tmpDataRegister(15 downto 0)    <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(47), 16));
tmpDataRegister(31 downto 16)   <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(46), 16));
tmpDataRegister(47 downto 32)   <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(45), 16));
tmpDataRegister(63 downto 48)   <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(44), 16));
tmpDataRegister(79 downto 64)   <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(43), 16));
tmpDataRegister(95 downto 80)   <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(42), 16));
tmpDataRegister(111 downto 96)  <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(41), 16));
tmpDataRegister(127 downto 112) <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(40), 16));
tmpDataRegister(143 downto 128) <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(39), 16));
tmpDataRegister(159 downto 144) <= std_logic_vector(to_unsigned( TX_ENGINE_DATA_IN(foo)(38), 16));
(weitere konvertierungen)
...

Nach der Synthese bzw. dem Mapping sieht der Report wie folgt aus:
Design Summary
   Number of registers:  14792 out of  4941 (299%)
      PFU registers:        14792 out of  4320 (342%)
      PIO registers:            0 out of   621 (0%)
   Number of SLICEs:      9208 out of  2160 (426%)
      SLICEs as Logic/ROM:   9208 out of  2160 (426%)
      SLICEs as RAM:            0 out of  1620 (0%)
      SLICEs as Carry:         78 out of  2160 (4%)
   Number of LUT4s:        8789 out of  4320 (203%)
      Number used as logic LUTs:        8633
      Number used as distributed RAM:     0
      Number used as ripple logic:      156
      Number used as shift registers:     0

Wenn ich hingegen diese eine Zeile:
RGB_RES_ARRAY(row)(col) <= RESULT;

Dahingehend ändere (in eine fixe Zuweisung):
RGB_RES_ARRAY(row)(col) <= 123;

So ergibt der Report folgendes:
Design Summary
   Number of registers:     75 out of  4941 (2%)
      PFU registers:           75 out of  4320 (2%)
      PIO registers:            0 out of   621 (0%)
   Number of SLICEs:       241 out of  2160 (11%)
      SLICEs as Logic/ROM:    241 out of  2160 (11%)
      SLICEs as RAM:            0 out of  1620 (0%)
      SLICEs as Carry:         16 out of  2160 (1%)
   Number of LUT4s:        481 out of  4320 (11%)
      Number used as logic LUTs:        449
      Number used as distributed RAM:     0
      Number used as ripple logic:       32
      Number used as shift registers:     0


Die Frage die sich mir nun stellen sind:

- Ist die Konvertierung von Integer zu std_logic_vector evtl. Ressourcen 
intensiv?

- Ist es ein Problem, dass ich mehrere solcher Arrays verwende?

- Die VHDL-Bedingungen scheinen sehr viele Multiplexer zu erzeugen. Gibt 
es für das von mir benötigte Mapping evtl. elegantere Umwege?

- Hat evtl. jemand allgemein eine Idee für mein Problem?


Danke!

von Dergute W. (derguteweka)


Bewertung
0 lesenswert
nicht lesenswert
Moin,

Solche Vergleiche auf groesser/kleiner stell' ich mir ressourcenhungrig 
vor:

RESULT > RGB_RES_ARRAY(row)(col)

Gruss
WK

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


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> - Ist die Konvertierung von Integer zu std_logic_vector evtl. Ressourcen
> intensiv?

Nein. Synthetisier doch einfach mal ein Minimalbeispiel in dem nichts 
anderes drin ist als eine Konvertierung von int zu std_logic. Dann 
kannst im RTL Viewer ja sehen was passiert.

von Charles G. (Firma: Ingenieurbuero Gardiner) (cfgardiner)


Bewertung
0 lesenswert
nicht lesenswert
Hej,

type t_RESMemory_row is array (0 to 17) of integer range 0 to 65535;

ist schon verdächtig groß. Aus den deinem Reports fehlen leider auch die 
Angaben, ob du embedded Memory Blöcke überhaupt verwendest.  Je nach 
Anwendung, könnten diese die restliche Logik erheblich entlasten.

z.B. (ohne deine Schaltung genau zu kennen, aber aus meiner vergangenen 
Lösungen), einen BMRAM als Pipeline verwenden, zyklisch hineinschreiben 
und einen konstanten Abstand zwischen Schreib- und Lese-Pointer 
verwenden.

Viel Erfolg.

von Strubi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich hab's jetzt nur schnell diagonal gelesen, aber der hier:

Holger K. schrieb:
> RGB_RES_ARRAY(row)(col) <= RESULT;

sorgt sehrwahrscheinlich dafuer, dass der Mapper nicht mehr einen EBR 
fuer dein RAM inferiert (und alles in die LUTs packen muss). Bei einem 
konstanten Wert schon. Guck doch auch mal nach den EBR in den 
Mapper-Stats.

Also: no such fun. Wenn du so in das RAM schreiben willst, musst du eine 
I/O-Logik dazu basteln.

von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Danke für eure Antworten.

Charles G. schrieb:
> ist schon verdächtig groß.

Ja. Ist wirklich nicht klein!

Charles G. schrieb:
> Aus den deinem Reports fehlen leider auch die
> Angaben, ob du embedded Memory Blöcke überhaupt verwendest.

Nein, aktuell verwende ich kein Memory dafür.

Charles G. schrieb:
> zyklisch hineinschreiben
> und einen konstanten Abstand zwischen Schreib- und Lese-Pointer
> verwenden.

Wie meinst du zyklisch hineinschreiben?

Ich muss für meine Anwendung immer ein wenig am RAM ergänzen bzw. ändern 
und dann wieder das gesamte Memory auslesen. Dann wieder ein Paar werte 
anpassen und wieder Auslesen.

Daher kann der Abstand zwischen schreib und lese-pointer nie konstant 
sein. Müsste ich dafür evtl. ein Dualport BMRAM verwenden?

von Laserfreak (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:

> Leider aber wird mein VHDL-Code in eine riesige Struktur synthetisiert.

Dann packe dein komplettes Projekt in eine Zip-Datei und lade sie hier 
hoch.

von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Strubi schrieb:
> Guck doch auch mal nach den EBR in den
> Mapper-Stats.

Danke für die Antwort. Hier der komplette Log:
Design Summary
   Number of registers:  14792 out of  4941 (299%)
      PFU registers:        14792 out of  4320 (342%)
      PIO registers:            0 out of   621 (0%)
   Number of SLICEs:      9208 out of  2160 (426%)
      SLICEs as Logic/ROM:   9208 out of  2160 (426%)
      SLICEs as RAM:            0 out of  1620 (0%)
      SLICEs as Carry:         78 out of  2160 (4%)
   Number of LUT4s:        8789 out of  4320 (203%)
      Number used as logic LUTs:        8633
      Number used as distributed RAM:     0
      Number used as ripple logic:      156
      Number used as shift registers:     0
   Number of PIO sites used: 79 + 4(JTAG) out of 207 (40%)
      Number of PIO sites used for single ended IOs: 63
      Number of PIO sites used for differential IOs: 20 (represented by 10 PIO
     comps in NCD)
   Number of IDDR/ODDR/TDDR cells used: 9 out of 621 (1%)
      Number of IDDR cells:   0
      Number of ODDR cells:   9
      Number of TDDR cells:   0
   Number of PIO using at least one IDDR/ODDR/TDDR: 9 (9 differential)
      Number of PIO using IDDR only:        0 (0 differential)
      Number of PIO using ODDR only:        9 (9 differential)
      Number of PIO using TDDR only:        0 (0 differential)
      Number of PIO using IDDR/ODDR:        0 (0 differential)
      Number of PIO using IDDR/TDDR:        0 (0 differential)
      Number of PIO using ODDR/TDDR:        0 (0 differential)
      Number of PIO using IDDR/ODDR/TDDR:   0 (0 differential)
   Number of block RAMs:  0 out of 10 (0%)
   Number of GSRs:        1 out of 1 (100%)
   EFB used :        No
   JTAG used :       No
   Readback used :   No
   Oscillator used : Yes
   Startup used :    No
   POR :             On
   Bandgap :         On
   Number of Power Controller:  0 out of 1 (0%)

   Number of Dynamic Bank Controller (BCINRD):  0 out of 6 (0%)
   Number of Dynamic Bank Controller (BCLVDSO):  0 out of 1 (0%)
   Number of DCCA:  0 out of 8 (0%)
   Number of DCMA:  0 out of 2 (0%)
   Number of PLLs:  1 out of 2 (50%)
   Number of DQSDLLs:  0 out of 2 (0%)
   Number of CLKDIVC:  1 out of 4 (25%)
   Number of ECLKSYNCA:  1 out of 4 (25%)
   Number of ECLKBRIDGECS:  0 out of 2 (0%)
   Notes:-
      1. Total number of LUT4s = (Number of logic LUT4s) + 2*(Number of
     distributed RAMs) + 2*(Number of ripple logic)
      2. Number of logic LUT4s does not include count of distributed RAM and
     ripple logic.

Scheint kein EBR verwendet worden zu sein.

Strubi schrieb:
> musst du eine
> I/O-Logik dazu basteln.

Wie stellst du dir diese vor? bzw. was soll diese genau umsetzen?

Laserfreak schrieb:
> Holger K. schrieb:
>
>> Leider aber wird mein VHDL-Code in eine riesige Struktur synthetisiert.
>
> Dann packe dein komplettes Projekt in eine Zip-Datei und lade sie hier
> hoch.

Werde ich sogleich tun.

: Bearbeitet durch User
von Laserfreak (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Strubi schrieb:
>> Guck doch auch mal nach den EBR in den
>> Mapper-Stats.
>
> Danke für die Antwort. Hier der komplette Log:

Jetzt noch das Projekt und wir können es durchsehen

von Achim S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Meine Glaskugel sagt: du versuchst die Berechnung für das gesamte Array 
auf einmal durchzuführen. Sinnvoller wäre, das nacheinander für jedes 
Element des Array durchzuführen.

Um beides unterscheiden zu können wäre hilfreich, was in diesem Prozess 
von dir

process (CLK)
if(rising_edge(CLK)) then
..
 if(RESULT > RGB_RES_ARRAY(row)(col)) then

        RGB_RES_ARRAY(row)(col) <= RESULT;
     end if;
   ...
   end if;

mit row und column während eines Taktzyklus passiert. Sind das Signale, 
die taktsynchron durchzählen (also pro Takt nur eine Element des Arrays 
ansprechen)? Oder sind das Variablen, die du innerhalb des gezeigten 
Prozesses in Schleifen durchzählst (also pro Takt alle Elemente des 
Arrays ansprechen)?

Laserfreak schrieb:
> Jetzt noch das Projekt und wir können es durchsehen

Damit ließe sich meine Glaskugel dann wieder rekalibrieren ;-)

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Sicherlich gibt es (wie bei den üblichen Verdächtigen) auch bei Lattice 
ein Kapitel "recommended design practice" (oder so ähnlich), das dir 
Infos darüber liefert, wie Du die Synthese dazu bringst, ROM-Strukturen 
im Memory anzulegen?

von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Sicherlich gibt es (wie bei den üblichen Verdächtigen) auch bei
> Lattice
> ein Kapitel "recommended design practice" (oder so ähnlich), das dir
> Infos darüber liefert, wie Du die Synthese dazu bringst, ROM-Strukturen
> im Memory anzulegen?

Gute Idee. Das sollte ich mir anschauen.

Hier noch das Projekt zum download:

https://omega.databyte.ch/index.php/s/nD8DL9f4Xm9KJew/download

von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Hat sich das Projekt schon jemand angeschaut?

Bezüglich dem RAM habe ich dieses Dokument gefunden.
Hast du dieses gemeint?

https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/LZ/LSETutorial311.ashx?document_id=51562

(Seite 10)
// RAM that can be inferred by LSE.
module RAM_single_port (Address, Data, Clock, WE, ClockEn, Q);
parameter addr_width = 5;
parameter data_width = 8;
input [addr_width-1:0] Address;
input [data_width-1:0] Data, Q;
input WE, Clock, ClockEn;
reg [data_width-1:0] mem [(1<<addr_width)-1:0];
// Define RAM as an indexed memory array.
always @(posedge Clock) // Control with a clock edge.
begin
if (ClockEn)
if (WE) // And control with a write enable.
mem[(Address)] <= Data;
end
assign Q = mem[Address];
endmodule

von Achim S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Hat sich das Projekt schon jemand angeschaut?

Nicht das ganze Projekt. Aber immerhin mal so viel, um ein Beispiel daür 
zu finden, wodurch du sehr große Logikblöcke erzeugst.

Dieser Code in rgbanalyzer.vhd steht innerhalb eines getakteten 
Prozesses:
for I in 0 to led_count_x loop
      if I < led_count_x then
        if X_POS+1 > boundaries_x(I) and X_POS+1 < boundaries_x(I+1) then
          col <= I+1;
        end if;
      else
        if X_POS+1 > boundaries_x(I) and X_POS+1 < boundaries_x(led_count_x) then
          col <= I+1;
        end if;
      end if;

      if X_POS+1 > 0 and X_POS+1 < boundaries_x(0) then
        col <= 0;
      end if;
    end loop;

Du beschreibst hiermit, dass gleichzeitig (innerhalb eines Taktzyklus) 
led_count_x Berechnungen auf einmal durchgeführt werden. Damit kann z.B. 
boundaries_x nicht in einem Blockram gespeichert werden, weil alle 
Elemente davon gleichzeit benötigt werden. Und du hast einen 
entsprechend große Logik, um all diese Berechnungen innerhalb eines 
Taktzyklus durchführen zu können.

Sehr viel kompakter würde das, wenn du pro Taktzyklus nur einen Wert von 
I betrachten würdest. Und dann mit dem Takt I von 0 bis led_count_x 
(-1?) hochzählen würdest. Dann würde das ganze halt nicht einen Takt 
dauern sondern led_count_x Takte.

led_count_x ist nur 18, deshalb kann es ggf. sein, dass du wirklich die 
gleichzeitige, parallele Berechnung auf alle 18 Elemente anwenden 
willst. Aber schau deinen Code mal kritisch nach weiteren for-Schleifen 
innerhalb von Prozessen durch. Wenn die Schleife über viele Elemente 
läuft (z.B. bei geschachtelten Schleifen), dann wird die erzeugte Logik 
automatisch riesig.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Hast du dieses gemeint?

Wahrscheinlich habe ich das gemeint (Lattice kenn' ich nicht).

Aber die müssten ja auch was aus der VHDL-Abteilung haben, oder nicht?

von Strubi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Scheint kein EBR verwendet worden zu sein.
>

Das war zu erwarten. Jetzt nochmal mit dem Fall der statischen 
Konstanten, da solltest du eine EBR-Instanzierung sehen.


> Strubi schrieb:
>> musst du eine
>> I/O-Logik dazu basteln.
>
> Wie stellst du dir diese vor? bzw. was soll diese genau umsetzen?

Du musst da dem 'Standard' fuer inferierbare Memories folgen, oben hast 
du ja schon die Verilog-Version zitiert.
Such dir sonst hier eins aus:

https://github.com/hackfin/MaSoCist/tree/opensource/hdl/ram

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Bezüglich dem RAM habe ich dieses Dokument gefunden.
Sieh dir mal die Technical Note TN1290 (bzw. den Memory Usage Guide for 
MachXO3 Devices) näher an.

von Charles G. (Firma: Ingenieurbuero Gardiner) (cfgardiner)


Bewertung
0 lesenswert
nicht lesenswert
Hej,

für Lattice gibt es auch z.B.
http://www.latticesemi.com/view_document?document_id=48203 (HDL Coding 
guidelines)

http://www.latticesemi.com/view_document?document_id=51556 (Lattice 
Synthesis Engine (LSE) User Guide)

und falls du Diamond heruntergeladen hast, die ganze Synplify 
Dokumentation im Verzeichnis C:\lscc\diamond\3.11_x64\synpbase\doc

von Holger K. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Achim S. schrieb:
> Dieser Code in rgbanalyzer.vhd steht innerhalb eines getakteten
> Prozesses:for I in 0 to led_count_x loop
>       if I < led_count_x then
>         if X_POS+1 > boundaries_x(I) and X_POS+1 < boundaries_x(I+1)
> then
>           col <= I+1;
>         end if;
>       else
>         if X_POS+1 > boundaries_x(I) and X_POS+1 <
> boundaries_x(led_count_x) then
>           col <= I+1;
>         end if;
>       end if;
>
>       if X_POS+1 > 0 and X_POS+1 < boundaries_x(0) then
>         col <= 0;
>       end if;
>     end loop;
>
> Du beschreibst hiermit, dass gleichzeitig (innerhalb eines Taktzyklus)
> led_count_x Berechnungen auf einmal durchgeführt werden. Damit kann z.B.
> boundaries_x nicht in einem Blockram gespeichert werden, weil alle
> Elemente davon gleichzeit benötigt werden. Und du hast einen
> entsprechend große Logik, um all diese Berechnungen innerhalb eines
> Taktzyklus durchführen zu können.
>
> Sehr viel kompakter würde das, wenn du pro Taktzyklus nur einen Wert von
> I betrachten würdest. Und dann mit dem Takt I von 0 bis led_count_x
> (-1?) hochzählen würdest. Dann würde das ganze halt nicht einen Takt
> dauern sondern led_count_x Takte.
>
> led_count_x ist nur 18, deshalb kann es ggf. sein, dass du wirklich die
> gleichzeitige, parallele Berechnung auf alle 18 Elemente anwenden
> willst. Aber schau deinen Code mal kritisch nach weiteren for-Schleifen
> innerhalb von Prozessen durch. Wenn die Schleife über viele Elemente
> läuft (z.B. bei geschachtelten Schleifen), dann wird die erzeugte Logik
> automatisch riesig.

Danke für deine Antwort.

Bei diesem Codeabschnitt geht es darum zu prüfen, in welchem Abschnitt 
sich die aktuelle X bzw. Y-Position befindet.

Die Grenzen wurden zuvor mittels:
  genboundsX :
  for I in 0 to led_count_x generate
    boundaries_x(I) <= ((display_width) / (led_count_x + 1)) * (I+1);
  end generate;

  genboundsY :
  for I in 0 to led_count_y generate
    boundaries_y(I) <= ((display_heigth) / (led_count_y + 1)) * (I+1);
  end generate;

Definiert.
Obiger Code sollte eigentlich Konstanten generieren.

von Holger K. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hier das ganze ausgeschrieben:
  if X_POS+1 > boundaries_x(0) and X_POS+1 < boundaries_x(1) then
    col <= 1;
  elsif X_POS+1 > boundaries_x(1) and X_POS+1 < boundaries_x(2) then
    col <= 2;
  elsif X_POS+1 > boundaries_x(2) and X_POS+1 < boundaries_x(3) then
    col <= 3;
  elsif X_POS+1 > boundaries_x(3) and X_POS+1 < boundaries_x(4) then
    col <= 4;
  ....
  elsif X_POS+1 > boundaries_x(14) and X_POS+1 < boundaries_x(15) then
    col <= 15;
  elsif X_POS+1 > boundaries_x(15) and X_POS+1 < boundaries_x(16) then
    col <= 16;
  elsif X_POS+1 > boundaries_x(16) and X_POS+1 < boundaries_x(17) then
    col <= 17;
  else
    col <= 0;
  end if;

Denkt ihr, das dieser Code schneller ist als jener mit for?
Eigentlich erwarte ich, dass das synthese tool selbst ein ensprechendes 
Konstrukt  generiert.

von Achim S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Die Grenzen wurden zuvor mittels:
> ......
> Definiert.
> Obiger Code sollte eigentlich Konstanten generieren.

Ok. Mit "zuvor ermittelt" meinst du "zuvor während der Synthese", d.h. 
die Konstanten werden bereits auf deinem PC berechnet und dann als 
konstanter Wert in die Konfiguration des FPGA übernommen? Dann vergiss 
meinen früheren Beitrag.

Oder meinst du mit "zuvor" etwas, was während der "Laufzeit" bestimmt 
werden muss (also nicht vom PC, sondern vom FPGA)? In dem Fall bleibt es 
bei meiner früheren Aussage: du generierst damit eine riesige Logik.

Holger K. schrieb:
> Denkt ihr, das dieser Code schneller ist als jener mit for?

Wieso jetzt "schneller"? Ich dachte dein Problem sei, dass dein FPGA 
überläuft. Geschwindigkeit und Ressourcenverbrauch sind oft 
gegensätzliche Anforderungen: du kannst Ressourcen im FPGA sparen (ein 
"kleineres" Design machen) wenn du bereit bist, Berechnungen nicht 
parallel durchzuführen sondern - von einem Takt gesteuert - 
nacheinander.

von Holger K. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Achim S. schrieb:
> Ok. Mit "zuvor ermittelt" meinst du "zuvor während der Synthese", d.h.
> die Konstanten werden bereits auf deinem PC berechnet und dann als
> konstanter Wert in die Konfiguration des FPGA übernommen?

Das war das Ziel bei diesem Code:
  genboundsX :
  for I in 0 to led_count_x generate
    boundaries_x(I) <= ((display_width) / (led_count_x + 1)) * (I+1);
  end generate;

  genboundsY :
  for I in 0 to led_count_y generate
    boundaries_y(I) <= ((display_heigth) / (led_count_y + 1)) * (I+1);
  end generate;

Achim S. schrieb:
> Wieso jetzt "schneller"? Ich dachte dein Problem sei, dass dein FPGA
> überläuft. Geschwindigkeit und Ressourcenverbrauch sind oft
> gegensätzliche Anforderungen: du kannst Ressourcen im FPGA sparen (ein
> "kleineres" Design machen) wenn du bereit bist, Berechnungen nicht
> parallel durchzuführen sondern - von einem Takt gesteuert -
> nacheinander.

Ja du hast natürlich recht. Ich meine nicht schneller. Sondern 
platzsparender.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Hier das ganze ausgeschrieben:
>
>
>   if X_POS+1 > boundaries_x(0) and X_POS+1 < boundaries_x(1) then
>     col <= 1;
>   elsif X_POS+1 > boundaries_x(1) and X_POS+1 < boundaries_x(2) then
>     col <= 2;
...
> 
>
> Denkt ihr, das dieser Code schneller ist als jener mit for?
> Eigentlich erwarte ich, dass das synthese tool selbst ein ensprechendes
> Konstrukt  generiert.

Wenn dein Synthesetool nicht schlau genug ist herauszufinden, dass hier 
nur ein Fall zutreffend sein kann, wird es möglicherweise daraus einen 
Priority-Encoder bauen (ich bin gerade nicht motiviert genug, das selbst 
rauszufinden).

Jedenfalls fährst Du m.E. hier mit separaten if's u.U. besser.

von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Danke für deine Antwort.

Habe herausgefunden, dass das Problem gar nicht in diesem Code-Abschnitt 
liegt.

Das FPGA überfüllt bei der Ausgabefunktion an den SPI, da hier ebenfalls 
ein 288 x 16Bit grosses register liegt.

Wenn ich nur schon diese Register hochzähle (ohne irgendwelche Pixel 
analyse) eskaliert mir die Netzlistengrösse...

Mal eine Grundsätzliche Frage:

Ist ein FPGA mit diesen Eckdaten:
Design Summary
   Number of registers:  14792 out of  4941 (299%)
      PFU registers:        14792 out of  4320 (342%)
      PIO registers:            0 out of   621 (0%)
   Number of SLICEs:      9208 out of  2160 (426%)
      SLICEs as Logic/ROM:   9208 out of  2160 (426%)
      SLICEs as RAM:            0 out of  1620 (0%)
      SLICEs as Carry:         78 out of  2160 (4%)
   Number of LUT4s:        8789 out of  4320 (203%)
      Number used as logic LUTs:        8633
      Number used as distributed RAM:     0
      Number used as ripple logic:      156
      Number used as shift registers:     0

Aus eurer Erfahrung heraus überhaupt geeignet eine Aufgabe wie die hier 
geplante umzusetzen?

Ziel ist es: Bildinhalt Pixelweise zu analysieren und dabei die 
Helligkeit pro Segment zu bestimmen. Diese Information (288 x 16Bit 
Wert) soll dann mittels SPI ausgegeben werden.

An sich eine banale Aufgabe aber scheinbar mit meiner jetzigen 
Implementierung nicht optimal gelöst. An der Implementierung des RAMs 
arbeite ich noch.

Aber denkt ihr, sowas sollte mit  den obigen Ressourcen machbar sein?
Oder schiesst das total über die Ressourcen hinaus?

: Bearbeitet durch User
von Achim S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Aber denkt ihr, sowas sollte mit  den obigen Ressourcen machbar sein?

wenn das Bild selbst ins blockram passt, dann sollte der Rest deines 
Designs lockerst ins FPGA passen. Mehr als ein paar Zähler, Addierer, 
kleine Schieberegister, einen FIFO für's SPI und ein bisschen FSM 
sollten nicht dabei herauskommen

von Achim S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
noch eine kleine Ergänzung zu:

Achim S. schrieb:
> einen FIFO für's SPI

Wenn die Reihenfolge des Datenzugriffs über SPI wahlfrei sein soll, dann 
natürlich kein FIFO sondern ein Blockram. Aber es sollten eben nicht 
288*16=4608 Register dafür verschwendet werden, wenn die Daten 
genausogut in einem Blockram gehalten werden können.

von Holger K. (holgerkraehe)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Achim S. schrieb:
> 288*16=4608 Register dafür verschwendet werden, wenn die Daten

Danke für deine Antwort.
Das macht absolut Sinn!

Achim S. schrieb:
> wenn das Bild selbst ins blockram passt, dann sollte der Rest deines
> Designs lockerst ins FPGA passen.

Nun, das Bild selbst möchte ich ja garnicht zwischenspeichern.

Mein Ziel ist folgendes: (siehe Bild im Anhang)

Ich Habe Zugang zum Bilddatenstrom innerhalb des FPGAs. Nun erhalte ich 
synchron zum Pixelclock die Farbinformationen des aktuellen Pixels. Also 
R G sowie B mit jeweils 8 bit. Nun Muss ich prüfen, in welchem Segment 
sich das aktuelle Pixel gerade befindet. Aufgrund von
  genboundsX :
  for I in 0 to led_count_x generate
    boundaries_x(I) <= ((display_width) / (led_count_x + 1)) * (I+1);
  end generate;

  genboundsY :
  for I in 0 to led_count_y generate
    boundaries_y(I) <= ((display_heigth) / (led_count_y + 1)) * (I+1);
  end generate;

Kenne ich die X und Y Grenzen aller Segmente.

Mittels der bereits mehrfach beschriebenen for-loop, versuche ich zu 
prüfen in welchem Segment sich das aktuelle Pixel gerade befindet.

Is nun row und col bekannt (und damit das aktuell gültige Segment) so 
habe ich bisher versucht, den zuvor in diesem Segment abgespeicherte 
16-Bit Wert auszulesen und mit einem, aufgrund von R G und B neu 
berechnetem Wert zu vergleichen. Ist der neue Wert höher, so speichere 
ich diesen ab (im Array welches aktuell eben (row x col) Werte fasst. 
Dies entspricht 288 x 16-Bit Werten.

Dies mache ich solange, bis Zeitpunkt t0 eingetreten ist. Ist eine Row 
zu Ende, so wird der Wert aller Rows ausgegeben!

Dies wiederholt sich nun ständig.

Mein Ansatz ist nun folgender:

Ich halte mir aktuell nur noch eine einzelne Row als Register (18 x 
16-Bit Wert). Am Ende einer Row speichere ich dieses in ein DP-RAM.
Nun setz eich ein Flag welches dazu führt, dass eine andere Logik das 
DP-RAM asliest und per SPI weiterleitet.

Das RAM muss demnach auch 288x16Bit Werte halten können.
Damit die Zuordnung stimmt, muss beim Auslesen aus dem RAM ein 
Adressdekoder/Multiplexer aufgebaut werden.

Das RAM hätte ich als 288x16Bit organisation realisiert.
Nun muss aber jedes Word (2-Byte) in einer bestimmten Reihenfolge per 
SPI gesendet werden.

Daher müsste ich eine Zuordnung ähnlich dieser Umsetzen:

Counter | RAM-Adresse
0 -> 42
1 -> 99
2 -> 128
3 -> 14
...

Könnte dies wieder zu einem enormen Ressourcenverbrauch führen?

Vielen Dank!

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.