VHDL-Projekt III/37 - Gruppe 4
|
Benutzung des Multiplikationsbausteins
Quellcode der Schaltung
Testumgebung
Testbench
Top Entity
Testablauf
Schaltbild
Erkenntnisse
-
Navigation: Projekthauptseite
Benutzung des Multiplikationsbausteins
|
An den Multiplikationsbausteins müssen an den beiden 8-Bit-Eingängen in_data_1 und
in_data_2 die beiden Faktoren der Multiplikation angelegt werden. Das Einlesen der
Werte und der Start der Berechnung wird über den load Eingang gesteuert, indem man
ihn auf '1' setzt.
Die Multiplikation ist abgeschlossen, wenn ready='1' ist. Dann kann das Ergebnis der
Multiplikation über den 16-Bit Ausgang out_data gelesen werden.
Während der Berechnung ist ready='0' und an out_data liegt der Wert 0 an.
Neue Werte werden erst eingelesen, wenn ready='1' ist.
Die Schaltung kann vereinfacht als Kasten folgender Gestalt angesehen werden:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY synth;
USE synth.vhdlsynth.all;
ENTITY multiplier IS
PORT (
clk : IN STD_LOGIC; -- Taktsignal
load : IN STD_LOGIC; -- "Werte laden" Signal
in_data_1 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 1. Faktor
in_data_2 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 2. Faktor
ready : OUT STD_LOGIC; -- 1=Berechnung abgeschlossen
out_data : OUT STD_LOGIC_VECTOR(15 DOWNTO 0) -- Ergebnis
);
END multiplier;
ARCHITECTURE multiplier_arch OF multiplier IS
SIGNAL add : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; -- Summand
SIGNAL counter : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; -- verbleibende Additionen
SIGNAL speicher : STD_LOGIC_VECTOR(15 DOWNTO 0) := "0000000000000000"; -- Zwischenergebnis
BEGIN
multiplication:
PROCESS (clk)
BEGIN
IF clk'EVENT AND clk='1' THEN
IF counter > 0 THEN
speicher <= speicher + ("00000000" & add); -- Berechnungsschritt
counter <= counter-1;
ELSE
IF load='1' THEN -- geladen wird nur, wenn
speicher <= "0000000000000000"; -- keine Berechnung angestoßen wurde
IF in_data_1<in_data_2 THEN -- um benötigte Taktzyklen zu
counter <= in_data_1; -- minimieren wird der kleinere
add <= in_data_2; -- Wert als Zähler verwendet
ELSE
counter <= in_data_2;
add <= in_data_1;
END IF;
END IF;
END IF;
END IF;
END PROCESS;
out_data <= speicher WHEN counter=0 ELSE "0000000000000000"; -- Ergebnis nur ausgeben,wenn
-- Berechnung abgeschlossen ist
ready <= '1' WHEN counter=0 ELSE '0';
END multiplier_arch;
|
Verhalten.vhd
Die genaue Beschreibung der Ein-/Ausgänge und des Verhaltens des Bausteins finden Sie in
der Spezifikation.
Um die Korrektheit unserer Schaltung zu überprüfen, wurde die Schaltung mit Hilfe einer
Testbench getestet.
Der Testbench-Baustein erzeugt zum einen ein 10 MHz Taktsignal, mit dem die Schaltung
dann betrieben wird.
Außderdem erzeugt er alle 256*256=65536 möglichen Kombinationen für in_data_1 und
in_data_2. Das wird dadurch erreicht, daß die Testbench ständig über das ready
Signal des Multiplizierers überprüft, ob eine Berechnung abgeschlossen ist in diesem Fall
load auf 1 setzt, um eine neue Berechnung anzustoßen. Gleichzeitig werden die Werte von
in_data_1 und (wenn in_data_1 von "11111111" auf "00000000" springt)
in_data_2 um 1 erhöht.
Um das Zeitverhalten der Schaltung nachvollziehen zu können, wird in dem 16-Bit Signal
tempcyc die Anzahl der verstrichenen Taktzyklen festgehalten.
Hier der Quellcode von Testbench.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY synth;
USE synth.vhdlsynth.all;
ENTITY testbench IS
PORT (
in_data_1,
in_data_2 : OUT STD_LOGIC_VECTOR(7 downto 0); -- die beiden Faktoren
load : OUT STD_LOGIC; -- "Werte Laden" Signal
ready : IN STD_LOGIC; -- =1, wenn multiplier fertig ist
clk : OUT STD_LOGIC -- generiertes Taktsignal
);
END testbench;
ARCHITECTURE testbench_arch OF testbench IS
SIGNAL tempcyc : NATURAL := 0; -- zählt verstrichene Taktzyklen
SIGNAL tempclk : STD_LOGIC := '0'; -- zur Generierung des Takts
CONSTANT clk_period : TIME := 100 ns; -- 10 MHz Taktfrequenz
SIGNAL buffer1, -- Zwischenspeicher für die Faktoren
buffer2 : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
BEGIN
clk <= tempclk;
in_data_1 <= buffer1;
in_data_2 <= buffer2;
clock: PROCESS
-- generiert das Taktsignal
BEGIN
tempclk <= '1';
WAIT FOR clk_period / 2; -- fallende Taktflanke
tempclk <= '0';
WAIT FOR clk_period / 2; -- steigende Taktflanke
tempcyc <= tempcyc + 1; -- ein Taktzyklus verstrichen
END PROCESS clock;
stimulus: PROCESS(tempclk)
-- durchläuft alle möglichen Kombinationen der
-- beiden Faktoren (65536 verschiedene)
BEGIN
IF (tempclk'EVENT AND tempclk = '1') THEN
IF (ready='1') THEN -- ist multiplier bereit ?
load <= '1'; -- neue Werte laden
buffer1 <= buffer1 + "00000001";
IF (buffer1 = "11111111") THEN
buffer2 <= buffer2 + "00000001";
END IF;
ELSE -- noch nicht bereit, also warten
load <= '0';
END IF;
END IF;
END PROCESS stimulus;
END testbench_arch;
|
Die Top Entity stellt die Verbindung zwischen der Testbench und dem Multiplizierer her.
Hier der Quellcode von Top.vhd:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY synth;
USE synth.vhdlsynth.all;
ENTITY TOP IS
END TOP;
ARCHITECTURE TOP_ARCH OF TOP IS
SIGNAL clk,
load,
ready : STD_LOGIC := '0';
SIGNAL in_data_1,
in_data_2 : STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000000";
SIGNAL out_data : STD_LOGIC_VECTOR (15 DOWNTO 0) := "0000000000000000";
COMPONENT multiplier
PORT (
clk : IN STD_LOGIC; -- Takt
load : IN STD_LOGIC; -- "Werte laden" Signal
in_data_1 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 1. Faktor
in_data_2 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 2. Faktor
ready : OUT STD_LOGIC; -- =1, wenn multiplier fertig ist
out_data : OUT STD_LOGIC_VECTOR(15 DOWNTO 0) -- Ergebnis
);
END COMPONENT;
FOR TEIL_1: multiplier USE ENTITY WORK.multiplier(multiplier_arch);
COMPONENT testbench
PORT (
in_data_1,
in_data_2 : OUT STD_LOGIC_VECTOR(7 downto 0); -- die beiden Faktoren
load : OUT STD_LOGIC; -- "Werte Laden" Signal
ready : IN STD_LOGIC; -- =1, wenn multiplier fertig ist
clk : OUT STD_LOGIC -- generiertes Taktsignal
);
END COMPONENT;
FOR TEIL_2: testbench USE ENTITY WORK.testbench(testbench_arch);
BEGIN
TEIL_1: multiplier PORT MAP (clk, load, in_data_1, in_data_2, ready, out_data);
TEIL_2: testbench PORT MAP (in_data_1, in_data_2, load, ready, clk);
END TOP_ARCH;
|
Mit Hilfe des Programms Speedwave wurde die Gesamtschaltung der Topentity simuliert und
gleichzeitig mit dem Programm VWave der Verlauf der wichtigsten Signale aufgezeichnet.
Nachfolgend ist ein Ausschnitt dieser Aufzeichnung zu sehen:

In dem markierten Bereich kann man die Multiplikation von 0Fh mit 03h verfolgen.
| Takt 1 |
|
Man erkennt, wie der kleinere Faktor 03h in counter und der größere
Faktor 0Fh in add eingelesen wird. Außerdem wird speicher mit 0 initialisiert.
|
| Takt 2 |
Der erste Additionsschritt wird ausgeführt, also 0Fh zu speicher addiert. Gleichzeitig
wird counter um 1 dekrementiert. |
| Takt 3 |
zweiter Addititionsschritt |
| Takt 4 |
Letzter Additionsschritt. counter wurde auf 0 heruntergezählt, deswegen wird nun
ready auf 1 gesetzt und out_data mit dem Ergebnis 2Dh der Multiplikation geladen. |
Die in VHDL beschriebene Schaltung multiplier wurde nun noch mit dem Programm
Aurora synthetisiert. Das mit dem Programm Viewdraw darstellbare Ergebnis ist
ein Schaltbild, in dem multiplier auf Gatterebene dargestellt wird.
Wir beschränken uns hier auf die Übersichtsdarstellung der Schaltung, Details (z.B. Gatter)
werden erst bei starker Vergrößerung (mit Viewdraw) gut erkennbar.
Eingänge

Ausgänge
Die Multiplikation durch fortgesetzte Addition ist sicher nicht die schnellste Methode.
Wie in der Spezifikation bereits angegeben, benötigt die Schaltung
| T = min(in_data1, in_data2) + 1 |
Takte, bis sie ein Ergebnis liefert. Im Zeitalter der Hochgeschwindigkeitsrechner sind z.B.
101 Takte für die Multiplikation von 100 mit 200 eine viel zu lange Zeit. So benötigt z.B. der
Pentium Prozessor für eine 8-Bit Multiplikation unabhängig vom Wert der Faktoren nur
11 Takte.
Eine Alternative zu unserer Lösung wäre z.B. ein Multipliziernetz.
01.07.98