Forum: FPGA, VHDL & Co. Shift operation auf Integer vereinfachen


von Holger K. (holgerkraehe)


Lesenswert?

Hallo zusammen

Aktuell versuche ich wie folgt, aus einem integer zwei einzelne Bytes zu 
formen:
1
SPI_DATA_H <= std_logic_vector(shift_right(unsigned(std_logic_vector(to_unsigned(r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL), SPI_DATA_H'length))), 8));
2
3
SPI_DATA_L <= std_logic_vector(to_unsigned(r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL), SPI_DATA_L'length));

SPI_DATA_H/L ist std_logic_vector (7 downto 0);
r_MemSegmentValue()() ist ein integer range 0 to 65535;

Es funktioniert in der Simulation. Vermutlich ja auch in HW.
Aber geht das evtl eleganter?

Danke schonmal.

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


Lesenswert?

Holger K. schrieb:
> Aber geht das evtl eleganter?
Man könnte es als Grund ansehen, eine Variable einzusetzen(*)... ;-)
1
variable spitxdata : std_logic_vector (15 downto 0);
2
3
-- Umwandlung
4
spitxdata := std_logic_vector(to_unsigned(r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL), 16));
5
-- Zuweisung
6
SPI_DATA_H <= spitxdata(15 downto 8);
7
SPI_DATA_L <= spitxdata( 7 downto 0);
Aber das gibt mir sowieso zu denken, dass du da so wahllos und direkt in 
den Speicher greifst. Welche Art Speicher hast du da? Wie groß können 
die Indices werden?


(*)das geht natürlich auch mit Signalen, aber dazu müsste mehr vom 
Drumherum der obigen Codezeilen bekannt sein.

: Bearbeitet durch Moderator
von Markus F. (mfro)


Lesenswert?

Lothar M. schrieb:
>
>
1
> variable spitxdata : std_logic_vector (15 downto 0);
2
> 
3
> -- Umwandlung
4
> spitxdata := std_logic_vector(to_unsigned(r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL), 16));
5
> -- Zuweisung
6
> SPI_DATA_H <= spitxdata(15 downto 8);
7
> SPI_DATA_L <= spitxdata( 7 downto 0);
8
>

Kann man so machen, aber geht m.E. auch schöner (wobei Schönheit ja 
immer im Auge des Betrachters liegt).

Das ist (wenn das Synthesetool damit umgehen kann, aber ich wüsste 
keins, daß das nicht könnte) ein Lehrbeispiel für Aliase.
1
    signal spitxdata  : std_logic_vector(15 downto 0);
2
    alias spi_data_low is spitxdata(7 downto 0);
3
    alias spi_data_high is spitxdata(15 downto 8);

Jetzt ist es egal, wo spitxdata zugewiesen wird - die Aliase haben 
immer den richtigen Wert.

von Thomas S. (thschl)


Lesenswert?

schon mal an sowas gedacht

typedef union

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


Lesenswert?

Thomas S. schrieb:
> schon mal an sowas gedacht
> typedef union
Hui, neue VHDL Schlüsselwörter?

Markus F. schrieb:
> die Aliase haben immer den richtigen Wert.
Richtig, ich wollte das in die (*) mit reinpacken, dann kam mir aber die 
Frage nach dem RAM-Typ in den Sinn.
Und letztendlich ging es darum, für die Berechnung nichts zu schieben,
sondern über die Bereiche das Zeug einfach nur anders zu verdrahten.

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Man könnte es als Grund ansehen, eine Variable einzusetzen(*)... ;-)

Noch eleganter faende ich eine Funktion (entweder mit 2 Argumenten oder 
2 Funktionen mit einem Argument), zumindest ist das fuer mich lesbarer. 
Und hat den Vorteil, dass wenn man es oefters an verschiedene Stellen im 
Code braucht besser wartbar ist.

Alte Informatik Regel: Sobald ich einmal Copy&Paste mache, gibt es 
mindestens eine Loesung die besser waere. ;-)

von Gustl B. (-gb-)


Lesenswert?

Mal ganz naiv gefragt:

Was wird denn gebaut wenn man

SPI_DATA_H <= r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL)/256
SPI_DATA_L <= r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL)%256

schreibt? Das wären dann zwei Integer, aber ist doch eigentlich egal, 
dann muss man die eben überall dort wo man sie verwendet in slvs 
umwandeln wenn man das benötigt.

: Bearbeitet durch User
von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Gustl B. schrieb:
> Mal ganz naiv gefragt:
>
> Was wird denn gebaut wenn man
>
> SPI_DATA_H <= r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL)/256
> SPI_DATA_L <= r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL)%256
>
> schreibt? Das wären dann zwei Integer, aber ist doch eigentlich egal,
> dann muss man die eben überall dort wo man sie verwendet in slvs
> umwandeln wenn man das benötigt.

Das haengt vom Synthese Tool ab. Da hilft nur: Ausprobieren und das 
Resultat ansehen.

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


Lesenswert?

Gustl B. schrieb:
> Was wird denn gebaut wenn man
> SPI_DATA_H <= r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL)/256
> SPI_DATA_L <= r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL)%256
> schreibt?
In erster Näherung eine Fehlermeldung wegen der nicht passenden 
Datentypen.

