Multiplitierer in VHDL

Gast #1190925
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;
Moderator (Firma: Titel) Persönliche Seite #1190945
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;
Gast #1190990
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.
Gast #1190995
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.
Moderator (Firma: Titel) Persönliche Seite #1191195
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.
Gast #1191650
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
#1191685
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.
(Firma: abaxor engineering) #1192001
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
Moderator (Firma: Titel) Persönliche Seite #1192040
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.
Gast #1196036
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;
Moderator (Firma: Titel) Persönliche Seite #1196051
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.
Gast #2037455
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;
Gast #2037467
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 ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren