Forum: FPGA, VHDL & Co. große Dezimalwerte in VHDL zuweisen


von Tomse (Gast)


Lesenswert?

Ich muss einem VHDL-Vektor einen Wert zuweisen , der 64 Bit auslastet 
und würde gerne die aus MATHCAD generierten Werte nehmen. Das sind 
positive Dezimalwerte.

Bei der Zuweisung bekomme ich aber schon beim INIT einen ÜBerlauffehler:

signal rtm_wert : std_logic_vector(63 downto 0) <= std_logic_vector 
(to_unsigned( 5030521883283424760,64));

Was könnte da falsch sein?

Wenn ich es mit CALC umrechne auf Bit und zuweise geht es:

signal rtm_wert : std_logic_vector(63 downto 0) := 
"100010111010000000000001111111111111111111100000000010111111000";

benutzt wird:

use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

von -gb- (Gast)


Lesenswert?

Tomse schrieb:
> signal rtm_wert : std_logic_vector(63 downto 0) <= std_logic_vector
> (to_unsigned( 5030521883283424760,64));

:= statt <=

von Tomse (Gast)


Lesenswert?

Kleine Korrektur, auch im CALC geht es auch nicht. Der Calc läuft da 
auch über. Die Werte scheinen zu groß zu sein. Der hier z.B. 
18445829279364155008. Da muss ich mal Rücksprache mit den Kollegen 
halten, ob die überhaupt stimmen.

Der automatische erzeugte Code in Verilog sieht so aus:

64'd 5030521883283424760
64'd18445829279364155008

von Tomse (Gast)


Lesenswert?

-gb- schrieb:
> := statt <=
Da habe ich was falsches rauskopiert, es war kein Syntaxproblem.

So war es:

signal rtm_wert : std_logic_vector(63 downto 0) := std_logic_vector 
(to_unsigned( 5030521883283424760,64));

response:
** Error: D:\rtm_generator\src\rtm.vhd(37): near "5030521883283424760": 
(vcom-119) Integer value exceeds INTEGER'high.

von Simon L. (dfgh)


Lesenswert?

Numerische (dezimale) Literale sind leider erstmal integer, bevor man 
sie in unsigned(mein int) stecken kann.

Mit den Vektorvarianten x"AFFEC0FFEEDEADBEEF" (x für Hex) geht es aber.

Wenn man große Zahlen unbedingt dezimal schreiben will, könnte man die 
Ziffern in ein Hexliteral gießen und die Umrechnung zur richtigen Zahl 
schnell mal als Funktion schreiben. Da du intialisierst kostet das ja 
keine Hardware.

von Tomse (Gast)


Lesenswert?

Ja, könnte man, leider fehlt mir momentan der Ansatz, wie ich aus den 
gegebenen Dezimalwerten gültige Zahlen mache, die ich zuweisen kann.

Ich könnte ja HEX nehmen, aber die laufe auch irgendwie über.

Der größte Wert für z.B. 3FFF...F ist 9223372036854775807

D.h. der 18445829279364155008 kann gar nicht in 64 bit passen.

Ich frage mich was der soll. Kann jemand diese Veriloganweisung 
interpretieren? muss ich die 1 weglassen?

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


Lesenswert?

Tomse schrieb:
> der 18445829279364155008 kann gar nicht in 64 bit passen.
Warum nicht? Das ist (unsigned) FFFC_BFFF_DA22_FA00. Da ist also schon 
noch "Luft" bis FFFF_FFFF_FFFF_FFFF.

> Der größte Wert für z.B. 3FFF...F ist 9223372036854775807
Der höchste signed 64-Bit Wert 7FFF_FFFF_FFFF_FFFF entspricht der obigen 
Dezimalzahl. signed FFFF_FFFF_FFFF_FFFF wäre dann ja -1. Und signed 
1000_0000_0000_0000 sind -9223372036854775808.

Simon L. schrieb:
> Numerische (dezimale) Literale sind leider erstmal integer
Und leider ist integer'high noch immer nur 2^31-1.

: Bearbeitet durch Moderator
von DurchDieGegendWandern.not_blind (Gast)


Lesenswert?

Der TO sollte mal die konkrete Fehlermeldung des Tools hier wiedergeben, 
als die Experten stumpf raten zu lassen.