Und praktisch wird das mit hoher Wahrscheinlichkeit einfach wie oben 
verdrahtet. Und das obwohl die Division für negative Zahlen (also der 
Hälfte des Zahlenbereichs des Integers und damit ein Viertel der 
Integerzahlen) dann eigentlich falsch rundet.
Denn: was gibt bei Integer-Rechnung 5/2 und was gibt -5/2?
Richtig: 2 und -2 wegen des Abschneidens der Nachkommastellen.
Und was kommt bei der simplen Umverdrahtung statt -5/2 heraus?
Das ergibt -3!
1
bin   dez    /2     umverdrahtet ohne letztes Bit (=shift 1 nach rechts)
2
                    bin    dez
3
0111   7      3     011    3
4
0110   6      3     011    3
5
0101   5      2     010    2
6
0100   4      2     010    2
7
0011   3      1     001    1
8
0010   2      1     001    1
9
0001   1      0     000    0
10
0000   0      0     000    0
11
1111  -1      0     111   -1     ***
12
1110  -2     -1     111   -1
13
1101  -3     -1     110   -2     ***
14
1100  -4     -2     110   -2
15
1011  -5     -2     101   -3     ***
16
1010  -6     -3     101   -3
17
1001  -7     -3     100   -4     ***
18
1000  -8     -4     100   -4
In den *** Zeilen passt das Ergebnis der mathematisch korrekten 
Integer-Division nicht zur simplen "umverdrahteten" (oder eben 
"geshifteten") Version. Trotzdem ersetzt der Synthesizer die 
mathematisch korrekte Division (wenn Zahl negativ, dann mach eine 
posizive Zahl daraus, teile die durch 2 und mach wieder eine negative 
Zahl daraus) mit hoher Wahrscheinlichkeit durch die Umverdrahtung.

Ausprobieren macht hier schlau. Und man lernt daraus, dass man solches 
Mapping besser direkt macht, als es irgendwelchen mathematischen 
Operationen zuzumuten und sich drauf zu verlassen, dass die das schon so 
können wie man es braucht.

: Bearbeitet durch Moderator
von Gustl B. (-gb-)


Lesenswert?

Lothar M. schrieb:
> negative Zahlen

Holger K. schrieb:
> r_MemSegmentValue()() ist ein integer range 0 to 65535;

Lothar M. schrieb:
> Und man lernt daraus, dass man solches
> Mapping besser direkt macht, als es irgendwelchen mathematischen
> Operationen zuzumuten und sich drauf zu verlassen, dass die das schon so
> können wie man es braucht.

Ja, stimmt. Wobei ich finde, dass man solche Sachen schon machen darf 
wenn man verstanden hat was dabei passiert.

von FPGAzumSpass (Gast)


Lesenswert?

Ich benutze das auch, gerade in Situationen wo alles außer 
Integer-Rechnung nervig wird.

Beispiel:
1
signal x_div            : integer range 1 to 2;
2
variable pixeladdr      : integer range 0 to 524287;
3
4
pixeladdr := pixeladdr_base + (x_flip_offset - ((x_scrolled mod 8) / x_div));
5
if (hicolor = '0') then
6
   pixeladdr := pixeladdr + ((7 - (y_scrolled mod 8)) * 4);
7
else
8
   pixeladdr := pixeladdr + ((7 - (y_scrolled mod 8)) * 8);
9
end if;

Wie man sieht klappt es nicht nur mit "mod" die unteren Bits raus zu 
ziehen, sondern sogar die Division über ein Signal(x_div) zu einem 
conditional Shift zu machen, wenn der Wertebereich so eingegrenzt ist. 
(Quartus 18.1)

Mit dem Cyclone 4 konnte man sogar noch das *4 und *8 in einem signal 
zuweisen und damit das If contruct sparen:
1
signal hicolormul: integer range 4 to 8;
2
3
if (hicolor = '0') then
4
   hicolormul <= 4;
5
else
6
   hicolormul <= 8;
7
end if;
8
9
pixeladdr := pixeladdr + ((7 - (y_scrolled mod 8)) * hicolormul);

Mit dem Cyclone 4 führt das zu einem conditional Shift, mit dem Cyclone 
5 leider zu einem echten MUL (DSP Element), warum auch immer die 
Synthese sowas macht.

von S. R. (svenska)


Lesenswert?

Gustl B. schrieb:
> Ja, stimmt. Wobei ich finde, dass man solche Sachen schon
> machen darf wenn man verstanden hat was dabei passiert.

Und wenn man einigermaßen sicher sein kann, dass andere Nutzer des 
Quellcodes das auch verstanden haben. Das ist je nach Umfeld 
schwieriger.

von Gustl B. (-gb-)


Lesenswert?

Andere Menschen machen Dinge fast meistens schwieriger.

von Christoph Z. (christophz)


Lesenswert?

Tobias B. schrieb:
> Alte Informatik Regel: Sobald ich einmal Copy&Paste mache, gibt es
> mindestens eine Loesung die besser waere. ;-)

Gleich mal rüberkopiert:
Beitrag "Programmierer-Sprüche"

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.