Forum: FPGA, VHDL & Co. Modulofunktion


von Steven H. (mme365)


Lesenswert?

Guten Abend Community

Ich suche für ein kleiners Projekt, einen fertigen Modulo-Algorithmus ( 
x mod 7) für unsigned Variablen mit max. 8 bit.

vielleicht hat ja jemand sowas schon mal geschrieben und würde es mit 
mir Teilen?

Gruß Steven

von Cakaes (Gast)


Lesenswert?

Welche Sprache/Controller?


1
m = x % 7;

von Steven H. (mme365)


Lesenswert?

VHDL (ISE)

: Bearbeitet durch User
von Burkhard K. (buks)


Lesenswert?

Steven H. schrieb:
> VHDL (ISE)

Siehe z.B. https://www.csee.umbc.edu/portal/help/VHDL/operator.html. 
Unsigned nach Integer casten, Modulo berechnen und dann mit 
to_unsigned() zurückwandeln.

von Steven H. (mme365)


Lesenswert?

Ganz so einfach, das man einfach den Typ wechselt, ist es leider nicht.
Das Maximum für die Mod-Berechnung in VHDL (ISE) liegt leider bei 2 
sprich ( x mod 2)
Sprich man braucht einen Divisionsalgorithmus + die Ausgabe des Restes

von Yalu X. (yalu) (Moderator)


Lesenswert?

Gesucht ist:
1
  y₂y₁y₀ =  x₇x₆x₅x₄x₃x₂x₁x₀ mod 7

Das kann nach folgendem Schema ohne Division berechnet werden:

1
a₃a₂a₁a₀ = x₅x₄x₃ + x₂x₁x₀
2
3
  b₂b₁b₀ =   x₇x₆ +     a₃
4
5
c₃c₂c₁c₀ = a₂a₁a₀ + b₂b₁b₀
6
7
  d₂d₁d₀ =     c₃ + c₂c₁c₀
8
9
           ⎧ 0 0 0   falls d₂=d₁=d₀=1
10
  y₂y₁y₀ = ⎨
11
           ⎩ d₂d₁d₀  sonst

Da ich kein VHDL kann, darfst du den Rest selber erledigen :)

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


Lesenswert?

Steven H. schrieb:
> Ganz so einfach, das man einfach den Typ wechselt, ist es leider nicht.
> Das Maximum für die Mod-Berechnung in VHDL (ISE) liegt leider bei 2
> sprich ( x mod 2)
Mitnichten. Wenn man %7 hinschreibt und alles in 1 Takt erledigt haben 
will, dann macht der Synthesizer einen kombinatorischen Divider.
Siehe z.B. den Beitrag "Re: Rechnen mit unsigned vs. signed und einer division"

> Sprich man braucht einen Divisionsalgorithmus + die Ausgabe des Restes
Man kann auch "hinreichend genau" auf eine Multiplikation mit 
anschließendem "Abschneiden" (aka Division duch Zweierpotenz) 
ausweichen:
mod7 <= x-7*((x*9362)/65536);

Der Trick dabei 9362/65536 = 1/7,000213

: Bearbeitet durch Moderator
von Burkhard K. (buks)


Lesenswert?

Steven H. schrieb:
> Das Maximum für die Mod-Berechnung in VHDL (ISE) liegt leider bei 2
> sprich ( x mod 2)

Etwas mehr geht schon, tatsächlich kann der XST für Series 7 u.a.:
  rem - Supported if the right operand is a constant power of 2
  mod - Supported if the right operand is a constant power of 2

https://www.xilinx.com/support/documentation/sw_manuals/xilinx14_7/xst_v6s6.pdf:

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


Lesenswert?

Burkhard K. schrieb:
> Etwas mehr geht schon, tatsächlich kann der XST für Series 7 u.a.:
>   rem - Supported if the right operand is a constant power of 2
>   mod - Supported if the right operand is a constant power of 2
Das geht schon immer. Es ist ja nur ein "Weglassen" der unteren Bits.
Im Prinzip funktioniert das aber nur bei Unsigned Vektoren korrekt...

von VHDL hotline (Gast)


Lesenswert?

Für 8 bit, sprich 256 Werte, kann man die vorberechneten Werte einfach 
in einem Speicher hinterlegen, den man mit dem Wert selbst addressiert.

von Hagen R. (hagen)


Lesenswert?

@Yalu: geht dein beschriebener Trick so zu generalisieren?
1
y = x mod (2^k-1)
2
3
wiederhole 
4
  x = (x / 2^k) + (x and (2^k-1))
5
solange bis x <= (2^k-1)
6
7
wenn x = (2^k-1) dann y = 0 ansonsten y = x.

Wobei natürlich die Division von x / 2^k ein simpler rechts Shift ist.

Kennst du noch andere solche Tricks, zb. modulo (x^y +- z)

