Hallo,
ich bin noch Anfänger in VHDL und habe folgendes Problem:
Ich habe zwei Eingangsvektoren, der eine stellt die Daten dar (8 Bit)
und der andere gibt einen möglichen Offset an(4 Bit). Ich möchte mit
Hilfe des Offsets den Eingangsvektor variabel einem Ausgangsvektor
zuweisen, der 16 Bit hat.
Dabei soll z. B. bei einer "1" auf dem Offset Vektor die Daten des 8Bit
Vektors auf das 2-9. Stelle des Ausgangsvektor zugewiesen werden.
Mit welchen Anweisungen kann ich das am Besten realisieren?
Meine Idee wäre das mit einer Statemachine zu machen, die aber ja dann
so viel Zustände haben muss, wie ich mit dem Offset Werte darstellen
kann.
Gibt es eventuell noch eine elegantere Methode?
Vielen Dank für eure Hilfe.
erwin86 schrieb:> Dabei soll z. B. bei einer "1" auf dem Offset Vektor die Daten des 8Bit> Vektors auf das 2-9. Stelle des Ausgangsvektor zugewiesen werden.
Und was sollte ab einem Wert Offset>=9 passieren?
> Dabei soll z. B. bei einer "1" auf dem Offset Vektor die Daten des 8Bit> Vektors auf das 2-9. Stelle des Ausgangsvektor zugewiesen werden.
Das ist erstmal ein "Verschieben". Damit würde ich mit einem
Schieberegister anfangen...
1
std_logic_vectorVin(7downto0);
2
std_logic_vectorOffset(3downto0);
3
std_logic_vectorVout(15downto0);
4
5
process(Vin,Offset)
6
variablesr:std_logic_vector(15downto0);
7
variablecnt:integer;
8
begin
9
sr:=x"00"&Vin;
10
cnt:=to_integer(unsigned(Offset));
11
while(cnt/=0)loop
12
sr:=sr(14downto0)&'0';
13
cnt:=cnt-1;
14
endloop;
15
Vout<=sr;
16
endprocess;
Allerdings könnte die Aufgabe auch als Mux ausgeführt werden. Hier wäre
es aber schön, den Offset auf 0..8 zu begrenzen, dann werden die Grenzen
des Zielvektors nicht so leicht angekratzt...
Siehe dort im Abschnitt Vektormanipulation:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std
Marcus Harnisch schrieb:> Würde soetwas nicht genügen?
Manchmal sieht man die naheliegendste Lösung nicht... :-/
> Würde soetwas nicht genügen?
Doch, das ist sogar so einfach, dass sofort ein Barrelshifter erkannt
und implementiert wird...
> variable shift_i : integer range 0 to dout'length - din'length;
Nicht, wenn der Offset auch mal 15 werden kann (und das kann er
eigentlich schon bei einem 4 Bit Vektor)...
Ich würde hier range 0 to 15 vorschlagen...
Und ganz kompakt wäre dann
Lothar Miller schrieb:>> variable shift_i : integer range 0 to dout'length - din'length;> Nicht, wenn der Offset auch mal 15 werden kann (und das kann er> eigentlich schon bei einem 4 Bit Vektor)...
Ja, ich habe mich durch Deinen Beitrag irritieren lassen, in dem Du
schriebst: "Hier wäre es aber schön, den Offset auf 0..8 zu begrenzen,"
Wenn man das nicht will, dann lässt man es natürlich bleiben :-)
--
Marcus
erwin86 schrieb:> Dabei soll z. B. bei einer "1" auf dem Offset Vektor die Daten des 8Bit> Vektors auf das 2-9. Stelle des Ausgangsvektor zugewiesen werden.
bei Offset = 2 auf Stelle 3..10 Multiplikation mit 8
bei Offset = 3 auf Stelle 4..11 Multiplikation mit 16
bei Offset = 4 auf Stelle 5..12 Multiplikation mit 32
bei Offset = 5 auf Stelle 6..13 Multiplikation mit 64
usw.
Das Schieben lässt sich mit einer Multiplikation innerhalb eines Taktes
erledigen. Und alle modernen FPGAs haben einen Multiplizierer. Du musst
dir nur aus deinem Offset den richtigen Faktor bauen.
Tom
Thomas Reinemann schrieb:> Das Schieben lässt sich mit einer Multiplikation innerhalb eines Taktes> erledigen
Hier ist noch nirgends ein Takt beteiligt... :-o
Seis drum, der Multiplizierer arbeitet auch kombinatorisch. Und dann
ergibt sich folgendes Bild:
Fazit: die Multiplizierer-Lösung ist die kompakteste,
die Schieberegisterlösung die schnellste... ;-)
Und meine beiden sind Schrott... :-(
(Mich hatten die unerträglich langen Durchlaufzeiten schon sehr
gewundert...)
erwin86 schrieb:>>>> gibt einen möglichen Offset an(4 Bit)Ütze schrieb:> bei 8 rein und 16 raus hab ich sowas im kopf:
Das geht aber schief, wenn shift mal >8 wird.
Und das kann es bei 4 Bit... :-o
Ütze schrieb:> dout(0 + my_shift to 7 + my_shift)
Üblicher wäre die umgekehrte Reihenfolge:
dout(7 + my_shift downto my_shift)
auch hier findet der Synthesizer eine sehr effiziente Lösung, allerdings
ist die Multiplizierer-Geschichte eigentlich unschlagbar...
BTW:
> wenn es "ringsrum" gehen soll
Das tut es trotzdem nicht, ich suche jetzt aber den Fehler nicht...
Lothar Miller schrieb:> Ütze schrieb:>> dout(0 + my_shift to 7 + my_shift)> Warum immer diese verkehrte Bitreihenfolge?> Das gibt doch eh' nur Fehler:
also bei mir nicht, der Unterschied ist doch nur "little/big-endian"
aber war noch n logischer Fehler drin, weswegen "ringsrum" nicht ging,
die variablen statt signalen sind zwecks latches sicher besser, nu
lupts
Ütze schrieb:> acht_bit_invector : in std_logic_vector(0 to 7);
So definiert ehrlich gesagt niemand Vektoren... :-/
Für mich ist das höchstwertige Bit immer das mit dem höchsten Index und
beim Lesen das Linke (so wie im Dezimalsystem der Tausender links vom
Zehner ist)...
> der Unterschied ist doch nur "little/big-endian"
Nein.
Mal davon abgesehen, dass little- und big-endian ganz was anderes ist,
ist der Unterschied viel tiefgehender...
Ich verwende sowas auch mal ausnahmsweise zum Umdrehen der
Bitreihenfolge, wenn ich keine for-Schleife machen will (in der unteren
Hälfte):
http://www.lothar-miller.de/s9y/categories/50-RC-5
Aber welchen Grund hast du, die Vektorwertigkeit dauernd so zu
definieren?
> die variablen statt signalen sind zwecks latches sicher besser
Die Latches kommen von woanders her... :-/
Lothar Miller schrieb:>> acht_bit_invector : in std_logic_vector(0 to 7);> So definiert ehrlich gesagt niemand Vektoren... :-/
Doch, leider. Xilinx beim Microblaze :-(
Wahrscheinlich war da grad der Praktikant am Werk...
Duke
Lothar Miller schrieb:> Ütze schrieb:>> acht_bit_invector : in std_logic_vector(0 to 7);> So definiert ehrlich gesagt niemand Vektoren... :-/
Wenn man im xps mit dem Wizzard einen Peripheral Core exportiert wird
unter anderem das generiert:
1
entityuser_logicis
2
generic
3
(
4
-- ADD USER GENERICS BELOW THIS LINE ---------------
5
--USER generics added here
6
-- ADD USER GENERICS ABOVE THIS LINE ---------------
7
8
-- DO NOT EDIT BELOW THIS LINE ---------------------
9
-- Bus protocol parameters, do not add to or delete
10
C_SLV_DWIDTH:integer:=32;
11
C_NUM_REG:integer:=1
12
-- DO NOT EDIT ABOVE THIS LINE ---------------------
13
);
14
port
15
(
16
-- ADD USER PORTS BELOW THIS LINE ------------------
17
--USER ports added here
18
-- ADD USER PORTS ABOVE THIS LINE ------------------
19
20
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- DO NOT EDIT ABOVE THIS LINE ---------------------
33
);
> Für mich ist das höchstwertige Bit immer das mit dem höchsten Index und> beim Lesen das Linke (so wie im Dezimalsystem der Tausender links vom> Zehner ist)...>>> der Unterschied ist doch nur "little/big-endian"> Nein.
glaube mich zu erinnern in dem "VHDL-Synthese"-Buch gelesen zu haben das
der zuerstgenannten Zahl das am weitest links stehende Element
zugeordnet wird. So ziemlich genau in den Worten.
> Mal davon abgesehen, dass little- und big-endian ganz was anderes ist,
Byte nicht Bit order deswegen die Anführungszeichen
> ist der Unterschied viel tiefgehender...> Ich verwende sowas auch mal ausnahmsweise zum Umdrehen der> Bitreihenfolge, wenn ich keine for-Schleife machen will (in der unteren> Hälfte):> http://www.lothar-miller.de/s9y/categories/50-RC-5>> Aber welchen Grund hast du, die Vektorwertigkeit dauernd so zu> definieren?
weil ich hauptsächlich an solchen Periphären Cores arbeite
>> die variablen statt signalen sind zwecks latches sicher besser> Die Latches kommen von woanders her... :-/
bitte genauer, da fehlt mir noch Erfahrung: ich bekomme bei der Synthese
mit Signalen Warnungen wegen Einfügen von Latches bei to_much( was ich
wegen unvollständiger Zuweisung nachvollziehen kann), mit Variablen gibt
es keine Warnung -> daher meine Annahme
Ütze schrieb:> mit Variablen gibt es keine Warnung
Dort erkennt die Synthese, dass dieser Wert im nicht verwendeten Zweig
unnötig ist, und macht die Variable daher nicht speichernd...
Eine Variable ist nur dann speichernd, wenn sie vor der ersten Zuweisung
gelesen wird. Und das ist bei dir nicht der Fall.
> ich bekomme bei der Synthese mit Signalen Warnungen> wegen Einfügen von Latches bei to_much
Du meinst also, wenn to_much ein Signal ist?
BTW: falls das so wäre, müsste es auf jeden Fall auch in die
Sensitivliste, sonst ist die Simulation falsch...
Duke Scarring schrieb:>> So definiert ehrlich gesagt niemand Vektoren... :-/> Doch, leider. Xilinx beim Microblaze :-(
Es gibt Sachen, die sind zum Glück unnötig wie ein Kropf.
Und der Microblaze ist eine davon...
Lothar Miller schrieb:> -- Number of Slices 8> -- Number of 4 input LUTs 15> -- S3AN 12.005ns> process (Vin, Offset)> variable m : integer;> variable din_u : unsigned(Vout'range);> begin> case Offset is> [...]> when "1110" => m := 16348;> when others => m := 32786;> end case;> din_u := resize(unsigned(Vin), Vout'length);> din_u := din_u * m;> Vout <= std_logic_vector(din_u);> end process;
Vielleicht verbessert sich das Ergebnis ja noch, wenn Du die beiden
Zahlendreher im case entfernst.
Gruß
Marcus
Marcus Harnisch schrieb:> Vielleicht verbessert sich das Ergebnis ja noch, wenn Du die beiden> Zahlendreher im case entfernst.
Ups.. :-o
Glaube ich zwar nicht, probiers trotzdem aus...
Buäääh... :-(
Alles ist schlechter geworden:
Lothar Miller schrieb:> Es gibt Sachen, die sind zum Glück unnötig wie ein Kropf.> Und der Microblaze ist eine davon..
veto,z.B. lassen sich protokollbasierte Kommunikationen ( z.B. mit PC)
wesentlich leichter (zeitsparender) in c/c++ implementieren als in vhdl
Ütze schrieb:> veto,z.B. lassen sich protokollbasierte Kommunikationen ( z.B. mit PC)> wesentlich leichter (zeitsparender) in c/c++ implementieren als in vhdl
Man kann aber doch nicht das Fehlen eines geeigneten
Kommunikationsprozessors und dessen anschliessende aufwendige
Implementation als Vorteil verkaufen...
Nein, da hab ich mich missverständlich ausgedrückt: Ich meine nicht
etabliert Schnittstellen(meinetwegen USB,Ethernet) im Microblaze
nachzubilden, sondern darauf aufsätzende (eigene) Protokolle darüber zu
sprechen. Microblaze empfängt Anfragen, ereugt Header und konfiguriert
DMA (gib mir nur jeden 5. Wert oder jeden 10.). Klar geht das alles auch
in vhdl doch ungleich aufwendiger
Lothar Miller schrieb:> Es gibt Sachen, die sind zum Glück unnötig wie ein Kropf.> Und der Microblaze ist eine davon...
<OT>
Da verstehe ich Dich nicht. Der Microblaze ist doch perfekt zum Testen
von eigener Hardware (IP) in einer komplexen OS (z.B. Linux) Umgebung.
Natürlich macht es nicht immer Sinn, einen Prozessor zu verwenden, aber
wenn man für solche Aufgaben erstmal ein ein PLB Design entwerfen muss,
um einen ARM an die FPGA zu bekommen ... . Ohne böse klingen zu wollen:
das hört sich ein bisschen an wie die "ewig Gestrigen", die ihre GUI in
C machen und das ganze ".NET Geraffel" verurteilen, ohne einen Blick auf
die Entwicklungs-Ersparnis in MM ( < n^2 und n ist groß) im Sinne des
RAD zu werfen. Für den Hobby-Frickler und gleichzeitigen
Open-Source-Fetischisten mag das reichen; im kommerziellen Umfeld würde
man dafür gehenkt werden. Und das zu recht!
<OT>
Oliver Punk schrieb:> wenn man für solche Aufgaben erstmal ein ein PLB Design entwerfen muss,> um einen ARM an die FPGA zu bekommen
Wie wäre es mit "Kaufen"?
Seit wann ist jetzt der Microblaze eine ARM-Architektur?
Ich schließe das FPGA einfach mit PCI(e) an einen PC an und fertig. Da
bekomme ich für die Entwicklung für kleines Geld Rechenleistung satt und
kann alle Tools incl. Entwicklungsumgebung direkt auf dem Zielsystem
laufen lassen...
Da freut man sich, wenn der Microblaze mit 100MHz (von mir aus auch 200)
läuft, das war auf dem PC Technik von vor 20 Jahren...
Ein Prozessor auf dem FPGA ist Verschwendung von Silizium.
Nur das ist meine Aussage... ;-)
Lothar Miller schrieb:> Es gibt Sachen, die sind zum Glück unnötig wie ein Kropf.> Und der Microblaze ist eine davon...
Da gehe ich nicht mit. Es gibt schon Probleme, da benötigt man einen
Microblaze oder anders herum, andere Lösungen (FPGA + externer
Prozessor) sind deutlich aufwändiger.
Folgende Aufgabenstellung
Ein 12 Bit ADC erfasst Daten mit 250 MS/s. Ein Fenster von bis zu 2 ms
muss abgespeichert werden, d.h. man braucht für 2ms eine
Speicherbandbreite von 500MB/s. Die Menge passt nicht in den FPGA, d.h.
man braucht externen RAM. Die Daten aus dem externen RAM müssen dann per
UDP an einen PC verschickt werden. Für die Erstellung der Datagramme
benötigt man einen Prozessor. Es gibt noch zwei weitere Speicherbereiche
über die der Microblaze mit der Logik für die Signalverarbeitung
kommuniziert.
Wie soll man es besser mit einem Prozessor und FPGA hin bekommen?
Das Ganze wird in einem Virtex 5 LXT umgesetzt. Ein V5 FXT (der mit PPC)
ist deutlich teurer und benötigt deutlich mehr Strom, letzteres spielt
eine besondere Rolle. Der Platz auf der Leiterplatte ist auch begrenzt.
Tom
Thomas Reinemann schrieb:> Ein 12 Bit ADC erfasst Daten mit 250 MS/s. Ein Fenster von bis zu 2 ms> muss abgespeichert werden, d.h. man braucht für 2ms eine> Speicherbandbreite von 500MB/s. Die Menge passt nicht in den FPGA, d.h.> man braucht externen RAM. Die Daten aus dem externen RAM müssen dann per> UDP an einen PC verschickt werden. Für die Erstellung der Datagramme> benötigt man einen Prozessor. Es gibt noch zwei weitere Speicherbereiche> über die der Microblaze mit der Logik für die Signalverarbeitung> kommuniziert.
Eine einseitige UDP Kommunikation geht auch locker ohne Prozessor, man
muss nur gültige Frames erzeugen. Du hast auch nicht gesagt wie schnell
diese Daten an den PC geschickt werden müssen.
Und der Rest hängt nur davon ab ob der Speicher das mitmacht.
D. I. schrieb:> Eine einseitige UDP Kommunikation geht auch locker ohne Prozessor, man> muss nur gültige Frames erzeugen. Du hast auch nicht gesagt wie schnell> diese Daten an den PC geschickt werden müssen.> Und der Rest hängt nur davon ab ob der Speicher das mitmacht.
Ja es wird beidseitig kommuniziert, es werden auch noch einige
Berechnung im Prozessor gemacht. Die gesamte Spezifikation ist 50 Seiten
lang.
Tom