mikrocontroller.net

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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Holger K. (holgerkraehe)


Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen

Aktuell versuche ich wie folgt, aus einem integer zwei einzelne Bytes zu 
formen:
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));

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. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Holger K. schrieb:
> Aber geht das evtl eleganter?
Man könnte es als Grund ansehen, eine Variable einzusetzen(*)... ;-)
variable spitxdata : std_logic_vector (15 downto 0);

-- Umwandlung
spitxdata := std_logic_vector(to_unsigned(r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL), 16));
-- Zuweisung
SPI_DATA_H <= spitxdata(15 downto 8);
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)


Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
>
>
> variable spitxdata : std_logic_vector (15 downto 0);
> 
> -- Umwandlung
> spitxdata := std_logic_vector(to_unsigned(r_MemSegmentValue(SPI_TX_ROW)(SPI_TX_COL), 16));
> -- Zuweisung
> SPI_DATA_H <= spitxdata(15 downto 8);
> SPI_DATA_L <= spitxdata( 7 downto 0);
> 

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.
    signal spitxdata  : std_logic_vector(15 downto 0);
    alias spi_data_low is spitxdata(7 downto 0);
    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)


Bewertung
-1 lesenswert
nicht lesenswert
schon mal an sowas gedacht

typedef union

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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-)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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!
bin   dez    /2     umverdrahtet ohne letztes Bit (=shift 1 nach rechts)
                    bin    dez
0111   7      3     011    3
0110   6      3     011    3
0101   5      2     010    2
0100   4      2     010    2
0011   3      1     001    1
0010   2      1     001    1
0001   1      0     000    0
0000   0      0     000    0
1111  -1      0     111   -1     ***
1110  -2     -1     111   -1
1101  -3     -1     110   -2     ***
1100  -4     -2     110   -2
1011  -5     -2     101   -3     ***
1010  -6     -3     101   -3
1001  -7     -3     100   -4     ***
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-)


Bewertung
0 lesenswert
nicht 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)


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

Beispiel:
signal x_div            : integer range 1 to 2;
variable pixeladdr      : integer range 0 to 524287;

pixeladdr := pixeladdr_base + (x_flip_offset - ((x_scrolled mod 8) / x_div));
if (hicolor = '0') then
   pixeladdr := pixeladdr + ((7 - (y_scrolled mod 8)) * 4);
else
   pixeladdr := pixeladdr + ((7 - (y_scrolled mod 8)) * 8);
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:
signal hicolormul: integer range 4 to 8;

if (hicolor = '0') then
   hicolormul <= 4;
else
   hicolormul <= 8;
end if;

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)


Bewertung
0 lesenswert
nicht 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-)


Bewertung
0 lesenswert
nicht lesenswert
Andere Menschen machen Dinge fast meistens schwieriger.

von Christoph Z. (christophz)


Bewertung
0 lesenswert
nicht 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"

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.