www.mikrocontroller.net

Forum: FPGA, VHDL & Co. VHDL: variable Breite bei (2D)-Array-Ports?


Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
um mein Entity feiner handhaben zu können, würde ich gerne die Breite 
eines 2-dimensionalen Ports (array) variabel definieren können, über 
generics.

Die Suchfunktion hat mich zu mehreren Threads geführt
(Beitrag "Vektoren variabler Breite?"
Beitrag "Variabler Eingang in Portliste? std_logic_vector und std_logic")
die eine variable Portbreite von Vektoren diskutieren.

Die Lösungsansätze wie

    generic (
        WIDTH : integer := 3);
    port (
        vec : in std_logic_vector(WIDTH - 1 downto 0));

gefallen mir prinzipiell gut, aber ich frage mich nun, ob das in VHDL 
auch für zwei- (oder mehr) -dimensionale Arrays möglich ist?

Also (gedanklich geschrieben) in etwa sowas:

    generic (
        LENGTH: integer := 4;
        WIDTH: integer := 5);
    port (
        vec : in array(WIDTH x LENGTH));


Das Problem dabei ist, dass Arrays in VHDL ja zuvor als typ definiert 
werden müssen, wie z.B.

    type array_4x5 is array (3 downto 0) of std_vec(4 downto 0);

Hat wer eine Idee, wie man das Schreiben oder besser Lösen könnte?

Ein erster Workaround, der mir eingefallen ist, definiert das Array 
nicht zweidimensional sondern nur einen Vektor, der eben LENGTH * WIDTH 
groß ist. Also:

        vec : in std_logic_vector((WIDTH*LENGTH)-1 downto 0));

Dieser wird dann nicht über array(x)(y) indiziert sondern als 
vec(x*LENGTH+y). Diese "Lösung" ist aber wesentlich umständlicher zu 
verwenden und m.M. nach auch fehleranfälliger.

Danke für eure Anregungen,
lg Harry

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du wirst ein Package definieren müssen, mit dem du deinen Typ bekannt 
machst. Erst dann kannst du sowas im Port einer Entity verwenden.

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi und danke für deine Antwort,
das mit dem Package war mir schon bekannt. Das Problem ist nur, dass der 
Typ ja nicht fix ist, sondern wie erwähnt variabel über generics 
"einzustellen" sein soll. Das heißt zwei Instanzen derselben Entity 
können dann verschieden breite Arrays als Ports haben.
lg Harry

Autor: SuperWilly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zauberwort: unconstrained arrays

Im Package:
type type_arr is array(natural range <>, natural range <>) of std_logic;

