Forum: FPGA, VHDL & Co. Multiplexer entity mit generate


von Anonymous U. (gastt)


Lesenswert?

Hallo

Ich will in VHDL einen Multiplexer-Baustein programmieren, in dem man 
die Anzahl der Eingänge (und Busbreite) per generate übergeben kann. 
Aus- und Eingänge will ich mit std_logic_vektoren realisieren. Mein 
Problem ist nun das sich für den select Eingang je nach größe des MUXes 
unterschiedliche Längen des Vektors ergeben. Wie berechne ich am 
elegantesten diese Länge? Hier mein Code:
1
use ieee.std_logic_1164.all
2
use ieee.std_numeric.all
3
4
entity mux is
5
  generic (   bus_width     : positive;
6
              number_inputs : positive
7
          );
8
  port    (   select_input  : in  std_logic_vector( log2(number_inputs) downto 0);
9
              input         : in  is array (0 to number_inputs-1) of std_logic_vector(bus_width-1 downto 0);
10
              output        : out std_logic_vector(bus_width downto 0)
11
          );
12
end mux;
13
14
architecture mux_behaviour of mux is
15
begin
16
  process( select_input, input )
17
  begin
18
      output <= input( to_integer(signed(select_input)) );
19
  end process;
20
end mux_behaviour;

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


Lesenswert?

Anonymous U. schrieb:
> Hier mein Code:
Und was ist an dem Code schlecht? Warum funktioniert er nicht? Was 
erwartest du und was passiert stattdessen? Welche Fehlermeldung bekommst 
du?

> Mein Problem ist nun das sich für den select Eingang je nach größe des
> MUXes unterschiedliche Längen des Vektors ergeben. Wie berechne ich am
> elegantesten diese Länge?
Dein Ansatz ist prinzipiell richtig, aber natürlich 1. kennt der 
Synthesizer von sich aus kein log() und 2. zudem ist das Ergebnis von 
log() ein float. Zudem musst noch an den Zweierpotenzen-Grenzen (z.b. 
7->8, 63->64) aufpassen und einiges zurechtschieben. Heraus kommt sowas:
http://www.lothar-miller.de/s9y/archives/72-Breite-eines-Vektors-berechnen-log2.html

Und dann ist natürlich 3. das Hauptproblem, dass du die Portbreite so 
nicht definieren kannst. Du musst dafür ein Package machen und darin die 
Portbreite ausrechnen.

Ich würde hier einfach die Busbreite des Multiplexers generisch machen 
und gar keinen Bereich angeben. Etwa so:
1
use ieee.std_logic_1164.all
2
use ieee.std_numeric.all
3
4
entity mux is
5
  generic (   number_inputs : positive
6
          );
7
  port    (   select_input  : in  std_logic_vector;
8
              input         : in  is array (0 to number_inputs-1) of std_logic_vector;
9
              output        : out std_logic_vector
10
          );
11
end mux;
12
13
architecture mux_behaviour of mux is
14
begin
15
  process( select_input, input )
16
  begin
17
      output <= input( to_integer(signed(select_input)) );
18
  end process;
19
end mux_behaviour;

: Bearbeitet durch Moderator
von Anonymous U. (gastt)


Lesenswert?

Vielen Dank schonmal.

Ich bin jetzt ein bisschen weiter, und modelsim ist gewillt folgenden 
Code zu compilieren:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
4
-- definition of generic array
5
package mux_package is
6
    type array_input is array (natural range <>) of std_logic_vector;
7
end;
8
9
10
library ieee;
11
use work.mux_package.all;
12
use ieee.std_logic_1164.all;
13
use ieee.numeric_std.all;
14
use ieee.math_real.log2;
15
use ieee.math_real.ceil;
16
17
entity mux is
18
  generic (   bus_width     : positive;
19
              number_inputs : positive
20
          );
21
  port    (   select_input  : in  std_logic_vector( 1+integer(ceil(log2(real(number_inputs-1)))) downto 0);
22
              input         : in  array_input(number_inputs-1 downto 0)(bus_width-1 downto 0);
23
              output        : out std_logic_vector(bus_width downto 0)
24
          );
25
end mux;
26
27
architecture mux_behaviour of mux is
28
begin
29
  process( select_input, input )
30
  begin
31
      output <= input( to_integer(signed(select_input)) );
32
  end process;
33
end mux_behaviour;

