Forum: FPGA, VHDL & Co. Multiplitierer in VHDL


von ingo (Gast)


Lesenswert?

Hallo liebe Leute,ich muss hier ein multiplitierer programmieren denn 
den wert von A*B in shift speicher und die an der ausgang result 
ubergeben soll.Das problem ist ubergebende wert muss nicht große und 
nicht kleiner als limit.ich hatte gedacht mit schieben von bit kann ich 
etwas erreichen aber es schien mein idee nicht so gut gewesen zu 
sein.Hat jemand  eine idee oder ist meine idee gut und ic kann es nicht 
umsetzen.ich danke euch.was ich gemacht habe ist hier unten.
entity Mul is
port ( clk       :in std_logic;
       reset_n    :in std_logic;
       A            :in std_logic_vector(15 downto 0);
       B            :in std_logic_vector(15 downto 0);
       limit        :in std_logic_vector(15 downto 0);
       result       :out std_logic_vector(15 downto 0)
       );
end Mul;
architecture verh of Mul is
signal shift        :std_logic_vector(15 downto 0);
 begin
  process(clk,reset_n)
    begin
    if reset_n = '0' then
    --  A <= x"0";
      --B <= x"0";
       elsif clk='1' and clk'event then
      shift <= A * B ;
       if shift >= limit then
      shift<= '0' & limit(14 downto 0);
       elsif shift <= limit then
      shift<= limit(15 downto 1) & '1';
    end if;
  end if;
    end process;
 result<= shift;
end verh;

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


Lesenswert?

> wert muss nicht große und nicht kleiner als limit.
Dann muß er gleich sein  :-o

Das Ergebnis einers Multipliziers ist genaus breit wie die beiden 
Eingangswerte zusammen.

Ein Multiplizierer ist ein kombinatorisches Bauwerk.
Dashalb brauchst du keinen Takt und keinen Reset und kannst für die 
Multiplikation ganz einfach schreiben:
1
:
2
use IEEE.numeric_std.all
3
:
4
entity Mul is
5
port ( A            :in std_logic_vector(15 downto 0);
6
       B            :in std_logic_vector(15 downto 0);
7
       result       :out std_logic_vector(31 downto 0) --- Breite!!!
8
       );
9
end Mul;
10
11
architecture verh of Mul is
12
begin
13
 result <= std_logic_vector(unsigned(A) * unsigned(B));
14
end verh;

von Der Besucher (Gast)


Lesenswert?

Wenn ingo 16 Takte Zeit hat für die Berechnung, kann man einen schönen 
einfachen Multiplizierer basteln, der erheblich kleiner ist als das 
vorgeschlagene (schnelle) kombinatorische Konstrukt.

von befro (Gast)


Lesenswert?

>Ein Multiplizierer ist ein kombinatorisches Bauwerk.
Das hängt davon ab, wieviele Resourcen man verbraten will. Einen 
Multiplizierer mit getakteter Struktur braucht zwar mehr Rechenzeit, 
dafür aber weniger Gatter.

von Matthias G. (mgottke)


Lesenswert?

Je nach dem auf welcher Zielhardware man hat, kann ev. auch ein 
integrierter Hardwaremultiplizierer verwendet werden.

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


Lesenswert?

Ich sehe das so:
Wenn ich ein FPGA mit einem übrigen Multiplizierer habe, dann habe ich 
sogar noch Ressourcen besser ausgenutzt, wenn ich diesen verwende. Und 
wenn kein Multiplizierer mehr übrig ist, dann muß ich einen der anderen 
multiplexen. Dann bin ich in einem Takt fertig...

Ja, und wenn ich keinen Multiplizierer habe, dann mache ich das 
logischerweise auch nicht kombinatorisch (wobei es auf die Wortbreite 
ankommt). Aber die meisten meinen eben, ein Mutliplizierer müsse 
getaktet sein.

von Der Besucher (Gast)


Lesenswert?

Wer meint denn das?

von Ingo (Gast)


Lesenswert?