Im Modul:

 generic (
        LENGTH: integer := 4;
        WIDTH: integer := 5);
    port (
        vec : in type_arr(LENGTH-1 downto 0, WIDTH-1 downto 0);



Gruß,
SuperWilly

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow, das wusste ich noch nicht. Man lernt halt nie aus und das ist gut 
so. Vielen Dank, Willy, werde das gleich mal ausprobieren.

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal,
ich hab das soeben mal ausprobiert, so wie's aussieht, lässt sich dieses 
Problem mit unconstrained Arrays nicht synthetisieren.
Warum eigentlich nicht? Es liegt doch über die generics zur 
"Compile"-Zeit fest, wie groß welches Array ist. Somit kann die Hardware 
spezifiert werden. Aber offenbar checkt dies das Xi... Synthese-Tool 
nicht.

lg Harry

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähm, das lässt sich garantiert synthetisieren. Sieh dir doch mal die 
Definition eines std_logic_vectors an, bei dem wird das genauso gemacht:
TYPE STD_LOGIC_VECTOR IS ARRAY (NATURAL RANGE <>) OF STD_LOGIC;
und den verwendest du andauernd....

Sieh dir mal diesen Multiplexer an. Der lässt sich synthetisieren:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
package mytype is
   type typ_array is array(natural range <>, natural range <>) of std_logic_vector(7 downto 0);
end;
package body mytype is
end package body;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.mytype.all;

entity UnconstrainedArray is
    generic ( X: integer := 4;
              Y: integer := 4);
    port ( vec  : in  typ_array(X-1 downto 0, Y-1 downto 0);
           selx : in  STD_LOGIC_VECTOR (X-1 downto 0);
           sely : in  STD_LOGIC_VECTOR (Y-1 downto 0);
           dout : out STD_LOGIC_VECTOR (7 downto 0)
         );
end UnconstrainedArray;

architecture Behavioral of UnconstrainedArray is
begin
   dout <= vec(to_integer(unsigned(selx)),to_integer(unsigned(sely)));
end Behavioral;

EDIT: das Beispiel hier ist übrigens schon ein dreidimensionales Array. 
Der std_logic_vector selbst ist bereits eine Dimension (denn du kannst 
dort js jedes Bit einzeln indizieren).

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Lothar,
danke für deine Ausführungen und sorry für die späte Antwort.
Stimmt, das mit den unconstrained Arrays ist tatsächlich 
synthetisierbar. Der Fehler lag bei mir woanders.
"Unconstrained Arrays" -> Eine feine Sache, wenn man mal weiß, wie man 
damit umzugehen hat. Bringt viel Flexibilität.
lg Harry

Autor: Didi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen

Ich habe ein endliches Problem. Jedoch möchte ich die Aufteilung wie 
folgt machen, da auf diese weise die Ansteuerung einfacher wäre:

Im Package:
type type_arr is array(natural range <>) of std_logic_vector(natural 
range <>);

Im Modul:

 generic (
        LENGTH: integer := 4;
        WIDTH: integer := 5);
    port (
        vec : in type_arr(LENGTH-1 downto 0, WIDTH-1 downto 0);


aber leider funktioniert dies nicht. Wie kann ich 2 Attribute übergeben?
Wie muss ich es umschreiben damit dies Funktioniert?

Autor: mac4ever (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
type_arr ist bei dir eindimensional.
Folglich geht
vec : in type_arr(LENGTH-1 downto 0, WIDTH-1 downto 0);
schief

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
Ich habe nun dank eurer Hinweise die "unconstrained arrays" in mein VHDL 
Repertoire aufgenommen und verwende sie auch, wenns denn mal reinpasst.

Ich bin aber gerade wieder darüber gestolpert und frage mich, warum 
eigentlich eine Zuweisung wie die folgende (Zeile "--8") nicht vom XST 
geschluckt wird:
   subtype v8 is std_logic_vector(7 downto 0); --1
   type variable_array_x8 is array (natural range <>) of v8; --2
   type array_5x8 is array (4 downto 0) of std_logic_vector(7 downto 0); --3

   signal my_var_array_5x8 : variable_array_x8(4 downto 0); --5
   signal my_array_5x8     : array_5x8; --6

   my_array_5x8 <= my_var_array_5x8; --8

XST meckert, dass die Datentypen nicht zusammenpassen:
ERROR:HDLParsers:800 - "top.vhd" Line 319. Type of my_array_5x8 is 
incompatible with type of my_var_array_5x8."

Durch die explizite Anordnung in "--5" wird doch das variable Array doch 
auf 5x8 Bit zur compile-time festgelegt und entspricht somit exakt dem 
gleichen Typ wie das "array_5x8". Ist VHDL wirklich so 
Datentypen-vernarrt, dass es zwei unterschiedliche Äpfel nicht trotzdem 
als zwei Äpfel erkennen kann?

Das hier funktioniert wiederum problemlos, da hier das Array sozusagen 
aufgelöst wird und jeweils "nur" mehr ein std_logic_vector überbleibt:
myLoop: for i in 0 to 4 generate
begin
   my_array_5x8(i) <= my_var_array_5x8(i);
end generate;

Kann mir das bitte noch wer erklären? Würde das nur zu gern verstehen. 
Oder vielleicht gibts auch noch eine andere Schreibweise, die 
funktioniert?

Danke im Voraus,
lg Harry

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da steht es:
> Type of my_array_5x8 is incompatible with type of my_var_array_5x8."
Weil ja variable_array_x8 und array_5x8 ganz einfach unterschiedlich 
definierte Typen sind. Dass die atomaren Einzelteile der Arrays gleich 
sind, das ist dem Synthesizer egal. Du mußt also ein Umwandlung auf 
kompatibler Ebene vornehmen...

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Lothar,
und danke für die Antwort.

Lothar Miller schrieb:
> Du mußt also eine Umwandlung auf
> kompatibler Ebene vornehmen...

... Heißt also sowas wie das "generate"-konstrukt im Beitrag oberhalb? 
Oder gibts da was eleganteres? Diese Umwandlungs-Notwendigkeit nimmt dem 
Ganzen die Attraktivität, wenn man sich zuerst um modularen Code bemüht, 
und dann beim Verbinden solche Kopfstände machen muss.

lg

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Harry schrieb:
> Heißt also sowas wie das "generate"-konstrukt im Beitrag oberhalb?
Im Prinzip ja.

> Oder gibts da was eleganteres?
Du könntest die Typen in ein Package packen, und dann eine 
Zuweisungsfunktion definieren, aber glaub mir: das macht die Sache 
langfristig nicht besser verständlich...
Etwa im Stil von Beitrag "Eigene Auflösungsfunktion für Tri-state"

> Oder gibts da was eleganteres?
Evtl. lässt sich diese Zuweisung auch in eine Funktion verpacken...

Autor: fpga (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der Beitrag ist schon ein wenig alt, aber genau dazu habe ich eine 
Frage.
Ich würde gerne für ein array of array die Operation "+" definieren:

ich habe es so probiert, aber das ist nicht korrekt:
package matrix_pkg is
  type matrix_type is array(natural range <>, natural range <>) of integer range 0 to 2**18-1;
  type vector_type is array(natural range <>) of integer range 0 to 2**18-1;
  function "+" (L, R: matrix_type) return matrix_type;
end matrix_pkg;

package body matrix_pkg is
  function "+" (L, R: matrix_type) return matrix_type is
    variable result : matrix_type(L'left downto L'right, L'high downto L'low);
    begin
      -- confirm arrays are the same shape
      assert (L'left = R'left) and (L'right = R'right);
      assert (L'low = R'low) and (L'high = R'high);
      for i in L'right to L'left loop 
        for j in L'low to L'high loop
          result(i,j) := L(i,j) + R(i,j);
        end loop;
      end loop;
      return result;
  end "+";
end matrix_pkg;

Bislang habe ich nichts dazu gefunden, wie man bei variabler größen bei 
einem array of array wieder an die Range kommt.
Kann mir da jemand weiterhelfen?

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
fpga schrieb:
> ich habe es so probiert, aber das ist nicht korrekt:
Was ist denn daran nicht korrekt?

ModelSim kompiliert den Code problemlos:
$ vcom matrix_pkg.vhd
Model Technology ModelSim SE-64 vcom 10.1d Compiler 2012.11 Nov  1 2012
-- Loading package STANDARD
-- Compiling package matrix_pkg
-- Compiling package body matrix_pkg
-- Loading package matrix_pkg

Duke

Autor: fpga (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK kompilieren schon, aber wenn ich das hier schreibe:
  signal state_X : matrix_type(0 downto 0,DIM_X-1 downto 0);
  signal state_Y : matrix_type(0 downto 0,DIM_X-1 downto 0);

state_X <= state_X + state_Y;
gibt es eine Fehlermeldung, welche darauf hindeutet, dass das Überladen 
von "+" nicht so funktioniert.

Ich vermute inzwischen, dass es folgendermaßen klappen könnte. Jedoch 
muss ich das erst noch per TB verifizieren:
variable result : matrix_type(L'range(1), L'range(2));

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei der folgenden Testbench stimmen erstmal nur die Dimensionen nicht:
entity matrix_tb is
end entity matrix_tb;

library work;
use work.matrix_pkg.all;

architecture testbench of matrix_tb is

    constant DIM_X : integer := 5;

    signal state_X : matrix_type(0 downto 0,DIM_X-1 downto 0);
    signal state_Y : matrix_type(0 downto 0,DIM_X-1 downto 0);

begin

    main: process
    begin
        state_X <= state_X + state_Y;
        wait;
    end process;

end architecture testbench;
> vsim -voptargs=+acc work.matrix_tb
# vsim -voptargs=+acc work.matrix_tb 
# ** Note: (vsim-3812) Design is being optimized...
# 
# Loading std.standard
# Loading work.matrix_pkg(body)
# Loading work.matrix_tb(testbench)#1
add wave *
run -all
# ** Fatal: (vsim-3714) At array depth 2, array lengths do not match. Left is 5 (4 downto 0). Right is 1 (0 downto 0).
#    Time: 0 ps  Iteration: 0  Process: /matrix_tb/main File: matrix_tb.vhd
# Fatal error in Process main at matrix_tb.vhd line 20
# 
# HDL call sequence:
# Stopped at matrix_tb.vhd 20 Process main
# 

Wenn ich DIM_X auf 1 setze läuft es fehlerfrei durch.

Duke

Autor: fpga (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das problem ist eben, dass die erste Version der "+" function die Range 
nicht richtig erkannt hat. Aber mit range(1) und range(2) geht es.

Aber den Tipp mit L'range(1) und L'range(2) habe ich erst nach mehreren 
Stunden suchen gefunden :)

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt ist nur noch die Frage, ob sich das synthetisieren lässt.
Oder brauchst Du das nur für die Simulation?

Duke

Autor: fpga (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun, die Synthese ergibt mit Xilinx 13.4 keinen Fehler.
Wirklich auf dem FPGA habe ich es noch nicht getestet. An sich addiere 
ich ja auch nur Integer, aber eben "einfacher" in Matrixform 
geschrieben.

Muss erstmal per Testbench das ganze Modul testen.

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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