Wie in den Antworten zu sehen ist, kann es kein Überlauffehler sein, da 
der bspw  der Syntax falsch geschrieben ist.

Und natürlich ist zu klären, welches tool hier den Fehler schmeisst.

von Christoph Z. (christophz)


Lesenswert?

Simon L. schrieb:
> Wenn man große Zahlen unbedingt dezimal schreiben will, könnte man die
> Ziffern in ein Hexliteral gießen und die Umrechnung zur richtigen Zahl
> schnell mal als Funktion schreiben. Da du intialisierst kostet das ja
> keine Hardware.

Interessanter Ansatz, gefällt mir aber nicht so, weil ich ein gültiges 
Hexliteral habe, das aber ohne Umrechnung (die man vergessen könnte 
hinzuschreiben) falsch ist.

Als Umweg aus dem Problem, das INT'high nur 2^31-1 ist, könnte man 
trotzdem mit Funktionen arbeiten aber vielleicht besser in der Form von 
unendlich genauen Decimals. Das wäre in VHDL am einfachsten ein Array 
vom Typ int jeweils mit range 0 to 9.

Dann überlädt man noch die Funktion to_unsigned mit einer eigenen für 
diesen neuen Arraytyp und es sollte klappen, ohne das es gross anders 
aussieht. Die Zuweisung müsste wohl dann etwa so gehen:
signal rtm_wert : std_logic_vector(63 downto 0) := std_logic_vector
(to_unsigned("5030521883283424760",64));

Hab ich etwas übersehen, das meiner Idee im Weg steht?

von Leierkastenopa (Gast)


Lesenswert?

Christoph Z. schrieb:
> Hab ich etwas übersehen, das meiner Idee im Weg steht?

Ja, den test mit einem Synthesetool.
Die haben sich oft zickig, wenn man standard-Funktionen nach 
Gutsherrenart verbiegt aehm, overloaded. VHDL ist nicht C++.

von VHDL hotline (Gast)


Lesenswert?

Lothar M. schrieb:
> Und leider ist integer'high noch immer nur 2^31-1

"Bald" nicht mehr.

https://vhdlwhiz.com/vhdl-2019/#long-integers

von Markus F. (mfro)


Lesenswert?

Warum kein VHDL 2008?