Danke für euere hilfe.Aber lothar ich muss den ausgang an einer eingang 
von FPGA mikroprocesseur mit 16 bit verbinden deswegen ist es unmöglich 
meine ausgang mit 32 bits zu machen.mit den clk und reset ist klar.Und 
limit ist normaleweise da um den wert von A*B aus die herausgegeben 
werden soll nicht mehr als und nicht weniger als 16 bits ist.
Danke

von John-eric K. (mockup)


Lesenswert?

du kannst die Daten doch nacheinander einlesen.
erst die höheren 16bit
und danach die unteren 16. (oder andersherum)

wie wäre es damit(nicht getestet)

entity Mul is
port ( clk          :in std_logic;
       reset_n      :in std_logic;
       A            :in std_logic_vector(15 downto 0);
       B            :in std_logic_vector(15 downto 0);
       limit        :in std_logic_vector(15 downto 0);
       result       :out std_logic_vector(15 downto 0)
       );
end Mul;
architecture verh of Mul is
signal shift        :std_logic_vector(32 downto 0);
 begin
  process(clk)
    begin
     if rising_edge(clk) then
      shift <= A * B;
       if shift >= ("0000" & limit) then
      shift(15 downto 0) <= '0' & limit(14 downto 0);
       elsif shift <= ("0000" & limit) then
      shift(15 downto 0)<= limit(15 downto 1) & '1';
    end if;
  end if;
    end process;
 result<= shift(15 downto 0);
end verh;

jetzt kannste ganz normal berechnen und wenn der wert über/unter deiner 
limit variable liegt, wird sie geändert.

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Hallo Ingo,

Du darfst nicht innerhalb eines Prozesses einem Signal zweimal einen 
Wert zuweisen ohne die Zuweisungen zu priorisieren. In deinem Fall 
erfolgen

shift <= A * B ;
und eine der Zuweisungen gleichzeitig.
  shift<= '0' & limit(14 downto 0);
  shift<= limit(15 downto 1) & '1';
Welche Tatsächlich ausgeführt wird hängt von der Code-Optimierung sowohl 
im Simulator als auch in der Synthese ab. Das führt zu frustierenden 
Ergebnissen.

Bei dem Fall treten auch keine multiplen Treiber auf, d.h. elektrisch 
ist es richtig nur nicht logisch.

Versuche mal folgendes

prod <= A * B;
if prod >= ("0000" & limit) then
  shift(15 downto 0) <= '0' & limit(14 downto 0);
elsif prod < ("0000" & limit) then -- kein <= da = schon im if; Warum
                                   -- überhaupt ein elsif?
  shift(15 downto 0)<= limit(15 downto 1) & '1';
end if;

Tom

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


Lesenswert?

> Welche Tatsächlich ausgeführt wird hängt von der Code-Optimierung sowohl
> im Simulator als auch in der Synthese ab.
Nein, in einem Prozess wird die letze ausgeführte Zuweisung an ein 
Signal ausgeführt. Das bedeutet hier allerdings, dass shift mit einem 
Takt Latency daherkommt.

Offenbar sollte das
> signal shift        :std_logic_vector(32 downto 0);
eine Variable sein.
Denn dann wird erst die Multiplikation ausgeführt, danach das Ergebnis 
der Multiplikation zur weiteren Verarbeitung verwendet.

von Ingo (Gast)


Lesenswert?

Hallo zusammen,
 ich habe alles möglich probiert. den code compliliert richtig aber wenn 
ich das uber nios 2 aufruf wird keine multiplcatin ausgeführt.Wie kann 
ich dass verändert?
danke euch

von Ingo (Gast)


Lesenswert?

ich habe noch probiert und bekomme nur den wert von limit raus ? und es 
sollte nicht sein.Bitte kann mir jemand helfen

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


Lesenswert?

> Bitte kann mir jemand helfen
Zeig doch mal deinen Code.

von ingo (Gast)