Gruß hagen

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hagen R. schrieb:
> @Yalu: geht dein beschriebener Trick so zu generalisieren?
> y = x mod (2^k-1)
>
> wiederhole
>   x = (x / 2^k) + (x and (2^k-1))
> solange bis x <= (2^k-1)
>
> wenn x = (2^k-1) dann y = 0 ansonsten y = x.

Ja, genau.

Genauso wie der Neunerrest im Dezimalsystem über die Quersumme berechnet
werden kann (https://de.wikipedia.org/wiki/Neunerrest), ist dies für den
Siebenerrest im Oktalsystem oder allgemein für den Rest modulo n-1 im
Stellenwertsystem zur Basis n möglich. Man macht sich dabei zunutze,
dass

  n^i mod (n-1) = 1  für alle i ∈ ℕ

Ist n eine Zweierpotenz (n=2^k), dann wird die Zerlegung einer im
Binärsystem gegebenen Zahl in Ziffern besonders einfach, da dann jede
Ziffer einer Gruppe von k Bits entspricht. Man kann damit leicht die
Reste modulo 3, 7, 15 usw. berechnen.

Den Algorithmus für das Ganze hast du ja oben in sehr eleganter Form
hingeschrieben.

> Wobei natürlich die Division von x / 2^k ein simpler rechts Shift ist.

Auf dem FPGA muss nicht einmal unbedingt geshiftet werden. Da die Anzahl
der benötigten Additionen bei gegebener Bitbreite der zu bearbeitenden
Zahl nach oben beschränkt ist, kann die Berechnung rein kombinatorisch
(also ohne Flipflops) erfolgen.

> Kennst du noch andere solche Tricks, zb. modulo (x^y +- z)

Modulo n+1 in der Basis n geht auch relativ leicht, nämlich über die
alternierende Quersumme. Damit können mit einem ähnlichen Verfahren die
Reste modulo 2^k+1 (5, 9, 17 usw.) berechnet werden. Hier macht man sich
zunutze, dass

  n^i mod (n+1) = (-1)^i  für alle i ∈ ℕ

Möglicherweise wird die Umsetzung für ein FPGA wegen der negativen
Zwischenergebnisse etwas kniffliger.

von Hagen R. (hagen)


Lesenswert?

Danke Yalu

von J. S. (engineer) Benutzerseite


Lesenswert?

Yalu X. schrieb:

> Möglicherweise wird die Umsetzung für ein FPGA wegen der negativen
> Zwischenergebnisse etwas kniffliger.
Nicht unbedingt, man müsste sie nach meinem Verständnis als unsigned 
halten können, um bei den Berechnungen nicht schief zu laufen, weil sie 
"restklassenmäßig" dann stimmen müssten.

von Markus F. (mfro)


Lesenswert?

Lothar M. schrieb:
> Man kann auch "hinreichend genau" auf eine Multiplikation mit
> anschließendem "Abschneiden" (aka Division duch Zweierpotenz)
> ausweichen:
> mod7 <= x-7*((x*9362)/65536);
>
> Der Trick dabei 9362/65536 = 1/7,000213

Auch das lässt sich generalisieren: 
https://homepage.divms.uiowa.edu/~jones/bcd/divide.html (oder, wenn man 
lieber Bücher liest, "Hacker's Delight, 2nd Edition"): Multiplikationen 
mit dem binären Kehrwert, die man anschliessend in Shifts und Additionen 
zerlegt:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
entity tb2 is
6
end tb2;
7
8
architecture rtl of tb2 is
9
begin
10
    p_initial : process
11
        variable n      : unsigned(7 downto 0);
12
        variable u_div  : unsigned(7 downto 0);
13
        variable u_mod  : unsigned(7 downto 0);
14
    begin
15
        for i in 0 to 255 loop
16
            n := to_unsigned(i, 8);
17
            u_div := shift_right(n, 1) + shift_right(n, 4);    
18
            u_div := shift_right(u_div + shift_right(u_div, 6), 2);
19
            u_mod := n - (shift_left(u_div, 3) - u_div);
20
            u_div := u_div + shift_right(u_mod + 1, 3);
21
            if u_mod > 6 then
22
                u_mod := u_mod - 7;
23
            end if;
24
            report "i = " & integer'image(i) & " div 7 = " & integer'image(to_integer(u_div)) & "," &
25
                                               " mod 7 = " & integer'image(to_integer(u_mod)) severity note;
26
        end loop;
27
        wait;
28
    end process p_initial;
29
end architecture rtl;

u_div ist der Quotient und u_mod der Rest. Der bei der angenäherten 
Division entstehende Fehler lässt sich leicht korrigieren.

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


Lesenswert?

Markus F. schrieb:
> Multiplikationen mit dem binären Kehrwert, die man anschliessend in
> Shifts und Additionen zerlegt
Es stimmt natürlich, dass man Multiplikationen durch Additionen und 
Subtraktionen von Zweierpotenzen ersetzen kann. Aber wenn noch ein 
Multipizierer übrig ist (und das ist er typischerweise bei denen, die 
solche Fragen stellen... ;-) dann muss man die Multiplikation nicht 
weiter optimieren.

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.