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
ELSIFrising_edge(CLK)THEN
6
IFPORT_IN='1'THEN
7
cnt<=cnt+to_signed(1,cnt'LENGTH);
8
ELSE
9
cnt<=cnt-to_signed(1,cnt'LENGTH);
10
ENDIF;
11
ENDIF;
12
ENDPROCESScount;
Die Anzahl der Takte, die ich zählen möchte lege ich mit einem Integer
fest.
1
SIGNALcycles:integerRANGE8DOWNTO0:=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
SIGNALcnt:signed(4DOWNTO0);
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_VHDLhttp://www.lothar-miller.de/s9y/categories/16-Numeric_Std
Vielen Dank!
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
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...
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!
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.
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
SIGNALcycles:integerRANGE0TO8:=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
SIGNALcycles:integerRANGE-8TO8;
Mal sehen, ob ich da etwas sinnvolles heraus bekomme :)
Vielen Dank!
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?
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
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! :)
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
signalcounter:naturalrange0to99;
2
signaldigit_0:unsigned(3downto0);
3
...
4
digit_0<=to_unsigned(counter/10,4);
5
digit_1<=to_unsigned(countermod10,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
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
> 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
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
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... ;-)