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


von Harry (Gast)


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

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


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.

von Harry (Gast)


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

von SuperWilly (Gast)


Lesenswert?

zauberwort: unconstrained arrays
1
Im Package:
2
type type_arr is array(natural range <>, natural range <>) of std_logic;
3
4
Im Modul:
5
6
 generic (
7
        LENGTH: integer := 4;
8
        WIDTH: integer := 5);
9
    port (
10
        vec : in type_arr(LENGTH-1 downto 0, WIDTH-1 downto 0);


Gruß,
SuperWilly

von Harry (Gast)


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.

von Harry (Gast)


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

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


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:
1
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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
package mytype is
4
   type typ_array is array(natural range <>, natural range <>) of std_logic_vector(7 downto 0);
5
end;
6
package body mytype is
7
end package body;
8
9
library IEEE;
10
use IEEE.STD_LOGIC_1164.ALL;
11
use IEEE.NUMERIC_STD.ALL;
12
use work.mytype.all;
13
14
entity UnconstrainedArray is
15
    generic ( X: integer := 4;
16
              Y: integer := 4);
17
    port ( vec  : in  typ_array(X-1 downto 0, Y-1 downto 0);
18
           selx : in  STD_LOGIC_VECTOR (X-1 downto 0);
19
           sely : in  STD_LOGIC_VECTOR (Y-1 downto 0);
20
           dout : out STD_LOGIC_VECTOR (7 downto 0)
21
         );
22
end UnconstrainedArray;
23
24
architecture Behavioral of UnconstrainedArray is
25
begin
26
   dout <= vec(to_integer(unsigned(selx)),to_integer(unsigned(sely)));
27
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).

von Harry (Gast)


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

von Didi (Gast)


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?

von mac4ever (Gast)


Lesenswert?

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

von Harry (Gast)


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:
1
   subtype v8 is std_logic_vector(7 downto 0); --1
2
   type variable_array_x8 is array (natural range <>) of v8; --2
3
   type array_5x8 is array (4 downto 0) of std_logic_vector(7 downto 0); --3
4
5
   signal my_var_array_5x8 : variable_array_x8(4 downto 0); --5
6
   signal my_array_5x8     : array_5x8; --6
7
8
   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:
1
myLoop: for i in 0 to 4 generate
2
begin
3
   my_array_5x8(i) <= my_var_array_5x8(i);
4
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

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


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...

von Harry (Gast)


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

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


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...

von fpga (Gast)


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:
1
package matrix_pkg is
2
  type matrix_type is array(natural range <>, natural range <>) of integer range 0 to 2**18-1;
3
  type vector_type is array(natural range <>) of integer range 0 to 2**18-1;
4
  function "+" (L, R: matrix_type) return matrix_type;
5
end matrix_pkg;
6
7
package body matrix_pkg is
8
  function "+" (L, R: matrix_type) return matrix_type is
9
    variable result : matrix_type(L'left downto L'right, L'high downto L'low);
10
    begin
11
      -- confirm arrays are the same shape
12
      assert (L'left = R'left) and (L'right = R'right);
13
      assert (L'low = R'low) and (L'high = R'high);
14
      for i in L'right to L'left loop 
15
        for j in L'low to L'high loop
16
          result(i,j) := L(i,j) + R(i,j);
17
        end loop;
18
      end loop;
19
      return result;
20
  end "+";
21
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?

von Duke Scarring (Gast)


Lesenswert?

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

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

Duke

von fpga (Gast)


Lesenswert?

OK kompilieren schon, aber wenn ich das hier schreibe:
1
  signal state_X : matrix_type(0 downto 0,DIM_X-1 downto 0);
2
  signal state_Y : matrix_type(0 downto 0,DIM_X-1 downto 0);
3
4
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:
1
variable result : matrix_type(L'range(1), L'range(2));

von Duke Scarring (Gast)


Lesenswert?

Bei der folgenden Testbench stimmen erstmal nur die Dimensionen nicht:
1
entity matrix_tb is
2
end entity matrix_tb;
3
4
library work;
5
use work.matrix_pkg.all;
6
7
architecture testbench of matrix_tb is
8
9
    constant DIM_X : integer := 5;
10
11
    signal state_X : matrix_type(0 downto 0,DIM_X-1 downto 0);
12
    signal state_Y : matrix_type(0 downto 0,DIM_X-1 downto 0);
13
14
begin
15
16
    main: process
17
    begin
18
        state_X <= state_X + state_Y;
19
        wait;
20
    end process;
21
22
end architecture testbench;
1
> vsim -voptargs=+acc work.matrix_tb
2
# vsim -voptargs=+acc work.matrix_tb 
3
# ** Note: (vsim-3812) Design is being optimized...
4
# 
5
# Loading std.standard
6
# Loading work.matrix_pkg(body)
7
# Loading work.matrix_tb(testbench)#1
8
add wave *
9
run -all
10
# ** Fatal: (vsim-3714) At array depth 2, array lengths do not match. Left is 5 (4 downto 0). Right is 1 (0 downto 0).
11
#    Time: 0 ps  Iteration: 0  Process: /matrix_tb/main File: matrix_tb.vhd
12
# Fatal error in Process main at matrix_tb.vhd line 20
13
# 
14
# HDL call sequence:
15
# Stopped at matrix_tb.vhd 20 Process main
16
#

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

Duke

von fpga (Gast)


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 :)

von Duke Scarring (Gast)


Lesenswert?

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

Duke

von fpga (Gast)


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.

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.