Ein Nachteil bei meinem Code ist das er nur mit VHDL 2008 unterstützt 
wird :-(

Was mir bei deinem Code nicht ganz klar ist: Wenn ich für die 
select-Leitung keinen logic_bit_vector verwende, optimiert das 
synthesetool dann automatisch auf die benötigten Leitungen. Bzw. ist die 
Vorgehensweise mit dem logic_bit_vector nicht schöner oder ist das 
unüblich? Ich bin noch blutiger Anfänger in VHDL und habe noch nicht 
viel Gefühl in der Vorgehensweise...

PS: Ich habe gerade gesehen: Die select-Leitung ist auch bei dir ein 
std_logic_vektor, aber ohne Größenangabe. Macht das Synthesetool daraus 
dann erstmal 32 bit Breite und optimiert dann?

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


Lesenswert?

Anonymous U. schrieb:
> Wenn ich für die select-Leitung keinen logic_bit_vector verwende,
Was ist das? Ein selbst definierter Datentyp?

> optimiert das synthesetool dann automatisch auf die benötigten
> Leitungen.
Ja.

> Bzw. ist die Vorgehensweise mit dem logic_bit_vector nicht
> schöner oder ist das unüblich?
Die allermeisten Bibliotheksfunktionen arbeiten mit "unconstrained 
vectors", denn sonst müsste ja eine to_integer()-Funktion die Breite des 
Vektors mitbekommen. Sieh dir einfach mal z.B. die numeric_std an:
https://www.csee.umbc.edu/portal/help/VHDL/packages/numeric_std.vhd
Mal ganz exemplarisch daraus die Funktion to_integer():
1
function TO_INTEGER(ARG: UNSIGNED) return NATURAL is
2
constant ARG_LEFT:INTEGER:= ARG'length-1;
3
alias XXARG:UNSIGNED(ARG_LEFT downto 0) is ARG;
4
variable XARG:UNSIGNED(ARG_LEFT downto 0); 
5
variable RESULT: NATURAL:= 0;
6
variable w : INTEGER:= 1;  -- weight factor
7
begin
8
  if (ARG'length<1) then
9
    assert NO_WARNING
10
    report "numeric_std.TO_INTEGER: null arg"
11
    severity warning;
12
    return 0;
13
    end if;
14
  XARG:= TO_01(XXARG);
15
  if (XARG(XARG'left)='X') then
16
    assert NO_WARNING
17
    report "numeric_std.TO_INTEGER: metavalue arg set to 0"
18
    severity warning;
19
    return 0;
20
    end if;
21
  for i in XARG'reverse_range loop
22
    if XARG (i) = '1' then
23
      RESULT:= RESULT + w;
24
      end if;
25
    if (i /= XARG'left) then w := w + w;
26
      end if;
27
    end loop;
28
  return RESULT;
29
end TO_INTEGER;
Dort siehst du in der ersten Zeile, dass nur ein UNSIGNED Vektor 
unbestimmter Breite übergeben wird. Der Rest wird mit Attributen 
gemacht, hier eine schöne Anwendung für das Attribut 'reverse_range, das 
den Vektor in einer for-Schleife von "hinten" her durchnudelt.

Als Tipp: es schadet nicht, diese Bibliotheken mal genauer anzuschauen, 
da sind einige hübsche "Tricks" versteckt. Und vor Allem: die 
funktionieren garantiert.

: Bearbeitet durch Moderator
von Anonymous U. (gastt)


Lesenswert?

Lothar M. schrieb:
> Anonymous U. schrieb:
>> Wenn ich für die select-Leitung keinen logic_bit_vector verwende,
> Was ist das? Ein selbst definierter Datentyp?

oh, ich meinte std_logic_vector.

Lothar M. schrieb:
> Dort siehst du in der ersten Zeile, dass nur ein UNSIGNED Vektor
> unbestimmter Breite übergeben wird.

Dann werd ich das genauso machen.

Bauchweh habe ich allerdings noch wegen dem Array: durch das generic 
package funktioniert der Code nur mit VHDL 2008. Das soll anscheinend 
bei einigen Programmen Probleme geben. Da komme ich aber nicht herum, 
wenn ich die Busbreite variabel halten will oder?
1
library ieee;
2
use ieee.std_logic_1164.all;
3
4
-- definition of generic array
5
package mux_package is
6
    type array_input is array (natural range <>) of std_logic_vector;
7
end;
8
9
10
library ieee;
11
use ieee.std_logic_1164.all;
12
use ieee.numeric_std.all;
13
use work.mux_package.all;
14
15
entity mux is
16
  generic (   number_inputs : positive
17
          );
18
  port    (   select_input  : in  std_logic_vector;
19
              input         : in  array_input (0 to number_inputs-1);
20
              output        : out std_logic_vector
21
          );
22
end mux;
23
24
architecture mux_behaviour of mux is
25
begin
26
  process( select_input, input )
27
  begin
28
      output <= input( to_integer(signed(select_input)) );
29
  end process;
30
end mux_behaviour;

: Bearbeitet durch User
von Vancouver (Gast)


Lesenswert?

Verwirrung... Du hast geschrieben, dass Du die Anzahl der Eingänge per 
"generate" übergeben willst. Ich vermute, Du meinst generic und hoffe, 
der Unterschied ist Dir bekannt.

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.