Da schreibt man einfach
1
signal rtm_wert  : std_logic_vector(63 downto 0) := std_logic_vector(unsigned'(64d"5030521883283424760"));
und hat kein Problem mit "verkrüppelten" 32 Bit Integern.

von Tomse (Gast)


Lesenswert?

Lothar M. schrieb:
>> der 18445829279364155008 kann gar nicht in 64 bit passen.
> Warum nicht? Das ist (unsigned) FFFC_BFFF_DA22_FA00. Da ist also schon
> noch "Luft" bis FFFF_FFFF_FFFF_FFFF.

Tja, da stehe ich wohl komplett auf dem Schlauch. Ich habe das in den 
CALC eingegeben und mich daran aufgehängt. Der rechnet aber auch signed, 
wie mir scheint und hat noch andere Probleme, weil er vorn abschneidet.

Wenn ich dort z.B. die o.g. Zahl eingebe, druckt er mir binär das aus
11001100.11001010.00110011.00110011.00010011.00110011.00111000.01100
da fehlen also Stellen.

In der kleinen Ansicht sieht man die führenden Nullen.

Wenn ich deinen HEX eingebe, geht es: er bringt halt nur einen negativen 
Wert.

Kennt jemand einen Rechner, der das nicht falsch macht?

Das andere Problem mit dem limitierten Integer habe ich verstanden. 
Hatte ich auch übersehen.

Das Dumme ist wie gesagt, dass die Zahlen aus MATHCAD eben in Real 
rauskommen und ich nur die Zahlen habe. Hex wäre super, das kann ich 
zuweisen.

von Markus F. (mfro)


Lesenswert?

Tomse schrieb:
> Lothar M. schrieb:
>>> der 18445829279364155008 kann gar nicht in 64 bit passen.
>> Warum nicht? Das ist (unsigned) FFFC_BFFF_DA22_FA00. Da ist also schon
>> noch "Luft" bis FFFF_FFFF_FFFF_FFFF.

ich glaub', Lothar (oder sein Taschenrechner) hat sich da verrechnet.

Das ist tatsächlich (jedenfalls nach meiner Rechnung) 
FFFC_BFFF_D800_0680.
Recht hat er trotzdem.

von Tomse (Gast)


Lesenswert?

Ja, ich denke, die Zahlen stimmen. Die Hinternisse sind offenbar INT im 
VHDL und im PC, die das limitieren. Interessante Erkenntnis.

Bleibt die Frage nach einem Window-Taschenrechner, der 64 Bit breite 
Dezimalwerte korrekt und direkt in HEX umrechnet. Den CALC kann ich 
nicht auf unsigned umstellen oder dazu bewegen mit dieser großen Zahl zu 
rechnen.

Müsste man erst splitten, nehme ich an. Z.B. 8 Bit wegnehmen und die per 
Hand in HEX umbauen.

Beitrag #7272598 wurde von einem Moderator gelöscht.
von Samuel C. (neoexacun)


Lesenswert?

Muss ja nicht zwingend ein Windows-kompatibler Rechner sein.

https://www.wolframalpha.com/input?i=18445829279364155008+to+hexadecimal

von Tomse (Gast)


Lesenswert?

Markus F. schrieb:
> Da schreibt man einfachsignal rtm_wert  : std_logic_vector(63 downto 0)
> := std_logic_vector(unsigned'(64d"5030521883283424760"));
> und hat kein Problem mit "verkrüppelten" 32 Bit Integern.

VHDL 2008 ist die Lösung! Danke!

von Markus F. (mfro)


Lesenswert?

Tomse schrieb:
> Ja, könnte man, leider fehlt mir momentan der Ansatz, wie ich aus den
> gegebenen Dezimalwerten gültige Zahlen mache, die ich zuweisen kann.

So zum Beispiel (die Routine ist signed und muss deswegen ein Bit mehr 
haben als 64):
1
library ieee;
2
use ieee.numeric_std.all;
3
use std.textio.all;
4
5
entity large_decimals is
6
    generic
7
    (
8
        BITS    : natural := 65;
9
        DEBUG   : boolean := false
10
    );
11
end entity large_decimals;
12
13
architecture sim of large_decimals is
14
15
    -- missing from numeric_std
16
    function "**"(num : signed; exp : signed) return signed is
17
        variable result  : signed(BITS - 1 downto 0);
18
        variable e : signed(BITS - 1 downto 0);
19
    begin
20
        result := num;
21
        e := exp;
22
        if e = 0 then return to_signed(1, BITS); end if;
23
        l : loop
24
            assert not DEBUG report "result=" & to_hstring(result) severity note;
25
            e := e - 1;
26
            if e = 0 then
27
                exit;
28
            end if;
29
            result := resize(result * num, result'length);
30
        end loop;
31
        return result;
32
    end function "**";
33
34
    function to_dstring(s : signed) return string is
35
        function to_dstring_recursive(s : signed) return string is
36
            variable digit : character;
37
        begin
38
            digit := integer'image(to_integer(s mod 10))(1);
39
            if s / 10 > 0 then
40
                return to_dstring(s / 10) & digit;
41
            end if;
42
            return to_string(digit);
43
        end function to_dstring_recursive;
44
45
        variable digit : character;
46
    begin -- to_dstring
47
        digit := integer'image(to_integer(s mod 10))(1);
48
        if s / 10 > 0 then
49
            return to_dstring_recursive(s / to_signed(10, s'length)) & digit;
50
        end if;
51
        return to_string(digit);
52
    end to_dstring;
53
54
55
    procedure int64_read(variable ln : inout line; num : out signed; good : out boolean) is
56
        constant dvals      : string := "0123456789";
57
        variable c          : character;
58
        variable maxdepth   : signed(BITS - 1 downto 0);
59
60
        --
61
        -- translate a single numeric ('0' - '9') into its integer equivalent.
62
        -- Return -1 if character isn't identified as valid numeric
63
        --
64
        function ival(c : character) return signed is
65
        begin
66
            for i in dvals'range loop
67
                if dvals(i) = c then
68
                    return to_signed(i - 1, BITS);
69
                end if;
70
            end loop;
71
            -- if character isn't numeric
72
            return to_signed(-1, BITS);
73
        end function ival;
74
75
        --
76
        -- check if character is a numeric.
77
        --
78
        function is_dec(c : character) return boolean is
79
        begin
80
            return ival(c) /= to_signed(-1, BITS);
81
        end function is_dec;
82
83
        --
84
        -- The recursive part of int64_read. Collects single digit's numerical values in
85
        -- string in a recursive descend until it hits a non-digit character.
86
        -- Then, on ascent of the recursive call, adds up all the collected digits
87
        -- multiplied by ther digit position's valence.
88
        --
89
        -- TODO: lacks any overflow checks.
90
        --
91
        impure function recursive_int64_read(depth : signed) return signed is
92
            variable num    : signed(BITS - 1 downto 0);
93
            variable c      : character;
94
        begin
95
            -- peek into the line buffer to see if there is another numeric character
96
            if ln.all'length > 0 and is_dec(ln.all(ln.all'left)) then
97
                read(ln, c);
98
                num := ival(c);
99
                assert not DEBUG report "digit = " & c severity note;
100
                return recursive_int64_read(depth + 1) + num * 
101
                                                         to_signed(10, BITS) **
102
                                                         (maxdepth - depth);
103
            else
104
                -- walk on, nothing to see here
105
                maxdepth := depth - 1;
106
                return to_signed(0, BITS);
107
            end if;
108
        end function recursive_int64_read;
109
110
    begin -- int64_read
111
        maxdepth := to_signed(0, maxdepth'length);
112
        -- skip leading white space
113
        if ln.all'length > 0 then
114
            skip_loop: for i in ln.all'range loop
115
                if ln.all(ln.all'left) = ' ' or ln.all(ln.all'left) = HT then
116
                    read(ln, c);
117
                else
118
                    exit skip_loop;
119
                end if;
120
            end loop;
121
122
            -- call recursive part
123
            num := resize(recursive_int64_read(to_signed(1, BITS)), num'length);
124
            -- error checking
125
            if maxdepth < 1 then
126
                good := false;
127
            else
128
                good := true;
129
            end if;
130
        end if;
131
    end int64_read;
132
133
begin   -- architecture sim
134
    p_initial : process
135
        variable l      : line;
136
        variable s      : signed(BITS downto 0);
137
        variable good   : boolean;
138
    begin
139
        l := new string'("18445829279364155008");
140
        
141
        int64_read(l, s, good);
142
143
        if good then
144
            write(output, "result= " & to_dstring(s) & " (" & to_hstring(s) & ")");
145
        else
146
            write(l, "error reading from string " & l.all);
147
            writeline(output, l);
148
        end if;
149
        wait;
150
    end process p_initiaL;
151
end architecture sim;
1
result= 18445829279364155008 (0FFFCBFFFD8000680)

: Bearbeitet durch User
von Christoph Z. (christophz)


Lesenswert?

Tomse schrieb:
> Bleibt die Frage nach einem Window-Taschenrechner, der 64 Bit breite
> Dezimalwerte korrekt und direkt in HEX umrechnet.

Ich nehme gerne SpeedCrunch:
https://heldercorreia.bitbucket.io/speedcrunch/

Zum Rechnen kannst du binär und hex wie gewohnt eintippen. Potenz geht 
wie in C oder in Python beides (^ oder **), constanten etc. gibt es 
auch.

Die Resultate musst du auch nicht in HEX umrechnen, sondern zu schaltest 
einfach die Basis um, in der die Resultate angezeigt werden (das geht 
mit F4 bis F8).

Gibt es für übliche Betriebssysteme und läuft auch Portabel, wenn man 
nix installieren darf.

von Tomse (Gast)


Lesenswert?

Werde ich probieren! Danke!

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

>SpeedCrunch
Danke für den Tip, hab es unter Ubuntu installiert, ging problemlos.

Beitrag "Re: Hilbert Transformation im uC berechnen"
da hatte ich auch breitere Berechnungen benötigt als sie LibreOfficeCalc 
erlaubt. Eine Zerlegung in Binärbrüche um ein IIR-Filter ohne 
Multiplizierer in einem CPLD unterzubringen.

Sollwert:                      0,161758498367701
LibreOfficeCalc aus Binärzahl: 0,161758423782885
mit Speedcrunch berechnet:     0,161758498288691
also fast 10 Stellen identisch, mit LibreOffice sind es nur 7. Der Rest 
kann ein Rundungsfehler sein, da nur die ersten 32 binären 
Nachkommastellen berücksichtigt sind.

Eingabe dazu in Speedcrunch (die Hilfefunktion ist gut verständlich):
dec(0b0,00101001011010010000000101000100)

: Bearbeitet durch User
von Tomse (Gast)


Lesenswert?

Woraus definiert sich hier der "Sollwert"? Ist das die Realzahl und die 
anderen die rückgerechneten Werte aus der zwischenzeitlichen 
Transformation in Binär?

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Ja genau, der Sollwert liegt dezimal vor, die anderen sind vom 
Binärbruch auf dezimal zurückgerechnet.

Ich habe einen Text von 2001, darin sind 8 Koeffizienten für ein 
IIR-Filter genannt. Die müssen noch quadriert werden, damit werden sie 
doppelt so breit. Die Zahl 0,161758498367701 ist der kleinste quadrierte 
Koeffizient.
Quadriert habe ich mit dem Gnome-Calculator, der rechnet mit bis zu 64 
Bit, kennt aber keine Binärbrüche im Gegensatz zum SpeedCrunch.

Normalerweise wird dann in einem DSP oder Mikrocontroller damit 
multipliziert. Ich habe aber einen anderen Text aus der Zeit, in dem ein 
"multiplierless" IIR-Filter beschrieben ist, das so in ein CPLD passen 
soll.
Dazu muss ich die 8 quadrierten Koeffizienten zu einer (hier auf 32 Bit 
gerundeten) Summe von Binärbrüchen umformen. Dann braucht man nur noch 
Addierer und Schieberegister, was (hoffentlich) weniger Platz im CPLD 
braucht als 8 Multiplizierer mit mindestens 16 Bit Breite, oder 
ersatzweise auch ein einziger Multiplizierer, der acht Berechnungen 
nacheinander durchführt.

: Bearbeitet durch User
von dfIas (Gast)


Lesenswert?

Ist denn überhaupt eine so hohe Auflösung nötig? Was passiert, wenn man 
auf ein paar Bits verzichtet? Braucht die Anwendung diese Genauigkeit 
oder ist es der Rechentechnik geschuldet, damit keine störenden 
Artefakte entstehen? Man kennt solche Probleme z. B. bei 
Potenzreihenentwicklungen, die bei unzureichender Näherung schnell ins 
Oszillieren geraten.
Für Astronomie brauchte man sehr hohe Genauigkeiten, hieß es mal. Dafür 
wurden Programmiersprachen entwickelt, die das unterstützten. Aber ich 
vermute, dass man seinerzeit Auflösung und Dynamik nicht unterschieden 
hatte. Ein Sonnensystem, dass Millionen Lichtjahre entfernt ist, da 
kommt es doch wohl nicht mehr auf einen Zentimeter an.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Ich kann dazu nur den Artikel zitieren.

Beitrag "Re: Hilbert Transformation im uC berechnen"
das sind die beiden Texte, um 2001 als Zeitschriftenartikel und als 
Kapitel in einem Buch erschienen. Damals waren programmierbare 
Logikbauteile noch weniger komplex als heute, Multiplizierer in Hardware 
noch selten enthalten.

In den Diagrammen sind jeweils (nur berechnet, nicht gemessen) die 
exakte Kurve mit den auf vier dezimale Nachkommastellen gerundeten 
Koeffizienten als durchgehende Linie gezeigt, und gestrichelt die mit 
Binärbrüchen angenäherten, maximal auf die 6. binäre Nachkommastelle 
gerundet. Wobei ich nicht weiß, wie die Binärzerlegung genau gemacht 
ist.

Die Abweichungen kleiner als 1/10000 dB im Durchlass sind uninteressant, 
aber eine Seitenbandunterdrückung von 55 oder nur 50 dB wären mit dem 
Spektrumanalysator schon deutlich messbar.

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.