Forum: FPGA, VHDL & Co. Division von 2 Vektoren


von Alex I. (sanyagerua)


Lesenswert?

Hallo zusammen!
Ich brauche 2 Vektoren miteinander zu dividieren. Dazu habe ich ein 
kleines Programm geschrieben, das zwei std_logic_vectoren mit der Längen 
10 miteinander dividiert. Leider funktioniert das nicht:( Ich denke, 
dass es an die unterschiedlichen Dauer der Instruktionen liegt. So die 
Werte, die durch Verschiebung entstehen können möglicherweise erts in 
der nächsten Clock fertig sein, so dass die for-schleife mit falschen 
Werten arbeitet. Vielleicht kann man  irgendwie eine Verzögerung 
überlegen, befor man in die for- Schleife kommt. Und darf ich überhaupt 
in diesem Fall die for- Schleife benutzen??? Bin für jede Hilfe dankbar! 
Hier ist mein Programm und Testbench.


library STD;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity VectorDivision is
Port(Clock   : in std_logic;
     VectorA : in std_logic_vector(9 downto 0);
     VectorB : in std_logic_vector(9 downto 0);
    Ergebnis:out std_logic_vector(9 downto 0);
    Rest    :out std_logic_vector(9 downto 0));
end VectorDivision;

architecture Behavioral of VectorDivision is

signal Nullen: std_logic_vector(8 downto 0):=(others=>'0');
signal tempA:  std_logic_vector(18 downto 0);
signal tempB:  std_logic_vector(27 downto 0);
signal tempC:  std_logic_vector(18 downto 0);
signal y:      std_logic_vector(9 downto 0);
begin

Process (Clock)
begin
if rising_edge(Clock) then
 tempA <=Nullen & VectorA;--Erweiterung mit Nullen, damit beim Vergleich
 tempB <=Nullen & VectorB & Nullen;   -- die Laengen uebereinstimmen

 for i in 9 downto 0 loop
   tempC <= tempB(27-i downto 9-i);
   if tempA >= tempC then   -- Vector A mit Vector B*2**i vergleichen
      y(i)<= '1';           --A groesser als B*2**i wird i-Bit gesetzt
      tempA <= tempA-tempC; --und B*2**i wird von A abgezogen
   else
       y(i) <=  '0';
    end if;
 end loop;

   Rest <= tempA(9 downto 0);
   Ergebnis <= y;
 end if;
end process;
end Behavioral;



library STD;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY TB_VecortDivision IS
END TB_VecortDivision;

ARCHITECTURE behavior OF TB_VecortDivision IS

    COMPONENT VectorDivision
    PORT(
         Clock : IN  std_logic;
         VectorA : IN  std_logic_vector(9 downto 0);
         VectorB : IN  std_logic_vector(9 downto 0);
         Ergebnis : OUT  std_logic_vector(9 downto 0);
         Rest : OUT  std_logic_vector(9 downto 0)
        );
    END COMPONENT;

signal Clock : std_logic := '0';
signal VectorA : std_logic_vector(9 downto 0) := "1111101000"; --1000 
dec
signal VectorB : std_logic_vector(9 downto 0) := "0000010100"; --  20 
dec
signal Ergebnis: std_logic_vector(9 downto 0);
signal Rest    : std_logic_vector(9 downto 0);
constant ClockPeriod: time:= 6.666 ns;

BEGIN

   uut: VectorDivision PORT MAP (
          Clock => Clock,
          VectorA => VectorA,
          VectorB => VectorB,
          Ergebnis => Ergebnis,
          Rest => Rest
        );

   ClockProcess :process
   begin
    Clock <= '1';
    wait for ClockPeriod;
    Clock <= '0';
    wait for ClockPeriod;
   end process;

END;

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Signale erhalten ihren neuen Wert erst dann, wenn der Prozess zum 
nächsten Mal ausgeführt wird. Wenn du Variablen anstatt von Signalen 
verwenden würdest, dann könnte dein Programm zumindest im Simulator 
funktionieren. Für die Synthese ist der Ansatz aber komplett falsch; 
wiederholte Ausführung mit Schleifen gibt es da nicht, das muss man von 
Hand mit einem Zustandsautomaten machen. Am besten schaust du dir noch 
mal ein paar einfachere VHDL-Beispiele an, und liest nach wie die 
einzelnen Konstrukte (Variablen, Signale, Schleifen) funktionieren. Da 
fehlen noch ein paar Grundlagen bevor du dich an einen Dividierer wagen 
kannst.

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


Lesenswert?

> Ich denke, dass es an die unterschiedlichen Dauer der Instruktionen liegt.
Diese Denkweise ist grundlegend falsch.  :-o
Deine VHDL-Beschreibung wird parallel in Hardware umgesetzt, und mit 
jedem Takt einmal komplett ausgeführt. Wenn da ein langsamer 
Kombinatorikpfad drin ist, dann sagt dir das das Synthesetool.

Vergiss für den Anfang das Schlüsselwort loop. Eine Schleife in VHDL 
beschreibt nicht etwas, das nacheinander x-mal ausgeführt wird, 
sondern etwas, das x-mal gleichzeitig auf das FPGA abgebildet wird.

Und vor allem: wenn du irgendwas simulieren kannst, dann heißt das noch 
lange nicht, dass du es auch auf Hardware synthetisiert bekommst...


BTW:
Beitrag "Re: Funktionsplan in VHDL übersetzen"

von Alex I. (sanyagerua)


Lesenswert?

Erstmal danke für eure Anweisungen! Ich habe jetzt versucht das ganze 
als einen Zustandsautomat zu machen. Das Ergebnis  im Vergleich zum 
richtigen wird um ein bit nach nach hinten verschoben. Und das wird 
erstmal wenn z zweimal komplett durchgelaufen wird. Hat jemand eine Idee 
woran es liegen kann?

entity VectorDivision is
Port(Clock   : in std_logic;
     VectorA : in std_logic_vector(9 downto 0);
     VectorB : in std_logic_vector(9 downto 0);
     Ergebnis:out std_logic_vector(9 downto 0);
     Rest    :out std_logic_vector(9 downto 0));
end VectorDivision;

architecture Behavioral of VectorDivision is

signal Nullen: std_logic_vector(8 downto 0):=(others=>'0');
signal tempA:  std_logic_vector(18 downto 0);
signal tempB:  std_logic_vector(18 downto 0);
signal tempC:  std_logic_vector(27 downto 0);
signal y:      std_logic_vector(9 downto 0);
signal z,zplus :integer:=9;

begin

Process (Clock)
 begin
   if rising_edge(Clock) then
      z <= zplus;
      if z=9 then
         tempA <= Nullen & VectorA;
         tempC <= Nullen & VectorB & Nullen;
      end if;

      tempB <= tempC(27-z downto 9-z);

      if tempA >= tempB then
         y(z)  <= '1';
         tempA <= tempA - tempB;
      else
          y(z)<='0';
      end if;

    end if;
   end process;

 Process(z)
  begin
    case z is
     when 0=>  zplus <= 9; Rest <= tempA(9 downto 0);Ergebnis<=y;
     when others => zplus <= z-1;
   end case;
 end process;

end Behavioral;

von Alex I. (sanyagerua)


Lesenswert?

So wird das Ergebniss rechtzeitig berechnet, aber trotzdem um ein Bit 
verschoben

Process(z)
begin
 case z is
  when 0      =>  zplus <= 9;
  when 9      =>  zplus <= z-1; Rest <=tempA(9 downto 0); Ergebnis<=y;
  when others =>  zplus <= z-1;
 end case;
end process;

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


Lesenswert?

Du bemerkst das in der Simulation, richtig?

Übliche Ursache für eigenartiges Verhalten in der simulation: die 
Sensitivliste eines kombinatorischen Prozesses ist unvollständig.
1
Process(z)
Hier gehört das temA und y auch mit rein, denn beim Zustand 9 hängt das 
Ergebnis auch von diesen beiden Werten ab:
1
Process(z, tempa, y) 
2
begin
3
 case z is
4
  when 0      =>  zplus <= 9;
5
  when 9      =>  zplus <= z-1; Rest <=tempA(9 downto 0); Ergebnis<=y;
6
  when others =>  zplus <= z-1;
7
 end case;
8
end process;

von Alex I. (sanyagerua)


Lesenswert?

Ja genau, das stelle ich durch die Simulation fest! Die Erweiterung der 
Sensitivliste hat leider nichts gebracht. Zusätzlich bei der Division 
mit Rest (z.B. 1000 durch 3) ergibt sich  das falsche Ergebnis, das sich 
ständig je 10. Takt zwischen 166dec(0010100110 ist eigentlich 333dec um 
ein bit nach rechts verschoben) und 512dec(1000000000)  wechselt.

Wenn ich mein Code von Hand  durchgehe dann soll alles stimmen, aber in 
der Realität.... Ich habe kein Plan:(

von D. I. (Gast)


Lesenswert?

Nimm doch den Divider von Lothar's Miller Seite oder den vom Coregen

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.