Forum: FPGA, VHDL & Co. Rechnen mit signed und integer


von Marc M. (bench)


Lesenswert?

Hallo zusammen,

ich habe ein Problem mit den Bitbreiten beim Rechnen mit signed und 
integer.

Ich habe einen Eingang und einen counter.
Ist der Eingang HIGH, dann zähle ich +1.
Ist der Eingang LOW, dann zähle ich -1.
Das ganze mache ich für 2^3 = 8 Taktzyklen.
1
  count : PROCESS (CLK, NRES)
2
  BEGIN
3
    IF (NRES = '0') THEN
4
      cnt <= (OTHERS => '0');
5
    ELSIF rising_edge(CLK) THEN
6
        IF PORT_IN = '1' THEN
7
          cnt <= cnt + to_signed(1, cnt'LENGTH);
8
        ELSE
9
          cnt <= cnt - to_signed(1, cnt'LENGTH);
10
        END IF;
11
    END IF;
12
  END PROCESS count;

Die Anzahl der Takte, die ich zählen möchte lege ich mit einem Integer 
fest.
1
SIGNAL cycles   : integer RANGE 8 DOWNTO 0 := 8;

Nun habe ich also 8 Takte die ich zähle.
Mein cnt kann also 8 oder -8 sein, sollte der Eingang dauerhaft HIGH 
oder LOW sein.
Mein cnt muss ich also so festlegen:
1
SIGNAL cnt : signed(4 DOWNTO 0);

Nun muss ich anschließend cnt und cycles aber noch addieren.
1
temp <= cnt + to_signed(cycles, cnt'LENGTH)
Hier habe ich also -8 + 8 = 0. Oder ich habe 8 + 8 = 16. Vom 
Wertebereich her sollten also wieder 5 bit ausreichen.
Aber wird die Rechnung dann immer noch korrekt, oder muss temp dann 
unsigned sein, damit das passt?
Kann ich dann einfach bei temp das "Vorzeichenbit" abschneiden, weil 
negative Werte ja ausgeschlossen sind?

Kann mir jemand auf die Sprünge helfen?

Folgende Links haben mir leider nicht weiter geholfen:
https://www.mikrocontroller.net/articles/Rechnen_in_VHDL
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

Vielen Dank!

: Bearbeitet durch User
von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Marc M. schrieb:
> Hier habe ich also -8 + 8 = 0. Oder ich habe 8 + 8 = 16. Vom
> Wertebereich her sollten also wieder 5 bit ausreichen.
> Aber wird die Rechnung dann immer noch korrekt, oder muss temp dann
> unsigned sein, damit das passt?
Da hast uns die Definition von temp noch nicht gezeigt.

> Kann ich dann einfach bei temp das "Vorzeichenbit" abschneiden, weil
> negative Werte ja ausgeschlossen sind?
Ich denke ja.

Du kannst es ja einfach in der Simulation ausprobieren.
Anbei eine Testbench...

Duke

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


Lesenswert?

Marc M. schrieb:
> SIGNAL cycles   : integer RANGE 8 DOWNTO 0 := 8;
Ein "üblicher" Integer ist aufsteigend definiert. Warum ist deiner 
andersrum?

> Mein cnt kann also 8 oder -8 sein, sollte der Eingang dauerhaft HIGH
> oder LOW sein.
> Mein cnt muss ich also so festlegen:SIGNAL cnt : signed(4 DOWNTO 0);
Richtig. Mit 5 Bit kannst du -16..+15 abbilden...

> Aber wird die Rechnung dann immer noch korrekt, oder muss temp dann
> unsigned sein, damit das passt?
> Kann mir jemand auf die Sprünge helfen?
Warum diese umständliche Bastelei mit dem Signed-Vektor?
Mach den cnt doch einfach zum Integer. Und auch deine ganze Rechnung 
machst du mit Integer-Signalen. Du kannst dann einfach vor der Zuweisung 
an ein externes Signal den Integer auf 5 Bits (signed oder was auch 
immer) zurechtstutzen...

von Marc M. (bench)


Lesenswert?

Lothar M. schrieb:
> Ein "üblicher" Integer ist aufsteigend definiert. Warum ist deiner
> andersrum?

Keine Ahnung, macht das einen Unterschied?
Ich denke, das habe ich irgendwann via copy & paste übernommen und mache 
es seit dem immer so. Habe mir nie Gedanken darüber gemacht.

Lothar M. schrieb:
> Warum diese umständliche Bastelei mit dem Signed-Vektor?

Wenn cnt = 0 ist und PORT_IN LOW, dann komme ich mit Integer nicht weit, 
weil Integer nur > 0 definiert ist?
Oder habe ich auch hier schon einen Denkfehler?

Vielen Dank!

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


Lesenswert?

Marc M. schrieb:
> Keine Ahnung, macht das einen Unterschied?
Wenn du Attribute anwendest kann das durchaus überraschende Effekte mit 
sich bringen.

> Ich denke, das habe ich irgendwann via copy & paste übernommen
Weißt du die Quelle noch?
Sinnvol ist downto bei Vektoren, weil dort dann das "linkeste" Bit den 
höchsten Index hat. Und das "nullte" Bit mit 2^0 den Wert 1.

> und mache es seit dem immer so. Habe mir nie Gedanken darüber gemacht.
Es ist von der Logik her falsch. Ein Integer an sich ist aufsteigend 
definiert, ein (mit range) eingeschränkter Integer somit eigentlich 
auch...

> Wenn cnt = 0 ist und PORT_IN LOW, dann komme ich mit Integer nicht weit,
> weil Integer nur > 0 definiert ist?
Verwechselst du da was mit natural oder gar positive?
http://www.csee.umbc.edu/portal/help/VHDL/types.html
Ein Integer geht üblicherweise von -(2^31) bis +(2^31)-1 also von 
-2147483648 bis +2147483647.

: Bearbeitet durch Moderator
von Marc M. (bench)


Lesenswert?

Lothar M. schrieb:
> Es ist von der Logik her falsch. Ein Integer an sich ist aufsteigend
> definiert, ein (mit range) eingeschränkter Integer somit eigentlich
> auch...

Ok, dann verwende ich ab jetzt immer
1
SIGNAL cycles   : integer RANGE 0 TO 8  := 8;
Habe in anderen Projekten von mir nachgeschaut und dort habe ich auch 
das TO verwendet, keine Ahnung wieso ich hier wieder umgeschwenkt bin. 
Wie gesagt sicher nur ein copy&paste Fehler.

Lothar M. schrieb:
> Verwechselst du da was mit natural oder gar positive?

Ja das kann gut sein.
Dann werde ich mein cnt mal versuchen so zu definieren:
1
SIGNAL cycles   : integer RANGE -8 TO 8;
Mal sehen, ob ich da etwas sinnvolles heraus bekomme :)

Vielen Dank!

: Bearbeitet durch User
von Marc M. (bench)


Lesenswert?

Kann ich den Integerwert dann auch shiften?

Wenn ich z.B. mein integer-cnt Ergebnis durch 4 teilen möchte (* 
2^-2)...
Muss ich es dann erst nach signed konvertieren und dann shiften?
Muss ich beim rechts-shiften von signed beachten, dass ich die führenden 
Stellen dann mit '1' auffülle, wenn die Vektorbreite konstant bleiben 
soll, korrekt?

: Bearbeitet durch User
von Duke Scarring (Gast)


Lesenswert?

Marc M. schrieb:
> Wenn ich z.B. mein integer-cnt Ergebnis durch 4 teilen möchte (*
> 2^-2)...
Dann schreib eine Division hin. Die Tools verstehen das.

Duke

von Marc M. (bench)


Lesenswert?

Duke Scarring schrieb:
> Dann schreib eine Division hin. Die Tools verstehen das.

Das wird ja immer einfacher mit diesem ominösen Integer ^^

Das ist sicher so etwas wie das kabellose telefonieren, oder dieses 
Internet - total toll, aber wird sich nie durchsetzen...

Wenn ich das Ergebnis dann aber einen std_logic_vector zuweisen will, 
muss ich dann doch nochmal darüber nachdenken, welche Range ich dann 
angebe. Aber wenn die Rechnung mit Integer wirklich so "trivial" in VHDL 
zu implementieren geht, solange man 2^n Werte verwendet, dann bin ich 
echt restlos begeistert und habe wieder viel gelernt! :)

: Bearbeitet durch User
von Duke Scarring (Gast)


Lesenswert?

Marc M. schrieb:
> Aber wenn die Rechnung mit Integer wirklich so "trivial" in VHDL
> zu implementieren geht, solange man 2^n Werte verwendet, dann bin ich
> echt restlos begeistert und habe wieder viel gelernt! :)
Jepp.