Lesenswert?

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;
USE IEEE.std_logic_signed.ALL;
entity Mul is
port ( clk       :in std_logic;
       reset_n    :in std_logic;
       A            :in std_logic_vector(15 downto 0);
       B            :in std_logic_vector(15 downto 0);
       limit        :in std_logic_vector(15 downto 0);
       result       :out std_logic_vector(15 downto 0)
       );
end Mul;
architecture verh of Mul is
signal shift        :std_logic_vector(31 downto 0);
 begin
  process(clk,reset_n)
    begin
    if reset_n = '0' then
      elsif clk='1' and clk'event then
      shift <= A * B ;
      if shift >=("0000" & limit) then
        shift(15 downto 0) <=  limit(15 downto 0);
      elsif shift < ("0000" & limit)  then
        shift(15 downto 0) <= limit (15 downto 0) ;
      end if;
      result <= shift(15 downto 0);
    end if;
end process;
end verh;

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


Lesenswert?

> aber wenn ich das uber nios 2 aufruf wird keine multiplcatin ausgeführt.
Du wartest in deinem NIOS-Code aber schon, bis die Multiplikation fertig 
ist?

Hast du die vorhergehenden Posts gelesen?
Ich zitiere mich selbst ungern, aber:
> Offenbar sollte das
>> signal shift        :std_logic_vector(32 downto 0);
> eine Variable sein.
> Denn dann wird erst die Multiplikation ausgeführt, danach das Ergebnis
> der Multiplikation zur weiteren Verarbeitung verwendet.

EDIT:
Noch ein Zitat
>>> wert muss nicht große und nicht kleiner als limit.
>> Dann muß er gleich sein  :-o
Und genau das macht die Abfrage in deinem Code (ja, ich weiß dass du den 
"nur" kopiert hast; das entschuldigt dich aber nicht). Denn das:
1
      if shift >=("0000" & limit) then      -- wenn größer oder gleich
2
        shift(15 downto 0) <=  limit(15 downto 0);
3
      elsif shift < ("0000" & limit)  then  -- wenn kleiner
4
        shift(15 downto 0) <= limit (15 downto 0) ;
5
      end if;
könnte auch so geschrieben werden:
1
      if ( shift>=("0000"&limit) or   shift<("0000"&limit) )then      -- wenn größer oder gleich oder kleiner
2
        shift(15 downto 0) <=  limit(15 downto 0);
3
      end if;
oder wesentlich kompakter:
1
        shift(15 downto 0) <=  limit(15 downto 0);
Und genau das erhältst du.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Vor allem was soll das bringen? Der NIOS-II hat doch die Option einen 
Hardwaremultiplizierer (sogar 32 bit) anzubinden...
Und wenns per hand sein soll/muß würd ich da auch eher das 
CustomInstruction Interface vorschlagen.

von m.rose (Gast)


Lesenswert?

Der obige Quelltext kann nicht funktionieren, weil die Signalzuweisung 
nur EINMAL erfolgt, und zwar wenn der Simulator den Prozess verläßt.

Aber das läßt sich sehr einfach lösen, indem du im Prozess mit Variablen 
arbeitest. Variablen werden SOFORT zugewiesen, nachdem die betreffende 
Anweisung gelesen wurde.

Am Ende, d.h. direkt vor der Anweisung "end ...", weist du dann dem 
Signal die Variable einmalig zu, und alles ist paletti.

SIGNAL sig: typ;
VARIABLE var : typ; -- gleicher typ wie sig!


PROCESS (clk)

   IF (clk'EVENT AND clk=1) THEN

       -- 1) Signal an Variable übergeben:

          var := sig;

       -- 2) mit Variable rechnen, etwa wie folgt:

          var := var +1;
          IF var = 10 THEN var:=0;

       -- 3) das ergebnis einmalig dem signal zuweisen:

          sig <= var;

   END IF;

END PROCESS;

von Klaus (Gast)


Lesenswert?

Ähm, Mr. m.rose (Gast), ich finds gut, dass du hier Zeit investieren 
möchtest, um anderen Leuten zu helfen. Aber ob die Leute wirklich 
jahrelang auf eine Antwort gewartet haben, wage ich zu bezweifeln ;-)

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.