Hallo, habe schon andere Beiträge gesichtet, die sich mit unsigned
befassen, konnte aber das Problem nicht lösen.
Ich habe eine komisches Problem mit ModelSIM. Er meldet:
Time: 10 ns Iteration: 1 Instance: /btm_tb/dut
# ** Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31
downto 0). Right is 64 (63 downto 0).
und das hier ist der Befehl:
WIDTH ist 32. ModelSIM zeigt auch alle Signale mit 31 downto 0 an.
Wie schreibe ich die Formel?
Die Werte sind so, dass es kein Überlauf geben kann.
Ich habe auch probiert:
1
OUT_NEW<=VAL_OLD&'0'+ROT_OLD;
dann meckert er wegen 33 Bit.
Ist eigentlich klar, aber ich würde gerne das Herumbasteln mit Vektoren
vermeiden.
Vor allem würde mich interessieren, wie er auf die doppelte Zahl der
Bits kommt!
Modelsim weiß jetzt nicht so genau.
Aber ich würde vermuten, dass er die 2 schon als 32 Bit auffasst und
deswegen auf die 64 Bit kommt. Das könnte er besser wissen und 33
annehmen, aber naja. Muss man mal in der Doku schauen.
VAL_OLD & '0' ist, nach dem was Du über die Breite von VAL_OLD sagst,
nun einmal auch 33 Bit lang. Mit dem Summanden ergibt das potentiell
noch 34 Bit.
Du wirst nicht darum herum kommen, mit Vektoren zu fummeln, denke ich.
Es gibt Ausdrücke mit denen man auf der rechten Seite, den Vektor nach
der Operation in der Breite verändern kann.
Aber ich rate Dir zunächst mal ganz genau zu überlegen wie groß die
Summanden sein können. Du sagst ja nur, die sind nicht so groß, aber da
Du keine Einzelheiten angibst, kann man da nichts raten, als das: Schaus
Dir genau an.
-- Result subtype: UNSIGNED(MAX(L'LENGTH, R'LENGTH)-1 downto 0).
4
-- Result: Adds two UNSIGNED vectors that may be of different lengths.
Also ist üblicherweise für unsigned Vektoren der '+' Operator eine
Addition. Für eine Concatenation nimmt man den '&' Operator.
> Das + bei Signalen ist keine Rechenoperation, sondern eine> Aneinanderreihung.
Signale können alles Mögliche sein, z.B. auch die Zustände von FSM.
Irgendwie ist dann auch klar, dass man den Zustand "idle" natürlich
nicht mit dem '+' Operator auf den Zustand "run" addieren kann um einen
anderen Zustand zu "berechnen".
Und natürlich kann ich für meine selbst definierten Typen den '+'
Operator mit beliebigen Funktionen überladen. Aber für bekannte und
allgemein verwendete Datentypen und Vektoren ist der '+' Operator eine
Addition.
Batzi schrieb:> Vor allem würde mich interessieren, wie er auf die doppelte Zahl der> Bits kommt!
Das ist allerdings interessant. Man könnte fast meinen, der kommt mit
der Priorität der Operatoren durcheinander. Was passiert, wenn du das
zusätzlich zum impliziten "Punkt vor Strich" noch klammerst?
OUT_NEW <= (VAL_OLD * 2) + ROT_OLD;
Welche Packages verwendest du?
Kannst du mal einen ausführbaren "Dreizeiler" posten?
Batzi schrieb:> Ich habe auch probiert: OUT_NEW <= VAL_OLD & '0' + ROT_OLD;> dann meckert er wegen 33 Bit.
Spricht eigentlich was gegen Rechnungen mit Integern, wenn du sowieso
die "überzähligen" Bits ignorieren willst?
Batzi schrieb:> und das hier ist der Befehl:OUT_NEW <= VAL_OLD * 2 + ROT_OLD;
Das Ausgangsvektor der Multiplikation ist so groß wie die addierte Länge
der Eingangsvektoren. Siehe die Lothar verlinkte numeric_std:
1
-- Id: A.15
2
function "*" (L,R: UNSIGNED ) return UNSIGNED;
3
-- Result subtype: UNSIGNED((L'length+R'length-1) downto 0).
4
-- Result: Performs the multiplication operation on two UNSIGNED vectors
Rudolph schrieb:> Das Ausgangsvektor der Multiplikation ist so groß wie die addierte Länge> der Eingangsvektoren.
Das war ja einfach... ;-)
Allerdings gilt hier diese Funktionsdefinition, weil '2' ja kein
unsigned Vektor, sondern ein natürlicher Wert ist:
1
-- Id: A.17
2
function"*"(L:UNSIGNED;R:NATURAL)returnUNSIGNED;
3
-- Result subtype: UNSIGNED((L'length+L'length-1) downto 0).
Ich würde also ebenso einfach den "resize" Hebel ansetzen. Wenn es eine
globale WIDTH gibt, dann ist das ja nicht allzu umständlich:
Lothar M. schrieb:> Ich würde also ebenso einfach den "resize" Hebel ansetzen. Wenn es eine> globale WIDTH gibt, dann ist das ja nicht allzu umständlich:> OUT_NEW <= resize(VAL_OLD * 2 + ROT_OLD, WIDTH);
Und wenn es keine globale WIDTH gibt, dann geht es so:
Lothar M. schrieb:> Batzi schrieb:>> Ich habe auch probiert: OUT_NEW <= VAL_OLD & '0' + ROT_OLD;>> dann meckert er wegen 33 Bit.> Spricht eigentlich was gegen Rechnungen mit Integern, wenn du sowieso> die "überzähligen" Bits ignorieren willst?
Weil es keinen Überlauf geben kann und ich nicht unnötig umhercasten
möchte. Das Ergebnis wird wieder vorne reingeworfen, sodass eine
Iteration entsteht. Der unsigned würde dann immer größer werden. Er muss
also beschnitten werden.
Weiter vorne mache ich das - außerhalb eines Prozesses! - auch so:
1
TMP_SUM<=VAL_SUM+ROT_OLD;
Sind auch beides 32 Bit. Dort meckert der ModelSIM nicht wegen eines
Überlaufes, sondern ihm sind die Breiten genehm. Dort könnte allerdings
auch ein Überlauf passieren, es ist nur in meiner Anwendung nicht
möglich, weil ich weiß, was vorne reinkommt und wie lange iteriert wird.
Das kann ModelSIM aber garantiert nicht sehen.
Wie auch immer: Ich habe nun resize verwendet und es geht!
Ich möchte aber dennoch die Frage stellen, wie man das in VHDL am besten
macht:
Es kann ja nicht sein, dass man nicht einfach C = A * B schreiben kann
und er kriegt die Breiten selber raus, bzw multipliziert und addiert so,
dass das mathematisch richtige Ergebnis rauskommt ohne dass ich immer
mit den Breiten tricksen muss, dass es stimmt. Das macht den Code nicht
gerade leserlich.
Lothar M. schrieb:> Welche Packages verwendest du?> Kannst du mal einen ausführbaren "Dreizeiler" posten?
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
Posten darf ich den Code nicht. Firmeneigentum :-)
Lothar M. schrieb:> OUT_NEW <= (VAL_OLD * 2) + ROT_OLD;
Das hatte keine Wirkung zurfolge.
Ich gehe davon aus, dass er zunächst die 2 in einen passenden Vektor
übersetzt und dann ein 32Bit x 32Bit erkennt.
Ich werde mich jetzt mal an der Nutzung eines signed probieren. Das
steht als kommend an. (Meine Iteration muss sich auch pendelnd annähern
können).
Batzi schrieb:> Es kann ja nicht sein...
Weil VHDL stark typisiert ist und nicht hintenrum implizit gemacht wird,
ist es aber trotzdem so. Fazit: hinnehmen oder Verilog machen. Da ist
das wesentlich lascher gehalten... ?
Batzi schrieb:> Ich gehe davon aus, dass er zunächst die 2 in einen passenden Vektor> übersetzt und dann ein 32Bit x 32Bit erkennt.
Ja, ich habe ja die Funktion für die Multiplikation gepostet. Da steht
es drin, was mit dem Eingangsvektor passiert.
Batzi schrieb:> Es kann ja nicht sein, dass man nicht einfach C = A * B schreiben kann> und er kriegt die Breiten selber raus, bzw multipliziert und addiert so,> dass das mathematisch richtige Ergebnis rauskommt ohne dass ich immer> mit den Breiten tricksen muss, dass es stimmt.
In meinen Augen ist das eine Inkonsistenz im VHDL-Standard.
Bei der Addition wird leider ungefragt abgeschnitten, während die
Multiplikation saubere Bitbreiten erfordert.
Duke
Duke Scarring schrieb:> In meinen Augen ist das eine Inkonsistenz im VHDL-Standard.
Oder eher in der Umsetzung...
Denn die letztlich zur Addition verwendete Funktion ADD_UNSIGNED() nimmt
zwar ein Carry an, gibt aber keinen Übertrag mehr aus:
1
-- this internal function computes the addition of two UNSIGNED
(Auszug aus
https://www.csee.umbc.edu/portal/help/VHDL/packages/numeric_std.vhd)
> während die Multiplikation saubere Bitbreiten erfordert.
Oder im Falle einer Multiplikation z.B. eines n-Bit Vektors mit einem
Integer >2**n-1 wenigstens eine Warnung ausgibt, weil ja die
Multiplikation nur 2*n Bits Platz vorsieht und den Integer auf die
Anzahl Bits des unsigned Vektros zusammenstutzen will:
1
-- Id: A.17
2
function"*"(L:UNSIGNED;R:NATURAL)returnUNSIGNEDis
3
begin
4
returnL*TO_UNSIGNED(R,L'length);-- <-- der Integer muss in die Länge des UNSIGNED Vektors passen
Lothar M. schrieb:> Das war ja einfach... ;-)> Allerdings gilt hier diese Funktionsdefinition, weil '2' ja kein> unsigned Vektor, sondern ein natürlicher Wert ist:
Da fällt mir natürlich spontan die Frage auf, warum das so ist?
Wenn die 2, hier ein natural, massgeblich ist für die effektive Breite
des Vektors, müsste man nicht pauschal die Länge der Vektors L als
Breite nehmen, wie es dort steht:
-- Result subtype: UNSIGNED((L'length+L'length-1) downto 0).
Denn was passiert, wenn ein 8 Bit unsigned mit 700 multipliziert ?
Dann würden 2x8 = 16 nicht reichen.
Warum benutzt er nicht "Länge von A" + "Länge von B"?
Batzi schrieb:> Denn was passiert, wenn ein 8 Bit unsigned mit 700 multipliziert ?
Probiers einfach aus. Oder sieh dir den Code dieses Operators
UNSIGNED*INTEGER an.
Fazit: Meldung "vector truncated"
> Warum benutzt er nicht "Länge von A" + "Länge von B"?
Weil es so im Code steht.
Wer aber auf die kreative Idee gekommen ist, hier implizit einfach den
UNSIGNED Vektor zu verdoppeln, das dürfte sich in den Annalen verloren
haben.
Lothar M. schrieb:> Wer aber auf die kreative Idee gekommen ist, hier implizit einfach den> UNSIGNED Vektor zu verdoppeln, das dürfte sich in den Annalen verloren> haben.
Möglicherweise einfach Bequemlichkeit? Am Ende ist es egal, ob man 1
oder n Bits addiert, weil sich der Anwender in beiden Fällen Gedanken
über die letztlich zu verwendenden Bits machen und passend abschneiden
muss.
Wenn ich es mir recht überlege, dann wäre es aber schon sinnvoll, es
konsistent zu haben, d.h. die Verbreiterung des Vektors so anzulegen,
wie es die Zahl erfordert.
Jürgen S. schrieb:> Wenn ich es mir recht überlege, dann wäre es aber schon sinnvoll, es> konsistent zu haben, d.h. die Verbreiterung des Vektors so anzulegen,> wie es die Zahl erfordert.
Das stört aber bei Parametrierung, wenn plötzlich interne Signale
unterschiedliche, parameterabhängige Breiten haben. Überflüssige Bits
wirft die Optimierung raus, die muss man im Code nicht behandeln, exakte
Bitbreiten schon.
S. R. schrieb:> Jürgen S. schrieb:>> Wenn ich es mir recht überlege, dann wäre es aber schon sinnvoll, es>> konsistent zu haben, d.h. die Verbreiterung des Vektors so anzulegen,>> wie es die Zahl erfordert.>> Das stört aber bei Parametrierung, wenn plötzlich interne Signale> unterschiedliche, parameterabhängige Breiten haben. Überflüssige Bits> wirft die Optimierung raus, die muss man im Code nicht behandeln, exakte> Bitbreiten schon.
Ja, aber neben anderen Nachteilen tritt dann der Fall aus, dass die
Synthese massenhaft warnings produziert, womit das nicht mehr als
Korrektiv für richtigen Code nutzbar ist.
Stimmt, wobei ich den Sinn bei manchen Warnungen nicht verstehe.
In C achte ich darauf, Warnungen zu vermeiden (-Wall, manchmal -Wextra),
aber in VHDL/Verilog scheint das ein Ding der Unmöglichkeit zu sein. Und
wenn sogar Vivados selbst-generierter Code in der Synthese mit Warnungen
nur so um sich schmeißt, ...naja.
Ein __attribute__((i_know_you_will_remove_the_high_bits)) wäre schön,
ist aber zumindest in VHDL nicht vorgesehen (oder mehr Schreibaufwand
als nötig). Ich bin wahrscheinlich zu sehr Anfänger, aber ein Gefühl für
"sauberes HDL" habe ich noch nicht gefunden.
In Quartus II lassen sich Warnungen im "Message Suppression Manager"
unterdrücken. Dann muß man sie nicht 100x angucken.
Ich bin fast überzeugt, die Xilinx-Tools können so was auch.
Markus F. schrieb:> Ich bin fast überzeugt, die Xilinx-Tools können so was auch.
Idee, wo ich das einstelle? Ich klicke immer die warning an und lasse
sie wegfiltern, trotzdem kommen immer wieder neue, die ähnlich sind. Das
ist mühsam.
Aber nochmals zum eigentlichen Problem:
Wenn ich ich nicht jedesmal resize verwenden möchte, bin ich eigentlich
der Willkür des Compilers ausgeliefert. Bei einer Kombination aus den
beiden Beispielen von weiter vorn, nämlich der Addition und der
Multiplikation handhabt er den Überlauf auch wieder falsch, weil die
"*"-Operation einen gesonders großen Vektor erzeugt und die parallele
Addition da unter geht. Dass in Wirklichkeit (k)ein weiteres Bit erzeugt
wird und damit das Ergebnis nicht stimmt, kümmert ihn wenig.
Duke Scarring schrieb:> In meinen Augen ist das eine Inkonsistenz im VHDL-Standard.> Bei der Addition wird leider ungefragt abgeschnitten, während die> Multiplikation saubere Bitbreiten erfordert.
Alerdings und nicht nur da.
Wenn ich im Taschenrechner mal und plus eingebe, kriegt er es auch
gebacken und erhöhrt seine Stellen richtig. Das müsste doch mit einem
FPGA auch gehen.
Batzi schrieb:> Wenn ich ich nicht jedesmal resize verwenden möchte, bin ich eigentlich> der Willkür des Compilers ausgeliefert.
Hallo,
die VHDL-Sprache ist die am wenigsten willkürliche die ich kenne. Das
Problem liegt leider im Code:
1
OUT_NEW<=VAL_OLD*2+ROT_OLD;
OUT_NEW ist 32 bit breit, wie auch die synthese bestätigt. VAL_OLD ist
ebenfalls 32 bit breit. Die '2' ist aber ein Integer, der, nach
Standard, 64 Bit breit ist. Hier hast du deine 64 Bit.
Wenn du es unbedingt auf diese Breiten begrenzen willst, kannst du es
folgendermaßen machen:
Also: Schiebe eins nach links und entferne das höchste Bit.
Möglicherweise habe ich im Code einen Tippfehler (nicht getestet), aber
so würde es (ohne Willkür) gehen.
Stefan U. schrieb:> die VHDL-Sprache ist die am wenigsten willkürliche die ich kenne.
Dafür ist deine Erklärung aber erstaunlich falsch. :-)
Stefan U. schrieb:> Die '2' ist aber ein Integer, der, nach> Standard, 64 Bit breit ist.
Ein Integer in VHDL ist immer 32 Bit breit und signed.
Das Problem ist, dass in VHDL eine 32x32-Multiplikation immer einen 64
Bit breiten Vektor ergibt, unabhängig von den Wertebereichen.
S. R. schrieb:> Ein Integer in VHDL ist immer 32 Bit breit und signed.
Tatsächlich legt der VHDL-Standard die Breite von Integern nicht fest,
sondern läßt sie als "implementation defined" offen. Er sagt nur, daß
mindestens der Wertebereich eines 32-Bit unsigned abgedeckt werden
muß.
Es könnte also (auch wenn mir das bislang noch nicht untergekommen
ist) auch Implementierungen mit breiteren integer-Typen geben.
S. R. schrieb:> Ein Integer in VHDL ist immer 32 Bit breit und signed.
Das ist richtig. Ich war irgendwie bei den Physical-Types..
@TO:
Du nutzt ja numeric_std als package. Hier mal ein Link dazu:
https://www.csee.umbc.edu/portal/help/VHDL/packages/numeric_std.vhd
Wenn man den nich hizufügen darf, bitte entfernen.
Unter dem Punkt A.17 ist die Multiplikation von unsigned und natural
definiert. In der Beschreibung steht, dass die Größe des Return-Vektors
doppelt so groß ist wie der unsigned-Input-Vektor.
Stefan U. schrieb:> Hier mal ein Link dazu:> https://www.csee.umbc.edu/portal/help/VHDL/packages/numeric_std.vhd> Wenn man den nich hizufügen darf, bitte entfernen.
Darf man schon, habe ich ja vor zweieinhalb Monaten auch schon gemacht:
Beitrag "Re: rechnen mit unsigned"> Unter dem Punkt A.17 ist die Multiplikation von unsigned und natural> definiert. In der Beschreibung steht, dass die Größe des Return-Vektors> doppelt so groß ist wie der unsigned-Input-Vektor.
Jetzt sind wir dann aber echt in einer Zeitschleife gefangen:
Beitrag "Re: rechnen mit unsigned"
Wiederholtes Fazit: wer was mit der numeric_std und den darin
definierten Datentypen machen will, der sollte sich das Package einfach
mal anschauen. Man lernt was dabei... ;-)
Lothar M. schrieb:> Jetzt sind wir dann aber echt in einer Zeitschleife gefangen:
Oh! Sorry.. Das hab ich wohl überlesen. Aber da stimmen wir überein:
--Erstmal das eingebundene Package lesen.--
wenn's dir nur darum geht, mit einer festen Vektorbreite zu rechnen
(also alle höherwertigen Bits abzuschneiden) und dir resize() zu sperrig
ist, hätte ich hier eine kürzere Alternative:
1
signale:unsigned(31downto0);
2
...
3
e<="+"("*"(a,b)(e'range),c)(e'range);
Zugegeben, ein bißchen ungewohnt zu lesen; aber völlig korrektes VHDL
(und man kann gleich testen, ob der Leser mit der Sprache vertraut ist
;) ).