Ich war letztens mal mutig und habe ein Division mit 10 hingeschrieben.
1
    signal counter : natural range 0 to 99;
2
    signal digit_0 : unsigned( 3 downto 0);
3
...
4
    digit_0 <= to_unsigned( counter  /  10, 4);
5
    digit_1 <= to_unsigned( counter mod 10, 4);

Daraufhin hat Xilinx-XST das folgende Rechenmonster gemacht:
1
Synthesizing Unit <div_7u_4u>.
2
    Related source file is "".
3
    Found 11-bit adder for signal <n0201> created at line 0.
4
    Found 11-bit adder for signal <GND_62_o_b[3]_add_1_OUT> created at line 0.
5
    Found 10-bit adder for signal <n0205> created at line 0.
6
    Found 10-bit adder for signal <GND_62_o_b[3]_add_3_OUT> created at line 0.
7
    Found 9-bit adder for signal <n0209> created at line 0.
8
    Found 9-bit adder for signal <GND_62_o_b[3]_add_5_OUT> created at line 0.
9
    Found 8-bit adder for signal <n0213> created at line 0.
10
    Found 8-bit adder for signal <GND_62_o_b[3]_add_7_OUT> created at line 0.
11
    Found 7-bit adder for signal <n0217> created at line 0.
12
    Found 7-bit adder for signal <a[6]_b[3]_add_9_OUT[6:0]> created at line 0.
13
    Found 7-bit adder for signal <n0221> created at line 0.
14
    Found 7-bit adder for signal <a[6]_GND_62_o_add_11_OUT[6:0]> created at line 0.
15
    Found 7-bit adder for signal <n0225> created at line 0.
16
    Found 7-bit adder for signal <a[6]_GND_62_o_add_13_OUT[6:0]> created at line 0.
17
    Found 11-bit comparator lessequal for signal <BUS_0001> created at line 0
18
    Found 10-bit comparator lessequal for signal <BUS_0002> created at line 0
19
    Found 9-bit comparator lessequal for signal <BUS_0003> created at line 0
20
    Found 8-bit comparator lessequal for signal <BUS_0004> created at line 0
21
    Found 7-bit comparator lessequal for signal <BUS_0005> created at line 0
22
    Found 7-bit comparator lessequal for signal <BUS_0006> created at line 0
23
    Found 7-bit comparator lessequal for signal <BUS_0007> created at line 0
24
    Found 7-bit comparator lessequal for signal <BUS_0008> created at line 0
25
    Summary:
26
        inferred  14 Adder/Subtractor(s).
27
        inferred   8 Comparator(s).
28
        inferred  31 Multiplexer(s).
29
Unit <div_7u_4u> synthesized.

Nicht wirklich elegant, aber es geht.

Duke

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


Lesenswert?

Duke Scarring schrieb:
> Found 11-bit adder for signal <n0201> created at line 0.
>     Found 11-bit adder for signal <GND_62_o_b[3]_add_1_OUT> created at
> line 0.
>     Found 10-bit adder for signal <n0205> created at line 0.
>     Found 10-bit adder for signal <GND_62_o_b[3]_add_3_OUT> created at
> line 0.
>     Found 9-bit adder for signal <n0209> created at line 0.
>     Found 9-bit adder for signal <GND_62_o_b[3]_add_5_OUT> created at
> line 0.
>     Found 8-bit adder for signal <n0213> created at line 0.
>     Found 8-bit adder for signal <GND_62_o_b[3]_add_7_OUT> created at
> line 0.
>     Found 7-bit adder for signal <n0217> created at line 0.
>     Found 7-bit adder for signal <a[6]_b[3]_add_9_OUT[6:0]> created at
> line 0.
>     Found 7-bit adder for signal <n0221> created at line 0.
>     Found 7-bit adder for signal <a[6]_GND_62_o_add_11_OUT[6:0]> created
> at line 0.
>     Found 7-bit adder for signal <n0225> created at line 0.
>     Found 7-bit adder for signal <a[6]_GND_62_o_add_13_OUT[6:0]> created
> at line 0.
Damit hat der Synthesizer eigentlich nichts anderes gemacht, als 
fortgesetzte Additionen von Divisionen durch Zweierpotenzen:
1
-- Division durch 10 durch Additionen von Vektorsegmenten 
2
erg <= wert/16 + wert/32 + wert/256 + wert/512 + wert/1024 + ....;

> Ich war letztens mal mutig und habe ein Division mit 10 hingeschrieben.
Eine Division durch eine Konstante ist insgesamt wesentlich einfacher 
umzusetzen als eine Division durch eine Variable.
Aber ich würde hier nach wie vor die Lösung über einen Multiplizierer 
gehen. So z.B.:
1
-- Division durch 10 mit einem Fehler von +1 Promille
2
erg <= (wert*205) / 2048;
3
4
-- Division durch 10 mit einem Fehler von -0,24 Promille
5
erg <= (wert*819) / 8192;
6
7
-- Division durch 10 mit einem Fehler von +0,06 Promille
8
erg <= (wert*3277) / 32768;

: Bearbeitet durch Moderator
von Duke Scarring (Gast)


Lesenswert?

Lothar M. schrieb:
> Aber ich würde hier nach wie vor die Lösung über einen Multiplizierer
> gehen.
In diesem Fall wäre die richtige Lösung diese:
Zwei getrennte Dezimalzähler für Einer- und Zehnerstelle.
Die Ziffern werden nur für die Anzeige gebraucht.

Duke

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


Lesenswert?

Duke Scarring schrieb:
> Zwei getrennte Dezimalzähler für Einer- und Zehnerstelle.
Richtig, es ist z.B. für eine Hardwareuhr wesentlich einfacher, jede 
Anzeigestelle mit einem eigenen Zähler anzubilden, und nicht (wie z.B. 
beim PC mit dem time_t) nur einen einzigen Sekundenzähler zu haben, der 
dann mit vielen Divisionen und Subtraktionen auf die Anzeige umgerechnet 
wird.

Und das, obwohl von den für einen Dezimalzähler nötigen 4 Bits nur 5/8 
tatsächlich benützt werden...  ;-)

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.